When you enable a network interface, you create a bi-directional path. Just as you can go out over the network, there is a path for attackers to come into your system. Firewall software, such as Tcpwrappers and IP Tables, enable you to restrict, modify, and manage network packet handling.
Using the network usually has one other limitation: there is no security. Although a user may connect remotely using SSH or some other secure protocol, the ability to connect in the first place can lead to security risks in highly sensitive environments. Fortunately, Dapper includes IPsec and IPv6. These network layer protocols can authenticate, validate, and encrypt network traffic. It's one thing to require a user-login using SSH; it's another thing to block SSH connections in the first place if they are not authenticated.
The basic Ubuntu installation includes two types of firewalls: Tcpwrappers and IP Tables. Tcpwrappers is usually used with automated services such as inetd and xinetd. This system consults two files (/etc/hosts.allow and /etc/hosts.deny) and grants access based on these settings. Both files are in the same format: daemon : clients. For example, to restrict access for incoming FTP requests to only machines in the mydomain.lan domain, you can use:
in.ftpd : .mydomain.lan
Note | There are many different FTP servers available. In this example, the server's executable is called in.ftpd. For the full list, use apt-cache search ftpd. You will need a server that supports libwrap or starts from inetd. See the section "Enabling Tcpwrappers" later in this chapter. |
When a new network request for the daemon is received, Tcpwrappers first checks /etc/ hosts.allow and then /etc/hosts.deny. If the restriction is found in /etc/hosts.allow, then the connection is permitted to contact the daemon. The /etc/hosts.deny restriction blocks the request from ever reaching the daemon. And if there is no restriction, then the connection is permitted.
If you don't want to list specific daemons and hosts, then you can use the keyword ALL.Very secure systems usually have an /etc/hosts.deny that says:
ALL: ALL
This creates a default-deny configuration and blocks access to every service from every client except when they are explicitly permitted by /etc/hosts.allow.
Warning | If you set /etc/hosts.deny to ALL: ALL and forget to grant access in /etc/hosts.allow, then new remote access connections will fail! You may not notice this immediately if you are already remotely connected; Tcpwrappers impacts only new connections, not established ones. |
You can check your Tcpwrappers configuration using the tcpdmatch command. For example, to check if the host myhost.mydomain.lan can access the service in.ftpd, you can use:
tcpdmatch in.ftpd myhost.mydomain.lan
This displays any host name warnings, service issues, and whether access is granted or denied. In addition, if any rule is matched then it will tell you which file (/etc/hosts.allow or /etc/hosts.deny) and which line.
The active program for running Tcpwrappers is called tcpd (/usr/sbin/tcpd). This is usually found in /etc/inetd.conf for starting services. For example:
netbios-ssn stream tcp nowait root /usr/sbin/tcpd /usr/sbin/smbd
This line says to run the SMB daemon when there is a connection on port 139/tcp (the netbios-ssn TCP port). Before running the smbd daemon, Tcpwrappers is used to check if the connection is permitted.
Not every program that uses Tcpwrappers runs the tcpd program; Tcpwrappers is commonly compiled into some network daemons. For example, the SSH daemon (sudo apt-get install openssh-server) has Tcpwrappers built-in. You can check for this by using the ldd command to list all linked libraries and search the libwrap shared library.
$ ldd /usr/sbin/sshd | grep libwrap libwrap.so.0 => /lib/libwrap.so.0 (0xb7eee000)
This means that the SSH server will consult /etc/hosts.allow and /etc/hosts.deny before allowing connections. You can generate a list of libwrap-enabled applications using a small script:
# find all executables and test for libwrap find /bin /usr/bin /sbin /usr/sbin -type f -perm -1 | \ while read filename ; do haslib='ldd "$filename" | grep libwrap.so'; if [ "$haslib" != "" ] ; then echo "$filename" ; fi ; done
Tcpwrappers operates on the network's transport layer. It can filter TCP or UDP ports, but cannot filter network layer (IP, IPv6, and so on) traffic. For this type of filtering, you can use IP Tables. Unlike Tcpwrappers, which runs as an application, IP Tables are provided as a kernel module. As a result, IP Tables impact all applications, not just those designed or configured to use it.
By default, IP Tables stores three types of filters:
INPUT-This table identifies what type of incoming packets to accept. For example, to block SSH packets that use TCP on port 22 from the subnet 172.16.23.0/24, then you can use:
sudo iptables -A INPUT -p tcp --dport 22 \ --source 172.16.23.0/24 -j REJECT
OUTPUT-This table is used to filter outbound network traffic (from your system to a remote system). For example, to block all connections to Microsoft, you can use:
sudo iptables -A OUTPUT --destination 207.46.0.0/16 -j REJECT
FORWARD-This table is used to forward traffic, in case you want to use your Ubuntu system as a network firewall. For example, to allow all traffic from my local LAN (10.0.0.0/8) to relay through my Ubuntu system, I can use:
sudo iptables --table nat -A POSTROUTING \ --out-interface eth0 -j MASQUERADE sudo iptables -A FORWARD --in-interface eth0 \ --source 10.0.0.0/8 -j ACCEPT
However, if I only want to forward web traffic, then I can specify a destination port:
sudo iptables -A FORWARD --in-interface eth0 \ --source 10.0.0.0/8 -p tcp --dport 80 -j ACCEPT
After configuring your system to forward traffic, you can use it as the network gateway for other systems on your network.
The iptables command manages a set of tables and rules, called chains. A single table may have many different chains. The default table is called filter and has the INPUT, OUTPUT, and FORWARD chains. Other tables include nat (for network address translations), mangle (for packet modification), and raw for low-level packet management.
The iptables command takes a variety of options. Table 11-3 lists some of the more common parameters. The full list can be found in the man page for iptables.
Parameter | Example | Purpose |
---|---|---|
-t, –table | -t nat | Specify the table to act on, such as filter, nat, mangle, or raw. The default table is filter. |
-A, –append | -A INPUT | Append rules to a particular chain, such as INPUT, FORWARD, or OUTPUT. |
-s, –source; -d, –destination | -s 10.0.0.0/8 | Specify the source (-s or – source) and destination (-d or –destination) network address. You may include an optional subnet mask. |
-p, –proto | -p tcp | Specify the transport layer protocol, such as tcp, udp, icmp, or all. Without this option, all protocols match the rule. |
–sport, –dport, –port | –port 22 | If you specify a protocol with -p, then you can also specify the port number. This can be a source port (–sport), destination port (– dport), or either (–port). |
–in-interface and –out-interface | –in-interface eth0 | Specify the port used for receiving (in) or sending (out) packets. |
-j, –jump | -j ACCEPT | Identify how to handle the rule. Common rules usually use ACCEPT, REJECT, or DROP. There are a variety of other rules including ones for rewriting packets, triggering logs, or generating specific packet responses. |
When you are finished, you can view your tables using sudo iptables -L. For example:
$ sudo iptables -L Chain INPUT (policy ACCEPT) target prot opt source destination REJECT tcp -- 172.16.23.0/24 anywhere tcp dpt:ssh reject-with icmp-port-unreachable REJECT tcp -- 172.16.23.0/24 anywhere tcp dpt:ssh reject-with icmp-port-unreachable Chain FORWARD (policy ACCEPT) target prot opt source destination ACCEPT tcp -- 10.0.0.0/8 anywhere tcp dpt:www Chain OUTPUT (policy ACCEPT) target prot opt source destination REJECT all -- anywhere 207.46.0.0/16 reject-with icmp-port-unreachable
Changes made using IP Tables are not permanent. To make them happen every time you reboot, you will need to save the settings and re-load them during boot.
Configure IP Tables and test them to make sure they do what you want.
Usually when administrators configure IP Tables, it is done to block external attack paths or enable routing through an existing computer. However, there is another use.
Many different types of viruses, spyware, and worms call out to remote control systems. Using the OUTPUT chain from the filter table, you can block known communication protocols. For example, if nobody without your network should be accessing IRC servers, then you can block TCP ports 6666 and 6667 since these are commonly used for IRC:
sudo iptables -A OUTPUT -p tcp –dport 6666 -j REJECT sudo iptables -A OUTPUT -p tcp –dport 6667 -j REJECT
On mail servers, you can use this to block access from known spam subnets, and on proxy servers you can block access to sites that are infected with malware.
Personally, I have a different use. I perform computer network audits and some systems may be off limits or outside the scope of the audit. To prevent accidental access, I block outbound traffic to the restricted hosts. In some cases, hosts may only be accessed during certain hours (to prevent interference with regular customers). In this case, I use a cron job to add and remove access as needed. (See Chapter 7 for scheduling tasks with cron.)
Save your changes to a configuration file.
sudo iptables-save > iptables.conf sudo mv iptables.conf /etc/iptables.conf
Make an init script for IP Tables. I created /etc/init.d/iptables and the contents are in Listing 11-4. Be sure to make the script executable: chmod 755 /etc/init.d/iptables.
Listing 11-4: The /etc/init.d/iptables Startup Script
#! /bin/sh PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin NAME=iptables DESC="IP Tables" [ -f /etc/iptables.conf ] || exit 1 case "$1" in start) echo "Starting $DESC: $NAME" /sbin/iptables --flush -t filter /sbin/iptables --flush -t nat /sbin/iptables-restore /etc/iptables.conf ;; stop) /sbin/iptables --flush -t filter /sbin/iptables --flush -t nat ;; restart|reload|force-reload) echo "Restarting $DESC: $NAME" /sbin/iptables --flush -t filter /sbin/iptables --flush -t nat /sbin/iptables-restore /etc/iptables.conf ;; *) echo "Usage: $0 {start|stop|restart|force-reload}" >&2 exit 1 ;; esac exit 0
Add the script to the startup configuration. It is configured to be one of the first scripts to run.
cd /etc/rcS.d sudo ln -s ../init.d/iptables S37iptables
Now, any configuration saved in /etc/iptables.conf will be included during startup. If you make new changes using iptables, you can save them using sudo iptables-save.
Although firewalls prevent some connections, they do nothing to actually authenticate the connection and offer no privacy options. If you really need to make sure the connection is permitted and don't want someone to see what you are doing, then consider using IPsec, the security extension to IP. IPsec offers digital signatures for authentication and encryption for privacy.
Note | There are two common versions of the Internet Protocol: the older IP (also called IPv4) and the newer IPv6. IPv6 uses the same security options found in IPsec. The only difference: the availability of these security functions is optional for IPv4, but mandatory for IPv6. However, available is not the same an enabled. The security in IPv6 is normally turned off unless you explicitly enable it. Turning on the security for IPv6 is exactly the same as configuring the security for IPsec. |
IPsec provides point-to-point security that can be used as a secure path or as a virtual private network (VPN). The configuration happens in two stages. First you define the keys to use, and then you define the security policies.
The main program for configuring IPsec is called setkey and it comes from the ipsec- tools package.
sudo apt-get install ipsec-tools
There is an alternate package to ipsec-tools called racoon. (Yes, it is spelled with one c, not like the animal with the same name.) Although racoon is popular with some Linux and BSD distributions, ipsec-tools was the first one included in the main repository for older versions of Ubuntu. This historical precedence gives it slightly more popularity with Ubuntu users. Both packages include the setkey program and both have nearly identical usage. Ironically, the man page for setkey from the ipsec-tools package explicitly references racoon, even if you don't install racoon.
So, what is the difference between racoon and ipsec-tools? Not much from my viewpoint. ipsec-tools accepts configuration commands from a file or stdin, while racoon also supports configurations on the command-line. The racoon package also uses a different configuration file location: /etc/racoon/racoon-tool. conf instead of /etc/ipsec-tools.conf.
Warning | I strongly recommend against remotely using setkey to configure IPsec. As soon as you run the command, it becomes implemented. If you configure a rule to require a key, then your network connection may be immediately terminated. Unless you have an alternate route onto the system, you can easily become locked out. |
To create a key, you need to know the IP addresses for the source and destination hosts, the algorithm, and the key. For example, to define a key for 3DES encryption using cipher block chaining (CBC), I can use:
echo 'add 10.1.1.5 10.1.2.10 esp 0x201 -m tunnel -E 3des-cbc "Twenty-four characters!!" -A hmac-md5 0xdeadbeefcafe1234deadbeefcafe1234 ;' | sudo setkey -c
In this case, the 3DES key for encryption is the string Twenty-four characters!!, and the secret password used for authenticating the packet is the hexadecimal value 0xdeadbeef- cafe1234deadbeefcafe1234.
The setkey program either reads in commands from a file or from stdin. If you just want to run one setting, then place the command in an echo statement and pipe the data into setkey -c. The -c option to setkey says to read from stdin, whereas -f says to read from a file. The lines that it reads are commands such as add or delete and include configuration options. Each command needs to end with a semicolon.
The add option within the setkey command is used to specify a Security Association Database (SAD) entry. These are basically combinations of encryption, authentication, and compression definitions along with network addresses.
Addresses-The first two options to the add command are the source and destination IP addresses. These can be IP or IPv6 address (although they must both be IP or both be IPv6).
Protocol-The next parameter specifies the type of protocol. The available values are usually either esp for encapsulating security payload or ah for authenticated header. The former defines a protected payload, while the latter is only used for authenticating the sender. Other protocols include esp-old and ah-old (from obsolete standards), ipcomp, and tcp for using TCP with MD5 for validation.
SPI-The protocol is followed by a Security Parameter Index used to identify the SAD entry.
Mode-The -m option identifies the type of protocol. It can be tunnel, transport, or any.A tunnel is used for a VPN, while transport is only used for protecting the transport layer (TCP or UDP traffic). Other protocols, such as ICMP, will not pass through the secure connection when using transport. Specifying -m any allows the SAD to be used for either tunnel or transport security.
Encryption-The -E option specifies an encryption algorithm and a secret key used for the encryption. The length of the key depends on the selected encryption algorithm. For example, -E 3des-cbc requires a 24-byte key. Table 11-4 lists the available encryption algorithms and the required key lengths. Keys can be provided as hexadecimal values (beginning with 0x) or as quoted strings. If you do not specify an encryption algorithm, then the entire packet will be sent unencrypted-the same as using the null cipher with no key.
Algorithm | Key size in bits | Key size in bytes |
---|---|---|
des-cbc | 64 | 8 |
3des-cbc | 192 | 24 |
Null | 0–2048 | 0–256 |
blowfish-cbc | 40–448 | 5–56 |
cast128-cbc | 40–128 | 5–16 |
des-deriv | 64 | 8 |
3des-deriv | 192 | 24 |
rijndael-cbc | 128, 192, or 256 | 16, 24, or 32 |
twofish-cbc | 0–256 | 0–32 |
aes-ctr | 160, 224, or 288 | 20, 28, or 36 |
Warning | The setkey program will not load the command if the key length is wrong. It will only say that the key length is wrong; it won't tell you what the key length should be. Also, the man page for setkey only gives you the key length in bits, not bytes or characters. |
Authentication-The -A option specifies the algorithm for digitally signing the packet. This authentication header allows the recipient to know that the packet is actually from the sender. As with encryption, the key can either be a hexadecimal value (beginning with 0x) or a quoted string, and the key size depends on the algorithm (see Table 11-5). If this option is not specified, then the header is not authenticated.
Algorithm | Key size in bits | Key size in bytes |
---|---|---|
hmac-md5 | 128 | 16 |
hmac-sha1 | 160 | 20 |
keyed-md5 | 128 | 16 |
keyed-sha1 | 160 | 20 |
Null | 0–2048 | 0–256 |
hmac-sha256 | 256 | 32 |
hmac-sha384 | 384 | 48 |
hmac-sha512 | 512 | 64 |
hmac-ripemd160 | 160 | 20 |
aes-xcbc-mac | 128 | 16 |
tcp-md5 | 8–640 | 1–80 |
Compression-The -C option can be used to specify packet compression. The only available algorithm is deflate, based on the same algorithm used to compress gzip files (see RFC2394). However, unlike gzip, you cannot specify the compression level. Although compression is useful in some situations, such as transmitting large text files, it isn't ideal for all situations. For example, most encryption algorithms generate random looking data that may not compress well. Also if the data being transmitted is already compressed, then it won't compress any further. Trying to compress data again may only consume more CPU resources. If you're transmitting small packets or not using encryption, then it might be worthwhile to enable compression since the TCP header (a significant transmission overhead) will be compressed. However, for large blocks of streaming data through an encrypted tunnel, you might see better performance without using encryption. This is because the TCP header no longer accounts for a significant amount of data, and encrypted data does not compress well. For these reasons, this option is usually not enabled.
Both ends of an encrypted tunnel need to have the same configuration. Otherwise, they will be unable to communicate. However, both directions of an encrypted tunnel do not need to use the same configuration. For example, transmitting IPsec packets may use an authenticated header with one key, and responses may use authentication and encryption with different keys.
While the Security Association Database (SAD) is used to match algorithms to a particular configuration, the Security Policy Database (SPD) says when to use the SAD entries. The setkey option spdadd defines the requirements. For example:
spdadd 10.1.2.10 10.1.1.5 any -P in ipsec esp/tunnel/10.1.2.10-10.1.1.5/require;
As with the add command, spdadd takes a series of parameters.
Addresses-The first two parameters specify the source and destination addresses. These can be provided as IP or IPv6. They can also contain an optional subnet mask and port number. For example, 10.1.2.10 is the same as 10.1.2.10/32 and 10.1.2.10/32[any]. If you want to allow an entire subnet, then you can use something like 10.1.2.0/24. You can specify port (for example, port 80) as 10.1.2.10[80] or 10.1.2.0/24[80]. Specific ports are very useful if you are configuring a static VPN.
Policy-The -P option specifies policy requirements. This starts with the direction of packet traversal; -P in, -P out, or -P any. While both sides of an IPsec connection need to have the same SAD values, the -P option in the SDP need to be reversed. If one system says -P in then the other needs to say -P out. The policy also defines what should happen. The options are ipsec for enabling IPsec, discard to deny access, or none to allow unsecured connections.
IPsec-If the policy specifies using ipsec, then you also need to specify which SAD to associate with the SPD and when to associate it. The specification has four parameters, separated by slashes.
Protocol-This can be either esp or ah.
Mode-This can be either tunnel or transport.
Addresses-This is only required for tunnels; it lists the source and destination addresses with optional ports. For transport mode, this field can be blank (denoted by //).
Level-This says when to enable IPsec. The value must be either default, use, or require. The default setting will consult the esp_trans_deflev kernel variable (see Chapter 7 for sysctl). If you have not changed anything, then this means no IPsec. The use value will try to use IPsec, but fall back to regular IP if a connection cannot be established. Finally, the require value demands IPsec and will not establish a connection without it-this is the most secure option.
There is a startup script called /etc/init.d/setkey that configures IPsec at boot. It does this by consulting the configuration file /etc/ipsec-tools.conf. If you want to configure IPsec, place your settings in this file. Listing 11-5 shows a sample configuration file that uses encryption and authenticated headers between two hosts.
Listing 11-5: Sample /etc/ipsec-tools.conf
#!/usr/sbin/setkey -f # Flush the SAD and SPD flush; spdflush; ######### # My host is 10.1.1.5 # The remote host is 10.1.2.10 ######### # Set a tunnel between 10.1.1.5 and 10.1.2.10 add 10.1.1.5 10.1.2.10 esp 0x201 -m tunnel -E 3des-cbc "Twenty-four characters!!" -A hmac-md5 "0123456789abcdef" ; add 10.1.2.10 10.1.1.5 esp 0x301 -m tunnel -E 3des-cbc "Twenty-two plus two more" -A hmac-md5 0xdeadbeefcafe1234deadbeefcafe1234; ######## # Security policies # NOTE: If this file is placed on the remote host, then # swap the "-P out" and "-P in" values. # All outbound traffic must go through the tunnel spdadd 10.1.1.5 10.1.2.10 any -P out ipsec esp/tunnel/10.1.1.5-10.1.2.10/require; # All inbound traffic must come from the tunnel spdadd 10.1.2.10 10.1.1.5 any -P in ipsec esp/tunnel/10.1.2.10-10.1.1.5/require;
After creating the configuration file, you can test it using:
sudo setkey -f /etc/ipsec-tools.conf
If there are any errors when it loads, they will be cryptic but at least you will know that there is a problem. Errors are likely due to typographical mistakes or oversights. After it loads, you can use setkey -D and setkey -DP to view the current settings.
$ sudo setkey -D 10.1.1.5 10.1.2.10 esp mode=tunnel spi=513(0x00000201) reqid=0(0x00000000) E: 3des-cbc 5477656e 74792d66 6f757220 63686172 61637465 72732121 A: hmac-md5 30313233 34353637 38396162 63646566 seq=0x00000000 replay=0 flags=0x00000000 state=mature created: Nov 25 16:53:50 2006 current: Nov 25 16:53:55 2006 diff: 5(s) hard: 0(s) soft: 0(s) last: hard: 0(s) soft: 0(s) current: 0(bytes) hard: 0(bytes) soft: 0(bytes) allocated: 0 hard: 0 soft: 0 sadb_seq=1 pid=9861 refcnt=0 10.1.2.10 10.1.1.5 esp mode=tunnel spi=769(0x00000301) reqid=0(0x00000000) E: 3des-cbc 5477656e 74792d74 776f2070 6c757320 74776f20 6d6f7265 A: hmac-md5 deadbeef cafe1234 deadbeef cafe1234 seq=0x00000000 replay=0 flags=0x00000000 state=mature created: Nov 25 16:53:50 2006 current: Nov 25 16:53:55 2006 diff: 5(s) hard: 0(s) soft: 0(s) last: hard: 0(s) soft: 0(s) current: 0(bytes) hard: 0(bytes) soft: 0(bytes) allocated: 0 hard: 0 soft: 0 sadb_seq=0 pid=9861 refcnt=0 $ sudo setkey -DP 10.1.2.10[any] 10.1.1.5[any] any in prio def ipsec esp/tunnel/10.1.2.10-10.1.1.5/require created: Nov 25 16:53:50 2006 lastused: lifetime: 0(s) validtime: 0(s) spid=32 seq=2 pid=9864 refcnt=1 10.1.1.5[any] 10.1.2.10[any] any out prio def ipsec esp/tunnel/10.1.1.5-10.1.2.10/require created: Nov 25 16:53:50 2006 lastused: lifetime: 0(s) validtime: 0(s) spid=25 seq=1 pid=9864 refcnt=1 10.1.2.10[any] 10.1.1.5[any] any fwd prio def ipsec esp/tunnel/10.1.2.10-10.1.1.5/require created: Nov 25 16:53:50 2006 lastused: lifetime: 0(s) validtime: 0(s) spid=42 seq=0 pid=9864 refcnt=1
Finally, you can test the connection. If you can ping the host or connect using a known service such as SSH or HTTP, then you know it is working.