5
Lately I’ve been working on several "test codes" to exercise the "head", specifically codes involving the API of sockets of Unix. The most recent code I wrote was a simple server that receives a new connection from a client every 2 seconds. The main idea behind the code was to simply compare customer addresses and see if they weren’t the same who successfully connected on a previous connection.
Here’s the server code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define PORT "9009"
short int check_addr(struct sockaddr aux,
const struct sockaddr *vet, size_t amount)
{
short int rv=0;
struct sockaddr_in *aux4=NULL, *addr4=NULL;
struct sockaddr_in6 *aux6=NULL, *addr6=NULL;
if(aux.sa_family==AF_INET){
aux4=(struct sockaddr_in*)&aux;
addr4=(struct sockaddr_in*)vet;
for(size_t i=0; i<amount; i++){
if(aux4->sin_addr.s_addr==addr4[i].sin_addr.s_addr){
rv=-1;
break;
}
}
}else if(aux.sa_family==AF_INET6){
aux6=(struct sockaddr_in6*)&aux;
addr6=(struct sockaddr_in6*)vet;
for(size_t i=0; i<amount; i++){
if(aux6->sin6_addr.s6_addr==addr6[i].sin6_addr.s6_addr){
rv=-1;
break;
}
}
}else{
rv=-2;
}
return rv;
}
void show_addr(struct sockaddr addr){
char address[1024];
struct sockaddr_in *addr4=NULL;
struct sockaddr_in6 *addr6=NULL;
if(addr.sa_family==AF_INET){
addr4=(struct sockaddr_in*)&addr;
inet_ntop(AF_INET,
&addr4->sin_addr.s_addr, address, INET_ADDRSTRLEN);
}else{
addr6=(struct sockaddr_in6*)&addr;
inet_ntop(AF_INET6,
&addr6->sin6_addr.s6_addr, address, INET6_ADDRSTRLEN);
}
printf("%s\n", address);
}
int make_server_socket(void){
int sockfd;
struct addrinfo *res=NULL, *ptr=NULL, hints;
memset(&hints, 0, sizeof(hints));
hints.ai_flags=AI_PASSIVE;
hints.ai_family=AF_INET6;
hints.ai_socktype=SOCK_STREAM;
hints.ai_protocol=IPPROTO_TCP;
if(getaddrinfo(NULL, PORT, &hints, &res)!=0){
sockfd=-1;
}else{
for(ptr=res; ptr!=NULL; ptr=ptr->ai_next){
if(ptr->ai_family==AF_INET || ptr->ai_family==AF_INET6){
sockfd=socket(ptr->ai_family, SOCK_STREAM, IPPROTO_TCP);
if(sockfd<0){
continue;
}
if(bind(sockfd, ptr->ai_addr, ptr->ai_addrlen)==0){
break;
}
close(sockfd);
}
}
freeaddrinfo(res);
}
return sockfd;
}
int main(void){
int sockfd=make_server_socket();
if(sockfd<0){
exit(1);
}
if(listen(sockfd, 10)<0){
exit(1);
}
int csockfd;
size_t count=0;
struct sockaddr *vet=NULL, aux;
socklen_t addrlen=sizeof(struct sockaddr);
for(size_t i=0; i<1000; i++){
csockfd=accept(sockfd, &aux, &addrlen);
if(csockfd<0){
continue;
}else{
if(check_addr(aux, vet, count)==0){
count++;
vet=realloc(vet, addrlen*count);
vet[i]=aux;
show_addr(vet[i]);
close(csockfd);
}
}
}
close(sockfd);
free(vet);
vet=NULL;
return 0;
}
As not everything in the programming are flowers my server ended up presenting the following problems:
first - The function check_addr()
can only tell the difference between Ipv4, thus making the acceptance of several connections coming from the same client/ip that uses Ipv6. For a better understanding of the problem described here, see below the following demostration:
Accepting connections from a client using IPv6
(AF_INET6
):
zherkezhi@zherkezhi :~/Documents/C$ ./server
2804:d47:1b17:2100::
2804:d47:1b17:2100::
2804:d47:1b17:2100::
2804:d47:1b17:2100::
2804:d47:1b17:2100::
2804:d47:1b17:2100::
2804:d47:1b17:2100::
2804:d47:1b17:2100::
2804:d47:1b17:2100::
2804:d47:1b17:2100::
2804:d47:1b17:2100::
2804:d47:1b17:2100::
Accepting connections from a client using IPv4
(AF_INET
):
zherkezhi@zherkezhi :~/Documents/C$ ./server
192.168.1.123
In the above case, I had made my client try to connect to the 12x server using the first time IPv6
and in the second IPv4
. With Ipv6 presented problems (the one described above) and with IPv4
the same did not occur.
2nd - The function inet_ntop()
apparently is working only with Ipv4, that is, when it comes to Ipv6 the following situation occurs:
Client
zherkezhi@zherkezhi :~/Documents/C$ nc
2804:d47:1b17:2100:XXXX:XXXX:XXXX:XXXX 9009
Server
zherkezhi@zherkezhi :~/Documents/C$ ./server
2804:d47:1b17:2100::
It was to print 2804:d47:1b17:2100:XXXX:XXXX:XXXX:XXXX
and not 2804:d47:1b17:2100::
, that is, the inaccuracy of the address is incorrect/incomplete.
So what would be a possible solution to the problems presented above?
OBS: I didn’t post the client code here because I felt it was unnecessary, since my client is nothing more than a phone call from netcat
every 2 seconds.
but in my case my external Ipv6 does not show these 0’s but other values not 0’s. And in the case of the failure when comparing two Ipv6 to each other? Because the comparison fails?
– user129861
I used the function
memcmp
and did not work, continued accepting the same connections.– user129861