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 :
kali@kali:~/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.
CodePudding user response:
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.