我想向我的 httpd 服务器发送一个 syn 数据包并获得一个响应的 syn-ack 数据包。但是当我使用 Wireshark 进行监控时,数据包是由我的本地接口(interface) lo
而不是 eth0
发送的。
我已经尝试在 setsockopt
中设置一些不同的值,正如您在下面的代码中看到的那样,但似乎都没有用,它总是使用 lo
接口(interface)并且不是 eth0
。我不知道使它通过本地接口(interface)的 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;
}
我的界面:
# 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
编辑
...
#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
接口(interface)。我的虚拟机中的桥接网络接口(interface)是否有问题?
编辑 2
我现在已经将我的原始 ip 数据包与 hping2 发送的数据包进行了比较,唯一不同的是接口(interface) id(在帧中指定)并且以太网层不包含任何 MAC 地址信息。 hping2通过eth0
接口(interface)发送,包含所有MAC地址信息。我的程序确实通过 lo
发送它并且不包含任何 MAC 信息(可能它是通过 lo
接口(interface)发送的因为它不包含任何 MAC 地址信息在数据包???)。看这张图片:
我还将 hping2 的源代码与我在如何构建原始 IP 数据包方面的代码进行了比较,但我看不到任何可以使数据包像我的情况一样通过 lo
接口(interface)的东西。而且我完全不知道为什么我的程序不会在我的数据包中包含任何 MAC 地址。我数据包中的其他所有内容都与 hping2 数据包中的内容相同,除了随机的序列号。
还有其他想法吗?
最佳答案
自己解决了。指向发件人 IP 的是 sin.sin_addr.s_addr
,但它必须是服务器 ip!要小心,因为在代码中发现此类错误并不总是那么容易! :-)
现在数据包包含正确的 MAC 信息。
下一个问题是为什么我没有从服务器获得任何syn-acks
,但我会针对该问题提出一个新问题。
关于c++ - 发送带有 syn 标志集的原始 tcp 数据包只是通过 lo 接口(interface),而不是我想要的 eth0,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20855587/