First implementation of tor-fw-helper.

tor-fw-helper is a command-line tool to wrap and abstract various
firewall port-forwarding tools.

This commit matches the state of Jacob's tor-fw-helper branch as of
23 September 2010.

  (commit msg by Nick)
This commit is contained in:
Jacob Appelbaum 2010-04-16 17:45:12 -07:00 committed by Nick Mathewson
parent 3ad43ef75f
commit 9cc76cf005
12 changed files with 762 additions and 2 deletions

6
.gitignore vendored
View File

@ -161,6 +161,12 @@
/src/tools/Makefile /src/tools/Makefile
/src/tools/Makefile.in /src/tools/Makefile.in
# /src/tools/tor-fw-helper/
/src/tools/tor-fw-helper/tor-fw-helper
/src/tools/tor-fw-helper/tor-fw-helper.exe
/src/tools/tor-fw-helper/Makefile
/src/tools/tor-fw-helper/Makefile.in
# /src/win32/ # /src/win32/
/src/win32/Makefile /src/win32/Makefile
/src/win32/Makefile.in /src/win32/Makefile.in

View File

@ -68,7 +68,8 @@ check-spaces:
src/common/*.h \ src/common/*.h \
src/common/[^asO]*.c src/common/address.c \ src/common/[^asO]*.c src/common/address.c \
src/or/[^e]*.[ch] src/or/eventdns_tor.h \ src/or/[^e]*.[ch] src/or/eventdns_tor.h \
src/test/test*.[ch] src/tools/*.[ch] src/test/test*.[ch] src/tools/*.[ch] \
src/tools/tor-fw-helper/*.[ch]
check-docs: check-docs:
./contrib/checkOptionDocs.pl ./contrib/checkOptionDocs.pl

View File

@ -59,6 +59,24 @@ AC_ARG_ENABLE(asciidoc,
*) AC_MSG_ERROR(bad value for --disable-asciidoc) ;; *) AC_MSG_ERROR(bad value for --disable-asciidoc) ;;
esac], [asciidoc=true]) esac], [asciidoc=true])
# By default, we're not ready to ship a NAT-PMP aware Tor
AC_ARG_ENABLE(nat-pmp,
AS_HELP_STRING(--enable-nat-pmp, enable NAT-PMP support),
[case "${enableval}" in
yes) natpmp=true ;;
no) natpmp=false ;;
* ) AC_MSG_ERROR(bad value for --enable-nat-pmp) ;;
esac], [natpmp=false])
# By default, we're not ready to ship a UPnP aware Tor
AC_ARG_ENABLE(upnp,
AS_HELP_STRING(--enable-upnp, enable UPnP support),
[case "${enableval}" in
yes) upnp=true ;;
no) upnp=false ;;
* ) AC_MSG_ERROR(bad value for --enable-upnp) ;;
esac], [upnp=false])
AC_ARG_ENABLE(threads, AC_ARG_ENABLE(threads,
AS_HELP_STRING(--disable-threads, disable multi-threading support)) AS_HELP_STRING(--disable-threads, disable multi-threading support))
@ -135,6 +153,8 @@ AC_PATH_PROG([A2X], [a2x], none)
AM_CONDITIONAL(USE_ASCIIDOC, test x$asciidoc = xtrue) AM_CONDITIONAL(USE_ASCIIDOC, test x$asciidoc = xtrue)
AM_CONDITIONAL(USE_FW_HELPER, test x$natpmp = xtrue || x$upnp = xtrue)
AC_PATH_PROG([SHA1SUM], [sha1sum], none) AC_PATH_PROG([SHA1SUM], [sha1sum], none)
AC_PATH_PROG([OPENSSL], [openssl], none) AC_PATH_PROG([OPENSSL], [openssl], none)
@ -440,6 +460,44 @@ AC_SUBST(TOR_ZLIB_LIBS)
dnl Make sure to enable support for large off_t if available. dnl Make sure to enable support for large off_t if available.
dnl ------------------------------------------------------
dnl Where do you live, libnatpmp? And how do we call you?
dnl There are no packages for Debian or Redhat as of this patch
if test "$natpmp" = "true"; then
AC_DEFINE(NAT_PMP, 1, [Define to 1 if we are building with nat-pmp.])
TOR_SEARCH_LIBRARY(libnatpmp, $trylibnatpmpdir, [-lnatpmp],
[#include <natpmp.h>],
[#include <natpmp.h>],
[ int r;
natpmp_t natpmp;
natpmpresp_t response;
r = initnatpmp(&natpmp);],
[printf("initnatpmp() returned %d (%s)\n", r, r?"FAILED":"SUCCESS");
exit(0);],
[--with-libnatpmp-dir],
[/usr/lib/])
fi
dnl ------------------------------------------------------
dnl Where do you live, libminiupnpc? And how do we call you?
dnl There are no packages for Debian or Redhat as of this patch
if test "$upnp" = "true"; then
AC_DEFINE(UPNP, 1, [Define to 1 if we are building with UPnP.])
TOR_SEARCH_LIBRARY(libminiupnpc, $trylibminiupnpcdir, [-lminiupnpc],
[#include <miniupnpc/miniwget.h>
#include <miniupnpc/miniupnpc.h>
#include <miniupnpc/upnpcommands.h>],
[void upnpDiscover(int delay, const char * multicastif,
const char * minissdpdsock, int sameport);],
[upnpDiscover(1, 0, 0, 0); exit(0);],
[--with-libminiupnpc-dir],
[/usr/lib/])
fi
AC_SYS_LARGEFILE AC_SYS_LARGEFILE
AC_CHECK_HEADERS(unistd.h string.h signal.h sys/stat.h sys/types.h fcntl.h sys/fcntl.h sys/time.h errno.h assert.h time.h, , AC_MSG_WARN(Some headers were not found, compilation may fail. If compilation succeeds, please send your orconfig.h to the developers so we can fix this warning.)) AC_CHECK_HEADERS(unistd.h string.h signal.h sys/stat.h sys/types.h fcntl.h sys/fcntl.h sys/time.h errno.h assert.h time.h, , AC_MSG_WARN(Some headers were not found, compilation may fail. If compilation succeeds, please send your orconfig.h to the developers so we can fix this warning.))
@ -967,7 +1025,7 @@ fi
CPPFLAGS="$CPPFLAGS $TOR_CPPFLAGS_libevent $TOR_CPPFLAGS_openssl $TOR_CPPFLAGS_zlib" CPPFLAGS="$CPPFLAGS $TOR_CPPFLAGS_libevent $TOR_CPPFLAGS_openssl $TOR_CPPFLAGS_zlib"
AC_CONFIG_FILES([Makefile tor.spec Doxyfile contrib/tor.sh contrib/torctl contrib/torify contrib/tor.logrotate contrib/Makefile contrib/osx/Makefile contrib/osx/TorBundleDesc.plist contrib/osx/TorBundleInfo.plist contrib/osx/TorDesc.plist contrib/osx/TorInfo.plist contrib/osx/TorStartupDesc.plist src/config/torrc.sample src/Makefile doc/Makefile doc/spec/Makefile src/config/Makefile src/common/Makefile src/or/Makefile src/test/Makefile src/win32/Makefile src/tools/Makefile contrib/suse/Makefile contrib/suse/tor.sh]) AC_CONFIG_FILES([Makefile tor.spec Doxyfile contrib/tor.sh contrib/torctl contrib/torify contrib/tor.logrotate contrib/Makefile contrib/osx/Makefile contrib/osx/TorBundleDesc.plist contrib/osx/TorBundleInfo.plist contrib/osx/TorDesc.plist contrib/osx/TorInfo.plist contrib/osx/TorStartupDesc.plist src/config/torrc.sample src/Makefile doc/Makefile doc/spec/Makefile src/config/Makefile src/common/Makefile src/or/Makefile src/test/Makefile src/win32/Makefile src/tools/Makefile src/tools/tor-fw-helper/Makefile contrib/suse/Makefile contrib/suse/tor.sh])
AC_OUTPUT AC_OUTPUT
if test -x /usr/bin/perl && test -x ./contrib/updateVersions.pl ; then if test -x /usr/bin/perl && test -x ./contrib/updateVersions.pl ; then

View File

@ -0,0 +1,44 @@
Tor's (little) Firewall Helper specification
Jacob Appelbaum
0. Preface
This document describes issues faced by Tor users who are behind NAT devices
and wish to share their resources with the rest of the Tor network. It also
explains a possible solution for some NAT devices.
1. Overview
Tor users often wish to relay traffic for the Tor network and their upstream
firewall thwarts their attempted generosity. Automatic port forwarding
configuration for many consumer NAT devices is often available with two common
protocols NAT-PMP[0] and UPnP[1].
2. Implementation
tor-fw-helper is a program that implements basic port forwarding requests; it
may be used alone or called from Tor itself.
2.1 Output format
When tor-fw-helper has completed the requested action successfully, it will
report the following message to standard output:
tor-fw-helper: SUCCESS
If tor-fw-helper was unable to complete the requested action successfully, it
will report the following message to standard error:
tor-fw-helper: FAILURE
All informational messages are printed to standard output; all error messages
are printed to standard error.
3. Security Concerns
It is probably best to hand configure port forwarding and in the process, we
suggest disabling NAT-PMP and/or UPnP.
[0] http://en.wikipedia.org/wiki/NAT_Port_Mapping_Protocol
[1] http://en.wikipedia.org/wiki/Universal_Plug_and_Play

View File

@ -16,3 +16,7 @@ tor_checkkey_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
@TOR_LDFLAGS_libevent@ @TOR_LDFLAGS_libevent@
tor_checkkey_LDADD = ../common/libor.a ../common/libor-crypto.a \ tor_checkkey_LDADD = ../common/libor.a ../common/libor-crypto.a \
-lm @TOR_ZLIB_LIBS@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ -lm @TOR_ZLIB_LIBS@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@
SUBDIRS = tor-fw-helper
DIST_SUBDIRS = tor-fw-helper

View File

@ -0,0 +1,12 @@
if USE_FW_HELPER
bin_PROGRAMS = tor-fw-helper
else
bin_PROGRAMS =
endif
tor_fw_helper_SOURCES = tor-fw-helper.c \
tor-fw-helper-natpmp.c tor-fw-helper-upnp.c
tor_fw_helper_INCLUDES = tor-fw-helper.h tor-fw-helper-natpmp.h tor-fw-helper-upnp.h
tor_fw_helper_LDFLAGS = @TOR_LDFLAGS_libnatpmp@ @TOR_LDFLAGS_libminiupnpc@
tor_fw_helper_LDADD = -lnatpmp -lminiupnpc ../../common/libor.a @TOR_LIB_WS32@
tor_fw_helper_CPPFLAGS = @TOR_CPPFLAGS_libnatpmp@ @TOR_CPPFLAGS_libminiupnpc@

View File

@ -0,0 +1,142 @@
/* Copyright (c) 2010, Jacob Appelbaum, Steven J. Murdoch.
* Copyright (c) 2010, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include "tor-fw-helper.h"
#include "tor-fw-helper-natpmp.h"
int
tor_natpmp_add_tcp_mapping(tor_fw_options_t *tor_fw_options)
{
int r = 0;
int x = 0;
int sav_errno;
int protocol = NATPMP_PROTOCOL_TCP;
int lease = NATPMP_DEFAULT_LEASE;
natpmp_t natpmp;
natpmpresp_t response;
fd_set fds;
struct timeval timeout;
if (tor_fw_options->verbose)
fprintf(stdout, "V: natpmp init...\n");
initnatpmp(&natpmp);
if (tor_fw_options->verbose)
fprintf(stdout, "V: sending natpmp portmapping request...\n");
r = sendnewportmappingrequest(&natpmp, protocol,
tor_fw_options->internal_port,
tor_fw_options->external_port,
lease);
fprintf(stdout, "tor-fw-helper: NAT-PMP sendnewportmappingrequest returned"
" %d (%s)\n", r, r==12?"SUCCESS":"FAILED");
do {
FD_ZERO(&fds);
FD_SET(natpmp.s, &fds);
getnatpmprequesttimeout(&natpmp, &timeout);
select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
if (tor_fw_options->verbose)
fprintf(stdout, "V: attempting to readnatpmpreponseorretry...\n");
r = readnatpmpresponseorretry(&natpmp, &response);
sav_errno = errno;
if (r<0 && r!=NATPMP_TRYAGAIN)
{
fprintf(stderr, "E: readnatpmpresponseorretry failed %d\n", r);
fprintf(stderr, "E: errno=%d '%s'\n", sav_errno,
strerror(sav_errno));
}
} while ( r == NATPMP_TRYAGAIN );
if (r == NATPMP_SUCCESS) {
fprintf(stdout, "tor-fw-helper: NAT-PMP mapped public port %hu to"
" localport %hu liftime %u\n",
response.pnu.newportmapping.mappedpublicport,
response.pnu.newportmapping.privateport,
response.pnu.newportmapping.lifetime);
}
x = closenatpmp(&natpmp);
if (tor_fw_options->verbose)
fprintf(stdout, "V: closing natpmp socket: %d\n", x);
return r;
}
int
tor_natpmp_fetch_public_ip(tor_fw_options_t *tor_fw_options)
{
int r = 0;
int x = 0;
int sav_errno;
natpmp_t natpmp;
natpmpresp_t response;
struct timeval timeout;
fd_set fds;
r = initnatpmp(&natpmp);
if (tor_fw_options->verbose)
fprintf(stdout, "V: NAT-PMP init: %d\n", r);
r = sendpublicaddressrequest(&natpmp);
fprintf(stdout, "tor-fw-helper: NAT-PMP sendpublicaddressrequest returned"
" %d (%s)\n", r, r==2?"SUCCESS":"FAILED");
do {
FD_ZERO(&fds);
FD_SET(natpmp.s, &fds);
getnatpmprequesttimeout(&natpmp, &timeout);
select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
if (tor_fw_options->verbose)
fprintf(stdout, "V: NAT-PMP attempting to read reponse...\n");
r = readnatpmpresponseorretry(&natpmp, &response);
sav_errno = errno;
if (tor_fw_options->verbose)
fprintf(stdout, "V: NAT-PMP readnatpmpresponseorretry returned"
" %d\n", r);
if ( r < 0 && r != NATPMP_TRYAGAIN)
{
fprintf(stderr, "E: NAT-PMP readnatpmpresponseorretry failed %d\n",
r);
fprintf(stderr, "E: NAT-PMP errno=%d '%s'\n", sav_errno,
strerror(sav_errno));
}
} while ( r == NATPMP_TRYAGAIN );
if (r != 0)
{
fprintf(stderr, "E: NAT-PMP It appears that something went wrong:"
" %d\n", r);
return r;
}
fprintf(stdout, "tor-fw-helper: ExternalIPAddress = %s\n",
inet_ntoa(response.pnu.publicaddress.addr));
x = closenatpmp(&natpmp);
if (tor_fw_options->verbose)
{
fprintf(stdout, "V: result = %u\n", r);
fprintf(stdout, "V: type = %u\n", response.type);
fprintf(stdout, "V: resultcode = %u\n", response.resultcode);
fprintf(stdout, "V: epoch = %u\n", response.epoch);
fprintf(stdout, "V: closing natpmp result: %d\n", r);
}
return r;
}

View File

@ -0,0 +1,18 @@
/* Copyright (c) 2010, Jacob Appelbaum, Steven J. Murdoch.
* Copyright (c) 2010, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef _TOR_FW_HELPER_NATPMP_H
#define _TOR_FW_HELPER_NATPMP_H
#include <natpmp.h>
#define NATPMP_DEFAULT_LEASE 3600
#define NATPMP_SUCCESS 0
int tor_natpmp_add_tcp_mapping(tor_fw_options_t *tor_fw_options);
int tor_natpmp_fetch_public_ip(tor_fw_options_t *tor_fw_options);
#endif

View File

@ -0,0 +1,125 @@
/* Copyright (c) 2010, Jacob Appelbaum, Steven J. Murdoch.
* Copyright (c) 2010, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "tor-fw-helper.h"
#include "tor-fw-helper-upnp.h"
#define UPNP_DISCOVER_TIMEOUT 2000
/* Description of the port mapping in the UPnP table */
#define UPNP_DESC "Tor relay"
#define UPNP_ERR_SUCCESS 0
#define UPNP_ERR_NODEVICESFOUND 1
#define UPNP_ERR_NOIGDFOUND 2
#define UPNP_ERR_ADDPORTMAPPING 3
#define UPNP_ERR_GETPORTMAPPING 4
#define UPNP_ERR_DELPORTMAPPING 5
#define UPNP_ERR_GETEXTERNALIP 6
#define UPNP_ERR_INVAL 7
#define UPNP_ERR_OTHER 8
#define UPNP_SUCCESS 1
int
tor_upnp_init(miniupnpc_state_t *state)
{
struct UPNPDev *devlist;
int r;
memset(&(state->urls), 0, sizeof(struct UPNPUrls));
memset(&(state->data), 0, sizeof(struct IGDdatas));
devlist = upnpDiscover(UPNP_DISCOVER_TIMEOUT, NULL, NULL, 0);
if (NULL == devlist) {
fprintf(stderr, "E: upnpDiscover returned: NULL\n");
return UPNP_ERR_NODEVICESFOUND;
}
r = UPNP_GetValidIGD(devlist, &(state->urls), &(state->data),
state->lanaddr, UPNP_LANADDR_SZ);
fprintf(stdout, "tor-fw-helper: UPnP GetValidIGD returned: %d (%s)\n", r,
r==UPNP_SUCCESS?"SUCCESS":"FAILED");
freeUPNPDevlist(devlist);
if (r != 1 && r != 2)
return UPNP_ERR_NOIGDFOUND;
state->init = 1;
return UPNP_ERR_SUCCESS;
}
int
tor_upnp_cleanup(miniupnpc_state_t *state)
{
if (state->init)
FreeUPNPUrls(&(state->urls));
state->init = 0;
return UPNP_ERR_SUCCESS;
}
int
tor_upnp_fetch_public_ip(miniupnpc_state_t *state)
{
int r;
char externalIPAddress[16];
if (!state->init) {
r = tor_upnp_init(state);
if (r != UPNP_ERR_SUCCESS)
return r;
}
r = UPNP_GetExternalIPAddress(state->urls.controlURL,
state->data.first.servicetype,
externalIPAddress);
if (r != UPNPCOMMAND_SUCCESS)
goto err;
if (externalIPAddress[0]) {
fprintf(stdout, "tor-fw-helper: ExternalIPAddress = %s\n",
externalIPAddress); tor_upnp_cleanup(state);
return UPNP_ERR_SUCCESS;
} else
goto err;
err:
tor_upnp_cleanup(state);
return UPNP_ERR_GETEXTERNALIP;
}
int
tor_upnp_add_tcp_mapping(miniupnpc_state_t *state,
uint16_t internal_port, uint16_t external_port)
{
int r;
char internal_port_str[6];
char external_port_str[6];
if (!state->init) {
r = tor_upnp_init(state);
if (r != UPNP_ERR_SUCCESS)
return r;
}
snprintf(internal_port_str, sizeof(internal_port_str),
"%d", internal_port);
snprintf(external_port_str, sizeof(external_port_str),
"%d", external_port);
r = UPNP_AddPortMapping(state->urls.controlURL,
state->data.first.servicetype,
external_port_str, internal_port_str,
state->lanaddr, UPNP_DESC, "TCP", 0);
if (r != UPNPCOMMAND_SUCCESS)
return UPNP_ERR_ADDPORTMAPPING;
return UPNP_ERR_SUCCESS;
}

