travisghansen / hass-opnsense

OPNsense integration with Home Assistant
Apache License 2.0
218 stars 29 forks source link

[Bug]: OpenVPN sensors never show anything #264

Closed jesmak closed 1 week ago

jesmak commented 1 week ago

What happened?

Hello. So this has never worked for me, but I finally decided to do some digging. I have two OpenVPN configurations set up in my OPNsense-system. One is a site-to-site VPN which is basically always on, one is a road warrior configuration which I sometimes use on the road with my phone. The integration properly creates sensors for both of these (total bytes received, total bytes received kb/s, total bytes sent, total bytes sent kb/s and connected client count), but the values are always 0 except for the client counts which are always unavailable. I enabled debug logging and could see relevant logging there to retrieve the data (post requests to two URLs). I opened the URLs manually and could see that there is actual data there (I will paste the data to relevant logs section). It seems as though the integration just doesn't use it.

hass-opnsense Version

0.3.5

OPNsense Firmware

24.7.6-amd64

Home Assistant Version

2024.10.2

Relevant logs

From the debug log:

2024-10-15 08:58:32.302 DEBUG (MainThread) [custom_components.opnsense.pyopnsense] [post] url: https://opnsense.localdomain:8443/api/openvpn/export/providers
2024-10-15 08:58:32.302 DEBUG (MainThread) [custom_components.opnsense.pyopnsense] [post] payload: None
2024-10-15 08:58:32.402 DEBUG (MainThread) [custom_components.opnsense.pyopnsense] [post] Response 200: OK
2024-10-15 08:58:32.402 DEBUG (MainThread) [custom_components.opnsense.pyopnsense] [post] url: https://opnsense.localdomain:8443/api/openvpn/service/searchSessions
2024-10-15 08:58:32.402 DEBUG (MainThread) [custom_components.opnsense.pyopnsense] [post] payload: None
2024-10-15 08:58:32.552 DEBUG (MainThread) [custom_components.opnsense.pyopnsense] [post] Response 200: OK

Actual contents (sensitive data redacted) of https://opnsense.localdomain:8443/api/openvpn/export/providers:

{"1":{"name":"XXXXXXUDP:XXXX","mode":"server_tls_user","vpnid":"1","hostname":"XXXXXX","template":"PlainOpenVPN","local_port":"XXXX","random_local_port":"1","validate_server_cn":"1","cryptoapi":null,"auth_nocache":null,"plain_config":null},"2":{"name":"XXXXXXX UDP:XXXX","mode":"server_tls_user","vpnid":"2","hostname":"XXXXXX","template":"PlainOpenVPN","local_port":"XXXX","random_local_port":"1","validate_server_cn":"1","cryptoapi":null,"auth_nocache":null,"plain_config":null}}

Actual contents (sensitive data redacted) of https://opnsense.localdomain:8443/api/openvpn/service/searchSessions: 

{"total":2,"rowCount":2,"current":1,"rows":[{"status":"ok","type":"server","id":"1_XXX.XXX.XXX.XXX:57696","description":"XXXXXX","common_name":"XXXXXX","real_address":"XXX.XXX.XXX.XXX:57696","virtual_address":"XXX.XXX.XXX.XXX","virtual_ipv6_address":"","bytes_received":"72073184066","bytes_sent":"2682504890","connected_since":"2024-10-13 11:55:25","connected_since__time_t_":"1728809725","username":"XXXXXXX","client_id":"3","peer_id":"0","data_channel_cipher":"AES-256-GCM","is_client":true},{"status":"ok","type":"server","id":"2_XXX.XXX.XXX.XXX:60130","description":"Road warrior","common_name":"XXXXX","real_address":"XXX.XXX.XXX.XXX:60130","virtual_address":"XXX.XXX.XXX.XXX","virtual_ipv6_address":"","bytes_received":"8436","bytes_sent":"7953","connected_since":"2024-10-15 08:59:16","connected_since__time_t_":"1728971956","username":"jesmak","client_id":"0","peer_id":"0","data_channel_cipher":"AES-256-GCM","is_client":true}]}

Additional Details

No response

jesmak commented 1 week ago

Just realized that 0.3.6 was released yesterday, so tested with that too but the issue remains.

jesmak commented 1 week ago

Looking at init.py, I think this might be the culprit (didn't debug though):

for vpnid, vpn_info in openvpn_info.items():
    vpn: Mapping[str, Any] = {}
    vpn["vpnid"] = vpn_info.get("vpnid", "")
    vpn["name"] = vpn_info.get("name", "")
    total_bytes_recv = 0
    total_bytes_sent = 0
    for connect in connection_info.get("rows", {}):
        if connect.get("id", None) and connect.get("id", None) == vpn.get(
            "vpnid", None
        ):
            total_bytes_recv += self._try_to_int(
                connect.get("bytes_received", 0), 0
            )
            total_bytes_sent += self._try_to_int(
                connect.get("bytes_sent", 0), 0
            )
    vpn["total_bytes_recv"] = total_bytes_recv
    vpn["total_bytes_sent"] = total_bytes_sent
    # Missing connected_client_count
    # vpn["connected_client_count"] =
    openvpn["servers"][vpnid] = vpn

vpnid from /api/openvpn/export/providers is "1", but the relevant id from /api/openvpn/service/searchSessions is "1_IP_ADDRESS:PORT" so the comparison never works. And I guess the unavailable clients count can be explained with the last few lines above :)

jesmak commented 1 week ago

Debugged a bit further and fixed this issue. Created a PR of the fix: #264.

Turns out that the format of the id-field is not the same in every scenario. Values for id-field retrieved from /api/openvpn/service/searchSessions are integers when the VPN-connection is not active, but when the connection is live, the values are strings in format "ID_IP-ADDRESS:PORT". So in the PR I modified the id check to work for both of these scenarios. I also fixed the connected client count that was commented out, by setting the count to the amount of sessions that have a value in connected_since field.

Snuffy2 commented 1 week ago

v0.3.7