Internetworking Part 2 - The Transport Layer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [ Copyright (C) 2003 by rattle ] [ http://www.awarenetwork.org/ ] __________ [ Contents ] ЇЇЇЇЇЇЇЇЇЇ ::[0] Introduction ::[1] The Transmission Control Protocol :.. : ::(1.1) TCP Segments : ::(1.2) Safe Delivery and TCP Timers : :.. : : ::{1.2.1} Retransmission Timer : : : ::(1.3) Sliding Windows : ::(1.4) The TCP Header : :.. : : ::{1.4.01} Source Port : : ::{1.4.02} Destination Port : : ::{1.4.03} Sequence Number : : ::{1.4.04} Acknowledgement Number : : ::{1.4.05} Offset : : ::{1.4.06} Reserved : : ::{1.4.07} Flags : : ::{1.4.08} Window Advertisement : : ::{1.4.09} Checksum : : ::{1.4.10} Urgent Pointer : : ::{1.4.11} Options and Padding : : : ::(1.5) Establishing a Connection : :.. : : ::{1.5.1} Step One - Request : : ::{1.5.2} Step Two - Reply : : ::{1.5.3} Step Three - Connection : : : ::(1.6) Closing a Connection : ::[2] Advanced Portscanning :.. : ::(2.1) What is Portscanning? : ::(2.2) NMAP stealth scanning : :.. : ::{2.2.1} SYN Stealth : ::{2.2.2} FIN Stealth : ::[3] The User Datagram Protocol :.. : ::(3.1) The UDP Header : :.. : : ::{3.1.01} Source Port : : ::{3.1.02} Destination Port : : ::{3.1.03} Length : : ::{3.1.04} Checksum : : : ::(3.2) UDP spoofing : ::[A] Ports :.. : ::(A-1) Well-known ports : ::(A-2) Registered ports : ::(A-3) Dynamic ports : ::[B] Sockets : ::[4] Last Words _ ______________ [0] :: [ Introduction ] Ї ЇЇЇЇЇЇЇЇЇЇЇЇЇЇ Hello boys and girls. This is actually the second part of a set of tutorials I am writing about networking protocols, techniques and algorithms. I would definitely recommend to read the first part before you read on here for a complete understanding of what I am trying to convey. You can find it here: http://rs.box.sk/papers/ip.txt So now about this tutorial: Why should you know anything about the transport layer? Because it is essential for understanding how data is being transferred within the large networks of today - like, for instance, the internet. You will mainly learn about TCP (Transmission Control Protocol) here since I consider it the most popular protocol as far as transport layer protocols are concerned. It is widely used and a bit complex as well - and we don't just want to scrap the surface this time, you won't get away with a schematic summary of the three way handshake. Besides an indepth explanation of TCP, you will also learn about UDP (User Datagram Protocol), which is rather easy to understand and which also offers less goodies than TCP. If you did not understand the words "protocol", "network", or "layer" - please read my first tutorial or refer to some more basic stuff. Also, if you are an expert and if you feel to elite for this, go read something else. This tutorial is not for complete newbies, neither was it written for networking gurus. You need to be familiar with high level application-layer networking and some average knowledge about programming in C. I will try to express everything as simply as possible and as detailed as necessary, and I just hope you will enjoy it. Perhaps it helps you understand the things that I did not understand when reading the first tutorials about networking protocols at ease. As always, the appendixes are important. I would definitely recommend to read them if you are not sure that you know everything about ports and sockets. Almost no knowledge is required to read [A], some coding background could be useful for [B] but is not necessary. However, both provide an important background knowledge for many parts of this paper. Have a look at least. _ ___________________________________ [1] :: [ The Transmission Control Protocol ] Ї ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ So, if you already know IP, you should also know that TCP as a transport layer protocol is responsible for safe exchange of data. "Safe" in this context means that no data is lost, altered after transmission or violated in any way. While IP merely offers a channel to route packets through from one host to the other, TCP needs to make sure that one chunk of data is still the same chunk of data when it has been sent and received by the remote host. (No idea what I am talking about? Read the first tutorial ...) Furthermore, TCP is "connection-oriented". While IP sends raw packets from one router to the next one, TCP wants to exchange data a bit more organized and in this very order: 1.) establish a connection 2.) send and exchange data 3.) close connection This probably seems quite simple to you since TCP is usually implemented by the operating system and not even programmers have to care about what it does. However, remember IP and its chaotic treatment of packets: packets get lost, packets are blindly routed to their destination until their TTL exceeds and if it does not work, they are discarded. Sure, I am exaggerating here, but it is obvious that finding a suitable way to provide connection-oriented and safe data exchange is not easy if all you can rely on is IP. This time and for TCP only, I will not start with explaining the TCP header - because too much would have to be left open and everything would get too complicated. I will explain some basic theory behind the way TCP works at first, then the header explanation will follow. I won't explain how a connection is established and closed either yet, you will read about this in the last part. ___ ______________ (1.1) : ( TCP Segments ) ЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇЇ TCP uses so-called segments to split up one chunk of data that has to be sent. Think of this procedure as of the way IP splits up data into packets, since it is fairly the same procedure. The size of one segment mainly depends on the MTU (Maximum transfer Unit) of the respective network. Let's assume we are using a normal ethernet line. In this case, the network layer gives us an ethernet frame size of 1518 byte. The network layer itself needs 18 byte for its header, IP needs 20 bytes and the TCP header itself has a size of 20 bytes as well. Therefore, the MSS in a normal ethernet would be: 1518-18-20-20 = 1460 Byte ___________________________________________________________________________________ | | | Note, in case you are wondering: | | | | TCP does not have to care about whether the networks between the originating and | | the remote host might have smaller MTU's than itself, because it can rely on IP | | in this case - IP will once again split the segment up into packets if the | | segment is too large for a certain network. | |___________________________________________________________________________________| Now as one host connects to another one, a certain problem might occur: One host has a larger MSS than the other one. So it would not be very effective if one host merely uses his own MSS to define the segment size, upon connection establishment both hosts need to find an agreement. In fact, this is quite simple: 1.) Host A connects, sends his MSS 2.) Host B accepts the request, sends his MSS 3.) Both of them compare their own MSS to the one of the remote side and use the smaller MSS for their segments. The MSS of both hosts is sent as a part of the TCP header, and will be explained in detail later - refer to (1.5). From now on, I will refer to a TCP packet as a segment. A packet would not be correct as the segment that is being sent can be split up into packets by IP and therefore is not a real packet. ___ ______________________________ (1.2) : ( Safe Delivery and TCP Timers ) ЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ As I already mentioned, TCP wants to deliver all the segments safely, it wants to ensure that all segments reach their destination. There is only one way to make sure that a segment has been sent successfully - the sender needs to receive an acknowledgement for each single segment that has been sent. Once again, don't worry how this looks in detail. After a segment has been sent to its destination, a retransmission timer is started at the sender's end. If the timer exceeds before an acknowledgement for the segment reaches the sender, the segment is sent again. On the other hand, delivery might be successful and an acknowledgement reaches the sender before the timer exceeds - in this case, the timer stops and the transmission of the segment was successful. That works pretty good as we know, but we still don't know how TCP calculates the timeout value for the timer that is started. The speed of our networks is not always the same, the internet and especially the route used for our segment can be very slow or pretty fast as well - TCP simply does not know. Therefore, a constant value for the timer would not be a good idea. The timer has to be calculated dynamically while data is being exchanged. If you are not interested in how this works, leave out the following part. The calculation of the retransmission timer's timeout value is task of TCP implementations and you don't necessarily need to know about it for an understanding of what will follow. _____ ______________________ {1.2.1} · { Retransmission Timer } ЇЇЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ As TCP has to work in an unstable environment like the Internet, the timeout for the retransmission timer has to be calculated dynamically. The algorithm that is mainly being used to achieve this was invented by Van Jacobson and works as follows: For every connection, TCP uses a variable called RTT (Round Trip Time) to represent the currently best guess at how long it takes for a segment to reach the destination and for the acknowledgement to be sent. The RTT basically represents the time that is assumed to pass until the acknowledgement reaches the sender. Whenever an acknowledgement for a segment reaches the sender before the appropriate timer exceeds, TCP measures the time that has passed instead of the calculated timeout. This so-called Sample Round Trip Time (SRTT) is used to recalculate the RTT: RTT = (alpha * RTT) + ((1 - alpha) * SRTT) Now what about alpha? It is a constant value that expresses how important the new measured SRTT is for the new RTT. alpha is usually a value between 0.8 and 0.9, 0.875 is a popular value. Besides the RTT, TCP also uses two further variables. Obviously, it uses a variable for the actual Time Out value which is referred to as RTO. The third variable called MDEV is used to calculate the RTO from the RTT: RTO = RTT + (4 * MDEV) MDEV represents the average absolute error - we allow the acknowledgement to take 4 times the MDEV longer than expected (as the RTT is the time we would expect). As you might have guessed, the MDEV is a variable as well and is calculated as follows: MDEV = (betha * MDEV) + ((1 - betha) * |RTT - SRTT|) betha is once again a constant value which should be smaller than alpha, Jacobson himself suggested a value of 0.75 for this constant. This is a pretty nice and smooth algorithm now and it works pretty good. There have been several different algorithms to calculate the RTO in the past, but I consider this technique the most modern and most accurate way to do so. One more thing about the retransmission timer though: What about segments that have to be sent again when their timer exceeds? If an acknowledgement for such a segment reaches the sender before its timer exceeds, we do not know whether this acknowledgement refers to the segment we sent first or to the segment we sent again after the first segment's timer exceeded. Therefore, segments that are sent twice or more often are never used to calculate the RTT or the MDEV. Instead, the RTO is doubled for every segment that has to be sent again. This technique is used by most TCP-implementations. ___ ________________ (1.3) : ( Sliding Window ) ЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ We live in a multithreaded world, and this has seriously affected TCP as well. TCP does not send segment by segment one after the other, it sends multiple segments at the same time. In theory, you think of these segments as part of a "window": <---------------------------- Segments -------------------------------> _________________________________________________ | | | | |_________________________________________________|____________________ | | | | | | | | | | |····|····|····| | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 |·11·|·12·|·13·| ... | | | | | | | | | | |····|····|····| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ | Initial Window | |_________________________________________________| (Figure 1.3.1: The initial TCP window) Figure 1.2.1 shows an initial TCP window that would allow TCP to send 10 segments at once. The segments displayed with points (·) are not being sent yet. After the acknowledgement for segment 1 has reached the originating host (the sender), the window "Slides" to the right side by one and segment 11 is being sent. This goes on like this untill all data is sent - every time the acknowledgement for the first segment in the window reaches the sender, the window slides on. Figure 1.3.2 shows our TCP window after two segments have been sent successfully: <---------------------------- Segments -------------------------------> ..........._________________________________________________ : | | : | | :_________|_________________________________________________|__________ |####|####| | | | | | | | | | |····| |#01#|#02#| 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |·13·| ... |####|####| | | | | | | | | | |····| :ЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇ : | Window Slides ----> | :.........|_________________________________________________| (Figure 1.3.2: The sliding TCP window) This sliding window in our example has a length of 10 segments - but in fact, the window size is variable. This has numerous advantages: - TCP can react when there is a problem or a very slow network between the sender and the receiver. This is known as congestion avoidance. - Imagine two differently strong hosts that are exchanging data via TCP, for instance a big server and a small client. The server can send much more data than the client can handle in its small buffer, therefore the ammount of data that is send at once has to be adjusted as well. This is known as flow control. Now as you know why we need flow control, let's see how it's done. Once again, the theory is fairly simple. The receiver sends a window advertisement with every acknowledgement it sends - this window advertisement tells the sender how big his window for sending data should be. The sender, of course, does as he is told and adjusts his window size according to the window advertisement he received. A window advertisement can also set the window size to 0 which stops the entire transfer, until a window advertisement > 0 is sent. ___ ________________ (1.4) : ( The TCP Header ) ЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ Now you have learned enough about the basic TCP theory, let's have a look at the TCP header. As always, the header is sent before the data, and the TCP header directly follows the IP header. <-------------------------------------------- Bits --------------------------------------------> _______________________________________________________________________________________________ |01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | Source Port | Destination Port | |_______________________________________________|_______________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | Squence Number | |_______________________________________________________________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | Acknowledgement Number | |_______________________________________________________________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | Offset | Reserved | Flags | Window Advertisement | |___________|_________________|_________________|_______________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | Checksum | Urgent Pointer | |_______________________________________________|_______________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | Options and Padding | |_______________________________________________________________________________________________| |###############################################################################################| |###########################################[ Data ]############################################| |###############################################################################################| ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ (Figure 1.4.1: The TCP Header Format as explained in RFC 793, part 3.1: http://www.rfc-editor.org/rfc/rfc793.txt) Ok, I will now explain the respective parts of the header in detail, and also explain their function related to each other. ______ ______ _____________ {1.4.01} · {16 Bit} · { Source Port } ЇЇЇЇЇЇ ЇЇЇЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇ The source port is the port that the sender of the respective segment uses for this TCP connection. Please refer to [A] for an explanation of all the different ports and of all kinds of ports. ______ ______ __________________ {1.4.02} · {16 Bit} · { Destination Port } ЇЇЇЇЇЇ ЇЇЇЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ The destination port. Obviously, this port is the port used by the remote host for this particular TCP connection. Again, refer to [A] for more info about ports. ______ ______ _________________ {1.4.03} · {32 Bit} · { Sequence Number } ЇЇЇЇЇЇ ЇЇЇЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ TCP segments will not reach their destination in the same order that they were sent in, some segments might take longer to be delivered and some of them will find a faster way, that depends on IP again. Therefore, the sender uses a sequence number to identify every segment - the sequence number specifies the position of the data sent with the respective segment relative to the complete stream of data. During the data exchange, the sequence number is always increased by the number of bytes that have been sent already. Once again, remember that the sequence number refers to the number of bytes and not to the number of segments that have already been sent. In Fact, the sequence number is used for identifcation purposes - The sequence number is always a unique value, and the receiver will only accept and interpret segments that use the sequence number he expects to receive. For example, the sequence number is also used and continuously increased when a connection is established (and when it is canceled), although no data is being sent at that point of time. Although both the receiver and the sender as well use the complete TCP header for their segments (which is quite logical), the sequence number is only interpreted by the host that is currently receiving data. The sender will receiver an acknowledgement segment by the receiver which contains a complete TCP header as well, but he ignores the sequence number as it is not of any interest for him. Instead, the sender only uses the acknowledgement number in this acknowledgement segment to determine what segments have already been delivered successfully: Refer to {1.4.4}. ______ ______ ________________________ {1.4.04} · {32 Bit} · { Acknowledgement Number } ЇЇЇЇЇЇ ЇЇЇЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ The acknowledgement number is used to send the acknowledgement for a received segment, refer to (1.2). This number always represents the next segment that is expected to be received - therefore, it is the next sequence used by the sender. If the receiver receives a segment with the sequence number X, it sends an acknowledgement with an acknowledgement number of (X+1) to tell the sender what segment is expected to be received now. 1.) receive data segment from sender with Sequence Number X 2.) send acknowledgement segment to sender with Acknowledgement Number (X+1) 3.) receive data segment from sender with Sequence Number (X+1) 4.) ... The acknowledgement number is closely linked to the sequence number as you might already have figured. The acknowledgement number always contains the sequence number that the receiver expects to receive next and therefore, the acknowledgement number, as well, is part of the TCP identification mechanism. ______ ______ ________ {1.4.05} · { 4 Bit} · { Offset } ЇЇЇЇЇЇ ЇЇЇЇЇЇ ЇЇЇЇЇЇЇЇ The offset is merely the length of the TCP header, which is not always the same due to the options field. The name offset was chosen because the data begins at this offset, relative to the position of the header. ______ ______ __________ {1.4.06} · { 6 Bit} · { Reserved } ЇЇЇЇЇЇ ЇЇЇЇЇЇ ЇЇЇЇЇЇЇЇЇЇ Oh how I hate reserved fields. Reserved fields are never used and they will never be used for future implementations. It has never ever happened! Oh well anyway, the reserved field within the TCP header contains, well, nothing. It is currently being ignored and has no sense at all. ______ ______ _______ {1.4.07} · { 6 Bit} · { Flags } ЇЇЇЇЇЇ ЇЇЇЇЇЇ ЇЇЇЇЇЇЇ The TCP flags are used to represent the purpose of a particular segment. <----------------------- Bits ----------------------> _____________________________________________________ ... | 11 | 12 | 13 | 14 | 15 | 16 | ... ЇЇЇЇЇ|ЇЇЇЇЇЇ|ЇЇЇЇЇЇ|ЇЇЇЇЇЇ|ЇЇЇЇЇЇ|ЇЇЇЇЇЇ|ЇЇЇЇЇЇ|ЇЇЇЇЇ ... | URG | ACK | PSH | RST | SYN | FIN | ... _____|______|______|______|______|______|______|_____ (Figure 1.4.07.1: TCP Flags) The 6 bits of the flags field can be set to set the appropriate flag. The meaning of the flags when they are set (or not set) will be explained in detail later, but here is a quick overview: +------+-------------------------------------------------------------------------+ | Flag | Description | +------+-------------------------------------------------------------------------+ | URG | If URG is set, the Urgent Pointer field of the TCP header is evaluated. | +------+-------------------------------------------------------------------------+ | ACK | If ACK is set, the acknowledgement number field is evaluated: this | | | means, that an acknowledgement is being sent. Also, the window | | | advertisement is evaluated only when ACK is set. | +------+-------------------------------------------------------------------------+ | PSH | If PSH is set, the data that the segment contains is not buffered but | | | the respective application listening on the destination port is fed | | | with the data immediately. | +------+-------------------------------------------------------------------------+ | RST | The RST bit is set when the connection has to be terminated immediately | | | in case of an error or when a connection is refused. | +------+-------------------------------------------------------------------------+ | SYN | The SYN bit is set on connection establishment. Refer to (1.5) | +------+-------------------------------------------------------------------------+ | FIN | The FIN bit is set when the connection is closed Refer to (1.6) | +------+-------------------------------------------------------------------------+ To use the field like a bitmask, you might define these constants in a normal C program and use the bitwise OR to combine them as you wish: #define URG 0x20 #define ACK 0x10 #define PSH 0x08 #define RST 0x04 #define SYN 0x02 #define FIN 0x01 ___________________________________________________________________________________ | | | Note, in case you are wondering: | | | | When you use the bitwise OR to combine, let's say the ACK and the SYN flag, this | | is what exactly happens: | | | | Position: 1 2 3 4 5 6 | | | | SYN = 0x02 = 0 0 0 0 1 0 | | ACK = 0x10 = 0 1 0 0 0 0 | | | | Now each bit of the SYN flag is compared to the bit of the ACK flag at the same | | position: | | | | Position 1: 0 OR 0 is 0: 0..... | | Position 2: 0 OR 1 is 1: 01.... | | Position 3: 0 OR 0 is 0: 010... | | Position 4: 0 OR 0 is 0: 0100.. | | Position 5: 1 OR 0 is 1: 01001. | | Position 6: 0 OR 0 is 0: 010010 | | | | The result is a bitmask that contains a bit set at position 2 and 5, which means | | that, relative to the TCP header, the 12th and 15th bit are set. There you are, | | the ACK and SYN flag are set. | |___________________________________________________________________________________| ______ ______ ______________________ {1.4.08} · {16 Bit} · { Window Advertisement } ЇЇЇЇЇЇ ЇЇЇЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ Make sure you have read (1.3) to understand this. This field of the TCP header contains the number of BYTES that the receiver is willing to receive. It is not the number of segments within the window, it is actually the number of bytes. Therefore, if the receiver advertises a window size of 2400 and the MSS that the two hosts use is 380 (one segment has a size of 400, MSS plus the header length of 20) then the window has a size of 6 segments that are sent simultaneously. If the receiver's window advertisement was only 2300, the sender's window would have a size of 6 segments as well, though - the last segment, however, would not contain 380 but 280 bytes. The Window Advertisement field is only evaluated by the sender when he receives an acknowledgement (a segment with the ACK flag set). ______ ______ __________ {1.4.09} · {16 Bit} · { Checksum } ЇЇЇЇЇЇ ЇЇЇЇЇЇ ЇЇЇЇЇЇЇЇЇЇ Calculating checksums, always the same pain in the ass. The TCP checksum, like probably all checksums, is computed as the 16-bit one's complement of the one's complement sum of something. However, TCP is not like IP or ICMP in this case, because it does not calculate the checksum of its own header or its data, but it calculates the checksum of a buffer that contains: [ A pseudo header ] [ The TCP header ] [ The Data ] This pseudo header is never sent, it is never received and it is only used once to calculate the TCP checksum. It contains information from the IP header and the TCP header, which is in fact a violation of the protocol hierarchy. However, it helps TCP to find packets that have not been delivered correctly by IP. The pseudo header contains the following fields: _______________________________________________________________________________________________ |01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | Source IP Address | |_______________________________________________________________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | Destination IP Address | |_______________________________________________________________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 0 | 6 | TCP Segment Length | |_______________________|_______________________|_______________________________________________| (Figure 1.4.09.1: The TCP pseudo header) The field of the pseudo header that is set to 6 actually represents the protocol, but as the TCP pseudo header is used for calculating the TCP checksum, it will always be 6 as this is the number that represents the TCP protocol. The field that is set to 0 is not declared as a reserved field, it just contains zeros to make the pseudo header length a multiple of two bytes. When calculating the checksum, the checksum field of the TCP header is always set to 0 (the TCP header itself is part of the buffer that is used to calculate the checksum, so this has to be clearly defined). Once the receiver calculates the checksum for the segment he receives (without the pseudo header, of course), the result will be zero if the checksum was correct. ______ ______ ________________ {1.4.10} · {16 Bit} · { Urgent Pointer } ЇЇЇЇЇЇ ЇЇЇЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ If the URG flag is set, this field points to the sequence number of the last byte in a sequence of "urgent" data. Although the Urgent mechanism may be used for any application, it is normally used to send 'interrupt'- type commands to a Telnet program. Here's what [RFC793] says about the urgent pointer: "TCP does not attempt to define what the user specifically does upon being notified of pending urgent data, but the general notion is that the receiving process will take action to process the urgent data quickly." Well in real life, urgent data is also referred to as out of band data. To receive out of band data through the socket interface (Refer to [B] for more information about sockets), you can use the MSG_OOB flag on a recv call: #ifdef _WIN32 #include #include #else #include #include #endif int main(int argc, char** argv) { sockaddr_in remote = {0}; int sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); /* ... */ char sUrgent[42] = {0}; // buffer for urgent data recv(sock,sUrgent,42,MSG_OOB); // receive out of band, aka urgent data if (*sUrgent) printf("Very urgent: %s", sUrgent); return 0; } ______ ___________ _____________________ {1.4.11} · {0-44 bytes } · { Options and Padding } ЇЇЇЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ Options are a very famous concept to allow improvement, enhancement or an extension of an existing protocol. I like them much more than "reserved" fields, they are more flexible and dynamic. Think of an option as of a little, additional header that is added to the TCP header at the end - it includes additional information of any kind. An option has always the same format: <---------------------------------- Bits -------------------------------------> ______________________________________________________________________________ |01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20| ... | Length * 8 | |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | Type | Length | Data | |_______________________|_______________________|______________________________| (Figure 1.4.11.1: A general TCP option) The option is identified by its Type (one byte), and the data field as well as its length depend completely on the option. The Length field specifies the length of the complete option in bytes. Two special options do not have a length or a data field: End of Option List: _______________________ The End of Option List "option" is actually just one byte |01|02|03|04|05|06|07|08| byte that is set to 0. Think of it as of a terminating |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| null character. It does nothing but specifying the end | Type = 0 | of all options, it is always the last option when options |_______________________| are sent. No Operation This option, similar to the End of Option List option does _______________________ not have a Length or a Data field. It is one single byte |01|02|03|04|05|06|07|08| that is set to 1. Usually, this option is used for padding |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| the next option up to the next word boundary, but as a | Type = 1 | sender does not have to use this option, receivers must be |_______________________| prepared to process options even if they do not begin on a word boundary. Here is a complete list of all options: +------+--------+-------------------------------------+-------------------------------------------+ | Kind | Length | Description | References | +------+--------+-------------------------------------+-------------------------------------------+ | 0 | 1 | End of Option List. | http://www.rfc-editor.org/rfc/rfc793.txt | +------+--------+-------------------------------------+-------------------------------------------+ | 1 | 1 | No Operation. | http://www.rfc-editor.org/rfc/rfc793.txt | +------+--------+-------------------------------------+-------------------------------------------+ | 2 | 4 | Maximum Segment Size. | http://www.rfc-editor.org/rfc/rfc793.txt | +------+--------+-------------------------------------+-------------------------------------------+ | 3 | 3 | Window scale factor. | http://www.rfc-editor.org/rfc/rfc1072.txt | | | | | http://www.rfc-editor.org/rfc/rfc1323.txt | +------+--------+-------------------------------------+-------------------------------------------+ | 4 | 2 | SACK permitted. | http://www.rfc-editor.org/rfc/rfc2018.txt | +------+--------+-------------------------------------+-------------------------------------------+ | 5 | - | SACK. | http://www.rfc-editor.org/rfc/rfc2018.txt | | | | | http://www.rfc-editor.org/rfc/rfc2883.txt | +------+--------+-------------------------------------+-------------------------------------------+ | 6 | 6 | Echo. | http://www.rfc-editor.org/rfc/rfc1072.txt | +------+--------+-------------------------------------+-------------------------------------------+ | 7 | 6 | Echo reply. | http://www.rfc-editor.org/rfc/rfc1072.txt | +------+--------+-------------------------------------+-------------------------------------------+ | 8 | 10 | Timestamp. | http://www.rfc-editor.org/rfc/rfc1323.txt | +------+--------+-------------------------------------+-------------------------------------------+ | 9 | 2 | Partial Order Connection Permitted. | http://www.rfc-editor.org/rfc/rfc1693.txt | +------+--------+-------------------------------------+-------------------------------------------+ | 10 | 3 | Partial Order Service Profile. | http://www.rfc-editor.org/rfc/rfc1693.txt | +------+--------+-------------------------------------+-------------------------------------------+ | 11 | 6 | CC, Connection Count. | http://www.rfc-editor.org/rfc/rfc1644.txt | +------+--------+-------------------------------------+-------------------------------------------+ | 12 | 6 | CC.NEW | http://www.rfc-editor.org/rfc/rfc1644.txt | +------+--------+-------------------------------------+-------------------------------------------+ | 13 | 6 | CC.ECHO | http://www.rfc-editor.org/rfc/rfc1644.txt | +------+--------+-------------------------------------+-------------------------------------------+ | 14 | 3 | TCP Alternate Checksum Request. | http://www.rfc-editor.org/rfc/rfc1146.txt | +------+--------+-------------------------------------+-------------------------------------------+ | 15 | - | TCP Alternate Checksum Data. | http://www.rfc-editor.org/rfc/rfc1146.txt | +------+--------+-------------------------------------+-------------------------------------------+ | 16 | - | Skeeter. | | +------+--------+-------------------------------------+-------------------------------------------+ | 17 | - | Bubba. | | +------+--------+-------------------------------------+-------------------------------------------+ | 18 | 3 | Trailer Checksum Option. | | +------+--------+-------------------------------------+-------------------------------------------+ | 19 | 18 | MD5 signature. | http://www.rfc-editor.org/rfc/rfc2385.txt | +------+--------+-------------------------------------+-------------------------------------------+ | 20 | - | SCPS Capabilities. | | +------+--------+-------------------------------------+-------------------------------------------+ | 21 | - | Selective Negative Acknowledgements | | +------+--------+-------------------------------------+-------------------------------------------+ | 22 | - | Record Boundaries. | | +------+--------+-------------------------------------+-------------------------------------------+ | 23 | - | Corruption experienced. | | +------+--------+-------------------------------------+-------------------------------------------+ | 24 | - | SNAP. | | +------+--------+-------------------------------------+-------------------------------------------+ | 26 | - | TCP Compression Filter. | | +------+--------+-------------------------------------+-------------------------------------------+ ___ ___________________________ (1.5) : ( Establishing a Connection ) ЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ When two hosts want to establish a connection using TCP, they perform three essential steps before both of them think "Well, now I am connected". This procedure is known as the "Three-Way-Handshake", the most famous TCP buzzword ever. You might have already heard about it, read about how it works and you might already be about to leave out this part of the tutorial because you have read about the three way handshake a million times. However, I would really recommend you to read this part carefully to understand the concept completely. You should definitely read [A] before continuing with this chapter. _____ ____________________ {1.5.1} · { Step One - Request } ЇЇЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ Now we can have a closer look at the actual connection. The host that wants to connect (the client) sends a TCP segment to the server. This TCP segment contains a valid source and destination port number, a SYN flag, no data and the ISN. What is the ISN? It is an Initial Sequence Number - a random number that is chosen when the connection is established. Correct, the sequence number does not start with 0, it starts with a random value. This random ISN has to be subtracted from the sequence number that is sent with all the following segments to get the real byte position. Why is a random value chosen? This has basically just security purposes. Attacks like spoofing or faking packets are close to impossible when you cannot calculate a valid sequence number - segments with invalid sequence numbers will be ignored by the server. So, this is a sample of what the client might send: _______________________________________________________________________________________________ |01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 49155 | 80 | |_______________________________________________|_______________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 1431655765 (random) | |_______________________________________________________________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 0 (ignored, no ACK flag set) | |_______________________________________________________________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 28 | 0 | 000010 (SYN)* | 0 (ignored, no ACK flag set) | |___________|_________________|_________________|_______________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | Checksum (too lazy to calculate) | 0 (ignored, no URG flag set) | |_______________________________________________|_______________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 2 (MSS) | 4 | 1460 (standard MSS) | |_______________________|_______________________|_______________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 0 (End of Options) | 0 (Padding 3 bytes) | |_______________________|_______________________________________________________________________| * the flags field is set to 2. This is 000010 in binary, which means the SYN flag is set. (Figure 1.5.1.1: TCP connection request; client) So what is happening? The client himself has registered the dynamic port 49155 and connects to port 80 on the server - this is the beginning of a normal HTTP request. And what are the last two lines (the last two double words)? This is the MSS option sent with the TCP header. As I told you in (1.1), the MSS is exchanged upon connection establishment. The MSS option is sent within segments that have the SYN (synchronization, sounds logical) flag set. The option itself is pretty simple. The type byte is 2, the length is 4 bytes and the word that specifies the actual MSS of the client is the last field of the option. After the MSS option follows a complete double word full of zeros - one byte to specify the end of the option list and the remaining zeros are used for padding the TCP header length up to a multiple of 32 bit. The offset field is set to 28 instead of the 20 bytes that the "usual" TCP header contains - because of the options. _____ __________________ {1.5.2} · { Step Two - Reply } ЇЇЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ When the server receives this segment, he has two options - tell the client that he can connect or tell him that he can't. The client cannot connect to a port that is not registered on the remote operating system - perhaps there is no HTTP server running on the box. In both cases, the header would look similar, only the TCP flags would change. If the server is willing to establish a connection, he will send a segment with both a SYN and an ACK flag - SYN to signalize that he is sending his own ISN to be synchronized with the client and ACK to acknowledge the ISN that the client has sent. Therefore, the acknowledgement number will contain the ISN of the client plus 1. If, however, the server refuses a connection, he sets only the RST flag and sends a segment with any sequence number he wants. I think you can imagine how the RST segment looks like, so I will only show you how the reply would look like if a connection will actually be established. I will stick to the example in {1.5.1}, you can check back with the numbers there to see what happens: _______________________________________________________________________________________________ |01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 80 | 49155 | |_______________________________________________|_______________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 1717986918 (random) | |_______________________________________________________________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 1431655766 (ACK: 1431655765 + 1) | |_______________________________________________________________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 28 | 0 | 010010 (A,S)* | 7300 (5 segments per window.) | |___________|_________________|_________________|_______________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | Checksum (too lazy to calculate) | 0 (ignored, no URG flag set) | |_______________________________________________|_______________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 2 (MSS) | 4 | 1460 (standard MSS) | |_______________________|_______________________|_______________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 0 (End of Options) | 0 (Padding 3 bytes) | |_______________________|_______________________________________________________________________| * S stands for SYN and A stands for ACK: the flags field is set to 18. This is 010010 in binary, which means the SYN and the ACK flags are set. (Figure 1.5.2.1: TCP connection reply; server) I think it is pretty obvious what's going on - as this is a segment with a SYN flag set, the MSS option is sent again and to keep this as simple as even possible, the server uses the same MSS as the client :-). As the ACK flag is set, the server also sends his window size. 5 * 1460 is 7300 which seemed like a good window count for me. I have no idea if this is a realistic number, but this is just an example after all. Due to the ACK flag, as well, the server send the appropriate acknowledgement number that contains the client's ISN (1431655765) plus one (1431655766). Additionally, the server sends his own ISN (1717986918). Of course, the destination port is now the port that was registered by the client and the server specifies his own port (80) as the source port. Simple, right? I bet you're still with me. _____ _________________________ {1.5.2} · { Step Three - Connection } ЇЇЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ It's almost done - the client sent a request to connect to the server and the server sent a valid reply, with a nice and correct sequence number, the correct acknowledgement number and both of them calculated the checksum correctly (not abig surprise, they got algorithms which perform these tasks for them.) Now it is called a three-way-handshake and the client has to send a final segment that actually establishes the connection. Since everything has been synchronized, the SYN flag will not be set in this segment. However, as the server sent his ISN, the client needs to acknowledge it now. So, you guessed it, only the ACK flag is set. The acknowledgement number is not difficult to guess, it is the server's ISN plus one. The server also sent the correct acknowledgement for the client's ISN and this way he told the client what sequence number has to be sent next. Well, as the ACK flag is set, the client will also send his own window advertisement this time, but there is not much to wonder about this time. This is how the last segment, referring to our example, would look like: _______________________________________________________________________________________________ |01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 49155 | 80 | |_______________________________________________|_______________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 1431655766 (Using the server's last acknowledgement number) | |_______________________________________________________________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 1717986919 (ACK: 1717986918 + 1) | |_______________________________________________________________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 20 | 0 | 010000 (ACK)* | 7300 (5 segments per window.) | |___________|_________________|_________________|_______________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | Checksum (too lazy to calculate) | 0 (ignored, no URG flag set) | |_______________________________________________|_______________________________________________| * the flags field is set to 16. This is 010000 in binary, which means the ACK flag is set. (Figure 1.5.3.1: TCP connection established: final segment of three-way-handshake) This time we don't send any options: The offset field of the TCP header is set to 20. You might have noticed that the client uses the same window size as the server - this is just an example. When a connection is established, the smaller one of both window advertisements is used by both ends of the connection, similar to how the MSS is handled. Those who are chronically pessimistic and those who use nmap might have thought about how the client can cancel the connection even at this point. Yes indeed, the client does not have to send the final acknowledgement to establish the connection - he can also send an RST segment. Sounds a bit strange, huh? One would think that the client would not want to cancel the connection he just tried to establish. However, there are numerous reasons to cancel the connection at this point of time: - The client application might have crashed - The server's reply can be invalid - The server's reply might contain specifications that don't appeal to the client. Now let's assume the server sent a wrong acknolwedgement number - what sequence number would be used for the RST segment? The sequence number that would usually follow or the wrong one that the server expects to receive? The wrong one. We have to use the sequence number that the server expects to receive because he would ignore the segment if the sequence number was not his previous ack number. Furthermore, the client does not send an acknowledgement as no ACK flag is set. As always, I am referring to the sample we used all the time - this is how such an RST segment sent by the client might look like: _______________________________________________________________________________________________ |01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 49155 | 80 | |_______________________________________________|_______________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 1431655766 (Using the server's last acknowledgement number, even if it was wrong!) | |_______________________________________________________________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 0 (ignored, no ACK flag set.) | |_______________________________________________________________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 20 | 0 | 000100 (RST)** | 0 (ignored, no ACK flag set) | |___________|_________________|_________________|_______________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | Checksum (too lazy to calculate) | 0 (ignored, no URG flag set) | |_______________________________________________|_______________________________________________| ** the flags field is set to 4. This is 000100 in binary, which means the RST flag is set. (Figure 1.5.3.2: TCP connection reset: final segment of three-way-handshake) So, I hope you're still with me, let's move on to the next chapter. ___ ______________________ (1.6) : ( Closing a Connection ) ЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ Whereas establishing a connection takes 3 steps, closing a connection requires 4 steps. Why does it have to be so complicated? Well, both sides can send and receive data at the same time - this means that both sides might be sending data when one side wants to close the connection. Thus, both sides of the connection have to announce a closing of the connection independantly as well. However, it is not as complicated as you might think. Although 4 steps are required to completely close the connection, the complete procedure is not as tricky as establishing a connection - each host performs only 2 steps and both hosts basically do the same. In this chapter I will refer to the sample in (1.5), here are the sequence numbers again so you don't have to scroll up every time you need to check back. And believe me, you should check back and really understand what number is used or inreased when and how. Client ISN: 1431655765 = 0x55555555 Server ISN: 1717986918 = 0x66666666 (I bet you didn't figure. Bad coder humor I guess ...) One of the two hosts has to initiate the process once he does not want to send any more data. This is important to understand the terminology used by TCP - closing means that no more data is sent. If the client closes the connection, he declares that he will not, by no means, send any more data to the server. The client still has to receive data sent from the server - until the server himself closes the connection. Don't worry, here are the details: Let's assume the client wants to disconnect - In this very case, he sends a TCP segment that contains the FIN and the ACK flag. This segment uses the client's ISN as the sequence number and the server's ISN as the acknowledgement number - pretty simple actually. _______________________________________________________________________________________________ |01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 49155 | 80 | |_______________________________________________|_______________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 1431655765 (Client ISN) | |_______________________________________________________________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 1717986918 (Server ISN) | |_______________________________________________________________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 20 | 0 | 010001 (A,F)* | 7300 (still receiving data) | |___________|_________________|_________________|_______________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | Checksum (too lazy to calculate) | 0 (ignored, no URG flag set) | |_______________________________________________|_______________________________________________| * F stands for FIN, A stands for ACK. The flags field is set to 17, this is 010001 in binary: The ACK and the FIN flag are set. (Figure 1.6.1: client closes the connection) This is not too complicated. After the client has sent this segment, he does not send any more data and waits for the server to acknowledge the FIN segment. If the server does not reply until the timer for this FIN segment times out, the client sends it again, though. Now the server will acknowledge this FIN segment like any other segment. The server uses his own ISN as the sequence number, since this was the last acknowledgement number used by the client - he used it in his FIN segment. TCP is very strict here, a host always has to use the sequence number that was "requested" by the previous acknowledgement number in a segment from the other side of the connection. Furthermore, as we send an acknowledgement, the ACK flag is set and he acknowledgement numer field contains the client ISN plus one. _______________________________________________________________________________________________ |01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 80 | 49155 | |_______________________________________________|_______________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 1717986918 (Server ISN - the value of the clients previous acknowledgement number.) | |_______________________________________________________________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 1431655766 (Client ISN + 1) | |_______________________________________________________________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 20 | 0 | 010000 (ACK)** | 0 (won't receive any more data) | |___________|_________________|_________________|_______________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | Checksum (too lazy to calculate) | 0 (ignored, no URG flag set) | |_______________________________________________|_______________________________________________| ** The flags field is set to 16, this is 010000 in binary: The ACK flag is set. (Figure 1.6.2: server acknowledges FIN segment from client) It is not a strict TCP rule that the window advertisement has to be zero in this kind of acknowledgement, but it seems logical to set it to zero as no more data is expected to be received. Now the server finishes sending his data to the client and then he performs the same procedure - but of course, the sequence number he uses for his FIN segment is HIS own ISN and so on. I don't think I have to explain this in detail. Now after each the client and the server (both sides of the connection) have announced that they want to close the connection, the connection is, well, closed. No more data will be sent and both sides forget about the synchronized data they had stored, like the ISN's, the MSS and any other stuff used during the data exchange. _ _______________________ [2] :: [ Advanced Portscanning ] Ї ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ Note - this chapter is not required for any part of this tutorial or any tutorial that belongs to my Internetworking series. It is just for fun, if you know nmap and if you want to know how it works. Now as you have learned about TCP and pretty much all the important facts about how it works, it is nice to see that this knowledge is actually good for something. Knowledge about how TCP initiates a connection is useful to understand the SYN stealth scan that nmap uses to determine the open ports on a computer. Make sure that you have read [A] as well as [B] and (1.5) before you read on, because I will refer to many things I explained in these chapters. ___ _______________________ (2.1) : ( What is Portscanning? ) ЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ Portscanning is the process of determining what ports on a certain machine are open and which are closed, basically. Some people will tell you that every attempt to break into a server starts with a portscan - because the portscan can tell you which services are running on the computer you are scanning. A service is basically just another name for a server application, like an FTP server listening on TCP port 21 or anything else. These server application provide services to the client and sometimes the client is able to abuse the services offered to him. More details about this would lead much too far, so let's concentrate on the portscan itself. I will explain here what would probably called the "classic" portscan. This method is also known as a connect-portscan. This merely refers to the connect() call I told you about in [B]. A portscanner is basically a program that uses the connect() call, trying to connect to the computer that is being scanned on a wide range of possible ports. Once the program can establish a connection on a certain port, the one who uses the scanner knows that the port is "open", meaning that the server accepts connections on this port. If it accepts connections on this port, there is a service running and listening on that port - and this service might be abused, giving a potential attacker the oportunity to gain access to the system. However - it is not as simple as that, fortunately. This is a sample connect() portscanner in python - it is a simple and single-threaded sample, but I'm sure it would work. I would give you a sample in c, but that would be much more work as I have to do a lot of error checking and other stuff myself in c. Check http://www.pyton.org/ if you want to know more about this great language ... from socket import * import sys FALSE = None; TRUE = 1; def ScanPort(sServer, iPort): bReturn = TRUE s = socket(AF_INET,SOCK_STREAM) try: s.connect((str(sServer),int(iPort))) except: bReturn = FALSE if (bReturn): s.close(); del s; return bReturn; if __name__ == '__main__': i1Port = 1; # lowest valid port i2Port = 2**16; # highest valid port: 16 bits sServ = sys.argv[1] if (len(sys.argv)>3): i1Port = int(sys.argv[2]); i2Port = int(sys.argv[3]); for i in range(i1Port, i2Port+1): if (ScanPort(sServ,i)): print "Open Port:", i What is the problem with connect-portscanning? Every time an open port is open on the remote machine, the application connects completely and disconnects again. Of course, it is not only possible to log these scans on the server easiely, it is done by default usually. Since a malicious hacker was really planning to compromise the server, he would not want to get logged and caught while he is just begging to prepare for an attack by scanning the server ... From his point of view, a much more stealthy method had to be invented ... ___ _______________________ (2.2) : ( NMAP stealth scanning ) ЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ nmap is a portscanner with many more nice and interesting features. It was made by the good guys at http://www.insecure.org/ and was the first portscanner (as far as I know) that used the so-called SYN stealth scan. SYN sounds pretty familiar and with the background knowledge about TCP that you should have by now, you might have already figured how it works. Anyhow, other methods have been developed by the nmap coders as well to perform stealthy scans and I will discuss the two of them that I consider directly related to the topic of this paper. _____ _____________ {2.2.1} · { SYN Stealth } ЇЇЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇ Pretty much the most famous stealth port scan. Check back with (1.5), as this scan is based on the way in which a connection is established. You know, the client sends a SYN packet to request that a connection is established and then the server replies with his own SYN|ACK segment to establish the connection or with an RST segment to reject the request. The SYN stealth scan is pretty simple - The portscanner sends the SYN packet and waits for a reply. If an RST packet is returned, the port that is currently being probed is closed. Now if a SYN|ACK packet is returned however, the client already knows that the port he is currently probing is open on the server. Now instead of really establishing the connection like a connect-portscanner would do, nmap immediately sends an RST segment to tell the server that some critical error has occured on the client side and that the connection will not be established. This "failed" connection attempt is (or rather, was) not logged by most servers. This has changed most probably when you read this, as the SYN stealth scan has become a pretty famous technique and is also used by other portscanners like Retina from eEye (http://www.eEye.com/). _____ _____________ {2.2.2} · { FIN Stealth } ЇЇЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇ The FIN stealth scan is even more stealthy than SYN scanning - the portscanner never attempts to conenct to the server at all. A FIN scan uses a sheer FIN segment to probe ports. What happens if a FIN packet is sent to a closed port? I am quoting RFC 793 on page 64, as referred to in the nmap manual: "[...] If the state is CLOSED (i.e., TCB does not exist) then all data in the incoming segment is discarded. An incoming segment containing a RST is discarded. An incoming segment not containing a RST causes a RST to be sent in response. [...]" (http://www.rfc-editor.org/rfc/rfc793.txt) So, an RST packet will be sent to the portscanner if the port is closed. However, if the port is open (in LISTEN state) and a segment with only the FIN flag set is sent, the packet will be ignored as stated on page 67 of the RFC 793: "[...] fifth, if neither of the SYN or RST bits is set then drop the segment and return. [...]" That's about it - send the raw FIN segment. If an RST is returned, the port is closed, and if no reply is sent the port is probably open. How to find out if no reply is being sent? Thats a bit tricky, but nmap certainly uses some decent timer. There are two other related scanning methods used by nmap - the XMas tree and the Null scan. Those work like the FIN stealth scan, but the XMas tree scan turns on FIN, URG and PSH while the Null scan does not turn on any flag for this type of scan. _ ____________________________ [3] :: [ The User Datagram Protocol ] Ї ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ Relax, UDP is completely different. UDP was invented in RFC 768 and is a non-connection oriented transport protocol. Neither does it offer any mechanisms to ensure that the data arrives at the remote end or any other smart algorithms. UDP has often been called an unreliable protocol and sometimes it is referred to as an insecure protocol. In fact, UDP is still a useful protocol for applications that do not have to transfer huge ammounts of data. A simple client - server application usually wants to avoid the complex mechanism to establish a connection and to acknowledge every packet when only 2 or 3 packets have to be sent - UDP is perfect for this kind of simple data exchange. An example: Back when ICQ was still a simple Instant Messenger, it used UDP to communicate with the ICQ server. ___ ________________ (3.1) : ( The UDP Header ) ЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ This time we will start directly with the header as an UDP implementation does not utilize any further algorithms or techniques. UDP packets are just being sent, there is nothing else to do. <-------------------------------------------- Bits --------------------------------------------> _______________________________________________________________________________________________ |01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | Source Port | Destination Port | |_______________________________________________|_______________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | Length | Checksum | |_______________________________________________|_______________________________________________| |###############################################################################################| |###########################################[ Data ]############################################| |###############################################################################################| ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ (Figure 3.1.1: The TCP Header Format as explained in RFC 793, part 3.1: http://www.rfc-editor.org/rfc/rfc768.txt) As always, I will explain all the fields of the UDP header in detail now. ______ ______ _____________ {3.1.01} · {16 Bit} · { Source Port } ЇЇЇЇЇЇ ЇЇЇЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇ The source port is the port that the sender of the respective segment uses for this TCP connection. Please refer to [A] for an explanation of all the different ports and of all kinds of ports. (Right, this is the same concept TCP uses.) ______ ______ __________________ {3.1.02} · {16 Bit} · { Destination Port } ЇЇЇЇЇЇ ЇЇЇЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ The destination port is the port used by the remote host for this data exchange. Again, refer to [A] for more info about ports. ______ ______ ________ {3.1.03} · {16 Bit} · { Length } ЇЇЇЇЇЇ ЇЇЇЇЇЇ ЇЇЇЇЇЇЇЇ The length field contains the complete length of the UDP datagram, including the header and the data, of course. This value will also be based on the MTU of the respective network, if larger datagrams are being sent at all. ______ ______ __________ {3.1.04} · {16 Bit} · { Checksum } ЇЇЇЇЇЇ ЇЇЇЇЇЇ ЇЇЇЇЇЇЇЇЇЇ I hope you still remember the TCP header, otherwise please check out (1.4) before you read this or at least have a look at {1.4.09} that explains how the TCP checksum us calculated. Why am I referring to the TCP header or its checksum? Because calculating the UDP checksum is basically the same procedure. Before the checksum is calculated, the checksum field of the UDP header is set to zero. Then a pseudo header is created and copied to a buffer along with the real UDP header and the data. The buffer then looks like this: [ A pseudo header ] [ The UDP header ] [ The Data ] This pseudo header is never sent with the datagram, I have to stress this again and again. It is never being received and it is only used once by the sender to calculate the checksum. It contains information from the IP header as well, and for UDP it looks like this: _______________________________________________________________________________________________ |01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | Source IP Address | |_______________________________________________________________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | Destination IP Address | |_______________________________________________________________________________________________| |ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ|ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ| | 0 | 17 | UDP Datagram Length | |_______________________|_______________________|_______________________________________________| (Figure 3.1.04.1: The UDP pseudo header) If you compare figure 3.1.04.1 with figure 1.4.09.1, you certainly notice that they look quite similar. Indeed, transport layer pseudo headers always work the same way: They contain the source and the destination IP address, then a zero-byte followed by one byte that contains the protocol number for the transport layer protocol that is being used. The word that follows is always the length of the complete packet that is supposed to be sent. So, obviously, the field which is set to 17 actually represents the UDP protocol number. The field that is set to 0 is not declared as a reserved field, it just contains zeros to make the pseudo header length a multiple of two bytes. Anyhow, the checksum field is optional. If the sender of an UDP datagram sets the checksum field of the UDP header to zero, it will just be ignored by the receiver. This is actually a good argument to call UDP an insecure protocol, in my opinion. ___ ______________ (3.2) : ( UDP Spoofing ) ЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇЇ TCP - Flashback: You might not have thought about it yet, but the sequence and acknowledgement numbers in TCP were added on purpose and not just to annoy people who are creating a TCP implementation. The sequence number is chosen randomly once a connection is established and TCP segments that contain an invalid sequence number are ignored. This is actually a quite secure mechanism, and additional to that, TCP is connection-oriented. The three-way-handshake requires both partners of the connection to identify themselves by acknowledging a segment they received from the other side. It is almost impossible to spoof such a connection - at least TCP is quite secure. Comparing UDP to TCP: There is no sequence number. There is no acknowledgement. There is nothing in UDP to check whether a packet is valid at all. This allows spoofing and faking UDP datagrams - one could think about a million things that could be done. However, spoofing UDP packets is usually not that simple - as the applications that use UDP usually implement several security measures within the application layer which makes it much more complicated to attack a specific service. UDP might be insecure, but IP itself is insecure as well - that does not count until you see the whole picture, aka all layers combined. I won't present a tacky UDP spoofing example here, that should be left for the tutorial about raw sockets that should follow soon. _ _______ [A] :: [ Ports ] Ї ЇЇЇЇЇЇЇ Ports are an essential concept of transport layer protocols. Each side of the connection registers a port number with the operating system. This port is used as the virtual interface for a computer program to receive data from the network. The port number is actually just a number - when registering a port, nothing extraordinary happens. The application that registers a port basically tells your OS that it wants to register this specific port and the OS assigns this port number to the process that represents the running application. When the port is assigned, nothing more happens - the OS only remembers that the process ID of this application belongs to a certain port number. Thus, the port number is just an identifier. When the operating system receives data from the physical network layer, it parses the transport layer protocol header and looks for a field that contains the target port. Now the OS knows which application had registered this port and forwards all incomming data that is sent to this port to the appropriate application. This functionality is implemented by the socket interface which will be explained in [B]. Now, as you know what a port actually is and represents, let's get into detail. A port number is a 16 bit word, the biggest possible port number therefor is 0xFFFF = 65535. However, port numbers are not used randomly, they have been devided into 3 groups with different meanings and tasks: ___ __________________ (A-1) : ( Well-known Ports ) ЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ The well-known ports range from 0 to 1023. These ports are used for well known services such as HTTP and FTP. The Internet Assigned Numbers Authority (IANA) administrates this range of ports and is responsible for new services to be registered and any other changes to the public standard of the well knonw ports. ___ __________________ (A-2) : ( Registered Ports ) ЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ Registered ports are used for services that normally use the respective service. For instance, the port 8080 is officially an alternative HTTP port and is usually used by proxies and also by some unofficial or private HTTP servers that want to get around port restrictions set by their ISP. The registered ports range from 1024 to 49151. ___ _______________ (A-3) : ( Dynamic Ports ) ЇЇЇ ЇЇЇЇЇЇЇЇЇЇЇЇЇЇЇ The dynamic or private ports are actually used randomly. These ports can be used by any application for any purpose - dynamic ports can be used for IPC (Inter-Process Comunication) as well as for a client application that connects to a well known service. However, no well known service has registered a dynamic port - actually, no dynamic port may be registered to any service as they are, by definition, dynamic. Obviously, the dynamic ports range from 49152 to 65535. _ _________ [B] :: [ Sockets ] Ї ЇЇЇЇЇЇЇЇЇ The word "socket" is often used like a buzzword, even by programmers and people who should know what they are talking about - ask them what a socket is, and many of them will not be able to give you a correct answer. The first thing to keep in mind is that a socket is merely an abstract idea, just like a port. The socket is not some sort of object or device. The socket can be described as the abstract idea of one side of a connection. The virtual socket interface has to provide mechanisms to register a port number with the OS, to send and receive data, and so forth. Please read [A] before you go on in order to understand the concept of registering and using a port number. The core socket interface is a set of functions that are provided by every operating system to allow programmers to develop platform independant networking code. The function that has to be called in order to create a socket is the socket() function, which is usually linked to an API routine implemented by the operating system. As I already said, a socket is an abstract interface. Therefore, the function does not return any object or structure but simply an integer number. This integer number is the socket identifier. This identifier is actually derived from the IP Address of the computer that the socket is created on and the port number that belongs to it. As both the IP Address of a certain host and the port number of a service are always unique, the socket identifier itself is unique for each socket object. Thus, it provides an easy and yet clean way to wrap the complex mechanisms behind TCP/IP. As this is not a socket tutorial for C coders, I will leave out code samples and explanations of the socket interface API. Perhaps this will be part of a socket tutorial that might follow in this series. _ ____________ [4] :: [ Last Words ] Ї ЇЇЇЇЇЇЇЇЇЇЇЇ Well, this is the second part of my series, looks like I will really write more of these. I am definitely planning to publish one about raw sockets (especially in Windows 2000 environments) and about IPv6. This tutorial probably contains the basic knowledge required to understand most of the other topics that might follow and therefore I need feedback. I had the impression that part 1 was quite ok, and I hope that this one helped some people as well. Anyway, just tell me what you think and also give me advice if you think I could formulate this or that part in a better way. For in time, you know what counts: Always the real thing. Yours, rattlesnake@box.sk