Please help me! I need to translate (or convert) domain names (for example google.com) to IP address. For that purpose I have found code on interet, which work perfectly, but I don't understand, why there is called function inet_ntop() two times. Please help me. Here is code:
/*
* getaddrinfo.c - Simple example of using getaddrinfo(3) function.
*
* Michal Ludvig <michal#logix.cz> (c) 2002, 2003
* http://www.logix.cz/michal/devel/
*
* License: public domain.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int
lookup_host (const char *host)
{
struct addrinfo hints, *res;
int errcode;
char addrstr[100];
void *ptr;
memset (&hints, 0, sizeof (hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags |= AI_CANONNAME;
errcode = getaddrinfo (host, NULL, &hints, &res);
if (errcode != 0)
{
perror ("getaddrinfo");
return -1;
}
printf ("Host: %s\n", host);
while (res)
{
inet_ntop (res->ai_family, res->ai_addr->sa_data, addrstr, 100);
switch (res->ai_family)
{
case AF_INET:
ptr = &((struct sockaddr_in *) res->ai_addr)->sin_addr;
break;
case AF_INET6:
ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
break;
}
inet_ntop (res->ai_family, ptr, addrstr, 100);
printf ("IPv%d address: %s (%s)\n", res->ai_family == PF_INET6 ? 6 : 4,
addrstr, res->ai_canonname);
res = res->ai_next;
}
return 0;
}
int
main (int argc, char *argv[])
{
if (argc < 2)
exit (1);
return lookup_host (argv[1]);
}
My question is - why there is function inet_ntop() used twice? I thought, that the first calling give you IP address...but why you need the second calling?
Thanks!
The first call to inet_ntop isn't doing anything useful here. What it writes to addrstr is overwritten on the following call.
The author either didn't understand why they were calling it twice or left in test code they shouldn't have.
Related
I'm trying to download a few seconds from a livestream using sockets.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> /* close() */
#include <sys/socket.h>
#include <netdb.h>
int main(void)
{
int sock;
char host[] = "http://141.138.89.176/fun-1-44-128";
char port[] = "80";
struct addrinfo hints, *res;
char message[] = "GET / HTTP/1.1\nHost: http://141.138.89.176/fun-1-44-128";
unsigned int i;
char buf[1024];
int bytes_read;
int status;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
status = getaddrinfo(host, port, &hints, &res);
if (status != 0) {
perror("getaddrinfo");
return 1;
}
sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sock == -1) {
perror("socket");
return 1;
}
status = connect(sock, res->ai_addr, res->ai_addrlen);
if (status == -1) {
perror("connect");
return 1;
}
freeaddrinfo(res);
send(sock, message, strlen(message), 0);
do {
bytes_read = recv(sock, buf, 1024, 0);
if (bytes_read == -1) {
perror("recv");
}
else {
printf("%.*s", bytes_read, buf);
}
} while (bytes_read > 0);
close(sock);
return 0;
}
The code compiles, however when running, getaddrinfo() fails. I assume that this means that the host cannot be found.
This is my url: http://141.138.89.176/fun-1-44-128
It works in my browser so I don't know what's going on. Could anyone shed some light on the problem?
I tested your code on my environment and it's perfectly working so your code is surely okay. I recommend checking your compiler, maybe reinstall it.
EDIT: Okay I think I found the problem. It was that the host should only be the ip address, not the full link.
(also added a fix to the error reporting from getaddrinfo)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> /* close() */
#include <sys/socket.h>
#include <netdb.h>
int main(void)
{
int sock;
char host[] = "141.138.89.176";
char port[] = "80";
struct addrinfo hints, *res;
char message[] = "GET / HTTP/1.1\nHost: 141.138.89.176/fun-1-44-128";
unsigned int i;
char buf[1024];
int bytes_read;
int status;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
status = getaddrinfo(host, port, &hints, &res);
if (status != 0) {
printf("Code: %d\n", status);
printf("Message: %s\n", gai_strerror(status));
return 1;
}
...
OK I figured out the solution.
getaddrinfo() only accepts base host names, domain names or ip addresses, with no subdirectories.
This means that 192.168.0.4, www.site.com, localhost are all valid. 192.168.0.4/Search, www.site.com/Search, localhost/Search are not.
You also don't need to include the scheme. Sockets don't differentiate http from https, it's how requests are dealt with makes the difference.
You need to change host so that it only contains the IP address.
What you want is:
char host[] = "141.138.89.176";
You won't get that error now.
If you want to access a subdirectory you pass it as a GET request. It's actually the web server that handles file and directory stuff. The base IP stays the same.
First off your formatting is wrong. It should be \r\n and \r\n\n\n to finish. It should look like this: char message[] = "GET / HTTP/1.1\r\nHost: 141.138.89.176/fun-1-44-128\r\n\n\n";
Now if you try this, you will get a 400 error. this is because it's incorrectly written. Much like the above Host only accepts the base url/ip. See that / right after the GET? That's where you request any subdirectories/files you want. The / you have there now indicates that you want the top level dictionary.
It should look like this:
message[] = "GET /fun-1-44-128 HTTP/1.1\r\nHost: 141.138.89.176\r\n\n\n";
I am creating a UDP server-client program. Client requests a file and the server sends to client if found.
Based on Beej's Guide to Networking,
inet_ntoa() returns the dots-and-numbers string in a static buffer that is overwritten with each call to the function.
inet_ntop() returns the dst parameter on success, or NULL on failure (and errno is set).
The guide mentions ntoa is deprecated so ntop is recommended since it supports IPv4 and IPv6.
On my code I am getting different results when I use function or the other and my understanding is that they should throw the same result. Anything I am missing? Any help would be greatly appreciated.
Code:
//UDP Client
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define MAXBUFLEN 1024
#define SER_IP "176.180.226.0"
#define SER_PORT "1212"
// Get port, IPv4 or IPv6:
in_port_t get_in_port(struct sockaddr *sa){
if (sa->sa_family == AF_INET) {
return (((struct sockaddr_in*)sa)->sin_port);
}
return (((struct sockaddr_in6*)sa)->sin6_port);
}
int main(int argc, char *argv[]){
int sock, rv, numbytes;
struct addrinfo hints, *servinfo, *p;
char buffer[MAXBUFLEN];
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
rv = getaddrinfo(NULL, SER_PORT, &hints, &servinfo);
if (rv != 0){
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
exit(1);
}
// Printing IP, should provide same result
for(p = servinfo; p != NULL; p = p->ai_next) {
char str1[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &p->ai_addr, str1, INET_ADDRSTRLEN);
printf("ntop:%s\n", str1) ;
printf("inet_ntoa:%s \n", inet_ntoa(((struct sockaddr_in *)p->ai_addr)->sin_addr));
printf("\n");
}
exit(1);
}
Current output:
ntop:64.80.142.0
inet_ntoa:0.0.0.0
ntop:160.80.142.0
inet_ntoa:127.0.0.1
As per the man page, in the case of AF_INET the argument src must point to a struct in_addr (network byte order).
In your struct addrinfo you have a pointer to struct sockaddr which is basically
sa_family_t sa_family;
char sa_data[];
However, struct sockaddr_in is
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
So, you need to replace
inet_ntop(AF_INET, &p->ai_addr, str1, INET_ADDRSTRLEN);
by either
inet_ntop(AF_INET, &p->ai_addr->sa_data[2], str1, INET_ADDRSTRLEN);
(the src argument may be &p->ai_addr->sa_data[1 << 1] to avoid the "magic number" 2 - the offset which counts for the port number storage)
or
inet_ntop(AF_INET, &((struct sockaddr_in *)p->ai_addr)->sin_addr, str1, INET_ADDRSTRLEN);
Then it will produce correct output.
I am reading Beej's guide to network programming and in chapter 5.1, in the showip.c program I see the following line of code:
memset(&hints, 0, sizeof hints);
After a discussion on the ##c channel on freenode I deducted that the reasoning of that memset call could be to set the value of hints.ai_flags to 0(note that the program works fine I remove that line and I explicitly initialize hints.ai_flags to 0). If this is true, why does he need to set the whole struct to 0?
This is the full source:
/*
** showip.c -- show IP addresses for a host given on the command line
*/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main(int argc, char *argv[])
{
struct addrinfo hints, *res, *p;
int status;
char ipstr[INET6_ADDRSTRLEN];
if (argc != 2) {
fprintf(stderr,"usage: showip hostname\n");
return 1;
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version
hints.ai_socktype = SOCK_STREAM;
if ((status = getaddrinfo(argv[1], NULL, &hints, &res)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
return 2;
}
printf("IP addresses for %s:\n\n", argv[1]);
for(p = res;p != NULL; p = p->ai_next) {
void *addr;
char *ipver;
// get the pointer to the address itself,
// different fields in IPv4 and IPv6:
if (p->ai_family == AF_INET) { // IPv4
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
addr = &(ipv4->sin_addr);
ipver = "IPv4";
} else { // IPv6
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
addr = &(ipv6->sin6_addr);
ipver = "IPv6";
}
// convert the IP to a string and print it:
inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
printf(" %s: %s\n", ipver, ipstr);
}
freeaddrinfo(res); // free the linked list
return 0;
}
It's required by getaddrinfo() function documentation (where you pass your hints variable as parameter). From man getaddrinfo:
All the other fields in the structure pointed to by hints must contain either 0 or a NULL pointer, as appropriate.
It's because you are only going to fill/use/initialize some of the fields of the struct, giving 0 to the other fields prevents reading an uninitialzied variable, and sometimes 0 is the default value for those variables.
note that the program works fine I remove that line and I explicitly initialize hints.ai_flags to 0
Not necessarily, if you are on linux, I suggest using valgrind to detect reads to uninitialized variables, since that causes undefined behavior, the behavior could be that nothing wierd happens.
I’m trying to use socket in C on CentOS 6.4.
Following LIST1 is my code.
My code gets hostname from command line and sends datagram to server with UDP successfully.
What I want to know is how to print IP address that getaddrinfo() resolved wiht 192.168.10.1 format.
When I try to print IP address segmentation error happens.
Does anyone know how to fix this code?
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
int
main(int argc,char *argv[]){
int sock;
struct addrinfo hints,*res;
int n;
int err;
if(argc != 2){
fprintf(stderr,"Usage : %s dst \n",argv[0]);
return 1;
}
memset(&hints,0,sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
err = getaddrinfo(argv[1],"12345",&hints,&res);
if(err != 0){
perror("getaddrinfo");
printf("getaddrinfo %s\n",strerror(errno));
printf("getaddrinfo : %s \n",gai_strerror(err));
return 1;
}
sock = socket(res->ai_family,res->ai_socktype,0);
if(sock < 0){
perror("socket");
return 1;
const char *ipverstr;
switch (res->ai_family){
case AF_INET:
ipverstr = "IPv4";
break;
case AF_INET6:
ipverstr = "IPv6";
break;
default:
ipverstr = "unknown";
break;
}
printf("ipverstr = %s\n ",ipverstr);
}
n = sendto(sock,"HELLO",5,0,res->ai_addr,res->ai_addrlen);
if(n<1){
perror("sendto");
return 1;
}
struct sockaddr_in *addr;
addr = (struct sockaddr_in *)res->ai_addr;
printf("inet_ntoa(in_addr)sin = %s\n",inet_ntoa((struct in_addr)addr->sin_addr));
printf("############ finish !! #######\n");
close(sock);
freeaddrinfo(res);
return 0;
}
The code misses to include the prototype for inet_ntoa().
The compiler should have told you this.
Do add:
#include <arpa/inet.h>
However the code still compiles as due to the missing protoype for inet_ntoa() it is assumed to return int, whereas it returns a char* which is a pointer, which on a 64bit system is 8 bytes, which is not the same size as int which typically has a size of 4. Due to this mismatch things go terribly wrong and end up in a segmentation violation.
Also please note: inet_ntoa() is to be used for ipv4 addresses only. Verbatim from man inet_ntoa (italics by me):
The inet_ntoa() function converts the Internet host address in, given in network byte order, to a string in IPv4 dotted-decimal notation. The string is returned in a statically allocated buffer, which subsequent calls will
overwrite
To be able to convert both (IPv4 and IPv6) struct sockaddr_XYZ's binary addresses to a char[] use inet_ntop().
The counterpart of getaddrinfo() is getnameinfo(). This turns a struct sockaddr into a string.
I have a C function to check a host and its port, when I use FQDN host name, the function return error like: connect() failed: connect time out, but if I use IP address instead, it seems ok, how to fix this?
Thanks.
#include <unistd.h>
#include <string.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
int is_network_up(char *chkhost, unsigned short chkport) {
int sock;
struct sockaddr_in chksock;
struct hostent *host = NULL;
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
syslog(LOG_ERR, "socket() creation error: %s", strerror(errno));
return 0;
}
memset(&chksock, 0, sizeof(chksock));
chksock.sin_family = AF_INET;
chksock.sin_port = htons(chkport);
/* get the server address */
if (inet_pton(AF_INET, chkhost, &(chksock.sin_addr.s_addr)) <= 0) {
if ((host = gethostbyname(chkhost)) == NULL) {
syslog(LOG_ERR, "%s", hstrerror(h_errno));
return 0;
}
memcpy(&(chksock.sin_addr.s_addr), &(host->h_addr_list[0]),
sizeof(struct in_addr));
}
/* try to connect */
if (connect(sock, (struct sockaddr *) &chksock, sizeof(chksock)) < 0) {
syslog(LOG_ERR, "connect() failed: %s", strerror(errno));
return 0;
}
close(sock);
return 1;
}
inet_pton() is the wrong task for that. It only accepts numerical addresses.
In former times, people used to use gethostbyname() for name resolution.
But as we have 2012 meanwhile, this method is outdated for several years now, as it is still restricted to AF_INET.
With the program below, you should achieve about the same and stay future compatible.
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdlib.h>
#include <stdio.h>
int is_network_up(char *chkhost, unsigned short chkport) {
int sock = -1;
struct addrinfo * res, *rp;
int ret = 0;
char sport[10];
snprintf(sport, sizeof sport, "%d", chkport);
struct addrinfo hints = { .ai_socktype=SOCK_STREAM };
if (getaddrinfo(chkhost, sport, &hints, &res)) {
perror("gai");
return 0;
}
for (rp = res; rp && !ret; rp = rp->ai_next) {
sock = socket(rp->ai_family, rp->ai_socktype,
rp->ai_protocol);
if (sock == -1) continue;
if (connect(sock, rp->ai_addr, rp->ai_addrlen) != -1) {
char node[200], service[100];
getnameinfo(res->ai_addr, res->ai_addrlen, node, sizeof node, service, sizeof
service, NI_NUMERICHOST);
printf("Success on %s, %s\n", node, service);
ret = 1; /* Success */
}
close(sock);
}
freeaddrinfo(res);
return ret;
}
int main(int argc, char** argv) {
if (argc > 1) {
printf("%s: %d\n", argv[1], is_network_up(argv[1], 22));
}
}
Make sure name resolution is working. See if you can ping the machine by name from the exact same environment in which your code runs.
If ping works, try telnet <machinename> <portnumber> -- If both of those work it is likely a problem with your code (which I did not look at in depth, too sleepy:).
Make sure you're converting anything returned by the OS as an ip address from network order to host order. IIRC, gethostbyname returns binary ip addresses in network order.
ntohl can be used on chksock.sin_addr.s_addr after the memcpy to achieve this.