1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

Block IPs by country

Discussion in 'Tomato Firmware' started by ValiE, Mar 29, 2013.

  1. ValiE

    ValiE Serious Server Member

    Hi, any simple way I can drop packets from different countries, for example China? I'm forwarding some ports to a NAS behind firewall and I'm getting tons of failed login attempts, many with source IP from China. I'm using TomatoUSB version by Shibby. Thanks in advance
  2. RMerlin

    RMerlin Network Guru Member

    This is something best done through ipsets, otherwise you will most likely get a notable performance hit from having too many iptable rules to get through. Tomato doesn't support ipsets however.
  3. ValiE

    ValiE Serious Server Member

    I thought hundreds of ip tables rules will cause the router to perform poorly. Any 3rd party firmware with this feature called ipsets?
  4. RMerlin

    RMerlin Network Guru Member

    Hard to tell since you didn't mention which router you have.
  5. ValiE

    ValiE Serious Server Member

    Sorry about that : Linksys E3200
  6. phuque99

    phuque99 LI Guru Member

    The latest trunk or development copy of OpenWRT supports E3200 and there is full ipset support in that firmware: https://dev.openwrt.org/changeset/36139 However I think there might be stability issues with the radio based on feedback in the forums.

    You can risk trying to add 2000 additional lines to block China IP address on the command line to see what happens with the following one liner. If it slows down or causes the router to hang, you can reboot with no permanent harm done. Otherwise, this is the simplest method on the "firewall script":

    for ip in $(wget -qO- http://ipdeny.com/ipblocks/data/countries/cn.zone); do iptables -I wanin -s $ip -j DROP; done
    I also wrote a guide on using geoip module. That requires a bit more work and a USB drive permanently attached to the router to keep the database:

  7. ValiE

    ValiE Serious Server Member

    Hi phuque99,
    I've pasted the ip table command you gave in firewall script, reboot and checked iptables --list. Tons of subnets are present. The CPU or speed penalty, at least for the moment, is not impacted. I will keep you posted and I will read also your link. Thanks guys
  8. mstombs

    mstombs Network Guru Member

    I was quite surprised how well an RT-N16 could cope with 1000s of blocked IPs (but do look forward to experimenting with ipset), but cpu not limiting my broadband connection!. You will find that loading the rules 1 at a time using iptables commands is very slow, but if you use the iptables-restore method that Tomato uses internally it is much faster, see for example here:-

  9. phuque99

    phuque99 LI Guru Member

    Takes almost two minutes if you're not in a hurry, and it runs in the background:
    /root# date; for ip in $(wget -qO- http://ipdeny.com/ipblocks/data/countries/cn.zone); do iptables
    -I test -s $ip -j DROP; done; date
    Sun Mar 31 09:28:27 UTC 2013
    Sun Mar 31 09:30:07 UTC 2013
    However geoip or ipset is much better at filtering large amount of CIDRs.
  10. ValiE

    ValiE Serious Server Member

    @phuque99, I want to try the geoip variant but I have some questions : on what chain should I append the drop line (input, wanin etc). How the iptables line should look like knowing that I want to drop any traffic coming from China?
  11. Monk E. Boy

    Monk E. Boy Network Guru Member

    You could put it on wanprerouting since, on Tomato, that's the initial table for the WAN port.
  12. ValiE

    ValiE Serious Server Member

    Hi Monk, i only have the following chain entries in iptables :
    INPUT, FORWARD, OUTPUT, L7in, monitor, shlimit, wanin, wanout.
    Please help me also with the iptables command.
  13. Monk E. Boy

    Monk E. Boy Network Guru Member

    Yeah it's hard to wrap your head around all the iptables in Tomato, every time I go looking for them I forget how to see them all. I've never really got a good picture of how all the pieces fit together, I probably need to actually print them out on paper and stare at them for a while to trace all the paths packets can take.

    Unless this information has been outdated by a recent build, these commands should show all chains on all tables:
    iptables -nvL
    iptables -nvL -t nat
    iptables -nvL -t mangle

    WANPREROUTING should be on the nat table (the first command lists chains on the filter table). As I recall wanprerouting is in effect when the device is in Gateway mode (if you place it in Router mode the nat table should be empty - or at least never used).

    for ip in $(wget -qO- http://ipdeny.com/ipblocks/data/countries/cn.zone); do iptables -t nat -I WANPREROUTING -s $ip -j DROP; done
    Definitely don't stick this in your firewall/etc. script right off the bat, I have no idea how this'll impact your performance (as I recall this is the first chain for port forwarded traffic).

    I do believe the wainin chain on the filter table should work, which is how you had it setup before, but you should check for "hits" to make sure. (iptables -nvL wanin)
  14. Monk E. Boy

    Monk E. Boy Network Guru Member

    FWIW, IMHO, phuque99's geoip technique looks (at a glance) far superior to this.

    While a powerful enough router can certainly handle all the rules you can throw at it, a lot of rules waste CPU time that you'll probably want available for more useful things (e.g. L7 filtering).

    OTOH since geoip is hosted on a USB stick you'll waste some CPU time transferring data to/from USB, which isn't entirely inconsequential. Ideally the USB drive should be in ext2 or ext3 format to minimize those penalties.
  15. phuque99

    phuque99 LI Guru Member

    You can simply add:
    iptables -I wanin -m geoip -src CN -j DROP
    Not entirely true :) The geoip module is hard coded to use /var/geoip/geoipdb. The scripts I recommended copies the db file from USB drive into tmpfs /var/geoip during startup. So iptables will be reading the file off the router's memory.

    Instead of "allow all / block CN", you can consider "block all / allow source CIDR" from network locations that needs to access your NAS, especially if the source CIDR list is a lot less than 2000 blocks.
  16. Monk E. Boy

    Monk E. Boy Network Guru Member

    Aha! Yup, I totally missed that bit.
  17. bagu

    bagu Network Guru Member

    iptables -I wanin -m geoip -src CN -j DROP
    Give me an error -m is not listed in the available options when i do iptables -h
    Can you give us the full way to make it working ?
  18. phuque99

    phuque99 LI Guru Member

  19. i1135t

    i1135t Network Guru Member

    Actually I followed the instructions and geoip does not work. After successfully loading the module and setting the iptable rules (wanin, nat wanprerouting, output), I still can access the blocked sites. Tested against US IPs where I could still reach US sites (even though this is not the intended purpose).
  20. koitsu

    koitsu Network Guru Member

    The thread link phuque99 provided allows you to use geoip to block **inbound** connections to your router. What this provides is the ability to block foreign networks/CIDRs from reaching services that you might permit, or might be forwarded by your router to IPs on your LAN.

    I get the impression from the wording of your above paragraph that you're trying to block **outbound** connections (e.g. connections initiated by clients on your LAN to IPs within networks you don't like). If that's the case, you need to use the wanout chain (this applies to the (default) filter table, not the nat table). Example:

    iptables -A wanout -p icmp -d -j DROP
    ...which will silently drop all ICMP packets (from clients on your LAN) destined to I have tested this and it works correctly.

    You can tweak the rules as you see fit, e.g. -p tcp --dport 1234 to silently drop all TCP packets destined to port 1234, etc... You get the idea.

    Why/how this works: the wanout chain is referenced within the FORWARD chain; for blocking outbound packets, FORWARD where you want things. However, where you place the rules within FORWARD matters, and the wanout chain reference is definitely in the correct spot/location.
  21. phuque99

    phuque99 LI Guru Member

    If you wanted to block internal machines from reaching US IP addresses, try:

    iptables -I wanout -m geoip -dst US -j DROP
  22. Monk E. Boy

    Monk E. Boy Network Guru Member

    Freudian slip? :)
  23. phuque99

    phuque99 LI Guru Member


    I actually recommend using "reject" for blocked outbound connections to prevent clients waiting for timeout:
    iptables -I wanout -m geoip -dst US -j REJECT
  24. koitsu

    koitsu Network Guru Member

    "Blanket rules" like this type often have downsides; while, for example, the above will match all protocols (TCP, UDP, and ICMP), for TCP you'd almost certainly want TCP RST being returned to the client as well. Furthermore, regardless of protocol, REJECT is supposed to send back an ICMP port unreachable response to the client -- yet I've found there are cases where it doesn't (meaning in effect REJECT is behaving like DROP) -- and yes, I did packet captures to verify this. The only thing I can think of is that the ICMP port-unreach might be going out the wrong interface (which would be very very bad).
  25. phuque99

    phuque99 LI Guru Member

    Well, there's always room for improvement. The owner of the router can and should evaluate the entire ipt as a whole and decide what's best and efficient. I've never had that problem with reject acting like drop. If that was a problem, then maybe a more "wholesome" reject can be done with:
    iptables -I wanout -p tcp -m geoip -dst US -j REJECT --reject-with tcp-reset
    iptables -I wanout -p udp -m geoip -dst US -j REJECT
    That'll teach the client not to reach US IPs anymore! :)
  26. Monk E. Boy

    Monk E. Boy Network Guru Member


    iptables -I wanout -m geoip -dst US -j REJECT
    iptables -I wanout -p tcp -m geoip -dst US -j REJECT --reject-with tcp-reset

    If it's TCP it gets rejected with a reset, if it's not TCP then it gets rejected. -I inserts in the order reverse of how you add the rules (since each rule goes up to the top), so the second rule is before the first.
  27. koitsu

    koitsu Network Guru Member

    I should be clear in what I'm saying: I normally wouldn't solicit injection of TCP RST, except that for whatever reason, ICMP port-unreach does not tend to be sent back to the client when encountering rules in the FORWARD chain. Like I said, I did packet captures and I saw no ICMP traffic of any kind -- the rules worked, but effectively were acting like DROP. This is troublesome.
  28. i1135t

    i1135t Network Guru Member

    Thanks at first I assumed if incoming is blocked for ping requests/web traffic that would be enough to cut the communication line for send/receive.

    iptables -I wanout -m geoip --dst-cc CN,NG -j DROP
    iptables -I wanin -m geoip --src-cc CN,NG -j DROP
    Outbound works for blocking so it would be safe to assume that inbound works as well.

    For me personally, whether it's REJECT or DROP, as long as it gets the job done and there is no leak... Thx all!
  29. bagu

    bagu Network Guru Member

    iptables -I wanin -m geoip --src-cc CN,NG,AU,RU -j DROP
    Work like a charm. Thanks.
  30. Monk E. Boy

    Monk E. Boy Network Guru Member

    One idea about using REJECT over DROP is that if the packet is simply dropped the sender may try to resend the packet. Possibly multiple times. But if it gets rejected the sender knows it was rejected, and typically then packets don't get resent. Of course that's assuming all the ducks line up properly and the reject message gets through.
  31. Bird333

    Bird333 Network Guru Member

    I think with these 'hacker' countries it's probably better to use DROP so they don't know a real machine exists on that ip address.
  32. phuque99

    phuque99 LI Guru Member

    The discussion above was about rejecting egress traffic, not ingress. Rejection is preferred to prevent your applications hanging and waiting for timeout.
  33. RobF

    RobF Serious Server Member

    I'm using ipset sets with Shibby 109 AIO to block countries on my RT-N66U. While it may not be supported it does appear to be working fine although I'm still testing.

    I was initially getting syntax errors from iptables --set commands until I noticed that lsmod didn't show that ipt_set.ko was loaded. I did an "insmod ipt_set" command and then the iptables commands completed without error.
    For some reason that kernel module is not loaded by default but once I loaded it then iptables was happy when I added rules with set matching.

    lsmod *SNIP*
    root@router:/opt/sbin# lsmod
    Module                  Size  Used by    Tainted: P
    ipt_set                  928  2
    ip_set_nethash          7984  2
    ip_set                14496  3 ipt_set,ip_set_nethash
    So here is what I did.

    insmod ipt_set
    Then create the ipset set and rules as follows:
    ipset -N geoblock nethash
    iptables -I INPUT 3 -m set --set geoblock src -j DROP
    iptables -I wanin -m set --set geoblock src -j DROP
    The first line creates the ipset set geoblock of type nethash and loads the ip_set_nethash kernel module if its not loaded already.

    The INPUT rule keeps those that match geoblock src addr from connecting to ports on the router that are NOT forwarded to internal servers. (e.g. ping/icmp, ssh, remote admin access)

    The wanin rule prevents new connections from those that match geoblock src addr on forwarded ports to internal servers. In my case, smtp, www etc.

    I chose position 3 on the INPUT rule for efficiency as the state comparison is MUCH faster than ripping through a hash table of 10K entries.
    For wanin I think it should be first since you don't want people in the list to make new connections if they match the src ip!
    The above steps need to make it in the firewall startup scripts or you re-type each time you reboot. ( I haven't actually done this part yet... still doing it manually )

    Next I build an input file of CIDRs with this simple script.
    you can re-run this periodically and update your ipset set as shown below. As long as you have your rules above coded to load on boot then you shouldn't have to touch them again.

    getblocks() {
    cat <<EOF
    # Generated by ipset 4.5 on Fri May 31 18:57:10 2013
    -N geotmp nethash --hashsize 199288 --probes 4 --resize 50
    COUNTRIES="cn kr pk tw sg hk pe br ua in tr vn kz it es pl"
    #echo "loading country $COUNTRY" >&2
    wget -q -O - http://www.ipdeny.com/ipblocks/data/countries/$COUNTRY.zone|sed -e "s/^/-A geotmp /"
    cat <<EOF
    getblocks > /opt/tmp/geoblock.ipset
    This script is rough and could use tweaking but it works and is fast... the hashsize could probably start at 1024.. that number shown above was from an ipset save I did during testing.

    edit COUNTRIES to suit your blocking needs.
    Then execute the script.
    I have entware set up on an sdcard which is mounted on opt so I save the file over there in tmp.

    then do the following to load a new set of data.

    ipset -R < /opt/tmp/geoblock.ipset
    ipset -W geotmp geoblock
    ipset -X geotmp
    First do an ipset RESTORE on the temp set name geotmp with the CIDRs just downloaded.
    Then ipset swap the current geoblock set with the new geotmp set
    Lastly, ipset -X the temporary geotmp set since it has just been loaded with the old data via the swap.

    I use the swap feature so that you can easily update the data without having to remove sets from iptables rules.
    The restore process wants to create the set name so that is why I use a temp name and then swap it with the "real" list because you can't delete sets if they are in use by rules.

    Perhaps there is an easier way but I've found this to work well so far.

    My INPUT Chain.. *SNIP*
    Chain INPUT (policy DROP)
    target    prot opt source              destination
    DROP      all  --  anywhere            anywhere            state INVALID
    ACCEPT    all  --  anywhere            anywhere            state RELATED,ESTABLISHED
    DROP      all  --  anywhere            anywhere            set geoblock src
    My wanin Chain.. *SNIP*
    Chain wanin (1 references)
    target    prot opt source              destination
    DROP      all  --  anywhere            anywhere            set geoblock src
    ACCEPT    tcp  --  anywhere        tcp dpt:pop3
    ACCEPT    tcp  --  anywhere        tcp dpt:www
    you can use this site to test connections from China.

    The shanghai test got through but all the other China sites timed out as expected.
    With the ipset set empty they all make it through.
    I'll check the shanghai ip addr against the list tomorrow to see if its an error or not.

    You can test with other non-china sites there too. USA, Australia, Germany.
    These all were successful in connecting to my web server.

    ipset set matching is far superior to just using iptables so this will be a big help to me if this is working as well as I think it is.

    If you're interested in this method for country blocking please take a look and see what you think.

    mstombs likes this.
  34. RMerlin

    RMerlin Network Guru Member

    That's because shibby added ipset support in release 109.
    shibby20 likes this.
  35. RobF

    RobF Serious Server Member

    Thanks for adding that @RMerlin ! It looks like my timing for upgrading couldn't have been better.

    Any idea why I had to load the ipt_set.ko module manually?
    I was expecting that using the set "feature" would trigger a load similar to the loading of the nethash module.

  36. phuque99

    phuque99 LI Guru Member

    Looks like the script can be shortened with curl into a one-liner:
    ipset -N geoblock nethash
    iptables -I INPUT 3 -m set --set geoblock src -j DROP
    iptables -I wanin -m set --set geoblock src -j DROP
    (for ip in $(curl -s http://ipdeny.com/ipblocks/data/countries/{cn,kr,pk,tw,sg,hk,pe,br,ua,in,tr,vn,kz,it,es,pl}.zone); do ipset -q add geoblock $ip; done)&
    Considered blocking Syria too? :)
  37. shibby20

    shibby20 Network Guru Member

    pl? Why do you want block Poland??? tomato.groov.pl is in poland ;P
  38. RobF

    RobF Serious Server Member

    I added countries from a top ten list... no offense intended Shibby! Its too bad I can't add the USA.. one of the worst offenders! ;) Thanks for the suggestion on Syria... added it.

    I don't have curl on my router and while that may be a simple one liner I found that running one ipset per line is very, very, very slow and that is why I went with sed and then a ipset restore. The whole process of adding iptables rules, downloading, creating and loading the CIDR ipsets takes about 3 seconds.

    Thanks for the input.
  39. RMerlin

    RMerlin Network Guru Member

    Not sure. On my firmware the module does get auto-loaded indeed. Must be something specific to Tomato and/or the iptables userspace tool they use.
  40. mstombs

    mstombs Network Guru Member

    Must be something missing in the tomato build system to do with "depmod", maybe deliberate to avoid a big system map file. The tomato rc code also explicity loads iptables modules for access restrictions etc. If the correct map file exist iptables will autoload, perhaps using modprobe. Think this will be in the kernel Makefile

Share This Page