From 727d104b15d6293d7223e7830f2e37ae98022cac Mon Sep 17 00:00:00 2001 From: paul Date: Fri, 13 Dec 2002 20:50:29 +0000 Subject: Added RIPv1 patch - bug fixes and improved/more interoperable classful subnet handling --- lib/if.c | 59 +++++++++++++++++++++++++++ lib/if.h | 1 + ripd/ripd.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 161 insertions(+), 31 deletions(-) diff --git a/lib/if.c b/lib/if.c index bbf22ab1..0934e40d 100644 --- a/lib/if.c +++ b/lib/if.c @@ -553,6 +553,65 @@ connected_delete_by_prefix (struct interface *ifp, struct prefix *p) return NULL; } +/* Find the IPv4 address on our side that will be used when packets + are sent to dst. */ +struct connected * +connected_lookup_address (struct interface *ifp, struct in_addr dst) +{ + struct prefix addr; + struct prefix best; + listnode cnode; + struct prefix *p; + struct connected *c; + struct connected *match; + + /* Zero structures - get rid of rubbish from stack */ + memset(&addr, 0, sizeof(addr)); + memset(&best, 0, sizeof(best)); + + addr.family = AF_INET; + addr.u.prefix4 = dst; + addr.prefixlen = IPV4_MAX_BITLEN; + + match = NULL; + + for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) + { + c = getdata (cnode); + + if (if_is_pointopoint (ifp)) + { + p = c->address; + + if (p && p->family == AF_INET) + { +#ifdef OLD_RIB /* PTP links are conventionally identified + by the address of the far end - MAG */ + if (IPV4_ADDR_SAME (&p->u.prefix4, &dst)) + return c; +#endif + p = c->destination; + if (p && IPV4_ADDR_SAME (&p->u.prefix4, &dst)) + return c; + } + } + else + { + p = c->address; + + if (p->family == AF_INET) + { + if (prefix_match (p, &addr) && p->prefixlen > best.prefixlen) + { + best = *p; + match = c; + } + } + } + } + return match; +} + /* Check the connected information is PtP style or not. */ int ifc_pointopoint (struct connected *ifc) diff --git a/lib/if.h b/lib/if.h index 3896d187..55337fc4 100644 --- a/lib/if.h +++ b/lib/if.h @@ -202,6 +202,7 @@ struct connected *connected_new (); void connected_free (struct connected *); void connected_add (struct interface *, struct connected *); struct connected *connected_delete_by_prefix (struct interface *, struct prefix *); +struct connected *connected_lookup_address (struct interface *, struct in_addr); int ifc_pointopoint (struct connected *); #ifndef HAVE_IF_NAMETOINDEX diff --git a/ripd/ripd.c b/ripd/ripd.c index c017fe56..3c55479d 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -55,8 +55,8 @@ long rip_global_queries = 0; /* Prototypes. */ void rip_event (enum rip_event, int); -void rip_output_process (struct interface *, struct sockaddr_in *, - int, u_char); +void rip_output_process (struct interface *, struct prefix *, + struct sockaddr_in *, int, u_char); /* RIP output routes type. */ enum @@ -955,7 +955,14 @@ rip_response_process (struct rip_packet *packet, int size, { caddr_t lim; struct rte *rte; + struct prefix_ipv4 ifaddr; + struct prefix_ipv4 ifaddrclass; + struct connected *c; + int subnetted; + /* We don't know yet. */ + subnetted = -1; + /* The Response must be ignored if it is not from the RIP port. (RFC2453 - Sec. 3.9.2)*/ if (ntohs (from->sin_port) != RIP_PORT_DEFAULT) @@ -1108,23 +1115,51 @@ rip_response_process (struct rip_packet *packet, int size, { u_int32_t destination; - destination = ntohl (rte->prefix.s_addr); - - if (destination & 0xff) + if (subnetted == -1) { - masklen2ip (32, &rte->mask); + c = connected_lookup_address (ifp, from->sin_addr); + if (c != NULL) + { + memcpy (&ifaddr, c->address, sizeof (struct prefix_ipv4)); + memcpy (&ifaddrclass, &ifaddr, sizeof (struct prefix_ipv4)); + apply_classful_mask_ipv4 (&ifaddrclass); + subnetted = 0; + if (ifaddr.prefixlen > ifaddrclass.prefixlen) + subnetted = 1; + } } - else if ((destination & 0xff00) || IN_CLASSC (destination)) - { + + destination = ntohl (rte->prefix.s_addr); + + if (IN_CLASSA (destination)) + masklen2ip (8, &rte->mask); + else if (IN_CLASSB (destination)) + masklen2ip (16, &rte->mask); + else if (IN_CLASSC (destination)) masklen2ip (24, &rte->mask); + + if (subnetted == 1) + masklen2ip (ifaddrclass.prefixlen, + (struct in_addr *) &destination); + if ((subnetted == 1) && ((rte->prefix.s_addr & destination) == + ifaddrclass.prefix.s_addr)) + { + masklen2ip (ifaddr.prefixlen, &rte->mask); + if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr) + masklen2ip (32, &rte->mask); + if (IS_RIP_DEBUG_EVENT) + zlog_info ("Subnetted route %s", inet_ntoa (rte->prefix)); } - else if ((destination & 0xff0000) || IN_CLASSB (destination)) + else { - masklen2ip (16, &rte->mask); + if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr) + continue; } - else + + if (IS_RIP_DEBUG_EVENT) { - masklen2ip (8, &rte->mask); + zlog_info ("Resultant route %s", inet_ntoa (rte->prefix)); + zlog_info ("Resultant mask %s", inet_ntoa (rte->mask)); } } @@ -1353,7 +1388,7 @@ rip_request_process (struct rip_packet *packet, int size, ntohl (rte->metric) == RIP_METRIC_INFINITY) { /* All route with split horizon */ - rip_output_process (ifp, from, rip_all_route, packet->version); + rip_output_process (ifp, NULL, from, rip_all_route, packet->version); } else { @@ -1884,8 +1919,8 @@ rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p, /* Send update to the ifp or spcified neighbor. */ void -rip_output_process (struct interface *ifp, struct sockaddr_in *to, - int route_type, u_char version) +rip_output_process (struct interface *ifp, struct prefix *ifaddr, + struct sockaddr_in *to, int route_type, u_char version) { int ret; struct stream *s; @@ -1894,8 +1929,11 @@ rip_output_process (struct interface *ifp, struct sockaddr_in *to, struct rip_interface *ri; struct prefix_ipv4 *p; struct prefix_ipv4 classfull; + struct prefix_ipv4 ifaddrclass; + struct connected *c; int num; int rtemax; + int subnetted; /* Logging output event. */ if (IS_RIP_DEBUG_EVENT) @@ -1946,29 +1984,60 @@ rip_output_process (struct interface *ifp, struct sockaddr_in *to, rtemax -=1; } + if (version == RIPv1) + { + if (ifaddr == NULL) + { + c = connected_lookup_address (ifp, to->sin_addr); + if (c != NULL) + ifaddr = c->address; + } + if (ifaddr == NULL) + { + zlog_warn ("cannot find source address for packets to neighbor %s", + inet_ntoa (to->sin_addr)); + return; + } + memcpy (&ifaddrclass, ifaddr, sizeof (struct prefix_ipv4)); + apply_classful_mask_ipv4 (&ifaddrclass); + subnetted = 0; + if (ifaddr->prefixlen > ifaddrclass.prefixlen) + subnetted = 1; + } + for (rp = route_top (rip->table); rp; rp = route_next (rp)) if ((rinfo = rp->info) != NULL) { - /* Some inheritance stuff: */ - /* Before we process with ipv4 prefix we should mask it */ - /* with Classful mask if we send RIPv1 packet.That's because */ - /* user could set non-classful mask or we could get it by RIPv2 */ - /* or other protocol. checked with Cisco's way of life :) */ + /* For RIPv1, if we are subnetted, output subnets in our network */ + /* that have the same mask as the output "interface". For other */ + /* networks, only the classfull version is output. */ if (version == RIPv1) { - memcpy (&classfull, &rp->p, sizeof (struct prefix_ipv4)); + p = (struct prefix_ipv4 *) &rp->p; if (IS_RIP_DEBUG_PACKET) - zlog_info("%s/%d before RIPv1 mask check ", - inet_ntoa (classfull.prefix), classfull.prefixlen); - - apply_classful_mask_ipv4 (&classfull); - p = &classfull; + zlog_info("RIPv1 mask check, %s/%d considered for output", + inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen); + if (subnetted && + prefix_match ((struct prefix *) &ifaddrclass, &rp->p)) + { + if ((ifaddr->prefixlen != rp->p.prefixlen) && + (rp->p.prefixlen != 32)) + continue; + } + else + { + memcpy (&classfull, &rp->p, sizeof(struct prefix_ipv4)); + apply_classful_mask_ipv4(&classfull); + if (rp->p.u.prefix4.s_addr != 0 && + classfull.prefixlen != rp->p.prefixlen) + continue; + } if (IS_RIP_DEBUG_PACKET) - zlog_info("%s/%d after RIPv1 mask check", - inet_ntoa (p->prefix), p->prefixlen); + zlog_info("RIPv1 mask check, %s/%d made it through", + inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen); } else p = (struct prefix_ipv4 *) &rp->p; @@ -2109,7 +2178,7 @@ rip_update_interface (struct interface *ifp, u_char version, int route_type) if (IS_RIP_DEBUG_EVENT) zlog_info ("multicast announce on %s ", ifp->name); - rip_output_process (ifp, NULL, route_type, version); + rip_output_process (ifp, NULL, NULL, route_type, version); return; } @@ -2136,7 +2205,8 @@ rip_update_interface (struct interface *ifp, u_char version, int route_type) if_is_pointopoint (ifp) ? "unicast" : "broadcast", inet_ntoa (to.sin_addr), ifp->name); - rip_output_process (ifp, &to, route_type, version); + rip_output_process (ifp, connected->address, &to, route_type, + version); } } } @@ -2224,7 +2294,7 @@ rip_update_process (int route_type) to.sin_port = htons (RIP_PORT_DEFAULT); /* RIP version is rip's configuration. */ - rip_output_process (ifp, &to, route_type, rip->version); + rip_output_process (ifp, NULL, &to, route_type, rip->version); } } -- cgit v1.2.1