File: | netinet/ipsec_input.c |
Warning: | line 561, column 4 3rd function call argument is an uninitialized value |
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 | } |