PDA

View Full Version : [SOLVED] Using iptables to restrict web browsing



qprfact
January 4th, 2010, 08:07 AM
I have a small home network and an ISP that has download limits in business hours. Not an issue for me, as I am at work, but when kids come in they will go on internet! I want to restrict internet usage to IM only until 6pm when they can then look at sites too.

I have assigned static IPs and have set up iptables, but they are not stopping browsing. I don't know if this is down to the iptables, or perhaps the individual PC config.

This is what I have in resolv.conf for the PC most likely to use internet:


nameserver 208.67.222.222
nameserver 208.67.220.220

(Open DNS)

and this is in network/interfaces:


auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
#iface eth0 inet dhcp
#now static
address 192.168.2.4
netmask 255.255.255.0
network 192.168.1.1
broadcast 192.168.0.255
gateway 192.168.2.5

#auto eth1
#iface eth1 inet dhcp

#auto eth2
#iface eth2 inet dhcp

#auto ath0
#iface ath0 inet dhcp

#auto wlan0
#iface wlan0 inet static

ifconfig reads:


eth0 Link encap:Ethernet HWaddr 00:18:8b:77:32:bf
inet addr:192.168.2.4 Bcast:192.168.0.255 Mask:255.255.255.0
inet6 addr: fe80::218:8bff:fe77:32bf/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:4302693 errors:0 dropped:0 overruns:0 frame:0
TX packets:3855196 errors:0 dropped:0 overruns:0 carrier:0
collisions:1487171 txqueuelen:1000
RX bytes:3547798956 (3.5 GB) TX bytes:712400850 (712.4 MB)
Interrupt:19

lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:1234 errors:0 dropped:0 overruns:0 frame:0
TX packets:1234 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:169502 (169.5 KB) TX bytes:169502 (169.5 KB)

and the "restricted" iptables rules are:


# Amended version for daytime (peak) use
*nat
:PREROUTING ACCEPT [6:334]
:POSTROUTING ACCEPT [43:6498]
:OUTPUT ACCEPT [38:6234]
-A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -j MASQUERADE
COMMIT
# Completed on Wed Dec 30 17:09:31 2009
# Generated by iptables-save v1.4.4 on Wed Dec 30 17:09:31 2009
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [18:1381]
:OUTPUT ACCEPT [315:51848]

# Always on access for server

-A INPUT -s 192.168.2.5/32 -j ACCEPT

# Always on access for MacBook

-A INPUT -s 192.168.2.3/32 -j ACCEPT
-A INPUT -s 192.168.2.2/32 -j ACCEPT

# Loopback

-A INPUT -i lo -j ACCEPT

# DNS

-A INPUT -p tcp -m tcp --sport 53 -j ACCEPT
-A INPUT -p udp -m udp --sport 53 -j ACCEPT

# SSH

-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT

# MSN on Pidgin

-A INPUT -p tcp -m tcp --dport 1863 -j ACCEPT

# Logging

-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7

# HTTP

#-A INPUT -p tcp -m tcp --dport 80 -m comment --comment "http apache" -j ACCEPT

# HTTPS

#-A INPUT -p tcp -m tcp --dport 443 -m comment --comment "https apache" -j ACCEPT

# Established sessions

#-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

# Samba access

-A INPUT -s 192.168.2.0/24 -p tcp -m multiport --dports 139,145 -j ACCEPT
-A INPUT -s 192.168.2.0/24 -p udp -m multiport --dports 137,138 -j ACCEPT

# VNC

-A INPUT -s 192.168.2.0/24 -p tcp -m multiport --dports 5900,5901 -j ACCEPT

# Webmin

-A INPUT -p tcp -m tcp --dport 10000 -j ACCEPT

# Drop all else

-A INPUT -j DROP
COMMIT
# Completed on Wed Dec 30 17:09:31 2009


iptables -L on the computer in question (NOT the server) reads:


Chain INPUT (policy ACCEPT)
target prot opt source destination

Chain FORWARD (policy ACCEPT)
target prot opt source destination

