mirror of
https://github.com/yrutschle/sslh.git
synced 2026-10-22 18:12:10 +03:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c43f6daf03 | ||
|
|
736b108a75 | ||
|
|
7ca567fcd9 | ||
|
|
3117c15fbd | ||
|
|
e428fc505c | ||
|
|
4dfb4d300a | ||
|
|
39184b5622 | ||
|
|
940461de18 | ||
|
|
6f949419d1 | ||
|
|
dab5df7409 | ||
|
|
402ca5219b | ||
|
|
046401148d | ||
|
|
780e536aeb | ||
|
|
ed0ab12a16 | ||
|
|
b65f1e8b26 | ||
|
|
91b649daa0 | ||
|
|
7499c26e9e | ||
|
|
90a55b6f9d | ||
|
|
1f66e2e093 | ||
|
|
92d2326016 | ||
|
|
81eed9d56a | ||
|
|
490a44723b | ||
|
|
23fb1eba6f | ||
|
|
be66848e2d | ||
|
|
3e93c1d43d | ||
|
|
8930ec395e |
No files matched your search
@@ -3,8 +3,10 @@
|
||||
*.o
|
||||
cscope.*
|
||||
echosrv
|
||||
libsslh.a
|
||||
sslh-fork
|
||||
sslh-select
|
||||
sslh-ev
|
||||
sslh.8.gz
|
||||
tags
|
||||
version.h
|
||||
@@ -1,3 +1,14 @@
|
||||
v2.1.0:
|
||||
Support for the Landlock LSM. After initial setup,
|
||||
sslh gives up all local file access rights.
|
||||
|
||||
Reintroduced --ssl as an alias to --tls.
|
||||
|
||||
Introduce autoconf to adapt to landlock presence.
|
||||
|
||||
Close connexion without error message if remote
|
||||
client forcefully closes connexion, for Windows.
|
||||
|
||||
v2.0.1:
|
||||
Fix resolve_on_forward setting, which would crash
|
||||
sslh reliably.
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ RUN apk add --no-cache \
|
||||
|
||||
COPY . /sslh
|
||||
|
||||
RUN make sslh-select && strip sslh-select
|
||||
RUN ./configure && make sslh-select && strip sslh-select
|
||||
|
||||
FROM docker.io/${TARGET_ARCH}/alpine:${ALPINE_VERSION}
|
||||
|
||||
|
||||
+12
-6
@@ -3,9 +3,11 @@ VERSION=$(shell ./genver.sh -r)
|
||||
|
||||
# Configuration -- you probably need to `make clean` if you
|
||||
# change any of these
|
||||
# landlock is checked by `configure` and set in config.h
|
||||
ENABLE_SANITIZER= # Enable ASAN/LSAN/UBSAN
|
||||
ENABLE_REGEX=1 # Enable regex probes
|
||||
USELIBCONFIG=1 # Use libconfig? (necessary to use configuration files)
|
||||
USELIBEV=1 # Use libev?
|
||||
USELIBWRAP?= # Use libwrap?
|
||||
USELIBCAP= # Use libcap?
|
||||
USESYSTEMD= # Make use of systemd socket activation
|
||||
@@ -34,7 +36,7 @@ CFLAGS +=-Wall -O2 -DLIBPCRE -g $(CFLAGS_COV) $(CFLAGS_SAN)
|
||||
|
||||
|
||||
LIBS=-lm -lpcre2-8
|
||||
OBJS=sslh-conf.o common.o log.o sslh-main.o probe.o tls.o argtable3.o collection.o gap.o tcp-probe.o
|
||||
OBJS=sslh-conf.o common.o log.o sslh-main.o probe.o tls.o argtable3.o collection.o gap.o tcp-probe.o landlock.o
|
||||
OBJS_A=libsslh.a
|
||||
FORK_OBJS=sslh-fork.o $(OBJS_A)
|
||||
SELECT_OBJS=processes.o udp-listener.o sslh-select.o hash.o tcp-listener.o $(OBJS_A)
|
||||
@@ -72,8 +74,11 @@ ifneq ($(strip $(USELIBBSD)),)
|
||||
CPPFLAGS+=-DLIBBSD
|
||||
endif
|
||||
|
||||
ifneq ($(strip $(USELIBEV)),)
|
||||
CONDITIONAL_TARGETS+=sslh-ev
|
||||
endif
|
||||
|
||||
all: sslh $(MAN) echosrv $(CONDITIONAL_TARGETS)
|
||||
all: sslh-fork sslh-select $(MAN) echosrv $(CONDITIONAL_TARGETS)
|
||||
|
||||
%.o: %.c %.h version.h
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
|
||||
@@ -84,8 +89,6 @@ $(OBJS_A): $(OBJS)
|
||||
version.h:
|
||||
./genver.sh >version.h
|
||||
|
||||
sslh: sslh-fork sslh-select sslh-ev
|
||||
|
||||
$(OBJS) $(FORK_OBJS) $(SELECT_OBJS) $(EV_OBJS): argtable3.h collection.h common.h gap.h hash.h log.h probe.h processes.h sslh-conf.h tcp-listener.h tcp-probe.h tls.h udp-listener.h version.h
|
||||
|
||||
|
||||
@@ -114,6 +117,9 @@ echosrv-conf.c echosrv-conf.h: echosrv.cfg
|
||||
echosrv: version.h echosrv-conf.c echosrv.o echosrv-conf.o argtable3.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o echosrv echosrv.o echosrv-conf.o argtable3.o $(LIBS)
|
||||
|
||||
|
||||
landlock.o: config.h
|
||||
|
||||
$(MAN): sslh.pod Makefile
|
||||
pod2man --section=8 --release=$(VERSION) --center=" " sslh.pod | gzip -9 - > $(MAN)
|
||||
|
||||
@@ -133,7 +139,7 @@ docker-clean:
|
||||
yes | docker image prune
|
||||
|
||||
# generic install: install binary and man page
|
||||
install: sslh $(MAN)
|
||||
install: sslh-fork $(MAN)
|
||||
mkdir -p $(DESTDIR)/$(BINDIR)
|
||||
mkdir -p $(DESTDIR)/$(MANDIR)
|
||||
install -p sslh-fork $(DESTDIR)/$(BINDIR)/sslh
|
||||
@@ -153,7 +159,7 @@ distclean: clean
|
||||
rm -f tags sslh-conf.[ch] echosrv-conf.[ch] cscope.*
|
||||
|
||||
clean:
|
||||
rm -f sslh-fork sslh-select sslh-ev echosrv version.h $(MAN) systemd-sslh-generator *.o *.gcov *.gcno *.gcda *.png *.html *.css *.info
|
||||
rm -f sslh-fork sslh-select $(CONDITIONAL_TARGETS) echosrv version.h $(MAN) systemd-sslh-generator *.o *.gcov *.gcno *.gcda *.png *.html *.css *.info
|
||||
|
||||
tags:
|
||||
ctags --globals -T *.[ch]
|
||||
@@ -21,8 +21,9 @@ address.
|
||||
`sslh` has the bells and whistles expected from a mature
|
||||
daemon: privilege and capabilities dropping, inetd support,
|
||||
systemd support, transparent proxying, chroot, logging,
|
||||
IPv4 and IPv6, TCP and UDP, a fork-based and a select-based
|
||||
model, and more.
|
||||
IPv4 and IPv6, TCP and UDP, a fork-based, a select-based
|
||||
model, and yet another based on libev for larger
|
||||
installations.
|
||||
|
||||
Install
|
||||
=======
|
||||
@@ -35,6 +36,18 @@ Configuration
|
||||
|
||||
Please refer to the [configuration guide](doc/config.md).
|
||||
|
||||
Transparent proxying allows the target server to see the
|
||||
original client IP address, i.e. `sslh` becomes invisible.
|
||||
This makes it easier to use the server's logs, and potential
|
||||
IP-based banning ability.
|
||||
|
||||
Configuration of transparent proxying is highly dependent on
|
||||
your network environment and infrastructure setup. There is
|
||||
no known generic approach, and if you do not find directions
|
||||
for your exact setup, you will probably need an extensive
|
||||
knowledge of network management and iptables setup".
|
||||
|
||||
It is described in its own [document](tproxy.md).
|
||||
|
||||
|
||||
Docker image
|
||||
@@ -65,7 +78,7 @@ version: "3"
|
||||
|
||||
services:
|
||||
sslh:
|
||||
image: sslh:latest
|
||||
image: ghcr.io/yrutschle/sslh:latest
|
||||
hostname: sslh
|
||||
ports:
|
||||
- 443:443
|
||||
|
||||
@@ -110,7 +110,7 @@ int make_listen_tfo(int s)
|
||||
return setsockopt(s, SOL_SOCKET, TCP_FASTOPEN, (char*)&qlen, sizeof(qlen));
|
||||
}
|
||||
|
||||
/* Starts listening on a single address
|
||||
/* Starts listening on a single address
|
||||
* Returns a socket filehandle, or dies with message in case of major error */
|
||||
int listen_single_addr(struct addrinfo* addr, int keepalive, int udp)
|
||||
{
|
||||
@@ -262,7 +262,7 @@ int bind_peer(int fd, int fd_from)
|
||||
/* if the destination is the same machine, there's no need to do bind */
|
||||
if (is_same_machine(&from))
|
||||
return 0;
|
||||
|
||||
|
||||
#ifndef IP_BINDANY /* use IP_TRANSPARENT */
|
||||
res = setsockopt(fd, IPPROTO_IP, IP_TRANSPARENT, &trans, sizeof(trans));
|
||||
CHECK_RES_DIE(res, "setsockopt IP_TRANSPARENT");
|
||||
@@ -278,7 +278,26 @@ int bind_peer(int fd, int fd_from)
|
||||
}
|
||||
#endif /* IP_TRANSPARENT / IP_BINDANY */
|
||||
res = bind(fd, from.ai_addr, from.ai_addrlen);
|
||||
CHECK_RES_RETURN(res, "bind", res);
|
||||
if (res == -1) {
|
||||
if (errno != EADDRINUSE) {
|
||||
print_message(msg_system_error, "%s:%d:%s:%d:%s\n", __FILE__, __LINE__,
|
||||
"bind", errno, strerror(errno));
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is more than one transparent mode proxy going on, such as
|
||||
* using sslh as the target of stunnel also in transparent mode, then
|
||||
* the (ip,port) combination will already be bound for the previous application.
|
||||
* In that case, the best we can do is bind with a different port.
|
||||
* This does mean the local server can't use the ident protocol as the port will
|
||||
* have changed, but most people won't care.
|
||||
* Also note that stunnel uses the same logic for the same situation.
|
||||
*/
|
||||
((struct sockaddr_in *)from.ai_addr)->sin_port = 0;
|
||||
res = bind(fd, from.ai_addr, from.ai_addrlen);
|
||||
CHECK_RES_RETURN(res, "bind", res);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -463,6 +482,7 @@ int fd2fd(struct queue *target_q, struct queue *from_q)
|
||||
return FD_NODATA;
|
||||
|
||||
case ECONNRESET:
|
||||
case ENOTSOCK:
|
||||
case EPIPE:
|
||||
return FD_CNXCLOSED;
|
||||
}
|
||||
@@ -530,7 +550,8 @@ char* sprintaddr(char* buf, size_t size, struct addrinfo *a)
|
||||
}
|
||||
|
||||
/* Turns a hostname and port (or service) into a list of struct addrinfo
|
||||
* returns 0 on success, -1 otherwise and logs error
|
||||
* On success, returns 0
|
||||
* On failure, returns -1 or one of getaddrinfo() codes
|
||||
*/
|
||||
int resolve_split_name(struct addrinfo **out, char* host, char* serv)
|
||||
{
|
||||
@@ -556,7 +577,7 @@ int resolve_split_name(struct addrinfo **out, char* host, char* serv)
|
||||
|
||||
res = getaddrinfo(host, serv, &hint, out);
|
||||
if (res)
|
||||
print_message(msg_system_error, "%s `%s:%s'\n", gai_strerror(res), host, serv);
|
||||
print_message(msg_system_error, "resolve_split_name: %s `%s:%s'\n", gai_strerror(res), host, serv);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -848,4 +869,3 @@ void write_pid_file(const char* pidfile)
|
||||
exit(3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,4 +183,8 @@ void start_shoveler(int);
|
||||
|
||||
void main_loop(struct listen_endpoint *listen_sockets, int num_addr_listen);
|
||||
|
||||
/* landlock.c */
|
||||
void setup_landlock(void);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
|
||||
#ifndef CONFIG_H
|
||||
/* Template for config.h, filled by `configure`. */
|
||||
|
||||
/* Landlock sandboxing Linux LSM */
|
||||
#undef HAVE_LANDLOCK
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,9 @@
|
||||
|
||||
dnl Use autoconf to generate the `configure` script from this and Makefile.in
|
||||
|
||||
AC_INIT
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
|
||||
AC_CHECK_HEADERS(linux/landlock.h, AC_DEFINE(HAVE_LANDLOCK), [])
|
||||
AC_OUTPUT
|
||||
@@ -1,3 +1,12 @@
|
||||
Pre-built binaries
|
||||
==================
|
||||
|
||||
Docker images of `master` and of the tagged versions are
|
||||
available directly from [Github](https://github.com/yrutschle/sslh/pkgs/container/sslh).
|
||||
|
||||
Windows binaries for Cygwin are graciouly produced by
|
||||
nono303 on his [repository](https://github.com/nono303/sslh).
|
||||
|
||||
Compile and install
|
||||
===================
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
It is possible to run `sslh` on Windows. The `fork` model
|
||||
should be avoided as it is very inefficient on Windows, but
|
||||
`sslh-select` and `sslh-ev` both work with good performance
|
||||
(prefer the latter, however).
|
||||
|
||||
|
||||
The following script downloads the latest cygwin, the latest version of sslh, and then compiles and copies the binaries with dependancies to an output folder.
|
||||
|
||||
It may be needed to correct it from time to time, but it works. I use it in a virtual machine.
|
||||
Just retrieve WGET.EXE from [https://eternallybored.org/misc/wget/](url) or git binaries.
|
||||
|
||||
Copy the 3 files
|
||||
|
||||
GO.cmd
|
||||
wget.exe
|
||||
compile.sh
|
||||
|
||||
to C root folder, then execute **GO.cmd** with administrative rights.
|
||||
|
||||
with **GO.cmd**
|
||||
|
||||
@ECHO OFF
|
||||
CD /D "%~dp0"
|
||||
|
||||
NET SESSION >NUL 2>&1
|
||||
IF %ERRORLEVEL% NEQ 0 (
|
||||
ECHO Permission denied. This script must be run as an Administrator.
|
||||
ECHO:
|
||||
GOTO FIN
|
||||
) ELSE (
|
||||
ECHO Running as Administrator.
|
||||
TIMEOUT /T 2 >NUL
|
||||
wget --no-check-certificate https://www.cygwin.com/setup-x86_64.exe
|
||||
IF NOT EXIST setup-x86_64.exe GOTO FIN
|
||||
MKDIR C:\Z
|
||||
setup-x86_64.exe -l C:\Z -s ftp://ftp.funet.fi/pub/mirrors/sourceware.org/pub/cygwin/ -q -P make -P git -P gcc-g++ -P autoconf -P automake -P libtool -P libpcre-devel -P libpcre2-devel -P bison -P libev-devel
|
||||
MKDIR C:\cygwin64\home\user
|
||||
COPY COMPILE.SH C:\cygwin64\home\user
|
||||
START C:\cygwin64\bin\mintty.exe /bin/bash --login -i ~/compile.sh
|
||||
START EXPLORER C:\zzSORTIE
|
||||
)
|
||||
:FIN
|
||||
PAUSE
|
||||
EXIT
|
||||
|
||||
|
||||
and **compile.sh**
|
||||
|
||||
# SAVE FILE TO UNIX FORMAT
|
||||
# COPY IT IN C cygwin64 home user
|
||||
git clone https://github.com/hyperrealm/libconfig.git
|
||||
cd libconfig
|
||||
autoreconf -fi
|
||||
./configure
|
||||
make
|
||||
make install
|
||||
cd ..
|
||||
cp /usr/local/lib/libconfig.* /usr/lib
|
||||
git clone https://github.com/yrutschle/sslh.git
|
||||
cd sslh
|
||||
make
|
||||
cd ..
|
||||
mkdir /cygdrive/c/zzSORTIE
|
||||
cp ./sslh/sslh*.exe /cygdrive/c/zzSORTIE
|
||||
cp /usr/local/bin/cygconfig-11.dll /cygdrive/c/zzSORTIE
|
||||
cp /cygdrive/c/cygwin64/bin/cygwin1.dll /cygdrive/c/zzSORTIE
|
||||
cp /cygdrive/c/cygwin64/bin/cygpcreposix-0.dll /cygdrive/c/zzSORTIE
|
||||
cp /cygdrive/c/cygwin64/bin/cygpcre-1.dll /cygdrive/c/zzSORTIE
|
||||
cp /cygdrive/c/cygwin64/bin/cygev-4.dll /cygdrive/c/zzSORTIE
|
||||
cp /cygdrive/c/cygwin64/bin/cygpcre2-8-0.dll /cygdrive/c/zzSORTIE
|
||||
|
||||
This method was contributed by lerenardo on [github](https://github.com/yrutschle/sslh/issues/196#issuecomment-1692805639).
|
||||
+2
-6
@@ -99,12 +99,8 @@ Then you can run sslh-select as an unprivileged user, e.g.:
|
||||
Transparent proxy support
|
||||
-------------------------
|
||||
|
||||
Transparent proxying allows the target server to see the
|
||||
original client IP address, i.e. `sslh` becomes invisible.
|
||||
This makes it easier to use the server's logs, and potential
|
||||
IP-based banning ability.
|
||||
|
||||
Set up can get complicated, so it has its own [document](tproxy.md).
|
||||
Transparent proxying is described in its own
|
||||
[document](tproxy.md).
|
||||
|
||||
Systemd Socket Activation
|
||||
-------------------------
|
||||
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Setup a sandbox using the Landlock LSM, if available.
|
||||
|
||||
# Copyright (C) 2023 Yves Rutschle
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# The full text for the General Public License is here:
|
||||
# http://www.gnu.org/licenses/gpl.html
|
||||
#
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
|
||||
#ifdef HAVE_LANDLOCK
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <linux/landlock.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
/* Ubuntu 22.04 does not have this symbol */
|
||||
#ifndef LANDLOCK_ACCESS_FS_REFER
|
||||
#define LANDLOCK_ACCESS_FS_REFER (1ULL << 13)
|
||||
#endif
|
||||
|
||||
#ifndef landlock_create_ruleset
|
||||
static inline int
|
||||
landlock_create_ruleset(const struct landlock_ruleset_attr *const attr,
|
||||
const size_t size, const __u32 flags)
|
||||
{
|
||||
return syscall(__NR_landlock_create_ruleset, attr, size, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef landlock_add_rule
|
||||
static inline int landlock_add_rule(const int ruleset_fd,
|
||||
const enum landlock_rule_type rule_type,
|
||||
const void *const rule_attr,
|
||||
const __u32 flags)
|
||||
{
|
||||
return syscall(__NR_landlock_add_rule, ruleset_fd, rule_type, rule_attr,
|
||||
flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef landlock_restrict_self
|
||||
static inline int landlock_restrict_self(const int ruleset_fd,
|
||||
const __u32 flags)
|
||||
{
|
||||
return syscall(__NR_landlock_restrict_self, ruleset_fd, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
LL_TREE,
|
||||
LL_FILE
|
||||
} ll_obj_type;
|
||||
|
||||
static int add_path_ro(int ruleset_fd, ll_obj_type otype, const char* path)
|
||||
{
|
||||
int fd = open(path, O_PATH | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
print_message(msg_config_error, "Landlock: Failed to open %s: %s\n", path, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct landlock_path_beneath_attr path_beneath = {
|
||||
.allowed_access = (otype == LL_TREE ? LANDLOCK_ACCESS_FS_READ_DIR : 0 ) |
|
||||
LANDLOCK_ACCESS_FS_READ_FILE,
|
||||
.parent_fd = fd,
|
||||
};
|
||||
|
||||
int res = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, &path_beneath, 0);
|
||||
if (res) {
|
||||
print_message(msg_config_error, "Landlock: Failed to update the ruleset with \"%s\": %s\n",
|
||||
path, strerror(errno));
|
||||
close(path_beneath.parent_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void setup_landlock(void)
|
||||
{
|
||||
__u64 restrict_rules =
|
||||
LANDLOCK_ACCESS_FS_EXECUTE |
|
||||
LANDLOCK_ACCESS_FS_READ_FILE |
|
||||
LANDLOCK_ACCESS_FS_READ_DIR |
|
||||
LANDLOCK_ACCESS_FS_WRITE_FILE |
|
||||
LANDLOCK_ACCESS_FS_REMOVE_DIR |
|
||||
LANDLOCK_ACCESS_FS_REMOVE_FILE |
|
||||
LANDLOCK_ACCESS_FS_MAKE_CHAR |
|
||||
LANDLOCK_ACCESS_FS_MAKE_DIR |
|
||||
LANDLOCK_ACCESS_FS_MAKE_REG |
|
||||
LANDLOCK_ACCESS_FS_MAKE_SOCK |
|
||||
LANDLOCK_ACCESS_FS_MAKE_FIFO |
|
||||
LANDLOCK_ACCESS_FS_MAKE_BLOCK |
|
||||
LANDLOCK_ACCESS_FS_MAKE_SYM |
|
||||
LANDLOCK_ACCESS_FS_REFER;
|
||||
|
||||
struct landlock_ruleset_attr ruleset_attr = {
|
||||
.handled_access_fs = restrict_rules
|
||||
};
|
||||
|
||||
/* ruleset_addr.handled_access_fs contains all rights that will be restricted
|
||||
* unless explicitly added */
|
||||
int ruleset_fd = landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
|
||||
if (ruleset_fd < 0) {
|
||||
print_message(msg_config_error, "Landlock: Failed to create a ruleset");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Access to libraries, to be able to fork */
|
||||
add_path_ro(ruleset_fd, LL_TREE, "/lib");
|
||||
add_path_ro(ruleset_fd, LL_TREE, "/usr/lib");
|
||||
add_path_ro(ruleset_fd, LL_FILE, "/etc/ld.so.cache"); /* To avoid searching all libs... */
|
||||
|
||||
/* Files to resolve names (required when dynamic resolution is used) */
|
||||
add_path_ro(ruleset_fd, LL_FILE, "/etc/hosts");
|
||||
add_path_ro(ruleset_fd, LL_FILE, "/etc/resolv.conf");
|
||||
add_path_ro(ruleset_fd, LL_FILE, "/etc/nsswitch.conf");
|
||||
|
||||
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
|
||||
print_message(msg_config_error, "Landlock: Failed to restrict privileges");
|
||||
return;
|
||||
}
|
||||
if (landlock_restrict_self(ruleset_fd, 0)) {
|
||||
print_message(msg_config_error, "Landlock: Failed to enforce ruleset");
|
||||
return;
|
||||
}
|
||||
close(ruleset_fd);
|
||||
|
||||
print_message(msg_config, "Landlock: all restricted\n");
|
||||
}
|
||||
|
||||
#else /* HAVE_LANDLOCK */
|
||||
void setup_landlock(void)
|
||||
{
|
||||
print_message(msg_config, "Landlock: not built in\n");
|
||||
return;
|
||||
}
|
||||
#endif /* HAVE_LANDLOCK */
|
||||
+27
-4
@@ -1,5 +1,5 @@
|
||||
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
|
||||
* on Sun Sep 11 21:43:25 2022.
|
||||
* on Tue Jan 2 21:25:47 2024.
|
||||
|
||||
# conf2struct: generate libconf parsers that read to structs
|
||||
# Copyright (C) 2018-2021 Yves Rutschle
|
||||
@@ -365,7 +365,7 @@ static int clcpy(config_type type, void* target, const void* cl_arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy the value of a string argument to arbitrary memory
|
||||
/* Copy the value of a string argument to arbitary memory
|
||||
* location that must be large enough, converting on the way
|
||||
* (i.e. CFG_INT gets atoi() and so on) */
|
||||
/* 0: success
|
||||
@@ -471,6 +471,7 @@ struct arg_file* sslhcfg_conffile;
|
||||
struct arg_str* sslhcfg_listen;
|
||||
struct arg_str* sslhcfg_ssh;
|
||||
struct arg_str* sslhcfg_tls;
|
||||
struct arg_str* sslhcfg_ssl;
|
||||
struct arg_str* sslhcfg_openvpn;
|
||||
struct arg_str* sslhcfg_tinc;
|
||||
struct arg_str* sslhcfg_wireguard;
|
||||
@@ -1333,6 +1334,15 @@ static struct compound_cl_target sslhcfg_openvpn_targets [] = {
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static struct compound_cl_target sslhcfg_ssl_targets [] = {
|
||||
{ & table_sslhcfg_protocols[0], 0, .value.def_string = "tls" },
|
||||
{ & table_sslhcfg_protocols[1], 1, .value.def_string = "0" },
|
||||
{ & table_sslhcfg_protocols[2], 2, .value.def_string = "0" },
|
||||
{ & table_sslhcfg_protocols[10], 0, .value.def_int = 1 },
|
||||
{ & table_sslhcfg_protocols[7], 0, .value.def_bool = 1 },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static struct compound_cl_target sslhcfg_tls_targets [] = {
|
||||
{ & table_sslhcfg_protocols[0], 0, .value.def_string = "tls" },
|
||||
{ & table_sslhcfg_protocols[1], 1, .value.def_string = "0" },
|
||||
@@ -1395,6 +1405,18 @@ static struct compound_cl_arg compound_cl_args[] = {
|
||||
.override_const = "tls",
|
||||
},
|
||||
|
||||
{ /* arg: ssl */
|
||||
.regex = "(.+):(\\w+)",
|
||||
.arg_cl = & sslhcfg_ssl,
|
||||
.base_entry = & table_sslhcfg [26],
|
||||
.targets = sslhcfg_ssl_targets,
|
||||
|
||||
|
||||
.override_desc = & table_sslhcfg_protocols [0],
|
||||
.override_matchindex = 0,
|
||||
.override_const = "tls",
|
||||
},
|
||||
|
||||
{ /* arg: openvpn */
|
||||
.regex = "(.+):(\\w+)",
|
||||
.arg_cl = & sslhcfg_openvpn,
|
||||
@@ -1818,7 +1840,7 @@ static int set_target_fields(void* target_addr, struct compound_cl_arg* arg, con
|
||||
if (pmatch[pmatch_cnt].rm_so == -1) {
|
||||
/* This should not happen as regexec() did
|
||||
* match before, unless there is a
|
||||
* discrepancy between the regex and the
|
||||
* discrepency between the regex and the
|
||||
* number of backreferences */
|
||||
return 0;
|
||||
}
|
||||
@@ -2111,7 +2133,7 @@ static void scalar_to_string(char** strp, config_setting_t* s)
|
||||
|
||||
/* Typesets all the settings in a configuration as a
|
||||
* newly-allocated string. The string management is caller's
|
||||
* responsibility.
|
||||
* responsability.
|
||||
* Returns the number of scalars in the configuration */
|
||||
static int cfg_as_string(config_setting_t* parent, const char* path, char** strp)
|
||||
{
|
||||
@@ -2199,6 +2221,7 @@ int sslhcfg_cl_parse(int argc, char* argv[], struct sslhcfg_item* cfg)
|
||||
sslhcfg_listen = arg_strn("p", "listen", "<host:port>", 0, 10, "Listen on host:port"),
|
||||
sslhcfg_ssh = arg_strn(NULL, "ssh", "<host:port>", 0, 10, "Set up ssh target"),
|
||||
sslhcfg_tls = arg_strn(NULL, "tls", "<host:port>", 0, 10, "Set up TLS/SSL target"),
|
||||
sslhcfg_ssl = arg_strn(NULL, "ssl", "<host:port>", 0, 10, "Set up TLS/SSL target"),
|
||||
sslhcfg_openvpn = arg_strn(NULL, "openvpn", "<host:port>", 0, 10, "Set up OpenVPN target"),
|
||||
sslhcfg_tinc = arg_strn(NULL, "tinc", "<host:port>", 0, 10, "Set up tinc target"),
|
||||
sslhcfg_wireguard = arg_strn(NULL, "wireguard", "<host:port>", 0, 10, "Set up WireGuard target"),
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
|
||||
* on Sun Sep 11 21:43:25 2022.
|
||||
* on Tue Jan 2 21:25:47 2024.
|
||||
|
||||
# conf2struct: generate libconf parsers that read to structs
|
||||
# Copyright (C) 2018-2021 Yves Rutschle
|
||||
|
||||
+21
@@ -178,6 +178,25 @@ void tcp_listener(struct listen_endpoint* endpoint, int num_endpoints, int activ
|
||||
while (1) {
|
||||
in_socket = accept(endpoint[active_endpoint].socketfd, 0, 0);
|
||||
CHECK_RES_RETURN(in_socket, "accept", /*void*/ );
|
||||
if (in_socket == -1) {
|
||||
print_message(msg_system_error, "%s:%d:%s:%d:%s\n",
|
||||
__FILE__, __LINE__, "accept", errno, strerror(errno));
|
||||
switch(in_socket) {
|
||||
case ENETDOWN: /* accept(2) cites all these errnos as "you should retry" */
|
||||
case EPROTO:
|
||||
case ENOPROTOOPT:
|
||||
case EHOSTDOWN:
|
||||
case ENONET:
|
||||
case EHOSTUNREACH:
|
||||
case EOPNOTSUPP:
|
||||
case ENETUNREACH:
|
||||
case ECONNABORTED:
|
||||
continue;
|
||||
|
||||
default: /* Otherwise, it's something wrong in our parameters, we fail */
|
||||
return;
|
||||
}
|
||||
}
|
||||
print_message(msg_fd, "accepted fd %d\n", in_socket);
|
||||
|
||||
switch(fork()) {
|
||||
@@ -224,6 +243,8 @@ void main_loop(struct listen_endpoint listen_sockets[], int num_addr_listen)
|
||||
print_message(msg_config_error, "UDP not (yet?) supported in sslh-fork\n");
|
||||
else
|
||||
tcp_listener(listen_sockets, num_addr_listen, i);
|
||||
|
||||
exit(0);
|
||||
break;
|
||||
|
||||
/* We're in the parent, we don't need to do anything */
|
||||
|
||||
@@ -283,6 +283,7 @@ int main(int argc, char *argv[], char* envp[])
|
||||
|
||||
if (cfg.user || cfg.chroot)
|
||||
drop_privileges(cfg.user, cfg.chroot);
|
||||
setup_landlock();
|
||||
|
||||
printcaps();
|
||||
|
||||
|
||||
@@ -186,6 +186,19 @@ cl_groups: (
|
||||
{ path: "tfo_ok"; value: 1 }
|
||||
);
|
||||
},
|
||||
# Redundant with the --tls setting before, for backwards compatibility
|
||||
{ name: "ssl"; pattern: "(.+):(\w+)"; description: "Set up TLS/SSL target";
|
||||
list: "protocols";
|
||||
override: "name";
|
||||
argdesc: "<host:port>";
|
||||
targets: (
|
||||
{ path: "name"; value: "tls" },
|
||||
{ path: "host"; value: "$1" },
|
||||
{ path: "port"; value: "$2" },
|
||||
{ path: "log_level"; value: 1 },
|
||||
{ path: "tfo_ok"; value: 1 }
|
||||
);
|
||||
},
|
||||
{ name: "openvpn"; pattern: "(.+):(\w+)"; description: "Set up OpenVPN target";
|
||||
list: "protocols";
|
||||
override: "name";
|
||||
|
||||
+11
-8
@@ -36,10 +36,10 @@
|
||||
|
||||
static int cnx_cmp(struct connection* cnx1, struct connection* cnx2)
|
||||
{
|
||||
struct sockaddr* addr1 = &cnx1->client_addr;
|
||||
struct sockaddr_storage* addr1 = &cnx1->client_addr;
|
||||
socklen_t addrlen1 = cnx1->addrlen;
|
||||
|
||||
struct sockaddr* addr2 = &cnx2->client_addr;
|
||||
struct sockaddr_storage* addr2 = &cnx2->client_addr;
|
||||
socklen_t addrlen2 = cnx2->addrlen;
|
||||
|
||||
if (addrlen1 != addrlen2) return -1;
|
||||
@@ -52,13 +52,13 @@ static int cnx_cmp(struct connection* cnx1, struct connection* cnx2)
|
||||
* lowest bytes of remote port */
|
||||
static int hash_make_key(hash_item new)
|
||||
{
|
||||
struct sockaddr* addr = &new->client_addr;
|
||||
struct sockaddr_storage* addr = &new->client_addr;
|
||||
//socklen_t addrlen = new->addrlen;
|
||||
struct sockaddr_in* addr4;
|
||||
struct sockaddr_in6* addr6;
|
||||
int out;
|
||||
|
||||
switch (addr->sa_family) {
|
||||
switch (((struct sockaddr*)addr)->sa_family) {
|
||||
case AF_INET:
|
||||
addr4 = (struct sockaddr_in*)addr;
|
||||
out = addr4->sin_port;
|
||||
@@ -225,13 +225,16 @@ static void mark_active(struct connection* cnx)
|
||||
/* Creates a new non-blocking socket */
|
||||
static int nonblocking_socket(struct sslhcfg_protocols_item* proto)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (proto->resolve_on_forward) {
|
||||
resolve_split_name(&(proto->saddr), proto->host,
|
||||
proto->port);
|
||||
res = resolve_split_name(&(proto->saddr), proto->host,
|
||||
proto->port);
|
||||
if (res) return -1;
|
||||
}
|
||||
|
||||
int out = socket(proto->saddr->ai_family, SOCK_DGRAM, 0);
|
||||
int res = set_nonblock(out);
|
||||
res = set_nonblock(out);
|
||||
if (res == -1) {
|
||||
print_message(msg_system_error, "%s:%d:%s:%d:%s\n", __FILE__, __LINE__, "udp:socket:nonblock", errno, strerror(errno));
|
||||
close(out);
|
||||
@@ -327,7 +330,7 @@ void udp_s2c_forward(struct connection* cnx)
|
||||
if ((res == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) return;
|
||||
CHECK_RES_DIE(res, "udp_listener/recvfrom");
|
||||
res = sendto(cnx->local_endpoint, data, res, 0,
|
||||
&cnx->client_addr, cnx->addrlen);
|
||||
(struct sockaddr*)&cnx->client_addr, cnx->addrlen);
|
||||
mark_active(cnx);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user