implement auto gateway Ip auto detection #25
@@ -84,7 +84,7 @@ vi /etc/openuf/openuf.conf
|
||||
Example Configuration
|
||||
|
||||
```ini
|
||||
controller_ip = 192.168.1.1 # UniFi controller IP
|
||||
controller_ip = # Empty: use IPv4 default gateway
|
||||
lan_if = br-lan # Default Lan interface Name
|
||||
ufmodel = u6-inwall # emulated model
|
||||
inform_interval = 10 # inform interval
|
||||
@@ -96,6 +96,10 @@ protocol_debug_level = 0 # 0=off, 1=safe response details,
|
||||
|
||||
```
|
||||
|
||||
Set `controller_ip` to a controller IPv4 address or hostname to override
|
||||
autodetection. The automatic mode uses the IPv4 default-route gateway for
|
||||
initial adoption; after adoption, the controller-provided inform URL is kept.
|
||||
|
||||
Daemon settings live in `/etc/openuf/openuf.conf`. Adoption and controller state
|
||||
are persisted separately in `/etc/openuf/state.json`; do not copy that file
|
||||
between devices because it contains the device authentication key.
|
||||
|
||||
+3
-2
@@ -1,6 +1,7 @@
|
||||
# openuf — configuration
|
||||
#
|
||||
# controller_ip: UniFi controller IP address or hostname
|
||||
# controller_ip: UniFi controller IP address or hostname; when empty,
|
||||
# autodetect from the IPv4 default-route gateway
|
||||
# lan_if: primary LAN interface (used for the AP MAC and IP)
|
||||
# ufmodel: emulated model (u6-inwall recommended)
|
||||
# inform_interval: seconds between inform requests (minimum 5)
|
||||
@@ -10,7 +11,7 @@
|
||||
# protocol_debug_level: 0=off, 1=safe response structure,
|
||||
# 2=full decrypted response; may expose credentials
|
||||
|
||||
controller_ip = 10.10.10.1
|
||||
controller_ip =
|
||||
lan_if = br-lan
|
||||
ufmodel = uapg2-ac-lr
|
||||
inform_interval = 10
|
||||
|
||||
+22
-6
@@ -1,11 +1,13 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include "config.h"
|
||||
|
||||
void config_load(openuf_config_t *cfg)
|
||||
{
|
||||
/* Defaults */
|
||||
memset(cfg, 0, sizeof(*cfg));
|
||||
strncpy(cfg->controller_ip, DEFAULT_CONTROLLER_IP, sizeof(cfg->controller_ip) - 1);
|
||||
strncpy(cfg->lan_if, DEFAULT_LAN_IF, sizeof(cfg->lan_if) - 1);
|
||||
strncpy(cfg->ufmodel, DEFAULT_UFMODEL, sizeof(cfg->ufmodel) - 1);
|
||||
@@ -21,15 +23,29 @@ void config_load(openuf_config_t *cfg)
|
||||
|
||||
char line[256];
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
/* Strip newline */
|
||||
char *key, *val, *eq, *end;
|
||||
|
||||
line[strcspn(line, "\r\n")] = '\0';
|
||||
/* Skip comments / empty */
|
||||
if (line[0] == '#' || line[0] == '\0') continue;
|
||||
key = line;
|
||||
while (isspace((unsigned char)*key)) key++;
|
||||
if (*key == '#' || *key == '\0') continue;
|
||||
|
||||
char key[64] = {0}, val[192] = {0};
|
||||
if (sscanf(line, " %63[^= ] = %191s", key, val) != 2) continue;
|
||||
eq = strchr(key, '=');
|
||||
if (!eq) continue;
|
||||
*eq = '\0';
|
||||
end = eq;
|
||||
while (end > key && isspace((unsigned char)end[-1])) *--end = '\0';
|
||||
|
||||
if (!strcmp(key, "controller_ip")) strncpy(cfg->controller_ip, val, sizeof(cfg->controller_ip) - 1);
|
||||
val = eq + 1;
|
||||
while (isspace((unsigned char)*val)) val++;
|
||||
end = val;
|
||||
while (*end && !isspace((unsigned char)*end) && *end != '#') end++;
|
||||
*end = '\0';
|
||||
|
||||
if (!strcmp(key, "controller_ip")) {
|
||||
strncpy(cfg->controller_ip, val, sizeof(cfg->controller_ip) - 1);
|
||||
cfg->controller_ip[sizeof(cfg->controller_ip) - 1] = '\0';
|
||||
}
|
||||
else if (!strcmp(key, "lan_if")) strncpy(cfg->lan_if, val, sizeof(cfg->lan_if) - 1);
|
||||
else if (!strcmp(key, "ufmodel")) strncpy(cfg->ufmodel, val, sizeof(cfg->ufmodel) - 1);
|
||||
else if (!strcmp(key, "inform_interval")) cfg->inform_interval = atoi(val);
|
||||
|
||||
+3
-2
@@ -9,7 +9,7 @@
|
||||
#ifndef ENABLE_LOGGING
|
||||
#define ENABLE_LOGGING 1
|
||||
#endif
|
||||
#define DEFAULT_CONTROLLER_IP "10.10.10.1"
|
||||
#define DEFAULT_CONTROLLER_IP ""
|
||||
#define DEFAULT_LAN_IF "br-lan"
|
||||
#define DEFAULT_UFMODEL "uapg2-ac-lr"
|
||||
#define DEFAULT_INFORM_INTERVAL 10
|
||||
@@ -39,7 +39,8 @@ typedef struct {
|
||||
} openuf_config_t;
|
||||
|
||||
/* Parse /etc/openuf/openuf.conf (simple key=value).
|
||||
* Fills *cfg with defaults first, then overrides from file. */
|
||||
* Fills *cfg with defaults first, then overrides from file.
|
||||
* An empty controller_ip selects default-gateway autodetection. */
|
||||
void config_load(openuf_config_t *cfg);
|
||||
|
||||
#endif /* OPENUF_CONFIG_H */
|
||||
|
||||
+86
-1
@@ -15,6 +15,7 @@
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/route.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
@@ -64,6 +65,54 @@ static int get_ip(const char *iface, char *out, size_t sz)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Find the IPv4 next hop used by the kernel's default route. Prefer the
|
||||
* configured LAN interface when more than one default route exists. */
|
||||
static int get_default_gateway(const char *preferred_iface,
|
||||
char *out, size_t sz)
|
||||
{
|
||||
FILE *f = fopen("/proc/net/route", "r");
|
||||
if (!f) return -1;
|
||||
|
||||
char line[256];
|
||||
char iface[IFNAMSIZ];
|
||||
unsigned long destination, gateway;
|
||||
unsigned int flags, metric;
|
||||
unsigned int best_metric = ~0U;
|
||||
unsigned long best_gateway = 0;
|
||||
int best_preferred = 0;
|
||||
|
||||
/* Skip the column headings. */
|
||||
if (!fgets(line, sizeof(line), f)) {
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
if (sscanf(line, "%15s %lx %lx %x %*u %*u %u %*lx",
|
||||
iface, &destination, &gateway, &flags,
|
||||
&metric) != 5)
|
||||
continue;
|
||||
if (destination != 0 || gateway == 0 ||
|
||||
!(flags & RTF_UP) || !(flags & RTF_GATEWAY))
|
||||
continue;
|
||||
|
||||
int preferred = preferred_iface && preferred_iface[0] &&
|
||||
!strcmp(iface, preferred_iface);
|
||||
if (!best_gateway || preferred > best_preferred ||
|
||||
(preferred == best_preferred && metric < best_metric)) {
|
||||
best_gateway = gateway;
|
||||
best_metric = metric;
|
||||
best_preferred = preferred;
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if (!best_gateway) return -1;
|
||||
|
||||
struct in_addr addr = { .s_addr = (in_addr_t)best_gateway };
|
||||
return inet_ntop(AF_INET, &addr, out, sz) ? 0 : -1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
for (int i = 1; i < argc-1; i++)
|
||||
@@ -105,9 +154,31 @@ int main(int argc, char *argv[])
|
||||
LOG("Initial device state: adopted=%d, authkey=%.8s...", state.adopted,
|
||||
state.authkey[0] ? state.authkey : "DEFAULT");
|
||||
|
||||
if (!state.adopted || !state.inform_url[0])
|
||||
/*
|
||||
* A configured controller is an explicit override, including after
|
||||
* adoption. With an empty setting, discover the initial controller from
|
||||
* the default-route gateway and then preserve controller-issued state.
|
||||
*/
|
||||
if (cfg.controller_ip[0]) {
|
||||
snprintf(state.inform_url, sizeof(state.inform_url),
|
||||
"http://%s:%d%s", cfg.controller_ip, INFORM_PORT, INFORM_PATH);
|
||||
LOG("Using configured controller override: %s", cfg.controller_ip);
|
||||
} else if (!state.adopted || !state.inform_url[0]) {
|
||||
char controller_ip[INET_ADDRSTRLEN] = {0};
|
||||
if (get_default_gateway(cfg.lan_if, controller_ip,
|
||||
sizeof(controller_ip)) == 0) {
|
||||
snprintf(state.inform_url, sizeof(state.inform_url),
|
||||
"http://%s:%d%s", controller_ip,
|
||||
INFORM_PORT, INFORM_PATH);
|
||||
LOG("Autodetected controller from default gateway: %s",
|
||||
controller_ip);
|
||||
} else {
|
||||
state.inform_url[0] = '\0';
|
||||
fprintf(stderr,
|
||||
"[openuf] No controller configured and no IPv4 default "
|
||||
"gateway found\n");
|
||||
}
|
||||
}
|
||||
state_save(&state);
|
||||
|
||||
printf("[openuf] Starting model=%-8s MAC=%s IP=%s\n",
|
||||
@@ -180,6 +251,20 @@ int main(int argc, char *argv[])
|
||||
last_inform = now;
|
||||
LOG("Sending inform");
|
||||
|
||||
/* The default route may appear after the service starts. */
|
||||
if (!cfg.controller_ip[0] && !state.inform_url[0]) {
|
||||
char controller_ip[INET_ADDRSTRLEN] = {0};
|
||||
if (get_default_gateway(cfg.lan_if, controller_ip,
|
||||
sizeof(controller_ip)) == 0) {
|
||||
snprintf(state.inform_url, sizeof(state.inform_url),
|
||||
"http://%s:%d%s", controller_ip,
|
||||
INFORM_PORT, INFORM_PATH);
|
||||
LOG("Autodetected controller after startup: %s",
|
||||
controller_ip);
|
||||
state_save(&state);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update IP each cycle */
|
||||
char new_ip[64] = {0};
|
||||
if (get_ip(cfg.lan_if, new_ip, sizeof(new_ip)) == 0 ||
|
||||
|
||||
Reference in New Issue
Block a user