diff options
Diffstat (limited to 'netlink.c')
-rw-r--r-- | netlink.c | 62 |
1 files changed, 47 insertions, 15 deletions
@@ -334,19 +334,18 @@ next: } /** - * nl_addr() - Get/set IP addresses - * @ns: Use netlink socket in namespace - * @ifi: Interface index + * nl_addr() - Get/set/copy IP addresses for given interface and address family + * @op: Requested operation + * @ifi: Interface index in outer network namespace + * @ifi_ns: Interface index in target namespace for NL_SET, NL_DUP * @af: Address family - * @addr: Global address to fill if zero, to set if not, ignored if NULL + * @addr: Global address to fill on NL_GET, to set on NL_SET * @prefix_len: Mask or prefix length, set or fetched (for IPv4) - * @addr_l: Link-scoped address to fill, NULL if not requested + * @addr_l: Link-scoped address to fill on NL_GET */ -void nl_addr(int ns, unsigned int ifi, sa_family_t af, - void *addr, int *prefix_len, void *addr_l) +void nl_addr(enum nl_op op, unsigned int ifi, unsigned int ifi_ns, + sa_family_t af, void *addr, int *prefix_len, void *addr_l) { - int set = addr && ((af == AF_INET6 && !IN6_IS_ADDR_UNSPECIFIED(addr)) || - (af == AF_INET && *(uint32_t *)addr)); struct req_t { struct nlmsghdr nlh; struct ifaddrmsg ifa; @@ -365,23 +364,23 @@ void nl_addr(int ns, unsigned int ifi, sa_family_t af, } a6; } set; } req = { - .nlh.nlmsg_type = set ? RTM_NEWADDR : RTM_GETADDR, + .nlh.nlmsg_type = op == NL_SET ? RTM_NEWADDR : RTM_GETADDR, .nlh.nlmsg_flags = NLM_F_REQUEST, .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)), .nlh.nlmsg_seq = nl_seq++, .ifa.ifa_family = af, .ifa.ifa_index = ifi, - .ifa.ifa_prefixlen = *prefix_len, + .ifa.ifa_prefixlen = op == NL_SET ? *prefix_len : 0, }; + ssize_t n, nlmsgs_size; struct ifaddrmsg *ifa; struct nlmsghdr *nh; struct rtattr *rta; char buf[NLBUFSIZ]; - ssize_t n; size_t na; - if (set) { + if (op == NL_SET) { if (af == AF_INET6) { size_t rta_len = RTA_LENGTH(sizeof(req.set.a6.l)); @@ -416,21 +415,47 @@ void nl_addr(int ns, unsigned int ifi, sa_family_t af, req.nlh.nlmsg_flags |= NLM_F_DUMP; } - if ((n = nl_req(ns, buf, &req, req.nlh.nlmsg_len)) < 0 || set) + if ((n = nl_req(op == NL_SET, buf, &req, req.nlh.nlmsg_len)) < 0) + return; + + if (op == NL_SET) return; nh = (struct nlmsghdr *)buf; + nlmsgs_size = n; + for ( ; NLMSG_OK(nh, n); nh = NLMSG_NEXT(nh, n)) { if (nh->nlmsg_type != RTM_NEWADDR) goto next; + if (op == NL_DUP) { + nh->nlmsg_seq = nl_seq++; + nh->nlmsg_pid = 0; + nh->nlmsg_flags &= ~NLM_F_DUMP_FILTERED; + nh->nlmsg_flags |= NLM_F_REQUEST | NLM_F_ACK | + NLM_F_CREATE; + } + ifa = (struct ifaddrmsg *)NLMSG_DATA(nh); + + if (op == NL_DUP && (ifa->ifa_scope == RT_SCOPE_LINK || + ifa->ifa_index != ifi)) { + ifa->ifa_family = AF_UNSPEC; + goto next; + } + if (ifa->ifa_index != ifi) goto next; + if (op == NL_DUP) + ifa->ifa_index = ifi_ns; + for (rta = IFA_RTA(ifa), na = RTM_PAYLOAD(nh); RTA_OK(rta, na); rta = RTA_NEXT(rta, na)) { - if (rta->rta_type != IFA_ADDRESS) + if (op == NL_DUP && rta->rta_type == IFA_LABEL) + rta->rta_type = IFA_UNSPEC; + + if (op == NL_DUP || rta->rta_type != IFA_ADDRESS) continue; if (af == AF_INET && addr && !*(uint32_t *)addr) { @@ -451,6 +476,13 @@ next: if (nh->nlmsg_type == NLMSG_DONE) break; } + + if (op == NL_DUP) { + char resp[NLBUFSIZ]; + + nh = (struct nlmsghdr *)buf; + nl_req(1, resp, nh, nlmsgs_size); + } } /** |