Increased the number of directives allowed in group and user configurations.

This commit is contained in:
Nikos Mavrogiannopoulos
2013-10-28 21:35:47 +01:00
parent 00554b2f28
commit 2480a2cf58
23 changed files with 920 additions and 579 deletions

View File

@@ -16,7 +16,7 @@ CCAN_SOURCES = ccan/build_assert/build_assert.h ccan/check_type/check_type.h \
ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \ ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \
http-parser/http_parser.c ipc.h cookies.c worker-tun.c main-misc.c \ http-parser/http_parser.c ipc.h cookies.c worker-tun.c main-misc.c \
main-config.c \ main-config.c ip-lease.c ip-lease.h \
vpn.h cookies.h tlslib.h http-parser/http_parser.h log.c tun.c tun.h \ vpn.h cookies.h tlslib.h http-parser/http_parser.h log.c tun.c tun.h \
config.c pam.c pam.h worker-resume.c worker.h main-resume.c main.h \ config.c pam.c pam.h worker-resume.c worker.h main-resume.c main.h \
worker-extras.c main-auth.h html.c html.h \ worker-extras.c main-auth.h html.c html.h \

View File

@@ -20,6 +20,9 @@
#include <stdint.h> #include <stdint.h>
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#include <string.h>
#include <vpn.h>
#include <sys/socket.h>
ssize_t force_write(int sockfd, const void *buf, size_t len) ssize_t force_write(int sockfd, const void *buf, size_t len)
{ {
@@ -64,3 +67,12 @@ uint8_t * p = buf;
return len; return len;
} }
int ip_cmp(const struct sockaddr_storage *s1, const struct sockaddr_storage *s2, size_t n)
{
if (((struct sockaddr*)s1)->sa_family == AF_INET) {
return memcmp(SA_IN_P(s1), SA_IN_P(s2), sizeof(struct in_addr));
} else { /* inet6 */
return memcmp(SA_IN6_P(s1), SA_IN6_P(s2), sizeof(struct in6_addr));
}
}

View File

@@ -2,6 +2,7 @@
# define COMMON_H # define COMMON_H
ssize_t force_write(int sockfd, const void *buf, size_t len); ssize_t force_write(int sockfd, const void *buf, size_t len);
ssize_t force_read(int sockfd, void *buf, size_t len); ssize_t force_read(int sockfd, void *buf, size_t len);
int ip_cmp(const struct sockaddr_storage *s1, const struct sockaddr_storage *s2, size_t n);
#endif #endif

391
src/ip-lease.c Normal file
View File

@@ -0,0 +1,391 @@
/*
* Copyright (C) 2013 Nikos Mavrogiannopoulos
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <config.h>
#include <stdbool.h>
#include <stdio.h>
#include <ip-lease.h>
#include <main.h>
#include <common.h>
#include <gnutls/crypto.h>
#include <icmp-ping.h>
#include <arpa/inet.h>
static void bignum_add (uint8_t * num, unsigned size, unsigned step)
{
register int i;
register unsigned tmp, y;
for (i = size-1; i >= 0; i--)
{
tmp = num[i];
num[i] += step;
if (num[i] < tmp)
y = 1;
else
y = 0;
if (y == 0)
break;
}
}
void ip_lease_deinit(struct ip_lease_db_st* db)
{
struct ip_lease_st * cache;
struct htable_iter iter;
cache = htable_first(&db->ht, &iter);
while(cache != NULL) {
free(cache);
cache = htable_next(&db->ht, &iter);
}
htable_clear(&db->ht);
db->entries = 0;
return;
}
static size_t rehash(const void* _e, void* unused)
{
const struct ip_lease_st * e = _e;
return hash_stable_8(&e->rip, e->rip_len, 0);
}
void ip_lease_init(struct ip_lease_db_st* db)
{
htable_init(&db->ht, rehash, NULL);
db->entries = 0;
}
static bool ip_lease_cmp(const void* _c1, void* _c2)
{
const struct ip_lease_st* c1 = _c1;
struct ip_lease_st* c2 = _c2;
if (c1->rip_len == c2->rip_len &&
ip_cmp(&c1->rip, &c2->rip, c2->rip_len) == 0)
return 1;
return 0;
}
static int ip_lease_exists(main_server_st* s, struct sockaddr_storage* ip, size_t sockaddrlen)
{
struct ip_lease_st t;
t.rip_len = sockaddrlen;
memcpy(&t.rip, ip, sizeof(*ip));
if (htable_get(&s->ip_leases.ht, rehash(&t, NULL), ip_lease_cmp, &t) != 0)
return 1;
return 0;
}
#define MAX_IP_TRIES 16
static
int get_ipv4_lease(main_server_st* s, struct proc_st* proc)
{
struct sockaddr_storage tmp, mask, network, rnd;
unsigned i;
unsigned max_loops = MAX_IP_TRIES;
int ret;
const char* c_network, *c_netmask;
char buf[64];
if (proc->config.ipv4_network && proc->config.ipv4_netmask) {
c_network = proc->config.ipv4_network;
c_netmask = proc->config.ipv4_netmask;
} else {
c_network = s->config->network.ipv4;
c_netmask = s->config->network.ipv4_netmask;
}
if (c_network && c_netmask) {
ret =
inet_pton(AF_INET, c_network, SA_IN_P(&network));
if (ret != 1) {
mslog(s, NULL, LOG_ERR, "Error reading IP: %s\n", c_network);
return -1;
}
ret =
inet_pton(AF_INET, c_netmask, SA_IN_P(&mask));
if (ret != 1) {
mslog(s, NULL, LOG_ERR, "Error reading mask: %s\n", c_netmask);
return -1;
}
proc->ipv4 = calloc(1, sizeof(*proc->ipv4));
if (proc->ipv4 == NULL)
return ERR_MEM;
/* mask the network (just in case it is wrong) */
for (i=0;i<sizeof(struct in_addr);i++)
SA_IN_U8_P(&network)[i] &= (SA_IN_U8_P(&mask)[i]);
((struct sockaddr_in*)&network)->sin_family = AF_INET;
((struct sockaddr_in*)&network)->sin_port = 0;
memcpy(&tmp, &network, sizeof(tmp));
((struct sockaddr_in*)&tmp)->sin_family = AF_INET;
((struct sockaddr_in*)&tmp)->sin_port = 0;
((struct sockaddr_in*)&rnd)->sin_family = AF_INET;
((struct sockaddr_in*)&rnd)->sin_port = 0;
do {
if (max_loops == 0) {
mslog(s, proc, LOG_ERR, "Could not figure out a valid IPv4 IP.\n");
ret = ERR_NO_IP;
goto fail;
}
if (max_loops == MAX_IP_TRIES) {
uint32_t t = hash_any(proc->username, strlen(proc->username), 0);
memcpy(SA_IN_U8_P(&rnd), &t, 4);
} else
gnutls_rnd(GNUTLS_RND_NONCE, SA_IN_U8_P(&rnd), sizeof(struct in_addr));
max_loops--;
if (SA_IN_U8_P(&rnd)[3] == 255) /* broadcast */
bignum_add(SA_IN_U8_P(&rnd), sizeof(struct in_addr), 1);
/* Mask the random number with the netmask */
for (i=0;i<sizeof(struct in_addr);i++) {
SA_IN_U8_P(&rnd)[i] &= ~(SA_IN_U8_P(&mask)[i]);
}
SA_IN_U8_P(&rnd)[sizeof(struct in_addr)-1] &= 0xFE;
/* Now add the IP to the masked random number */
for (i=0;i<sizeof(struct in_addr);i++)
SA_IN_U8_P(&rnd)[i] |= (SA_IN_U8_P(&network)[i]);
/* check if it exists in the hash table */
if (ip_lease_exists(s, &rnd, sizeof(struct sockaddr_in)) != 0)
continue;
memcpy(&proc->ipv4->lip, &rnd, sizeof(struct sockaddr_in));
proc->ipv4->lip_len = sizeof(struct sockaddr_in);
/* RIP = LIP + 1 */
memcpy(&tmp, &proc->ipv4->lip, sizeof(struct sockaddr_in));
bignum_add(SA_IN_U8_P(&tmp), sizeof(struct in_addr), 1);
/* check if it exists in the hash table */
if (ip_lease_exists(s, &tmp, sizeof(struct sockaddr_in)) != 0)
continue;
memcpy(&proc->ipv4->rip, &tmp, sizeof(struct sockaddr_in));
proc->ipv4->rip_len = sizeof(struct sockaddr_in);
/* mask the last IP with the netmask */
for (i=0;i<sizeof(struct in_addr);i++)
SA_IN_U8_P(&tmp)[i] &= (SA_IN_U8_P(&mask)[i]);
/* the result should match the network */
if (memcmp(SA_IN_U8_P(&network), SA_IN_U8_P(&tmp), sizeof(struct in_addr)) != 0) {
continue;
}
mslog(s, proc, LOG_DEBUG, "Selected IP: %s\n",
human_addr((void*)&proc->ipv4->lip, proc->ipv4->lip_len, buf, sizeof(buf)));
if (icmp_ping4(s, (void*)&proc->ipv4->lip, (void*)&proc->ipv4->rip) == 0)
break;
} while(1);
}
return 0;
fail:
free(proc->ipv4);
proc->ipv4 = NULL;
return ret;
}
static
int get_ipv6_lease(main_server_st* s, struct proc_st* proc)
{
struct sockaddr_storage tmp, mask, network, rnd;
unsigned i, max_loops = MAX_IP_TRIES;
int ret;
const char* c_network, *c_netmask;
if (proc->config.ipv6_network && proc->config.ipv6_netmask) {
c_network = proc->config.ipv6_network;
c_netmask = proc->config.ipv6_netmask;
} else {
c_network = s->config->network.ipv6;
c_netmask = s->config->network.ipv6_netmask;
}
if (c_network && c_netmask) {
ret =
inet_pton(AF_INET6, c_network, SA_IN6_P(&network));
if (ret != 1) {
mslog(s, NULL, LOG_ERR, "Error reading IP: %s\n", c_network);
return -1;
}
ret =
inet_pton(AF_INET6, c_netmask, SA_IN6_P(&mask));
if (ret != 1) {
mslog(s, NULL, LOG_ERR, "Error reading mask: %s\n", c_netmask);
return -1;
}
proc->ipv6 = calloc(1, sizeof(*proc->ipv6));
if (proc->ipv6 == NULL)
return ERR_MEM;
/* mask the network */
for (i=0;i<sizeof(struct in6_addr);i++)
SA_IN6_U8_P(&network)[i] &= (SA_IN6_U8_P(&mask)[i]);
((struct sockaddr_in6*)&network)->sin6_family = AF_INET6;
((struct sockaddr_in6*)&network)->sin6_port = 0;
memcpy(&tmp, &network, sizeof(tmp));
((struct sockaddr_in6*)&tmp)->sin6_family = AF_INET6;
((struct sockaddr_in6*)&tmp)->sin6_port = AF_INET6;
((struct sockaddr_in6*)&rnd)->sin6_family = AF_INET6;
((struct sockaddr_in6*)&rnd)->sin6_port = AF_INET6;
do {
if (max_loops == 0) {
mslog(s, NULL, LOG_ERR, "Could not figure out a valid IPv6 IP.\n");
ret = ERR_NO_IP;
goto fail;
}
if (max_loops == MAX_IP_TRIES) {
uint32_t t = hash_any(proc->username, strlen(proc->username), 0);
memset(SA_IN6_U8_P(&rnd), 0, sizeof(struct in6_addr));
memcpy(SA_IN6_U8_P(&rnd)+sizeof(struct in6_addr)-5, &t, 4);
} else
gnutls_rnd(GNUTLS_RND_NONCE, SA_IN6_U8_P(&rnd), sizeof(struct in6_addr));
max_loops--;
/* Mask the random number with the netmask */
for (i=0;i<sizeof(struct in6_addr);i++)
SA_IN6_U8_P(&rnd)[i] &= ~(SA_IN6_U8_P(&mask)[i]);
SA_IN6_U8_P(&rnd)[sizeof(struct in6_addr)-1] &= 0xFE;
/* Now add the network to the masked random number */
for (i=0;i<sizeof(struct in6_addr);i++)
SA_IN6_U8_P(&rnd)[i] |= (SA_IN6_U8_P(&network)[i]);
/* check if it exists in the hash table */
if (ip_lease_exists(s, &rnd, sizeof(struct sockaddr_in6)) != 0)
continue;
proc->ipv6->lip_len = sizeof(struct sockaddr_in6);
memcpy(&proc->ipv6->lip, &rnd, proc->ipv6->lip_len);
/* RIP = LIP + 1 */
memcpy(&tmp, &proc->ipv6->lip, proc->ipv6->rip_len);
bignum_add(SA_IN6_U8_P(&tmp), sizeof(struct in6_addr), 1);
/* check if it exists in the hash table */
if (ip_lease_exists(s, &tmp, sizeof(struct sockaddr_in6)) != 0)
continue;
proc->ipv6->rip_len = sizeof(struct sockaddr_in6);
memcpy(&proc->ipv6->rip, &tmp, proc->ipv6->rip_len);
/* mask the last IP with the netmask */
for (i=0;i<sizeof(struct in6_addr);i++)
SA_IN6_U8_P(&tmp)[i] &= (SA_IN6_U8_P(&mask)[i]);
/* the result should match the network */
if (memcmp(SA_IN6_U8_P(&network), SA_IN6_U8_P(&tmp), sizeof(struct in6_addr)) != 0) {
continue;
}
if (icmp_ping6(s, (void*)&proc->ipv6->lip, (void*)&proc->ipv6->rip) == 0)
break;
} while(1);
}
return 0;
fail:
free(proc->ipv6);
proc->ipv6 = NULL;
return ret;
}
int get_ip_leases(main_server_st* s, struct proc_st* proc)
{
int ret;
ret = get_ipv4_lease(s, proc);
if (ret < 0)
return ret;
ret = get_ipv6_lease(s, proc);
if (ret < 0)
return ret;
if (proc->ipv4)
htable_add(&s->ip_leases.ht, rehash(proc->ipv4, NULL), proc->ipv4);
if (proc->ipv6)
htable_add(&s->ip_leases.ht, rehash(proc->ipv6, NULL), proc->ipv6);
if (proc->ipv4 == 0 && proc->ipv6 == 0) {
mslog(s, NULL, LOG_ERR, "No IPv4 or IPv6 addresses are configured. Cannot obtain lease.\n");
return -1;
}
return 0;
}
void remove_ip_leases(main_server_st* s, struct proc_st* proc)
{
if (proc->ipv4) {
htable_del(&s->ip_leases.ht, rehash(proc->ipv4, NULL), proc->ipv4);
free(proc->ipv4);
proc->ipv4 = NULL;
}
if (proc->ipv6) {
htable_del(&s->ip_leases.ht, rehash(proc->ipv6, NULL), proc->ipv6);
free(proc->ipv6);
proc->ipv6 = NULL;
}
}

