Skip to content

Commit

Permalink
Merge branch 'dev' (version 0.3.2)
Browse files Browse the repository at this point in the history
* fix wrong latest handshake retrieval
* add support for eth interface if wifi not available (thanks to J. Peletier)
  • Loading branch information
droscy committed Jun 29, 2023
2 parents f2c116a + 09521ff commit 4e17811
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 104 deletions.
111 changes: 19 additions & 92 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion library.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "esp_wireguard",
"version": "0.3.0",
"version": "0.3.2",
"description": "WireGuard implementation for ESPHome",
"keywords":[
"communication",
Expand Down
4 changes: 2 additions & 2 deletions src/esp_wireguard.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/wireguard.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
41 changes: 33 additions & 8 deletions src/wireguardif.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand All @@ -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));
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 4e17811

Please sign in to comment.