Running a Proxy-Arp LVS-NAT Director/Firewall with Keepalived

(C) 2003 Vince Worthington, released under GPL


How to have one Linux box be your LVS-NAT director with Keepalived, and be a Proxy-Arp firewall/gateway with Stateful Inspection too.

Last Revised: 05/15/2003 (Document is Still In Development/Beta Status)

The most recent revision of this document should always be available at our website, with the following direct URL:

http://www.lvwnet.com/vince/linux/Keepalived-LVS-NAT-Director-ProxyArp-Firewall-HOWTO.html

1. Introduction

Keepalived - At the Center of our Linux Virtual Server Setup

Keepalived is a powerful virtual server manager package written in C by Alexandre Cassen, which works with the IPVS/Linux Virtual Server (LVS) software and kernel patches. Keepalived can create, monitor, and manage virtual services on your LVS Director, and is also well-suited to running a redundant pair (or group) of directors, via its implementation of the VRRPv2 Virtual Router Redundancy Protocol.

Keepalived uses native kernel netlink functions to dynamically manage VIP's and routes on the Directors, rather than the old-style IP/interface aliases (ie, eth0:0, eth0:110, etc.). So having multiple IP/VIP addresses per interface is not a problem, and you don't run into problems trying to write iptables rules for an "interface" whose name has a ':' in it, either.

When a failover to a different master director occurs, keepalived on the new master takes over the VIP's and routes from the failed master, and sends out gratuitous ARP messages for the VIP's it has taken over. Keepalived also supports IPVS Connection Synchronization between Directors, so transition at point of failover is rapid, and the LVS Real Servers start using the new master Director with hardly even a hiccup.

Making the LVS Director pair a Stateful Firewall

