andrew_shadoura-tnat64-tnat64-0.05/.hg_archival.txt0000644000000000000000000000017711634674321020270 0ustar 00000000000000repo: bb9a6bd44c2fd992117a5c3a6f924e6badef0f0b node: 0b186dda93d31893b70095e0160bfdadff8b64af branch: default tag: tnat64-0.05 andrew_shadoura-tnat64-tnat64-0.05/.hgtags0000644000000000000000000000032411634674321016452 0ustar 000000000000006928f4314581d6f2c141f7c25bdb88d42d239f36 tnat64-0.01 cc4d17bb3ac7a5938392dcf66342602a356269c8 tnat64-0.02 079118137b29daffcac857aa28b2f36b74e04ccc tnat64-0.03 262ad3e186999246c689ce02ab44d12a3212f40b tnat64-0.04 andrew_shadoura-tnat64-tnat64-0.05/.indent.pro0000644000000000000000000000117211634674321017257 0ustar 00000000000000/* $Id: .indent.pro 238 2005-09-21 05:26:03Z nenolod $ */ /* copy this file to the source dir then run indent file.c */ --gnu-style /* This is the indent before the brace not inside the block. */ --brace-indent0 /* Indent case: by 2 and braces inside case by 0(then by 0)... */ --case-brace-indentation0 --case-indentation2 --indent-level4 /* Put while() on the brace from do... */ --cuddle-do-while /* Disable an annoying format... */ --no-space-after-function-call-names /* Disable an annoying format... */ --dont-break-procedure-type /* Disable an annoying format... */ --no-space-after-casts --line-length200 --no-tabs andrew_shadoura-tnat64-tnat64-0.05/COPYING0000644000000000000000000004307011634674321016234 0ustar 00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy 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., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. andrew_shadoura-tnat64-tnat64-0.05/ChangeLog0000644000000000000000000000347111634674321016754 0ustar 000000000000002011-09-16 Andrew O. Shadoura * Version 0.05 released. 2011-09-16 Barak A. Pearlmutter * Fix malloc return code checking error * Squash unused variable warnings * Autotools modernisation - Fix autoheader issue (crashed, did not generate config.h.in). - Create Makefile.am, use automake, rm manually-created Makefile.in. - Put m4 cache in m4/, make stub file there to preserve directory. - Generate tnat64 / tnat64.8 from tnat64.in / tnat64.8.in, thereby allowing them to be specialized to current configuration. - Delete files which can be generated by autoreconf --install * Update INSTALL instructions * Rename validateconf to tnet64-validateconf and include in installation * Add and slightly improve README.creole 2011-09-11 Andrew O. Shadura * Version 0.04 released. * The dynamic library moved into subdirectory. * Some minor fixes. 2011-05-19 Andrew O. Shadura * Version 0.03 released. * X11 compatibility (get*name functions now work properly). * Crash on wrong function calls order fixed. * Better debug facilities. 2011-04-29 Andrew O. Shadura * Version 0.02 released. * getsockname(2) and getpeername(2) are now intercepted, too; that improves the compatibility with some software. * Some bugs fixed. 2011-04-19 Andrew O. Shadura * The first release: 0.01. 2011-03-02 Andrew O. Shadura * Got it working! 2011-03-01 Andrew O. Shadura * First attempt to implement NAT64 wrapper, tsocks code is used as a starting point. andrew_shadoura-tnat64-tnat64-0.05/INSTALL0000644000000000000000000001021111634674321016221 0ustar 00000000000000Quick Installation Instructions ------------------------------- 1. Unpack the archive (though if you're reading this you've probably already achieved that) tar -zxvf tnat64-.tar.bz2 or hg clone http://bitbucket.org/andrew_shadoura/tnat64/ 2. Generate config scripts by running: autoreconf --install --symlink 3. Run ./configure, options which might be of interest (and that are specific to tnat64) include: --disable-debug This configuration option tells tnat64 to never output error messages to stderr. This can also be achieved at run time by defining the environment variable TSOCKS_NO_ERROR to be "yes" --enable-oldmethod This forces tnat64 not to use the RTLD_NEXT parameter to dlsym to get the address of the connect() method tnat64 overrides, instead it loads a reference to the libc shared library and then uses dlsym(). Again this is not very elegant and shouldn't be required. --with-conf= You can specify the location of the tnat64 configuration file using this option, it defaults to '/etc/tnat64.conf' Other standard autoconf options are provided by typing './configure --help' NOTE: The install path for the library is _NOT_ prefixed with --prefix, this is because it is strongly recommended that tnat64 is installed into /lib (and not /usr/lib). This is important if tnat64 is put into /etc/ld.so.preload since /usr is not mounted on many systems at boot time, meaning that programs running before /usr is mounted will try to preload tnat64, fail to find it and die, making the machine unusable. If you really wish to install the library into some other path use --libdir. 4. Compile the code by typing: make This should result in the creation of the following: - libtnat64.so - the libtnat64 library - tnat64-validateconf - a utility to verify the tnat64 configuration file 5. If you experience any errors at this step and don't know how to fix them, seek help using the contacts listed on the projects homepage. 6. Install the compiled library. You can skip this step if you only plan to use the library for personal use. If you want all users on the machine to be able to use it however, su to root then type make install This will install the library, the tnat64 script and its man pages (tnat64(8), tnat64(1) and tnat64.conf(5)) to the paths specified to configure. Note that by default the library is installed to /lib and that the configure --prefix is IGNORED. See above for more detail. 7. At this point you'll need to create the tnat64 configuration file. There are two samples provided in the build directory called tnat64.conf.simple.example and tnat64.conf.complex.example. Documentation on the configuration file format is provided in the tnat64.conf man page ('man tnat64.conf'). 8. Having created the tnat64.conf file you should verify it using tnat64-validateconf (some detail on validateconf can be found in the tnat64.conf man page). Normally validateconf is run without arguments ('./tnat64-validateconf'). Any errors which are displayed by validateconf need to be rectified before tnat64 will function correctly. 9. You can now choose to make the library affect all users or just those who choose to use it. If you want users to use it themselves, they can simply use the tnat64(1) shell script to run programs (see 'man tnat64') or do the following in their shell before running applications that need to be transparently proxied: (in Bash) export LD_PRELOAD= (in CSH) setenv LD_PRELOAD = e.g /lib/libtnat64.so.1.8 If you want all users to pick up the library, place the full path to the full library in the file /etc/ld.so.preload (e.g "/lib/libtnat64.so"). Be EXTREMELY careful if you do this, if you mistype it or in some way get it wrong this will make your machine UNUSABLE. Also, if you do this, make sure the directory you put the library in is in the root of the filesystem, if the library is not available at boot time, again, your machine will be UNUSABLE. 10. Go ahead and use it! At this point everything should work. Again, if you experience any problems, use the contact points listed at the project's homepage. andrew_shadoura-tnat64-tnat64-0.05/Makefile.am0000644000000000000000000000262711634674321017240 0ustar 00000000000000ACLOCAL_AMFLAGS = -I m4 bin_SCRIPTS = tnat64 do_subst = sed -e 's,[@]libdir[@],$(libdir),g' \ -e 's,[@]pkglibdir[@],$(pkglibdir),g' \ -e 's,[@]bindir[@],$(bindir),g' \ -e 's,[@]CONF_FILE[@],$(CONF_FILE),g' \ -e 's,[@]PERL[@],$(PERL),g' \ -e 's,[@]PACKAGE[@],$(PACKAGE),g' \ -e 's,[@]VERSION[@],$(VERSION),g' # It is tempting to generate tnat64 from tnat64.in during ./configure # by adding it to AC_CONFIG_FILES() in configure.ac, but that has a # horrible bug of leaving unexpanded variables in paths, which is # unpleasant to work around. The below is the recommended procedure. tnat64: tnat64.in Makefile $(do_subst) < $(srcdir)/tnat64.in > tnat64 chmod +x tnat64 tnat64.8: tnat64.8.in Makefile $(do_subst) < $(srcdir)/tnat64.8.in > tnat64.8 EXTRA_DIST = tnat64.in tnat64.8.in bin_PROGRAMS = tnat64-validateconf tnat64_validateconf_SOURCES = validateconf.c common.c parser.c tnat64_validateconf_CFLAGS = $(AM_CFLAGS) # this renames object files pkglib_LTLIBRARIES = libtnat64.la libtnat64_la_SOURCES = tnat64.c common.c parser.c libtnat64_la_LDFLAGS = -Wc,-nostdlib libtnat64_la_LIBADD = -ldl -lc man_MANS = tnat64.1 tnat64.8 tnat64.conf.5 doc_DATA = tnat64.conf.complex.example tnat64.conf.simple.example install-exec-hook: cd $(DESTDIR)$(pkglibdir) && \ rm -f libtnat64.a && \ rm -f libtnat64.la && \ rm -f libtnat64.so && \ rm -f libtnat64.so.0 && \ mv libtnat64.so.0.0.0 libtnat64.so andrew_shadoura-tnat64-tnat64-0.05/README.creole0000644000000000000000000000625711634674321017337 0ustar 00000000000000=== What is TNAT64? === TNAT64 is an interceptor which redirects outgoing TCPv4 connections through NAT64, thus enabling an application running on an IPv6-only host to communicate with the IPv4 world, even if that application does not support IPv6 at all. TNAT64 is based on the original code of [[http://tsocks.sourceforge.net/|tsocks]]. === What is NAT64? === According to Wikipædia, ‘//NAT64 is a mechanism to allow IPv6 hosts to communicate with IPv4 servers. The NAT64 server is the endpoint for at least one IPv4 address and an IPv6 network segment of 32-bits (e.g. 64:FF9B::/96). The IPv6 client embeds the IPv4 address it wishes to communicate with using these bits, and sends its packets to the resulting address. The NAT64 server then creates a NAT-mapping between the IPv6 and the IPv4 address, allowing them to communicate.//’ ~[[[http://en.wikipedia.org/wiki/NAT64|1]]] === How does it work? === From the user's point of view, the application is run by prepending its name with //tnat64//: {{{ $ tnat64 some-old-application }}} And then magic happens: when on an IPv6-only network, the application uses NAT64 facilities to contact IPv4 hosts, and when IPv6 is not available, but IPv4 is functional, IPv4 is used. Everything happens without the need to reconfigure or recompile anything. === But how does it work deep inside? === TNAT64 is implemented as a shared object library which is loaded into your application by means of the [[http://linux.die.net/man/8/ld.so|ld.so(8)]] LD_PRELOAD feature. The library intercepts certain BSD socket calls (namely, [[http://linux.die.net/man/2/socket|socket(2)]] and [[http://linux.die.net/man/2/connect|connect(2)]]). When an application creates a socket of AF_INET family and SOCK_STREAM type, that is, an TCPv4 socket, that call is intercepted, and an AF_INET6 socket is returned instead. Following this, any connect(2) call on this socket is also intercepted. TNAT64 then decides if the destination host is reachable over IPv4, or instead needs to be forwarded to the NAT64. The decision is made as follows: # First, the configuration file is consulted to find the appropriate NAT64 prefix. If the prefix isn't specified for the destination network, this issue is reported to the user. # The NAT64 destination address is constructed by appending the IPv4 destination address to the NAT64 prefix. E.g. the destination address 198.51.100.192 and the NAT64 prefix [[http://tools.ietf.org/html/rfc6052|64:ff9b::/96]] would result in the NAT64 address 64:ff9b::198.51.100.192 (aka 64:ff9b::c933:64c0). # A connection attempt is performed to that address. # If the connection attempt fails because the destination network is unreachable, the IPv4-mapped IPv6 address is constructed and a connection attempt to that address is performed. These addresses have the prefix ::ffff:0:0/96 and are constructed just as described above. The connect call to this address is interpreted by the network stack the same way as if an TCPv4 connection was requested, thus the connection is made over IPv4 and not IPv6. This way the host can be reached via IPv4 when IPv6 networking is not available. # The next time the connection is requested, the host is contacted using the last successful method. andrew_shadoura-tnat64-tnat64-0.05/common.c0000644000000000000000000000715111634674321016635 0ustar 00000000000000/* commmon.c - Common routines for the tnat64 package */ #include #include #include #include #include #include #include #include #include #include #include #include /* Globals */ int loglevel = MSGERR; /* The default logging level is to only log error messages */ char *logfilename = NULL; /* Name of file to which log messages should be redirected */ FILE *logfile = NULL; /* File to which messages should be logged */ int logstamp = 0; /* Timestamp (and pid stamp) messages */ unsigned int HIDDENSYM resolve_ip(char *host, int showmsg, int allownames) { struct hostent *new; unsigned int hostaddr; struct in_addr *ip; if ((hostaddr = inet_addr(host)) == (unsigned int)-1) { /* We couldn't convert it as a numerical ip so */ /* try it as a dns name */ if (allownames) { #ifdef HAVE_GETHOSTBYNAME if ((new = gethostbyname(host)) == (struct hostent *)0) { #endif return (-1); #ifdef HAVE_GETHOSTBYNAME } else { ip = ((struct in_addr *)*new->h_addr_list); hostaddr = ip->s_addr; if (showmsg) printf("Connecting to %s...\n", inet_ntoa(*ip)); } #endif } else return (-1); } return (hostaddr); } /* Set logging options, the options are as follows: */ /* level - This sets the logging threshold, messages with */ /* a higher level (i.e lower importance) will not be */ /* output. For example, if the threshold is set to */ /* MSGWARN a call to log a message of level MSGDEBUG */ /* would be ignored. This can be set to -1 to disable */ /* messages entirely */ /* filename - This is a filename to which the messages should */ /* be logged instead of to standard error */ /* timestamp - This indicates that messages should be prefixed */ /* with timestamps (and the process id) */ void HIDDENSYM set_log_options(int level, char *filename, int timestamp) { loglevel = level; if (loglevel < MSGERR) loglevel = MSGNONE; if (filename) { logfilename = strdup(filename); } logstamp = timestamp; } void HIDDENSYM show_msg(int level, char *fmt, ...) { va_list ap; int saveerr; extern char *progname; char timestring[20]; time_t timestamp; if ((loglevel == MSGNONE) || (level > loglevel)) return; if (!logfile) { if (logfilename) { logfile = fopen(logfilename, "a"); if (logfile == NULL) { logfile = stderr; show_msg(MSGERR, "Could not open log file, %s, %s\n", logfilename, strerror(errno)); } } else logfile = stderr; } if (logstamp) { timestamp = time(NULL); strftime(timestring, sizeof(timestring), "%H:%M:%S", localtime(×tamp)); fprintf(logfile, "%s ", timestring); } fputs(progname, logfile); if (logstamp) { fprintf(logfile, "(%d)", getpid()); } fputs(": ", logfile); va_start(ap, fmt); /* Save errno */ saveerr = errno; vfprintf(logfile, fmt, ap); fflush(logfile); errno = saveerr; va_end(ap); } andrew_shadoura-tnat64-tnat64-0.05/common.h0000644000000000000000000000054311634674321016640 0ustar 00000000000000/* Common functions provided in common.c */ void set_log_options(int, char *, int); void show_msg(int level, char *, ...); unsigned int resolve_ip(char *, int, int); #define HIDDENSYM __attribute__ ((visibility ("hidden"))) #define NAT64PREFIXLEN 12 #define MSGNONE -1 #define MSGERR 0 #define MSGWARN 1 #define MSGNOTICE 2 #define MSGDEBUG 2 andrew_shadoura-tnat64-tnat64-0.05/configure.ac0000644000000000000000000002545211634674321017473 0ustar 00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.68]) AC_INIT([tnat64],[0.04],[],[],[http://bitbucket.org/andrew_shadoura/tnat64/]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([tnat64.c]) AM_INIT_AUTOMAKE([foreign]) LT_INIT AM_PROG_CC_C_O AC_CONFIG_HEADERS([config.h]) dnl Our default prefix is /usr/ since most people will be using tsocks dnl on Linux systems and that /usr/local/ stuff annoys them AC_PREFIX_DEFAULT([/usr]) dnl if libdir hasn't been set by the user default it to /lib since dnl tsocks needs to be on the root partition if put in the dnl /etc/ld.so.preload file test "$libdir" = "\${exec_prefix}/lib" && libdir="/lib" dnl Arguments we allow AC_ARG_ENABLE(debug, [ --disable-debug disable ALL error messages from tsocks ]) AC_ARG_ENABLE(oldmethod, [ --enable-oldmethod use the old method to override connect ]) AC_ARG_ENABLE(envconf, [ --disable-envconf do not allow TNAT64_CONF_FILE to specify configuration file ]) AC_ARG_WITH(conf, [ --with-conf= location of configuration file (/etc/tnat64.conf default)],[ if test "${withval}" = "yes" ; then AC_MSG_ERROR("--with-conf requires the location of the configuration file as an argument") else CONF_FILE=${withval} fi ], [ CONF_FILE=/etc/tnat64.conf ]) AC_DEFINE_UNQUOTED(CONF_FILE,["${CONF_FILE}"],[Location of configuration file (typically /etc/tnat64.conf)]) AC_SUBST(CONF_FILE) dnl ----------------------------------- dnl Get hostname and other information. dnl ----------------------------------- AC_CANONICAL_HOST dnl Checks for programs. AC_PROG_INSTALL AC_PROG_LN_S dnl Check if the C compiler accepts -Wall AC_MSG_CHECKING("if the C compiler accepts -Wall") OLDCFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wall" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[AC_MSG_RESULT(yes)],[ CFLAGS="$OLDCFLAGS" AC_MSG_RESULT(no)]) dnl Checks for standard header files. AC_HEADER_STDC dnl Check for the dynamic loader function header AC_CHECK_HEADER(dlfcn.h,,AC_MSG_ERROR("dlfcn.h not found")) dnl Check for the socket header AC_CHECK_HEADER(sys/socket.h,,AC_MSG_ERROR("sys/socket.h not found")) dnl Check for the arpa/inet.h header (inet_ntoa and inet_addr) AC_CHECK_HEADER(arpa/inet.h,,AC_MSG_ERROR("arpa/inet.h not found")) dnl Check for the fcntl header AC_CHECK_HEADER(fcntl.h,,AC_MSG_ERROR("fcntl.h not found")) dnl Check for the poll header AC_CHECK_HEADER(sys/poll.h,,AC_MSG_ERROR("sys/poll.h not found")) dnl Other headers we're interested in # Checks for header files. AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdlib.h string.h strings.h sys/socket.h sys/time.h unistd.h]) # Checks for library functions. AC_FUNC_MALLOC AC_CHECK_FUNCS([gethostbyname inet_ntoa memset socket strcspn strdup strerror strspn strtol]) # Checks for typedefs, structures, and compiler characteristics. AC_TYPE_UINT16_T dnl First find the library that contains connect() (obviously dnl the most important library for us). Once we've found it dnl we chuck it on the end of LIBS, that lib may end up there dnl more than once (since we do our search with an empty libs dnl list) but that isn't a problem OLDLIBS="${LIBS}" LIBS= CONNECTLIB= for LIB in c socket; do AC_CHECK_LIB("${LIB}",connect,[ CONNECTLIB="${LIB}" break ],) done LIBS="${OLDLIBS} -l${CONNECTLIB}" if test "${CONNECTLIB}" = ""; then AC_MSG_ERROR('Could not find library containing connect()') fi dnl Check for socket AC_CHECK_FUNC(socket,, [ AC_CHECK_LIB(socket, socket,,AC_MSG_ERROR("socket function not found"))]) dnl Check for a function to convert an ascii ip address dnl to a sin_addr. AH_TEMPLATE(HAVE_INET_ADDR,[Work out which function we have for conversion from string IPs to numerical ones]) AH_TEMPLATE(HAVE_INET_ATON,[Work out which function we have for conversion from string IPs to numerical ones]) AC_CHECK_FUNC(inet_aton, AC_DEFINE(HAVE_INET_ATON), [ AC_CHECK_FUNC(inet_addr, AC_DEFINE(HAVE_INET_ADDR), [ AC_CHECK_LIB(nsl, inet_addr, [ AC_DEFINE(HAVE_INET_ADDR) LIBS="${LIBS} -lnsl" ], [ AC_MSG_ERROR("Neither inet_aton or inet_addr present")])])]) dnl Look for gethostbyname (needed by tsocks and inspectsocks) AC_CHECK_FUNC(gethostbyname, AC_DEFINE(HAVE_GETHOSTBYNAME), [ AC_CHECK_LIB(xnet, gethostbyname, AC_DEFINE(HAVE_GETHOSTBYNAME), [ AC_MSG_ERROR(["gethostbyname not found, name lookups in " \ "tsocks and inspectsocks disabled"])])]) dnl The simple programs (saveme and inspectsocks) have no further dnl requirements, so save the libs needed here and use them in the dnl Makefile SIMPLELIBS=${LIBS} LIBS= dnl Checks for libraries. dnl Replace `main' with a function in -ldl: AC_CHECK_LIB(dl, dlsym,,AC_MSG_ERROR("libdl is required")) dnl If we're using gcc here define _GNU_SOURCE AC_MSG_CHECKING(for RTLD_NEXT from dlfcn.h) AH_TEMPLATE(USE_GNU_SOURCE,[Use _GNU_SOURCE to define RTLD_NEXT, mostly for RH7 systems]) AC_EGREP_CPP(yes, [ #include #ifdef RTLD_NEXT yes #endif ], [ AC_MSG_RESULT(yes) ], [ AC_MSG_RESULT(no) AC_MSG_CHECKING(for RTLD_NEXT from dlfcn.h with _GNU_SOURCE) AC_EGREP_CPP(yes, [ #define _GNU_SOURCE #include #ifdef RTLD_NEXT yes #endif ], [ AC_MSG_RESULT(yes) AC_DEFINE(USE_GNU_SOURCE) ], [ AC_MSG_RESULT(no) AC_DEFINE(USE_OLD_DLSYM) oldmethod="yes" ]) ]) AH_TEMPLATE(ALLOW_ENV_CONFIG,[Allow TSOCKS_CONF_FILE in environment to specify config file location]) if test "x${enable_envconf}" = "x"; then AC_DEFINE(ALLOW_ENV_CONFIG) fi AH_TEMPLATE(USE_OLD_DLSYM,,[dlopen() the old libc to get connect() instead of RTLD_NEXT, hopefully shouldn't be needed]) if test "${enable_oldmethod}" = "yes"; then AC_DEFINE(USE_OLD_DLSYM) oldmethod="yes" fi AH_TEMPLATE(ALLOW_MSG_OUTPUT,[Allow tsocks to generate messages to stderr when errors are encountered, this is really important and should only be disabled if you're REALLY sure. It can also be turned off at run time, see the man page for details]) if test "x${enable_debug}" = "x"; then AC_DEFINE(ALLOW_MSG_OUTPUT) fi dnl If we have to use the old method of overriding connect (i.e no dnl RTLD_NEXT) we need to know the location of the library that dnl contains connect(), select(), poll() and close() if test "${oldmethod}" = "yes"; then dnl We need to find the path to the library, to do dnl this we use find on the usual suspects, i.e /lib and dnl /usr/lib dnl Check that find is available, it should be somehere dnl in the path AC_CHECK_PROG(FIND, find, find) if test "${FIND}" = ""; then AC_MSG_ERROR('find not found in path') fi dnl Find tail, it should always be somewhere in the path dnl but for safety's sake AC_CHECK_PROG(TAIL, tail, tail) if test "${TAIL}" = ""; then AC_MSG_ERROR('tail not found in path') fi dnl Now find the library we need AC_MSG_CHECKING("location of lib${CONNECTLIB}.so") LIBCONNECT= for DIR in '/lib' '/usr/lib'; do if test "${LIBCONNECT}" = ""; then LIBCONNECT=`$FIND $DIR -name "lib${CONNECTLIB}.so.?" 2>/dev/null | $TAIL -1` fi done AC_DEFINE_UNQUOTED(LIBCONNECT, "${LIBCONNECT}",[path to library containing connect(), needed if USE_OLD_DLSYM is enabled]) if test "${LIBCONNECT}" = ""; then AC_MSG_ERROR("not found!") fi AC_MSG_RESULT($LIBCONNECT) dnl close() should be in libc, find it AC_MSG_CHECKING("location of libc.so") LIBC= for DIR in '/lib' '/usr/lib'; do if test "${LIBC}" = ""; then LIBC=`$FIND $DIR -name "libc.so.?" 2>/dev/null | $TAIL -1` fi done AC_DEFINE_UNQUOTED(LIBC, "${LIBC}",[path to libc, needed if USE_OLD_DLSYM is enabled]) if test "${LIBC}" = ""; then AC_MSG_ERROR("not found!") fi AC_MSG_RESULT($LIBC) fi dnl Find the correct connect prototype on this machine AC_MSG_CHECKING(for correct connect prototype) PROTO= PROTO1='int __fd, const struct sockaddr * __addr, int len' PROTO2='int __fd, const struct sockaddr_in * __addr, socklen_t __len' PROTO3='int __fd, struct sockaddr * __addr, int __len' PROTO4='int __fd, const struct sockaddr * __addr, socklen_t __len' for testproto in "${PROTO1}" \ "${PROTO2}" \ "${PROTO3}" \ "${PROTO4}" do if test "${PROTO}" = ""; then AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include int connect($testproto); ]], [[]])],[PROTO="$testproto";],[]) fi done if test "${PROTO}" = ""; then AC_MSG_ERROR("no match found!") fi AC_MSG_RESULT([connect(${PROTO})]) AC_DEFINE_UNQUOTED(CONNECT_SIGNATURE, [${PROTO}],[Prototype and function header for connect function]) dnl Find the correct socket prototype on this machine AC_MSG_CHECKING(for correct socket prototype) PROTO= PROTO1='int __domain, int __type, int __protocol' for testproto in "${PROTO1}" do if test "${PROTO}" = ""; then AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include int socket($testproto); ]], [[]])],[PROTO="$testproto";],[]) fi done if test "${PROTO}" = ""; then AC_MSG_ERROR("no match found!") fi AC_MSG_RESULT([socket(${PROTO})]) AC_DEFINE_UNQUOTED(SOCKET_SIGNATURE, [${PROTO}],[Prototype and function header for socket function]) dnl Find the correct getpeername prototype on this machine AC_MSG_CHECKING(for correct getpeername prototype) PROTO= PROTO1='int __fd, struct sockaddr * __addr, socklen_t * __len' for testproto in "${PROTO1}" do if test "${PROTO}" = ""; then AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include int getpeername($testproto); ]], [[]])],[PROTO="$testproto";],[]) fi done if test "${PROTO}" = ""; then AC_MSG_ERROR("no match found!") fi AC_MSG_RESULT([getpeername(${PROTO})]) AC_DEFINE_UNQUOTED(GETPEERNAME_SIGNATURE, [${PROTO}],[Prototype and function header for getpeername function]) dnl Find the correct getsockname prototype on this machine AC_MSG_CHECKING(for correct getsockname prototype) PROTO= PROTO1='int __fd, struct sockaddr * __addr, socklen_t * __len' for testproto in "${PROTO1}" do if test "${PROTO}" = ""; then AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include int getsockname($testproto); ]], [[]])],[PROTO="$testproto";],[]) fi done if test "${PROTO}" = ""; then AC_MSG_ERROR("no match found!") fi AC_MSG_RESULT([getsockname(${PROTO})]) AC_DEFINE_UNQUOTED(GETSOCKNAME_SIGNATURE, [${PROTO}],[Prototype and function header for getsockname function]) dnl Pick which of the sockaddr type arguments we need for dnl connect(), we need to cast one of ours to it later SOCKETARG="struct sockaddr *" case "${PROTO}" in *sockaddr_in*) SOCKETARG="struct sockaddr_in *" ;; esac AC_DEFINE_UNQUOTED(CONNECT_SOCKARG, [${SOCKETARG}],[The type of socket structure pointer to use to call the real connect]) dnl Output the special librarys (libdl etc needed for tsocks) SPECIALLIBS=${LIBS} AC_SUBST(SPECIALLIBS) LIBS=${SIMPLELIBS} AC_CONFIG_FILES([Makefile]) AC_OUTPUT andrew_shadoura-tnat64-tnat64-0.05/m4/WHAT-IS-THIS0000644000000000000000000000005011634674321017254 0ustar 00000000000000directory for in-tree copy of m4 macros andrew_shadoura-tnat64-tnat64-0.05/parser.c0000644000000000000000000004353511634674321016647 0ustar 00000000000000/* parser.c - Parsing routines for tnat64.conf */ #include #include #include #include #include #include #include #include #include "common.h" #include "parser.h" /* Global configuration variables */ #define MAXLINE BUFSIZ /* Max length of conf line */ static struct prefixent *currentcontext = NULL; static int handle_line(struct parsedfile *, char *, int); static int tokenize(char *, int, char *[]); static int handle_path(struct parsedfile *, int, int, char *[]); static int handle_endpath(struct parsedfile *, int, int, char *[]); static int handle_subnet(struct parsedfile *, int, char *); static int handle_local(struct parsedfile *, int, char *); static int handle_prefix(struct parsedfile *, int, char *); static int make_netent(char *value, struct netent **ent); int HIDDENSYM read_config(char *filename, struct parsedfile *config) { FILE *conf; char line[MAXLINE]; int rc = 0; int lineno = 1; /* Clear out the structure */ memset(config, 0x0, sizeof(*config)); /* Initialization */ currentcontext = &(config->defaultprefix); /* If a filename wasn't provided, use the default */ if (filename == NULL) { strncpy(line, CONF_FILE, sizeof(line) - 1); /* Insure null termination */ line[sizeof(line) - 1] = (char)0; filename = line; } show_msg(MSGDEBUG, "Opening configuration file (%s)\n", filename); /* Read the configuration file */ if ((conf = fopen(filename, "r")) == NULL) { show_msg(MSGERR, "Could not open NAT64 configuration file " "(%s), assuming all networks local\n", filename); handle_local(config, 0, "0.0.0.0/0.0.0.0"); rc = 1; /* Severe errors reading configuration */ } else { memset(&(config->defaultprefix), 0x0, sizeof(config->defaultprefix)); while (NULL != fgets(line, MAXLINE, conf)) { /* This line _SHOULD_ end in \n so we */ /* just chop off the \n and hand it on */ if (strlen(line) > 0) line[strlen(line) - 1] = '\0'; handle_line(config, line, lineno); lineno++; } fclose(conf); /* Always add the 127.0.0.1/255.0.0.0 subnet to local */ handle_local(config, 0, "127.0.0.0/255.0.0.0"); } return (rc); } static int handle_line(struct parsedfile *config, char *line, int lineno) { char *words[10]; static char savedline[MAXLINE]; int nowords = 0, i; /* Save the input string */ strncpy(savedline, line, MAXLINE - 1); savedline[MAXLINE - 1] = (char)0; /* Tokenize the input string */ nowords = tokenize(line, 10, words); /* Set the spare slots to an empty string to simplify */ /* processing */ for (i = nowords; i < 10; i++) words[i] = ""; if (nowords > 0) { /* Now this can either be a "path" block starter or */ /* ender, otherwise it has to be a pair ( = */ /* ) */ if (!strcmp(words[0], "path")) { handle_path(config, lineno, nowords, words); } else if (!strcmp(words[0], "}")) { handle_endpath(config, lineno, nowords, words); } else { /* Has to be a pair */ if ((nowords != 3) || (strcmp(words[1], "="))) { show_msg(MSGERR, "Malformed configuration pair " "on line %d in configuration " "file, \"%s\"\n", lineno, savedline); } else if (!strcmp(words[0], "subnet")) { handle_subnet(config, lineno, words[2]); } else if (!strcmp(words[0], "nat64_prefix")) { handle_prefix(config, lineno, words[2]); } else if (!strcmp(words[0], "local")) { handle_local(config, lineno, words[2]); } else { show_msg(MSGERR, "Invalid pair type (%s) specified " "on line %d in configuration file, " "\"%s\"\n", words[0], lineno, savedline); } } } return (0); } /* This routines breaks up input lines into tokens */ /* and places these tokens into the array specified */ /* by tokens */ static int tokenize(char *line, int arrsize, char *tokens[]) { int tokenno = -1; int finished = 0; /* Whitespace is ignored before and after tokens */ while ((tokenno < (arrsize - 1)) && (line = line + strspn(line, " \t")) && (*line != (char)0) && (!finished)) { tokenno++; tokens[tokenno] = line; line = line + strcspn(line, " \t"); *line = (char)0; line++; /* We ignore everything after a # */ if (*tokens[tokenno] == '#') { finished = 1; tokenno--; } } return (tokenno + 1); } static int handle_path(struct parsedfile *config, int lineno, int nowords, char *words[]) { struct prefixent *newprefix; if ((nowords != 2) || (strcmp(words[1], "{"))) { show_msg(MSGERR, "Badly formed path open statement on line %d " "in configuration file (should look like " "\"path {\")\n", lineno); } else if (currentcontext != &(config->defaultprefix)) { /* You cannot nest path statements so check that */ /* the current context is defaultprefix */ show_msg(MSGERR, "Path statements cannot be nested on line %d " "in configuration file\n", lineno); } else { /* Open up a new prefixent, put it on the list */ /* then set the current context */ if ((newprefix = (struct prefixent *)malloc(sizeof(struct prefixent))) == NULL) exit(-1); /* Initialize the structure */ show_msg(MSGDEBUG, "New prefix structure from line %d in configuration file going " "to 0x%08x\n", lineno, newprefix); memset(newprefix, 0x0, sizeof(*newprefix)); newprefix->next = config->paths; newprefix->lineno = lineno; config->paths = newprefix; currentcontext = newprefix; } return (0); } static int handle_endpath(struct parsedfile *config, int lineno, int nowords, char *words[]) { if (nowords != 1) { show_msg(MSGERR, "Badly formed path close statement on line " "%d in configuration file (should look like " "\"}\")\n", lineno); } else { currentcontext = &(config->defaultprefix); } /* We could perform some checking on the validty of data in */ /* the completed path here, but thats what verifyconf is */ /* designed to do, no point in weighing down libtsocks */ return (0); } static int handle_subnet(struct parsedfile *config, int lineno, char *value) { int rc; struct netent *ent; rc = make_netent(value, &ent); switch (rc) { case 1: show_msg(MSGERR, "Local network specification (%s) is not validly " "constructed in subnet statement on line " "%d in configuration " "file\n", value, lineno); return (0); break; case 2: show_msg(MSGERR, "IP in subnet statement " "network specification (%s) is not valid on line " "%d in configuration file\n", value, lineno); return (0); break; case 3: show_msg(MSGERR, "SUBNET in subnet statement " "network specification (%s) is not valid on " "line %d in configuration file\n", value, lineno); return (0); break; case 4: show_msg(MSGERR, "IP (%s) & ", inet_ntoa(ent->localip)); show_msg(MSGERR, "SUBNET (%s) != IP on line %d in " "configuration file, ignored\n", inet_ntoa(ent->localnet), lineno); return (0); break; case 5: show_msg(MSGERR, "Start port in subnet statement " "network specification (%s) is not valid on line " "%d in configuration file\n", value, lineno); return (0); break; case 6: show_msg(MSGERR, "End port in subnet statement " "network specification (%s) is not valid on line " "%d in configuration file\n", value, lineno); return (0); break; case 7: show_msg(MSGERR, "End port in subnet statement " "network specification (%s) is less than the start " "port on line %d in configuration file\n", value, lineno); return (0); break; } /* The entry is valid so add it to linked list */ ent->next = currentcontext->reachnets; currentcontext->reachnets = ent; return (0); } static int handle_prefix(struct parsedfile *config, int lineno, char *value) { char *ip; ip = strsplit(NULL, &value, " "); if (currentcontext->address == NULL) { currentcontext->address = strdup(ip); if (!inet_pton(AF_INET6, ip, ¤tcontext->prefix)) { show_msg(MSGERR, "Cannot parse NAT64 prefix " "specified at line %d in " "configuration file\n", lineno); } } else { if (currentcontext == &(config->defaultprefix)) show_msg(MSGERR, "Only one default NAT64 prefix " "may be specified at line %d in " "configuration file\n", lineno); else show_msg(MSGERR, "Only one NAT64 prefix may be specified " "per path on line %d in configuration " "file. (Path begins on line %d)\n", lineno, currentcontext->lineno); } return (0); } static int handle_local(struct parsedfile *config, int lineno, char *value) { int rc; struct netent *ent; if (currentcontext != &(config->defaultprefix)) { show_msg(MSGERR, "Local networks cannot be specified in path " "block at like %d in configuration file. " "(Path block started at line %d)\n", lineno, currentcontext->lineno); return (0); } rc = make_netent(value, &ent); switch (rc) { case 1: show_msg(MSGERR, "Local network specification (%s) is not validly " "constructed on line %d in configuration " "file\n", value, lineno); return (0); break; case 2: show_msg(MSGERR, "IP for local " "network specification (%s) is not valid on line " "%d in configuration file\n", value, lineno); return (0); break; case 3: show_msg(MSGERR, "SUBNET for " "local network specification (%s) is not valid on " "line %d in configuration file\n", value, lineno); return (0); break; case 4: show_msg(MSGERR, "IP (%s) & ", inet_ntoa(ent->localip)); show_msg(MSGERR, "SUBNET (%s) != IP on line %d in " "configuration file, ignored\n", inet_ntoa(ent->localnet), lineno); return (0); case 5: case 6: case 7: show_msg(MSGERR, "Port specification is invalid and " "not allowed in local network specification " "(%s) on line %d in configuration file\n", value, lineno); return (0); break; } if (ent->startport || ent->endport) { show_msg(MSGERR, "Port specification is " "not allowed in local network specification " "(%s) on line %d in configuration file\n", value, lineno); return (0); } /* The entry is valid so add it to linked list */ ent->next = config->localnets; (config->localnets) = ent; return (0); } /* Construct a netent given a string like */ /* "198.126.0.1[:portno[-portno]]/255.255.255.0" */ int HIDDENSYM make_netent(char *value, struct netent **ent) { char *ip; char *subnet; char *startport = NULL; char *endport = NULL; char *badchar; char separator; static char buf[200]; char *split; /* Get a copy of the string so we can modify it */ strncpy(buf, value, sizeof(buf) - 1); buf[sizeof(buf) - 1] = (char)0; split = buf; /* Now rip it up */ ip = strsplit(&separator, &split, "/:"); if (separator == ':') { /* We have a start port */ startport = strsplit(&separator, &split, "-/"); if (separator == '-') /* We have an end port */ endport = strsplit(&separator, &split, "/"); } subnet = strsplit(NULL, &split, " \n"); if ((ip == NULL) || (subnet == NULL)) { /* Network specification not validly constructed */ return (1); } /* Allocate the new entry */ if ((*ent = (struct netent *)malloc(sizeof(struct netent))) == NULL) { /* If we couldn't malloc some storage, leave */ exit(1); } show_msg(MSGDEBUG, "New network entry for %s going to 0x%08x\n", ip, *ent); if (!startport) (*ent)->startport = 0; if (!endport) (*ent)->endport = 0; #ifdef HAVE_INET_ADDR if (((*ent)->localip.s_addr = inet_addr(ip)) == -1) { #elif defined(HAVE_INET_ATON) if (!(inet_aton(ip, &((*ent)->localip)))) { #endif /* Badly constructed IP */ free(*ent); return (2); } #ifdef HAVE_INET_ADDR else if (((*ent)->localnet.s_addr = inet_addr(subnet)) == -1) { #elif defined(HAVE_INET_ATON) else if (!(inet_aton(subnet, &((*ent)->localnet)))) { #endif /* Badly constructed subnet */ free(*ent); return (3); } else if (((*ent)->localip.s_addr & (*ent)->localnet.s_addr) != (*ent)->localip.s_addr) { /* Subnet and Ip != Ip */ free(*ent); return (4); } else if (startport && (!((*ent)->startport = strtol(startport, &badchar, 10)) || (*badchar != 0) || ((*ent)->startport > 65535))) { /* Bad start port */ free(*ent); return (5); } else if (endport && (!((*ent)->endport = strtol(endport, &badchar, 10)) || (*badchar != 0) || ((*ent)->endport > 65535))) { /* Bad end port */ free(*ent); return (6); } else if (((*ent)->startport > (*ent)->endport) && !(startport && !endport)) { /* End port is less than start port */ free(*ent); return (7); } if (startport && !endport) (*ent)->endport = (*ent)->startport; return (0); } int HIDDENSYM is_local(struct parsedfile *config, struct in_addr *testip) { struct netent *ent; for (ent = (config->localnets); ent != NULL; ent = ent->next) { if ((testip->s_addr & ent->localnet.s_addr) == (ent->localip.s_addr & ent->localnet.s_addr)) { return (0); } } return (1); } /* Find the appropriate prefix to reach an ip */ int HIDDENSYM pick_prefix(struct parsedfile *config, struct prefixent **ent, struct in_addr *ip, uint16_t port) { struct netent *net; char ipbuf[64]; show_msg(MSGDEBUG, "Picking appropriate prefix for %s\n", inet_ntoa(*ip)); *ent = (config->paths); while (*ent != NULL) { /* Go through all the prefixes looking for one */ /* with a path to this network */ show_msg(MSGDEBUG, "Checking NAT64 prefix %s\n", ((*ent)->address ? (*ent)->address : "(No Address)")); net = (*ent)->reachnets; while (net != NULL) { strcpy(ipbuf, inet_ntoa(net->localip)); show_msg(MSGDEBUG, "%s/%s is reachable through this prefix\n", ipbuf, inet_ntoa(net->localnet)); if (((ip->s_addr & net->localnet.s_addr) == (net->localip.s_addr & net->localnet.s_addr)) && (!net->startport || ((net->startport <= port) && (net->endport >= port)))) { show_msg(MSGDEBUG, "The target is reachable\n"); /* Found the net, return */ return (0); } net = net->next; } (*ent) = (*ent)->next; } *ent = &(config->defaultprefix); return (0); } int HIDDENSYM check_prefix(struct parsedfile *config, struct in6_addr * addr) { struct prefixent *ent; char addrbuffer[INET6_ADDRSTRLEN]; if (inet_ntop(AF_INET6, addr, addrbuffer, sizeof(addrbuffer))) { show_msg(MSGDEBUG, "Checking if IPv6 address %s is behind the NAT64...\n", addrbuffer); } ent = (config->paths); while (ent != NULL) { /* Go through all the prefixes */ show_msg(MSGDEBUG, "Checking NAT64 prefix %s\n", (ent->address ? ent->address : "(No Address)")); if ((ent->address)) { if (!memcmp(addr, &(ent->prefix), NAT64PREFIXLEN)) { show_msg(MSGDEBUG, "Match!\n"); return 1; } } ent = ent->next; } ent = &(config->defaultprefix); show_msg(MSGDEBUG, "Checking the default NAT64 prefix %s\n", (ent->address ? ent->address : "(No Address)")); if (!memcmp(addr, &(ent->prefix), NAT64PREFIXLEN)) { show_msg(MSGDEBUG, "Match!\n"); return 1; } return 0; } /* This function is very much like strsep, it looks in a string for */ /* a character from a list of characters, when it finds one it */ /* replaces it with a \0 and returns the start of the string */ /* (basically spitting out tokens with arbitrary separators). If no */ /* match is found the remainder of the string is returned and */ /* the start pointer is set to be NULL. The difference between */ /* standard strsep and this function is that this one will */ /* set *separator to the character separator found if it isn't null */ char HIDDENSYM *strsplit(char *separator, char **text, const char *search) { int len; char *ret; ret = *text; if (*text == NULL) { if (separator) *separator = '\0'; return (NULL); } else { len = strcspn(*text, search); if (len == strlen(*text)) { if (separator) *separator = '\0'; *text = NULL; } else { *text = *text + len; if (separator) *separator = **text; **text = '\0'; *text = *text + 1; } } return (ret); } andrew_shadoura-tnat64-tnat64-0.05/parser.h0000644000000000000000000000305611634674321016646 0ustar 00000000000000/* parser.h - Structures, functions and global variables for the */ /* tsocks parsing routines */ #ifndef _PARSER_H #define _PARSER_H 1 /* Structure definitions */ /* Structure representing one NAT64 prefix specified in the config */ struct prefixent { int lineno; /* Line number in conf file this path started on */ char *address; /* IPv6 address prefix in textual form */ struct in6_addr prefix; /* the same, but in binary form */ struct netent *reachnets; /* Linked list of nets from this preifx */ struct prefixent *next; /* Pointer to next prefix entry */ }; /* Structure representing a network */ struct netent { struct in_addr localip; /* Base IP of the network */ struct in_addr localnet; /* Mask for the network */ unsigned long startport; /* Range of ports for the */ unsigned long endport; /* network */ struct netent *next; /* Pointer to next network entry */ }; /* Structure representing a complete parsed file */ struct parsedfile { struct netent *localnets; struct prefixent defaultprefix; struct prefixent *paths; }; /* Functions provided by parser module */ int read_config(char *, struct parsedfile *); int is_local(struct parsedfile *, struct in_addr *); int pick_prefix(struct parsedfile *, struct prefixent **, struct in_addr *, uint16_t port); int check_prefix(struct parsedfile *config, struct in6_addr * addr); char *strsplit(char *separator, char **text, const char *search); #endif andrew_shadoura-tnat64-tnat64-0.05/tnat64.10000644000000000000000000000305111634674321016376 0ustar 00000000000000.TH TNAT64 1 "" "TNAT64" .SH NAME .BR tnat64 \- Shell wrapper to simplify the use of the tnat64(8) library to transparently allow an application to connect to IPv4 hosts via NAT64 on IPv6-only systems when the application doesn't support IPv6 itself. .SH SYNOPSIS .B tnat64 .RB [application\ [application's\ arguments]] .br or .B tnat64 .RB [on|off] .br or .B tnat64 .SH DESCRIPTION .B tnat64 is a wrapper between the tnat64 library and the application what you would like to run through NAT64. .SH OPTIONS .IP \fB[application\ \fB[application's\ arguments]] run the application as specified with the environment (LD_PRELOAD) set such that tnat64(8) will transparently forward all connections to the NAT64 via IPv6 .IP \fB[on|off] this option adds or removes tnat64(8) from the LD_PRELOAD environment variable. When tnat64(8) is in this variable all executed applications are automatically NAT64-ed. If you want to use this function, you HAVE to source the shell script from yours, like this: "source /usr/bin/tnat64" or ". /usr/bin/tnat64" .br Example: .br ". tnat64 on" -- add the tnat64 lib to LD_PRELOAD .br ". tnat64 off" -- remove the tnat64 lib from LD_PRELOAD .IP \fB[show|sh] show the current value of the LD_PRELOAD variable .IP \fB create a new shell with LD_PRELOAD including tnat64(8). .PP .SH AUTHOR This script was created by Tamas SZERB for the Debian package of tsocks. It (along with this manual page) have since been adapted into the main tsocks project and modified, and then modified to be used with tnat64. andrew_shadoura-tnat64-tnat64-0.05/tnat64.8.in0000644000000000000000000001445311634674321017022 0ustar 00000000000000.TH TNAT64 8 "" "TNAT64" \" -*- \" nroff -* .SH NAME .BR tnat64 \- Library for intercepting outgoing network connections and redirecting them through the NAT64. .SH SYNOPSIS Set LD_PRELOAD to load the library then use applications as normal The syntax to force preload of the library for different shells is specified below: Bash, Ksh and Bourne shell \- export LD_PRELOAD=@pkglibdir@/libtnat64.so C Shell \- setenv LD_PRELOAD=@pkglibdir@/libtnat64.so This process can be automated (for Bash, Bourne and Korn shell users) for a single command or for all commands in a shell session by using the tnat64(1) script You can also setup tnat64 in such a way that all processes automatically use it, a very useful configuration. For more information on this configuration see the CAVEATS section of this manual page. .SH DESCRIPTION .BR tnat64 is a library to allow IPv4-only application to access IPv4 hosts on IPv6-only systems by using NAT64. It wraps the normal connect() function. When a connection is attempted, it consults the configuration file (which is defined at configure time but defaults to @CONF_FILE@) and determines if the IP address specified is local. If it is not, the library redirects the connection to an IPv6 address inside the NAT64 prefix that is specified in the configuration file. The redirection is performed only if the destination host is unreachable (when there's no route to host). Also, after the first successful redirection all the following connection attempts are redirected immediately without even trying to connect to the host via IPv4. When the destination host cannot be reached via IPv6, the redirection is disabled. .BR tnat64 avoids the need to recompile applications so they can use reach hosts even if they do not support IPv6 and there's no IPv4 connectivity. .BR tnat64 is heavily based on the source code of tsocks, a library that intercepts outgoing TCP connections and redirects them though SOCKS proxy. Many thanks for tsocks author, Shaun Clowes! .SS ARGUMENTS Most arguments to .BR tnat64 are provided in the configuration file (the location of which is defined at configure time by the \-\-with-conf= argument but defaults to @CONF_FILE@). The structure of this file is documented in tnat64.conf(8) Some configuration options can be specified at run time using environment variables as follows: .TP .I TNAT64_CONF_FILE This environment variable overrides the default location of the tnat64 configuration file. This variable is not honored if the program tnat64 is embedded in is setuid. In addition this environment variable can be compiled out of tnat64 with the \-\-disable-envconf argument to configure at build time .TP .I TNAT64_DEBUG This environment variable sets the level of debug output that should be generated by tnat64 (debug output is generated in the form of output to standard error). If this variable is not present by default the logging level is set to 0 which indicates that only error messages should be output. Setting it to higher values will cause tnat64 to generate more messages describing what it is doing. If set to \-1 tnat64 will output absolutely no error or debugging messages. This is only needed if tnat64 output interferes with a program it is embedded in. Message output can be permanently compiled out of tnat64 by specifying the \-\-disable-debug option to configure at build time .TP .I TNAT64_DEBUG_FILE This option can be used to redirect the tnat64 output (which would normally be sent to standard error) to a file. This variable is not honored if the program tnat64 is embedded in is setuid. For programs where tnat64 output interferes with normal operation this option is generally better than disabling messages (with TNAT64_DEBUG = \-1) .SS ERRORS .BR tnat64 will generate error messages and print them to stderr when there are problems with the configuration file if the TNAT64_DEBUG environment variable is not set to \-1 or and \-\-disable-debug was not specified at compile time. This output may cause some problems with programs that redirect standard error. .SS CAVEATS .BR tnat64 will not in the above configuration be able to provide proxying to setuid applications or applications that are not run from a shell. You can force all applications to LD_PRELOAD the library by placing the path to libtnat64 in /etc/ld.so.preload. Please make sure you correctly enter the full path to the library in this file if you do this. If you get it wrong, you will be UNABLE TO DO ANYTHING with the machine and will have to boot it with a rescue disk and remove the file (or try the saveme program, see the INSTALL file for more info). THIS IS A ***WARNING***, please be careful. Also be sure the library is in the root filesystem as all hell will break loose if the directory it is in is not available at boot time. .SH BUGS .BR tnat64 can only proxy outgoing TCP connections .BR tnat64 does NOT work correctly with asynchronous sockets (though it does work with non blocking sockets). This bug would be very difficult to fix and there appears to be no demand for it (I know of no major application that uses asynchronous sockets) .BR tnat64 uses ELF dynamic loader features to intercept dynamic function calls from programs in which it is embedded. As a result, it cannot trace the actions of statically linked executables, non-ELF executables, or executables that make system calls directly with the system call trap or through the syscall() routine. .SH FILES @CONF_FILE@ - default tnat64 configuration file .SH SEE ALSO tnat64.conf(5) tnat64(1) .SH AUTHORS Andrew O. Shadura (bugzilla@tut.by), Shaun Clowes (delius@progsoc.uts.edu.au) .SH COPYRIGHT Copyright 2011 Andrew O. Shadura Original tsocks manual page, copyright 2000 Shaun Clowes tnat64 and its documentation may be freely copied under the terms and conditions of version 2 of the GNU General Public License, as published by the Free Software Foundation (Cambridge, Massachusetts, United States of America). This documentation is heavily based on the documentation for tsocks, transparent SOCKSification library, whose documentation itself is based on the documentation for logwrites, another shared library interceptor. One line of code from it was used in tsocks and a lot of the documentation :) logwrites is by adam@yggdrasil.com (Adam J. Richter) and can be had from ftp.yggdrasil.com pub/dist/pkg andrew_shadoura-tnat64-tnat64-0.05/tnat64.c0000644000000000000000000003100111634674321016454 0ustar 00000000000000/* TNAT64 - Wrapper library for redirecting IPv4 connections to NAT64 Copyright (C) 2011 Andrew O. Shadura Based on original code of TSOCKS, copyright (C) 2000 Shaun Clowes 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* PreProcessor Defines */ #include #ifdef USE_GNU_SOURCE #define _GNU_SOURCE #endif /* Global configuration variables */ char *progname = "libtnat64"; /* Name used in err msgs */ /* Header Files */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Mask which covers at least up to SOCK_MASK-1. The * * remaining bits are used as flags. * per Linux kernel 2.6.* */ #define SOCK_TYPE_MASK 0xf /* Global Declarations */ static int (*realsocket) (SOCKET_SIGNATURE); static int (*realconnect) (CONNECT_SIGNATURE); static int (*realgetpeername) (GETPEERNAME_SIGNATURE); static int (*realgetsockname) (GETSOCKNAME_SIGNATURE); static struct parsedfile *config; static int suid = 0; static char *conffile = NULL; static struct in6_addr ipv4mapped; static int current_af = AF_INET6; /* Exported Function Prototypes */ void _init(void); int socket(SOCKET_SIGNATURE); int connect(CONNECT_SIGNATURE); int getpeername(GETPEERNAME_SIGNATURE); int getsockname(GETSOCKNAME_SIGNATURE); /* Private Function Prototypes */ static int get_config(); static int get_environment(); void _init(void) { #ifdef USE_OLD_DLSYM void *lib; #endif /* We could do all our initialization here, but to be honest */ /* most programs that are run won't use our services, so */ /* we do our general initialization on first call */ /* Determine the logging level */ suid = (getuid() != geteuid()); #ifndef USE_OLD_DLSYM realconnect = dlsym(RTLD_NEXT, "connect"); realsocket = dlsym(RTLD_NEXT, "socket"); realgetpeername = dlsym(RTLD_NEXT, "getpeername"); realgetsockname = dlsym(RTLD_NEXT, "getsockname"); #else lib = dlopen(LIBCONNECT, RTLD_LAZY); realconnect = dlsym(lib, "connect"); realsocket = dlsym(lib, "socket"); realgetpeername = dlsym(lib, "getpeername"); realgetsockname = dlsym(lib, "getsockname"); dlclose(lib); #endif inet_pton(AF_INET6, "::ffff:0.0.0.0", &ipv4mapped); get_environment(); } static int get_environment() { static int done = 0; int loglevel = MSGERR; char *logfilename = NULL; char *env; if (done) return (0); /* Determine the logging level */ #ifndef ALLOW_MSG_OUTPUT set_log_options(MSGNONE, NULL, 0); #else if ((env = getenv("TNAT64_DEBUG"))) loglevel = atoi(env); if (((env = getenv("TNAT64_DEBUG_FILE"))) && !suid) logfilename = env; set_log_options(loglevel, logfilename, 1); #endif done = 1; return (0); } static int get_config() { static int done = 0; if (done) return (0); /* Determine the location of the config file */ #ifdef ALLOW_ENV_CONFIG if (!suid) conffile = getenv("TNAT64_CONF_FILE"); #endif /* Read in the config file */ config = malloc(sizeof(*config)); if (!config) return (0); read_config(conffile, config); if (config->paths) show_msg(MSGDEBUG, "First lineno for first path is %d\n", config->paths->lineno); done = 1; return (0); } int socket(SOCKET_SIGNATURE) { /* If the real socket doesn't exist, we're stuffed */ if (realsocket == NULL) { show_msg(MSGERR, "Unresolved symbol: socket\n"); return (-1); } if ((__domain == AF_INET) && ((__type & SOCK_TYPE_MASK) == SOCK_STREAM)) { return realsocket(AF_INET6, __type, __protocol); } else { return realsocket(__domain, __type, __protocol); } } int connect(CONNECT_SIGNATURE) { struct sockaddr_in *connaddr; char addrbuffer[INET6_ADDRSTRLEN]; struct sockaddr_in6 dest_address6; int sock_type = -1; socklen_t sock_type_len = sizeof(sock_type); struct prefixent *path; int failed = 0; /* If the real connect doesn't exist, we're stuffed */ if (realconnect == NULL) { show_msg(MSGERR, "Unresolved symbol: connect\n"); return (-1); } show_msg(MSGDEBUG, "Got connection request\n"); connaddr = (struct sockaddr_in *)__addr; /* Get the type of the socket */ getsockopt(__fd, SOL_SOCKET, SO_TYPE, (void *)&sock_type, &sock_type_len); /* If this isn't an INET socket for a TCP stream we can't */ /* handle it, just call the real connect now */ if ((connaddr->sin_family != AF_INET) || (sock_type != SOCK_STREAM)) { show_msg(MSGDEBUG, "Connection isn't a TCP/IPv4 stream, ignoring\n"); return realconnect(__fd, __addr, __len); } /* If we haven't initialized yet, do it now */ get_config(); show_msg(MSGDEBUG, "Got connection request for socket %d to " "%s:%d\n", __fd, inet_ntoa(connaddr->sin_addr), connaddr->sin_port); /* If the address is local call realconnect */ if (!(is_local(config, &(connaddr->sin_addr)))) { show_msg(MSGDEBUG, "Connection for socket %d is local\n", __fd); return realconnect(__fd, __addr, __len); } /* Don't retry more than once */ while (failed < 2) { if (current_af == AF_INET) { /* Construct the IPv4-mapped IPv6 address */ dest_address6.sin6_family = AF_INET6; dest_address6.sin6_port = connaddr->sin_port; dest_address6.sin6_flowinfo = 0; dest_address6.sin6_scope_id = 0; memcpy(&dest_address6.sin6_addr, &ipv4mapped, sizeof(struct in6_addr)); memcpy(&dest_address6.sin6_addr.s6_addr[NAT64PREFIXLEN], &connaddr->sin_addr, sizeof(struct in_addr)); if (inet_ntop(AF_INET6, &dest_address6.sin6_addr, addrbuffer, sizeof(addrbuffer))) { show_msg(MSGDEBUG, "Trying IPv4-mapped IPv6 address %s...\n", addrbuffer); } if (realconnect(__fd, (struct sockaddr *)&dest_address6, sizeof(struct sockaddr_in6)) == 0) { show_msg(MSGDEBUG, "Success.\n"); return 0; } if (errno != ENETUNREACH) { show_msg(MSGDEBUG, "Error: %d (%s)\n", errno, sys_errlist[errno]); return -1; } else { show_msg(MSGDEBUG, "Error: %d (%s)\n", errno, sys_errlist[errno]); current_af = AF_INET6; failed++; } } else { /* Ok, so its not local, we need a path to the net */ pick_prefix(config, &path, &(connaddr->sin_addr), ntohs(connaddr->sin_port)); show_msg(MSGDEBUG, "Picked prefix %s for connection\n", (path->address ? path->address : "(Not Provided)")); if (path->address == NULL) { if (path == &(config->defaultprefix)) show_msg(MSGERR, "Connection needs to be made " "via default prefix but " "the default prefix has not " "been specified\n"); else show_msg(MSGERR, "Connection needs to be made " "via path specified at line " "%d in configuration file but " "the prefix has not been " "specified for this path\n", path->lineno); } else { /* Construct the NAT64-ed address */ dest_address6.sin6_family = AF_INET6; dest_address6.sin6_port = connaddr->sin_port; dest_address6.sin6_flowinfo = 0; dest_address6.sin6_scope_id = 0; memcpy(&dest_address6.sin6_addr, &path->prefix, sizeof(struct in6_addr)); memcpy(&dest_address6.sin6_addr.s6_addr[12], &connaddr->sin_addr, sizeof(struct in_addr)); if (inet_ntop(AF_INET6, &dest_address6.sin6_addr, addrbuffer, sizeof(addrbuffer))) { show_msg(MSGDEBUG, "Trying IPv6 address %s...\n", addrbuffer); } if (realconnect(__fd, (struct sockaddr *)&dest_address6, sizeof(struct sockaddr_in6)) == 0) { return 0; } if (errno != ENETUNREACH) { return -1; } else { current_af = AF_INET; failed++; } } } } /* If we haven't found a valid NAT64 prefix to route the connection, we return ECONNREFUSED */ errno = ECONNREFUSED; return -1; } static char afs[][16] = { "AF_UNSPEC", "AF_UNIX", "AF_INET", "AF_AX25", "AF_IPX", "AF_APPLETALK", "AF_NETROM", "AF_BRIDGE", "AF_ATMPVC", "AF_X25", "AF_INET6" }; int getpeername(GETPEERNAME_SIGNATURE) { /* If the real getpeername doesn't exist, we're stuffed */ if (realgetpeername == NULL) { show_msg(MSGERR, "Unresolved symbol: getpeername\n"); return (-1); } /* If we haven't initialized yet, do it now */ get_config(); show_msg(MSGDEBUG, "Got getpeername call for socket %d\n", __fd); struct sockaddr_in6 realpeer; socklen_t needlen = *__len; socklen_t realpeerlen = sizeof(realpeer); int ret = realgetpeername(__fd, __addr, &needlen); struct sockaddr_in * result; if (*__len < sizeof(struct sockaddr_in)) { *__len = sizeof(struct sockaddr_in); errno = EINVAL; return -1; } if (__addr->sa_family <= 10) show_msg(MSGDEBUG, "Address family is %s\n", afs[__addr->sa_family]); if (__addr->sa_family == AF_INET6) { int ret = realgetpeername(__fd, (struct sockaddr *)&realpeer, &realpeerlen); if ((!memcmp(&realpeer.sin6_addr, &ipv4mapped, NAT64PREFIXLEN)) || (check_prefix(config, &realpeer.sin6_addr))) { result = (struct sockaddr_in *)__addr; result->sin_family = AF_INET; result->sin_port = realpeer.sin6_port; memcpy(&result->sin_addr, &realpeer.sin6_addr.s6_addr[12], sizeof(struct in_addr)); *__len = sizeof(struct sockaddr_in); return ret; } } return ret; } int getsockname(GETSOCKNAME_SIGNATURE) { /* If the real getsockname doesn't exist, we're stuffed */ if (realgetsockname == NULL) { show_msg(MSGERR, "Unresolved symbol: getsockname\n"); return (-1); } if (realgetpeername == NULL) { show_msg(MSGERR, "Unresolved symbol: getpeername\n"); return (-1); } /* If we haven't initialized yet, do it now */ get_config(); show_msg(MSGDEBUG, "Got getsockname call for socket %d\n", __fd); struct sockaddr_in6 realpeer; socklen_t needlen = *__len; socklen_t realpeerlen = sizeof(realpeer); int ret = realgetsockname(__fd, __addr, &needlen); struct sockaddr_in * result; if (*__len < sizeof(struct sockaddr_in)) { *__len = sizeof(struct sockaddr_in); errno = EINVAL; return -1; } if (__addr->sa_family <= 10) show_msg(MSGDEBUG, "Address family is %s\n", afs[__addr->sa_family]); if (__addr->sa_family == AF_INET6) { int ret = realgetpeername(__fd, (struct sockaddr *)&realpeer, &realpeerlen); if ((!memcmp(&realpeer.sin6_addr, &ipv4mapped, NAT64PREFIXLEN)) || (check_prefix(config, &realpeer.sin6_addr))) { result = (struct sockaddr_in *)__addr; result->sin_family = AF_INET; result->sin_port = 0; memset(&result->sin_addr, 0, sizeof(struct in_addr)); *__len = sizeof(struct sockaddr_in); return ret; } } return ret; } andrew_shadoura-tnat64-tnat64-0.05/tnat64.conf.50000644000000000000000000001160111634674321017326 0ustar 00000000000000.TH TNAT64.CONF 5 "" "TNAT64" \" -*- \" nroff -* .SH NAME .BR tnat64.conf \- configuration file for tnat64(8) .SH OVERVIEW The configuration for tnat64 can be anything from two lines to hundreds of lines based on the needs at any particular site. The basic idea is to define any networks the machine can access directly via IPv4 and define one or many NAT64 prefixes to be used to access other networks (including a 'default' prefix). Local networks are declared using the 'local' keyword in the configuration file. When applications attempt to connect to machines in networks marked as local tnat64 will not attempt to use a NAT64 prefix. Obviously if a connection is not to a locally accessible network it will need to be proxied over a NAT64. However, sometimes you may need to use different NAT64 prefixes to access different internal (and external) networks. For this reason the configuration file allows the definition of 'paths' as well as a default NAT64 prefix. Paths are declared as blocks in the configuration file. That is, they begin with a 'path {' line in the configuration file and end with a '}' line. Inside this block directives should be used to declare a NAT64 proxy (as documented later in this manual page) and 'subnet' directives should be used to declare networks and even destination ports in those networks that this server should be used to reach. Please note that each path MUST define a NAT64 prefix and contain one or more 'subnet' directives. NAT64 prefix declaration directives that are not contained within a 'path' block define the default NAT64 prefix. If tnat64 needs to connect to a machine via a NAT64 (i.e it isn't a network declared as 'local') and no 'path' has declared it can reach that network via a 'subnet' directive, this NAT64 prefix is used to construct IPv6 addresses. .SH CONFIGURATION SYNTAX The basic structure of all lines in the configuration file is: .RS = .RE The exception to this is 'path' blocks which look like: .RS path { .RS = .RE } .RE Empty lines are ignored and all input on a line after a '#' character is ignored. .SS DIRECTIVES The following directives are used in the tnat64 configuration file: .TP .I nat64_prefix The prefix of IPv6 address of the NAT64 (e.g. "nat64_prefix = 64:ff9b::"). Only one NAT64 prefix may be specified per path block, or one outside a path block (to define the default NAT64 prefix). The NAT64 prefix is always /96. .TP .I local An IP/subnet pair specifying a network which may be accessed directly without proxying through NAT64 (e.g "local = 10.0.0.0/255.0.0.0"). .TP .I subnet This directive is only valid inside a path block. Its parameter is formed as IP[:startport[\-endport]]/subnet and it specifies a network (and a range of ports on that network) that can be accessed by through NAT64 specified in this path block. For example, in a path block "subnet = 150.0.0.0:80\-1024/255.0.0.0" indicates to tnat64 that the NAT64 prefix specified in the current path block should be used to access any IPs in the range 150.0.0.0 to 150.255.255.255 when the connection request is for ports 80\-1024. .SH UTILITIES tnat64 comes with two utilities that can be useful in creating and verifying the tnat64 configuration file. .TP tnat64-validateconf tnat64-validateconf can be used to verify the configuration file. It checks the format of the file and also the contents for errors. Having read the file it dumps the configuration to the screen in a formatted, readable manner. This can be extremely useful in debugging problems. tnat64-validateconf can read a configuration file from a location other than the location specified at compile time with the \-f command line option. Normally tnat64-validateconf simply dumps the configuration read to the screen (in a nicely readable format), however it also has a useful 'test' mode. When passed a hostname/ip on the command line like \-t , tnat64-validateconf determines which of the NAT64 prefixes specified in the configuration file would be used by tnat64 to access the specified host. .SH SEE ALSO tnat64(8) .SH AUTHORS Andrew O. Shadura (bugzilla@tut.by), Shaun Clowes (delius@progsoc.uts.edu.au) .SH COPYRIGHT Copyright 2011 Andrew O. Shadura Original tsocks manual page, copyright 2000 Shaun Clowes tnat64 and its documentation may be freely copied under the terms and conditions of version 2 of the GNU General Public License, as published by the Free Software Foundation (Cambridge, Massachusetts, United States of America). This documentation is heavily based on the documentation for tsocks, transparent SOCKSification library, whose documentation itself is based on the documentation for logwrites, another shared library interceptor. One line of code from it was used in tnat64 and a lot of the documentation :) logwrites is by adam@yggdrasil.com (Adam J. Richter) and can be had from ftp.yggdrasil.com pub/dist/pkg andrew_shadoura-tnat64-tnat64-0.05/tnat64.conf.complex.example0000644000000000000000000000244111634674321022265 0ustar 00000000000000# This is the configuration for libtsocks (transparent socks) # Lines beginning with # and blank lines are ignored # # The basic idea is to specify: # - Local subnets - Networks that can be accessed directly without # being routed to NAT64 # - Paths - Paths are basically lists of networks and NAT64 prefix # which can be used to reach these networks # - Default server - NAT64 prefix which should be used to access # networks for which no path is available # Much more documentation than provided in these comments can be found in # the man pages, tnat64(8) and tnat64.conf(8) # Local networks # For this example this machine can directly access 192.168.0.0/255.255.255.0 # (192.168.0.*) and 10.0.0.0/255.0.0.0 (10.*) local = 192.168.0.0/255.255.255.0 local = 10.0.0.0/255.0.0.0 # Paths # For this example this machine needs to access 150.0.0.0/255.255.0.0 as # well as port 80 on the network 150.1.0.0/255.255.0.0 through # the NAT64 with the prefix 2001:aaa:bbbb:0:ccc:616::/96 path { subnet = 150.0.0.0/255.255.0.0 subnet = 150.1.0.0:80/255.255.0.0 nat64_prefix = 2001:aaa:bbbb:0:ccc:616:: } # Default NAT64 prefix # For connections that aren't to the local subnets or to 150.0.0.0/255.255.0.0 # the NAT64 with the prefix 64:ff9b::/96 should be used nat64_prefix = 64:ff9b:: andrew_shadoura-tnat64-tnat64-0.05/tnat64.conf.simple.example0000644000000000000000000000114611634674321022110 0ustar 00000000000000# This is the configuration for libtnat64 (transparent NAT64) # Lines beginning with # and blank lines are ignored # # This sample configuration shows the simplest (and most common) use of # tnat64. This is a basic LAN, this machine can access anything on the # local ethernet (192.168.0.*) but anything else has to use the NAT64. # Further details can be found in the man pages, # tnat64(8) and tnat64.conf(5) and a more complex example is presented in # tnat64.conf.complex.example # We can access 192.168.0.* directly local = 192.168.0.0/255.255.255.0 # Otherwise we use the NAT64 nat64_prefix = 64:ff9b:: andrew_shadoura-tnat64-tnat64-0.05/tnat64.in0000755000000000000000000000421511634674321016652 0ustar 00000000000000#!/bin/sh # Wrapper script for use of the tnat64(8) library # # There are three forms of usage for this script: # # @bindir@/tnat64 program [program arguments...] # # This form sets the users LD_PRELOAD environment variable so that tsocks(8) # will be loaded to socksify the application then executes the specified # program (with the provided arguments). The following simple example might # be used to telnet to www.foo.org via a tnat64.conf(5) configured socks server: # # @bindir@/tnat64 telnet www.foo.org # # The second form allows for tnat64(8) to be switched on and off for a # session (that is, it adds and removes tnat64 from the LD_PRELOAD environment # variable). This form must be _sourced_ into the user's existing session # (and will only work with bourne shell users): # # . @bindir@/tnat64 on # telnet www.foo.org # . @bindir@/tnat64 off # # Or # # source @bindir@/tnat64 on # telnet www.foo.org # source @bindir@/tnat64 off # # The third form creates a new shell with LD_PRELOAD set and is achieved # simply by running the script with no arguments # # @bindir@/tnat64 # # When finished the user can simply terminate the shell with 'exit' # # This script is originally from the debian tsocks package by # Tamas Szerb if [ $# = 0 ] ; then echo "$0: insufficient arguments" exit fi case "$1" in on) if [ -z "$LD_PRELOAD" ] then export LD_PRELOAD="@pkglibdir@/libtnat64.so" else echo $LD_PRELOAD | grep -q "@pkglibdir@/libtnat64\.so" || \ export LD_PRELOAD="@pkglibdir@/libtnat64.so $LD_PRELOAD" fi ;; off) export LD_PRELOAD=$(echo -n $LD_PRELOAD | sed 's:@pkglibdir@/libtnat64.so \?::') if [ -z "$LD_PRELOAD" ] then unset LD_PRELOAD fi ;; show|sh) echo "LD_PRELOAD=\"$LD_PRELOAD\"" ;; -h|-?) echo "$0: Please see tnat64(1) or read comment at top of $0" ;; *) if [ -z "$LD_PRELOAD" ] then export LD_PRELOAD="@pkglibdir@/libtnat64.so" else echo $LD_PRELOAD | grep -q "@pkglibdir@/libtnat64\.so" || \ export LD_PRELOAD="@pkglibdir@/libtnat64.so $LD_PRELOAD" fi if [ $# = 0 ] then ${SHELL:-/bin/sh} fi if [ $# -gt 0 ] then exec "$@" fi ;; esac #EOF andrew_shadoura-tnat64-tnat64-0.05/validateconf.c0000644000000000000000000001462411634674321020007 0ustar 00000000000000/* VALIDATECONF - Part of the tnat64 package This utility can be used to validate the tnat64.conf configuration file Copyright (C) 2000 Shaun Clowes 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Global configuration variables */ char *progname = "tnat64-validateconf"; /* Name for error msgs */ /* Header Files */ #include #include #include #include #include #include #include #include #include #include #include #include void show_prefix(struct parsedfile *, struct prefixent *, int); void show_conf(struct parsedfile *config); void test_host(struct parsedfile *config, char *); int main(int argc, char *argv[]) { char *usage = "Usage: [-f conf file] [-t hostname/ip[:port]]"; char *filename = NULL; char *testhost = NULL; struct parsedfile config; int i; if ((argc > 5) || (((argc - 1) % 2) != 0)) { show_msg(MSGERR, "Invalid number of arguments\n"); show_msg(MSGERR, "%s\n", usage); exit(1); } for (i = 1; i < argc; i = i + 2) { if (!strcmp(argv[i], "-f")) { filename = argv[(i + 1)]; } else if (!strcmp(argv[i], "-t")) { testhost = argv[(i + 1)]; } else { show_msg(MSGERR, "Unknown option %s\n", argv[i]); show_msg(MSGERR, "%s\n", usage); exit(1); } } if (!filename) filename = strdup(CONF_FILE); printf("Reading configuration file %s...\n", filename); if (read_config(filename, &config) == 0) printf("... Read complete\n\n"); else exit(1); /* If they specified a test host, test it, otherwise */ /* dump the configuration */ if (!testhost) show_conf(&config); else test_host(&config, testhost); return (0); } void test_host(struct parsedfile *config, char *host) { struct in_addr hostaddr; struct prefixent *path; char *hostname, *port; char separator; unsigned long portno = 0; /* See if a port has been specified */ hostname = strsplit(&separator, &host, ": \t\n"); if (separator == ':') { port = strsplit(NULL, &host, " \t\n"); if (port) portno = strtol(port, NULL, 0); } /* First resolve the host to an ip */ if ((hostaddr.s_addr = resolve_ip(hostname, 0, 1)) == -1) { fprintf(stderr, "Error: Cannot resolve %s\n", host); return; } else { printf("Finding path for %s...\n", inet_ntoa(hostaddr)); if (!(is_local(config, &(hostaddr)))) { printf("Path is local\n"); } else { pick_prefix(config, &path, &hostaddr, portno); if (path == &(config->defaultprefix)) { printf("Path is reached via default NAT64 prefix:\n"); show_prefix(config, path, 1); } else { printf("Host is reached via this path:\n"); show_prefix(config, path, 0); } } } return; } void show_conf(struct parsedfile *config) { struct netent *net; struct prefixent *prefix; /* Show the local networks */ printf("=== Local networks (no NAT64 needed) ===\n"); net = (config->localnets); while (net != NULL) { printf("Network: %15s ", inet_ntoa(net->localip)); printf("Netmask: %15s\n", inet_ntoa(net->localnet)); net = net->next; } printf("\n"); /* If we have a default prefix configuration show it */ printf("=== Default NAT64 prefix configuration ===\n"); if ((config->defaultprefix).address != NULL) { show_prefix(config, &(config->defaultprefix), 1); } else { printf("No default NAT64 prefix specified, this is rarely a " "good idea\n"); } printf("\n"); /* Now show paths */ if ((config->paths) != NULL) { prefix = (config->paths); while (prefix != NULL) { printf("=== Path (line no %d in configuration file)" " ===\n", prefix->lineno); show_prefix(config, prefix, 0); printf("\n"); prefix = prefix->next; } } return; } void show_prefix(struct parsedfile *config, struct prefixent *prefix, int def) { struct netent *net; /* Show address */ if (prefix->address != NULL) printf("NAT64 prefix: %s\n", prefix->address); else printf("NAT64 prefix: ERROR! None specified\n"); /* If this is the default servers and it has reachnets, thats stupid */ if (def) { if (prefix->reachnets != NULL) { fprintf(stderr, "Error: The default NAT64 prefix has " "specified networks it can be used to reach (subnet statements), " "these statements are ignored since the " "default NAT64 prefix will be used for any network " "which is not specified in a subnet statement " "for other prefixes\n"); } } else if (prefix->reachnets == NULL) { fprintf(stderr, "Error: No subnet statements specified for " "this NAT64 prefix, it will never be used\n"); } else { printf("This NAT64 prefix can be used to reach:\n"); net = prefix->reachnets; while (net != NULL) { printf("Network: %15s ", inet_ntoa(net->localip)); printf("Netmask: %15s ", inet_ntoa(net->localnet)); if (net->startport) printf("Ports: %5lu - %5lu", net->startport, net->endport); printf("\n"); net = net->next; } } }