Skip to content

Possible Memory Leakage #91

@Xaelp

Description

@Xaelp

I am running a container that I use to proxy requests to the tor network. I've setup memory limit to 350MB and I noticed that , recurrently, the container memory usage grows till maximum over and over again. I've tried increasing it and still happens which suggests memory leaking somewhere.

Image

Does anyone have had this issue before? could be from Privoxy or Tor process but haven't dug deep to check it.

Configuration

Dockerfile:

FROM alpine:3.16

RUN apk --no-progress upgrade && \
    apk --no-progress add bash curl privoxy shadow tini tor tzdata && \
    file='/etc/privoxy/config' && \
    mv ${file}.new $file && \
    mv /etc/privoxy/default.action.new /etc/privoxy/default.action && \
    mv /etc/privoxy/default.filter.new /etc/privoxy/default.filter && \
    mv /etc/privoxy/match-all.action.new /etc/privoxy/match-all.action && \
    mv /etc/privoxy/regression-tests.action.new /etc/privoxy/regression-tests.action && \
    mv /etc/privoxy/trust.new /etc/privoxy/trust && \
    mv /etc/privoxy/user.action.new /etc/privoxy/user.action && \
    mv /etc/privoxy/user.filter.new /etc/privoxy/user.filter && \
    sed -i 's|^\(accept-intercepted-requests\) .*|\1 1|' $file && \
    sed -i '/^listen/s|127\.0\.0\.1||' $file && \
    sed -i '/^listen.*::1/s|^|#|' $file && \
    sed -i 's|^\(logfile\)|#\1|' $file && \
    sed -i 's|^#\(log-messages\)|\1|' $file && \
    sed -i 's|^#\(log-highlight-messages\)|\1|' $file && \
    sed -i '/forward *localhost\//a forward-socks5t / 127.0.0.1:9050 .' $file &&\
    sed -i '/^forward-socks5t \//a forward 172.16.*.*/ .' $file && \
    sed -i '/^forward 172\.16\.\*\.\*\//a forward 172.17.*.*/ .' $file && \
    sed -i '/^forward 172\.17\.\*\.\*\//a forward 172.18.*.*/ .' $file && \
    sed -i '/^forward 172\.18\.\*\.\*\//a forward 172.19.*.*/ .' $file && \
    sed -i '/^forward 172\.19\.\*\.\*\//a forward 172.20.*.*/ .' $file && \
    sed -i '/^forward 172\.20\.\*\.\*\//a forward 172.21.*.*/ .' $file && \
    sed -i '/^forward 172\.21\.\*\.\*\//a forward 172.22.*.*/ .' $file && \
    sed -i '/^forward 172\.22\.\*\.\*\//a forward 172.23.*.*/ .' $file && \
    sed -i '/^forward 172\.23\.\*\.\*\//a forward 172.24.*.*/ .' $file && \
    sed -i '/^forward 172\.24\.\*\.\*\//a forward 172.25.*.*/ .' $file && \
    sed -i '/^forward 172\.25\.\*\.\*\//a forward 172.26.*.*/ .' $file && \
    sed -i '/^forward 172\.26\.\*\.\*\//a forward 172.27.*.*/ .' $file && \
    sed -i '/^forward 172\.27\.\*\.\*\//a forward 172.28.*.*/ .' $file && \
    sed -i '/^forward 172\.28\.\*\.\*\//a forward 172.29.*.*/ .' $file && \
    sed -i '/^forward 172\.29\.\*\.\*\//a forward 172.30.*.*/ .' $file && \
    sed -i '/^forward 172\.30\.\*\.\*\//a forward 172.31.*.*/ .' $file && \
    sed -i '/^forward 172\.31\.\*\.\*\//a forward 10.*.*.*/ .' $file && \
    sed -i '/^forward 10\.\*\.\*\.\*\//a forward 192.168.*.*/ .' $file && \
    sed -i '/^forward 192\.168\.\*\.\*\//a forward 127.*.*.*/ .' $file && \
    sed -i '/^forward 127\.\*\.\*\.\*\//a forward localhost/ .' $file && \
    sed -i 's/actionsfile match-all.action/#actionsfile match-all.action/' $file && \
    sed -i 's/actionsfile default.action/#actionsfile default.action/' $file && \
    sed -i 's/actionsfile user.action/#actionsfile user.action/' $file && \
    torrc='/etc/tor/torrc' && \
    echo 'AutomapHostsOnResolve 1' >>$torrc && \
    echo 'ControlPort 9051' >>$torrc && \
    echo 'ControlSocket /etc/tor/run/control' >>$torrc && \
    echo 'ControlSocketsGroupWritable 1' >>$torrc && \
    echo 'CookieAuthentication 1' >>$torrc && \
    echo 'CookieAuthFile /etc/tor/run/control.authcookie' >>$torrc && \
    echo 'CookieAuthFileGroupReadable 1' >>$torrc && \
    echo 'DNSPort 5353' >>$torrc && \
    echo 'DataDirectory /var/lib/tor' >>$torrc && \
    echo 'ExitPolicy reject *:*' >>$torrc && \
    echo 'Log notice stderr' >>$torrc && \
    echo 'RunAsDaemon 0' >>$torrc && \
    echo 'SocksPort 0.0.0.0:9050 IsolateDestAddr' >>$torrc && \
    echo 'TransPort 0.0.0.0:9040' >>$torrc && \
    echo 'User tor' >>$torrc && \
    echo 'VirtualAddrNetworkIPv4 10.192.0.0/10' >>$torrc && \
    mkdir -p /etc/tor/run && \
    chown -Rh tor. /var/lib/tor /etc/tor/run && \
    chmod 0750 /etc/tor/run && \
    rm -rf /tmp/*

COPY torproxy.sh /usr/bin/

EXPOSE 8118 9051

HEALTHCHECK --interval=60s --timeout=15s --start-period=20s \
            CMD curl -sx localhost:8118 'https://check.torproject.org/' | \
            grep -qm1 Congratulations

VOLUME ["/etc/tor", "/var/lib/tor"]

ENTRYPOINT ["/sbin/tini", "--", "/usr/bin/torproxy.sh"]

torproxy.sh:

#!/usr/bin/env bash

set -o nounset                              # Treat unset variables as an error

### bandwidth: set the BW available for relaying
# Arguments:
#   KiB/s) KiB/s of data that can be relayed
# Return: Updated configuration file
bandwidth() { local kbs="${1:-10}" file=/etc/tor/torrc
    sed -i '/^RelayBandwidth/d' $file
    echo "RelayBandwidthRate $kbs KB" >>$file
    echo "RelayBandwidthBurst $(( kbs * 2 )) KB" >>$file
}

### exitnode: Allow exit traffic
# Arguments:
#   N/A)
# Return: Updated configuration file
exitnode() { local file=/etc/tor/torrc
    sed -i '/^ExitPolicy/d' $file
}

### exitnode_country: Only allow traffic to exit in a specified country
# Arguments:
#   country) country where we want to exit
# Return: Updated configuration file
exitnode_country() { local country="$1" file=/etc/tor/torrc
    sed -i '/^StrictNodes/d; /^ExitNodes/d' $file
    echo "StrictNodes 1" >>$file
    echo "ExitNodes {$country}" >>$file
}

### hidden_service: setup a hidden service
# Arguments:
#   port) port to connect to service
#   host) host:port where service is running
# Return: Updated configuration file
hidden_service() { local port="$1" host="$2" file=/etc/tor/torrc
    sed -i '/^HiddenServicePort '"$port"' /d' $file
    grep -q '^HiddenServiceDir' $file ||
        echo "HiddenServiceDir /var/lib/tor/hidden_service" >>$file
    echo "HiddenServicePort $port $host" >>$file
}

### newnym: setup new circuits
# Arguments:
#   N/A)
# Return: New circuits for tor connections
newnym() { local file=/etc/tor/run/control.authcookie
    echo -e 'AUTHENTICATE "'"$(cat $file)"'"\nSIGNAL NEWNYM\nQUIT' |
                nc 127.0.0.1 9051
    if ps -ef | egrep -v 'grep|torproxy.sh' | grep -q tor; then exit 0; fi
}

### password: setup a hashed password
# Arguments:
#   passwd) passwd to set
# Return: Updated configuration file
password() { local passwd="$1" file=/etc/tor/torrc
    sed -i '/^HashedControlPassword/d' $file
    sed -i '/^ControlPort/s/ 9051/ 0.0.0.0:9051/' $file
    echo "HashedControlPassword $(su - tor -s/bin/bash -c \
                "tor --hash-password '$passwd' |tail -n 1")" >>$file 2>/dev/null
}

### usage: Help
# Arguments:
#   none)
# Return: Help text
usage() { local RC="${1:-0}"
    echo "Usage: ${0##*/} [-opt] [command]
