This repository is private.
All pages are served over SSL and all pushing and pulling is done over SSH.
No one may fork, clone, or view it unless they are added as a member.
Every repository with this icon (
) is private.
Every repository with this icon (
This repository is public.
Anyone may fork, clone, or view it.
Every repository with this icon (
) is public.
Every repository with this icon (
jw.firewall / rc.firewall
| 6675eeda » | jwiegley | 2008-08-30 | 1 | #!/bin/bash | |
| 2 | |||||
| 3 | ############################################################################## | ||||
| 4 | # | ||||
| 5 | # rc.firewall | ||||
| 6 | # | ||||
| fa6d5816 » | jwiegley | 2008-09-16 | 7 | # version 1.68 (2008/09/09) by John Wiegley <johnw@newartisans.com> | |
| 6675eeda » | jwiegley | 2008-08-30 | 8 | # | |
| 9 | # This script takes a series of arguments describing the current network | ||||
| 10 | # interfaces and the networks behind them. Basic usage is: | ||||
| 11 | # | ||||
| 12 | # rc.firewall [OPTIONS] [INTERFACES...] | ||||
| 13 | # | ||||
| 14 | # The list of INTERFACES specifies which interfaces and networks you know | ||||
| 15 | # about, and their respective level of trust. | ||||
| 16 | # | ||||
| 17 | # NOTE: Interfaces/networks which are not mentioned are completely shut out | ||||
| 18 | # and *not logged*. This means that if no interfaces are given, the effect is | ||||
| 19 | # to shut out networking entirely, except for DHCP and certain types of ICMP. | ||||
| 20 | # This is not a bad idea as a default after startup, until you know what your | ||||
| 21 | # networking environment looks like. | ||||
| 22 | # | ||||
| 23 | # An INTERFACE may be just an interface name, in which case traffic is not | ||||
| 24 | # filtered by a netmask. This is important for interfaces that will access | ||||
| 25 | # addresses outside of their own range, such as those wishing to reach the | ||||
| 26 | # Internet. If a network base address and mask is given after a colon, it | ||||
| 27 | # specifies legal address ranges for that interface: this is used to check for | ||||
| 28 | # spoofing and illegal addresses. If two colons are used, the network is | ||||
| 29 | # considered "trusted" and additional traffic, such as Rendezvous, is allowed. | ||||
| 30 | # | ||||
| 745ce485 » | jwiegley | 2008-09-08 | 31 | # INTERFACE EXAMPLES | |
| 6675eeda » | jwiegley | 2008-08-30 | 32 | # | |
| 33 | # en1{0,0} en1 (Airport) accesses the Internet | ||||
| 34 | # and uses priority packet queueing, | ||||
| 35 | # but without rate limiting | ||||
| 36 | # en0:192.168.0.0/24 Local network on en0: 192.168.0.x | ||||
| 37 | # en0::192.168.0.0/16 Trusted network on en0: 192.168.x.x | ||||
| 745ce485 » | jwiegley | 2008-09-08 | 38 | # en0::192.168.0.0:255.255.0.0 Same as previous | |
| 6675eeda » | jwiegley | 2008-08-30 | 39 | # en0+mac::192.168.0.0/16 Trusted Mac network on en0 | |
| 40 | # en0+win::192.168.0.0/16 Trusted Windows network on en0 | ||||
| 41 | # en0+mac+win::192.168.0.0/16 Trusted mixed network on en0 | ||||
| 42 | # | ||||
| 43 | # The same interface can appear multiple times, if you have several networks | ||||
| 44 | # connected to it (such as having your router's local network, and the | ||||
| 45 | # Internet, both visible over en1). NOTE: *In that case, always list the most | ||||
| 46 | # specific interfaces/networks first*. This means that if you access both | ||||
| 47 | # 192.168.0.0/24 and the Internet over en1, use this: | ||||
| 48 | # | ||||
| 745ce485 » | jwiegley | 2008-09-08 | 49 | # rc.firewall en1::192.168.0.0/24 en1\{0,0\} | |
| 6675eeda » | jwiegley | 2008-08-30 | 50 | # | |
| 51 | # The string {0,0} (escaped for the shell) specifies inbound and outbound | ||||
| 52 | # bandwidth limits for public interfaces. A pair of zeros means bandwith | ||||
| 745ce485 » | jwiegley | 2008-09-08 | 53 | # isn't limited, but it *is* shaped -- under the assumption that resources | |
| 54 | # probably *are* limited, you just don't want to specify an artifical number | ||||
| 6675eeda » | jwiegley | 2008-08-30 | 55 | # right now. If the "{IN,OUT}" isn't specified for an interface, it means | |
| 56 | # neither limiting nor shaping is performed. | ||||
| 57 | # | ||||
| 58 | # NOTE: A deficiency of this script is that I limit/shape based on the | ||||
| 59 | # interface, not the network; to compensate, traffic bound for internal | ||||
| 60 | # networks is never limited or shaped. | ||||
| 61 | |||||
| 745ce485 » | jwiegley | 2008-09-08 | 62 | # RECIPES | |
| 6675eeda » | jwiegley | 2008-08-30 | 63 | # | |
| 745ce485 » | jwiegley | 2008-09-08 | 64 | # 1. You're going to be gaming on a mixed local LAN tonight over Ethernet, but | |
| 65 | # your Internet access will be via Wireless: | ||||
| 66 | # | ||||
| 67 | # rc.firewall --gaming en0\{0,0\}+mac+win::192.168.x.0/24 en1 | ||||
| 68 | # | ||||
| 69 | # 2. You're at a local coffee shop, using wireless, and you'd like to be a | ||||
| 70 | # good citizen (i.e., not saturate their network with your downloads), so | ||||
| 71 | # you limit voluntarily rate-limit yourself to 512 Kbits down and 128 Kbits | ||||
| 72 | # up: | ||||
| 73 | # | ||||
| 74 | # rc.firewall --stealth --blackhole en1\{512Kbits/s,128Kbits/s\} | ||||
| 75 | # | ||||
| 76 | # 3. You're at home, where you connect by wireless and have a Mac network, | ||||
| 77 | # plus you leave your SSH port open: | ||||
| 78 | # | ||||
| 79 | # rc.firewall --trusted-tcp 22 en1+mac::192.168.x.0/24 en1\{0,0\} | ||||
| 80 | # | ||||
| 81 | # 4. You're running your secure little Mac at the cafe, same as #2, but you | ||||
| 82 | # also have a Windows box running in VMware that you'd like to trust, and | ||||
| 83 | # you have a VPN connection to your Windows-based office. Lastly, you | ||||
| 84 | # sometimes route *all* traffic through the VPN, though not always: | ||||
| 85 | # | ||||
| 86 | # rc.firewall --stealth --blackhole \ | ||||
| 87 | # en1\{512Kbits/s,128Kbits/s\} \ | ||||
| 88 | # vmnet8+win::192.168.36.0/24 \ | ||||
| 89 | # tap0\{500Kbits/s,118Kbits/s\}+win::10.0.0.0/8 \ | ||||
| 90 | # tap0\{500Kbits/s,118Kbits/s\} | ||||
| 91 | |||||
| 92 | # OPTIONS | ||||
| 6675eeda » | jwiegley | 2008-08-30 | 93 | # | |
| 94 | # --debug | ||||
| 745ce485 » | jwiegley | 2008-09-08 | 95 | # Show what commands would have been executed to setup the firewall. No | |
| 96 | # system changes are made. | ||||
| 97 | # | ||||
| 98 | # --verbose | ||||
| 99 | # Log suspicious packets. Note that on some network, this can result in | ||||
| 100 | # rather large log files. | ||||
| 6675eeda » | jwiegley | 2008-08-30 | 101 | # | |
| 102 | # --log-all | ||||
| 745ce485 » | jwiegley | 2008-09-08 | 103 | # Log every rejected packet, not just the suspicious ones. Note: If you're | |
| 104 | # restarting the firewall, you'll initially reject a lot of established | ||||
| 105 | # packets from connections made before the restart. | ||||
| 6675eeda » | jwiegley | 2008-08-30 | 106 | # | |
| 107 | # --stealth | ||||
| 745ce485 » | jwiegley | 2008-09-08 | 108 | # Try to be as stealthy as possible. Ordinarily, this script responds to | |
| 109 | # failed connection attempts in the following manner: | ||||
| 6675eeda » | jwiegley | 2008-08-30 | 110 | # | |
| 111 | # port 113 TCP RESET | ||||
| 112 | # broadcasts ICMP host-prohib | ||||
| 113 | # connections ICMP filter-prohib | ||||
| 114 | # old established connections TCP RESET | ||||
| 115 | # NetBIOS/Rendezvous traffic silently drop packet | ||||
| 116 | # | ||||
| 745ce485 » | jwiegley | 2008-09-08 | 117 | # Also, while all "normal" outbound traffic is silently allowed, anything | |
| 118 | # out of the ordinary is logged (if --verbose is used). | ||||
| 6675eeda » | jwiegley | 2008-08-30 | 119 | # | |
| 745ce485 » | jwiegley | 2008-09-08 | 120 | # When --stealth mode is on, this script drops all inbound packets silently, | |
| 121 | # and also all suspicious outbound packets. It tries to make your machine | ||||
| 122 | # appear as far under the radar as possible on an open network. | ||||
| 6675eeda » | jwiegley | 2008-08-30 | 123 | # | |
| 745ce485 » | jwiegley | 2008-09-08 | 124 | # However, do realize that being entirely stealthy is not possible. Anyone | |
| 125 | # on the same local network as you will be able to see your ARP packets | ||||
| 126 | # flying around, and will know you are there and what your MAC address is. | ||||
| 127 | # Also, by attempting to scan you, they will know you're trying to be | ||||
| 128 | # stealthy. In fact, --stealth mode is really only effective against the | ||||
| 129 | # most casual of observers. | ||||
| 6675eeda » | jwiegley | 2008-08-30 | 130 | # | |
| 131 | # --blackhole | ||||
| 745ce485 » | jwiegley | 2008-09-08 | 132 | # If used, a tcp/udp blackhole is configured to help block stealth scanning. | |
| 133 | # Note however that this has caused known slowdowns in services like Samba | ||||
| 134 | # (smbfs). | ||||
| 135 | # | ||||
| 136 | # --gaming | ||||
| 137 | # Indicates that you intend to use the machine primarily for gaming, where | ||||
| 138 | # latency is more important than throughput. Kernel variables are tuned | ||||
| 139 | # accordingly. You should also use priority queuing (suffix {0,0} to the | ||||
| 140 | # interface) so that small ACK packets get out ASAP. | ||||
| 6675eeda » | jwiegley | 2008-08-30 | 141 | # | |
| 142 | # --router INTF1,INTF2:NET | ||||
| 745ce485 » | jwiegley | 2008-09-08 | 143 | # This machine acts as a router between INTF1 and INTF2 for network NET. | |
| 144 | # INTF1 specifies the target interface, so if you wanted to route traffic | ||||
| 145 | # from en1 (local clients connected to your Airport network) over en0 (cable | ||||
| 146 | # modem connection to the Internet), you would use: | ||||
| 147 | # | ||||
| 148 | # rc.firewall --router en0,en1:192.168.10.0/24 | ||||
| 149 | # | ||||
| 150 | # This might read as "route traffic over Ethernet (en0) coming from the | ||||
| 151 | # Wireless (en1) subnetwork (192.168.10.0/24)". | ||||
| 6675eeda » | jwiegley | 2008-08-30 | 152 | # | |
| 153 | # --tcp PORT[,PORT...] | ||||
| 154 | # --udp PORT[,PORT...] | ||||
| 155 | # Make the given inbound PORTs accessible on any configured interface. | ||||
| 156 | # | ||||
| 157 | # --local-tcp PORT[,PORT...] | ||||
| 158 | # --local-udp PORT[,PORT...] | ||||
| 745ce485 » | jwiegley | 2008-09-08 | 159 | # Make the given inbound PORTs accessible to local networks (i.e., not the | |
| 160 | # Internet). | ||||
| 6675eeda » | jwiegley | 2008-08-30 | 161 | # | |
| 162 | # --trusted-tcp PORT[,PORT...] | ||||
| 163 | # --trusted-udp PORT[,PORT...] | ||||
| 164 | # Make the given inbound PORTs accessible to trusted networks only. | ||||
| 165 | |||||
| 166 | # NOTES | ||||
| 167 | # | ||||
| 168 | # A word about a few of the things this script cannot do, owing to | ||||
| 169 | # deficiencies in ipfw on Mac OS X 10.4 and 10.5: | ||||
| 170 | # | ||||
| 171 | # * You cannot filter incoming packets based on the MAC address of the source. | ||||
| 172 | # This is because the necessary support is not compiled into the OS X | ||||
| 745ce485 » | jwiegley | 2008-09-08 | 173 | # kernel, not because ipfw doesn't support it. | |
| 6675eeda » | jwiegley | 2008-08-30 | 174 | # | |
| 175 | # * You cannot take action based on counters, like shutting off ECHO REQUEST | ||||
| 176 | # packets from a certain host once they exceed a certain number within a | ||||
| 177 | # given set of time. Tools like IPNetSentryX can do this. | ||||
| 178 | # | ||||
| 179 | # * Although you can shape traffic by directing it along specific pipes or | ||||
| 180 | # queues, you cannot manipulate traffic as it passes down the chain. Doing | ||||
| 181 | # this requires divert'ing the traffic to a user-space daemon, which | ||||
| 745ce485 » | jwiegley | 2008-09-08 | 182 | # modifies the packets and passes them on (google for 'throttled' as an | |
| 183 | # excellent example). iptables on Linux can do this sort of thing very | ||||
| 184 | # easily, it's a shame ipfw cannot. | ||||
| 6675eeda » | jwiegley | 2008-08-30 | 185 | # | |
| 186 | # * You can't match a packet based on its IP fragment offset, only on the | ||||
| 745ce485 » | jwiegley | 2008-09-08 | 187 | # existence of fragmentation or not. Also, ipfw always drops TCP packets | |
| 188 | # with a fragment offset of 1. | ||||
| 6675eeda » | jwiegley | 2008-08-30 | 189 | # | |
| 190 | ############################################################################## | ||||
| 191 | |||||
| 192 | |||||
| 193 | ############################################################################## | ||||
| 194 | # | ||||
| 195 | # Process command-line options | ||||
| 196 | # | ||||
| 197 | ############################################################################## | ||||
| 198 | |||||
| 199 | IPFW="/sbin/ipfw -q" | ||||
| 200 | |||||
| 201 | debug=false | ||||
| 745ce485 » | jwiegley | 2008-09-08 | 202 | gaming=false | |
| 6675eeda » | jwiegley | 2008-08-30 | 203 | blackhole=false | |
| 204 | router=false | ||||
| 205 | this="me" | ||||
| 206 | logall="" | ||||
| 207 | |||||
| 208 | stealth=false | ||||
| 745ce485 » | jwiegley | 2008-09-08 | 209 | verbose=false | |
| 6675eeda » | jwiegley | 2008-08-30 | 210 | tcp_reset="reset" | |
| 211 | unreach_host="unreach host" # aka, reject | ||||
| 212 | unreach_host_prohib="unreach host-prohib" | ||||
| 213 | unreach_filter_prohib="unreach filter-prohib" | ||||
| 214 | |||||
| 215 | trusted_tcp_ports="" | ||||
| 216 | trusted_udp_ports="" | ||||
| 217 | local_tcp_ports="" | ||||
| 218 | local_udp_ports="" | ||||
| 219 | public_tcp_ports="" | ||||
| 220 | public_udp_ports="" | ||||
| 221 | |||||
| 222 | while [[ -n "$1" ]] && (echo $1 | grep -q -e ^--); do | ||||
| 223 | case "$1" in | ||||
| 224 | --debug) | ||||
| 225 | shift 1 | ||||
| 226 | debug=true | ||||
| 227 | IPFW="echo ipfw" ;; | ||||
| 228 | |||||
| 745ce485 » | jwiegley | 2008-09-08 | 229 | --gaming) | |
| 230 | shift 1 | ||||
| 231 | gaming=true ;; | ||||
| 232 | |||||
| 233 | --verbose) | ||||
| 234 | shift 1 | ||||
| 235 | verbose=true ;; | ||||
| 236 | |||||
| 6675eeda » | jwiegley | 2008-08-30 | 237 | --log-all) | |
| 238 | shift 1 | ||||
| 239 | echo Logging all denied packets | ||||
| 240 | logall="log" ;; | ||||
| 241 | |||||
| 242 | --stealth) | ||||
| 243 | shift 1 | ||||
| 244 | echo Enabling stealth mode to avoid detection and leakage | ||||
| 245 | tcp_reset="drop" | ||||
| 246 | unreach_host="drop" # aka, reject | ||||
| 247 | unreach_host_prohib="drop" | ||||
| 248 | unreach_filter_prohib="drop" | ||||
| 249 | stealth="true" ;; | ||||
| 250 | |||||
| 251 | --blackhole) | ||||
| 252 | shift 1 | ||||
| 253 | echo Enabling blackhole to avoid stealth port scans | ||||
| 254 | blackhole="true" ;; | ||||
| 255 | |||||
| 256 | --router) | ||||
| 257 | shift 1 | ||||
| 258 | router=true | ||||
| 259 | external_intf=$(echo $1 | sed 's/,.*//') | ||||
| 260 | client_intf=$(echo $1 | sed 's/.*,//') | ||||
| 261 | client_net=$(echo $client_intf | sed 's/.*://') | ||||
| 262 | client_intf=$(echo $client_intf | sed 's/:.*//') | ||||
| 263 | echo Enabling routing $client_intf \($client_net\) -\> $external_intf | ||||
| 264 | shift 1;; | ||||
| 265 | |||||
| 266 | --trusted-tcp) | ||||
| 267 | shift 1 | ||||
| 268 | if [[ -n "$trusted_tcp_ports" ]]; then | ||||
| 269 | trusted_tcp_ports="$trusted_tcp_ports,$1" | ||||
| 270 | else | ||||
| 271 | trusted_tcp_ports="$1" | ||||
| 272 | fi | ||||
| 273 | echo Opening trusted TCP ports: $trusted_tcp_ports | ||||
| 274 | shift 1 ;; | ||||
| 275 | |||||
| 276 | --local-tcp) | ||||
| 277 | shift 1 | ||||
| 278 | if [[ -n "$local_tcp_ports" ]]; then | ||||
| 279 | local_tcp_ports="$local_tcp_ports,$1" | ||||
| 280 | else | ||||
| 281 | local_tcp_ports="$1" | ||||
| 282 | fi | ||||
| 283 | echo Opening local TCP ports: $local_tcp_ports | ||||
| 284 | shift 1 ;; | ||||
| 285 | |||||
| 286 | --tcp) | ||||
| 287 | shift 1 | ||||
| 288 | if [[ -n "$public_tcp_ports" ]]; then | ||||
| 289 | public_tcp_ports="$public_tcp_ports,$1" | ||||
| 290 | else | ||||
| 291 | public_tcp_ports="$1" | ||||
| 292 | fi | ||||
| 293 | echo Opening public TCP ports: $public_tcp_ports | ||||
| 294 | shift 1 ;; | ||||
| 295 | |||||
| 296 | --trusted-udp) | ||||
| 297 | shift 1 | ||||
| 298 | if [[ -n "$trusted_udp_ports" ]]; then | ||||
| 299 | trusted_udp_ports="$trusted_udp_ports,$1" | ||||
| 300 | else | ||||
| 301 | trusted_udp_ports="$1" | ||||
| 302 | fi | ||||
| 303 | echo Opening trusted UDP ports: $trusted_udp_ports | ||||
| 304 | shift 1 ;; | ||||
| 305 | |||||
| 306 | --local-udp) | ||||
| 307 | shift 1 | ||||
| 308 | if [[ -n "$local_udp_ports" ]]; then | ||||
| 309 | local_udp_ports="$local_udp_ports,$1" | ||||
| 310 | else | ||||
| 311 | local_udp_ports="$1" | ||||
| 312 | fi | ||||
| 313 | echo Opening local UDP ports: $local_udp_ports | ||||
| 314 | shift 1 ;; | ||||
| 315 | |||||
| 316 | --udp) | ||||
| 317 | shift 1 | ||||
| 318 | if [[ -n "$public_udp_ports" ]]; then | ||||
| 319 | public_udp_ports="$public_udp_ports,$1" | ||||
| 320 | else | ||||
| 321 | public_udp_ports="$1" | ||||
| 322 | fi | ||||
| 323 | echo Opening public UDP ports: $public_udp_ports | ||||
| 324 | shift 1 ;; | ||||
| 325 | |||||
| 326 | *) | ||||
| 327 | echo Unrecognized option $1 | ||||
| 328 | exit 1 | ||||
| 329 | esac | ||||
| 330 | done | ||||
| 331 | |||||
| 332 | |||||
| 333 | ############################################################################## | ||||
| 334 | # | ||||
| 335 | # If interfaces were given, setup the global variables used by all the | ||||
| 336 | # rules. | ||||
| 337 | # | ||||
| 338 | ############################################################################## | ||||
| 339 | |||||
| 340 | args="$@" | ||||
| 341 | |||||
| 342 | declare -a interfaces | ||||
| 343 | declare -a networks | ||||
| 344 | declare -a trust | ||||
| 345 | declare -a nettype | ||||
| 346 | declare -a inbw | ||||
| 347 | declare -a outbw | ||||
| 348 | declare -a all_intf | ||||
| 349 | |||||
| 350 | intf_count=0 | ||||
| 351 | |||||
| b339b60b » | jwiegley | 2008-08-31 | 352 | function add_interface() | |
| 6675eeda » | jwiegley | 2008-08-30 | 353 | { | |
| 354 | intf=$1 | ||||
| 355 | netw=$2 | ||||
| 356 | trusted=$3 | ||||
| 357 | ntype=$4 | ||||
| 358 | intf_inbw=$5 | ||||
| 359 | intf_outbw=$6 | ||||
| 360 | |||||
| 361 | interfaces[$intf_count]=$intf | ||||
| 362 | networks[$intf_count]=$netw | ||||
| 363 | trust[$intf_count]=$trusted | ||||
| 364 | nettype[$intf_count]=$ntype | ||||
| 365 | inbw[$intf_count]=$intf_inbw | ||||
| 366 | outbw[$intf_count]=$intf_outbw | ||||
| 367 | |||||
| 368 | echo Configuring interface $intf_count: $intf $netw \ | ||||
| 369 | trusted? $trusted type $ntype \ | ||||
| 370 | \(in $intf_inbw out $intf_outbw\) | ||||
| 371 | |||||
| 372 | # Configure bandwith shaping in/out pipes for each interface that | ||||
| 373 | # has a bandwith defined | ||||
| 374 | if [[ -n "$intf_inbw" ]]; then | ||||
| 375 | $IPFW pipe $((100 + intf_count)) config bw 0 | ||||
| 376 | $IPFW pipe $((200 + intf_count)) config bw 0 | ||||
| 377 | fi | ||||
| 378 | |||||
| 379 | # If the interface is not yet in the `all_intf' array, add it | ||||
| 380 | if echo ${all_intf[@]} | grep -qv "\\<$intf\\>"; then | ||||
| 381 | all_intf=(${all_intf[@]} $intf) | ||||
| 382 | fi | ||||
| 383 | |||||
| 384 | intf_count=$((intf_count + 1)) | ||||
| 385 | } | ||||
| 386 | |||||
| 387 | while [[ -n "$1" ]]; do | ||||
| 388 | intf="" | ||||
| 389 | netw=any | ||||
| 390 | trusted=false | ||||
| 391 | ntype=unknown | ||||
| 392 | |||||
| 393 | intf=$(echo "$1" | sed 's/[+:].*//') | ||||
| 394 | netw=$(echo "$1" | sed 's/^[^:]*:*//') | ||||
| 395 | |||||
| 396 | if [[ -z "$netw" ]]; then | ||||
| 397 | netw=any | ||||
| 398 | fi | ||||
| 399 | |||||
| 400 | if echo "$1" | grep -q "::"; then | ||||
| 401 | trusted=true | ||||
| 402 | fi | ||||
| 403 | |||||
| 404 | if echo "$1" | grep -q "\\+mac"; then | ||||
| 405 | ntype=mac | ||||
| 406 | fi | ||||
| 407 | |||||
| 408 | if echo "$1" | grep -q "\\+win"; then | ||||
| 409 | if [[ $ntype == mac ]]; then | ||||
| 410 | ntype=both | ||||
| 411 | else | ||||
| 412 | ntype=win | ||||
| 413 | fi | ||||
| 414 | fi | ||||
| 415 | |||||
| 416 | if echo "$intf" | grep -q "{"; then | ||||
| 417 | intf_inbw=$(echo "$intf" | sed 's/.*{//' | sed 's/,.*//' | sed 's/}//') | ||||
| 418 | intf_outbw=$(echo "$intf" | sed 's/.*{//' | sed 's/.*,//' | sed 's/}//') | ||||
| 419 | intf=$(echo "$intf" | sed 's/{.*//') | ||||
| 420 | else | ||||
| 421 | intf_inbw="" | ||||
| 422 | intf_outbw="" | ||||
| 423 | fi | ||||
| 424 | |||||
| 425 | add_interface $intf $netw $trusted $ntype $intf_inbw $intf_outbw | ||||
| 426 | |||||
| 427 | shift 1 | ||||
| 428 | done | ||||
| 429 | |||||
| 430 | via_all="" | ||||
| 431 | |||||
| 432 | if [[ $intf_count > 0 ]]; then | ||||
| 433 | for intf in ${all_intf[@]}; do | ||||
| 434 | if [[ -z "$via_all" ]]; then | ||||
| 435 | via_all="{" | ||||
| 436 | else | ||||
| 437 | via_all="$via_all or" | ||||
| 438 | fi | ||||
| 439 | via_all="$via_all via $intf" | ||||
| 440 | done | ||||
| 441 | |||||
| 442 | if [[ -n "$via_all" ]]; then | ||||
| 443 | via_all="$via_all }" | ||||
| 444 | fi | ||||
| 445 | fi | ||||
| 446 | |||||
| 447 | |||||
| 448 | ############################################################################## | ||||
| 449 | # | ||||
| 450 | # Function for rate limiting/traffic shaping an interface | ||||
| 451 | # | ||||
| 452 | ############################################################################## | ||||
| 453 | |||||
| 454 | declare -a limited | ||||
| 455 | |||||
| 456 | function limit_intf() | ||||
| 457 | { | ||||
| 458 | intf=$1 | ||||
| 459 | intf_index="" | ||||
| 460 | |||||
| 461 | for (( i=0; i < intf_count; i++ )); do | ||||
| 462 | if [[ ${interfaces[$i]} == $intf && \ | ||||
| 463 | -z "${limited[$i]}" && -n "${inbw[$i]}" ]]; then | ||||
| 464 | limited[$i]=true | ||||
| 465 | |||||
| 466 | # Put a pipe in place for all remaining inbound/outbound traffic, | ||||
| 467 | # which can be throttled using the option --setrate or the | ||||
| 468 | # separate script "setrate". This makes it easy to be kind to | ||||
| 469 | # other people's networks, no matter what kind of traffic it is. | ||||
| 470 | inpipe="pipe $((100 + i))" | ||||
| 471 | outpipe="pipe $((200 + i))" | ||||
| 472 | |||||
| 473 | $IPFW $inpipe config bw ${inbw[$i]} | ||||
| 474 | $IPFW $outpipe config bw ${outbw[$i]} | ||||
| b339b60b » | jwiegley | 2008-08-31 | 475 | ||
| 6675eeda » | jwiegley | 2008-08-30 | 476 | private="192.168.0.0/16,172.16.0.0/12,10.0.0.0/8" | |
| 477 | |||||
| 478 | $IPFW add 450 set 0 skipto 900 all from any to $private out via $intf | ||||
| 479 | $IPFW add 460 set 0 skipto 900 all from $private to any in via $intf | ||||
| 480 | |||||
| 481 | $IPFW add 500 set 0 $inpipe tcp from any to any in via $intf tcpflags !syn | ||||
| 482 | $IPFW add 510 set 0 $inpipe udp from any to any in via $intf | ||||
| 483 | |||||
| 484 | # Shape the outbound pipe so that some protocols get priority going | ||||
| 485 | # out | ||||
| 486 | $IPFW queue $((100 + i)) config $outpipe weight 7 # high-priority | ||||
| 487 | $IPFW queue $((200 + i)) config $outpipe weight 5 # medium-priority | ||||
| 488 | $IPFW queue $((300 + i)) config $outpipe weight 1 # low-priority | ||||
| b339b60b » | jwiegley | 2008-08-31 | 489 | ||
| 6675eeda » | jwiegley | 2008-08-30 | 490 | # Assign outgoing empty/small ACK packets to the high-priority queue | |
| 491 | $IPFW add 600 set 0 queue $((100 + i)) \ | ||||
| 492 | tcp from any to any out via $intf tcpflags ack iplen 0-80 | ||||
| b339b60b » | jwiegley | 2008-08-31 | 493 | ||
| 6675eeda » | jwiegley | 2008-08-30 | 494 | # Assign outgoing UDP (DNS) and SSH traffic to the medium-priority queue | |
| 495 | $IPFW add 700 set 0 queue $((200 + i)) tcp from any to any 22,80,443,5900 \ | ||||
| 496 | out via $intf \{ tcpflags \!ack or iplen 81-65535 \} | ||||
| 497 | $IPFW add 710 set 0 queue $((200 + i)) udp from any to any 53,1194 out via $intf | ||||
| b339b60b » | jwiegley | 2008-08-31 | 498 | ||
| 6675eeda » | jwiegley | 2008-08-30 | 499 | # Assign all other outgoing traffic to the low-priority queue: | |
| 500 | $IPFW add 800 set 0 queue $((300 + i)) tcp from any to any not 22,80,443,5900 \ | ||||
| 501 | out via $intf \{ tcpflags \!ack or iplen 81-65535 \} | ||||
| 502 | $IPFW add 810 set 0 queue $((300 + i)) udp from any to any not 53,1194 out via $intf | ||||
| 503 | |||||
| 504 | fi | ||||
| 505 | done | ||||
| 506 | } | ||||
| 507 | |||||
| 508 | |||||
| 509 | ############################################################################## | ||||
| 510 | # | ||||
| 511 | # Initialize and tune the firewalling environment | ||||
| 512 | # | ||||
| 513 | ############################################################################## | ||||
| 514 | |||||
| 515 | # Remove any rules previously defined and flush the dynamic tables | ||||
| 516 | $IPFW -f flush | ||||
| 517 | $IPFW -f pipe flush | ||||
| 518 | |||||
| 519 | # Log all rejected packets, which are always "suspect" | ||||
| 520 | if [[ $debug == false ]]; then | ||||
| 745ce485 » | jwiegley | 2008-09-08 | 521 | if [[ $verbose == true ]]; then | |
| 522 | sysctl -w net.inet.ip.fw.verbose=1 | ||||
| 523 | else | ||||
| 524 | sysctl -w net.inet.ip.fw.verbose=0 | ||||
| 525 | fi | ||||
| 6675eeda » | jwiegley | 2008-08-30 | 526 | ||
| 527 | # Make sure packets get reinjected | ||||
| 528 | sysctl -w net.inet.ip.fw.one_pass=0 | ||||
| 529 | # Check that packets are appropriate to their interface | ||||
| 530 | sysctl -w net.inet.ip.check_interface=1 | ||||
| 745ce485 » | jwiegley | 2008-09-08 | 531 | ||
| 6675eeda » | jwiegley | 2008-08-30 | 532 | # Turn on RFC1323 TCP high speed optimization. | |
| 533 | # NOTE: This can be a security risk (DoS attack) | ||||
| 534 | sysctl -w net.inet.tcp.rfc1323=1 | ||||
| 535 | # ICMP limit | ||||
| 536 | sysctl -w net.inet.icmp.icmplim=1024 | ||||
| 537 | # Stop redirects | ||||
| 538 | sysctl -w net.inet.icmp.drop_redirect=1 | ||||
| 539 | sysctl -w net.inet.icmp.log_redirect=1 | ||||
| 540 | sysctl -w net.inet.ip.redirect=0 | ||||
| 541 | # Stop source routing | ||||
| 542 | sysctl -w net.inet.ip.sourceroute=0 | ||||
| 543 | sysctl -w net.inet.ip.accept_sourceroute=0 | ||||
| 544 | # Stop broadcast ECHO response | ||||
| 545 | sysctl -w net.inet.icmp.bmcastecho=0 | ||||
| 546 | # Stop other broadcast probes | ||||
| 547 | sysctl -w net.inet.icmp.maskrepl=0 | ||||
| 548 | # Turn on strong TCP sequencing | ||||
| 549 | sysctl -w net.inet.tcp.strict_rfc1948=1 | ||||
| 550 | # Socket queue defense against SYN attacks | ||||
| 551 | sysctl -w kern.ipc.somaxconn=1024 | ||||
| 552 | # IPC max buffering | ||||
| 553 | sysctl -w kern.ipc.maxsockbuf=523288 | ||||
| 554 | # ARP cleanup | ||||
| 555 | sysctl -w net.link.ether.inet.max_age=1200 | ||||
| 556 | |||||
| 745ce485 » | jwiegley | 2008-09-08 | 557 | # Increase buffers for faster downloads when you have very | |
| 558 | # high-speed, latency-free bandwidth (ie, _not_ DSL which dies badly | ||||
| 559 | # as it saturates) | ||||
| 560 | if [[ $gaming == true ]]; then | ||||
| 561 | sysctl -w net.inet.tcp.sendspace=16383 | ||||
| 562 | sysctl -w net.inet.tcp.recvspace=16383 | ||||
| 563 | sysctl -w net.inet.udp.recvspace=42080 | ||||
| 564 | sysctl -w net.inet.raw.recvspace=8192 | ||||
| 565 | sysctl -w net.local.dgram.maxdgram=4196 | ||||
| 566 | |||||
| 567 | # Other network buffering | ||||
| 568 | sysctl -w net.local.stream.recvspace=16383 | ||||
| 569 | sysctl -w net.local.stream.sendspace=16383 | ||||
| 570 | sysctl -w net.local.dgram.recvspace=8192 | ||||
| 571 | |||||
| 572 | # TCP delayed ack off, better latency | ||||
| 573 | sysctl -w net.inet.tcp.delayed_ack=0 | ||||
| 574 | else | ||||
| 575 | sysctl -w net.inet.tcp.sendspace=32767 | ||||
| 576 | sysctl -w net.inet.tcp.recvspace=32767 | ||||
| 577 | sysctl -w net.inet.udp.recvspace=65535 | ||||
| 578 | sysctl -w net.inet.raw.recvspace=16384 | ||||
| 579 | sysctl -w net.local.dgram.maxdgram=8192 | ||||
| 580 | |||||
| 581 | # Other network buffering | ||||
| 582 | sysctl -w net.local.stream.recvspace=32767 | ||||
| 583 | sysctl -w net.local.stream.sendspace=32767 | ||||
| 584 | sysctl -w net.local.dgram.recvspace=16384 | ||||
| 585 | |||||
| 586 | # TCP delayed ack on, better throughput | ||||
| 587 | sysctl -w net.inet.tcp.delayed_ack=1 | ||||
| 588 | fi | ||||
| 589 | |||||
| 6675eeda » | jwiegley | 2008-08-30 | 590 | # Create a blackhole to avoid stealth port scans | |
| 591 | if [[ $blackhole == true ]]; then | ||||
| 592 | sysctl -w net.inet.tcp.blackhole=2 | ||||
| 593 | sysctl -w net.inet.udp.blackhole=1 | ||||
| 594 | else | ||||
| 595 | sysctl -w net.inet.tcp.blackhole=0 | ||||
| 596 | sysctl -w net.inet.udp.blackhole=0 | ||||
| 597 | fi | ||||
| 598 | |||||
| 599 | # If we're acting as a router, enable packet forwarding | ||||
| 600 | if [[ $router == true ]]; then | ||||
| 601 | sysctl -w net.inet.ip.forwarding=1 | ||||
| 602 | else | ||||
| 603 | sysctl -w net.inet.ip.forwarding=0 | ||||
| 604 | fi | ||||
| 605 | fi | ||||
| 606 | |||||
| 607 | |||||
| 608 | ############################################################################## | ||||
| 609 | # | ||||
| 610 | # Set 0: Allow loopback, divert NAT packets, shape ICMP/TCP-SYN | ||||
| 611 | # | ||||
| 612 | ############################################################################## | ||||
| 613 | |||||
| 614 | # Allow all loopback traffic, don't bother with anything else | ||||
| 615 | $IPFW add 100 set 0 allow all from any to any via 'lo*' | ||||
| 616 | |||||
| 617 | if [[ $router == true ]]; then | ||||
| 618 | # Divert traffic from the external interface to the nat daemon | ||||
| 619 | # (note: using "in" here, as some firewalls do, causes OpenVPN to | ||||
| 620 | # stop working) | ||||
| 621 | $IPFW add 200 set 0 divert natd all from any to any via $external_intf | ||||
| 622 | fi | ||||
| 623 | |||||
| 624 | # Rate limit TCP traffic used to establish connections, to protect | ||||
| 625 | # against SYN flooding | ||||
| 626 | $IPFW pipe 300 config bw 64Kbit/s queue 5 | ||||
| 627 | |||||
| 628 | $IPFW add 300 set 0 pipe 300 tcp from any to any in setup | ||||
| 629 | |||||
| 630 | # Delay TCP RESET packets. From the IPNetSentryX docs: "Some | ||||
| 631 | # firewalls can send TCP RESET segments when denying access. If the | ||||
| 632 | # interface running such a firewall is set to promiscuous mode, the | ||||
| 633 | # firewall may send TCP RESET segments in response to connection | ||||
| 634 | # requests that were not originally addressed to that host. The | ||||
| 635 | # symptom is frequent “Connection refused” responses when trying to | ||||
| 636 | # access remote servers. By delaying such TCP RESET segments | ||||
| 637 | # (approximately 0.5 seconds), we allow the actual target of the | ||||
| 638 | # connection request (if any) to respond first completing the | ||||
| 639 | # connection process. When the RESET arrives, it will be safely | ||||
| 640 | # ignored as out of order if the target host has already responded." | ||||
| 641 | $IPFW pipe 350 config delay 500 | ||||
| 642 | |||||
| 643 | $IPFW add 350 set 0 pipe 350 tcp from any to any in tcpflags rst | ||||
| 644 | |||||
| 645 | # Rate limit ICMP traffic to avoid line clogging by Smurf attacks | ||||
| 646 | $IPFW pipe 400 config bw 16Kbit/s queue 1 | ||||
| 647 | $IPFW pipe 410 config bw 16Kbit/s queue 5 | ||||
| 648 | |||||
| 649 | $IPFW add 410 set 0 pipe 400 icmp from any to any in | ||||
| 650 | $IPFW add 415 set 0 pipe 410 icmp from any to any out | ||||
| 651 | |||||
| 652 | # Rules 500-899 are defined by limit_intf() above | ||||
| 653 | |||||
| 654 | $IPFW add 901 set 0 deny log all from any to any ipoptions rr in $via_all | ||||
| 655 | $IPFW add 911 set 0 deny log all from any to any ipoptions ts in $via_all | ||||
| 656 | $IPFW add 921 set 0 deny log all from any to any ipoptions lsrr in $via_all | ||||
| 657 | $IPFW add 931 set 0 deny log all from any to any ipoptions ssrr in $via_all | ||||
| 658 | |||||
| 659 | $IPFW add 941 set 0 deny log tcp from any to any tcpflags syn,fin | ||||
| 660 | $IPFW add 951 set 0 deny log tcp from any to any tcpflags syn,rst | ||||
| 661 | $IPFW add 961 set 0 deny log tcp from any 0 to any | ||||
| 662 | $IPFW add 971 set 0 deny log tcp from any to any 0 | ||||
| 663 | $IPFW add 981 set 0 deny log udp from any 0 to any | ||||
| 664 | $IPFW add 991 set 0 deny log udp from any to any 0 | ||||
| 665 | |||||
| 666 | |||||
| 667 | ############################################################################## | ||||
| 668 | # | ||||
| 669 | # Set 1: Allow routed traffic | ||||
| 670 | # | ||||
| 671 | # If this machine is acting as a router, allow traffic to pass through | ||||
| 672 | # between the two connected interfaces. | ||||
| 673 | # | ||||
| 674 | ############################################################################## | ||||
| 675 | |||||
| 676 | if [[ $router == true ]]; then | ||||
| 677 | # Allow traffic coming in from the "client" network, and traffic | ||||
| 678 | # coming in from the Internet bound for the client network | ||||
| 679 | $IPFW add 1000 set 1 allow all from $client_net to any in recv $client_intf | ||||
| 680 | $IPFW add 1010 set 1 allow all from any to $client_net in recv $external_intf | ||||
| 681 | |||||
| 682 | # And allow this traffic out through the respective target interface | ||||
| 683 | $IPFW add 1100 set 1 allow all \ | ||||
| 684 | from $client_net to any out recv $client_intf xmit $external_intf | ||||
| 685 | $IPFW add 1110 set 1 allow all \ | ||||
| 686 | from any to $client_net out recv $external_intf xmit $client_intf | ||||
| 687 | |||||
| 688 | # Also allow the client network to see the router | ||||
| 689 | $IPFW add 1200 set 1 allow all from $client_net to me out recv $client_intf | ||||
| 690 | $IPFW add 1210 set 1 allow all from me to $client_net out xmit $client_intf | ||||
| 691 | fi | ||||
| 692 | |||||
| 693 | |||||
| 694 | ############################################################################## | ||||
| 695 | # | ||||
| 696 | # Set 2: Allow traffic relating to ongoing conversations | ||||
| 697 | # | ||||
| 698 | # But deny fragments and established connections not so related. | ||||
| 699 | # | ||||
| 700 | ############################################################################## | ||||
| 701 | |||||
| 702 | # Allow traffic if it matches the dynamic table | ||||
| 703 | $IPFW add 2000 set 2 check-state | ||||
| 704 | |||||
| 705 | # Drop fragments and reset established connections not matched by the | ||||
| 706 | # dynamic table | ||||
| 707 | $IPFW add 2100 set 2 deny $logall all from any to any frag | ||||
| 708 | $IPFW add 2110 set 2 $tcp_reset $logall tcp from any to any established | ||||
| 709 | |||||
| 710 | |||||
| 711 | ############################################################################## | ||||
| 712 | # | ||||
| fa6d5816 » | jwiegley | 2008-09-16 | 713 | # Set 3: Allow Rendezvous/Bonjour and AFP for Apple networks | |
| 6675eeda » | jwiegley | 2008-08-30 | 714 | # | |
| 715 | ############################################################################## | ||||
| 716 | |||||
| 717 | # TCP 548 Apple AFP | ||||
| 718 | # 5009 Apple Airport Express Admin | ||||
| fa6d5816 » | jwiegley | 2008-09-16 | 719 | # 5900 Apple VNC (screen sharing) | |
| 6675eeda » | jwiegley | 2008-08-30 | 720 | ||
| 9d533ab1 » | jwiegley | 2008-09-03 | 721 | tcp_ports=548,5009,5900 | |
| 6675eeda » | jwiegley | 2008-08-30 | 722 | ||
| 723 | # UDP 192 Apple UPnP (network discovery) | ||||
| 724 | |||||
| 725 | udp_ports=192 | ||||
| 726 | |||||
| 727 | allowed=false | ||||
| 728 | |||||
| 729 | for (( index=0; index < intf_count; index++ )); do | ||||
| 730 | if [[ ${nettype[$index]} == mac || ${nettype[$index]} == both ]]; then | ||||
| 731 | netw=${networks[$index]} | ||||
| 732 | intf=${interfaces[$index]} | ||||
| 733 | |||||
| 734 | # Allow outbound and inbound TCP connections to tcp_ports | ||||
| 735 | $IPFW add $((3100 + index)) set 3 allow $logall \ | ||||
| 2ccd2cae » | jwiegley | 2008-09-01 | 736 | tcp from me to $netw $tcp_ports out via $intf setup keep-state | |
| 737 | $IPFW add $((3110 + index)) set 3 allow $logall \ | ||||
| 738 | tcp from $netw to me $tcp_ports in via $intf setup keep-state | ||||
| 6675eeda » | jwiegley | 2008-08-30 | 739 | ||
| 740 | # Allow outbound and inbound UDP connections to udp_ports | ||||
| 741 | $IPFW add $((3200 + index)) set 3 allow $logall \ | ||||
| 2ccd2cae » | jwiegley | 2008-09-01 | 742 | udp from me to $netw $udp_ports out via $intf keep-state | |
| 743 | $IPFW add $((3210 + index)) set 3 allow $logall \ | ||||
| 744 | udp from $netw to me $udp_ports in via $intf keep-state | ||||
| 6675eeda » | jwiegley | 2008-08-30 | 745 | ||
| fa6d5816 » | jwiegley | 2008-09-16 | 746 | # Allow Rendezvous/Bonjour (Zeroconf) traffic | |
| 6675eeda » | jwiegley | 2008-08-30 | 747 | $IPFW add $((3300 + index)) set 3 allow $logall \ | |
| 748 | udp from $netw to any 5353 via $intf keep-state | ||||
| 749 | |||||
| 750 | # Allow three types of broadcast traffic typically found in | ||||
| 751 | # Windows and Apple enviroments | ||||
| 752 | $IPFW add $((3400 + index)) set 3 allow $logall \ | ||||
| 753 | ip from $netw to 224.0.0.0/3 via $intf keep-state | ||||
| 754 | $IPFW add $((3410 + index)) set 3 allow $logall \ | ||||
| 755 | udp from $netw to 239.255.255.253 via $intf keep-state | ||||
| 756 | $IPFW add $((3420 + index)) set 3 allow $logall \ | ||||
| 757 | udp from $netw to 255.255.255.255 via $intf keep-state | ||||
| 758 | |||||
| 759 | allowed=true | ||||
| 760 | fi | ||||
| 761 | done | ||||
| 762 | |||||
| 763 | # Load or unload the Apple Multicast daemon based on whether we're | ||||
| 764 | # using Rendezvous at all; no need to broadcast if we're not, since | ||||
| 765 | # the packets won't even be let out | ||||
| fa6d5816 » | jwiegley | 2008-09-16 | 766 | if [[ $debug == false ]]; then | |
| 767 | launchctl unload /System/Library/LaunchDaemons/com.apple.mDNSResponder.plist 2> /dev/null | ||||
| 768 | if [[ $allowed == true ]]; then | ||||
| 769 | launchctl load -w /System/Library/LaunchDaemons/com.apple.mDNSResponder.plist | ||||
| 770 | fi | ||||
| 6675eeda » | jwiegley | 2008-08-30 | 771 | fi | |
| 772 | |||||
| 773 | ############################################################################## | ||||
| 774 | # | ||||
| 775 | # Set 4: Allow NetBIOS and SMB for Windows networks | ||||
| 776 | # | ||||
| 777 | ############################################################################## | ||||
| 778 | |||||
| 779 | # TCP 135-139 Windows File sharing (http://support.microsoft.com/kb/298804) | ||||
| 780 | # 445 Windows Direct-hosted SMB traffic (same URL) | ||||
| 781 | # 5000 Windows UPnP | ||||
| 782 | |||||
| 783 | tcp_ports=135-139,445,5000 | ||||
| 784 | |||||
| 785 | # UDP 135-139 Windows File sharing (see above) | ||||
| 786 | # 427 Windows SLP (Service Location Protocol) | ||||
| 787 | # 445 Windows Direct-hosted SMB traffic | ||||
| 788 | # 1900 Windows UPnP | ||||
| 789 | |||||
| 790 | udp_ports=135-139,427,445,1900 | ||||
| 791 | |||||
| 792 | for (( index=0; index < intf_count; index++ )); do | ||||
| 793 | if [[ ${nettype[$index]} == win || ${nettype[$index]} == both ]]; then | ||||
| 794 | netw=${networks[$index]} | ||||
| 795 | intf=${interfaces[$index]} | ||||
| 796 | |||||
| 797 | # Allow outbound and inbound TCP connections to tcp_ports | ||||
| 798 | $IPFW add $((4100 + index)) set 4 allow $logall \ | ||||
| 2ccd2cae » | jwiegley | 2008-09-01 | 799 | tcp from me to $netw $tcp_ports out via $intf setup keep-state | |
| 800 | $IPFW add $((4110 + index)) set 4 allow $logall \ | ||||
| 801 | tcp from $netw to me $tcp_ports in via $intf setup keep-state | ||||
| 6675eeda » | jwiegley | 2008-08-30 | 802 | ||
| 803 | # Allow outbound and inbound UDP connections to udp_ports | ||||
| 804 | $IPFW add $((4200 + index)) set 4 allow $logall \ | ||||
| 2ccd2cae » | jwiegley | 2008-09-01 | 805 | udp from me to $netw $udp_ports out via $intf keep-state | |
| 806 | $IPFW add $((4210 + index)) set 4 allow $logall \ | ||||
| 807 | udp from $netw to me $udp_ports in via $intf keep-state | ||||
| 6675eeda » | jwiegley | 2008-08-30 | 808 | ||
| 809 | # Allow three types of broadcast traffic typically found in | ||||
| 810 | # Windows and Apple enviroments | ||||
| 811 | $IPFW add $((4300 + index)) set 4 allow $logall \ | ||||
| 812 | ip from $netw to 224.0.0.0/3 via $intf keep-state | ||||
| 813 | $IPFW add $((4320 + index)) set 4 allow $logall \ | ||||
| 814 | udp from $netw to 239.255.255.253 via $intf keep-state | ||||
| 815 | $IPFW add $((4340 + index)) set 4 allow $logall \ | ||||
| 816 | udp from $netw to 255.255.255.255 via $intf keep-state | ||||
| 817 | fi | ||||
| 818 | done | ||||
| 819 | |||||
| 820 | |||||
| 821 | ############################################################################## | ||||
| 822 | # | ||||
| 823 | # Set 5: Allow certain kinds of traffic for trusted networks | ||||
| 824 | # | ||||
| 825 | ############################################################################## | ||||
| 826 | |||||
| 827 | for (( index=0; index < intf_count; index++ )); do | ||||
| 828 | if [[ ${trust[$index]} == true ]]; then | ||||
| 829 | netw=${networks[$index]} | ||||
| 830 | intf=${interfaces[$index]} | ||||
| 831 | |||||
| 832 | # Allow all ICMP traffic within trusted networks (aka ping) | ||||
| 833 | $IPFW add $((5100 + index)) set 5 allow $logall \ | ||||
| 2ccd2cae » | jwiegley | 2008-09-01 | 834 | icmp from me to $netw out via $intf | |
| 835 | $IPFW add $((5110 + index)) set 5 allow $logall \ | ||||
| 836 | icmp from $netw to me in via $intf | ||||
| 6675eeda » | jwiegley | 2008-08-30 | 837 | fi | |
| 838 | done | ||||
| 839 | |||||
| 840 | # Reject broadcast traffic (possibly related to Rendezvous/NetBIOS) | ||||
| 841 | $IPFW add 5200 set 5 $unreach_host_prohib $logall ip from any to 224.0.0.0/3 not 67-68 | ||||
| 842 | $IPFW add 5210 set 5 $unreach_host_prohib $logall ip from any to 239.255.255.253 not 67-68 | ||||
| 843 | $IPFW add 5220 set 5 $unreach_host_prohib $logall ip from any to 255.255.255.255 not 67-68 | ||||
| 844 | |||||
| 845 | # Deny Windows and Apple network related UDP traffic reaching this | ||||
| 846 | # point; reject TCP with host-prohib | ||||
| 847 | $IPFW add 5300 set 5 deny $logall udp from any to any $udp_ports | ||||
| 848 | $IPFW add 5310 set 5 $unreach_host_prohib $logall tcp from any to any $tcp_ports | ||||
| 849 | |||||
| 850 | |||||
| 851 | ############################################################################## | ||||
| 852 | # | ||||
| 853 | # Set 6: Allow in/out packets related to DHCP and some ICMP | ||||
| 854 | # | ||||
| 855 | # This rule set allows our network interfaces to be configured. It can | ||||
| 856 | # be skipped if DHCP is not being used; it could also be disabled once | ||||
| 857 | # an address is assigned, although only for as long as the lease will | ||||
| 858 | # last. | ||||
| 859 | # | ||||
| 860 | ############################################################################## | ||||
| 861 | |||||
| 2f270493 » | jwiegley | 2009-03-23 | 862 | # Allow DHCP packets in and out, including broadcast. Since we don't have | |
| 863 | # an address yet, we can't use "me" as a target here. | ||||
| 864 | $IPFW add 6000 set 6 allow $logall udp \ | ||||
| 865 | from any 67-68 to any 67-68 keep-state | ||||
| 866 | |||||
| 867 | # Allow certain types of ICMP packets on known interfaces, which might be | ||||
| 868 | # necessary for proper operation | ||||
| 869 | $IPFW add 6100 set 6 allow $logall icmp from any to any \ | ||||
| 870 | icmptypes 0,3,4,11,12,13,14 keep-state | ||||
| 6675eeda » | jwiegley | 2008-08-30 | 871 | ||
| 872 | ############################################################################## | ||||
| 873 | # | ||||
| 874 | # Set 7: Filter inbound traffic | ||||
| 875 | # | ||||
| 876 | # Stateful firewalling is used to allow in packets related to | ||||
| 877 | # established outbound connections. Filtering is used to remove | ||||
| 878 | # possible spoof packets. The remainder might be consider "legitimate | ||||
| 879 | # inbound requests", and are passed to the subsequent rule sets. | ||||
| 880 | # | ||||
| 881 | ############################################################################## | ||||
| 882 | |||||
| 883 | # Verify reverse path to help avoid spoofed packets. This means any | ||||
| 884 | # packet coming from a particular interface must have an address | ||||
| 885 | # matching the netmask for that interface. The `via_all' variable is | ||||
| 886 | # used to avoid logging packets on interfaces we're not interested in. | ||||
| 887 | $IPFW add 7000 set 7 deny $logall all from any to any not verrevpath in $via_all | ||||
| 888 | |||||
| 889 | # Reject anything received that was not directly intended for this | ||||
| 890 | # matchine with a "host prohibited" response. This mostly means | ||||
| 891 | # broadcast. We omit DHCP from this because until a DHCP lease is | ||||
| 892 | # given, we have no idea what our address is/will be. | ||||
| 893 | $IPFW add 7100 set 7 $unreach_host_prohib log all from any to not me not 67-68 in $via_all | ||||
| 894 | $IPFW add 7110 set 7 $unreach_host_prohib log all from not me to any out $via_all | ||||
| 895 | |||||
| 896 | # Filter packets inbound on known interfaces | ||||
| 897 | via_check="" | ||||
| 898 | |||||
| 899 | for (( index=0; index < intf_count; index++ )); do | ||||
| 900 | netw=${networks[$index]} | ||||
| 901 | intf=${interfaces[$index]} | ||||
| 902 | |||||
| 903 | if [[ $netw == any ]]; then | ||||
| 904 | if [[ -z "$via_check" ]]; then | ||||
| 905 | via_check="{" | ||||
| 906 | else | ||||
| 907 | via_check="$via_check or" | ||||
| 908 | fi | ||||
| 909 | via_check="$via_check via $intf" | ||||
| 910 | fi | ||||
| 911 | done | ||||
| 912 | |||||
| 913 | if [[ -n "$via_check" ]]; then | ||||
| 914 | via_check="$via_check }" | ||||
| 915 | fi | ||||
| 916 | |||||
| 917 | for (( index=0; index < intf_count; index++ )); do | ||||
| 918 | netw=${networks[$index]} | ||||
| 919 | intf=${interfaces[$index]} | ||||
| 920 | |||||
| 921 | if [[ $netw != any ]]; then | ||||
| 922 | $IPFW add $((7200 + index)) set 7 skipto 7500 \ | ||||
| 923 | all from $netw to me in via $intf | ||||
| 924 | fi | ||||
| 925 | done | ||||
| 926 | |||||
| 927 | if [[ -n "$via_check" ]]; then | ||||
| 928 | # Deny all inbound traffic from RFC1918 address spaces (spoof!) | ||||
| 929 | $IPFW add $((7300 + index)) set 7 deny log \ | ||||
| 930 | all from 192.168.0.0/16 to any in $via_check | ||||
| 931 | $IPFW add $((7320 + index)) set 7 deny log \ | ||||
| 932 | all from 172.16.0.0/12 to any in $via_check | ||||
| 933 | $IPFW add $((7340 + index)) set 7 deny log \ | ||||
| 934 | all from 10.0.0.0/8 to any in $via_check | ||||
| 935 | |||||
| 936 | # Deny all inbound traffic from a loopback address (spoof!) | ||||
| 937 | $IPFW add $((7400 + index)) set 7 deny log \ | ||||
| 938 | all from 127.0.0.0/8 to any in $via_check | ||||
| 939 | fi | ||||
| 940 | |||||
| 941 | # Reject broadcasts not related to DHCP | ||||
| 942 | $IPFW add 7500 set 7 $unreach_host_prohib $logall all from 0.0.0.0/8 to any not 67-68 in | ||||
| 943 | |||||
| 944 | # Reject DHCP auto-config, and public class D & E multicast | ||||
| 945 | $IPFW add 7600 set 7 $unreach_host_prohib $logall all from 169.254.0.0/16 to any in | ||||
| 946 | $IPFW add 7610 set 7 $unreach_host_prohib $logall all from 224.0.0.0/3 to any in | ||||
| 947 | |||||
| 948 | # Send TCP RST on attempted auth connections; IRC and SMTP might try | ||||
| 949 | # to connect back to us legitimately | ||||
| 950 | $IPFW add 7700 set 7 $tcp_reset $logall tcp from any to me 113 in setup | ||||
| 951 | |||||
| 952 | |||||
| 953 | ############################################################################## | ||||
| 954 | # | ||||
| 955 | # Set 10: Shape outbound traffic | ||||
| 956 | # | ||||
| 957 | # Outbound traffic is shaped for best response while concurrent | ||||
| 958 | # transfers might be occurring in both directions. The actual shaping | ||||
| 959 | # is done at a much earlier step, even though we set it up at this | ||||
| 960 | # point in the script. | ||||
| 961 | # | ||||
| 962 | ############################################################################## | ||||
| 963 | |||||
| 964 | $IPFW set disable 10 | ||||
| 965 | |||||
| 966 | for (( index=0; index < intf_count; index++ )); do | ||||
| 967 | limit_intf ${interfaces[$index]} ${inbw[$index]} ${outbw[$index]} | ||||
| 968 | done | ||||
| 969 | |||||
| 970 | if [[ $intf_count > 0 ]]; then | ||||
| 971 | $IPFW set enable 10 | ||||
| 972 | fi | ||||
| 973 | |||||
| 974 | |||||
| 975 | ############################################################################## | ||||
| 976 | # | ||||
| 977 | # Set 11: Allow all outbound traffic | ||||
| 978 | # | ||||
| 979 | # If this ruleset is enabled, all other outbound traffic will be allowed | ||||
| 980 | # here. I use the application Little Snitch to allow/deny outbound | ||||
| 981 | # packets on a per-Application basis. | ||||
| 982 | # | ||||
| 983 | # Note that all "known" outbound traffic is silently allowed, whereas | ||||
| 984 | # unknown traffic is logged. If the --stealth option is used, unknown | ||||
| 985 | # traffic is logged and denied. | ||||
| 986 | # | ||||
| 987 | ############################################################################## | ||||
| 988 | |||||
| 989 | $IPFW set disable 11 | ||||
| 990 | |||||
| 991 | tcp_out_ports="80,443" # Web | ||||
| 992 | tcp_out_ports="$tcp_out_ports,21" # FTP | ||||
| 993 | tcp_out_ports="$tcp_out_ports,22" # OpenSSH | ||||
| 994 | tcp_out_ports="$tcp_out_ports,5900" # VNC | ||||
| 995 | tcp_out_ports="$tcp_out_ports,5222,5190,5050,1863" # IM | ||||
| 996 | tcp_out_ports="$tcp_out_ports,6667" # IRC | ||||
| 997 | tcp_out_ports="$tcp_out_ports,25,26" # SMTP | ||||
| 998 | tcp_out_ports="$tcp_out_ports,110" # POP3 | ||||
| 999 | tcp_out_ports="$tcp_out_ports,995" # POP3S | ||||
| 1000 | tcp_out_ports="$tcp_out_ports,143" # IMAP4 | ||||
| 1001 | tcp_out_ports="$tcp_out_ports,993" # IMAP4S | ||||
| 1002 | |||||
| 1003 | udp_out_ports="1194" # OpenVPN | ||||
| 1004 | udp_out_ports="$udp_out_ports,53" # DNS | ||||
| 1005 | udp_out_ports="$udp_out_ports,123" # NTP | ||||
| 1006 | |||||
| 2ccd2cae » | jwiegley | 2008-09-01 | 1007 | for (( index=0; index < intf_count; index++ )); do | |
| 1008 | netw=${networks[$index]} | ||||
| 1009 | intf=${interfaces[$index]} | ||||
| 6675eeda » | jwiegley | 2008-08-30 | 1010 | ||
| 2ccd2cae » | jwiegley | 2008-09-01 | 1011 | $IPFW add 11000 set 11 allow $logall \ | |
| 1012 | tcp from me to $netw $tcp_out_ports out via $intf setup keep-state | ||||
| 6675eeda » | jwiegley | 2008-08-30 | 1013 | ||
| 2ccd2cae » | jwiegley | 2008-09-01 | 1014 | $IPFW add 11100 set 11 allow $logall udp \ | |
| 1015 | from me to $netw $udp_out_ports out via $intf keep-state | ||||
| 6675eeda » | jwiegley | 2008-08-30 | 1016 | ||
| 2ccd2cae » | jwiegley | 2008-09-01 | 1017 | $IPFW add 11200 set 11 allow $logall tcp \ | |
| 1018 | from me to $netw out via $intf setup keep-state | ||||
| 1019 | $IPFW add 11210 set 11 allow $logall ip \ | ||||
| 1020 | from me to $netw out via $intf keep-state | ||||
| 1021 | |||||
| 1022 | if [[ $intf_count > 0 ]]; then | ||||
| 1023 | $IPFW set enable 11 | ||||
| 1024 | fi | ||||
| 1025 | done | ||||
| 6675eeda » | jwiegley | 2008-08-30 | 1026 | ||
| 1027 | |||||
| 1028 | ############################################################################## | ||||
| 1029 | # | ||||
| 1030 | # Set 20: Allowing specified inbound traffic | ||||
| 1031 | # | ||||
| 1032 | # Ports can be opened for inbound traffic using the following options | ||||
| 1033 | # when invoking this script: | ||||
| 1034 | # | ||||
| 1035 | # --trusted-tcp PORT[,PORT...] | ||||
| 1036 | # --local-tcp PORT[,PORT...] | ||||
| 1037 | # --tcp PORT[,PORT...] | ||||
| 1038 | # | ||||
| 1039 | # --trusted-udp PORT[,PORT...] | ||||
| 1040 | # --local-udp PORT[,PORT...] | ||||
| 1041 | # --udp PORT[,PORT...] | ||||
| 1042 | # | ||||
| 1043 | # These options can specified a group of ports separated by commas, such | ||||
| 1044 | # as "--tcp 80,443", or you can give the same option multiple times, | ||||
| 1045 | # such as "--tcp 80 --tcp 443". | ||||
| 1046 | # | ||||
| 1047 | # The default, if no options are given, is to allow nothing. | ||||
| 1048 | # | ||||
| 1049 | ############################################################################## | ||||
| 1050 | |||||
| 1051 | $IPFW set disable 20 | ||||
| 1052 | |||||
| 1053 | for (( index=0; index < intf_count; index++ )); do | ||||
| 1054 | netw=${networks[$index]} | ||||
| 1055 | intf=${interfaces[$index]} | ||||
| 1056 | |||||
| 1057 | if [[ ${trust[$index]} != false ]]; then | ||||
| 1058 | if [[ -n "$trusted_tcp_ports" ]]; then | ||||
| 1059 | $IPFW add $((20000 + index)) set 20 allow tcp $logall \ | ||||
| 1060 | from $netw to me $trusted_tcp_ports \ | ||||
| 1061 | in via $intf setup keep-state | ||||
| 1062 | fi | ||||
| 1063 | if [[ -n "$trusted_udp_ports" ]]; then | ||||
| 1064 | $IPFW add $((20020 + index)) set 20 allow udp $logall \ | ||||
| 1065 | from $netw to me $trusted_udp_ports \ | ||||
| 1066 | in via $intf keep-state | ||||
| 1067 | fi | ||||
| 1068 | fi | ||||
| 1069 | |||||
| 1070 | if [[ $netw != any || ${trust[$index]} != false ]]; then | ||||
| 1071 | if [[ -n "$local_tcp_ports" ]]; then | ||||
| 1072 | $IPFW add $((20100 + index)) set 20 allow tcp $logall \ | ||||
| 1073 | from $netw to me $local_tcp_ports \ | ||||
| 1074 | in via $intf setup keep-state | ||||
| 1075 | fi | ||||
| 1076 | if [[ -n "$local_udp_ports" ]]; then | ||||
| 1077 | $IPFW add $((20120 + index)) set 20 allow udp $logall \ | ||||
| 1078 | from $netw to me $local_udp_ports \ | ||||
| 1079 | in via $intf keep-state | ||||
| 1080 | fi | ||||
| 1081 | fi | ||||
| 1082 | |||||
| 1083 | if [[ -n "$public_tcp_ports" ]]; then | ||||
| 1084 | $IPFW add $((20200 + index)) set 20 allow tcp $logall \ | ||||
| 1085 | from $netw to me $public_tcp_ports \ | ||||
| 1086 | in via $intf setup keep-state | ||||
| 1087 | fi | ||||
| 1088 | if [[ -n "$public_udp_ports" ]]; then | ||||
| 1089 | $IPFW add $((20220 + index)) set 20 allow udp $logall \ | ||||
| 1090 | from $netw to me $public_udp_ports \ | ||||
| 1091 | in via $intf keep-state | ||||
| 1092 | fi | ||||
| 1093 | done | ||||
| 1094 | |||||
| 1095 | if [[ $intf_count > 0 ]]; then | ||||
| 1096 | $IPFW set enable 20 | ||||
| 1097 | fi | ||||
| 1098 | |||||
| 1099 | |||||
| 1100 | ############################################################################## | ||||
| 1101 | # | ||||
| 1102 | # Set 30: Reject ALL remaining packets, in or out | ||||
| 1103 | # | ||||
| 1104 | # Disabling this rule set will cause the default behavior to be to allow | ||||
| 1105 | # all packets not rejected by the above rules. | ||||
| 1106 | # | ||||
| 1107 | ############################################################################## | ||||
| 1108 | |||||
| 1109 | # Reject certain packets that seem to fly around with no purpose | ||||
| 1110 | $IPFW add 30000 set 30 $unreach_host_prohib $logall udp from any 53 to any in $via_all | ||||
| 1111 | $IPFW add 30010 set 30 $unreach_host_prohib $logall udp from any to any 53 in $via_all | ||||
| 1112 | |||||
| 1113 | # Deny all traffic in or out, but divide the log between packets | ||||
| 1114 | # inbound on known interfaces and all other packets | ||||
| 1115 | $IPFW add 30100 set 30 $unreach_filter_prohib $logall udp from any to any in $via_all | ||||
| 1116 | $IPFW add 30110 set 30 $unreach_filter_prohib log tcp from any to any in $via_all | ||||
| 1117 | $IPFW add 30120 set 30 $unreach_filter_prohib $logall all from any to any in $via_all | ||||
| 1118 | |||||
| 1119 | # Deny all outbound traffic reaching this point, and log it so we know | ||||
| 1120 | # what the machine was trying to do | ||||
| 1121 | $IPFW add 30200 set 30 $unreach_filter_prohib log all from any to any out $via_all | ||||
| 1122 | |||||
| 1123 | # Lastly, we simply drop it all. | ||||
| 1124 | $IPFW add 30300 set 30 $unreach_filter_prohib $logall all from any to any | ||||
| 1125 | |||||
| 1126 | |||||
| 1127 | ############################################################################## | ||||
| 1128 | # | ||||
| 1129 | # END: Inform the system that the firewall is now installed | ||||
| 1130 | # | ||||
| 1131 | ############################################################################## | ||||
| 1132 | |||||
| 1133 | logger -i -p daemon.notice -t firewall "firewall installed: $args" | ||||
| 1134 | |||||
| 1135 | # rc.firewall ends here | ||||







