Tor blacklist
Few month ago i was interested in how to block incoming traffic from Tor network. Tor network have finitely numbers of exit nodes, so the solution is to block traffic from this nodes. I see two solutions how to block exit nodes. First use TorDNSEL service, in brief you can check that connection comes from Tor exit node or not by querying special domain name. It is useful if you want to do this check in your php script, for example. But i do not know how to protect host completely by this method. Another way is to use exitlist. By this way you can get list of addresses. Both ways have advantages and disadvantages. I prefer last solution because, it allow to protect my hosts completely. Cons of this method – near 700-800 rules into firewall, that can slow down your host.
Anyway, first that i done – simply script that fetch list of IP and print them to standard output. When i started to writing script i wanted to expand features in future. I want to generate ready firewall rules for example, but now this script can only print list of IP’s. I do not want to integrate firewall rules application in this script, because i think this job must be done by another script.
So, now this script only fetch and print IP addresses or exit with error code if can not do it:
#!/usr/bin/perl -w use strict; use LWP::Simple; my $list = get("http://exitlist.torproject.org/exit-addresses"); my $i; my @ips; if( ! defined( $list ) ) { die( "Can not fetch addresses.\n" ); } foreach $i (split( /\n/, $list )) { push( @ips, $1 ) if( $i =~ m/((?:\d{1,3}\.){3}\d{1,3})/); } if( defined( $ARGV[0] ) && $ARGV[0] eq "-ip" ) { print( join( "\n", @ips )); } else { die( "Usage $0 -ip\n" ); } |
Next that you need – apply rules on firewall. As i say before, when you apply one rule per IP you will get near 700-800 rules, it is reason why you need optimize sequence of your rules. It can be done in next manner:
1. Rule to accept packets flowing thru loopback.
2. Rule to accept packets of RELATED and ESTABLISHED connections.
3. Rule to drop packets from blacklisted sources.
4. Rule to accept packets from whitelisted sources.
5. Rule for fail2ban (optional).
6. Rule for Tor exit nodes.
7. Other rules (for example, accept connection on ssh, http, https ports).
This sequence allow to make decision for most packets before they pass Tor filtration rules.
I organize Tor filtration rules in separate table called TorExitnodes, it allow to update only this table and do not touch other firewall rules. Also i create table TorBlockAndLog that contain LOG and DROP target, but it is optional, you can simply drop packets.
For updating firewall rules for exit nodes i made next bash scrip and place it in cront:
#!/bin/bash SOLVE="/root/bin/solve.pl" if /usr/bin/perl $SOLVE then /sbin/iptables -F TorExitnodes /sbin/iptables -I TorExitnodes -j RETURN for i in `/usr/bin/perl $SOLVE -ip` do /sbin/iptables -I TorExitnodes -s $i -j TorBlockAndLog done else echo "Can not fetch Tor exit nodes" 1>&2 exit 1; fi |
Where is variable “SOLVE” store path to previous perl script, as i say before, if you do not need special action for incoming connections from Tor, you can change “TorBlockAndLog” on “DROP”.
Thats all.
PS
It is good idea to place whitelist before TorExitnodes, who can know, may be one fine day you found -s 0.0.0.0/0 -j DROP into this table. =)
How to deal with hotmail spam filter
Few months ago i faced with hotmail spam filter, every time when my host tried to send email to any hotmail address i saw next error in log file:
550 SC-001 (SNT0-MC2-F18) Unfortunately, messages from IP.AD.DR.ESS weren’t sent. Please contact your Internet service provider since part of their network is on our block list. You can also refer your provider to http://mail.live.com/mail/troubleshooting.aspx#errors.
I configured correct PTR, SPF, DKIM records, sent email to hotmail support two times, fill and submit big strange long form here, but anyway every time when i tried to sent message i got “550 SC-001”.
Hotmail support said next:
Hello Ivan,
I do apologize if I am unable to provide any details about this situation since we do not have the liberty to discuss the nature of the block.
At this point, I would suggest that you review and comply with Windows Live Hotmail’s technical standards. This information can be found at http://postmaster.live.com/Guidelines.aspx
We regret that we are unable to provide any additional information or assistance at this time.
Yeah, brilliant, thanks for help man. I was tired of the situation, so i just configured exim to send all emails for hotmail.com and live.com thru gmail account.
On this host i had debian squeeze and exim4 configured to send emails directly, i made next modifications in config files, first i created domainlist for “sick” domains:
$ echo 'domainlist route_thru_smarthost = "live.com : live.ru : hotmail.com : hotmail.ru : msn.com"' > \ /etc/exim4/conf.d/main/04_exim4-config_route_thru_smarthost |
Modified default dnslookup router and added new router for hotmail in file /etc/exim4/conf.d/router/200_exim4-config_primary into DCconfig_internet block:
dnslookup: debug_print = "R: dnslookup for $local_part@$domain" driver = dnslookup domains = ! +local_domains : ! +route_thru_smarthost transport = remote_smtp same_domain_copy_routing = yes # ignore private rfc1918 and APIPA addresses ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8 : 192.168.0.0/16 :\ 172.16.0.0/12 : 10.0.0.0/8 : 169.254.0.0/16 :\ 255.255.255.255 no_more hotmail_router: debug_print = "R: hotmail_router for $local_part@$domain" driver = manualroute domains = ! +local_domains : +route_thru_smarthost transport = remote_smtp_smarthost route_list = * DCsmarthost byname host_find_failed = defer same_domain_copy_routing = yes no_more |
Last step – create account into google apps and add credentials into /etc/exim4/passwd.client
$ echo '*.google.com:Login:Password' >> /etc/exim4/passwd.client |
Regenerate template and update config:
$ update-exim4.conf.template -r
$ update-exim4.conf |
After that i checked routing:
$ exim4 -bt hate@hotmail.com R: hotmail_router for hate@hotmail.com hate@hotmail.com router = hotmail_router, transport = remote_smtp_smarthost host gmail-smtp-msa.l.google.com [74.125.79.108] port=587 host gmail-smtp-msa.l.google.com [74.125.79.109] port=587 |
And sent test email:
$ echo subj|mail -s "burn in hell" support@hotmail.com $ grep support@hotmail.com /var/log/exim4/mainlog 2012-03-34 09:11:09 1SAwmJ-0006sf-56 => support@hotmail.com R=hotmail_router T=remote_smtp_smarthost H=gmail-smtp-msa.l.google.com [74.125.79.108] X=TLS1.0:RSA_ARCFOUR_SHA1:16 DN="C=US,ST=California,L=Mountain View,O=Google Inc,CN=smtp.gmail.com" |
Success.
Port based routing
After i came on new work i found that can not send email thru SMTPS, because port 465 closed on router. At this point i already had configured VPN access on my home router, so i think that it is good idea to route SMTPS traffic thru VPN, let’s start.
For this purposes i needed iproute2 and iptables. First i created new route table and add default route:
$ echo "1 VPN" >> /etc/iproute2/rt_tables $ ip route add default via 192.168.107.5 src 192.168.107.6 dev tun_vpn table VPN $ ip route show table VPN default via 192.168.107.5 dev tun_vpn src 192.168.107.6 |
Where 192.168.107.5 – ip of my router into VPN and tun_vpn – VPN interface.
After that i created rule, that route marked packets thru VPN route table:
$ ip rule add from all fwmark 0x16 lookup VPN $ ip ru sh 0: from all lookup local 32765: from all fwmark 0x16 lookup VPN 32766: from all lookup main 32767: from all lookup default |
There is time to mark SMTPS packets:
$ iptables -t mangle -I PREROUTING -p tcp --dport 465 -j MARK --set-mark 0x16 $ iptables -t mangle -I OUTPUT -p tcp --dport 465 -j MARK --set-mark 0x16 |
Let’s check:
$ traceroute -n -T -p 993 imap.gmail.com traceroute to imap.gmail.com (173.194.69.109), 30 hops max, 60 byte packets 1 192.168.130.1 0.217 ms 0.233 ms 0.201 ms 2 * 2.318 ms 2.377 ms 2.503 ms 3 * 1.411 ms 1.714 ms 1.947 ms 4 * 1.486 ms 1.733 ms 1.796 ms 5 * 12.762 ms 72.14.212.22 12.791 ms 12.836 ms 6 * 65.528 ms 61.534 ms 67.431 ms 7 216.239.43.250 66.606 ms 209.85.248.132 61.808 ms 216.239.43.250 60.219 ms 8 216.239.48.53 66.225 ms 209.85.254.153 61.190 ms 64.233.174.55 66.038 ms 9 66.249.95.67 60.271 ms 66.249.95.175 60.510 ms 60.956 ms 10 64.233.174.55 65.304 ms 65.610 ms 64.233.174.29 76.697 ms 11 173.194.69.109 66.954 ms 65.824 ms 61.563 ms $ traceroute -n -T -p 465 imap.gmail.com traceroute to imap.gmail.com (173.194.69.108), 30 hops max, 60 byte packets 1 192.168.107.1 26.088 ms 42.767 ms 42.748 ms 2 * 42.813 ms 42.799 ms 68.297 ms 3 * 42.668 ms 42.665 ms 42.619 ms 4 * 42.539 ms 42.521 ms 42.504 ms 5 * 42.522 ms 68.071 ms 68.039 ms 6 * 68.015 ms 76.070 ms 85.085 ms 7 * 136.618 ms 136.634 ms 136.555 ms 8 216.239.43.250 110.732 ms 110.744 ms 110.712 ms 9 64.233.174.55 136.549 ms 209.85.254.153 136.506 ms 136.463 ms 10 * 66.249.95.67 137.978 ms 66.249.95.175 137.887 ms 11 173.194.69.108 137.893 ms 216.239.48.53 137.846 ms 64.233.174.55 130.177 ms |
Profit!
PS
In my situation i observed strange effect, although that i set src ip, my host trying to send packets with src ip of local ethernet interface, so i just add masquerade rule into iptables.
$ iptables -A POSTROUTING -o tun_vpn -J MASQUERADE |
Another way to fix it, set route to local work network on router, but i too lazy to do it.
Password protected access to “/wp-admin” on nginx
Here i found advice how to make wordpress more securely, idea is to protect access to “/wp-admin” by http auth, but “/wp-admin/admin-ajax.php” must stay available for everyone, same is true for some .css files.
I spend some time to research solution, it was a bit complicated:
location /wp-admin { location ~ /wp-admin/admin-ajax.php$ { # Php handler } location ~* /wp-admin/.*\.php$ { auth_basic "You shall not pass!"; auth_basic_user_file $document_root/.htpasswd; # Php handler } } |
It is possible to add additional location to serve static content, but i am too lazy to do it.
PS
Also here i found receipts for apache and lighttpd if anybody interesting. Continue reading
Forbid access to php into “wp-content”.
I expected in few articles an advice to disable direct access to php scripts into “/wp-content/uploads” i done small research and observed, than .php placed into “/wp-content” and into subdirs was newer directly accessed thru web. So i just completely disabled direct access to php scripts placed into that dir and subdirs. Looks more securely.
PS
I made mistake. At least tiny-mce php scripts must be accessible thru web. So i just convert this rules that touch ‘/wp-include’ for nginx:
location ~* /wp-includes { location ~* /wp-includes/[^/]+\.php$ { deny all; } location ~* /wp-includes/js/tinymce/langs/.+\.php$ { deny all; } location ~* /wp-includes/theme-compat { deny all; } location ~ /wp-includes/.+\.php$ { include php_wordpress_handler; } } |
Strange pattern on roof of my car
Yesterday before i go to sleep, i looked through the window and found strange circle on roof of my car. Day was very sunny and first i thought that something dark (like a leaf) fell on roof, heated it and melted snow. But edges was very sharp and it looked like accurate circle, next guess was that somebody forget something on my car or it just a prank. With these thoughts i fell asleep. At the morning i want to the car and found frozen water streams on the windshield and grounded battery. After that i remember that last sunday i tuned shock sensor and used lamp attached to roof inside the car. I remember that i swiched it off, but this lamp have strange complicated construction and i was not turned of it completely. The final surprise was that the car could not be opened with a remote control and all locks on doors was blocked by dust (because i never used it before), but WD-40 saved the situation.
How to change page order of top menu in wordpress.
I try to reorder menu items by setting page order into Dashboard/Pages/Quick Edit, also i try plugin called ‘my page orders’, but anyway menu items was sorted alphabetically by page title, so i started to dig deeper.
In my template ‘top menu’ generated by function ‘wp_nav_menu
‘ placed into header.php. When i looked at template, i saw that in parameters specified ‘fallback_cb
‘ function defined in function.php. When i found this function, i saw that this function uses ‘get_pages
‘ with default arguments to get pages, so i just define 'sort_column'
now function looks like get_pages(array( ‘sort_column’ => ‘menu_order’))
After that modification pages in menu sorted by as i expected.