diff --git a/README.md b/README.md index a0263bf..250d69b 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ providing fiche-based service all the time on this address `solusipse.net` and t ## Server-side usage ## ``` -usage: fiche [-DepbsdolBuw]. +usage: fiche [-D6epbsdSolBuw]. [-d domain] [-p port] [-s slug size] [-o output directory] [-B buffer size] [-u user name] [-l log file] [-b banlist] [-w whitelist] @@ -189,6 +189,14 @@ fiche -e ----------------- +#### Use IPv6 #### + +this will allow fiche to accept connections from IPv6 clients: + +fiche -6 + +----------------- + #### Examples #### Logging connections with banlist: diff --git a/fiche.c b/fiche.c index ca8136d..9a60195 100644 --- a/fiche.c +++ b/fiche.c @@ -59,8 +59,21 @@ int main(int argc, char **argv) listen_socket = create_socket(); setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval , sizeof(int)); - server_address = set_address(server_address); - bind_to_port(listen_socket, server_address); +#if (HAVE_INET6) + struct sockaddr_in6 server_address6; + if (IPv6) + { + server_address6 = set_address6(server_address6); + bind_to_port6(listen_socket, server_address6); + } + else + { +#else + if (1) { +#endif + server_address = set_address(server_address); + bind_to_port(listen_socket, server_address); + } if (DAEMON) { @@ -81,9 +94,23 @@ int main(int argc, char **argv) void *thread_connection(void *args) { int connection_socket = ((struct thread_arguments *) args ) -> connection_socket; - struct sockaddr_in client_address = ((struct thread_arguments *) args ) -> client_address; - - struct client_data data = get_client_address(client_address); + struct sockaddr_in client_address; + struct client_data data; +#if (HAVE_INET6) + struct sockaddr_in6 client_address6; + if (IPv6) + { + client_address6 = ((struct thread_arguments *) args ) -> client_address6; + data = get_client_address6(client_address6); + } + else + { +#else + if (1) { +#endif + client_address = ((struct thread_arguments *) args ) -> client_address; + data = get_client_address(client_address); + } char buffer[BUFSIZE]; bzero(buffer, BUFSIZE); @@ -139,8 +166,24 @@ void perform_connection(int listen_socket) pthread_t thread_id; struct sockaddr_in client_address; - int address_length = sizeof(client_address); - int connection_socket = accept(listen_socket, (struct sockaddr *) &client_address, (void *) &address_length); + int address_length; + int connection_socket; + +#if (HAVE_INET6) + struct sockaddr_in6 client_address6; + if (IPv6) + { + address_length = sizeof(client_address6); + connection_socket = accept(listen_socket, (struct sockaddr *) &client_address6, (void *) &address_length); + } + else + { +#else + if (1) { +#endif + address_length = sizeof(client_address); + connection_socket = accept(listen_socket, (struct sockaddr *) &client_address, (void *) &address_length); + } struct timeval timeout; timeout.tv_sec = 5; @@ -153,7 +196,12 @@ void perform_connection(int listen_socket) struct thread_arguments arguments; arguments.connection_socket = connection_socket; - arguments.client_address = client_address; +#if (HAVE_INET6) + if (IPv6) + arguments.client_address6 = client_address6; + else +#endif + arguments.client_address = client_address; if (pthread_create(&thread_id, NULL, &thread_connection, &arguments) != 0) error("on thread creation"); @@ -202,6 +250,36 @@ struct client_data get_client_address(struct sockaddr_in client_address) return data; } +#if (HAVE_INET6) +struct client_data get_client_address6(struct sockaddr_in6 client_address6) +{ + struct hostent *hostp; + struct client_data data; + static char hostaddrp[INET6_ADDRSTRLEN]; + + hostp = gethostbyaddr((const char *)&client_address6.sin6_addr, sizeof(client_address6.sin6_addr), AF_INET6); + if (hostp == NULL) + { + printf("WARNING: Couldn't obtain client's hostname\n"); + data.hostname = "n/a"; + } + else + data.hostname = hostp->h_name; + + inet_ntop(AF_INET6, &(client_address6.sin6_addr), hostaddrp, + INET6_ADDRSTRLEN); + if (hostaddrp == NULL) + { + printf("WARNING: Couldn't obtain client's address\n"); + data.ip_address = "n/a"; + } + else + data.ip_address = hostaddrp; + + return data; +} +#endif + void save_log(char *slug, char *hostaddrp, char *h_name) { if (LOG != NULL) @@ -275,7 +353,13 @@ void load_list(char *file_path, int type) int create_socket() { - int lsocket = socket(AF_INET, SOCK_STREAM, 0); + int lsocket; +#if (HAVE_INET6) + if (IPv6) + lsocket = socket(AF_INET6, SOCK_STREAM, 0); + else +#endif + lsocket = socket(AF_INET, SOCK_STREAM, 0); if (lsocket < 0) error("Couldn't open socket"); @@ -292,6 +376,17 @@ struct sockaddr_in set_address(struct sockaddr_in server_address) return server_address; } +#if (HAVE_INET6) +struct sockaddr_in6 set_address6(struct sockaddr_in6 server_address6) +{ + bzero((char *) &server_address6, sizeof(server_address6)); + server_address6.sin6_family = AF_INET6; + server_address6.sin6_addr = in6addr_any; + server_address6.sin6_port = htons((unsigned short)PORT); + return server_address6; +} +#endif + void bind_to_port(int listen_socket, struct sockaddr_in server_address) { if (bind(listen_socket, (struct sockaddr *) &server_address, sizeof(server_address)) < 0) @@ -300,6 +395,16 @@ void bind_to_port(int listen_socket, struct sockaddr_in server_address) error("while starting listening"); } +#if (HAVE_INET6) +void bind_to_port6(int listen_socket, struct sockaddr_in6 server_address6) +{ + if (bind(listen_socket, (struct sockaddr *) &server_address6, sizeof(server_address6)) < 0) + error("while binding to port"); + if (listen(listen_socket, QUEUE_SIZE) < 0) + error("while starting listening"); +} +#endif + void generate_url(char *buffer, char *slug, size_t slug_length, struct client_data data) { int i; @@ -419,12 +524,15 @@ void parse_parameters(int argc, char **argv) { int c; - while ((c = getopt (argc, argv, "DeSp:b:s:d:o:l:B:u:w:")) != -1) + while ((c = getopt (argc, argv, "D6eSp:b:s:d:o:l:B:u:w:")) != -1) switch (c) { case 'D': DAEMON = 1; break; + case '6': + IPv6 = 1; + break; case 'e': snprintf(symbols, sizeof symbols, "%s", "abcdefghijklmnopqrstuvwxyz0123456789-+_=.ABCDEFGHIJKLMNOPQRSTUVWXYZ"); break; @@ -461,7 +569,7 @@ void parse_parameters(int argc, char **argv) load_list(WHITEFILE, 1); break; default: - printf("usage: fiche [-pbsdSolBuw].\n"); + printf("usage: fiche [-D6epbsdSolBuw].\n"); printf(" [-d domain] [-p port] [-s slug_size]\n"); printf(" [-o output directory] [-B buffer_size] [-u user name]\n"); printf(" [-l log file] [-b banlist] [-w whitelist]\n"); diff --git a/fiche.h b/fiche.h index da509a2..9ef6d9c 100644 --- a/fiche.h +++ b/fiche.h @@ -31,6 +31,10 @@ $ cat fiche.c | nc localhost 9999 #ifndef FICHE_H #define FICHE_H +#ifndef HAVE_INET6 +#define HAVE_INET6 1 +#endif + #include #include #include @@ -56,6 +60,7 @@ char *WHITELIST; int DAEMON = 0; int HTTPS = 0; int PORT = 9999; +int IPv6 = 0; int SLUG_SIZE = 4; int BUFSIZE = 32768; int QUEUE_SIZE = 500; @@ -68,6 +73,9 @@ struct thread_arguments { int connection_socket; struct sockaddr_in client_address; +#if (HAVE_INET6) + struct sockaddr_in6 client_address6; +#endif }; struct client_data @@ -81,6 +89,9 @@ int create_directory(char *slug); int check_protocol(char *buffer); void bind_to_port(int listen_socket, struct sockaddr_in serveraddr); +#if (HAVE_INET6) +void bind_to_port6(int listen_socket, struct sockaddr_in6 serveraddr6); +#endif void error(char *buffer); void perform_connection(int listen_socket); void generate_url(char *buffer, char *slug, size_t slug_length, struct client_data data); @@ -99,6 +110,12 @@ char *check_whitelist(char *ip_address); char *get_date(); struct sockaddr_in set_address(struct sockaddr_in serveraddr); +#if (HAVE_INET6) +struct sockaddr_in6 set_address6(struct sockaddr_in6 serveraddr6); +#endif struct client_data get_client_address(struct sockaddr_in client_address); +#if (HAVE_INET6) +struct client_data get_client_address6(struct sockaddr_in6 client_address6); +#endif #endif