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

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.

Related

What is the socket address family defined by 30?

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]

How to find out IP address of a given process connected through TCP

So I want to obtain the address of the machine a process (subscriber) is working on, so I can send it in a message to the server (intermediary), next to a specific port, so the server can answer on that other port.
That is, they are going to be connected, but I want the answer in another port. So I want to forward the port next to the address of the suscriber so the server can connect.
I believe ONE way of doing it would be similar to an example found
http://beej.us/guide/bgnet/output/html/multipage/getaddrinfoman.html
so I would use getaddrinfo to do something like this
if ((rv = getaddrinfo(NULL, "3490", &hints, &servinfo)) != 0) {
and then I would look in the linked list for the address in
dir_tcp_srv.sin_addr.s_addr
But I think this is in fact not the correct use. I don't fully understand but I believe this is not quite the way of doing it.
I guess there are many ways of doing this but essentially I want to obtain the data (I already have the port number) so that the client and server roles switch, and the server makes a connection to the client
Edit: Ok so I'm reading time and time again how the server knows the address of the client once it's connected. I'm re-reading man pages to know how to obtain that info but can't find it yet.
Also, I found this:
https://suite.io/guy-lecky-thompson/7sd21g
But I can't say I quite get it.
Edit2: I think I've had a concept wrong for a long time.
In my code I make accept like this:
fdSocketDevuelto = accept(sock_tcp, (struct sockaddr )&dir_tcp_srv, (socklen_t) &sizeSock);
Which I now believe is overwriting the info previously stored in the struct, that I used to bind, listen, all that, with the client's info. If someone can confirm this I can comment to my own question with this as the answer or delete the whole thing since it was something I never fully understood/used.
I understand the question as you are wanting to have server find the client's IP address and Port. Take a look at getpeername():
From Beej's guide:
http://beej.us/guide/bgnet/output/html/multipage/getpeernameman.html
// assume s is a connected socket
socklen_t len;
struct sockaddr_storage addr;
char ipstr[INET6_ADDRSTRLEN];
int port;
len = sizeof addr;
getpeername(s, (struct sockaddr*)&addr, &len);
// deal with both IPv4 and IPv6:
if (addr.ss_family == AF_INET) {
struct sockaddr_in *s = (struct sockaddr_in *)&addr;
port = ntohs(s->sin_port);
inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
} else { // AF_INET6
struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr;
port = ntohs(s->sin6_port);
inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr);
}
printf("Peer IP address: %s\n", ipstr);
printf("Peer port : %d\n", port);

Getting IP adress associated to REAL hardware ethernet controller in Windows C

I tried to search for it but I could'nt find any working soultions.
Nowadays Windows can detect more than ONE PROPER HARDWARE installed eternet controlled due to Hamachi, Virtual box etc etc.
Now i need to get the real IP adress of machine. When i tried do it by using gethostbyname it returned IP adress of my Hamachi client.
Now I need to find 100% solid method to receive real ip adress. Any links/tips/articles/methods really appreciate.
EDIT:
So far got this - method sugested by Remy Lebau, but it doesn't work the way I want - always returning 127.0.0.1:
int main()
{
WSADATA WSA_info;
if (WSAStartup(MAKEWORD(2,2),&WSA_info)!=0)
{
std::cout << "Error with WSA.\n";
std::cin.get();
return -1;
}
SOCKADDR_IN adress;
adress.sin_family = AF_INET;
adress.sin_port = htons(80);
adress.sin_addr.S_un.S_addr = inet_addr("213.241.88.40"); //its google's IP adress - to chech it I used ping google.com in cmd (maybe there is somethign wrong with this)
SOCKET sock;
if ((sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))== INVALID_SOCKET){
std::cout << "Error while creating socket." << std::endl;
closesocket(sock);
WSACleanup();
std::cin.get();
return -1;
}
if (connect(sock,(sockaddr*)&adress,sizeof(sockaddr))== SOCKET_ERROR) {
std::cout << "Couldnt connect." << std::endl;
closesocket(sock);
WSACleanup();
std::cin.get();
return -1;
}
sockaddr_in test;
int len = sizeof(test);
getsockname(sock,(struct sockaddr *) &test, &len);
std::cout << inet_ntoa(test.sin_addr);
std::cin.get();
}
A PC can be connected to multiple networks at the same time (Internet, VM, VPN, etc), each with its own IP address, and you could initialize sockets on any of them at the same time and it would work. And more and more common, PCs are getting their Internet access from home router/ICS connections, not directly from Internet modems.
So what "real IP address" are you looking for? The PC can have multiple IP addresses, and they are all "real" as far as the OS cares.
If you just want to enumerate the available local IP addresses, you can use GetAdaptersInfo() or GetAdaptersAddresses(). DO NOT use gethostbyname() to discover local IP addresses - that is not what it is meant for, and it can report false information!
I think the question you actually want to ask is - how do I find the IP of the Ethernet controller used to access the Internet - am I right?
For that, you will have to connect() an unbound socket to an outside server that is running on the Internet, and if successful then you can use getsockname() to find out which local IP address the OS bound the socket to, for example:
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
sockaddr_in remoteaddr = {0};
remoteaddr.sin_family = AF_INET;
remoteaddr.sin_addr.s_addr = inet_addr("remote ip address");
remoteaddr.sin_port = htons(80);
if (connect(sock, (sock_addr*)&remoteaddr, sizeof(remoteaddr)) == 0)
{
sockaddr_in localaddr = {0};
int len = sizeof(localaddr);
getsockname(sock, (sock_addr*)&localaddr, &len);
// use localaddr as needed...
}
closesocket(sock);
But that is only going to tell you the IP address on the local PC. If you are behind a router/ICS, that is not going to be the same IP address that the Internet uses to send packets to your PC. To get that IP address, you can connect to and query an outside iplookup service, such as http://whatismyip.com, and see what IP address it reports back to you.

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.

Get IP address of my computer on a local network by way of BSD sockets?

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.

Resources