[Swan-dev] Why enable KLIPS to have NAT-T detection with NETKEY?
Oleg Rosowiecki
orosowiecki at gmail.com
Mon Oct 17 16:45:23 UTC 2016
Libreswan code related to NAT-T support detection in the kernel looks very confusing to me.
Could someone explain why we need to compile in KLIPS in order for NAT-T to be detected with NETKEY?
NAT-T support gets detected in nat_traversal_espinudp_socket() as follows
(I'm omitting irrelevant code to reduce clutter):
int nat_traversal_espinudp_socket(int sk, const char *fam)
{
int r;
struct ifreq ifr;
int *fdp = (int *) &ifr.ifr_data;
const char *ifn;
DBG(DBG_NATT, DBG_log("NAT-Traversal: Trying new style NAT-T"));
zero(&ifr);
switch (kern_interface) {
/* ... OR: omitted for brevity */
case USE_NETKEY:
/* Let's hope we have at least one ethernet device */
ifn = "eth0";
break;
/* ... OR: omitted for brevity */
}
strncpy(ifr.ifr_name, ifn, sizeof(ifr.ifr_name));
fdp[0] = sk;
fdp[1] = ESPINUDP_WITH_NON_ESP; /* no longer support non-ike or non-floating */
r = ioctl(sk, IPSEC_UDP_ENCAP_CONVERT, &ifr);
if (r == -1) {
/* OR: signal failure to support new style NAT-T and errno */
} else {
/* OR: signal success */
return r;
}
/* OR: If we failed to detect new style NAT-T, try old style NAT-T detection... */
}
As far as I can see, the above code is bound to fail with NETKEY. The ioctl()
system call on the socket is serviced in the kernel by sock_ioctl()
and then subsequently by dev_ifsioc() as follows.
static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
{
int err;
struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name);
const struct net_device_ops *ops;
if (!dev)
return -ENODEV;
ops = dev->netdev_ops;
switch (cmd) {
/* OR: omitted for brevity */
default:
if ((cmd >= SIOCDEVPRIVATE &&
cmd <= SIOCDEVPRIVATE + 15) /* omitted */
err = -EOPNOTSUPP;
if (ops->ndo_do_ioctl) {
if (netif_device_present(dev))
err = ops->ndo_do_ioctl(dev, ifr, cmd);
else
err = -ENODEV;
}
}
}
First of all, we hard-code "eth0" in our struct ifreq that gets passed to the kernel.
On a machine with no "eth0", this will fail with ENODEV, as the above code illustrates.
On a machine that does have "eth0", this is most probably going to fail with EOPNOTSUPP,
since SIOCDEVPRIVATE + 3 means nothing to an average NIC driver (?).
The question is: is new NAT-T detection really supposed to work with NETKEY?
The test for the old style NAT-T is compiled conditionally:
#if defined(KLIPS)
DBG(DBG_NATT, DBG_log("NAT-Traversal: Trying old style NAT-T"));
const int type = ESPINUDP_WITH_NON_ESP;
r = setsockopt(sk, SOL_UDP, UDP_ESPINUDP, &type, sizeof(type));
if (r == -1) {
/* OR: signal failure to support old style NAT-T */
} else {
/* OR: signal success */
return r;
}
# else
DBG(DBG_NATT,
DBG_log("NAT-Traversal: ESPINUDP() setup for old style NAT-T family not available - KLIPS support not compiled in"));
#endif
Setting the socket option works perfectly with NETKEY. At first sight I'd say
the KLIPS-related #if directives rather belong around the new style NAT-T detection portion.
Could anybody explain the reason of the conditional compilation for old-style NAT-T?
Many thanks,
Oleg Rosowiecki
More information about the Swan-dev
mailing list