Linux原始以太网套接字绑定到特定协议

7

我正在编写代码,在两个Linux机器之间发送原始以太网帧。为了测试,我只想得到一个简单的客户端发送和服务器接收。

我已经成功地让客户端制作数据包(我可以使用数据包嗅探器看到它们)。

在服务器端,我这样初始化套接字:

fd = socket(PF_PACKET, SOCK_RAW, htons(MY_ETH_PROTOCOL));

在这里,MY_ETH_PROTOCOL是我用作以太类型的2字节常量,以便我不会听到杂乱的网络流量。

当我将此套接字绑定到我的接口时,我必须再次在socket_addr结构中传递协议: socket_address.sll_protocol = htons(MY_ETH_PROTOCOL);
如果我像这样编译和运行代码,则会失败。我的服务器看不到数据包。但是,如果我像这样更改代码:
socket_address.sll_protocol = htons(ETH_P_ALL);
那么服务器就可以看到从客户端发送的数据包(以及许多其他数据包),所以我必须检查数据包是否与MY_ETH_PROTOCOL匹配。

但我不想让我的服务器听到未在指定协议上发送的流量,因此这不是一个解决方案。我该怎么做?


你能贴出设定socket_address的代码吗? - bstpierre
2个回答

5

我已经解决了这个问题。

根据http://linuxreviews.org/dictionary/Ethernet/所述,MAC地址后面的2字节字段:

"该字段的值在64到1522之间表示使用具有长度字段的新802.3以太网格式,而1536十进制数(0600十六进制数)及以上的值表示使用具有EtherType子协议标识符的原始DIX或以太网II帧格式。"

因此,我必须确保我的以太类型(ethertype)大于等于0x0600。

根据http://standards.ieee.org/regauth/ethertype/eth.txt所述,使用0x88b5和0x88b6是“可供公众用于原型和特定厂商协议开发”。因此,这就是我要用作以太类型(ethertype)的内容。我不需要进行进一步过滤,因为内核应该确保仅选择具有正确目标MAC地址并使用该协议的以太网帧。


我按照你说的做了。但是我的客户端无法接收指定协议数据包。你能把你的代码粘贴一下吗?谢谢!邮箱:ycsunjane@gmail.com - jianxi sun

0

我过去曾经通过使用数据包过滤器来解决这个问题。

手势演示(未经测试的伪代码)

struct bpf_insn my_filter[] = {
    ...
}

s = socket(PF_PACKET, SOCK_DGRAM, htons(protocol));
struct sock_fprog pf;
pf.filter = my_filter;
pf.len = my_filter_len;
setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &pf, sizeof(pf));

sll.sll_family = PF_PACKET;
sll.sll_protocol = htons(protocol);
sll.sll_ifindex = if_nametoindex("eth0");

bind(s, &sll, sizeof(sll));

错误检查和正确设置数据包过滤器留给读者自行练习...

根据您的应用程序,一个可能更容易使用的替代方案是libpcap


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接