From 173b776a9b3e108d364069e4b178f093c8ec36f0 Mon Sep 17 00:00:00 2001 From: David Gwynne Date: Wed, 7 Feb 2018 01:09:58 +0000 Subject: split mobileip(4) out from the gre(4) driver. having mobileip in gre makes it hard to cut gre up. the current mobileip code is also broken, so this is def and improvement. it also makes it easy to disable and remove mobileip in the future. ok claudio@ henning@ --- share/man/man4/Makefile | 6 +- share/man/man4/gre.4 | 37 +-- share/man/man4/mobileip.4 | 139 ++++++++++ sys/conf/GENERIC | 4 +- sys/conf/files | 4 +- sys/net/if_mobileip.c | 637 ++++++++++++++++++++++++++++++++++++++++++++++ sys/net/if_mobileip.h | 41 +++ sys/netinet/in_proto.c | 15 +- sys/netinet/ip_gre.c | 112 +------- 9 files changed, 844 insertions(+), 151 deletions(-) create mode 100644 share/man/man4/mobileip.4 create mode 100644 sys/net/if_mobileip.c create mode 100644 sys/net/if_mobileip.h diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index 20b409df996..3568370ab8e 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.663 2018/01/02 22:56:01 kettenis Exp $ +# $OpenBSD: Makefile,v 1.664 2018/02/07 01:09:57 dlg Exp $ MAN= aac.4 ac97.4 acphy.4 acrtc.4 \ acpi.4 acpiac.4 acpials.4 acpiasus.4 acpibat.4 \ @@ -38,8 +38,8 @@ MAN= aac.4 ac97.4 acphy.4 acrtc.4 \ lmenv.4 lmn.4 lmtemp.4 lo.4 lpt.4 lxtphy.4 luphy.4 \ maestro.4 mainbus.4 malo.4 maxds.4 maxrtc.4 maxtmp.4 mbg.4 midi.4 \ mii.4 mfi.4 \ - mfii.4 mlphy.4 moscom.4 mos.4 mpe.4 mpath.4 mpi.4 mpii.4 mpu.4 msk.4 \ - mpw.4 msts.4 mtd.4 mtdphy.4 multicast.4 mtio.4 myx.4 \ + mfii.4 mlphy.4 mobileip.4 moscom.4 mos.4 mpe.4 mpath.4 mpi.4 mpii.4 \ + mpu.4 msk.4 mpw.4 msts.4 mtd.4 mtdphy.4 multicast.4 mtio.4 myx.4 \ ne.4 neo.4 nep.4 netintro.4 nfe.4 nge.4 nmea.4 \ nsclpcsio.4 nsgphy.4 nsphy.4 nsphyter.4 null.4 nviic.4 nvme.4 nvt.4 \ oce.4 ohci.4 options.4 onewire.4 oosiop.4 osiop.4 otus.4 \ diff --git a/share/man/man4/gre.4 b/share/man/man4/gre.4 index ad8dbf749b7..ffa4a017dcf 100644 --- a/share/man/man4/gre.4 +++ b/share/man/man4/gre.4 @@ -1,4 +1,4 @@ -.\" $OpenBSD: gre.4,v 1.49 2018/01/12 04:36:44 deraadt Exp $ +.\" $OpenBSD: gre.4,v 1.50 2018/02/07 01:09:57 dlg Exp $ .\" $NetBSD: gre.4,v 1.10 1999/12/22 14:55:49 kleink Exp $ .\" .\" Copyright 1998 (c) The NetBSD Foundation, Inc. @@ -28,25 +28,23 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: January 12 2018 $ +.Dd $Mdocdate: February 7 2018 $ .Dt GRE 4 .Os .Sh NAME -.Nm gre , -.Nm mobileip +.Nm gre .Nd encapsulating network device .Sh SYNOPSIS .Cd "pseudo-device gre" .Sh DESCRIPTION The .Nm -driver allows tunnel construction using the Cisco GRE or -the Mobile IP (RFC 2004) encapsulation protocols. +driver allows tunnel construction using the GRE (RFC 1701) +encapsulation protocol. .Pp -.Tn GRE , -.Tn WCCPv1 , +.Tn GRE and -.Tn Mobile IP +.Tn WCCPv1 are enabled with the following .Xr sysctl 2 variables respectively in @@ -64,13 +62,8 @@ to do anything useful with these packets. This sysctl requires .Va gre.allow to be set. -.It Va net.inet.mobileip.allow -Allow Mobile IP packets in and out of the system. .El .Pp -This driver currently supports the following modes of operation: -.Bl -tag -width mobileipXXX -.It Nm gre GRE datagrams (IP protocol number 47) are prepended by an outer datagram and a GRE header. The GRE header specifies the type of the encapsulated datagram @@ -80,18 +73,9 @@ GRE mode is the default tunnel mode on Cisco routers. This is also the default mode of operation of the .Nm interfaces. -.It Nm mobileip -MOBILE datagrams (IP protocol number 55) -are encapsulated into IP, but with a much smaller -encapsulation header. -This protocol only supports IP in IP encapsulation, and is intended -for use with Mobile IP. -.El .Pp A .Nm gre -or -.Nm mobileip interface can be created at runtime using the .Ic ifconfig gre Ns Ar N Ic create command or by setting up a @@ -228,13 +212,6 @@ pass quick on gre proto gre no state .Re .Pp .Rs -.%A C. Perkins -.%D October 1996 -.%R RFC 2004 -.%T Minimal Encapsulation within IP -.Re -.Pp -.Rs .%U https://tools.ietf.org/html/draft-ietf-wrec-web-pro-00.txt .%T Web Cache Coordination Protocol V1.0 .Re diff --git a/share/man/man4/mobileip.4 b/share/man/man4/mobileip.4 new file mode 100644 index 00000000000..386dd038930 --- /dev/null +++ b/share/man/man4/mobileip.4 @@ -0,0 +1,139 @@ +.\" $OpenBSD: mobileip.4,v 1.1 2018/02/07 01:09:57 dlg Exp $ +.\" +.\" Copyright (c) 2018 David Gwynne +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: February 7 2018 $ +.Dt MOBILEIP 4 +.Sh NAME +.Nm mobileip +.Nd MobileIP encapsulating network device +.Sh SYNOPSIS +.Cd "pseudo-device mobileip" +.Sh DESCRIPTION +The +.Nm +driver provides IP tunnel construction using +the Mobile IP (RFC 2004) encapsulation protocol +.Pp +.Nm +datagrams (IP protocol number 55) +are encapsulated into IP using a small encapsulation header. +This protocol according to the RFC only supports encapsulating IPv4, +and is intended for use with Mobile IP. +.Pp +A +.Nm +interface can be created at runtime using the +.Ic ifconfig Nm Ns Ar N Ic create +command or by setting up a +.Xr hostname.if 5 +configuration file for +.Xr netstart 8 . +.Pp +The MTU is set to 1488 by default. +This may not be an optimal value +depending on the link between the two tunnel endpoints, +but it can be adjusted via +.Xr ifconfig 8 . +.Pp +For correct operation, the route to the tunnel destination must not +go over the interface itself. +This can be implemented by adding a distinct or a more specific +route to the tunnel destination than the hosts or networks routed +via the tunnel interface. +Alternatively, the tunnel traffic may be configured in a separate +routing table to the encapsulated traffic. +.Pp +.Nm +interfaces support the following +.Xr ioctl 2 Ns s +for configuring tunnel options: +.Bl -tag -width indent -offset 3n +.It Dv SIOCSLIFPHYADDR Fa "struct if_laddrreq *" +Set the addresses of the outer IP header. +The addresses may only be configured while the interface is down. +.It Dv SIOCGLIFPHYADDR Fa "struct if_laddrreq *" +Get the addresses of the outer IP header. +.It Dv SIOCDIFPHYADDR +Clear the outer IP header addresses. +The addresses may only be cleared while the interface is down. +.It Dv SIOCSLIFPHYRTABLE Fa "struct ifreq *" +Set the routing table the encapsulated IP packets operate within. +The routing table may only be configured while the interface is down. +.It Dv SIOCGLIFPHYRTABLE Fa "struct ifreq *" +Get the routing table the encapsulated IP packets operate within. +.El +.Sh EXAMPLES +Configuration example: +.Bd -literal +Host X --- Host A ----------- MobileIP ------------ Host D --- Host E + \e / + \e / + +------ Host B ------ Host C ------+ +.Ed +.Pp +On Host A +.Pq Ox : +.Bd -literal -offset indent +# route add default B +# ifconfig mobileipN create +# ifconfig mobileipN tunnel A D +# ifconfig mobileipN A D netmask 255.255.255.255 +# route add E D +.Ed +.Pp +On Host D +.Pq Ox : +.Bd -literal -offset indent +# route add default C +# ifconfig mobileipN create +# ifconfig mobileipN tunnel D A +# ifconfig mobileipN D A netmask 255.255.255.255 +# route add D E +.Ed +.Pp +The route domain used for the encapsulated traffic may be set using +.Xr ifconfig 8 +and the tunneldomain argument: +.Bd -literal -offset indent +# ifconfig mobileipN tunneldomain 1 +.Ed +.Sh SEE ALSO +.Xr inet 4 , +.Xr ip 4 , +.Xr netintro 4 , +.Xr options 4 , +.Xr hostname.if 5 , +.Xr protocols 5 , +.Xr ifconfig 8 , +.Xr netstart 8 +.Sh STANDARDS +.Rs +.Re +The C. Perkins +.%D October 1996 +.%R RFC 2004 +.%T Minimal Encapsulation within IP +.Re +.Sh HISTORY +Support for the MobileIP protocol was originally implemented as part of the +.Xr gre 4 +driver. +The +.Nm +driver was split off from +.Xr gre 4 +in +.Ox 6.3 . diff --git a/sys/conf/GENERIC b/sys/conf/GENERIC index ff356c01069..9945a24c9e1 100644 --- a/sys/conf/GENERIC +++ b/sys/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.250 2017/10/25 12:38:21 job Exp $ +# $OpenBSD: GENERIC,v 1.251 2018/02/07 01:09:57 dlg Exp $ # # Machine-independent option; used by all architectures for their # GENERIC kernel @@ -17,7 +17,6 @@ option PTRACE # ptrace(2) system call #option WITNESS # witness(4) lock checker #option KVA_GUARDPAGES # slow virtual address recycling (+ guarding) -option POOL_DEBUG # pool corruption detection #option VFSLCKDEBUG # VFS locking checks option CRYPTO # Cryptographic framework @@ -90,6 +89,7 @@ pseudo-device carp # CARP protocol support pseudo-device etherip # EtherIP (RFC 3378) pseudo-device gif # IPv[46] over IPv[46] tunnel (RFC1933) pseudo-device gre # GRE encapsulation interface +pseudo-device mobileip # MobileIP encapsulation interface pseudo-device loop # network loopback pseudo-device mpe # MPLS PE interface pseudo-device mpw # MPLS pseudowire support diff --git a/sys/conf/files b/sys/conf/files index f623c4101e3..d8cc6a02a6b 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $OpenBSD: files,v 1.657 2018/02/06 23:44:48 henning Exp $ +# $OpenBSD: files,v 1.658 2018/02/07 01:09:57 dlg Exp $ # $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -551,6 +551,7 @@ pseudo-device carp: ifnet, ether pseudo-device sppp: ifnet pseudo-device gif: ifnet pseudo-device gre: ifnet +pseudo-device mobileip: ifnet pseudo-device crypto: ifnet pseudo-device trunk: ifnet, ether, ifmedia pseudo-device mpe: ifnet, ether @@ -799,6 +800,7 @@ file net/rtsock.c file net/slcompress.c ppp file net/if_enc.c enc needs-count file net/if_gre.c gre needs-count +file net/if_mobileip.c mobileip needs-count file net/if_trunk.c trunk needs-count file net/trunklacp.c trunk file net/if_mpe.c mpe needs-count diff --git a/sys/net/if_mobileip.c b/sys/net/if_mobileip.c new file mode 100644 index 00000000000..80a111adc05 --- /dev/null +++ b/sys/net/if_mobileip.c @@ -0,0 +1,637 @@ +/* $OpenBSD: if_mobileip.c,v 1.1 2018/02/07 01:09:57 dlg Exp $ */ + +/* + * Copyright (c) 2016 David Gwynne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "mobileip.h" + +#include "bpfilter.h" +#include "pf.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#if NBPFILTER > 0 +#include +#endif + +#if NPF > 0 +#include +#endif + +#include + +struct mobileip_softc { + struct ifnet sc_if; + + RBT_ENTRY(mobileip_softc) + sc_entry; + + unsigned int sc_rtableid; + uint32_t sc_src; + uint32_t sc_dst; +}; + +static int mobileip_clone_create(struct if_clone *, int); +static int mobileip_clone_destroy(struct ifnet *); + +static struct if_clone mobileip_cloner = IF_CLONE_INITIALIZER("mobileip", + mobileip_clone_create, mobileip_clone_destroy); + +RBT_HEAD(mobileip_tree, mobileip_softc); + +static inline int + mobileip_cmp(const struct mobileip_softc *, + const struct mobileip_softc *); + +RBT_PROTOTYPE(mobileip_tree, mobileip_softc, sc_entry, mobileip_cmp); + +struct mobileip_tree mobileip_softcs = RBT_INITIALIZER(); + +#define MOBILEIPMTU (1500 - (sizeof(struct mobileip_header) + \ + sizeof(struct mobileip_h_src))) \ + +static int mobileip_ioctl(struct ifnet *, u_long, caddr_t); +static int mobileip_up(struct mobileip_softc *); +static int mobileip_down(struct mobileip_softc *); +static int mobileip_set_tunnel(struct mobileip_softc *, + struct if_laddrreq *); +static int mobileip_get_tunnel(struct mobileip_softc *, + struct if_laddrreq *); +static int mobileip_del_tunnel(struct mobileip_softc *); + +static int mobileip_output(struct ifnet *, struct mbuf *, + struct sockaddr *, struct rtentry *); +static void mobileip_start(struct ifnet *); +static int mobileip_encap(struct mobileip_softc *, struct mbuf *); + +/* + * let's begin + */ + +int mobileip_allow = 0; + +void +mobileipattach(int n) +{ + if_clone_attach(&mobileip_cloner); +} + +int +mobileip_clone_create(struct if_clone *ifc, int unit) +{ + struct mobileip_softc *sc; + + sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT|M_ZERO); + if (!sc) + return (ENOMEM); + + sc->sc_rtableid = 0; + sc->sc_src = INADDR_ANY; + sc->sc_dst = INADDR_ANY; + + snprintf(sc->sc_if.if_xname, sizeof sc->sc_if.if_xname, "%s%d", + ifc->ifc_name, unit); + sc->sc_if.if_softc = sc; + sc->sc_if.if_type = IFT_TUNNEL; + sc->sc_if.if_addrlen = 0; + sc->sc_if.if_mtu = MOBILEIPMTU; + sc->sc_if.if_flags = IFF_POINTOPOINT|IFF_MULTICAST; + sc->sc_if.if_output = mobileip_output; + sc->sc_if.if_start = mobileip_start; + sc->sc_if.if_ioctl = mobileip_ioctl; + sc->sc_if.if_rtrequest = p2p_rtrequest; + + if_attach(&sc->sc_if); + if_alloc_sadl(&sc->sc_if); + +#if NBPFILTER > 0 + bpfattach(&sc->sc_if.if_bpf, &sc->sc_if, DLT_LOOP, sizeof(uint32_t)); +#endif + + return (0); +} + +int +mobileip_clone_destroy(struct ifnet *ifp) +{ + struct mobileip_softc *sc = ifp->if_softc; + + if_detach(ifp); + + free(sc, M_DEVBUF, sizeof(*sc)); + + return (0); +} + +/* + * do a checksum of a header. + * + * assumes len is aligned correctly, and not an odd number of bytes. + */ +static inline uint16_t +mobileip_cksum(const void *buf, size_t len) +{ + const uint16_t *p = buf; + uint32_t sum = 0; + + do { + sum += bemtoh16(p++); + } while (len -= 2); + + /* end-around-carry */ + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + return (~sum); +} + +static inline int +mobileip_cmp(const struct mobileip_softc *a, const struct mobileip_softc *b) +{ + if (a->sc_src > b->sc_src) + return (1); + if (a->sc_src < b->sc_src) + return (-1); + + if (a->sc_dst > b->sc_dst) + return (1); + if (a->sc_dst < b->sc_dst) + return (-1); + + if (a->sc_rtableid > b->sc_rtableid) + return (1); + if (a->sc_rtableid < b->sc_rtableid) + return (-1); + + return (0); +} + +static int +mobileip_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, + struct rtentry *rt) +{ + struct m_tag *mtag; + int error = 0; + + if (!mobileip_allow) { + m_freem(m); + error = EACCES; + goto end; + } + + if (!ISSET(ifp->if_flags, IFF_RUNNING)) { + m_freem(m); + error = ENETDOWN; + goto end; + } + + if (dst->sa_family != AF_INET) { + m_freem(m); + error = EAFNOSUPPORT; + goto end; + } + + /* Try to limit infinite recursion through misconfiguration. */ + for (mtag = m_tag_find(m, PACKET_TAG_GRE, NULL); mtag; + mtag = m_tag_find(m, PACKET_TAG_GRE, mtag)) { + if (memcmp(mtag + 1, &ifp->if_index, + sizeof(ifp->if_index)) == 0) { + m_freem(m); + error = EIO; + goto end; + } + } + + mtag = m_tag_get(PACKET_TAG_GRE, sizeof(ifp->if_index), M_NOWAIT); + if (mtag == NULL) { + m_freem(m); + error = ENOBUFS; + goto end; + } + memcpy(mtag + 1, &ifp->if_index, sizeof(ifp->if_index)); + m_tag_prepend(m, mtag); + + error = if_enqueue(ifp, m); + end: + if (error) + ifp->if_oerrors++; + return (error); +} + +static void +mobileip_start(struct ifnet *ifp) +{ + struct mobileip_softc *sc = ifp->if_softc; + struct mbuf *m; + + while ((m = ifq_dequeue(&ifp->if_snd)) != NULL) { +#if NBPFILTER > 0 + if (ifp->if_bpf) + bpf_mtap_af(ifp->if_bpf, AF_INET, m, BPF_DIRECTION_OUT); +#endif + + if (mobileip_encap(sc, m) != 0) + ifp->if_oerrors++; + } +} + +static int +mobileip_encap(struct mobileip_softc *sc, struct mbuf *m) +{ + struct ip *ip; + struct mobileip_header *mh; + struct mobileip_h_src *msh; + caddr_t hdr; + int iphlen, hlen; + + /* look at the current IP header */ + m = m_pullup(m, sizeof(*ip)); + if (m == NULL) + return (ENOBUFS); + + /* figure out how long it is */ + ip = mtod(m, struct ip *); + iphlen = ip->ip_hl << 2; + + /* figure out how much extra space we'll need */ + hlen = sizeof(*mh); + if (ip->ip_src.s_addr != sc->sc_src) + hlen += sizeof(*msh); + + /* add the space */ + m = m_prepend(m, hlen, M_DONTWAIT); + if (m == NULL) + return (ENOBUFS); + + /* make the IP and mobileip headers contig */ + m = m_pullup(m, iphlen + hlen); + if (m == NULL) + return (ENOBUFS); + + /* move the IP header to the front */ + hdr = mtod(m, caddr_t); + memmove(hdr, hdr + hlen, iphlen); + + /* fill in the headers */ + ip = (struct ip *)hdr; + mh = (struct mobileip_header *)(hdr + iphlen); + mh->mip_proto = ip->ip_p; + mh->mip_flags = 0; + mh->mip_hcrc = 0; + mh->mip_dst = ip->ip_dst.s_addr; + + if (ip->ip_src.s_addr != sc->sc_src) { + mh->mip_flags |= MOBILEIP_SP; + + msh = (struct mobileip_h_src *)(mh + 1); + msh->mip_src = ip->ip_src.s_addr; + + ip->ip_src.s_addr = sc->sc_src; + } + + htobem16(&mh->mip_hcrc, mobileip_cksum(mh, hlen)); + + ip->ip_p = IPPROTO_MOBILE; + htobem16(&ip->ip_len, bemtoh16(&ip->ip_len) + hlen); + ip->ip_dst.s_addr = sc->sc_dst; + + m->m_flags &= ~(M_BCAST|M_MCAST); + m->m_pkthdr.ph_rtableid = sc->sc_rtableid; + +#if NPF > 0 + pf_pkt_addr_changed(m); +#endif + + ip_send(m); + + return (0); +} + +int +mobileip_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) +{ + struct mobileip_softc *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *)data; + int error = 0; + + switch(cmd) { + case SIOCSIFADDR: + /* XXX restrict to AF_INET */ + ifp->if_flags |= IFF_UP; + /* FALLTHROUGH */ + case SIOCSIFFLAGS: + if (ISSET(ifp->if_flags, IFF_UP)) { + if (!ISSET(ifp->if_flags, IFF_RUNNING)) + error = mobileip_up(sc); + else + error = ENETRESET; + } else { + if (ISSET(ifp->if_flags, IFF_RUNNING)) + error = mobileip_down(sc); + } + break; + case SIOCSIFDSTADDR: + break; + case SIOCSIFMTU: + if (ifr->ifr_mtu < 576) { + error = EINVAL; + break; + } + ifp->if_mtu = ifr->ifr_mtu; + break; + case SIOCGIFMTU: + ifr->ifr_mtu = sc->sc_if.if_mtu; + break; + case SIOCADDMULTI: + case SIOCDELMULTI: + break; + + case SIOCSLIFPHYADDR: + error = mobileip_set_tunnel(sc, (struct if_laddrreq *)data); + break; + case SIOCGLIFPHYADDR: + error = mobileip_get_tunnel(sc, (struct if_laddrreq *)data); + break; + case SIOCDIFPHYADDR: + error = mobileip_del_tunnel(sc); + break; + + case SIOCSLIFPHYRTABLE: + if (ISSET(ifp->if_flags, IFF_RUNNING)) { + error = EBUSY; + break; + } + + if (ifr->ifr_rdomainid < 0 || + ifr->ifr_rdomainid > RT_TABLEID_MAX || + !rtable_exists(ifr->ifr_rdomainid)) { + error = EINVAL; + break; + } + sc->sc_rtableid = ifr->ifr_rdomainid; + break; + case SIOCGLIFPHYRTABLE: + ifr->ifr_rdomainid = sc->sc_rtableid; + break; + + default: + error = ENOTTY; + break; + } + + return (error); +} + +static int +mobileip_up(struct mobileip_softc *sc) +{ + struct mobileip_softc *osc; + + if (sc->sc_dst == INADDR_ANY) + return (EDESTADDRREQ); + + NET_ASSERT_LOCKED(); + osc = RBT_INSERT(mobileip_tree, &mobileip_softcs, sc); + if (osc != NULL) + return (EADDRINUSE); + + SET(sc->sc_if.if_flags, IFF_RUNNING); + + return (0); +} + +static int +mobileip_down(struct mobileip_softc *sc) +{ + NET_ASSERT_LOCKED(); + RBT_REMOVE(mobileip_tree, &mobileip_softcs, sc); + + CLR(sc->sc_if.if_flags, IFF_RUNNING); + + ifq_barrier(&sc->sc_if.if_snd); + + return (0); +} + +static int +mobileip_set_tunnel(struct mobileip_softc *sc, struct if_laddrreq *req) +{ + struct sockaddr_in *src = (struct sockaddr_in *)&req->addr; + struct sockaddr_in *dst = (struct sockaddr_in *)&req->dstaddr; + + if (ISSET(sc->sc_if.if_flags, IFF_RUNNING)) + return (EBUSY); + + /* sa_family and sa_len must be equal */ + if (src->sin_family != dst->sin_family || src->sin_len != dst->sin_len) + return (EINVAL); + + if (dst->sin_family != AF_INET) + return (EAFNOSUPPORT); + if (dst->sin_len != sizeof(*dst)) + return (EINVAL); + + if (in_nullhost(src->sin_addr) || + IN_MULTICAST(src->sin_addr.s_addr) || + in_nullhost(dst->sin_addr) || + IN_MULTICAST(dst->sin_addr.s_addr)) + return (EINVAL); + + /* commit */ + sc->sc_src = src->sin_addr.s_addr; + sc->sc_dst = dst->sin_addr.s_addr; + + return (0); +} + +static int +mobileip_get_tunnel(struct mobileip_softc *sc, struct if_laddrreq *req) +{ + struct sockaddr_in *src = (struct sockaddr_in *)&req->addr; + struct sockaddr_in *dst = (struct sockaddr_in *)&req->dstaddr; + + if (sc->sc_dst == INADDR_ANY) + return (EADDRNOTAVAIL); + + memset(src, 0, sizeof(*src)); + src->sin_family = AF_INET; + src->sin_len = sizeof(*src); + src->sin_addr.s_addr = sc->sc_src; + + memset(dst, 0, sizeof(*dst)); + dst->sin_family = AF_INET; + dst->sin_len = sizeof(*dst); + dst->sin_addr.s_addr = sc->sc_dst; + + return (0); +} + +static int +mobileip_del_tunnel(struct mobileip_softc *sc) +{ + if (ISSET(sc->sc_if.if_flags, IFF_RUNNING)) + return (EBUSY); + + /* commit */ + sc->sc_src = INADDR_ANY; + sc->sc_dst = INADDR_ANY; + + return (0); +} + +int +mobileip_input(struct mbuf **mp, int *offp, int type, int af) +{ + struct mobileip_softc key; + struct mbuf *m = *mp; + struct ifnet *ifp; + struct mobileip_softc *sc; + caddr_t hdr; + struct ip *ip; + struct mobileip_header *mh; + struct mobileip_h_src *msh; + int iphlen = 0; + int hlen; + + if (!mobileip_allow) + goto drop; + + ip = mtod(m, struct ip *); + + key.sc_rtableid = m->m_pkthdr.ph_rtableid; + key.sc_src = ip->ip_dst.s_addr; + key.sc_dst = ip->ip_src.s_addr; + + /* NET_ASSERT_READ_LOCKED() */ + sc = RBT_FIND(mobileip_tree, &mobileip_softcs, &key); + if (sc == NULL) + goto drop; + + /* it's ours now, we can do what we want */ + + iphlen = ip->ip_hl << 2; + hlen = sizeof(*mh); + m = m_pullup(m, iphlen + hlen); + if (m == NULL) + return (IPPROTO_DONE); + + hdr = mtod(m, caddr_t); + ip = (struct ip *)hdr; + mh = (struct mobileip_header *)(hdr + iphlen); + + if (mh->mip_flags & ~MOBILEIP_SP) + goto drop; + + if (ISSET(mh->mip_flags, MOBILEIP_SP)) { + hlen += sizeof(*msh); + m = m_pullup(m, iphlen + hlen); + if (m == NULL) + return (IPPROTO_DONE); + + hdr = mtod(m, caddr_t); + ip = (struct ip *)hdr; + mh = (struct mobileip_header *)(hdr + iphlen); + msh = (struct mobileip_h_src *)(mh + 1); + + ip->ip_src.s_addr = msh->mip_src; + } + + if (mobileip_cksum(mh, hlen) != 0) + goto drop; + + ip->ip_p = mh->mip_proto; + htobem16(&ip->ip_len, bemtoh16(&ip->ip_len) - hlen); + ip->ip_dst.s_addr = mh->mip_dst; + + memmove(hdr + hlen, hdr, iphlen); + m_adj(m, hlen); + + ifp = &sc->sc_if; + + CLR(m->m_flags, M_MCAST|M_BCAST); + SET(m->m_pkthdr.csum_flags, M_IPV4_CSUM_IN_OK); + m->m_pkthdr.ph_ifidx = ifp->if_index; + m->m_pkthdr.ph_rtableid = ifp->if_rdomain; + +#if NPF > 0 + pf_pkt_addr_changed(m); +#endif + + ifp->if_ipackets++; + ifp->if_ibytes += m->m_pkthdr.len; + +#if NBPFILTER > 0 + if (ifp->if_bpf) + bpf_mtap_af(ifp->if_bpf, AF_INET, m, BPF_DIRECTION_IN); +#endif + + ipv4_input(ifp, m); + + return (IPPROTO_DONE); + +drop: + m_freem(m); + return (IPPROTO_DONE); +} + +#include +#include + +int +mobileip_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, + void *newp, size_t newlen) +{ + int allow; + int error; + + /* All sysctl names at this level are terminal. */ + if (namelen != 1) + return (ENOTDIR); + + switch (name[0]) { + case MOBILEIPCTL_ALLOW: + allow = mobileip_allow; + + error = sysctl_int(oldp, oldlenp, newp, newlen, + &allow); + if (error != 0) + return (error); + + mobileip_allow = allow; + break; + default: + return (ENOPROTOOPT); + } + + return (0); +} + +RBT_GENERATE(mobileip_tree, mobileip_softc, sc_entry, mobileip_cmp); diff --git a/sys/net/if_mobileip.h b/sys/net/if_mobileip.h new file mode 100644 index 00000000000..1055f36a254 --- /dev/null +++ b/sys/net/if_mobileip.h @@ -0,0 +1,41 @@ +/* $OpenBSD: if_mobileip.h,v 1.1 2018/02/07 01:09:57 dlg Exp $ */ + +/* + * Copyright (c) 2016 David Gwynne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _NET_IF_MOBILEIP_H +#define _NET_IF_MOBILEIP_H + +struct mobileip_header { + uint8_t mip_proto; /* original protocol */ + uint8_t mip_flags; +#define MOBILEIP_SP 0x80 /* src address is present */ + uint16_t mip_hcrc; /* header checksum */ + uint32_t mip_dst; /* original dst address */ +} __packed __aligned(4); + +struct mobileip_h_src { + uint32_t mip_src; /* original src address */ +} __packed __aligned(4); + +#ifdef _KERNEL +void mobileipattach(int); +int mobileip_input(struct mbuf **, int *, int, int); +int mobileip_sysctl(int *, u_int, void *, size_t *, + void *, size_t); +#endif /* _KERNEL */ + +#endif /* _NET_IF_MOBILEIP_H_ */ diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c index 697b95c66e4..54ad512571d 100644 --- a/sys/netinet/in_proto.c +++ b/sys/netinet/in_proto.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in_proto.c,v 1.88 2017/11/23 13:45:46 mpi Exp $ */ +/* $OpenBSD: in_proto.c,v 1.89 2018/02/07 01:09:57 dlg Exp $ */ /* $NetBSD: in_proto.c,v 1.14 1996/02/18 18:58:32 christos Exp $ */ /* @@ -172,6 +172,11 @@ #include #endif +#include "mobileip.h" +#if NMOBILEIP > 0 +#include +#endif + u_char ip_protox[IPPROTO_MAX]; const struct protosw inetsw[] = { @@ -348,19 +353,21 @@ const struct protosw inetsw[] = { .pr_detach = rip_detach, .pr_sysctl = gre_sysctl }, +#endif /* NGRE > 0 */ +#if NMOBILEIP > 0 { .pr_type = SOCK_RAW, .pr_domain = &inetdomain, .pr_protocol = IPPROTO_MOBILE, .pr_flags = PR_ATOMIC|PR_ADDR, - .pr_input = gre_mobile_input, + .pr_input = mobileip_input, .pr_ctloutput = rip_ctloutput, .pr_usrreq = rip_usrreq, .pr_attach = rip_attach, .pr_detach = rip_detach, - .pr_sysctl = ipmobile_sysctl + .pr_sysctl = mobileip_sysctl }, -#endif /* NGRE > 0 */ +#endif /* NMOBILEIP > 0 */ #if NCARP > 0 { .pr_type = SOCK_RAW, diff --git a/sys/netinet/ip_gre.c b/sys/netinet/ip_gre.c index 0dba2339b21..5dad1d88d38 100644 --- a/sys/netinet/ip_gre.c +++ b/sys/netinet/ip_gre.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_gre.c,v 1.69 2018/01/09 06:24:15 dlg Exp $ */ +/* $OpenBSD: ip_gre.c,v 1.70 2018/02/07 01:09:57 dlg Exp $ */ /* $NetBSD: ip_gre.c,v 1.9 1999/10/25 19:18:11 drochner Exp $ */ /* @@ -260,93 +260,6 @@ gre_input(struct mbuf **mp, int *offp, int proto, int af) return IPPROTO_DONE; } -/* - * Input routine for IPPROTO_MOBILE. - * This is a little bit different from the other modes, as the - * encapsulating header was not prepended, but instead inserted - * between IP header and payload. - */ - -int -gre_mobile_input(struct mbuf **mp, int *offp, int proto, int af) -{ - struct mbuf *m = *mp; - struct ip *ip; - struct mobip_h *mip; - struct gre_softc *sc; - u_char osrc = 0; - int msiz; - - if (!ip_mobile_allow) { - m_freem(m); - return IPPROTO_DONE; - } - - if ((sc = gre_lookup(m, proto)) == NULL) { - /* No matching tunnel or tunnel is down. */ - m_freem(m); - return IPPROTO_DONE; - } - - if (m->m_len < sizeof(*mip)) { - m = *mp = m_pullup(m, sizeof(*mip)); - if (m == NULL) - return IPPROTO_DONE; - } - ip = mtod(m, struct ip *); - mip = mtod(m, struct mobip_h *); - - m->m_pkthdr.ph_ifidx = sc->sc_if.if_index; - - sc->sc_if.if_ipackets++; - sc->sc_if.if_ibytes += m->m_pkthdr.len; - - if (ntohs(mip->mh.proto) & MOB_H_SBIT) { - osrc = 1; - msiz = MOB_H_SIZ_L; - mip->mi.ip_src.s_addr = mip->mh.osrc; - } else - msiz = MOB_H_SIZ_S; - - if (m->m_len < (ip->ip_hl << 2) + msiz) { - m = *mp = m_pullup(m, (ip->ip_hl << 2) + msiz); - if (m == NULL) - return IPPROTO_DONE; - ip = mtod(m, struct ip *); - mip = mtod(m, struct mobip_h *); - } - - mip->mi.ip_dst.s_addr = mip->mh.odst; - mip->mi.ip_p = (ntohs(mip->mh.proto) >> 8); - - if (gre_in_cksum((u_short *) &mip->mh, msiz) != 0) { - m_freem(m); - return IPPROTO_DONE; - } - - memmove(ip + (ip->ip_hl << 2), ip + (ip->ip_hl << 2) + msiz, - m->m_len - msiz - (ip->ip_hl << 2)); - - m->m_len -= msiz; - ip->ip_len = htons(ntohs(ip->ip_len) - msiz); - m->m_pkthdr.len -= msiz; - - ip->ip_sum = 0; - ip->ip_sum = in_cksum(m,(ip->ip_hl << 2)); - -#if NBPFILTER > 0 - if (sc->sc_if.if_bpf) - bpf_mtap_af(sc->sc_if.if_bpf, AF_INET, m, BPF_DIRECTION_IN); -#endif - -#if NPF > 0 - pf_pkt_addr_changed(m); -#endif - - ipv4_input(&sc->sc_if, m); - return IPPROTO_DONE; -} - /* * Find the gre interface associated with our src/dst/proto set. */ @@ -397,29 +310,6 @@ gre_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, /* NOTREACHED */ } -int -ipmobile_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, - void *newp, size_t newlen) -{ - int error; - - /* All sysctl names at this level are terminal. */ - if (namelen != 1) - return (ENOTDIR); - - switch (name[0]) { - case MOBILEIPCTL_ALLOW: - NET_LOCK(); - error = sysctl_int(oldp, oldlenp, newp, newlen, - &ip_mobile_allow); - NET_UNLOCK(); - return (error); - default: - return (ENOPROTOOPT); - } - /* NOTREACHED */ -} - int gre_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, struct mbuf *control, struct proc *p) -- cgit v1.2.3