mighty-snitch

mighty-snitch

noticing and preventing network requests should be easy

github.com/nathants/mighty-snitch

why

noticing and preventing network requests should be easy.

how

interactively filter network requests with rules and visual prompts.

what

a linux security module communicates via netlink with the userspace snitch on each sendmsg/recvmsg.

snitch decides whether to allow or deny the network request.

rules are checked. if no rule exists, a visual prompt is displayed to the user.

finally snitch responds to the kernel and the request is allowed or denied.

demo

hardware

the primary test environments are alpine x86_64 and postmarketos arm64.

the primary test devices are thinkpad x1 and oneplus 6t.

prior art

little-snitch which introduced me to this concept.

open-snitch which introduced me to nfq.

tiny-snitch which helped me understand what is possible with nfq and bpftrace.

uslm which helped me understand what is possible with lsm.

design

mighty-snitch uses lsm instead of nfq to filter network requests.

the primary advantage is that it has direct access to the pid, executable, and commandline of the process making the request.

the primary disadvantage is that it requires a custom kernel.

the visual prompt is a terminal application which responds to keyboard input. a new terminal is launched for each prompt and exits after y/n are pressed. st is used on x86_64 and foot is used on arm64, though any terminal should work.

the systems fails closed. when snitch isn't running, network requests are not possible.

dns packets received on udp 53 are read via nfq so that rules can specify domains in addition to ipv4 addresses.

constraints

the following are simplifying constraints. other configurations should be possible.

  • ipv6 is disabled.

  • io_uring is disabled.

  • nftables rules are replaced when snitch starts.

  • iptables rules should be empty.

  • all other lsm are disabled.

  • kernel commandline parameters for lsm are ignored.

rules

snitch creates a rules file: ~/.snitch.rules

when this file is edited, snitch reloads the rules.

typically rules are created by choosing the forever duration in the visual prompt, but can also be directly added to the rules file.

address can be a wildcard up to three subdomains.

commandline can be a wildcard.

here are the rules for firefox to deny all the unprompted connections it makes:

send  deny  /usr/lib/firefox/firefox  content-signature-2.cdn.mozilla.net    443  tcp  /usr/lib/firefox/firefox
send  deny  /usr/lib/firefox/firefox  content-signature-2.cdn.mozilla.net    80   tcp  /usr/lib/firefox/firefox
send  deny  /usr/lib/firefox/firefox  contile.services.mozilla.com           443  tcp  /usr/lib/firefox/firefox
send  deny  /usr/lib/firefox/firefox  firefox.settings.services.mozilla.com  443  tcp  /usr/lib/firefox/firefox
send  deny  /usr/lib/firefox/firefox  firefox.settings.services.mozilla.com  443  udp  /usr/lib/firefox/firefox
send  deny  /usr/lib/firefox/firefox  getpocket.cdn.mozilla.net              443  tcp  /usr/lib/firefox/firefox
send  deny  /usr/lib/firefox/firefox  location.services.mozilla.com          443  tcp  /usr/lib/firefox/firefox
send  deny  /usr/lib/firefox/firefox  mozilla.cloudflare-dns.com             443  tcp  /usr/lib/firefox/firefox
send  deny  /usr/lib/firefox/firefox  normandy.cdn.mozilla.net               443  tcp  /usr/lib/firefox/firefox
send  deny  /usr/lib/firefox/firefox  push.services.mozilla.com              443  tcp  /usr/lib/firefox/firefox
send  deny  /usr/lib/firefox/firefox  shavar.services.mozilla.com            443  tcp  /usr/lib/firefox/firefox

install x86_64

copy latest wget urls from: https://github.com/nathants/mighty-snitch/releases

cd /tmp
wget linux-edge-*.apk
wget linux-edge-dev-*.apk
wget me@nathants.com-*.rsa.pub
sudo mv *.pub /etc/apk/keys/
sudo apk add *.apk
sudo reboot

cd ~
git clone https://github.com/nathants/mighty-snitch

cd ~/might-snitch/snitch-prompt
sudo pip install .

cd ~/mighty-snitch/snitch
bash snitch.sh

install arm64

copy latest wget urls from: https://github.com/nathants/mighty-snitch/releases

cd /tmp
wget linux-postmarketos-qcom-sdm845-*.apk
wget pmos@local-*.rsa.pub
sudo mv *.pub /etc/apk/keys/
sudo apk add *.apk
sudo reboot

cd ~
git clone https://github.com/nathants/mighty-snitch

cd ~/might-snitch/snitch-prompt
sudo pip install .

cd ~/mighty-snitch/snitch
bash snitch.sh

build on aws and install x86_64

sudo apk add go
go install github.com/nathants/libaws@latest
export PATH=$PATH:$(go env GOPATH)/bin

export MIGHTY_SNITCH_S3_BUCKET=$NAME
export MIGHTY_SNITCH_AWS_ACCOUNT=$ACCOUNT_NUMBER
export MIGHTY_SNITCH_PUBKEY_CONTENT=$(cat ~/.ssh/id_ed25519.pub)

cd ~
git clone https://github.com/nathants/mighty-snitch

cd ~/might-snitch/kernel/alpine
bash build.sh
sudo mv /tmp/abuild/*.pub /etc/apk/keys/
sudo apk add /tmp/packages/*/*/*.apk
sudo reboot

cd ~/mighty-snitch/snitch-prompt
sudo pip install .

cd ~/mighty-snitch/snitch
bash snitch.sh

build on aws and install arm64

sudo apk add go
go install github.com/nathants/libaws@latest
export PATH=$PATH:$(go env GOPATH)/bin

export MIGHTY_SNITCH_S3_BUCKET=$NAME
export MIGHTY_SNITCH_AWS_ACCOUNT=$ACCOUNT_NUMBER
export MIGHTY_SNITCH_PUBKEY_CONTENT=$(cat ~/.ssh/id_ed25519.pub)

cd ~
git clone https://github.com/nathants/mighty-snitch

cd ~/mighty-snitch/kernel/alpine-sdm845
bash build.sh
sudo mv /tmp/*.pub /etc/apk/keys/
sudo apk add /tmp/*.apk
sudo reboot

cd ~/mighty-snitch/snitch-prompt
sudo pip install .

cd ~/mighty-snitch/snitch
bash snitch.sh