getpeername Invalid argument after running a server several times - c

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.

Related

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 address from a socket fd (not duplicate) [duplicate]

This question already has an answer here:
getpeername always gives bad file descriptor
(1 answer)
Closed 8 years ago.
I am attaching my process (with root privileges) to a browser process to intercepts its system calls using ptrace. To decode the parameters of the connect() system call i got the sockfd. But i have been trying from days to get the ip address of the other end of that socket but with no success.
i came accross these 2 questions while looking around
1)Get IP address from socket descriptor?
2)Getting IP address, port and connection type from a socket fd
I followed the suggestion of the 1st question, but somehow it was giving error. something error: ‘struct sockaddr_in’ has no member named ‘sa_data’. I digged deeper into the internet and got another hint, which i used to write this code
temp = getpeername(regs.rdi, (struct sockaddr *)&ip_addr_struct, &ip_addr_structlen);
struct sockaddr_in *s = (struct sockaddr_in *)&ip_addr_struct;
int port = ntohs(s->sin_port);
inet_ntop(AF_INET, &s->sin_addr, ip_addr, 1024);
printf("%d-%s\n", port, ip_addr);
here regs.rdi is the sockfd. But even with this code everytime i get 0-0.0.0.0
as output. please help anyone. Is there any other way to get the ip addrres or am i doing something wrong?
If your requirement is to get the IP address of the connecting client, use this :)
struct sockaddr_in their_addr;
if ((*cli_fd = accept(listener, (struct sockaddr *)&their_addr,&sin_size)) == -1)
{
close (*cli_fd);
return -1;
}
This is the client ip address ==> inet_ntoa(their_addr.sin_addr)

inet_ntop returns 0.0.0.0 in first usage

I'm trying to write server application. I want to get client's ip. My problem is with inet_ntop function. I can't get it working properly. Here is my usage :
void client_loop(uint16_t port) {
int cfd;
int socket = bind_socket(port, INADDR_ANY);
char ip[INET_ADDRSTRLEN];
struct sockaddr client_addr;
struct sockaddr_in *addr_in;
socklen_t cli_len;
while (work) {
if ((cfd = TEMP_FAILURE_RETRY(accept(socket, &client_addr, &cli_len))) < 0) {
if (EAGAIN == errno || EWOULDBLOCK == errno)
continue;
ERR("accept");
}
addr_in=(struct sockaddr_in *)&client_addr;
inet_ntop(AF_INET, &(addr_in->sin_addr),ip, sizeof(ip));
printf("INET_NTOP: %s\n",ip);
}
}
First usage of inet_ntop always returns 0.0.0.0 Then it works properly. When im moving inet_ntop to outside function it works properly only for connections from localhost. Thanks.
EDIT:
Fixed. The problem was that cli_len wasn't initialized so accept wasn't filling client_addr.
With this line its working like a boss:
socklen_t cli_len=sizeof(struct sockaddr);
i couldn't find the issue, but i see that you have given cli_len as argument, but you have to use sizeof(ip) in place of the 4 th argument (cli_len) of inet_ntop. and also please check for the cli_len also before calling inet_ntop

Identifying the problems with connect( )

I have been working on a proxy server. It has to connect to another "monitor" program and get connection address information from that program. That program in running on a known ip and port. If I use the following to connect it works fine:
struct hostent *serv;
int sockfd;
struct sockaddr_in serv_addr;
serv = gethostbyname("localhost");
sockfd = socket(AF)INET, SOCK_STREAM, 0);
if (sockfd < 0)
/* Error handling */
bzero((char *) &serv_addr, sizeof (serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *) server->h_addr, (char *) &serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(portno); // portno is an int holding the port number
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
/* error handling */
However I wanted to use the exact ip address instead of local host, they may not alway be on the same machine, and gethostbyname () is obsolete. I attempted to use getaddrinfo() like this:
struct addrinfo hints, *server;
int sockfd, i;
char *host = "192.168.2.4";
char *port = "4044";
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = 0;
hints.ai_protocol = IPPROTO_TCP; // have also tried it with 0
i = getaddrinfo(host, port, &hints, &server);
if (i != 0)
/* Error handling */
sockfd = socket(server->ai_family, server->ai_socktype, server->ai_protocol);
freeaddrinfo (server); // have also tried without this line
if (sockfd < 0)
/* Error handling */
printf("Attempting to connect\n");
if (connect(sockfd, server->ai_addr, server->ai_addrlen) != -1)
/* Error handling */
printf("Connection attempt complete\n");
This second attempt hangs for a long time on the connect() command and finally returns in error. I have gone over the examples in several places and searched previous questions here on stackoverflow but can't find the problem, or why one works and the other doesn't. I think it has something to do with the server->ai_addr value but have not been able to verify it yet.
Any help would be appreciated, am I doing something obviously wrong? I don't know where else to look for more ideas to check.
EDIT UPDATE:
I have figured out one problem. In the line if (connect (/* */) != -1)
it should have been != 0. One of the samples I was looking at used a bind() statement instead. If I use the local host address with the second may it will work with that change. However I still can't connect to a specific ip address node. I am beginning to suspect that the ip address I was given isn't one that this computer can receive network traffic on. I am not sure how to check that though. I will see If I can figure out any more info on the error with using the specific ip address and edit again with the information.
EDIT UPDATE: I added #include and tried to print out the error code after the system call returns. I also printed out the return. It returns a -1 which according to the documentation I found just means an error occurred when I try to print out the errno it seg faults.
fprintf(stderr, "Error Code %s\n", errno); // seg faults
However changing it to:
fprintf(stderr, "Error Code %d\n", errno); // returns Error Code 60
Try to replace
hints.ai_flags = 0;
with
hints.ai_flags = AI_NUMERICHOST;
and see what happens.
The ip address that I was given is not the ip on the computer I am using. I finally decided that the ip address had to be the problem. I found the ip address on my computer and got the server program to bind to it. I also put it in as the ip address for the code included above instead of local host and it was able to connect regardless of rather the server was on that specific ip address or simply connected to INADDR_ANY.

getpeername() Returns Wrong Data

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.

Resources