diff --git a/demos/tunala/INSTALL b/demos/tunala/INSTALL new file mode 100644 index 0000000000000000000000000000000000000000..c7328dad34328462870d3e423c75c60881a676ce --- /dev/null +++ b/demos/tunala/INSTALL @@ -0,0 +1,119 @@ +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 ... + diff --git a/demos/tunala/Makefile b/demos/tunala/Makefile index a68db7a39d3f9baa8719e7afdc273081e401a268..bef1704a3caa69018d404fb260e0bb334b146beb 100644 --- a/demos/tunala/Makefile +++ b/demos/tunala/Makefile @@ -11,14 +11,14 @@ RM=rm -f 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 diff --git a/demos/tunala/Makefile.am b/demos/tunala/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..1616004d260e572baa14e2be22a5671853edba1f --- /dev/null +++ b/demos/tunala/Makefile.am @@ -0,0 +1,11 @@ +# 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 diff --git a/demos/tunala/README b/demos/tunala/README index 3f3a4097a72eddb631c4e1e5925ab2b20569b1f2..15690088f3356b69bade9676883903fd95f4fedc 100644 --- a/demos/tunala/README +++ b/demos/tunala/README @@ -188,20 +188,16 @@ flags inside the Makefile. Likewise, if you want to tweak the building, it's 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. @@ -217,8 +213,10 @@ In another console, type; -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: diff --git a/demos/tunala/autogunk.sh b/demos/tunala/autogunk.sh new file mode 100755 index 0000000000000000000000000000000000000000..c9783c6261c398ea165889b56961ec84726ad862 --- /dev/null +++ b/demos/tunala/autogunk.sh @@ -0,0 +1,25 @@ +#!/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 diff --git a/demos/tunala/autoungunk.sh b/demos/tunala/autoungunk.sh new file mode 100755 index 0000000000000000000000000000000000000000..14d10790fd871989a037f36e43bcc8f73891a3fb --- /dev/null +++ b/demos/tunala/autoungunk.sh @@ -0,0 +1,18 @@ +#!/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 diff --git a/demos/tunala/breakage.c b/demos/tunala/breakage.c new file mode 100644 index 0000000000000000000000000000000000000000..dcdd64b0ef183556f5ea977ebcfcdc3624a5c717 --- /dev/null +++ b/demos/tunala/breakage.c @@ -0,0 +1,66 @@ +#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 diff --git a/demos/tunala/configure.in b/demos/tunala/configure.in new file mode 100644 index 0000000000000000000000000000000000000000..8a6f01fda85daa6e0988ab593549f4db16636428 --- /dev/null +++ b/demos/tunala/configure.in @@ -0,0 +1,28 @@ +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) diff --git a/demos/tunala/ip.c b/demos/tunala/ip.c index 4874d620d50c5b3fd05a9ec03ec83b14f2d17537..96ef4e65360682d64553c70b2ca01e9b0c10f23e 100644 --- a/demos/tunala/ip.c +++ b/demos/tunala/ip.c @@ -18,7 +18,7 @@ int ip_initialise(void) 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; @@ -36,7 +36,7 @@ int ip_create_listener_split(const unsigned char *ip, unsigned short port) 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) @@ -48,7 +48,7 @@ err: 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; @@ -65,7 +65,8 @@ int ip_create_connection_split(const unsigned char *ip, unsigned short port) 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; @@ -75,17 +76,16 @@ err: 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 @@ -110,8 +110,7 @@ int ip_parse_address(const char *address, unsigned char **parsed_ip, 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; @@ -120,7 +119,7 @@ determine_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)) @@ -130,7 +129,7 @@ int ip_create_listener(const char *address) int ip_create_connection(const char *address) { - unsigned char *ip; + const char *ip; unsigned short port; if(!ip_parse_address(address, &ip, &port, 0)) diff --git a/demos/tunala/tunala.c b/demos/tunala/tunala.c index dbf155c67a04d822b6b53520c485ae0d38f07a07..708cb92532a5b6d1cf1778224bb02caa338d9493 100644 --- a/demos/tunala/tunala.c +++ b/demos/tunala/tunala.c @@ -80,7 +80,7 @@ static int selector_select(tunala_selector_t *selector); * 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); @@ -219,9 +219,7 @@ static int err_str1(const char *fmt, const char *str1) 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; @@ -233,9 +231,7 @@ static int parse_max_tunnels(const char *s, unsigned int *maxtunnels) 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; @@ -258,9 +254,7 @@ static int parse_dh_special(const char *s, const char **dh_special) 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; @@ -272,9 +266,7 @@ static int parse_verify_level(const char *s, unsigned int *verify_level) 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; @@ -299,7 +291,7 @@ int main(int argc, char *argv[]) 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; @@ -527,7 +519,7 @@ main_loop: 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; @@ -589,6 +581,7 @@ skip_totals: } goto main_loop; /* Should never get here */ +shouldnt_happen: abort(); return 1; } @@ -736,6 +729,7 @@ static SSL_CTX *initialise_ssl_ctx(int server_mode, const char *engine_id, 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); @@ -935,7 +929,7 @@ static int tunala_world_make_room(tunala_world_t *world) } 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; diff --git a/demos/tunala/tunala.h b/demos/tunala/tunala.h index bc8623a182acb32835c4d79810c66975812169e0..4271a4d4a817d625378e9ce10980bd3b87bb8083 100644 --- a/demos/tunala/tunala.h +++ b/demos/tunala/tunala.h @@ -17,13 +17,57 @@ #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 #ifndef NO_SYSTEM_H #include +#ifdef HAVE_UNISTD_H #include +#endif +#ifdef HAVE_FCNTL_H #include +#endif +#ifdef HAVE_LIMITS_H +#include +#endif #include #include #include +#include #include #endif /* !defined(NO_SYSTEM_H) */ @@ -143,20 +187,28 @@ int ip_initialise(void); /* 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) */