使用 C++ 将完整的以太网数据包发送到特定的 ip
Send full ethernet packet to specific ip using C++
我正在尝试将完整的数据包发送到特定的 IP 地址。关键是我已经有了完整的数据包二进制文件,我不想将它封装到任何额外的数据包中 headers。这是我的逻辑:
std::string destination_ip = "127.0.0.1";
uint16_t destination_port = 8080;
int socket_fd;
struct sockaddr_in socket_attrs;
if ((socket_fd = socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL))) < 0)
{
printf("Socket creation error\n");
return false;
}
memset(&socket_attrs, '0', sizeof(socket_attrs));
socket_attrs.sin_family = AF_INET;
socket_attrs.sin_port = htons(destination_port);
if(inet_pton(AF_INET, destination_ip.c_str(), &socket_attrs.sin_addr)<=0)
{
printf("Invalid IP address/ IP address not supported\n");
return false;
}
if (connect(socket_fd, (struct sockaddr *)&socket_attrs, sizeof(socket_attrs)) < 0)
{
printf("Connection Failed\n");
return false;
}
if((write(socket_fd , <PACKET_DATA> , <PACKET_SIZE>)) < 0){
std::cout << "Error sending packets to the network" << std::endl;
exit(1);
}
输出:
Connection Failed
谁能帮我实现我的目标?
特别使用libpcap
、pcap_inject()。
你不能使用socket()
,也不能使用IPPROTO_RAW
,因为在这种情况下L2(eth)和L3(ip)也会被OS的IP栈伪造.
您需要将数据包直接注入网卡。如果你想把它传送到一个不同于原始 IP 的 IP,你必须 "edit" 数据包内容。
从此处粘贴的示例:http://www.microhowto.info/howto/send_an_arbitrary_ethernet_frame_using_libpcap.html
char pcap_errbuf[PCAP_ERRBUF_SIZE];
pcap_errbuf[0]='[=10=]';
pcap_t* pcap=pcap_open_live(if_name,65536,0,0,pcap_errbuf);
if (pcap_errbuf[0]!='[=10=]') {
fprintf(stderr,"%s",pcap_errbuf);
}
if (!pcap) {
exit(1);
}
if (pcap_inject(pcap, <PACKET_DATA> , <PACKET_SIZE> )==-1) {
pcap_perror(pcap,0);
pcap_close(pcap);
exit(1);
}
pcap_close(pcap)
如果您不想编辑 IP 目标,只有当两个对等点之间没有 switches/routers 时,数据包才能到达线路的另一端。
作为替代方案,OP 建议使用隧道。它确实有效(我用 tcpreplay
测试过它)——你可以使用 GRE 隧道,它实际上也可以传输以太网流量。
在两个点上你可以建立一个gretap隧道。我使用了这些命令:
主机A(其IP地址为192.168.1.211):
ip link add gretap1 type gretap local 192.168.1.211 remote 192.168.1.64
ip link set gretap1 up
在主机 B 上(其 IP 地址为 192.168.1.64):
ip link add gretap1 type gretap local 192.168.1.64 remote 192.168.1.211
ip link set gretap1 up
此时可以使用 L2 GRE 隧道并让它使用 gretap1 接口传输 ETH 流量。在一个对等点上,我使用以下命令将流量注入隧道:
tcpreplay -i gretap1 test.pcap
并且在另一个节点上验证了流量已传输,使用 wireshark 或 tcpdump 在 gretap1 接口上捕获它。
不幸的是,此设置存在一个问题:隧道的 MTU 小于网络的 MTU,因此不能保证您可以重播所有数据包。
我正在尝试将完整的数据包发送到特定的 IP 地址。关键是我已经有了完整的数据包二进制文件,我不想将它封装到任何额外的数据包中 headers。这是我的逻辑:
std::string destination_ip = "127.0.0.1";
uint16_t destination_port = 8080;
int socket_fd;
struct sockaddr_in socket_attrs;
if ((socket_fd = socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL))) < 0)
{
printf("Socket creation error\n");
return false;
}
memset(&socket_attrs, '0', sizeof(socket_attrs));
socket_attrs.sin_family = AF_INET;
socket_attrs.sin_port = htons(destination_port);
if(inet_pton(AF_INET, destination_ip.c_str(), &socket_attrs.sin_addr)<=0)
{
printf("Invalid IP address/ IP address not supported\n");
return false;
}
if (connect(socket_fd, (struct sockaddr *)&socket_attrs, sizeof(socket_attrs)) < 0)
{
printf("Connection Failed\n");
return false;
}
if((write(socket_fd , <PACKET_DATA> , <PACKET_SIZE>)) < 0){
std::cout << "Error sending packets to the network" << std::endl;
exit(1);
}
输出:
Connection Failed
谁能帮我实现我的目标?
特别使用libpcap
、pcap_inject()。
你不能使用socket()
,也不能使用IPPROTO_RAW
,因为在这种情况下L2(eth)和L3(ip)也会被OS的IP栈伪造.
您需要将数据包直接注入网卡。如果你想把它传送到一个不同于原始 IP 的 IP,你必须 "edit" 数据包内容。
从此处粘贴的示例:http://www.microhowto.info/howto/send_an_arbitrary_ethernet_frame_using_libpcap.html
char pcap_errbuf[PCAP_ERRBUF_SIZE];
pcap_errbuf[0]='[=10=]';
pcap_t* pcap=pcap_open_live(if_name,65536,0,0,pcap_errbuf);
if (pcap_errbuf[0]!='[=10=]') {
fprintf(stderr,"%s",pcap_errbuf);
}
if (!pcap) {
exit(1);
}
if (pcap_inject(pcap, <PACKET_DATA> , <PACKET_SIZE> )==-1) {
pcap_perror(pcap,0);
pcap_close(pcap);
exit(1);
}
pcap_close(pcap)
如果您不想编辑 IP 目标,只有当两个对等点之间没有 switches/routers 时,数据包才能到达线路的另一端。
作为替代方案,OP 建议使用隧道。它确实有效(我用 tcpreplay
测试过它)——你可以使用 GRE 隧道,它实际上也可以传输以太网流量。
在两个点上你可以建立一个gretap隧道。我使用了这些命令:
主机A(其IP地址为192.168.1.211):
ip link add gretap1 type gretap local 192.168.1.211 remote 192.168.1.64
ip link set gretap1 up
在主机 B 上(其 IP 地址为 192.168.1.64):
ip link add gretap1 type gretap local 192.168.1.64 remote 192.168.1.211
ip link set gretap1 up
此时可以使用 L2 GRE 隧道并让它使用 gretap1 接口传输 ETH 流量。在一个对等点上,我使用以下命令将流量注入隧道:
tcpreplay -i gretap1 test.pcap
并且在另一个节点上验证了流量已传输,使用 wireshark 或 tcpdump 在 gretap1 接口上捕获它。
不幸的是,此设置存在一个问题:隧道的 MTU 小于网络的 MTU,因此不能保证您可以重播所有数据包。