-1

I am using raw sockets to send datagrams as given in this tutorial (section III). However, I am unable to print the response properly (showing junk characters). Not sure what is wrong with the program. Anyone able to identify the error?

#define P 80        /* TCP port 80 - HTTP */

unsigned short /* this function generates header checksums */
csum(unsigned short *buf, int nwords)
{
    //checksum code here, omitting for stackoverflow question
}

int main()
{
    int s = socket(PF_INET, SOCK_RAW, IPPROTO_TCP); /* open raw socket */
    char datagram[4096]; /* this buffer will contain ip header, tcp header,
     and payload. we'll point an ip header structure
     at its beginning, and a tcp header structure after
     that to write the header values into it */
    struct ip *iph = (struct ip *) datagram;
    struct tcphdr *tcph = (struct tcphdr *) datagram + sizeof(struct ip);
    struct sockaddr_in sin;
    /* the sockaddr_in containing the dest. address is used
     in sendto() to determine the datagrams path */

    sin.sin_family = AF_INET;
    sin.sin_port = htons(P);/* you byte-order >1byte header values to network
     byte order (not needed on big endian machines) */
    sin.sin_addr.s_addr = inet_addr("74.125.224.72"); //google's ip address

    memset(datagram, 0, 4096); /* zero out the buffer */

    /* we'll now fill in the ip/tcp header values, see above for explanations */
    iph->ip_hl = 5;
    iph->ip_v = 4;
    iph->ip_tos = 0;
    iph->ip_len = sizeof(struct ip) + sizeof(struct tcphdr); /* no payload */
    iph->ip_id = htonl(54321); /* the value doesn't matter here */
    iph->ip_off = 0;
    iph->ip_ttl = 255;
    iph->ip_p = 6;
    iph->ip_sum = 0; /* set it to 0 before computing the actual checksum later */
    iph->ip_src.s_addr = inet_addr("1.2.3.4");/* SYN's can be blindly spoofed */
    iph->ip_dst.s_addr = sin.sin_addr.s_addr;
    tcph->th_sport = htons(1234); /* arbitrary port */
    tcph->th_dport = htons(P);
    tcph->th_seq = random();/* in a SYN packet, the sequence is a random */
    tcph->th_ack = 0;/* number, and the ack sequence is 0 in the 1st packet */
    tcph->th_x2 = 0;
    tcph->th_off = 0; /* first and only tcp segment */
    tcph->th_flags = TH_SYN; /* initial connection request */
    tcph->th_win = htonl(65535); /* maximum allowed window size */
    tcph->th_sum = 0;/* if you set a checksum to zero, your kernel's IP stack
     should fill in the correct checksum during transmission */
    tcph->th_urp = 0;

    iph->ip_sum = csum((unsigned short *) datagram, iph->ip_len >> 1);

    /* finally, it is very advisable to do a IP_HDRINCL call, to make sure
     that the kernel knows the header is included in the data, and doesn't
     insert its own header into the packet before our data */
    int one = 1;
    const int *val = &one;
    if (setsockopt(s, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0)
        printf("Warning: Cannot set HDRINCL!\n");

    if (sendto(s,datagram,iph->ip_len,0,(struct sockaddr *) &sin, sizeof(sin)) < 0) 
        printf("error\n");
    else
        printf(".\n\n");

    sleep(2); // giving enough time to receive response

    char buffer[8192]; /* single packets are usually not bigger than 8192 bytes */
    memset(buffer, 0, 8192); /* zero out the buffer */
    while (recv(s, buffer, 8192, 0) > 0)
        printf("Caught tcp packet: %s\n", buffer + sizeof(struct iphdr) + sizeof(struct tcphdr));

    close(s);
    return 0;
}

The output I am getting is shown in this image: https://i.stack.imgur.com/4MfLg.jpg

bbastu
  • 508
  • 3
  • 10
sam
  • 95
  • 1
  • 1
  • 12
  • 1
    First of all, use tools such as [Wireshark](http://www.wireshark.org/) to see what's happening on the network. Secondly, it looks like you are trying to [establish a connection](http://en.wikipedia.org/wiki/Transmission_Control_Protocol#Connection_establishment) in which case you will not get a reply back with any data. And you don't even check *if* you get a reply back with data, you just print the "data" anyway. – Some programmer dude Nov 23 '14 at 03:57
  • I think the program will print only when some data is received with `recv()` function. Since it is a SYN packet, I think server should send an ACK. – sam Nov 23 '14 at 04:00
  • Since you are working with raw socket, the packets you get receive will contain the IP and TCP headers, and those will be counted in the size returned. – Some programmer dude Nov 23 '14 at 04:04
  • You mean: there won't be any payload in server's response? – sam Nov 23 '14 at 04:08
  • 1
    If you send a `SYN` packet, you should receive a `ACK+SYN` (or a `RST`) back, and that packet will not have any payload. – Some programmer dude Nov 23 '14 at 04:09

3 Answers3

0

Try changing:

printf("Caught tcp packet: %s\n", buffer + sizeof(struct iphdr) + sizeof(struct tcphdr));

to:

printf("Caught tcp packet: %s\n", buffer);
Pang
  • 9,564
  • 146
  • 81
  • 122
Davinder
  • 5,107
  • 1
  • 11
  • 8
0
while (recv(s, buffer, 8192, 0) > 0)
    printf("Caught tcp packet: %s\n", buffer + sizeof(struct iphdr) + sizeof(struct tcphdr));

It is never correct not to store the result of recv() in a variable. You need to test it for zero and -1 and otherwise to use it as the length of the data received. Try this:

int count;
while ((count = recv(s, buffer, sizeof buffer, 0)) > 0)
    printf("Caught tcp packet: %.*s\n", count - sizeof(struct iphdr) - sizeof(struct tcphdr, buffer + sizeof(struct iphdr) + sizeof(struct tcphdr));
if (count < 0)
    perror("recv");

EDIT You seem to be trying to print the contents of a SYN-ACK packet. There aren't any.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • Thanks EJP, but I am still receiving similar "junk characters" with your code too. – sam Nov 23 '14 at 03:56
  • 2
    That's because `count` is the raw number of bytes received, not the number of characters to print. You never wrote any code to sanely receive the data and arrange to have it printed. You're expecting it to work by magic. – David Schwartz Nov 23 '14 at 04:17
  • @sam See edit. But all this follows your assumption that the data actually is printable. – user207421 Nov 23 '14 at 04:57
0

You need to use the libpcap library to retrieve the packet from the link layer .

jps
  • 173
  • 1
  • 13