透過原始碼理解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的早期實現。
原文來自:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2724352/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- ARP(地址解析協議)和RARP(逆地址解析協議)協議
- 透視RPC協議:SOFA-BOLT協議原始碼分析RPC協議原始碼
- 系列TCP/IP協議-ARP與RARPTCP協議
- Runtime原始碼 protocol(協議)原始碼Protocol協議
- ipad協議及原始碼iPad協議原始碼
- svn透過https協議訪問的搭建過程HTTP協議
- 理解http協議HTTP協議
- 透過wireshark簡單瞭解S7協議協議
- 透過Python指令碼理解系統程式Python指令碼
- https協議的理解HTTP協議
- Dubbo原始碼學習--Rmi協議(八)原始碼協議
- 一文帶你理解透MyBatis原始碼MyBatis原始碼
- 影片直播原始碼開發中的流媒體協議:rtmp協議原始碼協議
- Linux - openssh透過原始碼build rpm包Linux原始碼UI
- 域滲透之ldap協議LDA協議
- 深入理解 HTTP 協議HTTP協議
- 如何理解TCP/IP協議?TCP協議
- 深入理解OSPF協議協議
- 理解 OAuth2 協議OAuth協議
- CP341+CM1241透過ASCII(自由口)協議通訊ASCII協議
- C# wm6透過udp協議和pc通訊C#UDP協議
- NEO從原始碼分析看共識協議原始碼協議
- consul 原始碼解析(一)raft 協議實現原始碼Raft協議
- .NET 透過原始碼深究依賴注入原理原始碼依賴注入
- 滲透&&探測 (之DNS協議)DNS協議
- 一文講透Modbus協議協議
- 客戶端和伺服器透過http協議基於》》tcp協議,經過三次握手進行socket連線客戶端伺服器HTTP協議TCP
- dubbo原始碼解析(三十)遠端呼叫——rest協議原始碼REST協議
- Netty 原始碼中對 Redis 協議的實現Netty原始碼Redis協議
- 物聯網協議之MQTT原始碼分析(二)協議MQQT原始碼
- 物聯網協議之MQTT原始碼分析(一)協議MQQT原始碼
- HDFS原始碼解析系列一——HDFS通訊協議原始碼協議
- 死磕以太坊原始碼分析之rlpx協議原始碼協議
- 關於wsgi協議的理解協議
- 第22條:理解NSCopying協議協議
- 深入理解 tcp 協議(一)TCP協議
- 如何在本地區域網中透過SMB協議加密共享檔案協議加密
- Mac 透過 SMB 協議使用 Ubuntu 做時間機器備份盤Mac協議Ubuntu