diff options
Diffstat (limited to 'src')
40 files changed, 6205 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..a6ccd11 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,7 @@ +bin_PROGRAMS = afserver afclient +afserver_SOURCES = afserver.c network.c file.c stats.c buflist.c remoteadmin.c \ + server_check.c server_set.c server_eval.c server_find.c server_remove.c \ + make_ssl_handshake.c first_run.c inet_ntop.c realmnames.c clientnames.c usernames.c +afclient_LDFLAGS = ${USE_RDYNAMIC} ${LINKED_LDLIB} +afclient_SOURCES = afclient.c network.c stats.c buflist.c modules.c remoteadmin.c \ + make_ssl_handshake.c first_run.c inet_ntop.c realmnames.c clientnames.c usernames.c diff --git a/src/activefor.h b/src/activefor.h new file mode 100644 index 0000000..8d07c8b --- /dev/null +++ b/src/activefor.h @@ -0,0 +1,162 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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_ACTIVEFOR_H +#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 AF_S_WRONG 13 +#define AF_S_ADMIN_LOGIN 14 +#define AF_S_ADMIN_CMD 15 + +#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.6" + +#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_SET_ZERO(type) (type=0) +#define TYPE_IS_SET(type) (type&1) +#define TYPE_IS_UDP(type) TYPE_IS_SET(type)&&(type&2) +#define TYPE_IS_TCP(type) TYPE_IS_SET(type)&&(!(type&2)) +#define TYPE_SET_UDP(type) (type|=TYPE_UDP) +#define TYPE_SET_TCP(type) (type|=TYPE_TCP) +#define TYPE_SET_SSL(type) (type|=TYPE_SSL) +#define TYPE_UNSET_SSL(type) (type&=(~TYPE_SSL)) +#define TYPE_IS_SSL(type) (type&TYPE_SSL) +#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* lisportnum; + char* manportnum; + int listenfd; + int managefd; +} UsrCliT; + +typedef struct { + char state; + int connfd; + int whatcli; + int userid; + time_t connecttime; + char namebuf[128]; + char portbuf[7]; + blnodeT* head; +} ConnectuserT; + +typedef struct { + char ready; + clifd cliconn; + struct timeval tv; + int* users; + int usercon; + int usernum; + int listenfd; + int whatusrcli; + int clientnum; + time_t connecttime; + char* clientid; + char namebuf[128]; + char portbuf[7]; +} ConnectclientT; + +typedef struct { + char* hostname; + char* users; + char* clients; + char* raclients; + char* usrpcli; + char* clim; + char* timeout; + char* realmname; + unsigned char pass[4]; + int usercon; + int usernum; + int clicon; + int clinum; + int raclicon; + int raclinum; + int upcnum; + int tmout; + int climode; + int usrclinum; + int clientcounter; + int usercounter; + char type; + char dnslookups; + char baseport; + socklen_t addrlen; + struct sockaddr* cliaddr; + ConnectuserT* contable; + ConnectclientT* clitable; + ConnectclientT* raclitable; + UsrCliT* usrclitable; +} RealmT; + +typedef struct { + char* certif; + char* keys; + char* logfnam; + char* logsport; + char* dateformat; + char logging; + char socklogging; + int size; + time_t starttime; + RealmT* realmtable; +} ConfigurationT; + +#endif + 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 <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 <config.h> + +#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); +} + diff --git a/src/afclient.h b/src/afclient.h new file mode 100644 index 0000000..108751b --- /dev/null +++ b/src/afclient.h @@ -0,0 +1,50 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 "activefor.h" +#include "network.h" +#include "stats.h" +#include "modules.h" +#include "remoteadmin.h" +#include "make_ssl_handshake.h" +#include "first_run.h" + +#include <openssl/rsa.h> +#include <openssl/ssl.h> +#include <openssl/err.h> +#include <sys/time.h> +#include <sys/ioctl.h> +#ifdef HAVE_LINUX_SOCKIOS_H +#include <linux/sockios.h> +#endif +#include <signal.h> +#include <string.h> +#include <fcntl.h> + +#include <getopt.h> + +#ifndef _JS_AFCLIENT_H +#define _JS_AFCLIENT_H + +static void usage(char* info); +static void sig_int(int); + +#endif + diff --git a/src/afserver.c b/src/afserver.c new file mode 100644 index 0000000..d1e11b7 --- /dev/null +++ b/src/afserver.c @@ -0,0 +1,1720 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 <config.h> + +#include "afserver.h" + +static struct option long_options[] = { + {"help", 0, 0, 'h'}, + {"hostname", 1, 0, 'n'}, + {"listenport", 1, 0, 'l'}, + {"manageport", 1, 0, 'm'}, + {"timeout", 1, 0, 't'}, + {"verbose", 0, 0, 'v'}, + {"users", 1, 0, 'u'}, + {"clients", 1, 0, 'C'}, + {"realm", 1, 0, 'r'}, + {"raclients", 1, 0, 'R'}, + {"usrpcli", 1, 0, 'U'}, + {"climode", 1, 0, 'M'}, + {"cerfile", 1, 0, 'c'}, + {"keyfile", 1, 0, 'k'}, + {"cfgfile", 1, 0, 'f'}, + {"proto", 1, 0, 'p'}, + {"lightlog", 1, 0, 'o'}, + {"heavylog", 1, 0, 'O'}, + {"heavysocklog", 1, 0, 'S'}, + {"lightsocklog", 1, 0, 's'}, + {"nossl", 0, 0, 301}, + {"nozlib", 0, 0, 302}, + {"pass", 1, 0, 303}, +#ifdef AF_INET6 + {"ipv4", 0, 0, '4'}, + {"ipv6", 0, 0, '6'}, +#endif + {"baseport", 0, 0, 'b'}, + {"dnslookups", 0, 0, 311}, + {"dateformat", 1, 0, 'D'}, + {0, 0, 0, 0} +}; + +static ConfigurationT config; + +int +main(int argc, char **argv) +{ + int i, j=0, k, l, n, flags, sent = 0; + socklen_t len; + unsigned char buff[9000]; + int maxfdp1; + fd_set rset, allset, wset, tmpset; + int manconnecting, numofcon, length; + char* name = NULL; + char** listen = NULL; + int listencount = 0; + char** manage = NULL; + int managecount = 0; + char* amount = NULL; + char* clients = NULL; + char* raclients = NULL; + char* usrpcli = NULL; + char* clim = NULL; + char* filenam = NULL; + char* type = NULL; + char* timeout = NULL; + char* realmname = NULL; + unsigned char pass[4] = {1, 2, 3, 4}; + char verbose = 0; + char mode = 0; + char ipfam = 0; + char baseport = 0; + char dnslookups = 0; + RealmT* pointer = NULL; + struct sigaction act; + + char* certif = NULL; + char* keys = NULL; + char* logfnam = NULL; + char* logsport = NULL; + char* dateformat = NULL; + char logging = 0; + char socklogging = 0; + + SSL_METHOD* method; + SSL_CTX* ctx; + SSL* tmp_ssl; + + 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); + + config.certif = NULL; + config.keys = NULL; + config.size = 0; + config.realmtable = NULL; + config.logging = 0; + config.socklogging = 0; + config.logfnam = NULL; + config.logsport = NULL; + config.dateformat = NULL; + +#ifdef AF_INET6 + while ((n = getopt_long(argc, argv, "hn:l:m:vu:c:k:f:p:o:O:46t:C:U:M:bD:S:s:R:r:", long_options, 0)) != -1) { +#else + while ((n = getopt_long(argc, argv, "hn:l:m:vu:c:k:f:p:o:O:t:C:U:M:bD:S:s:R:r:", long_options, 0)) != -1) { +#endif + switch (n) { + case 'h': { + usage(AF_VER("Active port forwarder (server)")); + break; + } + case 'n': { + name = optarg; + break; + } + case 'l': { + ++listencount; + listen = realloc(listen, sizeof(char*)); + listen[listencount-1] = optarg; + break; + } + case 'm': { + ++managecount; + manage = realloc(manage, sizeof(char*)); + manage[managecount-1] = optarg; + break; + } + case 't': { + timeout = optarg; + break; + } + case 'v': { + ++verbose; + break; + } + case 'u': { + amount = optarg; + break; + } + case 'C': { + clients = optarg; + break; + } + case 'r': { + realmname = optarg; + break; + } + case 'R': { + raclients = optarg; + break; + } + case 'U': { + usrpcli = optarg; + break; + } + case 'M': { + clim = optarg; + break; + } + case 'c': { + certif = optarg; + break; + } + case 'k': { + keys = optarg; + break; + } + case 'p': { + type = optarg; + break; + } + case 'f': { + filenam = optarg; + break; + } + case 'O': { + logfnam = optarg; + logging = 3; + break; + } + case 'o': { + logfnam = optarg; + logging = 1; + break; + } + case 'S': { + logsport = optarg; + socklogging = 3; + break; + } + case 's': { + logsport = optarg; + socklogging = 1; + break; + } + case 301: { + TYPE_UNSET_SSL(mode); + break; + } + case 302: { + TYPE_UNSET_ZLIB(mode); + break; + } + case 303: { + n = strlen(optarg); + memset(pass, 0, 4); + for (i = 0; i < n; ++i) { + pass[i%4] += optarg[i]; + } + sent = 1; + 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 + case 'b': { + baseport = 1; + break; + } + case 311: { + dnslookups = 1; + break; + } + case 'D': { + dateformat = optarg; + break; + } + case '?': { + usage(""); + break; + } + } + } + + if (optind < argc) { + usage("Unrecognized non-option elements"); + } + + if (filenam != NULL) { + config = parsefile(filenam, &n); + if (n) { + printf("parsing failed! line:%d\n", n); + exit(1); + } + else { + if (certif == NULL) { + config.certif = "cacert.pem"; + } + else { + config.certif = certif; + } + if (keys == NULL) { + config.keys = "server.rsa"; + } + else { + config.keys = keys; + } + if (logfnam != NULL) { + config.logfnam = logfnam; + } + if (logsport != NULL) { + config.logsport = logsport; + } + if (dateformat != NULL) { + config.dateformat = dateformat; + } + if (logging != 0) { + config.logging = logging; + } + if (socklogging != 0) { + config.socklogging = socklogging; + } + + if ((k = loginit(verbose, config.logging, config.socklogging, + config.logfnam, config.logsport, config.dateformat))) { + switch (k) { + 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); + } + + aflog(1, "cfg file OK! (readed realms: %d)", config.size); + if (name != NULL) + aflog(1, "Warning: hostname=%s will be ignored", name); + if (listen != NULL) + aflog(1, "Warning: listenport will be ignored"); + if (manage != NULL) + aflog(1, "Warning: manageport will be ignored"); + if (realmname != NULL) + aflog(1, "Warning: realmname=%s will be ignored", realmname); + if (sent == 1) + aflog(1, "Warning: password from command line will be ignored"); + } + } + else { + config.certif = certif; + config.keys = keys; + config.logfnam = logfnam; + config.logsport = logsport; + config.dateformat = dateformat; + config.logging = logging; + config.socklogging = socklogging; + + if ((k = loginit(verbose, config.logging, config.socklogging, + config.logfnam, config.logsport, config.dateformat))) { + switch (k) { + 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); + } + + if (listen == NULL) { + listencount = 1; + listen = calloc(1, sizeof(char*)); + listen[0] = "50127"; + } + if (manage == NULL) { + managecount = 1; + manage = calloc(1, sizeof(char*)); + manage[0] = "50126"; + } + if (managecount != listencount) { + aflog(0, "Number of listen and manage options are not the same... exiting"); + exit(1); + } + if (config.certif == NULL) { + config.certif = "cacert.pem"; + } + if (config.keys == NULL) { + config.keys = "server.rsa"; + } + if (type == NULL) { + type = "tcp"; + } + config.size = 1; + config.realmtable = calloc(config.size, sizeof(RealmT)); + config.realmtable[0].hostname = name; + config.realmtable[0].usrclinum = managecount; + config.realmtable[0].usrclitable = calloc(managecount, sizeof(UsrCliT)); + for (i = 0; i < config.realmtable[0].usrclinum; ++i) { + config.realmtable[0].usrclitable[i].lisportnum = listen[i]; + config.realmtable[0].usrclitable[i].manportnum = manage[i]; + } + config.realmtable[0].users = amount; + config.realmtable[0].clients = clients; + config.realmtable[0].raclients = raclients; + config.realmtable[0].timeout = timeout; + config.realmtable[0].usrpcli = usrpcli; + config.realmtable[0].clim = clim; + config.realmtable[0].baseport = baseport; + config.realmtable[0].dnslookups = dnslookups; + config.realmtable[0].realmname = realmname; + memcpy(config.realmtable[0].pass, pass, 4); + if (strcmp(type, "tcp") == 0) { + TYPE_SET_TCP(config.realmtable[0].type); + } + else if (strcmp(type, "udp") == 0) { + TYPE_SET_UDP(config.realmtable[0].type); + } + else { + TYPE_SET_ZERO(config.realmtable[0].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(config.realmtable[0].type); + } + else if (ipfam == 6) { + TYPE_SET_IPV6(config.realmtable[0].type); + } +#endif + config.realmtable[0].type |= mode; + } + + maxfdp1 = manconnecting = 0; + + SSL_library_init(); + method = SSLv3_server_method(); + ctx = SSL_CTX_new(method); + if (SSL_CTX_set_cipher_list(ctx, "ALL:@STRENGTH") == 0) { + aflog(0, "Setting ciphers list failed... exiting"); + exit(1); + } + if ((flags = create_apf_dir())) { + aflog(1, "Warning: Creating ~/.apf directory failed (%d)", flags); + } + if ((flags = generate_rsa_key(&config.keys))) { + aflog(1, "Warning: Something bad happened when generating rsa keys... (%d)", flags); + } + if (SSL_CTX_use_RSAPrivateKey_file(ctx, config.keys, SSL_FILETYPE_PEM) != 1) { + aflog(0, "Setting rsa key failed (%s)... exiting", config.keys); + exit(1); + } + if ((flags = generate_certificate(&config.certif, config.keys))) { + aflog(1, "Warning: Something bad happened when generating certificate... (%d)", flags); + } + if (SSL_CTX_use_certificate_file(ctx, config.certif, SSL_FILETYPE_PEM) != 1) { + aflog(0, "Setting certificate failed (%s)... exiting", config.certif); + exit(1); + } + + if (config.size == 0) { + aflog(0, "Working without sense is really without sense..."); + exit(1); + } + + FD_ZERO(&allset); + FD_ZERO(&wset); + + for (i = 0; i < config.size; ++i) { + if (config.realmtable[i].usrclinum == 0) { + aflog(0, "You have to specify at least one listen port and one manage port in each realm"); + exit(1); + } + for (j = 0; j < config.realmtable[i].usrclinum; ++j) { + if ((config.realmtable[i].usrclitable[j].lisportnum == NULL) || + (config.realmtable[i].usrclitable[j].manportnum == NULL)) { + aflog(0, "Missing some of the variables...\nRealm: %d\nlistenport[%d]: %s\nmanageport[%d]: %s", + i, j, config.realmtable[i].usrclitable[j].lisportnum, + j, config.realmtable[i].usrclitable[j].manportnum); + exit(1); + } + } + /* checking type of the realm */ + if (!TYPE_IS_SET(config.realmtable[i].type)) { + if (type != NULL) { + if (strcmp(type, "tcp") == 0) { + TYPE_SET_TCP(config.realmtable[i].type); + } + else if (strcmp(type, "udp") == 0) { + TYPE_SET_UDP(config.realmtable[i].type); + } + else { + TYPE_SET_TCP(config.realmtable[i].type); + } + } + else { + TYPE_SET_TCP(config.realmtable[i].type); + } + } +#ifdef AF_INET6 + /* using user's value for ipfam*/ + if (TYPE_IS_UNSPEC(config.realmtable[i].type)) { + if (ipfam == -1) { + aflog(0, "Conflicting types of ip protocol family... exiting"); + exit(1); + } + else if (ipfam == 4) { + TYPE_SET_IPV4(config.realmtable[i].type); + } + else if (ipfam == 6) { + TYPE_SET_IPV6(config.realmtable[i].type); + } + } +#endif + /* using user's values for zlib and ssl mode*/ + if (!TYPE_IS_SSL(mode)) { + TYPE_UNSET_SSL(config.realmtable[i].type); + } + if (!TYPE_IS_ZLIB(mode)) { + TYPE_UNSET_ZLIB(config.realmtable[i].type); + } + /* using user's baseport value*/ + if (config.realmtable[i].baseport == 0) { + config.realmtable[i].baseport = baseport; + } + /* using user's dnslookups value*/ + if (config.realmtable[i].dnslookups == 0) { + config.realmtable[i].dnslookups = dnslookups; + } + /* checking users amount */ + set_value(&(config.realmtable[i].users), amount, "5"); + check_value(&(config.realmtable[i].usernum), config.realmtable[i].users, "Invalid users amount"); + /* checking clients amount */ + set_value(&(config.realmtable[i].clients), clients, "1"); + check_value(&(config.realmtable[i].clinum), config.realmtable[i].clients, "Invalid clients amount"); + /* checking raclients amount */ + set_value(&(config.realmtable[i].raclients), raclients, "1"); + check_value(&(config.realmtable[i].raclinum), config.realmtable[i].raclients, "Invalid raclients amount"); + /* checking usrpcli value */ + set_value(&(config.realmtable[i].usrpcli), usrpcli, config.realmtable[i].users); + check_value(&(config.realmtable[i].upcnum), config.realmtable[i].usrpcli, "Invalid usrpcli value"); + /* checking timeout value */ + set_value(&(config.realmtable[i].timeout), timeout, "5"); + check_value(&(config.realmtable[i].tmout), config.realmtable[i].timeout, "Invalid timeout value"); + /* checking climode value */ + set_value(&(config.realmtable[i].clim), clim, "1"); + check_value(&(config.realmtable[i].climode), config.realmtable[i].clim, "Invalid climode value"); + /* allocating memory*/ + config.realmtable[i].contable = calloc( config.realmtable[i].usernum, sizeof(ConnectuserT)); + if (config.realmtable[i].contable == NULL) { + aflog(0, "Calloc error - try define smaller amount of users"); + exit(1); + } + config.realmtable[i].clitable = calloc( config.realmtable[i].clinum, sizeof(ConnectclientT)); + if (config.realmtable[i].clitable == NULL) { + aflog(0, "Calloc error - try define smaller amount of clients"); + exit(1); + } + config.realmtable[i].raclitable = calloc( config.realmtable[i].raclinum, sizeof(ConnectclientT)); + if (config.realmtable[i].raclitable == NULL) { + aflog(0, "Calloc error - try define smaller amount of raclients"); + exit(1); + } + ipfam = 0x01; +#ifdef AF_INET6 + if (TYPE_IS_IPV4(config.realmtable[i].type)) { + ipfam |= 0x02; + } + else if (TYPE_IS_IPV6(config.realmtable[i].type)) { + ipfam |= 0x04; + } +#endif + if (config.realmtable[i].baseport == 0) { + for (j = 0; j < config.realmtable[i].usrclinum; ++j) { + if (ip_listen(&(config.realmtable[i].usrclitable[j].listenfd), config.realmtable[i].hostname, + config.realmtable[i].usrclitable[j].lisportnum, (&(config.realmtable[i].addrlen)), ipfam)) { + aflog(0, +#ifdef AF_INET6 + "tcp_listen_%s error for %s, %s", + (ipfam & 0x02)?"ipv4":(ipfam & 0x04)?"ipv6":"unspec", +#else + "tcp_listen error for %s, %s", +#endif + config.realmtable[i].hostname, config.realmtable[i].usrclitable[j].lisportnum); + exit(1); + } + } + } + for (j = 0; j < config.realmtable[i].usrclinum; ++j) { + if (ip_listen(&(config.realmtable[i].usrclitable[j].managefd), config.realmtable[i].hostname, + config.realmtable[i].usrclitable[j].manportnum, (&(config.realmtable[i].addrlen)), ipfam)) { + aflog(0, +#ifdef AF_INET6 + "tcp_listen_%s error for %s, %s", + (ipfam & 0x02)?"ipv4":(ipfam & 0x04)?"ipv6":"unspec", +#else + "tcp_listen error for %s, %s", +#endif + config.realmtable[i].hostname, config.realmtable[i].usrclitable[j].manportnum); + exit(1); + } + } + config.realmtable[i].cliaddr = malloc(config.realmtable[i].addrlen); + + for (j=0; j<config.realmtable[i].clinum; ++j) { + config.realmtable[i].clitable[j].cliconn.ssl = SSL_new(ctx); + if (config.realmtable[i].clitable[j].cliconn.ssl == NULL) { + aflog(0, "Creating of ssl object failed... exiting"); + exit(1); + } + } + + for (j=0; j<config.realmtable[i].raclinum; ++j) { + config.realmtable[i].raclitable[j].cliconn.ssl = SSL_new(ctx); + if (config.realmtable[i].raclitable[j].cliconn.ssl == NULL) { + aflog(0, "Creating of ssl object failed... exiting"); + exit(1); + } + } + + for (j = 0; j < config.realmtable[i].usrclinum; ++j) { + FD_SET(config.realmtable[i].usrclitable[j].managefd, &allset); + maxfdp1 = (maxfdp1 > (config.realmtable[i].usrclitable[j].managefd+1)) ? + maxfdp1 : (config.realmtable[i].usrclitable[j].managefd+1); + } + if (config.realmtable[i].baseport == 0) { + for (j = 0; j < config.realmtable[i].usrclinum; ++j) { + FD_SET(config.realmtable[i].usrclitable[j].listenfd, &allset); + maxfdp1 = (maxfdp1 > (config.realmtable[i].usrclitable[j].listenfd+1)) ? + maxfdp1 : (config.realmtable[i].usrclitable[j].listenfd+1); + } + } + config.realmtable[i].usercon = 0; + config.realmtable[i].clicon = 0; + config.realmtable[i].raclicon = 0; + for (j=0; j<config.realmtable[i].clinum; ++j) { + config.realmtable[i].clitable[j].tv.tv_sec = config.realmtable[i].tmout; + config.realmtable[i].clitable[j].usernum = config.realmtable[i].upcnum; + config.realmtable[i].clitable[j].users = malloc( config.realmtable[i].clitable[j].usernum * sizeof(int)); + if (config.realmtable[i].clitable[j].users == NULL) { + aflog(0, "Calloc error - try define smaller amount of usrpcli (or users)"); + exit(1); + } + for (k=0; k<config.realmtable[i].clitable[j].usernum; ++k) { + config.realmtable[i].clitable[j].users[k] = -1; + } + } + for (j=0; j<config.realmtable[i].raclinum; ++j) { + config.realmtable[i].raclitable[j].tv.tv_sec = config.realmtable[i].tmout; + } + } + + if (!verbose) + daemon(0, 0); + + aflog(1, "SERVER STARTED realms: %d", config.size); + time(&config.starttime); + + for ( ; ; ) { + rset = allset; + tmpset = wset; + aflog(3, ">select, maxfdp1: %d", maxfdp1); + if (manconnecting) { + /* find out, in what realm client is trying to connect */ + l = -1; + for (k = 0; k < config.size; ++k) { + for (j=0; j < config.realmtable[k].clinum; ++j) { + if ((config.realmtable[k].clitable[j].ready == 1) || (config.realmtable[k].clitable[j].ready == 2)) { + i = k; + k = config.size; + l = 0; + break; /* so i points to first good realm and j to good client */ + } + } + if (l == -1) { + for (j=0; j < config.realmtable[k].raclinum; ++j) { + if ((config.realmtable[k].raclitable[j].ready==1) || (config.realmtable[k].raclitable[j].ready==2)) { + i = k; + k = config.size; + l = 1; + break; /* so i points to first good realm and j to good client */ + } + } + } + } + if (!l) { + if (select(maxfdp1, &rset, &tmpset, NULL, (&(config.realmtable[i].clitable[j].tv))) == 0) { + close (config.realmtable[i].clitable[j].cliconn.commfd); + FD_CLR(config.realmtable[i].clitable[j].cliconn.commfd, &allset); + SSL_clear(config.realmtable[i].clitable[j].cliconn.ssl); + config.realmtable[i].clitable[j].ready = 0; + manconnecting--; + config.realmtable[i].clicon--; + aflog(1, " realm[%s]: Client[%s]: SSL_accept failed (timeout)", + get_realmname(&config, i), get_clientname(pointer, j)); + } + } + else { + if (select(maxfdp1, &rset, &tmpset, NULL, (&(config.realmtable[i].raclitable[j].tv))) == 0) { + close (config.realmtable[i].raclitable[j].cliconn.commfd); + FD_CLR(config.realmtable[i].raclitable[j].cliconn.commfd, &allset); + SSL_clear(config.realmtable[i].raclitable[j].cliconn.ssl); + config.realmtable[i].raclitable[j].ready = 0; + manconnecting--; + config.realmtable[i].clicon--; + aflog(1, " realm[%s]: Client[%s] (ra): SSL_accept failed (timeout)", + get_realmname(&config, i), get_raclientname(pointer, j)); + } + } + } + else { + select(maxfdp1, &rset, &tmpset, NULL, NULL); + } + 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) || (pointer->contable[i].state == S_STATE_STOPPED)) + if (FD_ISSET(pointer->contable[i].connfd, &rset)) { + k = eval_usernum(&(pointer->clitable[pointer->contable[i].whatcli]), i); + aflog(3, " realm[%s]: Client[%s]: user[%d]: FD_ISSET", get_realmname(&config, j), + get_clientname(pointer, pointer->contable[i].whatcli), get_username(pointer, k)); + if (TYPE_IS_TCP(pointer->type)) { /* forwarding tcp packets */ + n = read(pointer->contable[i].connfd, &buff[5], 8091); + if (n == -1) { + if (errno == EAGAIN) { + continue; + } + aflog(3, " realm[%s]: Client[%s]: user[%d]: READ ERROR (%d)", get_realmname(&config, j), + get_clientname(pointer, pointer->contable[i].whatcli), get_username(pointer, k), errno); + n = 0; + } + if (n) { + aflog(2, " realm[%s]: Client[%s]: FROM user[%d]: MESSAGE length=%d", get_realmname(&config, j), + get_clientname(pointer, pointer->contable[i].whatcli), get_username(pointer, k), n); + if ((buff[5] == AF_S_MESSAGE) && (buff[6] == AF_S_LOGIN) && (buff[7] == AF_S_MESSAGE)) { + aflog(2, " WARNING: got packet similiar to udp"); + } + buff[0] = AF_S_MESSAGE; /* sending message */ + buff[1] = k >> 8; /* high bits of user number */ + buff[2] = k; /* low bits of user number */ + buff[3] = n >> 8; /* high bits of message length */ + buff[4] = n; /* low bits of message length */ + send_message(pointer->type, pointer->clitable[pointer->contable[i].whatcli].cliconn, buff, n+5); + } + else { + aflog(1, " realm[%s]: Client[%s]: user[%d]: CLOSED", get_realmname(&config, j), + get_clientname(pointer, pointer->contable[i].whatcli), get_username(pointer, k)); + 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] = k >> 8; /* high bits of user number */ + buff[2] = k; /* low bits of user number */ + send_message(pointer->type, pointer->clitable[pointer->contable[i].whatcli].cliconn, buff, 5); + } + } + else { /* when forwarding udp packets */ + n = readn(pointer->contable[i].connfd, buff, 5 ); + if (n != 5) { + n = 0; + } + if (n) { + if ((buff[0] == AF_S_MESSAGE) && (buff[1] == AF_S_LOGIN) && (buff[2] == AF_S_MESSAGE)) { + length = buff[3]; + length = length << 8; + length += buff[4]; /* this is length of message */ + if ((n = readn(pointer->contable[i].connfd, &buff[5], length)) != 0) { + aflog(2, " realm[%s]: Client[%s]: FROM user[%d]: MESSAGE length=%d", + get_realmname(&config, j), get_clientname(pointer, pointer->contable[i].whatcli), + get_username(pointer, k), n); + buff[1] = k >> 8; /* high bits of user number */ + buff[2] = k; /* low bits of user number */ + send_message(pointer->type, pointer->clitable[pointer->contable[i].whatcli].cliconn, + buff, n+5); + } + } + else { + n = 0; + } + } + + if (n == 0) { + aflog(1, " realm[%s]: Client[%s]: user[%d]: CLOSED (udp mode)", get_realmname(&config, j), + get_clientname(pointer, pointer->contable[i].whatcli), get_username(pointer, k)); + 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] = k >> 8; /* high bits of user number */ + buff[2] = k; /* low bits of user number */ + send_message(pointer->type, pointer->clitable[pointer->contable[i].whatcli].cliconn, buff, 5); + } + + } + } + } + /* ------------------------------------ */ + for (i = 0; i <pointer->usernum; ++i) { + if (pointer->contable[i].state == S_STATE_STOPPED) + if (FD_ISSET(pointer->contable[i].connfd, &tmpset)) { + k = eval_usernum(&(pointer->clitable[pointer->contable[i].whatcli]), i); + aflog(3, " realm[%s]: Client[%s]: user[%d]: FD_ISSET - WRITE", get_realmname(&config, j), + get_clientname(pointer, pointer->contable[i].whatcli), get_username(pointer, k)); + 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; + aflog(3, " realm[%s]: Client[%s]: user[%d]: (%d/%d)", get_realmname(&config, j), + get_clientname(pointer, pointer->contable[i].whatcli), get_username(pointer, k), sent, n); + } + else if ((sent == -1) && (errno == EAGAIN)) { + aflog(3, " realm[%s]: Client[%s]: user[%d]: EAGAIN", get_realmname(&config, j), + get_clientname(pointer, pointer->contable[i].whatcli), get_username(pointer, k)); + } + else if (sent == -1) { + aflog(1, " realm[%s]: Client[%s]: user[%d]: CLOSED", get_realmname(&config, j), + get_clientname(pointer, pointer->contable[i].whatcli), get_username(pointer, k)); + 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] = k >> 8; /* high bits of user number */ + buff[2] = k; /* low bits of user number */ + send_message(pointer->type, pointer->clitable[pointer->contable[i].whatcli].cliconn, buff, 5); + } + else { + aflog(3, " realm[%s]: Client[%s]: user[%d]: (%d/%d)", get_realmname(&config, j), + get_clientname(pointer, pointer->contable[i].whatcli), get_username(pointer, k), sent, n); + 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] = k >> 8; /* high bits of user number */ + buff[2] = k; /* low bits of user number */ + aflog(3, " realm[%s]: Client[%s]: TO user[%d]: BUFFERING MESSAGE ENDED", + get_realmname(&config, j), get_clientname(pointer, pointer->contable[i].whatcli), + get_username(pointer, k)); + send_message(pointer->type, pointer->clitable[pointer->contable[i].whatcli].cliconn, buff, 5); + } + } + } + } + /* ------------------------------------ */ + if (pointer->baseport == 0) { + for (l = 0; l < pointer->usrclinum; ++l) { + if (FD_ISSET(pointer->usrclitable[l].listenfd, &rset)) { + len = pointer->addrlen; + sent = accept(pointer->usrclitable[l].listenfd, pointer->cliaddr, &len); + flags = fcntl(sent, F_GETFL, 0); + fcntl(sent, F_SETFL, flags | O_NONBLOCK); + aflog(3, " realm[%s]: listenfd: FD_ISSET", get_realmname(&config, j)); + k = find_client(pointer, pointer->climode, l); + if (pointer->clitable[k].ready == 3) { + if (pointer->usercon == pointer->usernum) { + close(sent); + aflog(3, " realm[%s]: user limit EXCEEDED", get_realmname(&config, j)); + } + else if(pointer->clitable[k].usercon == pointer->clitable[k].usernum) { + close(sent); + aflog(3, " realm[%s]: Client[%s]: usrpcli limit EXCEEDED", + get_realmname(&config, j), get_clientname(pointer, k)); + } + else { + for (i = 0; i < pointer->usernum; ++i) { + if (pointer->contable[i].state == S_STATE_CLEAR) { + pointer->contable[i].userid = pointer->usercounter; + ++(pointer->usercounter); + aflog(1, " realm[%s]: Client[%s]: new user: CONNECTING from IP: %s", + get_realmname(&config, j), get_clientname(pointer, k), + sock_ntop(pointer->cliaddr, len, pointer->contable[i].namebuf, + pointer->contable[i].portbuf, pointer->dnslookups)); + pointer->contable[i].connfd = sent; + pointer->contable[i].state = S_STATE_OPENING; + pointer->contable[i].whatcli = k; + time(&pointer->contable[i].connecttime); + pointer->usercon++; + pointer->clitable[k].usercon++; + memcpy(&buff[5], pointer->contable[i].namebuf, 128); + memcpy(&buff[133], pointer->contable[i].portbuf, 7); + n = 135; + i = find_usernum(&(pointer->clitable[k]), i); + buff[0] = AF_S_CONOPEN; /* opening connection */ + 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 */ + send_message(pointer->type, pointer->clitable[k].cliconn, buff, n+5); + break; + } + } + } + } + else { + close(sent); + aflog(3, " realm[%s]: Client(%d) is NOT CONNECTED", + get_realmname(&config, j), k); + } + } + } + } + /* ------------------------------------ */ + if (pointer->baseport == 1) + for (k = 0; k < pointer->clinum; ++k) + if (pointer->clitable[k].ready == 3) /* Command file descriptor */ + if (FD_ISSET(pointer->clitable[k].listenfd, &rset)) { + len = pointer->addrlen; + sent = accept(pointer->clitable[k].listenfd, pointer->cliaddr, &len); + flags = fcntl(sent, F_GETFL, 0); + fcntl(sent, F_SETFL, flags | O_NONBLOCK); + aflog(3, " realm[%s]: Client[%s]: listenfd: FD_ISSET", + get_realmname(&config, j), get_clientname(pointer, k)); + if (pointer->clitable[k].ready == 3) { + if (pointer->usercon == pointer->usernum) { + close(sent); + aflog(3, " realm[%s]: user limit EXCEEDED", get_realmname(&config, j)); + } + else if(pointer->clitable[k].usercon == pointer->clitable[k].usernum) { + close(sent); + aflog(3, " realm[%s]: Client[%s]: usrpcli limit EXCEEDED", + get_realmname(&config, j), get_clientname(pointer, k)); + } + else { + for (i = 0; i < pointer->usernum; ++i) { + if (pointer->contable[i].state == S_STATE_CLEAR) { + pointer->contable[i].userid = pointer->usercounter; + ++(pointer->usercounter); + aflog(1, " realm[%s]: Client[%s]: new user: CONNECTING from IP: %s", + get_realmname(&config, j), get_clientname(pointer, k), + sock_ntop(pointer->cliaddr, len, pointer->contable[i].namebuf, pointer->contable[i].portbuf, pointer->dnslookups)); + pointer->contable[i].connfd = sent; + pointer->contable[i].state = S_STATE_OPENING; + pointer->contable[i].whatcli = k; + time(&pointer->contable[i].connecttime); + pointer->usercon++; + pointer->clitable[k].usercon++; + memcpy(&buff[5], pointer->contable[i].namebuf, 128); + memcpy(&buff[133], pointer->contable[i].portbuf, 7); + n = 135; + i = find_usernum(&(pointer->clitable[k]), i); + buff[0] = AF_S_CONOPEN; /* opening connection */ + 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 */ + send_message(pointer->type, pointer->clitable[k].cliconn, buff, n+5); + break; + } + } + } + } + } + /* ------------------------------------ */ + for (k = 0; k < pointer->clinum; ++k) + if ((pointer->clitable[k].ready != 0) && (FD_ISSET(pointer->clitable[k].cliconn.commfd, &rset))) { + if (pointer->clitable[k].ready == 1) { + make_ssl_initialize(&(pointer->clitable[k].cliconn)); + aflog(2, " realm[%s]: new Client[%s]: SSL_accept", + get_realmname(&config, j), get_clientname(pointer, k)); + switch (make_ssl_accept(&(pointer->clitable[k].cliconn))) { + case 2: { + close (pointer->clitable[k].cliconn.commfd); + FD_CLR(pointer->clitable[k].cliconn.commfd, &allset); + SSL_clear(pointer->clitable[k].cliconn.ssl); + pointer->clitable[k].ready = 0; + manconnecting--; + pointer->clicon--; + aflog(1, " realm[%s]: new Client[%s]: DENIED by SSL_accept", + get_realmname(&config, j), get_clientname(pointer, k)); + } + case 1: { + continue; + } + default: { + aflog(1, " realm[%s]: new Client[%s]: ACCEPTED by SSL_accept", + get_realmname(&config, j), get_clientname(pointer, k)); + pointer->clitable[k].ready = 2; + continue; + } + } + } + aflog(3, " realm[%s]: Client[%s]: commfd: FD_ISSET", + get_realmname(&config, j), get_clientname(pointer, k)); + if (pointer->clitable[k].ready == 2) { + n = get_message(pointer->type | TYPE_SSL | TYPE_ZLIB, pointer->clitable[k].cliconn, buff, -5); + } + else { + n = get_message(pointer->type, pointer->clitable[k].cliconn, buff, -5); + } + if (n == -1) { + if (errno == EAGAIN) { + aflog(4, " realm[%s]: Client[%s]: commfd: EAGAIN", + get_realmname(&config, j), get_clientname(pointer, k)); + continue; + } + else { + aflog(4, " realm[%s]: Client[%s]: commfd: ERROR: %d", + get_realmname(&config, j), get_clientname(pointer, k), errno); + n = 0; + } + } + else if (n != 5) { + if (n != 0) { + aflog(4, " realm[%s]: Client[%s]: header length = %d --> closing client", + get_realmname(&config, j), get_clientname(pointer, k), n); + } + n = 0; + } + if (n==0) { + remove_client(pointer, k, &allset, &wset, &manconnecting); + aflog(1, " realm[%s]: Client[%s]: commfd: CLOSED", + get_realmname(&config, j), get_clientname(pointer, k)); + continue; + } + + 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 */ + + if ((k == pointer->clinum) && (buff[0] != AF_S_LOGIN) && + (buff[0] != AF_S_ADMIN_LOGIN) && (buff[0] != AF_S_ADMIN_CMD)) { + buff[0] = AF_S_WRONG; + } + if (pointer->clitable[k].ready<2) { + aflog(1, " realm[%s]: Client[%s]: Impossible behaviour --> ignoring", + get_realmname(&config, j), get_clientname(pointer, k)); + continue; + } + if ((pointer->clitable[k].ready == 2) && (buff[0] != AF_S_LOGIN) && (buff[0] != AF_S_ADMIN_LOGIN)) { + buff[0] = AF_S_WRONG; + } + + switch (buff[0]) { + case AF_S_CONCLOSED : { + n = numofcon; + numofcon = eval_numofcon(pointer, k, numofcon); + if ((numofcon>=0) && (numofcon<(pointer->usernum)) && ((pointer->clitable[k].ready)==3)) { + pointer->usercon--; + pointer->clitable[k].usercon--; + pointer->clitable[k].users[n] = -1; + if (pointer->contable[numofcon].state == S_STATE_CLOSING) { + pointer->contable[numofcon].state = S_STATE_CLEAR; + aflog(3, " realm[%s]: user[%d]: CLOSE CONFIRMED", + get_realmname(&config, j), get_username(pointer, numofcon)); + } + else if ((pointer->contable[numofcon].state == S_STATE_OPEN) || + (pointer->contable[numofcon].state == S_STATE_STOPPED)) { + aflog(1, " realm[%s]: user[%d]: KICKED", + get_realmname(&config, j), get_username(pointer, 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 */ + send_message(pointer->type, pointer->clitable[k].cliconn, buff, 5); + } + } + else { + remove_client(pointer, k, &allset, &wset, &manconnecting); + } + break; + } + case AF_S_CONOPEN : { + numofcon = eval_numofcon(pointer, k, numofcon); + if ((numofcon>=0) && (numofcon<(pointer->usernum)) && ((pointer->clitable[k].ready)==3)) { + if (pointer->contable[numofcon].state == S_STATE_OPENING) { + aflog(2, " realm[%s]: user[%d]: NEW", + get_realmname(&config, j), get_username(pointer, numofcon)); + FD_SET(pointer->contable[numofcon].connfd, &allset); + maxfdp1 = (maxfdp1 > (pointer->contable[numofcon].connfd+1)) ? + maxfdp1 : (pointer->contable[numofcon].connfd+1); + pointer->contable[numofcon].state = S_STATE_OPEN; + } + } + else { + remove_client(pointer, k, &allset, &wset, &manconnecting); + } + break; + } + case AF_S_CANT_OPEN : { + n = numofcon; + numofcon = eval_numofcon(pointer, k, numofcon); + if ((numofcon>=0) && (numofcon<(pointer->usernum)) && ((pointer->clitable[k].ready)==3)) { + if (pointer->contable[numofcon].state == S_STATE_OPENING) { + aflog(2, " realm[%s]: user[%d]: DROPPED", + get_realmname(&config, j), get_username(pointer, numofcon)); + pointer->usercon--; + pointer->clitable[k].usercon--; + pointer->clitable[k].users[n] = -1; + close(pointer->contable[numofcon].connfd); + pointer->contable[numofcon].state = S_STATE_CLEAR; + } + } + else { + remove_client(pointer, k, &allset, &wset, &manconnecting); + } + break; + } + case AF_S_MESSAGE : { + if ((pointer->clitable[k].ready) != 3) { + remove_client(pointer, k, &allset, &wset, &manconnecting); + break; + } + if (TYPE_IS_UDP(pointer->type)) { /* udp */ + n = get_message(pointer->type, pointer->clitable[k].cliconn, &buff[5], length); + } + else { + n = get_message(pointer->type, pointer->clitable[k].cliconn, buff, length); + } + numofcon = eval_numofcon(pointer, k, numofcon); + if ((numofcon>=0) && (numofcon<(pointer->usernum))) { + if (pointer->contable[numofcon].state == S_STATE_OPEN) { + aflog(2, " realm[%s]: TO user[%d]: MESSAGE length=%d", + get_realmname(&config, j), get_username(pointer, numofcon), n); + 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 */ + sent = write(pointer->contable[numofcon].connfd, buff, n+5); + if (sent == -1) { + aflog(1, " realm[%s]: user[%d]: CLOSED (write-udp)", + get_realmname(&config, j), get_username(pointer, 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->clitable[k].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[%s]: TO user[%d]: BUFFERING MESSAGE STARTED (%d/%d)", + get_realmname(&config, j), get_username(pointer, numofcon), sent, n); + send_message(pointer->type, pointer->clitable[k].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[%s]: TO user[%d]: BUFFERING MESSAGE STARTED (%d/%d)", + get_realmname(&config, j), get_username(pointer, numofcon), sent, n); + send_message(pointer->type, pointer->clitable[k].cliconn, buff, 5); + } + else if (sent == -1) { + aflog(1, " realm[%s]: user[%d]: CLOSED (write-tcp)", + get_realmname(&config, j), get_username(pointer, 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->clitable[k].cliconn, buff, 5); + } + } + } + else if (pointer->contable[numofcon].state == S_STATE_STOPPED) { + aflog(3, " realm[%s]: TO user[%d]: BUFFERING MESSAGE (%d)", + get_realmname(&config, j), get_username(pointer, numofcon), n); + 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 { + insertblnode(&(pointer->contable[numofcon].head), 0, n, buff); + } + } + else if (pointer->contable[numofcon].state == S_STATE_CLOSING) { + aflog(3, " realm[%s]: TO user[%d]: IGNORED message length=%d", + get_realmname(&config, j), get_username(pointer, numofcon), n); + } + } + break; + } + case AF_S_LOGIN : { + if ((pointer->clitable[k].ready == 2) && (numofcon==(pointer->pass[0]*256+pointer->pass[1])) && + (length==(pointer->pass[2]*256+pointer->pass[3]))) { + if (k != pointer->clinum) { + pointer->clitable[k].ready = 3; + aflog(1, " realm[%s]: Client[%s]: pass ok - ACCESS GRANTED", + get_realmname(&config, j), get_clientname(pointer, k)); + buff[0] = AF_S_LOGIN; /* sending message */ + buff[1] = pointer->clitable[k].usernum >> 8;/* high bits of user number */ + buff[2] = pointer->clitable[k].usernum; /* low bits of user number */ + buff[3] = pointer->type; /* type of connection */ + send_message(pointer->type | TYPE_SSL | TYPE_ZLIB, pointer->clitable[k].cliconn, buff, 5); + manconnecting--; + if (pointer->baseport == 1) { + long tmp_val; + char tmp_tab[6]; + if (check_long(pointer->usrclitable[pointer->clitable[k].whatusrcli].lisportnum, &tmp_val)) { + aflog(1, " realm[%s]: INVALID listenport - removing Client[%s]", + get_realmname(&config, j), get_clientname(pointer, k)); + remove_client(pointer, k, &allset, &wset, &manconnecting); + break; + } + tmp_val = tmp_val%65536; + memset(tmp_tab, 0, 6); + sprintf(tmp_tab, "%d", (int)tmp_val); + ipfam = 0x01; +#ifdef AF_INET6 + if (TYPE_IS_IPV4(pointer->type)) { + ipfam |= 0x02; + } + else if (TYPE_IS_IPV6(pointer->type)) { + ipfam |= 0x04; + } +#endif + while (ip_listen(&(pointer->clitable[k].listenfd), pointer->hostname, + tmp_tab, (&(pointer->addrlen)), ipfam)) { + tmp_val = (tmp_val+1)%65536; + memset(tmp_tab, 0, 6); + sprintf(tmp_tab, "%d", (int)tmp_val); + } + FD_SET(pointer->clitable[k].listenfd, &allset); + maxfdp1 = (maxfdp1 > (pointer->clitable[k].listenfd+1)) ? + maxfdp1 : (pointer->clitable[k].listenfd+1); + aflog(1, " realm[%s]: Client[%s]: listenport=%s", + get_realmname(&config, j), get_clientname(pointer, k), tmp_tab); + } + } + else { + aflog(3, " realm[%s]: client limit EXCEEDED", get_realmname(&config, j)); + buff[0] = AF_S_CANT_OPEN; /* sending message */ + send_message(pointer->type | TYPE_SSL, pointer->clitable[k].cliconn, buff, 5); + remove_client(pointer, k, &allset, &wset, &manconnecting); + } + } + else if ((pointer->clitable[k].ready == 3) && (numofcon == 0)) { + n = get_message(pointer->type, pointer->clitable[k].cliconn, buff, length); + buff[n] = 0; + aflog(1, " realm[%s]: Client[%s]: ID received: %s", + get_realmname(&config, j), get_clientname(pointer, k), buff); + if (pointer->clitable[k].clientid) { + free(pointer->clitable[k].clientid); + } + pointer->clitable[k].clientid = malloc(n+1); + if (pointer->clitable[k].clientid) { + memcpy(pointer->clitable[k].clientid, buff, n+1); + } + } + else { + aflog(1, " realm[%s]: Client[%s]: Wrong password - CLOSING", + get_realmname(&config, j), get_clientname(pointer, k)); + remove_client(pointer, k, &allset, &wset, &manconnecting); + } + break; + } + case AF_S_DONT_SEND: { + aflog(3, " realm[%s]: user[%d]: STOP READING", + get_realmname(&config, j), get_username(pointer, numofcon)); + FD_CLR(pointer->contable[numofcon].connfd, &allset); + break; + } + case AF_S_CAN_SEND: { + aflog(3, " realm[%s]: user[%d]: START READING", + get_realmname(&config, j), get_username(pointer, numofcon)); + FD_SET(pointer->contable[numofcon].connfd, &allset); + break; + } + case AF_S_WRONG: { + aflog(1, " realm[%s]: Client[%s]: Wrong message - CLOSING", + get_realmname(&config, j), get_clientname(pointer, k)); + remove_client(pointer, k, &allset, &wset, &manconnecting); + break; + } + case AF_S_ADMIN_LOGIN: { + if ((pointer->clitable[k].ready == 2) && (numofcon==(pointer->pass[0]*256+pointer->pass[1])) && + (length==(pointer->pass[2]*256+pointer->pass[3]))) { + aflog(1, " realm[%s]: Client[%s]: NEW remote admin -- pass OK", + get_realmname(&config, j), get_clientname(pointer, k)); + for (l = 0; l < pointer->raclinum; ++l) { + if (pointer->raclitable[l].ready == 0) { + pointer->raclitable[l].cliconn.commfd = pointer->clitable[k].cliconn.commfd; + pointer->raclitable[l].connecttime = pointer->clitable[k].connecttime; + pointer->raclitable[l].clientnum = pointer->clitable[k].clientnum; + memcpy(pointer->raclitable[l].namebuf, pointer->clitable[k].namebuf, 128); + memcpy(pointer->raclitable[l].portbuf, pointer->clitable[k].portbuf, 7); + tmp_ssl = pointer->raclitable[l].cliconn.ssl; + pointer->raclitable[l].cliconn.ssl = pointer->clitable[k].cliconn.ssl; + pointer->clitable[k].cliconn.ssl = tmp_ssl; + pointer->clitable[k].ready = 0; + break; + } + } + if (l != pointer->raclinum) { + pointer->raclitable[l].ready = 3; + pointer->raclicon++; + manconnecting--; + sprintf((char*) &buff[5], AF_VER("AFSERVER")); + n = strlen((char*) &buff[5]); + buff[0] = AF_S_ADMIN_LOGIN; /* sending message */ + buff[1] = pointer->type; /* type of connection */ + buff[2] = AF_RA_UNDEFINED; + buff[3] = n >> 8; /* high bits of message length */ + buff[4] = n; /* low bits of message length */ + send_message(pointer->type | TYPE_SSL, pointer->raclitable[l].cliconn, buff, n+5); + } + else { + aflog(1, " realm[%s]: Client[%s]: remote admin -- limit EXCEEDED", + get_realmname(&config, j), get_clientname(pointer, k)); + buff[0] = AF_S_CANT_OPEN; /* sending message */ + send_message(pointer->type | TYPE_SSL | TYPE_ZLIB, pointer->clitable[k].cliconn, buff, 5); + remove_client(pointer, k, &allset, &wset, &manconnecting); + } + } + break; + } + default : { + aflog(1, " realm[%s]: Client[%s]: Unrecognized message - CLOSING", + get_realmname(&config, j), get_clientname(pointer, k)); + remove_client(pointer, k, &allset, &wset, &manconnecting); + } + } + } + /* ------------------------------------ */ + for (k = 0; k < pointer->raclinum; ++k) + if ((pointer->raclitable[k].ready != 0) && (FD_ISSET(pointer->raclitable[k].cliconn.commfd, &rset))) { + if (pointer->raclitable[k].ready == 1) { + make_ssl_initialize(&(pointer->raclitable[k].cliconn)); + aflog(2, " realm[%s]: new Client[%s] (ra): SSL_accept", + get_realmname(&config, j), get_raclientname(pointer, k)); + switch (make_ssl_accept(&(pointer->raclitable[k].cliconn))) { + case 2: { + close (pointer->raclitable[k].cliconn.commfd); + FD_CLR(pointer->raclitable[k].cliconn.commfd, &allset); + SSL_clear(pointer->raclitable[k].cliconn.ssl); + pointer->raclitable[k].ready = 0; + manconnecting--; + pointer->clicon--; + aflog(1, " realm[%s]: new Client[%s] (ra): DENIED by SSL_accept", + get_realmname(&config, j), get_raclientname(pointer, k)); + } + case 1: { + continue; + } + default: { + aflog(1, " realm[%s]: new Client[%s] (ra): ACCEPTED by SSL_accept", + get_realmname(&config, j), get_raclientname(pointer, k)); + pointer->raclitable[k].ready = 2; + continue; + } + } + } + aflog(3, " realm[%s]: Client[%s] (ra): commfd: FD_ISSET", + get_realmname(&config, j), get_raclientname(pointer, k)); + n = get_message(pointer->type | TYPE_SSL | TYPE_ZLIB, pointer->raclitable[k].cliconn, buff, -5); + if (n == -1) { + if (errno == EAGAIN) { + aflog(4, " realm[%s]: Client[%s] (ra): commfd: EAGAIN", + get_realmname(&config, j), get_raclientname(pointer, k)); + continue; + } + else { + aflog(4, " realm[%s]: Client[%s] (ra): commfd: ERROR: %d", + get_realmname(&config, j), get_raclientname(pointer, k), errno); + n = 0; + } + } + else if (n != 5) { + if (n != 0) { + aflog(4, " realm[%s]: Client[%s] (ra): header length = %d --> closing client", + get_realmname(&config, j), get_raclientname(pointer, k), n); + } + n = 0; + } + if (n==0) { + remove_raclient(pointer, k, &allset, &wset, &manconnecting); + aflog(1, " realm[%s]: Client[%s] (ra): commfd: CLOSED", + get_realmname(&config, j), get_raclientname(pointer, k)); + continue; + } + + 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 */ + + if (pointer->raclitable[k].ready<2) { + aflog(1, " realm[%s]: Client[%s] (ra): Impossible behaviour --> ignoring", + get_realmname(&config, j), get_raclientname(pointer, k)); + continue; + } + if ((pointer->raclitable[k].ready == 2) && (buff[0] != AF_S_LOGIN) && (buff[0] != AF_S_ADMIN_LOGIN)) { + buff[0] = AF_S_WRONG; + } + + switch (buff[0]) { + case AF_S_LOGIN : { + if ((pointer->raclitable[k].ready == 2) && (numofcon==(pointer->pass[0]*256+pointer->pass[1])) && + (length==(pointer->pass[2]*256+pointer->pass[3]))) { + for (l = 0; l < pointer->clinum; ++l) { + if (!(pointer->clitable[l].ready)) { + aflog(1, " realm[%s]: Client[%s] (ra) --> Client[%s]", + get_realmname(&config, j), get_raclientname(pointer, k), get_clientname(pointer, l)); + pointer->clitable[l].cliconn.commfd = pointer->raclitable[k].cliconn.commfd; + pointer->clitable[l].connecttime = pointer->raclitable[k].connecttime; + pointer->clitable[l].clientnum = pointer->raclitable[k].clientnum; + memcpy(pointer->clitable[l].namebuf, pointer->raclitable[k].namebuf, 128); + memcpy(pointer->clitable[l].portbuf, pointer->raclitable[k].portbuf, 7); + tmp_ssl = pointer->clitable[l].cliconn.ssl; + pointer->clitable[l].cliconn.ssl = pointer->raclitable[k].cliconn.ssl; + pointer->raclitable[k].cliconn.ssl = tmp_ssl; + pointer->clitable[l].whatusrcli = pointer->raclitable[k].whatusrcli; + pointer->raclitable[k].ready = 0; + break; + } + } + if (l != pointer->clinum) { + pointer->clitable[l].ready = 3; + aflog(1, " realm[%s]: Client[%s]: pass ok - ACCESS GRANTED", + get_realmname(&config, j), get_clientname(pointer, l)); + buff[0] = AF_S_LOGIN; /* sending message */ + buff[1] = pointer->clitable[l].usernum >> 8;/* high bits of user number */ + buff[2] = pointer->clitable[l].usernum; /* low bits of user number */ + buff[3] = pointer->type; /* type of connection */ + send_message(pointer->type | TYPE_SSL | TYPE_ZLIB, pointer->clitable[l].cliconn, buff, 5); + manconnecting--; + if (pointer->baseport == 1) { + long tmp_val; + char tmp_tab[6]; + if (check_long(pointer->usrclitable[pointer->clitable[l].whatusrcli].lisportnum, &tmp_val)) { + aflog(1, " realm[%s]: INVALID listenport - removing Client[%s]", + get_realmname(&config, j), get_clientname(pointer, l)); + remove_client(pointer, l, &allset, &wset, &manconnecting); + break; + } + tmp_val = tmp_val%65536; + memset(tmp_tab, 0, 6); + sprintf(tmp_tab, "%d", (int)tmp_val); + ipfam = 0x01; +#ifdef AF_INET6 + if (TYPE_IS_IPV4(pointer->type)) { + ipfam |= 0x02; + } + else if (TYPE_IS_IPV6(pointer->type)) { + ipfam |= 0x04; + } +#endif + while (ip_listen(&(pointer->clitable[l].listenfd), pointer->hostname, + tmp_tab, (&(pointer->addrlen)), ipfam)) { + tmp_val = (tmp_val+1)%65536; + memset(tmp_tab, 0, 6); + sprintf(tmp_tab, "%d", (int)tmp_val); + } + FD_SET(pointer->clitable[l].listenfd, &allset); + maxfdp1 = (maxfdp1 > (pointer->clitable[l].listenfd+1)) ? + maxfdp1 : (pointer->clitable[l].listenfd+1); + aflog(1, " realm[%s]: Client[%s]: listenport=%s", + get_realmname(&config, j), get_clientname(pointer, l), tmp_tab); + } + } + else { + aflog(3, " realm[%s]: client limit EXCEEDED", get_realmname(&config, j)); + buff[0] = AF_S_CANT_OPEN; /* sending message */ + send_message(pointer->type | TYPE_SSL | TYPE_ZLIB, pointer->raclitable[k].cliconn, buff, 5); + remove_raclient(pointer, k, &allset, &wset, &manconnecting); + } + } + else if ((pointer->raclitable[k].ready == 3) && (numofcon == 0)) { + n = get_message(pointer->type, pointer->raclitable[k].cliconn, buff, length); + buff[n] = 0; + aflog(1, " realm[%s]: Client[%s] (ra): ID received: %s", + get_realmname(&config, j), get_raclientname(pointer, k), buff); + if (pointer->raclitable[k].clientid) { + free(pointer->raclitable[k].clientid); + } + pointer->raclitable[k].clientid = malloc(n+1); + if (pointer->raclitable[k].clientid) { + memcpy(pointer->raclitable[k].clientid, buff, n+1); + } + } + else { + aflog(1, " realm[%s]: Client[%s] (ra): Wrong password - CLOSING", + get_realmname(&config, j), get_raclientname(pointer, k)); + remove_raclient(pointer, k, &allset, &wset, &manconnecting); + } + break; + } + case AF_S_WRONG: { + aflog(1, " realm[%s]: Client[%s] (ra): Wrong message - CLOSING", + get_realmname(&config, j), get_raclientname(pointer, k)); + remove_raclient(pointer, k, &allset, &wset, &manconnecting); + break; + } + case AF_S_ADMIN_LOGIN: { + if ((pointer->raclitable[k].ready == 2) && (numofcon==(pointer->pass[0]*256+pointer->pass[1])) && + (length==(pointer->pass[2]*256+pointer->pass[3]))) { + aflog(1, " realm[%s]: Client[%s] (ra): NEW remote admin -- pass OK", + get_realmname(&config, j), get_raclientname(pointer, k)); + pointer->raclitable[k].ready = 3; + pointer->raclicon++; + manconnecting--; + sprintf((char*) &buff[5], AF_VER("AFSERVER")); + n = strlen((char*) &buff[5]); + buff[0] = AF_S_ADMIN_LOGIN; /* sending message */ + buff[1] = pointer->type; /* type of connection */ + buff[2] = AF_RA_UNDEFINED; + buff[3] = n >> 8; /* high bits of message length */ + buff[4] = n; /* low bits of message length */ + send_message(pointer->type | TYPE_SSL | TYPE_ZLIB, pointer->raclitable[k].cliconn, buff, n+5); + } + break; + } + case AF_S_ADMIN_CMD: { + if (pointer->raclitable[k].ready == 3) { + if (serve_admin(&config, j, k, buff)) { + remove_raclient(pointer, k, &allset, &wset, &manconnecting); + } + } + else { + aflog(1, " realm[%s]: Client[%s] (ra): remote admin -- security VIOLATION", + get_realmname(&config, j), get_raclientname(pointer, k)); + remove_raclient(pointer, k, &allset, &wset, &manconnecting); + } + break; + } + default : { + aflog(1, " realm[%s]: Client[%s] (ra): Unrecognized message - CLOSING", + get_realmname(&config, j), get_raclientname(pointer, k)); + remove_raclient(pointer, k, &allset, &wset, &manconnecting); + } + } + } + /* ------------------------------------ */ + for (l = 0; l < pointer->usrclinum; ++l) { + if (FD_ISSET(pointer->usrclitable[l].managefd, &rset)) { + aflog(3, " realm[%s]: managefd: FD_ISSET", get_realmname(&config, j)); + len = pointer->addrlen; + sent = accept(pointer->usrclitable[l].managefd,pointer->cliaddr,&len); + flags = fcntl(sent, F_GETFL, 0); + fcntl(sent, F_SETFL, flags | O_NONBLOCK); + for (k = 0; k < pointer->clinum; ++k) { + if (!(pointer->clitable[k].ready)) { + pointer->clitable[k].clientnum = pointer->clientcounter; + ++(pointer->clientcounter); + aflog(2, " realm[%s]: new Client[%s]: CONNECTING", + get_realmname(&config, j), get_clientname(pointer, k)); + pointer->clitable[k].cliconn.commfd = sent; + pointer->clitable[k].whatusrcli = l; + time(&pointer->clitable[k].connecttime); + aflog(1, " realm[%s]: new Client[%s] IP:%s", get_realmname(&config, j), get_clientname(pointer, k), + sock_ntop(pointer->cliaddr, len, pointer->clitable[k].namebuf, + pointer->clitable[k].portbuf, pointer->dnslookups)); + FD_SET(pointer->clitable[k].cliconn.commfd, &allset); + maxfdp1 = (maxfdp1 > (pointer->clitable[k].cliconn.commfd+1)) ? + maxfdp1 : (pointer->clitable[k].cliconn.commfd+1); + pointer->clicon++; + pointer->clitable[k].tv.tv_sec = pointer->tmout; + manconnecting++; + pointer->clitable[k].ready = 1; + break; + } + } + if (k == pointer->clinum) { + for (k = 0; k < pointer->raclinum; ++k) { + if ((!pointer->raclitable[k].ready)) { + pointer->raclitable[k].clientnum = pointer->clientcounter; + ++(pointer->clientcounter); + aflog(2, " realm[%s]: new Client[%s] (ra): CONNECTING", + get_realmname(&config, j), get_raclientname(pointer, k)); + pointer->raclitable[k].cliconn.commfd = sent; + pointer->raclitable[k].whatusrcli = l; + time(&pointer->raclitable[k].connecttime); + aflog(1, " realm[%s]: new Client[%s] (ra) IP:%s", + get_realmname(&config, j), get_raclientname(pointer, k), + sock_ntop(pointer->cliaddr, len, pointer->raclitable[k].namebuf, + pointer->raclitable[k].portbuf, pointer->dnslookups)); + FD_SET(pointer->raclitable[k].cliconn.commfd, &allset); + maxfdp1 = (maxfdp1 > (pointer->raclitable[k].cliconn.commfd+1)) ? + maxfdp1 : (pointer->raclitable[k].cliconn.commfd+1); + pointer->clicon++; + pointer->raclitable[k].tv.tv_sec = pointer->tmout; + manconnecting++; + pointer->raclitable[k].ready = 1; + break; + } + } + if (k == pointer->raclinum) { + aflog(3, " realm[%s]: client limit EXCEEDED", get_realmname(&config, j)); + close(sent); + } + } + } + } + } /* realms loop */ + } +} + +static void +usage(char* info) +{ + printf("\n%s\n\n\n", info); + printf(" Basic options:\n\n"); + printf(" -n, --hostname - it's used when creating listening sockets\n"); + printf(" (default: '')\n"); + printf(" -l, --listenport - listening port number - users connect\n"); + printf(" to it (default: 50127)\n"); + printf(" -m, --manageport - manage port number - second part of the active\n"); + printf(" port forwarder connects to it (default: 50126)\n"); + printf(" -h, --help - prints this help\n\n"); + printf(" Authorization:\n\n"); + printf(" --pass - set the password used for client identification\n"); + printf(" (default: no password)\n\n"); + printf(" Configuration:\n\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(" -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(" -t, --timeout - the timeout value for the client's connection\n"); + printf(" (default: 5)\n"); + printf(" -u, --users - the amount of users allowed to use this server\n"); + printf(" (default: 5)\n"); + printf(" -C, --clients - the number of allowed clients to use this server\n"); + printf(" (default: 1)\n"); + printf(" -r, --realm - set the realm name (default: none)\n"); + printf(" -R, --raclients - the number of allowed clients in remote administration\n"); + printf(" mode to use this server (default: 1)\n"); + printf(" -U, --usrpcli - the number of allowed users per client (default: $users)\n"); + printf(" -M, --climode - strategy used to connect users with clients (default: 1)\n"); + printf(" Available strategies:\n"); + printf(" 1. fill first client before go to next\n\n"); + printf(" -p, --proto - type of server (tcp|udp) - what protocol it will be\n"); + printf(" operating for (default: tcp)\n"); + printf(" -b, --baseport - listenports are temporary and differ for each client\n"); + printf(" --nossl - ssl is not used to transfer data (but it's still used\n"); + printf(" to establish a connection) (default: ssl is used)\n"); + printf(" --nozlib - zlib is not used to compress data (default: zlib is\n"); + printf(" used)\n"); + printf(" --dnslookups - try to obtain dns names of the computers rather than\n"); + printf(" their numeric IP\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 + exit(0); +} + +static void +sig_int(int signo) +{ + int i, j; + unsigned char buff[5]; + for (j = 0; j < config.size; ++j) { + buff[0] = AF_S_CLOSING; /* closing */ + for (i = 0; i < config.realmtable[j].clinum+1; ++i) { + if (config.realmtable[j].clitable[i].ready == 3) { + if (config.realmtable[j].clinum == i) { + send_message(config.realmtable[j].type | TYPE_SSL, config.realmtable[j].clitable[i].cliconn, buff, 5); + } + else { + send_message(config.realmtable[j].type, config.realmtable[j].clitable[i].cliconn, buff, 5); + } + } + } + } + aflog(1, "SERVER CLOSED cg: %ld bytes", getcg()); + exit(0); +} + diff --git a/src/afserver.h b/src/afserver.h new file mode 100644 index 0000000..6975af4 --- /dev/null +++ b/src/afserver.h @@ -0,0 +1,51 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 "activefor.h" +#include "network.h" +#include "file.h" +#include "stats.h" +#include "remoteadmin.h" +#include "server_check.h" +#include "server_set.h" +#include "server_eval.h" +#include "server_find.h" +#include "server_remove.h" +#include "make_ssl_handshake.h" +#include "first_run.h" +#include "realmnames.h" +#include "clientnames.h" +#include "usernames.h" + +#include <openssl/ssl.h> +#include <openssl/err.h> +#include <fcntl.h> +#include <signal.h> +#include <string.h> +#include <getopt.h> + +#ifndef _JS_AFSERVER_H +#define _JS_AFSERVER_H + +static void usage(char* info); +static void sig_int(int); + +#endif + diff --git a/src/buflist.c b/src/buflist.c new file mode 100644 index 0000000..7ee5ede --- /dev/null +++ b/src/buflist.c @@ -0,0 +1,70 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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; + memcpy((char*)newnode->buff, (char*)buff+actptr, 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; + if (node->buff != NULL) + free(node->buff); + free(node); + return 0; +} + +int +freebuflist(blnodeT** headRef) +{ + while (*headRef) { + deleteblnode(headRef); + } + return 0; +} diff --git a/src/buflist.h b/src/buflist.h new file mode 100644 index 0000000..bc96e73 --- /dev/null +++ b/src/buflist.h @@ -0,0 +1,35 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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/src/clientnames.c b/src/clientnames.c new file mode 100644 index 0000000..9658903 --- /dev/null +++ b/src/clientnames.c @@ -0,0 +1,129 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 <stdio.h> +#include <string.h> +#include "clientnames.h" + +char* +get_clientname(RealmT* pointer, int client) +{ + static char clientname[10]; + + if (pointer->clitable[client].clientid == NULL) { + memset(clientname, 0, 10); + sprintf(clientname, "%d", pointer->clitable[client].clientnum); + return clientname; + } + + return pointer->clitable[client].clientid; +} + +int +get_clientid(RealmT* pointer, char* clientname) +{ + int i, n; + char guard; + + for (i = 0; i < pointer->clinum; ++i) { + if (pointer->clitable[i].clientid != NULL) { + if (strcmp(clientname, pointer->clitable[i].clientid) == 0) { + return pointer->clitable[i].clientnum; + } + } + } + + if (sscanf(clientname, "%d%c", &i, &guard) == 1) { + n = get_clientnumber(pointer, i); + if ((n >= 0) && (n < pointer->clinum)) { + if (pointer->clitable[n].clientid == NULL) { + return i; + } + } + } + + return -1; +} + +int +get_clientnumber(RealmT* pointer, int clientid) +{ + int i; + for (i = 0; i < pointer->clinum; ++i) { + if (pointer->clitable[i].clientnum == clientid) { + return i; + } + } + + return -1; +} + +char* +get_raclientname(RealmT* pointer, int client) +{ + static char clientname[10]; + + if (pointer->raclitable[client].clientid == NULL) { + memset(clientname, 0, 10); + sprintf(clientname, "%d", pointer->raclitable[client].clientnum); + return clientname; + } + + return pointer->raclitable[client].clientid; +} + +int +get_raclientid(RealmT* pointer, char* clientname) +{ + int i, n; + char guard; + + for (i = 0; i < pointer->raclinum; ++i) { + if (pointer->raclitable[i].clientid != NULL) { + if (strcmp(clientname, pointer->raclitable[i].clientid) == 0) { + return pointer->raclitable[i].clientnum; + } + } + } + + if (sscanf(clientname, "%d%c", &i, &guard) == 1) { + n = get_raclientnumber(pointer, i); + if ((n >= 0) && (n < pointer->raclinum)) { + if (pointer->raclitable[n].clientid == NULL) { + return i; + } + } + } + + return -1; +} + +int +get_raclientnumber(RealmT* pointer, int clientid) +{ + int i; + for (i = 0; i < pointer->raclinum; ++i) { + if (pointer->raclitable[i].clientnum == clientid) { + return i; + } + } + + return -1; +} diff --git a/src/clientnames.h b/src/clientnames.h new file mode 100644 index 0000000..c93a2dc --- /dev/null +++ b/src/clientnames.h @@ -0,0 +1,35 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 "activefor.h" + +#ifndef _JS_CLIENTNAMES_H +#define _JS_CLIENTNAMES_H + +char* get_clientname(RealmT*, int); +int get_clientid(RealmT*, char*); +int get_clientnumber(RealmT*, int); + +char* get_raclientname(RealmT*, int); +int get_raclientid(RealmT*, char*); +int get_raclientnumber(RealmT*, int); + +#endif + diff --git a/src/file.c b/src/file.c new file mode 100644 index 0000000..e4cde62 --- /dev/null +++ b/src/file.c @@ -0,0 +1,373 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 "file.h" +#include "activefor.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <limits.h> +#include <ctype.h> + +int +parse_line(char* buff, char* tab1, char* tab2) +{ + int state, i, j, lastDot; + state = i = j = 0; + lastDot = -1; + while (buff[i] != 0) { + if (buff[i] == '#') { + if ((i > 0) && (buff[i-1] == '\\')) { + --j; + } + else { + break; + } + } + switch (state) { + case 0: { /* before option name */ + if (!isspace(buff[i])) { + tab1[j] = buff[i]; + j = 1; + state = 1; + } + break; + } + case 1: { /* option */ + if (isspace(buff[i])) { + tab1[j] = 0; + state = 2; + j = 0; + } + else { + tab1[j] = buff[i]; + ++j; + } + break; + } + case 2: { /* before option value */ + if (!isspace(buff[i])) { + if (buff[i] != '.') { + tab2[j] = buff[i]; + j = 1; + } + state = 3; + } + break; + } + case 3: { /* option value */ + if (buff[i] == '.') { + lastDot = j; + } + else if (!isspace(buff[i])) { + lastDot = -1; + } + else if (lastDot == -1) { + lastDot = j; + } + tab2[j] = buff[i]; + ++j; + break; + } + } + ++i; + } + if (lastDot != -1) { + tab2[lastDot] = 0; + } + if (state == 3) { + return 2; + } + if (state == 0) { + return 0; + } + return 1; +} + +ConfigurationT +parsefile(char* name, int* status) +{ + static ConfigurationT cfg; + FILE* file = NULL; + int state, i, n, listencount, managecount; + char buff[256]; + char helpbuf1[256]; + char helpbuf2[256]; + + *status = 1; + + memset(buff, 0, 256); + + cfg.certif = NULL; + cfg.keys = NULL; + cfg.size = 0; + cfg.realmtable = NULL; + cfg.logging = 0; + cfg.socklogging = 0; + cfg.logfnam = NULL; + cfg.logsport = NULL; + cfg.dateformat = NULL; + + state = F_UNKNOWN; + + file = fopen(name, "r"); + if (file == NULL) { + return cfg; + } + + while (fgets(buff, 256, file) != NULL) { /* first loop - counting realm */ + helpbuf1[0] = 0; + parse_line(buff, helpbuf1, helpbuf2); + if (strcmp(helpbuf1, "realm")==0) { + ++cfg.size; + } + } + rewind(file); + + cfg.realmtable = calloc(cfg.size, sizeof(RealmT)); + for (i=0; i<cfg.size; ++i) { + cfg.realmtable[i].pass[0] = 1; + cfg.realmtable[i].pass[1] = 2; + cfg.realmtable[i].pass[2] = 3; + cfg.realmtable[i].pass[3] = 4; + } + cfg.size = 0; + *status = 0; + + listencount = managecount = 0; + + + while (fgets(buff, 256, file) != NULL) { /* second loop - counting listen */ + (*status)++; + state = parse_line(buff, helpbuf1, helpbuf2); + if (state) { + if (strcmp(helpbuf1, "realm")==0) { + ++cfg.size; + if (listencount != managecount) { + return cfg; + } + listencount = managecount = 0; + } + else if (strcmp(helpbuf1, "listen")==0) { + if (cfg.size == 0) { + return cfg; + } + ++cfg.realmtable[cfg.size-1].usrclinum; + ++listencount; + } + else if (strcmp(helpbuf1, "manage")==0) { + if (cfg.size == 0) { + return cfg; + } + ++managecount; + } + } + } + rewind(file); + + if (listencount != managecount) { + return cfg; + } + + for (i=0; i<cfg.size; ++i) { + cfg.realmtable[i].usrclitable = calloc(cfg.realmtable[i].usrclinum, sizeof(UsrCliT)); + } + + cfg.size = 0; + *status = 0; + + + while (fgets(buff, 256, file) != NULL) { /* third loop - parsing file */ + (*status)++; + state = parse_line(buff, helpbuf1, helpbuf2); + if (helpbuf1[0] == '#') { + memset(buff, 0, 256); + continue; + } + if (state == 1) { + if (strcmp(helpbuf1, "realm")==0) { + ++cfg.size; + TYPE_SET_SSL(cfg.realmtable[cfg.size-1].type); + TYPE_SET_ZLIB(cfg.realmtable[cfg.size-1].type); + listencount = managecount = 0; + } + 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, "baseport")==0) { + cfg.realmtable[cfg.size-1].baseport = 1; + } + else if (strcmp(helpbuf1, "dnslookups")==0) { + cfg.realmtable[cfg.size-1].dnslookups = 1; + } + 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, "realm")==0) { + ++cfg.size; + TYPE_SET_SSL(cfg.realmtable[cfg.size-1].type); + TYPE_SET_ZLIB(cfg.realmtable[cfg.size-1].type); + listencount = managecount = 0; + cfg.realmtable[cfg.size-1].realmname = calloc(strlen(helpbuf2)+1, sizeof(char)); + strcpy(cfg.realmtable[cfg.size-1].realmname, helpbuf2); + } + else 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 (strcmp(helpbuf1, "heavysocklog")==0) { + if (cfg.socklogging) { + return cfg; + } + cfg.socklogging = 3; + cfg.logsport = calloc(strlen(helpbuf2)+1, sizeof(char)); + strcpy(cfg.logsport, helpbuf2); + } + else if (strcmp(helpbuf1, "lightsocklog")==0) { + if (cfg.socklogging) { + return cfg; + } + cfg.socklogging = 1; + cfg.logsport = calloc(strlen(helpbuf2)+1, sizeof(char)); + strcpy(cfg.logsport, helpbuf2); + } + else if (strcmp(helpbuf1, "dateformat")==0) { + cfg.dateformat = calloc(strlen(helpbuf2)+1, sizeof(char)); + strcpy(cfg.dateformat, 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].usrclitable[listencount].lisportnum=calloc(strlen(helpbuf2)+1, sizeof(char)); + strcpy(cfg.realmtable[cfg.size-1].usrclitable[listencount].lisportnum, helpbuf2); + ++listencount; + } + else if (strcmp(helpbuf1, "pass")==0) { + n = strlen(helpbuf2); + memset(cfg.realmtable[cfg.size-1].pass, 0, 4); + 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].usrclitable[managecount].manportnum=calloc(strlen(helpbuf2)+1, sizeof(char)); + strcpy(cfg.realmtable[cfg.size-1].usrclitable[managecount].manportnum, helpbuf2); + ++managecount; + } + 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, "timeout")==0) { + cfg.realmtable[cfg.size-1].timeout = calloc(strlen(helpbuf2)+1, sizeof(char)); + strcpy(cfg.realmtable[cfg.size-1].timeout, helpbuf2); + } + else if (strcmp(helpbuf1, "clients")==0) { + cfg.realmtable[cfg.size-1].clients = calloc(strlen(helpbuf2)+1, sizeof(char)); + strcpy(cfg.realmtable[cfg.size-1].clients, helpbuf2); + } + else if (strcmp(helpbuf1, "raclients")==0) { + cfg.realmtable[cfg.size-1].raclients = calloc(strlen(helpbuf2)+1, sizeof(char)); + strcpy(cfg.realmtable[cfg.size-1].raclients, helpbuf2); + } + else if (strcmp(helpbuf1, "usrpcli")==0) { + cfg.realmtable[cfg.size-1].usrpcli = calloc(strlen(helpbuf2)+1, sizeof(char)); + strcpy(cfg.realmtable[cfg.size-1].usrpcli, helpbuf2); + } + else if (strcmp(helpbuf1, "climode")==0) { + cfg.realmtable[cfg.size-1].clim = calloc(strlen(helpbuf2)+1, sizeof(char)); + strcpy(cfg.realmtable[cfg.size-1].clim, 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); + + *status = 0; + return cfg; +} + diff --git a/src/file.h b/src/file.h new file mode 100644 index 0000000..7738df6 --- /dev/null +++ b/src/file.h @@ -0,0 +1,37 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 "activefor.h" +#include "network.h" +#include <openssl/ssl.h> + +#ifndef _JS_FILE_H +#define _JS_FILE_H + +#define F_UNKNOWN 1 +#define F_IGNORE 2 +#define F_ROPTION 3 +#define F_RVALUE 4 +#define F_MIDDLE 5 + +ConfigurationT parsefile(char*, int*); /* parse the cfg file */ + +#endif + diff --git a/src/first_run.c b/src/first_run.c new file mode 100644 index 0000000..842a3e0 --- /dev/null +++ b/src/first_run.c @@ -0,0 +1,156 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <pwd.h> + +static char* home_dir = NULL; +static char* home_dir_key = NULL; +static char* home_dir_cer = NULL; + +int +create_apf_dir() +{ + int length; + struct stat buf; + struct passwd *user = getpwuid(getuid()); + if (user == NULL) { + return 1; /* some problems witch fetching user info*/ + } + if (user->pw_dir == NULL) { + return 2; /* home directory is not set? */ + } + if (home_dir) { + free(home_dir); + home_dir = NULL; + } + length = strlen(user->pw_dir); + home_dir = calloc(1, length + 6); + if (home_dir == NULL) { + return 3; /* calloc failed */ + } + strcpy(home_dir, user->pw_dir); + if (home_dir[length] == '/') { + strcpy(&home_dir[length], ".apf"); + } + else { + strcpy(&home_dir[length], "/.apf"); + } + if (stat(home_dir, &buf)) { + if (mkdir(home_dir, 0700)) { + return 4; /* creating directory failed */ + } + } + return 0; +} + +int +generate_rsa_key(char** keyfile) +{ + int key_length, home_length, status; + char openssl_cmd[101]; + struct stat buf; + /* check in local directory first */ + if (stat(*keyfile, &buf) == 0) { + return 0; + } + /* check in home_dir */ + key_length = strlen(*keyfile); + home_length = strlen(home_dir); + if (home_dir_key) { + free(home_dir_key); + home_dir_key = NULL; + } + home_dir_key = calloc(1, home_length + key_length + 2); + if (home_dir_key == NULL) { + return 1; /* calloc failed */ + } + strcpy(home_dir_key, home_dir); + home_dir_key[home_length] = '/'; + strcpy(&home_dir_key[home_length+1], *keyfile); + *keyfile = home_dir_key; + if (stat(home_dir_key, &buf) == 0) { + return 0; + } + /* have to generate the key */ + if (snprintf(openssl_cmd, 101, "openssl genrsa -out %s 2048", home_dir_key) > 100) { + return 2; /* string is too long */ + } + status = system(openssl_cmd); + if (status == -1) { + return -1; + } + return WEXITSTATUS(status); +} + +int +generate_certificate(char** cerfile, char* keyfile) +{ + int cer_length, home_length, status, tmp_fd1, tmp_fd2; + char openssl_cmd[301]; + struct stat buf; + /* check in local directory first */ + if (stat(*cerfile, &buf) == 0) { + return 0; + } + /* check in home_dir */ + cer_length = strlen(*cerfile); + home_length = strlen(home_dir); + if (home_dir_cer) { + free(home_dir_cer); + home_dir_cer = NULL; + } + home_dir_cer = calloc(1, home_length + cer_length + 2); + if (home_dir_cer == NULL) { + return 1; /* calloc failed */ + } + strcpy(home_dir_cer, home_dir); + home_dir_cer[home_length] = '/'; + strcpy(&home_dir_cer[home_length+1], *cerfile); + *cerfile = home_dir_cer; + if (stat(home_dir_cer, &buf) == 0) { + return 0; + } + /* have to generate the certificate */ + if (snprintf(openssl_cmd, 201, "echo -e \"pl\nWar-Maz\nOlsztyn\nSHEG\nUtils productions\njeremian\njeremian@poczta.fm\" | openssl req -new -x509 -key %s -out %s -days 1095", keyfile, home_dir_cer) > 300) { + return 2; /* string is too long */ + } + tmp_fd1 = dup(STDOUT_FILENO); + tmp_fd2 = dup(STDERR_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + status = system(openssl_cmd); + dup2(tmp_fd1, STDOUT_FILENO); + dup2(tmp_fd2, STDERR_FILENO); + close(tmp_fd1); + close(tmp_fd2); + if (status == -1) { + return -1; + } + return WEXITSTATUS(status); +} diff --git a/src/first_run.h b/src/first_run.h new file mode 100644 index 0000000..5a36ff6 --- /dev/null +++ b/src/first_run.h @@ -0,0 +1,29 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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_FIRST_RUN_H +#define _JS_FIRST_RUN_H + +int create_apf_dir(); +int generate_rsa_key(char**); +int generate_certificate(char**, char*); + +#endif + diff --git a/src/inet_ntop.c b/src/inet_ntop.c new file mode 100644 index 0000000..6d37620 --- /dev/null +++ b/src/inet_ntop.c @@ -0,0 +1,227 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 is from the BIND 4.9.4 release, modified to compile by itself */ + +/* Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#include "inet_ntop.h" + +#ifndef HAVE_THIS_INET_NTOP +#define HAVE_THIS_INET_NTOP + +#if defined(LIBC_SCCS) && !defined(lint) +static char rcsid[] = "$Id: inet_ntop.c,v 8.5 1996/05/22 04:56:30 vixie Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <string.h> +#include <errno.h> +#include <stdio.h> + +#define IN6ADDRSZ 16 +#define INT16SZ 2 + +/* + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + +static const char *inet_ntop4(const u_char *src, char *dst, size_t size); +#ifdef AF_INET6 +static const char *inet_ntop6(const u_char *src, char *dst, size_t size); +#endif + +/* char * + * inet_ntop(af, src, dst, size) + * convert a network format address to presentation format. + * return: + * pointer to presentation format address (`dst'), or NULL (see errno). + * author: + * Paul Vixie, 1996. + */ +const char * +inet_ntop(af, src, dst, size) + int af; + const void *src; + char *dst; + size_t size; +{ + switch (af) { + case AF_INET: + return (inet_ntop4(src, dst, size)); +#ifdef AF_INET6 + case AF_INET6: + return (inet_ntop6(src, dst, size)); +#endif + default: + errno = EAFNOSUPPORT; + return (NULL); + } + /* NOTREACHED */ +} + +/* const char * + * inet_ntop4(src, dst, size) + * format an IPv4 address, more or less like inet_ntoa() + * return: + * `dst' (as a const) + * notes: + * (1) uses no statics + * (2) takes a u_char* not an in_addr as input + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop4(src, dst, size) + const u_char *src; + char *dst; + size_t size; +{ + static const char fmt[] = "%u.%u.%u.%u"; + char tmp[sizeof "255.255.255.255"]; + + sprintf(tmp, fmt, src[0], src[1], src[2], src[3]); + if (strlen(tmp) > size) { + errno = ENOSPC; + return (NULL); + } + strcpy(dst, tmp); + return (dst); +} + +#ifdef AF_INET6 +/* const char * + * inet_ntop6(src, dst, size) + * convert IPv6 binary address into presentation (printable) format + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop6(src, dst, size) + const u_char *src; + char *dst; + size_t size; +{ + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; + struct { int base, len; } best, cur; + u_int words[IN6ADDRSZ / INT16SZ]; + int i; + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, 0, sizeof words); + for (i = 0; i < IN6ADDRSZ; i++) + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); + best.base = -1; + cur.base = -1; + for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { + if (words[i] == 0) { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } else { + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* + * Format the result. + */ + tp = tmp; + for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && + i < (best.base + best.len)) { + if (i == best.base) + *tp++ = ':'; + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) + *tp++ = ':'; + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && + (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { + if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) + return (NULL); + tp += strlen(tp); + break; + } + sprintf(tp, "%x", words[i]); + tp += strlen(tp); + } + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) + *tp++ = ':'; + *tp++ = '\0'; + + /* + * Check for overflow, copy, and we're done. + */ + if ((tp - tmp) > size) { + errno = ENOSPC; + return (NULL); + } + strcpy(dst, tmp); + return (dst); +} +#endif + +#endif diff --git a/src/inet_ntop.h b/src/inet_ntop.h new file mode 100644 index 0000000..9e49f1f --- /dev/null +++ b/src/inet_ntop.h @@ -0,0 +1,36 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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. + * + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#ifndef HAVE_INET_NTOP + +#include <sys/types.h> + +# ifndef _JS_INET_NTOP_H +# define _JS_INET_NTOP_H + +const char* inet_ntop(int af, const void *src, char *dst, size_t size); + +# endif + +#endif diff --git a/src/make_ssl_handshake.c b/src/make_ssl_handshake.c new file mode 100644 index 0000000..a5c97eb --- /dev/null +++ b/src/make_ssl_handshake.c @@ -0,0 +1,103 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 "make_ssl_handshake.h" +#include "stats.h" + +#include <config.h> + +#include <errno.h> +#include <openssl/err.h> + +void +make_ssl_initialize(clifd *cliconn) +{ + if (SSL_set_fd(cliconn->ssl, cliconn->commfd) != 1) { + aflog(0, "Problem with initializing ssl... exiting"); + exit(1); + } +} + +int +make_ssl_accept(clifd *cliconn) +{ + int result; + if ((result = SSL_accept(cliconn->ssl)) != 1) { + return get_ssl_error(cliconn, " SSL_accept has failed", result); + } + return 0; +} + +int +get_ssl_error(clifd *cliconn, char* info, int result) +{ + int merror; +#ifdef HAVE_ERR_ERROR_STRING + char err_buff[200]; +#endif + merror = SSL_get_error(cliconn->ssl, result); + switch (merror) { + case SSL_ERROR_NONE : { + aflog(2, "%s(%d): none", info, result); + break; + } + case SSL_ERROR_ZERO_RETURN : { + aflog(2, "%s(%d): zero", info, result); + break; + } + case SSL_ERROR_WANT_READ : { + aflog(2, "%s(%d): w_read", info, result); + break; + } + case SSL_ERROR_WANT_WRITE : { + aflog(2, "%s(%d): w_write", info, result); + break; + } + case SSL_ERROR_WANT_CONNECT : { + aflog(2, "%s(%d): w_connect", info, result); + break; + } + case SSL_ERROR_WANT_X509_LOOKUP : { + aflog(2, "%s(%d): w_x509_lookup", info, result); + break; + } + case SSL_ERROR_SYSCALL : { + aflog(2, "%s(%d): syscall", info, result); + break; + } + case SSL_ERROR_SSL : { + SSL_load_error_strings(); +#ifdef HAVE_ERR_ERROR_STRING + aflog(2, "%s(%d): ssl:%s", info, result, + ERR_error_string(ERR_get_error(), err_buff)); +#else + aflog(2, "%s(%d): ssl", info, result); +#endif + break; + } + default: { + aflog(2, "%s(%d): unrecognized error (%d)", info, result, errno); + } + } + if (merror == SSL_ERROR_WANT_READ) { + return 1; + } + return 2; +} diff --git a/src/make_ssl_handshake.h b/src/make_ssl_handshake.h new file mode 100644 index 0000000..674867a --- /dev/null +++ b/src/make_ssl_handshake.h @@ -0,0 +1,31 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 "network.h" + +#ifndef _JS_MAKE_SSL_HANDSHAKE_H +#define _JS_MAKE_SSL_HANDSHAKE_H + +void make_ssl_initialize(clifd *cliconn); +int make_ssl_accept(clifd *cliconn); +int get_ssl_error(clifd *cliconn, char* info, int result); + +#endif + diff --git a/src/modules.c b/src/modules.c new file mode 100644 index 0000000..0d153be --- /dev/null +++ b/src/modules.c @@ -0,0 +1,69 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 <config.h> + +#ifdef HAVE_LIBDL + +#include "modules.h" + +#include <stdlib.h> +#include <dlfcn.h> + +int +loadmodule(moduleT* module) +{ + if (module->name) { + module->handle = dlopen(module->name, RTLD_NOW); + if (!module->handle) { + return 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) { + return 2; + } + module->loaded = 1; + } + return 0; +} + +int +releasemodule(moduleT* module) +{ + if (ismloaded(module)) { + module->loaded = 0; + module->info = NULL; + module->allow = NULL; + module->filter = NULL; + return dlclose(module->handle); + } + return 0; +} + +int +ismloaded(moduleT* module) +{ + return module->loaded; +} + +#endif diff --git a/src/modules.h b/src/modules.h new file mode 100644 index 0000000..f6f8ea9 --- /dev/null +++ b/src/modules.h @@ -0,0 +1,43 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 <config.h> + +#ifdef HAVE_LIBDL + +# ifndef _JS_MODULES_H +# define _JS_MODULES_H + +typedef struct { + char loaded; + char* name; + void* handle; + char* (*info)(void); + int (*allow)(char*, char*); + int (*filter)(char*, unsigned char*, int*); +} moduleT; + +int loadmodule(moduleT* module); +int releasemodule(moduleT* module); +int ismloaded(moduleT* module); + +# endif + +#endif diff --git a/src/network.c b/src/network.c new file mode 100644 index 0000000..7618c76 --- /dev/null +++ b/src/network.c @@ -0,0 +1,484 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 <config.h> + +#include "inet_ntop.h" +#include "network.h" +#include "activefor.h" +#include "stats.h" +#include <string.h> +#include <errno.h> +#include <zlib.h> + +int +ip_listen(int* sockfd, const char *host, const char *serv, socklen_t *addrlenp, const char type) +{ +#if defined(HAVE_GETADDRINFO) && defined(AF_INET6) + int n; + const int on = 1; + struct addrinfo hints, *res, *ressave; + + bzero(&hints, sizeof(struct addrinfo)); + hints.ai_flags = AI_PASSIVE; + 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 { + hints.ai_socktype = SOCK_DGRAM; + } + + if ( (n = getaddrinfo(host, serv, &hints, &res)) != 0) { + return n; + } + ressave = res; + + do { + (*sockfd) = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if ((*sockfd) < 0) { + continue; /* error, try next one */ + } + + 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((*sockfd)); /* bind error, close and try next one */ + } while ( (res = res->ai_next) != NULL); + + if (res == NULL) { /* errno from final socket() or bind() */ + return 1; + } + + if (type & 0x01) { /* tcp_listen */ + listen((*sockfd), 1); + } + + if (addrlenp) { + *addrlenp = res->ai_addrlen; /* return size of protocol address */ + } + + freeaddrinfo(ressave); +#else + struct sockaddr_in servaddr; + struct hostent* hostaddr; + int port; + + if (type & 0x01) { + (*sockfd) = socket(AF_INET, SOCK_STREAM, 0); + } + else { + (*sockfd) = socket(AF_INET, SOCK_DGRAM, 0); + } + + if ((*sockfd) == -1) { + return 1; + } + port = atoi(serv); + + if (host) { + hostaddr = gethostbyname(host); + if (hostaddr == NULL) { + return 2; + } + } + + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + if (host) { + memcpy(&servaddr.sin_addr.s_addr, hostaddr->h_addr_list[0], hostaddr->h_length); + } + else { + servaddr.sin_addr.s_addr = htonl(INADDR_ANY); + } + servaddr.sin_port = htons(port); + + if (bind((*sockfd), (struct sockaddr*) &servaddr, sizeof(servaddr))){ + return 4; + } + + if (listen((*sockfd), 5)){ + return 5; + } +#endif + + return(0); +} + +int +ip_connect(int* sockfd, const char *host, const char *serv, const char type) +{ +#if defined(HAVE_GETADDRINFO) && defined(AF_INET6) + int n; + struct addrinfo hints, *res, *ressave; + + bzero(&hints, sizeof(struct addrinfo)); + 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 { + hints.ai_socktype = SOCK_DGRAM; + } + + if ( (n = getaddrinfo(host, serv, &hints, &res)) != 0) { + return n; + } + ressave = res; + + do { + (*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) { + break; /* success */ + } + + close((*sockfd)); /* ignore this one */ + } while ( (res = res->ai_next) != NULL); + + if (res == NULL) { /* errno set from final connect() */ + return 1; + } + + freeaddrinfo(ressave); +#else + struct sockaddr_in servaddr; + struct hostent* hostaddr; + int port; + + if (type & 0x01) { + (*sockfd) = socket(AF_INET, SOCK_STREAM, 0); + } + else { + (*sockfd) = socket(AF_INET, SOCK_DGRAM, 0); + } + + if ((*sockfd) == -1) { + return 1; + } + port = atoi(serv); + + hostaddr = gethostbyname(host); + if (hostaddr == NULL) { + return 2; + } + + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(port); + memcpy(&servaddr.sin_addr.s_addr, hostaddr->h_addr_list[0], hostaddr->h_length); + + if (connect((*sockfd), (struct sockaddr*) &servaddr, sizeof(servaddr))){ + return 3; + } +#endif + + return(0); +} + +char * +sock_ntop(const struct sockaddr *sa, socklen_t salen, char* namebuf, char* portbuf, char type) +{ + char portstr[7]; + static char str[136]; /* Unix domain is largest */ + + switch (sa->sa_family) { + case AF_INET: { + struct sockaddr_in *sin = (struct sockaddr_in *) sa; + + if (type) { +#ifdef HAVE_GETNAMEINFO + if (getnameinfo(sa, salen, str, 128, NULL, 0, 0)) { + return NULL; + } +#else + struct hostent* hostname; + if ((hostname = gethostbyaddr(&sin->sin_addr, sizeof(struct in_addr), AF_INET))) { + strncpy(str, hostname->h_name, 127); + str[127] = 0; + } + else { + if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)) == NULL) { + return NULL; + } + } +#endif + + } + else { + if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)) == NULL) { + return NULL; + } + } + if (namebuf) { + memcpy(namebuf, str, 128); + } + 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 AF_INET6 + case AF_INET6: { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa; + + if (type) { +#ifdef HAVE_GETNAMEINFO + if (getnameinfo(sa, salen, str, 128, NULL, 0, 0)) { + return NULL; + } +#else + struct hostent* hostname; + if ((hostname = gethostbyaddr(&sin6->sin6_addr, sizeof(struct in6_addr), AF_INET6))) { + strncpy(str, hostname->h_name, 127); + str[127] = 0; + } + else { + if (inet_ntop(AF_INET6, &sin6->sin6_addr, str, sizeof(str)) == NULL) { + return NULL; + } + } +#endif + + } + else { + if (inet_ntop(AF_INET6, &sin6->sin6_addr, str, sizeof(str)) == NULL) { + return NULL; + } + } + if (namebuf) { + memcpy(namebuf, str, 128); + } + 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); + return(str); + } + } + return NULL; +} + +int +SSL_writen(SSL* fd, unsigned char* buf, int amount) +{ + int sent, n; + sent = 0; + while (sent < amount) { + n = SSL_write(fd, buf+sent, amount - sent); + if (n != -1) { + sent += n; + } + if (n == -1) { + if (errno != EAGAIN) + return 0; + } + } + return amount; +} + +int +SSL_readn(SSL* fd, unsigned char* buf, int amount) +{ + int sent, n; + sent = 0; + while (sent < amount) { + n = SSL_read(fd, buf+sent, amount - sent); + if (n != -1) { + sent += n; + } + if (n == 0) + return 0; + if (n == -1) { + if (errno != EAGAIN) + return 0; + } + } + return amount; +} + +int +writen(int fd, unsigned char* buf, int amount) +{ + int sent, n; + sent = 0; + while (sent < amount) { + n = write(fd, buf+sent, amount - sent); + if (n != -1) { + sent += n; + } + if (n == -1) { + if (errno != EAGAIN) + return 0; + } + } + return amount; +} + +int +readn(int fd, unsigned char* buf, int amount) +{ + int sent, n; + sent = 0; + while (sent < amount) { + n = read(fd, buf+sent, amount - sent); + if (n != -1) { + sent += n; + } + if (n == 0) + return 0; + if (n == -1) { + if (errno != EAGAIN) + return 0; + } + } + return amount; + +} + +int +send_message(char type, clifd fd, unsigned char* buf, int amount) +{ + unsigned long clen; + int length; + static unsigned char bufor[9000]; + aflog(4, " send_message: ssl:%s zlib:%s length:%d", (TYPE_IS_SSL(type))?"yes":"no", + (TYPE_IS_ZLIB(type))?"yes":"no", amount); + clen = 8995; + length = amount - 5; + if (TYPE_IS_ZLIB(type)) { + memcpy(bufor, buf, 5); + if (amount > 5) { + compress(&bufor[5], &clen, &buf[5], length); + if (clen < length) { + length = clen; + TYPE_SET_COMP(length); + bufor[3] = length >> 8; /* high bits of message length */ + bufor[4] = length; /* low bits of message length */ + addtocg(amount-5 - clen); + } + } + if (TYPE_IS_SSL(type)) { + if (TYPE_IS_COMP(length)) { + return SSL_writen(fd.ssl, bufor, clen+5); + } + else { + return SSL_writen(fd.ssl, buf, amount); + } + } + else { + if (TYPE_IS_COMP(length)) { + return writen(fd.commfd, bufor, clen+5); + } + else { + return writen(fd.commfd, buf, amount); + } + } + } + else { + if (TYPE_IS_SSL(type)) { + return SSL_writen(fd.ssl, buf, amount); + } + else { + return writen(fd.commfd, buf, amount); + } + } +} + +int +get_message(char type, clifd fd, unsigned char* buf, int amount) +{ + int length; + unsigned long elen; + static unsigned char bufor[9000]; + aflog(4, " get_message: ssl:%s zlib:%s length:%d", (TYPE_IS_SSL(type))?"yes":"no", + (TYPE_IS_ZLIB(type))?"yes":"no", amount); + if (amount == -5) { + if (TYPE_IS_SSL(type)) { + return SSL_read(fd.ssl, buf, 5); + } + else { + return read(fd.commfd, buf, 5); + } + } + if (TYPE_IS_ZLIB(type)) { + if (TYPE_IS_SSL(type)) { + length = SSL_readn(fd.ssl, bufor, amount&0xBFFF); + } + else { + length = readn(fd.commfd, bufor, amount&0xBFFF); + } + if (length <= 0) return length; + elen = 8096; + if (TYPE_IS_COMP(amount)) { + uncompress(buf, &elen, bufor, length); + } + else { + memcpy(buf, bufor, length); + elen = length; + } + return elen; + } + else + { + if (TYPE_IS_SSL(type)) { + return SSL_readn(fd.ssl, buf, amount); + } + else { + return readn(fd.commfd, buf, amount); + } + } +} diff --git a/src/network.h b/src/network.h new file mode 100644 index 0000000..401a627 --- /dev/null +++ b/src/network.h @@ -0,0 +1,54 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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_NETWORK_H +#define _JS_NETWORK_H + +#include <stdio.h> +#include <stdlib.h> +#include <strings.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <unistd.h> +#include <pthread.h> +#include <netdb.h> +#include <openssl/ssl.h> + +typedef struct { + int commfd; + SSL* ssl; +} clifd; + +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, char type); /* 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); + +int SSL_writen(SSL* fd, unsigned char* buf, int amount); +int SSL_readn(SSL* fd, unsigned char* buf, int amount); +int writen(int fd, unsigned char* buf, int amount); +int readn(int fd, unsigned char* buf, int amount); + +#endif diff --git a/src/realmnames.c b/src/realmnames.c new file mode 100644 index 0000000..84d9f53 --- /dev/null +++ b/src/realmnames.c @@ -0,0 +1,62 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 <stdio.h> +#include <string.h> +#include "realmnames.h" + +char* +get_realmname(ConfigurationT* config, int realm) +{ + static char realmname[10]; + + if (config->realmtable[realm].realmname == NULL) { + memset(realmname, 0, 10); + sprintf(realmname, "%d", realm); + return realmname; + } + + return config->realmtable[realm].realmname; +} + +int +get_realmnumber(ConfigurationT* config, char* realmname) +{ + int i; + char guard; + + for (i = 0; i < config->size; ++i) { + if (config->realmtable[i].realmname != NULL) { + if (strcmp(realmname, config->realmtable[i].realmname) == 0) { + return i; + } + } + } + + if (sscanf(realmname, "%d%c", &i, &guard) == 1) { + if ((i >= 0) && (i < config->size)) { + if (config->realmtable[i].realmname == NULL) { + return i; + } + } + } + + return -1; +} diff --git a/src/realmnames.h b/src/realmnames.h new file mode 100644 index 0000000..70ad46f --- /dev/null +++ b/src/realmnames.h @@ -0,0 +1,30 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 "activefor.h" + +#ifndef _JS_REALMNAMES_H +#define _JS_REALMNAMES_H + +char* get_realmname(ConfigurationT*, int); +int get_realmnumber(ConfigurationT*, char*); + +#endif + diff --git a/src/remoteadmin.c b/src/remoteadmin.c new file mode 100644 index 0000000..4e777c1 --- /dev/null +++ b/src/remoteadmin.c @@ -0,0 +1,503 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 "remoteadmin.h" + +static char newmessage; + +static int +parse_cmd(unsigned char* buff, int* ret) +{ + int i, j, state; + char cmd[31]; + + i = j = state = 0; + newmessage = 1; + while (buff[i] != 0) { + if (state == 1) { + if (isspace(buff[i])) { + break; + } + else { + if (j == 30) { + return 0; + } + cmd[j] = buff[i]; + ++j; + } + } + if (state == 0) { + if (!isspace(buff[i])) { + cmd[j] = buff[i]; + j = 1; + state = 1; + } + } + ++i; + } + if (state == 0) { + return 0; + } + while (isspace(buff[i])) { + ++i; + } + if (buff[i] == '.') { + ++i; + } + (*ret) = i; + cmd[j] = 0; + if (strcmp(cmd, "help") == 0) { return 1; } + if (strcmp(cmd, "lcmd") == 0) { return 2; } + if (strcmp(cmd, "info") == 0) { return 3; } + if (strcmp(cmd, "rshow") == 0) { return 4; } + if (strcmp(cmd, "cshow") == 0) { return 5; } + if (strcmp(cmd, "ushow") == 0) { return 6; } + if (strcmp(cmd, "quit") == 0) { return 7; } + return 0; +} + +static void +send_adm_message(char type, clifd master, unsigned char* buff, unsigned char st) +{ + int n; + if (!newmessage) { + n = strlen((char*) &buff[5]); + } + else { + n = 0; + } + buff[0] = AF_S_ADMIN_CMD; + buff[1] = st; + buff[2] = AF_RA_UNDEFINED; + buff[3] = n >> 8; /* high bits of message length */ + buff[4] = n; /* low bits of message length */ + send_message(type, master, buff, n+5); +} + +static void +add_to_message(unsigned char* buff, const char* format, ...) +{ + va_list ap; + int n; + if (!newmessage) { + n = strlen((char*) &buff[5]); + } + else { + n = 0; + } + newmessage = 0; + va_start(ap, format); + + vsprintf((char*) &buff[5+n], format, ap); + n = strlen((char*) &buff[5]); + sprintf((char*) &buff[5+n], "\n"); + + va_end(ap); +} + +static void +add_uptime_to_message(unsigned char* buff, char* info, time_t period) +{ + int hours, minutes, seconds; + + hours = period/3600; + minutes = (period/60)%60; + seconds = period%60; + + if (hours) { + add_to_message(buff, "%s: %d:%02d:%02d", info, hours, minutes, seconds); + } + else { + add_to_message(buff, "%s: %d:%02d", info, minutes, seconds); + } +} + +int +serve_admin(ConfigurationT* config, int realm, int client, unsigned char* buff) +{ + int length, n, i, j, ret; + time_t now, tmp; + char type = config->realmtable[realm].type | TYPE_SSL | TYPE_ZLIB; + clifd master = config->realmtable[realm].raclitable[client].cliconn; + + length = buff[3]; + length = length << 8; + length += buff[4]; /* this is length of message */ + + time(&now); + + switch (buff[1]) { + case AF_RA_CMD: { + n = get_message(type, master, buff, length); + buff[n] = 0; + aflog(2, " realm[%s]: admin: message length = %d [%s]", + get_realmname(config, realm), n, buff); + switch (parse_cmd(buff, &ret)) { + case 1: { /* help */ + add_to_message(buff, AF_VER("AFSERVER")); + add_to_message(buff, "\nValid commands are:"); + add_to_message(buff, " help display help"); + add_to_message(buff, " lcmd lists available commands"); + add_to_message(buff, " info prints info about server"); + add_to_message(buff, " rshow display realms"); + add_to_message(buff, " cshow X display clients in X realm"); + add_to_message(buff, " ushow X display users in X realm"); + add_to_message(buff, " quit quit connection"); + send_adm_message(type, master, buff, AF_RA_STATUS_OK); + break; + } + case 2: { /* lcmd */ + add_to_message(buff, "help"); + add_to_message(buff, "lcmd"); + add_to_message(buff, "info"); + add_to_message(buff, "rshow"); + add_to_message(buff, "cshow"); + add_to_message(buff, "ushow"); + add_to_message(buff, "quit"); + send_adm_message(type, master, buff, AF_RA_STATUS_OK); + break; + } + case 3: { /* info */ + add_to_message(buff, AF_VER("Version:")); + add_to_message(buff, "Realms: %d", config->size); + add_to_message(buff, "Certificate: %s", config->certif); + add_to_message(buff, "Key: %s", config->keys); + if (config->logging) { + add_to_message(buff, "logfile: %s (verbosity:%d)", + config->logfnam, config->logging); + } + else { + add_to_message(buff, "no logfile"); + } + if (config->socklogging) { + add_to_message(buff, "logsocket: %s (verbosity:%d)", + config->logsport, config->socklogging); + } + else { + add_to_message(buff, "no logsocket"); + } + tmp = now - config->starttime; + add_uptime_to_message(buff, "Uptime", tmp); + add_to_message(buff, "Cg: %ld B", getcg()); + send_adm_message(type, master, buff, AF_RA_STATUS_OK); + break; + } + case 4: { /* rshow */ + for (i = 0; i < config->size; ++i) { + add_to_message(buff, "\nRealm[%s]:", get_realmname(config, i)); + add_to_message(buff, "hostname: %s", config->realmtable[i].hostname); + add_to_message(buff, "users: %d (max: %d)", + config->realmtable[i].usercon, config->realmtable[i].usernum); + add_to_message(buff, "clients: %d (max: %d)", + config->realmtable[i].clicon-config->realmtable[i].raclicon, + config->realmtable[i].clinum); + add_to_message(buff, "raclients: %d (max: %d)", + config->realmtable[i].raclicon, config->realmtable[i].raclinum); + add_to_message(buff, "users per client: %s", config->realmtable[i].usrpcli); + add_to_message(buff, "user-client pairs: %d", + config->realmtable[i].usrclinum); + for (j = 0; j < config->realmtable[i].usrclinum; ++j) { + add_to_message(buff, " pair[%d]: listenport: %s, manageport: %s", j, + config->realmtable[i].usrclitable[j].lisportnum, + config->realmtable[i].usrclitable[j].manportnum); + } + add_to_message(buff, "climode: %s", config->realmtable[i].clim); + add_to_message(buff, "timeout: %s", config->realmtable[i].timeout); + add_to_message(buff, "baseport: %s", config->realmtable[i].baseport ? + "yes" : "no"); + add_to_message(buff, "ssl: %s, zlib: %s, mode: %s", + (TYPE_IS_SSL(config->realmtable[i].type))?"yes":"no", + (TYPE_IS_ZLIB(config->realmtable[i].type))?"yes":"no", + (TYPE_IS_TCP(config->realmtable[i].type))?"tcp":"udp"); + } + send_adm_message(type, master, buff, AF_RA_STATUS_OK); + break; + } + case 5: { /* cshow*/ + n = get_realmnumber(config, (char*) &buff[ret]); + if ((n >= 0) && (n < config->size)) { + for (i = 0; i < config->realmtable[n].clinum; ++i) { + if (config->realmtable[n].clitable[i].ready) { + add_to_message(buff, "\nClient[%s]:", + get_clientname(&(config->realmtable[n]), i)); + switch (config->realmtable[n].clitable[i].ready) { + case 1: { + add_to_message(buff, "state: ssl handshake"); + break; + } + case 2: { + add_to_message(buff, "state: authorization"); + break; + } + case 3: { + add_to_message(buff, "state: running"); + break; + } + default: { + add_to_message(buff, "state: unknown"); + } + } + add_to_message(buff, "users: %d (max: %d)", + config->realmtable[n].clitable[i].usercon, + config->realmtable[n].clitable[i].usernum); + add_to_message(buff, "user-client pair: %d", + config->realmtable[n].clitable[i].whatusrcli); + tmp = now - config->realmtable[n].clitable[i].connecttime; + add_uptime_to_message(buff, "Connection time", tmp); + add_to_message(buff, "Id: %s", + (config->realmtable[n].clitable[i].clientid == NULL)?"": + config->realmtable[n].clitable[i].clientid); + add_to_message(buff, "IP: %s, port: %s", + config->realmtable[n].clitable[i].namebuf, + config->realmtable[n].clitable[i].portbuf); + } + } + send_adm_message(type, master, buff, AF_RA_STATUS_OK); + break; + } + add_to_message(buff, "Wrong realm name"); + send_adm_message(type, master, buff, AF_RA_FAILED); + break; + } + case 6: { /* ushow */ + n = get_realmnumber(config, (char*) &buff[ret]); + if ((n >= 0) && (n < config->size)) { + for (i = 0; i < config->realmtable[n].usernum; ++i) { + if (config->realmtable[n].contable[i].state != S_STATE_CLEAR) { + add_to_message(buff, "\nUser[%d]:", + get_username(&(config->realmtable[n]), i)); + switch (config->realmtable[n].contable[i].state) { + case S_STATE_CLOSING: { + add_to_message(buff, "state: closing"); + break; + } + case S_STATE_OPENING: { + add_to_message(buff, "state: opening"); + break; + } + case S_STATE_OPEN: { + add_to_message(buff, "state: running"); + break; + } + case S_STATE_STOPPED: { + add_to_message(buff, "state: stopped"); + break; + } + default: { + add_to_message(buff, "state: unknown"); + } + } + add_to_message(buff, "connected to: Client[%s]", + get_clientname(&(config->realmtable[n]), + config->realmtable[n].contable[i].whatcli)); + tmp = now - config->realmtable[n].contable[i].connecttime; + add_uptime_to_message(buff, "Connection time", tmp); + add_to_message(buff, "IP: %s, port: %s", + config->realmtable[n].contable[i].namebuf, + config->realmtable[n].contable[i].portbuf); + } + } + send_adm_message(type, master, buff, AF_RA_STATUS_OK); + break; + } + add_to_message(buff, "Wrong realm name"); + send_adm_message(type, master, buff, AF_RA_FAILED); + break; + } + case 7: { /* quit */ + aflog(1, " realm[%s]: Client[%s] (ra): commfd: CLOSED", + get_realmname(config, realm), + get_raclientname(&(config->realmtable[realm]), client)); + send_adm_message(type, master, buff, AF_RA_KICKED); + return 1; + } + default: { + aflog(2, " realm[%s]: admin: cmd ignored", get_realmname(config, realm)); + send_adm_message(type, master, buff, AF_RA_UNDEFINED); + } + } + break; + } + case AF_RA_REPEAT: { + break; + } + default: { + aflog(1, "Unrecognized message from remote admin --> closing"); + return 1; + } + } + return 0; +} + +int +client_admin(char type, clifd master, unsigned char* buff, int connectfd, char* id) +{ + fd_set rset, allset; + int maxfdp1, n, length, infd; + FILE *outfp, *infp; + + buff[0] = AF_S_ADMIN_LOGIN; + send_message(type, master, buff, 5); + buff[0] = 0; + get_message(type, master, buff, -5); + + if ( buff[0] == 0 ) { + aflog(0, "Wrong password"); + return 1; + } + if ( buff[0] == AF_S_CANT_OPEN ) { + aflog(0, "Server is full"); + return 1; + } + if ( buff[0] != AF_S_ADMIN_LOGIN ) { + aflog(0, "Incompatible server type or server full"); + return 1; + } + + aflog(1, "CLIENT STARTED mode: remote administration"); + + if (connectfd > 0) { + outfp = fdopen(connectfd, "w"); + if (outfp == NULL) { + aflog(0, "Error in opening file descriptor for writing"); + return 1; + } + infd = connectfd; + } + else { + infd = STDIN_FILENO; + outfp = stdout; + } + infp = fdopen(infd, "r"); + if (infp == NULL) { + aflog(0, "Error in opening file descriptor for reading"); + return 1; + } + + length = buff[3]; + length = length << 8; + length += buff[4]; /* this is length of message */ + n = get_message(type, master, buff, length); + buff[n] = 0; + fprintf(outfp, "%s\n", (char*) buff); + fflush(outfp); + + FD_ZERO(&allset); + + FD_SET(master.commfd, &allset); + FD_SET(infd, &allset); + + maxfdp1 = (infd > master.commfd) ? infd+1: master.commfd+1; + + 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); + } + + while (1) { + rset = allset; + select(maxfdp1, &rset, NULL, NULL, NULL); + + if (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) + return 1; + } + if (n == 0) { /* server quits -> we do the same... */ + aflog(0, " SERVER: premature quit --> exiting..."); + return 1; + } + if (buff[0] == AF_S_CLOSING) { + aflog(0, " SERVER: CLOSED -> exiting... cg: %ld bytes", getcg()); + return 0; + } + if (buff[0] != AF_S_ADMIN_CMD) { + aflog(0, " SERVER: wrong message --> exiting"); + return 1; + } + length = buff[3]; + length = length << 8; + length += buff[4]; /* this is length of message */ + + switch (buff[1]) { + case AF_RA_STATUS_OK: { + aflog(1, " SERVER: cmd successful"); + } + case AF_RA_FAILED: { + if (buff[1] == AF_RA_FAILED) { + aflog(1, " SERVER: cmd failed"); + } + } + case AF_RA_UNDEFINED: { + if (buff[1] == AF_RA_UNDEFINED) { + aflog(1, " SERVER: unknown cmd"); + } + n = get_message(type, master, buff, length); + buff[n] = 0; + fprintf(outfp, "%s", (char*) buff); + fflush(outfp); + break; + } + case AF_RA_KICKED: { + aflog(0, " SERVER: kicked us -> exiting... cg: %ld bytes", getcg()); + return 1; + break; + } + default: { + aflog(0, " SERVER: unrecognized message -> exiting... cg: %ld bytes", getcg()); + return 1; + } + } + } + + if (FD_ISSET(infd, &rset)) { + aflog(3, " infd: FD_ISSET"); + if (fgets((char*) &buff[5], 8091, infp) == NULL) { /* client quits --> exiting */ + aflog(0, " CLIENT CLOSED cg: %ld bytes", getcg()); + return 0; + } + n = strlen((char*) &buff[5]); + if ((n > 0) && (buff[n+4] == '\n')) { + --n; + } + buff[0] = AF_S_ADMIN_CMD; + buff[1] = AF_RA_CMD; + buff[2] = AF_RA_UNDEFINED; + buff[3] = n >> 8; /* high bits of message length */ + buff[4] = n; /* low bits of message length */ + send_message(type, master, buff, n+5); + } + } +} diff --git a/src/remoteadmin.h b/src/remoteadmin.h new file mode 100644 index 0000000..cad9c76 --- /dev/null +++ b/src/remoteadmin.h @@ -0,0 +1,49 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 "file.h" +#include "stats.h" +#include "activefor.h" +#include "realmnames.h" +#include "clientnames.h" +#include "usernames.h" +#include "make_ssl_handshake.h" + +#include <openssl/err.h> +#include <string.h> +#include <ctype.h> +#include <stdarg.h> + +#ifndef _JS_REMOTEADMIN_H +#define _JS_REMOTEADMIN_H + +#define AF_RA_UNDEFINED 0 +#define AF_RA_CMD 1 +#define AF_RA_REPEAT 2 +#define AF_RA_STATUS_OK 3 +#define AF_RA_NOT_KNOWN 4 +#define AF_RA_FAILED 5 +#define AF_RA_KICKED 6 + +int serve_admin(ConfigurationT*, int, int, unsigned char*); +int client_admin(char, clifd, unsigned char*, int, char*); + +#endif + diff --git a/src/server_check.c b/src/server_check.c new file mode 100644 index 0000000..94069cc --- /dev/null +++ b/src/server_check.c @@ -0,0 +1,61 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 <stdio.h> +#include <stdlib.h> +#include <limits.h> + +#include "stats.h" + +void +check_value(int* where, char* what, char* info) +{ + char* znak; + long tmp; + if ((tmp = strtol(what, &znak, 10)) >= INT_MAX) { + aflog(0, "%s: %s\n", info, what); + exit(1); + } + if (((*what) == '\0') || (*znak != '\0')) { + aflog(0, "%s: %s\n", info, what); + exit(1); + } + if (tmp <= 0) { + aflog(0, "%s: %d\n", info, *where); + exit(1); + } + (*where) = tmp; +} + +int +check_long(char* text, long* number) +{ + char* tmp; + if (((*number = strtol(text, &tmp, 10)) == LONG_MAX) || (*number == LONG_MIN)) { + return 1; + } + if ((*text != '\0') && (*tmp == '\0')) { + return 0; + } + else { + return 2; + } +} + diff --git a/src/server_check.h b/src/server_check.h new file mode 100644 index 0000000..3877426 --- /dev/null +++ b/src/server_check.h @@ -0,0 +1,28 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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_SERVER_CHECK_H +#define _JS_SERVER_CHECK_H + +void check_value(int* where, char* what, char* info); +int check_long(char* text, long* number); + +#endif + diff --git a/src/server_eval.c b/src/server_eval.c new file mode 100644 index 0000000..d487b01 --- /dev/null +++ b/src/server_eval.c @@ -0,0 +1,44 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 "server_eval.h" + +int +eval_numofcon(RealmT* ptr, int client, int numofcon) +{ + if ((numofcon >= 0) && (numofcon < ptr->clitable[client].usernum)) { + numofcon = ptr->clitable[client].users[numofcon]; + } + else { + numofcon = -1; + } + return numofcon; +} + +int +eval_usernum(ConnectclientT* ptr, int usernum) +{ + int i; + for (i = 0; i < ptr->usernum; ++i) { + if (ptr->users[i] == usernum) + return i; + } + return -1; +} diff --git a/src/server_eval.h b/src/server_eval.h new file mode 100644 index 0000000..ed09e84 --- /dev/null +++ b/src/server_eval.h @@ -0,0 +1,31 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 "file.h" +#include "activefor.h" + +#ifndef _JS_SERVER_EVAL_H +#define _JS_SERVER_EVAL_H + +int eval_numofcon(RealmT*, int, int); +int eval_usernum(ConnectclientT*, int); + +#endif + diff --git a/src/server_find.c b/src/server_find.c new file mode 100644 index 0000000..1d67640 --- /dev/null +++ b/src/server_find.c @@ -0,0 +1,56 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 "server_find.h" + +int +find_client(RealmT* ptr, char mode, int usrclipair) +{ + int i; + switch(mode) { + case 1: { /* fill first client before go to next */ + for (i = 0; i < ptr->clinum; ++i) { + if ((ptr->clitable[i].ready == 3) && (ptr->clitable[i].whatusrcli == usrclipair)) { + if (ptr->clitable[i].usercon < ptr->clitable[i].usernum) { + return i; + } + } + } + break; + } + default: { + return 0; + } + } + return 0; +} + +int +find_usernum(ConnectclientT* ptr, int usernum) +{ + int i; + for (i = 0; i < ptr->usernum; ++i) { + if (ptr->users[i] == -1) { + ptr->users[i] = usernum; + return i; + } + } + return -1; +} diff --git a/src/server_find.h b/src/server_find.h new file mode 100644 index 0000000..36642cc --- /dev/null +++ b/src/server_find.h @@ -0,0 +1,31 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 "activefor.h" +#include "file.h" + +#ifndef _JS_SERVER_FIND_H +#define _JS_SERVER_FIND_H + +int find_client(RealmT*, char, int); +int find_usernum(ConnectclientT*, int); + +#endif + diff --git a/src/server_remove.c b/src/server_remove.c new file mode 100644 index 0000000..de2df66 --- /dev/null +++ b/src/server_remove.c @@ -0,0 +1,84 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 "server_remove.h" + +void +remove_client(RealmT* ptr, int client, fd_set* set, fd_set* wset, int* con) +{ + int i; + if (ptr->clitable[client].ready == 3) { + for (i = 0; i < ptr->usernum; ++i) { + if (ptr->contable[i].whatcli == client) { + if (ptr->contable[i].state != S_STATE_CLEAR) { + ptr->contable[i].state = S_STATE_CLEAR; + FD_CLR(ptr->contable[i].connfd, set); + FD_CLR(ptr->contable[i].connfd, wset); + close(ptr->contable[i].connfd); + ptr->usercon--; + } + } + } + } + for (i=0; i<ptr->clitable[client].usernum; ++i) { + ptr->clitable[client].users[i] = -1; + } + if ((ptr->clinum != client) && (ptr->baseport == 1)) { + close(ptr->clitable[client].listenfd); + FD_CLR(ptr->clitable[client].listenfd, set); + } + if (ptr->clitable[client].clientid) { + free(ptr->clitable[client].clientid); + ptr->clitable[client].clientid = NULL; + } + ptr->clitable[client].usercon = 0; + close(ptr->clitable[client].cliconn.commfd); + FD_CLR(ptr->clitable[client].cliconn.commfd, set); + if (ptr->clitable[client].ready == 2) + (*con)--; + SSL_clear(ptr->clitable[client].cliconn.ssl); + ptr->clitable[client].ready = 0; + ptr->clicon--; +} + +void +remove_raclient(RealmT* ptr, int client, fd_set* set, fd_set* wset, int* con) +{ + int i; + for (i=0; i<ptr->raclitable[client].usernum; ++i) { + ptr->raclitable[client].users[i] = -1; + } + if (ptr->raclitable[client].clientid) { + free(ptr->raclitable[client].clientid); + ptr->raclitable[client].clientid = NULL; + } + ptr->raclitable[client].usercon = 0; + close(ptr->raclitable[client].cliconn.commfd); + FD_CLR(ptr->raclitable[client].cliconn.commfd, set); + if (ptr->raclitable[client].ready == 2) { + (*con)--; + } + SSL_clear(ptr->raclitable[client].cliconn.ssl); + ptr->clicon--; + if (ptr->raclitable[client].ready == 3) { + ptr->raclicon--; + } + ptr->raclitable[client].ready = 0; +} diff --git a/src/server_remove.h b/src/server_remove.h new file mode 100644 index 0000000..363b1cc --- /dev/null +++ b/src/server_remove.h @@ -0,0 +1,30 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 "file.h" + +#ifndef _JS_SERVER_REMOVE_H +#define _JS_SERVER_REMOVE_H + +void remove_client(RealmT*, int, fd_set*, fd_set*, int*); +void remove_raclient(RealmT*, int, fd_set*, fd_set*, int*); + +#endif + diff --git a/src/server_set.c b/src/server_set.c new file mode 100644 index 0000000..c3a0058 --- /dev/null +++ b/src/server_set.c @@ -0,0 +1,34 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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> + +void +set_value(char** dest, char* from, char* def) +{ + if ((*dest) == NULL) { + if (from != NULL) { + (*dest) = from; + } + else { + (*dest) = def; + } + } +} diff --git a/src/server_set.h b/src/server_set.h new file mode 100644 index 0000000..5bd4de5 --- /dev/null +++ b/src/server_set.h @@ -0,0 +1,27 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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_SERVER_SET_H +#define _JS_SERVER_SET_H + +void set_value(char** dest, char* from, char* def); + +#endif + diff --git a/src/stats.c b/src/stats.c new file mode 100644 index 0000000..82e90aa --- /dev/null +++ b/src/stats.c @@ -0,0 +1,127 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 "stats.h" +#include "network.h" +#include <stdio.h> +#include <time.h> +#include <string.h> +#include <stdarg.h> + +static char verlev; +static char loglev; +static char logsocklev; +static FILE* logfd; +static FILE* logsockfd; +static signed long compressgained; +static char* format = "%d.%m.%Y %H:%M:%S"; + +char* +datum(void) +{ + time_t sec; + struct tm* tm; + static char timedat[31]; + time(&sec); + tm = localtime(&sec); + memset(timedat, 0, 31); + strftime(timedat, 30, format, tm); + return timedat; +} + +int +loginit(char verl, char logl, char logsl, const char* logfname, const char* port, char* dateformat) { + int tmpfd; + verlev = loglev = 0; + if (logfd) + fclose(logfd); + logfd = NULL; + logsockfd = NULL; + verlev = verl; + loglev = logl; + logsocklev = logsl; + if (dateformat) + format = dateformat; + if (loglev) { + logfd = fopen(logfname, "a"); + if (logfd == NULL) + return 1; /* logging to a non-opened file? */ + } + if (logsocklev) { + if (ip_connect(&tmpfd, "localhost", port, 1)) + return 2; /* can't connect to localhost:port */ + logsockfd = fdopen(tmpfd, "a"); + if (logsockfd == NULL) + return 3; /* can't create FILE* to log to */ + } + return 0; +} + +void +aflog(char type, const char* format, ...) +{ + va_list ap; + + if ((verlev) || (!type)) + if (type <= verlev) { + printf("[%s] ", datum()); + va_start(ap, format); + vfprintf(stdout, format, ap); + va_end(ap); + printf("\n"); + } + if (loglev) + if (type <= loglev) { + fprintf(logfd, "[%s] ", datum()); + va_start(ap, format); + vfprintf(logfd, format, ap); + va_end(ap); + fprintf(logfd, "\n"); + fflush(logfd); + } + if (logsocklev) + if (type <= logsocklev) { + fprintf(logsockfd, "[%s] ", datum()); + va_start(ap, format); + vfprintf(logsockfd, format, ap); + va_end(ap); + fprintf(logsockfd, "\n"); + fflush(logsockfd); + } + +} + +void +addtocg(int amount) +{ + compressgained += amount; +} + +signed long +getcg(void) +{ + return compressgained; +} + +void +resetcg(void) +{ + compressgained = 0; +} diff --git a/src/stats.h b/src/stats.h new file mode 100644 index 0000000..08838ad --- /dev/null +++ b/src/stats.h @@ -0,0 +1,36 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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_STATS_H +#define _JS_STATS_H + + /* initializing logging routine */ +int loginit(char verlev, char loglev, char logsocklev, const char* logfname, const char* port, char* dateformat); + /* log to a file or|and screen */ +void aflog(char type, const char* format, ...); + /* add amount to compressgained value */ +void addtocg(int amount); + /* reset the compressgained value */ +void resetcg(void); + /* returns the compressgained value */ +signed long getcg(void); + +#endif + diff --git a/src/usernames.c b/src/usernames.c new file mode 100644 index 0000000..3e4b24c --- /dev/null +++ b/src/usernames.c @@ -0,0 +1,41 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 "usernames.h" + +int +get_username(RealmT* pointer, int user) +{ + return pointer->contable[user].userid; +} + +int +get_usernumber(RealmT* pointer, int userid) +{ + int i; + + for (i = 0; i < pointer->usernum; ++i) { + if (userid == pointer->contable[i].userid) { + return i; + } + } + + return -1; +} diff --git a/src/usernames.h b/src/usernames.h new file mode 100644 index 0000000..0d0cb21 --- /dev/null +++ b/src/usernames.h @@ -0,0 +1,30 @@ +/* + * active port forwarder - software for secure forwarding + * Copyright (C) 2003,2004,2005 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 "activefor.h" + +#ifndef _JS_USERNAMES_H +#define _JS_USERNAMES_H + +int get_username(RealmT*, int); +int get_usernumber(RealmT*, int); + +#endif + |