How to detect your IP/name using gethostbyname() - c

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).

Related

Socket programming: bind()-invalid argument

I am trying to bind my local IPv6 address to a socket. But always get "invalid argument". The reason I want to bind the specific IP address to socket is that if I don't bind the error "No route to host" came up. When I tried to ping an IPv6 address with command below it does not work.
ping6 fe80::7ed1:c3ff:fe86
I have to point out from which interface I want to send the packet.
ping6 -I en1 fe80::7ed1:c3ff:fe86
And this works fine. So I think if I bind the socket to the interface then I can send the packet successfully.
Anyone can tell me how to send an IPv6 address without specify the interface or how to solve this problem of binding?
Here are the codes.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <netdb.h>
#define LOCALADDR "fe80::7ed1:c3ff:fe86:ddae"
int main(void)
{
int sock,status;
struct addrinfo local_addr;
struct addrinfo *servinfo;
char buffer[1024];
/* create a DGRAM (UDP) socket in the INET6 (IPv6) protocol */
sock = socket(PF_INET6, SOCK_DGRAM, 0);
if (sock < 0) {
perror("creating socket");
exit(1);
}
/*Binding specific interface to socket*/
memset(&local_addr, 0, sizeof(local_addr));
local_addr.ai_family = AF_INET6;
local_addr.ai_socktype = SOCK_DGRAM;
local_addr.ai_flags = AI_PASSIVE;
if ((status = getaddrinfo(NULL, "3535", &local_addr, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
if (bind(sock, (struct sockaddr *) &local_addr, sizeof(local_addr)) < 0)
error("ERROR on binding");
I have also tried to replace "NULL" in the "getaddrinfo" to be "LOCALADDR".
if ((status = getaddrinfo(LOCALADDR, "3535", &local_addr, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
And I still get the same problem.
I can successfully binding the socket with "in6addr_any",but then I get the error "No route to host".
That is a link-local IPv6 address, not a routable IPv6 address. The link-local addresses are specific to a link, and each link can have the same addresses as the other links. For instance if you have three different interfaces, you can assign the same link-local address to each of the interfaces. To use a link-local address, you need to specify the interface so that the OS knows which link to use. All the interfaces will have a link-local address in the same network: fe80::/10.
If you use a routable IPv6 address, you will not need to specify an interface.
You are creating the socket incorrectly. The 'domain' (first argument) should be AF_INET6, not PF_INET6. I am uncertain whether these in fact expand to different values in your environment, but the AF_* macros are the ones designated for this purpose.
Otherwise, for a socket that accepts connections, you should get an address much the way you first present. In particular, the docs for getaddrinfo() say
If the AI_PASSIVE flag is specified in hints.ai_flags, and node is NULL, then the returned socket addresses will be suitable for bind(2)ing a socket that will accept(2) connections. The returned socket address will contain the "wildcard address" (INADDR_ANY for IPv4 addresses, IN6ADDR_ANY_INIT for IPv6 address). The wildcard address is used by applications (typically servers) that intend to accept connections on any of the hosts’s network addresses. If node is not NULL, then the AI_PASSIVE flag is ignored.
Thus, you certainly could and probably should specify a NULL first argument.
Note, however, that getaddrinfo() returns a linked list of addresses, and under some circumstances it is necessary to choose a different one than the first. I think the first ought to be fine in this particular case, though.
Do also be aware that a "no route to host" message from a client trying to connect does not necessarily indicate that the server is not listening. It could well be that the client is using the wrong address (c.f. #RonMaupin's answer) or, just as it says, that there is no (known) route through the network from the client to the server. That could arise because of router or firewall configuration, for example.

Binding Sockets to IPv6 Addresses

I am trying to write a web server that listens on both IPv4 and IPv6 addresses. However, the code that I originally wrote did not work. Then I found out that the IPv6 structures work for both IPv4 and IPv6. So now I use the IPv6 structures however, only the IPv4 addresses work. This post, why can't i bind ipv6 socket to a linklocal address, which said to add server.sin6_scope_id = 5; so I did that but it still does not accept IPv6 telnet connections. Any help would be greatly appreciated because I am thoroughly stumped.
Thanks!
My code is below:
void initialize_server(int port, int connections, char* address)
{
struct sockaddr_in6 socket_struct;
/*Creates the socket*/
if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
syslog(LOG_ERR, "%s\n", strerror(errno));
exit(EXIT_FAILURE);
}/*Ends the socket creation*/
/*Populates the socket address structure*/
socket_struct.sin6_family = AF_INET6;
if(address == NULL)
socket_struct.sin6_addr=in6addr_any;
else
{
inet_pton(AF_INET6, "fe80::216:3eff:fec3:3c22", (void *)&socket_struct.sin6_addr.s6_addr);
}
socket_struct.sin6_port =htons(port);
socket_struct.sin6_scope_id = 0;
if (bind(sock_fd, (struct sockaddr*) &socket_struct, sizeof(socket_struct)) < 0)
{
syslog(LOG_ERR, "%s\n", strerror(errno));
exit(EXIT_FAILURE);
}//Ends the binding.
if (listen(sock_fd, connections) <0)
{
syslog(LOG_ERR, "%s\n", strerror(errno));
exit(EXIT_FAILURE);
}//Ends the listening function
}//ends the initialize server function.
Saying "server.sin6_scope_id = 5;" is arbitrary. I fought with this awhile myself and discovered you need to use the actual scope of the actual interface you want to bind on. It can be found with an obsure but useful little function.
#include <net/if.h>
server.sin6_scope_id=if_nametoindex("eth0");
Of course, hardcoding it to one particular adapter is bad, shortsighted coding. A more complete solution is to loop through all of them and match on the ip address you're binding. The following is not perfect in that it doesn't account for quirks like having non-canonical addresses and two adapters with the same ip, etc. But besoverall, this sample function works great and should get you started.
#include <string.h> // strcmp
#include <net/if.h> // if_nametoindex()
#include <ifaddrs.h> // getifaddrs()
#include <netdb.h> // NI_ constants
// returns 0 on error
unsigned getScopeForIp(const char *ip){
struct ifaddrs *addrs;
char ipAddress[NI_MAXHOST];
unsigned scope=0;
// walk over the list of all interface addresses
getifaddrs(&addrs);
for(ifaddrs *addr=addrs;addr;addr=addr->ifa_next){
if (addr->ifa_addr && addr->ifa_addr->sa_family==AF_INET6){ // only interested in ipv6 ones
getnameinfo(addr->ifa_addr,sizeof(struct sockaddr_in6),ipAddress,sizeof(ipAddress),NULL,0,NI_NUMERICHOST);
// result actually contains the interface name, so strip it
for(int i=0;ipAddress[i];i++){
if(ipAddress[i]=='%'){
ipAddress[i]='\0';
break;
}
}
// if the ip matches, convert the interface name to a scope index
if(strcmp(ipAddress,ip)==0){
scope=if_nametoindex(addr->ifa_name);
break;
}
}
}
freeifaddrs(addrs);
return scope;
}
You're creating a socket in the AF_INET family, but then trying to bind it to an address in the AF_INET6 family. Switch to using AF_INET6 in your call to socket().

Unix - how to get IP address of domain name?

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) );

get LAN ip and print it

Does anyone know how do I get my LAN IP and print it on the screen.
*I don't mean on shell, but in c programming.
**I will appreciate if you'll post me a sample code.
There's a few approaches; first, you could set up a connection to a known peer using connect(2) and then read the local socket 'name' with getsockname(2). This is a pretty poor mechanism, but it is easy.
But, getsockname(2) will only report one IP address, when a machine may have thousands of IP addresses, and which IP is returned will depend in part upon the peer that you chose! So, not very reliable.
A much better answer is to use rtnetlink(7) to read the IP addresses for the machine directly from the kernel: you would send RTM_GETADDR messages to the kernel for each interface on the machine and read the answers back. Your best bet for understanding how to use this is probably to read the source code for the ip program.
Another option is to use the SIOCGIFCONF ioctl(2) on an IP socket. This interface isn't as flexible as the rtnetlink(7) interface, so it might not always be correct, but it'll be a mid-way point. The ifconfig(8) utility uses this approach for displaying ifconfig -a output. Again, your best bet would be to read the source. (There is some slight documentation in ioctl_list(2).)
The getifaddrs() function from <ifaddrs.h> is the simplest way to get the current interfaces and corresponding addresses:
#include <stdio.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main()
{
struct ifaddrs *iflist, *iface;
if (getifaddrs(&iflist) < 0) {
perror("getifaddrs");
return 1;
}
for (iface = iflist; iface; iface = iface->ifa_next) {
int af = iface->ifa_addr->sa_family;
const void *addr;
char addrp[INET6_ADDRSTRLEN];
switch (af) {
case AF_INET:
addr = &((struct sockaddr_in *)iface->ifa_addr)->sin_addr;
break;
case AF_INET6:
addr = &((struct sockaddr_in6 *)iface->ifa_addr)->sin6_addr;
break;
default:
addr = NULL;
}
if (addr) {
if (inet_ntop(af, addr, addrp, sizeof addrp) == NULL) {
perror("inet_ntop");
continue;
}
printf("Interface %s has address %s\n", iface->ifa_name, addrp);
}
}
freeifaddrs(iflist);
return 0;
}
gethostbyname should help you to do this. Example:
GetLocalAddress()
{
char ac[80];
// Get my host name
if (gethostname(ac, sizeof(ac)) != -1)
{
printf("Host name: %s\n", ac);
// Find IP addresses
struct hostent* p_he = gethostbyname(ac);
if (p_he != 0)
{
for (int i=0; p_he->h_addr_list[i] != 0; ++i)
{
struct in_addr addr;
memcpy(&addr, p_he->h_addr_list[i], sizeof(struct in_addr));
printf("IP address %d: %s\n", i, inet_ntoa(addr));
}
}
}
You might want to filter to remove 127.0.0.1 from the list.

Why can't a bind linux service to the loop-back only?

I am writing a server application that will provide a service on an ephemeral port that I only want accessible on the loopback interface. In order to do this, I am writing code like the following:
struct sockaddr_in bind_addr;
memset(&bind_addr,0,sizeof(bind_addr));
bind_addr.sin_family = AF_INET;
bind_addr.sin_port = 0;
bind_addr.sin_addr.s_addr = htonl(inet_addr("127.0.0.1"));
rcd = ::bind(
socket_handle,
reinterpret_cast<struct sockaddr *>(&bind_addr),
sizeof(bind_addr));
The return value for this call to bind() is -1 and the value of errno is 99 (Cannot assign requested address). Is this failing because inet_addr() already returns its result in network order or is there some other reason?
inet_addr should be avoided, for there is a much saner method of constructing struct sockaddrs (which means it also obsoletes gethostby*):
#include <netdb.h>
/* Error checking omitted for brevity */
struct addrinfo hints = {.ai_flags = AI_PASSIVE};
struct addrinfo *res;
getaddrinfo("::1", NULL, &hints, &res); /* or 127.0.0.1 if you are 60+ */
bind(fd, res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
Is this failing because inet_addr() already returns its result in network order
Yes.
So remove the htonl call.

Resources