15 Ekim 2018 Pazartesi

IPV4 Header

Giriş
Şöyledir
0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version|  IHL  |Type of Service|          Total Length         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Identification        |Flags|      Fragment Offset    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Time to Live |    Protocol   |         Header Checksum       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Source Address                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Destination Address                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options                    |    Padding    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
IPV4 zarfı şöyle düşünülebilir. 12 byte kontrol bilgisi + 8 byte adres bilgisi. Yani toplam 20 byte.

TCP/IP kullanılan bant genişliği düşük hatlarda Van Jacobson TCP/IP Header Compression kullanılarak byte sayısı düşürülebiliyor.

Struct
IPv4 Header şeklen şöyle. Linux'ta şu satırı dahil ederiz.
#include <netinet/in.h>
typedef struct header
{
  //IP-Header
  unsigned char ip_v:4, ip_hl:4;
  unsigned char ip_tos;       //1 Byte
  unsigned short int ip_len;  //2 Byte
  unsigned short int ip_id;   //2 Byte
  unsigned short int ip_off;  //2 Byte
  unsigned char ip_ttl;       //1 Byte
  unsigned char ip_p;         //1 Byte
  unsigned short int ip_sum;  //2 Byte
  unsigned int ip_src;        //4 Byte
  unsigned int ip_dst;        //4 Byte

}
Yukarıdaki tanımda eksik olan şey makinenin Most Significant Bit'inin (MSB) ne olduğuna dikkat edilmemesi. IPV4 ilginç bir şekilde MSB 0 olacak şekilde tanımlı. Dolayısıyla version ve header alanlarının yeri mimariye göre değişe. Örneğin Linux'ta gerçek kod şöyle tanımlı. Little Endian mimaride MSB 7. bit. Yani en solda. Big Endian'da ise MSB 0. bit yani en sağda. Dolayısıyla ters sırada tanımlı.
struct ip
{
  #if __BYTE_ORDER == __LITTLE_ENDIAN
    unsigned int ip_hl:4;               /* header length */
    unsigned int ip_v:4;                /* version */
  #endif
  #if __BYTE_ORDER == __BIG_ENDIAN
    unsigned int ip_v:4;                /* version */
    unsigned int ip_hl:4;               /* header length */
  #endif
  ...
};
Direkt bellek alanı ile çalışınca bu tür detaylara dikkat etmek gerekiyor. Eğer sadece kod ile çalışsaydık okuma esnasında bu tür detaylara dikkat etmezdik. Yani şu kod çalışırdı.
int ip_vhl; // version and header togather
#define IP_HL(ip) (((ip)->ip_vhl) & 0x0f) //split header length
#define IP_V(ip) (((ip)->ip_vhl) >> 4) //split IP version


1. Version Alanı - ip_v
4 bit büyüklüğünde. Bu alanlar sabit. Version her zaman IPv4 olduğu için 4.

2. Header Length Alanı - ip_hl
4 bit büyüklüğünde. IP Header'ın uzunluğu. Data hariçtir. Birim olarak 4 byte kullanır. 20 byte'lık header için 5 değeri yazılır. Bu alan Total Length alanından farklıdır. Şöyle yaparız.
struct ipheader* ip = ....; 
int ip_header_len = ip->iph_ihl * 4; 
Bu alan en çok Ip'den sonra gelen veriye erişmek için kullanılır. Şöyle yaparız.
int ip_header_len = ip->iph_ihl * 4;

struct icmpheader* icmp = (struct icmpheader *) ((u_char *)ip + ip_header_len);

3. Service Type Alanı  - Eski Kullanım 
8 bit büyüklüğünde.İlk 2 bit MBZ (Must be Zero), sonraki 3 bit precedence, sonraki 3 bit Type of Service (ToS) anlamına gelirdi.

3.1 MBZ
Hep sıfırdır.

3.2 Precedence
Precedence ile IP paketleri 0-7 değerleri arasında öncelik kazanabiliyordu. Precedence (ServiceType & 0xE0) >> 5) yapılarak okunur.

3.3 ToS
Açıklama yaz

3. Differentiated Services Code Point - Yeni Kullanım 
3.1 Explicit Congestion Notification - ECN
Bir router'da tıkanıklık olursa, router IP paketindeki bu alanı işaretler.


