我正在编写代码以在两个Linux机箱之间发送原始以太网帧。为了测试这一点,我只想获得一个简单的客户端发送和服务器接收。
我让客户端正确地创建数据包(我可以使用数据包嗅探器看到它们)。
在服务器端,我像这样初始化套接字:
fd = socket(PF_PACKET, SOCK_RAW, htons(MY_ETH_PROTOCOL));
其中MY_ETH_PROTOCOL
是一个2字节常量,我用作ethertype,所以我没有听到无关的网络流量。
当我将此套接字绑定到我的接口时,我必须在socket_addr结构中再次传递一个协议:
socket_address.sll_protocol = htons(MY_ETH_PROTOCOL);
如果我编译并运行这样的代码,那么它就会失败。我的服务器没有看到数据包。但是,如果我像这样更改代码:
socket_address.sll_protocol = htons(ETH_P_ALL);
然后,服务器可以看到从客户端发送的数据包(以及许多其他数据包),因此我必须对数据包进行一些检查,以确定它与MY_ETH_PROTOCOL
匹配。
但我不希望我的服务器听到未在指定协议上发送的流量,因此这不是解决方案。我该怎么做?
答案 0 :(得分:5)
我已经解决了这个问题。
根据http://linuxreviews.org/dictionary/Ethernet/引用MAC地址后面的2字节字段:
“64和1522之间的该字段的值表示使用具有长度字段的新802.3以太网格式,而1536十进制(0600十六进制)和更大的值表示使用原始DIX或以太网II帧格式一个EtherType子协议标识符。“
所以我必须确保我的ethertype是> = 0x0600。
根据http://standards.ieee.org/regauth/ethertype/eth.txt使用0x88b5和0x88b6“可供公众使用,用于原型和特定于供应商的协议开发。”所以这就是我要用作ethertype的东西。我不需要任何进一步的过滤,因为内核应该确保只使用正确的目标MAC地址并使用该协议来获取以太网帧。
答案 1 :(得分: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。