Author Topic: Parsing IPV4 header values correctly with nasm  (Read 6895 times)

Offline mik3ca

  • Jr. Member
  • *
  • Posts: 30
Parsing IPV4 header values correctly with nasm
« on: February 05, 2021, 04:42:45 AM »
I managed to write a program with (Qbasic and a TSR I wrote) that picked up a network packet and displayed its contents in hex form. When analyzing it along with source code from the mTCP internet package for DOS, it turns out that I can start reading the IP header at the 15th byte. So I made code to reflect this:

Code: [Select]
;Here DS:DI contains the network packet including the IPV4 packet
;and ES:DI points to a far struct with a bunch of members to be filled in with data

  xor AX,AX
  xor BX,BX
  mov AL,[DS:SI+0Eh] ;version + IHL (4 bits each)
  mov CX,[DS:SI+0Ch] ;ether type (2 bytes)
  mov BL,AL
  and AL,0Fh
  shr BL,04h
  and BL,0Fh
  mov [ES:DI+IPihl],AX ; IHL field value as 16-bit
  mov [ES:DI+IPver],BX ;IP version value as 16-bit
  mov [ES:DI+ethertype],CX ;ethernet type as CX (its returning 8h instead of 800h which is bad)
  mov AL,[DS:SI+0Fh] ;DSCP + ECN fields. ECN needs to be 2 bits and DSCP 6 bits
  mov BX,[DS:SI+10h] ;Length (Returns 15360. Isn't this too large of a value?)
  mov CX,[DS:SI+12h] ;identification field
  mov DX,[DS:SI+14h] ;Flag and Fragment offset combined
  mov [ES:DI+IPdscpecn],AX ;Copy DSCP+ECN together to my struct
  shr DX,13 ;move Flag feld to the right
  mov [ES:DI+IPsz],BX ;store size
  and DX,7h ;and limit flag field to 3 bits
  mov BX,[DS:SI+14h] ;Get Flag and fragment offset again
  mov [ES:DI+IPid],CX ;Store identification
  and BX,1FFFh ;Take only the fragment offset value
  mov [ES:DI+IPfl],DX ;Save the flag field
  mov [ES:DI+IPfrago],BX ;Save fragment offset value
  mov BX,[DS:SI+18h] ;Get header checksum
  mov AL,[DS:SI+17h] ;Get protocol number (returns 6 which is correct)
  mov [ES:DI+IPchks],BX ;header checksum
  mov [ES:DI+IPprot],AX ;store protocol
  mov ECX,[DS:SI+1Ah] ;Get source IP address
  mov EDX,[DS:SI+1Eh] ;Get destination IP address
  mov AL,[DS:SI+16h] ;Get time to live
  mov [ES:DI+IPsrcaddr],ECX ;Save source address (seems to be backwards when printed in hex)
  mov [ES:DI+IPdstaddr],EDX ;Save destination address
  mov [ES:DI+IPttl],AX ;Store time to live (correct)

The part I think is the most problemmatic is the data length. I see the value 15360. If I took the value in hex, flip the bytes and converted it to normal, I get a small number like 60 or 64 which I think is reasonable because the only other item accessing the particular interface is a linux utility CURL just to attempt to access the IP.

How do I fix this?
Am I to do everything backwards on a bit-by-bit basis with a lot of shifting and carry checking?
I want a solution that would not be slow.
My goal is to extract each field of the IPV4 header correctly into 16-bit variables (or 32-bit variables in the case of IP addresses).

The reason I limit data collection to the external struct to 16 and 32-bit variables is because I evaluate the data in Quickbasic and their structs do not support 8-bit numbers directly.

Any advice?

Offline fredericopissarra

  • Full Member
  • **
  • Posts: 371
  • Country: br
Re: Parsing IPV4 header values correctly with nasm
« Reply #1 on: February 05, 2021, 02:32:55 PM »
Your processor (x86) uses little endian encoding for multibyte integers (WORD, DWORD, ...). TCP/IP uses BIG endian encoding.

In C language there are 3 functions to translate WORDs and DWORDs: htons(), ntohs(), htonl() and ntohl(), where `h` is host and `n` is netword; `s` is short and `l` is long. For these 'functions' you need only to do:

Code: [Select]
xchg ah,al   ; Assuming AX is your word. OR...
bswap eax   ; ...Assuming EAX is your dword.

if you want to avoid using 386 instructions you can use DX:AX to hold the 32 bit values and do:
Code: [Select]
xchg dh,al
xchg dl,ah

And a byte isn't 'inverted' in any way (it is shown inverted in diagrams, but a byte is a normal byte).
« Last Edit: February 05, 2021, 03:28:42 PM by fredericopissarra »