int route_loop(route_t *r, route_handler callback, void *arg) { struct rt_msghdr *rtm; struct route_entry entry; struct sockaddr *sa; char *buf, *lim, *next; int ret; #ifdef HAVE_SYS_SYSCTL_H int mib[6] = { CTL_NET, PF_ROUTE, 0, 0 /* XXX */, NET_RT_DUMP, 0 }; size_t len; if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) return (-1); if (len == 0) return (0); if ((buf = malloc(len)) == NULL) return (-1); if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { free(buf); return (-1); } lim = buf + len; next = buf; #elif defined(HAVE_GETKERNINFO) int len = getkerninfo(KINFO_RT_DUMP,0,0,0); if (len == 0) return (0); if ((buf = malloc(len)) == NULL) return (-1); if (getkerninfo(KINFO_RT_DUMP,buf,&len,0) < 0) { free(buf); return (-1); } lim = buf + len; next = buf; #else /* HAVE_STREAMS_ROUTE */ struct rt_giarg giarg, *gp; memset(&giarg, 0, sizeof(giarg)); giarg.gi_op = KINFO_RT_DUMP; if (ioctl(r->fd, RTSTR_GETROUTE, &giarg) < 0) return (-1); if ((buf = malloc(giarg.gi_size)) == NULL) return (-1); gp = (struct rt_giarg *)buf; gp->gi_size = giarg.gi_size; gp->gi_op = KINFO_RT_DUMP; gp->gi_where = buf; gp->gi_arg = RTF_UP | RTF_GATEWAY; if (ioctl(r->fd, RTSTR_GETROUTE, buf) < 0) { free(buf); return (-1); } lim = buf + gp->gi_size; next = buf + sizeof(giarg); #endif /* This loop assumes that RTA_DST, RTA_GATEWAY, and RTA_NETMASK have the * values, 1, 2, and 4 respectively. Cf. Unix Network Programming, * p. 494, function get_rtaddrs. */ for (ret = 0; next < lim; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)next; sa = (struct sockaddr *)(rtm + 1); if ((rtm->rtm_addrs & RTA_DST) == 0) /* Need a destination. */ continue; if (addr_ston(sa, &entry.route_dst) < 0) continue; if ((rtm->rtm_addrs & RTA_GATEWAY) == 0) /* Need a gateway. */ continue; sa = NEXTSA(sa); if (addr_ston_gateway(&entry.route_dst, sa, &entry.route_gw) < 0) continue; if (entry.route_dst.addr_type != entry.route_gw.addr_type || (entry.route_dst.addr_type != ADDR_TYPE_IP && entry.route_dst.addr_type != ADDR_TYPE_IP6)) continue; if (rtm->rtm_addrs & RTA_NETMASK) { sa = NEXTSA(sa); if (addr_stob(sa, &entry.route_dst.addr_bits) < 0) continue; } if ((ret = callback(&entry, arg)) != 0) break; } free(buf); return (ret); }
static int route_msg(route_t *r, int type, struct addr *dst, struct addr *gw) { struct addr net; struct rt_msghdr *rtm; struct sockaddr *sa; u_char buf[BUFSIZ]; pid_t pid; int len; memset(buf, 0, sizeof(buf)); rtm = (struct rt_msghdr *)buf; rtm->rtm_version = RTM_VERSION; if ((rtm->rtm_type = type) != RTM_DELETE) rtm->rtm_flags = RTF_UP; rtm->rtm_addrs = RTA_DST; rtm->rtm_seq = ++r->seq; /* Destination */ sa = (struct sockaddr *)(rtm + 1); if (addr_net(dst, &net) < 0 || addr_ntos(&net, sa) < 0) return (-1); sa = NEXTSA(sa); /* Gateway */ if (gw != NULL && type != RTM_GET) { rtm->rtm_flags |= RTF_GATEWAY; rtm->rtm_addrs |= RTA_GATEWAY; if (addr_ntos(gw, sa) < 0) return (-1); sa = NEXTSA(sa); } /* Netmask */ if (dst->addr_ip == IP_ADDR_ANY || dst->addr_bits < IP_ADDR_BITS) { rtm->rtm_addrs |= RTA_NETMASK; if (addr_btos(dst->addr_bits, sa) < 0) return (-1); sa = NEXTSA(sa); } else rtm->rtm_flags |= RTF_HOST; rtm->rtm_msglen = (u_char *)sa - buf; #ifdef DEBUG route_msg_print(rtm); #endif #ifdef HAVE_STREAMS_ROUTE if (ioctl(r->fd, RTSTR_SEND, rtm) < 0) return (-1); #else if (write(r->fd, buf, rtm->rtm_msglen) < 0) return (-1); pid = getpid(); while (type == RTM_GET && (len = read(r->fd, buf, sizeof(buf))) > 0) { if (len < (int)sizeof(*rtm)) { return (-1); } if (rtm->rtm_type == type && rtm->rtm_pid == pid && rtm->rtm_seq == r->seq) { if (rtm->rtm_errno) { errno = rtm->rtm_errno; return (-1); } break; } } #endif if (type == RTM_GET && (rtm->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY)) { sa = (struct sockaddr *)(rtm + 1); sa = NEXTSA(sa); if (addr_ston(sa, gw) < 0 || gw->addr_type != ADDR_TYPE_IP) { errno = ESRCH; return (-1); } } return (0); }
int route_loop(route_t *r, route_handler callback, void *arg) { struct rt_msghdr *rtm; struct route_entry entry; struct sockaddr *sa; char *buf, *lim, *next; int ret; #ifdef HAVE_SYS_SYSCTL_H int mib[6] = { CTL_NET, PF_ROUTE, 0, 0 /* XXX */, NET_RT_DUMP, 0 }; size_t len; if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) return (-1); if (len == 0) return (0); if ((buf = malloc(len)) == NULL) return (-1); if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { free(buf); return (-1); } lim = buf + len; next = buf; #else /* HAVE_STREAMS_ROUTE */ struct rt_giarg giarg, *gp; memset(&giarg, 0, sizeof(giarg)); giarg.gi_op = KINFO_RT_DUMP; if (ioctl(r->fd, RTSTR_GETROUTE, &giarg) < 0) return (-1); if ((buf = malloc(giarg.gi_size)) == NULL) return (-1); gp = (struct rt_giarg *)buf; gp->gi_size = giarg.gi_size; gp->gi_op = KINFO_RT_DUMP; gp->gi_where = buf; gp->gi_arg = RTF_UP | RTF_GATEWAY; if (ioctl(r->fd, RTSTR_GETROUTE, buf) < 0) { free(buf); return (-1); } lim = buf + gp->gi_size; next = buf + sizeof(giarg); #endif for (ret = 0; next < lim; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)next; sa = (struct sockaddr *)(rtm + 1); if (addr_ston(sa, &entry.route_dst) < 0 || (rtm->rtm_addrs & RTA_GATEWAY) == 0) continue; sa = NEXTSA(sa); if (addr_ston(sa, &entry.route_gw) < 0) continue; if (entry.route_dst.addr_type != entry.route_gw.addr_type || (entry.route_dst.addr_type != ADDR_TYPE_IP && entry.route_dst.addr_type != ADDR_TYPE_IP6)) continue; if (rtm->rtm_addrs & RTA_NETMASK) { sa = NEXTSA(sa); if (addr_stob(sa, &entry.route_dst.addr_bits) < 0) continue; } if ((ret = callback(&entry, arg)) != 0) break; } free(buf); return (ret); }