arp_send()函数分析

  (代码基于linux2.4.0)

void arp_send(int type,/*arp协议编码,如ARPOP_REPLY(arp响应)、ARPOP_REQUEST(arp请求)等*/
       int ptype, /*以太网协议类型,或者说是接口的硬件类型,如ARP(ETH_P_ARP)、x.25(ETH_P_X25)、ip(ETH_P_IP)等*/
       u32 dest_ip, /*目的ip地址*/
       struct net_device *dev, /*用于发包的网卡设备*/
       u32 src_ip, /*源ip地址*/
       unsigned char *dest_hw, /*目的硬件地址*/
       unsigned char *src_hw,/*源硬件地址*/
       unsigned char *target_hw) /*目的硬件地址,它用于arp响应时填充到arp包中,arp请求应该填0*/
{
 struct sk_buff *skb;/*用于管理封装arp包的存储空间的sk_buff指针*/
 struct arphdr *arp;/*指向arp包头*/
 unsigned char *arp_ptr;/*指向arp数据*/

 /*
  * No arp on this interface.
  */
 
 if (dev->flags&IFF_NOARP)
  return;

 /*
  * 分配缓冲区,
  * ARP数据包格式为:
  * 硬件类型(2bytes)+协议类型(2bytes)+硬件地址长度(1bytes)+协议长度(1bytes)+操作码(2bytes)
  *     +源mac地址(6bytes)+源IP地址(4bytes)+目的mac地址(6bytes)+目的IP地址(4bytes)
  * 长度=以太网包头长度+arp包头长度+arp数据长度(源ip长度4+源硬件地址长度+目的ip长度4+目的硬件地址长度)+15(用作缓冲区字对齐)
  */
 
 skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4)
    + dev->hard_header_len + 15, GFP_ATOMIC);
 if (skb == NULL)
  return;

 skb_reserve(skb, (dev->hard_header_len+15)&~15);/*在skb中申请以太网硬件头缓冲区,且边界字对齐*/
 skb->nh.raw = skb->data;
 /*在skb中申请arp数据包缓冲区(包括arp头和数据)*/
 arp = (struct arphdr *) skb_put(skb,sizeof(struct arphdr) + 2*(dev->addr_len+4));
 skb->dev = dev;/*指定数据包发送网卡*/
 skb->protocol = __constant_htons (ETH_P_ARP);
 if (src_hw == NULL)
  src_hw = dev->dev_addr;/*如果源硬件mac地址未提供则赋值为发送网卡的硬件地址*/
 if (dest_hw == NULL)
  dest_hw = dev->broadcast;/*如果目标硬件mac地址未提供则赋值为广播地址,通常arp请求时它置为广播地址*/

 /*
  *填充设备MAC地址.MAC帧格式:
  *目的地址(6字节)+ 源地址(6字节)+ 2字节字段(IEEE802.3:数据长度/DIX以太网:数据类型)+ 数据(46~~1500)+FCS
  */
 if (dev->hard_header &&
     dev->hard_header(skb,dev,ptype,dest_hw,src_hw,skb->len) < 0)
  goto out;

 /*
  * Fill out the arp protocol part.
  *
  * The arp hardware type should match the device type, except for FDDI,
  * which (according to RFC 1390) should always equal 1 (Ethernet).
  */
 /*
  * Exceptions everywhere. AX.25 uses the AX.25 PID value not the
  * DIX code for the protocol. Make these device structure fields.
  */
 switch (dev->type) {
 default:
  arp->ar_hrd = htons(dev->type);
  arp->ar_pro = __constant_htons(ETH_P_IP);
  break;

#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
 case ARPHRD_AX25:
  arp->ar_hrd = __constant_htons(ARPHRD_AX25);
  arp->ar_pro = __constant_htons(AX25_P_IP);
  break;

#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
 case ARPHRD_NETROM:
  arp->ar_hrd = __constant_htons(ARPHRD_NETROM);
  arp->ar_pro = __constant_htons(AX25_P_IP);
  break;
#endif
#endif

#ifdef CONFIG_FDDI
 case ARPHRD_FDDI:
  arp->ar_hrd = __constant_htons(ARPHRD_ETHER);
  arp->ar_pro = __constant_htons(ETH_P_IP);
  break;
#endif
#ifdef CONFIG_TR
 case ARPHRD_IEEE802_TR:
  arp->ar_hrd = __constant_htons(ARPHRD_IEEE802);
  arp->ar_pro = __constant_htons(ETH_P_IP);
  break;
#endif
 }
 
 arp->ar_hln = dev->addr_len;/*对以太网而言,是MAC地址长度,应该为6*/
 arp->ar_pln = 4;/*对IP协议则是IP地址的长度*/
 arp->ar_op = htons(type);/*arp请求或响应*/

 arp_ptr=(unsigned char *)(arp+1);/*跳过ARP头,指向数据部分*/

 memcpy(arp_ptr, src_hw, dev->addr_len);/*填充源硬件地址*/
 arp_ptr+=dev->addr_len;/*指针后移*/
 memcpy(arp_ptr, &src_ip,4);/*填充源IP地址*/
 arp_ptr+=4;/*指针后移*/
 if (target_hw != NULL) /*不为空则填充目标硬件地址,一般用于arp响应,填充解析的硬件地址*/
  memcpy(arp_ptr, target_hw, dev->addr_len);
 else  /*否则填充全0地址,一般用于arp请求,因为目标硬件地址未知*/
  memset(arp_ptr, 0, dev->addr_len);
 arp_ptr+=dev->addr_len; /*指针后移*/
 memcpy(arp_ptr, &dest_ip, 4);/*填充目的IP地址*/
 skb->dev = dev; /*指定发送数据包的网卡设备*/

 dev_queue_xmit(skb);/*函数内部调用以太网卡驱动程序的发送函数将数据包发送到网络上*/
 return;

