]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netinet6/esp_input.c
xnu-3248.60.10.tar.gz
[apple/xnu.git] / bsd / netinet6 / esp_input.c
index 277e6963ed5bae230ed785569387999cedbc438d..e51ea9b0f972fc870b021907bbd32488a8a5d031 100644 (file)
@@ -168,7 +168,7 @@ esp6_input_strip_udp_encap (struct mbuf *m, int ip6hlen)
        m->m_len -= stripsiz;
        m->m_pkthdr.len -= stripsiz;
        ip6 = mtod(m, __typeof__(ip6));
-       ip6->ip6_plen = ip6->ip6_plen - stripsiz;
+       ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz);
        ip6->ip6_nxt = IPPROTO_ESP;
        return ip6;
 }
@@ -521,7 +521,8 @@ noreplaycheck:
                 * XXX more sanity checks
                 * XXX relationship with gif?
                 */
-               u_int8_t tos;
+               u_int8_t tos, otos;
+               int sum;
 
                tos = ip->ip_tos;
                m_adj(m, off + esplen + ivlen);
@@ -537,10 +538,21 @@ noreplaycheck:
                        }
                        ip = mtod(m, struct ip *);
                        /* ECN consideration. */
+
+                       otos = ip->ip_tos;
                        if (ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos) == 0) {
                                IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
                                goto bad;
                        }
+
+                       if (otos != ip->ip_tos) {
+                           sum = ~ntohs(ip->ip_sum) & 0xffff;
+                           sum += (~otos & 0xffff) + ip->ip_tos;
+                           sum = (sum >> 16) + (sum & 0xffff);
+                           sum += (sum >> 16);  /* add carry */
+                           ip->ip_sum = htons(~sum & 0xffff);
+                       }
+
                        if (!key_checktunnelsanity(sav, AF_INET,
                            (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) {
                                ipseclog((LOG_ERR, "ipsec tunnel address mismatch "
@@ -1187,12 +1199,26 @@ noreplaycheck:
                                        goto bad;
                                }
                        }
+
+                       u_int8_t otos;
+                       int sum;
+
                        ip = mtod(m, struct ip *);
+                       otos = ip->ip_tos;
                        /* ECN consideration. */
                        if (ip46_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip->ip_tos) == 0) {
                                IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
                                goto bad;
                        }
+
+                       if (otos != ip->ip_tos) {
+                           sum = ~ntohs(ip->ip_sum) & 0xffff;
+                           sum += (~otos & 0xffff) + ip->ip_tos;
+                           sum = (sum >> 16) + (sum & 0xffff);
+                           sum += (sum >> 16);  /* add carry */
+                           ip->ip_sum = htons(~sum & 0xffff);
+                       }
+
                        if (!key_checktunnelsanity(sav, AF_INET,
                            (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) {
                                ipseclog((LOG_ERR, "ipsec tunnel address mismatch "
@@ -1246,7 +1272,7 @@ noreplaycheck:
                        }
                }
 
-               if (proto_input(PF_INET6, m) != 0)
+               if (proto_input(ifamily == AF_INET ? PF_INET : PF_INET6, m) != 0)
                        goto bad;
                nxt = IPPROTO_DONE;
        } else {
@@ -1345,6 +1371,17 @@ noreplaycheck:
                        goto bad;
                }
 
+               /*
+                * Set the csum valid flag, if we authenticated the
+                * packet, the payload shouldn't be corrupt unless
+                * it was corrupted before being signed on the other
+                * side.
+                */
+               if (nxt == IPPROTO_TCP || nxt == IPPROTO_UDP) {
+                       m->m_pkthdr.csum_flags = CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
+                       m->m_pkthdr.csum_data = 0xFFFF;
+               }
+
                // Input via IPSec interface
                if (sav->sah->ipsec_if != NULL) {
                        if (ipsec_inject_inbound_packet(sav->sah->ipsec_if, m) == 0) {