Subject: Routing socket RTM_GET handling is broken
To: None <current-users@netbsd.org>
From: Tom Ivar Helbekkmo <tih@eunetnorge.no>
List: current-users
Date: 10/18/2004 09:50:53
Working with Asterisk (the open source IP telephony PBX) under
NetBSD-current, I've discovered that the routing socket handling in
sys/net/rtsock.c is slightly broken.  Specifically, it goes a bit too
far in its parameter checking, disallowing the old hack where an
RTM_GET (which can really only take one parameter, the destination
address) claims to supply interface information as well -- but what
this means, in that specific case, is that the client wants the kernel
to supply that information in the response message.

The code to do the work is present in rtsock.c, but sanity checking of
the request message prevents it from being invoked.  I've modified my
rtsock.c locally like this:

Index: sys/net/rtsock.c
===================================================================
RCS file: /cvsroot/src/sys/net/rtsock.c,v
retrieving revision 1.71
diff -u -r1.71 rtsock.c
--- sys/net/rtsock.c	25 May 2004 04:33:59 -0000	1.71
+++ sys/net/rtsock.c	18 Oct 2004 06:47:17 -0000
@@ -100,7 +100,7 @@
 
 static struct mbuf *rt_msg1(int, struct rt_addrinfo *, caddr_t, int);
 static int rt_msg2(int, struct rt_addrinfo *, caddr_t, struct walkarg *, int *);
-static int rt_xaddrs(const char *, const char *, struct rt_addrinfo *);
+static int rt_xaddrs(u_char, const char *, const char *, struct rt_addrinfo *);
 static int sysctl_dumpentry(struct radix_node *, void *);
 static int sysctl_iflist(int, struct walkarg *, int);
 static int sysctl_rtable(SYSCTLFN_PROTO);
@@ -235,7 +235,7 @@
 	rtm->rtm_pid = curproc->p_pid;
 	memset(&info, 0, sizeof(info));
 	info.rti_addrs = rtm->rtm_addrs;
-	if (rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info))
+	if (rt_xaddrs(rtm->rtm_type, (caddr_t)(rtm + 1), len + (caddr_t)rtm, &info))
 		senderr(EINVAL);
 	info.rti_flags = rtm->rtm_flags;
 	if (dst == 0 || (dst->sa_family >= AF_MAX))
@@ -470,7 +470,7 @@
 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
 
 static int
-rt_xaddrs(const char *cp, const char *cplim, struct rt_addrinfo *rtinfo)
+rt_xaddrs(u_char rtmtype, const char *cp, const char *cplim, struct rt_addrinfo *rtinfo)
 {
 	const struct sockaddr *sa = NULL;	/* Quell compiler warning */
 	int i;
@@ -482,9 +482,14 @@
 		ADVANCE(cp, sa);
 	}
 
-	/* Check for extra addresses specified.  */
-	if ((rtinfo->rti_addrs & (~0 << i)) != 0)
-		return (1);
+	/* Check for extra addresses specified, except RTM_GET asking for interface info.  */
+	if (rtmtype == RTM_GET) {
+		if (((rtinfo->rti_addrs & (~((1 << RTAX_IFP) | (1 << RTAX_IFA)))) & (~0 << i)) != 0)
+			return (1);
+	} else {
+		if ((rtinfo->rti_addrs & (~0 << i)) != 0)
+			return (1);
+	}
 	/* Check for bad data length.  */
 	if (cp != cplim) {
 		if (i == RTAX_NETMASK + 1 &&

With this patch in place, the requests written to the socket by
Asterisk, which wants the interface information, are handled correctly.

-tih
-- 
Tom Ivar Helbekkmo, Senior System Administrator, EUnet Norway Hosting
www.eunet.no  T +47-22092958 M +47-93013940 F +47-22092901 FWD 484145