Git Product home page Git Product logo

esp_wireguard's Introduction

esp_wireguard, WireGuard Implementation for ESP-IDF

This is an implementation of the WireGuard® for ESP-IDF, based on WireGuard Implementation for lwIP.

Build examples

Status

The code is alpha.

A single tunnel to a WireGuard peer has been working.

Supported ESP-IDF versions and targets

The following ESP-IDF versions are supported:

  • esp-idf master
  • esp-idf v4.2.x
  • esp-idf v4.3.x
  • esp-idf v4.4.x
  • ESP8266 RTOS SDK v3.4

The following targets are supported:

  • esp32
  • esp32s2
  • esp32c3
  • esp8266

Usage

In menuconfig under WireGuard, choose a TCP/IP adapter. The default is ESP-NETIF. SDKs older than esp-idf v4.1, including ESP8266 RTOS SDK v3.4 requires TCP/IP Adapter.

Both peers must have synced time. The library does not sync time.

A working network interface is required.

Create WireGuard configuration, wireguard_config_t. Use ESP_WIREGUARD_CONFIG_DEFAULT to initialize wireguard_config_t variable. Create wireguard_ctx_t. Pass the variables to esp_wireguard_init(). Then, call esp_wireguard_connect(). Call esp_wireguard_disconnect() to disconnect from the peer (and destroy the WireGuard interface).

#include <esp_wireguard.h>

esp_err_t err = ESP_FAIL;

wireguard_config_t wg_config = ESP_WIREGUARD_CONFIG_DEFAULT();

wg_config.private_key = CONFIG_WG_PRIVATE_KEY;
wg_config.listen_port = CONFIG_WG_LOCAL_PORT;
wg_config.public_key = CONFIG_WG_PEER_PUBLIC_KEY;
wg_config.allowed_ip = CONFIG_WG_LOCAL_IP_ADDRESS;
wg_config.allowed_ip_mask = CONFIG_WG_LOCAL_IP_NETMASK;
wg_config.endpoint = CONFIG_WG_PEER_ADDRESS;
wg_config.port = CONFIG_WG_PEER_PORT;

/* If the device is behind NAT or stateful firewall, set persistent_keepalive.
   persistent_keepalive is disabled by default */
// wg_config.persistent_keepalive = 10;

wireguard_ctx_t ctx = {0};
err = esp_wireguard_init(&wg_config, &ctx);

/* start establishing the link. after this call, esp_wireguard start
   establishing connection. */
err = esp_wireguard_connect(&ctx);

/* after some time, see if the link is up. note that it takes some time to
   establish the link */
