From 1adde65db245ec1fca752cfee4c198badf40fb5f Mon Sep 17 00:00:00 2001 From: Jakub Sławiński Date: Tue, 15 Mar 2005 01:22:55 +0100 Subject: v0.6 - Fixed: default password incompatibilities from config file - Added: "client's id" option - Lightly Modified: verbose mode - Added: temporary listen ports - Fixed: bug in printing "client's id" - Added: 'dateformat' option to set format of the date in the logs - Modified: command line option and config file behaviour - Added: logging to a socket - Fixed: parsing config file - Fixed: major bug in packet buffering - Added: several clients-users in one realm - Modified: default hostname used by afserver - Modified: server listening behaviour (for clients) - Fixed: bug in checking options values - Modified: verbose mode - Modified: client initial connection to server - Added: connection time / uptime statistics - Added: first version of remote administration (statistics only) - Fixed: major bug in remove_client routine - Added: 'raclients' option - Added: use of automake/autoconf - Added: creating ~/.apf directory - Modified: the way of creating/managing keys/certificates - Added: 'dnslookups' option - Modified: usage functions - Fixed: no handling of missing 'listen' option after 'newrealm' in config file - Added: 'quit' command in remote administration mode - Modified: logging error messages during initialization - Modified: 'newrealm' changed to 'realm' in config file - Added: realm names - Modified: connection time / uptime - Added: client names / unique numbers - Added: user unique numbers - Fixed: segmentation fault after 'quit' command --- src/afclient.c | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1000 insertions(+) create mode 100644 src/afclient.c (limited to 'src/afclient.c') diff --git a/src/afclient.c b/src/afclient.c new file mode 100644 index 0000000..cc3c0c8 --- /dev/null +++ b/src/afclient.c @@ -0,0 +1,1000 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 jeremian + * + * 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 + +#include "afclient.h" + +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'}, + {"heavysocklog", 1, 0, 'S'}, + {"lightsocklog", 1, 0, 's'}, + {"pass", 1, 0, 301}, +#ifdef AF_INET6 + {"ipv4", 0, 0, '4'}, + {"ipv6", 0, 0, '6'}, +#endif +#ifdef HAVE_LIBDL + {"load", 1, 0, 'l'}, + {"Load", 1, 0, 'L'}, +#endif + {"id", 1, 0, 'i'}, + {"dateformat", 1, 0, 'D'}, + {"remoteadmin", 0, 0, 'r'}, + {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]; + int maxfdp1, usernum, usercon; + socklen_t len, addrlen; + struct sockaddr* cliaddr; + fd_set rset, allset, wset, tmpset; + char verbose = 0; + char remote = 0; + char logging = 0; + char socklogging = 0; + char* name = NULL; + char* id = NULL; + char* manage = NULL; + char* desnam = NULL; + char* despor = NULL; + char* keys = NULL; + char* logfname = NULL; + char* logsport = NULL; + char* dateformat = NULL; + char ipfam = 0; + unsigned char pass[4] = {1, 2, 3, 4}; + char udp = 0; + char reverse = 0; + char type = 0; + struct sigaction act; +#ifdef HAVE_LIBDL + moduleT module = {0, NULL, NULL, NULL, NULL}, secmodule = {0, NULL, NULL, NULL, NULL}; +#endif + + 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); + +#ifdef AF_INET6 +# ifdef HAVE_LIBDL + while ((n = getopt_long(argc, argv, "huUn:m:d:p:vk:O:o:46l:L:i:D:S:s:r", long_options, 0)) != -1) { +# else + while ((n = getopt_long(argc, argv, "huUn:m:d:p:vk:O:o:46i:D:S:s:r", long_options, 0)) != -1) { +# endif +#else +# ifdef HAVE_LIBDL + while ((n = getopt_long(argc, argv, "huUn:m:d:p:vk:O:o:l:L:i:D:S:s:r", long_options, 0)) != -1) { +# else + while ((n = getopt_long(argc, argv, "huUn:m:d:p:vk:O:o:i:D:S:s:r", long_options, 0)) != -1) { +# endif +#endif + switch (n) { + case 'h': { + usage(AF_VER("Active port forwarder (client)")); + break; + } + case 'n': { + name = optarg; + break; + } + case 'i': { + id = 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 'S': { + logsport = optarg; + socklogging = 3; + break; + } + case 's': { + logsport = optarg; + socklogging = 1; + break; + } + case 301: { + n = strlen(optarg); + memset(pass, 0, 4); + for (i = 0; i < n; ++i) { + pass[i%4] += optarg[i]; + } + break; + } +#ifdef AF_INET6 + case '4': { + if (ipfam != 0) { + ipfam = -1; + } + else { + ipfam = 4; + } + break; + } + case '6': { + if (ipfam != 0) { + ipfam = -1; + } + else { + ipfam = 6; + } + break; + } +#endif +#ifdef HAVE_LIBDL + case 'l': { + module.name = optarg; + break; + } + case 'L': { + secmodule.name = optarg; + break; + } +#endif + case 'D': { + dateformat = optarg; + break; + } + case 'r': { + remote = 1; + break; + } + case '?': { + usage(""); + break; + } + } + } + + 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 (keys == NULL) { + keys = "client.rsa"; + } + if ((reverse == 0) && (remote == 0) && (desnam == NULL)) { + gethostname(hostname, 100); + desnam = hostname; + } + if ((!remote) && (despor == NULL)) { + usage("Destination port number is required"); + } + + if ((temp2 = loginit(verbose, logging, socklogging, logfname, logsport, dateformat))) { + switch (temp2) { + case 1: + printf("Can't open file to log to... exiting\n"); + break; + case 2: + printf("Can't connect to localhost:%s... exiting\n", logsport); + break; + case 3: + printf("Can't open socket to log to... exiting\n"); + break; + } + exit(1); + } + +#ifdef HAVE_LIBDL + if (loadmodule(&module)) { + aflog(0, "Loading a module %s failed!", module.name); + exit(1); + } + if (loadmodule(&secmodule)) { + aflog(0, "Loading a module %s failed!", secmodule.name); + exit(1); + } +#endif + + TYPE_SET_SSL(type); + TYPE_SET_ZLIB(type); + +#ifdef AF_INET6 + if (ipfam == -1) { + aflog(0, "Conflicting types of ip protocol family... exiting"); + exit(1); + } + else if (ipfam == 4) { + TYPE_SET_IPV4(type); + } + else if (ipfam == 6) { + TYPE_SET_IPV6(type); + } +#endif + ipfam = 0x01; +#ifdef AF_INET6 + if (TYPE_IS_IPV4(type)) { + ipfam |= 0x02; + } + else if (TYPE_IS_IPV6(type)) { + ipfam |= 0x04; + } +#endif + + if (!reverse) { + SSL_library_init(); + method = SSLv3_client_method(); + ctx = SSL_CTX_new(method); + if (SSL_CTX_set_cipher_list(ctx, "ALL:@STRENGTH") == 0) { + aflog(0, "Setting cipher list failed... exiting"); + exit(1); + } + if ((temp2 = create_apf_dir())) { + aflog(1, "Warning: Creating ~/.apf directory failed (%d)", temp2); + } + if ((temp2 = generate_rsa_key(&keys))) { + aflog(1, "Warning: Something bad happened when generating rsa keys... (%d)", temp2); + } + if (SSL_CTX_use_RSAPrivateKey_file(ctx, keys, SSL_FILETYPE_PEM) != 1) { + aflog(0, "Setting rsa key failed (%s)... exiting", keys); + exit(1); + } + + if (remote) { + temp2 = -1; + if (despor) { + if (ip_listen(&n, desnam, despor, &addrlen, ipfam)) { +#ifdef AF_INET6 + aflog(0, "tcp_listen_%s error for %s, %s", + (ipfam & 0x02)?"ipv4":(ipfam & 0x04)?"ipv6":"unspec", desnam, despor); +#else + aflog(0, "tcp_listen error for %s, %s", desnam, despor); +#endif + exit(1); + } + if (!verbose) + daemon(0, 0); + cliaddr = malloc(addrlen); + temp2 = accept(n, cliaddr, &addrlen); + } + } + + if (ip_connect(&(master.commfd), name, manage, ipfam)) { +#ifdef AF_INET6 + aflog(0, "tcp_connect_%s error for %s, %s", + (ipfam & 0x02)?"ipv4":(ipfam & 0x04)?"ipv6":"unspec", name, manage); +#else + aflog(0, "tcp_connect error for %s, %s", name, manage); +#endif + exit(1); + } + master.ssl = SSL_new(ctx); + if (SSL_set_fd(master.ssl, master.commfd) != 1) { + aflog(0, "Problem with initializing ssl... exiting"); + exit(1); + } + + aflog(1, "Trying SSL_connect"); + if ((n = SSL_connect(master.ssl)) == 1) { + aflog(1, "SSL_connect successfull"); + } + else { + aflog(0, "SSL_connect has failed (%d)... exiting", n); + exit(1); + } + + buff[0] = AF_S_LOGIN; + buff[1] = pass[0]; + buff[2] = pass[1]; + buff[3] = pass[2]; + buff[4] = pass[3]; + + if (remote) { + return client_admin(type, master, buff, temp2, id); + } + + send_message(type, master, buff, 5); + buff[0] = 0; + get_message(type, master, buff, -5); + + if ( buff[0] == 0 ) { + aflog(0, "Wrong password"); + exit(1); + } + if ( buff[0] == AF_S_CANT_OPEN ) { + aflog(0, "Server is full"); + exit(1); + } + if ( buff[0] != AF_S_LOGIN ) { + aflog(0, "Incompatible server type or server full"); + exit(1); + } + + type = buff[3]; + usernum = buff[1]; + usernum = usernum << 8; + usernum += buff[2]; + } /* !reverse */ + else { + usernum = 1; + if (ip_connect(&(master.commfd), name, manage, ipfam)) { +#ifdef AF_INET6 + aflog(0, "tcp_connect_%s error for %s, %s", + (ipfam & 0x02)?"ipv4":(ipfam & 0x04)?"ipv6":"unspec", name, manage); +#else + aflog(0, "tcp_connect error for %s, %s", name, manage); +#endif + exit(1); + } + master.ssl = NULL; + } + + contable = calloc( usernum, sizeof(ConnectuserT)); + if (contable == NULL) { + aflog(0, "Calloc error - unable to succesfully communicate with server"); + exit(1); + } + + len = 4; + if (getsockopt(master.commfd, SOL_SOCKET, SO_SNDBUF, &buflength, &len) == -1) { + aflog(0, "Can't get socket send buffer size - exiting..."); + exit(1); + } + + if (!verbose) + daemon(0, 0); + + FD_ZERO(&allset); + FD_ZERO(&wset); + + FD_SET(master.commfd, &allset); + maxfdp1 = master.commfd + 1; + + /* UDP REVERSE MODE */ + + if (reverse) { + ipfam = 0; +#ifdef AF_INET6 + if (TYPE_IS_IPV4(type)) { + ipfam |= 0x02; + } + else if (TYPE_IS_IPV6(type)) { + ipfam |= 0x04; + } +#endif + if (ip_listen(&(contable[0].connfd), desnam, despor, &addrlen, ipfam)) { +#ifdef AF_INET6 + aflog(0, "udp_listen_%s error for %s, %s", + (ipfam & 0x02)?"ipv4":(ipfam & 0x04)?"ipv6":"unspec", desnam, despor); +#else + aflog(0, "udp_listen error for %s, %s", desnam, despor); +#endif + 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 HAVE_LINUX_SOCKIOS_H +# 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); +# 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); +# endif + } + else { +#endif + if (n > 0) { +#ifdef HAVE_LINUX_SOCKIOS_H + aflog(2, "Sending %d bytes to service (w:%d/%d) (FROM:%s)", n, +# ifdef SIOCOUTQ + notsent +# else + buflength - notsent +# endif + , buflength, sock_ntop(cliaddr, len, NULL, NULL, 0)); +#else + aflog(2, "Sending %d bytes to service (FROM:%s)", n, sock_ntop(cliaddr, len, NULL, NULL, 0)); +#endif + 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); + } +#ifdef HAVE_LINUX_SOCKIOS_H + } +#endif + } /* - 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... */ + aflog(0, "premature quit of the server -> exiting..."); + exit(1); + } + aflog(2, "Sending %d bytes to user (TO:%s)", n, sock_ntop(cliaddr, addrlen, NULL, NULL, 0)); + 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(2, "CIPHER: %s VER: %s", SSL_get_cipher_name(master.ssl), SSL_get_cipher_version(master.ssl)); +#ifdef HAVE_LIBDL + if (ismloaded(&module)) { + aflog(1, "LOADED MODULE: %s INFO: %s", module.name, module.info()); + } + if (ismloaded(&secmodule)) { + aflog(1, "LOADED MODULE (ser): %s INFO: %s", secmodule.name, secmodule.info()); + } +#endif + if (id != NULL) { + buff[0] = AF_S_LOGIN; + buff[1] = buff[2] = 0; + n = strlen(id); + memcpy(&buff[5], id, n); + buff[3] = n >> 8; /* high bits of message length */ + buff[4] = n; /* low bits of message length */ + send_message(type, master, buff, n+5); + aflog(1, "ID SENT: %s", id); + } + + 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)||(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 HAVE_LINUX_SOCKIOS_H +# 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 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 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 */ + } + } +#endif + if (n) { +#ifdef HAVE_LIBDL + if (ismloaded(&secmodule)) { + switch ((temp2 = secmodule.filter(contable[i].namebuf, &buff[5], &n))) { + case 1: case 4: { + aflog(3, " user[%d] (by ser): PACKET IGNORED BY MODULE", i); + if (temp2 == 4) { + aflog(1, "RELEASED MODULE (ser): %s INFO: %s", secmodule.name, secmodule.info()); + releasemodule(&secmodule); + } + continue; + break; + } + case 2: case 5: { + aflog(2, " user[%d] (by ser): DROPPED BY MODULE", 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); + if (temp2 == 5) { + aflog(1, "RELEASED MODULE (ser): %s INFO: %s", secmodule.name, secmodule.info()); + releasemodule(&secmodule); + } + continue; + break; + } + case 3: { + aflog(1, "RELEASED MODULE (ser): %s INFO: %s", secmodule.name, secmodule.info()); + releasemodule(&secmodule); + break; + } + } + } +#endif + 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 */ +#ifdef HAVE_LINUX_SOCKIOS_H + aflog(2, " user[%d]: TO msglen: %d [%d/%d]", i, n, +# ifdef SIOCOUTQ + notsent +# else + buflength - notsent +# endif + , buflength); +#else + aflog(2, " user[%d]: TO msglen: %d", i, n); +#endif + 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)) { + get_ssl_error(&master, "FE", n); + 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 : { + aflog(4, " user[%d]: AF_S_CONCLOSED", numofcon); + if ((numofcon>=0) && (numofcon<=usernum)) { + usercon--; + if (contable[numofcon].state == S_STATE_CLOSING) { + contable[numofcon].state = S_STATE_CLEAR; + aflog(1, " user[%d]: CLOSED", numofcon); + } + else if ((contable[numofcon].state==S_STATE_OPEN) || (contable[numofcon].state==S_STATE_STOPPED)){ + aflog(1, " 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 : { + aflog(4, " user[%d]: AF_S_CONOPEN", numofcon); + 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); +#ifdef HAVE_LIBDL + if (ismloaded(&module) && 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; + } +#endif + if (udp) { + ipfam = 0; + } + else { + ipfam = 0x01; + } +#ifdef AF_INET6 + if (TYPE_IS_IPV4(type)) { + ipfam |= 0x02; + } + else if (TYPE_IS_IPV6(type)) { + ipfam |= 0x04; + } +#endif + 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(4, " user[%d]: AF_S_MESSAGE", numofcon); + 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) { +#ifdef HAVE_LIBDL + if (ismloaded(&module)) { + switch ((temp2 = module.filter(contable[numofcon].namebuf, buff, &n))) { + case 1: case 4:{ + aflog(3, " user[%d]: PACKET IGNORED BY MODULE", numofcon); + if (temp2 == 4) { + aflog(1, "RELEASED MODULE: %s INFO: %s", module.name, module.info()); + releasemodule(&module); + } + continue; + break; + } + case 2: case 5:{ + 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); + if (temp2 == 5) { + aflog(1, "RELEASED MODULE: %s INFO: %s", module.name, module.info()); + releasemodule(&module); + } + continue; + break; + } + case 3: { + aflog(1, "RELEASED MODULE: %s INFO: %s", module.name, module.info()); + releasemodule(&module); + break; + } + } + } +#endif + 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; + 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); + } + } + 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: { + aflog(4, " user[%d]: AF_S_DONT_SEND", numofcon); + FD_CLR(contable[numofcon].connfd, &allset); + break; + } + case AF_S_CAN_SEND: { + aflog(4, " user[%d]: AF_S_CAN_SEND", numofcon); + 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\n", info); + printf(" Basic options:\n\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(" -h, --help - prints this help\n\n"); + printf(" Authorization:\n\n"); + printf(" -i, --id - sends the id string to afserver\n"); + printf(" --pass - set the password used for client identification\n"); + printf(" (default: no password)\n\n"); + printf(" Configuration:\n\n"); + printf(" -k, --keyfile - the name of the file with RSA key (default: client.rsa)\n"); + printf(" -D, --dateformat - format of the date printed in logs (see 'man strftime'\n"); + printf(" for details) (default: %%d.%%m.%%Y %%H:%%M:%%S)\n\n"); + printf(" Modes:\n\n"); + printf(" -u, --udpmode - udp mode - client will use udp protocol to\n"); + printf(" communicate with the hostname:portnum (-p)\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(" -r, --remoteadmin - remote administration mode. (using '-p #port' will\n"); + printf(" force afclient to use port rather then stdin-stdout)\n\n"); + printf(" Logging:\n\n"); + printf(" -O, --heavylog - logging everything to a logfile\n"); + printf(" -o, --lightlog - logging some data to a logfile\n"); + printf(" -S, --heavysocklog - logging everything to a localport\n"); + printf(" -s, --lightsocklog - logging some data to a localport\n"); + printf(" -v, --verbose - to be verbose - program won't enter the daemon mode\n"); + printf(" (use several times for greater effect)\n\n"); +#ifdef AF_INET6 + printf(" IP family:\n\n"); + printf(" -4, --ipv4 - use ipv4 only\n"); + printf(" -6, --ipv6 - use ipv6 only\n\n"); +#endif +#ifdef HAVE_LIBDL + printf(" Modules:\n\n"); + printf(" -l, --load - load a module for user's packets filtering\n"); + printf(" -L, --Load - load a module for service's packets filtering\n\n"); +#endif + + exit(0); +} + +static void +sig_int(int signo) +{ + aflog(1, "CLIENT CLOSED cg: %ld bytes", getcg()); + exit(0); +} + -- cgit v1.1