24
src/ip-lease.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef IP_LEASE_H
# define IP_LEASE_H
#include <vpn.h>
#include <string.h>
#include <sys/socket.h>
#include <ccan/hash/hash.h>
#include <main.h>
struct ip_lease_st {
struct sockaddr_storage rip;
socklen_t rip_len;
struct sockaddr_storage lip;
socklen_t lip_len;
};
void ip_lease_deinit(struct ip_lease_db_st* db);
void ip_lease_init(struct ip_lease_db_st* db);
int get_ip_leases(struct main_server_st* s, struct proc_st* proc);
void remove_ip_leases(struct main_server_st* s, struct proc_st* proc);
#endif

View File

@@ -87,8 +87,7 @@ struct __attribute__ ((__packed__)) cmd_auth_reply_st {
char vname[IFNAMSIZ]; /* interface name */ char vname[IFNAMSIZ]; /* interface name */
char user[MAX_USERNAME_SIZE]; char user[MAX_USERNAME_SIZE];
uint8_t routes_size; /* up to MAX_ROUTES */ /* additional data follow */
/* routes_size routes of cmd_auth_reply_route_st follow */
} ok; } ok;
/* in case of REP_AUTH_MSG */ /* in case of REP_AUTH_MSG */
char msg[MAX_MSG_SIZE]; char msg[MAX_MSG_SIZE];

View File

@@ -61,8 +61,103 @@ void main_auth_init(main_server_st *s)
} }
} }
static int send_str_value_length(main_server_st* s, struct proc_st* proc, char* data)
{
uint8_t len;
int ret;
if (data != NULL) {
len = strlen(data);
ret = force_write(proc->fd, &len, 1);
if (ret < 0)
return ret;
ret = force_write(proc->fd, proc->config.ipv4_dns, len);
if (ret < 0)
return ret;
} else {
len = 0;
ret = force_write(proc->fd, &len, 1);
if (ret < 0)
return ret;
}
return 0;
}
static
int serialize_additional_data(main_server_st* s, struct proc_st* proc)
{
int ret;
unsigned i;
uint8_t len;
/* IPv4 DNS */
if (proc->config.ipv4_dns)
mslog(s, proc, LOG_DEBUG, "sending DNS '%s'", proc->config.ipv4_dns);
ret = send_str_value_length(s, proc, proc->config.ipv4_dns);
if (ret < 0)
return ret;
/* IPv6 DNS */
if (proc->config.ipv6_dns)
mslog(s, proc, LOG_DEBUG, "sending DNS '%s'", proc->config.ipv6_dns);
ret = send_str_value_length(s, proc, proc->config.ipv6_dns);
if (ret < 0)
return ret;
/* IPv4 NBNS */
if (proc->config.ipv4_nbns)
mslog(s, proc, LOG_DEBUG, "sending NBNS '%s'", proc->config.ipv4_nbns);
ret = send_str_value_length(s, proc, proc->config.ipv4_nbns);
if (ret < 0)
return ret;
/* IPv6 NBNS */
if (proc->config.ipv6_nbns)
mslog(s, proc, LOG_DEBUG, "sending NBNS '%s'", proc->config.ipv6_nbns);
ret = send_str_value_length(s, proc, proc->config.ipv6_nbns);
if (ret < 0)
return ret;
/* IPv4 netmask */
if (proc->config.ipv4_netmask)
mslog(s, proc, LOG_DEBUG, "sending netmask '%s'", proc->config.ipv4_netmask);
ret = send_str_value_length(s, proc, proc->config.ipv4_netmask);
if (ret < 0)
return ret;
/* IPv6 netmask */
if (proc->config.ipv6_netmask)
mslog(s, proc, LOG_DEBUG, "sending netmask '%s'", proc->config.ipv6_netmask);
ret = send_str_value_length(s, proc, proc->config.ipv6_netmask);
if (ret < 0)
return ret;
/* routes */
len = proc->config.routes_size;
ret = force_write(proc->fd, &len, 1);
if (ret < 0)
return ret;
for (i=0;i<proc->config.routes_size;i++) {
len = strlen(proc->config.routes[i]);
mslog(s, proc, LOG_DEBUG, "sending route '%s'", proc->config.routes[i]);
ret = force_write(proc->fd, &len, 1);
if (ret < 0)
return ret;
ret = force_write(proc->fd, proc->config.routes[i], len);
if (ret < 0)
return ret;
}
return 0;
}
int send_auth_reply(main_server_st* s, struct proc_st* proc, int send_auth_reply(main_server_st* s, struct proc_st* proc,
cmd_auth_reply_t r, struct group_cfg_st* cfg) cmd_auth_reply_t r)
{ {
struct iovec iov[2]; struct iovec iov[2];
uint8_t cmd[2]; uint8_t cmd[2];
@@ -73,12 +168,11 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc,
} control_un; } control_un;
struct cmd_auth_reply_st resp; struct cmd_auth_reply_st resp;
struct cmsghdr *cmptr; struct cmsghdr *cmptr;
unsigned i;
int ret; int ret;
if (cfg->routes_size > MAX_ROUTES) { if (proc->config.routes_size > MAX_ROUTES) {
mslog(s, proc, LOG_INFO, "Note that the routes sent to the client (%d) exceed the maximum allowed (%d). Truncating.", (int)cfg->routes_size, (int)MAX_ROUTES); mslog(s, proc, LOG_INFO, "Note that the routes sent to the client (%d) exceed the maximum allowed (%d). Truncating.", (int)proc->config.routes_size, (int)MAX_ROUTES);
cfg->routes_size = MAX_ROUTES; proc->config.routes_size = MAX_ROUTES;
} }
memset(&control_un, 0, sizeof(control_un)); memset(&control_un, 0, sizeof(control_un));
@@ -86,7 +180,7 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc,
hdr.msg_iov = iov; hdr.msg_iov = iov;
if (r == REP_AUTH_OK && proc->lease != NULL) { if (r == REP_AUTH_OK && proc->tun_lease.name[0] != 0) {
cmd[0] = AUTH_REP; cmd[0] = AUTH_REP;
iov[0].iov_base = cmd; iov[0].iov_base = cmd;
@@ -96,15 +190,13 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc,
resp.reply = r; resp.reply = r;
memcpy(resp.data.ok.cookie, proc->cookie, COOKIE_SIZE); memcpy(resp.data.ok.cookie, proc->cookie, COOKIE_SIZE);
memcpy(resp.data.ok.session_id, proc->session_id, sizeof(resp.data.ok.session_id)); memcpy(resp.data.ok.session_id, proc->session_id, sizeof(resp.data.ok.session_id));
memcpy(resp.data.ok.vname, proc->lease->name, sizeof(resp.data.ok.vname)); memcpy(resp.data.ok.vname, proc->tun_lease.name, sizeof(resp.data.ok.vname));
memcpy(resp.data.ok.user, proc->username, sizeof(resp.data.ok.user)); memcpy(resp.data.ok.user, proc->username, sizeof(resp.data.ok.user));
iov[1].iov_base = &resp; iov[1].iov_base = &resp;
iov[1].iov_len = sizeof(resp); iov[1].iov_len = sizeof(resp);
hdr.msg_iovlen++; hdr.msg_iovlen++;
resp.data.ok.routes_size = cfg->routes_size;
/* Send the tun fd */ /* Send the tun fd */
hdr.msg_control = control_un.control; hdr.msg_control = control_un.control;
hdr.msg_controllen = sizeof(control_un.control); hdr.msg_controllen = sizeof(control_un.control);
@@ -113,7 +205,7 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc,
cmptr->cmsg_len = CMSG_LEN(sizeof(int)); cmptr->cmsg_len = CMSG_LEN(sizeof(int));
cmptr->cmsg_level = SOL_SOCKET; cmptr->cmsg_level = SOL_SOCKET;
cmptr->cmsg_type = SCM_RIGHTS; cmptr->cmsg_type = SCM_RIGHTS;
memcpy(CMSG_DATA(cmptr), &proc->lease->fd, sizeof(int)); memcpy(CMSG_DATA(cmptr), &proc->tun_lease.fd, sizeof(int));
} else { } else {
cmd[0] = AUTH_REP; cmd[0] = AUTH_REP;
cmd[1] = REP_AUTH_FAILED; cmd[1] = REP_AUTH_FAILED;
@@ -128,55 +220,11 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc,
return ret; return ret;
if (r == REP_AUTH_OK) { if (r == REP_AUTH_OK) {
uint8_t len; ret = serialize_additional_data(s, proc);
if (ret < 0)
if (cfg->ipv4_dns) { return ret;
len = strlen(cfg->ipv4_dns);
mslog(s, proc, LOG_INFO, "sending DNS '%s' with size %d", cfg->ipv4_dns, len);
ret = force_write(proc->fd, &len, 1);
if (ret < 0)
return ret;
ret = force_write(proc->fd, cfg->ipv4_dns, len);
if (ret < 0)
return ret;
} else {
len = 0;
ret = force_write(proc->fd, &len, 1);
if (ret < 0)
return ret;
}
if (cfg->ipv6_dns) {
len = strlen(cfg->ipv6_dns);
mslog(s, proc, LOG_INFO, "sending DNS '%s' with size %d", cfg->ipv6_dns, len);
ret = force_write(proc->fd, &len, 1);
if (ret < 0)
return ret;
ret = force_write(proc->fd, cfg->ipv6_dns, len);
if (ret < 0)
return ret;
} else {
len = 0;
ret = force_write(proc->fd, &len, 1);
if (ret < 0)
return ret;
}
for (i=0;i<cfg->routes_size;i++) {
len = strlen(cfg->routes[i]);
mslog(s, proc, LOG_INFO, "sending route '%s' with size %d", cfg->routes[i], len);
ret = force_write(proc->fd, &len, 1);
if (ret < 0)
return ret;
ret = force_write(proc->fd, cfg->routes[i], len);
if (ret < 0)
return ret;
}
} }
return 0; return 0;
} }

