LINUX arp

来源:互联网 发布:java能开发什么软件 编辑:程序博客网 时间:2024/06/16 00:52

ARP协议:   

ARP (Address Resolution Protocol) 是个地址解析协议。也就是负责L3地址到L2地址之间的映射关系。或者说,以太网中,当一个上层协议要发包时,有了该节点的IP地址,ARP就能提供该节点的MAC地址。

OSI 模式把网络工作分为七层,彼此不直接打交道,只通过接口. IP地址在第三层, MAC地址在第二层。

协议在发生数据包时,首先要封装第三层 (IP地址)和第二层 (MAC地址)的报头, 但协议只知道目的节点的IP地址,不知道其物理地址,又不能跨第二、三层,所以得用ARP的服务。

Linux arp协议相关注册:

static struct packet_type arp_packet_type = {
 .type = cpu_to_be16(ETH_P_ARP),
 .func = arp_rcv,
};

static int arp_proc_init(void);

void __init arp_init(void)
{
 neigh_table_init(NEIGH_ARP_TABLE, &arp_tbl);

 dev_add_pack(&arp_packet_type);
 arp_proc_init();
#ifdef CONFIG_SYSCTL
 neigh_sysctl_register(NULL, &arp_tbl.parms, NULL);
#endif
 register_netdevice_notifier(&arp_netdev_notifier);
}

 

对于Linux kernel来说,整个arp封包发送由两个主要函数完成,即arp_create()和arp_xmit(),前者用于ARP封包的创建,后者用于ARP封包的发送。当然也可以直接调用函数arp_send()创建并发送ARP封包。

对于ARP封包的接收,也就是上面的arp_rcv()函数处理。

/*
 * Create an arp packet. If dest_hw is not set, we create a broadcast
 * message.
 */
struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
      struct net_device *dev, __be32 src_ip,
      const unsigned char *dest_hw,
      const unsigned char *src_hw,
      const unsigned char *target_hw)
{
 struct sk_buff *skb;
 struct arphdr *arp;
 unsigned char *arp_ptr;
 int hlen = LL_RESERVED_SPACE(dev);
 int tlen = dev->needed_tailroom;

 /*
  * Allocate a buffer
  */

 skb = alloc_skb(arp_hdr_len(dev) + hlen + tlen, GFP_ATOMIC);
 if (!skb)
  return NULL;

 skb_reserve(skb, hlen);
 skb_reset_network_header(skb);
 arp = (struct arphdr *) skb_put(skb, arp_hdr_len(dev));
 skb->dev = dev;
 skb->protocol = htons(ETH_P_ARP);
 if (!src_hw)
  src_hw = dev->dev_addr;
 if (!dest_hw)
  dest_hw = dev->broadcast;

 /*
  * Fill the device header for the ARP frame
  */
 if (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 = htons(ETH_P_IP);
  break;

#if IS_ENABLED(CONFIG_AX25)
 case ARPHRD_AX25:
  arp->ar_hrd = htons(ARPHRD_AX25);
  arp->ar_pro = htons(AX25_P_IP);
  break;

#if IS_ENABLED(CONFIG_NETROM)
 case ARPHRD_NETROM:
  arp->ar_hrd = htons(ARPHRD_NETROM);
  arp->ar_pro = htons(AX25_P_IP);
  break;
#endif
#endif

#if IS_ENABLED(CONFIG_FDDI)
 case ARPHRD_FDDI:
  arp->ar_hrd = htons(ARPHRD_ETHER);
  arp->ar_pro = htons(ETH_P_IP);
  break;
#endif
 }

 arp->ar_hln = dev->addr_len;
 arp->ar_pln = 4;
 arp->ar_op = htons(type);

 arp_ptr = (unsigned char *)(arp + 1);

 memcpy(arp_ptr, src_hw, dev->addr_len);
 arp_ptr += dev->addr_len;
 memcpy(arp_ptr, &src_ip, 4);
 arp_ptr += 4;

 switch (dev->type) {
#if IS_ENABLED(CONFIG_FIREWIRE_NET)
 case ARPHRD_IEEE1394:
  break;
#endif
 default:
  if (target_hw)
   memcpy(arp_ptr, target_hw, dev->addr_len);
  else
   memset(arp_ptr, 0, dev->addr_len);
  arp_ptr += dev->addr_len;
 }
 memcpy(arp_ptr, &dest_ip, 4);

 return skb;

out:
 kfree_skb(skb);
 return NULL;
}
发送处理:

