以源码的方式讲解一下Rarp协议

rarp是通过mac地址查询ip的协议,主要用于有mac的主机,但是没有ip的情况。

rarp协议的格式和arp协议是一样的,他们都是通过一种地址查询另外一种地址。操作系统内维护了一个转换表。定义如下。

struct rarp_table
{
   struct rarp_table  *next;             /* Linked entry list           */
   unsigned long      ip;                /* ip address of entry         */
   unsigned char      ha[MAX_ADDR_LEN];  /* Hardware address            */
   unsigned char      hlen;              /* Length of hardware address  */
   unsigned char      htype;             /* Type of hardware in use     */
   struct device      *dev;              /* Device the entry is tied to */
};

初始化的时候是空的,这个表格的数据来源于,用户通过操作系统提供的接口设置。我们看如何操作这个表。

int rarp_ioctl(unsigned int cmd, void *arg)
{
   struct arpreq r;
   struct sockaddr_in *si;
   int err;

   switch(cmd)
   {
       case SIOCDRARP:
           if (!suser())
               return -EPERM;
           err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq));
           if(err)
               return err;
           memcpy_fromfs(&r, arg, sizeof(r));
           if (r.arp_pa.sa_family != AF_INET)
               return -EPFNOSUPPORT;
           si = (struct sockaddr_in *) &r.arp_pa;
           rarp_destroy(si->sin_addr.s_addr);
           return 0;

       case SIOCGRARP:
           err = verify_area(VERIFY_WRITE, arg, sizeof(struct arpreq));
           if(err)
               return err;
           return rarp_req_get((struct arpreq *)arg);
       case SIOCSRARP:
           if (!suser())
               return -EPERM;
           err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq));
           if(err)
               return err;
           return rarp_req_set((struct arpreq *)arg);
       default:
           return -EINVAL;
   }

   /*NOTREACHED*/
   return 0;
}

通过ioctl函数,我们可以对表格进行增删改查。我们只关注新增的逻辑。因为其他的是类似的。下面是arpreq 的定义

struct arpreq {
 struct sockaddr    arp_pa;        /* protocol address        */
 struct sockaddr    arp_ha;        /* hardware address        */
 int            arp_flags;    /* flags            */
 struct sockaddr       arp_netmask;    /* netmask (only for proxy arps) */
};
static int rarp_req_set(struct arpreq *req)
{
   struct arpreq r;
   struct rarp_table *entry;
   struct sockaddr_in *si;
   int htype, hlen;
   unsigned long ip;
   struct rtable *rt;

   memcpy_fromfs(&r, req, sizeof(r));

   /*
    *    We only understand about IP addresses...  
    */

   if (r.arp_pa.sa_family != AF_INET)
       return -EPFNOSUPPORT;

   switch (r.arp_ha.sa_family)  
   {
       case ARPHRD_ETHER:
           htype = ARPHRD_ETHER;
           hlen = ETH_ALEN;
           break;
       default:
           return -EPFNOSUPPORT;
   }

   si = (struct sockaddr_in *) &r.arp_pa;
   ip = si->sin_addr.s_addr;
   if (ip == 0)
   {
       printk("RARP: SETRARP: requested PA is 0.0.0.0 !\n");
       return -EINVAL;
   }
   //  
   rt = ip_rt_route(ip, NULL, NULL);
   if (rt == NULL)
       return -ENETUNREACH;

/*
*    Is there an existing entry for this address?  Find out...
*/

   cli();
   // 判断之前是不是已经存在
   for (entry = rarp_tables; entry != NULL; entry = entry->next)
       if (entry->ip == ip)
           break;

/*
*    If no entry was found, create a new one.
*/
   // 不存在则创建一个表项
   if (entry == NULL)
   {
       entry = (struct rarp_table *) kmalloc(sizeof(struct rarp_table),
                   GFP_ATOMIC);
       // 还没初始化则初始化
       if(initflag)
       {
           rarp_init();
           initflag=0;
       }

       entry->next = rarp_tables;
       rarp_tables = entry;
   }

   entry->ip = ip;
   entry->hlen = hlen;
   entry->htype = htype;
   memcpy(&entry->ha, &r.arp_ha.sa_data, hlen);
   entry->dev = rt->rt_dev;

   sti();

   return 0;
}

我们看到这里会往表里插入一个表项(如果不存在的话),还有另外一个逻辑是rarp_init。

static void rarp_init (void)
{
   /* Register the packet type */
   rarp_packet_type.type=htons(ETH_P_RARP);
   dev_add_pack(&rarp_packet_type);
}

这个函数是往底层注册一个节点,当mac底层收到一个ETH_P_RARP类型的数据包的时候(在mac协议头里定义),就会执行rarp_packet_type中定义的函数。下面是该rarp_packet_type的定义

static struct packet_type rarp_packet_type =
{
   0,  
   0,                /* copy */
   rarp_rcv,
   NULL,
   NULL
};

rarp_rcv函数就是收到一个rarp请求的时候(来自其他主机),执行的函数。

int rarp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{
/*
*    We shouldn't use this type conversion. Check later. */    // rarp协议报文    struct arphdr *rarp = (struct arphdr *)skb->h.raw;    // rarp协议数据部分    unsigned char *rarp_ptr = (unsigned char *)(rarp+1);    struct rarp_table *entry;    long sip,tip;    unsigned char *sha,*tha;            /* s for "source", t for "target" */    // 硬件地址长度或类型不一致则忽略    if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd)          || dev->flags&IFF_NOARP)    {        kfree_skb(skb, FREE_READ);        return 0;    }    /*     *    If it's not a RARP request, delete it.
    */
   // 不是请求报文则忽略
   if (rarp->ar_op != htons(ARPOP_RREQUEST))
   {
       kfree_skb(skb, FREE_READ);
       return 0;
   }
   /*
    *    Extract variable width fields
    */
   // rarp协议首地址
   sha=rarp_ptr;
   // 发送端mac地址长度
   rarp_ptr+=dev->addr_len;
   // 拿到发送端ip,存到sip
   memcpy(&sip,rarp_ptr,4);
   // 跳过4字节
   rarp_ptr+=4;
   // 目的mac地址
   tha=rarp_ptr;
   // 跳过mac地址长度
   rarp_ptr+=dev->addr_len;
   // 目的ip地址
   memcpy(&tip,rarp_ptr,4);

   /*
    *    Process entry. Use tha for table lookup according to RFC903.
    */

   cli();
   for (entry = rarp_tables; entry != NULL; entry = entry->next)
       // 判断mac地址是否相等
       if (!memcmp(entry->ha, tha, rarp->ar_hln))
           break;
   // 非空则说明找到
   if (entry != NULL)
   {    // 拿到对应的ip
       sip=entry->ip;
       sti();
       // 回复,类似是响应ARPOP_RREPLY
       arp_send(ARPOP_RREPLY, ETH_P_RARP, sip, dev, dev->pa_addr, sha,  
           dev->dev_addr);
   }
   else
       sti();

   kfree_skb(skb, FREE_READ);
   return 0;
}

我们看到这个函数很长,不过逻辑比较简单,就是解析收到的rarp请求中的数据,然后根据其他主机请求的mac地址,从维护的表格中找到对应的ip(如果有的话),然后调用arp_send函数发送回包。下面列一下该函数的代码。