View File

@@ -43,6 +43,12 @@ static struct cfg_options available_options[] = {
{ .name = "route", .type = OPTION_MULTI_LINE }, { .name = "route", .type = OPTION_MULTI_LINE },
{ .name = "ipv4-dns", .type = OPTION_STRING }, { .name = "ipv4-dns", .type = OPTION_STRING },
{ .name = "ipv6-dns", .type = OPTION_STRING }, { .name = "ipv6-dns", .type = OPTION_STRING },
{ .name = "ipv4-nbns", .type = OPTION_STRING },
{ .name = "ipv6-nbns", .type = OPTION_STRING },
{ .name = "ipv4-network", .type = OPTION_STRING },
{ .name = "ipv6-network", .type = OPTION_STRING },
{ .name = "ipv4-netmask", .type = OPTION_STRING },
{ .name = "ipv6-netmask", .type = OPTION_STRING },
}; };
#define READ_RAW_MULTI_LINE(name, s_name, num) \ #define READ_RAW_MULTI_LINE(name, s_name, num) \
@@ -114,6 +120,12 @@ const tOptionValue* val, *prev;
READ_RAW_STRING("ipv4-dns", config->ipv4_dns); READ_RAW_STRING("ipv4-dns", config->ipv4_dns);
READ_RAW_STRING("ipv6-dns", config->ipv6_dns); READ_RAW_STRING("ipv6-dns", config->ipv6_dns);
READ_RAW_STRING("ipv4-nbns", config->ipv4_nbns);
READ_RAW_STRING("ipv6-nbns", config->ipv6_nbns);
READ_RAW_STRING("ipv4-network", config->ipv4_network);
READ_RAW_STRING("ipv6-network", config->ipv6_network);
READ_RAW_STRING("ipv4-netmask", config->ipv4_netmask);
READ_RAW_STRING("ipv6-netmask", config->ipv6_netmask);
optionUnloadNested(pov); optionUnloadNested(pov);

View File

