📄 dyn_ip.c
字号:
* @device: incoming network device name (iif), or %NULL if not set * * Add a routing rule for packets from @src to @dst using iif @device to * @table. * * Returns: 0 on success or -1 on failure */int dyn_ip_rule_add_table(struct in_addr *src, struct in_addr *dst, int table, const char *device){ DEBUG(DEBUG_FLAG, "\tip rule add from %s to %s table %d iif %s\n", src != NULL ? inet_ntoa(*src) : "N/A", dst != NULL ? inet_ntoa(*dst) : "N/A", table, device != NULL ? device : "N/A"); return change_iprule(RTM_NEWRULE, RTN_UNICAST, src, dst, table, device, -1);}/** * dyn_ip_rule_del_table: * @src: source IP address (from), or %NULL if not set * @dst: destination IP address (to), or %NULL if not set * @table: routing table number * @device: incoming network device name (iif), or %NULL if not set * * Delete the routing rule for packets from @src to @dst using iif @device to * @table. * * Returns: 0 on success or -1 on failure */int dyn_ip_rule_del_table(struct in_addr *src, struct in_addr *dst, int table, const char *device){ DEBUG(DEBUG_FLAG, "\tip rule del from %s to %s table %d iif %s\n", src != NULL ? inet_ntoa(*src) : "N/A", dst != NULL ? inet_ntoa(*dst) : "N/A", table, device != NULL ? device : "N/A"); return change_iprule(RTM_DELRULE, RTN_UNICAST, src, dst, table, device, -1);}/** * dyn_ip_route_get: * @dst: destination address * @dev: memory buffer for the interface name * @max_len: maximum length of the buffer (buffer will have to have space * for the name including null termination) * * Find out the correct interface from the destination address * * Returns: 0 on success, -1 if failed, -2 if the buffer for the interface * name is too small */int dyn_ip_route_get(struct in_addr dst, char *dev, int max_len){ struct rtnl_handle rth; struct { struct nlmsghdr n; struct rtmsg r; char buf[1024]; } req; struct rtattr * tb[RTA_MAX+1]; int len; char *tmp; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_GETROUTE; req.r.rtm_table = 0; req.r.rtm_protocol = 0; req.r.rtm_scope = 0; req.r.rtm_type = 0; req.r.rtm_src_len = 0; req.r.rtm_tos = 0; req.r.rtm_family = AF_INET; req.r.rtm_dst_len = 32; /* bits */ addattr_l(&req.n, sizeof(req), RTA_DST, (void*) &dst, sizeof(struct in_addr)); if (rtnl_open(&rth, 0) != 0) return -1; if (ll_init_map(&rth) != 0) { ll_free_map(); close(rth.fd); return -1; } if (rtnl_talk(&rth, &req.n, &req.n) < 0) { DEBUG(DEBUG_FLAG, "dyn_ip_route_get(%s): rtnl_talk failed\n", inet_ntoa(dst)); ll_free_map(); close(rth.fd); return -1; } close(rth.fd); if (req.n.nlmsg_type != RTM_NEWROUTE) { DEBUG(DEBUG_FLAG, "dyn_ip_route_get: not a route\n"); ll_free_map(); return -1; } len = req.n.nlmsg_len - NLMSG_LENGTH(sizeof(req.r)); if (len < 0) { DEBUG(DEBUG_FLAG, "dyn_ip_route_get: invalid length\n"); ll_free_map(); return -1; } memset(tb, 0, sizeof(tb)); parse_rtattr(tb, RTA_MAX, RTM_RTA(&req.r), len); if (tb[RTA_OIF] == 0) { DEBUG(DEBUG_FLAG, "dyn_ip_route_get: no RTA_OIF?\n"); ll_free_map(); return -1; } tmp = ll_index_to_name(*(int *) RTA_DATA(tb[RTA_OIF])); if (tmp == NULL) { ll_free_map(); DEBUG(DEBUG_FLAG, "ll_index_to_name failed\n"); return -1; } if (strlen(tmp) >= max_len) { DEBUG(DEBUG_FLAG, "dyn_ip_route_get: device name does not fit " "to the given buffer\n"); ll_free_map(); return -2; } dynamics_strlcpy(dev, tmp, max_len); ll_free_map(); return 0;}/** * dyn_ip_route_to_host: * @dst: destination IP address * * Get current routing entry for a given host @dst and add a host route with * that information. * * Returns: 0 if successful, else -1 */int dyn_ip_route_to_host(struct in_addr dst){ struct rtnl_handle rth; struct { struct nlmsghdr n; struct rtmsg r; char buf[1024]; } req; struct rtattr *tb[RTA_MAX+1]; int len; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_GETROUTE; req.r.rtm_table = 0; req.r.rtm_protocol = 0; req.r.rtm_scope = 0; req.r.rtm_type = 0; req.r.rtm_src_len = 0; req.r.rtm_tos = 0; req.r.rtm_family = AF_INET; req.r.rtm_dst_len = 32; /* bits */ addattr_l(&req.n, sizeof(req), RTA_DST, (void*) &dst, sizeof(struct in_addr)); if (rtnl_open(&rth, 0) != 0) return -1; if (rtnl_talk(&rth, &req.n, &req.n) < 0) { close(rth.fd); DEBUG(DEBUG_FLAG, "dyn_ip_route_to_host: rtnl_talk (get) " "failed\n"); return -1; } req.n.nlmsg_type = RTM_NEWROUTE; req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE; /* make sure this is a host route and remove cache information */ req.r.rtm_dst_len = 32; req.r.rtm_flags &= ~RTM_F_CLONED; req.r.rtm_protocol = RTPROT_BOOT; req.r.rtm_type = RTN_UNICAST; memset(tb, 0, sizeof(tb)); len = req.n.nlmsg_len - NLMSG_LENGTH(sizeof(req.r)); if (len < 0) { close(rth.fd); DEBUG(DEBUG_FLAG, "dyn_ip_route_to_host: invalid len\n"); return -1; } parse_rtattr(tb, RTA_MAX, RTM_RTA(&req.r), len); if (tb[RTA_METRICS]) { int i; unsigned mxlock = 0; struct rtattr *mxrta[RTAX_MAX+1]; memset(mxrta, 0, sizeof(mxrta)); parse_rtattr(mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]), RTA_PAYLOAD(tb[RTA_METRICS])); if (mxrta[RTAX_LOCK]) mxlock = *(unsigned*)RTA_DATA(mxrta[RTAX_LOCK]); for (i=2; i<=RTAX_MAX; i++) { if (mxrta[i] != NULL) *(unsigned*)RTA_DATA(mxrta[i]) = 0; } } if (rtnl_talk(&rth, &req.n, NULL) < 0) { close(rth.fd); DEBUG(DEBUG_FLAG, "dyn_ip_route_to_host: rtnl_talk (set) " "failed\n"); return -1; } close(rth.fd); return 0;}/** * dyn_ip_get_ifaddr: * @dev: network interface name * @addr: address of the interface * * Fill in @addr with the IP address of @dev. * * Returns: 0 if successful, else -1 */int dyn_ip_get_ifaddr(const char *dev, struct in_addr *addr){ struct ifreq ifr; int s; struct sockaddr_in *saddr; memset(&ifr, 0, sizeof(ifr)); assert(dev != NULL && strlen(dev) < IFNAMSIZ); dynamics_strlcpy(ifr.ifr_name, dev, IFNAMSIZ); s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { DEBUG(DEBUG_FLAG, "dyn_ip_get_ifaddr: socket: %s\n", strerror(errno)); return -1; } if (ioctl(s, SIOCGIFADDR, &ifr) != 0) { DEBUG(DEBUG_FLAG, "dyn_ip_get_ifaddr(%s): ioctl: %s\n", dev, strerror(errno)); close(s); return -1; } close(s); saddr = (struct sockaddr_in *) &ifr.ifr_addr; if (saddr->sin_family != AF_INET) { DEBUG(DEBUG_FLAG, "dyn_ip_get_ifaddr(%s): invalid address family %i\n", dev, saddr->sin_family); return -1; } memcpy(addr, &saddr->sin_addr, sizeof(*addr)); return 0;}/** * dyn_ip_get_bcaddr: * @dev: network interface name * @addr: broadcast address of the interface * * Fill in @addr with the broadcast IP address of @dev. * * Returns: 0 if successful, else -1 */int dyn_ip_get_bcaddr(const char *dev, struct in_addr *addr){ struct ifreq ifr; int s; struct sockaddr_in *saddr; memset(&ifr, 0, sizeof(ifr)); assert(dev != NULL && strlen(dev) < IFNAMSIZ); dynamics_strlcpy(ifr.ifr_name, dev, IFNAMSIZ); s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { DEBUG(DEBUG_FLAG, "dyn_ip_get_bcaddr: socket: %s\n", strerror(errno)); return -1; } if (ioctl(s, SIOCGIFBRDADDR, &ifr) != 0) { DEBUG(DEBUG_FLAG, "dyn_ip_get_bcaddr(%s): ioctl: %s\n", dev, strerror(errno)); close(s); return -1; } close(s); saddr = (struct sockaddr_in *) &ifr.ifr_addr; if (saddr->sin_family != AF_INET) { DEBUG(DEBUG_FLAG, "dyn_ip_get_bcaddr(%s): invalid address family %i\n", dev, saddr->sin_family); return -1; } memcpy(addr, &saddr->sin_addr, sizeof(*addr)); return 0;}/** * dyn_ip_get_local_addr: * @remote: destination IP address * @local: buffer for the local IP address * * Get the @local address of the interface to which the packet to @remote * address are sent. * * Returns: 0 if successful, else -1 */int dyn_ip_get_local_addr(const struct in_addr *remote, struct in_addr *local){ char dev[IFNAMSIZ]; if (dyn_ip_route_get(*remote, dev, IFNAMSIZ) != 0) return -1; if (dyn_ip_get_ifaddr(dev, local) != 0) return -1; DEBUG(DEBUG_FLAG, "dyn_ip_get_local_addr: %s =>", inet_ntoa(*remote)); DEBUG(DEBUG_FLAG, " %s (%s)\n", inet_ntoa(*local), dev); return 0;}/** * dyn_ip_route_replace: * @dst_addr: destination address * @dev: network device name * * Replace the route to @dst_addr to go to @dev. * * Returns: 0 on success or -1 on failure */int dyn_ip_route_replace(struct in_addr dst_addr, const char *dev){ return rtnl_modify_route(RTM_NEWROUTE, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE, RTN_UNICAST, dev, -1, &dst_addr, 32, NULL, NULL);}/** * dyn_ip_route_replace_table: * @dst_addr: destination address * @dev: network device name * @table: routing table number * * Replace the route to @dst_addr in @table to go to @dev. * * Returns: 0 on success or -1 on failure */int dyn_ip_route_replace_table(struct in_addr dst_addr, const char *dev, int table){ return rtnl_modify_route(RTM_NEWROUTE, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE, RTN_UNICAST, dev, table, &dst_addr, 32, NULL, NULL);}/** * dyn_ip_route_add: * @dst_addr: destination address * @dev: network device name * * Add a routing entry for @dst_addr to @dev. * * Returns: 0 on success or -1 on failure */int dyn_ip_route_add(struct in_addr dst_addr, const char *dev){ return rtnl_modify_route(RTM_NEWROUTE, NLM_F_REQUEST | NLM_F_CREATE, RTN_UNICAST, dev, -1, &dst_addr, 32, NULL, NULL);}/** * dyn_ip_route_del: * @dst_addr: destination address * @dev: network device name * * Delete the route of @dst_addr to @dev. * * Returns: 0 on success or -1 on failure */int dyn_ip_route_del(struct in_addr dst_addr, const char *dev){ return rtnl_modify_route(RTM_DELROUTE, NLM_F_REQUEST, RTN_UNSPEC, dev, -1, &dst_addr, 32, NULL, NULL);}#define MAX_ROUTE_ADDR_LEN 8static int default_route_saved = 0;static struct rtmsg saved_default_route;static char saved_default_route_dev[IFNAMSIZ];static int saved_default_route_dev_index;static char saved_default_route_via[MAX_ROUTE_ADDR_LEN];static int saved_default_route_via_len;static char saved_default_route_prefsrc[MAX_ROUTE_ADDR_LEN];static int saved_default_route_prefsrc_len;/** * dyn_ip_get_saved_ifindex: * * Return the interface index of the saved default route. * * Returns: interface index or -1 on failure */int dyn_ip_get_saved_ifindex(void){ if (default_route_saved) return saved_default_route_dev_index; else return -1;}static int get_default_route(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg){ struct in_addr *forced_gateway = (struct in_addr *) arg; struct rtattr *tb[RTA_MAX + 1]; struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; if (n->nlmsg_type != RTM_NEWROUTE || r == NULL) { DEBUG(DEBUG_FLAG, "get_default_route: not a route: %08x %08x %08x\n", n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); return 0; } len -= NLMSG_LENGTH(sizeof(*r)); if (len < 0) { DEBUG(DEBUG_FLAG, "get_default_route: wrong len %d\n", len); return -1; } memset(tb, 0, sizeof(tb)); parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); if (tb[RTA_DST] || r->rtm_dst_len != 0 || r->rtm_table != RT_TABLE_MAIN) { /* not the default route */ return 0; } if (forced_gateway != NULL) { saved_default_route_via_len = 4; memcpy(saved_default_route_via, forced_gateway, 4); } else if (tb[RTA_GATEWAY]) { if (tb[RTA_GATEWAY]->rta_len > MAX_ROUTE_ADDR_LEN) { saved_default_route_via_len = 0; DEBUG(DEBUG_FLAG, "get_default_route: too long (%i) via address\n", tb[RTA_GATEWAY]->rta_len); } else { saved_default_route_via_len = tb[RTA_GATEWAY]->rta_len; memcpy(saved_default_route_via, RTA_DATA(tb[RTA_GATEWAY]), saved_default_route_via_len); } } else { saved_default_route_via_len = 0; } if (tb[RTA_OIF]) { saved_default_route_dev_index = *(int *) RTA_DATA(tb[RTA_OIF]); memcpy(saved_default_route_dev, ll_index_to_name(saved_default_route_dev_index), IFNAMSIZ); DEBUG(DEBUG_FLAG, "get_default_route: idx=%i(%s)\n", saved_default_route_dev_index, saved_default_route_dev); } else { DEBUG(DEBUG_FLAG, "get_default_route: no device for default route\n"); saved_default_route_dev[0] = '\0'; } if (tb[RTA_PREFSRC]) { if (tb[RTA_PREFSRC]->rta_len > MAX_ROUTE_ADDR_LEN) { saved_default_route_prefsrc_len = 0; DEBUG(DEBUG_FLAG, "get_default_route: too long (%i) prefsrc " "address\n", tb[RTA_PREFSRC]->rta_len); } else { saved_default_route_prefsrc_len = tb[RTA_PREFSRC]->rta_len; memcpy(saved_default_route_prefsrc, RTA_DATA(tb[RTA_PREFSRC]), saved_default_route_prefsrc_len); } } memcpy(&saved_default_route, r, sizeof(struct rtmsg)); default_route_saved = 1; return 0;}/** * dyn_ip_route_save_default: * @forced_gateway: forced gateway address or %NULL if none * * Save the current default route. If @forced_gateway != %NULL, set the via * entry of the saved data (i.e., not of the routing table) to point to * @forced_gateway. * * Returns: 0 on success or -1 on failure */int dyn_ip_route_save_default(struct in_addr *forced_gateway){ struct rtnl_handle rth; int ret = 0; default_route_saved = 0; if (rtnl_open(&rth, 0) != 0) return -1; if (ll_init_map(&rth) != 0) { ret = -1; } if (ret == 0 && rtnl_wilddump_request(&rth, AF_INET, RTM_GETROUTE) < 0) { DEBUG(DEBUG_FLAG, "dyn_ip_route_get_default: cannot send dump request\n"); ret = -1; } if (ret == 0 && rtnl_dump_filter(&rth, get_default_route, forced_gateway) < 0) { DEBUG(DEBUG_FLAG, "dyn_ip_route_get_default: dump terminated\n"); ret = -1; } if (!default_route_saved && forced_gateway != NULL) { DEBUG(DEBUG_FLAG, "dyn_ip_route_get_default: " "Using forced gateway\n"); saved_default_route_via_len = 4; memcpy(saved_default_route_via, forced_gateway, 4); if (idxmap != NULL) { memcpy(saved_default_route_dev, idxmap->name, IFNAMSIZ);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -