Separated logging for worker and main and oc_syslog() respects log-level

This makes oc_syslog respect the configured log-level. This also introduces
a clear separation of the logging function between the two processes.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
This commit is contained in:
Nikos Mavrogiannopoulos
2023-12-16 06:13:08 +01:00
parent f0067ae0ea
commit e44cc6fd78
19 changed files with 703 additions and 469 deletions

View File

@@ -34,12 +34,12 @@ endif
CORE_SOURCES = $(HTTP_PARSER_SOURCES) \
common/hmac.c common/hmac.h common/snapshot.c common/snapshot.h \
common-config.h config.c config-kkdcp.c config-ports.c defs.h gettime.h \
icmp-ping.c icmp-ping.h inih/ini.c inih/ini.h ip-lease.c ip-lease.h \
ip-util.c ip-util.h isolate.h isolate.c main.h main-ctl.h \
inih/ini.c inih/ini.h \
ip-util.c ip-util.h main.h main-ctl.h \
script-list.h setproctitle.c setproctitle.h str.c str.h subconfig.c \
sup-config/file.c sup-config/file.h sup-config/radius.c \
sup-config/radius.h tlslib.c tlslib.h tun.c tun.h valid-hostname.c \
vasprintf.c vasprintf.h vhost.h vpn.h namespace.h log.c log.h
sup-config/radius.h tlslib.c tlslib.h valid-hostname.c \
vasprintf.c vasprintf.h vhost.h vpn.h namespace.h worker-log.c
if ENABLE_COMPRESSION
CORE_SOURCES += lzs.c lzs.h
@@ -66,7 +66,9 @@ ocserv_SOURCES = $(CORE_SOURCES) $(AUTH_SOURCES) $(ACCT_SOURCES) \
proc-search.h route-add.c route-add.h sec-mod.c sec-mod.h sec-mod-acct.h \
sec-mod-auth.c sec-mod-auth.h sec-mod-cookies.c sec-mod-db.c \
sec-mod-resume.c sec-mod-resume.h sec-mod-sup-config.c sec-mod-sup-config.h \
common/sockdiag.h common/sockdiag.c namespace.c
common/sockdiag.h common/sockdiag.c namespace.c main-log.c \
icmp-ping.c icmp-ping.h ip-lease.c ip-lease.h tun.c tun.h \
main-limits.c main-limits.h
ocserv_LDADD = $(CORE_LDADD)
@@ -75,8 +77,8 @@ ocserv_worker_SOURCES = $(CORE_SOURCES) \
html.c html.h http-heads.h worker.c worker.h worker-auth.c \
worker-bandwidth.c worker-bandwidth.h worker-http.c worker-http-handlers.c \
worker-kkdcp.c worker-misc.c worker-privs.c worker-proxyproto.c \
worker-resume.c worker-vpn.c worker-svc.c
worker-resume.c worker-vpn.c worker-svc.c worker-tun.c isolate.c \
isolate.h
ocserv_worker_LDADD = $(CORE_LDADD)
noinst_LIBRARIES = libipc.a
@@ -154,7 +156,8 @@ ocpasswd_ocpasswd_LDADD += $(LIBGNUTLS_LIBS) $(LIBCRYPT) $(CODE_COVERAGE_LDFLAGS
# Files common to ocserv and occtl.
libcommon_a_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/common
libcommon_a_SOURCES=common/common.c common/common.h common/system.c common/system.h \
common/cloexec.c common/cloexec.h common/base64-helper.c common/base64-helper.h
common/cloexec.c common/cloexec.h common/base64-helper.c common/base64-helper.h \
log.c log.h
libcommon_a_LIBS = $(NEEDED_LIBPROTOBUF_LIBS)
noinst_LIBRARIES += libcommon.a

View File

@@ -830,6 +830,7 @@ static int cfg_ini_handler(void *_ctx, const char *section, const char *name, co
READ_NUMERIC(vhost->perm_config.sec_mod_scale);
} else if (strcmp(name, "log-level") == 0) {
READ_NUMERIC(vhost->perm_config.log_level);
global_log_prio = vhost->perm_config.log_level;
} else {
stage1_found = 0;
}
@@ -1648,6 +1649,7 @@ int cmd_parser (void *pool, int argc, char **argv, struct list_head *head, bool
break;
case 'd':
vhost->perm_config.log_level = atoi(optarg);
global_log_prio = vhost->perm_config.log_level;
debug_asked = 1;
break;
case 't':

View File

@@ -98,7 +98,7 @@ int ip_route_sanity_check(void *pool, char **_route)
p = strchr(p, '/');
if (p == NULL) {
fprintf(stderr, "route '%s' in wrong format, use xxx.xxx.xxx.xxx/xxx.xxx.xxx.xxx\n", route);
oc_syslog(LOG_ERR, "route '%s' in wrong format, use xxx.xxx.xxx.xxx/xxx.xxx.xxx.xxx\n", route);
return -1;
}
slash_ptr = p;
@@ -113,7 +113,7 @@ int ip_route_sanity_check(void *pool, char **_route)
pstr = ipv4_prefix_to_strmask(pool, prefix);
if (pstr == NULL) {
fprintf(stderr, "cannot figure format of route '%s'\n", route);
oc_syslog(LOG_ERR, "cannot figure format of route '%s'\n", route);
return -1;
}
@@ -121,7 +121,7 @@ int ip_route_sanity_check(void *pool, char **_route)
n = talloc_asprintf(pool, "%s/%s", route, pstr);
if (n == NULL) {
fprintf(stderr, "memory error\n");
oc_syslog(LOG_ERR, "memory error\n");
return -1;
}
*_route = n;

View File

@@ -21,105 +21,36 @@
#include <fcntl.h>
#include <sys/resource.h>
#include <grp.h>
#include <main.h>
#include <limits.h>
void init_fd_limits_default(main_server_st * s)
/* Adjusts the file descriptor limits for the worker processes
*/
void set_worker_fd_limits(struct worker_st *ws)
{
#ifdef RLIMIT_NOFILE
int ret = getrlimit(RLIMIT_NOFILE, &s->fd_limits_default_set);
if (ret < 0) {
fprintf(stderr, "error in getrlimit: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
#endif
}
/* (Maximum clients) + (small buffer) + (sec mod fds)
* The (small buffer) is to allow unknown fds used by backends (e.g.,
* gnutls) as well as to allow running up to that many scripts (due to dup2)
* when close to the maximum limit.
*/
#define MAX_FD_LIMIT(clients) (clients + 128 + s->sec_mod_instance_count * 2)
/* Adjusts the file descriptor limits for the main or worker processes
*/
void update_fd_limits(main_server_st * s, unsigned main)
{
#ifdef RLIMIT_NOFILE
struct rlimit new_set;
unsigned max;
struct rlimit def_set;
int ret;
if (main) {
if (GETCONFIG(s)->max_clients > 0)
max = MAX_FD_LIMIT(GETCONFIG(s)->max_clients);
else
// If the admin doesn't specify max_clients,
// then we are limiting it to around 8K.
max = MAX_FD_LIMIT(8 * 1024);
ret = getrlimit(RLIMIT_NOFILE, &def_set);
if (ret < 0) {
int e = errno;
oclog(ws, LOG_ERR,
"error in getrlimit: %s\n", strerror(e));
exit(EXIT_FAILURE);
}
if (max > s->fd_limits_default_set.rlim_cur) {
new_set.rlim_cur = max;
new_set.rlim_max = s->fd_limits_default_set.rlim_max;
ret = setrlimit(RLIMIT_NOFILE, &new_set);
if (ret < 0) {
fprintf(stderr,
"error in setrlimit(%u): %s (cur: %u)\n",
max, strerror(errno),
(unsigned)s->fd_limits_default_set.
rlim_cur);
}
}
} else {
/* set limits for worker processes */
ret = setrlimit(RLIMIT_NOFILE, &s->fd_limits_default_set);
if (ret < 0) {
mslog(s, NULL, LOG_INFO,
"cannot update file limit(%u): %s\n",
(unsigned)s->fd_limits_default_set.rlim_cur,
strerror(errno));
}
ret = setrlimit(RLIMIT_NOFILE, &def_set);
if (ret < 0) {
oclog(ws, LOG_INFO,
"cannot update file limit(%u): %s\n",
(unsigned)def_set.rlim_cur,
strerror(errno));
}
#endif
}
void set_self_oom_score_adj(main_server_st * s)
{
#ifdef __linux__
static const char proc_self_oom_adj_score_path[] = "/proc/self/oom_score_adj";
static const char oom_adj_score_value[] = "1000";
size_t written = 0;
int fd;
fd = open(proc_self_oom_adj_score_path, O_WRONLY,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (fd == -1) {
int e = errno;
mslog(s, NULL, LOG_ERR, "cannot open %s: %s",
proc_self_oom_adj_score_path, strerror(e));
goto cleanup;
}
written = write(fd, oom_adj_score_value, sizeof(oom_adj_score_value));
if (written != sizeof(oom_adj_score_value)) {
int e = errno;
mslog(s, NULL, LOG_ERR, "cannot write %s: %s",
proc_self_oom_adj_score_path, strerror(e));
goto cleanup;
}
cleanup:
if (fd >= 0) {
close(fd);
}
#endif
}
void drop_privileges(main_server_st * s)
void drop_privileges(struct worker_st *ws, main_server_st *s)
{
int ret, e;
struct rlimit rl;
@@ -128,7 +59,7 @@ void drop_privileges(main_server_st * s)
ret = chdir(GETPCONFIG(s)->chroot_dir);
if (ret != 0) {
e = errno;
mslog(s, NULL, LOG_ERR, "cannot chdir to %s: %s",
oclog(ws, LOG_ERR, "cannot chdir to %s: %s",
GETPCONFIG(s)->chroot_dir, strerror(e));
exit(EXIT_FAILURE);
}
@@ -136,7 +67,7 @@ void drop_privileges(main_server_st * s)
ret = chroot(GETPCONFIG(s)->chroot_dir);
if (ret != 0) {
e = errno;
mslog(s, NULL, LOG_ERR, "cannot chroot to %s: %s",
oclog(ws, LOG_ERR, "cannot chroot to %s: %s",
GETPCONFIG(s)->chroot_dir, strerror(e));
exit(EXIT_FAILURE);
}
@@ -146,7 +77,7 @@ void drop_privileges(main_server_st * s)
ret = setgid(GETPCONFIG(s)->gid);
if (ret < 0) {
e = errno;
mslog(s, NULL, LOG_ERR, "cannot set gid to %d: %s\n",
oclog(ws, LOG_ERR, "cannot set gid to %d: %s\n",
(int)GETPCONFIG(s)->gid, strerror(e));
exit(EXIT_FAILURE);
}
@@ -154,7 +85,7 @@ void drop_privileges(main_server_st * s)
ret = setgroups(1, &GETPCONFIG(s)->gid);
if (ret < 0) {
e = errno;
mslog(s, NULL, LOG_ERR, "cannot set groups to %d: %s\n",
oclog(ws, LOG_ERR, "cannot set groups to %d: %s\n",
(int)GETPCONFIG(s)->gid, strerror(e));
exit(EXIT_FAILURE);
}
@@ -164,21 +95,19 @@ void drop_privileges(main_server_st * s)
ret = setuid(GETPCONFIG(s)->uid);
if (ret < 0) {
e = errno;
mslog(s, NULL, LOG_ERR, "cannot set uid to %d: %s\n",
oclog(ws, LOG_ERR, "cannot set uid to %d: %s\n",
(int)GETPCONFIG(s)->uid, strerror(e));
exit(EXIT_FAILURE);
}
}
update_fd_limits(s, 0);
rl.rlim_cur = 0;
rl.rlim_max = 0;
ret = setrlimit(RLIMIT_NPROC, &rl);
if (ret < 0) {
e = errno;
mslog(s, NULL, LOG_ERR, "cannot enforce NPROC limit: %s\n",
oclog(ws, LOG_ERR, "cannot enforce NPROC limit: %s\n",
strerror(e));
}
}

View File

@@ -19,15 +19,8 @@
#ifndef OC_ISOLATE_H
# define OC_ISOLATE_H
void set_worker_fd_limits(struct worker_st *);
void init_fd_limits_default(struct main_server_st * s);
/* Adjusts the file descriptor limits for the main or worker processes
*/
void update_fd_limits(struct main_server_st * s, unsigned main);
void set_self_oom_score_adj(struct main_server_st * s);
void drop_privileges(struct main_server_st * s);
void drop_privileges(struct worker_st *ws, main_server_st *s);
#endif

235
src/log.c
View File

@@ -31,245 +31,22 @@
#include "sec-mod.h"
#include "log.h"
/* Returns zero when the given priority is not sufficient
* for logging. Updates the priority with */
static unsigned check_priority(int oc_priority, int log_prio, int *syslog_prio)
{
switch (oc_priority) {
case LOG_ERR:
case LOG_WARNING:
case LOG_NOTICE:
if (syslog_prio)
*syslog_prio = oc_priority;
break;
case LOG_DEBUG:
if (log_prio < OCLOG_DEBUG)
return 0;
if (syslog_prio)
*syslog_prio = oc_priority;
break;
case LOG_INFO:
if (log_prio < OCLOG_INFO)
return 0;
/* This global variable is used by oc_syslog() */
int global_log_prio = DEFAULT_LOG_LEVEL;
if (syslog_prio)
*syslog_prio = oc_priority;
break;
case LOG_HTTP_DEBUG:
if (log_prio < OCLOG_HTTP)
return 0;
if (syslog_prio)
*syslog_prio = LOG_DEBUG;
break;
case LOG_TRANSFER_DEBUG:
if (log_prio < OCLOG_TRANSFERRED)
return 0;
if (syslog_prio)
*syslog_prio = LOG_DEBUG;
break;
case LOG_SENSITIVE:
if (log_prio < OCLOG_SENSITIVE)
return 0;
if (syslog_prio)
*syslog_prio = LOG_DEBUG;
break;
default:
syslog(LOG_DEBUG, "unknown log level %d", oc_priority);
if (syslog_prio)
*syslog_prio = LOG_DEBUG;
}
return 1;
}
void __attribute__ ((format(printf, 3, 4)))
_oclog(const worker_st * ws, int priority, const char *fmt, ...)
{
char buf[512];
char name[MAX_USERNAME_SIZE+MAX_HOSTNAME_SIZE+3];
const char* ip;
va_list args;
int log_prio;
unsigned have_vhosts;
int syslog_prio;
if (ws->vhost)
log_prio = WSPCONFIG(ws)->log_level;
else
log_prio = GETPCONFIG(ws)->log_level;
if (!check_priority(priority, log_prio, &syslog_prio))
return;
ip = ws->remote_ip_str;
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
have_vhosts = HAVE_VHOSTS(ws);
if (have_vhosts && ws->username[0] != 0) {
snprintf(name, sizeof(name), "[%s%s]", PREFIX_VHOST(ws->vhost), ws->username);
} else if (have_vhosts && ws->username[0] == 0 && ws->vhost && ws->vhost->name) {
snprintf(name, sizeof(name), "[vhost:%s]", VHOSTNAME(ws->vhost));
} else if (ws->username[0] != 0) {
snprintf(name, sizeof(name), "[%s]", ws->username);
} else
name[0] = 0;
oc_syslog(syslog_prio, "worker%s: %s %s", name, ip?ip:"[unknown]", buf);
}
/* proc is optional */
void __attribute__ ((format(printf, 4, 5)))
_mslog(const main_server_st * s, const struct proc_st* proc,
int priority, const char *fmt, ...)
{
char buf[512];
char ipbuf[128];
char name[MAX_USERNAME_SIZE+MAX_HOSTNAME_SIZE+3];
const char* ip = NULL;
va_list args;
int log_prio = DEFAULT_LOG_LEVEL;
unsigned have_vhosts;
int syslog_prio;
if (s)
log_prio = GETPCONFIG(s)->log_level;
if (!check_priority(priority, log_prio, &syslog_prio))
return;
if (proc) {
ip = human_addr((void*)&proc->remote_addr, proc->remote_addr_len,
ipbuf, sizeof(ipbuf));
} else {
ip = "";
}
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
have_vhosts = s?HAVE_VHOSTS(s):0;
if (have_vhosts && proc && proc->username[0] != 0) {
snprintf(name, sizeof(name), "[%s%s]", PREFIX_VHOST(proc->vhost), proc->username);
} else if (have_vhosts && proc && proc->username[0] == 0 && proc->vhost && proc->vhost->name) {
snprintf(name, sizeof(name), "[vhost:%s]", VHOSTNAME(proc->vhost));
} else if (proc && proc->username[0] != 0) {
snprintf(name, sizeof(name), "[%s]", proc->username);
} else
name[0] = 0;
oc_syslog(syslog_prio, "main%s:%s %s", name, ip?ip:"[unknown]", buf);
}
void mslog_hex(const main_server_st * s, const struct proc_st* proc,
int priority, const char *prefix, uint8_t* bin, unsigned bin_size, unsigned b64)
{
char buf[512];
int ret;
size_t buf_size;
gnutls_datum_t data = {bin, bin_size};
int log_prio = DEFAULT_LOG_LEVEL;
if (s)
log_prio = GETPCONFIG(s)->log_level;
if (!check_priority(priority, log_prio, NULL))
return;
if (b64) {
oc_base64_encode((char*)bin, bin_size, (char*)buf, sizeof(buf));
} else {
buf_size = sizeof(buf);
ret = gnutls_hex_encode(&data, buf, &buf_size);
if (ret < 0)
return;
}
_mslog(s, proc, priority, "%s %s", prefix, buf);
}
void oclog_hex(const worker_st* ws, int priority,
const char *prefix, uint8_t* bin, unsigned bin_size, unsigned b64)
{
char buf[512];
int ret;
size_t buf_size;
gnutls_datum_t data = {bin, bin_size};
int log_prio;
if (ws->vhost)
log_prio = WSPCONFIG(ws)->log_level;
else
log_prio = GETPCONFIG(ws)->log_level;
if (!check_priority(priority, log_prio, NULL))
return;
if (b64) {
oc_base64_encode((char*)bin, bin_size, (char*)buf, sizeof(buf));
} else {
buf_size = sizeof(buf);
ret = gnutls_hex_encode(&data, buf, &buf_size);
if (ret < 0)
return;
}
_oclog(ws, priority, "%s %s", prefix, buf);
}
void seclog_hex(const struct sec_mod_st* sec, int priority,
const char *prefix, uint8_t* bin, unsigned bin_size, unsigned b64)
{
char buf[512];
int ret;
size_t buf_size;
gnutls_datum_t data = {bin, bin_size};
int log_prio;
log_prio = GETPCONFIG(sec)->log_level;
if (!check_priority(priority, log_prio, NULL))
return;
if (b64) {
oc_base64_encode((char*)bin, bin_size, (char*)buf, sizeof(buf));
} else {
buf_size = sizeof(buf);
ret = gnutls_hex_encode(&data, buf, &buf_size);
if (ret < 0)
return;
}
seclog(sec, priority, "%s %s", prefix, buf);
}
void __attribute__ ((format(printf, 3, 4)))
_seclog(const sec_mod_st* sec, int priority, const char *fmt, ...)
void __attribute__ ((format(printf, 2, 3)))
oc_syslog(int priority, const char *fmt, ...)
{
char buf[512];
va_list args;
int log_prio = DEFAULT_LOG_LEVEL;
int syslog_prio;
if (sec)
log_prio = GETPCONFIG(sec)->log_level;
if (!check_priority(priority, log_prio, &syslog_prio))
if (!log_check_priority(priority, global_log_prio, &syslog_prio))
return;
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
oc_syslog(syslog_prio, "sec-mod: %s", buf);
_oc_syslog(syslog_prio, "%s", buf);
}

View File

@@ -24,30 +24,41 @@
#include <stdint.h>
#include <stdio.h>
#include <syslog.h>
#include "defs.h"
extern int syslog_open;
extern int global_log_prio;
#ifdef __GNUC__
# define oc_syslog(prio, fmt, ...) do { \
if (syslog_open) { \
syslog(prio, "sec-mod: "fmt, ##__VA_ARGS__); \
} else { \
fprintf(stderr, "sec-mod: "fmt, ##__VA_ARGS__); \
}} while(0)
#else
# define oc_syslog(prio, ...) do { \
/* For logging in the main process or sec-mod use the following:
* mslog(const struct main_server_st * s, const struct proc_st* proc,
* int priority, const char *fmt, ...);
* seclog(const struct sec_mod_st* sec, int priority, const char *fmt, ...);
* int priority, const char *fmt, ...);
*
* For logging in the worker process:
* oclog(const struct worker_st * server, int priority, const char *fmt, ...);
*
* Each ensures that the log gets the necessary information to distinguish
* between sessions and users. On low-level functions or on startup use:
* oc_syslog(int priority, const char *fmt, ...);
*
* All the logging functions respect the configured log-level and
* send the logging to stderr or syslog, as requested.
*/
#define _oc_syslog(prio, ...) do { \
if (syslog_open) { \
syslog(prio, __VA_ARGS__); \
} else { \
fprintf(stderr, __VA_ARGS__); \
}} while(0)
#endif
#ifdef UNDER_TEST
/* for testing */
# define mslog(...)
# define oclog(...)
# define seclog(...)
# define oc_syslog _oc_syslog
#else
@@ -67,6 +78,10 @@ void __attribute__ ((format(printf, 3, 4)))
void __attribute__ ((format(printf, 3, 4)))
_seclog(const struct sec_mod_st* sec, int priority, const char *fmt, ...);
void __attribute__ ((format(printf, 2, 3)))
oc_syslog(int priority, const char *fmt, ...);
# ifdef __GNUC__
# define mslog(s, proc, prio, fmt, ...) \
(prio==LOG_ERR)?_mslog(s, proc, prio, "%s:%d: "fmt, __FILE__, __LINE__, ##__VA_ARGS__): \
@@ -96,4 +111,61 @@ void seclog_hex(const struct sec_mod_st* sec, int priority,
#endif
/* Returns zero when the given priority is not sufficient
* for logging. Updates the priority with */
inline static
unsigned log_check_priority(int oc_priority, int log_prio, int *syslog_prio)
{
switch (oc_priority) {
case LOG_ERR:
case LOG_WARNING:
case LOG_NOTICE:
if (syslog_prio)
*syslog_prio = oc_priority;
break;
case LOG_DEBUG:
if (log_prio < OCLOG_DEBUG)
return 0;
if (syslog_prio)
*syslog_prio = oc_priority;
break;
case LOG_INFO:
if (log_prio < OCLOG_INFO)
return 0;
if (syslog_prio)
*syslog_prio = oc_priority;
break;
case LOG_HTTP_DEBUG:
if (log_prio < OCLOG_HTTP)
return 0;
if (syslog_prio)
*syslog_prio = LOG_DEBUG;
break;
case LOG_TRANSFER_DEBUG:
if (log_prio < OCLOG_TRANSFERRED)
return 0;
if (syslog_prio)
*syslog_prio = LOG_DEBUG;
break;
case LOG_SENSITIVE:
if (log_prio < OCLOG_SENSITIVE)
return 0;
if (syslog_prio)
*syslog_prio = LOG_DEBUG;
break;
default:
syslog(LOG_DEBUG, "unknown log level %d", oc_priority);
if (syslog_prio)
*syslog_prio = LOG_DEBUG;
}
return 1;
}
#endif /* OC_LOG_H */

View File

@@ -71,7 +71,7 @@ void *main_ban_db_init(main_server_st *s)
{
struct htable *db = talloc(s, struct htable);
if (db == NULL) {
fprintf(stderr, "error initializing ban DB\n");
oc_syslog(LOG_ERR, "error initializing ban DB\n");
exit(EXIT_FAILURE);
}
@@ -344,7 +344,7 @@ int if_address_init(main_server_st *s)
if (getifaddrs(&ifaddr) < 0) {
int err = errno;
fprintf(stderr, "Failed to read local if address list: %s", strerror(err));
oc_syslog(LOG_ERR, "Failed to read local if address list: %s", strerror(err));
goto cleanup;
}
@@ -357,7 +357,7 @@ int if_address_init(main_server_st *s)
local_if_addresses = talloc_array(s, if_address_st, count);
if (local_if_addresses == NULL) {
fprintf(stderr, "Failed to allocate");
oc_syslog(LOG_ERR, "Failed to allocate");
goto cleanup;
}

108
src/main-limits.c Normal file
View File

@@ -0,0 +1,108 @@
/*
* Copyright (C) 2013-2018 Nikos Mavrogiannopoulos
* Copyright (C) 2015-2016 Red Hat, Inc.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <fcntl.h>
#include <sys/resource.h>
#include <grp.h>
#include <main.h>
#include <limits.h>
void init_fd_limits_default(main_server_st * s)
{
#ifdef RLIMIT_NOFILE
int ret = getrlimit(RLIMIT_NOFILE, &s->fd_limits_default_set);
if (ret < 0) {
oc_syslog(LOG_ERR, "error in getrlimit: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
#endif
}
/* (Maximum clients) + (small buffer) + (sec mod fds)
* The (small buffer) is to allow unknown fds used by backends (e.g.,
* gnutls) as well as to allow running up to that many scripts (due to dup2)
* when close to the maximum limit.
*/
#define MAX_FD_LIMIT(clients) (clients + 128 + s->sec_mod_instance_count * 2)
/* Adjusts the file descriptor limits for the main or worker processes
*/
void set_main_fd_limits(main_server_st * s)
{
#ifdef RLIMIT_NOFILE
struct rlimit new_set;
unsigned max;
int ret;
if (GETCONFIG(s)->max_clients > 0)
max = MAX_FD_LIMIT(GETCONFIG(s)->max_clients);
else
// If the admin doesn't specify max_clients,
// then we are limiting it to around 8K.
max = MAX_FD_LIMIT(8 * 1024);
if (max > s->fd_limits_default_set.rlim_cur) {
new_set.rlim_cur = max;
new_set.rlim_max = s->fd_limits_default_set.rlim_max;
ret = setrlimit(RLIMIT_NOFILE, &new_set);
if (ret < 0) {
fprintf(stderr,
"error in setrlimit(%u): %s (cur: %u)\n",
max, strerror(errno),
(unsigned)s->fd_limits_default_set.
rlim_cur);
}
}
#endif
}
void set_self_oom_score_adj(main_server_st * s)
{
#ifdef __linux__
static const char proc_self_oom_adj_score_path[] = "/proc/self/oom_score_adj";
static const char oom_adj_score_value[] = "1000";
size_t written = 0;
int fd;
fd = open(proc_self_oom_adj_score_path, O_WRONLY,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (fd == -1) {
int e = errno;
mslog(s, NULL, LOG_ERR, "cannot open %s: %s",
proc_self_oom_adj_score_path, strerror(e));
goto cleanup;
}
written = write(fd, oom_adj_score_value, sizeof(oom_adj_score_value));
if (written != sizeof(oom_adj_score_value)) {
int e = errno;
mslog(s, NULL, LOG_ERR, "cannot write %s: %s",
proc_self_oom_adj_score_path, strerror(e));
goto cleanup;
}
cleanup:
if (fd >= 0) {
close(fd);
}
#endif
}

31
src/main-limits.h Normal file
View File

@@ -0,0 +1,31 @@
/*
* Copyright (C) 2013-2018 Nikos Mavrogiannopoulos
* Copyright (C) 2015-2016 Red Hat, Inc.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef MAIN_LIMITS_H
# define MAIN_LIMITS_H
void init_fd_limits_default(struct main_server_st * s);
/* Adjusts the file descriptor limits for the main or worker processes
*/
void set_main_fd_limits(struct main_server_st * s);
void set_self_oom_score_adj(struct main_server_st * s);
#endif

151
src/main-log.c Normal file
View File

@@ -0,0 +1,151 @@
/*
* Copyright (C) 2013-2023 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, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <syslog.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <arpa/inet.h>
#include <base64-helper.h>
#include <worker.h>
#include <main.h>
#include "sec-mod.h"
#include "log.h"
/* proc is optional */
void __attribute__ ((format(printf, 4, 5)))
_mslog(const main_server_st * s, const struct proc_st* proc,
int priority, const char *fmt, ...)
{
char buf[512];
char ipbuf[128];
char name[MAX_USERNAME_SIZE+MAX_HOSTNAME_SIZE+3];
const char* ip = NULL;
va_list args;
int log_prio = DEFAULT_LOG_LEVEL;
unsigned have_vhosts;
int syslog_prio;
if (s)
log_prio = GETPCONFIG(s)->log_level;
if (!log_check_priority(priority, log_prio, &syslog_prio))
return;
if (proc) {
ip = human_addr((void*)&proc->remote_addr, proc->remote_addr_len,
ipbuf, sizeof(ipbuf));
} else {
ip = "";
}
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
have_vhosts = s?HAVE_VHOSTS(s):0;
if (have_vhosts && proc && proc->username[0] != 0) {
snprintf(name, sizeof(name), "[%s%s]", PREFIX_VHOST(proc->vhost), proc->username);
} else if (have_vhosts && proc && proc->username[0] == 0 && proc->vhost && proc->vhost->name) {
snprintf(name, sizeof(name), "[vhost:%s]", VHOSTNAME(proc->vhost));
} else if (proc && proc->username[0] != 0) {
snprintf(name, sizeof(name), "[%s]", proc->username);
} else
name[0] = 0;
_oc_syslog(syslog_prio, "main%s:%s %s", name, ip?ip:"[unknown]", buf);
}
void mslog_hex(const main_server_st * s, const struct proc_st* proc,
int priority, const char *prefix, uint8_t* bin, unsigned bin_size, unsigned b64)
{
char buf[512];
int ret;
size_t buf_size;
gnutls_datum_t data = {bin, bin_size};
int log_prio = DEFAULT_LOG_LEVEL;
if (s)
log_prio = GETPCONFIG(s)->log_level;
if (!log_check_priority(priority, log_prio, NULL))
return;
if (b64) {
oc_base64_encode((char*)bin, bin_size, (char*)buf, sizeof(buf));
} else {
buf_size = sizeof(buf);
ret = gnutls_hex_encode(&data, buf, &buf_size);
if (ret < 0)
return;
}
_mslog(s, proc, priority, "%s %s", prefix, buf);
}
void seclog_hex(const struct sec_mod_st* sec, int priority,
const char *prefix, uint8_t* bin, unsigned bin_size, unsigned b64)
{
char buf[512];
int ret;
size_t buf_size;
gnutls_datum_t data = {bin, bin_size};
int log_prio;
log_prio = GETPCONFIG(sec)->log_level;
if (!log_check_priority(priority, log_prio, NULL))
return;
if (b64) {
oc_base64_encode((char*)bin, bin_size, (char*)buf, sizeof(buf));
} else {
buf_size = sizeof(buf);
ret = gnutls_hex_encode(&data, buf, &buf_size);
if (ret < 0)
return;
}
seclog(sec, priority, "%s %s", prefix, buf);
}
void __attribute__ ((format(printf, 3, 4)))
_seclog(const sec_mod_st* sec, int priority, const char *fmt, ...)
{
char buf[512];
va_list args;
int log_prio = DEFAULT_LOG_LEVEL;
int syslog_prio;
if (sec)
log_prio = GETPCONFIG(sec)->log_level;
if (!log_check_priority(priority, log_prio, &syslog_prio))
return;
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
_oc_syslog(syslog_prio, "sec-mod: %s", buf);
}

View File

@@ -66,7 +66,7 @@
#include <hmac.h>
#include <base64-helper.h>
#include <snapshot.h>
#include <isolate.h>
#include <main-limits.h>
#include <sockdiag.h>
#include <namespace.h>
@@ -1566,7 +1566,7 @@ int main(int argc, char** argv)
init_fd_limits_default(s);
/* increase the number of our allowed file descriptors */
update_fd_limits(s, 1);
set_main_fd_limits(s);
ev_set_userdata (main_loop, s);
ev_set_syserr_cb(syserr_cb);

View File

@@ -610,7 +610,7 @@ static void certificate_check(main_server_st *s, const char *vhostname, gnutls_p
ret = gnutls_x509_crt_get_key_usage(crt, &usage, NULL);
if (ret >= 0) {
if (!(usage & GNUTLS_KEY_KEY_ENCIPHERMENT)) {
mslog(s, NULL, LOG_WARNING, "%s certificate key usage prevents key encipherment; unable to support the RSA ciphersuites; "
oc_syslog(LOG_WARNING, "%s certificate key usage prevents key encipherment; unable to support the RSA ciphersuites; "
"if that is not intentional, regenerate the server certificate with the key usage flag 'key encipherment' set.",
cert_name);
}
@@ -619,19 +619,19 @@ static void certificate_check(main_server_st *s, const char *vhostname, gnutls_p
if (vhostname) {
/* check whether the hostname matches our vhost */
if (!gnutls_x509_crt_check_hostname(crt, vhostname)) {
mslog(s, NULL, LOG_WARNING, "The %s certificate's name doesn't match for vhost %s",
oc_syslog(LOG_WARNING, "The %s certificate's name doesn't match for vhost %s",
cert_name, vhostname);
}
}
t = gnutls_x509_crt_get_expiration_time(crt);
if (t < time(NULL)) {
mslog(s, NULL, LOG_WARNING, "The %s certificate set is expired!", cert_name);
oc_syslog(LOG_WARNING, "The %s certificate set is expired!", cert_name);
}
t = gnutls_x509_crt_get_activation_time(crt);
if (t > time(NULL)) {
mslog(s, NULL, LOG_WARNING, "The %s certificate set is not yet active!", cert_name);
oc_syslog(LOG_WARNING, "The %s certificate set is not yet active!", cert_name);
}
cleanup:
@@ -827,19 +827,19 @@ int load_cert_files(main_server_st *s, struct vhost_cfg_st *vhost)
/* load the certificate */
if (gnutls_url_is_supported(vhost->perm_config.cert[i]) != 0) {
mslog(s, NULL, LOG_ERR, "Loading a certificate from '%s' is unsupported", vhost->perm_config.cert[i]);
oc_syslog(LOG_ERR, "Loading a certificate from '%s' is unsupported", vhost->perm_config.cert[i]);
return -1;
} else {
ret = gnutls_load_file(vhost->perm_config.cert[i], &data);
if (ret < 0) {
mslog(s, NULL, LOG_ERR, "error loading file[%d] '%s'", i, vhost->perm_config.cert[i]);
oc_syslog(LOG_ERR, "error loading file[%d] '%s'", i, vhost->perm_config.cert[i]);
return -1;
}
pcert_list_size = 8;
pcert_list = talloc_size(vhost->pool, sizeof(pcert_list[0])*pcert_list_size);
if (pcert_list == NULL) {
mslog(s, NULL, LOG_ERR, "error allocating memory");
oc_syslog(LOG_ERR, "error allocating memory");
return -1;
}
@@ -866,7 +866,7 @@ int load_cert_files(main_server_st *s, struct vhost_cfg_st *vhost)
*/
cdata = talloc_zero(vhost->pool, struct key_cb_data);
if (cdata == NULL) {
mslog(s, NULL, LOG_ERR, "error allocating memory");
oc_syslog(LOG_ERR, "error allocating memory");
return -1;
}
@@ -953,7 +953,7 @@ void tls_load_files(main_server_st *s, struct vhost_cfg_st *vhost)
if (need_reload == 0)
return;
mslog(s, NULL, LOG_INFO, "reloading server certificates");
oc_syslog(LOG_INFO, "reloading server certificates");
}
if (vhost->perm_config.log_level >= OCLOG_TLS) {
@@ -974,7 +974,7 @@ void tls_load_files(main_server_st *s, struct vhost_cfg_st *vhost)
set_dh_params(s, vhost);
if (vhost->perm_config.key_size == 0 || vhost->perm_config.cert_size == 0) {
mslog(s, NULL, LOG_ERR, "no certificate or key files were specified");
oc_syslog(LOG_ERR, "no certificate or key files were specified");
exit(EXIT_FAILURE);
}
@@ -987,7 +987,7 @@ void tls_load_files(main_server_st *s, struct vhost_cfg_st *vhost)
ret = load_cert_files(s, vhost);
if (ret < 0) {
mslog(s, NULL, LOG_ERR, "error loading the certificate or key file");
oc_syslog(LOG_ERR, "error loading the certificate or key file");
exit(EXIT_FAILURE);
}
@@ -998,12 +998,12 @@ void tls_load_files(main_server_st *s, struct vhost_cfg_st *vhost)
vhost->perm_config.ca,
GNUTLS_X509_FMT_PEM);
if (ret < 0) {
mslog(s, NULL, LOG_ERR, "error setting the CA (%s) file",
oc_syslog(LOG_ERR, "error setting the CA (%s) file",
vhost->perm_config.ca);
exit(EXIT_FAILURE);
}
mslog(s, NULL, LOG_INFO, "processed %d CA certificate(s)", ret);
oc_syslog(LOG_INFO, "processed %d CA certificate(s)", ret);
}
tls_reload_crl(s, vhost, 1);
@@ -1064,7 +1064,7 @@ void tls_load_prio(main_server_st *s, struct vhost_cfg_st *vhost)
ret = gnutls_priority_init(&vhost->creds.cprio, vhost->perm_config.config->priorities, &perr);
if (ret == GNUTLS_E_PARSING_ERROR)
mslog(s, NULL, LOG_ERR, "error in TLS priority string: %s", perr);
oc_syslog(LOG_ERR, "error in TLS priority string: %s", perr);
GNUTLS_FATAL_ERR(ret);
}
@@ -1081,7 +1081,7 @@ void tls_reload_crl(main_server_st* s, struct vhost_cfg_st *vhost, unsigned forc
if (vhost->perm_config.config->cert_req != GNUTLS_CERT_IGNORE && vhost->perm_config.config->crl != NULL) {
if (need_file_reload(vhost->perm_config.config->crl, vhost->crl_last_access) == 0) {
mslog(s, NULL, LOG_DEBUG, "skipping already loaded CRL: %s", vhost->perm_config.config->crl);
oc_syslog(LOG_DEBUG, "skipping already loaded CRL: %s", vhost->perm_config.config->crl);
return;
}
@@ -1103,11 +1103,11 @@ void tls_reload_crl(main_server_st* s, struct vhost_cfg_st *vhost, unsigned forc
}
if (ret < 0) {
/* ignore the CRL file when empty */
mslog(s, NULL, LOG_ERR, "error reading the CRL (%s) file: %s",
oc_syslog(LOG_ERR, "error reading the CRL (%s) file: %s",
vhost->perm_config.config->crl, gnutls_strerror(ret));
exit(EXIT_FAILURE);
}
mslog(s, NULL, LOG_INFO, "loaded CRL: %s", vhost->perm_config.config->crl);
oc_syslog(LOG_INFO, "loaded CRL: %s", vhost->perm_config.config->crl);
}
}
#endif /* UNDER_TEST */
@@ -1156,14 +1156,14 @@ void *calc_sha1_hash(void *pool, char* file, unsigned cert)
gnutls_free(data.data);
if (ret < 0) {
fprintf(stderr, "error calculating hash of '%s': %s", file, gnutls_strerror(ret));
oc_syslog(LOG_ERR, "error calculating hash of '%s': %s", file, gnutls_strerror(ret));
exit(EXIT_FAILURE);
}
size_t ret_size = sizeof(digest)*2+1;
retval = talloc_size(pool, ret_size);
if (retval == NULL) {
fprintf(stderr, "memory error");
oc_syslog(LOG_ERR, "memory error");
exit(EXIT_FAILURE);
}
@@ -1171,7 +1171,7 @@ void *calc_sha1_hash(void *pool, char* file, unsigned cert)
data.size = sizeof(digest);
ret = gnutls_hex_encode(&data, retval, &ret_size);
if (ret < 0) {
fprintf(stderr, "error in hex encode: %s", gnutls_strerror(ret));
oc_syslog(LOG_ERR, "error in hex encode: %s", gnutls_strerror(ret));
exit(EXIT_FAILURE);
}
if (retval[ret_size-1] == 0) ret_size--; /* remove the null terminator */

View File

@@ -833,86 +833,3 @@ void reset_tun(struct proc_st* proc)
}
}
#if defined(__OpenBSD__) || defined(TUNSIFHEAD)
# define TUN_AF_PREFIX 1
#endif
#ifdef TUN_AF_PREFIX
ssize_t tun_write(int sockfd, const void *buf, size_t len)
{
struct ip *iph = (void *)buf;
uint32_t head;
const uint8_t *data = buf;
static int complained = 0;
struct iovec iov[2];
int ret;
if (iph->ip_v == 6)
head = htonl(AF_INET6);
else if (iph->ip_v == 4)
head = htonl(AF_INET);
else {
if (!complained) {
complained = 1;
oc_syslog(LOG_ERR, "tun_write: Unknown packet (len %d) received %02x %02x %02x %02x...\n",
(int)len, data[0], data[1], data[2], data[3]);
}
return -1;
}
iov[0].iov_base = &head;
iov[0].iov_len = sizeof(head);
iov[1].iov_base = (void*)buf;
iov[1].iov_len = len;
ret = writev(sockfd, iov, 2);
if (ret >= sizeof(uint32_t))
ret -= sizeof(uint32_t);
return ret;
}
ssize_t tun_read(int sockfd, void *buf, size_t len)
{
uint32_t head;
struct iovec iov[2];
int ret;
iov[0].iov_base = &head;
iov[0].iov_len = sizeof(head);
iov[1].iov_base = buf;
iov[1].iov_len = len;
ret = readv(sockfd, iov, 2);
if (ret >= sizeof(uint32_t))
ret -= sizeof(uint32_t);
return ret;
}
#else
ssize_t tun_write(int sockfd, const void *buf, size_t len)
{
return force_write(sockfd, buf, len);
}
ssize_t tun_read(int sockfd, void *buf, size_t len)
{
return read(sockfd, buf, len);
}
#endif
#ifndef __FreeBSD__
int tun_claim(int sockfd)
{
return 0;
}
#else
/*
* FreeBSD has a mechanism by which a tunnel has a single controlling process,
* and only that one process may close it. When the controlling process closes
* the tunnel, the state is torn down.
*/
int tun_claim(int sockfd)
{
return ioctl(sockfd, TUNSIFPID, 0);
}
#endif /* !__FreeBSD__ */

101
src/worker-log.c Normal file
View File

@@ -0,0 +1,101 @@
/*
* Copyright (C) 2013-2023 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, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <syslog.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <arpa/inet.h>
#include <base64-helper.h>
#include <worker.h>
#include <main.h>
#include "sec-mod.h"
#include "log.h"
void __attribute__ ((format(printf, 3, 4)))
_oclog(const worker_st * ws, int priority, const char *fmt, ...)
{
char buf[512];
char name[MAX_USERNAME_SIZE+MAX_HOSTNAME_SIZE+3];
const char* ip;
va_list args;
int log_prio;
unsigned have_vhosts;
int syslog_prio;
if (ws->vhost)
log_prio = WSPCONFIG(ws)->log_level;
else
log_prio = GETPCONFIG(ws)->log_level;
if (!log_check_priority(priority, log_prio, &syslog_prio))
return;
ip = ws->remote_ip_str;
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
have_vhosts = HAVE_VHOSTS(ws);
if (have_vhosts && ws->username[0] != 0) {
snprintf(name, sizeof(name), "[%s%s]", PREFIX_VHOST(ws->vhost), ws->username);
} else if (have_vhosts && ws->username[0] == 0 && ws->vhost && ws->vhost->name) {
snprintf(name, sizeof(name), "[vhost:%s]", VHOSTNAME(ws->vhost));
} else if (ws->username[0] != 0) {
snprintf(name, sizeof(name), "[%s]", ws->username);
} else
name[0] = 0;
_oc_syslog(syslog_prio, "worker%s: %s %s", name, ip?ip:"[unknown]", buf);
}
void oclog_hex(const worker_st* ws, int priority,
const char *prefix, uint8_t* bin, unsigned bin_size, unsigned b64)
{
char buf[512];
int ret;
size_t buf_size;
gnutls_datum_t data = {bin, bin_size};
int log_prio;
if (ws->vhost)
log_prio = WSPCONFIG(ws)->log_level;
else
log_prio = GETPCONFIG(ws)->log_level;
if (!log_check_priority(priority, log_prio, NULL))
return;
if (b64) {
oc_base64_encode((char*)bin, bin_size, (char*)buf, sizeof(buf));
} else {
buf_size = sizeof(buf);
ret = gnutls_hex_encode(&data, buf, &buf_size);
if (ret < 0)
return;
}
_oclog(ws, priority, "%s %s", prefix, buf);
}

View File

@@ -45,7 +45,7 @@
void sigsys_action(int sig, siginfo_t * info, void* ucontext)
{
char * call_addr = *backtrace_symbols(&info->si_call_addr, 1);
fprintf(stderr, "Function %s called disabled syscall %d\n", call_addr, info->si_syscall);
oc_syslog(LOG_ERR, "Function %s called disabled syscall %d\n", call_addr, info->si_syscall);
exit(EXIT_FAILURE);
}

146
src/worker-tun.c Normal file
View File

@@ -0,0 +1,146 @@
/*
* Copyright (C) 2013 Nikos Mavrogiannopoulos
*
* This file is part of ocserv.
*
* ocserv is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* ocserv is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <cloexec.h>
#include <ip-lease.h>
#if defined(HAVE_LINUX_IF_TUN_H)
# include <linux/if_tun.h>
#elif defined(HAVE_NET_IF_TUN_H)
# include <net/if_tun.h>
#endif
#include <netdb.h>
#include <vpn.h>
#include <tun.h>
#include <main.h>
#include <ccan/list/list.h>
#include "vhost.h"
#include "log.h"
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
# include <net/if_var.h>
# include <netinet/in_var.h>
#endif
#if defined(__OpenBSD__)
# include <netinet6/in6_var.h>
#endif
#if defined(__DragonFly__)
# include <net/tun/if_tun.h>
#endif
#if defined(__OpenBSD__) || defined(TUNSIFHEAD)
# define TUN_AF_PREFIX 1
#endif
#ifdef TUN_AF_PREFIX
ssize_t tun_write(int sockfd, const void *buf, size_t len)
{
struct ip *iph = (void *)buf;
uint32_t head;
const uint8_t *data = buf;
static int complained = 0;
struct iovec iov[2];
int ret;
if (iph->ip_v == 6)
head = htonl(AF_INET6);
else if (iph->ip_v == 4)
head = htonl(AF_INET);
else {
if (!complained) {
complained = 1;
oc_syslog(LOG_ERR, "tun_write: Unknown packet (len %d) received %02x %02x %02x %02x...\n",
(int)len, data[0], data[1], data[2], data[3]);
}
return -1;
}
iov[0].iov_base = &head;
iov[0].iov_len = sizeof(head);
iov[1].iov_base = (void*)buf;
iov[1].iov_len = len;
ret = writev(sockfd, iov, 2);
if (ret >= sizeof(uint32_t))
ret -= sizeof(uint32_t);
return ret;
}
ssize_t tun_read(int sockfd, void *buf, size_t len)
{
uint32_t head;
struct iovec iov[2];
int ret;
iov[0].iov_base = &head;
iov[0].iov_len = sizeof(head);
iov[1].iov_base = buf;
iov[1].iov_len = len;
ret = readv(sockfd, iov, 2);
if (ret >= sizeof(uint32_t))
ret -= sizeof(uint32_t);
return ret;
}
#else
ssize_t tun_write(int sockfd, const void *buf, size_t len)
{
return force_write(sockfd, buf, len);
}
ssize_t tun_read(int sockfd, void *buf, size_t len)
{
return read(sockfd, buf, len);
}
#endif
#ifndef __FreeBSD__
int tun_claim(int sockfd)
{
return 0;
}
#else
/*
* FreeBSD has a mechanism by which a tunnel has a single controlling process,
* and only that one process may close it. When the controlling process closes
* the tunnel, the state is torn down.
*/
int tun_claim(int sockfd)
{
return ioctl(sockfd, TUNSIFPID, 0);
}
#endif /* !__FreeBSD__ */

View File

@@ -174,13 +174,10 @@ int main(int argc, char **argv)
/* Initialize kkdcp structures */
ret = asn1_array2tree(kkdcp_asn1_tab, &_kkdcp_pkix1_asn, NULL);
if (ret != ASN1_SUCCESS) {
mslog(s, NULL, LOG_ERR, "KKDCP ASN.1 initialization error");
oc_syslog(LOG_ERR, "KKDCP ASN.1 initialization error");
exit(EXIT_FAILURE);
}
#endif
init_fd_limits_default(s);
sigprocmask(SIG_SETMASK, &sig_default_set, NULL);
setproctitle(PACKAGE_NAME "-worker");
@@ -193,8 +190,10 @@ int main(int argc, char **argv)
DTLS_ACTIVE(ws)->dtls_tptr.fd = -1;
DTLS_INACTIVE(ws)->dtls_tptr.fd = -1;
set_worker_fd_limits(ws);
/* Drop privileges after this point */
drop_privileges(s);
drop_privileges(ws, s);
vpn_server(ws);

View File

@@ -141,12 +141,15 @@ cstp_recv_LDADD = $(LDADD) $(LIBGNUTLS_LIBS)
json_escape_SOURCES = json-escape.c
json_escape_LDADD = $(LDADD)
url_escape_CPPFLAGS = $(AM_CPPFLAGS) -DUNDER_TEST
url_escape_SOURCES = url-escape.c
url_escape_LDADD = $(LDADD)
html_escape_CPPFLAGS = $(AM_CPPFLAGS) -DUNDER_TEST
html_escape_SOURCES = html-escape.c
html_escape_LDADD = $(LDADD)
ipv4_prefix_CPPFLAGS = $(AM_CPPFLAGS) -DUNDER_TEST
ipv4_prefix_SOURCES = ipv4-prefix.c
ipv4_prefix_LDADD = $(LDADD)
@@ -160,16 +163,18 @@ str_test_LDADD = $(LDADD)
str_test2_SOURCES = str-test2.c
str_test2_LDADD = $(LDADD)
ipv6_prefix_CPPFLAGS = $(AM_CPPFLAGS) -DUNDER_TEST
ipv6_prefix_SOURCES = ipv6-prefix.c
ipv6_prefix_LDADD = $(LDADD)
human_addr_CPPFLAGS = $(AM_CPPFLAGS)
human_addr_CPPFLAGS = $(AM_CPPFLAGS) -DUNDER_TEST
human_addr_SOURCES = human_addr.c
human_addr_LDADD = $(LDADD)
valid_hostname_LDADD = $(LDADD)
port_parsing_CPPFLAGS = $(AM_CPPFLAGS) -DUNDER_TEST
port_parsing_LDADD = $(LDADD)
check_PROGRAMS = str-test str-test2 ipv4-prefix ipv6-prefix kkdcp-parsing json-escape ban-ips \