@(#)Tuning Solaris for FireWall-1 v1.0 14 AUG 2000 Rob Thomas robt@cymru.com Tuning Solaris 7 for FireWall-1 4.0, by Rob Thomas Tuning Solaris for FireWall-1 by Rob Thomas Sun and Check Point have an intertwined history. Long resold as Solstice FireWall-1, it has become one of the most ubiquitous firewall packages in use today. While FireWall-1 on Solaris makes for a strong bastion, Solaris is not inherently tuned to provide filtering and routing services. This article will address some of the steps necessary to create an efficient and robust firewall. A Brief Introduction to FireWall-1 on Solaris Check Point FireWall-1 runs in kernel space on the Solaris platform. By inserting itself between OSI layer 2 and 3, Check Point captures and inspects all of the packets before the IP input routines (e.g. ipintr()) are called. If, based on the Check Point rule base, the packet is denied, it is dropped before traveling further up the stack. If the packet is allowed, it is passed further up the stack for processing. This processing is usually the routing of the packet out of another interface on the Solaris firewall. While Solaris includes a robust IP stack, it is not a platform built strictly for routing. Therefore, a fair bit of tuning is required to enhance the routing capabilities of Solaris. Regardless of the rule base, a FireWall-1 host is a router above all else, and should be tuned accordingly. It is important that the packets spend as little time as possible "inside" the firewall. It should be noted that the hardware platform makes a significant difference to the overall performance of the firewall. My tests have shown that a Sun E450, dual 200Mhz CPUs, 1GB RAM, a single QFE card, running Solaris 2.6 and Check Point FireWall-1 4.0 with a rule base containing 258 rules will provide throughput of 94.50 Mb/s without load, and throughput of 39.49Mb/s with a 100Mb/s load presented on two of the four interfaces. If your throughput requirements are considerably above these numbers, then you should consider the Nokia platform, specifically the Nokia IP650. More information about the Nokia firewall platform can be found at http://www.nokia.com/securitysolutions/. It is assumed that the reader is familiar with the operation of Check Point FireWall-1, as well as the basics of TCP/IP. For further Information on FireWall-1, visit http://www.checkpoint.com http://support.checkpoint.com/kb/ or PhoneBoy's FireWall-1 site at http://www.phoneboy.com/fw1/. For a deeper understanding of TCP/IP and the implementation of TCP/IP on UNIX, peruse _TCP/IP Illustrated, Volume 1_ by Richard Stevens and _TCP/IP Illustrated, Volume 2_ by Gary Wright and Richard Stevens. Tuning the IP Stack with ndd(1M) Our first set of tunings will be conducted using the ndd command. The ndd command, found in /usr/sbin under Solaris 7, allows us to peruse and modify the settings of the IP stack. These tunings will provide enhanced performance and a robust defense against the malcontents. These modifications should be placed in /etc/init.d/inetinit. I recommend placing them at the top of the file, surrounded by detailed comments. These commands can be run from the command line as well. The following, complete with comments, are the initial settings. # Do not forward directed broadcasts, e.g. Smurf attacks /usr/sbin/ndd -set /dev/ip ip_forward_directed_broadcasts 0 # Do not forward source routed packets /usr/sbin/ndd -set /dev/ip ip_forward_src_routed 0 # Do not respond to queries for our netmask /usr/sbin/ndd -set /dev/ip ip_respond_to_address_mask_broadcast 0 # Do not respond to broadcast ICMP_ECHO (ping) /usr/sbin/ndd -set /dev/ip ip_respond_to_echo_broadcast 0 # Do not respond to broadcasted timestamp queries /usr/sbin/ndd -set /dev/ip ip_respond_to_timestamp_broadcast 0 # Do not issue redirects -- fix the routing table instead /usr/sbin/ndd -set /dev/ip ip_send_redirects 0 # Don't let others modify our routing table /usr/sbin/ndd -set /dev/ip ip_ignore_redirect 1 # Increase our defense against SYN floods. # The "q" queue is the completed socket holding pen where sockets # remain until the application issues accept(). /usr/sbin/ndd -set /dev/tcp tcp_conn_req_max_q 1280 # The "q0" queue is the half-open socket queue. /usr/sbin/ndd -set /dev/tcp tcp_conn_req_max_q0 10240 If the firewall logging will be sent to a remote host, e.g. remote Enterprise Management Console, then additional enhancements should be included. Depend- ing on the rule base, the logging can be quite copious and create a bevy of TCP traffic between the firewall and the EMC. It is important to increase the efficiency of this TCP traffic, and this can be accomplished by enabling both RFC1323 and RFC2018 on both the firewall and the EMC. If the EMC host does not support RFC1323 and RFC2018, do not enable them on the Solaris firewall. These modifications should also be included in /etc/init.d/inetinit: # Increase the efficiency of TCP connections. See RFC1323 and # RFC2018 for more information. # Support SACK, RFC2018. /usr/sbin/ndd -set /dev/tcp tcp_sack_permitted 1 # Go with larger send and receive windows, RFC1323. /usr/sbin/ndd -set /dev/tcp tcp_xmit_hiwat 65535 /usr/sbin/ndd -set /dev/tcp tcp_recv_hiwat 65535 With the completion of the IP stack tuning, we are ready to proceed to the next step. Modifying the STREAMS Queues The Solaris 7 IP stack is based on STREAMS. This paradigm presents sig- nificant improvements and performance benefits. We will make only one en- hancement here. By increasing sq_max_size, we increase the number of message blocks (mblk) that can be in any given syncq. Several concurrent and large bulk trans- fers can quickly exhaust the default number of syncq message blocks. This will result in significantly decreased throughput through the firewall. This enhancement requires a bit of calculation. To determine the optimal size of the STREAMS queue, multiply 25 times every 64MB of RAM. For ex- ample, 64MB of RAM will yield 25. 128MB of RAM will yield 50. Insert the following (with your result in place of the number 25) in /etc/system. Remember that modifications to /etc/system require a reboot to take effect. * Increase STREAMS queues set sq_max_size = 25 Modifying the Behaviour of fsflush On firewalls, it is not at all uncommon to have quite a bit of physical memory. However, as the amount of physical memory is increased, the amount of time the kernel spends managing that memory also increases. During periods of high load, this may decrease throughput. To decrease the amount of memory fsflush scans during any scan interval, we must modify the kernel variable autoup. The default is 60. For fire- walls with 128MB of RAM or more, we shall increase this value by placing the following in /etc/system: * Decrease the amount of RAM scanned by fsflush set autoup = 120 The end result is less time spent managing buffers, and more time spent servicing packets. Blackholes Even the most robust security screens suffer from some weakness, and it is possible that someone will breach your network. These attacks may take the form of spoofed sources hitting your hosts, resulting in your end stations attempting to respond to these spoofed addresses. Fortunately, the script kiddies often utilize bogon networks, or networks that are not officially "allowed" on the Internet. We can utilize blackhole routes to block traffic to these bogon networks. It is likely that your FW-1 rule base is quite permissive with your internal hosts, perhaps allowing all traffic that originates within your network to go out to the Internet. The black hole routes ensure that traffic destined for the bogon networks will not pass the firewall, and will therefore leave your Internet link and screening router unscathed. Further, because the packet is simply dropped, the performance impact is quite low. To add a black hole route, we utilize the route command. Here is an example of a blackhole route for an RFC1918 network, 10/8. route add 10.0.0.0 -netmask 255.0.0.0 8.8.8.1 -blackhole Where 8.8.8.1 is the internal (intranet) IP address of our firewall. The result of this route addition is that the firewall will silently discard all packets destined for the RFC1918 network, 10/8. Be careful here, however! Do not add blackhole routes for networks that you utilize in- ternally. I recommend the following black hole routes, which should be added to the end of /etc/init.d/inetinit. Remember to replace 8.8.8.1 with the IP address of the internal interface of your firewall. route add 1.0.0.0 -netmask 255.0.0.0 8.8.8.1 -blackhole route add 2.0.0.0 -netmask 255.0.0.0 8.8.8.1 -blackhole route add 10.0.0.0 -netmask 255.0.0.0 8.8.8.1 -blackhole route add 172.16.0.0 -netmask 255.240.0.0 8.8.8.1 -blackhole route add 192.168.0.0 -netmask 255.255.0.0 8.8.8.1 -blackhole route add 192.0.2.0 -netmask 255.255.255.0 8.8.8.1 -blackhole route add 169.254.0.0 -netmask 255.255.0.0 8.8.8.1 -blackhole route add 240.0.0.0 -netmask 240.0.0.0 8.8.8.1 -blackhole If necessary (e.g. during an attack), other blackhole routes can be added in real time from the command line. Our tuning is now complete. It is wise to reboot at this stage to ensure that all of our changes have been applied and are working as expected. How is My Firewall Doing? Once your finely tuned firewall is in production, it is important to "health check" it from time to time. Fortunately, Solaris provides several commands that will make this possible. I will not cover the Check Point command set here. Please refer to the Check Point documentation for the Check Point command set. The first command to utilize is netstat -mv. This command will reveal the memory allocations to the various STREAMS buckets. Here is an example of the output: firewall# netstat -mv streams allocation: cumulative allocation current maximum total failures streams 197 231 606416 0 queues 502 555 1170440 0 mblk 809 7747 1314600 0 dblk_40 409 3444 417488125 0 dblk_72 118 868 63359226 0 dblk_136 50 126 21172406 0 dblk_328 222 3300 5742272 0 dblk_616 0 48 9556749 0 dblk_1096 2 70 68267716 0 dblk_1576 0 60 42263915 0 dblk_1992 0 6 13779515 0 dblk_2664 0 9 82229300 0 dblk_4040 0 2 22651 0 dblk_8136 0 7 73106 0 dblk_12232 0 1 951 0 dblk_esb 0 63 8609885 0 dblk_total 801 8004 732565817 0 linkblk 6 169 8 0 strevent 11 169 7340372 0 syncq 13 56 55709 0 qband 2 127 2 0 350 Kbytes allocated for streams data Watch for any number greater than zero in the "allocation failures" column of the dblk entries. This indicates resource exhaustion, and the possi- bility that the kernel does not have enough memory allocated to the stack. In this case, an increase in physical memory may be required. The output of netstat -k , where is a network interface such as qfe3, can be quite helpful as well. This largely undocumented feature re- quests interface statistics from the kstat interface in the kernel, as de- tailed in the driver specific includes in /usr/include/sys. One example would be /usr/include/sys/hme.h. Here is some sample output: firewall# netstat -k le0 le0: ipackets 9038375 ierrors 415 opackets 1502503 oerrors 1 collisions 103594 defer 131451 framing 0 crc 0 oflo 0 uflo 0 missed 415 late_collisions 0 retry_error 0 nocarrier 0 inits 67 notmds 0 notbufs 13711 norbufs 420553 nocanput 9387 allocbfail 0 rbytes 1467633274 obytes 479889547 multircv 13 multixmt 0 brdcstrcv 133133 brdcstxmt 4285 norcvbuf 9158 noxmtbuf 0 When reviewing this output, focus on the following fields: collisions - While the example above utilizes the LANCE Ethernet interface, the HME interface will support full duplex. Any routing device should be wired to a switch that supports full duplex operation. allocbfail - The number of times that the driver has been unable to allocate a STREAMS message block, e.g. a failure of a call to allocb(). Verify the errors with the output of netstat -mv. It may be necessary to increase the amount of physical RAM in the firewall. nocanput - The number of times the driver could not send packets upstream due to a full STREAMS queue. The name comes from the canput() call. This can be resolved by increasing the sq_max_size parameter. notbufs - This indicates an exhaustion of the transmit buffers in the NIC driver. norbufs - This indicates an exhaustion of the receive buffers in the NIC driver. If the notbufs or norbufs variables are significant, then the driver is over- burdened and can't keep pace with the traffic. It will be necessary to de- crease the network load on the firewall. With the output of netstat -s, you can actually monitor the amount of traf- fic the firewall is forwarding. Here is an edited sample containing only the IP statistics: IP ipForwarding = 1 ipDefaultTTL = 255 ipInReceives =3886887 ipInHdrErrors = 0 ipInAddrErrors = 0 ipInCksumErrs = 0 ipForwDatagrams =3716846 ipForwProhibits = 89 ipInUnknownProtos = 0 ipInDiscards = 0 ipInDelivers =171327 ipOutRequests = 86170 ipOutDiscards = 0 ipOutNoRoutes = 0 ipReasmTimeout = 60 ipReasmReqds = 4 ipReasmOKs = 4 ipReasmFails = 0 ipReasmDuplicates = 0 ipReasmPartDups = 0 ipFragOKs = 4 ipFragFails = 0 ipFragCreates = 8 ipRoutingDiscards = 0 tcpInErrs = 0 udpNoPorts = 22 udpInCksumErrs = 0 udpInOverflows = 0 rawipInOverflows = 0 Here we can see that this firewall has forwarded 3716846 datagrams out of 3886887 datagrams received. There have been few errors of note. However, if errors do occur, examine the TCP and UDP portions of the netstat -s out- put for details regarding the error types. Conclusion Providing firewall services is not a trivial task. With a few modifications and careful monitoring, a Solaris box can be configured to provide robust and secure routing for enterprise networks. Rob Thomas, robt@cymru.com http://www.cymru.com