void add_ptopt_localrt(struct interface *ifp) { struct rt_entry *rt; struct sockaddr *dst; struct sockaddr_in net; int state; state = RTS_INTERFACE | RTS_PASSIVE; /* look for route to logical network */ memset(&net, 0, sizeof (net)); net.sin_family = AF_INET; net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY); dst = (struct sockaddr *)&net; rt = rtfind(dst); if (rt && rt->rt_state & RTS_INTERNAL) state |= RTS_SUBNET; dst = &ifp->int_addr; if ((rt = rtfind(dst))!=NULL) { if (rt && rt->rt_state & RTS_INTERFACE) return; rtdelete(rt); } rtadd(dst, &loopaddr, 1, state); }
void addrouteforif(struct interface *ifp) { struct sockaddr_in net; struct sockaddr *dst; int state; struct rt_entry *rt; if (ifp->int_flags & IFF_POINTOPOINT) dst = &ifp->int_dstaddr; else { memset(&net, 0, sizeof (net)); net.sin_family = AF_INET; net.sin_addr = inet_makeaddr(ifp->int_subnet, INADDR_ANY); dst = (struct sockaddr *)&net; } rt = rtfind(dst); if (rt && (rt->rt_state & (RTS_INTERFACE | RTS_INTERNAL)) == RTS_INTERFACE) return; if (rt) rtdelete(rt); /* * If interface on subnetted network, * install route to network as well. * This is meant for external viewers. */ if ((ifp->int_flags & (IFF_SUBNET|IFF_POINTOPOINT)) == IFF_SUBNET) { struct in_addr subnet; subnet = net.sin_addr; net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY); rt = rtfind(dst); if (rt == 0) rtadd(dst, &ifp->int_addr, ifp->int_metric, ((ifp->int_flags & (IFF_INTERFACE|IFF_REMOTE)) | RTS_PASSIVE | RTS_INTERNAL | RTS_SUBNET)); else if ((rt->rt_state & (RTS_INTERNAL|RTS_SUBNET)) == (RTS_INTERNAL|RTS_SUBNET) && ifp->int_metric < rt->rt_metric) rtchange(rt, &rt->rt_router, ifp->int_metric); net.sin_addr = subnet; } if (ifp->int_transitions++ > 0) syslog(LOG_ERR, "re-installing interface %s", ifp->int_name); state = ifp->int_flags & (IFF_INTERFACE | IFF_PASSIVE | IFF_REMOTE | IFF_SUBNET); if (ifp->int_flags & IFF_POINTOPOINT && (ntohl(((struct sockaddr_in *)&ifp->int_dstaddr)->sin_addr.s_addr) & ifp->int_netmask) != ifp->int_net) state &= ~RTS_SUBNET; if (ifp->int_flags & IFF_LOOPBACK) state |= RTS_EXTERNAL; rtadd(dst, &ifp->int_addr, ifp->int_metric, state); if (ifp->int_flags & IFF_POINTOPOINT && foundloopback) add_ptopt_localrt(ifp); }
/* Supply dst with the contents of the routing tables. * If this won't fit in one packet, chop it up into several. */ void supply(struct sockaddr_in *dst, struct interface *ifp, /* output interface */ enum output_type type, int flash, /* 1=flash update */ int vers, /* RIP version */ int passwd_ok) /* OK to include cleartext password */ { struct rt_entry *rt; int def_metric; ws.state = 0; ws.gen_limit = 1024; ws.to = *dst; ws.to_std_mask = std_mask(ws.to.sin_addr.s_addr); ws.to_std_net = ntohl(ws.to.sin_addr.s_addr) & ws.to_std_mask; if (ifp != NULL) { ws.to_mask = ifp->int_mask; ws.to_net = ifp->int_net; if (on_net(ws.to.sin_addr.s_addr, ws.to_net, ws.to_mask)) ws.state |= WS_ST_TO_ON_NET; } else { ws.to_mask = ripv1_mask_net(ws.to.sin_addr.s_addr, 0); ws.to_net = ntohl(ws.to.sin_addr.s_addr) & ws.to_mask; rt = rtfind(dst->sin_addr.s_addr); if (rt) ifp = rt->rt_ifp; } ws.npackets = 0; if (flash) ws.state |= WS_ST_FLASH; if ((ws.ifp = ifp) == NULL) { ws.metric = 1; } else { /* Adjust the advertised metric by the outgoing interface * metric. */ ws.metric = ifp->int_metric+1; } ripv12_buf.rip.rip_vers = vers; switch (type) { case OUT_MULTICAST: if (ifp->int_if_flags & IFF_MULTICAST) v2buf.type = OUT_MULTICAST; else v2buf.type = NO_OUT_MULTICAST; v12buf.type = OUT_BROADCAST; break; case OUT_QUERY: ws.state |= WS_ST_QUERY; /* fall through */ case OUT_BROADCAST: case OUT_UNICAST: v2buf.type = (vers == RIPv2) ? type : NO_OUT_RIPV2; v12buf.type = type; break; case NO_OUT_MULTICAST: case NO_OUT_RIPV2: break; /* no output */ } if (vers == RIPv2) { /* full RIPv2 only if cannot be heard by RIPv1 listeners */ if (type != OUT_BROADCAST) ws.state |= WS_ST_RIP2_ALL; if ((ws.state & WS_ST_QUERY) || !(ws.state & WS_ST_TO_ON_NET)) { ws.state |= (WS_ST_AG | WS_ST_SUPER_AG); } else if (ifp == NULL || !(ifp->int_state & IS_NO_AG)) { ws.state |= WS_ST_AG; if (type != OUT_BROADCAST && (ifp == NULL || !(ifp->int_state & IS_NO_SUPER_AG))) ws.state |= WS_ST_SUPER_AG; } } ws.a = (vers == RIPv2) ? find_auth(ifp) : 0; if (!passwd_ok && ws.a != NULL && ws.a->type == RIP_AUTH_PW) ws.a = NULL; clr_ws_buf(&v12buf,ws.a); clr_ws_buf(&v2buf,ws.a); /* Fake a default route if asked and if there is not already * a better, real default route. */ if (supplier && (def_metric = ifp->int_d_metric) != 0) { if (NULL == (rt = rtget(RIP_DEFAULT, 0)) || rt->rt_metric+ws.metric >= def_metric) { ws.state |= WS_ST_DEFAULT; ag_check(0, 0, 0, 0, def_metric, def_metric, 0, 0, 0, supply_out); } else { def_metric = rt->rt_metric+ws.metric; } /* If both RIPv2 and the poor-man's router discovery * kludge are on, arrange to advertise an extra * default route via RIPv1. */ if ((ws.state & WS_ST_RIP2_ALL) && (ifp->int_state & IS_PM_RDISC)) { ripv12_buf.rip.rip_vers = RIPv1; v12buf.n->n_family = RIP_AF_INET; v12buf.n->n_dst = htonl(RIP_DEFAULT); v12buf.n->n_metric = htonl(def_metric); v12buf.n++; } } rn_walktree(rhead, walk_supply, 0); ag_flush(0,0,supply_out); /* Flush the packet buffers, provided they are not empty and * do not contain only the password. */ if (v12buf.n != v12buf.base && (v12buf.n > v12buf.base+1 || v12buf.base->n_family != RIP_AF_AUTH)) supply_write(&v12buf); if (v2buf.n != v2buf.base && (v2buf.n > v2buf.base+1 || v2buf.base->n_family != RIP_AF_AUTH)) supply_write(&v2buf); /* If we sent nothing and this is an answer to a query, send * an empty buffer. */ if (ws.npackets == 0 && (ws.state & WS_ST_QUERY)) supply_write(&v12buf); }