📄 router.c
字号:
/* snap-1.0. Copyright (C) 2000 by Jonathan T. Moore and Michael Hicks. * * router.c : reads the Linux routing table from /proc/net/route and * implements a simple-minded routing lookup engine. Also, reads * names of interfaces from /proc/net/dev. * * $Id: router.c,v 1.2 2003/09/17 11:26:10 tmoerlan Exp $ */#include <sys/types.h>#include <sys/sysctl.h>#include <assert.h>#include <sys/socket.h>#include <net/route.h>//#include <netinet/in_systm.h>#include <netinet/in.h>#include <net/if.h>#include <net/if_var.h>#include <net/if_mib.h>#include <string.h>#include "bytecode.h"#include "d_printf.h"#include "memalloc.h"#include "router.h"#include "proc.h"#define NIPQUAD(addr) \ ((unsigned char *)&(addr))[0], \ ((unsigned char *)&(addr))[1], \ ((unsigned char *)&(addr))[2], \ ((unsigned char *)&(addr))[3]static addr_t get_addr(char *addrstr) { char buf[20]; addr_t addr = 0; sprintf(buf,"0x%s",addrstr); sscanf(buf,"%x",&addr); return addr;}static void sprintf_addr(char *addrstr, addr_t addr) { sprintf(addrstr,"%d.%d.%d.%d",NIPQUAD(addr));}#ifdef LINUX/* MWH---defined my own version of rtentry that uses addr_t's rather than sockaddrs */struct rtentry { addr_t rt_dst; /* Target address. */ addr_t rt_gateway; /* Gateway addr. */ addr_t rt_genmask; /* Target network mask (IP). */ unsigned short int rt_flags; short int rt_pad2; unsigned long int rt_ifidx; /* index of device used */ unsigned char rt_tos; unsigned char rt_class; short int rt_pad4; short int rt_metric; /* +1 for binary compatibility! */ char *rt_dev; /* Forcing the device at add. */ unsigned long int rt_mtu; /* Per route MTU/Window. */ unsigned long int rt_window; /* Window clamping. */ unsigned short int rt_irtt; /* Initial RTT. */};#endif/* route table */struct rtentry *routes = NULL;int num_rt_entries = 0;int num_routes = 0;/* #define rt_ifidx rt_pad3 */struct sockaddr mask[5];/* interface table. right now we just track interface names */char **ifaces = NULL;int num_if_entries = 0;int num_ifaces = 0;/* get the interface number of the named interface */int get_iface_index(char *iface_name) { int i; assert(iface_name != NULL); for(i = 0; i<num_ifaces; i++) { if (strcmp(iface_name,ifaces[i]) == 0) { return(i); } } return(-1);}#ifndef LINUX/* iface_file is not used by this function */void read_ifaces(char *iface_file) { struct ifmibdata ifmd; int name[6]; size_t len; len = sizeof(num_if_entries); name[0] = CTL_NET; name[1] = PF_LINK; name[2] = NETLINK_GENERIC; name[3] = IFMIB_SYSTEM; name[4] = IFMIB_IFCOUNT; if (sysctl(name, 5, &num_if_entries, &len, (void *)0, 0) < 0) d_printf(40, "sysctl error while getting ifcount\n"); num_ifaces = num_if_entries; d_printf(40, "found %d interfaces\n", num_ifaces); ifaces = (char **) malloc(sizeof(char *) * num_ifaces); name[0] = CTL_NET; name[1] = PF_LINK; name[2] = NETLINK_GENERIC; name[3] = IFMIB_IFDATA; name[5] = IFDATA_GENERAL; len = sizeof(ifmd); int i; for(i = 1; i <= num_ifaces; i++) { name[4] = i; if (sysctl(name, 6, &ifmd, &len, (void *)0, 0) < 0) d_printf(40, "sysctl error while getting ifname\n"); ifaces[i-1] = strdup(ifmd.ifmd_name); d_printf(40, "%s\t", ifaces[i-1]); } d_printf(40, "\n");} #else/* read interface names in out of /proc/net/dev */void read_ifaces(char *iface_file) { char buf[2048]; FILE *f; int num_ifs; char **curr_if; char iface[256]; f = fopen("/compat/linux/proc/net/dev"/*iface_file*/,"r"); if (f == NULL) { fprintf(stderr,"%s:%d: unable to open %s\n", __FILE__,__LINE__,iface_file); fflush(stderr); exit(1); } num_ifs = 0; /* count number of interfaces */ while(fgets(buf,sizeof(buf),f)) { num_ifs++; } num_ifs -= 2; /* strip off title lines */ d_printf(40,"%s:%d: reading %d interfaces\n",__FILE__,__LINE__,num_ifs); /* make room in the interface table */ if (num_ifs > num_if_entries) { if (ifaces != NULL) { free(ifaces); } memalloc(ifaces,char **,sizeof(char *) * num_ifs); num_if_entries = num_ifs; } /* now read in the interface names */ rewind(f); fgets(buf,sizeof(buf)-1,f); /* strip off 2 title lines */ fgets(buf,sizeof(buf)-1,f); curr_if = &ifaces[0]; while(fgets(buf,sizeof(buf)-1,f)) { int _sscanf_retval = 0; char *cp = NULL; assert(curr_if >= &ifaces[0]); assert(curr_if < &ifaces[num_ifs]); _sscanf_retval = sscanf(buf,"%s",iface); if (_sscanf_retval < 1) { fprintf(stderr, "Warning: scanf (%d) failed on bogus iface entry |%s|\n", _sscanf_retval, buf); continue; } /* strip the : */ cp = &iface[0]; while(*cp != '\0' && *cp != ':') cp++; *cp = '\0'; d_printf(40,"%s:%d: found interface %d = %s\n", __FILE__,__LINE__,(curr_if - ifaces),iface); *curr_if = strdup(iface); curr_if++; } num_ifaces = curr_if - ifaces; return;}#endif#ifndef LINUX#define ROUNDUP(a) \ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))voidroute_ParseHdr(struct rt_msghdr *rtm, struct sockaddr *sa[RTAX_MAX]){ char *wp; int rtax; wp = (char *)(rtm + 1); for (rtax = 0; rtax < RTAX_MAX; rtax++) if (rtm->rtm_addrs & (1 << rtax)) { sa[rtax] = (struct sockaddr *)wp; wp += ROUNDUP(sa[rtax]->sa_len); if (sa[rtax]->sa_family == 0) sa[rtax] = NULL; /* ??? */ } else sa[rtax] = NULL;}/* route_file is not used anymore */void read_routes(char *route_file) { int mib[] = { CTL_NET, PF_ROUTE,0,0,NET_RT_DUMP, 0 }; size_t len; static void *p; void *q; int nr = 0; memset(mask, 0, 4 * sizeof(struct sockaddr)); mask[0].sa_len = 16; memset(mask[0].sa_data, 0xff, 1); mask[1].sa_len = 16; memset(mask[1].sa_data, 0xff, 2); mask[2].sa_len = 16; memset(mask[2].sa_data, 0xff, 3); mask[3].sa_len = 16; memset(mask[3].sa_data, 0xff, 4); mask[4].sa_len = 16; memset(mask[4].sa_data, 0, 4); if (p != NULL) free(p); sysctl(mib,sizeof(mib)/sizeof(int),NULL,&len,NULL,0); p = malloc(len); sysctl(mib,sizeof(mib)/sizeof(int),p,&len,NULL,0); for(q=p; q<p+len;) { struct rt_msghdr *rtmsg = (struct rt_msghdr *) q; nr++; q += rtmsg->rtm_msglen; }; d_printf(45, "found %d routetable entries\n", nr); if (nr > num_rt_entries) { d_printf(45, "alloc'ing mem\n"); if (routes != NULL) free(routes); routes = malloc(sizeof(struct rtentry) * nr); if (routes == NULL) d_printf(45, "ERROR: not enough mem for routing table\n"); num_rt_entries = nr; } nr = 0; d_printf(45, "pointer p = %p\n", p); for(q=p; q<p+len;) { struct rt_msghdr *rtmsg = (struct rt_msghdr *) q; struct sockaddr *sa[RTAX_MAX]; struct rtentry *current_rt = &routes[nr];// d_printf(45, "routes addr = %p, current_rt = %p\n", routes, current_rt);// d_printf(45, "rt_msghdr %d: %d extra bytes\n", nr, rtmsg->rtm_msglen - sizeof(struct rt_msghdr)); route_ParseHdr(rtmsg, sa); if (sa[RTAX_GATEWAY]) { /* take only the internet routes */ if (sa[RTAX_GATEWAY]->sa_family != AF_INET) { q += rtmsg->rtm_msglen; continue; } d_printf(45, "gateway %d.%d.%d.%d\t ", NIPQUAD(sa[RTAX_GATEWAY]->sa_data[2])); current_rt->rt_gateway = sa[RTAX_GATEWAY]; } if (sa[RTAX_DST]) { d_printf(45, "dst %d.%d.%d.%d (%d)\t ", NIPQUAD(sa[RTAX_DST]->sa_data[2]), sa[RTAX_DST]->sa_len); rt_key(current_rt) = sa[RTAX_DST]; //, sa[RTAX_DST], sizeof(struct sockaddr)); }/* if (sa[RTAX_NETMASK]) { d_printf(45, "netmask %d.%d.%d.%d\n ", NIPQUAD(sa[RTAX_NETMASK]->sa_data));// rt_mask(current_rt) = sa[RTAX_NETMASK];// d_printf(45, "netmask sa ptr = %p\n", rt_mask(current_rt));// d_printf(45, "maskptr = %p\n", rt_mask(current_rt)->sa_data);// d_printf(45, "mask = %d.%d.%d.%d\n", NIPQUAD(*(rt_mask(current_rt)->sa_data)));// rt_mask(current_rt) = (struct sockaddr *) 1; } else*/ { unsigned int *m = (unsigned int *) &sa[RTAX_DST]->sa_data[2]; if ((*m & 0xffffffff) == 0) {//default entry, set mask to 0.0.0.0 to autoselect the of default //we'll take the route entry with greatest netmask in nexthop anyway rt_mask(current_rt) = &mask[4]; } else if ((*m & 0xffffff00) == 0) rt_mask(current_rt) = &mask[0]; else if ((*m & 0xffff0000) == 0) rt_mask(current_rt) = &mask[1]; else if ((*m & 0xff000000) == 0) rt_mask(current_rt) = &mask[2]; else { rt_mask(current_rt) = &mask[3]; } d_printf(45, "created netmask %d.%d.%d.%d\n", NIPQUAD(*(rt_mask(current_rt)->sa_data))); } if (sa[RTAX_GENMASK]) { d_printf(45, "genmask %d.%d.%d.%d\t ", NIPQUAD(sa[RTAX_GENMASK]->sa_data)); current_rt->rt_genmask = sa[RTAX_GENMASK]; } current_rt->rt_ifp = malloc(sizeof(struct ifnet)); current_rt->rt_ifp->if_index = rtmsg->rtm_index;// d_printf(45, "iface index=%d\n", rtmsg->rtm_index); nr++; q += rtmsg->rtm_msglen; }; num_routes = nr; d_printf(45, "%d INET routes among them\n", nr);}/* looks up the next hop to the given destination address. On success, fill in the results in retval, and return 0. On failure, return -1. */extern int nexthop(addr_t dstaddr, struct rt_lookup *retval) { int i; unsigned int found_gw = 0; unsigned int found_index = 0; unsigned int found_netmask = 0x0; assert(retval != NULL); assert(routes != NULL); d_printf(16, "nexthop!\n");// print_anti_timer(16,"nexthop"); for(i=0; i<num_routes; i++) { struct rtentry *rt = &routes[i];#if LINUX unsigned int *gw = (unsigned int *)&(rt->rt_gateway.sa_data); unsigned int *dest_net = (unsigned int *)&(rt->rt_dst.sa_data); unsigned int *mask = (unsigned int *)&(rt->rt_genmask.sa_data);#else unsigned int *gw = (unsigned int *)(&rt->rt_gateway->sa_data[2]); unsigned int *dest_net = (unsigned int *)(&rt_key(rt)->sa_data[2]); unsigned int *mask = (unsigned int *)(rt_mask(rt)->sa_data); unsigned short if_index = rt->rt_ifp->if_index;#endif d_printf(16, "%d.%d.%d.%d & %d.%d.%d.%d ?= %d.%d.%d.%d : %d\n", NIPQUAD(dstaddr), NIPQUAD(*mask), NIPQUAD(*dest_net), (dstaddr & *mask) == *dest_net ? 1 : 0); if ((dstaddr & *mask) == *dest_net) { d_printf(16, "found a gw!\n"); if (*mask >= found_netmask) { //we found a higher precision route entry (mask is bigger) found_netmask = *mask; found_gw = *gw; found_index = if_index; } } } //for... if (found_gw > 0) { retval->hopaddr = (addr_t) found_gw; retval->ifidx = found_index; d_printf(16, "nexthop returning for dest %d.%d.%d.%d --> gw %d.%d.%d.%d, iface %s (%d)\n", NIPQUAD(dstaddr), NIPQUAD(retval->hopaddr), ifaces[retval->ifidx-1], retval->ifidx); return(0); } else { d_printf(16, "nexthop: no gateway found in routing table for dest %d.%d.%d.%d\n", NIPQUAD(dstaddr)); }// print_timer(16,"nexthop"); return(-1);}#else/* read routing table out of /proc/net/route */void read_routes(char *route_file) { char buf[1024]; FILE *f; int nr; struct rtentry *curr_rt; char *fmt; char addrstr1[22],addrstr2[22],addrstr3[22]; char iface[16]; addr_t mask, dest_addr, gw_addr; unsigned int flags,refcnt,use,metric,mtu,window,irtt; f = fopen(route_file,"r"); if (f == NULL) { fprintf(stderr,"%s:%d: unable to open %s\n", __FILE__,__LINE__,route_file); exit(1); } nr = 0; /* count number of routes */ while(fgets(buf,sizeof(buf),f)) { nr++; } nr--; /* strip off title line */ d_printf(40,"%s:%d: reading %d routes\n",__FILE__,__LINE__,nr); /* do we have enough room in the routing table? */ if (nr > num_rt_entries) { if (routes != NULL) { free(routes); } memalloc(routes,struct rtentry *,sizeof(struct rtentry) * nr); num_rt_entries = nr; } /* now read in the routes */ rewind(f); fmt = proc_gen_fmt(route_file, f, "Iface", "%16s", "Destination", "%s", "Gateway", "%s", "Flags", "%X", "RefCnt", "%d", "Use", "%d", "Metric", "%d", "Mask", "%s", "MTU", "%d", "Window", "%d", "IRTT", "%d", NULL); if (fmt == NULL) { fprintf(stderr,"%s:%d: did not get format for reading %s\n",__FILE__, __LINE__,route_file); exit(1); } curr_rt = routes; while(fgets(buf,sizeof(buf)-1,f)) { int ifidx; assert(curr_rt >= &routes[0]); assert(curr_rt < &routes[nr]); if (sscanf(buf,fmt, iface,addrstr1,addrstr2,&flags,&refcnt,&use, &metric,addrstr3,&mtu,&window,&irtt) < 11) { fprintf(stderr,"Warning: scanf failed on bogus tab entry |%s|\n",buf); continue; } /* read the addresses */ dest_addr = get_addr(addrstr1); gw_addr = get_addr(addrstr2); mask = get_addr(addrstr3); ifidx = if_nametoindex(iface); if (ifidx == -1) { /* unknown interface! */ fprintf(stderr,"Warning: unknown iface |%s| in tab entry |%s|\n", iface,buf); continue; } sprintf_addr(addrstr1,dest_addr); sprintf_addr(addrstr2,gw_addr); sprintf_addr(addrstr3,mask); d_printf(45,"%s:%d: route : dst = %s, gw = %s, mask = %s, ifidx = %d (%s)\n", __FILE__,__LINE__,addrstr1,addrstr2,addrstr3, ifidx,iface); curr_rt->rt_ifidx = ifidx; curr_rt->rt_dst = dest_addr; curr_rt->rt_gateway = gw_addr; curr_rt->rt_genmask = mask; curr_rt->rt_flags = (unsigned short int)flags; curr_rt->rt_metric = (short int)metric; curr_rt->rt_mtu = (unsigned long int)mtu; curr_rt->rt_window = (unsigned long int)window; curr_rt->rt_irtt = (unsigned short int)irtt; curr_rt++; } num_routes = curr_rt - routes;}/* looks up the next hop to the given destination address. On success, fill in the results in retval, and return 0. On failure, return -1. */extern int nexthop(addr_t dstaddr, struct rt_lookup *retval) { int i; assert(retval != NULL); print_anti_timer(16,"nexthop"); for(i=0; i<num_routes; i++) { struct rtentry *rt = &routes[i]; addr_t dest_net = rt->rt_dst; addr_t gw = rt->rt_gateway; addr_t mask = rt->rt_genmask; if ((dstaddr & mask) == dest_net) { print_timer(16,"nexthop"); if (gw == 0) { retval->hopaddr = dstaddr; } else { retval->hopaddr = gw; } retval->ifidx = rt->rt_ifidx; return(0); } } print_timer(16,"nexthop"); return(-1);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -