Отправка необработанного tcp-пакета с установленным флагом syn просто проходит через интерфейс lo, а не eth0, как я хочу

Я хотел бы отправить пакет syn на мой httpd-сервер и получить ответный пакет syn-ack. Но когда я слежу за Wireshark, пакет отправляется моим локальным интерфейсом, lo и не eth0,

Я пытался установить несколько разных значений в setsockopt как вы можете видеть в коде ниже, но ни один из них не работает, он всегда использует lo интерфейс, а не eth0, Я не знаю, если что-то не так в пакете 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 интерфейс. Это что-то с мостовым сетевым интерфейсом в моей виртуальной машине?

РЕДАКТИРОВАТЬ 2

Теперь я сравнил свои необработанные ip-пакеты с теми, которые отправляет hping2, и единственное, что отличается, — это идентификатор интерфейса (указанный в кадре) и то, что уровень Ethernet не содержит никакой информации MAC-адреса. hping2 отправляет через eth0 интерфейс и содержит всю информацию MAC-адреса. Моя программа отправляет его через lo и не содержит никакой информации MAC (возможно это отправлено через lo интерфейс, потому что он не содержит никакой информации MAC-адреса в пакете ???). Посмотри на эту картину:
Кадр Ethernet не содержит информацию о MAC-адресе

Я также сравнил исходный код hping2 с моим кодом в том, как создать необработанный IP-пакет, и я не вижу ничего, что могло бы заставить пакеты проходить через lo интерфейс, как в моем случае. И я даже не представляю, почему, черт возьми, моя программа не будет включать MAC-адреса в мои пакеты. Все остальное в моем пакете равно содержимому в пакетах hping2, кроме порядкового номера, который рандомизирован.

Есть другие идеи?

8

Решение

Решил это сам. Это было sin.sin_addr.s_addr что указывало на IP отправителей, но это должны были быть ip серверов! Будьте осторожны, потому что не всегда легко увидеть такие ошибки в коде! 🙂

Теперь пакеты содержат правильную информацию MAC.

Следующая проблема — почему я не получаю syn-acks с сервера, но я сделаю новый вопрос для этой проблемы.

4

Другие решения

Чтобы выбрать определенный сетевой интерфейс (в Linux) для выходного трафика, вы можете использовать:

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

Ссылки с примером кода

Дополнительная информация

3

По вопросам рекламы [email protected]