Cannot open FTP connection when server address is FQDN - c

My FTP program written in C only works when the server address is an IP address. But the connection fails when the server address is a Fully Qualified Domain Name (FQDN).
When ftp_host is FQDN, the ftp connection fails to open. Please help.

I'd strongly recommend using the getaddrinfo() function, as gethostbyname() is obsolete. This also has the advantage that it's easy to convert to IPv6, either now or later.
I'm assuming you only care about IPv4 addresses, so here's an example of a function which will take a hostname as its parameter and fill in a struct sockaddr_in for you:
int get_ftp_addr(const char *hostname, struct sockaddr_in *addr)
{
char host_buffer[256];
struct addrinfo hints;
struct addrinfo *result;
struct sockaddr_in *res_addr;
int error = -1;
char *colon;
snprintf(host_buffer, sizeof(host_buffer), "%s", hostname);
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
colon = strchr(host_buffer, ':');
if (colon) {
*colon = '\0';
error = getaddrinfo(host_buffer, colon + 1, &hints, &result);
} else {
error = getaddrinfo(host_buffer, "ftp", &hints, &result);
}
if (error != 0 || !result) {
return error;
}
res_addr = (struct sockaddr_in*)(result->ai_addr);
memcpy(addr, res_addr, sizeof(struct sockaddr_in));
freeaddrinfo(result);
return 0;
}
Note that I only take a copy of the string to avoid modifying the version in the caller - don't feel obliged to keep that part if you don't want to, but personally I think it makes a cleaner interface.
This function will accept both IP addresses in dotted quad notation and fully-qualified hostnames, as getaddrinfo() accepts both of those. If a port is specified with a colon it will be used, otherwise the default FTP port will be used.
A zero return value indicates success. A positive return can be passed into gai_strerror() to get a string error code, or you can check the getaddrinfo() man page for the possible error codes. A return of -1 indicates a successful result from getaddrinfo() but no result structure - I don't think this can happen, but I don't like leaving any possible return code unhandled.
There are several caveats here, the two most important are:
This code only support IPv4 as it stands, although getaddrinfo() makes it really easy to support IPv6 as well. If you want to support both then change the AF_INET in the hints structure to AF_UNSPEC and you'll get all address families. You'll need to iterate over addresses, though, and filter out only the IPv4 and IPv6 ones (see my next point).
A DNS lookup can potentially look up to multiple IP addresses - this is quite common with large sites such as Google as they use this feature for load-balancing across hosts, and also redundancy. Ideally you code should iterate across all the returned addresses and try connecting to each one until one works. For an FTP client this is perhaps overkill, but I think it's important to be aware of it.
If you want to support IPv6, or support multi-A-records (i.e. multiple addresses back from the DNS query), then you need to follow the ai_next pointer in the struct addrinfo structure - something like this:
struct addrinfo *res;
/* Assume result is initialised as above via getaddrinfo() */
for (res = result; res != NULL; res = res->ai_next) {
...
}

Related

Server socket: get own IP direction after accept [duplicate]