void arp_xmit(struct sk_buff *skb)
{
 /* Send it off, maybe filter it using firewalling first.  */
 NF_HOOK(NFPROTO_ARP, NF_ARP_OUT,
  dev_net(skb->dev), NULL, skb, NULL, skb->dev,
  arp_xmit_finish);
}
EXPORT_SYMBOL(arp_xmit);

 

ARP报文字段总共有28个字节


1.硬件类型:占2个字节,表明ARP实现在何种类型的网络上。值为1:表示以太网。

2.协议类型:占2个字节表示要映射的协议地址类型。IP:0800。

3.硬件地址长度:占1个字节,表示 MAC地址长度,其值为6个字节。

4.协议地址长度:占1个字节,表示IP地址长度,此处值4个字节。

5.操作类型 :占2个字节,表示ARP数据包类型。 值为1表示ARP请求。 值2表示ARP应答。

6.源MAC地址:占6个字节,表示发送端MAC地址。

7.源IP地址:占4个字节,表示发送端IP地址。

8.目的以太网地址:占6个字节,表示目标设备的MAC物理地址。

9.目的IP地址:占4个字节,表示目标设备的IP地址。

注意:在ARP操作中,有效数据的长度为28个字节,不足以太网的最小长度46字节长度,需要填充字节,填充字节最小长度为18个字节。

说明:

Ø  在网络通讯时,源主机的应用程序知道目的主机的IP地址和端口号,却不知道目的主机的硬件地址,而数据包首先是被网卡接收到再去处理上层协议的,如果接收到的数据包的硬件地址与本机不符,则直接丢弃。因此在通讯前必须获得目的主机的硬件地址。ARP协议就起到这个作用。

Ø  当一台主机把以太网数据帧发送到位于同一局域网上的另一台主机时,是根据 48位的以太网地址来确定目的接口的,设备驱动程序从不检查 IP数据报中的目的IP地址。ARP(地址解析)模块的功能为这两种不同的地址形式提供映射:32位的 IP地址和 48位的以太网地址。

 

二.ARP请求分组或应答分组

以太网首部总共有14字节数据,arp请求报文总共有28字节。所以一个ARP请求分组或应答分组总共有46字节数据。而以太网数据包的最小数据为60字节。所以,要对其进行填充。

这里有一些重复信息

1.  在以太网的数据帧报头中和ARP请求数据帧中都有发送端的MAC物理地址。

2.  在发送ARP请求时,以太网帧头中的目的MAC物理地址为FF-FF-FF-FF-FF-FF,而在ARP帧中的目的MAC处此时为空。

3.  对一个ARP请求来说,除ARP中目的端MAC硬件地址外的所有其他的字段都有填充值。当系统收到一份目的端为本地的ARP请求报文后,它就把硬件地址填进去,然后用两个目的端地址分别替换两个发送端地址,并把操作字段置为2,最后发送出去。

 

arp_rcv()实现如下:

 /*
 * Receive an arp request from the device layer.
 */

static int arp_rcv(struct sk_buff *skb, struct net_device *dev,
     struct packet_type *pt, struct net_device *orig_dev)
{
 const struct arphdr *arp;

 /* do not tweak dropwatch on an ARP we will ignore */
 if (dev->flags & IFF_NOARP ||
     skb->pkt_type == PACKET_OTHERHOST ||
     skb->pkt_type == PACKET_LOOPBACK)
  goto consumeskb;

 skb = skb_share_check(skb, GFP_ATOMIC);
 if (!skb)
  goto out_of_mem;

 /* ARP header, plus 2 device addresses, plus 2 IP addresses.  */
 if (!pskb_may_pull(skb, arp_hdr_len(dev)))
  goto freeskb;

