Transmission Control Protocol (TCP) and Internet Protocol (IP) are the native protocols governing most Internet communications. TCP has its roots in the Department of Defense (DoD) Arpanet project and is fully defined in the RFC document #793: Transmission Control Protocol. You are using TCP, along with IP, each time an e-mail is sent or received, a file is downloaded, or a Web site is visited. In this article, I’ll cover the details of TCP and explain how to use UNIX tools to monitor the network and apply security.

What does TCP do?
TCP is one of two transport protocols defined by the DoD. UDP is termed an unreliable service with little overhead, while TCP is considered a reliable service with high overhead. TCP uses sockets, or ports, to facilitate communication. You may be familiar with some common ports like 21 for FT or 25 for SMTP. TCP provides port-to-port communications with error and flow control, as well as end-to-end control of establishing the connection and handling termination and interruption.

Although TCP is considered high overhead compared to UDP, which does not have the additional control features, it takes only about 20 bytes, or 3 percent, to send a 65-Kbps data block. Consequently, the overhead is quite reasonable, given the reliability.

TCP header
Let’s take a closer look at a TCP header. A minimal header requires 20 octets, with the information shown in Table A.

Table A
Source port 16 bits This is the number of the calling port.
Destination port 16 bits This is the number of the called port.
Sequence number 32 bits This number ensures that data is processed in the right sequence. The number represents the byte sequence number of the first octet of the enclosed data and will be incremented accordingly in subsequent segments.
Acknowledgement number 32 bits This represents the next expected TCP octet.
Data offset 4 bits This is the number of 32-bit words in the TCP header.
Reserved 6 bits This is set to zero.
Flags 6 bits These control the setup and termination of the connection, and data flow:
URG—Urgent pointer field significant
ACK—Acknowledgement field significant
PHS—Push function
RST—Reset connection
SYN—Synchronize sequence numbers
FIN—No more data from sender
Window 16 bits This is the receive window size, indicating the number of octets the sender is willing to accept.
Checksum 16 bits This is a checksum based on the IP address fields and the TCP header and length.
Urgent pointer 16 bits This points to the first octet that follows the urgent data, allowing the receiver to know how much urgent data is coming.
Options variable Currently, only the maximum TCP segment size is defined.

The actual data stream follows the header. When used in conjunction with IP, an IP header that takes care of routing the information between the two hosts using their IP address information would prefix the TCP header. Figure A shows how a TCP header will appear.

Figure A
TCP header

Network analysis
A number of programs, such as tcpdump and Ethereal, allow logging and diagnosis of TCP headers and data. These types of programs serve a useful network analysis function, and they can intercept data intended to be private communication. That’s why security folks are adamant about using ssh rather than Telnet to log in to a remote machine and why they use VPN-encrypted tunnels and PGP/GPG encryption of e-mail messages to protect them from prying eyes.

To illustrate, look at this track of a Telnet login on my local network of the user tcpguest with password tcp, using a program called Sniffit. This is the actual login session at the client machine:
bash-2.03$ telnet powerbook
Connected to powerbook.
login: tcpguest
Last login: Sun Feb 17 10:58:01 from moe
[tcpguest@powerbook tcpguest]$

Figure B shows what Sniffit displays by watching port 23 (Telnet) on the destination machine.

Figure B
Sniffit Telnet

Now let’s look at the same user logging in to the same machine via ssh:
bash-2.03$ ssh tcpguest@powerbook
tcpguest@powerbook’s password:
Last login: Sun Feb 17 11:10:00 2002 from moe
[tcpguest@powerbook tcpguest]$

Figure C shows the result.

Figure C
Sniffit ssh

This should be enough to illustrate why methods of accessing other machines using clear text passwords are generally frowned upon these days.

As you may have noticed from the Sniffit screen shots, TCP communications on an IP-based system (and that includes most networks these days, along with the Internet) is all about IP addresses and ports. The IP layer gets the data from one machine to another. The TCP layer passes the data back and forth to the appropriate ports. For this to work, the machine at the other end of the communication path must have software listening to the port that can respond to the request. The software is generally a server daemon of some type and can perform a variety of tasks, not only network services but also things such as power monitoring and management. For the previous examples, the machine I was accessing was running both Telnet and ssh servers that watch ports 23 and 22, respectively, for requests for access to the system.

A highly secure system may not have any servers running, or it may have only selected ports enabled for ssh or other necessary services. Servers can either be triggered to be brought up by inetd or xinetd, or they can be run independently at system boot by scripts in /etc/rc.d/init.d on many Linux systems.

Scanning ports
A common practice crackers use is to scan a system for open ports and then try to apply various attack methodologies to exploit those open ports and gain access to a system. Bugs are regularly uncovered in various server programs, and if you are running services open to the Internet, you need to stay current on security updates for the package in question.

So how do you know what ports are open on a machine before the crackers let you know? Netstat is one tool. Netstat -t will list the active TCP connections, as shown in Listing A.

In this case, it’s the machine I’m sitting at while I write this piece. I have xmms playing an Internet radio station (the lsac2-1-s01.shoutc entry), 2 IRC sessions on two different servers, and the previous Telnet session to the laptop. Commonly known ports will be listed by name or, if you prefer numerical listing of IP addresses and ports, you can add the -n option. This shows my active connections, but what ports do I have open listening for access? If you add the -a option to the netstat command, you’ll see listings for active listening ports on the machine, as shown in Listing B.

So in this case, my machine is running an sshd server to allow remote login via ssh. A common practice is to review what ports you have open and close down services you don’t need, so you can reduce your vulnerability to attack. Adding a firewall with port forwarding inside your Internet connection allows you to select which ports will be available for outside access, perhaps having more services available only on your internal network.

If you want to scan your own systems or a friend’s, tools like Nmap and Nessus will run a sequence of scans against an IP. You shouldn’t arbitrarily point these tools at another system without permission, or your actions may be interpreted as a crack attempt. There are also automated, Web-based scanning services, such as, that perform a scan against your IP address and display or e-mail you the results.

Services that inetd will automatically trigger (if the server is installed) are listed in /etc/inetd.conf, or you can refer to the definitive list at IANA. You can disable services by adding # in front of the entry. For xinetd, each service has its own configuration file under /etc/xinetd.d.

Deny access
You can also run services and limit what machines can access them by using tcp_wrappers, which provides the files /etc/hosts.deny and /etc/hosts.allow. Tcp_wrappers is generally provided in most Linux distributions. Adding this entry in hosts.deny blocks all outside access:

Then, you can selectively turn on access in hosts.allow:
sshd: 192.168.192.

This allows ssh access to the machine from all IPs in the 192.168.192. subnet. Entries in hosts.allow override the hosts.deny directive. Tcpdchk is part of tcp_filters. It will check that your entries in the hosts.* files are correct and issue any possible warnings. You can use tcpdmatch to test the behavior (see Listing C).

You can see by this output that ssh access is granted for IP, as it is in our local subnet, which we allow, but access for will be denied.

That about does it for common commands you can use to see and control what TCP ports are available on your system. In the next installment, we’ll look at an example of how you can use TCP via UNIX sockets in writing a program to monitor a port and respond to a request.