Unable to Display Packet's Ethertype - c

So, I have a program to sniff packets, and so far it has been working very well. I am now trying to add additional functionality, but I keep running into problems when I try to decode the ethertype of a captured packet's Ethernet header. To isolate the location in which the error is occurring, I wrote a modified program to dump only the Ethernet header in hexadecimal, and then, using custom headers, decode the the source MAC address, destination MAC address, and ethertype, but this is the output:
Sniffing on device wlan0
308 BYTE PACKET
01 00 5e 00 00 fb 04 e5 36 4a 5d 3a 08 00 | ..^.....6J]:..
SRC 01:00:5e:00:00:fb DST 04:e5:36:4a:5d:3a TYPE 0000
328 BYTE PACKET
33 33 00 00 00 fb 04 e5 36 4a 5d 3a 86 dd | 33......6J]:..
SRC 33:33:00:00:00:fb DST 04:e5:36:4a:5d:3a TYPE ff11
194 BYTE PACKET
01 00 5e 00 00 fb 04 e5 36 4a 5d 3a 08 00 | ..^.....6J]:..
SRC 01:00:5e:00:00:fb DST 04:e5:36:4a:5d:3a TYPE 0000
Captured 3 packets
Apparently, the program has no problem decoding the MAC addresses, which are the first twelve bytes of the fourteen byte header, but, for some reason, when it reaches the final two bytes comprising the ethertype, the program fails to display them properly. The first and third packets' ethertypes are 0x0800, or IP, and the second packet's ethertype is 0x86dd, or IPv6. I have tried displaying the ethertype in numerous formats, but none have yielded proper results.
These are the lines of code responsible for displaying the MAC addresses and ethertype:
ethernet_header = (const struct sniff_ethernet_hdr *)packet;
printf ("SRC %02x", ethernet_header->ether_shost[0]);
for (i = 1; i < ETH_ALEN; i++)
printf (":%02x", ethernet_header->ether_shost[i]);
printf (" DST %02x", ethernet_header->ether_dhost[0]);
for (i = 1; i < ETH_ALEN; i++)
printf (":%02x", ethernet_header->ether_dhost[i]);
printf (" TYPE %.4x", ethernet_header->ether_type);
printf ("\n");
Does anyone have any suggestions or notice any problems with the code?
EDIT: I continued to play with this program, and I discovered something strange. I set a pointer called eth_ptr to point to the thirteenth byte of the packet, where the ethertype begins. When I dereferenced this pointer and printed the result, it was, indeed, the first byte of the ethertype. So, I added a line to the program that prints the addresses of eth_ptr and the ethertype of the Ethernet header struct. These are the results:
Sniffing on device wlan0
104 BYTE PACKET
01 00 5e 00 00 fb 04 e5 36 4a 5d 3a 08 00 | ..^.....6J]:..
SRC 01:00:5e:00:00:fb DST 04:e5:36:4a:5d:3a TYPE 8
eth_ptr # 0x7ffafd0b1944 ether_type # 0x7ffafd0b194c
124 BYTE PACKET
33 33 00 00 00 fb 04 e5 36 4a 5d 3a 86 dd | 33......6J]:..
SRC 33:33:00:00:00:fb DST 04:e5:36:4a:5d:3a TYPE 86
eth_ptr # 0x7ffafd0b1944 ether_type # 0x7ffafd0b194c
319 BYTE PACKET
01 00 5e 00 00 fb 04 e5 36 4a 5d 3a 08 00 | ..^.....6J]:..
SRC 01:00:5e:00:00:fb DST 04:e5:36:4a:5d:3a TYPE 8
eth_ptr # 0x7ffafd0b1944 ether_type # 0x7ffafd0b194c
Captured 3 packets
$ gdb -q
(gdb) p /x 0x7ffafd0b194c - 0x7ffafd0b1944
$1 = 0x8
The type that is being printed is really the dereferenced pointer, which points to the first byte of the ethertype. This pointer is located eight bytes before ethernet_header->ether_type in memory; therefore, the problem is that the ethertype element of the struct is located eight bytes ahead of where it is supposed to be. I do not know why this is, or how to fix this. Can anyone offer an explanation?
EDIT AGAIN: Well, I am a fool. I just took a close look at the Ethernet header structure:
struct sniff_ethernet_hdr
{
uint8_t ether_shost[ETH_ALEN];
uint8_t ether_dhost[ETH_HLEN];
uint16_t ether_type;
} __attribute__ ((__packed__));
The macros:
#define ETH_ALEN 6
#define ETH_HLEN 14
After I fixed this careless mistake, the program ran flawlessly.

Related

How to print data in a buffer irrespective of zeros in between till the given length

