├── README.md └── torblock.sh /README.md: -------------------------------------------------------------------------------- 1 | TORBlock 2 | ======== 3 | 4 | TORBlock is a BASH script to automatically download the list of TOR exit-nodes and add them to your IPTables ruleset. 5 | 6 | This script uses hosts advertised on TOR's public exit-node lists in order to extract IP addresses and roll out the rules. 7 | 8 | TORBlock uses and (configurable) dedicated chain (default = TORBLOCK) in order to ease management and permit chain flushing 9 | on updates. 10 | 11 | EXPERIMENTAL 12 | ------------------ 13 | WARNING! The 'OPT_REDIR' function is under implementation and may not work (sorry for that!) 14 | 15 | Requirements 16 | ---------------- 17 | - iptables 18 | - curl 19 | - grep 20 | 21 | 22 | @TODO 23 | --------- 24 | - Implement in BSD's IPF 25 | -------------------------------------------------------------------------------- /torblock.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Options Bitmap @DO NOT EDIT 4 | OPT_LOG=1 5 | OPT_BLOCK=2 6 | OPT_REDIRECT=4 7 | 8 | #### 9 | # Script configuration 10 | ### 11 | 12 | # Exit node url must retrieve a list with 13 | # one IP by line 14 | EXIT_NODE_URL="https://www.dan.me.uk/torlist/" 15 | #EXIT_NODE_URL="http://10.1.1.114" 16 | 17 | # IPTables Chain Name 18 | CHAIN_NAME="TORBLOCK" 19 | 20 | # Logging options 21 | LOG_LEVEL=7 # RFC5424 Severity levels: 0 = Emergency, 1 = Alert, 2 = Critical, 3 = Error, 4 = Warning, 5 = Notice, 6 = Informational, 7 = Debug 22 | LOG_LIMIT_AMT=5 # Limit Amount 23 | LOG_LIMIT_BURST=7 # Limit Burst 24 | 25 | # Add TORBLOCK hosts to 26 | # INPUT, OUTPUT or FORWARD 27 | ADD_OUTPUT_RULES=0 # 0 = False, 1 = True 28 | ADD_INPUT_RULES=1 # 0 = False, 1 = True 29 | ADD_FORWARD_RULES=1 # 0 = False, 1 = True 30 | 31 | # Action to perform. 32 | # Sum up the options needed. 33 | # Available: OPT_LOG, OPT_BLOCK (-j DROP) 34 | # and OPT_REDIRECT (NAT) 35 | ACTIONS=$OPT_LOG+$OPT_REDIRECT # WARNING: Cannot DROP and NAT 36 | 37 | # Redirect to IP (Only if OPT_REDIRECT is set) 38 | REDIRECT_IP="10.1.1.112" 39 | 40 | #### 41 | # Script variables and constants 42 | # DO NOT EDIT BELOW THIS LINE 43 | ### 44 | 45 | # Options Bitmap 46 | OPT_LOG=1 47 | OPT_BLOCK=2 48 | OPT_REDIRECT=4 49 | 50 | # Bins 51 | BIN_CURL=$(which curl) 52 | BIN_IPTABLES=$(which iptables) 53 | BIN_IPTABLES_SAVE=$(which iptables-save) 54 | 55 | # Holders 56 | TOR_IPS="" 57 | ACTION_SET=$(($ACTIONS)) 58 | IPTABLES_SAVE_OUT=$($BIN_IPTABLES_SAVE) 59 | 60 | check() { 61 | # Make sure only root can run our script 62 | if [[ $EUID -ne 0 ]]; then 63 | echo "This script must be run as root" 1>&2 64 | exit 1 65 | fi 66 | 67 | # OPT_BLOCK and OPT_REDIRECT cannot be set both 68 | if [ $(is_action $OPT_BLOCK) -eq 1 ] && [ $(is_action $OPT_REDIRECT) -eq 1 ]; then 69 | echo "Cannot Drop (OPT_BLOCK) and Redirect (OPT_REDIRECT) request at the same time" 1>&2 70 | exit 1 71 | fi 72 | } 73 | 74 | download_list() { 75 | 76 | TOR_IPS=$($BIN_CURL -s $EXIT_NODE_URL | sort | uniq) 77 | if [ "$TOR_IPS" == "" ]; then 78 | echo "!! Error downloading list from $EXIT_NODE_URL. Exitting."; 79 | exit 127 80 | fi 81 | 82 | } 83 | 84 | add_rules() { 85 | 86 | _TOR_HOSTS_ADDED=0 87 | 88 | # Check if $CHAIN_NAME chain exists 89 | if [ $(has_rule ":$CHAIN_NAME") -eq 0 ]; then 90 | echo "Chain $CHAIN_NAME absent, creating..." 91 | $BIN_IPTABLES -N $CHAIN_NAME 92 | fi 93 | 94 | # Check if chain is added to input and output and forward 95 | ## INPUT 96 | if [ $(has_rule "-A INPUT -j $CHAIN_NAME") -eq 0 -a $ADD_INPUT_RULES -eq 1 ]; then 97 | echo "Adding chain $CHAIN_NAME rule to INPUT top (-I)" 98 | $BIN_IPTABLES -I INPUT -j $CHAIN_NAME 99 | fi 100 | 101 | ## OUTPUT 102 | if [ $(has_rule "-A OUTPUT -j $CHAIN_NAME") -eq 0 -a $ADD_OUTPUT_RULES -eq 1 ]; then 103 | echo "Adding chain $CHAIN_NAME rule to OUTPUT top (-I)" 104 | $BIN_IPTABLES -I OUTPUT -j $CHAIN_NAME > /dev/null 2>&1 105 | fi 106 | 107 | # FORWARD 108 | if [ $(is_action $OPT_REDIRECT) -eq 1 ]; then 109 | # NAT REDIR Chain 110 | if [ $(has_rule ":${CHAIN_NAME}_REDIRECT") -eq 0 ]; then 111 | $BIN_IPTABLES -t nat -N ${CHAIN_NAME}_REDIRECT 2>&1 112 | fi 113 | 114 | # Postrouting & Masquerade 115 | if [ $(has_rule "-A POSTROUTING -j MASQUERADE") -eq 0 ]; then 116 | echo "Adding NAT Masquerade rule" 117 | $BIN_IPTABLES -t nat -A POSTROUTING -j MASQUERADE 2>&1 118 | fi 119 | 120 | # Add default postroute to REDIR chain 121 | if [ $(has_rule "-A PREROUTING -j ${CHAIN_NAME}_REDIRECT") -eq 0 ]; then 122 | $BIN_IPTABLES -t nat -A PREROUTING -j ${CHAIN_NAME}_REDIRECT 2>&1 123 | fi 124 | 125 | if [ $(has_rule "-A FORWARD -j $CHAIN_NAME") -eq 0 -a $ADD_FORWARD_RULES -eq 1 ]; then 126 | echo "Adding chain $CHAIN_NAME rule to FORWARD top (-I)" 127 | $BIN_IPTABLES -I FORWARD -j $CHAIN_NAME > /dev/null 2>&1 128 | fi 129 | 130 | 131 | fi 132 | 133 | # Flushing rules 134 | echo "Flushing rules from $CHAIN_NAME chain" 135 | $BIN_IPTABLES -F $CHAIN_NAME 136 | 137 | # Add rules 138 | echo "Adding IPs to chain" 139 | for i in $TOR_IPS; do 140 | 141 | if [ $(is_ip $i) -eq 1 ]; then 142 | echo "'$i' is not an valid ip. Skipping" 1>&2 143 | continue 144 | fi 145 | 146 | # LOG 147 | if [ $(is_action $OPT_LOG) -eq 1 ]; then 148 | $BIN_IPTABLES -A $CHAIN_NAME -s $i -j LOG -m limit --limit ${LOG_LIMIT_AMT}/m --limit-burst $LOG_LIMIT_BURST --log-prefix "TORBLOCK: Inbound access: " --log-level $LOG_LEVEL > /dev/null 2>&1 # source LOG 149 | fi 150 | 151 | # DROP 152 | if [ $(is_action $OPT_BLOCK) -eq 1 ]; then 153 | $BIN_IPTABLES -A $CHAIN_NAME -s $i -j DROP > /dev/null 2>&1 # source DROP 154 | fi 155 | 156 | # REDIRECT 157 | if [ $(is_action $OPT_REDIRECT) -eq 1 ] && [ "$REDIRECT_IP" != "" ]; then 158 | $BIN_IPTABLES -t nat -A ${CHAIN_NAME}_REDIRECT -s $i -j DNAT --to-destination $REDIRECT_IP > /dev/null 2>&1 # source REDIRECT 159 | fi 160 | 161 | # Add to OUTPUT ? 162 | if [ $ADD_OUTPUT_RULES -eq 1 ]; then 163 | # Log 164 | if [ $(is_action $OPT_LOG) -eq 1 ]; then 165 | $BIN_IPTABLES -A $CHAIN_NAME -d $i -j LOG -m limit --limit ${LOG_LIMIT_AMT}/m --limit-burst $LOG_LIMIT_BURST --log-prefix "TORBLOCK: Outbound access: " --log-level $LOG_LEVEL > /dev/null 2>&1 # destination LOG 166 | fi 167 | # Block 168 | if [ $(is_action $OPT_LOG) -eq 1 ]; then 169 | $BIN_IPTABLES -A $CHAIN_NAME -d $i -j DROP > /dev/null 2>&1 # destination DROP 170 | fi 171 | fi 172 | _TOR_HOSTS_ADDED=$(($_TOR_HOSTS_ADDED+1)) 173 | echo "... added $i to $CHAIN_NAME (source/dest)" 174 | done; 175 | 176 | echo "$_TOR_HOSTS_ADDED TOR Exit-Nodes successfully added to iptables rules" 177 | } 178 | 179 | # Auxiliary Functions 180 | 181 | has_rule() { 182 | 183 | _RULE=$1 184 | 185 | 186 | echo -e "$IPTABLES_SAVE_OUT" | grep -ei "$_RULE" > /dev/null 2>&1 187 | if [ $? -eq 1 ]; then 188 | echo 1; 189 | else 190 | echo 0; 191 | fi 192 | 193 | } 194 | 195 | is_action() { 196 | VALID=$(($ACTION_SET | $1)) 197 | if [ $VALID -eq $ACTION_SET ]; then 198 | echo 1; 199 | else 200 | echo 0; 201 | fi 202 | } 203 | 204 | is_ip() { 205 | if [[ $1 =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then 206 | ret=0 207 | else 208 | ret=1 209 | fi 210 | echo $ret 211 | } 212 | 213 | clear_rules() { 214 | # DEBUGGING PURPOSES ONLY 215 | iptables -F INPUT 216 | iptables -F OUTPUT 217 | iptables -F FORWARD 218 | iptables -F $CHAIN_NAME 219 | iptables -X $CHAIN_NAME 220 | iptables -t nat -F ${CHAIN_NAME}_REDIRECT 221 | iptables -t nat -X ${CHAIN_NAME}_REDIRECT 222 | iptables -t nat -F PREROUTING 223 | iptables -t nat -F POSTROUTING 224 | } 225 | 226 | # Main function 227 | 228 | main() { 229 | 230 | #clear_rules #DEBUGGING ONLY! WILL WIPE OUT ALL IPTABLES RULES 231 | check 232 | download_list 233 | add_rules 234 | 235 | } 236 | 237 | main 238 | --------------------------------------------------------------------------------