summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/netinet/in.c97
-rw-r--r--sys/netinet/in.h3
2 files changed, 66 insertions, 34 deletions
diff --git a/sys/netinet/in.c b/sys/netinet/in.c
index 10f19cc11fd..9263a59df8a 100644
--- a/sys/netinet/in.c
+++ b/sys/netinet/in.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in.c,v 1.163 2019/07/25 13:56:24 krw Exp $ */
+/* $OpenBSD: in.c,v 1.164 2019/10/23 19:58:32 bluhm Exp $ */
/* $NetBSD: in.c,v 1.26 1996/02/13 23:41:39 christos Exp $ */
/*
@@ -185,6 +185,18 @@ in_nam2sin(const struct mbuf *nam, struct sockaddr_in **sin)
}
int
+in_sa2sin(struct sockaddr *sa, struct sockaddr_in **sin)
+{
+ if (sa->sa_family != AF_INET)
+ return EAFNOSUPPORT;
+ if (sa->sa_len != sizeof(struct sockaddr_in))
+ return EINVAL;
+ *sin = satosin(sa);
+
+ return 0;
+}
+
+int
in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp)
{
int privileged;
@@ -372,28 +384,29 @@ in_ioctl_change_ifaddr(u_long cmd, caddr_t data, struct ifnet *ifp,
struct ifaddr *ifa;
struct in_ifaddr *ia = NULL;
struct in_aliasreq *ifra = (struct in_aliasreq *)data;
+ struct sockaddr_in *sin = NULL, *dstsin = NULL, *broadsin = NULL;
int error = 0;
int newifaddr;
+ if (ifra->ifra_addr.sin_family == AF_INET) {
+ error = in_sa2sin(sintosa(&ifra->ifra_addr), &sin);
+ if (error)
+ return (error);
+ }
+
NET_LOCK();
TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
- if (ifa->ifa_addr->sa_family == AF_INET) {
+ if (ifa->ifa_addr->sa_family != AF_INET)
+ continue;
+ /* find first address, if no exact match wanted */
+ if (sin == NULL || sin->sin_addr.s_addr ==
+ ifatoia(ifa)->ia_addr.sin_addr.s_addr) {
ia = ifatoia(ifa);
break;
}
}
- if (ifra->ifra_addr.sin_family == AF_INET) {
- for (; ifa != NULL; ifa = TAILQ_NEXT(ifa, ifa_list)) {
- if ((ifa->ifa_addr->sa_family == AF_INET) &&
- ifatoia(ifa)->ia_addr.sin_addr.s_addr ==
- ifra->ifra_addr.sin_addr.s_addr)
- break;
- }
- ia = ifatoia(ifa);
- }
-
switch (cmd) {
case SIOCAIFADDR: {
int needinit = 0;
@@ -403,6 +416,27 @@ in_ioctl_change_ifaddr(u_long cmd, caddr_t data, struct ifnet *ifp,
break;
}
+ if (ifra->ifra_mask.sin_len) {
+ if (ifra->ifra_mask.sin_len < 8) {
+ error = EINVAL;
+ break;
+ }
+ }
+ if ((ifp->if_flags & IFF_POINTOPOINT) &&
+ ifra->ifra_dstaddr.sin_family == AF_INET) {
+ error = in_sa2sin(sintosa(&ifra->ifra_dstaddr),
+ &dstsin);
+ if (error)
+ break;
+ }
+ if ((ifp->if_flags & IFF_BROADCAST) &&
+ ifra->ifra_broadaddr.sin_family == AF_INET) {
+ error = in_sa2sin(sintosa(&ifra->ifra_broadaddr),
+ &broadsin);
+ if (error)
+ break;
+ }
+
if (ia == NULL) {
ia = malloc(sizeof *ia, M_IFADDR, M_WAITOK | M_ZERO);
ia->ia_addr.sin_family = AF_INET;
@@ -421,41 +455,38 @@ in_ioctl_change_ifaddr(u_long cmd, caddr_t data, struct ifnet *ifp,
} else
newifaddr = 0;
- if (ia->ia_addr.sin_family == AF_INET) {
- if (ifra->ifra_addr.sin_len == 0)
- ifra->ifra_addr = ia->ia_addr;
- else if (ifra->ifra_addr.sin_addr.s_addr !=
- ia->ia_addr.sin_addr.s_addr || newifaddr)
- needinit = 1;
+ if (sin == NULL) {
+ sin = &ia->ia_addr;
+ } else if (newifaddr ||
+ sin->sin_addr.s_addr != ia->ia_addr.sin_addr.s_addr) {
+ needinit = 1;
}
if (ifra->ifra_mask.sin_len) {
in_ifscrub(ifp, ia);
- ia->ia_sockmask = ifra->ifra_mask;
- ia->ia_netmask = ia->ia_sockmask.sin_addr.s_addr;
+ ia->ia_netmask = ia->ia_sockmask.sin_addr.s_addr =
+ ifra->ifra_mask.sin_addr.s_addr;
needinit = 1;
}
- if ((ifp->if_flags & IFF_POINTOPOINT) &&
- (ifra->ifra_dstaddr.sin_family == AF_INET)) {
+ if (dstsin != NULL) {
in_ifscrub(ifp, ia);
- ia->ia_dstaddr = ifra->ifra_dstaddr;
- needinit = 1;
+ ia->ia_dstaddr = *dstsin;
+ needinit = 1;
}
- if ((ifp->if_flags & IFF_BROADCAST) &&
- (ifra->ifra_broadaddr.sin_family == AF_INET)) {
+ if (broadsin != NULL) {
if (newifaddr)
- ia->ia_broadaddr = ifra->ifra_broadaddr;
+ ia->ia_broadaddr = *broadsin;
else
ifa_update_broadaddr(ifp, &ia->ia_ifa,
- sintosa(&ifra->ifra_broadaddr));
+ sintosa(broadsin));
}
- if (ifra->ifra_addr.sin_family == AF_INET && needinit) {
- error = in_ifinit(ifp, ia, &ifra->ifra_addr, newifaddr);
+ if (needinit) {
+ error = in_ifinit(ifp, ia, sin, newifaddr);
+ if (error)
+ break;
}
- if (error)
- break;
dohooks(ifp->if_addrhooks, 0);
break;
- }
+ }
case SIOCDIFADDR:
if (!privileged) {
error = EPERM;
diff --git a/sys/netinet/in.h b/sys/netinet/in.h
index 5190efc0206..48111a1c5bc 100644
--- a/sys/netinet/in.h
+++ b/sys/netinet/in.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: in.h,v 1.133 2018/10/13 18:36:01 florian Exp $ */
+/* $OpenBSD: in.h,v 1.134 2019/10/23 19:58:32 bluhm Exp $ */
/* $NetBSD: in.h,v 1.20 1996/02/13 23:41:47 christos Exp $ */
/*
@@ -818,6 +818,7 @@ void in_ifdetach(struct ifnet *);
int in_mask2len(struct in_addr *);
void in_len2mask(struct in_addr *, int);
int in_nam2sin(const struct mbuf *, struct sockaddr_in **);
+int in_sa2sin(struct sockaddr *, struct sockaddr_in **);
char *inet_ntoa(struct in_addr);
int inet_nat64(int, const void *, void *, const void *, u_int8_t);