I would like to send a syn packet to my httpd server and get a responding syn-ack packet. But when I monitor with Wireshark, the packet is beeing sent by my local interface, lo
and not 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
. 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.
#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. Is it something with the bridged networking interface in my virtual machine?
EDIT 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. hping2 sends through the eth0
interface and contains all MAC address information. 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???). Look at this picture:
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. And I have not clue at all why the heck my program won't include any MAC addresses in my packets. Everything else in my packet is equal to the contents in the hping2 packets, except sequence number which is randomized.
Any other ideas?