]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netipsec/xform_ipip.c
Remove redundant ip6_plen initialization.
[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_INT(_net_inet_ipip, OID_AUTO, ipip_allow, CTLFLAG_VNET | CTLFLAG_RW,
101     &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_hlim = IPV6_DEFHLIM;
492                 ip6o->ip6_dst = saidx->dst.sin6.sin6_addr;
493                 ip6o->ip6_src = saidx->src.sin6.sin6_addr;
494                 ip6o->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
495
496                 switch (tp) {
497 #ifdef INET
498                 case IPVERSION:
499                         /* Save ECN notification */
500                         m_copydata(m, sizeof(struct ip6_hdr) +
501                             offsetof(struct ip, ip_tos), sizeof(u_int8_t),
502                             (caddr_t) &itos);
503
504                         /* This is really IPVERSION. */
505                         ip6o->ip6_nxt = IPPROTO_IPIP;
506                         break;
507 #endif /* INET */
508                 case (IPV6_VERSION >> 4):
509                 {
510                         u_int32_t itos32;
511
512                         /* Save ECN notification. */
513                         m_copydata(m, sizeof(struct ip6_hdr) +
514                             offsetof(struct ip6_hdr, ip6_flow),
515                             sizeof(u_int32_t), (caddr_t) &itos32);
516                         itos = ntohl(itos32) >> 20;
517
518                         ip6o->ip6_nxt = IPPROTO_IPV6;
519                         break;
520                 }
521                 default:
522                         goto nofamily;
523                 }
524
525                 otos = 0;
526                 ip_ecn_ingress(V_ip6_ipsec_ecn, &otos, &itos);
527                 ip6o->ip6_flow |= htonl((u_int32_t) otos << 20);
528                 break;
529 #endif /* INET6 */
530
531         default:
532 nofamily:
533                 DPRINTF(("%s: unsupported protocol family %u\n", __func__,
534                     saidx->dst.sa.sa_family));
535                 IPIPSTAT_INC(ipips_family);
536                 error = EAFNOSUPPORT;           /* XXX diffs from openbsd */
537                 goto bad;
538         }
539
540         IPIPSTAT_INC(ipips_opackets);
541         *mp = m;
542
543 #ifdef INET
544         if (saidx->dst.sa.sa_family == AF_INET) {
545 #if 0
546                 if (sav->tdb_xform->xf_type == XF_IP4)
547                         tdb->tdb_cur_bytes +=
548                             m->m_pkthdr.len - sizeof(struct ip);
549 #endif
550                 IPIPSTAT_ADD(ipips_obytes,
551                     m->m_pkthdr.len - sizeof(struct ip));
552         }
553 #endif /* INET */
554
555 #ifdef INET6
556         if (saidx->dst.sa.sa_family == AF_INET6) {
557 #if 0
558                 if (sav->tdb_xform->xf_type == XF_IP4)
559                         tdb->tdb_cur_bytes +=
560                             m->m_pkthdr.len - sizeof(struct ip6_hdr);
561 #endif
562                 IPIPSTAT_ADD(ipips_obytes,
563                     m->m_pkthdr.len - sizeof(struct ip6_hdr));
564         }
565 #endif /* INET6 */
566
567         return 0;
568 bad:
569         if (m)
570                 m_freem(m);
571         *mp = NULL;
572         return (error);
573 }
574
575 #ifdef IPSEC
576 #if defined(INET) || defined(INET6)
577 static int
578 ipe4_init(struct secasvar *sav, struct xformsw *xsp)
579 {
580         sav->tdb_xform = xsp;
581         return 0;
582 }
583
584 static int
585 ipe4_zeroize(struct secasvar *sav)
586 {
587         sav->tdb_xform = NULL;
588         return 0;
589 }
590
591 static int
592 ipe4_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
593 {
594         /* This is a rather serious mistake, so no conditional printing. */
595         printf("%s: should never be called\n", __func__);
596         if (m)
597                 m_freem(m);
598         return EOPNOTSUPP;
599 }
600
601 static struct xformsw ipe4_xformsw = {
602         XF_IP4,         0,              "IPv4 Simple Encapsulation",
603         ipe4_init,      ipe4_zeroize,   ipe4_input,     ipip_output,
604 };
605
606 extern struct domain inetdomain;
607 #endif /* INET || INET6 */
608 #ifdef INET
609 static struct protosw ipe4_protosw = {
610         .pr_type =      SOCK_RAW,
611         .pr_domain =    &inetdomain,
612         .pr_protocol =  IPPROTO_IPV4,
613         .pr_flags =     PR_ATOMIC|PR_ADDR|PR_LASTHDR,
614         .pr_input =     ip4_input,
615         .pr_ctloutput = rip_ctloutput,
616         .pr_usrreqs =   &rip_usrreqs
617 };
618 #endif /* INET */
619 #if defined(INET6) && defined(INET)
620 static struct protosw ipe6_protosw = {
621         .pr_type =      SOCK_RAW,
622         .pr_domain =    &inetdomain,
623         .pr_protocol =  IPPROTO_IPV6,
624         .pr_flags =     PR_ATOMIC|PR_ADDR|PR_LASTHDR,
625         .pr_input =     ip4_input6,
626         .pr_ctloutput = rip_ctloutput,
627         .pr_usrreqs =   &rip_usrreqs
628 };
629 #endif /* INET6 && INET */
630
631 #ifdef INET
632 /*
633  * Check the encapsulated packet to see if we want it
634  */
635 static int
636 ipe4_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
637 {
638         /*
639          * Only take packets coming from IPSEC tunnels; the rest
640          * must be handled by the gif tunnel code.  Note that we
641          * also return a minimum priority when we want the packet
642          * so any explicit gif tunnels take precedence.
643          */
644         return ((m->m_flags & M_IPSEC) != 0 ? 1 : 0);
645 }
646 #endif /* INET */
647
648 static void
649 ipe4_attach(void)
650 {
651
652         xform_register(&ipe4_xformsw);
653         /* attach to encapsulation framework */
654         /* XXX save return cookie for detach on module remove */
655 #ifdef INET
656         (void) encap_attach_func(AF_INET, -1,
657                 ipe4_encapcheck, &ipe4_protosw, NULL);
658 #endif
659 #if defined(INET6) && defined(INET)
660         (void) encap_attach_func(AF_INET6, -1,
661                 ipe4_encapcheck, (struct protosw *)&ipe6_protosw, NULL);
662 #endif
663 }
664 SYSINIT(ipe4_xform_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE, ipe4_attach, NULL);
665 #endif  /* IPSEC */