Index: sbin/ifconfig/ifconfig.c =================================================================== RCS file: /cvs/src/sbin/ifconfig/ifconfig.c,v retrieving revision 1.360 diff -u -p -r1.360 ifconfig.c --- sbin/ifconfig/ifconfig.c 20 Feb 2018 15:33:16 -0000 1.360 +++ sbin/ifconfig/ifconfig.c 27 Feb 2018 04:39:16 -0000 @@ -200,6 +200,7 @@ void unsetifnwflag(const char *, int); void setifnetmask(const char *, int); void setifprefixlen(const char *, int); void settunnel(const char *, const char *); +void settunneladdr(const char *, int); void deletetunnel(const char *, int); void settunnelinst(const char *, int); void settunnelttl(const char *, int); @@ -451,6 +452,7 @@ const struct cmd { { "defer", 1, 0, setpfsync_defer }, { "-defer", 0, 0, setpfsync_defer }, { "tunnel", NEXTARG2, 0, NULL, settunnel }, + { "tunneladdr", NEXTARG, 0, settunneladdr }, { "-tunnel", 0, 0, deletetunnel }, /* deletetunnel is for backward compat, remove during 6.4-current */ { "deletetunnel", 0, 0, deletetunnel }, @@ -2734,42 +2736,76 @@ print_media_word(uint64_t ifmw, int prin printf(" instance %lld", IFM_INST(ifmw)); } -/* ARGSUSED */ static void -phys_status(int force) +print_tunnel(const struct if_laddrreq *req) { char psrcaddr[NI_MAXHOST]; char pdstaddr[NI_MAXHOST]; const char *ver = ""; const int niflag = NI_NUMERICHOST; - struct if_laddrreq req; - in_port_t dstport = 0; + + if (req == NULL) { + printf("(unset)"); + return; + } psrcaddr[0] = pdstaddr[0] = '\0'; - memset(&req, 0, sizeof(req)); - (void) strlcpy(req.iflr_name, name, sizeof(req.iflr_name)); - if (ioctl(s, SIOCGLIFPHYADDR, (caddr_t)&req) < 0) - return; - if (getnameinfo((struct sockaddr *)&req.addr, req.addr.ss_len, + if (getnameinfo((struct sockaddr *)&req->addr, req->addr.ss_len, psrcaddr, sizeof(psrcaddr), 0, 0, niflag) != 0) strlcpy(psrcaddr, "", sizeof(psrcaddr)); - if (req.addr.ss_family == AF_INET6) + if (req->addr.ss_family == AF_INET6) ver = "6"; - if (req.dstaddr.ss_family == AF_INET) - dstport = ((struct sockaddr_in *)&req.dstaddr)->sin_port; - else if (req.dstaddr.ss_family == AF_INET6) - dstport = ((struct sockaddr_in6 *)&req.dstaddr)->sin6_port; - if (getnameinfo((struct sockaddr *)&req.dstaddr, req.dstaddr.ss_len, - pdstaddr, sizeof(pdstaddr), 0, 0, niflag) != 0) - strlcpy(pdstaddr, "", sizeof(pdstaddr)); + printf("inet%s %s", ver, psrcaddr); + + if (req->dstaddr.ss_family != AF_UNSPEC) { + in_port_t dstport = 0; + const struct sockaddr_in *sin; + const struct sockaddr_in6 *sin6; + + if (getnameinfo((struct sockaddr *)&req->dstaddr, + req->dstaddr.ss_len, pdstaddr, sizeof(pdstaddr), + 0, 0, niflag) != 0) + strlcpy(pdstaddr, "", sizeof(pdstaddr)); + + printf(" -> %s", pdstaddr); + + switch (req->dstaddr.ss_family) { + case AF_INET: + sin = (const struct sockaddr_in *)&req->dstaddr; + dstport = sin->sin_port; + break; + case AF_INET6: + sin6 = (const struct sockaddr_in6 *)&req->dstaddr; + dstport = sin6->sin6_port; + break; + } + + if (dstport) + printf(":%u", ntohs(dstport)); + } +} + +/* ARGSUSED */ +static void +phys_status(int force) +{ + struct if_laddrreq req; + struct if_laddrreq *r = &req; + + memset(&req, 0, sizeof(req)); + (void) strlcpy(req.iflr_name, name, sizeof(req.iflr_name)); + if (ioctl(s, SIOCGLIFPHYADDR, (caddr_t)&req) < 0) { + if (errno != EADDRNOTAVAIL) + return; - printf("\ttunnel: inet%s %s -> %s", ver, - psrcaddr, pdstaddr); + r = NULL; + } + + printf("\ttunnel: "); + print_tunnel(r); - if (dstport) - printf(":%u", ntohs(dstport)); if (ioctl(s, SIOCGLIFPHYTTL, (caddr_t)&ifr) == 0) { if (ifr.ifr_ttl == -1) printf(" ttl copy"); @@ -3269,6 +3305,40 @@ settunnel(const char *src, const char *d freeaddrinfo(srcres); freeaddrinfo(dstres); +} + +void +settunneladdr(const char *addr, int ignored) +{ + struct addrinfo hints, *res; + struct if_laddrreq req; + ssize_t len; + int rv; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = 0; + hints.ai_flags = AI_PASSIVE; + + rv = getaddrinfo(addr, NULL, &hints, &res); + if (rv != 0) + errx(1, "tunneladdr %s: %s", addr, gai_strerror(rv)); + + memset(&req, 0, sizeof(req)); + len = strlcpy(req.iflr_name, name, sizeof(req.iflr_name)); + if (len >= sizeof(req.iflr_name)) + errx(1, "%s: Interface name too long", name); + + memcpy(&req.addr, res->ai_addr, res->ai_addrlen); + + req.dstaddr.ss_len = 2; + req.dstaddr.ss_family = AF_UNSPEC; + + if (ioctl(s, SIOCSLIFPHYADDR, &req) < 0) + warn("tunneladdr %s", addr); + + freeaddrinfo(res); } /* ARGSUSED */ Index: sys/net/if_gre.c =================================================================== RCS file: /cvs/src/sys/net/if_gre.c,v retrieving revision 1.115 diff -u -p -r1.115 if_gre.c --- sys/net/if_gre.c 27 Feb 2018 04:36:18 -0000 1.115 +++ sys/net/if_gre.c 27 Feb 2018 04:39:16 -0000 @@ -1,4 +1,4 @@ -/* $OpenBSD: if_gre.c,v 1.115 2018/02/27 04:36:18 dlg Exp $ */ +/* $OpenBSD: if_gre.c,v 1.114 2018/02/25 01:52:25 dlg Exp $ */ /* $NetBSD: if_gre.c,v 1.9 1999/10/25 19:18:11 drochner Exp $ */ /* @@ -304,6 +304,8 @@ static int mgre_output(struct ifnet *, s static void mgre_start(struct ifnet *); static int mgre_ioctl(struct ifnet *, u_long, caddr_t); +static int mgre_set_tunnel(struct mgre_softc *, struct if_laddrreq *); +static int mgre_get_tunnel(struct mgre_softc *, struct if_laddrreq *); static int mgre_up(struct mgre_softc *); static int mgre_down(struct mgre_softc *); @@ -2026,7 +2028,16 @@ mgre_ioctl(struct ifnet *ifp, u_long cmd break; case SIOCSLIFPHYADDR: - /* XXX */ + if (ISSET(ifp->if_flags, IFF_RUNNING)) { + error = EBUSY; + break; + } + error = mgre_set_tunnel(sc, (struct if_laddrreq *)data); + break; + case SIOCGLIFPHYADDR: + error = mgre_get_tunnel(sc, (struct if_laddrreq *)data); + break; + case SIOCSVNETID: case SIOCDVNETID: case SIOCDIFPHYADDR: @@ -2043,6 +2054,104 @@ mgre_ioctl(struct ifnet *ifp, u_long cmd } return (error); +} + +static int +mgre_set_tunnel(struct mgre_softc *sc, struct if_laddrreq *req) +{ + struct gre_tunnel *tunnel = &sc->sc_tunnel; + struct sockaddr *addr = (struct sockaddr *)&req->addr; + struct sockaddr *dstaddr = (struct sockaddr *)&req->dstaddr; + struct sockaddr_in *addr4; +#ifdef INET6 + struct sockaddr_in6 *addr6; + int error; +#endif + + if (dstaddr->sa_family != AF_UNSPEC) + return (EINVAL); + + /* validate */ + switch (addr->sa_family) { + case AF_INET: + if (addr->sa_len != sizeof(*addr4)) + return (EINVAL); + + addr4 = (struct sockaddr_in *)addr; + if (in_nullhost(addr4->sin_addr) || + IN_MULTICAST(addr4->sin_addr.s_addr)) + return (EINVAL); + + tunnel->t_src4 = addr4->sin_addr; + tunnel->t_dst4.s_addr = INADDR_ANY; + + break; +#ifdef INET6 + case AF_INET6: + if (addr->sa_len != sizeof(*addr6)) + return (EINVAL); + + addr6 = (struct sockaddr_in6 *)addr; + if (IN6_IS_ADDR_UNSPECIFIED(&addr6->sin6_addr) || + IN6_IS_ADDR_MULTICAST(&addr6->sin6_addr)) + return (EINVAL); + + error = in6_embedscope(&tunnel->t_src6, addr6, NULL); + if (error != 0) + return (error); + + memset(&tunnel->t_dst6, 0, sizeof(tunnel->t_dst6)); + + break; +#endif + default: + return (EAFNOSUPPORT); + } + + /* commit */ + tunnel->t_af = addr->sa_family; + + return (0); +} + +static int +mgre_get_tunnel(struct mgre_softc *sc, struct if_laddrreq *req) +{ + struct gre_tunnel *tunnel = &sc->sc_tunnel; + struct sockaddr *dstaddr = (struct sockaddr *)&req->dstaddr; + struct sockaddr_in *sin; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif + + switch (tunnel->t_af) { + case AF_UNSPEC: + return (EADDRNOTAVAIL); + case AF_INET: + sin = (struct sockaddr_in *)&req->addr; + memset(sin, 0, sizeof(*sin)); + sin->sin_family = AF_INET; + sin->sin_len = sizeof(*sin); + sin->sin_addr = tunnel->t_src4; + break; + +#ifdef INET6 + case AF_INET6: + sin6 = (struct sockaddr_in6 *)&req->addr; + memset(sin6, 0, sizeof(*sin6)); + sin6->sin6_family = AF_INET6; + sin6->sin6_len = sizeof(*sin6); + in6_recoverscope(sin6, &tunnel->t_src6); + break; +#endif + default: + unhandled_af(tunnel->t_af); + } + + dstaddr->sa_len = 2; + dstaddr->sa_family = AF_UNSPEC; + + return (0); } static int