 arp = arp_hdr(skb);
 if (arp->ar_hln != dev->addr_len || arp->ar_pln != 4)
  goto freeskb;

 memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));

 return NF_HOOK(NFPROTO_ARP, NF_ARP_IN,
         dev_net(dev), NULL, skb, dev, NULL,
         arp_process);

consumeskb:
 consume_skb(skb);
 return NET_RX_SUCCESS;
freeskb:
 kfree_skb(skb);
out_of_mem:
 return NET_RX_DROP;
}


/*
 * Process an arp request.
 */

static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
{
 struct net_device *dev = skb->dev;
 struct in_device *in_dev = __in_dev_get_rcu(dev);
 struct arphdr *arp;
 unsigned char *arp_ptr;
 struct rtable *rt;
 unsigned char *sha;
 __be32 sip, tip;
 u16 dev_type = dev->type;
 int addr_type;
 struct neighbour *n;
 struct dst_entry *reply_dst = NULL;
 bool is_garp = false;

 /* arp_rcv below verifies the ARP header and verifies the device
  * is ARP'able.
  */

 if (!in_dev)
  goto out_free_skb;

 arp = arp_hdr(skb);

 switch (dev_type) {
 default:
  if (arp->ar_pro != htons(ETH_P_IP) ||
      htons(dev_type) != arp->ar_hrd)
   goto out_free_skb;
  break;
 case ARPHRD_ETHER:
 case ARPHRD_FDDI:
 case ARPHRD_IEEE802:
  /*
   * ETHERNET, and Fibre Channel (which are IEEE 802
   * devices, according to RFC 2625) devices will accept ARP
   * hardware types of either 1 (Ethernet) or 6 (IEEE 802.2).
   * This is the case also of FDDI, where the RFC 1390 says that
   * FDDI devices should accept ARP hardware of (1) Ethernet,
   * however, to be more robust, we'll accept both 1 (Ethernet)
   * or 6 (IEEE 802.2)
   */
  if ((arp->ar_hrd != htons(ARPHRD_ETHER) &&
       arp->ar_hrd != htons(ARPHRD_IEEE802)) ||
      arp->ar_pro != htons(ETH_P_IP))
   goto out_free_skb;
  break;
 case ARPHRD_AX25:
  if (arp->ar_pro != htons(AX25_P_IP) ||
      arp->ar_hrd != htons(ARPHRD_AX25))
   goto out_free_skb;
  break;
 case ARPHRD_NETROM:
  if (arp->ar_pro != htons(AX25_P_IP) ||
      arp->ar_hrd != htons(ARPHRD_NETROM))
   goto out_free_skb;
  break;
 }

 /* Understand only these message types */

 if (arp->ar_op != htons(ARPOP_REPLY) &&
     arp->ar_op != htons(ARPOP_REQUEST))
  goto out_free_skb;

/*
 * Extract fields
 */
 arp_ptr = (unsigned char *)(arp + 1);
 sha = arp_ptr;
 arp_ptr += dev->addr_len;
 memcpy(&sip, arp_ptr, 4);
 arp_ptr += 4;
 switch (dev_type) {
#if IS_ENABLED(CONFIG_FIREWIRE_NET)
 case ARPHRD_IEEE1394:
  break;
#endif
 default:
  arp_ptr += dev->addr_len;
 }
 memcpy(&tip, arp_ptr, 4);
/*
 * Check for bad requests for 127.x.x.x and requests for multicast
 * addresses.  If this is one such, delete it.
 */
 if (ipv4_is_multicast(tip) ||
     (!IN_DEV_ROUTE_LOCALNET(in_dev) && ipv4_is_loopback(tip)))
  goto out_free_skb;

 /*
  * For some 802.11 wireless deployments (and possibly other networks),
  * there will be an ARP proxy and gratuitous ARP frames are attacks
  * and thus should not be accepted.
  */
 if (sip == tip && IN_DEV_ORCONF(in_dev, DROP_GRATUITOUS_ARP))
  goto out_free_skb;

/*
 *     Special case: We must set Frame Relay source Q.922 address
 */
 if (dev_type == ARPHRD_DLCI)
  sha = dev->broadcast;

/*
 *  Process entry.  The idea here is we want to send a reply if it is a
 *  request for us or if it is a request for someone else that we hold
 *  a proxy for.  We want to add an entry to our cache if it is a reply
 *  to us or if it is a request for our address.
 *  (The assumption for this last is that if someone is requesting our
 *  address, they are probably intending to talk to us, so it saves time
 *  if we cache their address.  Their address is also probably not in
 *  our cache, since ours is not in their cache.)
 *
 *  Putting this another way, we only care about replies if they are to
 *  us, in which case we add them to the cache.  For requests, we care
 *  about those for us and those for our proxies.  We reply to both,
 *  and in the case of requests for us we add the requester to the arp
 *  cache.
 */

 if (arp->ar_op == htons(ARPOP_REQUEST) && skb_metadata_dst(skb))
  reply_dst = (struct dst_entry *)
       iptunnel_metadata_reply(skb_metadata_dst(skb),
          GFP_ATOMIC);

 /* Special case: IPv4 duplicate address detection packet (RFC2131) */
 if (sip == 0) {
  if (arp->ar_op == htons(ARPOP_REQUEST) &&
      inet_addr_type_dev_table(net, dev, tip) == RTN_LOCAL &&
      !arp_ignore(in_dev, sip, tip))
   arp_send_dst(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip,
         sha, dev->dev_addr, sha, reply_dst);
  goto out_consume_skb;
 }

 if (arp->ar_op == htons(ARPOP_REQUEST) &&
     ip_route_input_noref(skb, tip, sip, 0, dev) == 0) {

  rt = skb_rtable(skb);
  addr_type = rt->rt_type;

  if (addr_type == RTN_LOCAL) {
   int dont_send;

   dont_send = arp_ignore(in_dev, sip, tip);
   if (!dont_send && IN_DEV_ARPFILTER(in_dev))
    dont_send = arp_filter(sip, tip, dev);
   if (!dont_send) {
    n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
    if (n) {
     arp_send_dst(ARPOP_REPLY, ETH_P_ARP,
           sip, dev, tip, sha,
           dev->dev_addr, sha,
           reply_dst);
     neigh_release(n);
    }
   }
   goto out_consume_skb;
  } else if (IN_DEV_FORWARD(in_dev)) {
   if (addr_type == RTN_UNICAST  &&
       (arp_fwd_proxy(in_dev, dev, rt) ||
        arp_fwd_pvlan(in_dev, dev, rt, sip, tip) ||
        (rt->dst.dev != dev &&
         pneigh_lookup(&arp_tbl, net, &tip, dev, 0)))) {
    n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
    if (n)
     neigh_release(n);

    if (NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED ||
        skb->pkt_type == PACKET_HOST ||
        NEIGH_VAR(in_dev->arp_parms, PROXY_DELAY) == 0) {
     arp_send_dst(ARPOP_REPLY, ETH_P_ARP,
           sip, dev, tip, sha,
           dev->dev_addr, sha,
           reply_dst);
    } else {
     pneigh_enqueue(&arp_tbl,
             in_dev->arp_parms, skb);
     goto out_free_dst;
    }
    goto out_consume_skb;
   }
  }
 }

 /* Update our ARP tables */

 n = __neigh_lookup(&arp_tbl, &sip, dev, 0);

 if (IN_DEV_ARP_ACCEPT(in_dev)) {
  unsigned int addr_type = inet_addr_type_dev_table(net, dev, sip);

  /* Unsolicited ARP is not accepted by default.
     It is possible, that this option should be enabled for some
     devices (strip is candidate)
   */
  is_garp = arp->ar_op == htons(ARPOP_REQUEST) && tip == sip &&
     addr_type == RTN_UNICAST;

  if (!n &&
      ((arp->ar_op == htons(ARPOP_REPLY)  &&
    addr_type == RTN_UNICAST) || is_garp))
   n = __neigh_lookup(&arp_tbl, &sip, dev, 1);
 }

 if (n) {
  int state = NUD_REACHABLE;
  int override;

  /* If several different ARP replies follows back-to-back,
     use the FIRST one. It is possible, if several proxy
     agents are active. Taking the first reply prevents
     arp trashing and chooses the fastest router.
   */
  override = time_after(jiffies,
          n->updated +
          NEIGH_VAR(n->parms, LOCKTIME)) ||
      is_garp;

  /* Broadcast replies and request packets
     do not assert neighbour reachability.
   */
  if (arp->ar_op != htons(ARPOP_REPLY) ||
      skb->pkt_type != PACKET_HOST)
   state = NUD_STALE;
  neigh_update(n, sha, state,
        override ? NEIGH_UPDATE_F_OVERRIDE : 0);
  neigh_release(n);
 }

out_consume_skb:
 consume_skb(skb);

out_free_dst:
 dst_release(reply_dst);
 return NET_RX_SUCCESS;

out_free_skb:
 kfree_skb(skb);
 return NET_RX_DROP;
}