I wrote a simple program to read a packet till layer 3 and print the same in hex format.
I gave input in hex format. My output should be same as this.
Input:
45 00 00 44 ad 0b 00 00 40 11 72 72 ac 14 02 fd ac 14
00 06 e5 87 00 35 00 30 5b 6d ab c9 01 00 00 01
00 00 00 00 00 00 09 6d 63 63 6c 65 6c 6c 61 6e
02 63 73 05 6d 69 61 6d 69 03 65 64 75 00 00 01
00 01
I am able to read the packet. Here the hex dump in gdb
(gdb) p packet
$1 = 0x603240 "E"
(gdb) x/32x 0x603240
0x603240: 0x00440045 0x00000000 0x00400b0e 0x00000000
0x603250: 0x00603010 0x0035e587 0xe3200030 0x63206261
0x603260: 0x31302039 0x20303020 0x30203030 0x30302031
0x603270: 0x20303020 0x30203030 0x30302030 0x20303020
0x603280: 0x36203930 0x33362064 0x20333620 0x36206336
0x603290: 0x63362035 0x20633620 0x36203136 0x32302065
0x6032a0: 0x20333620 0x30203337 0x64362035 0x20393620
0x6032b0: 0x36203136 0x39362064 0x20333020 0x36203536
But when I tried to print the packet in console using %s I can't see the total packet because of zeros in between. But I wanted to print it till length of the packet(I am taking it as input to print function).
output on console is:
packet: E
My print function is something like this.
void print(char *packet, int len) {
printf("packet: ");
printf("%s\n\n" , packet );
}
Can you tell me any other way to print the packet till the len(input to print function).
PS: Reading l3 information I didn,t complete. So in gdb of packet l3 information vary form my input.
A string in C is defined as a sequence of characters ending with '\0' (a 0-byte), and the %s conversion specifier of printf() is for strings. So the solution to your problem is doing something else for printing the binary bytes. If you want for example to print their hexadecimal values, you could change your print function like this:
void print(unsigned char *packet, size_t len)
{
for (size_t i = 0; i < len; ++i) printf("%02hhx ", packet[i]);
puts("");
}
Note I also changed the types here:
char can be signed. If you want to handle raw bytes, it's better to always use unsigned char.
int might be too small for a size, always use size_t which is guaranteed to hold any size possible on your platform.
If you really want to print encoded characters (which is unlikely with binary data), you can use %c in printf(), or use the putchar() function, or fwrite() the whole chunk to stdout.

C program Reading Hex values from Fat MBR

I am new to the C language and am trying to create a forensic tool. So far i have this. It reads a dd file which is a dump of a fat16 MBR. I am able to read certain bytes properly but not some.
What i need help with is the SizeOfFat variable needs to get the values of byte 0x16 and 0x17 read in little endian. How would i have it read FB00 and then convert it to 00FB and then print the value ?
char buf[64];
int startFat16 = part_entry[0].start_sect,sectorSize = 512,dirEntrySize=32;
fseek(fp, startFat16*512, SEEK_SET);
fread(buf, 1, 64, fp);
int rootDir = *(int*)(buf+0x11);
int sectorPerCluster = *(int*)(buf+0x0D);
int sizeOfFat = *(int*)(buf+0x16);
int fatCopies = *(int*)(buf+0x10);
printf("\n Phase 2 \n no of sectors per cluster : %d \n",(unsigned char)sectorPerCluster);
printf("size of fat : %d \n",(unsigned char)sizeOfFat);
printf("no of Fat copies : %d \n",(unsigned char)fatCopies);
printf("maximum number of root directories : %d \n",(unsigned char)rootDir);
The hex values im working with here are -
EB 3C 90 4D 53 44 4F 53 35 2E 30 00 02 08 02 00
02 00 02 00 00 F8 FB 00 3F 00 FF 00 3F 00 00 00
E1 D7 07 00 80 00 29 CD 31 52 F4 4E 4F 20 4E 41
With int, you only got the guarantee that it can hold 32-bit signed integers. With your code, you read sizeof(int) bytes for every of your variables, even though they differ in size. There are uint16_t, uint8_t, uint32_t types on most systems. Use those for fixed-width data. Note also that they are unsigned. You don't want negative sectors per cluster, do you?

Dissecting a binary file in C