Extending upon the functionality provided by Keepalived itself, with some additional work, it is possible to create a highly-available LVS-NAT Director pair which also functions as the primary firewall/gateway for a network of servers and hosts -- even a "mixed DMZ" containing some LVS Real Servers, (where the VIP's are actually on the director), and other hosts which have routable IP's themselves, and only need the director/firewall to route and netfilter their traffic, without performing any LVS or NAT tricks on it.

Proxy Arp
We will use the Proxy Arp facility of the Linux kernel to cause the Master Director to answer ARP requests for routable hosts on both "sides" of the director/firewall (DMZ and ISP gateway), and therefore route and filter their traffic through the firewall. While using Proxy Arp can be most helpful when you want a "hidden firewall", it still has advantages which are not diminished by having IP's defined on its interfaces.

Because we are running a Proxy Arp setup, we will make use of the tcp_nonlocal_bind ip sysctl, and the arping utility (from the iproute2 utils) in a notify_master script. This script will deal with updating our DMZ hosts (and our ISP's gateway) with the newly-elected MASTER Director's MAC addresses when a failover occurs, so that our DMZ hosts will not experience a loss of connectivity to the internet. We need to do this because Keepalived does not send gratuitous arps for addresses it hasn't taken over.

Return of the Antefacto Patch
With the help of an additional patch to the IPVS and linux (2.4-series) kernel sources called the "Antefacto" patch (documented in the LVS-HOWTO, section 21 or so), we will reacquire the ability to run an iptables firewall rule set on the Director which performs Stateful Inspection of ALL traffic moving through the firewall -- even traffic to/from LVS RealServers. So it is no longer necessary for your LVS Director and your main firewall to be on separate boxes -- The Antefacto patch adds enough netfilter connection state tracking support to IPVS to allow netfilter to be aware of IPVS-managed connections.

With some very helpful information from Ben North, I have managed to hand-fit the Antefacto patch into the 2.4.19 kernel and IPVS v1.0.7 source code, and come up with a modified IPVS v1.0.7 Single Kernel Patch for kernel 2.4.19 which has the Antefacto code in it. I've been running a Director/Firewall for over 3 weeks with this code, and all is working well, and as expected. Apparently this will be available now in some way as a contrib feature for the IPVS source code. Since my programming skills are not very good, if the IPVS or Kernel sources change drastically at some point in the future, maintenance of the Antefacto patch to bring its functionality forward into those kernel/IPVS sources may need to be done by others. I'll be glad to host/distribute any updates here. If only Antefacto could be merged into the main IPVS source code...

I have included a basic sample iptables firewall script near the end of this HOWTO.

NOTE about the Antefacto patch:
To this point, neither Ben North nor I have been able to test IPVS patched with Antefacto on an SMP machine. (My director/firewall boxes are older UP boxes).

Ben said that at one time, there was apparently potential in IPVS for a race condition with this patch, but there was code added to handle it, and he does not know if it is even an issue anymore. Ben said he believes the code is solid, but cautioned me that it has not been tested on an SMP machine. Any info from testers with SMP machines would probably be very welcome, and I suspect that multiple success stories may help the Antefacto patch get merged into the main IPVS source code distribution.

2. Setting it up

Hardware Requirements and Notes

To build a box according to this HOW-TO, you will need:

Software you will need

Note: As a general practice, you should rebuild iptables any time you are building a new kernel from fresh kernel sources, since all but a few of the iptables pending, extra, or other patches are patches against the kernel source you are working with. I also recommend NOT using the pre-compiled iptables package(s) distributed with many Linux distributions, since they are built against against the pre-compiled KERNELS also distributed with them. Your iptables binaries and libraries need to stay in sync with the kernel sources they were built with - if you build a kernel with fresh kernel sources, you need to build/rebuild iptables too.

REAL penguins build their own kernels and binaries!

Assumptions made

The assumption is made that you are already familiar/comfortable with typical Linux system/network administrative tasks and customization, such as: Any of these subjects are beyond the scope of this document, or my ability to provide any support for. Excellent documentation is already available elsewhere. ;)

I will document any of the above that needs to be done a certain way for things to work according to this HOWTO, but otherwise, the standard documentation for the software packages involved applies. Please refer to their documentation or support mechanisms (web pages, mailing list archives, etc.).

Also, I have included a section below which documents the kernel configuration options I have used for our Director/Firewall boxes.

Anyway, let's move on to getting the keepalived director set up.

General Plan for Building the Setup

1. Unpack the 2.4.19 kernel source tarball somewhere

2. Fix /usr/src/linux symlinks (and kernel headers symlinks if you use them) to point to the new kernel source tree

3. cd into the dir you unpacked your new kernel source tree, and 'make mrproper'

4. (optional) copy your previous 2.4-series custom kernel's .config file and edit out the netfilter options (see tips below), then run 'make oldconfig'.

5. Patch the kernel source with the IPVS v1.0.7/Antefacto single kernel patch

6. Unpack the iptables source tree somewhere

7. (optional) Unpack iptables patch-o-matic and run it to add any iptables/netfilter patches you want/need

8. Build and install iptables

9. Configure the kernel (ie, 'make menuconfig'), selecting any options you want/need. See LVS HOWTO for options you have to have enabled for the type of LVS setup you will run.

10. Build and install the kernel. Keep a known-good kernel available, and don't forget to update your lilo/grub configuration!

11. Reboot with new kernel.

12. (optional) Build and install ipvsadm v1.2.1

13. Build and install keepalived.

When you get past Step 13, you should be almost ready get keepalived running.

Building the Kernel for the Director/Firewall

Any kernel-building trickery you normally employ can of course be applied.

A Couple of Free Kernel Building Tips:

1. Use the .config file from your last customized kernel
If you already have a custom-built 2.4.19 (or earlier 2.4-series) kernel, you can save yourself the time and hassle of manually configuring every kernel option you need. This may also help you avoid the risk of forgetting to set something you need to get this server booted up properly, like filesystem or storage hardware support the server needs.

Copy the .config file from that kernel's source tree into the fresh 2.4.19 source tree, and run "make oldconfig" on it. You will only be prompted for "new" (non-existent) options, and the others will retain their original settings. Just make sure you WAIT to do this trick until AFTER you have run 'make mrproper' on the new source tree, since mrproper removes any .config file that exists in the top level directory!

After this, you can run through and check everything out (ie, make sure you didn't forget something) with the usual 'make menuconfig' before you compile.

2. How to reset your old kernel's .config file netfilter options when that kernel had extra options from iptables patch-o-matic
This is VERY useful when building new kernel versions on firewall boxes.

Since you will be building/rebuilding iptables from scratch because of the new kernel version, if your old kernel had any netfilter kernel options added by netfilter patch-o-matic (pending, extra, or otherwise), you can "reset" your old .config file netfilter options back to only having what comes with the new kernel. You want to do this AFTER you have copied the other kernel's .config file into the new source tree, but BEFORE you run 'make oldconfig' (or build iptables, run patch-o-matic, or start configuring kernel options). Here's what to do:

Open your .config file with your favorite text editor, and search for the section that reads:

#
# IP: Netfilter Configuration
#

When you find it, carefully delete ALL lines immediately below it (commented out or not) that start with 'CONFIG_IP_NF_'. This should take you right down to CONFIG_IPV6 and CONFIG_KHTTPD. Save the file, and then run 'make oldconfig'. You will have to answer Y/N/M for each of the netfilter options, but when you're done, you won't have orphaned netfilter options in your .config file for which no patches exist, and then you can add back the options you want when you run patch-o-matic and configure the kernel with 'make menuconfig' (or whatever you prefer to use to configure the kernel options).

3. EXTRAVERSION setting in the kernel top-level directory Makefile
Many people know about this trick already, but it's still a good trick.

By setting something unique in the EXTRAVERSION field of the main Makefile in a kernel source tree (maybe "lvs-test1") prior to compilation, the newly-compiled kernel will have that string appended to its version number (such as the output you would get from a 'uname -r' command), and 'make modules_install' will install the kernel modules under a separate dir with that string in its name under /lib/modules (example: /lib/modules/2.4.19lvs-test1). So if you want to build an experimental kernel to test out some option, and not overwrite your existing (and known-working) previous kernel and modules, setting/changing the value of EXTRAVERSION before you build the kernel is an easy way to do it, and will allow you to have multiple kernels built from a single kernel source tree.

Now to be fully scientific in your experimentation, you may want to make a backup copy of your .config file (maybe to something with the EXTRAVERSION string in its filename) before you run 'make menuconfig' for your next experimental kernel, so that you have a copy of the .config file that produced each kernel. I usually name the bzImage files I copy to /boot after the EXTRAVERSION too. (example: /boot/vmlinuz-2.4.19lvs-test1)

Example of Kernel Configuration Options for a Firewall/Director

This is what my Linux 2.4.19 kernel config options look like, for Networking Options, Netfilter options, and IPVS options. Not all items selected are required for LVS/IPVS to function properly, or to accomplish what we are doing with this HOWTO. But with these options selected on my Director/Firewall boxes, it works for me.

Also, you will see some extra options in my list of Netfilter options that aren't in your list -- these came from running iptables' patch-o-matic to add them in. The extra options listed do not conflict with each other, but adding other extras may possibly cause conflicts.

Usually you will know if a certain patch-o-matic optional patch will "work out" or not by selecting the Test (t) option to see if it can successfully patch against your kernel source. But be careful!!! There are one or two patches I know of that will TEST OK, and even apply cleanly -- yet produce an uncompilable kernel if you pick them in combination with certain other patches!

A good general rule to follow when you are picking extra netfilter options is to only pick the ones you need. There is documentation out there as to which options don't get along with each other - some can be found with patch-o-matic itself, and more can also be found on the netfilter website and mailing list archives.


Again, not all of the Netfilter options selected are required for LVS/IPVS, or to accomplish what we are doing with this example. But this is a snapshot of the Networking and Netfilter kernel configuration options from a known-stable, live firewall box.

NOTE: You won't have the IPVS options available until you apply the IPVS kernel patch.


Networking Options

<*> Packet socket
[*] Packet socket: mmapped IO
< > Netlink device emulation
[*] Network packet filtering (replaces ipchains)
[ ] Network packet filtering debugging
[ ] Socket Filtering
<*> Unix domain sockets
[*] TCP/IP networking
[*] IP: multicasting
[*] IP: advanced router
[*] IP: policy routing
[*] IP: use netfilter MARK value as routing key
[*] IP: fast network address translation
[*] IP: equal cost multipath
[ ] IP: use TOS value as routing key
[*] IP: verbose route monitoring
[ ] IP: large routing tables
[ ] IP: kernel level autoconfiguration
<*> IP: tunneling
<*> IP: GRE tunnels over IP
[ ] IP: broadcast GRE over IP
[*] IP: multicast routing
[*] IP: PIM-SM version 1 support
[*] IP: PIM-SM version 2 support
[ ] IP: ARP daemon support (EXPERIMENTAL)
[ ] IP: TCP Explicit Congestion Notification support
[*] IP: TCP syncookie support (disabled per default)
IP: Netfilter Configuration --->
IP: Virtual Server Configuration --->
< > The IPv6 protocol (EXPERIMENTAL)
< > Kernel httpd acceleration (EXPERIMENTAL)
[ ] Asynchronous Transfer Mode (ATM) (EXPERIMENTAL)
<M> 802.1Q VLAN Support
---
< > The IPX protocol
< > Appletalk protocol support
Appletalk devices --->
< > DECnet Support
< > 802.1d Ethernet Bridging
< > CCITT X.25 Packet Layer (EXPERIMENTAL)
< > LAPB Data Link Driver (EXPERIMENTAL)
[ ] 802.2 LLC (EXPERIMENTAL)
[ ] Frame Diverter (EXPERIMENTAL)
< > Acorn Econet/AUN protocols (EXPERIMENTAL)
< > WAN router
[ ] Fast switching (read help!)
[ ] Forwarding between high speed interfaces
QoS and/or fair queueing --->
Network testing --->


IP: Netfilter Configuration

<*> Connection tracking (required for masq/NAT)
<*> FTP protocol support
< > IRC protocol support
< > Userspace queueing via NETLINK (EXPERIMENTAL)
<*> IP tables support (required for filtering/masq/NAT)
<*> limit match support
<M> MAC address match support
<*> Packet type match support (EXPERIMENTAL)
<*> netfilter MARK match support
<M> Multiple port match support
<M> TOS match support
<*> psd match support
<*> AH/ESP match support
<*> LENGTH match support
<*> TTL match support
<M> tcpmss match support
<*> Connection state match support
<*> Connections/IP limit match support
<M> Unclean match support (EXPERIMENTAL)
<M> Owner match support (EXPERIMENTAL)
<*> Packet filtering
<*> REJECT target support
<*> MIRROR target support (EXPERIMENTAL)
<*> Full NAT
<*> MASQUERADE target support
<*> REDIRECT target support
[ ] NAT of local connections (READ HELP)
< > Basic SNMP-ALG support (EXPERIMENTAL)
<*> Packet mangling
<*> TOS target support
<*> MARK target support
<*> LOG target support
<*> TTL target support
< > ULOG target support
<M> TCPMSS target support
<M> ARP tables support
<M> ARP packet filtering


IP: Virtual Server Configuration

<*> virtual server support (EXPERIMENTAL)
[*] IP virtual server debugging
(14) IPVS connection hash table size (the Nth power of 2) <--- (NOTE: 16,384 connections)
--- IPVS scheduler
<M> round-robin scheduling
<M> weighted round-robin scheduling
<M> least-connection scheduling scheduling
<M> weighted least-connection scheduling
<M> locality-based least-connection scheduling
<M> locality-based least-connection with replication scheduling
<M> destination hashing scheduling
<M> source hashing scheduling
--- IPVS application helper
<M> FTP protocol helper

NOTE: On our setup, our FTP server is one of the DMZ hosts with its own routable IP address, it is not LVS'd.

3. An Example Working Configuration

Introductory Info

Throughout this example, eth0 is the internal network interface, and eth1 is the external interface, as viewed from each host. "Internal" means "looking towards the inside of our network", and "external" means "looking out towards the Internet".

On the Director boxes, eth0 is for the DMZ, and eth1 connects to our ADSL CPE.

On the Real Servers, eth0 is for talking to our backend servers and internal hosts (on a different subnet), and eth1 is for the DMZ. (Our Real Servers do not forward any traffic between interfaces).

I set up an Untagged VLAN with 3 of the ports on our 3Com managed ethernet switch, one port for the ethernet interface on our ADSL bridge modem, and one port for the eth1 interface on each Director/Firewall. This keeps traffic which has not cleared our firewall segmented from the rest of the network. And since it's an Untagged VLAN, I get real VLAN segmentation on the switch without the hassles of exceeding legal packet length, adjusting everybody's max MTU size on the network, 802.1Q tags, and whether the ADSL CPE supports 802.1Q VLAN's or not. It just works, and it is completely transparent to the hosts.

I created an additional Untagged VLAN on the switch for all DMZ hosts' DMZ interfaces. So if traffic is going to get into or out of the DMZ, it is going to have to get past the iptables ruleset running on the active Master Director/Firewall (and the firewall scripts also running on the other DMZ hosts).

VLAN's... I knew there was a reason I paid extra for a managed ethernet switch!

This could also be done with a small, separate ethernet switch (or hub) for the Directors' external interfaces and ADSL CPE, and a larger switch (or hub) for the DMZ hosts, and segment the DMZ and internal subnet(s) using separate switches/hubs, 802.1Q VLAN's, or any other ideas that keep the subnets separated.

Anyway, let's see what the makeup of our example DMZ looks like.

Layout of Our Example DMZ

Our setup has a "mixed DMZ" of LVS-NAT-based RealServers (the routable VIP's are on the active MASTER LVS Director/Firewall), and other DMZ hosts who use some of our routable IP addresses themselves, and only need our Director/firewall box to gateway and filter their traffic via Proxy Arp.

We have two Real Servers which handle DNS, SMTP, POP3, and Apache public services for the domains we run here, and we will configure keepalived so that these services are "highly available". This means one Real Server can fail or be taken down for maintenance, and the virtual services are still available.

Our Routable (Public) IP Address Space

In our example, we have a /28 block of 16 routable static IP addresses from our ISP. For the purposes of this document, I'll call them 10.1.2.80/28 (ie, 10.1.2.80 - 10.1.2.95), and we'll all pretend that 10.0.0.0/8 is routable address space. ;)

The subnet mask our ISP uses in this IP range is /26, or 255.255.255.192, for the CIDR-challenged. ;) So as far as the ISP is concerned, IP's 10.1.2.64 - 10.1.2.127 are all in the same subnet (and the network ID is 10.1.2.64/26). The ISP's default gateway is 10.1.2.65.

A Quick Word about IP Network ID's vs. IP Netmasks (for the less experienced)
It should be fairly obvious that for our Directors and DMZ hosts to be able to "see" our ISP's gateway, that we have to use the same /26 subnet mask our ISP does, when we define our routable IP addresses on our DMZ hosts and Directors. We do have /28 (16 hosts) of that /26 (64 host subnet), but that's not the same as us having a /28 subnet mask.

If you aren't sure you understand the difference (when you would use /28 vs. when you would use /26), you might want to read up on Subnet Masks and Network ID's a little before you proceed. But basically, in routing statements, iptables address matching arguments, etc., we can use a network ID of 10.1.2.80/28 to refer to the entire block of routable IP addresses we have, but we can't define our public IP's where we use them with a subnet mask of /28, or we lose two of our static IP's (10.1.2.80 and 10.1.2.95) to the subnet bitbucket, and 10.1.2.65, our way out to the internet, is no longer "visible" -- because a /28 subnet mask puts blinders on us that says we can't reach it.

(Actually, we need to define at least one of our routable VIP's on the Director with a subnet mask of /26, we can just define the address itself for the rest of the routable VIP's -- see the keepalived.conf example below).

Routable IP's In Use For This Example

Here is a list of our routable IP address space that we are currently using, and whether each is a Virtual IP (VIP), or being used on a DMZ host:

IP Address        Usage
10.1.2.80            VIP - DNS Server 1, also SMTP/POP (for all hosted domains), and Apache (1st IP-based virtual domain)
10.1.2.81            VIP - DNS Server 2
10.1.2.82            VIP - Apache (2nd IP-based virtual domain)
10.1.2.93            DMZ Host - FTP server
10.1.2.94            DMZ Host - NAT gateway/firewall for internal LAN internet access
10.1.2.95            VIP - gateway addr for active master (moves to new master upon failover)

Internal Network Addresses on our LVS Members

We will use the RFC1918-compliant Private/Reserved IP subnet of 192.168.0.0/24 for our LVS-NAT cluster members. Note that ALL of the addresses listed below are permanently-assigned addresses except 192.168.0.254 - this is a VIP which each LVS-NAT Real Server must be configured to use as Default Gateway (DGW), and will be taken over by the new MASTER Director/Firewall in the event of a failover. Each keepalived Director/Firewall also has a "DMZ Management" address defined on its internal interface.

We'll use our system startup scripts (on Redhat systems: /etc/sysconfig/network and /etc/sysconfig/network-scripts/ifcfg-ethN) to set the DMZ Management address, subnet mask, etc. on our LVS cluster members (Directors and Real Servers). Make sure each Real Server is set to use the LVS-NAT DGW VIP (192.168.0.254 in our example) as default gateway! Example files for Redhat systems are included below. We'll use the firewall script we run on our Real Servers to add the additional private IP addresses our public services will handle traffic from internet on. Snip-it examples are included below.

IP Address             Usage
192.168.0.1            "DMZ Management" IP address for LVS Director/Firewall #1 - interface eth0
192.168.0.2            "DMZ Management" IP address for LVS Director/Firewall #2 - interface eth0
192.168.0.10          "DMZ Management" IP address for Real Server #1 - interface eth1
192.168.0.20          "DMZ Management" IP address for Real Server #2 - interface eth1

192.168.0.111         Real Server #1 - DNS, SMTP, POP, and Apache IP-Based VirtualHost #1 - interface eth1
192.168.0.112         Real Server #1 - Apache IP-Based VirtualHost #2 - interface eth1

192.168.0.211         Real Server #2 - DNS, SMTP, POP, and Apache IP-Based VirtualHost #1 - interface eth1
192.168.0.212         Real Server #2 - Apache IP-Based VirtualHost #2 - interface eth1

192.168.0.254         VIP - LVS-NAT Default Gateway (DGW) Address - active Master Director interface eth0

DNS Server Notes
Our 2 DNS servers are set up as master and slave, and are authoritative on the internet for the domains we host here. Their VIP's are their registered DNS server IP addresses.

You may notice, looking at the keepalived.conf file below, that we are going to set up each DNS server's registered IP as a virtual service, with both Real Servers listed for each. This means that one of our Real Servers can go down, and the remaining Real Server will still be able to serve authoritative name records for our domains, regardless of which registered DNS server address the request was originally sent to. Pretty neat.

While we do have a health check set up for our TCP services, we don't do any connect check on DNS 53/udp right now, since we can't do that just yet with keepalived.

Mail Server Notes
As far as mail service goes, we're keeping it relatively simple for now. The zone files for both domains we host here have mail.myprimarydomain.bogus listed as the MX (SMTP mail exchanger) for their domain, with the same single VIP listed (10.1.2.80). Qmail listens on each Real Server, and has both domains listed in rcpthosts on both Real Servers. mail.primarydomain.bogus is also the name of the "mail server" we give our mail users for POP3, SMTP, etc.

Speaking of SMTP servers...
Some ISP's are "getting tough on spam". That's what they tell their board members and users, anyway. So they block their users from connecting outbound on destination port 25. If you're using their ISP service, you can only connect to THEIR SMTP servers on port 25. That's really funny to me, because some of these ISP's are still among the biggest ORIGINATORS of spam on the net, and they have been blocking port 25 outbound on their users for 2 years or more. What about all the spam that THEIR SMTP servers deliver?

If you know how to run a secure SMTP server (SMTP-Auth is very helpful, for example), and want your users to be able to use your SMTP server from the internet (even when they are connecting to you from a "spambuster" ISP), check out the optional "SMTP High Port" virtual service shown in the example keepalived.conf file below. By using an extra "high" port number for access to your SMTP service, your remote users can bypass their ISP's silly "spambuster" security, and use your SMTP server anyway. You will need to instruct your "spambusted" users to change the SMTP Server Port in their email client's config settings for your SMTP server, to whatever port number you set up the virtual service on. Notice that the virtual service changes the destination port number back to 25 before it directs it to a Real Server.

Apache Notes
For now, we will keep things simple/reliable, and use an IP-based VirtualHost setup for Apache. I say reliable, because many of the indexing bots used by the big search engines are still not capable of making HTTP/1.1-style requests which include the hostname (ie, which name-based VirtualHost should respond). So if you want your pages to show up on the web search engines, I'd stick to IP-based VirtualHosts for a while.

Hits coming to one domain's website (VIP) will be directed to a Real Server whose Apache VirtualHost directive instructs it to listen for connections to one IP (192.168.0.111 on RS1, 192.168.0.211 on RS2) -- while hits coming to the other domain's website (VIP) will be directed to one of the same RealServers, but to a different VirtualHost IP which listens for the second domain (192.168.0.112 on RS1, 192.168.0.212 on RS2). Consult your Apache documentation for instructions on how to set up IP-based virtual hosts.

The Configuration Files

keepalived.conf

The config files presented here as examples do not take advantage of some of keepalived's other features, such as encrypted authentication between routers, SMTP notifications, and the ability to group virtual services with virtual_server_group, just to name a few. Also, we are just doing a basic "TCP Check" to verify our TCP virtual services are responding.

Our health checking is one of the main improvements we could make to our configuration. By using virtual_server_group, we could combine virtual services which are actually served by the same daemons into a group, and do a single plain TCP check to satisfy keepalived that the service is still responding. Our normal SMTP port virtual service and our High SMTP port virtual service would be good candidates for merging into a virtual_server_group. So would our Apache virtual services. And if I am understanding the capabilities correctly, we may also be able to put the 53/tcp and 53/udp virtual services of each registered DNS server's IP together into a virtual_server_group, and get around not being able to do a UDP connection check just yet.

I would also recommend setting up the secure authentication, once you get a running setup going and running smoothly.

As I have opportunity to set up these additional features and verify proper usage, I will update this documentation to reflect their usage.

Here is an example keepalived.conf file for the MASTER keepalived LVS Director/Firewall:
 
global_defs {
lvs_id lvs1
}
 
# VRRP Instances
 
vrrp_sync_group VG1 {
group {
EXT
INT
}
}
 
vrrp_instance EXT {
state MASTER
interface eth1
lvs_sync_daemon_interface eth0
mcast_src_ip 192.168.0.1
debug 0
virtual_router_id 51
priority 150
advert_int 5
authentication {
auth_type PASS
auth_pass zoiks!
}
virtual_ipaddress {
10.1.2.95/26
10.1.2.80
10.1.2.81
10.1.2.82
}
virtual_routes {
src 10.1.2.95 to 10.1.2.65 dev eth1
src 10.1.2.95 to 0.0.0.0/0 via 10.1.2.65 dev eth1
}
# This script will come behind the master takeover
# process and take care of a few extra things for us
# (since we are running a Proxy Arp firewall).
#
notify_master "/etc/keepalived/proxyarpfix"
}
 
vrrp_instance INT {
state MASTER
interface eth0
lvs_sync_daemon_interface eth0
mcast_src_ip 192.168.0.1
debug 0
virtual_router_id 52
priority 150
advert_int 5
authentication {
auth_type PASS
auth_pass scooby!
}
virtual_ipaddress {
10.1.2.95/26
192.168.0.254/24
}
virtual_routes {
src 10.1.2.95 to 10.1.2.80/28 dev eth0
}
}
 
virtual_server 10.1.2.80 25 {
delay_loop 3
lb_algo rr
lb_kind NAT
protocol TCP
ha_suspend
 
real_server 192.168.0.111 25 {
weight 1
TCP_CHECK {
connect_port 25
connect_timeout 3
}
}
real_server 192.168.0.211 25 {
weight 1
TCP_CHECK {
connect_port 25
connect_timeout 3
}
}
}
 
# Optional SMTP High Port for remote users who have
# ISP's that try to stop spammers from using their
# service by blocking outbound destination port 25.
# We have to give those users another port to use
# to get around this, and they will need to configure
# their email client's SMTP server port number for your
# SMTP server to use the high port number instead.
#
virtual_server 10.1.2.80 20025 {
delay_loop 3
lb_algo rr
lb_kind NAT
protocol TCP
ha_suspend
 
real_server 192.168.0.111 25 {
weight 1
TCP_CHECK {
connect_port 25
connect_timeout 3
}
}
real_server 192.168.0.211 25 {
weight 1
TCP_CHECK {
connect_port 25
connect_timeout 3
}
}
}
 
virtual_server 10.1.2.80 53 {
delay_loop 3
lb_algo rr
lb_kind NAT
protocol TCP
ha_suspend
 
real_server 192.168.0.111 53 {
weight 1
TCP_CHECK {
connect_port 53
connect_timeout 3
}
}
real_server 192.168.0.211 53 {
weight 1
TCP_CHECK {
connect_port 53
connect_timeout 3
}
}
}
 
virtual_server 10.1.2.80 53 {
delay_loop 3
lb_algo rr
lb_kind NAT
protocol UDP
ha_suspend
 
real_server 192.168.0.111 53 {
weight 1
}
real_server 192.168.0.211 53 {
weight 1
}
}
 
virtual_server 10.1.2.81 53 {
delay_loop 3
lb_algo rr
lb_kind NAT
protocol TCP
ha_suspend
 
real_server 192.168.0.111 53 {
weight 1
TCP_CHECK {
connect_port 53
connect_timeout 3
}
}
real_server 192.168.0.211 53 {
weight 1
TCP_CHECK {
connect_port 53
connect_timeout 3
}
}
}
 
virtual_server 10.1.2.81 53 {
delay_loop 3
lb_algo rr
lb_kind NAT
protocol UDP
ha_suspend
 
real_server 192.168.0.111 53 {
weight 1
}
real_server 192.168.0.211 53 {
weight 1
}
}
 
virtual_server 10.1.2.80 80 {
delay_loop 3
lb_algo rr
lb_kind NAT
protocol TCP
ha_suspend
 
real_server 192.168.0.111 80 {
weight 1
TCP_CHECK {
connect_port 80
connect_timeout 3
}
}
real_server 192.168.0.211 80 {
weight 1
TCP_CHECK {
connect_port 80
connect_timeout 3
}
}
}
 
virtual_server 10.1.2.80 443 {
delay_loop 3
lb_algo rr
lb_kind NAT
persistence_timeout 600
protocol TCP
ha_suspend
 
real_server 192.168.0.111 443 {
weight 1
TCP_CHECK {
connect_port 443
connect_timeout 3
}
}
real_server 192.168.0.211 443 {
weight 1
TCP_CHECK {
connect_port 443
connect_timeout 3
}
}
}
 
virtual_server 10.1.2.80 110 {
delay_loop 3
lb_algo rr
lb_kind NAT
protocol TCP
ha_suspend
 
real_server 192.168.0.111 110 {
weight 1
TCP_CHECK {
connect_port 110
connect_timeout 3
}
}
real_server 192.168.0.211 110 {
weight 1
TCP_CHECK {
connect_port 110
connect_timeout 3
}
}
}
 
# VIP for 2nd hosted domain's website
# We will direct traffic coming in on
# this VIP:80 to different IP's on the
# Real Servers, where Apache is
# listening for this IP-based VirtualHost.
virtual_server 10.1.2.82 80 {
delay_loop 3
lb_algo rr
lb_kind NAT
protocol TCP
ha_suspend
 
real_server 192.168.0.112 80 {
weight 1
TCP_CHECK {
connect_port 80
connect_timeout 3
}
}
real_server 192.168.0.212 80 {
weight 1
TCP_CHECK {
connect_port 80
connect_timeout 3
}
}
}
 
 
And here is an example keepalived.conf file for the BACKUP keepalived LVS Director/Firewall:
 
global_defs {
lvs_id lvs2
}
 
# VRRP Instances
 
vrrp_sync_group VG1 {
group {
EXT
INT
}
}
 
vrrp_instance EXT {
state BACKUP
interface eth1
lvs_sync_daemon_interface eth0
mcast_src_ip 192.168.0.2
debug 0
virtual_router_id 51
priority 100
advert_int 5
authentication {
auth_type PASS
auth_pass zoiks!
}
virtual_ipaddress {
10.1.2.95/26
10.1.2.80
10.1.2.81
10.1.2.82
}
virtual_routes {
src 10.1.2.95 to 10.1.2.65 dev eth1
src 10.1.2.95 to 0.0.0.0/0 via 10.1.2.65 dev eth1
}
# This script will come behind the master takeover
# process and take care of a few extra things for us
# (since we are running a Proxy Arp firewall).
#
notify_master "/etc/keepalived/proxyarpfix"
}
 
vrrp_instance INT {
state BACKUP
interface eth0
lvs_sync_daemon_interface eth0
mcast_src_ip 192.168.0.2
debug 0
virtual_router_id 52
priority 100
advert_int 5
authentication {
auth_type PASS
auth_pass scooby!
}
virtual_ipaddress {
10.1.2.95/26
192.168.0.254/24
}
virtual_routes {
src 10.1.2.95 to 10.1.2.80/28 dev eth0
}
}
 
virtual_server 10.1.2.80 25 {
delay_loop 3
lb_algo rr
lb_kind NAT
protocol TCP
ha_suspend
 
real_server 192.168.0.111 25 {
weight 1
TCP_CHECK {
connect_port 25
connect_timeout 3
}
}
real_server 192.168.0.211 25 {
weight 1
TCP_CHECK {
connect_port 25
connect_timeout 3
}
}
}
 
# Optional SMTP High Port for remote users who have
# ISP's that try to stop spammers from using their
# service by blocking outbound destination port 25.
# We have to give those users another port to use
# to get around this, and they will need to configure
# their email client's SMTP server port number for your
# SMTP server to use the high port number instead.
#
virtual_server 10.1.2.80 20025 {
delay_loop 3
lb_algo rr
lb_kind NAT
protocol TCP
ha_suspend
 
real_server 192.168.0.111 25 {
weight 1
TCP_CHECK {
connect_port 25
connect_timeout 3
}
}
real_server 192.168.0.211 25 {
weight 1
TCP_CHECK {
connect_port 25
connect_timeout 3
}
}
}
 
virtual_server 10.1.2.80 53 {
delay_loop 3
lb_algo rr
lb_kind NAT
protocol TCP
ha_suspend
 
real_server 192.168.0.111 53 {
weight 1
TCP_CHECK {
connect_port 53
connect_timeout 3
}
}
real_server 192.168.0.211 53 {
weight 1
TCP_CHECK {
connect_port 53
connect_timeout 3
}
}
}
 
virtual_server 10.1.2.80 53 {
delay_loop 3
lb_algo rr
lb_kind NAT
protocol UDP
ha_suspend
 
real_server 192.168.0.111 53 {
weight 1
}
real_server 192.168.0.211 53 {
weight 1
}
}
 
virtual_server 10.1.2.81 53 {
delay_loop 3
lb_algo rr
lb_kind NAT
protocol TCP
ha_suspend
 
real_server 192.168.0.111 53 {
weight 1
TCP_CHECK {
connect_port 53
connect_timeout 3
}
}
real_server 192.168.0.211 53 {
weight 1
TCP_CHECK {
connect_port 53
connect_timeout 3
}
}
}
 
virtual_server 10.1.2.81 53 {
delay_loop 3
lb_algo rr
lb_kind NAT
protocol UDP
ha_suspend
 
real_server 192.168.0.111 53 {
weight 1
}
real_server 192.168.0.211 53 {
weight 1
}
}
 
virtual_server 10.1.2.80 80 {
delay_loop 3
lb_algo rr
lb_kind NAT
protocol TCP
ha_suspend
 
real_server 192.168.0.111 80 {
weight 1
TCP_CHECK {
connect_port 80
connect_timeout 3
}
}
real_server 192.168.0.211 80 {
weight 1
TCP_CHECK {
connect_port 80
connect_timeout 3
}
}
}
 
virtual_server 10.1.2.80 443 {
delay_loop 3
lb_algo rr
lb_kind NAT
persistence_timeout 600
protocol TCP
ha_suspend
 
real_server 192.168.0.111 443 {
weight 1
TCP_CHECK {
connect_port 443
connect_timeout 3
}
}
real_server 192.168.0.211 443 {
weight 1
TCP_CHECK {
connect_port 443
connect_timeout 3
}
}
}
 
virtual_server 10.1.2.80 110 {
delay_loop 3
lb_algo rr
lb_kind NAT
protocol TCP
ha_suspend
 
real_server 192.168.0.111 110 {
weight 1
TCP_CHECK {
connect_port 110
connect_timeout 3
}
}
real_server 192.168.0.211 110 {
weight 1
TCP_CHECK {
connect_port 110
connect_timeout 3
}
}
}
 
# VIP for 2nd hosted domain's website
# We will direct traffic coming in on
# this VIP:80 to different IP's on the
# Real Servers, where Apache is
# listening for this IP-based VirtualHost.
virtual_server 10.1.2.82 80 {
delay_loop 3
lb_algo rr
lb_kind NAT
protocol TCP
ha_suspend
 
real_server 192.168.0.112 80 {
weight 1
TCP_CHECK {
connect_port 80
connect_timeout 3
}
}
real_server 192.168.0.212 80 {
weight 1
TCP_CHECK {
connect_port 80
connect_timeout 3
}
}
}
 
 
As you can see, there is very little difference between the MASTER and the BACKUP config files.

Here is my proxyarpfix script file, referred to by keepalived.conf. This will be run by the MASTER keepalived director at startup, and will also be run by either director when it takes over (or re-assumes) MASTER director duties. This is a bash script, and needs to be made executable (chmod 750 or 700):

#!/bin/bash
#
# keepalived proxyarpfix notify_master script
#
# Drop the larger ISP subnet route on our DMZ interface -
# The kernel adds this route since we defined an IP on
# the DMZ interface with a /26 netmask (which is correct),
# but only /28 of the ISP's subnet can really be reached
# in our DMZ. The rest of them can only be reached on the
# external interface through the ISP gateway.
#
/sbin/ip route del 10.1.2.80/26 dev eth0

# temporarily turn on the ability to arping an IP we don't have
# on a local interface
#
echo 1 > /proc/sys/net/ipv4/ip_nonlocal_bind

# ARPING
# Note: The '&' symbol at the end of each of the arping
# command lines in this script is important - we don't want
# to wait for the first arping to finish executing before
# we start the next one - this has to be done ASAP!!!
#
# Any additional hosts in the DMZ which get set up with
# one of our routable static IP's will NEED to be added to
# this script, in BOTH sections (ISP Gateway and DMZ)!!!
#
#
# ISP Gateway Section
#
# 10.1.2.93 and 10.1.2.94 are DMZ hosts with routable IP's
# in our /28 block. 10.1.2.65 is our ISP's gateway. Since
# we're doing proxy arp, we have to update our ISP's arp
# cache with the MAC addr of the new active Director's
# external interface (posing as each DMZ host).
#
/sbin/arping -U -I eth1 -c 3 -s 10.1.2.93 10.1.2.65 &
/sbin/arping -U -I eth1 -c 3 -s 10.1.2.94 10.1.2.65 &

# DMZ Section
#
# Now we will update our DMZ hosts' arp cache with the MAC addr
# of the new Director's internal interface (posing as ISP gateway):
#
/sbin/arping -U -I eth0 -c 3 -s 10.1.2.65 10.1.2.93 &
/sbin/arping -U -I eth0 -c 3 -s 10.1.2.65 10.1.2.94 &

# Give all of the arpings time to finish. 5 seconds should
# be long enough, but if running this script manually on
# your box yields ANY "bind: cannot assign requested address"
# messages, you may need to increase this value.
/bin/sleep 5

# OK turn the sysctl back off now
#
echo 0 > /proc/sys/net/ipv4/ip_nonlocal_bind
exit 0

Writing a Stateful iptables Firewall Script for the LVS-NAT Director

Introduction

This is where the Antefacto patch really comes into play. Without the Antefacto patch to IPVS, it would basically not be possible to statefully inspect traffic heading to/from our virtual servers and services with our firewall script. IPVS unmodified works independently of Netfilter connection state tracking. So we can't ask Netfilter to keep an eye on IPVS traffic, and make sure we only let good traffic into or out of our LVS. Netfilter simply doesn't know what's going on with those connections, because it has been kept out of the loop.

While it is agreed and logical that IPVS needs to manage the connections to our virtual servers/services by itself to be efficient, keeping Netfilter "out of the loop" effectively mandates that our main firewall has to be a separate box, if we want to run an iptables firewall which statefully inspects ALL traffic passing through it.

That may be acceptable or desirable for some network admins. But if I only have two boxes I can use on this project, and I can choose to either:
(A) Use one box as the stateful firewall, and the other as the LVS-NAT Director behind the firewall, with no HA of either box; or
(B) Patch IPVS so it lets Netfilter know what's going on with its connections, so that the LVS-NAT Director CAN be the stateful firewall too, meaning it only takes one box to do both jobs well;

Then the OBVIOUS choice is to go with Option B. I can build two of them, one as MASTER and the other as BACKUP, and guess what? Now we have a highly-available FIREWALL/DIRECTOR too!

And those with only one box to work with can kill both birds (LVS-NAT Director and Main Stateful Firewall) with one stone.

How do we statefully inspect IPVS traffic with iptables rules?

Of significant note is the way that new connections destined for IPVS-managed virtual services are handled. Things are just slightly different. On a NORMAL firewall box without IPVS, if you wanted to allow new connections to be forwarded to your webserver, you would generally start at or near the top of your forward chain with something like:


/sbin/iptables -A FORWARD -i eth1 -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT

to let connections already in progress continue without further delay, and then you would allow new connections to port 80 of your webserver ($APACHE1) like so:


/sbin/iptables -A FORWARD -i eth1 -o eth0 -p tcp --syn -d $APACHE1 --dport 80 -m state --state NEW -j ACCEPT

But it's a little different with IPVS-managed connections. Remember, the firewall IS the Director, so the VIP's are LOCAL addresses on the firewall.

This means we have to put the rules that accept NEW connections to the LVS webserver in the INPUT chain (or user-defined chains called from the INPUT chain). Once our firewall allows the connection, at that point, IPVS sees the connection, changes the state of this NEW connection to ESTABLISHED, and does its tricks to FORWARD it to a Real Server. What happens from there is goverened by your firewall's FORWARD chain(s). So to summarize, you let NEW and ESTABLISHED/RELATED traffic into your LVS with appropriate ACCEPT rules in the Director's INPUT chain, then you let IPVS direct that traffic to the Real Servers with ACCEPT rules in the Director's FORWARD chain(s).

Note also that if it is IPVS traffic passing through the firewall, even the client's initial connection request (SYN packet) will be called part of an ESTABLISHED connection when it hits the Director's FORWARD chains! Of course it would still be seen as a new connection when it arrives at the Real Server.

So here is the equivalent way to allow connections to your webserver in an LVS-NAT environment, with Antefacto as part of the equation:


# Allow ESTABLISHED and RELATED traffic in from the external interface. This rule
# covers IPVS traffic (connections in progress with Real Servers), as well as
# non-IPVS connections that THIS server has in progress with the outside.
#
/sbin/iptables -A INPUT -i eth1 -m state --state ESTABLISHED,RELATED -j ACCEPT

# Let new SYN packets in on port 80, if the destination IP is the VIP of our
# webserver, so IPVS can see them. ($APACHEVIP1 is a variable, assumed to be
# previously defined in the script).
#
/sbin/iptables -A INPUT -i eth1 -p tcp --syn -d $APACHEVIP --dport 80 -m state --state NEW -j ACCEPT

Then in the FORWARD chain, the only rule we need is to allow ESTABLISHED and RELATED traffic to pass through. Conveniently, this covers traffic headed for LVS Real Servers (even the initial connection request packets) *AND* ESTABLISHED/RELATED traffic for DMZ hosts which are not IPVS virtual servers! (NOTE: for non-IPVS servers you still have to have a rule to allow NEW connections to be forwarded to the DMZ host):

/sbin/iptables -A FORWARD -i eth1 -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT

# (our FTP server is a standalone DMZ host with its own routable IP,
# it is not an LVS virtual service, so unlike traffic headed for
# IPVS-managed services, we have to have a rule to allow new
# connection requests through):
#
/sbin/iptables -A FORWARD -i eth1 -o eth0 -p tcp --syn -d $FTPSERVER --dport 21 -m state --state NEW -j ACCEPT

A Sample iptables Stateful Firewall Script for our LVS-NAT Director

This is a basic firewall script, which demonstrates the basic layout of the type of rules that can/should be used to statefully inspect ALL traffic moving through the firewall, based upon the layout of our example DMZ. It is somewhat comprehensive in nature, but you will probably need to add additional rules for additional services, or for other ports and IP's you want to let through.

This firewall script demonstrates and employs the following concepts:

VARIABLES
We will use variables in as many places as possible, so that if/when changes to IP addresses used by the hosts are necessary, it is usually only necessary to change them where they are defined at the top of the script.

BLOCK UNLESS SPECIFICALLY ALLOWED
We will ONLY let things in/through from the outside that we HAVE to let in for things to work properly. This is "Building Good Firewalls 101". We will either DROP or REJECT things that fail our rules, depending on whether it is a local host or someone from the internet generating the traffic (from the internet = DROP, from local network = REJECT). A REJECT politely informs the host with an ICMP errormsg of some type, a DROP just ignores it and sends no response at all.

USER-DEFINED CHAINS
We will make EXTENSIVE use of iptables user-defined chains in our script. The idea is to make our firewall ruleset as efficient as possible, by quickly determining (in the built-in chains) the general TYPE of traffic the packet is, and then immediately sending that packet to a user-defined chain which ONLY contains rules for those kinds of packets. This greatly reduces the number of rules that any given packet has to be checked against before its fate is decided. So aside from a few "preliminary" checks (like invalid addresses, etc.), the main thing we will use the built-in INPUT, OUTPUT, and FORWARD chains to do for us is to act as a sort of jump table, to quickly determine which user-defined chain the packet should be sent to. Our criteria will be three-fold: (1) Protocol (TCP, UDP, or ICMP); (2) Which interface the traffic is moving on (forward chains based on which interface the traffic is coming IN on); and (3) where it is headed (IN, OUT, or FORWARD). We'll tie up the remaining loose ends (IGMP traffic, etc.) at the end of the built-in chains (although user-defined chains for IGMP, or whatever else, could also be added).

GIVING CREDIT WHERE CREDIT IS DUE
I would like to take a moment to credit and thank David Ranch for the documentation and firewall scripts he had published on his TrinityOS website back in 1999, when I built my first Linux machine to serve as a firewall for our network. His scripts were pretty helpful, since I was pretty unfamiliar with Linux at the time, and not even sure how to approach the task of setting up a Linux firewall.

A lot has changed since '99. I have become moderately proficient in a few things with Linux, but that is to be expected with the amount of time I have put into working with it, and how much I enjoy running Linux. Our network has grown considerably, and we are not just a private network with a couple machines sharing our internet access anymore. Our internet connection has also steadily improved. But most importantly, Linux itself has changed radically in the last 4 years. Ipchains is old news -- if not altogether obsolete.

All of these factors, and others, have led to many major changes to that original firewall script I downloaded from David's website back in '99. Some to (hopefully) make the rules more efficient, but most just to keep up with the changes and improvements -- such as gutting and rewriting it for iptables, which I did by myself, using Rusty Russell's iptables/netfilter documentation as a guide. (Great documentation, by the way). I haven't followed David's updates to his TrinityOS firewall scripts in quite a long time.

As a result, the rc.firewall script you will see here is a different animal - it is NOT just a cheap ripoff with a couple of tiny edits. And I don't mean this in a bad way, but I am not compelled to ask anybody's permission to publish it here.

Still, I do wish to thank and credit David Ranch as my original source for a great firewall script (back in 1999), and for the great Linux documentation on his TrinityOS website, which he does continue to update.

The firewall init script basically IS David's script - but updated for iptables.

For the record, anybody who likes my firewall script is welcome to use it in any way that they see fit. Change it around, rewrite it, print it out and line your bird cage with it, whatever makes you happy. I don't claim that I came up with 100% of this myself.

This is an open source community, folks. Freely you have received, freely give - that's the way I see it. I do believe that people should get due credit for their work. But if I cared or had time to worry about how somebody was going to use my work, or that they might "steal it" and call it their own, I wouldn't be publishing it on the internet. But that's just me. <grin>


#!/bin/bash
#
# This script needs to be made executable to run (chmod 700 or 750).
#
# An example iptables stateful firewall script for IPVS LVS-NAT
# Directors running with the Antefacto netfilter-conntrack patch.
#
######################################################################
# VARIABLES
# Here we will define some variables we will use throughout the script.
######################################################################
#
# DEFAULT LOG LEVEL
# By setting the default log level to 6, when we get a firewall hit,
# it only writes it to the system logs, it doesn't throw it up on
# every virtual console also (that's really annoying).
#
# If you want a firewall log event, use the variable $LOG in the
# rule, without a -j in front of it. And if you want a custom log
# prefix for that log rule, add a --log-prefix "CustomLogPrefix"
# to the end.
#
# Examples:
# I want this logged with no custom log (?)
# /sbin/iptables -A INPUT -i $EXTIF -p tcp -s 1.2.3.4 $LOG
#
# I want this logged with a custom log prefix
# /sbin/iptables -A INPUT -i $EXTIF -p tcp -s 3.4.5.6 $LOG --log-prefix "Some Hacker! :"
#
LOG="-j LOG --log-level 6"
######################################################################
#
# ADDRESS VARIABLES
#
# Our Routable IP Address Space (Network ID)
# (IP's we will route traffic for)
OURIPBLOCK="10.1.2.80/28"

# Broadcast Address for the ISP's subnet mask
# Although we may have use/need for broadcast to
# DMZ Hosts, we will not allow broadcast traffic
# out of the external interface.
DMZBROAD="10.1.2.127"
echo "ISP Subnet Broadcast Address (DMZ Use Only):" $DMZBROAD

# LVS VIP Addresses
VIP1="10.1.2.80"
VIP2="10.1.2.81"
VIP3="10.1.2.82"
MYIP="10.1.2.95"

# DMZ HOSTS with Routable IP Addresses
#
# Our FTP Server (not LVS)
PUBFTP="10.1.2.93"

# INTERNAL NAT GATEWAY/FIREWALL
# The NAT gateway is an internal firewall host in
# the DMZ, which routes all traffic to/from the
# internet for our internal network hosts. We
# use one of our static IP's as a "source NAT"
# address for all internal internet traffic.
# "Source NAT" is the way to do IP Masquerading
# with iptables when you have a static IP address
# to NAT with.
#
# Note that the actual SNAT work will be done on the
# internal firewall host with a POSTROUTING rule. We
# have this variable here because we will need some
# specific ACCEPT rules on this firewall to allow
# certain types of NEW connections to come in from the
# outside, and make it to the internal NAT gateway
# where the traffic will actually be forwarded in
# to the internal network hosts.
#
SNATIP="10.1.2.94"

# DMZ LAN IP Subnet
# IP Subnet of LVS Real Servers and other
# internal hosts with internal "mgmt"
# IP's.
DMZLAN="192.168.0.0/24"

# IP Address of the DSL Modem CPE device
DSLMODEMIP="192.168.1.1"
echo DSL Modem IP Address: $DSLMODEMIP

# DSL Modem IP Address w/Netmask
DSLIPMASK="192.168.1.1/29"
echo "DSL Modem IP Address w/NetMask:" $DSLIPMASK

# Our IP Address on the CPE Mgmt Subnet
CPELANIP="192.168.1.2"
echo OUR IP Address on CPE Mgmt Subnet: $CPELANIP

# Our IP Address on the CPE Mgmt Subnet w/Netmask
# (make this different on the backup director)
CPELANIPMASK="192.168.1.2/29"
echo "OUR IP Address on CPE Mgmt Subnet w/Netmask:" $CPELANIPMASK

######################################################################
#
# INTERFACE VARIABLES
#
# External Interface (connected to internet)
EXTIF="eth1"

# DMZ Interface
DMZIF="eth0"

######################################################################
#
# OTHER VARIABLES
#
# XWindow Ports
XWINPORTS="6000:6063"

######################################################################
#
# FIREWALL SYSCTLS
#
# TURN OFF IP FORWARDING IN THE LINUX KERNEL UNTIL COMPLETE
# SET OF FIREWALL RULES ARE LOADED
echo "0" > /proc/sys/net/ipv4/ip_forward

# Turn OFF PROXY ARP functionality until all of the firewall rules
# are loaded. Note that without an address on a certain interface,
# we cannot actually toggle the value of proxy_arp, because the
# sysctl for that interface doesn't exist until it has an address.
# But by setting the default proxy_arp value, as soon as an address
# is put on the interface, the proxy_arp sysctl will come up for
# the interface, with the default value.
echo "0" > /proc/sys/net/ipv4/conf/$DMZIF/proxy_arp
echo "0" > /proc/sys/net/ipv4/conf/$EXTIF/proxy_arp
echo "0" > /proc/sys/net/ipv4/conf/all/proxy_arp
echo "0" > /proc/sys/net/ipv4/conf/default/proxy_arp

# Disable IP spoofing attacks.
#
echo " - Disabling IP Spoofing attacks."
for file in /proc/sys/net/ipv4/conf/*/rp_filter; do
echo "1" > $file
done

# Enable TCP SYN Cookies
#
echo " - Enabling TCP SYN Cookies"
echo "1" > /proc/sys/net/ipv4/tcp_syncookies

# ICMP SYSCTLS
#
echo " - Setting ICMP handling controls"

# Enable ICMP broadcast echo protection
echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts

# Enable bad error message protection
echo "1" > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses

# Disable ICMP Re-directs
for file in /proc/sys/net/ipv4/conf/*/accept_redirects; do
echo "0" > $file
done

# From IPVS How-To - Turn off sending of ICMP redirects
echo "0" > /proc/sys/net/ipv4/conf/all/send_redirects
echo "0" > /proc/sys/net/ipv4/conf/default/send_redirects
echo "0" > /proc/sys/net/ipv4/conf/$DMZIF/send_redirects
echo "0" > /proc/sys/net/ipv4/conf/$EXTIF/send_redirects

# Accepting Source-Routed Traffic
# If you are running IPROUTE2 and doing some more advanced
# routing of traffic, this may need to be DISABLED (set to 1).
#
echo " - Dropping source-routed packets "
for file in /proc/sys/net/ipv4/conf/*/accept_source_route; do
echo "0" > $file
done

######################################################################
# ROUTING TABLE STUFF
######################################################################
# ADD MULTICAST ROUTE
# In this example, we are adding a multicast route for the DMZ
# interface. Keepalived needs to be able to multicast in order
# to communicate with the BACKUP Director(s). If you are using
# a different interface for Keepalived/VRRP elections, or doing
# other kinds of multicasting, you may need to modify this.

echo " - Adding multicast route on DMZ interface"
/sbin/ip route add 224.0.0.0/4 dev $DMZIF

######################################################################
#
# IPTABLES INITIALIZATION
#
######################################################################
# CLEAR OUT THE RULES AND RELOAD THEM
#
# Change default policies to DROP.
#
# If there isn't a rule to specifically allow a certain type of
# traffic, it will be DROPPED. Note that some of our user-defined
# chains will change this behavior by having the last rule in the
# chain be a blanket ACCEPT (after passing specific block tests).
#
# IPTables doesn't like using REJECT as a chain policy, we'll have to use
# DROP instead
echo " - Setting Default Policies of Built-In Chains"
/sbin/iptables -P INPUT DROP
/sbin/iptables -P OUTPUT DROP
/sbin/iptables -P FORWARD DROP

echo " - Setting Default NAT Policies to ACCEPT:"
/sbin/iptables -t nat -P PREROUTING ACCEPT
/sbin/iptables -t nat -P POSTROUTING ACCEPT
/sbin/iptables -t nat -P OUTPUT ACCEPT

echo " - Flushing All Built-In Chain Rules"
# Flush all old rule sets
#
/sbin/iptables -F

echo " - Flushing NAT Rules"
# Flush NAT rules
/sbin/iptables -t nat -F

echo " - Flushing MANGLE Rules"
/sbin/iptables -t mangle -F

echo " - Flushing and Deleting All User-Defined Chains"
# Flush all user-defined chains. Per how-to, not specifying a specific chain
# flushes all of them. I like this better than 28 more flush commands... ;)
/sbin/iptables -F

# Now that the user-defined chains are empty, we can delete them. Again,
# we'll kill all of them by not specifying a specific chain.
/sbin/iptables -X
/sbin/iptables -t nat -X
/sbin/iptables -t mangle -X

#############################################################################
#
# BUILD THE CHAINS
#
#############################################################################
# CREATE THE USER-DEFINED CPE MGMT TRAFFIC CHAINS FIRST
# We have to do this because we are referring (jumping) to some of
# the CPE MGMT TRAFFIC chains VERY EARLY in the built-in OUTPUT
# rules. Since chains that are referred to must already exist
# when a rule is added that points to them, we have to do this NOW,
# and we may as well keep this all together.
#
# The CPE has an RFC1918 private network address on its ethernet
# interface (defined by the DSLMODEMIP variable), which would
# otherwise be considered a bad destination address for traffic
# going out the external interface. We want/need to be able to
# ping, telnet, and ftp the CPE from our firewall boxes, so we
# will place matching rules ahead of the "bad destinations" list
# in the main OUTPUT chain.
#
# Some explanation may be in order here on my DSLLAN chains...
#
# I only allow REPLY (ESTABLISHED,RELATED) traffic from
# $DSLMODEMIP. My CPE is configured to ONLY function as an
# "ADSL ethernet bridge" device, so any incoming NEW traffic
# from $DSLMODEMIP would be HIGHLY suspect.
#
/sbin/iptables -N tcp_cpe_in
/sbin/iptables -N tcp_cpe_out

/sbin/iptables -N udp_cpe_in
/sbin/iptables -N udp_cpe_out

/sbin/iptables -N icmp_cpe_in
/sbin/iptables -N icmp_cpe_out

###########################################################################
# CPE TCP INPUT RULES tcp_cpe_in
#

# Connections in progress are OK
/sbin/iptables -A tcp_cpe_in -m state --state ESTABLISHED,RELATED -j ACCEPT

# END OF DSLLAN TCP INPUT CHAIN
# Anything else tries to come through, I want to know about it
/sbin/iptables -A tcp_cpe_in -m limit $LOG --log-prefix "CPE Chatter Block:"
/sbin/iptables -A tcp_cpe_in -j REJECT
###########################################################################

###########################################################################
# DSLLAN UDP INPUT RULES udp_cpe_in
#
# Connections in progress are OK
/sbin/iptables -A udp_cpe_in -m state --state ESTABLISHED,RELATED -j ACCEPT

# END OF DSLLAN TCP INPUT CHAIN
# Anything else tries to come through, I want to know about it
/sbin/iptables -A udp_cpe_in -m limit $LOG --log-prefix "CPE Chatter Block:"
/sbin/iptables -A udp_cpe_in -j REJECT
###########################################################################

###########################################################################
# DSLLAN ICMP INPUT RULES icmp_cpe_in
#
# Connections in progress are OK
/sbin/iptables -A icmp_cpe_in -m state --state ESTABLISHED,RELATED -j ACCEPT

# END OF DSLLAN TCP INPUT CHAIN
# Anything else tries to come through, I want to know about it
/sbin/iptables -A icmp_cpe_in -m limit $LOG --log-prefix "CPE Chatter Block:"
/sbin/iptables -A icmp_cpe_in -j REJECT
###########################################################################

###########################################################################
# DSLLAN TCP OUTPUT RULES tcp_cpe_out
#
# Anything goes...
/sbin/iptables -A tcp_cpe_out -j ACCEPT
###########################################################################

###########################################################################
# DSLLAN UDP OUTPUT RULES udp_cpe_out
# Anything goes...
/sbin/iptables -A udp_cpe_out -j ACCEPT
###########################################################################

###########################################################################
# DSLLAN ICMP OUTPUT RULES icmp_cpe_out
# Anything goes...
/sbin/iptables -A icmp_cpe_out -j ACCEPT
###########################################################################

###########################################################################

echo " Initializing BUILT-IN Chains: "
echo "----------------------------------------------------"

# GENERAL RULES
###########################################################################
# FIRST THINGS FIRST - RULES WE WANT TO PUT IN THE BUILT-IN CHAINS
#
echo " --- "
echo " Populating built-in chains with preliminary rules:"
echo " --------------------------------------------------"
echo " - Populating built-in OUTPUT chain..."

# DSL/CPE MGMT TRAFFIC OUTPUT JUMP TABLES ***MUST*** GO FIRST
# Since we are using private RFC1918 addresses on the DSL Modem
# and as an additional address on the external interface,
# we have to put the jump tables for CPE MGMT traffic ahead of
# everything else, and mainly before we let it hit the REJECT rules
# for other non-routable addresses in the same RFC1918 subnet...
#
# This ALSO means that the chains we are referring to have to already
# exist and be preloaded with their rules. So we had to pull these
# out and stick them above all of this. If we're going to do that,
# we might as well put ALL of the CPE MGMT traffic-related chains
# above this, so we can at least keep them all together.
/sbin/iptables -A OUTPUT -o $EXTIF -p tcp -d $DSLMODEMIP -j tcp_cpe_out
/sbin/iptables -A OUTPUT -o $EXTIF -p udp -d $DSLMODEMIP -j udp_cpe_out
/sbin/iptables -A OUTPUT -o $EXTIF -p icmp -d $DSLMODEMIP -j icmp_cpe_out

echo " - Monitoring Outbound LOCAL Traffic for Bad Destination IP's..."
# OUTBOUND TRAFFIC FROM THIS BOX
# We will REJECT this traffic, rather than DROP it, so the app generating
# the traffic will QUICKLY find out (via DESTINATION UNREACHABLE) we can't
# get there from here.
/sbin/iptables -A OUTPUT -o $EXTIF -d 0.0.0.0/8 -j REJECT
/sbin/iptables -A OUTPUT -o $EXTIF -d 1.0.0.0/8 -j REJECT
/sbin/iptables -A OUTPUT -o $EXTIF -d 10.0.0.0/8 -j REJECT
/sbin/iptables -A OUTPUT -o $EXTIF -d 127.0.0.0/8 -j REJECT
/sbin/iptables -A OUTPUT -o $EXTIF -d 128.0.0.0/16 -j REJECT
/sbin/iptables -A OUTPUT -o $EXTIF -d 128.66.0.0/16 -j REJECT
/sbin/iptables -A OUTPUT -o $EXTIF -d 172.16.0.0/12 -j REJECT
/sbin/iptables -A OUTPUT -o $EXTIF -d 191.255.0.0/16 -j REJECT
/sbin/iptables -A OUTPUT -o $EXTIF -d 192.0.0.0/24 -j REJECT
/sbin/iptables -A OUTPUT -o $EXTIF -d 192.0.1.0/24 -j REJECT
/sbin/iptables -A OUTPUT -o $EXTIF -d 192.0.2.0/24 -j REJECT
/sbin/iptables -A OUTPUT -o $EXTIF -d 192.168.0.0/24 -j REJECT
/sbin/iptables -A OUTPUT -o $EXTIF -d 192.168.1.0/24 -j REJECT
/sbin/iptables -A OUTPUT -o $EXTIF -d 240.0.0.0/5 -j REJECT
/sbin/iptables -A OUTPUT -o $EXTIF -d 248.0.0.0/6 -j REJECT

echo " - Monitoring Outbound FWD Traffic for Bad Destination IP's..."
# OUTBOUND TRAFFIC FROM THE INTERNAL NETWORK
# We will REJECT this traffic, rather than DROP it, so the app generating
# the traffic will QUICKLY find out (via DESTINATION UNREACHABLE) we can't
# get there from here. The -i !$EXTIF statement will cover all interfaces
# except the external interface.
/sbin/iptables -A FORWARD ! -i $EXTIF -o $EXTIF -d 0.0.0.0/8 -j REJECT
/sbin/iptables -A FORWARD ! -i $EXTIF -o $EXTIF -d 1.0.0.0/8 -j REJECT
/sbin/iptables -A FORWARD ! -i $EXTIF -o $EXTIF -d 10.0.0.0/8 -j REJECT
/sbin/iptables -A FORWARD ! -i $EXTIF -o $EXTIF -d 127.0.0.0/8 -j REJECT
/sbin/iptables -A FORWARD ! -i $EXTIF -o $EXTIF -d 128.0.0.0/16 -j REJECT
/sbin/iptables -A FORWARD ! -i $EXTIF -o $EXTIF -d 128.66.0.0/16 -j REJECT
/sbin/iptables -A FORWARD ! -i $EXTIF -o $EXTIF -d 172.16.0.0/12 -j REJECT
/sbin/iptables -A FORWARD ! -i $EXTIF -o $EXTIF -d 191.255.0.0/16 -j REJECT
/sbin/iptables -A FORWARD ! -i $EXTIF -o $EXTIF -d 192.0.0.0/24 -j REJECT
/sbin/iptables -A FORWARD ! -i $EXTIF -o $EXTIF -d 192.0.1.0/24 -j REJECT
/sbin/iptables -A FORWARD ! -i $EXTIF -o $EXTIF -d 192.0.2.0/24 -j REJECT
/sbin/iptables -A FORWARD ! -i $EXTIF -o $EXTIF -d 192.168.0.0/24 -j REJECT
/sbin/iptables -A FORWARD ! -i $EXTIF -o $EXTIF -d 192.168.1.0/24 -j REJECT
/sbin/iptables -A FORWARD ! -i $EXTIF -o $EXTIF -d 240.0.0.0/5 -j REJECT
/sbin/iptables -A FORWARD ! -i $EXTIF -o $EXTIF -d 248.0.0.0/6 -j REJECT

echo " - Suppressing Broadcast Output on the External Interface..."
/sbin/iptables -A OUTPUT -o $EXTIF -d $DMZBROAD -j REJECT
/sbin/iptables -A FORWARD -o $EXTIF -d $DMZBROAD -j REJECT

echo " --- "

###########################################################################
# USER-DEFINED CHAINS
###########################################################################
#
# PROTOCOL/INTERFACE/ROUTE IDENTIFICATION
#
# By categorizing the packets early in the process by type (ie protocol),
# which interface(s), and which direction they're going, we can keep the
# number of rules any packet has to traverse before its fate is determined
# to a minimum (vs. having single giant input, output, and forward chains).
# And more significantly, packets will only be checked against rules that
# apply to that category of traffic. This should help speed things up,
# at least for a lot of the traffic.
#
# The user-defined chains are named like this --
#
# FIRST part of name is which protocol this chain is for.
#
# SECOND part is for which interface the packets are moving on. In the
# case of the fwd chains, this part is which interface the traffic is
# coming IN on.
#
# THIRD part is for where the traffic is headed (IN or OUT of this box,
# or forwarding THRU the box).

echo " Creating custom traffic chains:"
echo " -------------------------------"

# LOCALHOST CHAINS
# For some reason, I HAD to make user-defined localhost chains. Having
# explicit ACCEPTS at the top of the INPUT and OUTPUT chains for lo *DID
# NOT WORK* (the rules were not actually getting put into the INPUT and
# OUTPUT chains!!!).
#
/sbin/iptables -N local_in
/sbin/iptables -N local_out

/sbin/iptables -N tcp_ext_in
/sbin/iptables -N tcp_ext_fwd
/sbin/iptables -N tcp_ext_out
/sbin/iptables -N tcp_dmz_in
/sbin/iptables -N tcp_dmz_fwd
/sbin/iptables -N tcp_dmz_out

/sbin/iptables -N udp_ext_in
/sbin/iptables -N udp_ext_fwd
/sbin/iptables -N udp_ext_out
/sbin/iptables -N udp_dmz_in
/sbin/iptables -N udp_dmz_fwd
/sbin/iptables -N udp_dmz_out

/sbin/iptables -N icmp_ext_in
/sbin/iptables -N icmp_ext_fwd
/sbin/iptables -N icmp_ext_out
/sbin/iptables -N icmp_dmz_in
/sbin/iptables -N icmp_dmz_fwd
/sbin/iptables -N icmp_dmz_out


###########################################################################
# SPECIAL DROP & REJECT CHAINS
# This wouldn't be necessary if it were possible to LOG a packet we wanted to
# kill and DROP/REJECT it at the same time. (This could be done in IPCHAINS).
#
# Anything that gets sent to these chains are going to be either DROPPED
# or REJECTED. We just have separate chains so we can get offending
# traffic out of the calling chains before they hit an ACCEPT rule.
/sbin/iptables -N bad_tcp_reject
/sbin/iptables -N bad_udp_reject

# PRE- and POSTROUTING DROP and REJECT chains
/sbin/iptables -t nat -N prenat_bad_dest
/sbin/iptables -t nat -N prenat_bad_src
/sbin/iptables -t nat -N prenat_getlost
/sbin/iptables -t nat -N prenat_impostor
/sbin/iptables -t nat -N bad_prenat
###########################################################################


###########################################################################
# BAD TCP OUTPUT/FORWARD REJECT CHAIN bad_tcp_reject
#
# This chain is pretty much like the rules in the bad_prenat chain, except,
# well you guessed it, we're going to REJECT the packets instead of just
# dropping 'em.
#
# This chain is for Internal / DMZ hosts, so they get a quick ICMP
# errormsg back. The folks on the internet just get DROPPED.
#
# If your box is a little strained for CPU Idle time, you may want to
# comment out the custom log entries and uncomment the generic log
# entry at the bottom of this chain. You'll lose the custom log
# entries but it should reduce the CPU load a bit...
###########################################################################
echo " - Populating TCP Outbound/FWD LOG and REJECT Chain..."
###########################################################################
# RPC
/sbin/iptables -A bad_tcp_reject -p tcp --sport 111 -m limit $LOG --log-prefix "RPC Block:"
/sbin/iptables -A bad_tcp_reject -p tcp --dport 111 -m limit $LOG --log-prefix "RPC Block:"

# SMB
/sbin/iptables -A bad_tcp_reject -p tcp --dport 135:139 -m limit $LOG --log-prefix "SMB LEAK:"
/sbin/iptables -A bad_tcp_reject -p tcp --dport 445 -m limit $LOG --log-prefix "SMB LEAK:"
/sbin/iptables -A bad_tcp_reject -p tcp --sport 135:139 -m limit $LOG --log-prefix "SMB LEAK:"
/sbin/iptables -A bad_tcp_reject -p tcp --sport 445 -m limit $LOG --log-prefix "SMB LEAK:"

# IPSec
/sbin/iptables -A bad_tcp_reject -p tcp --sport 500 -m limit $LOG --log-prefix "IPSec Block:"
/sbin/iptables -A bad_tcp_reject -p tcp --dport 500 -m limit $LOG --log-prefix "IPSec Block:"

# PPTP
/sbin/iptables -A bad_tcp_reject -p tcp --dport 1723 -m limit $LOG --log-prefix "PPTP Block:"

# Remote Winsock
/sbin/iptables -A bad_tcp_reject -p tcp --dport 1745 -m limit $LOG --log-prefix "RmtWinSock Block:"

# NFS
/sbin/iptables -A bad_tcp_reject -p tcp --sport 2049 -m limit $LOG --log-prefix "NFS Block:"
/sbin/iptables -A bad_tcp_reject -p tcp --dport 2049 -m limit $LOG --log-prefix "NFS Block:"

# MySQL
/sbin/iptables -A bad_tcp_reject -p tcp --sport 3306 -m limit $LOG --log-prefix "MySQL Block:"

# EggDrop IRC Bots
/sbin/iptables -A bad_tcp_reject -p tcp --sport 3456 -m limit $LOG --log-prefix "EggDrop Block:"

# PCAnywhere
/sbin/iptables -A bad_tcp_reject -p tcp --dport 5631 -m limit $LOG --log-prefix "PCAnywhere Block:"
/sbin/iptables -A bad_tcp_reject -p tcp --dport 5632 -m limit $LOG --log-prefix "PCAnywhere Block:"

# XWindows
/sbin/iptables -A bad_tcp_reject -p tcp --dport $XWINPORTS -m limit $LOG --log-prefix "XWIN Block:"

# TCP TRACEROUTE REPLIES
/sbin/iptables -A bad_tcp_reject -p tcp --dport 33434 -m limit $LOG --log-prefix "TrcRt Reply Block:"

# KNOWN TROJANS
#
# WinCrash
/sbin/iptables -A bad_tcp_reject -p tcp --dport 5742 -m limit $LOG --log-prefix "WinCrash? :"

# NetBus
/sbin/iptables -A bad_tcp_reject -p tcp --dport 12345 -m limit $LOG --log-prefix "NetBus? :"
/sbin/iptables -A bad_tcp_reject -p tcp --dport 12346 -m limit $LOG --log-prefix "NetBus? :"

# NetBus Pro
/sbin/iptables -A bad_tcp_reject -p tcp --dport 20034 -m limit $LOG --log-prefix "NetBus Pro? :"

# Shaft
/sbin/iptables -A bad_tcp_reject -p tcp --sport 20432 -m limit $LOG --log-prefix "Shaft? :"

# Trinoo UDP Flooder
/sbin/iptables -A bad_tcp_reject -p tcp --sport 27665 -m limit $LOG --log-prefix "Trinoo? :"

# Socket DeTroye
/sbin/iptables -A bad_tcp_reject -p tcp --dport 30303 -m limit $LOG --log-prefix "SocketDeTroye? :"

# Unknown Trojan (Master's Paradise [CHR])
/sbin/iptables -A bad_tcp_reject -p tcp --dport 40421 -m limit $LOG --log-prefix "Master's Paradise? :"

# GENERIC LOG TARGET
# If the CPU is low on horsepower, we can reduce the load somewhat by
# commenting all of the above LOG matching rules, and only using this line:
#/sbin/iptables -A bad_tcp_reject -m limit $LOG --log-prefix "Bad TCP Reject:"

# END OF bad_tcp_reject CHAIN
#/sbin/iptables -A bad_tcp_reject -j REJECT
###########################################################################


###########################################################################
# BAD UDP OUT/FWD REJECT CHAIN bad_udp_reject
#
# This is for Internal / DMZ hosts. We will REJECT this traffic, so an
# ICMP errmsg will be immediately returned to them.
#
# If your box is a little strained for CPU Idle time, you may want to
# comment out the custom log entries and uncomment the generic
# log entry at the bottom of this chain. You'll lose the custom log
# entries but it should reduce the CPU load a bit...
#
###########################################################################
echo " - Populating UDP Outbound/FWD LOG and REJECT Chain..." ###########################################################################
# RPC
/sbin/iptables -A bad_udp_reject -p udp --dport 111 -m limit $LOG --log-prefix "RPC Block:"
/sbin/iptables -A bad_udp_reject -p udp --sport 111 -m limit $LOG --log-prefix "RPC Block:"

# SMB
/sbin/iptables -A bad_udp_reject -p udp --dport 135:139 -m limit $LOG --log-prefix "SMB LEAK:"
/sbin/iptables -A bad_udp_reject -p udp --dport 445 -m limit $LOG --log-prefix "SMB LEAK:"
/sbin/iptables -A bad_udp_reject -p udp --sport 135:139 -m limit $LOG --log-prefix "SMB LEAK:"
/sbin/iptables -A bad_udp_reject -p udp --sport 445 -m limit $LOG --log-prefix "SMB LEAK:"

# Mountd
/sbin/iptables -A bad_udp_reject -p udp --dport 635 -m limit $LOG --log-prefix "Mountd Block:"
/sbin/iptables -A bad_udp_reject -p udp --sport 635 -m limit $LOG --log-prefix "Mountd Block:"

# PPTP
/sbin/iptables -A bad_udp_reject -p udp --dport 1723 -m limit $LOG --log-prefix "PPTP Block:"

# Remote Winsock
/sbin/iptables -A bad_udp_reject -p udp --dport 1745 -m limit $LOG --log-prefix "RmtWinSock Block:"

# NFS
/sbin/iptables -A bad_udp_reject -p udp --dport 2049 -m limit $LOG --log-prefix "NFS Block:"
/sbin/iptables -A bad_udp_reject -p udp --sport 2049 -m limit $LOG --log-prefix "NFS Block:"

# PcAnywhere
/sbin/iptables -A bad_udp_reject -p udp --dport 5631 -m limit $LOG --log-prefix "PCAnyWhere Block:"
/sbin/iptables -A bad_udp_reject -p udp --dport 5632 -m limit $LOG --log-prefix "PCAnyWhere Block:"

# Xwindows
/sbin/iptables -A bad_udp_reject -p udp --dport $XWINPORTS -m limit $LOG --log-prefix "XWin Block:"

# KNOWN TROJANS
#
# Shaft
/sbin/iptables -A bad_udp_reject -p udp --sport 18753 -m limit $LOG --log-prefix "Shaft? :"
/sbin/iptables -A bad_udp_reject -p udp --sport 20433 -m limit $LOG --log-prefix "Shaft? :"

# Trinoo UDP flooder
/sbin/iptables -A bad_udp_reject -p udp --sport 27444 -m limit $LOG --log-prefix "Trinoo? :"
/sbin/iptables -A bad_udp_reject -p udp --sport 31335 -m limit $LOG --log-prefix "Trinoo? :"

# BackOrifice
/sbin/iptables -A bad_udp_reject -p udp --dport 31337 -m limit $LOG --log-prefix "BackOrifice? :"
/sbin/iptables -A bad_udp_reject -p udp --dport 31338 -m limit $LOG --log-prefix "BackOrifice? :"

#
# GENERIC LOG TARGET
# If the CPU is low on horsepower, we can reduce the load somewhat
# by commenting all of the above LOG matching rules, and only using
# this one:
#/sbin/iptables -A bad_udp_reject -m limit $LOG --log-prefix "Bad UDP Reject:"

# END OF CHAIN - REJECT
/sbin/iptables -A bad_udp_reject -j REJECT
###########################################################################


echo " - Populating Inbound DROP & LOG Chains..."
###########################################################################
# NAT PRE-ROUTING BAD ADDRESS LOG & DROP CHAINS
#
# The logic here is fairly simple and we do not want to waste a lot of
# CPU ticks. Anything that ends up in either of these chains got here
# because of either a bad source or destination IP address. There is
# really no need to test any further to figure out what is wrong, since
# each case has its own log and drop chain. We only need two rules
# in each chain, the first to log, and the other to drop the packet.
###########################################################################
# DROP ANY INCOMING TRAFFIC NOT SPECIFICALLY ADDRESSED TO US
# This will hopefully also cover broadcast traffic, etc. The NAT
# PREROUTING chain seems to be the logical place to put this if you ask me,
# so it gets dropped before we spend any more time on the packets.
/sbin/iptables -t nat -A prenat_bad_dest -m limit $LOG --log-prefix "PreNAT-Bad Dest:"
/sbin/iptables -t nat -A prenat_bad_dest -j DROP
###########################################################################
# DROP INBOUND PKTS WITH INVALID SOURCE ADDRESSES
# (RESERVED BLOCKS, RFC 1918, BLACKHOLE ADDRESSES, ETC.)
#
# We will not even grace these folks with a reply. They are either up to
# NO GOOD, or they are polluting the internet with their misconfigured LAN.
# Either way, I don't have time for them.
/sbin/iptables -t nat -A prenat_bad_src -m limit $LOG --log-prefix "PreNAT-Bad Src:"
/sbin/iptables -t nat -A prenat_bad_src -j DROP
###########################################################################


###########################################################################
# DROP INBOUND PKTS FROM PEOPLE WHO NEED TO GET A LIFE
# AND MIND THEIR OWN BUSINESS
/sbin/iptables -t nat -A prenat_getlost $LOG --log-prefix "PreNAT-GetLost:"
/sbin/iptables -t nat -A prenat_getlost -j DROP
###########################################################################


###########################################################################
# DROP INBOUND PKTS FROM EXTERNAL INTERFACE IMPOSTORS
#
# DROP and LOG any traffic coming from the EXTERNAL interface, when
# it claims to be from a SOURCE address in our IP block (they are
# trying to bypass the firewall by claiming to be from inside)
#
# The truth of the matter is, we shouldn't really see anything hit
# this chain, because it is what the rp_filter sysctl is supposed
# to do. It's here just in case...
/sbin/iptables -t nat -A prenat_impostor -s $OURIPBLOCK -m limit $LOG --log-prefix "PreNAT-Impostor!:"
/sbin/iptables -t nat -A prenat_impostor -j DROP
###########################################################################


###########################################################################
# NAT PRE-ROUTING LOG AND DROP CHAIN bad_prenat
# Things hitting this chain are already headed for the bitbucket, we
# are only doing further testing to pick up custom log entries.
#
# If your box is a little strained for CPU Idle time, you may want to
# comment out the custom log entries and uncomment the generic
# log entry at the bottom of this chain. You'll lose the custom log
# entries but it should reduce the CPU load a bit...
#
###########################################################################
# Port Scanners
/sbin/iptables -t nat -A bad_prenat -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s --limit-burst 5 $LOG --log-prefix "PORTSCAN! :"

# Trinoo UDP flooder - port # will probably change over time
/sbin/iptables -t nat -A bad_prenat -p tcp --sport 27665 -m limit $LOG --log-prefix "PreNAT-Trinoo Ctl Block:"
/sbin/iptables -t nat -A bad_prenat -p udp --sport 27444 -m limit --limit 1/s $LOG --log-prefix "PreNAT-Trinoo UDP Flood! :"
/sbin/iptables -t nat -A bad_prenat -p udp --sport 31335 -m limit --limit 1/s $LOG --log-prefix "PreNAT-Trinoo UDP Flood! :"

# Shaft distributed flooder - port # will probably change over time
/sbin/iptables -t nat -A bad_prenat -p tcp --sport 20432 -m limit $LOG --log-prefix "PreNAT-Shaft Ctl Block:"
/sbin/iptables -t nat -A bad_prenat -p udp --sport 18753 -m limit --limit 1/s $LOG --log-prefix "PreNAT-Shaft UDP Flood! :"
/sbin/iptables -t nat -A bad_prenat -p udp --sport 20433 -m limit --limit 1/s $LOG --log-prefix "PreNAT-Shaft UDP Flood! :"

# GENERIC LOG TARGET
# If the CPU is low on horsepower, we can reduce the load somewhat
# by commenting all of the above LOG matching rules, and only using
# this line:
#/sbin/iptables -t nat -A bad_prenat -m limit --limit 1/s $LOG --log-prefix "Bad PreNAT:"

# END OF CHAIN - DROP (NO REPLY)
/sbin/iptables -t nat -A bad_prenat -j DROP
###########################################################################


###########################################################################
# USER-DEFINED CHAINS
###########################################################################
echo " "
echo " --------------------------------------------"
echo " Populating User-Defined Chains..."
###########################################################################
# LOCALHOST CHAINS
# I don't know why but I had to do this to get localhost-generated traffic
# to work. I originally tried just adding ACCEPT rules to the main input
# and output chains, but it wouldn't actually add the rules! Go figure...
###########################################################################
# LOCALHOST INPUT
/sbin/iptables -A local_in -j ACCEPT
###########################################################################
# LOCALHOST OUTPUT
/sbin/iptables -A local_out -j ACCEPT
###########################################################################


###########################################################################
# INPUT CHAINS
# Remember -- with IPTables, INPUT means the destination address is defined
# on the firewall machine, not a host behind the firewall! (Those are
# handled by FORWARD rules).
#
# HOWEVER, things change a bit with this being an LVS(-NAT) DIRECTOR.
# VIP's that are publically advertised via external DNS records are
# actually defined on the Director, and then DNAT'd to internal hosts by
# IPVS. So we have to let this traffic come IN on the INPUT chain, then
# after IPVS mangles the packets, they will hit the FORWARD chains to get
# to the Real Server IP's (RIP's).
###########################################################################
#
# EXTERNAL TCP INPUT tcp_ext_in
# We will only define items we specifically want to ALLOW, and DROP
# everything else at the end of the chain.
#
# Allow connections already in progress, and those related to others already
# in progress.
#
/sbin/iptables -A tcp_ext_in -i $EXTIF -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT

# IPVS RULES
#
# Telnet to VIP1 - for testing only
#/sbin/iptables -A tcp_ext_in -i $EXTIF -p tcp --syn -d $VIP1 --dport 23 -m state --state NEW -j ACCEPT

# SMTP
/sbin/iptables -A tcp_ext_in -i $EXTIF -p tcp --syn -d $VIP1 --dport 25 -m state --state NEW -j ACCEPT

# SMTP High Port
/sbin/iptables -A tcp_ext_in -i $EXTIF -p tcp --syn -d $VIP1 --dport 20025 -m state --state NEW -j ACCEPT

# PUBLIC DNS
/sbin/iptables -A tcp_ext_in -i $EXTIF -p tcp --syn -d $VIP1 --dport 53 -m state --state NEW -j ACCEPT
/sbin/iptables -A tcp_ext_in -i $EXTIF -p tcp --syn -d $VIP2 --dport 53 -m state --state NEW -j ACCEPT

# Apache Webservers
/sbin/iptables -A tcp_ext_in -i $EXTIF -p tcp --syn -d $VIP1 --dport 80 -m state --state NEW -j ACCEPT
/sbin/iptables -A tcp_ext_in -i $EXTIF -p tcp --syn -d $VIP3 --dport 80 -m state --state NEW -j ACCEPT

# POP3
/sbin/iptables -A tcp_ext_in -i $EXTIF -p tcp --syn -d $VIP1 --dport 110 -m state --state NEW -j ACCEPT

# HTTPS (VIP1 Only)
/sbin/iptables -A tcp_ext_in -i $EXTIF -p tcp --syn -d $VIP1 --dport 443 -m state --state NEW -j ACCEPT

#END OF EXTERNAL TCP INPUT CHAIN
# If you're not so concerned about LOGGING inbound stuff that gets dropped,
# you can comment out the line below to just DROP it:
/sbin/iptables -A tcp_ext_in -i $EXTIF -p tcp -m limit $LOG --log-prefix "TCP IN Drop:"
/sbin/iptables -A tcp_ext_in -i $EXTIF -p tcp -j DROP
###########################################################################


###########################################################################
# EXTERNAL UDP INPUT udp_ext_in
# Again, we will only define the items we WANT, the rest will be dropped.
/sbin/iptables -A udp_ext_in -i $EXTIF -p udp -m state --state ESTABLISHED,RELATED -j ACCEPT

# IPVS rules
#
# DNS
/sbin/iptables -A udp_ext_in -i $EXTIF -p udp -d $VIP1 --dport 53 -m state --state NEW -j ACCEPT
/sbin/iptables -A udp_ext_in -i $EXTIF -p udp -d $VIP2 --dport 53 -m state --state NEW -j ACCEPT

# END OF EXTERNAL UDP INPUT CHAIN
# If you're not so concerned about LOGGING inbound stuff that gets dropped,
# you can comment out the line below to just DROP it:
/sbin/iptables -A udp_ext_in -i $EXTIF -p udp -m limit $LOG --log-prefix "UDP IN Drop:"
/sbin/iptables -A udp_ext_in -i $EXTIF -p udp -j DROP
###########################################################################


###########################################################################
# EXTERNAL ICMP INPUT icmp_ext_in
# We are going to be VERY picky about what kind of ICMP traffic we allow in
# from the external interface.
#
# It is really nice that IPTables and Kernel 2.4.x can do stateful
# inspection on ICMP! Thanks guys!!!!
#
# Echo Replies - ONLY accept echo replies from addresses we actually sent an
# echo request to:
/sbin/iptables -A icmp_ext_in -i $EXTIF -p icmp --icmp-type echo-reply -m state --state ESTABLISHED,RELATED -j ACCEPT

# ICMP Traceroute Replies (TTL-EXPIRED, etc.)
/sbin/iptables -A icmp_ext_in -i $EXTIF -p icmp --icmp-type 11 -m state --state ESTABLISHED,RELATED -j ACCEPT

# ICMP Destination (host, protocol, etc.) Unreachable
/sbin/iptables -A icmp_ext_in -i $EXTIF -p icmp --icmp-type 3 -m state --state ESTABLISHED,RELATED -j ACCEPT

#Fragmentation Needed - we NEED to let this in (and also forward)
/sbin/iptables -A icmp_ext_in -i $EXTIF -p icmp --icmp-type fragmentation-needed -m state --state ESTABLISHED,RELATED -j ACCEPT

# OPTIONAL - ALLOW INBOUND ECHO REQUESTS
# If you don't mind your firewall being pinged from the outside,
# you can uncomment the following rule. The NAT PREROUTING rules
# will have already cut down on the number of echo requests at a
# time we let in. Also note that if you want this box to be able
# to REPLY, you will also have to uncomment the rule in the
# icmp_ext_out chain to allow echo-reply traffic.
#/sbin/iptables -A icmp_ext_in -i $EXTIF -p icmp --icmp-type echo-request -j ACCEPT

#END OF EXTERNAL ICMP INPUT CHAIN
# If you're not so concerned about LOGGING inbound stuff that gets dropped,
# you can comment out the line below to just DROP it:
#/sbin/iptables -A icmp_ext_in -i $EXTIF -p icmp -m limit --limit 1/s $LOG --log-prefix "ICMP IN Drop:"
/sbin/iptables -A icmp_ext_in -i $EXTIF -p icmp -j DROP
###########################################################################


###########################################################################
# EXTERNAL TCP OUTPUT tcp_ext_out
# Remember, the OUTPUT chains *ONLY* control output directly from this box,
# not traffic forwarded THRU the box!
#
# If the connection is not already in progress (ie, a new connection), we
# are going to MAKE SURE it isn't bad traffic before we let it go out.
#
# Also, we need to LOG a lot of the things we are specifically forbidding to
# go out, because if these things are happening, we probably need to know
# about them! So we will send them to the bad_tcp_reject chain.
###########################################################################

# SESSIONS IN PROGRESS ARE OK
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT

# OUTPUT TYPES WE DON'T ALLOW
# SMB
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp --dport 135:139 -j bad_tcp_reject
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp --dport 445 -j bad_tcp_reject
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp --sport 135:139 -j bad_tcp_reject
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp --sport 445 -j bad_tcp_reject

# RPC
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp --sport 111 -j bad_tcp_reject
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp --dport 111 -j bad_tcp_reject

# IPSec VPN
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp --sport 500 -j bad_tcp_reject
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp --dport 500 -j bad_tcp_reject

# PPTP
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp --dport 1723 -j bad_tcp_reject

# NFS
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp --sport 2049 -j bad_tcp_reject
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp --dport 2049 -j bad_tcp_reject

# MySQL
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp --sport 3306 -j bad_tcp_reject

# EggDrop IRC Bot
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp --sport 3456 -j bad_tcp_reject

# Xwindows
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp --dport $XWINPORTS -j bad_tcp_reject

# TCP TRACEROUTE REQUESTS
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp --dport 33434 -j bad_tcp_reject

# KNOWN TROJANS
#
# Win Crash Trojan
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp --dport 5742 -j bad_tcp_reject

# NetBus
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp --dport 12345 -j bad_tcp_reject
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp --dport 12346 -j bad_tcp_reject

# NetBus Pro
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp --dport 20034 -j bad_tcp_reject

# Shaft distributed flooder - port # will probably change over time
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp --sport 20432 -j bad_tcp_reject

# Trinoo UDP flooder - port # will probably change over time
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp --sport 27665 -j bad_tcp_reject

# Socket De Troye
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp --dport 30303 -j bad_tcp_reject

# Unknown Trojan Horse (Master's Paradise [CHR])
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp --dport 40421 -j bad_tcp_reject

###########################################################################
# END OF TCP EXTERNAL OUTPUT CHAIN
# Now that we have checked to make sure stuff going out isn't one of the
# above, we will allow new connections to go out of THIS box. If anything
# is left after that, we'll REJECT it.
###########################################################################
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp -m state --state NEW -j ACCEPT
/sbin/iptables -A tcp_ext_out -o $EXTIF -p tcp -j bad_tcp_reject
###########################################################################


###########################################################################
# EXTERNAL UDP OUTPUT RULES udp_ext_out
#
# Remember, the OUTPUT chains *ONLY* control output directly from this box,
# not traffic forwarded THRU the box!
#
# If the connection is not already in progress (ie, a new connection), we
# are going to MAKE SURE it isn't bad traffic before we let it go out.
#
# Also, we need to LOG a lot of the things we are specifically forbidding to
# go out, because if these things are happening, we probably need to know
# about them! So we will send them to the bad_udp_reject chain.
###########################################################################

# Sessions in progress are OK
/sbin/iptables -A udp_ext_out -o $EXTIF -p udp -m state --state ESTABLISHED,RELATED -j ACCEPT

# RPC
/sbin/iptables -A udp_ext_out -o $EXTIF -p udp --dport 111 -j bad_udp_reject
/sbin/iptables -A udp_ext_out -o $EXTIF -p udp --sport 111 -j bad_udp_reject

# SMB
/sbin/iptables -A udp_ext_out -o $EXTIF -p udp --dport 135:139 -j bad_udp_reject
/sbin/iptables -A udp_ext_out -o $EXTIF -p udp --dport 445 -j bad_udp_reject
/sbin/iptables -A udp_ext_out -o $EXTIF -p udp --sport 135:139 -j bad_udp_reject
/sbin/iptables -A udp_ext_out -o $EXTIF -p udp --sport 445 -j bad_udp_reject

# Mountd
/sbin/iptables -A udp_ext_out -o $EXTIF -p udp --dport 635 -j bad_udp_reject
/sbin/iptables -A udp_ext_out -o $EXTIF -p udp --sport 635 -j bad_udp_reject

# PPTP
/sbin/iptables -A udp_ext_out -o $EXTIF -p udp --dport 1723 -j bad_udp_reject

# Remote Winsock
/sbin/iptables -A udp_ext_out -o $EXTIF -p udp --dport 1745 -j bad_udp_reject

# NFS
/sbin/iptables -A udp_ext_out -o $EXTIF -p udp --dport 2049 -j bad_udp_reject
/sbin/iptables -A udp_ext_out -o $EXTIF -p udp --sport 2049 -j bad_udp_reject

# Xwindows
/sbin/iptables -A udp_ext_out -o $EXTIF -p udp --dport $XWINPORTS -j bad_udp_reject

# Known Trojan ports
#
# Shaft distributed flooder - port # will probably change over time
/sbin/iptables -A udp_ext_out -o $EXTIF -p udp --sport 18753 -j bad_udp_reject
/sbin/iptables -A udp_ext_out -o $EXTIF -p udp --sport 20433 -j bad_udp_reject

# Trinoo UDP flooder - port # will probably change over time
/sbin/iptables -A udp_ext_out -o $EXTIF -p udp --sport 27444 -j bad_udp_reject
/sbin/iptables -A udp_ext_out -o $EXTIF -p udp --sport 31335 -j bad_udp_reject

# BackOrifice
/sbin/iptables -A udp_ext_out -o $EXTIF -p udp --dport 31337 -j bad_udp_reject
/sbin/iptables -A udp_ext_out -o $EXTIF -p udp --dport 31338 -j bad_udp_reject

###########################################################################
# END OF UDP_EXT_OUTPUT CHAIN
# Now that we have checked to make sure stuff going out isn't one of the
# above, we will allow new connections to go out of THIS box. If anything
# is left after that, we'll REJECT it.
/sbin/iptables -A udp_ext_out -o $EXTIF -p udp -m state --state NEW -j ACCEPT
/sbin/iptables -A udp_ext_out -o $EXTIF -p udp -j bad_udp_reject
###########################################################################


###########################################################################
# EXTERNAL ICMP OUTPUT RULES icmp_ext_out
# Sort of like our ICMP Input, I am being VERY picky about what ICMP
# traffic I will let out of this box onto the internet. Basically, all I
# am letting out are echo requests (this also lets you do a traceroute from
# this box to hosts on the internet).
#
# Needless to say, we need to REJECT other output, rather than DROP it.
# We want to be polite to our firewall!!! ;)
#
# PING and TRACEROUTE hosts on the internet
/sbin/iptables -A icmp_ext_out -o $EXTIF -p icmp --icmp-type echo-request -j ACCEPT

# OPTIONAL - Let echo replies go out
# If you don't mind allowing your firewall to reply to incoming
# ping requests, you need to let the replies out. This is
# disabled by default.
#/sbin/iptables -A icmp_ext_out -o $EXTIF -p icmp --icmp-type echo-reply -j ACCEPT

# THIS IS JUST ABOUT ALL WE WANT TO LET OUT, SO THE CHAIN STOPS HERE
/sbin/iptables -A icmp_ext_out -o $EXTIF -p icmp -m limit $LOG --log-prefix "ICMP Out Block:"
/sbin/iptables -A icmp_ext_out -o $EXTIF -p icmp -j REJECT
###########################################################################


###########################################################################
# COMMENTS ON THE FORWARD CHAINS
#
# The jump tables in the main FORWARD chains are written based on which
# interface the traffic to be forwarded (or not) is coming *IN* on.
# Therefore, in each of these user-defined FORWARD chains, we only have to
# worry about where the traffic is going, not where it came from.
#
# By basing the jump tables (and the chains they lead to) on the interfaces
# the would-be FWD traffic is coming IN on, we can end each chain with
# either a DROP or a REJECT:
#
# Traffic we want to block coming from INSIDE our network will get a
# REJECT - this is more polite - as it will send the host an ICMP error
# message, and the host will quickly recover, rather than sitting there
# waiting for a reply which will never come, until it times out.
#
# On the other hand, traffic coming IN from the INTERNET which fails the
# _ext_fwd chains will simply be DROPPED. They will get no type of reply
# from us (especially since we're blocking all types of outbound ICMP except
# echo-request).
#
###########################################################################


###########################################################################
# EXTERNAL TCP FORWARDING RULES tcp_ext_fwd
#
# CONNECTIONS IN PROGRESS ARE OK
# Since these are already in progress I won't specify interfaces and will
# let this stuff thru without any further adieu.... ;)
#
# IPVS NOTE:
# With the way that IPVS with Antefacto mangles the packets destined
# for the Real Servers, even packets creating NEW CONNECTIONS (the
# initial SYN packets) will be marked ESTABLISHED as they hit the
# forward chains. This seems a little unusual, but it works out
# great for our firewall rules. Just don't forget that this ONLY
# works this way for IPVS services. If it's not an IPVS virtual
# service you will still need an explicit rule to allow NEW SYN
# packets to be forwarded (like our FTP server example rule below).

/sbin/iptables -A tcp_ext_fwd -i $EXTIF -o $DMZIF -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT

# ACK PACKETS
# Per a msg I read in netfilter mailing list, I decided to add the
# following rule to let packets through that have the ACK flag set.
# The firewall was logging a lot of dropped ACK packets because it
# didn't think they were part of an ESTABLISHED or RELATED
# connection, when they actually were.
/sbin/iptables -A tcp_ext_fwd -i $EXTIF -o $DMZIF -p tcp --tcp-flags ACK ACK -j ACCEPT

###########################################################################
# FORWARD FROM EXTIF INTO DMZ
#
# Public FTP Server
# Netfilter's conntrack ftp helper will handle the port 20 stuff.
/sbin/iptables -A tcp_ext_fwd -o $DMZIF -p tcp --syn -d $PUBFTP --dport 21 -m state --state NEW -j ACCEPT

###########################################################################
# FORWARD FROM EXTIF INTO INTERNAL LAN
#
# For the most part, we only want to forward REPLY traffic all the way
# into the INTERNAL LAN. We have already done this with the first rule in
# this chain.
#
# However, we DO need to add specific forwarding rules to allow any
# incoming new connections we are going to allow to be made to hosts on
# our internal LAN which are behind the internal SNAT gateway/firewall,
# such as hosts running WinMX, BitTorrent, etc. Note that the internal
# SNAT gateway/firewall is doing all the -j DNAT work to get this traffic
# to the correct internal hosts in its NAT PREROUTING rules.
###########################################################################
#
# WinMX TCP PORTS (To allow sharing)
/sbin/iptables -A tcp_ext_fwd -o $DMZIF -p tcp --syn -d $SNATIP --dport 6690:6696 -m state --state NEW -j ACCEPT

# BitTorrent
# Another file sharing application, used to get the latest 24 episodes
#/sbin/iptables -A tcp_ext_fwd -o $DMZIF -p tcp --syn -d $SNATIP --dport 6881:6889 -m state --state NEW -j ACCEPT
/sbin/iptables -A tcp_ext_fwd -o $DMZIF -p tcp --syn -d $SNATIP --dport 6881 -m state --state NEW -j ACCEPT

# END OF TCP EXTERNAL FORWARD CHAIN
# We are going to DROP anything we haven't specifically allowed above,
# so if there is any other traffic you need to let in, you need to add
# a specific forwarding rule before we get here.
/sbin/iptables -A tcp_ext_fwd -o $DMZIF -p tcp -m limit $LOG --log-prefix "TCP ExtFwd Drop:"
/sbin/iptables -A tcp_ext_fwd -o $DMZIF -p tcp -j DROP
###########################################################################


###########################################################################
# EXTERNAL UDP FORWARDING RULES udp_ext_fwd
#
# CONNECTIONS IN PROGRESS ARE OK
# Since these are already in progress I won't specify interfaces and will
# let this stuff thru without any further adieu.... ;)
#
# IPVS NOTE:
# With the way that IPVS with Antefacto mangles the packets destined
# for the Real Servers, even NEW CONNECTIONS will be marked ESTABLISHED
# as they hit the forward chains. This is a little unusual, but it works
# out great for our firewall rules. Just don't forget that this ONLY
# works this way for IPVS services. If it's not an IPVS virtual service
# you will still need an explicit rule to allow UDP packets the firewall
# considers NEW to be forwarded.

/sbin/iptables -A udp_ext_fwd -o $DMZIF -p udp -m state --state ESTABLISHED,RELATED -j ACCEPT

###########################################################################
# FORWARD FROM EXTIF INTO DMZ
###########################################################################
# ALLOW UNRESTRICTED UDP FROM PUBLIC NTP SERVERS WE SYNC FROM
# Allow FWD of External "new" UDP NTP traffic to our internal NTP server,
# but only from specified inet hosts. It's not really NEW traffic, but
# without these rules, the firewall isn't going to let our NTP server
# completely communicate with the NTP servers we sync from on the 'net.
#
# NOTE: The IP's listed here aren't real NTP servers, they're just here
# to demonstrate what needs to be done if you run an NTP time server for
# your local network, and it syncs itself with public NTP servers.

/sbin/iptables -A udp_ext_fwd -o $DMZIF -p udp -s 10.23.24.25 -d $NTPSRV --dport 123 -j ACCEPT
/sbin/iptables -A udp_ext_fwd -o $DMZIF -p udp -s 10.26.27.28 -d $NTPSRV --dport 123 -j ACCEPT
/sbin/iptables -A udp_ext_fwd -o $DMZIF -p udp -s 10.29.30.31 -d $NTPSRV --dport 123 -j ACCEPT

# Block MySQL (without logging it)
/sbin/iptables -A udp_ext_fwd -o $DMZIF -p udp --dport 3306 -j DROP

###########################################################################
# FORWARD FROM EXTIF INTO INTERNAL LAN
#
# For the most part, we only want to forward REPLY traffic all the way into
# the INTERNAL LAN. We have already done this with the first rule in this
# chain.
#
# However, we DO need to add specific forwarding rules to allow any
# incoming new connections we are going to allow to be made to hosts on
# our internal LAN which are behind the internal SNAT gateway/firewall,
# such as hosts running WinMX, BitTorrent, etc. Note that the internal
# SNAT gateway/firewall is doing all the -j DNAT work to get this traffic
# to the correct internal hosts in its NAT PREROUTING rules.
###########################################################################
#
# WINMX UDP PORTS (PEER-BASED CONNECTIONS)
/sbin/iptables -A udp_ext_fwd -o $DMZIF -p udp -d $SNATIP --dport 6257:6263 -j ACCEPT

# RealPlayer UDP Transport
# RealPlayer likes 3 UDP ports per host
/sbin/iptables -A udp_ext_fwd -o $DMZIF -p udp -d $SNATIP --dport 7073:7075 -j ACCEPT

# END OF EXTERNAL UDP FORWARD CHAIN
#
/sbin/iptables -A udp_ext_fwd -o $DMZIF -p udp -m limit --limit 1/s $LOG --log-prefix "UDP ExtFwd Drop:"
/sbin/iptables -A udp_ext_fwd -o $DMZIF -p udp -j DROP
###########################################################################


###########################################################################
# EXTERNAL ICMP FORWARDING RULES icmp_ext_fwd
#
# We are going to be VERY picky about what kind of ICMP traffic we allow in
# from the external interface.
#
# It is really nice that IPTables and Kernel 2.4.x can do stateful
# inspection on ICMP! Thanks guys!!!!
#

# Echo Replies - ONLY accept echo replies from addresses we sent an echo
# request to:
/sbin/iptables -A icmp_ext_fwd -o $DMZIF -p icmp --icmp-type echo-reply -m state --state ESTABLISHED,RELATED -j ACCEPT

# ICMP Traceroute Replies (TTL-EXPIRED, etc.)
/sbin/iptables -A icmp_ext_fwd -o $DMZIF -p icmp --icmp-type 11 -m state --state ESTABLISHED,RELATED -j ACCEPT

# ICMP Destination (host, protocol, etc.) Unreachable
/sbin/iptables -A icmp_ext_fwd -o $DMZIF -p icmp --icmp-type 3 -m state --state ESTABLISHED,RELATED -j ACCEPT

#Fragmentation Needed - we NEED to let this in (and also forward)
/sbin/iptables -A icmp_ext_fwd -o $DMZIF -p icmp --icmp-type fragmentation-needed -m state --state ESTABLISHED,RELATED -j ACCEPT

#END OF EXTERNAL ICMP INPUT CHAIN
# Log if you want all the gory details
#/sbin/iptables -A icmp_ext_fwd -o $DMZIF -p icmp -m limit --limit 1/s $LOG --log-prefix "ICMP ExtFwd Drop:"
/sbin/iptables -A icmp_ext_fwd -o $DMZIF -j DROP
###########################################################################


###########################################################################
# DMZ TCP INPUT RULES tcp_dmz_in
#
# For now I'll keep this simple and trust stuff coming from the DMZ
/sbin/iptables -A tcp_dmz_in -i $DMZIF -p tcp -j ACCEPT
###########################################################################


###########################################################################
# DMZ UDP INPUT RULES udp_dmz_in
# For now I'll keep this simple and trust stuff coming from the DMZ
/sbin/iptables -A udp_dmz_in -i $DMZIF -p udp -j ACCEPT
###########################################################################


###########################################################################
# DMZ ICMP INPUT RULES icmp_dmz_in
# For now I'll keep this simple and trust stuff coming from the DMZ
/sbin/iptables -A icmp_dmz_in -i $DMZIF -p icmp -j ACCEPT
###########################################################################


###########################################################################
# DMZ TCP OUTPUT RULES tcp_dmz_out
# For now I'll keep this simple and trust stuff leaving this box headed
# to DMZ
/sbin/iptables -A tcp_dmz_out -o $DMZIF -p tcp -j ACCEPT
###########################################################################


###########################################################################
# DMZ UDP OUTPUT RULES udp_dmz_out
# For now I'll keep this simple and trust stuff leaving this box headed
# to DMZ
/sbin/iptables -A udp_dmz_out -o $DMZIF -p udp -j ACCEPT
###########################################################################


###########################################################################
# DMZ ICMP OUTPUT RULES icmp_dmz_out
# For now I'll keep this simple and trust stuff leaving this box headed
# to DMZ
/sbin/iptables -A icmp_dmz_out -o $DMZIF -p icmp -j ACCEPT
###########################################################################


###########################################################################
# DMZ TCP FORWARDING RULES tcp_dmz_fwd
#
# NOTE: Keep in mind that we are not only forwarding traffic from hosts in
# the DMZ with this chain, we're also forwarding from Internal Hosts
# BEHIND the DMZ!!!
#
# Connections in Progress - Since these are already in progress I won't
# specify interfaces and will let this stuff thru without any further
# adieu.... ;)
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT

# SPECIFIC FWD REJECTIONS
# Things we don't want to let out of our network.

# RPC
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -o $EXTIF -p tcp --dport 111 -j bad_tcp_reject
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -o $EXTIF -p tcp --sport 111 -j bad_tcp_reject

# SMB - don't let this be forwarded to the internet, kill it politely
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -o $EXTIF -p tcp --dport 135:139 -j bad_tcp_reject
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -o $EXTIF -p tcp --dport 445 -j bad_tcp_reject
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -o $EXTIF -p tcp --sport 135:139 -j bad_tcp_reject
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -o $EXTIF -p tcp --sport 445 -j bad_tcp_reject

# IPSec VPN
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -o $EXTIF -p tcp --sport 500 -j bad_tcp_reject
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -o $EXTIF -p tcp --dport 500 -j bad_tcp_reject

# PPTP
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -o $EXTIF -p tcp --dport 1723 -j bad_tcp_reject

# Remote Winsock
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -o $EXTIF -p tcp --dport 1745 -j bad_tcp_reject

# NFS
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -o $EXTIF -p tcp --sport 2049 -j bad_tcp_reject
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -o $EXTIF -p tcp --dport 2049 -j bad_tcp_reject

# MySQL
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -o $EXTIF -p tcp --sport 3306 -j bad_tcp_reject

# EggDrop IRC Bot
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -o $EXTIF -p tcp --sport 3456 -j bad_tcp_reject

# PcAnywhere
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -o $EXTIF -p tcp --dport 5631 -j bad_tcp_reject
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -o $EXTIF -p tcp --dport 5632 -j bad_tcp_reject

# Xwindows
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -o $EXTIF -p tcp --dport $XWINPORTS -j bad_tcp_reject

# KNOWN TROJANS
#
# Win Crash Trojan
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -o $EXTIF -p tcp --dport 5742 -j bad_tcp_reject

# NetBus
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -o $EXTIF -p tcp --dport 12345 -j bad_tcp_reject
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -o $EXTIF -p tcp --dport 12346 -j bad_tcp_reject

# NetBus Pro
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -o $EXTIF -p tcp --dport 20034 -j bad_tcp_reject

# Shaft distributed flooder - port # will probably change over time
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -o $EXTIF -p tcp --sport 20432 -j bad_tcp_reject

# Trinoo UDP flooder - port # will probably change over time
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -o $EXTIF -p tcp --sport 27665 -j bad_tcp_reject

# Socket De Troye
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -o $EXTIF -p tcp --dport 30303 -j bad_tcp_reject

# Unknown Trojan Horse (Master's Paradise [CHR])
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -o $EXTIF -p tcp --dport 40421 -j bad_tcp_reject

# END OF TCP DMZ FORWARD CHAIN
# Now that our would-be FWD traffic has satisfied the above rules, we'll let
# unspecified new connections go out to the internet.
/sbin/iptables -A tcp_dmz_fwd -i $DMZIF -p tcp -j ACCEPT
###########################################################################


###########################################################################
# DMZ UDP FORWARDING RULES udp_dmz_fwd
#
# Connections in progress are OK
/sbin/iptables -A udp_dmz_fwd -i $DMZIF -p udp -m state --state ESTABLISHED,RELATED -j ACCEPT

# SPECIFIC FWD REJECTIONS
# Things we don't want to let out of our network.

# RPC
/sbin/iptables -A udp_dmz_fwd -i $DMZIF -o $EXTIF -p udp --dport 111 -j bad_udp_reject
/sbin/iptables -A udp_dmz_fwd -i $DMZIF -o $EXTIF -p udp --sport 111 -j bad_udp_reject

# SMB
/sbin/iptables -A udp_dmz_fwd -i $DMZIF -o $EXTIF -p udp --dport 135:139 -j bad_udp_reject
/sbin/iptables -A udp_dmz_fwd -i $DMZIF -o $EXTIF -p udp --dport 445 -j bad_udp_reject
/sbin/iptables -A udp_dmz_fwd -i $DMZIF -o $EXTIF -p udp --sport 135:139 -j bad_udp_reject
/sbin/iptables -A udp_dmz_fwd -i $DMZIF -o $EXTIF -p udp --sport 445 -j bad_udp_reject

# Mountd
/sbin/iptables -A udp_dmz_fwd -i $DMZIF -o $EXTIF -p udp --dport 635 -j bad_udp_reject
/sbin/iptables -A udp_dmz_fwd -i $DMZIF -o $EXTIF -p udp --sport 635 -j bad_udp_reject

# PPTP
/sbin/iptables -A udp_dmz_fwd -i $DMZIF -o $EXTIF -p udp --dport 1723 -j bad_udp_reject

# Remote Winsock
/sbin/iptables -A udp_dmz_fwd -i $DMZIF -o $EXTIF -p udp --dport 1745 -j bad_udp_reject

# NFS
/sbin/iptables -A udp_dmz_fwd -i $DMZIF -o $EXTIF -p udp --dport 2049 -j bad_udp_reject
/sbin/iptables -A udp_dmz_fwd -i $DMZIF -o $EXTIF -p udp --sport 2049 -j bad_udp_reject

# PcAnywhere
/sbin/iptables -A udp_dmz_fwd -i $DMZIF -o $EXTIF -p udp --dport 5631 -j bad_udp_reject
/sbin/iptables -A udp_dmz_fwd -i $DMZIF -o $EXTIF -p udp --dport 5632 -j bad_udp_reject

# Xwindows
/sbin/iptables -A udp_dmz_fwd -i $DMZIF -o $EXTIF -p udp --dport $XWINPORTS -j bad_udp_reject

# KNOWN TROJANS
#
# Shaft distributed flooder - port # will probably change over time
/sbin/iptables -A udp_dmz_fwd -i $DMZIF -o $EXTIF -p udp --sport 18753 -j bad_udp_reject
/sbin/iptables -A udp_dmz_fwd -i $DMZIF -o $EXTIF -p udp --sport 20433 -j bad_udp_reject

# Trinoo UDP flooder - port # will probably change over time
/sbin/iptables -A udp_dmz_fwd -i $DMZIF -o $EXTIF -p udp --sport 27444 -j bad_udp_reject
/sbin/iptables -A udp_dmz_fwd -i $DMZIF -o $EXTIF -p udp --sport 31335 -j bad_udp_reject

# BackOrifice
/sbin/iptables -A udp_dmz_fwd -i $DMZIF -o $EXTIF -p udp --dport 31337 -j bad_udp_reject
/sbin/iptables -A udp_dmz_fwd -i $DMZIF -o $EXTIF -p udp --dport 31338 -j bad_udp_reject

# END OF UDP DMZ FORWARDING CHAIN
# Now that our would-be FWD traffic has satisfied the above rules, we'll let
# unspecified UDP traffic out to the internet.
/sbin/iptables -A udp_dmz_fwd -i $DMZIF -p udp -j ACCEPT
###########################################################################


###########################################################################
# DMZ ICMP FORWARDING RULES icmp_dmz_fwd
# Once again, we're being very picky!

# DMZ and Internal Hosts can PING or TRACEROUTE anywhere they want to,
# inside or outside
/sbin/iptables -A icmp_dmz_fwd -i $DMZIF -o $EXTIF -p icmp --icmp-type echo-request -j ACCEPT

# END OF DMZ ICMP FWD CHAIN - REJECT anything else
/sbin/iptables -A icmp_dmz_fwd -i $DMZIF -o $DMZIF -p icmp -m limit $LOG --log-prefix "ICMP FWD Reject:"
/sbin/iptables -A icmp_dmz_fwd -i $DMZIF -o $DMZIF -p icmp -j REJECT
###########################################################################

echo " - Population of User-Defined Chains is Complete."
echo " --- "


###########################################################################
# CREATE JUMP TABLES IN BUILT-IN CHAINS
echo " - Loading Jump Tables into Main INPUT, OUTPUT, and FWD Chains..."
###########################################################################
# OK, now that we have the protocol- and interface-specific user-defined
# chains created, let's create the "jump tables" - these are type-matching
# rules in the built-in INPUT, OUTPUT, and FORWARD chains -- which will
# direct packets to the appropriate user-defined chains. Since a packet
# will have already matched one of these types to even end up in one of
# these user-defined chains, and also since we cannot define a default
# policy for user-defined chains, we will put a DROP, REJECT, or ACCEPT (as
# appropriate) at the end of EACH user-defined chain.
#
# INPUT CHAIN
/sbin/iptables -A INPUT -i lo -j local_in
#
/sbin/iptables -A INPUT -i $EXTIF -p tcp -s $DSLMODEMIP -j tcp_dsl_in
/sbin/iptables -A INPUT -i $EXTIF -p tcp -j tcp_ext_in
/sbin/iptables -A INPUT -i $DMZIF -p tcp -j tcp_dmz_in
#
/sbin/iptables -A INPUT -i $EXTIF -p udp -s $DSLMODEMIP -j udp_dsl_in
/sbin/iptables -A INPUT -i $EXTIF -p udp -j udp_ext_in
/sbin/iptables -A INPUT -i $DMZIF -p udp -j udp_dmz_in
#
/sbin/iptables -A INPUT -i $EXTIF -p icmp -s $DSLMODEMIP -j icmp_dsl_in
/sbin/iptables -A INPUT -i $EXTIF -p icmp -j icmp_ext_in
/sbin/iptables -A INPUT -i $DMZIF -p icmp -j icmp_dmz_in
#
#
# OUTPUT CHAIN
/sbin/iptables -A OUTPUT -o lo -j local_out
#
/sbin/iptables -A OUTPUT -o $EXTIF -p tcp -j tcp_ext_out
/sbin/iptables -A OUTPUT -o $DMZIF -p tcp -j tcp_dmz_out
#
/sbin/iptables -A OUTPUT -o $EXTIF -p udp -j udp_ext_out
/sbin/iptables -A OUTPUT -o $DMZIF -p udp -j udp_dmz_out
#
/sbin/iptables -A OUTPUT -o $EXTIF -p icmp -j icmp_ext_out
/sbin/iptables -A OUTPUT -o $DMZIF -p icmp -j icmp_dmz_out
#
#
# FORWARD CHAIN
/sbin/iptables -A FORWARD -i $EXTIF -p tcp -j tcp_ext_fwd
/sbin/iptables -A FORWARD -i $DMZIF -p tcp -j tcp_dmz_fwd
#
/sbin/iptables -A FORWARD -i $EXTIF -p udp -j udp_ext_fwd
/sbin/iptables -A FORWARD -i $DMZIF -p udp -j udp_dmz_fwd
#
/sbin/iptables -A FORWARD -i $EXTIF -p icmp -j icmp_ext_fwd
/sbin/iptables -A FORWARD -i $DMZIF -p icmp -j icmp_dmz_fwd
#
#
echo " - Jump Tables Loaded for TCP, UDP, and ICMP Protocols."
echo " --- "


###########################################################################
# ALLOW IGMP AND VRRP PROTOCOLS FOR KEEPALIVED
# We need specific allow rules for these protocols so that keepalived
# can communicate between the MASTER and BACKUP Director(s). Note that if
# you are doing your Keepalived communications on a different interface,
# or doing other multicast traffic/routing, you may need to modify these
# rules a bit.
###########################################################################
echo " Permitting IGMP & VRRP Protocol (112) on DMZ Interface for Keepalived."
###########################################################################

#
# Allow IGMP input on DMZ Interface
/sbin/iptables -A INPUT -i $DMZIF -p igmp -j ACCEPT

#
# Allow VRRP input on DMZ Interface
/sbin/iptables -A INPUT -i $DMZIF -p 112 -j ACCEPT

#
# Allow IGMP Output on DMZ Interface
/sbin/iptables -A OUTPUT -o $DMZIF -p igmp -j ACCEPT

#
# Allow VRRP Output on DMZ Interface
/sbin/iptables -A OUTPUT -o $DMZIF -p 112 -j ACCEPT
###########################################################################


###########################################################################
# END OF JUMP TABLES - DROP OR REJECT ALL OTHER INPUT/OUTPUT/FWD TRAFFIC
echo " - Discarding ALL OTHER TRAFFIC."
###########################################################################

/sbin/iptables -A INPUT -i $EXTIF -j DROP
/sbin/iptables -A INPUT ! -i $EXTIF $LOG --log-prefix "EndofInput-Reject:"
/sbin/iptables -A INPUT ! -i $EXTIF -j REJECT

# Reject output of multicast traffic on EXTIF without logging it
/sbin/iptables -A OUTPUT -o $EXTIF -d 224.0.0.0/4 -j REJECT
/sbin/iptables -A OUTPUT $LOG --log-prefix "EndofOutput-Reject:"
/sbin/iptables -A OUTPUT -j REJECT

/sbin/iptables -A FORWARD -i $EXTIF -j DROP
/sbin/iptables -A FORWARD ! -i $EXTIF -j REJECT
###########################################################################

echo " ---------------------"

###########################################################################
# MANGLE TABLE RULES
# Packet mangling stuff. I'm not really doing much of this, other than
# occasional bumping of TTL so I can MIRROR annoying traffic back at the
# senders.
###########################################################################
echo " Populating MANGLE table"
echo " "
###########################################################################
echo " - Changing TTL of REALLY annoying internet traffic "
echo " so we can MIRROR it back at them and hopefully "
echo " achieve successful delivery..."

#
# UDP Ports 1433-1434 (MS SQL Server?)
/sbin/iptables -t mangle -A PREROUTING -i $EXTIF -p udp -d $OURIPBLOCK --dport 1433:1434 -j TTL --ttl-set 255
#
#
###########################################################################
echo " MANGLE table completed."
###########################################################################

echo " ---------------------"

###########################################################################
# NAT TABLES
echo " Loading NAT Tables..."
###########################################################################
# IPTables uses 2 main chains, PREROUTING for input, and POSTROUTING for
# output. We'll do the PREROUTING first, since we are being much more
# picky on incoming stuff.
#
# There is also an OUTPUT NAT chain for locally-generated stuff. It is
# probably not required to tell NAT to NAT stuff heading out from the local
# box though. I think it's just there in case you want to redirect the
# packets elsewhere.
#
###########################################################################
# NAT PREROUTING CHAIN
# Incoming packets are processed by NAT before they are actually passed to
# the packet filter. And since we don't NEED to try to figure out where
# SOME kinds of traffic are really going before we kill them, we can save
# some CPU ticks (and eliminate some redundancy in the INPUT and FORWARD
# chains) by doing some checking here first. But AGAIN, since we don't want
# to let packets we deem BAD hit any ACCEPT rules in this chain (because
# they could match them too!), we have to send them to a different DROP
# chain to LOG *AND* KILL them.
#
###########################################################################
echo " - Loading NAT PRE-ROUTING Rules..."
###########################################################################
# DROP FAKE MULTICAST TRAFFIC
# Per the RFC's, real multicast traffic will not have a source IP address
# in the 224.0.0.0/4 IP range, it will have a routable source IP. So
# anything claiming to be from 224.0.0.0/4 is bogus.
echo " - Blocking Incoming FAKE Multicast Traffic from External Interface."
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -s 224.0.0.0/4 -j DROP
###########################################################################
# DROP ANY INCOMING TRAFFIC NOT SPECIFICALLY ADDRESSED TO US
# This shouldn't really ever be a problem unless your ISP has poorly-
# programmed routers or something. But this should also cover broadcast
# traffic, something that could be a problem anyway.
echo " - LOG and DROP packets not having $OURIPBLOCK as Destination Address."
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -d ! $OURIPBLOCK -j prenat_bad_dest
###########################################################################
# DROP INBOUND PKTS WITH INVALID SOURCE ADDRESSES (RESERVED BLOCKS,
# RFC 1918, ETC.)
# We will not even grace these folks with a reply. They are either up to NO
# GOOD, or they are polluting the internet with their misconfigured LAN.
# Either way, I don't have time for them.
echo " - DROP and LOG inbound packets with RESERVED or INVALID Source Addresses..."
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -s 0.0.0.0/8 -j prenat_bad_src
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -s 1.0.0.0/8 -j prenat_bad_src
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -s 10.0.0.0/8 -j prenat_bad_src
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -s 127.0.0.0/8 -j prenat_bad_src
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -s 128.0.0.0/16 -j prenat_bad_src
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -s 128.66.0.0/16 -j prenat_bad_src
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -s 172.16.0.0/12 -j prenat_bad_src
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -s 191.255.0.0/16 -j prenat_bad_src
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -s 192.0.0.0/24 -j prenat_bad_src
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -s 192.0.1.0/24 -j prenat_bad_src
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -s 192.0.2.0/24 -j prenat_bad_src
#ALLOW MGMT TRAFFIC IN FROM DSL MODEM
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -s $DSLMODEMIP -j ACCEPT
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -s 192.168.0.0/24 -j prenat_bad_src
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -s 192.168.1.0/24 -j prenat_bad_src
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -s 240.0.0.0/5 -j prenat_bad_src
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -s 248.0.0.0/6 -j prenat_bad_src
###########################################################################
# IP Spoofing
# This shouldn't really be necessary since we have the rp_filter sysctl
# running, but just in case...
echo " - DROP and LOG External inbound with SOURCE ADDR claiming to be $OURIPBLOCK..."
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -s $OURIPBLOCK -j prenat_impostor
###########################################################################
echo " - Reserved / Invalid Address Tables Loaded."

###########################################################################
# BLACKLISTED IP ADDRESSES, SUBNETS, AND TRAFFIC TYPES
# IP's, IP subnets, and traffic listed here are of particular annoyance
# to me, and worthy of being listed to demonstrate example usage of these
# rules and user-defined chains. Each of these represents something that
# has generated enough log activity that I am tired of looking at it.
###########################################################################
echo " - Populating NAT PREROUTING BLACKLISTED Source IP and Traffic List."
###########################################################################
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -s 216.52.126.0/24 -j DROP

# getting a bunch of pings from these folks
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -s 64.94.1.64/28 -j DROP

# these people keep scanning our IP block and indexing our webservers
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -s 217.21.114.0/24 -j prenat_getlost

# M$-SQL TRAFFIC
# MIRROR M$-SQL Server UDP traffic back at the admins who don't know how
# to maintain their servers. Maybe we'll get their attention (but I'm
# not going to hold my breath - you can always tell an MCSE, but you
# can't tell him much... ;)
#/sbin/iptables -t nat -A PREROUTING -i $EXTIF -p udp --dport 1433:1434 -m limit $LOG --log-prefix "MS-SQL Mirror: "
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -p udp --dport 1433:1434 -j MIRROR

#
# SILENTLY DROP M$-SQL SERVER Connection Attempts
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -p tcp --dport 1433 -j DROP

# SILENTLY DROP NETBIOS/SMB TRAFFIC
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -p tcp --dport 135:139 -j DROP
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -p tcp --dport 445 -j DROP
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -p tcp --sport 135:139 -j DROP
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -p tcp --sport 445 -j DROP
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -p udp --dport 135:139 -j DROP
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -p udp --dport 445 -j DROP
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -p udp --sport 135:139 -j DROP
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -p udp --sport 445 -j DROP

# Block MySQL
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -p tcp --dport 3306 -j DROP

# SILENTLY DROP Port 27374 (what is this?)
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -p tcp --dport 27374 -j DROP

echo " - BLACKLISTED Source IP and Traffic Table Completed."
###########################################################################

#######################################################################
# AVOIDANCE (or should we say "reduced impact") OF SOME DoS ATTACKS
#######################################################################
echo " - Enabling Protection from DoS Attacks.."
#
# SYN-FLOOD
# If I'm understanding this correctly it should not hurt legitimate
# inbound connections.
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -p tcp --syn -m limit --limit 5/s -j ACCEPT

# PING ATTACKS
# This rule doesn't mean "I want to accept pings" - it just limits
# how many will be allowed past the NAT PREROUTING chain into the INPUT
# and FORWARD chains.
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT

# Trinoo UDP flooder - port # will probably change over time
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -p tcp --sport 27665 -j bad_prenat
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -p udp --sport 27444 -j bad_prenat
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -p udp --sport 31335 -j bad_prenat

# Shaft distributed flooder - port # will probably change over time
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -p tcp --sport 20432 -j bad_prenat
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -p udp --sport 18753 -j bad_prenat
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -p udp --sport 20433 -j bad_prenat

#######################################################################
echo " - DoS Protection Ruleset Loading Complete."
#######################################################################

#######################################################################

# NAT PREROUTING DNAT RULES
# These rules will cause incoming traffic the firewall sees as NEW to
# have the destination address changed (DNAT'd) to the address we want
# it to be delivered to. This is really useful, especially when the
# destination address is a reserved/private address (like our LVS-NAT
# Real Servers).

# NTP TRAFFIC
# External "new" NTP traffic - DNAT to NTPSRV (This is our NTP Server)
# This had to be done because some traffic coming in from our selected
# internet servers wasn't being seen as established/related.
#
# NOTE: The 3 source IP's listed aren't real NTP servers, they're just
# shown here as an example to demonstrate what you'll probably need to
# do so your local NTP server can sync with public NTP servers on the
# internet.

/sbin/iptables -t nat -A PREROUTING -i $EXTIF -p udp -s 10.23.24.25 -d $VIP1 --dport 123 -m state --state NEW -j DNAT --to $NTPSRV
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -p udp -s 10.26.27.28 -d $VIP1 --dport 123 -m state --state NEW -j DNAT --to $NTPSRV
/sbin/iptables -t nat -A PREROUTING -i $EXTIF -p udp -s 10.29.30.31 -d $VIP1 --dport 123 -m state --state NEW -j DNAT --to $NTPSRV
###########################################################################
# END OF NAT PREROUTING CHAIN
# echo " - NAT PREROUTING Chain and Port Forwarding Table Loaded."
###########################################################################


###########################################################################
# NAT *POSTROUTING* CHAIN
# We shouldn't need much here, except for SNAT rules to change the source
# IP addresses of new outgoing connections from our LVS-NAT Real Servers
# into one of our routable public IP's.
#
# One possible optimization we could make to the firewall script would be
# to move the specific rejects in the *_ext_out and *_dmz_fwd chains
# (which currently have many redundant rules) to a set of rules here,
# like we did with the NAT PREROUTING chain.
###########################################################################

# SOURCE-NAT ALL OUTBOUND NEW CONNECTIONS FROM DMZHOSTS
# We need to change the source IP address of NEW outbound connections from
# DMZ Hosts with internal private addresses (ie, our LVS Real Servers),
# before we let their traffic out onto the internet. This will allow these
# hosts to make the outbound connections they need to make - examples
# include SMTP delivery, DNS digs, pings, just to name a few. Many of
# the new outbound connections we need to let out will be expected
# to be coming from "official" (DNS-listed) IP addresses, like SMTP
# delivery.
#
# NOTE: If your DNS-listed servers (MX's, etc.) are registered to more
# than one IP, you MAY have to add more rules here, and be more specific
# with the -s address you want each rule to do SNAT work on (ie, which
# routable IP address you want to SNAT those hosts to)
/sbin/iptables -t nat -A POSTROUTING -o $EXTIF -s $DMZLAN -j SNAT --to $VIP1
###########################################################################

# OK Everything is loaded - LET'S ROCK!!!

# TURN ON IP FORWARDING IN THE LINUX KERNEL
echo "1" > /proc/sys/net/ipv4/ip_forward

# Turn on PROXY ARP functionality
echo "1" > /proc/sys/net/ipv4/conf/$DMZIF/proxy_arp
echo "1" > /proc/sys/net/ipv4/conf/$EXTIF/proxy_arp
echo "1" > /proc/sys/net/ipv4/conf/all/proxy_arp
echo "1" > /proc/sys/net/ipv4/conf/default/proxy_arp

###########################################################################

echo "Firewall Rule Set Loading is COMPLETE."
echo "IPVS Virtual Services, Proxy-ARP, and IP Forwarding is now ENABLED."