路由訊息協定(RIP)是一種動態路由協定,它使用躍點數作為路由度量來搜尋源網路和目標網路之間的最佳路徑。而RIP協定封裝在UDP之上,連接埠為520,它是一種距離向量路由協定,具有AD值120,適用於OSI模型的應用層。
RIP協定有哪些版本
RIP是最古老的距離向量協定路由協定之一,於1980年代發明。它使用跳數(源和目標網路之間的路由器數量)作為度量標準,並且配置非常簡單。開發了兩種版本的協定,主要是RIPv1,RIPv2,RIPng
- RIPv1
RIPv1僅支援有類路由協定,並且在路由更新中不發送子網掩碼。使用廣播每30秒發送一次完整的更新。
- RIPv2
RIPv2 支援無類路由,並在路由更新中發送子網掩碼。
在RIP中的身份驗證中,路由訊息協定RIPv2的Cisco實現支援身份驗證,金鑰管理,路由匯總,無類域間路由(CIDR)和可變長度子網掩碼(VLSM)。
RIPv1不支援身份驗證。如果要發送和接收RIP v2資料包,則可以在介面上啟用RIP身份驗證。
RIP訊息格式
現在,我們看一下RIP訊息格式的結構。訊息格式用於在不同路由器之間共享訊息。RIP在訊息中包含以下欄位:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | command (1) | version (1) | must be zero (2) | +---------------+---------------+-------------------------------+ | address family identifier (2) | must be zero (2) | +-------------------------------+-------------------------------+ | IP address (4) | +---------------------------------------------------------------+ | must be zero (4) | +---------------------------------------------------------------+ | must be zero (4) | +---------------------------------------------------------------+ | metric (4) | +---------------------------------------------------------------+ |
command :這是一個8位欄位,用於請求或答覆。請求的值為1,回復的值為2。
version :這裡的版本表示我們正在使用的協定版本。假設我們使用的是版本1的協定,然後將1放在此欄位中。
must be zero :這是一個保留欄位,因此用零填充。
address family identifier:這是一個16位欄位。由於我們使用的是TCP / IP系列,因此我們在此欄位中輸入2值。
IP address:定義為14個位元組的欄位。如果使用IPv4版本,則使用4個位元組,其他10個位元組全為零。
metric :距離欄位指定跳數,即到達目的地的跳數。
如何確定跳數?
當路由器將資料包發送到網段時,將其計為單跳。
在上圖中,當路由器1將資料包轉發到路由器2時,它將計為1跳計數。同樣,當路由器2將資料包轉發到路由器3時,它將計為2跳數,而當路由器3將資料包轉發到路由器4時,它將計為3跳數。
同樣,RIP最多可以支援15個躍點,這意味著可以在RIP中配置16個路由器。
RIP如何工作?
如果網路中有8個路由器,路由器1希望將資料發送到路由器3。如果網路配置了RIP,它將選擇跳數最少的路由。
上面的網路中有3條路由,即路由1,路由2和路由3。路由2包含的跳數最少,即2,其中路由1包含3跳,路由3包含4跳,因此RIP將選擇路線2。
RIP協定解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | #include <sys/stat.h> #include <sys/types.h> #include <netinet/tcp.h> #include <netinet/udp.h> #include <netinet/ip.h> #include <netinet/ip6.h> #include <net/ethernet.h> #include <pcap.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define UDP_PORT_RIP 520 #define RIPv1 1 #define RIPv2 2 #define RIP_HEADER_LENGTH 4 #define RIP_ENTRY_LENGTH 20 #define MD5_AUTH_DATA_LEN 16 #define AFVAL_UNSPEC 0 #define AFVAL_IP 2 #define AUTH_IP_ROUTE 1 #define AUTH_PASSWORD 2 #define AUTH_KEYED_MSG_DIGEST 3 bool is_rip_version(uint8_t version) {<!-- --> if (version == RIPv1 || version == RIPv2) return true; return false; } static void dissect_rip_authentication(u_char *data_info ,int offset) {<!-- --> uint8_t auth_data_len = 0; char *pszInfoBuf = NULL; offset += 2;/*skip 0xFFFF*/ uint16_t authtype = ntohs(*(uint16_t*)(data_info + offset)); printf("authtype 0x%X ",authtype); switch(authtype) {<!-- --> case AUTH_PASSWORD: offset += 2; /*skip auth type*/ pszInfoBuf = (char*)malloc(1024); if (pszInfoBuf != 0) {<!-- --> memcpy(pszInfoBuf, data_info + offset,16); pszInfoBuf[16] = ' '; printf("Password = %s ",pszInfoBuf); } break; case AUTH_KEYED_MSG_DIGEST: offset += 2; /*authenication type*/ printf("Digest Offset %d ",ntohs(*(uint16_t*)(data_info + offset))); offset += 2; /*Digest Offset*/ offset += 1; /*skip authenication type、Digest Offset、Key ID*/ auth_data_len = *(uint8_t*)(data_info + offset); printf("Auth Data Len: %d ",auth_data_len); break; default: break; } //return auth_data_len; } static void dissect_ip_rip_vektor(u_char *data_info, int offset, uint8_t version) {<!-- --> uint32_t metric = 0; printf("Address Family %d ",ntohs(*(uint16_t*)(data_info + offset))); offset += 2; /*Address Family*/ if (version == RIPv2) {<!-- --> printf("Route Tag %d ",ntohs(*(uint16_t*)(data_info + offset))); } offset += 2; /*Route Tag*/ printf("IP Address %d.%d.%d.%d ",data_info[offset],data_info[offset +1],data_info[offset+2],data_info[offset+3]); offset += 4; /*IP Address*/ if (version == RIPv2) {<!-- --> printf("Netmask: %d.%d.%d.%d ",data_info[offset],data_info[offset +1],data_info[offset+2],data_info[offset+3]); offset += 4; /*Netmask*/ printf("Next Hop: %d.%d.%d.%d ",data_info[offset],data_info[offset +1],data_info[offset+2],data_info[offset+3]); offset += 4; /*Next Hop*/ printf("Metric: %d ",ntohl(*(uint32_t*)(data_info + offset))); } if (version == RIPv1) {<!-- --> offset += 8; printf("Metric: %d ",ntohl(*(uint32_t*)(data_info + offset))); } } static void dissect_unspec_rip_vektor(u_char *data_info, int offset, uint8_t version) {<!-- --> uint32_t metric = 0; printf("Address Family %d ",ntohs(*(uint16_t*)(data_info + offset))); offset += 2; /*Address Family*/ if (version == RIPv2) {<!-- --> printf("Route Tag %d ",ntohs(*(uint16_t*)(data_info + offset))); } offset += 2; /*Route Tag*/ if (version == RIPv2) {<!-- --> printf("Netmask: %d.%d.%d.%d ",data_info[offset],data_info[offset +1],data_info[offset+2],data_info[offset+3]); offset += 4; /*Netmask*/ printf("Next Hop: %d.%d.%d.%d ",data_info[offset],data_info[offset +1],data_info[offset+2],data_info[offset+3]); offset += 4; /*Next Hop*/ printf("Metric: %d ",ntohl(*(uint32_t*)(data_info + offset))); } if (version == RIPv1) {<!-- --> offset += 14; printf("Metric: %d ",ntohl(*(uint32_t*)(data_info + offset))); } } static void dissect_rip(u_char *data_info) {<!-- --> int offset = 0; uint8_t command = data_info[offset]; uint8_t version = data_info[offset + 1]; printf("version %d ",version); if ( !is_rip_version(version) ) return; /* skip header */ offset = RIP_HEADER_LENGTH; uint16_t family = ntohs(*(uint16_t*)(data_info + offset)); printf("family 0x%X ",family); switch(family) {<!-- --> case AFVAL_UNSPEC: /* Unspecified */ dissect_unspec_rip_vektor(data_info,offset,version); break; case AFVAL_IP: /* IP */ dissect_ip_rip_vektor(data_info,offset,version); break; case 0xFFFF: if (offset == RIP_HEADER_LENGTH) {<!-- --> dissect_rip_authentication(data_info,offset); } break; default: break; } offset += RIP_ENTRY_LENGTH; } static void confirm_rip_packet(struct ip *pIp) {<!-- --> int iIpTotalLen = ntohs(pIp->ip_len); int offset = 0; int nFragSeq = 0; struct udphdr* pUdpHdr = (struct udphdr*)((char*)pIp + (pIp->ip_hl<<2)); if (pIp->ip_p == IPPROTO_UDP && (ntohs(pUdpHdr->dest) == UDP_PORT_RIP) || (ntohs(pUdpHdr->source) == UDP_PORT_RIP) ) {<!-- --> printf(" "); printf("info udp "); int iPayloadLen = iIpTotalLen - (pIp->ip_hl<<2) - 8; //printf("UDP Payload Len %d ", iPayloadLen); u_char *pRipHdr = (u_char*)(pUdpHdr+1); dissect_rip(pRipHdr ); } } |
編譯執行
RIPv1
RIPv2
總結
路由訊息在RIP網路中透過RIP請求和RIP回應資料包進行交換。剛剛啟動的路由器可以在所有啟用RIP的介面上廣播RIP請求。
在那些鏈路上執行RIP的任何路由器都會收到請求並透過立即向路由器發送RIP回應資料包來做出回應。
在沒有RIP請求資料包的情況下,所有RIP路由器每30秒在所有啟用RIP的介面上廣播RIP回應資料包。RIP廣播是在整個網路中泛洪拓撲訊息的主要方式。
參考:http:/ /www.ietf.org/rfc/rfc2082.txt
歡迎關注微信公眾號【程式猿編碼】,歡迎新增本人微訊號(17865354792),歡迎進入技術交流群。我們一起學習進步!