Foundations of Python Network Programming

(WallPaper) #1
Chapter 2 ■ UDp

29

First, doing a connect() on a UDP socket does not send any information across the network or do anything to
warn the server that packets might be coming. It simply writes the address into the operating system’s memory for use
when you later call send() and recv().
Second, please remember that doing a connect()—or even filtering out unwanted packets yourself using the
return address—is not a form of security! If there is someone on the network who is really malicious, it is usually easy
enough for their computer to forge packets with the server’s return address so that their faked replies will make it past
your address filter just fine.
Sending packets with another computer’s return address is called spoofing, and it is one of the first things that
protocol designers have to think about when designing protocols that are supposed to be safe against interference.
See Chapter 6 for more information about this.


Request IDs: A Good Idea

The messages sent in both Listings 2–1 and 2–2 were simple ASCII text. But if you ever design a scheme of your own
for doing UDP requests and responses, you should strongly consider adding a sequence number to each request and
making sure that the reply you accept uses the same number. On the server side, just copy the number from each
request into the corresponding reply. This has at least two big advantages.
First, it protects you from being confused by duplicate answers to requests that were repeated several times by a
client performing an exponential backoff loop.
You can see easily enough how duplication could happen. You send request A. You get bored waiting for an
answer, so you repeat request A. Then you finally get an answer, reply A. You assume that the first copy got lost, so you
continue merrily on your way.
However, what if both requests made it to the server and the replies have been just a bit slow in making it back?
You received one of the two replies, but is the other about to arrive? If you now send request B to the server and start
listening, you will almost immediately receive the duplicate reply A and perhaps think that it is the answer to the
question you asked in request B, and you will become confused. You could, from then on, wind up completely out of
step, interpreting each reply as corresponding to a different request than the one you think it does!
Request IDs protect you against that. If you gave every copy of request A the request ID #42496 and request B the
ID #16916, then the program loop waiting for the answer to B can simply keep discarding replies whose IDs do not
equal #16916 until it finally receives one that matches. This protects against duplicate replies, which arise not only in
the case where you repeated the question, but also in the rare circumstance where a redundancy in the network fabric
accidentally generates two copies of the packet somewhere between the server and the client.
The other purpose that request IDs can serve, as mentioned in the section “Promiscuity,” is to provide a deterrent
against spoofing, at least in the case where the attackers cannot see your packets. If they can, of course, then you are
completely lost: they will see the IP, port number, and request ID of every single packet you send and can try sending
fake replies—hoping that their answers arrive before those of the server, of course—to any request that they like! But
in the case where the attackers cannot observe your traffic and have to shoot UDP packets at your server blindly, a
good-sized request ID number can make it much less likely that your client will accept their answer.
You will note that the example request IDs that I used in the story I just told were neither sequential nor easy
to guess. These features mean that an attacker will have no idea what is a likely sequence number. If you start with 0
or 1 and count upward from there, you make an attacker’s job much easier. Instead, try using the random module to
generate large integers. If your ID number is a random number between 0 and N, then an attacker’s chance of hitting
you with a valid packet—even assuming that the attacker knows the server’s address and port—is at most 1/N and
may be much less if he or she has to try wildly hitting all possible port numbers on your machine.
But, of course, none of this is real security—it just protects against naive spoofing attacks from people who cannot
observe your network traffic. Real security protects you even if attackers can both observe your traffic and insert their
own messages whenever they like. In Chapter 6, you will look at how real security works.

Free download pdf