I want to get the IP address of the computer my program is launched on, to be able then to send it to a client, but I always get 0.0.0.1 instead of the real IP address (like 127.0.0.1 for instance).
I'm currently able to get the port, but not the IP address.
How can I get it?
The best solution would be to be able to get it with a sockaddr_in. Here's what I'm currently doing:
int open_connection(char* ip, int* port)
{
int sock;
struct sockaddr_in sin;
socklen_t len;
int i;
i = 0;
len = sizeof(sin);
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
return (-1);
bzero(&sin, sizeof(struct sockaddr_in));
sin.sin_family = AF_INET;
if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0)
perror("Error on bind");
if (getsockname(sock, (struct sockaddr *)&sin, &len) != 0)
perror("Error on getsockname");
strcpy(ip, inet_ntoa(sin.sin_addr)); // IP = 0.0.0.0
*port = sin.sin_port;
return (sock);
}
EDIT: I understand I was going on the wrong way with my way of thinking. So my question is: What's the best way to get your own IP address?
When you bind() a socket to 0.0.0.0, that is the only IP the socket has available when calling getsockname(). It means the socket is bound to all local interfaces. In order to get a specific IP from a socket, it has to be bound to a specific IP.
Using the socket API to get the machine's local IP(s) is the wrong approach anyway. A common mistake is to use gethostname() with gethostbyname() or getaddrinfo() to get the local IP list. Usually that works, but it has some hidden gotchas that can cause false information, but people tend to ignore that fact, or don't even know about it in the first place (I didn't know about it for years, but then I learned better).
Instead, you really should use platform-specific APIs for enumerating the local networking interfaces. That will provide more reliable information. Windows has GetAdaptersInfo() and GetAdaptersAddresses(). Other platforms have getifaddrs(). Those will tell you what local IPs are available. You can then bind() a socket to 0.0.0.0 in order to accept clients on any of those IPs, or bind() to a specific IP to accept clients only on that IP.
The sockets API allows you to enumerate the IP addresses assigned to your network interfaces, but it will not tell you what you "real IP" is if you are connecting to the Internet from behind a router.
The only way to know it is by asking someone outside. Thats how servers like FileZilla FTP Server do that. They instruct you to configure the URL to a "ip.php" script like this one in the server's settings so it can ask the Internet whats its public IP address, to use in Passive Mode.
You can also consider using STUN, a protocol widely used in VoIP to discover public IP.
You could call ioctl(sock, SIOCGIFADDR, adr)
see netdevice(7)
Following #Remy Lebeau's answer I wrote a function that return current machine's address. I have only tested this on macOS High Sierra.
interfaec can be anything among lo0, en0, etc.
ipVersion can be AF_INET or AF_INET6.
long int getInternalAddress(char* interface, sa_family_t ipVersion)
{
struct ifaddrs *ifaddrHead, *ifaddr;
/* int_8 */
sa_family_t family;
int n;
char *interfaceName;
if (getifaddrs(&ifaddrHead) != 0)
{
fprintf(stderr, "ifaddrs error");
}
/* iterate through address list */
for (ifaddr = ifaddrHead, n = 0; ifaddr != NULL; ifaddr = ifaddr->ifa_next, n++)
{
family = ifaddr->ifa_addr->sa_family;
interfaceName = ifaddr->ifa_name;
if (!family || family != ipVersion || strcmp(interfaceName, interface)) continue;
struct sockaddr *addr = ifaddr->ifa_addr;
struct sockaddr_in* addr_in = (struct sockaddr_in*) addr;
long int address = addr_in->sin_addr.s_addr;
freeifaddrs(ifaddrHead);
return address;
}
freeifaddrs(ifaddrHead);
return 0;
}
To use it,
int main()
{
long int address = getInternalAddress((char*) &"en0", AF_INET);
printf("%li\n", address);
return 0;
}
I'm still a beginner in C, if there is anything wrong please tell me.

How to get its own IP address with a socket address?

I want to get the IP address of the computer my program is launched on, to be able then to send it to a client, but I always get 0.0.0.1 instead of the real IP address (like 127.0.0.1 for instance).
I'm currently able to get the port, but not the IP address.
How can I get it?
The best solution would be to be able to get it with a sockaddr_in. Here's what I'm currently doing:
int open_connection(char* ip, int* port)
{
int sock;
struct sockaddr_in sin;
socklen_t len;
int i;
i = 0;
len = sizeof(sin);
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
return (-1);
bzero(&sin, sizeof(struct sockaddr_in));
sin.sin_family = AF_INET;
if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0)
perror("Error on bind");
if (getsockname(sock, (struct sockaddr *)&sin, &len) != 0)
perror("Error on getsockname");
strcpy(ip, inet_ntoa(sin.sin_addr)); // IP = 0.0.0.0
*port = sin.sin_port;
return (sock);
}
EDIT: I understand I was going on the wrong way with my way of thinking. So my question is: What's the best way to get your own IP address?
When you bind() a socket to 0.0.0.0, that is the only IP the socket has available when calling getsockname(). It means the socket is bound to all local interfaces. In order to get a specific IP from a socket, it has to be bound to a specific IP.
Using the socket API to get the machine's local IP(s) is the wrong approach anyway. A common mistake is to use gethostname() with gethostbyname() or getaddrinfo() to get the local IP list. Usually that works, but it has some hidden gotchas that can cause false information, but people tend to ignore that fact, or don't even know about it in the first place (I didn't know about it for years, but then I learned better).
Instead, you really should use platform-specific APIs for enumerating the local networking interfaces. That will provide more reliable information. Windows has GetAdaptersInfo() and GetAdaptersAddresses(). Other platforms have getifaddrs(). Those will tell you what local IPs are available. You can then bind() a socket to 0.0.0.0 in order to accept clients on any of those IPs, or bind() to a specific IP to accept clients only on that IP.
The sockets API allows you to enumerate the IP addresses assigned to your network interfaces, but it will not tell you what you "real IP" is if you are connecting to the Internet from behind a router.
The only way to know it is by asking someone outside. Thats how servers like FileZilla FTP Server do that. They instruct you to configure the URL to a "ip.php" script like this one in the server's settings so it can ask the Internet whats its public IP address, to use in Passive Mode.
You can also consider using STUN, a protocol widely used in VoIP to discover public IP.
You could call ioctl(sock, SIOCGIFADDR, adr)
see netdevice(7)
Following #Remy Lebeau's answer I wrote a function that return current machine's address. I have only tested this on macOS High Sierra.
interfaec can be anything among lo0, en0, etc.
ipVersion can be AF_INET or AF_INET6.
long int getInternalAddress(char* interface, sa_family_t ipVersion)
{
struct ifaddrs *ifaddrHead, *ifaddr;
/* int_8 */
sa_family_t family;
int n;
char *interfaceName;
if (getifaddrs(&ifaddrHead) != 0)
{
fprintf(stderr, "ifaddrs error");
}
/* iterate through address list */
for (ifaddr = ifaddrHead, n = 0; ifaddr != NULL; ifaddr = ifaddr->ifa_next, n++)
{
family = ifaddr->ifa_addr->sa_family;
interfaceName = ifaddr->ifa_name;
if (!family || family != ipVersion || strcmp(interfaceName, interface)) continue;
struct sockaddr *addr = ifaddr->ifa_addr;
struct sockaddr_in* addr_in = (struct sockaddr_in*) addr;
long int address = addr_in->sin_addr.s_addr;
freeifaddrs(ifaddrHead);
return address;
}
freeifaddrs(ifaddrHead);
return 0;
}
To use it,
int main()
{
long int address = getInternalAddress((char*) &"en0", AF_INET);
printf("%li\n", address);
return 0;
}
I'm still a beginner in C, if there is anything wrong please tell me.

Error from socket() call

I wanted to add IPv6 support for my program and came across odd error. I want to open socket which accepts connections. Here is my scenario:
First I use getaddrinfo() to find socket configuration:
struct addrinfo hint, *info = NULL;
memset((void *)&hint, 0, sizeof(hint));
hint.ai_family = AF_INET6;
hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
hint.ai_socktype = SOCK_STREAM;
if ((error = getaddrinfo(NULL, "1234", &hint, &info))) {
/* some error handling */
}
I gen non-NULL result in info. Then I want to create socket:
socket(info->ai_family, info->ai_socktype, info->ai_protocol)
Here I get -1
strerror(errno)
returns Address family not supported by protocol
I thought that getaddrinfo() returns only addresses that can be bound and I would expect it to return NULL in this case. What am I missing?
I want to add that my eth0 does not have IPv6 address right now. I am using uClibc 0.9.32
You need to add AI_ADDRCONFIG to ai_flags to make sure it doesn't return address families unsupported by the kernel. I pretty much always add that flag nowadays.
If you want to support kernels without IPv6 you'll have to avoid setting ai_family to AF_INET6. Instead you have to listen on all the returned addresses, and make sure to set IPV6_V6ONLY on the AF_INET6 ones. There's no guarantee that the AF_INET6 address will be returned first, unfortunately.
getaddrinfo returns a linked list of struct addrinfo objects, which you can traverse using the ai_next member. You should try each returned addrinfo object in turn until you get a connection (or hit NULL/end of list).

Unix sockets with getaddrinfo() in C

Does anyone know if it's possible to use getaddrinfo with unix sockets in C (AF_UNIX). I've tried a couple of things but I can't make it work.
This is basically what I'm trying:
struct addrinfo hints, *res;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNIX;
hints.ai_socktype = SOCK_STREAM;
if(getaddrinfo("What should I put here?", "What should I put here?", &hints, &res) != 0){
//do sth about
}
My question is how to fill the node and service fields, in case that is possible to use it with unix sockets.
Thanks in advance.
Some implementations of getaddrinfo() have supported AF_UNIX socket addresses, but they no longer do so due to security concerns.
You don't really need a function to "look up" an AF_UNIX address anyway - if you know the socket path, then you can just copy it straight into a sockaddr_un of sufficient size. There's no resolution step for AF_UNIX addresses - the socket name is the socket address.
From man 3 getaddrinfo:
The hints parameter specifies the preferred socket type, or protocol. A NULL hints specifies that any network address or protocol is acceptable. If this parameter is not NULL it points to an addrinfo structure whose ai_family, ai_socktype, and ai_protocol members specify the preferred socket type. AF_UNSPEC in ai_family specifies any protocol family (either IPv4 or IPv6, for example). 0 in ai_socktype or ai_protocol specifies that any socket type or protocol is acceptable as well. The ai_flags member specifies additional options, defined below. Multiple flags are specified by logically OR-ing them together. All the other members in the hints parameter must contain either 0, or a null pointer.
So it looks like you need to pass in the hints parameter to tell it you want a unix socket.
A lot late, but just for the records, did you try this -
struct addrinfo hints, *res;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; //is the address family(IPV4 or 6) or UNSPEC for either
hints.ai_socktype = SOCK_STREAM;
if(getaddrinfo(parm1, parm2, &hints, &res) != 0){
//do sth about
}
parm1 -> is the host name or address to connect to. A call with NULL here puts the address of local host, in which case you specify hints.ai_flags=AI_PASSIVE.
parm2 -> is the name of the intended service (http, ftp etc) or the corresponding port number for that service the socket is used for

How does this code from "Network programming" examples work?

I am reading Beej's "Guide to network programming".
In one of his intro examples he talks about getting the IP address for a hostname (like google.com or yahoo.com for instance).
Here is the code.
/*
** 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>
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;
}
The part that confuses me is the for loop.
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);
}
Would anyone mind going through psuedo-step-by-step at whats going on or what these things are? Is it iterating through a linked list?.. I have a general idea of what the struct addrinfo are but what the heck is struct *res and struct *p or void *addr and *char ipversion.
First thing's first, do you know what a linked list is? If you understand that, you'll recognise what that for loop is going. p is a pointer to a structure that also references (links) the next structure in the list. So you're looping through a list of those structures, which are addrinfo structs. 4
Now, the thing you need to know about network packets is that they're made up of a header. Specifically the Ethernet frame. This is the hardware to hardware protocol. It let's you get things around on a physical, bounded network but knows nothing about routing across physical network boundaries.
Next up comes tcp or possibly another transport layer protocol, which sits somewhere inbetween the two levels. TCP versus UDP versus X is about how you manage the packets - for example TCP requires packets be reassembled in order, whereas UDP is a "broadcast"-type protocol.
Finally, you have the internet protocol suite (IPv4, IPv6). These are higher level protocols that control the broader sense of routing, so they know about the internet at large, but less about the steps needed to get there.
A great explanation of this is the handy diagram on this page. To complete the picture, BGP is how routers know how to move stuff around.
tcp/udp fit into this picture by being a part of (enscapulated in) the protocol in question (IPv4 for example)
So ethernet frames contain other protocols most notably IPv4, which contain the information routers need to get it out across the internet (across multiple physical networks). The internet protocol specifies where you want to go, from where you are. So a typical's IPv4 body remains unchanged across its whole transit, but every time it traverses physical networks it gets wrapped up in a different ethernet packet.
Now, in the ethernet header there is a field for finding out what the "ethernet body" contains. This line:
if (p->ai_family == AF_INET) {
Does. AF_INET is a constant that matches the value tcp uses to identify the packet body as IPv4. So, if you're looking at an IPv4 header, this loop then goes on to read that information.
The else clause is technically wrong, because not being IPv4 doesn't automatically make it IPv6. You could change it to test for IPv6 like this:
else if (p->ai_family == AF_INET6) {
Which you might want to do, just in case you pick up something else.
Now it's worth explaining this bit of magic:
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
This basically takes the network, or raw, form of the data which appears as a sequence of bytes, and casts it (coverts it) into fields in a struct. Because you know how big the fields are going to be, this is a very quick and easy way to extract out what you need.
The last thing that needs explanation is this:
inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
There are other ways of achieving this, specifically ntohs().
Basically network data is transmitted in big endian encoding, and in order to read it, you need (potentially) to convert the data to the encoding of your system. It could be big endian, or it could be little, it depends on your system for the most part. Have a read of the wikipedia article on endianness.
Summary: what you're looking at here is a combination of computer science structures, how networks work and C code.
Well, it's not that complicated. getaddrinfo returns a linked list of addrinfo structs (struct addrinfo **res in the manpage) where each of these structs contains information about one address available to the given interface (const char *node in the manpage).
Now, every struct is being inspected and information about the struct is being printed out. To print out either IPv4 or IPv6, the variable ipver is set accordingly. Before printing out the information, the address has to be converted from a binary form to a string. This is done by inet_ntop (*n*umber to *p*ointer).
The resulting string of inet_ntop (ipstr) and ipver are now printed out to console. Printing ipver, however, is not neccessary since you would recognize the address type from the ipstr: an IPv4 address (as we all know) gets written 192.168.1.10 whereas IPv6 addresses use colons to separate the address elements: 2001:0db8:85a3:0000:0000:8a2e:0370:7334.
Yes, res points to a linked list of addrinfo structures that represent the different IP addresses of a host. The MSDN documentation on the getaddrinfo function is pretty good. I don't know what platform you're running on, but it shouldn't be much different on other platforms.

Resources