summaryrefslogtreecommitdiff
path: root/src/client_reverse_udp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/client_reverse_udp.c')
-rw-r--r--src/client_reverse_udp.c213
1 files changed, 213 insertions, 0 deletions
diff --git a/src/client_reverse_udp.c b/src/client_reverse_udp.c
new file mode 100644
index 0000000..882a6f9
--- /dev/null
+++ b/src/client_reverse_udp.c
@@ -0,0 +1,213 @@
+/*
+ * active port forwarder - software for secure forwarding
+ * Copyright (C) 2003-2007 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 "client_reverse_udp.h"
+
+#include <stdlib.h>
+
+/*
+ * Function name: initialize_client_reverse_udp
+ * Description: Initializes the realm for reverse udp connection.
+ * Arguments: cr - pointer to ClientRealm structure
+ * Returns: 0 - connection was initialized successfully,
+ * 1 - connection initialization failed.
+ */
+
+int
+initialize_client_reverse_udp(ClientRealm* cr)
+{
+ int tmp;
+ int wanttoexit = (ArOptions_get_arStart(ClientRealm_get_arOptions(cr)) == AR_OPTION_ENABLED) ? 0 : 1;
+ ClientRealm_set_usersLimit(cr, 1);
+ if (ip_connect(&tmp, ClientRealm_get_serverName(cr),
+ ClientRealm_get_managePort(cr),
+ ClientRealm_get_ipFamily(cr), NULL, NULL)) {
+#ifdef AF_INET6
+ aflog(LOG_T_INIT, LOG_I_CRIT,
+ "tcp_connect_%s error for %s, %s",
+ (ClientRealm_get_ipFamily(cr) & 0x02) ?
+ "ipv4" : (ClientRealm_get_ipFamily(cr) & 0x04) ?
+ "ipv6":"unspec", ClientRealm_get_serverName(cr), ClientRealm_get_managePort(cr));
+#else
+ aflog(LOG_T_INIT, LOG_I_CRIT,
+ "tcp_connect error for %s, %s", ClientRealm_get_serverName(cr), ClientRealm_get_managePort(cr));
+#endif
+ if (wanttoexit) {
+ exit(1);
+ }
+ else {
+ return 1;
+ }
+
+ }
+ SslFd_set_fd(ClientRealm_get_masterSslFd(cr), tmp);
+ SslFd_set_ssl(ClientRealm_get_masterSslFd(cr), NULL);
+ return 0;
+}
+
+/*
+ * Function name: client_reverse_udp
+ * Description: This function is responsible for the client part of the reverse udp tunnel.
+ * Arguments: cr - pointer to ClientRealm structure
+ * buff - buffer which will be used for communication
+ * buflength - socket send buffer size
+ */
+
+void
+client_reverse_udp(ClientRealm* cr, unsigned char* buff, int buflength)
+{
+ socklen_t len, addrlen;
+ int maxfdp1, temp, n, length;
+#ifdef HAVE_LINUX_SOCKIOS_H
+ int notsent;
+#endif
+ struct sockaddr* cliaddr;
+ fd_set rset, allset;
+
+ if (ip_listen(&temp, ClientRealm_get_hostName(cr),
+ PortListNode_get_portName(PortList_get_nth(ClientRealm_get_destinationPorts(cr), 0)), &addrlen,
+ ClientRealm_get_ipFamily(cr) & 0xfe)) {
+#ifdef AF_INET6
+ aflog(LOG_T_INIT, LOG_I_DEBUG,
+ "udp_listen_%s error for %s, %s",
+ (ClientRealm_get_ipFamily(cr) & 0x02) ?
+ "ipv4":(ClientRealm_get_ipFamily(cr) & 0x04) ?
+ "ipv6":"unspec", ClientRealm_get_hostName(cr),
+ PortListNode_get_portName(PortList_get_nth(ClientRealm_get_destinationPorts(cr), 0)));
+#else
+ aflog(LOG_T_INIT, LOG_I_DEBUG,
+ "udp_listen error for %s, %s", ClientRealm_get_hostName(cr),
+ PortListNode_get_portName(PortList_get_nth(ClientRealm_get_destinationPorts(cr), 0)));
+#endif
+ exit(1);
+ }
+ ConnectUser_set_connFd(ClientRealm_get_usersTable(cr)[0], temp);
+ cliaddr = malloc(addrlen);
+ FD_ZERO(&allset);
+
+ FD_SET(SslFd_get_fd(ClientRealm_get_masterSslFd(cr)), &allset);
+ maxfdp1 = SslFd_get_fd(ClientRealm_get_masterSslFd(cr)) + 1;
+ maxfdp1 = (maxfdp1 > (ConnectUser_get_connFd(ClientRealm_get_usersTable(cr)[0]) + 1)) ?
+ maxfdp1 : (ConnectUser_get_connFd(ClientRealm_get_usersTable(cr)[0]) + 1);
+ FD_SET(ConnectUser_get_connFd(ClientRealm_get_usersTable(cr)[0]), &allset);
+ aflog(LOG_T_CLIENT, LOG_I_INFO,
+ "CLIENT STARTED mode: udp reverse");
+ for ( ; ; ) {
+ len = 4;
+ if (getsockopt(SslFd_get_fd(ClientRealm_get_masterSslFd(cr)), SOL_SOCKET, SO_SNDBUF, &temp, &len) != -1) {
+ if (temp != buflength) {
+ buflength = temp;
+ aflog(LOG_T_CLIENT, LOG_I_WARNING,
+ "Send buffer size changed...");
+ }
+ }
+ len = addrlen;
+ rset = allset;
+ aflog(LOG_T_MAIN, LOG_I_DEBUG,
+ "select");
+ select(maxfdp1, &rset, NULL, NULL, NULL);
+ aflog(LOG_T_MAIN, LOG_I_DEBUG,
+ "after select...");
+
+ if (FD_ISSET(ConnectUser_get_connFd(ClientRealm_get_usersTable(cr)[0]), &rset)) { /* FD_ISSET CONTABLE[0].CONNFD RSET*/
+ n = recvfrom(ConnectUser_get_connFd(ClientRealm_get_usersTable(cr)[0]), &buff[5], 8091, 0, cliaddr, &len);
+#ifdef HAVE_LINUX_SOCKIOS_H
+# ifdef SIOCOUTQ
+ aflog(LOG_T_MAIN, LOG_I_DDEBUG,
+ "SIOCOUTQ is defined");
+ if (ioctl(SslFd_get_fd(ClientRealm_get_masterSslFd(cr)), SIOCOUTQ, &notsent)) {
+ aflog(LOG_T_CLIENT, LOG_I_CRIT,
+ "ioctl error -> exiting...");
+ exit(1);
+ }
+ if (buflength <= notsent + n + 5) { /* when we can't do this */
+ aflog(LOG_T_CLIENT, LOG_I_INFO,
+ "drop: size:%d, buf:%d, w:%d/%d", n, buflength, notsent, buflength);
+# else
+ aflog(LOG_T_MAIN< LOG_I_DDEBUG,
+ "TIOCOUTQ is defined");
+ if (ioctl(SslFd_get_fd(ClientRealm_get_masterSslFd(cr)), TIOCOUTQ, &notsent)) {
+ aflog(LOG_T_CLIENT, LOG_I_CRIT,
+ "ioctl error -> exiting...");
+ exit(1);
+ }
+ if (notsent <= n + 5) { /* when we can't do this */
+ aflog(LOG_T_CLIENT, LOG_I_INFO,
+ "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(LOG_T_CLIENT, LOG_I_INFO,
+ "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(LOG_T_CLIENT, LOG_I_INFO,
+ "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(SslFd_get_fd(ClientRealm_get_masterSslFd(cr)), buff, n + 5);
+ }
+#ifdef HAVE_LINUX_SOCKIOS_H
+ }
+#endif
+ } /* - FD_ISSET CONTABLE[0].CONNFD RSET */
+
+ if (FD_ISSET(SslFd_get_fd(ClientRealm_get_masterSslFd(cr)), &rset)) { /* FD_ISSET MASTER.COMMFD RSET */
+ n = readn(SslFd_get_fd(ClientRealm_get_masterSslFd(cr)), buff, 5);
+ if (n == 5) {
+ if ((buff[0] != AF_S_MESSAGE) || (buff[1] != AF_S_LOGIN) || (buff[2] != AF_S_MESSAGE)) {
+ aflog(LOG_T_CLIENT, LOG_I_CRIT,
+ "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(SslFd_get_fd(ClientRealm_get_masterSslFd(cr)), buff, length);
+ }
+ else {
+ n = 0;
+ }
+ if (n == 0) { /* server quits -> we do the same... */
+ aflog(LOG_T_CLIENT, LOG_I_CRIT,
+ "premature quit of the server -> exiting...");
+ exit(1);
+ }
+ aflog(LOG_T_CLIENT, LOG_I_INFO,
+ "Sending %d bytes to user (TO:%s)", n, sock_ntop(cliaddr, addrlen, NULL, NULL, 0));
+ sendto(ConnectUser_get_connFd(ClientRealm_get_usersTable(cr)[0]), buff, n, 0, cliaddr, addrlen);
+ } /* - FD_ISSET MASTER.COMMFD RSET */
+ }
+ exit(0); /* we shouldn't get here */
+}