Options (fields in '[]' are optional, '<>' are required):
    -h          This help
    -b \"\"       Configure tor relaying bandwidth in KB/s
                possible arg: \"[number]\" - # of KB/s to allow
    -e          Allow this to be an exit node for tor traffic
    -l \"<country>\" Configure tor to only use exit nodes in specified country
                required args: \"<country>\" (IE, "US" or "DE")
                <country> - country traffic should exit in
    -n          Generate new circuits now
    -p \"<password>\" Configure tor HashedControlPassword for control port
    -s \"<port>;<host:port>\" Configure tor hidden service
                required args: \"<port>;<host:port>\"
                <port> - port for .onion service to listen on
                <host:port> - destination for service request

The 'command' (if provided and valid) will be run instead of torproxy
" >&2
    exit $RC
}

while getopts ":hb:el:np:s:" opt; do
    case "$opt" in
        h) usage ;;
        b) bandwidth "$OPTARG" ;;
        e) exitnode ;;
        l) exitnode_country "$OPTARG" ;;
        n) newnym ;;
        p) password "$OPTARG" ;;
        s) eval hidden_service $(sed 's/^/"/; s/$/"/; s/;/" "/g' <<< $OPTARG) ;;
        "?") echo "Unknown option: -$OPTARG"; usage 1 ;;
        ":") echo "No argument value for option: -$OPTARG"; usage 2 ;;
    esac
