1 /* $OpenBSD: ipsec_output.c,v 1.20 2001/12/06 22:52:10 angelos 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 <sys/param.h> 24 #include <sys/systm.h> 25 #include <sys/mbuf.h> 26 #include <sys/socket.h> 27 #include <sys/kernel.h> 28 29 #include <net/if.h> 30 #include <net/route.h> 31 32 #ifdef INET 33 #include <netinet/in.h> 34 #include <netinet/in_systm.h> 35 #include <netinet/ip.h> 36 #include <netinet/in_pcb.h> 37 #include <netinet/ip_var.h> 38 #endif /* INET */ 39 40 #ifdef INET6 41 #ifndef INET 42 #include <netinet/in.h> 43 #endif 44 #include <netinet6/in6_var.h> 45 #endif /* INET6 */ 46 47 #include <netinet/ip_ipsp.h> 48 #include <netinet/ip_ah.h> 49 #include <netinet/ip_esp.h> 50 #include <netinet/ip_ipcomp.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 /* 60 * Loop over a tdb chain, taking into consideration protocol tunneling. The 61 * fourth argument is set if the first encapsulation header is already in 62 * place. 63 */ 64 int 65 ipsp_process_packet(struct mbuf *m, struct tdb *tdb, int af, int tunalready) 66 { 67 struct timeval tv; 68 int i, off, error; 69 struct mbuf *mp; 70 71 #ifdef INET 72 int setdf = 0; 73 struct ip *ip; 74 #endif /* INET */ 75 #ifdef INET6 76 struct ip6_hdr *ip6; 77 #endif /* INET6 */ 78 79 /* Check that the transform is allowed by the administrator. */ 80 if ((tdb->tdb_sproto == IPPROTO_ESP && !esp_enable) || 81 (tdb->tdb_sproto == IPPROTO_AH && !ah_enable) || 82 (tdb->tdb_sproto == IPPROTO_IPCOMP && !ipcomp_enable)) { 83 DPRINTF(("ipsp_process_packet(): IPSec outbound packet " 84 "dropped due to policy (check your sysctls)\n")); 85 m_freem(m); 86 return EHOSTUNREACH; 87 } 88 89 /* Sanity check. */ 90 if (!tdb->tdb_xform) { 91 DPRINTF(("ipsp_process_packet(): uninitialized TDB\n")); 92 m_freem(m); 93 return EHOSTUNREACH; 94 } 95 96 /* Check if the SPI is invalid. */ 97 if (tdb->tdb_flags & TDBF_INVALID) { 98 DPRINTF(("ipsp_process_packet(): attempt to use invalid " 99 "SA %s/%08x/%u\n", ipsp_address(tdb->tdb_dst), 100 ntohl(tdb->tdb_spi), tdb->tdb_sproto)); 101 m_freem(m); 102 return ENXIO; 103 } 104 105 /* Check that the network protocol is supported */ 106 switch (tdb->tdb_dst.sa.sa_family) { 107 #ifdef INET 108 case AF_INET: 109 break; 110 #endif /* INET */ 111 112 #ifdef INET6 113 case AF_INET6: 114 break; 115 #endif /* INET6 */ 116 117 default: 118 DPRINTF(("ipsp_process_packet(): attempt to use " 119 "SA %s/%08x/%u for protocol family %d\n", 120 ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi), 121 tdb->tdb_sproto, tdb->tdb_dst.sa.sa_family)); 122 m_freem(m); 123 return ENXIO; 124 } 125 126 /* 127 * Register first use if applicable, setup relevant expiration timer. 128 */ 129 if (tdb->tdb_first_use == 0) { 130 int pri; 131 132 pri = splhigh(); 133 tdb->tdb_first_use = time.tv_sec; 134 splx(pri); 135 136 tv.tv_usec = 0; 137 138 tv.tv_sec = tdb->tdb_first_use + tdb->tdb_exp_first_use; 139 if (tdb->tdb_flags & TDBF_FIRSTUSE) 140 timeout_add(&tdb->tdb_first_tmo, 141 hzto(&tv)); 142 143 tv.tv_sec = tdb->tdb_first_use + tdb->tdb_soft_first_use; 144 if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE) 145 timeout_add(&tdb->tdb_sfirst_tmo, 146 hzto(&tv)); 147 } 148 149 /* 150 * Check for tunneling if we don't have the first header in place. 151 * When doing Ethernet-over-IP, we are handed an already-encapsulated 152 * frame, so we don't need to re-encapsulate. 153 */ 154 if (tunalready == 0) { 155 /* 156 * If the target protocol family is different, we know we'll be 157 * doing tunneling. 158 */ 159 if (af == tdb->tdb_dst.sa.sa_family) { 160 #ifdef INET 161 if (af == AF_INET) 162 i = sizeof(struct ip); 163 #endif /* INET */ 164 165 #ifdef INET6 166 if (af == AF_INET6) 167 i = sizeof(struct ip6_hdr); 168 #endif /* INET6 */ 169 170 /* Bring the network header in the first mbuf. */ 171 if (m->m_len < i) { 172 if ((m = m_pullup(m, i)) == NULL) 173 return ENOBUFS; 174 } 175 176 #ifdef INET 177 ip = mtod(m, struct ip *); 178 179 /* 180 * This is not a bridge packet, remember if we 181 * had IP_DF. 182 */ 183 setdf = ntohs(ip->ip_off) & IP_DF; 184 #endif /* INET */ 185 186 #ifdef INET6 187 ip6 = mtod(m, struct ip6_hdr *); 188 #endif /* INET6 */ 189 } 190 191 /* Do the appropriate encapsulation, if necessary. */ 192 if ((tdb->tdb_dst.sa.sa_family != af) || /* PF mismatch */ 193 (tdb->tdb_flags & TDBF_TUNNELING) || /* Tunneling needed */ 194 (tdb->tdb_xform->xf_type == XF_IP4) || /* ditto */ 195 #ifdef INET 196 ((tdb->tdb_dst.sa.sa_family == AF_INET) && 197 (tdb->tdb_dst.sin.sin_addr.s_addr != INADDR_ANY) && 198 (tdb->tdb_dst.sin.sin_addr.s_addr != ip->ip_dst.s_addr)) || 199 #endif /* INET */ 200 #ifdef INET6 201 ((tdb->tdb_dst.sa.sa_family == AF_INET6) && 202 (!IN6_IS_ADDR_UNSPECIFIED(&tdb->tdb_dst.sin6.sin6_addr)) && 203 (!IN6_ARE_ADDR_EQUAL(&tdb->tdb_dst.sin6.sin6_addr, 204 &ip6->ip6_dst))) || 205 #endif /* INET6 */ 206 0) { 207 #ifdef INET 208 /* Fix IPv4 header checksum and length. */ 209 if (af == AF_INET) { 210 if (m->m_len < sizeof(struct ip)) 211 if ((m = m_pullup(m, 212 sizeof(struct ip))) == NULL) 213 return ENOBUFS; 214 215 ip = mtod(m, struct ip *); 216 ip->ip_len = htons(m->m_pkthdr.len); 217 ip->ip_sum = 0; 218 ip->ip_sum = in_cksum(m, ip->ip_hl << 2); 219 } 220 #endif /* INET */ 221 222 #ifdef INET6 223 /* Fix IPv6 header payload length. */ 224 if (af == AF_INET6) { 225 if (m->m_len < sizeof(struct ip6_hdr)) 226 if ((m = m_pullup(m, 227 sizeof(struct ip6_hdr))) == NULL) 228 return ENOBUFS; 229 230 if (m->m_pkthdr.len - sizeof(*ip6) > 231 IPV6_MAXPACKET) { 232 /* No jumbogram support. */ 233 m_freem(m); 234 return ENXIO; /*?*/ 235 } 236 ip6 = mtod(m, struct ip6_hdr *); 237 ip6->ip6_plen = htons(m->m_pkthdr.len 238 - sizeof(*ip6)); 239 } 240 #endif /* INET6 */ 241 242 /* Encapsulate -- the last two arguments are unused. */ 243 error = ipip_output(m, tdb, &mp, 0, 0); 244 if ((mp == NULL) && (!error)) 245 error = EFAULT; 246 if (error) { 247 if (mp) { 248 m_freem(mp); 249 mp = NULL; 250 } 251 return error; 252 } 253 254 m = mp; 255 mp = NULL; 256 257 #ifdef INET 258 if (tdb->tdb_dst.sa.sa_family == AF_INET && setdf) { 259 ip = mtod(m, struct ip *); 260 if (m->m_len < sizeof(struct ip)) 261 if ((m = m_pullup(m, 262 sizeof(struct ip))) == NULL) 263 return ENOBUFS; 264 265 NTOHS(ip->ip_off); 266 ip->ip_off |= IP_DF; 267 HTONS(ip->ip_off); 268 } 269 270 /* Remember that we appended a tunnel header. */ 271 tdb->tdb_flags |= TDBF_USEDTUNNEL; 272 #endif 273 } 274 275 /* We may be done with this TDB */ 276 if (tdb->tdb_xform->xf_type == XF_IP4) 277 return ipsp_process_done(m, tdb); 278 } else { 279 /* 280 * If this is just an IP-IP TDB and we're told there's 281 * already an encapsulation header, move on. 282 */ 283 if (tdb->tdb_xform->xf_type == XF_IP4) 284 return ipsp_process_done(m, tdb); 285 } 286 287 /* Extract some information off the headers. */ 288 switch (tdb->tdb_dst.sa.sa_family) { 289 #ifdef INET 290 case AF_INET: 291 ip = mtod(m, struct ip *); 292 i = ip->ip_hl << 2; 293 off = offsetof(struct ip, ip_p); 294 break; 295 #endif /* INET */ 296 297 #ifdef INET6 298 case AF_INET6: 299 ip6 = mtod(m, struct ip6_hdr *); 300 i = sizeof(struct ip6_hdr); 301 off = offsetof(struct ip6_hdr, ip6_nxt); 302 break; 303 #endif /* INET6 */ 304 } 305 306 /* Non expansion policy for IPCOMP */ 307 if (tdb->tdb_sproto == IPPROTO_IPCOMP) { 308 if ((m->m_pkthdr.len - i) < tdb->tdb_compalgxform->minlen) { 309 /* No need to compress, leave the packet untouched */ 310 return ipsp_process_done(m, tdb); 311 } 312 } 313 314 /* Invoke the IPsec transform. */ 315 return (*(tdb->tdb_xform->xf_output))(m, tdb, NULL, i, off); 316 } 317 318 /* 319 * Called by the IPsec output transform callbacks, to transmit the packet 320 * or do further processing, as necessary. 321 */ 322 int 323 ipsp_process_done(struct mbuf *m, struct tdb *tdb) 324 { 325 #ifdef INET 326 struct ip *ip; 327 #endif /* INET */ 328 329 #ifdef INET6 330 struct ip6_hdr *ip6; 331 #endif /* INET6 */ 332 333 struct tdb_ident *tdbi; 334 struct m_tag *mtag; 335 336 tdb->tdb_last_used = time.tv_sec; 337 338 switch (tdb->tdb_dst.sa.sa_family) { 339 #ifdef INET 340 case AF_INET: 341 /* Fix the header length, for AH processing. */ 342 if (tdb->tdb_dst.sa.sa_family == AF_INET) { 343 ip = mtod(m, struct ip *); 344 ip->ip_len = htons(m->m_pkthdr.len); 345 } 346 break; 347 #endif /* INET */ 348 349 #ifdef INET6 350 case AF_INET6: 351 /* Fix the header length, for AH processing. */ 352 if (tdb->tdb_dst.sa.sa_family == AF_INET6) { 353 if (m->m_pkthdr.len < sizeof(*ip6)) { 354 m_freem(m); 355 return ENXIO; 356 } 357 if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) { 358 /* No jumbogram support. */ 359 m_freem(m); 360 return ENXIO; /*?*/ 361 } 362 ip6 = mtod(m, struct ip6_hdr *); 363 ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6)); 364 } 365 break; 366 #endif /* INET6 */ 367 368 default: 369 m_freem(m); 370 DPRINTF(("ipsp_process_done(): unknown protocol family (%d)\n", 371 tdb->tdb_dst.sa.sa_family)); 372 return ENXIO; 373 } 374 375 /* 376 * Add a record of what we've done or what needs to be done to the 377 * packet. 378 */ 379 if ((tdb->tdb_flags & TDBF_SKIPCRYPTO) == 0) 380 mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_DONE, 381 sizeof(struct tdb_ident), 382 M_NOWAIT); 383 else 384 mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED, 385 sizeof(struct tdb_ident), M_NOWAIT); 386 387 if (mtag == NULL) { 388 m_freem(m); 389 DPRINTF(("ipsp_process_done(): could not allocate packet " 390 "tag\n")); 391 return ENOMEM; 392 } 393 394 tdbi = (struct tdb_ident *)(mtag + 1); 395 bcopy(&tdb->tdb_dst, &tdbi->dst, sizeof(union sockaddr_union)); 396 tdbi->proto = tdb->tdb_sproto; 397 tdbi->spi = tdb->tdb_spi; 398 399 m_tag_prepend(m, mtag); 400 401 /* If there's another (bundled) TDB to apply, do so. */ 402 if (tdb->tdb_onext) 403 return ipsp_process_packet(m, tdb->tdb_onext, 404 tdb->tdb_dst.sa.sa_family, 0); 405 406 /* 407 * We're done with IPsec processing, transmit the packet using the 408 * appropriate network protocol (IP or IPv6). SPD lookup will be 409 * performed again there. 410 */ 411 switch (tdb->tdb_dst.sa.sa_family) { 412 #ifdef INET 413 case AF_INET: 414 NTOHS(ip->ip_len); 415 NTOHS(ip->ip_off); 416 417 return ip_output(m, NULL, NULL, IP_RAWOUTPUT, NULL, NULL); 418 #endif /* INET */ 419 420 #ifdef INET6 421 case AF_INET6: 422 /* 423 * We don't need massage, IPv6 header fields are always in 424 * net endian. 425 */ 426 return ip6_output(m, NULL, NULL, 0, NULL, NULL); 427 #endif /* INET6 */ 428 } 429 return EINVAL; /* Not reached. */ 430 } 431 432 ssize_t 433 ipsec_hdrsz(struct tdb *tdbp) 434 { 435 ssize_t adjust; 436 437 switch (tdbp->tdb_sproto) { 438 case IPPROTO_ESP: 439 if (tdbp->tdb_encalgxform == NULL) 440 return (-1); 441 442 /* Header length */ 443 if (tdbp->tdb_flags & TDBF_NOREPLAY) 444 adjust = sizeof(u_int32_t) + tdbp->tdb_ivlen; 445 else 446 adjust = 2 * sizeof(u_int32_t) + tdbp->tdb_ivlen; 447 /* Authenticator */ 448 if (tdbp->tdb_authalgxform != NULL) 449 adjust += AH_HMAC_HASHLEN; 450 /* Padding */ 451 adjust += tdbp->tdb_encalgxform->blocksize; 452 break; 453 454 case IPPROTO_AH: 455 if (tdbp->tdb_authalgxform == NULL) 456 return (-1); 457 458 if (!(tdbp->tdb_flags & TDBF_NOREPLAY)) 459 adjust = AH_FLENGTH + sizeof(u_int32_t); 460 else 461 adjust = AH_FLENGTH; 462 adjust += tdbp->tdb_authalgxform->authsize; 463 break; 464 465 default: 466 return (-1); 467 } 468 469 if (!(tdbp->tdb_flags & TDBF_TUNNELING) && 470 !(tdbp->tdb_flags & TDBF_USEDTUNNEL)) 471 return (adjust); 472 473 switch (tdbp->tdb_dst.sa.sa_family) { 474 #ifdef INET 475 case AF_INET: 476 adjust += sizeof(struct ip); 477 break; 478 #endif /* INET */ 479 #ifdef INET6 480 case AF_INET6: 481 adjust += sizeof(struct ip6_hdr); 482 break; 483 #endif /* INET6 */ 484 } 485 486 return (adjust); 487 } 488 489 void 490 ipsec_adjust_mtu(struct mbuf *m, u_int32_t mtu) 491 { 492 struct tdb_ident *tdbi; 493 struct tdb *tdbp; 494 struct m_tag *mtag; 495 ssize_t adjust; 496 int s; 497 498 s = spltdb(); 499 500 for (mtag = m_tag_find(m, PACKET_TAG_IPSEC_OUT_DONE, NULL); mtag; 501 mtag = m_tag_find(m, PACKET_TAG_IPSEC_OUT_DONE, mtag)) { 502 tdbi = (struct tdb_ident *)(mtag + 1); 503 tdbp = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto); 504 if (tdbp == NULL) 505 break; 506 507 if ((adjust = ipsec_hdrsz(tdbp)) == -1) 508 break; 509 510 mtu -= adjust; 511 tdbp->tdb_mtu = mtu; 512 tdbp->tdb_mtutimeout = time.tv_sec + ip_mtudisc_timeout; 513 } 514 515 splx(s); 516 } 517