I'm working on assignment in which I need to dissect a binary file retrieve the source address from the header data. I was able to get hex data from the file to write out as we were instructed but I can't make heads or tails of what I am looking at. Here's the print out code I used.
FILE *ptr_myfile;
char buf[8];
ptr_myfile = fopen("packets.1","rb");
if (!ptr_myfile)
{
printf("Unable to open file!");
return 1;
}
size_t rb;
do {
rb = fread(buf, 1, 8, ptr_myfile);
if( rb ) {
size_t i;
for(i = 0; i < rb; ++i) {
printf("%02x", (unsigned int)buf[i]);
}
printf("\n");
}
} while( rb );
And here's a small portion of the output:
120000003c000000
4500003c195d0000
ffffff80011b60ffffff8115250b
4a7d156708004d56
0001000561626364
65666768696a6b6c
6d6e6f7071727374
7576776162636465
666768693c000000
4500003c00000000
ffffffff01ffffffb5ffffffbc4a7d1567
ffffff8115250b00005556
0001000561626364
65666768696a6b6c
6d6e6f7071727374
7576776162636465
666768693c000000
4500003c195d0000
ffffff8001775545ffffffcfffffffbe29
ffffff8115250108004d56
0001000561626364
65666768696a6b6c
6d6e6f7071727374
7576776162636465
666768693c000000
4500003c195f0000
......
So we are using this diagram to aid in the assignment
I'm really having difficulty translating information from the binary file to some thing useful that I can manage, and searching the website hasn't yielded me much. I just need some help putting me in the right direction.
Ok, it looks like you actually are reversing parts of an IP packet based on the diagram. This diagram is based on 32-bit words, with each bit being shown as the small 'ticks' along the horizontal ruler looking thing at the top. Bytes are shown as the big 'ticks' on the top ruler.
So, if you were to read the first byte of the file, the low-order nibble (the low-order four bytes) contains the version, and the high order nibble contains the number of 32-bit words in the header (assuming we can interpret this as an IP header).
So, from you diagram, you can see that the source address is in the fourth word so to read this, you can advance the file point to this point and read in four bytes. So in pseudo-code you should be able to do this:
fp = fopen("the file name")
fseek(fp, 12) // advance the file pointer 12 bytes
fread(buf, 1, 4, fp) // read in four bytes from the file.
Now you should have the source address in buf.
OK, to make this a bit more concrete, here is a packet I captured off my home network:
0000 00 15 ff 2e 93 78 bc 5f f4 fc e0 b6 08 00 45 00 .....x._......E.
0010 00 28 18 c7 40 00 80 06 00 00 c0 a8 01 05 5e 1f .(..#.........^.
0020 1d 9a fd d3 00 50 bd 72 7e e9 cf 19 6a 19 50 10 .....P.r~...j.P.
0030 41 10 3d 81 00 00 A.=...
The first 14 bytes are the EthernetII header, with the first six bytes (00 15 ff 2e 93 78) being the destination MAC address, the next six bytes (bc 5f f4 fc e0 b6) is the source MAC address and the new two bytes (08 00) denote that the next header is of type IP.
The next twenty bytes is the IP header (which you show in your figure), these bytes are:
0000 45 00 00 28 18 c7 40 00 80 06 00 00 c0 a8 01 05 E..(..#.........
0010 5e 1f 1d 9a ^...
So to interpret this lets look at 4-byte words.
The first 4-byte word (45 00 00 28), according to your figure is:
first byte : version & length, we have 0x45 meaning IPv4, and 5 4-byte words in length
second byte : Type of Service 0x00
3rd & 4th bytes: total length 0x00 0x28 or 40 bytes.
The second 4-byte word (18 c7 40 00), according to your figure is:
1st & 2nd bytes: identification 0x18 0xc7
3rd & 4th bytes: flags (3-bits) & fragmentation offset (13-bits)
flags - 0x02 0x40 is 0100 0000 in binary, and taking the first three bits 010 gives us 0x02 for the flags.
offset - 0x00
The third 4-byte word (80 06 00 00), according to your figure is:
first byte : TTL, 0x80 or 128 hops
second byte : protocol 0x06 or TCP
3rd & 4th bytes: 0x00 0x00
The fourth 4-byte word (c0 a8 01 05), according to your figure is:
1st to 4th bytes: source address, in this case 192.168.1.5
notice that each byte corresponds to one of the octets in the IP address.
The fifth 4-byte word (5e 1f 1d 9a), according to your figure is:
1st to 4th bytes: destination address, in this case 94.31.29.154
Doing this type of programming is a bit confusing at first, I recommend doing a paring by hand (like I did above) a few times to get the hang of it.
One final thing, in this line of code printf("%02x", (unsigned int)buf[i]);, I'd recommend changing it to printf("%02x ", (unsigned char)buf[i]);. Remember that each element in you buf array represents a single byte read from the file.
Hope this helps,
T.

beacon frame captured by libpcap is something strange

I captured beacon frame with library libpcap(Ubuntu, c)
I changed wlan mode to monitor and captured by following function calls
// 3000 is large enough number for test
pcd = pcap_open_live(dev,3000,PROMISCUOUS,-1,errbuf)
// filter with "wlan type mgt subtype beacon"
pcap_compile(pcd,&bpg,"wlan type mgt subtype beacon",1,PCAP_NETMASK_UNKNOWN)
pcap_setfilter(pcd, &bpg)
and following is packet_view
void packet_view(
unsigned char *user,
const struct pcap_pkthdr *h,
const unsigned char *p
){
int len;
len = 0;
printf("PACKET\n");
while(len < h->len) {
printf("%02x ", *(p++));
if(!(++len % 16))
printf("\n");
}
printf("\n");
return ;
}
and my got following result (just most significant 32bits)
00 00 12 00 2e 48 00 00 00 02 6c 09 a0 00 bb 01
00 00 80 00 00 00 ff ff ff ff ff ff 00 08 9f bf
but... actually beacon frame must start with bit "08"
because beacon frame's protocol version = 00 type = 00 and subtype = 1000 => 00001000(08)
what is the reason that i got packet start with 00? althougt I filtered with "wlan type mgt subtype beacon" ??
You're missing one pcap call - a call to pcap_datalink().
Unless pcap_datalink() returns DLT_IEEE802_11, the packet does NOT begin with an 802.11 header. If, for example, it returns DLT_IEEE802_11_RADIO, the packet begins with a radiotap header, and has an 802.11 header after it; that looks like what your packet has.
See the tcpdump.org link-layer header types page for information on the values pcap_datalink() can return and the values that appear in pcap and pcap-ng files.
Set your filter to
"link[0] == 0x80"
Works for me!
Since apparently
https://wiki.wireshark.org/CaptureFilters
Capture WLAN traffic without Beacons:
link[0] != 0x80

How can I access members of a struct when it's not aligned properly?

I'm afraid that I'm not very good at low level C stuff, I'm more used to
using objects in Obj-c, so please excuse me if this is an obvious question, or if I've completely misunderstood something...
I am attempting to write an application in Cocoa/Obj-C which communicates with an external bit of hardware (a cash till.) I have the format of the data the device sends and receives - and have successfully got some chunks of data from the device.
For example: the till exchanges PLU (price data) in chunks of data in the following format: (from the documentation)
Name Bytes Type
Name Bytes Type
PLU code h 4 long
PLU code L 4 long
desc 19 char
Group 3 char
Status 5 char
PLU link code h 4 long
PLU link code l 4 long
M&M Link 1 char
Min. Stock. 2 int
Price 1 4 long
Price 2 4 long
Total 54 Bytes
So I have a struct in the following form in which to hold the data from the till:
typedef struct MFPLUStructure {
UInt32 pluCodeH;
UInt32 pluCodeL;
unsigned char description[19];
unsigned char group[3];
unsigned char status[5];
UInt32 linkCodeH;
UInt32 linkCodeL;
unsigned char mixMatchLink;
UInt16 minStock;
UInt32 price[2];
} MFPLUStructure;
I have some known sample data from the till (below) which I have checked by hand and is valid
00 00 00 00 4E 61 BC 00 54 65 73 74 20 50 4C 55 00 00 00 00 00 00 00 00 00 00 00 09 08 07 17 13 7C 14 04 00 00 00 00 09 03 00 00 05 BC 01 7B 00 00 00 00 00 00 00
i.e.
bytes 46 to 50 are <7B 00 00 00> == 123 as I would expect as the price is set to '123' on the till.
byte 43 is <05> == 5 as I would expect as the 'mix and match link' is set to 5 on the till.
bytes 39 to 43 are <09 03 00 00> == 777 as I would expect as the 'link code' is set to '777' on the till.
Bytes 27,28,29 are <09 08 07> which are the three groups (7,8 & 9) that I would expect.
The problem comes when I try to get some of the data out of the structure programmatically: The early members work correctly right up to, and including the five 'status' bytes. However, members after that don't come out properly. (see debugger screenshot below.)
Image 1 - http://i.stack.imgur.com/nOdER.png
I assume that the reason for this is because the five status bytes push later members out of alignment - i.e. they are over machine word boundaries. Is this right?
Image 2 - i.imgur.com/ZhbXU.png
Am I right in making that assumption?
And if so, how can I get the members in and out correctly?
Thanks for any help.
Either access the data a byte at a time and assemble it into larger types, or memcpy it into an aligned variable. The latter is better if the data is known to be in a format specific to the host's endianness, etc. The former is better if the data follows an external specification that might not match the host.
If you're sure that endianness of host and wire agree, you could also use a packed structure to read the data in a single pass. However, this is compiler-specific and will most likely impact performance of member access.
Assuming gcc, you'd use the following declarations:
struct __attribute__ ((__packed__)) MFPLUStructure { ... };
typedef struct MFPLUStructure MFPLUStructure;
If you decide to use a packed structure, you should also verify that it is of correct size:
assert(sizeof (MFPLUStructure) == 54);

Resources