首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >发送带有syn标志集的原始tcp数据包只是通过lo接口,而不是我想要的eth0。

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

Stack Overflow用户
提问于 2013-12-31 10:10:49
回答 2查看 3.7K关注 0票数 8

我想发送一个syn包到我的httpd服务器并得到一个响应syn-ack数据包。但是当我用Wireshark进行监控时,数据包是由我的本地接口lo而不是eth0发送的。

我尝试在setsockopt中设置一些不同的值,正如您在下面的代码中所看到的那样,但是似乎没有一个能起作用,它总是使用lo接口而不是eth0。我不知道tcp数据包中是否有问题使其通过本地接口,或者是否是其他原因。

代码语言:javascript
复制
#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;
}

我的接口:

代码语言:javascript
复制
# 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

编辑

代码语言:javascript
复制
...
#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");

但它仍然要通过lo接口。是因为我的虚拟机中的桥接网络接口吗?

编辑2

我现在已经比较了我的原始ip包和hping2发送的数据包,唯一不同的是接口id (在帧中指定),并且以太网层不包含任何MAC地址信息。hping2通过eth0接口发送并包含所有MAC地址信息。我的程序确实通过lo发送它,并且不包含任何MAC信息(可能是通过接口发送的,因为它在数据包??中不包含任何MAC地址信息)。看看这幅画:

​

在如何构造原始IP包方面,我还比较了hping2的源代码和我的代码,我看不到任何东西可以使包通过lo接口,就像我的例子一样。我完全不知道为什么我的程序不会在我的数据包中包含任何MAC地址。我的数据包中的其他所有内容都等于hping2数据包中的内容,但序列号是随机的。

还有其他想法吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-01-03 00:39:25

我自己解决了。是sin.sin_addr.s_addr指向发送者IP,但它必须是服务器ip!小心,因为在代码中看到这样的错误并不总是容易的!:-)

现在数据包包含正确的MAC信息。

下一个问题是为什么我没有从服务器获得任何syn-acks,但我会对这个问题提出一个新的问题。

票数 4
EN

Stack Overflow用户

发布于 2013-12-31 11:42:23

若要为出口通信选择特定的网络接口(在Linux上),可以使用:

代码语言:javascript
复制
setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, device, sizeof(device)); 

带有示例代码段的链接

更多信息

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20855587

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档