Initial commit

This commit is contained in:
WatermelonModders
2022-05-31 12:35:46 -04:00
commit fc5cb0c32c
4097 changed files with 447075 additions and 0 deletions
+25
View File
@@ -0,0 +1,25 @@
Copyright 2012 Bump Technologies, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list
of conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED BY BUMP TECHNOLOGIES, INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BUMP TECHNOLOGIES, INC. OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those of the
authors and should not be interpreted as representing official policies, either expressed
or implied, of Bump Technologies, Inc.
+52
View File
@@ -0,0 +1,52 @@
# [g]make USE_xxxx=1
#
# USE_SHARED_CACHE : enable/disable a shared session cache (disabled by default)
DESTDIR =
PREFIX = /usr/local
BINDIR = $(PREFIX)/bin
MANDIR = $(PREFIX)/share/man
CFLAGS = -O2 -g -std=c99 -fno-strict-aliasing -Wall -W -D_GNU_SOURCE -I/usr/local/include
LDFLAGS = -lssl -lcrypto -lev -L/usr/local/lib
OBJS = stud.o ringbuffer.o configuration.o
all: realall
# Shared cache feature
ifneq ($(USE_SHARED_CACHE),)
CFLAGS += -DUSE_SHARED_CACHE -DUSE_SYSCALL_FUTEX
OBJS += shctx.o ebtree/libebtree.a
ALL += ebtree
ebtree/libebtree.a: $(wildcard ebtree/*.c)
make -C ebtree
ebtree:
@[ -d ebtree ] || ( \
echo "*** Download libebtree at http://1wt.eu/tools/ebtree/" ; \
echo "*** Untar it and make a link named 'ebtree' to point on it"; \
exit 1 )
endif
# No config file support?
ifneq ($(NO_CONFIG_FILE),)
CFLAGS += -DNO_CONFIG_FILE
endif
ALL += stud
realall: $(ALL)
stud: $(OBJS)
$(CC) -o $@ $^ $(LDFLAGS)
install: $(ALL)
install -d $(DESTDIR)$(BINDIR)
install stud $(DESTDIR)$(BINDIR)
install -d $(DESTDIR)$(MANDIR)/man8
install -m 644 stud.8 $(DESTDIR)$(MANDIR)/man8
clean:
rm -f stud $(OBJS)
.PHONY: all realall
+191
View File
@@ -0,0 +1,191 @@
STATUS
======
Stud is now officially abandonware, thanks for playing.
Recommended alternative: https://github.com/varnish/hitch
More info: https://blog.jamwt.com/2016/03/21/stud-no-more/
stud - The Scalable TLS Unwrapping Daemon
=========================================
`stud` is a network proxy that terminates TLS/SSL connections and forwards the
unencrypted traffic to some backend. It's designed to handle 10s of thousands of
connections efficiently on multicore machines.
It follows a process-per-core model; a parent process spawns N children who
each `accept()` on a common socket to distribute connected clients among them.
Within each child, asynchronous socket I/O is conducted across the local
connections using `libev` and `OpenSSL`'s nonblocking API. By default,
`stud` has an overhead of ~200KB per connection--it preallocates
some buffer space for data in flight between frontend and backend.
`stud` has very few features--it's designed to be paired with an intelligent
backend like haproxy or nginx. It maintains a strict 1:1 connection pattern
with this backend handler so that the backend can dictate throttling behavior,
maxmium connection behavior, availability of service, etc.
`stud` will optionally write the client IP address as the first few octets
(depending on IPv4 or IPv6) to the backend--or provide that information
using HAProxy's PROXY protocol. When used with the PROXY protocol, `stud` can
also transparently pass an existing PROXY header to the cleartext stream. This
is especially useful if a TCP proxy is used in front of `stud`. Using either of
these techniques, backends who care about the client IP can still access it even
though `stud` itself appears to be the connected client.
Thanks to a contribution from Emeric at Exceliance (the folks behind HAProxy),
a special build of `stud` can be made that utilitizes shared memory to
use a common session cache between all child processes. This can speed up
large `stud` deployments by avoiding client renegotiation.
Releases
---------
Please be aware of the policy regarding releases, code stability, and security:
* In git, the tip of the master branch should always build on Linux and
FreeBSD, and is likely to be as stable as any other changeset. A
careful review of patches is conducted before being pushed to github.
* Periodically, a version tag will be pushed to github for an old(er)
changeset--0.1, 0.2, etc. These tags mark a particular release of
`stud` that has seen heavy testing and several weeks of production
stability. Conservative users are advised to use a tag.
* `stud` has an optional build that utilizes shared memory-based SSL contexts
and UDP peer communication to keep a session cache between many child processes
running on many machines. The use of this build can dramatically speed
up SSL handshakes on many-core and/or clustered deployments.
However, it's important to acknowledge the inevitable theoretical
security tradeoffs associated with the use of this (substantially more
complex) binary. Therefore, the deeply paranoid are advised to use
only the standard `stud` binary at the cost of some performance.
Requirements and Limitations
----------------------------
`stud` requires:
libev >= 4
openssl (recent, >=1.0.0 recommended)
Stud currently works on Linux, OpenBSD, FreeBSD, and MacOSX.
It has been tested the most heavily on Linux/x86_64.
While porting it to other POSIX platforms is likely trivial, it hasn't be done
yet. Patches welcome!
If you're handling a large number of connections, you'll
probably want to raise `ulimit -n` before running `stud`.
It's very strongly recommended to not run `stud` as root; ideally, it would
be run as a user ("stud", perhaps) that does nothing but run `stud`. Stud
will setuid (using -u) after binding if you need to bind to a low port (< 1024).
Installing
----------
To install `stud`:
$ make
$ sudo make install
Usage
-----
The only required argument is a path to a PEM file that contains the certificate
(or a chain of certificates) and private key. If multiple certificates are
given, `stud` will attempt to perform SNI (Server Name Indication) on new
connections, by comparing the indicated name with the names on each of the
certificates, in order. The first certificate that matches will be used. If none
of the certificates matches, the last certificate will be used as the default.
Detail about the entire set of options can be found by invoking `stud -h`:
CONFIGURATION:
--config=FILE Load configuration from specified file.
--default-config Prints default configuration to stdout.
ENCRYPTION METHODS:
--tls TLSv1 (default)
--ssl SSLv3 (implies no TLSv1)
-c --ciphers=SUITE Sets allowed ciphers (Default: "")
-e --ssl-engine=NAME Sets OpenSSL engine (Default: "")
-O --prefer-server-ciphers Prefer server list order
SOCKET:
-b --backend=HOST,PORT Backend [connect] (default is "[127.0.0.1]:8000")
-f --frontend=HOST,PORT Frontend [bind] (default is "[*]:8443")
PERFORMANCE:
-n --workers=NUM Number of worker processes (Default: 1)
-B --backlog=NUM Set listen backlog size (Default: 100)
-k --keepalive=SECS TCP keepalive on client socket (Default: 3600)
SECURITY:
-r --chroot=DIR Sets chroot directory (Default: "")
-u --user=USER Set uid/gid after binding the socket (Default: "")
-g --group=GROUP Set gid after binding the socket (Default: "")
LOGGING:
-q --quiet Be quiet; emit only error messages
-s --syslog Send log message to syslog in addition to stderr/stdout
--syslog-facility=FACILITY Syslog facility to use (Default: "daemon")
OTHER OPTIONS:
--daemon Fork into background and become a daemon (Default: off)
--write-ip Write 1 octet with the IP family followed by the IP
address in 4 (IPv4) or 16 (IPv6) octets little-endian
to backend before the actual data
(Default: off)
--write-proxy Write HaProxy's PROXY (IPv4 or IPv6) protocol line
before actual data
(Default: off)
--proxy-proxy Proxy HaProxy's PROXY (IPv4 or IPv6) protocol line
before actual data
(Default: off)
-t --test Test configuration and exit
-V --version Print program version and exit
-h --help This help message
Configuration File
------------------
Stud can also use a configuration file that supports all the same options as the
command-line arguments. You can use `stud --default-config` to
generate the default configuration on stdout; then, customize your configuration and
pass it to `stud --config=FILE`.
Serving HTTPS
-------------
If you're using `stud` for HTTPS, please make sure to use the `--ssl` option!
DiffieHellman
--------------
To use DH with stud, you will need to add some bytes to your pem file:
% openssl dhparam -rand - 1024 >> PEMFILE
Be sure to set your cipher suite appropriately: -c DHE-RSA-AES256-SHA
Authors
-------
`stud` was originally written by Jamie Turner (@jamwt) and is maintained
by the Bump (http://bu.mp) server team. It currently (12/11) provides
server-side TLS termination for over 85 million Bump users.
Special thanks to Colin Percival (@cperciva) for an early security
audit and code review.
Finally, thank you to all the stud contributors, who have taken the
program from a good start to a solid project:
https://github.com/bumptech/stud/contributors
+8
View File
@@ -0,0 +1,8 @@
#!/bin/sh
openssl genrsa -out test.com.key 1024
openssl req -new -key test.com.key -out test.com.csr
openssl x509 -req -days 365 -in test.com.csr -signkey test.com.key -out test.com.crt
cat test.com.key test.com.crt > openssl genrsa -out test.com.key 1024
openssl req -new -key test.com.key -out test.com.csr
openssl x509 -req -days 365 -in test.com.csr -signkey test.com.key -out test.com.crt
cat test.com.key test.com.crt > test.com.pem
File diff suppressed because it is too large Load Diff
+80
View File
@@ -0,0 +1,80 @@
/**
* configuration.h
*
* Author: Brane F. Gracnar
*
*/
#include <sys/types.h>
#ifdef USE_SHARED_CACHE
#include "shctx.h"
#ifndef MAX_SHCUPD_PEERS
#define MAX_SHCUPD_PEERS 15
#endif
typedef struct shcupd_peer_opt {
char *ip;
char *port;
} shcupd_peer_opt;
#endif
typedef enum {
ENC_TLS,
ENC_SSL
} ENC_TYPE;
typedef enum {
SSL_SERVER,
SSL_CLIENT
} PROXY_MODE;
struct cert_files {
char *CERT_FILE;
struct cert_files *NEXT;
};
/* configuration structure */
struct __stud_config {
ENC_TYPE ETYPE;
PROXY_MODE PMODE;
int WRITE_IP_OCTET;
int WRITE_PROXY_LINE;
int PROXY_PROXY_LINE;
char *CHROOT;
uid_t UID;
gid_t GID;
char *FRONT_IP;
char *FRONT_PORT;
char *BACK_IP;
char *BACK_PORT;
long NCORES;
struct cert_files *CERT_FILES;
char *CIPHER_SUITE;
char *ENGINE;
int BACKLOG;
#ifdef USE_SHARED_CACHE
int SHARED_CACHE;
char *SHCUPD_IP;
char *SHCUPD_PORT;
shcupd_peer_opt SHCUPD_PEERS[MAX_SHCUPD_PEERS+1];
char *SHCUPD_MCASTIF;
char *SHCUPD_MCASTTTL;
#endif
int QUIET;
int SYSLOG;
int SYSLOG_FACILITY;
int TCP_KEEPALIVE_TIME;
int DAEMONIZE;
int PREFER_SERVER_CIPHERS;
};
typedef struct __stud_config stud_config;
char * config_error_get (void);
stud_config * config_new (void);
void config_destroy (stud_config *cfg);
int config_file_parse (char *file, stud_config *cfg);
void config_parse_cli(int argc, char **argv, stud_config *cfg);
+6
View File
@@ -0,0 +1,6 @@
stud (0.3~0.20111212) unstable; urgency=low
* Initial release.
-- Charlie Root <root@interseek.com> Mon, 12 Dec 2011 13:24:18 +0100
+1
View File
@@ -0,0 +1 @@
7
+26
View File
@@ -0,0 +1,26 @@
Source: stud
Section: universe/net
Priority: optional
Maintainer: Charlie Root <root@example.com>
Build-Depends: debhelper (>= 7.0.50~)
Standards-Version: 3.9.2
Homepage: https://github.com/bumptech/stud
Package: stud
Section: universe/net
Priority: optional
Architecture: any
Depends: libc6 (>= 2.4), libev4 (>= 1:4.04), libssl0.9.8 (>= 0.9.8k-1) | libssl1.0.0 (>= 1.0.0e-1)
# Depends: ${shlibs:Depends}, ${misc:Depends}
Description: The Scalable TLS Unwrapping Daemon
stud is a network proxy that terminates TLS/SSL connections and forwards
the unencrypted traffic to some backend. It's designed to handle 10s of
thousands of connections efficiently on multicore machines.
.
It follows a process-per-core model; a parent process spawns N children who
each accept() on a common socket to distribute connected clients among them.
Within each child, asynchronous socket I/O is conducted across the local
connections using libev and OpenSSL's nonblocking API. By default, stud
has an overhead of ~200KB per connection--it preallocates some buffer space
for data in flight between frontend and backend.
+25
View File
@@ -0,0 +1,25 @@
Copyright 2011 Bump Technologies, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list
of conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED BY BUMP TECHNOLOGIES, INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BUMP TECHNOLOGIES, INC. OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those of the
authors and should not be interpreted as representing official policies, either expressed
or implied, of Bump Technologies, Inc.
+43
View File
@@ -0,0 +1,43 @@
#!/bin/sh
case $1 in
# Configure this package. If the package must prompt the user for
# information, do it here.
configure)
mkdir -p /var/run/stud
;;
# Back out of an attempt to upgrade this package FROM THIS VERSION
# to version $2. Undo the effects of "prerm upgrade $2".
abort-upgrade)
;;
# Back out of an attempt to remove this package, which was due to
# a conflict with package $3 (version $4). Undo the effects of
# "prerm remove in-favour $3 $4".
abort-remove)
;;
# Back out of an attempt to deconfigure this package, which was
# due to package $6 (version $7) which we depend on being removed
# to make way for package $3 (version $4). Undo the effects of
# "prerm deconfigure in-favour $3 $4 removing $6 $7".
abort-deconfigure)
;;
*)
echo "$0: didn't understand being called with \`$1'" 1>&2
exit 1;
;;
esac
if service stud status >/dev/null 2>&1; then
echo
echo " !!!! WARNING !!!!"
echo
echo "stud is running, you should restart it."
echo
fi
# EOF
+34
View File
@@ -0,0 +1,34 @@
#!/bin/sh
case "$1" in
remove|purge|abort-install|abort-upgrade)
# This package is being removed, but its configuration has not yet
# been purged.
# stud shouldn't start at system startup
# update-rc.d -f stud remove
# remove rundir
rm -rf /var/run/stud >/dev/null 2>&1
# remove config dir
rm -rf /etc/stud >/dev/null 2>&1
;;
disappear)
;;
upgrade)
;;
failed-upgrade)
;;
*) echo "$0: didn't understand being called with \`$1'" 1>&2
exit 1;;
esac
exit 0
# EOF
+28
View File
@@ -0,0 +1,28 @@
#!/bin/sh
case "$1" in
remove|purge|abort-install|abort-upgrade)
# This package is being removed, but its configuration has not yet
# been purged.
# shutdown service
service stud stop
;;
disappear)
;;
upgrade)
;;
failed-upgrade)
;;
*) echo "$0: didn't understand being called with \`$1'" 1>&2
exit 1;;
esac
exit 0
# EOF
+33
View File
@@ -0,0 +1,33 @@
#!/usr/bin/make -f
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
override_dh_auto_clean:
rm -rf ebtree
make clean
override_dh_auto_configure:
if [ ! -f ebtree-6.0.6.tar.gz ]; then wget http://1wt.eu/tools/ebtree/ebtree-6.0.6.tar.gz; fi
if [ ! -d ebtree ]; then tar zxpf ebtree-6.0.6.tar.gz; mv ebtree-6.0.6 ebtree; fi
override_dh_auto_build:
make USE_SHARED_CACHE=1 PREFIX=/usr
override_dh_auto_install:
dh_testdir
dh_testroot
dh_prep
dh_installdirs
make install DESTDIR=$(CURDIR)/debian/stud PREFIX=/usr
# create stud instance configuration directory
mkdir -p $(CURDIR)/debian/stud/etc/stud
chown -R root:root $(CURDIR)/debian/stud/etc/stud
chmod 700 $(CURDIR)/debian/stud/etc/stud
echo "Run /etc/init.d/stud --sample-config > /etc/stud/something.conf for default instance configuration" >> "$(CURDIR)/debian/stud/etc/stud/README.TXT"
%:
dh $@
# EOF
+7
View File
@@ -0,0 +1,7 @@
openssl genrsa -out test.com.key 1024
penssl req -new -key test.com.key -out test.com.csr
openssl x509 -req -days 365 -in test.com.csr -signkey test.com.key -out test.com.crt
cat test.com.key test.com.crt > openssl genrsa -out test.com.key 1024
openssl req -new -key test.com.key -out test.com.csr
openssl x509 -req -days 365 -in test.com.csr -signkey test.com.key -out test.com.crt
cat test.com.key test.com.crt > test.com.pem
+837
View File
@@ -0,0 +1,837 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: stud
# Required-Start: $local_fs $remote_fs
# Required-Stop: $local_fs $remote_fs
# Should-Start: $syslog
# Should-Stop: $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start or stop stud (SSL offloader)
### END INIT INFO
#######################################################
# GLOBALS #
#######################################################
# instance configuration directory
CONFIG_DIR="/etc/stud"
# Runtime directory data
RUNTIME_DIR="/var/run/stud"
#######################################################
#######################################################
stud_single_instance_config_reset() {
#######################################################
# stud instance configuration #
#######################################################
# stud listening address
FRONTEND_ADDRESS="*,8443"
# upstream service address
BACKEND_ADDRESS="127.0.0.1,80"
# x509 certificate file
CERT_FILE=""
# TLS only service? Don't set this to 1 if you're
# offloading HTTPS.
TLS_ONLY="0"
# cipher suite (run openssl ciphers for full list)
CIPHER_SUITE="HIGH"
# OpenSSL engine
ENGINE=""
# Number of worker processes
WORKERS="1"
# Listen backlog
BACKLOG=""
# Chroot directory
CHROOT_DIR=""
# drop privileges and run as specified
# user if set
SETUID_USER=""
# use shared cache with specified number of sessions
# WARNING: stud must be compiled with USE_SHARED_CACHE=1
SHARED_CACHE_SESSIONS="0"
# Accept cache updates on specified address
#
# syntax: HOST,PORT
#
# WARNING: stud must be compiled with USE_SHARED_CACHE=1
# SHARED_CACHE_SESSIONS must be >= 1
CACHE_UPDATE_ACCEPT=""
# Send cache updates to specified list space separated peers
#
# syntax: HOST1,PORT HOST2,PORT
#
# WARNING: stud must be compiled with USE_SHARED_CACHE=1
# and CACHE_UPDATE_ACCEPT must be defined
CACHE_UPDATE_SEND=""
# Force network interface and ttl to receive and send multicast
# cache updates
#
# syntax: IFACE[,TTL]
#
# WARNING: stud must be compiled with USE_SHARED_CACHE=1
# and CACHE_UPDATE_ACCEPT must be defined
CACHE_UPDATE_IFACE=""
# default tcp keepalive on client socket in seconds
CLIENT_TCP_KEEPALIVE_SEC=""
# log to syslog?
SYSLOG="1"
# Enable write-ip?
WRITE_IP="0"
# Enable SENDPROXY protocol; see
# http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt
# for additional info
WRITE_PROXY="0"
# Alternative OpenSSL library dir
# Use this if you'd like to run stud with different
# version of OpenSSL library
OPENSSL_LIB_DIR=""
# Semicolon separated list of process affinities; requires
# taskset(8) utility.
#
# SYNTAX:
# "<process_number>:<affinity>;<process_number2>:<affinity2>;..."
#
# <process_number>: stud worker process number, starting with 1
# <affinity>: process affinity, see taskset(8) for details
#
# EXAMPLES:
#
# "1:0" => bind first process to CPU0
#
# "1:0;2:3-4;3:5;4:7" => bind first worker process to CPU0,
# second worker process to CPU3 and CPU4,
# third worker process to CPU5 and fourth
# worker process to CPU7
PROCESS_AFFINITY=""
# Process priority (integer between -19 to 19)
# lower value means higher priority
#
PROCESS_PRIORITY=""
# ulimit -n value before starting single stud instance
#
# Comment out or set to 0 to disable ulimit -n
# setup.
#
ULIMIT_N=""
# Additional stud command line options
#
# NOTE: set this only if you really know what your're
# doing
#
# ADDITIONAL_STUD_OPT=""
# EOF
}
PATH="${PATH}:."
INSTANCE_NAME=""
STUD=`which stud 2>/dev/null`
die() {
msg_log "FATAL: $@"
echo "FATAL: $@" 1>&2
exit 1
}
msg_log() {
ident="stud"
test ! -z "${INSTANCE_NAME}" && ident="${ident}/${INSTANCE_NAME}"
logger -i -t "${ident}" "$@" >/dev/null 2>&1
}
msg_err() {
msg_log "ERROR: $@"
}
_real_single_instance_start() {
# check stud binary
if [ -z "${STUD}" ] || [ ! -f "${STUD}" ] || [ ! -x "${STUD}" ]; then
die "Invalid stud binary: '${STUD}'"
fi
# generate stud command line options
opts="-f ${FRONTEND_ADDRESS}"
opts="${opts} -b ${BACKEND_ADDRESS}"
if [ "${TLS_ONLY}" = "1" ]; then
opts="${opts} --tls"
else
opts="${opts} --ssl"
fi
test ! -z "${CIPHER_SUITE}" && opts="${opts} -c ${CIPHER_SUITE}"
test ! -z "${ENGINE}" && opts="${opts} -e ${ENGINE}"
if [ ! -z "${WORKERS}" ] && [ ${WORKERS} -gt 0 ]; then
opts="${opts} -n ${WORKERS}"
fi
if [ ! -z "${BACKLOG}" ] && [ ${BACKLOG} -gt 0 ]; then
opts="${opts} -B ${BACKLOG}"
fi
if [ ! -z "${CLIENT_TCP_KEEPALIVE_SEC}" ] && [ ${CLIENT_TCP_KEEPALIVE_SEC} -gt 0 ]; then
opts="${opts} -k ${CLIENT_TCP_KEEPALIVE_SEC}"
fi
# shared cache sessions...
if [ ! -z "${SHARED_CACHE_SESSIONS}" ] && [ ${SHARED_CACHE_SESSIONS} -gt 0 ]; then
opts="${opts} -C ${SHARED_CACHE_SESSIONS}"
# shared cache stuff
if [ ! -z "${CACHE_UPDATE_ACCEPT}" ]; then
opts="${opts} -U ${CACHE_UPDATE_ACCEPT}"
c_u=0
for h in ${CACHE_UPDATE_SEND}; do
test ! -z "${h}" || continue
opts="${opts} -P ${h}"
c_u=$((c_u + 1))
done
if [ ${c_u} -lt 1 ]; then
die "Cache updates are enabled but CACHE_UPDATE_SEND option seems to be empty."
fi
if [ ! -z "${CACHE_UPDATE_IFACE}" ]; then
opts="${opts} -M ${CACHE_UPDATE_IFACE}"
fi
fi
fi
# chroot?
test ! -z "${CHROOT_DIR}" && opts="${opts} -r ${CHROOT_DIR}"
test ! -z "${SETUID_USER}" && opts="${opts} -u ${SETUID_USER}"
opts="${opts} -q"
test "${SYSLOG}" = "1" && opts="${opts} -s"
test "${WRITE_IP}" = "1" && opts="${opts} --write-ip"
test "${WRITE_PROXY}" = "1" && opts="${opts} --write-proxy"
if [ ! -z "${CERT_FILE}" ] && [ -f "${CERT_FILE}" ] && [ -r "${CERT_FILE}" ]; then
opts="${opts} ${CERT_FILE}"
else
die "Invalid or unreadable certificate file '${CERT_FILE}'."
fi
# additional command line options?!
if [ ! -z "${ADDITIONAL_STUD_OPT}" ]; then
opts="${opts} ${ADDITIONAL_STUD_OPT}"
fi
# priority?!
prefix=""
if [ ! -z "${PROCESS_PRIORITY}" ]; then
prefix="nice -n ${PROCESS_PRIORITY}"
fi
# we want to start stud in a daemon mode...
opts="${opts} --daemon"
# set ulimits!
ulimit_set || die "Unable to set stud runtime limits."
# disable linker stuff
unset LD_LIBRARY_PATH
# set new lib path if requested
if [ ! -z "${OPENSSL_LIB_DIR}" -a -d "${OPENSSL_LIB_DIR}" ]; then
LD_LIBRARY_PATH="${OPENSSL_LIB_DIR}"
export LD_LIBRARY_PATH
fi
# start stud!
msg_log "Starting instance '${INSTANCE_NAME}': ${STUD} ${opts}"
out=`${prefix} ${STUD} ${opts} 2>&1`
# remove lib path
unset LD_LIBRARY_PATH
# check invocation
stud_pid=`echo "${out}" | tail -n 1 | cut -d " " -f5 | tr -d '.'`
if [ -z "${stud_pid}" ]; then
die "Empty stud pid. This is extremely weird."
fi
# wait a little bit, check if pid is still alive
sleep 0.2 >/dev/null 2>&1
if ! kill -0 "${stud_pid}" >/dev/null 2>&1; then
die "Stud started successfully as pid ${stud_pid} but died shortly after startup.";
fi
# write pid file!
pid_file_write "${INSTANCE_NAME}" "${stud_pid}" || msg_warn "${Error}"
# set affinity!
stud_affinity_set "${stud_pid}" || die "${Error}"
}
stud_single_instance_start() {
name="${1}"
if [ -z "${name}" ]; then
Error="Unable to stop undefined stud instance."
return 1
fi
# check if it is running
if stud_single_instance_status "${name}"; then
Error="Instance ${name} is already running as pid ${Error}."
return 1
fi
# do the real stuff...
Error=""
out=`_real_single_instance_start 2>&1`
rv=$?
if [ "${rv}" != "0" ]; then
Error="${out}"
rv=1
fi
# this is it! :)
return $rv
}
stud_single_instance_stop() {
name="${1}"
if [ -z "${name}" ]; then
Error="Unable to stop undefined stud instance."
return 1
fi
# check if it is running
stud_single_instance_status "${name}" || return 1
# time to stop instance
pid="${Error}"
msg_log "Stopping stud instance '${name}', pid ${pid}."
ok=0
if ! kill "${pid}" >/dev/null 2>&1; then
Error="Unable to stop instance: unable to kill pid ${pid}."
return 1
fi
# wait for termination
i=0
while [ ${i} -lt 9 ]; do
i=$((i + 1))
# are you dead yet?
if ! kill -0 "${pid}" >/dev/null 2>&1; then
ok=1
break
fi
sleep 0.1 >/dev/null 2>&1
done
# not ok?! try to with headshot...
if [ "${ok}" != "1" ]; then
msg_log "Gentle stop of instance ${name} failed, trying to stop it with SIGKILL."
if ! kill -9 "${pid}"; then
Error="Unable to stop instance ${name}: kill(1) failed."
return 1
fi
fi
return 0
}
stud_single_instance_restart() {
name="${1}"
if [ -z "${name}" ]; then
Error="Unable to stop undefined stud instance."
return 1
fi
# maybe we need to stop it first...
if stud_single_instance_status "${name}"; then
stud_single_instance_stop "${name}" || return 1
fi
# start it back...
Error=""
stud_single_instance_start "${name}"
}
stud_single_instance_status() {
Error=""
if [ -z "${1}" ]; then
Error="Invalid instance name."
return 1
fi
# get pid file...
pid=`pid_file_read "${1}"`
# check it...
if [ -z "${pid}" ] || ! kill -0 "${pid}" >/dev/null 2>&1; then
Error="Instance '${1}' is stopped."
return 1
fi
# set pid to Error
Error="${pid}"
return 0
}
# reads pid file of specific instance
pid_file_read() {
test -z "${1}" && return 1
file="${RUNTIME_DIR}/${1}.pid"
test -f "${file}" -a -r "${file}" || return 1
head -n 1 "${file}"
}
# writes pid file for specific instance
pid_file_write() {
test -z "${1}" && return 1
test -z "${2}" && return 1
# check runtime directory
if [ ! -e "${RUNTIME_DIR}" ] || [ ! -d "${RUNTIME_DIR}" ] || [ ! -w "${RUNTIME_DIR}" ]; then
# try to create directory
mkdir -p "${RUNTIME_DIR}" || die "Unable to create missing runtime directory '${RUNTIME_DIR}'"
fi
file="${RUNTIME_DIR}/${1}.pid"
echo "${2}" > "${file}"
}
# lists running instances
running_instance_list() {
list=""
for file in ${RUNTIME_DIR}/*.pid; do
test -f "${file}" || continue
fileb=`basename "${file}"`
name=`echo "${fileb}" | cut -d. -f1`
if [ -z "${name}" ]; then
msg_log "Removing bogus pid file '${file}'."
rm -f "${file}" >/dev/null 2>&1
continue
fi
pid=`pid_file_read "${name}"`
if [ -z "${pid}" ]; then
msg_log "Removing bogus pid file '${file}': instance '${name}' doesn't contain pid."
rm -f "${file}" >/dev/null 2>&1
continue
fi
# is this pid alive?
if ! kill -0 "${pid}" >/dev/null 2>&1 ; then
msg_log "Removing bogus pid file '${file}': instance '${name}' [pid ${pid}] is stopped."
rm -f "${file}" >/dev/null 2>&1
continue
fi
list="${list} ${name}"
done
echo ${list}
}
stud_instances_start() {
list="$@"
if [ -z "${list}" ]; then
list=`stud_config_instances_list`
fi
if [ -z "${list}" ]; then
die "No stud instances configured in directory '${CONFIG_DIR}'."
fi
echo "Starting stud instances:"
num_ok=0
num_failed=0
for instance in ${list}; do
echo -n " ${instance}: "
# load configuration
if ! stud_single_instance_config_load "${instance}"; then
echo "failed: ${Error}"
return 1
# start instance
elif stud_single_instance_start "${instance}"; then
echo "done."
msg_log "Instance ${name} successfully started."
num_ok=$((num_ok + 1))
else
echo "failed: ${Error}"
msg_err "Error starting instance ${name}: ${Error}"
num_failed=$((num_failed + 1))
fi
done
if [ "${num_failed}" != "0" ]; then
return 1
else
return 0
fi
}
stud_instances_stop() {
list="$@"
if [ -z "${list}" ]; then
list=`running_instance_list`
fi
if [ -z "${list}" ]; then
die "No stud instances are running."
fi
echo "Stopping stud instances:"
num_ok=0
num_failed=0
for instance in ${list}; do
echo -n " ${instance}: "
if stud_single_instance_stop "${instance}"; then
echo "done."
num_ok=$((num_ok + 1))
msg_log "Instance ${instance} successfully stopped."
else
echo "failed: ${Error}"
msg_err "Error stopping instance ${instance}: ${Error}"
num_failed=$((num_failed + 1))
fi
done
if [ "${num_failed}" != "0" ]; then
return 1
else
return 0
fi
}
stud_instances_restart() {
list="$@"
if [ -z "${list}" ]; then
list=`(running_instance_list ; stud_config_instances_list) | tr ' ' '\n' | sort -u | xargs echo`
fi
echo "Restarting stud instances: "
num_ok=0
num_failed=0
for instance in ${list}; do
echo -n " ${instance}: ";
# load configuration
if ! stud_single_instance_config_load "${instance}"; then
echo "failed: ${Error}"
return 1
# restart instance
elif stud_single_instance_restart "${instance}"; then
echo "done."
num_ok=$((num_ok + 1))
msg_log "Instance ${instance} successfully restarted."
else
echo "failed: ${Error}"
msg_err "Error restarting instance ${instance}: ${Error}"
num_failed=$((num_failed + 1))
fi
done
if [ "${num_failed}" != "0" ]; then
return 1
else
return 0
fi
}
stud_instances_status() {
list_config=`stud_config_instances_list`
list_running=`running_instance_list`
list_all=`echo ${list_config} ${list_running} | tr ' ' '\n' | sort -u | xargs echo`
i=0;
echo "Stud instance status: "
if [ -z "${list_all}" ]; then
die "No instances are configured and/or running."
fi
for instance in ${list_all}; do
echo -n " ${instance}: "
if stud_single_instance_status "${instance}"; then
echo "running as pid $Error"
i=$((i + 1))
else
echo "stopped"
fi
done
if [ ${i} -gt 0 ]; then
return 0
else
return 1
fi
}
stud_config_instances_list() {
list=""
for file in ${CONFIG_DIR}/*.conf; do
test -f "${file}" -a -r "${file}" || continue
fileb=`basename "${file}"`
name=`echo "${fileb}" | cut -d. -f1`
test ! -z "${name}" || continue
list="${list} ${name}"
done
echo ${list}
}
stud_single_instance_config_print() {
head -n 151 "$0" | tail -n 123
}
stud_single_instance_config_load() {
file="${CONFIG_DIR}/${1}.conf"
INSTANCE_NAME=""
# reset configuration
stud_single_instance_config_reset
Error=''
if [ -f "${file}" -a -r "${file}" ]; then
. "${file}" >/dev/null || Error="Unable to load instance configuration file '${file}'."
else
Error="Invalid or unreadable instance configuration file '${file}'."
return 1
fi
# set instance name...
INSTANCE_NAME="${1}"
return 0
}
stud_instance_worker_pids() {
test -z "${1}" && return 1
ps -ef | grep " ${1} " | grep -v ' 1 ' | grep -v ' grep ' | awk '{print $2}' | xargs echo
}
# prints worker pid for n-th worker
# arguments:
# $1: list of worker pids (string)
# $2: worker number
stud_instance_worker_pid_by_num() {
i=0
local IFS=" "
for e in ${1}; do
i=$((i + 1))
if [ "${i}" = "${2}" ]; then
echo "$e"
return 0
fi
done
return 1
}
stud_affinity_set() {
# nothing to set?
test -z "$PROCESS_AFFINITY" && return 0
Error=""
# "1:0;2:3-4;3:5;4:7" => bind first haproxy process to CPU0,
# second haproxy process to CPU3 and CPU4,
# third haproxy process to CPU5 and fourth
# process to CPU7
worker_pids=`stud_instance_worker_pids "${1}"`
local IFS=";"
item=""
for item in $PROCESS_AFFINITY; do
num=`echo "${item}" | cut -f1 -d:`
affinity=`echo "${item}" | cut -f2 -d:`
# validate process number
test -z "$num" && continue
test ${num} -ge 1 2>&1 || continue
# validate affinity
test -z "${affinity}" && continue
# WORKS: OpenSUSE
# DOESNT WORK: Debian/Ubuntu!!!
#echo "${affinity}" | grep -qPi '[^a-f0-9\-\,x]' && continue
# is this raw affinity mask?
raw_affinity=0
echo "${affinity}" | grep -qE '^0x' && raw_affinity=1
# get pid for process id $num
pid=`stud_instance_worker_pid_by_num "${worker_pids}" "$num"`
test -z "$pid" && continue
#echo "item: $item; process num: $num; pid: $pid; affinity: $affinity; raw: $raw_affinity"
opt="-p"
test "${raw_affinity}" = "0" && opt="${opt} -c"
opt="${opt} ${affinity}"
opt="${opt} ${pid}"
# echo "WILL RUN: 'taskset $opt'"
msg_log "Setting stud worker number ${num} (pid ${pid}) affinity using command: taskset ${opt}"
eval taskset ${opt} >/dev/null 2>&1 || msg_log "Error setting process affinity."
done
}
ulimit_n_set() {
if [ -z "$ULIMIT_N" ] || [ "$ULIMIT_N" = "0" ]; then
return 0
fi
# try to set maximum possible limit...
i="$ULIMIT_N"
num=0
while [ $i -gt 0 ]; do
num=$((num + 1))
if ulimit -n "$i" > /dev/null 2>&1; then
percentage=$((i*100 / ${ULIMIT_N}))
if [ $percentage -lt 75 ]; then
Error="Filedescriptor limit set to only $i (${percentage}% of desired value of $ULIMIT_N); check your system settings."
return 1
fi
msg_log "Filedescriptor limit successfully set to $i (${percentage}% of desired value of $ULIMIT_N) after ${num} iteration(s)."
return 0
break
else
i=$((i - 100))
fi
done
Error="Filedescriptor limit of $ULIMIT_N could not be set."
msg_log "$Error"
return 1
}
ulimit_set() {
# set fd limit
ulimit_n_set || return 1
# set core file limit
ulimit -c unlimited >/dev/null 2>&1
return 0
}
printhelp() {
cat <<EOF
Usage: ${MYNAME} {start|stop|restart|status|sample_instance_config} [name, name2, ...]
This is stud SSL offloader multi-instance init script.
OPTIONS:
-C --config-dir Instance configuration directory (Default: "${CONFIG_DIR}")
This directory is searched for files matching *.conf
glob pattern; each file represents single stud instance
configuration file.
-R --runtime-dir Runtime (pid file) directory (Default: "${RUNTIME_DIR}")
--sample-config Prints out default single instance configuration
-V --version Prints script version
-h --help This help message
EOF
}
# parse command line...
TEMP=`getopt -o C:R:Vh --long config-dir:,runtime-dir:,sample-config,version,help -n "$MYNAME" -- "$@"`
test "$?" != "0" && die "Invalid command line arguments. Run $MYNAME --help for instructions."
eval set -- "$TEMP"
while true; do
case $1 in
-C|--config-dir)
CONFIG_DIR="${2}"
shift 2
;;
-R|--runtime-dir)
RUNTIME_DIR="${2}"
shift 2
;;
--sample-config)
stud_single_instance_config_print
exit 0
;;
-V|--version)
echo "$MYNAME $VERSION"
exit 0
;;
-h|--help)
printhelp
exit 0
;;
--)
shift
break
;;
*)
die "Invalid command line arguments. Run $MYNAME --help for instructions."
;;
esac
done
# weed out real action and do something
case $1 in
start)
shift
stud_instances_start "$@"
;;
stop)
shift
stud_instances_stop "$@"
;;
force-reload|restart)
shift
stud_instances_restart "$@"
;;
status)
stud_instances_status
exit $?
;;
sample_instance_config|instance_config)
stud_single_instance_config_print
exit 0
;;
*)
printhelp
exit 1
;;
esac
# EOF
+110
View File
@@ -0,0 +1,110 @@
/**
* Copyright 2011 Bump Technologies, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BUMP TECHNOLOGIES, INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BUMP TECHNOLOGIES, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of Bump Technologies, Inc.
*
**/
#include "ringbuffer.h"
#include <assert.h>
/* Initialize a ringbuffer structure to empty */
void ringbuffer_init(ringbuffer *rb) {
rb->head = &rb->slots[0];
rb->tail = &rb->slots[0];
rb->used = 0;
int x;
for (x=0; x<RING_SLOTS; x++)
rb->slots[x].next = &(rb->slots[(x + 1) % RING_SLOTS]);
}
/** READ FUNCTIONS **/
/* Return a char * that represents the current unconsumed buffer */
char * ringbuffer_read_next(ringbuffer *rb, int * length) {
assert(rb->used);
*length = rb->head->left;
return rb->head->ptr;
}
/* Mark consumption of only part of the read head buffer */
void ringbuffer_read_skip(ringbuffer *rb, int length) {
assert(rb->used);
rb->head->ptr += length;
rb->head->left -= length;
}
/* Pop a consumed (fully read) head from the buffer */
void ringbuffer_read_pop(ringbuffer *rb) {
assert(rb->used);
rb->head = rb->head->next;
rb->used--;
}
/** WRITE FUNCTIONS **/
/* Return the tail ptr (current target of new writes) */
char * ringbuffer_write_ptr(ringbuffer *rb) {
assert(rb->used < RING_SLOTS);
return rb->tail->data;
}
/* Mark the tail appended for `length` bytes, and move the cursor
* to the next slot */
void ringbuffer_write_append(ringbuffer *rb, int length) {
assert(rb->used < RING_SLOTS);
rb->used++;
rb->tail->ptr = rb->tail->data;
rb->tail->left = length;
rb->tail = rb->tail->next;
}
/** RING STATE FUNCTIONS **/
/* Used size of the ringbuffer */
int ringbuffer_size(ringbuffer *rb) {
return rb->used;
}
/* Used size of the ringbuffer */
int ringbuffer_capacity(ringbuffer *rb) {
(void) rb;
return RING_SLOTS;
}
/* Is the ringbuffer completely empty (implies: no data to be written) */
int ringbuffer_is_empty(ringbuffer *rb) {
return rb->used == 0;
}
/* Is the ringbuffer completely full (implies: no more data should be read) */
int ringbuffer_is_full(ringbuffer *rb) {
return rb->used == RING_SLOTS;
}
+67
View File
@@ -0,0 +1,67 @@
/**
* Copyright 2011 Bump Technologies, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BUMP TECHNOLOGIES, INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BUMP TECHNOLOGIES, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of Bump Technologies, Inc.
*
**/
#ifndef RINGBUFFER_H
#define RINGBUFFER_H
#include <stddef.h>
/* Tweak these for potential memory/throughput tradeoffs */
#define RING_SLOTS 3
#define RING_DATA_LEN 1024 * 32
typedef struct bufent {
char data[RING_DATA_LEN];
char *ptr;
size_t left;
struct bufent *next;
} bufent;
typedef struct ringbuffer {
bufent slots[RING_SLOTS];
bufent *head; // reads from the head
bufent *tail; // writes to the tail
size_t used;
} ringbuffer;
void ringbuffer_init(ringbuffer *rb);
char * ringbuffer_read_next(ringbuffer *rb, int * length);
void ringbuffer_read_skip(ringbuffer *rb, int length);
void ringbuffer_read_pop(ringbuffer *rb);
char * ringbuffer_write_ptr(ringbuffer *rb);
void ringbuffer_write_append(ringbuffer *rb, int length);
int ringbuffer_size(ringbuffer *rb);
int ringbuffer_capacity(ringbuffer *rb);
int ringbuffer_is_empty(ringbuffer *rb);
int ringbuffer_is_full(ringbuffer *rb);
#endif /* RINGBUFFER_H */
+395
View File
@@ -0,0 +1,395 @@
/*
* shctx.c
*
* Copyright (C) 2011 EXCELIANCE
*
* Author: Emeric Brun - emeric@exceliance.fr
*
*/
#include <sys/mman.h>
#ifdef USE_SYSCALL_FUTEX
#include <unistd.h>
#include <linux/futex.h>
#include <sys/syscall.h>
#else /* USE_SYSCALL_FUTEX */
#include <pthread.h>
#endif /* USE_SYSCALL_FUTEX */
#include "ebtree/ebmbtree.h"
#include "shctx.h"
struct shared_session {
struct ebmb_node key;
unsigned char key_data[SSL_MAX_SSL_SESSION_ID_LENGTH];
long c_date;
int data_len;
unsigned char data[SHSESS_MAX_DATA_LEN];
struct shared_session *p;
struct shared_session *n;
};
struct shared_context {
#ifdef USE_SYSCALL_FUTEX
unsigned int waiters;
#else /* USE_SYSCALL_FUTEX */
pthread_mutex_t mutex;
#endif
struct shared_session active;
struct shared_session free;
};
/* Static shared context */
static struct shared_context *shctx = NULL;
/* Callbacks */
static void (*shared_session_new_cbk)(unsigned char *session, unsigned int session_len, long cdate);
/* Lock functions */
#ifdef USE_SYSCALL_FUTEX
static inline unsigned int xchg(unsigned int *ptr, unsigned int x)
{
__asm volatile("lock xchgl %0,%1"
: "=r" (x), "+m" (*ptr)
: "0" (x)
: "memory");
return x;
}
static inline unsigned int cmpxchg(unsigned int *ptr, unsigned int old, unsigned int new)
{
unsigned int ret;
__asm volatile("lock cmpxchgl %2,%1"
: "=a" (ret), "+m" (*ptr)
: "r" (new), "0" (old)
: "memory");
return ret;
}
static inline unsigned char atomic_inc(unsigned int *ptr)
{
unsigned char ret;
__asm volatile("lock incl %0\n"
"setne %1\n"
: "+m" (*ptr), "=qm" (ret)
:
: "memory");
return ret;
}
static inline unsigned char atomic_dec(unsigned int *ptr)
{
unsigned char ret;
__asm volatile("lock decl %0\n"
"setne %1\n"
: "+m" (*ptr), "=qm" (ret)
:
: "memory");
return ret;
}
static inline void shared_context_lock(void)
{
unsigned int x;
x = cmpxchg(&shctx->waiters, 0, 1);
if (x) {
if (x != 2)
x = xchg(&shctx->waiters, 2);
while (x) {
syscall(SYS_futex, &shctx->waiters, FUTEX_WAIT, 2, NULL, 0, 0);
x = xchg(&shctx->waiters, 2);
}
}
}
static inline void shared_context_unlock(void)
{
if (atomic_dec(&shctx->waiters)) {
shctx->waiters = 0;
syscall(SYS_futex, &shctx->waiters, FUTEX_WAKE, 1, NULL, 0, 0);
}
}
#else /* USE_SYSCALL_FUTEX */
#define shared_context_lock(v) pthread_mutex_lock(&shctx->mutex)
#define shared_context_unlock(v) pthread_mutex_unlock(&shctx->mutex)
#endif
/* List Macros */
#define shsess_unset(s) (s)->n->p = (s)->p; \
(s)->p->n = (s)->n;
#define shsess_set_free(s) shsess_unset(s) \
(s)->p = &shctx->free; \
(s)->n = shctx->free.n; \
shctx->free.n->p = s; \
shctx->free.n = s;
#define shsess_set_active(s) shsess_unset(s) \
(s)->p = &shctx->active; \
(s)->n = shctx->active.n; \
shctx->active.n->p = s; \
shctx->active.n = s;
#define shsess_get_next() (shctx->free.p == shctx->free.n) ? \
shctx->active.p : shctx->free.p;
/* Tree Macros */
#define shsess_tree_delete(s) ebmb_delete(&(s)->key);
#define shsess_tree_insert(s) (struct shared_session *)ebmb_insert(&shctx->active.key.node.branches, \
&(s)->key, SSL_MAX_SSL_SESSION_ID_LENGTH);
#define shsess_tree_lookup(k) (struct shared_session *)ebmb_lookup(&shctx->active.key.node.branches, \
(k), SSL_MAX_SSL_SESSION_ID_LENGTH);
/* Other Macros */
#define shsess_set_key(s,k,l) { memcpy((s)->key_data, (k), (l)); \
if ((l) < SSL_MAX_SSL_SESSION_ID_LENGTH) \
memset((s)->key_data+(l), 0, SSL_MAX_SSL_SESSION_ID_LENGTH-(l)); };
/* SSL context callbacks */
/* SSL callback used on new session creation */
int shctx_new_cb(SSL *ssl, SSL_SESSION *sess) {
(void)ssl;
struct shared_session *shsess;
unsigned char *data,*p;
unsigned int data_len;
unsigned char encsess[SHSESS_MAX_ENCODED_LEN];
/* check if session reserved size in aligned buffer is large enougth for the ASN1 encode session */
data_len=i2d_SSL_SESSION(sess, NULL);
if(data_len > SHSESS_MAX_DATA_LEN)
return 1;
/* process ASN1 session encoding before the lock: lower cost */
p = data = encsess+SSL_MAX_SSL_SESSION_ID_LENGTH;
i2d_SSL_SESSION(sess, &p);
shared_context_lock();
shsess = shsess_get_next();
shsess_tree_delete(shsess);
shsess_set_key(shsess, sess->session_id, sess->session_id_length);
/* it returns the already existing node or current node if none, never returns null */
shsess = shsess_tree_insert(shsess);
/* store ASN1 encoded session into cache */
shsess->data_len = data_len;
memcpy(shsess->data, data, data_len);
/* store creation date */
shsess->c_date = SSL_SESSION_get_time(sess);
shsess_set_active(shsess);
shared_context_unlock();
if (shared_session_new_cbk) { /* if user level callback is set */
/* copy sessionid padded with 0 into the sessionid + data aligned buffer */
memcpy(encsess, sess->session_id, sess->session_id_length);
if (sess->session_id_length < SSL_MAX_SSL_SESSION_ID_LENGTH)
memset(encsess+sess->session_id_length, 0, SSL_MAX_SSL_SESSION_ID_LENGTH-sess->session_id_length);
shared_session_new_cbk(encsess, SSL_MAX_SSL_SESSION_ID_LENGTH+data_len, SSL_SESSION_get_time(sess));
}
return 0; /* do not increment session reference count */
}
/* SSL callback used on lookup an existing session cause none found in internal cache */
SSL_SESSION *shctx_get_cb(SSL *ssl, unsigned char *key, int key_len, int *do_copy) {
(void)ssl;
struct shared_session *shsess;
unsigned char data[SHSESS_MAX_DATA_LEN], *p;
unsigned char tmpkey[SSL_MAX_SSL_SESSION_ID_LENGTH];
unsigned int data_len;
long cdate;
SSL_SESSION *sess;
/* allow the session to be freed automatically by openssl */
*do_copy = 0;
/* tree key is zeros padded sessionid */
if ( key_len < SSL_MAX_SSL_SESSION_ID_LENGTH ) {
memcpy(tmpkey, key, key_len);
memset(tmpkey+key_len, 0, SSL_MAX_SSL_SESSION_ID_LENGTH-key_len);
key = tmpkey;
}
/* lock cache */
shared_context_lock();
/* lookup for session */
shsess = shsess_tree_lookup(key);
if(!shsess) {
/* no session found: unlock cache and exit */
shared_context_unlock();
return NULL;
}
/* backup creation date to reset in session after ASN1 decode */
cdate = shsess->c_date;
/* copy ASN1 session data to decode outside the lock */
data_len = shsess->data_len;
memcpy(data, shsess->data, shsess->data_len);
shsess_set_active(shsess);
shared_context_unlock();
/* decode ASN1 session */
p = data;
sess = d2i_SSL_SESSION(NULL, (const unsigned char **)&p, data_len);
/* reset creation date */
if (sess)
SSL_SESSION_set_time(sess, cdate);
return sess;
}
/* SSL callback used to signal session is no more used in internal cache */
void shctx_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess) {
(void)ctx;
struct shared_session *shsess;
unsigned char tmpkey[SSL_MAX_SSL_SESSION_ID_LENGTH];
unsigned char *key = sess->session_id;
/* tree key is zeros padded sessionid */
if ( sess->session_id_length < SSL_MAX_SSL_SESSION_ID_LENGTH ) {
memcpy(tmpkey, sess->session_id, sess->session_id_length);
memset(tmpkey+sess->session_id_length, 0, SSL_MAX_SSL_SESSION_ID_LENGTH-sess->session_id_length);
key = tmpkey;
}
shared_context_lock();
/* lookup for session */
shsess = shsess_tree_lookup(key);
if ( shsess ) {
shsess_set_free(shsess);
}
/* unlock cache */
shared_context_unlock();
}
/* User level function called to add a session to the cache (remote updates) */
void shctx_sess_add(const unsigned char *encsess, unsigned int len, long cdate) {
struct shared_session *shsess;
/* check buffer is at least padded key long + 1 byte
and data_len not too long */
if ( (len <= SSL_MAX_SSL_SESSION_ID_LENGTH)
|| (len > SHSESS_MAX_DATA_LEN+SSL_MAX_SSL_SESSION_ID_LENGTH) )
return;
shared_context_lock();
shsess = shsess_get_next();
shsess_tree_delete(shsess);
shsess_set_key(shsess, encsess, SSL_MAX_SSL_SESSION_ID_LENGTH);
/* it returns the already existing node or current node if none, never returns null */
shsess = shsess_tree_insert(shsess);
/* store into cache and update earlier on session get events */
if (cdate)
shsess->c_date = (long)cdate;
/* copy ASN1 session data into cache */
shsess->data_len = len-SSL_MAX_SSL_SESSION_ID_LENGTH;
memcpy(shsess->data, encsess+SSL_MAX_SSL_SESSION_ID_LENGTH, shsess->data_len);
shsess_set_active(shsess);
shared_context_unlock();
}
/* Function used to set a callback on new session creation */
void shsess_set_new_cbk(void (*func)(unsigned char *, unsigned int, long)) {
shared_session_new_cbk = func;
}
/* Init shared memory context if not allocated and set SSL context callbacks
* size is the max number of stored session
* Returns: -1 on alloc failure, size if performs context alloc, and 0 if just perform
* callbacks registration */
int shared_context_init(SSL_CTX *ctx, int size)
{
int ret = 0;
if (!shctx) {
int i;
#ifndef USE_SYSCALL_FUTEX
pthread_mutexattr_t attr;
#endif /* USE_SYSCALL_FUTEX */
struct shared_session *prev,*cur;
shctx = (struct shared_context *)mmap(NULL, sizeof(struct shared_context)+(size*sizeof(struct shared_session)),
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (!shctx || shctx == MAP_FAILED)
return -1;
#ifdef USE_SYSCALL_FUTEX
shctx->waiters = 0;
#else
pthread_mutexattr_init(&attr);
pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(&shctx->mutex, &attr);
#endif
memset(&shctx->active.key, 0, sizeof(struct ebmb_node));
memset(&shctx->free.key, 0, sizeof(struct ebmb_node));
/* No duplicate authorized in tree: */
shctx->active.key.node.branches.b[1] = (void *)1;
cur = &shctx->active;
cur->n = cur->p = cur;
cur = &shctx->free;
for ( i = 0 ; i < size ; i++) {
prev = cur;
cur = (struct shared_session *)((char *)prev + sizeof(struct shared_session));
prev->n = cur;
cur->p = prev;
}
cur->n = &shctx->free;
shctx->free.p = cur;
ret = size;
}
/* set SSL internal cache size to external cache / 8 + 123 */
SSL_CTX_sess_set_cache_size(ctx, size >> 3 | 0x3ff);
/* Set callbacks */
SSL_CTX_sess_set_new_cb(ctx, shctx_new_cb);
SSL_CTX_sess_set_get_cb(ctx, shctx_get_cb);
SSL_CTX_sess_set_remove_cb(ctx, shctx_remove_cb);
return ret;
}
+53
View File
@@ -0,0 +1,53 @@
/*
* shctx.h
*
* Copyright (C) 2011 EXCELIANCE
*
* Author: Emeric Brun - emeric@exceliance.fr
*
*/
#ifndef SHCTX_H
#define SHCTX_H
#include <openssl/ssl.h>
#include <stdint.h>
#ifndef SHSESS_MAX_FOOTER_LEN
#define SHSESS_MAX_FOOTER_LEN sizeof(uint32_t) \
+ EVP_MAX_MD_SIZE
#endif
#ifndef SHSESS_MAX_DATA_LEN
#define SHSESS_MAX_DATA_LEN 512
#endif
#define SHSESS_MAX_ENCODED_LEN SSL_MAX_SSL_SESSION_ID_LENGTH \
+ SHSESS_MAX_DATA_LEN \
+ SHSESS_MAX_FOOTER_LEN
/* Callback called on a new session event:
* session contains the sessionid zeros padded to SSL_MAX_SSL_SESSION_ID_LENGTH
* followed by ASN1 session encoding.
* len is set to SSL_MAX_SSL_SESSION_ID_LENGTH + ASN1 session length
* len is always less than SSL_MAX_SSL_SESSION_ID_LENGTH + SHSESS_MAX_DATA_LEN.
* Remaining Bytes from len to SHSESS_MAX_ENCODED_LEN can be used to add a footer.
* cdate is the creation date timestamp.
*/
void shsess_set_new_cbk(void (*func)(unsigned char *session, unsigned int len, long cdate));
/* Add a session into the cache,
* session contains the sessionid zeros padded to SSL_MAX_SSL_SESSION_ID_LENGTH
* followed by ASN1 session encoding.
* len is set to SSL_MAX_SSL_SESSION_ID_LENGTH + ASN1 data length.
* if len greater than SHSESS_MAX_ENCODED_LEN, session is not added.
* if cdate not 0, on get events session creation date will be reset to cdate */
void shctx_sess_add(const unsigned char *session, unsigned int session_len, long cdate);
/* Init shared memory context if not allocated and set SSL context callbacks
* size is the max number of stored session
* Returns: -1 on alloc failure, size if performs context alloc, and 0 if just
* perform callbacks registration */
int shared_context_init(SSL_CTX *ctx, int size);
#endif /* SHCTX_H */
+129
View File
@@ -0,0 +1,129 @@
.\" Copyright (c) 2011 Vincent Bernat <bernat@luffy.cx>
.\"
.\" Redistribution and use in source and binary forms, with or without modification, are
.\" permitted provided that the following conditions are met:
.\"
.\" 1. Redistributions of source code must retain the above copyright notice, this list of
.\" conditions and the following disclaimer.
.\"
.\" 2. Redistributions in binary form must reproduce the above copyright notice, this list
.\" of conditions and the following disclaimer in the documentation and/or other materials
.\" provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY BUMP TECHNOLOGIES, INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED
.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
.\" FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BUMP TECHNOLOGIES, INC. OR
.\" CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
.\" ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
.\" NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" The views and conclusions contained in the software and documentation are those of the
.\" authors and should not be interpreted as representing official policies, either expressed
.\" or implied, of Bump Technologies, Inc.
.\"
.Dd $Mdocdate: September 23 2011 $
.Dt STUD 8
.Os
.Sh NAME
.Nm stud
.Nd The Scalable TLS Unwrapping Daemon
.Sh SYNOPSIS
.Nm
.Op Fl -tls
.Op Fl -ssl
.Op Fl c Ar ciphers
.Op Fl e Ar engine
.Op Fl b Ar host,port
.Op Fl f Ar host,port
.Op Fl n Ar cores
.Op Fl B Ar backlog
.Op Fl C Ar cache
.Op Fl r Ar path
.Op Fl u Ar username
.Op Fl qs
.Op Fl -write-ip
.Op Fl -write-proxy
.Ar certificate.pem
.Sh DESCRIPTION
.Nm
is a network proxy that terminates TLS/SSL connections and forwards the
unencrypted traffic to some backend. It's designed to handle 10s of thousands of
connections efficiently on multicore machines.
.Pp
.Nm
has very few features -- it's designed to be paired with an intelligent
backend like haproxy or nginx. It maintains a strict 1:1 connection pattern
with this backend handler so that the backend can dictate throttling behavior,
maxmium connection behavior, availability of service, etc.
.Pp
The only required argument is a path to a PEM file that contains the certificate
(or a chain of certificates) and private key. It should also contain
DH parameter if you wish to use Diffie-Hellman cipher suites.
.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl -tls
Use TLSv1 (default).
.It Fl -ssl
Use only SSLv3 and no TLSv1.
.It Fl c Ar ciphers
Set allowed ciphers using the same format as
.Ic openssl ciphers .
For example, you can use
.Ar RSA:!COMPLEMENTOFALL .
.It Fl e Ar engine
Specify an OpenSSL engine by its unique ID. The engine will be used by
default for all algorithms. The keyword
.Ar auto
can be used to load all available engines.
.It Fl b Ar host,port
Define backend. Default is
.Ar 127.0.0.1,8000 .
Incoming connections will be unwrapped and sent to this IP and port.
.It Fl f Ar host,port
Define frontend. Default is
.Ar *,8443 .
Incoming connections will be accepted to this IP and port and will be
sent to the backend defined above.
.It Fl n Ar cores
Use
.Ar cores
worker processes. Default is 1.
.It Fl B Ar backlog
Set listen backlog size. Default is 100.
.It Fl C Ar cache
Set shared cache size in sessions. By default, no shared cache is used.
.It Fl r Ar path
Chroot to the given path. By default, no chroot is done.
.It Fl u Ar username
Set GID/UID after binding the socket. By default, no privilege is dropped.
.It Fl q
Be quiet. Only emit error messages.
.It Fl s
Send messages to syslog in addition to
.Em stderr
and
.Em stdout .
.It Fl -syslog-facility Ar facility
Syslog facility to use. Default is
.Ar daemon .
.It Fl -write-ip
Write 1 octet with the IP family followed by the IP address in 4
(IPv4) or 16 (IPv6) octets little-endian to backend before the actual
data.
.It Fl -write-proxy
Write HaProxy's PROXY (IPv4 or IPv6) protocol line
before actual data.
.El
.Sh SEE ALSO
.Xr ciphers 1SSL ,
.Xr dhparam 1SSL ,
.Xr haproxy 1
.Sh AUTHORS
.Nm
was originally written by Jamie Turner (@jamwt) and is maintained by
the Bump server team. It currently provides server-side TLS
termination for over 40 million Bump users.
+1878
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -0,0 +1 @@
#define STUD_VERSION "0.3-dev"