diff -r -c -N linux-2.6.22/include/net/xfrmudp.h linux-2.6.22-natt/include/net/xfrmudp.h *** linux-2.6.22/include/net/xfrmudp.h Wed Dec 31 19:00:00 1969 --- linux-2.6.22-natt/include/net/xfrmudp.h Wed May 7 20:21:20 2008 *************** *** 0 **** --- 1,10 ---- + /* + * pointer to function for type that xfrm4_input wants, to permit + * decoupling of XFRM from udp.c + */ + #define HAVE_XFRM4_UDP_REGISTER + + typedef int (*xfrm4_rcv_encap_t)(struct sk_buff *skb, __u16 encap_type); + extern int udp4_register_esp_rcvencap(xfrm4_rcv_encap_t func + , xfrm4_rcv_encap_t *oldfunc); + extern int udp4_unregister_esp_rcvencap(xfrm4_rcv_encap_t func); diff -r -c -N linux-2.6.22/net/ipv4/Kconfig linux-2.6.22-natt/net/ipv4/Kconfig *** linux-2.6.22/net/ipv4/Kconfig Sun Jul 8 19:32:17 2007 --- linux-2.6.22-natt/net/ipv4/Kconfig Wed May 7 20:21:20 2008 *************** *** 409,414 **** --- 409,420 ---- tristate default n + config IPSEC_NAT_TRAVERSAL + bool "IPSEC NAT-Traversal (KLIPS compatible)" + depends on INET + ---help--- + Includes support for RFC3947/RFC3948 NAT-Traversal of ESP over UDP. + config INET_XFRM_MODE_TRANSPORT tristate "IP: IPsec transport mode" default y diff -r -c -N linux-2.6.22/net/ipv4/udp.c linux-2.6.22-natt/net/ipv4/udp.c *** linux-2.6.22/net/ipv4/udp.c Sun Jul 8 19:32:17 2007 --- linux-2.6.22-natt/net/ipv4/udp.c Wed May 7 22:13:19 2008 *************** *** 101,106 **** --- 101,107 ---- #include #include #include + #include #include "udp_impl.h" /* *************** *** 1017,1022 **** --- 1018,1145 ---- #endif } + #if defined(CONFIG_XFRM) || defined(CONFIG_IPSEC_NAT_TRAVERSAL) + + static xfrm4_rcv_encap_t xfrm4_rcv_encap_func = NULL; + + /* + * de-encapsulate and pass to the registered xfrm4_rcv_encap_func function. + * Most of this code stolen from net/ipv4/xfrm4_input.c + * which is attributed to YOSHIFUJI Hideaki @USAGI, and + * Derek Atkins + */ + + static int xfrm4_udp_encap_rcv_wrapper(struct sock *sk, struct sk_buff *skb) + { + struct udp_sock *up = udp_sk(sk); + struct udphdr *uh; + struct iphdr *iph; + int iphlen, len; + int ret; + + __u8 *udpdata; + __be32 *udpdata32; + __u16 encap_type = up->encap_type; + + /* if this is not encapsulated socket, then just return now */ + if (!encap_type && !xfrm4_rcv_encap_func) + return 1; + + /* If this is a paged skb, make sure we pull up + * whatever data we need to look at. */ + len = skb->len - sizeof(struct udphdr); + if (!pskb_may_pull(skb, sizeof(struct udphdr) + min(len, 8))) + return 1; + + /* Now we can get the pointers */ + uh = udp_hdr(skb); + udpdata = (__u8 *)uh + sizeof(struct udphdr); + udpdata32 = (__be32 *)udpdata; + + switch (encap_type) { + default: + case UDP_ENCAP_ESPINUDP: + /* Check if this is a keepalive packet. If so, eat it. */ + if (len == 1 && udpdata[0] == 0xff) { + goto drop; + } else if (len > sizeof(struct ip_esp_hdr) && udpdata32[0] != 0) { + /* ESP Packet without Non-ESP header */ + len = sizeof(struct udphdr); + } else + /* Must be an IKE packet.. pass it through */ + return 1; + break; + case UDP_ENCAP_ESPINUDP_NON_IKE: + /* Check if this is a keepalive packet. If so, eat it. */ + if (len == 1 && udpdata[0] == 0xff) { + goto drop; + } else if (len > 2 * sizeof(u32) + sizeof(struct ip_esp_hdr) && + udpdata32[0] == 0 && udpdata32[1] == 0) { + + /* ESP Packet with Non-IKE marker */ + len = sizeof(struct udphdr) + 2 * sizeof(u32); + } else + /* Must be an IKE packet.. pass it through */ + return 1; + break; + } + + /* At this point we are sure that this is an ESPinUDP packet, + * so we need to remove 'len' bytes from the packet (the UDP + * header and optional ESP marker bytes) and then modify the + * protocol to ESP, and then call into the transform receiver. + */ + if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) + goto drop; + + /* Now we can update and verify the packet length... */ + iph = ip_hdr(skb); + iphlen = iph->ihl << 2; + iph->tot_len = htons(ntohs(iph->tot_len) - len); + if (skb->len < iphlen + len) { + /* packet is too small!?! */ + goto drop; + } + + /* pull the data buffer up to the ESP header and set the + * transport header to point to ESP. Keep UDP on the stack + * for later. + */ + __skb_pull(skb, len); + skb_reset_transport_header(skb); + + /* modify the protocol (it's ESP!) */ + iph->protocol = IPPROTO_ESP; + + /* process ESP */ + ret = (*xfrm4_rcv_encap_func)(skb, encap_type); + return ret; + + drop: + kfree_skb(skb); + return 0; + } + + int udp4_register_esp_rcvencap(xfrm4_rcv_encap_t func, + xfrm4_rcv_encap_t *oldfunc) + { + if (oldfunc != NULL) + *oldfunc = xfrm4_rcv_encap_func; + xfrm4_rcv_encap_func = func; + return 0; + } + + int udp4_unregister_esp_rcvencap(xfrm4_rcv_encap_t func) + { + if (xfrm4_rcv_encap_func != func) + return -1; + + xfrm4_rcv_encap_func = NULL; + return 0; + } + + #endif /* CONFIG_XFRM_MODULE || CONFIG_IPSEC_NAT_TRAVERSAL */ + /* returns: * -1: error * 0: success *************** *** 1349,1355 **** case 0: case UDP_ENCAP_ESPINUDP: case UDP_ENCAP_ESPINUDP_NON_IKE: ! up->encap_type = val; break; default: err = -ENOPROTOOPT; --- 1472,1483 ---- case 0: case UDP_ENCAP_ESPINUDP: case UDP_ENCAP_ESPINUDP_NON_IKE: ! #if defined(CONFIG_XFRM) || defined(CONFIG_IPSEC_NAT_TRAVERSAL) ! if (xfrm4_rcv_encap_func) ! up->encap_rcv = xfrm4_udp_encap_rcv_wrapper; ! else ! #endif ! up->encap_type = val; break; default: err = -ENOPROTOOPT; *************** *** 1742,1744 **** --- 1870,1878 ---- EXPORT_SYMBOL(udp_proc_register); EXPORT_SYMBOL(udp_proc_unregister); #endif + + #if defined(CONFIG_IPSEC_NAT_TRAVERSAL) + EXPORT_SYMBOL(udp4_register_esp_rcvencap); + EXPORT_SYMBOL(udp4_unregister_esp_rcvencap); + #endif +