Chain OUTPUT (policy ACCEPT)
target prot opt source destination

and the one on the server says:


Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- ubuntu.local anywhere
ACCEPT all -- 4.local anywhere
ACCEPT all -- 4.local anywhere
ACCEPT all -- anywhere anywhere
ACCEPT tcp -- anywhere anywhere tcp spt:domain
ACCEPT udp -- anywhere anywhere udp spt:domain
ACCEPT tcp -- anywhere anywhere tcp dpt:ssh
ACCEPT tcp -- anywhere anywhere tcp dpt:msnp
LOG all -- anywhere anywhere limit: avg 5/min burst 5 LOG level debug prefix `iptables denied: '
ACCEPT tcp -- anywhere anywhere tcp dpt:www /* http apache */
ACCEPT tcp -- anywhere anywhere tcp dpt:https /* https apache */
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
ACCEPT tcp -- 192.168.2.0/24 anywhere multiport dports netbios-ssn,145
ACCEPT udp -- 192.168.2.0/24 anywhere multiport dports netbios-ns,netbios-dgm
ACCEPT tcp -- 192.168.2.0/24 anywhere multiport dports 5900,5901
ACCEPT tcp -- anywhere anywhere tcp dpt:webmin
DROP all -- anywhere anywhere

Chain FORWARD (policy ACCEPT)
target prot opt source destination

Chain OUTPUT (policy ACCEPT)
target prot opt source destination

Can anyone see what basic step I have omitted?

Thanks!

Lars Noodén
January 4th, 2010, 03:44 PM
You might be happier trying squid (http://www.squid-cache.org/Versions/v2/2.7/cfgman/) for that.
See about acl (http://www.squid-cache.org/Doc/config/acl/)s where 'time' is mentioned. squid will also do rate-limiting.

Regarding the IPTables rules, you might strongly consider using REJECT instead of DROP so that you get an proper error message to help with the diagnosis. Using DROP won't really help against intruders that much either.

qprfact
January 5th, 2010, 07:55 AM
Thanks Lars

I had previously looked into Squid actually, and it seemed as though iptables would be simpler!

I think I am getting somewhere now though, as I think I had the REJECT (I've changed to that from DROP) in the wrong place. My iptables -L now reads:


Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- ubuntu.local anywhere
ACCEPT all -- 4.local anywhere
ACCEPT all -- 4.local anywhere
ACCEPT all -- anywhere anywhere
ACCEPT tcp -- anywhere anywhere tcp spt:domain
ACCEPT udp -- anywhere anywhere udp spt:domain
ACCEPT tcp -- anywhere anywhere tcp dpt:ssh
LOG all -- anywhere anywhere limit: avg 5/min burst 5 LOG level debug prefix `iptables denied: '
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
ACCEPT tcp -- 192.168.2.0/24 anywhere multiport dports netbios-ssn,145
ACCEPT udp -- 192.168.2.0/24 anywhere multiport dports netbios-ns,netbios-dgm
ACCEPT tcp -- 192.168.2.0/24 anywhere multiport dports 5900,5901
ACCEPT tcp -- anywhere anywhere tcp dpt:webmin
REJECT all -- anywhere anywhere reject-with icmp-port-unreachable

Chain FORWARD (policy ACCEPT)
target prot opt source destination
ACCEPT all -- ubuntu.local anywhere
ACCEPT all -- 4.local anywhere
ACCEPT all -- 4.local anywhere
ACCEPT tcp -- anywhere anywhere multiport dports msnp
ACCEPT tcp -- anywhere anywhere multiport dports www /* http apache */
ACCEPT tcp -- anywhere anywhere multiport dports https /* https apache */
REJECT all -- anywhere anywhere reject-with icmp-port-unreachable

Chain OUTPUT (policy ACCEPT)
target prot opt source destination

This does now block traffic as I wished, but does it a little over-zealously - the very final REJECT statement over-rides the two preceding ACCEPT statements for http and https. If I can get those (and the MSN ACCEPT) to work and all else to REJECT, then I am there I believe.

Any thoughts?

