[SOLVED] C language : gethostbyaddr() return : Operation not permitted

Issue

Currently i’m trying to make a ping-like program and it work pretty good but i’ve a probleme on the DNS_lookup()

Here is my function :

char *DNS_reverse_lookup(struct sockaddr_in *host_addr)
{
    if (host_addr == NULL)
    {
        printf("host_addr is empty.\n");
        return NULL;
    }

    struct hostent *host_info = NULL;
    host_info = gethostbyaddr(&host_addr->sin_addr.s_addr, sizeof(*host_addr), host_addr->sin_family);
    if (host_info == NULL)
    {
        printf("%s:%d : gethostbyaddr() failed : %s\n", __FILE__, __LINE__, strerror(h_errno));
        return NULL;
    }

    return host_info->h_name;
}

Here the gethostbyaddr() return Operation not permitted for some domain for exemple for google.com but for my ovh server it return the expected result and i don’t know why

someone can explain ?

Here’s all of my code :

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

#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <netinet/ip_icmp.h>
#include <signal.h>
#include <ifaddrs.h>

#include "globaldata/gd.h"
#include "netsocket/netsocket.h"

// packet size
#define PING_PKT_S 64

// Automatic port number
#define PORT_NB 0

#define PING_SLEEP_RATE 1000000

// Give the timeout delay for receiving packets
// In seconds
#define RECV_TIMEOUT 2

struct icmp_pkt {
    struct icmphdr header;
    char msg[PING_PKT_S - sizeof(struct icmphdr)];
};

void sigintHandler(int sig_num);
unsigned short checksum(void *b, int len);
struct sockaddr_in *DNS_lookup(char *host_domain_name);
char *DNS_reverse_lookup(struct sockaddr_in *host_addr);
void send_ping(Socket_t *socket, char *ping_ip, char *host_domain_name);

GlobalData gd;

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

    // information about the host
    struct sockaddr_in *host_addr = NULL;
    socklen_t host_addr_len = sizeof(*host_addr);
    Socket_t *socket = NULL;
    char *host_domain_name;
    int opt_value = 0, i = 0;
    FILE *socket_file = NULL;
    int arg_port = 0;
    int port = 0;
    struct ifaddrs *ifaces;
    struct ifaddrs *tmp = NULL;

    /* Allocation */

    socket = SOCKET_New();

    /* Initialisation */

    // Correct syntax
    if (argc < 2)
    {
        printf("\nFormat %s <address>\n", argv[0]);
        goto FatalError;
    }

    for (i = 0 ; argv[i] != 0 ; i++)
    {
        if (strcmp(argv[i], "-p") == 0)
        {
            arg_port = i;
        }
    }

    if (arg_port)
    {
        port = atoi(argv[arg_port+1]);
        printf("port = %d\n", port);
    }

    // loop while the ping is performed
    gd.ping_loop = 1;

    // Open socket
    if (SOCKET_OpenSocket(socket, AF_INET, SOCK_RAW, IPPROTO_ICMP) == NULL)
    {
        printf("SOCKET_OpenSocket() failed.\n");
        goto FatalError;
    }

    opt_value = 1;
    if (setsockopt(socket->sockfd, SOL_SOCKET, SO_REUSEADDR, &opt_value, sizeof(opt_value)) == -1)
    {
        printf("setsockopt() failed : %s\n", strerror(errno));
    }

    if (SOCKET_SetAddr(socket, inet_addr(argv[1]), AF_INET, port, 5) == NULL)
    {
        printf("SOCKET_SetAddr() failed?\n");
        goto FatalError;
    }



    // Get host domain name (if there is)
    host_domain_name = DNS_reverse_lookup(&socket->addr);
    if (host_domain_name == NULL)
    {
        printf("DNS_reverse_lookup() failed.\n");
        host_domain_name = 0;
        // goto FatalError;
    }
    printf("host domain name = %s (%s)\n", host_domain_name, argv[1]);

    // printf("\nsockaddr :\nIP = %x\nPort = %d\nFamily = %d\n", socket->addr.sin_addr.s_addr, socket->addr.sin_port, socket->addr.sin_family);
    // if (SOCKET_BindToSocket(socket) == NULL)
    // {
    //     printf("SOCKET_BindToSocket() failed.\n");
    //     goto FatalError;
    // }

    // handle interrupt signal
    signal(SIGINT, sigintHandler); 

    send_ping(socket, argv[1], host_domain_name);

    /* Leave */

    if (socket != NULL)
    {
        if (socket->sockfd > 0)
        {
            shutdown(socket->sockfd, SHUT_RDWR);
            close(socket->sockfd);
            printf("\nsocket closed.\n");
        }
        socket = SOCKET_Free(socket);
    }

    printf("Terminated : Without Error.\n");
    return EXIT_SUCCESS;

