Commit 7dd66d70 authored by venaas's avatar venaas Committed by venaas
Browse files

now changed to allow prefix/prefixlen for host

git-svn-id: https://svn.testnett.uninett.no/radsecproxy/trunk@159 e88ac4ed-0b26-0410-9574-a7f39faa03bf
parent 64564a6f
...@@ -52,12 +52,40 @@ void *list_shift(struct list *list) { ...@@ -52,12 +52,40 @@ void *list_shift(struct list *list) {
node = list->first; node = list->first;
list->first = node->next; list->first = node->next;
if (!list->first)
list->last = NULL;
data = node->data; data = node->data;
free(node); free(node);
return data; return data;
} }
/* removes first entry with matching data pointer */
void list_removedata(struct list *list, void *data) {
struct list_node *node, *t;
if (!list->first)
return;
node = list->first;
if (node->data == data) {
list->first = node->next;
if (!list->first)
list->last = NULL;
free(node);
return;
}
for (; node->next; node = node->next)
if (node->next->data == data) {
t = node->next;
node->next = node->next->next;
if (!node->next) /* we removed the last one */
list->last = node;
free(t);
return;
}
}
/* returns first node */ /* returns first node */
struct list_node *list_first(struct list *list) { struct list_node *list_first(struct list *list) {
return list->first; return list->first;
......
...@@ -19,6 +19,9 @@ int list_push(struct list *list, void *data); ...@@ -19,6 +19,9 @@ int list_push(struct list *list, void *data);
/* removes first entry from list and returns data */ /* removes first entry from list and returns data */
void *list_shift(struct list *list); void *list_shift(struct list *list);
/* removes first entry with matching data pointer */
void list_removedata(struct list *list, void *data);
/* returns first node */ /* returns first node */
struct list_node *list_first(struct list *list); struct list_node *list_first(struct list *list);
......
...@@ -132,16 +132,60 @@ static int verify_cb(int ok, X509_STORE_CTX *ctx) { ...@@ -132,16 +132,60 @@ static int verify_cb(int ok, X509_STORE_CTX *ctx) {
int resolvepeer(struct clsrvconf *conf, int ai_flags) { int resolvepeer(struct clsrvconf *conf, int ai_flags) {
struct addrinfo hints, *addrinfo; struct addrinfo hints, *addrinfo;
char *slash, *s;
int plen;
slash = conf->host ? strchr(conf->host, '/') : NULL;
if (slash) {
s = slash + 1;
if (!*s) {
debug(DBG_WARN, "resolvepeer: prefix length must be specified after the / in %s", conf->host);
return 0;
}
for (; *s; s++)
if (*s < '0' || *s > '9') {
debug(DBG_WARN, "resolvepeer: %s in %s is not a valid prefix length", slash + 1, conf->host);
return 0;
}
plen = atoi(slash + 1);
if (plen < 0 || plen > 128) {
debug(DBG_WARN, "resolvepeer: %s in %s is not a valid prefix length", slash + 1, conf->host);
return 0;
}
*slash = '\0';
}
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
hints.ai_socktype = (conf->type == 'T' ? SOCK_STREAM : SOCK_DGRAM); hints.ai_socktype = (conf->type == 'T' ? SOCK_STREAM : SOCK_DGRAM);
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
hints.ai_flags = ai_flags; hints.ai_flags = ai_flags;
if (slash)
hints.ai_flags |= AI_NUMERICHOST;
if (getaddrinfo(conf->host, conf->port, &hints, &addrinfo)) { if (getaddrinfo(conf->host, conf->port, &hints, &addrinfo)) {
debug(DBG_WARN, "resolvepeer: can't resolve %s port %s", conf->host, conf->port); debug(DBG_WARN, "resolvepeer: can't resolve %s port %s", conf->host, conf->port);
return 0; return 0;
} }
if (slash) {
*slash = '/';
switch (addrinfo->ai_family) {
case AF_INET:
if (plen > 32) {
debug(DBG_WARN, "resolvepeer: prefix length must be <= 32 in %s", conf->host);
freeaddrinfo(addrinfo);
return 0;
}
break;
case AF_INET6:
break;
default:
debug(DBG_WARN, "resolvepeer: prefix must be IPv4 or IPv6 in %s", conf->host);
freeaddrinfo(addrinfo);
return 0;
}
conf->prefixlen = plen;
} else
conf->prefixlen = 255;
if (conf->addrinfo) if (conf->addrinfo)
freeaddrinfo(conf->addrinfo); freeaddrinfo(conf->addrinfo);
conf->addrinfo = addrinfo; conf->addrinfo = addrinfo;
...@@ -187,7 +231,19 @@ int bindtoaddr(struct addrinfo *addrinfo) { ...@@ -187,7 +231,19 @@ int bindtoaddr(struct addrinfo *addrinfo) {
return -1; return -1;
} }
/* returns the peer with matching address, or NULL */ /* returns 1 if the len first bits are equal, else 0 */
int prefixmatch(void *a1, void *a2, uint8_t len) {
static uint8_t mask[] = { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };
int r, l = len / 8;
if (l && memcmp(a1, a2, l))
return 0;
r = len % 8;
if (!r)
return 1;
return (((uint8_t *)a1)[l] & mask[r]) == (((uint8_t *)a2)[l] & mask[r]);
}
/* returns the config with matching address, or NULL */
/* if conf argument is not NULL, we only check that one */ /* if conf argument is not NULL, we only check that one */
struct clsrvconf *find_conf(char type, struct sockaddr *addr, struct list *confs, struct clsrvconf *conf) { struct clsrvconf *find_conf(char type, struct sockaddr *addr, struct list *confs, struct clsrvconf *conf) {
struct sockaddr_in6 *sa6 = NULL; struct sockaddr_in6 *sa6 = NULL;
...@@ -197,35 +253,55 @@ struct clsrvconf *find_conf(char type, struct sockaddr *addr, struct list *confs ...@@ -197,35 +253,55 @@ struct clsrvconf *find_conf(char type, struct sockaddr *addr, struct list *confs
if (addr->sa_family == AF_INET6) { if (addr->sa_family == AF_INET6) {
sa6 = (struct sockaddr_in6 *)addr; sa6 = (struct sockaddr_in6 *)addr;
if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) {
a4 = (struct in_addr *)&sa6->sin6_addr.s6_addr[12]; a4 = (struct in_addr *)&sa6->sin6_addr.s6_addr[12];
sa6 = NULL;
}
} else } else
a4 = &((struct sockaddr_in *)addr)->sin_addr; a4 = &((struct sockaddr_in *)addr)->sin_addr;
if (conf) { if (conf) {
if (conf->type == type) if (conf->type == type) {
if (!conf->host) /* for now this means match everything */ if (conf->prefixlen == 255) {
return conf; for (res = conf->addrinfo; res; res = res->ai_next)
for (res = conf->addrinfo; res; res = res->ai_next) if ((a4 && res->ai_family == AF_INET &&
if ((a4 && res->ai_family == AF_INET && !memcmp(a4, &((struct sockaddr_in *)res->ai_addr)->sin_addr, 4)) ||
!memcmp(a4, &((struct sockaddr_in *)res->ai_addr)->sin_addr, 4)) || (sa6 && res->ai_family == AF_INET6 &&
(sa6 && res->ai_family == AF_INET6 && !memcmp(&sa6->sin6_addr, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, 16)))
!memcmp(&sa6->sin6_addr, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, 16))) return conf;
} else {
res = conf->addrinfo;
if (res &&
((a4 && res->ai_family == AF_INET &&
prefixmatch(a4, &((struct sockaddr_in *)res->ai_addr)->sin_addr, conf->prefixlen)) ||
(sa6 && res->ai_family == AF_INET6 &&
prefixmatch(&sa6->sin6_addr, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, conf->prefixlen))))
return conf; return conf;
}
}
return NULL; return NULL;
} }
for (entry = list_first(confs); entry; entry = list_next(entry)) { for (entry = list_first(confs); entry; entry = list_next(entry)) {
conf = (struct clsrvconf *)entry->data; conf = (struct clsrvconf *)entry->data;
if (conf->type == type) if (conf->type == type) {
if (!conf->host) /* for now this means match everything */ if (conf->prefixlen == 255) {
return conf; for (res = conf->addrinfo; res; res = res->ai_next)
for (res = conf->addrinfo; res; res = res->ai_next) if ((a4 && res->ai_family == AF_INET &&
if ((a4 && res->ai_family == AF_INET && !memcmp(a4, &((struct sockaddr_in *)res->ai_addr)->sin_addr, 4)) ||
!memcmp(a4, &((struct sockaddr_in *)res->ai_addr)->sin_addr, 4)) || (sa6 && res->ai_family == AF_INET6 &&
(sa6 && res->ai_family == AF_INET6 && !memcmp(&sa6->sin6_addr, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, 16)))
!memcmp(&sa6->sin6_addr, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, 16))) return conf;
} else {
res = conf->addrinfo;
if (res &&
((a4 && res->ai_family == AF_INET &&
prefixmatch(a4, &((struct sockaddr_in *)res->ai_addr)->sin_addr, conf->prefixlen)) ||
(sa6 && res->ai_family == AF_INET6 &&
prefixmatch(&sa6->sin6_addr, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, conf->prefixlen))))
return conf; return conf;
}
}
} }
return NULL; return NULL;
} }
...@@ -244,19 +320,35 @@ struct replyq *newreplyq() { ...@@ -244,19 +320,35 @@ struct replyq *newreplyq() {
return replyq; return replyq;
} }
void addclient(struct clsrvconf *conf) { struct client *addclient(struct clsrvconf *conf) {
if (conf->clients) { struct client *new = malloc(sizeof(struct client));
debug(DBG_ERR, "currently works with just one client per conf");
return; if (!new) {
debug(DBG_ERR, "malloc failed");
return NULL;
} }
conf->clients = malloc(sizeof(struct client));
if (!conf->clients) { if (!conf->clients) {
debug(DBG_ERR, "malloc failed"); conf->clients = list_create();
return; if (!conf->clients) {
debug(DBG_ERR, "malloc failed");
return NULL;
}
} }
memset(conf->clients, 0, sizeof(struct client));
conf->clients->conf = conf; memset(new, 0, sizeof(struct client));
conf->clients->replyq = conf->type == 'T' ? newreplyq() : udp_server_replyq; new->conf = conf;
new->replyq = conf->type == 'T' ? newreplyq() : udp_server_replyq;
list_push(conf->clients, new);
return new;
}
void removeclient(struct client *client) {
if (!client || !client->conf->clients)
return;
list_removedata(client->conf->clients, client);
free(client);
} }
void addserver(struct clsrvconf *conf) { void addserver(struct clsrvconf *conf) {
...@@ -340,12 +432,11 @@ unsigned char *radudpget(int s, struct client **client, struct server **server, ...@@ -340,12 +432,11 @@ unsigned char *radudpget(int s, struct client **client, struct server **server,
if (client && !*client) { if (client && !*client) {
if (!p->clients) if (!p->clients)
addclient(p); *client = addclient(p);
if (!p->clients) { if (!*client) {
free(rad); free(rad);
continue; continue;
} }
*client = p->clients;
} else if (server && !*server) } else if (server && !*server)
*server = p->servers; *server = p->servers;
...@@ -1725,7 +1816,7 @@ void *tlsserverrd(void *arg) { ...@@ -1725,7 +1816,7 @@ void *tlsserverrd(void *arg) {
shutdown(s, SHUT_RDWR); shutdown(s, SHUT_RDWR);
close(s); close(s);
debug(DBG_DBG, "tlsserverrd thread for %s exiting", client->conf->host); debug(DBG_DBG, "tlsserverrd thread for %s exiting", client->conf->host);
client->ssl = NULL; removeclient(client);
pthread_exit(NULL); pthread_exit(NULL);
} }
...@@ -1760,13 +1851,10 @@ int tlslistener() { ...@@ -1760,13 +1851,10 @@ int tlslistener() {
continue; continue;
} }
if (!conf->clients) client = addclient(conf);
addclient(conf);
client = conf->clients;
if (!client || client->ssl) { if (!client) {
if (client) debug(DBG_WARN, "Failed to create new client instance");
debug(DBG_WARN, "Ignoring incoming TLS connection, already have one from this client");
shutdown(snew, SHUT_RDWR); shutdown(snew, SHUT_RDWR);
close(snew); close(snew);
continue; continue;
...@@ -1776,9 +1864,9 @@ int tlslistener() { ...@@ -1776,9 +1864,9 @@ int tlslistener() {
if (pthread_create(&tlsserverth, NULL, tlsserverrd, (void *)client)) { if (pthread_create(&tlsserverth, NULL, tlsserverrd, (void *)client)) {
debug(DBG_ERR, "tlslistener: pthread_create failed"); debug(DBG_ERR, "tlslistener: pthread_create failed");
SSL_free(client->ssl); SSL_free(client->ssl);
removeclient(client);
shutdown(snew, SHUT_RDWR); shutdown(snew, SHUT_RDWR);
close(snew); close(snew);
client->ssl = NULL;
continue; continue;
} }
pthread_detach(tlsserverth); pthread_detach(tlsserverth);
...@@ -2235,11 +2323,6 @@ void confclient_cb(FILE *f, char *block, char *opt, char *val) { ...@@ -2235,11 +2323,6 @@ void confclient_cb(FILE *f, char *block, char *opt, char *val) {
if (!conf->host) if (!conf->host)
conf->host = stringcopy(val, 0); conf->host = stringcopy(val, 0);
if (!strcmp(conf->host, "*")) {
free(conf->host);
conf->host = NULL;
}
if (type && !strcasecmp(type, "udp")) { if (type && !strcasecmp(type, "udp")) {
conf->type = 'U'; conf->type = 'U';
client_udp_count++; client_udp_count++;
...@@ -2259,10 +2342,8 @@ void confclient_cb(FILE *f, char *block, char *opt, char *val) { ...@@ -2259,10 +2342,8 @@ void confclient_cb(FILE *f, char *block, char *opt, char *val) {
if (matchcertattr) if (matchcertattr)
free(matchcertattr); free(matchcertattr);
if (conf->host) { if (!resolvepeer(conf, 0))
if (!resolvepeer(conf, 0)) debugx(1, DBG_ERR, "failed to resolve host %s port %s, exiting", conf->host, conf->port);
debugx(1, DBG_ERR, "failed to resolve host %s port %s, exiting", conf->host, conf->port);
}
if (!conf->secret) { if (!conf->secret) {
if (conf->type == 'U') if (conf->type == 'U')
......
...@@ -82,7 +82,8 @@ struct clsrvconf { ...@@ -82,7 +82,8 @@ struct clsrvconf {
uint8_t statusserver; uint8_t statusserver;
SSL_CTX *ssl_ctx; SSL_CTX *ssl_ctx;
struct addrinfo *addrinfo; struct addrinfo *addrinfo;
struct client *clients; uint8_t prefixlen;
struct list *clients;
struct server *servers; struct server *servers;
}; };
...@@ -90,6 +91,7 @@ struct client { ...@@ -90,6 +91,7 @@ struct client {
struct clsrvconf *conf; struct clsrvconf *conf;
SSL *ssl; SSL *ssl;
struct replyq *replyq; struct replyq *replyq;
struct client *next;
}; };
struct server { struct server {
......
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