Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proxy connect to hostname vs IP #47

Open
snarl817 opened this issue Sep 16, 2023 · 6 comments
Open

Proxy connect to hostname vs IP #47

snarl817 opened this issue Sep 16, 2023 · 6 comments

Comments

@snarl817
Copy link

Why does the PW_HOST setting in the env file have to be an IP address? I tried setting it to the hostname of the Gateway, but the container complains that it can't connect. Why would I want to use the hostname? If my Access Point reboots for an update, the gateway disconnects and falls back to the ethernet connection...which has a DIFFERENT IP address. Which means that the dashboard isn't getting any data. By specifying a hostname instead of an IP address, the proxy will ALWAYS be able to connect to the gateway, regardless of if it's connected via WiFi or ethernet.

@jamesescott
Copy link

jamesescott commented Sep 16, 2023 via email

@jasonacox
Copy link
Owner

There isn't anything in the pypowerwall code or the proxy that would prohibit you from using a hostname. However, if you are running it in a container, your container environment (e.g. docker run) must allow it to to do the lookup (e.g. DNS query).

As @jamesescott mentioned it would be good to know how you are setting up your DNS record for your Powerwall. I haven't done that and use a pinned/reserved DHCP IP address for my Powerwall (both for my hardwired ethernet connection and WiFi). I would recommend that path. Most routers are able to do IP reservation so the address is always the same.

@snarl817
Copy link
Author

I'm running dhcpd alongside bind. When the Gateway switches interfaces, it sends a DHCP request and gets assigned an address from the lease file. .72 for wired ethernet, and .73 for WiFi. The hostname follows the active interface IP address, and IS resolvable from a utility container on the same docker host, but ONLY if I specify the FQDN. When I tried using the hostname the first time, I used the FQDN. It makes me wonder if there's something in the network config for the Powerwall Dashboard stack that isn't playing nicely with DNS forwarding.

I'll need to play with it...maybe pull the image to a secondary docker host to see if I can get it to work with a hostname instead of an IP. Maybe install bind-utils to check name resolution from inside the container.

@snarl817
Copy link
Author

snarl817 commented Sep 18, 2023

This looks to be a problem with SSL.

Here's the error I get when I tell it to use the FQDN:

 Traceback (most recent call last):
   File "/usr/local/lib/python3.10/site-packages/urllib3/connectionpool.py", line 467, in _make_request
     self._validate_conn(conn)
   File "/usr/local/lib/python3.10/site-packages/urllib3/connectionpool.py", line 1092, in _validate_conn
     conn.connect()  
   File "/usr/local/lib/python3.10/site-packages/urllib3/connection.py", line 635, in connect 
     sock_and_verified = _ssl_wrap_socket_and_match_hostname(
   File "/usr/local/lib/python3.10/site-packages/urllib3/connection.py", line 774, in _ssl_wrap_socket_and_match_hostname
     ssl_sock = ssl_wrap_socket(
   File "/usr/local/lib/python3.10/site-packages/urllib3/util/ssl_.py", line 459, in ssl_wrap_socket 
     ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls, server_hostname)
   File "/usr/local/lib/python3.10/site-packages/urllib3/util/ssl_.py", line 503, in _ssl_wrap_socket_impl
     return ssl_context.wrap_socket(sock, server_hostname=server_hostname)
   File "/usr/local/lib/python3.10/ssl.py", line 513, in wrap_socket
     return self.sslsocket_class._create(
   File "/usr/local/lib/python3.10/ssl.py", line 1071, in _create
     self.do_handshake()
   File "/usr/local/lib/python3.10/ssl.py", line 1342, in do_handshake 
     self._sslobj.do_handshake()
 ssl.SSLEOFError: [SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol (_ssl.c:1007)

For some reason it cannot establish an SSL connection to the gateway via FQDN. Out of curiosity, I used openssl to try and pull the cert chain from the gateway. When using the hostname, I got the following error:

❯ openssl s_client -connect ${GATEWAY_HOST}:443 -showcerts
CONNECTED(00000003)
804B6A72307F0000:error:0A000126:SSL routines:ssl3_read_n:unexpected eof while reading:ssl/record/rec_layer_s3.c:320:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 352 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)

So, it connects and validates the cert, but can't pull a cert chain.

If I specify the IP Address, I get the cert chain. Of note, in the cert chain, the SAN contains "teg":
X509v3 Subject Alternative Name:
DNS:teg, DNS:powerwall, DNS:powerpack, IP Address:192.168.90.1, IP Address:192.168.90.2, IP Address:192.168.91.1

Let me try adding a CNAME to my DNS.

@jasonacox
Copy link
Owner

Interesting! The Powerwall presents an self-signed cert which requires any client to ignore the warning. But since you are assigning an arbitrary DNS name to it, it seems that the https Connection Pool client sees that as a hard fail (unable to authenticate). I'll need to research that. We have verify=False in the actual request, but I suspect this may require a change to the connection pooling.

if self.poolmaxsize > 0:
# Create session object for http connection re-use
self.session = requests.Session()
a = requests.adapters.HTTPAdapter(pool_maxsize=self.poolmaxsize)
self.session.mount('https://', a)
else:
# Disable http persistent connections
self.session = requests

A way to test that would be to disable connection pooling by adding this environmental setting for the pypowerwall container:

PW_POOL_MAXSIZE=0

@snarl817
Copy link
Author

I disabled connection pooling, but still get the same error about the protocol violation.
So, it should be noted that this isn't an arbitrary hostname: this is the hostname the gateway has assigned itself. The hostname is attached to the DHCP request, so when the gateway registers itself with the network, that hostname gets pushed into DNS.

There must have been a firmware update recently that changed the network on the gateway...it USED to be that both the WiFi and ethernet ports were active at the same time - I could login to the admin interface using either IP, and DNS would return the most recent registered IP address. Now, if you login and tell the gateway to connect to WiFi, the ethernet interface shuts off. I mean, I KIND of understand why: linux does NOT like having multiple interfaces on the same subnet.

If you feel like testing other solutions, you can obtain this hostname by logging into the gateway, clicking on Summary, and looking at the gateway name. Add it to /etc/hosts with the IP for your gateway, and try pointing the proxy at the hostname instead of IP address (assuming that your router doesn't run it's own DNS alongside DHCP).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants