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