I have recently been working on a number of "test-codes" to exercise the "head", specifically codes involving Unix sockets . The most recent code I wrote was a simple server that receives a new connection from one client every 2 seconds. The main idea behind the code was to simply compare the clients' addresses and see if they were not the same ones that successfully connected to a previous connection.
Here is 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 is flowers my server ended up presenting the following problems:
1st - The function check_addr()
can only notice 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 the following demostration below:
Accepting client connections 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 client connections using IPv4
( AF_INET
):
zherkezhi@zherkezhi :~/Documents/C$ ./server
192.168.1.123
In the case above, I had my client try to connect to the 12x server using the first time IPv6
and the second IPv4
. With IPv6 presented problems (the one described above) and with IPv4
the same did not occur.
2nd - The function inet_ntop()
seems to be working only with IPv4 , that is, when it comes to IPv6 :
Customer
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 address printing is incorrect / incomplete.
So what would be a possible solution to the problems presented above?
NOTE: I did not post client code here because I found it unnecessary, since my client is only a netcat
call every 2 seconds.