Commit 8684bfa2 authored by Alessandro Rubini's avatar Alessandro Rubini

rvlan: support a list of servers

Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent aa679b1e
...@@ -36,11 +36,13 @@ char *prgname; /* argv[0], for my laziness */ ...@@ -36,11 +36,13 @@ char *prgname; /* argv[0], for my laziness */
int verbose; int verbose;
int rvlan_pmask = ~0; int rvlan_pmask = ~0;
int rvlan_change_pending; /* wrsw_vlans must be called globally */ int rvlan_change_pending; /* wrsw_vlans must be called globally */
char *rvlan_radius_servers; /* strdup from config */
char *rvlan_radius_secret; char *rvlan_radius_secret;
unsigned long rvlan_server_fail_nr;
int rvlan_auth_vlan, rvlan_noauth_vlan, rvlan_obey_dotconfig; int rvlan_auth_vlan, rvlan_noauth_vlan, rvlan_obey_dotconfig;
int rvlan_gotsignal; int rvlan_gotsignal;
struct rvlan_radius_server; /* defined later */
struct rvlan_dev { struct rvlan_dev {
char *name; /* Allocated */ char *name; /* Allocated */
int portnr; int portnr;
...@@ -54,6 +56,7 @@ struct rvlan_dev { ...@@ -54,6 +56,7 @@ struct rvlan_dev {
unsigned char mac[ETH_ALEN]; /* Own mac address */ unsigned char mac[ETH_ALEN]; /* Own mac address */
char radbuffer[10240]; char radbuffer[10240];
int radbuffer_size; int radbuffer_size;
struct rvlan_radius_server *server;
struct rvlan_dev *next; struct rvlan_dev *next;
}; };
...@@ -62,6 +65,7 @@ enum fsm_state { ...@@ -62,6 +65,7 @@ enum fsm_state {
RVLAN_DOWN, RVLAN_DOWN,
RVLAN_JUSTUP, RVLAN_JUSTUP,
RVLAN_SNIFF, RVLAN_SNIFF,
RVLAN_RADCLIENT,
RVLAN_AUTH, RVLAN_AUTH,
RVLAN_CONFIG, RVLAN_CONFIG,
RVLAN_CONFIGURED, RVLAN_CONFIGURED,
...@@ -72,6 +76,7 @@ char *fsm_names[] = { ...@@ -72,6 +76,7 @@ char *fsm_names[] = {
[RVLAN_DOWN] = "down", [RVLAN_DOWN] = "down",
[RVLAN_JUSTUP] = "justup", [RVLAN_JUSTUP] = "justup",
[RVLAN_SNIFF] = "sniff", [RVLAN_SNIFF] = "sniff",
[RVLAN_RADCLIENT] = "radclient",
[RVLAN_AUTH] = "auth", [RVLAN_AUTH] = "auth",
[RVLAN_CONFIG] = "config", [RVLAN_CONFIG] = "config",
[RVLAN_CONFIGURED] = "configured", [RVLAN_CONFIGURED] = "configured",
...@@ -98,6 +103,64 @@ int rvlan_mac_is_local(uint8_t *address) ...@@ -98,6 +103,64 @@ int rvlan_mac_is_local(uint8_t *address)
return 0; return 0;
} }
/* Another list: all the servers */
struct rvlan_radius_server {
char *addr;
unsigned long last_failure;
struct rvlan_radius_server *next;
};
struct rvlan_radius_server *servers;
/* Create a list of servers */
int rvlan_server_mklist(char *names)
{
struct rvlan_radius_server *new, *last = NULL;
char *comma;
while (names[0]) {
new = calloc(1, sizeof(*new));
if (!new)
return -1;
comma = strchr(names, ',');
if (comma)
*comma = '\0';
new->addr = strdup(names);
if (comma)
names = comma + 1;
else
names = "";
/* save at the end of the list, to preserve order */
if (last) {
last->next = new;
last = new;
} else {
servers = last = new;
}
if (verbose)
printf("Radius server: \"%s\"\n", new->addr);
}
return 0;
}
/* Report a server failure */
void rvlan_server_failed(struct rvlan_dev *dev)
{
if (dev->server)
dev->server->last_failure = ++rvlan_server_fail_nr;
}
/* Return the best server */
struct rvlan_radius_server *rvlan_server_get(void)
{
struct rvlan_radius_server *s, *best;
for (s = best = servers; s; s = s->next)
if (s->last_failure < best->last_failure)
best = s;
return best;
}
/* Helper for calling the wrs_vlan executable */ /* Helper for calling the wrs_vlan executable */
int rvlan_change_vlan(struct rvlan_dev *dev) int rvlan_change_vlan(struct rvlan_dev *dev)
{ {
...@@ -227,7 +290,14 @@ int rvlan_fsm(struct rvlan_dev *dev, fd_set *rdset) ...@@ -227,7 +290,14 @@ int rvlan_fsm(struct rvlan_dev *dev, fd_set *rdset)
frame[12] << 8 | frame[13], dev->peer_mac); frame[12] << 8 | frame[13], dev->peer_mac);
close(dev->poll_fd); close(dev->poll_fd);
dev->poll_fd = -1; dev->poll_fd = -1;
dev->fsm_state = RVLAN_RADCLIENT;
/* and fall through */
case RVLAN_RADCLIENT:
dev->server = rvlan_server_get();
if (verbose)
printf("dev %s queries server %s\n", dev->name,
dev->server->addr);
/* /*
* Now, fire the radclient process before changing state * Now, fire the radclient process before changing state
*/ */
...@@ -249,9 +319,10 @@ int rvlan_fsm(struct rvlan_dev *dev, fd_set *rdset) ...@@ -249,9 +319,10 @@ int rvlan_fsm(struct rvlan_dev *dev, fd_set *rdset)
dup(pipe1[1]); close(pipe1[1]); dup(pipe1[1]); close(pipe1[1]);
close(STDERR_FILENO); dup(STDOUT_FILENO); close(STDERR_FILENO); dup(STDOUT_FILENO);
/* radclient <IP> auth <SECRET> */ /* radclient <IP> auth <SECRET> */
execlp("radclient", "radclient", execlp("radclient",
rvlan_radius_servers, "auth", "radclient", dev->server->addr,
rvlan_radius_secret, NULL); "auth", rvlan_radius_secret,
NULL);
fprintf(stderr, "%s: exec(): %s\n", fprintf(stderr, "%s: exec(): %s\n",
prgname, strerror(errno)); prgname, strerror(errno));
exit(1); exit(1);
...@@ -330,6 +401,15 @@ int rvlan_fsm(struct rvlan_dev *dev, fd_set *rdset) ...@@ -330,6 +401,15 @@ int rvlan_fsm(struct rvlan_dev *dev, fd_set *rdset)
fclose(f); fclose(f);
} }
} }
/* See if there was a server error */
if (WEXITSTATUS(i) != 0
&& !strncmp(dev->radbuffer, "radclient", 9)) {
rvlan_server_failed(dev);
if (verbose)
printf("%s: server failed\n", dev->name);
dev->fsm_state = RVLAN_RADCLIENT; /* and go back */
break;
}
/* And parse the result */ /* And parse the result */
dev->chosen_vlan = rvlan_noauth_vlan; dev->chosen_vlan = rvlan_noauth_vlan;
...@@ -725,6 +805,7 @@ int main(int argc, char **argv) ...@@ -725,6 +805,7 @@ int main(int argc, char **argv)
int sock; int sock;
char *rvlan_dev_prefix = "wri"; char *rvlan_dev_prefix = "wri";
char *dotconfig = "/wr/etc/dot-config"; char *dotconfig = "/wr/etc/dot-config";
char *servers;
prgname = argv[0]; prgname = argv[0];
verbose = getenv("RVLAN_VERBOSE") != NULL; verbose = getenv("RVLAN_VERBOSE") != NULL;
...@@ -741,7 +822,6 @@ int main(int argc, char **argv) ...@@ -741,7 +822,6 @@ int main(int argc, char **argv)
if (IS_WRS) { if (IS_WRS) {
int i, mask; int i, mask;
char *s; char *s;
char *comma;
i = libwr_cfg_read_file(dotconfig); i = libwr_cfg_read_file(dotconfig);
if (i < 0) { if (i < 0) {
...@@ -784,28 +864,14 @@ int main(int argc, char **argv) ...@@ -784,28 +864,14 @@ int main(int argc, char **argv)
if (s && s[0]=='y') if (s && s[0]=='y')
rvlan_obey_dotconfig = 1; rvlan_obey_dotconfig = 1;
rvlan_radius_servers = libwr_cfg_get("RVLAN_RADIUS_SERVERS"); servers = libwr_cfg_get("RVLAN_RADIUS_SERVERS");
rvlan_radius_secret = libwr_cfg_get("RVLAN_RADIUS_SECRET"); rvlan_radius_secret = libwr_cfg_get("RVLAN_RADIUS_SECRET");
if (!rvlan_radius_servers || !rvlan_radius_secret) { if (!servers || !rvlan_radius_secret) {
fprintf(stderr, "%s: missing dot-config items\n", fprintf(stderr, "%s: missing dot-config items\n",
argv[0]); argv[0]);
exit(1); exit(1);
} }
rvlan_radius_servers = strdup(rvlan_radius_servers); rvlan_server_mklist(servers);
if (!rvlan_radius_servers) {
fprintf(stderr, "%s: strdup(): %s\n",
argv[0], strerror(errno));
exit(1);
}
comma = strchr(rvlan_radius_servers, ',');
if (comma) {
*comma = '\0';
fprintf(stderr, "%s: Warning: using first radius "
"server only (\"%s\")\n", argv[0],
rvlan_radius_servers);
}
if (0)
libwr_cfg_dump(stdout);
} }
/* Create a list of "wr" devices */ /* Create a list of "wr" devices */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment