简体   繁体   English

发送带有syn标志设置的原始tcp数据包只是通过lo接口,而不是我想要的eth0

[英]Sending a raw tcp packet with syn flag set just goes through the lo interface, not eth0 as I want

I would like to send a syn packet to my httpd server and get a responding syn-ack packet. 我想发送一个syn数据包到我的httpd服务器并获得响应的syn-ack数据包。 But when I monitor with Wireshark, the packet is beeing sent by my local interface, lo and not eth0 . 但是,当我使用Wireshark监控,数据包与否有关我的本地接口,发送lo ,而不是eth0

I have tried to set some different values in setsockopt as you can see in the code below, but none seems to work, it is always using the lo interface and not eth0 . 我已经尝试在setsockopt设置一些不同的值,如下面的代码所示,但似乎没有一个工作,它总是使用lo接口而不是eth0 I don't know if it something wrong in the tcp packet that makes it go through local interface, or if it is something else. 我不知道tcp数据包是否有什么问题导致它通过本地接口,或者是否是其他东西。

#include <cstdlib>
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>

#define PCKT_LEN 8192

unsigned short csum(unsigned short *buf, int len) {
    unsigned long sum;
    for(sum=0; len>0; len--)
        sum += *buf++;
    sum = (sum >> 16) + (sum &0xffff);
    sum += (sum >> 16);
    return (unsigned short)(~sum);
}

int main(int argc, char** argv) {

    char *buffer = new char[PCKT_LEN]();

    class iphdr *ip = (struct iphdr *) buffer;
    class tcphdr *tcp = (struct tcphdr *) (buffer + sizeof(struct iphdr));

    class sockaddr_in sin;

    int sd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
    if(sd < 0) {
       perror("socket() error");
       exit(-1);
    } else {
        printf("socket()-SOCK_RAW and tcp protocol is OK.\n");
    }

    sin.sin_family = AF_INET;           // Address family
    sin.sin_port = htons(atoi("2345")); // Source port
    inet_pton(AF_INET, "192.168.1.11", &(sin.sin_addr.s_addr)); // Dest IP - ERROR WAS WRONG IP

    ip->ihl = 5;
    ip->version = 4;
    ip->tos = 16;
    ip->tot_len = sizeof(class iphdr) + sizeof(class tcphdr);
    ip->id = htons(54321);
    ip->frag_off = 0;
    ip->ttl = 32;
    ip->protocol = 6; // TCP
    ip->check = 0; // Done by kernel
    inet_pton(AF_INET, "192.168.1.10", &(ip->saddr)); // Source IP
    inet_pton(AF_INET, "192.168.1.11", &(ip->daddr)); // Destination IP

    // The TCP structure
    tcp->source = htons(atoi("2345"));
    tcp->dest = htons(atoi("80"));      // Destination port
    tcp->seq = htonl(1);
    tcp->ack_seq = random();
    tcp->doff = 5;
    tcp->syn = 1;
    tcp->ack = 0;
    tcp->window = htons(32767);
    tcp->check = 0; // Done by kernel
    tcp->rst = 0;
    tcp->urg_ptr = 0;

    ip->check = csum((unsigned short *) buffer, (sizeof(class iphdr) + sizeof(class tcphdr)));

    // Bind socket to interface
    int iface = 1;
    const int *val = &iface;
    char *opt = "eth0";
    if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(iface)) < 0) {
    //if(setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, opt, 4) < 0) {
        perror("setsockopt() error");
        exit(-1);
    }
    else
        printf("setsockopt() is OK\n");

    if(sendto(sd, buffer, ip->tot_len, 0, (sockaddr*)&sin, sizeof(class sockaddr_in)) < 0) {
       perror("sendto() error");
       exit(-1);
    }
    else
        printf("Send OK!");

    close(sd);
    return 0;
}

My interfaces: 我的界面:

# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000
    link/ether 00:0c:29:6e:82:29 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.10/24 brd 192.168.1.255 scope global eth0
    inet6 fe80::20c:29ff:fe6e:8229/64 scope link 
       valid_lft forever preferred_lft forever

EDIT 编辑

...
#include <sys/ioctl.h>
#include <net/if.h>
...

struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "eth0");
if(ioctl(sd, SIOCGIFINDEX, &ifr) < 0) {
    perror("ioctl failed!");
    return EXIT_FAILURE;
}
if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, &ifr, sizeof(ifr)) < 0) {
    perror("setsockopt() error");
    exit(-1);
}
    printf("setsockopt() is OK\n");

But it still goes through lo interface. 但它仍然通过lo接口。 Is it something with the bridged networking interface in my virtual machine? 它是否与我的虚拟机中的桥接网络接口有关?

EDIT 2 编辑2

I have now compared my raw ip packets with the ones that hping2 sends and the only thing that differs is the interface id (specified in the frame) and that the ethernet layer does not contain any MAC address information. 我现在比较了我的原始ip数据包和hping2发送的数据包,唯一不同的是接口ID(在帧中指定),以及以太网层不包含任何MAC地址信息。 hping2 sends through the eth0 interface and contains all MAC address information. hping2通过eth0接口发送并包含所有MAC地址信息。 My program does send it through lo and does NOT contain any MAC information ( maybe it is sent through lo interface because it does not contain any MAC address information in the packet??? ). 我的程序确实发送它通过lo并且不包含任何MAC信息( 也许它是通过lo接口发送的,因为它不包含数据包中的任何MAC地址信息??? )。 Look at this picture: 看这张图片: 以太网帧不包含MAC地址信息

I have also compared the source code of hping2 with my code in how to construct a raw IP packet and I cannot see anything that would make the packets go through the lo interface as in my case. 我还将hping2的源代码与我的代码进行了比较,以了解如何构建原始IP数据包,我看不到任何可以使数据包通过lo接口的内容,就像我的情况一样。 And I have not clue at all why the heck my program won't include any MAC addresses in my packets. 而且我还没有弄清楚为什么我的程序不会在我的数据包中包含任何MAC地址。 Everything else in my packet is equal to the contents in the hping2 packets, except sequence number which is randomized. 我的数据包中的其他所有内容都等于hping2数据包中的内容,但随机化的序列号除外。

Any other ideas? 还有其他想法吗?

Solved it myself. 自己解决了。 It was the sin.sin_addr.s_addr that pointed at the senders IP, but it had to be the servers ip! sin.sin_addr.s_addr指向发件人IP,但它必须是服务器IP! Be careful because it isn´t always easy to see such errors in the code! 要小心,因为在代码中看到这样的错误并不容易! :-) :-)

Now the packets contain correct MAC information. 现在数据包包含正确的MAC信息。

The next problem is why I don´t get any syn-acks from the server, but I will make a new question for that issue. 接下来的问题是为什么我没有从服务器获得任何syn-acks ,但我会为这个问题提出一个新问题。

To select a specific network interface (on Linux) for egress traffic you can use: 要为出口流量选择特定的网络接口(在Linux上),您可以使用:

setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, device, sizeof(device)); 

Links with sample code snippet 链接示例代码段

More information 更多信息

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

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