自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

通過源碼理解Rarp協(xié)議(基于linux1.2.13)

網(wǎng)絡(luò) 通信技術(shù)
arp是通過mac地址查詢ip的協(xié)議,主要用于有mac的主機(jī),但是沒有ip的情況。

[[342609]]

本文轉(zhuǎn)載自微信公眾號(hào)「 編程雜技」,作者theanarkh 。轉(zhuǎn)載本文請(qǐng)聯(lián)系 編程雜技公眾號(hào)。

rarp是通過mac地址查詢ip的協(xié)議,主要用于有mac的主機(jī),但是沒有ip的情況。我們先看看rarp協(xié)議的協(xié)議定義(來自網(wǎng)上的圖[1])。

rarp協(xié)議的格式和arp協(xié)議是一樣的,他們都是通過一種地址查詢另外一種地址。操作系統(tǒng)內(nèi)維護(hù)了一個(gè)轉(zhuǎn)換表。定義如下。

  1. struct rarp_table 
  2.     struct rarp_table  *next;             /* Linked entry list           */ 
  3.     unsigned long      ip;                /* ip address of entry         */ 
  4.     unsigned char      ha[MAX_ADDR_LEN];  /* Hardware address            */ 
  5.     unsigned char      hlen;              /* Length of hardware address  */ 
  6.     unsigned char      htype;             /* Type of hardware in use     */ 
  7.     struct device      *dev;              /* Device the entry is tied to */ 
  8. }; 

初始化的時(shí)候是空的,這個(gè)表格的數(shù)據(jù)來源于,用戶通過操作系統(tǒng)提供的接口設(shè)置。我們看如何操作這個(gè)表。

  1. int rarp_ioctl(unsigned int cmd, void *arg) 
  2.     struct arpreq r; 
  3.     struct sockaddr_in *si; 
  4.     int err; 
  5.  
  6.     switch(cmd) 
  7.     { 
  8.         case SIOCDRARP: 
  9.             if (!suser()) 
  10.                 return -EPERM; 
  11.             err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq)); 
  12.             if(err) 
  13.                 return err; 
  14.             memcpy_fromfs(&r, arg, sizeof(r)); 
  15.             if (r.arp_pa.sa_family != AF_INET) 
  16.                 return -EPFNOSUPPORT; 
  17.             si = (struct sockaddr_in *) &r.arp_pa; 
  18.             rarp_destroy(si->sin_addr.s_addr); 
  19.             return 0; 
  20.  
  21.         case SIOCGRARP: 
  22.             err = verify_area(VERIFY_WRITE, arg, sizeof(struct arpreq)); 
  23.             if(err) 
  24.                 return err; 
  25.             return rarp_req_get((struct arpreq *)arg); 
  26.         case SIOCSRARP: 
  27.             if (!suser()) 
  28.                 return -EPERM; 
  29.             err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq)); 
  30.             if(err) 
  31.                 return err; 
  32.             return rarp_req_set((struct arpreq *)arg); 
  33.         default
  34.             return -EINVAL; 
  35.     } 
  36.  
  37.     /*NOTREACHED*/ 
  38.     return 0; 

