6

I have the following piece of code for getting the hostname and IP address,

#include <stdlib.h>
#include <stdio.h>
#include <netdb.h> /* This is the header file needed for gethostbyname() */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>


int main(int argc, char *argv[])
{
struct hostent *he;

if (argc!=2){
printf("Usage: %s <hostname>\n",argv[0]);
exit(-1);
}

if ((he=gethostbyname(argv[1]))==NULL){
printf("gethostbyname() error\n");
exit(-1);
}

printf("Hostname : %s\n",he->h_name); /* prints the hostname */
printf("IP Address: %s\n",inet_ntoa(*((struct in_addr *)he->h_addr))); /* prints IP address */
}

But I am getting a warning during compilation:

$cc host.c -o host
host.c: In function ‘main’:
host.c:24: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int’

Then there is a segmentation fault when I run the code:

./host 192.168.1.4
Hostname : 192.168.1.4
Segmentation fault

What is the error in the code?

Gilles 'SO- stop being evil'
  • 104,111
  • 38
  • 209
  • 254
Biranchi
  • 16,120
  • 23
  • 124
  • 161
  • 4
    You're doing something horrible to an innocent struct. – SLaks May 25 '10 at 17:25
  • By the way, you should generally not use `gethostbyname` in new code, mainly since it is not compatible with IPv6. You should use `getaddrinfo` instead: http://beej.us/guide/bgnet/output/html/multipage/getaddrinfoman.html – Tyler McHenry May 25 '10 at 17:30
  • What happens if you run ./host www.stackoverflow.com ? That is, if you use it with an actual name rather than an IP address. – nsayer May 25 '10 at 17:33
  • @nsayer It is working $ ./host www.stackoverflow.com Hostname : stackoverflow.com IP Address: 69.59.196.211 – Biranchi May 25 '10 at 17:44

5 Answers5

8

I had a similar code (if not the same) and it compiled fine in a machine in our school laboratory, but when I compiled it on my machine at home, it had the same error (I didn't edit the code). I read the man page for inet, and found that I had one header file missing, which is the #include <arpa/inet.h>. After I added that header to my C program, it compiled and run fine.

Flexo
  • 87,323
  • 22
  • 191
  • 272
ivan storm
  • 81
  • 1
  • 1
6

The warning about the mismatch for the printf format is an important warning. In this case, it comes because the compiler is thinking that the function inet_ntoa returns an int, but you specified to expect a string in the format-string.

The incorrect return-type for inet_ntoa is the result of an old C rule that states that if you try to use a function without a prior declaration, then the compiler must assume the function returns an int and takes an unknown (but fixed) number of arguments. The mismatch between the assumed return type and the actual return type of the function results in undefined behaviour, which manifests itself as a crash in your case.

The solution is to include the correct header for inet_ntoa.

Bart van Ingen Schenau
  • 15,488
  • 4
  • 32
  • 41
1

Break this code:

printf("IP Address: %s\n",inet_ntoa(*((struct in_addr *)he->h_addr)));

Into this:

struct in_addr* address = (in_addr*) he->h_addr;
char* ip_address = inet_ntoa(*address);
printf("IP address: %s\n", ip_address);

It also makes it easier to debug and pinpoint the problem.

karlphillip
  • 92,053
  • 36
  • 243
  • 426
0

Actually, I just compiled that code on my FreeBSD machine at home and it works.

nsayer
  • 16,925
  • 3
  • 33
  • 51
0

You could try dumping the value of he->h_addr before trying to dereference it and pass it to inet_ntoa. If it was NULL, that would result in a seg fault.

How about running it through strace?

tomlogic
  • 11,489
  • 3
  • 33
  • 59