mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-02-10 00:37:00 +08:00
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:
1
TODO
1
TODO
@@ -1,4 +1,3 @@
|
||||
* Use a single UDP port
|
||||
* Add a simple username/password back-end
|
||||
* Certificate authentication to the main process (can it be done without
|
||||
moving the TLS handshake over the main thread?)
|
||||
|
||||
@@ -125,6 +125,7 @@ unsigned j;
|
||||
READ_STRING("listen-host", config->name, 0);
|
||||
|
||||
READ_NUMERIC("tcp-port", config->port, 1);
|
||||
READ_NUMERIC("udp-port", config->udp_port, 0);
|
||||
READ_NUMERIC("keepalive", config->keepalive, 0);
|
||||
|
||||
READ_STRING("server-cert", config->cert, 1);
|
||||
@@ -200,6 +201,9 @@ static void check_cfg( struct cfg_st *config)
|
||||
if (config->keepalive == 0)
|
||||
config->keepalive = 30;
|
||||
|
||||
if (config->udp_port == 0)
|
||||
config->udp_port = config->port;
|
||||
|
||||
if (config->priorities == NULL)
|
||||
config->priorities = "NORMAL:%SERVER_PRECEDENCE:%COMPAT";
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ typedef enum {
|
||||
RESUME_DELETE_REQ,
|
||||
RESUME_FETCH_REQ,
|
||||
RESUME_FETCH_REP,
|
||||
CMD_UDP_FD,
|
||||
CMD_TERMINATE,
|
||||
} cmd_request_t;
|
||||
|
||||
|
||||
32
src/log.c
32
src/log.c
@@ -92,3 +92,35 @@ void __attribute__ ((format(printf, 3, 4)))
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ static int send_auth_reply(main_server_st* s, struct proc_st* proc,
|
||||
hdr.msg_iovlen++;
|
||||
|
||||
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++;
|
||||
|
||||
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->username, sc.username, sizeof(proc->username));
|
||||
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)
|
||||
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));
|
||||
if (ret < 0)
|
||||
return -2;
|
||||
proc->session_id_size = sizeof( proc->session_id);
|
||||
|
||||
sc = calloc(1, sizeof(*sc));
|
||||
if (sc == NULL)
|
||||
@@ -180,7 +182,7 @@ unsigned username_set = 0;
|
||||
memcpy(proc->username, req->cert_user, MAX_USERNAME_SIZE);
|
||||
else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -190,7 +192,7 @@ unsigned username_set = 0;
|
||||
if (req->hostname[0] != 0)
|
||||
memcpy(proc->hostname, req->hostname, MAX_HOSTNAME_SIZE);
|
||||
|
||||
ret = open_tun(s->config, s->tun, lease);
|
||||
ret = open_tun(s, lease);
|
||||
if (ret < 0)
|
||||
ret = -1; /* sorry */
|
||||
}
|
||||
@@ -232,7 +234,7 @@ int handle_commands(main_server_st *s, struct proc_st* proc)
|
||||
ret = recvmsg( proc->fd, &hdr, 0);
|
||||
if (ret == -1) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -245,24 +247,24 @@ int handle_commands(main_server_st *s, struct proc_st* proc)
|
||||
switch(cmd) {
|
||||
case RESUME_STORE_REQ:
|
||||
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;
|
||||
}
|
||||
ret = handle_resume_store_req(s, proc, &cmd_data.sresume);
|
||||
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;
|
||||
|
||||
case RESUME_DELETE_REQ:
|
||||
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;
|
||||
}
|
||||
ret = handle_resume_delete_req(s, proc, &cmd_data.fresume);
|
||||
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;
|
||||
@@ -270,19 +272,19 @@ int handle_commands(main_server_st *s, struct proc_st* proc)
|
||||
struct cmd_resume_fetch_reply_st reply;
|
||||
|
||||
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;
|
||||
}
|
||||
ret = handle_resume_fetch_req(s, proc, &cmd_data.fresume, &reply);
|
||||
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);
|
||||
} else
|
||||
ret = send_resume_fetch_reply(s, proc, REP_RESUME_OK, &reply);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -293,14 +295,14 @@ int handle_commands(main_server_st *s, struct proc_st* proc)
|
||||
|
||||
if (cmd == AUTH_REQ) {
|
||||
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;
|
||||
}
|
||||
|
||||
ret = handle_auth_req(s, proc, &cmd_data.auth, &lease);
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -310,7 +312,7 @@ int handle_commands(main_server_st *s, struct proc_st* proc)
|
||||
if (ret == 0) {
|
||||
ret = user_connected(s, proc, lease);
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -336,17 +338,17 @@ int handle_commands(main_server_st *s, struct proc_st* proc)
|
||||
close(lease->fd);
|
||||
lease->fd = -1;
|
||||
} 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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,42 @@ int send_resume_fetch_reply(main_server_st* s, struct proc_st * proc,
|
||||
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,
|
||||
const struct cmd_resume_fetch_req_st * req)
|
||||
{
|
||||
|
||||
313
src/main.c
313
src/main.c
@@ -53,46 +53,31 @@ static void tls_log_func(int level, const char *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 listen_list_st *list, const char *node,
|
||||
int listen_port, int socktype)
|
||||
static
|
||||
int _listen_ports(struct cfg_st* config, struct addrinfo *res, struct listen_list_st *list)
|
||||
{
|
||||
struct addrinfo hints, *res, *ptr;
|
||||
char portname[6];
|
||||
struct addrinfo *ptr;
|
||||
int s, y;
|
||||
const char* type = NULL;
|
||||
char buf[512];
|
||||
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) {
|
||||
#ifndef HAVE_IPV6
|
||||
if (ptr->ai_family != AF_INET)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
if (ptr->ai_socktype == SOCK_STREAM)
|
||||
type = "TCP";
|
||||
else if (ptr->ai_socktype == SOCK_DGRAM)
|
||||
type = "UDP";
|
||||
else
|
||||
continue;
|
||||
|
||||
if (config->foreground != 0)
|
||||
fprintf(stderr, "listening on %s...\n",
|
||||
human_addr(ptr->ai_addr, ptr->ai_addrlen,
|
||||
fprintf(stderr, "listening (%s) on %s...\n",
|
||||
type, human_addr(ptr->ai_addr, ptr->ai_addrlen,
|
||||
buf, sizeof(buf)));
|
||||
|
||||
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
|
||||
|
||||
if (socktype == SOCK_STREAM) {
|
||||
if (ptr->ai_socktype == SOCK_STREAM) {
|
||||
y = 1;
|
||||
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
|
||||
(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;
|
||||
}
|
||||
} else {
|
||||
y = 1;
|
||||
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const void *) &y, sizeof(y));
|
||||
#if defined(IP_DONTFRAG)
|
||||
y = 1;
|
||||
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;
|
||||
}
|
||||
|
||||
if (socktype == SOCK_STREAM) {
|
||||
if (ptr->ai_socktype == SOCK_STREAM) {
|
||||
if (listen(s, 10) < 0) {
|
||||
perror("listen() failed");
|
||||
exit(1);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
tmp = calloc(1, sizeof(struct listener_st));
|
||||
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->total++;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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)
|
||||
{
|
||||
int status;
|
||||
@@ -171,7 +284,7 @@ pid_t pid;
|
||||
if (WEXITSTATUS(status) != 0 ||
|
||||
(WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV)) {
|
||||
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;
|
||||
@@ -248,36 +361,36 @@ static int verify_certificate_cb(gnutls_session_t session)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void drop_privileges(struct cfg_st *config)
|
||||
static void drop_privileges(main_server_st* s)
|
||||
{
|
||||
int ret, e;
|
||||
|
||||
if (config->chroot_dir) {
|
||||
ret = chroot(config->chroot_dir);
|
||||
if (s->config->chroot_dir) {
|
||||
ret = chroot(s->config->chroot_dir);
|
||||
if (ret != 0) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (config->gid != -1 && (getgid() == 0 || getegid() == 0)) {
|
||||
ret = setgid(config->gid);
|
||||
if (s->config->gid != -1 && (getgid() == 0 || getegid() == 0)) {
|
||||
ret = setgid(s->config->gid);
|
||||
if (ret < 0) {
|
||||
e = errno;
|
||||
syslog(LOG_ERR, "Cannot set gid to %d: %s\n",
|
||||
(int) config->gid, strerror(e));
|
||||
mslog(s, NULL, LOG_ERR, "Cannot set gid to %d: %s\n",
|
||||
(int) s->config->gid, strerror(e));
|
||||
exit(1);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (config->uid != -1 && (getuid() == 0 || geteuid() == 0)) {
|
||||
ret = setuid(config->uid);
|
||||
if (s->config->uid != -1 && (getuid() == 0 || geteuid() == 0)) {
|
||||
ret = setuid(s->config->uid);
|
||||
if (ret < 0) {
|
||||
e = errno;
|
||||
syslog(LOG_ERR, "Cannot set uid to %d: %s\n",
|
||||
(int) config->uid, strerror(e));
|
||||
mslog(s, NULL, LOG_ERR, "Cannot set uid to %d: %s\n",
|
||||
(int) s->config->uid, strerror(e));
|
||||
exit(1);
|
||||
|
||||
}
|
||||
@@ -335,6 +448,76 @@ static void handle_term(int signo)
|
||||
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 fd, pid, e;
|
||||
@@ -344,13 +527,14 @@ int main(int argc, char** argv)
|
||||
struct listener_st *ltmp;
|
||||
struct proc_st *ctmp, *cpos;
|
||||
struct tun_st tun;
|
||||
const char* perr;
|
||||
fd_set rd;
|
||||
int val, n = 0, ret;
|
||||
struct timeval tv;
|
||||
int cmd_fd[2];
|
||||
struct worker_st ws;
|
||||
struct cfg_st config;
|
||||
unsigned active_clients = 0;
|
||||
unsigned active_clients = 0, set;
|
||||
main_server_st s;
|
||||
|
||||
list_head_init(&clist.head);
|
||||
@@ -383,7 +567,7 @@ int main(int argc, char** argv)
|
||||
s.clist = &clist;
|
||||
|
||||
/* 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) {
|
||||
fprintf(stderr, "Cannot listen to specified ports\n");
|
||||
exit(1);
|
||||
@@ -413,6 +597,7 @@ int main(int argc, char** argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (config.cert_req != GNUTLS_CERT_IGNORE) {
|
||||
if (config.ca != NULL) {
|
||||
ret =
|
||||
gnutls_certificate_set_x509_trust_file(creds.xcred,
|
||||
@@ -435,13 +620,13 @@ int main(int argc, char** argv)
|
||||
GNUTLS_FATAL_ERR(ret);
|
||||
}
|
||||
|
||||
|
||||
if (config.cert_req != GNUTLS_CERT_IGNORE) {
|
||||
gnutls_certificate_set_verify_function(creds.xcred,
|
||||
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);
|
||||
|
||||
memset(&ws, 0, sizeof(ws));
|
||||
@@ -464,11 +649,14 @@ int main(int argc, char** argv)
|
||||
FD_ZERO(&rd);
|
||||
|
||||
list_for_each(&llist.head, ltmp, list) {
|
||||
if (ltmp->fd == -1) continue;
|
||||
|
||||
val = fcntl(ltmp->fd, F_GETFL, 0);
|
||||
if ((val == -1)
|
||||
|| (fcntl(ltmp->fd, F_SETFL, val | O_NONBLOCK) <
|
||||
0)) {
|
||||
perror("fcntl()");
|
||||
e = errno;
|
||||
mslog(&s, NULL, LOG_ERR, "fcntl() error: %s", strerror(e));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -489,18 +677,20 @@ int main(int argc, char** argv)
|
||||
|
||||
if (ret < 0) {
|
||||
e = errno;
|
||||
syslog(LOG_ERR, "Error in select(): %s",
|
||||
mslog(&s, NULL, LOG_ERR, "Error in select(): %s",
|
||||
strerror(e));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Check for new connections to accept */
|
||||
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);
|
||||
fd = accept(ltmp->fd, (void*)&ws.remote_addr, &ws.remote_addr_len);
|
||||
if (fd < 0) {
|
||||
syslog(LOG_ERR,
|
||||
mslog(&s, NULL, LOG_ERR,
|
||||
"Error in accept(): %s",
|
||||
strerror(errno));
|
||||
continue;
|
||||
@@ -509,14 +699,14 @@ int main(int argc, char** argv)
|
||||
|
||||
if (config.max_clients > 0 && active_clients >= config.max_clients) {
|
||||
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;
|
||||
}
|
||||
|
||||
/* Create a command socket */
|
||||
ret = socketpair(AF_UNIX, SOCK_STREAM, 0, cmd_fd);
|
||||
if (ret < 0) {
|
||||
syslog(LOG_ERR, "Error creating command socket");
|
||||
mslog(&s, NULL, LOG_ERR, "Error creating command socket");
|
||||
close(fd);
|
||||
break;
|
||||
}
|
||||
@@ -525,7 +715,7 @@ int main(int argc, char** argv)
|
||||
if (pid == 0) { /* child */
|
||||
|
||||
/* Drop privileges after this point */
|
||||
drop_privileges(&config);
|
||||
drop_privileges(&s);
|
||||
|
||||
/* close any open descriptors before
|
||||
* running the server
|
||||
@@ -536,6 +726,7 @@ int main(int argc, char** argv)
|
||||
ws.config = &config;
|
||||
ws.cmd_fd = cmd_fd[1];
|
||||
ws.tun_fd = -1;
|
||||
ws.udp_fd = -1;
|
||||
ws.conn_fd = fd;
|
||||
ws.creds = &creds;
|
||||
|
||||
@@ -562,6 +753,12 @@ fork_failed:
|
||||
}
|
||||
close(cmd_fd[1]);
|
||||
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;
|
||||
pid = fork();
|
||||
if (pid == 0) { /* child */
|
||||
syslog(LOG_INFO, "Performing maintainance");
|
||||
mslog(&s, NULL, LOG_INFO, "Performing maintainance");
|
||||
clear_lists(&s);
|
||||
|
||||
expire_cookies(&s);
|
||||
|
||||
18
src/main.h
18
src/main.h
@@ -14,6 +14,12 @@ int cmd_parser (int argc, char **argv, struct cfg_st* config);
|
||||
struct listener_st {
|
||||
struct list_node list;
|
||||
int fd;
|
||||
int socktype;
|
||||
|
||||
struct sockaddr_storage addr; /* local socket address */
|
||||
socklen_t addr_len;
|
||||
int family;
|
||||
int protocol;
|
||||
};
|
||||
|
||||
struct listen_list_st {
|
||||
@@ -30,7 +36,10 @@ struct proc_st {
|
||||
char username[MAX_USERNAME_SIZE]; /* the owner */
|
||||
char hostname[MAX_HOSTNAME_SIZE]; /* the requested hostname */
|
||||
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];
|
||||
unsigned session_id_size; /* would act as a flag if session_id is set */
|
||||
unsigned udp_fd_received;
|
||||
|
||||
/* the tun lease this process has */
|
||||
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,
|
||||
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,
|
||||
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
|
||||
__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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* 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
|
||||
* and the template file options
|
||||
*
|
||||
|
||||
@@ -74,8 +74,9 @@ auth = "pam"
|
||||
#max-clients = 1024
|
||||
max-clients = 16
|
||||
|
||||
# TCP port number
|
||||
# TCP and UDP port number
|
||||
tcp-port = 3333
|
||||
udp-port = 3333
|
||||
|
||||
# The key and the certificates of the server
|
||||
server-cert = /path/to/cert.pem
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* 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
|
||||
* and the template file options
|
||||
*
|
||||
|
||||
@@ -17,8 +17,9 @@ max-clients = 4
|
||||
# to authentication
|
||||
auth-timeout = 40
|
||||
|
||||
# TCP port number
|
||||
# TCP and UDP port number
|
||||
tcp-port = 3333
|
||||
udp-port = 3333
|
||||
|
||||
# Keepalive in seconds
|
||||
keepalive = 90
|
||||
@@ -64,8 +65,8 @@ device = vpns
|
||||
# IP-REAL is the remote IP of the client,
|
||||
# IP-LOCAL is the local IP in the P-t-P connection and IP-REMOTE
|
||||
# is the VPN client IP.
|
||||
connect-script = /bin/echo
|
||||
disconnect-script = /bin/echo
|
||||
#connect-script = /bin/echo
|
||||
#disconnect-script = /bin/echo
|
||||
|
||||
# The pool from which the VPN user IPs will be drawn from.
|
||||
ipv4-network = 192.168.1.0
|
||||
|
||||
168
src/tun.c
168
src/tun.c
@@ -31,8 +31,11 @@
|
||||
#include <errno.h>
|
||||
#include <cloexec.h>
|
||||
|
||||
#include <netdb.h>
|
||||
|
||||
#include <vpn.h>
|
||||
#include <tun.h>
|
||||
#include <main.h>
|
||||
#include <ccan/list/list.h>
|
||||
|
||||
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,
|
||||
const struct lease_st *last6, struct lease_st* lease)
|
||||
{
|
||||
struct sockaddr_storage tmp, mask;
|
||||
struct sockaddr_in *t4;
|
||||
struct sockaddr_in6 *t6;
|
||||
struct sockaddr_storage tmp, mask, network;
|
||||
unsigned i;
|
||||
int ret;
|
||||
|
||||
@@ -73,13 +74,9 @@ static int get_avail_network_addresses(const struct cfg_st *config, const struct
|
||||
|
||||
memset(&tmp, 0, sizeof(tmp));
|
||||
|
||||
/* read the network */
|
||||
if (last4 == NULL && (config->network.ipv4 && config->network.ipv4_netmask)) {
|
||||
t4 = (void*)&tmp;
|
||||
t4->sin_family = AF_INET;
|
||||
|
||||
if (config->network.ipv4 && config->network.ipv4_netmask) {
|
||||
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) {
|
||||
syslog(LOG_ERR, "Error reading IP: %s\n", config->network.ipv4);
|
||||
@@ -94,39 +91,36 @@ static int get_avail_network_addresses(const struct cfg_st *config, const struct
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* mask the network */
|
||||
/* mask the network (just in case it is wrong) */
|
||||
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 */
|
||||
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);
|
||||
memcpy(&lease->lip4, t4, lease->lip4_len);
|
||||
memcpy(&lease->lip4, &tmp, lease->lip4_len);
|
||||
|
||||
/* add one to get remote IP */
|
||||
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);
|
||||
memcpy(&lease->rip4, t4, lease->rip4_len);
|
||||
|
||||
memcpy(&lease->rip4, &tmp, lease->rip4_len);
|
||||
} 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;
|
||||
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));
|
||||
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);
|
||||
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);
|
||||
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) {
|
||||
syslog(LOG_ERR, "Reached limit of maximum IPs.\n");
|
||||
/* the result should match the network */
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (last6 == NULL && (config->network.ipv6 && config->network.ipv6_netmask)) {
|
||||
t6 = (void*)&tmp;
|
||||
t6->sin6_family = AF_INET6;
|
||||
|
||||
if (config->network.ipv6 && config->network.ipv6_netmask) {
|
||||
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) {
|
||||
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 */
|
||||
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 */
|
||||
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);
|
||||
memcpy(&lease->lip6, t6, lease->lip6_len);
|
||||
memcpy(&lease->lip6, &tmp, lease->lip6_len);
|
||||
|
||||
/* add one to get remote IP */
|
||||
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);
|
||||
memcpy(&lease->rip6, t6, lease->rip6_len);
|
||||
memcpy(&lease->rip6, &tmp, lease->rip6_len);
|
||||
} 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;
|
||||
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));
|
||||
|
||||
lease->rip6_len = last6->rip6_len;
|
||||
memcpy(&lease->rip6, &lease->lip6, lease->rip6_len);
|
||||
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);
|
||||
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) {
|
||||
syslog(LOG_ERR, "Reached limit of maximum IPs.\n");
|
||||
/* the result should match the network */
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -230,7 +218,7 @@ static int get_avail_network_addresses(const struct cfg_st *config, const struct
|
||||
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;
|
||||
int fd, ret;
|
||||
@@ -248,7 +236,7 @@ static int set_network_info( const struct lease_st *lease)
|
||||
|
||||
ret = ioctl(fd, SIOCSIFADDR, &ifr);
|
||||
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));
|
||||
@@ -258,7 +246,7 @@ static int set_network_info( const struct lease_st *lease)
|
||||
|
||||
ret = ioctl(fd, SIOCSIFDSTADDR, &ifr);
|
||||
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);
|
||||
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));
|
||||
@@ -281,12 +269,12 @@ static int set_network_info( const struct lease_st *lease)
|
||||
|
||||
ret = ioctl(fd, SIOCSIFDSTADDR, &ifr);
|
||||
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) {
|
||||
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;
|
||||
} else
|
||||
ret = 0;
|
||||
@@ -299,7 +287,7 @@ static int set_network_info( const struct lease_st *lease)
|
||||
|
||||
ret = ioctl(fd, SIOCSIFFLAGS, &ifr);
|
||||
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);
|
||||
@@ -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;
|
||||
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 *last4, *tmp;
|
||||
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));
|
||||
if (lease == NULL)
|
||||
return -1;
|
||||
|
||||
/* 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) {
|
||||
free(lease);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Add into the list */
|
||||
list_add_tail( &tun->head, &lease->list);
|
||||
tun->total++;
|
||||
list_add_tail( &s->tun->head, &lease->list);
|
||||
s->tun->total++;
|
||||
} else {
|
||||
last4 = last6 = NULL;
|
||||
|
||||
/* 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) {
|
||||
lease = tmp;
|
||||
break;
|
||||
@@ -347,26 +336,27 @@ int open_tun(const struct cfg_st *config, struct tun_st* tun, struct lease_st**
|
||||
if (lease == NULL)
|
||||
return -1;
|
||||
|
||||
list_for_each_rev(&tun->head, tmp, list) {
|
||||
if (tmp->rip4_len > 0)
|
||||
list_for_each_rev(&s->tun->head, tmp, list) {
|
||||
if (last4 == NULL && tmp->rip4_len > 0)
|
||||
last4 = tmp;
|
||||
|
||||
if (tmp->rip6_len > 0)
|
||||
|
||||
if (last6 == NULL && tmp->rip6_len > 0)
|
||||
last6 = tmp;
|
||||
|
||||
if (last4 && last6)
|
||||
break;
|
||||
}
|
||||
|
||||
ret = get_avail_network_addresses(config, last4, last6, lease);
|
||||
ret = get_avail_network_addresses(s->config, last4, last6, lease);
|
||||
if (ret < 0) {
|
||||
free(lease);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Add into the list */
|
||||
list_add_tail( &tun->head, &lease->list);
|
||||
tun->total++;
|
||||
list_add_tail( &s->tun->head, &lease->list);
|
||||
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);
|
||||
if (tunfd < 0) {
|
||||
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));
|
||||
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));
|
||||
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));
|
||||
|
||||
if (ioctl(tunfd, TUNSETIFF, (void *) &ifr) < 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (config->uid != -1) {
|
||||
t = config->uid;
|
||||
if (s->config->uid != -1) {
|
||||
t = s->config->uid;
|
||||
ret = ioctl(tunfd, TUNSETOWNER, t);
|
||||
if (ret < 0) {
|
||||
e = errno;
|
||||
syslog(LOG_INFO, "TUNSETOWNER: %s\n",
|
||||
strerror(e));
|
||||
mslog(s, NULL, LOG_INFO, "%s: TUNSETOWNER: %s\n",
|
||||
lease->name, strerror(e));
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (config->gid != -1) {
|
||||
t = config->uid;
|
||||
if (s->config->gid != -1) {
|
||||
t = s->config->uid;
|
||||
ret = ioctl(tunfd, TUNSETGROUP, t);
|
||||
if (ret < 0) {
|
||||
e = errno;
|
||||
syslog(LOG_ERR, "TUNSETGROUP: %s\n",
|
||||
strerror(e));
|
||||
mslog(s, NULL, LOG_ERR, "%s: TUNSETGROUP: %s\n",
|
||||
lease->name, strerror(e));
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* set IP/mask */
|
||||
ret = set_network_info(lease);
|
||||
ret = set_network_info(s, lease);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -53,6 +53,7 @@ struct vpn_st {
|
||||
struct cfg_st {
|
||||
const char *name;
|
||||
unsigned int port;
|
||||
unsigned int udp_port;
|
||||
const char *cert;
|
||||
const char *key;
|
||||
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_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
|
||||
|
||||
@@ -157,8 +157,7 @@ static int recv_auth_reply(worker_st *ws)
|
||||
uint8_t cmd = 0;
|
||||
struct cmd_auth_reply_st resp;
|
||||
struct msghdr hdr;
|
||||
int ret;
|
||||
|
||||
int ret, cmdlen;
|
||||
union {
|
||||
struct cmsghdr cm;
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
if (cmd != AUTH_REP)
|
||||
return -1;
|
||||
|
||||
cmdlen--;
|
||||
|
||||
switch(resp.reply) {
|
||||
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_level != SOL_SOCKET)
|
||||
return -1;
|
||||
|
||||
210
src/worker-vpn.c
210
src/worker-vpn.c
@@ -237,56 +237,10 @@ char* tmp = malloc(length+1);
|
||||
|
||||
static int setup_dtls_connection(struct worker_st *ws)
|
||||
{
|
||||
int ret, e;
|
||||
int ret;
|
||||
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 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.
|
||||
* Initialize session.
|
||||
@@ -354,6 +308,10 @@ void vpn_server(struct worker_st* ws)
|
||||
syslog(LOG_INFO, "Accepted connection from %s",
|
||||
human_addr((void*)&ws->remote_addr, ws->remote_addr_len,
|
||||
buf, sizeof(buf)));
|
||||
if (ws->remote_addr_len == sizeof(struct sockaddr_in))
|
||||
ws->proto = AF_INET;
|
||||
else
|
||||
ws->proto = AF_INET6;
|
||||
|
||||
/* initialize the session */
|
||||
ret = gnutls_init(&session, GNUTLS_SERVER);
|
||||
@@ -631,103 +589,6 @@ fail:
|
||||
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)
|
||||
{
|
||||
int left = len;
|
||||
@@ -845,7 +706,7 @@ unsigned mtu_overhead, dtls_mtu = 0;
|
||||
}
|
||||
|
||||
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, "X-Reason: Server configuration error\r\n\r\n");
|
||||
return -1;
|
||||
@@ -869,11 +730,6 @@ unsigned mtu_overhead, dtls_mtu = 0;
|
||||
ws->udp_state = UP_DISABLED;
|
||||
if (req->master_secret_set != 0) {
|
||||
memcpy(ws->master_secret, req->master_secret, TLS_MASTER_SIZE);
|
||||
|
||||
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-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_printf(ws->session, "X-DTLS-Keepalive: %u\r\n", ws->config->keepalive);
|
||||
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;
|
||||
else
|
||||
mtu_overhead = 40+8;
|
||||
@@ -940,7 +797,7 @@ unsigned mtu_overhead, dtls_mtu = 0;
|
||||
max = MAX(ws->cmd_fd,ws->conn_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);
|
||||
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) {
|
||||
case UP_ACTIVE:
|
||||
@@ -1135,10 +992,16 @@ int handle_worker_commands(struct worker_st *ws)
|
||||
uint8_t cmd;
|
||||
struct msghdr hdr;
|
||||
union {
|
||||
char x[20];
|
||||
char x[32];
|
||||
struct sockaddr_storage ss;
|
||||
} cmd_data;
|
||||
int ret;
|
||||
/*int cmd_data_len;*/
|
||||
union {
|
||||
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));
|
||||
|
||||
@@ -1152,6 +1015,9 @@ int handle_worker_commands(struct worker_st *ws)
|
||||
hdr.msg_iov = iov;
|
||||
hdr.msg_iovlen = 2;
|
||||
|
||||
hdr.msg_control = control_un.control;
|
||||
hdr.msg_controllen = sizeof(control_un.control);
|
||||
|
||||
ret = recvmsg( ws->cmd_fd, &hdr, 0);
|
||||
if (ret == -1) {
|
||||
oclog(ws, LOG_ERR, "Cannot obtain data from command socket");
|
||||
@@ -1162,11 +1028,39 @@ int handle_worker_commands(struct worker_st *ws)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*cmd_data_len = ret - 1;*/
|
||||
cmd_data_len = ret - 1;
|
||||
|
||||
switch(cmd) {
|
||||
case CMD_TERMINATE:
|
||||
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:
|
||||
oclog(ws, LOG_ERR, "Unknown CMD 0x%x", (unsigned)cmd);
|
||||
exit(1);
|
||||
|
||||
@@ -44,12 +44,11 @@ typedef struct worker_st {
|
||||
|
||||
struct sockaddr_storage remote_addr; /* peer's address */
|
||||
socklen_t remote_addr_len;
|
||||
int proto; /* AF_INET or AF_INET6 */
|
||||
|
||||
/* set after authentication */
|
||||
int udp_fd;
|
||||
udp_port_state_t udp_state;
|
||||
unsigned int udp_port;
|
||||
int udp_port_proto;
|
||||
|
||||
/* for mtu trials */
|
||||
unsigned last_good_mtu;
|
||||
|
||||
Reference in New Issue
Block a user