📄 ripd.c
字号:
return len; } if (len > RIP_PACKET_MAXSIZ) { zlog_warn ("packet size %d is larger than max size %d", len, RIP_PACKET_MAXSIZ); rip_peer_bad_packet (&from); return len; } /* Packet alignment check. */ if ((len - RIP_PACKET_MINSIZ) % 20) { zlog_warn ("packet size %d is wrong for RIP packet alignment", len); rip_peer_bad_packet (&from); return len; } /* Set RTE number. */ rtenum = ((len - RIP_PACKET_MINSIZ) / 20); /* For easy to handle. */ packet = &rip_buf.rip_packet; /* RIP version check. */ if (packet->version == 0) { zlog_info ("version 0 with command %d received.", packet->command); rip_peer_bad_packet (&from); return -1; } /* Dump RIP packet. */ if (IS_RIP_DEBUG_RECV) rip_packet_dump (packet, len, "RECV"); /* RIP version adjust. This code should rethink now. RFC1058 says that "Version 1 implementations are to ignore this extra data and process only the fields specified in this document.". So RIPv3 packet should be treated as RIPv1 ignoring must be zero field. */ if (packet->version > RIPv2) packet->version = RIPv2; /* Is RIP running or is this RIP neighbor ?*/ ri = ifp->info; if (! ri->running && ! rip_neighbor_lookup (&from)) { if (IS_RIP_DEBUG_EVENT) zlog_info ("RIP is not enabled on interface %s.", ifp->name); rip_peer_bad_packet (&from); return -1; } /* RIP Version check. */ if (packet->command == RIP_RESPONSE) { if (ri->ri_receive == RI_RIP_UNSPEC) { if (packet->version != rip->version) { if (IS_RIP_DEBUG_PACKET) zlog_warn (" packet's v%d doesn't fit to my version %d", packet->version, rip->version); rip_peer_bad_packet (&from); return -1; } } else { if (packet->version == RIPv1) if (! (ri->ri_receive & RIPv1)) { if (IS_RIP_DEBUG_PACKET) zlog_warn (" packet's v%d doesn't fit to if version spec", packet->version); rip_peer_bad_packet (&from); return -1; } if (packet->version == RIPv2) if (! (ri->ri_receive & RIPv2)) { if (IS_RIP_DEBUG_PACKET) zlog_warn (" packet's v%d doesn't fit to if version spec", packet->version); rip_peer_bad_packet (&from); return -1; } } } /* RFC2453 5.2 If the router is not configured to authenticate RIP-2 messages, then RIP-1 and unauthenticated RIP-2 messages will be accepted; authenticated RIP-2 messages shall be discarded. */ if ((ri->auth_type == RIP_NO_AUTH) && rtenum && (packet->version == RIPv2) && (packet->rte->family == 0xffff)) { if (IS_RIP_DEBUG_EVENT) zlog_warn ("packet RIPv%d is dropped because authentication disabled", packet->version); rip_peer_bad_packet (&from); return -1; } /* If the router is configured to authenticate RIP-2 messages, then RIP-1 messages and RIP-2 messages which pass authentication testing shall be accepted; unauthenticated and failed authentication RIP-2 messages shall be discarded. For maximum security, RIP-1 messages should be ignored when authentication is in use (see section 4.1); otherwise, the routing information from authenticated messages will be propagated by RIP-1 routers in an unauthenticated manner. */ if ((ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD || ri->auth_type == RIP_AUTH_MD5) && rtenum) { /* We follow maximum security. */ if (packet->version == RIPv1 && packet->rte->family == 0xffff) { if (IS_RIP_DEBUG_PACKET) zlog_warn ("packet RIPv%d is dropped because authentication enabled", packet->version); rip_peer_bad_packet (&from); return -1; } /* Check RIPv2 authentication. */ if (packet->version == RIPv2) { if (packet->rte->family == 0xffff) { if (ntohs (packet->rte->tag) == RIP_AUTH_SIMPLE_PASSWORD) { ret = rip_auth_simple_password (packet->rte, &from, ifp); if (! ret) { if (IS_RIP_DEBUG_EVENT) zlog_warn ("RIPv2 simple password authentication failed"); rip_peer_bad_packet (&from); return -1; } else { if (IS_RIP_DEBUG_EVENT) zlog_info ("RIPv2 simple password authentication success"); } } else if (ntohs (packet->rte->tag) == RIP_AUTH_MD5) { ret = rip_auth_md5 (packet, &from, ifp); if (! ret) { if (IS_RIP_DEBUG_EVENT) zlog_warn ("RIPv2 MD5 authentication failed"); rip_peer_bad_packet (&from); return -1; } else { if (IS_RIP_DEBUG_EVENT) zlog_info ("RIPv2 MD5 authentication success"); } /* Reset RIP packet length to trim MD5 data. */ len = ret; } else { if (IS_RIP_DEBUG_EVENT) zlog_warn ("Unknown authentication type %d", ntohs (packet->rte->tag)); rip_peer_bad_packet (&from); return -1; } } else { /* There is no authentication in the packet. */ if (ri->auth_str || ri->key_chain) { if (IS_RIP_DEBUG_EVENT) zlog_warn ("RIPv2 authentication failed: no authentication in packet"); rip_peer_bad_packet (&from); return -1; } } } } /* Process each command. */ switch (packet->command) { case RIP_RESPONSE: rip_response_process (packet, len, &from, ifp); break; case RIP_REQUEST: case RIP_POLL: rip_request_process (packet, len, &from, ifp); break; case RIP_TRACEON: case RIP_TRACEOFF: zlog_info ("Obsolete command %s received, please sent it to routed", lookup (rip_msg, packet->command)); rip_peer_bad_packet (&from); break; case RIP_POLL_ENTRY: zlog_info ("Obsolete command %s received", lookup (rip_msg, packet->command)); rip_peer_bad_packet (&from); break; default: zlog_info ("Unknown RIP command %d received", packet->command); rip_peer_bad_packet (&from); break; } return len;}/* Make socket for RIP protocol. */int rip_create_socket (){ int ret; int sock; struct sockaddr_in addr; struct servent *sp; memset (&addr, 0, sizeof (struct sockaddr_in)); /* Set RIP port. */ sp = getservbyname ("router", "udp"); if (sp) addr.sin_port = sp->s_port; else addr.sin_port = htons (RIP_PORT_DEFAULT); /* Address shoud be any address. */ addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; /* Make datagram socket. */ sock = socket (AF_INET, SOCK_DGRAM, 0); if (sock < 0) { perror ("socket"); exit (1); } sockopt_broadcast (sock); sockopt_reuseaddr (sock); sockopt_reuseport (sock);#ifdef RIP_RECVMSG setsockopt_pktinfo (sock);#endif /* RIP_RECVMSG */ ret = bind (sock, (struct sockaddr *) & addr, sizeof (addr)); if (ret < 0) { perror ("bind"); return ret; } return sock;}/* Write routing table entry to the stream and return next index of the routing table entry in the stream. */intrip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p, u_char version, struct rip_info *rinfo, struct interface *ifp){ struct in_addr mask; struct rip_interface *ri; /* RIP packet header. */ if (num == 0) { stream_putc (s, RIP_RESPONSE); stream_putc (s, version); stream_putw (s, 0); /* In case of we need RIPv2 authentication. */ if (version == RIPv2 && ifp) { ri = ifp->info; if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD) { if (ri->auth_str) { stream_putw (s, 0xffff); stream_putw (s, RIP_AUTH_SIMPLE_PASSWORD); memset ((s->data + s->putp), 0, 16); strncpy ((s->data + s->putp), ri->auth_str, 16); stream_set_putp (s, s->putp + 16); num++; } if (ri->key_chain) { struct keychain *keychain; struct key *key; keychain = keychain_lookup (ri->key_chain); if (keychain) { key = key_lookup_for_send (keychain); if (key) { stream_putw (s, 0xffff); stream_putw (s, RIP_AUTH_SIMPLE_PASSWORD); memset ((s->data + s->putp), 0, 16); strncpy ((s->data + s->putp), key->string, 16); stream_set_putp (s, s->putp + 16); num++; } } } } } } /* Write routing table entry. */ if (version == RIPv1) { stream_putw (s, AF_INET); stream_putw (s, 0); stream_put_ipv4 (s, p->prefix.s_addr); stream_put_ipv4 (s, 0); stream_put_ipv4 (s, 0); stream_putl (s, rinfo->metric_out); } else { masklen2ip (p->prefixlen, &mask); stream_putw (s, AF_INET); stream_putw (s, rinfo->tag); stream_put_ipv4 (s, p->prefix.s_addr); stream_put_ipv4 (s, mask.s_addr); stream_put_ipv4 (s, rinfo->nexthop_out.s_addr); stream_putl (s, rinfo->metric_out); } return ++num;}/* Send update to the ifp or spcified neighbor. */voidrip_output_process (struct interface *ifp, struct sockaddr_in *to, int route_type, u_char version){ int ret; struct stream *s; struct route_node *rp; struct rip_info *rinfo; struct rip_interface *ri; struct prefix_ipv4 *p; struct prefix_ipv4 classfull; int num; int rtemax; /* Logging output event. */ if (IS_RIP_DEBUG_EVENT) { if (to) zlog_info ("update routes to neighbor %s", inet_ntoa (to->sin_addr)); else zlog_info ("update routes on interface %s ifindex %d", ifp->name, ifp->ifindex); } /* Set output stream. */ s = rip->obuf; /* Reset stream and RTE counter. */ stream_reset (s); num = 0; rtemax = (RIP_PACKET_MAXSIZ - 4) / 20; /* Get RIP interface. */ ri = ifp->info; /* If output interface is in simple password authentication mode, we need space for authentication data. */ if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD) rtemax -= 1; /* If output interface is in MD5 authentication mode, we need space for authentication header and data. */ if (ri->auth_type == RIP_AUTH_MD5) rtemax -= 2; /* If output interface is in simple password authentication mode and string or keychain is specified we need space for auth. data */ if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD) { if (ri->key_chain) { struct keychain *keychain; keychain = keychain_lookup (ri->key_chain); if (keychain) if (key_lookup_for_send (keychain)) rtemax -=1; } else if (ri->auth_str) rtemax -=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 :) */ if (version == RIPv1) { memcpy (&classfull, &rp->p, sizeof (struct prefix_ipv4)); 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; if (IS_RIP_DEBUG_PACKET) zlog_info("%s/%d after RIPv1 mask check", inet_ntoa (p->prefix), p->prefixlen); } else p = (struct prefix_ipv4 *) &rp->p; /* Apply output filters. */ ret = rip_outgoing_filter (p, ri); if (ret < 0) continue; /* Changed route only output. */ if (route_type == rip_changed_route && (! (rinfo->flags & RIP_RTF_CHANGED))) continue; /* Split horizon. */ /* if (split_horizon == rip_split_horizon) */ if (ri->split_horizon) { /* We perform split horizon for RIP and connected route. */ if ((rinfo->type == ZEBRA_ROUTE_RIP || rinfo->type == ZEBRA_ROUTE_CONNECT) && rinfo->ifindex == ifp->ifindex) continue; } /* Preparation for route-map. */ rinfo->metric_set = 0; rinfo->nexthop_out.s_addr = 0; rinfo->metric_out = rinfo->metric; rinfo->ifindex_out = ifp->ifindex; /* In order to avoid some local loops, if the RIP route has a nexthop via this interface, keep the nexthop, otherwise set it to 0. The nexthop should not be propagated beyond the local broadcast/multicast area in order to avoid an IGP multi-level recursive look-up. For RIP and connected route, we don't set next hop value automatically. For settting next hop to those routes, please use route-map. */ if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT && rinfo->ifindex == ifp->ifindex) rinfo->nexthop_out = rinfo->nexthop; /* Apply route map - continue, if deny */ if (rip->route_map[rinfo->type].name && rinfo->sub_type != RIP_ROUTE_INTERFACE) { ret = route_map_apply (rip->route_map[rinfo->type].map, (struct prefix *)p, RMAP_RIP, rinfo); if (ret == RMAP_DENYMATCH) { if (IS_RIP_DEBUG_PACKET) zlog_info ("%s/%d is filtered by route-map", inet_ntoa (p->prefix), p->prefixlen); continue; } } /* When route-map does not set metric. */ if (! rinfo->metric_set) { /* If redistribute metric is set. */ if (rip->route_map[rinfo->type].metric_config && rinfo->metric != RIP_METRIC_INFINITY) { rinfo->metric_out = rip->route_map[rinfo->type].metric; } else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -