Wrote this for a few people that I work with to clear some things up. It's VERY basic, but covers just enough to get people into trouble. lol
Rick’s TCP/IP primer--------------------
Programming networked applications can be a pain, especially if you’re unfamiliar with how networks work, and what all of the fancy terminology means. I intend to explain the basics, in an easy to understand manner with the hope of easing some of this pain.
TCP/IP (Transmission Control Protocol / Internet Protocol) has emerged as the standard protocol stack used in most network scenarios that a programmer will encounter. There are several protocols in the ‘stack’, but we will focus on the 2 most common, and leave the rest as a research exercise for the reader (if needed, or wanted).
The basis for TCP/IP network is the IP address. In this text I will focus solely on IPv4 (Internet Protocol Version 4), which is still the most widely used protocol on the market. From this point forward it is assumed that when I talk about an IP address, I’m discussing an IPv4 address. Should we all convert to IPv6? Absolutely. Have we? Nope.
I WILL NOT teach you how to be a network engineer, nor will I delve into the details of the protocols, and packets that are passed. If your intention is to get into to packet sniffing, and understanding what SYN and ACK mean, then there are plenty of other texts available on the topic.
This is arguably the most confusing aspect of networking to the programmer. What do these numbers mean? WTF is a netmask?! Thankfully there isn’t any magic here. An IP address is simply a 32-bit number, broken down into 8-bit ‘octets’ like this:
so the first octet (192) can be expressed as 11000000 in binary
and the second (168) as 10101000 and the third and forth (both 1) as 00000001. So all together we have:
Yay! .. well. Not really. What good does that do us? Well, to decide that, we need to figure out what the IP address is used for. Amazingly enough, it’s used just like a mailing address. Computers can use the IP address to locate another computer to send information to, or get information from, and just as your mailing address is broken down to street address, and city/state/zip, the IP address is broken down to Network and Host.
The first portion of the IP address is used to specify a network, and the last portion of it is used to specify the actual host on the network. “But how?!”, you cry, “It’s just a single 32-bit number!”. That’s where the netmask comes in. There are some network/host combinations that can be assumed by the numbers (and fancy words like Network Class), but we won’t concern ourselves with those. Just like the IP address, the netmask is a 32-bit number, broken down into 8-bit octets like this:
and it is used just as the name implies, as a ‘mask’. So let’s take our netmask in binary:
and compare it to our IP address in binary:
What this tells us is that the first 24 bits of the IP address are used as the network address, and the last 8 bits are used as the host address. Any bit that lines up with a '1' in the mask, is considered to be part of the network address, and any bit that lines up with a ‘0‘ in the mask, is considered to be part of the host address. So this computer is host 1 on network 192.168.1. Now, those thinkers among you are probably already formulating some pretty gnarly combinations of network/host, and although they will work on some systems (I’ve tried a few), I recommend sticking with all of the network bits on the left, and host bits on the right.
You may have already latched on the the number ‘24‘, when I said that it was how many bits were used for networking, and if that looks familiar, then you’ve most likely been exposed to people who use the abbreviated addressing scheme. This address can be express as:
IP Address: 192.168.1.1
OR, in the abbreviated form of:
which is to say, “24 bits of networking”.
Now, at first glance it might appear that there are 256 usable addresses in the 192.168.1.0/24 (pay attention to how I wrote that) network, but 2 of those addresses are reserved for special use. In every IP network, the very first (or lowest/all 0s) host address is reserved as the ‘network’ address, and the last (or highest/all 1s) is reserved as the ‘broadcast’ address. We’ll deal with broadcast later, but the network address is generally used to label a network. So when I’m talking about the network that our IP address lives in, I refer to it as the 192.168.1.0(/24) network. This IP address cannot be assigned to a host on the network, and neither can 192.168.1.255.
The one last question that is burning in your mind, I’m sure, is what happens if I plug a computer with IP 192.168.1.1/24 into a computer with IP 192.168.2.1/24. Can they talk to each other? No, they cannot. Those two computers are on separate logical networks (192.168.1.0/24 and 192.168.2.0/24), and therefore will not be able to talk to each other without the use of a router. Which segues nicely into our next section:
If your computer decides that it needs to send packets to a computer on the same network as itself, it simply sends those packets to the IP address on the local network (There are other protocols used to take this to the physical level, but we’re not interested in those.) This is all well and good, and things would be an awesome, happy place if we all lived on the same network, but what happens when I want to connect to a computer that is NOT on my local network?
Your computer holds what is known as a routing table, that it uses to make these decisions. The routing table can be simplified as the following pseudo code:
if destination_network == my_network:
elif destination_network in static_routes:
So you saw the term ‘default gateway’ buried in there and got excited? It’s exactly what you think it is. The default gateway/route is where your computer will send packets that it otherwise doesn’t know what to do with. The one issue with gateways, that must always be remembered, is that they MUST reside in the same network as your computer. So if I have an IP address of 192.168.1.35/24 and a default gateway of 192.168.1.254, then I’m golden, but a gateway of 192.168.2.1 absolutely will not work. The gateway must be reachable on a network that is local to the computer wishing to use it.
The magic behind the gateway is that it’s connected to 2 or more networks, with additional routing information to take the packet either further down the line, or to the destination itself.
Let’s imagine, for a moment, that I have 3 linux machines. Two on separate networks, and a third that is on both networks. They’re configured like so:
now, the cool part here is that we can use MACHINE3 as a router to let MACHINE1 and MACHINE2 talk to each other. Firstly, MACHINE3 would need to have ip forwarding enabled:
MACHINE3:/# echo 1 > /proc/sys/net/ipv4/ip_forward
Then we would need to add a static route to MACHINE1:
MACHINE1:/# ip route add 192.168.5.0/24 via 192.168.1.10
w00t! We did it! Let’s ping and test:
MACHINE1:/# ping 192.168.5.22
Sadly, this won’t work. Can you figure out why? The packet actually goes out to the router, and the router sends the packet to MACHINE2, at which point MACHINE2 attempts to reply by sending a response back to the source IP address (192.168.1.25). Uh oh! MACHINE2 doesn’t have a route back to 192.168.1.25. This is a HUGE gotcha, and still bites me every now and again. So let’s fix that:
MACHINE2:/# ip route add 192.168.1.0/24 via 192.168.5.10
again, note that the gateway address for this route is on the same network as MACHINE2, which is an absolute must. I can’t stress this fact enough, simply because I catch technicians trying to enter routes to ip addresses on a completely different network ALL THE TIME.
So, now our ping should work.
One more thing I feel that I must mention is the concept of NAT (Network Address Translation), AKA Firewalling or Masquerading. A NAT device has two or more interfaces, and acts as a router with one special exception. It proxies connections on one side, to connections on the other side. In this way we can have a single Internet IP address on our firewall/wireless router/whatever and an entire network of IP addresses on the private network. Whenever a packet traverses the NAT device, it sends the packet out, on behalf of the private address, and returns whatever packets get sent back for that connection. The details involved (connection tracking, etc) go beyond the scope of this text, but suffice it to say that connectionless protocols like UDP tend to not work without special port-forwarding in the NAT device.
--TCP (Transmission Control Protocol) is the most commonly used protocol on the Internet. It uses handshakes, error checking, and flow control to ensure that the data you’re sending is actually getting to where it’s going. It uses a basic three-step handshake to establish a connection which roughly goes like this:
Source machine: Hey, you there, do you have a service on this port? Write me back on my port number (some random port above 1024) if you do. (SYN)
Destination machine: Why yes, kind sir, I actually do have a service on that port. (SYN-ACK)
Source machine: Ok then, cool, I have some data for you. (ACK)
In this way, TCP is able to ensure that the connection is valid. This seems pretty simple, but in reality it’s not at all. Without all of the connection tracking, handshaking, etc you would simply be throwing packets at something, hoping that they got there. In fact there’s a name for that:
--UDP (User Datagram Protocol) is most commonly used where speed is far more important than data integrity. There is no handshaking or error checking. Our example above would look like this:
Source machine: Hey, you there, here’s some data on a port.
Source machine: <twiddles thumbs>
unless the application on the other end is written to respond, the source machine has NO idea if the packet got where it was going, or if it even got there in one piece. So why would this be useful? Without all of the overhead incurred by TCPs tracking, error checking and handshaking, UDP is much faster, and in applications such as audio, or gaming, where speed is at a premium and a few dropped packets make little-to-no difference, the gain is significant.
This also introduces an interesting concept in the form of broadcasting. Do you remember the broadcast address that was mentioned earlier? Amazingly enough, any packet that is sent to that address is received by every single computer in that network. Now since UDP is connectionless, you can send UDP packets to the broadcast address, and any machine listening on that address (and to the port that you’re sending to) can receive those packets, and because it’s connectionless, you won’t get a crap-ton of errors back from all of the other computers/printers/cellphones that are not. Pretty cool huh?
Hopefully this has cleared up some of the magic behind networking, and will help some of you to get a little further along, with a better understanding of the way things work. If this kind of stuff interests you, then please please please research it further. With VirtualBox, and a few small linux router virtual machines, it is really easy to set up an experimental network, and break things until they work.
D. Rick Anderson