FatalError:

    if (socket != NULL)
    {
        if (socket->sockfd > 0)
        {
            shutdown(socket->sockfd, SHUT_RDWR);
            close(socket->sockfd);
            printf("\nsocket closed.\n");
        }
        socket = SOCKET_Free(socket);
    }


    printf("Terminated : Fatal Error.\n");
    return EXIT_FAILURE;
}

void sigintHandler(int sig_num)
{
    gd.ping_loop = 0;
}

unsigned short checksum(void *b, int len)
{
    unsigned short *buf = b;
    unsigned int sum = 0;
    unsigned short result;

    for (sum = 0 ; len > 1 ; len -= 2)
    {
        sum += *buf++;
    }

    if (len == 1)
    {
        sum += *(unsigned char *)buf;
    }
    sum = (sum >> 16) + (sum & 0xFFFF);
    sum += (sum >> 16);
    result = ~sum;

    return result;
}

// Return struct sockaddr_in *ptr on success or 0 on error
struct sockaddr_in *DNS_lookup(char *host_domain_name)
{
    printf("\nResolving DNS...\n");

    // store host info in struct hostent
    struct hostent *host_info = NULL;
    static struct sockaddr_in host_addr;
    memset(&host_addr, 0, sizeof(host_addr));

    if ((host_info = gethostbyname(host_domain_name)) == NULL)
    {
        printf("%s:%d : gethostbyname() failed %s\n", __FILE__, __LINE__, strerror(h_errno));
        return NULL;
    }

    host_addr.sin_addr.s_addr = inet_addr(host_info->h_addr_list[0]);
    host_addr.sin_family = host_info->h_addrtype;
    host_addr.sin_port = htons(PORT_NB);

    printf("Resolved.\n\n");

    return &host_addr;
}

// Return char *host_domain_name on success or 0 on error
char *DNS_reverse_lookup(struct sockaddr_in *host_addr)
{
    if (host_addr == NULL)
    {
        printf("host_addr is empty.\n");
        return NULL;
    }

    struct hostent *host_info = NULL;
    host_info = gethostbyaddr(&host_addr->sin_addr.s_addr, sizeof(*host_addr), host_addr->sin_family);
    if (host_info == NULL)
    {
        printf("%s:%d : gethostbyaddr() failed : %s\n", __FILE__, __LINE__, strerror(h_errno));
        return NULL;
    }

    return host_info->h_name;
}

