Hi,
FWIW. Not sure what exactly we can use this for, but I would not be
surprised if this could help make some parts of Tails safer or the
implementation more elegant :)
This article documents how the traffic of specific Linux processes can be
subjected to a custom firewall or routing configuration, thanks to the magic
of cgroups. We will use the [Network classifier
cgroup](
https://www.kernel.org/doc/Documentation/cgroups/net_cls.txt), which
allows tagging the packets sent by specific processes.
To create the cgroup which will be used to identify the processes I added
something like this to `/etc/rc.local`:
mkdir /sys/fs/cgroup/net_cls/unlocator
/bin/echo 42 > /sys/fs/cgroup/net_cls/unlocator/net_cls.classid
chown md: /sys/fs/cgroup/net_cls/unlocator/tasks
The `tasks` file, which controls the membership of processes in a cgroup, is
made writeable by my user: this way I can add new processes without becoming
root. 42 is the arbitrary class identifier that the kernel will associate with
the packets generated by the member processes.
A command like `systemd-cgls /sys/fs/cgroup/net_cls/` can be used to explore
which processes are in which cgroup.
I use a simple shell wrapper to start a shell or a new program as members of
this cgroup:
#!/bin/sh -e
CGROUP_NAME=unlocator
if [ ! -d /sys/fs/cgroup/net_cls/$CGROUP_NAME/ ]; then
echo "The $CGROUP_NAME net_cls cgroup does not exist!" >&2
exit 1
fi
/bin/echo $$ > /sys/fs/cgroup/net_cls/$CGROUP_NAME/tasks
if [ $# = 0 ]; then
exec ${SHELL:-/bin/sh}
fi
exec "$@"
My first goal is to use a _special_ name server for the DNS queries of some
processes, thanks to a second dnsmasq process which acts as a caching
forwarder.
`/etc/dnsmasq2.conf`:
port=5354
listen-address=127.0.0.1
bind-interfaces
no-dhcp-interface=*
no-hosts
no-resolv
server=185.37.37.37
server=185.37.37.185
`/etc/systemd/system/dnsmasq2.service`:
[Unit]
Description=dnsmasq - Second instance
Requires=network.target
[Service]
ExecStartPre=/usr/sbin/dnsmasq --test
ExecStart=/usr/sbin/dnsmasq --keep-in-foreground --conf-file=/etc/dnsmasq2.conf
ExecReload=/bin/kill -HUP $MAINPID
PIDFile=/run/dnsmasq/dnsmasq.pid
[Install]
WantedBy=multi-user.target
Do not forget to enable the new service:
systemctl enable dnsmasq2
systemctl start dnsmasq2
Since the [cgroup match extension](
https://git.netfilter.org/iptables/plain/ex
tensions/libxt_cgroup.man) is not yet available in a released version of
iptables, you will first need to build and install it manually:
git clone git://git.netfilter.org/iptables.git
cd iptables
./autogen.sh
./configure
make -k
sudo cp extensions/libxt_cgroup.so /lib/xtables/
sudo chmod -x /lib/xtables/libxt_cgroup.so
The netfilter configuration required is very simple: all DNS traffic from the
marked processes is redirected to the port of the local dnsmasq2:
iptables -t nat -A OUTPUT -m cgroup --cgroup 42 -p udp --dport 53 -j REDIRECT --to-ports 5354
iptables -t nat -A OUTPUT -m cgroup --cgroup 42 -p tcp --dport 53 -j REDIRECT --to-ports 5354
For related reasons, I also need to disable IPv6 for these processes:
ip6tables -A OUTPUT -m cgroup --cgroup 42 -j REJECT
I use a different cgroup to force some programs to use my office VPN by first
setting a netfilter packet mark on their traffic:
iptables -t mangle -A OUTPUT -m cgroup --cgroup 43 -j MARK --set-mark 43
The packet mark is then used to policy-route this traffic using a dedicate
VRF, i.e. routing table 43:
ip rule add fwmark 43 table 43
This VPN VRF just contains a default route for the VPN interface:
ip route add default dev tun0 table 43
Depending on your local configuration it may be a good idea to also add to the
VPN VRF the routes of your local interfaces:
ip route show scope link proto kernel \
| xargs -I ROUTE ip route add ROUTE table 43
Since the source address selection happens before the traffic is diverted to
the VPN, we also need to source-NAT to the VPN address the marked packets:
iptables -t nat -A POSTROUTING -m mark --mark 43 --out-interface tun0 -j MASQUERADE
URL:
http://blog.bofh.it/debian/id_457
--
intrigeri