| 1 | /* $NetBSD: ipsec_output.c,v 1.41 2015/03/30 03:51:50 ozaki-r Exp $ */ |
| 2 | |
| 3 | /*- |
| 4 | * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting |
| 5 | * All rights reserved. |
| 6 | * |
| 7 | * Redistribution and use in source and binary forms, with or without |
| 8 | * modification, are permitted provided that the following conditions |
| 9 | * are met: |
| 10 | * 1. Redistributions of source code must retain the above copyright |
| 11 | * notice, this list of conditions and the following disclaimer. |
| 12 | * 2. Redistributions in binary form must reproduce the above copyright |
| 13 | * notice, this list of conditions and the following disclaimer in the |
| 14 | * documentation and/or other materials provided with the distribution. |
| 15 | * |
| 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
| 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
| 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 26 | * SUCH DAMAGE. |
| 27 | * |
| 28 | * $FreeBSD: /repoman/r/ncvs/src/sys/netipsec/ipsec_output.c,v 1.3.2.2 2003/03/28 20:32:53 sam Exp $ |
| 29 | */ |
| 30 | |
| 31 | #include <sys/cdefs.h> |
| 32 | __KERNEL_RCSID(0, "$NetBSD: ipsec_output.c,v 1.41 2015/03/30 03:51:50 ozaki-r Exp $" ); |
| 33 | |
| 34 | /* |
| 35 | * IPsec output processing. |
| 36 | */ |
| 37 | #include "opt_inet.h" |
| 38 | #ifdef __FreeBSD__ |
| 39 | #include "opt_inet6.h" |
| 40 | #endif |
| 41 | |
| 42 | #include <sys/param.h> |
| 43 | #include <sys/systm.h> |
| 44 | #include <sys/mbuf.h> |
| 45 | #include <sys/domain.h> |
| 46 | #include <sys/protosw.h> |
| 47 | #include <sys/socket.h> |
| 48 | #include <sys/errno.h> |
| 49 | #include <sys/syslog.h> |
| 50 | |
| 51 | #include <net/if.h> |
| 52 | #include <net/route.h> |
| 53 | |
| 54 | #include <netinet/in.h> |
| 55 | #include <netinet/in_systm.h> |
| 56 | #include <netinet/ip.h> |
| 57 | #include <netinet/ip_var.h> |
| 58 | #include <netinet/in_var.h> |
| 59 | #include <netinet/ip_ecn.h> |
| 60 | #ifdef INET6 |
| 61 | # ifdef __FreeBSD__ |
| 62 | # include <netinet6/ip6_ecn.h> |
| 63 | # endif |
| 64 | #endif |
| 65 | |
| 66 | #include <netinet/ip6.h> |
| 67 | #ifdef INET6 |
| 68 | #include <netinet6/ip6_var.h> |
| 69 | #endif |
| 70 | #include <netinet/in_pcb.h> |
| 71 | #ifdef INET6 |
| 72 | #include <netinet/icmp6.h> |
| 73 | #endif |
| 74 | #include <netinet/udp.h> |
| 75 | |
| 76 | #include <netipsec/ipsec.h> |
| 77 | #include <netipsec/ipsec_var.h> |
| 78 | #include <netipsec/ipsec_private.h> |
| 79 | #ifdef INET6 |
| 80 | #include <netipsec/ipsec6.h> |
| 81 | #endif |
| 82 | #include <netipsec/ah_var.h> |
| 83 | #include <netipsec/esp_var.h> |
| 84 | #include <netipsec/ipcomp_var.h> |
| 85 | |
| 86 | #include <netipsec/xform.h> |
| 87 | |
| 88 | #include <netipsec/key.h> |
| 89 | #include <netipsec/keydb.h> |
| 90 | #include <netipsec/key_debug.h> |
| 91 | #include <netipsec/ipsec_osdep.h> |
| 92 | |
| 93 | #include <net/net_osdep.h> /* ovbcopy() in ipsec6_encapsulate() */ |
| 94 | |
| 95 | |
| 96 | /* |
| 97 | * Add a IPSEC_OUT_DONE tag to mark that we have finished the ipsec processing |
| 98 | * It will be used by ip{,6}_output to check if we have already or not |
| 99 | * processed this packet. |
| 100 | */ |
| 101 | static int |
| 102 | ipsec_register_done(struct mbuf *m, int * error) |
| 103 | { |
| 104 | struct m_tag *mtag; |
| 105 | |
| 106 | mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_DONE, 0, M_NOWAIT); |
| 107 | if (mtag == NULL) { |
| 108 | DPRINTF(("ipsec_register_done: could not get packet tag\n" )); |
| 109 | *error = ENOMEM; |
| 110 | return -1; |
| 111 | } |
| 112 | |
| 113 | m_tag_prepend(m, mtag); |
| 114 | return 0; |
| 115 | } |
| 116 | |
| 117 | static int |
| 118 | ipsec_reinject_ipstack(struct mbuf *m, int af) |
| 119 | { |
| 120 | #ifdef INET |
| 121 | #ifdef __FreeBSD__ |
| 122 | struct ip *ip; |
| 123 | #endif /* __FreeBSD_ */ |
| 124 | #endif /* INET */ |
| 125 | #if defined(INET) || defined(INET6) |
| 126 | int rv; |
| 127 | #endif |
| 128 | |
| 129 | switch (af) { |
| 130 | #ifdef INET |
| 131 | case AF_INET: |
| 132 | #ifdef __FreeBSD__ |
| 133 | ip = mtod(m, struct ip *); |
| 134 | /* FreeBSD ip_output() expects ip_len, ip_off in host endian */ |
| 135 | ip->ip_len = ntohs(ip->ip_len); |
| 136 | ip->ip_off = ntohs(ip->ip_off); |
| 137 | #endif /* __FreeBSD_ */ |
| 138 | KERNEL_LOCK(1, NULL); |
| 139 | rv = ip_output(m, NULL, NULL, IP_RAWOUTPUT|IP_NOIPNEWID, |
| 140 | NULL, NULL); |
| 141 | KERNEL_UNLOCK_ONE(NULL); |
| 142 | return rv; |
| 143 | |
| 144 | #endif /* INET */ |
| 145 | #ifdef INET6 |
| 146 | case AF_INET6: |
| 147 | /* |
| 148 | * We don't need massage, IPv6 header fields are always in |
| 149 | * net endian. |
| 150 | */ |
| 151 | KERNEL_LOCK(1, NULL); |
| 152 | rv = ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); |
| 153 | KERNEL_UNLOCK_ONE(NULL); |
| 154 | return rv; |
| 155 | #endif /* INET6 */ |
| 156 | } |
| 157 | |
| 158 | panic("ipsec_reinject_ipstack : iunknown protocol family %u\n" , af); |
| 159 | return -1; /* NOTREACHED */ |
| 160 | } |
| 161 | |
| 162 | int |
| 163 | ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr) |
| 164 | { |
| 165 | struct secasvar *sav; |
| 166 | struct secasindex *saidx; |
| 167 | int error; |
| 168 | #ifdef INET |
| 169 | struct ip * ip; |
| 170 | #endif /* INET */ |
| 171 | #ifdef INET6 |
| 172 | struct ip6_hdr * ip6; |
| 173 | #endif /* INET6 */ |
| 174 | struct mbuf * mo; |
| 175 | struct udphdr *udp = NULL; |
| 176 | uint64_t * data = NULL; |
| 177 | int hlen, roff; |
| 178 | |
| 179 | IPSEC_SPLASSERT_SOFTNET("ipsec_process_done" ); |
| 180 | |
| 181 | IPSEC_ASSERT(m != NULL, ("ipsec_process_done: null mbuf" )); |
| 182 | IPSEC_ASSERT(isr != NULL, ("ipsec_process_done: null ISR" )); |
| 183 | sav = isr->sav; |
| 184 | IPSEC_ASSERT(sav != NULL, ("ipsec_process_done: null SA" )); |
| 185 | IPSEC_ASSERT(sav->sah != NULL, ("ipsec_process_done: null SAH" )); |
| 186 | |
| 187 | saidx = &sav->sah->saidx; |
| 188 | |
| 189 | if(sav->natt_type != 0) { |
| 190 | ip = mtod(m, struct ip *); |
| 191 | |
| 192 | hlen = sizeof(struct udphdr); |
| 193 | if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE) |
| 194 | hlen += sizeof(uint64_t); |
| 195 | |
| 196 | mo = m_makespace(m, sizeof(struct ip), hlen, &roff); |
| 197 | if (mo == NULL) { |
| 198 | DPRINTF(("ipsec_process_done : failed to inject" |
| 199 | "%u byte UDP for SA %s/%08lx\n" , |
| 200 | hlen, ipsec_address(&saidx->dst), |
| 201 | (u_long) ntohl(sav->spi))); |
| 202 | error = ENOBUFS; |
| 203 | goto bad; |
| 204 | } |
| 205 | |
| 206 | udp = (struct udphdr*) (mtod(mo, char*) + roff); |
| 207 | data = (uint64_t*) (udp + 1); |
| 208 | |
| 209 | if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE) |
| 210 | *data = 0; /* NON-IKE Marker */ |
| 211 | |
| 212 | if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE) |
| 213 | udp->uh_sport = htons(UDP_ENCAP_ESPINUDP_PORT); |
| 214 | else |
| 215 | udp->uh_sport = key_portfromsaddr(&saidx->src); |
| 216 | |
| 217 | udp->uh_dport = key_portfromsaddr(&saidx->dst); |
| 218 | udp->uh_sum = 0; |
| 219 | udp->uh_ulen = htons(m->m_pkthdr.len - (ip->ip_hl << 2)); |
| 220 | } |
| 221 | |
| 222 | switch (saidx->dst.sa.sa_family) { |
| 223 | #ifdef INET |
| 224 | case AF_INET: |
| 225 | /* Fix the header length, for AH processing. */ |
| 226 | ip = mtod(m, struct ip *); |
| 227 | ip->ip_len = htons(m->m_pkthdr.len); |
| 228 | if (sav->natt_type != 0) |
| 229 | ip->ip_p = IPPROTO_UDP; |
| 230 | break; |
| 231 | #endif /* INET */ |
| 232 | #ifdef INET6 |
| 233 | case AF_INET6: |
| 234 | /* Fix the header length, for AH processing. */ |
| 235 | if (m->m_pkthdr.len < sizeof (struct ip6_hdr)) { |
| 236 | error = ENXIO; |
| 237 | goto bad; |
| 238 | } |
| 239 | if (m->m_pkthdr.len - sizeof (struct ip6_hdr) > IPV6_MAXPACKET) { |
| 240 | /* No jumbogram support. */ |
| 241 | error = ENXIO; /*?*/ |
| 242 | goto bad; |
| 243 | } |
| 244 | ip6 = mtod(m, struct ip6_hdr *); |
| 245 | ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr)); |
| 246 | if (sav->natt_type != 0) |
| 247 | ip6->ip6_nxt = IPPROTO_UDP; |
| 248 | break; |
| 249 | #endif /* INET6 */ |
| 250 | default: |
| 251 | DPRINTF(("ipsec_process_done: unknown protocol family %u\n" , |
| 252 | saidx->dst.sa.sa_family)); |
| 253 | error = ENXIO; |
| 254 | goto bad; |
| 255 | } |
| 256 | |
| 257 | key_sa_recordxfer(sav, m); |
| 258 | |
| 259 | /* |
| 260 | * If there's another (bundled) SA to apply, do so. |
| 261 | * Note that this puts a burden on the kernel stack size. |
| 262 | * If this is a problem we'll need to introduce a queue |
| 263 | * to set the packet on so we can unwind the stack before |
| 264 | * doing further processing. |
| 265 | */ |
| 266 | if (isr->next) { |
| 267 | IPSEC_STATINC(IPSEC_STAT_OUT_BUNDLESA); |
| 268 | switch ( saidx->dst.sa.sa_family ) { |
| 269 | #ifdef INET |
| 270 | case AF_INET: |
| 271 | return ipsec4_process_packet(m, isr->next, 0,0); |
| 272 | #endif /* INET */ |
| 273 | #ifdef INET6 |
| 274 | case AF_INET6: |
| 275 | return ipsec6_process_packet(m,isr->next); |
| 276 | #endif /* INET6 */ |
| 277 | default : |
| 278 | DPRINTF(("ipsec_process_done: unknown protocol family %u\n" , |
| 279 | saidx->dst.sa.sa_family)); |
| 280 | error = ENXIO; |
| 281 | goto bad; |
| 282 | } |
| 283 | } |
| 284 | |
| 285 | /* |
| 286 | * We're done with IPsec processing, |
| 287 | * mark that we have already processed the packet |
| 288 | * transmit it packet using the appropriate network protocol (IP or IPv6). |
| 289 | */ |
| 290 | |
| 291 | if (ipsec_register_done(m, &error) < 0) |
| 292 | goto bad; |
| 293 | |
| 294 | return ipsec_reinject_ipstack(m, saidx->dst.sa.sa_family); |
| 295 | bad: |
| 296 | m_freem(m); |
| 297 | KEY_FREESAV(&sav); |
| 298 | return (error); |
| 299 | } |
| 300 | |
| 301 | /* |
| 302 | * ipsec_nextisr can return : |
| 303 | * - isr == NULL and error != 0 => something is bad : the packet must be |
| 304 | * discarded |
| 305 | * - isr == NULL and error == 0 => no more rules to apply, ipsec processing |
| 306 | * is done, reinject it in ip stack |
| 307 | * - isr != NULL (error == 0) => we need to apply one rule to the packet |
| 308 | */ |
| 309 | static struct ipsecrequest * |
| 310 | ipsec_nextisr( |
| 311 | struct mbuf *m, |
| 312 | struct ipsecrequest *isr, |
| 313 | int af, |
| 314 | struct secasindex *saidx, |
| 315 | int *error |
| 316 | ) |
| 317 | { |
| 318 | #define IPSEC_OSTAT(x, y, z) \ |
| 319 | do { \ |
| 320 | switch (isr->saidx.proto) { \ |
| 321 | case IPPROTO_ESP: \ |
| 322 | ESP_STATINC(x); \ |
| 323 | break; \ |
| 324 | case IPPROTO_AH: \ |
| 325 | AH_STATINC(y); \ |
| 326 | break; \ |
| 327 | default: \ |
| 328 | IPCOMP_STATINC(z); \ |
| 329 | break; \ |
| 330 | } \ |
| 331 | } while (/*CONSTCOND*/0) |
| 332 | |
| 333 | struct secasvar *sav; |
| 334 | |
| 335 | IPSEC_SPLASSERT_SOFTNET("ipsec_nextisr" ); |
| 336 | IPSEC_ASSERT(af == AF_INET || af == AF_INET6, |
| 337 | ("ipsec_nextisr: invalid address family %u" , af)); |
| 338 | again: |
| 339 | /* |
| 340 | * Craft SA index to search for proper SA. Note that |
| 341 | * we only fillin unspecified SA peers for transport |
| 342 | * mode; for tunnel mode they must already be filled in. |
| 343 | */ |
| 344 | *saidx = isr->saidx; |
| 345 | if (isr->saidx.mode == IPSEC_MODE_TRANSPORT) { |
| 346 | /* Fillin unspecified SA peers only for transport mode */ |
| 347 | if (af == AF_INET) { |
| 348 | struct sockaddr_in *sin; |
| 349 | struct ip *ip = mtod(m, struct ip *); |
| 350 | |
| 351 | if (saidx->src.sa.sa_len == 0) { |
| 352 | sin = &saidx->src.sin; |
| 353 | sin->sin_len = sizeof(*sin); |
| 354 | sin->sin_family = AF_INET; |
| 355 | sin->sin_port = IPSEC_PORT_ANY; |
| 356 | sin->sin_addr = ip->ip_src; |
| 357 | } |
| 358 | if (saidx->dst.sa.sa_len == 0) { |
| 359 | sin = &saidx->dst.sin; |
| 360 | sin->sin_len = sizeof(*sin); |
| 361 | sin->sin_family = AF_INET; |
| 362 | sin->sin_port = IPSEC_PORT_ANY; |
| 363 | sin->sin_addr = ip->ip_dst; |
| 364 | } |
| 365 | } else { |
| 366 | struct sockaddr_in6 *sin6; |
| 367 | struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); |
| 368 | |
| 369 | if (saidx->src.sin6.sin6_len == 0) { |
| 370 | sin6 = (struct sockaddr_in6 *)&saidx->src; |
| 371 | sin6->sin6_len = sizeof(*sin6); |
| 372 | sin6->sin6_family = AF_INET6; |
| 373 | sin6->sin6_port = IPSEC_PORT_ANY; |
| 374 | sin6->sin6_addr = ip6->ip6_src; |
| 375 | if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) { |
| 376 | /* fix scope id for comparing SPD */ |
| 377 | sin6->sin6_addr.s6_addr16[1] = 0; |
| 378 | sin6->sin6_scope_id = |
| 379 | ntohs(ip6->ip6_src.s6_addr16[1]); |
| 380 | } |
| 381 | } |
| 382 | if (saidx->dst.sin6.sin6_len == 0) { |
| 383 | sin6 = (struct sockaddr_in6 *)&saidx->dst; |
| 384 | sin6->sin6_len = sizeof(*sin6); |
| 385 | sin6->sin6_family = AF_INET6; |
| 386 | sin6->sin6_port = IPSEC_PORT_ANY; |
| 387 | sin6->sin6_addr = ip6->ip6_dst; |
| 388 | if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { |
| 389 | /* fix scope id for comparing SPD */ |
| 390 | sin6->sin6_addr.s6_addr16[1] = 0; |
| 391 | sin6->sin6_scope_id = |
| 392 | ntohs(ip6->ip6_dst.s6_addr16[1]); |
| 393 | } |
| 394 | } |
| 395 | } |
| 396 | } |
| 397 | |
| 398 | /* |
| 399 | * Lookup SA and validate it. |
| 400 | */ |
| 401 | *error = key_checkrequest(isr, saidx); |
| 402 | if (*error != 0) { |
| 403 | /* |
| 404 | * IPsec processing is required, but no SA found. |
| 405 | * I assume that key_acquire() had been called |
| 406 | * to get/establish the SA. Here I discard |
| 407 | * this packet because it is responsibility for |
| 408 | * upper layer to retransmit the packet. |
| 409 | */ |
| 410 | IPSEC_STATINC(IPSEC_STAT_OUT_NOSA); |
| 411 | goto bad; |
| 412 | } |
| 413 | sav = isr->sav; |
| 414 | /* sav may be NULL here if we have an USE rule */ |
| 415 | if (sav == NULL) { |
| 416 | IPSEC_ASSERT(ipsec_get_reqlevel(isr) == IPSEC_LEVEL_USE, |
| 417 | ("ipsec_nextisr: no SA found, but required; level %u" , |
| 418 | ipsec_get_reqlevel(isr))); |
| 419 | isr = isr->next; |
| 420 | /* |
| 421 | * No more rules to apply, return NULL isr and no error |
| 422 | * It can happen when the last rules are USE rules |
| 423 | * */ |
| 424 | if (isr == NULL) { |
| 425 | *error = 0; |
| 426 | return isr; |
| 427 | } |
| 428 | goto again; |
| 429 | } |
| 430 | |
| 431 | /* |
| 432 | * Check system global policy controls. |
| 433 | */ |
| 434 | if ((isr->saidx.proto == IPPROTO_ESP && !esp_enable) || |
| 435 | (isr->saidx.proto == IPPROTO_AH && !ah_enable) || |
| 436 | (isr->saidx.proto == IPPROTO_IPCOMP && !ipcomp_enable)) { |
| 437 | DPRINTF(("ipsec_nextisr: IPsec outbound packet dropped due" |
| 438 | " to policy (check your sysctls)\n" )); |
| 439 | IPSEC_OSTAT(ESP_STAT_PDROPS, AH_STAT_PDROPS, |
| 440 | IPCOMP_STAT_PDROPS); |
| 441 | *error = EHOSTUNREACH; |
| 442 | goto bad; |
| 443 | } |
| 444 | |
| 445 | /* |
| 446 | * Sanity check the SA contents for the caller |
| 447 | * before they invoke the xform output method. |
| 448 | */ |
| 449 | if (sav->tdb_xform == NULL) { |
| 450 | DPRINTF(("ipsec_nextisr: no transform for SA\n" )); |
| 451 | IPSEC_OSTAT(ESP_STAT_NOXFORM, AH_STAT_NOXFORM, |
| 452 | IPCOMP_STAT_NOXFORM); |
| 453 | *error = EHOSTUNREACH; |
| 454 | goto bad; |
| 455 | } |
| 456 | return isr; |
| 457 | bad: |
| 458 | IPSEC_ASSERT(*error != 0, ("ipsec_nextisr: error return w/ no error code" )); |
| 459 | return NULL; |
| 460 | #undef IPSEC_OSTAT |
| 461 | } |
| 462 | |
| 463 | #ifdef INET |
| 464 | /* |
| 465 | * IPsec output logic for IPv4. |
| 466 | */ |
| 467 | int |
| 468 | ipsec4_process_packet( |
| 469 | struct mbuf *m, |
| 470 | struct ipsecrequest *isr, |
| 471 | int flags, |
| 472 | int tunalready |
| 473 | ) |
| 474 | { |
| 475 | struct secasindex saidx; |
| 476 | struct secasvar *sav; |
| 477 | struct ip *ip; |
| 478 | int s, error, i, off; |
| 479 | |
| 480 | IPSEC_ASSERT(m != NULL, ("ipsec4_process_packet: null mbuf" )); |
| 481 | IPSEC_ASSERT(isr != NULL, ("ipsec4_process_packet: null isr" )); |
| 482 | |
| 483 | s = splsoftnet(); /* insure SA contents don't change */ |
| 484 | |
| 485 | isr = ipsec_nextisr(m, isr, AF_INET, &saidx, &error); |
| 486 | if (isr == NULL) { |
| 487 | if (error != 0) { |
| 488 | goto bad; |
| 489 | } else { |
| 490 | if (ipsec_register_done(m, &error) < 0) |
| 491 | goto bad; |
| 492 | |
| 493 | splx(s); |
| 494 | return ipsec_reinject_ipstack(m, AF_INET); |
| 495 | } |
| 496 | } |
| 497 | |
| 498 | sav = isr->sav; |
| 499 | if (!tunalready) { |
| 500 | union sockaddr_union *dst = &sav->sah->saidx.dst; |
| 501 | int setdf; |
| 502 | |
| 503 | /* |
| 504 | * Collect IP_DF state from the outer header. |
| 505 | */ |
| 506 | if (dst->sa.sa_family == AF_INET) { |
| 507 | if (m->m_len < sizeof (struct ip) && |
| 508 | (m = m_pullup(m, sizeof (struct ip))) == NULL) { |
| 509 | error = ENOBUFS; |
| 510 | goto bad; |
| 511 | } |
| 512 | ip = mtod(m, struct ip *); |
| 513 | /* Honor system-wide control of how to handle IP_DF */ |
| 514 | switch (ip4_ipsec_dfbit) { |
| 515 | case 0: /* clear in outer header */ |
| 516 | case 1: /* set in outer header */ |
| 517 | setdf = ip4_ipsec_dfbit; |
| 518 | break; |
| 519 | default: /* propagate to outer header */ |
| 520 | setdf = ip->ip_off; |
| 521 | #ifndef __FreeBSD__ |
| 522 | /* On FreeBSD, ip_off and ip_len assumed in host endian. */ |
| 523 | setdf = ntohs(setdf); |
| 524 | #endif |
| 525 | setdf = htons(setdf & IP_DF); |
| 526 | break; |
| 527 | } |
| 528 | } else { |
| 529 | ip = NULL; /* keep compiler happy */ |
| 530 | setdf = 0; |
| 531 | } |
| 532 | /* Do the appropriate encapsulation, if necessary */ |
| 533 | if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */ |
| 534 | dst->sa.sa_family != AF_INET || /* PF mismatch */ |
| 535 | #if 0 |
| 536 | (sav->flags & SADB_X_SAFLAGS_TUNNEL) || /* Tunnel requ'd */ |
| 537 | sav->tdb_xform->xf_type == XF_IP4 || /* ditto */ |
| 538 | #endif |
| 539 | (dst->sa.sa_family == AF_INET && /* Proxy */ |
| 540 | dst->sin.sin_addr.s_addr != INADDR_ANY && |
| 541 | dst->sin.sin_addr.s_addr != ip->ip_dst.s_addr)) { |
| 542 | struct mbuf *mp; |
| 543 | |
| 544 | /* Fix IPv4 header checksum and length */ |
| 545 | if (m->m_len < sizeof (struct ip) && |
| 546 | (m = m_pullup(m, sizeof (struct ip))) == NULL) { |
| 547 | error = ENOBUFS; |
| 548 | goto bad; |
| 549 | } |
| 550 | ip = mtod(m, struct ip *); |
| 551 | ip->ip_len = htons(m->m_pkthdr.len); |
| 552 | ip->ip_sum = 0; |
| 553 | ip->ip_sum = in_cksum(m, ip->ip_hl << 2); |
| 554 | |
| 555 | /* Encapsulate the packet */ |
| 556 | error = ipip_output(m, isr, &mp, 0, 0); |
| 557 | if (mp == NULL && !error) { |
| 558 | /* Should never happen. */ |
| 559 | DPRINTF(("ipsec4_process_packet: ipip_output " |
| 560 | "returns no mbuf and no error!" )); |
| 561 | error = EFAULT; |
| 562 | } |
| 563 | if (error) { |
| 564 | if (mp) { |
| 565 | /* XXX: Should never happen! */ |
| 566 | m_freem(mp); |
| 567 | } |
| 568 | m = NULL; /* ipip_output() already freed it */ |
| 569 | goto bad; |
| 570 | } |
| 571 | m = mp, mp = NULL; |
| 572 | /* |
| 573 | * ipip_output clears IP_DF in the new header. If |
| 574 | * we need to propagate IP_DF from the outer header, |
| 575 | * then we have to do it here. |
| 576 | * |
| 577 | * XXX shouldn't assume what ipip_output does. |
| 578 | */ |
| 579 | if (dst->sa.sa_family == AF_INET && setdf) { |
| 580 | if (m->m_len < sizeof (struct ip) && |
| 581 | (m = m_pullup(m, sizeof (struct ip))) == NULL) { |
| 582 | error = ENOBUFS; |
| 583 | goto bad; |
| 584 | } |
| 585 | ip = mtod(m, struct ip *); |
| 586 | ip->ip_off |= IP_OFF_CONVERT(IP_DF); |
| 587 | } |
| 588 | } |
| 589 | } |
| 590 | |
| 591 | /* |
| 592 | * Dispatch to the appropriate IPsec transform logic. The |
| 593 | * packet will be returned for transmission after crypto |
| 594 | * processing, etc. are completed. For encapsulation we |
| 595 | * bypass this call because of the explicit call done above |
| 596 | * (necessary to deal with IP_DF handling for IPv4). |
| 597 | * |
| 598 | * NB: m & sav are ``passed to caller'' who's reponsible for |
| 599 | * for reclaiming their resources. |
| 600 | */ |
| 601 | if (sav->tdb_xform->xf_type != XF_IP4) { |
| 602 | union sockaddr_union *dst = &sav->sah->saidx.dst; |
| 603 | if (dst->sa.sa_family == AF_INET) { |
| 604 | ip = mtod(m, struct ip *); |
| 605 | i = ip->ip_hl << 2; |
| 606 | off = offsetof(struct ip, ip_p); |
| 607 | } else { |
| 608 | i = sizeof(struct ip6_hdr); |
| 609 | off = offsetof(struct ip6_hdr, ip6_nxt); |
| 610 | } |
| 611 | error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off); |
| 612 | } else { |
| 613 | error = ipsec_process_done(m, isr); |
| 614 | } |
| 615 | splx(s); |
| 616 | return error; |
| 617 | bad: |
| 618 | splx(s); |
| 619 | if (m) |
| 620 | m_freem(m); |
| 621 | return error; |
| 622 | } |
| 623 | #endif |
| 624 | |
| 625 | #ifdef INET6 |
| 626 | static void |
| 627 | compute_ipsec_pos(struct mbuf *m, int *i, int *off) |
| 628 | { |
| 629 | int nxt; |
| 630 | struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr*); |
| 631 | struct ip6_ext ip6e; |
| 632 | int dstopt = 0; |
| 633 | |
| 634 | *i = sizeof(struct ip6_hdr); |
| 635 | *off = offsetof(struct ip6_hdr, ip6_nxt); |
| 636 | nxt = ip6->ip6_nxt; |
| 637 | |
| 638 | /* |
| 639 | * chase mbuf chain to find the appropriate place to |
| 640 | * put AH/ESP/IPcomp header. |
| 641 | * IPv6 hbh dest1 rthdr ah* [esp* dest2 payload] |
| 642 | */ |
| 643 | do { |
| 644 | switch (nxt) { |
| 645 | case IPPROTO_AH: |
| 646 | case IPPROTO_ESP: |
| 647 | case IPPROTO_IPCOMP: |
| 648 | /* |
| 649 | * we should not skip security header added |
| 650 | * beforehand. |
| 651 | */ |
| 652 | return; |
| 653 | |
| 654 | case IPPROTO_HOPOPTS: |
| 655 | case IPPROTO_DSTOPTS: |
| 656 | case IPPROTO_ROUTING: |
| 657 | /* |
| 658 | * if we see 2nd destination option header, |
| 659 | * we should stop there. |
| 660 | */ |
| 661 | if (nxt == IPPROTO_DSTOPTS && dstopt) |
| 662 | return; |
| 663 | |
| 664 | if (nxt == IPPROTO_DSTOPTS) { |
| 665 | /* |
| 666 | * seen 1st or 2nd destination option. |
| 667 | * next time we see one, it must be 2nd. |
| 668 | */ |
| 669 | dstopt = 1; |
| 670 | } else if (nxt == IPPROTO_ROUTING) { |
| 671 | /* |
| 672 | * if we see destionation option next |
| 673 | * time, it must be dest2. |
| 674 | */ |
| 675 | dstopt = 2; |
| 676 | } |
| 677 | |
| 678 | /* skip this header */ |
| 679 | m_copydata(m, *i, sizeof(ip6e), &ip6e); |
| 680 | nxt = ip6e.ip6e_nxt; |
| 681 | *off = *i + offsetof(struct ip6_ext, ip6e_nxt); |
| 682 | /* |
| 683 | * we will never see nxt == IPPROTO_AH |
| 684 | * so it is safe to omit AH case. |
| 685 | */ |
| 686 | *i += (ip6e.ip6e_len + 1) << 3; |
| 687 | break; |
| 688 | default: |
| 689 | return; |
| 690 | } |
| 691 | } while (*i < m->m_pkthdr.len); |
| 692 | } |
| 693 | |
| 694 | static int |
| 695 | in6_sa_equal_addrwithscope(const struct sockaddr_in6 *sa, const struct in6_addr *ia) |
| 696 | { |
| 697 | struct in6_addr ia2; |
| 698 | |
| 699 | memcpy(&ia2, &sa->sin6_addr, sizeof(ia2)); |
| 700 | if (IN6_IS_SCOPE_LINKLOCAL(&sa->sin6_addr)) |
| 701 | ia2.s6_addr16[1] = htons(sa->sin6_scope_id); |
| 702 | |
| 703 | return IN6_ARE_ADDR_EQUAL(ia, &ia2); |
| 704 | } |
| 705 | |
| 706 | int |
| 707 | ipsec6_process_packet( |
| 708 | struct mbuf *m, |
| 709 | struct ipsecrequest *isr |
| 710 | ) |
| 711 | { |
| 712 | struct secasindex saidx; |
| 713 | struct secasvar *sav; |
| 714 | struct ip6_hdr *ip6; |
| 715 | int s, error, i, off; |
| 716 | union sockaddr_union *dst; |
| 717 | |
| 718 | IPSEC_ASSERT(m != NULL, ("ipsec6_process_packet: null mbuf" )); |
| 719 | IPSEC_ASSERT(isr != NULL, ("ipsec6_process_packet: null isr" )); |
| 720 | |
| 721 | s = splsoftnet(); /* insure SA contents don't change */ |
| 722 | |
| 723 | isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error); |
| 724 | if (isr == NULL) { |
| 725 | if (error != 0) { |
| 726 | /* XXX Should we send a notification ? */ |
| 727 | goto bad; |
| 728 | } else { |
| 729 | if (ipsec_register_done(m, &error) < 0) |
| 730 | goto bad; |
| 731 | |
| 732 | splx(s); |
| 733 | return ipsec_reinject_ipstack(m, AF_INET6); |
| 734 | } |
| 735 | } |
| 736 | |
| 737 | sav = isr->sav; |
| 738 | dst = &sav->sah->saidx.dst; |
| 739 | |
| 740 | ip6 = mtod(m, struct ip6_hdr *); /* XXX */ |
| 741 | |
| 742 | /* Do the appropriate encapsulation, if necessary */ |
| 743 | if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */ |
| 744 | dst->sa.sa_family != AF_INET6 || /* PF mismatch */ |
| 745 | ((dst->sa.sa_family == AF_INET6) && |
| 746 | (!IN6_IS_ADDR_UNSPECIFIED(&dst->sin6.sin6_addr)) && |
| 747 | (!in6_sa_equal_addrwithscope(&dst->sin6, |
| 748 | &ip6->ip6_dst)))) { |
| 749 | struct mbuf *mp; |
| 750 | |
| 751 | /* Fix IPv6 header payload length. */ |
| 752 | if (m->m_len < sizeof(struct ip6_hdr)) |
| 753 | if ((m = m_pullup(m,sizeof(struct ip6_hdr))) == NULL) |
| 754 | return ENOBUFS; |
| 755 | |
| 756 | if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) { |
| 757 | /* No jumbogram support. */ |
| 758 | m_freem(m); |
| 759 | return ENXIO; /*XXX*/ |
| 760 | } |
| 761 | |
| 762 | ip6 = mtod(m, struct ip6_hdr *); |
| 763 | ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6)); |
| 764 | |
| 765 | /* Encapsulate the packet */ |
| 766 | error = ipip_output(m, isr, &mp, 0, 0); |
| 767 | if (mp == NULL && !error) { |
| 768 | /* Should never happen. */ |
| 769 | DPRINTF(("ipsec6_process_packet: ipip_output " |
| 770 | "returns no mbuf and no error!" )); |
| 771 | error = EFAULT; |
| 772 | } |
| 773 | |
| 774 | if (error) { |
| 775 | if (mp) { |
| 776 | /* XXX: Should never happen! */ |
| 777 | m_freem(mp); |
| 778 | } |
| 779 | m = NULL; /* ipip_output() already freed it */ |
| 780 | goto bad; |
| 781 | } |
| 782 | |
| 783 | m = mp; |
| 784 | mp = NULL; |
| 785 | } |
| 786 | |
| 787 | if (dst->sa.sa_family == AF_INET) { |
| 788 | struct ip *ip; |
| 789 | ip = mtod(m, struct ip *); |
| 790 | i = ip->ip_hl << 2; |
| 791 | off = offsetof(struct ip, ip_p); |
| 792 | } else { |
| 793 | compute_ipsec_pos(m, &i, &off); |
| 794 | } |
| 795 | error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off); |
| 796 | splx(s); |
| 797 | return error; |
| 798 | bad: |
| 799 | splx(s); |
| 800 | if (m) |
| 801 | m_freem(m); |
| 802 | return error; |
| 803 | } |
| 804 | #endif /*INET6*/ |
| 805 | |