? share/man/man4/wi.4 ? share/man/man4/man4.hppa/cpu.4 Index: sys/net/if_gre.c =================================================================== RCS file: /cvs/src/sys/net/if_gre.c,v retrieving revision 1.122 diff -u -p -r1.122 if_gre.c --- sys/net/if_gre.c 12 Mar 2018 12:47:35 -0000 1.122 +++ sys/net/if_gre.c 27 May 2018 00:12:36 -0000 @@ -124,6 +124,13 @@ struct gre_h_key { uint32_t gre_key; } __packed __aligned(4); +#define GRE_EOIP 0x6400 + +struct gre_h_key_eoip { + uint16_t eoip_len; /* network order */ + uint16_t eoip_tunnel_id; /* little endian */ +} __packed __aligned(4); + #define NVGRE_VSID_RES_MIN 0x000000 /* reserved for future use */ #define NVGRE_VSID_RES_MAX 0x000fff #define NVGRE_VSID_NVE2NVE 0xffffff /* vendor specific NVE-to-NVE comms */ @@ -211,6 +218,12 @@ static struct mbuf * #define gre_encap(_t, _m, _p, _ttl, _tos) \ gre_encap_dst((_t), &(_t)->t_dst, (_m), (_p), (_ttl), (_tos)) +static struct mbuf * + gre_encap_dst_ip(const struct gre_tunnel *, + const union gre_addr *, struct mbuf *, uint8_t, uint8_t); +#define gre_encap_ip(_t, _m, _ttl, _tos) \ + gre_encap_dst_ip((_t), &(_t)->t_dst, (_m), (_ttl), (_tos)) + static int gre_ip_output(const struct gre_tunnel *, struct mbuf *); @@ -266,7 +279,7 @@ static int gre_ioctl(struct ifnet *, u_l static int gre_up(struct gre_softc *); static int gre_down(struct gre_softc *); -static void gre_link_state(struct gre_softc *); +static void gre_link_state(struct ifnet *, unsigned int); static int gre_input_key(struct mbuf **, int *, int, int, struct gre_tunnel *); @@ -457,6 +470,61 @@ struct nvgre_ucast_tree nvgre_ucast_tree struct nvgre_mcast_tree nvgre_mcast_tree = RBT_INITIALIZER(); /* + * MikroTik Ethernet over IP protocol (eoip) + */ + +struct eoip_softc { + struct gre_tunnel sc_tunnel; /* must be first */ + uint16_t sc_tunnel_id; + RBT_ENTRY(eoip_softc) sc_entry; + + struct arpcom sc_ac; + struct ifmedia sc_media; + + struct timeout sc_ka_send; + struct timeout sc_ka_hold; + + unsigned int sc_ka_state; + unsigned int sc_ka_timeo; + unsigned int sc_ka_count; + + unsigned int sc_ka_holdmax; + unsigned int sc_ka_holdcnt; +}; + +RBT_HEAD(eoip_tree, eoip_softc); + +static inline int + eoip_cmp(const struct eoip_softc *, const struct eoip_softc *); + +RBT_PROTOTYPE(eoip_tree, eoip_softc, sc_entry, eoip_cmp); + +static int eoip_clone_create(struct if_clone *, int); +static int eoip_clone_destroy(struct ifnet *); + +static void eoip_start(struct ifnet *); +static int eoip_ioctl(struct ifnet *, u_long, caddr_t); + +static void eoip_keepalive_send(void *); +static void eoip_keepalive_recv(struct eoip_softc *); +static void eoip_keepalive_hold(void *); + +static int eoip_up(struct eoip_softc *); +static int eoip_down(struct eoip_softc *); + +static struct mbuf * + eoip_encap(struct eoip_softc *, struct mbuf *, uint8_t); + +static struct mbuf * + eoip_input(struct gre_tunnel *, struct mbuf *, + const struct gre_header *, int); +struct if_clone eoip_cloner = + IF_CLONE_INITIALIZER("eoip", eoip_clone_create, eoip_clone_destroy); + +/* protected by NET_LOCK */ +struct eoip_tree eoip_tree = RBT_INITIALIZER(); + +/* * It is not easy to calculate the right value for a GRE MTU. * We leave this task to the admin and use the same default that * other vendors use. @@ -482,6 +550,7 @@ greattach(int n) if_clone_attach(&mgre_cloner); if_clone_attach(&egre_cloner); if_clone_attach(&nvgre_cloner); + if_clone_attach(&eoip_cloner); } static int @@ -725,6 +794,65 @@ nvgre_clone_destroy(struct ifnet *ifp) return (0); } +static int +eoip_clone_create(struct if_clone *ifc, int unit) +{ + struct eoip_softc *sc; + struct ifnet *ifp; + + sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); + ifp = &sc->sc_ac.ac_if; + + snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", + ifc->ifc_name, unit); + + ifp->if_softc = sc; + ifp->if_ioctl = eoip_ioctl; + ifp->if_start = eoip_start; + ifp->if_xflags = IFXF_CLONED; + IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ether_fakeaddr(ifp); + + sc->sc_tunnel.t_ttl = ip_defttl; + sc->sc_tunnel.t_df = htons(0); + + sc->sc_ka_timeo = 10; + sc->sc_ka_count = 10; + + timeout_set(&sc->sc_ka_send, eoip_keepalive_send, sc); + timeout_set_proc(&sc->sc_ka_hold, eoip_keepalive_hold, sc); + sc->sc_ka_state = GRE_KA_DOWN; + + ifmedia_init(&sc->sc_media, 0, egre_media_change, egre_media_status); + ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL); + ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO); + + if_attach(ifp); + ether_ifattach(ifp); + + return (0); +} + +static int +eoip_clone_destroy(struct ifnet *ifp) +{ + struct eoip_softc *sc = ifp->if_softc; + + NET_LOCK(); + if (ISSET(ifp->if_flags, IFF_RUNNING)) + eoip_down(sc); + NET_UNLOCK(); + + ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY); + ether_ifdetach(ifp); + if_detach(ifp); + + free(sc, M_DEVBUF, sizeof(*sc)); + + return (0); +} + int gre_input(struct mbuf **mp, int *offp, int type, int af) { @@ -802,6 +930,31 @@ mgre_find(const struct gre_tunnel *key) return (NULL); } +static struct mbuf * +gre_input_1(struct gre_tunnel *key, struct mbuf *m, + const struct gre_header *gh, int iphlen) +{ + switch (gh->gre_proto) { + case htons(ETHERTYPE_PPP): +#ifdef PIPEX + if (pipex_enable) { + struct pipex_session *session; + + session = pipex_pptp_lookup_session(m); + if (session != NULL && + pipex_pptp_input(m, session) == NULL) + return (NULL); + } +#endif + break; + case htons(GRE_EOIP): + return (eoip_input(key, m, gh, iphlen)); + break; + } + + return (m); +} + static int gre_input_key(struct mbuf **mp, int *offp, int type, int af, struct gre_tunnel *key) @@ -821,6 +974,8 @@ gre_input_key(struct mbuf **mp, int *off if (!gre_allow) goto decline; + key->t_rtableid = m->m_pkthdr.ph_rtableid; + hlen = iphlen + sizeof(*gh); if (m->m_pkthdr.len < hlen) goto decline; @@ -838,16 +993,9 @@ gre_input_key(struct mbuf **mp, int *off break; case htons(GRE_VERS_1): -#ifdef PIPEX - if (pipex_enable) { - struct pipex_session *session; - - session = pipex_pptp_lookup_session(m); - if (session != NULL && - pipex_pptp_input(m, session) == NULL) - return (IPPROTO_DONE); - } -#endif + m = gre_input_1(key, m, gh, iphlen); + if (m == NULL) + return (IPPROTO_DONE); /* FALLTHROUGH */ default: goto decline; @@ -875,8 +1023,6 @@ gre_input_key(struct mbuf **mp, int *off } else key->t_key_mask = GRE_KEY_NONE; - key->t_rtableid = m->m_pkthdr.ph_rtableid; - if (gh->gre_proto == htons(ETHERTYPE_TRANSETHER)) { if (egre_input(key, m, hlen) == -1 && nvgre_input(key, m, hlen) == -1) @@ -1381,7 +1527,7 @@ gre_keepalive_recv(struct ifnet *ifp, st break; sc->sc_ka_state = GRE_KA_UP; - gre_link_state(sc); + gre_link_state(&sc->sc_if, sc->sc_ka_state); break; case GRE_KA_UP: @@ -1815,6 +1961,13 @@ gre_encap_dst(const struct gre_tunnel *t } } + return (gre_encap_dst_ip(tunnel, dst, m, ttl, tos)); +} + +static struct mbuf * +gre_encap_dst_ip(const struct gre_tunnel *tunnel, const union gre_addr *dst, + struct mbuf *m, uint8_t ttl, uint8_t tos) +{ switch (tunnel->t_af) { case AF_INET: { struct ip *ip; @@ -2446,6 +2599,140 @@ nvgre_ioctl(struct ifnet *ifp, u_long cm } static int +eoip_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) +{ + struct eoip_softc *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *)data; + struct ifkalivereq *ikar = (struct ifkalivereq *)data; + int error = 0; + + switch(cmd) { + case SIOCSIFADDR: + break; + case SIOCSIFFLAGS: + if (ISSET(ifp->if_flags, IFF_UP)) { + if (!ISSET(ifp->if_flags, IFF_RUNNING)) + error = eoip_up(sc); + else + error = 0; + } else { + if (ISSET(ifp->if_flags, IFF_RUNNING)) + error = eoip_down(sc); + } + break; + + case SIOCSETKALIVE: + if (ISSET(ifp->if_flags, IFF_RUNNING)) { + error = EBUSY; + break; + } + + if (ikar->ikar_timeo < 0 || ikar->ikar_timeo > 86400 || + ikar->ikar_cnt < 0 || ikar->ikar_cnt > 256) + return (EINVAL); + + if (ikar->ikar_timeo == 0 || ikar->ikar_cnt == 0) { + sc->sc_ka_count = 0; + sc->sc_ka_timeo = 0; + sc->sc_ka_state = GRE_KA_NONE; + } else { + sc->sc_ka_count = ikar->ikar_cnt; + sc->sc_ka_timeo = ikar->ikar_timeo; + sc->sc_ka_state = GRE_KA_DOWN; + } + break; + + case SIOCGETKALIVE: + ikar->ikar_cnt = sc->sc_ka_count; + ikar->ikar_timeo = sc->sc_ka_timeo; + break; + + case SIOCSVNETID: + if (ISSET(ifp->if_flags, IFF_RUNNING)) { + error = EBUSY; + break; + } + if (ifr->ifr_vnetid < 0 || ifr->ifr_vnetid > 0xffff) + return (EINVAL); + + sc->sc_tunnel.t_key = htole16(ifr->ifr_vnetid); /* for cmp */ + sc->sc_tunnel_id = htole16(ifr->ifr_vnetid); + break; + + case SIOCGVNETID: + ifr->ifr_vnetid = letoh16(sc->sc_tunnel_id); + break; + + case SIOCSLIFPHYADDR: + if (ISSET(ifp->if_flags, IFF_RUNNING)) { + error = EBUSY; + break; + } + + error = gre_set_tunnel(&sc->sc_tunnel, + (struct if_laddrreq *)data, 1); + break; + case SIOCGLIFPHYADDR: + error = gre_get_tunnel(&sc->sc_tunnel, + (struct if_laddrreq *)data); + break; + case SIOCDIFPHYADDR: + if (ISSET(ifp->if_flags, IFF_RUNNING)) { + error = EBUSY; + break; + } + + error = gre_del_tunnel(&sc->sc_tunnel); + 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_tunnel.t_rtableid = ifr->ifr_rdomainid; + break; + case SIOCGLIFPHYRTABLE: + ifr->ifr_rdomainid = sc->sc_tunnel.t_rtableid; + break; + + case SIOCSLIFPHYTTL: + if (ifr->ifr_ttl < 1 || ifr->ifr_ttl > 0xff) { + error = EINVAL; + break; + } + + /* commit */ + sc->sc_tunnel.t_ttl = (uint8_t)ifr->ifr_ttl; + break; + case SIOCGLIFPHYTTL: + ifr->ifr_ttl = (int)sc->sc_tunnel.t_ttl; + break; + + case SIOCSLIFPHYDF: + /* commit */ + sc->sc_tunnel.t_df = ifr->ifr_df ? htons(IP_DF) : htons(0); + break; + case SIOCGLIFPHYDF: + ifr->ifr_df = sc->sc_tunnel.t_df ? 1 : 0; + break; + + default: + error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); + break; + } + + return (error); +} + +static int gre_up(struct gre_softc *sc) { NET_ASSERT_LOCKED(); @@ -2477,21 +2764,19 @@ gre_down(struct gre_softc *sc) timeout_barrier(&sc->sc_ka_send); sc->sc_ka_state = GRE_KA_DOWN; - - gre_link_state(sc); + gre_link_state(&sc->sc_if, sc->sc_ka_state); } return (0); } static void -gre_link_state(struct gre_softc *sc) +gre_link_state(struct ifnet *ifp, unsigned int state) { - struct ifnet *ifp = &sc->sc_if; int link_state = LINK_STATE_UNKNOWN; if (ISSET(ifp->if_flags, IFF_RUNNING)) { - switch (sc->sc_ka_state) { + switch (state) { case GRE_KA_NONE: /* maybe up? or down? it's unknown, really */ break; @@ -2613,14 +2898,15 @@ static void gre_keepalive_hold(void *arg) { struct gre_softc *sc = arg; + struct ifnet *ifp = &sc->sc_if; - if (!ISSET(sc->sc_if.if_flags, IFF_RUNNING) || + if (!ISSET(ifp->if_flags, IFF_RUNNING) || sc->sc_ka_state == GRE_KA_NONE) return; NET_LOCK(); sc->sc_ka_state = GRE_KA_DOWN; - gre_link_state(sc); + gre_link_state(ifp, sc->sc_ka_state); NET_UNLOCK(); } @@ -3330,6 +3616,263 @@ nvgre_send(void *arg) ifp->if_oerrors += oerrors; /* XXX should be ifq_oerrors */ } +static int +eoip_up(struct eoip_softc *sc) +{ + if (sc->sc_tunnel.t_af == AF_UNSPEC) + return (EDESTADDRREQ); + + NET_ASSERT_LOCKED(); + + if (RBT_INSERT(eoip_tree, &eoip_tree, sc) != NULL) + return (EADDRINUSE); + + SET(sc->sc_ac.ac_if.if_flags, IFF_RUNNING); + + if (sc->sc_ka_state != GRE_KA_NONE) { + sc->sc_ka_holdmax = sc->sc_ka_count; + eoip_keepalive_send(sc); + } + + return (0); +} + +static int +eoip_down(struct eoip_softc *sc) +{ + NET_ASSERT_LOCKED(); + CLR(sc->sc_ac.ac_if.if_flags, IFF_RUNNING); + + if (sc->sc_ka_state != GRE_KA_NONE) { + if (!timeout_del(&sc->sc_ka_hold)) + timeout_barrier(&sc->sc_ka_hold); + if (!timeout_del(&sc->sc_ka_send)) + timeout_barrier(&sc->sc_ka_send); + + sc->sc_ka_state = GRE_KA_DOWN; + gre_link_state(&sc->sc_ac.ac_if, sc->sc_ka_state); + } + + RBT_REMOVE(eoip_tree, &eoip_tree, sc); + + return (0); +} + +static void +eoip_start(struct ifnet *ifp) +{ + struct eoip_softc *sc = ifp->if_softc; + struct mbuf *m0, *m; +#if NBPFILTER > 0 + caddr_t if_bpf; +#endif + + if (!gre_allow) { + ifq_purge(&ifp->if_snd); + return; + } + + while ((m0 = ifq_dequeue(&ifp->if_snd)) != NULL) { +#if NBPFILTER > 0 + if_bpf = ifp->if_bpf; + if (if_bpf) + bpf_mtap_ether(if_bpf, m0, BPF_DIRECTION_OUT); +#endif + + m = m_gethdr(M_DONTWAIT, m0->m_type); + if (m == NULL) { + m_freem(m0); + continue; + } + + M_MOVE_PKTHDR(m, m0); + m->m_next = m0; + + MH_ALIGN(m, 0); + m->m_len = 0; + + m = eoip_encap(sc, m, 0); + if (m == NULL || gre_ip_output(&sc->sc_tunnel, m) != 0) { + ifp->if_oerrors++; + continue; + } + } +} + +static struct mbuf * +eoip_encap(struct eoip_softc *sc, struct mbuf *m, uint8_t tos) +{ + struct gre_header *gh; + struct gre_h_key_eoip *eoiph; + int len = m->m_pkthdr.len; + + m = m_prepend(m, sizeof(*gh) + sizeof(*eoiph), M_DONTWAIT); + if (m == NULL) + return (NULL); + + gh = mtod(m, struct gre_header *); + gh->gre_flags = htons(GRE_VERS_1 | GRE_KP); + gh->gre_proto = htons(GRE_EOIP); + + eoiph = (struct gre_h_key_eoip *)(gh + 1); + htobem16(&eoiph->eoip_len, len); + eoiph->eoip_tunnel_id = sc->sc_tunnel_id; + + return (gre_encap_ip(&sc->sc_tunnel, m, sc->sc_tunnel.t_ttl, tos)); +} + +static void +eoip_keepalive_send(void *arg) +{ + struct eoip_softc *sc = arg; + struct mbuf *m; + int linkhdr; + + if (!ISSET(sc->sc_ac.ac_if.if_flags, IFF_RUNNING)) + return; + + /* this is really conservative */ +#ifdef INET6 + linkhdr = max_linkhdr + MAX(sizeof(struct ip), sizeof(struct ip6_hdr)) + + sizeof(struct gre_header) + sizeof(struct gre_h_key_eoip); +#else + linkhdr = max_linkhdr + sizeof(struct ip) + + sizeof(struct gre_header) + sizeof(struct gre_h_key_eoip); +#endif + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == NULL) + return; + + if (linkhdr > MHLEN) { + MCLGETI(m, M_DONTWAIT, NULL, linkhdr); + if (!ISSET(m->m_flags, M_EXT)) { + m_freem(m); + return; + } + } + + m->m_pkthdr.len = m->m_len = linkhdr; + m_adj(m, linkhdr); + + m = eoip_encap(sc, m, IPTOS_PREC_INTERNETCONTROL); + if (m == NULL) + return; + + gre_ip_output(&sc->sc_tunnel, m); + + timeout_add_sec(&sc->sc_ka_send, sc->sc_ka_timeo); +} + +static void +eoip_keepalive_hold(void *arg) +{ + struct eoip_softc *sc = arg; + struct ifnet *ifp = &sc->sc_ac.ac_if; + + if (!ISSET(ifp->if_flags, IFF_RUNNING)) + return; + + NET_LOCK(); + sc->sc_ka_state = GRE_KA_DOWN; + gre_link_state(ifp, sc->sc_ka_state); + NET_UNLOCK(); +} + +static void +eoip_keepalive_recv(struct eoip_softc *sc) +{ + switch (sc->sc_ka_state) { + case GRE_KA_NONE: + return; + case GRE_KA_DOWN: + sc->sc_ka_state = GRE_KA_HOLD; + sc->sc_ka_holdcnt = sc->sc_ka_holdmax; + sc->sc_ka_holdmax = MIN(sc->sc_ka_holdmax * 2, + 16 * sc->sc_ka_count); + break; + case GRE_KA_HOLD: + if (--sc->sc_ka_holdcnt > 0) + break; + + sc->sc_ka_state = GRE_KA_UP; + gre_link_state(&sc->sc_ac.ac_if, sc->sc_ka_state); + break; + + case GRE_KA_UP: + sc->sc_ka_holdmax--; + sc->sc_ka_holdmax = MAX(sc->sc_ka_holdmax, sc->sc_ka_count); + break; + } + + timeout_add_sec(&sc->sc_ka_hold, sc->sc_ka_timeo * sc->sc_ka_count); +} + +static struct mbuf * +eoip_input(struct gre_tunnel *key, struct mbuf *m, + const struct gre_header *gh, int iphlen) +{ + struct mbuf_list ml = MBUF_LIST_INITIALIZER(); + struct eoip_softc *sc; + struct gre_h_key_eoip *eoiph; + int hlen, len; + caddr_t buf; + + if (gh->gre_flags != htons(GRE_KP | GRE_VERS_1)) + goto decline; + + hlen = iphlen + sizeof(*gh) + sizeof(*eoiph); + if (m->m_pkthdr.len < hlen) + goto decline; + + m = m_pullup(m, hlen); + if (m == NULL) + return (NULL); + + buf = mtod(m, caddr_t); + gh = (struct gre_header *)(buf + iphlen); + eoiph = (struct gre_h_key_eoip *)(gh + 1); + + key->t_key = eoiph->eoip_tunnel_id; + + NET_ASSERT_LOCKED(); + sc = RBT_FIND(eoip_tree, &eoip_tree, (const struct eoip_softc *)key); + if (sc == NULL) + goto decline; + + /* it's ours now */ + len = bemtoh16(&eoiph->eoip_len); + if (len == 0) { + eoip_keepalive_recv(sc); + goto drop; + } + + m = gre_ether_align(m, hlen); + if (m == NULL) + return (NULL); + + if (m->m_pkthdr.len < len) + goto drop; + if (m->m_pkthdr.len != len) + m_adj(m, len - m->m_pkthdr.len); + + m->m_flags &= ~(M_MCAST|M_BCAST); + +#if NPF > 0 + pf_pkt_addr_changed(m); +#endif + + ml_enqueue(&ml, m); + if_input(&sc->sc_ac.ac_if, &ml); + + return (NULL); + +decline: + return (m); +drop: + m_freem(m); + return (NULL); +} + int gre_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) @@ -3543,3 +4086,40 @@ nvgre_cmp_mcast_sc(const struct nvgre_so RBT_GENERATE(nvgre_ucast_tree, nvgre_softc, sc_uentry, nvgre_cmp_ucast); RBT_GENERATE(nvgre_mcast_tree, nvgre_softc, sc_mentry, nvgre_cmp_mcast_sc); + +static inline int +eoip_cmp(const struct eoip_softc *ea, const struct eoip_softc *eb) +{ + const struct gre_tunnel *a = &ea->sc_tunnel; + const struct gre_tunnel *b = &eb->sc_tunnel; + int rv; + + if (a->t_key > b->t_key) + return (1); + if (a->t_key < b->t_key) + return (-1); + + /* sort by routing table */ + if (a->t_rtableid > b->t_rtableid) + return (1); + if (a->t_rtableid < b->t_rtableid) + return (-1); + + /* sort by address */ + if (a->t_af > b->t_af) + return (1); + if (a->t_af < b->t_af) + return (-1); + + rv = gre_ip_cmp(a->t_af, &a->t_src, &b->t_src); + if (rv != 0) + return (rv); + + rv = gre_ip_cmp(a->t_af, &a->t_dst, &b->t_dst); + if (rv != 0) + return (rv); + + return (0); +} + +RBT_GENERATE(eoip_tree, eoip_softc, sc_entry, eoip_cmp); Index: usr.sbin/tcpdump/print-gre.c =================================================================== RCS file: /cvs/src/usr.sbin/tcpdump/print-gre.c,v retrieving revision 1.19 diff -u -p -r1.19 print-gre.c --- usr.sbin/tcpdump/print-gre.c 24 Feb 2018 08:53:36 -0000 1.19 +++ usr.sbin/tcpdump/print-gre.c 27 May 2018 00:12:36 -0000 @@ -79,6 +79,8 @@ struct wccp_redirect { void gre_print_0(const u_char *, u_int); void gre_print_1(const u_char *, u_int); +void gre_print_pptp(const u_char *, u_int, uint16_t); +void gre_print_eoip(const u_char *, u_int, uint16_t); void gre_sre_print(u_int16_t, u_int8_t, u_int8_t, const u_char *, u_int); void gre_sre_ip_print(u_int8_t, u_int8_t, const u_char *, u_int); void gre_sre_asn_print(u_int8_t, u_int8_t, const u_char *, u_int); @@ -271,7 +273,7 @@ trunc: void gre_print_1(const u_char *p, u_int length) { - uint16_t flags, proto, len; + uint16_t flags, proto; int l; l = snapend - p; @@ -281,10 +283,45 @@ gre_print_1(const u_char *p, u_int lengt l -= sizeof(flags); length -= sizeof(flags); + if (l < sizeof(proto)) + goto trunc; + + proto = EXTRACT_16BITS(p); + p += sizeof(proto); + l -= sizeof(proto); + length -= sizeof(proto); + + switch (proto) { + case ETHERTYPE_PPP: + gre_print_pptp(p, length, flags); + break; + case 0x6400: + /* MikroTik RouterBoard Ethernet over IP (EoIP) */ + gre_print_eoip(p, length, flags); + break; + default: + printf("unknown-gre1-proto-%04x", proto); + break; + } + + return; + +trunc: + printf("[|gre1]"); +} + +void +gre_print_pptp(const u_char *p, u_int length, uint16_t flags) +{ + uint16_t len; + int l; + + l = snapend - p; + printf("pptp"); if (vflag) { - printf(" [%s%s%s%s%s%s] ", + printf(" [%s%s%s%s%s%s]", (flags & GRE_CP) ? "C" : "", (flags & GRE_RP) ? "R" : "", (flags & GRE_KP) ? "K" : "", @@ -293,14 +330,6 @@ gre_print_1(const u_char *p, u_int lengt (flags & GRE_AP) ? "A" : ""); } - if (l < sizeof(proto)) - goto trunc; - - proto = EXTRACT_16BITS(p); - p += sizeof(proto); - l -= sizeof(proto); - length -= sizeof(proto); - if (flags & GRE_CP) { printf(" cpset!"); return; @@ -365,18 +394,67 @@ gre_print_1(const u_char *p, u_int lengt printf(": "); - switch (proto) { - case ETHERTYPE_PPP: - ppp_hdlc_print(p, len); - break; - default: - printf("unknown-proto-%04x", proto); - break; - } + ppp_hdlc_print(p, len); return; trunc: printf("[|pptp]"); +} + +void +gre_print_eoip(const u_char *p, u_int length, uint16_t flags) +{ + uint16_t len, id; + int l; + + l = snapend - p; + + printf("eoip"); + + flags &= ~GRE_VERS; + if (flags != GRE_KP) { + printf(" unknown-eoip-flags-%04x!", flags); + return; + } + + if (l < sizeof(len)) + goto trunc; + + len = EXTRACT_16BITS(p); + p += sizeof(len); + l -= sizeof(len); + length -= sizeof(len); + + if (l < sizeof(id)) + goto trunc; + + id = EXTRACT_LE_16BITS(p); + p += sizeof(id); + l -= sizeof(id); + length -= sizeof(id); + + if (vflag) + printf(" len=%u tunnel-id=%u", len, id); + else + printf(" %u", id); + + if (length < len) { + (void)printf(" truncated-eoip - %d bytes missing!", + len - length); + len = length; + } + + printf(": "); + + if (len == 0) + printf("keepalive"); + else + ether_tryprint(p, len, 0); + + return; + +trunc: + printf("[|eoip]"); } void Index: share/man/man4/Makefile =================================================================== RCS file: /cvs/src/share/man/man4/Makefile,v retrieving revision 1.681 diff -u -p -r1.681 Makefile --- share/man/man4/Makefile 23 May 2018 22:34:31 -0000 1.681 +++ share/man/man4/Makefile 27 May 2018 00:12:36 -0000 @@ -23,7 +23,7 @@ MAN= aac.4 ac97.4 acphy.4 acrtc.4 \ dc.4 dcphy.4 ddb.4 de.4 diskmap.4 divert.4 dpt.4 drm.4 dwctwo.4 \ dwdog.4 dwge.4 dwiic.4 dwmmc.4 dwpcie.4 dwxe.4 \ eap.4 ec.4 eephy.4 ef.4 eg.4 ehci.4 eisa.4 el.4 em.4 emc.4 gcu.4 \ - emu.4 enc.4 endrun.4 envy.4 ep.4 epic.4 esa.4 \ + emu.4 enc.4 endrun.4 envy.4 eoip.4 ep.4 epic.4 esa.4 \ eso.4 ess.4 et.4 etherip.4 etphy.4 ex.4 exphy.4 exrtc.4 \ fd.4 fdc.4 fec.4 fins.4 fintek.4 fms.4 fuse.4 fxp.4 gdt.4 \ gentbi.4 gem.4 gif.4 \ Index: share/man/man4/eoip.4 =================================================================== RCS file: share/man/man4/eoip.4 diff -N share/man/man4/eoip.4 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ share/man/man4/eoip.4 27 May 2018 00:12:36 -0000 @@ -0,0 +1,202 @@ +.\" $OpenBSD: gre.4,v 1.72 2018/04/20 22:55:53 bentley Exp $ +.\" $NetBSD: gre.4,v 1.10 1999/12/22 14:55:49 kleink Exp $ +.\" +.\" Copyright 1998 (c) The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Heiko W. Rupp +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd $Mdocdate: April 20 2018 $ +.Dt EOIP 4 +.Os +.Sh NAME +.Nm eoip +.Nd MikroTik Ethernet over IP tunnel network device +.Sh SYNOPSIS +.Cd "pseudo-device gre" +.Sh DESCRIPTION +The +.Nm +interface provides tunnelling of IP protocols across +IPv4 and IPv6 networks using the +MikroTik Ethernet over IP (EoIP) encapsulation protocol. +.Pp +The protocol is based on the Generic Routing and Encapsulation (GRE) +protocol. +GRE datagrams (IP protocol number 47) consist of a GRE header +and an outer IP header for encapsulating another protocol's datagram. +The GRE header specifies a version, and the type of the encapsulated datagram, +allowing for the tunnelling of multiple protocols. +EoIP uses GRE version 1 and it's own protocol identifier for Ethernet +and it's own keepalive semantics, +making it distinct from GRE version 0 protocols. +However, it is implemented as part of the same driver providing +.Xr gre 4 , +.Xr egre 4 , +.Xr mgre 4 , +and +.Xr nvgre 4 . +.Pp +Different tunnels between the same endpoints are distinguished +by a 16-bit tunnel identifier field in the header. +.Pp +All GRE packet processing in the system is allowed or denied by setting the +.Va net.inet.gre.allow +.Xr sysctl 8 +variable. +To allow GRE packet processing, set +.Va net.inet.gre.allow +to 1. +.Pp +.Nm +interfaces can be created at runtime using the +.Ic ifconfig eoip Ns Ar N Ic create +command or by setting up a +.Xr hostname.if 5 +configuration file for +.Xr netstart 8 . +.Pp +For correct operation, encapsulated traffic must not be routed +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. +.Ss Programming Interface +.Nm +interfaces support the following +.Xr ioctl 2 +calls for configuring tunnel options: +.Bl -tag -width indent -offset 3n +.It Dv SIOCSLIFPHYADDR Fa "struct if_laddrreq *" +Set the unicast IPv4 or IPv6 addresses for the encapsulating IP packets. +The addresses may only be configured while the interface is down. +.It Dv SIOCGLIFPHYADDR Fa "struct if_laddrreq *" +Get the addresses used for the encapsulating IP packets. +.It Dv SIOCDIFPHYADDR Fa "struct ifreq *" +Clear the addresses used for the encapsulating IP packets. +The addresses may only be cleared while the interface is down. +.It Dv SIOCSVNETID Fa "struct ifreq *" +Configure a virtual network identifier for use as the Tunnel Identifier. +The virtual network identifier may only be configured while the +interface is down. +The Tunnel Identifier is a 16-bit value. +.It Dv SIOCGVNETID Fa "struct ifreq *" +Get the virtual network identifer used in the GRE Key header. +.It Dv SIOCSLIFPHYRTABLE Fa "struct ifreq *" +Set the routing table the tunnel traffic operates in. +The routing table may only be configured while the interface is down. +.It Dv SIOCGLIFPHYRTABLE Fa "struct ifreq *" +Get the routing table the tunnel traffic operates in. +.It Dv SIOCSLIFPHYTTL Fa "struct ifreq *" +Set the Time-To-Live field in IPv4 encapsulation headers, or the +Hop Limit field in IPv6 encapsulation headers. +.It Dv SIOCGLIFPHYTTL Fa "struct ifreq *" +Get the value used in the Time-To-Live field in a IPv4 encapsulation +header or the Hop Limit field in a IPv6 encapsulation header. +.It Dv SIOCSLIFPHYDF Fa "struct ifreq *" +Configure whether the tunnel traffic sent by the interface can be +fragmented or not. +This sets the Don't Fragment (DF) bit on IPv4 packets, +and disables fragmentation of IPv6 packets. +.It Dv SIOCGLIFPHYDF Fa "struct ifreq *" +Get whether the tunnel traffic sent by the interface can be fragmented +or not. +.It Dv SIOCSETKALIVE Fa "struct ifkalivereq *" +Enable the transmission of keepalive packets to detect tunnel failure. +Keepalives may only be configured while the interace is down. +.Pp +Setting the keepalive period or count to 0 disables keepalives on +the tunnel. +.It Dv SIOCGETKALIVE Fa "struct ifkalivereq *" +Get the configuration of keepalive packets. +.El +.Ss Security Considerations +EoIP does not provide any integrated security features. +It should only be deployed on trusted private networks, +or protected with IPsec to add authentication and encryption for +confidentiality. +IPsec is especially recommended when transporting EoIP over the +public internet. +.Pp +The Packet Filter +.Xr pf 4 +can be used to filter tunnel traffic with endpoint policies +.Xr pf.conf 5 . +.Pp +The Time-to-Live (TTL) value of a tunnel can be set to 1 or a low +value to restrict the traffic to the local network: +.Bd -literal -offset indent +# ifconfig eoipN tunnelttl 1 +.Ed +.Sh EXAMPLES +.Bd -literal +Host X ---- Host A ------------ tunnel ----------- MikroTik 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 eoipN create +# ifconfig eoipN tunnel A D +# ifconfig eoipN up +# route add E D +.Ed +.Pp +On Host D (MikroTik): +.Bd -literal -offset indent +[admin@MikroTik] > interface eoip +[admin@MikroTik] /interface eoip> add name="eoipN" \e +\e... local-address=D remote-address=A +[admin@MikroTik] /interface eoip> enable eoipN +.Ed +.Sh SEE ALSO +.Xr egre 4 , +.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 , +.Xr sysctl 8 +.Sh STANDARDS +.Rs +.%A S. Hanks +.%A "T. Li" +.%A D. Farinacci +.%A P. Traina +.%D October 1994 +.%R RFC 1701 +.%T Generic Routing Encapsulation (GRE) +.Re +.Sh AUTHORS +.An David Gwynne Aq Mt dlg@openbsd.org