diff --git a/src/WireGuard-ESP32.h b/src/WireGuard-ESP32.h index b30c884..8477514 100644 --- a/src/WireGuard-ESP32.h +++ b/src/WireGuard-ESP32.h @@ -4,14 +4,17 @@ */ #pragma once #include +#include "esp_netif.h" class WireGuard { private: bool _is_initialized = false; + public: - bool begin(const IPAddress& localIP, const IPAddress& Subnet, const IPAddress& Gateway, const char* privateKey, const char* remotePeerAddress, const char* remotePeerPublicKey, uint16_t remotePeerPort); - bool begin(const IPAddress& localIP, const char* privateKey, const char* remotePeerAddress, const char* remotePeerPublicKey, uint16_t remotePeerPort); + esp_netif_t *netif(); + bool begin(const IPAddress &localIP, const IPAddress &Subnet, const IPAddress &Gateway, const char *privateKey, const char *remotePeerAddress, const char *remotePeerPublicKey, uint16_t remotePeerPort); + bool begin(const IPAddress &localIP, const char *privateKey, const char *remotePeerAddress, const char *remotePeerPublicKey, uint16_t remotePeerPort); void end(); bool is_initialized() const { return this->_is_initialized; } }; diff --git a/src/WireGuard.cpp b/src/WireGuard.cpp index ce69650..84b9c24 100644 --- a/src/WireGuard.cpp +++ b/src/WireGuard.cpp @@ -8,15 +8,24 @@ #include "freertos/task.h" #include "freertos/event_groups.h" #include "esp_system.h" +#include "esp_event.h" +#include "esp_netif_types.h" +#include "esp_netif_net_stack.h" #include "lwip/err.h" #include "lwip/sys.h" #include "lwip/ip.h" +#include "lwip/ip4.h" +#include "lwip/esp_netif_net_stack.h" +#include "lwip/netif.h" +#include "lwip/opt.h" #include "lwip/netdb.h" +#include "lwip/tcpip.h" #include "esp32-hal-log.h" -extern "C" { +extern "C" +{ #include "wireguardif.h" #include "wireguard-platform.h" } @@ -24,12 +33,66 @@ extern "C" { // Wireguard instance static struct netif wg_netif_struct = {0}; static struct netif *wg_netif = NULL; +static esp_netif_t *wg_esp_netif = NULL; static struct netif *previous_default_netif = NULL; static uint8_t wireguard_peer_index = WIREGUARDIF_INVALID_INDEX; #define TAG "[WireGuard] " -bool WireGuard::begin(const IPAddress& localIP, const IPAddress& Subnet, const IPAddress& Gateway, const char* privateKey, const char* remotePeerAddress, const char* remotePeerPublicKey, uint16_t remotePeerPort) { +typedef struct +{ + esp_netif_driver_base_t base; + struct netif *lwip_nif; +} wg_driver_glue_t; + +static err_t wg_lwip_init(netif *netif) +{ + return ERR_OK; +} + +static void wg_lwip_input(void *h, void *buffer, size_t len, void *eb) +{ + if (buffer) + { + pbuf_free((struct pbuf *)buffer); + } +} + +static esp_err_t wg_driver_transmit(void *h, void *buffer, size_t len) +{ + log_w(TAG "wg_driver_transmit called unexpectedly, len=%u", (unsigned)len); + esp_netif_free_rx_buffer(h, buffer); + + return ESP_OK; +} + +static void wg_driver_free_rx(void *h, void *buffer) {} + +static esp_err_t wg_post_attach(esp_netif_t *esp_netif, void *args) +{ + wg_driver_glue_t *glue = (wg_driver_glue_t *)args; + const esp_netif_driver_ifconfig_t ifc = { + .handle = glue, + .transmit = wg_driver_transmit, + .driver_free_rx_buffer = wg_driver_free_rx, + }; + esp_netif_set_driver_config(esp_netif, &ifc); + glue->base.netif = esp_netif; + + return ESP_OK; +} + +/* ------------------------------------------------------------- */ +static wg_driver_glue_t *create_wg_glue(struct netif *lwip) +{ + auto *g = (wg_driver_glue_t *)calloc(1, sizeof(wg_driver_glue_t)); + g->base.post_attach = wg_post_attach; + g->lwip_nif = lwip; + return g; +} + +bool WireGuard::begin(const IPAddress &localIP, const IPAddress &Subnet, const IPAddress &Gateway, const char *privateKey, const char *remotePeerAddress, const char *remotePeerPublicKey, uint16_t remotePeerPort) +{ struct wireguardif_init_data wg; struct wireguardif_peer peer; ip_addr_t ipaddr = IPADDR4_INIT(static_cast(localIP)); @@ -43,92 +106,149 @@ bool WireGuard::begin(const IPAddress& localIP, const IPAddress& Subnet, const I // Setup the WireGuard device structure wg.private_key = privateKey; - wg.listen_port = remotePeerPort; - + wg.listen_port = remotePeerPort; + wg.bind_netif = NULL; // Initialise the first WireGuard peer structure wireguardif_peer_init(&peer); // If we know the endpoint's address can add here bool success_get_endpoint_ip = false; - for(int retry = 0; retry < 5; retry++) { - ip_addr_t endpoint_ip = IPADDR4_INIT_BYTES(0, 0, 0, 0); - struct addrinfo *res = NULL; - struct addrinfo hint; - memset(&hint, 0, sizeof(hint)); - memset(&endpoint_ip, 0, sizeof(endpoint_ip)); - if( lwip_getaddrinfo(remotePeerAddress, NULL, &hint, &res) != 0 ) { + for (int retry = 0; retry < 5; retry++) + { + ip_addr_t endpoint_ip = IPADDR4_INIT_BYTES(0, 0, 0, 0); + struct addrinfo *res = NULL; + struct addrinfo hint; + memset(&hint, 0, sizeof(hint)); + memset(&endpoint_ip, 0, sizeof(endpoint_ip)); + if (lwip_getaddrinfo(remotePeerAddress, NULL, &hint, &res) != 0) + { vTaskDelay(pdMS_TO_TICKS(2000)); continue; } success_get_endpoint_ip = true; - struct in_addr addr4 = ((struct sockaddr_in *) (res->ai_addr))->sin_addr; - inet_addr_to_ip4addr(ip_2_ip4(&endpoint_ip), &addr4); - lwip_freeaddrinfo(res); - - peer.endpoint_ip = endpoint_ip; - log_i(TAG "%s is %3d.%3d.%3d.%3d" - , remotePeerAddress - , (endpoint_ip.u_addr.ip4.addr >> 0) & 0xff - , (endpoint_ip.u_addr.ip4.addr >> 8) & 0xff - , (endpoint_ip.u_addr.ip4.addr >> 16) & 0xff - , (endpoint_ip.u_addr.ip4.addr >> 24) & 0xff - ); + struct in_addr addr4 = ((struct sockaddr_in *)(res->ai_addr))->sin_addr; + inet_addr_to_ip4addr(ip_2_ip4(&endpoint_ip), &addr4); + lwip_freeaddrinfo(res); + + peer.endpoint_ip = endpoint_ip; + log_i(TAG "%s is %3d.%3d.%3d.%3d", remotePeerAddress, (endpoint_ip.u_addr.ip4.addr >> 0) & 0xff, (endpoint_ip.u_addr.ip4.addr >> 8) & 0xff, (endpoint_ip.u_addr.ip4.addr >> 16) & 0xff, (endpoint_ip.u_addr.ip4.addr >> 24) & 0xff); break; - } - if( !success_get_endpoint_ip ) { + } + if (!success_get_endpoint_ip) + { log_e(TAG "failed to get endpoint ip."); return false; } + + LOCK_TCPIP_CORE(); // Register the new WireGuard network interface with lwIP wg_netif = netif_add(&wg_netif_struct, ip_2_ip4(&ipaddr), ip_2_ip4(&netmask), ip_2_ip4(&gateway), &wg, &wireguardif_init, &ip_input); - if( wg_netif == nullptr ) { + if (wg_netif == nullptr) + { log_e(TAG "failed to initialize WG netif."); return false; } + UNLOCK_TCPIP_CORE(); + + esp_netif_inherent_config_t inh = ESP_NETIF_INHERENT_DEFAULT_ETH(); + inh.flags = (esp_netif_flags_t)(ESP_NETIF_FLAG_AUTOUP); + inh.route_prio = 20; + inh.get_ip_event = 0; + inh.lost_ip_event = 0; + inh.if_key = "WG_DEF"; + inh.if_desc = "wg"; + + static const esp_netif_netstack_config_t wg_netstack = { + .lwip = { + .init_fn = wg_lwip_init, + .input_fn = wg_lwip_input, + }}; + esp_netif_config_t cfg = { + .base = &inh, + .driver = nullptr, + .stack = &wg_netstack, + }; + + wg_esp_netif = esp_netif_new(&cfg); + if (!wg_esp_netif) + { + log_w(TAG "esp_netif_new failed"); + return false; + } + + esp_netif_dhcpc_stop(wg_esp_netif); + wg_driver_glue_t *wg_glue = create_wg_glue(wg_netif); + esp_netif_attach(wg_esp_netif, wg_glue); + + ip_event_got_ip_t evt = {}; + evt.esp_netif = wg_esp_netif; + evt.ip_changed = true; + evt.ip_info.ip.addr = ipaddr.u_addr.ip4.addr; + evt.ip_info.gw.addr = gateway.u_addr.ip4.addr; + evt.ip_info.netmask.addr = netmask.u_addr.ip4.addr; + + esp_netif_set_ip_info(wg_esp_netif, &evt.ip_info); + esp_netif_action_connected(wg_esp_netif, NULL, 0, NULL); + // Mark the interface as administratively up, link up flag is set automatically when peer connects + LOCK_TCPIP_CORE(); netif_set_up(wg_netif); + netif_set_link_up(wg_netif); + UNLOCK_TCPIP_CORE(); peer.public_key = remotePeerPublicKey; peer.preshared_key = NULL; // Allow all IPs through tunnel - { - ip_addr_t allowed_ip = IPADDR4_INIT_BYTES(0, 0, 0, 0); - peer.allowed_ip = allowed_ip; - ip_addr_t allowed_mask = IPADDR4_INIT_BYTES(0, 0, 0, 0); - peer.allowed_mask = allowed_mask; - } - + { + ip_addr_t allowed_ip = IPADDR4_INIT_BYTES(0, 0, 0, 0); + peer.allowed_ip = allowed_ip; + ip_addr_t allowed_mask = IPADDR4_INIT_BYTES(0, 0, 0, 0); + peer.allowed_mask = allowed_mask; + } + peer.endport_port = remotePeerPort; - // Initialize the platform - wireguard_platform_init(); + // Initialize the platform + wireguard_platform_init(); // Register the new WireGuard peer with the netwok interface wireguardif_add_peer(wg_netif, &peer, &wireguard_peer_index); - if ((wireguard_peer_index != WIREGUARDIF_INVALID_INDEX) && !ip_addr_isany(&peer.endpoint_ip)) { + if ((wireguard_peer_index != WIREGUARDIF_INVALID_INDEX) && !ip_addr_isany(&peer.endpoint_ip)) + { // Start outbound connection to peer - log_i(TAG "connecting wireguard..."); + log_i(TAG "connecting wireguard..."); wireguardif_connect(wg_netif, wireguard_peer_index); // Save the current default interface for restoring when shutting down the WG interface. previous_default_netif = netif_default; // Set default interface to WG device. - netif_set_default(wg_netif); + LOCK_TCPIP_CORE(); + netif_set_default(wg_netif); + UNLOCK_TCPIP_CORE(); } this->_is_initialized = true; return true; } -bool WireGuard::begin(const IPAddress& localIP, const char* privateKey, const char* remotePeerAddress, const char* remotePeerPublicKey, uint16_t remotePeerPort) { - // Maintain compatiblity with old begin - auto subnet = IPAddress(255,255,255,255); - auto gateway = IPAddress(0,0,0,0); +esp_netif_t *WireGuard::netif() +{ + return wg_esp_netif; +} + +bool WireGuard::begin(const IPAddress &localIP, const char *privateKey, const char *remotePeerAddress, const char *remotePeerPublicKey, uint16_t remotePeerPort) +{ + // Maintain compatiblity with old begin + auto subnet = IPAddress(255, 255, 255, 255); + auto gateway = IPAddress(0, 0, 0, 0); return WireGuard::begin(localIP, subnet, gateway, privateKey, remotePeerAddress, remotePeerPublicKey, remotePeerPort); } -void WireGuard::end() { - if( !this->_is_initialized ) return; +void WireGuard::end() +{ + if (!this->_is_initialized) + return; + LOCK_TCPIP_CORE(); // Restore the default interface. netif_set_default(previous_default_netif); previous_default_netif = nullptr; @@ -141,7 +261,10 @@ void WireGuard::end() { wireguardif_shutdown(wg_netif); // Remove the WG interface; netif_remove(wg_netif); - wg_netif = nullptr; + esp_netif_destroy(wg_esp_netif); + UNLOCK_TCPIP_CORE(); + wg_netif = nullptr; + wg_esp_netif = nullptr; this->_is_initialized = false; } \ No newline at end of file diff --git a/src/crypto/refc/x25519.c b/src/crypto/refc/x25519.c index 3b5ebe3..70d04e0 100644 --- a/src/crypto/refc/x25519.c +++ b/src/crypto/refc/x25519.c @@ -129,7 +129,7 @@ swapout(uint8_t *out, limb_t *x) { memcpy(out,x,sizeof(fe)); } -static void mul(fe out, const fe a, const fe b, unsigned nb) { +static void mul(fe out, const fe a, const limb_t *b, unsigned nb) { /* GCC at least produces pretty decent asm for this, so don't need to have dedicated asm. */ limb_t accum[2*NLIMBS] = {0}; unsigned i,j; diff --git a/src/wireguard.h b/src/wireguard.h index 961792a..53a0db8 100644 --- a/src/wireguard.h +++ b/src/wireguard.h @@ -256,6 +256,8 @@ struct wireguard_peer *peer_lookup_by_handshake(struct wireguard_device *device, void wireguard_start_session(struct wireguard_peer *peer, bool initiator); +void handshake_destroy(struct wireguard_handshake *handshake); + void keypair_update(struct wireguard_peer *peer, struct wireguard_keypair *received_keypair); void keypair_destroy(struct wireguard_keypair *keypair); diff --git a/src/wireguardif.c b/src/wireguardif.c index d64ad85..6fc0f71 100644 --- a/src/wireguardif.c +++ b/src/wireguardif.c @@ -44,11 +44,12 @@ #include "lwip/mem.h" #include "lwip/sys.h" #include "lwip/timeouts.h" +#include "lwip/tcpip.h" #include "wireguard.h" #include "crypto.h" #include "esp_log.h" -#include "tcpip_adapter.h" +#include "esp_netif.h" #include "esp32-hal-log.h" @@ -88,11 +89,14 @@ static err_t wireguardif_peer_output(struct netif *netif, struct pbuf *q, struct struct wireguard_device *device = (struct wireguard_device *)netif->state; // Send to last know port, not the connect port //TODO: Support DSCP and ECN - lwip requires this set on PCB globally, not per packet - return udp_sendto_if(device->udp_pcb, q, &peer->ip, peer->port, device->underlying_netif); + err_t err = udp_sendto_if(device->udp_pcb, q, &peer->ip, peer->port, device->underlying_netif); + + return err; } static err_t wireguardif_device_output(struct wireguard_device *device, struct pbuf *q, const ip_addr_t *ipaddr, u16_t port) { - return udp_sendto_if(device->udp_pcb, q, ipaddr, port, device->underlying_netif); + err_t err = udp_sendto_if(device->udp_pcb, q, ipaddr, port, device->underlying_netif); + return err; } static err_t wireguardif_output_to_peer(struct netif *netif, struct pbuf *q, const ip_addr_t *ipaddr, struct wireguard_peer *peer) { @@ -556,7 +560,7 @@ void wireguardif_network_rx(void *arg, struct udp_pcb *pcb, struct pbuf *p, cons struct message_transport_data *msg_data; uint8_t type = wireguard_get_message_type(data, len); - ESP_LOGV(TAG, "network_rx: %08x:%d", addr->u_addr.ip4.addr, port); + log_d(TAG "network_rx: %08x:%d", addr->u_addr.ip4.addr, port); switch (type) { case MESSAGE_HANDSHAKE_INITIATION: @@ -606,7 +610,7 @@ void wireguardif_network_rx(void *arg, struct udp_pcb *pcb, struct pbuf *p, cons break; case MESSAGE_TRANSPORT_DATA: - ESP_LOGV(TAG, "TRANSPORT_DATA: %08x:%d", addr->u_addr.ip4.addr, port); + log_d(TAG "TRANSPORT_DATA: %08x:%d", addr->u_addr.ip4.addr, port); msg_data = (struct message_transport_data *)data; peer = peer_lookup_by_receiver(device, msg_data->receiver); @@ -920,8 +924,27 @@ err_t wireguardif_init(struct netif *netif) { uint8_t private_key[WIREGUARD_PRIVATE_KEY_LEN]; size_t private_key_len = sizeof(private_key); - struct netif* underlying_netif; - tcpip_adapter_get_netif(TCPIP_ADAPTER_IF_STA, &underlying_netif); + struct netif *underlying_netif = NULL; + char lwip_netif_name[8] = {0}; + esp_netif_t *netif_handle = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); + if (netif_handle == NULL) { + log_e(TAG "No default STA interface"); + result = ERR_IF; + goto fail; + } + esp_err_t err = esp_netif_get_netif_impl_name(netif_handle, lwip_netif_name); + if (err != ESP_OK) { + log_e(TAG "esp_netif_get_netif_impl_name failed: %s", esp_err_to_name(err)); + result = ERR_IF; + goto fail; + } + underlying_netif = netif_find(lwip_netif_name); + if (underlying_netif == NULL) { + log_e(TAG "netif_find: cannot find WIFI_STA_DEF"); + result = ERR_IF; + goto fail; + } + log_i(TAG "underlying_netif = %p", underlying_netif); LWIP_ASSERT("netif != NULL", (netif != NULL)); @@ -941,11 +964,12 @@ err_t wireguardif_init(struct netif *netif) { if (wireguard_base64_decode(init_data->private_key, private_key, &private_key_len) && (private_key_len == WIREGUARD_PRIVATE_KEY_LEN)) { - + udp = udp_new(); if (udp) { result = udp_bind(udp, IP_ADDR_ANY, init_data->listen_port); // Note this listens on all interfaces! Really just want the passed netif + if (result == ERR_OK) { device = (struct wireguard_device *)mem_calloc(1, sizeof(struct wireguard_device)); if (device) { @@ -1010,6 +1034,7 @@ err_t wireguardif_init(struct netif *netif) { log_e(TAG "netif or state is NULL: netif=%p, netif.state:%p", netif, netif ? netif->state : NULL); result = ERR_ARG; } +fail: return result; }