三.ARP协议工作过程:

1.     原理:(ARP协议只使用于局域网中)

1>   在局域网中,网络中实际传输的是“帧”,帧里面是有目标主机的MAC地址的。

2>   在以太网中,一个主机要和另一个主机进行直接通信,必须要知道目标主机的MAC地址。但这个目标MAC地址是如何获得呢?它就是通过地址解析协议获得的。所谓“地址解析”就是主机在发送帧前将目标IP地址转换成目标MAC地址的过程。

3>   ARP协议的基本功能就是通过目标设备的IP地址,查询目标设备的MAC地址,以保证通信的顺利进行。

4>   点对点的连接是不需要ARP协议的

2.    工作过程:

1>   当主机A向本局域网上的某个主机B发送IP数据报时,就先在自己的ARP缓冲表中查看有无主机B的IP地址。

2>   如果有,就可以查出其对应的硬件地址,再将此硬件地址写入MAC帧,然后通过以太网将数据包发送到目的主机中。

3>   如果查不到主机B的IP地址的表项。可能是主机B才入网,也可能是主机A刚刚加电。其高速缓冲表还是空的。在这中情况下,主机A就自动运行ARP。

(1)ARP进程在本局域网上广播一个ARP请求分组。ARP请求分组的主要内容是表明:我的IP地址是192.168.0.2,我的硬件地址是00-00-C0-15-AD-18.我想知道IP地址为192.168.0.4的主机的硬件地址。

