1 /* $NetBSD: in_gif.c,v 1.15 2000/07/05 21:01:38 thorpej Exp $ */ 2 /* $KAME: in_gif.c,v 1.39 2000/04/26 05:33:31 itojun 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 * in_gif.c 35 */ 36 37 #ifdef __FreeBSD__ 38 #include "opt_mrouting.h" 39 #endif 40 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) 41 #include "opt_inet.h" 42 #endif 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/socket.h> 47 #include <sys/sockio.h> 48 #include <sys/mbuf.h> 49 #include <sys/errno.h> 50 #ifdef __FreeBSD__ 51 #include <sys/kernel.h> 52 #include <sys/sysctl.h> 53 #endif 54 #if !defined(__FreeBSD__) || __FreeBSD__ < 3 55 #include <sys/ioctl.h> 56 #endif 57 58 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 59 #include <sys/malloc.h> 60 #endif 61 62 #include <net/if.h> 63 #include <net/route.h> 64 65 #include <netinet/in.h> 66 #include <netinet/in_systm.h> 67 #include <netinet/ip.h> 68 #include <netinet/ip_var.h> 69 #include <netinet/in_gif.h> 70 #include <netinet/in_var.h> 71 #include <netinet/ip_encap.h> 72 #include <netinet/ip_ecn.h> 73 #ifdef __OpenBSD__ 74 #include <netinet/ip_ipsp.h> 75 #endif 76 77 #ifdef INET6 78 #include <netinet/ip6.h> 79 #endif 80 81 #ifdef MROUTING 82 #include <netinet/ip_mroute.h> 83 #endif /* MROUTING */ 84 85 #include <net/if_gif.h> 86 87 #include "gif.h" 88 89 #include <machine/stdarg.h> 90 91 #include <net/net_osdep.h> 92 93 #if NGIF > 0 94 int ip_gif_ttl = GIF_TTL; 95 #else 96 int ip_gif_ttl = 0; 97 #endif 98 #ifdef __FreeBSD__ 99 SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW, 100 &ip_gif_ttl, 0, ""); 101 #endif 102 103 int 104 in_gif_output(ifp, family, m, rt) 105 struct ifnet *ifp; 106 int family; 107 struct mbuf *m; 108 struct rtentry *rt; 109 { 110 register struct gif_softc *sc = (struct gif_softc*)ifp; 111 struct sockaddr_in *dst = (struct sockaddr_in *)&sc->gif_ro.ro_dst; 112 struct sockaddr_in *sin_src = (struct sockaddr_in *)sc->gif_psrc; 113 struct sockaddr_in *sin_dst = (struct sockaddr_in *)sc->gif_pdst; 114 struct ip iphdr; /* capsule IP header, host byte ordered */ 115 int proto, error; 116 u_int8_t tos; 117 118 if (sin_src == NULL || sin_dst == NULL || 119 sin_src->sin_family != AF_INET || 120 sin_dst->sin_family != AF_INET) { 121 m_freem(m); 122 return EAFNOSUPPORT; 123 } 124 125 bzero(&iphdr, sizeof(iphdr)); 126 127 switch (family) { 128 #ifdef INET 129 case AF_INET: 130 { 131 struct ip *ip; 132 133 proto = IPPROTO_IPV4; 134 if (m->m_len < sizeof(*ip)) { 135 m = m_pullup(m, sizeof(*ip)); 136 if (!m) 137 return ENOBUFS; 138 } 139 ip = mtod(m, struct ip *); 140 tos = ip->ip_tos; 141 142 /* RFCs 1853, 2003, 2401 -- copy the DF bit. */ 143 iphdr.ip_off |= (ntohs(ip->ip_off) & IP_DF); 144 break; 145 } 146 #endif /*INET*/ 147 #ifdef INET6 148 case AF_INET6: 149 { 150 struct ip6_hdr *ip6; 151 proto = IPPROTO_IPV6; 152 if (m->m_len < sizeof(*ip6)) { 153 m = m_pullup(m, sizeof(*ip6)); 154 if (!m) 155 return ENOBUFS; 156 } 157 ip6 = mtod(m, struct ip6_hdr *); 158 tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 159 break; 160 } 161 #endif /*INET6*/ 162 default: 163 #ifdef DEBUG 164 printf("in_gif_output: warning: unknown family %d passed\n", 165 family); 166 #endif 167 m_freem(m); 168 return EAFNOSUPPORT; 169 } 170 171 iphdr.ip_src = sin_src->sin_addr; 172 if (ifp->if_flags & IFF_LINK0) { 173 /* multi-destination mode */ 174 if (sin_dst->sin_addr.s_addr != INADDR_ANY) 175 iphdr.ip_dst = sin_dst->sin_addr; 176 else if (rt) { 177 if (family != AF_INET) { 178 m_freem(m); 179 return EINVAL; /*XXX*/ 180 } 181 iphdr.ip_dst = ((struct sockaddr_in *) 182 (rt->rt_gateway))->sin_addr; 183 } else { 184 m_freem(m); 185 return ENETUNREACH; 186 } 187 } else { 188 /* bidirectional configured tunnel mode */ 189 if (sin_dst->sin_addr.s_addr != INADDR_ANY) 190 iphdr.ip_dst = sin_dst->sin_addr; 191 else { 192 m_freem(m); 193 return ENETUNREACH; 194 } 195 } 196 iphdr.ip_p = proto; 197 /* version will be set in ip_output() */ 198 iphdr.ip_ttl = ip_gif_ttl; 199 iphdr.ip_len = m->m_pkthdr.len + sizeof(struct ip); 200 if (ifp->if_flags & IFF_LINK1) 201 ip_ecn_ingress(ECN_ALLOWED, &iphdr.ip_tos, &tos); 202 203 /* prepend new IP header */ 204 M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); 205 if (m && m->m_len < sizeof(struct ip)) 206 m = m_pullup(m, sizeof(struct ip)); 207 if (m == NULL) { 208 printf("ENOBUFS in in_gif_output %d\n", __LINE__); 209 return ENOBUFS; 210 } 211 bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip)); 212 213 if (dst->sin_family != sin_dst->sin_family || 214 dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr) { 215 /* cache route doesn't match */ 216 dst->sin_family = sin_dst->sin_family; 217 dst->sin_len = sizeof(struct sockaddr_in); 218 dst->sin_addr = sin_dst->sin_addr; 219 if (sc->gif_ro.ro_rt) { 220 RTFREE(sc->gif_ro.ro_rt); 221 sc->gif_ro.ro_rt = NULL; 222 } 223 #if 0 224 sc->gif_if.if_mtu = GIF_MTU; 225 #endif 226 } 227 228 if (sc->gif_ro.ro_rt == NULL) { 229 rtalloc(&sc->gif_ro); 230 if (sc->gif_ro.ro_rt == NULL) { 231 m_freem(m); 232 return ENETUNREACH; 233 } 234 235 /* if it constitutes infinite encapsulation, punt. */ 236 if (sc->gif_ro.ro_rt->rt_ifp == ifp) { 237 m_freem(m); 238 return ENETUNREACH; /*XXX*/ 239 } 240 #if 0 241 ifp->if_mtu = sc->gif_ro.ro_rt->rt_ifp->if_mtu 242 - sizeof(struct ip); 243 #endif 244 } 245 246 #ifndef __OpenBSD__ 247 error = ip_output(m, NULL, &sc->gif_ro, 0, NULL); 248 #else 249 error = ip_output(m, NULL, &sc->gif_ro, 0, NULL, NULL); 250 #endif 251 return(error); 252 } 253 254 void 255 #if __STDC__ 256 in_gif_input(struct mbuf *m, ...) 257 #else 258 in_gif_input(m, va_alist) 259 struct mbuf *m; 260 va_dcl 261 #endif 262 { 263 int off, proto; 264 struct ifnet *gifp = NULL; 265 struct ip *ip; 266 int af; 267 va_list ap; 268 u_int8_t otos; 269 270 va_start(ap, m); 271 off = va_arg(ap, int); 272 #ifndef __OpenBSD__ 273 proto = va_arg(ap, int); 274 #endif 275 va_end(ap); 276 277 ip = mtod(m, struct ip *); 278 #ifdef __OpenBSD__ 279 proto = ip->ip_p; 280 #endif 281 282 gifp = (struct ifnet *)encap_getarg(m); 283 284 if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) { 285 m_freem(m); 286 ipstat.ips_nogif++; 287 return; 288 } 289 290 otos = ip->ip_tos; 291 m_adj(m, off); 292 293 switch (proto) { 294 #ifdef INET 295 case IPPROTO_IPV4: 296 { 297 struct ip *ip; 298 af = AF_INET; 299 if (m->m_len < sizeof(*ip)) { 300 m = m_pullup(m, sizeof(*ip)); 301 if (!m) 302 return; 303 } 304 ip = mtod(m, struct ip *); 305 if (gifp->if_flags & IFF_LINK1) 306 ip_ecn_egress(ECN_ALLOWED, &otos, &ip->ip_tos); 307 break; 308 } 309 #endif 310 #ifdef INET6 311 case IPPROTO_IPV6: 312 { 313 struct ip6_hdr *ip6; 314 u_int8_t itos; 315 af = AF_INET6; 316 if (m->m_len < sizeof(*ip6)) { 317 m = m_pullup(m, sizeof(*ip6)); 318 if (!m) 319 return; 320 } 321 ip6 = mtod(m, struct ip6_hdr *); 322 itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 323 if (gifp->if_flags & IFF_LINK1) 324 ip_ecn_egress(ECN_ALLOWED, &otos, &itos); 325 ip6->ip6_flow &= ~htonl(0xff << 20); 326 ip6->ip6_flow |= htonl((u_int32_t)itos << 20); 327 break; 328 } 329 #endif /* INET6 */ 330 default: 331 ipstat.ips_nogif++; 332 m_freem(m); 333 return; 334 } 335 gif_input(m, af, gifp); 336 return; 337 } 338 339 /* 340 * we know that we are in IFF_UP, outer address available, and outer family 341 * matched the physical addr family. see gif_encapcheck(). 342 */ 343 int 344 gif_encapcheck4(m, off, proto, arg) 345 const struct mbuf *m; 346 int off; 347 int proto; 348 void *arg; 349 { 350 struct ip ip; 351 struct gif_softc *sc; 352 struct sockaddr_in *src, *dst; 353 int addrmatch; 354 struct in_ifaddr *ia4; 355 356 /* sanity check done in caller */ 357 sc = (struct gif_softc *)arg; 358 src = (struct sockaddr_in *)sc->gif_psrc; 359 dst = (struct sockaddr_in *)sc->gif_pdst; 360 361 /* LINTED const cast */ 362 m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip); 363 364 /* check for address match */ 365 addrmatch = 0; 366 if (src->sin_addr.s_addr == ip.ip_dst.s_addr) 367 addrmatch |= 1; 368 if (dst->sin_addr.s_addr == ip.ip_src.s_addr) 369 addrmatch |= 2; 370 else if ((sc->gif_if.if_flags & IFF_LINK0) != 0 && 371 dst->sin_addr.s_addr == INADDR_ANY) { 372 addrmatch |= 2; /* we accept any source */ 373 } 374 if (addrmatch != 3) 375 return 0; 376 377 /* martian filters on outer source - NOT done in ip_input! */ 378 if (IN_MULTICAST(ip.ip_src.s_addr)) 379 return 0; 380 switch ((ntohl(ip.ip_src.s_addr) & 0xff000000) >> 24) { 381 case 0: case 127: case 255: 382 return 0; 383 } 384 /* reject packets with broadcast on source */ 385 #if defined(__OpenBSD__) || defined(__NetBSD__) 386 for (ia4 = in_ifaddr.tqh_first; ia4; ia4 = ia4->ia_list.tqe_next) 387 #elif (defined(__FreeBSD__) && __FreeBSD__ >= 3) 388 for (ia4 = TAILQ_FIRST(&in_ifaddrhead); ia4; 389 ia4 = TAILQ_NEXT(ia4, ia_link)) 390 #else 391 for (ia4 = in_ifaddr; ia4 != NULL; ia4 = ia4->ia_next) 392 #endif 393 { 394 if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0) 395 continue; 396 if (ip.ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr) 397 return 0; 398 } 399 400 /* ingress filters on outer source */ 401 if ((m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) { 402 struct sockaddr_in sin; 403 struct rtentry *rt; 404 405 bzero(&sin, sizeof(sin)); 406 sin.sin_family = AF_INET; 407 sin.sin_len = sizeof(struct sockaddr_in); 408 sin.sin_addr = ip.ip_src; 409 #ifdef __FreeBSD__ 410 rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL); 411 #else 412 rt = rtalloc1((struct sockaddr *)&sin, 0); 413 #endif 414 if (!rt) 415 return 0; 416 if (rt->rt_ifp != m->m_pkthdr.rcvif) { 417 rtfree(rt); 418 return 0; 419 } 420 rtfree(rt); 421 } 422 423 /* prioritize: IFF_LINK0 mode is less preferred */ 424 return (sc->gif_if.if_flags & IFF_LINK0) ? 32 : 32 * 2; 425 } 426