penguin_to_bits
02-29-2008, 01:37 AM
I've been programming in C and C++ for some time but I'm new to network programming.
I started using Berkeley sockets today and I managed to handcraft my own ethernet frames (i.e. I was able to send a raw byte buffer). I was playing around with sending arp request and arp replies today, and I got it working.
Before I go any further with Berkeley sockets tho, I'd like to make sure that it's the best choice. I've heard that a lot of programs, such as nmap, use pcap. Which one's better, pcap or Berkeley? I suppose I should be more specific -- these are the criteria I'm looking at:
1) Portability (I hear Berkeley is the most portable... that right?)
2) Best at low-level stuff (e.g. handcrafting your own Ethernet frames)
3) Best at high-level stuff (e.g. communicating over TCP)
I found some sample code on the web for sending raw ethernet frames with Berkeley, and I took hints from it to write my own code. The following is the code I produced for sending arp requests and replies. If anyone here is familiar with Berkeley, I'd like to ask why I have to make a call to "ioctl" to get the index of the NIC? I mean, the socket's already open, so why should I need the index of the NIC? (I've tried doing it without getting the NIC's index and it doesn't work)
Here's my code, maybe someone can enlighten me on how I can do it better:
#include <stdlib.h> /* EXIT_FAILURE */
#include <string.h> /* memcpy, memset */
#include <stdio.h> /* puts */
#include <sys/ioctl.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <linux/if_ether.h>
#include <netpacket/packet.h>
typedef char unsigned uint8;
typedef struct HeaderFrame {
uint8 dest[6], src[6], proto[2];
} HeaderFrame;
typedef struct HeaderARP {
uint8 hard_type[2],
proto_type[2],
hard_len,
proto_len,
op[2],
src_MAC[6],
src_IP[4],
dest_MAC[6],
dest_IP[4];
} HeaderARP;
typedef struct EntireARPFrame {
HeaderFrame hframe;
HeaderARP harp;
} EntireARPFrame;
void SetCommonARPFields(EntireARPFrame *const p)
{
# define frame (p->hframe)
# define arp (p->harp)
frame.proto[0] = 0x08; frame.proto[1] = 0x06;
arp.hard_type[0] = 0x00; arp.hard_type[1] = 0x01;
arp.proto_type[0] = 0x08; arp.proto_type[1] = 0x00;
arp.hard_len = 6;
arp.proto_len = 4;
arp.op[0] = 0x00;
# undef frame
# undef arp
}
void SendARPRequest(int const s, struct sockaddr_ll const *const nic_dev,
uint8 const (*const pdest_IP)[4],
uint8 const (*const psrc_IP)[4],
uint8 const (*const psrc_MAC)[6])
{
EntireARPFrame eaf;
SetCommonARPFields(&eaf);
# define frame (eaf.hframe)
# define arp (eaf.harp)
memset(frame.dest,0xFF,sizeof frame.dest);
memcpy(frame.src,psrc_MAC,sizeof frame.src);
arp.op[1] = 0x01; /* 1 == Request */
memcpy(arp.src_MAC,psrc_MAC,sizeof arp.src_MAC);
memcpy(arp.src_IP,psrc_IP,sizeof arp.src_IP);
memset(arp.dest_MAC,0x00,sizeof arp.dest_MAC);
memcpy(arp.dest_IP,pdest_IP,sizeof arp.dest_IP);
# undef frame
# undef arp
puts("Sending frame");
sendto(s, &eaf, sizeof eaf, 0, (struct sockaddr const*)nic_dev,sizeof *nic_dev);
puts("Frame sent");
}
void SendARPReply(int const s, struct sockaddr_ll const *const nic_dev,
uint8 const (*const pdest_IP)[4],
uint8 const (*const pdest_MAC)[6],
uint8 const (*const psrc_IP)[4],
uint8 const (*const psrc_MAC)[6])
{
EntireARPFrame eaf;
SetCommonARPFields(&eaf);
# define frame (eaf.hframe)
# define arp (eaf.harp)
memcpy(frame.dest,pdest_MAC,sizeof frame.dest);
memcpy(frame.src,psrc_MAC,sizeof frame.src);
arp.op[1] = 0x02; /* 2 == reply */
memcpy(arp.src_MAC,psrc_MAC,sizeof arp.src_MAC);
memcpy(arp.src_IP,psrc_IP,sizeof arp.src_IP);
memcpy(arp.dest_MAC,pdest_MAC,sizeof arp.dest_MAC);
memcpy(arp.dest_IP,pdest_IP,sizeof arp.dest_IP);
# undef frame
# undef arp
puts("Sending frame");
sendto(s, &eaf, sizeof eaf, 0, (struct sockaddr const*)nic_dev,sizeof *nic_dev);
//sendto(s,&eaf,sizeof eaf,0,0,0);
puts("Frame sent");
}
void PrepareDevice(int const s,struct sockaddr_ll *const p)
{
# define device (*p)
//uint8 const src_MAC[6] = {0x00,0x19,0xE0,0x68,0x8A,0x71};
//uint8 const src_MAC[6] = {0xEE,0x01,0x02,0x03,0x04,0x05};
struct ifreq card;
strcpy(card.ifr_name, "rausb0");
puts("Attempting to get NIC index");
if (-1 == ioctl(s, SIOCGIFINDEX, &card)) return;
puts("Got NIC index");
memset(&device, 0, sizeof device);
device.sll_ifindex = card.ifr_ifindex;
//device.sll_family = AF_PACKET;
//memcpy(device.sll_addr, src_MAC, 6);
//device.sll_halen = htons(6);
/* I commented the above crap out coz it turned out I didn't need it */
# undef device
}
uint8 const src_MAC[6] = {0x00,0x19,0xE0,0x78,0x7D,0x82};
uint8 const dest_MAC[6] = {0x00,0x19,0xE0,0x64,0xBB,0x32};
uint8 src_IP[4] = {10,9,8,35};
uint8 dest_IP[4] = {10,9,8,1};
int main(void)
{
struct sockaddr_ll nic_dev = {0};
int s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
puts("Attempting to open socket");
if (s < 0) return EXIT_FAILURE;
puts("Socket is open");
PrepareDevice(s,&nic_dev);
for (src_IP[3] = 100; 255 != dest_IP[3]; ++dest_IP[3])
{
if (35 == dest_IP[3]) continue;
SendARPReply(s,&nic_dev,&dest_IP,&dest_MAC,&src_IP,&src_MAC);
}
return 0;
}
Don't mind the code I wrote in main, what I'm curious about is whether I went about writing the other functions correctly.
Thanks for reading!
MOD EDIT: please use code tags
I started using Berkeley sockets today and I managed to handcraft my own ethernet frames (i.e. I was able to send a raw byte buffer). I was playing around with sending arp request and arp replies today, and I got it working.
Before I go any further with Berkeley sockets tho, I'd like to make sure that it's the best choice. I've heard that a lot of programs, such as nmap, use pcap. Which one's better, pcap or Berkeley? I suppose I should be more specific -- these are the criteria I'm looking at:
1) Portability (I hear Berkeley is the most portable... that right?)
2) Best at low-level stuff (e.g. handcrafting your own Ethernet frames)
3) Best at high-level stuff (e.g. communicating over TCP)
I found some sample code on the web for sending raw ethernet frames with Berkeley, and I took hints from it to write my own code. The following is the code I produced for sending arp requests and replies. If anyone here is familiar with Berkeley, I'd like to ask why I have to make a call to "ioctl" to get the index of the NIC? I mean, the socket's already open, so why should I need the index of the NIC? (I've tried doing it without getting the NIC's index and it doesn't work)
Here's my code, maybe someone can enlighten me on how I can do it better:
#include <stdlib.h> /* EXIT_FAILURE */
#include <string.h> /* memcpy, memset */
#include <stdio.h> /* puts */
#include <sys/ioctl.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <linux/if_ether.h>
#include <netpacket/packet.h>
typedef char unsigned uint8;
typedef struct HeaderFrame {
uint8 dest[6], src[6], proto[2];
} HeaderFrame;
typedef struct HeaderARP {
uint8 hard_type[2],
proto_type[2],
hard_len,
proto_len,
op[2],
src_MAC[6],
src_IP[4],
dest_MAC[6],
dest_IP[4];
} HeaderARP;
typedef struct EntireARPFrame {
HeaderFrame hframe;
HeaderARP harp;
} EntireARPFrame;
void SetCommonARPFields(EntireARPFrame *const p)
{
# define frame (p->hframe)
# define arp (p->harp)
frame.proto[0] = 0x08; frame.proto[1] = 0x06;
arp.hard_type[0] = 0x00; arp.hard_type[1] = 0x01;
arp.proto_type[0] = 0x08; arp.proto_type[1] = 0x00;
arp.hard_len = 6;
arp.proto_len = 4;
arp.op[0] = 0x00;
# undef frame
# undef arp
}
void SendARPRequest(int const s, struct sockaddr_ll const *const nic_dev,
uint8 const (*const pdest_IP)[4],
uint8 const (*const psrc_IP)[4],
uint8 const (*const psrc_MAC)[6])
{
EntireARPFrame eaf;
SetCommonARPFields(&eaf);
# define frame (eaf.hframe)
# define arp (eaf.harp)
memset(frame.dest,0xFF,sizeof frame.dest);
memcpy(frame.src,psrc_MAC,sizeof frame.src);
arp.op[1] = 0x01; /* 1 == Request */
memcpy(arp.src_MAC,psrc_MAC,sizeof arp.src_MAC);
memcpy(arp.src_IP,psrc_IP,sizeof arp.src_IP);
memset(arp.dest_MAC,0x00,sizeof arp.dest_MAC);
memcpy(arp.dest_IP,pdest_IP,sizeof arp.dest_IP);
# undef frame
# undef arp
puts("Sending frame");
sendto(s, &eaf, sizeof eaf, 0, (struct sockaddr const*)nic_dev,sizeof *nic_dev);
puts("Frame sent");
}
void SendARPReply(int const s, struct sockaddr_ll const *const nic_dev,
uint8 const (*const pdest_IP)[4],
uint8 const (*const pdest_MAC)[6],
uint8 const (*const psrc_IP)[4],
uint8 const (*const psrc_MAC)[6])
{
EntireARPFrame eaf;
SetCommonARPFields(&eaf);
# define frame (eaf.hframe)
# define arp (eaf.harp)
memcpy(frame.dest,pdest_MAC,sizeof frame.dest);
memcpy(frame.src,psrc_MAC,sizeof frame.src);
arp.op[1] = 0x02; /* 2 == reply */
memcpy(arp.src_MAC,psrc_MAC,sizeof arp.src_MAC);
memcpy(arp.src_IP,psrc_IP,sizeof arp.src_IP);
memcpy(arp.dest_MAC,pdest_MAC,sizeof arp.dest_MAC);
memcpy(arp.dest_IP,pdest_IP,sizeof arp.dest_IP);
# undef frame
# undef arp
puts("Sending frame");
sendto(s, &eaf, sizeof eaf, 0, (struct sockaddr const*)nic_dev,sizeof *nic_dev);
//sendto(s,&eaf,sizeof eaf,0,0,0);
puts("Frame sent");
}
void PrepareDevice(int const s,struct sockaddr_ll *const p)
{
# define device (*p)
//uint8 const src_MAC[6] = {0x00,0x19,0xE0,0x68,0x8A,0x71};
//uint8 const src_MAC[6] = {0xEE,0x01,0x02,0x03,0x04,0x05};
struct ifreq card;
strcpy(card.ifr_name, "rausb0");
puts("Attempting to get NIC index");
if (-1 == ioctl(s, SIOCGIFINDEX, &card)) return;
puts("Got NIC index");
memset(&device, 0, sizeof device);
device.sll_ifindex = card.ifr_ifindex;
//device.sll_family = AF_PACKET;
//memcpy(device.sll_addr, src_MAC, 6);
//device.sll_halen = htons(6);
/* I commented the above crap out coz it turned out I didn't need it */
# undef device
}
uint8 const src_MAC[6] = {0x00,0x19,0xE0,0x78,0x7D,0x82};
uint8 const dest_MAC[6] = {0x00,0x19,0xE0,0x64,0xBB,0x32};
uint8 src_IP[4] = {10,9,8,35};
uint8 dest_IP[4] = {10,9,8,1};
int main(void)
{
struct sockaddr_ll nic_dev = {0};
int s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
puts("Attempting to open socket");
if (s < 0) return EXIT_FAILURE;
puts("Socket is open");
PrepareDevice(s,&nic_dev);
for (src_IP[3] = 100; 255 != dest_IP[3]; ++dest_IP[3])
{
if (35 == dest_IP[3]) continue;
SendARPReply(s,&nic_dev,&dest_IP,&dest_MAC,&src_IP,&src_MAC);
}
return 0;
}
Don't mind the code I wrote in main, what I'm curious about is whether I went about writing the other functions correctly.
Thanks for reading!
MOD EDIT: please use code tags