LCOV - code coverage report
Current view: top level - netinet - ipsec_output.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 261 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 5 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: ipsec_output.c,v 1.74 2018/08/28 15:15:02 mpi Exp $ */
       2             : /*
       3             :  * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
       4             :  *
       5             :  * Copyright (c) 2000-2001 Angelos D. Keromytis.
       6             :  *
       7             :  * Permission to use, copy, and modify this software with or without fee
       8             :  * is hereby granted, provided that this entire notice is included in
       9             :  * all copies of any software which is or includes a copy or
      10             :  * modification of this software.
      11             :  * You may use this code under the GNU public license if you so wish. Please
      12             :  * contribute changes back to the authors under this freer than GPL license
      13             :  * so that we may further the use of strong encryption without limitations to
      14             :  * all.
      15             :  *
      16             :  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
      17             :  * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
      18             :  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
      19             :  * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
      20             :  * PURPOSE.
      21             :  */
      22             : 
      23             : #include "pf.h"
      24             : 
      25             : #include <sys/param.h>
      26             : #include <sys/systm.h>
      27             : #include <sys/mbuf.h>
      28             : #include <sys/socket.h>
      29             : #include <sys/kernel.h>
      30             : #include <sys/timeout.h>
      31             : 
      32             : #include <net/if.h>
      33             : #include <net/route.h>
      34             : 
      35             : #include <netinet/in.h>
      36             : #include <netinet/ip.h>
      37             : #include <netinet/in_pcb.h>
      38             : #include <netinet/ip_var.h>
      39             : 
      40             : #if NPF > 0
      41             : #include <net/pfvar.h>
      42             : #endif
      43             : 
      44             : #include <netinet/udp.h>
      45             : #include <netinet/ip_ipip.h>
      46             : #include <netinet/ip_ah.h>
      47             : #include <netinet/ip_esp.h>
      48             : #include <netinet/ip_ipcomp.h>
      49             : 
      50             : #include <crypto/cryptodev.h>
      51             : #include <crypto/xform.h>
      52             : 
      53             : #ifdef ENCDEBUG
      54             : #define DPRINTF(x)      if (encdebug) printf x
      55             : #else
      56             : #define DPRINTF(x)
      57             : #endif
      58             : 
      59             : int     udpencap_enable = 1;    /* enabled by default */
      60             : int     udpencap_port = 4500;   /* triggers decapsulation */
      61             : 
      62             : /*
      63             :  * Loop over a tdb chain, taking into consideration protocol tunneling. The
      64             :  * fourth argument is set if the first encapsulation header is already in
      65             :  * place.
      66             :  */
      67             : int
      68           0 : ipsp_process_packet(struct mbuf *m, struct tdb *tdb, int af, int tunalready)
      69             : {
      70             :         int hlen, off, error;
      71           0 :         struct mbuf *mp;
      72             : #ifdef INET6
      73           0 :         struct ip6_ext ip6e;
      74             :         int nxt;
      75             :         int dstopt = 0;
      76             : #endif
      77             : 
      78             :         int setdf = 0;
      79             :         struct ip *ip;
      80             : #ifdef INET6
      81             :         struct ip6_hdr *ip6;
      82             : #endif /* INET6 */
      83             : 
      84             : #ifdef ENCDEBUG
      85             :         char buf[INET6_ADDRSTRLEN];
      86             : #endif
      87             : 
      88             :         /* Check that the transform is allowed by the administrator. */
      89           0 :         if ((tdb->tdb_sproto == IPPROTO_ESP && !esp_enable) ||
      90           0 :             (tdb->tdb_sproto == IPPROTO_AH && !ah_enable) ||
      91           0 :             (tdb->tdb_sproto == IPPROTO_IPCOMP && !ipcomp_enable)) {
      92             :                 DPRINTF(("ipsp_process_packet(): IPsec outbound packet "
      93             :                     "dropped due to policy (check your sysctls)\n"));
      94             :                 error = EHOSTUNREACH;
      95           0 :                 goto drop;
      96             :         }
      97             : 
      98             :         /* Sanity check. */
      99           0 :         if (!tdb->tdb_xform) {
     100             :                 DPRINTF(("%s: uninitialized TDB\n", __func__));
     101             :                 error = EHOSTUNREACH;
     102           0 :                 goto drop;
     103             :         }
     104             : 
     105             :         /* Check if the SPI is invalid. */
     106           0 :         if (tdb->tdb_flags & TDBF_INVALID) {
     107             :                 DPRINTF(("ipsp_process_packet(): attempt to use invalid "
     108             :                     "SA %s/%08x/%u\n", ipsp_address(&tdb->tdb_dst, buf,
     109             :                     sizeof(buf)), ntohl(tdb->tdb_spi), tdb->tdb_sproto));
     110             :                 error = ENXIO;
     111           0 :                 goto drop;
     112             :         }
     113             : 
     114             :         /* Check that the network protocol is supported */
     115           0 :         switch (tdb->tdb_dst.sa.sa_family) {
     116             :         case AF_INET:
     117             :                 break;
     118             : 
     119             : #ifdef INET6
     120             :         case AF_INET6:
     121             :                 break;
     122             : #endif /* INET6 */
     123             : 
     124             :         default:
     125             :                 DPRINTF(("ipsp_process_packet(): attempt to use "
     126             :                     "SA %s/%08x/%u for protocol family %d\n",
     127             :                     ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
     128             :                     ntohl(tdb->tdb_spi), tdb->tdb_sproto,
     129             :                     tdb->tdb_dst.sa.sa_family));
     130             :                 error = ENXIO;
     131           0 :                 goto drop;
     132             :         }
     133             : 
     134             :         /*
     135             :          * Register first use if applicable, setup relevant expiration timer.
     136             :          */
     137           0 :         if (tdb->tdb_first_use == 0) {
     138           0 :                 tdb->tdb_first_use = time_second;
     139           0 :                 if (tdb->tdb_flags & TDBF_FIRSTUSE)
     140           0 :                         timeout_add_sec(&tdb->tdb_first_tmo,
     141           0 :                             tdb->tdb_exp_first_use);
     142           0 :                 if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE)
     143           0 :                         timeout_add_sec(&tdb->tdb_sfirst_tmo,
     144           0 :                             tdb->tdb_soft_first_use);
     145             :         }
     146             : 
     147             :         /*
     148             :          * Check for tunneling if we don't have the first header in place.
     149             :          * When doing Ethernet-over-IP, we are handed an already-encapsulated
     150             :          * frame, so we don't need to re-encapsulate.
     151             :          */
     152           0 :         if (tunalready == 0) {
     153             :                 /*
     154             :                  * If the target protocol family is different, we know we'll be
     155             :                  * doing tunneling.
     156             :                  */
     157           0 :                 if (af == tdb->tdb_dst.sa.sa_family) {
     158           0 :                         if (af == AF_INET)
     159           0 :                                 hlen = sizeof(struct ip);
     160             : 
     161             : #ifdef INET6
     162           0 :                         if (af == AF_INET6)
     163           0 :                                 hlen = sizeof(struct ip6_hdr);
     164             : #endif /* INET6 */
     165             : 
     166             :                         /* Bring the network header in the first mbuf. */
     167           0 :                         if (m->m_len < hlen) {
     168           0 :                                 if ((m = m_pullup(m, hlen)) == NULL) {
     169             :                                         error = ENOBUFS;
     170           0 :                                         goto drop;
     171             :                                 }
     172             :                         }
     173             : 
     174           0 :                         if (af == AF_INET) {
     175           0 :                                 ip = mtod(m, struct ip *);
     176             : 
     177             :                                 /*
     178             :                                  * This is not a bridge packet, remember if we
     179             :                                  * had IP_DF.
     180             :                                  */
     181           0 :                                 setdf = ip->ip_off & htons(IP_DF);
     182           0 :                         }
     183             : 
     184             : #ifdef INET6
     185           0 :                         if (af == AF_INET6)
     186           0 :                                 ip6 = mtod(m, struct ip6_hdr *);
     187             : #endif /* INET6 */
     188             :                 }
     189             : 
     190             :                 /* Do the appropriate encapsulation, if necessary. */
     191           0 :                 if ((tdb->tdb_dst.sa.sa_family != af) || /* PF mismatch */
     192           0 :                     (tdb->tdb_flags & TDBF_TUNNELING) || /* Tunneling needed */
     193           0 :                     (tdb->tdb_xform->xf_type == XF_IP4) || /* ditto */
     194           0 :                     ((tdb->tdb_dst.sa.sa_family == AF_INET) &&
     195           0 :                      (tdb->tdb_dst.sin.sin_addr.s_addr != INADDR_ANY) &&
     196           0 :                      (tdb->tdb_dst.sin.sin_addr.s_addr != ip->ip_dst.s_addr)) ||
     197             : #ifdef INET6
     198           0 :                     ((tdb->tdb_dst.sa.sa_family == AF_INET6) &&
     199           0 :                      (!IN6_IS_ADDR_UNSPECIFIED(&tdb->tdb_dst.sin6.sin6_addr)) &&
     200           0 :                      (!IN6_ARE_ADDR_EQUAL(&tdb->tdb_dst.sin6.sin6_addr,
     201             :                       &ip6->ip6_dst))) ||
     202             : #endif /* INET6 */
     203             :                     0) {
     204             :                         /* Fix IPv4 header checksum and length. */
     205           0 :                         if (af == AF_INET) {
     206           0 :                                 if (m->m_len < sizeof(struct ip))
     207           0 :                                         if ((m = m_pullup(m,
     208           0 :                                             sizeof(struct ip))) == NULL) {
     209             :                                                 error = ENOBUFS;
     210           0 :                                                 goto drop;
     211             :                                         }
     212             : 
     213           0 :                                 ip = mtod(m, struct ip *);
     214           0 :                                 ip->ip_len = htons(m->m_pkthdr.len);
     215           0 :                                 ip->ip_sum = 0;
     216           0 :                                 ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
     217           0 :                         }
     218             : 
     219             : #ifdef INET6
     220             :                         /* Fix IPv6 header payload length. */
     221           0 :                         if (af == AF_INET6) {
     222           0 :                                 if (m->m_len < sizeof(struct ip6_hdr))
     223           0 :                                         if ((m = m_pullup(m,
     224           0 :                                             sizeof(struct ip6_hdr))) == NULL) {
     225             :                                                 error = ENOBUFS;
     226           0 :                                                 goto drop;
     227             :                                         }
     228             : 
     229           0 :                                 if (m->m_pkthdr.len - sizeof(*ip6) >
     230             :                                     IPV6_MAXPACKET) {
     231             :                                         /* No jumbogram support. */
     232             :                                         error = ENXIO;  /*?*/
     233           0 :                                         goto drop;
     234             :                                 }
     235           0 :                                 ip6 = mtod(m, struct ip6_hdr *);
     236           0 :                                 ip6->ip6_plen = htons(m->m_pkthdr.len
     237             :                                     - sizeof(*ip6));
     238           0 :                         }
     239             : #endif /* INET6 */
     240             : 
     241             :                         /* Encapsulate -- the last two arguments are unused. */
     242           0 :                         error = ipip_output(m, tdb, &mp, 0, 0);
     243           0 :                         if ((mp == NULL) && (!error))
     244             :                                 error = EFAULT;
     245             :                         m = mp;
     246           0 :                         mp = NULL;
     247           0 :                         if (error)
     248             :                                 goto drop;
     249             : 
     250           0 :                         if (tdb->tdb_dst.sa.sa_family == AF_INET && setdf) {
     251           0 :                                 if (m->m_len < sizeof(struct ip))
     252           0 :                                         if ((m = m_pullup(m,
     253           0 :                                             sizeof(struct ip))) == NULL) {
     254             :                                                 error = ENOBUFS;
     255           0 :                                                 goto drop;
     256             :                                         }
     257             : 
     258           0 :                                 ip = mtod(m, struct ip *);
     259           0 :                                 ip->ip_off |= htons(IP_DF);
     260           0 :                         }
     261             : 
     262             :                         /* Remember that we appended a tunnel header. */
     263           0 :                         tdb->tdb_flags |= TDBF_USEDTUNNEL;
     264           0 :                 }
     265             : 
     266             :                 /* We may be done with this TDB */
     267           0 :                 if (tdb->tdb_xform->xf_type == XF_IP4)
     268           0 :                         return ipsp_process_done(m, tdb);
     269             :         } else {
     270             :                 /*
     271             :                  * If this is just an IP-IP TDB and we're told there's
     272             :                  * already an encapsulation header, move on.
     273             :                  */
     274           0 :                 if (tdb->tdb_xform->xf_type == XF_IP4)
     275           0 :                         return ipsp_process_done(m, tdb);
     276             :         }
     277             : 
     278             :         /* Extract some information off the headers. */
     279           0 :         switch (tdb->tdb_dst.sa.sa_family) {
     280             :         case AF_INET:
     281           0 :                 ip = mtod(m, struct ip *);
     282           0 :                 hlen = ip->ip_hl << 2;
     283             :                 off = offsetof(struct ip, ip_p);
     284           0 :                 break;
     285             : 
     286             : #ifdef INET6
     287             :         case AF_INET6:
     288           0 :                 ip6 = mtod(m, struct ip6_hdr *);
     289             :                 hlen = sizeof(struct ip6_hdr);
     290             :                 off = offsetof(struct ip6_hdr, ip6_nxt);
     291           0 :                 nxt = ip6->ip6_nxt;
     292             :                 /*
     293             :                  * chase mbuf chain to find the appropriate place to
     294             :                  * put AH/ESP/IPcomp header.
     295             :                  *      IPv6 hbh dest1 rthdr ah* [esp* dest2 payload]
     296             :                  */
     297           0 :                 do {
     298           0 :                         switch (nxt) {
     299             :                         case IPPROTO_AH:
     300             :                         case IPPROTO_ESP:
     301             :                         case IPPROTO_IPCOMP:
     302             :                                 /*
     303             :                                  * we should not skip security header added
     304             :                                  * beforehand.
     305             :                                  */
     306             :                                 goto exitip6loop;
     307             : 
     308             :                         case IPPROTO_HOPOPTS:
     309             :                         case IPPROTO_DSTOPTS:
     310             :                         case IPPROTO_ROUTING:
     311             :                                 /*
     312             :                                  * if we see 2nd destination option header,
     313             :                                  * we should stop there.
     314             :                                  */
     315           0 :                                 if (nxt == IPPROTO_DSTOPTS && dstopt)
     316             :                                         goto exitip6loop;
     317             : 
     318           0 :                                 if (nxt == IPPROTO_DSTOPTS) {
     319             :                                         /*
     320             :                                          * seen 1st or 2nd destination option.
     321             :                                          * next time we see one, it must be 2nd.
     322             :                                          */
     323             :                                         dstopt = 1;
     324           0 :                                 } else if (nxt == IPPROTO_ROUTING) {
     325             :                                         /*
     326             :                                          * if we see destionation option next
     327             :                                          * time, it must be dest2.
     328             :                                          */
     329             :                                         dstopt = 2;
     330           0 :                                 }
     331           0 :                                 if (m->m_pkthdr.len < hlen + sizeof(ip6e)) {
     332             :                                         error = EINVAL;
     333           0 :                                         goto drop;
     334             :                                 }
     335             :                                 /* skip this header */
     336           0 :                                 m_copydata(m, hlen, sizeof(ip6e),
     337             :                                     (caddr_t)&ip6e);
     338           0 :                                 nxt = ip6e.ip6e_nxt;
     339             :                                 off = hlen + offsetof(struct ip6_ext, ip6e_nxt);
     340             :                                 /*
     341             :                                  * we will never see nxt == IPPROTO_AH
     342             :                                  * so it is safe to omit AH case.
     343             :                                  */
     344           0 :                                 hlen += (ip6e.ip6e_len + 1) << 3;
     345             :                                 break;
     346             :                         default:
     347             :                                 goto exitip6loop;
     348             :                         }
     349           0 :                 } while (hlen < m->m_pkthdr.len);
     350             :         exitip6loop:
     351             :                 break;
     352             : #endif /* INET6 */
     353             :         default:
     354             :                 error = EINVAL;
     355           0 :                 goto drop;
     356             :         }
     357             : 
     358           0 :         if (m->m_pkthdr.len < hlen) {
     359             :                 error = EINVAL;
     360           0 :                 goto drop;
     361             :         }
     362             : 
     363           0 :         ipsecstat_add(ipsec_ouncompbytes, m->m_pkthdr.len);
     364           0 :         tdb->tdb_ouncompbytes += m->m_pkthdr.len;
     365             : 
     366             :         /* Non expansion policy for IPCOMP */
     367           0 :         if (tdb->tdb_sproto == IPPROTO_IPCOMP) {
     368           0 :                 if ((m->m_pkthdr.len - hlen) < tdb->tdb_compalgxform->minlen) {
     369             :                         /* No need to compress, leave the packet untouched */
     370           0 :                         ipcompstat_inc(ipcomps_minlen);
     371           0 :                         return ipsp_process_done(m, tdb);
     372             :                 }
     373             :         }
     374             : 
     375             :         /* Invoke the IPsec transform. */
     376           0 :         return (*(tdb->tdb_xform->xf_output))(m, tdb, NULL, hlen, off);
     377             : 
     378             :  drop:
     379           0 :         m_freem(m);
     380           0 :         return error;
     381           0 : }
     382             : 
     383             : /*
     384             :  * IPsec output callback, called directly by the crypto driver.
     385             :  */
     386             : void
     387           0 : ipsec_output_cb(struct cryptop *crp)
     388             : {
     389           0 :         struct tdb_crypto *tc = (struct tdb_crypto *) crp->crp_opaque;
     390           0 :         struct mbuf *m = (struct mbuf *) crp->crp_buf;
     391             :         struct tdb *tdb;
     392             :         int error, ilen, olen;
     393             : 
     394           0 :         if (m == NULL) {
     395             :                 DPRINTF(("%s: bogus returned buffer from crypto\n", __func__));
     396           0 :                 ipsecstat_inc(ipsec_crypto);
     397           0 :                 goto droponly;
     398             :         }
     399             : 
     400           0 :         NET_LOCK();
     401           0 :         tdb = gettdb(tc->tc_rdomain, tc->tc_spi, &tc->tc_dst, tc->tc_proto);
     402           0 :         if (tdb == NULL) {
     403             :                 DPRINTF(("%s: TDB is expired while in crypto\n", __func__));
     404           0 :                 ipsecstat_inc(ipsec_notdb);
     405           0 :                 goto baddone;
     406             :         }
     407             : 
     408             :         /* Check for crypto errors. */
     409           0 :         if (crp->crp_etype) {
     410           0 :                 if (crp->crp_etype == EAGAIN) {
     411             :                         /* Reset the session ID */
     412           0 :                         if (tdb->tdb_cryptoid != 0)
     413           0 :                                 tdb->tdb_cryptoid = crp->crp_sid;
     414           0 :                         NET_UNLOCK();
     415           0 :                         crypto_dispatch(crp);
     416           0 :                         return;
     417             :                 }
     418             :                 DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype));
     419           0 :                 ipsecstat_inc(ipsec_noxform);
     420           0 :                 goto baddone;
     421             :         }
     422             : 
     423           0 :         olen = crp->crp_olen;
     424           0 :         ilen = crp->crp_ilen;
     425             : 
     426             :         /* Release crypto descriptors. */
     427           0 :         crypto_freereq(crp);
     428             : 
     429           0 :         switch (tdb->tdb_sproto) {
     430             :         case IPPROTO_ESP:
     431           0 :                 error = esp_output_cb(tdb, tc, m, ilen, olen);
     432           0 :                 break;
     433             :         case IPPROTO_AH:
     434           0 :                 error = ah_output_cb(tdb, tc, m, ilen, olen);
     435           0 :                 break;
     436             :         case IPPROTO_IPCOMP:
     437           0 :                 error = ipcomp_output_cb(tdb, tc, m, ilen, olen);
     438           0 :                 break;
     439             :         default:
     440           0 :                 panic("%s: unknown/unsupported security protocol %d",
     441             :                     __func__, tdb->tdb_sproto);
     442             :         }
     443             : 
     444           0 :         NET_UNLOCK();
     445           0 :         if (error) {
     446           0 :                 ipsecstat_inc(ipsec_odrops);
     447           0 :                 tdb->tdb_odrops++;
     448           0 :         }
     449           0 :         return;
     450             : 
     451             :  baddone:
     452           0 :         NET_UNLOCK();
     453             :  droponly:
     454           0 :         if (tdb != NULL)
     455           0 :                 tdb->tdb_odrops++;
     456           0 :         m_freem(m);
     457           0 :         free(tc, M_XDATA, 0);
     458           0 :         crypto_freereq(crp);
     459           0 :         ipsecstat_inc(ipsec_odrops);
     460           0 : }
     461             : 
     462             : /*
     463             :  * Called by the IPsec output transform callbacks, to transmit the packet
     464             :  * or do further processing, as necessary.
     465             :  */
     466             : int
     467           0 : ipsp_process_done(struct mbuf *m, struct tdb *tdb)
     468             : {
     469             :         struct ip *ip;
     470             : #ifdef INET6
     471             :         struct ip6_hdr *ip6;
     472             : #endif /* INET6 */
     473             :         struct tdb_ident *tdbi;
     474             :         struct m_tag *mtag;
     475           0 :         int roff, error;
     476             : 
     477           0 :         tdb->tdb_last_used = time_second;
     478             : 
     479           0 :         if ((tdb->tdb_flags & TDBF_UDPENCAP) != 0) {
     480             :                 struct mbuf *mi;
     481             :                 struct udphdr *uh;
     482             :                 int iphlen;
     483             : 
     484           0 :                 if (!udpencap_enable || !udpencap_port) {
     485             :                         error = ENXIO;
     486           0 :                         goto drop;
     487             :                 }
     488             : 
     489           0 :                 switch (tdb->tdb_dst.sa.sa_family) {
     490             :                 case AF_INET:
     491             :                         iphlen = sizeof(struct ip);
     492           0 :                         break;
     493             : #ifdef INET6
     494             :                 case AF_INET6:
     495             :                         iphlen = sizeof(struct ip6_hdr);
     496           0 :                         break;
     497             : #endif /* INET6 */
     498             :                 default:
     499             :                         DPRINTF(("ipsp_process_done(): unknown protocol family "
     500             :                             "(%d)\n", tdb->tdb_dst.sa.sa_family));
     501             :                         error = ENXIO;
     502           0 :                         goto drop;
     503             :                 }
     504             : 
     505           0 :                 mi = m_makespace(m, iphlen, sizeof(struct udphdr), &roff);
     506           0 :                 if (mi == NULL) {
     507             :                         error = ENOMEM;
     508           0 :                         goto drop;
     509             :                 }
     510           0 :                 uh = (struct udphdr *)(mtod(mi, caddr_t) + roff);
     511           0 :                 uh->uh_sport = uh->uh_dport = htons(udpencap_port);
     512           0 :                 if (tdb->tdb_udpencap_port)
     513           0 :                         uh->uh_dport = tdb->tdb_udpencap_port;
     514             : 
     515           0 :                 uh->uh_ulen = htons(m->m_pkthdr.len - iphlen);
     516           0 :                 uh->uh_sum = 0;
     517             : #ifdef INET6
     518           0 :                 if (tdb->tdb_dst.sa.sa_family == AF_INET6)
     519           0 :                         m->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT;
     520             : #endif /* INET6 */
     521           0 :                 espstat_inc(esps_udpencout);
     522           0 :         }
     523             : 
     524           0 :         switch (tdb->tdb_dst.sa.sa_family) {
     525             :         case AF_INET:
     526             :                 /* Fix the header length, for AH processing. */
     527           0 :                 ip = mtod(m, struct ip *);
     528           0 :                 ip->ip_len = htons(m->m_pkthdr.len);
     529           0 :                 if ((tdb->tdb_flags & TDBF_UDPENCAP) != 0)
     530           0 :                         ip->ip_p = IPPROTO_UDP;
     531             :                 break;
     532             : 
     533             : #ifdef INET6
     534             :         case AF_INET6:
     535             :                 /* Fix the header length, for AH processing. */
     536           0 :                 if (m->m_pkthdr.len < sizeof(*ip6)) {
     537             :                         error = ENXIO;
     538           0 :                         goto drop;
     539             :                 }
     540           0 :                 if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) {
     541             :                         /* No jumbogram support. */
     542             :                         error = ENXIO;
     543           0 :                         goto drop;
     544             :                 }
     545           0 :                 ip6 = mtod(m, struct ip6_hdr *);
     546           0 :                 ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
     547           0 :                 if ((tdb->tdb_flags & TDBF_UDPENCAP) != 0)
     548           0 :                         ip6->ip6_nxt = IPPROTO_UDP;
     549             :                 break;
     550             : #endif /* INET6 */
     551             : 
     552             :         default:
     553             :                 DPRINTF(("ipsp_process_done(): unknown protocol family (%d)\n",
     554             :                     tdb->tdb_dst.sa.sa_family));
     555             :                 error = ENXIO;
     556           0 :                 goto drop;
     557             :         }
     558             : 
     559             :         /*
     560             :          * Add a record of what we've done or what needs to be done to the
     561             :          * packet.
     562             :          */
     563           0 :         mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_DONE, sizeof(struct tdb_ident),
     564             :             M_NOWAIT);
     565           0 :         if (mtag == NULL) {
     566             :                 DPRINTF(("ipsp_process_done(): could not allocate packet "
     567             :                     "tag\n"));
     568             :                 error = ENOMEM;
     569           0 :                 goto drop;
     570             :         }
     571             : 
     572           0 :         tdbi = (struct tdb_ident *)(mtag + 1);
     573           0 :         tdbi->dst = tdb->tdb_dst;
     574           0 :         tdbi->proto = tdb->tdb_sproto;
     575           0 :         tdbi->spi = tdb->tdb_spi;
     576           0 :         tdbi->rdomain = tdb->tdb_rdomain;
     577             : 
     578           0 :         m_tag_prepend(m, mtag);
     579             : 
     580           0 :         ipsecstat_inc(ipsec_opackets);
     581           0 :         ipsecstat_add(ipsec_obytes, m->m_pkthdr.len);
     582           0 :         tdb->tdb_opackets++;
     583           0 :         tdb->tdb_obytes += m->m_pkthdr.len;
     584             : 
     585             :         /* If there's another (bundled) TDB to apply, do so. */
     586           0 :         if (tdb->tdb_onext)
     587           0 :                 return ipsp_process_packet(m, tdb->tdb_onext,
     588           0 :                     tdb->tdb_dst.sa.sa_family, 0);
     589             : 
     590             : #if NPF > 0
     591             :         /* Add pf tag if requested. */
     592           0 :         pf_tag_packet(m, tdb->tdb_tag, -1);
     593           0 :         pf_pkt_addr_changed(m);
     594             : #endif
     595             : 
     596             :         /*
     597             :          * We're done with IPsec processing, transmit the packet using the
     598             :          * appropriate network protocol (IP or IPv6). SPD lookup will be
     599             :          * performed again there.
     600             :          */
     601           0 :         switch (tdb->tdb_dst.sa.sa_family) {
     602             :         case AF_INET:
     603           0 :                 return (ip_output(m, NULL, NULL, IP_RAWOUTPUT, NULL, NULL, 0));
     604             : 
     605             : #ifdef INET6
     606             :         case AF_INET6:
     607             :                 /*
     608             :                  * We don't need massage, IPv6 header fields are always in
     609             :                  * net endian.
     610             :                  */
     611           0 :                 return (ip6_output(m, NULL, NULL, 0, NULL, NULL));
     612             : #endif /* INET6 */
     613             :         }
     614           0 :         error = EINVAL; /* Not reached. */
     615             : 
     616             :  drop:
     617           0 :         m_freem(m);
     618           0 :         return error;
     619           0 : }
     620             : 
     621             : ssize_t
     622           0 : ipsec_hdrsz(struct tdb *tdbp)
     623             : {
     624             :         ssize_t adjust;
     625             : 
     626           0 :         switch (tdbp->tdb_sproto) {
     627             :         case IPPROTO_IPIP:
     628             :                 adjust = 0;
     629           0 :                 break;
     630             : 
     631             :         case IPPROTO_ESP:
     632           0 :                 if (tdbp->tdb_encalgxform == NULL)
     633           0 :                         return (-1);
     634             : 
     635             :                 /* Header length */
     636           0 :                 adjust = 2 * sizeof(u_int32_t) + tdbp->tdb_ivlen;
     637           0 :                 if (tdbp->tdb_flags & TDBF_UDPENCAP)
     638           0 :                         adjust += sizeof(struct udphdr);
     639             :                 /* Authenticator */
     640           0 :                 if (tdbp->tdb_authalgxform != NULL)
     641           0 :                         adjust += tdbp->tdb_authalgxform->authsize;
     642             :                 /* Padding */
     643           0 :                 adjust += MAX(4, tdbp->tdb_encalgxform->blocksize);
     644           0 :                 break;
     645             : 
     646             :         case IPPROTO_AH:
     647           0 :                 if (tdbp->tdb_authalgxform == NULL)
     648           0 :                         return (-1);
     649             : 
     650             :                 adjust = AH_FLENGTH + sizeof(u_int32_t);
     651           0 :                 adjust += tdbp->tdb_authalgxform->authsize;
     652           0 :                 break;
     653             : 
     654             :         default:
     655           0 :                 return (-1);
     656             :         }
     657             : 
     658           0 :         if (!(tdbp->tdb_flags & TDBF_TUNNELING) &&
     659           0 :             !(tdbp->tdb_flags & TDBF_USEDTUNNEL))
     660           0 :                 return (adjust);
     661             : 
     662           0 :         switch (tdbp->tdb_dst.sa.sa_family) {
     663             :         case AF_INET:
     664           0 :                 adjust += sizeof(struct ip);
     665           0 :                 break;
     666             : #ifdef INET6
     667             :         case AF_INET6:
     668           0 :                 adjust += sizeof(struct ip6_hdr);
     669           0 :                 break;
     670             : #endif /* INET6 */
     671             :         }
     672             : 
     673           0 :         return (adjust);
     674           0 : }
     675             : 
     676             : void
     677           0 : ipsec_adjust_mtu(struct mbuf *m, u_int32_t mtu)
     678             : {
     679             :         struct tdb_ident *tdbi;
     680             :         struct tdb *tdbp;
     681             :         struct m_tag *mtag;
     682             :         ssize_t adjust;
     683             : 
     684           0 :         NET_ASSERT_LOCKED();
     685             : 
     686           0 :         for (mtag = m_tag_find(m, PACKET_TAG_IPSEC_OUT_DONE, NULL); mtag;
     687           0 :              mtag = m_tag_find(m, PACKET_TAG_IPSEC_OUT_DONE, mtag)) {
     688           0 :                 tdbi = (struct tdb_ident *)(mtag + 1);
     689           0 :                 tdbp = gettdb(tdbi->rdomain, tdbi->spi, &tdbi->dst,
     690           0 :                     tdbi->proto);
     691           0 :                 if (tdbp == NULL)
     692             :                         break;
     693             : 
     694           0 :                 if ((adjust = ipsec_hdrsz(tdbp)) == -1)
     695             :                         break;
     696             : 
     697           0 :                 mtu -= adjust;
     698           0 :                 tdbp->tdb_mtu = mtu;
     699           0 :                 tdbp->tdb_mtutimeout = time_second + ip_mtudisc_timeout;
     700             :                 DPRINTF(("ipsec_adjust_mtu: "
     701             :                     "spi %08x mtu %d adjust %ld mbuf %p\n",
     702             :                     ntohl(tdbp->tdb_spi), tdbp->tdb_mtu,
     703             :                     adjust, m));
     704             :         }
     705           0 : }

Generated by: LCOV version 1.13