mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-02-10 16:57:00 +08:00
Increased the number of directives allowed in group and user configurations.
This commit is contained in:
@@ -16,7 +16,7 @@ CCAN_SOURCES = ccan/build_assert/build_assert.h ccan/check_type/check_type.h \
|
|||||||
|
|
||||||
ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \
|
ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \
|
||||||
http-parser/http_parser.c ipc.h cookies.c worker-tun.c main-misc.c \
|
http-parser/http_parser.c ipc.h cookies.c worker-tun.c main-misc.c \
|
||||||
main-config.c \
|
main-config.c ip-lease.c ip-lease.h \
|
||||||
vpn.h cookies.h tlslib.h http-parser/http_parser.h log.c tun.c tun.h \
|
vpn.h cookies.h tlslib.h http-parser/http_parser.h log.c tun.c tun.h \
|
||||||
config.c pam.c pam.h worker-resume.c worker.h main-resume.c main.h \
|
config.c pam.c pam.h worker-resume.c worker.h main-resume.c main.h \
|
||||||
worker-extras.c main-auth.h html.c html.h \
|
worker-extras.c main-auth.h html.c html.h \
|
||||||
|
|||||||
12
src/common.c
12
src/common.c
@@ -20,6 +20,9 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <vpn.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
ssize_t force_write(int sockfd, const void *buf, size_t len)
|
ssize_t force_write(int sockfd, const void *buf, size_t len)
|
||||||
{
|
{
|
||||||
@@ -64,3 +67,12 @@ uint8_t * p = buf;
|
|||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ip_cmp(const struct sockaddr_storage *s1, const struct sockaddr_storage *s2, size_t n)
|
||||||
|
{
|
||||||
|
if (((struct sockaddr*)s1)->sa_family == AF_INET) {
|
||||||
|
return memcmp(SA_IN_P(s1), SA_IN_P(s2), sizeof(struct in_addr));
|
||||||
|
} else { /* inet6 */
|
||||||
|
return memcmp(SA_IN6_P(s1), SA_IN6_P(s2), sizeof(struct in6_addr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
# define COMMON_H
|
# define COMMON_H
|
||||||
ssize_t force_write(int sockfd, const void *buf, size_t len);
|
ssize_t force_write(int sockfd, const void *buf, size_t len);
|
||||||
ssize_t force_read(int sockfd, void *buf, size_t len);
|
ssize_t force_read(int sockfd, void *buf, size_t len);
|
||||||
|
int ip_cmp(const struct sockaddr_storage *s1, const struct sockaddr_storage *s2, size_t n);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
391
src/ip-lease.c
Normal file
391
src/ip-lease.c
Normal file
@@ -0,0 +1,391 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Nikos Mavrogiannopoulos
|
||||||
|
*
|
||||||
|
* This program 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.
|
||||||
|
*
|
||||||
|
* This program 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <ip-lease.h>
|
||||||
|
#include <main.h>
|
||||||
|
#include <common.h>
|
||||||
|
#include <gnutls/crypto.h>
|
||||||
|
#include <icmp-ping.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
static void bignum_add (uint8_t * num, unsigned size, unsigned step)
|
||||||
|
{
|
||||||
|
register int i;
|
||||||
|
register unsigned tmp, y;
|
||||||
|
|
||||||
|
for (i = size-1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
tmp = num[i];
|
||||||
|
|
||||||
|
num[i] += step;
|
||||||
|
if (num[i] < tmp)
|
||||||
|
y = 1;
|
||||||
|
else
|
||||||
|
y = 0;
|
||||||
|
|
||||||
|
if (y == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ip_lease_deinit(struct ip_lease_db_st* db)
|
||||||
|
{
|
||||||
|
struct ip_lease_st * cache;
|
||||||
|
struct htable_iter iter;
|
||||||
|
|
||||||
|
cache = htable_first(&db->ht, &iter);
|
||||||
|
while(cache != NULL) {
|
||||||
|
free(cache);
|
||||||
|
|
||||||
|
cache = htable_next(&db->ht, &iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
htable_clear(&db->ht);
|
||||||
|
db->entries = 0;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t rehash(const void* _e, void* unused)
|
||||||
|
{
|
||||||
|
const struct ip_lease_st * e = _e;
|
||||||
|
|
||||||
|
return hash_stable_8(&e->rip, e->rip_len, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ip_lease_init(struct ip_lease_db_st* db)
|
||||||
|
{
|
||||||
|
htable_init(&db->ht, rehash, NULL);
|
||||||
|
db->entries = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ip_lease_cmp(const void* _c1, void* _c2)
|
||||||
|
{
|
||||||
|
const struct ip_lease_st* c1 = _c1;
|
||||||
|
struct ip_lease_st* c2 = _c2;
|
||||||
|
|
||||||
|
if (c1->rip_len == c2->rip_len &&
|
||||||
|
ip_cmp(&c1->rip, &c2->rip, c2->rip_len) == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ip_lease_exists(main_server_st* s, struct sockaddr_storage* ip, size_t sockaddrlen)
|
||||||
|
{
|
||||||
|
struct ip_lease_st t;
|
||||||
|
|
||||||
|
t.rip_len = sockaddrlen;
|
||||||
|
memcpy(&t.rip, ip, sizeof(*ip));
|
||||||
|
|
||||||
|
if (htable_get(&s->ip_leases.ht, rehash(&t, NULL), ip_lease_cmp, &t) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_IP_TRIES 16
|
||||||
|
|
||||||
|
static
|
||||||
|
int get_ipv4_lease(main_server_st* s, struct proc_st* proc)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct sockaddr_storage tmp, mask, network, rnd;
|
||||||
|
unsigned i;
|
||||||
|
unsigned max_loops = MAX_IP_TRIES;
|
||||||
|
int ret;
|
||||||
|
const char* c_network, *c_netmask;
|
||||||
|
char buf[64];
|
||||||
|
|
||||||
|
if (proc->config.ipv4_network && proc->config.ipv4_netmask) {
|
||||||
|
c_network = proc->config.ipv4_network;
|
||||||
|
c_netmask = proc->config.ipv4_netmask;
|
||||||
|
} else {
|
||||||
|
c_network = s->config->network.ipv4;
|
||||||
|
c_netmask = s->config->network.ipv4_netmask;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c_network && c_netmask) {
|
||||||
|
ret =
|
||||||
|
inet_pton(AF_INET, c_network, SA_IN_P(&network));
|
||||||
|
|
||||||
|
if (ret != 1) {
|
||||||
|
mslog(s, NULL, LOG_ERR, "Error reading IP: %s\n", c_network);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret =
|
||||||
|
inet_pton(AF_INET, c_netmask, SA_IN_P(&mask));
|
||||||
|
|
||||||
|
if (ret != 1) {
|
||||||
|
mslog(s, NULL, LOG_ERR, "Error reading mask: %s\n", c_netmask);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
proc->ipv4 = calloc(1, sizeof(*proc->ipv4));
|
||||||
|
if (proc->ipv4 == NULL)
|
||||||
|
return ERR_MEM;
|
||||||
|
|
||||||
|
/* mask the network (just in case it is wrong) */
|
||||||
|
for (i=0;i<sizeof(struct in_addr);i++)
|
||||||
|
SA_IN_U8_P(&network)[i] &= (SA_IN_U8_P(&mask)[i]);
|
||||||
|
((struct sockaddr_in*)&network)->sin_family = AF_INET;
|
||||||
|
((struct sockaddr_in*)&network)->sin_port = 0;
|
||||||
|
|
||||||
|
memcpy(&tmp, &network, sizeof(tmp));
|
||||||
|
((struct sockaddr_in*)&tmp)->sin_family = AF_INET;
|
||||||
|
((struct sockaddr_in*)&tmp)->sin_port = 0;
|
||||||
|
|
||||||
|
((struct sockaddr_in*)&rnd)->sin_family = AF_INET;
|
||||||
|
((struct sockaddr_in*)&rnd)->sin_port = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (max_loops == 0) {
|
||||||
|
mslog(s, proc, LOG_ERR, "Could not figure out a valid IPv4 IP.\n");
|
||||||
|
ret = ERR_NO_IP;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (max_loops == MAX_IP_TRIES) {
|
||||||
|
uint32_t t = hash_any(proc->username, strlen(proc->username), 0);
|
||||||
|
memcpy(SA_IN_U8_P(&rnd), &t, 4);
|
||||||
|
} else
|
||||||
|
gnutls_rnd(GNUTLS_RND_NONCE, SA_IN_U8_P(&rnd), sizeof(struct in_addr));
|
||||||
|
max_loops--;
|
||||||
|
|
||||||
|
if (SA_IN_U8_P(&rnd)[3] == 255) /* broadcast */
|
||||||
|
bignum_add(SA_IN_U8_P(&rnd), sizeof(struct in_addr), 1);
|
||||||
|
|
||||||
|
/* Mask the random number with the netmask */
|
||||||
|
for (i=0;i<sizeof(struct in_addr);i++) {
|
||||||
|
SA_IN_U8_P(&rnd)[i] &= ~(SA_IN_U8_P(&mask)[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
SA_IN_U8_P(&rnd)[sizeof(struct in_addr)-1] &= 0xFE;
|
||||||
|
|
||||||
|
/* Now add the IP to the masked random number */
|
||||||
|
for (i=0;i<sizeof(struct in_addr);i++)
|
||||||
|
SA_IN_U8_P(&rnd)[i] |= (SA_IN_U8_P(&network)[i]);
|
||||||
|
|
||||||
|
/* check if it exists in the hash table */
|
||||||
|
if (ip_lease_exists(s, &rnd, sizeof(struct sockaddr_in)) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
memcpy(&proc->ipv4->lip, &rnd, sizeof(struct sockaddr_in));
|
||||||
|
proc->ipv4->lip_len = sizeof(struct sockaddr_in);
|
||||||
|
|
||||||
|
/* RIP = LIP + 1 */
|
||||||
|
memcpy(&tmp, &proc->ipv4->lip, sizeof(struct sockaddr_in));
|
||||||
|
bignum_add(SA_IN_U8_P(&tmp), sizeof(struct in_addr), 1);
|
||||||
|
|
||||||
|
/* check if it exists in the hash table */
|
||||||
|
if (ip_lease_exists(s, &tmp, sizeof(struct sockaddr_in)) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
memcpy(&proc->ipv4->rip, &tmp, sizeof(struct sockaddr_in));
|
||||||
|
proc->ipv4->rip_len = sizeof(struct sockaddr_in);
|
||||||
|
|
||||||
|
/* mask the last IP with the netmask */
|
||||||
|
for (i=0;i<sizeof(struct in_addr);i++)
|
||||||
|
SA_IN_U8_P(&tmp)[i] &= (SA_IN_U8_P(&mask)[i]);
|
||||||
|
|
||||||
|
/* the result should match the network */
|
||||||
|
if (memcmp(SA_IN_U8_P(&network), SA_IN_U8_P(&tmp), sizeof(struct in_addr)) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
mslog(s, proc, LOG_DEBUG, "Selected IP: %s\n",
|
||||||
|
human_addr((void*)&proc->ipv4->lip, proc->ipv4->lip_len, buf, sizeof(buf)));
|
||||||
|
|
||||||
|
if (icmp_ping4(s, (void*)&proc->ipv4->lip, (void*)&proc->ipv4->rip) == 0)
|
||||||
|
break;
|
||||||
|
} while(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
free(proc->ipv4);
|
||||||
|
proc->ipv4 = NULL;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int get_ipv6_lease(main_server_st* s, struct proc_st* proc)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct sockaddr_storage tmp, mask, network, rnd;
|
||||||
|
unsigned i, max_loops = MAX_IP_TRIES;
|
||||||
|
int ret;
|
||||||
|
const char* c_network, *c_netmask;
|
||||||
|
|
||||||
|
if (proc->config.ipv6_network && proc->config.ipv6_netmask) {
|
||||||
|
c_network = proc->config.ipv6_network;
|
||||||
|
c_netmask = proc->config.ipv6_netmask;
|
||||||
|
} else {
|
||||||
|
c_network = s->config->network.ipv6;
|
||||||
|
c_netmask = s->config->network.ipv6_netmask;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c_network && c_netmask) {
|
||||||
|
ret =
|
||||||
|
inet_pton(AF_INET6, c_network, SA_IN6_P(&network));
|
||||||
|
|
||||||
|
if (ret != 1) {
|
||||||
|
mslog(s, NULL, LOG_ERR, "Error reading IP: %s\n", c_network);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret =
|
||||||
|
inet_pton(AF_INET6, c_netmask, SA_IN6_P(&mask));
|
||||||
|
|
||||||
|
if (ret != 1) {
|
||||||
|
mslog(s, NULL, LOG_ERR, "Error reading mask: %s\n", c_netmask);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
proc->ipv6 = calloc(1, sizeof(*proc->ipv6));
|
||||||
|
if (proc->ipv6 == NULL)
|
||||||
|
return ERR_MEM;
|
||||||
|
|
||||||
|
/* mask the network */
|
||||||
|
for (i=0;i<sizeof(struct in6_addr);i++)
|
||||||
|
SA_IN6_U8_P(&network)[i] &= (SA_IN6_U8_P(&mask)[i]);
|
||||||
|
((struct sockaddr_in6*)&network)->sin6_family = AF_INET6;
|
||||||
|
((struct sockaddr_in6*)&network)->sin6_port = 0;
|
||||||
|
|
||||||
|
memcpy(&tmp, &network, sizeof(tmp));
|
||||||
|
((struct sockaddr_in6*)&tmp)->sin6_family = AF_INET6;
|
||||||
|
((struct sockaddr_in6*)&tmp)->sin6_port = AF_INET6;
|
||||||
|
|
||||||
|
((struct sockaddr_in6*)&rnd)->sin6_family = AF_INET6;
|
||||||
|
((struct sockaddr_in6*)&rnd)->sin6_port = AF_INET6;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (max_loops == 0) {
|
||||||
|
mslog(s, NULL, LOG_ERR, "Could not figure out a valid IPv6 IP.\n");
|
||||||
|
ret = ERR_NO_IP;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_loops == MAX_IP_TRIES) {
|
||||||
|
uint32_t t = hash_any(proc->username, strlen(proc->username), 0);
|
||||||
|
memset(SA_IN6_U8_P(&rnd), 0, sizeof(struct in6_addr));
|
||||||
|
memcpy(SA_IN6_U8_P(&rnd)+sizeof(struct in6_addr)-5, &t, 4);
|
||||||
|
} else
|
||||||
|
gnutls_rnd(GNUTLS_RND_NONCE, SA_IN6_U8_P(&rnd), sizeof(struct in6_addr));
|
||||||
|
max_loops--;
|
||||||
|
|
||||||
|
/* Mask the random number with the netmask */
|
||||||
|
for (i=0;i<sizeof(struct in6_addr);i++)
|
||||||
|
SA_IN6_U8_P(&rnd)[i] &= ~(SA_IN6_U8_P(&mask)[i]);
|
||||||
|
|
||||||
|
SA_IN6_U8_P(&rnd)[sizeof(struct in6_addr)-1] &= 0xFE;
|
||||||
|
|
||||||
|
/* Now add the network to the masked random number */
|
||||||
|
for (i=0;i<sizeof(struct in6_addr);i++)
|
||||||
|
SA_IN6_U8_P(&rnd)[i] |= (SA_IN6_U8_P(&network)[i]);
|
||||||
|
|
||||||
|
/* check if it exists in the hash table */
|
||||||
|
if (ip_lease_exists(s, &rnd, sizeof(struct sockaddr_in6)) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
proc->ipv6->lip_len = sizeof(struct sockaddr_in6);
|
||||||
|
memcpy(&proc->ipv6->lip, &rnd, proc->ipv6->lip_len);
|
||||||
|
|
||||||
|
/* RIP = LIP + 1 */
|
||||||
|
memcpy(&tmp, &proc->ipv6->lip, proc->ipv6->rip_len);
|
||||||
|
|
||||||
|
bignum_add(SA_IN6_U8_P(&tmp), sizeof(struct in6_addr), 1);
|
||||||
|
|
||||||
|
/* check if it exists in the hash table */
|
||||||
|
if (ip_lease_exists(s, &tmp, sizeof(struct sockaddr_in6)) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
proc->ipv6->rip_len = sizeof(struct sockaddr_in6);
|
||||||
|
memcpy(&proc->ipv6->rip, &tmp, proc->ipv6->rip_len);
|
||||||
|
|
||||||
|
/* mask the last IP with the netmask */
|
||||||
|
for (i=0;i<sizeof(struct in6_addr);i++)
|
||||||
|
SA_IN6_U8_P(&tmp)[i] &= (SA_IN6_U8_P(&mask)[i]);
|
||||||
|
|
||||||
|
/* the result should match the network */
|
||||||
|
if (memcmp(SA_IN6_U8_P(&network), SA_IN6_U8_P(&tmp), sizeof(struct in6_addr)) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (icmp_ping6(s, (void*)&proc->ipv6->lip, (void*)&proc->ipv6->rip) == 0)
|
||||||
|
break;
|
||||||
|
} while(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
fail:
|
||||||
|
free(proc->ipv6);
|
||||||
|
proc->ipv6 = NULL;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_ip_leases(main_server_st* s, struct proc_st* proc)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = get_ipv4_lease(s, proc);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = get_ipv6_lease(s, proc);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (proc->ipv4)
|
||||||
|
htable_add(&s->ip_leases.ht, rehash(proc->ipv4, NULL), proc->ipv4);
|
||||||
|
|
||||||
|
if (proc->ipv6)
|
||||||
|
htable_add(&s->ip_leases.ht, rehash(proc->ipv6, NULL), proc->ipv6);
|
||||||
|
|
||||||
|
if (proc->ipv4 == 0 && proc->ipv6 == 0) {
|
||||||
|
mslog(s, NULL, LOG_ERR, "No IPv4 or IPv6 addresses are configured. Cannot obtain lease.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove_ip_leases(main_server_st* s, struct proc_st* proc)
|
||||||
|
{
|
||||||
|
if (proc->ipv4) {
|
||||||
|
htable_del(&s->ip_leases.ht, rehash(proc->ipv4, NULL), proc->ipv4);
|
||||||
|
free(proc->ipv4);
|
||||||
|
proc->ipv4 = NULL;
|
||||||
|
}
|
||||||
|
if (proc->ipv6) {
|
||||||
|
htable_del(&s->ip_leases.ht, rehash(proc->ipv6, NULL), proc->ipv6);
|
||||||
|
free(proc->ipv6);
|
||||||
|
proc->ipv6 = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/ip-lease.h
Normal file
24
src/ip-lease.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef IP_LEASE_H
|
||||||
|
# define IP_LEASE_H
|
||||||
|
|
||||||
|
#include <vpn.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <ccan/hash/hash.h>
|
||||||
|
#include <main.h>
|
||||||
|
|
||||||
|
struct ip_lease_st {
|
||||||
|
struct sockaddr_storage rip;
|
||||||
|
socklen_t rip_len;
|
||||||
|
|
||||||
|
struct sockaddr_storage lip;
|
||||||
|
socklen_t lip_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
void ip_lease_deinit(struct ip_lease_db_st* db);
|
||||||
|
void ip_lease_init(struct ip_lease_db_st* db);
|
||||||
|
|
||||||
|
int get_ip_leases(struct main_server_st* s, struct proc_st* proc);
|
||||||
|
void remove_ip_leases(struct main_server_st* s, struct proc_st* proc);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -87,8 +87,7 @@ struct __attribute__ ((__packed__)) cmd_auth_reply_st {
|
|||||||
char vname[IFNAMSIZ]; /* interface name */
|
char vname[IFNAMSIZ]; /* interface name */
|
||||||
char user[MAX_USERNAME_SIZE];
|
char user[MAX_USERNAME_SIZE];
|
||||||
|
|
||||||
uint8_t routes_size; /* up to MAX_ROUTES */
|
/* additional data follow */
|
||||||
/* routes_size routes of cmd_auth_reply_route_st follow */
|
|
||||||
} ok;
|
} ok;
|
||||||
/* in case of REP_AUTH_MSG */
|
/* in case of REP_AUTH_MSG */
|
||||||
char msg[MAX_MSG_SIZE];
|
char msg[MAX_MSG_SIZE];
|
||||||
|
|||||||
164
src/main-auth.c
164
src/main-auth.c
@@ -61,8 +61,103 @@ void main_auth_init(main_server_st *s)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int send_str_value_length(main_server_st* s, struct proc_st* proc, char* data)
|
||||||
|
{
|
||||||
|
uint8_t len;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (data != NULL) {
|
||||||
|
len = strlen(data);
|
||||||
|
ret = force_write(proc->fd, &len, 1);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = force_write(proc->fd, proc->config.ipv4_dns, len);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
len = 0;
|
||||||
|
ret = force_write(proc->fd, &len, 1);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int serialize_additional_data(main_server_st* s, struct proc_st* proc)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
unsigned i;
|
||||||
|
uint8_t len;
|
||||||
|
|
||||||
|
/* IPv4 DNS */
|
||||||
|
if (proc->config.ipv4_dns)
|
||||||
|
mslog(s, proc, LOG_DEBUG, "sending DNS '%s'", proc->config.ipv4_dns);
|
||||||
|
ret = send_str_value_length(s, proc, proc->config.ipv4_dns);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* IPv6 DNS */
|
||||||
|
if (proc->config.ipv6_dns)
|
||||||
|
mslog(s, proc, LOG_DEBUG, "sending DNS '%s'", proc->config.ipv6_dns);
|
||||||
|
ret = send_str_value_length(s, proc, proc->config.ipv6_dns);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* IPv4 NBNS */
|
||||||
|
if (proc->config.ipv4_nbns)
|
||||||
|
mslog(s, proc, LOG_DEBUG, "sending NBNS '%s'", proc->config.ipv4_nbns);
|
||||||
|
ret = send_str_value_length(s, proc, proc->config.ipv4_nbns);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* IPv6 NBNS */
|
||||||
|
if (proc->config.ipv6_nbns)
|
||||||
|
mslog(s, proc, LOG_DEBUG, "sending NBNS '%s'", proc->config.ipv6_nbns);
|
||||||
|
ret = send_str_value_length(s, proc, proc->config.ipv6_nbns);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* IPv4 netmask */
|
||||||
|
if (proc->config.ipv4_netmask)
|
||||||
|
mslog(s, proc, LOG_DEBUG, "sending netmask '%s'", proc->config.ipv4_netmask);
|
||||||
|
ret = send_str_value_length(s, proc, proc->config.ipv4_netmask);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* IPv6 netmask */
|
||||||
|
if (proc->config.ipv6_netmask)
|
||||||
|
mslog(s, proc, LOG_DEBUG, "sending netmask '%s'", proc->config.ipv6_netmask);
|
||||||
|
ret = send_str_value_length(s, proc, proc->config.ipv6_netmask);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* routes */
|
||||||
|
len = proc->config.routes_size;
|
||||||
|
ret = force_write(proc->fd, &len, 1);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
for (i=0;i<proc->config.routes_size;i++) {
|
||||||
|
len = strlen(proc->config.routes[i]);
|
||||||
|
|
||||||
|
mslog(s, proc, LOG_DEBUG, "sending route '%s'", proc->config.routes[i]);
|
||||||
|
ret = force_write(proc->fd, &len, 1);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = force_write(proc->fd, proc->config.routes[i], len);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int send_auth_reply(main_server_st* s, struct proc_st* proc,
|
int send_auth_reply(main_server_st* s, struct proc_st* proc,
|
||||||
cmd_auth_reply_t r, struct group_cfg_st* cfg)
|
cmd_auth_reply_t r)
|
||||||
{
|
{
|
||||||
struct iovec iov[2];
|
struct iovec iov[2];
|
||||||
uint8_t cmd[2];
|
uint8_t cmd[2];
|
||||||
@@ -73,12 +168,11 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc,
|
|||||||
} control_un;
|
} control_un;
|
||||||
struct cmd_auth_reply_st resp;
|
struct cmd_auth_reply_st resp;
|
||||||
struct cmsghdr *cmptr;
|
struct cmsghdr *cmptr;
|
||||||
unsigned i;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (cfg->routes_size > MAX_ROUTES) {
|
if (proc->config.routes_size > MAX_ROUTES) {
|
||||||
mslog(s, proc, LOG_INFO, "Note that the routes sent to the client (%d) exceed the maximum allowed (%d). Truncating.", (int)cfg->routes_size, (int)MAX_ROUTES);
|
mslog(s, proc, LOG_INFO, "Note that the routes sent to the client (%d) exceed the maximum allowed (%d). Truncating.", (int)proc->config.routes_size, (int)MAX_ROUTES);
|
||||||
cfg->routes_size = MAX_ROUTES;
|
proc->config.routes_size = MAX_ROUTES;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&control_un, 0, sizeof(control_un));
|
memset(&control_un, 0, sizeof(control_un));
|
||||||
@@ -86,7 +180,7 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc,
|
|||||||
|
|
||||||
hdr.msg_iov = iov;
|
hdr.msg_iov = iov;
|
||||||
|
|
||||||
if (r == REP_AUTH_OK && proc->lease != NULL) {
|
if (r == REP_AUTH_OK && proc->tun_lease.name[0] != 0) {
|
||||||
cmd[0] = AUTH_REP;
|
cmd[0] = AUTH_REP;
|
||||||
|
|
||||||
iov[0].iov_base = cmd;
|
iov[0].iov_base = cmd;
|
||||||
@@ -96,15 +190,13 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc,
|
|||||||
resp.reply = r;
|
resp.reply = r;
|
||||||
memcpy(resp.data.ok.cookie, proc->cookie, COOKIE_SIZE);
|
memcpy(resp.data.ok.cookie, proc->cookie, COOKIE_SIZE);
|
||||||
memcpy(resp.data.ok.session_id, proc->session_id, sizeof(resp.data.ok.session_id));
|
memcpy(resp.data.ok.session_id, proc->session_id, sizeof(resp.data.ok.session_id));
|
||||||
memcpy(resp.data.ok.vname, proc->lease->name, sizeof(resp.data.ok.vname));
|
memcpy(resp.data.ok.vname, proc->tun_lease.name, sizeof(resp.data.ok.vname));
|
||||||
memcpy(resp.data.ok.user, proc->username, sizeof(resp.data.ok.user));
|
memcpy(resp.data.ok.user, proc->username, sizeof(resp.data.ok.user));
|
||||||
|
|
||||||
iov[1].iov_base = &resp;
|
iov[1].iov_base = &resp;
|
||||||
iov[1].iov_len = sizeof(resp);
|
iov[1].iov_len = sizeof(resp);
|
||||||
hdr.msg_iovlen++;
|
hdr.msg_iovlen++;
|
||||||
|
|
||||||
resp.data.ok.routes_size = cfg->routes_size;
|
|
||||||
|
|
||||||
/* Send the tun fd */
|
/* Send the tun fd */
|
||||||
hdr.msg_control = control_un.control;
|
hdr.msg_control = control_un.control;
|
||||||
hdr.msg_controllen = sizeof(control_un.control);
|
hdr.msg_controllen = sizeof(control_un.control);
|
||||||
@@ -113,7 +205,7 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc,
|
|||||||
cmptr->cmsg_len = CMSG_LEN(sizeof(int));
|
cmptr->cmsg_len = CMSG_LEN(sizeof(int));
|
||||||
cmptr->cmsg_level = SOL_SOCKET;
|
cmptr->cmsg_level = SOL_SOCKET;
|
||||||
cmptr->cmsg_type = SCM_RIGHTS;
|
cmptr->cmsg_type = SCM_RIGHTS;
|
||||||
memcpy(CMSG_DATA(cmptr), &proc->lease->fd, sizeof(int));
|
memcpy(CMSG_DATA(cmptr), &proc->tun_lease.fd, sizeof(int));
|
||||||
} else {
|
} else {
|
||||||
cmd[0] = AUTH_REP;
|
cmd[0] = AUTH_REP;
|
||||||
cmd[1] = REP_AUTH_FAILED;
|
cmd[1] = REP_AUTH_FAILED;
|
||||||
@@ -128,55 +220,11 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc,
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (r == REP_AUTH_OK) {
|
if (r == REP_AUTH_OK) {
|
||||||
uint8_t len;
|
ret = serialize_additional_data(s, proc);
|
||||||
|
if (ret < 0)
|
||||||
if (cfg->ipv4_dns) {
|
return ret;
|
||||||
len = strlen(cfg->ipv4_dns);
|
|
||||||
mslog(s, proc, LOG_INFO, "sending DNS '%s' with size %d", cfg->ipv4_dns, len);
|
|
||||||
ret = force_write(proc->fd, &len, 1);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = force_write(proc->fd, cfg->ipv4_dns, len);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
} else {
|
|
||||||
len = 0;
|
|
||||||
ret = force_write(proc->fd, &len, 1);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cfg->ipv6_dns) {
|
|
||||||
len = strlen(cfg->ipv6_dns);
|
|
||||||
mslog(s, proc, LOG_INFO, "sending DNS '%s' with size %d", cfg->ipv6_dns, len);
|
|
||||||
ret = force_write(proc->fd, &len, 1);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = force_write(proc->fd, cfg->ipv6_dns, len);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
} else {
|
|
||||||
len = 0;
|
|
||||||
ret = force_write(proc->fd, &len, 1);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i=0;i<cfg->routes_size;i++) {
|
|
||||||
len = strlen(cfg->routes[i]);
|
|
||||||
|
|
||||||
mslog(s, proc, LOG_INFO, "sending route '%s' with size %d", cfg->routes[i], len);
|
|
||||||
ret = force_write(proc->fd, &len, 1);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = force_write(proc->fd, cfg->routes[i], len);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,12 @@ static struct cfg_options available_options[] = {
|
|||||||
{ .name = "route", .type = OPTION_MULTI_LINE },
|
{ .name = "route", .type = OPTION_MULTI_LINE },
|
||||||
{ .name = "ipv4-dns", .type = OPTION_STRING },
|
{ .name = "ipv4-dns", .type = OPTION_STRING },
|
||||||
{ .name = "ipv6-dns", .type = OPTION_STRING },
|
{ .name = "ipv6-dns", .type = OPTION_STRING },
|
||||||
|
{ .name = "ipv4-nbns", .type = OPTION_STRING },
|
||||||
|
{ .name = "ipv6-nbns", .type = OPTION_STRING },
|
||||||
|
{ .name = "ipv4-network", .type = OPTION_STRING },
|
||||||
|
{ .name = "ipv6-network", .type = OPTION_STRING },
|
||||||
|
{ .name = "ipv4-netmask", .type = OPTION_STRING },
|
||||||
|
{ .name = "ipv6-netmask", .type = OPTION_STRING },
|
||||||
};
|
};
|
||||||
|
|
||||||
#define READ_RAW_MULTI_LINE(name, s_name, num) \
|
#define READ_RAW_MULTI_LINE(name, s_name, num) \
|
||||||
@@ -114,6 +120,12 @@ const tOptionValue* val, *prev;
|
|||||||
|
|
||||||
READ_RAW_STRING("ipv4-dns", config->ipv4_dns);
|
READ_RAW_STRING("ipv4-dns", config->ipv4_dns);
|
||||||
READ_RAW_STRING("ipv6-dns", config->ipv6_dns);
|
READ_RAW_STRING("ipv6-dns", config->ipv6_dns);
|
||||||
|
READ_RAW_STRING("ipv4-nbns", config->ipv4_nbns);
|
||||||
|
READ_RAW_STRING("ipv6-nbns", config->ipv6_nbns);
|
||||||
|
READ_RAW_STRING("ipv4-network", config->ipv4_network);
|
||||||
|
READ_RAW_STRING("ipv6-network", config->ipv6_network);
|
||||||
|
READ_RAW_STRING("ipv4-netmask", config->ipv4_netmask);
|
||||||
|
READ_RAW_STRING("ipv6-netmask", config->ipv6_netmask);
|
||||||
|
|
||||||
optionUnloadNested(pov);
|
optionUnloadNested(pov);
|
||||||
|
|
||||||
|
|||||||
255
src/main-misc.c
255
src/main-misc.c
@@ -53,10 +53,10 @@ int fd, ret, e;
|
|||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
const char* name;
|
const char* name;
|
||||||
|
|
||||||
if (proc->lease == NULL)
|
if (proc->tun_lease.name[0] == 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
name = proc->lease->name;
|
name = proc->tun_lease.name;
|
||||||
|
|
||||||
mslog(s, proc, LOG_DEBUG, "setting %s MTU to %u", name, mtu);
|
mslog(s, proc, LOG_DEBUG, "setting %s MTU to %u", name, mtu);
|
||||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
@@ -112,119 +112,12 @@ int send_udp_fd(main_server_st* s, struct proc_st * proc, int fd)
|
|||||||
return(sendmsg(proc->fd, &hdr, 0));
|
return(sendmsg(proc->fd, &hdr, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void del_additional_config(struct group_cfg_st* config)
|
|
||||||
{
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
for(i=0;i<config->routes_size;i++) {
|
|
||||||
free(config->routes[i]);
|
|
||||||
}
|
|
||||||
free(config->routes);
|
|
||||||
free(config->ipv4_dns);
|
|
||||||
free(config->ipv6_dns);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int read_additional_config(main_server_st* s, struct proc_st* proc,
|
|
||||||
struct group_cfg_st *config)
|
|
||||||
{
|
|
||||||
struct group_cfg_st u_cfg;
|
|
||||||
struct group_cfg_st g_cfg;
|
|
||||||
char file[_POSIX_PATH_MAX];
|
|
||||||
int ret;
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
memset(config, 0, sizeof(*config));
|
|
||||||
|
|
||||||
if (s->config->per_user_dir != NULL) {
|
|
||||||
snprintf(file, sizeof(file), "%s/%s", s->config->per_user_dir, proc->username);
|
|
||||||
|
|
||||||
if (access(file, R_OK) == 0) {
|
|
||||||
mslog(s, proc, LOG_INFO, "Loading user configuration '%s'", file);
|
|
||||||
|
|
||||||
ret = parse_group_cfg_file(s, file, &u_cfg);
|
|
||||||
if (ret < 0)
|
|
||||||
return ERR_READ_CONFIG;
|
|
||||||
|
|
||||||
if (u_cfg.routes_size > 0) {
|
|
||||||
config->routes = u_cfg.routes;
|
|
||||||
config->routes_size = u_cfg.routes_size;
|
|
||||||
|
|
||||||
u_cfg.routes = NULL;
|
|
||||||
u_cfg.routes_size = 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
config->ipv4_dns = u_cfg.ipv4_dns;
|
|
||||||
u_cfg.ipv4_dns = NULL;
|
|
||||||
|
|
||||||
config->ipv6_dns = u_cfg.ipv6_dns;
|
|
||||||
u_cfg.ipv6_dns = NULL;
|
|
||||||
del_additional_config(&u_cfg);
|
|
||||||
|
|
||||||
|
|
||||||
} else
|
|
||||||
mslog(s, proc, LOG_INFO, "No user configuration for '%s'", proc->username);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s->config->per_group_dir != NULL) {
|
|
||||||
snprintf(file, sizeof(file), "%s/%s", s->config->per_group_dir, proc->groupname);
|
|
||||||
|
|
||||||
if (access(file, R_OK) == 0) {
|
|
||||||
mslog(s, proc, LOG_INFO, "Loading group configuration '%s'", file);
|
|
||||||
|
|
||||||
ret = parse_group_cfg_file(s, file, &g_cfg);
|
|
||||||
if (ret < 0)
|
|
||||||
return ERR_READ_CONFIG;
|
|
||||||
|
|
||||||
if (g_cfg.routes_size > 0) {
|
|
||||||
config->routes = realloc(config->routes, (config->routes_size+g_cfg.routes_size) * sizeof(config->routes[0]));
|
|
||||||
if (config->routes == NULL)
|
|
||||||
return ERR_MEM;
|
|
||||||
|
|
||||||
for (i=0;i<g_cfg.routes_size;i++) {
|
|
||||||
config->routes[config->routes_size] = g_cfg.routes[i];
|
|
||||||
g_cfg.routes[i] = NULL;
|
|
||||||
config->routes_size++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config->ipv4_dns == NULL) {
|
|
||||||
config->ipv4_dns = g_cfg.ipv4_dns;
|
|
||||||
g_cfg.ipv4_dns = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config->ipv6_dns == NULL) {
|
|
||||||
config->ipv6_dns = g_cfg.ipv6_dns;
|
|
||||||
g_cfg.ipv6_dns = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
del_additional_config(&g_cfg);
|
|
||||||
|
|
||||||
} else
|
|
||||||
mslog(s, proc, LOG_INFO, "No group configuration for '%s'", proc->groupname);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int handle_script_exit(main_server_st *s, struct proc_st* proc, int code)
|
int handle_script_exit(main_server_st *s, struct proc_st* proc, int code)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (code == 0) {
|
if (code == 0) {
|
||||||
struct group_cfg_st cfg;
|
ret = send_auth_reply(s, proc, REP_AUTH_OK);
|
||||||
|
|
||||||
ret = read_additional_config(s, proc, &cfg);
|
|
||||||
if (ret < 0) {
|
|
||||||
mslog(s, proc, LOG_ERR, "error reading additional routes");
|
|
||||||
ret = ERR_READ_ROUTES;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = send_auth_reply(s, proc, REP_AUTH_OK, &cfg);
|
|
||||||
|
|
||||||
del_additional_config(&cfg);
|
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
mslog(s, proc, LOG_ERR, "could not send reply auth cmd.");
|
mslog(s, proc, LOG_ERR, "could not send reply auth cmd.");
|
||||||
ret = ERR_BAD_COMMAND;
|
ret = ERR_BAD_COMMAND;
|
||||||
@@ -232,7 +125,7 @@ int ret;
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mslog(s, proc, 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);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
mslog(s, proc, LOG_ERR, "could not send reply auth cmd.");
|
mslog(s, proc, LOG_ERR, "could not send reply auth cmd.");
|
||||||
ret = ERR_BAD_COMMAND;
|
ret = ERR_BAD_COMMAND;
|
||||||
@@ -245,15 +138,141 @@ fail:
|
|||||||
/* we close the lease tun fd both on success and failure.
|
/* we close the lease tun fd both on success and failure.
|
||||||
* The parent doesn't need to keep the tunfd.
|
* The parent doesn't need to keep the tunfd.
|
||||||
*/
|
*/
|
||||||
if (proc->lease) {
|
if (proc->tun_lease.name[0] != 0) {
|
||||||
if (proc->lease->fd >= 0)
|
if (proc->tun_lease.fd >= 0)
|
||||||
close(proc->lease->fd);
|
close(proc->tun_lease.fd);
|
||||||
proc->lease->fd = -1;
|
proc->tun_lease.fd = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void del_additional_config(struct group_cfg_st* config)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
for(i=0;i<config->routes_size;i++) {
|
||||||
|
free(config->routes[i]);
|
||||||
|
}
|
||||||
|
free(config->routes);
|
||||||
|
free(config->ipv4_dns);
|
||||||
|
free(config->ipv6_dns);
|
||||||
|
free(config->ipv4_nbns);
|
||||||
|
free(config->ipv6_nbns);
|
||||||
|
free(config->ipv4_network);
|
||||||
|
free(config->ipv6_network);
|
||||||
|
free(config->ipv4_netmask);
|
||||||
|
free(config->ipv6_netmask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_config_file(main_server_st* s, struct proc_st* proc, const char* file, const char* type)
|
||||||
|
{
|
||||||
|
struct group_cfg_st cfg;
|
||||||
|
int ret;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
if (access(file, R_OK) == 0) {
|
||||||
|
mslog(s, proc, LOG_DEBUG, "Loading %s configuration '%s'", type, file);
|
||||||
|
|
||||||
|
ret = parse_group_cfg_file(s, file, &cfg);
|
||||||
|
if (ret < 0)
|
||||||
|
return ERR_READ_CONFIG;
|
||||||
|
|
||||||
|
if (cfg.routes_size > 0) {
|
||||||
|
if (proc->config.routes == NULL) {
|
||||||
|
proc->config.routes = cfg.routes;
|
||||||
|
proc->config.routes_size = cfg.routes_size;
|
||||||
|
|
||||||
|
cfg.routes = NULL;
|
||||||
|
cfg.routes_size = 0;
|
||||||
|
} else {
|
||||||
|
proc->config.routes = realloc(proc->config.routes, (proc->config.routes_size + cfg.routes_size) * sizeof(proc->config.routes[0]));
|
||||||
|
if (proc->config.routes == NULL)
|
||||||
|
return ERR_MEM;
|
||||||
|
|
||||||
|
for (i=0;i<cfg.routes_size;i++) {
|
||||||
|
proc->config.routes[proc->config.routes_size] = cfg.routes[i];
|
||||||
|
cfg.routes[i] = NULL;
|
||||||
|
proc->config.routes_size++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proc->config.ipv4_dns == NULL) {
|
||||||
|
proc->config.ipv4_dns = cfg.ipv4_dns;
|
||||||
|
cfg.ipv4_dns = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proc->config.ipv6_dns == NULL) {
|
||||||
|
proc->config.ipv6_dns = cfg.ipv6_dns;
|
||||||
|
cfg.ipv6_dns = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proc->config.ipv4_nbns == NULL) {
|
||||||
|
proc->config.ipv4_nbns = cfg.ipv4_nbns;
|
||||||
|
cfg.ipv4_nbns = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proc->config.ipv6_nbns == NULL) {
|
||||||
|
proc->config.ipv6_nbns = cfg.ipv6_nbns;
|
||||||
|
cfg.ipv6_nbns = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proc->config.ipv4_network == NULL) {
|
||||||
|
proc->config.ipv4_network = cfg.ipv4_network;
|
||||||
|
cfg.ipv4_network = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proc->config.ipv6_network == NULL) {
|
||||||
|
proc->config.ipv6_network = cfg.ipv6_network;
|
||||||
|
cfg.ipv6_network = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proc->config.ipv4_netmask == NULL) {
|
||||||
|
proc->config.ipv4_netmask = cfg.ipv4_netmask;
|
||||||
|
cfg.ipv4_netmask = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proc->config.ipv6_netmask == NULL) {
|
||||||
|
proc->config.ipv6_netmask = cfg.ipv6_netmask;
|
||||||
|
cfg.ipv6_netmask = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
del_additional_config(&cfg);
|
||||||
|
|
||||||
|
} else
|
||||||
|
mslog(s, proc, LOG_DEBUG, "No %s configuration for '%s'", type, proc->username);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int read_additional_config(struct main_server_st* s, struct proc_st* proc)
|
||||||
|
{
|
||||||
|
char file[_POSIX_PATH_MAX];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
memset(&proc->config, 0, sizeof(proc->config));
|
||||||
|
|
||||||
|
if (s->config->per_user_dir != NULL) {
|
||||||
|
snprintf(file, sizeof(file), "%s/%s", s->config->per_user_dir, proc->username);
|
||||||
|
|
||||||
|
ret = read_config_file(s, proc, file, "user");
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->config->per_group_dir != NULL) {
|
||||||
|
snprintf(file, sizeof(file), "%s/%s", s->config->per_group_dir, proc->groupname);
|
||||||
|
|
||||||
|
ret = read_config_file(s, proc, file, "group");
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int accept_user(main_server_st *s, struct proc_st* proc, unsigned cmd)
|
static int accept_user(main_server_st *s, struct proc_st* proc, unsigned cmd)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@@ -269,6 +288,12 @@ const char* group;
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = read_additional_config(s, proc);
|
||||||
|
if (ret < 0) {
|
||||||
|
mslog(s, proc, LOG_ERR, "error reading additional configuration");
|
||||||
|
return ERR_READ_CONFIG;
|
||||||
|
}
|
||||||
|
|
||||||
ret = open_tun(s, proc);
|
ret = open_tun(s, proc);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
@@ -32,12 +32,12 @@
|
|||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <gnutls/gnutls.h>
|
#include <gnutls/gnutls.h>
|
||||||
#include <gnutls/crypto.h>
|
#include <gnutls/crypto.h>
|
||||||
#include <tlslib.h>
|
|
||||||
#include "ipc.h"
|
#include "ipc.h"
|
||||||
#include <ccan/hash/hash.h>
|
#include <ccan/hash/hash.h>
|
||||||
|
|
||||||
#include <vpn.h>
|
#include <vpn.h>
|
||||||
#include <main.h>
|
#include <main.h>
|
||||||
|
#include <common.h>
|
||||||
#include <tlslib.h>
|
#include <tlslib.h>
|
||||||
|
|
||||||
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,
|
||||||
@@ -69,7 +69,7 @@ tls_cache_st* cache;
|
|||||||
struct htable_iter iter;
|
struct htable_iter iter;
|
||||||
size_t key;
|
size_t key;
|
||||||
|
|
||||||
key = hash_stable_8(req->session_id, req->session_id_size, 0);
|
key = hash_any(req->session_id, req->session_id_size, 0);
|
||||||
|
|
||||||
cache = htable_firstval(&s->tls_db->ht, &iter, key);
|
cache = htable_firstval(&s->tls_db->ht, &iter, key);
|
||||||
while(cache != NULL) {
|
while(cache != NULL) {
|
||||||
@@ -91,15 +91,6 @@ size_t key;
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ip_cmp(const struct sockaddr_storage *s1, const struct sockaddr_storage *s2, size_t n)
|
|
||||||
{
|
|
||||||
if (((struct sockaddr*)s1)->sa_family == AF_INET) {
|
|
||||||
return memcmp(SA_IN_P(s1), SA_IN_P(s2), sizeof(struct in_addr));
|
|
||||||
} else { /* inet6 */
|
|
||||||
return memcmp(SA_IN6_P(s1), SA_IN6_P(s2), sizeof(struct in6_addr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int handle_resume_fetch_req(main_server_st* s, struct proc_st * proc,
|
int handle_resume_fetch_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,
|
||||||
struct cmd_resume_fetch_reply_st * rep)
|
struct cmd_resume_fetch_reply_st * rep)
|
||||||
@@ -110,7 +101,7 @@ size_t key;
|
|||||||
|
|
||||||
rep->reply = REP_RESUME_FAILED;
|
rep->reply = REP_RESUME_FAILED;
|
||||||
|
|
||||||
key = hash_stable_8(req->session_id, req->session_id_size, 0);
|
key = hash_any(req->session_id, req->session_id_size, 0);
|
||||||
|
|
||||||
cache = htable_firstval(&s->tls_db->ht, &iter, key);
|
cache = htable_firstval(&s->tls_db->ht, &iter, key);
|
||||||
while(cache != NULL) {
|
while(cache != NULL) {
|
||||||
@@ -155,7 +146,7 @@ unsigned int max;
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
key = hash_stable_8(req->session_id, req->session_id_size, 0);
|
key = hash_any(req->session_id, req->session_id_size, 0);
|
||||||
|
|
||||||
cache = malloc(sizeof(*cache));
|
cache = malloc(sizeof(*cache));
|
||||||
if (cache == NULL)
|
if (cache == NULL)
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
#include <cookies.h>
|
#include <cookies.h>
|
||||||
#include <tun.h>
|
#include <tun.h>
|
||||||
#include <main.h>
|
#include <main.h>
|
||||||
|
#include <ip-lease.h>
|
||||||
#include <script-list.h>
|
#include <script-list.h>
|
||||||
#include <ccan/list/list.h>
|
#include <ccan/list/list.h>
|
||||||
|
|
||||||
@@ -66,32 +67,32 @@ const char* script;
|
|||||||
char local[64];
|
char local[64];
|
||||||
char remote[64];
|
char remote[64];
|
||||||
|
|
||||||
if (proc->lease == NULL)
|
if (proc->ipv4 == NULL && proc->ipv6 == NULL)
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
||||||
if (getnameinfo((void*)&proc->remote_addr, proc->remote_addr_len, real, sizeof(real), NULL, 0, NI_NUMERICHOST) != 0)
|
if (getnameinfo((void*)&proc->remote_addr, proc->remote_addr_len, real, sizeof(real), NULL, 0, NI_NUMERICHOST) != 0)
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
||||||
if (proc->lease->lip4_len > 0) {
|
if (proc->ipv4 && proc->ipv4->lip_len > 0) {
|
||||||
if (getnameinfo((void*)&proc->lease->lip4, proc->lease->lip4_len, local, sizeof(local), NULL, 0, NI_NUMERICHOST) != 0)
|
if (getnameinfo((void*)&proc->ipv4->lip, proc->ipv4->lip_len, local, sizeof(local), NULL, 0, NI_NUMERICHOST) != 0)
|
||||||
exit(1);
|
exit(1);
|
||||||
} else {
|
} else {
|
||||||
if (getnameinfo((void*)&proc->lease->lip6, proc->lease->lip6_len, local, sizeof(local), NULL, 0, NI_NUMERICHOST) != 0)
|
if (getnameinfo((void*)&proc->ipv6->lip, proc->ipv6->lip_len, local, sizeof(local), NULL, 0, NI_NUMERICHOST) != 0)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proc->lease->rip4_len > 0) {
|
if (proc->ipv4 && proc->ipv4->rip_len > 0) {
|
||||||
if (getnameinfo((void*)&proc->lease->rip4, proc->lease->rip4_len, remote, sizeof(remote), NULL, 0, NI_NUMERICHOST) != 0)
|
if (getnameinfo((void*)&proc->ipv4->rip, proc->ipv4->rip_len, remote, sizeof(remote), NULL, 0, NI_NUMERICHOST) != 0)
|
||||||
exit(1);
|
exit(1);
|
||||||
} else {
|
} else {
|
||||||
if (getnameinfo((void*)&proc->lease->rip6, proc->lease->rip6_len, remote, sizeof(remote), NULL, 0, NI_NUMERICHOST) != 0)
|
if (getnameinfo((void*)&proc->ipv6->rip, proc->ipv6->rip_len, remote, sizeof(remote), NULL, 0, NI_NUMERICHOST) != 0)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
setenv("USERNAME", proc->username, 1);
|
setenv("USERNAME", proc->username, 1);
|
||||||
setenv("GROUPNAME", proc->groupname, 1);
|
setenv("GROUPNAME", proc->groupname, 1);
|
||||||
setenv("HOSTNAME", proc->hostname, 1);
|
setenv("HOSTNAME", proc->hostname, 1);
|
||||||
setenv("DEVICE", proc->lease->name, 1);
|
setenv("DEVICE", proc->tun_lease.name, 1);
|
||||||
setenv("IP_REAL", real, 1);
|
setenv("IP_REAL", real, 1);
|
||||||
setenv("IP_LOCAL", local, 1);
|
setenv("IP_LOCAL", local, 1);
|
||||||
setenv("IP_REMOTE", remote, 1);
|
setenv("IP_REMOTE", remote, 1);
|
||||||
@@ -134,7 +135,7 @@ add_utmp_entry(main_server_st *s, struct proc_st* proc)
|
|||||||
memset(&entry, 0, sizeof(entry));
|
memset(&entry, 0, sizeof(entry));
|
||||||
entry.ut_type = USER_PROCESS;
|
entry.ut_type = USER_PROCESS;
|
||||||
entry.ut_pid = proc->pid;
|
entry.ut_pid = proc->pid;
|
||||||
snprintf(entry.ut_line, sizeof(entry.ut_line), "%s", proc->lease->name);
|
snprintf(entry.ut_line, sizeof(entry.ut_line), "%s", proc->tun_lease.name);
|
||||||
snprintf(entry.ut_user, sizeof(entry.ut_user), "%s", proc->username);
|
snprintf(entry.ut_user, sizeof(entry.ut_user), "%s", proc->username);
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
if (proc->remote_addr_len == sizeof(struct sockaddr_in))
|
if (proc->remote_addr_len == sizeof(struct sockaddr_in))
|
||||||
@@ -171,8 +172,8 @@ static void remove_utmp_entry(main_server_st *s, struct proc_st* proc)
|
|||||||
|
|
||||||
memset(&entry, 0, sizeof(entry));
|
memset(&entry, 0, sizeof(entry));
|
||||||
entry.ut_type = DEAD_PROCESS;
|
entry.ut_type = DEAD_PROCESS;
|
||||||
if (proc->lease && proc->lease->name)
|
if (proc->tun_lease.name[0] != 0)
|
||||||
snprintf(entry.ut_line, sizeof(entry.ut_line), "%s", proc->lease->name);
|
snprintf(entry.ut_line, sizeof(entry.ut_line), "%s", proc->tun_lease.name);
|
||||||
entry.ut_pid = proc->pid;
|
entry.ut_pid = proc->pid;
|
||||||
|
|
||||||
setutxent();
|
setutxent();
|
||||||
|
|||||||
17
src/main.c
17
src/main.c
@@ -49,6 +49,7 @@
|
|||||||
#include <worker.h>
|
#include <worker.h>
|
||||||
#include <cookies.h>
|
#include <cookies.h>
|
||||||
#include <tun.h>
|
#include <tun.h>
|
||||||
|
#include <ip-lease.h>
|
||||||
#include <ccan/list/list.h>
|
#include <ccan/list/list.h>
|
||||||
|
|
||||||
int syslog_open = 0;
|
int syslog_open = 0;
|
||||||
@@ -302,11 +303,14 @@ static void remove_proc(main_server_st* s, struct proc_st *proc, unsigned k)
|
|||||||
proc->fd = -1;
|
proc->fd = -1;
|
||||||
proc->pid = -1;
|
proc->pid = -1;
|
||||||
|
|
||||||
|
del_additional_config(&proc->config);
|
||||||
|
|
||||||
if (proc->auth_ctx != NULL)
|
if (proc->auth_ctx != NULL)
|
||||||
proc_auth_deinit(s, proc);
|
proc_auth_deinit(s, proc);
|
||||||
|
|
||||||
if (proc->lease)
|
if (proc->ipv4 || proc->ipv6)
|
||||||
proc->lease->in_use = 0;
|
remove_ip_leases(s, proc);
|
||||||
|
|
||||||
list_del(&proc->list);
|
list_del(&proc->list);
|
||||||
free(proc);
|
free(proc);
|
||||||
s->active_clients--;
|
s->active_clients--;
|
||||||
@@ -459,6 +463,9 @@ void clear_lists(main_server_st *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
tls_cache_deinit(s->tls_db);
|
tls_cache_deinit(s->tls_db);
|
||||||
|
|
||||||
|
ip_lease_deinit(&s->ip_leases);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kill_children(main_server_st* s)
|
static void kill_children(main_server_st* s)
|
||||||
@@ -628,7 +635,6 @@ int main(int argc, char** argv)
|
|||||||
int fd, pid, e;
|
int fd, pid, e;
|
||||||
struct listener_st *ltmp;
|
struct listener_st *ltmp;
|
||||||
struct proc_st *ctmp, *cpos;
|
struct proc_st *ctmp, *cpos;
|
||||||
struct tun_st tun;
|
|
||||||
fd_set rd;
|
fd_set rd;
|
||||||
int val, n = 0, ret, flags;
|
int val, n = 0, ret, flags;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
@@ -643,9 +649,9 @@ int main(int argc, char** argv)
|
|||||||
list_head_init(&s.clist.head);
|
list_head_init(&s.clist.head);
|
||||||
list_head_init(&s.ban_list.head);
|
list_head_init(&s.ban_list.head);
|
||||||
list_head_init(&s.script_list.head);
|
list_head_init(&s.script_list.head);
|
||||||
tun_st_init(&tun);
|
|
||||||
tls_cache_init(&s.tls_db);
|
tls_cache_init(&s.tls_db);
|
||||||
|
ip_lease_init(&s.ip_leases);
|
||||||
|
|
||||||
ocsignal(SIGINT, handle_term);
|
ocsignal(SIGINT, handle_term);
|
||||||
ocsignal(SIGTERM, handle_term);
|
ocsignal(SIGTERM, handle_term);
|
||||||
ocsignal(SIGPIPE, SIG_IGN);
|
ocsignal(SIGPIPE, SIG_IGN);
|
||||||
@@ -677,7 +683,6 @@ int main(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.config = &config;
|
s.config = &config;
|
||||||
s.tun = &tun;
|
|
||||||
|
|
||||||
main_auth_init(&s);
|
main_auth_init(&s);
|
||||||
|
|
||||||
|
|||||||
19
src/main.h
19
src/main.h
@@ -55,7 +55,9 @@ struct proc_st {
|
|||||||
unsigned udp_fd_received; /* if the corresponding process has received a UDP fd */
|
unsigned udp_fd_received; /* if the corresponding process has received a UDP fd */
|
||||||
|
|
||||||
/* the tun lease this process has */
|
/* the tun lease this process has */
|
||||||
struct lease_st* lease;
|
struct tun_lease_st tun_lease;
|
||||||
|
struct ip_lease_st *ipv4;
|
||||||
|
struct ip_lease_st *ipv6;
|
||||||
|
|
||||||
struct sockaddr_storage remote_addr; /* peer address */
|
struct sockaddr_storage remote_addr; /* peer address */
|
||||||
socklen_t remote_addr_len;
|
socklen_t remote_addr_len;
|
||||||
@@ -75,6 +77,13 @@ struct proc_st {
|
|||||||
void * auth_ctx; /* the context of authentication */
|
void * auth_ctx; /* the context of authentication */
|
||||||
unsigned auth_status; /* PS_AUTH_ */
|
unsigned auth_status; /* PS_AUTH_ */
|
||||||
unsigned auth_reqs; /* the number of requests received */
|
unsigned auth_reqs; /* the number of requests received */
|
||||||
|
|
||||||
|
struct group_cfg_st config; /* custom user/group config */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_lease_db_st {
|
||||||
|
struct htable ht;
|
||||||
|
unsigned entries;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct proc_list_st {
|
struct proc_list_st {
|
||||||
@@ -99,7 +108,9 @@ struct ban_list_st {
|
|||||||
|
|
||||||
typedef struct main_server_st {
|
typedef struct main_server_st {
|
||||||
struct cfg_st *config;
|
struct cfg_st *config;
|
||||||
struct tun_st *tun;
|
|
||||||
|
struct ip_lease_db_st ip_leases;
|
||||||
|
|
||||||
hash_db_st *tls_db;
|
hash_db_st *tls_db;
|
||||||
|
|
||||||
uint8_t cookie_key[16];
|
uint8_t cookie_key[16];
|
||||||
@@ -157,7 +168,7 @@ int set_tun_mtu(main_server_st* s, struct proc_st * proc, unsigned mtu);
|
|||||||
int send_auth_reply_msg(main_server_st* s, struct proc_st* proc);
|
int send_auth_reply_msg(main_server_st* s, struct proc_st* proc);
|
||||||
|
|
||||||
int send_auth_reply(main_server_st* s, struct proc_st* proc,
|
int send_auth_reply(main_server_st* s, struct proc_st* proc,
|
||||||
cmd_auth_reply_t r, struct group_cfg_st*);
|
cmd_auth_reply_t r);
|
||||||
|
|
||||||
int handle_auth_cookie_req(main_server_st* s, struct proc_st* proc,
|
int handle_auth_cookie_req(main_server_st* s, struct proc_st* proc,
|
||||||
const struct cmd_auth_cookie_req_st * req);
|
const struct cmd_auth_cookie_req_st * req);
|
||||||
@@ -179,4 +190,6 @@ void run_sec_mod(main_server_st * s);
|
|||||||
|
|
||||||
int parse_group_cfg_file(main_server_st* s, const char* file, struct group_cfg_st *config);
|
int parse_group_cfg_file(main_server_st* s, const char* file, struct group_cfg_st *config);
|
||||||
|
|
||||||
|
void del_additional_config(struct group_cfg_st* config);
|
||||||
|
|
||||||
#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 October 28, 2013 at 11:41:39 AM by AutoGen 5.17
|
* It has been AutoGen-ed October 28, 2013 at 07:03:52 PM by AutoGen 5.17
|
||||||
* From the definitions ocserv-args.def
|
* From the definitions ocserv-args.def
|
||||||
* and the template file options
|
* and the template file options
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -263,7 +263,8 @@ route = 192.168.5.0/255.255.255.0
|
|||||||
# Configuration files that will be applied per user connection or
|
# Configuration files that will be applied per user connection or
|
||||||
# per group. Each file name on these directories must match the username
|
# per group. Each file name on these directories must match the username
|
||||||
# or the groupname.
|
# or the groupname.
|
||||||
# The options allow in such configuration files are ipv?-dns, and route.
|
# The options allow in such configuration files are ipv?-dns, ipv?-nbns,
|
||||||
|
# ipv?-network, ipv?-netmask and route.
|
||||||
#config-per-user = /etc/ocserv/config-per-user/
|
#config-per-user = /etc/ocserv/config-per-user/
|
||||||
#config-per-group = /etc/ocserv/config-per-group/
|
#config-per-group = /etc/ocserv/config-per-group/
|
||||||
|
|
||||||
|
|||||||
@@ -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 October 28, 2013 at 11:41:39 AM by AutoGen 5.17
|
* It has been AutoGen-ed October 28, 2013 at 07:03:52 PM by AutoGen 5.17
|
||||||
* From the definitions ocserv-args.def
|
* From the definitions ocserv-args.def
|
||||||
* and the template file options
|
* and the template file options
|
||||||
*
|
*
|
||||||
|
|||||||
290
src/tun.c
290
src/tun.c
@@ -30,7 +30,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <cloexec.h>
|
#include <cloexec.h>
|
||||||
#include <icmp-ping.h>
|
#include <ip-lease.h>
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
# include <linux/if_tun.h>
|
# include <linux/if_tun.h>
|
||||||
@@ -45,174 +45,7 @@
|
|||||||
#include <main.h>
|
#include <main.h>
|
||||||
#include <ccan/list/list.h>
|
#include <ccan/list/list.h>
|
||||||
|
|
||||||
/* INCREMENT taken from nettle's macros */
|
static int set_network_info( main_server_st* s, struct proc_st* proc)
|
||||||
/* Requires that size > 0 */
|
|
||||||
#define INCREMENT(size, ctr) \
|
|
||||||
do { \
|
|
||||||
unsigned increment_i = (size) - 1; \
|
|
||||||
if (++(ctr)[increment_i] == 0) \
|
|
||||||
while (increment_i > 0 \
|
|
||||||
&& ++(ctr)[--increment_i] == 0 ) \
|
|
||||||
; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
static void bignum_add (uint8_t * num, unsigned size, unsigned step)
|
|
||||||
{
|
|
||||||
register int i;
|
|
||||||
register unsigned tmp, y;
|
|
||||||
|
|
||||||
for (i = size-1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
tmp = num[i];
|
|
||||||
|
|
||||||
num[i] += step;
|
|
||||||
if (num[i] < tmp)
|
|
||||||
y = 1;
|
|
||||||
else
|
|
||||||
y = 0;
|
|
||||||
|
|
||||||
if (y == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_avail_network_addresses(main_server_st* s, const struct lease_st *last4,
|
|
||||||
const struct lease_st *last6, struct lease_st* lease)
|
|
||||||
{
|
|
||||||
struct sockaddr_storage tmp, mask, network;
|
|
||||||
unsigned i;
|
|
||||||
int ret, step;
|
|
||||||
|
|
||||||
lease->rip4_len = 0;
|
|
||||||
lease->lip4_len = 0;
|
|
||||||
lease->rip6_len = 0;
|
|
||||||
lease->lip6_len = 0;
|
|
||||||
|
|
||||||
memset(&tmp, 0, sizeof(tmp));
|
|
||||||
|
|
||||||
if (s->config->network.ipv4 && s->config->network.ipv4_netmask) {
|
|
||||||
ret =
|
|
||||||
inet_pton(AF_INET, s->config->network.ipv4, SA_IN_P(&network));
|
|
||||||
|
|
||||||
if (ret != 1) {
|
|
||||||
mslog(s, NULL, LOG_ERR, "Error reading IP: %s\n", s->config->network.ipv4);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret =
|
|
||||||
inet_pton(AF_INET, s->config->network.ipv4_netmask, SA_IN_P(&mask));
|
|
||||||
|
|
||||||
if (ret != 1) {
|
|
||||||
mslog(s, NULL, LOG_ERR, "Error reading mask: %s\n", s->config->network.ipv4_netmask);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* mask the network (just in case it is wrong) */
|
|
||||||
for (i=0;i<sizeof(struct in_addr);i++)
|
|
||||||
SA_IN_U8_P(&network)[i] &= (SA_IN_U8_P(&mask)[i]);
|
|
||||||
((struct sockaddr_in*)&network)->sin_family = AF_INET;
|
|
||||||
|
|
||||||
if (last4 != NULL) {
|
|
||||||
memcpy(&tmp, &last4->rip4, last4->rip4_len);
|
|
||||||
} else {
|
|
||||||
memcpy(&tmp, &network, sizeof(tmp));
|
|
||||||
((struct sockaddr_in*)&tmp)->sin_family = AF_INET;
|
|
||||||
}
|
|
||||||
|
|
||||||
lease->lip4_len = sizeof(struct sockaddr_in);
|
|
||||||
memcpy(&lease->lip4, &tmp, sizeof(struct sockaddr_in));
|
|
||||||
|
|
||||||
step = 1;
|
|
||||||
do {
|
|
||||||
bignum_add(SA_IN_U8_P(&lease->lip4), sizeof(struct in_addr), step);
|
|
||||||
if (SA_IN_U8_P(&lease->lip4)[3] == 255) /* broadcast */
|
|
||||||
bignum_add(SA_IN_U8_P(&lease->lip4), sizeof(struct in_addr), step);
|
|
||||||
|
|
||||||
lease->rip4_len = sizeof(struct sockaddr_in);
|
|
||||||
memcpy(&lease->rip4, &lease->lip4, sizeof(struct sockaddr_in));
|
|
||||||
bignum_add(SA_IN_U8_P(&lease->rip4), sizeof(struct in_addr), step);
|
|
||||||
|
|
||||||
/* mask the last IP with the netmask */
|
|
||||||
memcpy(&tmp, &lease->rip4, lease->rip4_len);
|
|
||||||
for (i=0;i<sizeof(struct in_addr);i++)
|
|
||||||
SA_IN_U8_P(&tmp)[i] &= (SA_IN_U8_P(&mask)[i]);
|
|
||||||
|
|
||||||
/* the result should match the network */
|
|
||||||
if (memcmp(SA_IN_U8_P(&network), SA_IN_U8_P(&tmp), sizeof(struct in_addr)) != 0) {
|
|
||||||
mslog(s, NULL, LOG_ERR, "Reached limit of maximum (v4) IPs.\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} while((step=icmp_ping4(s, (void*)&lease->lip4, (void*)&lease->rip4)) != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s->config->network.ipv6 && s->config->network.ipv6_netmask) {
|
|
||||||
ret =
|
|
||||||
inet_pton(AF_INET6, s->config->network.ipv6, SA_IN6_P(&network));
|
|
||||||
|
|
||||||
if (ret != 1) {
|
|
||||||
mslog(s, NULL, LOG_ERR, "Error reading IP: %s\n", s->config->network.ipv6);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret =
|
|
||||||
inet_pton(AF_INET6, s->config->network.ipv6_netmask, SA_IN6_P(&mask));
|
|
||||||
|
|
||||||
if (ret != 1) {
|
|
||||||
mslog(s, NULL, LOG_ERR, "Error reading mask: %s\n", s->config->network.ipv6_netmask);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* mask the network */
|
|
||||||
for (i=0;i<sizeof(struct in6_addr);i++)
|
|
||||||
SA_IN6_U8_P(&network)[i] &= (SA_IN6_U8_P(&mask)[i]);
|
|
||||||
((struct sockaddr_in6*)&network)->sin6_family = AF_INET6;
|
|
||||||
|
|
||||||
if (last6 != NULL) {
|
|
||||||
memcpy(&tmp, &last6->rip6, last6->rip6_len);
|
|
||||||
} else {
|
|
||||||
memcpy(&tmp, &network, sizeof(tmp));
|
|
||||||
((struct sockaddr_in6*)&tmp)->sin6_family = AF_INET6;
|
|
||||||
}
|
|
||||||
|
|
||||||
lease->lip6_len = sizeof(struct sockaddr_in6);
|
|
||||||
memcpy(&lease->lip6, &tmp, sizeof(struct sockaddr_in6));
|
|
||||||
|
|
||||||
step = 1;
|
|
||||||
do {
|
|
||||||
bignum_add(SA_IN6_U8_P(&lease->lip6), sizeof(struct in6_addr), step);
|
|
||||||
|
|
||||||
lease->rip6_len = last6->rip6_len;
|
|
||||||
memcpy(&lease->rip6, &lease->lip6, lease->rip6_len);
|
|
||||||
bignum_add(SA_IN6_U8_P(&lease->rip6), sizeof(struct in6_addr), step);
|
|
||||||
|
|
||||||
/* mask the last IP with the netmask */
|
|
||||||
memcpy(&tmp, &lease->rip6, lease->rip6_len);
|
|
||||||
for (i=0;i<sizeof(struct in6_addr);i++)
|
|
||||||
SA_IN6_U8_P(&tmp)[i] &= (SA_IN6_U8_P(&mask)[i]);
|
|
||||||
|
|
||||||
/* the result should match the network */
|
|
||||||
if (memcmp(SA_IN6_U8_P(&network), SA_IN6_U8_P(&tmp), sizeof(struct in6_addr)) != 0) {
|
|
||||||
mslog(s, NULL, LOG_ERR, "Reached limit of maximum (v6) IPs.\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} while((step=icmp_ping6(s, (void*)&lease->lip6, (void*)&lease->rip6)) != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lease->lip6_len == 0 && lease->lip4_len == 0) {
|
|
||||||
mslog(s, NULL, 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( main_server_st* s, const struct lease_st *lease)
|
|
||||||
{
|
{
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
int fd, ret;
|
int fd, ret;
|
||||||
@@ -221,54 +54,54 @@ static int set_network_info( main_server_st* s, const struct lease_st *lease)
|
|||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (lease->lip4_len > 0 && lease->rip4_len > 0) {
|
if (proc->ipv4 && proc->ipv4->lip_len > 0 && proc->ipv4->rip_len > 0) {
|
||||||
memset(&ifr, 0, sizeof(ifr));
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
ifr.ifr_addr.sa_family = AF_INET;
|
ifr.ifr_addr.sa_family = AF_INET;
|
||||||
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", lease->name);
|
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", proc->tun_lease.name);
|
||||||
|
|
||||||
memcpy(&ifr.ifr_addr, &lease->lip4, lease->lip4_len);
|
memcpy(&ifr.ifr_addr, &proc->ipv4->lip, proc->ipv4->lip_len);
|
||||||
|
|
||||||
ret = ioctl(fd, SIOCSIFADDR, &ifr);
|
ret = ioctl(fd, SIOCSIFADDR, &ifr);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
mslog(s, NULL, LOG_ERR, "%s: Error setting IPv4.\n", lease->name);
|
mslog(s, NULL, LOG_ERR, "%s: Error setting IPv4.\n", proc->tun_lease.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&ifr, 0, sizeof(ifr));
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
ifr.ifr_addr.sa_family = AF_INET;
|
ifr.ifr_addr.sa_family = AF_INET;
|
||||||
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", lease->name);
|
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", proc->tun_lease.name);
|
||||||
memcpy(&ifr.ifr_dstaddr, &lease->rip4, lease->rip4_len);
|
memcpy(&ifr.ifr_dstaddr, &proc->ipv4->rip, proc->ipv4->rip_len);
|
||||||
|
|
||||||
ret = ioctl(fd, SIOCSIFDSTADDR, &ifr);
|
ret = ioctl(fd, SIOCSIFDSTADDR, &ifr);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
mslog(s, NULL, LOG_ERR, "%s: Error setting DST IPv4.\n", lease->name);
|
mslog(s, NULL, LOG_ERR, "%s: Error setting DST IPv4.\n", proc->tun_lease.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lease->lip6_len > 0 && lease->rip6_len > 0) {
|
if (proc->ipv6 && proc->ipv6->lip_len > 0 && proc->ipv6->rip_len > 0) {
|
||||||
memset(&ifr, 0, sizeof(ifr));
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
ifr.ifr_addr.sa_family = AF_INET6;
|
ifr.ifr_addr.sa_family = AF_INET6;
|
||||||
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", lease->name);
|
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", proc->tun_lease.name);
|
||||||
|
|
||||||
memcpy(&ifr.ifr_addr, &lease->lip6, lease->lip6_len);
|
memcpy(&ifr.ifr_addr, &proc->ipv6->lip, proc->ipv6->lip_len);
|
||||||
|
|
||||||
ret = ioctl(fd, SIOCSIFADDR, &ifr);
|
ret = ioctl(fd, SIOCSIFADDR, &ifr);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
mslog(s, NULL, LOG_ERR, "%s: Error setting IPv6.\n", lease->name);
|
mslog(s, NULL, LOG_ERR, "%s: Error setting IPv6.\n", proc->tun_lease.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&ifr, 0, sizeof(ifr));
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
ifr.ifr_addr.sa_family = AF_INET6;
|
ifr.ifr_addr.sa_family = AF_INET6;
|
||||||
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", lease->name);
|
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", proc->tun_lease.name);
|
||||||
memcpy(&ifr.ifr_dstaddr, &lease->rip6, lease->rip6_len);
|
memcpy(&ifr.ifr_dstaddr, &proc->ipv6->rip, proc->ipv6->rip_len);
|
||||||
|
|
||||||
ret = ioctl(fd, SIOCSIFDSTADDR, &ifr);
|
ret = ioctl(fd, SIOCSIFDSTADDR, &ifr);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
mslog(s, NULL, LOG_ERR, "%s: Error setting DST IPv6.\n", lease->name);
|
mslog(s, NULL, LOG_ERR, "%s: Error setting DST IPv6.\n", proc->tun_lease.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lease->lip6_len == 0 && lease->lip4_len == 0) {
|
if (proc->ipv6 == 0 && proc->ipv4 == 0) {
|
||||||
mslog(s, NULL, LOG_ERR, "%s: Could not set any IP.\n", lease->name);
|
mslog(s, NULL, LOG_ERR, "%s: Could not set any IP.\n", proc->tun_lease.name);
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@@ -277,11 +110,11 @@ static int set_network_info( main_server_st* s, const struct lease_st *lease)
|
|||||||
memset(&ifr, 0, sizeof(ifr));
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
ifr.ifr_addr.sa_family = AF_INET;
|
ifr.ifr_addr.sa_family = AF_INET;
|
||||||
ifr.ifr_flags |= IFF_UP;
|
ifr.ifr_flags |= IFF_UP;
|
||||||
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", lease->name);
|
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", proc->tun_lease.name);
|
||||||
|
|
||||||
ret = ioctl(fd, SIOCSIFFLAGS, &ifr);
|
ret = ioctl(fd, SIOCSIFFLAGS, &ifr);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
mslog(s, NULL, LOG_ERR, "%s: Could not bring up interface.\n", lease->name);
|
mslog(s, NULL, LOG_ERR, "%s: Could not bring up interface.\n", proc->tun_lease.name);
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,63 +123,18 @@ cleanup:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include <ccan/hash/hash.h>
|
||||||
|
|
||||||
int open_tun(main_server_st* s, struct proc_st* proc)
|
int open_tun(main_server_st* s, struct proc_st* proc)
|
||||||
{
|
{
|
||||||
int tunfd, ret, e;
|
int tunfd, ret, e;
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
unsigned int t;
|
unsigned int t;
|
||||||
struct lease_st *lease = NULL;
|
|
||||||
struct lease_st *last4, *tmp;
|
|
||||||
struct lease_st *last6;
|
|
||||||
unsigned current = s->tun->total;
|
|
||||||
time_t now = time(0);
|
|
||||||
|
|
||||||
last4 = last6 = NULL;
|
ret = get_ip_leases(s, proc);
|
||||||
|
if (ret < 0)
|
||||||
/* try to re-use an address */
|
return ret;
|
||||||
list_for_each(&s->tun->head, tmp, list) {
|
snprintf(proc->tun_lease.name, sizeof(proc->tun_lease.name), "%s%%d", s->config->network.name);
|
||||||
/* if the device isn't in use by the server and the IPs
|
|
||||||
* are free. */
|
|
||||||
if (tmp->in_use == 0 && (tmp->available_at < now || (proc->username[0] != 0 && strcmp(proc->username, tmp->username) == 0))) {
|
|
||||||
if ((tmp->lip6_len != 0 && icmp_ping6(s, (void*)&tmp->lip6, (void*)&tmp->rip6) == 0) ||
|
|
||||||
(tmp->lip4_len != 0 && icmp_ping4(s, (void*)&tmp->lip4, (void*)&tmp->rip4) == 0)) {
|
|
||||||
lease = tmp;
|
|
||||||
mslog(s, NULL, LOG_INFO, "reusing tun device %s\n", lease->name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* nothing to re-use */
|
|
||||||
if (lease == NULL) {
|
|
||||||
lease = calloc(1, sizeof(*lease));
|
|
||||||
if (lease == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
list_for_each_rev(&s->tun->head, tmp, list) {
|
|
||||||
if (last4 == NULL && tmp->rip4_len > 0)
|
|
||||||
last4 = tmp;
|
|
||||||
|
|
||||||
if (last6 == NULL && tmp->rip6_len > 0)
|
|
||||||
last6 = tmp;
|
|
||||||
|
|
||||||
if (last4 && last6)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = get_avail_network_addresses(s, last4, last6, lease);
|
|
||||||
if (ret < 0) {
|
|
||||||
free(lease);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add into the list */
|
|
||||||
list_add_tail( &s->tun->head, &lease->list);
|
|
||||||
snprintf(lease->name, sizeof(lease->name), "%s%u", s->config->network.name, current);
|
|
||||||
snprintf(lease->username, sizeof(lease->username), "%s", proc->username);
|
|
||||||
s->tun->total++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* No need to free the lease after this point.
|
/* No need to free the lease after this point.
|
||||||
*/
|
*/
|
||||||
@@ -366,21 +154,24 @@ int open_tun(main_server_st* s, struct proc_st* proc)
|
|||||||
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;
|
||||||
|
|
||||||
memcpy(ifr.ifr_name, lease->name, IFNAMSIZ);
|
memcpy(ifr.ifr_name, proc->tun_lease.name, IFNAMSIZ);
|
||||||
|
|
||||||
if (ioctl(tunfd, TUNSETIFF, (void *) &ifr) < 0) {
|
if (ioctl(tunfd, TUNSETIFF, (void *) &ifr) < 0) {
|
||||||
e = errno;
|
e = errno;
|
||||||
mslog(s, NULL, LOG_ERR, "%s: TUNSETIFF: %s\n", lease->name, strerror(e));
|
mslog(s, NULL, LOG_ERR, "%s: TUNSETIFF: %s\n", proc->tun_lease.name, strerror(e));
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
memcpy(lease->name, ifr.ifr_name, IFNAMSIZ);
|
memcpy(proc->tun_lease.name, ifr.ifr_name, IFNAMSIZ);
|
||||||
mslog(s, NULL, LOG_INFO, "assigning tun device %s\n", lease->name);
|
mslog(s, NULL, LOG_INFO, "assigning tun device %s\n", proc->tun_lease.name);
|
||||||
|
|
||||||
|
# if 0
|
||||||
|
/* we no longer use persistent tun */
|
||||||
if (ioctl(tunfd, TUNSETPERSIST, (void *)0) < 0) {
|
if (ioctl(tunfd, TUNSETPERSIST, (void *)0) < 0) {
|
||||||
e = errno;
|
e = errno;
|
||||||
mslog(s, NULL, LOG_ERR, "%s: TUNSETPERSIST: %s\n", lease->name, strerror(e));
|
mslog(s, NULL, LOG_ERR, "%s: TUNSETPERSIST: %s\n", proc->tun_lease.name, strerror(e));
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
if (s->config->uid != -1) {
|
if (s->config->uid != -1) {
|
||||||
t = s->config->uid;
|
t = s->config->uid;
|
||||||
@@ -388,7 +179,7 @@ int open_tun(main_server_st* s, struct proc_st* proc)
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
e = errno;
|
e = errno;
|
||||||
mslog(s, NULL, LOG_INFO, "%s: TUNSETOWNER: %s\n",
|
mslog(s, NULL, LOG_INFO, "%s: TUNSETOWNER: %s\n",
|
||||||
lease->name, strerror(e));
|
proc->tun_lease.name, strerror(e));
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -400,7 +191,7 @@ int open_tun(main_server_st* s, struct proc_st* proc)
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
e = errno;
|
e = errno;
|
||||||
mslog(s, NULL, LOG_ERR, "%s: TUNSETGROUP: %s\n",
|
mslog(s, NULL, LOG_ERR, "%s: TUNSETGROUP: %s\n",
|
||||||
lease->name, strerror(e));
|
proc->tun_lease.name, strerror(e));
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -425,22 +216,19 @@ int open_tun(main_server_st* s, struct proc_st* proc)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(lease->name, sizeof(lease->name), "%s", devname(st.st_rdev, S_IFCHR));
|
snprintf(proc->tun_lease.name, sizeof(proc->tun_lease.name), "%s", devname(st.st_rdev, S_IFCHR));
|
||||||
}
|
}
|
||||||
|
|
||||||
set_cloexec_flag (tunfd, 1);
|
set_cloexec_flag (tunfd, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* set IP/mask */
|
/* set IP/mask */
|
||||||
ret = set_network_info(s, lease);
|
ret = set_network_info(s, proc);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
lease->in_use = 1;
|
proc->tun_lease.fd = tunfd;
|
||||||
lease->available_at = now + s->config->cookie_validity;
|
|
||||||
lease->fd = tunfd;
|
|
||||||
proc->lease = lease;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
fail:
|
fail:
|
||||||
|
|||||||
40
src/tun.h
40
src/tun.h
@@ -5,50 +5,12 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ccan/list/list.h>
|
#include <ccan/list/list.h>
|
||||||
|
|
||||||
struct lease_st {
|
struct tun_lease_st {
|
||||||
struct list_node list;
|
|
||||||
|
|
||||||
char name[IFNAMSIZ];
|
char name[IFNAMSIZ];
|
||||||
char username[MAX_USERNAME_SIZE]; /* owner */
|
|
||||||
unsigned int tun_nr;
|
|
||||||
unsigned int in_use;
|
|
||||||
time_t available_at; /* when it will be available */
|
|
||||||
|
|
||||||
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. */
|
/* this is used temporarily. */
|
||||||
int fd;
|
int fd;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tun_st {
|
|
||||||
struct list_head head;
|
|
||||||
unsigned total;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline static void tun_st_init(struct tun_st* ts)
|
|
||||||
{
|
|
||||||
memset(ts, 0, sizeof(*ts));
|
|
||||||
list_head_init(&ts->head);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static void tun_st_deinit(struct tun_st* ts)
|
|
||||||
{
|
|
||||||
struct lease_st *ltmp, *pos;
|
|
||||||
|
|
||||||
list_for_each_safe(&ts->head, ltmp, pos, list) {
|
|
||||||
list_del(<mp->list);
|
|
||||||
ts->total--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
10
src/vpn.h
10
src/vpn.h
@@ -47,8 +47,8 @@ extern int syslog_open;
|
|||||||
#define ERR_AUTH_CONTINUE -4
|
#define ERR_AUTH_CONTINUE -4
|
||||||
#define ERR_WAIT_FOR_SCRIPT -5
|
#define ERR_WAIT_FOR_SCRIPT -5
|
||||||
#define ERR_MEM -6
|
#define ERR_MEM -6
|
||||||
#define ERR_READ_ROUTES -7
|
#define ERR_READ_CONFIG -7
|
||||||
#define ERR_READ_CONFIG -8
|
#define ERR_NO_IP -8
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@@ -62,6 +62,12 @@ struct group_cfg_st {
|
|||||||
|
|
||||||
char *ipv4_dns;
|
char *ipv4_dns;
|
||||||
char *ipv6_dns;
|
char *ipv6_dns;
|
||||||
|
char *ipv4_nbns;
|
||||||
|
char *ipv6_nbns;
|
||||||
|
char *ipv4_network;
|
||||||
|
char *ipv6_network;
|
||||||
|
char *ipv4_netmask;
|
||||||
|
char *ipv6_netmask;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vpn_st {
|
struct vpn_st {
|
||||||
|
|||||||
@@ -235,10 +235,105 @@ static int send_auth_cookie_req(int fd, const struct cmd_auth_cookie_req_st* r)
|
|||||||
return(sendmsg(fd, &hdr, 0));
|
return(sendmsg(fd, &hdr, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int read_str_value_length(worker_st *ws, char** res)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
uint8_t len;
|
||||||
|
|
||||||
|
ret = force_read(ws->cmd_fd, &len, 1);
|
||||||
|
if (ret != 1) {
|
||||||
|
oclog(ws, LOG_ERR, "Error receiving length-value from main (%d)", ret);
|
||||||
|
return ERR_BAD_COMMAND;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > 0) {
|
||||||
|
*res = malloc(((int)len)+1);
|
||||||
|
if (*res == NULL)
|
||||||
|
return ERR_MEM;
|
||||||
|
|
||||||
|
ret = force_read(ws->cmd_fd, *res, len);
|
||||||
|
if (ret != len) {
|
||||||
|
oclog(ws, LOG_ERR, "Error receiving value from main (%d)", ret);
|
||||||
|
return ERR_BAD_COMMAND;
|
||||||
|
}
|
||||||
|
(*res)[len] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int deserialize_additional_data(worker_st* ws)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
uint8_t len;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
/* IPV4 DNS */
|
||||||
|
ret = read_str_value_length(ws, &ws->ipv4_dns);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* IPV6 DNS */
|
||||||
|
ret = read_str_value_length(ws, &ws->ipv6_dns);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* IPV4 NBNS */
|
||||||
|
ret = read_str_value_length(ws, &ws->ipv4_nbns);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* IPV6 NBNS */
|
||||||
|
ret = read_str_value_length(ws, &ws->ipv6_nbns);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* IPV4 netmask */
|
||||||
|
ret = read_str_value_length(ws, &ws->ipv4_netmask);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* IPV6 netmask */
|
||||||
|
ret = read_str_value_length(ws, &ws->ipv6_netmask);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* number of routes */
|
||||||
|
ret = force_read(ws->cmd_fd, &len, 1);
|
||||||
|
if (ret != 1) {
|
||||||
|
oclog(ws, LOG_ERR, "Error receiving length-value from main (%d)", ret);
|
||||||
|
return ERR_BAD_COMMAND;
|
||||||
|
}
|
||||||
|
ws->routes_size = len;
|
||||||
|
|
||||||
|
/* routes */
|
||||||
|
for (i=0;i<ws->routes_size;i++) {
|
||||||
|
ret = force_read(ws->cmd_fd, &ws->routes[i].size, 1);
|
||||||
|
if (ret != 1) {
|
||||||
|
oclog(ws, LOG_ERR, "Error received route size from main (%d)", ret);
|
||||||
|
return ERR_BAD_COMMAND;
|
||||||
|
}
|
||||||
|
|
||||||
|
ws->routes[i].route = malloc(ws->routes[i].size+1);
|
||||||
|
if (ws->routes[i].route == NULL)
|
||||||
|
return ERR_MEM;
|
||||||
|
|
||||||
|
ret = force_read(ws->cmd_fd, ws->routes[i].route, ws->routes[i].size);
|
||||||
|
if (ret != ws->routes[i].size) {
|
||||||
|
oclog(ws, LOG_ERR, "Error received routes from main (%d)", ret);
|
||||||
|
return ERR_BAD_COMMAND;
|
||||||
|
}
|
||||||
|
ws->routes[i].route[ws->routes[i].size] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int recv_auth_reply(worker_st *ws, struct cmd_auth_reply_st *resp)
|
static int recv_auth_reply(worker_st *ws, struct cmd_auth_reply_st *resp)
|
||||||
{
|
{
|
||||||
struct iovec iov[2];
|
struct iovec iov[2];
|
||||||
uint8_t cmd = 0, len;
|
uint8_t cmd = 0;
|
||||||
struct msghdr hdr;
|
struct msghdr hdr;
|
||||||
int ret, cmdlen;
|
int ret, cmdlen;
|
||||||
union {
|
union {
|
||||||
@@ -246,7 +341,6 @@ static int recv_auth_reply(worker_st *ws, struct cmd_auth_reply_st *resp)
|
|||||||
char control[CMSG_SPACE(sizeof(int))];
|
char control[CMSG_SPACE(sizeof(int))];
|
||||||
} control_un;
|
} control_un;
|
||||||
struct cmsghdr *cmptr;
|
struct cmsghdr *cmptr;
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
iov[0].iov_base = &cmd;
|
iov[0].iov_base = &cmd;
|
||||||
iov[0].iov_len = 1;
|
iov[0].iov_len = 1;
|
||||||
@@ -295,69 +389,11 @@ static int recv_auth_reply(worker_st *ws, struct cmd_auth_reply_st *resp)
|
|||||||
memcpy(ws->cookie, resp->data.ok.cookie, sizeof(ws->cookie));
|
memcpy(ws->cookie, resp->data.ok.cookie, sizeof(ws->cookie));
|
||||||
memcpy(ws->session_id, resp->data.ok.session_id, sizeof(ws->session_id));
|
memcpy(ws->session_id, resp->data.ok.session_id, sizeof(ws->session_id));
|
||||||
|
|
||||||
ws->routes_size = resp->data.ok.routes_size;
|
|
||||||
|
|
||||||
/* Read any additional data */
|
/* Read any additional data */
|
||||||
|
|
||||||
/* IPV4 DNS */
|
ret = deserialize_additional_data(ws);
|
||||||
ret = force_read(ws->cmd_fd, &len, 1);
|
if (ret < 0)
|
||||||
if (ret != 1) {
|
return ret;
|
||||||
oclog(ws, LOG_ERR, "Error received route size from main (%d)", ret);
|
|
||||||
return ERR_BAD_COMMAND;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len > 0) {
|
|
||||||
ws->ipv4_dns = malloc(len+1);
|
|
||||||
if (ws->ipv4_dns == NULL)
|
|
||||||
return ERR_MEM;
|
|
||||||
|
|
||||||
ret = force_read(ws->cmd_fd, ws->ipv4_dns, len);
|
|
||||||
if (ret != len) {
|
|
||||||
oclog(ws, LOG_ERR, "Error received routes from main (%d)", ret);
|
|
||||||
return ERR_BAD_COMMAND;
|
|
||||||
}
|
|
||||||
ws->ipv4_dns[len] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* IPV6 DNS */
|
|
||||||
ret = force_read(ws->cmd_fd, &len, 1);
|
|
||||||
if (ret != 1) {
|
|
||||||
oclog(ws, LOG_ERR, "Error received route size from main (%d)", ret);
|
|
||||||
return ERR_BAD_COMMAND;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len > 0) {
|
|
||||||
ws->ipv6_dns = malloc(len+1);
|
|
||||||
if (ws->ipv6_dns == NULL)
|
|
||||||
return ERR_MEM;
|
|
||||||
|
|
||||||
ret = force_read(ws->cmd_fd, ws->ipv6_dns, len);
|
|
||||||
if (ret != len) {
|
|
||||||
oclog(ws, LOG_ERR, "Error received routes from main (%d)", ret);
|
|
||||||
return ERR_BAD_COMMAND;
|
|
||||||
}
|
|
||||||
ws->ipv6_dns[len] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* routes */
|
|
||||||
for (i=0;i<ws->routes_size;i++) {
|
|
||||||
ret = force_read(ws->cmd_fd, &ws->routes[i].size, 1);
|
|
||||||
if (ret != 1) {
|
|
||||||
oclog(ws, LOG_ERR, "Error received route size from main (%d)", ret);
|
|
||||||
return ERR_BAD_COMMAND;
|
|
||||||
}
|
|
||||||
ws->routes[i].route = malloc(ws->routes[i].size+1);
|
|
||||||
if (ws->routes[i].route == NULL)
|
|
||||||
return ERR_MEM;
|
|
||||||
|
|
||||||
ret = force_read(ws->cmd_fd, ws->routes[i].route, ws->routes[i].size);
|
|
||||||
if (ret != ws->routes[i].size) {
|
|
||||||
oclog(ws, LOG_ERR, "Error received routes from main (%d)", ret);
|
|
||||||
return ERR_BAD_COMMAND;
|
|
||||||
}
|
|
||||||
ws->routes[i].route[ws->routes[i].size] = 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} else
|
} else
|
||||||
return ERR_AUTH_FAIL;
|
return ERR_AUTH_FAIL;
|
||||||
|
|||||||
@@ -157,22 +157,47 @@ struct ifreq ifr;
|
|||||||
oclog(ws, LOG_DEBUG, "cannot obtain IPv4 local IP for %s", vinfo->name);
|
oclog(ws, LOG_DEBUG, "cannot obtain IPv4 local IP for %s", vinfo->name);
|
||||||
|
|
||||||
#define LOCAL "local"
|
#define LOCAL "local"
|
||||||
if (ws->config->network.ipv4_dns && strcmp(ws->config->network.ipv4_dns, LOCAL) == 0)
|
if (ws->ipv4_dns != NULL)
|
||||||
|
vinfo->ipv4_dns = ws->ipv4_dns;
|
||||||
|
else if (ws->config->network.ipv4_dns && strcmp(ws->config->network.ipv4_dns, LOCAL) == 0)
|
||||||
vinfo->ipv4_dns = vinfo->ipv4_local;
|
vinfo->ipv4_dns = vinfo->ipv4_local;
|
||||||
else
|
else
|
||||||
vinfo->ipv4_dns = ws->config->network.ipv4_dns;
|
vinfo->ipv4_dns = ws->config->network.ipv4_dns;
|
||||||
|
|
||||||
if (ws->config->network.ipv6_dns && strcmp(ws->config->network.ipv6_dns, LOCAL) == 0)
|
if (ws->ipv6_dns != NULL)
|
||||||
|
vinfo->ipv6_dns = ws->ipv6_dns;
|
||||||
|
else if (ws->config->network.ipv6_dns && strcmp(ws->config->network.ipv6_dns, LOCAL) == 0)
|
||||||
vinfo->ipv6_dns = vinfo->ipv6_local;
|
vinfo->ipv6_dns = vinfo->ipv6_local;
|
||||||
else
|
else
|
||||||
vinfo->ipv6_dns = ws->config->network.ipv6_dns;
|
vinfo->ipv6_dns = ws->config->network.ipv6_dns;
|
||||||
|
|
||||||
|
if (ws->ipv4_nbns != NULL)
|
||||||
|
vinfo->ipv4_nbns = ws->ipv4_nbns;
|
||||||
|
else 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->ipv6_nbns != NULL)
|
||||||
|
vinfo->ipv6_nbns = ws->ipv6_nbns;
|
||||||
|
else 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;
|
vinfo->routes_size = ws->config->network.routes_size;
|
||||||
if (ws->config->network.routes_size > 0)
|
if (ws->config->network.routes_size > 0)
|
||||||
vinfo->routes = ws->config->network.routes;
|
vinfo->routes = ws->config->network.routes;
|
||||||
|
|
||||||
vinfo->ipv4_netmask = ws->config->network.ipv4_netmask;
|
if (ws->ipv4_netmask != NULL)
|
||||||
vinfo->ipv6_netmask = ws->config->network.ipv6_netmask;
|
vinfo->ipv4_netmask = ws->ipv4_netmask;
|
||||||
|
else
|
||||||
|
vinfo->ipv4_netmask = ws->config->network.ipv4_netmask;
|
||||||
|
|
||||||
|
if (ws->ipv6_netmask != NULL)
|
||||||
|
vinfo->ipv6_netmask = ws->ipv6_netmask;
|
||||||
|
else
|
||||||
|
vinfo->ipv6_netmask = ws->config->network.ipv6_netmask;
|
||||||
|
|
||||||
memset(&ifr, 0, sizeof(ifr));
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
ifr.ifr_addr.sa_family = AF_INET;
|
ifr.ifr_addr.sa_family = AF_INET;
|
||||||
|
|||||||
@@ -854,13 +854,11 @@ socklen_t sl;
|
|||||||
SEND_ERR(ret);
|
SEND_ERR(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ws->ipv4_dns) {
|
if (vinfo.ipv4_dns) {
|
||||||
ret = tls_printf(ws->session, "X-CSTP-DNS: %s\r\n", ws->ipv4_dns);
|
|
||||||
SEND_ERR(ret);
|
|
||||||
} else if (vinfo.ipv4_dns) {
|
|
||||||
ret = tls_printf(ws->session, "X-CSTP-DNS: %s\r\n", vinfo.ipv4_dns);
|
ret = tls_printf(ws->session, "X-CSTP-DNS: %s\r\n", vinfo.ipv4_dns);
|
||||||
SEND_ERR(ret);
|
SEND_ERR(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vinfo.ipv4_nbns) {
|
if (vinfo.ipv4_nbns) {
|
||||||
ret = tls_printf(ws->session, "X-CSTP-NBNS: %s\r\n", vinfo.ipv4_nbns);
|
ret = tls_printf(ws->session, "X-CSTP-NBNS: %s\r\n", vinfo.ipv4_nbns);
|
||||||
SEND_ERR(ret);
|
SEND_ERR(ret);
|
||||||
@@ -877,19 +875,18 @@ socklen_t sl;
|
|||||||
SEND_ERR(ret);
|
SEND_ERR(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ws->ipv6_dns) {
|
if (vinfo.ipv6_dns) {
|
||||||
ret = tls_printf(ws->session, "X-CSTP-DNS: %s\r\n", ws->ipv6_dns);
|
|
||||||
SEND_ERR(ret);
|
|
||||||
} else if (vinfo.ipv6_dns) {
|
|
||||||
ret = tls_printf(ws->session, "X-CSTP-DNS: %s\r\n", vinfo.ipv6_dns);
|
ret = tls_printf(ws->session, "X-CSTP-DNS: %s\r\n", vinfo.ipv6_dns);
|
||||||
SEND_ERR(ret);
|
SEND_ERR(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vinfo.ipv6_nbns) {
|
if (vinfo.ipv6_nbns) {
|
||||||
ret = tls_printf(ws->session, "X-CSTP-NBNS: %s\r\n", vinfo.ipv6_nbns);
|
ret = tls_printf(ws->session, "X-CSTP-NBNS: %s\r\n", vinfo.ipv6_nbns);
|
||||||
SEND_ERR(ret);
|
SEND_ERR(ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (i=0;i<vinfo.routes_size;i++) {
|
for (i=0;i<vinfo.routes_size;i++) {
|
||||||
if (req->no_ipv6 != 0 && strchr(vinfo.routes[i], ':') != 0)
|
if (req->no_ipv6 != 0 && strchr(vinfo.routes[i], ':') != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -121,6 +121,10 @@ typedef struct worker_st {
|
|||||||
/* additional data - received per user or per group */
|
/* additional data - received per user or per group */
|
||||||
char *ipv4_dns;
|
char *ipv4_dns;
|
||||||
char *ipv6_dns;
|
char *ipv6_dns;
|
||||||
|
char *ipv4_nbns;
|
||||||
|
char *ipv6_nbns;
|
||||||
|
char *ipv4_netmask;
|
||||||
|
char *ipv6_netmask;
|
||||||
unsigned routes_size;
|
unsigned routes_size;
|
||||||
struct route_st routes[MAX_ROUTES];
|
struct route_st routes[MAX_ROUTES];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user