Lars Noodén
January 5th, 2010, 06:21 PM
Using some of your own chains might help keep things sorted. I sometimes add a chain just for the REJECT target and then point to that last in each of the INPUT and OUTPUT chains. FORWARD should not be needed unless the machine is a router.

I was initially going to propose allowing mail, but too many people use mail as a surrogate for a file system these days and base64-encoded binaries take many times more bandwidth than plain text. So for bandwidth conservation those are out.

Ping, etc - ICMP in / out

DNS - UDP 53 in / out
DHCP - UDP 67 in/out, 68 in/out

Chat protocols:

Jabber / xmpp - tcp 5222, tcp 5223
https://web.amessage.eu/firewalled/

IRC
tcp /6667

Talk
517/UDP
Ntalk
518/UDP

ICQ
5190 /TCP

etc.

There looks like there might be a problem with MSN, as that looks like it might use 443 which is the same port as HTTPS... You might try generating some test cases - applications and chat sessions. Then
set up some temporary rules that log everything from one user and then --uid-owner username or --uid-owner userid run through the test cases. Then go through the logs and see what which ports beyond DNS are needed. Be sure to allow ICMP, because without that your net is broken.

qprfact
January 12th, 2010, 12:17 AM
Thanks Lars, I'm creeping closer but I'm not quite there yet!

I amended the iptables to be this:


# Generated by iptables-save v1.4.4 on Sat Jan 9 19:15:49 2010
*nat
:PREROUTING ACCEPT [583:45175]
:POSTROUTING ACCEPT [694:60887]
:OUTPUT ACCEPT [143:18642]
-A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -j MASQUERADE
COMMIT
# Completed on Sat Jan 9 19:15:49 2010
# Generated by iptables-save v1.4.4 on Sat Jan 9 19:15:49 2010
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [436:28062]
:OUTPUT ACCEPT [223:27990]
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m tcp --sport 53 -j ACCEPT
-A INPUT -p udp -m udp --sport 53 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -s 192.168.2.5/32 -j ACCEPT
-A INPUT -s 192.168.2.3/32 -j ACCEPT
-A INPUT -s 192.168.2.2/32 -j ACCEPT
-A INPUT -s 192.168.2.1/32 -p tcp -m tcp --dport 60344 -j ACCEPT
-A INPUT -s 192.168.2.3/32 -p tcp -m tcp --dport 49744 -j ACCEPT
-A INPUT -s 192.168.2.2/32 -p tcp -m tcp --dport 49743 -j ACCEPT
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -s 192.168.2.0/24 -p tcp -m multiport --dports 139,145 -j ACCEPT
-A INPUT -s 192.168.2.0/24 -p udp -m multiport --dports 137,138 -j ACCEPT
-A INPUT -s 192.168.2.0/24 -p tcp -m multiport --dports 5900,5901 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 10000 -j ACCEPT
-A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT
-A INPUT -j DROP

-A FORWARD -p tcp -m tcp --dport 22 -j ACCEPT
-A FORWARD -s 192.168.2.10/32 -p udp -m multiport --dports 28910,29900,29901,29920,443 -j ACCEPT
-A FORWARD -s 192.168.2.2/32 -p tcp -m tcp --dport 49743 -j ACCEPT
-A FORWARD -s 192.168.2.5/32 -j ACCEPT
-A FORWARD -s 192.168.2.3/32 -j ACCEPT
-A FORWARD -s 192.168.2.2/32 -j ACCEPT
-A FORWARD -p tcp -m multiport --dports 1863 -j ACCEPT
-A FORWARD -p tcp -m multiport --dports 80 -m comment --comment "http apache" -j ACCEPT
-A FORWARD -p tcp -m multiport --dports 443 -m comment --comment "https apache" -j ACCEPT
-A FORWARD -j DROP

-A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
COMMIT
# Completed on Sat Jan 9 19:15:49 2010

The Forward section is intended to allow connections via SSH, outward connections from a Wii, and MSN too (the 1863 one).

It should then allow ports 80 and 443 and drop all else.

