Jir
Jir

Reputation: 3125

IPv6 address problem in `ifreq` struct

I am working with the following code:

struct sockaddr_in6 *sin;
struct ifreq ifr;
sin = (struct sockaddr_in6 *)&ifr.ifr_addr;

ifr_addr is of type struct sockaddr, which for convenience is reported here under:

struct sockaddr {
        sa_family_t     sa_family;      /* address family, AF_xxx       */
        char            sa_data[14];    /* 14 bytes of protocol address */
};

How am I supposed to put an IPv6 address (via sin->sin6_addr.s6_addr) in the ifr_addr field given there are only 14 bytes available?

Where am I going wrong?

TIA, Chris

Upvotes: 2

Views: 3492

Answers (2)

Omnifarious
Omnifarious

Reputation: 56038

Fortunately struct ifreq is declared to contain the addresses in a union at the end of the structure:

struct ifreq
  {


    union
      {
 char ifrn_name[16];
      } ifr_ifrn;

    union
      {
 struct sockaddr ifru_addr;
 struct sockaddr ifru_dstaddr;
 struct sockaddr ifru_broadaddr;
 struct sockaddr ifru_netmask;
 struct sockaddr ifru_hwaddr;
 short int ifru_flags;
 int ifru_ivalue;
 int ifru_mtu;
 struct ifmap ifru_map;
 char ifru_slave[16];
 char ifru_newname[16];
 __caddr_t ifru_data;
      } ifr_ifru;
  };

Note that the above was the result of gcc -E and so all the preprocessor stuff has been expanded. Also note that ifr_addr is #defined to be ifr_ifru.ifru_addr.

This means that technically, you can allocate bytes off the end of the structure to hold the address.

In my opinion, this is extremely sloppy. The union should be declared to hold a value of type sockaddr_storage along with everything else. Then the structure size will be big enough to hold any address.

If you wanted to declare your own structure of the right size that you could use pretty easily, just do this:

union my_ifreq {
    struct ifreq sys_ifreq;
    struct {
        char name_pad[IFNAMSIZ];
        struct sockaddr_storage addr;
    } padding;
};

Then you will have a structure that always has enough storage that you can stuff any valid address in sys_ifreq.ifr_addr and have it work.

Upvotes: 3

Steve-o
Steve-o

Reputation: 12866

The platforms that use struct sockaddr inside struct ifreq also have an IPv6 friendly version struct lifreq that uses struct sockaddr_storage instead for example Solaris, other platforms such as Linux and AIX already use the longer structure.

Upvotes: 0

Related Questions