简体   繁体   English

使用C ++将完整的以太网数据包发送到特定的IP

[英]Send full ethernet packet to specific ip using C++

I am trying to send a full packet to specific IP address. 我正在尝试将完整的数据包发送到特定的IP地址。 The point is that I already have full packet binary and I don't want it to be encapsulated into any additional packet headers. 关键是我已经拥有完整的数据包二进制文件,并且不希望将其封装到任何其他数据包头中。 Here is my logic: 这是我的逻辑:

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);
}

Output: 输出:

Connection Failed

Could anyone help me achieve my goal? 谁能帮助我实现我的目标?

Use libpcap , pcap_inject() in particular. 特别使用libpcappcap_inject()

You cannot use socket() , using IPPROTO_RAW either, because L2(eth) and L3(ip) will be forged by the IP stack of the OS in this case too. 您也不能使用socket() ,也不能使用IPPROTO_RAW ,因为在这种情况下,L2(eth)和L3(ip)也将由操作系统的IP堆栈伪造。

You need to inject the packet directly into the network card. 您需要将数据包直接注入网卡。 If you want it delivered to an IP different from the original one, you have to "edit" the packet contents. 如果要将其传递给与原始IP不同的IP,则必须“编辑”数据包内容。

Example pasted from here: http://www.microhowto.info/howto/send_an_arbitrary_ethernet_frame_using_libpcap.html 从此处粘贴的示例: http : //www.microhowto.info/howto/send_an_arbitrary_ethernet_frame_using_libpcap.html

char pcap_errbuf[PCAP_ERRBUF_SIZE];
pcap_errbuf[0]='\0';

pcap_t* pcap=pcap_open_live(if_name,65536,0,0,pcap_errbuf);
if (pcap_errbuf[0]!='\0') {
    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)

If you don't want to edit the IP destination, the packet will be able to reach the other end of the wire only if you haven't switches/routers between the two peers. 如果您不想编辑IP目的地,则只有在两个对等方之间没有交换机/路由器时,数据包才能到达线路的另一端。

As an alternative the OP suggesting to use a tunnel. 作为替代方案,OP建议使用隧道。 It actually works (I tested it with tcpreplay ) - you can use a GRE tunnel, which actually can transport ethernet traffic too. 它实际上可以工作(我用tcpreplay测试过)-您可以使用GRE隧道,它实际上也可以传输以太网流量。

On the two peers you can establish a gretap tunnel. 在两个对等点上,您可以建立一个gretap隧道。 I used these commands: 我使用了以下命令:

on host A (its IP address is 192.168.1.211): 在主机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

on host B (its IP address is 192.168.1.64): 在主机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

At this point it's possible to use the L2 GRE tunnel and let it transport ETH traffic using the gretap1 interfaces. 此时,可以使用L2 GRE隧道,并使其使用gretap1接口传输ETH流量。 On one peer I injected the traffic into the tunnel with the command: 在一个对等体上,我使用以下命令将流量注入隧道:

tcpreplay -i gretap1 test.pcap

and on the other peer verified the traffic was transmitted capturing it on the gretap1 interface using wireshark or tcpdump. 在另一对等端上,已验证通过wireshark或tcpdump在gretap1接口上捕获流量以传输流量。

Unfortunately there is a problem with this setup: the MTU of the tunnel is smaller than the MTU of the network, so it's not guaranteed that you can replay all the packets. 不幸的是,这种设置存在一个问题:隧道的MTU小于网络的MTU,因此不能保证可以重播所有数据包。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM