diff --git a/README.md b/README.md index cb3c0e4..1db51b9 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ for `esp-idf` only but it seems to work on `Arduino` too. ## Usage -Add the following configuration to your `yaml` file: +Add the following configuration to your ESPHome `yaml` file: ```yaml # Define wireguard external source @@ -55,9 +55,9 @@ time: # Setup WireGuard wireguard: address: x.y.z.w - private_key: !secret wg_privkey + private_key: private_key= peer_endpoint: wg.server.example - peer_public_key: !secret wg_peer_pubkey + peer_public_key: public_key= # optional netmask (this is the default if omitted) netmask: 255.255.255.255 @@ -66,10 +66,19 @@ wireguard: peer_port: 51820 # optional pre-shared key - peer_preshared_key: !secret wg_peer_shrdkey + peer_preshared_key: shared_key= # optional keepalive in seconds (disabled by default) peer_persistent_keepalive: 25 + + # optional list of allowed ip/mask (the default is to allow any host if omitted) + peer_allowed_ips: + - x.y.z.0/24 + - l.m.n.o/32 # the /32 can be omitted for single host + - [...] + + # reboot the board if remote peer in unreachable (default to 15min, set to 0s to disable) + reboot_timeout: 15min ``` ### Sensors diff --git a/include/esp_wireguard.h b/include/esp_wireguard.h index baeee96..e27123a 100644 --- a/include/esp_wireguard.h +++ b/include/esp_wireguard.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2022 Tomoyuki Sakurai + * Copyright (c) 2023 Simone Rossetto * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -145,6 +146,19 @@ esp_err_t esp_wireguardif_peer_is_up(const wireguard_ctx_t *ctx); */ esp_err_t esp_wireguard_latest_handshake(const wireguard_ctx_t *ctx, time_t *result); +/** + * @brief Add new allowed IP/mask to the list of allowed ip/mask + * @param ctx Context of WireGuard + * @param allowed_ip The new IP to be allowed through tunnel + * @param allowed_ip_mask The mask of the new IP + * @return + * - ESP_OK on success + * - ESP_FAIL if the adding failed + * - ESP_ERR_INVALID_ARG if ctx, allowed_ip or allowed_ip_mask are invalid or empty + * - ESP_ERR_INVALID_STATE if data inside ctx is not valid + */ +esp_err_t esp_wireguard_add_allowed_ip(const wireguard_ctx_t *ctx, const char *allowed_ip, const char *allowed_ip_mask); + /** * @brief Disconnect from the peer * diff --git a/library.json b/library.json index 215907c..8a50684 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "esp_wireguard", - "version": "0.1.0", + "version": "0.2.0", "description": "WireGuard implementation for ESPHome", "keywords":[ "communication", @@ -57,11 +57,6 @@ }, "build":{ "includeDir": "include", - "srcDir": "src", - "flags": [ - "-DCONFIG_WIREGUARD_MAX_PEERS=1", - "-DCONFIG_WIREGUARD_MAX_SRC_IPS=1", - "-DCONFIG_MAX_INITIATIONS_PER_SECOND=2" - ] + "srcDir": "src" } } diff --git a/src/esp_wireguard.c b/src/esp_wireguard.c index f92f74a..2ac347f 100644 --- a/src/esp_wireguard.c +++ b/src/esp_wireguard.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2022 Tomoyuki Sakurai + * Copyright (c) 2023 Simone Rossetto * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -49,6 +50,7 @@ #define TAG "esp_wireguard" #define WG_KEY_LEN (32) #define WG_B64_KEY_LEN (4 * ((WG_KEY_LEN + 2) / 3)) + #if defined(CONFIG_LWIP_IPV6) #define WG_ADDRSTRLEN INET6_ADDRSTRLEN #else @@ -98,12 +100,19 @@ static esp_err_t esp_wireguard_peer_init(const wireguard_config_t *config, struc } peer->keep_alive = config->persistent_keepalive; - /* Allow all IPs through tunnel */ + /* Allow device address/netmask 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; + if(ipaddr_aton(config->allowed_ip, &(peer->allowed_ip)) != 1) { + ESP_LOGE(TAG, "peer_init: invalid allowed_ip: `%s`", config->allowed_ip); + err = ESP_ERR_INVALID_ARG; + goto fail; + } + + if(ipaddr_aton(config->allowed_ip_mask, &(peer->allowed_mask)) != 1) { + ESP_LOGE(TAG, "peer_init: invalid allowed_ip_mask: `%s`", config->allowed_ip_mask); + err = ESP_ERR_INVALID_ARG; + goto fail; + } } /* resolve peer name or IP address */ @@ -166,19 +175,19 @@ static esp_err_t esp_wireguard_netif_create(const wireguard_config_t *config) wg.listen_port = config->listen_port; wg.bind_netif = NULL; - ESP_LOGI(TAG, "allowed_ip: %s", config->allowed_ip); - if (ipaddr_aton(config->allowed_ip, &ip_addr) != 1) { - ESP_LOGE(TAG, "ipaddr_aton: invalid allowed_ip: `%s`", config->allowed_ip); + ESP_LOGE(TAG, "netif_create: invalid allowed_ip: `%s`", config->allowed_ip); err = ESP_ERR_INVALID_ARG; goto fail; } if (ipaddr_aton(config->allowed_ip_mask, &netmask) != 1) { - ESP_LOGE(TAG, "ipaddr_aton: invalid allowed_ip_mask: `%s`", config->allowed_ip_mask); + ESP_LOGE(TAG, "netif_create: invalid allowed_ip_mask: `%s`", config->allowed_ip_mask); err = ESP_ERR_INVALID_ARG; goto fail; } + ESP_LOGI(TAG, "default allowed_ip: %s/%s", config->allowed_ip, config->allowed_ip_mask); + /* Register the new WireGuard network interface with lwIP */ wg_netif = netif_add( &wg_netif_struct, @@ -360,6 +369,44 @@ esp_err_t esp_wireguard_latest_handshake(const wireguard_ctx_t *ctx, time_t *res *result = wireguardif_latest_handshake(ctx->netif, wireguard_peer_index); err = (*result > 0) ? ESP_OK : ESP_FAIL; +fail: + return err; +} + +esp_err_t esp_wireguard_add_allowed_ip(const wireguard_ctx_t *ctx, const char *allowed_ip, const char *allowed_ip_mask) +{ + esp_err_t err; + err_t lwip_err; + + ip_addr_t ip_addr; + ip_addr_t netmask; + + if (!ctx || !allowed_ip || !allowed_ip_mask) { + err = ESP_ERR_INVALID_ARG; + goto fail; + } + + if (!ctx->netif) { + err = ESP_ERR_INVALID_STATE; + goto fail; + } + + if (ipaddr_aton(allowed_ip, &ip_addr) != 1) { + ESP_LOGE(TAG, "add_allowed_ip: invalid allowed_ip: `%s`", allowed_ip); + err = ESP_ERR_INVALID_ARG; + goto fail; + } + + if (ipaddr_aton(allowed_ip_mask, &netmask) != 1) { + ESP_LOGE(TAG, "add_allowed_ip: invalid allowed_ip_mask: `%s`", allowed_ip_mask); + err = ESP_ERR_INVALID_ARG; + goto fail; + } + + ESP_LOGI(TAG, "add allowed_ip: %s/%s", allowed_ip, allowed_ip_mask); + lwip_err = wireguardif_add_allowed_ip(ctx->netif, wireguard_peer_index, ip_addr, netmask); + err = (lwip_err == ERR_OK ? ESP_OK : ESP_FAIL); + fail: return err; } diff --git a/src/wireguard-platform.h b/src/wireguard-platform.h index 5c0a13b..5a9341d 100644 --- a/src/wireguard-platform.h +++ b/src/wireguard-platform.h @@ -44,11 +44,24 @@ extern "C" { #include "esp_err.h" // Peers are allocated statically inside the device structure to avoid malloc -#define WIREGUARD_MAX_PEERS (CONFIG_WIREGUARD_MAX_PEERS) -#define WIREGUARD_MAX_SRC_IPS (CONFIG_WIREGUARD_MAX_SRC_IPS) +#ifdef CONFIG_WIREGUARD_MAX_PEERS + #define WIREGUARD_MAX_PEERS (CONFIG_WIREGUARD_MAX_PEERS) +#else + #define WIREGUARD_MAX_PEERS (1) +#endif + +#ifdef CONFIG_WIREGUARD_MAX_SRC_IPS + #define WIREGUARD_MAX_SRC_IPS (CONFIG_WIREGUARD_MAX_SRC_IPS) +#else + #define WIREGUARD_MAX_SRC_IPS (1) +#endif // Per device limit on accepting (valid) initiation requests - per peer -#define MAX_INITIATIONS_PER_SECOND (CONFIG_MAX_INITIATIONS_PER_SECOND) +#ifdef CONFIG_WIREGUARD_MAX_INIT_PER_SECOND + #define MAX_INITIATIONS_PER_SECOND (CONFIG_WIREGUARD_MAX_INIT_PER_SECOND) +#else + #define MAX_INITIATIONS_PER_SECOND (2) +#endif // Initialize crypto backend (return ESP_OK on success) esp_err_t wireguard_platform_init(); diff --git a/src/wireguardif.c b/src/wireguardif.c index 2ddc678..30b04f6 100644 --- a/src/wireguardif.c +++ b/src/wireguardif.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2021 Daniel Hope (www.floorsense.nz) * Copyright (c) 2021 Kenta Ida (fuga@fugafuga.org) + * Copyright (c) 2023 Simone Rossetto * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -731,6 +732,19 @@ time_t wireguardif_latest_handshake(struct netif *netif, u8_t peer_index) { return result; } +err_t wireguardif_add_allowed_ip(struct netif *netif, u8_t peer_index, ip_addr_t ip, ip_addr_t mask) { + struct wireguard_peer *peer; + err_t result = wireguardif_lookup_peer(netif, peer_index, &peer); + if (result == ERR_OK) { + if(peer_add_ip(peer, ip, mask)) { + result = ERR_OK; + } else { + result = ERR_MEM; + } + } + return result; +} + err_t wireguardif_remove_peer(struct netif *netif, u8_t peer_index) { struct wireguard_peer *peer; err_t result = wireguardif_lookup_peer(netif, peer_index, &peer); diff --git a/src/wireguardif.h b/src/wireguardif.h index 1f8284e..b011863 100644 --- a/src/wireguardif.h +++ b/src/wireguardif.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2021 Daniel Hope (www.floorsense.nz) + * Copyright (c) 2023 Simone Rossetto * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, @@ -139,6 +140,9 @@ err_t wireguardif_peer_is_up(struct netif *netif, u8_t peer_index, ip_addr_t *cu // Return 0 if no handshake already done or in case of errors time_t wireguardif_latest_handshake(struct netif *netif, u8_t peer_index); +// Add ip/mask to the list of allowed ips of the given peer +err_t wireguardif_add_allowed_ip(struct netif *netif, u8_t peer_index, ip_addr_t ip, ip_addr_t mask); + #ifdef __cplusplus } #endif