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 */
int verbose;
int rvlan_pmask = ~0;
int rvlan_change_pending; /* wrsw_vlans must be called globally */
char *rvlan_radius_servers; /* strdup from config */
char *rvlan_radius_secret;
unsigned long rvlan_server_fail_nr;
int rvlan_auth_vlan, rvlan_noauth_vlan, rvlan_obey_dotconfig;
int rvlan_gotsignal;
struct rvlan_radius_server; /* defined later */
struct rvlan_dev {
char *name; /* Allocated */
int portnr;
......@@ -54,6 +56,7 @@ struct rvlan_dev {
unsigned char mac[ETH_ALEN]; /* Own mac address */
char radbuffer[10240];
int radbuffer_size;
struct rvlan_radius_server *server;
struct rvlan_dev *next;
};
......@@ -62,6 +65,7 @@ enum fsm_state {
RVLAN_DOWN,
RVLAN_JUSTUP,
RVLAN_SNIFF,
RVLAN_RADCLIENT,
RVLAN_AUTH,
RVLAN_CONFIG,
RVLAN_CONFIGURED,
......@@ -72,6 +76,7 @@ char *fsm_names[] = {
[RVLAN_DOWN] = "down",
[RVLAN_JUSTUP] = "justup",
[RVLAN_SNIFF] = "sniff",
[RVLAN_RADCLIENT] = "radclient",
[RVLAN_AUTH] = "auth",
[RVLAN_CONFIG] = "config",
[RVLAN_CONFIGURED] = "configured",
......@@ -98,6 +103,64 @@ int rvlan_mac_is_local(uint8_t *address)
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 */
int rvlan_change_vlan(struct rvlan_dev *dev)
{
......@@ -227,7 +290,14 @@ int rvlan_fsm(struct rvlan_dev *dev, fd_set *rdset)
frame[12] << 8 | frame[13], dev->peer_mac);
close(dev->poll_fd);
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
*/
......@@ -249,9 +319,10 @@ int rvlan_fsm(struct rvlan_dev *dev, fd_set *rdset)
dup(pipe1[1]); close(pipe1[1]);
close(STDERR_FILENO); dup(STDOUT_FILENO);
/* radclient <IP> auth <SECRET> */
execlp("radclient", "radclient",
rvlan_radius_servers, "auth",
rvlan_radius_secret, NULL);
execlp("radclient",
"radclient", dev->server->addr,
"auth", rvlan_radius_secret,
NULL);
fprintf(stderr, "%s: exec(): %s\n",
prgname, strerror(errno));
exit(1);
......@@ -330,6 +401,15 @@ int rvlan_fsm(struct rvlan_dev *dev, fd_set *rdset)
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 */
dev->chosen_vlan = rvlan_noauth_vlan;
......@@ -725,6 +805,7 @@ int main(int argc, char **argv)
int sock;
char *rvlan_dev_prefix = "wri";
char *dotconfig = "/wr/etc/dot-config";
char *servers;
prgname = argv[0];
verbose = getenv("RVLAN_VERBOSE") != NULL;
......@@ -741,7 +822,6 @@ int main(int argc, char **argv)
if (IS_WRS) {
int i, mask;
char *s;
char *comma;
i = libwr_cfg_read_file(dotconfig);
if (i < 0) {
......@@ -784,28 +864,14 @@ int main(int argc, char **argv)
if (s && s[0]=='y')
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");
if (!rvlan_radius_servers || !rvlan_radius_secret) {
if (!servers || !rvlan_radius_secret) {
fprintf(stderr, "%s: missing dot-config items\n",
argv[0]);
exit(1);
}
rvlan_radius_servers = strdup(rvlan_radius_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);
rvlan_server_mklist(servers);
}
/* 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