diff options
author | Alexander V. Chernikov <melifaro@FreeBSD.org> | 2023-05-25 14:50:57 +0000 |
---|---|---|
committer | Alexander V. Chernikov <melifaro@FreeBSD.org> | 2023-05-25 15:03:35 +0000 |
commit | 6d204407ec6eb3403306578a2550a92b8560d92b (patch) | |
tree | 022e78d2f096277d3d46a55d3dccbb576e2b797f | |
parent | 6c08fd3dc804c9c3064add3b9a6ff678a541d210 (diff) | |
download | src-6d204407ec6eb3403306578a2550a92b8560d92b.tar.gz src-6d204407ec6eb3403306578a2550a92b8560d92b.zip |
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
-rw-r--r-- | sbin/ifconfig/af_inet.c | 14 | ||||
-rw-r--r-- | sbin/ifconfig/af_inet6.c | 14 | ||||
-rw-r--r-- | sbin/ifconfig/ifconfig.c | 11 | ||||
-rw-r--r-- | 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 @@ -202,6 +202,12 @@ static struct sockaddr_in *sintab[] = { }; 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) { struct sockaddr_in *sin = sintab[which]; @@ -257,6 +263,13 @@ static struct in_px *sintab_nl[] = { }; 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) { struct hostent *hp; @@ -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 @@ -422,6 +422,13 @@ static struct in6_px *sin6tab_nl[] = { }; 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) { struct in6_px *px = sin6tab_nl[which]; @@ -505,6 +512,12 @@ static struct sockaddr_in6 *sin6tab[] = { }; 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) { struct sockaddr_in6 *sin = sin6tab[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; |