(2)在本局域网上的所有主机上运行的ARP进行都收到此ARP请求分组。

(3)主机B在ARP请求分组中见到自己的IP地址,就向主机A发送ARP响应分组,并写入自己的硬件地址。其余的所有主机都不理睬这个ARP请求分组。ARP响应分组的主要内容是表明:“我的IP地址是192.168.0.4,我的硬件地址是08-00-2B-00-EE-AA”,请注意:虽然ARP请求分组是广播发送的,但ARP响应分组是普通的单播,即从一个源地址发送到一个目的地址。

(4)主机A收到主机B的ARP响应分组后,就在其ARP高速缓冲表中写入主机B的IP地址到硬件地址的映射。

 

需要注意的是,ARP协议与邻居子系统密切合作:相关数据结构对象定义如下:

static const struct neigh_ops arp_generic_ops = {
 .family =  AF_INET,
 .solicit =  arp_solicit,
 .error_report =  arp_error_report,
 .output =  neigh_resolve_output,
 .connected_output = neigh_connected_output,
};

static const struct neigh_ops arp_hh_ops = {
 .family =  AF_INET,
 .solicit =  arp_solicit,
 .error_report =  arp_error_report,
 .output =  neigh_resolve_output,
 .connected_output = neigh_resolve_output,
};

static const struct neigh_ops arp_direct_ops = {
 .family =  AF_INET,
 .output =  neigh_direct_output,
 .connected_output = neigh_direct_output,
};

