implement auto gateway Ip auto detection (#25)

Reviewed-on: #25
implemented #19
This commit was merged in pull request #25.
This commit is contained in:
2026-07-14 19:32:02 +01:00
parent 74de317ecb
commit a08cd30853
5 changed files with 119 additions and 12 deletions
+86 -1
View File
@@ -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 ||