From gethostbyname(3) - Linux manual
The functions gethostbyname() and gethostbyaddr() may return pointers
to static data, which may be overwritten by later calls. Copying the
struct hostent does not suffice, since it contains pointers; a deep
copy is required.
I've written programs that make multiple calls to gethostbyname and haven't had anything break because of overwriting of static data.
Could I ask for an example when multiple calls to gethostbyname would overwrite this static data?
It will be a problem when you do something like this:
struct hostent *google = gethostbyname("www.google.com");
struct hostent *youtube = gethostbyname("www.youtube.com");
printf("Official name of host for www.google.com: %s\n", google->h_name);
printf("Official name of host for www.youtube.com: %s\n", youtube->h_name);
printf("same? %s\n", google == youtube ? "yes" : "no");
The output will be
Official name of host for www.google.com: youtube-ui.l.google.com
Official name of host for www.youtube.com: youtube-ui.l.google.com
same? yes
which is wrong, as the official host name of www.google.com is www.google.com
and not youtube-ui.l.google.com. The problem is that google and youtube
point at the same location (as you can see from the same? yes output),
so the information about www.google.com is lost when you execute gethostbyname again.
If you however do
struct hostent *google = gethostbyname("www.google.com");
printf("Official name of host for www.google.com: %s\n", google->h_name);
struct hostent *youtube = gethostbyname("www.youtube.com");
printf("Official name of host for www.youtube.com: %s\n", youtube->h_name);
then the output will be
Official name of host for www.google.com: www.google.com
Official name of host for www.youtube.com: youtube-ui.l.google.com
So as long as you process the hostent pointer of the first gethostbyname
call before you do the second call, you will be fine.
struct hostent *host1 = gethostbyname("host1");
struct hostent *host2 = gethostbyname("host2");
if(host1......)
the second call has overwritten (possibly) the result of the first one
Here's an example:
struct hostent *he1 = gethostbyname("host1");
struct in_addr *addr1 = (struct in_addr *)(he1->h_addr);
printf("addr1=%s\n", inet_ntoa(*addr1)); // prints IP1
struct hostent *he2 = gethostbyname("host2");
struct in_addr *addr2 = (struct in_addr *)(he2->h_addr);
printf("addr2=%s\n", inet_ntoa(*addr2)); // prints IP2
printf("addr1=%s\n", inet_ntoa(*addr1)); // prints IP1 (!)
Related
I'm just wondering how to save the results of hostent in a temp buffer to process it knowing that if i called gethostbyname twice it overwrites the first call like this example
struct hostent* d = gethostbyname("www.google.com");
struct hostent* b = gethostbyname("www.youtube.com");
printf("%s",d->h_name);
printf("%s",b->h_name);
Output will be in twice
youtube-ui.l.google.com
youtube-ui.l.google.com
What i want to do that save the results of each in two seperate hostent and when get the h_name of each one i get the h_name of google.com and the h_name of www.youtube.com and doesn't overwrite each other
What i tried something like this and it doesn't work
struct hostent d = *(gethostbyname("www.google.com"));
struct hostent b = *(gethostbyname("www.youtube.com"));
printf("%s",d.h_name); // doesn't give an output
printf("%s",b.h_name); // gives youtube-ui.l.google.com
I am writing a simple FTP server program in C. I am mostly following Beej's Guide to Network Programming. In order to complete the pasv mode functionality, I have to create another socket and send its ip and port to the client.
Since gethostbyname() is deprecated, I am using getsockname() to get my current network IP address. My plan is that I separate two cases (ipv4 and ipv6) and send info to the client accordingly. But, whenever I try to get the address family it always 30. I am not sure if I am printing this correctly though.
I am doing something simple like this (which might include mistakes), and it prints 30.
struct sockaddr_storage my_addr;
int result;
socklen_t len = sizeof(my_addr);
result = getsockname(current_fd, (struct sockaddr *) &my_addr, &len);
if (my_addr.ss_family == AF_INET) { // ipv4
struct sockaddr_in * ipv4 = (struct sockaddr_in *) &my_addr;
addr = &(ipv4->sin_addr);
} else { // ipv6
struct sockaddr_in6 * ipv6 = (struct sockaddr_in6 *) &my_addr;
addr = &(ipv6->sin6_addr);
}
printf(" family: %u\n", (unsigned short) my_addr.ss_family);
When I searched this online, I got:
#define AF_ATM 30 /* ATM */
What is this exactly? Is this expected? If not, where am I doing something wrong?
Thank you.
Edit:
Apparently what it was printing was something different.
It is not defined as:
#define AF_ATM 30 /* ATM */
but it is defines as:
MT IPv6: Multi-Topology IP version 6 [RFC7307]
I defined a struct like this (and other fields but they are not relevant with the question)
typedef struct {
struct sockaddr_in addr_destination;
}MY_PACKET;
The main call a function send_command
struct sockaddr_in *addr_server;
socklen_t addr_server_lenght;
MY_PACKET command_packet;
void send_command(char *comm, int socket_file_descriptor, struct sockaddr_in *server_address) {
addr_server = server_address;
addr_server_lenght = sizeof(*addr_server);
printf("Server address: %s\n", inet_ntoa(addr_server->sin_addr));
command_packet.addr_destination = *addr_server;
printf("Server address: %s\n", inet_ntoa(command_packet.addr_destination.sin_addr));
}
so the first printf prints "127.0.0.1" correctly
the second prints "0.0.0.0"
The rest of the program consists on a thread that send this packet to a server and wait for ack (so i must be able to access all the fields of command_packet from the thread function), but I'm stuck saving the server address in the packet correctly, what am I doing wrong? Thanks
How can I know if a string is the canonical name or the IP address?
Because if argv[1] is the IP address I do:
sscanf(argv[2],"%" SCNu16,&server_port);
inet_aton(argv[1],&server_address);
remote_address.sin_family = AF_INET;
remote_address.sin_port = htons(server_port);
remote_address.sin_addr = server_address;
And if argv[1] is the canonical name I do:
h = gethostbyname(server);
indirizzo_remoto.sin_family = AF_INET;
indirizzo_remoto.sin_port = htons(porta_server);
indirizzo_remoto.sin_addr = XYZ;
Also, what do I have to have in place of XYZ?
POSSIBLE SOLUTION:
struct in_addr indirizzo_server;
struct hostent *h;
h = gethostbyname(server);
inet_aton(h->h_addr_list[0],&indirizzo_server);
indirizzo_remoto.sin_family = AF_INET;
indirizzo_remoto.sin_port = htons(porta_server);
indirizzo_remoto.sin_addr = indirizzo_server;
Get familiar with getaddrinfo(3) that can do either, and also supports IPv6.
Why the fuzz? gethostbyname already takes care of that. Quoting the manual:
[...]name is either a hostname, or an IPv4
address in standard dot notation (as for inet_addr(3)), or an IPv6
address in colon (and possibly dot) notation.
So delete the special handling with inet_aton and be done.
Regarding the XYZ part: The hostent structure contains two things you must copy into your in_addr:
the h_addrtype which might indicate IPv4 or IPv6. Copy it into sin_family.
the actual address(es) in h_add_list. Copy this into your sin_addr using memcpy and the length given in h_length.
This should both handle IPv4 and IPv6 automatically.
I'm writing simple server/client and trying to get client IP address and save it on server side to decide which client should get into critical section. I googled it several times but couldn't find proper way to get IP address from sock structure.
I believe this is a way to get IP from sock struct after server accept request from client. More specifically in c after server execute
csock = accept(ssock, (struct sockaddr *)&client_addr, &clen)
Thanks
OK assuming you are using IPV4 then do the following:
struct sockaddr_in* pV4Addr = (struct sockaddr_in*)&client_addr;
struct in_addr ipAddr = pV4Addr->sin_addr;
If you then want the ip address as a string then do the following:
char str[INET_ADDRSTRLEN];
inet_ntop( AF_INET, &ipAddr, str, INET_ADDRSTRLEN );
IPV6 is pretty easy as well ...
struct sockaddr_in6* pV6Addr = (struct sockaddr_in6*)&client_addr;
struct in6_addr ipAddr = pV6Addr->sin6_addr;
and getting a string is almost identical to IPV4
char str[INET6_ADDRSTRLEN];
inet_ntop( AF_INET6, &ipAddr, str, INET6_ADDRSTRLEN );
The easier and correct way for extracting IP address and port number would be:
printf("IP address is: %s\n", inet_ntoa(client_addr.sin_addr));
printf("port is: %d\n", (int) ntohs(client_addr.sin_port));
The SoapBox's accepted answer won't be correct for all architectures. See Big and Little Endian.
Assuming client_addr is a struct sockaddr_in (which it usually is). You can get the IP address (as a 32-bit unsigned integer) from client_addr.sin_addr.s_addr.
You can convert it to a string this way:
printf("%d.%d.%d.%d\n",
int(client.sin_addr.s_addr&0xFF),
int((client.sin_addr.s_addr&0xFF00)>>8),
int((client.sin_addr.s_addr&0xFF0000)>>16),
int((client.sin_addr.s_addr&0xFF000000)>>24));