struct neigh_table arp_tbl = {
 .family  = AF_INET,
 .key_len = 4,
 .protocol = cpu_to_be16(ETH_P_IP),
 .hash  = arp_hash,
 .key_eq  = arp_key_eq,
 .constructor = arp_constructor,
 .proxy_redo = parp_redo,
 .id  = "arp_cache",
 .parms  = {
  .tbl   = &arp_tbl,
  .reachable_time  = 30 * HZ,
  .data = {
   [NEIGH_VAR_MCAST_PROBES] = 3,
   [NEIGH_VAR_UCAST_PROBES] = 3,
   [NEIGH_VAR_RETRANS_TIME] = 1 * HZ,
   [NEIGH_VAR_BASE_REACHABLE_TIME] = 30 * HZ,
   [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ,
   [NEIGH_VAR_GC_STALETIME] = 60 * HZ,
   [NEIGH_VAR_QUEUE_LEN_BYTES] = 64 * 1024,
   [NEIGH_VAR_PROXY_QLEN] = 64,
   [NEIGH_VAR_ANYCAST_DELAY] = 1 * HZ,
   [NEIGH_VAR_PROXY_DELAY] = (8 * HZ) / 10,
   [NEIGH_VAR_LOCKTIME] = 1 * HZ,
  },
 },
 .gc_interval = 30 * HZ,
 .gc_thresh1 = 128,
 .gc_thresh2 = 512,
 .gc_thresh3 = 1024,
};
EXPORT_SYMBOL(arp_tbl);

3.    事例说明:用ping说明ARP工作的原理

假设我们的计算机IP地址是192.168.1.1,要执行这个命令:ping192.168.1.2。该命令会通过ICMP协议发送ICMP(以太网控制报文协议)数据包

该过程需要经过下面的步骤:  

1> 应用程序构造数据包,该示例是产生ICMP包,被提交给内核(网络驱动程序);   

2> 内核检查是否能够转化该IP地址为MAC地址,也就是在本地的ARP缓存中查看IP-MAC对应表;

3> 如果存在该IP-MAC对应关系,那么跳到步骤<7;

如果不存在该IP-MAC对应关系,那么接续下面的步骤;

4> 内核进行ARP广播,目的MAC地址是FF-FF-FF-FF-FF-FF,ARP命令类型为REQUEST(1),其中包含有自己的MAC地址;   

5> 当192.168.1.2主机接收到该ARP请求后,就发送一个ARP的REPLY(2)命令,其中包含自己的MAC地址;   

6> 本地获得192.168.1.2主机的IP-MAC地址对应关系,并保存到ARP缓存中;   

7> 内核将把IP转化为MAC地址,然后封装在以太网头结构中,再把数据发送出去;  

4.    特殊情况:

ARP是解决同一个局域网上的主机或路由器的IP地址和硬件地址的映射问题。如果所要找的目标设备和源主机不在同一个局域网上。

1>此时主机A就无法解析出主机B的硬件地址(实际上主机A也不需要知道远程主机B的硬件地址);

2>此时主机A需要的是将路由器R1的IP地址解析出来,然后将该IP数据报发送给路由器R1.

3>R1从路由表中找出下一跳路由器R2,同时使用ARP解析出R2的硬件地址。于是IP数据报按照路由器R2的硬件地址转发到路由器R2。

4>路由器R2在转发这个IP数据报时用类似方法解析出目的主机B的硬件地址,使IP数据报最终交付给主机B.

说明:

Ø  如果你的数据包是发送到不同网段的目的地,那么就一定存在一条网关的IP-MAC地址对应的记录。   

Ø  知道了ARP协议的作用,就能够很清楚地知道,数据包的向外传输很依靠ARP协议,当然,也就是依赖ARP缓存。要知道,ARP协议的所有操作都是内核自动完成的,同其他的应用程序没有任何关系。同时需要注意的是,ARP协议只使用于本网络。

 

 

四.ARP缓冲表和TTL

1.  ARP缓冲表

1> ARP协议的本质是完成网络地址到物理地址的映射。从概念上将就是找到一个映射方法f,使得“物理地址 = f(网络地址)“。物理地址有两种基本类型:以太网类型和令牌环网类型。网络地址特指IP地址,对映射方法的要求就是高效。具体到以太网,它使用的是动态绑定转换的方法。一般是设置ARP高速缓存,通过学习,老化,更新,溢出算法处理ARP映射表来解决这些问题。

Ø 学习指ARP收到任何指向本结点IP地址的ARP/IP包,从中提取出地址对,当ARP缓冲表中无对应项时,由ARP接收部分添加;

Ø 老化指为每项设置寿命域,以便代谢掉陈旧的地址映射项;

Ø 更新指ARP提取到新的地址对时,用其更新缓存里已有的对应项;

Ø 溢出算法指当缓存慢时,采取何种方法替代旧有的地址对。

2> ARP缓存表由状态,寿命,IP地址,MAC地址4个字段组成。状态字段指示地址对是否有效;寿命字段用于老化操作,初始存入最大值,以后由OS时间函数调用,每秒减1,直至为0清除;IP地址和MAC地址字段保存网络地址和物理地址的映射。围绕ARP缓存表,完成了4种操作:学习,老化,更新,表满处理。

3> 当ARP被询问一个已只IP地址节点的MAC地址时,先在ARPcache 查看

l  若存在,就直接返回MAC地址,

l  若不存在,才发送ARP request向局域网查询。

4>   当主机A向B发送数据报时,很可能以后不久主机B还要向A发送数据报,因而主机B可能要向A发送ARP请求分组。

所以,为了减少网络上的通信量,主机A在发送其ARP请求分组时,就将自己的IP地址到硬件地址的写入主机B自己的ARP高速缓冲表中。这对主机B以后向A发送数据报时就更方便了。

Tiger 说明

任何事物都有两面性,如果掌握的好它就是天使,如果掌握的不好它就是Satan,ARP中的缓冲表为计算机之间的通信效率和减少网络通信量之间作出了巨大的贡献,但是它同时为我们上网时留下了安全隐患;例如交换机嗅探(在下面会有介绍)

2.  ARP中的TTL(即上面所说的寿命域)

ARP将保存在高速缓冲表中的每一个映射地址表项都设置了TTL(生存时间),只要TTL小于0的项目就从高速缓冲表中删除掉。

(ARP的超时值一般为20分钟,对不完整的表项设置为20分钟,而对不完整的表项设置为2分钟《不完整的表项:即在以太网上对一个不存在的主机发出ARP请求》,当这些表项再次使用时,这些实现一般都把超时值重新设为20分钟。)

好处:主机A和B通信。A的ARP高速缓冲表里保存有B的物理地址。但B的网卡突然坏了,B立即就更换了一块,因此B的硬件地址就改变了。A还要和B继续通信。A在其ARP缓冲表中查找到B原先的硬件地址,并使用该硬件地址向B发送数据帧。但B原先的硬件地址已经失效了。因此A无法找到主机B。但是过了一段时间,A的ARP高速缓冲表中已经删除了B原先的硬件地址(因为它的生存时间到了),于是A重新光播发送ARP请求分组,又找到了B。

五.ARP命令:

1.      使用arp-a命令就可以查看本地的ARP缓存内容,所以,执行一个本地的PING命令后,ARP缓存就会存在一个目的IP的记录了。

2.     使用arp –d来删除ARP高速缓存中的某一项内容

3.     使用arp –s来增加高速缓冲表中的内容,这个命令需要主机名和以太网地址。新增加的内容是永久性的,除非在命令行的末尾加上关键字temp。

arp –s 157.55.85.212  00-aa-aa-562-c6-09

增加一个静态的ARP表项。

4.     arppub –s:使系统起着主机ARP代理功能。系统将回答与主机名对应的IP地址的ARP请求。

 

六ARP其他方面

1.交换网络的嗅探

1>1.ARP协议并不只在发送了ARP请求才接收ARP应答

当计算机接收到ARP应答数据包的时候,就会对本地的ARP缓存进行更新,将应答中的IP和MAC地址存储在ARP缓存中。

因此,在上面的假设网络中,B向A发送一个自己伪造的ARP应答,而这个应答中的数据为发送方IP地址是192.168.10.3(C的IP地址),MAC地址是DD-DD-DD-DD-DD-DD(C的MAC地址本来应该是CC-CC-CC-CC-CC-CC,这里被伪造了)。当A接收到B伪造的ARP应答,就会更新本地的ARP缓存,将本地的IP-MAC对应表更换为接收到的数据格式,由于这一切都是A的系统内核自动完成的,A可不知道被伪造了。ARP欺骗的主要用途就是进行在交换网络中的嗅探。

2.IP地址冲突

1>如果网络中存在相同IP地址的主机时候,就会报告出IP地址冲突的警告。

2>如何产生?

Ø  比如某主机B规定IP地址为192.168.0.1,如果它处于开机状态,那么其他机器A更该IP地址为192.168.0.1就会造成IP地址冲突。

Ø  其原理是:主机A在连接网路(或更改IP地址)的时候就会向网络发送ARP包广播自己的IP地址,也就是free arp(免费ARP).如果网络中存在相同IP地址的主机B,那么B就会通过ARP来reply该地址,当A接收到这个reply后,A就会跳出IP地址冲突的警告,当然B也会有警告。因此用ARP欺骗可以来伪造这个ARPreply,从而使目标一直遭受IP地址冲突警告的困扰。

3.阻止目标的数据包通过网关

1>比如在一个局域网内通过网管上网,那么连接外部的计算机上的ARP缓存中就存在网管IP-MAC对应记录

2>如果,该记录被更改,那么该计算机向外发送的数据包总是发送到了错误的网关硬件地址上,这样,该计算机就不能上网了。

3>这里也主要是通过ARP欺骗进行的。有两种方法达到这样的目的:

Ø  向目标发送伪造的ARP应答数据包,其中发送方的IP地址为网管的地址,而MAC地址则为一个伪造的地址。当目标接收到ARP包,那么就更新自身的ARP缓存。如果该欺骗一直持续下去,那么目标的网管缓存一直是一个被伪造的错误记录。不过,如果使用arp –a,就知道问题所在了。

Ø  第二种方法是欺骗网管。向网管发送伪造的ARP应答数据包,其中发送方的IP地址为目标的IP地址,而MAC地址则为一个伪造的地址。这样,网管上的目标ARP记录就是一个错误的,网管发送给目标的数据报都是使用了错误的MAC地址。这种情况下,目标能够发送数据到网管,却不能接收到网管的任何数据。同时,目标自己查看arp –a却看不出任何问题来。

4.通过检测混杂模式节点

1>在混杂模式中,网卡进行包过滤不同于普通模式。本来在普通模式下,只有本地地址的数据包或者广播(多播等)才会被网卡提交给系统核心,否则的话,这些数据包就直接被网卡抛弃。现在,混合模式让所有经过的数据包都传递给系统核心,然后被sniffer等程序利用。   

2>通过特殊设计的ARP请求可以用来在一定程度上检测处于混杂模式的节点,比如对网络中的每个节点都发送MAC地址为FF-FF-FF-FF-FF-FE的ARP请求。对于网卡来说这不是一个广播地址(FF-FF-FF-FF-FF-FF),所以处于普通模式的节点就会直接抛弃该数据包,但是多数操作系统核心都认为这是一个广播地址,如果有一般的sniffer程序存在,并设置网卡为混杂模式,那么系统核心就会作出应答,这样就可以判断这些节点是否存在嗅探器了。

3>可以查看,很多基于ARP的攻击都是通过ARP欺骗实现的。至于ARP欺骗的防范,还是尽可能使用静态的ARP。对于WIN,使用arp-s来进行静态ARP的设置。

当然,如果能够完全使用静态的IP+MAC对应,就更好了,因为静态的ARP缓存只是相对的。当然,可以有一些方法来实现ARP欺骗的检测。设置一个ARP的嗅探器,其中维护着一个本地网络的IP-MAC地址的静态对应表,查看所有经过的ARP数据,并检查其中的IP-MAC对应关系,如果捕获的IP-MAC对应关系和维护的静态对应关系对应不上,那么就表明是一个欺骗的ARP数据包了。

0 0