+
+ /*
+ * UDP to port 4500 with a payload where the first four bytes are
+ * not zero is a UDP encapsulated IPSec packet. Packets where
+ * the payload is one byte and that byte is 0xFF are NAT keepalive
+ * packets. Decapsulate the ESP packet and carry on with IPSec input
+ * or discard the NAT keep-alive.
+ */
+ if (ipsec_bypass == 0 && (esp_udp_encap_port & 0xFFFF) != 0 &&
+ uh->uh_dport == ntohs((u_short)esp_udp_encap_port)) {
+ int payload_len = len - sizeof(struct udphdr) > 4 ? 4 : len - sizeof(struct udphdr);
+ if (m->m_len < iphlen + sizeof(struct udphdr) + payload_len) {
+ if ((m = m_pullup(m, iphlen + sizeof(struct udphdr) + payload_len)) == 0) {
+ udpstat.udps_hdrops++;
+ KERNEL_DEBUG(DBG_FNC_UDP_INPUT | DBG_FUNC_END, 0,0,0,0,0);
+ return;
+ }
+ ip = mtod(m, struct ip *);
+ uh = (struct udphdr *)((caddr_t)ip + iphlen);
+ }
+ /* Check for NAT keepalive packet */
+ if (payload_len == 1 && *(u_int8_t*)((caddr_t)uh + sizeof(struct udphdr)) == 0xFF) {
+ m_freem(m);
+ KERNEL_DEBUG(DBG_FNC_UDP_INPUT | DBG_FUNC_END, 0,0,0,0,0);
+ return;
+ }
+ else if (payload_len == 4 && *(u_int32_t*)((caddr_t)uh + sizeof(struct udphdr)) != 0) {
+ /* UDP encapsulated IPSec packet to pass through NAT */
+ size_t stripsiz;
+
+ stripsiz = sizeof(struct udphdr);
+
+ ip = mtod(m, struct ip *);
+ ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), iphlen);
+ m->m_data += stripsiz;
+ m->m_len -= stripsiz;
+ m->m_pkthdr.len -= stripsiz;
+ ip = mtod(m, struct ip *);
+ ip->ip_len = ip->ip_len - stripsiz;
+ ip->ip_p = IPPROTO_ESP;
+
+ KERNEL_DEBUG(DBG_FNC_UDP_INPUT | DBG_FUNC_END, 0,0,0,0,0);
+ esp4_input(m, iphlen);
+ return;
+ }
+ }
+