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
|
* 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?)
|
||||||
|
|||||||
@@ -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";
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
32
src/log.c
32
src/log.c
@@ -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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
351
src/main.c
351
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);
|
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);
|
||||||
|
|||||||
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 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
|
||||||
|
|||||||
@@ -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
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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
174
src/tun.c
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
212
src/worker-vpn.c
212
src/worker-vpn.c
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user