How gethostbyname() or getnameinfo() work in background?
#include <stdlib.h>
#include <stdio.h>
#include <netdb.h>
/* paddr: print the IP address in a standard decimal dotted format */
void
paddr(unsigned char *a)
{
printf("%d.%d.%d.%d\n", a[0], a[1], a[2], a[3]);
}
main(int argc, char **argv) {
struct hostent *hp;
char *host = "google.com";
int i;
hp = gethostbyname(host);
if (!hp) {
fprintf(stderr, "could not obtain address of %s\n", host);
return 0;
}
for (i=0; hp->h_addr_list[i] != 0; i++)
paddr((unsigned char*) hp->h_addr_list[i]);
exit(0);
}
output for google.com:
74.125.236.198
74.125.236.199
74.125.236.206
74.125.236.201
74.125.236.200
74.125.236.196
74.125.236.193
74.125.236.197
74.125.236.194
74.125.236.195
74.125.236.192
output for www.google.com:
74.125.236.210
74.125.236.209
74.125.236.212
74.125.236.208
74.125.236.211
Will the above program do a check in the internet to resolve into IP?
Why its showing less IP addresses for www.google.com and more for just google.com?
On a Linux system the gethostbyname() call implemented in the glibc performs lookups according to the configuration files /etc/host.conf and /etc/nsswitch.conf.
Typically in a default configuration it will first look in the /etc/hosts file if a local entry for the given name exists and if so, returns that. Otherwise it will proceed with the DNS protocol that is in turn configured by /etc/resolv.conf where the nameservers are stated.
Much more complex setups can be configured that lookup LDAP servers, databases etc.
You can also look into some man pages like man 5 nsswitch.conf.
Related
I am new to internet programming, and I am trying to use the gethostbyname() function. When I input a string such as "www.yahoo.com" to gethostbyname function it works fine, but when I input a char array, it will always return an empty buffer.
char hostname[100];
struct hostent* h;
gethostname(hostname, sizeof hostname );
printf("Hostname: %s\n", hostname);
h = gethostbyname(hostname);
Any idea how to solve this?
Your server can't resolve itself. The most common way of "fixing" this is to put its own name into its hostfile. While this is a good idea for various reasons, the underlying problem really should be fixed.
The DNS search list should normally be set to the domainname that contains the hostname -or- the hostname should be fully qualified itself.
DNS should be correctly set up for the host.
This makes it not really a C problem at all, but a server configuration problem. Off it goes then.
WSADATA wsaData;
int error;
if ((error = WSAStartup(MAKEWORD(1, 1), &wsaData)) !=0)
{
printf("Error %d in WSAStartup, result will fail\n",error);
}
char hostname[100];
struct hostent* h;
gethostname(hostname, sizeof hostname );
printf("Hostname: %s\n", hostname);
h = gethostbyname(hostname);
In the linux programmers manual the function has the following declaration:
struct hostent *gethostbyname(const char *name);
This means the parameter must be a char array (or string in layman terms). A quoted string such as "yahoo.com" can be used directly when calling the function.
The following code is a working example on how gethostbyname works:
#include <stdio.h>
#include <string.h>
#include <netdb.h>
int main(){
struct hostent* h=gethostbyname("yahoo.com");
printf("Hostname: %s\n", h->h_name);
printf("Address type #: %d\n", h->h_addrtype);
printf("Address length: %d\n", h->h_length);
char text[50]; // allocate 50 bytes (a.k.a. char array)
strcpy(text,"bing.ca"); //copy string "bing.ca" to first 7 bytes of the array
h=gethostbyname(text); //plug in the value into the function. text="bing.ca"
printf("Hostname: %s\n", h->h_name);
printf("Address type #: %d\n", h->h_addrtype);
printf("Address length: %d\n", h->h_length);
return 0;
}
I called it twice. Once for yahoo.com and once for bing.ca and I retrieved the hostname, the address type number and the address length (which is the number of bytes required to store the IP).
For calling the bing address, I allocated a char array, filled it with a string then passed that char array as a parameter to the function.
One good reason why it's returning NULL is because the hostname what you are passing is not correct.
Sometimes even doing hostname -v will not give the correct host name.
Try following:
cat /etc/hosts
this will show you output as:
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain
That 'localhost' next to 127.0.0.1 in the output above is your host name. This will work perfectly with gethostbyname.
In a C program in UNIX, gethostbyname() can be used to obtain the address of domain like "localhost". How does one convert the result from gethostbyname() to dotted decimal notation.
struct hostent* pHostInfo;
long nHostAddress;
/* get IP address from name */
pHostInfo=gethostbyname("localhost");
if(!pHostInfo){
printf("Could not resolve host name\n");
return 0;
}
/* copy address into long */
memset(&nHostAddress, 0, sizeof(nHostAddress));
memcpy(&nHostAddress,pHostInfo->h_addr,pHostInfo->h_length);
nHostAddress contains the following:
16777243
How do I convert the result so that I can get the output as :
127.0.0.1
It is easy Just Compile This Code
#include<stdio.h>
#include<netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main()
{
struct hostent *ghbn=gethostbyname("www.kamonesium.in");//change the domain name
if (ghbn) {
printf("Host Name->%s\n", ghbn->h_name);
printf("IP ADDRESS->%s\n",inet_ntoa(*(struct in_addr *)ghbn->h_name) );
}
}
You can convert from a struct in_addr directly to a string using inet_ntoa():
char *address = inet_ntoa(pHostInfo->h_addr);
The value you've got (16777243) looks wrong, though -- that comes out to 1.0.0.27!
The inet_ntoa() API does what you're looking for, but is apparently deprecated:
https://beej.us/guide/bgnet/html/multi/inet_ntoaman.html
If you want something more future-proof-IPV6ish, there's inet_ntop():
https://beej.us/guide/bgnet/html/multi/inet_ntopman.html
The variable "h_name" in the last statement needs to change as "h_addr" shown in follows:
printf("IP ADDRESS->%s\n",inet_ntoa(*(struct in_addr *)ghbn->h_addr) );
Following example code from the libpcap documentation yields the following code which should report the IP address of the given interface (eth0 in this case) [Error checking omitted for brevity]
#include <stdio.h>
#include <pcap.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
char errbuf[PCAP_ERRBUF_SIZE];
bpf_u_int32 mask;
bpf_u_int32 ip;
struct in_addr ip_addr;
/* Find the properties for the device */
pcap_lookupnet("eth0", &ip, &mask, errbuf);
ip_addr.s_addr = ip;
printf("IP Address: %s\n", inet_ntoa(ip_addr));
return 0;
}
However, this results in 192.168.1.0, rather than the correct 192.168.1.100. Running this on a different machine on a different subnet yields 10.0.0.0 rather than the correct 10.0.0.107 which leads me to believe libpcap is not copying the last octet correctly. I've manually converted the integer returned by pcap_lookupnet to ensure it's not an issue with the use of inet_ntoa (I've also tried inet_ntop, with identical results). Following the code from this question:
Get IP address of an interface on Linux
reports the correct IP address. Is this a bug in libpcap or am I doing something wrong?
Your statement "which should report the IP address of the given interface" is incorrect.
From the manpage:
pcap_lookupnet() is used to determine the IPv4 network number and
mask
associated with the network device device. Both netp and maskp are
bpf_u_int32 pointers.
are you sure you have a network number of 10.0.0.107 or 192.168.1.100 respectively? Sounds rather unusual.
is there a way to get the IP number from gethostname()?
We are randomly generating IP addresses for the computers in the lab we are in. We use gethostbyname(<random ip>) to get the IP of a computer.
What we want to do essentially is compare the ip that we get from gethostbyname() with what we get from gethostname().
We tried:
struct hostent* host;
char temp[MAX_LEN];
gethostname(temp, MAX_LEN);
host = gethostbyname(<random ip address>)
if(host->h_name == temp) printf("They are the same\n");
The problem is, is that host->h_name is '172.125.45.1' (i made that
up) and temp is 'u-my_comp'
so we cant compare the strings cause one gives us the name of the computer (u-my_comp), and the other gives the ip...
Is there anyway to make these functions return the same type of value?
we have tried doing something like
gethostname(temp, 24)
temp_host = gethostbyname(temp)
in hopes that now we could compare temp_host->h_name with host->h_name...but yeah, that didnt work either.
Any ideas?
thanks!
gethostbyname() is for converting a hostname into a socket address. If the "hostname" you supply is a dotted-quad IPv4 address, that will be all you get in the h_name parameter of the result.
To convert a socket address back into a name what you want is the companion function gethostbyaddr() - except that you don't, because both gethostbyname() and gethostbyaddr() are deprecated. Instead, you should be using getaddrinfo() and getnameinfo().
For example:
#include <stdio.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main()
{
struct sockaddr_in sa;
char host[1024];
int gni_err;
sa.sin_family = AF_INET;
sa.sin_port = 0;
sa.sin_addr.s_addr = inet_addr("127.0.0.1");
gni_err = getnameinfo((struct sockaddr *)&sa, sizeof sa, host, sizeof host, NULL, 0, NI_NAMEREQD | NI_NOFQDN);
if (gni_err == 0) {
printf("host is: %s\n", host);
} else {
fprintf(stderr, "Error looking up host: %s\n", gai_strerror(gni_err));
}
return 0;
}
If you call:
myhost = gethostbyname(temp);
(having allocated myhost) then you will have two hostent structures you will compare - you will have the IP address lists for both the target query host and the current host (not just the hostname for the current host).
I think there is no way to enumerate each network interface on my system and their assigned IP address using just sockets. Is this correct?
I mean, in Linux this could be:
eth0: 192.168.1.5
wlan0: 192.168.0.5
lo: 127.0.0.1
I don't care about interface names, just the IP addresses assigned.
I recall to have done this in the past in Windows, using Win32 (though I don't remember how). But is there a method to do this in a portable way?
Here's a good start:
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <stdio.h>
void
print_sockaddr(struct sockaddr* addr,const char *name)
{
char addrbuf[128] ;
addrbuf[0] = 0;
if(addr->sa_family == AF_UNSPEC)
return;
switch(addr->sa_family) {
case AF_INET:
inet_ntop(addr->sa_family,&((struct sockaddr_in*)addr)->sin_addr,addrbuf,sizeof(addrbuf));
break;
case AF_INET6:
inet_ntop(addr->sa_family,&((struct sockaddr_in6*)addr)->sin6_addr,addrbuf,sizeof(addrbuf));
break;
default:
sprintf(addrbuf,"Unknown (%d)",(int)addr->sa_family);
break;
}
printf("%-16s %s\n",name,addrbuf);
}
void
print_ifaddr(struct ifaddrs *addr)
{
char addrbuf[128] ;
addrbuf[0] = 0;
printf("%-16s %s\n","Name",addr->ifa_name);
if(addr->ifa_addr != NULL)
print_sockaddr(addr->ifa_addr,"Address");
if(addr->ifa_netmask != NULL)
print_sockaddr(addr->ifa_netmask,"Netmask");
if(addr->ifa_broadaddr != NULL)
print_sockaddr(addr->ifa_broadaddr,"Broadcast addr.");
if(addr->ifa_dstaddr != NULL)
print_sockaddr(addr->ifa_dstaddr,"Peer addr.");
puts("");
}
int main(int argc,char *argv[])
{
struct ifaddrs *addrs,*tmp;
if(getifaddrs(&addrs) != 0) {
perror("getifaddrs");
return 1;
}
for(tmp = addrs; tmp ; tmp = tmp->ifa_next) {
print_ifaddr(tmp);
}
freeifaddrs(addrs);
return 0;
}
Use gethostname() to retreive the machine's local DNS name, and then pass that name to gethostbyname() to get its local IP addresses.
If the OS supports IPv6, then look at the getaddrinfo() function instead of gethostbyname().
Take a look at the ioctl() function. If I recall correctly, you can use it to obtain information on any interface, as well as obtaining the available interfaces.
I don't remember the correct invocation though. As with fcntl(), it takes a request argument plus variable parameters that determine its behaviour.
On Linux, that information is accessed through NETLINK sockets. See the manual pages for libnetlink(3), netlink(7) and rtnetlink(7).
A somewhat more portable way of doing this is via ioctl()'s. SIOCGIFCONF is the one you want. See the manual page for netdevice(7). This one works on some other *nixes.