2

I was playing around with Berkeley sockets, and then I did this:

#include <iostream>
#include <sys/socket.h>
#include <cstring>

int main()
{
    auto res = socket(AF_INET6, SOCK_STREAM, 58);
    if (res < 0) {
        std::cout << "  Error in creating socket: " << strerror(errno) << '\n';
    }
    return 0;
}

And the output was: Error in creating socket: Protocol not supported. I chose 58 as I wanted to try out as an example a ICMP IPv6 socket, and using the contents of /etc/protocols I got this: ipv6-icmp 58 IPv6-ICMP # ICMP for IPv6. Then I tried 0 in place of 58 in the code above and the program ran fine. So my questions are:

  1. why is the need of this 3rd parameter in socket() call, if we have
    already specified SOCK_STREAM(TCP) as protocol in 2nd parameter i.e. what is the reason of existence of this protocol (3rd parameter) ?

  2. If the protocol(3rd argument) is necessary then what all values can it take
    with all possible combinations of domain(1st argument) and type(2nd argument) ?

It would be very helpful, if someone can explain this with examples ,otherwise too it would be fine. Thanks

tkhurana96
  • 919
  • 7
  • 25

1 Answers1

2
  1. from my experience, the protocol field is usually only used when you use SOCK_RAW instead of SOCK_DGRAM or SOCK_STREAM.
  2. the values that protocol can accept depend on the values of the first two arguments. The domains and types that are available are listed here. The same page says the following about the protocol field:
   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.

Here is a link to a page listing the available protocols and their associated values. The ICMP protocol value is 1.

To setup for ICMP packets you could do the following: sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);

to setup for UDP packets you would use

sock = socket(AF_INET, SOCK_DGRAM, 0);

or

sock = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);

Also check out this answer to another question. It's talking about normal ICMPv4 sockets but it should still be helpful and some parts may be applicable.

Community
  • 1
  • 1
  • well, I tried this: `auto res = socket(AF_INET6, SOCK_STREAM, 6);` and it worked like charm, and then I tried this: `auto res = socket(AF_INET6, SOCK_STREAM, 132);` and it also worked like charm, and for 0 it also works, but apart from these 3 values it gives the error ` Error in creating socket: Protocol not supported`. – tkhurana96 Mar 02 '17 at 21:07
  • So there must be some standard/rule specifying which protocol values can be used when and when not ? – tkhurana96 Mar 02 '17 at 21:09
  • @tkhurana96, according to the document i linked to above with the protocol values, 6=TCP and 132=SCTP. Give 58 a try for ICMPv6 with a raw socket. – Louis P. Dartez Mar 02 '17 at 21:19
  • Although you linked a good document but I have a question:So the `protocol` argument is for specifying a protocol another than TCP(2nd argument) and UDP(2nd argument) ? If so, then why not we only need the `protocol` argument and no `type` (2nd argument) ? – tkhurana96 Mar 02 '17 at 21:22
  • 1
    @tkhurana96, this is brushing up against what I understand. But I believe the answer to your question is more historical than anything else. Back in the day it was thought that each address family would come to support many different types each with their own set of protocols...but over time this didn't end up happening. socket wrappers have popped up over the years to cover it up so that devs wouldn't have to deal with it. – Louis P. Dartez Mar 02 '17 at 21:24
  • 1
    From _The Linux Programming Interface_ by Michael Kerrisk: Initially, it was conceived that a single protocol family might support multiple address families. In practice, no protocol family supporting multiple address families has ever been defined, and all existing implementations define the PF_ constants to be synonymous with the corresponding AF_ constants. (SUSv3 specifies the AF_ constants, but not the PF_ constants.) In this book, we always use the AF_ constants. Further information about the history of these constants can be found in Section 4.2 of [Stevens et al., 2004]. – Louis P. Dartez Mar 02 '17 at 21:27
  • Thanks @Louis P. Dartez, you gave a great explanation, Can you elaborate more on PF_ and AF_ constants i.e. what was protocol family and how was it different from address family ? – tkhurana96 Mar 02 '17 at 21:33
  • sure, at the risk of turning this into too long of a discussion (and getting nabbed by a mod). AF_INET only works for IPv4, AF_INET6 works on IPv6 (i'm not sure if it supports v4), and PF_* works for both IPv4 and IPv6. My understanding is that the AF_* values are being deprecated _eventually_ and we should be using PF_* now. – Louis P. Dartez Mar 02 '17 at 21:38
  • One more question @Louis P. Dartez: And what does PF_ constants have to do with type(2nd argument) ? Do PF_ constants represent `type` or are they different ? – tkhurana96 Mar 02 '17 at 21:42
  • To answer that check out [this question and answer](http://stackoverflow.com/questions/6729366/what-is-the-difference-between-af-inet-and-pf-inet-in-socket-programming). – Louis P. Dartez Mar 02 '17 at 21:45
  • Well @Louis P. Dartez the link answered differences between AF_ (1st parameter) and PF_ , but I still don't get the difference between PF_ and `type` (2nd argument) – tkhurana96 Mar 02 '17 at 21:52
  • I suggest checking [this link out](https://users.cs.cf.ac.uk/Dave.Marshall/C/node28.html). – Louis P. Dartez Mar 02 '17 at 22:18