1 | #include <machine/rtems-bsd-kernel-space.h> |
---|
2 | |
---|
3 | /* $FreeBSD$ */ |
---|
4 | /* $KAME: ipsec.c,v 1.103 2001/05/24 07:14:18 sakane Exp $ */ |
---|
5 | |
---|
6 | /*- |
---|
7 | * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
---|
8 | * All rights reserved. |
---|
9 | * |
---|
10 | * Redistribution and use in source and binary forms, with or without |
---|
11 | * modification, are permitted provided that the following conditions |
---|
12 | * are met: |
---|
13 | * 1. Redistributions of source code must retain the above copyright |
---|
14 | * notice, this list of conditions and the following disclaimer. |
---|
15 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
16 | * notice, this list of conditions and the following disclaimer in the |
---|
17 | * documentation and/or other materials provided with the distribution. |
---|
18 | * 3. Neither the name of the project nor the names of its contributors |
---|
19 | * may be used to endorse or promote products derived from this software |
---|
20 | * without specific prior written permission. |
---|
21 | * |
---|
22 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
---|
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
---|
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
32 | * SUCH DAMAGE. |
---|
33 | */ |
---|
34 | |
---|
35 | /* |
---|
36 | * IPsec controller part. |
---|
37 | */ |
---|
38 | |
---|
39 | #include <rtems/bsd/local/opt_inet.h> |
---|
40 | #include <rtems/bsd/local/opt_inet6.h> |
---|
41 | #include <rtems/bsd/local/opt_ipsec.h> |
---|
42 | |
---|
43 | #include <rtems/bsd/sys/param.h> |
---|
44 | #include <sys/systm.h> |
---|
45 | #include <sys/malloc.h> |
---|
46 | #include <sys/mbuf.h> |
---|
47 | #include <sys/domain.h> |
---|
48 | #include <sys/priv.h> |
---|
49 | #include <sys/protosw.h> |
---|
50 | #include <sys/socket.h> |
---|
51 | #include <sys/socketvar.h> |
---|
52 | #include <rtems/bsd/sys/errno.h> |
---|
53 | #include <sys/time.h> |
---|
54 | #include <sys/kernel.h> |
---|
55 | #include <sys/syslog.h> |
---|
56 | #include <sys/sysctl.h> |
---|
57 | #include <sys/proc.h> |
---|
58 | |
---|
59 | #include <net/if.h> |
---|
60 | #include <net/route.h> |
---|
61 | #include <net/vnet.h> |
---|
62 | |
---|
63 | #include <netinet/in.h> |
---|
64 | #include <netinet/in_systm.h> |
---|
65 | #include <netinet/ip.h> |
---|
66 | #include <netinet/ip_var.h> |
---|
67 | #include <netinet/in_var.h> |
---|
68 | #include <netinet/udp.h> |
---|
69 | #include <netinet/udp_var.h> |
---|
70 | #include <netinet/tcp.h> |
---|
71 | #include <netinet/udp.h> |
---|
72 | |
---|
73 | #include <netinet/ip6.h> |
---|
74 | #ifdef INET6 |
---|
75 | #include <netinet6/ip6_var.h> |
---|
76 | #endif |
---|
77 | #include <netinet/in_pcb.h> |
---|
78 | #ifdef INET6 |
---|
79 | #include <netinet/icmp6.h> |
---|
80 | #endif |
---|
81 | |
---|
82 | #include <sys/types.h> |
---|
83 | #include <netipsec/ipsec.h> |
---|
84 | #ifdef INET6 |
---|
85 | #include <netipsec/ipsec6.h> |
---|
86 | #endif |
---|
87 | #include <netipsec/ah_var.h> |
---|
88 | #include <netipsec/esp_var.h> |
---|
89 | #include <netipsec/ipcomp.h> /*XXX*/ |
---|
90 | #include <netipsec/ipcomp_var.h> |
---|
91 | |
---|
92 | #include <netipsec/key.h> |
---|
93 | #include <netipsec/keydb.h> |
---|
94 | #include <netipsec/key_debug.h> |
---|
95 | |
---|
96 | #include <netipsec/xform.h> |
---|
97 | |
---|
98 | #include <machine/in_cksum.h> |
---|
99 | |
---|
100 | #include <opencrypto/cryptodev.h> |
---|
101 | |
---|
102 | #ifdef IPSEC_DEBUG |
---|
103 | VNET_DEFINE(int, ipsec_debug) = 1; |
---|
104 | #else |
---|
105 | VNET_DEFINE(int, ipsec_debug) = 0; |
---|
106 | #endif |
---|
107 | |
---|
108 | /* NB: name changed so netstat doesn't use it. */ |
---|
109 | VNET_DEFINE(struct ipsecstat, ipsec4stat); |
---|
110 | VNET_DEFINE(int, ip4_ah_offsetmask) = 0; /* maybe IP_DF? */ |
---|
111 | /* DF bit on encap. 0: clear 1: set 2: copy */ |
---|
112 | VNET_DEFINE(int, ip4_ipsec_dfbit) = 0; |
---|
113 | VNET_DEFINE(int, ip4_esp_trans_deflev) = IPSEC_LEVEL_USE; |
---|
114 | VNET_DEFINE(int, ip4_esp_net_deflev) = IPSEC_LEVEL_USE; |
---|
115 | VNET_DEFINE(int, ip4_ah_trans_deflev) = IPSEC_LEVEL_USE; |
---|
116 | VNET_DEFINE(int, ip4_ah_net_deflev) = IPSEC_LEVEL_USE; |
---|
117 | VNET_DEFINE(struct secpolicy, ip4_def_policy); |
---|
118 | /* ECN ignore(-1)/forbidden(0)/allowed(1) */ |
---|
119 | VNET_DEFINE(int, ip4_ipsec_ecn) = 0; |
---|
120 | VNET_DEFINE(int, ip4_esp_randpad) = -1; |
---|
121 | |
---|
122 | /* |
---|
123 | * Crypto support requirements: |
---|
124 | * |
---|
125 | * 1 require hardware support |
---|
126 | * -1 require software support |
---|
127 | * 0 take anything |
---|
128 | */ |
---|
129 | VNET_DEFINE(int, crypto_support) = CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE; |
---|
130 | |
---|
131 | FEATURE(ipsec, "Internet Protocol Security (IPsec)"); |
---|
132 | #ifdef IPSEC_NAT_T |
---|
133 | FEATURE(ipsec_natt, "UDP Encapsulation of IPsec ESP Packets ('NAT-T')"); |
---|
134 | #endif |
---|
135 | |
---|
136 | SYSCTL_DECL(_net_inet_ipsec); |
---|
137 | |
---|
138 | /* net.inet.ipsec */ |
---|
139 | SYSCTL_VNET_INT(_net_inet_ipsec, IPSECCTL_DEF_POLICY, def_policy, |
---|
140 | CTLFLAG_RW, &VNET_NAME(ip4_def_policy).policy, 0, |
---|
141 | "IPsec default policy."); |
---|
142 | SYSCTL_VNET_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev, |
---|
143 | CTLFLAG_RW, &VNET_NAME(ip4_esp_trans_deflev), 0, |
---|
144 | "Default ESP transport mode level"); |
---|
145 | SYSCTL_VNET_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, |
---|
146 | CTLFLAG_RW, &VNET_NAME(ip4_esp_net_deflev), 0, |
---|
147 | "Default ESP tunnel mode level."); |
---|
148 | SYSCTL_VNET_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, |
---|
149 | CTLFLAG_RW, &VNET_NAME(ip4_ah_trans_deflev), 0, |
---|
150 | "AH transfer mode default level."); |
---|
151 | SYSCTL_VNET_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, |
---|
152 | CTLFLAG_RW, &VNET_NAME(ip4_ah_net_deflev), 0, |
---|
153 | "AH tunnel mode default level."); |
---|
154 | SYSCTL_VNET_INT(_net_inet_ipsec, IPSECCTL_AH_CLEARTOS, ah_cleartos, |
---|
155 | CTLFLAG_RW, &VNET_NAME(ah_cleartos), 0, |
---|
156 | "If set clear type-of-service field when doing AH computation."); |
---|
157 | SYSCTL_VNET_INT(_net_inet_ipsec, IPSECCTL_AH_OFFSETMASK, ah_offsetmask, |
---|
158 | CTLFLAG_RW, &VNET_NAME(ip4_ah_offsetmask), 0, |
---|
159 | "If not set clear offset field mask when doing AH computation."); |
---|
160 | SYSCTL_VNET_INT(_net_inet_ipsec, IPSECCTL_DFBIT, dfbit, |
---|
161 | CTLFLAG_RW, &VNET_NAME(ip4_ipsec_dfbit), 0, |
---|
162 | "Do not fragment bit on encap."); |
---|
163 | SYSCTL_VNET_INT(_net_inet_ipsec, IPSECCTL_ECN, ecn, |
---|
164 | CTLFLAG_RW, &VNET_NAME(ip4_ipsec_ecn), 0, |
---|
165 | "Explicit Congestion Notification handling."); |
---|
166 | SYSCTL_VNET_INT(_net_inet_ipsec, IPSECCTL_DEBUG, debug, |
---|
167 | CTLFLAG_RW, &VNET_NAME(ipsec_debug), 0, |
---|
168 | "Enable IPsec debugging output when set."); |
---|
169 | SYSCTL_VNET_INT(_net_inet_ipsec, OID_AUTO, crypto_support, |
---|
170 | CTLFLAG_RW, &VNET_NAME(crypto_support), 0, |
---|
171 | "Crypto driver selection."); |
---|
172 | SYSCTL_VNET_STRUCT(_net_inet_ipsec, OID_AUTO, ipsecstats, |
---|
173 | CTLFLAG_RD, &VNET_NAME(ipsec4stat), ipsecstat, |
---|
174 | "IPsec IPv4 statistics."); |
---|
175 | |
---|
176 | #ifdef REGRESSION |
---|
177 | /* |
---|
178 | * When set to 1, IPsec will send packets with the same sequence number. |
---|
179 | * This allows to verify if the other side has proper replay attacks detection. |
---|
180 | */ |
---|
181 | VNET_DEFINE(int, ipsec_replay) = 0; |
---|
182 | SYSCTL_VNET_INT(_net_inet_ipsec, OID_AUTO, test_replay, |
---|
183 | CTLFLAG_RW, &VNET_NAME(ipsec_replay), 0, |
---|
184 | "Emulate replay attack"); |
---|
185 | /* |
---|
186 | * When set 1, IPsec will send packets with corrupted HMAC. |
---|
187 | * This allows to verify if the other side properly detects modified packets. |
---|
188 | */ |
---|
189 | VNET_DEFINE(int, ipsec_integrity) = 0; |
---|
190 | SYSCTL_VNET_INT(_net_inet_ipsec, OID_AUTO, test_integrity, |
---|
191 | CTLFLAG_RW, &VNET_NAME(ipsec_integrity), 0, |
---|
192 | "Emulate man-in-the-middle attack"); |
---|
193 | #endif |
---|
194 | |
---|
195 | #ifdef INET6 |
---|
196 | VNET_DEFINE(struct ipsecstat, ipsec6stat); |
---|
197 | VNET_DEFINE(int, ip6_esp_trans_deflev) = IPSEC_LEVEL_USE; |
---|
198 | VNET_DEFINE(int, ip6_esp_net_deflev) = IPSEC_LEVEL_USE; |
---|
199 | VNET_DEFINE(int, ip6_ah_trans_deflev) = IPSEC_LEVEL_USE; |
---|
200 | VNET_DEFINE(int, ip6_ah_net_deflev) = IPSEC_LEVEL_USE; |
---|
201 | VNET_DEFINE(int, ip6_ipsec_ecn) = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ |
---|
202 | |
---|
203 | SYSCTL_DECL(_net_inet6_ipsec6); |
---|
204 | |
---|
205 | /* net.inet6.ipsec6 */ |
---|
206 | #ifdef COMPAT_KAME |
---|
207 | SYSCTL_OID(_net_inet6_ipsec6, IPSECCTL_STATS, stats, CTLFLAG_RD, |
---|
208 | 0, 0, compat_ipsecstats_sysctl, "S", "IPsec IPv6 statistics."); |
---|
209 | #endif /* COMPAT_KAME */ |
---|
210 | SYSCTL_VNET_INT(_net_inet6_ipsec6, IPSECCTL_DEF_POLICY, def_policy, CTLFLAG_RW, |
---|
211 | &VNET_NAME(ip4_def_policy).policy, 0, |
---|
212 | "IPsec default policy."); |
---|
213 | SYSCTL_VNET_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_TRANSLEV, |
---|
214 | esp_trans_deflev, CTLFLAG_RW, &VNET_NAME(ip6_esp_trans_deflev), 0, |
---|
215 | "Default ESP transport mode level."); |
---|
216 | SYSCTL_VNET_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_NETLEV, |
---|
217 | esp_net_deflev, CTLFLAG_RW, &VNET_NAME(ip6_esp_net_deflev), 0, |
---|
218 | "Default ESP tunnel mode level."); |
---|
219 | SYSCTL_VNET_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_TRANSLEV, |
---|
220 | ah_trans_deflev, CTLFLAG_RW, &VNET_NAME(ip6_ah_trans_deflev), 0, |
---|
221 | "AH transfer mode default level."); |
---|
222 | SYSCTL_VNET_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_NETLEV, |
---|
223 | ah_net_deflev, CTLFLAG_RW, &VNET_NAME(ip6_ah_net_deflev), 0, |
---|
224 | "AH tunnel mode default level."); |
---|
225 | SYSCTL_VNET_INT(_net_inet6_ipsec6, IPSECCTL_ECN, |
---|
226 | ecn, CTLFLAG_RW, &VNET_NAME(ip6_ipsec_ecn), 0, |
---|
227 | "Explicit Congestion Notification handling."); |
---|
228 | SYSCTL_VNET_INT(_net_inet6_ipsec6, IPSECCTL_DEBUG, debug, CTLFLAG_RW, |
---|
229 | &VNET_NAME(ipsec_debug), 0, |
---|
230 | "Enable IPsec debugging output when set."); |
---|
231 | SYSCTL_VNET_STRUCT(_net_inet6_ipsec6, IPSECCTL_STATS, |
---|
232 | ipsecstats, CTLFLAG_RD, &VNET_NAME(ipsec6stat), ipsecstat, |
---|
233 | "IPsec IPv6 statistics."); |
---|
234 | #endif /* INET6 */ |
---|
235 | |
---|
236 | static int ipsec_setspidx_inpcb __P((struct mbuf *, struct inpcb *)); |
---|
237 | static int ipsec_setspidx __P((struct mbuf *, struct secpolicyindex *, int)); |
---|
238 | static void ipsec4_get_ulp __P((struct mbuf *m, struct secpolicyindex *, int)); |
---|
239 | static int ipsec4_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *)); |
---|
240 | #ifdef INET6 |
---|
241 | static void ipsec6_get_ulp __P((struct mbuf *m, struct secpolicyindex *, int)); |
---|
242 | static int ipsec6_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *)); |
---|
243 | #endif |
---|
244 | static void ipsec_delpcbpolicy __P((struct inpcbpolicy *)); |
---|
245 | static struct secpolicy *ipsec_deepcopy_policy __P((struct secpolicy *src)); |
---|
246 | static void vshiftl __P((unsigned char *, int, int)); |
---|
247 | |
---|
248 | MALLOC_DEFINE(M_IPSEC_INPCB, "inpcbpolicy", "inpcb-resident ipsec policy"); |
---|
249 | |
---|
250 | /* |
---|
251 | * Return a held reference to the default SP. |
---|
252 | */ |
---|
253 | static struct secpolicy * |
---|
254 | key_allocsp_default(const char* where, int tag) |
---|
255 | { |
---|
256 | struct secpolicy *sp; |
---|
257 | |
---|
258 | KEYDEBUG(KEYDEBUG_IPSEC_STAMP, |
---|
259 | printf("DP key_allocsp_default from %s:%u\n", where, tag)); |
---|
260 | |
---|
261 | sp = &V_ip4_def_policy; |
---|
262 | if (sp->policy != IPSEC_POLICY_DISCARD && |
---|
263 | sp->policy != IPSEC_POLICY_NONE) { |
---|
264 | ipseclog((LOG_INFO, "fixed system default policy: %d->%d\n", |
---|
265 | sp->policy, IPSEC_POLICY_NONE)); |
---|
266 | sp->policy = IPSEC_POLICY_NONE; |
---|
267 | } |
---|
268 | key_addref(sp); |
---|
269 | |
---|
270 | KEYDEBUG(KEYDEBUG_IPSEC_STAMP, |
---|
271 | printf("DP key_allocsp_default returns SP:%p (%u)\n", |
---|
272 | sp, sp->refcnt)); |
---|
273 | return (sp); |
---|
274 | } |
---|
275 | #define KEY_ALLOCSP_DEFAULT() \ |
---|
276 | key_allocsp_default(__FILE__, __LINE__) |
---|
277 | |
---|
278 | /* |
---|
279 | * For OUTBOUND packet having a socket. Searching SPD for packet, |
---|
280 | * and return a pointer to SP. |
---|
281 | * OUT: NULL: no apropreate SP found, the following value is set to error. |
---|
282 | * 0 : bypass |
---|
283 | * EACCES : discard packet. |
---|
284 | * ENOENT : ipsec_acquire() in progress, maybe. |
---|
285 | * others : error occured. |
---|
286 | * others: a pointer to SP |
---|
287 | * |
---|
288 | * NOTE: IPv6 mapped adddress concern is implemented here. |
---|
289 | */ |
---|
290 | struct secpolicy * |
---|
291 | ipsec_getpolicy(struct tdb_ident *tdbi, u_int dir) |
---|
292 | { |
---|
293 | struct secpolicy *sp; |
---|
294 | |
---|
295 | IPSEC_ASSERT(tdbi != NULL, ("null tdbi")); |
---|
296 | IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND, |
---|
297 | ("invalid direction %u", dir)); |
---|
298 | |
---|
299 | sp = KEY_ALLOCSP2(tdbi->spi, &tdbi->dst, tdbi->proto, dir); |
---|
300 | if (sp == NULL) /*XXX????*/ |
---|
301 | sp = KEY_ALLOCSP_DEFAULT(); |
---|
302 | IPSEC_ASSERT(sp != NULL, ("null SP")); |
---|
303 | return (sp); |
---|
304 | } |
---|
305 | |
---|
306 | /* |
---|
307 | * For OUTBOUND packet having a socket. Searching SPD for packet, |
---|
308 | * and return a pointer to SP. |
---|
309 | * OUT: NULL: no apropreate SP found, the following value is set to error. |
---|
310 | * 0 : bypass |
---|
311 | * EACCES : discard packet. |
---|
312 | * ENOENT : ipsec_acquire() in progress, maybe. |
---|
313 | * others : error occured. |
---|
314 | * others: a pointer to SP |
---|
315 | * |
---|
316 | * NOTE: IPv6 mapped adddress concern is implemented here. |
---|
317 | */ |
---|
318 | static struct secpolicy * |
---|
319 | ipsec_getpolicybysock(struct mbuf *m, u_int dir, struct inpcb *inp, int *error) |
---|
320 | { |
---|
321 | struct inpcbpolicy *pcbsp; |
---|
322 | struct secpolicy *currsp = NULL; /* Policy on socket. */ |
---|
323 | struct secpolicy *sp; |
---|
324 | |
---|
325 | IPSEC_ASSERT(m != NULL, ("null mbuf")); |
---|
326 | IPSEC_ASSERT(inp != NULL, ("null inpcb")); |
---|
327 | IPSEC_ASSERT(error != NULL, ("null error")); |
---|
328 | IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND, |
---|
329 | ("invalid direction %u", dir)); |
---|
330 | |
---|
331 | /* Set spidx in pcb. */ |
---|
332 | *error = ipsec_setspidx_inpcb(m, inp); |
---|
333 | if (*error) |
---|
334 | return (NULL); |
---|
335 | |
---|
336 | pcbsp = inp->inp_sp; |
---|
337 | IPSEC_ASSERT(pcbsp != NULL, ("null pcbsp")); |
---|
338 | switch (dir) { |
---|
339 | case IPSEC_DIR_INBOUND: |
---|
340 | currsp = pcbsp->sp_in; |
---|
341 | break; |
---|
342 | case IPSEC_DIR_OUTBOUND: |
---|
343 | currsp = pcbsp->sp_out; |
---|
344 | break; |
---|
345 | } |
---|
346 | IPSEC_ASSERT(currsp != NULL, ("null currsp")); |
---|
347 | |
---|
348 | if (pcbsp->priv) { /* When privilieged socket. */ |
---|
349 | switch (currsp->policy) { |
---|
350 | case IPSEC_POLICY_BYPASS: |
---|
351 | case IPSEC_POLICY_IPSEC: |
---|
352 | key_addref(currsp); |
---|
353 | sp = currsp; |
---|
354 | break; |
---|
355 | |
---|
356 | case IPSEC_POLICY_ENTRUST: |
---|
357 | /* Look for a policy in SPD. */ |
---|
358 | sp = KEY_ALLOCSP(&currsp->spidx, dir); |
---|
359 | if (sp == NULL) /* No SP found. */ |
---|
360 | sp = KEY_ALLOCSP_DEFAULT(); |
---|
361 | break; |
---|
362 | |
---|
363 | default: |
---|
364 | ipseclog((LOG_ERR, "%s: Invalid policy for PCB %d\n", |
---|
365 | __func__, currsp->policy)); |
---|
366 | *error = EINVAL; |
---|
367 | return (NULL); |
---|
368 | } |
---|
369 | } else { /* Unpriv, SPD has policy. */ |
---|
370 | sp = KEY_ALLOCSP(&currsp->spidx, dir); |
---|
371 | if (sp == NULL) { /* No SP found. */ |
---|
372 | switch (currsp->policy) { |
---|
373 | case IPSEC_POLICY_BYPASS: |
---|
374 | ipseclog((LOG_ERR, "%s: Illegal policy for " |
---|
375 | "non-priviliged defined %d\n", |
---|
376 | __func__, currsp->policy)); |
---|
377 | *error = EINVAL; |
---|
378 | return (NULL); |
---|
379 | |
---|
380 | case IPSEC_POLICY_ENTRUST: |
---|
381 | sp = KEY_ALLOCSP_DEFAULT(); |
---|
382 | break; |
---|
383 | |
---|
384 | case IPSEC_POLICY_IPSEC: |
---|
385 | key_addref(currsp); |
---|
386 | sp = currsp; |
---|
387 | break; |
---|
388 | |
---|
389 | default: |
---|
390 | ipseclog((LOG_ERR, "%s: Invalid policy for " |
---|
391 | "PCB %d\n", __func__, currsp->policy)); |
---|
392 | *error = EINVAL; |
---|
393 | return (NULL); |
---|
394 | } |
---|
395 | } |
---|
396 | } |
---|
397 | IPSEC_ASSERT(sp != NULL, |
---|
398 | ("null SP (priv %u policy %u", pcbsp->priv, currsp->policy)); |
---|
399 | KEYDEBUG(KEYDEBUG_IPSEC_STAMP, |
---|
400 | printf("DP %s (priv %u policy %u) allocate SP:%p (refcnt %u)\n", |
---|
401 | __func__, pcbsp->priv, currsp->policy, sp, sp->refcnt)); |
---|
402 | return (sp); |
---|
403 | } |
---|
404 | |
---|
405 | /* |
---|
406 | * For FORWADING packet or OUTBOUND without a socket. Searching SPD for packet, |
---|
407 | * and return a pointer to SP. |
---|
408 | * OUT: positive: a pointer to the entry for security policy leaf matched. |
---|
409 | * NULL: no apropreate SP found, the following value is set to error. |
---|
410 | * 0 : bypass |
---|
411 | * EACCES : discard packet. |
---|
412 | * ENOENT : ipsec_acquire() in progress, maybe. |
---|
413 | * others : error occured. |
---|
414 | */ |
---|
415 | struct secpolicy * |
---|
416 | ipsec_getpolicybyaddr(struct mbuf *m, u_int dir, int flag, int *error) |
---|
417 | { |
---|
418 | struct secpolicyindex spidx; |
---|
419 | struct secpolicy *sp; |
---|
420 | |
---|
421 | IPSEC_ASSERT(m != NULL, ("null mbuf")); |
---|
422 | IPSEC_ASSERT(error != NULL, ("null error")); |
---|
423 | IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND, |
---|
424 | ("invalid direction %u", dir)); |
---|
425 | |
---|
426 | sp = NULL; |
---|
427 | if (key_havesp(dir)) { |
---|
428 | /* Make an index to look for a policy. */ |
---|
429 | *error = ipsec_setspidx(m, &spidx, |
---|
430 | (flag & IP_FORWARDING) ? 0 : 1); |
---|
431 | if (*error != 0) { |
---|
432 | DPRINTF(("%s: setpidx failed, dir %u flag %u\n", |
---|
433 | __func__, dir, flag)); |
---|
434 | return (NULL); |
---|
435 | } |
---|
436 | spidx.dir = dir; |
---|
437 | |
---|
438 | sp = KEY_ALLOCSP(&spidx, dir); |
---|
439 | } |
---|
440 | if (sp == NULL) /* No SP found, use system default. */ |
---|
441 | sp = KEY_ALLOCSP_DEFAULT(); |
---|
442 | IPSEC_ASSERT(sp != NULL, ("null SP")); |
---|
443 | return (sp); |
---|
444 | } |
---|
445 | |
---|
446 | struct secpolicy * |
---|
447 | ipsec4_checkpolicy(struct mbuf *m, u_int dir, u_int flag, int *error, |
---|
448 | struct inpcb *inp) |
---|
449 | { |
---|
450 | struct secpolicy *sp; |
---|
451 | |
---|
452 | *error = 0; |
---|
453 | if (inp == NULL) |
---|
454 | sp = ipsec_getpolicybyaddr(m, dir, flag, error); |
---|
455 | else |
---|
456 | sp = ipsec_getpolicybysock(m, dir, inp, error); |
---|
457 | if (sp == NULL) { |
---|
458 | IPSEC_ASSERT(*error != 0, ("getpolicy failed w/o error")); |
---|
459 | IPSECSTAT_INC(ips_out_inval); |
---|
460 | return (NULL); |
---|
461 | } |
---|
462 | IPSEC_ASSERT(*error == 0, ("sp w/ error set to %u", *error)); |
---|
463 | switch (sp->policy) { |
---|
464 | case IPSEC_POLICY_ENTRUST: |
---|
465 | default: |
---|
466 | printf("%s: invalid policy %u\n", __func__, sp->policy); |
---|
467 | /* FALLTHROUGH */ |
---|
468 | case IPSEC_POLICY_DISCARD: |
---|
469 | IPSECSTAT_INC(ips_out_polvio); |
---|
470 | *error = -EINVAL; /* Packet is discarded by caller. */ |
---|
471 | break; |
---|
472 | case IPSEC_POLICY_BYPASS: |
---|
473 | case IPSEC_POLICY_NONE: |
---|
474 | KEY_FREESP(&sp); |
---|
475 | sp = NULL; /* NB: force NULL result. */ |
---|
476 | break; |
---|
477 | case IPSEC_POLICY_IPSEC: |
---|
478 | if (sp->req == NULL) /* Acquire a SA. */ |
---|
479 | *error = key_spdacquire(sp); |
---|
480 | break; |
---|
481 | } |
---|
482 | if (*error != 0) { |
---|
483 | KEY_FREESP(&sp); |
---|
484 | sp = NULL; |
---|
485 | } |
---|
486 | return (sp); |
---|
487 | } |
---|
488 | |
---|
489 | static int |
---|
490 | ipsec_setspidx_inpcb(struct mbuf *m, struct inpcb *inp) |
---|
491 | { |
---|
492 | int error; |
---|
493 | |
---|
494 | IPSEC_ASSERT(inp != NULL, ("null inp")); |
---|
495 | IPSEC_ASSERT(inp->inp_sp != NULL, ("null inp_sp")); |
---|
496 | IPSEC_ASSERT(inp->inp_sp->sp_out != NULL && inp->inp_sp->sp_in != NULL, |
---|
497 | ("null sp_in || sp_out")); |
---|
498 | |
---|
499 | error = ipsec_setspidx(m, &inp->inp_sp->sp_in->spidx, 1); |
---|
500 | if (error == 0) { |
---|
501 | inp->inp_sp->sp_in->spidx.dir = IPSEC_DIR_INBOUND; |
---|
502 | inp->inp_sp->sp_out->spidx = inp->inp_sp->sp_in->spidx; |
---|
503 | inp->inp_sp->sp_out->spidx.dir = IPSEC_DIR_OUTBOUND; |
---|
504 | } else { |
---|
505 | bzero(&inp->inp_sp->sp_in->spidx, |
---|
506 | sizeof (inp->inp_sp->sp_in->spidx)); |
---|
507 | bzero(&inp->inp_sp->sp_out->spidx, |
---|
508 | sizeof (inp->inp_sp->sp_in->spidx)); |
---|
509 | } |
---|
510 | return (error); |
---|
511 | } |
---|
512 | |
---|
513 | /* |
---|
514 | * Configure security policy index (src/dst/proto/sport/dport) |
---|
515 | * by looking at the content of mbuf. |
---|
516 | * The caller is responsible for error recovery (like clearing up spidx). |
---|
517 | */ |
---|
518 | static int |
---|
519 | ipsec_setspidx(struct mbuf *m, struct secpolicyindex *spidx, int needport) |
---|
520 | { |
---|
521 | struct ip *ip = NULL; |
---|
522 | struct ip ipbuf; |
---|
523 | u_int v; |
---|
524 | struct mbuf *n; |
---|
525 | int len; |
---|
526 | int error; |
---|
527 | |
---|
528 | IPSEC_ASSERT(m != NULL, ("null mbuf")); |
---|
529 | |
---|
530 | /* |
---|
531 | * Validate m->m_pkthdr.len. We see incorrect length if we |
---|
532 | * mistakenly call this function with inconsistent mbuf chain |
---|
533 | * (like 4.4BSD tcp/udp processing). XXX Should we panic here? |
---|
534 | */ |
---|
535 | len = 0; |
---|
536 | for (n = m; n; n = n->m_next) |
---|
537 | len += n->m_len; |
---|
538 | if (m->m_pkthdr.len != len) { |
---|
539 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, |
---|
540 | printf("%s: pkthdr len(%d) mismatch (%d), ignored.\n", |
---|
541 | __func__, len, m->m_pkthdr.len)); |
---|
542 | return (EINVAL); |
---|
543 | } |
---|
544 | |
---|
545 | if (m->m_pkthdr.len < sizeof(struct ip)) { |
---|
546 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, |
---|
547 | printf("%s: pkthdr len(%d) too small (v4), ignored.\n", |
---|
548 | __func__, m->m_pkthdr.len)); |
---|
549 | return (EINVAL); |
---|
550 | } |
---|
551 | |
---|
552 | if (m->m_len >= sizeof(*ip)) |
---|
553 | ip = mtod(m, struct ip *); |
---|
554 | else { |
---|
555 | m_copydata(m, 0, sizeof(ipbuf), (caddr_t)&ipbuf); |
---|
556 | ip = &ipbuf; |
---|
557 | } |
---|
558 | #ifdef _IP_VHL |
---|
559 | v = _IP_VHL_V(ip->ip_vhl); |
---|
560 | #else |
---|
561 | v = ip->ip_v; |
---|
562 | #endif |
---|
563 | switch (v) { |
---|
564 | case 4: |
---|
565 | error = ipsec4_setspidx_ipaddr(m, spidx); |
---|
566 | if (error) |
---|
567 | return (error); |
---|
568 | ipsec4_get_ulp(m, spidx, needport); |
---|
569 | return (0); |
---|
570 | #ifdef INET6 |
---|
571 | case 6: |
---|
572 | if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) { |
---|
573 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, |
---|
574 | printf("%s: pkthdr len(%d) too small (v6), " |
---|
575 | "ignored\n", __func__, m->m_pkthdr.len)); |
---|
576 | return (EINVAL); |
---|
577 | } |
---|
578 | error = ipsec6_setspidx_ipaddr(m, spidx); |
---|
579 | if (error) |
---|
580 | return (error); |
---|
581 | ipsec6_get_ulp(m, spidx, needport); |
---|
582 | return (0); |
---|
583 | #endif |
---|
584 | default: |
---|
585 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, |
---|
586 | printf("%s: " "unknown IP version %u, ignored.\n", |
---|
587 | __func__, v)); |
---|
588 | return (EINVAL); |
---|
589 | } |
---|
590 | } |
---|
591 | |
---|
592 | static void |
---|
593 | ipsec4_get_ulp(struct mbuf *m, struct secpolicyindex *spidx, int needport) |
---|
594 | { |
---|
595 | u_int8_t nxt; |
---|
596 | int off; |
---|
597 | |
---|
598 | /* Sanity check. */ |
---|
599 | IPSEC_ASSERT(m != NULL, ("null mbuf")); |
---|
600 | IPSEC_ASSERT(m->m_pkthdr.len >= sizeof(struct ip),("packet too short")); |
---|
601 | |
---|
602 | /* NB: ip_input() flips it into host endian. XXX Need more checking. */ |
---|
603 | if (m->m_len >= sizeof (struct ip)) { |
---|
604 | struct ip *ip = mtod(m, struct ip *); |
---|
605 | if (ip->ip_off & (IP_MF | IP_OFFMASK)) |
---|
606 | goto done; |
---|
607 | #ifdef _IP_VHL |
---|
608 | off = _IP_VHL_HL(ip->ip_vhl) << 2; |
---|
609 | #else |
---|
610 | off = ip->ip_hl << 2; |
---|
611 | #endif |
---|
612 | nxt = ip->ip_p; |
---|
613 | } else { |
---|
614 | struct ip ih; |
---|
615 | |
---|
616 | m_copydata(m, 0, sizeof (struct ip), (caddr_t) &ih); |
---|
617 | if (ih.ip_off & (IP_MF | IP_OFFMASK)) |
---|
618 | goto done; |
---|
619 | #ifdef _IP_VHL |
---|
620 | off = _IP_VHL_HL(ih.ip_vhl) << 2; |
---|
621 | #else |
---|
622 | off = ih.ip_hl << 2; |
---|
623 | #endif |
---|
624 | nxt = ih.ip_p; |
---|
625 | } |
---|
626 | |
---|
627 | while (off < m->m_pkthdr.len) { |
---|
628 | struct ip6_ext ip6e; |
---|
629 | struct tcphdr th; |
---|
630 | struct udphdr uh; |
---|
631 | |
---|
632 | switch (nxt) { |
---|
633 | case IPPROTO_TCP: |
---|
634 | spidx->ul_proto = nxt; |
---|
635 | if (!needport) |
---|
636 | goto done_proto; |
---|
637 | if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) |
---|
638 | goto done; |
---|
639 | m_copydata(m, off, sizeof (th), (caddr_t) &th); |
---|
640 | spidx->src.sin.sin_port = th.th_sport; |
---|
641 | spidx->dst.sin.sin_port = th.th_dport; |
---|
642 | return; |
---|
643 | case IPPROTO_UDP: |
---|
644 | spidx->ul_proto = nxt; |
---|
645 | if (!needport) |
---|
646 | goto done_proto; |
---|
647 | if (off + sizeof(struct udphdr) > m->m_pkthdr.len) |
---|
648 | goto done; |
---|
649 | m_copydata(m, off, sizeof (uh), (caddr_t) &uh); |
---|
650 | spidx->src.sin.sin_port = uh.uh_sport; |
---|
651 | spidx->dst.sin.sin_port = uh.uh_dport; |
---|
652 | return; |
---|
653 | case IPPROTO_AH: |
---|
654 | if (off + sizeof(ip6e) > m->m_pkthdr.len) |
---|
655 | goto done; |
---|
656 | /* XXX Sigh, this works but is totally bogus. */ |
---|
657 | m_copydata(m, off, sizeof(ip6e), (caddr_t) &ip6e); |
---|
658 | off += (ip6e.ip6e_len + 2) << 2; |
---|
659 | nxt = ip6e.ip6e_nxt; |
---|
660 | break; |
---|
661 | case IPPROTO_ICMP: |
---|
662 | default: |
---|
663 | /* XXX Intermediate headers??? */ |
---|
664 | spidx->ul_proto = nxt; |
---|
665 | goto done_proto; |
---|
666 | } |
---|
667 | } |
---|
668 | done: |
---|
669 | spidx->ul_proto = IPSEC_ULPROTO_ANY; |
---|
670 | done_proto: |
---|
671 | spidx->src.sin.sin_port = IPSEC_PORT_ANY; |
---|
672 | spidx->dst.sin.sin_port = IPSEC_PORT_ANY; |
---|
673 | } |
---|
674 | |
---|
675 | /* Assumes that m is sane. */ |
---|
676 | static int |
---|
677 | ipsec4_setspidx_ipaddr(struct mbuf *m, struct secpolicyindex *spidx) |
---|
678 | { |
---|
679 | static const struct sockaddr_in template = { |
---|
680 | sizeof (struct sockaddr_in), |
---|
681 | AF_INET, |
---|
682 | 0, { 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } |
---|
683 | }; |
---|
684 | |
---|
685 | spidx->src.sin = template; |
---|
686 | spidx->dst.sin = template; |
---|
687 | |
---|
688 | if (m->m_len < sizeof (struct ip)) { |
---|
689 | m_copydata(m, offsetof(struct ip, ip_src), |
---|
690 | sizeof (struct in_addr), |
---|
691 | (caddr_t) &spidx->src.sin.sin_addr); |
---|
692 | m_copydata(m, offsetof(struct ip, ip_dst), |
---|
693 | sizeof (struct in_addr), |
---|
694 | (caddr_t) &spidx->dst.sin.sin_addr); |
---|
695 | } else { |
---|
696 | struct ip *ip = mtod(m, struct ip *); |
---|
697 | spidx->src.sin.sin_addr = ip->ip_src; |
---|
698 | spidx->dst.sin.sin_addr = ip->ip_dst; |
---|
699 | } |
---|
700 | |
---|
701 | spidx->prefs = sizeof(struct in_addr) << 3; |
---|
702 | spidx->prefd = sizeof(struct in_addr) << 3; |
---|
703 | |
---|
704 | return (0); |
---|
705 | } |
---|
706 | |
---|
707 | #ifdef INET6 |
---|
708 | static void |
---|
709 | ipsec6_get_ulp(struct mbuf *m, struct secpolicyindex *spidx, int needport) |
---|
710 | { |
---|
711 | int off, nxt; |
---|
712 | struct tcphdr th; |
---|
713 | struct udphdr uh; |
---|
714 | struct icmp6_hdr ih; |
---|
715 | |
---|
716 | /* Sanity check. */ |
---|
717 | if (m == NULL) |
---|
718 | panic("%s: NULL pointer was passed.\n", __func__); |
---|
719 | |
---|
720 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, |
---|
721 | printf("%s:\n", __func__); kdebug_mbuf(m)); |
---|
722 | |
---|
723 | /* Set default. */ |
---|
724 | spidx->ul_proto = IPSEC_ULPROTO_ANY; |
---|
725 | ((struct sockaddr_in6 *)&spidx->src)->sin6_port = IPSEC_PORT_ANY; |
---|
726 | ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = IPSEC_PORT_ANY; |
---|
727 | |
---|
728 | nxt = -1; |
---|
729 | off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt); |
---|
730 | if (off < 0 || m->m_pkthdr.len < off) |
---|
731 | return; |
---|
732 | |
---|
733 | switch (nxt) { |
---|
734 | case IPPROTO_TCP: |
---|
735 | spidx->ul_proto = nxt; |
---|
736 | if (!needport) |
---|
737 | break; |
---|
738 | if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) |
---|
739 | break; |
---|
740 | m_copydata(m, off, sizeof(th), (caddr_t)&th); |
---|
741 | ((struct sockaddr_in6 *)&spidx->src)->sin6_port = th.th_sport; |
---|
742 | ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = th.th_dport; |
---|
743 | break; |
---|
744 | case IPPROTO_UDP: |
---|
745 | spidx->ul_proto = nxt; |
---|
746 | if (!needport) |
---|
747 | break; |
---|
748 | if (off + sizeof(struct udphdr) > m->m_pkthdr.len) |
---|
749 | break; |
---|
750 | m_copydata(m, off, sizeof(uh), (caddr_t)&uh); |
---|
751 | ((struct sockaddr_in6 *)&spidx->src)->sin6_port = uh.uh_sport; |
---|
752 | ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = uh.uh_dport; |
---|
753 | break; |
---|
754 | case IPPROTO_ICMPV6: |
---|
755 | spidx->ul_proto = nxt; |
---|
756 | if (off + sizeof(struct icmp6_hdr) > m->m_pkthdr.len) |
---|
757 | break; |
---|
758 | m_copydata(m, off, sizeof(ih), (caddr_t)&ih); |
---|
759 | ((struct sockaddr_in6 *)&spidx->src)->sin6_port = |
---|
760 | htons((uint16_t)ih.icmp6_type); |
---|
761 | ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = |
---|
762 | htons((uint16_t)ih.icmp6_code); |
---|
763 | break; |
---|
764 | default: |
---|
765 | /* XXX Intermediate headers??? */ |
---|
766 | spidx->ul_proto = nxt; |
---|
767 | break; |
---|
768 | } |
---|
769 | } |
---|
770 | |
---|
771 | /* Assumes that m is sane. */ |
---|
772 | static int |
---|
773 | ipsec6_setspidx_ipaddr(struct mbuf *m, struct secpolicyindex *spidx) |
---|
774 | { |
---|
775 | struct ip6_hdr *ip6 = NULL; |
---|
776 | struct ip6_hdr ip6buf; |
---|
777 | struct sockaddr_in6 *sin6; |
---|
778 | |
---|
779 | if (m->m_len >= sizeof(*ip6)) |
---|
780 | ip6 = mtod(m, struct ip6_hdr *); |
---|
781 | else { |
---|
782 | m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf); |
---|
783 | ip6 = &ip6buf; |
---|
784 | } |
---|
785 | |
---|
786 | sin6 = (struct sockaddr_in6 *)&spidx->src; |
---|
787 | bzero(sin6, sizeof(*sin6)); |
---|
788 | sin6->sin6_family = AF_INET6; |
---|
789 | sin6->sin6_len = sizeof(struct sockaddr_in6); |
---|
790 | bcopy(&ip6->ip6_src, &sin6->sin6_addr, sizeof(ip6->ip6_src)); |
---|
791 | if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) { |
---|
792 | sin6->sin6_addr.s6_addr16[1] = 0; |
---|
793 | sin6->sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]); |
---|
794 | } |
---|
795 | spidx->prefs = sizeof(struct in6_addr) << 3; |
---|
796 | |
---|
797 | sin6 = (struct sockaddr_in6 *)&spidx->dst; |
---|
798 | bzero(sin6, sizeof(*sin6)); |
---|
799 | sin6->sin6_family = AF_INET6; |
---|
800 | sin6->sin6_len = sizeof(struct sockaddr_in6); |
---|
801 | bcopy(&ip6->ip6_dst, &sin6->sin6_addr, sizeof(ip6->ip6_dst)); |
---|
802 | if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { |
---|
803 | sin6->sin6_addr.s6_addr16[1] = 0; |
---|
804 | sin6->sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]); |
---|
805 | } |
---|
806 | spidx->prefd = sizeof(struct in6_addr) << 3; |
---|
807 | |
---|
808 | return (0); |
---|
809 | } |
---|
810 | #endif |
---|
811 | |
---|
812 | static void |
---|
813 | ipsec_delpcbpolicy(struct inpcbpolicy *p) |
---|
814 | { |
---|
815 | |
---|
816 | free(p, M_IPSEC_INPCB); |
---|
817 | } |
---|
818 | |
---|
819 | /* Initialize policy in PCB. */ |
---|
820 | int |
---|
821 | ipsec_init_policy(struct socket *so, struct inpcbpolicy **pcb_sp) |
---|
822 | { |
---|
823 | struct inpcbpolicy *new; |
---|
824 | |
---|
825 | /* Sanity check. */ |
---|
826 | if (so == NULL || pcb_sp == NULL) |
---|
827 | panic("%s: NULL pointer was passed.\n", __func__); |
---|
828 | |
---|
829 | new = (struct inpcbpolicy *) malloc(sizeof(struct inpcbpolicy), |
---|
830 | M_IPSEC_INPCB, M_NOWAIT|M_ZERO); |
---|
831 | if (new == NULL) { |
---|
832 | ipseclog((LOG_DEBUG, "%s: No more memory.\n", __func__)); |
---|
833 | return (ENOBUFS); |
---|
834 | } |
---|
835 | |
---|
836 | new->priv = IPSEC_IS_PRIVILEGED_SO(so); |
---|
837 | |
---|
838 | if ((new->sp_in = KEY_NEWSP()) == NULL) { |
---|
839 | ipsec_delpcbpolicy(new); |
---|
840 | return (ENOBUFS); |
---|
841 | } |
---|
842 | new->sp_in->state = IPSEC_SPSTATE_ALIVE; |
---|
843 | new->sp_in->policy = IPSEC_POLICY_ENTRUST; |
---|
844 | |
---|
845 | if ((new->sp_out = KEY_NEWSP()) == NULL) { |
---|
846 | KEY_FREESP(&new->sp_in); |
---|
847 | ipsec_delpcbpolicy(new); |
---|
848 | return (ENOBUFS); |
---|
849 | } |
---|
850 | new->sp_out->state = IPSEC_SPSTATE_ALIVE; |
---|
851 | new->sp_out->policy = IPSEC_POLICY_ENTRUST; |
---|
852 | |
---|
853 | *pcb_sp = new; |
---|
854 | |
---|
855 | return (0); |
---|
856 | } |
---|
857 | |
---|
858 | /* Copy old IPsec policy into new. */ |
---|
859 | int |
---|
860 | ipsec_copy_policy(struct inpcbpolicy *old, struct inpcbpolicy *new) |
---|
861 | { |
---|
862 | struct secpolicy *sp; |
---|
863 | |
---|
864 | sp = ipsec_deepcopy_policy(old->sp_in); |
---|
865 | if (sp) { |
---|
866 | KEY_FREESP(&new->sp_in); |
---|
867 | new->sp_in = sp; |
---|
868 | } else |
---|
869 | return (ENOBUFS); |
---|
870 | |
---|
871 | sp = ipsec_deepcopy_policy(old->sp_out); |
---|
872 | if (sp) { |
---|
873 | KEY_FREESP(&new->sp_out); |
---|
874 | new->sp_out = sp; |
---|
875 | } else |
---|
876 | return (ENOBUFS); |
---|
877 | |
---|
878 | new->priv = old->priv; |
---|
879 | |
---|
880 | return (0); |
---|
881 | } |
---|
882 | |
---|
883 | struct ipsecrequest * |
---|
884 | ipsec_newisr(void) |
---|
885 | { |
---|
886 | struct ipsecrequest *p; |
---|
887 | |
---|
888 | p = malloc(sizeof(struct ipsecrequest), M_IPSEC_SR, M_NOWAIT|M_ZERO); |
---|
889 | if (p != NULL) |
---|
890 | IPSECREQUEST_LOCK_INIT(p); |
---|
891 | return (p); |
---|
892 | } |
---|
893 | |
---|
894 | void |
---|
895 | ipsec_delisr(struct ipsecrequest *p) |
---|
896 | { |
---|
897 | |
---|
898 | IPSECREQUEST_LOCK_DESTROY(p); |
---|
899 | free(p, M_IPSEC_SR); |
---|
900 | } |
---|
901 | |
---|
902 | /* Deep-copy a policy in PCB. */ |
---|
903 | static struct secpolicy * |
---|
904 | ipsec_deepcopy_policy(struct secpolicy *src) |
---|
905 | { |
---|
906 | struct ipsecrequest *newchain = NULL; |
---|
907 | struct ipsecrequest *p; |
---|
908 | struct ipsecrequest **q; |
---|
909 | struct ipsecrequest *r; |
---|
910 | struct secpolicy *dst; |
---|
911 | |
---|
912 | if (src == NULL) |
---|
913 | return (NULL); |
---|
914 | dst = KEY_NEWSP(); |
---|
915 | if (dst == NULL) |
---|
916 | return (NULL); |
---|
917 | |
---|
918 | /* |
---|
919 | * Deep-copy IPsec request chain. This is required since struct |
---|
920 | * ipsecrequest is not reference counted. |
---|
921 | */ |
---|
922 | q = &newchain; |
---|
923 | for (p = src->req; p; p = p->next) { |
---|
924 | *q = ipsec_newisr(); |
---|
925 | if (*q == NULL) |
---|
926 | goto fail; |
---|
927 | (*q)->saidx.proto = p->saidx.proto; |
---|
928 | (*q)->saidx.mode = p->saidx.mode; |
---|
929 | (*q)->level = p->level; |
---|
930 | (*q)->saidx.reqid = p->saidx.reqid; |
---|
931 | |
---|
932 | bcopy(&p->saidx.src, &(*q)->saidx.src, sizeof((*q)->saidx.src)); |
---|
933 | bcopy(&p->saidx.dst, &(*q)->saidx.dst, sizeof((*q)->saidx.dst)); |
---|
934 | |
---|
935 | (*q)->sp = dst; |
---|
936 | |
---|
937 | q = &((*q)->next); |
---|
938 | } |
---|
939 | |
---|
940 | dst->req = newchain; |
---|
941 | dst->state = src->state; |
---|
942 | dst->policy = src->policy; |
---|
943 | /* Do not touch the refcnt fields. */ |
---|
944 | |
---|
945 | return (dst); |
---|
946 | |
---|
947 | fail: |
---|
948 | for (p = newchain; p; p = r) { |
---|
949 | r = p->next; |
---|
950 | ipsec_delisr(p); |
---|
951 | p = NULL; |
---|
952 | } |
---|
953 | return (NULL); |
---|
954 | } |
---|
955 | |
---|
956 | /* Set policy and IPsec request if present. */ |
---|
957 | static int |
---|
958 | ipsec_set_policy_internal(struct secpolicy **pcb_sp, int optname, |
---|
959 | caddr_t request, size_t len, struct ucred *cred) |
---|
960 | { |
---|
961 | struct sadb_x_policy *xpl; |
---|
962 | struct secpolicy *newsp = NULL; |
---|
963 | int error; |
---|
964 | |
---|
965 | /* Sanity check. */ |
---|
966 | if (pcb_sp == NULL || *pcb_sp == NULL || request == NULL) |
---|
967 | return (EINVAL); |
---|
968 | if (len < sizeof(*xpl)) |
---|
969 | return (EINVAL); |
---|
970 | xpl = (struct sadb_x_policy *)request; |
---|
971 | |
---|
972 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, |
---|
973 | printf("%s: passed policy\n", __func__); |
---|
974 | kdebug_sadb_x_policy((struct sadb_ext *)xpl)); |
---|
975 | |
---|
976 | /* Check policy type. */ |
---|
977 | /* ipsec_set_policy_internal() accepts IPSEC, ENTRUST and BYPASS. */ |
---|
978 | if (xpl->sadb_x_policy_type == IPSEC_POLICY_DISCARD |
---|
979 | || xpl->sadb_x_policy_type == IPSEC_POLICY_NONE) |
---|
980 | return (EINVAL); |
---|
981 | |
---|
982 | /* Check privileged socket. */ |
---|
983 | if (cred != NULL && xpl->sadb_x_policy_type == IPSEC_POLICY_BYPASS) { |
---|
984 | error = priv_check_cred(cred, PRIV_NETINET_IPSEC, 0); |
---|
985 | if (error) |
---|
986 | return (EACCES); |
---|
987 | } |
---|
988 | |
---|
989 | /* Allocating new SP entry. */ |
---|
990 | if ((newsp = key_msg2sp(xpl, len, &error)) == NULL) |
---|
991 | return (error); |
---|
992 | |
---|
993 | newsp->state = IPSEC_SPSTATE_ALIVE; |
---|
994 | |
---|
995 | /* Clear old SP and set new SP. */ |
---|
996 | KEY_FREESP(pcb_sp); |
---|
997 | *pcb_sp = newsp; |
---|
998 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, |
---|
999 | printf("%s: new policy\n", __func__); |
---|
1000 | kdebug_secpolicy(newsp)); |
---|
1001 | |
---|
1002 | return (0); |
---|
1003 | } |
---|
1004 | |
---|
1005 | int |
---|
1006 | ipsec_set_policy(struct inpcb *inp, int optname, caddr_t request, |
---|
1007 | size_t len, struct ucred *cred) |
---|
1008 | { |
---|
1009 | struct sadb_x_policy *xpl; |
---|
1010 | struct secpolicy **pcb_sp; |
---|
1011 | |
---|
1012 | /* Sanity check. */ |
---|
1013 | if (inp == NULL || request == NULL) |
---|
1014 | return (EINVAL); |
---|
1015 | if (len < sizeof(*xpl)) |
---|
1016 | return (EINVAL); |
---|
1017 | xpl = (struct sadb_x_policy *)request; |
---|
1018 | |
---|
1019 | /* Select direction. */ |
---|
1020 | switch (xpl->sadb_x_policy_dir) { |
---|
1021 | case IPSEC_DIR_INBOUND: |
---|
1022 | pcb_sp = &inp->inp_sp->sp_in; |
---|
1023 | break; |
---|
1024 | case IPSEC_DIR_OUTBOUND: |
---|
1025 | pcb_sp = &inp->inp_sp->sp_out; |
---|
1026 | break; |
---|
1027 | default: |
---|
1028 | ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__, |
---|
1029 | xpl->sadb_x_policy_dir)); |
---|
1030 | return (EINVAL); |
---|
1031 | } |
---|
1032 | |
---|
1033 | return (ipsec_set_policy_internal(pcb_sp, optname, request, len, cred)); |
---|
1034 | } |
---|
1035 | |
---|
1036 | int |
---|
1037 | ipsec_get_policy(struct inpcb *inp, caddr_t request, size_t len, |
---|
1038 | struct mbuf **mp) |
---|
1039 | { |
---|
1040 | struct sadb_x_policy *xpl; |
---|
1041 | struct secpolicy *pcb_sp; |
---|
1042 | |
---|
1043 | /* Sanity check. */ |
---|
1044 | if (inp == NULL || request == NULL || mp == NULL) |
---|
1045 | return (EINVAL); |
---|
1046 | IPSEC_ASSERT(inp->inp_sp != NULL, ("null inp_sp")); |
---|
1047 | if (len < sizeof(*xpl)) |
---|
1048 | return (EINVAL); |
---|
1049 | xpl = (struct sadb_x_policy *)request; |
---|
1050 | |
---|
1051 | /* Select direction. */ |
---|
1052 | switch (xpl->sadb_x_policy_dir) { |
---|
1053 | case IPSEC_DIR_INBOUND: |
---|
1054 | pcb_sp = inp->inp_sp->sp_in; |
---|
1055 | break; |
---|
1056 | case IPSEC_DIR_OUTBOUND: |
---|
1057 | pcb_sp = inp->inp_sp->sp_out; |
---|
1058 | break; |
---|
1059 | default: |
---|
1060 | ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__, |
---|
1061 | xpl->sadb_x_policy_dir)); |
---|
1062 | return (EINVAL); |
---|
1063 | } |
---|
1064 | |
---|
1065 | /* Sanity check. Should be an IPSEC_ASSERT. */ |
---|
1066 | if (pcb_sp == NULL) |
---|
1067 | return (EINVAL); |
---|
1068 | |
---|
1069 | *mp = key_sp2msg(pcb_sp); |
---|
1070 | if (!*mp) { |
---|
1071 | ipseclog((LOG_DEBUG, "%s: No more memory.\n", __func__)); |
---|
1072 | return (ENOBUFS); |
---|
1073 | } |
---|
1074 | |
---|
1075 | (*mp)->m_type = MT_DATA; |
---|
1076 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, |
---|
1077 | printf("%s:\n", __func__); kdebug_mbuf(*mp)); |
---|
1078 | |
---|
1079 | return (0); |
---|
1080 | } |
---|
1081 | |
---|
1082 | /* Delete policy in PCB. */ |
---|
1083 | int |
---|
1084 | ipsec_delete_pcbpolicy(struct inpcb *inp) |
---|
1085 | { |
---|
1086 | IPSEC_ASSERT(inp != NULL, ("null inp")); |
---|
1087 | |
---|
1088 | if (inp->inp_sp == NULL) |
---|
1089 | return (0); |
---|
1090 | |
---|
1091 | if (inp->inp_sp->sp_in != NULL) |
---|
1092 | KEY_FREESP(&inp->inp_sp->sp_in); |
---|
1093 | |
---|
1094 | if (inp->inp_sp->sp_out != NULL) |
---|
1095 | KEY_FREESP(&inp->inp_sp->sp_out); |
---|
1096 | |
---|
1097 | ipsec_delpcbpolicy(inp->inp_sp); |
---|
1098 | inp->inp_sp = NULL; |
---|
1099 | |
---|
1100 | return (0); |
---|
1101 | } |
---|
1102 | |
---|
1103 | /* |
---|
1104 | * Return current level. |
---|
1105 | * Either IPSEC_LEVEL_USE or IPSEC_LEVEL_REQUIRE are always returned. |
---|
1106 | */ |
---|
1107 | u_int |
---|
1108 | ipsec_get_reqlevel(struct ipsecrequest *isr) |
---|
1109 | { |
---|
1110 | u_int level = 0; |
---|
1111 | u_int esp_trans_deflev, esp_net_deflev; |
---|
1112 | u_int ah_trans_deflev, ah_net_deflev; |
---|
1113 | |
---|
1114 | IPSEC_ASSERT(isr != NULL && isr->sp != NULL, ("null argument")); |
---|
1115 | IPSEC_ASSERT(isr->sp->spidx.src.sa.sa_family == isr->sp->spidx.dst.sa.sa_family, |
---|
1116 | ("af family mismatch, src %u, dst %u", |
---|
1117 | isr->sp->spidx.src.sa.sa_family, |
---|
1118 | isr->sp->spidx.dst.sa.sa_family)); |
---|
1119 | |
---|
1120 | /* XXX Note that we have ipseclog() expanded here - code sync issue. */ |
---|
1121 | #define IPSEC_CHECK_DEFAULT(lev) \ |
---|
1122 | (((lev) != IPSEC_LEVEL_USE && (lev) != IPSEC_LEVEL_REQUIRE \ |
---|
1123 | && (lev) != IPSEC_LEVEL_UNIQUE) \ |
---|
1124 | ? (V_ipsec_debug \ |
---|
1125 | ? log(LOG_INFO, "fixed system default level " #lev ":%d->%d\n",\ |
---|
1126 | (lev), IPSEC_LEVEL_REQUIRE) \ |
---|
1127 | : 0), \ |
---|
1128 | (lev) = IPSEC_LEVEL_REQUIRE, \ |
---|
1129 | (lev) \ |
---|
1130 | : (lev)) |
---|
1131 | |
---|
1132 | /* Set default level. */ |
---|
1133 | switch (((struct sockaddr *)&isr->sp->spidx.src)->sa_family) { |
---|
1134 | #ifdef INET |
---|
1135 | case AF_INET: |
---|
1136 | esp_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip4_esp_trans_deflev); |
---|
1137 | esp_net_deflev = IPSEC_CHECK_DEFAULT(V_ip4_esp_net_deflev); |
---|
1138 | ah_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip4_ah_trans_deflev); |
---|
1139 | ah_net_deflev = IPSEC_CHECK_DEFAULT(V_ip4_ah_net_deflev); |
---|
1140 | break; |
---|
1141 | #endif |
---|
1142 | #ifdef INET6 |
---|
1143 | case AF_INET6: |
---|
1144 | esp_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip6_esp_trans_deflev); |
---|
1145 | esp_net_deflev = IPSEC_CHECK_DEFAULT(V_ip6_esp_net_deflev); |
---|
1146 | ah_trans_deflev = IPSEC_CHECK_DEFAULT(V_ip6_ah_trans_deflev); |
---|
1147 | ah_net_deflev = IPSEC_CHECK_DEFAULT(V_ip6_ah_net_deflev); |
---|
1148 | break; |
---|
1149 | #endif /* INET6 */ |
---|
1150 | default: |
---|
1151 | panic("%s: unknown af %u", |
---|
1152 | __func__, isr->sp->spidx.src.sa.sa_family); |
---|
1153 | } |
---|
1154 | |
---|
1155 | #undef IPSEC_CHECK_DEFAULT |
---|
1156 | |
---|
1157 | /* Set level. */ |
---|
1158 | switch (isr->level) { |
---|
1159 | case IPSEC_LEVEL_DEFAULT: |
---|
1160 | switch (isr->saidx.proto) { |
---|
1161 | case IPPROTO_ESP: |
---|
1162 | if (isr->saidx.mode == IPSEC_MODE_TUNNEL) |
---|
1163 | level = esp_net_deflev; |
---|
1164 | else |
---|
1165 | level = esp_trans_deflev; |
---|
1166 | break; |
---|
1167 | case IPPROTO_AH: |
---|
1168 | if (isr->saidx.mode == IPSEC_MODE_TUNNEL) |
---|
1169 | level = ah_net_deflev; |
---|
1170 | else |
---|
1171 | level = ah_trans_deflev; |
---|
1172 | break; |
---|
1173 | case IPPROTO_IPCOMP: |
---|
1174 | /* |
---|
1175 | * We don't really care, as IPcomp document says that |
---|
1176 | * we shouldn't compress small packets. |
---|
1177 | */ |
---|
1178 | level = IPSEC_LEVEL_USE; |
---|
1179 | break; |
---|
1180 | default: |
---|
1181 | panic("%s: Illegal protocol defined %u\n", __func__, |
---|
1182 | isr->saidx.proto); |
---|
1183 | } |
---|
1184 | break; |
---|
1185 | |
---|
1186 | case IPSEC_LEVEL_USE: |
---|
1187 | case IPSEC_LEVEL_REQUIRE: |
---|
1188 | level = isr->level; |
---|
1189 | break; |
---|
1190 | case IPSEC_LEVEL_UNIQUE: |
---|
1191 | level = IPSEC_LEVEL_REQUIRE; |
---|
1192 | break; |
---|
1193 | |
---|
1194 | default: |
---|
1195 | panic("%s: Illegal IPsec level %u\n", __func__, isr->level); |
---|
1196 | } |
---|
1197 | |
---|
1198 | return (level); |
---|
1199 | } |
---|
1200 | |
---|
1201 | /* |
---|
1202 | * Check security policy requirements against the actual |
---|
1203 | * packet contents. Return one if the packet should be |
---|
1204 | * reject as "invalid"; otherwiser return zero to have the |
---|
1205 | * packet treated as "valid". |
---|
1206 | * |
---|
1207 | * OUT: |
---|
1208 | * 0: valid |
---|
1209 | * 1: invalid |
---|
1210 | */ |
---|
1211 | int |
---|
1212 | ipsec_in_reject(struct secpolicy *sp, struct mbuf *m) |
---|
1213 | { |
---|
1214 | struct ipsecrequest *isr; |
---|
1215 | int need_auth; |
---|
1216 | |
---|
1217 | KEYDEBUG(KEYDEBUG_IPSEC_DATA, |
---|
1218 | printf("%s: using SP\n", __func__); kdebug_secpolicy(sp)); |
---|
1219 | |
---|
1220 | /* Check policy. */ |
---|
1221 | switch (sp->policy) { |
---|
1222 | case IPSEC_POLICY_DISCARD: |
---|
1223 | return (1); |
---|
1224 | case IPSEC_POLICY_BYPASS: |
---|
1225 | case IPSEC_POLICY_NONE: |
---|
1226 | return (0); |
---|
1227 | } |
---|
1228 | |
---|
1229 | IPSEC_ASSERT(sp->policy == IPSEC_POLICY_IPSEC, |
---|
1230 | ("invalid policy %u", sp->policy)); |
---|
1231 | |
---|
1232 | /* XXX Should compare policy against IPsec header history. */ |
---|
1233 | |
---|
1234 | need_auth = 0; |
---|
1235 | for (isr = sp->req; isr != NULL; isr = isr->next) { |
---|
1236 | if (ipsec_get_reqlevel(isr) != IPSEC_LEVEL_REQUIRE) |
---|
1237 | continue; |
---|
1238 | switch (isr->saidx.proto) { |
---|
1239 | case IPPROTO_ESP: |
---|
1240 | if ((m->m_flags & M_DECRYPTED) == 0) { |
---|
1241 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, |
---|
1242 | printf("%s: ESP m_flags:%x\n", __func__, |
---|
1243 | m->m_flags)); |
---|
1244 | return (1); |
---|
1245 | } |
---|
1246 | |
---|
1247 | if (!need_auth && |
---|
1248 | isr->sav != NULL && |
---|
1249 | isr->sav->tdb_authalgxform != NULL && |
---|
1250 | (m->m_flags & M_AUTHIPDGM) == 0) { |
---|
1251 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, |
---|
1252 | printf("%s: ESP/AH m_flags:%x\n", __func__, |
---|
1253 | m->m_flags)); |
---|
1254 | return (1); |
---|
1255 | } |
---|
1256 | break; |
---|
1257 | case IPPROTO_AH: |
---|
1258 | need_auth = 1; |
---|
1259 | if ((m->m_flags & M_AUTHIPHDR) == 0) { |
---|
1260 | KEYDEBUG(KEYDEBUG_IPSEC_DUMP, |
---|
1261 | printf("%s: AH m_flags:%x\n", __func__, |
---|
1262 | m->m_flags)); |
---|
1263 | return (1); |
---|
1264 | } |
---|
1265 | break; |
---|
1266 | case IPPROTO_IPCOMP: |
---|
1267 | /* |
---|
1268 | * We don't really care, as IPcomp document |
---|
1269 | * says that we shouldn't compress small |
---|
1270 | * packets. IPComp policy should always be |
---|
1271 | * treated as being in "use" level. |
---|
1272 | */ |
---|
1273 | break; |
---|
1274 | } |
---|
1275 | } |
---|
1276 | return (0); /* Valid. */ |
---|
1277 | } |
---|
1278 | |
---|
1279 | static int |
---|
1280 | ipsec46_in_reject(struct mbuf *m, struct inpcb *inp) |
---|
1281 | { |
---|
1282 | struct secpolicy *sp; |
---|
1283 | int error; |
---|
1284 | int result; |
---|
1285 | |
---|
1286 | IPSEC_ASSERT(m != NULL, ("null mbuf")); |
---|
1287 | |
---|
1288 | /* |
---|
1289 | * Get SP for this packet. |
---|
1290 | * When we are called from ip_forward(), we call |
---|
1291 | * ipsec_getpolicybyaddr() with IP_FORWARDING flag. |
---|
1292 | */ |
---|
1293 | if (inp == NULL) |
---|
1294 | sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, IP_FORWARDING, &error); |
---|
1295 | else |
---|
1296 | sp = ipsec_getpolicybysock(m, IPSEC_DIR_INBOUND, inp, &error); |
---|
1297 | |
---|
1298 | if (sp != NULL) { |
---|
1299 | result = ipsec_in_reject(sp, m); |
---|
1300 | KEY_FREESP(&sp); |
---|
1301 | } else { |
---|
1302 | result = 0; /* XXX Should be panic? |
---|
1303 | * -> No, there may be error. */ |
---|
1304 | } |
---|
1305 | return (result); |
---|
1306 | } |
---|
1307 | |
---|
1308 | /* |
---|
1309 | * Check AH/ESP integrity. |
---|
1310 | * This function is called from tcp_input(), udp_input(), |
---|
1311 | * and {ah,esp}4_input for tunnel mode. |
---|
1312 | */ |
---|
1313 | int |
---|
1314 | ipsec4_in_reject(struct mbuf *m, struct inpcb *inp) |
---|
1315 | { |
---|
1316 | int result; |
---|
1317 | |
---|
1318 | result = ipsec46_in_reject(m, inp); |
---|
1319 | if (result) |
---|
1320 | IPSECSTAT_INC(ips_in_polvio); |
---|
1321 | |
---|
1322 | return (result); |
---|
1323 | } |
---|
1324 | |
---|
1325 | #ifdef INET6 |
---|
1326 | /* |
---|
1327 | * Check AH/ESP integrity. |
---|
1328 | * This function is called from tcp6_input(), udp6_input(), |
---|
1329 | * and {ah,esp}6_input for tunnel mode. |
---|
1330 | */ |
---|
1331 | int |
---|
1332 | ipsec6_in_reject(struct mbuf *m, struct inpcb *inp) |
---|
1333 | { |
---|
1334 | int result; |
---|
1335 | |
---|
1336 | result = ipsec46_in_reject(m, inp); |
---|
1337 | if (result) |
---|
1338 | IPSEC6STAT_INC(ips_in_polvio); |
---|
1339 | |
---|
1340 | return (result); |
---|
1341 | } |
---|
1342 | #endif |
---|
1343 | |
---|
1344 | /* |
---|
1345 | * Compute the byte size to be occupied by IPsec header. |
---|
1346 | * In case it is tunnelled, it includes the size of outer IP header. |
---|
1347 | * NOTE: SP passed is freed in this function. |
---|
1348 | */ |
---|
1349 | static size_t |
---|
1350 | ipsec_hdrsiz_internal(struct secpolicy *sp) |
---|
1351 | { |
---|
1352 | struct ipsecrequest *isr; |
---|
1353 | size_t size; |
---|
1354 | |
---|
1355 | KEYDEBUG(KEYDEBUG_IPSEC_DATA, |
---|
1356 | printf("%s: using SP\n", __func__); kdebug_secpolicy(sp)); |
---|
1357 | |
---|
1358 | switch (sp->policy) { |
---|
1359 | case IPSEC_POLICY_DISCARD: |
---|
1360 | case IPSEC_POLICY_BYPASS: |
---|
1361 | case IPSEC_POLICY_NONE: |
---|
1362 | return (0); |
---|
1363 | } |
---|
1364 | |
---|
1365 | IPSEC_ASSERT(sp->policy == IPSEC_POLICY_IPSEC, |
---|
1366 | ("invalid policy %u", sp->policy)); |
---|
1367 | |
---|
1368 | size = 0; |
---|
1369 | for (isr = sp->req; isr != NULL; isr = isr->next) { |
---|
1370 | size_t clen = 0; |
---|
1371 | |
---|
1372 | switch (isr->saidx.proto) { |
---|
1373 | case IPPROTO_ESP: |
---|
1374 | clen = esp_hdrsiz(isr->sav); |
---|
1375 | break; |
---|
1376 | case IPPROTO_AH: |
---|
1377 | clen = ah_hdrsiz(isr->sav); |
---|
1378 | break; |
---|
1379 | case IPPROTO_IPCOMP: |
---|
1380 | clen = sizeof(struct ipcomp); |
---|
1381 | break; |
---|
1382 | } |
---|
1383 | |
---|
1384 | if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { |
---|
1385 | switch (isr->saidx.dst.sa.sa_family) { |
---|
1386 | case AF_INET: |
---|
1387 | clen += sizeof(struct ip); |
---|
1388 | break; |
---|
1389 | #ifdef INET6 |
---|
1390 | case AF_INET6: |
---|
1391 | clen += sizeof(struct ip6_hdr); |
---|
1392 | break; |
---|
1393 | #endif |
---|
1394 | default: |
---|
1395 | ipseclog((LOG_ERR, "%s: unknown AF %d in " |
---|
1396 | "IPsec tunnel SA\n", __func__, |
---|
1397 | ((struct sockaddr *)&isr->saidx.dst)->sa_family)); |
---|
1398 | break; |
---|
1399 | } |
---|
1400 | } |
---|
1401 | size += clen; |
---|
1402 | } |
---|
1403 | |
---|
1404 | return (size); |
---|
1405 | } |
---|
1406 | |
---|
1407 | /* |
---|
1408 | * This function is called from ipsec_hdrsiz_tcp(), ip_ipsec_mtu(), |
---|
1409 | * disabled ip6_ipsec_mtu() and ip6_forward(). |
---|
1410 | */ |
---|
1411 | size_t |
---|
1412 | ipsec_hdrsiz(struct mbuf *m, u_int dir, struct inpcb *inp) |
---|
1413 | { |
---|
1414 | struct secpolicy *sp; |
---|
1415 | int error; |
---|
1416 | size_t size; |
---|
1417 | |
---|
1418 | IPSEC_ASSERT(m != NULL, ("null mbuf")); |
---|
1419 | |
---|
1420 | /* Get SP for this packet. |
---|
1421 | * When we are called from ip_forward(), we call |
---|
1422 | * ipsec_getpolicybyaddr() with IP_FORWARDING flag. |
---|
1423 | */ |
---|
1424 | if (inp == NULL) |
---|
1425 | sp = ipsec_getpolicybyaddr(m, dir, IP_FORWARDING, &error); |
---|
1426 | else |
---|
1427 | sp = ipsec_getpolicybysock(m, dir, inp, &error); |
---|
1428 | |
---|
1429 | if (sp != NULL) { |
---|
1430 | size = ipsec_hdrsiz_internal(sp); |
---|
1431 | KEYDEBUG(KEYDEBUG_IPSEC_DATA, |
---|
1432 | printf("%s: size:%lu.\n", __func__, |
---|
1433 | (unsigned long)size)); |
---|
1434 | |
---|
1435 | KEY_FREESP(&sp); |
---|
1436 | } else { |
---|
1437 | size = 0; /* XXX Should be panic? |
---|
1438 | * -> No, we are called w/o knowing if |
---|
1439 | * IPsec processing is needed. */ |
---|
1440 | } |
---|
1441 | return (size); |
---|
1442 | } |
---|
1443 | |
---|
1444 | /* |
---|
1445 | * Check the variable replay window. |
---|
1446 | * ipsec_chkreplay() performs replay check before ICV verification. |
---|
1447 | * ipsec_updatereplay() updates replay bitmap. This must be called after |
---|
1448 | * ICV verification (it also performs replay check, which is usually done |
---|
1449 | * beforehand). |
---|
1450 | * 0 (zero) is returned if packet disallowed, 1 if packet permitted. |
---|
1451 | * |
---|
1452 | * Based on RFC 2401. |
---|
1453 | */ |
---|
1454 | int |
---|
1455 | ipsec_chkreplay(u_int32_t seq, struct secasvar *sav) |
---|
1456 | { |
---|
1457 | const struct secreplay *replay; |
---|
1458 | u_int32_t diff; |
---|
1459 | int fr; |
---|
1460 | u_int32_t wsizeb; /* Constant: bits of window size. */ |
---|
1461 | int frlast; /* Constant: last frame. */ |
---|
1462 | |
---|
1463 | IPSEC_ASSERT(sav != NULL, ("Null SA")); |
---|
1464 | IPSEC_ASSERT(sav->replay != NULL, ("Null replay state")); |
---|
1465 | |
---|
1466 | replay = sav->replay; |
---|
1467 | |
---|
1468 | if (replay->wsize == 0) |
---|
1469 | return (1); /* No need to check replay. */ |
---|
1470 | |
---|
1471 | /* Constant. */ |
---|
1472 | frlast = replay->wsize - 1; |
---|
1473 | wsizeb = replay->wsize << 3; |
---|
1474 | |
---|
1475 | /* Sequence number of 0 is invalid. */ |
---|
1476 | if (seq == 0) |
---|
1477 | return (0); |
---|
1478 | |
---|
1479 | /* First time is always okay. */ |
---|
1480 | if (replay->count == 0) |
---|
1481 | return (1); |
---|
1482 | |
---|
1483 | if (seq > replay->lastseq) { |
---|
1484 | /* Larger sequences are okay. */ |
---|
1485 | return (1); |
---|
1486 | } else { |
---|
1487 | /* seq is equal or less than lastseq. */ |
---|
1488 | diff = replay->lastseq - seq; |
---|
1489 | |
---|
1490 | /* Over range to check, i.e. too old or wrapped. */ |
---|
1491 | if (diff >= wsizeb) |
---|
1492 | return (0); |
---|
1493 | |
---|
1494 | fr = frlast - diff / 8; |
---|
1495 | |
---|
1496 | /* This packet already seen? */ |
---|
1497 | if ((replay->bitmap)[fr] & (1 << (diff % 8))) |
---|
1498 | return (0); |
---|
1499 | |
---|
1500 | /* Out of order but good. */ |
---|
1501 | return (1); |
---|
1502 | } |
---|
1503 | } |
---|
1504 | |
---|
1505 | /* |
---|
1506 | * Check replay counter whether to update or not. |
---|
1507 | * OUT: 0: OK |
---|
1508 | * 1: NG |
---|
1509 | */ |
---|
1510 | int |
---|
1511 | ipsec_updatereplay(u_int32_t seq, struct secasvar *sav) |
---|
1512 | { |
---|
1513 | struct secreplay *replay; |
---|
1514 | u_int32_t diff; |
---|
1515 | int fr; |
---|
1516 | u_int32_t wsizeb; /* Constant: bits of window size. */ |
---|
1517 | int frlast; /* Constant: last frame. */ |
---|
1518 | |
---|
1519 | IPSEC_ASSERT(sav != NULL, ("Null SA")); |
---|
1520 | IPSEC_ASSERT(sav->replay != NULL, ("Null replay state")); |
---|
1521 | |
---|
1522 | replay = sav->replay; |
---|
1523 | |
---|
1524 | if (replay->wsize == 0) |
---|
1525 | goto ok; /* No need to check replay. */ |
---|
1526 | |
---|
1527 | /* Constant. */ |
---|
1528 | frlast = replay->wsize - 1; |
---|
1529 | wsizeb = replay->wsize << 3; |
---|
1530 | |
---|
1531 | /* Sequence number of 0 is invalid. */ |
---|
1532 | if (seq == 0) |
---|
1533 | return (1); |
---|
1534 | |
---|
1535 | /* First time. */ |
---|
1536 | if (replay->count == 0) { |
---|
1537 | replay->lastseq = seq; |
---|
1538 | bzero(replay->bitmap, replay->wsize); |
---|
1539 | (replay->bitmap)[frlast] = 1; |
---|
1540 | goto ok; |
---|
1541 | } |
---|
1542 | |
---|
1543 | if (seq > replay->lastseq) { |
---|
1544 | /* seq is larger than lastseq. */ |
---|
1545 | diff = seq - replay->lastseq; |
---|
1546 | |
---|
1547 | /* New larger sequence number. */ |
---|
1548 | if (diff < wsizeb) { |
---|
1549 | /* In window. */ |
---|
1550 | /* Set bit for this packet. */ |
---|
1551 | vshiftl(replay->bitmap, diff, replay->wsize); |
---|
1552 | (replay->bitmap)[frlast] |= 1; |
---|
1553 | } else { |
---|
1554 | /* This packet has a "way larger". */ |
---|
1555 | bzero(replay->bitmap, replay->wsize); |
---|
1556 | (replay->bitmap)[frlast] = 1; |
---|
1557 | } |
---|
1558 | replay->lastseq = seq; |
---|
1559 | |
---|
1560 | /* Larger is good. */ |
---|
1561 | } else { |
---|
1562 | /* seq is equal or less than lastseq. */ |
---|
1563 | diff = replay->lastseq - seq; |
---|
1564 | |
---|
1565 | /* Over range to check, i.e. too old or wrapped. */ |
---|
1566 | if (diff >= wsizeb) |
---|
1567 | return (1); |
---|
1568 | |
---|
1569 | fr = frlast - diff / 8; |
---|
1570 | |
---|
1571 | /* This packet already seen? */ |
---|
1572 | if ((replay->bitmap)[fr] & (1 << (diff % 8))) |
---|
1573 | return (1); |
---|
1574 | |
---|
1575 | /* Mark as seen. */ |
---|
1576 | (replay->bitmap)[fr] |= (1 << (diff % 8)); |
---|
1577 | |
---|
1578 | /* Out of order but good. */ |
---|
1579 | } |
---|
1580 | |
---|
1581 | ok: |
---|
1582 | if (replay->count == ~0) { |
---|
1583 | |
---|
1584 | /* Set overflow flag. */ |
---|
1585 | replay->overflow++; |
---|
1586 | |
---|
1587 | /* Don't increment, no more packets accepted. */ |
---|
1588 | if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) |
---|
1589 | return (1); |
---|
1590 | |
---|
1591 | ipseclog((LOG_WARNING, "%s: replay counter made %d cycle. %s\n", |
---|
1592 | __func__, replay->overflow, ipsec_logsastr(sav))); |
---|
1593 | } |
---|
1594 | |
---|
1595 | replay->count++; |
---|
1596 | |
---|
1597 | return (0); |
---|
1598 | } |
---|
1599 | |
---|
1600 | /* |
---|
1601 | * Shift variable length buffer to left. |
---|
1602 | * IN: bitmap: pointer to the buffer |
---|
1603 | * nbit: the number of to shift. |
---|
1604 | * wsize: buffer size (bytes). |
---|
1605 | */ |
---|
1606 | static void |
---|
1607 | vshiftl(unsigned char *bitmap, int nbit, int wsize) |
---|
1608 | { |
---|
1609 | int s, j, i; |
---|
1610 | unsigned char over; |
---|
1611 | |
---|
1612 | for (j = 0; j < nbit; j += 8) { |
---|
1613 | s = (nbit - j < 8) ? (nbit - j): 8; |
---|
1614 | bitmap[0] <<= s; |
---|
1615 | for (i = 1; i < wsize; i++) { |
---|
1616 | over = (bitmap[i] >> (8 - s)); |
---|
1617 | bitmap[i] <<= s; |
---|
1618 | bitmap[i-1] |= over; |
---|
1619 | } |
---|
1620 | } |
---|
1621 | } |
---|
1622 | |
---|
1623 | #ifdef INET |
---|
1624 | /* Return a printable string for the IPv4 address. */ |
---|
1625 | static char * |
---|
1626 | inet_ntoa4(struct in_addr ina) |
---|
1627 | { |
---|
1628 | static char buf[4][4 * sizeof "123" + 4]; |
---|
1629 | unsigned char *ucp = (unsigned char *) &ina; |
---|
1630 | static int i = 3; |
---|
1631 | |
---|
1632 | /* XXX-BZ Returns static buffer. */ |
---|
1633 | i = (i + 1) % 4; |
---|
1634 | sprintf(buf[i], "%d.%d.%d.%d", ucp[0] & 0xff, ucp[1] & 0xff, |
---|
1635 | ucp[2] & 0xff, ucp[3] & 0xff); |
---|
1636 | return (buf[i]); |
---|
1637 | } |
---|
1638 | #endif |
---|
1639 | |
---|
1640 | /* Return a printable string for the address. */ |
---|
1641 | char * |
---|
1642 | ipsec_address(union sockaddr_union* sa) |
---|
1643 | { |
---|
1644 | #ifdef INET6 |
---|
1645 | char ip6buf[INET6_ADDRSTRLEN]; |
---|
1646 | #endif |
---|
1647 | |
---|
1648 | switch (sa->sa.sa_family) { |
---|
1649 | #ifdef INET |
---|
1650 | case AF_INET: |
---|
1651 | return (inet_ntoa4(sa->sin.sin_addr)); |
---|
1652 | #endif /* INET */ |
---|
1653 | #ifdef INET6 |
---|
1654 | case AF_INET6: |
---|
1655 | return (ip6_sprintf(ip6buf, &sa->sin6.sin6_addr)); |
---|
1656 | #endif /* INET6 */ |
---|
1657 | default: |
---|
1658 | return ("(unknown address family)"); |
---|
1659 | } |
---|
1660 | } |
---|
1661 | |
---|
1662 | const char * |
---|
1663 | ipsec_logsastr(struct secasvar *sav) |
---|
1664 | { |
---|
1665 | static char buf[256]; |
---|
1666 | char *p; |
---|
1667 | struct secasindex *saidx = &sav->sah->saidx; |
---|
1668 | |
---|
1669 | IPSEC_ASSERT(saidx->src.sa.sa_family == saidx->dst.sa.sa_family, |
---|
1670 | ("address family mismatch")); |
---|
1671 | |
---|
1672 | p = buf; |
---|
1673 | snprintf(buf, sizeof(buf), "SA(SPI=%u ", (u_int32_t)ntohl(sav->spi)); |
---|
1674 | while (p && *p) |
---|
1675 | p++; |
---|
1676 | /* NB: only use ipsec_address on one address at a time. */ |
---|
1677 | snprintf(p, sizeof (buf) - (p - buf), "src=%s ", |
---|
1678 | ipsec_address(&saidx->src)); |
---|
1679 | while (p && *p) |
---|
1680 | p++; |
---|
1681 | snprintf(p, sizeof (buf) - (p - buf), "dst=%s)", |
---|
1682 | ipsec_address(&saidx->dst)); |
---|
1683 | |
---|
1684 | return (buf); |
---|
1685 | } |
---|
1686 | |
---|
1687 | void |
---|
1688 | ipsec_dumpmbuf(struct mbuf *m) |
---|
1689 | { |
---|
1690 | int totlen; |
---|
1691 | int i; |
---|
1692 | u_char *p; |
---|
1693 | |
---|
1694 | totlen = 0; |
---|
1695 | printf("---\n"); |
---|
1696 | while (m) { |
---|
1697 | p = mtod(m, u_char *); |
---|
1698 | for (i = 0; i < m->m_len; i++) { |
---|
1699 | printf("%02x ", p[i]); |
---|
1700 | totlen++; |
---|
1701 | if (totlen % 16 == 0) |
---|
1702 | printf("\n"); |
---|
1703 | } |
---|
1704 | m = m->m_next; |
---|
1705 | } |
---|
1706 | if (totlen % 16 != 0) |
---|
1707 | printf("\n"); |
---|
1708 | printf("---\n"); |
---|
1709 | } |
---|
1710 | |
---|
1711 | static void |
---|
1712 | ipsec_init(const void *unused __unused) |
---|
1713 | { |
---|
1714 | |
---|
1715 | SECPOLICY_LOCK_INIT(&V_ip4_def_policy); |
---|
1716 | V_ip4_def_policy.refcnt = 1; /* NB: disallow free. */ |
---|
1717 | } |
---|
1718 | VNET_SYSINIT(ipsec_init, SI_SUB_PROTO_DOMAININIT, SI_ORDER_ANY, ipsec_init, |
---|
1719 | NULL); |
---|
1720 | |
---|
1721 | |
---|
1722 | /* XXX This stuff doesn't belong here... */ |
---|
1723 | |
---|
1724 | static struct xformsw* xforms = NULL; |
---|
1725 | |
---|
1726 | /* |
---|
1727 | * Register a transform; typically at system startup. |
---|
1728 | */ |
---|
1729 | void |
---|
1730 | xform_register(struct xformsw* xsp) |
---|
1731 | { |
---|
1732 | |
---|
1733 | xsp->xf_next = xforms; |
---|
1734 | xforms = xsp; |
---|
1735 | } |
---|
1736 | |
---|
1737 | /* |
---|
1738 | * Initialize transform support in an sav. |
---|
1739 | */ |
---|
1740 | int |
---|
1741 | xform_init(struct secasvar *sav, int xftype) |
---|
1742 | { |
---|
1743 | struct xformsw *xsp; |
---|
1744 | |
---|
1745 | if (sav->tdb_xform != NULL) /* Previously initialized. */ |
---|
1746 | return (0); |
---|
1747 | for (xsp = xforms; xsp; xsp = xsp->xf_next) |
---|
1748 | if (xsp->xf_type == xftype) |
---|
1749 | return ((*xsp->xf_init)(sav, xsp)); |
---|
1750 | return (EINVAL); |
---|
1751 | } |
---|