天天看點

LinuxC下擷取UDP包中的路由目的IP位址和頭辨別目的位址

在接受到UDP包後,有時候我們需要根據所接收到得UDP包,擷取它的路由目的IP位址和頭辨別目的位址。

在setsockopt中設定IP_PKTINFO,然後通過recvmsg來擷取struct in_pktinfo(struct in_pktinfo是struct msghdr中msg_control的成員).in_pktinfo 結構體(如下所示),我們可以從in_pktinfo中擷取路由目的位址(destination address of the packet)、頭辨別目的位址(source address of the packet)。這種方法隻能用于UDP(資料報)傳輸中。

ipi_ifindex指的是接收包的接口的唯一索引,ipi_spec_dst指的是路由表記錄中的目的位址,而ipi_addr 指的是標頭中的目的位址。如果給setsockopt傳遞了IP_PKTINFO,那麼外發的包會通過在ipi_ifindex中指定的接口發送出去,同時把ipi_spec_dst設定為目的位址。

LinuxC下擷取UDP包中的路由目的IP位址和頭辨別目的位址
LinuxC下擷取UDP包中的路由目的IP位址和頭辨別目的位址
LinuxC下擷取UDP包中的路由目的IP位址和頭辨別目的位址
LinuxC下擷取UDP包中的路由目的IP位址和頭辨別目的位址

1、開啟虛拟機下面的例子程式

2、通過windows下面的網絡調試助手向虛拟機發送資料

LinuxC下擷取UDP包中的路由目的IP位址和頭辨別目的位址
LinuxC下擷取UDP包中的路由目的IP位址和頭辨別目的位址

因為通過虛拟網卡的,是以我們看到目标IP位址并不是網絡調試助手中設定的IP,而是虛拟網卡的位址,通過Linux下的tcpdump我們可以看到其中網卡轉發的過程。

LinuxC下擷取UDP包中的路由目的IP位址和頭辨別目的位址

1、struct in_addr

in_addr_t 一般為 32位的unsigned long,其位元組順序為網絡順序(network byte ordered),即該無符号整數采用大端位元組序

2、struct msghdr

LinuxC下擷取UDP包中的路由目的IP位址和頭辨別目的位址
LinuxC下擷取UDP包中的路由目的IP位址和頭辨別目的位址

struct msghdr看上去似乎是一個需要建立的巨大的結構。但是不要怕。其結構成員可分為四組:

套接口位址成員: msg_name與msg_namelen。  I/O向量引用:msg_iov與msg_iovlen。  附屬資料緩沖區成員:msg_control與msg_controllen。  接收資訊标記位:msg_flags。

在我們将這個結構分為上面的幾類以後,結構看起來就不那樣巨大了。

标記位

描述 

MSG_EOR

 當接收到記錄結尾時會設定這一位。這通常對于SOCK_SEQPACKET套接口類型十分有用。

MSG_TRUNC

這個标記位表明資料的結尾被截短,因為接收緩沖區太小不足以接收全部的資料。

MSG_CTRUNC

這個标記位表明某些控制資料(附屬資料)被截短,因為緩沖區太小。

MSG_OOB

這個标記位表明接收了帶外資料。

MSG_ERRQUEUE

個标記位表明沒有接收到資料,但是傳回一個擴充錯誤。

3、struct cmsghdr結構

recvmsg與sendmsg函數允許程式發送或是接收附屬資料。然而,這些額外的資訊受限于一定的格式規則。下面将會介紹控制資訊頭與程式将會用來管理這些資訊的宏。

屬資訊可以包括0,1,或是更多的單獨附屬資料對象。在每一個對象之前都有一個struct cmsghdr結構。頭部之後是填充位元組,然後是對象本身。最後,附屬資料對象之後,下一個cmsghdr之前也許要有更多的填充位元組。在這裡,我們将要關注的附屬資料對象是檔案描述符與證書結構。 

圖1顯示了一個包含附屬資料的緩沖區是如何組織的。

LinuxC下擷取UDP包中的路由目的IP位址和頭辨別目的位址

                                                  圖1  輔助資料結構是由各種子結構、資料區, 填充位元組構成 

我們需要注意以下幾點: 

cmsg_len與CMSG_LEN()宏值所顯示的長度相同。 

CMSG_SPACE()宏可以計算一個附屬資料對象的所必需的空白。 

msg_controllen是CMSG_SPACE()長度之後,并且為每一個附屬資料對象進行計算。

其成員描述如下:

成員

描述

cmsg_len

附屬資料的位元組計數,這包含結構頭的尺寸。這個值是由CMSG_LEN()宏計算的。

cmsg_level

這個值表明了原始的協定級别(例如,SOL_SOCKET)。

cmsg_type

這個值表明了控制資訊類型(例如,SCM_RIGHTS)。

cmsg_data

這個成員并不實際存在。他用來指明實際的額外附屬資料所在的位置。

這一章所用的例子程式隻使用SOL_SOCKET的cmsg_level值。這一章我們感興趣的控制資訊類型如下(cmsg_level=SOL_SOCKET):

SCM_RIGHTS

附屬資料對象是一個檔案描述符

SCM_CREDENTIALS

附屬資料對象是一個包含證書資訊的結構

LinuxC下擷取UDP包中的路由目的IP位址和頭辨別目的位址
LinuxC下擷取UDP包中的路由目的IP位址和頭辨別目的位址

參考連結

<a href="http://hi.baidu.com/linux_kernel/item/c1f91d3fb0ffd5352e20c494">套接字選項(四)</a>

<a href="http://blog.chinaunix.net/uid-20583479-id-1919933.html">inet_pton &amp; inet_ntop函數</a>

<a href="http://blog.csdn.net/wsllq334/article/details/6977039">關于struct msghdr和struct cmsghdr</a>

<a href="http://alas.matf.bg.ac.rs/manuals/lspe/mode=1.html">Linux Socket Programming by Example - Warren Gay</a>

<a href="http://blog.csdn.net/mylxiaoyi/article/category/304912">Linux Socket學習</a>

本文轉自陳哈哈部落格園部落格,原文連結<b>http://www.cnblogs.com/kissazi2/p/3158603.html如需轉載請自行聯系原作者</b>

<b></b>

<b>kissazi2</b>

繼續閱讀