[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]

FreeBSD/Linux Kernel Cross Reference
sys/netipsec/ipsec.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  1 /*      $FreeBSD: src/sys/netipsec/ipsec.c,v 1.36 2008/11/27 10:43:08 bz Exp $  */
  2 /*      $KAME: ipsec.c,v 1.103 2001/05/24 07:14:18 sakane Exp $ */
  3 
  4 /*-
  5  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
  6  * All rights reserved.
  7  *
  8  * Redistribution and use in source and binary forms, with or without
  9  * modification, are permitted provided that the following conditions
 10  * are met:
 11  * 1. Redistributions of source code must retain the above copyright
 12  *    notice, this list of conditions and the following disclaimer.
 13  * 2. Redistributions in binary form must reproduce the above copyright
 14  *    notice, this list of conditions and the following disclaimer in the
 15  *    documentation and/or other materials provided with the distribution.
 16  * 3. Neither the name of the project nor the names of its contributors
 17  *    may be used to endorse or promote products derived from this software
 18  *    without specific prior written permission.
 19  *
 20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
 21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
 24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 30  * SUCH DAMAGE.
 31  */
 32 
 33 /*
 34  * IPsec controller part.
 35  */
 36 
 37 #include "opt_inet.h"
 38 #include "opt_inet6.h"
 39 #include "opt_ipsec.h"
 40 
 41 #include <sys/param.h>
 42 #include <sys/systm.h>
 43 #include <sys/malloc.h>
 44 #include <sys/mbuf.h>
 45 #include <sys/domain.h>
 46 #include <sys/priv.h>
 47 #include <sys/protosw.h>
 48 #include <sys/socket.h>
 49 #include <sys/socketvar.h>
 50 #include <sys/errno.h>
 51 #include <sys/time.h>
 52 #include <sys/kernel.h>
 53 #include <sys/syslog.h>
 54 #include <sys/sysctl.h>
 55 #include <sys/proc.h>
 56 #include <sys/vimage.h>
 57 
 58 #include <net/if.h>
 59 #include <net/route.h>
 60 
 61 #include <netinet/in.h>
 62 #include <netinet/in_systm.h>
 63 #include <netinet/ip.h>
 64 #include <netinet/ip_var.h>
 65 #include <netinet/in_var.h>
 66 #include <netinet/udp.h>
 67 #include <netinet/udp_var.h>
 68 #include <netinet/tcp.h>
 69 #include <netinet/udp.h>
 70 
 71 #include <netinet/ip6.h>
 72 #ifdef INET6
 73 #include <netinet6/ip6_var.h>
 74 #endif
 75 #include <netinet/in_pcb.h>
 76 #ifdef INET6
 77 #include <netinet/icmp6.h>
 78 #endif
 79 
 80 #include <sys/types.h>
 81 #include <netipsec/ipsec.h>
 82 #ifdef INET6
 83 #include <netipsec/ipsec6.h>
 84 #endif
 85 #include <netipsec/ah_var.h>
 86 #include <netipsec/esp_var.h>
 87 #include <netipsec/ipcomp.h>            /*XXX*/
 88 #include <netipsec/ipcomp_var.h>
 89 
 90 #include <netipsec/key.h>
 91 #include <netipsec/keydb.h>
 92 #include <netipsec/key_debug.h>
 93 
 94 #include <netipsec/xform.h>
 95 
 96 #include <machine/in_cksum.h>
 97 
 98 #include <opencrypto/cryptodev.h>
 99 
100 #ifdef VIMAGE_GLOBALS
101 /* NB: name changed so netstat doesn't use it */
102 struct ipsecstat ipsec4stat;
103 struct secpolicy ip4_def_policy;
104 int ipsec_debug;
105 int ip4_ah_offsetmask;
106 int ip4_ipsec_dfbit;
107 int ip4_esp_trans_deflev;
108 int ip4_esp_net_deflev;
109 int ip4_ah_trans_deflev;
110 int ip4_ah_net_deflev;
111 int ip4_ipsec_ecn;
112 int ip4_esp_randpad;
113 /*
114  * Crypto support requirements:
115  *
116  *  1   require hardware support
117  * -1   require software support
118  *  0   take anything
119  */
120 int     crypto_support;
121 #endif /* VIMAGE_GLOBALS */
122 
123 SYSCTL_DECL(_net_inet_ipsec);
124 
125 /* net.inet.ipsec */
126 SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_DEF_POLICY,
127         def_policy, CTLFLAG_RW, ip4_def_policy.policy,  0,
128         "IPsec default policy.");
129 SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_DEF_ESP_TRANSLEV,
130         esp_trans_deflev, CTLFLAG_RW, ip4_esp_trans_deflev,     0,
131         "Default ESP transport mode level");
132 SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_DEF_ESP_NETLEV,
133         esp_net_deflev, CTLFLAG_RW, ip4_esp_net_deflev, 0,
134         "Default ESP tunnel mode level.");
135 SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_DEF_AH_TRANSLEV,
136         ah_trans_deflev, CTLFLAG_RW, ip4_ah_trans_deflev,       0,
137         "AH transfer mode default level.");
138 SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_DEF_AH_NETLEV,
139         ah_net_deflev, CTLFLAG_RW, ip4_ah_net_deflev,   0,
140         "AH tunnel mode default level.");
141 SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_AH_CLEARTOS,
142         ah_cleartos, CTLFLAG_RW,        ah_cleartos,    0,
143         "If set clear type-of-service field when doing AH computation.");
144 SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_AH_OFFSETMASK,
145         ah_offsetmask, CTLFLAG_RW,      ip4_ah_offsetmask,      0,
146         "If not set clear offset field mask when doing AH computation.");
147 SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_DFBIT,
148         dfbit, CTLFLAG_RW,      ip4_ipsec_dfbit,        0,
149         "Do not fragment bit on encap.");
150 SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_ECN,
151         ecn, CTLFLAG_RW,        ip4_ipsec_ecn,  0,
152         "Explicit Congestion Notification handling.");
153 SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, IPSECCTL_DEBUG,
154         debug, CTLFLAG_RW,      ipsec_debug,    0,
155         "Enable IPsec debugging output when set.");
156 SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet_ipsec, OID_AUTO,
157         crypto_support, CTLFLAG_RW,     crypto_support,0,
158         "Crypto driver selection.");
159 SYSCTL_V_STRUCT(V_NET, vnet_ipsec, _net_inet_ipsec, OID_AUTO,
160         ipsecstats,     CTLFLAG_RD,     ipsec4stat, ipsecstat,  
161         "IPsec IPv4 statistics.");
162 
163 #ifdef REGRESSION
164 #ifdef VIMAGE_GLOBALS
165 int ipsec_replay;
166 int ipsec_integrity;
167 #endif
168 /*
169  * When set to 1, IPsec will send packets with the same sequence number.
170  * This allows to verify if the other side has proper replay attacks detection.
171  */
172 SYSCTL_V_INT(V_NET, vnet_ipsec,_net_inet_ipsec, OID_AUTO, test_replay,
173         CTLFLAG_RW, ipsec_replay, 0, "Emulate replay attack");
174 /*
175  * When set 1, IPsec will send packets with corrupted HMAC.
176  * This allows to verify if the other side properly detects modified packets.
177  */
178 SYSCTL_V_INT(V_NET, vnet_ipsec,_net_inet_ipsec, OID_AUTO, test_integrity,
179         CTLFLAG_RW, ipsec_integrity, 0, "Emulate man-in-the-middle attack");
180 #endif
181 
182 #ifdef INET6 
183 #ifdef VIMAGE_GLOBALS
184 struct ipsecstat ipsec6stat;
185 int ip6_esp_trans_deflev;
186 int ip6_esp_net_deflev;
187 int ip6_ah_trans_deflev;
188 int ip6_ah_net_deflev;
189 int ip6_ipsec_ecn;
190 #endif
191 
192 SYSCTL_DECL(_net_inet6_ipsec6);
193 
194 /* net.inet6.ipsec6 */
195 #ifdef COMPAT_KAME
196 SYSCTL_OID(_net_inet6_ipsec6, IPSECCTL_STATS, stats, CTLFLAG_RD,
197     0, 0, compat_ipsecstats_sysctl, "S", "IPsec IPv6 statistics.");
198 #endif /* COMPAT_KAME */
199 SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet6_ipsec6, IPSECCTL_DEF_POLICY,
200         def_policy, CTLFLAG_RW, ip4_def_policy.policy,  0,
201         "IPsec default policy.");
202 SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet6_ipsec6, IPSECCTL_DEF_ESP_TRANSLEV, 
203         esp_trans_deflev, CTLFLAG_RW, ip6_esp_trans_deflev,     0,
204         "Default ESP transport mode level.");
205 SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet6_ipsec6, IPSECCTL_DEF_ESP_NETLEV, 
206         esp_net_deflev, CTLFLAG_RW, ip6_esp_net_deflev, 0,
207         "Default ESP tunnel mode level.");
208 SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet6_ipsec6, IPSECCTL_DEF_AH_TRANSLEV, 
209         ah_trans_deflev, CTLFLAG_RW, ip6_ah_trans_deflev,       0,
210         "AH transfer mode default level.");
211 SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet6_ipsec6, IPSECCTL_DEF_AH_NETLEV, 
212         ah_net_deflev, CTLFLAG_RW, ip6_ah_net_deflev,   0,
213         "AH tunnel mode default level.");
214 SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet6_ipsec6, IPSECCTL_ECN,
215         ecn, CTLFLAG_RW, ip6_ipsec_ecn, 0,
216         "Explicit Congestion Notification handling.");
217 SYSCTL_V_INT(V_NET, vnet_ipsec, _net_inet6_ipsec6, IPSECCTL_DEBUG,
218         debug, CTLFLAG_RW,      ipsec_debug,    0,
219         "Enable IPsec debugging output when set.");
220 SYSCTL_V_STRUCT(V_NET, vnet_ipsec, _net_inet6_ipsec6, IPSECCTL_STATS,
221         ipsecstats, CTLFLAG_RD, ipsec6stat, ipsecstat,
222         "IPsec IPv6 statistics.");
223 #endif /* INET6 */
224 
225 static int ipsec4_setspidx_inpcb __P((struct mbuf *, struct inpcb *pcb));
226 #ifdef INET6
227 static int ipsec6_setspidx_in6pcb __P((struct mbuf *, struct in6pcb *pcb));
228 #endif
229 static int ipsec_setspidx __P((struct mbuf *, struct secpolicyindex *, int));
230 static void ipsec4_get_ulp __P((struct mbuf *m, struct secpolicyindex *, int));
231 static int ipsec4_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *));
232 #ifdef INET6
233 static void ipsec6_get_ulp __P((struct mbuf *m, struct secpolicyindex *, int));
234 static int ipsec6_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *));
235 #endif
236 static void ipsec_delpcbpolicy __P((struct inpcbpolicy *));
237 static struct secpolicy *ipsec_deepcopy_policy __P((struct secpolicy *src));
238 static int ipsec_set_policy __P((struct secpolicy **pcb_sp,
239         int optname, caddr_t request, size_t len, struct ucred *cred));
240 static int ipsec_get_policy __P((struct secpolicy *pcb_sp, struct mbuf **mp));
241 static void vshiftl __P((unsigned char *, int, int));
242 static size_t ipsec_hdrsiz __P((struct secpolicy *));
243 
244 MALLOC_DEFINE(M_IPSEC_INPCB, "inpcbpolicy", "inpcb-resident ipsec policy");
245 
246 void
247 ipsec_init(void)
248 {
249         INIT_VNET_IPSEC(curvnet);
250 
251 #ifdef IPSEC_DEBUG
252         V_ipsec_debug = 1;
253 #else
254         V_ipsec_debug = 0;
255 #endif
256 
257         V_ip4_ah_offsetmask = 0;        /* maybe IP_DF? */
258         V_ip4_ipsec_dfbit = 0;  /* DF bit on encap. 0: clear 1: set 2: copy */
259         V_ip4_esp_trans_deflev = IPSEC_LEVEL_USE;
260         V_ip4_esp_net_deflev = IPSEC_LEVEL_USE;
261         V_ip4_ah_trans_deflev = IPSEC_LEVEL_USE;
262         V_ip4_ah_net_deflev = IPSEC_LEVEL_USE;
263         V_ip4_ipsec_ecn = 0;    /* ECN ignore(-1)/forbidden(0)/allowed(1) */
264         V_ip4_esp_randpad = -1;
265 
266         V_crypto_support = CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE;
267 
268 #ifdef REGRESSION
269         V_ipsec_replay = 0;
270         V_ipsec_integrity = 0;
271 #endif
272 
273 #ifdef INET6 
274         V_ip6_esp_trans_deflev = IPSEC_LEVEL_USE;
275         V_ip6_esp_net_deflev = IPSEC_LEVEL_USE;
276         V_ip6_ah_trans_deflev = IPSEC_LEVEL_USE;
277         V_ip6_ah_net_deflev = IPSEC_LEVEL_USE;
278         V_ip6_ipsec_ecn = 0;    /* ECN ignore(-1)/forbidden(0)/allowed(1) */
279 #endif
280 }
281 
282 /*
283  * Return a held reference to the default SP.
284  */
285 static struct secpolicy *
286 key_allocsp_default(const char* where, int tag)
287 {
288         INIT_VNET_IPSEC(curvnet);
289         struct secpolicy *sp;
290 
291         KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
292                 printf("DP key_allocsp_default from %s:%u\n", where, tag));
293 
294         sp = &V_ip4_def_policy;
295         if (sp->policy != IPSEC_POLICY_DISCARD &&
296             sp->policy != IPSEC_POLICY_NONE) {
297                 ipseclog((LOG_INFO, "fixed system default policy: %d->%d\n",
298                     sp->policy, IPSEC_POLICY_NONE));
299                 sp->policy = IPSEC_POLICY_NONE;
300         }
301         key_addref(sp);
302 
303         KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
304                 printf("DP key_allocsp_default returns SP:%p (%u)\n",
305                         sp, sp->refcnt));
306         return sp;
307 }
308 #define KEY_ALLOCSP_DEFAULT() \
309         key_allocsp_default(__FILE__, __LINE__)
310 
311 /*
312  * For OUTBOUND packet having a socket. Searching SPD for packet,
313  * and return a pointer to SP.
314  * OUT: NULL:   no apropreate SP found, the following value is set to error.
315  *              0       : bypass
316  *              EACCES  : discard packet.
317  *              ENOENT  : ipsec_acquire() in progress, maybe.
318  *              others  : error occured.
319  *      others: a pointer to SP
320  *
321  * NOTE: IPv6 mapped adddress concern is implemented here.
322  */
323 struct secpolicy *
324 ipsec_getpolicy(struct tdb_ident *tdbi, u_int dir)
325 {
326         struct secpolicy *sp;
327 
328         IPSEC_ASSERT(tdbi != NULL, ("null tdbi"));
329         IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND,
330                 ("invalid direction %u", dir));
331 
332         sp = KEY_ALLOCSP2(tdbi->spi, &tdbi->dst, tdbi->proto, dir);
333         if (sp == NULL)                 /*XXX????*/
334                 sp = KEY_ALLOCSP_DEFAULT();
335         IPSEC_ASSERT(sp != NULL, ("null SP"));
336         return sp;
337 }
338 
339 /*
340  * For OUTBOUND packet having a socket. Searching SPD for packet,
341  * and return a pointer to SP.
342  * OUT: NULL:   no apropreate SP found, the following value is set to error.
343  *              0       : bypass
344  *              EACCES  : discard packet.
345  *              ENOENT  : ipsec_acquire() in progress, maybe.
346  *              others  : error occured.
347  *      others: a pointer to SP
348  *
349  * NOTE: IPv6 mapped adddress concern is implemented here.
350  */
351 struct secpolicy *
352 ipsec_getpolicybysock(m, dir, inp, error)
353         struct mbuf *m;
354         u_int dir;
355         struct inpcb *inp;
356         int *error;
357 {
358         INIT_VNET_IPSEC(curvnet);
359         struct inpcbpolicy *pcbsp = NULL;
360         struct secpolicy *currsp = NULL;        /* policy on socket */
361         struct secpolicy *sp;
362 
363         IPSEC_ASSERT(m != NULL, ("null mbuf"));
364         IPSEC_ASSERT(inp != NULL, ("null inpcb"));
365         IPSEC_ASSERT(error != NULL, ("null error"));
366         IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND,
367                 ("invalid direction %u", dir));
368 
369         /* set spidx in pcb */
370         if (inp->inp_vflag & INP_IPV6PROTO) {
371 #ifdef INET6
372                 *error = ipsec6_setspidx_in6pcb(m, inp);
373                 pcbsp = inp->in6p_sp;
374 #else
375                 *error = EINVAL;                /* should not happen */
376 #endif
377         } else {
378                 *error = ipsec4_setspidx_inpcb(m, inp);
379                 pcbsp = inp->inp_sp;
380         }
381         if (*error)
382                 return NULL;
383 
384         IPSEC_ASSERT(pcbsp != NULL, ("null pcbsp"));
385         switch (dir) {
386         case IPSEC_DIR_INBOUND:
387                 currsp = pcbsp->sp_in;
388                 break;
389         case IPSEC_DIR_OUTBOUND:
390                 currsp = pcbsp->sp_out;
391                 break;
392         }
393         IPSEC_ASSERT(currsp != NULL, ("null currsp"));
394 
395         if (pcbsp->priv) {                      /* when privilieged socket */
396                 switch (currsp->policy) {
397                 case IPSEC_POLICY_BYPASS:
398                 case IPSEC_POLICY_IPSEC:
399                         key_addref(currsp);
400                         sp = currsp;
401                         break;
402 
403                 case IPSEC_POLICY_ENTRUST:
404                         /* look for a policy in SPD */
405                         sp = KEY_ALLOCSP(&currsp->spidx, dir);
406                         if (sp == NULL)         /* no SP found */
407                                 sp = KEY_ALLOCSP_DEFAULT();
408                         break;
409 
410                 default:
411                         ipseclog((LOG_ERR, "%s: Invalid policy for PCB %d\n",
412                                 __func__, currsp->policy));
413                         *error = EINVAL;
414                         return NULL;
415                 }
416         } else {                                /* unpriv, SPD has policy */
417                 sp = KEY_ALLOCSP(&currsp->spidx, dir);
418                 if (sp == NULL) {               /* no SP found */
419                         switch (currsp->policy) {
420                         case IPSEC_POLICY_BYPASS:
421                                 ipseclog((LOG_ERR, "%s: Illegal policy for "
422                                         "non-priviliged defined %d\n",
423                                         __func__, currsp->policy));
424                                 *error = EINVAL;
425                                 return NULL;
426 
427                         case IPSEC_POLICY_ENTRUST:
428                                 sp = KEY_ALLOCSP_DEFAULT();
429                                 break;
430 
431                         case IPSEC_POLICY_IPSEC:
432                                 key_addref(currsp);
433                                 sp = currsp;
434                                 break;
435 
436                         default:
437                                 ipseclog((LOG_ERR, "%s: Invalid policy for "
438                                         "PCB %d\n", __func__, currsp->policy));
439                                 *error = EINVAL;
440                                 return NULL;
441                         }
442                 }
443         }
444         IPSEC_ASSERT(sp != NULL,
445                 ("null SP (priv %u policy %u", pcbsp->priv, currsp->policy));
446         KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
447                 printf("DP %s (priv %u policy %u) allocate SP:%p (refcnt %u)\n",
448                         __func__, pcbsp->priv, currsp->policy, sp, sp->refcnt));
449         return sp;
450 }
451 
452 /*
453  * For FORWADING packet or OUTBOUND without a socket. Searching SPD for packet,
454  * and return a pointer to SP.
455  * OUT: positive: a pointer to the entry for security policy leaf matched.
456  *      NULL:   no apropreate SP found, the following value is set to error.
457  *              0       : bypass
458  *              EACCES  : discard packet.
459  *              ENOENT  : ipsec_acquire() in progress, maybe.
460  *              others  : error occured.
461  */
462 struct secpolicy *
463 ipsec_getpolicybyaddr(m, dir, flag, error)
464         struct mbuf *m;
465         u_int dir;
466         int flag;
467         int *error;
468 {
469         INIT_VNET_IPSEC(curvnet);
470         struct secpolicyindex spidx;
471         struct secpolicy *sp;
472 
473         IPSEC_ASSERT(m != NULL, ("null mbuf"));
474         IPSEC_ASSERT(error != NULL, ("null error"));
475         IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND,
476                 ("invalid direction %u", dir));
477 
478         sp = NULL;
479         if (key_havesp(dir)) {
480                 /* Make an index to look for a policy. */
481                 *error = ipsec_setspidx(m, &spidx,
482                                         (flag & IP_FORWARDING) ? 0 : 1);
483                 if (*error != 0) {
484                         DPRINTF(("%s: setpidx failed, dir %u flag %u\n",
485                                 __func__, dir, flag));
486                         return NULL;
487                 }
488                 spidx.dir = dir;
489 
490                 sp = KEY_ALLOCSP(&spidx, dir);
491         }
492         if (sp == NULL)                 /* no SP found, use system default */
493                 sp = KEY_ALLOCSP_DEFAULT();
494         IPSEC_ASSERT(sp != NULL, ("null SP"));
495         return sp;
496 }
497 
498 struct secpolicy *
499 ipsec4_checkpolicy(m, dir, flag, error, inp)
500         struct mbuf *m;
501         u_int dir, flag;
502         int *error;
503         struct inpcb *inp;
504 {
505         INIT_VNET_IPSEC(curvnet);
506         struct secpolicy *sp;
507 
508         *error = 0;
509         if (inp == NULL)
510                 sp = ipsec_getpolicybyaddr(m, dir, flag, error);
511         else
512                 sp = ipsec_getpolicybysock(m, dir, inp, error);
513         if (sp == NULL) {
514                 IPSEC_ASSERT(*error != 0, ("getpolicy failed w/o error"));
515                 V_ipsec4stat.ips_out_inval++;
516                 return NULL;
517         }
518         IPSEC_ASSERT(*error == 0, ("sp w/ error set to %u", *error));
519         switch (sp->policy) {
520         case IPSEC_POLICY_ENTRUST:
521         default:
522                 printf("%s: invalid policy %u\n", __func__, sp->policy);
523                 /* fall thru... */
524         case IPSEC_POLICY_DISCARD:
525                 V_ipsec4stat.ips_out_polvio++;
526                 *error = -EINVAL;       /* packet is discarded by caller */
527                 break;
528         case IPSEC_POLICY_BYPASS:
529         case IPSEC_POLICY_NONE:
530                 KEY_FREESP(&sp);
531                 sp = NULL;              /* NB: force NULL result */
532                 break;
533         case IPSEC_POLICY_IPSEC:
534                 if (sp->req == NULL)    /* acquire an SA */
535                         *error = key_spdacquire(sp);
536                 break;
537         }
538         if (*error != 0) {
539                 KEY_FREESP(&sp);
540                 sp = NULL;
541         }
542         return sp;
543 }
544 
545 static int
546 ipsec4_setspidx_inpcb(m, pcb)
547         struct mbuf *m;
548         struct inpcb *pcb;
549 {
550         int error;
551 
552         IPSEC_ASSERT(pcb != NULL, ("null pcb"));
553         IPSEC_ASSERT(pcb->inp_sp != NULL, ("null inp_sp"));
554         IPSEC_ASSERT(pcb->inp_sp->sp_out != NULL && pcb->inp_sp->sp_in != NULL,
555                 ("null sp_in || sp_out"));
556 
557         error = ipsec_setspidx(m, &pcb->inp_sp->sp_in->spidx, 1);
558         if (error == 0) {
559                 pcb->inp_sp->sp_in->spidx.dir = IPSEC_DIR_INBOUND;
560                 pcb->inp_sp->sp_out->spidx = pcb->inp_sp->sp_in->spidx;
561                 pcb->inp_sp->sp_out->spidx.dir = IPSEC_DIR_OUTBOUND;
562         } else {
563                 bzero(&pcb->inp_sp->sp_in->spidx,
564                         sizeof (pcb->inp_sp->sp_in->spidx));
565                 bzero(&pcb->inp_sp->sp_out->spidx,
566                         sizeof (pcb->inp_sp->sp_in->spidx));
567         }
568         return error;
569 }
570 
571 #ifdef INET6
572 static int
573 ipsec6_setspidx_in6pcb(m, pcb)
574         struct mbuf *m;
575         struct in6pcb *pcb;
576 {
577         //INIT_VNET_IPSEC(curvnet);
578         struct secpolicyindex *spidx;
579         int error;
580 
581         IPSEC_ASSERT(pcb != NULL, ("null pcb"));
582         IPSEC_ASSERT(pcb->in6p_sp != NULL, ("null inp_sp"));
583         IPSEC_ASSERT(pcb->in6p_sp->sp_out != NULL && pcb->in6p_sp->sp_in != NULL,
584                 ("null sp_in || sp_out"));
585 
586         bzero(&pcb->in6p_sp->sp_in->spidx, sizeof(*spidx));
587         bzero(&pcb->in6p_sp->sp_out->spidx, sizeof(*spidx));
588 
589         spidx = &pcb->in6p_sp->sp_in->spidx;
590         error = ipsec_setspidx(m, spidx, 1);
591         if (error)
592                 goto bad;
593         spidx->dir = IPSEC_DIR_INBOUND;
594 
595         spidx = &pcb->in6p_sp->sp_out->spidx;
596         error = ipsec_setspidx(m, spidx, 1);
597         if (error)
598                 goto bad;
599         spidx->dir = IPSEC_DIR_OUTBOUND;
600 
601         return 0;
602 
603 bad:
604         bzero(&pcb->in6p_sp->sp_in->spidx, sizeof(*spidx));
605         bzero(&pcb->in6p_sp->sp_out->spidx, sizeof(*spidx));
606         return error;
607 }
608 #endif
609 
610 /*
611  * configure security policy index (src/dst/proto/sport/dport)
612  * by looking at the content of mbuf.
613  * the caller is responsible for error recovery (like clearing up spidx).
614  */
615 static int
616 ipsec_setspidx(m, spidx, needport)
617         struct mbuf *m;
618         struct secpolicyindex *spidx;
619         int needport;
620 {
621         INIT_VNET_IPSEC(curvnet);
622         struct ip *ip = NULL;
623         struct ip ipbuf;
624         u_int v;
625         struct mbuf *n;
626         int len;
627         int error;
628 
629         IPSEC_ASSERT(m != NULL, ("null mbuf"));
630 
631         /*
632          * validate m->m_pkthdr.len.  we see incorrect length if we
633          * mistakenly call this function with inconsistent mbuf chain
634          * (like 4.4BSD tcp/udp processing).  XXX should we panic here?
635          */
636         len = 0;
637         for (n = m; n; n = n->m_next)
638                 len += n->m_len;
639         if (m->m_pkthdr.len != len) {
640                 KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
641                         printf("%s: pkthdr len(%d) mismatch (%d), ignored.\n",
642                                 __func__, len, m->m_pkthdr.len));
643                 return EINVAL;
644         }
645 
646         if (m->m_pkthdr.len < sizeof(struct ip)) {
647                 KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
648                         printf("%s: pkthdr len(%d) too small (v4), ignored.\n",
649                             __func__, m->m_pkthdr.len));
650                 return EINVAL;
651         }
652 
653         if (m->m_len >= sizeof(*ip))
654                 ip = mtod(m, struct ip *);
655         else {
656                 m_copydata(m, 0, sizeof(ipbuf), (caddr_t)&ipbuf);
657                 ip = &ipbuf;
658         }
659 #ifdef _IP_VHL
660         v = _IP_VHL_V(ip->ip_vhl);
661 #else
662         v = ip->ip_v;
663 #endif
664         switch (v) {
665         case 4:
666                 error = ipsec4_setspidx_ipaddr(m, spidx);
667                 if (error)
668                         return error;
669                 ipsec4_get_ulp(m, spidx, needport);
670                 return 0;
671 #ifdef INET6
672         case 6:
673                 if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) {
674                         KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
675                                 printf("%s: pkthdr len(%d) too small (v6), "
676                                 "ignored\n", __func__, m->m_pkthdr.len));
677                         return EINVAL;
678                 }
679                 error = ipsec6_setspidx_ipaddr(m, spidx);
680                 if (error)
681                         return error;
682                 ipsec6_get_ulp(m, spidx, needport);
683                 return 0;
684 #endif
685         default:
686                 KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
687                         printf("%s: " "unknown IP version %u, ignored.\n",
688                                 __func__, v));
689                 return EINVAL;
690         }
691 }
692 
693 static void
694 ipsec4_get_ulp(struct mbuf *m, struct secpolicyindex *spidx, int needport)
695 {
696         u_int8_t nxt;
697         int off;
698 
699         /* sanity check */
700         IPSEC_ASSERT(m != NULL, ("null mbuf"));
701         IPSEC_ASSERT(m->m_pkthdr.len >= sizeof(struct ip),("packet too short"));
702 
703         /* NB: ip_input() flips it into host endian XXX need more checking */
704         if (m->m_len < sizeof (struct ip)) {
705                 struct ip *ip = mtod(m, struct ip *);
706                 if (ip->ip_off & (IP_MF | IP_OFFMASK))
707                         goto done;
708 #ifdef _IP_VHL
709                 off = _IP_VHL_HL(ip->ip_vhl) << 2;
710 #else
711                 off = ip->ip_hl << 2;
712 #endif
713                 nxt = ip->ip_p;
714         } else {
715                 struct ip ih;
716 
717                 m_copydata(m, 0, sizeof (struct ip), (caddr_t) &ih);
718                 if (ih.ip_off & (IP_MF | IP_OFFMASK))
719                         goto done;
720 #ifdef _IP_VHL
721                 off = _IP_VHL_HL(ih.ip_vhl) << 2;
722 #else
723                 off = ih.ip_hl << 2;
724 #endif
725                 nxt = ih.ip_p;
726         }
727 
728         while (off < m->m_pkthdr.len) {
729                 struct ip6_ext ip6e;
730                 struct tcphdr th;
731                 struct udphdr uh;
732 
733                 switch (nxt) {
734                 case IPPROTO_TCP:
735                         spidx->ul_proto = nxt;
736                         if (!needport)
737                                 goto done_proto;
738                         if (off + sizeof(struct tcphdr) > m->m_pkthdr.len)
739                                 goto done;
740                         m_copydata(m, off, sizeof (th), (caddr_t) &th);
741                         spidx->src.sin.sin_port = th.th_sport;
742                         spidx->dst.sin.sin_port = th.th_dport;
743                         return;
744                 case IPPROTO_UDP:
745                         spidx->ul_proto = nxt;
746                         if (!needport)
747                                 goto done_proto;
748                         if (off + sizeof(struct udphdr) > m->m_pkthdr.len)
749                                 goto done;
750                         m_copydata(m, off, sizeof (uh), (caddr_t) &uh);
751                         spidx->src.sin.sin_port = uh.uh_sport;
752                         spidx->dst.sin.sin_port = uh.uh_dport;
753                         return;
754                 case IPPROTO_AH:
755                         if (off + sizeof(ip6e) > m->m_pkthdr.len)
756                                 goto done;
757                         /* XXX sigh, this works but is totally bogus */
758                         m_copydata(m, off, sizeof(ip6e), (caddr_t) &ip6e);
759                         off += (ip6e.ip6e_len + 2) << 2;
760                         nxt = ip6e.ip6e_nxt;
761                         break;
762                 case IPPROTO_ICMP:
763                 default:
764                         /* XXX intermediate headers??? */
765                         spidx->ul_proto = nxt;
766                         goto done_proto;
767                 }
768         }
769 done:
770         spidx->ul_proto = IPSEC_ULPROTO_ANY;
771 done_proto:
772         spidx->src.sin.sin_port = IPSEC_PORT_ANY;
773         spidx->dst.sin.sin_port = IPSEC_PORT_ANY;
774 }
775 
776 /* assumes that m is sane */
777 static int
778 ipsec4_setspidx_ipaddr(struct mbuf *m, struct secpolicyindex *spidx)
779 {
780         static const struct sockaddr_in template = {
781                 sizeof (struct sockaddr_in),
782                 AF_INET,
783                 0, { 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }
784         };
785 
786         spidx->src.sin = template;
787         spidx->dst.sin = template;
788 
789         if (m->m_len < sizeof (struct ip)) {
790                 m_copydata(m, offsetof(struct ip, ip_src),
791                            sizeof (struct  in_addr),
792                            (caddr_t) &spidx->src.sin.sin_addr);
793                 m_copydata(m, offsetof(struct ip, ip_dst),
794                            sizeof (struct  in_addr),
795                            (caddr_t) &spidx->dst.sin.sin_addr);
796         } else {
797                 struct ip *ip = mtod(m, struct ip *);
798                 spidx->src.sin.sin_addr = ip->ip_src;
799                 spidx->dst.sin.sin_addr = ip->ip_dst;
800         }
801 
802         spidx->prefs = sizeof(struct in_addr) << 3;
803         spidx->prefd = sizeof(struct in_addr) << 3;
804 
805         return 0;
806 }
807 
808 #ifdef INET6
809 static void
810 ipsec6_get_ulp(m, spidx, needport)
811         struct mbuf *m;
812         struct secpolicyindex *spidx;
813         int needport;
814 {
815         INIT_VNET_IPSEC(curvnet);
816         int off, nxt;
817         struct tcphdr th;
818         struct udphdr uh;
819         struct icmp6_hdr ih;
820 
821         /* sanity check */
822         if (m == NULL)
823                 panic("%s: NULL pointer was passed.\n", __func__);
824 
825         KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
826                 printf("%s:\n", __func__); kdebug_mbuf(m));
827 
828         /* set default */
829         spidx->ul_proto = IPSEC_ULPROTO_ANY;
830         ((struct sockaddr_in6 *)&spidx->src)->sin6_port = IPSEC_PORT_ANY;
831         ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = IPSEC_PORT_ANY;
832 
833         nxt = -1;
834         off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt);
835         if (off < 0 || m->m_pkthdr.len < off)
836                 return;
837 
838         switch (nxt) {
839         case IPPROTO_TCP:
840                 spidx->ul_proto = nxt;
841                 if (!needport)
842                         break;
843                 if (off + sizeof(struct tcphdr) > m->m_pkthdr.len)
844                         break;
845                 m_copydata(m, off, sizeof(th), (caddr_t)&th);
846                 ((struct sockaddr_in6 *)&spidx->src)->sin6_port = th.th_sport;
847                 ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = th.th_dport;
848                 break;
849         case IPPROTO_UDP:
850                 spidx->ul_proto = nxt;
851                 if (!needport)
852                         break;
853                 if (off + sizeof(struct udphdr) > m->m_pkthdr.len)
854                         break;
855                 m_copydata(m, off, sizeof(uh), (caddr_t)&uh);
856                 ((struct sockaddr_in6 *)&spidx->src)->sin6_port = uh.uh_sport;
857                 ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = uh.uh_dport;
858                 break;
859         case IPPROTO_ICMPV6:
860                 spidx->ul_proto = nxt;
861                 if (off + sizeof(struct icmp6_hdr) > m->m_pkthdr.len)
862                         break;
863                 m_copydata(m, off, sizeof(ih), (caddr_t)&ih);
864                 ((struct sockaddr_in6 *)&spidx->src)->sin6_port =
865                     htons((uint16_t)ih.icmp6_type);
866                 ((struct sockaddr_in6 *)&spidx->dst)->sin6_port =
867                     htons((uint16_t)ih.icmp6_code);
868                 break;
869         default:
870                 /* XXX intermediate headers??? */
871                 spidx->ul_proto = nxt;
872                 break;
873         }
874 }
875 
876 /* assumes that m is sane */
877 static int
878 ipsec6_setspidx_ipaddr(m, spidx)
879         struct mbuf *m;
880         struct secpolicyindex *spidx;
881 {
882         struct ip6_hdr *ip6 = NULL;
883         struct ip6_hdr ip6buf;
884         struct sockaddr_in6 *sin6;
885 
886         if (m->m_len >= sizeof(*ip6))
887                 ip6 = mtod(m, struct ip6_hdr *);
888         else {
889                 m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf);
890                 ip6 = &ip6buf;
891         }
892 
893         sin6 = (struct sockaddr_in6 *)&spidx->src;
894         bzero(sin6, sizeof(*sin6));
895         sin6->sin6_family = AF_INET6;
896         sin6->sin6_len = sizeof(struct sockaddr_in6);
897         bcopy(&ip6->ip6_src, &sin6->sin6_addr, sizeof(ip6->ip6_src));
898         if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
899                 sin6->sin6_addr.s6_addr16[1] = 0;
900                 sin6->sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]);
901         }
902         spidx->prefs = sizeof(struct in6_addr) << 3;
903 
904         sin6 = (struct sockaddr_in6 *)&spidx->dst;
905         bzero(sin6, sizeof(*sin6));
906         sin6->sin6_family = AF_INET6;
907         sin6->sin6_len = sizeof(struct sockaddr_in6);
908         bcopy(&ip6->ip6_dst, &sin6->sin6_addr, sizeof(ip6->ip6_dst));
909         if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
910                 sin6->sin6_addr.s6_addr16[1] = 0;
911                 sin6->sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]);
912         }
913         spidx->prefd = sizeof(struct in6_addr) << 3;
914 
915         return 0;
916 }
917 #endif
918 
919 static void
920 ipsec_delpcbpolicy(p)
921         struct inpcbpolicy *p;
922 {
923         free(p, M_IPSEC_INPCB);
924 }
925 
926 /* initialize policy in PCB */
927 int
928 ipsec_init_policy(so, pcb_sp)
929         struct socket *so;
930         struct inpcbpolicy **pcb_sp;
931 {
932         INIT_VNET_IPSEC(curvnet);
933         struct inpcbpolicy *new;
934 
935         /* sanity check. */
936         if (so == NULL || pcb_sp == NULL)
937                 panic("%s: NULL pointer was passed.\n", __func__);
938