segfault/sfbin/sf
2023-01-26 22:13:09 +00:00

174 lines
6.0 KiB
Bash
Executable File

#! /bin/bash
down()
{
docker container prune -f
c=($(docker ps -f name=^lg --all --quiet))
[[ -n $c ]] && docker stop "${c[@]}"
docker-compose "$@"
docker network prune -f
# Sometimes docker gets into a state when it complains about overlappting
# network pool even that 'docker network ls' shows no networks beside
# the 3 default networks and with no containers running:
ip link show | cut -f2 -d" " | grep -E "^(br-)" | while read x; do x="${x%@*}"; x="${x%:*}"; [[ -z $x ]] && continue; ip link delete "${x}" down; done
}
[[ -z $SF_REDIS_AUTH ]] && {
SF_REDIS_AUTH=$(echo -n "Redis AUTH $SF_SEED" | sha512sum | base64 -w0)
SF_REDIS_AUTH="${SF_REDIS_AUTH//[^[:alnum:]]}"
SF_REDIS_AUTH="${SF_REDIS_AUTH:0:32}"
export SF_REDIS_AUTH
}
[[ "$1" == down ]] && {
down "$@"
exit
}
[[ "$1" != up ]] && exec docker-compose "$@"
# HERE: "up"
BINDIR="$(cd "$(dirname "${0}")" || exit; pwd)"
source "${BINDIR}/funcs.sh" || exit 254
[[ -z $SF_SEED ]] && ERREXIT 255 "SF_SEED= not set"
# Load variables from ENV but only those not already set in
# user's environemtn.
load_env()
{
local n
local v
local arr
local a
envfile="./.env"
[[ -n $SF_BASEDIR ]] && envfile="${SF_BASEDIR}/.env"
if [[ ! -f "${envfile}" ]]; then
WARN "Not found: \${SF_BASEDIR}/.env (${envfile})"
else
IFS=$'\n'
arr=( $(grep -v ^# "${envfile}") )
for a in "${arr[@]}"; do
n="${a%%=*}"
v="${a#*=}"
# Prefer user's environemtn over .env settings.
[[ -z "$(eval echo \$$n)" ]] && eval "${n}=\"${v}\""
done
fi
[[ -z $SF_BASEDIR ]] && ERREXIT 255 "SF_BASEDIR= not set in ${envfile}."
}
blockio_init()
{
local is_bfq
local n
# Check if there is BFQ-Scheduler support in the Kernel
for fn in /sys/class/block/*/queue/scheduler; do
[[ ! -f "${fn}" ]] && break
grep bfq "${fn}" >/dev/null || break
is_bfq=1
break
done
[[ -z $is_bfq ]] && {
# HERE: no BFQ support. Try load module.
# Try: apt install linux-modules-extra-aws
modprobe bfq || { WARN "No BFQ-Scheduler. Attacker can DoS block-IO."; return; }
is_bfq=1
}
# Return if BFQ is set
for fn in /sys/class/block/*/queue/scheduler; do
[[ ! -f "${fn}" ]] && break
echo bfq >"${fn}" || { WARN ""${fn%/queue*}": Failed to set BFQ scheduler."; return; }
done
# Odd bug. On some systems we set all correctly and docker still complains that
# it cant use Block IO weights. It appears to be a problem with cgroup v1?
# It can be fixed on v1 systems by using --cgroup-parent=/guest and creating:
# mkdir -p /sys/fs/cgroup/blkio/guest
# echo 1 >/sys/fs/cgroup/blkio/guest/blkio.bfq.weight
# => But then why cant docker fix this crap?
# https://github.com/moby/moby/issues/16173#issuecomment-1298432655
# Test if docker accepts --blkio-weight:
docker run --rm --blkio-weight=100 alpine true 2>&1 | grep "does not support Block" >/dev/null && { WARN "DOCKER: Your kernel does not support Block I/O weight."; return; }
}
warn_file()
{
[[ -f "$1" ]] && return
WARN "Not found: $1"
}
load_env
[[ -z $SF_DATADIR ]] && SF_DATADIR="${SF_BASEDIR}/data"
[[ ! -d "${SF_DATADIR}/user" ]] && mkdir -p "${SF_DATADIR}/user"
[[ ! -d "${SF_DATADIR}/share" ]] && mkdir -p "${SF_DATADIR}/share"
[[ ! -f "${SF_DATADIR}/share/GeoLite2-City.mmdb" ]] && {
WARN "Not found: data/share/GeoLite2-City.mmdb"
echo -e "Try \`curl 'https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key=zNACjsJrHnGPBxgI&suffix=tar.gz' | tar xfvz - --strip-components=1 --no-anchored -C '${SF_DATADIR}/share/' 'GeoLite2-City.mmdb'\`."
}
[[ ! -f "${SF_DATADIR}/share/tor-exit-nodes.txt" ]] && {
WARN "Not found: data/share/tor-exit-nodes.txt"
echo -e "Try \`curl 'https://www.dan.me.uk/torlist/?exit' >'${SF_DATADIR}/share/tor-exit-nodes.txt'\`"
}
[[ -z $SF_OVERLAYDIR ]] && [[ -d "${SF_BASEDIR}/docker/overlay2" ]] && export SF_OVERLAYDIR="${SF_BASEDIR}/docker/overlay2"
# xfs_init_quota "${SF_DATADIR}/everyone-root" "everyone" 100 16384 16G
# Enable BFQ on all block devices to allow cgroup's io.weight
# FIXME: One day but this into udev/startup scripts and only for
# device that we are using...
blockio_init
# BUG-ARP-CACHE:
# User can cause arp-table overflow. The kernel limit is global for all arp tables
# but each container gets its own arp table. All containers just put pressure on the global
# limit.
# Attack: A user can spawn multiple containers and create 'incomplete' arp entries in its own
# table. Those entries reduce the amount of entries avaialble for other containers (it's a global limit
# and not a limit per container).
#
# Oddity: Docker-compose is making the host name of each service available (e.g sf-redis, sf-tor etc).
# This is not done via an /etc/hosts entry but handled by Docker internally. The problem is that
# 'somewhere' docker (internally) needs an arp-entry (which fails during an attack). Then the
# name (e.g. sf-redis or so) can not be resolved and all goes to shits.
#
# Tweaking base_reachable_time_ms and gc_stale_time has no effect. Best we can do:
# 1. Use static IPs where possible for inter-container communication.
# 2. Limit the User's local network (to /22 or /24)
# 3. Increase the global size of the kernel's arp table (gc_thresh3)
sysctl -q -w net.ipv4.neigh.default.gc_thresh3=65536 || WARN "Could not set /proc/.../gc_thresh3"
sysctl -q -w net.netfilter.nf_conntrack_buckets=16384 || WARN "Could not set /proc/.../nf_conntrack_buckets"
sysctl -q -w net.netfilter.nf_conntrack_max=131072 || WARN "Could not set /proc/.../nf_conntrack_max"
warn_file "${SF_BASEDIR}/config/etc/nginx/nginx-rpc.conf"
warn_file "${SF_BASEDIR}/config/etc/nginx/nginx.conf"
warn_file "${SF_BASEDIR}/config/etc/sf/sf.conf"
# STOP HERE: Check if there are any fils in /sf/sfbin that are not equal to ./sfbin
# Make sure /dev/shm is 'shared'
[[ "$(findmnt -no TARGET,PROPAGATION /dev/shm)" != *"shared"* ]] && {
mount --make-shared /dev/shm/ || ERREXIT 252
}
# If there was a warning then wait...
WARN_ENTER
# exec docker-compose "$@"
docker-compose "$@"
ret=$?
# If not started as background (-d): run DOWN.
[[ "$*" != *" -d"* ]] && { down "down"; exit; }
echo -e "May need to run \`${CDC}$0 down${CN}\` (code=$ret)"