NAME

分組(也譯為資料包),PF_PACKET - 在裝置層的分組介面 譯註:PF_PACKET 中的 PF 是 protocol family(協議族)的縮寫。
 

SYNOPSIS 總覽

#include <sys/socket.h>
 
#include <features.h> /* 需要裡面的 glibc 版本號 */
 
#if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1
 
#include <netpacket/packet.h>
 
#include <net/ethernet.h> /* 鏈路層(L2)協議 */
 
#else
 
#include <asm/types.h>
 
#include <linux/if_packet.h>
 
#include <linux/if_ether.h> /* 鏈路層協議 */
 
#endif
 
packet_socket=socket(PF_PACKET,intsocket_type,intprotocol);

DESCRIPTION 描述

分組套介面(也譯為插口或套接字)被用於在裝置層(OSI 的鏈路層) 收發原始(raw )分組。它允許使用者在使用者空間實現在物理層之上的 協議模組。
 
 
對於包含鏈路層報頭的原始分組,socket_type 引數是 SOCK_RAW; 對於去除了鏈路層報頭的加工過的分組,socket_type 引數是 SOCK_DGRAM。鏈路層報頭資訊可在作為一般格式的 sockaddr_ll 中 的中得到。socket 的 protocol 引數指的是 IEEE 802.3 的按網路 層排序的協議號,在標頭檔案中有所有被允許的 協議的列表。當 protocol 被設定為 htons(ETH_P_ALL)時,可以接 收所有的協議。到來的此種類型的分組在傳送到在核心實現的協議 之前要先傳送給分組套介面。
 
譯註:DGRAM 是資料報的意思,htons 函式名是 hosts to networks of a short (16位整數的從主機到網路的位元組序變換)的縮寫。
 
只有有效 uid 是 0 或有 CAP_NET_RAW 能力的程序可以開啟分組 套介面。
 
 
傳送到裝置和從裝置傳送來的 SOCK_RAW 分組不改變任何分組資料。 當收到一個 SOCK_RAW 分組時, 地址仍被分析並傳送到一個標準的 sockaddr_ll 地址結構中。當傳送一個 SOCK_RAW 分組時, 使用者供 給的緩衝區應該包含物理層報頭。接著此分組不加修改的放入目的 地址定義的介面的網路驅動程式的佇列中。一些裝置驅動程式總是 增加其他報頭。SOCK_RAW 分組與已被廢棄的 Linux 2.0 的 SOCK_PACKET 分組類似但不相容。
 
對 SOCK_DGRAM 分組的操作要稍微高一層次。在分組被傳送到使用者 之前物理報頭已被去除。從 SOCK_DGRAM分組套介面送出的分組在被 放入網路驅動程式的佇列之前,基於在 sockaddr_ll 中的目的地址 得到一個適合的物理層報頭。
 
預設的所有特定協議型別的分組被髮送到分組套介面。為了只從特 定的介面得到分組,使用bind(2)來指定一個在 sockaddr_ll 結構 中的地址,以此把一個分組套介面繫結到一個介面上。只有地址字 段 sll_protocol 和 sll_ifindex 被繫結用途所使用。
 
不支援在分組套介面上的 connect(2) 操作。(不能作為客戶端使用)
 

ADDRESS TYPES 地址型別

sockaddr_ll 是裝置無關的物理層地址。
 
struct sockaddr_ll
{
unsigned short sll_family; /* 總是 AF_PACKET */
unsigned short sll_protocol; /* 物理層的協議 */
int sll_ifindex; /* 介面號 */
unsigned short sll_hatype; /* 報頭型別 */
unsigned char sll_pkttype; /* 分組型別 */
unsigned char sll_halen; /* 地址長度 */
unsigned char sll_addr[8]; /* 物理層地址 */
};
 
