summaryrefslogtreecommitdiffstats
path: root/ripd/ripd.c
diff options
context:
space:
mode:
Diffstat (limited to 'ripd/ripd.c')
-rw-r--r--ripd/ripd.c147
1 files changed, 112 insertions, 35 deletions
diff --git a/ripd/ripd.c b/ripd/ripd.c
index c017fe56..42974a72 100644
--- a/ripd/ripd.c
+++ b/ripd/ripd.c
@@ -36,10 +36,13 @@
#include "distribute.h"
#include "md5-gnu.h"
#include "keychain.h"
+#include "privs.h"
#include "ripd/ripd.h"
#include "ripd/rip_debug.h"
+extern struct zebra_privs_t ripd_privs;
+
/* RIP Structure. */
struct rip *rip = NULL;
@@ -55,8 +58,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 +958,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)
@@ -969,7 +979,7 @@ rip_response_process (struct rip_packet *packet, int size,
/* The datagram's IPv4 source address should be checked to see
whether the datagram is from a valid neighbor; the source of the
datagram must be on a directly connected network */
- if (! if_valid_neighbor (from->sin_addr))
+ if (if_lookup_address (from->sin_addr) == NULL)
{
zlog_info ("This datagram doesn't came from a valid neighbor: %s",
inet_ntoa (from->sin_addr));
@@ -1108,23 +1118,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 +1391,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
{
@@ -1500,7 +1538,7 @@ rip_read (struct thread *t)
}
/* Check is this packet comming from myself? */
- if (if_check_address (from.sin_addr))
+ if (if_lookup_exact_address (from.sin_addr))
{
if (IS_RIP_DEBUG_PACKET)
zlog_warn ("ignore packet comes from myself");
@@ -1785,13 +1823,17 @@ rip_create_socket ()
setsockopt_pktinfo (sock);
#endif /* RIP_RECVMSG */
+ if (ripd_privs.change (ZPRIVS_RAISE))
+ zlog_err ("rip_create_socket: could not raise privs");
ret = bind (sock, (struct sockaddr *) & addr, sizeof (addr));
if (ret < 0)
{
perror ("bind");
return ret;
}
-
+ if (ripd_privs.change (ZPRIVS_LOWER))
+ zlog_err ("rip_create_socket: could not lower privs");
+
return sock;
}
@@ -1884,8 +1926,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 +1936,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 +1991,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 +2185,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 +2212,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);
}
}
}
@@ -2161,7 +2238,7 @@ rip_update_process (int route_type)
if (if_is_loopback (ifp))
continue;
- if (! if_is_up (ifp))
+ if (! if_is_operative (ifp))
continue;
/* Fetch RIP interface information. */
@@ -2224,7 +2301,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);
}
}