The worker process receives the client's IPs from the main process.

That eliminates the need to read the IP address from the tun device
(which can be quite tricky to implement in a clean portable way).
This commit is contained in:
Nikos Mavrogiannopoulos
2014-01-31 20:47:20 +01:00
parent f715cf08f0
commit 28e5d62f3f
12 changed files with 172 additions and 275 deletions

View File

@@ -46,7 +46,7 @@ ocserv-args.c: $(srcdir)/ocserv-args.def
ocserv-args.h: ocserv-args.c
ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \
cookies.c worker-tun.c main-misc.c main-ctl-handler.c \
cookies.c main-misc.c main-ctl-handler.c \
group-config.c ip-lease.c ip-lease.h \
vpn.h cookies.h tlslib.h log.c tun.c tun.h \
config.c pam.c pam.h worker-resume.c worker.h main-resume.c main.h \

View File

@@ -214,7 +214,7 @@ int send_socket_msg(int fd, uint8_t cmd,
if (length > 0) {
packed = malloc(length);
if (packed == NULL) {
syslog(LOG_ERR, "%s:%u: memory error", __func__, __LINE__);
syslog(LOG_ERR, "%s:%u: memory error", __FILE__, __LINE__);
return -1;
}
@@ -223,7 +223,7 @@ int send_socket_msg(int fd, uint8_t cmd,
ret = pack(msg, packed);
if (ret == 0) {
syslog(LOG_ERR, "%s:%u: packing error", __func__, __LINE__);
syslog(LOG_ERR, "%s:%u: packing error", __FILE__, __LINE__);
ret = -1;
goto cleanup;
}
@@ -245,7 +245,7 @@ int send_socket_msg(int fd, uint8_t cmd,
ret = sendmsg(fd, &hdr, 0);
if (ret < 0) {
int e = errno;
syslog(LOG_ERR, "%s:%u: %s", __func__, __LINE__, strerror(e));
syslog(LOG_ERR, "%s:%u: %s", __FILE__, __LINE__, strerror(e));
}
cleanup:
@@ -293,12 +293,12 @@ int recv_socket_msg(int fd, uint8_t cmd,
} while (ret == -1 && errno == EINTR);
if (ret == -1) {
int e = errno;
syslog(LOG_ERR, "%s:%u: recvmsg: %s", __func__, __LINE__, strerror(e));
syslog(LOG_ERR, "%s:%u: recvmsg: %s", __FILE__, __LINE__, strerror(e));
return ERR_BAD_COMMAND;
}
if (ret == 0) {
syslog(LOG_ERR, "%s:%u: recvmsg returned zero", __func__, __LINE__);
syslog(LOG_ERR, "%s:%u: recvmsg returned zero", __FILE__, __LINE__);
return ERR_WORKER_TERMINATED;
}
@@ -310,7 +310,7 @@ int recv_socket_msg(int fd, uint8_t cmd,
if (socketfd != NULL) {
if ( (cmptr = CMSG_FIRSTHDR(&hdr)) != NULL && cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
if (cmptr->cmsg_level != SOL_SOCKET || cmptr->cmsg_type != SCM_RIGHTS) {
syslog(LOG_ERR, "%s:%u: recvmsg returned invalid msg type", __func__, __LINE__);
syslog(LOG_ERR, "%s:%u: recvmsg returned invalid msg type", __FILE__, __LINE__);
return ERR_BAD_COMMAND;
}
@@ -330,14 +330,14 @@ int recv_socket_msg(int fd, uint8_t cmd,
ret = force_read(fd, data, length);
if (ret < length) {
int e = errno;
syslog(LOG_ERR, "%s:%u: recvmsg: %s", __func__, __LINE__, strerror(e));
syslog(LOG_ERR, "%s:%u: recvmsg: %s", __FILE__, __LINE__, strerror(e));
ret = ERR_BAD_COMMAND;
goto cleanup;
}
*msg = unpack(NULL, length, data);
if (*msg == NULL) {
syslog(LOG_ERR, "%s:%u: unpacking error", __func__, __LINE__);
syslog(LOG_ERR, "%s:%u: unpacking error", __FILE__, __LINE__);
ret = ERR_MEM;
goto cleanup;
}

View File

@@ -157,7 +157,16 @@ unsigned j;
fprintf(stderr, "Configuration option %s is mandatory.\n", name); \
exit(1); \
}
#define READ_STATIC_STRING(name, s_name) \
val = get_option(name, &mand); \
if (val != NULL && val->valType == OPARG_TYPE_STRING) \
snprintf(s_name, sizeof(s_name), "%s", val->v.strVal); \
else if (mand != 0) { \
fprintf(stderr, "Configuration option %s is mandatory.\n", name); \
exit(1); \
}
#define READ_TF(name, s_name, def) \
{ char* tmp_tf = NULL; \
READ_STRING(name, tmp_tf); \
@@ -383,7 +392,7 @@ unsigned force_cert_auth;
config->gid = grp->gr_gid;
}
READ_STRING("device", config->network.name);
READ_STATIC_STRING("device", config->network.name);
READ_STRING("cgroup", config->cgroup);
READ_STRING("ipv4-network", config->network.ipv4);
@@ -560,7 +569,6 @@ unsigned i;
DEL(config->connect_script);
DEL(config->disconnect_script);
DEL(config->network.name);
DEL(config->network.ipv4);
DEL(config->network.ipv4_netmask);
DEL(config->network.ipv4_dns);

View File

@@ -82,17 +82,23 @@ message auth_reply_msg
optional string user_name = 5;
optional string msg = 6;
/* the ips of the tun device */
optional string ipv4 = 7;
optional string ipv6 = 8;
optional string ipv4_local = 9;
optional string ipv6_local = 10;
/* additional config */
optional string ipv4_dns = 7;
optional string ipv6_dns = 8;
optional string ipv4_nbns = 9;
optional string ipv6_nbns = 10;
optional string ipv4_netmask = 11;
optional string ipv6_netmask = 12;
optional uint32 rx_per_sec = 13;
optional uint32 tx_per_sec = 14;
optional uint32 net_priority = 15;
repeated string routes = 16;
optional string ipv4_dns = 11;
optional string ipv6_dns = 12;
optional string ipv4_nbns = 13;
optional string ipv6_nbns = 14;
optional string ipv4_netmask = 15;
optional string ipv6_netmask = 16;
optional uint32 rx_per_sec = 17;
optional uint32 tx_per_sec = 18;
optional uint32 net_priority = 19;
repeated string routes = 20;
}
/* RESUME_FETCH_REQ + RESUME_DELETE_REQ */

View File

@@ -29,10 +29,10 @@
#include <worker.h>
#include <main.h>
const char *human_addr2(const struct sockaddr *sa, socklen_t salen,
char *human_addr2(const struct sockaddr *sa, socklen_t salen,
void *_buf, size_t buflen, unsigned full)
{
const char *save_buf = _buf;
char *save_buf = _buf;
char *buf = _buf;
size_t l;

View File

@@ -34,6 +34,7 @@
#include <gnutls/crypto.h>
#include <tlslib.h>
#include <script-list.h>
#include <ip-lease.h>
#include "str.h"
#include <vpn.h>
@@ -74,6 +75,10 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc,
}
if (r == AUTH_REPLY_MSG__AUTH__REP__OK && proc->tun_lease.name[0] != 0) {
char ipv6[MAX_IP_STR];
char ipv4[MAX_IP_STR];
char ipv6_local[MAX_IP_STR];
char ipv4_local[MAX_IP_STR];
/* fill message */
msg.reply = AUTH_REPLY_MSG__AUTH__REP__OK;
@@ -88,6 +93,20 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc,
msg.vname = proc->tun_lease.name;
msg.user_name = proc->username;
if (proc->ipv4 && proc->ipv4->rip_len > 0) {
msg.ipv4 = human_addr2((struct sockaddr*)&proc->ipv4->rip, proc->ipv4->rip_len,
ipv4, sizeof(ipv4), 0);
msg.ipv4_local = human_addr2((struct sockaddr*)&proc->ipv4->lip, proc->ipv4->lip_len,
ipv4_local, sizeof(ipv4_local), 0);
}
if (proc->ipv6 && proc->ipv6->rip_len > 0) {
msg.ipv6 = human_addr2((struct sockaddr*)&proc->ipv6->rip, proc->ipv6->rip_len,
ipv6, sizeof(ipv6), 0);
msg.ipv6_local = human_addr2((struct sockaddr*)&proc->ipv6->lip, proc->ipv6->lip_len,
ipv6_local, sizeof(ipv6_local), 0);
}
msg.ipv4_dns = proc->config.ipv4_dns;
msg.ipv6_dns = proc->config.ipv6_dns;
msg.ipv4_nbns = proc->config.ipv4_nbns;

View File

@@ -106,6 +106,8 @@ typedef struct
unsigned int entries;
} hash_db_st;
#define MAX_IP_STR 46
struct group_cfg_st {
/* routes to be forwarded to the client */
char **routes;
@@ -133,7 +135,7 @@ struct group_cfg_st {
};
struct vpn_st {
char *name; /* device name */
char name[IFNAMSIZ];
char *ipv4_netmask;
char *ipv4;
char *ipv4_local; /* local IPv4 address */
@@ -246,7 +248,7 @@ struct main_server_st;
#include <tun.h>
const char *human_addr2(const struct sockaddr *sa, socklen_t salen,
char *human_addr2(const struct sockaddr *sa, socklen_t salen,
void *buf, size_t buflen, unsigned full);
#define human_addr(x, y, z, w) human_addr2(x, y, z, w, 1)

View File

@@ -251,7 +251,7 @@ static int recv_auth_reply(worker_st * ws, char *txt, size_t max_txt_size)
goto cleanup;
}
snprintf(ws->tun_name, sizeof(ws->tun_name), "%s",
snprintf(ws->vinfo.name, sizeof(ws->vinfo.name), "%s",
msg->vname);
snprintf(ws->username, sizeof(ws->username), "%s",
msg->user_name);
@@ -265,6 +265,38 @@ static int recv_auth_reply(worker_st * ws, char *txt, size_t max_txt_size)
memcpy(ws->session_id, msg->session_id.data,
msg->session_id.len);
if (msg->ipv4 != NULL) {
free(ws->vinfo.ipv4);
if (strcmp(msg->ipv4, "0.0.0.0") == 0)
ws->vinfo.ipv4 = NULL;
else
ws->vinfo.ipv4 = strdup(msg->ipv4);
}
if (msg->ipv6 != NULL) {
free(ws->vinfo.ipv6);
if (strcmp(msg->ipv6, "::") == 0)
ws->vinfo.ipv6 = NULL;
else
ws->vinfo.ipv6 = strdup(msg->ipv6);
}
if (msg->ipv4_local != NULL) {
free(ws->vinfo.ipv4_local);
if (strcmp(msg->ipv4_local, "0.0.0.0") == 0)
ws->vinfo.ipv4_local = NULL;
else
ws->vinfo.ipv4_local = strdup(msg->ipv4_local);
}
if (msg->ipv6_local != NULL) {
free(ws->vinfo.ipv6_local);
if (strcmp(msg->ipv6_local, "::") == 0)
ws->vinfo.ipv6_local = NULL;
else
ws->vinfo.ipv6_local = strdup(msg->ipv6_local);
}
/* Read any additional data */
if (msg->ipv4_dns != NULL) {
free(ws->config->network.ipv4_dns);

View File

@@ -33,6 +33,10 @@
#include <unistd.h>
#include <limits.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <vpn.h>
#include <worker.h>
#include <cookies.h>
@@ -132,3 +136,72 @@ udp_fd_fail:
return -1;
}
/* Completes the VPN device information.
*
* Returns 0 on success.
*/
int complete_vpn_info(worker_st * ws, struct vpn_st *vinfo)
{
int ret, fd;
struct ifreq ifr;
if (vinfo->ipv4 == NULL && vinfo->ipv6 == NULL) {
return -1;
}
#define LOCAL "local"
if (ws->config->network.ipv4_dns
&& strcmp(ws->config->network.ipv4_dns, LOCAL) == 0)
vinfo->ipv4_dns = vinfo->ipv4_local;
else
vinfo->ipv4_dns = ws->config->network.ipv4_dns;
if (ws->config->network.ipv6_dns
&& strcmp(ws->config->network.ipv6_dns, LOCAL) == 0)
vinfo->ipv6_dns = vinfo->ipv6_local;
else
vinfo->ipv6_dns = ws->config->network.ipv6_dns;
if (ws->config->network.ipv4_nbns
&& strcmp(ws->config->network.ipv4_nbns, LOCAL) == 0)
vinfo->ipv4_nbns = vinfo->ipv4_local;
else
vinfo->ipv4_nbns = ws->config->network.ipv4_nbns;
if (ws->config->network.ipv6_nbns
&& strcmp(ws->config->network.ipv6_nbns, LOCAL) == 0)
vinfo->ipv6_nbns = vinfo->ipv6_local;
else
vinfo->ipv6_nbns = ws->config->network.ipv6_nbns;
vinfo->routes_size = ws->config->network.routes_size;
if (ws->config->network.routes_size > 0)
vinfo->routes = ws->config->network.routes;
vinfo->ipv4_netmask = ws->config->network.ipv4_netmask;
vinfo->ipv6_netmask = ws->config->network.ipv6_netmask;
if (ws->config->network.mtu != 0) {
vinfo->mtu = ws->config->network.mtu;
} else {
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1)
return -1;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_addr.sa_family = AF_INET;
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", vinfo->name);
ret = ioctl(fd, SIOCGIFMTU, (caddr_t) & ifr);
if (ret < 0) {
oclog(ws, LOG_ERR,
"cannot obtain MTU for %s. Assuming 1500",
vinfo->name);
vinfo->mtu = 1500;
} else {
vinfo->mtu = ifr.ifr_mtu;
}
close(fd);
}
return 0;
}

View File

@@ -1,244 +0,0 @@
/*
* Copyright (C) 2013 Nikos Mavrogiannopoulos
*
* This file is part of ocserv.
*
* ocserv is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* GnuTLS is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <gnutls/gnutls.h>
#include <gnutls/dtls.h>
#include <gnutls/crypto.h>
#include <errno.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <signal.h>
#include <time.h>
#include <vpn.h>
#include <worker.h>
#include <tlslib.h>
#include <ifaddrs.h>
static
int get_ips(struct worker_st *ws, struct vpn_st *vinfo, char **buffer,
size_t * buffer_size)
{
struct ifaddrs *ifaddr, *ifa;
int ret, e;
void *p;
/* getifaddrs looks like a waste, especially when the number of devices/clients
* is large. We should instead get that info from the main process
*/
ret = getifaddrs(&ifaddr);
if (ret != 0) {
e = errno;
oclog(ws, LOG_ERR, "getifaddrs error: %s", strerror(e));
return -1;
}
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL)
continue;
if (strcmp(vinfo->name, ifa->ifa_name) == 0) {
p = (char *)inet_ntop(ifa->ifa_addr->sa_family,
SA_IN_P_TYPE(ifa->ifa_addr,
ifa->ifa_addr->
sa_family), *buffer,
*buffer_size);
if (p == NULL) {
e = errno;
oclog(ws, LOG_ERR, "inet_ntop error: %s",
strerror(e));
continue;
}
ret = strlen(p) + 1;
*buffer += ret;
*buffer_size -= ret;
if (ifa->ifa_addr->sa_family == AF_INET) {
if (strcmp(p, "0.0.0.0") == 0)
p = NULL;
vinfo->ipv4_local = p;
} else {
if (strcmp(p, "::") == 0)
p = NULL;
vinfo->ipv6_local = p;
}
if (ifa->ifa_addr->sa_family == AF_INET6) {
/* no DST address */
struct in6_addr ip;
memcpy(&ip,
SA_IN_P_TYPE(ifa->ifa_addr,
ifa->ifa_addr->sa_family),
sizeof(ip));
((uint8_t *) & ip)[15]++;
p = (char *)inet_ntop(AF_INET6,
&ip, *buffer,
*buffer_size);
if (p == NULL) {
e = errno;
oclog(ws, LOG_ERR,
"inet_ntop error: %s",
strerror(e));
continue;
}
ret = strlen(p) + 1;
*buffer += ret;
*buffer_size -= ret;
if (strcmp(p, "::") == 0)
p = NULL;
vinfo->ipv6 = p;
} else {
/* DST */
if (ifa->ifa_dstaddr == NULL)
continue;
p = (char *)inet_ntop(ifa->ifa_dstaddr->
sa_family,
SA_IN_P_TYPE(ifa->
ifa_dstaddr,
ifa->
ifa_dstaddr->
sa_family),
*buffer, *buffer_size);
if (p == NULL) {
e = errno;
oclog(ws, LOG_ERR,
"inet_ntop error: %s",
strerror(e));
continue;
}
ret = strlen(p) + 1;
*buffer += ret;
*buffer_size -= ret;
if (strcmp(p, "0.0.0.0") == 0)
p = NULL;
vinfo->ipv4 = p;
}
}
}
freeifaddrs(ifaddr);
return 0;
}
/* Returns information based on an VPN network stored in worker_st but
* using real time information for many fields. Nothing is allocated,
* the provided buffer is used.
*
* Returns 0 on success.
*/
int get_rt_vpn_info(worker_st * ws,
struct vpn_st *vinfo, char *buffer, size_t buffer_size)
{
int ret, fd;
struct ifreq ifr;
memset(vinfo, 0, sizeof(*vinfo));
vinfo->name = ws->tun_name;
/* get the remote IPs */
ret = get_ips(ws, vinfo, &buffer, &buffer_size);
if (ret < 0) {
oclog(ws, LOG_DEBUG, "cannot obtain IPs for %s", vinfo->name);
}
if (vinfo->ipv4 == NULL && vinfo->ipv6 == NULL) {
return -1;
}
#define LOCAL "local"
if (ws->config->network.ipv4_dns
&& strcmp(ws->config->network.ipv4_dns, LOCAL) == 0)
vinfo->ipv4_dns = vinfo->ipv4_local;
else
vinfo->ipv4_dns = ws->config->network.ipv4_dns;
if (ws->config->network.ipv6_dns
&& strcmp(ws->config->network.ipv6_dns, LOCAL) == 0)
vinfo->ipv6_dns = vinfo->ipv6_local;
else
vinfo->ipv6_dns = ws->config->network.ipv6_dns;
if (ws->config->network.ipv4_nbns
&& strcmp(ws->config->network.ipv4_nbns, LOCAL) == 0)
vinfo->ipv4_nbns = vinfo->ipv4_local;
else
vinfo->ipv4_nbns = ws->config->network.ipv4_nbns;
if (ws->config->network.ipv6_nbns
&& strcmp(ws->config->network.ipv6_nbns, LOCAL) == 0)
vinfo->ipv6_nbns = vinfo->ipv6_local;
else
vinfo->ipv6_nbns = ws->config->network.ipv6_nbns;
vinfo->routes_size = ws->config->network.routes_size;
if (ws->config->network.routes_size > 0)
vinfo->routes = ws->config->network.routes;
vinfo->ipv4_netmask = ws->config->network.ipv4_netmask;
vinfo->ipv6_netmask = ws->config->network.ipv6_netmask;
if (ws->config->network.mtu != 0) {
vinfo->mtu = ws->config->network.mtu;
} else {
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1)
return -1;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_addr.sa_family = AF_INET;
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", vinfo->name);
ret = ioctl(fd, SIOCGIFMTU, (caddr_t) & ifr);
if (ret < 0) {
oclog(ws, LOG_ERR,
"cannot obtain MTU for %s. Assuming 1500",
vinfo->name);
vinfo->mtu = 1500;
} else {
vinfo->mtu = ifr.ifr_mtu;
}
close(fd);
}
return 0;
}

View File

@@ -1083,7 +1083,7 @@ static int connect_handler(worker_st * ws)
return -1;
}
ret = get_rt_vpn_info(ws, &ws->vinfo, (char *)ws->buffer, ws->buffer_size);
ret = complete_vpn_info(ws, &ws->vinfo);
if (ret < 0) {
oclog(ws, LOG_ERR,
"no networks are configured; rejecting client");

View File

@@ -148,7 +148,8 @@ typedef struct worker_st {
unsigned buffer_size;
/* the following are set only if authentication is complete */
char tun_name[IFNAMSIZ];
char username[MAX_USERNAME_SIZE];
char hostname[MAX_HOSTNAME_SIZE];
uint8_t cookie[COOKIE_SIZE];
@@ -194,8 +195,8 @@ void __attribute__ ((format(printf, 3, 4)))
# define oclog _oclog
#endif
int get_rt_vpn_info(worker_st * ws,
struct vpn_st* vinfo, char* buffer, size_t buffer_size);
int complete_vpn_info(worker_st * ws,
struct vpn_st* vinfo);
int send_tun_mtu(worker_st *ws, unsigned int mtu);
int handle_worker_commands(struct worker_st *ws);