From owner-svn-src-stable-12@freebsd.org Sun Nov 18 00:09:35 2018 Return-Path: Delivered-To: svn-src-stable-12@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 5A95F110C127; Sun, 18 Nov 2018 00:09:35 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id F181B87349; Sun, 18 Nov 2018 00:09:34 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id CC989341C; Sun, 18 Nov 2018 00:09:34 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id wAI09Ygr078160; Sun, 18 Nov 2018 00:09:34 GMT (envelope-from ae@FreeBSD.org) Received: (from ae@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id wAI09YI8078157; Sun, 18 Nov 2018 00:09:34 GMT (envelope-from ae@FreeBSD.org) Message-Id: <201811180009.wAI09YI8078157@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: ae set sender to ae@FreeBSD.org using -f From: "Andrey V. Elsukov" Date: Sun, 18 Nov 2018 00:09:34 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Subject: svn commit: r340533 - in stable/12/sys: net netinet X-SVN-Group: stable-12 X-SVN-Commit-Author: ae X-SVN-Commit-Paths: in stable/12/sys: net netinet X-SVN-Commit-Revision: 340533 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: F181B87349 X-Spamd-Result: default: False [-0.12 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_SHORT(-0.12)[-0.119,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US] X-Rspamd-Server: mx1.freebsd.org X-BeenThere: svn-src-stable-12@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: SVN commit messages for only the 12-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 18 Nov 2018 00:09:35 -0000 Author: ae Date: Sun Nov 18 00:09:33 2018 New Revision: 340533 URL: https://svnweb.freebsd.org/changeset/base/340533 Log: MFC r339550,339556: Add KPI that can be used by tunneling interfaces to handle IP addresses appearing and disappearing on the host system. Such handling is need, because tunneling interfaces must use addresses, that are configured on the host as ingress addresses for tunnels. Otherwise the system can send spoofed packets with source address, that belongs to foreign host. The KPI uses ifaddr_event_ext event to implement addresses tracking. Tunneling interfaces register event handlers and then they are notified by the kernel, when an address disappears or appears. ifaddr_event_compat() handler from if.c replaced by srcaddr_change_event() in the ip_encap.c Sponsored by: Yandex LLC Differential Revision: https://reviews.freebsd.org/D17134 Modified: stable/12/sys/net/if.c stable/12/sys/netinet/ip_encap.c stable/12/sys/netinet/ip_encap.h Directory Properties: stable/12/ (props changed) Modified: stable/12/sys/net/if.c ============================================================================== --- stable/12/sys/net/if.c Sun Nov 18 00:04:03 2018 (r340532) +++ stable/12/sys/net/if.c Sun Nov 18 00:09:33 2018 (r340533) @@ -328,18 +328,6 @@ static MALLOC_DEFINE(M_IFNET, "ifnet", "interface inte MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address"); MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address"); -/* - * Support for old ifaddr_event. - */ -static void -ifaddr_event_compat(void *arg __unused, struct ifnet *ifp, - struct ifaddr *ifa __unused, int event __unused) -{ - - EVENTHANDLER_INVOKE(ifaddr_event, ifp); -} -EVENTHANDLER_DEFINE(ifaddr_event_ext, ifaddr_event_compat, NULL, 0); - struct ifnet * ifnet_byindex_locked(u_short idx) { Modified: stable/12/sys/netinet/ip_encap.c ============================================================================== --- stable/12/sys/netinet/ip_encap.c Sun Nov 18 00:04:03 2018 (r340532) +++ stable/12/sys/netinet/ip_encap.c Sun Nov 18 00:09:33 2018 (r340533) @@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -100,22 +101,139 @@ struct encaptab { encap_input_t input; }; +struct srcaddrtab { + CK_LIST_ENTRY(srcaddrtab) chain; + + encap_srcaddr_t srcaddr; + void *arg; +}; + CK_LIST_HEAD(encaptab_head, encaptab); +CK_LIST_HEAD(srcaddrtab_head, srcaddrtab); #ifdef INET static struct encaptab_head ipv4_encaptab = CK_LIST_HEAD_INITIALIZER(); +static struct srcaddrtab_head ipv4_srcaddrtab = CK_LIST_HEAD_INITIALIZER(); #endif #ifdef INET6 static struct encaptab_head ipv6_encaptab = CK_LIST_HEAD_INITIALIZER(); +static struct srcaddrtab_head ipv6_srcaddrtab = CK_LIST_HEAD_INITIALIZER(); #endif -static struct mtx encapmtx; +static struct mtx encapmtx, srcaddrmtx; MTX_SYSINIT(encapmtx, &encapmtx, "encapmtx", MTX_DEF); +MTX_SYSINIT(srcaddrmtx, &srcaddrmtx, "srcaddrmtx", MTX_DEF); #define ENCAP_WLOCK() mtx_lock(&encapmtx) #define ENCAP_WUNLOCK() mtx_unlock(&encapmtx) -#define ENCAP_RLOCK() struct epoch_tracker encap_et; epoch_enter_preempt(net_epoch_preempt, &encap_et) -#define ENCAP_RUNLOCK() epoch_exit_preempt(net_epoch_preempt, &encap_et) +#define ENCAP_RLOCK_TRACKER struct epoch_tracker encap_et +#define ENCAP_RLOCK() \ + epoch_enter_preempt(net_epoch_preempt, &encap_et) +#define ENCAP_RUNLOCK() \ + epoch_exit_preempt(net_epoch_preempt, &encap_et) #define ENCAP_WAIT() epoch_wait_preempt(net_epoch_preempt) +#define SRCADDR_WLOCK() mtx_lock(&srcaddrmtx) +#define SRCADDR_WUNLOCK() mtx_unlock(&srcaddrmtx) +#define SRCADDR_RLOCK_TRACKER struct epoch_tracker srcaddr_et +#define SRCADDR_RLOCK() \ + epoch_enter_preempt(net_epoch_preempt, &srcaddr_et) +#define SRCADDR_RUNLOCK() \ + epoch_exit_preempt(net_epoch_preempt, &srcaddr_et) +#define SRCADDR_WAIT() epoch_wait_preempt(net_epoch_preempt) + +/* + * ifaddr_event_ext handler. + * + * Tunnelling interfaces may request the kernel to notify when + * some interface addresses appears or disappears. Usually tunnelling + * interface must use an address configured on the local machine as + * ingress address to be able receive datagramms and do not send + * spoofed packets. + */ +static void +srcaddr_change_event(void *arg __unused, struct ifnet *ifp, + struct ifaddr *ifa, int event) +{ + SRCADDR_RLOCK_TRACKER; + struct srcaddrtab_head *head; + struct srcaddrtab *p; + + /* Support for old ifaddr_event. */ + EVENTHANDLER_INVOKE(ifaddr_event, ifp); + + switch (ifa->ifa_addr->sa_family) { +#ifdef INET + case AF_INET: + head = &ipv4_srcaddrtab; + break; +#endif +#ifdef INET6 + case AF_INET6: + head = &ipv6_srcaddrtab; + break; +#endif + default: + /* ignore event */ + return; + } + + SRCADDR_RLOCK(); + CK_LIST_FOREACH(p, head, chain) { + (*p->srcaddr)(p->arg, ifa->ifa_addr, event); + } + SRCADDR_RUNLOCK(); +} +EVENTHANDLER_DEFINE(ifaddr_event_ext, srcaddr_change_event, NULL, 0); + +static struct srcaddrtab * +encap_register_srcaddr(struct srcaddrtab_head *head, encap_srcaddr_t func, + void *arg, int mflags) +{ + struct srcaddrtab *p, *tmp; + + if (func == NULL) + return (NULL); + p = malloc(sizeof(*p), M_NETADDR, mflags); + if (p == NULL) + return (NULL); + p->srcaddr = func; + p->arg = arg; + + SRCADDR_WLOCK(); + CK_LIST_FOREACH(tmp, head, chain) { + if (func == tmp->srcaddr && arg == tmp->arg) + break; + } + if (tmp == NULL) + CK_LIST_INSERT_HEAD(head, p, chain); + SRCADDR_WUNLOCK(); + + if (tmp != NULL) { + free(p, M_NETADDR); + p = tmp; + } + return (p); +} + +static int +encap_unregister_srcaddr(struct srcaddrtab_head *head, + const struct srcaddrtab *cookie) +{ + struct srcaddrtab *p; + + SRCADDR_WLOCK(); + CK_LIST_FOREACH(p, head, chain) { + if (p == cookie) { + CK_LIST_REMOVE(p, chain); + SRCADDR_WUNLOCK(); + SRCADDR_WAIT(); + free(p, M_NETADDR); + return (0); + } + } + SRCADDR_WUNLOCK(); + return (EINVAL); +} + static struct encaptab * encap_attach(struct encaptab_head *head, const struct encap_config *cfg, void *arg, int mflags) @@ -175,6 +293,7 @@ encap_detach(struct encaptab_head *head, const struct static int encap_input(struct encaptab_head *head, struct mbuf *m, int off, int proto) { + ENCAP_RLOCK_TRACKER; struct encaptab *ep, *match; void *arg; int matchprio, ret; @@ -220,6 +339,20 @@ encap_input(struct encaptab_head *head, struct mbuf *m } #ifdef INET +const struct srcaddrtab * +ip_encap_register_srcaddr(encap_srcaddr_t func, void *arg, int mflags) +{ + + return (encap_register_srcaddr(&ipv4_srcaddrtab, func, arg, mflags)); +} + +int +ip_encap_unregister_srcaddr(const struct srcaddrtab *cookie) +{ + + return (encap_unregister_srcaddr(&ipv4_srcaddrtab, cookie)); +} + const struct encaptab * ip_encap_attach(const struct encap_config *cfg, void *arg, int mflags) { @@ -245,6 +378,20 @@ encap4_input(struct mbuf **mp, int *offp, int proto) #endif /* INET */ #ifdef INET6 +const struct srcaddrtab * +ip6_encap_register_srcaddr(encap_srcaddr_t func, void *arg, int mflags) +{ + + return (encap_register_srcaddr(&ipv6_srcaddrtab, func, arg, mflags)); +} + +int +ip6_encap_unregister_srcaddr(const struct srcaddrtab *cookie) +{ + + return (encap_unregister_srcaddr(&ipv6_srcaddrtab, cookie)); +} + const struct encaptab * ip6_encap_attach(const struct encap_config *cfg, void *arg, int mflags) { Modified: stable/12/sys/netinet/ip_encap.h ============================================================================== --- stable/12/sys/netinet/ip_encap.h Sun Nov 18 00:04:03 2018 (r340532) +++ stable/12/sys/netinet/ip_encap.h Sun Nov 18 00:09:33 2018 (r340533) @@ -43,7 +43,8 @@ int encap6_input(struct mbuf **, int *, int); typedef int (*encap_lookup_t)(const struct mbuf *, int, int, void **); typedef int (*encap_check_t)(const struct mbuf *, int, int, void *); -typedef int (*encap_input_t)(struct mbuf *, int , int, void *); +typedef int (*encap_input_t)(struct mbuf *, int, int, void *); +typedef void (*encap_srcaddr_t)(void *, const struct sockaddr *, int); struct encap_config { int proto; /* protocol */ @@ -60,12 +61,20 @@ struct encap_config { }; struct encaptab; +struct srcaddrtab; const struct encaptab *ip_encap_attach(const struct encap_config *, void *arg, int mflags); const struct encaptab *ip6_encap_attach(const struct encap_config *, void *arg, int mflags); +const struct srcaddrtab *ip_encap_register_srcaddr(encap_srcaddr_t, + void *arg, int mflags); +const struct srcaddrtab *ip6_encap_register_srcaddr(encap_srcaddr_t, + void *arg, int mflags); + +int ip_encap_unregister_srcaddr(const struct srcaddrtab *); +int ip6_encap_unregister_srcaddr(const struct srcaddrtab *); int ip_encap_detach(const struct encaptab *); int ip6_encap_detach(const struct encaptab *); #endif