mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-02-10 16:57:00 +08:00
updated
This commit is contained in:
608
main.c
608
main.c
@@ -1,608 +0,0 @@
|
||||
/*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <linux/if_tun.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <gnutls/x509.h>
|
||||
#include <tlslib.h>
|
||||
|
||||
#include <vpn.h>
|
||||
#include <cookies.h>
|
||||
#include <vpn.h>
|
||||
#include <list.h>
|
||||
|
||||
int syslog_open = 0;
|
||||
static unsigned int need_to_expire_cookies = 0;
|
||||
|
||||
struct listen_list_st {
|
||||
struct list_head list;
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct ptun_list_st {
|
||||
struct list_head list;
|
||||
int fd;
|
||||
};
|
||||
|
||||
static void tls_log_func(int level, const char *str)
|
||||
{
|
||||
syslog(LOG_DEBUG, "Debug[<%d>]: %s", level, str);
|
||||
}
|
||||
|
||||
static void tls_audit_log_func(gnutls_session_t session, const char *str)
|
||||
{
|
||||
syslog(LOG_AUTH, "Warning: %s", str);
|
||||
}
|
||||
|
||||
static struct cfg_st config = {
|
||||
.auth_types = AUTH_TYPE_USERNAME_PASS,
|
||||
.name = NULL,
|
||||
.port = 3333,
|
||||
.cert = "./test.pem",
|
||||
.key = "./test.pem",
|
||||
.cert_req = GNUTLS_CERT_IGNORE,
|
||||
.cert_user_oid = GNUTLS_OID_LDAP_UID /* or just GNUTLS_OID_X520_COMMON_NAME */,
|
||||
.root_dir = "root/",
|
||||
.cookie_validity = 3600,
|
||||
.db_file = "/tmp/db",
|
||||
.uid = 65534,
|
||||
.gid = 65534,
|
||||
.ca = NULL,
|
||||
.networks_size = 1,
|
||||
.networks = {{
|
||||
.name = "vpns0",
|
||||
.ipv4_netmask = "255.255.255.0",
|
||||
.ipv4 = "192.168.55.1",
|
||||
.ipv4_dns = "192.168.55.1",
|
||||
}}
|
||||
};
|
||||
|
||||
/* Returns 0 on success or negative value on error.
|
||||
*/
|
||||
static int
|
||||
listen_ports(struct listen_list_st *list, const char *node,
|
||||
int listen_port, int socktype)
|
||||
{
|
||||
struct addrinfo hints, *res, *ptr;
|
||||
char portname[6];
|
||||
int s, y;
|
||||
char buf[512];
|
||||
struct listen_list_st *tmp;
|
||||
|
||||
snprintf(portname, sizeof(portname), "%d", listen_port);
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_socktype = socktype;
|
||||
hints.ai_flags = AI_PASSIVE
|
||||
#ifdef AI_ADDRCONFIG
|
||||
| AI_ADDRCONFIG
|
||||
#endif
|
||||
;
|
||||
|
||||
s = getaddrinfo(node, portname, &hints, &res);
|
||||
if (s != 0) {
|
||||
fprintf(stderr, "getaddrinfo() failed: %s\n",
|
||||
gai_strerror(s));
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (ptr = res; ptr != NULL; ptr = ptr->ai_next) {
|
||||
#ifndef HAVE_IPV6
|
||||
if (ptr->ai_family != AF_INET)
|
||||
continue;
|
||||
#endif
|
||||
fprintf(stderr, "listening on %s...\n",
|
||||
human_addr(ptr->ai_addr, ptr->ai_addrlen,
|
||||
buf, sizeof(buf)));
|
||||
|
||||
s = socket(ptr->ai_family, ptr->ai_socktype,
|
||||
ptr->ai_protocol);
|
||||
if (s < 0) {
|
||||
perror("socket() failed");
|
||||
continue;
|
||||
}
|
||||
#if defined(HAVE_IPV6) && !defined(_WIN32)
|
||||
if (ptr->ai_family == AF_INET6) {
|
||||
y = 1;
|
||||
/* avoid listen on ipv6 addresses failing
|
||||
* because already listening on ipv4 addresses: */
|
||||
setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
(const void *) &y, sizeof(y));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (socktype == SOCK_STREAM) {
|
||||
y = 1;
|
||||
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
|
||||
(const void *) &y, sizeof(y)) < 0) {
|
||||
perror("setsockopt() failed");
|
||||
close(s);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
#if defined(IP_DONTFRAG)
|
||||
y = 1;
|
||||
if (setsockopt(s, IPPROTO_IP, IP_DONTFRAG,
|
||||
(const void *) &y, sizeof(y)) < 0)
|
||||
perror("setsockopt(IP_DF) failed");
|
||||
#elif defined(IP_MTU_DISCOVER)
|
||||
y = IP_PMTUDISC_DO;
|
||||
if (setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER,
|
||||
(const void *) &y, sizeof(y)) < 0)
|
||||
perror("setsockopt(IP_DF) failed");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (bind(s, ptr->ai_addr, ptr->ai_addrlen) < 0) {
|
||||
perror("bind() failed");
|
||||
close(s);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (socktype == SOCK_STREAM) {
|
||||
if (listen(s, 10) < 0) {
|
||||
perror("listen() failed");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
tmp = calloc(1, sizeof(struct listen_list_st));
|
||||
tmp->fd = s;
|
||||
list_add(&(tmp->list), &(list->list));
|
||||
}
|
||||
|
||||
fflush(stderr);
|
||||
freeaddrinfo(res);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void handle_children(int signo)
|
||||
{
|
||||
while (waitpid(-1, NULL, WNOHANG) > 0);
|
||||
}
|
||||
|
||||
static void handle_alarm(int signo)
|
||||
{
|
||||
need_to_expire_cookies = 1;
|
||||
}
|
||||
|
||||
static int set_network_info(const struct vpn_st* vinfo)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int fd, ret;
|
||||
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
/* set netmask */
|
||||
if (vinfo->ipv4_netmask && vinfo->ipv4) {
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", vinfo->name);
|
||||
|
||||
ret = inet_pton(AF_INET, vinfo->ipv4_netmask, &((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr);
|
||||
if (ret != 1) {
|
||||
syslog(LOG_ERR, "%s: Error reading mask: %s\n",
|
||||
vinfo->name, vinfo->ipv4_netmask);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = ioctl(fd, SIOCSIFNETMASK, &ifr);
|
||||
if (ret != 0) {
|
||||
syslog(LOG_ERR, "%s: Error setting mask: %s\n",
|
||||
vinfo->name, vinfo->ipv4_netmask);
|
||||
}
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", vinfo->name);
|
||||
|
||||
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",
|
||||
vinfo->name, vinfo->ipv4_netmask);
|
||||
goto fail;
|
||||
|
||||
}
|
||||
|
||||
ret = ioctl(fd, SIOCSIFADDR, &ifr);
|
||||
if (ret != 0) {
|
||||
syslog(LOG_ERR, "%s: Error setting IP: %s\n",
|
||||
vinfo->name, vinfo->ipv4);
|
||||
}
|
||||
}
|
||||
|
||||
if (vinfo->ipv6_netmask && vinfo->ipv6) {
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_addr.sa_family = AF_INET6;
|
||||
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", vinfo->name);
|
||||
|
||||
ret = inet_pton(AF_INET6, vinfo->ipv6_netmask, &((struct sockaddr_in6 *)&ifr.ifr_addr)->sin6_addr);
|
||||
if (ret != 1) {
|
||||
syslog(LOG_ERR, "%s: Error reading mask: %s\n",
|
||||
vinfo->name, vinfo->ipv6_netmask);
|
||||
goto fail;
|
||||
|
||||
}
|
||||
|
||||
ret = ioctl(fd, SIOCSIFNETMASK, &ifr);
|
||||
if (ret != 0) {
|
||||
syslog(LOG_ERR, "%s: Error setting mask: %s\n",
|
||||
vinfo->name, vinfo->ipv6_netmask);
|
||||
}
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_addr.sa_family = AF_INET6;
|
||||
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", vinfo->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",
|
||||
vinfo->name, vinfo->ipv6_netmask);
|
||||
goto fail;
|
||||
|
||||
}
|
||||
|
||||
ret = ioctl(fd, SIOCSIFADDR, &ifr);
|
||||
if (ret != 0) {
|
||||
syslog(LOG_ERR, "%s: Error setting IP: %s\n",
|
||||
vinfo->name, vinfo->ipv6);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int open_tun(struct cfg_st *config)
|
||||
{
|
||||
int tunfd, ret, e;
|
||||
struct ifreq ifr;
|
||||
unsigned int i, t;
|
||||
|
||||
tunfd = open("/dev/net/tun", O_RDWR);
|
||||
if (tunfd < 0) {
|
||||
int e = errno;
|
||||
syslog(LOG_ERR, "Can't open /dev/net/tun: %s\n",
|
||||
strerror(e));
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i=0;i<config->networks_size;i++) {
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
|
||||
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), config->networks[i].name, 0);
|
||||
if (ioctl(tunfd, TUNSETIFF, (void *) &ifr) < 0) {
|
||||
e = errno;
|
||||
syslog(LOG_ERR, "TUNSETIFF: %s\n", strerror(e));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (config->uid != -1) {
|
||||
t = config->uid;
|
||||
ret = ioctl(tunfd, TUNSETOWNER, t);
|
||||
if (ret < 0) {
|
||||
e = errno;
|
||||
syslog(LOG_ERR, "TUNSETOWNER: %s\n", strerror(e));
|
||||
exit(1);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (config->gid != -1) {
|
||||
t = config->uid;
|
||||
ret = ioctl(tunfd, TUNSETGROUP, t);
|
||||
if (ret < 0) {
|
||||
e = errno;
|
||||
syslog(LOG_ERR, "TUNSETGROUP: %s\n", strerror(e));
|
||||
exit(1);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* set IP/mask */
|
||||
ret = set_network_info(&config->networks[i]);
|
||||
if (ret < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return tunfd;
|
||||
}
|
||||
|
||||
static int verify_certificate_cb(gnutls_session_t session)
|
||||
{
|
||||
unsigned int status;
|
||||
int ret, type;
|
||||
gnutls_datum_t out;
|
||||
|
||||
/* This verification function uses the trusted CAs in the credentials
|
||||
* structure. So you must have installed one or more CA certificates.
|
||||
*/
|
||||
ret = gnutls_certificate_verify_peers2(session, &status);
|
||||
if (ret < 0) {
|
||||
syslog(LOG_ERR, "Error verifying client certificate");
|
||||
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||
}
|
||||
|
||||
type = gnutls_certificate_type_get(session);
|
||||
|
||||
ret =
|
||||
gnutls_certificate_verification_status_print(status, type,
|
||||
&out, 0);
|
||||
if (ret < 0) {
|
||||
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||
}
|
||||
|
||||
syslog(LOG_INFO, "verification: %s", out.data);
|
||||
|
||||
gnutls_free(out.data);
|
||||
|
||||
if (status != 0) /* Certificate is not trusted */
|
||||
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||
|
||||
/* notify gnutls to continue handshake normally */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void drop_privileges(struct cfg_st *config)
|
||||
{
|
||||
int ret, e;
|
||||
|
||||
if (config->gid != -1) {
|
||||
ret = setgid(config->gid);
|
||||
if (ret < 0) {
|
||||
e = errno;
|
||||
syslog(LOG_ERR, "Cannot set gid to %d: %s\n", (int)config->gid, strerror(e));
|
||||
exit(1);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (config->uid != -1) {
|
||||
ret = setuid(config->uid);
|
||||
if (ret < 0) {
|
||||
e = errno;
|
||||
syslog(LOG_ERR, "Cannot set uid to %d: %s\n", (int)config->uid, strerror(e));
|
||||
exit(1);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
||||
int fd, pid, e;
|
||||
struct tls_st creds;
|
||||
struct listen_list_st llist;
|
||||
struct listen_list_st *tmp;
|
||||
struct list_head *pos;
|
||||
struct ptun_list_st lptun;
|
||||
struct ptun_list_st *ptmp;
|
||||
fd_set rd;
|
||||
int val, n = 0, ret, tunfd;
|
||||
struct timeval tv;
|
||||
int sockets[2];
|
||||
|
||||
INIT_LIST_HEAD(&lptun->list);
|
||||
INIT_LIST_HEAD(&llist->list);
|
||||
|
||||
/*signal(SIGINT, SIG_IGN); */
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
signal(SIGCHLD, handle_children);
|
||||
signal(SIGALRM, handle_alarm);
|
||||
|
||||
/* XXX load configuration */
|
||||
|
||||
ret = listen_ports(&llist, config.name, config.port, SOCK_STREAM);
|
||||
if (ret < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
tunfd = open_tun(&config);
|
||||
if (tunfd < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
drop_privileges(&config);
|
||||
|
||||
gnutls_global_set_log_function(tls_log_func);
|
||||
gnutls_global_set_audit_log_function(tls_audit_log_func);
|
||||
gnutls_global_set_log_level(0);
|
||||
|
||||
ret = gnutls_global_init();
|
||||
GNUTLS_FATAL_ERR(ret);
|
||||
|
||||
ret = gnutls_certificate_allocate_credentials(&creds.xcred);
|
||||
GNUTLS_FATAL_ERR(ret);
|
||||
|
||||
ret =
|
||||
gnutls_certificate_set_x509_key_file(creds.xcred, config.cert,
|
||||
config.key,
|
||||
GNUTLS_X509_FMT_PEM);
|
||||
GNUTLS_FATAL_ERR(ret);
|
||||
|
||||
if (config.ca != NULL) {
|
||||
ret =
|
||||
gnutls_certificate_set_x509_trust_file(creds.xcred,
|
||||
config.ca,
|
||||
GNUTLS_X509_FMT_PEM);
|
||||
GNUTLS_FATAL_ERR(ret);
|
||||
printf("Processed %d CA certificate(s).\n", ret);
|
||||
}
|
||||
|
||||
if (config.crl != NULL) {
|
||||
ret =
|
||||
gnutls_certificate_set_x509_crl_file(creds.xcred,
|
||||
config.crl,
|
||||
GNUTLS_X509_FMT_PEM);
|
||||
GNUTLS_FATAL_ERR(ret);
|
||||
}
|
||||
|
||||
|
||||
if (config.cert_req != GNUTLS_CERT_IGNORE) {
|
||||
gnutls_certificate_set_verify_function(creds.xcred,
|
||||
verify_certificate_cb);
|
||||
}
|
||||
|
||||
ret = gnutls_priority_init(&creds.cprio, config.priorities, NULL);
|
||||
GNUTLS_FATAL_ERR(ret);
|
||||
|
||||
alarm(config.cookie_validity+300);
|
||||
openlog("ocserv", LOG_PID, LOG_LOCAL0);
|
||||
syslog_open = 1;
|
||||
|
||||
for (;;) {
|
||||
FD_ZERO(&rd);
|
||||
|
||||
list_for_each(pos, &llist.list) {
|
||||
tmp = list_entry(pos, struct listen_list_st, list);
|
||||
#ifndef _WIN32
|
||||
val = fcntl(tmp->fd, F_GETFL, 0);
|
||||
if ((val == -1)
|
||||
|| (fcntl(tmp->fd, F_SETFL, val | O_NONBLOCK) <
|
||||
0)) {
|
||||
perror("fcntl()");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
FD_SET(tmp->fd, &rd);
|
||||
n = MAX(n, tmp->fd);
|
||||
}
|
||||
n = MAX(n, tunfd);
|
||||
|
||||
tv.tv_usec = 0;
|
||||
tv.tv_sec = 10;
|
||||
n = select(n + 1, &rd, NULL, NULL, &tv);
|
||||
if (n == -1 && errno == EINTR)
|
||||
continue;
|
||||
|
||||
if (n < 0) {
|
||||
syslog(LOG_ERR, "Error in select(): %s", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (need_to_expire_cookies != 0) {
|
||||
need_to_expire_cookies = 0;
|
||||
pid = fork();
|
||||
if (pid == 0) { /* child */
|
||||
list_for_each(pos, &llist.list) {
|
||||
tmp = list_entry(pos, struct listen_list_st, list);
|
||||
close(tmp->fd);
|
||||
}
|
||||
|
||||
expire_cookies(&config);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (FD_ISSET(tunfd, &rd)) {
|
||||
/* read packet */
|
||||
/* check IP/IPv6 */
|
||||
|
||||
list_for_each(pos, &lptun.list) {
|
||||
ptmp = list_entry(pos, struct ptun_list_st, list);
|
||||
/* if (ptmp->ip matches) { */
|
||||
/* forward to appropriate process */
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each(pos, &lptun.list) {
|
||||
ptmp = list_entry(pos, struct ptun_list_st, list);
|
||||
if (FD_ISSET(ptmp->fd, &rd)) {
|
||||
/* forward to appropriate process */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
list_for_each(pos, &llist.list) {
|
||||
tmp = list_entry(pos, struct listen_list_st, list);
|
||||
if (FD_ISSET(tmp->fd, &rd)) {
|
||||
fd = accept(tmp->fd, NULL, NULL);
|
||||
if (fd < 0) {
|
||||
syslog(LOG_ERR, "Error in accept(): %s", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = socketpair (AF_UNIX, SOCK_DGRAM, 0, sockets);
|
||||
if (ret != 0) {
|
||||
syslog(LOG_ERR, "Error in socketpair(): %s", strerror(errno));
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid == 0) { /* child */
|
||||
list_for_each(pos, &llist.list) {
|
||||
tmp = list_entry(pos, struct listen_list_st, list);
|
||||
close(tmp->fd);
|
||||
}
|
||||
|
||||
close(sockets[1]);
|
||||
vpn_server(&config, &creds,
|
||||
sockets[0], fd);
|
||||
exit(0);
|
||||
} else if (pid > 0) {/* parent */
|
||||
close(sockets[0]);
|
||||
|
||||
ptmp = calloc(1, sizeof(struct ptun_list_st));
|
||||
if (ptmp == NULL) {
|
||||
close(fd);
|
||||
close(sockets[0]);
|
||||
continue;
|
||||
}
|
||||
|
||||
ptmp->fd = sockets[1];
|
||||
list_add(&(ptmp->list), &(lptun->list));
|
||||
} else {
|
||||
close(sockets[0]);
|
||||
close(sockets[1]);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
127
src/http_auth.c
127
src/http_auth.c
@@ -70,6 +70,7 @@ int ret;
|
||||
|
||||
}
|
||||
|
||||
static
|
||||
int get_cert_username(server_st *server, const gnutls_datum_t* raw,
|
||||
char* username, size_t username_size)
|
||||
{
|
||||
@@ -131,11 +132,11 @@ 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, int* tunfd)
|
||||
static int recv_auth_reply(int cmdfd, struct tun_id_st * tunid)
|
||||
{
|
||||
struct iovec iov[2];
|
||||
uint8_t cmd;
|
||||
uint8_t reply;
|
||||
struct iovec iov[3];
|
||||
uint8_t cmd = 0;
|
||||
struct cmd_auth_resp_st resp;
|
||||
struct msghdr hdr;
|
||||
int ret;
|
||||
|
||||
@@ -148,12 +149,15 @@ static int recv_auth_reply(int cmdfd, int* tunfd)
|
||||
iov[0].iov_base = &cmd;
|
||||
iov[0].iov_len = 1;
|
||||
|
||||
iov[1].iov_base = &reply;
|
||||
iov[1].iov_base = &resp.reply;
|
||||
iov[1].iov_len = 1;
|
||||
|
||||
iov[2].iov_base = &resp.vname;
|
||||
iov[2].iov_len = sizeof(resp.vname);
|
||||
|
||||
memset(&hdr, 0, sizeof(hdr));
|
||||
hdr.msg_iov = iov;
|
||||
hdr.msg_iovlen = 2;
|
||||
hdr.msg_iovlen = 3;
|
||||
|
||||
hdr.msg_control = control_un.control;
|
||||
hdr.msg_controllen = sizeof(control_un.control);
|
||||
@@ -162,11 +166,10 @@ static int recv_auth_reply(int cmdfd, int* tunfd)
|
||||
if (ret <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cmd != AUTH_REP)
|
||||
return -1;
|
||||
|
||||
switch(reply) {
|
||||
switch(resp.reply) {
|
||||
case REP_AUTH_OK:
|
||||
if ( (cmptr = CMSG_FIRSTHDR(&hdr)) != NULL && cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
|
||||
if (cmptr->cmsg_level != SOL_SOCKET)
|
||||
@@ -174,7 +177,8 @@ static int recv_auth_reply(int cmdfd, int* tunfd)
|
||||
if (cmptr->cmsg_type != SCM_RIGHTS)
|
||||
return -1;
|
||||
|
||||
*tunfd = *((int *) CMSG_DATA(cmptr));
|
||||
tunid->fd = *((int *) CMSG_DATA(cmptr));
|
||||
memcpy(tunid->name, resp.vname, sizeof(tunid->name));
|
||||
} else
|
||||
return -1;
|
||||
break;
|
||||
@@ -187,7 +191,7 @@ static int recv_auth_reply(int cmdfd, int* tunfd)
|
||||
|
||||
/* sends an authentication request to main thread and waits for
|
||||
* a reply */
|
||||
static int auth_user(int cmdfd, struct cmd_auth_req_st* areq, int* tunfd)
|
||||
static int auth_user(int cmdfd, struct cmd_auth_req_st* areq, struct tun_id_st* tunid)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -195,9 +199,37 @@ int ret;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return recv_auth_reply(cmdfd, tunfd);
|
||||
return recv_auth_reply(cmdfd, tunid);
|
||||
}
|
||||
|
||||
static
|
||||
int get_cert_info(server_st *server, struct cmd_auth_req_st *areq, const char** reason)
|
||||
{
|
||||
const gnutls_datum_t * cert;
|
||||
unsigned int ncerts;
|
||||
int ret;
|
||||
|
||||
/* this is superflous. Verification has already been performed
|
||||
* during handshake. */
|
||||
cert = gnutls_certificate_get_peers (server->session, &ncerts);
|
||||
|
||||
if (cert == NULL) {
|
||||
*reason = "No certificate found";
|
||||
return -1;
|
||||
}
|
||||
|
||||
areq->tls_auth_ok = 1;
|
||||
if (server->config->cert_user_oid) { /* otherwise certificate username is ignored */
|
||||
ret = get_cert_username(server, cert, areq->cert_user, sizeof(areq->cert_user));
|
||||
if (ret < 0) {
|
||||
oclog(server, LOG_ERR, "Cannot get username (%s) from certificate", server->config->cert_user_oid);
|
||||
*reason = "No username in certificate";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int post_old_auth_handler(server_st *server)
|
||||
{
|
||||
@@ -216,28 +248,11 @@ struct cmd_auth_req_st areq;
|
||||
memset(&areq, 0, sizeof(areq));
|
||||
|
||||
if (server->config->auth_types & AUTH_TYPE_CERTIFICATE) {
|
||||
const gnutls_datum_t * cert;
|
||||
unsigned int ncerts;
|
||||
|
||||
/* this is superflous. Verification has already been performed
|
||||
* during handshake. */
|
||||
cert = gnutls_certificate_get_peers (server->session, &ncerts);
|
||||
|
||||
if (cert == NULL) {
|
||||
reason = "No certificate found";
|
||||
ret = get_cert_info(server, &areq, &reason);
|
||||
if (ret < 0)
|
||||
goto auth_fail;
|
||||
}
|
||||
|
||||
areq.tls_auth_ok = 1;
|
||||
if (server->config->cert_user_oid) { /* otherwise certificate username is ignored */
|
||||
ret = get_cert_username(server, cert, areq.cert_user, sizeof(areq.cert_user));
|
||||
if (ret < 0) {
|
||||
oclog(server, LOG_ERR, "Cannot get username (%s) from certificate", server->config->cert_user_oid);
|
||||
reason = "No username in certificate";
|
||||
goto auth_fail;
|
||||
}
|
||||
username = areq.cert_user;
|
||||
}
|
||||
username = areq.cert_user;
|
||||
}
|
||||
|
||||
if (server->config->auth_types & AUTH_TYPE_USERNAME_PASS) {
|
||||
@@ -280,7 +295,7 @@ struct cmd_auth_req_st areq;
|
||||
snprintf(areq.pass, sizeof(areq.pass), "%s", password);
|
||||
}
|
||||
|
||||
ret = auth_user(server->cmdfd, &areq, &server->tunfd);
|
||||
ret = auth_user(server->cmdfd, &areq, &server->tunid);
|
||||
if (ret < 0)
|
||||
goto auth_fail;
|
||||
|
||||
@@ -345,6 +360,17 @@ char * password = NULL;
|
||||
char *p;
|
||||
unsigned int i;
|
||||
struct stored_cookie_st sc;
|
||||
struct cmd_auth_req_st areq;
|
||||
|
||||
memset(&areq, 0, sizeof(areq));
|
||||
|
||||
if (server->config->auth_types & AUTH_TYPE_CERTIFICATE) {
|
||||
ret = get_cert_info(server, &areq, &reason);
|
||||
if (ret < 0)
|
||||
goto auth_fail;
|
||||
|
||||
username = areq.cert_user;
|
||||
}
|
||||
|
||||
if (server->config->auth_types & AUTH_TYPE_USERNAME_PASS) {
|
||||
/* body should contain <username>test</username><password>test</password> */
|
||||
@@ -381,40 +407,15 @@ struct stored_cookie_st sc;
|
||||
p++;
|
||||
}
|
||||
|
||||
/* XXX: now verify username and passwords */
|
||||
if (strcmp(username, "test") != 0 || strcmp(password, "test") != 0)
|
||||
goto auth_fail;
|
||||
areq.user_pass_present = 1;
|
||||
snprintf(areq.user, sizeof(areq.user), "%s", username);
|
||||
snprintf(areq.pass, sizeof(areq.pass), "%s", password);
|
||||
}
|
||||
|
||||
if (server->config->auth_types & AUTH_TYPE_CERTIFICATE) {
|
||||
const gnutls_datum_t * cert;
|
||||
unsigned int ncerts;
|
||||
|
||||
/* this is superflous. Verification has already been performed
|
||||
* during handshake. */
|
||||
cert = gnutls_certificate_get_peers (server->session, &ncerts);
|
||||
|
||||
if (cert == NULL) {
|
||||
reason = "No certificate found";
|
||||
goto auth_fail;
|
||||
}
|
||||
|
||||
if (server->config->cert_user_oid) { /* otherwise certificate username is ignored */
|
||||
ret = get_cert_username(server, cert, cert_username, sizeof(cert_username));
|
||||
if (ret < 0) {
|
||||
oclog(server, LOG_ERR, "Cannot get username (%s) from certificate", server->config->cert_user_oid);
|
||||
reason = "No username in certificate";
|
||||
goto auth_fail;
|
||||
}
|
||||
|
||||
if (username) {
|
||||
if (strcmp(username, cert_username) != 0)
|
||||
oclog(server, LOG_NOTICE, "User '%s' presented the certificate of user '%s'", username, cert_username);
|
||||
} else {
|
||||
username = cert_username;
|
||||
}
|
||||
}
|
||||
}
|
||||
ret = auth_user(server->cmdfd, &areq, &server->tunid);
|
||||
if (ret < 0)
|
||||
goto auth_fail;
|
||||
|
||||
oclog(server, LOG_INFO, "User '%s' logged in\n", username);
|
||||
|
||||
|
||||
34
src/main.c
34
src/main.c
@@ -519,9 +519,9 @@ fork_failed:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_auth_reply(int fd, cmd_auth_reply_t r, int sendfd)
|
||||
static int send_auth_reply(int fd, cmd_auth_reply_t r, struct tun_id_st* tunid)
|
||||
{
|
||||
struct iovec iov[1];
|
||||
struct iovec iov[2];
|
||||
uint8_t cmd[2];
|
||||
struct msghdr hdr;
|
||||
union {
|
||||
@@ -538,14 +538,20 @@ static int send_auth_reply(int fd, cmd_auth_reply_t r, int sendfd)
|
||||
|
||||
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;
|
||||
hdr.msg_iovlen = 1;
|
||||
|
||||
if (r == REP_AUTH_OK) {
|
||||
if (r == REP_AUTH_OK && tunid != NULL) {
|
||||
iov[1].iov_base = tunid->name;
|
||||
hdr.msg_iovlen++;
|
||||
|
||||
/* Send the tun fd */
|
||||
hdr.msg_control = control_un.control;
|
||||
hdr.msg_controllen = sizeof(control_un.control);
|
||||
@@ -554,14 +560,14 @@ static int send_auth_reply(int fd, cmd_auth_reply_t r, int sendfd)
|
||||
cmptr->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
cmptr->cmsg_level = SOL_SOCKET;
|
||||
cmptr->cmsg_type = SCM_RIGHTS;
|
||||
*((int *) CMSG_DATA(cmptr)) = sendfd;
|
||||
*((int *) CMSG_DATA(cmptr)) = tunid->fd;
|
||||
}
|
||||
|
||||
return(sendmsg(fd, &hdr, 0));
|
||||
}
|
||||
|
||||
static int handle_auth_req(struct cfg_st *config, struct tun_st *tun,
|
||||
struct cmd_auth_req_st * req, int *tunfd)
|
||||
struct cmd_auth_req_st * req, struct tun_id_st *tunid)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -569,10 +575,10 @@ int ret;
|
||||
ret = 0;
|
||||
else
|
||||
ret = -1;
|
||||
|
||||
|
||||
if (ret == 0) { /* open tun */
|
||||
*tunfd = open_tun(config, tun);
|
||||
if (*tunfd == -1)
|
||||
ret = open_tun(config, tun, tunid);
|
||||
if (ret < 0)
|
||||
ret = -1; /* sorry */
|
||||
}
|
||||
|
||||
@@ -584,7 +590,7 @@ static int handle_commands(struct cfg_st *config, struct tun_st *tun, int fd)
|
||||
struct iovec iov[2];
|
||||
uint8_t cmd;
|
||||
struct msghdr hdr;
|
||||
int tunfd;
|
||||
struct tun_id_st tunid;
|
||||
union {
|
||||
struct cmd_auth_req_st auth;
|
||||
} cmd_data;
|
||||
@@ -612,12 +618,12 @@ static int handle_commands(struct cfg_st *config, struct tun_st *tun, int fd)
|
||||
|
||||
switch(cmd) {
|
||||
case AUTH_REQ:
|
||||
ret = handle_auth_req(config, tun, &cmd_data.auth, &tunfd);
|
||||
ret = handle_auth_req(config, tun, &cmd_data.auth, &tunid);
|
||||
if (ret == 0) {
|
||||
ret = send_auth_reply(fd, REP_AUTH_OK, tunfd);
|
||||
close(tunfd);
|
||||
ret = send_auth_reply(fd, REP_AUTH_OK, &tunid);
|
||||
close(tunid.fd);
|
||||
} else
|
||||
ret = send_auth_reply(fd, REP_AUTH_FAILED, -1);
|
||||
ret = send_auth_reply(fd, REP_AUTH_FAILED, NULL);
|
||||
|
||||
if (ret < 0) {
|
||||
syslog(LOG_ERR, "Could not send reply cmd.");
|
||||
|
||||
75
src/tun.c
75
src/tun.c
@@ -33,7 +33,7 @@
|
||||
#include <tun.h>
|
||||
#include <list.h>
|
||||
|
||||
static int set_network_info(const struct vpn_st *vinfo)
|
||||
static int set_network_info(const char* vname, const struct vpn_st *vinfo)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int fd, ret;
|
||||
@@ -43,30 +43,14 @@ static int set_network_info(const struct vpn_st *vinfo)
|
||||
return -1;
|
||||
|
||||
/* set netmask */
|
||||
if (vinfo->ipv4_netmask && vinfo->ipv4) {
|
||||
if (vinfo->ipv4) {
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", vinfo->name);
|
||||
|
||||
ret =
|
||||
inet_pton(AF_INET, vinfo->ipv4_netmask,
|
||||
&((struct sockaddr_in *) &ifr.ifr_addr)->
|
||||
sin_addr);
|
||||
if (ret != 1) {
|
||||
syslog(LOG_ERR, "%s: Error reading mask: %s\n",
|
||||
vinfo->name, vinfo->ipv4_netmask);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = ioctl(fd, SIOCSIFNETMASK, &ifr);
|
||||
if (ret != 0) {
|
||||
syslog(LOG_ERR, "%s: Error setting mask: %s\n",
|
||||
vinfo->name, vinfo->ipv4_netmask);
|
||||
}
|
||||
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", vname);
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", vinfo->name);
|
||||
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", vname);
|
||||
|
||||
ret =
|
||||
inet_pton(AF_INET, vinfo->ipv4,
|
||||
@@ -74,7 +58,7 @@ static int set_network_info(const struct vpn_st *vinfo)
|
||||
sin_addr);
|
||||
if (ret != 1) {
|
||||
syslog(LOG_ERR, "%s: Error reading IP: %s\n",
|
||||
vinfo->name, vinfo->ipv4_netmask);
|
||||
vname, vinfo->ipv4);
|
||||
goto fail;
|
||||
|
||||
}
|
||||
@@ -82,35 +66,14 @@ static int set_network_info(const struct vpn_st *vinfo)
|
||||
ret = ioctl(fd, SIOCSIFADDR, &ifr);
|
||||
if (ret != 0) {
|
||||
syslog(LOG_ERR, "%s: Error setting IP: %s\n",
|
||||
vinfo->name, vinfo->ipv4);
|
||||
vname, vinfo->ipv4);
|
||||
}
|
||||
}
|
||||
|
||||
if (vinfo->ipv6_netmask && vinfo->ipv6) {
|
||||
if (vinfo->ipv6) {
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_addr.sa_family = AF_INET6;
|
||||
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", vinfo->name);
|
||||
|
||||
ret =
|
||||
inet_pton(AF_INET6, vinfo->ipv6_netmask,
|
||||
&((struct sockaddr_in6 *) &ifr.ifr_addr)->
|
||||
sin6_addr);
|
||||
if (ret != 1) {
|
||||
syslog(LOG_ERR, "%s: Error reading mask: %s\n",
|
||||
vinfo->name, vinfo->ipv6_netmask);
|
||||
goto fail;
|
||||
|
||||
}
|
||||
|
||||
ret = ioctl(fd, SIOCSIFNETMASK, &ifr);
|
||||
if (ret != 0) {
|
||||
syslog(LOG_ERR, "%s: Error setting mask: %s\n",
|
||||
vinfo->name, vinfo->ipv6_netmask);
|
||||
}
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_addr.sa_family = AF_INET6;
|
||||
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", vinfo->name);
|
||||
snprintf(ifr.ifr_name, IFNAMSIZ, "%s", vname);
|
||||
|
||||
ret =
|
||||
inet_pton(AF_INET6, vinfo->ipv6,
|
||||
@@ -118,33 +81,31 @@ static int set_network_info(const struct vpn_st *vinfo)
|
||||
sin6_addr);
|
||||
if (ret != 1) {
|
||||
syslog(LOG_ERR, "%s: Error reading IP: %s\n",
|
||||
vinfo->name, vinfo->ipv6_netmask);
|
||||
vname, vinfo->ipv6);
|
||||
goto fail;
|
||||
|
||||
}
|
||||
|
||||
ret = ioctl(fd, SIOCSIFADDR, &ifr);
|
||||
if (ret != 0) {
|
||||
syslog(LOG_ERR, "%s: Error setting IP: %s\n",
|
||||
vinfo->name, vinfo->ipv6);
|
||||
vname, vinfo->ipv6);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int open_tun(struct cfg_st *config, struct tun_st* tun)
|
||||
int open_tun(struct cfg_st *config, struct tun_st* tun, struct tun_id_st *id)
|
||||
{
|
||||
int tunfd, ret, e;
|
||||
struct ifreq ifr;
|
||||
unsigned int t;
|
||||
|
||||
/* XXX obtain random IPs + tun nr */
|
||||
|
||||
#warning fix
|
||||
tunfd = open("/dev/net/tun", O_RDWR);
|
||||
if (tunfd < 0) {
|
||||
int e = errno;
|
||||
@@ -155,8 +116,10 @@ int open_tun(struct cfg_st *config, struct tun_st* tun)
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
|
||||
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name),
|
||||
config->network.name, 0);
|
||||
|
||||
snprintf(id->name, sizeof(id->name), "%s%u", config->network.name, 0);
|
||||
memcpy(ifr.ifr_name, id->name, sizeof(ifr.ifr_name));
|
||||
|
||||
if (ioctl(tunfd, TUNSETIFF, (void *) &ifr) < 0) {
|
||||
e = errno;
|
||||
syslog(LOG_ERR, "TUNSETIFF: %s\n", strerror(e));
|
||||
@@ -186,12 +149,14 @@ int open_tun(struct cfg_st *config, struct tun_st* tun)
|
||||
}
|
||||
|
||||
/* set IP/mask */
|
||||
ret = set_network_info(&config->network);
|
||||
ret = set_network_info(id->name, &config->network);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
id->fd = tunfd;
|
||||
|
||||
return tunfd;
|
||||
return 0;
|
||||
fail:
|
||||
close(tunfd);
|
||||
return -1;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <vpn.h>
|
||||
|
||||
int open_tun(struct cfg_st *config, struct tun_st* tun);
|
||||
|
||||
int open_tun(struct cfg_st *config, struct tun_st* tun, struct tun_id_st *id);
|
||||
|
||||
#endif
|
||||
|
||||
41
src/vpn.c
41
src/vpn.c
@@ -99,7 +99,7 @@ int url_cb(http_parser* parser, const char *at, size_t length)
|
||||
memcpy(req->url, at, length);
|
||||
req->url[length] = 0;
|
||||
|
||||
fprintf(stderr, "request %s %s\n", http_method_str(parser->method), req->url);
|
||||
//fprintf(stderr, "request %s %s\n", http_method_str(parser->method), req->url);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -239,7 +239,7 @@ void vpn_server(struct cfg_st *config, struct tls_st *creds, int cmdfd, int fd)
|
||||
server->session = session;
|
||||
server->parser = &parser;
|
||||
server->cmdfd = cmdfd;
|
||||
server->tunfd = -1;
|
||||
server->tunid.fd = -1;
|
||||
|
||||
restart:
|
||||
http_parser_init(&parser, HTTP_REQUEST);
|
||||
@@ -308,7 +308,7 @@ finish:
|
||||
tls_close(session);
|
||||
}
|
||||
|
||||
static int get_remote_ip(int fd, int family,
|
||||
static int get_remote_ip(int fd, int family,
|
||||
struct vpn_st* vinfo, char** buffer, size_t* buffer_size)
|
||||
{
|
||||
unsigned char *ptr;
|
||||
@@ -366,8 +366,8 @@ fail:
|
||||
*
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
static int get_rt_vpn_info(server_st * server, struct vpn_st* vinfo,
|
||||
char* buffer, size_t buffer_size)
|
||||
static int get_rt_vpn_info(server_st * server,
|
||||
struct vpn_st* vinfo, char* buffer, size_t buffer_size)
|
||||
{
|
||||
unsigned int i;
|
||||
int fd, ret;
|
||||
@@ -375,6 +375,7 @@ struct ifreq ifr;
|
||||
const char* p;
|
||||
|
||||
memset(vinfo, 0, sizeof(*vinfo));
|
||||
vinfo->name = server->tunid.name;
|
||||
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (fd == -1)
|
||||
@@ -393,7 +394,6 @@ const char* p;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
vinfo->name = server->config->network.name;
|
||||
vinfo->ipv4_dns = server->config->network.ipv4_dns;
|
||||
vinfo->ipv6_dns = server->config->network.ipv6_dns;
|
||||
vinfo->routes_size = server->config->network.routes_size;
|
||||
@@ -440,7 +440,7 @@ unsigned int buffer_size;
|
||||
tls_fatal_close(server->session, GNUTLS_A_ACCESS_DENIED);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
ret = retrieve_cookie(server, req->cookie, sizeof(req->cookie), &sc);
|
||||
if (ret < 0) {
|
||||
oclog(server, LOG_INFO, "Connect request without authentication");
|
||||
@@ -458,7 +458,8 @@ unsigned int buffer_size;
|
||||
|
||||
if (server->config->network.name == NULL) {
|
||||
oclog(server, LOG_ERR, "No networks are configured. Rejecting client.");
|
||||
tls_puts(server->session, "HTTP/1.1 503 Service Unavailable\r\n\r\n");
|
||||
tls_puts(server->session, "HTTP/1.1 503 Service Unavailable\r\n");
|
||||
tls_puts(server->session, "X-Reason: Server configuration error\r\n\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -487,16 +488,22 @@ unsigned int buffer_size;
|
||||
tls_printf(server->session, "X-CSTP-MTU: %u\r\n", vinfo.mtu);
|
||||
tls_puts(server->session, "X-CSTP-DPD: 60\r\n");
|
||||
|
||||
if (vinfo.ipv4_netmask && vinfo.ipv4) {
|
||||
if (vinfo.ipv4) {
|
||||
oclog(server, LOG_DEBUG, "sending IPv4 %s", vinfo.ipv4);
|
||||
tls_printf(server->session, "X-CSTP-Address: %s\r\n", vinfo.ipv4);
|
||||
tls_printf(server->session, "X-CSTP-Netmask: %s\r\n", vinfo.ipv4_netmask);
|
||||
|
||||
if (vinfo.ipv4_netmask)
|
||||
tls_printf(server->session, "X-CSTP-Netmask: %s\r\n", vinfo.ipv4_netmask);
|
||||
if (vinfo.ipv4_dns)
|
||||
tls_printf(server->session, "X-CSTP-DNS: %s\r\n", vinfo.ipv4_dns);
|
||||
}
|
||||
|
||||
if (vinfo.ipv6_netmask && vinfo.ipv6) {
|
||||
tls_printf(server->session, "X-CSTP-Netmask: %s\r\n", vinfo.ipv6_netmask);
|
||||
if (vinfo.ipv6) {
|
||||
oclog(server, LOG_DEBUG, "sending IPv6 %s", vinfo.ipv6);
|
||||
tls_printf(server->session, "X-CSTP-Address: %s\r\n", vinfo.ipv6);
|
||||
|
||||
if (vinfo.ipv6_netmask)
|
||||
tls_printf(server->session, "X-CSTP-Netmask: %s\r\n", vinfo.ipv6_netmask);
|
||||
if (vinfo.ipv6_dns)
|
||||
tls_printf(server->session, "X-CSTP-DNS: %s\r\n", vinfo.ipv6_dns);
|
||||
}
|
||||
@@ -519,9 +526,9 @@ unsigned int buffer_size;
|
||||
|
||||
FD_SET(tls_fd, &rfds);
|
||||
FD_SET(server->cmdfd, &rfds);
|
||||
FD_SET(server->tunfd, &rfds);
|
||||
FD_SET(server->tunid.fd, &rfds);
|
||||
max = MAX(server->cmdfd,tls_fd);
|
||||
max = MAX(max,server->tunfd);
|
||||
max = MAX(max,server->tunid.fd);
|
||||
|
||||
if (gnutls_record_check_pending(server->session) == 0) {
|
||||
ret = select(max + 1, &rfds, NULL, NULL, NULL);
|
||||
@@ -529,8 +536,8 @@ unsigned int buffer_size;
|
||||
break;
|
||||
}
|
||||
|
||||
if (FD_ISSET(server->tunfd, &rfds)) {
|
||||
int l = read(server->tunfd, buf + 8, sizeof(buf) - 8);
|
||||
if (FD_ISSET(server->tunid.fd, &rfds)) {
|
||||
int l = read(server->tunid.fd, buf + 8, sizeof(buf) - 8);
|
||||
buf[0] = 'S';
|
||||
buf[1] = 'T';
|
||||
buf[2] = 'F';
|
||||
@@ -581,7 +588,7 @@ unsigned int buffer_size;
|
||||
break;
|
||||
|
||||
case AC_PKT_DATA:
|
||||
write(server->tunfd, buf + 8, pktlen);
|
||||
write(server->tunid.fd, buf + 8, pktlen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
13
src/vpn.h
13
src/vpn.h
@@ -8,6 +8,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#define AC_PKT_DATA 0 /* Uncompressed data */
|
||||
#define AC_PKT_DPD_OUT 3 /* Dead Peer Detection */
|
||||
@@ -73,10 +74,15 @@ struct tls_st {
|
||||
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;
|
||||
int tunfd;
|
||||
http_parser *parser;
|
||||
struct cfg_st *config;
|
||||
|
||||
@@ -120,6 +126,11 @@ struct cmd_auth_req_st {
|
||||
char cert_user[MAX_USERNAME_SIZE];
|
||||
};
|
||||
|
||||
struct cmd_auth_resp_st {
|
||||
uint8_t reply;
|
||||
char vname[IFNAMSIZ]; /* interface name */
|
||||
};
|
||||
|
||||
void vpn_server(struct cfg_st *config, struct tls_st *creds, int cmd_fd,
|
||||
int fd);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user