From f761503760fba2d4124cc3352f5260c31fac526d Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Thu, 15 Mar 2012 12:23:49 +0100 Subject: [PATCH] Fixes RIPng socket and neighbor handling. RIPng did not really work because of link-local addresses. Thanks to Roman Hoog Antink for some notes. --- proto/rip/rip.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/proto/rip/rip.c b/proto/rip/rip.c index f0a41347..30d2267e 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -281,7 +281,7 @@ rip_rte_update_if_better(rtable *tab, net *net, struct proto *p, rte *new) * bird core with this route. */ static void -advertise_entry( struct proto *p, struct rip_block *b, ip_addr whotoldme ) +advertise_entry( struct proto *p, struct rip_block *b, ip_addr whotoldme, struct iface *iface ) { rta *a, A; rte *r; @@ -309,7 +309,7 @@ advertise_entry( struct proto *p, struct rip_block *b, ip_addr whotoldme ) /* No need to look if destination looks valid - ie not net 0 or 127 -- core will do for us. */ - neighbor = neigh_find( p, &A.gw, 0 ); + neighbor = neigh_find2( p, &A.gw, iface, 0 ); if (!neighbor) { log( L_REMOTE "%s: %I asked me to route %I/%d using not-neighbor %I.", p->name, A.from, b->network, pxlen, A.gw ); return; @@ -353,7 +353,7 @@ advertise_entry( struct proto *p, struct rip_block *b, ip_addr whotoldme ) * process_block - do some basic check and pass block to advertise_entry */ static void -process_block( struct proto *p, struct rip_block *block, ip_addr whotoldme ) +process_block( struct proto *p, struct rip_block *block, ip_addr whotoldme, struct iface *iface ) { #ifndef IPV6 int metric = ntohl( block->metric ); @@ -380,7 +380,7 @@ process_block( struct proto *p, struct rip_block *block, ip_addr whotoldme ) return; } - advertise_entry( p, block, whotoldme ); + advertise_entry( p, block, whotoldme, iface ); } #define BAD( x ) { log( L_REMOTE "%s: " x, p->name ); return 1; } @@ -389,7 +389,7 @@ process_block( struct proto *p, struct rip_block *block, ip_addr whotoldme ) * rip_process_packet - this is main routine for incoming packets. */ static int -rip_process_packet( struct proto *p, struct rip_packet *packet, int num, ip_addr whotoldme, int port ) +rip_process_packet( struct proto *p, struct rip_packet *packet, int num, ip_addr whotoldme, int port, struct iface *iface ) { int i; int authenticated = 0; @@ -406,7 +406,7 @@ rip_process_packet( struct proto *p, struct rip_packet *packet, int num, ip_addr if (P_CF->honor == HO_NEVER) BAD( "They asked me to send routing table, but I was told not to do it" ); - if ((P_CF->honor == HO_NEIGHBOR) && (!neigh_find( p, &whotoldme, 0 ))) + if ((P_CF->honor == HO_NEIGHBOR) && (!neigh_find2( p, &whotoldme, iface, 0 ))) BAD( "They asked me to send routing table, but he is not my neighbor" ); rip_sendto( p, whotoldme, port, HEAD(P->interfaces) ); /* no broadcast */ break; @@ -416,7 +416,7 @@ rip_process_packet( struct proto *p, struct rip_packet *packet, int num, ip_addr return 1; } - if (!(neighbor = neigh_find( p, &whotoldme, 0 )) || neighbor->scope == SCOPE_HOST) { + if (!(neighbor = neigh_find2( p, &whotoldme, iface, 0 )) || neighbor->scope == SCOPE_HOST) { log( L_REMOTE "%s: %I send me routing info but he is not my neighbor", p->name, whotoldme ); return 0; } @@ -443,7 +443,7 @@ rip_process_packet( struct proto *p, struct rip_packet *packet, int num, ip_addr if (packet->heading.version == RIP_V1) /* FIXME (nonurgent): switch to disable this? */ block->netmask = ipa_class_mask(block->network); #endif - process_block( p, block, whotoldme ); + process_block( p, block, whotoldme, iface ); } break; case RIPCMD_TRACEON: @@ -463,12 +463,20 @@ rip_rx(sock *s, int size) { struct rip_interface *i = s->data; struct proto *p = i->proto; + struct iface *iface = NULL; int num; /* In non-listening mode, just ignore packet */ if (i->mode & IM_NOLISTEN) return 1; +#ifdef IPV6 + if (! i->iface || s->lifindex != i->iface->index) + return 1; + + iface = i->iface; +#endif + CHK_MAGIC; DBG( "RIP: message came: %d bytes from %I via %s\n", size, s->faddr, i->iface ? i->iface->name : "(dummy)" ); size -= sizeof( struct rip_packet_heading ); @@ -477,17 +485,12 @@ rip_rx(sock *s, int size) num = size / sizeof( struct rip_block ); if (num>PACKET_MAX) BAD( "Too many blocks" ); -#ifdef IPV6 - /* Try to absolutize link scope addresses */ - ipa_absolutize(&s->faddr, &i->iface->addr->ip); -#endif - if (ipa_equal(i->iface->addr->ip, s->faddr)) { DBG("My own packet\n"); return 1; } - rip_process_packet( p, (struct rip_packet *) s->rbuf, num, s->faddr, s->fport ); + rip_process_packet( p, (struct rip_packet *) s->rbuf, num, s->faddr, s->fport, iface ); return 1; } @@ -701,6 +704,7 @@ new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_ { rif->sock->ttl = 1; rif->sock->tos = IP_PREC_INTERNET_CONTROL; + rif->sock->flags = SKF_LADDR_RX; } if (new) { @@ -712,7 +716,6 @@ new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_ rif->sock->daddr = ipa_from_u32(0xe0000009); #else rif->sock->daddr = ipa_build(0xff020000, 0, 0, 9); - rif->sock->saddr = new->addr->ip; /* Does not really work on Linux */ #endif } else { rif->sock->daddr = new->addr->brd;