done
shift $(( OPTIND - 1 ))

[[ "${BW:-""}" ]] && bandwidth "$BW"
[[ "${EXITNODE:-""}" ]] && exitnode
[[ "${LOCATION:-""}" ]] && exitnode_country "$LOCATION"
[[ "${PASSWORD:-""}" ]] && password "$PASSWORD"
[[ "${SERVICE:-""}" ]] && eval hidden_service \
            $(sed 's/^/"/; s/$/"/; s/;/" "/g' <<< $SERVICE)
[[ "${USERID:-""}" =~ ^[0-9]+$ ]] && usermod -u $USERID -o tor
[[ "${GROUPID:-""}" =~ ^[0-9]+$ ]] && groupmod -g $GROUPID -o tor
for env in $(printenv | grep '^TOR_'); do
    name="$(cut -c5- <<< ${env%%=*})"
    val="\"${env##*=}\""
    [[ "$name" =~ _ ]] && continue
    [[ "$val" =~ ^\"([0-9]+|false|true)\"$ ]] && val="$(sed 's|"||g' <<< $val)"
    if grep -q "^$name" /etc/tor/torrc; then
        sed -i "/^$name/s| .*| $val|" /etc/tor/torrc
    else
        echo "$name $val" >>/etc/tor/torrc
    fi
done

chown -Rh tor. /etc/tor /var/lib/tor /var/log/tor 2>&1 |
            grep -iv 'Read-only' || :

if [[ $# -ge 1 && -x $(which $1 2>&-) ]]; then
    exec "$@"
elif [[ $# -ge 1 ]]; then
    echo "ERROR: command not found: $1"
    exit 13
elif ps -ef | egrep -v 'grep|torproxy.sh' | grep -q tor; then
    echo "Service already running, please restart container to apply changes"
else
    [[ -e /srv/tor/hidden_service/hostname ]] && {
        echo -en "\nHidden service hostname: "
        cat /srv/tor/hidden_service/hostname; echo; }
    /usr/sbin/privoxy --user privoxy /etc/privoxy/config
    exec /usr/bin/tor
fi

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions