git: 6d204407ec6e - main - ifconfig: fix ifconfig IFX inet[6] ADDR -alias

From: Alexander V. Chernikov <melifaro_at_FreeBSD.org>
Date: Thu, 25 May 2023 15:03:57 UTC
The branch main has been updated by melifaro:

URL: https://cgit.FreeBSD.org/src/commit/?id=6d204407ec6eb3403306578a2550a92b8560d92b

commit 6d204407ec6eb3403306578a2550a92b8560d92b
Author:     Alexander V. Chernikov <melifaro@FreeBSD.org>
AuthorDate: 2023-05-25 14:50:57 +0000
Commit:     Alexander V. Chernikov <melifaro@FreeBSD.org>
CommitDate: 2023-05-25 15:03:35 +0000

    ifconfig: fix ifconfig IFX inet[6] ADDR -alias
    
    Internally, inet and inet6 family handlers store state for
     address addition and deletion separately, as, for example,
     "ifconfig lo0 inet 127.0.0.2/32" triggers a) deletion of the
     first interface address and b) addition of a new one.
    The current logic behind handling "-alias" being the last argument
     is to copy the address from "addition" state to the "deletion"
     state. It is done by the generic ifconfig code, which explicitly
     typecasts opaque handler state pointers to "struct ifreq", which
     doesn't work in the Netlink case.
    
    Fix this by introducing family-specific "af_copyaddr" handler,
     which removes the peeking & typecasting logic from the generic code.
    
    Reported by:    otis
    Tested by:      otis
---
 sbin/ifconfig/af_inet.c  | 14 ++++++++++++++
 sbin/ifconfig/af_inet6.c | 14 ++++++++++++++
 sbin/ifconfig/ifconfig.c | 11 ++++-------
 sbin/ifconfig/ifconfig.h |  2 ++
 4 files changed, 34 insertions(+), 7 deletions(-)

diff --git a/sbin/ifconfig/af_inet.c b/sbin/ifconfig/af_inet.c
index 73decb229d0f..76787e62d908 100644
--- a/sbin/ifconfig/af_inet.c
+++ b/sbin/ifconfig/af_inet.c
@@ -201,6 +201,12 @@ static struct sockaddr_in *sintab[] = {
 	SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr)
 };
 
+static void
+in_copyaddr(if_ctx *ctx, int to, int from)
+{
+	memcpy(sintab[to], sintab[from], sizeof(struct sockaddr_in));
+}
+
 static void
 in_getaddr(const char *s, int which)
 {
@@ -256,6 +262,13 @@ static struct in_px *sintab_nl[] = {
 	&in_add.brd_addr,	/* BRDADDR*/
 };
 
+static void
+in_copyaddr(if_ctx *ctx, int to, int from)
+{
+	sintab_nl[to]->addr = sintab_nl[from]->addr;
+	sintab_nl[to]->addrset = sintab_nl[from]->addrset;
+}
+
 static void
 in_getip(const char *addr_str, struct in_addr *ip)
 {
@@ -537,6 +550,7 @@ static struct afswtch af_inet = {
 	.af_status	= in_status_nl,
 #endif
 	.af_getaddr	= in_getaddr,
+	.af_copyaddr	= in_copyaddr,
 	.af_postproc	= in_postproc,
 	.af_status_tunnel = in_status_tunnel,
 	.af_settunnel	= in_set_tunnel,
diff --git a/sbin/ifconfig/af_inet6.c b/sbin/ifconfig/af_inet6.c
index d5418b827789..f735afdc8797 100644
--- a/sbin/ifconfig/af_inet6.c
+++ b/sbin/ifconfig/af_inet6.c
@@ -421,6 +421,13 @@ static struct in6_px *sin6tab_nl[] = {
         &in6_add.dst_addr,      /* DSTADDR*/
 };
 
+static void
+in6_copyaddr(if_ctx *ctx, int to, int from)
+{
+	sin6tab_nl[to]->addr = sin6tab_nl[from]->addr;
+	sin6tab_nl[to]->set = sin6tab_nl[from]->set;
+}
+
 static void
 in6_getaddr(const char *addr_str, int which)
 {
@@ -504,6 +511,12 @@ static struct	sockaddr_in6 *sin6tab[] = {
 	&in6_addreq.ifra_prefixmask, &in6_addreq.ifra_dstaddr
 };
 
+static void
+in6_copyaddr(if_ctx *ctx, int to, int from)
+{
+	memcpy(sin6tab[to], sin6tab[from], sizeof(struct sockaddr_in6));
+}
+
 static void
 in6_getprefix(const char *plen, int which)
 {
@@ -733,6 +746,7 @@ static struct afswtch af_inet6 = {
 	.af_status	= in6_status_nl,
 #endif
 	.af_getaddr	= in6_getaddr,
+	.af_copyaddr	= in6_copyaddr,
 #ifdef WITHOUT_NETLINK
 	.af_getprefix	= in6_getprefix,
 #endif
diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c
index 8ae7920e6ea9..84df15a58ce1 100644
--- a/sbin/ifconfig/ifconfig.c
+++ b/sbin/ifconfig/ifconfig.c
@@ -1327,19 +1327,16 @@ notealias(if_ctx *ctx, const char *addr, int param)
 {
 	const struct afswtch *afp = ctx->afp;
 
-#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
-	if (setaddr && doalias == 0 && param < 0)
-		if (afp->af_addreq != NULL && afp->af_ridreq != NULL)
-			bcopy((caddr_t)rqtosa(af_addreq),
-			      (caddr_t)rqtosa(af_ridreq),
-			      rqtosa(af_addreq)->sa_len);
+	if (setaddr && doalias == 0 && param < 0) {
+		if (afp->af_copyaddr != NULL)
+			afp->af_copyaddr(ctx, RIDADDR, ADDR);
+	}
 	doalias = param;
 	if (param < 0) {
 		clearaddr = 1;
 		newaddr = 0;
 	} else
 		clearaddr = 0;
-#undef rqtosa
 }
 
 static void
diff --git a/sbin/ifconfig/ifconfig.h b/sbin/ifconfig/ifconfig.h
index 62dc0bdfe1f4..054e7a12f488 100644
--- a/sbin/ifconfig/ifconfig.h
+++ b/sbin/ifconfig/ifconfig.h
@@ -174,6 +174,7 @@ 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);
+typedef void af_copyaddr_f(if_ctx *ctx, int to, int from);
 
 struct afswtch {
 	const char	*af_name;	/* as given on cmd line, e.g. "inet" */
@@ -194,6 +195,7 @@ struct afswtch {
 #endif
 	af_other_status_f	*af_other_status;
 	void		(*af_getaddr)(const char *, int);
+	af_copyaddr_f	*af_copyaddr;	/* Copy address between <RID|*>ADDR */
 					/* parse prefix method (IPv6) */
 	void		(*af_getprefix)(const char *, int);
 	af_postproc_f	*af_postproc;