Use a single UDP port in the server.

Several modifications to use a single UDP port in the server. This
is currently done using a hack, i.e., pass the UDP socket to worker,
close it on the main server and then re-open it (using REUSEADDR).

Also several updates in TUN handling to allow more than one clients connecting.
This commit is contained in:
Nikos Mavrogiannopoulos
2013-02-07 17:48:16 +01:00
parent dd31208d4a
commit 1cb7ab38e9
18 changed files with 547 additions and 363 deletions

1
TODO
View File

@@ -1,4 +1,3 @@
* Use a single UDP port
* Add a simple username/password back-end * Add a simple username/password back-end
* Certificate authentication to the main process (can it be done without * Certificate authentication to the main process (can it be done without
moving the TLS handshake over the main thread?) moving the TLS handshake over the main thread?)

View File

@@ -125,6 +125,7 @@ unsigned j;
READ_STRING("listen-host", config->name, 0); READ_STRING("listen-host", config->name, 0);
READ_NUMERIC("tcp-port", config->port, 1); READ_NUMERIC("tcp-port", config->port, 1);
READ_NUMERIC("udp-port", config->udp_port, 0);
READ_NUMERIC("keepalive", config->keepalive, 0); READ_NUMERIC("keepalive", config->keepalive, 0);
READ_STRING("server-cert", config->cert, 1); READ_STRING("server-cert", config->cert, 1);
@@ -199,6 +200,9 @@ static void check_cfg( struct cfg_st *config)
if (config->keepalive == 0) if (config->keepalive == 0)
config->keepalive = 30; config->keepalive = 30;
if (config->udp_port == 0)
config->udp_port = config->port;
if (config->priorities == NULL) if (config->priorities == NULL)
config->priorities = "NORMAL:%SERVER_PRECEDENCE:%COMPAT"; config->priorities = "NORMAL:%SERVER_PRECEDENCE:%COMPAT";

View File

@@ -18,6 +18,7 @@ typedef enum {
RESUME_DELETE_REQ, RESUME_DELETE_REQ,
RESUME_FETCH_REQ, RESUME_FETCH_REQ,
RESUME_FETCH_REP, RESUME_FETCH_REP,
CMD_UDP_FD,
CMD_TERMINATE, CMD_TERMINATE,
} cmd_request_t; } cmd_request_t;

View File

@@ -92,3 +92,35 @@ void __attribute__ ((format(printf, 3, 4)))
return; return;
} }
/* proc is optional */
void __attribute__ ((format(printf, 4, 5)))
mslog(const main_server_st * s, const struct proc_st* proc,
int priority, const char *fmt, ...)
{
char buf[1024];
char ipbuf[128];
const char* ip = NULL;
va_list args;
if (priority == LOG_DEBUG && s->config->debug == 0)
return;
if (proc) {
ip = human_addr((void*)&proc->remote_addr, proc->remote_addr_len,
ipbuf, sizeof(ipbuf));
}
buf[1023] = 0;
va_start(args, fmt);
vsnprintf(buf, 1023, fmt, args);
va_end(args);
if (ip)
syslog(priority, "%s %s", ip, buf);
else
syslog(priority, "%s", buf);
return;
}

View File

@@ -73,7 +73,7 @@ static int send_auth_reply(main_server_st* s, struct proc_st* proc,
hdr.msg_iovlen++; hdr.msg_iovlen++;
iov[2].iov_base = proc->session_id; iov[2].iov_base = proc->session_id;
iov[2].iov_len = sizeof(proc->session_id); iov[2].iov_len = proc->session_id_size;
hdr.msg_iovlen++; hdr.msg_iovlen++;
iov[3].iov_base = lease->name; iov[3].iov_base = lease->name;
@@ -114,8 +114,9 @@ struct stored_cookie_st sc;
memcpy(proc->cookie, req->cookie, sizeof(proc->cookie)); memcpy(proc->cookie, req->cookie, sizeof(proc->cookie));
memcpy(proc->username, sc.username, sizeof(proc->username)); memcpy(proc->username, sc.username, sizeof(proc->username));
memcpy(proc->session_id, sc.session_id, sizeof(proc->session_id)); memcpy(proc->session_id, sc.session_id, sizeof(proc->session_id));
proc->session_id_size = sizeof(proc->session_id);
ret = open_tun(s->config, s->tun, lease); ret = open_tun(s, lease);
if (ret < 0) if (ret < 0)
ret = -1; /* sorry */ ret = -1; /* sorry */
@@ -134,6 +135,7 @@ struct stored_cookie_st *sc;
ret = gnutls_rnd(GNUTLS_RND_NONCE, proc->session_id, sizeof(proc->session_id)); ret = gnutls_rnd(GNUTLS_RND_NONCE, proc->session_id, sizeof(proc->session_id));
if (ret < 0) if (ret < 0)
return -2; return -2;
proc->session_id_size = sizeof( proc->session_id);
sc = calloc(1, sizeof(*sc)); sc = calloc(1, sizeof(*sc));
if (sc == NULL) if (sc == NULL)
@@ -180,7 +182,7 @@ unsigned username_set = 0;
memcpy(proc->username, req->cert_user, MAX_USERNAME_SIZE); memcpy(proc->username, req->cert_user, MAX_USERNAME_SIZE);
else { else {
if (strcmp(proc->username, req->cert_user) != 0) { if (strcmp(proc->username, req->cert_user) != 0) {
syslog(LOG_INFO, "User '%s' presented a certificate from user '%s'", proc->username, req->cert_user); mslog(s, proc, LOG_INFO, "User '%s' presented a certificate from user '%s'", proc->username, req->cert_user);
ret = -1; ret = -1;
} }
} }
@@ -190,7 +192,7 @@ unsigned username_set = 0;
if (req->hostname[0] != 0) if (req->hostname[0] != 0)
memcpy(proc->hostname, req->hostname, MAX_HOSTNAME_SIZE); memcpy(proc->hostname, req->hostname, MAX_HOSTNAME_SIZE);
ret = open_tun(s->config, s->tun, lease); ret = open_tun(s, lease);
if (ret < 0) if (ret < 0)
ret = -1; /* sorry */ ret = -1; /* sorry */
} }
@@ -232,7 +234,7 @@ int handle_commands(main_server_st *s, struct proc_st* proc)
ret = recvmsg( proc->fd, &hdr, 0); ret = recvmsg( proc->fd, &hdr, 0);
if (ret == -1) { if (ret == -1) {
e = errno; e = errno;
syslog(LOG_ERR, "Cannot obtain data from command socket (pid: %d, peer: %s): %s", proc->pid, peer_ip, strerror(e)); mslog(s, proc, LOG_ERR, "Cannot obtain data from command socket (pid: %d, peer: %s): %s", proc->pid, peer_ip, strerror(e));
return -1; return -1;
} }
@@ -245,24 +247,24 @@ int handle_commands(main_server_st *s, struct proc_st* proc)
switch(cmd) { switch(cmd) {
case RESUME_STORE_REQ: case RESUME_STORE_REQ:
if (cmd_data_len <= sizeof(cmd_data.sresume)-MAX_SESSION_DATA_SIZE) { if (cmd_data_len <= sizeof(cmd_data.sresume)-MAX_SESSION_DATA_SIZE) {
syslog(LOG_ERR, "Error in received message length (pid: %d, peer: %s).", proc->pid, peer_ip); mslog(s, proc, LOG_ERR, "Error in received message length (pid: %d, peer: %s).", proc->pid, peer_ip);
return -2; return -2;
} }
ret = handle_resume_store_req(s, proc, &cmd_data.sresume); ret = handle_resume_store_req(s, proc, &cmd_data.sresume);
if (ret < 0) { if (ret < 0) {
syslog(LOG_DEBUG, "Could not store resumption data (pid: %d, peer: %s).", proc->pid, peer_ip); mslog(s, proc, LOG_DEBUG, "Could not store resumption data (pid: %d, peer: %s).", proc->pid, peer_ip);
} }
break; break;
case RESUME_DELETE_REQ: case RESUME_DELETE_REQ:
if (cmd_data_len != sizeof(cmd_data.fresume)) { if (cmd_data_len != sizeof(cmd_data.fresume)) {
syslog(LOG_ERR, "Error in received message length (pid: %d, peer: %s).", proc->pid, peer_ip); mslog(s, proc, LOG_ERR, "Error in received message length (pid: %d, peer: %s).", proc->pid, peer_ip);
return -2; return -2;
} }
ret = handle_resume_delete_req(s, proc, &cmd_data.fresume); ret = handle_resume_delete_req(s, proc, &cmd_data.fresume);
if (ret < 0) { if (ret < 0) {
syslog(LOG_DEBUG, "Could not delete resumption data (pid: %d, peer: %s).", proc->pid, peer_ip); mslog(s, proc, LOG_DEBUG, "Could not delete resumption data (pid: %d, peer: %s).", proc->pid, peer_ip);
} }
break; break;
@@ -270,19 +272,19 @@ int handle_commands(main_server_st *s, struct proc_st* proc)
struct cmd_resume_fetch_reply_st reply; struct cmd_resume_fetch_reply_st reply;
if (cmd_data_len != sizeof(cmd_data.fresume)) { if (cmd_data_len != sizeof(cmd_data.fresume)) {
syslog(LOG_ERR, "Error in received message length (pid: %d, peer: %s).", proc->pid, peer_ip); mslog(s, proc, LOG_ERR, "Error in received message length (pid: %d, peer: %s).", proc->pid, peer_ip);
return -2; return -2;
} }
ret = handle_resume_fetch_req(s, proc, &cmd_data.fresume, &reply); ret = handle_resume_fetch_req(s, proc, &cmd_data.fresume, &reply);
if (ret < 0) { if (ret < 0) {
syslog(LOG_DEBUG, "Could not fetch resumption data (pid: %d, peer: %s).", proc->pid, peer_ip); mslog(s, proc, LOG_DEBUG, "Could not fetch resumption data (pid: %d, peer: %s).", proc->pid, peer_ip);
ret = send_resume_fetch_reply(s, proc, REP_RESUME_FAILED, NULL); ret = send_resume_fetch_reply(s, proc, REP_RESUME_FAILED, NULL);
} else } else
ret = send_resume_fetch_reply(s, proc, REP_RESUME_OK, &reply); ret = send_resume_fetch_reply(s, proc, REP_RESUME_OK, &reply);
} }
if (ret < 0) { if (ret < 0) {
syslog(LOG_ERR, "Could not send reply cmd (pid: %d, peer: %s).", proc->pid, peer_ip); mslog(s, proc, LOG_ERR, "Could not send reply cmd (pid: %d, peer: %s).", proc->pid, peer_ip);
return -2; return -2;
} }
@@ -293,14 +295,14 @@ int handle_commands(main_server_st *s, struct proc_st* proc)
if (cmd == AUTH_REQ) { if (cmd == AUTH_REQ) {
if (cmd_data_len != sizeof(cmd_data.auth)) { if (cmd_data_len != sizeof(cmd_data.auth)) {
syslog(LOG_ERR, "Error in received message length (pid: %d, peer: %s).", proc->pid, peer_ip); mslog(s, proc, LOG_ERR, "Error in received message length (pid: %d, peer: %s).", proc->pid, peer_ip);
return -2; return -2;
} }
ret = handle_auth_req(s, proc, &cmd_data.auth, &lease); ret = handle_auth_req(s, proc, &cmd_data.auth, &lease);
} else { } else {
if (cmd_data_len != sizeof(cmd_data.cauth)) { if (cmd_data_len != sizeof(cmd_data.cauth)) {
syslog(LOG_ERR, "Error in received message length (pid: %d, peer: %s).", proc->pid, peer_ip); mslog(s, proc, LOG_ERR, "Error in received message length (pid: %d, peer: %s).", proc->pid, peer_ip);
return -2; return -2;
} }
@@ -310,7 +312,7 @@ int handle_commands(main_server_st *s, struct proc_st* proc)
if (ret == 0) { if (ret == 0) {
ret = user_connected(s, proc, lease); ret = user_connected(s, proc, lease);
if (ret < 0) { if (ret < 0) {
syslog(LOG_INFO, "User '%s' disconnected due to script", proc->username); mslog(s, proc, LOG_INFO, "User '%s' disconnected due to script", proc->username);
} }
} }
@@ -323,10 +325,10 @@ int handle_commands(main_server_st *s, struct proc_st* proc)
} }
syslog(LOG_INFO, "User '%s' authenticated", proc->username); mslog(s, proc, LOG_INFO, "User '%s' authenticated", proc->username);
ret = send_auth_reply(s, proc, REP_AUTH_OK, lease); ret = send_auth_reply(s, proc, REP_AUTH_OK, lease);
if (ret < 0) { if (ret < 0) {
syslog(LOG_ERR, "Could not send reply cmd (pid: %d, peer: %s).", proc->pid, peer_ip); mslog(s, proc, LOG_ERR, "Could not send reply cmd (pid: %d, peer: %s).", proc->pid, peer_ip);
return -2; return -2;
} }
@@ -336,17 +338,17 @@ int handle_commands(main_server_st *s, struct proc_st* proc)
close(lease->fd); close(lease->fd);
lease->fd = -1; lease->fd = -1;
} else { } else {
syslog(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, NULL);
if (ret < 0) { if (ret < 0) {
syslog(LOG_ERR, "Could not send reply cmd (pid: %d, peer: %s).", proc->pid, peer_ip); mslog(s, proc, LOG_ERR, "Could not send reply cmd (pid: %d, peer: %s).", proc->pid, peer_ip);
return -2; return -2;
} }
} }
break; break;
default: default:
syslog(LOG_ERR, "Unknown CMD 0x%x (pid: %d, peer: %s).", (unsigned)cmd, proc->pid, peer_ip); mslog(s, proc, LOG_ERR, "Unknown CMD 0x%x (pid: %d, peer: %s).", (unsigned)cmd, proc->pid, peer_ip);
return -2; return -2;
} }

