From 0d47952611198ef6b1163f366dc03922d20b1475 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 09:42:04 +0200 Subject: Adding upstream version 7.94+git20230807.3be01efb1+dfsg. Signed-off-by: Daniel Baumann --- libdnet-stripped/src/route-linux.c | 310 +++++++++++++++++++++++++++++++++++++ 1 file changed, 310 insertions(+) create mode 100644 libdnet-stripped/src/route-linux.c (limited to 'libdnet-stripped/src/route-linux.c') diff --git a/libdnet-stripped/src/route-linux.c b/libdnet-stripped/src/route-linux.c new file mode 100644 index 0000000..b14c527 --- /dev/null +++ b/libdnet-stripped/src/route-linux.c @@ -0,0 +1,310 @@ +/* + * route-linux.c + * + * Copyright (c) 2000 Dug Song + * + * $Id: route-linux.c 619 2006-01-15 07:33:29Z dugsong $ + */ + +#include "config.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "dnet.h" + +#define ADDR_ISHOST(a) (((a)->addr_type == ADDR_TYPE_IP && \ + (a)->addr_bits == IP_ADDR_BITS) || \ + ((a)->addr_type == ADDR_TYPE_IP6 && \ + (a)->addr_bits == IP6_ADDR_BITS)) + +#define PROC_ROUTE_FILE "/proc/net/route" +#define PROC_IPV6_ROUTE_FILE "/proc/net/ipv6_route" + +struct route_handle { + int fd; + int nlfd; +}; + +route_t * +route_open(void) +{ + struct sockaddr_nl snl; + route_t *r; + + if ((r = calloc(1, sizeof(*r))) != NULL) { + r->fd = r->nlfd = -1; + + if ((r->fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + return (route_close(r)); + + if ((r->nlfd = socket(AF_NETLINK, SOCK_RAW, + NETLINK_ROUTE)) < 0) + return (route_close(r)); + + memset(&snl, 0, sizeof(snl)); + snl.nl_family = AF_NETLINK; + + if (bind(r->nlfd, (struct sockaddr *)&snl, sizeof(snl)) < 0) + return (route_close(r)); + } + return (r); +} + +int +route_add(route_t *r, const struct route_entry *entry) +{ + struct rtentry rt; + struct addr dst; + + memset(&rt, 0, sizeof(rt)); + rt.rt_flags = RTF_UP | RTF_GATEWAY; + + if (ADDR_ISHOST(&entry->route_dst)) { + rt.rt_flags |= RTF_HOST; + memcpy(&dst, &entry->route_dst, sizeof(dst)); + } else + addr_net(&entry->route_dst, &dst); + + if (addr_ntos(&dst, &rt.rt_dst) < 0 || + addr_ntos(&entry->route_gw, &rt.rt_gateway) < 0 || + addr_btos(entry->route_dst.addr_bits, &rt.rt_genmask) < 0) + return (-1); + + return (ioctl(r->fd, SIOCADDRT, &rt)); +} + +int +route_delete(route_t *r, const struct route_entry *entry) +{ + struct rtentry rt; + struct addr dst; + + memset(&rt, 0, sizeof(rt)); + rt.rt_flags = RTF_UP; + + if (ADDR_ISHOST(&entry->route_dst)) { + rt.rt_flags |= RTF_HOST; + memcpy(&dst, &entry->route_dst, sizeof(dst)); + } else + addr_net(&entry->route_dst, &dst); + + if (addr_ntos(&dst, &rt.rt_dst) < 0 || + addr_btos(entry->route_dst.addr_bits, &rt.rt_genmask) < 0) + return (-1); + + return (ioctl(r->fd, SIOCDELRT, &rt)); +} + +int +route_get(route_t *r, struct route_entry *entry) +{ + static int seq; + struct nlmsghdr *nmsg; + struct rtmsg *rmsg; + struct rtattr *rta; + struct sockaddr_nl snl; + struct iovec iov; + struct msghdr msg; + u_char buf[512]; + int i, af, alen; + + switch (entry->route_dst.addr_type) { + case ADDR_TYPE_IP: + af = AF_INET; + alen = IP_ADDR_LEN; + break; + case ADDR_TYPE_IP6: + af = AF_INET6; + alen = IP6_ADDR_LEN; + break; + default: + errno = EINVAL; + return (-1); + } + memset(buf, 0, sizeof(buf)); + + nmsg = (struct nlmsghdr *)buf; + nmsg->nlmsg_len = NLMSG_LENGTH(sizeof(*nmsg)) + RTA_LENGTH(alen); + nmsg->nlmsg_flags = NLM_F_REQUEST; + nmsg->nlmsg_type = RTM_GETROUTE; + nmsg->nlmsg_seq = ++seq; + + rmsg = (struct rtmsg *)(nmsg + 1); + rmsg->rtm_family = af; + rmsg->rtm_dst_len = entry->route_dst.addr_bits; + + rta = RTM_RTA(rmsg); + rta->rta_type = RTA_DST; + rta->rta_len = RTA_LENGTH(alen); + + /* XXX - gross hack for default route */ + if (af == AF_INET && entry->route_dst.addr_ip == IP_ADDR_ANY) { + i = htonl(0x60060606); + memcpy(RTA_DATA(rta), &i, alen); + } else + memcpy(RTA_DATA(rta), entry->route_dst.addr_data8, alen); + + memset(&snl, 0, sizeof(snl)); + snl.nl_family = AF_NETLINK; + + iov.iov_base = nmsg; + iov.iov_len = nmsg->nlmsg_len; + + memset(&msg, 0, sizeof(msg)); + msg.msg_name = &snl; + msg.msg_namelen = sizeof(snl); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + if (sendmsg(r->nlfd, &msg, 0) < 0) + return (-1); + + iov.iov_base = buf; + iov.iov_len = sizeof(buf); + + if ((i = recvmsg(r->nlfd, &msg, 0)) <= 0) + return (-1); + + if (nmsg->nlmsg_len < (int)sizeof(*nmsg) || nmsg->nlmsg_len > i || + nmsg->nlmsg_seq != seq) { + errno = EINVAL; + return (-1); + } + if (nmsg->nlmsg_type == NLMSG_ERROR) + return (-1); + + i -= NLMSG_LENGTH(sizeof(*nmsg)); + + entry->route_gw.addr_type = ADDR_TYPE_NONE; + entry->intf_name[0] = '\0'; + for (rta = RTM_RTA(rmsg); RTA_OK(rta, i); rta = RTA_NEXT(rta, i)) { + if (rta->rta_type == RTA_GATEWAY) { + entry->route_gw.addr_type = entry->route_dst.addr_type; + memcpy(entry->route_gw.addr_data8, RTA_DATA(rta), alen); + entry->route_gw.addr_bits = alen * 8; + } else if (rta->rta_type == RTA_OIF) { + char ifbuf[IFNAMSIZ]; + char *p; + int intf_index; + + intf_index = *(int *) RTA_DATA(rta); + p = if_indextoname(intf_index, ifbuf); + if (p == NULL) + return (-1); + strlcpy(entry->intf_name, ifbuf, sizeof(entry->intf_name)); + } + } + if (entry->route_gw.addr_type == ADDR_TYPE_NONE) { + errno = ESRCH; + return (-1); + } + + return (0); +} + +int +route_loop(route_t *r, route_handler callback, void *arg) +{ + FILE *fp; + struct route_entry entry; + char buf[BUFSIZ]; + char ifbuf[16]; + int ret = 0; + + if ((fp = fopen(PROC_ROUTE_FILE, "r")) != NULL) { + int i, iflags, refcnt, use, metric, mss, win, irtt; + uint32_t mask; + + while (fgets(buf, sizeof(buf), fp) != NULL) { + i = sscanf(buf, "%15s %X %X %X %d %d %d %X %d %d %d\n", + ifbuf, &entry.route_dst.addr_ip, + &entry.route_gw.addr_ip, &iflags, &refcnt, &use, + &metric, &mask, &mss, &win, &irtt); + + if (i < 11 || !(iflags & RTF_UP)) + continue; + + strlcpy(entry.intf_name, ifbuf, sizeof(entry.intf_name)); + + entry.route_dst.addr_type = entry.route_gw.addr_type = + ADDR_TYPE_IP; + + if (addr_mtob(&mask, IP_ADDR_LEN, + &entry.route_dst.addr_bits) < 0) + continue; + + entry.route_gw.addr_bits = IP_ADDR_BITS; + entry.metric = metric; + + if ((ret = callback(&entry, arg)) != 0) + break; + } + fclose(fp); + } + if (ret == 0 && (fp = fopen(PROC_IPV6_ROUTE_FILE, "r")) != NULL) { + char s[33], d[8][5], n[8][5]; + int i, iflags, metric; + u_int slen, dlen; + + while (fgets(buf, sizeof(buf), fp) != NULL) { + i = sscanf(buf, "%04s%04s%04s%04s%04s%04s%04s%04s %02x " + "%32s %02x %04s%04s%04s%04s%04s%04s%04s%04s " + "%x %*x %*x %x %15s", + d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], + &dlen, s, &slen, + n[0], n[1], n[2], n[3], n[4], n[5], n[6], n[7], + &metric, &iflags, ifbuf); + + if (i < 21 || !(iflags & RTF_UP)) + continue; + + strlcpy(entry.intf_name, ifbuf, sizeof(entry.intf_name)); + + snprintf(buf, sizeof(buf), "%s:%s:%s:%s:%s:%s:%s:%s/%d", + d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], + dlen); + addr_aton(buf, &entry.route_dst); + snprintf(buf, sizeof(buf), "%s:%s:%s:%s:%s:%s:%s:%s/%d", + n[0], n[1], n[2], n[3], n[4], n[5], n[6], n[7], + IP6_ADDR_BITS); + addr_aton(buf, &entry.route_gw); + entry.metric = metric; + + if ((ret = callback(&entry, arg)) != 0) + break; + } + fclose(fp); + } + return (ret); +} + +route_t * +route_close(route_t *r) +{ + if (r != NULL) { + if (r->fd >= 0) + close(r->fd); + if (r->nlfd >= 0) + close(r->nlfd); + free(r); + } + return (NULL); +} -- cgit v1.2.3