void send_ping(Socket_t *socket, char *ping_ip, char *host_domain_name)
{
    if (socket == NULL)
    {
        printf("%s:%d : Bad socket.\n", __FILE__, __LINE__);
        return;
    }
    if (socket->sockfd <= 0)
    {
        printf("%s:%d : Bad socket file descriptor.\n", __FILE__, __LINE__);
    }

    int ttl_value, msg_count, i, addr_len, flag, msg_received_count;
    struct icmp_pkt packet;
    struct sockaddr_in r_addr;

    long double rtt_msec, total_msec;
    struct timespec time_start, time_end, tfs, tfe;
    struct timeval tv_out;
    tv_out.tv_sec = RECV_TIMEOUT;
    tv_out.tv_usec = 0;

    ttl_value = 64;
    msg_count = 0;
    i = 0;
    addr_len = 0;
    flag = 1;
    msg_received_count = 0;
    rtt_msec = total_msec = 0.0;

    // time start
    clock_gettime(CLOCK_MONOTONIC, &tfs);

    // SOL = Set Option Level
    // SO = Set Option
    // Set time to live value
    if (setsockopt(socket->sockfd, SOL_IP, IP_TTL, &ttl_value, sizeof(ttl_value)) == -1)
    {
        printf("%s:%d : setsockopt() failed : %s\n", __FILE__, __LINE__, strerror(errno));
        return;
    }
    printf("Socket set to TTL : %d\n", ttl_value);

    // Set timeout of receiving setting
    if (setsockopt(socket->sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv_out, sizeof(tv_out)) == -1)
    {
        printf("%s:%d : setsockopt() failed : %s\n", __FILE__, __LINE__, strerror(errno));
        return;
    }

    printf("Ping to %s (%s).\n", host_domain_name, ping_ip);

    while (gd.ping_loop)
    {
        // flag is whether packet was sent or not
        flag = 1;

        // filling packet
        memset(&packet, 0, sizeof(packet));

        packet.header.type = ICMP_ECHO;
        packet.header.un.echo.id = getpid();

        for (i = 0 ; i < sizeof(packet.msg) ; i++)
        {
            packet.msg[i] = '\0';
        }

        char message[] = "Anything";
        strncpy(packet.msg, message, strlen(message));

        packet.header.un.echo.sequence = msg_count++;
        packet.header.checksum = checksum(&packet, sizeof(packet));

        usleep(PING_SLEEP_RATE);

        // send packet
        clock_gettime(CLOCK_MONOTONIC, &time_start);
        // if (write(socket->sockfd, &packet, sizeof(packet)) == -1)
        // {
        //     printf("%s:%d : write() failed : %s\n", __FILE__, __LINE__, strerror(errno));
        //     flag = 0;
        // }

        if (sendto(socket->sockfd, &packet, sizeof(packet), 0, (struct sockaddr *)&socket->addr, socket->addr_len) == -1)
        {
            printf("%s:%d : sento() failed : %s\n", __FILE__, __LINE__, strerror(errno));
            return;
        }

        // receiving packet

        // printf("reading packet...\n");
        // if (read(socket->sockfd, &packet, sizeof(packet)) == -1 && msg_count > 1)
        // {
        //     printf("%s:%d : read() failed : %s\n", __FILE__, __LINE__, strerror(errno));
        //     flag = 0;
        // }
        if (recvfrom(socket->sockfd, &packet, sizeof(packet), 0, (struct sockaddr *)&socket->addr, &socket->addr_len) == -1)
        {
            printf("%s:%d : recvfrom() failed : %s\n", __FILE__, __LINE__, strerror(errno));
            return;
        }

        else
        {
            clock_gettime(CLOCK_MONOTONIC, &time_end);

            double time_elapsed = ((double)time_end.tv_nsec - (double)time_start.tv_nsec) / 1000000.0;
            printf("time elapsed = %.4f\n", time_elapsed);

            rtt_msec = (double)(time_end.tv_sec - time_start.tv_sec) * 1000.0 + time_elapsed;

            // case packet wasn't sent or received
            if (!flag)
            {
                printf("%s:%d : ERROR : Packet received with ICMP type %d code %d\n", __FILE__, __LINE__, packet.header.type, packet.header.code);
            }else{
                printf("%d bytes from %d (h: %s) (%s) msg_seq=%d ttl=%d rtt = %Lf ms.\n", PING_PKT_S, socket->addr.sin_family, host_domain_name, ping_ip, msg_count, ttl_value, rtt_msec);
                msg_received_count++;
            }
        }
    }

    clock_gettime(CLOCK_MONOTONIC, &tfe);
    double time_elapsed = ((double)(tfe.tv_nsec - tfs.tv_nsec)) / 1000000.0;
    total_msec = (tfe.tv_sec - tfs.tv_sec) * 1000 + time_elapsed;

    printf("\n===%s ping statistics===\n", ping_ip);
    printf("\n%d packets sent, %d packets received, %f percent packet loss. Total time: %Lf ms.\n\n", msg_count, msg_received_count, (double)((msg_count - msg_received_count)/msg_count) * 100.0, total_msec); 

}

terminal exec :

[email protected]:~/Code/Network/Ping$ sudo ./pingto 151.101.65.69
main.c:232 : gethostbyaddr() failed : Operation not permitted
DNS_reverse_lookup() failed.
host domain name = (null) (151.101.65.69)
Socket set to TTL : 64
Ping to (null) (151.101.65.69).
time elapsed = 8.1787
64 bytes from 2 (h: (null)) (151.101.65.69) msg_seq=1 ttl=64 rtt = 8.178748 ms.
time elapsed = 7.9054
64 bytes from 2 (h: (null)) (151.101.65.69) msg_seq=2 ttl=64 rtt = 7.905438 ms.
time elapsed = 8.2425
64 bytes from 2 (h: (null)) (151.101.65.69) msg_seq=3 ttl=64 rtt = 8.242489 ms.
^Ctime elapsed = 7.9805
64 bytes from 2 (h: (null)) (151.101.65.69) msg_seq=4 ttl=64 rtt = 7.980547 ms.

===151.101.65.69 ping statistics===

4 packets sent, 4 packets received, 0.000000 percent packet loss. Total time: 3494.951433 ms.


socket closed.
Terminated : Without Error.


Solution

You’re not decoding the error code properly.

The values of h_errno do not correspond to the values that errno correspond to, so you can’t use strerror to get the error text.

There is a function called hstrerror that does the same as strerror but for error codes returned by gethostbyname and other related functions.

The error codes listed in the man page are as follows:

   HOST_NOT_FOUND
          The specified host is unknown.

   NO_ADDRESS or NO_DATA
          The requested name is valid but does not have an IP address.

   NO_RECOVERY
          A nonrecoverable name server error occurred.

   TRY_AGAIN
          A temporary error occurred on an authoritative name server.  Try
          again later.

The "operation not permitted" code is EPERM, which on my system is 1. That code corresponds on my system to HOST_NOT_FOUND, so assuming your error codes are the same that’s the actual error you’re seeing.

Answered By – dbush

Answer Checked By – Terry (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published.