-1

I am trying to write a client/server application using RAW sockets.

There are multiple problems:

  1. When the client sends a message to the server using sendto() method, an error invalid argument is returned by sendto() method. Why this error message?. The corresponding code is marked under the section ERROR 1. The code of sendto() is commented in this post.

  2. Since I have commented the send message part, the client should wait for a message; recvfrom() being a blocking system call. Instead, recvfrom() returns with a message E always. From where did this message arrive?. The corresponding code is marked as ERROR 2.

  3. If I change protocol (3rd) argument in socket() to 0 or IPPROTO_RAW I get Protocol not supported error. Why these errors?

The operating system is Ubuntu.

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>

    #include <sys/socket.h> // For the socket () etc. functions.
    #include <netinet/in.h> // For IPv4 data struct..
    #include <string.h>     // For memset.
    #include <arpa/inet.h>  // For inet_pton ().

    #define BUF_SIZE 30

    void main ()

    {
        int rst; // Return status of functions.
    /**************** Create a socket. *******************************/
    int sfd; // Socket file descriptor.
    sfd = socket (AF_INET, SOCK_RAW, IPPROTO_UDP); /* 
            * AF_INET --> IPv4, SOCK_RAW for Raw socket,  
            * 0 --> for any protocol. */
    if (sfd == -1) 
    {
        perror ("Client: socket error");
        exit (1);
    }


    /*********** Server's address ***********************************/
    struct sockaddr_in srv_addr;
    socklen_t addrlen = sizeof (struct sockaddr_in); 

    // Initializing the server's address to zero.
    memset (&srv_addr, 0, addrlen); 

    srv_addr.sin_family = AF_INET;    // Address is in IPv4 format.
    // srv_addr.sin_port   = htons (0);  // Port number of the server. 


    rst = inet_pton (AF_INET, "127.0.0.1", &srv_addr.sin_addr); /* Note
            * that third field should point to an in_addr (in6_addr). */
    if (rst <= 0)
    {
        perror ("Client Presentation to network address conversion.\n");
        exit (1);
    }        



    /****************** ERROR 1 ************************************
    ******************* Sending message to the server. *************/
    const int flags = 0;
    const char *msg = "Hello";
    /* rst = sendto (sfd, msg, strlen(msg)+1, flags, 
                    (struct sockaddr *) &srv_addr, 
                    sizeof (struct sockaddr_in));
    if (rst < 0)
    {
        perror ("Client: Sendto function call failed");
        exit (1);
    }
    else 
        printf ("Client: Sent data size = %d\n", rst);

    */


    /******************* ERROR 2 ***********************************
     ******************* Receiving message from server. ************/
    // Initializing the server's address to zero.
    memset (&srv_addr, 0, addrlen); 

    char buf[BUF_SIZE] = {'\0'};

    rst = recvfrom (sfd, buf, BUF_SIZE, flags, 
                    (struct sockaddr *) &srv_addr, 
                    &addrlen);
    if (rst < 0)
    {
        perror ("Client: couldn't receive");
        exit (1);
    }
    printf ("Message from server = |%s|\n", buf);

    /* Address of the server. */
    const char *buf2 = inet_ntop (AF_INET, 
                       (struct sockaddr *) &srv_addr, buf, BUF_SIZE);
    if (buf2 == NULL)
    {
        perror ("Client: Conversion of sender's address to presentation failed");
        exit (1);
    }

    printf ("Servers address,  = %s\n", buf2);
    close (sfd);

}
Kulwant Singh
  • 121
  • 2
  • 12
  • Your "ERROR 1" works fine for me. You can run your program with the strace tool and post the output if you need further help in debugging. Keep in mind that raw sockets receive every IP packet your machine receives. Perhaps you're receiving a DNS or SSH packet etc. the 'E' you print out is the 1. byte of the IP header. The 1 byte in an IPv4 packet is 0x45 which is interpreted as an E in ascii. So, keep in mind that since you use RAW sockets, you're receiving also the IP header. If you're using IPPROTO_RAW, you need to create a valid IP header that you send. – nos Feb 05 '16 at 14:50

2 Answers2

1

SOCK_RAW is not for use with UDP. SOCK_DGRAM is correct. For a tutorial, see:

a tutorial from Rutgers

bmargulies
  • 97,814
  • 39
  • 186
  • 310
  • I need to use **RAW sockets**. The **IPPROTO_UDP** needs to be changed to **IPPROTO_RAW**. But as mentioned in **point 3**, it produces _Invalid Protocol_ error. – Kulwant Singh Feb 05 '16 at 13:08
1

edit: overlooked the init of the srv_addr... sorry.

using AF_INET + SOCK_RAW socket you can send anything - the payload is just added on top of the IP-layer. the IPPROTO_UDP just tells the kernel what the next layer will be (the layer your payload is added to) and which value the protocol field of the IP header must be set to. so to stay save (if you go to send raw data) set the protocol to something not commonly used).

you need the permission to create a raw socket. this commonly means: start as root, create the socket and then drop the privileges.

q2: this is the message you send to yourself (and a strong indication that your code somehow worked). The 'E' is just the first byte (0x45) in the IP-header - version 4 and header length 5. just dump the whole buffer..., eg.

printf ("Message from server = |");
    for (i = 0; i < rst; i++)
        printf("%c", isprint(buf[i]) ? buf[i] : '?') ;
printf ("|\n");

q3:

0 means: guess what is usually used (eg. INET + DGRAM -> TCP). As you specified raw the kernel is not able to choose a common protocol for the next layer.

IPPROTO_RAW should work (see comment of @nos)

hecke
  • 236
  • 1
  • 6
  • 1
    socket(AF_INET, SOCK_RAW, IPPROTO_RAW) should work , it just moves you a layer down, as documented [here](http://manpages.ubuntu.com/manpages/wily/en/man7/raw.7.html) – nos Feb 05 '16 at 14:45