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.
Related
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]
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) {
...
}
Since there is no function in BSD sockets to get the IP address, I did client/server program to establish the connection. One thread for each: server and client.
The IP address returned from "inet_ntoa" with localhost was 127.0.0.1.
But the network says my computer is this 10.0.0.7, and this address is what works.
How do I get the 10.0.0.7 address?
Thx
Here is my code:
DWORD WINAPI CIpAddressDlg::Thread_TcpServer(LPVOID iValue)
{
CIpAddressDlg *pp = (CIpAddressDlg*)iValue;
CString c;
char buffer[128];
int sinlen;
struct sockaddr_in sin;
int s, h;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(4000); // Port
s = socket(AF_INET, SOCK_STREAM,0);
bind(s,(struct sockaddr*)&sin,sizeof(sin));
listen(s,1);
sinlen = sizeof(sin);
h=accept(s,(struct sockaddr*)&sin,&sinlen );
//get IP address
int len = sizeof sin;
if(::getsockname(h,(struct sockaddr*)&sin,&len) == -1)
pp->MessageBox("Error local host ip");
c.Format("%d\nlocal addr %s:%u\n errno: %d", sin.sin_addr, inet_ntoa(sin.sin_addr),ntohs(sin.sin_port), errno);
pp->MessageBox(c);
//verification of send
recv(h,buffer,sizeof(buffer),0);
pp->MessageBox(buffer);
send(h,buffer,strlen(buffer),0);
::closesocket(s);
return 0;
}
DWORD WINAPI CIpAddressDlg::Thread_TcpClient(LPVOID iValue)
{
CIpAddressDlg *pp = (CIpAddressDlg*)iValue;
CString c;
char buffer[128]= "Hello world";
struct sockaddr_in sin;
struct hostent *host;
int s;
host = gethostbyname("localhost");
memcpy(&(sin.sin_addr), host->h_addr,host->h_length);
sin.sin_family = host->h_addrtype;
sin.sin_port = htons(4000);
s = socket(AF_INET, SOCK_STREAM,0);
connect(s, (struct sockaddr*)&sin,sizeof(sin));
send(s,buffer,strlen(buffer)+1,0);
recv(s,buffer,sizeof(buffer),0);
::closesocket(s);
return 0;
}
Despite the intuitive appeal of the concept and, for that matter, widespread belief in said concept, computers do not have IP addresses.
Interfaces have IP addresses.
You can get a list of the interfaces and choose the first one. Unfortunately, getting a list of interfaces in most languages is system dependent.
The usual approach is to just use 0.0.0.0.
There are easier ways to get the "private" / "LAN" IP of the machine your program is running on. Your solution is very ingenuitive though.
I think the most straightforward is probably GetAdaptersAddresses. The example code on the MSDN page seems pretty thorough.
But if that requires a newer compiler version, consider GetAdaptersInfo. See "Method Three" here and some sample code here.
Also, it seems like you could also access the IP address via the WinSock API. See this example.
Lastly, just as a sidenote, there is a function in BSD sockets to do exactly this (getifaddrs()), its just not ported to Windows.
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
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));