err = esp_wireguardif_peer_is_up(&ctx);
if (err == ESP_OK) {
    /* the link is up */
else {
    /* the link is not up */
}

/* do something */

err = esp_wireguard_disconnect(&ctx);

See examples at examples.

IPv6 support

Enable CONFIG_LWIP_IPV6 under lwip component in menuconfig.

IPv6 support is alpha and probably broken. See also Known issues.

Driver configuration

The driver configuration is under [Component config] -> [WireGuard].

Under WIREGUARD_x25519_IMPLEMENTATION, you may choose an implementation of scalar multiplication. The default is WIREGUARD_x25519_IMPLEMENTATION_DEFAULT, which is derived from WireGuard Implementation for lwIP. WIREGUARD_x25519_IMPLEMENTATION_NACL uses crypto_scalarmult() from NaCL. Note that, with WIREGUARD_x25519_IMPLEMENTATION_NACL, some stack sizes must be increased. In my test, 5KB for both CONFIG_LWIP_TCPIP_TASK_STACK_SIZE, and CONFIG_MAIN_TASK_STACK_SIZE is known to work on ESP32-D0WD-V3.

Known issues

The implementation uses LwIP as TCP/IP protocol stack.

IPv6 support is not tested. Dual stack (IPv4 and IPv6) is not supported (see Issue #5). The first address of endpoint is used to choose IPv4 or IPv6 as a transport. The chosen transport must be available and usable.

The library assumes the interface is WiFi interface. Ethernet is not supported.

Older esp-idf versions with TCP/IP Adapter, such as v4.1.x, should work, but there are others issues, not directly related to the library.

License

BSD 3-Clause "New" or "Revised" License (SPDX ID: BSD-3-Clause). See LICENSE for details.

[src/nacl/crypto_scalarmult/curve25519/ref/smult.c] is Public domain.

Authors

esp_wireguard's People

Contributors

ciniml avatar droscy avatar jefftharris avatar pecius avatar smartalock avatar trombik avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

esp_wireguard's Issues

Crash on esp32s3

Hi @trombik

many thanks for this repo.
I wanted to mention that I had a crash which I was unable to reproduce in this code

static struct wireguard_peer *peer_lookup_by_allowed_ip(struct wireguard_device *device, const ip_addr_t *ipaddr) {
...
		tmp = &device->peers[x];
		if (tmp->valid) {

As far as I can see tmp was NULL, and hence there was no dereference to tmp->valid
I have not been able to reproduce, but maybe this will give you an indication
I was going to make a trivial fix to change to
if (tmp && tmp->valid) {
I will leave to you to decide

Thx
Lee

crash wtih esp-idf 5.x, or master

I (5659) demo: Initializing WireGuard.
I (5659) demo: Connecting to the peer.
I (5659) esp_wireguard: allowed_ip: 192.168.4.58
Guru Meditation Error: Core  0 panic'ed (LoadProhibited). Exception was unhandled.

Core  0 register dump:
PC      : 0x400f8bd5  PS      : 0x00060630  A0      : 0x800f8ced  A1      : 0x3ffbaaf0  
0x400f8bd5: esp_netif_internal_dhcpc_cb at /usr/home/trombik/github/trombik/esp-idf/components/esp_netif/lwip/esp_netif_lwip.c:1111

A2      : 0x3ffb467c  A3      : 0x3ffbac88  A4      : 0x00000000  A5      : 0x3ffbacf0  
A6      : 0x0000000c  A7      : 0xff000000  A8      : 0x3a04a8c0  A9      : 0x00000000  
A10     : 0x00000004  A11     : 0x3f40d29c  A12     : 0x3f40d4a0  A13     : 0x00001625  
A14     : 0x3f40d29c  A15     : 0x3f40ded8  SAR     : 0x00000004  EXCCAUSE: 0x0000001c  
EXCVADDR: 0x00000000  LBEG    : 0x400014fd  LEND    : 0x4000150d  LCOUNT  : 0xfffffffc  


Backtrace: 0x400f8bd2:0x3ffbaaf0 0x400f8cea:0x3ffbab40 0x400e5ca3:0x3ffbab60 0x400e5d4e:0x3ffbab80 0x400e5e92:0x3ffbac00 0x400d7b34:0x3ffbac30 0x400d7dd4:0x3ffbacc0 0x400d76c6:0x3ffbacf0 0x400d78d8:0x3ffbad10 0x40154b3b:0x3ffbadb0 0x4008bca5:0x3ffbade0
0x400f8bd2: esp_netif_internal_dhcpc_cb at /usr/home/trombik/github/trombik/esp-idf/components/esp_netif/lwip/esp_netif_lwip.c:1108

0x400f8cea: netif_callback_fn at /usr/home/trombik/github/trombik/esp-idf/components/esp_netif/lwip/esp_netif_lwip.c:123

0x400e5ca3: netif_invoke_ext_callback at /usr/home/trombik/github/trombik/esp-idf/components/lwip/lwip/src/core/netif.c:1819

0x400e5d4e: netif_set_addr at /usr/home/trombik/github/trombik/esp-idf/components/lwip/lwip/src/core/netif.c:733

0x400e5e92: netif_add at /usr/home/trombik/github/trombik/esp-idf/components/lwip/lwip/src/core/netif.c:376

0x400d7b34: esp_wireguard_netif_create at /usr/home/trombik/github/trombik/esp_wireguard/examples/demo/components/esp_wireguard/src/esp_wireguard.c:180

0x400d7dd4: esp_wireguard_connect at /usr/home/trombik/github/trombik/esp_wireguard/examples/demo/components/esp_wireguard/src/esp_wireguard.c:235

0x400d76c6: wireguard_setup at /usr/home/trombik/github/trombik/esp_wireguard/examples/demo/main/main.c:79 (discriminator 13)

0x400d78d8: app_main at /usr/home/trombik/github/trombik/esp_wireguard/examples/demo/main/main.c:381

0x40154b3b: main_task at /usr/home/trombik/github/trombik/esp-idf/components/freertos/FreeRTOS-Kernel/portable/port_common.c:131 (discriminator 2)

0x4008bca5: vPortTaskWrapper at /usr/home/trombik/github/trombik/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:151





ELF file SHA256: f2a1169a2b5c9528

Rebooting...

Invalid handshake initiation after connectivity issue

Hello trombik, I'm facing this odd behavior: if the esp device looses its main network for whatever reason (reboot, link error, wifi change, etc), it cannot reconnect to the wireguard server. In the dmesg I see "Invalid handshake initiation from ww.ww.ww.ww:kkkkk"
(either if the source IP is the same or not).

In order to have the device connected again I need to remove the peer from server with wg set wg0 peer AAAABBBB....FFFF= remove and re-add it.

It looks like a server-side bug but I don't have such behavior with other peers (all Linux peers).

When the esp device looses the main connection I see the following in dmesg of the server:

wireguard: wg0: Retrying handshake with peer 97 (xx.xx.xx.xx:yyyyy) because we stopped hearing back after 15 seconds
wireguard: wg0: Sending handshake initiation to peer 97 (xx.xx.xx.xx:yyyyy)
wireguard: wg0: Handshake for peer 97 (xx.xx.xx.xx:yyyyy) did not complete after 5 seconds, retrying (try 2)
wireguard: wg0: Sending handshake initiation to peer 97 (xx.xx.xx.xx:yyyyy)
wireguard: wg0: Handshake for peer 97 (xx.xx.xx.xx:yyyyy) did not complete after 5 seconds, retrying (try 3)
wireguard: wg0: Sending handshake initiation to peer 97 (xx.xx.xx.xx:yyyyy)
wireguard: wg0: Handshake for peer 97 (xx.xx.xx.xx:yyyyy) did not complete after 5 seconds, retrying (try 4)
[...]

When the esp device is online again and starts the handshake I see:

wireguard: wg0: Retrying handshake with peer 97 (xx.xx.xx.xx:yyyyy) because we stopped hearing back after 15 seconds
wireguard: wg0: Handshake for peer 97 (xx.xx.xx.xx:yyyyy) did not complete after 5 seconds, retrying (try 2)
wireguard: wg0: Sending handshake initiation to peer 97 (xx.xx.xx.xx:yyyyy)
wireguard: wg0: Handshake for peer 97 (xx.xx.xx.xx:yyyyy) did not complete after 5 seconds, retrying (try 4)
wireguard: wg0: Invalid handshake initiation from ww.ww.ww.ww:kkkkk
wireguard: wg0: Handshake for peer 97 (xx.xx.xx.xx:yyyyy) did not complete after 5 seconds, retrying (try 5)
wireguard: wg0: Sending handshake initiation to peer 97 (xx.xx.xx.xx:yyyyy)
wireguard: wg0: Retrying handshake with peer 97 (xx.xx.xx.xx:yyyyy) because we stopped hearing back after 15 seconds
wireguard: wg0: Invalid handshake initiation from ww.ww.ww.ww:kkkkk
wireguard: wg0: Handshake for peer 97 (xx.xx.xx.xx:yyyyy) did not complete after 5 seconds, retrying (try 2)
wireguard: wg0: Sending handshake initiation to peer 97 (xx.xx.xx.xx:yyyyy)
wireguard: wg0: Invalid handshake initiation from ww.ww.ww.ww:kkkkk
[...]

ad so on, being xx.xx.xx.xx and ww.ww.ww.ww the same IP or not.

If you need more information or tests feel free to ask, I'll do my best to support you.

IPV6 endpoint configured but peer is not connecting

Endpoint is configured for IPV6 but peer not getting connected
endpoint is up and normal ping cmd from esp to wireguard server or visa versa is working
but peer is not able get connected to the ipv6 of the server

Crash on ESP8266-RTOS-SDK

Steps to reproduce:

  1. Use this docker image. The command is similar to sudo docker run -it --rm -v (pwd):/project -w /project --device /dev/ttyUSB0 mbenabda/esp8266-rtos-sdk bash.
  2. Modify the example/demos to host an HTTP server (using the built-in httpd library)
  3. Wait for a client to load a page
  4. Close the HTTPD handle
  5. Try to close the wireguard context (crashes)

Log:

Guru Meditation Error: Core  0 panic'ed (LoadProhibited). Exception was unhandled.
Core 0 register dump:
PC      : 0x40263503  PS      : 0x00000030  A0      : 0x4023621b  A1      : 0x3ffeb9d0  
0x40263503: peer_lookup_by_allowed_ip at /project/examples/wol/components/esp_wireguard/src/wireguardif.c:74

0x4023621b: wireguardif_output at /project/examples/wol/components/esp_wireguard/src/wireguardif.c:205

A2      : 0x00000000  A3      : 0x3ffeb9d0  A4      : 0x00000000  A5      : 0x00000000  
A6      : 0x00000000  A7      : 0x00000000  A8      : 0x000000b0  A9      : 0x000000b0  
A10     : 0x0a00080a  A11     : 0x0000002f  A12     : 0x3ffea660  A13     : 0x3fff33ec  
A14     : 0x00009058  A15     : 0x3fff4e6c  SAR     : 0x0000001d  EXCCAUSE: 0x0000001c  

Backtrace: 0x40263503:0x3ffeb9d0 0x4023621b:0x3ffeb9d0 0x4024f120:0x3ffeb9f0 0x4024f180:0x3ffeba40 0x4024f1a8:0x3ffeba60 0x4024a61c:0x3ffeba80 0x4024b039:0x3ffebac0 0x40244809:0x3ffebb00 0x40244838:0x3ffebb40 0x40244928:0x3ffebb50 0x4024495f:0x3ffebb60 0x4024920e:0x3ffebb70 0x402495c4:0x3ffebb80 0x40235aa0:0x3ffebb90 0x4022231a:0x3ffebba0 0x40222368:0x3ffebbb0 0x402121eb:0x3ffebc00 
0x40263503: peer_lookup_by_allowed_ip at /project/examples/wol/components/esp_wireguard/src/wireguardif.c:74

0x4023621b: wireguardif_output at /project/examples/wol/components/esp_wireguard/src/wireguardif.c:205

0x4024f120: ip4_output_if_opt_src at /opt/sdk/components/lwip/lwip/src/core/ipv4/ip4.c:1089

0x4024f180: ip4_output_if_opt at /opt/sdk/components/lwip/lwip/src/core/ipv4/ip4.c:895

0x4024f1a8: ip4_output_if at /opt/sdk/components/lwip/lwip/src/core/ipv4/ip4.c:868

0x4024a61c: tcp_output_control_segment at /opt/sdk/components/lwip/lwip/src/core/tcp_out.c:1951

0x4024b039: tcp_rst at /opt/sdk/components/lwip/lwip/src/core/tcp_out.c:2011

0x40244809: tcp_abandon at /opt/sdk/components/lwip/lwip/src/core/tcp.c:621

0x40244838: tcp_abort at /opt/sdk/components/lwip/lwip/src/core/tcp.c:641

0x40244928: tcp_netif_ip_addr_changed_pcblist at /opt/sdk/components/lwip/lwip/src/core/tcp.c:2411

0x4024495f: tcp_netif_ip_addr_changed at /opt/sdk/components/lwip/lwip/src/core/tcp.c:2430

0x4024920e: netif_do_ip_addr_changed at /opt/sdk/components/lwip/lwip/src/core/netif.c:458

0x402495c4: netif_remove at /opt/sdk/components/lwip/lwip/src/core/netif.c:779

0x40235aa0: esp_wireguard_disconnect at /project/examples/wol/components/esp_wireguard/src/esp_wireguard.c:315 (discriminator 15)

(Issue made per project authors suggestion #33 (comment))

Compatibility with esp_modem?

Sorry that i'm missusing an Issued to ask a question!

I've been trying to get wireguard running over via sim800/sim7000 GSM/LTE Modems and to run mqtt (not via http bit via native protocol) over the wireguard tunnel.

My old solution uses arduino-libs, e.g. tinygsm and pubsubclient which both do not work with wireguard.
(Pubsubclient needs a client object in it's initializer which could be wifi client or gsmclient, but not (arduino-)wireguard, and the arduino-wireguard tunnel will not run over tinygsm links).

As this (and the Arduino "version" of wireguard) uses lwip, bit tinygsm client does not I guess the trick is to switch to espidf and libs that use lwip.

So I came to the idea that using esp_modem for the PPP link and this wireguard lib here I should have a basis to use an lwip aware mqtt client.

But I've no idea about lwip interfaces, routes,.... IMHO my guess would be that wireguard registers a lwip interface (

wg_netif = netif_add(
) and somehow the default-route is applied to it.
But on the other hand the esp_modem would like to do the same, but there's no netif_add in it's code (https://github.com/espressif/esp-protocols/tree/master/components/esp_modem) and there's no hint about adding routes?

So both interfaces would need to be daisy-chained from a routing point - wireguard if should be default gateway, but it should have a route that forwards everything to the PPP interface.

But how could this be accomplished?
I'm thankful for any hint as I'm stuck.

Thanks and Best Regards, Martin.

Not able to install lib.

Hi

I cannot install the package in the latest Arduino IDE 2.X… Even when i try i an older version.

Could it be that there is something wrong with the new package?

Error: Request installZip failed with message: 13
INTERNAL: Library install failed: library not valid

the driver does not support changes in DNS records

the original WireGuard implementation resolves DNS name of peer endpoint once at startup. it does not re-resolve the DNS name. the developer said "it's not a bug". a script, reresolve-dns, to "refresh" addresses is provided for Un*x machines. i believe this behavior is not part of the spec, but other implementations, including the upstream and OpenBSD's wg(4) for example, do the same. One implementation supports DNS resolution in its driver (DNS Updates to WireGuard Endpoints | Pro Custodibus).

Question regarding AP+STA mode

@trombik
I hope you can help
I have an application which uses APSTA mode for the WiFi device
esp_wifi_set_mode(WIFI_MODE_APSTA)

When using this mode rather than WIFI_MODE_STA I suspect there is a configuration issue - I wonder if you could advise. I cannot seem to get the SNTP to synchronize neither to connect the WG interface.

If I run in WIFI_MODE_STA I can connect.

Do you have any idea what could be happening here ?

I could try to construct a testcase - but it is very complicated, so simply wanted to ask the question first.

Cannot complete handshake if pre-shared key is in use

Hi trombik, maybe this is a known limitation, but I report it.

If a pre-shared key is set (both in wireguard_config_t and in server conf file), the device can't complete the handshake.

This is what I observe in server's dmesg

wireguard: wg0: Receiving handshake initiation from peer 96 (xx.xx.xx.xx:yyyyy)
wireguard: wg0: Sending handshake response to peer 96 (xx.xx.xx.xx:yyyyy)
wireguard: wg0: Keypair 73332 created for peer 96
[...]
wireguard: wg0: Receiving handshake initiation from peer 96 (xx.xx.xx.xx:yyyyy)
wireguard: wg0: Sending handshake response to peer 96 (xx.xx.xx.xx:yyyyy)
wireguard: wg0: Keypair 73332 destroyed for peer 96
wireguard: wg0: Keypair 73333 created for peer 96
[...]
wireguard: wg0: Receiving handshake initiation from peer 96 (xx.xx.xx.xx:yyyyy)
wireguard: wg0: Sending handshake response to peer 96 (xx.xx.xx.xx:yyyyy)
wireguard: wg0: Keypair 73333 destroyed for peer 96
wireguard: wg0: Keypair 73334 created for peer 96
[...]

The same again ad again. It is repeated approximately every 3 seconds.

If you need more (or different) information feel free to ask, I'll try to do whatever tests you will need.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.