I am writing my first sockets program on Linux and am trying to print the IP address and port of the peer I have connected to. I use getpeername() along with inet_ntop() and ntohs() to get the data out of the sockaddr_in struct. When I look at the results, I get an IP address that does not go to any server that I know of (ping fails) and says that I am listening to a port that netstat says is not being used.
What am I doing wrong? I should be getting 130.215.28.181:39000, but instead I am getting 209.94.72.137:18825 every time I run the program. Looking at netstat shows that I am indeed listening on port 39000.
Here is a snippet from my client program:
connect(sockfd,&serv_addr,sizeof(serv_addr))
// print welcome message
char ipstr[INET6_ADDRSTRLEN];
bzero(ipstr, 50);
struct sockaddr_in *address;
socklen_t address_len = sizeof(*address);
getpeername(sockfd, (struct sockaddr *) address, &address_len);
inet_ntop(AF_INET, &address->sin_addr, ipstr, sizeof(ipstr));
printf("Connection established successfully with %s:%i!\n", ipstr, ntohs(address->sin_port));
You're not allocating any memory for your sockaddr_in structure, you's just passing a pointer to some random memory location. Instead, allocate the address structure on the stack:
struct sockaddr_in addr;
socklen_t addr_len = sizeof(addr);
int err = getpeername(sockfd, (struct sockaddr *) &addr, &addr_len);
if (err != 0) {
// error
}
You should also be checking the return value of every function that is documented to return an error code. In particular, both connect and getpeername return error codes that you should be checking.
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]
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);
I've got this, taken from beej guide and slightly adapted:
socklen_t len;
struct sockaddr_storage addr;
char ipstr[INET6_ADDRSTRLEN];
char nombreSubscriptor[INET6_ADDRSTRLEN+sizeof(int)];
int port;
len = sizeof(addr);
if(getpeername(fdSocketDevuelto, (struct sockaddr*)&addr, &len)<0){
perror("GETPEERNAME error");
close(fdSocketDevuelto);
exit(1);
}
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);
So I run the client and server and send messages to the server, everything works fine, showing like this
Peer IP address: 127.0.0.1
Peer port : 42639
But if I close and open several times (sometimes it's in the first 1-2 times I try it, but this has happened less), at some point I'm getting this:
GETPEERNAME error: Invalid argument
And before I used the perror and exit(1) in the getpeername I was getting stuff similar to this (it changed slightly in the numbers):
Peer IP address: 2325:2ec7:c37f::
Peer port : 20423
I had already asked here Recv gives Bad file descriptor only sometimes (run the program it works fine, sometimes it does not work) but the question is flat out wrong since it's not the recv that has the failure, it's the getpeername function. And I decided to ask again with proper data this time, which I'm unsure if it's the right thing to do.
The question is: why would this happen? Why sometimes it passes and Ip is fine and sometimes is not? It's two completly different runs of the code, I close and run again, and do not compile or do anything. When it gives me the failure, I wait some minutes (this also looks to be changing from time to time) and I can run again and it works just fine again.
I want to get the IP address of the client who’s just connected into my server running WinSock2. I’m using C.
You could get the client's IP-address and port via the call to accept().
Just pass in the appropriate data into the last two parameters.
struct sockaddr_in sa = {0}; /* for TCP/IP */
socklen_t socklen = sizeof sa;
... = accept(..., (struct sockaddr *) &sa, &socklen);
For details please read here.
Have not done it myself, but take a look at getpeername. Looks like this is what you need.
This work for me on winsock2. No need of getpeername
SOCKET newConnection;
SOCKADDR_IN addr;
int addrlen = sizeof(addr);
newConnection = accept(sListen, (SOCKADDR*)&addr, &addrlen);
char *ip = inet_ntoa(addr.sin_addr);
printf("Accepted Connection from : %s", ip);
I've got a sockaddr_storage containing the ipv4 address and port of a remote host. I haven't seen these structs before though and I'm not sure how to cast it into a struct where I can directly retrieve IP address and port number. I've tried googling the struct but haven't found anything. Any suggestions on how to do this?
Thanks
You can cast the pointer to struct sockaddr_in * or struct sockaddr_in6 * and access the members directly, but that's going to open a can of worms about aliasing violations and miscompilation issues.
A better approach would be to pass the pointer to getnameinfo with the NI_NUMERICHOST and NI_NUMERICSERV flags to get a string representation of the address and port. This has the advantage that it supports both IPv4 and IPv6 with no additional code, and in theory supports all future address types too. You might have to cast the pointer to void * (or struct sockaddr * explicitly, if you're using C++) to pass it to getnameinfo, but this should not cause problems.
To extend an answer above and provide a code that uses getnameinfo function, check this snippet:
struct sockaddr_storage client_addr;
socklen_t client_len = sizeof(struct sockaddr_storage);
// Accept client request
int client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_len);
char hoststr[NI_MAXHOST];
char portstr[NI_MAXSERV];
int rc = getnameinfo((struct sockaddr *)&client_addr, client_len, hoststr, sizeof(hoststr), portstr, sizeof(portstr), NI_NUMERICHOST | NI_NUMERICSERV);
if (rc == 0) printf("New connection from %s %s", hoststr, portstr);
The result is that a hoststr contains an IP address from struct sockaddr_storage and a portstr contains a port respectively.