Shared publicly  - 
 
Total bandwidth control on Ubuntu

Due to an unfortunate series of events, I went from uncapped free high-speed broadband to no internet within the span of a week. I'm now limping along with some expensive data bundles until a few week's time when I can upgrade my iBurst package and get back to large caps.

Since I am running Ubuntu, I figured I'd be able to limit my bandwidth usage quite easily, unlike on some other OS's where cloud services and background updates suck your bandwidth when you're doing nothing. Unfortunately, even on Ubuntu, background services and other unknown processes chew through data unpredictably. Once, I tethered my 3G phone to Ubuntu, only to have Ubuntu use up 63Mb of data without me having browsed any websites! So I figured I needed total control.

Firewall
Typically, the solution is to use a firewall. Unfortunately, I couldn't find a way to firewall by application - allowing just HTTP traffic already gives access to most background scripts and updaters, since that is the port they all use. What I wanted was quite simple: block everything and allow only Firefox access to the internet. Also maybe any other app I specifically choose to allow, e.g. Skype.

On Mac OS, I'd bought an app to block all access and have a whitelist of apps I allowed, but even this was less than ideal, because often I would have to grant "python" or "java" access, which means a whole lot of apps, not just one. Also, maintaining that whitelist was a pain and often I'd have to disable the firewall to let the OS update or install apps.

The magic solution
I found a solution that is simple and easy to use, although a bit of command-line use is needed: I created a group called "internet" and set up a firewall rule to block all traffic other than that initiated by a user in the "internet" group.

Now, if I just added my user to the "internet" group, then all apps I start will have internet access (including all the unwanted background services that start when I log in), so instead, I don't add myself to the group. So by default, no apps have internet access. Now I open a terminal and grant that terminal access to the "internet" group, so that any app I start from that terminal will have internet access. Total control!

This might sound complicated, but it's simple. First, create the "internet" group like so:
sudo groupadd internet

Then, save this into a script:

#!/bin/sh
# Firewall apps - only allow apps run from "internet" group to run

# clear previous rules
sudo iptables -F

# accept packets for internet group
sudo iptables -A OUTPUT -p tcp -m owner --gid-owner internet -j ACCEPT

# also allow local connections
sudo iptables -A OUTPUT -p tcp -d 127.0.0.1 -j ACCEPT
sudo iptables -A OUTPUT -p tcp -d 192.168.0.1/24 -j ACCEPT

# reject packets for other users
sudo iptables -A OUTPUT -p tcp -j REJECT

# open a shell with internet access
sudo -g internet -s

Once you run the above script, all access is blocked (except for already-established connections, which you may need to kill), and you get a shell with internet access. Now just launch Firefox, Skype, or any other app from this terminal and only those apps will have internet access. No more run-away bandwidth leaks.

You can use "sudo watch netstat -tnp" to see which apps have internet connections (see screenshot). It's nice to have total control.
8
2
Rudi von Staden's profile photoJonathan Rung's profile photoWerdna Revicm's profile photoRichard Wooding's profile photo
8 comments
 
Thanks +Toby Kurien for the nice howto.

iftop and bwm-ng are two nice CLI tools that show current (not historical) bandwidth information. iftop is like "top" for your network connections.

... and for (rooted) android #Droidwall is a must :-)
 
Saving a copy of this now, because normally when you need this, you only have limited expensive bandwidth available... Thanks!
 
One caveat: remember that even root won't have internet access, so to run "sudo apt-get update" for example, you will need to explicitly grant internet access like so: sudo -g internet -u root apt-get update
 
Thanks +Toby Kurien, nice script! I've modified a couple of things in my setup - first, it saves the current rules before clearing; second, it opens the shell as your user rather than as root; and finally, when you exit the shell (type 'exit'), it restores the rules to the previous state. Seems to work this way too.

#!/bin/sh
# Firewall apps - only allow apps run from "internet" group to run

# save current rules
sudo sh -c "iptables-save > /etc/iptables.rules"

# clear previous rules
sudo iptables -F

# accept packets for internet group
sudo iptables -A OUTPUT -p tcp -m owner --gid-owner internet -j ACCEPT

# also allow local connections
sudo iptables -A OUTPUT -p tcp -d 127.0.0.1 -j ACCEPT
sudo iptables -A OUTPUT -p tcp -d 192.168.0.1/24 -j ACCEPT

# reject packets for other users
sudo iptables -A OUTPUT -p tcp -j REJECT

# open a shell with internet access, and restore rules when shell closes
sudo -g internet -u <username> -s; sudo iptables-restore < /etc/iptables.rules 
 
hmm... the -u <username> switch doesn't seem to work, which means I have to run everything as root. Am I missing something?
 
My last command (sudo -g internet -s) opens a terminal in your username (not root), but with the added group permission. To run as root, you would do this: sudo -g internet -u root -s
 
Seems there are some issues with that command (sudo -g internet -s) on my system: "Sorry, user rudi is not allowed to execute '/bin/bash' as rudi:internet on rudi-dell." ...

After some research, I figured out that to run a command as a different group on ubuntu, you need to edit the admin group permissions in your /etc/sudoers file so that it reads "%admin ALL=(ALL:ALL) ALL". See http://askubuntu.com/questions/162390/run-as-group-fails-sudo-g/162420#162420
and
http://askubuntu.com/questions/43317/what-is-the-difference-between-the-sudo-and-admin-group if you're interested.
 
+Toby Kurien, thanks! I'm using my phone to tether, and was worried about unexpected data, so tried using a small handful of firewall software programs from the USC.  None of them were quite what I was looing for; like you, limiting to HTTP didn't seem like much insurance, and the other programs were over hy head.  Luckily, I found your script, and it's working perfectly.  Such an elegant solution!

If you ever have spare time for a little project, I would love to have a little notification program for this script with a really simple, utilitarian GUI that lists user accessible applications (or maybe even a user-defined list, if you want to get fancy) on one side, and the running applications with connections on the other side.  You could click, say, firefox+thunderbird from the user apps to bring them over to the active connections, and click on the open, undesired active connections to block them.

Just an idea, but there are lots of tethered people out there!  Regardless, thanks again!
Add a comment...