summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorru <ru@FreeBSD.org>2001-03-18 13:04:07 +0000
committerru <ru@FreeBSD.org>2001-03-18 13:04:07 +0000
commit138742874459a589bb8a1e1be592285c1b9d3257 (patch)
treeaeed9dd38b26cf7ee4f57de4db738cd782f56997
parent03b7cd74e6403cfb2aec57ff1f063918582d9276 (diff)
downloadFreeBSD-src-138742874459a589bb8a1e1be592285c1b9d3257.zip
FreeBSD-src-138742874459a589bb8a1e1be592285c1b9d3257.tar.gz
Make sure the cached forwarding route (ipforward_rt) is still up before
using it. Not checking this may have caused the wrong IP address to be used when processing certain IP options (see example below). This also caused the wrong route to be passed to ip_output() when forwarding, but fortunately ip_output() is smart enough to detect this. This example demonstrates the wrong behavior of the Record Route option observed with this bug. Host ``freebsd'' is acting as the gateway for the ``sysv''. 1. On the gateway, we add the route to the destination. The new route will use the primary address of the loopback interface, 127.0.0.1: : freebsd# route add 10.0.0.66 -iface lo0 -reject : add host 10.0.0.66: gateway lo0 2. From the client, we ping the destination. We see the correct replies. Please note that this also causes the relevant route on the ``freebsd'' gateway to be cached in ipforward_rt variable: : sysv# ping -snv 10.0.0.66 : PING 10.0.0.66: 56 data bytes : ICMP Host Unreachable from gateway 192.168.0.115 : ICMP Host Unreachable from gateway 192.168.0.115 : ICMP Host Unreachable from gateway 192.168.0.115 : : ----10.0.0.66 PING Statistics---- : 3 packets transmitted, 0 packets received, 100% packet loss 3. On the gateway, we delete the route to the destination, thus making the destination reachable through the `default' route: : freebsd# route delete 10.0.0.66 : delete host 10.0.0.66 4. From the client, we ping destination again, now with the RR option turned on. The surprise here is the 127.0.0.1 in the first reply. This is caused by the bug in ip_rtaddr() not checking the cached route is still up befor use. The debug code also shows that the wrong (down) route is further passed to ip_output(). The latter detects that the route is down, and replaces the bogus route with the valid one, so we see the correct replies (192.168.0.115) on further probes: : sysv# ping -snRv 10.0.0.66 : PING 10.0.0.66: 56 data bytes : 64 bytes from 10.0.0.66: icmp_seq=0. time=10. ms : IP options: <record route> 127.0.0.1, 10.0.0.65, 10.0.0.66, : 192.168.0.65, 192.168.0.115, 192.168.0.120, : 0.0.0.0(Current), 0.0.0.0, 0.0.0.0 : 64 bytes from 10.0.0.66: icmp_seq=1. time=0. ms : IP options: <record route> 192.168.0.115, 10.0.0.65, 10.0.0.66, : 192.168.0.65, 192.168.0.115, 192.168.0.120, : 0.0.0.0(Current), 0.0.0.0, 0.0.0.0 : 64 bytes from 10.0.0.66: icmp_seq=2. time=0. ms : IP options: <record route> 192.168.0.115, 10.0.0.65, 10.0.0.66, : 192.168.0.65, 192.168.0.115, 192.168.0.120, : 0.0.0.0(Current), 0.0.0.0, 0.0.0.0 : : ----10.0.0.66 PING Statistics---- : 3 packets transmitted, 3 packets received, 0% packet loss : round-trip (ms) min/avg/max = 0/3/10
-rw-r--r--sys/netinet/ip_input.c26
1 files changed, 7 insertions, 19 deletions
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index 774d7da..7ee78dd 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -1344,7 +1344,9 @@ ip_rtaddr(dst)
sin = (struct sockaddr_in *) &ipforward_rt.ro_dst;
- if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) {
+ if (ipforward_rt.ro_rt == 0 ||
+ !(ipforward_rt.ro_rt->rt_flags & RTF_UP) ||
+ dst.s_addr != sin->sin_addr.s_addr) {
if (ipforward_rt.ro_rt) {
RTFREE(ipforward_rt.ro_rt);
ipforward_rt.ro_rt = 0;
@@ -1508,7 +1510,6 @@ ip_forward(m, srcrt)
int srcrt;
{
register struct ip *ip = mtod(m, struct ip *);
- register struct sockaddr_in *sin;
register struct rtentry *rt;
int error, type = 0, code = 0;
struct mbuf *mcopy;
@@ -1544,24 +1545,11 @@ ip_forward(m, srcrt)
}
#endif
- sin = (struct sockaddr_in *)&ipforward_rt.ro_dst;
- if ((rt = ipforward_rt.ro_rt) == 0 ||
- ip->ip_dst.s_addr != sin->sin_addr.s_addr) {
- if (ipforward_rt.ro_rt) {
- RTFREE(ipforward_rt.ro_rt);
- ipforward_rt.ro_rt = 0;
- }
- sin->sin_family = AF_INET;
- sin->sin_len = sizeof(*sin);
- sin->sin_addr = ip->ip_dst;
-
- rtalloc_ign(&ipforward_rt, RTF_PRCLONING);
- if (ipforward_rt.ro_rt == 0) {
- icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0);
- return;
- }
+ if (ip_rtaddr(ip->ip_dst) == 0) {
+ icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0);
+ return;
+ } else
rt = ipforward_rt.ro_rt;
- }
/*
* Save the IP header and at most 8 bytes of the payload,
OpenPOWER on IntegriCloud