I'm writing a program that would check if a port on given url or ip is open or not. In order to obtain the ip adress of given url, I'm using gethostbyname()
. When trying to look up the address of localhost it returns the correct value, however, trying to look up the address of a remote host it usually fails and returns an ip address with negative numbers. For example:
/test.out google.com
ip: -40.58.-42.78
/test.out reddit.com
ip: -105.101.-127.-116
./test.out facebook.com
ip: 31.13.84.36
Weirdly, the last one works. Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
int main(int argc, char **argv)
{
struct hostent *he;
struct in_addr **addr_list;
if ((he = gethostbyname(argv[1])) == NULL) {
herror("gethostbyname");
return 1;
}
printf("ip: ");
for (int i = 0; i < he->h_length; i++) {
printf("%d", he->h_addr_list[0][i]);
if (i != he->h_length - 1) printf(".");
}
printf("\n");
}
Also, why is the type of h_addr_list
char **
? Shouldn't it be an integer, or even better an unsigned one?
The components of an IP address are unsigned bytes but, in a struct hostent
they are stored as char
(i.e. signed). This means the values 128
..255
are interpreted as negative numbers.
You print them using the %d
format that prints the values as signed because this is how it receives them. Convert the values to unsigned char
(or unsigned int
if you prefer) when you pass them to printf()
:
printf("%d", (unsigned char)he->h_addr_list[0][i]);
You can also use %u
instead of %d
(it treats as unsigned
the values it receives), but you still need to convert the values to pass to it to unsigned
1:
printf("%u", (unsigned char)he->h_addr_list[0][i]);
Another option is to force printf()
use only the least significant byte of the value it gets and print it as unsigned, using "%hhu"
. However, this looks more like a hack than the correct solution.
1 Without the conversion, because printf()
is a variadic function, the values passed to it as arguments (he->h_addr_list[0][i]
) are promoted from (signed) char
to (signed) int
. Using "%u"
to print them produces very large numbers instead of negative numbers for the components that are larger than 127
.