GCC_STACK_PROTECT_LIB
AX_LIBRARY_NET
+AX_ARG_OPENSSL
AX_ARG_ENABLE_ASSERT
AX_ARG_ENABLE_WARNINGS
protocol = HTTP:3128;
protocol = HTTP:6588;
+ protocol = HTTPS:443;
+ protocol = HTTPS:8443;
+
/*
* SOCKS4/5 - well known proxy protocols, probably the second most
* common for insecure proxies, also offers transparent two way TCP
*/
protocol = HTTPPOST:80;
+ protocol = HTTPSPOST:443;
+ protocol = HTTPSPOST:8443;
+
/*
* IP address this scanner will bind to. Use this if you need your scans to
* come FROM a particular interface on the machine you run HOPM from.
--- /dev/null
+AC_DEFUN([AX_ARG_OPENSSL], [
+AC_ARG_ENABLE(openssl,
+[ --enable-openssl[=DIR] Enable LibreSSL/OpenSSL support (DIR optional).
+ --disable-openssl Disable LibreSSL/OpenSSL support. ],
+[ cf_enable_openssl=$enableval ],
+[ cf_enable_openssl="auto" ])
+AC_MSG_CHECKING([for LibreSSL/OpenSSL])
+if test "$cf_enable_openssl" != "no"; then
+ cf_openssl_basedir=""
+ if test "$cf_enable_openssl" != "auto" &&
+ test "$cf_enable_openssl" != "yes"; then
+ dnl Support for --enable-openssl=/some/place
+ cf_openssl_basedir="${cf_enable_openssl}"
+ else
+ dnl Do the auto-probe here. Check some common directory paths.
+ for dirs in /usr/local/ssl /usr/pkg /usr/local /usr/lib /usr/lib/ssl\
+ /opt /opt/openssl /usr/local/openssl; do
+ if test -f "${dirs}/include/openssl/opensslv.h"; then
+ cf_openssl_basedir="${dirs}"
+ break
+ fi
+ done
+ unset dirs
+ fi
+
+ dnl Now check cf_openssl_found to see if we found anything.
+ if test ! -z "$cf_openssl_basedir"; then
+ if test -f "${cf_openssl_basedir}/include/openssl/opensslv.h"; then
+ CPPFLAGS="-I${cf_openssl_basedir}/include $CPPFLAGS"
+ LDFLAGS="-L${cf_openssl_basedir}/lib $LDFLAGS"
+ else
+ dnl OpenSSL wasn't found in the directory specified. Naughty
+ dnl administrator...
+ cf_openssl_basedir=""
+ fi
+ else
+ dnl Check for stock FreeBSD 4.x and 5.x systems, since their files
+ dnl are in /usr/include and /usr/lib. In this case, we don't want to
+ dnl change INCLUDES or LIBS, but still want to enable OpenSSL.
+ dnl We can't do this check above, because some people want two versions
+ dnl of OpenSSL installed (stock FreeBSD 4.x/5.x and /usr/local/ssl)
+ dnl and they want /usr/local/ssl to have preference.
+ if test -f "/usr/include/openssl/opensslv.h"; then
+ cf_openssl_basedir="/usr"
+ fi
+ fi
+
+ dnl If we have a basedir defined, then everything is okay. Otherwise,
+ dnl we have a problem.
+ if test ! -z "$cf_openssl_basedir"; then
+ AC_MSG_RESULT([$cf_openssl_basedir])
+ cf_enable_openssl="yes"
+ else
+ AC_MSG_RESULT([not found. Please check your path.])
+ cf_enable_openssl="no"
+ fi
+ unset cf_openssl_basedir
+else
+ dnl If --disable-openssl was specified
+ AC_MSG_RESULT([disabled])
+fi
+
+AS_IF([test "$cf_enable_openssl" != "no"],
+ [AC_MSG_CHECKING(for LibreSSL or OpenSSL 0.9.8o and above)
+ AC_RUN_IFELSE([
+ AC_LANG_PROGRAM([
+ #include <openssl/opensslv.h>
+ #include <stdlib.h>],
+ [[ exit(!(OPENSSL_VERSION_NUMBER >= 0x009080ffL)); ]])],
+ [cf_openssl_version_ok=yes],
+ [cf_openssl_version_ok=no],
+ [cf_openssl_version_ok=no])
+
+ AS_IF([test "$cf_openssl_version_ok" = "yes"],
+ [AC_MSG_RESULT(found)
+
+ AC_CHECK_LIB(crypto, RSA_free)
+ AS_IF([test "$ac_cv_lib_crypto_RSA_free" = "yes"],
+ [AC_CHECK_LIB(ssl, SSL_connect)])
+ ],[AC_MSG_RESULT(no - LibreSSL/OpenSSL support disabled)
+ cf_enable_openssl="no"])])
+
+AM_CONDITIONAL(ENABLE_SSL, [test "$ac_cv_lib_ssl_SSL_connect" = yes])
+])
return PROTOCOLTYPE;
}
+HTTPS {
+ yylval.number = OPM_TYPE_HTTPS;
+ return PROTOCOLTYPE;
+ }
+
+HTTPSPOST {
+ yylval.number = OPM_TYPE_HTTPSPOST;
+ return PROTOCOLTYPE;
+ }
+
SOCKS4 {
yylval.number = OPM_TYPE_SOCKS4;
return PROTOCOLTYPE;
#include <unistd.h>
#include <string.h>
#include <poll.h>
+#ifdef HAVE_LIBCRYPTO
+#include <openssl/ssl.h>
+#endif
static OPM_PROTOCOL_CONFIG_T *libopm_protocol_config_create(void);
static void libopm_do_connect(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
static void libopm_do_readready(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
+static int libopm_do_readready_tls(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
static void libopm_do_writeready(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
static void libopm_do_hup(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
static void libopm_do_read(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
*/
static OPM_PROTOCOL_T OPM_PROTOCOLS[] =
{
- { OPM_TYPE_HTTP, libopm_proxy_http_write, NULL },
- { OPM_TYPE_SOCKS4, libopm_proxy_socks4_write, NULL },
- { OPM_TYPE_SOCKS5, libopm_proxy_socks5_write, NULL },
- { OPM_TYPE_ROUTER, libopm_proxy_router_write, NULL },
- { OPM_TYPE_WINGATE, libopm_proxy_wingate_write, NULL },
- { OPM_TYPE_HTTPPOST, libopm_proxy_httppost_write, NULL },
- { OPM_TYPE_DREAMBOX, libopm_proxy_dreambox_write, NULL }
+ { OPM_TYPE_HTTP, libopm_proxy_http_write, NULL, 0 },
+ { OPM_TYPE_SOCKS4, libopm_proxy_socks4_write, NULL, 0 },
+ { OPM_TYPE_SOCKS5, libopm_proxy_socks5_write, NULL, 0 },
+ { OPM_TYPE_ROUTER, libopm_proxy_router_write, NULL, 0 },
+ { OPM_TYPE_WINGATE, libopm_proxy_wingate_write, NULL, 0 },
+ { OPM_TYPE_HTTPPOST, libopm_proxy_httppost_write, NULL, 0 },
+ { OPM_TYPE_DREAMBOX, libopm_proxy_dreambox_write, NULL, 0 },
+ { OPM_TYPE_HTTPS, libopm_proxy_https_write, libopm_do_readready_tls, 1 },
+ { OPM_TYPE_HTTPSPOST, libopm_proxy_httpspost_write, libopm_do_readready_tls, 1 }
};
/* opm_create
{
if (type == OPM_PROTOCOLS[i].type)
{
+#ifndef HAVE_LIBCRYPTO
+ if (OPM_PROTOCOLS[i].use_tls)
+ return OPM_ERR_BADPROTOCOL;
+#endif
protocol_config = libopm_protocol_config_create();
protocol_config->type = &OPM_PROTOCOLS[i];
protocol_config->port = port;
{
if (type == OPM_PROTOCOLS[i].type)
{
+#ifndef HAVE_LIBCRYPTO
+ if (OPM_PROTOCOLS[i].use_tls)
+ return OPM_ERR_BADPROTOCOL;
+#endif
protocol_config = libopm_protocol_config_create();
protocol_config->type = &OPM_PROTOCOLS[i];
protocol_config->port = port;
OPM_SCAN_T *ret;
OPM_CONNECTION_T *conn;
OPM_NODE_T *node, *p;
+#ifdef HAVE_LIBCRYPTO
+ static int tls_init = 0;
+ static SSL_CTX *ctx_client;
+
+ if (!tls_init)
+ {
+ tls_init = 1;
+ SSLeay_add_ssl_algorithms();
+
+ ctx_client = SSL_CTX_new(SSLv23_client_method());
+ if (!ctx_client)
+ exit(EXIT_FAILURE);
+ }
+#endif
ret = xcalloc(sizeof(*ret));
ret->remote = remote;
conn->protocol = ((OPM_PROTOCOL_CONFIG_T *)p->data)->type;
conn->port = ((OPM_PROTOCOL_CONFIG_T *)p->data)->port;
+#ifdef HAVE_LIBCRYPTO
+ if (conn->protocol->use_tls)
+ /* SSL_new does only fail if OOM in which case HOPM exits anyway */
+ conn->tls_handle = SSL_new(ctx_client);
+#endif
+
node = libopm_node_create(conn);
libopm_list_add(ret->connections, node);
}
conn->protocol = ((OPM_PROTOCOL_CONFIG_T *)p->data)->type;
conn->port = ((OPM_PROTOCOL_CONFIG_T *)p->data)->port;
+#ifdef HAVE_LIBCRYPTO
+ if (conn->protocol->use_tls)
+ /* SSL_new does only fail if OOM in which case HOPM exits anyway */
+ conn->tls_handle = SSL_new(ctx_client);
+#endif
+
node = libopm_node_create(conn);
libopm_list_add(ret->connections, node);
}
if (conn->state == OPM_STATE_CLOSED)
{
+#ifdef HAVE_LIBCRYPTO
+ if (conn->protocol->use_tls)
+ {
+ SSL_set_shutdown(conn->tls_handle, SSL_RECEIVED_SHUTDOWN);
+ if (!SSL_shutdown(conn->tls_handle))
+ SSL_shutdown(conn->tls_handle);
+ SSL_free(conn->tls_handle);
+ }
+#endif
if (conn->fd > 0)
close(conn->fd);
if (((present - conn->creation) >= timeout) && conn->state != OPM_STATE_UNESTABLISHED)
{
+#ifdef HAVE_LIBCRYPTO
+ if (conn->protocol->use_tls)
+ {
+ SSL_set_shutdown(conn->tls_handle, SSL_RECEIVED_SHUTDOWN);
+ if (!SSL_shutdown(conn->tls_handle))
+ SSL_shutdown(conn->tls_handle);
+ SSL_free(conn->tls_handle);
+ }
+#endif
close(conn->fd);
scanner->fd_use--;
connect(conn->fd, (struct sockaddr *)addr, sizeof(*addr));
+#ifdef HAVE_LIBCRYPTO
+ if (conn->protocol->use_tls)
+ SSL_set_fd(conn->tls_handle, conn->fd);
+#endif
+
conn->state = OPM_STATE_ESTABLISHED;
time(&conn->creation); /* Stamp creation time, for timeout */
}
}
}
+static int
+libopm_do_readready_tls(OPM_T *scanner, OPM_SCAN_T *scan, OPM_CONNECTION_T *conn)
+{
+#ifdef HAVE_LIBCRYPTO
+ int max_read, length;
+ char readbuf[LIBOPM_TLS_RECORD_SIZE];
+
+ if (!SSL_is_init_finished(conn->tls_handle))
+ return 0;
+
+ if ((length = SSL_read(conn->tls_handle, readbuf, sizeof(readbuf))) <= 0)
+ {
+ switch (SSL_get_error(conn->tls_handle, length))
+ {
+ /* TBD: possibly could recover here from some errors */
+ default:
+ libopm_do_hup(scanner, scan, conn);
+ return 0;
+ }
+ }
+
+ max_read = *(int *)libopm_config(scanner->config, OPM_CONFIG_MAX_READ);
+
+ for (const char *p = readbuf, *end = readbuf + length; p < end; ++p)
+ {
+ conn->bytes_read++;
+
+ if (conn->bytes_read >= max_read)
+ {
+ libopm_do_callback(scanner, libopm_setup_remote(scan->remote, conn), OPM_CALLBACK_ERROR, OPM_ERR_MAX_READ);
+ conn->state = OPM_STATE_CLOSED;
+ return 0;
+ }
+
+ if (*p == '\0' || *p == '\r')
+ continue;
+
+ if (*p == '\n')
+ {
+ conn->readbuf[conn->readlen] = '\0';
+ conn->readlen = 0;
+
+ libopm_do_read(scanner, scan, conn);
+
+ if (conn->state == OPM_STATE_CLOSED)
+ return 0;
+
+ continue;
+ }
+
+ if (conn->readlen < READBUFLEN)
+ conn->readbuf[++(conn->readlen) - 1] = *p; /* -1 to pad for null term */
+ }
+#endif
+ return 0;
+}
+
/* do_readready
*
* Remote connection is read ready, read the data into a buffer and check it against
{
OPM_PROTOCOL_T *protocol;
+#ifdef HAVE_LIBCRYPTO
+ if (conn->protocol->use_tls)
+ {
+ if (!SSL_is_init_finished(conn->tls_handle))
+ {
+ SSL_connect(conn->tls_handle);
+ return;
+ }
+ }
+#endif
+
protocol = conn->protocol;
/* Call write function for specific protocol */
#define CBLEN 5 /* Number of callback functions */
#define READBUFLEN 128 /* Size of conn->readbuf */
#define SENDBUFLEN 512 /* Size of sendbuffer in proxy.c */
+#define LIBOPM_TLS_RECORD_SIZE 16384
typedef struct _OPM_SCAN OPM_SCAN_T;
typedef struct _OPM_CONNECTION OPM_CONNECTION_T;
unsigned short int readlen; /* Length of readbuf */
unsigned short int state; /* State of connection */
time_t creation; /* When this connection was established */
+ void *tls_handle; /* SSL structure created by SSL_new() */
};
struct _OPM_PROTOCOL_CONFIG
int type; /* Protocol type */
OPM_PROXYWRITE_T *write_function; /* Write function handler for this protocol */
OPM_PROXYREAD_T *read_function; /* Read function handler for this protocol */
+ int use_tls; /* TLS/SSL-enabled protocol such as HTTPS */
};
#endif /* LIBOPM_H */
#define OPM_TYPE_ROUTER 5
#define OPM_TYPE_HTTPPOST 6
#define OPM_TYPE_DREAMBOX 7
+#define OPM_TYPE_HTTPS 8
+#define OPM_TYPE_HTTPSPOST 9
+
/* States */
#define OPM_STATE_UNESTABLISHED 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#ifdef HAVE_LIBCRYPTO
+#include <openssl/ssl.h>
+#endif
#include "inet.h"
#include "config.h"
return OPM_SUCCESS;
}
+
+int
+libopm_proxy_https_write(OPM_T *scanner, OPM_SCAN_T *scan, OPM_CONNECTION_T *conn)
+{
+#ifdef HAVE_LIBCRYPTO
+ size_t len = snprintf(SENDBUF, SENDBUFLEN, "CONNECT %s:%d HTTP/1.0\r\n\r\n",
+ (char *)libopm_config(scanner->config, OPM_CONFIG_SCAN_IP),
+ *(int *)libopm_config(scanner->config, OPM_CONFIG_SCAN_PORT));
+
+ SSL_write(conn->tls_handle, SENDBUF, len);
+
+ /* extra linefeed required for MikroTik HttpProxy, must be separate send() */
+ SSL_write(conn->tls_handle, "\r\n", 2);
+#endif
+ return OPM_SUCCESS;
+}
+
+/*
+ * HTTPS POST Scanning
+ *
+ */
+int
+libopm_proxy_httpspost_write(OPM_T *scanner, OPM_SCAN_T *scan, OPM_CONNECTION_T *conn)
+{
+#ifdef HAVE_LIBCRYPTO
+ size_t len;
+ int scan_port;
+ char *scan_ip;
+
+ scan_ip = (char *)libopm_config(scanner->config, OPM_CONFIG_SCAN_IP);
+ scan_port = *(int *)libopm_config(scanner->config, OPM_CONFIG_SCAN_PORT);
+
+ len = snprintf(SENDBUF, SENDBUFLEN,
+ "POST http://%s:%d/ HTTP/1.0\r\n"
+ "Content-type: text/plain\r\n"
+ "Content-length: 5\r\n\r\n"
+ "quit\r\n\r\n", scan_ip, scan_port);
+
+ SSL_write(conn->tls_handle, SENDBUF, len);
+#endif
+ return OPM_SUCCESS;
+}
extern int libopm_proxy_router_write(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
extern int libopm_proxy_httppost_write(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
extern int libopm_proxy_dreambox_write(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
+extern int libopm_proxy_https_write(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
+extern int libopm_proxy_httpspost_write(OPM_T *, OPM_SCAN_T *, OPM_CONNECTION_T *);
#endif /* PROXY_H */
static const char *undef = "undefined";
static const struct protocol_assoc protocols[] =
{
- { OPM_TYPE_HTTP, "HTTP" },
- { OPM_TYPE_HTTPPOST, "HTTPPOST" },
- { OPM_TYPE_SOCKS4, "SOCKS4" },
- { OPM_TYPE_SOCKS5, "SOCKS5" },
- { OPM_TYPE_WINGATE, "WINGATE" },
- { OPM_TYPE_ROUTER, "ROUTER" },
- { OPM_TYPE_DREAMBOX, "DREAMBOX" }
+ { OPM_TYPE_HTTP, "HTTP" },
+ { OPM_TYPE_HTTPPOST, "HTTPPOST" },
+ { OPM_TYPE_SOCKS4, "SOCKS4" },
+ { OPM_TYPE_SOCKS5, "SOCKS5" },
+ { OPM_TYPE_WINGATE, "WINGATE" },
+ { OPM_TYPE_ROUTER, "ROUTER" },
+ { OPM_TYPE_HTTPS, "HTTPS" },
+ { OPM_TYPE_HTTPSPOST, "HTTPSPOST" },
+ { OPM_TYPE_DREAMBOX, "DREAMBOX" }
};
for (unsigned int i = 0; i < (sizeof(protocols) / sizeof(struct protocol_assoc)); ++i)
static struct StatsHash STATS_PROXIES[] =
{
- { OPM_TYPE_HTTP, 0, "HTTP" },
- { OPM_TYPE_HTTPPOST, 0, "HTTPPOST" },
- { OPM_TYPE_SOCKS4, 0, "SOCKS4" },
- { OPM_TYPE_SOCKS5, 0, "SOCKS5" },
- { OPM_TYPE_ROUTER, 0, "ROUTER" },
- { OPM_TYPE_WINGATE, 0, "WINGATE" },
- { OPM_TYPE_DREAMBOX, 0, "DREAMBOX" },
+ { OPM_TYPE_HTTP, 0, "HTTP" },
+ { OPM_TYPE_HTTPPOST, 0, "HTTPPOST" },
+#ifdef HAVE_LIBCRYPTO
+ { OPM_TYPE_HTTPS, 0, "HTTPS" },
+ { OPM_TYPE_HTTPSPOST, 0, "HTTPSPOST" },
+#endif
+ { OPM_TYPE_SOCKS4, 0, "SOCKS4" },
+ { OPM_TYPE_SOCKS5, 0, "SOCKS5" },
+ { OPM_TYPE_ROUTER, 0, "ROUTER" },
+ { OPM_TYPE_WINGATE, 0, "WINGATE" },
+ { OPM_TYPE_DREAMBOX, 0, "DREAMBOX" },
{ 0, 0, NULL }
};