tprasadtp / protonvpn-docker

ProtonVPN Wireguard Docker Image. Supports ARMv8 (64-bit ) and x86 (64-Bit).
GNU General Public License v3.0
274 stars 24 forks source link

[BUG] - container consistently fails to verify its connection (even though it is still connected), and eventually restarts its process because of this, cutting off other containers in the docker compose #258

Open alexispurslane opened 9 months ago

alexispurslane commented 9 months ago

Version

7.2.3

Credential and Server Validation

System Architecture

x86_64

Kernel Version

6.1.0-12-amd64

Running on a NAS?

No

Runtime

Systemd (>244) Unit, docker-rootless

Version of Runtime

systemd 252 (252.12-1~deb12u1)
+PAM +AUDIT +SELINUX +APPARMOR +IMA +SMACK +SECCOMP +GCRYPT -GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN +IPTC +KMOD +LIBCRYPTSETUP +LIBFDISK +PCRE2 -PWQUALITY +P11KIT +QRENCODE +TPM2 +BZIP2 +LZ4 +XZ +ZLIB +ZSTD -BPF_FRAMEWORK -XKBCOMMON +UTMP +SYSVINIT default-hierarchy=unified
Client: Docker Engine - Community
 Version:    24.0.6
 Context:    default
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc.)
    Version:  v0.11.2
    Path:     /usr/libexec/docker/cli-plugins/docker-buildx
  compose: Docker Compose (Docker Inc.)
    Version:  v2.21.0
    Path:     /usr/libexec/docker/cli-plugins/docker-compose

Server:
 Containers: 13
  Running: 12
  Paused: 0
  Stopped: 1
 Images: 14
 Server Version: 24.0.6
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Using metacopy: false
  Native Overlay Diff: true
  userxattr: false
 Logging Driver: json-file
 Cgroup Driver: systemd
 Cgroup Version: 2
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: io.containerd.runc.v2 runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 61f9fd88f79f081d64d6fa3bb1a0dc71ec870523
 runc version: v1.1.9-0-gccaecfc
 init version: de40ad0
 Security Options:
  apparmor
  seccomp
   Profile: builtin
  cgroupns
 Kernel Version: 6.1.0-12-amd64
 Operating System: Debian GNU/Linux 12 (bookworm)
 OSType: linux
 Architecture: x86_64
 CPUs: 4
 Total Memory: 15.48GiB
 Name: ,,,
 ID: ,,,
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false

My configuration

---
version: "2.3"
services:
  protonwire:
    container_name: protonwire
    image: ghcr.io/tprasadtp/protonwire:latest
    init: true
    restart: unless-stopped
    environment:
      PROTONVPN_SERVER: ...
      DEBUG: 1
    cap_add:
      - NET_ADMIN
    sysctls:
      net.ipv4.conf.all.rp_filter: 2
      net.ipv6.conf.all.disable_ipv6: 1
    volumes:
      - type: tmpfs
        target: /tmp
      - type: bind
        source: ...
        target: /etc/protonwire/private-key
        read_only: true
    ports:
      - 6969:6969
      - 6881:6881
      - 6881:6881/udp
  another_docker:
    ...
    network_mode: service:protonwire
   ...
    restart: unless-stopped
    depends_on:
      - protonwire

Whitelisting API endpoints

I am not using ad-blocking DNS server or gateway

Troubleshooting & Runtime

Container/Pod/systemd log output with DEBUG=1 or --debug flag

protonwire   | [DEBUG   ] IPCHECK_URL                         : https://protonwire-api.vercel.app/v1/client/ip 
protonwire   | [DEBUG   ] METADATA_URL                        : https://protonwire-api.vercel.app/v1/server 
protonwire   | [DEBUG   ] Running as container IDENTITY=uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video) 
protonwire   | [DEBUG   ] Checking requirements 
protonwire   | [DEBUG   ] Using resolvconf(8) for DNS (systemd is not available) 
protonwire   | [DEBUG   ] RUNTIME_DIRECTORY                   : NA 
protonwire   | [DEBUG   ] XDG_RUNTIME_DIR                     : NA 
protonwire   | [DEBUG   ] __PROTONWIRE_SRV_INFO_FILE          : /tmp/protonwire.server.json 
protonwire   | [DEBUG   ] __PROTONWIRE_HCR                    : /tmp/protonwire.hc.response 
protonwire   | [DEBUG   ] WATCHDOG_USEC is not set or invalid 
protonwire   | [DEBUG   ] Checking if IP on other interface is reserved - 127.0.0.1 
protonwire   | [DEBUG   ] Checking if IP on other interface is reserved - 172.28.0.2 
protonwire   | [NOTICE  ] Skipped validating default IPCHECK_URL 
protonwire   | [DEBUG   ] Can use CAP_NET_ADMIN capability 
protonwire   | [DEBUG   ] PROTONVPN_CHECK_THRESHOLD           : NA 
protonwire   | [DEBUG   ] IPCHECK_INTERVAL                    : NA 
protonwire   | [DEBUG   ] Server info file is missing - /tmp/protonwire.server.json 
protonwire   | [INFO    ] Refresing server metadata (for ...) 
protonwire   | [DEBUG   ] API - https://protonwire-api.vercel.app/v1/server/...
protonwire   | [SUCCESS ] Successfully refreshed server metadata 
protonwire   | [DEBUG   ] __PROTONWIRE_SRV_INFO_FILE JSON valid 
protonwire   | [DEBUG   ] metadata_fetch_tries=1 
protonwire   | [DEBUG   ] metadata_fetch_max_tries=3 
protonwire   | [SUCCESS ] Server ... is online 
protonwire   | [DEBUG   ] Selecting all ONLINE endpoints 
protonwire   | [DEBUG   ] __PROTONWIRE_ENDPOINT_IPS_ONLINE    : ,,,
protonwire   | [DEBUG   ] Selecting all endpoints for building keymap 
protonwire   | [DEBUG   ] __PROTONWIRE_ENDPOINT_IPS_ALL       : ...
protonwire   | [DEBUG   ] Endpoint(...) has pubkey - yYcyNBfbU6SWkTLNrzK7peMXHCkG4FKg9bk2D/5yLCo= 
protonwire   | [DEBUG   ] Valid Exit IP for [redacted] - [redacted] [x10]
protonwire   | [DEBUG   ] Not validating country 
protonwire   | [DEBUG   ] Not validating if server supports P2P 
protonwire   | [DEBUG   ] Not validating if server supports Stremaing 
protonwire   | [DEBUG   ] Not validating if server supports Tor 
protonwire   | [DEBUG   ] Not validating if server supports SecureCore 
protonwire   | [DEBUG   ] WIREGUARD_PRIVATE_KEY is not set 
protonwire   | [DEBUG   ] File - /etc/protonwire/private-key has correct permissions (600) 
protonwire   | [SUCCESS ] Using PrivateKeyFile - /etc/protonwire/private-key 
protonwire   | [SUCCESS ] net.ipv4.conf.all.rp_filter is already set to 2 
protonwire   | [NOTICE  ] Creating WireGuard Interface - protonwire0 
protonwire   | [INFO    ] Setting WireGuard interface address - 10.2.0.2 
protonwire   | [INFO    ] Setting WireGuard interface MTU to 1480 
protonwire   | [SUCCESS ] Configured WireGuard private key from /etc/protonwire/private-key 
protonwire   | [DEBUG   ] No configured endpoints on the interface 'protonwire0' 
protonwire   | [DEBUG   ] __PROTONWIRE_ENDPOINT_IPS_ONLINE    : ...
protonwire   | [DEBUG   ] Selected endpoint ...
protonwire   | [DEBUG   ] Peer public key - yYcyNBfbU6SWkTLNrzK7peMXHCkG4FKg9bk2D/5yLCo= 
protonwire   | [DEBUG   ] WireGuard interface is configured with peer - yYcyNBfbU6SWkTLNrzK7peMXHCkG4FKg9bk2D/5yLCo=(...) 
protonwire   | [INFO    ] Bringing WireGuard interface up 
protonwire   | [SUCCESS ] Configured fwmark on WireGuard interface to - 0xca6d 
protonwire   | [DEBUG   ] Excluding RFC-1918 subnets(IPv4) except DNS sever from WireGuard table 
protonwire   | [DEBUG   ] Excluding ULA subnets(IPv6) from WireGuard table 
protonwire   | [INFO    ] Configuring wireguard table 51821 (IPv4) 
protonwire   | [DEBUG   ] Not found wireguard table 51821 (IPv4) 
protonwire   | [DEBUG   ] No need to flush wireguard table 51821 (IPv4) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 10.2.0.1/32 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 0.0.0.0/5 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 8.0.0.0/7 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 11.0.0.0/8 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 12.0.0.0/6 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 16.0.0.0/4 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 32.0.0.0/3 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 64.0.0.0/3 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 96.0.0.0/6 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 100.0.0.0/10 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 100.128.0.0/9 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 101.0.0.0/8 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 102.0.0.0/7 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 104.0.0.0/5 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 112.0.0.0/5 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 120.0.0.0/6 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 124.0.0.0/7 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 126.0.0.0/8 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 128.0.0.0/3 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 160.0.0.0/5 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 168.0.0.0/8 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 169.0.0.0/9 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 169.128.0.0/10 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 169.192.0.0/11 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 169.224.0.0/12 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 169.240.0.0/13 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 169.248.0.0/14 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 169.252.0.0/15 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 169.255.0.0/16 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 170.0.0.0/7 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 172.0.0.0/12 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 172.32.0.0/11 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 172.64.0.0/10 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 172.128.0.0/9 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 173.0.0.0/8 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 174.0.0.0/7 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 176.0.0.0/4 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 192.0.0.0/9 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 192.128.0.0/11 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 192.160.0.0/13 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 192.169.0.0/16 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 192.170.0.0/15 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 192.172.0.0/14 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 192.176.0.0/12 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 192.192.0.0/10 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 193.0.0.0/8 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 194.0.0.0/7 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 196.0.0.0/6 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 200.0.0.0/5 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 208.0.0.0/4 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 224.0.1.0/24 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 224.0.2.0/23 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 224.0.4.0/22 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 224.0.8.0/21 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 224.0.16.0/20 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 224.0.32.0/19 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 224.0.64.0/18 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 224.0.128.0/17 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 224.1.0.0/16 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 224.2.0.0/15 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 224.4.0.0/14 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 224.8.0.0/13 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 224.16.0.0/12 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 224.32.0.0/11 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 224.64.0.0/10 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 224.128.0.0/9 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 225.0.0.0/8 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 226.0.0.0/7 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 228.0.0.0/6 to table(51821) 
protonwire   | [DEBUG   ] Added wireguard route(IPv4) - 232.0.0.0/5 to table(51821) 
protonwire   | [DEBUG   ] Killswitch is disabled, delete killswitch table 51822 if present 
protonwire   | [DEBUG   ] Killswitch table 51822 is not present or empty (IPv4) 
protonwire   | [INFO    ] Configuring IP rules (IPv4) 
protonwire   | [DEBUG   ] Cleanup old rules if any (IPv4) 
protonwire   | [DEBUG   ] No killswitch rules present 
protonwire   | [DEBUG   ] Adding IP rule for Wireguard Table (51821) 
protonwire   | [DEBUG   ] Successfully updated /etc/resolv.conf (via resolvconf) 
protonwire   | [SUCCESS ] Successfully configured DNS (resolvconf) 
protonwire   | [INFO    ] Verifying connection 
protonwire   | [DEBUG   ] WireGuard interface - protonwire0 is present 
protonwire   | [DEBUG   ] Connected to peer - yYcyNBfbU6SWkTLNrzK7peMXHCkG4FKg9bk2D/5yLCo= 
protonwire   | [DEBUG   ] Connected to server: ...
protonwire   | [DEBUG   ] Not validating country 
protonwire   | [DEBUG   ] Not validating if server supports P2P 
protonwire   | [DEBUG   ] Not validating if server supports Stremaing 
protonwire   | [DEBUG   ] Not validating if server supports Tor 
protonwire   | [DEBUG   ] Not validating if server supports SecureCore 
protonwire   | [DEBUG   ] Allowed ExitIPs  - [redacted]
protonwire   | [DEBUG   ] Checking client IP via https://protonwire-api.vercel.app/v1/client/ip 
protonwire   | [DEBUG   ] Healthcheck curl exit code - 6 
protonwire   | [ERROR   ] Failed to resolve DNS domain (https://protonwire-api.vercel.app/v1/client/ip) 
protonwire   | [ERROR   ] Retry (1/3) after 2 seconds 
protonwire   | [DEBUG   ] WireGuard interface - protonwire0 is present 
protonwire   | [DEBUG   ] Connected to peer - yYcyNBfbU6SWkTLNrzK7peMXHCkG4FKg9bk2D/5yLCo= 
protonwire   | [DEBUG   ] Connected to server: ...
protonwire   | [DEBUG   ] Not validating country 
protonwire   | [DEBUG   ] Not validating if server supports P2P 
protonwire   | [DEBUG   ] Not validating if server supports Stremaing 
protonwire   | [DEBUG   ] Not validating if server supports Tor 
protonwire   | [DEBUG   ] Not validating if server supports SecureCore 
protonwire   | [DEBUG   ] Allowed ExitIPs  - [redacted]
protonwire   | [DEBUG   ] Checking client IP via https://protonwire-api.vercel.app/v1/client/ip 
protonwire   | [DEBUG   ] Healthcheck curl exit code - 6 
protonwire   | [ERROR   ] Failed to resolve DNS domain (https://protonwire-api.vercel.app/v1/client/ip) 
protonwire   | [ERROR   ] Retry (2/3) after 2 seconds 
protonwire   | [DEBUG   ] WireGuard interface - protonwire0 is present 
protonwire   | [DEBUG   ] Connected to peer - yYcyNBfbU6SWkTLNrzK7peMXHCkG4FKg9bk2D/5yLCo= 
protonwire   | [DEBUG   ] Connected to server:...
protonwire   | [DEBUG   ] Not validating country 
protonwire   | [DEBUG   ] Not validating if server supports P2P 
protonwire   | [DEBUG   ] Not validating if server supports Stremaing 
protonwire   | [DEBUG   ] Not validating if server supports Tor 
protonwire   | [DEBUG   ] Not validating if server supports SecureCore 
protonwire   | [DEBUG   ] Allowed ExitIPs  -[redacted]
protonwire   | [DEBUG   ] Checking client IP via https://protonwire-api.vercel.app/v1/client/ip 
protonwire   | [DEBUG   ] Healthcheck curl exit code - 6 
protonwire   | [ERROR   ] Failed to resolve DNS domain (https://protonwire-api.vercel.app/v1/client/ip) 
protonwire   | [ERROR   ] Retry (3/3) after 2 seconds 
protonwire   | [ERROR   ] Failed to verify connection! 
protonwire   | [DEBUG   ] No systemd notify socket found, skiping stopping notification 
protonwire   | [DEBUG   ] Successfully restored /etc/resolv.conf (via resolvconf) 
protonwire   | [SUCCESS ] Successfully restored DNS(resolvconf) 
protonwire   | [INFO    ] IPv6 disabled, skipping IPv6 routes and rules 
protonwire   | [INFO    ] Removing IP routing rules 
protonwire   | [DEBUG   ] Flushing routing table 51821 (IPv4) 
protonwire   | [INFO    ] Removing WireGuard interface

Any additional info

I've also tried changing the IPCHECK_URL to https://api.ipify.org/, but it didn't help. It still continues to fail to verify.

Code of Conduct & PII Redaction

alexispurslane commented 9 months ago

I've tried pinging various things from inside docker compose exec protonwire bash and ping can never reach anything either, it just hangs forever. Even though, sometimes, before protonwire restarts itself (and gets a different log color), the docker container behind it can access the internet!

eebette commented 9 months ago

Same here. Usually have to go in and 'docker compose protonwire restart' to reset the entire stack but definitely looking for a fix here.

tprasadtp commented 9 months ago

Curl exit code 6 is DNS error. From the logs I can see that metadata endpoints are indeed reachable, So I guess the problem is with https://protonwire-api.vercel.app/v1/client/ip which redirects to https://icanhazip.com

Can you try to resolve protonwire-api.vercel.app and icanhazip.com from both inside and outside the container? container has bind-tools so host command should work, Can you try the following commands and post the output (Please redact your public IP).

host -t A protonwire-api.vercel.app
host -t A icanhazip.com
curl -Lv https://protonwire-api.vercel.app/v1/client/ip

If they do not work, try setting IPCHECK_URL to https://protonwire-api.vercel.app/api/client/exp/clientip and check if resolves the issue. This API endpoint is experimental do not spam it.

ping may be a different issue as it typically requires additional caps (CAP_NET_RAW or tweaking sysctl net.ipv4.ping_group_range.

alexispurslane commented 9 months ago

@tprasadtp excellent, thank you, I'll give these commands a shot and see what I get! I don't know if changing the API endpoint will work, since I already attempted to do that as noted in my bug report, but it's worth a shot too.

alexispurslane commented 9 months ago

Alright I ran the suggested commands inside the protonwire container and here's what I got:

protonwire-api.vercel.app has address 76.76.21.61
protonwire-api.vercel.app has address 76.76.21.93
icanhazip.com has address 104.18.115.97
icanhazip.com has address 104.18.114.97
*   Trying 76.76.21.61:443...
* Connected to protonwire-api.vercel.app (76.76.21.61) port 443 (#0)
* ALPN: offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: none
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_CHACHA20_POLY1305_SHA256
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=*.vercel.app
*  start date: Sep 25 03:14:47 2023 GMT
*  expire date: Dec 24 03:14:46 2023 GMT
*  subjectAltName: host "protonwire-api.vercel.app" matched cert's "*.vercel.app"
*  issuer: C=US; O=Let's Encrypt; CN=R3
*  SSL certificate verify ok.
* using HTTP/2
* h2h3 [:method: GET]
* h2h3 [:path: /v1/client/ip]
* h2h3 [:scheme: https]
* h2h3 [:authority: protonwire-api.vercel.app]
* h2h3 [user-agent: curl/8.0.1]
* h2h3 [accept: */*]
* Using Stream ID: 1 (easy handle 0x7fc30856faf0)
> GET /v1/client/ip HTTP/2
> Host: protonwire-api.vercel.app
> user-agent: curl/8.0.1
> accept: */*
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
< HTTP/2 308 
< cache-control: public, max-age=0, must-revalidate
< content-type: text/plain
< date: Fri, 29 Sep 2023 17:42:42 GMT
< location: https://icanhazip.com/
< refresh: 0;url=https://icanhazip.com/
< server: Vercel
< strict-transport-security: max-age=63072000; includeSubDomains; preload
< x-vercel-cache: MISS
< x-vercel-id: iad1::cj79f-1696009362684-a013ed042279
< 
* Ignoring the response-body
* Connection #0 to host protonwire-api.vercel.app left intact
* Issue another request to this URL: 'https://icanhazip.com/'
*   Trying 104.18.114.97:443...
* Connected to icanhazip.com (104.18.114.97) port 443 (#1)
* ALPN: offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN: server accepted h2
* Server certificate:
*  subject: C=US; ST=California; L=San Francisco; O=Cloudflare, Inc.; CN=sni.cloudflaressl.com
*  start date: Apr  7 00:00:00 2023 GMT
*  expire date: Apr  6 23:59:59 2024 GMT
*  subjectAltName: host "icanhazip.com" matched cert's "icanhazip.com"
*  issuer: C=US; O=Cloudflare, Inc.; CN=Cloudflare Inc ECC CA-3
*  SSL certificate verify ok.
* using HTTP/2
* h2h3 [:method: GET]
* h2h3 [:path: /]
* h2h3 [:scheme: https]
* h2h3 [:authority: icanhazip.com]
* h2h3 [user-agent: curl/8.0.1]
* h2h3 [accept: */*]
* Using Stream ID: 1 (easy handle 0x7fc30856faf0)
> GET / HTTP/2
> Host: icanhazip.com
> user-agent: curl/8.0.1
> accept: */*
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
< HTTP/2 200 
< date: Fri, 29 Sep 2023 17:42:42 GMT
< content-type: text/plain
< content-length: 13
< access-control-allow-origin: *
< access-control-allow-methods: GET
< set-cookie: __cf_bm=1EoYCZIBioCXpjESzk8BewS1FTnGiAfzvq0VjCVat1M-1696009362-0-AQr9fCq43QrcroeorxGZmw3zuYdXTWFrxrSfIW6Q9uYLQq8uybFhGBTbpaF0rb6jQgvEdqpibuugjryTptIv2Xc=; path=/; expires=Fri, 29-Sep-23 18:12:42 GMT; domain=.icanhazip.com; HttpOnly; Secure; SameSite=None
< server: cloudflare
< cf-ray: 80e60636395782fc-IAD
< alt-svc: h3=":443"; ma=86400
< 
[MY IP ADDRESS REDACTED]
* Connection #1 to host icanhazip.com left intact

It also appeared that I can ping both IP addresses and URLs, and even curl icanhazip.com, from inside the protonwire client, but the docker container behind it still couldn't access the internet (perhaps because protonwire had restarted so many times it finally became stable, but the other docker couldn't talk to the newly started processes) . This was presenting differently than it had been when I made the bug report, so I restarted the docker compose in order to see if I could do your commands while it was having the problems I initially described, for better diagnostics. Instead, now the problem is gone! The connection can be verified the first time, so protonwire doesn't need to restart, which means the container behind it can access the internet. I'm worried this will happen again though.

tprasadtp commented 9 months ago

It might be that server you selected was offline for a while, which obviously results in connection errors. Because DNS is kinda circular dependency it may result in DNS errors when wireguard client is up. (DNS is 10.2.0.1 which is only accessible if VPN is connected). Can you provide logs with timestamps and exact server name?

How are you running containers behind the VPN? There also might be a race condition which can lead to networking being broken inside them.

alexispurslane commented 9 months ago

I restarted my computer and I'm running into the exact same problems again, with basically the exact same logs, despite choosing a completely different server so I highly doubt that it's the server randomly being offline. Also as you can see in the docker composed that I put in the original issue post I have the docker container that's behind proton wire set up to depend on proton wire so there is no race condition there.

alexispurslane commented 9 months ago

Here is the current output of the three commands you listed above, now that protonwire is failing again:

 ;; communications error to 10.2.0.1#53: timed out
;; communications error to 10.2.0.1#53: timed out
;; no servers could be reached

;; communications error to 10.2.0.1#53: timed out
;; communications error to 10.2.0.1#53: timed out
;; no servers could be reached
tprasadtp commented 9 months ago

10.2.0.1 is the protonvpn server which also handles DNS, so connection errors to server breaks everything.

Whats the output of wg show protonwire0 (inside the container)? Can you curl an IP address? Try curl -vL https://1.1.1.1/ -o /dev/null (This should bypass the DNS)

If it does not work, can you try to run with SKIP_DNS_CONFIG=1? That should remove DNS from the variables.

alexispurslane commented 9 months ago

output of wg show protonwire0:

interface: protonwire0
  public key: ...
  private key: (hidden)
  listening port: 41637
  fwmark: 0xca6d

peer: [peer public key]
  endpoint: 193.29.107.162:51820
  allowed ips: 0.0.0.0/0, ::/0
  latest handshake: 1 minute, 28 seconds ago
  transfer: 801.47 KiB received, 327.49 KiB sent
  persistent keepalive: every 25 seconds

output of curl -vL https://1.1.1.1/ -o /dev/null:

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*   Trying 1.1.1.1:443...
* Connected to 1.1.1.1 (1.1.1.1) port 443 (#0)
* ALPN: offers h2,http/1.1
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: none
{ [5 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [122 bytes data]
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
{ [15 bytes data]
* TLSv1.3 (IN), TLS handshake, Certificate (11):
{ [2598 bytes data]
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
{ [79 bytes data]
* TLSv1.3 (IN), TLS handshake, Finished (20):
{ [52 bytes data]
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
} [1 bytes data]
* TLSv1.3 (OUT), TLS handshake, Finished (20):
} [52 bytes data]
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN: server accepted h2
* Server certificate:
*  subject: C=US; ST=California; L=San Francisco; O=Cloudflare, Inc.; CN=cloudflare-dns.com
*  start date: Jan 12 00:00:00 2023 GMT
*  expire date: Jan 11 23:59:59 2024 GMT
*  subjectAltName: host "1.1.1.1" matched cert's IP address!
*  issuer: C=US; O=DigiCert Inc; CN=DigiCert TLS Hybrid ECC SHA384 2020 CA1
*  SSL certificate verify ok.
} [5 bytes data]
* using HTTP/2
* h2h3 [:method: GET]
* h2h3 [:path: /]
* h2h3 [:scheme: https]
* h2h3 [:authority: 1.1.1.1]
* h2h3 [user-agent: curl/8.0.1]
* h2h3 [accept: */*]
* Using Stream ID: 1 (easy handle 0x7fb76c074af0)
} [5 bytes data]
> GET / HTTP/2
> Host: 1.1.1.1
> user-agent: curl/8.0.1
> accept: */*
> 
{ [5 bytes data]
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
{ [230 bytes data]
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
{ [230 bytes data]
* old SSL session ID is stale, removing
{ [5 bytes data]
< HTTP/2 200 
< date: Sun, 01 Oct 2023 18:24:18 GMT
< content-type: text/html
< report-to: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=hQOLzC6oLrf%2BCOOcvO8Ufzoh8lfJ9zaZs10q04YXUaPkewo3Q0no7Hur4PZANhkR%2FQww5bKG%2FxCds53IKCVzWSTphfLmUi8%2FFEvpzr5%2BPqnla2EBY%2FCbe5A%3D"}],"group":"cf-nel","max_age":604800}
< nel: {"report_to":"cf-nel","max_age":604800}
< last-modified: Fri, 21 Jul 2023 21:11:33 GMT
< strict-transport-security: max-age=31536000
< served-in-seconds: 0.004
< cache-control: public, max-age=14400
< cf-cache-status: HIT
< age: 38
< expires: Sun, 01 Oct 2023 22:24:18 GMT
< accept-ranges: bytes
< set-cookie: __cf_bm=.DknbODlodCAZFfdM3vxVzfz8H5wIh7tb5q6Nu5yjok-1696184658-0-AaOU+Yqd+1WwWrpGEe0XMyKAQQgVfjX0y2ov5OQUw8ucL5vNKnmEtVhFxu/Pu4bi0CU1ehEz123geZ3OI3/1Nh8=; path=/; expires=Sun, 01-Oct-23 18:54:18 GMT; domain=.every1dns.com; HttpOnly; Secure; SameSite=None
< server: cloudflare
< cf-ray: 80f6bde35e542c52-FRA
< alt-svc: h3=":443"; ma=86400
< 
{ [5 bytes data]
100 56597    0 56597    0     0  62328      0 --:--:-- --:--:-- --:--:-- 62331
* Connection #0 to host 1.1.1.1 left intact
tprasadtp commented 9 months ago

So it looks like it can connect fine to the internet. Try this command and check if it returns your public IP. If yes then something is wrong with routing/wireguard tunnel if not its only the DNS which is borked and need to be fixed.

curl -vfL --resolve "protonwire-api.vercel.app:443:76.76.21.9"  -H 'Host: protonwire-api.vercel.app' https://protonwire-api.vercel.app/api/client/exp/clientip

If you get protonVPN public IP from the above command, use SKIP_DNS_CONFIG=1 as a work around for now. You can configure DoT on systemd resolved to protect DNS queries.

alexispurslane commented 9 months ago

I ran that command, and I got the protonVPN endpoint IP address back, so it looks like it is just a DNS issue. I'm not using systemd-resolved though, and I'd rather not even slightly risk any data leaks (I have clinical anxiety and just don't want the mental space taken up by that lol) so I guess I'll just wait till a proper fix for the DNS is found.

tprasadtp commented 9 months ago

Next time you encounter the issue can you try the following?

cat /etc/resolv.conf
cat /etc/resolv.conf.protonwire
ls -alh /etc/resolv.conf

ip route get 10.2.0.1
ip -4 --json rule | jq
ip -4 --json route show table 51821  | jq

ping 10.2.0.1

I cannot reproduce the issue locally. Did the issue occur after upgrade to 7.2 or later ?

alexispurslane commented 9 months ago

Next time you encounter the issue can you try the following?

cat /etc/resolv.conf
cat /etc/resolv.conf.protonwire
ls -alh /etc/resolv.conf

ip route get 10.2.0.1
ip -4 --json rule | jq
ip -4 --json route show table 51821  | jq

ping 10.2.0.1

Sure, no problem! I'll run them right now

I cannot reproduce the issue locally. Did the issue occur after upgrade to 7.2 or later ?

I'm not sure, but I think so — I'd had the container up for like two or more straight months, then I finally rebooted my server and restarted the container, and that's when the problems started, which implies it started when the image was rebuilt, I think,

alexispurslane commented 9 months ago

@tprasadtp oh shit, I just realized, even though I thought I updated the container, it's still on version 7.0.3 according to docker inspect... strange. Let me try to update it and see if that resolves the problem.

alexispurslane commented 9 months ago

Interesting. Now that I've updated, it works fine... for now, at least.

Edit (later): nope, it's broken again

tprasadtp commented 9 months ago

I think change to updating the resolv.conf logic might be the issue. But openresolv(used in 7.0.x) is also broken as it does not behave well with bind mounted /etc/resolv.conf.

cat /etc/resolv.conf
cat /etc/resolv.conf.protonwire
ls -alh /etc/resolv.conf

ip route get 10.2.0.1
ip -4 --json rule | jq
ip -4 --json route show table 51821  | jq

ping 10.2.0.1

Can you please try these and give their outputs? Also output of docker inspect of the container?

alexispurslane commented 9 months ago

Alright. It started working again this morning when I restarted it (connection was able to be verified), but I'll wait until it fails again and run those commands. In the meantime, check out these logs, it's doing something new — verifying the connection is still failing, but then it's reconnecting to the server, which it wasn't doing before, and reconnnecting successfully too. It also says the server is online:

protonwire   | [INFO    ] Refresing server metadata (for ...) 
protonwire   | [SUCCESS ] Successfully refreshed server metadata 
protonwire   | [SUCCESS ] Server ... is online 
protonwire   | [SUCCESS ] Using PrivateKeyFile - /etc/protonwire/private-key 
protonwire   | [SUCCESS ] net.ipv4.conf.all.rp_filter is already set to 2 
protonwire   | [NOTICE  ] Creating WireGuard Interface - protonwire0 
protonwire   | [INFO    ] Setting WireGuard interface address - 10.2.0.2 
protonwire   | [INFO    ] Setting WireGuard interface MTU to 1480 
protonwire   | [SUCCESS ] Configured WireGuard private key from /etc/protonwire/private-key 
protonwire   | [INFO    ] WireGuard interface is configured with peer - ...
protonwire   | [INFO    ] Bringing WireGuard interface up 
protonwire   | [SUCCESS ] Configured fwmark on WireGuard interface to - 0xca6d 
protonwire   | [NOTICE  ] Creating routes (IPv4) 
protonwire   | [SUCCESS ] DNS is is set to 10.2.0.1 via /etc/resolv.conf 
protonwire   | [SUCCESS ] Successfully configured DNS (resolvconf) 
protonwire   | [INFO    ] Verifying connection 
protonwire   | [SUCCESS ] Connected to node-...
protonwire   | [SUCCESS ] Connection verified! 
protonwire   | [INFO    ] Checking status - every 120 seconds 
protonwire   | [ERROR   ] Failed to resolve DNS domain (https://protonwire-api.vercel.app/v1/client/ip) 
protonwire   | [ERROR   ] Failed to verify connection (1/5) 
protonwire   | [WARNING ] Attempting to re-connect to ...
protonwire   | [SUCCESS ] Server ... is online 
protonwire   | [SUCCESS ] Using PrivateKeyFile - /etc/protonwire/private-key 
protonwire   | [SUCCESS ] net.ipv4.conf.all.rp_filter is already set to 2 
protonwire   | [NOTICE  ] WireGuard interface 'protonwire0' already exists 
protonwire   | [SUCCESS ] WireGuard interface already has address - 10.2.0.2/32 
protonwire   | [SUCCESS ] WireGuard interface MTU is already set to - 1480 
protonwire   | [SUCCESS ] WireGuard interface already has private key configured 
protonwire   | [SUCCESS ] WireGuard interface already has peer - ...
protonwire   | [SUCCESS ] WireGuard interface is already UP 
protonwire   | [SUCCESS ] WireGuard interface fwmark is already set to - 0xca6d 
protonwire   | [SUCCESS ] Routes are algrady configured (IPv4) 
protonwire   | [SUCCESS ] Routing policy rule is already configured (IPv4) 
protonwire   | [SUCCESS ] DNS is already set to 10.2.0.1 in /etc/resolv.conf 
protonwire   | [SUCCESS ] Successfully configured DNS (resolvconf) 
protonwire   | [SUCCESS ] Connected to node-dk-05.protonvpn.net (via 193.29.107.163) 
protonwire   | [NOTICE  ] Successfully reconnected to ...
alexispurslane commented 9 months ago

Here's the command output:

# This file is managed by protonwire. DO NOT EDIT.
# If you do not wish to use ProtonVPN DNS servers,
# disable it via one of the following.
#  - Set 'SKIP_DNS_CONFIG' envirpnment variable to '1'.
#  - Use '--skip-dns-config' CLI flag.
#
# Your old DNS configration has been backed up at /etc/resolv.conf.protonwire.
# protonvpn will automatically restore your previous DNS config upon disconnect.
#
nameserver 10.2.0.1
nameserver 127.0.0.11
options ndots:0
-rw-r--r--    1 root     root         420 Oct  2 13:51 /etc/resolv.conf
10.2.0.1 dev protonwire0 table 51821 src 10.2.0.2 uid 0 
    cache 
[
  {
    "priority": 0,
    "src": "all",
    "table": "local"
  },
  {
    "priority": 32765,
    "not": null,
    "src": "all",
    "fwmark": "0xca6d",
    "table": "51821"
  },
  {
    "priority": 32766,
    "src": "all",
    "table": "main"
  },
  {
    "priority": 32767,
    "src": "all",
    "table": "default"
  }
]
[
  {
    "dst": "0.0.0.0/5",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "8.0.0.0/7",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "10.2.0.1",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "11.0.0.0/8",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "12.0.0.0/6",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "16.0.0.0/4",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "32.0.0.0/3",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "64.0.0.0/3",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "96.0.0.0/6",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "100.0.0.0/10",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "100.128.0.0/9",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "101.0.0.0/8",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "102.0.0.0/7",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "104.0.0.0/5",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "112.0.0.0/5",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "120.0.0.0/6",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "124.0.0.0/7",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "126.0.0.0/8",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "128.0.0.0/3",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "160.0.0.0/5",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "168.0.0.0/8",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "169.0.0.0/9",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "169.128.0.0/10",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "169.192.0.0/11",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "169.224.0.0/12",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "169.240.0.0/13",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "169.248.0.0/14",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "169.252.0.0/15",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "169.255.0.0/16",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "170.0.0.0/7",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "172.0.0.0/12",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "172.32.0.0/11",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "172.64.0.0/10",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "172.128.0.0/9",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "173.0.0.0/8",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "174.0.0.0/7",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "176.0.0.0/4",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "192.0.0.0/9",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "192.128.0.0/11",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "192.160.0.0/13",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "192.169.0.0/16",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "192.170.0.0/15",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "192.172.0.0/14",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "192.176.0.0/12",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "192.192.0.0/10",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "193.0.0.0/8",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "194.0.0.0/7",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "196.0.0.0/6",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "200.0.0.0/5",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "208.0.0.0/4",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "224.0.1.0/24",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "224.0.2.0/23",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "224.0.4.0/22",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "224.0.8.0/21",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "224.0.16.0/20",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "224.0.32.0/19",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "224.0.64.0/18",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "224.0.128.0/17",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "224.1.0.0/16",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "224.2.0.0/15",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "224.4.0.0/14",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "224.8.0.0/13",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "224.16.0.0/12",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "224.32.0.0/11",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "224.64.0.0/10",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "224.128.0.0/9",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "225.0.0.0/8",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "226.0.0.0/7",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "228.0.0.0/6",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  },
  {
    "dst": "232.0.0.0/5",
    "dev": "protonwire0",
    "scope": "link",
    "metric": 500,
    "flags": []
  }
]
PING 10.2.0.1 (10.2.0.1): 56 data bytes
64 bytes from 10.2.0.1: seq=0 ttl=64 time=107.875 ms
64 bytes from 10.2.0.1: seq=1 ttl=64 time=108.152 ms
64 bytes from 10.2.0.1: seq=2 ttl=64 time=113.538 ms
^C
--- 10.2.0.1 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 107.875/109.855/113.538 ms

here's the inspect output:


[
    {
        "Id": "...",
        "Created": "2023-10-01T22:52:30.692743725Z",
        "Path": "/usr/bin/protonwire",
        "Args": [
            "connect",
            "--container"
        ],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 237751,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2023-10-02T13:51:31.637724376Z",
            "FinishedAt": "2023-10-02T13:51:31.279691757Z"
        },
        "Image": "sha256:952d93f4bd6ae8144ff6692c9e3e864a0aa93d2cd0fbc5be6593d152faaf7887",
        "ResolvConfPath": "/var/lib/docker/containers/952e79f5dfaa2e757e1c7ee199869ad538d3e1389459395b552ddd1ec32ddeed/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/952e79f5dfaa2e757e1c7ee199869ad538d3e1389459395b552ddd1ec32ddeed/hostname",
        "HostsPath": "/var/lib/docker/containers/952e79f5dfaa2e757e1c7ee199869ad538d3e1389459395b552ddd1ec32ddeed/hosts",
        "LogPath": "/var/lib/docker/containers/952e79f5dfaa2e757e1c7ee199869ad538d3e1389459395b552ddd1ec32ddeed/952e79f5dfaa2e757e1c7ee199869ad538d3e1389459395b552ddd1ec32ddeed-json.log",
        "Name": "/protonwire",
        "RestartCount": 85,
        "Driver": "overlay2",
        "Platform": "linux",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "docker-default",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "projectname_default",
            "PortBindings": {
                "6881/tcp": [
                    {
                        "HostIp": "",
                        "HostPort": "6881"
                    }
                ],
                "6881/udp": [
                    {
                        "HostIp": "",
                        "HostPort": "6881"
                    }
                ],
                "6969/tcp": [
                    {
                        "HostIp": "",
                        "HostPort": "6969"
                    }
                ]
            },
            "RestartPolicy": {
                "Name": "unless-stopped",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "ConsoleSize": [
                0,
                0
            ],
            "CapAdd": [
                "NET_ADMIN"
            ],
            "CapDrop": null,
            "CgroupnsMode": "private",
            "Dns": null,
            "DnsOptions": null,
            "DnsSearch": null,
            "ExtraHosts": [],
            "GroupAdd": null,
            "IpcMode": "private",
            "Cgroup": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "UsernsMode": "",
            "ShmSize": 67108864,
            "Sysctls": {
                "net.ipv4.conf.all.rp_filter": "2",
                "net.ipv6.conf.all.disable_ipv6": "1"
            },
            "Runtime": "runc",
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": null,
            "BlkioDeviceReadBps": null,
            "BlkioDeviceWriteBps": null,
            "BlkioDeviceReadIOps": null,
            "BlkioDeviceWriteIOps": null,
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": null,
            "DeviceCgroupRules": null,
            "DeviceRequests": null,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": null,
            "OomKillDisable": null,
            "PidsLimit": null,
            "Ulimits": null,
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0,
            "Mounts": [
                {
                    "Type": "tmpfs",
                    "Target": "/tmp"
                },
                {
                    "Type": "bind",
                    "Source": "/opt/docker/projectname/wg2-private.key",
                    "Target": "/etc/protonwire/private-key",
                    "ReadOnly": true
                }
            ],
            "MaskedPaths": [
                "/proc/asound",
                "/proc/acpi",
                "/proc/kcore",
                "/proc/keys",
                "/proc/latency_stats",
                "/proc/timer_list",
                "/proc/timer_stats",
                "/proc/sched_debug",
                "/proc/scsi",
                "/sys/firmware"
            ],
            "ReadonlyPaths": [
                "/proc/bus",
                "/proc/fs",
                "/proc/irq",
                "/proc/sys",
                "/proc/sysrq-trigger"
            ],
            "Init": true
        },
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/577524c738e4e67596b7c164e4351a831e437fec127c110856ba3770c51ca24e-init/diff:/var/lib/docker/overlay2/0d5bbbeed3e21b388eb547b5a36712277dbb681c2970a2ebde7e01d477d183b7/diff:/var/lib/docker/overlay2/9478a60b4dc66f264edb60b6975c158f9777ee78c7e92e9a7692d716e87da10e/diff:/var/lib/docker/overlay2/bab38cec549e0a06f842239d6642393e8aef4c23982ad6da53a38892ae1d0296/diff:/var/lib/docker/overlay2/a4a97968382108a583457cd6b5af0de13ed4ae96ed52292357fa6657d06699fe/diff",
                "MergedDir": "/var/lib/docker/overlay2/577524c738e4e67596b7c164e4351a831e437fec127c110856ba3770c51ca24e/merged",
                "UpperDir": "/var/lib/docker/overlay2/577524c738e4e67596b7c164e4351a831e437fec127c110856ba3770c51ca24e/diff",
                "WorkDir": "/var/lib/docker/overlay2/577524c738e4e67596b7c164e4351a831e437fec127c110856ba3770c51ca24e/work"
            },
            "Name": "overlay2"
        },
        "Mounts": [
            {
                "Type": "tmpfs",
                "Source": "",
                "Destination": "/tmp",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            },
            {
                "Type": "bind",
                "Source": "/opt/docker/projectname/wg2-private.key",
                "Destination": "/etc/protonwire/private-key",
                "Mode": "",
                "RW": false,
                "Propagation": "rprivate"
            }
        ],
        "Config": {
            "Hostname": "952e79f5dfaa",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": true,
            "AttachStderr": true,
            "ExposedPorts": {
                "6881/tcp": {},
                "6881/udp": {},
                "6969/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PROTONVPN_SERVER=...",
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/usr/bin/protonwire",
                "connect",
                "--container"
            ],
            "Image": "ghcr.io/tprasadtp/protonwire:latest",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {
                "com.docker.compose.config-hash": "cfdc52264b86d28cbca5a42920dea92335e01d29f4840e732559510780f9c09b",
                "com.docker.compose.container-number": "1",
                "com.docker.compose.depends_on": "",
                "com.docker.compose.image": "sha256:952d93f4bd6ae8144ff6692c9e3e864a0aa93d2cd0fbc5be6593d152faaf7887",
                "com.docker.compose.oneoff": "False",
                "com.docker.compose.project": "projectname",
                "com.docker.compose.project.config_files": "/opt/docker/projectname/docker-compose.yml",
                "com.docker.compose.project.working_dir": "/opt/docker/projectname",
                "com.docker.compose.service": "protonwire",
                "com.docker.compose.version": "2.21.0",
                "io.github.tprasadtp.metadata.git.branch": "HEAD",
                "io.github.tprasadtp.metadata.git.commit": "3adea60a05cd076ee612f4f818dd886d21e8a430",
                "io.github.tprasadtp.metadata.git.shortCommit": "3adea60",
                "io.github.tprasadtp.metadata.git.tag": "7.2.3",
                "io.github.tprasadtp.metadata.version.major": "7",
                "io.github.tprasadtp.metadata.version.minor": "2",
                "io.github.tprasadtp.metadata.version.patch": "3",
                "io.github.tprasadtp.metadata.version.prerelease": "",
                "io.github.tprasadtp.metadata.version.snapshot": "false",
                "org.opencontainers.image.created": "2023-09-24T20:38:01Z",
                "org.opencontainers.image.description": "\"ProtonVPN Wireguard Client for Linux\"",
                "org.opencontainers.image.documentation": "https://tprasadtp.github.io/protonwire",
                "org.opencontainers.image.licenses": "GPLv3",
                "org.opencontainers.image.revision": "3adea60a05cd076ee612f4f818dd886d21e8a430",
                "org.opencontainers.image.source": "\"https://github.com/tprasadtp/protonwire\"",
                "org.opencontainers.image.title": "protonwire",
                "org.opencontainers.image.url": "https://ghcr.io/tprasadtp/protonwire",
                "org.opencontainers.image.vendor": "\"Prasad Tengse <tprasadtp@users.noreply.github.com>\"",
                "org.opencontainers.image.version": "7.2.3"
            }
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "0ee1735cd5c84e0ea1201d9247dd6bf5fc8039d96539781fd7e8690f14dfe361",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {
                "6881/tcp": [
                    {
                        "HostIp": "0.0.0.0",
                        "HostPort": "6881"
                    },
                    {
                        "HostIp": "::",
                        "HostPort": "6881"
                    }
                ],
                "6881/udp": [
                    {
                        "HostIp": "0.0.0.0",
                        "HostPort": "6881"
                    },
                    {
                        "HostIp": "::",
                        "HostPort": "6881"
                    }
                ],
                "6969/tcp": [
                    {
                        "HostIp": "0.0.0.0",
                        "HostPort": "6969"
                    },
                    {
                        "HostIp": "::",
                        "HostPort": "6969"
                    }
                ]
            },
            "SandboxKey": "/var/run/docker/netns/0ee1735cd5c8",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "",
            "Gateway": "",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "",
            "IPPrefixLen": 0,
            "IPv6Gateway": "",
            "MacAddress": "",
            "Networks": {
                "projectname_default": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": [
                        "protonwire",
                        "protonwire",
                        "952e79f5dfaa"
                    ],
                    "NetworkID": "f2e23327b187848d908ce53d5a1b76ca8ab8ac101a8f15d2dbdf6b9e36dca5f9",
                    "EndpointID": "48b152225ed5514aff6ea1d2df8d8461ef27a3a8a5204229926982be3cc2439c",
                    "Gateway": "172.21.0.1",
                    "IPAddress": "172.21.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:15:00:02",
                    "DriverOpts": null
                }
            }
        }
    }
]
tprasadtp commented 9 months ago

Just to be clear this is output when connection fails, correct? Everything looks fine from routing table and routing priorities. Are you still able to resolve some random DNS from inside the container?

alexispurslane commented 9 months ago

Just to be clear this is output when connection fails, correct?

Yeah

Everything looks fine from routing table and routing priorities. Are you still able to resolve some random DNS from inside the container?

I'll check in a bit

tprasadtp commented 9 months ago

Yeah

Its really weird. You can ping to DNS server it routes via correct interface, but only DNS resolution fails? Really strange.

I'll check in a bit

Take your time.

I re-built the container image with debian as the base image ghcr.io/tprasadtp/protonwire:7.2.3-debug-alexis. (It was built by github actions and is signed) try it and check if it helps? Another option is to run with a different container runtime.

Debian bookworm has podman can you try to run it with podman? Also rootless uses user-mode networking. I don't think its an issue but can you try to run container it in podman rootful mode?

Have you disabled Netshield in your protonvpn configuration?

alexispurslane commented 9 months ago

Have you disabled Netshield in your protonvpn configuration?

Yes

tprasadtp commented 9 months ago

Hmmm, This is really strange. Try it with debian image ghcr.io/tprasadtp/protonwire:7.2.3-debug-alexis, and next time when connection errors, try to ping 10.2.0.1 and also try to resolve a well known dns name like github.com inside the container and also verify DNS queries are being routed via wireguard. ip route get 10.2.0.1 I will try to reproduce this on bookworm and same docker version.

tprasadtp commented 9 months ago

I can somewhat reproduce the issue, but it recovers on its own quickly.

docker run -it \
    --name=protonwire-alexis-test-f8c2df2 \
    --init \
    --cap-add=CAP_NET_ADMIN \
    --userns=host -p=8000:80 \
    --mount type=bind,src=<key-file>,dst=/etc/protonwire/private-key,readonly \
    --sysctl net.ipv4.conf.all.rp_filter=2 \
    --tmpfs /tmp \
    ghcr.io/tprasadtp/protonwire:7.3.0-alpha1 \
    protonwire c nl-free-127.protonvpn.net --verbose --container --ks --check-interval 10
[•] Adding IP rule for Table 51821 (IPv4) 
[•] Updating /etc/resolv.conf 
[•] DNS is is set to 10.2.0.1 via /etc/resolv.conf 
[•] Successfully configured DNS (resolvconf) 
[•] Verifying connection 
[•] WireGuard interface - protonwire0 is present 
[•] Connected to peer - zFkaDAaf8Xt6c1FY82sp5Ncw/pN+GB9asDtGDOWClzo= 
[•] Connected to server: NL-FREE#128127(nl-free-127.protonvpn.net) 
[•] Not validating country 
[•] Not validating if server supports P2P 
[•] Not validating if server supports Stremaing 
[•] Not validating if server supports Tor 
[•] Not validating if server supports SecureCore 
[•] Allowed ExitIPs  - 185.107.56.76 185.107.56.78 185.107.56.80 185.107.56.83 
[•] Checking client IP via https://protonwire-api.vercel.app/v1/client/ip 
[•] (curl) % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current 
[•] (curl) Dload  Upload   Total   Spent    Left  Speed 
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* Could not resolve host: protonwire-api.vercel.app 
[•] (curl) * Closing connection 0 
[•] (curl) curl: (6) Could not resolve host: protonwire-api.vercel.app 
[•] Healthcheck curl exit code - 6 
[•] Failed to resolve DNS domain (https://protonwire-api.vercel.app/v1/client/ip) 
[•] Retry (1/5) after 2 seconds

But it happens sporadically but it recovers quickly. Only changes I have from your configuration is IPCHECK_INTERVAL=10 which might help if NAT gateway is forgetting connections too quickly and KILL_SWITCH=1.

I have pushed 7.3.0-alpha1 image which uses debian bookworm. Does the issue persist with that image as well?

Any output from

ip route get 10.2.0.1
ping 10.2.0.1
host -t A github.com

when the issue occurs might shed light on whats happening. If that too does not help, try to run with SKIP_DNS_CONFIG=1. (You don't need any connected containers just run the protonwire and see if the issue re-appears). Also try with a custom name server like 1.1.1.1 (use --dns flag or dns option.)

alexispurslane commented 8 months ago

Hmmm, This is really strange. Try it with debian image ghcr.io/tprasadtp/protonwire:7.2.3-debug-alexis, and next time when connection errors, try to ping 10.2.0.1 and also try to resolve a well known dns name like github.com inside the container and also verify DNS queries are being routed via wireguard. ip route get 10.2.0.1 I will try to reproduce this on bookworm and same docker version.

When using this container image, ping isn't provided for some reason. I'll try the stuff in your most recent comment instead.

alexispurslane commented 8 months ago

Okay, trying with the 7.3.0-alpha1 container image, and the different environment variables you mentioned, and I'm still getting the same failure to verify the connection because it can't resolve the DNS of the domain as before. Here's the output from the three commands you gave:

10.2.0.1 dev protonwire0 table 51821 src 10.2.0.2 uid 0 
    cache 
bash: ping: command not found
;; communications error to 10.2.0.1#53: timed out
;; communications error to 10.2.0.1#53: timed out
;; no servers could be reached
tprasadtp commented 8 months ago

I really appreciate your patience, you are being awesome! :tada:

bash: ping: command not found

Ahh my bad I missed iputils-ping (which was provided by busybox on alpine) 7.3.0-alpha2 should have it.

Lets narrow it down.

interface: protonwire0
  public key: xx
  private key: (hidden)
  listening port: 46403
  fwmark: 0xca6d

peer: zFkaDAaf8Xt6c1FY82sp5Ncw/pN+GB9asDtGDOWClzo=
  endpoint: 185.107.56.76:51820
  allowed ips: 0.0.0.0/0, ::/0
  latest handshake: 43 seconds ago
  transfer: 44.56 KiB received, 18.46 KiB sent
  persistent keepalive: every 25 seconds

grab endpoint IP from above and try to ping it (remove port).

ping <endpoint>
ping 1.1.1.1
host -t A github.com 1.1.1.1
host -t A protonwire-api.vercel.app 1.1.1.1
host -t A github.com
host -t A protonwire-api.vercel.app
alexispurslane commented 8 months ago

Cool I'll go through this tomorrow if that's okay. We'll get to the bottom of this! 😄

leona commented 8 months ago

I'm also having the same issue. Was working fine earlier today but no joy the past hour.

This fails from within the protonwire container but runs fine on the host machine. host -t A protonwire-api.vercel.app 1.1.1.1 ;; communications error to 1.1.1.1#53: timed out ;; communications error to 1.1.1.1#53: timed out ;; no servers could be reached

Same result when using SKIP_DNS_CONFIG 1 too, but I get a different error from protonwire.

[INFO ] Skipping DNS configuration [INFO ] Verifying connection [ERROR ] curl command exited with 35 [ERROR ] Retry (1/5) after 2 seconds [ERROR ] curl command exited with 35 [ERROR ] Retry (2/5) after 2 seconds

UPDATE Just switched server and its working again. Would it be possible to provide a list of servers and keys to rotate around in-case of this?

Seems to have stopped working again shortly after.

ianhundere commented 7 months ago

figured out the issue on my end...i had multiple containers using the same wireguard private key...i created new keys for each instance and the issue went away.

NWarila commented 4 months ago

For anyone else facing this issue.. make sure you are utilizing the PRIVATE KEY NOT the public key. IDK why it can present itself as a CURL issue, but hey, knowledge is power.