void arp_send(int type, int ptype, unsigned long dest_ip,  
         struct device *dev, unsigned long src_ip,  
         unsigned char *dest_hw, unsigned char *src_hw)
{
   struct sk_buff *skb;
   struct arphdr *arp;
   unsigned char *arp_ptr;

   /*
    *    No arp on this interface.
    */

   if(dev->flags&IFF_NOARP)
       return;

   /*
    *    Allocate a buffer
    */
   // 分配一个skb存储数据包
   skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4)
               + dev->hard_header_len, GFP_ATOMIC);
   // 构造arp协议数据包
   skb->len = sizeof(struct arphdr) + dev->hard_header_len + 2*(dev->addr_len+4);
   skb->arp = 1;
   skb->dev = dev;
   // 不存在缓存,发完可以销毁
   skb->free = 1;
   // 构造mac头
   dev->hard_header(skb->data,dev,ptype,dest_hw?dest_hw:dev->broadcast,src_hw?src_hw:NULL,skb->len,skb);

   /* Fill out the arp protocol part. */
   arp = (struct arphdr *) (skb->data + dev->hard_header_len);
   arp->ar_hrd = htons(dev->type);
   arp->ar_pro = htons(ETH_P_IP);
   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;
   if (dest_hw != NULL)
       memcpy(arp_ptr, dest_hw, dev->addr_len);
   else
       memset(arp_ptr, 0, dev->addr_len);
   arp_ptr+=dev->addr_len;
   memcpy(arp_ptr, &dest_ip, 4);
   // 调用mac头发送函数发送出去
   dev_queue_xmit(skb, dev, 0);
}

这就是rarp的早期实现。

文章来源网络,作者:运维,如若转载,请注明出处:https://shuyeidc.com/wp/223486.html<

(0)
运维的头像运维
上一篇2025-04-15 23:54
下一篇 2025-04-15 23:56

相关推荐

  • 个人主题怎么制作?

    制作个人主题是一个将个人风格、兴趣或专业领域转化为视觉化或结构化内容的过程,无论是用于个人博客、作品集、社交媒体账号还是品牌形象,核心都是围绕“个人特色”展开,以下从定位、内容规划、视觉设计、技术实现四个维度,详细拆解制作个人主题的完整流程,明确主题定位:找到个人特色的核心主题定位是所有工作的起点,需要先回答……

    2025-11-20
    0
  • 社群营销管理关键是什么?

    社群营销的核心在于通过建立有温度、有价值、有归属感的社群,实现用户留存、转化和品牌传播,其管理需贯穿“目标定位-内容运营-用户互动-数据驱动-风险控制”全流程,以下从五个维度展开详细说明:明确社群定位与目标社群管理的首要任务是精准定位,需明确社群的核心价值(如行业交流、产品使用指导、兴趣分享等)、目标用户画像……

    2025-11-20
    0
  • 香港公司网站备案需要什么材料?

    香港公司进行网站备案是一个涉及多部门协调、流程相对严谨的过程,尤其需兼顾中国内地与香港两地的监管要求,由于香港公司注册地与中国内地不同,其网站若主要服务内地用户或使用内地服务器,需根据服务器位置、网站内容性质等,选择对应的备案路径(如工信部ICP备案或公安备案),以下从备案主体资格、流程步骤、材料准备、注意事项……

    2025-11-20
    0
  • 如何企业上云推广

    企业上云已成为数字化转型的核心战略,但推广过程中需结合行业特性、企业痛点与市场需求,构建系统性、多维度的推广体系,以下从市场定位、策略设计、执行落地及效果优化四个维度,详细拆解企业上云推广的实践路径,精准定位:明确目标企业与核心价值企业上云并非“一刀切”的方案,需先锁定目标客户群体,提炼差异化价值主张,客户分层……

    2025-11-20
    0
  • PS设计搜索框的实用技巧有哪些?

    在PS中设计一个美观且功能性的搜索框需要结合创意构思、视觉设计和用户体验考量,以下从设计思路、制作步骤、细节优化及交互预览等方面详细说明,帮助打造符合需求的搜索框,设计前的规划明确使用场景:根据网站或APP的整体风格确定搜索框的调性,例如极简风适合细线条和纯色,科技感适合渐变和发光效果,电商类则可能需要突出搜索……

    2025-11-20
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注