| File: | netinet/ipsec_input.c |
| Warning: | line 594, column 2 Undefined or garbage value returned to caller |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: ipsec_input.c,v 1.206 2023/09/16 09:33:27 mpi Exp $ */ | ||||
| 2 | /* | ||||
| 3 | * The authors of this code are John Ioannidis (ji@tla.org), | ||||
| 4 | * Angelos D. Keromytis (kermit@csd.uch.gr) and | ||||
| 5 | * Niels Provos (provos@physnet.uni-hamburg.de). | ||||
| 6 | * | ||||
| 7 | * This code was written by John Ioannidis for BSD/OS in Athens, Greece, | ||||
| 8 | * in November 1995. | ||||
| 9 | * | ||||
| 10 | * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996, | ||||
| 11 | * by Angelos D. Keromytis. | ||||
| 12 | * | ||||
| 13 | * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis | ||||
| 14 | * and Niels Provos. | ||||
| 15 | * | ||||
| 16 | * Additional features in 1999 by Angelos D. Keromytis. | ||||
| 17 | * | ||||
| 18 | * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis, | ||||
| 19 | * Angelos D. Keromytis and Niels Provos. | ||||
| 20 | * Copyright (c) 2001, Angelos D. Keromytis. | ||||
| 21 | * | ||||
| 22 | * Permission to use, copy, and modify this software with or without fee | ||||
| 23 | * is hereby granted, provided that this entire notice is included in | ||||
| 24 | * all copies of any software which is or includes a copy or | ||||
| 25 | * modification of this software. | ||||
| 26 | * You may use this code under the GNU public license if you so wish. Please | ||||
| 27 | * contribute changes back to the authors under this freer than GPL license | ||||
| 28 | * so that we may further the use of strong encryption without limitations to | ||||
| 29 | * all. | ||||
| 30 | * | ||||
| 31 | * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR | ||||
| 32 | * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY | ||||
| 33 | * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE | ||||
| 34 | * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR | ||||
| 35 | * PURPOSE. | ||||
| 36 | */ | ||||
| 37 | |||||
| 38 | #include "pf.h" | ||||
| 39 | #include "sec.h" | ||||
| 40 | |||||
| 41 | #include <sys/param.h> | ||||
| 42 | #include <sys/systm.h> | ||||
| 43 | #include <sys/protosw.h> | ||||
| 44 | #include <sys/mbuf.h> | ||||
| 45 | #include <sys/socket.h> | ||||
| 46 | #include <sys/sysctl.h> | ||||
| 47 | #include <sys/kernel.h> | ||||
| 48 | #include <sys/timeout.h> | ||||
| 49 | |||||
| 50 | #include <net/if.h> | ||||
| 51 | #include <net/if_var.h> | ||||
| 52 | #include <net/netisr.h> | ||||
| 53 | #include <net/bpf.h> | ||||
| 54 | #include <net/route.h> | ||||
| 55 | |||||
| 56 | #include <netinet/in.h> | ||||
| 57 | #include <netinet/ip.h> | ||||
| 58 | #include <netinet/ip_var.h> | ||||
| 59 | #include <netinet/ip_icmp.h> | ||||
| 60 | #include <netinet/tcp.h> | ||||
| 61 | #include <netinet/udp.h> | ||||
| 62 | |||||
| 63 | #if NPF1 > 0 | ||||
| 64 | #include <net/pfvar.h> | ||||
| 65 | #endif | ||||
| 66 | |||||
| 67 | #if NSEC1 > 0 | ||||
| 68 | #include <net/if_sec.h> | ||||
| 69 | #endif | ||||
| 70 | |||||
| 71 | #ifdef INET61 | ||||
| 72 | #include <netinet6/in6_var.h> | ||||
| 73 | #include <netinet/ip6.h> | ||||
| 74 | #include <netinet6/ip6_var.h> | ||||
| 75 | #endif /* INET6 */ | ||||
| 76 | |||||
| 77 | #include <netinet/ip_ipsp.h> | ||||
| 78 | #include <netinet/ip_esp.h> | ||||
| 79 | #include <netinet/ip_ah.h> | ||||
| 80 | #include <netinet/ip_ipcomp.h> | ||||
| 81 | |||||
| 82 | #include <net/if_enc.h> | ||||
| 83 | |||||
| 84 | #include <crypto/cryptodev.h> | ||||
| 85 | #include <crypto/xform.h> | ||||
| 86 | |||||
| 87 | #include "bpfilter.h" | ||||
| 88 | |||||
| 89 | void ipsec_common_ctlinput(u_int, int, struct sockaddr *, void *, int); | ||||
| 90 | |||||
| 91 | #ifdef ENCDEBUG | ||||
| 92 | #define DPRINTF(fmt, args...)do { } while (0) \ | ||||
| 93 | do { \ | ||||
| 94 | if (encdebug) \ | ||||
| 95 | printf("%s: " fmt "\n", __func__, ## args); \ | ||||
| 96 | } while (0) | ||||
| 97 | #else | ||||
| 98 | #define DPRINTF(fmt, args...)do { } while (0) \ | ||||
| 99 | do { } while (0) | ||||
| 100 | #endif | ||||
| 101 | |||||
| 102 | /* sysctl variables */ | ||||
| 103 | int encdebug = 0; | ||||
| 104 | int ipsec_keep_invalid = IPSEC_DEFAULT_EMBRYONIC_SA_TIMEOUT60; | ||||
| 105 | int ipsec_require_pfs = IPSEC_DEFAULT_PFS1; | ||||
| 106 | int ipsec_soft_allocations = IPSEC_DEFAULT_SOFT_ALLOCATIONS0; | ||||
| 107 | int ipsec_exp_allocations = IPSEC_DEFAULT_EXP_ALLOCATIONS0; | ||||
| 108 | int ipsec_soft_bytes = IPSEC_DEFAULT_SOFT_BYTES0; | ||||
| 109 | int ipsec_exp_bytes = IPSEC_DEFAULT_EXP_BYTES0; | ||||
| 110 | int ipsec_soft_timeout = IPSEC_DEFAULT_SOFT_TIMEOUT80000; | ||||
| 111 | int ipsec_exp_timeout = IPSEC_DEFAULT_EXP_TIMEOUT86400; | ||||
| 112 | int ipsec_soft_first_use = IPSEC_DEFAULT_SOFT_FIRST_USE3600; | ||||
| 113 | int ipsec_exp_first_use = IPSEC_DEFAULT_EXP_FIRST_USE7200; | ||||
| 114 | int ipsec_expire_acquire = IPSEC_DEFAULT_EXPIRE_ACQUIRE30; | ||||
| 115 | |||||
| 116 | int esp_enable = 1; | ||||
| 117 | int ah_enable = 1; | ||||
| 118 | int ipcomp_enable = 0; | ||||
| 119 | |||||
| 120 | const struct sysctl_bounded_args espctl_vars[] = { | ||||
| 121 | {ESPCTL_ENABLE1, &esp_enable, 0, 1}, | ||||
| 122 | {ESPCTL_UDPENCAP_ENABLE2, &udpencap_enable, 0, 1}, | ||||
| 123 | {ESPCTL_UDPENCAP_PORT3, &udpencap_port, 0, 65535}, | ||||
| 124 | }; | ||||
| 125 | const struct sysctl_bounded_args ahctl_vars[] = { | ||||
| 126 | {AHCTL_ENABLE1, &ah_enable, 0, 1}, | ||||
| 127 | }; | ||||
| 128 | const struct sysctl_bounded_args ipcompctl_vars[] = { | ||||
| 129 | {IPCOMPCTL_ENABLE1, &ipcomp_enable, 0, 1}, | ||||
| 130 | }; | ||||
| 131 | |||||
| 132 | struct cpumem *espcounters; | ||||
| 133 | struct cpumem *ahcounters; | ||||
| 134 | struct cpumem *ipcompcounters; | ||||
| 135 | struct cpumem *ipseccounters; | ||||
| 136 | |||||
| 137 | char ipsec_def_enc[20]; | ||||
| 138 | char ipsec_def_auth[20]; | ||||
| 139 | char ipsec_def_comp[20]; | ||||
| 140 | |||||
| 141 | const struct sysctl_bounded_args ipsecctl_vars[] = { | ||||
| 142 | { IPSEC_ENCDEBUG12, &encdebug, 0, 1 }, | ||||
| 143 | { IPSEC_EXPIRE_ACQUIRE14, &ipsec_expire_acquire, 0, INT_MAX0x7fffffff }, | ||||
| 144 | { IPSEC_EMBRYONIC_SA_TIMEOUT15, &ipsec_keep_invalid, 0, INT_MAX0x7fffffff }, | ||||
| 145 | { IPSEC_REQUIRE_PFS16, &ipsec_require_pfs, 0, 1 }, | ||||
| 146 | { IPSEC_SOFT_ALLOCATIONS17, &ipsec_soft_allocations, 0, INT_MAX0x7fffffff }, | ||||
| 147 | { IPSEC_ALLOCATIONS18, &ipsec_exp_allocations, 0, INT_MAX0x7fffffff }, | ||||
| 148 | { IPSEC_SOFT_BYTES19, &ipsec_soft_bytes, 0, INT_MAX0x7fffffff }, | ||||
| 149 | { IPSEC_BYTES20, &ipsec_exp_bytes, 0, INT_MAX0x7fffffff }, | ||||
| 150 | { IPSEC_TIMEOUT21, &ipsec_exp_timeout, 0, INT_MAX0x7fffffff }, | ||||
| 151 | { IPSEC_SOFT_TIMEOUT22, &ipsec_soft_timeout,0, INT_MAX0x7fffffff }, | ||||
| 152 | { IPSEC_SOFT_FIRSTUSE23, &ipsec_soft_first_use, 0, INT_MAX0x7fffffff }, | ||||
| 153 | { IPSEC_FIRSTUSE24, &ipsec_exp_first_use, 0, INT_MAX0x7fffffff }, | ||||
| 154 | }; | ||||
| 155 | |||||
| 156 | int esp_sysctl_espstat(void *, size_t *, void *); | ||||
| 157 | int ah_sysctl_ahstat(void *, size_t *, void *); | ||||
| 158 | int ipcomp_sysctl_ipcompstat(void *, size_t *, void *); | ||||
| 159 | int ipsec_sysctl_ipsecstat(void *, size_t *, void *); | ||||
| 160 | |||||
| 161 | void | ||||
| 162 | ipsec_init(void) | ||||
| 163 | { | ||||
| 164 | espcounters = counters_alloc(esps_ncounters); | ||||
| 165 | ahcounters = counters_alloc(ahs_ncounters); | ||||
| 166 | ipcompcounters = counters_alloc(ipcomps_ncounters); | ||||
| 167 | ipseccounters = counters_alloc(ipsec_ncounters); | ||||
| 168 | |||||
| 169 | strlcpy(ipsec_def_enc, IPSEC_DEFAULT_DEF_ENC"aes", sizeof(ipsec_def_enc)); | ||||
| 170 | strlcpy(ipsec_def_auth, IPSEC_DEFAULT_DEF_AUTH"hmac-sha1", sizeof(ipsec_def_auth)); | ||||
| 171 | strlcpy(ipsec_def_comp, IPSEC_DEFAULT_DEF_COMP"deflate", sizeof(ipsec_def_comp)); | ||||
| 172 | |||||
| 173 | ipsp_init(); | ||||
| 174 | } | ||||
| 175 | |||||
| 176 | /* | ||||
| 177 | * ipsec_common_input() gets called when we receive an IPsec-protected packet | ||||
| 178 | * in IPv4 or IPv6. All it does is find the right TDB and call the appropriate | ||||
| 179 | * transform. The callback takes care of further processing (like ingress | ||||
| 180 | * filtering). | ||||
| 181 | */ | ||||
| 182 | int | ||||
| 183 | ipsec_common_input(struct mbuf **mp, int skip, int protoff, int af, int sproto, | ||||
| 184 | int udpencap) | ||||
| 185 | { | ||||
| 186 | #define IPSEC_ISTAT(x,y,z) do { \ | ||||
| 187 | if (sproto == IPPROTO_ESP50) \ | ||||
| 188 | espstat_inc(x); \ | ||||
| 189 | else if (sproto == IPPROTO_AH51) \ | ||||
| 190 | ahstat_inc(y); \ | ||||
| 191 | else \ | ||||
| 192 | ipcompstat_inc(z); \ | ||||
| 193 | } while (0) | ||||
| 194 | |||||
| 195 | struct mbuf *m = *mp; | ||||
| 196 | union sockaddr_union dst_address; | ||||
| 197 | struct tdb *tdbp = NULL((void *)0); | ||||
| 198 | u_int32_t spi; | ||||
| 199 | u_int16_t cpi; | ||||
| 200 | int prot; | ||||
| 201 | #ifdef ENCDEBUG | ||||
| 202 | char buf[INET6_ADDRSTRLEN46]; | ||||
| 203 | #endif | ||||
| 204 | |||||
| 205 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); | ||||
| 206 | |||||
| 207 | ipsecstat_pkt(ipsec_ipackets, ipsec_ibytes, m->m_pkthdrM_dat.MH.MH_pkthdr.len); | ||||
| 208 | IPSEC_ISTAT(esps_input, ahs_input, ipcomps_input); | ||||
| 209 | |||||
| 210 | if ((sproto == IPPROTO_IPCOMP108) && (m->m_flagsm_hdr.mh_flags & M_COMP0x4000)) { | ||||
| 211 | DPRINTF("repeated decompression")do { } while (0); | ||||
| 212 | ipcompstat_inc(ipcomps_pdrops); | ||||
| 213 | goto drop; | ||||
| 214 | } | ||||
| 215 | |||||
| 216 | if (m->m_pkthdrM_dat.MH.MH_pkthdr.len - skip < 2 * sizeof(u_int32_t)) { | ||||
| 217 | DPRINTF("packet too small")do { } while (0); | ||||
| 218 | IPSEC_ISTAT(esps_hdrops, ahs_hdrops, ipcomps_hdrops); | ||||
| 219 | goto drop; | ||||
| 220 | } | ||||
| 221 | |||||
| 222 | /* Retrieve the SPI from the relevant IPsec header */ | ||||
| 223 | switch (sproto) { | ||||
| 224 | case IPPROTO_ESP50: | ||||
| 225 | m_copydata(m, skip, sizeof(u_int32_t), (caddr_t) &spi); | ||||
| 226 | break; | ||||
| 227 | case IPPROTO_AH51: | ||||
| 228 | m_copydata(m, skip + sizeof(u_int32_t), sizeof(u_int32_t), | ||||
| 229 | (caddr_t) &spi); | ||||
| 230 | break; | ||||
| 231 | case IPPROTO_IPCOMP108: | ||||
| 232 | m_copydata(m, skip + sizeof(u_int16_t), sizeof(u_int16_t), | ||||
| 233 | (caddr_t) &cpi); | ||||
| 234 | spi = ntohl(htons(cpi))(__uint32_t)(__builtin_constant_p((__uint16_t)(__builtin_constant_p (cpi) ? (__uint16_t)(((__uint16_t)(cpi) & 0xffU) << 8 | ((__uint16_t)(cpi) & 0xff00U) >> 8) : __swap16md (cpi))) ? (__uint32_t)(((__uint32_t)((__uint16_t)(__builtin_constant_p (cpi) ? (__uint16_t)(((__uint16_t)(cpi) & 0xffU) << 8 | ((__uint16_t)(cpi) & 0xff00U) >> 8) : __swap16md (cpi))) & 0xff) << 24 | ((__uint32_t)((__uint16_t)( __builtin_constant_p(cpi) ? (__uint16_t)(((__uint16_t)(cpi) & 0xffU) << 8 | ((__uint16_t)(cpi) & 0xff00U) >> 8) : __swap16md(cpi))) & 0xff00) << 8 | ((__uint32_t )((__uint16_t)(__builtin_constant_p(cpi) ? (__uint16_t)(((__uint16_t )(cpi) & 0xffU) << 8 | ((__uint16_t)(cpi) & 0xff00U ) >> 8) : __swap16md(cpi))) & 0xff0000) >> 8 | ((__uint32_t)((__uint16_t)(__builtin_constant_p(cpi) ? (__uint16_t )(((__uint16_t)(cpi) & 0xffU) << 8 | ((__uint16_t)( cpi) & 0xff00U) >> 8) : __swap16md(cpi))) & 0xff000000 ) >> 24) : __swap32md((__uint16_t)(__builtin_constant_p (cpi) ? (__uint16_t)(((__uint16_t)(cpi) & 0xffU) << 8 | ((__uint16_t)(cpi) & 0xff00U) >> 8) : __swap16md (cpi)))); | ||||
| 235 | break; | ||||
| 236 | default: | ||||
| 237 | panic("%s: unknown/unsupported security protocol %d", | ||||
| 238 | __func__, sproto); | ||||
| 239 | } | ||||
| 240 | |||||
| 241 | /* | ||||
| 242 | * Find tunnel control block and (indirectly) call the appropriate | ||||
| 243 | * kernel crypto routine. The resulting mbuf chain is a valid | ||||
| 244 | * IP packet ready to go through input processing. | ||||
| 245 | */ | ||||
| 246 | |||||
| 247 | memset(&dst_address, 0, sizeof(dst_address))__builtin_memset((&dst_address), (0), (sizeof(dst_address ))); | ||||
| 248 | dst_address.sa.sa_family = af; | ||||
| 249 | |||||
| 250 | switch (af) { | ||||
| 251 | case AF_INET2: | ||||
| 252 | dst_address.sin.sin_len = sizeof(struct sockaddr_in); | ||||
| 253 | m_copydata(m, offsetof(struct ip, ip_dst)__builtin_offsetof(struct ip, ip_dst), | ||||
| 254 | sizeof(struct in_addr), | ||||
| 255 | (caddr_t) &(dst_address.sin.sin_addr)); | ||||
| 256 | break; | ||||
| 257 | |||||
| 258 | #ifdef INET61 | ||||
| 259 | case AF_INET624: | ||||
| 260 | dst_address.sin6.sin6_len = sizeof(struct sockaddr_in6); | ||||
| 261 | m_copydata(m, offsetof(struct ip6_hdr, ip6_dst)__builtin_offsetof(struct ip6_hdr, ip6_dst), | ||||
| 262 | sizeof(struct in6_addr), | ||||
| 263 | (caddr_t) &(dst_address.sin6.sin6_addr)); | ||||
| 264 | in6_recoverscope(&dst_address.sin6, | ||||
| 265 | &dst_address.sin6.sin6_addr); | ||||
| 266 | break; | ||||
| 267 | #endif /* INET6 */ | ||||
| 268 | |||||
| 269 | default: | ||||
| 270 | DPRINTF("unsupported protocol family %d", af)do { } while (0); | ||||
| 271 | IPSEC_ISTAT(esps_nopf, ahs_nopf, ipcomps_nopf); | ||||
| 272 | goto drop; | ||||
| 273 | } | ||||
| 274 | |||||
| 275 | tdbp = gettdb(rtable_l2(m->m_pkthdr.ph_rtableid),gettdb_dir((rtable_l2(m->M_dat.MH.MH_pkthdr.ph_rtableid)), (spi),(&dst_address),(sproto),0) | ||||
| 276 | spi, &dst_address, sproto)gettdb_dir((rtable_l2(m->M_dat.MH.MH_pkthdr.ph_rtableid)), (spi),(&dst_address),(sproto),0); | ||||
| 277 | if (tdbp == NULL((void *)0)) { | ||||
| 278 | DPRINTF("could not find SA for packet to %s, spi %08x",do { } while (0) | ||||
| 279 | ipsp_address(&dst_address, buf, sizeof(buf)), ntohl(spi))do { } while (0); | ||||
| 280 | IPSEC_ISTAT(esps_notdb, ahs_notdb, ipcomps_notdb); | ||||
| 281 | goto drop; | ||||
| 282 | } | ||||
| 283 | |||||
| 284 | if (tdbp->tdb_flags & TDBF_INVALID0x00010) { | ||||
| 285 | DPRINTF("attempted to use invalid SA %s/%08x/%u",do { } while (0) | ||||
| 286 | ipsp_address(&dst_address, buf, sizeof(buf)),do { } while (0) | ||||
| 287 | ntohl(spi), tdbp->tdb_sproto)do { } while (0); | ||||
| 288 | IPSEC_ISTAT(esps_invalid, ahs_invalid, ipcomps_invalid); | ||||
| 289 | goto drop; | ||||
| 290 | } | ||||
| 291 | |||||
| 292 | if (udpencap && !(tdbp->tdb_flags & TDBF_UDPENCAP0x20000)) { | ||||
| 293 | DPRINTF("attempted to use non-udpencap SA %s/%08x/%u",do { } while (0) | ||||
| 294 | ipsp_address(&dst_address, buf, sizeof(buf)),do { } while (0) | ||||
| 295 | ntohl(spi), tdbp->tdb_sproto)do { } while (0); | ||||
| 296 | espstat_inc(esps_udpinval); | ||||
| 297 | goto drop; | ||||
| 298 | } | ||||
| 299 | |||||
| 300 | if (!udpencap && (tdbp->tdb_flags & TDBF_UDPENCAP0x20000)) { | ||||
| 301 | DPRINTF("attempted to use udpencap SA %s/%08x/%u",do { } while (0) | ||||
| 302 | ipsp_address(&dst_address, buf, sizeof(buf)),do { } while (0) | ||||
| 303 | ntohl(spi), tdbp->tdb_sproto)do { } while (0); | ||||
| 304 | espstat_inc(esps_udpneeded); | ||||
| 305 | goto drop; | ||||
| 306 | } | ||||
| 307 | |||||
| 308 | if (tdbp->tdb_xform == NULL((void *)0)) { | ||||
| 309 | DPRINTF("attempted to use uninitialized SA %s/%08x/%u",do { } while (0) | ||||
| 310 | ipsp_address(&dst_address, buf, sizeof(buf)),do { } while (0) | ||||
| 311 | ntohl(spi), tdbp->tdb_sproto)do { } while (0); | ||||
| 312 | IPSEC_ISTAT(esps_noxform, ahs_noxform, ipcomps_noxform); | ||||
| 313 | goto drop; | ||||
| 314 | } | ||||
| 315 | |||||
| 316 | KERNEL_LOCK()_kernel_lock(); | ||||
| 317 | /* Register first use, setup expiration timer. */ | ||||
| 318 | if (tdbp->tdb_first_use == 0) { | ||||
| 319 | tdbp->tdb_first_use = gettime(); | ||||
| 320 | if (tdbp->tdb_flags & TDBF_FIRSTUSE0x00020) { | ||||
| 321 | if (timeout_add_sec(&tdbp->tdb_first_tmo, | ||||
| 322 | tdbp->tdb_exp_first_use)) | ||||
| 323 | tdb_ref(tdbp); | ||||
| 324 | } | ||||
| 325 | if (tdbp->tdb_flags & TDBF_SOFT_FIRSTUSE0x00400) { | ||||
| 326 | if (timeout_add_sec(&tdbp->tdb_sfirst_tmo, | ||||
| 327 | tdbp->tdb_soft_first_use)) | ||||
| 328 | tdb_ref(tdbp); | ||||
| 329 | } | ||||
| 330 | } | ||||
| 331 | |||||
| 332 | tdbstat_pkt(tdbp, tdb_ipackets, tdb_ibytes, m->m_pkthdrM_dat.MH.MH_pkthdr.len); | ||||
| 333 | |||||
| 334 | /* | ||||
| 335 | * Call appropriate transform and return -- callback takes care of | ||||
| 336 | * everything else. | ||||
| 337 | */ | ||||
| 338 | prot = (*(tdbp->tdb_xform->xf_input))(mp, tdbp, skip, protoff); | ||||
| 339 | if (prot == IPPROTO_DONE257) { | ||||
| 340 | ipsecstat_inc(ipsec_idrops); | ||||
| 341 | tdbstat_inc(tdbp, tdb_idrops); | ||||
| 342 | } | ||||
| 343 | tdb_unref(tdbp); | ||||
| 344 | KERNEL_UNLOCK()_kernel_unlock(); | ||||
| 345 | return prot; | ||||
| 346 | |||||
| 347 | drop: | ||||
| 348 | m_freemp(mp); | ||||
| 349 | ipsecstat_inc(ipsec_idrops); | ||||
| 350 | if (tdbp != NULL((void *)0)) | ||||
| 351 | tdbstat_inc(tdbp, tdb_idrops); | ||||
| 352 | tdb_unref(tdbp); | ||||
| 353 | return IPPROTO_DONE257; | ||||
| 354 | } | ||||
| 355 | |||||
| 356 | /* | ||||
| 357 | * IPsec input callback, called by the transform callback. Takes care of | ||||
| 358 | * filtering and other sanity checks on the processed packet. | ||||
| 359 | */ | ||||
| 360 | int | ||||
| 361 | ipsec_common_input_cb(struct mbuf **mp, struct tdb *tdbp, int skip, int protoff) | ||||
| 362 | { | ||||
| 363 | struct mbuf *m = *mp; | ||||
| 364 | int af, sproto; | ||||
| 365 | u_int8_t prot; | ||||
| |||||
| 366 | #if NBPFILTER1 > 0 | ||||
| 367 | struct ifnet *encif; | ||||
| 368 | #endif | ||||
| 369 | struct ip *ip; | ||||
| 370 | #ifdef INET61 | ||||
| 371 | struct ip6_hdr *ip6; | ||||
| 372 | #endif /* INET6 */ | ||||
| 373 | struct m_tag *mtag; | ||||
| 374 | struct tdb_ident *tdbi; | ||||
| 375 | #ifdef ENCDEBUG | ||||
| 376 | char buf[INET6_ADDRSTRLEN46]; | ||||
| 377 | #endif | ||||
| 378 | |||||
| 379 | af = tdbp->tdb_dst.sa.sa_family; | ||||
| 380 | sproto = tdbp->tdb_sproto; | ||||
| 381 | |||||
| 382 | tdbp->tdb_last_used = gettime(); | ||||
| 383 | |||||
| 384 | /* Fix IPv4 header */ | ||||
| 385 | if (af == AF_INET2) { | ||||
| 386 | if (m->m_lenm_hdr.mh_len < skip && | ||||
| 387 | (m = *mp = m_pullup(m, skip)) == NULL((void *)0)) { | ||||
| 388 | DPRINTF("processing failed for SA %s/%08x",do { } while (0) | ||||
| 389 | ipsp_address(&tdbp->tdb_dst, buf, sizeof(buf)),do { } while (0) | ||||
| 390 | ntohl(tdbp->tdb_spi))do { } while (0); | ||||
| 391 | IPSEC_ISTAT(esps_hdrops, ahs_hdrops, ipcomps_hdrops); | ||||
| 392 | goto baddone; | ||||
| 393 | } | ||||
| 394 | |||||
| 395 | ip = mtod(m, struct ip *)((struct ip *)((m)->m_hdr.mh_data)); | ||||
| 396 | ip->ip_len = htons(m->m_pkthdr.len)(__uint16_t)(__builtin_constant_p(m->M_dat.MH.MH_pkthdr.len ) ? (__uint16_t)(((__uint16_t)(m->M_dat.MH.MH_pkthdr.len) & 0xffU) << 8 | ((__uint16_t)(m->M_dat.MH.MH_pkthdr.len ) & 0xff00U) >> 8) : __swap16md(m->M_dat.MH.MH_pkthdr .len)); | ||||
| 397 | in_hdr_cksum_out(m, NULL((void *)0)); | ||||
| 398 | prot = ip->ip_p; | ||||
| 399 | } | ||||
| 400 | |||||
| 401 | #ifdef INET61 | ||||
| 402 | /* Fix IPv6 header */ | ||||
| 403 | if (af == AF_INET624) { | ||||
| 404 | if (m->m_lenm_hdr.mh_len < sizeof(struct ip6_hdr) && | ||||
| 405 | (m = *mp = m_pullup(m, sizeof(struct ip6_hdr))) == NULL((void *)0)) { | ||||
| 406 | |||||
| 407 | DPRINTF("processing failed for SA %s/%08x",do { } while (0) | ||||
| 408 | ipsp_address(&tdbp->tdb_dst, buf, sizeof(buf)),do { } while (0) | ||||
| 409 | ntohl(tdbp->tdb_spi))do { } while (0); | ||||
| 410 | IPSEC_ISTAT(esps_hdrops, ahs_hdrops, ipcomps_hdrops); | ||||
| 411 | goto baddone; | ||||
| 412 | } | ||||
| 413 | |||||
| 414 | ip6 = mtod(m, struct ip6_hdr *)((struct ip6_hdr *)((m)->m_hdr.mh_data)); | ||||
| 415 | ip6->ip6_plenip6_ctlun.ip6_un1.ip6_un1_plen = htons(m->m_pkthdr.len - skip)(__uint16_t)(__builtin_constant_p(m->M_dat.MH.MH_pkthdr.len - skip) ? (__uint16_t)(((__uint16_t)(m->M_dat.MH.MH_pkthdr .len - skip) & 0xffU) << 8 | ((__uint16_t)(m->M_dat .MH.MH_pkthdr.len - skip) & 0xff00U) >> 8) : __swap16md (m->M_dat.MH.MH_pkthdr.len - skip)); | ||||
| 416 | |||||
| 417 | /* Save protocol */ | ||||
| 418 | m_copydata(m, protoff, 1, (caddr_t) &prot); | ||||
| 419 | } | ||||
| 420 | #endif /* INET6 */ | ||||
| 421 | |||||
| 422 | /* | ||||
| 423 | * Fix TCP/UDP checksum of UDP encapsulated transport mode ESP packet. | ||||
| 424 | * (RFC3948 3.1.2) | ||||
| 425 | */ | ||||
| 426 | if ((af
| ||||
| 427 | (tdbp->tdb_flags & TDBF_UDPENCAP0x20000) && | ||||
| 428 | (tdbp->tdb_flags & TDBF_TUNNELING0x01000) == 0) { | ||||
| 429 | u_int16_t cksum; | ||||
| 430 | |||||
| 431 | switch (prot) { | ||||
| 432 | case IPPROTO_UDP17: | ||||
| 433 | if (m->m_pkthdrM_dat.MH.MH_pkthdr.len < skip + sizeof(struct udphdr)) { | ||||
| 434 | IPSEC_ISTAT(esps_hdrops, ahs_hdrops, | ||||
| 435 | ipcomps_hdrops); | ||||
| 436 | goto baddone; | ||||
| 437 | } | ||||
| 438 | cksum = 0; | ||||
| 439 | m_copyback(m, skip + offsetof(struct udphdr, uh_sum)__builtin_offsetof(struct udphdr, uh_sum), | ||||
| 440 | sizeof(cksum), &cksum, M_NOWAIT0x0002); | ||||
| 441 | #ifdef INET61 | ||||
| 442 | if (af == AF_INET624) { | ||||
| 443 | cksum = in6_cksum(m, IPPROTO_UDP17, skip, | ||||
| 444 | m->m_pkthdrM_dat.MH.MH_pkthdr.len - skip); | ||||
| 445 | m_copyback(m, skip + offsetof(struct udphdr,__builtin_offsetof(struct udphdr, uh_sum) | ||||
| 446 | uh_sum)__builtin_offsetof(struct udphdr, uh_sum), sizeof(cksum), &cksum, M_NOWAIT0x0002); | ||||
| 447 | } | ||||
| 448 | #endif | ||||
| 449 | break; | ||||
| 450 | case IPPROTO_TCP6: | ||||
| 451 | if (m->m_pkthdrM_dat.MH.MH_pkthdr.len < skip + sizeof(struct tcphdr)) { | ||||
| 452 | IPSEC_ISTAT(esps_hdrops, ahs_hdrops, | ||||
| 453 | ipcomps_hdrops); | ||||
| 454 | goto baddone; | ||||
| 455 | } | ||||
| 456 | cksum = 0; | ||||
| 457 | m_copyback(m, skip + offsetof(struct tcphdr, th_sum)__builtin_offsetof(struct tcphdr, th_sum), | ||||
| 458 | sizeof(cksum), &cksum, M_NOWAIT0x0002); | ||||
| 459 | if (af == AF_INET2) | ||||
| 460 | cksum = in4_cksum(m, IPPROTO_TCP6, skip, | ||||
| 461 | m->m_pkthdrM_dat.MH.MH_pkthdr.len - skip); | ||||
| 462 | #ifdef INET61 | ||||
| 463 | else if (af == AF_INET624) | ||||
| 464 | cksum = in6_cksum(m, IPPROTO_TCP6, skip, | ||||
| 465 | m->m_pkthdrM_dat.MH.MH_pkthdr.len - skip); | ||||
| 466 | #endif | ||||
| 467 | m_copyback(m, skip + offsetof(struct tcphdr, th_sum)__builtin_offsetof(struct tcphdr, th_sum), | ||||
| 468 | sizeof(cksum), &cksum, M_NOWAIT0x0002); | ||||
| 469 | break; | ||||
| 470 | } | ||||
| 471 | } | ||||
| 472 | |||||
| 473 | /* | ||||
| 474 | * Record what we've done to the packet (under what SA it was | ||||
| 475 | * processed). | ||||
| 476 | */ | ||||
| 477 | if (tdbp->tdb_sproto != IPPROTO_IPCOMP108) { | ||||
| 478 | mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE0x0001, | ||||
| 479 | sizeof(struct tdb_ident), M_NOWAIT0x0002); | ||||
| 480 | if (mtag == NULL((void *)0)) { | ||||
| 481 | DPRINTF("failed to get tag")do { } while (0); | ||||
| 482 | IPSEC_ISTAT(esps_hdrops, ahs_hdrops, ipcomps_hdrops); | ||||
| 483 | goto baddone; | ||||
| 484 | } | ||||
| 485 | |||||
| 486 | tdbi = (struct tdb_ident *)(mtag + 1); | ||||
| 487 | tdbi->dst = tdbp->tdb_dst; | ||||
| 488 | tdbi->proto = tdbp->tdb_sproto; | ||||
| 489 | tdbi->spi = tdbp->tdb_spi; | ||||
| 490 | tdbi->rdomain = tdbp->tdb_rdomain; | ||||
| 491 | |||||
| 492 | m_tag_prepend(m, mtag); | ||||
| 493 | } | ||||
| 494 | |||||
| 495 | switch (sproto) { | ||||
| 496 | case IPPROTO_ESP50: | ||||
| 497 | /* Packet is confidential ? */ | ||||
| 498 | if (tdbp->tdb_encalgxform) | ||||
| 499 | m->m_flagsm_hdr.mh_flags |= M_CONF0x0400; | ||||
| 500 | |||||
| 501 | /* Check if we had authenticated ESP. */ | ||||
| 502 | if (tdbp->tdb_authalgxform) | ||||
| 503 | m->m_flagsm_hdr.mh_flags |= M_AUTH0x0800; | ||||
| 504 | break; | ||||
| 505 | case IPPROTO_AH51: | ||||
| 506 | m->m_flagsm_hdr.mh_flags |= M_AUTH0x0800; | ||||
| 507 | break; | ||||
| 508 | case IPPROTO_IPCOMP108: | ||||
| 509 | m->m_flagsm_hdr.mh_flags |= M_COMP0x4000; | ||||
| 510 | break; | ||||
| 511 | default: | ||||
| 512 | panic("%s: unknown/unsupported security protocol %d", | ||||
| 513 | __func__, sproto); | ||||
| 514 | } | ||||
| 515 | |||||
| 516 | #if NPF1 > 0 | ||||
| 517 | /* Add pf tag if requested. */ | ||||
| 518 | pf_tag_packet(m, tdbp->tdb_tag, -1); | ||||
| 519 | pf_pkt_addr_changed(m); | ||||
| 520 | #endif | ||||
| 521 | if (tdbp->tdb_rdomain != tdbp->tdb_rdomain_post) | ||||
| 522 | m->m_pkthdrM_dat.MH.MH_pkthdr.ph_rtableid = tdbp->tdb_rdomain_post; | ||||
| 523 | |||||
| 524 | if (tdbp->tdb_flags & TDBF_TUNNELING0x01000) | ||||
| 525 | m->m_flagsm_hdr.mh_flags |= M_TUNNEL0x1000; | ||||
| 526 | |||||
| 527 | ipsecstat_add(ipsec_idecompbytes, m->m_pkthdrM_dat.MH.MH_pkthdr.len); | ||||
| 528 | tdbstat_add(tdbp, tdb_idecompbytes, m->m_pkthdrM_dat.MH.MH_pkthdr.len); | ||||
| 529 | |||||
| 530 | #if NBPFILTER1 > 0 | ||||
| 531 | encif = enc_getif(tdbp->tdb_rdomain_post, tdbp->tdb_tap); | ||||
| 532 | if (encif != NULL((void *)0)) { | ||||
| 533 | encif->if_ipacketsif_data.ifi_ipackets++; | ||||
| 534 | encif->if_ibytesif_data.ifi_ibytes += m->m_pkthdrM_dat.MH.MH_pkthdr.len; | ||||
| 535 | |||||
| 536 | if (sproto != IPPROTO_IPCOMP108) { | ||||
| 537 | /* XXX This conflicts with the scoped nature of IPv6 */ | ||||
| 538 | m->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx = encif->if_index; | ||||
| 539 | } | ||||
| 540 | if (encif->if_bpf) { | ||||
| 541 | struct enchdr hdr; | ||||
| 542 | |||||
| 543 | hdr.af = af; | ||||
| 544 | hdr.spi = tdbp->tdb_spi; | ||||
| 545 | hdr.flags = m->m_flagsm_hdr.mh_flags & (M_AUTH0x0800|M_CONF0x0400); | ||||
| 546 | |||||
| 547 | bpf_mtap_hdr(encif->if_bpf, (char *)&hdr, | ||||
| 548 | ENC_HDRLEN12, m, BPF_DIRECTION_IN(1 << 0)); | ||||
| 549 | } | ||||
| 550 | } | ||||
| 551 | #endif | ||||
| 552 | |||||
| 553 | if (ISSET(tdbp->tdb_flags, TDBF_IFACE)((tdbp->tdb_flags) & (0x400000))) { | ||||
| 554 | #if NSEC1 > 0 | ||||
| 555 | if (ISSET(tdbp->tdb_flags, TDBF_TUNNELING)((tdbp->tdb_flags) & (0x01000)) && | ||||
| 556 | tdbp->tdb_iface_dir == IPSP_DIRECTION_IN0x1) { | ||||
| 557 | struct sec_softc *sc = sec_get(tdbp->tdb_iface); | ||||
| 558 | if (sc == NULL((void *)0)) | ||||
| 559 | goto baddone; | ||||
| 560 | |||||
| 561 | sec_input(sc, af, prot, m); | ||||
| 562 | sec_put(sc); | ||||
| 563 | return IPPROTO_DONE257; | ||||
| 564 | } | ||||
| 565 | #endif /* NSEC > 0 */ | ||||
| 566 | goto baddone; | ||||
| 567 | } | ||||
| 568 | |||||
| 569 | #if NPF1 > 0 | ||||
| 570 | /* | ||||
| 571 | * The ip_deliver() shortcut avoids running through ip_input() with the | ||||
| 572 | * same IP header twice. Packets in transport mode have to be be | ||||
| 573 | * passed to pf explicitly. In tunnel mode the inner IP header will | ||||
| 574 | * run through ip_input() and pf anyway. | ||||
| 575 | */ | ||||
| 576 | if ((tdbp->tdb_flags & TDBF_TUNNELING0x01000) == 0) { | ||||
| 577 | struct ifnet *ifp; | ||||
| 578 | |||||
| 579 | /* This is the enc0 interface unless for ipcomp. */ | ||||
| 580 | if ((ifp = if_get(m->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx)) == NULL((void *)0)) { | ||||
| 581 | goto baddone; | ||||
| 582 | } | ||||
| 583 | if (pf_test(af, PF_IN, ifp, mp) != PF_PASS) { | ||||
| 584 | if_put(ifp); | ||||
| 585 | goto baddone; | ||||
| 586 | } | ||||
| 587 | m = *mp; | ||||
| 588 | if_put(ifp); | ||||
| 589 | if (m == NULL((void *)0)) | ||||
| 590 | return IPPROTO_DONE257; | ||||
| 591 | } | ||||
| 592 | #endif | ||||
| 593 | /* Return to the appropriate protocol handler in deliver loop. */ | ||||
| 594 | return prot; | ||||
| |||||
| 595 | |||||
| 596 | baddone: | ||||
| 597 | m_freemp(mp); | ||||
| 598 | return IPPROTO_DONE257; | ||||
| 599 | #undef IPSEC_ISTAT | ||||
| 600 | } | ||||
| 601 | |||||
| 602 | int | ||||
| 603 | ipsec_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, | ||||
| 604 | size_t newlen) | ||||
| 605 | { | ||||
| 606 | int error; | ||||
| 607 | |||||
| 608 | switch (name[0]) { | ||||
| 609 | case IPCTL_IPSEC_ENC_ALGORITHM25: | ||||
| 610 | NET_LOCK()do { rw_enter_write(&netlock); } while (0); | ||||
| 611 | error = sysctl_tstring(oldp, oldlenp, newp, newlen, | ||||
| 612 | ipsec_def_enc, sizeof(ipsec_def_enc)); | ||||
| 613 | NET_UNLOCK()do { rw_exit_write(&netlock); } while (0); | ||||
| 614 | return (error); | ||||
| 615 | case IPCTL_IPSEC_AUTH_ALGORITHM26: | ||||
| 616 | NET_LOCK()do { rw_enter_write(&netlock); } while (0); | ||||
| 617 | error = sysctl_tstring(oldp, oldlenp, newp, newlen, | ||||
| 618 | ipsec_def_auth, sizeof(ipsec_def_auth)); | ||||
| 619 | NET_UNLOCK()do { rw_exit_write(&netlock); } while (0); | ||||
| 620 | return (error); | ||||
| 621 | case IPCTL_IPSEC_IPCOMP_ALGORITHM29: | ||||
| 622 | NET_LOCK()do { rw_enter_write(&netlock); } while (0); | ||||
| 623 | error = sysctl_tstring(oldp, oldlenp, newp, newlen, | ||||
| 624 | ipsec_def_comp, sizeof(ipsec_def_comp)); | ||||
| 625 | NET_UNLOCK()do { rw_exit_write(&netlock); } while (0); | ||||
| 626 | return (error); | ||||
| 627 | case IPCTL_IPSEC_STATS13: | ||||
| 628 | return (ipsec_sysctl_ipsecstat(oldp, oldlenp, newp)); | ||||
| 629 | default: | ||||
| 630 | NET_LOCK()do { rw_enter_write(&netlock); } while (0); | ||||
| 631 | error = sysctl_bounded_arr(ipsecctl_vars, nitems(ipsecctl_vars)(sizeof((ipsecctl_vars)) / sizeof((ipsecctl_vars)[0])), | ||||
| 632 | name, namelen, oldp, oldlenp, newp, newlen); | ||||
| 633 | NET_UNLOCK()do { rw_exit_write(&netlock); } while (0); | ||||
| 634 | return (error); | ||||
| 635 | } | ||||
| 636 | } | ||||
| 637 | |||||
| 638 | int | ||||
| 639 | esp_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, | ||||
| 640 | size_t newlen) | ||||
| 641 | { | ||||
| 642 | int error; | ||||
| 643 | |||||
| 644 | /* All sysctl names at this level are terminal. */ | ||||
| 645 | if (namelen != 1) | ||||
| 646 | return (ENOTDIR20); | ||||
| 647 | |||||
| 648 | switch (name[0]) { | ||||
| 649 | case ESPCTL_STATS4: | ||||
| 650 | return (esp_sysctl_espstat(oldp, oldlenp, newp)); | ||||
| 651 | default: | ||||
| 652 | NET_LOCK()do { rw_enter_write(&netlock); } while (0); | ||||
| 653 | error = sysctl_bounded_arr(espctl_vars, nitems(espctl_vars)(sizeof((espctl_vars)) / sizeof((espctl_vars)[0])), | ||||
| 654 | name, namelen, oldp, oldlenp, newp, newlen); | ||||
| 655 | NET_UNLOCK()do { rw_exit_write(&netlock); } while (0); | ||||
| 656 | return (error); | ||||
| 657 | } | ||||
| 658 | } | ||||
| 659 | |||||
| 660 | int | ||||
| 661 | esp_sysctl_espstat(void *oldp, size_t *oldlenp, void *newp) | ||||
| 662 | { | ||||
| 663 | struct espstat espstat; | ||||
| 664 | |||||
| 665 | CTASSERT(sizeof(espstat) == (esps_ncounters * sizeof(uint64_t)))extern char _ctassert[(sizeof(espstat) == (esps_ncounters * sizeof (uint64_t))) ? 1 : -1 ] __attribute__((__unused__)); | ||||
| 666 | memset(&espstat, 0, sizeof espstat)__builtin_memset((&espstat), (0), (sizeof espstat)); | ||||
| 667 | counters_read(espcounters, (uint64_t *)&espstat, esps_ncounters, NULL((void *)0)); | ||||
| 668 | return (sysctl_rdstruct(oldp, oldlenp, newp, &espstat, | ||||
| 669 | sizeof(espstat))); | ||||
| 670 | } | ||||
| 671 | |||||
| 672 | int | ||||
| 673 | ah_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, | ||||
| 674 | size_t newlen) | ||||
| 675 | { | ||||
| 676 | int error; | ||||
| 677 | |||||
| 678 | /* All sysctl names at this level are terminal. */ | ||||
| 679 | if (namelen != 1) | ||||
| 680 | return (ENOTDIR20); | ||||
| 681 | |||||
| 682 | switch (name[0]) { | ||||
| 683 | case AHCTL_STATS2: | ||||
| 684 | return ah_sysctl_ahstat(oldp, oldlenp, newp); | ||||
| 685 | default: | ||||
| 686 | NET_LOCK()do { rw_enter_write(&netlock); } while (0); | ||||
| 687 | error = sysctl_bounded_arr(ahctl_vars, nitems(ahctl_vars)(sizeof((ahctl_vars)) / sizeof((ahctl_vars)[0])), name, | ||||
| 688 | namelen, oldp, oldlenp, newp, newlen); | ||||
| 689 | NET_UNLOCK()do { rw_exit_write(&netlock); } while (0); | ||||
| 690 | return (error); | ||||
| 691 | } | ||||
| 692 | } | ||||
| 693 | |||||
| 694 | int | ||||
| 695 | ah_sysctl_ahstat(void *oldp, size_t *oldlenp, void *newp) | ||||
| 696 | { | ||||
| 697 | struct ahstat ahstat; | ||||
| 698 | |||||
| 699 | CTASSERT(sizeof(ahstat) == (ahs_ncounters * sizeof(uint64_t)))extern char _ctassert[(sizeof(ahstat) == (ahs_ncounters * sizeof (uint64_t))) ? 1 : -1 ] __attribute__((__unused__)); | ||||
| 700 | memset(&ahstat, 0, sizeof ahstat)__builtin_memset((&ahstat), (0), (sizeof ahstat)); | ||||
| 701 | counters_read(ahcounters, (uint64_t *)&ahstat, ahs_ncounters, NULL((void *)0)); | ||||
| 702 | return (sysctl_rdstruct(oldp, oldlenp, newp, &ahstat, sizeof(ahstat))); | ||||
| 703 | } | ||||
| 704 | |||||
| 705 | int | ||||
| 706 | ipcomp_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, | ||||
| 707 | size_t newlen) | ||||
| 708 | { | ||||
| 709 | int error; | ||||
| 710 | |||||
| 711 | /* All sysctl names at this level are terminal. */ | ||||
| 712 | if (namelen != 1) | ||||
| 713 | return (ENOTDIR20); | ||||
| 714 | |||||
| 715 | switch (name[0]) { | ||||
| 716 | case IPCOMPCTL_STATS2: | ||||
| 717 | return ipcomp_sysctl_ipcompstat(oldp, oldlenp, newp); | ||||
| 718 | default: | ||||
| 719 | NET_LOCK()do { rw_enter_write(&netlock); } while (0); | ||||
| 720 | error = sysctl_bounded_arr(ipcompctl_vars, | ||||
| 721 | nitems(ipcompctl_vars)(sizeof((ipcompctl_vars)) / sizeof((ipcompctl_vars)[0])), name, namelen, oldp, oldlenp, | ||||
| 722 | newp, newlen); | ||||
| 723 | NET_UNLOCK()do { rw_exit_write(&netlock); } while (0); | ||||
| 724 | return (error); | ||||
| 725 | } | ||||
| 726 | } | ||||
| 727 | |||||
| 728 | int | ||||
| 729 | ipcomp_sysctl_ipcompstat(void *oldp, size_t *oldlenp, void *newp) | ||||
| 730 | { | ||||
| 731 | struct ipcompstat ipcompstat; | ||||
| 732 | |||||
| 733 | CTASSERT(sizeof(ipcompstat) == (ipcomps_ncounters * sizeof(uint64_t)))extern char _ctassert[(sizeof(ipcompstat) == (ipcomps_ncounters * sizeof(uint64_t))) ? 1 : -1 ] __attribute__((__unused__)); | ||||
| 734 | memset(&ipcompstat, 0, sizeof ipcompstat)__builtin_memset((&ipcompstat), (0), (sizeof ipcompstat)); | ||||
| 735 | counters_read(ipcompcounters, (uint64_t *)&ipcompstat, | ||||
| 736 | ipcomps_ncounters, NULL((void *)0)); | ||||
| 737 | return (sysctl_rdstruct(oldp, oldlenp, newp, &ipcompstat, | ||||
| 738 | sizeof(ipcompstat))); | ||||
| 739 | } | ||||
| 740 | |||||
| 741 | int | ||||
| 742 | ipsec_sysctl_ipsecstat(void *oldp, size_t *oldlenp, void *newp) | ||||
| 743 | { | ||||
| 744 | struct ipsecstat ipsecstat; | ||||
| 745 | |||||
| 746 | CTASSERT(sizeof(ipsecstat) == (ipsec_ncounters * sizeof(uint64_t)))extern char _ctassert[(sizeof(ipsecstat) == (ipsec_ncounters * sizeof(uint64_t))) ? 1 : -1 ] __attribute__((__unused__)); | ||||
| 747 | memset(&ipsecstat, 0, sizeof ipsecstat)__builtin_memset((&ipsecstat), (0), (sizeof ipsecstat)); | ||||
| 748 | counters_read(ipseccounters, (uint64_t *)&ipsecstat, ipsec_ncounters, | ||||
| 749 | NULL((void *)0)); | ||||
| 750 | return (sysctl_rdstruct(oldp, oldlenp, newp, &ipsecstat, | ||||
| 751 | sizeof(ipsecstat))); | ||||
| 752 | } | ||||
| 753 | |||||
| 754 | int | ||||
| 755 | ipsec_input_disabled(struct mbuf **mp, int *offp, int proto, int af) | ||||
| 756 | { | ||||
| 757 | switch (af) { | ||||
| 758 | case AF_INET2: | ||||
| 759 | return rip_input(mp, offp, proto, af); | ||||
| 760 | #ifdef INET61 | ||||
| 761 | case AF_INET624: | ||||
| 762 | return rip6_input(mp, offp, proto, af); | ||||
| 763 | #endif | ||||
| 764 | default: | ||||
| 765 | unhandled_af(af); | ||||
| 766 | } | ||||
| 767 | } | ||||
| 768 | |||||
| 769 | int | ||||
| 770 | ah46_input(struct mbuf **mp, int *offp, int proto, int af) | ||||
| 771 | { | ||||
| 772 | int protoff; | ||||
| 773 | |||||
| 774 | if ( | ||||
| 775 | #if NPF1 > 0 | ||||
| 776 | ((*mp)->m_pkthdrM_dat.MH.MH_pkthdr.pf.flags & PF_TAG_DIVERTED0x08) || | ||||
| 777 | #endif | ||||
| 778 | !ah_enable) | ||||
| 779 | return ipsec_input_disabled(mp, offp, proto, af); | ||||
| 780 | |||||
| 781 | protoff = ipsec_protoff(*mp, *offp, af); | ||||
| 782 | if (protoff < 0) { | ||||
| 783 | DPRINTF("bad packet header chain")do { } while (0); | ||||
| 784 | ahstat_inc(ahs_hdrops); | ||||
| 785 | m_freemp(mp); | ||||
| 786 | return IPPROTO_DONE257; | ||||
| 787 | } | ||||
| 788 | |||||
| 789 | return ipsec_common_input(mp, *offp, protoff, af, proto, 0); | ||||
| 790 | } | ||||
| 791 | |||||
| 792 | void | ||||
| 793 | ah4_ctlinput(int cmd, struct sockaddr *sa, u_int rdomain, void *v) | ||||
| 794 | { | ||||
| 795 | if (sa->sa_family != AF_INET2 || | ||||
| 796 | sa->sa_len != sizeof(struct sockaddr_in)) | ||||
| 797 | return; | ||||
| 798 | |||||
| 799 | ipsec_common_ctlinput(rdomain, cmd, sa, v, IPPROTO_AH51); | ||||
| 800 | } | ||||
| 801 | |||||
| 802 | int | ||||
| 803 | esp46_input(struct mbuf **mp, int *offp, int proto, int af) | ||||
| 804 | { | ||||
| 805 | int protoff; | ||||
| 806 | |||||
| 807 | if ( | ||||
| 808 | #if NPF1 > 0 | ||||
| 809 | ((*mp)->m_pkthdrM_dat.MH.MH_pkthdr.pf.flags & PF_TAG_DIVERTED0x08) || | ||||
| 810 | #endif | ||||
| 811 | !esp_enable) | ||||
| 812 | return ipsec_input_disabled(mp, offp, proto, af); | ||||
| 813 | |||||
| 814 | protoff = ipsec_protoff(*mp, *offp, af); | ||||
| 815 | if (protoff < 0) { | ||||
| 816 | DPRINTF("bad packet header chain")do { } while (0); | ||||
| 817 | espstat_inc(esps_hdrops); | ||||
| 818 | m_freemp(mp); | ||||
| 819 | return IPPROTO_DONE257; | ||||
| 820 | } | ||||
| 821 | |||||
| 822 | return ipsec_common_input(mp, *offp, protoff, af, proto, 0); | ||||
| 823 | } | ||||
| 824 | |||||
| 825 | /* IPv4 IPCOMP wrapper */ | ||||
| 826 | int | ||||
| 827 | ipcomp46_input(struct mbuf **mp, int *offp, int proto, int af) | ||||
| 828 | { | ||||
| 829 | int protoff; | ||||
| 830 | |||||
| 831 | if ( | ||||
| 832 | #if NPF1 > 0 | ||||
| 833 | ((*mp)->m_pkthdrM_dat.MH.MH_pkthdr.pf.flags & PF_TAG_DIVERTED0x08) || | ||||
| 834 | #endif | ||||
| 835 | !ipcomp_enable) | ||||
| 836 | return ipsec_input_disabled(mp, offp, proto, af); | ||||
| 837 | |||||
| 838 | protoff = ipsec_protoff(*mp, *offp, af); | ||||
| 839 | if (protoff < 0) { | ||||
| 840 | DPRINTF("bad packet header chain")do { } while (0); | ||||
| 841 | ipcompstat_inc(ipcomps_hdrops); | ||||
| 842 | m_freemp(mp); | ||||
| 843 | return IPPROTO_DONE257; | ||||
| 844 | } | ||||
| 845 | |||||
| 846 | return ipsec_common_input(mp, *offp, protoff, af, proto, 0); | ||||
| 847 | } | ||||
| 848 | |||||
| 849 | void | ||||
| 850 | ipsec_set_mtu(struct tdb *tdbp, u_int32_t mtu) | ||||
| 851 | { | ||||
| 852 | ssize_t adjust; | ||||
| 853 | |||||
| 854 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); | ||||
| 855 | |||||
| 856 | /* Walk the chain backwards to the first tdb */ | ||||
| 857 | for (; tdbp != NULL((void *)0); tdbp = tdbp->tdb_inext) { | ||||
| 858 | if (tdbp->tdb_flags & TDBF_INVALID0x00010 || | ||||
| 859 | (adjust = ipsec_hdrsz(tdbp)) == -1) | ||||
| 860 | return; | ||||
| 861 | |||||
| 862 | mtu -= adjust; | ||||
| 863 | |||||
| 864 | /* Store adjusted MTU in tdb */ | ||||
| 865 | tdbp->tdb_mtu = mtu; | ||||
| 866 | tdbp->tdb_mtutimeout = gettime() + ip_mtudisc_timeout; | ||||
| 867 | DPRINTF("spi %08x mtu %d adjust %ld",do { } while (0) | ||||
| 868 | ntohl(tdbp->tdb_spi), tdbp->tdb_mtu, adjust)do { } while (0); | ||||
| 869 | } | ||||
| 870 | } | ||||
| 871 | |||||
| 872 | void | ||||
| 873 | ipsec_common_ctlinput(u_int rdomain, int cmd, struct sockaddr *sa, | ||||
| 874 | void *v, int proto) | ||||
| 875 | { | ||||
| 876 | struct ip *ip = v; | ||||
| 877 | |||||
| 878 | if (cmd == PRC_MSGSIZE5 && ip && ip_mtudisc && ip->ip_v == 4) { | ||||
| 879 | struct tdb *tdbp; | ||||
| 880 | struct sockaddr_in dst; | ||||
| 881 | struct icmp *icp; | ||||
| 882 | int hlen = ip->ip_hl << 2; | ||||
| 883 | u_int32_t spi, mtu; | ||||
| 884 | |||||
| 885 | /* Find the right MTU. */ | ||||
| 886 | icp = (struct icmp *)((caddr_t) ip - | ||||
| 887 | offsetof(struct icmp, icmp_ip)__builtin_offsetof(struct icmp, icmp_dun.id_ip.idi_ip)); | ||||
| 888 | mtu = ntohs(icp->icmp_nextmtu)(__uint16_t)(__builtin_constant_p(icp->icmp_hun.ih_pmtu.ipm_nextmtu ) ? (__uint16_t)(((__uint16_t)(icp->icmp_hun.ih_pmtu.ipm_nextmtu ) & 0xffU) << 8 | ((__uint16_t)(icp->icmp_hun.ih_pmtu .ipm_nextmtu) & 0xff00U) >> 8) : __swap16md(icp-> icmp_hun.ih_pmtu.ipm_nextmtu)); | ||||
| 889 | |||||
| 890 | /* | ||||
| 891 | * Ignore the packet, if we do not receive a MTU | ||||
| 892 | * or the MTU is too small to be acceptable. | ||||
| 893 | */ | ||||
| 894 | if (mtu < 296) | ||||
| 895 | return; | ||||
| 896 | |||||
| 897 | memset(&dst, 0, sizeof(struct sockaddr_in))__builtin_memset((&dst), (0), (sizeof(struct sockaddr_in) )); | ||||
| 898 | dst.sin_family = AF_INET2; | ||||
| 899 | dst.sin_len = sizeof(struct sockaddr_in); | ||||
| 900 | dst.sin_addr.s_addr = ip->ip_dst.s_addr; | ||||
| 901 | |||||
| 902 | memcpy(&spi, (caddr_t)ip + hlen, sizeof(u_int32_t))__builtin_memcpy((&spi), ((caddr_t)ip + hlen), (sizeof(u_int32_t ))); | ||||
| 903 | |||||
| 904 | tdbp = gettdb_rev(rdomain, spi, (union sockaddr_union *)&dst,gettdb_dir((rdomain),(spi),((union sockaddr_union *)&dst) ,(proto),1) | ||||
| 905 | proto)gettdb_dir((rdomain),(spi),((union sockaddr_union *)&dst) ,(proto),1); | ||||
| 906 | ipsec_set_mtu(tdbp, mtu); | ||||
| 907 | tdb_unref(tdbp); | ||||
| 908 | } | ||||
| 909 | } | ||||
| 910 | |||||
| 911 | void | ||||
| 912 | udpencap_ctlinput(int cmd, struct sockaddr *sa, u_int rdomain, void *v) | ||||
| 913 | { | ||||
| 914 | struct ip *ip = v; | ||||
| 915 | struct tdb *tdbp, *first; | ||||
| 916 | struct icmp *icp; | ||||
| 917 | u_int32_t mtu; | ||||
| 918 | struct sockaddr_in dst, src; | ||||
| 919 | union sockaddr_union *su_dst, *su_src; | ||||
| 920 | |||||
| 921 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); | ||||
| 922 | |||||
| 923 | icp = (struct icmp *)((caddr_t) ip - offsetof(struct icmp, icmp_ip)__builtin_offsetof(struct icmp, icmp_dun.id_ip.idi_ip)); | ||||
| 924 | mtu = ntohs(icp->icmp_nextmtu)(__uint16_t)(__builtin_constant_p(icp->icmp_hun.ih_pmtu.ipm_nextmtu ) ? (__uint16_t)(((__uint16_t)(icp->icmp_hun.ih_pmtu.ipm_nextmtu ) & 0xffU) << 8 | ((__uint16_t)(icp->icmp_hun.ih_pmtu .ipm_nextmtu) & 0xff00U) >> 8) : __swap16md(icp-> icmp_hun.ih_pmtu.ipm_nextmtu)); | ||||
| 925 | |||||
| 926 | /* | ||||
| 927 | * Ignore the packet, if we do not receive a MTU | ||||
| 928 | * or the MTU is too small to be acceptable. | ||||
| 929 | */ | ||||
| 930 | if (mtu < 296) | ||||
| 931 | return; | ||||
| 932 | |||||
| 933 | memset(&dst, 0, sizeof(dst))__builtin_memset((&dst), (0), (sizeof(dst))); | ||||
| 934 | dst.sin_family = AF_INET2; | ||||
| 935 | dst.sin_len = sizeof(struct sockaddr_in); | ||||
| 936 | dst.sin_addr.s_addr = ip->ip_dst.s_addr; | ||||
| 937 | su_dst = (union sockaddr_union *)&dst; | ||||
| 938 | memset(&src, 0, sizeof(src))__builtin_memset((&src), (0), (sizeof(src))); | ||||
| 939 | src.sin_family = AF_INET2; | ||||
| 940 | src.sin_len = sizeof(struct sockaddr_in); | ||||
| 941 | src.sin_addr.s_addr = ip->ip_src.s_addr; | ||||
| 942 | su_src = (union sockaddr_union *)&src; | ||||
| 943 | |||||
| 944 | first = gettdbbysrcdst_rev(rdomain, 0, su_src, su_dst, IPPROTO_ESP)gettdbbysrcdst_dir((rdomain),(0),(su_src),(su_dst),(50),1); | ||||
| 945 | |||||
| 946 | mtx_enter(&tdb_sadb_mtx); | ||||
| 947 | for (tdbp = first; tdbp != NULL((void *)0); tdbp = tdbp->tdb_snext) { | ||||
| 948 | if (tdbp->tdb_sproto == IPPROTO_ESP50 && | ||||
| 949 | ((tdbp->tdb_flags & (TDBF_INVALID0x00010|TDBF_UDPENCAP0x20000)) == | ||||
| 950 | TDBF_UDPENCAP0x20000) && | ||||
| 951 | !memcmp(&tdbp->tdb_dst, &dst, su_dst->sa.sa_len)__builtin_memcmp((&tdbp->tdb_dst), (&dst), (su_dst ->sa.sa_len)) && | ||||
| 952 | !memcmp(&tdbp->tdb_src, &src, su_src->sa.sa_len)__builtin_memcmp((&tdbp->tdb_src), (&src), (su_src ->sa.sa_len))) | ||||
| 953 | ipsec_set_mtu(tdbp, mtu); | ||||
| 954 | } | ||||
| 955 | mtx_leave(&tdb_sadb_mtx); | ||||
| 956 | tdb_unref(first); | ||||
| 957 | } | ||||
| 958 | |||||
| 959 | void | ||||
| 960 | esp4_ctlinput(int cmd, struct sockaddr *sa, u_int rdomain, void *v) | ||||
| 961 | { | ||||
| 962 | if (sa->sa_family != AF_INET2 || | ||||
| 963 | sa->sa_len != sizeof(struct sockaddr_in)) | ||||
| 964 | return; | ||||
| 965 | |||||
| 966 | ipsec_common_ctlinput(rdomain, cmd, sa, v, IPPROTO_ESP50); | ||||
| 967 | } | ||||
| 968 | |||||
| 969 | /* Find the offset of the next protocol field in the previous header. */ | ||||
| 970 | int | ||||
| 971 | ipsec_protoff(struct mbuf *m, int off, int af) | ||||
| 972 | { | ||||
| 973 | #ifdef INET61 | ||||
| 974 | struct ip6_ext ip6e; | ||||
| 975 | int protoff, nxt, l; | ||||
| 976 | #endif /* INET6 */ | ||||
| 977 | |||||
| 978 | switch (af) { | ||||
| 979 | case AF_INET2: | ||||
| 980 | return offsetof(struct ip, ip_p)__builtin_offsetof(struct ip, ip_p); | ||||
| 981 | #ifdef INET61 | ||||
| 982 | case AF_INET624: | ||||
| 983 | break; | ||||
| 984 | #endif /* INET6 */ | ||||
| 985 | default: | ||||
| 986 | unhandled_af(af); | ||||
| 987 | } | ||||
| 988 | |||||
| 989 | #ifdef INET61 | ||||
| 990 | if (off < sizeof(struct ip6_hdr)) | ||||
| 991 | return -1; | ||||
| 992 | |||||
| 993 | if (off == sizeof(struct ip6_hdr)) | ||||
| 994 | return offsetof(struct ip6_hdr, ip6_nxt)__builtin_offsetof(struct ip6_hdr, ip6_ctlun.ip6_un1.ip6_un1_nxt ); | ||||
| 995 | |||||
| 996 | /* Chase down the header chain... */ | ||||
| 997 | protoff = sizeof(struct ip6_hdr); | ||||
| 998 | nxt = (mtod(m, struct ip6_hdr *)((struct ip6_hdr *)((m)->m_hdr.mh_data)))->ip6_nxtip6_ctlun.ip6_un1.ip6_un1_nxt; | ||||
| 999 | l = 0; | ||||
| 1000 | |||||
| 1001 | do { | ||||
| 1002 | protoff += l; | ||||
| 1003 | m_copydata(m, protoff, sizeof(ip6e), | ||||
| 1004 | (caddr_t) &ip6e); | ||||
| 1005 | |||||
| 1006 | if (nxt == IPPROTO_AH51) | ||||
| 1007 | l = (ip6e.ip6e_len + 2) << 2; | ||||
| 1008 | else | ||||
| 1009 | l = (ip6e.ip6e_len + 1) << 3; | ||||
| 1010 | #ifdef DIAGNOSTIC1 | ||||
| 1011 | if (l <= 0) | ||||
| 1012 | panic("%s: l went zero or negative", __func__); | ||||
| 1013 | #endif | ||||
| 1014 | |||||
| 1015 | nxt = ip6e.ip6e_nxt; | ||||
| 1016 | } while (protoff + l < off); | ||||
| 1017 | |||||
| 1018 | /* Malformed packet check */ | ||||
| 1019 | if (protoff + l != off) | ||||
| 1020 | return -1; | ||||
| 1021 | |||||
| 1022 | protoff += offsetof(struct ip6_ext, ip6e_nxt)__builtin_offsetof(struct ip6_ext, ip6e_nxt); | ||||
| 1023 | return protoff; | ||||
| 1024 | #endif /* INET6 */ | ||||
| 1025 | } | ||||
| 1026 | |||||
| 1027 | int | ||||
| 1028 | ipsec_forward_check(struct mbuf *m, int hlen, int af) | ||||
| 1029 | { | ||||
| 1030 | struct tdb *tdb; | ||||
| 1031 | struct tdb_ident *tdbi; | ||||
| 1032 | struct m_tag *mtag; | ||||
| 1033 | int error = 0; | ||||
| 1034 | |||||
| 1035 | /* | ||||
| 1036 | * IPsec policy check for forwarded packets. Look at | ||||
| 1037 | * inner-most IPsec SA used. | ||||
| 1038 | */ | ||||
| 1039 | mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE0x0001, NULL((void *)0)); | ||||
| 1040 | if (mtag != NULL((void *)0)) { | ||||
| 1041 | tdbi = (struct tdb_ident *)(mtag + 1); | ||||
| 1042 | tdb = gettdb(tdbi->rdomain, tdbi->spi, &tdbi->dst, tdbi->proto)gettdb_dir((tdbi->rdomain),(tdbi->spi),(&tdbi->dst ),(tdbi->proto),0); | ||||
| 1043 | } else | ||||
| 1044 | tdb = NULL((void *)0); | ||||
| 1045 | error = ipsp_spd_lookup(m, af, hlen, IPSP_DIRECTION_IN0x1, | ||||
| 1046 | tdb, NULL((void *)0), NULL((void *)0), NULL((void *)0)); | ||||
| 1047 | tdb_unref(tdb); | ||||
| 1048 | |||||
| 1049 | return error; | ||||
| 1050 | } | ||||
| 1051 | |||||
| 1052 | int | ||||
| 1053 | ipsec_local_check(struct mbuf *m, int hlen, int proto, int af) | ||||
| 1054 | { | ||||
| 1055 | struct tdb *tdb; | ||||
| 1056 | struct tdb_ident *tdbi; | ||||
| 1057 | struct m_tag *mtag; | ||||
| 1058 | int error = 0; | ||||
| 1059 | |||||
| 1060 | /* | ||||
| 1061 | * If it's a protected packet for us, skip the policy check. | ||||
| 1062 | * That's because we really only care about the properties of | ||||
| 1063 | * the protected packet, and not the intermediate versions. | ||||
| 1064 | * While this is not the most paranoid setting, it allows | ||||
| 1065 | * some flexibility in handling nested tunnels (in setting up | ||||
| 1066 | * the policies). | ||||
| 1067 | */ | ||||
| 1068 | if ((proto == IPPROTO_ESP50) || (proto == IPPROTO_AH51) || | ||||
| 1069 | (proto == IPPROTO_IPCOMP108)) | ||||
| 1070 | return 0; | ||||
| 1071 | |||||
| 1072 | /* | ||||
| 1073 | * If the protected packet was tunneled, then we need to | ||||
| 1074 | * verify the protected packet's information, not the | ||||
| 1075 | * external headers. Thus, skip the policy lookup for the | ||||
| 1076 | * external packet, and keep the IPsec information linked on | ||||
| 1077 | * the packet header (the encapsulation routines know how | ||||
| 1078 | * to deal with that). | ||||
| 1079 | */ | ||||
| 1080 | if ((proto == IPPROTO_IPV44) || (proto == IPPROTO_IPV641)) | ||||
| 1081 | return 0; | ||||
| 1082 | |||||
| 1083 | /* | ||||
| 1084 | * When processing IPv6 header chains, do not look at the | ||||
| 1085 | * outer header. The inner protocol is relevant and will | ||||
| 1086 | * be checked by the local delivery loop later. | ||||
| 1087 | */ | ||||
| 1088 | if ((af == AF_INET624) && ((proto == IPPROTO_DSTOPTS60) || | ||||
| 1089 | (proto == IPPROTO_ROUTING43) || (proto == IPPROTO_FRAGMENT44))) | ||||
| 1090 | return 0; | ||||
| 1091 | |||||
| 1092 | /* | ||||
| 1093 | * If the protected packet is TCP or UDP, we'll do the | ||||
| 1094 | * policy check in the respective input routine, so we can | ||||
| 1095 | * check for bypass sockets. | ||||
| 1096 | */ | ||||
| 1097 | if ((proto == IPPROTO_TCP6) || (proto == IPPROTO_UDP17)) | ||||
| 1098 | return 0; | ||||
| 1099 | |||||
| 1100 | /* | ||||
| 1101 | * IPsec policy check for local-delivery packets. Look at the | ||||
| 1102 | * inner-most SA that protected the packet. This is in fact | ||||
| 1103 | * a bit too restrictive (it could end up causing packets to | ||||
| 1104 | * be dropped that semantically follow the policy, e.g., in | ||||
| 1105 | * certain SA-bundle configurations); but the alternative is | ||||
| 1106 | * very complicated (and requires keeping track of what | ||||
| 1107 | * kinds of tunneling headers have been seen in-between the | ||||
| 1108 | * IPsec headers), and I don't think we lose much functionality | ||||
| 1109 | * that's needed in the real world (who uses bundles anyway ?). | ||||
| 1110 | */ | ||||
| 1111 | mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE0x0001, NULL((void *)0)); | ||||
| 1112 | if (mtag) { | ||||
| 1113 | tdbi = (struct tdb_ident *)(mtag + 1); | ||||
| 1114 | tdb = gettdb(tdbi->rdomain, tdbi->spi, &tdbi->dst,gettdb_dir((tdbi->rdomain),(tdbi->spi),(&tdbi->dst ),(tdbi->proto),0) | ||||
| 1115 | tdbi->proto)gettdb_dir((tdbi->rdomain),(tdbi->spi),(&tdbi->dst ),(tdbi->proto),0); | ||||
| 1116 | } else | ||||
| 1117 | tdb = NULL((void *)0); | ||||
| 1118 | error = ipsp_spd_lookup(m, af, hlen, IPSP_DIRECTION_IN0x1, | ||||
| 1119 | tdb, NULL((void *)0), NULL((void *)0), NULL((void *)0)); | ||||
| 1120 | tdb_unref(tdb); | ||||
| 1121 | |||||
| 1122 | return error; | ||||
| 1123 | } |