Feb 24, 2016
I wanted to create an environment where the only way a container
can access network is through Tor.
This means I can run a program (e.g. browser)
and be certain that it have no way revealing the connection.
That is, I want to run some of the applications through Tor, but not others.
All the possible related work is done by @jfrazelle.
One can transparent proxy all the traffic
or create a local proxy
The latter is almost what we want except that
the application must speak SOCKS, and is not forced to use the proxy.
There is even a video
about this latter approach.
Implementation
The idea is to start a new container with enough capability
to change iptables rules.
One can simply copy the transparent proxy scripts
form the Tor wiki and run it inside that container.
Any process in this container must go through the iptables rules, thus use Tor.
You can check my implementation here.
To start it:
docker run -d --cap-add NET_ADMIN --name=tor root_tor
The container sets some iptables rules after start;
at least the following is needed:
iptables -t nat -A OUTPUT -m owner --uid-owner $_tor_uid -j RETURN
iptables -t nat -A OUTPUT -p tcp --syn -j REDIRECT --to-ports 9040
iptables -A OUTPUT -m owner --uid-owner $_tor_uid -j ACCEPT
iptables -A OUTPUT -d 127.0.0.0/8 -j ACCEPT
iptables -A OUTPUT -m state --state ESTABLISHED -j ACCEPT
iptables -A OUTPUT -j REJECT
Check (from inside) that it really acts as a transparent proxy:
curl -k https://check.torproject.org/api/ip
With recent enough docker, one can create a special network with this container;
with older version (from 1.0), one can still
put containers (e.g. Chrome) into the network namespace of this Tor container.
docker run --rm -it \
--net=container:tor \
-e DISPLAY=:0 -v /tmp/.X11-unix/X0:/tmp/.X11-unix/X0:ro \
-u=$(id -u) -e HOME=/tmp \
--name=chrome \
jess/chrome --no-sandbox
Happy browsing!
Beware: Chrome can SIGBUS because /dev/shm
in Docker is small (only 64M).
Aug 20, 2015
Tales of a bughunt
All began with reading @jfrazelle stuffs about dockerizing desktop apps.
Some programs are not so good citizens, i.e. Okular leaves a KDE daemon running.
Another serious contender is my browser, Chromium, which after the
Google voice blob thing seemed appropriate to contain.
Something that is more private than private browsing and cannot use my
webcam/sound card would be really nice…
After learning Docker X sharing (simple bind mount), it should be easy to
create
or use someone else’s docker. Run it like
docker run --rm -it -e DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix:ro chromium_gui
and check some website: Aw, Snap!
. From previous experience, it may be SIGSEGV
Let’s check as usual: with gdb and strace:
#strace -ff -o log chromium --no-sandbox --user-data-dir=/tmp
log.143:--- SIGBUS {si_signo=SIGBUS, si_code=BUS_ADRERR, si_addr=0x7f3355a2b000} ---
SIGBUS on x86? gdb backtrace seems perfectly legal.
Google was not really helpful on this. And this is the same even for ssh X forward.
To check that this is really a Docker issue, I went insane:
mount --bind / /mnt/root/
mount --bind /sys/ /mnt/root/sys/
mount --bind /proc/ /mnt/root/proc/
mount --bind /dev/ /mnt/root/dev/
chroot /mnt/root/
chromium --no-sandbox --user-data-dir=/tmp
Of course, it worked. This bind mounts in Docker?
Works too; turns out, only /dev is needed (on Debian jessie).
Fortunately Debian sid (the other version I use)
differs in that /dev/shm
is a symlink to /run/shm
.
Mounting /dev
worked only jessie; on sid I got something like:
Creating shared memory in /dev/shm/.org.chromium.Chromium.sSLYBL failed: Permission denied
Unable to access(W_OK|X_OK) /dev/shm: Permission denied
This is frequently caused by incorrect permissions on /dev/shm. Try 'sudo chmod 1777 /dev/shm' to fix.
This leads to this Docker issue
and one possible workaround for the SIGBUS:
-v /dev/shm:/dev/shm -v /run/shm:/run/shm
Reduced steps to reproduce
What now? Is it that 64M /dev/shm is not enough for chromium?
What if mount -o remount,size=64M /dev/shm
? Aw, snap!
Unfortunately watching the output of df
came to my mind only this time.
Chromium uses /dev/shm
, but it does not really need shared memory;
mount --bind /tmp/ /dev/shm/
works perfectly too.
Getting this crash is not that far fetched; I managed get Aw, snap! on a machine
with 2G RAM by leaving the same amount of tabs I usually do on my >8G machines.
Lessons learned
- Google and
Stack Overflow
can be horribly wrong
- SIGBUS-ing on tmpfs full is an awful error message
- Watching the health of the system/docker container would have saved tons of time