diff --git a/conf.c b/conf.c index 404c7bc..cb1e09a 100644 --- a/conf.c +++ b/conf.c @@ -645,8 +645,10 @@ static unsigned int conf_ip4(unsigned int ifi, if (IN4_IS_ADDR_UNSPECIFIED(&ip4->gw)) nl_route(NL_GET, ifi, 0, AF_INET, &ip4->gw); - if (IN4_IS_ADDR_UNSPECIFIED(&ip4->addr)) - nl_addr(0, ifi, AF_INET, &ip4->addr, &ip4->prefix_len, NULL); + if (IN4_IS_ADDR_UNSPECIFIED(&ip4->addr)) { + nl_addr(NL_GET, ifi, 0, AF_INET, + &ip4->addr, &ip4->prefix_len, NULL); + } if (!ip4->prefix_len) { in_addr_t addr = ntohl(ip4->addr.s_addr); @@ -696,7 +698,7 @@ static unsigned int conf_ip6(unsigned int ifi, if (IN6_IS_ADDR_UNSPECIFIED(&ip6->gw)) nl_route(NL_GET, ifi, 0, AF_INET6, &ip6->gw); - nl_addr(0, ifi, AF_INET6, + nl_addr(NL_GET, ifi, 0, AF_INET6, IN6_IS_ADDR_UNSPECIFIED(&ip6->addr) ? &ip6->addr : NULL, &prefix_len, &ip6->addr_ll); diff --git a/netlink.c b/netlink.c index d93ecda..bc5b2bf 100644 --- a/netlink.c +++ b/netlink.c @@ -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); + } } /** diff --git a/netlink.h b/netlink.h index 217cf1e..cd0e666 100644 --- a/netlink.h +++ b/netlink.h @@ -16,8 +16,8 @@ void nl_sock_init(const struct ctx *c, bool ns); unsigned int nl_get_ext_if(sa_family_t af); void nl_route(enum nl_op op, unsigned int ifi, unsigned int ifi_ns, sa_family_t af, void *gw); -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); void nl_link(int ns, unsigned int ifi, void *mac, int up, int mtu); #endif /* NETLINK_H */ diff --git a/pasta.c b/pasta.c index c2fb1f4..798aeb6 100644 --- a/pasta.c +++ b/pasta.c @@ -278,16 +278,16 @@ void pasta_ns_conf(struct ctx *c) nl_link(1, c->pasta_ifi, c->mac_guest, 1, c->mtu); if (c->ifi4) { - nl_addr(1, c->pasta_ifi, AF_INET, &c->ip4.addr, - &c->ip4.prefix_len, NULL); + nl_addr(NL_SET, c->ifi4, c->pasta_ifi, AF_INET, + &c->ip4.addr, &c->ip4.prefix_len, NULL); nl_route(op_routes, c->ifi4, c->pasta_ifi, AF_INET, &c->ip4.gw); } if (c->ifi6) { int prefix_len = 64; - nl_addr(1, c->pasta_ifi, AF_INET6, &c->ip6.addr, - &prefix_len, NULL); + nl_addr(NL_SET, c->ifi6, c->pasta_ifi, AF_INET6, + &c->ip6.addr, &prefix_len, NULL); nl_route(op_routes, c->ifi6, c->pasta_ifi, AF_INET6, &c->ip6.gw); }