Subject: rfc: link-local ipv4 addrs and source selection
To: None <tech-net@netbsd.org>
From: David Young <dyoung@pobox.com>
List: tech-net
Date: 03/01/2005 22:40:37
--LQksG6bCIzRHxTLp
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
The IETF Zeroconf working group has introduced "link-local"
IPv4 addresses (those in 169.254/16). The "scope" of these IPv4
addresses is the attached link (ethernet, PPP, whatever), only. See
<http://files.zeroconf.org/draft-ietf-zeroconf-ipv4-linklocal.txt>, which
describes the link-local addresses and a method for auto-configuration.
Link-local IPv4 addresses are widely used in PC operating systems
(Windows, MacOS 9, Mac0S X) and peripherals (printers).
A host should not use a link-local source address to talk to non-link
local destinations. This breaks the scope rule. Attached is a patch
that makes sure a host selects non-link local source addresses for IPv4
packets that have non-link local destinations.
I would like to add this to the kernel, default disabled, enabled by
'options IPV4_LINKLOCAL'.
Please not that the ifa_getifa method is fairly versatile. It could be
used to implement preferred source addresses, for example. There was
a discussion about that a little while ago on tech-net@.
Your comments?
Dave
--
David Young OJC Technologies
dyoung@ojctech.com Urbana, IL * (217) 278-3933
--LQksG6bCIzRHxTLp
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=in_getifa-patch
Index: sys/net/if.h
===================================================================
RCS file: /cvsroot/src/sys/net/if.h,v
retrieving revision 1.100
diff -u -r1.100 if.h
--- sys/net/if.h 24 Jan 2005 21:25:09 -0000 1.100
+++ sys/net/if.h 19 Feb 2005 07:02:49 -0000
@@ -129,6 +129,7 @@
struct rtentry;
struct socket;
struct ether_header;
+struct ifaddr;
struct ifnet;
struct rt_addrinfo;
@@ -429,6 +430,8 @@
u_int ifa_flags; /* mostly rt_flags for cloning */
int ifa_refcnt; /* count of references */
int ifa_metric; /* cost of going out this interface */
+ struct ifaddr *(*ifa_getifa)(struct ifaddr *,
+ const struct sockaddr *);
};
#define IFA_ROUTE RTF_UP /* 0x01 *//* route installed */
Index: sys/net/route.c
===================================================================
RCS file: /cvsroot/src/sys/net/route.c,v
retrieving revision 1.64
diff -u -r1.64 route.c
--- sys/net/route.c 23 Jan 2005 18:41:56 -0000 1.64
+++ sys/net/route.c 19 Feb 2005 07:02:49 -0000
@@ -509,7 +509,6 @@
rt_getifa(struct rt_addrinfo *info)
{
struct ifaddr *ifa;
- int error = 0;
/*
* ifp may be specified by sockaddr_dl when protocol address
@@ -533,12 +532,13 @@
else if (sa != NULL)
info->rti_ifa = ifa_ifwithroute(flags, sa, sa);
}
- if ((ifa = info->rti_ifa) != NULL) {
- if (info->rti_ifp == NULL)
- info->rti_ifp = ifa->ifa_ifp;
- } else
- error = ENETUNREACH;
- return (error);
+ if ((ifa = info->rti_ifa) == NULL)
+ return ENETUNREACH;
+ if (ifa->ifa_getifa != NULL)
+ info->rti_ifa = ifa = (*ifa->ifa_getifa)(ifa, dst);
+ if (info->rti_ifp == NULL)
+ info->rti_ifp = ifa->ifa_ifp;
+ return 0;
}
int
Index: sys/netinet/in.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/in.c,v
retrieving revision 1.101
diff -u -r1.101 in.c
--- sys/netinet/in.c 24 Jan 2005 21:25:09 -0000 1.101
+++ sys/netinet/in.c 19 Feb 2005 07:02:51 -0000
@@ -139,7 +139,7 @@
static void in_len2mask __P((struct in_addr *, u_int));
static int in_lifaddr_ioctl __P((struct socket *, u_long, caddr_t,
struct ifnet *, struct proc *));
-
+static struct ifaddr *in_getifa(struct ifaddr *, const struct sockaddr *);
static int in_addprefix __P((struct in_ifaddr *, int));
static int in_scrubprefix __P((struct in_ifaddr *));
@@ -402,6 +402,7 @@
ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
+ ia->ia_ifa.ifa_getifa = in_getifa;
ia->ia_sockmask.sin_len = 8;
if (ifp->if_flags & IFF_BROADCAST) {
ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
@@ -947,6 +948,8 @@
/*
* if we got a matching prefix route inserted by other
* interface address, we don't need to bother
+ *
+ * XXX RADIX_MPATH implications here? -dcy
*/
if (ia->ia_flags & IFA_ROUTE)
return 0;
@@ -1157,4 +1160,37 @@
}
splx(s);
}
+
+static struct ifaddr *
+in_getifa(struct ifaddr *ifa, const struct sockaddr *dst)
+{
+ int linklocal;
+ struct ifaddr *alt_ifa;
+
+#define LOGIC_EQ(__a, __b) (!(__a) == !(__b))
+#define SIN_ANY_LOCAL(__sin) IN_ANY_LOCAL((__sin)->sin_addr.s_addr)
+
+ if (ifa->ifa_addr->sa_family != AF_INET) /* XXX impossible? */
+ return ifa;
+ if (dst != NULL && dst->sa_family != AF_INET) /* does occur */
+ return ifa;
+
+ linklocal = (dst != NULL && SIN_ANY_LOCAL(satosin(dst)));
+
+ if (LOGIC_EQ(linklocal, SIN_ANY_LOCAL(satosin(ifa->ifa_addr))))
+ return ifa;
+
+ TAILQ_FOREACH(alt_ifa, &ifa->ifa_ifp->if_addrlist, ifa_list) {
+ const struct sockaddr *alt_sa = alt_ifa->ifa_addr;
+ if (alt_ifa == ifa)
+ continue;
+ if (alt_sa->sa_family != AF_INET)
+ continue;
+ if (LOGIC_EQ(linklocal, SIN_ANY_LOCAL(satosin(alt_sa))))
+ return alt_ifa;
+ }
+#undef SIN_ANY_LOCAL
+#undef LOGIC_EQ
+ return ifa;
+}
#endif
Index: sys/netinet/in.h
===================================================================
RCS file: /cvsroot/src/sys/netinet/in.h,v
retrieving revision 1.69
diff -u -r1.69 in.h
--- sys/netinet/in.h 15 Dec 2004 04:25:19 -0000 1.69
+++ sys/netinet/in.h 19 Feb 2005 07:02:51 -0000
@@ -168,6 +168,9 @@
#define __IPADDR(x) ((uint32_t)(x))
#endif
+#define IN_LINKLOCAL(i) (((uint32_t)(i) & __IPADDR(0xffff0000)) == \
+ __IPADDR(0xa9fe0000))
+
#define IN_CLASSA(i) (((uint32_t)(i) & __IPADDR(0x80000000)) == \
__IPADDR(0x00000000))
#define IN_CLASSA_NET __IPADDR(0xff000000)
@@ -204,6 +207,8 @@
#define IN_LOCAL_GROUP(i) (((uint32_t)(i) & __IPADDR(0xffffff00)) == \
__IPADDR(0xe0000000))
+#define IN_ANY_LOCAL(i) (IN_LINKLOCAL(i) || IN_LOCAL_GROUP(i))
+
#define INADDR_ANY __IPADDR(0x00000000)
#define INADDR_LOOPBACK __IPADDR(0x7f000001)
#define INADDR_BROADCAST __IPADDR(0xffffffff) /* must be masked */
Index: sys/netinet/in_pcb.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/in_pcb.c,v
retrieving revision 1.96
diff -u -r1.96 in_pcb.c
--- sys/netinet/in_pcb.c 29 Sep 2004 21:30:00 -0000 1.96
+++ sys/netinet/in_pcb.c 19 Feb 2005 07:02:52 -0000
@@ -1013,5 +1013,6 @@
}
}
}
+ ia = ifatoia((*ia->ia_ifa.ifa_getifa)(&ia->ia_ifa, sintosa(sin)));
return satosin(&ia->ia_addr);
}
--LQksG6bCIzRHxTLp--