sll_protocol 是在 linux/if_ether.h 標頭檔案中定義的按網路層排 序的標準的以太楨協議型別。sll_ifindex 是介面的索引號(參見 netdevice(2));0 匹配所有的介面(當然只有合法的才用於繫結)。 sll_hatype 是在 linux/if_arp.h 中定義的 ARP 硬體地址型別。 sll_pkttype 包含分組型別。有效的分組型別是:目標地址是本地 主機的分組用的 PACKET_HOST,物理層廣播分組用的 PACKET_BROADCAST ,傳送到一個物理層多路廣播地址的分組用的 PACKET_MULTICAST, 在混雜(promiscuous)模式下的裝置驅動器發向其他主機的分組用的 PACKET_OTHERHOST,本源於本地主機的分組被環回到分組套介面用 的 PACKET_OUTGOING。這些型別只對接收到的分組有意義。sll_addr 和 sll_halen 包括物理層(例如 IEEE 802.3)地址和地址長度。精確 的解釋依賴於裝置。
 
譯註: (1) 對於乙太網(ethernet) OSI 模型不完全適用,以太楨定義包 括物理層和鏈路層的基本內容, 所謂的以太楨協議型別標識的是網路 層的協議。IEEE 802 委員會為與 OSI 相一致,把以太楨定義稱為 MAC(medium access control)層,在 MAC 層與網路層之間加入 LLC (logical link control)層,補充上了 OSI 標準的鏈路層。但在BSD TCP/IP 中是為了相容官方標準才被實現的。對於 TCP/IP 協議族 OSI 模型也不完全適用,TCP/IP 沒定義鏈路層,只能用 UNIX 的設 備驅動程式去對應鏈路層。無論如何這是既成事實,在本手冊頁中物 理層、鏈路層、裝置層指的都是乙太網的 MAC 層。餘以為不必嚴格 按層次劃分去理解問題,現在這個協議棧是優勝劣汰的結果,不是委 員會討論出來的。 (2) 乙太網地址分為三類,物理地址(最高位為0),多路廣播地址 (最高位為1),廣播地址(全是1)。以 DP8390 為例,它的接收配置 暫存器的 D2 位用來指定 NIC 是否接受廣播楨,D3 位用來指定 NIC 是否對多路廣播楨進行過濾,D4 位用來指定 NIC是否接受所有的物 理地址楨。混雜(Promiscuous)模式就是接收所有物理地址楨。
 

SOCKET OPTIONS 套介面選項

分組套介面可被用來配置物理層的多路廣播和混雜模式。配置透過呼叫 setsockopt(2)實現,套介面引數是一個分組套介面、層次引數為 SOL_PACKET 、選項引數中的 PACKET_ADD_MEMBERSHIP 用於增加一 個繫結,選項引數中的 PACKET_DROP_MEMBERSHIP 用於刪除一個綁 定。兩個選項都需要作為引數的 packet_mreq 結構:
 
struct packet_mreq
{
int mr_ifindex; /* 介面索引號 */
unsigned short mr_type; /* 動作 */
unsigned short mr_alen; /* 地址長度 */
unsigned char mr_address[8]; /* 物理層地址 */
};
 
mr_ifindex 包括介面的介面索引號,mr_ifindex 的狀態是可以改 變的。mr_type 引數指定完成那個動作。PACKET_MR_PROMISC 允許 接收在共享介質上的所有分組,這種接受狀態常被稱為混雜模式; PACKET_MR_MULTICAST 把套介面繫結到由mr_address 和 mr_alen 指定的物理層多路廣播組上;PACKET_MR_ALLMULTI 設定套介面接 收所有的來到介面的多路廣播分組。
 
 
除此之外傳統的 ioctls 如 SIOCSIFFLAGS, SIOCADDMULTI, SIOCDELMULTI 也能用於實現同樣的目的。
 

IOCTLS 輸入輸出控制

SIOCGSTAMP 用來接收最新收到的分組的時間戳。它的引數是 timeval 結構。
 
除此之外,所有的在 netdevice(7)socket(7) 中定義的標準 的 ioctl 在分組套介面上均有效。
 

ERROR HANDLING 錯誤處理

分組套接只對傳送分組到裝置驅動程式時發生的錯誤做錯誤處理, 其他不做錯誤處理。這裡沒有等待解決的錯誤的概念。
 

COMPATIBILITY 相容性

在 Linux 2.0 中,得到分組套介面的唯一方法是呼叫 socket(PF_INET, SOCK_PACKET, protocol)。它仍被支援但變得 沒有價值。兩種方法的主要不同在於 SOCK_PACKET 使用老的 sockaddr_pkt 結構來指定一個介面,沒有提供物理層介面無關性。 (依賴於物理裝置)
 
