我正在尝试通过网络发送一些手动制作的ARP数据包,更具体地说是获取主机MAC地址的ARP请求。 我无法得到最终的数据包,在wireshark上它仍然显示出一些不一致。 让我带你走过: 这是结构和& typedef我用遍了整个程序, 我已经定义了
代码:
#define ETH_ADDR_SIZE 6
#define IP_ADDR_SIZE 4
typedef u_char Packet;
typedef struct in_addr IP;
typedef struct ether_addr MAC;
struct Host {
IP ip;
MAC mac;
};
typedef struct pkt_eth {
MAC dest;
MAC src;
u_short type;
} pkt_eth;
typedef struct pkt_arp {
u_short htype;/* hardware type => ethernet , etc */
u_short ptype; /*protocol type => ipv4 or ipv6 */
u_char hard_addr_len; /* usually 6 bytes for ethernet */
u_char proto_addr_len; /*usually 8 bytes for ipv4 */
u_short opcode; /* type of arp */
MAC hard_addr_send;
IP proto_addr_send;
MAC hard_addr_dest;
IP proto_addr_dest;
} pkt_arp;
/* Designate our own MAC / IP addresses of the interface */
extern MAC mac;
extern IP ip;
extern char * interface;
/* Just some vars used to compare with the struct we use */
const MAC broadcast_mac = { 0xff,0xff,0xff,0xff,0xff,0xff };
const MAC null_mac = { 0x00,0x00,0x00,0x00,0x00,0x00 };
const IP broadcast_ip = { 0xffffffff };
const IP null_ip = { 0x00000000 };
const struct Host null_host = {{ 0x00000000 },
{ 0x00,0x00,0x00,0x00,0x00,0x00 }};
/* Empty mac address which can be used as a temp variable */
MAC tmp_mac = { 0x00,0x00,0x00,0x00,0x00,0x00 };
IP tmp_ip = { 0x00000000 };
以下是相关功能:
int
arp_resolve_mac ( struct Host * host )
{
struct pkt_arp * arp;
struct pkt_eth * eth;
/*Create the request packet */
Packet * request = arp_packet(REQUEST);
eth = (struct pkt_eth *) (request);
arp = (struct pkt_arp *) (request + ETH_SIZE);
/* ethernet frame */
copy_mac(ð->dest,&broadcast_mac);
copy_mac(ð->src,&mac);
/* arp request => mac dest address set to null */
copy_mac(&arp->hard_addr_send,&mac);
copy_mac(&arp->hard_addr_dest,&null_mac);
/* arp request => target ip ! */
copy_ip(&arp->proto_addr_send,&ip);
copy_ip(&arp->proto_addr_dest,&host->ip);
/* Set up sniffing. Better to do it before so less
* prepare time and if any error occurs, no need to send
* the packet. less intrusive */
pcap_init(interface,"arp");
pcap_set_arp_analyzer(arp_analyzer_resolv);
/* Sets the tmp ip variable so we will know if it the right
* response we get or a response coming from another source */
tmp_ip = host->ip;
/* sends the packet */
if(pcap_send_packet(request,ARP_PACKET_SIZE) == -1) {
fprintf(stderr,"Error while sending ARP request packet.\n");
return -1;
}
....
}
Packet *
arp_packet ( int opcode )
{
struct pkt_arp * arp;
struct pkt_eth * eth;
Packet * bytes = (Packet *) malloc(ARP_PACKET_SIZE);
if(bytes == NULL) {
fprintf(stderr,"Could not alloc ARP packet.\n");
return NULL;
}
eth = (struct pkt_eth *) (bytes);
eth->type = htons(ETHERTYPE_ARP);
/* length about hard / proto ... */
arp = (struct pkt_arp *) (bytes + ETH_SIZE);
arp->htype = htons(1);
arp->ptype = htons(0x0800);
arp->hard_addr_len = ETH_ADDR_SIZE;
arp->proto_addr_len = IP_ADDR_SIZE;
/* reply or request */
arp->opcode = opcode == REQUEST ? htons(ARPOP_REQUEST) : htons(ARPOP_REPLY);
return bytes;
} /* ----- end of function arp_empty ----- */
void copy_mac(MAC * m1,const MAC * m2) {
memcpy(m1,m2,ETH_ADDR_SIZE);
}
void copy_ip(IP * i1,const IP * i2) {
memcpy(i1,i2,IP_ADDR_SIZE);
}
void copy_host(struct Host * h1,const struct Host * h2) {
copy_mac(&h1->mac,&h2->mac);
copy_ip(&h1->ip,&h2->ip);
}
问题: 创建的数据包不太对。一切都很好,直到 hard_addr_send 。在此字段之后,有2个字节0x00,0x00(在GDB中看到),然后是IP地址。但由于这种偏移,无法正确解析此数据包。例如,在wireshark中,我没有获得“10.0.0.1”,而是获得了IP“0.0.10.0”。 以下是GDB的成绩单:
/** 14 to pass ethernet frame & 4 + 2 + 2 to go to the addresses section*/
(gdb) x/6xb request+14+4+2+2
/** My MAC address , field hard_addr_send. it's GOOD. */
0x606b16: 0x34 0x67 0x20 0x01 0x9a 0x67
(gdb) x/6xb request+14+4+2+2+6
/** 6bytes later, supposedly my IP address.
* It should be 10.0.0.7 but you can see the 0x0a shifted by 2 bytes */
0x606b1c: 0x00 0x00 0x0a 0x00 0x00 0x07
在方法“arp_resolv_mac”中,所有信息都是正确的,即struct Host包含好的信息等;我检查了一切。 我只是没有得到2个字节的偏移...在旧版本中,没有使用所有这些新结构(只有char *),我已经成功创建了一个正确的ARP数据包,所以我有点想知道如果这不是由于结构,但我对C的了解并没有延伸到记忆对象的主题......!
谢谢。
答案 0 :(得分:1)
问题是你的结构没有打包。一种解决方案是使用打包结构,即
typedef struct __attribute__ ((__packed__)) pkt_arp {
u_short htype;/* hardware type => ethernet , etc */
u_short ptype; /*protocol type => ipv4 or ipv6 */
u_char hard_addr_len; /* usually 6 bytes for ethernet */
u_char proto_addr_len; /*usually 8 bytes for ipv4 */
u_short opcode; /* type of arp */
MAC hard_addr_send;
IP proto_addr_send;
MAC hard_addr_dest;
IP proto_addr_dest;
} pkt_arp;
但是,这是其他编译器可能不支持的特定于gcc的扩展。
在我看来,最好的解决方案是直接访问字节数组的元素而不是使用结构。是的,它添加了几行代码,但它保证适用于那些不实现打包结构的编译器。