通過ioctl函數(shù),我們可以對(duì)表格進(jìn)行增刪改查。我們只關(guān)注新增的邏輯。因?yàn)槠渌氖穷愃频?。下面是arpreq 的定義

  1. struct arpreq { 
  2.   struct sockaddr    arp_pa;        /* protocol address        */ 
  3.   struct sockaddr    arp_ha;        /* hardware address        */ 
  4.   int            arp_flags;    /* flags            */ 
  5.   struct sockaddr       arp_netmask;    /* netmask (only for proxy arps) */ 
  6. }; 
  1. static int rarp_req_set(struct arpreq *req) 
  2.     struct arpreq r; 
  3.     struct rarp_table *entry; 
  4.     struct sockaddr_in *si; 
  5.     int htype, hlen; 
  6.     unsigned long ip; 
  7.     struct rtable *rt; 
  8.  
  9.     memcpy_fromfs(&r, req, sizeof(r)); 
  10.  
  11.     /* 
  12.      *    We only understand about IP addresses...  
  13.      */ 
  14.  
  15.     if (r.arp_pa.sa_family != AF_INET) 
  16.         return -EPFNOSUPPORT; 
  17.  
  18.     switch (r.arp_ha.sa_family)  
  19.     { 
  20.         case ARPHRD_ETHER: 
  21.             htype = ARPHRD_ETHER; 
  22.             hlen = ETH_ALEN; 
  23.             break; 
  24.         default
  25.             return -EPFNOSUPPORT; 
  26.     } 
  27.  
  28.     si = (struct sockaddr_in *) &r.arp_pa; 
  29.     ip = si->sin_addr.s_addr; 
  30.     if (ip == 0) 
  31.     { 
  32.         printk("RARP: SETRARP: requested PA is 0.0.0.0 !\n"); 
  33.         return -EINVAL; 
  34.     } 
  35.     //  
  36.     rt = ip_rt_route(ip, NULLNULL); 
  37.     if (rt == NULL
  38.         return -ENETUNREACH; 
  39.  
  40. /* 
  41.  *    Is there an existing entry for this address?  Find out... 
  42.  */ 
  43.  
  44.     cli(); 
  45.     // 判斷之前是不是已經(jīng)存在 
  46.     for (entry = rarp_tables; entry != NULL; entry = entry->next
  47.         if (entry->ip == ip) 
  48.             break; 
  49.  
  50. /* 
  51.  *    If no entry was found, create a new one. 
  52.  */ 
  53.     // 不存在則創(chuàng)建一個(gè)表項(xiàng) 
  54.     if (entry == NULL
  55.     { 
  56.         entry = (struct rarp_table *) kmalloc(sizeof(struct rarp_table), 
  57.                     GFP_ATOMIC); 
  58.         // 還沒初始化則初始化 
  59.         if(initflag) 
  60.         { 
  61.             rarp_init(); 
  62.             initflag=0; 
  63.         } 
  64.  
  65.         entry->next = rarp_tables; 
  66.         rarp_tables = entry; 
  67.     } 
  68.  
  69.     entry->ip = ip; 
  70.     entry->hlen = hlen; 
  71.     entry->htype = htype; 
  72.     memcpy(&entry->ha, &r.arp_ha.sa_data, hlen); 
  73.     entry->dev = rt->rt_dev; 
  74.  
  75.     sti(); 
  76.  
  77.     return 0; 

我們看到這里會(huì)往表里插入一個(gè)表項(xiàng)(如果不存在的話),還有另外一個(gè)邏輯是rarp_init。

  1. static void rarp_init (void) 
  2.     /* Register the packet type */ 
  3.     rarp_packet_type.type=htons(ETH_P_RARP); 
  4.     dev_add_pack(&rarp_packet_type); 

這個(gè)函數(shù)是往底層注冊(cè)一個(gè)節(jié)點(diǎn),當(dāng)mac底層收到一個(gè)ETH_P_RARP類型的數(shù)據(jù)包的時(shí)候(在mac協(xié)議頭里定義),就會(huì)執(zhí)行rarp_packet_type中定義的函數(shù)。下面是該rarp_packet_type的定義

  1. static struct packet_type rarp_packet_type = 
  2.     0,  
  3.     0,                /* copy */ 
  4.     rarp_rcv, 
  5.     NULL
  6.     NULL 
  7. }; 

rarp_rcv函數(shù)就是收到一個(gè)rarp請(qǐng)求的時(shí)候(來自其他主機(jī)),執(zhí)行的函數(shù)。

  1. int rarp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) 
  2. /* 
  3.  *    We shouldn't use this type conversion. Check later. 
  4.  */ 
  5.     // rarp協(xié)議報(bào)文 
  6.     struct arphdr *rarp = (struct arphdr *)skb->h.raw; 
  7.     // rarp協(xié)議數(shù)據(jù)部分 
  8.     unsigned char *rarp_ptr = (unsigned char *)(rarp+1); 
  9.     struct rarp_table *entry; 
  10.     long sip,tip; 
  11.     unsigned char *sha,*tha;            /* s for "source", t for "target" */ 
  12.  
  13.     // 硬件地址長度或類型不一致則忽略 
  14.     if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd)  
  15.         || dev->flags&IFF_NOARP) 
  16.     { 
  17.         kfree_skb(skb, FREE_READ); 
  18.         return 0; 
  19.     } 
  20.  
  21.     /* 
  22.      *    If it's not a RARP request, delete it. 
  23.      */ 
  24.     // 不是請(qǐng)求報(bào)文則忽略 
  25.     if (rarp->ar_op != htons(ARPOP_RREQUEST)) 
  26.     { 
  27.         kfree_skb(skb, FREE_READ); 
  28.         return 0; 
  29.     } 
  30.     /* 
  31.      *    Extract variable width fields 
  32.      */ 
  33.     // rarp協(xié)議首地址 
  34.     sha=rarp_ptr; 
  35.     // 發(fā)送端mac地址長度 
  36.     rarp_ptr+=dev->addr_len; 
  37.     // 拿到發(fā)送端ip,存到sip 
  38.     memcpy(&sip,rarp_ptr,4); 
  39.     // 跳過4字節(jié) 
  40.     rarp_ptr+=4; 
  41.     // 目的mac地址 
  42.     tha=rarp_ptr; 
  43.     // 跳過mac地址長度 
  44.     rarp_ptr+=dev->addr_len; 
  45.     // 目的ip地址 
  46.     memcpy(&tip,rarp_ptr,4); 
  47.  
  48.     /* 
  49.      *    Process entry. Use tha for table lookup according to RFC903. 
  50.      */ 
  51.  
  52.     cli(); 
  53.     for (entry = rarp_tables; entry != NULL; entry = entry->next
  54.         // 判斷mac地址是否相等 
  55.         if (!memcmp(entry->ha, tha, rarp->ar_hln)) 
  56.             break; 
  57.     // 非空則說明找到 
  58.     if (entry != NULL
  59.     {    // 拿到對(duì)應(yīng)的ip 
  60.         sip=entry->ip; 
  61.         sti(); 
  62.         // 回復(fù),類似是響應(yīng)ARPOP_RREPLY 
  63.         arp_send(ARPOP_RREPLY, ETH_P_RARP, sip, dev, dev->pa_addr, sha,  
  64.             dev->dev_addr); 
  65.     } 
  66.     else 
  67.         sti(); 
  68.  
  69.     kfree_skb(skb, FREE_READ); 
  70.     return 0; 

我們看到這個(gè)函數(shù)很長,不過邏輯比較簡單,就是解析收到的rarp請(qǐng)求中的數(shù)據(jù),然后根據(jù)其他主機(jī)請(qǐng)求的mac地址,從維護(hù)的表格中找到對(duì)應(yīng)的ip(如果有的話),然后調(diào)用arp_send函數(shù)發(fā)送回包。下面列一下該函數(shù)的代碼。

  1. void arp_send(int type, int ptype, unsigned long dest_ip,  
  2.           struct device *dev, unsigned long src_ip,  
  3.           unsigned char *dest_hw, unsigned char *src_hw) 
  4.     struct sk_buff *skb; 
  5.     struct arphdr *arp; 
  6.     unsigned char *arp_ptr; 
  7.  
  8.     /* 
  9.      *    No arp on this interface. 
  10.      */ 
  11.  
  12.     if(dev->flags&IFF_NOARP) 
  13.         return
  14.  
  15.     /* 
  16.      *    Allocate a buffer 
  17.      */ 
  18.     // 分配一個(gè)skb存儲(chǔ)數(shù)據(jù)包 
  19.     skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4) 
  20.                 + dev->hard_header_len, GFP_ATOMIC); 
  21.     // 構(gòu)造arp協(xié)議數(shù)據(jù)包 
  22.     skb->len = sizeof(struct arphdr) + dev->hard_header_len + 2*(dev->addr_len+4); 
  23.     skb->arp = 1; 
  24.     skb->dev = dev; 
  25.     // 不存在緩存,發(fā)完可以銷毀 
  26.     skb->free = 1; 
  27.     // 構(gòu)造mac頭 
  28.     dev->hard_header(skb->data,dev,ptype,dest_hw?dest_hw:dev->broadcast,src_hw?src_hw:NULL,skb->len,skb); 
  29.  
  30.     /* Fill out the arp protocol part. */ 
  31.     arp = (struct arphdr *) (skb->data + dev->hard_header_len); 
  32.     arp->ar_hrd = htons(dev->type); 
  33.     arp->ar_pro = htons(ETH_P_IP); 
  34.     arp->ar_hln = dev->addr_len; 
  35.     arp->ar_pln = 4; 
  36.     arp->ar_op = htons(type); 
  37.     arp_ptr=(unsigned char *)(arp+1); 
  38.     memcpy(arp_ptr, src_hw, dev->addr_len); 
  39.     arp_ptr+=dev->addr_len; 
  40.     memcpy(arp_ptr, &src_ip,4); 
  41.     arp_ptr+=4; 
  42.     if (dest_hw != NULL
  43.         memcpy(arp_ptr, dest_hw, dev->addr_len); 
  44.     else 
  45.         memset(arp_ptr, 0, dev->addr_len); 
  46.     arp_ptr+=dev->addr_len; 
  47.     memcpy(arp_ptr, &dest_ip, 4); 
  48.     // 調(diào)用mac頭發(fā)送函數(shù)發(fā)送出去 
  49.     dev_queue_xmit(skb, dev, 0); 

這就是rarp的早期實(shí)現(xiàn)。

References

[1] 網(wǎng)上的圖: https://wenku.baidu.com/view/8fbb89a7f524ccbff12184a0.html#

 

 

責(zé)任編輯:武曉燕 來源: 編程雜技
相關(guān)推薦

2014-06-11 13:25:14

IPARPRARP

2013-07-01 15:06:04

2010-06-13 14:36:20

RARP協(xié)議

2011-07-19 11:35:09

linux網(wǎng)絡(luò)協(xié)議

2023-07-04 09:39:45

Modbus鴻蒙

2016-12-19 15:09:02

Jedis源碼

2021-05-28 05:30:55

HandleV8代碼

2015-07-27 14:57:32

OpenFlow協(xié)議Ryu

2024-04-24 11:05:03

MapReduce編程大數(shù)據(jù)

2023-03-04 13:43:31

云終端傳輸協(xié)議

2010-07-09 10:13:42

UDP協(xié)議

2019-08-23 12:49:18

USB通信協(xié)議

2020-06-17 21:39:11

HTTP協(xié)議服務(wù)器

2022-11-02 21:45:54

SPIJava

2016-10-26 20:49:24

ReactJavascript前端

2020-11-04 00:00:29

Kerberos協(xié)議身份

2011-04-18 19:36:10

HSRP協(xié)議

2017-09-21 10:00:07

緩存web服務(wù)器

2023-12-25 08:04:42

2010-07-08 13:19:34

UDP協(xié)議
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)