📄 rsrr_unicast.c
字号:
static int dsttable_size;static int vif_by_if(int, int);int dst_init(void (*refresh)(struct dstentry*)){ if (rtnl_open(&rt_nl, 0) < 0) return -1; dst_refresh = refresh; return rt_nl.fd;}static void dst_rmseq(struct dstentry *d){ struct dstentry **dp; for (dp = &dstqueue; *dp; dp = &(*dp)->queue_next) { if (d == *dp) { *dp = d->queue_next; break; } } d->seq = 0;}static __inline__ void dst_addseq(struct dstentry *d){ if (d->seq) { d->next = dstqueue; dstqueue = d; }}static struct dstentry * dst_findseq(__u32 seq){ struct dstentry **dp, *d; for (dp = &dstqueue; (d=*dp)!=NULL; dp = &d->queue_next) { if (d->seq == seq) { *dp = d->queue_next; d->seq = 0; return d; } } return NULL;}static void release_path(struct dstentry *d){ if (d->path) { free(d->path); d->path = NULL; }}static __inline__ unsigned hash(int family, const void *dst, const void *src){ unsigned h; int offset = (family == AF_INET) ? 0 : 3; h = ((__u32*)dst)[offset]; if (src) h ^= (((__u32*)src)[offset])>>4; h ^= h>>16; h ^= h>>8; return h&0xFF;}static __inline__ struct dstentry*dst_lookup4(unsigned h, int iif, const void *dst, const void *src){ __u32 saddr = src ? *(__u32*)src : 0; __u32 daddr = dst ? *(__u32*)dst : 0; struct dstentry *d; for (d = dsttable[h]; d; d = d->next) { if (d->family == AF_INET && d->iif == iif && d->dst[0] == daddr && d->src[0] == saddr) return d; } return NULL;}static __inline__ struct dstentry*dst_lookup6(unsigned h, int iif, const void *dst, const void *src){ struct dstentry *d; if (src == NULL) src = &zerokey; if (dst == NULL) dst = &zerokey; for (d = dsttable[h]; d; d = d->next) { if (d->family == AF_INET6 && d->iif == iif && memcmp(dst, d->dst, 16) == 0 && memcmp(dst, d->src, 16) == 0) return d; } return NULL;}static struct dstentry*dst_lookup(int fam, int iif, const void *dst, const void *src){ unsigned h = hash(fam, dst, src); return (fam==AF_INET?dst_lookup4:dst_lookup6)(h, iif, dst, src);}static void dst_gc(){ static int expires = R_GC_TMO; struct dstentry **dp, *d; time_t now = time(NULL); int h; for (h = 0; h<256; h++) { dp = &dsttable[h]; while ((d=*dp)!=NULL) { if (!d->block) { if (now - d->accessed > expires) { *dp = d->next; if (d->seq) dst_rmseq(d); release_path(d); free(d); dsttable_size--; continue; } if (d->seq && now - d->updated > R_CANCEL_TMO) dst_rmseq(d); } dp = &d->next; } } if (dsttable_size > MAXDSTENTRIES) expires = ((expires+R_ASYNC_TMO)>>1) + 1; else expires = R_GC_TMO;}struct dstentry * dst_alloc(int family, void *dst, void *src, int iif){ unsigned h; struct dstentry *d; d = calloc(1, sizeof(*d)); if (d == NULL) return NULL; d->iif = iif; d->family = family; if (family == AF_INET) { d->dst[0] = *(__u32*)dst; if (src) d->src[0] = *(__u32*)src; }#ifdef USE_IPV6 else { memcpy(d->dst, dst, 16); memcpy(d->src, src ? : &zerokey, 16); }#endif if (dsttable_size > MAXDSTENTRIES) dst_gc(); dsttable_size++; h = hash(family,dst,src); d->next = dsttable[h]; dsttable[h] = d; return d;}static int dst_request(struct dstentry *d){ int rlen; char buf[256]; struct nlmsghdr *n = (struct nlmsghdr *) buf; struct rtmsg *r = NLMSG_DATA(n); struct sockaddr_nl addr; n->nlmsg_type = RTM_GETROUTE; n->nlmsg_flags = NLM_F_REQUEST; n->nlmsg_len = NLMSG_LENGTH(sizeof(*r)); n->nlmsg_pid = rt_nl.local.nl_pid; if (++rt_nl.seq == 0) rt_nl.seq = 1; n->nlmsg_seq = rt_nl.seq; if (d->seq) dst_rmseq(d); d->seq = n->nlmsg_seq; memset(r, 0, sizeof(*r)); r->rtm_family = d->family; r->rtm_flags = RTM_F_NOTIFY; if (d->iif) addattr32(n, sizeof(buf), RTA_IIF, d->iif); if (d->family == AF_INET) { r->rtm_dst_len = 32; if (d->src[0]) r->rtm_src_len = 32; }#ifdef USE_IPV6 else { r->rtm_dst_len = 128; if (d->src[0] || d->src[1] || d->src[2] || d->src[3]) r->rtm_src_len = 128; }#endif if (r->rtm_dst_len) addattr_l(n, sizeof(buf), RTA_DST, d->dst, r->rtm_dst_len/8); if (r->rtm_src_len) addattr_l(n, sizeof(buf), RTA_SRC, d->src, r->rtm_src_len/8); addr.nl_family = AF_NETLINK; addr.nl_groups = 0; addr.nl_pid = 0; if ((rlen = sendto(rt_nl.fd, buf, n->nlmsg_len, 0, (struct sockaddr *) &addr, sizeof(addr))) < 0) { d->seq = 0; return rlen; } dst_addseq(d); return 0;}static void netlink_accept(char *buf, int len){ struct nlmsghdr *n = (void*)buf; struct rtmsg *r = NLMSG_DATA(n); struct rtattr *rta[RTA_MAX + 1]; struct dstentry *d; time_t now = time(NULL); __u32 *dst = NULL; __u32 *src = NULL; int iif = 0; int err = 0; if (len < sizeof(struct nlmsghdr) || n->nlmsg_len > len) return; if (n->nlmsg_type == NLMSG_ERROR) { if (n->nlmsg_pid != rt_nl.local.nl_pid) return; err = ((struct nlmsgerr*)NLMSG_DATA(n))->error; d = dst_findseq(n->nlmsg_seq); if (d) goto failure; return; } if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) return; d = NULL; if (n->nlmsg_pid == rt_nl.local.nl_pid) d = dst_findseq(n->nlmsg_seq); if (parse_rtattr(rta, RTA_MAX, RTM_RTA(r), RTM_PAYLOAD(n))) { err = EINVAL; if (d) goto failure; return; } if (rta[RTA_DST]) dst = RTA_DATA(rta[RTA_DST]); if (rta[RTA_SRC]) src = RTA_DATA(rta[RTA_SRC]); if (rta[RTA_IIF]) iif = *(int*)RTA_DATA(rta[RTA_IIF]); if (d == NULL || d->iif != iif) { struct dstentry *d1 = d; d = dst_lookup(r->rtm_family,iif,dst,src); if (d == NULL) { if (d1) { d = dst_alloc(r->rtm_family,dst,src,iif); if (d == NULL) return; d->state = R_INCOMPLETE; } } if (d->seq) dst_rmseq(d); } if (n->nlmsg_type == RTM_DELROUTE) { if (d->state&R_VALID) d->state = R_STALE; return; } if (r->rtm_type == RTN_LOCAL) { release_path(d); d->state = R_FRESH; d->error = 0; } else if (r->rtm_type == RTN_UNICAST || r->rtm_type == RTN_MULTICAST) { struct rtattr *path = rta[RTA_MULTIPATH]; int do_free = 0; if (path == NULL) { struct rtnexthop *nh; int len = sizeof(struct rtnexthop); err = EINVAL; if (rta[RTA_OIF] == NULL) goto failure; if (rta[RTA_GATEWAY]) { if (memcmp(RTA_DATA(rta[RTA_GATEWAY]), dst, RTA_PAYLOAD(rta[RTA_GATEWAY]))) len += rta[RTA_GATEWAY]->rta_len; else rta[RTA_GATEWAY] = NULL; } path = malloc(RTA_LENGTH(len)); if (path == NULL) return; path->rta_type = RTA_MULTIPATH; path->rta_len = RTA_LENGTH(len); nh = RTA_DATA(path); nh->rtnh_len = len; nh->rtnh_hops = 0; nh->rtnh_flags = r->rtm_flags; nh->rtnh_ifindex = *(int*)RTA_DATA(rta[RTA_OIF]); if (rta[RTA_GATEWAY]) memcpy(RTNH_DATA(nh), rta[RTA_GATEWAY], rta[RTA_GATEWAY]->rta_len); do_free = 1; } if (d->path && d->path->rta_len == path->rta_len && memcmp(d->path, path, path->rta_len) == 0) { int old_state = d->state; d->state = R_FRESH; if (do_free) free(path); if (old_state&R_VALID) return; goto update; } if (!do_free) { struct rtattr *np = malloc(path->rta_len); if (np == NULL) return; memcpy(np, path, path->rta_len); path = np; } release_path(d); d->path = path; d->state = R_FRESH; } else { err = EINVAL;failure: release_path(d); d->state = R_FAILED; d->error = err; d->updated = now; return; }update: d->updated = now; if (!d->block && d->refresh) { d->refresh = 0; d->block++; if (dst_refresh) dst_refresh(d); d->block--; } return;}int netlink_read_wakeup(){ char buf[8192]; int recvlen; struct sockaddr_nl nladdr; int addr_len = sizeof(nladdr); recvlen = recvfrom(rt_nl.fd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr*)&nladdr, &addr_len); if (recvlen < 0) { if (errno == EAGAIN) return 1; return -1; } if (addr_len != sizeof(nladdr) || nladdr.nl_pid) return -1; netlink_accept(buf, recvlen); return 0;}struct dstentry *dst_route(int family, void *dst, void *src, int iif, unsigned flags){ time_t entered, now; struct dstentry *d; now = entered = time(NULL); d = dst_lookup(family, iif, dst, src); if (d == NULL) { if (flags&RTO_NOUPDATE) return NULL; d = dst_alloc(family, dst, src, iif); if (d == NULL) return NULL; } for (;;) { time_t age; int need_upd = 0; d->accessed = now; age = now - d->updated; if (d->state == R_FRESH) { if (age <= R_STALETIME) return d; d->state = R_STALE; } if ((d->state&(R_PROBE|R_INCOMPLETE)) && age > R_ASYNC_TMO) { d->state = R_FAILED; d->error = ETIMEDOUT; } else if (d->state == R_STALE) { need_upd = 1; d->state = R_PROBE; } else if (d->state == R_NONE || (d->state == R_FAILED && age > R_LOAD)) { need_upd = 1; d->updated = now; d->state = R_INCOMPLETE; } if (!(d->state&R_VALID)) release_path(d); if (need_upd) { int err = dst_request(d); if (err) { d->state = R_FAILED; d->updated = now; d->error = errno; release_path(d); } d->block++; while (netlink_read_wakeup() == 0) /* NOTHING */; d->block--; } if (d->state&(R_VALID|R_FAILED)) return d; if (flags&RTO_NOWAIT || now-entered > R_SYNC_TMO) return d; if (1) { fd_set fds; struct timeval tv; FD_ZERO(&fds); FD_SET(rt_nl.fd,&fds); tv.tv_sec = R_SYNC_TMO-(now-entered); tv.tv_usec = 0; select(rt_nl.fd+1, &fds, NULL, NULL, &tv); d->block++; netlink_read_wakeup(); d->block--; } now = time(NULL); }}int dst_is_connected(struct dstentry *d){ if (!(d->state&R_VALID)) return 0; if (d->path==NULL || d->path->rta_len <= RTA_LENGTH(sizeof(struct rtnexthop))) return 1; return 0;}int dst_oif(struct dstentry *d){ struct rtnexthop *nh; if (!(d->state&R_VALID)) return 0; if (d->path==NULL) return 0; nh = RTA_DATA(d->path); return nh->rtnh_ifindex;}int dst_route_oif(net_addr *addr){ int i; int family = AF_INET; net_addr *addr2; net_if *inf; struct dstentry *d; int best = -1; int out; int vif; addr2 = net_addr_ip(addr);#ifdef USE_IPV6 if (addr2->type == NET_ADDR_IPv6) family = AF_INET6;#endif d = dst_route(family, &NET_GET_ADDR(addr2), NULL, 0, RTO_NOWAIT); if (d == NULL || !(d->state&R_VALID)) { d = NULL; goto fallback; } if (d->path == NULL) return -1; out = dst_oif(d); vif = vif_by_if(family, out); /* log(LOG_DEBUG, 0, "dst_route_oif: out = %d\n", out); */ /* log(LOG_DEBUG, 0, "dst_route_oif: vif = %d\n", vif); */ return vif;fallback: /* First pass: check primary addresses */ for (i=0; i<if_num; i++) { if (IsNumAPI(i)) continue; if (IF_DOWN(i)) continue; inf = &GET_IF(i); if (NET_GET_TYPE(inf) != NET_IF_PHY) continue; if (net_addr_equal(addr2,&NET_GET_IF_PHY_ADDR(inf))) return i; } if (best >= 0) return best; if (d) { best = local_v4;#ifdef USE_IPV6 if (family == AF_INET6) best = local_v6;#endif } return best;}static int vif_by_if(int family, int ifindex){ int i; net_if *inf2; int type = NET_ADDR_IPv4;#ifdef USE_IPV6 if (family == AF_INET6) type = NET_ADDR_IPv6;#endif for (i=0; i<if_num; i++) { if (IsNumAPI(i)) continue; inf2 = &GET_IF(i); if (NET_GET_TYPE(inf2) == NET_IF_PHY && NET_GET_IF_PHY_ID(inf2) == ifindex && NET_GET_IF_PHY_ADDR(inf2).type == type) return i; } log(LOG_WARNING, 0, "ifindex %d/%d is not mapped to a vif\n", ifindex, type); return -1;}#elif sgi_53/* Do not have support for access to unicast routing table in IRIX 5.3. */intunicast_init() {#ifdef HOST_ONLY return(0);#else return(1);#endif}intunicast_route1(u_long dest){ /* This dummy routine is here to allow pre-routing-socket code to * compile. It should never be called. */ assert(0); return(0);}#else /* !sgi_53 && !linux *//* Following code should work for many systems derived from * older BSDs, but it is known to work for Sun OS. *//* * Copyright (c) 1983 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */#include <fcntl.h>#include <kvm.h>#include <nlist.h>#include <stdio.h>#include <sys/sockio.h>#include <sys/mbuf.h>#include <net/if.h>#include <net/route.h>#include <netinet/in.h>#include <netdb.h>#include <assert.h>#include <syslog.h>struct nlist nl[] = {#define N_RTHOST 0 { "_rthost" },#define N_RTNET 1 { "_rtnet" },#define N_RTHASHSIZE 2 { "_rthashsize" }, {""}};kvm_t *kd;char usage[] = "[-n] host";struct xroute { char ifname[IFNAMSIZ]; struct sockaddr_in netmask; struct sockaddr_in out_if; struct sockaddr_in dst; struct sockaddr_in gw;} routes[256];int nhost = 0;int nroute = 0;struct xroute default_route;int have_default = 0;int unicast_fd;/* forward declarations */int read_routes();int net_match(struct sockaddr_in *, struct xroute *);int rtfindx(struct sockaddr_in *);int ifname_to_if(char *);int kread(unsigned long addr, char *buf, unsigned nbytes);static int inet_netmatch(struct sockaddr_in *, struct sockaddr_in *);intunicast_init() { if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL)) == NULL) { log(LOG_INFO, 0, "Unicast routing information unavailable\n"); init_failed = 1; NoUnicast = 1; return(0); } if (kvm_nlist(kd, nl) < 0) { log(LOG_ERR, 0, "netstat: bad namelist\n"); init_failed = 1; NoUnicast = 1; return(0); } unicast_fd = socket(AF_INET, SOCK_DGRAM, 0); if (unicast_fd < 0) { log(LOG_ERR, errno, "unicast socket"); init_failed = 1; NoUnicast = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -