]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netipsec/xform_ipip.c
Merge OpenSSL 1.0.1j.
[FreeBSD/FreeBSD.git] / sys / netipsec / xform_ipip.c
1 /*      $FreeBSD$       */
2 /*      $OpenBSD: ip_ipip.c,v 1.25 2002/06/10 18:04:55 itojun Exp $ */
3 /*-
4  * The authors of this code are John Ioannidis (ji@tla.org),
5  * Angelos D. Keromytis (kermit@csd.uch.gr) and
6  * Niels Provos (provos@physnet.uni-hamburg.de).
7  *
8  * The original version of this code was written by John Ioannidis
9  * for BSD/OS in Athens, Greece, in November 1995.
10  *
11  * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
12  * by Angelos D. Keromytis.
13  *
14  * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
15  * and Niels Provos.
16  *
17  * Additional features in 1999 by Angelos D. Keromytis.
18  *
19  * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
20  * Angelos D. Keromytis and Niels Provos.
21  * Copyright (c) 2001, Angelos D. Keromytis.
22  *
23  * Permission to use, copy, and modify this software with or without fee
24  * is hereby granted, provided that this entire notice is included in
25  * all copies of any software which is or includes a copy or
26  * modification of this software.
27  * You may use this code under the GNU public license if you so wish. Please
28  * contribute changes back to the authors under this freer than GPL license
29  * so that we may further the use of strong encryption without limitations to
30  * all.
31  *
32  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
33  * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
34  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
35  * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
36  * PURPOSE.
37  */
38
39 /*
40  * IP-inside-IP processing
41  */
42 #include "opt_inet.h"
43 #include "opt_inet6.h"
44 #include "opt_enc.h"
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/mbuf.h>
49 #include <sys/socket.h>
50 #include <sys/kernel.h>
51 #include <sys/protosw.h>
52 #include <sys/sysctl.h>
53
54 #include <net/if.h>
55 #include <net/if_var.h>
56 #include <net/pfil.h>
57 #include <net/route.h>
58 #include <net/netisr.h>
59 #include <net/vnet.h>
60
61 #include <netinet/in.h>
62 #include <netinet/in_systm.h>
63 #include <netinet/in_var.h>
64 #include <netinet/ip.h>
65 #include <netinet/ip_ecn.h>
66 #include <netinet/ip_var.h>
67 #include <netinet/ip_encap.h>
68
69 #include <netipsec/ipsec.h>
70 #include <netipsec/xform.h>
71
72 #include <netipsec/ipip_var.h>
73
74 #ifdef INET6
75 #include <netinet/ip6.h>
76 #include <netipsec/ipsec6.h>
77 #include <netinet6/ip6_ecn.h>
78 #include <netinet6/in6_var.h>
79 #include <netinet6/ip6protosw.h>
80 #endif
81
82 #include <netipsec/key.h>
83 #include <netipsec/key_debug.h>
84
85 #include <machine/stdarg.h>
86
87 /*
88  * We can control the acceptance of IP4 packets by altering the sysctl
89  * net.inet.ipip.allow value.  Zero means drop them, all else is acceptance.
90  */
91 VNET_DEFINE(int, ipip_allow) = 0;
92 VNET_PCPUSTAT_DEFINE(struct ipipstat, ipipstat);
93 VNET_PCPUSTAT_SYSINIT(ipipstat);
94
95 #ifdef VIMAGE
96 VNET_PCPUSTAT_SYSUNINIT(ipipstat);
97 #endif /* VIMAGE */
98
99 SYSCTL_DECL(_net_inet_ipip);
100 SYSCTL_VNET_INT(_net_inet_ipip, OID_AUTO,
101         ipip_allow,     CTLFLAG_RW,     &VNET_NAME(ipip_allow), 0, "");
102 SYSCTL_VNET_PCPUSTAT(_net_inet_ipip, IPSECCTL_STATS, stats,
103     struct ipipstat, ipipstat,
104     "IPIP statistics (struct ipipstat, netipsec/ipip_var.h)");
105
106 /* XXX IPCOMP */
107 #define M_IPSEC (M_AUTHIPHDR|M_AUTHIPDGM|M_DECRYPTED)
108
109 static void _ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp);
110
111 #ifdef INET6
112 /*
113  * Really only a wrapper for ipip_input(), for use with IPv6.
114  */
115 int
116 ip4_input6(struct mbuf **m, int *offp, int proto)
117 {
118 #if 0
119         /* If we do not accept IP-in-IP explicitly, drop.  */
120         if (!V_ipip_allow && ((*m)->m_flags & M_IPSEC) == 0) {
121                 DPRINTF(("%s: dropped due to policy\n", __func__));
122                 IPIPSTAT_INC(ipips_pdrops);
123                 m_freem(*m);
124                 return IPPROTO_DONE;
125         }
126 #endif
127         _ipip_input(*m, *offp, NULL);
128         return IPPROTO_DONE;
129 }
130 #endif /* INET6 */
131
132 #ifdef INET
133 /*
134  * Really only a wrapper for ipip_input(), for use with IPv4.
135  */
136 int
137 ip4_input(struct mbuf **mp, int *offp, int proto)
138 {
139 #if 0
140         /* If we do not accept IP-in-IP explicitly, drop.  */
141         if (!V_ipip_allow && (m->m_flags & M_IPSEC) == 0) {
142                 DPRINTF(("%s: dropped due to policy\n", __func__));
143                 IPIPSTAT_INC(ipips_pdrops);
144                 m_freem(m);
145                 return;
146         }
147 #endif
148         _ipip_input(*mp, *offp, NULL);
149         return (IPPROTO_DONE);
150 }
151 #endif /* INET */
152
153 /*
154  * ipip_input gets called when we receive an IP{46} encapsulated packet,
155  * either because we got it at a real interface, or because AH or ESP
156  * were being used in tunnel mode (in which case the rcvif element will
157  * contain the address of the encX interface associated with the tunnel.
158  */
159
160 static void
161 _ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp)
162 {
163         struct ip *ipo;
164 #ifdef INET6
165         struct ip6_hdr *ip6 = NULL;
166         u_int8_t itos;
167 #endif
168         int isr;
169         u_int8_t otos;
170         u_int8_t v;
171         int hlen;
172
173         IPIPSTAT_INC(ipips_ipackets);
174
175         m_copydata(m, 0, 1, &v);
176
177         switch (v >> 4) {
178 #ifdef INET
179         case 4:
180                 hlen = sizeof(struct ip);
181                 break;
182 #endif /* INET */
183 #ifdef INET6
184         case 6:
185                 hlen = sizeof(struct ip6_hdr);
186                 break;
187 #endif
188         default:
189                 IPIPSTAT_INC(ipips_family);
190                 m_freem(m);
191                 return /* EAFNOSUPPORT */;
192         }
193
194         /* Bring the IP header in the first mbuf, if not there already */
195         if (m->m_len < hlen) {
196                 if ((m = m_pullup(m, hlen)) == NULL) {
197                         DPRINTF(("%s: m_pullup (1) failed\n", __func__));
198                         IPIPSTAT_INC(ipips_hdrops);
199                         return;
200                 }
201         }
202         ipo = mtod(m, struct ip *);
203
204         /* Keep outer ecn field. */
205         switch (v >> 4) {
206 #ifdef INET
207         case 4:
208                 otos = ipo->ip_tos;
209                 break;
210 #endif /* INET */
211 #ifdef INET6
212         case 6:
213                 otos = (ntohl(mtod(m, struct ip6_hdr *)->ip6_flow) >> 20) & 0xff;
214                 break;
215 #endif
216         default:
217                 panic("ipip_input: unknown ip version %u (outer)", v>>4);
218         }
219
220         /* Remove outer IP header */
221         m_adj(m, iphlen);
222
223         /* Sanity check */
224         if (m->m_pkthdr.len < sizeof(struct ip))  {
225                 IPIPSTAT_INC(ipips_hdrops);
226                 m_freem(m);
227                 return;
228         }
229
230         m_copydata(m, 0, 1, &v);
231
232         switch (v >> 4) {
233 #ifdef INET
234         case 4:
235                 hlen = sizeof(struct ip);
236                 break;
237 #endif /* INET */
238
239 #ifdef INET6
240         case 6:
241                 hlen = sizeof(struct ip6_hdr);
242                 break;
243 #endif
244         default:
245                 IPIPSTAT_INC(ipips_family);
246                 m_freem(m);
247                 return; /* EAFNOSUPPORT */
248         }
249
250         /*
251          * Bring the inner IP header in the first mbuf, if not there already.
252          */
253         if (m->m_len < hlen) {
254                 if ((m = m_pullup(m, hlen)) == NULL) {
255                         DPRINTF(("%s: m_pullup (2) failed\n", __func__));
256                         IPIPSTAT_INC(ipips_hdrops);
257                         return;
258                 }
259         }
260
261         /*
262          * RFC 1853 specifies that the inner TTL should not be touched on
263          * decapsulation. There's no reason this comment should be here, but
264          * this is as good as any a position.
265          */
266
267         /* Some sanity checks in the inner IP header */
268         switch (v >> 4) {
269 #ifdef INET
270         case 4:
271                 ipo = mtod(m, struct ip *);
272                 ip_ecn_egress(V_ip4_ipsec_ecn, &otos, &ipo->ip_tos);
273                 break;
274 #endif /* INET */
275 #ifdef INET6
276         case 6:
277                 ip6 = (struct ip6_hdr *) ipo;
278                 itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
279                 ip_ecn_egress(V_ip6_ipsec_ecn, &otos, &itos);
280                 ip6->ip6_flow &= ~htonl(0xff << 20);
281                 ip6->ip6_flow |= htonl((u_int32_t) itos << 20);
282                 break;
283 #endif
284         default:
285                 panic("ipip_input: unknown ip version %u (inner)", v>>4);
286         }
287
288         /* Check for local address spoofing. */
289         if ((m->m_pkthdr.rcvif == NULL ||
290             !(m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK)) &&
291             V_ipip_allow != 2) {
292 #ifdef INET
293                 if ((v >> 4) == IPVERSION &&
294                     in_localip(ipo->ip_src) != 0) {
295                         IPIPSTAT_INC(ipips_spoof);
296                         m_freem(m);
297                         return;
298                 }
299 #endif
300 #ifdef INET6
301                 if ((v & IPV6_VERSION_MASK) == IPV6_VERSION &&
302                     in6_localip(&ip6->ip6_src) != 0) {
303                         IPIPSTAT_INC(ipips_spoof);
304                         m_freem(m);
305                         return;
306                 }
307 #endif
308         }
309
310         /* Statistics */
311         IPIPSTAT_ADD(ipips_ibytes, m->m_pkthdr.len - iphlen);
312
313         /*
314          * Interface pointer stays the same; if no IPsec processing has
315          * been done (or will be done), this will point to a normal
316          * interface. Otherwise, it'll point to an enc interface, which
317          * will allow a packet filter to distinguish between secure and
318          * untrusted packets.
319          */
320
321         switch (v >> 4) {
322 #ifdef INET
323         case 4:
324                 isr = NETISR_IP;
325                 break;
326 #endif
327 #ifdef INET6
328         case 6:
329                 isr = NETISR_IPV6;
330                 break;
331 #endif
332         default:
333                 panic("%s: bogus ip version %u", __func__, v>>4);
334         }
335
336         if (netisr_queue(isr, m)) {     /* (0) on success. */
337                 IPIPSTAT_INC(ipips_qfull);
338                 DPRINTF(("%s: packet dropped because of full queue\n",
339                         __func__));
340         }
341 }
342
343 int
344 ipip_output(
345         struct mbuf *m,
346         struct ipsecrequest *isr,
347         struct mbuf **mp,
348         int skip,
349         int protoff
350 )
351 {
352         struct secasvar *sav;
353         u_int8_t tp, otos;
354         struct secasindex *saidx;
355         int error;
356 #if defined(INET) || defined(INET6)
357         u_int8_t itos;
358 #endif
359 #ifdef INET
360         struct ip *ipo;
361 #endif /* INET */
362 #ifdef INET6
363         struct ip6_hdr *ip6, *ip6o;
364 #endif /* INET6 */
365
366         sav = isr->sav;
367         IPSEC_ASSERT(sav != NULL, ("null SA"));
368         IPSEC_ASSERT(sav->sah != NULL, ("null SAH"));
369
370         /* XXX Deal with empty TDB source/destination addresses. */
371
372         m_copydata(m, 0, 1, &tp);
373         tp = (tp >> 4) & 0xff;  /* Get the IP version number. */
374
375         saidx = &sav->sah->saidx;
376         switch (saidx->dst.sa.sa_family) {
377 #ifdef INET
378         case AF_INET:
379                 if (saidx->src.sa.sa_family != AF_INET ||
380                     saidx->src.sin.sin_addr.s_addr == INADDR_ANY ||
381                     saidx->dst.sin.sin_addr.s_addr == INADDR_ANY) {
382                         DPRINTF(("%s: unspecified tunnel endpoint "
383                             "address in SA %s/%08lx\n", __func__,
384                             ipsec_address(&saidx->dst),
385                             (u_long) ntohl(sav->spi)));
386                         IPIPSTAT_INC(ipips_unspec);
387                         error = EINVAL;
388                         goto bad;
389                 }
390
391                 M_PREPEND(m, sizeof(struct ip), M_NOWAIT);
392                 if (m == 0) {
393                         DPRINTF(("%s: M_PREPEND failed\n", __func__));
394                         IPIPSTAT_INC(ipips_hdrops);
395                         error = ENOBUFS;
396                         goto bad;
397                 }
398
399                 ipo = mtod(m, struct ip *);
400
401                 ipo->ip_v = IPVERSION;
402                 ipo->ip_hl = 5;
403                 ipo->ip_len = htons(m->m_pkthdr.len);
404                 ipo->ip_ttl = V_ip_defttl;
405                 ipo->ip_sum = 0;
406                 ipo->ip_src = saidx->src.sin.sin_addr;
407                 ipo->ip_dst = saidx->dst.sin.sin_addr;
408
409                 ipo->ip_id = ip_newid();
410
411                 /* If the inner protocol is IP... */
412                 switch (tp) {
413                 case IPVERSION:
414                         /* Save ECN notification */
415                         m_copydata(m, sizeof(struct ip) +
416                             offsetof(struct ip, ip_tos),
417                             sizeof(u_int8_t), (caddr_t) &itos);
418
419                         ipo->ip_p = IPPROTO_IPIP;
420
421                         /*
422                          * We should be keeping tunnel soft-state and
423                          * send back ICMPs if needed.
424                          */
425                         m_copydata(m, sizeof(struct ip) +
426                             offsetof(struct ip, ip_off),
427                             sizeof(u_int16_t), (caddr_t) &ipo->ip_off);
428                         ipo->ip_off = ntohs(ipo->ip_off);
429                         ipo->ip_off &= ~(IP_DF | IP_MF | IP_OFFMASK);
430                         ipo->ip_off = htons(ipo->ip_off);
431                         break;
432 #ifdef INET6
433                 case (IPV6_VERSION >> 4):
434                 {
435                         u_int32_t itos32;
436
437                         /* Save ECN notification. */
438                         m_copydata(m, sizeof(struct ip) +
439                             offsetof(struct ip6_hdr, ip6_flow),
440                             sizeof(u_int32_t), (caddr_t) &itos32);
441                         itos = ntohl(itos32) >> 20;
442                         ipo->ip_p = IPPROTO_IPV6;
443                         ipo->ip_off = 0;
444                         break;
445                 }
446 #endif /* INET6 */
447                 default:
448                         goto nofamily;
449                 }
450
451                 otos = 0;
452                 ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);
453                 ipo->ip_tos = otos;
454                 break;
455 #endif /* INET */
456
457 #ifdef INET6
458         case AF_INET6:
459                 if (IN6_IS_ADDR_UNSPECIFIED(&saidx->dst.sin6.sin6_addr) ||
460                     saidx->src.sa.sa_family != AF_INET6 ||
461                     IN6_IS_ADDR_UNSPECIFIED(&saidx->src.sin6.sin6_addr)) {
462                         DPRINTF(("%s: unspecified tunnel endpoint "
463                             "address in SA %s/%08lx\n", __func__,
464                             ipsec_address(&saidx->dst),
465                             (u_long) ntohl(sav->spi)));
466                         IPIPSTAT_INC(ipips_unspec);
467                         error = ENOBUFS;
468                         goto bad;
469                 }
470
471                 /* scoped address handling */
472                 ip6 = mtod(m, struct ip6_hdr *);
473                 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
474                         ip6->ip6_src.s6_addr16[1] = 0;
475                 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
476                         ip6->ip6_dst.s6_addr16[1] = 0;
477
478                 M_PREPEND(m, sizeof(struct ip6_hdr), M_NOWAIT);
479                 if (m == 0) {
480                         DPRINTF(("%s: M_PREPEND failed\n", __func__));
481                         IPIPSTAT_INC(ipips_hdrops);
482                         error = ENOBUFS;
483                         goto bad;
484                 }
485
486                 /* Initialize IPv6 header */
487                 ip6o = mtod(m, struct ip6_hdr *);
488                 ip6o->ip6_flow = 0;
489                 ip6o->ip6_vfc &= ~IPV6_VERSION_MASK;
490                 ip6o->ip6_vfc |= IPV6_VERSION;
491                 ip6o->ip6_plen = htons(m->m_pkthdr.len);
492                 ip6o->ip6_hlim = IPV6_DEFHLIM;
493                 ip6o->ip6_dst = saidx->dst.sin6.sin6_addr;
494                 ip6o->ip6_src = saidx->src.sin6.sin6_addr;
495
496                 /* Fix payload length */
497                 ip6o->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
498
499                 switch (tp) {
500 #ifdef INET
501                 case IPVERSION:
502                         /* Save ECN notification */
503                         m_copydata(m, sizeof(struct ip6_hdr) +
504                             offsetof(struct ip, ip_tos), sizeof(u_int8_t),
505                             (caddr_t) &itos);
506
507                         /* This is really IPVERSION. */
508                         ip6o->ip6_nxt = IPPROTO_IPIP;
509                         break;
510 #endif /* INET */
511                 case (IPV6_VERSION >> 4):
512                 {
513                         u_int32_t itos32;
514
515                         /* Save ECN notification. */
516                         m_copydata(m, sizeof(struct ip6_hdr) +
517                             offsetof(struct ip6_hdr, ip6_flow),
518                             sizeof(u_int32_t), (caddr_t) &itos32);
519                         itos = ntohl(itos32) >> 20;
520
521                         ip6o->ip6_nxt = IPPROTO_IPV6;
522                         break;
523                 }
524                 default:
525                         goto nofamily;
526                 }
527
528                 otos = 0;
529                 ip_ecn_ingress(V_ip6_ipsec_ecn, &otos, &itos);
530                 ip6o->ip6_flow |= htonl((u_int32_t) otos << 20);
531                 break;
532 #endif /* INET6 */
533
534         default:
535 nofamily:
536                 DPRINTF(("%s: unsupported protocol family %u\n", __func__,
537                     saidx->dst.sa.sa_family));
538                 IPIPSTAT_INC(ipips_family);
539                 error = EAFNOSUPPORT;           /* XXX diffs from openbsd */
540                 goto bad;
541         }
542
543         IPIPSTAT_INC(ipips_opackets);
544         *mp = m;
545
546 #ifdef INET
547         if (saidx->dst.sa.sa_family == AF_INET) {
548 #if 0
549                 if (sav->tdb_xform->xf_type == XF_IP4)
550                         tdb->tdb_cur_bytes +=
551                             m->m_pkthdr.len - sizeof(struct ip);
552 #endif
553                 IPIPSTAT_ADD(ipips_obytes,
554                     m->m_pkthdr.len - sizeof(struct ip));
555         }
556 #endif /* INET */
557
558 #ifdef INET6
559         if (saidx->dst.sa.sa_family == AF_INET6) {
560 #if 0
561                 if (sav->tdb_xform->xf_type == XF_IP4)
562                         tdb->tdb_cur_bytes +=
563                             m->m_pkthdr.len - sizeof(struct ip6_hdr);
564 #endif
565                 IPIPSTAT_ADD(ipips_obytes,
566                     m->m_pkthdr.len - sizeof(struct ip6_hdr));
567         }
568 #endif /* INET6 */
569
570         return 0;
571 bad:
572         if (m)
573                 m_freem(m);
574         *mp = NULL;
575         return (error);
576 }
577
578 #ifdef IPSEC
579 #if defined(INET) || defined(INET6)
580 static int
581 ipe4_init(struct secasvar *sav, struct xformsw *xsp)
582 {
583         sav->tdb_xform = xsp;
584         return 0;
585 }
586
587 static int
588 ipe4_zeroize(struct secasvar *sav)
589 {
590         sav->tdb_xform = NULL;
591         return 0;
592 }
593
594 static int
595 ipe4_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
596 {
597         /* This is a rather serious mistake, so no conditional printing. */
598         printf("%s: should never be called\n", __func__);
599         if (m)
600                 m_freem(m);
601         return EOPNOTSUPP;
602 }
603
604 static struct xformsw ipe4_xformsw = {
605         XF_IP4,         0,              "IPv4 Simple Encapsulation",
606         ipe4_init,      ipe4_zeroize,   ipe4_input,     ipip_output,
607 };
608
609 extern struct domain inetdomain;
610 #endif /* INET || INET6 */
611 #ifdef INET
612 static struct protosw ipe4_protosw = {
613         .pr_type =      SOCK_RAW,
614         .pr_domain =    &inetdomain,
615         .pr_protocol =  IPPROTO_IPV4,
616         .pr_flags =     PR_ATOMIC|PR_ADDR|PR_LASTHDR,
617         .pr_input =     ip4_input,
618         .pr_ctloutput = rip_ctloutput,
619         .pr_usrreqs =   &rip_usrreqs
620 };
621 #endif /* INET */
622 #if defined(INET6) && defined(INET)
623 static struct protosw ipe6_protosw = {
624         .pr_type =      SOCK_RAW,
625         .pr_domain =    &inetdomain,
626         .pr_protocol =  IPPROTO_IPV6,
627         .pr_flags =     PR_ATOMIC|PR_ADDR|PR_LASTHDR,
628         .pr_input =     ip4_input6,
629         .pr_ctloutput = rip_ctloutput,
630         .pr_usrreqs =   &rip_usrreqs
631 };
632 #endif /* INET6 && INET */
633
634 #ifdef INET
635 /*
636  * Check the encapsulated packet to see if we want it
637  */
638 static int
639 ipe4_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
640 {
641         /*
642          * Only take packets coming from IPSEC tunnels; the rest
643          * must be handled by the gif tunnel code.  Note that we
644          * also return a minimum priority when we want the packet
645          * so any explicit gif tunnels take precedence.
646          */
647         return ((m->m_flags & M_IPSEC) != 0 ? 1 : 0);
648 }
649 #endif /* INET */
650
651 static void
652 ipe4_attach(void)
653 {
654
655         xform_register(&ipe4_xformsw);
656         /* attach to encapsulation framework */
657         /* XXX save return cookie for detach on module remove */
658 #ifdef INET
659         (void) encap_attach_func(AF_INET, -1,
660                 ipe4_encapcheck, &ipe4_protosw, NULL);
661 #endif
662 #if defined(INET6) && defined(INET)
663         (void) encap_attach_func(AF_INET6, -1,
664                 ipe4_encapcheck, (struct protosw *)&ipe6_protosw, NULL);
665 #endif
666 }
667 SYSINIT(ipe4_xform_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE, ipe4_attach, NULL);
668 #endif  /* IPSEC */