Reputation: 77
In a kernel module, given a struct sockaddr
with sa_family
initialized as AF_UNSPEC
, how can I reliably determine if it is a struct sockaddr_in
or struct sockaddr_in6
? On Linux 3.16.0-4-686-pae (x86).
struct sockaddr {
unsigned short sa_family; // AF_UNSPEC
char sa_data[14]; // ?
};
struct sockaddr_in {
unsigned short sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
struct sockaddr_in6 {
unsigned short sin6_family;
unsigned short sin6_port;
unsigned int sin6_flowinfo;
struct in6_addr sin6_addr;
unsigned int sin6_scope_id;
};
Upvotes: 1
Views: 722
Reputation: 2051
Usually, when something calls into the kernel and gives a struct sockaddr
, it also has to give the length of the struct sockaddr
. For example, see sendto()
:
ssize_t sendto (int sockfd, const void *buf, size_t buflen, int flags,
const struct sockaddr *addr, socklen_t addrlen);
Using the size of the buffer, you ought to be able to get a good guess as to what type of sockaddr
you need to use:
if (addr.sa_family == AF_UNSPEC) {
switch (addrlen) {
case sizeof (struct sockaddr_in): {
addr.sa_family = AF_INET;
break;
}
case sizeof (struct sockaddr_in6): {
addr.sa_family = AF_INET6;
break;
}
default: {
// handle error
break;
}
}
}
In an ideal world, the sa_family
would be set to seither AF_INET
(IPv4) or AF_INET6
(IPv6) already, but unfortunately that doesn't appear to be the case here.
Upvotes: 2