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?

3
  • 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. Commented Dec 4, 2014 at 14:15
  • I tried both but got weird numbers for eitehr. Updating code now anyways! Commented Dec 4, 2014 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? Commented Dec 4, 2014 at 14:26

1 Answer 1

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;
}
Sign up to request clarification or add additional context in comments.

5 Comments

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
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: en.wikipedia.org/wiki/IPv4#Header
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!
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).
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.