Skip to content

Commit

Permalink
Free wireguard_device after netif is removed
Browse files Browse the repository at this point in the history
The wireguard_device stored as the netif state pointer must remain valid until
after the netif is removed.  During removal, packets may be sent to disconnect
TCP sockets and such requiring a valid device for the wireguardif_output
function.

Move the device free from the wireguardif_shutdown function into a new
wireguardif_fini function which is called after the netif_remove.  Add a device
check in wireguardif_output as a precaution.

Make an explicit call to clear the IPv4 address of the Wireguard interface when
disconnecting.  The call mimics the behavior in netif_remove however it is
performed before the Wireguard peers are shutdown.  As a result, the TCP reset
packets can be sent.
  • Loading branch information
jefftharris committed Aug 14, 2023
1 parent a441e52 commit 5754fdd
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 1 deletion.
5 changes: 5 additions & 0 deletions src/esp_wireguard.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,10 @@ esp_err_t esp_wireguard_disconnect(wireguard_ctx_t *ctx)
goto fail;
}

// Clear the IP address to gracefully disconnect any clients while the
// peers are still valid
netif_set_ipaddr(ctx->netif, IP4_ADDR_ANY4);

lwip_err = wireguardif_disconnect(ctx->netif, wireguard_peer_index);
if (lwip_err != ERR_OK) {
ESP_LOGW(TAG, "wireguardif_disconnect: peer_index: %" PRIu8 " err: %i", wireguard_peer_index, lwip_err);
Expand All @@ -312,6 +316,7 @@ esp_err_t esp_wireguard_disconnect(wireguard_ctx_t *ctx)
wireguard_peer_index = WIREGUARDIF_INVALID_INDEX;
wireguardif_shutdown(ctx->netif);
netif_remove(ctx->netif);
wireguardif_fini(ctx->netif);
netif_set_default(ctx->netif_default);
ctx->netif = NULL;

Expand Down
16 changes: 15 additions & 1 deletion src/wireguardif.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,14 @@ static err_t wireguardif_output_to_peer(struct netif *netif, struct pbuf *q, con
// The ipaddr here is the one inside the VPN which we use to lookup the correct peer/endpoint
static err_t wireguardif_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ip4addr) {
struct wireguard_device *device = (struct wireguard_device *)netif->state;
// Send to peer that matches dest IP
ip_addr_t ipaddr;

if (!device) {
ESP_LOGE(TAG, "wireguardif_output NULL device");
return ERR_RTE;
}

// Send to peer that matches dest IP
ip_addr_copy_from_ip4(ipaddr, *ip4addr);
struct wireguard_peer *peer = peer_lookup_by_allowed_ip(device, &ipaddr);
if (peer) {
Expand Down Expand Up @@ -1037,6 +1043,14 @@ void wireguardif_shutdown(struct netif *netif) {
udp_remove(device->udp_pcb);
device->udp_pcb = NULL;
}
}

void wireguardif_fini(struct netif *netif) {
LWIP_ASSERT("netif != NULL", (netif != NULL));
LWIP_ASSERT("state != NULL", (netif->state != NULL));

struct wireguard_device *device = (struct wireguard_device *)netif->state;

// remove device context.
free(device);
netif->state = NULL;
Expand Down
3 changes: 3 additions & 0 deletions src/wireguardif.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ err_t wireguardif_disconnect(struct netif *netif, u8_t peer_index);
// Shutdown the WireGuard interface
void wireguardif_shutdown(struct netif *netif);

// Finalize the WireGuard interface after the netif is removed
void wireguardif_fini(struct netif *netif);

// Is the given peer "up"? A peer is up if it has a valid session key it can communicate with
err_t wireguardif_peer_is_up(struct netif *netif, u8_t peer_index, ip_addr_t *current_ip, u16_t *current_port);

Expand Down

0 comments on commit 5754fdd

Please sign in to comment.