📄 dyn_ip.c
字号:
struct msghdr msg = { (void *) &nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 }; status = recvmsg(rth->fd, &msg, 0); if (status < 0) { if (errno == EINTR) continue; DEBUG(DEBUG_FLAG, "rtnl_dump_filter: recvmsg OVERRUN: %s\n", strerror(errno)); continue; } if (status == 0) { DEBUG(DEBUG_FLAG, "rtnl_dump_filter: EOF on netlink\n"); return -1; } if (msg.msg_namelen != sizeof(nladdr)) { DEBUG(DEBUG_FLAG, "rtnl_dump_filter: sender address length " "== %i\n", msg.msg_namelen); return -1; } h = (struct nlmsghdr *) buf; while (NLMSG_OK(h, status)) { int err; if (h->nlmsg_pid != rth->local.nl_pid || h->nlmsg_seq != rth->dump) { DEBUG(DEBUG_FLAG, "rtnl_dump_filter: junk?\n"); h = NLMSG_NEXT(h, status); continue; } if (h->nlmsg_type == NLMSG_DONE) return 0; if (h->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA(h); if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { DEBUG(DEBUG_FLAG, "rtnl_dump_filter: " "ERROR truncated\n"); } else { errno = -err->error; DEBUG(DEBUG_FLAG, "rtnl_dump_filter: " "RTNETLINK error: %s\n", strerror(errno)); } return -1; } err = filter(&nladdr, h, arg1); if (err < 0) return err; h = NLMSG_NEXT(h, status); } if (msg.msg_flags & MSG_TRUNC) { DEBUG(DEBUG_FLAG, "rtnl_dump_filter: message truncated\n"); continue; } if (status) { DEBUG(DEBUG_FLAG, "rtnl_dump_filter: remnant of size %d\n", status); return -1; } } while (1);}static int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len){ while (RTA_OK(rta, len)) { if (rta->rta_type <= max) tb[rta->rta_type] = rta; rta = RTA_NEXT(rta,len); } if (len) DEBUG(DEBUG_FLAG, "parse_rtattr: Deficit %d, rta_len=%d\n", len, rta->rta_len); return 0;}static int ll_remember_index(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg){ struct idxmap **map = (struct idxmap **) arg; struct ifinfomsg *ifi = NLMSG_DATA(n); struct idxmap *im; struct rtattr *tb[IFLA_MAX + 1]; if (map == NULL) map = &idxmap; if (n->nlmsg_type != RTM_NEWLINK) return 0; if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi))) return -1; memset(tb, 0, sizeof(tb)); parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n)); if (tb[IFLA_IFNAME] == NULL) return 0; im = malloc(sizeof(*im)); if (im == NULL) return -1; im->next = *map; im->index = ifi->ifi_index; dynamics_strlcpy(im->name, RTA_DATA(tb[IFLA_IFNAME]), sizeof(im->name)); *map = im; return 0;}static int ll_name_to_index(const char *name){ struct idxmap *im; if (name == NULL) return 0; for (im = idxmap; im != NULL; im = im->next) if (strcmp(im->name, name) == 0) return im->index; return 0;}static char *ll_index_to_name(int idx){ struct idxmap *im; static char nbuf[64]; if (idx == 0) return "*"; for (im = idxmap; im != NULL; im = im->next) if (im->index == idx) return im->name; snprintf(nbuf, sizeof(nbuf), "if%d", idx); return nbuf;}static int ll_init_map(struct rtnl_handle *rth){ if (rtnl_wilddump_request(rth, AF_UNSPEC, RTM_GETLINK) < 0) { DEBUG(DEBUG_FLAG, "ll_init_map: cannot send dump request\n"); return -1; } assert(idxmap == NULL); if (rtnl_dump_filter(rth, ll_remember_index, &idxmap) < 0) { DEBUG(DEBUG_FLAG, "ll_init_map: dump terminated\n"); return -1; } return 0;}static void ll_free_map(void){ struct idxmap *idx, *prev; idx = idxmap; while (idx != NULL) { prev = idx; idx = idx->next; free(prev); } idxmap = NULL;}/* Helper function for dyn_ip_addr_* functions */static int dyn_ip_addr_ops(const char *dev, struct in_addr addr, int type){ struct rtnl_handle rth; struct { struct nlmsghdr n; struct ifaddrmsg ifa; char buf[256]; } req; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = type; req.ifa.ifa_family = AF_INET; req.ifa.ifa_prefixlen = 32; /* bits */ addattr_l(&req.n, sizeof(req), IFA_LOCAL, (void *) &addr, sizeof(struct in_addr)); if (rtnl_open(&rth, 0) != 0) return -1; if (ll_init_map(&rth) != 0) { DEBUG(DEBUG_FLAG, "dyn_ip_addr_ops: ll_init_map() failed\n"); ll_free_map(); close(rth.fd); return -1; } if ((req.ifa.ifa_index = ll_name_to_index(dev)) == 0) { DEBUG(DEBUG_FLAG, "dyn_ip_addr_ops: interface(%s) not found\n", dev); ll_free_map(); close(rth.fd); return -1; } ll_free_map(); if (rtnl_talk(&rth, &req.n, NULL) < 0) { DEBUG(DEBUG_FLAG, "dyn_ip_addr_ops: unknown interface %s\n", dev); close(rth.fd); return -1; } close(rth.fd); return 0;}/** * dyn_ip_addr_add: * @dev: network device name * @addr: IP address * * Add IP address @addr to device @dev. * * Returns: 0 if successful, else -1 */int dyn_ip_addr_add(const char *dev, struct in_addr addr){ return dyn_ip_addr_ops(dev, addr, RTM_NEWADDR);}/** * dyn_ip_addr_del: * @dev: network device name * @addr: IP address * * Remove IP address @addr from device @dev. * * Returns: 0 if successful, else -1 */int dyn_ip_addr_del(const char *dev, struct in_addr addr){ return dyn_ip_addr_ops(dev, addr, RTM_DELADDR);}/** * rtnl_modify_route: * @cmd: * @flags: * @type: * @dev: * @table: * @dst: * @bits: * @via: * @prefsrc: * * Handle route modification (add/del). * If table == -1 then table is not set (use RT_TABLE_MAIN). * If dst != NULL then dst contains destinations address for the route. * If dst == NULL then dst is ignored and default route is added. * If via != NULL then via contains the gateway address. * * Returns: 0 on success or -1 on failure */static int rtnl_modify_route(int cmd, int flags, int type, const char *dev, int table, const struct in_addr *dst, int bits, const struct in_addr *via, const struct in_addr *prefsrc){ struct rtnl_handle rth; struct { struct nlmsghdr n; struct rtmsg r; char buf[1024]; } req; int idx; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = flags; req.n.nlmsg_type = cmd; req.r.rtm_table = RT_TABLE_MAIN; if (cmd == RTM_DELROUTE) { req.r.rtm_protocol = RTPROT_UNSPEC; req.r.rtm_scope = RT_SCOPE_NOWHERE; } else { req.r.rtm_protocol = RTPROT_BOOT; req.r.rtm_scope = RT_SCOPE_LINK; } req.r.rtm_type = type; req.r.rtm_family = AF_INET; if (dst != NULL) { addattr_l(&req.n, sizeof(req), RTA_DST, (void *) dst, 4); req.r.rtm_dst_len = bits; } if (table != -1) { if (table < 0 || table > 255) { DEBUG(DEBUG_FLAG, "rtnl_modify_route: invalid table id %i\n", table); return -1; } req.r.rtm_table = table; } if (via != NULL) { addattr_l(&req.n, sizeof(req), RTA_GATEWAY, (void *) via, 4); req.r.rtm_scope = RT_SCOPE_UNIVERSE; } if (prefsrc != NULL) { addattr_l(&req.n, sizeof(req), RTA_PREFSRC, (void *) prefsrc, 4); } if (rtnl_open(&rth, 0) != 0) { DEBUG(DEBUG_FLAG, "rtnl_modify_route: rtnl_open failed\n"); return -1; } if (dev != NULL) { if (ll_init_map(&rth) != 0) { ll_free_map(); close(rth.fd); DEBUG(DEBUG_FLAG, "rtnl_modify_route: ll_init_map failed\n"); return -1; } if ((idx = ll_name_to_index((char*)dev)) == 0) { DEBUG(DEBUG_FLAG, "rtnl_modify_route: unknown interface %s\n", dev); ll_free_map(); close(rth.fd); return -1; } addattr32(&req.n, sizeof(req), RTA_OIF, idx); ll_free_map(); } if (rtnl_talk(&rth, &req.n, NULL) < 0) { close(rth.fd); DEBUG(DEBUG_FLAG, "rtnl_modify_route: rtnl_talk failed\n"); return -1; } close(rth.fd); return 0;}/** * dyn_ip_route_add_table: * @dev: network device name * @table: routing table number * @dst: destination IP address * * Add a route in table @table through to the host address @dst * through network device @dev. * * Returns: 0 if successful, else -1 */int dyn_ip_route_add_table(const char *dev, int table, const struct in_addr *dst){ return rtnl_modify_route(RTM_NEWROUTE, NLM_F_REQUEST | NLM_F_CREATE, RTN_UNICAST, dev, table, dst, 32, NULL, NULL);}/** * dyn_ip_route_del_table: * @dev: network device name * @table: routing table number * @dst: destination IP address * * Delete the route to the address @dst through device @dev * from table @table. * * Returns: 0 if successful, else -1 */int dyn_ip_route_del_table(const char *dev, int table, const struct in_addr *dst){ return rtnl_modify_route(RTM_DELROUTE, NLM_F_REQUEST, RTN_UNSPEC, dev, table, dst, 32, NULL, NULL);}/** * dyn_ip_route_add_net: * @dev: network device name * @dst: destination network address * @plen: prefix length of the network address * * Add a route to network @dst/@plen through @dev. * * Returns: 0 if successful, else -1 */int dyn_ip_route_add_net(const char *dev, const struct in_addr *dst, int plen){ return rtnl_modify_route(RTM_NEWROUTE, NLM_F_REQUEST | NLM_F_CREATE, RTN_UNICAST, dev, -1, dst, plen, NULL, NULL);}/** * dyn_ip_route_replace_net: * @dev: network device name * @dst: destination network address * @plen: prefix length of the network address * * Replace route to network @dst/@plen to go through @dev. * * Returns: 0 on success or -1 on failure */int dyn_ip_route_replace_net(const char *dev, const struct in_addr *dst, int plen){ return rtnl_modify_route(RTM_NEWROUTE, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE, RTN_UNICAST, dev, -1, dst, plen, NULL, NULL);}/** * dyn_ip_route_del_net: * @dev: network device name * @dst: destination network address * @plen: prefix length of the network address * * Delete a route to network @dst/@plen through @dev. * * Returns: 0 on success or -1 on failure */int dyn_ip_route_del_net(const char *dev, const struct in_addr *dst, int plen){ return rtnl_modify_route(RTM_DELROUTE, NLM_F_REQUEST, RTN_UNSPEC, dev, -1, dst, plen, NULL, NULL);}/** * dyn_ip_route_add_blackhole: * @table: routing table number * * Add a blackhole default routing entry to the given routing @table. * * Returns: 0 on success or -1 on failure */int dyn_ip_route_add_blackhole(int table){ return rtnl_modify_route(RTM_NEWROUTE, NLM_F_REQUEST | NLM_F_CREATE, RTN_BLACKHOLE, NULL, table, NULL, 32, NULL, NULL);}/** * dyn_ip_route_del_blackhole: * @table: routing table number * * Delete the blackhole default routing entry from the given routing @table. * * Returns: 0 on sucess or -1 on failure */int dyn_ip_route_del_blackhole(int table){ return rtnl_modify_route(RTM_DELROUTE, NLM_F_REQUEST, RTN_BLACKHOLE, NULL, table, NULL, 32, NULL, NULL);}/* generic routing rule help function for dyn_ip_rule_add_table() and * dyn_ip_rule_del_table() */static int change_iprule(int cmd, int type, struct in_addr *src, struct in_addr *dst, int table, const char *device, int prio){ struct rtnl_handle rth; struct { struct nlmsghdr n; struct rtmsg r; char buf[1024]; } req; memset(&req, 0, sizeof(req)); req.n.nlmsg_type = cmd; req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.r.rtm_family = AF_INET; req.r.rtm_protocol = RTPROT_BOOT; req.r.rtm_scope = RT_SCOPE_UNIVERSE; req.r.rtm_table = 0; req.r.rtm_type = type; if (cmd == RTM_NEWRULE) { req.n.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL; } if (src != NULL) { req.r.rtm_src_len = 32; /* bits */ addattr_l(&req.n, sizeof(req), RTA_SRC, (void *) src, sizeof(struct in_addr)); } if (dst != NULL) { req.r.rtm_dst_len = 32; /* bits */ addattr_l(&req.n, sizeof(req), RTA_DST, (void *) dst, sizeof(struct in_addr)); } if (table < 0 || table > 255) { DEBUG(DEBUG_FLAG, "change_iprule: invalid table id %i\n", table); return -1; } req.r.rtm_table = table; if (prio >= 0) { addattr32(&req.n, sizeof(req), RTA_PRIORITY, prio); } if (device != NULL) { /* Use also the incoming device to distinct packages */ addattr_l(&req.n, sizeof(req), RTA_IIF, device, strlen(device) + 1); } if (rtnl_open(&rth, 0) != 0) return -1; if (rtnl_talk(&rth, &req.n, NULL) < 0) { DEBUG(DEBUG_FLAG, "change_iprule: rtnl_talk failed\n"); close(rth.fd); return -1; } close(rth.fd); return 0;}/** * dyn_ip_rule_add_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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -