Enviado em 22/06/2021 - 18:42h
TL;DR
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define SERVICE "9009"
#define MAXCONN 3
static int make_server_socket(void) {
int sockfd, ecode;
struct addrinfo hints, *result = NULL, *rp = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
if ((ecode = getaddrinfo(NULL, SERVICE, &hints, &result)) != 0 ) {
fprintf(stderr, "make_server_socket() -> getaddrinfo() -> ERROR: %s\n", gai_strerror(ecode));
exit(EXIT_FAILURE);
}
for (rp = result; rp != NULL; rp = rp->ai_next) {
if ((sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) < 0 ) {
continue;
}
if (bind(sockfd, rp->ai_addr, rp->ai_addrlen) != -1 ) {
break;
}
close(sockfd);
}
if (rp == NULL) {
fprintf(stderr, "make_server_socket() -> socket()/bind() -> ERROR: %s\n", strerror(errno));
close(sockfd);
exit(EXIT_FAILURE);
}
if (listen(sockfd, SOMAXCONN) < 0 ) {
fprintf(stderr, "make_server_socket() -> listen() -> ERROR: %s\n", strerror(errno));
close(sockfd);
exit(EXIT_FAILURE);
}
return sockfd;
}
static int check_addr(int af, const unsigned char *buff_addr, unsigned char **buff_addr_table, size_t count) {
int res = 0;
if (af == AF_INET) {
struct sockaddr_in *addr4 = (struct sockaddr_in*)buff_addr;
for (size_t i = 0; i < count; i++) {
struct sockaddr_in *addr4_from_table = (struct sockaddr_in*)buff_addr_table[i];
if (memcmp(&addr4->sin_addr.s_addr, &addr4_from_table->sin_addr.s_addr, sizeof(addr4->sin_addr.s_addr)) == 0 ) {
res = -1;
}
}
} else if (af == AF_INET6) {
struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)buff_addr;
for(size_t i = 0; i < count; i++) {
struct sockaddr_in6 *addr6_from_table = (struct sockaddr_in6*)buff_addr_table[i];
if (memcmp(&addr6->sin6_addr.s6_addr, &addr6_from_table->sin6_addr.s6_addr, sizeof(addr6->sin6_addr.s6_addr)) == 0 ) {
res = -1;
}
}
} else {
res = -1;
}
return res;
}
static void show_addr(int af, unsigned char *buff_addr) {
char *ip = NULL;
if (af == AF_INET) {
ip = malloc(INET_ADDRSTRLEN * sizeof(*ip));
struct sockaddr_in *addr4 = (struct sockaddr_in*)buff_addr;
if (inet_ntop(af, &addr4->sin_addr.s_addr, ip, INET_ADDRSTRLEN) < 0 ) {
fprintf(stderr, "show_addr() -> inet_ntop() -> ERROR: %s\n", strerror(errno));
} else {
printf("%s\n", ip);
}
} else {
ip = malloc(INET6_ADDRSTRLEN * sizeof(*ip));
struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)buff_addr;
if (inet_ntop(af, &addr6->sin6_addr.s6_addr, ip, INET6_ADDRSTRLEN) < 0 ) {
fprintf(stderr, "show_addr() -> inet_ntop() -> ERROR: %s\n", strerror(errno));
} else {
printf("%s\n", ip);
}
}
free(ip);
}
static unsigned char **realloc_addr_table(unsigned char **buff_addr_table, size_t count, size_t addrlen) {
buff_addr_table = realloc(buff_addr_table, count * sizeof(*buff_addr_table));
if (buff_addr_table == NULL) {
fprintf(stderr, "ERROR: Memory allocation for %zu bytes failed\n", count * sizeof(unsigned char *));
fprintf(stderr, "realloc_addr_table -> realloc() -> ERROR: %s\n", strerror(errno));
}
buff_addr_table[count-1] = calloc(count, addrlen * sizeof(*buff_addr_table));
if (buff_addr_table == NULL) {
fprintf(stderr, "ERROR: Memory allocation for %zu bytes failed\n", count * sizeof(unsigned char *));
fprintf(stderr, "realloc_addr_table -> realloc() -> ERROR: %s\n", strerror(errno));
}
return buff_addr_table;
}
static void free_addr_table(unsigned char **buff_addr_table, size_t count) {
for (size_t i = 0; i < count; i++) {
free(buff_addr_table[i]);
}
free(buff_addr_table);
}
static void search(void) {
size_t i = 0;
int sockfd = make_server_socket();
unsigned char *buff_addr = NULL, **buff_addr_table = NULL;
const char msg_1[] = "Welcome!\n", msg_2[] = "Get out!\n";
while (i < MAXCONN) {
int new_sockfd;
struct sockaddr addr;
socklen_t addrlen = sizeof(addr);
if ((new_sockfd = accept(sockfd, &addr, &addrlen)) < 0 ) {
fprintf(stderr, "search() -> accept() -> ERROR: %s\n", strerror(errno));
} else {
buff_addr = (unsigned char *)&addr;
if (check_addr(addr.sa_family, buff_addr, buff_addr_table, i) != -1 ) {
i++;
buff_addr_table = realloc_addr_table(buff_addr_table, i, addrlen);
memcpy(buff_addr_table[i-1], &addr, addrlen * sizeof(*buff_addr_table));
show_addr(addr.sa_family, buff_addr);
send(new_sockfd, msg_1, sizeof(msg_1), 0);
}else{
send(new_sockfd, msg_2, sizeof(msg_2), 0);
}
close(new_sockfd);
}
}
free_addr_table(buff_addr_table, i);
close(sockfd);
}
int main(void) {
search();
return EXIT_SUCCESS;
}
[AB2201@fedora TCP]$ gcc -Wall server.c -o server
[AB2201@fedora TCP]$ ./server
::d00:0:0:0
[AB2201@fedora TCP]$ nc 127.0.0.1 9009
Welcome!
^C
[AB2201@fedora TCP]$ nc ::1 9009
Get out!
^C
[AB2201@fedora TCP]$ nc 192.168.1.107 9009
Get out!
^C
[AB2201@fedora TCP]$
::ffff:127.0.0.1
::1
::ffff:192.168.1.107