View File

@@ -63,6 +63,42 @@ int send_resume_fetch_reply(main_server_st* s, struct proc_st * proc,
return(sendmsg(proc->fd, &hdr, 0)); return(sendmsg(proc->fd, &hdr, 0));
} }
int send_udp_fd(main_server_st* s, struct proc_st * proc,
void* cli_addr, socklen_t cli_addr_size, int fd)
{
struct iovec iov[2];
uint8_t cmd = CMD_UDP_FD;
struct msghdr hdr;
union {
struct cmsghdr cm;
char control[CMSG_SPACE(sizeof(int))];
} control_un;
struct cmsghdr *cmptr;
memset(&hdr, 0, sizeof(hdr));
iov[0].iov_base = &cmd;
iov[0].iov_len = 1;
hdr.msg_iovlen++;
iov[1].iov_base = cli_addr;
iov[1].iov_len = cli_addr_size;
hdr.msg_iovlen++;
hdr.msg_iov = iov;
hdr.msg_control = control_un.control;
hdr.msg_controllen = sizeof(control_un.control);
cmptr = CMSG_FIRSTHDR(&hdr);
cmptr->cmsg_len = CMSG_LEN(sizeof(int));
cmptr->cmsg_level = SOL_SOCKET;
cmptr->cmsg_type = SCM_RIGHTS;
memcpy(CMSG_DATA(cmptr), &fd, sizeof(int));
return(sendmsg(proc->fd, &hdr, 0));
}
int handle_resume_delete_req(main_server_st* s, struct proc_st * proc, int handle_resume_delete_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)
{ {

View File

@@ -53,46 +53,31 @@ static void tls_log_func(int level, const char *str)
syslog(LOG_DEBUG, "TLS[<%d>]: %s", level, str); syslog(LOG_DEBUG, "TLS[<%d>]: %s", level, str);
} }
/* Returns 0 on success or negative value on error. static
*/ int _listen_ports(struct cfg_st* config, struct addrinfo *res, struct listen_list_st *list)
static int
listen_ports(struct cfg_st* config, struct listen_list_st *list, const char *node,
int listen_port, int socktype)
{ {
struct addrinfo hints, *res, *ptr; struct addrinfo *ptr;
char portname[6];
int s, y; int s, y;
const char* type = NULL;
char buf[512]; char buf[512];
struct listener_st *tmp; struct listener_st *tmp;
list_head_init(&list->head);
list->total = 0;
snprintf(portname, sizeof(portname), "%d", listen_port);
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = socktype;
hints.ai_flags = AI_PASSIVE
#ifdef AI_ADDRCONFIG
| AI_ADDRCONFIG
#endif
;
s = getaddrinfo(node, portname, &hints, &res);
if (s != 0) {
fprintf(stderr, "getaddrinfo() failed: %s\n",
gai_strerror(s));
return -1;
}
for (ptr = res; ptr != NULL; ptr = ptr->ai_next) { for (ptr = res; ptr != NULL; ptr = ptr->ai_next) {
#ifndef HAVE_IPV6 #ifndef HAVE_IPV6
if (ptr->ai_family != AF_INET) if (ptr->ai_family != AF_INET)
continue; continue;
#endif #endif
if (ptr->ai_socktype == SOCK_STREAM)
type = "TCP";
else if (ptr->ai_socktype == SOCK_DGRAM)
type = "UDP";
else
continue;
if (config->foreground != 0) if (config->foreground != 0)
fprintf(stderr, "listening on %s...\n", fprintf(stderr, "listening (%s) on %s...\n",
human_addr(ptr->ai_addr, ptr->ai_addrlen, type, human_addr(ptr->ai_addr, ptr->ai_addrlen,
buf, sizeof(buf))); buf, sizeof(buf)));
s = socket(ptr->ai_family, ptr->ai_socktype, s = socket(ptr->ai_family, ptr->ai_socktype,
@@ -113,7 +98,7 @@ listen_ports(struct cfg_st* config, struct listen_list_st *list, const char *nod
} }
#endif #endif
if (socktype == SOCK_STREAM) { if (ptr->ai_socktype == SOCK_STREAM) {
y = 1; y = 1;
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
(const void *) &y, sizeof(y)) < 0) { (const void *) &y, sizeof(y)) < 0) {
@@ -122,6 +107,8 @@ listen_ports(struct cfg_st* config, struct listen_list_st *list, const char *nod
continue; continue;
} }
} else { } else {
y = 1;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const void *) &y, sizeof(y));
#if defined(IP_DONTFRAG) #if defined(IP_DONTFRAG)
y = 1; y = 1;
if (setsockopt(s, IPPROTO_IP, IP_DONTFRAG, if (setsockopt(s, IPPROTO_IP, IP_DONTFRAG,
@@ -143,25 +130,151 @@ listen_ports(struct cfg_st* config, struct listen_list_st *list, const char *nod
continue; continue;
} }
if (socktype == SOCK_STREAM) { if (ptr->ai_socktype == SOCK_STREAM) {
if (listen(s, 10) < 0) { if (listen(s, 10) < 0) {
perror("listen() failed"); perror("listen() failed");
exit(1); return -1;
} }
} }
tmp = calloc(1, sizeof(struct listener_st)); tmp = calloc(1, sizeof(struct listener_st));
tmp->fd = s; tmp->fd = s;
tmp->family = ptr->ai_family;
tmp->socktype = ptr->ai_socktype;
tmp->protocol = ptr->ai_protocol;
tmp->addr_len = ptr->ai_addrlen;
memcpy(&tmp->addr, ptr->ai_addr, tmp->addr_len);
list_add(&list->head, &(tmp->list)); list_add(&list->head, &(tmp->list));
list->total++; list->total++;
} }
fflush(stderr); fflush(stderr);
return 0;
}
/* Returns 0 on success or negative value on error.
*/
static int
listen_ports(struct cfg_st* config, struct listen_list_st *list, const char *node)
{
struct addrinfo hints, *res;
char portname[6];
int ret;
list_head_init(&list->head);
list->total = 0;
snprintf(portname, sizeof(portname), "%d", config->port);
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE
#ifdef AI_ADDRCONFIG
| AI_ADDRCONFIG
#endif
;
ret = getaddrinfo(node, portname, &hints, &res);
if (ret != 0) {
fprintf(stderr, "getaddrinfo() failed: %s\n",
gai_strerror(ret));
return -1;
}
ret = _listen_ports(config, res, list);
if (ret < 0) {
return -1;
}
freeaddrinfo(res);
snprintf(portname, sizeof(portname), "%d", config->udp_port);
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE
#ifdef AI_ADDRCONFIG
| AI_ADDRCONFIG
#endif
;
ret = getaddrinfo(node, portname, &hints, &res);
if (ret != 0) {
fprintf(stderr, "getaddrinfo() failed: %s\n",
gai_strerror(ret));
return -1;
}
ret = _listen_ports(config, res, list);
if (ret < 0) {
return -1;
}
freeaddrinfo(res); freeaddrinfo(res);
return 0; return 0;
} }
/* This is a hack. I tried to use connect() on the worker
* and use connect() with unspec on the master process but all packets
* were received by master. Reopening the socket seems to resolve
* that.
*/
static
int reopen_udp_port(struct listener_st *l)
{
int s, y, e;
close(l->fd);
l->fd = -1;
s = socket(l->family, l->socktype, l->protocol);
if (s < 0) {
perror("socket() failed");
return -1;
}
#if defined(HAVE_IPV6) && !defined(_WIN32)
if (ptr->ai_family == AF_INET6) {
y = 1;
/* avoid listen on ipv6 addresses failing
* because already listening on ipv4 addresses: */
setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
(const void *) &y, sizeof(y));
}
#endif
y = 1;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const void *) &y, sizeof(y));
#if defined(IP_DONTFRAG)
y = 1;
setsockopt(s, IPPROTO_IP, IP_DONTFRAG,
(const void *) &y, sizeof(y));
#elif defined(IP_MTU_DISCOVER)
y = IP_PMTUDISC_DO;
setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER,
(const void *) &y, sizeof(y));
#endif
set_cloexec_flag (s, 1);
if (bind(s, (void*)&l->addr, l->addr_len) < 0) {
e = errno;
syslog(LOG_ERR, "bind() failed: %s", strerror(e));
close(s);
return -1;
}
l->fd = s;
return 0;
}
static void cleanup_children(main_server_st *s) static void cleanup_children(main_server_st *s)
{ {
int status; int status;
@@ -171,7 +284,7 @@ pid_t pid;
if (WEXITSTATUS(status) != 0 || if (WEXITSTATUS(status) != 0 ||
(WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV)) { (WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV)) {
if (WIFSIGNALED(status)) if (WIFSIGNALED(status))
syslog(LOG_ERR, "Child %u died with sigsegv\n", (unsigned)pid); mslog(s, NULL, LOG_ERR, "Child %u died with sigsegv\n", (unsigned)pid);
} }
} }
need_children_cleanup = 0; need_children_cleanup = 0;
@@ -248,36 +361,36 @@ static int verify_certificate_cb(gnutls_session_t session)
return 0; return 0;
} }
static void drop_privileges(struct cfg_st *config) static void drop_privileges(main_server_st* s)
{ {
int ret, e; int ret, e;
if (config->chroot_dir) { if (s->config->chroot_dir) {
ret = chroot(config->chroot_dir); ret = chroot(s->config->chroot_dir);
if (ret != 0) { if (ret != 0) {
e = errno; e = errno;
syslog(LOG_ERR, "Cannot chroot to %s: %s", config->chroot_dir, strerror(e)); mslog(s, NULL, LOG_ERR, "Cannot chroot to %s: %s", s->config->chroot_dir, strerror(e));
exit(1); exit(1);
} }
} }
if (config->gid != -1 && (getgid() == 0 || getegid() == 0)) { if (s->config->gid != -1 && (getgid() == 0 || getegid() == 0)) {
ret = setgid(config->gid); ret = setgid(s->config->gid);
if (ret < 0) { if (ret < 0) {
e = errno; e = errno;
syslog(LOG_ERR, "Cannot set gid to %d: %s\n", mslog(s, NULL, LOG_ERR, "Cannot set gid to %d: %s\n",
(int) config->gid, strerror(e)); (int) s->config->gid, strerror(e));
exit(1); exit(1);
} }
} }
if (config->uid != -1 && (getuid() == 0 || geteuid() == 0)) { if (s->config->uid != -1 && (getuid() == 0 || geteuid() == 0)) {
ret = setuid(config->uid); ret = setuid(s->config->uid);
if (ret < 0) { if (ret < 0) {
e = errno; e = errno;
syslog(LOG_ERR, "Cannot set uid to %d: %s\n", mslog(s, NULL, LOG_ERR, "Cannot set uid to %d: %s\n",
(int) config->uid, strerror(e)); (int) s->config->uid, strerror(e));
exit(1); exit(1);
} }
@@ -335,6 +448,76 @@ static void handle_term(int signo)
terminate = 1; terminate = 1;
} }
#define RECORD_PAYLOAD_POS 13
#define HANDSHAKE_SESSION_ID_POS 46
static int forward_udp_to_owner(main_server_st* s, struct listener_st *listener)
{
int ret;
struct sockaddr_storage cli_addr;
struct proc_st *ctmp;
socklen_t cli_addr_size;
uint8_t buffer[1024];
uint8_t *session_id;
int session_id_size;
ssize_t buffer_size;
int connected = 0;
/* first receive from the correct client and connect socket */
cli_addr_size = sizeof(cli_addr);
ret = recvfrom(listener->fd, buffer, sizeof(buffer), MSG_PEEK, (void*)&cli_addr, &cli_addr_size);
if (ret < 0) {
mslog(s, NULL, LOG_INFO, "Error receiving in UDP socket");
return -1;
}
buffer_size = ret;
/* obtain the session id */
if (buffer_size < RECORD_PAYLOAD_POS+HANDSHAKE_SESSION_ID_POS+GNUTLS_MAX_SESSION_ID+2)
goto fail;
/* check version */
if (buffer[1] != 254 && (buffer[1] != 1 && buffer[0] != 0)) {
mslog(s, NULL, LOG_ERR, "Unknown DTLS version: %u.%u", (unsigned)buffer[1], (unsigned)buffer[2]);
goto fail;
}
/* read session_id */
session_id_size = buffer[RECORD_PAYLOAD_POS+HANDSHAKE_SESSION_ID_POS];
session_id = &buffer[RECORD_PAYLOAD_POS+HANDSHAKE_SESSION_ID_POS+1];
/* search for the IP and the session ID in all procs */
list_for_each(&s->clist->head, ctmp, list) {
if (ctmp->udp_fd_received == 0 && session_id_size == ctmp->session_id_size &&
memcmp(session_id, ctmp->session_id, session_id_size) == 0) {
ret = send_udp_fd(s, ctmp, (void*)&cli_addr, cli_addr_size, listener->fd);
if (ret < 0) {
mslog(s, ctmp, LOG_ERR, "Error passing UDP socket");
return -1;
}
ctmp->udp_fd_received = 1;
connected = 1;
reopen_udp_port(listener);
break;
}
}
fail:
if (connected == 0) {
/* received packet from unknown host */
// mslog(s, NULL, LOG_ERR, "Received UDP packet from unexpected host; discarding it");
recv(listener->fd, buffer, buffer_size, 0);
return -1;
}
return 0;
}
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
int fd, pid, e; int fd, pid, e;
@@ -344,13 +527,14 @@ int main(int argc, char** argv)
struct listener_st *ltmp; struct listener_st *ltmp;
struct proc_st *ctmp, *cpos; struct proc_st *ctmp, *cpos;
struct tun_st tun; struct tun_st tun;
const char* perr;
fd_set rd; fd_set rd;
int val, n = 0, ret; int val, n = 0, ret;
struct timeval tv; struct timeval tv;
int cmd_fd[2]; int cmd_fd[2];
struct worker_st ws; struct worker_st ws;
struct cfg_st config; struct cfg_st config;
unsigned active_clients = 0; unsigned active_clients = 0, set;
main_server_st s; main_server_st s;
list_head_init(&clist.head); list_head_init(&clist.head);
@@ -383,7 +567,7 @@ int main(int argc, char** argv)
s.clist = &clist; s.clist = &clist;
/* Listen to network ports */ /* Listen to network ports */
ret = listen_ports(&config, &llist, config.name, config.port, SOCK_STREAM); ret = listen_ports(&config, &llist, config.name);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Cannot listen to specified ports\n"); fprintf(stderr, "Cannot listen to specified ports\n");
exit(1); exit(1);
@@ -413,35 +597,36 @@ int main(int argc, char** argv)
exit(1); exit(1);
} }
if (config.ca != NULL) { if (config.cert_req != GNUTLS_CERT_IGNORE) {
ret = if (config.ca != NULL) {
gnutls_certificate_set_x509_trust_file(creds.xcred, ret =
config.ca, gnutls_certificate_set_x509_trust_file(creds.xcred,
GNUTLS_X509_FMT_PEM); config.ca,
if (ret < 0) { GNUTLS_X509_FMT_PEM);
fprintf(stderr, "Error setting the CA (%s) file.\n", if (ret < 0) {
config.ca); fprintf(stderr, "Error setting the CA (%s) file.\n",
exit(1); config.ca);
exit(1);
}
printf("Processed %d CA certificate(s).\n", ret);
} }
printf("Processed %d CA certificate(s).\n", ret); if (config.crl != NULL) {
} ret =
gnutls_certificate_set_x509_crl_file(creds.xcred,
config.crl,
GNUTLS_X509_FMT_PEM);
GNUTLS_FATAL_ERR(ret);
}
if (config.crl != NULL) {
ret =
gnutls_certificate_set_x509_crl_file(creds.xcred,
config.crl,
GNUTLS_X509_FMT_PEM);
GNUTLS_FATAL_ERR(ret);
}
if (config.cert_req != GNUTLS_CERT_IGNORE) {
gnutls_certificate_set_verify_function(creds.xcred, gnutls_certificate_set_verify_function(creds.xcred,
verify_certificate_cb); verify_certificate_cb);
} }
ret = gnutls_priority_init(&creds.cprio, config.priorities, NULL); ret = gnutls_priority_init(&creds.cprio, config.priorities, &perr);
if (ret == GNUTLS_E_PARSING_ERROR)
fprintf(stderr, "Error in TLS priority string: %s\n", perr);
GNUTLS_FATAL_ERR(ret); GNUTLS_FATAL_ERR(ret);
memset(&ws, 0, sizeof(ws)); memset(&ws, 0, sizeof(ws));
@@ -464,11 +649,14 @@ int main(int argc, char** argv)
FD_ZERO(&rd); FD_ZERO(&rd);
list_for_each(&llist.head, ltmp, list) { list_for_each(&llist.head, ltmp, list) {
if (ltmp->fd == -1) continue;
val = fcntl(ltmp->fd, F_GETFL, 0); val = fcntl(ltmp->fd, F_GETFL, 0);
if ((val == -1) if ((val == -1)
|| (fcntl(ltmp->fd, F_SETFL, val | O_NONBLOCK) < || (fcntl(ltmp->fd, F_SETFL, val | O_NONBLOCK) <
0)) { 0)) {
perror("fcntl()"); e = errno;
mslog(&s, NULL, LOG_ERR, "fcntl() error: %s", strerror(e));
exit(1); exit(1);
} }
@@ -489,18 +677,20 @@ int main(int argc, char** argv)
if (ret < 0) { if (ret < 0) {
e = errno; e = errno;
syslog(LOG_ERR, "Error in select(): %s", mslog(&s, NULL, LOG_ERR, "Error in select(): %s",
strerror(e)); strerror(e));
exit(1); exit(1);
} }
/* Check for new connections to accept */ /* Check for new connections to accept */
list_for_each(&llist.head, ltmp, list) { list_for_each(&llist.head, ltmp, list) {
if (FD_ISSET(ltmp->fd, &rd)) { set = FD_ISSET(ltmp->fd, &rd);
if (set && ltmp->socktype == SOCK_STREAM) {
/* connection on TCP port */
ws.remote_addr_len = sizeof(ws.remote_addr); ws.remote_addr_len = sizeof(ws.remote_addr);
fd = accept(ltmp->fd, (void*)&ws.remote_addr, &ws.remote_addr_len); fd = accept(ltmp->fd, (void*)&ws.remote_addr, &ws.remote_addr_len);
if (fd < 0) { if (fd < 0) {
syslog(LOG_ERR, mslog(&s, NULL, LOG_ERR,
"Error in accept(): %s", "Error in accept(): %s",
strerror(errno)); strerror(errno));
continue; continue;
@@ -509,14 +699,14 @@ int main(int argc, char** argv)
if (config.max_clients > 0 && active_clients >= config.max_clients) { if (config.max_clients > 0 && active_clients >= config.max_clients) {
close(fd); close(fd);
syslog(LOG_INFO, "Reached maximum client limit (active: %u)", active_clients); mslog(&s, NULL, LOG_INFO, "Reached maximum client limit (active: %u)", active_clients);
break; break;
} }
/* Create a command socket */ /* Create a command socket */
ret = socketpair(AF_UNIX, SOCK_STREAM, 0, cmd_fd); ret = socketpair(AF_UNIX, SOCK_STREAM, 0, cmd_fd);
if (ret < 0) { if (ret < 0) {
syslog(LOG_ERR, "Error creating command socket"); mslog(&s, NULL, LOG_ERR, "Error creating command socket");
close(fd); close(fd);
break; break;
} }
@@ -525,7 +715,7 @@ int main(int argc, char** argv)
if (pid == 0) { /* child */ if (pid == 0) { /* child */
/* Drop privileges after this point */ /* Drop privileges after this point */
drop_privileges(&config); drop_privileges(&s);
/* close any open descriptors before /* close any open descriptors before
* running the server * running the server
@@ -536,6 +726,7 @@ int main(int argc, char** argv)
ws.config = &config; ws.config = &config;
ws.cmd_fd = cmd_fd[1]; ws.cmd_fd = cmd_fd[1];
ws.tun_fd = -1; ws.tun_fd = -1;
ws.udp_fd = -1;
ws.conn_fd = fd; ws.conn_fd = fd;
ws.creds = &creds; ws.creds = &creds;
@@ -562,6 +753,12 @@ fork_failed:
} }
close(cmd_fd[1]); close(cmd_fd[1]);
close(fd); close(fd);
} else if (set && ltmp->socktype == SOCK_DGRAM) {
/* connection on UDP port */
ret = forward_udp_to_owner(&s, ltmp);
if (ret < 0) {
mslog(&s, NULL, LOG_INFO, "Could not determine the owner of received UDP packet");
}
} }
} }
@@ -586,7 +783,7 @@ fork_failed:
need_maintainance = 0; need_maintainance = 0;
pid = fork(); pid = fork();
if (pid == 0) { /* child */ if (pid == 0) { /* child */
syslog(LOG_INFO, "Performing maintainance"); mslog(&s, NULL, LOG_INFO, "Performing maintainance");
clear_lists(&s); clear_lists(&s);
expire_cookies(&s); expire_cookies(&s);

View File

@@ -14,6 +14,12 @@ int cmd_parser (int argc, char **argv, struct cfg_st* config);
struct listener_st { struct listener_st {
struct list_node list; struct list_node list;
int fd; int fd;
int socktype;
struct sockaddr_storage addr; /* local socket address */
socklen_t addr_len;
int family;
int protocol;
}; };
struct listen_list_st { struct listen_list_st {
@@ -30,7 +36,10 @@ struct proc_st {
char username[MAX_USERNAME_SIZE]; /* the owner */ char username[MAX_USERNAME_SIZE]; /* the owner */
char hostname[MAX_HOSTNAME_SIZE]; /* the requested hostname */ char hostname[MAX_HOSTNAME_SIZE]; /* the requested hostname */
uint8_t cookie[COOKIE_SIZE]; /* the cookie associated with the session */ uint8_t cookie[COOKIE_SIZE]; /* the cookie associated with the session */
/* The DTLS session ID associated with the TLS session */
uint8_t session_id[GNUTLS_MAX_SESSION_ID]; uint8_t session_id[GNUTLS_MAX_SESSION_ID];
unsigned session_id_size; /* would act as a flag if session_id is set */
unsigned udp_fd_received;
/* the tun lease this process has */ /* the tun lease this process has */
struct lease_st* lease; struct lease_st* lease;
@@ -63,6 +72,8 @@ void expire_tls_sessions(main_server_st *s);
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,
cmd_resume_reply_t r, struct cmd_resume_fetch_reply_st * reply); cmd_resume_reply_t r, struct cmd_resume_fetch_reply_st * reply);
int send_udp_fd(main_server_st* s, struct proc_st* proc, void* cli_addr, socklen_t cli_addr_size, int fd);
int handle_resume_delete_req(main_server_st* s, struct proc_st* proc, int handle_resume_delete_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);
@@ -75,4 +86,11 @@ int handle_resume_store_req(main_server_st* s, struct proc_st *proc,
void expire_cookies(main_server_st* s); void expire_cookies(main_server_st* s);
void
__attribute__ ((format(printf, 4, 5)))
mslog(const main_server_st * s, const struct proc_st* proc,
int priority, const char *fmt, ...);
int open_tun(main_server_st* s, struct lease_st** l);
#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 February 7, 2013 at 12:56:29 AM by AutoGen 5.16 * It has been AutoGen-ed February 7, 2013 at 02:45:14 PM by AutoGen 5.16
* From the definitions ocserv-args.def * From the definitions ocserv-args.def
* and the template file options * and the template file options
* *

View File

@@ -74,8 +74,9 @@ auth = "pam"
#max-clients = 1024 #max-clients = 1024
max-clients = 16 max-clients = 16
# TCP port number # TCP and UDP port number
tcp-port = 3333 tcp-port = 3333
udp-port = 3333
# The key and the certificates of the server # The key and the certificates of the server
server-cert = /path/to/cert.pem server-cert = /path/to/cert.pem

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 February 7, 2013 at 12:56:29 AM by AutoGen 5.16 * It has been AutoGen-ed February 7, 2013 at 02:45:14 PM by AutoGen 5.16
* From the definitions ocserv-args.def * From the definitions ocserv-args.def
* and the template file options * and the template file options
* *

View File

@@ -17,8 +17,9 @@ max-clients = 4
# to authentication # to authentication
auth-timeout = 40 auth-timeout = 40
# TCP port number # TCP and UDP port number
tcp-port = 3333 tcp-port = 3333
udp-port = 3333
# Keepalive in seconds # Keepalive in seconds
keepalive = 90 keepalive = 90
@@ -64,8 +65,8 @@ device = vpns
# IP-REAL is the remote IP of the client, # IP-REAL is the remote IP of the client,
# IP-LOCAL is the local IP in the P-t-P connection and IP-REMOTE # IP-LOCAL is the local IP in the P-t-P connection and IP-REMOTE
# is the VPN client IP. # is the VPN client IP.
connect-script = /bin/echo #connect-script = /bin/echo
disconnect-script = /bin/echo #disconnect-script = /bin/echo
# The pool from which the VPN user IPs will be drawn from. # The pool from which the VPN user IPs will be drawn from.
ipv4-network = 192.168.1.0 ipv4-network = 192.168.1.0

174
src/tun.c
View File

@@ -31,8 +31,11 @@
#include <errno.h> #include <errno.h>
#include <cloexec.h> #include <cloexec.h>
#include <netdb.h>
#include <vpn.h> #include <vpn.h>
#include <tun.h> #include <tun.h>
#include <main.h>
#include <ccan/list/list.h> #include <ccan/list/list.h>
static int bignum_add1 (uint8_t * num, unsigned size) static int bignum_add1 (uint8_t * num, unsigned size)
@@ -60,9 +63,7 @@ static int bignum_add1 (uint8_t * num, unsigned size)
static int get_avail_network_addresses(const struct cfg_st *config, const struct lease_st *last4, static int get_avail_network_addresses(const struct cfg_st *config, const struct lease_st *last4,
const struct lease_st *last6, struct lease_st* lease) const struct lease_st *last6, struct lease_st* lease)
{ {
struct sockaddr_storage tmp, mask; struct sockaddr_storage tmp, mask, network;
struct sockaddr_in *t4;
struct sockaddr_in6 *t6;
unsigned i; unsigned i;
int ret; int ret;
@@ -73,13 +74,9 @@ static int get_avail_network_addresses(const struct cfg_st *config, const struct
memset(&tmp, 0, sizeof(tmp)); memset(&tmp, 0, sizeof(tmp));
/* read the network */ if (config->network.ipv4 && config->network.ipv4_netmask) {
if (last4 == NULL && (config->network.ipv4 && config->network.ipv4_netmask)) {
t4 = (void*)&tmp;
t4->sin_family = AF_INET;
ret = ret =
inet_pton(AF_INET, config->network.ipv4, SA_IN_P(t4)); inet_pton(AF_INET, config->network.ipv4, SA_IN_P(&network));
if (ret != 1) { if (ret != 1) {
syslog(LOG_ERR, "Error reading IP: %s\n", config->network.ipv4); syslog(LOG_ERR, "Error reading IP: %s\n", config->network.ipv4);
@@ -93,40 +90,37 @@ static int get_avail_network_addresses(const struct cfg_st *config, const struct
syslog(LOG_ERR, "Error reading mask: %s\n", config->network.ipv4_netmask); syslog(LOG_ERR, "Error reading mask: %s\n", config->network.ipv4_netmask);
return -1; return -1;
} }
/* mask the network */ /* mask the network (just in case it is wrong) */
for (i=0;i<sizeof(struct in_addr);i++) for (i=0;i<sizeof(struct in_addr);i++)
SA_IN_U8_P(t4)[i] &= (SA_IN_U8_P(&mask)[i]); SA_IN_U8_P(&network)[i] &= (SA_IN_U8_P(&mask)[i]);
memcpy(&tmp, &network, sizeof(tmp));
((struct sockaddr_in*)&tmp)->sin_family = AF_INET;
((struct sockaddr_in*)&network)->sin_family = AF_INET;
}
/* read the network */
if (last4 == NULL && (config->network.ipv4 && config->network.ipv4_netmask)) {
/* add one to get local IP */ /* add one to get local IP */
i = sizeof(struct in_addr)-1; i = sizeof(struct in_addr)-1;
SA_IN_U8_P(t4)[i]++; SA_IN_U8_P(&tmp)[i]++;
lease->lip4_len = sizeof(struct sockaddr_in); lease->lip4_len = sizeof(struct sockaddr_in);
memcpy(&lease->lip4, t4, lease->lip4_len); memcpy(&lease->lip4, &tmp, lease->lip4_len);
/* add one to get remote IP */ /* add one to get remote IP */
i = sizeof(struct in_addr)-1; i = sizeof(struct in_addr)-1;
SA_IN_U8_P(t4)[i]++; SA_IN_U8_P(&tmp)[i]++;
lease->rip4_len = sizeof(struct sockaddr_in); lease->rip4_len = sizeof(struct sockaddr_in);
memcpy(&lease->rip4, t4, lease->rip4_len); memcpy(&lease->rip4, &tmp, lease->rip4_len);
} else if (last4 != NULL) { } else if (last4 != NULL) {
t4 = (void*)&tmp;
t4->sin_family = AF_INET;
ret =
inet_pton(AF_INET, config->network.ipv4_netmask, SA_IN_P(&mask));
if (ret != 1) {
syslog(LOG_ERR, "Error reading mask: %s\n", config->network.ipv4_netmask);
return -1;
}
/* mask the network */
lease->lip4_len = last4->rip4_len; lease->lip4_len = last4->rip4_len;
memcpy(&lease->lip4, &last4->rip4, lease->rip4_len); memcpy(&lease->lip4, &last4->rip4, last4->rip4_len);
bignum_add1(SA_IN_U8_P(&lease->lip4), sizeof(struct in_addr)); bignum_add1(SA_IN_U8_P(&lease->lip4), sizeof(struct in_addr));
if (SA_IN_U8_P(&lease->lip4)[3] == 255) /* broadcast */ if (SA_IN_U8_P(&lease->lip4)[3] == 255) /* broadcast */
@@ -136,23 +130,21 @@ static int get_avail_network_addresses(const struct cfg_st *config, const struct
memcpy(&lease->rip4, &lease->lip4, lease->rip4_len); memcpy(&lease->rip4, &lease->lip4, lease->rip4_len);
bignum_add1(SA_IN_U8_P(&lease->rip4), sizeof(struct in_addr)); bignum_add1(SA_IN_U8_P(&lease->rip4), sizeof(struct in_addr));
/* mask the last IP with the complement of netmask */ /* mask the last IP with the netmask */
memcpy(&tmp, &lease->rip4, lease->rip4_len); memcpy(&tmp, &lease->rip4, lease->rip4_len);
for (i=0;i<sizeof(struct in_addr);i++) for (i=0;i<sizeof(struct in_addr);i++)
SA_IN_U8_P(t4)[i] &= ~(SA_IN_U8_P(&mask)[i]); SA_IN_U8_P(&tmp)[i] &= (SA_IN_U8_P(&mask)[i]);
if (memcmp(&tmp, &lease->rip4, lease->rip4_len) != 0) { /* the result should match the network */
syslog(LOG_ERR, "Reached limit of maximum IPs.\n"); if (memcmp(SA_IN_U8_P(&network), SA_IN_U8_P(&tmp), sizeof(struct in_addr)) != 0) {
syslog(LOG_ERR, "Reached limit of maximum (v4) IPs.\n");
return -1; return -1;
} }
} }
if (last6 == NULL && (config->network.ipv6 && config->network.ipv6_netmask)) { if (config->network.ipv6 && config->network.ipv6_netmask) {
t6 = (void*)&tmp;
t6->sin6_family = AF_INET6;
ret = ret =
inet_pton(AF_INET6, config->network.ipv6, SA_IN6_P(t6)); inet_pton(AF_INET6, config->network.ipv6, SA_IN6_P(&network));
if (ret != 1) { if (ret != 1) {
syslog(LOG_ERR, "Error reading IP: %s\n", config->network.ipv6); syslog(LOG_ERR, "Error reading IP: %s\n", config->network.ipv6);
@@ -169,49 +161,45 @@ static int get_avail_network_addresses(const struct cfg_st *config, const struct
/* mask the network */ /* mask the network */
for (i=0;i<sizeof(struct in6_addr);i++) for (i=0;i<sizeof(struct in6_addr);i++)
SA_IN6_U8_P(t6)[i] &= (SA_IN6_U8_P(&mask)[i]); SA_IN6_U8_P(&network)[i] &= (SA_IN6_U8_P(&mask)[i]);
memcpy(&tmp, &network, sizeof(tmp));
((struct sockaddr_in6*)&tmp)->sin6_family = AF_INET6;
((struct sockaddr_in6*)&network)->sin6_family = AF_INET6;
}
if (last6 == NULL && (config->network.ipv6 && config->network.ipv6_netmask)) {
/* add one to get local IP */ /* add one to get local IP */
i = sizeof(struct in6_addr)-1; i = sizeof(struct in6_addr)-1;
SA_IN6_U8_P(t6)[i]++; SA_IN6_U8_P(&tmp)[i]++;
lease->lip6_len = sizeof(struct sockaddr_in6); lease->lip6_len = sizeof(struct sockaddr_in6);
memcpy(&lease->lip6, t6, lease->lip6_len); memcpy(&lease->lip6, &tmp, lease->lip6_len);
/* add one to get remote IP */ /* add one to get remote IP */
i = sizeof(struct in6_addr)-1; i = sizeof(struct in6_addr)-1;
SA_IN6_U8_P(t6)[i]++; SA_IN6_U8_P(&tmp)[i]++;
lease->rip6_len = sizeof(struct sockaddr_in6); lease->rip6_len = sizeof(struct sockaddr_in6);
memcpy(&lease->rip6, t6, lease->rip6_len); memcpy(&lease->rip6, &tmp, lease->rip6_len);
} else if (last6 != NULL) { } else if (last6 != NULL) {
t6 = (void*)&tmp;
t6->sin6_family = AF_INET6;
ret =
inet_pton(AF_INET6, config->network.ipv6_netmask, SA_IN6_P(&mask));
if (ret != 1) {
syslog(LOG_ERR, "Error reading mask: %s\n", config->network.ipv6_netmask);
return -1;
}
/* mask the network */
lease->lip6_len = last6->rip6_len; lease->lip6_len = last6->rip6_len;
memcpy(&lease->lip6, &last6->rip6, lease->rip6_len); memcpy(&lease->lip6, &last6->rip6, last6->rip6_len);
bignum_add1(SA_IN6_U8_P(&lease->lip6), sizeof(struct in6_addr)); bignum_add1(SA_IN6_U8_P(&lease->lip6), sizeof(struct in6_addr));
lease->rip6_len = last6->rip6_len; lease->rip6_len = last6->rip6_len;
memcpy(&lease->rip6, &lease->lip6, lease->rip6_len); memcpy(&lease->rip6, &lease->lip6, lease->rip6_len);
bignum_add1(SA_IN6_U8_P(&lease->rip6), sizeof(struct in6_addr)); bignum_add1(SA_IN6_U8_P(&lease->rip6), sizeof(struct in6_addr));
/* mask the last IP with the complement of netmask */ /* mask the last IP with the netmask */
memcpy(&tmp, &lease->rip6, lease->rip6_len); memcpy(&tmp, &lease->rip6, lease->rip6_len);
for (i=0;i<sizeof(struct in6_addr);i++) for (i=0;i<sizeof(struct in6_addr);i++)
SA_IN6_U8_P(t6)[i] &= ~(SA_IN6_U8_P(&mask)[i]); SA_IN6_U8_P(&tmp)[i] &= (SA_IN6_U8_P(&mask)[i]);
if (memcmp(&tmp, &lease->rip6, lease->rip6_len) != 0) { /* the result should match the network */
syslog(LOG_ERR, "Reached limit of maximum IPs.\n"); if (memcmp(SA_IN6_U8_P(&network), SA_IN6_U8_P(&tmp), sizeof(struct in6_addr)) != 0) {
syslog(LOG_ERR, "Reached limit of maximum (v6) IPs.\n");
return -1; return -1;
} }
} }
@@ -230,7 +218,7 @@ static int get_avail_network_addresses(const struct cfg_st *config, const struct
return 0; return 0;
} }
static int set_network_info( const struct lease_st *lease) 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;
@@ -248,7 +236,7 @@ static int set_network_info( const struct lease_st *lease)
ret = ioctl(fd, SIOCSIFADDR, &ifr); ret = ioctl(fd, SIOCSIFADDR, &ifr);
if (ret != 0) { if (ret != 0) {
syslog(LOG_ERR, "%s: Error setting IPv4.\n", lease->name); mslog(s, NULL, LOG_ERR, "%s: Error setting IPv4.\n", lease->name);
} }
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
@@ -258,7 +246,7 @@ static int set_network_info( const struct lease_st *lease)
ret = ioctl(fd, SIOCSIFDSTADDR, &ifr); ret = ioctl(fd, SIOCSIFDSTADDR, &ifr);
if (ret != 0) { if (ret != 0) {
syslog(LOG_ERR, "%s: Error setting DST IPv4.\n", lease->name); mslog(s, NULL, LOG_ERR, "%s: Error setting DST IPv4.\n", lease->name);
} }
} }
@@ -271,7 +259,7 @@ static int set_network_info( const struct lease_st *lease)
ret = ioctl(fd, SIOCSIFADDR, &ifr); ret = ioctl(fd, SIOCSIFADDR, &ifr);
if (ret != 0) { if (ret != 0) {
syslog(LOG_ERR, "%s: Error setting IPv6.\n", lease->name); mslog(s, NULL, LOG_ERR, "%s: Error setting IPv6.\n", lease->name);
} }
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
@@ -281,12 +269,12 @@ static int set_network_info( const struct lease_st *lease)
ret = ioctl(fd, SIOCSIFDSTADDR, &ifr); ret = ioctl(fd, SIOCSIFDSTADDR, &ifr);
if (ret != 0) { if (ret != 0) {
syslog(LOG_ERR, "%s: Error setting DST IPv6.\n", lease->name); mslog(s, NULL, LOG_ERR, "%s: Error setting DST IPv6.\n", lease->name);
} }
} }
if (lease->lip6_len == 0 && lease->lip4_len == 0) { if (lease->lip6_len == 0 && lease->lip4_len == 0) {
syslog(LOG_ERR, "%s: Could not set any IP.\n", lease->name); mslog(s, NULL, LOG_ERR, "%s: Could not set any IP.\n", lease->name);
ret = -1; ret = -1;
} else } else
ret = 0; ret = 0;
@@ -299,7 +287,7 @@ static int set_network_info( const struct lease_st *lease)
ret = ioctl(fd, SIOCSIFFLAGS, &ifr); ret = ioctl(fd, SIOCSIFFLAGS, &ifr);
if (ret != 0) { if (ret != 0) {
syslog(LOG_ERR, "%s: Could not bring up interface.\n", lease->name); mslog(s, NULL, LOG_ERR, "%s: Could not bring up interface.\n", lease->name);
} }
close(fd); close(fd);
@@ -307,7 +295,7 @@ static int set_network_info( const struct lease_st *lease)
} }
int open_tun(const struct cfg_st *config, struct tun_st* tun, struct lease_st** l) int open_tun(main_server_st* s, struct lease_st** l)
{ {
int tunfd, ret, e; int tunfd, ret, e;
struct ifreq ifr; struct ifreq ifr;
@@ -315,27 +303,28 @@ int open_tun(const struct cfg_st *config, struct tun_st* tun, struct lease_st**
struct lease_st *lease = NULL; struct lease_st *lease = NULL;
struct lease_st *last4, *tmp; struct lease_st *last4, *tmp;
struct lease_st *last6; struct lease_st *last6;
unsigned current = s->tun->total;
if (list_empty(&tun->head)) { if (list_empty(&s->tun->head)) {
lease = calloc(1, sizeof(*lease)); lease = calloc(1, sizeof(*lease));
if (lease == NULL) if (lease == NULL)
return -1; return -1;
/* find the first IP address */ /* find the first IP address */
ret = get_avail_network_addresses(config, NULL, NULL, lease); ret = get_avail_network_addresses(s->config, NULL, NULL, lease);
if (ret < 0) { if (ret < 0) {
free(lease); free(lease);
return -1; return -1;
} }
/* Add into the list */ /* Add into the list */
list_add_tail( &tun->head, &lease->list); list_add_tail( &s->tun->head, &lease->list);
tun->total++; s->tun->total++;
} else { } else {
last4 = last6 = NULL; last4 = last6 = NULL;
/* try to re-use an address */ /* try to re-use an address */
list_for_each(&tun->head, tmp, list) { list_for_each(&s->tun->head, tmp, list) {
if (tmp->in_use == 0) { if (tmp->in_use == 0) {
lease = tmp; lease = tmp;
break; break;
@@ -347,26 +336,27 @@ int open_tun(const struct cfg_st *config, struct tun_st* tun, struct lease_st**
if (lease == NULL) if (lease == NULL)
return -1; return -1;
list_for_each_rev(&tun->head, tmp, list) { list_for_each_rev(&s->tun->head, tmp, list) {
if (tmp->rip4_len > 0) if (last4 == NULL && tmp->rip4_len > 0)
last4 = tmp; last4 = tmp;
if (tmp->rip6_len > 0)
if (last6 == NULL && tmp->rip6_len > 0)
last6 = tmp; last6 = tmp;
if (last4 && last6) if (last4 && last6)
break; break;
} }
ret = get_avail_network_addresses(config, last4, last6, lease); ret = get_avail_network_addresses(s->config, last4, last6, lease);
if (ret < 0) { if (ret < 0) {
free(lease); free(lease);
return -1; return -1;
} }
/* Add into the list */ /* Add into the list */
list_add_tail( &tun->head, &lease->list); list_add_tail( &s->tun->head, &lease->list);
tun->total++; s->tun->total++;
} }
} }
@@ -376,7 +366,7 @@ int open_tun(const struct cfg_st *config, struct tun_st* tun, struct lease_st**
tunfd = open("/dev/net/tun", O_RDWR); tunfd = open("/dev/net/tun", O_RDWR);
if (tunfd < 0) { if (tunfd < 0) {
int e = errno; int e = errno;
syslog(LOG_ERR, "Can't open /dev/net/tun: %s\n", mslog(s, NULL, LOG_ERR, "Can't open /dev/net/tun: %s\n",
strerror(e)); strerror(e));
return -1; return -1;
} }
@@ -386,39 +376,39 @@ int open_tun(const struct cfg_st *config, struct tun_st* tun, struct lease_st**
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;
snprintf(lease->name, sizeof(lease->name), "%s%u", config->network.name, 0); snprintf(lease->name, sizeof(lease->name), "%s%u", s->config->network.name, current);
memcpy(ifr.ifr_name, lease->name, sizeof(ifr.ifr_name)); memcpy(ifr.ifr_name, lease->name, sizeof(ifr.ifr_name));
if (ioctl(tunfd, TUNSETIFF, (void *) &ifr) < 0) { if (ioctl(tunfd, TUNSETIFF, (void *) &ifr) < 0) {
e = errno; e = errno;
syslog(LOG_ERR, "TUNSETIFF: %s\n", strerror(e)); mslog(s, NULL, LOG_ERR, "%s: TUNSETIFF: %s\n", lease->name, strerror(e));
goto fail; goto fail;
} }
if (config->uid != -1) { if (s->config->uid != -1) {
t = config->uid; t = s->config->uid;
ret = ioctl(tunfd, TUNSETOWNER, t); ret = ioctl(tunfd, TUNSETOWNER, t);
if (ret < 0) { if (ret < 0) {
e = errno; e = errno;
syslog(LOG_INFO, "TUNSETOWNER: %s\n", mslog(s, NULL, LOG_INFO, "%s: TUNSETOWNER: %s\n",
strerror(e)); lease->name, strerror(e));
goto fail; goto fail;
} }
} }
if (config->gid != -1) { if (s->config->gid != -1) {
t = config->uid; t = s->config->uid;
ret = ioctl(tunfd, TUNSETGROUP, t); ret = ioctl(tunfd, TUNSETGROUP, t);
if (ret < 0) { if (ret < 0) {
e = errno; e = errno;
syslog(LOG_ERR, "TUNSETGROUP: %s\n", mslog(s, NULL, LOG_ERR, "%s: TUNSETGROUP: %s\n",
strerror(e)); lease->name, strerror(e));
goto fail; goto fail;
} }
} }
/* set IP/mask */ /* set IP/mask */
ret = set_network_info(lease); ret = set_network_info(s, lease);
if (ret < 0) { if (ret < 0) {
goto fail; goto fail;
} }

View File

@@ -48,6 +48,4 @@ inline static void tun_st_deinit(struct tun_st* ts)
} }
} }
int open_tun(const struct cfg_st *config, struct tun_st* tun, struct lease_st **lease);
#endif #endif

View File

@@ -53,6 +53,7 @@ struct vpn_st {
struct cfg_st { struct cfg_st {
const char *name; const char *name;
unsigned int port; unsigned int port;
unsigned int udp_port;
const char *cert; const char *cert;
const char *key; const char *key;
const char *ca; const char *ca;
@@ -102,4 +103,6 @@ const char *human_addr(const struct sockaddr *sa, socklen_t salen,
#define SA_IN_PORT(p) (((struct sockaddr_in *)(p))->sin_port) #define SA_IN_PORT(p) (((struct sockaddr_in *)(p))->sin_port)
#define SA_IN6_PORT(p) (((struct sockaddr_in6 *)(p))->sin6_port) #define SA_IN6_PORT(p) (((struct sockaddr_in6 *)(p))->sin6_port)
#define SA_IN_P_GENERIC(addr, size) ((size==sizeof(struct sockaddr_in))?SA_IN_U8_P(addr):SA_IN6_U8_P(addr))
#define SA_IN_SIZE(size) ((size==sizeof(struct sockaddr_in))?sizeof(struct in_addr):sizeof(struct in6_addr))
#endif #endif

View File

@@ -157,8 +157,7 @@ static int recv_auth_reply(worker_st *ws)
uint8_t cmd = 0; uint8_t cmd = 0;
struct cmd_auth_reply_st resp; struct cmd_auth_reply_st resp;
struct msghdr hdr; struct msghdr hdr;
int ret; int ret, cmdlen;
union { union {
struct cmsghdr cm; struct cmsghdr cm;
char control[CMSG_SPACE(sizeof(int))]; char control[CMSG_SPACE(sizeof(int))];
@@ -179,15 +178,25 @@ static int recv_auth_reply(worker_st *ws)
hdr.msg_controllen = sizeof(control_un.control); hdr.msg_controllen = sizeof(control_un.control);
ret = recvmsg( ws->cmd_fd, &hdr, 0); ret = recvmsg( ws->cmd_fd, &hdr, 0);
if (ret < sizeof(resp)+1) {
oclog(ws, LOG_ERR, "Received incorrect data (%d, expected %d) from main", ret, (int)sizeof(resp)+1); cmdlen = ret;
if (cmdlen < 2) {
oclog(ws, LOG_ERR, "Received incorrect data (%d, expected %d) from main", cmdlen, (int)2);
return -1; return -1;
} }
if (cmd != AUTH_REP) if (cmd != AUTH_REP)
return -1; return -1;
cmdlen--;
switch(resp.reply) { switch(resp.reply) {
case REP_AUTH_OK: case REP_AUTH_OK:
if (cmdlen < sizeof(resp)) {
oclog(ws, LOG_ERR, "Received incorrect data (%d, expected %d) from main", ret, (int)sizeof(resp)+1);
return -1;
}
if ( (cmptr = CMSG_FIRSTHDR(&hdr)) != NULL && cmptr->cmsg_len == CMSG_LEN(sizeof(int))) { if ( (cmptr = CMSG_FIRSTHDR(&hdr)) != NULL && cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
if (cmptr->cmsg_level != SOL_SOCKET) if (cmptr->cmsg_level != SOL_SOCKET)
return -1; return -1;

View File

@@ -237,57 +237,11 @@ char* tmp = malloc(length+1);
static int setup_dtls_connection(struct worker_st *ws) static int setup_dtls_connection(struct worker_st *ws)
{ {
int ret, e; int ret;
gnutls_session_t session; gnutls_session_t session;
struct sockaddr_storage cli_addr;
socklen_t cli_addr_size;
uint8_t buffer[512];
ssize_t buffer_size;
gnutls_datum_t master = { ws->master_secret, sizeof(ws->master_secret) }; gnutls_datum_t master = { ws->master_secret, sizeof(ws->master_secret) };
gnutls_datum_t sid = { ws->session_id, sizeof(ws->session_id) }; gnutls_datum_t sid = { ws->session_id, sizeof(ws->session_id) };
unsigned port;
/* first receive from the correct client and connect socket */
cli_addr_size = sizeof(cli_addr);
ret = recvfrom(ws->udp_fd, buffer, sizeof(buffer), MSG_PEEK, (void*)&cli_addr, &cli_addr_size);
if (ret < 0) {
oclog(ws, LOG_ERR, "Error receiving in UDP socket");
return -1;
}
if (cli_addr_size == sizeof(struct sockaddr_in6)) {
port = SA_IN6_PORT(&cli_addr);
} else {
port = SA_IN_PORT(&cli_addr);
}
port = ntohs(port);
buffer_size = ret;
if ( (ws->remote_addr_len == sizeof(struct sockaddr_in) && memcmp(SA_IN_P(&cli_addr),
SA_IN_P(&ws->remote_addr), sizeof(struct in_addr)) == 0) ||
(ws->remote_addr_len == sizeof(struct sockaddr_in6) && memcmp(SA_IN6_P(&cli_addr),
SA_IN6_P(&ws->remote_addr), sizeof(struct in6_addr)) == 0)) {
/* connect to host */
#if 1
oclog(ws, LOG_ERR, "Connecting to UDP port %u", port);
ret = connect(ws->udp_fd, (void*)&cli_addr, cli_addr_size);
if (ret < 0) {
e = errno;
oclog(ws, LOG_ERR, "Error connecting: %s", strerror(e));
return -1;
}
#endif
} else {
/* received packet from unknown host */
oclog(ws, LOG_ERR, "Received UDP packet from unexpected host; discarding it");
recv(ws->udp_fd, buffer, buffer_size, 0);
return 0;
}
/* DTLS cookie verified. /* DTLS cookie verified.
* Initialize session. * Initialize session.
*/ */
@@ -354,6 +308,10 @@ void vpn_server(struct worker_st* ws)
syslog(LOG_INFO, "Accepted connection from %s", syslog(LOG_INFO, "Accepted connection from %s",
human_addr((void*)&ws->remote_addr, ws->remote_addr_len, human_addr((void*)&ws->remote_addr, ws->remote_addr_len,
buf, sizeof(buf))); buf, sizeof(buf)));
if (ws->remote_addr_len == sizeof(struct sockaddr_in))
ws->proto = AF_INET;
else
ws->proto = AF_INET6;
/* initialize the session */ /* initialize the session */
ret = gnutls_init(&session, GNUTLS_SERVER); ret = gnutls_init(&session, GNUTLS_SERVER);
@@ -631,103 +589,6 @@ fail:
return ret; return ret;
} }
static int open_udp_port(worker_st *ws)
{
int s, e, ret;
struct sockaddr_storage si;
struct sockaddr_storage stcp;
socklen_t len;
int proto;
len = sizeof(stcp);
ret = getsockname(ws->conn_fd, (void*)&stcp, &len);
if (ret == -1) {
e = errno;
oclog(ws, LOG_ERR, "Error in getsockname: %s", strerror(e));
return -1;
}
proto = ((struct sockaddr*)&stcp)->sa_family;
s = socket(proto, SOCK_DGRAM, IPPROTO_UDP);
if (s == -1) {
e = errno;
oclog(ws, LOG_ERR, "Could not open a UDP socket: %s", strerror(e));
return -1;
}
/* listen on the same IP the client connected at */
memset(&si, 0, sizeof(si));
((struct sockaddr*)&si)->sa_family = proto;
if (proto == AF_INET) {
memcpy(SA_IN_P(&si), SA_IN_P(&stcp), sizeof(*SA_IN_P(&si)));
} else if (proto == AF_INET6) {
memcpy(SA_IN6_P(&si), SA_IN6_P(&stcp), sizeof(*SA_IN6_P(&si)));
} else {
oclog(ws, LOG_ERR, "Unknown protocol family: %d", proto);
goto fail;
}
/* make sure we don't fragment packets */
#if defined(IP_DONTFRAG)
ret = 1;
if (setsockopt (s, IPPROTO_IP, IP_DONTFRAG,
(const void *) &ret, sizeof (ret)) < 0)
if (ret < 0) {
e = errno;
oclog(ws, LOG_ERR, "Error in setsockopt (IP_DF): %s", strerror(e));
goto fail;
}
#elif defined(IP_MTU_DISCOVER)
ret = IP_PMTUDISC_DO;
if (setsockopt (s, IPPROTO_IP, IP_MTU_DISCOVER,
(const void *) &ret, sizeof (ret)) < 0)
if (ret < 0) {
e = errno;
oclog(ws, LOG_ERR, "Error in setsockopt (IP_MTU_DISCOVER): %s", strerror(e));
goto fail;
}
#endif
#ifdef SO_REUSEPORT
ret = 1;
ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &ret, sizeof(ret));
if (ret < 0) {
e = errno;
oclog(ws, LOG_ERR, "Error in setsockopt (SO_REUSEPORT): %s", strerror(e));
goto fail;
}
#endif
ret = bind(s, (void*)&si, len);
if (ret == -1) {
e = errno;
oclog(ws, LOG_ERR, "Could not bind on a UDP port: %s", strerror(e));
goto fail;
}
len = sizeof(si);
ret = getsockname(s, (void*)&si, &len);
if (ret == -1) {
e = errno;
oclog(ws, LOG_ERR, "Could not obtain UDP port number: %s", strerror(e));
goto fail;
}
if (proto == AF_INET) {
ws->udp_port = ntohs(SA_IN_PORT(&si));
} else {
ws->udp_port = ntohs(SA_IN6_PORT(&si));
}
ws->udp_port_proto = proto;
ws->udp_fd = s;
return 0;
fail:
close(s);
return -1;
}
static ssize_t tun_write(int sockfd, const void *buf, size_t len) static ssize_t tun_write(int sockfd, const void *buf, size_t len)
{ {
int left = len; int left = len;
@@ -845,7 +706,7 @@ unsigned mtu_overhead, dtls_mtu = 0;
} }
if (ws->config->network.name == NULL) { if (ws->config->network.name == NULL) {
oclog(ws, LOG_ERR, "No networks are configured. Rejecting client"); oclog(ws, LOG_ERR, "No networks are configured; rejecting client");
tls_puts(ws->session, "HTTP/1.1 503 Service Unavailable\r\n"); tls_puts(ws->session, "HTTP/1.1 503 Service Unavailable\r\n");
tls_puts(ws->session, "X-Reason: Server configuration error\r\n\r\n"); tls_puts(ws->session, "X-Reason: Server configuration error\r\n\r\n");
return -1; return -1;
@@ -869,12 +730,7 @@ unsigned mtu_overhead, dtls_mtu = 0;
ws->udp_state = UP_DISABLED; ws->udp_state = UP_DISABLED;
if (req->master_secret_set != 0) { if (req->master_secret_set != 0) {
memcpy(ws->master_secret, req->master_secret, TLS_MASTER_SIZE); memcpy(ws->master_secret, req->master_secret, TLS_MASTER_SIZE);
ws->udp_state = UP_SETUP;
ret = open_udp_port(ws);
if (ret < 0) {
oclog(ws, LOG_NOTICE, "Could not open UDP port");
} else
ws->udp_state = UP_SETUP;
} }
@@ -914,12 +770,13 @@ unsigned mtu_overhead, dtls_mtu = 0;
} }
tls_printf(ws->session, "X-DTLS-Session-ID: %s\r\n", buffer); tls_printf(ws->session, "X-DTLS-Session-ID: %s\r\n", buffer);
tls_printf(ws->session, "X-DTLS-Port: %u\r\n", ws->udp_port); tls_printf(ws->session, "X-DTLS-Port: %u\r\n", ws->config->udp_port);
tls_puts(ws->session, "X-DTLS-ReKey-Time: 86400\r\n"); tls_puts(ws->session, "X-DTLS-ReKey-Time: 86400\r\n");
tls_printf(ws->session, "X-DTLS-Keepalive: %u\r\n", ws->config->keepalive); tls_printf(ws->session, "X-DTLS-Keepalive: %u\r\n", ws->config->keepalive);
tls_puts(ws->session, "X-DTLS-CipherSuite: "OPENSSL_CIPHERSUITE"\r\n"); tls_puts(ws->session, "X-DTLS-CipherSuite: "OPENSSL_CIPHERSUITE"\r\n");
if (ws->udp_port_proto == AF_INET) /* assume that if IPv6 is used over TCP then the same would be used over UDP */
if (ws->proto == AF_INET)
mtu_overhead = 20+8; mtu_overhead = 20+8;
else else
mtu_overhead = 40+8; mtu_overhead = 40+8;
@@ -940,7 +797,7 @@ unsigned mtu_overhead, dtls_mtu = 0;
max = MAX(ws->cmd_fd,ws->conn_fd); max = MAX(ws->cmd_fd,ws->conn_fd);
max = MAX(max,ws->tun_fd); max = MAX(max,ws->tun_fd);
if (ws->udp_state != UP_DISABLED) { if (ws->udp_state != UP_DISABLED && ws->udp_fd != -1) {
FD_SET(ws->udp_fd, &rfds); FD_SET(ws->udp_fd, &rfds);
max = MAX(max,ws->udp_fd); max = MAX(max,ws->udp_fd);
} }
@@ -1046,7 +903,7 @@ unsigned mtu_overhead, dtls_mtu = 0;
} }
} }
if (ws->udp_state != UP_DISABLED && (FD_ISSET(ws->udp_fd, &rfds) || dtls_pending != 0)) { if (ws->udp_fd != -1 && ws->udp_state != UP_DISABLED && (FD_ISSET(ws->udp_fd, &rfds) || dtls_pending != 0)) {
switch (ws->udp_state) { switch (ws->udp_state) {
case UP_ACTIVE: case UP_ACTIVE:
@@ -1135,10 +992,16 @@ int handle_worker_commands(struct worker_st *ws)
uint8_t cmd; uint8_t cmd;
struct msghdr hdr; struct msghdr hdr;
union { union {
char x[20]; char x[32];
struct sockaddr_storage ss;
} cmd_data; } cmd_data;
int ret; union {
/*int cmd_data_len;*/ struct cmsghdr cm;
char control[CMSG_SPACE(sizeof(int))];
} control_un;
struct cmsghdr *cmptr;
int ret, e;
int cmd_data_len;
memset(&cmd_data, 0, sizeof(cmd_data)); memset(&cmd_data, 0, sizeof(cmd_data));
@@ -1151,6 +1014,9 @@ int handle_worker_commands(struct worker_st *ws)
memset(&hdr, 0, sizeof(hdr)); memset(&hdr, 0, sizeof(hdr));
hdr.msg_iov = iov; hdr.msg_iov = iov;
hdr.msg_iovlen = 2; hdr.msg_iovlen = 2;
hdr.msg_control = control_un.control;
hdr.msg_controllen = sizeof(control_un.control);
ret = recvmsg( ws->cmd_fd, &hdr, 0); ret = recvmsg( ws->cmd_fd, &hdr, 0);
if (ret == -1) { if (ret == -1) {
@@ -1162,11 +1028,39 @@ int handle_worker_commands(struct worker_st *ws)
exit(1); exit(1);
} }
/*cmd_data_len = ret - 1;*/ cmd_data_len = ret - 1;
switch(cmd) { switch(cmd) {
case CMD_TERMINATE: case CMD_TERMINATE:
exit(0); exit(0);
case CMD_UDP_FD:
if ( (cmptr = CMSG_FIRSTHDR(&hdr)) != NULL && cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
if (cmptr->cmsg_level != SOL_SOCKET)
return -1;
if (cmptr->cmsg_type != SCM_RIGHTS)
return -1;
memcpy(&ws->udp_fd, CMSG_DATA(cmptr), sizeof(int));
if (cmd_data_len > 0) {
ret = connect(ws->udp_fd, (void*)&cmd_data.ss, cmd_data_len);
if (ret == -1) {
e = errno;
oclog(ws, LOG_ERR, "connect(): %s", strerror(e));
goto udp_fd_fail;
}
} else {
oclog(ws, LOG_ERR, "Didn't receive peer's UDP address");
goto udp_fd_fail;
}
return 0;
udp_fd_fail:
close(ws->udp_fd);
ws->udp_fd = -1;
return -1;
} else {
return -1;
}
break;
default: default:
oclog(ws, LOG_ERR, "Unknown CMD 0x%x", (unsigned)cmd); oclog(ws, LOG_ERR, "Unknown CMD 0x%x", (unsigned)cmd);
exit(1); exit(1);

View File

@@ -44,12 +44,11 @@ typedef struct worker_st {
struct sockaddr_storage remote_addr; /* peer's address */ struct sockaddr_storage remote_addr; /* peer's address */
socklen_t remote_addr_len; socklen_t remote_addr_len;
int proto; /* AF_INET or AF_INET6 */
/* set after authentication */ /* set after authentication */
int udp_fd; int udp_fd;
udp_port_state_t udp_state; udp_port_state_t udp_state;
unsigned int udp_port;
int udp_port_proto;
/* for mtu trials */ /* for mtu trials */
unsigned last_good_mtu; unsigned last_good_mtu;