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

时间:2019-01-09 11:32:12

标签: c++ sockets packet-capture

我正在尝试将完整的数据包发送到特定的IP地址。关键是我已经拥有完整的数据包二进制文件,并且不希望将其封装到任何其他数据包头中。这是我的逻辑:

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

有人可以帮助我实现我的目标吗?

1 个答案:

答案 0 :(得分:1)

特别使用libpcap,尤其是pcap_inject()

您也不能使用socket(),也不能使用IPPROTO_RAW,因为在这种情况下,L2(eth)和L3(ip)也将由OS的IP堆栈伪造。

您需要将数据包直接注入网卡。如果要将其传递到与原始IP不同的IP,则必须“编辑”数据包内容。

从此处粘贴的示例: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)

如果您不想编辑IP目的地,则只有在两个对等方之间没有交换机/路由器时,数据包才能到达线路的另一端。

作为替代方案,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

并在另一对等节点上验证了传输是通过使用wirehark或tcpdump在gretap1接口上捕获的。

不幸的是,此设置存在问题:隧道的MTU小于网络的MTU,因此不能保证可以重播所有数据包。