diff options
-rw-r--r-- | Changelog | 13 | ||||
-rw-r--r-- | Makefile | 22 | ||||
-rw-r--r-- | README | 284 | ||||
-rw-r--r-- | activefor.h | 23 | ||||
-rw-r--r-- | afclient.c | 1246 | ||||
-rw-r--r-- | afserver.c | 365 | ||||
-rw-r--r-- | buflist.c | 69 | ||||
-rw-r--r-- | buflist.h | 35 | ||||
-rw-r--r-- | docs/en/README | 284 | ||||
-rw-r--r-- | exmodule.c | 66 | ||||
-rw-r--r-- | file.c | 280 | ||||
-rw-r--r-- | network.c | 150 | ||||
-rw-r--r-- | network.h | 6 |
13 files changed, 1974 insertions, 869 deletions
@@ -1,6 +1,17 @@ +26.05.2004 (v0.5.4): + - Fixed: default password incompatibilities + - Modified: Server listening behaviour + - Added: Module support for client's packet filtering + - Modified: client behaviour after unsuccessful connection + - Fixed: printing ipv6 addresses + - Added: IP protocol family strict choice: 'ipv4' and 'ipv6' + - Added: flow control / packet buffering + - Fixed: signal handling + - Fixed: client freeze in udp reverse mode with zlib enabled + 09.01.2004 (v0.5.3): - Added: client password identification (weak) - - Added: sigint intercepting and server closing + - Added: sigint interception and server closing - Modified: communication between server and client - Added: 'nossl' and 'nozlib' modes - Added: zlib support @@ -5,20 +5,18 @@ security=server.rsa client.rsa cacert.pem all: compi $(programs) ok1 secure -afserver: afserver.c network.o file.o stats.o - $(CC) $(CFLAGS) -lssl -lz afserver.c network.o file.o stats.o -o afserver +afserver: afserver.c network.o file.o stats.o buflist.o + $(CC) $(CFLAGS) -lssl -lz afserver.c network.o file.o stats.o buflist.o -o afserver -afclient: afclient.c network.o stats.o - $(CC) $(CFLAGS) -lssl -lz afclient.c network.o stats.o -o afclient +afclient: afclient.c network.o stats.o buflist.o + $(CC) $(CFLAGS) -rdynamic -lssl -lz -ldl afclient.c network.o stats.o buflist.o -o afclient -network.o: network.c network.h - $(CC) $(CFLAGS) -c network.c +%.o: %.c %.h + $(CC) $(CFLAGS) -c $*.c -file.o: file.c file.h - $(CC) $(CFLAGS) -c file.c - -stats.o: stats.c stats.h - $(CC) $(CFLAGS) -c stats.c +exmodule: exmodule.c + $(CC) -fPIC $(CFLAGS) -c $@.c + $(CC) $(CFLAGS) -shared -o $@ $@.o secure: crea $(security) ok2 @@ -47,4 +45,4 @@ ok2: .PHONY: clean clean: - rm -rf a.out *~ *.o $(programs) $(security) + rm -rf a.out *~ *.o $(programs) $(security) exmodule @@ -1,4 +1,4 @@ -AF - Active Port Forwarder v0.5.3 - README +AF - Active Port Forwarder v0.5.4 - README Copyright (C) 2003,2004 jeremian - <jeremian [at] poczta.fm> =================== @@ -7,85 +7,287 @@ Copyright (C) 2003,2004 jeremian - <jeremian [at] poczta.fm> GRAY-WORLD.NET / Active Port Forwarder ========================== - The Active Port Forwarder program is part of the Gray-World.net projects. + The Active Port Forwarder program is part of the Gray-World.net projects. Our Gray-World Team presents on the http://gray-world.net website the projects - and publications we are working on which are related to the NACS (Network - Access Control System) bypassing research field and to the computer and + and publications we are working on which are related to the NACS (Network + Access Control System) bypassing research field and to the computer and network security topics. ================================================================================ +======= +SUMMARY +======= -Active port forwarder is a software for secure port forwarding. -It uses ssl for increasing security of communication between server and client. +INTRO -Af is dedicated for people, who don't have external ip number and want to +1. INSTALLATION + 1.1 Instructions + 1.2 Required libs + 1.3 Tested platforms +2. USAGE + 2.1 afserver + 2.2 afclient +3. EXAMPLES + 3.1 tcp mode + 3.2 reverse udp mode +4. BUGS/PROBLEMS + +NOTES + +THANKS + +================================================================================ + +===== +INTRO +===== + +Active port forwarder is a software tool for secure port forwarding. +It uses ssl to increase security of communication between a server and a client. +Originally, it was developed to forward data point to point. However, the need +for bypassing firewalls in order to connect to internally located computers +influenced the further development of the project. + +AF is dedicated for people, who don't have an external ip number and want to make some services available across the net. -Moreover, zlib is used to compress transfered data. +Moreover, zlib is used to compress the transferred data. + +Using one, permanent data/control channel with flow control / packet buffering +provides good performance and reasonably small latency. + +================================================================================ + +=============== +1. INSTALLATION +=============== + + 1.1 Instructions + ---------------- + +1. Download the compressed sources from http://www.gray-world.net/pr_af.shtml +2. Unpack them with tar zxvf +3. Type "make". +4. If something goes wrong - mail the author or post a message on + http://gray-world.net/board/ + + 1.2 Required libs + ----------------- + +1. openssl - http://www.openssl.org/ +2. zlib - http://www.gzip.org/zlib/ + + 1.3 Tested platforms + -------------------- + +1. Linux: + Gentoo, Slackware, Mandrake - built without any problems +2. Freebsd: + 4.4, 4.9 - have to use patch from project homepage +3. Windows: + win32 - cygwin version is available on the project homepage + +================================================================================ + +======== +2. USAGE +======== + + 2.1 afserver + ------------ + + Options: + -h, --help - prints this help + -n, --hostname - it's used when creating listening sockets + (default: name returned by hostname function) + -l, --listenport - listening port number - users connect + to it (default: 50127) + -m, --manageport - manage port number - second part of the active + port forwarder connects to it (default: 50126) + -u, --users - the amount of users allowed to use this server + (default: 5) + -c, --cerfile - the name of the file with certificate + (default: cacert.pem) + -k, --keyfile - the name of the file with RSA key (default: server.rsa) + -f, --cfgfile - the name of the file with the configuration for the + active forwarder (server) + -p, --proto - type of server (tcp|udp) - for which protocol it will be + operating (default: tcp) + -O, --heavylog - logging everything to a logfile + -o, --lightlog - logging some data to a logfile + -v, --verbose - to be verbose - program won't enter the daemon mode + (use several times for greater effect) + --nossl - ssl is not used for transferring data (but it's still + used to establish a connection) (default: ssl is used) + --nozlib - zlib is not used for compressing data (default: + zlib is used) + --pass - set the password used for client identification + (default: no password) + -4, --ipv4 - use ipv4 only + -6, --ipv6 - use ipv6 only -EXAMPLE 1: + 2.2 afclient + ------------ -The use of it is extremely simple. Let's suppose we want to create http server on -our computer and we are behind masquerade or firewall: + Options: + -h, --help - prints this help + -n, --servername - where the second part of the active + port forwarder is running (required) + -m, --manageport - manage port number - server must be + listening on it (default: 50126) + -d, --hostname - the name of this host/remote host - the final + destination of the packets (default: the name + returned by hostname function) + -p, --portnum - the port we are forwarding the connection to (required) + -k, --keyfile - the name of the file with RSA key (default: client.rsa) + -u, --udpmode - udp mode - client will use udp protocol to + communicate with the hostname + -U, --reverseudp - reverse udp forwarding. Udp packets will be forwarded + from hostname:portnum (-p) to the server name:portnum + (-m) + -O, --heavylog - logging everything to a logfile + -o, --lightlog - logging some data to a logfile + -v, --verbose - to be verbose - program won't enter the daemon mode + (use several times for greater effect) + --pass - set the password used for client identification + (default: no password) + -4, --ipv4 - use ipv4 only + -6, --ipv6 - use ipv6 only + -l, --load - load a module for packets filtering + +================================================================================ + +=========== +3. EXAMPLES +=========== + + 3.1 tcp mode + ------------ + + local network |FireWall| Internet + || + || User 1 + || /(tcp) + AF Client <---Encrypted/Compressed channel---> AF Server + / || | \(tcp) + /(tcp) || (tcp)| User 2 + / || \ + Http server || User 3 + || -1) We have to find some machine on the net with external ip and shell account. -2) Use make to compile everything on that machine. (you can freely remove afclient - and client.rsa files) +The use of it is extremely simple. Let's suppose we want to create a http server +on our computer and we are behind a masquerade or a firewall: -3) You can edit config file or just type from the console: (to use config type -f <cfgfile>) - $ ./afserver +1) We have to find some machine on the net with an external ip and a shell + account. + +2) Use "make" to compile everything on that machine. (you can freely remove the + afclient and client.rsa files) + +3) You can edit the config file or just type from the console (to use the config + type -f <cfgfile>) : + $ ./afserver This will work, if you want to use default values: - - hostname will be taken from hostname function (it would be ideally, if there is - appropriate registration in /etc/hosts) + - hostname will be taken from hostname function (it would be ideally, if + there is appropriate registration in /etc/hosts) - server will be listening for users on port 50127 - server will be listening for client on port 50126 - server will be for maximum 5 users - server will forward tcp packets - there will be no logging and no verbose messages - there will be no password identification + - ip protocol family will be unspecified -4) We use make on our machine (we can delete everything apart afclient and client.rsa) +4) We use "make" on our machine (we can delete everything apart from afclient + and client.rsa) 5) We are typing from the console: - $ ./afclient -n <name of the server> -p 80 - Where <name of the server> is a string like : 'bastion.univ.gda.pl' or '153.19.7.200' + $ ./afclient -n <name of the server> -p 80 + Where <name of the server> is a string like : 'bastion.univ.gda.pl' or + '153.19.7.200' + +6) We can now enter with a web-browser to: <name of the server>:50127 and we + will enter to our computer in the fact. + + 3.2 reverse udp mode + -------------------- -6) We can now enter with webbrowser to : <name of the server>:50127 and we will enter to our - computer in the fact. + local network |FireWall| Internet + || (udp) + || User 1-------AF Client + || /(tcp) + AF Client <---Encrypted/Compressed channel---> AF Server + / || | + /(udp) || (tcp)| + / || / + Game server || AF Client-------User 2 + || (udp) -EXAMPLE 2: -Let's see how to use af to forward udp packets. Suppose we want to create a game server -on our computer (udp port 27960 on our machine): +Let's see how to use af to forward udp packets. Suppose we want to create a game +server on our computer (udp port 27960 on our machine): -1) - 4) is the same like in example 1. (but we add option: -t udp) +1) - 4) is the same like in example 1. (but we add option: -p udp) 5) We are typing from the console: $ ./afclient -u -n <name of the server> -p 27960 - Where <name of the server> is a name (or ip) of a host where our server is running. + Where <name of the server> is a name (or ip) of a host where our server is + running. + +6) Connecting to our game is more complicated. The user must use afclient to do + this. He has to specify the server he is connecting to and the port, which + his program will be listening on: + $ ./afclient -U -d <hostname> -p <portnum> -n <name of the server> \ + -m <server port> + Where <hostname> is the name of the user machine (who wants to connect to our + game). <portnum> is the port he will be connecting to. <name of the server> + is the name of the host where our server is running. <server port> is the + port on which the server is listening for users. In order to connect to our + game, the user has to connect to <hostname>:<portnum>. + +================================================================================ + +================ +4. BUGS/PROBLEMS +================ + +There are no known/open bugs at the moment. + +================================================================================ + +===== +NOTES +===== + +Active port forwarder is still under development, so please sent any comments, +bugs notices and suggestions about it to <jeremian [at] poczta.fm> + +If you have some problems or want to share your opinions with others, feel free +to post a message at http://gray-world.net/board/ + +================================================================================ -6) Connecting to our game is more complicated. User must use afclient to do this. - He has to specify server he is connecting to and port which his program will be listening on: - $ ./afclient -U -d <hostname> -p <portnum> -n <name of the server> -m <server port> - Where <hostname> is name of user machine (who wants to connect to our game). <portnum> - is a port he will be connecting to. <name of the server> is a name of a host where our server - is running. <server port> is a port on which server is listening for users. - In order to connect to our game, user have to connect to <hostname>:<portnum>. +====== +THANKS +====== + Big thanks to the GW Team: -Active port forwarder is still under development, so please sent me any comments, bugs notices -and suggestions about it to jeremian@poczta.fm + to Alex <alex [at] gray-world.net> + and Simon <scastro [at] entreelibre.com> for testing AF and a lot of advices. + Thanks to Ilia Perevezentsev <iliaper [at] mail.ru> who read and corrected the +README file. -And thanks for using this software! + And thanks for using this software! LICENSE ------- - Active Port Forwarder is distributed under the terms of the GNU General Public License - v2.0 and is copyright (c) 2003 jeremian <jeremian [at] poczta.fm>. - See the file COPYING for details. + Active Port Forwarder is distributed under the terms of the GNU General + Public License v2.0 and is copyright (c) 2003,2004 jeremian <jeremian [at] + poczta.fm>. See the file COPYING for details. diff --git a/activefor.h b/activefor.h index aa08149..4c819c0 100644 --- a/activefor.h +++ b/activefor.h @@ -22,26 +22,32 @@ #define _JS_ACTIVEFOR_H #include "network.h" +#include "buflist.h" #define AF_S_CONCLOSED 1 #define AF_S_CONOPEN 2 #define AF_S_MESSAGE 3 #define AF_S_CLOSING 4 #define AF_S_LOGIN 8 +#define AF_S_DONT_SEND 9 +#define AF_S_CAN_SEND 10 +#define AF_S_CANT_OPEN 12 #define S_STATE_CLEAR 0 #define S_STATE_CLOSING 5 #define S_STATE_OPENING 6 #define S_STATE_OPEN 7 +#define S_STATE_STOPPED 11 -#define AF_VER(info) info" v0.5.3" +#define AF_VER(info) info" v0.5.4" #define TYPE_TCP 1 #define TYPE_UDP 3 #define TYPE_SSL 4 #define TYPE_ZLIB 8 +#define TYPE_IPV4 16 +#define TYPE_IPV6 32 #define TYPE_COMP 0x4000 -#define TYPE_NOTCOMP (~TYPE_COMP) #define TYPE_SET_ZERO(type) (type=0) #define TYPE_IS_SET(type) (type&1) @@ -55,12 +61,25 @@ #define TYPE_SET_ZLIB(type) (type|=TYPE_ZLIB) #define TYPE_UNSET_ZLIB(type) (type&=(~TYPE_ZLIB)) #define TYPE_IS_ZLIB(type) (type&TYPE_ZLIB) + +#define TYPE_SET_IPV4(type) (type|=TYPE_IPV4) +#define TYPE_UNSET_IPV4(type) (type&=(~TYPE_IPV4)) +#define TYPE_IS_IPV4(type) (type&TYPE_IPV4) +#define TYPE_SET_IPV6(type) (type|=TYPE_IPV6) +#define TYPE_UNSET_IPV6(type) (type&=(~TYPE_IPV6)) +#define TYPE_IS_IPV6(type) (type&TYPE_IPV6) +#define TYPE_SET_UNSPEC(type) (type&=(~(TYPE_IPV4|TYPE_IPV6))) +#define TYPE_IS_UNSPEC(type) (!(type&(TYPE_IPV4|TYPE_IPV6))) + #define TYPE_SET_COMP(type) (type|=TYPE_COMP) #define TYPE_IS_COMP(type) (type&TYPE_COMP) typedef struct { char state; int connfd; + char namebuf[128]; + char portbuf[7]; + blnodeT* head; } ConnectuserT; #endif @@ -29,6 +29,8 @@ #include <linux/sockios.h> #include <signal.h> #include <string.h> +#include <fcntl.h> +#include <dlfcn.h> #include <getopt.h> @@ -36,557 +38,791 @@ static void usage(char* info); static void sig_int(int); static struct option long_options[] = { - {"help", 0, 0, 'h'}, - {"udpmode", 0, 0, 'u'}, - {"reverseudp", 0, 0, 'U'}, - {"servername", 1, 0, 'n'}, - {"manageport", 1, 0, 'm'}, - {"hostname", 1, 0, 'd'}, - {"portnum", 1, 0, 'p'}, - {"verbose", 0, 0, 'v'}, - {"keyfile", 1, 0, 'k'}, - {"heavylog", 1, 0, 'O'}, - {"lightlog", 1, 0, 'o'}, - {"pass", 1, 0, 301}, - {0, 0, 0, 0} + {"help", 0, 0, 'h'}, + {"udpmode", 0, 0, 'u'}, + {"reverseudp", 0, 0, 'U'}, + {"servername", 1, 0, 'n'}, + {"manageport", 1, 0, 'm'}, + {"hostname", 1, 0, 'd'}, + {"portnum", 1, 0, 'p'}, + {"verbose", 0, 0, 'v'}, + {"keyfile", 1, 0, 'k'}, + {"heavylog", 1, 0, 'O'}, + {"lightlog", 1, 0, 'o'}, + {"pass", 1, 0, 301}, + {"ipv4", 0, 0, '4'}, + {"ipv6", 0, 0, '6'}, + {"load", 1, 0, 'l'}, + {0, 0, 0, 0} }; int main(int argc, char **argv) { - int i, n, numofcon, length, buflength, notsent, temp2; /* !!! */ - ConnectuserT* contable = NULL; - clifd master; - unsigned char buff[9000]; - char hostname[100]; - struct timeval tv; - int maxfdp1, usernum, usercon, merror; - socklen_t len, addrlen; - struct sockaddr* cliaddr; - fd_set rset, allset; - char verbose = 0; - char logging = 0; - char* name = NULL; - char* manage = NULL; - char* desnam = NULL; - char* despor = NULL; - char* keys = NULL; - char* logfname = NULL; - unsigned char pass[4]; - char udp = 0; - char reverse = 0; - char type; + int i, n, numofcon, length, buflength, notsent, temp2; + ConnectuserT* contable = NULL; + clifd master; + unsigned char buff[9000]; + char hostname[100]; + struct timeval tv; + int maxfdp1, usernum, usercon, merror; + socklen_t len, addrlen; + struct sockaddr* cliaddr; + fd_set rset, allset, wset, tmpset; + char verbose = 0; + char logging = 0; + char* name = NULL; + char* manage = NULL; + char* desnam = NULL; + char* despor = NULL; + char* keys = NULL; + char* logfname = NULL; + char ipfam = 0; + unsigned char pass[4] = {1, 2, 3, 4}; + char udp = 0; + char reverse = 0; + char type = 0; + struct sigaction act; + struct { + char loaded; + char* name; + void* handle; + char* (*info)(void); + int (*allow)(char*, char*); + int (*filter)(char*, unsigned char*, int*); + } module = {0, NULL, NULL, NULL, NULL}; - SSL_METHOD* method; - SSL_CTX* ctx; + SSL_METHOD* method; + SSL_CTX* ctx; + + sigfillset(&(act.sa_mask)); + act.sa_flags = 0; + + act.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &act, NULL); + act.sa_handler = sig_int; + sigaction(SIGINT, &act, NULL); - signal(SIGPIPE, SIG_IGN); - signal(SIGINT, sig_int); + while ((n = getopt_long(argc, argv, "huUn:m:d:p:vk:O:o:46l:", long_options, 0)) != -1) { + switch (n) { + case 'h': { + usage(AF_VER("Active port forwarder (client)")); + break; + } + case 'n': { + name = optarg; + break; + } + case 'm': { + manage = optarg; + break; + } + case 'd': { + desnam = optarg; + break; + } + case 'p': { + despor = optarg; + break; + } + case 'v': { + ++verbose; + break; + } + case 'u': { + udp = 1; + break; + } + case 'U': { + reverse = 1; + break; + } + case 'k': { + keys = optarg; + break; + } + case 'O': { + logfname = optarg; + logging = 3; + break; + } + case 'o': { + logfname = optarg; + logging = 1; + break; + } + case 301: { + n = strlen(optarg); + memset(pass, 0, 4); + for (i = 0; i < n; ++i) { + pass[i%4] += optarg[i]; + } + break; + } + case '4': { + if (ipfam != 0) { + ipfam = -1; + } + else { + ipfam = 4; + } + break; + } + case '6': { + if (ipfam != 0) { + ipfam = -1; + } + else { + ipfam = 6; + } + break; + } + case 'l': { + module.name = optarg; + break; + } + case '?': { + usage(""); + break; + } + } + } - while ((n = getopt_long(argc, argv, "huUn:m:d:p:vk:O:o:", long_options, 0)) != -1) { - switch (n) { - case 'h': { - usage(AF_VER("Active port forwarder (client)")); - break; - } - case 'n': { - name = optarg; - break; - } - case 'm': { - manage = optarg; - break; - } - case 'd': { - desnam = optarg; - break; - } - case 'p': { - despor = optarg; - break; - } - case 'v': { - ++verbose; - break; - } - case 'u': { - udp = 1; - break; - } - case 'U': { - reverse = 1; - break; - } - case 'k': { - keys = optarg; - break; - } - case 'O': { - logfname = optarg; - logging = 2; - break; - } - case 'o': { - logfname = optarg; - logging = 1; - break; - } - case 301: { - n = strlen(optarg); - memset(pass, 0, 4); - for (i = 0; i < n; ++i) { - pass[i%4] += optarg[i]; - } - break; - } - case '?': { - usage(""); - break; - } - } - } + if (optind < argc) { + usage("Unrecognized non-option elements"); + } - if (optind < argc) { - usage("Unrecognized non-option elements"); - } + if (name == NULL) { + usage("Name of the server is required"); + } + if (manage == NULL) { + manage = "50126"; + if (reverse) + usage("Port on the server is required in reverse mode"); + } + if (desnam == NULL) { + gethostname(hostname, 100); + desnam = hostname; + } + if (despor == NULL) { + usage("Destination port number is required"); + } + if (keys == NULL) { + keys = "client.rsa"; + } + if (module.name) { + module.handle = dlopen(module.name, RTLD_NOW); + if (!module.handle) { + printf("Can't load a module: %s\n", dlerror()); + exit(1); + } + dlerror(); + *(void**) (&module.info) = dlsym(module.handle, "info"); + *(void**) (&module.allow) = dlsym(module.handle, "allow"); + *(void**) (&module.filter) = dlsym(module.handle, "filter"); + if (dlerror() != NULL) { + printf("Loading a module %s failed!\n", module.name); + exit(1); + } + module.loaded = 1; + } - if (name == NULL) { - usage("Name of the server is required"); - } - if (manage == NULL) { - manage = "50126"; - if (reverse) - usage("Port on the server is required in reverse mode"); - } - if (desnam == NULL) { - gethostname(hostname, 100); - desnam = hostname; - } - if (despor == NULL) { - usage("Destination port number is required"); - } - if (keys == NULL) { - keys = "client.rsa"; - } + TYPE_SET_SSL(type); + TYPE_SET_ZLIB(type); - type = 0; - TYPE_SET_SSL(type); - TYPE_SET_ZLIB(type); + if (ipfam == -1) { + printf("Conflicting types of ip protocol family... exiting\n"); + exit(1); + } + else if (ipfam == 4) { + TYPE_SET_IPV4(type); + } + else if (ipfam == 6) { + TYPE_SET_IPV6(type); + } - master.commfd = ip_connect(name, manage, "tcp"); + ipfam = 0x01; + if (TYPE_IS_IPV4(type)) { + ipfam |= 0x02; + } + else if (TYPE_IS_IPV6(type)) { + ipfam |= 0x04; + } + if (ip_connect(&(master.commfd), name, manage, ipfam)) { + printf("tcp_connect_%s error for %s, %s\n", + (ipfam & 0x02)?"ipv4":(ipfam & 0x04)?"ipv6":"unspec", name, manage); + exit(1); + } - if (!reverse) { - SSL_library_init(); - method = SSLv3_client_method(); - ctx = SSL_CTX_new(method); - if (SSL_CTX_set_cipher_list(ctx, "ALL:@STRENGTH") == 0) { - printf("Setting cipher list failed... exiting\n"); - exit(1); - } - if (SSL_CTX_use_RSAPrivateKey_file(ctx, keys, SSL_FILETYPE_PEM) != 1) { - printf("Setting rsa key failed (%s)... exiting\n", keys); - exit(1); - } - master.ssl = SSL_new(ctx); - if (SSL_set_fd(master.ssl, master.commfd) != 1) { - printf("Problem with initializing ssl... exiting\n"); - exit(1); - } - if (verbose>1) - printf("Trying SSL_connect\n"); - if ((n = SSL_connect(master.ssl)) == 1) { - if (verbose) { - printf("SSL_connect successfull\n"); - } - } - else { - printf("SSL_connect has failed (%d)... exiting\n", n); - exit(1); - } + if (!reverse) { + SSL_library_init(); + method = SSLv3_client_method(); + ctx = SSL_CTX_new(method); + if (SSL_CTX_set_cipher_list(ctx, "ALL:@STRENGTH") == 0) { + printf("Setting cipher list failed... exiting\n"); + exit(1); + } + if (SSL_CTX_use_RSAPrivateKey_file(ctx, keys, SSL_FILETYPE_PEM) != 1) { + printf("Setting rsa key failed (%s)... exiting\n", keys); + exit(1); + } + master.ssl = SSL_new(ctx); + if (SSL_set_fd(master.ssl, master.commfd) != 1) { + printf("Problem with initializing ssl... exiting\n"); + exit(1); + } + if (verbose>1) + printf("Trying SSL_connect\n"); + if ((n = SSL_connect(master.ssl)) == 1) { + if (verbose) { + printf("SSL_connect successfull\n"); + } + } + else { + printf("SSL_connect has failed (%d)... exiting\n", n); + exit(1); + } - - buff[0] = AF_S_LOGIN; - buff[1] = pass[0]; - buff[2] = pass[1]; - buff[3] = pass[2]; - buff[4] = pass[3]; - send_message(type, master, buff, 5); - buff[0] = 0; - get_message(type, master, buff, -5); - - if ( buff[0] == 0 ) { - printf("Wrong password\n"); - exit(1); - } - if ( buff[0] != AF_S_LOGIN ) { - printf("Incompatible server type or server full\n"); - exit(1); - } + buff[0] = AF_S_LOGIN; + buff[1] = pass[0]; + buff[2] = pass[1]; + buff[3] = pass[2]; + buff[4] = pass[3]; + send_message(type, master, buff, 5); + buff[0] = 0; + get_message(type, master, buff, -5); - type = buff[3]; - usernum = buff[1]; - usernum = usernum << 8; - usernum += buff[2]; + if ( buff[0] == 0 ) { + printf("Wrong password\n"); + exit(1); + } + if ( buff[0] != AF_S_LOGIN ) { + printf("Incompatible server type or server full\n"); + exit(1); + } - } /* !reverse */ - else { - usernum = 1; - master.ssl = NULL; - } + type = buff[3]; + usernum = buff[1]; + usernum = usernum << 8; + usernum += buff[2]; + } /* !reverse */ + else { + usernum = 1; + master.ssl = NULL; + } - contable = calloc( usernum, sizeof(ConnectuserT)); - if (contable == NULL) { - printf("Calloc error - unable to succesfully comunicate with server\n"); - exit(1); - } + contable = calloc( usernum, sizeof(ConnectuserT)); + if (contable == NULL) { + printf("Calloc error - unable to succesfully comunicate with server\n"); + exit(1); + } - len = 4; - if (getsockopt(master.commfd, SOL_SOCKET, SO_SNDBUF, &buflength, &len) == -1) { - printf("Can't get socket send buffor size - exiting...\n"); - exit(1); - } + len = 4; + if (getsockopt(master.commfd, SOL_SOCKET, SO_SNDBUF, &buflength, &len) == -1) { + printf("Can't get socket send buffer size - exiting...\n"); + exit(1); + } - if (loginit(verbose, logging, logfname)) { - printf("Can't open file to log to... exiting\n"); - exit(1); - } + if (loginit(verbose, logging, logfname)) { + printf("Can't open file to log to... exiting\n"); + exit(1); + } - if (!verbose) - daemon(0, 0); + if (!verbose) + daemon(0, 0); - FD_ZERO(&allset); + FD_ZERO(&allset); + FD_ZERO(&wset); - FD_SET(master.commfd, &allset); - maxfdp1 = master.commfd + 1; + FD_SET(master.commfd, &allset); + maxfdp1 = master.commfd + 1; - if (reverse) { - contable[0].connfd=ip_listen(desnam, despor, &addrlen, "udp"); - cliaddr = malloc(addrlen); - maxfdp1 = (maxfdp1>contable[0].connfd+1) ? maxfdp1 : contable[0].connfd+1; - FD_SET(contable[0].connfd, &allset); - aflog(1, "CLIENT STARTED mode: udp reverse"); - for ( ; ; ) { - len = 4; - if (getsockopt(master.commfd, SOL_SOCKET, SO_SNDBUF, &temp2, &len) != -1) { - if (temp2 != buflength) { - buflength = temp2; - aflog(2, "Send buffor size changed..."); - } - } - len = addrlen; - rset = allset; - aflog(2, ">select"); - select(maxfdp1, &rset, NULL, NULL, NULL); - aflog(2, " >>after select..."); - if (FD_ISSET(contable[0].connfd, &rset)) { - n = recvfrom(contable[0].connfd, &buff[5], 8091, 0, cliaddr, &len); + /* UDP REVERSE MODE */ + + if (reverse) { + ipfam = 0; + if (TYPE_IS_IPV4(type)) { + ipfam |= 0x02; + } + else if (TYPE_IS_IPV6(type)) { + ipfam |= 0x04; + } + if (ip_listen(&(contable[0].connfd), desnam, despor, &addrlen, ipfam)) { + printf("udp_listen_%s error for %s, %s\n", + (ipfam & 0x02)?"ipv4":(ipfam & 0x04)?"ipv6":"unspec", desnam, despor); + exit(1); + } + cliaddr = malloc(addrlen); + maxfdp1 = (maxfdp1>contable[0].connfd+1) ? maxfdp1 : contable[0].connfd+1; + FD_SET(contable[0].connfd, &allset); + aflog(1, "CLIENT STARTED mode: udp reverse"); + for ( ; ; ) { + len = 4; + if (getsockopt(master.commfd, SOL_SOCKET, SO_SNDBUF, &temp2, &len) != -1) { + if (temp2 != buflength) { + buflength = temp2; + aflog(2, "Send buffer size changed..."); + } + } + len = addrlen; + rset = allset; + aflog(3, ">select"); + select(maxfdp1, &rset, NULL, NULL, NULL); + aflog(3, " >>after select..."); + + if (FD_ISSET(contable[0].connfd, &rset)) { /* FD_ISSET CONTABLE[0].CONNFD RSET*/ + n = recvfrom(contable[0].connfd, &buff[5], 8091, 0, cliaddr, &len); #ifdef SIOCOUTQ - if (ioctl(master.commfd, SIOCOUTQ, ¬sent)) { - aflog(0, "ioctl error -> exiting..."); - exit(1); - } - if (buflength <= notsent + n + 5) { /* when we can't do this */ - aflog(2, "drop: size:%d, buf:%d, w:%d/%d", - n, buflength, notsent, buflength); + if (ioctl(master.commfd, SIOCOUTQ, ¬sent)) { + aflog(0, "ioctl error -> exiting..."); + exit(1); + } + if (buflength <= notsent + n + 5) { /* when we can't do this */ + aflog(2, "drop: size:%d, buf:%d, w:%d/%d", n, buflength, notsent, buflength); #else - if (ioctl(master.commfd, TIOCOUTQ, ¬sent)) { - aflog(0, "ioctl error -> exiting..."); - exit(1); - } - if (notsent <= n + 5) { /* when we can't do this */ - aflog(2, "drop: size:%d, buf:%d, w:%d/%d", - n, buflength, buflength - notsent, buflength); + if (ioctl(master.commfd, TIOCOUTQ, ¬sent)) { + aflog(0, "ioctl error -> exiting..."); + exit(1); + } + if (notsent <= n + 5) { /* when we can't do this */ + aflog(2, "drop: size:%d, buf:%d, w:%d/%d", n, buflength, buflength - notsent, buflength); #endif - } - else { - if (n > 0) { - aflog(2, "Sending %d bytes to service (w:%d/%d)", - n, + } + else { + if (n > 0) { + aflog(2, "Sending %d bytes to service (w:%d/%d)", n, #ifdef SIOCOUTQ - notsent + notsent #else - buflength - notsent + buflength - notsent #endif - , buflength); - buff[0] = AF_S_MESSAGE; - buff[1] = AF_S_LOGIN; - buff[2] = AF_S_MESSAGE; - buff[3] = n >> 8; - buff[4] = n; - writen(master.commfd, buff, n + 5); - } - } - } - if (FD_ISSET(master.commfd, &rset)) { - n = readn(master.commfd, buff, 5); - if (n == 5) { - if ((buff[0] != AF_S_MESSAGE) || (buff[1] != AF_S_LOGIN) - || (buff[2] != AF_S_MESSAGE)) { - aflog(0, "Incompatible server type (not udp?) or data corruption -> exiting..."); - exit(1); - } - length = buff[3]; - length = length << 8; - length += buff[4]; /* this is length of message */ - n = readn(master.commfd, buff, length); - } - else { - n = 0; - } - if (n == 0) { /* server quits -> we do the same... */ - gettimeofday(&tv, 0); - aflog(0, "premature quit of the server -> exiting..."); - exit(1); - } - aflog(2, "Sending %d bytes to user", n); - sendto(contable[0].connfd, buff, n, 0, cliaddr, addrlen); - } - } - exit(0); /* we shouldn't get here */ - } + , buflength); + buff[0] = AF_S_MESSAGE; + buff[1] = AF_S_LOGIN; + buff[2] = AF_S_MESSAGE; + buff[3] = n >> 8; + buff[4] = n; + writen(master.commfd, buff, n + 5); + } + } + } /* - FD_ISSET CONTABLE[0].CONNFD RSET */ + if (FD_ISSET(master.commfd, &rset)) { /* FD_ISSET MASTER.COMMFD RSET */ + n = readn(master.commfd, buff, 5); + if (n == 5) { + if ((buff[0] != AF_S_MESSAGE) || (buff[1] != AF_S_LOGIN) || (buff[2] != AF_S_MESSAGE)) { + aflog(0, "Incompatible server type (not udp?) or data corruption -> exiting..."); + exit(1); + } + length = buff[3]; + length = length << 8; + length += buff[4]; /* this is length of message */ + n = readn(master.commfd, buff, length); + } + else { + n = 0; + } + if (n == 0) { /* server quits -> we do the same... */ + gettimeofday(&tv, 0); + aflog(0, "premature quit of the server -> exiting..."); + exit(1); + } + aflog(2, "Sending %d bytes to user", n); + sendto(contable[0].connfd, buff, n, 0, cliaddr, addrlen); + } /* - FD_ISSET MASTER.COMMFD RSET */ + } + exit(0); /* we shouldn't get here */ + } + + /* NORMAL MODE */ - aflog(1, "CLIENT STARTED mode: %s", (udp)?"udp":"tcp"); - aflog(1, "SERVER SSL: %s, ZLIB: %s, MODE: %s", (TYPE_IS_SSL(type))?"yes":"no", - (TYPE_IS_ZLIB(type))?"yes":"no", (TYPE_IS_TCP(type))?"tcp":"udp"); + aflog(1, "CLIENT STARTED mode: %s", (udp)?"udp":"tcp"); + aflog(1, "SERVER SSL: %s, ZLIB: %s, MODE: %s", (TYPE_IS_SSL(type))?"yes":"no", + (TYPE_IS_ZLIB(type))?"yes":"no", (TYPE_IS_TCP(type))?"tcp":"udp"); + aflog(2, "CIPHER: %s VER: %s", SSL_get_cipher_name(master.ssl), SSL_get_cipher_version(master.ssl)); + if (module.loaded) { + aflog(1, "LOADED MODULE: %s INFO: %s", module.name, module.info()); + } - for ( ; ; ) { - rset = allset; - aflog(2, ">select"); - select(maxfdp1, &rset, NULL, NULL, NULL); - aflog(2, " >>after select..."); + for ( ; ; ) { + rset = allset; + tmpset = wset; + aflog(3, ">select"); + select(maxfdp1, &rset, &tmpset, NULL, NULL); + aflog(3, " >>after select..."); - for (i = 0; i < usernum; ++i) { - if (contable[i].state == S_STATE_OPEN) - if (FD_ISSET(contable[i].connfd, &rset)) { - aflog(2, " user[%d]: FD_ISSET", i); - n = read(contable[i].connfd, &buff[5], 8091); - if (n == -1) { - aflog(0, " error (%d): while reading from service", n); - n = 0; - } + for (i = 0; i < usernum; ++i) { + if ((contable[i].state == S_STATE_OPEN)||(contable[i].state == S_STATE_STOPPED)) { + if (FD_ISSET(contable[i].connfd, &rset)) { /* FD_ISSET CONTABLE[i].CONNFD RSET */ + aflog(3, " user[%d]: FD_ISSET", i); + n = read(contable[i].connfd, &buff[5], 8091); + if (n == -1) { + aflog(0, " error (%d): while reading from service", n); + n = 0; + } #ifdef SIOCOUTQ - if (ioctl(master.commfd, SIOCOUTQ, ¬sent)) { - aflog(0, "ioctl error -> exiting..."); - exit(1); - } - if (udp) { - len = 4; - if (getsockopt(master.commfd, SOL_SOCKET, SO_SNDBUF, &temp2, &len) != -1) { - if (temp2 != buflength) { - buflength = temp2; - aflog(2, "Send buffor size changed..."); - } - } - if (buflength <= notsent + n + 5) { /* when we can't send this */ - aflog(2, " user[%d]: DROP size:%d, buf:%d, w:%d/%d", - i, n+5, buflength, notsent, buflength); + if (ioctl(master.commfd, SIOCOUTQ, ¬sent)) { + aflog(0, "ioctl error -> exiting..."); + exit(1); + } + if (udp) { + len = 4; + if (getsockopt(master.commfd, SOL_SOCKET, SO_SNDBUF, &temp2, &len) != -1) { + if (temp2 != buflength) { + buflength = temp2; + aflog(2, "Send buffer size changed..."); + } + } + if (buflength <= notsent + n + 5) { /* when we can't send this */ + aflog(2, " user[%d]: DROP size:%d, buf:%d, w:%d/%d", i, n+5, buflength, notsent, buflength); #else - if (ioctl(master.commfd, TIOCOUTQ, ¬sent)) { - aflog(0, "ioctl error -> exiting..."); - exit(1); - } - if (udp) { - len = 4; - if (getsockopt(master.commfd, SOL_SOCKET, SO_SNDBUF, &temp2, &len) != -1) { - if (temp2 != buflength) { - buflength = temp2; - aflog(2, "Send buffor size changed..."); - } - } - if (notsent <= n + 5) { /* when we can't send this */ - aflog(2, " user[%d]: DROP size:%d, buf:%d, w:%d/%d", - i, n+5, buflength, buflength-notsent, buflength); + if (ioctl(master.commfd, TIOCOUTQ, ¬sent)) { + aflog(0, "ioctl error -> exiting..."); + exit(1); + } + if (udp) { + len = 4; + if (getsockopt(master.commfd, SOL_SOCKET, SO_SNDBUF, &temp2, &len) != -1) { + if (temp2 != buflength) { + buflength = temp2; + aflog(2, "Send buffer size changed..."); + } + } + if (notsent <= n + 5) { /* when we can't send this */ + aflog(2, " user[%d]: DROP size:%d, buf:%d, w:%d/%d", + i, n+5, buflength, buflength-notsent, buflength); #endif - continue; /* drop this packet */ - } - } - if (n) { - buff[0] = AF_S_MESSAGE; /* sending message */ - buff[1] = i >> 8; /* high bits of user number */ - buff[2] = i; /* low bits of user number */ - buff[3] = n >> 8; /* high bits of message length */ - buff[4] = n; /* low bits of message length */ - aflog(2, " user[%d]: TO msglen: %d [%d/%d]", - i, n, + continue; /* drop this packet */ + } + } + if (n) { + buff[0] = AF_S_MESSAGE; /* sending message */ + buff[1] = i >> 8; /* high bits of user number */ + buff[2] = i; /* low bits of user number */ + buff[3] = n >> 8; /* high bits of message length */ + buff[4] = n; /* low bits of message length */ + aflog(2, " user[%d]: TO msglen: %d [%d/%d]", i, n, #ifdef SIOCOUTQ - notsent + notsent #else - buflength - notsent + buflength - notsent #endif - , buflength); - send_message(type, master, buff, n+5); - } - else if (!udp) { - close(contable[i].connfd); - FD_CLR(contable[i].connfd, &allset); - contable[i].state = S_STATE_CLOSING; - buff[0] = AF_S_CONCLOSED; /* closing connection */ - buff[1] = i >> 8; /* high bits of user number */ - buff[2] = i; /* low bits of user number */ - send_message(type, master, buff, 5); - } - } - } - - if (FD_ISSET(master.commfd, &rset)) { - aflog(2, " masterfd: FD_ISSET"); - n = get_message(type, master, buff, 5); - if (n != 5) { - aflog(2, " FATAL ERROR! (%d)", n); - if (n == -1) { - if (TYPE_IS_SSL(type)) { - merror = SSL_get_error(master.ssl, n); - switch (merror) { - case SSL_ERROR_NONE : { - aflog(2, "FE: none"); - break; - } - case SSL_ERROR_ZERO_RETURN : { - aflog(2, "FE: zero"); - break; - } - case SSL_ERROR_WANT_READ : { - aflog(2, "FE: w_read"); - break; - } - case SSL_ERROR_WANT_WRITE : { - aflog(2, "FE: w_write"); - break; - } - case SSL_ERROR_WANT_CONNECT : { - aflog(2, "FE: w_connect"); - break; - } - case SSL_ERROR_WANT_X509_LOOKUP : { - aflog(2, "FE: w_x509_lookup"); - break; - } - case SSL_ERROR_SYSCALL : { - aflog(2, "FE: syscall"); - break; - } - case SSL_ERROR_SSL : { - SSL_load_error_strings(); - aflog(2, "FE: ssl:%s", - ERR_error_string(ERR_get_error(), (char*) buff)); - break; - } - } - continue; /* what happened? */ - } - } - if (n != 0) - exit(1); - } - if (n == 0) { /* server quits -> we do the same... */ - aflog(0, " SERVER: premature quit -> exiting..."); - exit(1); - } - numofcon = buff[1]; - numofcon = numofcon << 8; - numofcon += buff[2]; /* this is id of user */ - length = buff[3]; - length = length << 8; - length += buff[4]; /* this is length of message */ - switch (buff[0]) { - case AF_S_CONCLOSED : { - if ((numofcon>=0) && (numofcon<=usernum)) { - usercon--; - if (contable[numofcon].state == S_STATE_CLOSING) { - contable[numofcon].state = S_STATE_CLEAR; - } - else if (contable[numofcon].state==S_STATE_OPEN) { - close(contable[numofcon].connfd); - FD_CLR(contable[numofcon].connfd, &allset); - contable[numofcon].state = S_STATE_CLEAR; - buff[0] = AF_S_CONCLOSED; /* closing connection */ - buff[1] = numofcon >> 8; /* high bits of user number */ - buff[2] = numofcon; /* low bits of user number */ - send_message(type, master, buff, 5); - } - } - break; - } - case AF_S_CONOPEN : { - if ((numofcon>=0) && (numofcon<=usernum)) { - usercon++; - if (contable[numofcon].state == S_STATE_CLEAR) { - if (udp) { - contable[numofcon].connfd=ip_connect(desnam,despor,"udp"); - } - else { - contable[numofcon].connfd=ip_connect(desnam,despor,"tcp"); - } - FD_SET(contable[numofcon].connfd, &allset); - maxfdp1 = (maxfdp1 > (contable[numofcon].connfd+1)) ? maxfdp1 : (contable[numofcon].connfd+1); - buff[0] = AF_S_CONOPEN; /* closing connection */ - buff[1] = numofcon >> 8; /* high bits of user number */ - buff[2] = numofcon; /* low bits of user number */ - send_message(type, master, buff, 5); - contable[numofcon].state = S_STATE_OPEN; - } - } - break; - } - case AF_S_MESSAGE : { - aflog(2, " user[%d]: FROM msglen: %d", numofcon, length); - n = get_message(type, master, buff, length); - if ((numofcon>=0) && (numofcon<=usernum)) { - if (contable[numofcon].state == S_STATE_OPEN) { - aflog(2, " user[%d]: FROM msglen: %d SENT", numofcon, n); - if (writen(contable[numofcon].connfd, buff, n)==-1) { - aflog(0, "Sending msg failed!"); - } - } - } - break; - } - case AF_S_CLOSING : { /* server shut down -> exiting... */ - aflog(0, " SERVER: CLOSED -> exiting... cg: %ld bytes", getcg()); - exit(1); - break; - } - default : { /* unrecognized type of message -> exiting... */ - aflog(0, " SERVER: unrecognized message -> exiting... cg: %ld bytes", getcg()); - exit(1); - break; - } - } - } - } + , buflength); + send_message(type, master, buff, n+5); + } + else if (!udp) { + aflog(2, " user[%d]: CLOSING", i); + close(contable[i].connfd); + FD_CLR(contable[i].connfd, &allset); + FD_CLR(contable[i].connfd, &wset); + contable[i].state = S_STATE_CLOSING; + freebuflist(&contable[i].head); + buff[0] = AF_S_CONCLOSED; /* closing connection */ + buff[1] = i >> 8; /* high bits of user number */ + buff[2] = i; /* low bits of user number */ + send_message(type, master, buff, 5); + } + } /* - FD_ISSET CONTABLE[i].CONNFD RSET */ + } + } + for (i = 0; i < usernum; ++i) { + if (contable[i].state == S_STATE_STOPPED) { + if (FD_ISSET(contable[i].connfd, &tmpset)) { /* FD_ISSET CONTABLE[i].CONNFD TMPSET */ + aflog(3, " user[%d]: FD_ISSET - WRITE", i); + n = contable[i].head->msglen - contable[i].head->actptr; + temp2 = write(contable[i].connfd, &(contable[i].head->buff[contable[i].head->actptr]), n); + if ((temp2 > 0) && (temp2 != n)) { + contable[i].head->actptr+=temp2; + } + else if ((temp2 == -1) && (errno == EAGAIN)) { + aflog(3, " user[%d]: Couldn't write?", i); + } + else if (temp2 == -1) { + close(contable[i].connfd); + FD_CLR(contable[i].connfd, &allset); + FD_CLR(contable[i].connfd, &wset); + contable[i].state = S_STATE_CLOSING; + buff[0] = AF_S_CONCLOSED; /* closing connection */ + buff[1] = i >> 8; /* high bits of user number */ + buff[2] = i; /* low bits of user number */ + send_message(type, master, buff, 5); + } + else { + deleteblnode(&contable[i].head); + if (contable[i].head == NULL) { + contable[i].state = S_STATE_OPEN; + FD_CLR(contable[i].connfd, &wset); + buff[0] = AF_S_CAN_SEND; /* stopping transfer */ + buff[1] = i >> 8; /* high bits of user number */ + buff[2] = i; /* low bits of user number */ + aflog(3, " FROM user[%d]: BUFFERING MESSAGE ENDED", i); + send_message(type, master, buff, 5); + } + } + } /* - FD_ISSET CONTABLE[i].CONNFD TMPSET */ + } + } + if (FD_ISSET(master.commfd, &rset)) { /* FD_ISSET MASTER.COMMFD RSET */ + aflog(3, " masterfd: FD_ISSET"); + n = get_message(type, master, buff, 5); + if (n != 5) { + aflog(2, " FATAL ERROR! (%d)", n); + if (n == -1) { + if (TYPE_IS_SSL(type)) { + merror = SSL_get_error(master.ssl, n); + switch (merror) { + case SSL_ERROR_NONE : { + aflog(2, "FE: none"); + break; + } + case SSL_ERROR_ZERO_RETURN : { + aflog(2, "FE: zero"); + break; + } + case SSL_ERROR_WANT_READ : { + aflog(2, "FE: w_read"); + break; + } + case SSL_ERROR_WANT_WRITE : { + aflog(2, "FE: w_write"); + break; + } + case SSL_ERROR_WANT_CONNECT : { + aflog(2, "FE: w_connect"); + break; + } + case SSL_ERROR_WANT_X509_LOOKUP : { + aflog(2, "FE: w_x509_lookup"); + break; + } + case SSL_ERROR_SYSCALL : { + aflog(2, "FE: syscall"); + break; + } + case SSL_ERROR_SSL : { + SSL_load_error_strings(); + aflog(2, "FE: ssl:%s", + ERR_error_string(ERR_get_error(), (char*) buff)); + break; + } + } + continue; /* what happened? */ + } + } + if (n != 0) + exit(1); + } + if (n == 0) { /* server quits -> we do the same... */ + aflog(0, " SERVER: premature quit -> exiting..."); + exit(1); + } + numofcon = buff[1]; + numofcon = numofcon << 8; + numofcon += buff[2]; /* this is id of user */ + length = buff[3]; + length = length << 8; + length += buff[4]; /* this is length of message */ + switch (buff[0]) { + case AF_S_CONCLOSED : { + if ((numofcon>=0) && (numofcon<=usernum)) { + usercon--; + if (contable[numofcon].state == S_STATE_CLOSING) { + contable[numofcon].state = S_STATE_CLEAR; + aflog(2, " user[%d]: CLOSED", numofcon); + } + else if ((contable[numofcon].state==S_STATE_OPEN) || (contable[numofcon].state==S_STATE_STOPPED)){ + aflog(2, " user[%d]: CLOSED", numofcon); + close(contable[numofcon].connfd); + FD_CLR(contable[numofcon].connfd, &allset); + FD_CLR(contable[numofcon].connfd, &wset); + contable[numofcon].state = S_STATE_CLEAR; + freebuflist(&contable[numofcon].head); + buff[0] = AF_S_CONCLOSED; /* closing connection */ + buff[1] = numofcon >> 8; /* high bits of user number */ + buff[2] = numofcon; /* low bits of user number */ + send_message(type, master, buff, 5); + } + } + break; + } + case AF_S_CONOPEN : { + if ((numofcon>=0) && (numofcon<=usernum)) { + usercon++; + if (contable[numofcon].state == S_STATE_CLEAR) { + n = get_message(type, master, buff, length); + memcpy(contable[numofcon].namebuf, buff, 128); + memcpy(contable[numofcon].portbuf,&buff[128],7); + aflog(2, " user[%d]: OPENING", numofcon); + aflog(1, "user[%d]: IP:%s PORT:%s", numofcon, + contable[numofcon].namebuf, contable[numofcon].portbuf); + if (module.loaded && module.allow(contable[numofcon].namebuf, contable[numofcon].portbuf)) { + aflog(2, " IT'S NOT ALLOWED - DROPPING", numofcon); + buff[0] = AF_S_CANT_OPEN; /* not opening connection */ + buff[1] = numofcon >> 8; /* high bits of user number */ + buff[2] = numofcon; /* low bits of user number */ + send_message(type, master, buff, 5); + usercon--; + continue; + } + if (udp) { + ipfam = 0; + } + else { + ipfam = 0x01; + } + if (TYPE_IS_IPV4(type)) { + ipfam |= 0x02; + } + else if (TYPE_IS_IPV6(type)) { + ipfam |= 0x04; + } + if (ip_connect(&(contable[numofcon].connfd), desnam, despor, ipfam)) { + aflog(2, " CAN'T OPEN - DROPPING", numofcon); + buff[0] = AF_S_CANT_OPEN; /* not opening connection */ + buff[1] = numofcon >> 8; /* high bits of user number */ + buff[2] = numofcon; /* low bits of user number */ + send_message(type, master, buff, 5); + usercon--; + continue; + } + temp2 = fcntl(contable[numofcon].connfd, F_GETFL, 0); + fcntl(contable[numofcon].connfd, F_SETFL, temp2 | O_NONBLOCK); + FD_SET(contable[numofcon].connfd, &allset); + maxfdp1 = (maxfdp1 > (contable[numofcon].connfd+1)) ? maxfdp1 : (contable[numofcon].connfd+1); + buff[0] = AF_S_CONOPEN; /* opening connection */ + buff[1] = numofcon >> 8; /* high bits of user number */ + buff[2] = numofcon; /* low bits of user number */ + send_message(type, master, buff, 5); + contable[numofcon].state = S_STATE_OPEN; + } + } + break; + } + case AF_S_MESSAGE : { + aflog(2, " user[%d]: FROM msglen: %d", numofcon, length); + n = get_message(type, master, buff, length); + if ((numofcon>=0) && (numofcon<=usernum)) { + if (contable[numofcon].state == S_STATE_OPEN) { + if (module.loaded) { + switch (module.filter(contable[numofcon].namebuf, buff, &n)) { + case 1: { + aflog(3, " user[%d]: PACKET IGNORED BY MODULE", numofcon); + continue; + break; + } + case 2: { + aflog(2, " user[%d]: DROPPED BY MODULE", numofcon); + close(contable[numofcon].connfd); + FD_CLR(contable[numofcon].connfd, &allset); + FD_CLR(contable[numofcon].connfd, &wset); + contable[numofcon].state = S_STATE_CLOSING; + freebuflist(&contable[numofcon].head); + buff[0] = AF_S_CONCLOSED; /* closing connection */ + buff[1] = numofcon >> 8; /* high bits of user number */ + buff[2] = numofcon; /* low bits of user number */ + send_message(type, master, buff, 5); + break; + } + } + } + aflog(2, " user[%d]: FROM msglen: %d SENT", numofcon, n); + temp2 = write(contable[numofcon].connfd, buff, n); + if ((temp2 > 0) && (temp2 != n)) { + insertblnode(&(contable[numofcon].head), temp2, n, buff); + contable[numofcon].state = S_STATE_STOPPED; + FD_SET(contable[numofcon].connfd, &wset); + buff[0] = AF_S_DONT_SEND; /* stopping transfer */ + buff[1] = numofcon >> 8; /* high bits of user number */ + buff[2] = numofcon; /* low bits of user number */ + aflog(3, " FROM user[%d]: BUFFERING MESSAGE STARTED", numofcon); + send_message(type, master, buff, 5); + } + else if ((temp2 == -1) && (errno == EAGAIN)) { + insertblnode(&(contable[numofcon].head), 0, n, buff); + contable[numofcon].state = S_STATE_STOPPED; + FD_SET(contable[numofcon].connfd, &wset); + buff[0] = AF_S_DONT_SEND; /* stopping transfer */ + buff[1] = numofcon >> 8; /* high bits of user number */ + buff[2] = numofcon; /* low bits of user number */ + aflog(3, " FROM user[%d]: BUFFERING MESSAGE STARTED", numofcon); + send_message(type, master, buff, 5); + } + else if (temp2 == -1) { + close(contable[numofcon].connfd); + FD_CLR(contable[numofcon].connfd, &allset); + FD_CLR(contable[numofcon].connfd, &wset); + contable[numofcon].state = S_STATE_CLOSING; + buff[0] = AF_S_CONCLOSED; /* closing connection */ + buff[1] = numofcon >> 8; /* high bits of user number */ + buff[2] = numofcon; /* low bits of user number */ + send_message(type, master, buff, 5); + } + } + else if (contable[numofcon].state == S_STATE_STOPPED) { + aflog(3, " FROM user[%d]: BUFFERING MESSAGE", numofcon); + insertblnode(&(contable[numofcon].head), 0, n, buff); + } + } + break; + } + case AF_S_CLOSING : { /* server shut down -> exiting... */ + aflog(0, " SERVER: CLOSED -> exiting... cg: %ld bytes", getcg()); + exit(1); + break; + } + case AF_S_DONT_SEND: { + FD_CLR(contable[numofcon].connfd, &allset); + break; + } + case AF_S_CAN_SEND: { + FD_SET(contable[numofcon].connfd, &allset); + break; + } + default : { /* unrecognized type of message -> exiting... */ + aflog(0, " SERVER: unrecognized message -> exiting... cg: %ld bytes", getcg()); + exit(1); + break; + } + } + } /* - FD_ISSET MASTER.COMMFD RSET */ + } } static void usage(char* info) { - printf("\n%s\n\n", info); - printf(" Options:\n"); - printf(" -h, --help - prints this help\n"); - printf(" -n, --servername - where the second part of the active\n"); - printf(" port forwarder is running (required)\n"); - printf(" -m, --manageport - the manage port number - server must\n"); - printf(" listening on it (default: 50126)\n"); - printf(" -d, --hostname - name of this host/remote host - the final\n"); - printf(" destination of the packets (default: name\n"); - printf(" returned by hostname function)\n"); - printf(" -p, --portnum - port we are forwarding connection to (required)\n"); - printf(" -k, --keyfile - name of the file with RSA key (default: client.rsa)\n"); - printf(" -u, --udpmode - udp mode - client will use udp protocol to\n"); - printf(" communicate with hostname\n"); - printf(" -U, --reverseudp - reverse udp forwarding. Udp packets will be forwarded\n"); - printf(" from hostname:portnum (-p) to server name:portnum (-m)\n"); - printf(" -O, --heavylog - logging everything to a logfile\n"); - printf(" -o, --lightlog - logging some data to a logfile\n"); - printf(" -v, --verbose - to be verbose - program won't enter into\n"); - printf(" the daemon mode (use twice for greater effect)\n"); - printf(" --pass - set the password used for client identification\n"); - printf(" (default: no password)\n\n"); - exit(0); + printf("\n%s\n\n", info); + printf(" Options:\n"); + printf(" -h, --help - prints this help\n"); + printf(" -n, --servername - where the second part of the active\n"); + printf(" port forwarder is running (required)\n"); + printf(" -m, --manageport - manage port number - server must be\n"); + printf(" listening on it (default: 50126)\n"); + printf(" -d, --hostname - the name of this host/remote host - the final\n"); + printf(" destination of the packets (default: the name\n"); + printf(" returned by hostname function)\n"); + printf(" -p, --portnum - the port we are forwarding connection to (required)\n"); + printf(" -k, --keyfile - the name of the file with RSA key (default: client.rsa)\n"); + printf(" -u, --udpmode - udp mode - client will use udp protocol to\n"); + printf(" communicate with the hostname\n"); + printf(" -U, --reverseudp - reverse udp forwarding. Udp packets will be forwarded\n"); + printf(" from hostname:portnum (-p) to the server name:portnum\n"); + printf(" (-m)\n"); + printf(" -O, --heavylog - logging everything to a logfile\n"); + printf(" -o, --lightlog - logging some data to a logfile\n"); + printf(" -v, --verbose - to be verbose - program won't enter the daemon mode\n"); + printf(" (use several times for greater effect)\n"); + printf(" --pass - set the password used for client identification\n"); + printf(" (default: no password)\n"); + printf(" -4, --ipv4 - use ipv4 only\n"); + printf(" -6, --ipv6 - use ipv6 only\n"); + printf(" -l, --load - load a module for packets filtering\n\n"); + + exit(0); } static void sig_int(int signo) { - aflog(1, "CLIENT CLOSED cg: %ld bytes", getcg()); - exit(0); + aflog(1, "CLIENT CLOSED cg: %ld bytes", getcg()); + exit(0); } @@ -50,6 +50,8 @@ static struct option long_options[] = { {"nossl", 0, 0, 301}, {"nozlib", 0, 0, 302}, {"pass", 1, 0, 303}, + {"ipv4", 0, 0, '4'}, + {"ipv6", 0, 0, '6'}, {0, 0, 0, 0} }; @@ -58,12 +60,12 @@ static ConfigurationT config; int main(int argc, char **argv) { - int i, j, n, flags; + int i, j, n, flags, sent; socklen_t len; unsigned char buff[9000]; char hostname[100]; int maxfdp1; - fd_set rset, allset; + fd_set rset, allset, wset, tmpset; int manconnecting, numofcon, length; char* name = NULL; char* listen = NULL; @@ -72,17 +74,24 @@ main(int argc, char **argv) char* filenam = NULL; char* type = NULL; char* znak; - unsigned char pass[4]; + unsigned char pass[4] = {1, 2, 3, 4}; char verbose = 0; char mode = 0; + char ipfam = 0; RealmT* pointer = NULL; + struct sigaction act; SSL_METHOD* method; SSL_CTX* ctx; - signal(SIGPIPE, SIG_IGN); - signal(SIGINT, sig_int); - + sigfillset(&(act.sa_mask)); + act.sa_flags = 0; + + act.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &act, NULL); + act.sa_handler = sig_int; + sigaction(SIGINT, &act, NULL); + TYPE_SET_SSL(mode); TYPE_SET_ZLIB(mode); @@ -93,7 +102,7 @@ main(int argc, char **argv) config.logging = 0; config.logfnam = NULL; - while ((n = getopt_long(argc, argv, "hn:l:m:vu:c:k:f:p:o:O:", long_options, 0)) != -1) { + while ((n = getopt_long(argc, argv, "hn:l:m:vu:c:k:f:p:o:O:46", long_options, 0)) != -1) { switch (n) { case 'h': { usage(AF_VER("Active port forwarder (server)")); @@ -161,7 +170,24 @@ main(int argc, char **argv) } break; } - + case '4': { + if (ipfam != 0) { + ipfam = -1; + } + else { + ipfam = 4; + } + break; + } + case '6': { + if (ipfam != 0) { + ipfam = -1; + } + else { + ipfam = 6; + } + break; + } case '?': { usage(""); break; @@ -224,6 +250,16 @@ main(int argc, char **argv) else { TYPE_SET_ZERO(config.realmtable[0].type); } + if (ipfam == -1) { + printf("Conflicting types of ip protocol family... exiting\n"); + exit(1); + } + else if (ipfam == 4) { + TYPE_SET_IPV4(config.realmtable[0].type); + } + else if (ipfam == 6) { + TYPE_SET_IPV6(config.realmtable[0].type); + } config.realmtable[0].type |= mode; } @@ -251,14 +287,16 @@ main(int argc, char **argv) } FD_ZERO(&allset); + FD_ZERO(&wset); for (i = 0; i < config.size; ++i) { if ((config.realmtable[i].hostname == NULL) || (config.realmtable[i].lisportnum == NULL) || (config.realmtable[i].manportnum == NULL) || (config.realmtable[i].users == NULL)) { - printf("Missing some of configurable variables... exiting\n"); - printf("%d) %s, %s, %s, %s\n", i, config.realmtable[i].hostname, + printf("Missing some of the configurable variables...\n"); + printf("\nRealm: %d\nhostname: %s\nlistenport: %s\nmanageport: %s\nusers: %s\n", + i, config.realmtable[i].hostname, config.realmtable[i].lisportnum, config.realmtable[i].manportnum, config.realmtable[i].users); @@ -282,11 +320,27 @@ main(int argc, char **argv) printf("Calloc error - try define smaller amount of users\n"); exit(1); } - - config.realmtable[i].listenfd = ip_listen(config.realmtable[i].hostname, - config.realmtable[i].lisportnum, (&(config.realmtable[i].addrlen)), "tcp"); - config.realmtable[i].managefd = ip_listen(config.realmtable[i].hostname, - config.realmtable[i].manportnum, (&(config.realmtable[i].addrlen)), "tcp"); + ipfam = 0x01; + if (TYPE_IS_IPV4(config.realmtable[i].type)) { + ipfam |= 0x02; + } + else if (TYPE_IS_IPV6(config.realmtable[i].type)) { + ipfam |= 0x04; + } + if (ip_listen(&(config.realmtable[i].listenfd), config.realmtable[i].hostname, + config.realmtable[i].lisportnum, (&(config.realmtable[i].addrlen)), ipfam)) { + printf("tcp_listen_%s error for %s, %s\n", + (ipfam & 0x02)?"ipv4":(ipfam & 0x04)?"ipv6":"unspec", + config.realmtable[i].hostname, config.realmtable[i].lisportnum); + exit(1); + } + if (ip_listen(&(config.realmtable[i].managefd), config.realmtable[i].hostname, + config.realmtable[i].manportnum, (&(config.realmtable[i].addrlen)), ipfam)) { + printf("tcp_listen_%s error for %s, %s\n", + (ipfam & 0x02)?"ipv4":(ipfam & 0x04)?"ipv6":"unspec", + config.realmtable[i].hostname, config.realmtable[i].manportnum); + exit(1); + } config.realmtable[i].cliaddr = malloc(config.realmtable[i].addrlen); config.realmtable[i].cliconn.ssl = SSL_new(ctx); @@ -296,7 +350,9 @@ main(int argc, char **argv) } FD_SET(config.realmtable[i].managefd, &allset); + FD_SET(config.realmtable[i].listenfd, &allset); maxfdp1 = (maxfdp1 > (config.realmtable[i].managefd+1)) ? maxfdp1 : (config.realmtable[i].managefd+1); + maxfdp1 = (maxfdp1 > (config.realmtable[i].listenfd+1)) ? maxfdp1 : (config.realmtable[i].listenfd+1); config.realmtable[i].usercon = 0; config.realmtable[i].ready = 0; config.realmtable[i].tv.tv_sec = 5; @@ -315,7 +371,8 @@ main(int argc, char **argv) for ( ; ; ) { rset = allset; - aflog(2, ">select, maxfdp1: %d", maxfdp1); + tmpset = wset; + aflog(3, ">select, maxfdp1: %d", maxfdp1); if (manconnecting) { /* find out, in what realm client is trying to connect */ for (i = 0; i < config.size; ++i) { @@ -323,10 +380,9 @@ main(int argc, char **argv) break; /* so i points to first good realm */ } } - if (select(maxfdp1, &rset, NULL, NULL, (&(config.realmtable[i].tv))) == 0) { + if (select(maxfdp1, &rset, &tmpset, NULL, (&(config.realmtable[i].tv))) == 0) { close (config.realmtable[i].cliconn.commfd); FD_CLR(config.realmtable[i].cliconn.commfd, &allset); - FD_CLR(config.realmtable[i].listenfd, &allset); FD_SET(config.realmtable[i].managefd, &allset); config.realmtable[i].ready = 0; manconnecting--; @@ -334,16 +390,17 @@ main(int argc, char **argv) } } else { - select(maxfdp1, &rset, NULL, NULL, NULL); + select(maxfdp1, &rset, &tmpset, NULL, NULL); } - aflog(2, " >>after select..."); + aflog(3, " >>after select..."); for (j = 0; j < config.size; ++j) { pointer = (&(config.realmtable[j])); for (i = 0; i <pointer->usernum; ++i) { - if (pointer->contable[i].state == S_STATE_OPEN) + if ((pointer->contable[i].state == S_STATE_OPEN) || + (pointer->contable[i].state == S_STATE_STOPPED)) if (FD_ISSET(pointer->contable[i].connfd, &rset)) { - aflog(2, " realm[%d]: user[%d]: FD_ISSET", j, i); + aflog(3, " realm[%d]: user[%d]: FD_ISSET", j, i); if (TYPE_IS_TCP(pointer->type)) { /* forwarding tcp packets */ n = read(pointer->contable[i].connfd, &buff[5], 8091); if (n == -1) @@ -364,9 +421,13 @@ main(int argc, char **argv) } else { aflog(1, " realm[%d]: user[%d]: CLOSED", j, i); + aflog(2, " IP:%s PORT:%s", pointer->contable[i].namebuf, + pointer->contable[i].portbuf); close(pointer->contable[i].connfd); FD_CLR(pointer->contable[i].connfd, &allset); + FD_CLR(pointer->contable[i].connfd, &wset); pointer->contable[i].state = S_STATE_CLOSING; + freebuflist(&pointer->contable[i].head); buff[0] = AF_S_CONCLOSED; /* closing connection */ buff[1] = i >> 8; /* high bits of user number */ buff[2] = i; /* low bits of user number */ @@ -398,9 +459,13 @@ main(int argc, char **argv) if (n == 0) { aflog(1, " realm[%d]: user[%d]: CLOSED", j, i); + aflog(2, " IP:%s PORT:%s", pointer->contable[i].namebuf, + pointer->contable[i].portbuf); close(pointer->contable[i].connfd); FD_CLR(pointer->contable[i].connfd, &allset); + FD_CLR(pointer->contable[i].connfd, &wset); pointer->contable[i].state = S_STATE_CLOSING; + freebuflist(&pointer->contable[i].head); buff[0] = AF_S_CONCLOSED; /* closing connection */ buff[1] = i >> 8; /* high bits of user number */ buff[2] = i; /* low bits of user number */ @@ -410,31 +475,88 @@ main(int argc, char **argv) } } } - if (pointer->ready == 3) + /* ------------------------------------ */ + for (i = 0; i <pointer->usernum; ++i) { + if (pointer->contable[i].state == S_STATE_STOPPED) + if (FD_ISSET(pointer->contable[i].connfd, &tmpset)) { + aflog(3, " realm[%d]: user[%d]: FD_ISSET - WRITE", j, i); + n = pointer->contable[i].head->msglen - pointer->contable[i].head->actptr; + sent = write(pointer->contable[i].connfd, + &(pointer->contable[i].head->buff[pointer->contable[i].head->actptr]), n); + if ((sent > 0) && (sent != n)) { + pointer->contable[i].head->actptr+=sent; + } + else if ((sent == -1) && (errno == EAGAIN)) { + } + else if (sent == -1) { + aflog(1, " realm[%d]: user[%d]: CLOSED", j, i); + aflog(2, " IP:%s PORT:%s", pointer->contable[i].namebuf, + pointer->contable[i].portbuf); + close(pointer->contable[i].connfd); + FD_CLR(pointer->contable[i].connfd, &allset); + FD_CLR(pointer->contable[i].connfd, &wset); + pointer->contable[i].state = S_STATE_CLOSING; + freebuflist(&pointer->contable[i].head); + buff[0] = AF_S_CONCLOSED; /* closing connection */ + buff[1] = i >> 8; /* high bits of user number */ + buff[2] = i; /* low bits of user number */ + send_message(pointer->type, pointer->cliconn, buff, 5); + } + else { + deleteblnode(&pointer->contable[i].head); + if (pointer->contable[i].head == NULL) { + pointer->contable[i].state = S_STATE_OPEN; + FD_CLR(pointer->contable[i].connfd, &wset); + buff[0] = AF_S_CAN_SEND; /* stopping transfer */ + buff[1] = i >> 8; /* high bits of user number */ + buff[2] = i; /* low bits of user number */ + aflog(3, " realm[%d]: TO user[%d]: BUFFERING MESSAGE ENDED", j, i); + send_message(pointer->type, pointer->cliconn, buff, 5); + } + } + } + } + /* ------------------------------------ */ if (FD_ISSET(pointer->listenfd, &rset)) { - aflog(2, " realm[%d]: listenfd: FD_ISSET", j); len = pointer->addrlen; + sent = accept(pointer->listenfd, pointer->cliaddr, &len); + flags = fcntl(sent, F_GETFL, 0); + fcntl(sent, F_SETFL, flags | O_NONBLOCK); + aflog(3, " realm[%d]: listenfd: FD_ISSET", j); if (pointer->ready == 3) { + if (pointer->usercon == pointer->usernum) { + close(sent); + aflog(3, " realm[%d]: user limit EXCEEDED", j); + } + else { for (i = 0; i < pointer->usernum; ++i) { if (pointer->contable[i].state == S_STATE_CLEAR) { - aflog(2, " realm[%d]: new user[%d]: CONNECTING", j, i); - pointer->contable[i].connfd = - accept(pointer->listenfd, pointer->cliaddr, &len); + aflog(2, " realm[%d]: new user[%d]: CONNECTING", j, i); + pointer->contable[i].connfd = sent; pointer->contable[i].state = S_STATE_OPENING; pointer->usercon++; - aflog(1, " user IP:%s",sock_ntop(pointer->cliaddr, len)); - if (pointer->usercon == pointer->usernum) - FD_CLR(pointer->listenfd, &allset); + aflog(1, " user IP:%s",sock_ntop(pointer->cliaddr, len, + pointer->contable[i].namebuf, pointer->contable[i].portbuf)); + memcpy(&buff[5], pointer->contable[i].namebuf, 128); + memcpy(&buff[133], pointer->contable[i].portbuf, 7); + n = 135; buff[0] = AF_S_CONOPEN; /* opening connection */ buff[1] = i >> 8; /* high bits of user number */ buff[2] = i; /* low bits of user number */ - send_message(pointer->type, pointer->cliconn, buff, 5); + buff[3] = n >> 8; /* high bits of message length */ + buff[4] = n; /* low bits of message length */ + send_message(pointer->type, pointer->cliconn, buff, n+5); break; } } + } + } + else { + close(sent); + aflog(3, " realm[%d]: client is NOT CONNECTED", j); } } - if (pointer->ready != 0) + if (pointer->ready != 0) /* Command file descriptor */ if (FD_ISSET(pointer->cliconn.commfd, &rset)) { if (pointer->ready == 1) { if (SSL_set_fd(pointer->cliconn.ssl, pointer->cliconn.commfd) != 1) { @@ -496,7 +618,7 @@ main(int argc, char **argv) } continue; /* in the case this is not our client */ } - aflog(2, " realm[%d]: commfd: FD_ISSET", j); + aflog(3, " realm[%d]: commfd: FD_ISSET", j); if (pointer->ready == 2) { n = get_message(pointer->type | TYPE_SSL, pointer->cliconn, buff, -5); } @@ -517,7 +639,6 @@ main(int argc, char **argv) if (n==0) { close(pointer->cliconn.commfd); FD_CLR(pointer->cliconn.commfd, &allset); - FD_CLR(pointer->listenfd, &allset); FD_SET(pointer->managefd, &allset); maxfdp1 = (maxfdp1 > (pointer->managefd+1)) ? maxfdp1 : (pointer->managefd+1); if (pointer->ready == 3) { @@ -525,6 +646,7 @@ main(int argc, char **argv) if (pointer->contable[i].state != S_STATE_CLEAR) { pointer->contable[i].state = S_STATE_CLEAR; FD_CLR(pointer->contable[i].connfd, &allset); + FD_CLR(pointer->contable[i].connfd, &wset); close(pointer->contable[i].connfd); } } @@ -547,19 +669,21 @@ main(int argc, char **argv) (numofcon<=(pointer->usernum)) && ((pointer->ready)==3)) { (pointer->usercon)--; - if (pointer->usercon == pointer->usernum-1) - FD_SET(pointer->listenfd, &allset); if (pointer->contable[numofcon].state == S_STATE_CLOSING) { pointer->contable[numofcon].state = S_STATE_CLEAR; } - else if (pointer->contable[numofcon].state == - S_STATE_OPEN) { + else if ((pointer->contable[numofcon].state == S_STATE_OPEN) || + (pointer->contable[numofcon].state == S_STATE_STOPPED)) { aflog(1, " realm[%d]: user[%d]: KICKED", j, numofcon); + aflog(2, " IP:%s PORT:%s", pointer->contable[numofcon].namebuf, + pointer->contable[numofcon].portbuf); close(pointer->contable[numofcon].connfd); FD_CLR(pointer->contable[numofcon].connfd, &allset); + FD_CLR(pointer->contable[numofcon].connfd, &wset); pointer->contable[numofcon].state = S_STATE_CLEAR; + freebuflist(&pointer->contable[numofcon].head); buff[0] = AF_S_CONCLOSED; /* closing connection */ buff[1] = numofcon >> 8; /* high bits of user number */ buff[2] = numofcon; /* low bits of user number */ @@ -569,7 +693,6 @@ main(int argc, char **argv) else { close (pointer->cliconn.commfd); FD_CLR(pointer->cliconn.commfd, &allset); - FD_CLR(pointer->listenfd, &allset); FD_SET(pointer->managefd, &allset); if (pointer->ready == 2) manconnecting--; @@ -595,7 +718,6 @@ main(int argc, char **argv) else { close (pointer->cliconn.commfd); FD_CLR(pointer->cliconn.commfd, &allset); - FD_CLR(pointer->listenfd, &allset); FD_SET(pointer->managefd, &allset); if (pointer->ready == 2) manconnecting--; @@ -604,11 +726,38 @@ main(int argc, char **argv) } break; } + + case AF_S_CANT_OPEN : { + if ((numofcon>=0) && + (numofcon<=(pointer->usernum)) && + ((pointer->ready)==3)) { + if (pointer->contable[numofcon].state == + S_STATE_OPENING) { + aflog(2, " realm[%d]: user[%d]: DROPPED",j, numofcon); + (pointer->usercon)--; + close(pointer->contable[numofcon].connfd); + pointer->contable[numofcon].state = + S_STATE_CLEAR; + } + } + else { + close (pointer->cliconn.commfd); + FD_CLR(pointer->cliconn.commfd, &allset); + FD_SET(pointer->managefd, &allset); + if (pointer->ready == 2) + manconnecting--; + SSL_clear(pointer->cliconn.ssl); + pointer->ready = 0; + } + break; + } + + + case AF_S_MESSAGE : { if ((pointer->ready) != 3) { close (pointer->cliconn.commfd); FD_CLR(pointer->cliconn.commfd, &allset); - FD_CLR(pointer->listenfd, &allset); FD_SET(pointer->managefd, &allset); manconnecting--; SSL_clear(pointer->cliconn.ssl); @@ -629,10 +778,94 @@ main(int argc, char **argv) if (TYPE_IS_UDP(pointer->type)) { /* udp */ buff[1] = AF_S_LOGIN; buff[2] = AF_S_MESSAGE; - writen(pointer->contable[numofcon].connfd, buff, n+5); + buff[3] = n >> 8; /* high bits of message length */ + buff[4] = n; /* low bits of message length */ + sent = write(pointer->contable[numofcon].connfd, buff, n+5); + if ((sent > 0) && (sent != n)) { + insertblnode(&(pointer->contable[numofcon].head), sent, n, buff); + pointer->contable[numofcon].state = S_STATE_STOPPED; + FD_SET(pointer->contable[numofcon].connfd, &wset); + buff[0] = AF_S_DONT_SEND; /* stopping transfer */ + buff[1] = numofcon >> 8; /* high bits of user number */ + buff[2] = numofcon; /* low bits of user number */ + aflog(3, " realm[%d]: TO user[%d]: BUFFERING MESSAGE STARTED", j, numofcon); + send_message(pointer->type, pointer->cliconn, buff, 5); + } + else if ((sent == -1) && (errno == EAGAIN)) { + insertblnode(&(pointer->contable[numofcon].head), 0, n, buff); + pointer->contable[numofcon].state = S_STATE_STOPPED; + FD_SET(pointer->contable[numofcon].connfd, &wset); + buff[0] = AF_S_DONT_SEND; /* stopping transfer */ + buff[1] = numofcon >> 8; /* high bits of user number */ + buff[2] = numofcon; /* low bits of user number */ + aflog(3, " realm[%d]: TO user[%d]: BUFFERING MESSAGE STARTED", j, numofcon); + send_message(pointer->type, pointer->cliconn, buff, 5); + } + else if (sent == -1) { + aflog(1, " realm[%d]: user[%d]: CLOSED", j, numofcon); + aflog(2, " IP:%s PORT:%s", pointer->contable[numofcon].namebuf, + pointer->contable[numofcon].portbuf); + close(pointer->contable[numofcon].connfd); + FD_CLR(pointer->contable[numofcon].connfd, &allset); + FD_CLR(pointer->contable[numofcon].connfd, &wset); + pointer->contable[numofcon].state = S_STATE_CLOSING; + freebuflist(&pointer->contable[numofcon].head); + buff[0] = AF_S_CONCLOSED; /* closing connection */ + buff[1] = numofcon >> 8; /* high bits of user number */ + buff[2] = numofcon; /* low bits of user number */ + send_message(pointer->type, pointer->cliconn, buff, 5); + } + } + else { /* tcp */ + sent = write(pointer->contable[numofcon].connfd, buff, n); + if ((sent > 0) && (sent != n)) { + insertblnode(&(pointer->contable[numofcon].head), sent, n, buff); + pointer->contable[numofcon].state = S_STATE_STOPPED; + FD_SET(pointer->contable[numofcon].connfd, &wset); + buff[0] = AF_S_DONT_SEND; /* stopping transfer */ + buff[1] = numofcon >> 8; /* high bits of user number */ + buff[2] = numofcon; /* low bits of user number */ + aflog(3, " realm[%d]: TO user[%d]: BUFFERING MESSAGE STARTED", j, numofcon); + send_message(pointer->type, pointer->cliconn, buff, 5); + } + else if ((sent == -1) && (errno == EAGAIN)) { + insertblnode(&(pointer->contable[numofcon].head), 0, n, buff); + pointer->contable[numofcon].state = S_STATE_STOPPED; + FD_SET(pointer->contable[numofcon].connfd, &wset); + buff[0] = AF_S_DONT_SEND; /* stopping transfer */ + buff[1] = numofcon >> 8; /* high bits of user number */ + buff[2] = numofcon; /* low bits of user number */ + aflog(3, " realm[%d]: TO user[%d]: BUFFERING MESSAGE STARTED", j, numofcon); + send_message(pointer->type, pointer->cliconn, buff, 5); + } + else if (sent == -1) { + aflog(1, " realm[%d]: user[%d]: CLOSED", j, numofcon); + aflog(2, " IP:%s PORT:%s", pointer->contable[numofcon].namebuf, + pointer->contable[numofcon].portbuf); + close(pointer->contable[numofcon].connfd); + FD_CLR(pointer->contable[numofcon].connfd, &allset); + FD_CLR(pointer->contable[numofcon].connfd, &wset); + pointer->contable[numofcon].state = S_STATE_CLOSING; + freebuflist(&pointer->contable[numofcon].head); + buff[0] = AF_S_CONCLOSED; /* closing connection */ + buff[1] = numofcon >> 8; /* high bits of user number */ + buff[2] = numofcon; /* low bits of user number */ + send_message(pointer->type, pointer->cliconn, buff, 5); + } + } + } + else if (pointer->contable[numofcon].state == + S_STATE_STOPPED) { + aflog(3, " realm[%d]: TO user[%d]: BUFFERING MESSAGE", j, numofcon); + if (TYPE_IS_UDP(pointer->type)) { /* udp */ + buff[1] = AF_S_LOGIN; + buff[2] = AF_S_MESSAGE; + buff[3] = n >> 8; /* high bits of message length */ + buff[4] = n; /* low bits of message length */ + insertblnode(&(pointer->contable[numofcon].head), 0, n+5, buff); } else { - writen(pointer->contable[numofcon].connfd, buff, n); + insertblnode(&(pointer->contable[numofcon].head), 0, n, buff); } } } @@ -649,14 +882,12 @@ main(int argc, char **argv) buff[2] = pointer->usernum; /* low bits of user number */ buff[3] = pointer->type; /* type of connection */ send_message(pointer->type | TYPE_SSL, pointer->cliconn, buff, 5); - FD_SET(pointer->listenfd, &allset); manconnecting--; } else { aflog(1, " realm[%d]: Wrong password - CLOSING", j); close (pointer->cliconn.commfd); FD_CLR(pointer->cliconn.commfd, &allset); - FD_CLR(pointer->listenfd, &allset); FD_SET(pointer->managefd, &allset); if (pointer->ready == 2) manconnecting--; @@ -665,11 +896,19 @@ main(int argc, char **argv) } break; } + case AF_S_DONT_SEND: { + FD_CLR(pointer->contable[numofcon].connfd, &allset); + break; + } + case AF_S_CAN_SEND: { + FD_SET(pointer->contable[numofcon].connfd, &allset); + break; + } + default : { aflog(1, " realm[%d]: Unrecognized message - CLOSING", j); close (pointer->cliconn.commfd); FD_CLR(pointer->cliconn.commfd, &allset); - FD_CLR(pointer->listenfd, &allset); FD_SET(pointer->managefd, &allset); if (pointer->ready == 2) manconnecting--; @@ -678,6 +917,7 @@ main(int argc, char **argv) if (pointer->contable[i].state != S_STATE_CLEAR) { pointer->contable[i].state = S_STATE_CLEAR; FD_CLR(pointer->contable[i].connfd, &allset); + FD_CLR(pointer->contable[i].connfd, &wset); close(pointer->contable[i].connfd); } } @@ -689,14 +929,14 @@ main(int argc, char **argv) } if (FD_ISSET(pointer->managefd, &rset)) { - aflog(2, " realm[%d]: managefd: FD_ISSET", j); + aflog(3, " realm[%d]: managefd: FD_ISSET", j); len = pointer->addrlen; if (!(pointer->ready)) { aflog(2, " realm[%d]: new client: CONNECTING", j); pointer->cliconn.commfd = accept(pointer->managefd, pointer->cliaddr, &len); flags = fcntl(pointer->cliconn.commfd, F_GETFL, 0); fcntl(pointer->cliconn.commfd, F_SETFL, flags | O_NONBLOCK); - aflog(1, " realm[%d]: Client IP:%s", j, sock_ntop(pointer->cliaddr, len)); + aflog(1, " realm[%d]: Client IP:%s", j, sock_ntop(pointer->cliaddr, len, NULL, NULL)); FD_SET(pointer->cliconn.commfd, &allset); maxfdp1 = (maxfdp1 > (pointer->cliconn.commfd+1)) ? maxfdp1 : (pointer->cliconn.commfd+1); FD_CLR(pointer->managefd, &allset); @@ -717,28 +957,31 @@ usage(char* info) printf(" -h, --help - prints this help\n"); printf(" -n, --hostname - it's used when creating listening sockets\n"); printf(" (default: name returned by hostname function)\n"); - printf(" -l, --listenport - the listening port number - users connect\n"); + printf(" -l, --listenport - listening port number - users connect\n"); printf(" to it (default: 50127)\n"); - printf(" -m, --manageport - the manage port number - second part of active\n"); + printf(" -m, --manageport - manage port number - second part of the active\n"); printf(" port forwarder connects to it (default: 50126)\n"); - printf(" -u, --users - amount of users allowed to use this server\n"); + printf(" -u, --users - the amount of users allowed to use this server\n"); printf(" (default: 5)\n"); - printf(" -c, --cerfile - name of the file with certificate (default: cacert.pem)\n"); - printf(" -k, --keyfile - name of the file with RSA key (default: server.rsa)\n"); - printf(" -f, --cfgfile - name of the file with configuration for active\n"); - printf(" forwarder (server)\n"); - printf(" -p, --proto - type of the server (tcp|udp) - for which protocol it\n"); - printf(" would be (default: tcp)\n"); + printf(" -c, --cerfile - the name of the file with certificate\n"); + printf(" (default: cacert.pem)\n"); + printf(" -k, --keyfile - the name of the file with RSA key (default: server.rsa)\n"); + printf(" -f, --cfgfile - the name of the file with the configuration for the\n"); + printf(" active forwarder (server)\n"); + printf(" -p, --proto - type of server (tcp|udp) - for which protocol it will be\n"); + printf(" operating (default: tcp)\n"); printf(" -O, --heavylog - logging everything to a logfile\n"); printf(" -o, --lightlog - logging some data to a logfile\n"); - printf(" -v, --verbose - to be verbose - program won't enter into\n"); - printf(" the daemon mode (use twice for greater effect)\n"); + printf(" -v, --verbose - to be verbose - program won't enter the daemon mode\n"); + printf(" (use several times for greater effect)\n"); printf(" --nossl - ssl is not used for transfering data (but it's still\n"); - printf(" used to establish connection) (default: ssl is used)\n"); + printf(" used to establish a connection) (default: ssl is used)\n"); printf(" --nozlib - zlib is not used for compressing data (default:\n"); printf(" zlib is used)\n"); printf(" --pass - set the password used for client identification\n"); - printf(" (default: no password)\n\n"); + printf(" (default: no password)\n"); + printf(" -4, --ipv4 - use ipv4 only\n"); + printf(" -6, --ipv6 - use ipv6 only\n\n"); exit(0); } diff --git a/buflist.c b/buflist.c new file mode 100644 index 0000000..b128249 --- /dev/null +++ b/buflist.c @@ -0,0 +1,69 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004 jeremian <jeremian [at] poczta.fm> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include <stdlib.h> +#include <string.h> + +#include "buflist.h" + +int +insertblnode(blnodeT** headRef, int actptr, int msglen, unsigned char* buff) +{ + blnodeT* newnode, *lastnode; + lastnode = newnode = *headRef; + while (newnode) { + lastnode = newnode; + newnode = newnode->next; + } + newnode = calloc(1, sizeof(blnodeT)); + newnode->next = NULL; + newnode->actptr = 0; + newnode->msglen = msglen - actptr; + newnode->buff = calloc(1, newnode->msglen); + if (newnode->buff == NULL) + return 1; + strncpy(newnode->buff, buff, newnode->msglen); + if (lastnode) + lastnode->next = newnode; + else + *headRef = newnode; + return 0; +} + +int +deleteblnode(blnodeT** headRef) +{ + blnodeT* node = *headRef; + if (*headRef == NULL) + return 1; + *headRef = node->next; + free(node->buff); + free(node); + return 0; +} + +int +freebuflist(blnodeT** headRef) +{ + while (*headRef) { + deleteblnode(headRef); + } + return 0; +} diff --git a/buflist.h b/buflist.h new file mode 100644 index 0000000..c4baeae --- /dev/null +++ b/buflist.h @@ -0,0 +1,35 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004 jeremian <jeremian [at] poczta.fm> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef _JS_BUFLIST_H +#define _JS_BUFLIST_H + +typedef struct blnode { + int actptr; + int msglen; + unsigned char* buff; + struct blnode* next; +} blnodeT; + +int insertblnode(blnodeT** headRef, int actptr, int msglen, unsigned char* buff); +int deleteblnode(blnodeT** headRef); +int freebuflist(blnodeT** headRef); + +#endif diff --git a/docs/en/README b/docs/en/README index fb52e60..e9ded51 100644 --- a/docs/en/README +++ b/docs/en/README @@ -1,4 +1,4 @@ -AF - Active Port Forwarder v0.5.3 - README +AF - Active Port Forwarder v0.5.4 - README Copyright (C) 2003,2004 jeremian - <jeremian [at] poczta.fm> =================== @@ -7,85 +7,287 @@ Copyright (C) 2003,2004 jeremian - <jeremian [at] poczta.fm> GRAY-WORLD.NET / Active Port Forwarder ========================== - The Active Port Forwarder program is part of the Gray-World.net projects. + The Active Port Forwarder program is part of the Gray-World.net projects. Our Gray-World Team presents on the http://gray-world.net website the projects - and publications we are working on which are related to the NACS (Network - Access Control System) bypassing research field and to the computer and + and publications we are working on which are related to the NACS (Network + Access Control System) bypassing research field and to the computer and network security topics. ================================================================================ +======= +SUMMARY +======= -Active port forwarder is a software for secure port forwarding. -It uses ssl for increasing security of communication between server and client. +INTRO -Af is dedicated for people, who don't have external ip number and want to +1. INSTALLATION + 1.1 Instructions + 1.2 Required libs + 1.3 Tested platforms +2. USAGE + 2.1 afserver + 2.2 afclient +3. EXAMPLES + 3.1 tcp mode + 3.2 reverse udp mode +4. BUGS/PROBLEMS + +NOTES + +THANKS + +================================================================================ + +===== +INTRO +===== + +Active port forwarder is a software tool for secure port forwarding. +It uses ssl to increase security of communication between a server and a client. +Originally, it was developed to forward data point to point. However, the need +for bypassing firewalls in order to connect to internally located computers +influenced the further development of the project. + +AF is dedicated for people, who don't have an external ip number and want to make some services available across the net. -Moreover, zlib is used to compress transfered data. +Moreover, zlib is used to compress the transferred data. + +Using one, permanent data/control channel with flow control / packet buffering +provides good performance and reasonably small latency. + +================================================================================ + +=============== +1. INSTALLATION +=============== + + 1.1 Instructions + ---------------- + +1. Download the compressed sources from http://www.gray-world.net/pr_af.shtml +2. Unpack them with tar zxvf +3. Type "make". +4. If something goes wrong - mail the author or post a message on + http://gray-world.net/board/ + + 1.2 Required libs + ----------------- + +1. openssl - http://www.openssl.org/ +2. zlib - http://www.gzip.org/zlib/ + + 1.3 Tested platforms + -------------------- + +1. Linux: + Gentoo, Slackware, Mandrake - built without any problems +2. Freebsd: + 4.4, 4.9 - have to use patch from project homepage +3. Windows: + win32 - cygwin version is available on the project homepage + +================================================================================ + +======== +2. USAGE +======== + + 2.1 afserver + ------------ + + Options: + -h, --help - prints this help + -n, --hostname - it's used when creating listening sockets + (default: name returned by hostname function) + -l, --listenport - listening port number - users connect + to it (default: 50127) + -m, --manageport - manage port number - second part of the active + port forwarder connects to it (default: 50126) + -u, --users - the amount of users allowed to use this server + (default: 5) + -c, --cerfile - the name of the file with certificate + (default: cacert.pem) + -k, --keyfile - the name of the file with RSA key (default: server.rsa) + -f, --cfgfile - the name of the file with the configuration for the + active forwarder (server) + -p, --proto - type of server (tcp|udp) - for which protocol it will be + operating (default: tcp) + -O, --heavylog - logging everything to a logfile + -o, --lightlog - logging some data to a logfile + -v, --verbose - to be verbose - program won't enter the daemon mode + (use several times for greater effect) + --nossl - ssl is not used for transferring data (but it's still + used to establish a connection) (default: ssl is used) + --nozlib - zlib is not used for compressing data (default: + zlib is used) + --pass - set the password used for client identification + (default: no password) + -4, --ipv4 - use ipv4 only + -6, --ipv6 - use ipv6 only -EXAMPLE 1: + 2.2 afclient + ------------ -The use of it is extremely simple. Let's suppose we want to create http server on -our computer and we are behind masquerade or firewall: + Options: + -h, --help - prints this help + -n, --servername - where the second part of the active + port forwarder is running (required) + -m, --manageport - manage port number - server must be + listening on it (default: 50126) + -d, --hostname - the name of this host/remote host - the final + destination of the packets (default: the name + returned by hostname function) + -p, --portnum - the port we are forwarding the connection to (required) + -k, --keyfile - the name of the file with RSA key (default: client.rsa) + -u, --udpmode - udp mode - client will use udp protocol to + communicate with the hostname + -U, --reverseudp - reverse udp forwarding. Udp packets will be forwarded + from hostname:portnum (-p) to the server name:portnum + (-m) + -O, --heavylog - logging everything to a logfile + -o, --lightlog - logging some data to a logfile + -v, --verbose - to be verbose - program won't enter the daemon mode + (use several times for greater effect) + --pass - set the password used for client identification + (default: no password) + -4, --ipv4 - use ipv4 only + -6, --ipv6 - use ipv6 only + -l, --load - load a module for packets filtering + +================================================================================ + +=========== +3. EXAMPLES +=========== + + 3.1 tcp mode + ------------ + + local network |FireWall| Internet + || + || User 1 + || /(tcp) + AF Client <---Encrypted/Compressed channel---> AF Server + / || | \(tcp) + /(tcp) || (tcp)| User 2 + / || \ + Http server || User 3 + || -1) We have to find some machine on the net with external ip and shell account. -2) Use make to compile everything on that machine. (you can freely remove afclient - and client.rsa files) +The use of it is extremely simple. Let's suppose we want to create a http server +on our computer and we are behind a masquerade or a firewall: -3) You can edit config file or just type from the console: (to use config type -f <cfgfile>) - $ ./afserver +1) We have to find some machine on the net with an external ip and a shell + account. + +2) Use "make" to compile everything on that machine. (you can freely remove the + afclient and client.rsa files) + +3) You can edit the config file or just type from the console (to use the config + type -f <cfgfile>) : + $ ./afserver This will work, if you want to use default values: - - hostname will be taken from hostname function (it would be ideally, if there is - appropriate registration in /etc/hosts) + - hostname will be taken from hostname function (it would be ideally, if + there is appropriate registration in /etc/hosts) - server will be listening for users on port 50127 - server will be listening for client on port 50126 - server will be for maximum 5 users - server will forward tcp packets - there will be no logging and no verbose messages - there will be no password identification + - ip protocol family will be unspecified -4) We use make on our machine (we can delete everything apart afclient and client.rsa) +4) We use "make" on our machine (we can delete everything apart from afclient + and client.rsa) 5) We are typing from the console: - $ ./afclient -n <name of the server> -p 80 - Where <name of the server> is a string like : 'bastion.univ.gda.pl' or '153.19.7.200' + $ ./afclient -n <name of the server> -p 80 + Where <name of the server> is a string like : 'bastion.univ.gda.pl' or + '153.19.7.200' + +6) We can now enter with a web-browser to: <name of the server>:50127 and we + will enter to our computer in the fact. + + 3.2 reverse udp mode + -------------------- -6) We can now enter with webbrowser to : <name of the server>:50127 and we will enter to our - computer in the fact. + local network |FireWall| Internet + || (udp) + || User 1-------AF Client + || /(tcp) + AF Client <---Encrypted/Compressed channel---> AF Server + / || | + /(udp) || (tcp)| + / || / + Game server || AF Client-------User 2 + || (udp) -EXAMPLE 2: -Let's see how to use af to forward udp packets. Suppose we want to create a game server -on our computer (udp port 27960 on our machine): +Let's see how to use af to forward udp packets. Suppose we want to create a game +server on our computer (udp port 27960 on our machine): -1) - 4) is the same like in example 1. (but we add option: -t udp) +1) - 4) is the same like in example 1. (but we add option: -p udp) 5) We are typing from the console: $ ./afclient -u -n <name of the server> -p 27960 - Where <name of the server> is a name (or ip) of a host where our server is running. + Where <name of the server> is a name (or ip) of a host where our server is + running. + +6) Connecting to our game is more complicated. The user must use afclient to do + this. He has to specify the server he is connecting to and the port, which + his program will be listening on: + $ ./afclient -U -d <hostname> -p <portnum> -n <name of the server> \ + -m <server port> + Where <hostname> is the name of the user machine (who wants to connect to our + game). <portnum> is the port he will be connecting to. <name of the server> + is the name of the host where our server is running. <server port> is the + port on which the server is listening for users. In order to connect to our + game, the user has to connect to <hostname>:<portnum>. + +================================================================================ + +================ +4. BUGS/PROBLEMS +================ + +There are no known/open bugs at the moment. + +================================================================================ + +===== +NOTES +===== + +Active port forwarder is still under development, so please sent any comments, +bugs notices and suggestions about it to <jeremian [at] poczta.fm> + +If you have some problems or want to share your opinions with others, feel free +to post a message at http://gray-world.net/board/ + +================================================================================ -6) Connecting to our game is more complicated. User must use afclient to do this. - He has to specify server he is connecting to and port which his program will be listening on: - $ ./afclient -U -d <hostname> -p <portnum> -n <name of the server> -m <server port> - Where <hostname> is name of user machine (who wants to connect to our game). <portnum> - is a port he will be connecting to. <name of the server> is a name of a host where our server - is running. <server port> is a port on which server is listening for users. - In order to connect to our game, user have to connect to <hostname>:<portnum>. +====== +THANKS +====== + Big thanks to the GW Team: -Active port forwarder is still under development, so please sent me any comments, bugs notices -and suggestions about it to jeremian@poczta.fm + to Alex <alex [at] gray-world.net> + and Simon <scastro [at] entreelibre.com> for testing AF and a lot of advices. + Thanks to Ilia Perevezentsev <iliaper [at] mail.ru> who read and corrected the +README file. -And thanks for using this software! + And thanks for using this software! LICENSE ------- - Active Port Forwarder is distributed under the terms of the GNU General Public License - v2.0 and is copyright (c) 2003 jeremian <jeremian [at] poczta.fm>. - See the file COPYING for details. + Active Port Forwarder is distributed under the terms of the GNU General + Public License v2.0 and is copyright (c) 2003,2004 jeremian <jeremian [at] + poczta.fm>. See the file COPYING for details. diff --git a/exmodule.c b/exmodule.c new file mode 100644 index 0000000..133609c --- /dev/null +++ b/exmodule.c @@ -0,0 +1,66 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004 jeremian <jeremian [at] poczta.fm> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +/* This example module put IP of the connected user into a body of the message */ +#include <string.h> +/* There is no required headers for module to work. + * We just need string.h for memcpy and strlen functions. + */ + +/* info + * return values: + * info about module + */ + +char* +info(void) +{ + return "An example module"; +} + +/* allow + * return values: + * 0 - allow to connect + * !=0 - drop the connection + */ + +int +allow(char* host, char* port) +{ + return 0; /* allow to connect */ +} + +/* filter + * return values: + * 0 - allow to transfer + * 1 - drop the packet + * 2 - drop the connection + */ + +int +filter(char* host, unsigned char* message, int* length) +{ + int n; + n = strlen(host); + message[*length] = '|'; + memcpy(&message[*length+1], host, n); + *length += n+1; + return 0; /* allow to transfer */ +} @@ -28,150 +28,160 @@ ConfigurationT parsefile(char* name, int* status) { - static ConfigurationT cfg; - FILE* file = NULL; - int state, i, n; - char buff[256]; - char helpbuf1[256]; - char helpbuf2[256]; + static ConfigurationT cfg; + FILE* file = NULL; + int state, i, n; + char buff[256]; + char helpbuf1[256]; + char helpbuf2[256]; - *status = 1; + *status = 1; - memset(buff, 0, 256); + memset(buff, 0, 256); - cfg.certif = NULL; - cfg.keys = NULL; - cfg.size = 0; - cfg.realmtable = NULL; - cfg.logging = 0; - cfg.logfnam = NULL; + cfg.certif = NULL; + cfg.keys = NULL; + cfg.size = 0; + cfg.realmtable = NULL; + cfg.logging = 0; + cfg.logfnam = NULL; - state = F_UNKNOWN; + state = F_UNKNOWN; - file = fopen(name, "r"); - if (file == NULL) { - return cfg; - } + file = fopen(name, "r"); + if (file == NULL) { + return cfg; + } - while (fgets(buff, 256, file) != NULL) { - helpbuf1[0] = 0; - sscanf(buff, "%s", helpbuf1); - if (strcmp(helpbuf1, "newrealm")==0) { - ++cfg.size; - } - } - rewind(file); + while (fgets(buff, 256, file) != NULL) { + helpbuf1[0] = 0; + sscanf(buff, "%s", helpbuf1); + if (strcmp(helpbuf1, "newrealm")==0) { + ++cfg.size; + } + } + rewind(file); - cfg.realmtable = calloc(cfg.size, sizeof(RealmT)); - cfg.size = 0; - *status = 0; + cfg.realmtable = calloc(cfg.size, sizeof(RealmT)); + cfg.size = 0; + *status = 0; - while (fgets(buff, 256, file) != NULL) { - (*status)++; - state = sscanf(buff, "%s %s", helpbuf1, helpbuf2); - if (helpbuf1[0] == '#') { - memset(buff, 0, 256); - continue; - } - if (state == 1) { - if (strcmp(helpbuf1, "newrealm")==0) { - ++cfg.size; - TYPE_SET_SSL(cfg.realmtable[cfg.size-1].type); - TYPE_SET_ZLIB(cfg.realmtable[cfg.size-1].type); - } - else if (cfg.size == 0) { - return cfg; - } - else if (strcmp(helpbuf1, "nossl")==0) { - TYPE_UNSET_SSL(cfg.realmtable[cfg.size-1].type); - } - else if (strcmp(helpbuf1, "nozlib")==0) { - TYPE_UNSET_ZLIB(cfg.realmtable[cfg.size-1].type); - } - else { - return cfg; - } - } - else if (state == 2) { - if (strcmp(helpbuf1, "certificate")==0) { - cfg.certif = calloc(strlen(helpbuf2)+1, sizeof(char)); - strcpy(cfg.certif, helpbuf2); - } - else if (strcmp(helpbuf1, "key")==0) { - cfg.keys = calloc(strlen(helpbuf2)+1, sizeof(char)); - strcpy(cfg.keys, helpbuf2); - } - else if (strcmp(helpbuf1, "heavylog")==0) { - if (cfg.logging) - return cfg; - cfg.logging = 2; - cfg.logfnam = calloc(strlen(helpbuf2)+1, - sizeof(char)); - strcpy(cfg.logfnam, helpbuf2); - - } - else if (strcmp(helpbuf1, "lightlog")==0) { - if (cfg.logging) { - return cfg; - } - cfg.logging = 1; - cfg.logfnam = calloc(strlen(helpbuf2)+1, - sizeof(char)); - strcpy(cfg.logfnam, helpbuf2); - } - else if (cfg.size == 0) { - return cfg; - } - else if (strcmp(helpbuf1, "hostname")==0) { - cfg.realmtable[cfg.size-1].hostname = calloc(strlen(helpbuf2)+1, - sizeof(char)); - strcpy(cfg.realmtable[cfg.size-1].hostname, helpbuf2); - } - else if (strcmp(helpbuf1, "listen")==0) { - cfg.realmtable[cfg.size-1].lisportnum = calloc(strlen(helpbuf2)+1, - sizeof(char)); - strcpy(cfg.realmtable[cfg.size-1].lisportnum, helpbuf2); - } - else if (strcmp(helpbuf1, "pass")==0) { - n = strlen(helpbuf2); - for (i = 0; i < n; ++i) { - cfg.realmtable[cfg.size-1].pass[i%4] += helpbuf2[i]; - } - } - else if (strcmp(helpbuf1, "manage")==0) { - cfg.realmtable[cfg.size-1].manportnum = calloc(strlen(helpbuf2)+1, - sizeof(char)); - strcpy(cfg.realmtable[cfg.size-1].manportnum, helpbuf2); - } - else if (strcmp(helpbuf1, "users")==0) { - cfg.realmtable[cfg.size-1].users = calloc(strlen(helpbuf2)+1, - sizeof(char)); - strcpy(cfg.realmtable[cfg.size-1].users, helpbuf2); - } - else if (strcmp(helpbuf1, "proto")==0) { - if (TYPE_IS_SET(cfg.realmtable[cfg.size-1].type)) { - return cfg; - } - if (strcmp(helpbuf2, "tcp")==0) { - TYPE_SET_TCP(cfg.realmtable[cfg.size-1].type); - } - else if (strcmp(helpbuf2, "udp")==0) { - TYPE_SET_UDP(cfg.realmtable[cfg.size-1].type); - } - else { - return cfg; - } - } - else { - return cfg; - } - } - memset(buff, 0, 256); - } + while (fgets(buff, 256, file) != NULL) { + (*status)++; + state = sscanf(buff, "%s %s", helpbuf1, helpbuf2); + if (helpbuf1[0] == '#') { + memset(buff, 0, 256); + continue; + } + if (state == 1) { + if (strcmp(helpbuf1, "newrealm")==0) { + ++cfg.size; + TYPE_SET_SSL(cfg.realmtable[cfg.size-1].type); + TYPE_SET_ZLIB(cfg.realmtable[cfg.size-1].type); + } + else if (cfg.size == 0) { + return cfg; + } + else if (strcmp(helpbuf1, "nossl")==0) { + TYPE_UNSET_SSL(cfg.realmtable[cfg.size-1].type); + } + else if (strcmp(helpbuf1, "nozlib")==0) { + TYPE_UNSET_ZLIB(cfg.realmtable[cfg.size-1].type); + } + else if (strcmp(helpbuf1, "ipv4")==0) { + if (TYPE_IS_UNSPEC(cfg.realmtable[cfg.size-1].type)) { + TYPE_SET_IPV4(cfg.realmtable[cfg.size-1].type); + } + else { + return cfg; + } + } + else if (strcmp(helpbuf1, "ipv6")==0) { + if (TYPE_IS_UNSPEC(cfg.realmtable[cfg.size-1].type)) { + TYPE_SET_IPV6(cfg.realmtable[cfg.size-1].type); + } + else { + return cfg; + } + } + else { + return cfg; + } + } + else if (state == 2) { + if (strcmp(helpbuf1, "certificate")==0) { + cfg.certif = calloc(strlen(helpbuf2)+1, sizeof(char)); + strcpy(cfg.certif, helpbuf2); + } + else if (strcmp(helpbuf1, "key")==0) { + cfg.keys = calloc(strlen(helpbuf2)+1, sizeof(char)); + strcpy(cfg.keys, helpbuf2); + } + else if (strcmp(helpbuf1, "heavylog")==0) { + if (cfg.logging) { + return cfg; + } + cfg.logging = 3; + cfg.logfnam = calloc(strlen(helpbuf2)+1, sizeof(char)); + strcpy(cfg.logfnam, helpbuf2); + } + else if (strcmp(helpbuf1, "lightlog")==0) { + if (cfg.logging) { + return cfg; + } + cfg.logging = 1; + cfg.logfnam = calloc(strlen(helpbuf2)+1, sizeof(char)); + strcpy(cfg.logfnam, helpbuf2); + } + else if (cfg.size == 0) { + return cfg; + } + else if (strcmp(helpbuf1, "hostname")==0) { + cfg.realmtable[cfg.size-1].hostname = calloc(strlen(helpbuf2)+1, sizeof(char)); + strcpy(cfg.realmtable[cfg.size-1].hostname, helpbuf2); + } + else if (strcmp(helpbuf1, "listen")==0) { + cfg.realmtable[cfg.size-1].lisportnum = calloc(strlen(helpbuf2)+1, sizeof(char)); + strcpy(cfg.realmtable[cfg.size-1].lisportnum, helpbuf2); + } + else if (strcmp(helpbuf1, "pass")==0) { + n = strlen(helpbuf2); + for (i = 0; i < n; ++i) { + cfg.realmtable[cfg.size-1].pass[i%4] += helpbuf2[i]; + } + } + else if (strcmp(helpbuf1, "manage")==0) { + cfg.realmtable[cfg.size-1].manportnum = calloc(strlen(helpbuf2)+1, sizeof(char)); + strcpy(cfg.realmtable[cfg.size-1].manportnum, helpbuf2); + } + else if (strcmp(helpbuf1, "users")==0) { + cfg.realmtable[cfg.size-1].users = calloc(strlen(helpbuf2)+1, sizeof(char)); + strcpy(cfg.realmtable[cfg.size-1].users, helpbuf2); + } + else if (strcmp(helpbuf1, "proto")==0) { + if (TYPE_IS_SET(cfg.realmtable[cfg.size-1].type)) { + return cfg; + } + if (strcmp(helpbuf2, "tcp")==0) { + TYPE_SET_TCP(cfg.realmtable[cfg.size-1].type); + } + else if (strcmp(helpbuf2, "udp")==0) { + TYPE_SET_UDP(cfg.realmtable[cfg.size-1].type); + } + else { + return cfg; + } + } + else { + return cfg; + } + } + memset(buff, 0, 256); + } - fclose(file); + fclose(file); - *status = 0; - return cfg; + *status = 0; + return cfg; } @@ -23,156 +23,176 @@ #include "stats.h" #include <string.h> #include <errno.h> -#include <signal.h> #include <zlib.h> -static void -sig_alrm(int signo) -{ - return; -} - int -ip_listen(const char *host, const char *serv, socklen_t *addrlenp, const char *type) +ip_listen(int* sockfd, const char *host, const char *serv, socklen_t *addrlenp, const char type) { - int listenfd, n, typ; + int n; const int on = 1; struct addrinfo hints, *res, *ressave; - if (strcmp(type, "udp") == 0) - typ = 0; /* this is udp_listen */ - else - typ = 1; /* default: tcp_listen */ - bzero(&hints, sizeof(struct addrinfo)); hints.ai_flags = AI_PASSIVE; - hints.ai_family = AF_UNSPEC; + if (type & 0x02) { + hints.ai_family = AF_INET; + } + else if (type & 0x04) { + hints.ai_family = AF_INET6; + } + else { + hints.ai_family = AF_UNSPEC; + } - if (typ) + if (type & 0x01) { hints.ai_socktype = SOCK_STREAM; - else + } + else { hints.ai_socktype = SOCK_DGRAM; + } if ( (n = getaddrinfo(host, serv, &hints, &res)) != 0) { - printf("%s_listen error for %s, %s: %s\n", - (typ)?"tcp":"udp", host, serv, gai_strerror(n)); - exit(1); + return n; } ressave = res; do { - listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (listenfd < 0) + (*sockfd) = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if ((*sockfd) < 0) { continue; /* error, try next one */ + } - if (typ) /* tcp_listen */ - setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0) + if (type & 0x01) { /* tcp_listen */ + setsockopt((*sockfd), SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + } + if (bind((*sockfd), res->ai_addr, res->ai_addrlen) == 0) { break; /* success */ + } - close(listenfd); /* bind error, close and try next one */ + close((*sockfd)); /* bind error, close and try next one */ } while ( (res = res->ai_next) != NULL); if (res == NULL) { /* errno from final socket() or bind() */ - printf("%s_listen error for %s, %s\n", (typ)?"tcp":"udp", host, serv); - exit(1); + return 1; } - if (typ) /* tcp_listen */ - listen(listenfd, 1); + if (type & 0x01) { /* tcp_listen */ + listen((*sockfd), 1); + } - if (addrlenp) + if (addrlenp) { *addrlenp = res->ai_addrlen; /* return size of protocol address */ + } freeaddrinfo(ressave); - return(listenfd); + return(0); } int -ip_connect(const char *host, const char *serv, const char* type) +ip_connect(int* sockfd, const char *host, const char *serv, const char type) { - int sockfd, n, typ; + int n; struct addrinfo hints, *res, *ressave; - if (strcmp(type, "udp") == 0) - typ = 0; /* this is udp_listen */ - else - typ = 1; /* default: tcp_listen */ - bzero(&hints, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; - if (typ) + if (type & 0x02) { + hints.ai_family = AF_INET; + } + else if (type & 0x04) { + hints.ai_family = AF_INET6; + } + else { + hints.ai_family = AF_UNSPEC; + } + if (type & 0x01) { hints.ai_socktype = SOCK_STREAM; - else + } + else { hints.ai_socktype = SOCK_DGRAM; + } if ( (n = getaddrinfo(host, serv, &hints, &res)) != 0) { - printf("%s_connect error for %s, %s: %s\n", - (typ)?"tcp":"udp", host, serv, gai_strerror(n)); - exit(1); + return n; } ressave = res; do { - sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (sockfd < 0) + (*sockfd) = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if ((*sockfd) < 0) { continue; /* ignore this one */ + } - if (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0) + if (connect((*sockfd), res->ai_addr, res->ai_addrlen) == 0) { break; /* success */ + } - close(sockfd); /* ignore this one */ + close((*sockfd)); /* ignore this one */ } while ( (res = res->ai_next) != NULL); if (res == NULL) { /* errno set from final connect() */ - printf("%s_connect error for %s, %s\n", (typ)?"tcp":"udp", host, serv); - exit(1); + return 1; } freeaddrinfo(ressave); - return(sockfd); + return(0); } char * -sock_ntop(const struct sockaddr *sa, socklen_t salen) +sock_ntop(const struct sockaddr *sa, socklen_t salen, char* namebuf, char* portbuf) { char portstr[7]; static char str[128]; /* Unix domain is largest */ - switch (sa->sa_family) { + switch (sa->sa_family) { case AF_INET: { struct sockaddr_in *sin = (struct sockaddr_in *) sa; - if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)) == NULL) + if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)) == NULL) { return(NULL); + } + if (namebuf) { + if (inet_ntop(AF_INET, &sin->sin_addr, namebuf, 128) == NULL) { + return(NULL); + } + } if (ntohs(sin->sin_port) != 0) { snprintf(portstr, sizeof(portstr), ".%d", ntohs(sin->sin_port)); + if (portbuf) { + snprintf(portbuf, 7, "%d", ntohs(sin->sin_port)); + } strcat(str, portstr); } return(str); } - -#ifdef IPV6 +#ifdef AF_INET6 case AF_INET6: { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa; - if (inet_ntop(AF_INET6, &sin6->sin6_addr, str, sizeof(str)) == NULL) + if (inet_ntop(AF_INET6, &sin6->sin6_addr, str, sizeof(str)) == NULL) { return(NULL); + } + if (namebuf) { + if (inet_ntop(AF_INET6, &sin6->sin6_addr, namebuf, 128) == NULL) { + return(NULL); + } + } if (ntohs(sin6->sin6_port) != 0) { snprintf(portstr, sizeof(portstr), ".%d", ntohs(sin6->sin6_port)); + if (portbuf) { + snprintf(portbuf, 7, "%d", ntohs(sin6->sin6_port)); + } strcat(str, portstr); } return(str); } #endif - - default: - snprintf(str, sizeof(str), "sock_ntop: unknown AF_xxx: %d, len %d", - sa->sa_family, salen); + default: { + snprintf(str, sizeof(str), "sock_ntop: unknown AF_xxx: %d, len %d", sa->sa_family, salen); return(str); } + } return (NULL); } @@ -182,10 +202,7 @@ SSL_writen(SSL* fd, unsigned char* buf, int amount) int sent, n; sent = 0; while (sent < amount) { - signal(SIGALRM, sig_alrm); - alarm(5); n = SSL_write(fd, buf+sent, amount - sent); - alarm(0); if (n != -1) { sent += n; } @@ -223,10 +240,7 @@ writen(int fd, unsigned char* buf, int amount) int sent, n; sent = 0; while (sent < amount) { - signal(SIGALRM, sig_alrm); - alarm(5); n = write(fd, buf+sent, amount - sent); - alarm(0); if (n != -1) { sent += n; } @@ -39,9 +39,9 @@ typedef struct { SSL* ssl; } clifd; -int ip_listen(const char *host, const char *serv, socklen_t *addrlenp, const char *type); /* socket, bind, listen... */ -int ip_connect(const char *host, const char *serv, const char *type); /* socket, connect... */ -char* sock_ntop(const struct sockaddr* sa, socklen_t salen); /* return the hostname of connected user */ +int ip_listen(int* sockfd, const char *host, const char *serv, socklen_t *addrlenp, const char type); /* socket, bind, listen... */ +int ip_connect(int* sockfd, const char *host, const char *serv, const char type); /* socket, connect... */ +char* sock_ntop(const struct sockaddr* sa, socklen_t salen, char* namebuf, char* portbuf); /* return the IP of connected user */ int send_message(char type, clifd fd, unsigned char* buf, int amount); int get_message(char type, clifd fd, unsigned char* buf, int amount); |