aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2020-05-18 23:19:47 -0600
committerJason A. Donenfeld <Jason@zx2c4.com>2020-05-19 17:08:34 -0600
commitf2058e4f4e9436db52908df6a566d7a7d2085908 (patch)
treed09ea56ef6d58f4c175d79030e4c889083b62e14
parentUpdate ifconfig.8 and wg.4 (diff)
downloadwireguard-openbsd-f2058e4f4e9436db52908df6a566d7a7d2085908.tar.xz
wireguard-openbsd-f2058e4f4e9436db52908df6a566d7a7d2085908.zip
Do not bring interface down and up on port/rtable change
-rw-r--r--src/if_wg.c89
1 files changed, 55 insertions, 34 deletions
diff --git a/src/if_wg.c b/src/if_wg.c
index a7518ee..73c2a0f 100644
--- a/src/if_wg.c
+++ b/src/if_wg.c
@@ -356,8 +356,8 @@ int wg_output(struct ifnet *, struct mbuf *, struct sockaddr *,
int wg_ioctl_set(struct wg_softc *, struct wg_data_io *);
int wg_ioctl_get(struct wg_softc *, struct wg_data_io *);
int wg_ioctl(struct ifnet *, u_long, caddr_t);
-int wg_up(struct wg_softc *, int);
-void wg_down(struct wg_softc *, int);
+int wg_up(struct wg_softc *);
+void wg_down(struct wg_softc *);
int wg_clone_create(struct if_clone *, int);
int wg_clone_destroy(struct ifnet *);
@@ -705,14 +705,13 @@ wg_bind(struct wg_softc *sc)
goto error;
}
- if ((ret = sobind(so4, &hostnam, curproc)) != 0) {
- sounlock(so4, s);
- goto error;
- }
-
+ ret = sobind(so4, &hostnam, curproc);
/* Update port to whatever v4 chose */
sc->sc_udp_port = sotoinpcb(so4)->inp_lport;
+ sc->sc_udp_rtable = sotoinpcb(so4)->inp_rtableid;
sounlock(so4, s);
+ if (ret)
+ goto error;
/* Listen v6 */
sin6 = mtod(&hostnam, struct sockaddr_in6 *);
@@ -732,11 +731,11 @@ wg_bind(struct wg_softc *sc)
goto error;
}
- if ((ret = sobind(so6, &hostnam, curproc)) != 0) {
- sounlock(so6, s);
- goto error;
- }
+ ret = sobind(so6, &hostnam, curproc);
+ sc->sc_udp_rtable = sotoinpcb(so6)->inp_rtableid;
sounlock(so6, s);
+ if (ret)
+ goto error;
/* Set wg_softc sockets to new values */
sc->sc_so4 = so4;
@@ -2084,7 +2083,7 @@ wg_ioctl_set(struct wg_softc *sc, struct wg_data_io *data)
uint8_t public[WG_KEY_SIZE], private[WG_KEY_SIZE];
size_t i, j;
- int ret, has_identity;
+ int ret, has_identity, already_set_rtable = false;
if ((ret = suser(curproc)) != 0)
return ret;
@@ -2119,21 +2118,47 @@ wg_ioctl_set(struct wg_softc *sc, struct wg_data_io *data)
noise_local_unlock_identity(&sc->sc_local);
}
- if ((iface_o.i_flags & WG_INTERFACE_HAS_PORT &&
- sc->sc_udp_port != htons(iface_o.i_port)) ||
- (iface_o.i_flags & WG_INTERFACE_HAS_RTABLE &&
- sc->sc_udp_rtable != iface_o.i_rtable)) {
- if (iface_o.i_flags & WG_INTERFACE_HAS_PORT)
- sc->sc_udp_port = htons(iface_o.i_port);
+ if (iface_o.i_flags & WG_INTERFACE_HAS_PORT &&
+ sc->sc_udp_port != htons(iface_o.i_port)) {
+ sc->sc_udp_port = htons(iface_o.i_port);
if (iface_o.i_flags & WG_INTERFACE_HAS_RTABLE)
sc->sc_udp_rtable = iface_o.i_rtable;
- NET_LOCK();
if (ISSET(sc->sc_if.if_flags, IFF_RUNNING)) {
- wg_down(sc, 0);
- if ((ret = wg_up(sc, 0)) != 0)
+ wg_unbind(sc);
+ if ((ret = wg_bind(sc)) != 0)
+ goto error;
+ already_set_rtable = true;
+
+ }
+ }
+ if (iface_o.i_flags & WG_INTERFACE_HAS_RTABLE &&
+ sc->sc_udp_rtable != iface_o.i_rtable && !already_set_rtable) {
+ sc->sc_udp_rtable = iface_o.i_rtable;
+ if (ISSET(sc->sc_if.if_flags, IFF_RUNNING)) {
+ struct socket *so4, *so6;
+ struct mbuf rtable;
+ m_inithdr(&rtable);
+ bzero(mtod(&rtable, u_int *), sizeof(u_int));
+ *mtod(&rtable, u_int *) = sc->sc_udp_rtable;
+ rtable.m_len = sizeof(u_int);
+ NET_LOCK();
+ so4 = sc->sc_so4;
+ so6 = sc->sc_so6;
+ ret = 0;
+ if (so4)
+ ret = sosetopt(so4, SOL_SOCKET, SO_RTABLE, &rtable);
+ if (so6 && !ret)
+ ret = sosetopt(so6, SOL_SOCKET, SO_RTABLE, &rtable);
+ if (so4)
+ sc->sc_udp_rtable = sotoinpcb(so4)->inp_rtableid;
+ if (so6)
+ sc->sc_udp_rtable = sotoinpcb(so6)->inp_rtableid;
+ NET_UNLOCK();
+ WG_PEERS_FOREACH(peer, sc)
+ wg_peer_clear_src(peer);
+ if (ret)
goto error;
}
- NET_UNLOCK();
}
peer_p = &iface_p->i_peers[0];
@@ -2344,9 +2369,9 @@ wg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
/* FALLTHROUGH */
case SIOCSIFFLAGS:
if (ISSET(ifp->if_flags, IFF_UP))
- ret = wg_up(sc, 1);
+ ret = wg_up(sc);
else
- wg_down(sc, 1);
+ wg_down(sc);
break;
case SIOCSIFMTU:
/* Arbitrary limits */
@@ -2366,7 +2391,7 @@ wg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
}
int
-wg_up(struct wg_softc *sc, int need_lock)
+wg_up(struct wg_softc *sc)
{
struct wg_peer *peer;
int ret = 0;
@@ -2380,8 +2405,7 @@ wg_up(struct wg_softc *sc, int need_lock)
SET(sc->sc_if.if_flags, IFF_RUNNING);
NET_UNLOCK();
- if (need_lock)
- rw_enter_write(&sc->sc_lock);
+ rw_enter_write(&sc->sc_lock);
/* If we successfully bind the socket, then enable the timers
* for the peer. This will send all staged packets and a
* keepalive if necessary. */
@@ -2391,8 +2415,7 @@ wg_up(struct wg_softc *sc, int need_lock)
wg_queue_out(sc, peer);
}
}
- if (need_lock)
- rw_exit_write(&sc->sc_lock);
+ rw_exit_write(&sc->sc_lock);
NET_LOCK();
if (ret != 0)
@@ -2402,7 +2425,7 @@ wg_up(struct wg_softc *sc, int need_lock)
}
void
-wg_down(struct wg_softc *sc, int need_lock)
+wg_down(struct wg_softc *sc)
{
struct wg_peer *peer;
@@ -2414,8 +2437,7 @@ wg_down(struct wg_softc *sc, int need_lock)
/* We only need a read lock here, as we aren't writing to anything
* that isn't granularly locked. */
- if (need_lock)
- rw_enter_read(&sc->sc_lock);
+ rw_enter_read(&sc->sc_lock);
WG_PEERS_FOREACH(peer, sc) {
mq_purge(&peer->p_stage_queue);
wg_timers_disable(&peer->p_timers);
@@ -2429,8 +2451,7 @@ wg_down(struct wg_softc *sc, int need_lock)
}
wg_unbind(sc);
- if (need_lock)
- rw_exit_read(&sc->sc_lock);
+ rw_exit_read(&sc->sc_lock);
NET_LOCK();
}