Sending a raw tcp packet using a set of synchronization flags is only done through the lo interface, not eth0, as I want to

I want to send a sync packet to my httpd server and get a syn-ack response packet. But when I track Wireshark, the packet is sent by my local lo interface, not eth0 .

I tried setting a few different values ​​in setsockopt , as you can see in the code below, but no one works, it always uses the lo interface, not eth0 . I don’t know if something is wrong in the tcp package, which forces it to go through the local interface, or if it is something else.

 #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 the lo interface. Is this something with a bridged network interface on my virtual machine?

EDIT 2

Now I have compared my raw ip packets to the ones that hping2 sends, and the only thing that differs is the interface identifier (indicated in the frame) and that the ethernet layer does not contain any MAC address information. hping2 sends via eth0 and contains all the MAC address information. My program sends it through lo and does NOT contain any MAC information ( maybe it is sent through the lo interface because it does not contain any MAC address information in the packet ). Look at this picture: Ethernet frame does not contain MAC address information

I also compared the hping2 source code with my code on how to create a raw IP packet, and I don't see anything that could make the packets go through the lo interface, as in my case. And I don’t understand why the hell my program will not include MAC addresses in my packages. Everything else in my package is equal to the contents of hping2 packages, except for the serial number, which is randomized.

Any other ideas?

+8
c ++ network-interface raw-sockets
source share
2 answers

I decided it myself. It was sin.sin_addr.s_addr that pointed to the sender's IP addresses, but it should have been an ip server! Be careful, because it is not always easy to see such errors in the code! :-)

The packets now contain the correct MAC information.

The next problem is why I am not getting syn-acks from the server, but I will ask a new question for this problem.

+4
source share

To select a specific network interface (on Linux) for outgoing traffic, you can use:

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

Links with sample code snippet

Additional Information

  • Problems with SO_BINDTODEVICE Linux socket option
+3
source share

All Articles