4. Total Length Alanı- ip_len
2 byte büyüklüğünde. Header + Data yani toplam paket uzunluğu. Byte cinsindendir.
nthos (ip->ip_len) ile okunur. Yani Big Endian olarak kullanılır.

Bu alan en fazla 65,535 değerini alabilir. Ping of death saldırısı bu değerden daha büyük paketlerin gönderilmesine dayanıyordu.

IP fragmentli bir yapıya sahip olabildiği için en büyük zarf 60 byte, en küçük faydalı yük 8 byte olabilir. Bu durumda gönderilebilecek MTU 68 byte olur. Açıklaması şöyle
Every internet module must be able to forward a datagram of 68 octets without further fragmentation. This is because an internet header may be up to 60 octets, and the minimum fragment is 8 octets.

5. Identification  Alanı
2 byte büyüklüğünde. Her IP paketin farklı bir sayı verilir.
Flags Alanı
3 bit büyüklüğünde.

6. Flags Alanı
3 bit büyüklüğünde. 3 tane flag var. Bunlar şöyle
Bit 0 - Reserved
Hep 0
Bit 1 - Don't Fragment (DF)
Açıklaması şöyle
IPv4 packets have a Don't-Fragment (DF) flag which indicates whether routers on the path are allowed to perform fragmentation when the packet doesn't fit the MTU of the next link. If you leave the DF flag off you can just send packets as large as possible on your local link, and routers along the path will fragment if/when necessary. You therefore as a sender don't need to discover the MTU for the whole path.

Only when you tell routers not to fragment IPv4 and turn the DF bit on do you need to learn about lower MTU's further along the path. Routers that would have fragmented will now send back ICMP messages (type 3: Destination Unreachable, subtype 4: Fragmentation Needed and Don't Fragment was Set) and the sender needs to receive these so they can adjust their packet size.

IPv6 doesn't have a DF flag, fragmentation along the path is always prohibited. It therefore behaves in a similar way as IPv4 with the DF flag on. Routers will send back ICMP messages (Type 2: Packet Too Big, it's not a subtype of Destination Unreachable anymore, it now is so important it has its own type) and the sender has to take those into account when determining the packet size.

So whether you have to implement Path MTU Discovery has nothing to do with where in the header the fragmentation is implemented (main header vs extension header), it depends on whether fragmentation is handled along the path or whether the sender has to determine the right packet size. If the routers along the path handle it (IPv4 with DF off) then the sender doesn't need to care, but otherwise (IPv4 with DF on, and IPv6) the sender must be able to receive those ICMP messages so it can adjust its behaviour accordingly.

Bit 2 - More Fragment (MF)
Açıklaması şöyle
Reassembly
A receiver knows that a packet is a fragment if at least one of the following conditions is true:
  • The "more fragments" flag is set. (This is true for all fragments except the last.)
  • The "fragment offset" field is nonzero. (This is true for all fragments except the first.)
The receiver identifies matching fragments using the foreign and local internet address, the protocol ID, and the identification field. The receiver will reassemble the data from fragments with the same ID using both the fragment offset and the more fragments flag. When the receiver receives the last fragment (which has the "more fragments" flag set to 0), it can calculate the length of the original data payload, by multiplying the last fragment's offset by eight, and adding the last fragment's data size. In the example above, this calculation was 495*8 + 540 = 4500 bytes.
When the receiver has all the fragments, it can put them in the correct order, by using their offsets. It can then pass their data up the stack for further processing.
7. Fragment Offset Alanı 
Prefragment yani paketlerin kaynakta bölünmesi ve daha sonra hedef'te birleştirilmesi IP protokolünü ilk tasarlayanların niyetiydi. Açıklama şöyle
I've read that fragmented IP packets "always" become reassembled at their ultimate destination, e.g. the recipient host.
Ancak bu niyet gerçekleşmedi. Açıklaması şöyle
That was the original intent of the Designers of IP, it's not so true nowadays though. Many firewalls will defragment packets because it's difficult to do effective firewalling on fragments.
Bu alanın açıklaması şöyle
To fragment a long internet datagram, an internet protocol module (for example, in a gateway), creates two new internet datagrams and copies the contents of the internet header fields from the long datagram into both new internet headers. The data of the long datagram is divided into two portions on a 8 octet (64 bit) boundary (the second portion might not be an integral multiple of 8 octets, but the first must be). Call the number of 8 octet blocks in the first portion NFB (for Number of Fragment Blocks). The first portion of the data is placed in the first new internet datagram, and the total length field is set to the length of the first datagram. The more-fragments flag is set to one. The second portion of the data is placed in the second new internet datagram, and the total length field is set to the length of the second datagram. The more-fragments flag carries the same value as the long datagram. The fragment offset field of the second new internet datagram is set to the value of that field in the long datagram plus NFB.
IPV6'da Fragment özelliği yok. Açıklaması şöyle
In contrast, IPv6, the next generation of the Internet Protocol, does not allow routers to perform fragmentation; hosts must determine the path MTU before sending datagrams.
IP, Ethernet MTU'dan daha büyük veri göndermek isterse veriyi parçalara böler (fragment). Aynı diziye ait fragmentlerde IP Header'daki identification alanı sabittir. Dizinin son elemanı hariç tüm elemanlarının "More Fragmentation Flag" bayrağına 1 değeri atanır. Ayrıca birleştirme işlemi için "Fragment Offset" alanı atanır.
Açıklaması şöyle.
There are three fields in the IPv4 header that are relavent to fragment detection and reassembly.

