what does 0 indicate in socket() system call? - c

what 0 indicates in following line?
what are other flags i can use?
server = socket(AF_UNIX, SOCK_STREAM, 0)

As others have likely said, the third argument to socket is generally an int indicating the protocol. 0 indicates that the caller does not want to specify the protocol and will leave it up to the service provider.
Other than zero, another common one is IPPROTO_TCP.
Full details can be found on the man page using man 2 socket on your machine or visiting here.

From the man pages of socket:
int socket(int domain, int type, int protocol);
The protocol specifies a
particular protocol to be used with
the socket. Normally only a single
protocol
exists to support a particular socket type within a given protocol
family, in which case protocol can be
speci‐
fied as 0. However, it is possible that many protocols may
exist, in which case a particular
protocol must be
specified in this manner. The protocol number to use is specific to
the “communication domain” in which
commu‐
nication is to take place; see protocols(5). See getprotoent(3) on
how to map protocol name strings to
proto‐
col numbers.

The best thing to do here is read the man page. This document states that the third parameter is the protocol, which in this case is SOCK_STREAM but can be others.

Related

What's the socket protocol with value 17?

Recall the declaration of a socket in C has the following signature:
int socket(int domain, int type, int protocol);
I met some reverse-engineered code where protocol = 17. Does anyone know what protocol this refers to? The net seems to be lacking of such int values; they have only the names, at best.
Protocol 17 would be UDP per IANA specifications, which is referred to at least in the Linux socket documentation. The name of the protocol should also be available via getprotoent if it’s supported by the platform.
Microsoft also uses same numbers for the protocols in socket.

What is the HOPOPT protocol and how does socket() work?

I'm messing with sockets in C and this protocol continues to show up, I couldn't find anything about it, so what is it used for? What's the difference between HOPOPT and IP?
Also i'm don't get why the last argument of the socket() function should be 0. According to the man page:
The protocol specifies a particular protocol to be used with the socket. Normally only a single protocol exists to support a particular socket type within a given protocol family, in which case protocol can be specified as 0. However, it is possible that many protocols may exist, in which case a particular protocol must be specified in this manner. The protocol number to use is specific to the “communication domain” in which communication is to take place; see protocols(5). See getprotoent(3) on how to map protocol name strings to protocol numbers.
As far as I understand setting the last argument to 0 will let the standard library to decide which protocol to use but in which case would one use a number other than 0?
HOPOPT is the acronym of the Hop-by-Hop IPv6 extension header. It is a header that allows to add even more options to an IPv6 packet. It is normal that IPv6 packets include this header.
socket() is the system call that BSD and others (Linux et al.) provide to create a new socket, that is the internal representation of a network connection. When creating a new socket, the desired protocol must be specified: TCP, UDP, etc., which may go over IPv4, IPv6, etc.
The paragraph that you are citing explains that one or many protocols may exist for each socket type.
If only one exists, the protocol argument must be zero. For instance, SOCK_STREAM sockets are only implemented by TCP:
int sk = socket(AF_INET, SOCK_STREAM, 0);
If more exist, than you must specify which protocol in particular you want to use. For example, the SOCK_SEQPACKET type can be implemented with the SCTP protocol:
int sk = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
So, in conclusion:
If you want to create a socket, choose what protocol to use, for instance TCP over IPv4.
HOPOPT is totally normal in an IPv6 packet. If you see it appear in your traces, because you created an IPv6 socket (using AF_INET6), it is OK.

Purpose of sendto address for C raw socket?

I'm sending some ping packets via a raw socket in C, on my linux machine.
int sock_fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
This means that I specify the IP packet header when I write to the socket (IP_HDRINCL is implied).
Writing to the socket with send fails, telling me I need to specify an address.
If I use sendto then it works. For sendto I must specify a sockaddr_in struct to use, which includes the fields sin_family, sin_port and sin_addr.
However, I have noticed a few things:
The sin_family is AF_INET - which was already specified when the socket was created.
The sin_port is naturally unused (ports are not a concept for IP).
It doesn't matter what address I use, so long as it is an external address (the IP packet specifies 8.8.8.8 and the sin_addr specifies 1.1.1.1).
It seems none of the extra fields in sendto are actually used to great extent. So, is there a technical reason why I have to use sendto instead of send or is it just an oversight in the API?
Writing to the socket with send fails, telling me I need to specify an address.
It fails, because the send() function can only be used on connected sockets (as stated here). Usually you would use send() for TCP communication (connection-oriented) and sendto() can be used to send UDP datagrams (connectionless).
Since you want to send "ping" packets, or more correctly ICMP datagrams, which are clearly connectionless, you have to use the sendto() function.
It seems none of the extra fields in sendto are actually used to great
extent. So, is there a technical reason why I have to use sendto
instead of send or is it just an oversight in the API?
Short answer:
When you are not allowed to use send(), then there is only one option left, called sendto().
Long answer:
It is not just an oversight in the API. If you want to send a UDP datagram by using an ordinary socket (e.g. SOCK_DGRAM), sendto() needs the information about the destination address and port, which you provided in the struct sockaddr_in, right? The kernel will insert that information into the resulting IP header, since the struct sockaddr_in is the only place where you specified who the receiver will be. Or in other words: in this case the kernel has to take the destination info from your struct as you don't provide an additional IP header.
Because sendto() is not only used for UDP but also raw sockets, it has to be a more or less "generic" function which can cover all the different use cases, even when some parameters like the port number are not relevant/used in the end.
For instance, by using IPPROTO_RAW (which automatically implies IP_HDRINCL), you show your intention that you want to create the IP header on your own. Thus the last two arguments of sendto() are actually redundant information, because they're already included in the data buffer you pass to sendto() as the second argument. Note that, even when you use IP_HDRINCL with your raw socket, the kernel will fill in the source address and checksum of your IP datagram if you set the corresponding fields to 0.
If you want to write your own ping program, you could also change the last argument in your socket() function from IPPROTO_RAW to IPPROTO_ICMP and let the kernel create the IP header for you, so you have one thing less to worry about. Now you can easily see how the two sendto()-parameters *dest_addr and addrlen become significant again because it's the only place where you provide a destination address.
The language and APIs are very old and have grown over time. Some APIs can look weird from todays perspective but you can't change the old interfaces without breaking a huge amount of existing code. Sometimes you just have to get used to things that were defined/designed many years or decades ago.
Hope that answers your question.
The send() call is used when the sockets are in a TCP SOCK_STREAM connected state.
From the man page:
the send() call may be used only when the socket is in a connected
state (so that the intended recipient is known).
Since your application obviously does not connect with any other socket, we cannot expect send() to work.
In addition to InvertedHeli's answer, the dest_addr passed in sendto() will be used by kernel to determine which network interface to used.
For example, if dest_addr has ip 127.0.0.1 and the raw packet has dest address 8.8.8.8, your packet will still be routed to the lo interface.