struct sockaddr_pkt
{
unsigned short spkt_family;
unsigned char spkt_device[14];
unsigned short spkt_protocol;
};
 
 
spkt_family 包括裝置型別,spkt_protocol 是在 中定義的 IEEE 802.3 協議型別,spkt_device 是表示裝置名的 null 終結的字串,例如 eth0。
 
譯註: "who is nntp" 就是一個以 null (' ')終結的字串。
 
 
這個結構已經被廢棄,不應在新的程式碼中使用。
 
 

NOTES 注意

不建議對要求可移植的程式透過 pcap(3) 使用 PF_PACKET 協議族; 它只覆蓋了 PF_PACKET 特徵的一個子集。
 
譯註:該函式庫可在 ftp://ftp.ee.lbl.gov/libpcap.tar.Z 得到。
 
 
SOCK_DGRAM 分組套介面對 IEEE 802.3 楨不做生成或分析 IEEE 802.2 LLC 報頭的嘗試。當在套介面中指定了 ETH_P_802_3 協議, 告知核心生成 802.3 楨,並填寫了長度欄位;使用者必須提供提供 LLC 報頭來產生符合標準的分組。到來的 802.3 分組不在協議 欄位 DSAP/SSAP 上實現多路複用;而是故意的把 ETH_P_802_2 協議的 LLC 報頭提供給使用者。所以不可能繫結到 ETH_P_802_3; 而可以繫結到 ETH_P_802_2 並自己做多路複用。預設的傳送的是 標準的乙太網 DIX 封裝並填寫協議欄位。
 
譯註: 長度欄位和協議欄位其實都是以太楨的第四欄位,這個欄位 的值在小於 1518 時表示此以太楨是 IEEE 802.3 楨,在大於1536 時表示此以太楨是 DIX 楨。DIX 中的 D 代表 DEC,I 代表 Intel, X 代表 Xerox。
 
 
分組套介面不是輸入或輸出防火牆的系列主題。
 
 
 

ERRORS 錯誤資訊

ENETDOWN
介面未啟動。
ENOTCONN
未傳遞介面地址。
ENODEV
在介面地址中指定了未知的裝置名或介面索引。
EMSGSIZE
分組比介面的 MTU(最大傳輸單元)大。
ENOBUFS
沒有足夠的記憶體分配給分組。
EFAULT
使用者傳遞了無效的地址。
EINVAL
無效引數。
ENXIO
介面地址包含非法介面索引號。
EPERM
使用者沒有足夠的許可權來執行這個操作。
EADDRNOTAVAIL
傳遞了未知的多路廣播組地址。
ENOENT
未收到分組。 除此之外,底層的驅動程式可能產生其他的錯誤資訊。

VERSIONS 版本

PF_PACKET 是 Linux 2.2 的新特徵。Linux 的早期版本只支援 SOCK_PACKET。
 

BUGS 缺陷

glibc 2.1 沒有定義 SOL_PACKET。建議的補救是使用
#ifndef SOL_PACKET
#define SOL_PACKET 263
#endif
在此以後的 glibc 版本中更正了錯誤並且在 libc5 系統上不會發生。
 
沒有對 IEEE 802.2/803.3 LLC 的處理被認為是缺陷。
 
套介面過濾器未歸入文件。
 

CREDITS 貢獻者

本手冊頁是 Andi Kleen 寫的,他得到了 Matthew Wilcox 的幫助。 在 Linux 2.2 中的 PF_PACKET 是 Alexey Kuznetsov 實現的,他 的實現是以 Alan Cox 和其他人的程式碼為基礎的。
 

SEE ALSO 參見

ip(7),socket(7),socket(2),raw(7),pcap(3). RFC894-IP資料報的Ethernet楨封裝標準。 RFC1700-IP資料報的IEEE802.3楨封裝標準。 標頭檔案linux/if_ether.h包含物理層協議。
 

[中文版維護人]

mhss <[email protected]>

[中文版最新更新]

2000/10/15

《中國linux論壇man手冊頁翻譯計劃》:

http://cmpp.linuxforum.net

本頁面中文版由中文 man 手冊頁計劃提供。
 
中文 man 手冊頁計劃: https://github.com/man-pages-zh/manpages-zh

Recommended readings

Pages related to packet you should read also: