在linux环境中要从链路层(MAC)直接收发数据帧,可以通过libpcap与libnet两个动态库来分别完成收与发的工作。虽然它已被广泛使用,但在要求进行跨平台移植的软件中使用仍然有很多弊端。
这里介绍一种更为直接地、无须安装其它库的从MAC层收发数据帧的方式,即通过定义链路层的套接字来完成。
Packet套接字用于在MAC层上收发原始数据帧,这样就允许用户在用户空间完成MAC之上各个层次的实现。给无论是进行开发还是测试的人们带来了极大的便利性。
Packet套接字的定义方式与传送层的套接字定义类似,这个套接字的打开需要用户有root权限,如下:
packet_socket=socket(PF_PACKET,int socket_type,int protocol);
其中socket_type有两种类型,一种为SOCK_RAW,它是包含了MAC层头部信息的原始分组,当然这种类型的套接字在发送的时候需要自己加上一个MAC头部(其类型定义在linux/if_ether.h中,ethhdr),另一种是SOCK_DGRAM类型,它是已经进行了MAC层头部处理的,即收上的帧已经去掉了头部,而发送时也无须用户添加头部字段。
Protocol是指其送交的上层的协议号,如IP为0x0800,当其为htons(ETH_P_ALL) (其宏定义为0)时表示收发所有的协议。
创建好套接字后,就可以通过与UDP一样的recvfrom与sendto函数进行数据的收发,其目的地址结构为sockaddr_ll,这与传送层的地址结构定义是不一样的,其长度为20字节(在TCP/IP的链路层地址中使用了18字节),而传送层的地址结构长度为16字节。
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)地址和地址长度。精确的解释依赖于设备。(本段引于packet的用户手册)
当在多个网络接口的主机上使用这个套接字时,若要指定接收或发送的接口时可以使用bind进行绑定,这与TCP套接字的操作一样,但其内涵并不相同。绑定时将根据地址结构中的sll_protocal和sll_ifindex分别绑定收发的协议号和接口索引号,接口索引号sll_ifindex为0时表示使用有效的所有接口。接口的sll_ifindex值可以通过ioctl获得,如下面是获得名字为“eth0”的接口的索引号:
strcpy(ifr.ifr_name,"eth0");
ioctl(fd_packet,SIOCGIFINDEX,&ifr);
取得的值保存在ifr结构体的ifr_ifindex中,ifr结构类型为“struct ifreq”。
BTW,要获得接口的物理地址同样使用ioctl可以得到:
ioctl(fd_packet,SIOCGIFHWADDR,&ifr);
以数据形式保存在ifr的ifr_hwaddr.sa_data中。
另外需要注意的是,在调用recvfrom函数时返回的地址长度信息为18字节,原因是在sockaddr_ll结构中的sll_addr[8]为8字节,MAC地址只使用了其中的前6字节。在用sendto发送时需要将目的地址结构体强制转换为struct sockaddr 类型,而且指定的长度必须为20字节,而不能是18或其它值。
分享到:
相关推荐
首先,PF_PACKET是Linux内核提供的一种原始套接字协议家族,它允许应用程序直接访问网络接口的物理层,而无需经过TCP/IP协议栈。这种直接访问使得开发者能够实现高效的数据传输,特别适合于低级别的网络协议实现,如...
`sockaddr_ll`结构体用于表示Packet套接字的地址信息,是链路层地址结构的一种。其具体定义如下: ```c struct sockaddr_ll { unsigned short sll_family; // 总是AF_PACKET unsigned short sll_protocol; // ...
这个示例创建了一个原始套接字,并设置了协议族为 PF_PACKET、套接字类为 SOCK_RAW、协议类别为 ETH_P_ALL。 六、结论 原始套接字是一种强大的网络编程技术,它允许开发者访问和控制网络协议栈的底层细节。但是,...
raw_socket = socket.socket(socket.PF_PACKET, socket.SOCK_RAW, socket.htons(0x1234)) raw_socket.bind((eth0, 0)) packet = struct.pack(!6s6sH, \xff\xff\xff\xff\xff\xff, \xaa\xaa\xaa\xaa\xaa\xaa, 0x1234) ...
- **PF_PACKET**:表示我们将使用原始套接字来与链路层进行通信。 - **type**:可以选择`SOCK_RAW`或`SOCK_DGRAM`。这两种类型的具体区别在于: - `SOCK_RAW`:这种类型的套接字会将完整的数据帧(包括MAC头部)...
1. **创建原始套接字**:使用`socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))`创建一个原始套接字,参数`PF_PACKET`指定使用数据链路层协议,`SOCK_RAW`表示创建的是原始套接字。 2. **设置混杂模式**:通过`ioctl...
- 在C++中,通常使用`socket()`函数创建一个原始套接字,指定`PF_INET`或`PF_PACKET`协议族,以及`SOCK_RAW`类型。 2. **基于MAC地址的通信**: - 在网络层之下,数据帧是通过MAC地址进行传输的。每个网络设备都...
- 创建套接字:使用`socket`函数创建一个PF_PACKET类型的原始套接字,其中第二个参数指定为SOCK_RAW,表明该套接字为原始套接字,数据包不会经过协议栈的处理。 - 设置接收条件:第三个参数指定接收的数据类型,可以...
2. 使用socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL)) 创建的原始套接字,用来捕获以太网数据帧。 3. socket(AF_INET, SOCK_PACKET, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL)) 是过时的方法,不...
这个ARP抓包程序的实现,不仅展示了如何在Linux环境下使用原始套接字捕获网络数据,还涉及到网络协议栈中不同层次的交互,特别是数据链路层的以太网帧和网络层的ARP协议。通过这样的程序,可以监控网络流量,分析...
使用`socket()`函数创建一个套接字,指定`PF_PACKET`协议家族和`SOCK_RAW`类型,可以获取到网络层的数据包。 2. **设置套接字选项**: 使用`setsockopt()`函数设置套接字选项,例如`SO_BINDTODEVICE`,可以选择...
在数据链路层,我们可以使用"packet socket"这一特殊的套接字类型来直接操作网络接口层的数据包,从而实现对网络流量的直接监控和控制。Packet socket允许程序直接访问网络设备驱动程序,提供了一种低级别的网络编程...
4. **原始套接字API**:学习如何创建和使用PF_PACKET或SOCK_RAW套接字,包括`bind()`、`recvfrom()`、`sendto()`等函数的使用。 5. **网络包捕获**:可能涉及到libpcap库的使用,这是一个广泛用于网络分析和故障...
在Linux下,libpcap通常结合PF_PACKET套接字使用,可以实现高效的数据包捕获。通过设置合适的过滤规则,我们可以只关注特定类型或特定源/目的的数据包,进一步提高效率。 提到“高带宽”,这暗示了我们可能需要处理...
libpcap利用操作系统提供的原始套接字(raw sockets)或者特定的内核驱动(如PF_PACKET在Linux下),直接访问网络接口的数据链路层。当数据包在网卡上传输时,libpcap能够拦截并复制这些数据包到用户空间,供应用...