1 /* $KAME: ip_encap.c,v 1.41 2001/03/15 08:35:08 itojun Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-3-Clause 5 * 6 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 7 * Copyright (c) 2018 Andrey V. Elsukov <ae@FreeBSD.org> 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 * My grandfather said that there's a devil inside tunnelling technology... 36 * 37 * We have surprisingly many protocols that want packets with IP protocol 38 * #4 or #41. Here's a list of protocols that want protocol #41: 39 * RFC1933 configured tunnel 40 * RFC1933 automatic tunnel 41 * RFC2401 IPsec tunnel 42 * RFC2473 IPv6 generic packet tunnelling 43 * RFC2529 6over4 tunnel 44 * mobile-ip6 (uses RFC2473) 45 * RFC3056 6to4 tunnel 46 * isatap tunnel 47 * Here's a list of protocol that want protocol #4: 48 * RFC1853 IPv4-in-IPv4 tunnelling 49 * RFC2003 IPv4 encapsulation within IPv4 50 * RFC2344 reverse tunnelling for mobile-ip4 51 * RFC2401 IPsec tunnel 52 * Well, what can I say. They impose different en/decapsulation mechanism 53 * from each other, so they need separate protocol handler. The only one 54 * we can easily determine by protocol # is IPsec, which always has 55 * AH/ESP/IPComp header right after outer IP header. 56 * 57 * So, clearly good old protosw does not work for protocol #4 and #41. 58 * The code will let you match protocol via src/dst address pair. 59 */ 60 61 #include <sys/cdefs.h> 62 __FBSDID("$FreeBSD$"); 63 64 #include "opt_inet.h" 65 #include "opt_inet6.h" 66 67 #include <sys/param.h> 68 #include <sys/systm.h> 69 #include <sys/kernel.h> 70 #include <sys/lock.h> 71 #include <sys/malloc.h> 72 #include <sys/mutex.h> 73 #include <sys/mbuf.h> 74 #include <sys/errno.h> 75 #include <sys/socket.h> 76 77 #include <net/if.h> 78 #include <net/if_var.h> 79 80 #include <netinet/in.h> 81 #include <netinet/ip_var.h> 82 #include <netinet/ip_encap.h> 83 84 #ifdef INET6 85 #include <netinet6/ip6_var.h> 86 #endif 87 88 static MALLOC_DEFINE(M_NETADDR, "encap_export_host", 89 "Export host address structure"); 90 91 struct encaptab { 92 CK_LIST_ENTRY(encaptab) chain; 93 int proto; 94 int min_length; 95 int exact_match; 96 void *arg; 97 98 encap_lookup_t lookup; 99 encap_check_t check; 100 encap_input_t input; 101 }; 102 103 CK_LIST_HEAD(encaptab_head, encaptab); 104 #ifdef INET 105 static struct encaptab_head ipv4_encaptab = CK_LIST_HEAD_INITIALIZER(); 106 #endif 107 #ifdef INET6 108 static struct encaptab_head ipv6_encaptab = CK_LIST_HEAD_INITIALIZER(); 109 #endif 110 111 static struct mtx encapmtx; 112 MTX_SYSINIT(encapmtx, &encapmtx, "encapmtx", MTX_DEF); 113 #define ENCAP_WLOCK() mtx_lock(&encapmtx) 114 #define ENCAP_WUNLOCK() mtx_unlock(&encapmtx) 115 #define ENCAP_RLOCK() struct epoch_tracker encap_et; epoch_enter_preempt(net_epoch_preempt, &encap_et) 116 #define ENCAP_RUNLOCK() epoch_exit_preempt(net_epoch_preempt, &encap_et) 117 #define ENCAP_WAIT() epoch_wait_preempt(net_epoch_preempt) 118 119 static struct encaptab * 120 encap_attach(struct encaptab_head *head, const struct encap_config *cfg, 121 void *arg, int mflags) 122 { 123 struct encaptab *ep, *tmp; 124 125 if (cfg == NULL || cfg->input == NULL || 126 (cfg->check == NULL && cfg->lookup == NULL) || 127 (cfg->lookup != NULL && cfg->exact_match != ENCAP_DRV_LOOKUP) || 128 (cfg->exact_match == ENCAP_DRV_LOOKUP && cfg->lookup == NULL)) 129 return (NULL); 130 131 ep = malloc(sizeof(*ep), M_NETADDR, mflags); 132 if (ep == NULL) 133 return (NULL); 134 135 ep->proto = cfg->proto; 136 ep->min_length = cfg->min_length; 137 ep->exact_match = cfg->exact_match; 138 ep->arg = arg; 139 ep->lookup = cfg->exact_match == ENCAP_DRV_LOOKUP ? cfg->lookup: NULL; 140 ep->check = cfg->exact_match != ENCAP_DRV_LOOKUP ? cfg->check: NULL; 141 ep->input = cfg->input; 142 143 ENCAP_WLOCK(); 144 CK_LIST_FOREACH(tmp, head, chain) { 145 if (tmp->exact_match <= ep->exact_match) 146 break; 147 } 148 if (tmp == NULL) 149 CK_LIST_INSERT_HEAD(head, ep, chain); 150 else 151 CK_LIST_INSERT_BEFORE(tmp, ep, chain); 152 ENCAP_WUNLOCK(); 153 return (ep); 154 } 155 156 static int 157 encap_detach(struct encaptab_head *head, const struct encaptab *cookie) 158 { 159 struct encaptab *ep; 160 161 ENCAP_WLOCK(); 162 CK_LIST_FOREACH(ep, head, chain) { 163 if (ep == cookie) { 164 CK_LIST_REMOVE(ep, chain); 165 ENCAP_WUNLOCK(); 166 ENCAP_WAIT(); 167 free(ep, M_NETADDR); 168 return (0); 169 } 170 } 171 ENCAP_WUNLOCK(); 172 return (EINVAL); 173 } 174 175 static int 176 encap_input(struct encaptab_head *head, struct mbuf *m, int off, int proto) 177 { 178 struct encaptab *ep, *match; 179 void *arg; 180 int matchprio, ret; 181 182 match = NULL; 183 matchprio = 0; 184 185 ENCAP_RLOCK(); 186 CK_LIST_FOREACH(ep, head, chain) { 187 if (ep->proto >= 0 && ep->proto != proto) 188 continue; 189 if (ep->min_length > m->m_pkthdr.len) 190 continue; 191 if (ep->exact_match == ENCAP_DRV_LOOKUP) 192 ret = (*ep->lookup)(m, off, proto, &arg); 193 else 194 ret = (*ep->check)(m, off, proto, ep->arg); 195 if (ret <= 0) 196 continue; 197 if (ret > matchprio) { 198 match = ep; 199 if (ep->exact_match != ENCAP_DRV_LOOKUP) 200 arg = ep->arg; 201 /* 202 * No need to continue the search, we got the 203 * exact match. 204 */ 205 if (ret >= ep->exact_match) 206 break; 207 matchprio = ret; 208 } 209 } 210 211 if (match != NULL) { 212 /* found a match, "match" has the best one */ 213 ret = (*match->input)(m, off, proto, arg); 214 ENCAP_RUNLOCK(); 215 MPASS(ret == IPPROTO_DONE); 216 return (IPPROTO_DONE); 217 } 218 ENCAP_RUNLOCK(); 219 return (0); 220 } 221 222 #ifdef INET 223 const struct encaptab * 224 ip_encap_attach(const struct encap_config *cfg, void *arg, int mflags) 225 { 226 227 return (encap_attach(&ipv4_encaptab, cfg, arg, mflags)); 228 } 229 230 int 231 ip_encap_detach(const struct encaptab *cookie) 232 { 233 234 return (encap_detach(&ipv4_encaptab, cookie)); 235 } 236 237 int 238 encap4_input(struct mbuf **mp, int *offp, int proto) 239 { 240 241 if (encap_input(&ipv4_encaptab, *mp, *offp, proto) != IPPROTO_DONE) 242 return (rip_input(mp, offp, proto)); 243 return (IPPROTO_DONE); 244 } 245 #endif /* INET */ 246 247 #ifdef INET6 248 const struct encaptab * 249 ip6_encap_attach(const struct encap_config *cfg, void *arg, int mflags) 250 { 251 252 return (encap_attach(&ipv6_encaptab, cfg, arg, mflags)); 253 } 254 255 int 256 ip6_encap_detach(const struct encaptab *cookie) 257 { 258 259 return (encap_detach(&ipv6_encaptab, cookie)); 260 } 261 262 int 263 encap6_input(struct mbuf **mp, int *offp, int proto) 264 { 265 266 if (encap_input(&ipv6_encaptab, *mp, *offp, proto) != IPPROTO_DONE) 267 return (rip6_input(mp, offp, proto)); 268 return (IPPROTO_DONE); 269 } 270 #endif /* INET6 */ 271