out:
 kfree_skb(skb);

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很抱歉,作为AI语言模型,我没有权限编写代码。但是,我可以为您提供一些关于使用WinPcap发送ARP数据包的基本信息。 WinPcap是一个用于Windows平台的网络数据包捕获库,它可以捕获和发送数据包。以下是使用WinPcap发送ARP数据包的基本步骤: 1. 打开WinPcap: ```c pcap_t *adhandle; adhandle = pcap_open_live(device, 65536, 1, 1000, errbuf); ``` 其中,device是要使用的网络设备,例如“eth0”或“wlan0”。65536是要捕获的数据包的最大大小,1是指要开启混杂模式(即捕获所有流经网络设备的数据包),1000是指超时时间(以毫秒为单位),errbuf是一个缓冲区,用于存储错误信息。 2. 构造ARP数据包: ```c char packet[42]; // ARP数据包的大小为42个字节 memset(packet, 0, sizeof(packet)); // 清零 struct ether_header *eth_header = (struct ether_header *) packet; struct ether_arp *arp_header = (struct ether_arp *) (packet + sizeof(struct ether_header)); // 填充以太网头部 eth_header->ether_dhost[0] = 0xff; eth_header->ether_dhost[1] = 0xff; eth_header->ether_dhost[2] = 0xff; eth_header->ether_dhost[3] = 0xff; eth_header->ether_dhost[4] = 0xff; eth_header->ether_dhost[5] = 0xff; eth_header->ether_shost[0] = 0x00; // 发送方MAC地址 eth_header->ether_shost[1] = 0x11; eth_header->ether_shost[2] = 0x22; eth_header->ether_shost[3] = 0x33; eth_header->ether_shost[4] = 0x44; eth_header->ether_shost[5] = 0x55; eth_header->ether_type = htons(ETHERTYPE_ARP); // ARP数据包类型 // 填充ARP头部 arp_header->arp_hrd = htons(ARPHRD_ETHER); // 以太网硬件类型 arp_header->arp_pro = htons(ETHERTYPE_IP); // IP协议类型 arp_header->arp_hln = 6; // MAC地址长度为6字节 arp_header->arp_pln = 4; // IP地址长度为4字节 arp_header->arp_op = htons(ARPOP_REQUEST); // ARP请求操作 arp_header->arp_sha[0] = 0x00; // 发送方MAC地址 arp_header->arp_sha[1] = 0x11; arp_header->arp_sha[2] = 0x22; arp_header->arp_sha[3] = 0x33; arp_header->arp_sha[4] = 0x44; arp_header->arp_sha[5] = 0x55; arp_header->arp_spa[0] = 192; // 发送方IP地址 arp_header->arp_spa[1] = 168; arp_header->arp_spa[2] = 1; arp_header->arp_spa[3] = 1; arp_header->arp_tha[0] = 0x00; // 目标MAC地址(未知) arp_header->arp_tha[1] = 0x00; arp_header->arp_tha[2] = 0x00; arp_header->arp_tha[3] = 0x00; arp_header->arp_tha[4] = 0x00; arp_header->arp_tha[5] = 0x00; arp_header->arp_tpa[0] = 192; // 目标IP地址 arp_header->arp_tpa[1] = 168; arp_header->arp_tpa[2] = 1; arp_header->arp_tpa[3] = 2; ``` 在上面的示例中,我们构造了一个ARP请求数据包,用于获取192.168.1.2的MAC地址。可以根据需要更改目标IP地址和发送方MAC地址。 3. 发送ARP数据包: ```c int res; res = pcap_sendpacket(adhandle, packet, sizeof(packet)); if (res != 0) { printf("Error sending ARP packet: %s\n", pcap_geterr(adhandle)); } ``` 在上面的示例中,我们使用pcap_sendpacket函数发送构造的ARP数据包,如果发送失败,则会打印错误信息。 希望以上信息能够帮助您编写WinPcap发送ARP数据包的程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值