@@ -53,10 +53,10 @@ int fd, ret, e;
struct ifreq ifr; struct ifreq ifr;
const char* name; const char* name;
if (proc->lease == NULL) if (proc->tun_lease.name[0] == 0)
return -1; return -1;
name = proc->lease->name; name = proc->tun_lease.name;
mslog(s, proc, LOG_DEBUG, "setting %s MTU to %u", name, mtu); mslog(s, proc, LOG_DEBUG, "setting %s MTU to %u", name, mtu);
fd = socket(AF_INET, SOCK_STREAM, 0); fd = socket(AF_INET, SOCK_STREAM, 0);
@@ -112,119 +112,12 @@ int send_udp_fd(main_server_st* s, struct proc_st * proc, int fd)
return(sendmsg(proc->fd, &hdr, 0)); return(sendmsg(proc->fd, &hdr, 0));
} }
static void del_additional_config(struct group_cfg_st* config)
{
unsigned i;
for(i=0;i<config->routes_size;i++) {
free(config->routes[i]);
}
free(config->routes);
free(config->ipv4_dns);
free(config->ipv6_dns);
}
static int read_additional_config(main_server_st* s, struct proc_st* proc,
struct group_cfg_st *config)
{
struct group_cfg_st u_cfg;
struct group_cfg_st g_cfg;
char file[_POSIX_PATH_MAX];
int ret;
unsigned i;
memset(config, 0, sizeof(*config));
if (s->config->per_user_dir != NULL) {
snprintf(file, sizeof(file), "%s/%s", s->config->per_user_dir, proc->username);
if (access(file, R_OK) == 0) {
mslog(s, proc, LOG_INFO, "Loading user configuration '%s'", file);
ret = parse_group_cfg_file(s, file, &u_cfg);
if (ret < 0)
return ERR_READ_CONFIG;
if (u_cfg.routes_size > 0) {
config->routes = u_cfg.routes;
config->routes_size = u_cfg.routes_size;
u_cfg.routes = NULL;
u_cfg.routes_size = 0;
}
config->ipv4_dns = u_cfg.ipv4_dns;
u_cfg.ipv4_dns = NULL;
config->ipv6_dns = u_cfg.ipv6_dns;
u_cfg.ipv6_dns = NULL;
del_additional_config(&u_cfg);
} else
mslog(s, proc, LOG_INFO, "No user configuration for '%s'", proc->username);
}
if (s->config->per_group_dir != NULL) {
snprintf(file, sizeof(file), "%s/%s", s->config->per_group_dir, proc->groupname);
if (access(file, R_OK) == 0) {
mslog(s, proc, LOG_INFO, "Loading group configuration '%s'", file);
ret = parse_group_cfg_file(s, file, &g_cfg);
if (ret < 0)
return ERR_READ_CONFIG;
if (g_cfg.routes_size > 0) {
config->routes = realloc(config->routes, (config->routes_size+g_cfg.routes_size) * sizeof(config->routes[0]));
if (config->routes == NULL)
return ERR_MEM;
for (i=0;i<g_cfg.routes_size;i++) {
config->routes[config->routes_size] = g_cfg.routes[i];
g_cfg.routes[i] = NULL;
config->routes_size++;
}
}
if (config->ipv4_dns == NULL) {
config->ipv4_dns = g_cfg.ipv4_dns;
g_cfg.ipv4_dns = NULL;
}
if (config->ipv6_dns == NULL) {
config->ipv6_dns = g_cfg.ipv6_dns;
g_cfg.ipv6_dns = NULL;
}
del_additional_config(&g_cfg);
} else
mslog(s, proc, LOG_INFO, "No group configuration for '%s'", proc->groupname);
}
return 0;
}
int handle_script_exit(main_server_st *s, struct proc_st* proc, int code) int handle_script_exit(main_server_st *s, struct proc_st* proc, int code)
{ {
int ret; int ret;
if (code == 0) { if (code == 0) {
struct group_cfg_st cfg; ret = send_auth_reply(s, proc, REP_AUTH_OK);
ret = read_additional_config(s, proc, &cfg);
if (ret < 0) {
mslog(s, proc, LOG_ERR, "error reading additional routes");
ret = ERR_READ_ROUTES;
goto fail;
}
ret = send_auth_reply(s, proc, REP_AUTH_OK, &cfg);
del_additional_config(&cfg);
if (ret < 0) { if (ret < 0) {
mslog(s, proc, LOG_ERR, "could not send reply auth cmd."); mslog(s, proc, LOG_ERR, "could not send reply auth cmd.");
ret = ERR_BAD_COMMAND; ret = ERR_BAD_COMMAND;
@@ -232,7 +125,7 @@ int ret;
} }
} else { } else {
mslog(s, proc, LOG_INFO, "failed authentication attempt for user '%s'", proc->username); mslog(s, proc, LOG_INFO, "failed authentication attempt for user '%s'", proc->username);
ret = send_auth_reply( s, proc, REP_AUTH_FAILED, NULL); ret = send_auth_reply( s, proc, REP_AUTH_FAILED);
if (ret < 0) { if (ret < 0) {
mslog(s, proc, LOG_ERR, "could not send reply auth cmd."); mslog(s, proc, LOG_ERR, "could not send reply auth cmd.");
ret = ERR_BAD_COMMAND; ret = ERR_BAD_COMMAND;
@@ -245,15 +138,141 @@ fail:
/* we close the lease tun fd both on success and failure. /* we close the lease tun fd both on success and failure.
* The parent doesn't need to keep the tunfd. * The parent doesn't need to keep the tunfd.
*/ */
if (proc->lease) { if (proc->tun_lease.name[0] != 0) {
if (proc->lease->fd >= 0) if (proc->tun_lease.fd >= 0)
close(proc->lease->fd); close(proc->tun_lease.fd);
proc->lease->fd = -1; proc->tun_lease.fd = -1;
} }
return ret; return ret;
} }
void del_additional_config(struct group_cfg_st* config)
{
unsigned i;
for(i=0;i<config->routes_size;i++) {
free(config->routes[i]);
}
free(config->routes);
free(config->ipv4_dns);
free(config->ipv6_dns);
free(config->ipv4_nbns);
free(config->ipv6_nbns);
free(config->ipv4_network);
free(config->ipv6_network);
free(config->ipv4_netmask);
free(config->ipv6_netmask);
}
static int read_config_file(main_server_st* s, struct proc_st* proc, const char* file, const char* type)
{
struct group_cfg_st cfg;
int ret;
unsigned i;
if (access(file, R_OK) == 0) {
mslog(s, proc, LOG_DEBUG, "Loading %s configuration '%s'", type, file);
ret = parse_group_cfg_file(s, file, &cfg);
if (ret < 0)
return ERR_READ_CONFIG;
if (cfg.routes_size > 0) {
if (proc->config.routes == NULL) {
proc->config.routes = cfg.routes;
proc->config.routes_size = cfg.routes_size;
cfg.routes = NULL;
cfg.routes_size = 0;
} else {
proc->config.routes = realloc(proc->config.routes, (proc->config.routes_size + cfg.routes_size) * sizeof(proc->config.routes[0]));
if (proc->config.routes == NULL)
return ERR_MEM;
for (i=0;i<cfg.routes_size;i++) {
proc->config.routes[proc->config.routes_size] = cfg.routes[i];
cfg.routes[i] = NULL;
proc->config.routes_size++;
}
}
}
if (proc->config.ipv4_dns == NULL) {
proc->config.ipv4_dns = cfg.ipv4_dns;
cfg.ipv4_dns = NULL;
}
if (proc->config.ipv6_dns == NULL) {
proc->config.ipv6_dns = cfg.ipv6_dns;
cfg.ipv6_dns = NULL;
}
if (proc->config.ipv4_nbns == NULL) {
proc->config.ipv4_nbns = cfg.ipv4_nbns;
cfg.ipv4_nbns = NULL;
}
if (proc->config.ipv6_nbns == NULL) {
proc->config.ipv6_nbns = cfg.ipv6_nbns;
cfg.ipv6_nbns = NULL;
}
if (proc->config.ipv4_network == NULL) {
proc->config.ipv4_network = cfg.ipv4_network;
cfg.ipv4_network = NULL;
}
if (proc->config.ipv6_network == NULL) {
proc->config.ipv6_network = cfg.ipv6_network;
cfg.ipv6_network = NULL;
}
if (proc->config.ipv4_netmask == NULL) {
proc->config.ipv4_netmask = cfg.ipv4_netmask;
cfg.ipv4_netmask = NULL;
}
if (proc->config.ipv6_netmask == NULL) {
proc->config.ipv6_netmask = cfg.ipv6_netmask;
cfg.ipv6_netmask = NULL;
}
del_additional_config(&cfg);
} else
mslog(s, proc, LOG_DEBUG, "No %s configuration for '%s'", type, proc->username);
return 0;
}
static int read_additional_config(struct main_server_st* s, struct proc_st* proc)
{
char file[_POSIX_PATH_MAX];
int ret;
memset(&proc->config, 0, sizeof(proc->config));
if (s->config->per_user_dir != NULL) {
snprintf(file, sizeof(file), "%s/%s", s->config->per_user_dir, proc->username);
ret = read_config_file(s, proc, file, "user");
if (ret < 0)
return ret;
}
if (s->config->per_group_dir != NULL) {
snprintf(file, sizeof(file), "%s/%s", s->config->per_group_dir, proc->groupname);
ret = read_config_file(s, proc, file, "group");
if (ret < 0)
return ret;
}
return 0;
}
static int accept_user(main_server_st *s, struct proc_st* proc, unsigned cmd) static int accept_user(main_server_st *s, struct proc_st* proc, unsigned cmd)
{ {
int ret; int ret;
@@ -269,6 +288,12 @@ const char* group;
return ret; return ret;
} }
ret = read_additional_config(s, proc);
if (ret < 0) {
mslog(s, proc, LOG_ERR, "error reading additional configuration");
return ERR_READ_CONFIG;
}
ret = open_tun(s, proc); ret = open_tun(s, proc);
if (ret < 0) { if (ret < 0) {
return -1; return -1;

View File

@@ -32,12 +32,12 @@
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <gnutls/gnutls.h> #include <gnutls/gnutls.h>
#include <gnutls/crypto.h> #include <gnutls/crypto.h>
#include <tlslib.h>
#include "ipc.h" #include "ipc.h"
#include <ccan/hash/hash.h> #include <ccan/hash/hash.h>
#include <vpn.h> #include <vpn.h>
#include <main.h> #include <main.h>
#include <common.h>
#include <tlslib.h> #include <tlslib.h>
int send_resume_fetch_reply(main_server_st* s, struct proc_st * proc, int send_resume_fetch_reply(main_server_st* s, struct proc_st * proc,
@@ -69,7 +69,7 @@ tls_cache_st* cache;
struct htable_iter iter; struct htable_iter iter;
size_t key; size_t key;
key = hash_stable_8(req->session_id, req->session_id_size, 0); key = hash_any(req->session_id, req->session_id_size, 0);
cache = htable_firstval(&s->tls_db->ht, &iter, key); cache = htable_firstval(&s->tls_db->ht, &iter, key);
while(cache != NULL) { while(cache != NULL) {
@@ -91,15 +91,6 @@ size_t key;
return 0; return 0;
} }
static int ip_cmp(const struct sockaddr_storage *s1, const struct sockaddr_storage *s2, size_t n)
{
if (((struct sockaddr*)s1)->sa_family == AF_INET) {
return memcmp(SA_IN_P(s1), SA_IN_P(s2), sizeof(struct in_addr));
} else { /* inet6 */
return memcmp(SA_IN6_P(s1), SA_IN6_P(s2), sizeof(struct in6_addr));
}
}
int handle_resume_fetch_req(main_server_st* s, struct proc_st * proc, int handle_resume_fetch_req(main_server_st* s, struct proc_st * proc,
const struct cmd_resume_fetch_req_st * req, const struct cmd_resume_fetch_req_st * req,
struct cmd_resume_fetch_reply_st * rep) struct cmd_resume_fetch_reply_st * rep)
@@ -110,7 +101,7 @@ size_t key;
rep->reply = REP_RESUME_FAILED; rep->reply = REP_RESUME_FAILED;
key = hash_stable_8(req->session_id, req->session_id_size, 0); key = hash_any(req->session_id, req->session_id_size, 0);
cache = htable_firstval(&s->tls_db->ht, &iter, key); cache = htable_firstval(&s->tls_db->ht, &iter, key);
while(cache != NULL) { while(cache != NULL) {
@@ -155,7 +146,7 @@ unsigned int max;
return -1; return -1;
} }
key = hash_stable_8(req->session_id, req->session_id_size, 0); key = hash_any(req->session_id, req->session_id_size, 0);
cache = malloc(sizeof(*cache)); cache = malloc(sizeof(*cache));
if (cache == NULL) if (cache == NULL)

View File

@@ -42,6 +42,7 @@
#include <cookies.h> #include <cookies.h>
#include <tun.h> #include <tun.h>
#include <main.h> #include <main.h>
#include <ip-lease.h>
#include <script-list.h> #include <script-list.h>
#include <ccan/list/list.h> #include <ccan/list/list.h>
@@ -66,32 +67,32 @@ const char* script;
char local[64]; char local[64];
char remote[64]; char remote[64];
if (proc->lease == NULL) if (proc->ipv4 == NULL && proc->ipv6 == NULL)
exit(1); exit(1);
if (getnameinfo((void*)&proc->remote_addr, proc->remote_addr_len, real, sizeof(real), NULL, 0, NI_NUMERICHOST) != 0) if (getnameinfo((void*)&proc->remote_addr, proc->remote_addr_len, real, sizeof(real), NULL, 0, NI_NUMERICHOST) != 0)
exit(1); exit(1);
if (proc->lease->lip4_len > 0) { if (proc->ipv4 && proc->ipv4->lip_len > 0) {
if (getnameinfo((void*)&proc->lease->lip4, proc->lease->lip4_len, local, sizeof(local), NULL, 0, NI_NUMERICHOST) != 0) if (getnameinfo((void*)&proc->ipv4->lip, proc->ipv4->lip_len, local, sizeof(local), NULL, 0, NI_NUMERICHOST) != 0)
exit(1); exit(1);
} else { } else {
if (getnameinfo((void*)&proc->lease->lip6, proc->lease->lip6_len, local, sizeof(local), NULL, 0, NI_NUMERICHOST) != 0) if (getnameinfo((void*)&proc->ipv6->lip, proc->ipv6->lip_len, local, sizeof(local), NULL, 0, NI_NUMERICHOST) != 0)
exit(1); exit(1);
} }
if (proc->lease->rip4_len > 0) { if (proc->ipv4 && proc->ipv4->rip_len > 0) {
if (getnameinfo((void*)&proc->lease->rip4, proc->lease->rip4_len, remote, sizeof(remote), NULL, 0, NI_NUMERICHOST) != 0) if (getnameinfo((void*)&proc->ipv4->rip, proc->ipv4->rip_len, remote, sizeof(remote), NULL, 0, NI_NUMERICHOST) != 0)
exit(1); exit(1);
} else { } else {
if (getnameinfo((void*)&proc->lease->rip6, proc->lease->rip6_len, remote, sizeof(remote), NULL, 0, NI_NUMERICHOST) != 0) if (getnameinfo((void*)&proc->ipv6->rip, proc->ipv6->rip_len, remote, sizeof(remote), NULL, 0, NI_NUMERICHOST) != 0)
exit(1); exit(1);
} }
setenv("USERNAME", proc->username, 1); setenv("USERNAME", proc->username, 1);
setenv("GROUPNAME", proc->groupname, 1); setenv("GROUPNAME", proc->groupname, 1);
setenv("HOSTNAME", proc->hostname, 1); setenv("HOSTNAME", proc->hostname, 1);
setenv("DEVICE", proc->lease->name, 1); setenv("DEVICE", proc->tun_lease.name, 1);
setenv("IP_REAL", real, 1); setenv("IP_REAL", real, 1);
setenv("IP_LOCAL", local, 1); setenv("IP_LOCAL", local, 1);
setenv("IP_REMOTE", remote, 1); setenv("IP_REMOTE", remote, 1);
@@ -134,7 +135,7 @@ add_utmp_entry(main_server_st *s, struct proc_st* proc)
memset(&entry, 0, sizeof(entry)); memset(&entry, 0, sizeof(entry));
entry.ut_type = USER_PROCESS; entry.ut_type = USER_PROCESS;
entry.ut_pid = proc->pid; entry.ut_pid = proc->pid;
snprintf(entry.ut_line, sizeof(entry.ut_line), "%s", proc->lease->name); snprintf(entry.ut_line, sizeof(entry.ut_line), "%s", proc->tun_lease.name);
snprintf(entry.ut_user, sizeof(entry.ut_user), "%s", proc->username); snprintf(entry.ut_user, sizeof(entry.ut_user), "%s", proc->username);
#ifdef __linux__ #ifdef __linux__
if (proc->remote_addr_len == sizeof(struct sockaddr_in)) if (proc->remote_addr_len == sizeof(struct sockaddr_in))
@@ -171,8 +172,8 @@ static void remove_utmp_entry(main_server_st *s, struct proc_st* proc)
memset(&entry, 0, sizeof(entry)); memset(&entry, 0, sizeof(entry));
entry.ut_type = DEAD_PROCESS; entry.ut_type = DEAD_PROCESS;
if (proc->lease && proc->lease->name) if (proc->tun_lease.name[0] != 0)
snprintf(entry.ut_line, sizeof(entry.ut_line), "%s", proc->lease->name); snprintf(entry.ut_line, sizeof(entry.ut_line), "%s", proc->tun_lease.name);
entry.ut_pid = proc->pid; entry.ut_pid = proc->pid;
setutxent(); setutxent();

View File

@@ -49,6 +49,7 @@
#include <worker.h> #include <worker.h>
#include <cookies.h> #include <cookies.h>
#include <tun.h> #include <tun.h>
#include <ip-lease.h>
#include <ccan/list/list.h> #include <ccan/list/list.h>
int syslog_open = 0; int syslog_open = 0;
@@ -302,11 +303,14 @@ static void remove_proc(main_server_st* s, struct proc_st *proc, unsigned k)
proc->fd = -1; proc->fd = -1;
proc->pid = -1; proc->pid = -1;
del_additional_config(&proc->config);
if (proc->auth_ctx != NULL) if (proc->auth_ctx != NULL)
proc_auth_deinit(s, proc); proc_auth_deinit(s, proc);
if (proc->lease) if (proc->ipv4 || proc->ipv6)
proc->lease->in_use = 0; remove_ip_leases(s, proc);
list_del(&proc->list); list_del(&proc->list);
free(proc); free(proc);
s->active_clients--; s->active_clients--;
@@ -459,6 +463,9 @@ void clear_lists(main_server_st *s)
} }
tls_cache_deinit(s->tls_db); tls_cache_deinit(s->tls_db);
ip_lease_deinit(&s->ip_leases);
} }
static void kill_children(main_server_st* s) static void kill_children(main_server_st* s)
@@ -628,7 +635,6 @@ int main(int argc, char** argv)
int fd, pid, e; int fd, pid, e;
struct listener_st *ltmp; struct listener_st *ltmp;
struct proc_st *ctmp, *cpos; struct proc_st *ctmp, *cpos;
struct tun_st tun;
fd_set rd; fd_set rd;
int val, n = 0, ret, flags; int val, n = 0, ret, flags;
struct timeval tv; struct timeval tv;
@@ -643,9 +649,9 @@ int main(int argc, char** argv)
list_head_init(&s.clist.head); list_head_init(&s.clist.head);
list_head_init(&s.ban_list.head); list_head_init(&s.ban_list.head);
list_head_init(&s.script_list.head); list_head_init(&s.script_list.head);
tun_st_init(&tun);
tls_cache_init(&s.tls_db); tls_cache_init(&s.tls_db);
ip_lease_init(&s.ip_leases);
ocsignal(SIGINT, handle_term); ocsignal(SIGINT, handle_term);
ocsignal(SIGTERM, handle_term); ocsignal(SIGTERM, handle_term);
ocsignal(SIGPIPE, SIG_IGN); ocsignal(SIGPIPE, SIG_IGN);
@@ -677,7 +683,6 @@ int main(int argc, char** argv)
} }
s.config = &config; s.config = &config;
s.tun = &tun;
main_auth_init(&s); main_auth_init(&s);

View File

@@ -55,7 +55,9 @@ struct proc_st {
unsigned udp_fd_received; /* if the corresponding process has received a UDP fd */ unsigned udp_fd_received; /* if the corresponding process has received a UDP fd */
/* the tun lease this process has */ /* the tun lease this process has */
struct lease_st* lease; struct tun_lease_st tun_lease;
struct ip_lease_st *ipv4;
struct ip_lease_st *ipv6;
struct sockaddr_storage remote_addr; /* peer address */ struct sockaddr_storage remote_addr; /* peer address */
socklen_t remote_addr_len; socklen_t remote_addr_len;
@@ -75,6 +77,13 @@ struct proc_st {
void * auth_ctx; /* the context of authentication */ void * auth_ctx; /* the context of authentication */
unsigned auth_status; /* PS_AUTH_ */ unsigned auth_status; /* PS_AUTH_ */
unsigned auth_reqs; /* the number of requests received */ unsigned auth_reqs; /* the number of requests received */
struct group_cfg_st config; /* custom user/group config */
};
struct ip_lease_db_st {
struct htable ht;
unsigned entries;
}; };
struct proc_list_st { struct proc_list_st {
@@ -99,7 +108,9 @@ struct ban_list_st {
typedef struct main_server_st { typedef struct main_server_st {
struct cfg_st *config; struct cfg_st *config;
struct tun_st *tun;
struct ip_lease_db_st ip_leases;
hash_db_st *tls_db; hash_db_st *tls_db;
uint8_t cookie_key[16]; uint8_t cookie_key[16];
@@ -157,7 +168,7 @@ int set_tun_mtu(main_server_st* s, struct proc_st * proc, unsigned mtu);
int send_auth_reply_msg(main_server_st* s, struct proc_st* proc); int send_auth_reply_msg(main_server_st* s, struct proc_st* proc);
int send_auth_reply(main_server_st* s, struct proc_st* proc, int send_auth_reply(main_server_st* s, struct proc_st* proc,
cmd_auth_reply_t r, struct group_cfg_st*); cmd_auth_reply_t r);
int handle_auth_cookie_req(main_server_st* s, struct proc_st* proc, int handle_auth_cookie_req(main_server_st* s, struct proc_st* proc,
const struct cmd_auth_cookie_req_st * req); const struct cmd_auth_cookie_req_st * req);
@@ -179,4 +190,6 @@ void run_sec_mod(main_server_st * s);
int parse_group_cfg_file(main_server_st* s, const char* file, struct group_cfg_st *config); int parse_group_cfg_file(main_server_st* s, const char* file, struct group_cfg_st *config);
void del_additional_config(struct group_cfg_st* config);
#endif #endif

View File

@@ -2,7 +2,7 @@
* *
* DO NOT EDIT THIS FILE (ocserv-args.c) * DO NOT EDIT THIS FILE (ocserv-args.c)
* *
* It has been AutoGen-ed October 28, 2013 at 11:41:39 AM by AutoGen 5.17 * It has been AutoGen-ed October 28, 2013 at 07:03:52 PM by AutoGen 5.17
* From the definitions ocserv-args.def * From the definitions ocserv-args.def
* and the template file options * and the template file options
* *

View File

@@ -263,7 +263,8 @@ route = 192.168.5.0/255.255.255.0
# Configuration files that will be applied per user connection or # Configuration files that will be applied per user connection or
# per group. Each file name on these directories must match the username # per group. Each file name on these directories must match the username
# or the groupname. # or the groupname.
# The options allow in such configuration files are ipv?-dns, and route. # The options allow in such configuration files are ipv?-dns, ipv?-nbns,
# ipv?-network, ipv?-netmask and route.
#config-per-user = /etc/ocserv/config-per-user/ #config-per-user = /etc/ocserv/config-per-user/
#config-per-group = /etc/ocserv/config-per-group/ #config-per-group = /etc/ocserv/config-per-group/

View File

@@ -2,7 +2,7 @@
* *
* DO NOT EDIT THIS FILE (ocserv-args.h) * DO NOT EDIT THIS FILE (ocserv-args.h)
* *
* It has been AutoGen-ed October 28, 2013 at 11:41:39 AM by AutoGen 5.17 * It has been AutoGen-ed October 28, 2013 at 07:03:52 PM by AutoGen 5.17
* From the definitions ocserv-args.def * From the definitions ocserv-args.def
* and the template file options * and the template file options
* *

290
src/tun.c
View File

@@ -30,7 +30,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <errno.h> #include <errno.h>
#include <cloexec.h> #include <cloexec.h>
#include <icmp-ping.h> #include <ip-lease.h>
#ifdef __linux__ #ifdef __linux__
# include <linux/if_tun.h> # include <linux/if_tun.h>
@@ -45,174 +45,7 @@
#include <main.h> #include <main.h>
#include <ccan/list/list.h> #include <ccan/list/list.h>
/* INCREMENT taken from nettle's macros */ static int set_network_info( main_server_st* s, struct proc_st* proc)
/* Requires that size > 0 */
#define INCREMENT(size, ctr) \
do { \
unsigned increment_i = (size) - 1; \
if (++(ctr)[increment_i] == 0) \
while (increment_i > 0 \
&& ++(ctr)[--increment_i] == 0 ) \
; \
} while (0)
static void bignum_add (uint8_t * num, unsigned size, unsigned step)
{
register int i;
register unsigned tmp, y;
for (i = size-1; i >= 0; i--)
{
tmp = num[i];
num[i] += step;
if (num[i] < tmp)
y = 1;
else
y = 0;
if (y == 0)
break;
}
}
static int get_avail_network_addresses(main_server_st* s, const struct lease_st *last4,
const struct lease_st *last6, struct lease_st* lease)
{
struct sockaddr_storage tmp, mask, network;
unsigned i;
int ret, step;
lease->rip4_len = 0;
lease->lip4_len = 0;
lease->rip6_len = 0;
lease->lip6_len = 0;
memset(&tmp, 0, sizeof(tmp));
if (s->config->network.ipv4 && s->config->network.ipv4_netmask) {
ret =
inet_pton(AF_INET, s->config->network.ipv4, SA_IN_P(&network));
if (ret != 1) {
mslog(s, NULL, LOG_ERR, "Error reading IP: %s\n", s->config->network.ipv4);
return -1;
}
ret =
inet_pton(AF_INET, s->config->network.ipv4_netmask, SA_IN_P(&mask));
if (ret != 1) {
mslog(s, NULL, LOG_ERR, "Error reading mask: %s\n", s->config->network.ipv4_netmask);
return -1;
}
/* mask the network (just in case it is wrong) */
for (i=0;i<sizeof(struct in_addr);i++)
SA_IN_U8_P(&network)[i] &= (SA_IN_U8_P(&mask)[i]);
((struct sockaddr_in*)&network)->sin_family = AF_INET;
if (last4 != NULL) {
memcpy(&tmp, &last4->rip4, last4->rip4_len);
} else {
memcpy(&tmp, &network, sizeof(tmp));
((struct sockaddr_in*)&tmp)->sin_family = AF_INET;
}
lease->lip4_len = sizeof(struct sockaddr_in);
memcpy(&lease->lip4, &tmp, sizeof(struct sockaddr_in));
step = 1;
do {
bignum_add(SA_IN_U8_P(&lease->lip4), sizeof(struct in_addr), step);
if (SA_IN_U8_P(&lease->lip4)[3] == 255) /* broadcast */
bignum_add(SA_IN_U8_P(&lease->lip4), sizeof(struct in_addr), step);
lease->rip4_len = sizeof(struct sockaddr_in);
memcpy(&lease->rip4, &lease->lip4, sizeof(struct sockaddr_in));
bignum_add(SA_IN_U8_P(&lease->rip4), sizeof(struct in_addr), step);
/* mask the last IP with the netmask */
memcpy(&tmp, &lease->rip4, lease->rip4_len);
for (i=0;i<sizeof(struct in_addr);i++)
SA_IN_U8_P(&tmp)[i] &= (SA_IN_U8_P(&mask)[i]);
/* the result should match the network */
if (memcmp(SA_IN_U8_P(&network), SA_IN_U8_P(&tmp), sizeof(struct in_addr)) != 0) {
mslog(s, NULL, LOG_ERR, "Reached limit of maximum (v4) IPs.\n");
return -1;
}
} while((step=icmp_ping4(s, (void*)&lease->lip4, (void*)&lease->rip4)) != 0);
}
if (s->config->network.ipv6 && s->config->network.ipv6_netmask) {
ret =
inet_pton(AF_INET6, s->config->network.ipv6, SA_IN6_P(&network));
if (ret != 1) {
mslog(s, NULL, LOG_ERR, "Error reading IP: %s\n", s->config->network.ipv6);
return -1;
}
ret =
inet_pton(AF_INET6, s->config->network.ipv6_netmask, SA_IN6_P(&mask));
if (ret != 1) {
mslog(s, NULL, LOG_ERR, "Error reading mask: %s\n", s->config->network.ipv6_netmask);
return -1;
}
/* mask the network */
for (i=0;i<sizeof(struct in6_addr);i++)
SA_IN6_U8_P(&network)[i] &= (SA_IN6_U8_P(&mask)[i]);
((struct sockaddr_in6*)&network)->sin6_family = AF_INET6;
if (last6 != NULL) {
memcpy(&tmp, &last6->rip6, last6->rip6_len);
} else {
memcpy(&tmp, &network, sizeof(tmp));
((struct sockaddr_in6*)&tmp)->sin6_family = AF_INET6;
}
lease->lip6_len = sizeof(struct sockaddr_in6);
memcpy(&lease->lip6, &tmp, sizeof(struct sockaddr_in6));
step = 1;
do {
bignum_add(SA_IN6_U8_P(&lease->lip6), sizeof(struct in6_addr), step);
lease->rip6_len = last6->rip6_len;
memcpy(&lease->rip6, &lease->lip6, lease->rip6_len);
bignum_add(SA_IN6_U8_P(&lease->rip6), sizeof(struct in6_addr), step);
/* mask the last IP with the netmask */
memcpy(&tmp, &lease->rip6, lease->rip6_len);
for (i=0;i<sizeof(struct in6_addr);i++)
SA_IN6_U8_P(&tmp)[i] &= (SA_IN6_U8_P(&mask)[i]);
/* the result should match the network */
if (memcmp(SA_IN6_U8_P(&network), SA_IN6_U8_P(&tmp), sizeof(struct in6_addr)) != 0) {
mslog(s, NULL, LOG_ERR, "Reached limit of maximum (v6) IPs.\n");
return -1;
}
} while((step=icmp_ping6(s, (void*)&lease->lip6, (void*)&lease->rip6)) != 0);
}
if (lease->lip6_len == 0 && lease->lip4_len == 0) {
mslog(s, NULL, LOG_ERR, "No IPv4 or IPv6 addresses are configured. Cannot obtain lease.\n");
return -1;
}
lease->tun_nr = 0;
if (last4)
lease->tun_nr = MAX(lease->tun_nr, last4->tun_nr+1);
if (last6)
lease->tun_nr = MAX(lease->tun_nr, last6->tun_nr+1);
return 0;
}
static int set_network_info( main_server_st* s, const struct lease_st *lease)
{ {
struct ifreq ifr; struct ifreq ifr;
int fd, ret; int fd, ret;
@@ -221,54 +54,54 @@ static int set_network_info( main_server_st* s, const struct lease_st *lease)
if (fd == -1) if (fd == -1)
return -1; return -1;
if (lease->lip4_len > 0 && lease->rip4_len > 0) { if (proc->ipv4 && proc->ipv4->lip_len > 0 && proc->ipv4->rip_len > 0) {
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
ifr.ifr_addr.sa_family = AF_INET; ifr.ifr_addr.sa_family = AF_INET;
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", lease->name); snprintf(ifr.ifr_name, IFNAMSIZ, "%s", proc->tun_lease.name);
memcpy(&ifr.ifr_addr, &lease->lip4, lease->lip4_len); memcpy(&ifr.ifr_addr, &proc->ipv4->lip, proc->ipv4->lip_len);
ret = ioctl(fd, SIOCSIFADDR, &ifr); ret = ioctl(fd, SIOCSIFADDR, &ifr);
if (ret != 0) { if (ret != 0) {
mslog(s, NULL, LOG_ERR, "%s: Error setting IPv4.\n", lease->name); mslog(s, NULL, LOG_ERR, "%s: Error setting IPv4.\n", proc->tun_lease.name);
} }
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
ifr.ifr_addr.sa_family = AF_INET; ifr.ifr_addr.sa_family = AF_INET;
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", lease->name); snprintf(ifr.ifr_name, IFNAMSIZ, "%s", proc->tun_lease.name);
memcpy(&ifr.ifr_dstaddr, &lease->rip4, lease->rip4_len); memcpy(&ifr.ifr_dstaddr, &proc->ipv4->rip, proc->ipv4->rip_len);
ret = ioctl(fd, SIOCSIFDSTADDR, &ifr); ret = ioctl(fd, SIOCSIFDSTADDR, &ifr);
if (ret != 0) { if (ret != 0) {
mslog(s, NULL, LOG_ERR, "%s: Error setting DST IPv4.\n", lease->name); mslog(s, NULL, LOG_ERR, "%s: Error setting DST IPv4.\n", proc->tun_lease.name);
} }
} }
if (lease->lip6_len > 0 && lease->rip6_len > 0) { if (proc->ipv6 && proc->ipv6->lip_len > 0 && proc->ipv6->rip_len > 0) {
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
ifr.ifr_addr.sa_family = AF_INET6; ifr.ifr_addr.sa_family = AF_INET6;
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", lease->name); snprintf(ifr.ifr_name, IFNAMSIZ, "%s", proc->tun_lease.name);
memcpy(&ifr.ifr_addr, &lease->lip6, lease->lip6_len); memcpy(&ifr.ifr_addr, &proc->ipv6->lip, proc->ipv6->lip_len);
ret = ioctl(fd, SIOCSIFADDR, &ifr); ret = ioctl(fd, SIOCSIFADDR, &ifr);
if (ret != 0) { if (ret != 0) {
mslog(s, NULL, LOG_ERR, "%s: Error setting IPv6.\n", lease->name); mslog(s, NULL, LOG_ERR, "%s: Error setting IPv6.\n", proc->tun_lease.name);
} }
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
ifr.ifr_addr.sa_family = AF_INET6; ifr.ifr_addr.sa_family = AF_INET6;
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", lease->name); snprintf(ifr.ifr_name, IFNAMSIZ, "%s", proc->tun_lease.name);
memcpy(&ifr.ifr_dstaddr, &lease->rip6, lease->rip6_len); memcpy(&ifr.ifr_dstaddr, &proc->ipv6->rip, proc->ipv6->rip_len);
ret = ioctl(fd, SIOCSIFDSTADDR, &ifr); ret = ioctl(fd, SIOCSIFDSTADDR, &ifr);
if (ret != 0) { if (ret != 0) {
mslog(s, NULL, LOG_ERR, "%s: Error setting DST IPv6.\n", lease->name); mslog(s, NULL, LOG_ERR, "%s: Error setting DST IPv6.\n", proc->tun_lease.name);
} }
} }
if (lease->lip6_len == 0 && lease->lip4_len == 0) { if (proc->ipv6 == 0 && proc->ipv4 == 0) {
mslog(s, NULL, LOG_ERR, "%s: Could not set any IP.\n", lease->name); mslog(s, NULL, LOG_ERR, "%s: Could not set any IP.\n", proc->tun_lease.name);
ret = -1; ret = -1;
goto cleanup; goto cleanup;
} }
@@ -277,11 +110,11 @@ static int set_network_info( main_server_st* s, const struct lease_st *lease)
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
ifr.ifr_addr.sa_family = AF_INET; ifr.ifr_addr.sa_family = AF_INET;
ifr.ifr_flags |= IFF_UP; ifr.ifr_flags |= IFF_UP;
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", lease->name); snprintf(ifr.ifr_name, IFNAMSIZ, "%s", proc->tun_lease.name);
ret = ioctl(fd, SIOCSIFFLAGS, &ifr); ret = ioctl(fd, SIOCSIFFLAGS, &ifr);
if (ret != 0) { if (ret != 0) {
mslog(s, NULL, LOG_ERR, "%s: Could not bring up interface.\n", lease->name); mslog(s, NULL, LOG_ERR, "%s: Could not bring up interface.\n", proc->tun_lease.name);
ret = -1; ret = -1;
} }
@@ -290,63 +123,18 @@ cleanup:
return ret; return ret;
} }
#include <ccan/hash/hash.h>
int open_tun(main_server_st* s, struct proc_st* proc) int open_tun(main_server_st* s, struct proc_st* proc)
{ {
int tunfd, ret, e; int tunfd, ret, e;
struct ifreq ifr; struct ifreq ifr;
unsigned int t; unsigned int t;
struct lease_st *lease = NULL;
struct lease_st *last4, *tmp;
struct lease_st *last6;
unsigned current = s->tun->total;
time_t now = time(0);
last4 = last6 = NULL; ret = get_ip_leases(s, proc);
if (ret < 0)
/* try to re-use an address */ return ret;
list_for_each(&s->tun->head, tmp, list) { snprintf(proc->tun_lease.name, sizeof(proc->tun_lease.name), "%s%%d", s->config->network.name);
/* if the device isn't in use by the server and the IPs
* are free. */
if (tmp->in_use == 0 && (tmp->available_at < now || (proc->username[0] != 0 && strcmp(proc->username, tmp->username) == 0))) {
if ((tmp->lip6_len != 0 && icmp_ping6(s, (void*)&tmp->lip6, (void*)&tmp->rip6) == 0) ||
(tmp->lip4_len != 0 && icmp_ping4(s, (void*)&tmp->lip4, (void*)&tmp->rip4) == 0)) {
lease = tmp;
mslog(s, NULL, LOG_INFO, "reusing tun device %s\n", lease->name);
break;
}
}
}
/* nothing to re-use */
if (lease == NULL) {
lease = calloc(1, sizeof(*lease));
if (lease == NULL)
return -1;
list_for_each_rev(&s->tun->head, tmp, list) {
if (last4 == NULL && tmp->rip4_len > 0)
last4 = tmp;
if (last6 == NULL && tmp->rip6_len > 0)
last6 = tmp;
if (last4 && last6)
break;
}
ret = get_avail_network_addresses(s, last4, last6, lease);
if (ret < 0) {
free(lease);
return -1;
}
/* Add into the list */
list_add_tail( &s->tun->head, &lease->list);
snprintf(lease->name, sizeof(lease->name), "%s%u", s->config->network.name, current);
snprintf(lease->username, sizeof(lease->username), "%s", proc->username);
s->tun->total++;
}
/* No need to free the lease after this point. /* No need to free the lease after this point.
*/ */
@@ -366,21 +154,24 @@ int open_tun(main_server_st* s, struct proc_st* proc)
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI; ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
memcpy(ifr.ifr_name, lease->name, IFNAMSIZ); memcpy(ifr.ifr_name, proc->tun_lease.name, IFNAMSIZ);
if (ioctl(tunfd, TUNSETIFF, (void *) &ifr) < 0) { if (ioctl(tunfd, TUNSETIFF, (void *) &ifr) < 0) {
e = errno; e = errno;
mslog(s, NULL, LOG_ERR, "%s: TUNSETIFF: %s\n", lease->name, strerror(e)); mslog(s, NULL, LOG_ERR, "%s: TUNSETIFF: %s\n", proc->tun_lease.name, strerror(e));
goto fail; goto fail;
} }
memcpy(lease->name, ifr.ifr_name, IFNAMSIZ); memcpy(proc->tun_lease.name, ifr.ifr_name, IFNAMSIZ);
mslog(s, NULL, LOG_INFO, "assigning tun device %s\n", lease->name); mslog(s, NULL, LOG_INFO, "assigning tun device %s\n", proc->tun_lease.name);
# if 0
/* we no longer use persistent tun */
if (ioctl(tunfd, TUNSETPERSIST, (void *)0) < 0) { if (ioctl(tunfd, TUNSETPERSIST, (void *)0) < 0) {
e = errno; e = errno;
mslog(s, NULL, LOG_ERR, "%s: TUNSETPERSIST: %s\n", lease->name, strerror(e)); mslog(s, NULL, LOG_ERR, "%s: TUNSETPERSIST: %s\n", proc->tun_lease.name, strerror(e));
goto fail; goto fail;
} }
# endif
if (s->config->uid != -1) { if (s->config->uid != -1) {
t = s->config->uid; t = s->config->uid;
@@ -388,7 +179,7 @@ int open_tun(main_server_st* s, struct proc_st* proc)
if (ret < 0) { if (ret < 0) {
e = errno; e = errno;
mslog(s, NULL, LOG_INFO, "%s: TUNSETOWNER: %s\n", mslog(s, NULL, LOG_INFO, "%s: TUNSETOWNER: %s\n",
lease->name, strerror(e)); proc->tun_lease.name, strerror(e));
goto fail; goto fail;
} }
} }
@@ -400,7 +191,7 @@ int open_tun(main_server_st* s, struct proc_st* proc)
if (ret < 0) { if (ret < 0) {
e = errno; e = errno;
mslog(s, NULL, LOG_ERR, "%s: TUNSETGROUP: %s\n", mslog(s, NULL, LOG_ERR, "%s: TUNSETGROUP: %s\n",
lease->name, strerror(e)); proc->tun_lease.name, strerror(e));
goto fail; goto fail;
} }
} }
@@ -425,22 +216,19 @@ int open_tun(main_server_st* s, struct proc_st* proc)
goto fail; goto fail;
} }
snprintf(lease->name, sizeof(lease->name), "%s", devname(st.st_rdev, S_IFCHR)); snprintf(proc->tun_lease.name, sizeof(proc->tun_lease.name), "%s", devname(st.st_rdev, S_IFCHR));
} }
set_cloexec_flag (tunfd, 1); set_cloexec_flag (tunfd, 1);
#endif #endif
/* set IP/mask */ /* set IP/mask */
ret = set_network_info(s, lease); ret = set_network_info(s, proc);
if (ret < 0) { if (ret < 0) {
goto fail; goto fail;
} }
lease->in_use = 1; proc->tun_lease.fd = tunfd;
lease->available_at = now + s->config->cookie_validity;
lease->fd = tunfd;
proc->lease = lease;
return 0; return 0;
fail: fail:

View File

@@ -5,50 +5,12 @@
#include <string.h> #include <string.h>
#include <ccan/list/list.h> #include <ccan/list/list.h>
struct lease_st { struct tun_lease_st {
struct list_node list;
char name[IFNAMSIZ]; char name[IFNAMSIZ];
char username[MAX_USERNAME_SIZE]; /* owner */
unsigned int tun_nr;
unsigned int in_use;
time_t available_at; /* when it will be available */
struct sockaddr_storage rip4;
socklen_t rip4_len;
struct sockaddr_storage lip4;
socklen_t lip4_len;
struct sockaddr_storage rip6;
socklen_t rip6_len;
struct sockaddr_storage lip6;
socklen_t lip6_len;
/* this is used temporarily. */ /* this is used temporarily. */
int fd; int fd;
}; };
struct tun_st {
struct list_head head;
unsigned total;
};
inline static void tun_st_init(struct tun_st* ts)
{
memset(ts, 0, sizeof(*ts));
list_head_init(&ts->head);
}
inline static void tun_st_deinit(struct tun_st* ts)
{
struct lease_st *ltmp, *pos;
list_for_each_safe(&ts->head, ltmp, pos, list) {
list_del(&ltmp->list);
ts->total--;
}
}
#endif #endif

View File

@@ -47,8 +47,8 @@ extern int syslog_open;
#define ERR_AUTH_CONTINUE -4 #define ERR_AUTH_CONTINUE -4
#define ERR_WAIT_FOR_SCRIPT -5 #define ERR_WAIT_FOR_SCRIPT -5
#define ERR_MEM -6 #define ERR_MEM -6
#define ERR_READ_ROUTES -7 #define ERR_READ_CONFIG -7
#define ERR_READ_CONFIG -8 #define ERR_NO_IP -8
typedef struct typedef struct
{ {
@@ -62,6 +62,12 @@ struct group_cfg_st {
char *ipv4_dns; char *ipv4_dns;
char *ipv6_dns; char *ipv6_dns;
char *ipv4_nbns;
char *ipv6_nbns;
char *ipv4_network;
char *ipv6_network;
char *ipv4_netmask;
char *ipv6_netmask;
}; };
struct vpn_st { struct vpn_st {

View File

@@ -235,10 +235,105 @@ static int send_auth_cookie_req(int fd, const struct cmd_auth_cookie_req_st* r)
return(sendmsg(fd, &hdr, 0)); return(sendmsg(fd, &hdr, 0));
} }
static int read_str_value_length(worker_st *ws, char** res)
{
int ret;
uint8_t len;
ret = force_read(ws->cmd_fd, &len, 1);
if (ret != 1) {
oclog(ws, LOG_ERR, "Error receiving length-value from main (%d)", ret);
return ERR_BAD_COMMAND;
}
if (len > 0) {
*res = malloc(((int)len)+1);
if (*res == NULL)
return ERR_MEM;
ret = force_read(ws->cmd_fd, *res, len);
if (ret != len) {
oclog(ws, LOG_ERR, "Error receiving value from main (%d)", ret);
return ERR_BAD_COMMAND;
}
(*res)[len] = 0;
}
return 0;
}
static
int deserialize_additional_data(worker_st* ws)
{
int ret;
uint8_t len;
unsigned i;
/* IPV4 DNS */
ret = read_str_value_length(ws, &ws->ipv4_dns);
if (ret < 0)
return ret;
/* IPV6 DNS */
ret = read_str_value_length(ws, &ws->ipv6_dns);
if (ret < 0)
return ret;
/* IPV4 NBNS */
ret = read_str_value_length(ws, &ws->ipv4_nbns);
if (ret < 0)
return ret;
/* IPV6 NBNS */
ret = read_str_value_length(ws, &ws->ipv6_nbns);
if (ret < 0)
return ret;
/* IPV4 netmask */
ret = read_str_value_length(ws, &ws->ipv4_netmask);
if (ret < 0)
return ret;
/* IPV6 netmask */
ret = read_str_value_length(ws, &ws->ipv6_netmask);
if (ret < 0)
return ret;
/* number of routes */
ret = force_read(ws->cmd_fd, &len, 1);
if (ret != 1) {
oclog(ws, LOG_ERR, "Error receiving length-value from main (%d)", ret);
return ERR_BAD_COMMAND;
}
ws->routes_size = len;
/* routes */
for (i=0;i<ws->routes_size;i++) {
ret = force_read(ws->cmd_fd, &ws->routes[i].size, 1);
if (ret != 1) {
oclog(ws, LOG_ERR, "Error received route size from main (%d)", ret);
return ERR_BAD_COMMAND;
}
ws->routes[i].route = malloc(ws->routes[i].size+1);
if (ws->routes[i].route == NULL)
return ERR_MEM;
ret = force_read(ws->cmd_fd, ws->routes[i].route, ws->routes[i].size);
if (ret != ws->routes[i].size) {
oclog(ws, LOG_ERR, "Error received routes from main (%d)", ret);
return ERR_BAD_COMMAND;
}
ws->routes[i].route[ws->routes[i].size] = 0;
}
return 0;
}
static int recv_auth_reply(worker_st *ws, struct cmd_auth_reply_st *resp) static int recv_auth_reply(worker_st *ws, struct cmd_auth_reply_st *resp)
{ {
struct iovec iov[2]; struct iovec iov[2];
uint8_t cmd = 0, len; uint8_t cmd = 0;
struct msghdr hdr; struct msghdr hdr;
int ret, cmdlen; int ret, cmdlen;
union { union {
@@ -246,7 +341,6 @@ static int recv_auth_reply(worker_st *ws, struct cmd_auth_reply_st *resp)
char control[CMSG_SPACE(sizeof(int))]; char control[CMSG_SPACE(sizeof(int))];
} control_un; } control_un;
struct cmsghdr *cmptr; struct cmsghdr *cmptr;
unsigned i;
iov[0].iov_base = &cmd; iov[0].iov_base = &cmd;
iov[0].iov_len = 1; iov[0].iov_len = 1;
@@ -295,69 +389,11 @@ static int recv_auth_reply(worker_st *ws, struct cmd_auth_reply_st *resp)
memcpy(ws->cookie, resp->data.ok.cookie, sizeof(ws->cookie)); memcpy(ws->cookie, resp->data.ok.cookie, sizeof(ws->cookie));
memcpy(ws->session_id, resp->data.ok.session_id, sizeof(ws->session_id)); memcpy(ws->session_id, resp->data.ok.session_id, sizeof(ws->session_id));
ws->routes_size = resp->data.ok.routes_size;
/* Read any additional data */ /* Read any additional data */
/* IPV4 DNS */ ret = deserialize_additional_data(ws);
ret = force_read(ws->cmd_fd, &len, 1); if (ret < 0)
if (ret != 1) { return ret;
oclog(ws, LOG_ERR, "Error received route size from main (%d)", ret);
return ERR_BAD_COMMAND;
}
if (len > 0) {
ws->ipv4_dns = malloc(len+1);
if (ws->ipv4_dns == NULL)
return ERR_MEM;
ret = force_read(ws->cmd_fd, ws->ipv4_dns, len);
if (ret != len) {
oclog(ws, LOG_ERR, "Error received routes from main (%d)", ret);
return ERR_BAD_COMMAND;
}
ws->ipv4_dns[len] = 0;
}
/* IPV6 DNS */
ret = force_read(ws->cmd_fd, &len, 1);
if (ret != 1) {
oclog(ws, LOG_ERR, "Error received route size from main (%d)", ret);
return ERR_BAD_COMMAND;
}
if (len > 0) {
ws->ipv6_dns = malloc(len+1);
if (ws->ipv6_dns == NULL)
return ERR_MEM;
ret = force_read(ws->cmd_fd, ws->ipv6_dns, len);
if (ret != len) {
oclog(ws, LOG_ERR, "Error received routes from main (%d)", ret);
return ERR_BAD_COMMAND;
}
ws->ipv6_dns[len] = 0;
}
/* routes */
for (i=0;i<ws->routes_size;i++) {
ret = force_read(ws->cmd_fd, &ws->routes[i].size, 1);
if (ret != 1) {
oclog(ws, LOG_ERR, "Error received route size from main (%d)", ret);
return ERR_BAD_COMMAND;
}
ws->routes[i].route = malloc(ws->routes[i].size+1);
if (ws->routes[i].route == NULL)
return ERR_MEM;
ret = force_read(ws->cmd_fd, ws->routes[i].route, ws->routes[i].size);
if (ret != ws->routes[i].size) {
oclog(ws, LOG_ERR, "Error received routes from main (%d)", ret);
return ERR_BAD_COMMAND;
}
ws->routes[i].route[ws->routes[i].size] = 0;
}
} else } else
return ERR_AUTH_FAIL; return ERR_AUTH_FAIL;

View File

@@ -157,22 +157,47 @@ struct ifreq ifr;
oclog(ws, LOG_DEBUG, "cannot obtain IPv4 local IP for %s", vinfo->name); oclog(ws, LOG_DEBUG, "cannot obtain IPv4 local IP for %s", vinfo->name);
#define LOCAL "local" #define LOCAL "local"
if (ws->config->network.ipv4_dns && strcmp(ws->config->network.ipv4_dns, LOCAL) == 0) if (ws->ipv4_dns != NULL)
vinfo->ipv4_dns = ws->ipv4_dns;
else if (ws->config->network.ipv4_dns && strcmp(ws->config->network.ipv4_dns, LOCAL) == 0)
vinfo->ipv4_dns = vinfo->ipv4_local; vinfo->ipv4_dns = vinfo->ipv4_local;
else else
vinfo->ipv4_dns = ws->config->network.ipv4_dns; vinfo->ipv4_dns = ws->config->network.ipv4_dns;
if (ws->config->network.ipv6_dns && strcmp(ws->config->network.ipv6_dns, LOCAL) == 0) if (ws->ipv6_dns != NULL)
vinfo->ipv6_dns = ws->ipv6_dns;
else if (ws->config->network.ipv6_dns && strcmp(ws->config->network.ipv6_dns, LOCAL) == 0)
vinfo->ipv6_dns = vinfo->ipv6_local; vinfo->ipv6_dns = vinfo->ipv6_local;
else else
vinfo->ipv6_dns = ws->config->network.ipv6_dns; vinfo->ipv6_dns = ws->config->network.ipv6_dns;
if (ws->ipv4_nbns != NULL)
vinfo->ipv4_nbns = ws->ipv4_nbns;
else if (ws->config->network.ipv4_nbns && strcmp(ws->config->network.ipv4_nbns, LOCAL) == 0)
vinfo->ipv4_nbns = vinfo->ipv4_local;
else
vinfo->ipv4_nbns = ws->config->network.ipv4_nbns;
if (ws->ipv6_nbns != NULL)
vinfo->ipv6_nbns = ws->ipv6_nbns;
else if (ws->config->network.ipv6_nbns && strcmp(ws->config->network.ipv6_nbns, LOCAL) == 0)
vinfo->ipv6_nbns = vinfo->ipv6_local;
else
vinfo->ipv6_nbns = ws->config->network.ipv6_nbns;
vinfo->routes_size = ws->config->network.routes_size; vinfo->routes_size = ws->config->network.routes_size;
if (ws->config->network.routes_size > 0) if (ws->config->network.routes_size > 0)
vinfo->routes = ws->config->network.routes; vinfo->routes = ws->config->network.routes;
vinfo->ipv4_netmask = ws->config->network.ipv4_netmask; if (ws->ipv4_netmask != NULL)
vinfo->ipv6_netmask = ws->config->network.ipv6_netmask; vinfo->ipv4_netmask = ws->ipv4_netmask;
else
vinfo->ipv4_netmask = ws->config->network.ipv4_netmask;
if (ws->ipv6_netmask != NULL)
vinfo->ipv6_netmask = ws->ipv6_netmask;
else
vinfo->ipv6_netmask = ws->config->network.ipv6_netmask;
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
ifr.ifr_addr.sa_family = AF_INET; ifr.ifr_addr.sa_family = AF_INET;

View File

@@ -854,13 +854,11 @@ socklen_t sl;
SEND_ERR(ret); SEND_ERR(ret);
} }
if (ws->ipv4_dns) { if (vinfo.ipv4_dns) {
ret = tls_printf(ws->session, "X-CSTP-DNS: %s\r\n", ws->ipv4_dns);
SEND_ERR(ret);
} else if (vinfo.ipv4_dns) {
ret = tls_printf(ws->session, "X-CSTP-DNS: %s\r\n", vinfo.ipv4_dns); ret = tls_printf(ws->session, "X-CSTP-DNS: %s\r\n", vinfo.ipv4_dns);
SEND_ERR(ret); SEND_ERR(ret);
} }
if (vinfo.ipv4_nbns) { if (vinfo.ipv4_nbns) {
ret = tls_printf(ws->session, "X-CSTP-NBNS: %s\r\n", vinfo.ipv4_nbns); ret = tls_printf(ws->session, "X-CSTP-NBNS: %s\r\n", vinfo.ipv4_nbns);
SEND_ERR(ret); SEND_ERR(ret);
@@ -877,19 +875,18 @@ socklen_t sl;
SEND_ERR(ret); SEND_ERR(ret);
} }
if (ws->ipv6_dns) { if (vinfo.ipv6_dns) {
ret = tls_printf(ws->session, "X-CSTP-DNS: %s\r\n", ws->ipv6_dns);
SEND_ERR(ret);
} else if (vinfo.ipv6_dns) {
ret = tls_printf(ws->session, "X-CSTP-DNS: %s\r\n", vinfo.ipv6_dns); ret = tls_printf(ws->session, "X-CSTP-DNS: %s\r\n", vinfo.ipv6_dns);
SEND_ERR(ret); SEND_ERR(ret);
} }
if (vinfo.ipv6_nbns) { if (vinfo.ipv6_nbns) {
ret = tls_printf(ws->session, "X-CSTP-NBNS: %s\r\n", vinfo.ipv6_nbns); ret = tls_printf(ws->session, "X-CSTP-NBNS: %s\r\n", vinfo.ipv6_nbns);
SEND_ERR(ret); SEND_ERR(ret);
} }
} }
for (i=0;i<vinfo.routes_size;i++) { for (i=0;i<vinfo.routes_size;i++) {
if (req->no_ipv6 != 0 && strchr(vinfo.routes[i], ':') != 0) if (req->no_ipv6 != 0 && strchr(vinfo.routes[i], ':') != 0)
continue; continue;

View File

@@ -121,6 +121,10 @@ typedef struct worker_st {
/* additional data - received per user or per group */ /* additional data - received per user or per group */
char *ipv4_dns; char *ipv4_dns;
char *ipv6_dns; char *ipv6_dns;
char *ipv4_nbns;
char *ipv6_nbns;
char *ipv4_netmask;
char *ipv6_netmask;
unsigned routes_size; unsigned routes_size;
struct route_st routes[MAX_ROUTES]; struct route_st routes[MAX_ROUTES];