📄 ripd.c
字号:
/* If there is an existing route, compare the next hop address to the address of the router from which the datagram came. If this datagram is from the same router as the existing route, reinitialize the timeout. */ same = IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr); if (same) rip_timeout_update (rinfo); /* Next, compare the metrics. If the datagram is from the same router as the existing route, and the new metric is different than the old one; or, if the new metric is lower than the old one; do the following actions: */ if ((same && rinfo->metric != rte->metric) || rte->metric < rinfo->metric) { /* - Adopt the route from the datagram. That is, put the new metric in, and adjust the next hop address (if necessary). */ oldmetric = rinfo->metric; rinfo->metric = rte->metric; rinfo->tag = ntohs (rte->tag); IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr); rinfo->ifindex = ifp->ifindex; rinfo->distance = rip_distance_apply (rinfo); /* Should a new route to this network be established while the garbage-collection timer is running, the new route will replace the one that is about to be deleted. In this case the garbage-collection timer must be cleared. */ if (oldmetric == RIP_METRIC_INFINITY && rinfo->metric < RIP_METRIC_INFINITY) { rinfo->type = ZEBRA_ROUTE_RIP; rinfo->sub_type = RIP_ROUTE_RTE; RIP_TIMER_OFF (rinfo->t_garbage_collect); if (! IPV4_ADDR_SAME (&rinfo->nexthop, nexthop)) IPV4_ADDR_COPY (&rinfo->nexthop, nexthop); rip_zebra_ipv4_add (&p, nexthop, rinfo->metric, rinfo->distance); rinfo->flags |= RIP_RTF_FIB; } /* Update nexthop and/or metric value. */ if (oldmetric != RIP_METRIC_INFINITY) { rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric); rip_zebra_ipv4_add (&p, nexthop, rinfo->metric, rinfo->distance); rinfo->flags |= RIP_RTF_FIB; if (! IPV4_ADDR_SAME (&rinfo->nexthop, nexthop)) IPV4_ADDR_COPY (&rinfo->nexthop, nexthop); } /* - Set the route change flag and signal the output process to trigger an update. */ rinfo->flags |= RIP_RTF_CHANGED; rip_event (RIP_TRIGGERED_UPDATE, 0); /* - If the new metric is infinity, start the deletion process (described above); */ if (rinfo->metric == RIP_METRIC_INFINITY) { /* If the new metric is infinity, the deletion process begins for the route, which is no longer used for routing packets. Note that the deletion process is started only when the metric is first set to infinity. If the metric was already infinity, then a new deletion process is not started. */ if (oldmetric != RIP_METRIC_INFINITY) { /* - The garbage-collection timer is set for 120 seconds. */ RIP_TIMER_ON (rinfo->t_garbage_collect, rip_garbage_collect, rip->garbage_time); RIP_TIMER_OFF (rinfo->t_timeout); /* - The metric for the route is set to 16 (infinity). This causes the route to be removed from service.*/ rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric); rinfo->flags &= ~RIP_RTF_FIB; /* - The route change flag is to indicate that this entry has been changed. */ /* - The output process is signalled to trigger a response. */ ; /* Above processes are already done previously. */ } } else { /* otherwise, re-initialize the timeout. */ rip_timeout_update (rinfo); } } /* Unlock tempolary lock of the route. */ route_unlock_node (rp); }}/* Dump RIP packet */voidrip_packet_dump (struct rip_packet *packet, int size, char *sndrcv){ caddr_t lim; struct rte *rte; char *command_str; char pbuf[BUFSIZ], nbuf[BUFSIZ]; u_char netmask = 0; u_char *p; /* Set command string. */ if (packet->command > 0 && packet->command < RIP_COMMAND_MAX) command_str = lookup (rip_msg, packet->command); else command_str = "unknown"; /* Dump packet header. */ zlog_info ("%s %s version %d packet size %d", sndrcv, command_str, packet->version, size); /* Dump each routing table entry. */ rte = packet->rte; for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++) { if (packet->version == RIPv2) { netmask = ip_masklen (rte->mask); if (ntohs (rte->family) == 0xffff) { if (ntohs (rte->tag) == RIP_AUTH_SIMPLE_PASSWORD) { p = (u_char *)&rte->prefix; zlog_info (" family 0x%X type %d auth string: %s", ntohs (rte->family), ntohs (rte->tag), p); } else if (ntohs (rte->tag) == RIP_AUTH_MD5) { struct rip_md5_info *md5; md5 = (struct rip_md5_info *) &packet->rte; zlog_info (" family 0x%X type %d (MD5 authentication)", ntohs (md5->family), ntohs (md5->type)); zlog_info (" RIP-2 packet len %d Key ID %d" " Auth Data len %d", ntohs (md5->packet_len), md5->keyid, md5->auth_len); zlog_info (" Sequence Number %ld", (u_long)ntohl (md5->sequence)); } else if (ntohs (rte->tag) == RIP_AUTH_DATA) { p = (u_char *)&rte->prefix; zlog_info (" family 0x%X type %d (MD5 data)", ntohs (rte->family), ntohs (rte->tag)); zlog_info (" MD5: %02X%02X%02X%02X%02X%02X%02X%02X" "%02X%02X%02X%02X%02X%02X%02X", p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7], p[9],p[10],p[11],p[12],p[13],p[14],p[15]); } else { zlog_info (" family 0x%X type %d (Unknown auth type)", ntohs (rte->family), ntohs (rte->tag)); } } else zlog_info (" %s/%d -> %s family %d tag %d metric %ld", inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),netmask, inet_ntop (AF_INET, &rte->nexthop, nbuf, BUFSIZ), ntohs (rte->family), ntohs (rte->tag), (u_long)ntohl (rte->metric)); } else { zlog_info (" %s family %d tag %d metric %ld", inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ), ntohs (rte->family), ntohs (rte->tag), (u_long)ntohl (rte->metric)); } }}/* Check if the destination address is valid (unicast; not net 0 or 127) (RFC2453 Section 3.9.2 - Page 26). But we don't check net 0 because we accept default route. */intrip_destination_check (struct in_addr addr){ u_int32_t destination; /* Convert to host byte order. */ destination = ntohl (addr.s_addr); if (IPV4_NET127 (destination)) return 0; /* Net 0 may match to the default route. */ if (IPV4_NET0 (destination) && destination != 0) return 0; /* Unicast address must belong to class A, B, C. */ if (IN_CLASSA (destination)) return 1; if (IN_CLASSB (destination)) return 1; if (IN_CLASSC (destination)) return 1; return 0;}/* RIP version 2 authentication. */intrip_auth_simple_password (struct rte *rte, struct sockaddr_in *from, struct interface *ifp){ struct rip_interface *ri; char *auth_str; if (IS_RIP_DEBUG_EVENT) zlog_info ("RIPv2 simple password authentication from %s", inet_ntoa (from->sin_addr)); ri = ifp->info; if (ri->auth_type != RIP_AUTH_SIMPLE_PASSWORD || ntohs (rte->tag) != RIP_AUTH_SIMPLE_PASSWORD) return 0; /* Simple password authentication. */ if (ri->auth_str) { auth_str = (char *) &rte->prefix; if (strncmp (auth_str, ri->auth_str, 16) == 0) return 1; } if (ri->key_chain) { struct keychain *keychain; struct key *key; keychain = keychain_lookup (ri->key_chain); if (keychain == NULL) return 0; key = key_match_for_accept (keychain, (char *) &rte->prefix); if (key) return 1; } return 0;}/* RIP version 2 authentication with MD5. */intrip_auth_md5 (struct rip_packet *packet, struct sockaddr_in *from, struct interface *ifp){ struct rip_interface *ri; struct rip_md5_info *md5; struct rip_md5_data *md5data; struct keychain *keychain; struct key *key; struct md5_ctx ctx; u_char pdigest[RIP_AUTH_MD5_SIZE]; u_char digest[RIP_AUTH_MD5_SIZE]; u_int16_t packet_len; char *auth_str = NULL; if (IS_RIP_DEBUG_EVENT) zlog_info ("RIPv2 MD5 authentication from %s", inet_ntoa (from->sin_addr)); ri = ifp->info; md5 = (struct rip_md5_info *) &packet->rte; /* Check auth type. */ if (ri->auth_type != RIP_AUTH_MD5 || ntohs (md5->type) != RIP_AUTH_MD5) return 0; if (md5->auth_len != RIP_HEADER_SIZE + RIP_AUTH_MD5_SIZE) return 0; if (ri->key_chain) { keychain = keychain_lookup (ri->key_chain); if (keychain == NULL) return 0; key = key_lookup_for_accept (keychain, md5->keyid); if (key == NULL) return 0; auth_str = key->string; } if (ri->auth_str) auth_str = ri->auth_str; if (! auth_str) return 0; /* MD5 digest authentication. */ packet_len = ntohs (md5->packet_len); md5data = (struct rip_md5_data *)(((u_char *) packet) + packet_len); /* Save digest to pdigest. */ memcpy (pdigest, md5data->digest, RIP_AUTH_MD5_SIZE); /* Overwrite digest by my secret. */ memset (md5data->digest, 0, RIP_AUTH_MD5_SIZE); strncpy (md5data->digest, auth_str, RIP_AUTH_MD5_SIZE); md5_init_ctx (&ctx); md5_process_bytes (packet, packet_len + md5->auth_len, &ctx); md5_finish_ctx (&ctx, digest); if (memcmp (pdigest, digest, RIP_AUTH_MD5_SIZE) == 0) return packet_len; else return 0;}voidrip_auth_md5_set (struct stream *s, struct interface *ifp){ struct rip_interface *ri; struct keychain *keychain = NULL; struct key *key = NULL; unsigned long len; struct md5_ctx ctx; unsigned char secret[RIP_AUTH_MD5_SIZE]; unsigned char digest[RIP_AUTH_MD5_SIZE]; char *auth_str = NULL; ri = ifp->info; /* Make it sure this interface is configured as MD5 authentication. */ if (ri->auth_type != RIP_AUTH_MD5) return; /* Lookup key chain. */ if (ri->key_chain) { keychain = keychain_lookup (ri->key_chain); if (keychain == NULL) return; /* Lookup key. */ key = key_lookup_for_send (keychain); if (key == NULL) return; auth_str = key->string; } if (ri->auth_str) auth_str = ri->auth_str; if (! auth_str) return; /* Get packet length. */ len = s->putp; /* Check packet length. */ if (len < (RIP_HEADER_SIZE + RIP_RTE_SIZE)) { zlog_err ("rip_auth_md5_set(): packet length %ld is less than minimum length.", len); return; } /* Move RTE. */ memmove (s->data + RIP_HEADER_SIZE + RIP_RTE_SIZE, s->data + RIP_HEADER_SIZE, len - RIP_HEADER_SIZE); /* Set pointer to authentication header. */ stream_set_putp (s, RIP_HEADER_SIZE); len += RIP_RTE_SIZE; /* MD5 authentication. */ stream_putw (s, 0xffff); stream_putw (s, RIP_AUTH_MD5); /* RIP-2 Packet length. Actual value is filled in rip_auth_md5_set(). */ stream_putw (s, len); /* Key ID. */ if (key) stream_putc (s, key->index % 256); else stream_putc (s, 1); /* Auth Data Len. Set 16 for MD5 authentication data. */ stream_putc (s, RIP_AUTH_MD5_SIZE + RIP_HEADER_SIZE); /* Sequence Number (non-decreasing). */ /* RFC2080: The value used in the sequence number is arbitrary, but two suggestions are the time of the message's creation or a simple message counter. */ stream_putl (s, time (NULL)); /* Reserved field must be zero. */ stream_putl (s, 0); stream_putl (s, 0); /* Set pointer to authentication data. */ stream_set_putp (s, len); /* Set authentication data. */ stream_putw (s, 0xffff); stream_putw (s, 0x01); /* Generate a digest for the RIP packet. */ memset (secret, 0, RIP_AUTH_MD5_SIZE); strncpy (secret, auth_str, RIP_AUTH_MD5_SIZE); md5_init_ctx (&ctx); md5_process_bytes (s->data, s->endp, &ctx); md5_process_bytes (secret, RIP_AUTH_MD5_SIZE, &ctx); md5_finish_ctx (&ctx, digest); /* Copy the digest to the packet. */ stream_write (s, digest, RIP_AUTH_MD5_SIZE);}/* RIP routing information. */voidrip_response_process (struct rip_packet *packet, int size, struct sockaddr_in *from, struct interface *ifp){ caddr_t lim; struct rte *rte; /* 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) { zlog_info ("response doesn't come from RIP port: %d", from->sin_port); rip_peer_bad_packet (from); return; } /* 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)) { zlog_info ("This datagram doesn't came from a valid neighbor: %s", inet_ntoa (from->sin_addr)); rip_peer_bad_packet (from); return; } /* It is also worth checking to see whether the response is from one of the router's own addresses. */ ; /* Alredy done in rip_read () */ /* Update RIP peer. */ rip_peer_update (from, packet->version); /* Set RTE pointer. */ rte = packet->rte; for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++) { /* RIPv2 authentication check. */ /* If the Address Family Identifier of the first (and only the first) entry in the message is 0xFFFF, then the remainder of the entry contains the authentication. */ /* If the packet gets here it means authentication enabled */ /* Check is done in rip_read(). So, just skipping it */ if (packet->version == RIPv2 && rte == packet->rte && rte->family == 0xffff) continue; if (ntohs (rte->family) != AF_INET) { /* Address family check. RIP only supports AF_INET. */ zlog_info ("Unsupported family %d from %s.", ntohs (rte->family), inet_ntoa (from->sin_addr)); continue; } /* - is the destination address valid (e.g., unicast; not net 0 or 127) */ if (! rip_destination_check (rte->prefix)) { zlog_info ("Network is net 0 or net 127 or it is not unicast network"); rip_peer_bad_route (from); continue; } /* Convert metric value to host byte order. */ rte->metric = ntohl (rte->metric);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -