9

Have some problems in receiving packets. I can receive and read incoming packets, but I think i do not get a handshake with any host. I only want to send a packet to a remote computer with an open port on receiving an answer to see the TTL(time to live) and the window size. Does anyone have an idea where the errors are? (I don't have very deep knowledge in C programming)

CODE:

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <net/ethernet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>

struct pseudohdr {
    u_int32_t src_addr;
    u_int32_t dst_addr;
    u_int8_t padding;
    u_int8_t proto;
    u_int16_t length;
};

struct data_4_checksum {
    struct pseudohdr pshd;
    struct tcphdr tcphdr;
    char payload[1024];
};
unsigned short comp_chksum(unsigned short *addr, int len) {
    long sum = 0;

    while (len > 1) {
        sum += *(addr++);
        len -= 2;
    }

    if (len > 0)
        sum += *addr;

    while (sum >> 16)
        sum = ((sum & 0xffff) + (sum >> 16));

    sum = ~sum;

    return ((u_short) sum);

}

int main(int argc, char *argv[]) {

    int sock, bytes, on = 1;
    char buffer[1024];
    struct iphdr *ip;
    struct tcphdr *tcp;
    struct sockaddr_in to;
    struct pseudohdr pseudoheader;
    struct data_4_checksum tcp_chk_construct;

    if (argc != 2) {
        fprintf(stderr, "Usage: %s ", argv[0]);
        fprintf(stderr, "<dest-addr>\n");
        return 1;
    }

    sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
    if (sock == -1) {
        perror("socket() failed");
        return 1;
    }else{
        printf("socket() ok\n");
    }

    if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) == -1) {
        perror("setsockopt() failed");
        return 2;
    }else{
        printf("setsockopt() ok\n");
    }

    ip = (struct iphdr*) buffer;
    tcp = (struct tcphdr*) (buffer + sizeof(struct tcphdr));

    int iphdrlen = sizeof(struct iphdr);
    int tcphdrlen = sizeof(struct tcphdr);
    int datalen = 0;
    printf("Typecasting ok\n");

    ip->frag_off = 0;
    ip->version = 4;
    ip->ihl = 5;
    ip->tot_len = htons(iphdrlen + tcphdrlen);
    ip->id = 0;
    ip->ttl = 40;
    ip->protocol = IPPROTO_TCP;
    ip->saddr = inet_addr("192.168.165.135");
    ip->daddr = inet_addr(argv[1]);
    ip->check = 0;

    tcp->source     = htons(12345);
    tcp->dest       = htons(80);
    tcp->seq        = random();
    tcp->doff       = 5;
    tcp->ack        = 0;
    tcp->psh        = 0;
    tcp->rst        = 0;
    tcp->urg        = 0;
    tcp->syn        = 1;
    tcp->fin        = 0;
    tcp->window     = htons(65535);

    pseudoheader.src_addr = ip->saddr;
    pseudoheader.dst_addr = ip->daddr;
    pseudoheader.padding = 0;
    pseudoheader.proto = ip->protocol;
    pseudoheader.length = htons(tcphdrlen + datalen);

    tcp_chk_construct.pshd = pseudoheader;
    tcp_chk_construct.tcphdr = *tcp;

    int checksum = comp_chksum((unsigned short*) &tcp_chk_construct,
            sizeof(struct pseudohdr) + tcphdrlen + datalen);

    tcp->check = checksum;

    printf("TCP Checksum: %i\n", checksum);
    printf("Destination : %i\n", ntohs(tcp->dest));
    printf("Source: %i\n", ntohs(tcp->source));

    to.sin_addr.s_addr = ip->daddr;
    to.sin_family = AF_INET;
    to.sin_port = tcp->dest;

    bytes = sendto(sock, buffer, ntohs(ip->tot_len), 0, (struct sockaddr*) &to,
            sizeof(to));

    if (bytes == -1) {
        perror("sendto() failed");
        return 1;
    }

    recv(sock, buffer, sizeof(buffer), 0);
    printf("TTL= %d\n", ip->ttl);
    printf("Window= %d\n", tcp->window);
    printf("ACK= %d\n", tcp->ack);
    printf("%s:%d\t --> \t%s:%d \tSeq: %d \tAck: %d\n",
                    inet_ntoa(*(struct in_addr*) &ip->saddr), ntohs(tcp->source),
                    inet_ntoa(*(struct in_addr *) &ip->daddr), ntohs(tcp->dest),
                    ntohl(tcp->seq), ntohl(tcp->ack_seq));

    return 0;
}
x4k3p
  • 1,598
  • 2
  • 22
  • 42
  • with incoming packets i mean, there are other incoming from everywhere but not from i need – x4k3p Dec 30 '12 at 04:18
  • 1
    why to parse the packet? i was trying to get some response on a clean unix machine under vmware. when i sended a packet manually, i got what i need. but if i simply wait nothing happens. under real system there are packets comming in. but these are from somewhere else. – x4k3p Dec 30 '12 at 04:30
  • I just re-posted my comments as an actual answer. I hope you don't mind. – jweyrich Dec 30 '12 at 04:49
  • Layer 2 => Data Link? I thought for layer 2 there are packet sockets. In my code I use typecast to access the buffer in the right way. And you don't get my problem. My problem is, that I'am receiving packets. Program works but I'am not receiving an answer to my packet I have send. – x4k3p Dec 30 '12 at 04:53
  • root@***:/********# ./OS_Sniffer 141.28.78.142 – x4k3p Dec 30 '12 at 04:57
  • socket() ok setsockopt() ok Typecasting ok TCP Checksum: 350 Destination : 80 Source: 12345 TTL= 52 Window= 31232 ACK= 1 67.228.168.221:80 --> 67.228.168.221:60806 Seq: -1525233884 Ack: -46020552 – x4k3p Dec 30 '12 at 04:58
  • sorry, typo. It's Layer 3. – jweyrich Dec 30 '12 at 04:58
  • no prob. please look at the output. it works, but wrong :) – x4k3p Dec 30 '12 at 05:00
  • I don't see what's wrong with your output. The negative values? Print them using the unsigned format specifier, `%u`. Other than that, could you highlight? – jweyrich Dec 30 '12 at 05:04
  • 67.228.168.221:80 --> 67.228.168.221:60806 But I need something from 141.28.78.142 – x4k3p Dec 30 '12 at 05:06
  • I'am working with C only for few weeks. Thats why its little bit difficult for me – x4k3p Dec 30 '12 at 05:07
  • Understandable, but you're doing great. Please, take a look at point 4 in my answer. – jweyrich Dec 30 '12 at 05:28

2 Answers2

12
  1. You're receiving and storing packets in buffer, but you're printing data from ip and tcp without parsing that buffer. You should parse the packet from buffer after receiving it, and before printing.
  2. Your code assumes all packets are TCP, which is not the case. RAW sockets only support Layer 3 protocols (IP, ICMP, etc). In other words, using IPPROTO_TCP is misleading when creating a RAW socket. Stick to IPPROTO_IP, and add the necessary conditions to your code for each protocol you care about (TCP, UDP, etc). This happens to be working because the Linux Kernel validates the protocol number, and fallbacks to IPPROTO_IP. However, this might not work in other systems.
  3. Review if your network communication is using the correct byte-order. The network-byte-order is Big-Endian, while the host-byte-order depends on your architecture, so you may need to convert multi-byte fields back and forth.
  4. Your tcp->seq might have an invalid value, because TCP only accepts values up to 65535, while random() returns values from 0 to RAND_MAX (0x7fffffff). Try tcp->seq = htonl(random() % 65535);
  5. Your offset calculation for the TCP header is incorrect. It should be sizeof(struct iphdr) rather than sizeof(struct tcphdr).
jweyrich
  • 31,198
  • 5
  • 66
  • 97
  • Is it even possible to receive TCP or UDP packets with a raw socket? I thought these incoming packets were always passed to the TCP and UDP drivers. – Barmar Dec 30 '12 at 05:08
  • @Barmar it's possible. The kernel delivers a copy of each datagram to every process that has created a RAW socket that matches the datagram protocol. – jweyrich Dec 30 '12 at 05:38
  • Found the error! Its the buffer, because i was sending some rubbish to the remote host. Therefore i could not receive an answer. Correction: char buffer[1024]={0}; – x4k3p Dec 30 '12 at 20:26
  • 3
    Regarding your point 2, trying to use `IPPROTO_IP` results in an error `Protocol not supported` for me, when calling `socket()` on linux. Using either `IPPROTO_TCP` or `IPPROTO_RAW` works, although I didn't check whether it filters TCP packets or not. – Benno Jan 27 '16 at 14:53
  • @jweyrich, ICMP is layer 3? – Pacerier Mar 03 '17 at 23:34
  • @Pacerier yep. It's encapsulated in IPv4/6 packets. It's part of the IP though. – jweyrich Mar 03 '17 at 23:55
1
ip = (struct iphdr*) buffer;
tcp = (struct tcphdr*) (buffer + sizeof(struct tcphdr)); //This is wrong

Here to get array index of tcp header in buffer, you need to add sizeof(struct iphdr) to buffer like mentioned below.

ip = (struct iphdr*) buffer;
tcp = (struct tcphdr*) (buffer + sizeof(struct iphdr)); //This is correct
rashok
  • 12,790
  • 16
  • 88
  • 100