mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-02-10 08:46:58 +08:00
Provide client with normal leased IPs.
This commit is contained in:
@@ -4,7 +4,8 @@ AM_CPPFLAGS = -I$(srcdir)../gl/ -I$(builddir)../gl/ \
|
||||
bin_PROGRAMS = ocserv
|
||||
|
||||
ocserv_SOURCES = main.c vpn.c http_auth.c tlslib.c cookies.c http-parser/http_parser.c \
|
||||
vpn.h auth.h cookies.h tlslib.h http-parser/http_parser.h log.c tun.c tun.h
|
||||
vpn.h auth.h cookies.h tlslib.h http-parser/http_parser.h log.c tun.c tun.h \
|
||||
uthash.h
|
||||
|
||||
ocserv_LDADD = ../gl/libgnu.a
|
||||
ocserv_LDADD += $(LIBGNUTLS_LIBS) $(GDBM_LIBS)
|
||||
|
||||
@@ -104,7 +104,7 @@ fail:
|
||||
|
||||
}
|
||||
|
||||
static int send_auth_req(int fd, struct cmd_auth_req_st* r)
|
||||
static int send_auth_req(int fd, const struct cmd_auth_req_st* r)
|
||||
{
|
||||
struct iovec iov[2];
|
||||
uint8_t cmd;
|
||||
@@ -123,7 +123,7 @@ static int send_auth_req(int fd, struct cmd_auth_req_st* r)
|
||||
iov[0].iov_base = &cmd;
|
||||
iov[0].iov_len = 1;
|
||||
|
||||
iov[1].iov_base = r;
|
||||
iov[1].iov_base = (void*)r;
|
||||
iov[1].iov_len = sizeof(*r);
|
||||
|
||||
hdr.msg_iov = iov;
|
||||
@@ -132,7 +132,7 @@ static int send_auth_req(int fd, struct cmd_auth_req_st* r)
|
||||
return(sendmsg(fd, &hdr, 0));
|
||||
}
|
||||
|
||||
static int recv_auth_reply(int cmdfd, struct tun_id_st * tunid)
|
||||
static int recv_auth_reply(server_st *server)
|
||||
{
|
||||
struct iovec iov[3];
|
||||
uint8_t cmd = 0;
|
||||
@@ -162,7 +162,7 @@ static int recv_auth_reply(int cmdfd, struct tun_id_st * tunid)
|
||||
hdr.msg_control = control_un.control;
|
||||
hdr.msg_controllen = sizeof(control_un.control);
|
||||
|
||||
ret = recvmsg( cmdfd, &hdr, 0);
|
||||
ret = recvmsg( server->cmd_fd, &hdr, 0);
|
||||
if (ret <= 0) {
|
||||
return -1;
|
||||
}
|
||||
@@ -177,8 +177,8 @@ static int recv_auth_reply(int cmdfd, struct tun_id_st * tunid)
|
||||
if (cmptr->cmsg_type != SCM_RIGHTS)
|
||||
return -1;
|
||||
|
||||
tunid->fd = *((int *) CMSG_DATA(cmptr));
|
||||
memcpy(tunid->name, resp.vname, sizeof(tunid->name));
|
||||
server->tun_fd = *((int *) CMSG_DATA(cmptr));
|
||||
memcpy(server->tun_name, resp.vname, sizeof(server->tun_name));
|
||||
} else
|
||||
return -1;
|
||||
break;
|
||||
@@ -191,15 +191,15 @@ static int recv_auth_reply(int cmdfd, struct tun_id_st * tunid)
|
||||
|
||||
/* sends an authentication request to main thread and waits for
|
||||
* a reply */
|
||||
static int auth_user(int cmdfd, struct cmd_auth_req_st* areq, struct tun_id_st* tunid)
|
||||
static int auth_user(server_st *server, const struct cmd_auth_req_st* areq)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = send_auth_req(cmdfd, areq);
|
||||
ret = send_auth_req(server->cmd_fd, areq);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return recv_auth_reply(cmdfd, tunid);
|
||||
return recv_auth_reply(server);
|
||||
}
|
||||
|
||||
static
|
||||
@@ -295,7 +295,7 @@ struct cmd_auth_req_st areq;
|
||||
snprintf(areq.pass, sizeof(areq.pass), "%s", password);
|
||||
}
|
||||
|
||||
ret = auth_user(server->cmdfd, &areq, &server->tunid);
|
||||
ret = auth_user(server, &areq);
|
||||
if (ret < 0)
|
||||
goto auth_fail;
|
||||
|
||||
@@ -412,8 +412,7 @@ struct cmd_auth_req_st areq;
|
||||
snprintf(areq.pass, sizeof(areq.pass), "%s", password);
|
||||
}
|
||||
|
||||
|
||||
ret = auth_user(server->cmdfd, &areq, &server->tunid);
|
||||
ret = auth_user(server, &areq);
|
||||
if (ret < 0)
|
||||
goto auth_fail;
|
||||
|
||||
|
||||
71
src/main.c
71
src/main.c
@@ -54,10 +54,13 @@ struct proc_list_st {
|
||||
pid_t pid;
|
||||
struct sockaddr_storage remote_addr; /* peer address */
|
||||
socklen_t remote_addr_len;
|
||||
|
||||
/* the tun lease this process has */
|
||||
struct lease_st* lease;
|
||||
};
|
||||
|
||||
static int handle_commands(const struct cfg_st *config, const struct tun_st *tun,
|
||||
const struct proc_list_st* proc);
|
||||
static int handle_commands(const struct cfg_st *config, struct tun_st *tun,
|
||||
struct proc_list_st* proc);
|
||||
|
||||
static void tls_log_func(int level, const char *str)
|
||||
{
|
||||
@@ -301,6 +304,7 @@ static void clear_proc_list(struct proc_list_st* clist)
|
||||
|
||||
list_for_each_safe(pos, cq, &clist->list) {
|
||||
ctmp = list_entry(pos, struct proc_list_st, list);
|
||||
if (ctmp->fd >= 0)
|
||||
close(ctmp->fd);
|
||||
list_del(&ctmp->list);
|
||||
}
|
||||
@@ -327,6 +331,7 @@ int main(void)
|
||||
socklen_t tmp_addr_len;
|
||||
|
||||
INIT_LIST_HEAD(&clist.list);
|
||||
tun_st_init(&tun);
|
||||
|
||||
/*signal(SIGINT, SIG_IGN); */
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
@@ -335,6 +340,7 @@ int main(void)
|
||||
signal(SIGALRM, handle_alarm);
|
||||
|
||||
/* XXX load configuration */
|
||||
#warning read configuration from file
|
||||
|
||||
/* Listen to network ports */
|
||||
ret = listen_ports(&llist, config.name, config.port, SOCK_STREAM);
|
||||
@@ -483,7 +489,6 @@ fork_failed:
|
||||
}
|
||||
close(cmd_fd[1]);
|
||||
close(fd);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -494,8 +499,14 @@ fork_failed:
|
||||
if (FD_ISSET(ctmp->fd, &rd)) {
|
||||
ret = handle_commands(&config, &tun, ctmp);
|
||||
if (ret < 0) {
|
||||
if (ctmp->fd >= 0)
|
||||
close(ctmp->fd);
|
||||
kill(ctmp->pid, SIGTERM);
|
||||
ctmp->fd = -1;
|
||||
|
||||
if (ret == -2) kill(ctmp->pid, SIGTERM);
|
||||
ctmp->pid = -1;
|
||||
if (ctmp->lease)
|
||||
ctmp->lease->in_use = 0;
|
||||
list_del(&ctmp->list);
|
||||
}
|
||||
}
|
||||
@@ -528,7 +539,7 @@ fork_failed:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_auth_reply(int fd, cmd_auth_reply_t r, struct tun_id_st* tunid)
|
||||
static int send_auth_reply(int fd, cmd_auth_reply_t r, struct lease_st* lease)
|
||||
{
|
||||
struct iovec iov[2];
|
||||
uint8_t cmd[2];
|
||||
@@ -547,18 +558,16 @@ static int send_auth_reply(int fd, cmd_auth_reply_t r, struct tun_id_st* tunid)
|
||||
|
||||
cmd[0] = AUTH_REP;
|
||||
cmd[1] = r;
|
||||
hdr.msg_iovlen++;
|
||||
|
||||
iov[0].iov_base = cmd;
|
||||
iov[0].iov_len = 2;
|
||||
hdr.msg_iovlen++;
|
||||
|
||||
iov[1].iov_len = sizeof(tunid->name);
|
||||
|
||||
hdr.msg_iov = iov;
|
||||
|
||||
if (r == REP_AUTH_OK && tunid != NULL) {
|
||||
iov[1].iov_base = tunid->name;
|
||||
if (r == REP_AUTH_OK && lease != NULL) {
|
||||
iov[1].iov_base = lease->name;
|
||||
iov[1].iov_len = sizeof(lease->name);
|
||||
hdr.msg_iovlen++;
|
||||
|
||||
/* Send the tun fd */
|
||||
@@ -569,14 +578,14 @@ static int send_auth_reply(int fd, cmd_auth_reply_t r, struct tun_id_st* tunid)
|
||||
cmptr->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
cmptr->cmsg_level = SOL_SOCKET;
|
||||
cmptr->cmsg_type = SCM_RIGHTS;
|
||||
*((int *) CMSG_DATA(cmptr)) = tunid->fd;
|
||||
*((int *) CMSG_DATA(cmptr)) = lease->fd;
|
||||
}
|
||||
|
||||
return(sendmsg(fd, &hdr, 0));
|
||||
}
|
||||
|
||||
static int handle_auth_req(const struct cfg_st *config, const struct tun_st *tun,
|
||||
const struct cmd_auth_req_st * req, struct tun_id_st *tunid)
|
||||
static int handle_auth_req(const struct cfg_st *config, struct tun_st *tun,
|
||||
const struct cmd_auth_req_st * req, struct lease_st **lease)
|
||||
{
|
||||
int ret;
|
||||
#warning fix auth
|
||||
@@ -586,7 +595,7 @@ int ret;
|
||||
ret = -1;
|
||||
|
||||
if (ret == 0) { /* open tun */
|
||||
ret = open_tun(config, tun, tunid);
|
||||
ret = open_tun(config, tun, lease);
|
||||
if (ret < 0)
|
||||
ret = -1; /* sorry */
|
||||
}
|
||||
@@ -594,14 +603,14 @@ int ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int handle_commands(const struct cfg_st *config, const struct tun_st *tun,
|
||||
const struct proc_list_st* proc)
|
||||
static int handle_commands(const struct cfg_st *config, struct tun_st *tun,
|
||||
struct proc_list_st* proc)
|
||||
{
|
||||
struct iovec iov[2];
|
||||
char buf[128];
|
||||
uint8_t cmd;
|
||||
struct msghdr hdr;
|
||||
struct tun_id_st tunid;
|
||||
struct lease_st *lease;
|
||||
union {
|
||||
struct cmd_auth_req_st auth;
|
||||
} cmd_data;
|
||||
@@ -638,24 +647,34 @@ static int handle_commands(const struct cfg_st *config, const struct tun_st *tun
|
||||
case AUTH_REQ:
|
||||
if (cmd_data_len != sizeof(cmd_data.auth)) {
|
||||
syslog(LOG_ERR, "Error in received message length (pid: %d, peer: %s).", proc->pid, peer_ip);
|
||||
return -1;
|
||||
return -2;
|
||||
}
|
||||
|
||||
ret = handle_auth_req(config, tun, &cmd_data.auth, &tunid);
|
||||
ret = handle_auth_req(config, tun, &cmd_data.auth, &lease);
|
||||
if (ret == 0) {
|
||||
ret = send_auth_reply(proc->fd, REP_AUTH_OK, &tunid);
|
||||
close(tunid.fd);
|
||||
} else
|
||||
ret = send_auth_reply(proc->fd, REP_AUTH_FAILED, NULL);
|
||||
|
||||
ret = send_auth_reply(proc->fd, REP_AUTH_OK, lease);
|
||||
if (ret < 0) {
|
||||
syslog(LOG_ERR, "Could not send reply cmd (pid: %d, peer: %s).", proc->pid, peer_ip);
|
||||
return -1;
|
||||
return -2;
|
||||
}
|
||||
|
||||
proc->lease = lease;
|
||||
proc->lease->in_use = 1;
|
||||
if (lease->fd >= 0)
|
||||
close(lease->fd);
|
||||
lease->fd = -1;
|
||||
} else {
|
||||
ret = send_auth_reply(proc->fd, REP_AUTH_FAILED, NULL);
|
||||
if (ret < 0) {
|
||||
syslog(LOG_ERR, "Could not send reply cmd (pid: %d, peer: %s).", proc->pid, peer_ip);
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
syslog(LOG_ERR, "Unknown CMD 0x%x (pid: %d, peer: %s).", (unsigned)cmd, proc->pid, peer_ip);
|
||||
return -1;
|
||||
return -2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
338
src/tun.c
338
src/tun.c
@@ -27,85 +27,340 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <vpn.h>
|
||||
#include <tun.h>
|
||||
#include <list.h>
|
||||
|
||||
static int set_network_info(const char* vname, const struct vpn_st *vinfo)
|
||||
static int bignum_add1 (uint8_t * num, unsigned size)
|
||||
{
|
||||
register int i, y = 0;
|
||||
|
||||
for (i = size-1; i >= 0; i--)
|
||||
{
|
||||
y = 0;
|
||||
if (num[i] == 0xff)
|
||||
{
|
||||
num[i] = 0;
|
||||
y = 1;
|
||||
}
|
||||
else
|
||||
num[i]++;
|
||||
|
||||
if (y == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define SA_IN_P(p) (&((struct sockaddr_in *)(p))->sin_addr)
|
||||
#define SA_IN_U8_P(p) ((uint8_t*)(&((struct sockaddr_in *)(p))->sin_addr))
|
||||
#define SA_IN6_P(p) (&((struct sockaddr_in6 *)(p))->sin6_addr)
|
||||
#define SA_IN6_U8_P(p) ((uint8_t*)(&((struct sockaddr_in6 *)(p))->sin6_addr))
|
||||
static int get_avail_network_addresses(const struct cfg_st *config, const struct lease_st *last4,
|
||||
const struct lease_st *last6, struct lease_st* lease)
|
||||
{
|
||||
struct sockaddr_storage tmp, mask;
|
||||
struct sockaddr_in *t4;
|
||||
struct sockaddr_in6 *t6;
|
||||
unsigned i;
|
||||
int ret;
|
||||
|
||||
lease->rip4_len = 0;
|
||||
lease->lip4_len = 0;
|
||||
lease->rip6_len = 0;
|
||||
lease->lip6_len = 0;
|
||||
|
||||
memset(&tmp, 0, sizeof(tmp));
|
||||
|
||||
/* read the network */
|
||||
if (last4 == NULL && (config->network.ipv4 && config->network.ipv4_netmask)) {
|
||||
t4 = (void*)&tmp;
|
||||
t4->sin_family = AF_INET;
|
||||
|
||||
ret =
|
||||
inet_pton(AF_INET, config->network.ipv4, SA_IN_P(t4));
|
||||
|
||||
if (ret != 1) {
|
||||
syslog(LOG_ERR, "Error reading IP: %s\n", config->network.ipv4);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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 */
|
||||
for (i=0;i<sizeof(struct in_addr);i++)
|
||||
SA_IN_U8_P(t4)[i] &= (SA_IN_U8_P(&mask)[i]);
|
||||
|
||||
/* add one to get local IP */
|
||||
i = sizeof(struct in_addr)-1;
|
||||
SA_IN_U8_P(t4)[i]++;
|
||||
|
||||
lease->lip4_len = sizeof(struct sockaddr_in);
|
||||
memcpy(&lease->lip4, t4, lease->lip4_len);
|
||||
|
||||
/* add one to get remote IP */
|
||||
i = sizeof(struct in_addr)-1;
|
||||
SA_IN_U8_P(t4)[i]++;
|
||||
|
||||
lease->rip4_len = sizeof(struct sockaddr_in);
|
||||
memcpy(&lease->rip4, t4, lease->rip4_len);
|
||||
|
||||
} else if (last4 != NULL) {
|
||||
ret =
|
||||
inet_pton(AF_INET, config->network.ipv4_netmask, SA_IN_P(&mask));
|
||||
|
||||
if (ret != 1) {
|
||||
syslog(LOG_ERR, "Error reading mask: %s\n", config->network.ipv4_netmask);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* mask the network */
|
||||
lease->lip4_len = last4->rip4_len;
|
||||
memcpy(&lease->lip4, &last4->rip4, lease->rip4_len);
|
||||
|
||||
bignum_add1(SA_IN_U8_P(&lease->lip4), sizeof(struct in_addr));
|
||||
if (SA_IN_U8_P(&lease->lip4)[3] == 255) /* broadcast */
|
||||
bignum_add1(SA_IN_U8_P(&lease->lip4), sizeof(struct in_addr));
|
||||
|
||||
lease->rip4_len = last4->rip4_len;
|
||||
memcpy(&lease->rip4, &lease->lip4, lease->rip4_len);
|
||||
bignum_add1(SA_IN_U8_P(&lease->rip4), sizeof(struct in_addr));
|
||||
|
||||
/* mask the last IP with the complement of netmask */
|
||||
memcpy(&tmp, &lease->rip4, lease->rip4_len);
|
||||
for (i=0;i<sizeof(struct in_addr);i++)
|
||||
SA_IN_U8_P(t4)[i] &= ~(SA_IN_U8_P(&mask)[i]);
|
||||
|
||||
if (memcmp(&tmp, &lease->rip4, lease->rip4_len) != 0) {
|
||||
syslog(LOG_ERR, "Reached limit of maximum IPs.\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (last6 == NULL && (config->network.ipv6 && config->network.ipv6_netmask)) {
|
||||
t6 = (void*)&tmp;
|
||||
t6->sin6_family = AF_INET6;
|
||||
|
||||
ret =
|
||||
inet_pton(AF_INET6, config->network.ipv6, SA_IN6_P(t6));
|
||||
|
||||
if (ret != 1) {
|
||||
syslog(LOG_ERR, "Error reading IP: %s\n", config->network.ipv6);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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 */
|
||||
for (i=0;i<sizeof(struct in6_addr);i++)
|
||||
SA_IN6_U8_P(t6)[i] &= (SA_IN6_U8_P(&mask)[i]);
|
||||
|
||||
/* add one to get local IP */
|
||||
i = sizeof(struct in6_addr)-1;
|
||||
SA_IN6_U8_P(t6)[i]++;
|
||||
|
||||
lease->lip6_len = sizeof(struct sockaddr_in6);
|
||||
memcpy(&lease->lip6, t6, lease->lip6_len);
|
||||
|
||||
/* add one to get remote IP */
|
||||
i = sizeof(struct in6_addr)-1;
|
||||
SA_IN6_U8_P(t6)[i]++;
|
||||
|
||||
lease->rip6_len = sizeof(struct sockaddr_in6);
|
||||
memcpy(&lease->rip6, t6, lease->rip6_len);
|
||||
} else if (last6 != NULL) {
|
||||
ret =
|
||||
inet_pton(AF_INET6, config->network.ipv6_netmask, SA_IN6_P(&mask));
|
||||
|
||||
if (ret != 1) {
|
||||
syslog(LOG_ERR, "Error reading mask: %s\n", config->network.ipv6_netmask);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* mask the network */
|
||||
lease->lip6_len = last6->rip6_len;
|
||||
memcpy(&lease->lip6, &last6->rip6, lease->rip6_len);
|
||||
bignum_add1(SA_IN6_U8_P(&lease->lip6), sizeof(struct in6_addr));
|
||||
|
||||
lease->rip6_len = last6->rip6_len;
|
||||
memcpy(&lease->rip6, &lease->lip6, lease->rip6_len);
|
||||
bignum_add1(SA_IN6_U8_P(&lease->rip6), sizeof(struct in6_addr));
|
||||
|
||||
/* mask the last IP with the complement of netmask */
|
||||
memcpy(&tmp, &lease->rip6, lease->rip6_len);
|
||||
for (i=0;i<sizeof(struct in6_addr);i++)
|
||||
SA_IN6_U8_P(t6)[i] &= ~(SA_IN6_U8_P(&mask)[i]);
|
||||
|
||||
if (memcmp(&tmp, &lease->rip6, lease->rip6_len) != 0) {
|
||||
syslog(LOG_ERR, "Reached limit of maximum IPs.\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (lease->lip6_len == 0 && lease->lip4_len == 0) {
|
||||
syslog(LOG_ERR, "No IPv4 or IPv6 addresses are configured. Cannot obtain lease.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
lease->tun_nr = 0;
|
||||
if (last4)
|
||||
lease->tun_nr = MAX(lease->tun_nr, last4->tun_nr+1);
|
||||
if (last6)
|
||||
lease->tun_nr = MAX(lease->tun_nr, last6->tun_nr+1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_network_info( const struct lease_st *lease)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int fd, ret;
|
||||
void* p;
|
||||
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
/* set netmask */
|
||||
if (vinfo->ipv4) {
|
||||
if (lease->lip4_len > 0 && lease->rip4_len > 0) {
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", vname);
|
||||
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", lease->name);
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", vname);
|
||||
|
||||
ret =
|
||||
inet_pton(AF_INET, vinfo->ipv4,
|
||||
&((struct sockaddr_in *) &ifr.ifr_addr)->
|
||||
sin_addr);
|
||||
if (ret != 1) {
|
||||
syslog(LOG_ERR, "%s: Error reading IP: %s\n",
|
||||
vname, vinfo->ipv4);
|
||||
goto fail;
|
||||
|
||||
}
|
||||
memcpy(&ifr.ifr_addr, &lease->lip4, lease->lip4_len);
|
||||
|
||||
ret = ioctl(fd, SIOCSIFADDR, &ifr);
|
||||
if (ret != 0) {
|
||||
syslog(LOG_ERR, "%s: Error setting IP: %s\n",
|
||||
vname, vinfo->ipv4);
|
||||
syslog(LOG_ERR, "%s: Error setting IPv4.\n", lease->name);
|
||||
}
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", lease->name);
|
||||
memcpy(&ifr.ifr_dstaddr, &lease->rip4, lease->rip4_len);
|
||||
|
||||
ret = ioctl(fd, SIOCSIFDSTADDR, &ifr);
|
||||
if (ret != 0) {
|
||||
syslog(LOG_ERR, "%s: Error setting DST IPv4.\n", lease->name);
|
||||
}
|
||||
}
|
||||
|
||||
if (vinfo->ipv6) {
|
||||
if (lease->lip6_len > 0 && lease->rip6_len > 0) {
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_addr.sa_family = AF_INET6;
|
||||
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", vname);
|
||||
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", lease->name);
|
||||
|
||||
ret =
|
||||
inet_pton(AF_INET6, vinfo->ipv6,
|
||||
&((struct sockaddr_in6 *) &ifr.ifr_addr)->
|
||||
sin6_addr);
|
||||
if (ret != 1) {
|
||||
syslog(LOG_ERR, "%s: Error reading IP: %s\n",
|
||||
vname, vinfo->ipv6);
|
||||
goto fail;
|
||||
}
|
||||
memcpy(&ifr.ifr_addr, &lease->lip6, lease->lip6_len);
|
||||
|
||||
ret = ioctl(fd, SIOCSIFADDR, &ifr);
|
||||
if (ret != 0) {
|
||||
syslog(LOG_ERR, "%s: Error setting IP: %s\n",
|
||||
vname, vinfo->ipv6);
|
||||
syslog(LOG_ERR, "%s: Error setting IPv6.\n", lease->name);
|
||||
}
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_addr.sa_family = AF_INET6;
|
||||
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", lease->name);
|
||||
memcpy(&ifr.ifr_dstaddr, &lease->rip6, lease->rip6_len);
|
||||
|
||||
ret = ioctl(fd, SIOCSIFDSTADDR, &ifr);
|
||||
if (ret != 0) {
|
||||
syslog(LOG_ERR, "%s: Error setting DST IPv6.\n", lease->name);
|
||||
}
|
||||
}
|
||||
|
||||
if (lease->lip6_len == 0 && lease->lip4_len == 0) {
|
||||
syslog(LOG_ERR, "%s: Could not set any IP.\n", lease->name);
|
||||
ret = -1;
|
||||
} else
|
||||
ret = 0;
|
||||
fail:
|
||||
fail:
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int open_tun(const struct cfg_st *config, const struct tun_st* tun, struct tun_id_st *id)
|
||||
|
||||
int open_tun(const struct cfg_st *config, struct tun_st* tun, struct lease_st** l)
|
||||
{
|
||||
int tunfd, ret, e;
|
||||
struct ifreq ifr;
|
||||
unsigned int t;
|
||||
struct lease_st *lease = NULL;
|
||||
struct list_head *pos;
|
||||
struct lease_st *last4, *tmp;
|
||||
struct lease_st *last6;
|
||||
|
||||
if (list_empty(&tun->lease_list.list)) {
|
||||
lease = calloc(1, sizeof(*lease));
|
||||
if (lease == NULL)
|
||||
return -1;
|
||||
|
||||
/* find the first IP address */
|
||||
ret = get_avail_network_addresses(config, NULL, NULL, lease);
|
||||
if (ret < 0) {
|
||||
free(lease);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Add into the list */
|
||||
list_add_tail( &lease->list, &tun->lease_list.list);
|
||||
} else {
|
||||
last4 = last6 = NULL;
|
||||
|
||||
/* try to re-use an address */
|
||||
list_for_each(pos, &tun->lease_list.list) {
|
||||
tmp = list_entry(pos, struct lease_st, list);
|
||||
if (tmp->in_use == 0) {
|
||||
lease = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (lease == NULL) { /* nothing to re-use */
|
||||
lease = calloc(1, sizeof(*lease));
|
||||
if (lease == NULL)
|
||||
return -1;
|
||||
|
||||
list_for_each_prev(pos, &tun->lease_list.list) {
|
||||
tmp = list_entry(pos, struct lease_st, list);
|
||||
if (tmp->rip4_len > 0)
|
||||
last4 = tmp;
|
||||
|
||||
if (tmp->rip6_len > 0)
|
||||
last6 = tmp;
|
||||
|
||||
if (last4 && last6)
|
||||
break;
|
||||
}
|
||||
|
||||
ret = get_avail_network_addresses(config, last4, last6, lease);
|
||||
if (ret < 0) {
|
||||
free(lease);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Add into the list */
|
||||
list_add_tail( &lease->list, &tun->lease_list.list);
|
||||
}
|
||||
}
|
||||
|
||||
/* No need to free the lease after this point.
|
||||
*/
|
||||
|
||||
/* XXX obtain random IPs + tun nr */
|
||||
#warning fix
|
||||
tunfd = open("/dev/net/tun", O_RDWR);
|
||||
if (tunfd < 0) {
|
||||
int e = errno;
|
||||
@@ -117,8 +372,8 @@ int open_tun(const struct cfg_st *config, const struct tun_st* tun, struct tun_i
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
|
||||
|
||||
snprintf(id->name, sizeof(id->name), "%s%u", config->network.name, 0);
|
||||
memcpy(ifr.ifr_name, id->name, sizeof(ifr.ifr_name));
|
||||
snprintf(lease->name, sizeof(lease->name), "%s%u", config->network.name, 0);
|
||||
memcpy(ifr.ifr_name, lease->name, sizeof(ifr.ifr_name));
|
||||
|
||||
if (ioctl(tunfd, TUNSETIFF, (void *) &ifr) < 0) {
|
||||
e = errno;
|
||||
@@ -149,12 +404,13 @@ int open_tun(const struct cfg_st *config, const struct tun_st* tun, struct tun_i
|
||||
}
|
||||
|
||||
/* set IP/mask */
|
||||
ret = set_network_info(id->name, &config->network);
|
||||
ret = set_network_info(lease);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
id->fd = tunfd;
|
||||
lease->fd = tunfd;
|
||||
*l = lease;
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
|
||||
35
src/tun.h
35
src/tun.h
@@ -2,8 +2,41 @@
|
||||
# define TUN_H
|
||||
|
||||
#include <vpn.h>
|
||||
#include <list.h>
|
||||
|
||||
struct lease_st {
|
||||
struct list_head list;
|
||||
|
||||
int open_tun(const struct cfg_st *config, const struct tun_st* tun, struct tun_id_st *id);
|
||||
char name[IFNAMSIZ];
|
||||
unsigned int tun_nr;
|
||||
unsigned int in_use;
|
||||
|
||||
struct sockaddr_storage rip4;
|
||||
socklen_t rip4_len;
|
||||
|
||||
struct sockaddr_storage lip4;
|
||||
socklen_t lip4_len;
|
||||
|
||||
struct sockaddr_storage rip6;
|
||||
socklen_t rip6_len;
|
||||
|
||||
struct sockaddr_storage lip6;
|
||||
socklen_t lip6_len;
|
||||
|
||||
/* this is used temporarily. */
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct tun_st {
|
||||
struct lease_st lease_list;
|
||||
};
|
||||
|
||||
inline static void tun_st_init(struct tun_st* ts)
|
||||
{
|
||||
memset(ts, 0, sizeof(*ts));
|
||||
INIT_LIST_HEAD(&ts->lease_list.list);
|
||||
}
|
||||
|
||||
int open_tun(const struct cfg_st *config, struct tun_st* tun, struct lease_st **lease);
|
||||
|
||||
#endif
|
||||
|
||||
22
src/vpn.c
22
src/vpn.c
@@ -183,7 +183,7 @@ char* tmp = malloc(length+1);
|
||||
|
||||
void vpn_server(struct cfg_st *config, struct tls_st *creds,
|
||||
struct sockaddr_storage* r_addr, socklen_t r_addr_len,
|
||||
int cmdfd, int fd)
|
||||
int cmd_fd, int fd)
|
||||
{
|
||||
unsigned char buf[2048];
|
||||
int ret;
|
||||
@@ -238,8 +238,8 @@ void vpn_server(struct cfg_st *config, struct tls_st *creds,
|
||||
server->config = config;
|
||||
server->session = session;
|
||||
server->parser = &parser;
|
||||
server->cmdfd = cmdfd;
|
||||
server->tunid.fd = -1;
|
||||
server->cmd_fd = cmd_fd;
|
||||
server->tun_fd = -1;
|
||||
|
||||
restart:
|
||||
http_parser_init(&parser, HTTP_REQUEST);
|
||||
@@ -375,7 +375,7 @@ struct ifreq ifr;
|
||||
const char* p;
|
||||
|
||||
memset(vinfo, 0, sizeof(*vinfo));
|
||||
vinfo->name = server->tunid.name;
|
||||
vinfo->name = server->tun_name;
|
||||
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (fd == -1)
|
||||
@@ -525,10 +525,10 @@ unsigned int buffer_size;
|
||||
FD_ZERO(&rfds);
|
||||
|
||||
FD_SET(tls_fd, &rfds);
|
||||
FD_SET(server->cmdfd, &rfds);
|
||||
FD_SET(server->tunid.fd, &rfds);
|
||||
max = MAX(server->cmdfd,tls_fd);
|
||||
max = MAX(max,server->tunid.fd);
|
||||
FD_SET(server->cmd_fd, &rfds);
|
||||
FD_SET(server->tun_fd, &rfds);
|
||||
max = MAX(server->cmd_fd,tls_fd);
|
||||
max = MAX(max,server->tun_fd);
|
||||
|
||||
if (gnutls_record_check_pending(server->session) == 0) {
|
||||
ret = select(max + 1, &rfds, NULL, NULL, NULL);
|
||||
@@ -536,8 +536,8 @@ unsigned int buffer_size;
|
||||
break;
|
||||
}
|
||||
|
||||
if (FD_ISSET(server->tunid.fd, &rfds)) {
|
||||
int l = read(server->tunid.fd, buf + 8, sizeof(buf) - 8);
|
||||
if (FD_ISSET(server->tun_fd, &rfds)) {
|
||||
int l = read(server->tun_fd, buf + 8, sizeof(buf) - 8);
|
||||
buf[0] = 'S';
|
||||
buf[1] = 'T';
|
||||
buf[2] = 'F';
|
||||
@@ -588,7 +588,7 @@ unsigned int buffer_size;
|
||||
break;
|
||||
|
||||
case AC_PKT_DATA:
|
||||
write(server->tunid.fd, buf + 8, pktlen);
|
||||
write(server->tun_fd, buf + 8, pktlen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
18
src/vpn.h
18
src/vpn.h
@@ -28,11 +28,6 @@ extern int syslog_open;
|
||||
#define MAX_NETWORKS 24
|
||||
#define MAX_ROUTES 64
|
||||
|
||||
struct tun_st {
|
||||
const char *ign;
|
||||
|
||||
};
|
||||
|
||||
struct vpn_st {
|
||||
const char *name; /* device name */
|
||||
const char *ipv4_netmask;
|
||||
@@ -69,20 +64,19 @@ struct cfg_st {
|
||||
struct vpn_st network;
|
||||
};
|
||||
|
||||
#include <tun.h>
|
||||
|
||||
struct tls_st {
|
||||
gnutls_certificate_credentials_t xcred;
|
||||
gnutls_priority_t cprio;
|
||||
};
|
||||
|
||||
struct tun_id_st {
|
||||
char name[IFNAMSIZ];
|
||||
int fd;
|
||||
};
|
||||
|
||||
typedef struct server_st {
|
||||
gnutls_session_t session;
|
||||
struct tun_id_st tunid;
|
||||
int cmdfd;
|
||||
char tun_name[IFNAMSIZ];
|
||||
int tun_fd;
|
||||
|
||||
int cmd_fd;
|
||||
http_parser *parser;
|
||||
struct cfg_st *config;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user