Unix Domain sockets (C) - Client "deletes" socket on connect()?

This may be a bit difficult to enumerate succinctly but I will give it my best on my novice understanding of the domain and problem.
I have 2 processes, one stream server who first unlinks, creates a socket descriptor, binds, listens, and accepts on a local unix socket. The job of the server is to accept a connection, send arbitrary data, and also receive arbitrary data. The client process' job is to do the same as the server with the exception of the initial setup; create a socket descriptor, and connect to the unix socket.
Upon launching the server, I can verify the unix socket is being created. Upon launching the client, I receive a connect() error stating the file or directory doesn't exist or invalid. And yes, attempting to locate the unix socket as before, the file no longer exists...
Does anyone know why or where in the bug may lie that is causing this behavior?
If code snippets would be helpful to clarify, I can certainly post those as well.
struct addrinfo * server;
int sockfd;
sockfd = socket( server->ai_family, server->ai_socktype, server->ai_protocol );
if( connect(sockfd, server->ai_addr, server->ai_addrlen) == 0 )
return sockfd;
else
perror("connect()");
It's probably also worth noting that I'm using a modified version of getaddrinfo to populate the addrinfo struct for the unix domain specifically.
Following the server startup, check that the socket file exists on the client system i.e. make sure that the file you're going to use in the sun_path field of the struct sockaddr_un passed into the connect on the client exists. This entry must match the one that was created in the server and passed into the bind. Also make sure that you are populating the sun_family field in both the client and the server with AF_UNIX.
In the client do not perform any creation/deletion of the socket file - i.e there should not be an unlink anywhere in the client code related to the location of the server socket.
These are the general processes I would follow to ensure that the code is doing the right thing. There is a sample server/client in the old, but still reliable Beej's guide to UNIX IPC which is probably the simplest example you should be comparing to.
Edit Based on the discussion in the comments, it turns out that the custom getaddrinfo call is the culprit in the deletion of the unix socket file. This is because there is server-side logic in the code which checks if hints->ai_flags & AI_PASSIVE is set. If this is the case, then it unlinks the socket file, as it expects the software to be performing a bind (as in be a server). The logic about the AI_PASSIVE flag is codified in the RFC, and in that case, the bind would fail if the file does not exist.
If the AI_PASSIVE flag is specified, the returned address information
shall be suitable for use in binding a socket for accepting incoming
connections for the specified service (i.e., a call to bind()).
However, the end sentence of that paragraph states:
This flag is ignored if the nodename argument is not null
So it seems like the logic is slightly incorrect in this case of the call getaddrinfo( "/local", "/tmp/socket", hints, &server), as the nodename parameter is not null.

Making a reliable UDP by socket function in c

I am having this doubt in socket programming which I could not get cleared by reading the man pages.
In c the declaration of socket function is int socket(int domain, int type, int protocol);
The linux man page says that while type decides the stream that will be followed the protocol number is the one that decides the protocol being followed.
So my question is that suppose I give the type parameter as SOCK_STREAM which is reliable and add the protocol number for UDP would it give me a reliable UDP which is same as TCP but without flow control and congestion control.
Unfortunately I can't test this out as I have a single machine so there is no packet loss happening.
Could anyone clear this doubt? Thanks a lot...
UDP cannot be made reliable. Transmission of the packets is done on a "best effort" capacity, but any router/host along the chain is free to drop the packet in the garbage and NOT inform the sender that it has done so.
That's not to say you can't impose extra semantics on the sending and receiving ends to expect packets within a certain time frame and say "hey, we didn't get anything in the last X seconds". But that can't be done at the protocol level. UDP is a "dump it into the outbox and hope it gets there" protocol.
No. For an IPV4 or IPV6 protocol stack, SOCK_STREAM is going to get you TCP and the type SOCK_DGRAM is going to give you UDP. The protocol parameter is not used for either of the choices and the socket library is typically expecting a value of 0 to be specified there.
If you do this:
socket(AF_INET,SOCK_STREAM,IPPROTO_UDP):
socket() will return -1 and sett errno to
EPROTONOSUPPORT
The protocol type or the specified protocol
is not supported within this domain.

Resources