mirror of
https://github.com/hackerschoice/segfault.git
synced 2024-06-27 09:18:41 +00:00
cpuaccting, xfs_quota, bash 2^63 bug
This commit is contained in:
parent
b2e7d48fa6
commit
2625082d2b
@ -20,6 +20,8 @@
|
||||
#SF_ULIMIT_NOFILE="256:256"
|
||||
SF_SHM_SIZE=16MB
|
||||
|
||||
#SF_USER_FS_BYTES_MAX= # e.g 1024m is 1GB
|
||||
#SF_USER_FS_INODE_MAX= # 16384
|
||||
|
||||
# Limit to 8 concurrently running servers per IP
|
||||
#SF_LIMIT_SERVER_BY_IP=8
|
||||
|
@ -26,16 +26,22 @@ services:
|
||||
- SYS_ADMIN
|
||||
security_opt:
|
||||
- apparmor:unconfined
|
||||
# xfs_quota needs this :/ FIXME
|
||||
privileged: true
|
||||
environment:
|
||||
- SF_REDIS_AUTH=${SF_REDIS_AUTH}
|
||||
- SF_SEED=${SF_SEED}
|
||||
- SF_DATADEV
|
||||
- SF_DEBUG
|
||||
command: ["/encfsd.sh"]
|
||||
networks:
|
||||
redis-net:
|
||||
devices:
|
||||
- "/dev/fuse:/dev/fuse"
|
||||
# - "${SF_DATADEV:-?}:/dev/loop1" -> not needed in priv mode?
|
||||
volumes:
|
||||
- "${SF_BASEDIR:-.}/config/db:/config/db:ro"
|
||||
- "${SF_BASEDIR:-.}/config/etc/sf:/config/etc/sf:ro"
|
||||
- "${SF_BASEDIR:-.}/data:/encfs/raw"
|
||||
- "${SF_SHMDIR:-/dev/shm/sf}/encfs-sec:/encfs/sec:shared"
|
||||
- "${SF_BASEDIR:-.}/sfbin:/sf/bin:ro"
|
||||
|
@ -2,8 +2,9 @@ FROM alpine
|
||||
|
||||
RUN apk add --no-cache --upgrade \
|
||||
&& apk add --no-cache \
|
||||
docker-cli \
|
||||
redis \
|
||||
bash \
|
||||
encfs
|
||||
docker-cli \
|
||||
encfs \
|
||||
redis \
|
||||
xfsprogs-extra
|
||||
COPY destructor.sh encfsd.sh portd.sh /
|
||||
|
@ -23,6 +23,9 @@ stop_lg()
|
||||
[[ ! -z $is_encfs ]] && { pkill -SIGTERM -f "^\[encfs-${lid}\]" || ERR "[${lid}] pkill"; }
|
||||
}
|
||||
|
||||
# Return 0 if we shall not check this container further
|
||||
# - It's recent
|
||||
# - It no longer exists.
|
||||
is_recent()
|
||||
{
|
||||
local pid
|
||||
@ -31,7 +34,8 @@ is_recent()
|
||||
|
||||
[[ -z "${pid}" ]] && { WARN "PID='${pid}' is empty"; return 0; }
|
||||
|
||||
ts=$(stat -c %Y "/proc/${pid}")
|
||||
ts=$(stat -c %Y "/proc/${pid}" 2>/dev/null) || return 0
|
||||
# Can happen that container quit just now. Ignore if failed.
|
||||
[[ -z $ts ]] && return 0
|
||||
# PID is younger than 20 seconds...
|
||||
[[ $((NOW - ts)) -lt 20 ]] && return 0
|
||||
@ -63,7 +67,7 @@ check_container()
|
||||
is_recent "${pid%% *}" && return
|
||||
|
||||
# Check how many PIDS are running inside container:
|
||||
pids=($(docker top "$c" -eo pid)) || { DEBUGF "docker top '$c' failed"; return; }
|
||||
pids=($(docker top "$c" -eo pid 2>/dev/null)) || { DEBUGF "docker top '$c' failed"; return; }
|
||||
# DEBUGF "[${CDM}${lid}${CN}] pids(${#pids[@]}) '${pids[*]}'"
|
||||
# 1. PS-Header (UID PID PPID C STIME TTY TIME)
|
||||
# 2. docker-init
|
||||
|
110
encfsd/encfsd.sh
110
encfsd/encfsd.sh
@ -2,6 +2,8 @@
|
||||
|
||||
source /sf/bin/funcs.sh
|
||||
|
||||
MARK_FN="THIS-DIRECTORY-IS-NOT-ENCRYPTED--DO-NOT-USE.txt"
|
||||
|
||||
BAD()
|
||||
{
|
||||
local delay
|
||||
@ -27,7 +29,32 @@ xmkdir()
|
||||
mkdir "$1"
|
||||
}
|
||||
|
||||
# [name] [SECRET] [SECDIR] [RAWDIR] [noatime,noexec]
|
||||
# [name] [secdir] [rawdir]
|
||||
encfs_mkdir()
|
||||
{
|
||||
local name
|
||||
local secdir
|
||||
name="$1"
|
||||
secdir="$2"
|
||||
|
||||
[[ -d "${secdir}" ]] && mountpoint "${secdir}" >/dev/null && {
|
||||
echo "[encfs-${name}] Already mounted."
|
||||
[[ ! -e "${secdir}/${MARK_FN}" ]] && return 0
|
||||
ERR "[encfs-${name}] Mounted but markfile exist showing not encrypted."
|
||||
return 255
|
||||
}
|
||||
|
||||
# If EncFS died then a stale mount point might still exist.
|
||||
# -d/-e/-f all fail (Transport endpoint is not connected)
|
||||
# Force an unmount if it's not a directory (it's 'stale').
|
||||
fusermount -zu "${secdir}" 2>/dev/null && [[ -d "${secdir}" ]] && return
|
||||
[[ ! -d "${secdir}" ]] && fusermount -zu "${secdir}" 2>/dev/null
|
||||
|
||||
xmkdir "${secdir}" || return 255
|
||||
xmkdir "${rawdir}" || return 255
|
||||
}
|
||||
|
||||
# [name] [SECRET] [SECDIR] [RAWDIR] [noatime,noexec] [info]
|
||||
encfs_mount()
|
||||
{
|
||||
local name
|
||||
@ -37,37 +64,20 @@ encfs_mount()
|
||||
local secdir
|
||||
local rawdir
|
||||
local opts
|
||||
local info
|
||||
name="$1"
|
||||
s="$2"
|
||||
secdir="$3"
|
||||
rawdir="$4"
|
||||
opts="$5"
|
||||
info="$6"
|
||||
|
||||
# is_tracked "${l}" && return 0 # Already mounted. Success.
|
||||
|
||||
local markfile
|
||||
markfile="${secdir}/THIS-DIRECTORY-IS-NOT-ENCRYPTED--DO-NOT-USE.txt"
|
||||
|
||||
[[ -d "${secdir}" ]] && mountpoint "${secdir}" >/dev/null && {
|
||||
echo "[encfs-${name}] Already mounted."
|
||||
[[ ! -e "${markfile}" ]] && return 0
|
||||
ERR "[encfs-${name}] Mounted but markfile exist showing not encrypted."
|
||||
return 255
|
||||
}
|
||||
|
||||
# If EncFS died then a stale mount point might still exist.
|
||||
# -d/-e/-f all fail (Transport endpoint is not connected)
|
||||
# Force an unmount if it's not a directory (it's 'stale').
|
||||
fusermount -zu "${1}" 2>/dev/null && [[ -d "$1" ]] && return
|
||||
[[ ! -d "${secdir}" ]] && fusermount -zu "${secdir}" 2>/dev/null
|
||||
|
||||
xmkdir "${secdir}" || return 255
|
||||
xmkdir "${rawdir}" || return 255
|
||||
|
||||
[[ ! -e "${markfile}" ]] && { echo "THIS-IS-NOT-ENCRYPTED *** DO NOT USE *** " >"${markfile}" || { BAD 0 "Could not create Markfile"; return 255; } }
|
||||
[[ ! -e "${secdir}/${MARK_FN}" ]] && { echo "THIS-IS-NOT-ENCRYPTED *** DO NOT USE *** " >"${secdir}/${MARK_FN}" || { BAD 0 "Could not create Markfile"; return 255; } }
|
||||
|
||||
# local cpid
|
||||
LOG "${name}" "Mounting ${secdir} to ${rawdir}."
|
||||
LOG "${name}" "Mounting ${info}"
|
||||
# echo "$s" | bash -c "exec -a '[encfs-${name:-BAD}]' encfs --standard --public -o nonempty -S \"${rawdir}\" \"${secdir}\" -- -o fsname=/dev/sec-\"${name}\" -o \"${opts}\"" >/dev/null
|
||||
# --nocache -> Blindly hoping that encfs consumes less memory?!
|
||||
echo "$s" | bash -c "exec -a '[encfs-${name:-BAD}]' encfs --nocache --standard --public -o nonempty -S \"${rawdir}\" \"${secdir}\" -- -o \"${opts}\"" >/dev/null
|
||||
@ -85,20 +95,38 @@ encfs_mount_server()
|
||||
local secret
|
||||
local name
|
||||
secdir="/encfs/sec/${1}-root"
|
||||
rawdir="/encfs/raw/${1}-root"
|
||||
name="$1"
|
||||
secret="$2"
|
||||
|
||||
encfs_mkdir "${name}" "${secdir}" "${rawdir}" || return
|
||||
|
||||
# We use a file as a semaphore so that we dont need to give
|
||||
# the waiting container access to redis.
|
||||
[[ -f "${secdir}/.IS-ENCRYPTED" ]] && rm -f "${secdir}/.IS-ENCRYPTED"
|
||||
encfs_mount "${name}" "${secret}" "${secdir}" "/encfs/raw/${name}-root" "noexec,noatime" || ERREXIT 254 "EncFS ${name}-root failed."
|
||||
encfs_mount "${name}" "${secret}" "${secdir}" "${rawdir}" "noexec,noatime" || ERREXIT 254 "EncFS ${name}-root failed."
|
||||
touch "${secdir}/.IS-ENCRYPTED"
|
||||
|
||||
# redis-cli -h sf-redis SET "encfs-ts-${name}" "$(date +%s)"
|
||||
}
|
||||
|
||||
# [LID]
|
||||
load_limits()
|
||||
{
|
||||
local lid
|
||||
lid="$1"
|
||||
|
||||
# First source global
|
||||
[[ -f "/config/etc/sf/sf.conf" ]] && eval "$(grep ^SF_ "/config/etc/sf/sf.conf")"
|
||||
|
||||
# Then source user specific limits
|
||||
[[ -f "/config/db/db-${lid}/limits.conf" ]] && eval "$(grep ^SF_ "/config/db/db-${lid}/limits.conf")"
|
||||
}
|
||||
|
||||
redis_loop_forever()
|
||||
{
|
||||
local secdir
|
||||
|
||||
while :; do
|
||||
res=$(redis-cli -h sf-redis BLPOP encfs 0) || ERREXIT 250 "Failed with $?"
|
||||
|
||||
@ -122,8 +150,36 @@ redis_loop_forever()
|
||||
|
||||
[[ ${#secret} -ne 24 || ${#name} -ne 10 ]] && { BAD 0 "Bad secret='$secret'/name='$name'"; continue; }
|
||||
|
||||
secdir="/encfs/sec/user-${name}"
|
||||
rawdir="/encfs/raw/user/user-${name}"
|
||||
encfs_mkdir "${name}" "${secdir}" "${rawdir}" || return
|
||||
|
||||
# Set up XFS limits
|
||||
# xfs_quota -x -c 'limit -p ihard=80 Alice' "${SF_DATADEV}"
|
||||
load_limits "${name}"
|
||||
[[ -n $SF_USER_FS_INODE_MAX ]] && [[ -n $SF_USER_FS_BYTES_MAX ]] && {
|
||||
SF_NUM=$(<"/config/db/db-${name}/num") || continue
|
||||
SF_HOSTNAME=$(<"/config/db/db-${name}/hostname") || continue
|
||||
prjid=$((SF_NUM + 10000000))
|
||||
# DEBUGF "SF_NUM=${SF_NUM}, prjid=${prjid}, SF_HOSTNAME=${SF_HOSTNAME}, INODE_MAX=${SF_USER_FS_INODE_MAX}, BYTES_MAX=${SF_USER_FS_BYTES_MAX}"
|
||||
err=$(xfs_quota -x -c "limit -p ihard=${SF_USER_FS_INODE_MAX} bhard=${SF_USER_FS_BYTES_MAX} ${prjid}" "${SF_DATADEV}" 2>&1) || { ERR "XFS-QUOTA: \n'$err'"; continue; }
|
||||
err=$(xfs_quota -x -c "project -s -p ${rawdir} ${prjid}" "${SF_DATADEV}" 2>&1) || { ERR "XFS-QUOTA /sec: \n'$err'"; continue; }
|
||||
}
|
||||
|
||||
# Mount if not already mounted. Continue on error (let client hang)
|
||||
encfs_mount "${name}" "${secret}" "/encfs/sec/user-${name}" "/encfs/raw/user/user-${name}" "noatime" || continue
|
||||
encfs_mount "${name}" "${secret}" "${secdir}" "${rawdir}" "noatime" "/sec (INODE_MAX=${SF_USER_FS_INODE_MAX}, BYTES_MAX=${SF_USER_FS_BYTES_MAX})" || continue
|
||||
|
||||
# XFS limit for /onion must be set up after mounting.
|
||||
# Finding out the WWW path is ghetto:
|
||||
# - xfs_quota can only work on the underlaying encfs structure.
|
||||
# That however is enrypted and we do not know the directory name
|
||||
# - Use last created directory.
|
||||
[[ ! -d "/encfs/sec/www-root/www/${SF_HOSTNAME,,}" ]] && {
|
||||
xmkdir "/encfs/sec/www-root/www/${SF_HOSTNAME,,}"
|
||||
USER_RAWDIR=$(find "${BASE_RAWDIR}" -type d -maxdepth 1 -print | tail -n1)
|
||||
[[ ! -d "${USER_RAWDIR:?}" ]] && continue
|
||||
err=$(xfs_quota -x -c "project -s -p ${USER_RAWDIR} ${prjid}" "${SF_DATADEV}" 2>&1) || { ERR "XFS Quota /onion: \n'$err'"; continue; }
|
||||
}
|
||||
|
||||
# Success. Tell the guest that EncFS is ready (newly mounted or was mounted)
|
||||
# prints "1" to stdout.
|
||||
@ -145,10 +201,16 @@ ENCFS_SERVER_PASS="${ENCFS_SERVER_PASS:0:24}"
|
||||
|
||||
export REDISCLI_AUTH="${SF_REDIS_AUTH}"
|
||||
|
||||
|
||||
# Mount Segfault-wide encrypted file systems
|
||||
encfs_mount_server "everyone" "${ENCFS_SERVER_PASS}"
|
||||
encfs_mount_server "www" "${ENCFS_SERVER_PASS}"
|
||||
|
||||
BASE_RAWDIR=$(find /encfs/raw/www-root/ -type d -maxdepth 1 -print | tail -n1)
|
||||
|
||||
[[ ! -d "${BASE_RAWDIR:?}" ]] && ERREXIT 255 "Cant find encrypted /encfs/raw/www-root/*"
|
||||
|
||||
# sleep infinity
|
||||
# Need to start redis-loop in the background. This way the foreground bash
|
||||
# will still be able to receive SIGTERM.
|
||||
redis_loop_forever &
|
||||
|
@ -21,6 +21,7 @@ RUN apt-get update -y \
|
||||
net-tools \
|
||||
procps \
|
||||
psmisc \
|
||||
rsync \
|
||||
vim \
|
||||
zsh \
|
||||
zsh-autosuggestions \
|
||||
@ -71,7 +72,6 @@ RUN apt-get update -y \
|
||||
netcat-traditional \
|
||||
man-db \
|
||||
manpages-dev \
|
||||
rsync \
|
||||
sudo \
|
||||
tcpdump \
|
||||
traceroute \
|
||||
@ -79,8 +79,11 @@ RUN apt-get update -y \
|
||||
wget \
|
||||
whois \
|
||||
&& DEBIAN_FRONTEND=noninteractive /pkg-install.sh HACK apt-get install -y --no-install-recommends \
|
||||
assetfinder \
|
||||
dnsmap \
|
||||
fuff \
|
||||
hydra \
|
||||
gobuster \
|
||||
irssi \
|
||||
nbtscan \
|
||||
netdiscover \
|
||||
@ -118,6 +121,7 @@ RUN apt-get update -y \
|
||||
lsof \
|
||||
lynx \
|
||||
mc \
|
||||
mg \
|
||||
mtr \
|
||||
most \
|
||||
neofetch \
|
||||
@ -147,6 +151,7 @@ RUN apt-get update -y \
|
||||
whatweb \
|
||||
wipe \
|
||||
wpscan \
|
||||
wrk \
|
||||
&& /pkg-install.sh HUGE apt-get install -y --no-install-recommends \
|
||||
default-jdk \
|
||||
exploitdb \
|
||||
@ -161,6 +166,7 @@ RUN apt-get update -y \
|
||||
x11-apps \
|
||||
&& /pkg-install.sh HUGE go install -v github.com/projectdiscovery/uncover/cmd/uncover@latest \
|
||||
&& /pkg-install.sh HUGE go install -v github.com/sagernet/sing-box/cmd/sing-box@latest \
|
||||
&& /pkg-install.sh HUGE go install -v github.com/tomnomnom/waybackurls@latest \
|
||||
&& /pkg-install.sh LARGE pip install --pre 'scapy[basic]' \
|
||||
&& /pkg-install.sh WEB pip install \
|
||||
'pelican[Markdown]' \
|
||||
|
@ -214,6 +214,7 @@ init_vars()
|
||||
|
||||
NOW="$(date +%s)"
|
||||
YOUR_IP="${SSH_CONNECTION%%[[:space:]]*}"
|
||||
YOUR_IP="${YOUR_IP//[^0-9.:]/}"
|
||||
[[ -z $YOUR_IP ]] && ERREXIT 255 "SSH_CONNECTION= is is not set. segfaultsh not started via sshd?"
|
||||
# Do not store IP addresses. Hash it with a secret (SEED) instead.
|
||||
local str
|
||||
@ -338,7 +339,7 @@ spawn_shell_exit()
|
||||
|
||||
# Update current IP:
|
||||
touch "/config/self-for-guest/lg-${LID}/THIS-DIRECTORY-IS-IN-MEMORY-ONLY"
|
||||
tofile "${YOUR_IP}" "/config/self-for-guest/lg-${LID}/ip"
|
||||
tofile "${YOUR_IP:?}" "/config/self-for-guest/lg-${LID}/ip"
|
||||
[[ -n $YOUR_GEOIP ]] && tofile "${YOUR_GEOIP}" "/config/self-for-guest/lg-${LID}/geoip"
|
||||
|
||||
# Request a reverse Port Forward
|
||||
@ -356,14 +357,21 @@ spawn_shell_exit()
|
||||
# Generate a mnemonic hostname from LID (e.g. ButterflyCat)
|
||||
mk_hostname()
|
||||
{
|
||||
NUM=$(echo "ibase=16; $(echo "$LID" | md5sum | cut -f1 -d" " | tr 'a-z' A-Z)" | bc)
|
||||
NUM=$(echo "$LID" | md5sum)
|
||||
NUM=${NUM%% *}
|
||||
NUM=$((16#${NUM:0:15}))
|
||||
# Oops. bash max integer is (2^63)-1, so limit to 15 hex.
|
||||
# NUM=$(echo "ibase=16; $(echo "$LID" | md5sum | cut -f1 -d" " | tr 'a-z' A-Z)" | bc)
|
||||
readarray -t english <"${SF_HOST_FS_ROOT}/etc/english.txt"
|
||||
SF_HOSTNAME="UnknownUnknown"
|
||||
if [[ "${#english[@]}" -eq 2048 ]]; then
|
||||
SF_HOSTNAME="${english[$((NUM % 2048))]}"
|
||||
SF_HOSTNAME+="${english[$(( (NUM / 2048) % 2048 ))]}"
|
||||
fi
|
||||
DEBUGF "SF_HOSTNAME=$SF_HOSTNAME"
|
||||
[[ "${#english[@]}" -lt 2048 ]] && ERREXIT 2 "english.txt bad"
|
||||
m=$((NUM % 2048))
|
||||
n=$(( (NUM / 2048) % 2048))
|
||||
SF_NUM="$((m * 2048 + n))"
|
||||
|
||||
SF_HOSTNAME="${english[$m]}"
|
||||
SF_HOSTNAME+="${english[$n]}"
|
||||
DEBUGF "SF_HOSTNAME=$SF_HOSTNAME, SF_NUM=${SF_NUM}, NUM=$NUM"
|
||||
unset NUM
|
||||
unset english
|
||||
}
|
||||
@ -392,7 +400,8 @@ load_limits()
|
||||
SF_USER_OOM_SCORE=500
|
||||
SF_USER_NICE_SCORE=10
|
||||
SF_LIMIT_SERVER_BY_IP=8
|
||||
SF_ULIMIT_NOFILE="256:1024"
|
||||
SF_ULIMIT_NOFILE="256:256"
|
||||
SF_MAX_LOAD="20" # No new shells until load goes below
|
||||
|
||||
# HACK: Use eval-trick to 'source' in a restricted bash shell
|
||||
[[ -f "${SF_ETCSF_DIR}/sf.conf" ]] && eval "$(grep ^SF_ "${SF_ETCSF_DIR}/sf.conf")"
|
||||
@ -448,7 +457,7 @@ wait_for_conn_limit()
|
||||
[[ ${ARR[0]} -lt $ts_good ]] && break
|
||||
|
||||
[[ $c -gt 60 ]] && echo -e >&2 "giving up. Try again later." && exit 255
|
||||
[[ $c -eq 0 ]] && echo -en >&2 "[${CY}SF${CN}] Waiting for resources..."
|
||||
[[ $c -eq 0 ]] && echo -e >&2 "[${CY}SF${CN}] Waiting for resources..."
|
||||
echo -n "."
|
||||
sleep 2
|
||||
((c++))
|
||||
@ -459,12 +468,30 @@ wait_for_conn_limit()
|
||||
tofile "ARR=(${ARR[*]:1:4} $NOW)" "${fn}"
|
||||
}
|
||||
|
||||
wait_for_load()
|
||||
{
|
||||
local load
|
||||
local max="$1"
|
||||
|
||||
# FIXME: Stop after waiting for too long.
|
||||
# FIXME: Implement garbage collector...
|
||||
while :; do
|
||||
load=($(</proc/loadavg))
|
||||
load=${load[0]%%.*}
|
||||
[[ $load -lt "$max" ]] && break
|
||||
echo -e >&2 "[${CY}SF${CN}] Waiting for load to go down..."
|
||||
sleep 5
|
||||
done
|
||||
}
|
||||
|
||||
wait_for_resources()
|
||||
{
|
||||
# 5 Connections within 60 seconds from the same IP.
|
||||
wait_for_conn_limit "${YOUR_IP_HASH}" "60"
|
||||
# 5 Connections within 15 seconds all in all
|
||||
wait_for_conn_limit "all" "15"
|
||||
wait_for_conn_limit "all" "30"
|
||||
|
||||
wait_for_load "${SF_MAX_LOAD}"
|
||||
}
|
||||
|
||||
# Check if max servers per IP are in use.
|
||||
@ -635,6 +662,9 @@ else
|
||||
|
||||
mkdir -p "${DB_DIR}/db-${LID}" || ERREXIT
|
||||
touch "${DB_DIR}/db-${LID}/created.txt" || ERREXIT
|
||||
tofile "$SF_NUM" "${DB_DIR}/db-${LID}/num"
|
||||
tofile "$SF_HOSTNAME" "${DB_DIR}/db-${LID}/hostname"
|
||||
# tofile "$SSH_CONNECTION" "${DB_DIR}/ssh_connection"
|
||||
# exec_errnull date +%s >"${DB_DIR}/db-${LID}/created.txt" || ERREXIT
|
||||
[[ -d "${HNLID_DIR}" ]] || exec_devnull mkdir "${HNLID_DIR}"
|
||||
tofile "$LID" "${HNLID_FILE}" || ERREXIT 231 "tofile: Failed to create hnlid_file"
|
||||
@ -668,18 +698,7 @@ echo_pty -n "...."
|
||||
# HERE: Instance does not exists.
|
||||
}
|
||||
|
||||
### Create ONION directory:
|
||||
# This script runs under UID=1000 (root) and does not have write permission to
|
||||
# /onion. Thus jump via docker.
|
||||
## NOTE: Not need because docker-run will create the mount point (-v forces creation)
|
||||
# [[ ! -d "${SF_WWW_ROOT_DIR}/${SF_HOSTNAME,,}" ]] && {
|
||||
# DEBUGF "Creating /onion/${SF_HOSTNAME,,}"
|
||||
# if [[ -z $SF_EMU ]]; then
|
||||
# exec_devnull docker exec "sf-host${SF_HOST_CONTAINER_NAME_SUFFIX}" mkdir "${SF_WWW_ROOT_DIR}/${SF_HOSTNAME,,}"
|
||||
# else
|
||||
# mkdir "${SF_WWW_ROOT_DIR}/${SF_HOSTNAME,,}" || ERREXIT
|
||||
# fi
|
||||
# }
|
||||
### Create ONION directory => From within encfsd (to set XFS quota)
|
||||
|
||||
# Starting GUEST shell
|
||||
# Challenge: Keep user processes running that got spawned in the background
|
||||
|
@ -171,6 +171,7 @@ init_config_run()
|
||||
mergedir "sfbin"
|
||||
}
|
||||
|
||||
|
||||
docker_fixdir()
|
||||
{
|
||||
[[ ! -d /sf/docker ]] && return
|
||||
@ -191,6 +192,33 @@ docker_fixdir()
|
||||
ln -s /sf/docker /var/lib/docker || return
|
||||
}
|
||||
|
||||
# Install $1 from provision/system to ${2}/${1}
|
||||
xinstall()
|
||||
{
|
||||
local fn
|
||||
local dir
|
||||
fn="$1"
|
||||
dir="$2"
|
||||
|
||||
[[ -f "${dir}/${fn}" ]] && { CONFLICT+=("${dir}/${fn}"); return 1; }
|
||||
|
||||
cp -a "${SFI_SRCDIR}/provision/system/${fn}" "${dir}" || ERREXIT 233
|
||||
}
|
||||
|
||||
docker_config()
|
||||
{
|
||||
local ncpu
|
||||
|
||||
xinstall daemon.json /etc/docker/
|
||||
xinstall docker_limit.slice /etc/systemd/system/ && {
|
||||
ncpu=$(nproc)
|
||||
[[ -n $ncpu ]] && ncpu=1
|
||||
sed "s/CPUQuota=.*/CPUQuota=${ncpu}00%/" -i /etc/systemd/system/docker_limit.slice
|
||||
sed 's/^Restart=always.*$/Restart=on-failure\nSlice=docker_limit.slice/' -i /lib/systemd/system/docker.service
|
||||
sed 's/^OOMScoreAdjust=.*$/OOMScoreAdjust=-1000/' -i /lib/systemd/system/docker.service
|
||||
}
|
||||
}
|
||||
|
||||
docker_start()
|
||||
{
|
||||
docker ps >/dev/null && return
|
||||
@ -216,6 +244,7 @@ init_basedir
|
||||
# Install Docker and docker-cli
|
||||
install_docker
|
||||
docker_fixdir
|
||||
docker_config
|
||||
docker_start
|
||||
|
||||
# SSHD's login user (normally 'root' with uid 1000) needs to start docker instances
|
||||
@ -329,7 +358,7 @@ INFO "SSH : ${CDC}ssh ${PORTSTR}${SF_USER:-root}@${SF_FQDN:-UNKN
|
||||
INFO "SSH (gsocket) : ${CDC}gsocket -s ${GS_SECRET} ssh ${SF_USER:-root}@${SF_FQDN%.*}.gsocket${CN}"
|
||||
|
||||
[[ -n $CONFLICT ]] && {
|
||||
WARN 7 "Not updating these directories in ${SF_BASEDIR}:"
|
||||
WARN 7 "Not updating these:"
|
||||
for x in "${CONFLICT[@]}"; do
|
||||
INFO "${x}"
|
||||
done
|
||||
|
@ -28,9 +28,11 @@ ERR()
|
||||
|
||||
WARN()
|
||||
{
|
||||
echo -e >&2 "[$(date '+%F %T' -u)] [${CDY}WARN${CN}] $*"
|
||||
((IS_WARN++))
|
||||
echo -e >&2 "[$(date '+%F %T' -u)] [${CDY}#${IS_WARN} WARN${CN}] $*"
|
||||
}
|
||||
|
||||
|
||||
LOG()
|
||||
{
|
||||
local lid
|
||||
@ -57,3 +59,11 @@ else
|
||||
DEBUGF(){ echo -e 1>&2 "${CY}DEBUG:${CN} $*";}
|
||||
fi
|
||||
|
||||
WARN_ENTER()
|
||||
{
|
||||
[[ -z $IS_WARN ]] && return
|
||||
unset IS_WARN
|
||||
|
||||
echo "Press Enter to continue. Aborting in 10 seconds otherwise..."
|
||||
read -t 10 || ERREXIT 255 "Aborting. User did not press Enter."
|
||||
}
|
||||
|
@ -71,14 +71,27 @@ cmd_delipports()
|
||||
{
|
||||
local ipport
|
||||
local r_port
|
||||
local res
|
||||
local err
|
||||
|
||||
[[ "${PROVIDER,,}" != "cryptostorm" ]] && return
|
||||
|
||||
DEBUGF "cmd_delipports ${PROVIDER} '${*}'"
|
||||
|
||||
err=1
|
||||
for ipport in "$@"; do
|
||||
r_port="${ipport##*:}"
|
||||
curl -fsSL --retry 3 --max-time 10 http://10.31.33.7/fwd "-ddelfwd=${r_port}"
|
||||
res=$(curl -fsSL --retry 3 --max-time 10 http://10.31.33.7/fwd "-ddelfwd=${r_port}" 2>/dev/null) && {
|
||||
[[ $res == *"has been removed"* ]] && unset err
|
||||
}
|
||||
|
||||
[[ -n $err ]] && {
|
||||
ERR "${PROVIDER} Failed to remove Port Forward (${ipport})"
|
||||
echo "------------------------"
|
||||
echo "${res:0:1024}"
|
||||
echo "------------------------"
|
||||
}
|
||||
|
||||
fw_del "${r_port}"
|
||||
done
|
||||
}
|
||||
|
77
sfbin/sf
77
sfbin/sf
@ -8,6 +8,7 @@
|
||||
export SF_REDIS_AUTH
|
||||
}
|
||||
|
||||
|
||||
[[ "$1" != up ]] && exec docker-compose "$@"
|
||||
|
||||
# HERE: "up"
|
||||
@ -16,17 +17,73 @@ source "${BINDIR}/funcs.sh" || exit 254
|
||||
|
||||
[[ -z $SF_SEED ]] && ERREXIT 255 "SF_SEED= not set"
|
||||
|
||||
# Sub-Shell because we source .env but need clean environment afterwards.
|
||||
(
|
||||
[[ -z $SF_BASEDIR ]] && [[ -f .env ]] && eval $(grep ^SF_BASEDIR .env)
|
||||
[[ -z $SF_BASEDIR ]] && ERREXIT 255 "SF_BASEDIR= not set or ./.env not found."
|
||||
# [DIR] [project name] [id] [INODE-LIMIT]
|
||||
xfs_init_quota()
|
||||
{
|
||||
local dir
|
||||
local prj
|
||||
local id
|
||||
local ihard
|
||||
local err
|
||||
dir=$(readlink -f "$1")
|
||||
prj=$2
|
||||
id=$3
|
||||
ihard=$4
|
||||
|
||||
[[ -z $SF_DATADIR ]] && SF_DATADIR="${SF_BASEDIR}/data"
|
||||
[[ ! -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'\`."
|
||||
}
|
||||
)
|
||||
command -v xfs_quota &>/dev/null || { WARN "[${prj}] XFS-QUOTA not set"; return 255; }
|
||||
|
||||
grep "^${prj}" /etc/projid >/dev/null || echo "${prj}:${id}" >>/etc/projid
|
||||
# This survives a reboot but maybe our parameters have changed. Set to latest:
|
||||
xfs_quota -x -c "limit -p ihard=${ihard} ${prj}" || { WARN "[${prj}] XFS-QUOTA not set"; return 255; }
|
||||
xfs_quota -x -c "project -s -p${dir} ${prj}" >/dev/null || { WARN "[${prj}] XFS-QUOTA not set"; return 255; }
|
||||
|
||||
echo "[${dir##*/}] Quota set to ihard=${ihard}."
|
||||
}
|
||||
|
||||
# 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%%=*}"
|
||||
# Prefer user's environemtn over .env settings.
|
||||
[[ -z "$(eval echo \$$n)" ]] && eval "${a}"
|
||||
done
|
||||
fi
|
||||
|
||||
[[ -z $SF_BASEDIR ]] && ERREXIT 255 "SF_BASEDIR= not set in ${envfile}."
|
||||
}
|
||||
|
||||
load_env
|
||||
|
||||
[[ -z $SF_DATADIR ]] && SF_DATADIR="${SF_BASEDIR}/data"
|
||||
[[ ! -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'\`."
|
||||
}
|
||||
|
||||
xfs_init_quota "${SF_DATADIR}/everyone-root" "everyone" 100 1024
|
||||
|
||||
# If there was a warning then wait...
|
||||
WARN_ENTER
|
||||
|
||||
[[ -z $SF_DATADEV ]] && {
|
||||
d=$(mount | grep -F "${SF_DATADIR}" | head -n1)
|
||||
export SF_DATADEV="${d%% *}"
|
||||
}
|
||||
|
||||
exec docker-compose "$@"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user