Sending a raw tcp packet with syn flag set just goes through the lo interface, not eth0 as I want
Asked Answered
N

2

8

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: Ethernet frame does not contain MAC address information

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?

Neuron answered 31/12, 2013 at 10:10 Comment(2)
is the http server on another machine or a virtual machine?Girish
It is on a virtual machine. Both the client (Kali Linux) and the server (CentOS) is virtualized and I am using bridged networking on both of the machines.Neuron
N
4

Solved it myself. It was the sin.sin_addr.s_addr that pointed at the senders IP, but it had to be the servers ip! Be careful because it isn´t always easy to see such errors in the code! :-)

Now the packets contain correct MAC information.

The next problem is why I don´t get any syn-acks from the server, but I will make a new question for that issue.

Neuron answered 3/1, 2014 at 0:39 Comment(1)
this is a prime example for some std::cerrGrandiloquence
M
3

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

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

Links with sample code snippet

More information

Mysticism answered 31/12, 2013 at 11:42 Comment(6)
My guess is that when you use raw sockets, it by passes ARP and simply send it out on the first interface on the list.Mysticism
Look at my edit. I tried the snippet in your first link, but it gives me some errors.Neuron
Ok first error is because of the assignment. You should do a strcpy/sprintf/memcpy. ifreq is a struct and on doing a google search I found posts where people have encountered issues when both linux/if.h and net/if.h are included (sometimes indirectly) by same source file. Can you try re-orderng the includes so that net/xxx comes first.Mysticism
austinmarton.wordpress.com/2011/09/14/…Mysticism
Thanks for the link. I have read the information very carefully and tried what it specifies, but without success. Look at my edit 2 in my post above.Neuron
Uninitialized MAC address is my prime suspect as well. If you have done what the blog above says under "Construct the Ethernet header:" then I have no idea why the mac address is uninitialized.Mysticism

© 2022 - 2024 — McMap. All rights reserved.