-The "fragment offset", a number where a fragment fits into the complete packet.
-The "more fragments" flag, a single bit flag that specifies whether there are more fragments after this one.
- The "ID" field, this identifies which packet a fragment belongs to.

If "fragment offset" and "more fragments" are both zero then it is a complete un-fragmented packet. Otherwise we are dealing with a fragment.
Paketin data kısmının büyüklüğü, son paket hariç 8 byte'ın katı olmalıdır. Eğer router'ın çıkış MTU değeri çok küçük ise paketin kaynağına ICMP mesajı gönderir. Açıklaması şöyle
If the MTU of the outgoing interface is smaller than the packet, the router will fragment the packet unless the DF flag is set. In that case the router will drop the packet and send an ICMP packet too big message back to the sender.

Tam bölünme örneği
Elimizde 302 byte uzunluğunda paket olsun. MTU 128 olsun. Paket şöyle bölünür.
Fragment 1 : 124 byte (20 byte zarf + 104 byte data) 104 / 8 = 13
Fragment 2 : 124 byte (20 byte zarf + 104 byte data) 104 / 8 = 13
Fragment 3 : 94 byte (20 byte zarf + 74 byte data) 104 / 8 = 13
Kısmi bölünme örneği
Elimizde 1396 byte uzunluğunda paket olsun. MTU 1400 byte olsun. Bu örnek için IP zarfının 40 byte olduğunu varsayalım. Ağda ise zarfları çıkarttıktan sonra 1356 byte veri için yer kalır.
1356 / 8 = 169.5
ancak bunu aşağı yuvarlarsak 169 elde ederiz.
169 * 8 = 1352.
Yani bir pakette en fazla 1352 byte gönderebiliriz.Dolayısıyla ilk paket 1352 byte içerir. İkinci paket ise 44 byte içerir. 44 sayısı 8'e tam bölünmez ancak son paket olduğu için 8'in katı olmak zorunda değil.

Kısmi bölünme örneği - 2
Elimizde 4500 byte uzunluğunda paket olsun. MTU ise 2600 olsun. Bu örnek için IP zarfının 40 byte olduğunu varsayalım. Paketler şöyle bölünür. 1924 sayısı 8'e tam bölünmez ancak son paket olduğu için 8'in katı olmak zorunda değil.
Fragment 1: 20 octet IPv4 header and 2576 octet payload . 2576 / 8 = 322
Fragment 2: 20 octet IPv4 header and 1924 octet payload 1924 / 8 = 240.5
8. TTL Alanı - ip_ttl
1 byte büyüklüğünde. 8 bit olduğu için en fazla 255 değerini alabilir. IPV4 için TTL genelde 1 veya 64 veya 128 veya 255 değeri ile dolduruluyor.

Windows ve Linux
Window ve Linux için değerler şöyle.
- Windows 128 ile dolduruyor.
- Linux 64 ile dolduruyor

255 Değeri Yeterli Olur mu ?
Paketin dünyayı dolaşması için 30 civarında hop şu anda yeterli. Dolayısıyla 255 fazla bile gelir.

