1 /* $OpenBSD: ip_gre.c,v 1.44 2011/07/09 00:47:18 henning Exp $ */ 2 /* $NetBSD: ip_gre.c,v 1.9 1999/10/25 19:18:11 drochner Exp $ */ 3 4 /* 5 * Copyright (c) 1998 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Heiko W.Rupp <hwr@pilhuhn.de> 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * decapsulate tunneled packets and send them on 35 * output half is in net/if_gre.[ch] 36 * This currently handles IPPROTO_GRE, IPPROTO_MOBILE 37 */ 38 39 40 #include "gre.h" 41 #if NGRE > 0 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/mbuf.h> 46 #include <sys/protosw.h> 47 #include <sys/socket.h> 48 #include <sys/socketvar.h> 49 #include <sys/proc.h> 50 #include <sys/sysctl.h> 51 #include <net/if.h> 52 #include <net/netisr.h> 53 #include <net/route.h> 54 #include <net/bpf.h> 55 56 #ifdef INET 57 #include <netinet/in.h> 58 #include <netinet/in_var.h> 59 #include <netinet/in_systm.h> 60 #include <netinet/ip.h> 61 #include <netinet/ip_var.h> 62 #include <netinet/ip_gre.h> 63 #include <netinet/if_ether.h> 64 #include <netinet/in_pcb.h> 65 #else 66 #error "ip_gre used without inet" 67 #endif 68 69 #ifdef MPLS 70 #include <netmpls/mpls.h> 71 #endif 72 73 #include "bpfilter.h" 74 #include "pf.h" 75 76 #if NPF > 0 77 #include <net/pfvar.h> 78 #endif 79 80 #ifdef PIPEX 81 #include <net/pipex.h> 82 #endif 83 84 /* Needs IP headers. */ 85 #include <net/if_gre.h> 86 87 struct gre_softc *gre_lookup(struct mbuf *, u_int8_t); 88 int gre_input2(struct mbuf *, int, u_char); 89 90 /* 91 * Decapsulate. 92 * Does the real work and is called from gre_input() (above) 93 * returns 0 if packet is not yet processed 94 * and 1 if it needs no further processing 95 * proto is the protocol number of the "calling" foo_input() 96 * routine. 97 */ 98 99 int 100 gre_input2(struct mbuf *m, int hlen, u_char proto) 101 { 102 struct greip *gip; 103 int s; 104 struct ifqueue *ifq; 105 struct gre_softc *sc; 106 u_short flags; 107 u_int af; 108 109 if ((sc = gre_lookup(m, proto)) == NULL) { 110 /* No matching tunnel or tunnel is down. */ 111 return (0); 112 } 113 114 if (m->m_len < sizeof(*gip)) { 115 m = m_pullup(m, sizeof(*gip)); 116 if (m == NULL) 117 return (ENOBUFS); 118 } 119 gip = mtod(m, struct greip *); 120 121 m->m_pkthdr.rcvif = &sc->sc_if; 122 m->m_pkthdr.rdomain = sc->sc_if.if_rdomain; 123 124 sc->sc_if.if_ipackets++; 125 sc->sc_if.if_ibytes += m->m_pkthdr.len; 126 127 switch (proto) { 128 case IPPROTO_GRE: 129 hlen += sizeof (struct gre_h); 130 131 /* process GRE flags as packet can be of variable len */ 132 flags = ntohs(gip->gi_flags); 133 134 /* Checksum & Offset are present */ 135 if ((flags & GRE_CP) | (flags & GRE_RP)) 136 hlen += 4; 137 138 /* We don't support routing fields (variable length) */ 139 if (flags & GRE_RP) 140 return (0); 141 142 if (flags & GRE_KP) 143 hlen += 4; 144 145 if (flags & GRE_SP) 146 hlen += 4; 147 148 switch (ntohs(gip->gi_ptype)) { /* ethertypes */ 149 case GREPROTO_WCCP: 150 /* WCCP/GRE: 151 * So far as I can see (and test) it seems that Cisco's WCCP 152 * GRE tunnel is precisely a IP-in-GRE tunnel that differs 153 * only in its protocol number. At least, it works for me. 154 * 155 * The Internet Draft can be found if you look for 156 * draft-forster-wrec-wccp-v1-00.txt 157 * 158 * So yes, we're doing a fall-through (unless, of course, 159 * net.inet.gre.wccp is 0). 160 */ 161 if (!gre_wccp) 162 return (0); 163 case ETHERTYPE_IP: /* shouldn't need a schednetisr(), as */ 164 ifq = &ipintrq; /* we are in ip_input */ 165 af = AF_INET; 166 break; 167 #ifdef INET6 168 case ETHERTYPE_IPV6: 169 ifq = &ip6intrq; 170 schednetisr(NETISR_IPV6); 171 af = AF_INET6; 172 break; 173 #endif 174 case 0: 175 /* keepalive reply, retrigger hold timer */ 176 gre_recv_keepalive(sc); 177 m_freem(m); 178 return (1); 179 #ifdef MPLS 180 case ETHERTYPE_MPLS: 181 case ETHERTYPE_MPLS_MCAST: 182 ifq = &mplsintrq; 183 schednetisr(NETISR_MPLS); 184 af = AF_MPLS; 185 break; 186 #endif 187 default: /* others not yet supported */ 188 return (0); 189 } 190 break; 191 default: 192 /* others not yet supported */ 193 return (0); 194 } 195 196 if (hlen > m->m_pkthdr.len) { 197 m_freem(m); 198 return (EINVAL); 199 } 200 m_adj(m, hlen); 201 202 #if NBPFILTER > 0 203 if (sc->sc_if.if_bpf) 204 bpf_mtap_af(sc->sc_if.if_bpf, af, m, BPF_DIRECTION_IN); 205 #endif 206 207 #if NPF > 0 208 pf_pkt_addr_changed(m); 209 #endif 210 211 s = splnet(); /* possible */ 212 IF_INPUT_ENQUEUE(ifq, m); 213 splx(s); 214 215 return (1); /* packet is done, no further processing needed */ 216 } 217 218 /* 219 * Decapsulate a packet and feed it back through ip_input (this 220 * routine is called whenever IP gets a packet with proto type 221 * IPPROTO_GRE and a local destination address). 222 */ 223 void 224 gre_input(struct mbuf *m, ...) 225 { 226 int hlen, ret; 227 va_list ap; 228 229 va_start(ap, m); 230 hlen = va_arg(ap, int); 231 va_end(ap); 232 233 if (!gre_allow) { 234 m_freem(m); 235 return; 236 } 237 238 #ifdef PIPEX 239 if (pipex_enable) { 240 struct pipex_session *session; 241 242 if ((session = pipex_pptp_lookup_session(m)) != NULL) { 243 if (pipex_pptp_input(m, session) == NULL) 244 return; 245 } 246 } 247 #endif 248 249 ret = gre_input2(m, hlen, IPPROTO_GRE); 250 /* 251 * ret == 0: packet not processed, but input from here 252 * means no matching tunnel that is up is found. 253 * we inject it to raw ip socket to see if anyone picks it up. 254 * possible that we received a WCCPv1-style GRE packet 255 * but we're not set to accept them. 256 */ 257 if (!ret) 258 rip_input(m, hlen, IPPROTO_GRE); 259 } 260 261 /* 262 * Input routine for IPPROTO_MOBILE. 263 * This is a little bit different from the other modes, as the 264 * encapsulating header was not prepended, but instead inserted 265 * between IP header and payload. 266 */ 267 268 void 269 gre_mobile_input(struct mbuf *m, ...) 270 { 271 struct ip *ip; 272 struct mobip_h *mip; 273 struct ifqueue *ifq; 274 struct gre_softc *sc; 275 int hlen, s; 276 va_list ap; 277 u_char osrc = 0; 278 int msiz; 279 280 va_start(ap, m); 281 hlen = va_arg(ap, int); 282 va_end(ap); 283 284 if (!ip_mobile_allow) { 285 m_freem(m); 286 return; 287 } 288 289 if ((sc = gre_lookup(m, IPPROTO_MOBILE)) == NULL) { 290 /* No matching tunnel or tunnel is down. */ 291 m_freem(m); 292 return; 293 } 294 295 if (m->m_len < sizeof(*mip)) { 296 m = m_pullup(m, sizeof(*mip)); 297 if (m == NULL) 298 return; 299 } 300 ip = mtod(m, struct ip *); 301 mip = mtod(m, struct mobip_h *); 302 303 m->m_pkthdr.rcvif = &sc->sc_if; 304 305 sc->sc_if.if_ipackets++; 306 sc->sc_if.if_ibytes += m->m_pkthdr.len; 307 308 if (ntohs(mip->mh.proto) & MOB_H_SBIT) { 309 osrc = 1; 310 msiz = MOB_H_SIZ_L; 311 mip->mi.ip_src.s_addr = mip->mh.osrc; 312 } else 313 msiz = MOB_H_SIZ_S; 314 315 if (m->m_len < (ip->ip_hl << 2) + msiz) { 316 m = m_pullup(m, (ip->ip_hl << 2) + msiz); 317 if (m == NULL) 318 return; 319 ip = mtod(m, struct ip *); 320 mip = mtod(m, struct mobip_h *); 321 } 322 323 mip->mi.ip_dst.s_addr = mip->mh.odst; 324 mip->mi.ip_p = (ntohs(mip->mh.proto) >> 8); 325 326 if (gre_in_cksum((u_short *) &mip->mh, msiz) != 0) { 327 m_freem(m); 328 return; 329 } 330 331 bcopy(ip + (ip->ip_hl << 2) + msiz, ip + (ip->ip_hl << 2), 332 m->m_len - msiz - (ip->ip_hl << 2)); 333 334 m->m_len -= msiz; 335 ip->ip_len = htons(ntohs(ip->ip_len) - msiz); 336 m->m_pkthdr.len -= msiz; 337 338 ip->ip_sum = 0; 339 ip->ip_sum = in_cksum(m,(ip->ip_hl << 2)); 340 341 ifq = &ipintrq; 342 343 #if NBPFILTER > 0 344 if (sc->sc_if.if_bpf) 345 bpf_mtap_af(sc->sc_if.if_bpf, AF_INET, m, BPF_DIRECTION_IN); 346 #endif 347 348 s = splnet(); /* possible */ 349 IF_INPUT_ENQUEUE(ifq, m); 350 splx(s); 351 } 352 353 /* 354 * Find the gre interface associated with our src/dst/proto set. 355 */ 356 struct gre_softc * 357 gre_lookup(struct mbuf *m, u_int8_t proto) 358 { 359 struct ip *ip = mtod(m, struct ip *); 360 struct gre_softc *sc; 361 362 LIST_FOREACH(sc, &gre_softc_list, sc_list) { 363 if ((sc->g_dst.s_addr == ip->ip_src.s_addr) && 364 (sc->g_src.s_addr == ip->ip_dst.s_addr) && 365 (sc->g_proto == proto) && 366 (rtable_l2(sc->g_rtableid) == 367 rtable_l2(m->m_pkthdr.rdomain)) && 368 ((sc->sc_if.if_flags & IFF_UP) != 0)) 369 return (sc); 370 } 371 372 return (NULL); 373 } 374 375 int 376 gre_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, 377 size_t newlen) 378 { 379 /* All sysctl names at this level are terminal. */ 380 if (namelen != 1) 381 return (ENOTDIR); 382 383 switch (name[0]) { 384 case GRECTL_ALLOW: 385 return (sysctl_int(oldp, oldlenp, newp, newlen, &gre_allow)); 386 case GRECTL_WCCP: 387 return (sysctl_int(oldp, oldlenp, newp, newlen, &gre_wccp)); 388 default: 389 return (ENOPROTOOPT); 390 } 391 /* NOTREACHED */ 392 } 393 394 int 395 ipmobile_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, 396 void *newp, size_t newlen) 397 { 398 /* All sysctl names at this level are terminal. */ 399 if (namelen != 1) 400 return (ENOTDIR); 401 402 switch (name[0]) { 403 case MOBILEIPCTL_ALLOW: 404 return (sysctl_int(oldp, oldlenp, newp, newlen, 405 &ip_mobile_allow)); 406 default: 407 return (ENOPROTOOPT); 408 } 409 /* NOTREACHED */ 410 } 411 412 int 413 gre_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, 414 struct mbuf *control, struct proc *p) 415 { 416 #ifdef PIPEX 417 struct inpcb *inp = sotoinpcb(so); 418 419 if (inp != NULL && inp->inp_pipex && req == PRU_SEND) { 420 int s; 421 struct sockaddr_in *sin4; 422 struct in_addr *ina_dst; 423 struct pipex_session *session; 424 425 s = splsoftnet(); 426 ina_dst = NULL; 427 if ((so->so_state & SS_ISCONNECTED) != 0) { 428 inp = sotoinpcb(so); 429 if (inp) 430 ina_dst = &inp->inp_laddr; 431 } else if (nam) { 432 sin4 = mtod(nam, struct sockaddr_in *); 433 if (nam->m_len == sizeof(struct sockaddr_in) && 434 sin4->sin_family == AF_INET) 435 ina_dst = &sin4->sin_addr; 436 } 437 if (ina_dst != NULL && 438 (session = pipex_pptp_userland_lookup_session_ipv4(m, 439 *ina_dst))) 440 m = pipex_pptp_userland_output(m, session); 441 splx(s); 442 443 if (m == NULL) 444 return (ENOMEM); 445 } 446 #endif 447 return rip_usrreq(so, req, m, nam, control, p); 448 } 449 #endif /* if NGRE > 0 */ 450