diff --git a/README.md b/README.md index 142f21d..eb10d37 100644 --- a/README.md +++ b/README.md @@ -5,119 +5,46 @@ for [ESPHome](https://esphome.io/), based on [Wireguard Implementation for ESP-IDF](https://github.com/trombik/esp_wireguard) (by [@trombik](https://github.com/trombik)). -The branch `trombik/main` will be kept in sync with -[@trombik](https://github.com/trombik)'s `main` branch. - -The branch `main` is where I push my most "stable" code. - [![PlatformIO Registry](https://badges.registry.platformio.org/packages/droscy/library/esp_wireguard.svg)](https://registry.platformio.org/libraries/droscy/esp_wireguard) -## Status - -The code is alpha. - -A single tunnel to a WireGuard peer has been working. - +## Status and platforms -## Supported boards and frameworks - -The code works only on `esp32` boards with both frameworks: -`esp-idf` and `Arduino`. - -The original [@trombik](https://github.com/trombik)'s code was designed -for `esp-idf` only but it seems to work on `Arduino` too. +The code is alpha and works only on `esp32` boards with both +frameworks: `esp-idf` and `Arduino`. ## Usage -Add the following configuration to your ESPHome `yaml` file: +Add the following snippet to your ESPHome `yaml` file: ```yaml -# Define wireguard external source external_components: - - source: - type: git - url: https://github.com/droscy/esphome - ref: wireguard/main - components: - - wireguard - - wireguard_status - - wireguard_handshake - -# Setup a time source. -# Do not use 'homeassistant' platform if Home Assistant is on the remote -# peer because the time synchronization is a prerequisite to establish -# the vpn link. -time: - - platform: sntp - -# Setup WireGuard -wireguard: - address: x.y.z.w - private_key: private_key= - peer_endpoint: wg.server.example - peer_public_key: public_key= - - # optional netmask (this is the default if omitted) - netmask: 255.255.255.255 - - # optional custom port (this is the wireguard default) - peer_port: 51820 - - # optional pre-shared key - peer_preshared_key: shared_key= - - # optional keepalive in seconds (disabled by default) - peer_persistent_keepalive: 25s - - # 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 + - source: github://pr#4256 + components: [wireguard] + + # or use my repo with code possibly not yet merged in official PR + #- source: + # type: git + # url: https://github.com/droscy/esphome + # ref: wireguard/main + # components: [wireguard] ``` -### Sensors - -The `wireguard_status` binary sensor can be used to check if remote peer is online: - -```yaml -binary_sensor: - - platform: wireguard_status - name: 'WireGuard Status' - - # optional (default to 10s) - update_interval: 10s -``` - -The `wireguard_handshake` sensor can be used to track the timestamp of the -latest completed handshake: - -```yaml -sensor: - - platform: wireguard_handshake - name: 'WireGuard Latest Handshake' - - # optional (default to 60s) - update_interval: 60s -``` +and then read the [preview](https://deploy-preview-2948--esphome.netlify.app/components/wireguard.html) +of the documentation with the description on how to use this component +along with its sensors. ## References For additional information see: -* the original feature-request [esphome/esphome#1444](https://github.com/esphome/feature-requests/issues/1444) - (starting from [this comment](https://github.com/esphome/feature-requests/issues/1444#issuecomment-1556090095)) +* the official PR [esphome/esphome#4256](https://github.com/esphome/esphome/pull/4256) -* the original component proposed by [@lhoracek](https://github.com/lhoracek) in his PR [esphome/esphome#4256](https://github.com/esphome/esphome/pull/4256) +* the documentation PR [esphome/esphome-docs#2948](https://github.com/esphome/esphome-docs/pull/2948) -* the proposed documentation [esphome/esphome-docs#2948](https://github.com/esphome/esphome-docs/pull/2948), here - you can find the link to preview the latest version +* the original feature-request [esphome/feature-requests#1444](https://github.com/esphome/feature-requests/issues/1444) ## License diff --git a/library.json b/library.json index cd1a29e..9a82061 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "esp_wireguard", - "version": "0.3.0", + "version": "0.3.2", "description": "WireGuard implementation for ESPHome", "keywords":[ "communication", diff --git a/src/esp_wireguard.c b/src/esp_wireguard.c index a8645d9..c789f56 100644 --- a/src/esp_wireguard.c +++ b/src/esp_wireguard.c @@ -144,7 +144,7 @@ static esp_err_t esp_wireguard_peer_init(const wireguard_config_t *config, struc if (inet_ntop(res->ai_family, &(peer->endpoint_ip), addr_str, WG_ADDRSTRLEN) == NULL) { ESP_LOGW(TAG, "inet_ntop: %i", errno); } else { - ESP_LOGI(TAG, "Peer: %s (%s:%i)", + ESP_LOGI(TAG, "peer endpoint: %s (%s), port: %i", config->endpoint, addr_str, config->port); @@ -270,7 +270,7 @@ esp_err_t esp_wireguard_connect(wireguard_ctx_t *ctx) goto fail; } - ESP_LOGI(TAG, "Connecting to %s:%i", ctx->config->endpoint, ctx->config->port); + ESP_LOGI(TAG, "connecting to %s:%i", ctx->config->endpoint, ctx->config->port); lwip_err = wireguardif_connect(ctx->netif, wireguard_peer_index); if (lwip_err != ERR_OK) { ESP_LOGE(TAG, "wireguardif_connect: %i", lwip_err); diff --git a/src/wireguard.c b/src/wireguard.c index 9d5664a..047b239 100644 --- a/src/wireguard.c +++ b/src/wireguard.c @@ -476,7 +476,7 @@ static void add_new_keypair(struct wireguard_peer *peer, struct wireguard_keypai peer->next_keypair = new_keypair; keypair_destroy(&peer->prev_keypair); } - peer->latest_handshake_millis = peer->curr_keypair.keypair_millis; + peer->latest_handshake_millis = new_keypair.keypair_millis; } void wireguard_start_session(struct wireguard_peer *peer, bool initiator) { diff --git a/src/wireguardif.c b/src/wireguardif.c index 30b04f6..d690ac2 100644 --- a/src/wireguardif.c +++ b/src/wireguardif.c @@ -659,9 +659,11 @@ static err_t wireguardif_lookup_peer(struct netif *netif, u8_t peer_index, struc if (peer) { result = ERR_OK; } else { + ESP_LOGD(TAG, "peer_lookup_by_peer_index: peer not found"); result = ERR_ARG; } } else { + ESP_LOGD(TAG, "wireguardif_lookup_peer: invalid device"); result = ERR_ARG; } *out = peer; @@ -708,6 +710,7 @@ err_t wireguardif_peer_is_up(struct netif *netif, u8_t peer_index, ip_addr_t *cu if ((peer->curr_keypair.valid) || (peer->prev_keypair.valid)) { result = ERR_OK; } else { + ESP_LOGD(TAG, "wireguardif_peer_is_up: invalid keypairs"); result = ERR_CONN; } if (current_ip) { @@ -726,7 +729,17 @@ time_t wireguardif_latest_handshake(struct netif *netif, u8_t peer_index) { err_t err = wireguardif_lookup_peer(netif, peer_index, &peer); if (err == ERR_OK) { if (peer->valid && peer->latest_handshake_millis > 0) { - result = peer->latest_handshake_millis / 1000 + (time(NULL) - (wireguard_sys_now() / 1000)); + /* + * The time() function returns the current timestamp (seconds since epoch), + * the wireguard_sys_now() function returns milliseconds since device boot up, + * so their difference is the timestamp (since epoch) of device boot time, + * so the latest handshake (saved executing wireguard_sys_now) plus timestamp + * of device boot time is the timestamp (since epoch)of the latest + * completed handshake. With ~1 second precision. + */ + result = (peer->latest_handshake_millis / 1000) + (time(NULL) - (wireguard_sys_now() / 1000)); + } else { + ESP_LOGD(TAG, "wireguardif_latest_handshake: valid=%d, lhs=%d", (int) peer->valid, peer->latest_handshake_millis); } } return result; @@ -815,7 +828,7 @@ err_t wireguardif_add_peer(struct netif *netif, struct wireguardif_peer *p, u8_t } uint32_t t2 = wireguard_sys_now(); - ESP_LOGD(TAG, "Adding peer took %" PRIu32 "ms", (t2-t1)); + ESP_LOGV(TAG, "peer adding took %" PRIu32 "ms", (t2-t1)); if (peer_index) { if (peer) { @@ -922,7 +935,7 @@ static void wireguardif_tmr(void *arg) { err_t wireguardif_init(struct netif *netif) { err_t result; - esp_err_t err; + esp_err_t err = ESP_FAIL; struct wireguardif_init_data *init_data; struct wireguard_device *device; struct udp_pcb *udp; @@ -932,20 +945,32 @@ err_t wireguardif_init(struct netif *netif) { struct netif* underlying_netif = NULL; char lwip_netif_name[8] = {0,}; - err = esp_netif_get_netif_impl_name(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), lwip_netif_name); + // list of interfaces to try to bind wireguard to + const char* ifkeys[2] = {"WIFI_STA_DEF", "ETH_DEF"}; + + // ifkey will contain the selected interface key + const char* ifkey = NULL; + + ESP_LOGD(TAG, "looking for available network interface"); + for (int i = 0; i < sizeof(ifkeys) / sizeof(char *) && err != ESP_OK; i++) { + ifkey = ifkeys[i]; + err = esp_netif_get_netif_impl_name(esp_netif_get_handle_from_ifkey(ifkey), lwip_netif_name); + ESP_LOGV(TAG, "esp_netif_get_netif_impl_name(%s): %s", ifkey, esp_err_to_name(err)); + } if (err != ESP_OK) { - ESP_LOGE(TAG, "esp_netif_get_netif_impl_name: %s", esp_err_to_name(err)); + ESP_LOGE(TAG, "could not find an available network interface"); result = ERR_IF; goto fail; } + underlying_netif = netif_find(lwip_netif_name); if (underlying_netif == NULL) { - ESP_LOGE(TAG, "netif_find: cannot find WIFI_STA_DEF"); + ESP_LOGE(TAG, "netif_find: cannot find %s (%s)", ifkey, lwip_netif_name); result = ERR_IF; goto fail; } - ESP_LOGD(TAG, "underlying_netif = %p", underlying_netif); + ESP_LOGV(TAG, "underlying_netif = %p", underlying_netif); LWIP_ASSERT("netif != NULL", (netif != NULL)); LWIP_ASSERT("state != NULL", (netif->state != NULL)); @@ -980,7 +1005,7 @@ err_t wireguardif_init(struct netif *netif) { uint32_t t1 = wireguard_sys_now(); if (wireguard_device_init(device, private_key)) { uint32_t t2 = wireguard_sys_now(); - ESP_LOGD(TAG, "Device init took %" PRIi32 "ms", (t2-t1)); + ESP_LOGV(TAG, "device init took %" PRIi32 "ms", (t2-t1)); #if LWIP_CHECKSUM_CTRL_PER_NETIF NETIF_SET_CHECKSUM_CTRL(netif, NETIF_CHECKSUM_ENABLE_ALL);