possible problems.
- New file breakage.c handles (so far) missing functions.
- Get rid of some signed/unsigned/const warnings thanks to solaris-cc
- Add autoconf/automake input files, and helper scripts to populate missing
(but auto-generated) files.
This change adds a configure.in and Makefile.am to build everything using
autoconf, automake, and libtool - and adds "gunk" scripts to generate the
various files those things need (and clean then up again after). This means
that "autogunk.sh" needs to be run first on a system with the autotools,
but the resulting directory should be "configure"able and compilable on
systems without those tools.
--- /dev/null
+There are two ways to build this code;
+
+(1) Manually
+
+(2) Using all-singing all-dancing (all-confusing) autotools, ie. autoconf,
+automake, libtool, and their little friends (autoheader, etc).
+
+=================
+Building Manually
+=================
+
+There is a basic "Makefile" in this directory that gets moved out of the way and
+ignored when building with autoconf et al. This Makefile is suitable for
+building tunala on Linux using gcc. Any other platform probably requires some
+tweaking. Here are the various bits you might need to do if you want to build
+this way and the default Makefile isn't sufficient;
+
+* Compiler: Edit the "CC" definition in Makefile
+
+* Headers, features: tunala.h controls what happens in the non-autoconf world.
+ It, by default, assumes the system has *everything* (except autoconf's
+ "config.h") so if a target system is missing something it must define the
+ appropriate "NO_***" symbols in CFLAGS. These include;
+
+ - NO_HAVE_UNISTD_H, NO_HAVE_FCNTL_H, NO_HAVE_LIMITS_H
+ Indicates the compiling system doesn't have (or need) these header files.
+ - NO_HAVE_STRSTR, NO_HAVE_STRTOUL
+ Indicates the compiling system doesn't have these functions. Replacements
+ are compiled and used in breakage.c
+ - NO_HAVE_SELECT, NO_HAVE_SOCKET
+ Pointless symbols - these indicate select() and/or socket() are missing in
+ which case the program won't compile anyway.
+
+ If you want to specify any of these, add them with "-D" prefixed to each in
+ the CFLAGS definition in Makefile.
+
+* Compilation flags: edit DEBUG_FLAGS and/or CFLAGS directly to control the
+ flags passed to the compiler. This can also be used to change the degree of
+ optimisation.
+
+* Linker flags: some systems (eg. Solaris) require extra linker flags such as;
+ -ldl, -lsocket, -lnsl, etc. If unsure, bring up the man page for whichever
+ function is "undefined" when the linker fails - that usually indicates what
+ you need to add. Make changes to the LINK_FLAGS symbol.
+
+* Linker command: if a different linker syntax or even a different program is
+ required to link, edit the linker line directly in the "tunala:" target
+ definition - it currently assumes the "CC" (compiler) program is used to link.
+
+======================
+Building Automagically
+======================
+
+Automagic building is handled courtesy of autoconf, automake, and libtool. There
+is in fact two steps required to build, and only the first has to be done on a
+system with these tools installed (and if I was prepared to bloat out the CVS
+repository, I could store these extra files, but I'm not).
+
+First step: "autogunk.sh"
+-------------------------
+
+The "./autogunk.sh" script will call all the necessary autotool commands to
+create missing files and run automake and autoconf. The result is that a
+"./configure" script should be generated and a "Makefile.in" generated from the
+supplied "Makefile.am". NB: This script also moves the "manual" Makefile (see
+above) out of the way and calls it "Makefile.plain" - the "ungunk" script
+reverses this to leave the directory it was previously.
+
+Once "ungunk" has been run, the resulting directory should be able to build on
+other systems without autoconf, automake, or libtool. Which is what the second
+step describes;
+
+Second step: "./configure"
+--------------------------
+
+The second step is to run the generated "./configure" script to create a
+config.h header for your system and to generate a "Makefile" (generated from
+"Makefile.in") tweaked to compile on your system. This is the standard sort of
+thing you see in GNU packages, for example, and the standard tricks also work.
+Eg. to override "configure"'s choice of compiler, set the CC environment
+variable prior to running configure, eg.
+
+ CC=gcc ./configure
+
+would cause "gcc" to be used even if there is an otherwise preferable (to
+autoconf) native compiler on your system.
+
+*IMPORTANT* It's highly recommended to pass "--disable-shared" to the configure
+script. Otherwise, libtool may elect to build most of the code as a
+shared-library, hide various bits of it in dotted directories and generating
+wrapper scripts in place of the linked binary. The autotool stuff, when "make
+install" is run (which you probably won't want to do for this dinky little
+thing) will unravel all that mess and either install a small executable +
+shared-lib or will install a linked executable. Passing the above flag ensures
+this is all done statically even if the platform supports building and using
+shared-libraries. Ie;
+
+ ./configure --disable-shared
+
+After this run "make" and it should build the "tunala" executable.
+
+Notes
+-----
+
+- Some versions of autoconf (or automake?) generate a Makefile syntax that gives
+ trouble to some "make" programs on some systems (eg. OpenBSD). If this
+ happens, either build 'Manually' (see above) or use "gmake" instead of "make".
+ I don't like this either but like even less the idea of sifting into all the
+ script magic crud that's involved.
+
+- On a solaris system I tried, the "configure" script specified some broken
+ compiler flags in the resulting Makefile that don't even get echoed to
+ stdout/err when the error happens (evil!). If this happens, go into the
+ generated Makefile, find the two affected targets ("%.o:" and "%.lo"), and
+ remove the offending hidden option in the $(COMPILE) line all the sludge after
+ the two first lines of script (ie. after the "echo" and the "COMPILE" lines).
+ NB: This will probably only function if "--disable-shared" was used, otherwise
+ who knows what would result ...
+
CC=gcc
DEBUG_FLAGS=-g -ggdb3 -Wall -Wshadow
INCLUDE_FLAGS=-I$(SSL_INCLUDEDIR)
-CFLAGS=$(DEBUG_FLAGS) $(INCLUDE_FLAGS)
+CFLAGS=$(DEBUG_FLAGS) $(INCLUDE_FLAGS) -DNO_CONFIG_H
COMPILE=$(CC) $(CFLAGS) -c
# Edit, particularly the "-ldl" if not building with "dlfcn" support
LINK_FLAGS=-L$(SSL_LIBDIR) -lssl -lcrypto -ldl
-SRCS=buffer.c cb.c ip.c sm.c tunala.c
-OBJS=buffer.o cb.o ip.o sm.o tunala.o
+SRCS=buffer.c cb.c ip.c sm.c tunala.c breakage.c
+OBJS=buffer.o cb.o ip.o sm.o tunala.o breakage.o
TARGETS=tunala
--- /dev/null
+# Our includes come from the OpenSSL build-tree we're in
+INCLUDES = -I$(top_builddir)/../../include
+
+lib_LTLIBRARIES = libtunala.la
+
+libtunala_la_SOURCES = buffer.c cb.c ip.c sm.c breakage.c
+
+bin_PROGRAMS = tunala
+
+tunala_SOURCES = tunala.c
+tunala_LDADD = libtunala.la -L$(top_builddir)/../.. -lssl -lcrypto
best to try and do so in the makefile (eg. removing the debug flags and adding
optimisation flags).
-Secondly, this code so far has only ever been built and run on Linux - network
-specifics are more than likely to create little glitches on other unixen,
-particularly Solaris in my experience. If you're not on Linux, please read the
-code wherever compilation flares up and try to make the necessary changes -
-usually the man-page associated with the relevant function is enough (eg. all
-that AF_INET/PF_INET stuff, subtlely different parameters to various
-IPv4-related functions like socket(), bind(), fcntl(), etc).
+Secondly, this code has mostly only been tested on Linux. However, some
+autoconf/etc support has been added and the code has been compiled on openbsd
+and solaris using that.
Thirdly, if you are Win32, you probably need to do some *major* rewriting of
ip.c to stand a hope in hell. Good luck, and please mail me the diff if you do
this, otherwise I will take a look at another time. It can certainly be done,
but it's very non-POSIXy.
-Type make.
+See the INSTALL document for details on building.
Now, if you don't have an executable "tunala" compiled, go back to "First,...".
Rinse and repeat.
-cert A-server.pem -server 1 -out_totals -v_peer -v_strict
Now if you open another console and "telnet localhost 8080", you should be
-tunneled through to the telnet service on your local machine. Feel free to
-experiment :-)
+tunneled through to the telnet service on your local machine (if it's running -
+you could change it to port "22" and tunnel ssh instead if you so desired). When
+you logout of the telnet session, the tunnel should cleanly shutdown and show
+you some traffic stats in both consoles. Feel free to experiment. :-)
Notes:
--- /dev/null
+#!/bin/sh
+
+# This script tries to follow the "GNU way" w.r.t. the autobits.
+# This does of course generate a number of irritating files.
+# Try to get over it (I am getting there myself).
+
+# This should generate any missing crud, and then run autoconf which should turn
+# configure.in into a "./configure" script and "Makefile.am" into a
+# "Makefile.in". Then running "./configure" should turn "Makefile.in" into
+# "Makefile" and should generate the config.h containing your systems various
+# settings. I know ... what a hassle ...
+
+# Also, sometimes these autobits things generate bizarre output (looking like
+# errors). So I direct everything "elsewhere" ...
+
+(aclocal
+autoheader
+libtoolize --copy --force
+automake --foreign --add-missing --copy
+autoconf) 1> /dev/null 2>&1
+
+# Move the "no-autotools" Makefile out of the way
+if test ! -f Makefile.plain; then
+ mv Makefile Makefile.plain
+fi
--- /dev/null
+#!/bin/sh
+
+# This script tries to clean up as much as is possible from whatever diabolical
+# mess has been left in the directory thanks to autoconf, automake, and their
+# friends.
+
+if test -f Makefile; then
+ make distclean
+ rm -f Makefile
+fi
+
+if test -f Makefile.plain; then
+ mv Makefile.plain Makefile
+fi
+
+rm -f aclocal.m4 config.* configure install-sh \
+ missing mkinstalldirs stamp-h.* Makefile.in \
+ ltconfig ltmain.sh
--- /dev/null
+#include "tunala.h"
+
+int int_strtoul(const char *str, unsigned long *val)
+{
+#ifdef HAVE_STRTOUL
+ char *tmp;
+ unsigned long ret = strtoul(str, &tmp, 10);
+ if((str == tmp) || (*tmp != '\0'))
+ /* The value didn't parse cleanly */
+ return 0;
+ if(ret == ULONG_MAX)
+ /* We hit a limit */
+ return 0;
+ *val = ret;
+ return 1;
+#else
+ char buf[2];
+ unsigned long ret = 0;
+ buf[1] = '\0';
+ if(str == '\0')
+ /* An empty string ... */
+ return 0;
+ while(*str != '\0') {
+ /* We have to multiply 'ret' by 10 before absorbing the next
+ * digit. If this will overflow, catch it now. */
+ if(ret && (((ULONG_MAX + 10) / ret) < 10))
+ return 0;
+ ret *= 10;
+ if(!isdigit(*str))
+ return 0;
+ buf[0] = *str;
+ ret += atoi(buf);
+ str++;
+ }
+ *val = ret;
+ return 1;
+#endif
+}
+
+#ifndef HAVE_STRSTR
+char *int_strstr(const char *haystack, const char *needle)
+{
+ const char *sub_haystack = haystack, *sub_needle = needle;
+ unsigned int offset = 0;
+ if(!needle)
+ return haystack;
+ if(!haystack)
+ return NULL;
+ while((*sub_haystack != '\0') && (*sub_needle != '\0')) {
+ if(sub_haystack[offset] == sub_needle) {
+ /* sub_haystack is still a candidate */
+ offset++;
+ sub_needle++;
+ } else {
+ /* sub_haystack is no longer a possibility */
+ sub_haystack++;
+ offset = 0;
+ sub_needle = needle;
+ }
+ }
+ if(*sub_haystack == '\0')
+ /* Found nothing */
+ return NULL;
+ return sub_haystack;
+}
+#endif
--- /dev/null
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(tunala.c)
+AM_CONFIG_HEADER(config.h)
+AM_INIT_AUTOMAKE(tunala, 0.0.1-dev)
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_LIBTOOL
+AM_PROG_LIBTOOL
+
+dnl Checks for libraries.
+AC_CHECK_LIB(dl, dlopen)
+AC_CHECK_LIB(socket, socket)
+AC_CHECK_LIB(nsl, gethostbyname)
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h limits.h unistd.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+
+dnl Checks for library functions.
+AC_CHECK_FUNCS(strstr strtoul)
+AC_CHECK_FUNCS(select socket)
+AC_CHECK_FUNCS(dlopen)
+
+AC_OUTPUT(Makefile)
return 1;
}
-int ip_create_listener_split(const unsigned char *ip, unsigned short port)
+int ip_create_listener_split(const char *ip, unsigned short port)
{
struct sockaddr_in in_addr;
int fd = -1;
memcpy(&in_addr.sin_addr.s_addr, ip, 4);
in_addr.sin_port = htons(port);
/* Bind to the required port/address/interface */
- if(bind(fd, &in_addr, sizeof(struct sockaddr_in)) != 0)
+ if(bind(fd, (struct sockaddr *)&in_addr, sizeof(struct sockaddr_in)) != 0)
goto err;
/* Start "listening" */
if(listen(fd, IP_LISTENER_BACKLOG) != 0)
return -1;
}
-int ip_create_connection_split(const unsigned char *ip, unsigned short port)
+int ip_create_connection_split(const char *ip, unsigned short port)
{
struct sockaddr_in in_addr;
int flags, fd = -1;
memcpy(&in_addr.sin_addr.s_addr, ip, 4);
in_addr.sin_port = htons(port);
/* Start a connect (non-blocking, in all likelihood) */
- if((connect(fd, &in_addr, sizeof(struct sockaddr_in)) != 0) &&
+ if((connect(fd, (struct sockaddr *)&in_addr,
+ sizeof(struct sockaddr_in)) != 0) &&
(errno != EINPROGRESS))
goto err;
return fd;
return -1;
}
-static unsigned char all_local_ip[] = {0x00,0x00,0x00,0x00};
+static char all_local_ip[] = {0x00,0x00,0x00,0x00};
-int ip_parse_address(const char *address, unsigned char **parsed_ip,
+int ip_parse_address(const char *address, const char **parsed_ip,
unsigned short *parsed_port, int accept_all_ip)
{
char buf[256];
struct hostent *lookup;
unsigned long port;
- char *temp;
const char *ptr = strstr(address, ":");
- unsigned char *ip = all_local_ip;
+ const char *ip = all_local_ip;
if(!ptr) {
/* We assume we're listening on all local interfaces and have
determine_port:
if(strlen(ptr) < 1)
return 0;
- port = strtoul(ptr, &temp, 10);
- if((temp == ptr) || (*temp != '\0') || (port > 65535))
+ if(!int_strtoul(ptr, &port) || (port > 65535))
return 0;
*parsed_ip = ip;
*parsed_port = (unsigned short)port;
int ip_create_listener(const char *address)
{
- unsigned char *ip;
+ const char *ip;
unsigned short port;
if(!ip_parse_address(address, &ip, &port, 1))
int ip_create_connection(const char *address)
{
- unsigned char *ip;
+ const char *ip;
unsigned short port;
if(!ip_parse_address(address, &ip, &port, 0))
* which case *newfd is populated. */
static int selector_get_listener(tunala_selector_t *selector, int fd, int *newfd);
static int tunala_world_new_item(tunala_world_t *world, int fd,
- const unsigned char *ip, unsigned short port, int flipped);
+ const char *ip, unsigned short port, int flipped);
static void tunala_world_del_item(tunala_world_t *world, unsigned int idx);
static int tunala_item_io(tunala_selector_t *selector, tunala_item_t *item);
static int parse_max_tunnels(const char *s, unsigned int *maxtunnels)
{
unsigned long l;
- char *temp;
- l = strtoul(s, &temp, 10);
- if((temp == s) || (*temp != '\0') || (l < 1) || (l > 1024)) {
+ if(!int_strtoul(s, &l) || (l < 1) || (l > 1024)) {
fprintf(stderr, "Error, '%s' is an invalid value for "
"maxtunnels\n", s);
return 0;
static int parse_server_mode(const char *s, int *servermode)
{
unsigned long l;
- char *temp;
- l = strtoul(s, &temp, 10);
- if((temp == s) || (*temp != '\0') || (l > 1)) {
+ if(!int_strtoul(s, &l) || (l > 1)) {
fprintf(stderr, "Error, '%s' is an invalid value for the "
"server mode\n", s);
return 0;
static int parse_verify_level(const char *s, unsigned int *verify_level)
{
unsigned long l;
- char *temp;
- l = strtoul(s, &temp, 10);
- if((temp == s) || (*temp != '\0') || (l > 3)) {
+ if(!int_strtoul(s, &l) || (l > 3)) {
fprintf(stderr, "Error, '%s' is an invalid value for "
"out_verify\n", s);
return 0;
static int parse_verify_depth(const char *s, unsigned int *verify_depth)
{
unsigned long l;
- char *temp;
- l = strtoul(s, &temp, 10);
- if((temp == s) || (*temp != '\0') || (l < 1) || (l > 50)) {
+ if(!int_strtoul(s, &l) || (l < 1) || (l > 50)) {
fprintf(stderr, "Error, '%s' is an invalid value for "
"verify_depth\n", s);
return 0;
int newfd;
tunala_world_t world;
tunala_item_t *t_item;
- unsigned char *proxy_ip;
+ const char *proxy_ip;
unsigned short proxy_port;
/* Overridables */
const char *proxyhost = def_proxyhost;
switch(selector_select(&world.selector)) {
case -1:
fprintf(stderr, "selector_select returned a badness error.\n");
- abort();
+ goto shouldnt_happen;
case 0:
fprintf(stderr, "Warn, selector_select returned 0 - signal??\n");
goto main_loop;
}
goto main_loop;
/* Should never get here */
+shouldnt_happen:
abort();
return 1;
}
if(meth == NULL)
goto err;
if(engine_id) {
+ ENGINE_load_builtin_engines();
if((e = ENGINE_by_id(engine_id)) == NULL) {
fprintf(stderr, "Error obtaining '%s' engine, openssl "
"errors follow\n", engine_id);
}
static int tunala_world_new_item(tunala_world_t *world, int fd,
- const unsigned char *ip, unsigned short port, int flipped)
+ const char *ip, unsigned short port, int flipped)
{
tunala_item_t *item;
int newfd;
#ifndef _TUNALA_H
#define _TUNALA_H
+/* pull in autoconf fluff */
+#ifndef NO_CONFIG_H
+#include "config.h"
+#else
+/* We don't have autoconf, we have to set all of these unless a tweaked Makefile
+ * tells us not to ... */
+/* headers */
+#ifndef NO_HAVE_SELECT
+#define HAVE_SELECT
+#endif
+#ifndef NO_HAVE_SOCKET
+#define HAVE_SOCKET
+#endif
+#ifndef NO_HAVE_UNISTD_H
+#define HAVE_UNISTD_H
+#endif
+#ifndef NO_HAVE_FCNTL_H
+#define HAVE_FCNTL_H
+#endif
+#ifndef NO_HAVE_LIMITS_H
+#define HAVE_LIMITS_H
+#endif
+/* features */
+#ifndef NO_HAVE_STRSTR
+#define HAVE_STRSTR
+#endif
+#ifndef NO_HAVE_STRTOUL
+#define HAVE_STRTOUL
+#endif
+#endif
+
+#if !defined(HAVE_SELECT) || !defined(HAVE_SOCKET)
+#error "can't build without some network basics like select() and socket()"
+#endif
+
+#include <stdlib.h>
#ifndef NO_SYSTEM_H
#include <string.h>
+#ifdef HAVE_UNISTD_H
#include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
#include <fcntl.h>
+#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
#include <netdb.h>
#include <signal.h>
#include <sys/socket.h>
+#include <sys/types.h>
#include <netinet/in.h>
#endif /* !defined(NO_SYSTEM_H) */
/* ip is the 4-byte ip address (eg. 127.0.0.1 is {0x7F,0x00,0x00,0x01}), port is
* the port to listen on (host byte order), and the return value is the
* file-descriptor or -1 on error. */
-int ip_create_listener_split(const unsigned char *ip, unsigned short port);
+int ip_create_listener_split(const char *ip, unsigned short port);
/* Same semantics as above. */
-int ip_create_connection_split(const unsigned char *ip, unsigned short port);
+int ip_create_connection_split(const char *ip, unsigned short port);
/* Converts a string into the ip/port before calling the above */
int ip_create_listener(const char *address);
int ip_create_connection(const char *address);
/* Just does a string conversion on its own. NB: If accept_all_ip is non-zero,
* then the address string could be just a port. Ie. it's suitable for a
* listening address but not a connecting address. */
-int ip_parse_address(const char *address, unsigned char **parsed_ip,
+int ip_parse_address(const char *address, const char **parsed_ip,
unsigned short *port, int accept_all_ip);
/* Accepts an incoming connection through the listener. Assumes selects and
* what-not have deemed it an appropriate thing to do. */
int ip_accept_connection(int listen_fd);
#endif /* !defined(NO_IP) */
+/* These functions wrap up things that can be portability hassles. */
+int int_strtoul(const char *str, unsigned long *val);
+#ifdef HAVE_STRSTR
+#define int_strstr strstr
+#else
+char *int_strstr(const char *haystack, const char *needle);
+#endif
+
#endif /* !defined(_TUNALA_H) */