|
Building a FreeBSD FirewallIntroductionA firewall is a computer that monitors traffic between two networks. Firewalls are generally used to restrict access to computers on private networks from external networks such as the global Internet. A computer that runs as a firewall is basically a glorified router. A normal router would route two networks by directing packets from one network to the other. A packet filtering router is one that examines the packets before letting them through. Packet filtering routers can decide whether to allow or deny access based on source and destination address, or the source and destination port number, or the type of protocol used (TCP, UDP, ICMP). The goal of this article is to build a firewall based on FreeBSD 4. 1. Kernel ConfigurationThe /sys/i386/config/LOCAL file. Enable IPv4 networking, but disable IPv6: options INET # InterNETworking #options INET6 # IPv6 communications protocolsStrict IP networking: options TCP_DROP_SYNFIN # drop TCP packets with SYN+FIN options TCP_RESTRICT_RST # restrict emission of TCP RST options ICMP_BANDLIM # rate limit ICMP repliesEnable firewalling code: options IPFIREWALL # firewall options IPFIREWALL_VERBOSE # print information about dropped packets #options IPFIREWALL_FORWARD # enable transparent proxy support options IPFIREWALL_VERBOSE_LIMIT=100 # limit verbosity #options IPFIREWALL_DEFAULT_TO_ACCEPT # allow everything by default options IPDIVERT # divert(4) sockets for NATDisable loadable kernel modules (security issues): options NO_LKMDisable BPF devices, used by tcpdump and other network sniffers: # The `bpf' pseudo-device enables the Berkeley Packet Filter. #pseudo-device bpf #Berkeley packet filterAnd remove all unused device drivers. Use dmesg to see which ones are in use, and only keep those. Comment out all the others. Rebuild a kernel with: # config LOCAL # cd /sys/compile/LOCAL # make depend && make && make install 2. Networking ConfigurationThe /etc/rc.conf file. This machine is a router: gateway_enable=YES forward_sourceroute=NO accept_sourceroute=NONo-frills TCP: tcp_extensions=NO tcp_keepalive=YES tcp_drop_synfin=YES tcp_restrict_rst=YESTight ICMP control: icmp_bmcastecho=NO icmp_drop_redirect=YES icmp_log_redirect=YES Marc Falesse <marc.falesse@libertysurf.fr> also recommends adding the following to /etc/sysctl.conf: net.inet.tcp.blackhole=2 net.inet.udp.blackhole=1 net.inet.tcp.log_in_vain=1 net.inet.udp.log_in_vain=1A backhole port is a closed port that never responds, not even to say it's closed. This gives out even less information to port scanners such as nmap and slows them down. The log_in_vain options are used to trigger logging of those events, i.e.
it allows packets destined for non-listening ports on a server to be logged to syslog. (Note that
this may open your firewall to a DoS attack by flooding it with bogus packets. On the other hand, this
may alert you of an ongoing portscan.)
3. Services ConfigurationAll unnecessary services should be disabled by default, and troublesome binaries deleted from the filesystem altogether (particularly named, sendmail, and gcc). portmap_enable=NO sendmail_enable=NO named_enable=NOSyslog is very useful on a firewall but we must close it to external DoS attacks: syslogd_enable=YES syslogd_flags="-ss"But keep the essentials: sshd_enable=YES xntpd_enable=YES 3.1. InetControls many other services, e.g. FTP, telnet, etc. Best to remove it entirely with: inetd_enable=NOAnother possibility is to have run on the internal interface only: # bind inetd to the internal interface only inetd_enable=YES inetd_flags="$inetd_flags -l -a interface_address"If you do decide to leave inetd running anyway, then make sure to enable logging and to increase the number of times a service can be invoked in one minute. (The default is 256, I recommend 1024 - adjust it yourself as you see fit). If you are connecting with a slow link (a modem for example), this will not matter, but if you have a fast connection this "feature" can be used to create a DoS (Denial of Service) attack. Someone can create a simple shell script to invoke more then 256 connections to your computer which will cause your inetd service to shut down. On the other hand, if you want to support 1024 simultaneous connection to your box make sure you have hardware to support that. Or else someone can also cause DoS and crash your computer by opening 1024 telnet connections at one time. Hence, in the file /etc/rc.conf the line right below: inetd_enable=YES inetd_flags="-l -R 1024"this will turn on logging (-l switch) and increase maximum connection number to 1024 from the default 256. You will also need to change your syslog.conf file in /etc directory. 3.2. NTP Time ProtocolNTP is a time protocol used to synchronize a computer to an external clock. The firewall can be used to broadcast time announcements to the internal network, keeping the correct time on all machines. Enable NTP in the configuration file with: xntpd_enable=YESFind below a sample NTP configuration file for a host located in California. # # NTP configuration file (ntpd) # ################### # global options # file storing permanent clock parameters driftfile /var/db/ntp.drift # default permission is to deny everything restrict default ignore # except from localhost restrict 127.0.0.1 ################# # time servers # ntp.pbi.net server 206.13.7.12 prefer restrict 206.13.7.12 nomodify noquery # ns.scruz.net server 165.227.1.1 restrict 165.227.1.1 nomodify noquery # ntp.ucsd.edu server 132.239.254.5 restrict 132.239.254.5 noquery nomodify # time.five-ten-sg.com server 205.147.40.50 restrict 205.147.40.50 noquery nomodify # ntp2.mainecoon.com server 63.192.96.3 restrict 63.192.96.3 noquery nomodify ################ # time service # broadcast time to local networks broadcast 10.1.255.255 Ntpd Configuration
4. Security LevelsEnabling security levels will slow down an attacker by preventing him from tampering with system files. Set the immutable flag on all system binaries with: # zsh # chflags schg /bin/*(*) /sbin/*(*) /usr/bin/*(*) /usr/sbin/*(*)Enable security levels with: # use security levels kern_securelevel_enable=YES kern_securelevel=3The kernel runs with four different levels of security. Any super-user process can raise the security level, but no process can lower it. The security levels are:
Secure levels are so powerful that they might get in the way of the system administrator; enable only on a production machine which configuration does not evolve anymore. 5. Network Address TranslationNatd, a userland program, is used to multiplex and demultiplex connections from internal hosts to the external network, acting as a "masquerading router" for the internal network. Enable NAT with: natd_enable=YES # Enable natd (if firewall_enable == YES) natd_interface=eth0 # Public interface or IP address to use natd_flags="–log_denied –use_sockets"Natd uses a divert socket to intercept the packet flow and perform the address translation: /sbin/ipfw add divert natd all from any to any via eth0After translation by natd, packets re-enter the firewall at the rule number following the rule number that caused the diversion (not the next rule if there are several at the s ame number). Because natd is a userland program, its use is not without impacting performance! 6. IP Filtering6.1. How It WorksEach packet that is destined for a host located behind the firewall is compared to a set of rules. Every packet filtering router must have a default rule that denies or allows all traffic to pass. When a packet arrives at the firewall, it will be compared to a "rule chain", a set of rules that describes which types of packets are allowed or not allowed. If the packet doesn't match any of the rules in the chain, the default accept or deny rule will be used. In other words, all packets go through the rules list, starting at the top (the lowest-numbered rule), to the bottom (the highest-numbered rule, which describes the default behavior). A packet is matched against each rule till one rule matches. This match decides what whether the packet is allowed through or dropped. Only the first match matters; once a packets matched a rule, its fate is decided and the processing of that packet terminates. Every packet potentially goes through the entire ruleset. Crafting the ruleset intelligently, i.e. ordering rules by match probability, minimizes the processing done for each packet. Ideally the most common packets should be matched at the very beginning of the ruleset. 6.2. TCP/IP BackgroundAn IP connection is a 5-tuple: [protocol, IP-source-address, IP-destination-address, source-port, destination-port] At least one element of the tuple must be different to identify a new connection. In other words, two connections cannot exist on the network that share these identifiers. 6.2.1. ICMPError and testing protocol.
ICMP Message Types
6.2.2. UDP = connection less
6.2.3. TCP = connection oriented protocol
Connection-oriented protocols necessitate the establishment of a connection. A TCP connection is created with special TCP packets, using TCP options such as SYN, FIN, RST, URG, ACK, PSH. A connection progresses through a series of states during its lifetime. The states are: LISTEN, SYN- SENT, SYN-RECEIVED, ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, LAST-ACK, TIME-WAIT, and the fictional state CLOSED. CLOSED is fictional because it represents the state when there is no connection. Briefly the meanings of the states are:
A TCP connection progresses from one state to another in response to events. The events are the user calls, OPEN, SEND, RECEIVE, CLOSE, ABORT, and STATUS; the incoming segments, particularly those containing the SYN, ACK, RST and FIN flags; and timeouts. For example, this is the diagram for opening a connection:
TCP A TCP B
1. CLOSED LISTEN
2. SYN-SENT --> [SEQ=100][CTL=SYN] --> SYN-RECEIVED
3. ESTABLISHED <-- [SEQ=300][ACK=101][CTL=SYN,ACK] <-- SYN-RECEIVED
4. ESTABLISHED --> [SEQ=101][ACK=301][CTL=ACK] --> ESTABLISHED
5. ESTABLISHED --> [SEQ=101][ACK=301][CTL=ACK][DATA] --> ESTABLISHED
Basic 3-Way Handshake for Connection Synchronization
Notice how the SYN bit is set on the first packet, then SYN+ACK on the second packet, resulting in a connection being in the ESTABLISHED state. All following packets have the ACK bit set. FIN and RST packets are used to terminate a TCP connection. 6.3. Firewall ConfigurationEnable firewall in /etc/rc.conf: firewall_enable=YES firewall_type=/usr/local/etc/firewall_rules firewall_quiet=YES firewall_flags="-p cpp \ -D INT_IF=eth0 \ -D INT_ADDR=192.168.1.1 \ -D INT_NET=192.168.0.0/24 \ -D EXT_IF=eth1 \ -D EXT_ADDR=207.238.131.190 \ -D EXT_NET=207.238.131.180/27 \ more options... "Create your own rules file to store site configuration. The files implementing this configuration are also available separately. 6.3.1. Firewall StatementsSome things to watch out for. The ipfw filter list (the ruleset) may not be modified if the system security level is set to 3 or higher (see init(8) for information on system security levels). Packets are filtered both going in and coming out. Most connections need packets going in both directions. Remember that ipfw rules are checked both on incoming and outgoing packets.
The via keyword causes the interface to always be checked. If recv or xmit is used instead of via, then the only receive or transmit interface (respectively) is checked. By specifying both, it is possible to match packets based on both receive and transmit interface, e.g.: ipfw add 100 deny ip from any to any out recv ed0 xmit ed1The recv interface can be tested on either incoming or outgoing packets, while the xmit interface can only be tested on outgoing packets. So out is required (and in is invalid) whenever xmit is used. Specifying via together with xmit or recv is invalid. A packet may not have a receive or transmit interface: packets originating from the local host have no receive interface, while packets destined for the local host have no transmit interface. Other options worth noting:
6.3.2. Firewall RulesA first and efficient way to limit access is the use of the following rules: ipfw add allow tcp from any to any established ipfw add allow tcp from net1 portlist1 to net2 portlist2 setup ipfw add allow tcp from net3 portlist3 to net3 portlist3 setup ... ipfw add deny tcp from any to anyThe first rule will be a quick match for normal TCP packets, but it will not match the initial SYN packet, which will be matched by the setup rules only for selected source/destination pairs. All other SYN packets will be rejected by the final deny rule. 6.4. An ipfw PrimerSome useful tips to manage the ruleset.
Ipfw Commands
Here is how to temporarily disable the entire filter: # ipfw add 1001 allow all from any to any # (tests...) # ipfw del 1001We insert this rule at number 1001, right after the diversion command to natd. Edit the rules file /usr/local/etc/firewall_rules then reload it with: # source /etc/rc.firewallThis is better done at the console, since a mistake in the rules can easily lock you out of the system. 6.5. Firewall Rules File /usr/local/etc/firewall_rulesThe complete version of this file is also available. 6.5.1. IP LevelFirst filter out all the bogus packets at the external interface. This is an optimization for natd: all packets that do not belong on this system are filtered out first. 00100 skipto 500 ip from any to EXT_ADDR in recv EXT_IF 00400 deny ip from any to any in recv EXT_IFHand off packets to natd. They will be reinjected with the address translation done, after this rule. 01200 divert natd ip from any to any via EXT_IFEnsure that packets are really going where they should (no spoofing allowed here): 01400 deny ip from INT_NET to any in recv EXT_IF 01400 deny ip from EXT_NET to any in recv INT_IFStop martians at the outside interface (RFC1918), both from being received and being sent: 01500 deny ip from 192.168.0.0/16 to any in recv EXT_IF 01500 deny ip from any to 192.168.0.0/16 out xmit EXT_IF 01500 deny ip from 172.16.0.0/12 to any in recv EXT_IF 01500 deny ip from any to 172.16.0.0/12 out xmit EXT_IF 01500 deny ip from 10.0.0.0/8 to any in recv EXT_IF 01500 deny ip from any to 10.0.0.0/8 out xmit EXT_IFAllow this host to communicate with the internal network: 02100 allow ip from INT_NET to INT_NET via any 6.5.2. TCP ConnectionsAllow all established connections: 07000 allow tcp from any to any establishedBy allowing all established connections, we now only need to look at connection setups. Allow outgoing TCP setups from the local host, and from the private network: 07100 allow tcp from EXT_ADDR to any out xmit EXT_IF setup 07200 allow tcp from INT_NET to any in recv INT_IF setupThis machine runs a SMTP server. Allow data to flow to/from it. 07500 allow tcp from any to EXT_ADDR smtp setupAllow and log SSH connections: 07600 allow log tcp from any to EXT_ADDR ssh setupReject & log all setup of incoming connections from the outside. Be aware that this may open the firewall to DoS attacks by flooding. 08000 reset log tcp from any to any in recv EXT_IF setupThat should be all for TCP. 6.5.3. UDP ConnectionsAllow DNS requests: 08100 allow udp from any domain to EXT_ADDR 08200 allow udp from EXT_ADDR to any domainAllow NTP packets to/from the firewall: 08500 allow udp from any 123 to EXT_ADDR ntp in recv EXT_IF 08600 allow udp from EXT_ADDR 123 to any ntp out xmit EXT_IFand to the local network: 08700 allow udp from INT_ADDR ntp to any ntp out xmit INT_IFReject & log UDP packets trying to sneak in through the external interface: 08900 unreach port log udp from any to any in recv EXT_IFOr just use "deny" instead of "unreach port". 6.5.4. ICMP PacketsVery important! ICMP is an essential component of the TCP/IP stack that cannot be entirely filtered out. Safest choice is to allow everything, although this may open to ICMP fingerprinting and network scanning. To/from the firewall: 10000 allow icmp from EXT_ADDR to any 10100 allow icmp from any to EXT_ADDRto/from the internal network: 10200 allow icmp from INT_NET to any 10300 allow icmp from any to INT_NETA more restrictive choice that still allows ping & traceroute from the firewall and the internal network would be: allow udp from EXT_ADDR to any 33434-33534 allow udp from INT_NET to any 33434-33534 allow icmp from EXT_ADDR to any icmptype 0,3,4,8,11,12 allow icmp from any to EXT_ADDR icmptype 0,3,4,8,11,12 allow icmp from INT_NET to any icmptype 3,4,8,11,12 allow icmp from any to INT_NET icmptype 0,3,4,11,12At the very least message types 3, 4, 11 and 12 must be allowed: allow icmp from EXT_ADDR to any icmptype 3,4,11,12 allow icmp from any to EXT_ADDR icmptype 3,4,11,12 allow icmp from INT_NET to any icmptype 3,4,11,12 allow icmp from any to INT_NET icmptype 3,4,11,12You may want to finish with: unreach filter-prohib icmp from any to any in recv EXT_IFor: deny icmp from any to any in recv EXT_IF 7. TestingGenerates copious outputs to the log files!! For natd: natd_flags += -verboseFor the IP filtering code: sysctl -w net.inet.ip.fw.verbose=1 About the authorRenaud Waldura is a freelance consultant specializing in Internet applications. With a Master's in Software Engineering and 7 years of experience in the business, Renaud is able to tell a good piece of software when he sees one: FreeBSD is one of them. Visit Renaud's Web site at http://renaud.waldura.com/ to learn more about how he can help you with your business. Copyright © 2000-2007 by Renaud Waldura. Permission to make digital or hard copies of part or all of this work for personal or classroom use is granted without fee, provided that copies are not made or distributed for profit or commercial advantage, and that copies bear this notice and full citation on the first page. Copyright for components of this work owned by others than Renaud Waldura must be honored. Abstracting with credit is permitted. To copy otherwise, to republish, to post on servers, or to redistribute to lists, requires prior specific permission and/or fee. Request permission to publish from renaud@waldura.com. Last modified: 2002/10/30 17:35:05 $ |