5

I am trying to parse a tcp packet and then assign to a pointer to the start of the payload.

I am using C and this is my code so far:

void dump(const unsigned char *data, int length) { //*data contains the raw packet data
    unsigned int i;
    static unsigned long pcount = 0;

    // Decode Packet Header
    struct ether_header *eth_header = (struct ether_header *) data;

    printf("\n\n === PACKET %ld HEADER ===\n", pcount);

    printf("\nSource MAC: ");
    for (i = 0; i < 6; ++i) {
        printf("%02x", eth_header->ether_shost[i]); //? Why don't i use nthos here?
        if (i < 5) printf(":");
    }

    unsigned short ethernet_type = ntohs(eth_header->ether_type);
    printf("\nType: %hu\n", ethernet_type);

    if (ethernet_type == ETHERTYPE_IP) { //IP Header
        printf("\n  == IP HEADER ==\n");
        struct ip *ip_hdr = (struct ip*) data + sizeof(struct ether_header);
        unsigned int size_ip = ip_hdr->ip_hl * 4;
        printf("\nIP Version: %u", ip_hdr->ip_v); //? Nthos or no nthos
        printf("\nHeader Length: %u", ip_hdr->ip_hl); //? Nthos or no nthos
        printf("\nTotal Length: %hu", ntohs(ip_hdr->ip_len)); //? Nthos or no nthos

        // TCP Header
        printf("\n== TCP HEADER ==\n");
        struct tcphdr *tcp_hdr = (struct tcphdr*) data + sizeof(struct ether_header) + size_ip;
        printf("\n Source Port: %" PRIu16, nthos(tcp_hdr->th_sport));
        printf("\n Destination Port: %" PRIu16, nthos(tcp_hdr->th_dport));
        printf("\n fin: %" PRIu16, tcp_hdr->fin);
        printf("\n urg: %" PRIu16, tcp_hdr->urg);
        printf("\n ack_seq: %" PRIu32, ntohl(tcp_hdr->ack_seq));

        //Transport payload! i.e. rest of the data
        const unsigned char *payload = data + ETH_HLEN + size_ip + sizeof(struct tcphdr) + tcp_hdr->doff;

    }

I'm sure there is mistakes in this code because the port numbers are all weird. Not a single one assigns to 80. The Ip version outputted can also be really weird (like version 11) as well. What am I doing wrong? Thanks!

Also I am unsure when to use nthos and when not to. I know nthos is for 16 bit unsigned integer and I know nthol is for 32 bit unsigned integers, but I'm aware your not meant to use them for everything in those packets (like: tcp_hdr->fin). Why certain things and not them?

MANY THANKS!

EDIT:

Thanks Art for fixing most f the problems. I edited my tcp_hdr and ip_hdr so the brackets are now correct!

I still have 2 problems:

  • The first 10 bytes of the payload has weird symbols (so I think I have not assigned the payload correctly).
  • I'm still unsure when to use nthos/nthol. I know u_int16_t is ntohs and u_int32_t is ntohl. But what about things that are signed int or unisgned short int. For instance I didn't use ntohs or nthol for the ip_v for it to work. Why not? Is "ip_hdr->ip_hl" nthol? etc...

EDIT2

I have fixed why my payload was not outputting correctly (it's because I calculated the TCP_header size wrong).

Although I am still confused about when to use nthos, I will put this as a separate question, as I think I asked too many questions on this 1 post!

When to use ntohs and ntohl in C?

Community
  • 1
  • 1
Yahya Uddin
  • 26,997
  • 35
  • 140
  • 231
  • You do know that things like port numbers are in *network* byte order? Use `ntohs` to convert a short (16-bit) value from network byte order to host byte order. – Some programmer dude Dec 04 '14 at 14:15
  • I tried both but got weird numbers for eitehr. Updating code now anyways! – Yahya Uddin Dec 04 '14 at 14:17
  • Are there other fields that looks correct? Like the source/destination addresses? The ethernet header? How does it look compared to the same packet in e.g. Wireshark? And you *do* receive this on a raw socket? And receive *all* of the packet? – Some programmer dude Dec 04 '14 at 14:26

1 Answers1

5

Most likely your problem is here:

struct ip *ip_hdr = (struct ip*) data + sizeof(struct ether_header);
struct tcphdr *tcp_hdr = (struct tcphdr*) data + sizeof(struct ether_header) + size_ip;

Doing (struct ip*) data + sizeof(struct ether_header) first casts data to struct ip *, then adds sizeof(struct ether_header) to it, which we know from pointer arithmetics will not do what you expect it to do.

If the problem is still unclear, here's a simple program that should point you in the right direction:

#include <stdio.h>

struct foo {
    int a, b;
};

int
main(int argc, char **argv)
{
    char *x = NULL;

    printf("%p\n", x);
    printf("%p\n", (struct foo *)x + 4);
    printf("%p\n", (struct foo *)(x + 4));

    return 0;
}
Art
  • 19,807
  • 1
  • 34
  • 60
  • Thats fixed like almost all my problems. Do you mind if you also answer the 2nd part of my question as when to use ntohs. My current rule I made up is for anything of type u_int16_t is ntohs and u_int32_t is ntohl. But what about things that are signed int or unisgned short int. For instance I didn't use ntohs for the ip_v for it to work. Why not? Thanks – Yahya Uddin Dec 04 '14 at 14:48
  • Look at the ip header and a definition. Basic rule is: you do not convert values that are 1B or shorter (ip_v, ip_hl). You use ntohs for 2B values (ip_len, ip_p). You use ntohl for 4B values. "But what about things that are signed int or unisgned short int": It doesn't really matter whether it's signed or not (and I don't think there are any signed values in ip hdr), so signed int is just 4B value and unsigned short is 2B value. You can see the ip header here: http://en.wikipedia.org/wiki/IPv4#Header – davak Dec 04 '14 at 15:38
  • so wait does "ip_hdr->ip_hl" use htol then as it is of type "unsigned int ip_hl:4;" When i added htol the program terminates before even reading the TCP header (probably meaning its reading a part of memory it's not supposed to). However when I left it without ntohl or ntohs it worked fine! – Yahya Uddin Dec 04 '14 at 15:52
  • 1
    No, it does not. ip_hl is just 4 bits. Talking about byte order only makes sense when you have a value of length 2 bytes or longer. If you have a variable that is 1 byte, it is the same in network byte order and in host byte order (if you change order of 1 byte it does not change). – davak Dec 04 '14 at 17:27
  • 1
    To clerify your example: I don't know what ip.h you have, but mine says that u_char ip_hl:4 (which is 1 byte). If yours says unsigned int, that can only mean that unsigned int ip_tos:8, unsigned int ip_len:16 follow. If you call ntohl on your ip_hl, it considers your 4 bit value 32 bits, so it fiddles with all the values I mentioned before, therefore it completely changes the meaning of the header. – davak Dec 04 '14 at 17:28