-1

i am working with libpcap(gcc, linux) and for some reason i want to extract the packet length from the u_char packet[], saving it in an integer; say the packet length stored in packet[38] packet[39] . something like:

#include <stdio.h>
#include <netdb.h>

int main(int argc, char *argv[]) {

u_char packet[2] = {0xaa, 0xfc};

int length = 0xaafc; // how to do that ?

printf("%d\n", length);
}

so far i have tried this :

#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>


int main(void)
{
    u_char packet[2] = {0xaa, 0xfc};
    int l = packet[0] | (packet[1]<<8);
    printf("%d\n", l);
}

but no success !

so how to accomplish this in c ? also if i should post the whole code here, just name it ...

thanks.

Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328
V1R4N64R
  • 23
  • 1
  • 8

2 Answers2

1

You should cast to an int before performing the left shift:

int l = packet[0] | (((int)packet[1])<<8);

Without this cast, packet[1]<<8 is 0 - you take an 8 bit variable and shift its bits left 8 times. You're going to end up with 8 zero bits.

zmbq
  • 38,013
  • 14
  • 101
  • 171
  • you're right ! i have modified that and the result should be `0xaafc = 43772` but the above code gives me 64682 which is unexpected ... thanks by the way . – V1R4N64R May 20 '14 at 21:01
  • 1
    @InterestedInC you'd likely be interested that 64682 decimal is 0xFCAA as hex. If you're expecting the input to be in big-endian byte order, then change the posted line to: `int l = packet[1] | (((int)packet[0])<<8);` If this is wire traffic, however, you should be using the utils provided for sending and receiving multibyte integer values as platform independent representations (see Jonathan's answer). – WhozCraig May 20 '14 at 21:16
  • @zmbq Confident the `(int)` is _not_ needed. Without the cast, `<<` takes 2 operands, `u_char packet` and `int 8`. As `packet` is rank less than `int`, "integer promotions" occur resulting in type `int packet` and `int 8`. See C11 spec §5.1.2.3 11 – chux - Reinstate Monica May 21 '14 at 13:46
0

While you could do it your way, it'd be far easier to cast a pointer to your buffer to the correct type:

#include <linux/ip.h>

int main(void)
{
    u_char *packet = ...;
    int total_len;
    int ip_hdr_len;

    struct iphdr* iph;
    struct tcphdr* tcph;

    iph = (void*)packet;

    // Remember fields are in network order!
    // convert them to host order with ntoh[sl]
    total_len = ntohs(iph->tot_len);

    ip_hdr_len = iph->ihl * 4;

    // Assuming TCP...
    // Also be sure to check that packet is long enough!
    tcph = (void*)(packet + ip_hdr_len);
}
Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328