[freeboxos] Add VPN Server monitoring (#19669)

* Adding VPN Server monitoring

Signed-off-by: gael@lhopital.org <gael@lhopital.org>
This commit is contained in:
Gaël L'hopital
2025-12-13 00:55:52 +01:00
committed by GitHub
parent 76e316f978
commit 21f561d4d4
10 changed files with 250 additions and 7 deletions
@@ -212,6 +212,18 @@ The following channels are supported:
| revolution, delta | connection-status | rate-down | Number:DataTransferRate | R | Current download rate |
| revolution, delta | connection-status | bytes-up | Number:DataAmount | R | Total data uploaded since last restart |
| revolution, delta | connection-status | bytes-down | Number:DataAmount | R | Total data downloaded since last restart |
| revolution, delta | wireguard | state | String | R | Current state of the VPN Server |
| revolution, delta | wireguard | connections | Number | R | Number of clients connected to the server |
| revolution, delta | wireguard | auth-connections | Number | R | Number of authenticated clients connected to the server |
| revolution, delta | pptp | state | String | R | Current state of the VPN Server |
| revolution, delta | pptp | connections | Number | R | Number of clients connected to the server |
| revolution, delta | pptp | auth-connections | Number | R | Number of authenticated clients connected to the server |
| revolution, delta | openvpn-routed | state | String | R | Current state of the VPN Server |
| revolution, delta | openvpn-routed | connections | Number | R | Number of clients connected to the server |
| revolution, delta | openvpn-routed | auth-connections | Number | R | Number of authenticated clients connected to the server |
| revolution, delta | openvpn-bridge | state | String | R | Current state of the VPN Server |
| revolution, delta | openvpn-bridge | connections | Number | R | Number of clients connected to the server |
| revolution, delta | openvpn-bridge | auth-connections | Number | R | Number of authenticated clients connected to the server |
| active-player, player | player-actions | key-code | String | W | Simulates pushing a remote control button |
| active-player | player-status | player-status | String | R | Status of the Freebox TV player |
| active-player | player-status | package | String | R | Name of the package currently active on the player |
@@ -155,6 +155,12 @@ public class FreeboxOsBindingConstants {
// Virtual machine channels
public static final String STATUS = "status";
// VPN Server channel groups
public static final String PPTP = "pptp";
public static final String OPENVPN_ROUTED = "openvpn-routed";
public static final String OPENVPN_BRIDGE = "openvpn-bridge";
public static final String WIREGUARD = "wireguard";
// Repeater channels
public static final String LED = "led";
public static final String HOST_COUNT = "host-count";
@@ -177,6 +183,11 @@ public class FreeboxOsBindingConstants {
// Home channels
public static final String TIMESTAMP_POSTFIX = "-timestamp";
// VPN Server channels
public static final String VPN_STATE = "state";
public static final String VPN_CONNECTIONS = "connections";
public static final String VPN_AUTHENTICATED = "auth-connections";
public static final String KEYFOB_ENABLE = "enable";
public static final String KEYFOB_PUSHED = "pushed";
public static final String KEYFOB_PUSHED_UPDATE = KEYFOB_PUSHED + TIMESTAMP_POSTFIX;
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2010-2025 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.freeboxos.internal.api.rest;
import java.time.ZonedDateTime;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.freeboxos.internal.api.FreeboxException;
import org.openhab.binding.freeboxos.internal.api.Response;
/**
* The {@link VpnServerManager} is the Java class used to handle api requests related to
* VPN Server monitoring
*
* @author Gaël L'hopital - Initial contribution
*/
@NonNullByDefault
public class VpnServerManager extends ListableRest<VpnServerManager.VpnServer, VpnServerManager.VpnServerResponse> {
private static final String PATH = "vpn";
private static final String CONNECTION_SUBPATH = "connection";
public enum ServerType {
IPSEC,
PPTP,
OPENVPN,
WIREGUARD
}
public enum ServerState {
STOPPED,
STARTING,
STARTED,
STOPPING,
ERROR
}
public static record VpnServer(ServerState state, ServerType type, String name, int connectionCount,
int authConnectionCount) {
}
public static record VpnConnection(//
long rxBytes, // received bytes
long txBytes, // transmitted bytes
boolean authenticated, // is the connection authenticated
String user, // user login
String id, // connection id
String vpn, // related VPN server id
String srcIp, // connection source IP address
String localIp, // attributed IP address from VPN address pool
ZonedDateTime authTime // timestamp of the authentication
) {
}
protected class VpnServerResponse extends Response<VpnServer> {
}
protected class VpnConnectionsResponse extends Response<VpnConnection> {
}
public VpnServerManager(FreeboxOsSession session) throws FreeboxException {
super(session, LoginManager.Permission.NONE, VpnServerResponse.class, session.getUriBuilder().path(PATH));
}
public List<VpnConnection> getVpnConnections() throws FreeboxException {
return get(VpnConnectionsResponse.class, CONNECTION_SUBPATH);
}
}
@@ -34,8 +34,6 @@ import org.openhab.core.thing.Thing;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link HomeNodeHandler} is the base class for handler of home node things.
@@ -44,7 +42,6 @@ import org.slf4j.LoggerFactory;
*/
@NonNullByDefault
public abstract class HomeNodeHandler extends ApiConsumerHandler {
private final Logger logger = LoggerFactory.getLogger(HomeNodeHandler.class);
public HomeNodeHandler(Thing thing) {
super(thing);
@@ -15,9 +15,9 @@ package org.openhab.binding.freeboxos.internal.handler;
import static org.openhab.binding.freeboxos.internal.FreeboxOsBindingConstants.*;
import static org.openhab.core.library.unit.Units.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -42,6 +42,7 @@ import org.openhab.binding.freeboxos.internal.api.rest.SambaManager.Samba;
import org.openhab.binding.freeboxos.internal.api.rest.SystemManager;
import org.openhab.binding.freeboxos.internal.api.rest.SystemManager.Config;
import org.openhab.binding.freeboxos.internal.api.rest.UPnPAVManager;
import org.openhab.binding.freeboxos.internal.api.rest.VpnServerManager;
import org.openhab.binding.freeboxos.internal.api.rest.WifiManager;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.SIUnits;
@@ -63,7 +64,7 @@ import org.slf4j.LoggerFactory;
*/
@NonNullByDefault
public class ServerHandler extends ApiConsumerHandler implements FreeDeviceIntf {
private static final BigDecimal HUNDRED = BigDecimal.valueOf(100);
private static final Set<String> VPN_SERVERS = Set.of(PPTP, OPENVPN_ROUTED, OPENVPN_BRIDGE, WIREGUARD);
private final Logger logger = LoggerFactory.getLogger(ServerHandler.class);
private final ChannelUID eventChannelUID;
@@ -71,6 +72,7 @@ public class ServerHandler extends ApiConsumerHandler implements FreeDeviceIntf
private long uptime = -1;
private boolean tryConfigureMediaSink = true;
private Set<String> vpnConnections = new HashSet<>();
public ServerHandler(Thing thing) {
super(thing);
@@ -129,6 +131,7 @@ public class ServerHandler extends ApiConsumerHandler implements FreeDeviceIntf
logger.debug("Polling server state...");
fetchConnectionStatus();
fetchSystemConfig();
fetchVpnStatus();
if (anyChannelLinked(GROUP_ACTIONS, Set.of(WIFI_STATUS))) {
updateChannelOnOff(GROUP_ACTIONS, WIFI_STATUS, getManager(WifiManager.class).getStatus());
@@ -179,6 +182,37 @@ public class ServerHandler extends ApiConsumerHandler implements FreeDeviceIntf
}
}
private void fetchVpnStatus() throws FreeboxException {
var vpnManager = getManager(VpnServerManager.class);
var servers = vpnManager.getDevices();
servers.forEach(vpnServer -> {
var groupName = vpnServer.name().replace("_", "-");
if (VPN_SERVERS.contains(groupName)) {
updateChannelString(groupName, VPN_STATE, vpnServer.state());
updateChannelDecimal(groupName, VPN_CONNECTIONS, vpnServer.connectionCount());
updateChannelDecimal(groupName, VPN_AUTHENTICATED, vpnServer.authConnectionCount());
} else {
logger.warn("Unexpected and VPN server type: {}", groupName);
}
});
var connections = vpnManager.getVpnConnections();
Set<String> currentConnections = new HashSet<>();
connections.forEach(connection -> {
var name = "%s %s:%s".formatted(connection.vpn(), connection.srcIp(), connection.user());
currentConnections.add(name);
if (!vpnConnections.contains(name)) {
triggerChannel(eventChannelUID, "connected %s".formatted(name));
}
});
Set<String> disconnected = new HashSet<>(vpnConnections);
disconnected.removeAll(currentConnections);
disconnected.forEach(c -> triggerChannel(eventChannelUID, "disconnected %s".formatted(c)));
vpnConnections = currentConnections;
}
private void fetchConnectionStatus() throws FreeboxException {
if (anyChannelLinked(GROUP_CONNECTION_STATUS,
Set.of(LINE_STATUS, LINE_TYPE, LINE_MEDIA, IP_ADDRESS, IPV6_ADDRESS, BYTES_UP, BYTES_DOWN, RATE + "-up",
@@ -33,6 +33,10 @@ thing-type.freeboxos.dect.channel.gain-rx.label = Gain RX
thing-type.freeboxos.dect.channel.gain-tx.label = Gain TX
thing-type.freeboxos.delta.label = Freebox Delta
thing-type.freeboxos.delta.description = Provides various informations regarding the status of the Freebox Delta Server
thing-type.freeboxos.delta.group.openvpn-bridge.label = OpenVPN Bridged VPN
thing-type.freeboxos.delta.group.openvpn-routed.label = OpenVPN Routed VPN
thing-type.freeboxos.delta.group.pptp.label = PPTP VPN
thing-type.freeboxos.delta.group.wireguard.label = Wireguard VPN
thing-type.freeboxos.freeplug.label = Freeplug
thing-type.freeboxos.freeplug.description = Ethernet / CPL gateway
thing-type.freeboxos.freeplug.channel.last-seen.label = Last Activity
@@ -60,6 +64,10 @@ thing-type.freeboxos.repeater.label = Wifi Repeater
thing-type.freeboxos.repeater.description = Provides informations and control over a Wifi Repeater
thing-type.freeboxos.revolution.label = Freebox Revolution
thing-type.freeboxos.revolution.description = Provides various informations regarding the status of the Freebox Revolution Server
thing-type.freeboxos.revolution.group.openvpn-bridge.label = OpenVPN Bridged VPN
thing-type.freeboxos.revolution.group.openvpn-routed.label = OpenVPN Routed VPN
thing-type.freeboxos.revolution.group.pptp.label = PPTP VPN
thing-type.freeboxos.revolution.group.wireguard.label = Wireguard VPN
thing-type.freeboxos.shutter.label = Freebox Home Shutter
thing-type.freeboxos.shutter.description = An IO Home Control shutter configured in your Freebox Server
thing-type.freeboxos.vm.label = Virtual Machine
@@ -202,6 +210,9 @@ channel-group-type.freeboxos.sysinfo.label = System Informations
channel-group-type.freeboxos.sysinfo.channel.ip-address.label = Internal IP
channel-group-type.freeboxos.sysinfo.channel.ip-address.description = Internal IPv4 Address of the Freebox Server
channel-group-type.freeboxos.vmstatus.label = VM Status
channel-group-type.freeboxos.vpn-server.label = VPN Information
channel-group-type.freeboxos.vpn-server.channel.auth-connections.label = Authenticated Connection Count
channel-group-type.freeboxos.vpn-server.channel.auth-connections.description = Number of authenticated clients connected to the server
channel-group-type.freeboxos.wifi.label = Wifi Related Information
channel-group-type.freeboxos.wifi.channel.rate-down.label = Rx Rate
channel-group-type.freeboxos.wifi.channel.rate-down.description = Current RX rate
@@ -233,6 +244,8 @@ channel-type.freeboxos.basic-shutter.label = Shutter
channel-type.freeboxos.basic-shutter.description = Shutter command
channel-type.freeboxos.box-event.label = Server Event
channel-type.freeboxos.box-event.description = Triggers when an event related to the Freebox server has been detected
channel-type.freeboxos.connection-count.label = Connection Count
channel-type.freeboxos.connection-count.description = Number of clients connected to the server
channel-type.freeboxos.connection-status.label = Connection
channel-type.freeboxos.connection-status.description = Connection Status
channel-type.freeboxos.dect-active.label = DECT Enabled
@@ -382,6 +395,13 @@ channel-type.freeboxos.upnpav-status.description = Indicates whether UPnP AV is
channel-type.freeboxos.uptime.label = Uptime
channel-type.freeboxos.uptime.description = Time since last reboot of the equipment
channel-type.freeboxos.uptime.state.pattern = %1$tdd %1$tHh %1$tMm %1$tSs
channel-type.freeboxos.vpn-state.label = Server State
channel-type.freeboxos.vpn-state.description = Current state of the VPN Server
channel-type.freeboxos.vpn-state.state.option.STOPPED = Stopped
channel-type.freeboxos.vpn-state.state.option.STARTING = Starting
channel-type.freeboxos.vpn-state.state.option.STARTED = Started
channel-type.freeboxos.vpn-state.state.option.STOPPING = Stopping
channel-type.freeboxos.vpn-state.state.option.ERROR = Error
channel-type.freeboxos.wifi-host.label = Access Point
channel-type.freeboxos.wifi-status.label = Wifi Enabled
channel-type.freeboxos.wifi-status.description = Indicates whether the wifi network is enabled
@@ -440,6 +440,31 @@
<state readOnly="true"/>
</channel-type>
<channel-type id="connection-count">
<item-type>Number</item-type>
<label>Connection Count</label>
<description>Number of clients connected to the server</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="vpn-state">
<item-type>String</item-type>
<label>Server State</label>
<description>Current state of the VPN Server</description>
<tags>
<tag>Status</tag>
</tags>
<state readOnly="true" pattern="%s">
<options>
<option value="STOPPED">Stopped</option>
<option value="STARTING">Starting</option>
<option value="STARTED">Started</option>
<option value="STOPPING">Stopping</option>
<option value="ERROR">Error</option>
</options>
</state>
</channel-type>
<channel-type id="keyfob-enable">
<item-type>Switch</item-type>
<label>Keyfob Enabled</label>
@@ -12,6 +12,18 @@
<label>Fans</label>
</channel-group-type>
<channel-group-type id="vpn-server">
<label>VPN Information</label>
<channels>
<channel id="state" typeId="vpn-state"/>
<channel id="connections" typeId="connection-count"/>
<channel id="auth-connections" typeId="connection-count">
<label>Authenticated Connection Count</label>
<description>Number of authenticated clients connected to the server</description>
</channel>
</channels>
</channel-group-type>
<channel-group-type id="sysinfo">
<label>System Informations</label>
<channels>
@@ -23,10 +23,22 @@
<channel-group typeId="connection-status" id="connection-status"/>
<channel-group typeId="ftth" id="ftth"/>
<channel-group typeId="xdsl" id="xdsl"/>
<channel-group typeId="vpn-server" id="wireguard">
<label>Wireguard VPN</label>
</channel-group>
<channel-group typeId="vpn-server" id="openvpn-bridge">
<label>OpenVPN Bridged VPN</label>
</channel-group>
<channel-group typeId="vpn-server" id="openvpn-routed">
<label>OpenVPN Routed VPN</label>
</channel-group>
<channel-group typeId="vpn-server" id="pptp">
<label>PPTP VPN</label>
</channel-group>
</channel-groups>
<properties>
<property name="thingTypeVersion">1</property>
<property name="thingTypeVersion">2</property>
</properties>
<representation-property>macAddress</representation-property>
@@ -41,6 +53,7 @@
<label>Freebox Delta</label>
<description>Provides various informations regarding the status of the Freebox Delta Server</description>
<semantic-equipment-tag>Router</semantic-equipment-tag>
<channel-groups>
<channel-group typeId="sensors" id="sensors"/>
@@ -51,10 +64,22 @@
<channel-group typeId="connection-status" id="connection-status"/>
<channel-group typeId="ftth" id="ftth"/>
<channel-group typeId="xdsl" id="xdsl"/>
<channel-group typeId="vpn-server" id="wireguard">
<label>Wireguard VPN</label>
</channel-group>
<channel-group typeId="vpn-server" id="openvpn-bridge">
<label>OpenVPN Bridged VPN</label>
</channel-group>
<channel-group typeId="vpn-server" id="openvpn-routed">
<label>OpenVPN Routed VPN</label>
</channel-group>
<channel-group typeId="vpn-server" id="pptp">
<label>PPTP VPN</label>
</channel-group>
</channel-groups>
<properties>
<property name="thingTypeVersion">1</property>
<property name="thingTypeVersion">2</property>
</properties>
<representation-property>macAddress</representation-property>
@@ -69,6 +69,20 @@
</add-channel>
</instruction-set>
<instruction-set targetVersion="2">
<add-channel id="state" groupIds="wireguard,openvpn-bridge,openvpn-routed,pptp">
<type>freeboxos:vpn-state</type>
</add-channel>
<add-channel id="connections" groupIds="wireguard,openvpn-bridge,openvpn-routed,pptp">
<type>freeboxos:connection-count</type>
</add-channel>
<add-channel id="auth-connections" groupIds="wireguard,openvpn-bridge,openvpn-routed,pptp">
<type>freeboxos:connection-count</type>
<label>Authenticated Connection Count</label>
<description>Number of authenticated clients connected to the server</description>
</add-channel>
</instruction-set>
</thing-type>
<thing-type uid="freeboxos:revolution">
@@ -114,5 +128,19 @@
</add-channel>
</instruction-set>
<instruction-set targetVersion="2">
<add-channel id="state" groupIds="wireguard,openvpn-bridge,openvpn-routed,pptp">
<type>freeboxos:vpn-state</type>
</add-channel>
<add-channel id="connections" groupIds="wireguard,openvpn-bridge,openvpn-routed,pptp">
<type>freeboxos:connection-count</type>
</add-channel>
<add-channel id="auth-connections" groupIds="wireguard,openvpn-bridge,openvpn-routed,pptp">
<type>freeboxos:connection-count</type>
<label>Authenticated Connection Count</label>
<description>Number of authenticated clients connected to the server</description>
</add-channel>
</instruction-set>
</thing-type>
</update:update-descriptions>