However, what it does is allow the MSN, but as well as dropping everything else, it drops http(s) too. I can't work out why, as these two chain precede the DROP chain, and my understanding was that iptables works in sequence. The only thing I can think of is that these two chains are somehow worded incorrectly - does anything leap out?

DGortze380
January 12th, 2010, 12:40 AM
http://www.pfsense.org/

This firewall will allow you to set rules by time of day, and captive portal to limit bandwidth on a per user basis.

qprfact
January 12th, 2010, 12:48 PM
Thanks, but that isn't something I can run on Ubuntu, is it? It's a whole new OS?

Lars Noodén
January 12th, 2010, 01:09 PM
Thanks, but that isn't something I can run on Ubuntu, is it? It's a whole new OS?

PFsense is a whole new family of OS. It's based on FreeBSD, but could just as easily be using NetBSD or OpenBSD since the main tool is PF, instead of IPTables. PF is a lot easier to use, IMHO, than IPTables, though I can find my way around in either.

I notice that the chains still end in DROP, that makes your diagnosis harder...

Please tell more about the topology of your network and specifically where your filter is to reside. Using FORWARD has no effect unless it is on a machine acting as a gateway between the users and the Internet. There should be one cable going to the Internet or ISP on one port and then any number of other ports going to the home LAN or to the user machines.

Where is this filter sitting? (A,B,C) or D ?



A---+---+
| |
B---+ D +---Internet
| |
C---+---+

qprfact
January 12th, 2010, 01:56 PM
Hi Lars

I have a Belkin ADSL wireless router. The Ubuntu server is connected to that, so acts as a gateway to the router. However, the firewall software on the router is not very configurable (and I can't install others unfortunately - they don't seem to work with Belkin), so I need to do my filters on the server, to which all the machines connect as a gateway.

All my local machines have static IP addresses, and most can connect wirelessly too.

Essentially I want to have everything blocked apart from specified traffic such as SSH, Webmin, HTTP and HTTPS.

The other reason I need to do this is due to ISP allowances (see previous!)

My ideal would be this:

Weekdays 9-6 - allow SSH, Webmin and IM. If possible, allow HTTP to specified URLs only

(My rules above actually do allow the SSH, Webmin, and IM. All else seems to drop)

After 6pm - allow HTTP and HTTPS in addition to the more restricted version above. If possible to do so with traffic shaping, even better!

So where I am at present is that - by accident - my rules accomodate the restricted solution above (albeit not the limited HTTP usage). Unfortunately, I *thought* I'd written them in such a way that it would allow HTTP and then drop anything after that.

Note that by removing the -A INPUT -j DROP rule virtually at the end, HTTP works again.

So as you can see, by accident or design, it ALMOST works!

qprfact
January 12th, 2010, 01:59 PM
Not sure if this rudimentary diagram helps?

Lars Noodén
January 12th, 2010, 04:13 PM
Ok. Just to be sure, your server is D below and has at least two ethernet ports



A---+
|
B---+---D---ADSL---Internet
|
C---+


And just to be sure, your setup is not like this, with the server as D?



A---+
|
B---+---ADSL---Internet
|
C---+
|
D---+

qprfact
January 12th, 2010, 04:26 PM
Hi Lars, yes, it is indeed the former

Lars Noodén
January 12th, 2010, 05:09 PM
Well, I'm not seeing DNS in the FORWARD chain, so maybe that is an issue.

Some combination of source host, port or protocol is not what you planned on. You might try seeing what is being blocked by temporarily adding some logging:



-N LOGANDSTOP
-A LOGANDSTOP -j LOG
-A LOGANDSTOP -j REJECT

...

# tail end of FORWARD chain
# instead of -A FORWARD -j DROP use this
-A FORWARD -j LOGANDSTOP

....

qprfact
January 12th, 2010, 10:10 PM
Thanks Lars. I've set that logging up so will see what happens

Does this log to /var/log/syslog?

qprfact
January 17th, 2010, 08:02 PM
I think I have it working - sort of - but this may be more by luck than design.

I was looking at the issue afresh, and looked again at your point regarding DNS.

So I added these lines to iptables:

Code:


-A FORWARD -p tcp -m tcp --dport 53 -j ACCEPT
-A FORWARD -p udp -m udp --dport 53 -j ACCEPT

and internet began to work!

So, I tried a little more experimentation to allow the various PCs to connect, so my FORWARD section now looks like this:

Code:


-A FORWARD -p tcp -m tcp --dport 53 -j ACCEPT
-A FORWARD -p udp -m udp --dport 53 -j ACCEPT
-A FORWARD -p tcp -m tcp --dport 22 -j ACCEPT
-A FORWARD -s 192.168.2.5/32 -j ACCEPT
-A FORWARD -s 192.168.2.3/32 -j ACCEPT
-A FORWARD -s 192.168.2.2/32 -j ACCEPT
-A FORWARD -s 192.168.2.4/32 -p tcp -m tcp --dport 80 -j ACCEPT
-A FORWARD -d 192.168.2.4/32 -p tcp -m tcp --dport 80 -j ACCEPT
-A FORWARD -s 192.168.2.15/32 -p tcp -m tcp --dport 80 -j ACCEPT
-A FORWARD -d 192.168.2.15/32 -p tcp -m tcp --dport 80 -j ACCEPT

and so on. Using the individual PCs worked too

Next, I tried an alternative version for IM ports:

Code:


-A FORWARD -s 192.168.2.15/32 -p tcp -m multiport --dports 1863,5222,5223,443 -j ACCEPT
-A FORWARD -d 192.168.2.15/32 -p tcp -m multiport --dports 1863,5222,5223,443 -j ACCEPT
-A FORWARD -s 192.168.2.16/32 -p tcp -m multiport --dports 1863,5222,5223,443 -j ACCEPT
-A FORWARD -d 192.168.2.16/32 -p tcp -m multiport --dports 1863,5222,5223,443 -j ACCEPT
-A FORWARD -s 192.168.2.17/32 -p tcp -m multiport --dports 1863,5222,5223,443 -j ACCEPT
-A FORWARD -d 192.168.2.17/32 -p tcp -m multiport --dports 1863,5222,5223,443 -j ACCEPT

So I now have IM and HTTP working in the unrestricted rules.

By removing the lines relating to HTTP, I have an IM only version (my restricted one). The downside, as you will no doubt have spotted, that one of the ports I need to open for MSN Messenger IM via Pidgin is 443, so therefore HTTPS access *IS* available.

Any ideas on how I can restrict this to addresses, or use the traffic shaping ability?

qprfact
January 21st, 2010, 11:28 AM
This all now seems to be working, with one minor issue. The server itself (192.168.2.5), even if specified like all the other network PCs, cannot access the internet!

Anyone able to assist?

Thanks!

DGortze380
January 21st, 2010, 03:30 PM
This all now seems to be working, with one minor issue. The server itself (192.168.2.5), even if specified like all the other network PCs, cannot access the internet!

Anyone able to assist?

Thanks!

what chain are you specifying the server rules in?

qprfact
January 21st, 2010, 04:07 PM
Hi there, it's this one:


-A FORWARD -s 192.168.2.5/32 -j ACCEPT


Though I also amended to this format:


-A FORWARD -s 192.168.2.5/32 -p tcp -m tcp --dport 80 -j ACCEPT
-A FORWARD -d 192.168.2.5/32 -p tcp -m tcp --dport 80 -j ACCEPT

DGortze380
January 21st, 2010, 07:06 PM
Hi there, it's this one:


-A FORWARD -s 192.168.2.5/32 -j ACCEPT


Though I also amended to this format:


-A FORWARD -s 192.168.2.5/32 -p tcp -m tcp --dport 80 -j ACCEPT
-A FORWARD -d 192.168.2.5/32 -p tcp -m tcp --dport 80 -j ACCEPT

The FORWARD chain should never pick up that traffic because it originates at the server on which you're implementing these rules. Try it in OUTBOUND.

qprfact
January 21st, 2010, 10:51 PM
Thank you thank you thank you!

That worked immediately!

Thanks again!