From nobody Thu May 25 12:22:38 2023 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4QRnHy50NVz4TRDp; Thu, 25 May 2023 12:22:38 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4QRnHy4jZqz40bl; Thu, 25 May 2023 12:22:38 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1685017358; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=y290sSHZr976I6EjX4lRzVbjF5bxVQEaWScHJ294jL0=; b=gYzwYTqpS8pwawwE/XvfU9HmSQnVHVu8MBoLEEIvqCLsM+R07IthdF5KXhp7SBW4+xiGte A9cVrWUODxFAg6g6id1i1uxz4Sy8SUO2ZKJ6nX1q25bdgpKmPZzkjpRXkaBge8CdKrfira wQFku9NKnWRQGL6AeFISJfCWZHzfQEXqrGNdZVr+ZS/m9slUn5KqAi5uDi75n1HScXfZQN rPki87NxdsYUb8RqLpGKznTqqlQIF0Ot1eWY1WVHU1HHajy3NUUvGdO3zP+caRY77vy4q7 5t0QPArDvChr55QsJqK3WRtozZ56sfmHuDjvGlqLZQ72rZiRF8HfjgpnM1pE/Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1685017358; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=y290sSHZr976I6EjX4lRzVbjF5bxVQEaWScHJ294jL0=; b=ZfB0JyhX+6UGB6kKJSvwiz8gN6/AVSZEWdKVkp8C5W1p+g8YEyukqaZyfaGaNzb385xx/I qp4tsxcYSMlegpKIEeH/gr0DKV+28XuCwn/a16sES69A6I6nj5GQRIJaulptphcGgkYk0+ U5lt+4K6wUOUhY1bQElwch5ek80qNfhdvnEXD1kLiyBCzCAS5joPydg6YH9nXq6NFaIhK4 6Da6DnW3NtfjKMojYYJAsTtqblkTpoGlLH2EDgSPWd3mlqaT8tD3RJEVlJ32rcvzMfQqC+ Jw3TCwPyg9Fwp1WXzfJnMXsfAOJcs1IZAGAYHqTHZt0TEpNTgMm2P7i8h7dDIQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1685017358; a=rsa-sha256; cv=none; b=J/ef5t87q2X3lhy9Av66wZyWu7bpdGbQZalX3qThhzjH9Af5w8Tem5eFlFMGJY4in1BMc5 SHQuAUOquj97WWWyRc7U9KWL8oggixuxhXd/mxFiEXgZibq0WMH7U71GzZV6bDQRC1Lipk T+74rserW5/M80DCvknJXc9k2lpmWxaGW918aoIafjPjkMR6Rj/OxDxAiUzHBEIPJuA9jN y17i9bK61Fz1rbICD3h6v5MSvu4al6ID5edmsroGykVSYFNXvfmUj5L9DzpnIyh2EIT3cA VjWaeUJ9yc2lH034MOaiXrLNrUhKfsQjxe6DTvlfwew3CqT/KCFHGDXeUI++0A== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4QRnHy3md3zPGj; Thu, 25 May 2023 12:22:38 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 34PCMcxI064859; Thu, 25 May 2023 12:22:38 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 34PCMcCw064858; Thu, 25 May 2023 12:22:38 GMT (envelope-from git) Date: Thu, 25 May 2023 12:22:38 GMT Message-Id: <202305251222.34PCMcCw064858@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: "Alexander V. Chernikov" Subject: git: 4bf44dd73bc0 - main - ifconfig: switch IPv4/IPv6 address manipulations to Netlink. List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-main@freebsd.org X-BeenThere: dev-commits-src-main@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: melifaro X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 4bf44dd73bc0a68b73f7ee50d52adf5d7cda3eb8 Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by melifaro: URL: https://cgit.FreeBSD.org/src/commit/?id=4bf44dd73bc0a68b73f7ee50d52adf5d7cda3eb8 commit 4bf44dd73bc0a68b73f7ee50d52adf5d7cda3eb8 Author: Alexander V. Chernikov AuthorDate: 2023-05-20 11:53:46 +0000 Commit: Alexander V. Chernikov CommitDate: 2023-05-25 12:22:18 +0000 ifconfig: switch IPv4/IPv6 address manipulations to Netlink. Differential Revision: https://reviews.freebsd.org/D40182 --- sbin/ifconfig/af_inet.c | 262 ++++++++++++++++++++++++++++++++++++++- sbin/ifconfig/af_inet6.c | 152 ++++++++++++++++++++++- sbin/ifconfig/af_link.c | 3 + sbin/ifconfig/ifconfig.c | 125 +++++++++++++------ sbin/ifconfig/ifconfig.h | 21 +++- sbin/ifconfig/ifconfig_netlink.c | 45 ++++++- 6 files changed, 554 insertions(+), 54 deletions(-) diff --git a/sbin/ifconfig/af_inet.c b/sbin/ifconfig/af_inet.c index fdde3bd23595..73decb229d0f 100644 --- a/sbin/ifconfig/af_inet.c +++ b/sbin/ifconfig/af_inet.c @@ -55,8 +55,26 @@ static const char rcsid[] = #include "ifconfig.h" #include "ifconfig_netlink.h" +#ifdef WITHOUT_NETLINK static struct in_aliasreq in_addreq; static struct ifreq in_ridreq; +#else +struct in_px { + struct in_addr addr; + int plen; + bool addrset; + bool maskset; +}; +struct in_pdata { + struct in_px addr; + struct in_px dst_addr; + struct in_px brd_addr; + uint32_t flags; + uint32_t vhid; +}; +static struct in_pdata in_add, in_del; +#endif + static char addr_buf[NI_MAXHOST]; /*for getnameinfo()*/ extern char *f_inet, *f_addr; @@ -175,6 +193,8 @@ in_status_nl(if_ctx *ctx __unused, if_link_t *link, if_addr_t *ifa) } #endif + +#ifdef WITHOUT_NETLINK #define SIN(x) ((struct sockaddr_in *) &(x)) static struct sockaddr_in *sintab[] = { SIN(in_ridreq.ifr_addr), SIN(in_addreq.ifra_addr), @@ -226,14 +246,234 @@ in_getaddr(const char *s, int which) errx(1, "%s: bad value", s); } +#else + +static struct in_px *sintab_nl[] = { + &in_del.addr, /* RIDADDR */ + &in_add.addr, /* ADDR */ + NULL, /* MASK */ + &in_add.dst_addr, /* DSTADDR*/ + &in_add.brd_addr, /* BRDADDR*/ +}; + +static void +in_getip(const char *addr_str, struct in_addr *ip) +{ + struct hostent *hp; + struct netent *np; + + if (inet_aton(addr_str, ip)) + return; + if ((hp = gethostbyname(addr_str)) != NULL) + bcopy(hp->h_addr, (char *)ip, + MIN((size_t)hp->h_length, sizeof(ip))); + else if ((np = getnetbyname(addr_str)) != NULL) + *ip = inet_makeaddr(np->n_net, INADDR_ANY); + else + errx(1, "%s: bad value", addr_str); +} + +static void +in_getaddr(const char *s, int which) +{ + struct in_px *px = sintab_nl[which]; + + if (which == MASK) { + struct in_px *px_addr = sintab_nl[ADDR]; + struct in_addr mask = {}; + + in_getip(s, &mask); + px_addr->plen = __bitcount32(mask.s_addr); + px_addr->maskset = true; + return; + } + + if (which == ADDR) { + char *p = NULL; + + if((p = strrchr(s, '/')) != NULL) { + const char *errstr; + /* address is `name/masklen' */ + int masklen; + *p = '\0'; + if (!isdigit(*(p + 1))) + errstr = "invalid"; + else + masklen = (int)strtonum(p + 1, 0, 32, &errstr); + if (errstr != NULL) { + *p = '/'; + errx(1, "%s: bad value (width %s)", s, errstr); + } + px->plen = masklen; + px->maskset = true; + } + } + + in_getip(s, &px->addr); + px->addrset = true; +} + +/* + * Deletes the first found IPv4 interface address for the interface. + * + * This function provides SIOCDIFADDR semantics missing in Netlink. + * When no valid IPv4 address is specified (sin_family or sin_len is wrong) to + * the SIOCDIFADDR call, it deletes the first found IPv4 address on the interface. + * 'ifconfig IFNAME inet addr/prefix' relies on that behavior, as it + * executes empty SIOCDIFADDR before adding a new address. + */ +static int +in_delete_first_nl(if_ctx *ctx) +{ + struct nlmsghdr *hdr; + struct ifaddrmsg *ifahdr; + uint32_t nlmsg_seq; + struct in_addr addr; + struct snl_writer nw = {}; + struct snl_errmsg_data e = {}; + struct snl_state *ss = ctx->io_ss; + bool found = false; + + uint32_t ifindex = if_nametoindex_nl(ss, name); + if (ifindex == 0) { + /* No interface with the desired name, nothing to delete */ + return (EADDRNOTAVAIL); + } + + snl_init_writer(ss, &nw); + hdr = snl_create_msg_request(&nw, NL_RTM_GETADDR); + hdr->nlmsg_flags |= NLM_F_DUMP; + ifahdr = snl_reserve_msg_object(&nw, struct ifaddrmsg); + ifahdr->ifa_family = AF_INET; + ifahdr->ifa_index = ifindex; + + if (!snl_finalize_msg(&nw) || !snl_send_message(ss, hdr)) + return (EINVAL); + + nlmsg_seq = hdr->nlmsg_seq; + while ((hdr = snl_read_reply_multi(ss, nlmsg_seq, &e)) != NULL) { + struct snl_parsed_addr attrs = {}; + if (snl_parse_nlmsg(ss, hdr, &snl_rtm_addr_parser, &attrs)) { + addr = satosin(attrs.ifa_local)->sin_addr; + ifindex = attrs.ifa_index; + found = true; + break; + } else + return (EINVAL); + } + if (e.error != 0) { + if (e.error_str != NULL) + warnx("%s(): %s", __func__, e.error_str); + return (e.error); + } + + if (!found) + return (0); + + /* Try to delete the found address */ + snl_init_writer(ss, &nw); + hdr = snl_create_msg_request(&nw, NL_RTM_DELADDR); + ifahdr = snl_reserve_msg_object(&nw, struct ifaddrmsg); + ifahdr->ifa_family = AF_INET; + ifahdr->ifa_index = ifindex; + snl_add_msg_attr_ip4(&nw, IFA_LOCAL, &addr); + + if (!snl_finalize_msg(&nw) || !snl_send_message(ss, hdr)) + return (EINVAL); + memset(&e, 0, sizeof(e)); + snl_read_reply_code(ss, hdr->nlmsg_seq, &e); + if (e.error_str != NULL) + warnx("%s(): %s", __func__, e.error_str); + + return (e.error); +} + + +static int +in_exec_nl(if_ctx *ctx, unsigned long action, void *data) +{ + struct in_pdata *pdata = (struct in_pdata *)data; + struct snl_writer nw = {}; + + if (action == NL_RTM_DELADDR && !pdata->addr.addrset) + return (in_delete_first_nl(ctx)); + + snl_init_writer(ctx->io_ss, &nw); + struct nlmsghdr *hdr = snl_create_msg_request(&nw, action); + struct ifaddrmsg *ifahdr = snl_reserve_msg_object(&nw, struct ifaddrmsg); + + ifahdr->ifa_family = AF_INET; + ifahdr->ifa_prefixlen = pdata->addr.plen; + ifahdr->ifa_index = if_nametoindex_nl(ctx->io_ss, name); + + snl_add_msg_attr_ip4(&nw, IFA_LOCAL, &pdata->addr.addr); + if (action == NL_RTM_NEWADDR && pdata->dst_addr.addrset) + snl_add_msg_attr_ip4(&nw, IFA_ADDRESS, &pdata->dst_addr.addr); + if (action == NL_RTM_NEWADDR && pdata->brd_addr.addrset) + snl_add_msg_attr_ip4(&nw, IFA_BROADCAST, &pdata->brd_addr.addr); + + int off = snl_add_msg_attr_nested(&nw, IFA_FREEBSD); + snl_add_msg_attr_u32(&nw, IFAF_FLAGS, pdata->flags); + if (pdata->vhid != 0) + snl_add_msg_attr_u32(&nw, IFAF_VHID, pdata->vhid); + snl_end_attr_nested(&nw, off); + + if (!snl_finalize_msg(&nw) || !snl_send_message(ctx->io_ss, hdr)) + return (0); + + struct snl_errmsg_data e = {}; + snl_read_reply_code(ctx->io_ss, hdr->nlmsg_seq, &e); + if (e.error_str != NULL) + warnx("%s(): %s", __func__, e.error_str); + + return (e.error); +} + +static void +in_setdefaultmask_nl(void) +{ + struct in_px *px = sintab_nl[ADDR]; + + in_addr_t i = ntohl(px->addr.s_addr); + + /* + * If netmask isn't supplied, use historical default. + * This is deprecated for interfaces other than loopback + * or point-to-point; warn in other cases. In the future + * we should return an error rather than warning. + */ + if (IN_CLASSA(i)) + px->plen = IN_CLASSA_NSHIFT; + else if (IN_CLASSB(i)) + px->plen = IN_CLASSB_NSHIFT; + else + px->plen = IN_CLASSC_NSHIFT; + px->maskset = true; +} +#endif + +static void +warn_nomask(int ifflags) +{ + if ((ifflags & (IFF_POINTOPOINT | IFF_LOOPBACK)) == 0) { + warnx("WARNING: setting interface address without mask " + "is deprecated,\ndefault mask may not be correct."); + } +} + static void in_postproc(if_ctx *ctx __unused, int newaddr, int ifflags) { - if (sintab[ADDR]->sin_len != 0 && sintab[MASK]->sin_len == 0 && - newaddr && (ifflags & (IFF_POINTOPOINT | IFF_LOOPBACK)) == 0) { - warnx("WARNING: setting interface address without mask " - "is deprecated,\ndefault mask may not be correct."); +#ifdef WITHOUT_NETLINK + if (sintab[ADDR]->sin_len != 0 && sintab[MASK]->sin_len == 0 && newaddr) { + warn_nomask(ifflags); + } +#else + if (sintab_nl[ADDR]->addrset && !sintab_nl[ADDR]->maskset && newaddr) { + warn_nomask(ifflags); + in_setdefaultmask_nl(); } +#endif } static void @@ -281,10 +521,13 @@ in_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres) static void in_set_vhid(int vhid) { +#ifdef WITHOUT_NETLINK in_addreq.ifra_vhid = vhid; +#else + in_add.vhid = (uint32_t)vhid; +#endif } - static struct afswtch af_inet = { .af_name = "inet", .af_af = AF_INET, @@ -298,10 +541,19 @@ static struct afswtch af_inet = { .af_status_tunnel = in_status_tunnel, .af_settunnel = in_set_tunnel, .af_setvhid = in_set_vhid, +#ifdef WITHOUT_NETLINK .af_difaddr = SIOCDIFADDR, .af_aifaddr = SIOCAIFADDR, .af_ridreq = &in_ridreq, .af_addreq = &in_addreq, + .af_exec = af_exec_ioctl, +#else + .af_difaddr = NL_RTM_DELADDR, + .af_aifaddr = NL_RTM_NEWADDR, + .af_ridreq = &in_del, + .af_addreq = &in_add, + .af_exec = in_exec_nl, +#endif }; static __constructor void diff --git a/sbin/ifconfig/af_inet6.c b/sbin/ifconfig/af_inet6.c index 8e2c4946e962..d5418b827789 100644 --- a/sbin/ifconfig/af_inet6.c +++ b/sbin/ifconfig/af_inet6.c @@ -59,10 +59,30 @@ static const char rcsid[] = #include "ifconfig.h" #include "ifconfig_netlink.h" +#ifndef WITHOUT_NETLINK +struct in6_px { + struct in6_addr addr; + int plen; + bool set; +}; +struct in6_pdata { + struct in6_px addr; + struct in6_px dst_addr; + struct in6_addrlifetime lifetime; + uint32_t flags; + uint32_t vhid; +}; + +static struct in6_pdata in6_del; +static struct in6_pdata in6_add = { + .lifetime = { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME }, +}; +#else static struct in6_ifreq in6_ridreq; static struct in6_aliasreq in6_addreq = { .ifra_flags = 0, .ifra_lifetime = { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME } }; +#endif static int ip6lifetime; #ifdef WITHOUT_NETLINK @@ -81,10 +101,18 @@ static char addr_buf[NI_MAXHOST]; /*for getnameinfo()*/ static void setifprefixlen(if_ctx *ctx, const char *addr, int dummy __unused) { +#ifdef WITHOUT_NETLINK const struct afswtch *afp = ctx->afp; if (afp->af_getprefix != NULL) afp->af_getprefix(addr, MASK); +#else + int plen = strtol(addr, NULL, 10); + + if ((plen < 0) || (plen > 128)) + errx(1, "%s: bad value", addr); + in6_add.addr.plen = plen; +#endif explicit_prefix = 1; } @@ -96,10 +124,17 @@ setip6flags(if_ctx *ctx, const char *dummyaddr __unused, int flag) if (afp->af_af != AF_INET6) err(1, "address flags can be set only for inet6 addresses"); +#ifdef WITHOUT_NETLINK if (flag < 0) in6_addreq.ifra_flags &= ~(-flag); else in6_addreq.ifra_flags |= flag; +#else + if (flag < 0) + in6_add.flags &= ~(-flag); + else + in6_add.flags |= flag; +#endif } static void @@ -109,6 +144,11 @@ setip6lifetime(if_ctx *ctx, const char *cmd, const char *val) struct timespec now; time_t newval; char *ep; +#ifdef WITHOUT_NETLINK + struct in6_addrlifetime *lifetime = &in6_addreq.ifra_lifetime; +#else + struct in6_addrlifetime *lifetime = &in6_add.lifetime; +#endif clock_gettime(CLOCK_MONOTONIC_FAST, &now); newval = (time_t)strtoul(val, &ep, 0); @@ -117,11 +157,11 @@ setip6lifetime(if_ctx *ctx, const char *cmd, const char *val) if (afp->af_af != AF_INET6) errx(1, "%s not allowed for the AF", cmd); if (strcmp(cmd, "vltime") == 0) { - in6_addreq.ifra_lifetime.ia6t_expire = now.tv_sec + newval; - in6_addreq.ifra_lifetime.ia6t_vltime = newval; + lifetime->ia6t_expire = now.tv_sec + newval; + lifetime->ia6t_vltime = newval; } else if (strcmp(cmd, "pltime") == 0) { - in6_addreq.ifra_lifetime.ia6t_preferred = now.tv_sec + newval; - in6_addreq.ifra_lifetime.ia6t_pltime = newval; + lifetime->ia6t_preferred = now.tv_sec + newval; + lifetime->ia6t_pltime = newval; } } @@ -148,7 +188,11 @@ setip6eui64(if_ctx *ctx, const char *cmd, int dummy __unused) if (afp->af_af != AF_INET6) errx(EXIT_FAILURE, "%s not allowed for the AF", cmd); +#ifdef WITHOUT_NETLINK in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr; +#else + in6 = &in6_add.addr.addr; +#endif if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0) errx(EXIT_FAILURE, "interface index is already filled"); if (getifaddrs(&ifap) != 0) @@ -369,8 +413,92 @@ in6_status_nl(if_ctx *ctx __unused, if_link_t *link, if_addr_t *ifa) putchar('\n'); } + +static struct in6_px *sin6tab_nl[] = { + &in6_del.addr, /* RIDADDR */ + &in6_add.addr, /* ADDR */ + NULL, /* MASK */ + &in6_add.dst_addr, /* DSTADDR*/ +}; + +static void +in6_getaddr(const char *addr_str, int which) +{ + struct in6_px *px = sin6tab_nl[which]; + + newaddr &= 1; + + px->set = true; + px->plen = 128; + if (which == ADDR) { + char *p = NULL; + if((p = strrchr(addr_str, '/')) != NULL) { + *p = '\0'; + int plen = strtol(p + 1, NULL, 10); + if (plen < 0 || plen > 128) + errx(1, "%s: bad value", p + 1); + px->plen = plen; + explicit_prefix = 1; + } + } + + struct addrinfo hints = { .ai_family = AF_INET6 }; + struct addrinfo *res; + + int error = getaddrinfo(addr_str, NULL, &hints, &res); + if (error != 0) { + if (inet_pton(AF_INET6, addr_str, &px->addr) != 1) + errx(1, "%s: bad value", addr_str); + } else { + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *)(void *)res->ai_addr; + px->addr = sin6->sin6_addr; + freeaddrinfo(res); + } +} + +static int +in6_exec_nl(if_ctx *ctx, unsigned long action, void *data) +{ + struct in6_pdata *pdata = (struct in6_pdata *)data; + struct snl_writer nw = {}; + + snl_init_writer(ctx->io_ss, &nw); + struct nlmsghdr *hdr = snl_create_msg_request(&nw, action); + struct ifaddrmsg *ifahdr = snl_reserve_msg_object(&nw, struct ifaddrmsg); + + ifahdr->ifa_family = AF_INET6; + ifahdr->ifa_prefixlen = pdata->addr.plen; + ifahdr->ifa_index = if_nametoindex_nl(ctx->io_ss, name); + + snl_add_msg_attr_ip6(&nw, IFA_LOCAL, &pdata->addr.addr); + if (action == NL_RTM_NEWADDR && pdata->dst_addr.set) + snl_add_msg_attr_ip6(&nw, IFA_ADDRESS, &pdata->dst_addr.addr); + + struct ifa_cacheinfo ci = { + .ifa_prefered = pdata->lifetime.ia6t_pltime, + .ifa_valid = pdata->lifetime.ia6t_vltime, + }; + snl_add_msg_attr(&nw, IFA_CACHEINFO, sizeof(ci), &ci); + + int off = snl_add_msg_attr_nested(&nw, IFA_FREEBSD); + snl_add_msg_attr_u32(&nw, IFAF_FLAGS, pdata->flags); + if (pdata->vhid != 0) + snl_add_msg_attr_u32(&nw, IFAF_VHID, pdata->vhid); + snl_end_attr_nested(&nw, off); + + if (!snl_finalize_msg(&nw) || !snl_send_message(ctx->io_ss, hdr)) + return (0); + + struct snl_errmsg_data e = {}; + snl_read_reply_code(ctx->io_ss, hdr->nlmsg_seq, &e); + + return (e.error); +} #endif +#ifdef WITHOUT_NETLINK static struct sockaddr_in6 *sin6tab[] = { &in6_ridreq.ifr_addr, &in6_addreq.ifra_addr, &in6_addreq.ifra_prefixmask, &in6_addreq.ifra_dstaddr @@ -434,7 +562,6 @@ in6_getaddr(const char *s, int which) } } -#ifdef WITHOUT_NETLINK static int prefix(void *val, int size) { @@ -554,7 +681,11 @@ in6_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres) static void in6_set_vhid(int vhid) { +#ifdef WITHOUT_NETLINK in6_addreq.ifra_vhid = vhid; +#else + in6_add.vhid = (uint32_t)vhid; +#endif } static struct cmd inet6_cmds[] = { @@ -602,16 +733,27 @@ static struct afswtch af_inet6 = { .af_status = in6_status_nl, #endif .af_getaddr = in6_getaddr, +#ifdef WITHOUT_NETLINK .af_getprefix = in6_getprefix, +#endif .af_other_status = nd6_status, .af_postproc = in6_postproc, .af_status_tunnel = in6_status_tunnel, .af_settunnel = in6_set_tunnel, .af_setvhid = in6_set_vhid, +#ifdef WITHOUT_NETLINK .af_difaddr = SIOCDIFADDR_IN6, .af_aifaddr = SIOCAIFADDR_IN6, .af_ridreq = &in6_addreq, .af_addreq = &in6_addreq, + .af_exec = af_exec_ioctl, +#else + .af_difaddr = NL_RTM_DELADDR, + .af_aifaddr = NL_RTM_NEWADDR, + .af_ridreq = &in6_add, + .af_addreq = &in6_add, + .af_exec = in6_exec_nl, +#endif }; static void diff --git a/sbin/ifconfig/af_link.c b/sbin/ifconfig/af_link.c index 978006c217de..8fd5e05044e2 100644 --- a/sbin/ifconfig/af_link.c +++ b/sbin/ifconfig/af_link.c @@ -228,6 +228,7 @@ static struct afswtch af_link = { .af_getaddr = link_getaddr, .af_aifaddr = SIOCSIFLLADDR, .af_addreq = &link_ridreq, + .af_exec = af_exec_ioctl, }; static struct afswtch af_ether = { .af_name = "ether", @@ -240,6 +241,7 @@ static struct afswtch af_ether = { .af_getaddr = link_getaddr, .af_aifaddr = SIOCSIFLLADDR, .af_addreq = &link_ridreq, + .af_exec = af_exec_ioctl, }; static struct afswtch af_lladdr = { .af_name = "lladdr", @@ -252,6 +254,7 @@ static struct afswtch af_lladdr = { .af_getaddr = link_getaddr, .af_aifaddr = SIOCSIFLLADDR, .af_addreq = &link_ridreq, + .af_exec = af_exec_ioctl, }; static __constructor void diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c index ba14f84f7e7e..8ae7920e6ea9 100644 --- a/sbin/ifconfig/ifconfig.c +++ b/sbin/ifconfig/ifconfig.c @@ -119,6 +119,7 @@ static void status(struct ifconfig_args *args, const struct sockaddr_dl *sdl, struct ifaddrs *ifa); #endif static _Noreturn void usage(void); +static void Perrorc(const char *cmd, int error); static int getifflags(const char *ifname, int us, bool err_ok); @@ -560,6 +561,34 @@ args_parse(struct ifconfig_args *args, int argc, char *argv[]) verbose = args->verbose; } +static int +ifconfig_wrapper(struct ifconfig_args *args, int iscreate, + const struct afswtch *uafp) +{ +#ifdef WITHOUT_NETLINK + struct ifconfig_context ctx = { + .args = args, + .io_s = -1, + }; + + return (ifconfig(&ctx, iscreate, uafp)); +#else + return (ifconfig_wrapper_nl(args, iscreate, uafp)); +#endif +} + +static bool +isargcreate(const char *arg) +{ + if (arg == NULL) + return (false); + + if (strcmp(arg, "create") == 0 || strcmp(arg, "plumb") == 0) + return (true); + + return (false); +} + int main(int ac, char *av[]) { @@ -613,13 +642,12 @@ main(int ac, char *av[]) * right here as we would otherwise fail when trying * to find the interface. */ - if (arg != NULL && (strcmp(arg, "create") == 0 || - strcmp(arg, "plumb") == 0)) { + if (isargcreate(arg)) { iflen = strlcpy(name, args->ifname, sizeof(name)); if (iflen >= sizeof(name)) errx(1, "%s: cloning name too long", args->ifname); - ifconfig(args->argc, args->argv, 1, NULL); + ifconfig_wrapper(args, 1, NULL); exit(exit_code); } #ifdef JAIL @@ -633,7 +661,7 @@ main(int ac, char *av[]) if (iflen >= sizeof(name)) errx(1, "%s: interface name too long", args->ifname); - ifconfig(args->argc, args->argv, 0, NULL); + ifconfig_wrapper(args, 0, NULL); exit(exit_code); } #endif @@ -643,8 +671,7 @@ main(int ac, char *av[]) * Do not allow use `create` command as hostname if * address family is not specified. */ - if (arg != NULL && (strcmp(arg, "create") == 0 || - strcmp(arg, "plumb") == 0)) { + if (isargcreate(arg)) { if (args->argc == 1) errx(1, "interface %s already exists", args->ifname); @@ -674,7 +701,7 @@ main(int ac, char *av[]) if (!(((flags & IFF_CANTCONFIG) != 0) || (args->downonly && (flags & IFF_UP) != 0) || (args->uponly && (flags & IFF_UP) == 0))) - ifconfig(args->argc, args->argv, 0, args->afp); + ifconfig_wrapper(args, 0, args->afp); } goto done; } @@ -802,7 +829,7 @@ list_interfaces_ioctl(struct ifconfig_args *args) ifindex++; if (args->argc > 0) - ifconfig(args->argc, args->argv, 0, args->afp); + ifconfig_wrapper(args, 0, args->afp); else status(args, sdl, ifa); } @@ -1001,31 +1028,42 @@ static void setifdstaddr(if_ctx *ctx, const char *addr, int param __unused); static const struct cmd setifdstaddr_cmd = DEF_CMD("ifdstaddr", 0, setifdstaddr); +int +af_exec_ioctl(if_ctx *ctx, unsigned long action, void *data) +{ + struct ifreq *req = (struct ifreq *)data; + + strlcpy(req->ifr_name, name, sizeof(req->ifr_name)); + if (ioctl_ctx(ctx, action, req) == 0) + return (0); + return (errno); +} + static void -delifaddr(int s, const struct afswtch *afp) +delifaddr(if_ctx *ctx, const struct afswtch *afp) { - if (afp->af_ridreq == NULL || afp->af_difaddr == 0) { + int error; + + if (afp->af_exec == NULL) { warnx("interface %s cannot change %s addresses!", name, afp->af_name); clearaddr = 0; return; } - strlcpy(((struct ifreq *)afp->af_ridreq)->ifr_name, name, - sizeof ifr.ifr_name); - int ret = ioctl(s, afp->af_difaddr, afp->af_ridreq); - if (ret < 0) { - if (errno == EADDRNOTAVAIL && (doalias >= 0)) { + error = afp->af_exec(ctx, afp->af_difaddr, afp->af_ridreq); + if (error != 0) { + if (error == EADDRNOTAVAIL && (doalias >= 0)) { /* means no previous address for interface */ } else - Perror("ioctl (SIOCDIFADDR)"); + Perrorc("ioctl (SIOCDIFADDR)", error); } } static void -addifaddr(int s, const struct afswtch *afp) +addifaddr(if_ctx *ctx, const struct afswtch *afp) { - if (afp->af_addreq == NULL || afp->af_aifaddr == 0) { + if (afp->af_exec == NULL) { warnx("interface %s cannot change %s addresses!", name, afp->af_name); newaddr = 0; @@ -1033,21 +1071,26 @@ addifaddr(int s, const struct afswtch *afp) } if (setaddr || setmask) { - strlcpy(((struct ifreq *)afp->af_addreq)->ifr_name, name, - sizeof ifr.ifr_name); - if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0) - Perror("ioctl (SIOCAIFADDR)"); + int error = afp->af_exec(ctx, afp->af_aifaddr, afp->af_addreq); + if (error != 0) + Perrorc("ioctl (SIOCAIFADDR)", error); } } int -ifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *uafp) +ifconfig(if_ctx *orig_ctx, int iscreate, const struct afswtch *uafp) { - struct ifconfig_context ctx = {}; const struct afswtch *afp, *nafp; const struct cmd *p; struct callback *cb; int s; + int argc = orig_ctx->args->argc; + char *const *argv = orig_ctx->args->argv; + struct ifconfig_context _ctx = { + .args = orig_ctx->args, + .io_ss = orig_ctx->io_ss, + }; + struct ifconfig_context *ctx = &_ctx; strlcpy(ifr.ifr_name, name, sizeof ifr.ifr_name); afp = NULL; @@ -1085,8 +1128,8 @@ top: (s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0)) err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family); - ctx.io_s = s; - ctx.afp = afp; + ctx->io_s = s; + ctx->afp = afp; while (argc > 0) { p = cmd_lookup(*argv, iscreate); @@ -1132,22 +1175,22 @@ top: if (argv[1] == NULL) errx(1, "'%s' requires argument", p->c_name); - p->c_u.c_func(&ctx, argv[1], 0); + p->c_u.c_func(ctx, argv[1], 0); argc--, argv++; } else if (p->c_parameter == OPTARG && p->c_u.c_func) { - p->c_u.c_func(&ctx, argv[1], 0); + p->c_u.c_func(ctx, argv[1], 0); if (argv[1] != NULL) argc--, argv++; } else if (p->c_parameter == NEXTARG2 && p->c_u.c_func2) { if (argc < 3) errx(1, "'%s' requires 2 arguments", p->c_name); - p->c_u.c_func2(&ctx, argv[1], argv[2]); + p->c_u.c_func2(ctx, argv[1], argv[2]); argc -= 2, argv += 2; } else if (p->c_parameter == SPARAM && p->c_u.c_func3) { - p->c_u.c_func3(&ctx, *argv, p->c_sparameter); + p->c_u.c_func3(ctx, *argv, p->c_sparameter); } else if (p->c_u.c_func) - p->c_u.c_func(&ctx, *argv, p->c_parameter); + p->c_u.c_func(ctx, *argv, p->c_parameter); argc--, argv++; } @@ -1155,7 +1198,7 @@ top: * Do any post argument processing required by the address family. */ if (afp->af_postproc != NULL) - afp->af_postproc(&ctx, newaddr, getifflags(name, s, true)); + afp->af_postproc(ctx, newaddr, getifflags(name, s, true)); /* * Do deferred callbacks registered while processing * command-line arguments. @@ -1166,9 +1209,9 @@ top: * Do deferred operations. */ if (clearaddr) - delifaddr(s, afp); + delifaddr(ctx, afp); if (newaddr) - addifaddr(s, afp); + addifaddr(ctx, afp); close(s); return(0); @@ -1276,7 +1319,7 @@ setifbroadaddr(if_ctx *ctx, const char *addr, int dummy __unused) const struct afswtch *afp = ctx->afp; if (afp->af_getaddr != NULL) - afp->af_getaddr(addr, DSTADDR); + afp->af_getaddr(addr, BRDADDR); } static void @@ -1749,8 +1792,8 @@ tunnel_status(int s) af_all_tunnel_status(s); } -void -Perror(const char *cmd) +static void +Perrorc(const char *cmd, int error) { switch (errno) { @@ -1763,10 +1806,16 @@ Perror(const char *cmd) break; default: - err(1, "%s", cmd); + errc(1, error, "%s", cmd); } } +void +Perror(const char *cmd) +{ + Perrorc(cmd, errno); +} + /* * Print a value a la the %b format of the kernel's printf */ diff --git a/sbin/ifconfig/ifconfig.h b/sbin/ifconfig/ifconfig.h index 994596f02bcb..62dc0bdfe1f4 100644 --- a/sbin/ifconfig/ifconfig.h +++ b/sbin/ifconfig/ifconfig.h @@ -152,10 +152,15 @@ struct ifaddrs; struct addrinfo; enum { - RIDADDR, - ADDR, - MASK, - DSTADDR, + RIDADDR = 0, + ADDR = 1, + MASK = 2, + DSTADDR = 3, +#ifdef WITHOUT_NETLINK + BRDADDR = 3, +#else + BRDADDR = 4, +#endif }; struct snl_parsed_addr; @@ -168,6 +173,7 @@ typedef void af_status_nl_f(if_ctx *ctx, if_link_t *link, if_addr_t *ifa); typedef void af_status_f(if_ctx *ctx, const struct ifaddrs *); typedef void af_other_status_f(if_ctx *ctx); typedef void af_postproc_f(if_ctx *ctx, int newaddr, int ifflags); +typedef int af_exec_f(if_ctx *ctx, unsigned long action, void *data); struct afswtch { const char *af_name; /* as given on cmd line, e.g. "inet" */ @@ -192,6 +198,7 @@ struct afswtch { void (*af_getprefix)(const char *, int); af_postproc_f *af_postproc; af_setvhid_f *af_setvhid; /* Set CARP vhid for an address */ + af_exec_f *af_exec; /* Handler to interact with kernel */ u_long af_difaddr; /* set dst if address ioctl */ u_long af_aifaddr; /* set if address ioctl */ void *af_ridreq; /* */ @@ -204,6 +211,7 @@ struct afswtch { struct addrinfo *dstres); }; void af_register(struct afswtch *); +int af_exec_ioctl(if_ctx *ctx, unsigned long action, void *data); struct ifconfig_args { bool all; /* Match everything */ @@ -262,7 +270,7 @@ void sfp_status(int s, struct ifreq *ifr, int verbose); struct sockaddr_dl; bool match_ether(const struct sockaddr_dl *sdl); bool match_if_flags(struct ifconfig_args *args, int if_flags); -int ifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *uafp); +int ifconfig(if_ctx *ctx, int iscreate, const struct afswtch *uafp); bool group_member(const char *ifname, const char *match, const char *nomatch); void print_ifcap(struct ifconfig_args *args, int s); void tunnel_status(int s); @@ -273,6 +281,9 @@ void print_metric(int s); /* Netlink-related functions */ void list_interfaces_nl(struct ifconfig_args *args); +int ifconfig_wrapper_nl(struct ifconfig_args *args, int iscreate, + const struct afswtch *uafp); +uint32_t if_nametoindex_nl(struct snl_state *ss, const char *ifname); /* * XXX expose this so modules that neeed to know of any pending diff --git a/sbin/ifconfig/ifconfig_netlink.c b/sbin/ifconfig/ifconfig_netlink.c index 140808e18681..ebebea33f3f6 100644 --- a/sbin/ifconfig/ifconfig_netlink.c +++ b/sbin/ifconfig/ifconfig_netlink.c @@ -122,6 +122,26 @@ nl_init_socket(struct snl_state *ss) err(1, "unable to open netlink socket"); } +int +ifconfig_wrapper_nl(struct ifconfig_args *args, int iscreate, + const struct afswtch *uafp) +{ + struct snl_state ss = {}; + struct ifconfig_context ctx = { + .args = args, + .io_s = -1, + .io_ss = &ss, + }; + *** 51 LINES SKIPPED ***