View File

@ -0,0 +1,32 @@
/* Copyright (c) 2010, Jacob Appelbaum, Steven J. Murdoch.
* Copyright (c) 2010, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef _TOR_FW_HELPER_UPNP_H
#define _TOR_FW_HELPER_UPNP_H
#include <miniupnpc/miniwget.h>
#include <miniupnpc/miniupnpc.h>
#include <miniupnpc/upnpcommands.h>
#include <miniupnpc/upnperrors.h>
#define UPNP_LANADDR_SZ 64
typedef struct miniupnpc_state_t {
struct UPNPUrls urls;
struct IGDdatas data;
char lanaddr[UPNP_LANADDR_SZ];
int init;
} miniupnpc_state_t;
int tor_upnp_init(miniupnpc_state_t *state);
int tor_upnp_cleanup(miniupnpc_state_t *state);
int tor_upnp_fetch_public_ip(miniupnpc_state_t *state);
int tor_upnp_add_tcp_mapping(miniupnpc_state_t *state,
uint16_t internal_port, uint16_t external_port);
#endif

View File

@ -0,0 +1,285 @@
/* Copyright (c) 2010, Jacob Appelbaum, Steven J. Murdoch.
* Copyright (c) 2010, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/*
* tor-fw-helper is a tool for opening firewalls with NAT-PMP and UPnP; this
* tool is designed to be called by hand or by Tor by way of a exec() at a
* later date.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <getopt.h>
#include <time.h>
#include "orconfig.h"
#include "tor-fw-helper.h"
#include "tor-fw-helper-natpmp.h"
#include "tor-fw-helper-upnp.h"
static void
usage(void)
{
fprintf(stderr, "tor-fw-helper usage:\n"
" [-h|--help]\n"
" [-T|--Test]\n"
" [-v|--verbose]\n"
" [-g|--fetch-public-ip]\n"
" -i|--internal-or-port [TCP port]\n"
" [-e|--external-or-port [TCP port]]\n"
" [-d|--internal-dir-port [TCP port]\n"
" [-p|--external-dir-port [TCP port]]]\n");
}
/* Log commandline options */
static int
test_commandline_options(int argc, char **argv)
{
int i, retval;
FILE *logfile;
time_t now;
/* Open the log file */
logfile = fopen("tor-fw-helper.log", "a");
if (NULL == logfile)
return -1;
/* Send all commandline arguments to the file */
now = time(NULL);
retval = fprintf(logfile, "START: %s\n", ctime(&now));
for (i = 0; i < argc; i++) {
retval = fprintf(logfile, "ARG: %d: %s\n", i, argv[i]);
if (retval < 0)
goto error;
retval = fprintf(stdout, "ARG: %d: %s\n", i, argv[i]);
if (retval < 0)
goto error;
}
now = time(NULL);
retval = fprintf(logfile, "END: %s\n", ctime(&now));
/* Close and clean up */
retval = fclose(logfile);
return retval;
/* If there was an error during writing */
error:
fclose(logfile);
return -1;
}
static void
tor_fw_fetch_public_ip(tor_fw_options_t *tor_fw_options,
miniupnpc_state_t *miniupnpc_state)
{
int r = 0;
r = tor_natpmp_fetch_public_ip(tor_fw_options);
if (tor_fw_options->verbose)
fprintf(stdout, "V: Attempts to fetch public ip (natpmp) resulted in: "
"%d\n", r);
if (r == 0)
tor_fw_options->public_ip_status = 1;
r = tor_upnp_fetch_public_ip(miniupnpc_state);
if (tor_fw_options->verbose)
fprintf(stdout, "V: Attempts to fetch public ip (upnp) resulted in: "
"%d\n", r);
if (r == 0)
tor_fw_options->public_ip_status = 1;
}
static void
tor_fw_add_or_port(tor_fw_options_t *tor_fw_options, miniupnpc_state_t
*miniupnpc_state)
{
int r = 0;
tor_fw_options->internal_port = tor_fw_options->private_or_port;
tor_fw_options->external_port = tor_fw_options->public_or_port;
r = tor_natpmp_add_tcp_mapping(tor_fw_options);
fprintf(stdout, "tor-fw-helper: Attempts to add ORPort mapping (natpmp)"
"resulted in: %d\n", r);
if (r == 0)
tor_fw_options->nat_pmp_status = 1;
r = tor_upnp_add_tcp_mapping(miniupnpc_state,
tor_fw_options->private_or_port,
tor_fw_options->public_or_port);
fprintf(stdout, "tor-fw-helper: Attempts to add ORPort mapping (upnp)"
"resulted in: %d\n", r);
if (r == 0)
tor_fw_options->upnp_status = 1;
}
static void
tor_fw_add_dir_port(tor_fw_options_t *tor_fw_options, miniupnpc_state_t
*miniupnpc_state)
{
int r = 0;
tor_fw_options->internal_port = tor_fw_options->private_dir_port;
tor_fw_options->external_port = tor_fw_options->public_dir_port;
r = tor_natpmp_add_tcp_mapping(tor_fw_options);
fprintf(stdout, "V: Attempts to add DirPort mapping (natpmp) resulted in: "
"%d\n", r);
r = tor_upnp_add_tcp_mapping(miniupnpc_state,
tor_fw_options->private_or_port,
tor_fw_options->public_or_port);
fprintf(stdout, "V: Attempts to add DirPort mapping (upnp) resulted in: "
"%d\n",
r);
}
int
main(int argc, char **argv)
{
int r = 0;
int c = 0;
tor_fw_options_t tor_fw_options = {0,0,0,0,0,0,0,0,0,0,0,0,0};
miniupnpc_state_t miniupnpc_state;
miniupnpc_state.init = 0;
while (1)
{
int option_index = 0;
static struct option long_options[] =
{
{"verbose", 0, 0, 'v'},
{"help", 0, 0, 'h'},
{"internal-or-port", 1, 0, 'i'},
{"external-or-port", 1, 0, 'e'},
{"internal-dir-port", 1, 0, 'd'},
{"external-dir-port", 1, 0, 'p'},
{"fetch-public-ip", 0, 0, 'g'},
{"test-commandline", 0, 0, 'T'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, "vhi:e:d:p:gT",
long_options, &option_index);
if (c == -1)
break;
switch (c)
{
case 'v': tor_fw_options.verbose = 1; break;
case 'h': tor_fw_options.help = 1; usage(); exit(1); break;
case 'i': sscanf(optarg, "%hu", &tor_fw_options.private_or_port);
break;
case 'e': sscanf(optarg, "%hu", &tor_fw_options.public_or_port);
break;
case 'd': sscanf(optarg, "%hu", &tor_fw_options.private_dir_port);
break;
case 'p': sscanf(optarg, "%hu", &tor_fw_options.public_dir_port);
break;
case 'g': tor_fw_options.fetch_public_ip = 1; break;
case 'T': tor_fw_options.test_commandline = 1; break;
case '?': break;
default : fprintf(stderr, "Unknown option!\n"); usage(); exit(1);
}
}
if (tor_fw_options.verbose)
{
fprintf(stderr, "V: tor-fw-helper version %s\n"
"V: We were called with the following arguments:\n"
"V: verbose = %d, help = %d, pub or port = %u, "
"priv or port = %u\n"
"V: pub dir port = %u, priv dir port = %u\n"
"V: fetch_public_ip = %u\n",
tor_fw_version, tor_fw_options.verbose, tor_fw_options.help,
tor_fw_options.private_or_port, tor_fw_options.public_or_port,
tor_fw_options.private_dir_port, tor_fw_options.public_dir_port,
tor_fw_options.fetch_public_ip);
}
if (tor_fw_options.test_commandline) {
return test_commandline_options(argc, argv);
}
/* At the very least, we require an ORPort;
Given a private ORPort, we can ask for a mapping that matches the port
externally.
*/
if (!tor_fw_options.private_or_port && !tor_fw_options.fetch_public_ip)
{
fprintf(stderr, "E: We require an ORPort or fetch_public_ip"
" request!\n");
usage();
exit(1);
} else {
/* When we only have one ORPort, internal/external are
set to be the same.*/
if (!tor_fw_options.public_or_port && tor_fw_options.private_or_port)
{
if (tor_fw_options.verbose)
fprintf(stdout, "V: We're setting public_or_port = "
"private_or_port.\n");
tor_fw_options.public_or_port = tor_fw_options.private_or_port;
}
}
if (!tor_fw_options.private_dir_port)
{
if (tor_fw_options.verbose)
fprintf(stdout, "V: We have no DirPort; no hole punching for "
"DirPorts\n");
} else {
/* When we only have one DirPort, internal/external are
set to be the same.*/
if (!tor_fw_options.public_dir_port && tor_fw_options.private_dir_port)
{
if (tor_fw_options.verbose)
fprintf(stdout, "V: We're setting public_or_port = "
"private_or_port.\n");
tor_fw_options.public_dir_port = tor_fw_options.private_dir_port;
}
}
if (tor_fw_options.verbose)
{
fprintf(stdout, "V: pub or port = %u, priv or port = %u\n"
"V: pub dir port = %u, priv dir port = %u\n",
tor_fw_options.private_or_port, tor_fw_options.public_or_port,
tor_fw_options.private_dir_port,
tor_fw_options.public_dir_port);
}
if (tor_fw_options.fetch_public_ip)
{
tor_fw_fetch_public_ip(&tor_fw_options, &miniupnpc_state);
}
if (tor_fw_options.private_or_port)
{
tor_fw_add_or_port(&tor_fw_options, &miniupnpc_state);
}
if (tor_fw_options.private_dir_port)
{
tor_fw_add_dir_port(&tor_fw_options, &miniupnpc_state);
}
r = (((tor_fw_options.nat_pmp_status | tor_fw_options.upnp_status)
|tor_fw_options.public_ip_status));
if (r > 0)
{
fprintf(stdout, "tor-fw-helper: SUCCESS\n");
} else {
fprintf(stderr, "tor-fw-helper: FAILURE\n");
}
exit(r);
}

View File

@ -0,0 +1,33 @@
/* Copyright (c) 2010, Jacob Appelbaum, Steven J. Murdoch.
* Copyright (c) 2010, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef _TOR_FW_HELPER_H
#define _TOR_FW_HELPER_H
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <time.h>
#define tor_fw_version "0.1"
typedef struct {
int verbose;
int help;
int test_commandline;
uint16_t private_dir_port;
uint16_t private_or_port;
uint16_t public_dir_port;
uint16_t public_or_port;
uint16_t internal_port;
uint16_t external_port;
int fetch_public_ip;
int nat_pmp_status;
int upnp_status;
int public_ip_status;
} tor_fw_options_t;
#endif