📄 ripd.c
字号:
/* - is the metric valid (i.e., between 1 and 16, inclusive) */ if (! (rte->metric >= 1 && rte->metric <= 16)) { zlog_info ("Route's metric is not in the 1-16 range."); rip_peer_bad_route (from); continue; } /* RIPv1 does not have nexthop value. */ if (packet->version == RIPv1 && rte->nexthop.s_addr != 0) { zlog_info ("RIPv1 packet with nexthop value %s", inet_ntoa (rte->nexthop)); rip_peer_bad_route (from); continue; } /* That is, if the provided information is ignored, a possibly sub-optimal, but absolutely valid, route may be taken. If the received Next Hop is not directly reachable, it should be treated as 0.0.0.0. */ if (packet->version == RIPv2 && rte->nexthop.s_addr != 0) { u_int32_t addrval; /* Multicast address check. */ addrval = ntohl (rte->nexthop.s_addr); if (IN_CLASSD (addrval)) { zlog_info ("Nexthop %s is multicast address, skip this rte", inet_ntoa (rte->nexthop)); continue; } if (! if_lookup_address (rte->nexthop)) { struct route_node *rn; struct rip_info *rinfo; rn = route_node_match_ipv4 (rip->table, &rte->nexthop); if (rn) { rinfo = rn->info; if (rinfo->type == ZEBRA_ROUTE_RIP && rinfo->sub_type == RIP_ROUTE_RTE) { if (IS_RIP_DEBUG_EVENT) zlog_info ("Next hop %s is on RIP network. Set nexthop to the packet's originator", inet_ntoa (rte->nexthop)); rte->nexthop = rinfo->from; } else { if (IS_RIP_DEBUG_EVENT) zlog_info ("Next hop %s is not directly reachable. Treat it as 0.0.0.0", inet_ntoa (rte->nexthop)); rte->nexthop.s_addr = 0; } route_unlock_node (rn); } else { if (IS_RIP_DEBUG_EVENT) zlog_info ("Next hop %s is not directly reachable. Treat it as 0.0.0.0", inet_ntoa (rte->nexthop)); rte->nexthop.s_addr = 0; } } } /* For RIPv1, there won't be a valid netmask. This is a best guess at the masks. If everyone was using old Ciscos before the 'ip subnet zero' option, it would be almost right too :-) Cisco summarize ripv1 advertisments to the classful boundary (/16 for class B's) except when the RIP packet does to inside the classful network in question. */ if ((packet->version == RIPv1 && rte->prefix.s_addr != 0) || (packet->version == RIPv2 && (rte->prefix.s_addr != 0 && rte->mask.s_addr == 0))) { u_int32_t destination; destination = ntohl (rte->prefix.s_addr); if (destination & 0xff) { masklen2ip (32, &rte->mask); } else if ((destination & 0xff00) || IN_CLASSC (destination)) { masklen2ip (24, &rte->mask); } else if ((destination & 0xff0000) || IN_CLASSB (destination)) { masklen2ip (16, &rte->mask); } else { masklen2ip (8, &rte->mask); } } /* In case of RIPv2, if prefix in RTE is not netmask applied one ignore the entry. */ if ((packet->version == RIPv2) && (rte->mask.s_addr != 0) && ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)) { zlog_warn ("RIPv2 address %s is not mask /%d applied one", inet_ntoa (rte->prefix), ip_masklen (rte->mask)); rip_peer_bad_route (from); continue; } /* Default route's netmask is ignored. */ if (packet->version == RIPv2 && (rte->prefix.s_addr == 0) && (rte->mask.s_addr != 0)) { if (IS_RIP_DEBUG_EVENT) zlog_info ("Default route with non-zero netmask. Set zero to netmask"); rte->mask.s_addr = 0; } /* Routing table updates. */ rip_rte_process (rte, from, ifp); }}/* RIP packet send to destination address. */intrip_send_packet (caddr_t buf, int size, struct sockaddr_in *to, struct interface *ifp){ int ret; struct sockaddr_in sin; int sock; /* Make destination address. */ memset (&sin, 0, sizeof (struct sockaddr_in)); sin.sin_family = AF_INET;#ifdef HAVE_SIN_LEN sin.sin_len = sizeof (struct sockaddr_in);#endif /* HAVE_SIN_LEN */ /* When destination is specified, use it's port and address. */ if (to) { sock = rip->sock; sin.sin_port = to->sin_port; sin.sin_addr = to->sin_addr; } else { sock = socket (AF_INET, SOCK_DGRAM, 0); sockopt_broadcast (sock); sockopt_reuseaddr (sock); sockopt_reuseport (sock); sin.sin_port = htons (RIP_PORT_DEFAULT); sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP); /* Set multicast interface. */ rip_interface_multicast_set (sock, ifp); } ret = sendto (sock, buf, size, 0, (struct sockaddr *)&sin, sizeof (struct sockaddr_in)); if (IS_RIP_DEBUG_EVENT) zlog_info ("SEND to socket %d port %d addr %s", sock, ntohs (sin.sin_port), inet_ntoa(sin.sin_addr)); if (ret < 0) zlog_warn ("can't send packet : %s", strerror (errno)); if (! to) close (sock); return ret;}/* Add redistributed route to RIP table. */voidrip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p, unsigned int ifindex, struct in_addr *nexthop){ int ret; struct route_node *rp; struct rip_info *rinfo; /* Redistribute route */ ret = rip_destination_check (p->prefix); if (! ret) return; rp = route_node_get (rip->table, (struct prefix *) p); rinfo = rp->info; if (rinfo) { if (rinfo->type == ZEBRA_ROUTE_CONNECT && rinfo->sub_type == RIP_ROUTE_INTERFACE && rinfo->metric != RIP_METRIC_INFINITY) { route_unlock_node (rp); return; } /* Manually configured RIP route check. */ if (rinfo->type == ZEBRA_ROUTE_RIP && rinfo->sub_type == RIP_ROUTE_STATIC) { if (type != ZEBRA_ROUTE_RIP || sub_type != RIP_ROUTE_STATIC) { route_unlock_node (rp); return; } } RIP_TIMER_OFF (rinfo->t_timeout); RIP_TIMER_OFF (rinfo->t_garbage_collect); if (rip_route_rte (rinfo)) rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, &rinfo->nexthop, rinfo->metric); rp->info = NULL; rip_info_free (rinfo); route_unlock_node (rp); } rinfo = rip_info_new (); rinfo->type = type; rinfo->sub_type = sub_type; rinfo->ifindex = ifindex; rinfo->metric = 1; rinfo->rp = rp; if (nexthop) rinfo->nexthop = *nexthop; rinfo->flags |= RIP_RTF_FIB; rp->info = rinfo; rinfo->flags |= RIP_RTF_CHANGED; rip_event (RIP_TRIGGERED_UPDATE, 0);}/* Delete redistributed route from RIP table. */voidrip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p, unsigned int ifindex){ int ret; struct route_node *rp; struct rip_info *rinfo; ret = rip_destination_check (p->prefix); if (! ret) return; rp = route_node_lookup (rip->table, (struct prefix *) p); if (rp) { rinfo = rp->info; if (rinfo != NULL && rinfo->type == type && rinfo->sub_type == sub_type && rinfo->ifindex == ifindex) { /* Perform poisoned reverse. */ rinfo->metric = RIP_METRIC_INFINITY; RIP_TIMER_ON (rinfo->t_garbage_collect, rip_garbage_collect, rip->garbage_time); RIP_TIMER_OFF (rinfo->t_timeout); rinfo->flags |= RIP_RTF_CHANGED; rip_event (RIP_TRIGGERED_UPDATE, 0); } }}/* Response to request called from rip_read ().*/voidrip_request_process (struct rip_packet *packet, int size, struct sockaddr_in *from, struct interface *ifp){ caddr_t lim; struct rte *rte; struct prefix_ipv4 p; struct route_node *rp; struct rip_info *rinfo; struct rip_interface *ri; ri = ifp->info; /* When passive interface is specified, suppress responses */ if (ri->passive) return; /* RIP peer update. */ rip_peer_update (from, packet->version); lim = ((caddr_t) packet) + size; rte = packet->rte; /* The Request is processed entry by entry. If there are no entries, no response is given. */ if (lim == (caddr_t) rte) return; /* There is one special case. If there is exactly one entry in the request, and it has an address family identifier of zero and a metric of infinity (i.e., 16), then this is a request to send the entire routing table. */ if ((rte->family == 0xFFFF) && (lim == ((caddr_t) (rte + 2)) )) rte++; if (lim == ((caddr_t) (rte + 1)) && ntohs (rte->family) == 0 && ntohl (rte->metric) == RIP_METRIC_INFINITY) { /* All route with split horizon */ rip_output_process (ifp, from, rip_all_route, packet->version); } else { /* Examine the list of RTEs in the Request one by one. For each entry, look up the destination in the router's routing database and, if there is a route, put that route's metric in the metric field of the RTE. If there is no explicit route to the specified destination, put infinity in the metric field. Once all the entries have been filled in, change the command from Request to Response and send the datagram back to the requestor. */ p.family = AF_INET; for (; ((caddr_t) rte) < lim; rte++) { p.prefix = rte->prefix; p.prefixlen = ip_masklen (rte->mask); apply_mask_ipv4 (&p); rp = route_node_lookup (rip->table, (struct prefix *) &p); if (rp) { rinfo = rp->info; rte->metric = htonl (rinfo->metric); route_unlock_node (rp); } else rte->metric = htonl (RIP_METRIC_INFINITY); } packet->command = RIP_RESPONSE; rip_send_packet ((caddr_t) packet, size, from, ifp); } rip_global_queries++;}#if RIP_RECVMSG/* Set IPv6 packet info to the socket. */static intsetsockopt_pktinfo (int sock){ int ret; int val = 1; ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val)); if (ret < 0) zlog_warn ("Can't setsockopt IP_PKTINFO : %s", strerror (errno)); return ret;}/* Read RIP packet by recvmsg function. */intrip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from, int *ifindex){ int ret; struct msghdr msg; struct iovec iov; struct cmsghdr *ptr; char adata[1024]; msg.msg_name = (void *) from; msg.msg_namelen = sizeof (struct sockaddr_in); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = (void *) adata; msg.msg_controllen = sizeof adata; iov.iov_base = buf; iov.iov_len = size; ret = recvmsg (sock, &msg, 0); if (ret < 0) return ret; for (ptr = CMSG_FIRSTHDR(&msg); ptr != NULL; ptr = CMSG_NXTHDR(&msg, ptr)) if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_PKTINFO) { struct in_pktinfo *pktinfo; int i; pktinfo = (struct in_pktinfo *) CMSG_DATA (ptr); i = pktinfo->ipi_ifindex; } return ret;}/* RIP packet read function. */intrip_read_new (struct thread *t){ int ret; int sock; char buf[RIP_PACKET_MAXSIZ]; struct sockaddr_in from; unsigned int ifindex; /* Fetch socket then register myself. */ sock = THREAD_FD (t); rip_event (RIP_READ, sock); /* Read RIP packet. */ ret = rip_recvmsg (sock, buf, RIP_PACKET_MAXSIZ, &from, (int *)&ifindex); if (ret < 0) { zlog_warn ("Can't read RIP packet: %s", strerror (errno)); return ret; } return ret;}#endif /* RIP_RECVMSG *//* First entry point of RIP packet. */intrip_read (struct thread *t){ int sock; int ret; int rtenum; union rip_buf rip_buf; struct rip_packet *packet; struct sockaddr_in from; int fromlen, len; struct interface *ifp; struct rip_interface *ri; /* Fetch socket then register myself. */ sock = THREAD_FD (t); rip->t_read = NULL; /* Add myself to tne next event */ rip_event (RIP_READ, sock); /* RIPd manages only IPv4. */ memset (&from, 0, sizeof (struct sockaddr_in)); fromlen = sizeof (struct sockaddr_in); len = recvfrom (sock, (char *)&rip_buf.buf, sizeof (rip_buf.buf), 0, (struct sockaddr *) &from, &fromlen); if (len < 0) { zlog_info ("recvfrom failed: %s", strerror (errno)); return len; } /* Check is this packet comming from myself? */ if (if_check_address (from.sin_addr)) { if (IS_RIP_DEBUG_PACKET) zlog_warn ("ignore packet comes from myself"); return -1; } /* Which interface is this packet comes from. */ ifp = if_lookup_address (from.sin_addr); /* RIP packet received */ if (IS_RIP_DEBUG_EVENT) zlog_info ("RECV packet from %s port %d on %s", inet_ntoa (from.sin_addr), ntohs (from.sin_port), ifp ? ifp->name : "unknown"); /* If this packet come from unknown interface, ignore it. */ if (ifp == NULL) { zlog_info ("packet comes from unknown interface"); return -1; } /* Packet length check. */ if (len < RIP_PACKET_MINSIZ) { zlog_warn ("packet size %d is smaller than minimum size %d", len, RIP_PACKET_MINSIZ); rip_peer_bad_packet (&from);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -