Subject: Re: Bug in routing socket handling
To: Christos Zoulas <christos@zoulas.com>
From: Tom Ivar Helbekkmo <tih@eunetnorge.no>
List: tech-net
Date: 10/23/2004 20:35:17
christos@zoulas.com (Christos Zoulas) writes:

> I've looked at the FreeBSD and OpenBSD versions of rtsock.c and they
> don't make any special provisions either. How does asterix work there?

Well, if they don't allow RTM_GET with the RTA_IFP or RTA_IFA flags
set, it doesn't work in the case where it needs to listen to more than
one interface.  Asterisk then needs to ask the kernel what address
will be the source address when sending UDP packets to a specified
target (because the source address has to be embedded inside the SIP
packet sent), so this code snippet needs to work:

	memset(&m_rtmsg, 0, sizeof(m_rtmsg));
	m_rtmsg.m_rtm.rtm_type = RTM_GET;
	m_rtmsg.m_rtm.rtm_version = RTM_VERSION;
	m_rtmsg.m_rtm.rtm_seq = seq;
	m_rtmsg.m_rtm.rtm_addrs = RTA_DST | RTA_IFA;
	m_rtmsg.m_rtm.rtm_msglen = sizeof(struct rt_msghdr)
				 + sizeof(struct sockaddr_in);
	sin = (struct sockaddr_in *)m_rtmsg.m_space;
	sin->sin_family = AF_INET;
	sin->sin_len = sizeof(struct sockaddr_in);
	sin->sin_addr = *them;
	if (write(s, (char *)&m_rtmsg, m_rtmsg.m_rtm.rtm_msglen) < 0) {
		ast_log(LOG_ERROR, "Routing socket: %s\n", strerror(errno));
		close(s);
		return -1;
	}

...and then it goes on to read from the socket.  (Lines have been
removed from the above to make the relevant stuff more obvious.)
Note that the additition of RTA_IFA to RTA_DST is *not* accompanied
by an extra address supplied with the message.  This is legal, and
described by, e.g., W. Richard Stevens.  The code to handle this
special case is present in rtsock.c, from line 317, thus:

		report:
			dst = rt_key(rt);
			gate = rt->rt_gateway;
			netmask = rt_mask(rt);
			genmask = rt->rt_genmask;
			if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) {
				if ((ifp = rt->rt_ifp) != NULL) {
					ifpaddr = TAILQ_FIRST(&ifp->if_addrlist)->ifa_addr;
					ifaaddr = rt->rt_ifa->ifa_addr;
					if (ifp->if_flags & IFF_POINTOPOINT)
						brdaddr = rt->rt_ifa->ifa_dstaddr;
					else
						brdaddr = 0;
					rtm->rtm_index = ifp->if_index;
				} else {
					ifpaddr = 0;
					ifaaddr = 0;
				}
			}

The problem is that this code is never invoked, because the error
checking in rt_xaddrs() fails to allow for the special case that those
two particular "address information present" bits change meaning from
"present" to "wanted" in the case of an RTM_GET message.

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