How did I find this out? In order to prepare for the happy day in the future when permanent, high-speed connections to the Internet will be offered in my area, I decided it was a good idea to start investigating security issues. The results were shocking.
The first shock came from looking at my long-neglected /var/log/syslog* files. A few 'refused connect from' entries. One 'connect from' to ftp which apparently succeeded. Oops. Dial-up Internet users are not overlooked by the crackers after all. And my security is not bullet-proof. Better to spend some time really looking at security. And to try to understand something of it this time. So this meant reading books, FAQ's, HOWTO's, and a lot of articles on the Web; and doing some experiments.
This is the result of my investigations. Mind: I am not an expert, but just an amateur, a home user trying to make things work. Nothing of this comes with any guarantee.
The contents of /etc/hosts on heaven, and c:\windows\hosts on earth, is:
127.0.0.1 localhostThis shows that my network uses the domain name my.home. This name is unregistered and meant only for local use. Mail to the outside will have its 'message from' and 'envelope from' addresses translated (in the July and September issues, 1999, of LG I described how to do this).
192.168.1.1 heaven.my.home heaven
192.168.1.2 earth.my.home earth
A LAN which is not connected to the Internet is a private network by definition. Unplug your modem, and you make your network private. But that is a not the kind of private network that I mean. I want to use the Net, send and receive mail, browse the Web, download files, etc. I just do not want anyone from the outside to enter my network.
Linux systems generally aren't private networks. By default, the installation procedure of a Linux distribution sets up all sort of nice network services (like telnet, ftp, finger, etc.) which are accessible by anyone in the world, protected (if at all) only by a password. Also, Microsoft Windows home LAN's are generally not private. Connect two Win95 computers and enable 'file sharing', and the whole world can share your files while your Internet connection is up.
To make non-private networks safe, various techniques are used; passwords of course, and also other security techniques that have been discussed in the Linux Gazette many times, like tcpd (alias tcp wrappers) and kernel-level packet filtering (with ipchains as the user interface). These techniques give some privacy to a system which is essentially public. They are like guards at the door, put there to keep out unwanted characters, while letting the desirable customers in. But why should there be doors at all? I don't want any customers. My network is private!
If we have servers running, reachable by the outside world, we always have to worry about having made some configuration mistake which can be exploited. Also, server programs often have bugs in them which offer openings to crackers. Only recently one was discovered in named. OK, it was later patched, so people who got the newest version of named do not have to worry anymore about this bug. But what about the next one? Better not to to have any doors at all!
If you really want to enable services (mp3 distribution, or whatever) for use by computers outside your home, you must study more advanced security techniques. But if you simply want a private network for the home, read on.
So: have your system scanned! Apart from Secure Design, other scan services exist, e.g. Shields Up!, DSL Reports, Sygate Online Services, and many others. A whole lot of them can be found at an Austrian site, Sicherheit im Kabelnetzwerk ('Security in the Cable Network'; there is also an English version with almost the same information). Use several scan services. Print the results. What this 'scanning' actually means will hopefully become clearer in the course of this article.
You can also 'scan' your system yourself by calling (after su-ing to root) netstat -pan --inet. Use a wide xterm window when doing this, because the output consists of rather long lines. Programs which have 0.0.0.0 in the 'Local Address' column are visible to the whole world!
One way of creating a private network is not to install servers at all, just clients. But that is too simple if you have a network at home connecting two or more computers. Inside your network you want to telnet from one machine to another, you want to run an internal mail service, etc. In other words you can't do without servers.
What servers do is listen. They listen for a signal that says: I want your service. The signal (at least for the TCP-based services) is a special IP packet, called a SYN packet, that enters your computer and specifies the number of a service. For instance, the number of the telnet service (that the in.telnetd program, if it is running, listens to) is 23. These numbers are usually called 'port numbers'. If the in.telnetd program is not running, no one listens to SYN packets with the number 23. So, as they say, 'port 23 is closed'.
Ports do not exist by themselves, like little doors in your computer that you can open or close. A port is open if a server listens to it. Otherwise it is closed. A TCP port comes into existence if there is a program which listens to it, and if not, it does not exist!
How do the SYN packets get into your computer? In the case of heaven, a packet can get 'into' it in three different ways:
It would be nice if all the server programs available on Linux systems had options specifying which interfaces they will listen to. In that case you could just tell all your servers never to listen to the ppp line, and you'd be all set. Hardly any security measures would be needed at all (tcpd, firewalls, etc.); you would only use them 'for good measure', as an extra precaution. Maybe this will happen at some time in the future, but at the moment only a few server programs have this (including the important cases of exim and samba). So we have to do several things to make our network private:
Examples of unneeded services are:
There is usually a command to prevent a service from starting automatically upon boot-up, by removing it from the start-up directories; for instance I got rid of a tamagotchi server, automatically installed by Debian 2.1, by calling
update-rc.d -f /etc/init.d/tama remove
alias startx="startx -- -nolisten tcp"The -nolisten tcp command should really be in one of the X11 resource files, but so far I haven't found out which one. The 'alias' approach works in any case. To test, run (as root) netstat -pan --inet. X should no longer be mentioned. Of course it would be nicer if we could keep X's network abilities for the local network, only blocking them against outside access, but I couldn't find a way to do that.
bind interfaces only = TrueAfter /etc/init.d/samba restart, the Samba daemons only listen to our home LAN. They are no longer visible to the outside world. Check with netstat -pan --inet, and by having the system scanned.
interfaces = 192.168.1.1
Exim turns out to have an option local_interfaces (which goes into the MAIN CONFIGURATION section of /etc/exim.conf). This is a list of (IP addresses of) interfaces that exim will listen to. This only works when exim runs as a daemon, independent of inetd. To set this up:
listen-address 192.168.1.1:5865
and now only machines on our own network can connect to it (including the gateway machine that junkbuster runs on, heaven in this example, provided heaven is entered in the Netscape 'Preferences/Advanced/Proxies' menu, not localhost).
0 DaemonPortOptions=Addr=192.168.1.1
in the sendmail.cf file. I did not try this.
Other problem cases may remain: servers which you need in your own network but which cannot be made private, and for which private alternatives do not exist. I have this problem with cannaserver, a system for inputting Japanese characters from the keyboard. Such services must be screened from the outside world by means of a packet-filtering firewall. See section 10 of this article.
One way to configure xinetd for telnet and pop3 is to put in /etc/xinetd.conf:
defaults
{
instances = 10
log_type = SYSLOG daemon
log_on_success += DURATION HOST USERID
log_on_failure += HOST
interface = 192.168.1.1
}
service telnet
{
socket_type = stream
wait = no
user = root
server = /usr/sbin/in.telnetd
}
service pop-3
{
socket_type = stream
wait = no
user = root
server = /usr/sbin/in.qpopper
}
So apart from a general 'defaults' section which specifies the interface, there is a separate section for each service that you want to run. Although the format is completely different, the data for the various sections can be found in your existing inetd.conf. See also man xinetd.conf.
I started xinetd and verified that is is now possible to telnet to heaven both from heaven itself and from earth. However, Secure Design no longer reports that my system has open telnet and pop3 ports! Success! NOTE: from my own machine, telnet heaven succeeds, but telnet localhost does not. xinetd can only bind to one interface; in this case 192.168.1.1, not at the same time to localhost, which is the loopback interface (127.0.0.1).
By now, all other services in /etc/inetd.conf have been commented out. Therefore inetd no longer does anything and we can get rid of it in the boot-up scripts. In Debian, it goes like this:
update-rc.d -f /etc/init.d/inetd removeIts place is taken by xinetd:
update-rc.d xinetd defaultsOK; another step towards security successfully taken.
The output of netstat -pan --inet is now something like:
heaven:~# netstat -pan --inet
Active Internet connections (servers and established)
Proto Local Address Foreign Address State PID/Program name
tcp 127.0.0.1:25 0.0.0.0:* LISTEN 11391/exim
tcp 192.168.1.1:25 0.0.0.0:* LISTEN 11391/exim
tcp 192.168.1.1:139 0.0.0.0:* LISTEN 10761/smbd
tcp 192.168.1.1:5865 0.0.0.0:* LISTEN 1670/junkbuster
tcp 192.168.1.1:110 0.0.0.0:* LISTEN 161/xinetd
tcp 192.168.1.1:23 0.0.0.0:* LISTEN 161/xinetd
tcp 0.0.0.0:515 0.0.0.0:* LISTEN 148/lpd MAIN
udp 192.168.1.1:138 0.0.0.0:* 10759/nmbd
udp 192.168.1.1:137 0.0.0.0:* 10759/nmbd
udp 0.0.0.0:138 0.0.0.0:* 10759/nmbd
udp 0.0.0.0:137 0.0.0.0:* 10759/nmbd
raw 0.0.0.0:1 0.0.0.0:* 7 -
raw 0.0.0.0:6 0.0.0.0:* 7 -
Almost all services now listen to a local interface. The print system is the exception: it listens to address 0.0.0.0 (i.e., everywhere) on port 515. Sure enough, if the system is scanned now, only port 515 is reported as 'open'. In fact some Windows-oriented scan services will report your system as totally 'closed', because they do not scan port 515.
What happened? Simply that earth, the Windows machine, only does three Internet-related things:
To switch IP masquerading and forwarding off, in Debian, you do
One often reads the advice to configure ipchains in such a way that 'everything is blocked by default', and then to make exceptions for the things that you want to allow. Theoretically this may be the right thing, but in practice it leads to much frustration. If everything is blocked, your system will basically not work. You are more or less groping in the dark when it comes to deciding what you have to allow. So I allow everything by default, and then add restrictions one by one. If the system breaks (e.g. no ping, or no Web page viewing) the last restriction has been too drastic, and must be undone. Setting the default policy of a chain to DENY or REJECT can then (again) be the last step, not the first.
I started by taking down the firewall (ipchains -F) and then running a simple firewall script with one rule:
#!/bin/sh
# simple firewall
ipchains -F input
ipchains -P input ACCEPT
ipchains -A input -i ppp0 -p TCP --syn -j DENY -l
This blocks SYN packets coming from the outside interface, enhancing the privacy of the system very considerably. Nobody from the outside can start a connection; outside scan services report that the site is completely closed (some now even call it 'stealthed' or 'invisible'). But we can add more restrictions. That is, we can use more general DENY/REJECT rules, and more specific ACCEPT rules.
Before you add restrictions, it is useful to do some experiments. You can make ipchains-type rules which let packets through while logging them (-j ACCEPT -l). So even if (like me) you do not really know which packets to block, you can see what is going on 'normally' by keeping a window open with tail -f /var/log/syslog in it. Then afterwards you can make rules to block packets which are not 'normal'. I strongly advise you to do your own experiments, and to make rules based on your own understanding.
After a few such experiments, my firewall script in /etc/ppp/ip-up.d looks as follows. This assumes you have no nameserver running, but have the addresses of TWO nameservers provided by your ISP in /etc/resolv/conf. Mind the important backquotes (`)! They may disappear if you cut-and-paste from this page.
#!/bin/sh
# A slightly more complicated firewall
# Find external name server addresses
ns="`grep nameserver /etc/resolv.conf | awk '{print $2}'`"
nameserver1="`echo $ns | sed -e 's/ .*//'`"
nameserver2="`echo $ns | sed -e 's/.* //'`"
# Set up INPUT rules
ipchains -F input
ipchains -P input ACCEPT
# Block outside input from reserved address ranges
ipchains -A input -i ppp0 -s 10.0.0.0/8 -j DENY
ipchains -A input -i ppp0 -s 172.16.0.0/12 -j DENY
ipchains -A input -i ppp0 -s 192.168.0.0/16 -j DENY
# Block TCP connections from the outside
ipchains -A input -i ppp0 -p TCP --syn -j DENY -l
# Block all UDP except nameserver replies
ipchains -A input -i ppp0 -p UDP -s $nameserver1 53 -j ACCEPT
ipchains -A input -i ppp0 -p UDP -s $nameserver2 53 -j ACCEPT
ipchains -A input -i ppp0 -p UDP -j DENY -l
# Allow (for now) but log all ICMP
ipchains -A input -i ppp0 -p ICMP -j ACCEPT -l
# From local net, allow only packets to us and broadcasts
# Forwarding is off, other packets won't go anywhere, but
# now we can log them to detect illegal activity on our net
ipchains -A input -i eth0 -d 192.168.1.1 -j ACCEPT
ipchains -A input -i eth0 -d 192.168.1.255 -j ACCEPT
ipchains -A input -i eth0 -j REJECT -l
# Set up OUTPUT rules
ipchains -F output
ipchains -P output ACCEPT
# Don't send packets out to reserved address ranges
ipchains -A output -i ppp0 -d 10.0.0.0/8 -j REJECT
ipchains -A output -i ppp0 -d 172.16.0.0/12 -j REJECT
ipchains -A output -i ppp0 -d 192.168.0.0/16 -j REJECT
# Block all UDP except nameserver requests
ipchains -A output -i ppp0 -p UDP -d $nameserver1 53 -j ACCEPT
ipchains -A output -i ppp0 -p UDP -d $nameserver2 53 -j ACCEPT
ipchains -A output -i ppp0 -p UDP -j REJECT -l
# Allow (for now) ICMP to the outside, but log
ipchains -A output -i ppp0 -p ICMP -j ACCEPT -l
# We do not have FORWARD rules; forwarding is off
Such a firewall (which you should adapt to your personal tastes and needs) will provide an extra 'shell' around the system. But basically, the security of your system should not depend on the firewall; if only because firewalls are complicated things, and it is far too easy to make mistakes with them. Many other things can be done first to ensure the privacy of your network.