Aslında TTL değerini ben Hop Count olarak düşünüyordum ancak paketin yaşaması gereken süreyi gösteriyormuş. Açıklaması şöyle.
Time to Live: 8 bits
This field indicates the maximum time the datagram is allowed to remain in the internet system. If this field contains the value zero, then the datagram must be destroyed. This field is modified in internet header processing. The time is measured in units of seconds, but since every module that processes a datagram must decrease the TTL by at least one even if it process the datagram in less than a second, the TTL must be thought of only as an upper bound on the time a datagram may exist. The intention is to cause undeliverable datagrams to be discarded, and to bound the maximum datagram lifetime.
Bir çok router TTL alanını değiştirmiyor. Bu yüzden IPv6'te bu alan "Hop Limit" olarak değiştirilmiş.
TTL 1 olursa açıklaması şöyle. Ingress ingestion yani gelen mesaj anlamına gelir.
TTL is checked on ingress packets and decreased when forwarding (=routing) packets. Accordingly, sending out a packet with TTL=1 will enable it to reach a local destination but it will not be routed.
9. Protocol Number Alanı - ip_p
IP paketinin hangi üst seviye protokole gönderilmesi gerektiğini belirten bir sayı. Açıklaması şöyle
The protocol number is used by the the layer-3 protocol (IPv4 or IPv6) to determine to which layer-4 protocol in the network stack it should send the payload of the packet.
Icmp, Tcp, Udp vs. olabilir. Ethernet paketindeki Type alanı benzer bir mantık kullanarak aynı işlevi görür. Şöyle yaparız.
if (ip->iph_protocol == IPPROTO_ICMP)
{
  ...
}
Tüm liste burada.
- 6 için TCP Header yazısına bakınız.
- 17 için UDP Header yazısına bakınız.
- 50 ve 51 için IPSec yazısına bakınız
- 144 numaralı protocol "any 0-hop protocol" olarak adlandırılır. Çok eskiden kullanılan ve sadece 1
hop gitmesi istenen bir protokoller içindir.

10. Header Checksum Alanı - ip_sum
IPV4, TCP ve UDP hep checksum yöntemini kullanır. IPV6 nedense artık checksum yöntemini kullanmıyor. Bu alan sadece IP Header için checksum'dır. Paketin yükü için checksum değildir.  Açıklaması şöyle
The header checksum in an IP packet only detects errors in the header. There is no trailing checksum in IP. It's up to the upper layers to detect errors in the payload.
TCP ve UDP paketlerinde checksum header + data içindir.

Bazı network kartları checksum hesaplamasını yapabilir. Bu durumda IP protocol stack normalde kendisinin yapması gereken bu görevi devreder. Açıklaması şöyle
IPv4 has 16-bit header checksum. It is calculated using the Internet checksum algorithm. It is much less reliable than Ethernet's FCS, and each router must modify the packet by decrementing hop count (and thus recalculating checksum), so this is not true end-to-end checksum either. Due to the additional workload required on routers, IPv6 has eliminated this checksum.
Paketi tekrar gönderecek router şöyle yapar.
In Ipv4, the receiving router first checks the checksum then decrements TTL and then recomputes the checksum.
11. Source  Ip Address Alanı 
Bu alanın 32 bit yani 4 byte olması tamemen tesadüf. Açıklaması şöyle.
According to Vint Cerf (the father of IP), the IPv4 32-bit address size of was chosen arbitrarily.
UDP iletişiminde bu alan "unicast RPF" kontrolü ile spoofed UDP paketlerini süzmek için kullanılabilir. Böylece DoS saldırıları önlenebilir.

inet_ntop ile 4 byte'lık adresler string'e çevrilir. inet_pton ile string 4'byte'a çevrilebilir.

Adres alanları IPV6'daki gibi 0'ları atarak kısaltarak gösterilmez.

IPV4 Adres Çeşitleri yazısına bakabilirsiniz.

12.  Destination Ip Address Alanı 
Yukarıdaki açıklama ile aynı

13. Options Alanı
Açıklaması şöyle
There are IPv4 options that may increase the packet header size. That is one of the things that IPv6 fixed. The maximum IPv4 packet header length is 60 bytes.
Record Route Option
RFC 791 ile tanımlı ancak kullanılmıyor

Hiç yorum yok:

Yorum Gönder