Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 21 Oct 2018 17:55:26 +0000 (UTC)
From:      "Andrey V. Elsukov" <ae@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r339550 - in head/sys: net netinet
Message-ID:  <201810211755.w9LHtQgR078596@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ae
Date: Sun Oct 21 17:55:26 2018
New Revision: 339550
URL: https://svnweb.freebsd.org/changeset/base/339550

Log:
  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
  
  MFC after:	1 month
  Sponsored by:	Yandex LLC
  Differential Revision:	https://reviews.freebsd.org/D17134

Modified:
  head/sys/net/if.c
  head/sys/netinet/ip_encap.c
  head/sys/netinet/ip_encap.h

Modified: head/sys/net/if.c
==============================================================================
--- head/sys/net/if.c	Sun Oct 21 17:38:52 2018	(r339549)
+++ head/sys/net/if.c	Sun Oct 21 17:55:26 2018	(r339550)
@@ -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: head/sys/netinet/ip_encap.c
==============================================================================
--- head/sys/netinet/ip_encap.c	Sun Oct 21 17:38:52 2018	(r339549)
+++ head/sys/netinet/ip_encap.c	Sun Oct 21 17:55:26 2018	(r339550)
@@ -100,22 +100,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 +292,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 +338,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 +377,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: head/sys/netinet/ip_encap.h
==============================================================================
--- head/sys/netinet/ip_encap.h	Sun Oct 21 17:38:52 2018	(r339549)
+++ head/sys/netinet/ip_encap.h	Sun Oct 21 17:55:26 2018	(r339550)
@@ -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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201810211755.w9LHtQgR078596>