From b1e9ce6d2a77e453e771ed21670a80effc830a16 Mon Sep 17 00:00:00 2001 From: Luca Deri Date: Sun, 23 Oct 2016 10:46:15 +0200 Subject: [PATCH] Initial SVN import of n2n v2 --- CMakeLists.txt | 131 ++ COPYING | 674 ++++++ HACKING | 255 ++ INSTALL | 50 + Makefile | 101 + NEW_FEATURES.txt | 6 + README.md | 112 + benchmark.c | 110 + debian/README.Debian | 7 + debian/changelog | 27 + debian/compat | 1 + debian/control | 51 + debian/copyright | 23 + debian/n2n-edge.default | 21 + debian/n2n-edge.docs | 1 + debian/n2n-edge.init | 129 ++ debian/n2n-edge.install | 1 + debian/n2n-edge.manpages | 2 + debian/n2n-supernode.init | 121 + debian/n2n-supernode.install | 1 + debian/n2n-supernode.manpages | 1 + debian/rules | 5 + edge.8 | 208 ++ edge.c | 2412 +++++++++++++++++++ gen_keyfile.py | 44 + lzoconf.h | 417 ++++ lzodefs.h | 1807 +++++++++++++++ minilzo.c | 4112 +++++++++++++++++++++++++++++++++ minilzo.h | 106 + n2n.c | 455 ++++ n2n.h | 254 ++ n2n.spec | 52 + n2n_keyfile.c | 203 ++ n2n_keyfile.h | 101 + n2n_transforms.h | 78 + n2n_v2.7 | 156 ++ n2n_wire.h | 321 +++ openwrt/kamikaze/Makefile | 55 + scripts/mk_SRPM.sh | 30 + scripts/mk_deb.sh | 46 + scripts/mk_tar.sh | 116 + sn.c | 793 +++++++ supernode.1 | 43 + test.c | 24 + transform_aes.c | 597 +++++ transform_null.c | 84 + transform_tf.c | 487 ++++ tuntap_freebsd.c | 132 ++ tuntap_linux.c | 165 ++ tuntap_netbsd.c | 146 ++ tuntap_osx.c | 132 ++ twofish.c | 1031 +++++++++ twofish.h | 292 +++ version.c | 3 + win32/CMakeLists.txt | 4 + win32/DotNet/n2n.sln | 26 + win32/DotNet/n2n.suo | Bin 0 -> 24576 bytes win32/DotNet/n2n.vcproj | 300 +++ win32/DotNet/supernode.vcproj | 226 ++ win32/getopt.c | 1074 +++++++++ win32/getopt.h | 169 ++ win32/getopt1.c | 188 ++ win32/n2n_win32.h | 109 + win32/version-msvc.c | 3 + win32/wintap.c | 310 +++ win32/wintap.h | 67 + wire.c | 461 ++++ 67 files changed, 19669 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 COPYING create mode 100644 HACKING create mode 100644 INSTALL create mode 100644 Makefile create mode 100644 NEW_FEATURES.txt create mode 100644 README.md create mode 100644 benchmark.c create mode 100644 debian/README.Debian create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/n2n-edge.default create mode 100644 debian/n2n-edge.docs create mode 100755 debian/n2n-edge.init create mode 100644 debian/n2n-edge.install create mode 100644 debian/n2n-edge.manpages create mode 100755 debian/n2n-supernode.init create mode 100644 debian/n2n-supernode.install create mode 100644 debian/n2n-supernode.manpages create mode 100755 debian/rules create mode 100644 edge.8 create mode 100644 edge.c create mode 100755 gen_keyfile.py create mode 100644 lzoconf.h create mode 100644 lzodefs.h create mode 100644 minilzo.c create mode 100644 minilzo.h create mode 100644 n2n.c create mode 100644 n2n.h create mode 100644 n2n.spec create mode 100644 n2n_keyfile.c create mode 100644 n2n_keyfile.h create mode 100644 n2n_transforms.h create mode 100644 n2n_v2.7 create mode 100644 n2n_wire.h create mode 100644 openwrt/kamikaze/Makefile create mode 100755 scripts/mk_SRPM.sh create mode 100755 scripts/mk_deb.sh create mode 100755 scripts/mk_tar.sh create mode 100644 sn.c create mode 100644 supernode.1 create mode 100644 test.c create mode 100644 transform_aes.c create mode 100644 transform_null.c create mode 100644 transform_tf.c create mode 100644 tuntap_freebsd.c create mode 100644 tuntap_linux.c create mode 100644 tuntap_netbsd.c create mode 100644 tuntap_osx.c create mode 100644 twofish.c create mode 100644 twofish.h create mode 100644 version.c create mode 100644 win32/CMakeLists.txt create mode 100644 win32/DotNet/n2n.sln create mode 100644 win32/DotNet/n2n.suo create mode 100644 win32/DotNet/n2n.vcproj create mode 100644 win32/DotNet/supernode.vcproj create mode 100644 win32/getopt.c create mode 100644 win32/getopt.h create mode 100644 win32/getopt1.c create mode 100644 win32/n2n_win32.h create mode 100644 win32/version-msvc.c create mode 100644 win32/wintap.c create mode 100644 win32/wintap.h create mode 100644 wire.c diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..c9ad81c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,131 @@ +project(n2n) +cmake_minimum_required(VERSION 2.6) + +# N2n information +set(N2N_VERSION 2.1.0) +set(N2N_OSNAME ${CMAKE_SYSTEM}) + +# N2n specific params +if(NOT DEFINED N2N_OPTION_AES) +set(N2N_OPTION_AES ON) +endif(NOT DEFINED N2N_OPTION_AES) + +add_definitions(-DN2N_VERSION='\"${N2N_VERSION}\"' -DN2N_OSNAME='\"${N2N_OSNAME}\"') + +if(N2N_OPTION_AES) +add_definitions(-DN2N_HAVE_AES) +endif(N2N_OPTION_AES) + +# Build information +if(NOT DEFINED BUILD_SHARED_LIBS) +set(BUILD_SHARED_LIBS OFF) +endif(NOT DEFINED BUILD_SHARED_LIBS) + +if(NOT DEFINED CMAKE_BUILD_TYPE) +set(CMAKE_BUILD_TYPE None) +endif(NOT DEFINED CMAKE_BUILD_TYPE) +#set(CMAKE_BUILD_TYPE Debug) +#set(CMAKE_BUILD_TYPE Release) + +#Ultrasparc64 users experiencing SIGBUS should try the following gcc options +#(thanks to Robert Gibbon) +#PLATOPTS_SPARC64=-mcpu=ultrasparc -pipe -fomit-frame-pointer -ffast-math -finline-functions -fweb -frename-registers -mapp-regs + +# None +set(CMAKE_C_FLAGS "-Wall -Wshadow -Wpointer-arith -Wmissing-declarations -Wnested-externs") +set(CMAKE_CXX_FLAGS "-Wall -Wshadow -Wpointer-arith -Wmissing-declarations -Wnested-externs") +# Debug +set(CMAKE_C_FLAGS_DEBUG "-g") +set(CMAKE_CXX_FLAGS_DEBUG "-g") +# Release +set(CMAKE_C_FLAGS_RELEASE "-O2 -DNDEBUG") +set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG") + +## DEBUG FOR CMAKE +#message(${N2N_VERSION}) +#message(${N2N_OSNAME}) +##message(${CMAKE_BUILD_TYPE}) +#message(${N2N_OPTION_AES}) +## DEBUG FOR CMAKE + +add_library(n2n n2n.c + n2n_keyfile.c + wire.c + minilzo.c + twofish.c + transform_null.c + transform_tf.c + transform_aes.c + tuntap_freebsd.c + tuntap_netbsd.c + tuntap_linux.c + tuntap_osx.c + version.c + ) + +if(DEFINED WIN32) +add_subdirectory(win32) +target_link_libraries(n2n n2n_win32) +endif(DEFINED WIN32) + +if(N2N_OPTION_AES) +target_link_libraries(n2n crypto) +endif(N2N_OPTION_AES) + +# For Solaris (or OpenSolaris?) +#target_link_libraries(n2n socket nsl) + +add_executable(edge edge.c) +target_link_libraries(edge n2n) + +add_executable(supernode sn.c) +target_link_libraries(supernode n2n) + +add_executable(test test.c) +target_link_libraries(test n2n) + +add_executable(benchmark benchmark.c) +target_link_libraries(benchmark n2n) + +install(TARGETS edge supernode + RUNTIME DESTINATION sbin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + ) + +# Documentation +if(DEFINED UNIX) +add_dependencies(n2n doc) +file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/doc) +add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/doc/edge.8.gz + COMMAND gzip -c ${PROJECT_SOURCE_DIR}/edge.8 > ${PROJECT_BINARY_DIR}/doc/edge.8.gz + DEPENDS ${PROJECT_SOURCE_DIR}/edge.8 + ) + +add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/doc/supernode.1.gz + COMMAND gzip -c ${PROJECT_SOURCE_DIR}/supernode.1 > ${PROJECT_BINARY_DIR}/doc/supernode.1.gz + DEPENDS ${PROJECT_SOURCE_DIR}/supernode.1 + ) + +add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/doc/n2n_v2.7.gz + COMMAND gzip -c ${PROJECT_SOURCE_DIR}/n2n_v2.7 > ${PROJECT_BINARY_DIR}/doc/n2n_v2.7.gz + DEPENDS ${PROJECT_SOURCE_DIR}/n2n_v2.7 + ) + +add_custom_target(doc DEPENDS ${PROJECT_BINARY_DIR}/doc/edge.8.gz + ${PROJECT_BINARY_DIR}/doc/supernode.1.gz + ${PROJECT_BINARY_DIR}/doc/n2n_v2.7.gz + ) + +set_source_files_properties(${PROJECT_BINARY_DIR}/doc/edge.8.gz + ${PROJECT_BINARY_DIR}/doc/supernode.1.gz + ${PROJECT_BINARY_DIR}/doc/n2n_v2.7.gz + PROPERTIES GENERATED 1) + +install(FILES ${PROJECT_BINARY_DIR}/doc/edge.8.gz + DESTINATION /usr/share/man8) +install(FILES ${PROJECT_BINARY_DIR}/doc/supernode.1.gz + DESTINATION /usr/share/man1) +install(FILES ${PROJECT_BINARY_DIR}/doc/n2n_v2.7.gz + DESTINATION /usr/share/man7) +endif(DEFINED UNIX) diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..b33b35d --- /dev/null +++ b/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. 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 +them 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 prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. 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. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey 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; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If 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 convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + 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. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +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. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + 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 +state 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) + + 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 3 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, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + n2n Copyright (C) 2007-08 Luca Deri + This program 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, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU 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 Lesser General +Public License instead of this License. But first, please read +. diff --git a/HACKING b/HACKING new file mode 100644 index 0000000..8a86a03 --- /dev/null +++ b/HACKING @@ -0,0 +1,255 @@ +file: HACKING + +Last updated: 2010-01-01 09:55 UTC + +-------- +(C) 2008-2010 - Richard Andrews + +This program and document 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 3 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 see see + +-------- + + +This file describes the internals of n2n. Read this before starting to modify +the code. Because coding examples may be present in this document it is licensed +under the GPL rather than FDL. + + +SYMMETRIC NAT +------------- + +Symmetric NAT is a form of firewall NAT in which an UDP packets are only passed +back to an inside host socket when the return packets originate from the outside +socket to which the initiating UDP packets were sent. This means that when an +inside host sends UDP to some outside socket; other hosts cannot piggyback on +this opening in the firewall to send data to the inside host. + +When two inside hosts are both behind symmetric NAT, peer-to-peer packet +exchange is not possible via n2n. These hosts will require the supernode to +relay packets. + + +ARP CACHE +--------- + +n2n makes use of the host operating system's own ARP cache. Each edge node +allocates a random MAC address to itself. This MAC is constant for the life of +the edge process. ARP packets are passed around as broadcast ethernet packets +over n2n and these packets cause the native ARP cache to be updated. + +Edge nodes send gratuitous ARP packets on startup. See GRATUITOUS ARP below. + + +REGISTRATION AND PEER-TO-PEER COMMUNICATION SETUP +------------------------------------------------- + +A and B are edge nodes with public sockets Apub and Bpub; and private network +addresses A and B respectively. S is the supernode. + +A sends {REGISTER,Amac} to S. S registers {Amac->Apub}. +B sends {REGISTER,Bmac} to S. S registers {Bmac->Bpub}. + +Now ping from A to B. + +A sends broadcast "arp who-has B" to S. S relays the packet to all known edge +nodes. B replies "B at Bmac" to supernode which forwards this to A. So now ping +A->B is known to be ping Amac(A)->Bmac(B). Note: gratuitous arp also requires +discussion. + +In response to receiving the arp reply, Apub sends {REGISTER,Amac} to Bpub. If +Bpub receives the request it sends back {REGISTER_ACK,Amac} and also sends its +own {REGISTER,Bmac} request. + +In response to receiving the "arp who-has", Bpub sends {REGISTER,Bmac} to Apub. + +Now the OS has received the arp reply and sends ICMP to Bmac(B) via the tunnel +on A. A looks up Bmac in the peers list and encapsulates the packet to Bpub or +the supernode if the MAC is not found. + +We assume that between two edge nodes, if Bpub receives a packet from Apub then +Apub can receive a packet from Bpub. This is the symmetric NAT case. Note: In +the symmetric NAT case, the public socket for a MAC address will be different +for direct contact when compared to information from the supernode. + +When two edge nodes are both behind symmetric NAT they cannot establish direct +communication. + +If A receives {REGISTER,Bmac} from B, A adds {Bmac->Bpub} to its peers list +knowing that Bmac is now reachable via that public socket. Similarly if B +receives {REGISTER,Amac} from A. + +The supernode never forwards REGISTER messages because the public socket seen by +the supervisor for some edge (eg. A) may be different to the socket seen by +another edge due to the actions of symmetric NAT (alocating a new public socket +for the new outbound UDP "connection"). + + +EDGE REGISTRATION DESIGN AMMENDMENTS (starting from 2008-04-10) +------------------------------------ + + * Send REGISTER on rx of PACKET or REGISTER only when dest_mac == device MAC +(do not send REGISTER on Rx of broadcast packets). + * After sending REGISTER add the new peer to pending_peers list; but + * Don't send REGISTER to a peer in pending_peers list + * Remove old entries from pending_peers at regular intervals + * On rx of REGISTER_ACK, move peer from pending_peers to known_peers for direct +comms and set last_seen=now + * On rx of any packet set last_seen=now in the known_peers entry (if it +exists); but do not add a new entry. + * If the public socket address for a known_peers entry changes, deleted it and +restart registration to the new peer. + * Peer sockets provided by the supernode are ignored unless no other entry +exists. Direct peer-to-peer sockets are always given more priority as the +supernode socket will not be usable for direct contact if the peer is behind +symmetric NAT. + + +The pending_peers list concept is to prevent massive registration traffic when +supernode relay is in force - this would occur if REGISTER was sent for every +incident packet sent via supernode. Periodic REGISTER attempts will still occur; +not for every received packet. In the case where the peer cannot be contacted +(eg. both peers behind symmetric NAT), then there will still be periodic +attempts. Suggest a pending timeout of about 60 sec. + +A peer is only considered operational for peer-to-peer sending when a +REGISTER_ACK is returned. Once operational the peer is kept operational while +any direct packet communications are occurring. REGISTER is not required to +keep the path open through any firewalls; just some activity in one direction. + +After an idle period; the peer should be deleted from the known_peers list. We +should not try to re-register when this time expires. If there is no data to +send then forget the peer. This helps scalability. + +If a peer wants to be remembered it can send gratuitous ARP traffic which will +keep its entry in the known_peers list of any peers which already have the +entry. + + + + +peer = find_by_src_mac( hdr, known_peers ); /* return NULL or entry */ + +if ( peer ) +{ + peer_last_seen = time(NULL); +} +else +{ + if ( ! is_broadcast( hdr ) ) /* ignore broadcasts */ + { + if ( IS_REGISTER_ACK( hdr ) ) + { + /* move from pending to known_peers */ + set_peer_operational( hdr ); + } + else + { + /* add to pending and send REGISTER - ignore if in pending. */ + try_send_register( hdr ) + } + } +} + + +(Notes): + + * In testing it was noted that if a symmetric NAT firewall shuts down the UDP +association but the known_peers registration is still active, then the peer +becomes unreachable until the known_peers registration is deleted. Suggest two +ways to mitigate this problem: + (a) make the known_peers purge timeout a config paramter; + (b) send packets direct and via supernode if the registration is older than + eg. 60 sec. + + +GRATUITOUS ARP +-------------- + +In addition to the ARP who-has mechanism noted above, two edge nodes can become +aware of one another by gratuitous ARP. A gratuitous ARP packet is a broadcast +packet sent by a node for no other purpose than to announce its presence and +identify its MAC and IP address. Gratuitous ARP packets are to keep ARP caches +up to date so contacting the host will be faster after an long idle time. + + +MAN PAGES +--------- + +Look at a non-installed man page like this (linux/UNIX): + +nroff -man edge.8 | less + + +PACKET message FORMAT +--------------------- + +All message encoding and decoding is contained in wire.c. The PACKET message is +of main concern as it is the most frequently transferred as it contains +encapsulated ethernet packets. + +Version 2 + + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Version=2 ! TTL ! Flags ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + 4 ! Community : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + 8 ! ... Community ... : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +12 ! ... Community ... : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +16 ! ... Community ... ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +20 ! Source MAC Address : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +24 : ! Destination MAC Address : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +28 : ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +32 ! Socket Flags (v=IPv4) ! Destination UDP Port ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +36 ! Destination IPv4 Address ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +40 ! Transform ID ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +44 ! Payload + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +So each n2n PACKET has a 44 byte overhead. For a 1500 byte ethernet packet this +is roughly 3%. + +Socket flags provides support for IPv6. In this case the PACKET message ends as +follows: + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +32 ! Socket Flags (v=IPv6) ! Destination UDP Port ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +36 ! Destination IPv6 Address : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +40 : : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +44 : : + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +48 : ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +52 ! Transform ID ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +56 ! Encapsulated ethernet payload + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +------- + +January 2010 - Richard Andrews diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..2200032 --- /dev/null +++ b/INSTALL @@ -0,0 +1,50 @@ +INSTALL + +To build the programs: + +$ make + +To install the programs and man pages: + +$ make install + +or + +$ make PREFIX=/usr/local install + + +RPM Package +----------- + +These steps should work with RPM based Linux distributions since rpmbuild was +split from the rpm utility (c RedHat 9). + + +To build an RPM the easy way follow these steps. + +1. Build SRPM + +$ cd n2n +$ scripts/mk_SRPM.sh + +Look for where the src.rpm file was put ( "Wrote:" ). + +2. Build binary RPM from SRPM + +$ rpm -i path/to/n2n-.src.rpm +$ rpmbuild -bb n2n.spec + + +All this can be done as non-root user if you have a ~/.rpmmacros file with this +line in it: + +%_topdir /home/username/rpmtopdir + + +To build an RPM the hard way follow these steps. + +$ cp -a n2ndir n2n-2.0 +$ tar czf n2n-2.0.tar.gz n2n-2.0 +$ mv n2n-2.0.tar.gz /usr/src/redhat/SOURCES +$ cp n2ndir/n2n.spec /usr/src/redhat/SPECS +$ rpmbuild -bb n2n.spec diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b670978 --- /dev/null +++ b/Makefile @@ -0,0 +1,101 @@ + +N2N_VERSION=2.1.0 +N2N_OSNAME=$(shell uname -p) + +######## + +CC=gcc +DEBUG?=-g3 +#OPTIMIZATION?=-O2 +WARN?=-Wall -Wshadow -Wpointer-arith -Wmissing-declarations -Wnested-externs + +#Ultrasparc64 users experiencing SIGBUS should try the following gcc options +#(thanks to Robert Gibbon) +PLATOPTS_SPARC64=-mcpu=ultrasparc -pipe -fomit-frame-pointer -ffast-math -finline-functions -fweb -frename-registers -mapp-regs + +N2N_DEFINES= +N2N_OBJS_OPT= +LIBS_EDGE_OPT= + +N2N_OPTION_AES?="yes" +#N2N_OPTION_AES=no + +ifeq ($(N2N_OPTION_AES), "yes") + N2N_DEFINES+="-DN2N_HAVE_AES" + LIBS_EDGE_OPT+=-lcrypto +endif + +CFLAGS+=$(DEBUG) $(OPTIMIZATION) $(WARN) $(OPTIONS) $(PLATOPTS) $(N2N_DEFINES) + +INSTALL=install +MKDIR=mkdir -p + +INSTALL_PROG=$(INSTALL) -m755 +INSTALL_DOC=$(INSTALL) -m644 + + +# DESTDIR set in debian make system +PREFIX?=$(DESTDIR)/usr +#BINDIR=$(PREFIX)/bin +SBINDIR=$(PREFIX)/sbin +MANDIR?=$(PREFIX)/share/man +MAN1DIR=$(MANDIR)/man1 +MAN7DIR=$(MANDIR)/man7 +MAN8DIR=$(MANDIR)/man8 + +N2N_LIB=n2n.a +N2N_OBJS=n2n.o n2n_keyfile.o wire.o minilzo.o twofish.o \ + transform_null.o transform_tf.o transform_aes.o \ + tuntap_freebsd.o tuntap_netbsd.o tuntap_linux.o tuntap_osx.o version.o +LIBS_EDGE+=$(LIBS_EDGE_OPT) +LIBS_SN= + +#For OpenSolaris (Solaris too?) +ifeq ($(shell uname), SunOS) +LIBS_EDGE+=-lsocket -lnsl +LIBS_SN+=-lsocket -lnsl +endif + +APPS=edge +APPS+=supernode + +DOCS=edge.8.gz supernode.1.gz n2n_v2.7.gz + +all: $(APPS) $(DOCS) + +edge: edge.c $(N2N_LIB) n2n_wire.h n2n.h Makefile + $(CC) $(CFLAGS) edge.c $(N2N_LIB) $(LIBS_EDGE) -o edge + +test: test.c $(N2N_LIB) n2n_wire.h n2n.h Makefile + $(CC) $(CFLAGS) test.c $(N2N_LIB) $(LIBS_EDGE) -o test + +supernode: sn.c $(N2N_LIB) n2n.h Makefile + $(CC) $(CFLAGS) sn.c $(N2N_LIB) $(LIBS_SN) -o supernode + +benchmark: benchmark.c $(N2N_LIB) n2n_wire.h n2n.h Makefile + $(CC) $(CFLAGS) benchmark.c $(N2N_LIB) $(LIBS_SN) -o benchmark + +.c.o: n2n.h n2n_keyfile.h n2n_transforms.h n2n_wire.h twofish.h Makefile + $(CC) $(CFLAGS) -c $< + +%.gz : % + gzip -c $< > $@ + +$(N2N_LIB): $(N2N_OBJS) + ar rcs $(N2N_LIB) $(N2N_OBJS) +# $(RANLIB) $@ + +version.o: Makefile + $(CC) $(CFLAGS) -DN2N_VERSION='"$(N2N_VERSION)"' -DN2N_OSNAME='"$(N2N_OSNAME)"' -c version.c + +clean: + rm -rf $(N2N_OBJS) $(N2N_LIB) $(APPS) $(DOCS) test *.dSYM *~ + +install: edge supernode edge.8.gz supernode.1.gz n2n_v2.7.gz + echo "MANDIR=$(MANDIR)" + $(MKDIR) $(SBINDIR) $(MAN1DIR) $(MAN7DIR) $(MAN8DIR) + $(INSTALL_PROG) supernode $(SBINDIR)/ + $(INSTALL_PROG) edge $(SBINDIR)/ + $(INSTALL_DOC) edge.8.gz $(MAN8DIR)/ + $(INSTALL_DOC) supernode.1.gz $(MAN1DIR)/ + $(INSTALL_DOC) n2n_v2.7.gz $(MAN7DIR)/ diff --git a/NEW_FEATURES.txt b/NEW_FEATURES.txt new file mode 100644 index 0000000..9efc587 --- /dev/null +++ b/NEW_FEATURES.txt @@ -0,0 +1,6 @@ + +Between 2.0.x and 2.1.x + +* Better ming Windows build support. +* Added -E flag to allow multicast ethernet traffic. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..cdc655a --- /dev/null +++ b/README.md @@ -0,0 +1,112 @@ + + +Edge node +--------- + +You need to start an edge node on each host you want to connect with the *same* +community. + +0. become root + +1. create tun device +# tunctl -t tun0 + +3. enable the edge process +# ./edge -d n2n0 -c mynetwork -k encryptme -u 99 -g 99 -m 3C:A0:12:34:56:78 -a 1.2.3.4 -l a.b.c.d:xyw + or +# N2N_KEY=encryptme ./edge -d n2n0 -c mynetwork -u 99 -g 99 -m 3C:A0:12:34:56:78 -a 1.2.3.4 -l a.b.c.d:xyw + +Once you have this worked out, you can add the "-f" option to make edge detach +and run as a daemon. + +Note that -u, -g and -f options are not available for Windows. + +Supernode +-------- + +You need to start the supernode once + +1. ./supernode -l 1234 -v + + +Dropping Root Privileges and SUID-Root Executables (UNIX) +-------------------------------------------------- + +The edge node uses superuser privileges to create a TAP network interface +device. Once this is created root privileges are not required and can constitute +a security hazard if there is some way for an attacker to take control of an +edge process while it is running. Edge will drop to a non-privileged user if you +specify the -u and -g options. These are numeric IDs. Consult +/etc/passwd. + +You may choose to install edge SUID-root to do this: + +1. Become root +2. chown root:root edge +3. chmod +s edge +done + +Any user can now run edge. You may not want this, but it may be convenient and +safe if your host has only one login user. + + +Running As a Daemon (UNIX) +------------------- + +Unless given "-f" as a command line option, edge will call daemon(3) after +successful setup. This causes the process to fork a child which closes stdin, +stdout and stderr then sets itself as process group leader. When this is done, +the edge command returns immediately and you will only see the edge process in +the process listings, eg. from ps or top. + +If the edge command returns 0 then the daemon started successfully. If it +returns non-zero then edge failed to start up for some reason. When edge starts +running as a daemon, all logging goes to syslog daemon.info facility. + + +IPv6 Support +------------ + +n2n supports the carriage of IPv6 packets within the n2n tunnel. N2n does not +yet use IPv6 for transport between edges and supernodes. + +To make IPv6 carriage work you need to manually add IPv6 addresses to the TAP +interfaces at each end. There is currently no way to specify an IPv6 address on +the edge command line. + +eg. under linux: + +on hostA: +[hostA] # /sbin/ip -6 addr add fc00:abcd:1234::7/48 dev n2n0 + +on hostB: +[hostB] # /sbin/ip -6 addr add fc00:abcd:1234::6/48 dev n2n0 + +You may find it useful to make use of tunctl from the uml-utilities +package. Tunctl allow you to bring up a TAP interface and configure addressing +prior to starting edge. It also allows edge to be restarted without the +interface closing (which would normally affect routing tables). + +Once the IPv6 addresses are configured and edge started, IPv6 neighbor discovery +packets flow (get broadcast) and IPv6 entities self arrange. Test your IPv6 +setup with ping6 - the IPv6 ping command. + + +Performance Notes +----------------- + +The time taken to perform a ping test for various ciphers is given below: + +Test: ping -f -l 8 -s 800 -c 10000 + +AES (-O0) 11820 +TF (-O0) 25761 + +TF (-O2) 20554 + +AES (-O3) 12532 +TF (-O3) 14046 +NULL (-O3) 10659 + +(C) 2007-2010 - Luca Deri , Richard Andrews +(C) 2016 - ntop \ No newline at end of file diff --git a/benchmark.c b/benchmark.c new file mode 100644 index 0000000..f6802ce --- /dev/null +++ b/benchmark.c @@ -0,0 +1,110 @@ +#include "n2n_wire.h" +#include "n2n_transforms.h" +#include "n2n.h" + +#include +#include +#include +#include + +uint8_t PKT_CONTENT[]={ + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 }; + +/* Prototypes */ +static ssize_t do_encode_packet( uint8_t * pktbuf, size_t bufsize, const n2n_community_t c ); + +int main( int argc, char * argv[] ) +{ + uint8_t pktbuf[N2N_PKT_BUF_SIZE]; + n2n_trans_op_t transop_null; + + n2n_common_t cmn; + n2n_PACKET_t pkt; + n2n_community_t c; + + struct timeval t1; + struct timeval t2; + + size_t i; + size_t n; + size_t idx; + size_t rem; + ssize_t nw; + ssize_t tdiff; + + transop_null_init( &transop_null ); + memset(c,0,sizeof(N2N_COMMUNITY_SIZE)); + + n=10000; + memcpy( c, "abc123def456", 12 ); + + gettimeofday( &t1, NULL ); + for(i=0; i %u nsec each) %u.%06u -> %u.%06u.\n", i, tdiff, (tdiff *1000)/i, (uint32_t)t1.tv_sec, (uint32_t)t1.tv_usec, (uint32_t)t2.tv_sec, (uint32_t)t2.tv_usec ); + + return 0; +} + +static ssize_t do_encode_packet( uint8_t * pktbuf, size_t bufsize, const n2n_community_t c ) +{ + n2n_mac_t destMac={0,1,2,3,4,5}; + n2n_common_t cmn; + n2n_PACKET_t pkt; + size_t idx; + + + memset( &cmn, 0, sizeof(cmn) ); + cmn.ttl = N2N_DEFAULT_TTL; + cmn.pc = n2n_packet; + cmn.flags=0; /* no options, not from supernode, no socket */ + memcpy( cmn.community, c, N2N_COMMUNITY_SIZE ); + + memset( &pkt, 0, sizeof(pkt) ); + memcpy( pkt.srcMac, destMac, N2N_MAC_SIZE); + memcpy( pkt.dstMac, destMac, N2N_MAC_SIZE); + + pkt.sock.family=0; /* do not encode sock */ + + idx=0; + encode_PACKET( pktbuf, &idx, &cmn, &pkt ); + traceEvent( TRACE_DEBUG, "encoded PACKET header of size=%u", (unsigned int)idx ); + + return idx; +} diff --git a/debian/README.Debian b/debian/README.Debian new file mode 100644 index 0000000..700c74e --- /dev/null +++ b/debian/README.Debian @@ -0,0 +1,7 @@ +n2n for Debian +-------------- + +This package depends on the kernel having the TUN/TAP driver configured in using +CONFIG_TUN=yes. + + -- Richard Andrews Thu, 10 Jul 2008 22:38:02 +1000 diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..bd31a4f --- /dev/null +++ b/debian/changelog @@ -0,0 +1,27 @@ +n2n (2.1.0-1) unstable; urgency=low + + * Split package in two. + * Move manpage for edge to section 8. + * Install manpage for n2n_v2 to section 7. + * Create init.d files for the daemons. + + -- Kim Hansen Sun, 04 Apr 2010 21:40:46 +0200 + +n2n (2.0-1) hardy; urgency=low + + * New upstream release + + -- Richard Andrews Tue, 30 Oct 2009 22:26:04 +1100 + +n2n (1.3-1) hardy; urgency=low + + * New upstream release + + -- Richard Andrews Fri, 30 Jan 2009 23:49:56 +1100 + +n2n (1.2-1) unstable; urgency=low + + * Initial release + + -- Richard Andrews Thu, 10 Jul 2008 22:38:02 +1000 + diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +5 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..1bdb6fa --- /dev/null +++ b/debian/control @@ -0,0 +1,51 @@ +Source: n2n +Section: net +Priority: extra +Maintainer: Jean-Baptiste Denis +Build-Depends: cdbs, debhelper (>= 5), libc6-dev (>= 2.0), dpatch, gcc, libssl-dev +Standards-Version: 3.7.2 + +Package: n2n +Architecture: any +Depends: n2n-edge, n2n-supernode +Description: dummy package for transition purposes + A dummy package for transition purposes that depends on n2n-edge and + n2n-supernode + +Package: n2n-edge +Architecture: any +Suggests: uml-utilities +Depends: ${shlibs:Depends}, ${misc:Depends} +Conflicts: n2n (<< 2.1.0-1) +Replaces: n2n (<< 2.1.0-1) +Description: a layer-two peer-to-peer virtual private network (VPN) + n2n is a layer-two peer-to-peer virtual private network (VPN) which allows + users to exploit features typical of P2P applications at network instead of + application level. This means that users can gain native IP visibility (e.g. + two PCs belonging to the same n2n network can ping each other) and be + reachable with the same network IP address regardless of the network where + they currently belong. In a nutshell, as OpenVPN moved SSL from application + (e.g. used to implement the https protocol) to network protocol, n2n moves + P2P from application to network level. + . + Edge is the edge node daemon for n2n which creates a TAP interface to expose + the n2n virtual LAN. + +Package: n2n-supernode +Architecture: any +Suggests: n2n-edge +Depends: ${shlibs:Depends}, ${misc:Depends} +Conflicts: n2n (<< 2.1.0-1) +Replaces: n2n (<< 2.1.0-1) +Description: a layer-two peer-to-peer virtual private network (VPN) + n2n is a layer-two peer-to-peer virtual private network (VPN) which allows + users to exploit features typical of P2P applications at network instead of + application level. This means that users can gain native IP visibility (e.g. + two PCs belonging to the same n2n network can ping each other) and be + reachable with the same network IP address regardless of the network where + they currently belong. In a nutshell, as OpenVPN moved SSL from application + (e.g. used to implement the https protocol) to network protocol, n2n moves + P2P from application to network level. + . + Supernode is a node introduction registry, broadcast conduit and packet relay + node for the n2n system. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..38346ce --- /dev/null +++ b/debian/copyright @@ -0,0 +1,23 @@ +This package was debianized by Jean-Baptiste Denis on +Thu, 20 Nov 2008 23:53:02 +1000. + +It was downloaded from http://www.ntop.org/n2n/ + +Upstream Author(s): + + Luca Deri + Richard Andrews + +Copyright: + + Copyright (C) 2008 Luca Deri + Copyright (C) 2008 Richard Andrews + +License: + + GPLv3 + +The Debian packaging is (C) 2008, Richard Andrews , +Luca Deri and is licensed under the GPLv3, see +`/usr/share/common-licenses/GPL-3'. + diff --git a/debian/n2n-edge.default b/debian/n2n-edge.default new file mode 100644 index 0000000..e37d806 --- /dev/null +++ b/debian/n2n-edge.default @@ -0,0 +1,21 @@ +# Config file for the n2n edge node daemon. + +# Sets the n2n community name. All edges within the same community appear on +# the same LAN (layer 2 network segment). Community name is 16 bytes in length. +N2N_COMMUNITY="MyCommunityName" + +# Sets the twofish encryption key from ASCII text. All edges communicating must +# use the same key and community name. +N2N_KEY="MySecretCode" + +# Sets the n2n supernode IP address to register to. +N2N_SUPERNODE="gw1.example.com" + +# Sets the n2n virtual LAN IP address being claimed. This is a private IP +# address. All IP addresses in an n2n community typical belong to the same /24 +# net‐ work (ie. only the last octet of the IP addresses varies). +N2N_IP="10.10.10.11" + +# Uncomment this to get edge node started. +#N2N_EDGE_CONFIG_DONE="yes" + diff --git a/debian/n2n-edge.docs b/debian/n2n-edge.docs new file mode 100644 index 0000000..e845566 --- /dev/null +++ b/debian/n2n-edge.docs @@ -0,0 +1 @@ +README diff --git a/debian/n2n-edge.init b/debian/n2n-edge.init new file mode 100755 index 0000000..5fd9f72 --- /dev/null +++ b/debian/n2n-edge.init @@ -0,0 +1,129 @@ +#! /bin/bash +### BEGIN INIT INFO +# Provides: n2n-edge +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: n2n-edge +# Description: Start n2n edge node daemon +### END INIT INFO + +# Init script for n2n edge node +# Copyright (C) 2010 Kim Hansen +# +# 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 3 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, see . + +# Do NOT "set -e" + +# PATH should only include /usr/* if it runs after the mountnfs.sh script +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC="n2n edge" +NAME=n2n-edge +DAEMON=/usr/sbin/edge +SCRIPTNAME=/etc/init.d/$NAME + +# Exit if the package is not installed +[ -x "$DAEMON" ] || exit 0 + +# Read configuration variable file if it is present +[ -r /etc/default/$NAME ] && . /etc/default/$NAME + +# Check config +if [ -z "$N2N_EDGE_CONFIG_DONE" ] +then + echo "Warning: n2n-edge not configured, edit config file in /etc/default/$NAME." 1>&2 + exit 0 +fi + +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.0-6) to ensure that this file is present. +. /lib/lsb/init-functions + +# +# Function that starts the daemon/service +# +do_start() +{ + # Return + # 0 if daemon has been started + # 1 if daemon was already running + # 2 if daemon could not be started + start-stop-daemon --start --quiet --user nobody --exec $DAEMON --test \ + || return 1 + export N2N_KEY + start-stop-daemon --start --quiet --user nobody --exec $DAEMON -- \ + -a $N2N_IP -c $N2N_COMMUNITY -l $N2N_SUPERNODE:7654 -u $(id -u nobody) -g $(id -g nobody) \ + $DAEMON_ARGS \ + || return 2 +} + +# +# Function that stops the daemon/service +# +do_stop() +{ + # Return + # 0 if daemon has been stopped + # 1 if daemon was already stopped + # 2 if daemon could not be stopped + # other if a failure occurred + start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --user nobody --exec $DAEMON +} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + restart|force-reload) + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2 + exit 3 + ;; +esac + +true # Set exit status to 0 (succes) diff --git a/debian/n2n-edge.install b/debian/n2n-edge.install new file mode 100644 index 0000000..2d0bd7c --- /dev/null +++ b/debian/n2n-edge.install @@ -0,0 +1 @@ +edge /usr/sbin diff --git a/debian/n2n-edge.manpages b/debian/n2n-edge.manpages new file mode 100644 index 0000000..2fa385b --- /dev/null +++ b/debian/n2n-edge.manpages @@ -0,0 +1,2 @@ +edge.8 +n2n_v2.7 diff --git a/debian/n2n-supernode.init b/debian/n2n-supernode.init new file mode 100755 index 0000000..7efc7d8 --- /dev/null +++ b/debian/n2n-supernode.init @@ -0,0 +1,121 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: n2n-supernode +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: n2n-supernode +# Description: Start n2n supernode +### END INIT INFO + +# Init script for n2n supernode +# Copyright (C) 2010 Kim Hansen +# +# 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 3 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, see . + +# Do NOT "set -e" + +# PATH should only include /usr/* if it runs after the mountnfs.sh script +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC="n2n supernode" +NAME=n2n-supernode +DAEMON=/usr/sbin/supernode +DAEMON_ARGS="" +SCRIPTNAME=/etc/init.d/$NAME + +# Exit if the package is not installed +[ -x "$DAEMON" ] || exit 0 + +# Read configuration variable file if it is present +[ -r /etc/default/$NAME ] && . /etc/default/$NAME + +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.0-6) to ensure that this file is present. +. /lib/lsb/init-functions + +# +# Function that starts the daemon/service +# +do_start() +{ + # Return + # 0 if daemon has been started + # 1 if daemon was already running + # 2 if daemon could not be started + start-stop-daemon --start --quiet --user nobody --exec $DAEMON --test \ + || return 1 + start-stop-daemon --start --quiet --user nobody --chuid nobody --exec $DAEMON -- \ + $DAEMON_ARGS \ + || return 2 +} + +# +# Function that stops the daemon/service +# +do_stop() +{ + # Return + # 0 if daemon has been stopped + # 1 if daemon was already stopped + # 2 if daemon could not be stopped + # other if a failure occurred + start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --user nobody --exec $DAEMON +} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + restart|force-reload) + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2 + exit 3 + ;; +esac + +true # Set exit status to 0 (succes) diff --git a/debian/n2n-supernode.install b/debian/n2n-supernode.install new file mode 100644 index 0000000..28fa224 --- /dev/null +++ b/debian/n2n-supernode.install @@ -0,0 +1 @@ +supernode /usr/sbin diff --git a/debian/n2n-supernode.manpages b/debian/n2n-supernode.manpages new file mode 100644 index 0000000..6ebfb37 --- /dev/null +++ b/debian/n2n-supernode.manpages @@ -0,0 +1 @@ +supernode.1 diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..0bbc9b8 --- /dev/null +++ b/debian/rules @@ -0,0 +1,5 @@ +#!/usr/bin/make -f + +include /usr/share/cdbs/1/rules/debhelper.mk +include /usr/share/cdbs/1/class/makefile.mk + diff --git a/edge.8 b/edge.8 new file mode 100644 index 0000000..5157653 --- /dev/null +++ b/edge.8 @@ -0,0 +1,208 @@ +.TH edge 8 "17 Mar 2010" "n2n-2.1" "SUPERUSER COMMANDS" +.SH NAME +edge \- n2n edge node daemon +.SH SYNOPSIS +.B edge +[\-d ] \-a \-c {\-k |\-K } +[\-s ] \-l +[\-p ] [\-u ] [\-g ] [-f] [\-m ] [\-r] [\-v] +.SH DESCRIPTION +N2N is a peer-to-peer VPN system. Edge is the edge node daemon for n2n which +creates a TAP interface to expose the n2n virtual LAN. On startup n2n creates +the TAP interface and configures it then registers with the supernode so it can +begin to find other nodes in the community. +.PP +.SH OPTIONS +.TP +\-d +sets the TAP device name as seen in ifconfig. Only available on Linux. +.TP +\-a {|static:|dhcp:0.0.0.0} +sets the n2n virtual LAN IP address being claimed. This is a private IP +address. All IP addresses in an n2n community typical belong to the same /24 +network (ie. only the last octet of the IP addresses varies). If DHCP is used to +assign interface addresses then specify the address as +.B -a dhcp:0.0.0.0 +.TP +\-b +cause edge to perform hostname resolution for the supernode address each time +the supernode is periodically contacted. This can cause reliability problems +because all packet processing stops while the supernode address is resolved +which might take 15 seconds. +.TP +\-c +sets the n2n community name. All edges within the same community appear on the +same LAN (layer 2 network segment). Community name is 16 bytes in length. A name +smaller than this is padded with 0x00 bytes and a name longer than this is +truncated to take the first 16 bytes. +.TP +\-h +write usage then exit. +.TP +\-k +sets the twofish encryption key from ASCII text (see also N2N_KEY in +ENVIRONMENT). All edges communicating must use the same key and community +name. If neither -k nor -K is used to specify a key source then edge uses +cleartext mode (no encryption). The -k and -K options are mutually exclusive. +.TP +\-K +Reads a key-schedule file and populates the internal transform +operations with the data found there. This mechanism allows keys to roll at +pre-determined times for a group of hosts. Accurate time synchronisation is not +required as older keys can be decoded for some time after expiry. If neither -k +nor -K is used to specify a key source then edge uses cleartext mode (no +encryption). The -k and -K options are mutually exclusive. +.TP +\-l : +sets the n2n supernode IP address and port to register to. Up to 2 supernodes +can be specified by two invocations of -l :. eg. +.B edge -l 12.34.56.78:7654 -l 98.76.54.32:7654 +. +.TP +\-p +binds edge to the given UDP port. Useful for keeping the same external socket +across restarts of edge. This allows peer edges which know the edge socket to +continue p2p operation without going back to the supernode. +.TP +\-t +binds the edge management system to the given UDP port. Default 5644. Use this +if you need to run multiple instance of edge; or something is bound to that +port. +.TP +\-u +causes the edge process to drop to the given user ID when privileges are no +longer required (UNIX). +.TP +\-g +causes the edge process to drop to the given group ID when privileges are no +longer required (UNIX). +.TP +\-f +disables daemon mode (UNIX) and causes edge to run in the foreground. +.TP +\-m +start the TAP interface with the given MAC address. This is highly recommended +as it means the same address will be used if edge stops and restarts. If this is +not done, the ARP caches of all peers will be wrong and packets will not flow to +this edge until the next ARP refresh. +.TP +\-M +set the MTU of the edge interface in bytes. MTU is the largest packet fragment +size allowed to be moved throught the interface. The default is 1400. +.TP +\-s +set the netmask of edge interface in IPv4 dotted decimal notation. The default +is 255.255.255.0 (ie. /24). +.TP +\-r +enable IP packet forwarding/routing through the n2n virtual LAN. Without this +option, IP packets arriving over n2n are dropped if not for the -a (or +DHCP assigned) IP address of the edge interface. +.TP +\-E +accept packets destined for multicast ethernet MAC addresses. These addresses +are used in multicast ethernet and IPv6 neighbour discovery. If this option is +not present these multicast packets are discarded as most users do not need or +understand them. +.TP +\-v +more verbose logging (may be specified several times for more verbosity). +.SH ENVIRONMENT +.TP +.B N2N_KEY +set the encryption key so it is not visible on the command line +.SH EXAMPLES +.TP +.B edge \-d n2n0 \-c mynetwork \-k encryptme \-u 99 \-g 99 \-m DE:AD:BE:EF:01:23 \-a 192.168.254.7 \-p 50001 \-l 123.121.120.119:7654 + +Start edge with TAP device n2n0 on community "mynetwork" with community +supernode at 123.121.120.119 UDP port 7654 and bind the locally used UDP port to +50001. Use "encryptme" as the single permanent shared encryption key. Assign MAC +address DE:AD:BE:EF:01:23 to the n2n interface and drop to user=99 and group=99 +after the TAP device is successfull configured. +.PP +Add the -f option to stop edge running as a daemon. +.PP +Somewhere else setup another edge with similar parameters, eg. + +.B edge \-d n2n0 \-c mynetwork \-k encryptme \-u 99 \-g 99 \-m DE:AD:BE:EF:01:21 \-a 192.168.254.5 \-p 50001 \-l 123.121.120.119:7654 +.PP +Now you can ping from 192.168.254.5 to 192.168.254.7. +.PP +The MAC address (-m ) and virtual IP address (-a ) must be different +on all edges in the same community. + +.SH KEY SCHEDULE FILES +(See +.B n2n_v2(7) +for more details). + +The -K option reads a key schedule file. + +.B edge \-d n2n0 \-c mynetwork \-K /path/to/file \-u 99 \-g 99 \-m DE:AD:BE:EF:01:21 \-a 192.168.254.5 \-p 50001 \-l 123.121.120.119:7654 +.PP + +The key schedule file consists of line, one per key in the schedule. The purpose +of key schedules is to encourage regular changing of the encryption keys used by +a community. The file structure also allows for full binary keys to be specified +as compared to the ASCII keys allowed by the single key injection. Each key line +consists of the following: + +.B + + and are ASCII decimal values of the UNIX times during which the +key is valid. is the index of the transform that applies +to. is some text which is parsed by the transform module to derive the +key for that line. + +Supported values are: +.TP +2 = TwoFish + has the form _. eg. + +.B 1252327945 1252328305 2 602_3d7c7769b34b2a4812f8c0e9d87ce9 + +This specifies security association number 602 and a 16-octet key of numeric +value 0x3d7c7769b34b2a4812f8c0e9d87ce9. is a 32-bit unsigned integer which +is used to identify the encryption key to the receiver. The SA number is sent +unencrypted so the receiver may find the correct key from the key +schedule. is up to 16 octets although shorter keys are allowed. + +.TP +3 = AES-CBC + has the form _. Same rules as TwoFish. + +.SH CLEARTEXT MODE +If neither +.B -k +nor +.B -K +is specified then edge uses cleartext mode. In cleartext mode there is no +transform of the packet data it is simply encrypted. This is useful for +debugging n2n as packet contents can be seen clearly. + +To prevent accidental exposure of data, edge only enters cleartext mode when no +keying parameters are specified. In the case where keying parameters are +specified but no valid keys can be determined, edge exits with an error at +startup. If all keys become invalid while running, edge continues to encode +using the last key that was valid. + +.SH MANAGEMENT INTERFACE +Edge provides a very simple management system on UDP port 5644. Send a newline +to receive a status output. Send 'reload' to cause re-read of the +keyfile. Send 'stop' to cause edge to exit cleanly. + +.SH EXIT STATUS +edge is a daemon and any exit is an error. +.SH AUTHORS +.TP +Richard Andrews +andrews (at) ntop.org - n2n-1 maintainer and main author of n2n-2 +.TP +Luca Deri +deri (at) ntop.org - original author of n2n +.TP +Don Bindner +(--) - significant contributions to n2n-1 +.SH SEE ALSO +ifconfig(8) supernode(1) tunctl(8) n2n_v2(7) diff --git a/edge.c b/edge.c new file mode 100644 index 0000000..b2407b9 --- /dev/null +++ b/edge.c @@ -0,0 +1,2412 @@ +/** + * (C) 2007-09 - Luca Deri + * Richard Andrews + * + * 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 3 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 see see + * + * Code contributions courtesy of: + * Don Bindner + * Sylwester Sosnowski + * Wilfried "Wonka" Klaebe + * Lukasz Taczuk + * + */ + +#include "n2n.h" +#include "n2n_transforms.h" +#include +#include +#include "minilzo.h" + +#if defined(DEBUG) +#define SOCKET_TIMEOUT_INTERVAL_SECS 5 +#define REGISTER_SUPER_INTERVAL_DFL 20 /* sec */ +#else /* #if defined(DEBUG) */ +#define SOCKET_TIMEOUT_INTERVAL_SECS 10 +#define REGISTER_SUPER_INTERVAL_DFL 60 /* sec */ +#endif /* #if defined(DEBUG) */ + +#define REGISTER_SUPER_INTERVAL_MIN 20 /* sec */ +#define REGISTER_SUPER_INTERVAL_MAX 3600 /* sec */ + +#define IFACE_UPDATE_INTERVAL (30) /* sec. How long it usually takes to get an IP lease. */ +#define TRANSOP_TICK_INTERVAL (10) /* sec */ + +/** maximum length of command line arguments */ +#define MAX_CMDLINE_BUFFER_LENGTH 4096 + +/** maximum length of a line in the configuration file */ +#define MAX_CONFFILE_LINE_LENGTH 1024 + +#define N2N_PATHNAME_MAXLEN 256 +#define N2N_MAX_TRANSFORMS 16 +#define N2N_EDGE_MGMT_PORT 5644 + +/** Positions in the transop array where various transforms are stored. + * + * Used by transop_enum_to_index(). See also the transform enumerations in + * n2n_transforms.h */ +#define N2N_TRANSOP_NULL_IDX 0 +#define N2N_TRANSOP_TF_IDX 1 +#define N2N_TRANSOP_AESCBC_IDX 2 +/* etc. */ + + + +/* Work-memory needed for compression. Allocate memory in units + * of `lzo_align_t' (instead of `char') to make sure it is properly aligned. + */ + +/* #define HEAP_ALLOC(var,size) \ */ +/* lzo_align_t __LZO_MMODEL var [ ((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t) ] */ + +/* static HEAP_ALLOC(wrkmem,LZO1X_1_MEM_COMPRESS); */ + +/* ******************************************************* */ + +#define N2N_EDGE_SN_HOST_SIZE 48 + +typedef char n2n_sn_name_t[N2N_EDGE_SN_HOST_SIZE]; + +#define N2N_EDGE_NUM_SUPERNODES 2 +#define N2N_EDGE_SUP_ATTEMPTS 3 /* Number of failed attmpts before moving on to next supernode. */ + + +/** Main structure type for edge. */ +struct n2n_edge +{ + int daemon; /**< Non-zero if edge should detach and run in the background. */ + uint8_t re_resolve_supernode_ip; + + n2n_sock_t supernode; + + size_t sn_idx; /**< Currently active supernode. */ + size_t sn_num; /**< Number of supernode addresses defined. */ + n2n_sn_name_t sn_ip_array[N2N_EDGE_NUM_SUPERNODES]; + int sn_wait; /**< Whether we are waiting for a supernode response. */ + + n2n_community_t community_name; /**< The community. 16 full octets. */ + char keyschedule[N2N_PATHNAME_MAXLEN]; + int null_transop; /**< Only allowed if no key sources defined. */ + + int udp_sock; + int udp_mgmt_sock; /**< socket for status info. */ + + tuntap_dev device; /**< All about the TUNTAP device */ + int dyn_ip_mode; /**< Interface IP address is dynamically allocated, eg. DHCP. */ + int allow_routing; /**< Accept packet no to interface address. */ + int drop_multicast; /**< Multicast ethernet addresses. */ + + n2n_trans_op_t transop[N2N_MAX_TRANSFORMS]; /* one for each transform at fixed positions */ + size_t tx_transop_idx; /**< The transop to use when encoding. */ + + struct peer_info * known_peers; /**< Edges we are connected to. */ + struct peer_info * pending_peers; /**< Edges we have tried to register with. */ + time_t last_register_req; /**< Check if time to re-register with super*/ + size_t register_lifetime; /**< Time distance after last_register_req at which to re-register. */ + time_t last_p2p; /**< Last time p2p traffic was received. */ + time_t last_sup; /**< Last time a packet arrived from supernode. */ + size_t sup_attempts; /**< Number of remaining attempts to this supernode. */ + n2n_cookie_t last_cookie; /**< Cookie sent in last REGISTER_SUPER. */ + + time_t start_time; /**< For calculating uptime */ + + /* Statistics */ + size_t tx_p2p; + size_t rx_p2p; + size_t tx_sup; + size_t rx_sup; +}; + +/** Return the IP address of the current supernode in the ring. */ +static const char * supernode_ip( const n2n_edge_t * eee ) +{ + return (eee->sn_ip_array)[eee->sn_idx]; +} + + +static void supernode2addr(n2n_sock_t * sn, const n2n_sn_name_t addr); + +static void send_packet2net(n2n_edge_t * eee, + uint8_t *decrypted_msg, size_t len); + + +/* ************************************** */ + +/* parse the configuration file */ +static int readConfFile(const char * filename, char * const linebuffer) { + struct stat stats; + FILE * fd; + char * buffer = NULL; + + buffer = (char *)malloc(MAX_CONFFILE_LINE_LENGTH); + if (!buffer) { + traceEvent( TRACE_ERROR, "Unable to allocate memory"); + return -1; + } + + if (stat(filename, &stats)) { + if (errno == ENOENT) + traceEvent(TRACE_ERROR, "parameter file %s not found/unable to access\n", filename); + else + traceEvent(TRACE_ERROR, "cannot stat file %s, errno=%d\n",filename, errno); + free(buffer); + return -1; + } + + fd = fopen(filename, "rb"); + if (!fd) { + traceEvent(TRACE_ERROR, "Unable to open parameter file '%s' (%d)...\n",filename,errno); + free(buffer); + return -1; + } + while(fgets(buffer, MAX_CONFFILE_LINE_LENGTH,fd)) { + char * p = NULL; + + /* strip out comments */ + p = strchr(buffer, '#'); + if (p) *p ='\0'; + + /* remove \n */ + p = strchr(buffer, '\n'); + if (p) *p ='\0'; + + /* strip out heading spaces */ + p = buffer; + while(*p == ' ' && *p != '\0') ++p; + if (p != buffer) strncpy(buffer,p,strlen(p)+1); + + /* strip out trailing spaces */ + while(strlen(buffer) && buffer[strlen(buffer)-1]==' ') + buffer[strlen(buffer)-1]= '\0'; + + /* check for nested @file option */ + if (strchr(buffer, '@')) { + traceEvent(TRACE_ERROR, "@file in file nesting is not supported\n"); + free(buffer); + return -1; + } + if ((strlen(linebuffer)+strlen(buffer)+2)< MAX_CMDLINE_BUFFER_LENGTH) { + strncat(linebuffer, " ", 1); + strncat(linebuffer, buffer, strlen(buffer)); + } else { + traceEvent(TRACE_ERROR, "too many argument"); + free(buffer); + return -1; + } + } + + free(buffer); + fclose(fd); + + return 0; +} + +/* Create the argv vector */ +static char ** buildargv(int * effectiveargc, char * const linebuffer) { + const int INITIAL_MAXARGC = 16; /* Number of args + NULL in initial argv */ + int maxargc; + int argc=0; + char ** argv; + char * buffer, * buff; + + *effectiveargc = 0; + buffer = (char *)calloc(1, strlen(linebuffer)+2); + if (!buffer) { + traceEvent( TRACE_ERROR, "Unable to allocate memory"); + return NULL; + } + strncpy(buffer, linebuffer,strlen(linebuffer)); + + maxargc = INITIAL_MAXARGC; + argv = (char **)malloc(maxargc * sizeof(char*)); + if (argv == NULL) { + traceEvent( TRACE_ERROR, "Unable to allocate memory"); + return NULL; + } + buff = buffer; + while(buff) { + char * p = strchr(buff,' '); + if (p) { + *p='\0'; + argv[argc++] = strdup(buff); + while(*++p == ' ' && *p != '\0'); + buff=p; + if (argc >= maxargc) { + maxargc *= 2; + argv = (char **)realloc(argv, maxargc * sizeof(char*)); + if (argv == NULL) { + traceEvent(TRACE_ERROR, "Unable to re-allocate memory"); + free(buffer); + return NULL; + } + } + } else { + argv[argc++] = strdup(buff); + break; + } + } + free(buffer); + *effectiveargc = argc; + return argv; +} + + + +/* ************************************** */ + + +/** Initialise an edge to defaults. + * + * This also initialises the NULL transform operation opstruct. + */ +static int edge_init(n2n_edge_t * eee) +{ +#ifdef WIN32 + initWin32(); +#endif + memset(eee, 0, sizeof(n2n_edge_t)); + eee->start_time = time(NULL); + + transop_null_init( &(eee->transop[N2N_TRANSOP_NULL_IDX]) ); + transop_twofish_init( &(eee->transop[N2N_TRANSOP_TF_IDX] ) ); + transop_aes_init( &(eee->transop[N2N_TRANSOP_AESCBC_IDX] ) ); + + eee->tx_transop_idx = N2N_TRANSOP_NULL_IDX; /* No guarantee the others have been setup */ + + eee->daemon = 1; /* By default run in daemon mode. */ + eee->re_resolve_supernode_ip = 0; + /* keyschedule set to NULLs by memset */ + /* community_name set to NULLs by memset */ + eee->null_transop = 0; + eee->udp_sock = -1; + eee->udp_mgmt_sock = -1; + eee->dyn_ip_mode = 0; + eee->allow_routing = 0; + eee->drop_multicast = 1; + eee->known_peers = NULL; + eee->pending_peers = NULL; + eee->last_register_req = 0; + eee->register_lifetime = REGISTER_SUPER_INTERVAL_DFL; + eee->last_p2p = 0; + eee->last_sup = 0; + eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; + + if(lzo_init() != LZO_E_OK) + { + traceEvent(TRACE_ERROR, "LZO compression error"); + return(-1); + } + + return(0); +} + + + +/* Called in main() after options are parsed. */ +static int edge_init_twofish( n2n_edge_t * eee, uint8_t *encrypt_pwd, uint32_t encrypt_pwd_len ) +{ + return transop_twofish_setup( &(eee->transop[N2N_TRANSOP_TF_IDX]), 0, encrypt_pwd, encrypt_pwd_len ); +} + + +/** Find the transop op-struct for the transform enumeration required. + * + * @return - index into the transop array, or -1 on failure. + */ +static int transop_enum_to_index( n2n_transform_t id ) +{ + switch (id) + { + case N2N_TRANSFORM_ID_TWOFISH: + return N2N_TRANSOP_TF_IDX; + break; + case N2N_TRANSFORM_ID_NULL: + return N2N_TRANSOP_NULL_IDX; + break; + case N2N_TRANSFORM_ID_AESCBC: + return N2N_TRANSOP_AESCBC_IDX; + break; + default: + return -1; + } +} + + +/** Called periodically to roll keys and do any periodic maintenance in the + * tranform operations state machines. */ +static int n2n_tick_transop( n2n_edge_t * eee, time_t now ) +{ + n2n_tostat_t tst; + size_t trop = eee->tx_transop_idx; + + /* Tests are done in order that most preferred transform is last and causes + * tx_transop_idx to be left at most preferred valid transform. */ + tst = (eee->transop[N2N_TRANSOP_NULL_IDX].tick)( &(eee->transop[N2N_TRANSOP_NULL_IDX]), now ); + tst = (eee->transop[N2N_TRANSOP_AESCBC_IDX].tick)( &(eee->transop[N2N_TRANSOP_AESCBC_IDX]), now ); + if ( tst.can_tx ) + { + traceEvent( TRACE_DEBUG, "can_tx AESCBC (idx=%u)", (unsigned int)N2N_TRANSOP_AESCBC_IDX ); + trop = N2N_TRANSOP_AESCBC_IDX; + } + + tst = (eee->transop[N2N_TRANSOP_TF_IDX].tick)( &(eee->transop[N2N_TRANSOP_TF_IDX]), now ); + if ( tst.can_tx ) + { + traceEvent( TRACE_DEBUG, "can_tx TF (idx=%u)", (unsigned int)N2N_TRANSOP_TF_IDX ); + trop = N2N_TRANSOP_TF_IDX; + } + + if ( trop != eee->tx_transop_idx ) + { + eee->tx_transop_idx = trop; + traceEvent( TRACE_NORMAL, "Chose new tx_transop_idx=%u", (unsigned int)(eee->tx_transop_idx) ); + } + + return 0; +} + + + +/** Read in a key-schedule file, parse the lines and pass each line to the + * appropriate trans_op for parsing of key-data and adding key-schedule + * entries. The lookup table of time->trans_op is constructed such that + * encoding can be passed to the correct trans_op. The trans_op internal table + * will then determine the best SA for that trans_op from the key schedule to + * use for encoding. */ +static int edge_init_keyschedule( n2n_edge_t * eee ) +{ + +#define N2N_NUM_CIPHERSPECS 32 + + int retval = -1; + ssize_t numSpecs=0; + n2n_cipherspec_t specs[N2N_NUM_CIPHERSPECS]; + size_t i; + time_t now = time(NULL); + + numSpecs = n2n_read_keyfile( specs, N2N_NUM_CIPHERSPECS, eee->keyschedule ); + + if ( numSpecs > 0 ) + { + traceEvent( TRACE_NORMAL, "keyfile = %s read -> %d specs.\n", optarg, (signed int)numSpecs); + + for ( i=0; i < (size_t)numSpecs; ++i ) + { + int idx; + + idx = transop_enum_to_index( specs[i].t ); + + switch (idx) + { + case N2N_TRANSOP_TF_IDX: + case N2N_TRANSOP_AESCBC_IDX: + { + retval = (eee->transop[idx].addspec)( &(eee->transop[idx]), + &(specs[i]) ); + break; + } + default: + retval = -1; + } + + if (0 != retval) + { + traceEvent( TRACE_ERROR, "keyschedule failed to add spec[%u] to transop[%d].\n", + (unsigned int)i, idx); + + return retval; + } + } + + n2n_tick_transop( eee, now ); + } + else + { + traceEvent( TRACE_ERROR, "Failed to process '%s'", eee->keyschedule ); + } + + return retval; +} + + +/** Deinitialise the edge and deallocate any owned memory. */ +static void edge_deinit(n2n_edge_t * eee) +{ + if ( eee->udp_sock >=0 ) + { + closesocket( eee->udp_sock ); + } + + if ( eee->udp_mgmt_sock >= 0 ) + { + closesocket(eee->udp_mgmt_sock); + } + + clear_peer_list( &(eee->pending_peers) ); + clear_peer_list( &(eee->known_peers) ); + + (eee->transop[N2N_TRANSOP_TF_IDX].deinit)(&eee->transop[N2N_TRANSOP_TF_IDX]); + (eee->transop[N2N_TRANSOP_NULL_IDX].deinit)(&eee->transop[N2N_TRANSOP_NULL_IDX]); +} + +static void readFromIPSocket( n2n_edge_t * eee ); + +static void readFromMgmtSocket( n2n_edge_t * eee, int * keep_running ); + +static void help() { + print_n2n_version(); + + printf("edge " +#if defined(N2N_CAN_NAME_IFACE) + "-d " +#endif /* #if defined(N2N_CAN_NAME_IFACE) */ + "-a [static:|dhcp:] " + "-c " + "[-k | -K ] " + "[-s ] " +#if defined(N2N_HAVE_SETUID) + "[-u -g ]" +#endif /* #ifndef N2N_HAVE_SETUID */ + +#if defined(N2N_HAVE_DAEMON) + "[-f]" +#endif /* #if defined(N2N_HAVE_DAEMON) */ + "[-m ]" + "\n" + "-l " + "[-p ] [-M ] " + "[-r] [-E] [-v] [-t ] [-b] [-h]\n\n"); + +#ifdef __linux__ + printf("-d | tun device name\n"); +#endif + + printf("-a | Set interface address. For DHCP use '-r -a dhcp:0.0.0.0'\n"); + printf("-c | n2n community name the edge belongs to.\n"); + printf("-k | Encryption key (ASCII) - also N2N_KEY=. Not with -K.\n"); + printf("-K | Specify a key schedule file to load. Not with -k.\n"); + printf("-s | Edge interface netmask in dotted decimal notation (255.255.255.0).\n"); + printf("-l | Supernode IP:port\n"); + printf("-b | Periodically resolve supernode IP\n"); + printf(" : (when supernodes are running on dynamic IPs)\n"); + printf("-p | Fixed local UDP port.\n"); +#ifndef WIN32 + printf("-u | User ID (numeric) to use when privileges are dropped.\n"); + printf("-g | Group ID (numeric) to use when privileges are dropped.\n"); +#endif /* ifndef WIN32 */ +#ifdef N2N_HAVE_DAEMON + printf("-f | Do not fork and run as a daemon; rather run in foreground.\n"); +#endif /* #ifdef N2N_HAVE_DAEMON */ + printf("-m | Fix MAC address for the TAP interface (otherwise it may be random)\n" + " : eg. -m 01:02:03:04:05:06\n"); + printf("-M | Specify n2n MTU of edge interface (default %d).\n", DEFAULT_MTU); + printf("-r | Enable packet forwarding through n2n community.\n"); + printf("-E | Accept multicast MAC addresses (default=drop).\n"); + printf("-v | Make more verbose. Repeat as required.\n"); + printf("-t | Management UDP Port (for multiple edges on a machine).\n"); + + printf("\nEnvironment variables:\n"); + printf(" N2N_KEY | Encryption key (ASCII). Not with -K or -k.\n" ); + + exit(0); +} + + +/** Send a datagram to a socket defined by a n2n_sock_t */ +static ssize_t sendto_sock( int fd, const void * buf, size_t len, const n2n_sock_t * dest ) +{ + struct sockaddr_in peer_addr; + ssize_t sent; + + fill_sockaddr( (struct sockaddr *) &peer_addr, + sizeof(peer_addr), + dest ); + + sent = sendto( fd, buf, len, 0/*flags*/, + (struct sockaddr *)&peer_addr, sizeof(struct sockaddr_in) ); + if ( sent < 0 ) + { + char * c = strerror(errno); + traceEvent( TRACE_ERROR, "sendto failed (%d) %s", errno, c ); + } + else + { + traceEvent( TRACE_DEBUG, "sendto sent=%d to ", (signed int)sent ); + } + + return sent; +} + + +/** Send a REGISTER packet to another edge. */ +static void send_register( n2n_edge_t * eee, + const n2n_sock_t * remote_peer) +{ + uint8_t pktbuf[N2N_PKT_BUF_SIZE]; + size_t idx; + ssize_t sent; + n2n_common_t cmn; + n2n_REGISTER_t reg; + n2n_sock_str_t sockbuf; + + memset(&cmn, 0, sizeof(cmn) ); + memset(®, 0, sizeof(reg) ); + cmn.ttl=N2N_DEFAULT_TTL; + cmn.pc = n2n_register; + cmn.flags = 0; + memcpy( cmn.community, eee->community_name, N2N_COMMUNITY_SIZE ); + + idx=0; + encode_uint32( reg.cookie, &idx, 123456789 ); + idx=0; + encode_mac( reg.srcMac, &idx, eee->device.mac_addr ); + + idx=0; + encode_REGISTER( pktbuf, &idx, &cmn, ® ); + + traceEvent( TRACE_INFO, "send REGISTER %s", + sock_to_cstr( sockbuf, remote_peer ) ); + + + sent = sendto_sock( eee->udp_sock, pktbuf, idx, remote_peer ); + +} + + +/** Send a REGISTER_SUPER packet to the current supernode. */ +static void send_register_super( n2n_edge_t * eee, + const n2n_sock_t * supernode) +{ + uint8_t pktbuf[N2N_PKT_BUF_SIZE]; + size_t idx; + ssize_t sent; + n2n_common_t cmn; + n2n_REGISTER_SUPER_t reg; + n2n_sock_str_t sockbuf; + + memset(&cmn, 0, sizeof(cmn) ); + memset(®, 0, sizeof(reg) ); + cmn.ttl=N2N_DEFAULT_TTL; + cmn.pc = n2n_register_super; + cmn.flags = 0; + memcpy( cmn.community, eee->community_name, N2N_COMMUNITY_SIZE ); + + for( idx=0; idx < N2N_COOKIE_SIZE; ++idx ) + { + eee->last_cookie[idx] = rand() % 0xff; + } + + memcpy( reg.cookie, eee->last_cookie, N2N_COOKIE_SIZE ); + reg.auth.scheme=0; /* No auth yet */ + + idx=0; + encode_mac( reg.edgeMac, &idx, eee->device.mac_addr ); + + idx=0; + encode_REGISTER_SUPER( pktbuf, &idx, &cmn, ® ); + + traceEvent( TRACE_INFO, "send REGISTER_SUPER to %s", + sock_to_cstr( sockbuf, supernode ) ); + + + sent = sendto_sock( eee->udp_sock, pktbuf, idx, supernode ); + +} + + +/** Send a REGISTER_ACK packet to a peer edge. */ +static void send_register_ack( n2n_edge_t * eee, + const n2n_sock_t * remote_peer, + const n2n_REGISTER_t * reg ) +{ + uint8_t pktbuf[N2N_PKT_BUF_SIZE]; + size_t idx; + ssize_t sent; + n2n_common_t cmn; + n2n_REGISTER_ACK_t ack; + n2n_sock_str_t sockbuf; + + memset(&cmn, 0, sizeof(cmn) ); + memset(&ack, 0, sizeof(reg) ); + cmn.ttl=N2N_DEFAULT_TTL; + cmn.pc = n2n_register_ack; + cmn.flags = 0; + memcpy( cmn.community, eee->community_name, N2N_COMMUNITY_SIZE ); + + memset( &ack, 0, sizeof(ack) ); + memcpy( ack.cookie, reg->cookie, N2N_COOKIE_SIZE ); + memcpy( ack.srcMac, eee->device.mac_addr, N2N_MAC_SIZE ); + memcpy( ack.dstMac, reg->srcMac, N2N_MAC_SIZE ); + + idx=0; + encode_REGISTER_ACK( pktbuf, &idx, &cmn, &ack ); + + traceEvent( TRACE_INFO, "send REGISTER_ACK %s", + sock_to_cstr( sockbuf, remote_peer ) ); + + + sent = sendto_sock( eee->udp_sock, pktbuf, idx, remote_peer ); +} + + +/** NOT IMPLEMENTED + * + * This would send a DEREGISTER packet to a peer edge or supernode to indicate + * the edge is going away. + */ +static void send_deregister(n2n_edge_t * eee, + n2n_sock_t * remote_peer) +{ + /* Marshall and send message */ +} + + +static int is_empty_ip_address( const n2n_sock_t * sock ); +static void update_peer_address(n2n_edge_t * eee, + uint8_t from_supernode, + const n2n_mac_t mac, + const n2n_sock_t * peer, + time_t when); +void check_peer( n2n_edge_t * eee, + uint8_t from_supernode, + const n2n_mac_t mac, + const n2n_sock_t * peer ); +void try_send_register( n2n_edge_t * eee, + uint8_t from_supernode, + const n2n_mac_t mac, + const n2n_sock_t * peer ); +void set_peer_operational( n2n_edge_t * eee, + const n2n_mac_t mac, + const n2n_sock_t * peer ); + + + +/** Start the registration process. + * + * If the peer is already in pending_peers, ignore the request. + * If not in pending_peers, add it and send a REGISTER. + * + * If hdr is for a direct peer-to-peer packet, try to register back to sender + * even if the MAC is in pending_peers. This is because an incident direct + * packet indicates that peer-to-peer exchange should work so more aggressive + * registration can be permitted (once per incoming packet) as this should only + * last for a small number of packets.. + * + * Called from the main loop when Rx a packet for our device mac. + */ +void try_send_register( n2n_edge_t * eee, + uint8_t from_supernode, + const n2n_mac_t mac, + const n2n_sock_t * peer ) +{ + /* REVISIT: purge of pending_peers not yet done. */ + struct peer_info * scan = find_peer_by_mac( eee->pending_peers, mac ); + macstr_t mac_buf; + n2n_sock_str_t sockbuf; + + if ( NULL == scan ) + { + scan = calloc( 1, sizeof( struct peer_info ) ); + + memcpy(scan->mac_addr, mac, N2N_MAC_SIZE); + scan->sock = *peer; + scan->last_seen = time(NULL); /* Don't change this it marks the pending peer for removal. */ + + peer_list_add( &(eee->pending_peers), scan ); + + traceEvent( TRACE_DEBUG, "=== new pending %s -> %s", + macaddr_str( mac_buf, scan->mac_addr ), + sock_to_cstr( sockbuf, &(scan->sock) ) ); + + traceEvent( TRACE_INFO, "Pending peers list size=%u", + (unsigned int)peer_list_size( eee->pending_peers ) ); + + /* trace Sending REGISTER */ + + send_register(eee, &(scan->sock) ); + + /* pending_peers now owns scan. */ + } + else + { + } +} + + +/** Update the last_seen time for this peer, or get registered. */ +void check_peer( n2n_edge_t * eee, + uint8_t from_supernode, + const n2n_mac_t mac, + const n2n_sock_t * peer ) +{ + struct peer_info * scan = find_peer_by_mac( eee->known_peers, mac ); + + if ( NULL == scan ) + { + /* Not in known_peers - start the REGISTER process. */ + try_send_register( eee, from_supernode, mac, peer ); + } + else + { + /* Already in known_peers. */ + update_peer_address( eee, from_supernode, mac, peer, time(NULL) ); + } +} + + +/* Move the peer from the pending_peers list to the known_peers lists. + * + * peer must be a pointer to an element of the pending_peers list. + * + * Called by main loop when Rx a REGISTER_ACK. + */ +void set_peer_operational( n2n_edge_t * eee, + const n2n_mac_t mac, + const n2n_sock_t * peer ) +{ + struct peer_info * prev = NULL; + struct peer_info * scan; + macstr_t mac_buf; + n2n_sock_str_t sockbuf; + + traceEvent( TRACE_INFO, "set_peer_operational: %s -> %s", + macaddr_str( mac_buf, mac), + sock_to_cstr( sockbuf, peer ) ); + + scan=eee->pending_peers; + + while ( NULL != scan ) + { + if ( 0 == memcmp( scan->mac_addr, mac, N2N_MAC_SIZE ) ) + { + break; /* found. */ + } + + prev = scan; + scan = scan->next; + } + + if ( scan ) + { + + + /* Remove scan from pending_peers. */ + if ( prev ) + { + prev->next = scan->next; + } + else + { + eee->pending_peers = scan->next; + } + + /* Add scan to known_peers. */ + scan->next = eee->known_peers; + eee->known_peers = scan; + + scan->sock = *peer; + + traceEvent( TRACE_DEBUG, "=== new peer %s -> %s", + macaddr_str( mac_buf, scan->mac_addr), + sock_to_cstr( sockbuf, &(scan->sock) ) ); + + traceEvent( TRACE_INFO, "Pending peers list size=%u", + (unsigned int)peer_list_size( eee->pending_peers ) ); + + traceEvent( TRACE_INFO, "Operational peers list size=%u", + (unsigned int)peer_list_size( eee->known_peers ) ); + + + scan->last_seen = time(NULL); + } + else + { + traceEvent( TRACE_DEBUG, "Failed to find sender in pending_peers." ); + } +} + + +n2n_mac_t broadcast_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +static int is_empty_ip_address( const n2n_sock_t * sock ) +{ + const uint8_t * ptr=NULL; + size_t len=0; + size_t i; + + if ( AF_INET6 == sock->family ) + { + ptr = sock->addr.v6; + len = 16; + } + else + { + ptr = sock->addr.v4; + len = 4; + } + + for (i=0; iknown_peers; + struct peer_info *prev = NULL; /* use to remove bad registrations. */ + n2n_sock_str_t sockbuf1; + n2n_sock_str_t sockbuf2; /* don't clobber sockbuf1 if writing two addresses to trace */ + macstr_t mac_buf; + + if ( is_empty_ip_address( peer ) ) + { + /* Not to be registered. */ + return; + } + + if ( 0 == memcmp( mac, broadcast_mac, N2N_MAC_SIZE ) ) + { + /* Not to be registered. */ + return; + } + + + while(scan != NULL) + { + if(memcmp(mac, scan->mac_addr, N2N_MAC_SIZE) == 0) + { + break; + } + + prev = scan; + scan = scan->next; + } + + if ( NULL == scan ) + { + /* Not in known_peers. */ + return; + } + + if ( 0 != sock_equal( &(scan->sock), peer)) + { + if ( 0 == from_supernode ) + { + traceEvent( TRACE_NORMAL, "Peer changed %s: %s -> %s", + macaddr_str( mac_buf, scan->mac_addr ), + sock_to_cstr(sockbuf1, &(scan->sock)), + sock_to_cstr(sockbuf2, peer) ); + + /* The peer has changed public socket. It can no longer be assumed to be reachable. */ + /* Remove the peer. */ + if ( NULL == prev ) + { + /* scan was head of list */ + eee->known_peers = scan->next; + } + else + { + prev->next = scan->next; + } + free(scan); + + try_send_register( eee, from_supernode, mac, peer ); + } + else + { + /* Don't worry about what the supernode reports, it could be seeing a different socket. */ + } + } + else + { + /* Found and unchanged. */ + scan->last_seen = when; + } +} + + + +#if defined(DUMMY_ID_00001) /* Disabled waiting for config option to enable it */ + + + +static char gratuitous_arp[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Dest mac */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Src mac */ + 0x08, 0x06, /* ARP */ + 0x00, 0x01, /* Ethernet */ + 0x08, 0x00, /* IP */ + 0x06, /* Hw Size */ + 0x04, /* Protocol Size */ + 0x00, 0x01, /* ARP Request */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Src mac */ + 0x00, 0x00, 0x00, 0x00, /* Src IP */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Target mac */ + 0x00, 0x00, 0x00, 0x00 /* Target IP */ +}; + + +/** Build a gratuitous ARP packet for a /24 layer 3 (IP) network. */ +static int build_gratuitous_arp(char *buffer, uint16_t buffer_len) { + if(buffer_len < sizeof(gratuitous_arp)) return(-1); + + memcpy(buffer, gratuitous_arp, sizeof(gratuitous_arp)); + memcpy(&buffer[6], device.mac_addr, 6); + memcpy(&buffer[22], device.mac_addr, 6); + memcpy(&buffer[28], &device.ip_addr, 4); + + /* REVISIT: BbMaj7 - use a real netmask here. This is valid only by accident + * for /24 IPv4 networks. */ + buffer[31] = 0xFF; /* Use a faked broadcast address */ + memcpy(&buffer[38], &device.ip_addr, 4); + return(sizeof(gratuitous_arp)); +} + +/** Called from update_supernode_reg to periodically send gratuitous ARP + * broadcasts. */ +static void send_grat_arps(n2n_edge_t * eee,) { + char buffer[48]; + size_t len; + + traceEvent(TRACE_NORMAL, "Sending gratuitous ARP..."); + len = build_gratuitous_arp(buffer, sizeof(buffer)); + send_packet2net(eee, buffer, len); + send_packet2net(eee, buffer, len); /* Two is better than one :-) */ +} +#endif /* #if defined(DUMMY_ID_00001) */ + + + + +/** @brief Check to see if we should re-register with the supernode. + * + * This is frequently called by the main loop. + */ +static void update_supernode_reg( n2n_edge_t * eee, time_t nowTime ) +{ + if ( eee->sn_wait && ( nowTime > (eee->last_register_req + (eee->register_lifetime/10) ) ) ) + { + /* fall through */ + traceEvent( TRACE_DEBUG, "update_supernode_reg: doing fast retry." ); + } + else if ( nowTime < (eee->last_register_req + eee->register_lifetime)) + { + return; /* Too early */ + } + + if ( 0 == eee->sup_attempts ) + { + /* Give up on that supernode and try the next one. */ + ++(eee->sn_idx); + + if (eee->sn_idx >= eee->sn_num) + { + /* Got to end of list, go back to the start. Also works for list of one entry. */ + eee->sn_idx=0; + } + + traceEvent(TRACE_WARNING, "Supernode not responding - moving to %u of %u", + (unsigned int)eee->sn_idx, (unsigned int)eee->sn_num ); + + eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; + } + else + { + --(eee->sup_attempts); + } + + if(eee->re_resolve_supernode_ip || (eee->sn_num > 1) ) + { + supernode2addr(&(eee->supernode), eee->sn_ip_array[eee->sn_idx] ); + } + + traceEvent(TRACE_DEBUG, "Registering with supernode (%s) (attempts left %u)", + supernode_ip(eee), (unsigned int)eee->sup_attempts); + + send_register_super( eee, &(eee->supernode) ); + + eee->sn_wait=1; + + /* REVISIT: turn-on gratuitous ARP with config option. */ + /* send_grat_arps(sock_fd, is_udp_sock); */ + + eee->last_register_req = nowTime; +} + + + +/* @return 1 if destination is a peer, 0 if destination is supernode */ +static int find_peer_destination(n2n_edge_t * eee, + n2n_mac_t mac_address, + n2n_sock_t * destination) +{ + const struct peer_info *scan = eee->known_peers; + macstr_t mac_buf; + n2n_sock_str_t sockbuf; + int retval=0; + + traceEvent(TRACE_DEBUG, "Searching destination peer for MAC %02X:%02X:%02X:%02X:%02X:%02X", + mac_address[0] & 0xFF, mac_address[1] & 0xFF, mac_address[2] & 0xFF, + mac_address[3] & 0xFF, mac_address[4] & 0xFF, mac_address[5] & 0xFF); + + while(scan != NULL) { + traceEvent(TRACE_DEBUG, "Evaluating peer [MAC=%02X:%02X:%02X:%02X:%02X:%02X]", + scan->mac_addr[0] & 0xFF, scan->mac_addr[1] & 0xFF, scan->mac_addr[2] & 0xFF, + scan->mac_addr[3] & 0xFF, scan->mac_addr[4] & 0xFF, scan->mac_addr[5] & 0xFF + ); + + if((scan->last_seen > 0) && + (memcmp(mac_address, scan->mac_addr, N2N_MAC_SIZE) == 0)) + { + memcpy(destination, &scan->sock, sizeof(n2n_sock_t)); + retval=1; + break; + } + scan = scan->next; + } + + if ( 0 == retval ) + { + memcpy(destination, &(eee->supernode), sizeof(struct sockaddr_in)); + } + + traceEvent(TRACE_DEBUG, "find_peer_address (%s) -> [%s]", + macaddr_str( mac_buf, mac_address ), + sock_to_cstr( sockbuf, destination ) ); + + return retval; +} + + + + +/* *********************************************** */ + +static const struct option long_options[] = { + { "community", required_argument, NULL, 'c' }, + { "supernode-list", required_argument, NULL, 'l' }, + { "tun-device", required_argument, NULL, 'd' }, + { "euid", required_argument, NULL, 'u' }, + { "egid", required_argument, NULL, 'g' }, + { "help" , no_argument, NULL, 'h' }, + { "verbose", no_argument, NULL, 'v' }, + { NULL, 0, NULL, 0 } +}; + +/* ***************************************************** */ + + +/** Send an ecapsulated ethernet PACKET to a destination edge or broadcast MAC + * address. */ +static int send_PACKET( n2n_edge_t * eee, + n2n_mac_t dstMac, + const uint8_t * pktbuf, + size_t pktlen ) +{ + int dest; + ssize_t s; + n2n_sock_str_t sockbuf; + n2n_sock_t destination; + + /* hexdump( pktbuf, pktlen ); */ + + dest = find_peer_destination(eee, dstMac, &destination); + + if ( dest ) + { + ++(eee->tx_p2p); + } + else + { + ++(eee->tx_sup); + } + + traceEvent( TRACE_INFO, "send_PACKET to %s", sock_to_cstr( sockbuf, &destination ) ); + + s = sendto_sock( eee->udp_sock, pktbuf, pktlen, &destination ); + + return 0; +} + + +/* Choose the transop for Tx. This should be based on the newest valid + * cipherspec in the key schedule. + * + * Never fall back to NULL tranform unless no key sources were specified. It is + * better to render edge inoperative than to expose user data in the clear. In + * the case where all SAs are expired an arbitrary transform will be chosen for + * Tx. It will fail having no valid SAs but one must be selected. + */ +static size_t edge_choose_tx_transop( const n2n_edge_t * eee ) +{ + if ( eee->null_transop) + { + return N2N_TRANSOP_NULL_IDX; + } + + return eee->tx_transop_idx; +} + + +/** A layer-2 packet was received at the tunnel and needs to be sent via UDP. */ +static void send_packet2net(n2n_edge_t * eee, + uint8_t *tap_pkt, size_t len) +{ + ipstr_t ip_buf; + n2n_mac_t destMac; + + n2n_common_t cmn; + n2n_PACKET_t pkt; + + uint8_t pktbuf[N2N_PKT_BUF_SIZE]; + size_t idx=0; + size_t tx_transop_idx=0; + + ether_hdr_t eh; + + /* tap_pkt is not aligned so we have to copy to aligned memory */ + memcpy( &eh, tap_pkt, sizeof(ether_hdr_t) ); + + /* Discard IP packets that are not originated by this hosts */ + if(!(eee->allow_routing)) { + if(ntohs(eh.type) == 0x0800) { + /* This is an IP packet from the local source address - not forwarded. */ +#define ETH_FRAMESIZE 14 +#define IP4_SRCOFFSET 12 + uint32_t *dst = (uint32_t*)&tap_pkt[ETH_FRAMESIZE + IP4_SRCOFFSET]; + + /* Note: all elements of the_ip are in network order */ + if( *dst != eee->device.ip_addr) { + /* This is a packet that needs to be routed */ + traceEvent(TRACE_INFO, "Discarding routed packet [%s]", + intoa(ntohl(*dst), ip_buf, sizeof(ip_buf))); + return; + } else { + /* This packet is originated by us */ + /* traceEvent(TRACE_INFO, "Sending non-routed packet"); */ + } + } + } + + /* Optionally compress then apply transforms, eg encryption. */ + + /* Once processed, send to destination in PACKET */ + + memcpy( destMac, tap_pkt, N2N_MAC_SIZE ); /* dest MAC is first in ethernet header */ + + memset( &cmn, 0, sizeof(cmn) ); + cmn.ttl = N2N_DEFAULT_TTL; + cmn.pc = n2n_packet; + cmn.flags=0; /* no options, not from supernode, no socket */ + memcpy( cmn.community, eee->community_name, N2N_COMMUNITY_SIZE ); + + memset( &pkt, 0, sizeof(pkt) ); + memcpy( pkt.srcMac, eee->device.mac_addr, N2N_MAC_SIZE); + memcpy( pkt.dstMac, destMac, N2N_MAC_SIZE); + + tx_transop_idx = edge_choose_tx_transop( eee ); + + pkt.sock.family=0; /* do not encode sock */ + pkt.transform = eee->transop[tx_transop_idx].transform_id; + + idx=0; + encode_PACKET( pktbuf, &idx, &cmn, &pkt ); + traceEvent( TRACE_DEBUG, "encoded PACKET header of size=%u transform %u (idx=%u)", + (unsigned int)idx, (unsigned int)pkt.transform, (unsigned int)tx_transop_idx ); + + idx += eee->transop[tx_transop_idx].fwd( &(eee->transop[tx_transop_idx]), + pktbuf+idx, N2N_PKT_BUF_SIZE-idx, + tap_pkt, len ); + ++(eee->transop[tx_transop_idx].tx_cnt); /* stats */ + + send_PACKET( eee, destMac, pktbuf, idx ); /* to peer or supernode */ +} + + +/** Destination MAC 33:33:0:00:00:00 - 33:33:FF:FF:FF:FF is reserved for IPv6 + * neighbour discovery. + */ +static int is_ip6_discovery( const void * buf, size_t bufsize ) +{ + int retval = 0; + + if ( bufsize >= sizeof(ether_hdr_t) ) + { + /* copy to aligned memory */ + ether_hdr_t eh; + memcpy( &eh, buf, sizeof(ether_hdr_t) ); + + if ( (0x33 == eh.dhost[0]) && + (0x33 == eh.dhost[1]) ) + { + retval = 1; /* This is an IPv6 multicast packet [RFC2464]. */ + } + } + return retval; +} + +/** Destination 01:00:5E:00:00:00 - 01:00:5E:7F:FF:FF is multicast ethernet. + */ +static int is_ethMulticast( const void * buf, size_t bufsize ) +{ + int retval = 0; + + /* Match 01:00:5E:00:00:00 - 01:00:5E:7F:FF:FF */ + if ( bufsize >= sizeof(ether_hdr_t) ) + { + /* copy to aligned memory */ + ether_hdr_t eh; + memcpy( &eh, buf, sizeof(ether_hdr_t) ); + + if ( (0x01 == eh.dhost[0]) && + (0x00 == eh.dhost[1]) && + (0x5E == eh.dhost[2]) && + (0 == (0x80 & eh.dhost[3])) ) + { + retval = 1; /* This is an ethernet multicast packet [RFC1112]. */ + } + } + return retval; +} + + + +/** Read a single packet from the TAP interface, process it and write out the + * corresponding packet to the cooked socket. + */ +static void readFromTAPSocket( n2n_edge_t * eee ) +{ + /* tun -> remote */ + uint8_t eth_pkt[N2N_PKT_BUF_SIZE]; + macstr_t mac_buf; + ssize_t len; + + len = tuntap_read( &(eee->device), eth_pkt, N2N_PKT_BUF_SIZE ); + + if( (len <= 0) || (len > N2N_PKT_BUF_SIZE) ) + { + traceEvent(TRACE_WARNING, "read()=%d [%d/%s]", + (signed int)len, errno, strerror(errno)); + } + else + { + const uint8_t * mac = eth_pkt; + traceEvent(TRACE_INFO, "### Rx TAP packet (%4d) for %s", + (signed int)len, macaddr_str(mac_buf, mac) ); + + if ( eee->drop_multicast && + ( is_ip6_discovery( eth_pkt, len ) || + is_ethMulticast( eth_pkt, len) + ) + ) + { + traceEvent(TRACE_DEBUG, "Dropping multicast"); + } + else + { + send_packet2net(eee, eth_pkt, len); + } + } +} + + + +/** A PACKET has arrived containing an encapsulated ethernet datagram - usually + * encrypted. */ +static int handle_PACKET( n2n_edge_t * eee, + const n2n_common_t * cmn, + const n2n_PACKET_t * pkt, + const n2n_sock_t * orig_sender, + uint8_t * payload, + size_t psize ) +{ + ssize_t data_sent_len; + uint8_t from_supernode; + uint8_t * eth_payload=NULL; + int retval = -1; + time_t now; + + now = time(NULL); + + traceEvent( TRACE_DEBUG, "handle_PACKET size %u transform %u", + (unsigned int)psize, (unsigned int)pkt->transform ); + /* hexdump( payload, psize ); */ + + from_supernode= cmn->flags & N2N_FLAGS_FROM_SUPERNODE; + + if ( from_supernode ) + { + ++(eee->rx_sup); + eee->last_sup=now; + } + else + { + ++(eee->rx_p2p); + eee->last_p2p=now; + } + + /* Update the sender in peer table entry */ + check_peer( eee, from_supernode, pkt->srcMac, orig_sender ); + + /* Handle transform. */ + { + uint8_t decodebuf[N2N_PKT_BUF_SIZE]; + size_t eth_size; + size_t rx_transop_idx=0; + + rx_transop_idx = transop_enum_to_index(pkt->transform); + + if ( rx_transop_idx >=0 ) + { + eth_payload = decodebuf; + eth_size = eee->transop[rx_transop_idx].rev( &(eee->transop[rx_transop_idx]), + eth_payload, N2N_PKT_BUF_SIZE, + payload, psize ); + ++(eee->transop[rx_transop_idx].rx_cnt); /* stats */ + + /* Write ethernet packet to tap device. */ + traceEvent( TRACE_INFO, "sending to TAP %u", (unsigned int)eth_size ); + data_sent_len = tuntap_write(&(eee->device), eth_payload, eth_size); + + if (data_sent_len == eth_size) + { + retval = 0; + } + } + else + { + traceEvent( TRACE_ERROR, "handle_PACKET dropped unknown transform enum %u", + (unsigned int)pkt->transform ); + } + } + + return retval; +} + + +/** Read a datagram from the management UDP socket and take appropriate + * action. */ +static void readFromMgmtSocket( n2n_edge_t * eee, int * keep_running ) +{ + uint8_t udp_buf[N2N_PKT_BUF_SIZE]; /* Compete UDP packet */ + ssize_t recvlen; + ssize_t sendlen; + struct sockaddr_in sender_sock; + socklen_t i; + size_t msg_len; + time_t now; + + now = time(NULL); + i = sizeof(sender_sock); + recvlen=recvfrom(eee->udp_mgmt_sock, udp_buf, N2N_PKT_BUF_SIZE, 0/*flags*/, + (struct sockaddr *)&sender_sock, (socklen_t*)&i); + + if ( recvlen < 0 ) + { + traceEvent(TRACE_ERROR, "mgmt recvfrom failed with %s", strerror(errno) ); + + return; /* failed to receive data from UDP */ + } + + if ( recvlen >= 4 ) + { + if ( 0 == memcmp( udp_buf, "stop", 4 ) ) + { + traceEvent( TRACE_ERROR, "stop command received." ); + *keep_running = 0; + return; + } + + if ( 0 == memcmp( udp_buf, "help", 4 ) ) + { + msg_len=0; + ++traceLevel; + + msg_len += snprintf( (char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len), + "Help for edge management console:\n" + " stop Gracefully exit edge\n" + " help This help message\n" + " +verb Increase verbosity of logging\n" + " -verb Decrease verbosity of logging\n" + " reload Re-read the keyschedule\n" + " Display statistics\n\n"); + + sendto( eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/, + (struct sockaddr *)&sender_sock, sizeof(struct sockaddr_in) ); + + return; + } + + } + + if ( recvlen >= 5 ) + { + if ( 0 == memcmp( udp_buf, "+verb", 5 ) ) + { + msg_len=0; + ++traceLevel; + + traceEvent( TRACE_ERROR, "+verb traceLevel=%u", (unsigned int)traceLevel ); + msg_len += snprintf( (char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len), + "> +OK traceLevel=%u\n", (unsigned int)traceLevel ); + + sendto( eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/, + (struct sockaddr *)&sender_sock, sizeof(struct sockaddr_in) ); + + return; + } + + if ( 0 == memcmp( udp_buf, "-verb", 5 ) ) + { + msg_len=0; + + if ( traceLevel > 0 ) + { + --traceLevel; + msg_len += snprintf( (char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len), + "> -OK traceLevel=%u\n", traceLevel ); + } + else + { + msg_len += snprintf( (char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len), + "> -NOK traceLevel=%u\n", traceLevel ); + } + + traceEvent( TRACE_ERROR, "-verb traceLevel=%u", (unsigned int)traceLevel ); + + sendto( eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/, + (struct sockaddr *)&sender_sock, sizeof(struct sockaddr_in) ); + return; + } + } + + if ( recvlen >= 6 ) + { + if ( 0 == memcmp( udp_buf, "reload", 6 ) ) + { + if ( strlen( eee->keyschedule ) > 0 ) + { + if ( edge_init_keyschedule(eee) == 0 ) + { + msg_len=0; + msg_len += snprintf( (char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len), + "> OK\n" ); + sendto( eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/, + (struct sockaddr *)&sender_sock, sizeof(struct sockaddr_in) ); + } + return; + } + } + } + + traceEvent(TRACE_DEBUG, "mgmt status rq" ); + + msg_len=0; + msg_len += snprintf( (char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len), + "Statistics for edge\n" ); + + msg_len += snprintf( (char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len), + "uptime %lu\n", + time(NULL) - eee->start_time ); + + msg_len += snprintf( (char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len), + "paths super:%u,%u p2p:%u,%u\n", + (unsigned int)eee->tx_sup, + (unsigned int)eee->rx_sup, + (unsigned int)eee->tx_p2p, + (unsigned int)eee->rx_p2p ); + + msg_len += snprintf( (char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len), + "trans:null |%6u|%6u|\n" + "trans:tf |%6u|%6u|\n" + "trans:aes |%6u|%6u|\n", + (unsigned int)eee->transop[N2N_TRANSOP_NULL_IDX].tx_cnt, + (unsigned int)eee->transop[N2N_TRANSOP_NULL_IDX].rx_cnt, + (unsigned int)eee->transop[N2N_TRANSOP_TF_IDX].tx_cnt, + (unsigned int)eee->transop[N2N_TRANSOP_TF_IDX].rx_cnt, + (unsigned int)eee->transop[N2N_TRANSOP_AESCBC_IDX].tx_cnt, + (unsigned int)eee->transop[N2N_TRANSOP_AESCBC_IDX].rx_cnt ); + + msg_len += snprintf( (char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len), + "peers pend:%u full:%u\n", + (unsigned int)peer_list_size( eee->pending_peers ), + (unsigned int)peer_list_size( eee->known_peers ) ); + + msg_len += snprintf( (char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len), + "last super:%lu(%ld sec ago) p2p:%lu(%ld sec ago)\n", + eee->last_sup, (now-eee->last_sup), eee->last_p2p, (now-eee->last_p2p) ); + + traceEvent(TRACE_DEBUG, "mgmt status sending: %s", udp_buf ); + + + sendlen = sendto( eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/, + (struct sockaddr *)&sender_sock, sizeof(struct sockaddr_in) ); + +} + + +/** Read a datagram from the main UDP socket to the internet. */ +static void readFromIPSocket( n2n_edge_t * eee ) +{ + n2n_common_t cmn; /* common fields in the packet header */ + + n2n_sock_str_t sockbuf1; + n2n_sock_str_t sockbuf2; /* don't clobber sockbuf1 if writing two addresses to trace */ + macstr_t mac_buf1; + macstr_t mac_buf2; + + uint8_t udp_buf[N2N_PKT_BUF_SIZE]; /* Compete UDP packet */ + ssize_t recvlen; + size_t rem; + size_t idx; + size_t msg_type; + uint8_t from_supernode; + struct sockaddr_in sender_sock; + n2n_sock_t sender; + n2n_sock_t * orig_sender=NULL; + time_t now=0; + + size_t i; + + i = sizeof(sender_sock); + recvlen=recvfrom(eee->udp_sock, udp_buf, N2N_PKT_BUF_SIZE, 0/*flags*/, + (struct sockaddr *)&sender_sock, (socklen_t*)&i); + + if ( recvlen < 0 ) + { + traceEvent(TRACE_ERROR, "recvfrom failed with %s", strerror(errno) ); + + return; /* failed to receive data from UDP */ + } + + /* REVISIT: when UDP/IPv6 is supported we will need a flag to indicate which + * IP transport version the packet arrived on. May need to UDP sockets. */ + sender.family = AF_INET; /* udp_sock was opened PF_INET v4 */ + sender.port = ntohs(sender_sock.sin_port); + memcpy( &(sender.addr.v4), &(sender_sock.sin_addr.s_addr), IPV4_SIZE ); + + /* The packet may not have an orig_sender socket spec. So default to last + * hop as sender. */ + orig_sender=&sender; + + traceEvent(TRACE_INFO, "### Rx N2N UDP (%d) from %s", + (signed int)recvlen, sock_to_cstr(sockbuf1, &sender) ); + + /* hexdump( udp_buf, recvlen ); */ + + rem = recvlen; /* Counts down bytes of packet to protect against buffer overruns. */ + idx = 0; /* marches through packet header as parts are decoded. */ + if ( decode_common(&cmn, udp_buf, &rem, &idx) < 0 ) + { + traceEvent( TRACE_ERROR, "Failed to decode common section in N2N_UDP" ); + return; /* failed to decode packet */ + } + + now = time(NULL); + + msg_type = cmn.pc; /* packet code */ + from_supernode= cmn.flags & N2N_FLAGS_FROM_SUPERNODE; + + if( 0 == memcmp(cmn.community, eee->community_name, N2N_COMMUNITY_SIZE) ) + { + if( msg_type == MSG_TYPE_PACKET) + { + /* process PACKET - most frequent so first in list. */ + n2n_PACKET_t pkt; + + decode_PACKET( &pkt, &cmn, udp_buf, &rem, &idx ); + + if ( pkt.sock.family ) + { + orig_sender = &(pkt.sock); + } + + traceEvent(TRACE_INFO, "Rx PACKET from %s (%s)", + sock_to_cstr(sockbuf1, &sender), + sock_to_cstr(sockbuf2, orig_sender) ); + + handle_PACKET( eee, &cmn, &pkt, orig_sender, udp_buf+idx, recvlen-idx ); + } + else if(msg_type == MSG_TYPE_REGISTER) + { + /* Another edge is registering with us */ + n2n_REGISTER_t reg; + + decode_REGISTER( ®, &cmn, udp_buf, &rem, &idx ); + + if ( reg.sock.family ) + { + orig_sender = &(reg.sock); + } + + traceEvent(TRACE_INFO, "Rx REGISTER src=%s dst=%s from peer %s (%s)", + macaddr_str( mac_buf1, reg.srcMac ), + macaddr_str( mac_buf2, reg.dstMac ), + sock_to_cstr(sockbuf1, &sender), + sock_to_cstr(sockbuf2, orig_sender) ); + + if ( 0 == memcmp(reg.dstMac, (eee->device.mac_addr), 6) ) + { + check_peer( eee, from_supernode, reg.srcMac, orig_sender ); + } + + send_register_ack(eee, orig_sender, ®); + } + else if(msg_type == MSG_TYPE_REGISTER_ACK) + { + /* Peer edge is acknowledging our register request */ + n2n_REGISTER_ACK_t ra; + + decode_REGISTER_ACK( &ra, &cmn, udp_buf, &rem, &idx ); + + if ( ra.sock.family ) + { + orig_sender = &(ra.sock); + } + + traceEvent(TRACE_INFO, "Rx REGISTER_ACK src=%s dst=%s from peer %s (%s)", + macaddr_str( mac_buf1, ra.srcMac ), + macaddr_str( mac_buf2, ra.dstMac ), + sock_to_cstr(sockbuf1, &sender), + sock_to_cstr(sockbuf2, orig_sender) ); + + /* Move from pending_peers to known_peers; ignore if not in pending. */ + set_peer_operational( eee, ra.srcMac, &sender ); + } + else if(msg_type == MSG_TYPE_REGISTER_SUPER_ACK) + { + n2n_REGISTER_SUPER_ACK_t ra; + + if ( eee->sn_wait ) + { + decode_REGISTER_SUPER_ACK( &ra, &cmn, udp_buf, &rem, &idx ); + + if ( ra.sock.family ) + { + orig_sender = &(ra.sock); + } + + traceEvent(TRACE_NORMAL, "Rx REGISTER_SUPER_ACK myMAC=%s [%s] (external %s). Attempts %u", + macaddr_str( mac_buf1, ra.edgeMac ), + sock_to_cstr(sockbuf1, &sender), + sock_to_cstr(sockbuf2, orig_sender), + (unsigned int)eee->sup_attempts ); + + if ( 0 == memcmp( ra.cookie, eee->last_cookie, N2N_COOKIE_SIZE ) ) + { + if ( ra.num_sn > 0 ) + { + traceEvent(TRACE_NORMAL, "Rx REGISTER_SUPER_ACK backup supernode at %s", + sock_to_cstr(sockbuf1, &(ra.sn_bak) ) ); + } + + eee->last_sup = now; + eee->sn_wait=0; + eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; /* refresh because we got a response */ + + /* REVISIT: store sn_back */ + eee->register_lifetime = ra.lifetime; + eee->register_lifetime = MAX( eee->register_lifetime, REGISTER_SUPER_INTERVAL_MIN ); + eee->register_lifetime = MIN( eee->register_lifetime, REGISTER_SUPER_INTERVAL_MAX ); + } + else + { + traceEvent( TRACE_WARNING, "Rx REGISTER_SUPER_ACK with wrong or old cookie." ); + } + } + else + { + traceEvent( TRACE_WARNING, "Rx REGISTER_SUPER_ACK with no outstanding REGISTER_SUPER." ); + } + } + else + { + /* Not a known message type */ + traceEvent(TRACE_WARNING, "Unable to handle packet type %d: ignored", (signed int)msg_type); + return; + } + } /* if (community match) */ + else + { + traceEvent(TRACE_WARNING, "Received packet with invalid community"); + } + +} + +/* ***************************************************** */ + + +#ifdef WIN32 +static DWORD tunReadThread(LPVOID lpArg ) +{ + n2n_edge_t *eee = (n2n_edge_t*)lpArg; + + while(1) + { + readFromTAPSocket(eee); + } + + return((DWORD)NULL); +} + + +/** Start a second thread in Windows because TUNTAP interfaces do not expose + * file descriptors. */ +static void startTunReadThread(n2n_edge_t *eee) +{ + HANDLE hThread; + DWORD dwThreadId; + + hThread = CreateThread(NULL, /* security attributes */ + 0, /* use default stack size */ + (LPTHREAD_START_ROUTINE)tunReadThread, /* thread function */ + (void*)eee, /* argument to thread function */ + 0, /* thread creation flags */ + &dwThreadId); /* thread id out */ +} +#endif + +/* ***************************************************** */ + +/** Resolve the supernode IP address. + * + * REVISIT: This is a really bad idea. The edge will block completely while the + * hostname resolution is performed. This could take 15 seconds. + */ +static void supernode2addr(n2n_sock_t * sn, const n2n_sn_name_t addrIn) +{ + n2n_sn_name_t addr; + const char *supernode_host; + + memcpy( addr, addrIn, N2N_EDGE_SN_HOST_SIZE ); + + supernode_host = strtok(addr, ":"); + + if(supernode_host) + { + in_addr_t sn_addr; + char *supernode_port = strtok(NULL, ":"); + const struct addrinfo aihints = {0, PF_INET, 0, 0, 0, NULL, NULL, NULL}; + struct addrinfo * ainfo = NULL; + int nameerr; + + if ( supernode_port ) + sn->port = atoi(supernode_port); + else + traceEvent(TRACE_WARNING, "Bad supernode parameter (-l ) %s %s:%s", + addr, supernode_host, supernode_port); + + nameerr = getaddrinfo( supernode_host, NULL, &aihints, &ainfo ); + + if( 0 == nameerr ) + { + struct sockaddr_in * saddr; + + /* ainfo s the head of a linked list if non-NULL. */ + if ( ainfo && (PF_INET == ainfo->ai_family) ) + { + /* It is definitely and IPv4 address -> sockaddr_in */ + saddr = (struct sockaddr_in *)ainfo->ai_addr; + + memcpy( sn->addr.v4, &(saddr->sin_addr.s_addr), IPV4_SIZE ); + sn->family=AF_INET; + } + else + { + /* Should only return IPv4 addresses due to aihints. */ + traceEvent(TRACE_WARNING, "Failed to resolve supernode IPv4 address for %s", supernode_host); + } + + freeaddrinfo(ainfo); /* free everything allocated by getaddrinfo(). */ + ainfo = NULL; + } else { + traceEvent(TRACE_WARNING, "Failed to resolve supernode host %s, assuming numeric", supernode_host); + sn_addr = inet_addr(supernode_host); /* uint32_t */ + memcpy( sn->addr.v4, &(sn_addr), IPV4_SIZE ); + sn->family=AF_INET; + } + + } else + traceEvent(TRACE_WARNING, "Wrong supernode parameter (-l )"); +} + +/* ***************************************************** */ + + +/** Find the address and IP mode for the tuntap device. + * + * s is one of these forms: + * + * := | A.B.C.D + * + * | static: | dhcp: + * + * If the mode is present (colon required) then fill ip_mode with that value + * otherwise do not change ip_mode. Fill ip_mode with everything after the + * colon if it is present; or s if colon is not present. + * + * ip_add and ip_mode are NULL terminated if modified. + * + * return 0 on success and -1 on error + */ +static int scan_address( char * ip_addr, size_t addr_size, + char * ip_mode, size_t mode_size, + const char * s ) +{ + int retval = -1; + char * p; + + if ( ( NULL == s ) || ( NULL == ip_addr) ) + { + return -1; + } + + memset(ip_addr, 0, addr_size); + + p = strpbrk(s, ":"); + + if ( p ) + { + /* colon is present */ + if ( ip_mode ) + { + size_t end=0; + + memset(ip_mode, 0, mode_size); + end = MIN( p-s, (ssize_t)(mode_size-1) ); /* ensure NULL term */ + strncpy( ip_mode, s, end ); + strncpy( ip_addr, p+1, addr_size-1 ); /* ensure NULL term */ + retval = 0; + } + } + else + { + /* colon is not present */ + strncpy( ip_addr, s, addr_size ); + } + + return retval; +} + +static int run_loop(n2n_edge_t * eee ); + +#define N2N_NETMASK_STR_SIZE 16 /* dotted decimal 12 numbers + 3 dots */ +#define N2N_MACNAMSIZ 18 /* AA:BB:CC:DD:EE:FF + NULL*/ +#define N2N_IF_MODE_SIZE 16 /* static | dhcp */ + +/** Entry point to program from kernel. */ +int main(int argc, char* argv[]) +{ + int opt; + int local_port = 0 /* any port */; + int mgmt_port = N2N_EDGE_MGMT_PORT; /* 5644 by default */ + char tuntap_dev_name[N2N_IFNAMSIZ] = "edge0"; + char ip_mode[N2N_IF_MODE_SIZE]="static"; + char ip_addr[N2N_NETMASK_STR_SIZE] = ""; + char netmask[N2N_NETMASK_STR_SIZE]="255.255.255.0"; + int mtu = DEFAULT_MTU; + int got_s = 0; + +#ifndef WIN32 + uid_t userid=0; /* root is the only guaranteed ID */ + gid_t groupid=0; /* root is the only guaranteed ID */ +#endif + + char device_mac[N2N_MACNAMSIZ]=""; + char * encrypt_key=NULL; + + int i, effectiveargc=0; + char ** effectiveargv=NULL; + char * linebuffer = NULL; + + n2n_edge_t eee; /* single instance for this program */ + + if (-1 == edge_init(&eee) ) + { + traceEvent( TRACE_ERROR, "Failed in edge_init" ); + exit(1); + } + + if( getenv( "N2N_KEY" )) + { + encrypt_key = strdup( getenv( "N2N_KEY" )); + } + +#ifdef WIN32 + tuntap_dev_name[0] = '\0'; +#endif + memset(&(eee.supernode), 0, sizeof(eee.supernode)); + eee.supernode.family = AF_INET; + + linebuffer = (char *)malloc(MAX_CMDLINE_BUFFER_LENGTH); + if (!linebuffer) + { + traceEvent( TRACE_ERROR, "Unable to allocate memory"); + exit(1); + } + snprintf(linebuffer, MAX_CMDLINE_BUFFER_LENGTH, "%s",argv[0]); + +#ifdef WIN32 + for(i=0; i < (int)strlen(linebuffer); i++) + if(linebuffer[i] == '\\') linebuffer[i] = '/'; +#endif + + for(i=1;i 0 ) + { + fprintf(stderr, "Error: -K and -k options are mutually exclusive.\n"); + exit(1); + } else { + traceEvent(TRACE_DEBUG, "encrypt_key = '%s'\n", encrypt_key); + encrypt_key = strdup(optarg); + } + break; + } + case 'r': /* enable packet routing across n2n endpoints */ + { + eee.allow_routing = 1; + break; + } + + case 'l': /* supernode-list */ + { + if ( eee.sn_num < N2N_EDGE_NUM_SUPERNODES ) + { + strncpy( (eee.sn_ip_array[eee.sn_num]), optarg, N2N_EDGE_SN_HOST_SIZE); + traceEvent(TRACE_DEBUG, "Adding supernode[%u] = %s\n", (unsigned int)eee.sn_num, (eee.sn_ip_array[eee.sn_num]) ); + ++eee.sn_num; + } + else + { + fprintf(stderr, "Too many supernodes!\n" ); + exit(1); + } + break; + } + +#if defined(N2N_CAN_NAME_IFACE) + case 'd': /* TUNTAP name */ + { + strncpy(tuntap_dev_name, optarg, N2N_IFNAMSIZ); + break; + } +#endif + + case 'b': + { + eee.re_resolve_supernode_ip = 1; + break; + } + + case 'p': + { + local_port = atoi(optarg); + break; + } + + case 't': + { + mgmt_port = atoi(optarg); + break; + } + + case 's': /* Subnet Mask */ + { + if (0 != got_s) + { + traceEvent(TRACE_WARNING, "Multiple subnet masks supplied."); + } + strncpy(netmask, optarg, N2N_NETMASK_STR_SIZE); + got_s = 1; + break; + } + + case 'h': /* help */ + { + help(); + break; + } + + case 'v': /* verbose */ + { + ++traceLevel; /* do 2 -v flags to increase verbosity to DEBUG level*/ + break; + } + + } /* end switch */ + } + + +#ifdef N2N_HAVE_DAEMON + if ( eee.daemon ) + { + useSyslog=1; /* traceEvent output now goes to syslog. */ + if ( -1 == daemon( 0, 0 ) ) + { + traceEvent( TRACE_ERROR, "Failed to become daemon." ); + exit(-5); + } + } +#endif /* #ifdef N2N_HAVE_DAEMON */ + + + traceEvent( TRACE_NORMAL, "Starting n2n edge %s %s", n2n_sw_version, n2n_sw_buildDate ); + + + for (i=0; i< N2N_EDGE_NUM_SUPERNODES; ++i ) + { + traceEvent( TRACE_NORMAL, "supernode %u => %s\n", i, (eee.sn_ip_array[i]) ); + } + + supernode2addr( &(eee.supernode), eee.sn_ip_array[eee.sn_idx] ); + + + for ( i=0; i 0) + traceEvent(TRACE_NORMAL, "Binding to local port %d", (signed int)local_port); + + if ( encrypt_key ) { + if(edge_init_twofish( &eee, (uint8_t *)(encrypt_key), strlen(encrypt_key) ) < 0) { + fprintf(stderr, "Error: twofish setup failed.\n" ); + return(-1); + } + } else if ( strlen(eee.keyschedule) > 0 ) { + if (edge_init_keyschedule( &eee ) != 0 ) { + fprintf(stderr, "Error: keyschedule setup failed.\n" ); + return(-1); + } + + } + /* else run in NULL mode */ + + + eee.udp_sock = open_socket(local_port, 1 /*bind ANY*/ ); + if(eee.udp_sock < 0) + { + traceEvent( TRACE_ERROR, "Failed to bind main UDP port %u", (signed int)local_port ); + return(-1); + } + + eee.udp_mgmt_sock = open_socket(mgmt_port, 0 /* bind LOOPBACK*/ ); + + if(eee.udp_mgmt_sock < 0) + { + traceEvent( TRACE_ERROR, "Failed to bind management UDP port %u", (unsigned int)N2N_EDGE_MGMT_PORT ); + return(-1); + } + + + traceEvent(TRACE_NORMAL, "edge started"); + + update_supernode_reg(&eee, time(NULL) ); + + return run_loop(&eee); +} + +static int run_loop(n2n_edge_t * eee ) +{ + int keep_running=1; + size_t numPurged; + time_t lastIfaceCheck=0; + time_t lastTransop=0; + + +#ifdef WIN32 + startTunReadThread(eee); +#endif + + /* Main loop + * + * select() is used to wait for input on either the TAP fd or the UDP/TCP + * socket. When input is present the data is read and processed by either + * readFromIPSocket() or readFromTAPSocket() + */ + + while(keep_running) + { + int rc, max_sock = 0; + fd_set socket_mask; + struct timeval wait_time; + time_t nowTime; + + FD_ZERO(&socket_mask); + FD_SET(eee->udp_sock, &socket_mask); + FD_SET(eee->udp_mgmt_sock, &socket_mask); + max_sock = max( eee->udp_sock, eee->udp_mgmt_sock ); +#ifndef WIN32 + FD_SET(eee->device.fd, &socket_mask); + max_sock = max( max_sock, eee->device.fd ); +#endif + + wait_time.tv_sec = SOCKET_TIMEOUT_INTERVAL_SECS; wait_time.tv_usec = 0; + + rc = select(max_sock+1, &socket_mask, NULL, NULL, &wait_time); + nowTime=time(NULL); + + /* Make sure ciphers are updated before the packet is treated. */ + if ( ( nowTime - lastTransop ) > TRANSOP_TICK_INTERVAL ) + { + lastTransop = nowTime; + + n2n_tick_transop( eee, nowTime ); + } + + if(rc > 0) + { + /* Any or all of the FDs could have input; check them all. */ + + if(FD_ISSET(eee->udp_sock, &socket_mask)) + { + /* Read a cooked socket from the internet socket. Writes on the TAP + * socket. */ + readFromIPSocket(eee); + } + + if(FD_ISSET(eee->udp_mgmt_sock, &socket_mask)) + { + /* Read a cooked socket from the internet socket. Writes on the TAP + * socket. */ + readFromMgmtSocket(eee, &keep_running); + } + +#ifndef WIN32 + if(FD_ISSET(eee->device.fd, &socket_mask)) + { + /* Read an ethernet frame from the TAP socket. Write on the IP + * socket. */ + readFromTAPSocket(eee); + } +#endif + } + + /* Finished processing select data. */ + + + update_supernode_reg(eee, nowTime); + + numPurged = purge_expired_registrations( &(eee->known_peers) ); + numPurged += purge_expired_registrations( &(eee->pending_peers) ); + if ( numPurged > 0 ) + { + traceEvent( TRACE_NORMAL, "Peer removed: pending=%u, operational=%u", + (unsigned int)peer_list_size( eee->pending_peers ), + (unsigned int)peer_list_size( eee->known_peers ) ); + } + + if ( eee->dyn_ip_mode && + (( nowTime - lastIfaceCheck ) > IFACE_UPDATE_INTERVAL ) ) + { + traceEvent(TRACE_NORMAL, "Re-checking dynamic IP address."); + tuntap_get_address( &(eee->device) ); + lastIfaceCheck = nowTime; + } + + } /* while */ + + send_deregister( eee, &(eee->supernode)); + + closesocket(eee->udp_sock); + tuntap_close(&(eee->device)); + + edge_deinit( eee ); + + return(0); +} + + diff --git a/gen_keyfile.py b/gen_keyfile.py new file mode 100755 index 0000000..b6dc3e6 --- /dev/null +++ b/gen_keyfile.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python + +# (c) 2009 Richard Andrews + +# Program to generate a n2n_edge key schedule file for twofish keys +# Each key line consists of the following element +# +# +# where , are UNIX time_t values of key valid period +# is the transform ID (=2 for twofish) +# is twofish-specific data as follows +# _ + +import os +import sys +import time +import random + +NUM_KEYS=30 +KEY_LIFE=300 +KEY_LEN=16 + +now=time.time() +start_sa=random.randint( 0, 0xffffffff ) + +random.seed(now) # note now is a floating point time value + +def rand_key(): + key=str() + for i in range(0,KEY_LEN): + key += "%02x"%( random.randint( 0, 255) ) + + return key + +for i in range(0,NUM_KEYS): + from_time = now + (KEY_LIFE * (i-1) ) + until_time = now + (KEY_LIFE * (i+1) ) + key = rand_key() + sa_idx = start_sa + i + transform_id = random.randint( 2, 3 ) + + sys.stdout.write("%d %d %d %d_%s\n"%(from_time, until_time, transform_id,sa_idx, key) ) + + diff --git a/lzoconf.h b/lzoconf.h new file mode 100644 index 0000000..cc437f1 --- /dev/null +++ b/lzoconf.h @@ -0,0 +1,417 @@ +/* lzoconf.h -- configuration for the LZO real-time data compression library + + This file is part of the LZO real-time data compression library. + + Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + The LZO library 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. + + The LZO library 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 the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Markus F.X.J. Oberhumer + + http://www.oberhumer.com/opensource/lzo/ + */ + + +#ifndef __LZOCONF_H_INCLUDED +#define __LZOCONF_H_INCLUDED + +#define LZO_VERSION 0x2030 +#define LZO_VERSION_STRING "2.03" +#define LZO_VERSION_DATE "Apr 30 2008" + +/* internal Autoconf configuration file - only used when building LZO */ +#if defined(LZO_HAVE_CONFIG_H) +# include +#endif +#include +#include + + +/*********************************************************************** +// LZO requires a conforming +************************************************************************/ + +#if !defined(CHAR_BIT) || (CHAR_BIT != 8) +# error "invalid CHAR_BIT" +#endif +#if !defined(UCHAR_MAX) || !defined(UINT_MAX) || !defined(ULONG_MAX) +# error "check your compiler installation" +#endif +#if (USHRT_MAX < 1) || (UINT_MAX < 1) || (ULONG_MAX < 1) +# error "your limits.h macros are broken" +#endif + +/* get OS and architecture defines */ +#ifndef __LZODEFS_H_INCLUDED +#include "lzodefs.h" +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + + +/*********************************************************************** +// some core defines +************************************************************************/ + +#if !defined(LZO_UINT32_C) +# if (UINT_MAX < LZO_0xffffffffL) +# define LZO_UINT32_C(c) c ## UL +# else +# define LZO_UINT32_C(c) ((c) + 0U) +# endif +#endif + +/* memory checkers */ +#if !defined(__LZO_CHECKER) +# if defined(__BOUNDS_CHECKING_ON) +# define __LZO_CHECKER 1 +# elif defined(__CHECKER__) +# define __LZO_CHECKER 1 +# elif defined(__INSURE__) +# define __LZO_CHECKER 1 +# elif defined(__PURIFY__) +# define __LZO_CHECKER 1 +# endif +#endif + + +/*********************************************************************** +// integral and pointer types +************************************************************************/ + +/* lzo_uint should match size_t */ +#if !defined(LZO_UINT_MAX) +# if defined(LZO_ABI_LLP64) /* WIN64 */ +# if defined(LZO_OS_WIN64) + typedef unsigned __int64 lzo_uint; + typedef __int64 lzo_int; +# else + typedef unsigned long long lzo_uint; + typedef long long lzo_int; +# endif +# define LZO_UINT_MAX 0xffffffffffffffffull +# define LZO_INT_MAX 9223372036854775807LL +# define LZO_INT_MIN (-1LL - LZO_INT_MAX) +# elif defined(LZO_ABI_IP32L64) /* MIPS R5900 */ + typedef unsigned int lzo_uint; + typedef int lzo_int; +# define LZO_UINT_MAX UINT_MAX +# define LZO_INT_MAX INT_MAX +# define LZO_INT_MIN INT_MIN +# elif (ULONG_MAX >= LZO_0xffffffffL) + typedef unsigned long lzo_uint; + typedef long lzo_int; +# define LZO_UINT_MAX ULONG_MAX +# define LZO_INT_MAX LONG_MAX +# define LZO_INT_MIN LONG_MIN +# else +# error "lzo_uint" +# endif +#endif + +/* Integral types with 32 bits or more. */ +#if !defined(LZO_UINT32_MAX) +# if (UINT_MAX >= LZO_0xffffffffL) + typedef unsigned int lzo_uint32; + typedef int lzo_int32; +# define LZO_UINT32_MAX UINT_MAX +# define LZO_INT32_MAX INT_MAX +# define LZO_INT32_MIN INT_MIN +# elif (ULONG_MAX >= LZO_0xffffffffL) + typedef unsigned long lzo_uint32; + typedef long lzo_int32; +# define LZO_UINT32_MAX ULONG_MAX +# define LZO_INT32_MAX LONG_MAX +# define LZO_INT32_MIN LONG_MIN +# else +# error "lzo_uint32" +# endif +#endif + +/* The larger type of lzo_uint and lzo_uint32. */ +#if (LZO_UINT_MAX >= LZO_UINT32_MAX) +# define lzo_xint lzo_uint +#else +# define lzo_xint lzo_uint32 +#endif + +/* Memory model that allows to access memory at offsets of lzo_uint. */ +#if !defined(__LZO_MMODEL) +# if (LZO_UINT_MAX <= UINT_MAX) +# define __LZO_MMODEL +# elif defined(LZO_HAVE_MM_HUGE_PTR) +# define __LZO_MMODEL_HUGE 1 +# define __LZO_MMODEL __huge +# else +# define __LZO_MMODEL +# endif +#endif + +/* no typedef here because of const-pointer issues */ +#define lzo_bytep unsigned char __LZO_MMODEL * +#define lzo_charp char __LZO_MMODEL * +#define lzo_voidp void __LZO_MMODEL * +#define lzo_shortp short __LZO_MMODEL * +#define lzo_ushortp unsigned short __LZO_MMODEL * +#define lzo_uint32p lzo_uint32 __LZO_MMODEL * +#define lzo_int32p lzo_int32 __LZO_MMODEL * +#define lzo_uintp lzo_uint __LZO_MMODEL * +#define lzo_intp lzo_int __LZO_MMODEL * +#define lzo_xintp lzo_xint __LZO_MMODEL * +#define lzo_voidpp lzo_voidp __LZO_MMODEL * +#define lzo_bytepp lzo_bytep __LZO_MMODEL * +/* deprecated - use `lzo_bytep' instead of `lzo_byte *' */ +#define lzo_byte unsigned char __LZO_MMODEL + +typedef int lzo_bool; + + +/*********************************************************************** +// function types +************************************************************************/ + +/* name mangling */ +#if !defined(__LZO_EXTERN_C) +# ifdef __cplusplus +# define __LZO_EXTERN_C extern "C" +# else +# define __LZO_EXTERN_C extern +# endif +#endif + +/* calling convention */ +#if !defined(__LZO_CDECL) +# define __LZO_CDECL __lzo_cdecl +#endif + +/* DLL export information */ +#if !defined(__LZO_EXPORT1) +# define __LZO_EXPORT1 +#endif +#if !defined(__LZO_EXPORT2) +# define __LZO_EXPORT2 +#endif + +/* __cdecl calling convention for public C and assembly functions */ +#if !defined(LZO_PUBLIC) +# define LZO_PUBLIC(_rettype) __LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_CDECL +#endif +#if !defined(LZO_EXTERN) +# define LZO_EXTERN(_rettype) __LZO_EXTERN_C LZO_PUBLIC(_rettype) +#endif +#if !defined(LZO_PRIVATE) +# define LZO_PRIVATE(_rettype) static _rettype __LZO_CDECL +#endif + +/* function types */ +typedef int +(__LZO_CDECL *lzo_compress_t) ( const lzo_bytep src, lzo_uint src_len, + lzo_bytep dst, lzo_uintp dst_len, + lzo_voidp wrkmem ); + +typedef int +(__LZO_CDECL *lzo_decompress_t) ( const lzo_bytep src, lzo_uint src_len, + lzo_bytep dst, lzo_uintp dst_len, + lzo_voidp wrkmem ); + +typedef int +(__LZO_CDECL *lzo_optimize_t) ( lzo_bytep src, lzo_uint src_len, + lzo_bytep dst, lzo_uintp dst_len, + lzo_voidp wrkmem ); + +typedef int +(__LZO_CDECL *lzo_compress_dict_t)(const lzo_bytep src, lzo_uint src_len, + lzo_bytep dst, lzo_uintp dst_len, + lzo_voidp wrkmem, + const lzo_bytep dict, lzo_uint dict_len ); + +typedef int +(__LZO_CDECL *lzo_decompress_dict_t)(const lzo_bytep src, lzo_uint src_len, + lzo_bytep dst, lzo_uintp dst_len, + lzo_voidp wrkmem, + const lzo_bytep dict, lzo_uint dict_len ); + + +/* Callback interface. Currently only the progress indicator ("nprogress") + * is used, but this may change in a future release. */ + +struct lzo_callback_t; +typedef struct lzo_callback_t lzo_callback_t; +#define lzo_callback_p lzo_callback_t __LZO_MMODEL * + +/* malloc & free function types */ +typedef lzo_voidp (__LZO_CDECL *lzo_alloc_func_t) + (lzo_callback_p self, lzo_uint items, lzo_uint size); +typedef void (__LZO_CDECL *lzo_free_func_t) + (lzo_callback_p self, lzo_voidp ptr); + +/* a progress indicator callback function */ +typedef void (__LZO_CDECL *lzo_progress_func_t) + (lzo_callback_p, lzo_uint, lzo_uint, int); + +struct lzo_callback_t +{ + /* custom allocators (set to 0 to disable) */ + lzo_alloc_func_t nalloc; /* [not used right now] */ + lzo_free_func_t nfree; /* [not used right now] */ + + /* a progress indicator callback function (set to 0 to disable) */ + lzo_progress_func_t nprogress; + + /* NOTE: the first parameter "self" of the nalloc/nfree/nprogress + * callbacks points back to this struct, so you are free to store + * some extra info in the following variables. */ + lzo_voidp user1; + lzo_xint user2; + lzo_xint user3; +}; + + +/*********************************************************************** +// error codes and prototypes +************************************************************************/ + +/* Error codes for the compression/decompression functions. Negative + * values are errors, positive values will be used for special but + * normal events. + */ +#define LZO_E_OK 0 +#define LZO_E_ERROR (-1) +#define LZO_E_OUT_OF_MEMORY (-2) /* [not used right now] */ +#define LZO_E_NOT_COMPRESSIBLE (-3) /* [not used right now] */ +#define LZO_E_INPUT_OVERRUN (-4) +#define LZO_E_OUTPUT_OVERRUN (-5) +#define LZO_E_LOOKBEHIND_OVERRUN (-6) +#define LZO_E_EOF_NOT_FOUND (-7) +#define LZO_E_INPUT_NOT_CONSUMED (-8) +#define LZO_E_NOT_YET_IMPLEMENTED (-9) /* [not used right now] */ + + +#ifndef lzo_sizeof_dict_t +# define lzo_sizeof_dict_t ((unsigned)sizeof(lzo_bytep)) +#endif + +/* lzo_init() should be the first function you call. + * Check the return code ! + * + * lzo_init() is a macro to allow checking that the library and the + * compiler's view of various types are consistent. + */ +#define lzo_init() __lzo_init_v2(LZO_VERSION,(int)sizeof(short),(int)sizeof(int),\ + (int)sizeof(long),(int)sizeof(lzo_uint32),(int)sizeof(lzo_uint),\ + (int)lzo_sizeof_dict_t,(int)sizeof(char *),(int)sizeof(lzo_voidp),\ + (int)sizeof(lzo_callback_t)) +LZO_EXTERN(int) __lzo_init_v2(unsigned,int,int,int,int,int,int,int,int,int); + +/* version functions (useful for shared libraries) */ +LZO_EXTERN(unsigned) lzo_version(void); +LZO_EXTERN(const char *) lzo_version_string(void); +LZO_EXTERN(const char *) lzo_version_date(void); +LZO_EXTERN(const lzo_charp) _lzo_version_string(void); +LZO_EXTERN(const lzo_charp) _lzo_version_date(void); + +/* string functions */ +LZO_EXTERN(int) +lzo_memcmp(const lzo_voidp _s1, const lzo_voidp _s2, lzo_uint _len); +LZO_EXTERN(lzo_voidp) +lzo_memcpy(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len); +LZO_EXTERN(lzo_voidp) +lzo_memmove(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len); +LZO_EXTERN(lzo_voidp) +lzo_memset(lzo_voidp _s, int _c, lzo_uint _len); + +/* checksum functions */ +LZO_EXTERN(lzo_uint32) +lzo_adler32(lzo_uint32 _adler, const lzo_bytep _buf, lzo_uint _len); +LZO_EXTERN(lzo_uint32) +lzo_crc32(lzo_uint32 _c, const lzo_bytep _buf, lzo_uint _len); +LZO_EXTERN(const lzo_uint32p) +lzo_get_crc32_table(void); + +/* misc. */ +LZO_EXTERN(int) _lzo_config_check(void); +typedef union { lzo_bytep p; lzo_uint u; } __lzo_pu_u; +typedef union { lzo_bytep p; lzo_uint32 u32; } __lzo_pu32_u; +typedef union { void *vp; lzo_bytep bp; lzo_uint32 u32; long l; } lzo_align_t; + +/* align a char pointer on a boundary that is a multiple of `size' */ +LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp _ptr, lzo_uint _size); +#define LZO_PTR_ALIGN_UP(_ptr,_size) \ + ((_ptr) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(_ptr),(lzo_uint)(_size))) + + +/*********************************************************************** +// deprecated macros - only for backward compatibility with LZO v1.xx +************************************************************************/ + +#if defined(LZO_CFG_COMPAT) + +#define __LZOCONF_H 1 + +#if defined(LZO_ARCH_I086) +# define __LZO_i386 1 +#elif defined(LZO_ARCH_I386) +# define __LZO_i386 1 +#endif + +#if defined(LZO_OS_DOS16) +# define __LZO_DOS 1 +# define __LZO_DOS16 1 +#elif defined(LZO_OS_DOS32) +# define __LZO_DOS 1 +#elif defined(LZO_OS_WIN16) +# define __LZO_WIN 1 +# define __LZO_WIN16 1 +#elif defined(LZO_OS_WIN32) +# define __LZO_WIN 1 +#endif + +#define __LZO_CMODEL +#define __LZO_DMODEL +#define __LZO_ENTRY __LZO_CDECL +#define LZO_EXTERN_CDECL LZO_EXTERN +#define LZO_ALIGN LZO_PTR_ALIGN_UP + +#define lzo_compress_asm_t lzo_compress_t +#define lzo_decompress_asm_t lzo_decompress_t + +#endif /* LZO_CFG_COMPAT */ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* already included */ + + +/* vim:set ts=4 et: */ diff --git a/lzodefs.h b/lzodefs.h new file mode 100644 index 0000000..1805637 --- /dev/null +++ b/lzodefs.h @@ -0,0 +1,1807 @@ +/* lzodefs.h -- architecture, OS and compiler specific defines + + This file is part of the LZO real-time data compression library. + + Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + The LZO library 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. + + The LZO library 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 the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Markus F.X.J. Oberhumer + + http://www.oberhumer.com/opensource/lzo/ + */ + + +#ifndef __LZODEFS_H_INCLUDED +#define __LZODEFS_H_INCLUDED 1 + +#if defined(__CYGWIN32__) && !defined(__CYGWIN__) +# define __CYGWIN__ __CYGWIN32__ +#endif +#if defined(__IBMCPP__) && !defined(__IBMC__) +# define __IBMC__ __IBMCPP__ +#endif +#if defined(__ICL) && defined(_WIN32) && !defined(__INTEL_COMPILER) +# define __INTEL_COMPILER __ICL +#endif +#if 1 && defined(__INTERIX) && defined(__GNUC__) && !defined(_ALL_SOURCE) +# define _ALL_SOURCE 1 +#endif +#if defined(__mips__) && defined(__R5900__) +# if !defined(__LONG_MAX__) +# define __LONG_MAX__ 9223372036854775807L +# endif +#endif +#if defined(__INTEL_COMPILER) && defined(__linux__) +# pragma warning(disable: 193) +#endif +#if defined(__KEIL__) && defined(__C166__) +# pragma warning disable = 322 +#elif 0 && defined(__C251__) +# pragma warning disable = 322 +#endif +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__MWERKS__) +# if (_MSC_VER >= 1300) +# pragma warning(disable: 4668) +# endif +#endif +#if 0 && defined(__WATCOMC__) +# if (__WATCOMC__ >= 1050) && (__WATCOMC__ < 1060) +# pragma warning 203 9 +# endif +#endif +#if defined(__BORLANDC__) && defined(__MSDOS__) && !defined(__FLAT__) +# pragma option -h +#endif +#if 0 +#define LZO_0xffffL 0xfffful +#define LZO_0xffffffffL 0xfffffffful +#else +#define LZO_0xffffL 65535ul +#define LZO_0xffffffffL 4294967295ul +#endif +#if (LZO_0xffffL == LZO_0xffffffffL) +# error "your preprocessor is broken 1" +#endif +#if (16ul * 16384ul != 262144ul) +# error "your preprocessor is broken 2" +#endif +#if 0 +#if (32767 >= 4294967295ul) +# error "your preprocessor is broken 3" +#endif +#if (65535u >= 4294967295ul) +# error "your preprocessor is broken 4" +#endif +#endif +#if (UINT_MAX == LZO_0xffffL) +#if defined(__ZTC__) && defined(__I86__) && !defined(__OS2__) +# if !defined(MSDOS) +# define MSDOS 1 +# endif +# if !defined(_MSDOS) +# define _MSDOS 1 +# endif +#elif 0 && defined(__VERSION) && defined(MB_LEN_MAX) +# if (__VERSION == 520) && (MB_LEN_MAX == 1) +# if !defined(__AZTEC_C__) +# define __AZTEC_C__ __VERSION +# endif +# if !defined(__DOS__) +# define __DOS__ 1 +# endif +# endif +#endif +#endif +#if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL) +# define ptrdiff_t long +# define _PTRDIFF_T_DEFINED +#endif +#if (UINT_MAX == LZO_0xffffL) +# undef __LZO_RENAME_A +# undef __LZO_RENAME_B +# if defined(__AZTEC_C__) && defined(__DOS__) +# define __LZO_RENAME_A 1 +# elif defined(_MSC_VER) && defined(MSDOS) +# if (_MSC_VER < 600) +# define __LZO_RENAME_A 1 +# elif (_MSC_VER < 700) +# define __LZO_RENAME_B 1 +# endif +# elif defined(__TSC__) && defined(__OS2__) +# define __LZO_RENAME_A 1 +# elif defined(__MSDOS__) && defined(__TURBOC__) && (__TURBOC__ < 0x0410) +# define __LZO_RENAME_A 1 +# elif defined(__PACIFIC__) && defined(DOS) +# if !defined(__far) +# define __far far +# endif +# if !defined(__near) +# define __near near +# endif +# endif +# if defined(__LZO_RENAME_A) +# if !defined(__cdecl) +# define __cdecl cdecl +# endif +# if !defined(__far) +# define __far far +# endif +# if !defined(__huge) +# define __huge huge +# endif +# if !defined(__near) +# define __near near +# endif +# if !defined(__pascal) +# define __pascal pascal +# endif +# if !defined(__huge) +# define __huge huge +# endif +# elif defined(__LZO_RENAME_B) +# if !defined(__cdecl) +# define __cdecl _cdecl +# endif +# if !defined(__far) +# define __far _far +# endif +# if !defined(__huge) +# define __huge _huge +# endif +# if !defined(__near) +# define __near _near +# endif +# if !defined(__pascal) +# define __pascal _pascal +# endif +# elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) +# if !defined(__cdecl) +# define __cdecl cdecl +# endif +# if !defined(__pascal) +# define __pascal pascal +# endif +# endif +# undef __LZO_RENAME_A +# undef __LZO_RENAME_B +#endif +#if (UINT_MAX == LZO_0xffffL) +#if defined(__AZTEC_C__) && defined(__DOS__) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +#elif defined(_MSC_VER) && defined(MSDOS) +# if (_MSC_VER < 600) +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +# endif +# if (_MSC_VER < 700) +# define LZO_BROKEN_INTEGRAL_PROMOTION 1 +# define LZO_BROKEN_SIZEOF 1 +# endif +#elif defined(__PACIFIC__) && defined(DOS) +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +#elif defined(__TURBOC__) && defined(__MSDOS__) +# if (__TURBOC__ < 0x0150) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +# define LZO_BROKEN_INTEGRAL_PROMOTION 1 +# endif +# if (__TURBOC__ < 0x0200) +# define LZO_BROKEN_SIZEOF 1 +# endif +# if (__TURBOC__ < 0x0400) && defined(__cplusplus) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +# endif +#elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +# define LZO_BROKEN_SIZEOF 1 +#endif +#endif +#if defined(__WATCOMC__) && (__WATCOMC__ < 900) +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +#endif +#if defined(_CRAY) && defined(_CRAY1) +# define LZO_BROKEN_SIGNED_RIGHT_SHIFT 1 +#endif +#define LZO_PP_STRINGIZE(x) #x +#define LZO_PP_MACRO_EXPAND(x) LZO_PP_STRINGIZE(x) +#define LZO_PP_CONCAT2(a,b) a ## b +#define LZO_PP_CONCAT3(a,b,c) a ## b ## c +#define LZO_PP_CONCAT4(a,b,c,d) a ## b ## c ## d +#define LZO_PP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e +#define LZO_PP_ECONCAT2(a,b) LZO_PP_CONCAT2(a,b) +#define LZO_PP_ECONCAT3(a,b,c) LZO_PP_CONCAT3(a,b,c) +#define LZO_PP_ECONCAT4(a,b,c,d) LZO_PP_CONCAT4(a,b,c,d) +#define LZO_PP_ECONCAT5(a,b,c,d,e) LZO_PP_CONCAT5(a,b,c,d,e) +#if 1 +#define LZO_CPP_STRINGIZE(x) #x +#define LZO_CPP_MACRO_EXPAND(x) LZO_CPP_STRINGIZE(x) +#define LZO_CPP_CONCAT2(a,b) a ## b +#define LZO_CPP_CONCAT3(a,b,c) a ## b ## c +#define LZO_CPP_CONCAT4(a,b,c,d) a ## b ## c ## d +#define LZO_CPP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e +#define LZO_CPP_ECONCAT2(a,b) LZO_CPP_CONCAT2(a,b) +#define LZO_CPP_ECONCAT3(a,b,c) LZO_CPP_CONCAT3(a,b,c) +#define LZO_CPP_ECONCAT4(a,b,c,d) LZO_CPP_CONCAT4(a,b,c,d) +#define LZO_CPP_ECONCAT5(a,b,c,d,e) LZO_CPP_CONCAT5(a,b,c,d,e) +#endif +#define __LZO_MASK_GEN(o,b) (((((o) << ((b)-1)) - (o)) << 1) + (o)) +#if 1 && defined(__cplusplus) +# if !defined(__STDC_CONSTANT_MACROS) +# define __STDC_CONSTANT_MACROS 1 +# endif +# if !defined(__STDC_LIMIT_MACROS) +# define __STDC_LIMIT_MACROS 1 +# endif +#endif +#if defined(__cplusplus) +# define LZO_EXTERN_C extern "C" +#else +# define LZO_EXTERN_C extern +#endif +#if !defined(__LZO_OS_OVERRIDE) +#if defined(LZO_OS_FREESTANDING) +# define LZO_INFO_OS "freestanding" +#elif defined(LZO_OS_EMBEDDED) +# define LZO_INFO_OS "embedded" +#elif 1 && defined(__IAR_SYSTEMS_ICC__) +# define LZO_OS_EMBEDDED 1 +# define LZO_INFO_OS "embedded" +#elif defined(__CYGWIN__) && defined(__GNUC__) +# define LZO_OS_CYGWIN 1 +# define LZO_INFO_OS "cygwin" +#elif defined(__EMX__) && defined(__GNUC__) +# define LZO_OS_EMX 1 +# define LZO_INFO_OS "emx" +#elif defined(__BEOS__) +# define LZO_OS_BEOS 1 +# define LZO_INFO_OS "beos" +#elif defined(__Lynx__) +# define LZO_OS_LYNXOS 1 +# define LZO_INFO_OS "lynxos" +#elif defined(__OS400__) +# define LZO_OS_OS400 1 +# define LZO_INFO_OS "os400" +#elif defined(__QNX__) +# define LZO_OS_QNX 1 +# define LZO_INFO_OS "qnx" +#elif defined(__BORLANDC__) && defined(__DPMI32__) && (__BORLANDC__ >= 0x0460) +# define LZO_OS_DOS32 1 +# define LZO_INFO_OS "dos32" +#elif defined(__BORLANDC__) && defined(__DPMI16__) +# define LZO_OS_DOS16 1 +# define LZO_INFO_OS "dos16" +#elif defined(__ZTC__) && defined(DOS386) +# define LZO_OS_DOS32 1 +# define LZO_INFO_OS "dos32" +#elif defined(__OS2__) || defined(__OS2V2__) +# if (UINT_MAX == LZO_0xffffL) +# define LZO_OS_OS216 1 +# define LZO_INFO_OS "os216" +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_OS_OS2 1 +# define LZO_INFO_OS "os2" +# else +# error "check your limits.h header" +# endif +#elif defined(__WIN64__) || defined(_WIN64) || defined(WIN64) +# define LZO_OS_WIN64 1 +# define LZO_INFO_OS "win64" +#elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WINDOWS_386__) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +#elif defined(__MWERKS__) && defined(__INTEL__) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +#elif defined(__WINDOWS__) || defined(_WINDOWS) || defined(_Windows) +# if (UINT_MAX == LZO_0xffffL) +# define LZO_OS_WIN16 1 +# define LZO_INFO_OS "win16" +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +# else +# error "check your limits.h header" +# endif +#elif defined(__DOS__) || defined(__MSDOS__) || defined(_MSDOS) || defined(MSDOS) || (defined(__PACIFIC__) && defined(DOS)) +# if (UINT_MAX == LZO_0xffffL) +# define LZO_OS_DOS16 1 +# define LZO_INFO_OS "dos16" +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_OS_DOS32 1 +# define LZO_INFO_OS "dos32" +# else +# error "check your limits.h header" +# endif +#elif defined(__WATCOMC__) +# if defined(__NT__) && (UINT_MAX == LZO_0xffffL) +# define LZO_OS_DOS16 1 +# define LZO_INFO_OS "dos16" +# elif defined(__NT__) && (__WATCOMC__ < 1100) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +# elif defined(__linux__) || defined(__LINUX__) +# define LZO_OS_POSIX 1 +# define LZO_INFO_OS "posix" +# else +# error "please specify a target using the -bt compiler option" +# endif +#elif defined(__palmos__) +# define LZO_OS_PALMOS 1 +# define LZO_INFO_OS "palmos" +#elif defined(__TOS__) || defined(__atarist__) +# define LZO_OS_TOS 1 +# define LZO_INFO_OS "tos" +#elif defined(macintosh) && !defined(__ppc__) +# define LZO_OS_MACCLASSIC 1 +# define LZO_INFO_OS "macclassic" +#elif defined(__VMS) +# define LZO_OS_VMS 1 +# define LZO_INFO_OS "vms" +#elif ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) +# define LZO_OS_CONSOLE 1 +# define LZO_OS_CONSOLE_PS2 1 +# define LZO_INFO_OS "console" +# define LZO_INFO_OS_CONSOLE "ps2" +#elif (defined(__mips__) && defined(__psp__)) +# define LZO_OS_CONSOLE 1 +# define LZO_OS_CONSOLE_PSP 1 +# define LZO_INFO_OS "console" +# define LZO_INFO_OS_CONSOLE "psp" +#else +# define LZO_OS_POSIX 1 +# define LZO_INFO_OS "posix" +#endif +#if (LZO_OS_POSIX) +# if defined(_AIX) || defined(__AIX__) || defined(__aix__) +# define LZO_OS_POSIX_AIX 1 +# define LZO_INFO_OS_POSIX "aix" +# elif defined(__FreeBSD__) +# define LZO_OS_POSIX_FREEBSD 1 +# define LZO_INFO_OS_POSIX "freebsd" +# elif defined(__hpux__) || defined(__hpux) +# define LZO_OS_POSIX_HPUX 1 +# define LZO_INFO_OS_POSIX "hpux" +# elif defined(__INTERIX) +# define LZO_OS_POSIX_INTERIX 1 +# define LZO_INFO_OS_POSIX "interix" +# elif defined(__IRIX__) || defined(__irix__) +# define LZO_OS_POSIX_IRIX 1 +# define LZO_INFO_OS_POSIX "irix" +# elif defined(__linux__) || defined(__linux) || defined(__LINUX__) +# define LZO_OS_POSIX_LINUX 1 +# define LZO_INFO_OS_POSIX "linux" +# elif defined(__APPLE__) || defined(__MACOS__) +# define LZO_OS_POSIX_MACOSX 1 +# define LZO_INFO_OS_POSIX "macosx" +# elif defined(__minix__) || defined(__minix) +# define LZO_OS_POSIX_MINIX 1 +# define LZO_INFO_OS_POSIX "minix" +# elif defined(__NetBSD__) +# define LZO_OS_POSIX_NETBSD 1 +# define LZO_INFO_OS_POSIX "netbsd" +# elif defined(__OpenBSD__) +# define LZO_OS_POSIX_OPENBSD 1 +# define LZO_INFO_OS_POSIX "openbsd" +# elif defined(__osf__) +# define LZO_OS_POSIX_OSF 1 +# define LZO_INFO_OS_POSIX "osf" +# elif defined(__solaris__) || defined(__sun) +# if defined(__SVR4) || defined(__svr4__) +# define LZO_OS_POSIX_SOLARIS 1 +# define LZO_INFO_OS_POSIX "solaris" +# else +# define LZO_OS_POSIX_SUNOS 1 +# define LZO_INFO_OS_POSIX "sunos" +# endif +# elif defined(__ultrix__) || defined(__ultrix) +# define LZO_OS_POSIX_ULTRIX 1 +# define LZO_INFO_OS_POSIX "ultrix" +# elif defined(_UNICOS) +# define LZO_OS_POSIX_UNICOS 1 +# define LZO_INFO_OS_POSIX "unicos" +# else +# define LZO_OS_POSIX_UNKNOWN 1 +# define LZO_INFO_OS_POSIX "unknown" +# endif +#endif +#endif +#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +# if (UINT_MAX != LZO_0xffffL) +# error "this should not happen" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +#endif +#if (LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_WIN32 || LZO_OS_WIN64) +# if (UINT_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +#endif +#if defined(CIL) && defined(_GNUCC) && defined(__GNUC__) +# define LZO_CC_CILLY 1 +# define LZO_INFO_CC "Cilly" +# if defined(__CILLY__) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CILLY__) +# else +# define LZO_INFO_CCVER "unknown" +# endif +#elif 0 && defined(SDCC) && defined(__VERSION__) && !defined(__GNUC__) +# define LZO_CC_SDCC 1 +# define LZO_INFO_CC "sdcc" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(SDCC) +#elif defined(__PATHSCALE__) && defined(__PATHCC_PATCHLEVEL__) +# define LZO_CC_PATHSCALE (__PATHCC__ * 0x10000L + __PATHCC_MINOR__ * 0x100 + __PATHCC_PATCHLEVEL__) +# define LZO_INFO_CC "Pathscale C" +# define LZO_INFO_CCVER __PATHSCALE__ +#elif defined(__INTEL_COMPILER) +# define LZO_CC_INTELC 1 +# define LZO_INFO_CC "Intel C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__INTEL_COMPILER) +# if defined(_WIN32) || defined(_WIN64) +# define LZO_CC_SYNTAX_MSC 1 +# else +# define LZO_CC_SYNTAX_GNUC 1 +# endif +#elif defined(__POCC__) && defined(_WIN32) +# define LZO_CC_PELLESC 1 +# define LZO_INFO_CC "Pelles C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__POCC__) +#elif defined(__llvm__) && defined(__GNUC__) && defined(__VERSION__) +# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) +# else +# define LZO_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) +# endif +# define LZO_INFO_CC "llvm-gcc" +# define LZO_INFO_CCVER __VERSION__ +#elif defined(__GNUC__) && defined(__VERSION__) +# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) +# elif defined(__GNUC_MINOR__) +# define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) +# else +# define LZO_CC_GNUC (__GNUC__ * 0x10000L) +# endif +# define LZO_INFO_CC "gcc" +# define LZO_INFO_CCVER __VERSION__ +#elif defined(__ACK__) && defined(_ACK) +# define LZO_CC_ACK 1 +# define LZO_INFO_CC "Amsterdam Compiler Kit C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__AZTEC_C__) +# define LZO_CC_AZTECC 1 +# define LZO_INFO_CC "Aztec C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__AZTEC_C__) +#elif defined(__BORLANDC__) +# define LZO_CC_BORLANDC 1 +# define LZO_INFO_CC "Borland C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__BORLANDC__) +#elif defined(_CRAYC) && defined(_RELEASE) +# define LZO_CC_CRAYC 1 +# define LZO_INFO_CC "Cray C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_RELEASE) +#elif defined(__DMC__) && defined(__SC__) +# define LZO_CC_DMC 1 +# define LZO_INFO_CC "Digital Mars C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DMC__) +#elif defined(__DECC) +# define LZO_CC_DECC 1 +# define LZO_INFO_CC "DEC C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DECC) +#elif defined(__HIGHC__) +# define LZO_CC_HIGHC 1 +# define LZO_INFO_CC "MetaWare High C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__IAR_SYSTEMS_ICC__) +# define LZO_CC_IARC 1 +# define LZO_INFO_CC "IAR C" +# if defined(__VER__) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__VER__) +# else +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__IBMC__) +# define LZO_CC_IBMC 1 +# define LZO_INFO_CC "IBM C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__IBMC__) +#elif defined(__KEIL__) && defined(__C166__) +# define LZO_CC_KEILC 1 +# define LZO_INFO_CC "Keil C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__C166__) +#elif defined(__LCC__) && defined(_WIN32) && defined(__LCCOPTIMLEVEL) +# define LZO_CC_LCCWIN32 1 +# define LZO_INFO_CC "lcc-win32" +# define LZO_INFO_CCVER "unknown" +#elif defined(__LCC__) +# define LZO_CC_LCC 1 +# define LZO_INFO_CC "lcc" +# if defined(__LCC_VERSION__) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__LCC_VERSION__) +# else +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(_MSC_VER) +# define LZO_CC_MSC 1 +# define LZO_INFO_CC "Microsoft C" +# if defined(_MSC_FULL_VER) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) "." LZO_PP_MACRO_EXPAND(_MSC_FULL_VER) +# else +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) +# endif +#elif defined(__MWERKS__) +# define LZO_CC_MWERKS 1 +# define LZO_INFO_CC "Metrowerks C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__MWERKS__) +#elif (defined(__NDPC__) || defined(__NDPX__)) && defined(__i386) +# define LZO_CC_NDPC 1 +# define LZO_INFO_CC "Microway NDP C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__PACIFIC__) +# define LZO_CC_PACIFICC 1 +# define LZO_INFO_CC "Pacific C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PACIFIC__) +#elif defined(__PGI) && (defined(__linux__) || defined(__WIN32__)) +# define LZO_CC_PGI 1 +# define LZO_INFO_CC "Portland Group PGI C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__PUREC__) && defined(__TOS__) +# define LZO_CC_PUREC 1 +# define LZO_INFO_CC "Pure C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PUREC__) +#elif defined(__SC__) && defined(__ZTC__) +# define LZO_CC_SYMANTECC 1 +# define LZO_INFO_CC "Symantec C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SC__) +#elif defined(__SUNPRO_C) +# define LZO_INFO_CC "SunPro C" +# if ((__SUNPRO_C)+0 > 0) +# define LZO_CC_SUNPROC __SUNPRO_C +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_C) +# else +# define LZO_CC_SUNPROC 1 +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__SUNPRO_CC) +# define LZO_INFO_CC "SunPro C" +# if ((__SUNPRO_CC)+0 > 0) +# define LZO_CC_SUNPROC __SUNPRO_CC +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_CC) +# else +# define LZO_CC_SUNPROC 1 +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__TINYC__) +# define LZO_CC_TINYC 1 +# define LZO_INFO_CC "Tiny C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TINYC__) +#elif defined(__TSC__) +# define LZO_CC_TOPSPEEDC 1 +# define LZO_INFO_CC "TopSpeed C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TSC__) +#elif defined(__WATCOMC__) +# define LZO_CC_WATCOMC 1 +# define LZO_INFO_CC "Watcom C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__WATCOMC__) +#elif defined(__TURBOC__) +# define LZO_CC_TURBOC 1 +# define LZO_INFO_CC "Turbo C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TURBOC__) +#elif defined(__ZTC__) +# define LZO_CC_ZORTECHC 1 +# define LZO_INFO_CC "Zortech C" +# if (__ZTC__ == 0x310) +# define LZO_INFO_CCVER "0x310" +# else +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__ZTC__) +# endif +#else +# define LZO_CC_UNKNOWN 1 +# define LZO_INFO_CC "unknown" +# define LZO_INFO_CCVER "unknown" +#endif +#if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER) +# error "LZO_CC_MSC: _MSC_FULL_VER is not defined" +#endif +#if !defined(__LZO_ARCH_OVERRIDE) && !defined(LZO_ARCH_GENERIC) && defined(_CRAY) +# if (UINT_MAX > LZO_0xffffffffL) && defined(_CRAY) +# if defined(_CRAYMPP) || defined(_CRAYT3D) || defined(_CRAYT3E) +# define LZO_ARCH_CRAY_MPP 1 +# elif defined(_CRAY1) +# define LZO_ARCH_CRAY_PVP 1 +# endif +# endif +#endif +#if !defined(__LZO_ARCH_OVERRIDE) +#if defined(LZO_ARCH_GENERIC) +# define LZO_INFO_ARCH "generic" +#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +# define LZO_ARCH_I086 1 +# define LZO_ARCH_IA16 1 +# define LZO_INFO_ARCH "i086" +#elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA) +# define LZO_ARCH_ALPHA 1 +# define LZO_INFO_ARCH "alpha" +#elif (LZO_ARCH_CRAY_MPP) && (defined(_CRAYT3D) || defined(_CRAYT3E)) +# define LZO_ARCH_ALPHA 1 +# define LZO_INFO_ARCH "alpha" +#elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64) +# define LZO_ARCH_AMD64 1 +# define LZO_INFO_ARCH "amd64" +#elif defined(__thumb__) || (defined(_M_ARM) && defined(_M_THUMB)) +# define LZO_ARCH_ARM 1 +# define LZO_ARCH_ARM_THUMB 1 +# define LZO_INFO_ARCH "arm_thumb" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__) +# define LZO_ARCH_ARM 1 +# if defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 1) +# define LZO_ARCH_ARM_THUMB 1 +# define LZO_INFO_ARCH "arm_thumb" +# elif defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 2) +# define LZO_INFO_ARCH "arm" +# else +# define LZO_INFO_ARCH "arm" +# endif +#elif defined(__arm__) || defined(_M_ARM) +# define LZO_ARCH_ARM 1 +# define LZO_INFO_ARCH "arm" +#elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__) +# define LZO_ARCH_AVR 1 +# define LZO_INFO_ARCH "avr" +#elif defined(__bfin__) +# define LZO_ARCH_BLACKFIN 1 +# define LZO_INFO_ARCH "blackfin" +#elif (UINT_MAX == LZO_0xffffL) && defined(__C166__) +# define LZO_ARCH_C166 1 +# define LZO_INFO_ARCH "c166" +#elif defined(__cris__) +# define LZO_ARCH_CRIS 1 +# define LZO_INFO_ARCH "cris" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCEZ80__) +# define LZO_ARCH_EZ80 1 +# define LZO_INFO_ARCH "ez80" +#elif defined(__H8300__) || defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) +# define LZO_ARCH_H8300 1 +# define LZO_INFO_ARCH "h8300" +#elif defined(__hppa__) || defined(__hppa) +# define LZO_ARCH_HPPA 1 +# define LZO_INFO_ARCH "hppa" +#elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386) +# define LZO_ARCH_I386 1 +# define LZO_ARCH_IA32 1 +# define LZO_INFO_ARCH "i386" +#elif (LZO_CC_ZORTECHC && defined(__I86__)) +# define LZO_ARCH_I386 1 +# define LZO_ARCH_IA32 1 +# define LZO_INFO_ARCH "i386" +#elif (LZO_OS_DOS32 && LZO_CC_HIGHC) && defined(_I386) +# define LZO_ARCH_I386 1 +# define LZO_ARCH_IA32 1 +# define LZO_INFO_ARCH "i386" +#elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64) +# define LZO_ARCH_IA64 1 +# define LZO_INFO_ARCH "ia64" +#elif (UINT_MAX == LZO_0xffffL) && defined(__m32c__) +# define LZO_ARCH_M16C 1 +# define LZO_INFO_ARCH "m16c" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCM16C__) +# define LZO_ARCH_M16C 1 +# define LZO_INFO_ARCH "m16c" +#elif defined(__m32r__) +# define LZO_ARCH_M32R 1 +# define LZO_INFO_ARCH "m32r" +#elif (LZO_OS_TOS) || defined(__m68k__) || defined(__m68000__) || defined(__mc68000__) || defined(__mc68020__) || defined(_M_M68K) +# define LZO_ARCH_M68K 1 +# define LZO_INFO_ARCH "m68k" +#elif (UINT_MAX == LZO_0xffffL) && defined(__C251__) +# define LZO_ARCH_MCS251 1 +# define LZO_INFO_ARCH "mcs251" +#elif (UINT_MAX == LZO_0xffffL) && defined(__C51__) +# define LZO_ARCH_MCS51 1 +# define LZO_INFO_ARCH "mcs51" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC8051__) +# define LZO_ARCH_MCS51 1 +# define LZO_INFO_ARCH "mcs51" +#elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000) +# define LZO_ARCH_MIPS 1 +# define LZO_INFO_ARCH "mips" +#elif (UINT_MAX == LZO_0xffffL) && defined(__MSP430__) +# define LZO_ARCH_MSP430 1 +# define LZO_INFO_ARCH "msp430" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC430__) +# define LZO_ARCH_MSP430 1 +# define LZO_INFO_ARCH "msp430" +#elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR) +# define LZO_ARCH_POWERPC 1 +# define LZO_INFO_ARCH "powerpc" +#elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x) +# define LZO_ARCH_S390 1 +# define LZO_INFO_ARCH "s390" +#elif defined(__sh__) || defined(_M_SH) +# define LZO_ARCH_SH 1 +# define LZO_INFO_ARCH "sh" +#elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8) +# define LZO_ARCH_SPARC 1 +# define LZO_INFO_ARCH "sparc" +#elif defined(__SPU__) +# define LZO_ARCH_SPU 1 +# define LZO_INFO_ARCH "spu" +#elif (UINT_MAX == LZO_0xffffL) && defined(__z80) +# define LZO_ARCH_Z80 1 +# define LZO_INFO_ARCH "z80" +#elif (LZO_ARCH_CRAY_PVP) +# if defined(_CRAYSV1) +# define LZO_ARCH_CRAY_SV1 1 +# define LZO_INFO_ARCH "cray_sv1" +# elif (_ADDR64) +# define LZO_ARCH_CRAY_T90 1 +# define LZO_INFO_ARCH "cray_t90" +# elif (_ADDR32) +# define LZO_ARCH_CRAY_YMP 1 +# define LZO_INFO_ARCH "cray_ymp" +# else +# define LZO_ARCH_CRAY_XMP 1 +# define LZO_INFO_ARCH "cray_xmp" +# endif +#else +# define LZO_ARCH_UNKNOWN 1 +# define LZO_INFO_ARCH "unknown" +#endif +#endif +#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_DOS32 || LZO_OS_OS2) +# error "FIXME - missing define for CPU architecture" +#endif +#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN32) +# error "FIXME - missing WIN32 define for CPU architecture" +#endif +#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN64) +# error "FIXME - missing WIN64 define for CPU architecture" +#endif +#if (LZO_OS_OS216 || LZO_OS_WIN16) +# define LZO_ARCH_I086PM 1 +# define LZO_ARCH_IA16PM 1 +#elif 1 && (LZO_OS_DOS16 && defined(BLX286)) +# define LZO_ARCH_I086PM 1 +# define LZO_ARCH_IA16PM 1 +#elif 1 && (LZO_OS_DOS16 && defined(DOSX286)) +# define LZO_ARCH_I086PM 1 +# define LZO_ARCH_IA16PM 1 +#elif 1 && (LZO_OS_DOS16 && LZO_CC_BORLANDC && defined(__DPMI16__)) +# define LZO_ARCH_I086PM 1 +# define LZO_ARCH_IA16PM 1 +#endif +#if defined(LZO_ARCH_ARM_THUMB) && !defined(LZO_ARCH_ARM) +# error "this should not happen" +#endif +#if defined(LZO_ARCH_I086PM) && !defined(LZO_ARCH_I086) +# error "this should not happen" +#endif +#if (LZO_ARCH_I086) +# if (UINT_MAX != LZO_0xffffL) +# error "this should not happen" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +#endif +#if (LZO_ARCH_I386) +# if (UINT_MAX != LZO_0xffffL) && defined(__i386_int16__) +# error "this should not happen" +# endif +# if (UINT_MAX != LZO_0xffffffffL) && !defined(__i386_int16__) +# error "this should not happen" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +#endif +#if !defined(__LZO_MM_OVERRIDE) +#if (LZO_ARCH_I086) +#if (UINT_MAX != LZO_0xffffL) +# error "this should not happen" +#endif +#if defined(__TINY__) || defined(M_I86TM) || defined(_M_I86TM) +# define LZO_MM_TINY 1 +#elif defined(__HUGE__) || defined(_HUGE_) || defined(M_I86HM) || defined(_M_I86HM) +# define LZO_MM_HUGE 1 +#elif defined(__SMALL__) || defined(M_I86SM) || defined(_M_I86SM) || defined(SMALL_MODEL) +# define LZO_MM_SMALL 1 +#elif defined(__MEDIUM__) || defined(M_I86MM) || defined(_M_I86MM) +# define LZO_MM_MEDIUM 1 +#elif defined(__COMPACT__) || defined(M_I86CM) || defined(_M_I86CM) +# define LZO_MM_COMPACT 1 +#elif defined(__LARGE__) || defined(M_I86LM) || defined(_M_I86LM) || defined(LARGE_MODEL) +# define LZO_MM_LARGE 1 +#elif (LZO_CC_AZTECC) +# if defined(_LARGE_CODE) && defined(_LARGE_DATA) +# define LZO_MM_LARGE 1 +# elif defined(_LARGE_CODE) +# define LZO_MM_MEDIUM 1 +# elif defined(_LARGE_DATA) +# define LZO_MM_COMPACT 1 +# else +# define LZO_MM_SMALL 1 +# endif +#elif (LZO_CC_ZORTECHC && defined(__VCM__)) +# define LZO_MM_LARGE 1 +#else +# error "unknown memory model" +#endif +#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +#define LZO_HAVE_MM_HUGE_PTR 1 +#define LZO_HAVE_MM_HUGE_ARRAY 1 +#if (LZO_MM_TINY) +# undef LZO_HAVE_MM_HUGE_ARRAY +#endif +#if (LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_ZORTECHC) +# undef LZO_HAVE_MM_HUGE_PTR +# undef LZO_HAVE_MM_HUGE_ARRAY +#elif (LZO_CC_DMC || LZO_CC_SYMANTECC) +# undef LZO_HAVE_MM_HUGE_ARRAY +#elif (LZO_CC_MSC && defined(_QC)) +# undef LZO_HAVE_MM_HUGE_ARRAY +# if (_MSC_VER < 600) +# undef LZO_HAVE_MM_HUGE_PTR +# endif +#elif (LZO_CC_TURBOC && (__TURBOC__ < 0x0295)) +# undef LZO_HAVE_MM_HUGE_ARRAY +#endif +#if (LZO_ARCH_I086PM) && !defined(LZO_HAVE_MM_HUGE_PTR) +# if (LZO_OS_DOS16) +# error "this should not happen" +# elif (LZO_CC_ZORTECHC) +# else +# error "this should not happen" +# endif +#endif +#ifdef __cplusplus +extern "C" { +#endif +#if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0200)) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif (LZO_CC_MSC || LZO_CC_TOPSPEEDC) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif (LZO_CC_TURBOC && (__TURBOC__ >= 0x0295)) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif ((LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_TURBOC) && LZO_OS_DOS16) +# define LZO_MM_AHSHIFT 12 +#elif (LZO_CC_WATCOMC) + extern unsigned char _HShift; +# define LZO_MM_AHSHIFT ((unsigned) _HShift) +#else +# error "FIXME - implement LZO_MM_AHSHIFT" +#endif +#ifdef __cplusplus +} +#endif +#endif +#elif (LZO_ARCH_C166) +#if !defined(__MODEL__) +# error "FIXME - C166 __MODEL__" +#elif ((__MODEL__) == 0) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 1) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 2) +# define LZO_MM_LARGE 1 +#elif ((__MODEL__) == 3) +# define LZO_MM_TINY 1 +#elif ((__MODEL__) == 4) +# define LZO_MM_XTINY 1 +#elif ((__MODEL__) == 5) +# define LZO_MM_XSMALL 1 +#else +# error "FIXME - C166 __MODEL__" +#endif +#elif (LZO_ARCH_MCS251) +#if !defined(__MODEL__) +# error "FIXME - MCS251 __MODEL__" +#elif ((__MODEL__) == 0) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 2) +# define LZO_MM_LARGE 1 +#elif ((__MODEL__) == 3) +# define LZO_MM_TINY 1 +#elif ((__MODEL__) == 4) +# define LZO_MM_XTINY 1 +#elif ((__MODEL__) == 5) +# define LZO_MM_XSMALL 1 +#else +# error "FIXME - MCS251 __MODEL__" +#endif +#elif (LZO_ARCH_MCS51) +#if !defined(__MODEL__) +# error "FIXME - MCS51 __MODEL__" +#elif ((__MODEL__) == 1) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 2) +# define LZO_MM_LARGE 1 +#elif ((__MODEL__) == 3) +# define LZO_MM_TINY 1 +#elif ((__MODEL__) == 4) +# define LZO_MM_XTINY 1 +#elif ((__MODEL__) == 5) +# define LZO_MM_XSMALL 1 +#else +# error "FIXME - MCS51 __MODEL__" +#endif +#elif (LZO_ARCH_CRAY_PVP) +# define LZO_MM_PVP 1 +#else +# define LZO_MM_FLAT 1 +#endif +#if (LZO_MM_COMPACT) +# define LZO_INFO_MM "compact" +#elif (LZO_MM_FLAT) +# define LZO_INFO_MM "flat" +#elif (LZO_MM_HUGE) +# define LZO_INFO_MM "huge" +#elif (LZO_MM_LARGE) +# define LZO_INFO_MM "large" +#elif (LZO_MM_MEDIUM) +# define LZO_INFO_MM "medium" +#elif (LZO_MM_PVP) +# define LZO_INFO_MM "pvp" +#elif (LZO_MM_SMALL) +# define LZO_INFO_MM "small" +#elif (LZO_MM_TINY) +# define LZO_INFO_MM "tiny" +#else +# error "unknown memory model" +#endif +#endif +#if defined(SIZEOF_SHORT) +# define LZO_SIZEOF_SHORT (SIZEOF_SHORT) +#endif +#if defined(SIZEOF_INT) +# define LZO_SIZEOF_INT (SIZEOF_INT) +#endif +#if defined(SIZEOF_LONG) +# define LZO_SIZEOF_LONG (SIZEOF_LONG) +#endif +#if defined(SIZEOF_LONG_LONG) +# define LZO_SIZEOF_LONG_LONG (SIZEOF_LONG_LONG) +#endif +#if defined(SIZEOF___INT16) +# define LZO_SIZEOF___INT16 (SIZEOF___INT16) +#endif +#if defined(SIZEOF___INT32) +# define LZO_SIZEOF___INT32 (SIZEOF___INT32) +#endif +#if defined(SIZEOF___INT64) +# define LZO_SIZEOF___INT64 (SIZEOF___INT64) +#endif +#if defined(SIZEOF_VOID_P) +# define LZO_SIZEOF_VOID_P (SIZEOF_VOID_P) +#endif +#if defined(SIZEOF_SIZE_T) +# define LZO_SIZEOF_SIZE_T (SIZEOF_SIZE_T) +#endif +#if defined(SIZEOF_PTRDIFF_T) +# define LZO_SIZEOF_PTRDIFF_T (SIZEOF_PTRDIFF_T) +#endif +#define __LZO_LSR(x,b) (((x)+0ul) >> (b)) +#if !defined(LZO_SIZEOF_SHORT) +# if (LZO_ARCH_CRAY_PVP) +# define LZO_SIZEOF_SHORT 8 +# elif (USHRT_MAX == LZO_0xffffL) +# define LZO_SIZEOF_SHORT 2 +# elif (__LZO_LSR(USHRT_MAX,7) == 1) +# define LZO_SIZEOF_SHORT 1 +# elif (__LZO_LSR(USHRT_MAX,15) == 1) +# define LZO_SIZEOF_SHORT 2 +# elif (__LZO_LSR(USHRT_MAX,31) == 1) +# define LZO_SIZEOF_SHORT 4 +# elif (__LZO_LSR(USHRT_MAX,63) == 1) +# define LZO_SIZEOF_SHORT 8 +# elif (__LZO_LSR(USHRT_MAX,127) == 1) +# define LZO_SIZEOF_SHORT 16 +# else +# error "LZO_SIZEOF_SHORT" +# endif +#endif +#if !defined(LZO_SIZEOF_INT) +# if (LZO_ARCH_CRAY_PVP) +# define LZO_SIZEOF_INT 8 +# elif (UINT_MAX == LZO_0xffffL) +# define LZO_SIZEOF_INT 2 +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_SIZEOF_INT 4 +# elif (__LZO_LSR(UINT_MAX,7) == 1) +# define LZO_SIZEOF_INT 1 +# elif (__LZO_LSR(UINT_MAX,15) == 1) +# define LZO_SIZEOF_INT 2 +# elif (__LZO_LSR(UINT_MAX,31) == 1) +# define LZO_SIZEOF_INT 4 +# elif (__LZO_LSR(UINT_MAX,63) == 1) +# define LZO_SIZEOF_INT 8 +# elif (__LZO_LSR(UINT_MAX,127) == 1) +# define LZO_SIZEOF_INT 16 +# else +# error "LZO_SIZEOF_INT" +# endif +#endif +#if !defined(LZO_SIZEOF_LONG) +# if (ULONG_MAX == LZO_0xffffffffL) +# define LZO_SIZEOF_LONG 4 +# elif (__LZO_LSR(ULONG_MAX,7) == 1) +# define LZO_SIZEOF_LONG 1 +# elif (__LZO_LSR(ULONG_MAX,15) == 1) +# define LZO_SIZEOF_LONG 2 +# elif (__LZO_LSR(ULONG_MAX,31) == 1) +# define LZO_SIZEOF_LONG 4 +# elif (__LZO_LSR(ULONG_MAX,63) == 1) +# define LZO_SIZEOF_LONG 8 +# elif (__LZO_LSR(ULONG_MAX,127) == 1) +# define LZO_SIZEOF_LONG 16 +# else +# error "LZO_SIZEOF_LONG" +# endif +#endif +#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) +#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) +# if defined(__LONG_MAX__) && defined(__LONG_LONG_MAX__) +# if (LZO_CC_GNUC >= 0x030300ul) +# if ((__LONG_MAX__)+0 == (__LONG_LONG_MAX__)+0) +# define LZO_SIZEOF_LONG_LONG LZO_SIZEOF_LONG +# elif (__LZO_LSR(__LONG_LONG_MAX__,30) == 1) +# define LZO_SIZEOF_LONG_LONG 4 +# endif +# endif +# endif +#endif +#endif +#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) +#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) +#if (LZO_ARCH_I086 && LZO_CC_DMC) +#elif (LZO_CC_CILLY) && defined(__GNUC__) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_SIZEOF_LONG_LONG 8 +#elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_OS_WIN64 || defined(_WIN64)) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_ARCH_I386 && (LZO_CC_DMC)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_SYMANTECC && (__SC__ >= 0x700))) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_INTELC && defined(__linux__))) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_MWERKS || LZO_CC_PELLESC || LZO_CC_PGI || LZO_CC_SUNPROC)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_INTELC || LZO_CC_MSC)) +# define LZO_SIZEOF___INT64 8 +#elif ((LZO_OS_WIN32 || defined(_WIN32)) && (LZO_CC_MSC)) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_ARCH_I386 && (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0520))) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_ARCH_I386 && (LZO_CC_WATCOMC && (__WATCOMC__ >= 1100))) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_CC_WATCOMC && defined(_INTEGRAL_MAX_BITS) && (_INTEGRAL_MAX_BITS == 64)) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_CC_SDCC) && (LZO_SIZEOF_INT == 2) +#elif 1 && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define LZO_SIZEOF_LONG_LONG 8 +#endif +#endif +#endif +#if defined(__cplusplus) && defined(LZO_CC_GNUC) +# if (LZO_CC_GNUC < 0x020800ul) +# undef LZO_SIZEOF_LONG_LONG +# endif +#endif +#if defined(LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG) +# undef LZO_SIZEOF_LONG_LONG +#endif +#if !defined(LZO_SIZEOF_VOID_P) +#if (LZO_ARCH_I086) +# define __LZO_WORDSIZE 2 +# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM) +# define LZO_SIZEOF_VOID_P 2 +# elif (LZO_MM_COMPACT || LZO_MM_LARGE || LZO_MM_HUGE) +# define LZO_SIZEOF_VOID_P 4 +# else +# error "LZO_MM" +# endif +#elif (LZO_ARCH_AVR || LZO_ARCH_Z80) +# define __LZO_WORDSIZE 1 +# define LZO_SIZEOF_VOID_P 2 +#elif (LZO_ARCH_C166 || LZO_ARCH_MCS51 || LZO_ARCH_MCS251 || LZO_ARCH_MSP430) +# define LZO_SIZEOF_VOID_P 2 +#elif (LZO_ARCH_H8300) +# if defined(__NORMAL_MODE__) +# define __LZO_WORDSIZE 4 +# define LZO_SIZEOF_VOID_P 2 +# elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) +# define __LZO_WORDSIZE 4 +# define LZO_SIZEOF_VOID_P 4 +# else +# define __LZO_WORDSIZE 2 +# define LZO_SIZEOF_VOID_P 2 +# endif +# if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_SIZEOF_INT == 4) +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_INT +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_INT +# endif +#elif (LZO_ARCH_M16C) +# define __LZO_WORDSIZE 2 +# if defined(__m32c_cpu__) || defined(__m32cm_cpu__) +# define LZO_SIZEOF_VOID_P 4 +# else +# define LZO_SIZEOF_VOID_P 2 +# endif +#elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) +# define __LZO_WORDSIZE 8 +# define LZO_SIZEOF_VOID_P 4 +#elif defined(__LLP64__) || defined(__LLP64) || defined(_LLP64) || defined(_WIN64) +# define __LZO_WORDSIZE 8 +# define LZO_SIZEOF_VOID_P 8 +#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__) +# define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG +#elif (LZO_OS_OS400 || defined(__OS400__)) +# define __LZO_WORDSIZE LZO_SIZEOF_LONG +# define LZO_SIZEOF_VOID_P 16 +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG +#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) +# define LZO_SIZEOF_VOID_P 8 +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG +#elif (LZO_ARCH_SPU) +# if 0 +# define __LZO_WORDSIZE 16 +# endif +# define LZO_SIZEOF_VOID_P 4 +#else +# define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG +#endif +#endif +#if !defined(LZO_WORDSIZE) +# if defined(__LZO_WORDSIZE) +# define LZO_WORDSIZE __LZO_WORDSIZE +# else +# define LZO_WORDSIZE LZO_SIZEOF_VOID_P +# endif +#endif +#if !defined(LZO_SIZEOF_SIZE_T) +#if (LZO_ARCH_I086 || LZO_ARCH_M16C) +# define LZO_SIZEOF_SIZE_T 2 +#else +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_VOID_P +#endif +#endif +#if !defined(LZO_SIZEOF_PTRDIFF_T) +#if (LZO_ARCH_I086) +# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM || LZO_MM_HUGE) +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_VOID_P +# elif (LZO_MM_COMPACT || LZO_MM_LARGE) +# if (LZO_CC_BORLANDC || LZO_CC_TURBOC) +# define LZO_SIZEOF_PTRDIFF_T 4 +# else +# define LZO_SIZEOF_PTRDIFF_T 2 +# endif +# else +# error "LZO_MM" +# endif +#else +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_SIZE_T +#endif +#endif +#if defined(LZO_ABI_NEUTRAL_ENDIAN) +# undef LZO_ABI_BIG_ENDIAN +# undef LZO_ABI_LITTLE_ENDIAN +#elif !defined(LZO_ABI_BIG_ENDIAN) && !defined(LZO_ABI_LITTLE_ENDIAN) +#if (LZO_ARCH_ALPHA) && (LZO_ARCH_CRAY_MPP) +# define LZO_ABI_BIG_ENDIAN 1 +#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif (LZO_ARCH_M68K || LZO_ARCH_S390) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__) +# if (__LITTLE_ENDIAN__ == 1) +# define LZO_ABI_LITTLE_ENDIAN 1 +# else +# define LZO_ABI_BIG_ENDIAN 1 +# endif +#elif 1 && defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEB__) && !defined(__ARMEL__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEL__) && !defined(__ARMEB__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#endif +#endif +#if defined(LZO_ABI_BIG_ENDIAN) && defined(LZO_ABI_LITTLE_ENDIAN) +# error "this should not happen" +#endif +#if defined(LZO_ABI_BIG_ENDIAN) +# define LZO_INFO_ABI_ENDIAN "be" +#elif defined(LZO_ABI_LITTLE_ENDIAN) +# define LZO_INFO_ABI_ENDIAN "le" +#elif defined(LZO_ABI_NEUTRAL_ENDIAN) +# define LZO_INFO_ABI_ENDIAN "neutral" +#endif +#if (LZO_SIZEOF_INT == 1 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) +# define LZO_ABI_I8LP16 1 +# define LZO_INFO_ABI_PM "i8lp16" +#elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) +# define LZO_ABI_ILP16 1 +# define LZO_INFO_ABI_PM "ilp16" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4) +# define LZO_ABI_ILP32 1 +# define LZO_INFO_ABI_PM "ilp32" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 8 && LZO_SIZEOF_SIZE_T == 8) +# define LZO_ABI_LLP64 1 +# define LZO_INFO_ABI_PM "llp64" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) +# define LZO_ABI_LP64 1 +# define LZO_INFO_ABI_PM "lp64" +#elif (LZO_SIZEOF_INT == 8 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) +# define LZO_ABI_ILP64 1 +# define LZO_INFO_ABI_PM "ilp64" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 4) +# define LZO_ABI_IP32L64 1 +# define LZO_INFO_ABI_PM "ip32l64" +#endif +#if !defined(__LZO_LIBC_OVERRIDE) +#if defined(LZO_LIBC_NAKED) +# define LZO_INFO_LIBC "naked" +#elif defined(LZO_LIBC_FREESTANDING) +# define LZO_INFO_LIBC "freestanding" +#elif defined(LZO_LIBC_MOSTLY_FREESTANDING) +# define LZO_INFO_LIBC "mfreestanding" +#elif defined(LZO_LIBC_ISOC90) +# define LZO_INFO_LIBC "isoc90" +#elif defined(LZO_LIBC_ISOC99) +# define LZO_INFO_LIBC "isoc99" +#elif defined(__dietlibc__) +# define LZO_LIBC_DIETLIBC 1 +# define LZO_INFO_LIBC "dietlibc" +#elif defined(_NEWLIB_VERSION) +# define LZO_LIBC_NEWLIB 1 +# define LZO_INFO_LIBC "newlib" +#elif defined(__UCLIBC__) && defined(__UCLIBC_MAJOR__) && defined(__UCLIBC_MINOR__) +# if defined(__UCLIBC_SUBLEVEL__) +# define LZO_LIBC_UCLIBC (__UCLIBC_MAJOR__ * 0x10000L + __UCLIBC_MINOR__ * 0x100 + __UCLIBC_SUBLEVEL__) +# else +# define LZO_LIBC_UCLIBC 0x00090bL +# endif +# define LZO_INFO_LIBC "uclibc" +#elif defined(__GLIBC__) && defined(__GLIBC_MINOR__) +# define LZO_LIBC_GLIBC (__GLIBC__ * 0x10000L + __GLIBC_MINOR__ * 0x100) +# define LZO_INFO_LIBC "glibc" +#elif (LZO_CC_MWERKS) && defined(__MSL__) +# define LZO_LIBC_MSL __MSL__ +# define LZO_INFO_LIBC "msl" +#elif 1 && defined(__IAR_SYSTEMS_ICC__) +# define LZO_LIBC_ISOC90 1 +# define LZO_INFO_LIBC "isoc90" +#else +# define LZO_LIBC_DEFAULT 1 +# define LZO_INFO_LIBC "default" +#endif +#endif +#if !defined(__lzo_gnuc_extension__) +#if (LZO_CC_GNUC >= 0x020800ul) +# define __lzo_gnuc_extension__ __extension__ +#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_gnuc_extension__ __extension__ +#else +# define __lzo_gnuc_extension__ +#endif +#endif +#if !defined(__lzo_ua_volatile) +# define __lzo_ua_volatile volatile +#endif +#if !defined(__lzo_alignof) +#if (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +# define __lzo_alignof(e) __alignof__(e) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700)) +# define __lzo_alignof(e) __alignof__(e) +#elif (LZO_CC_MSC && (_MSC_VER >= 1300)) +# define __lzo_alignof(e) __alignof(e) +#endif +#endif +#if defined(__lzo_alignof) +# define __lzo_HAVE_alignof 1 +#endif +#if !defined(__lzo_constructor) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_constructor __attribute__((__constructor__,__used__)) +#elif (LZO_CC_GNUC >= 0x020700ul) +# define __lzo_constructor __attribute__((__constructor__)) +#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_constructor __attribute__((__constructor__)) +#endif +#endif +#if defined(__lzo_constructor) +# define __lzo_HAVE_constructor 1 +#endif +#if !defined(__lzo_destructor) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_destructor __attribute__((__destructor__,__used__)) +#elif (LZO_CC_GNUC >= 0x020700ul) +# define __lzo_destructor __attribute__((__destructor__)) +#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_destructor __attribute__((__destructor__)) +#endif +#endif +#if defined(__lzo_destructor) +# define __lzo_HAVE_destructor 1 +#endif +#if defined(__lzo_HAVE_destructor) && !defined(__lzo_HAVE_constructor) +# error "this should not happen" +#endif +#if !defined(__lzo_inline) +#if (LZO_CC_TURBOC && (__TURBOC__ <= 0x0295)) +#elif defined(__cplusplus) +# define __lzo_inline inline +#elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550)) +# define __lzo_inline __inline +#elif (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +# define __lzo_inline __inline__ +#elif (LZO_CC_DMC) +# define __lzo_inline __inline +#elif (LZO_CC_INTELC) +# define __lzo_inline __inline +#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x2405)) +# define __lzo_inline __inline +#elif (LZO_CC_MSC && (_MSC_VER >= 900)) +# define __lzo_inline __inline +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define __lzo_inline inline +#endif +#endif +#if defined(__lzo_inline) +# define __lzo_HAVE_inline 1 +#else +# define __lzo_inline +#endif +#if !defined(__lzo_forceinline) +#if (LZO_CC_GNUC >= 0x030200ul) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) +# define __lzo_forceinline __forceinline +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) +# define __lzo_forceinline __forceinline +#endif +#endif +#if defined(__lzo_forceinline) +# define __lzo_HAVE_forceinline 1 +#else +# define __lzo_forceinline +#endif +#if !defined(__lzo_noinline) +#if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul) +# define __lzo_noinline __attribute__((__noinline__,__used__)) +#elif (LZO_CC_GNUC >= 0x030200ul) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_MSC) +# define __lzo_noinline __declspec(noinline) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1300)) +# define __lzo_noinline __declspec(noinline) +#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x3200) && (LZO_OS_WIN32 || LZO_OS_WIN64)) +# if defined(__cplusplus) +# else +# define __lzo_noinline __declspec(noinline) +# endif +#endif +#endif +#if defined(__lzo_noinline) +# define __lzo_HAVE_noinline 1 +#else +# define __lzo_noinline +#endif +#if (defined(__lzo_HAVE_forceinline) || defined(__lzo_HAVE_noinline)) && !defined(__lzo_HAVE_inline) +# error "this should not happen" +#endif +#if !defined(__lzo_noreturn) +#if (LZO_CC_GNUC >= 0x020700ul) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) +# define __lzo_noreturn __declspec(noreturn) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) +# define __lzo_noreturn __declspec(noreturn) +#endif +#endif +#if defined(__lzo_noreturn) +# define __lzo_HAVE_noreturn 1 +#else +# define __lzo_noreturn +#endif +#if !defined(__lzo_nothrow) +#if (LZO_CC_GNUC >= 0x030300ul) +# define __lzo_nothrow __attribute__((__nothrow__)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) && defined(__cplusplus) +# define __lzo_nothrow __declspec(nothrow) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) +# define __lzo_nothrow __attribute__((__nothrow__)) +#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_nothrow __attribute__((__nothrow__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus) +# define __lzo_nothrow __declspec(nothrow) +#endif +#endif +#if defined(__lzo_nothrow) +# define __lzo_HAVE_nothrow 1 +#else +# define __lzo_nothrow +#endif +#if !defined(__lzo_restrict) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_LLVM) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_MSC && (_MSC_VER >= 1400)) +# define __lzo_restrict __restrict +#endif +#endif +#if defined(__lzo_restrict) +# define __lzo_HAVE_restrict 1 +#else +# define __lzo_restrict +#endif +#if !defined(__lzo_likely) && !defined(__lzo_unlikely) +#if (LZO_CC_GNUC >= 0x030200ul) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800)) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#endif +#endif +#if defined(__lzo_likely) +# define __lzo_HAVE_likely 1 +#else +# define __lzo_likely(e) (e) +#endif +#if defined(__lzo_unlikely) +# define __lzo_HAVE_unlikely 1 +#else +# define __lzo_unlikely(e) (e) +#endif +#if !defined(LZO_UNUSED) +# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) +# define LZO_UNUSED(var) ((void) &var) +# elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC) +# define LZO_UNUSED(var) if (&var) ; else +# elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_UNUSED(var) ((void) var) +# elif (LZO_CC_MSC && (_MSC_VER < 900)) +# define LZO_UNUSED(var) if (&var) ; else +# elif (LZO_CC_KEILC) +# define LZO_UNUSED(var) {extern int __lzo_unused[1-2*!(sizeof(var)>0)];} +# elif (LZO_CC_PACIFICC) +# define LZO_UNUSED(var) ((void) sizeof(var)) +# elif (LZO_CC_WATCOMC) && defined(__cplusplus) +# define LZO_UNUSED(var) ((void) var) +# else +# define LZO_UNUSED(var) ((void) &var) +# endif +#endif +#if !defined(LZO_UNUSED_FUNC) +# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) +# define LZO_UNUSED_FUNC(func) ((void) func) +# elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC) +# define LZO_UNUSED_FUNC(func) if (func) ; else +# elif (LZO_CC_LLVM) +# define LZO_UNUSED_FUNC(func) ((void) &func) +# elif (LZO_CC_MSC && (_MSC_VER < 900)) +# define LZO_UNUSED_FUNC(func) if (func) ; else +# elif (LZO_CC_MSC) +# define LZO_UNUSED_FUNC(func) ((void) &func) +# elif (LZO_CC_KEILC || LZO_CC_PELLESC) +# define LZO_UNUSED_FUNC(func) {extern int __lzo_unused[1-2*!(sizeof((int)func)>0)];} +# else +# define LZO_UNUSED_FUNC(func) ((void) func) +# endif +#endif +#if !defined(LZO_UNUSED_LABEL) +# if (LZO_CC_WATCOMC) && defined(__cplusplus) +# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l +# elif (LZO_CC_INTELC || LZO_CC_WATCOMC) +# define LZO_UNUSED_LABEL(l) if (0) goto l +# else +# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l +# endif +#endif +#if !defined(LZO_DEFINE_UNINITIALIZED_VAR) +# if 0 +# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var +# elif 0 && (LZO_CC_GNUC) +# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = var +# else +# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = init +# endif +#endif +#if !defined(LZO_COMPILE_TIME_ASSERT_HEADER) +# if (LZO_CC_AZTECC || LZO_CC_ZORTECHC) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)]; +# elif (LZO_CC_DMC || LZO_CC_SYMANTECC) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1u-2*!(e)]; +# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)]; +# else +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-2*!(e)]; +# endif +#endif +#if !defined(LZO_COMPILE_TIME_ASSERT) +# if (LZO_CC_AZTECC) +# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-!(e)];} +# elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) +# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; +# elif (LZO_CC_MSC && (_MSC_VER < 900)) +# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; +# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) +# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; +# else +# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-2*!(e)];} +# endif +#endif +#if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64) +# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC) +# elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) +# define __lzo_cdecl __cdecl +# define __lzo_cdecl_atexit +# define __lzo_cdecl_main __cdecl +# if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) +# define __lzo_cdecl_qsort __pascal +# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) +# define __lzo_cdecl_qsort _stdcall +# else +# define __lzo_cdecl_qsort __cdecl +# endif +# elif (LZO_CC_WATCOMC) +# define __lzo_cdecl __cdecl +# else +# define __lzo_cdecl __cdecl +# define __lzo_cdecl_atexit __cdecl +# define __lzo_cdecl_main __cdecl +# define __lzo_cdecl_qsort __cdecl +# endif +# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC || LZO_CC_WATCOMC) +# elif (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) +# define __lzo_cdecl_sighandler __pascal +# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) +# define __lzo_cdecl_sighandler _stdcall +# elif (LZO_CC_MSC && (_MSC_VER >= 1400)) && defined(_M_CEE_PURE) +# define __lzo_cdecl_sighandler __clrcall +# elif (LZO_CC_MSC && (_MSC_VER >= 600 && _MSC_VER < 700)) +# if defined(_DLL) +# define __lzo_cdecl_sighandler _far _cdecl _loadds +# elif defined(_MT) +# define __lzo_cdecl_sighandler _far _cdecl +# else +# define __lzo_cdecl_sighandler _cdecl +# endif +# else +# define __lzo_cdecl_sighandler __cdecl +# endif +#elif (LZO_ARCH_I386) && (LZO_CC_WATCOMC) +# define __lzo_cdecl __cdecl +#elif (LZO_ARCH_M68K && LZO_OS_TOS && (LZO_CC_PUREC || LZO_CC_TURBOC)) +# define __lzo_cdecl cdecl +#endif +#if !defined(__lzo_cdecl) +# define __lzo_cdecl +#endif +#if !defined(__lzo_cdecl_atexit) +# define __lzo_cdecl_atexit +#endif +#if !defined(__lzo_cdecl_main) +# define __lzo_cdecl_main +#endif +#if !defined(__lzo_cdecl_qsort) +# define __lzo_cdecl_qsort +#endif +#if !defined(__lzo_cdecl_sighandler) +# define __lzo_cdecl_sighandler +#endif +#if !defined(__lzo_cdecl_va) +# define __lzo_cdecl_va __lzo_cdecl +#endif +#if !defined(LZO_CFG_NO_WINDOWS_H) +#if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64) +# if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000)) +# elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__) +# elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul))) +# else +# define LZO_HAVE_WINDOWS_H 1 +# endif +#endif +#endif +#if (LZO_ARCH_ALPHA) +# define LZO_OPT_AVOID_UINT_INDEX 1 +# define LZO_OPT_AVOID_SHORT 1 +# define LZO_OPT_AVOID_USHORT 1 +#elif (LZO_ARCH_AMD64) +# define LZO_OPT_AVOID_INT_INDEX 1 +# define LZO_OPT_AVOID_UINT_INDEX 1 +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +# define LZO_OPT_UNALIGNED64 1 +#elif (LZO_ARCH_ARM && LZO_ARCH_ARM_THUMB) +#elif (LZO_ARCH_ARM) +# define LZO_OPT_AVOID_SHORT 1 +# define LZO_OPT_AVOID_USHORT 1 +#elif (LZO_ARCH_CRIS) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +#elif (LZO_ARCH_I386) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +#elif (LZO_ARCH_IA64) +# define LZO_OPT_AVOID_INT_INDEX 1 +# define LZO_OPT_AVOID_UINT_INDEX 1 +# define LZO_OPT_PREFER_POSTINC 1 +#elif (LZO_ARCH_M68K) +# define LZO_OPT_PREFER_POSTINC 1 +# define LZO_OPT_PREFER_PREDEC 1 +# if defined(__mc68020__) && !defined(__mcoldfire__) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +# endif +#elif (LZO_ARCH_MIPS) +# define LZO_OPT_AVOID_UINT_INDEX 1 +#elif (LZO_ARCH_POWERPC) +# define LZO_OPT_PREFER_PREINC 1 +# define LZO_OPT_PREFER_PREDEC 1 +# if defined(LZO_ABI_BIG_ENDIAN) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +# endif +#elif (LZO_ARCH_S390) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +# if (LZO_SIZEOF_SIZE_T == 8) +# define LZO_OPT_UNALIGNED64 1 +# endif +#elif (LZO_ARCH_SH) +# define LZO_OPT_PREFER_POSTINC 1 +# define LZO_OPT_PREFER_PREDEC 1 +#endif +#if !defined(LZO_CFG_NO_INLINE_ASM) +#if defined(LZO_CC_LLVM) +# define LZO_CFG_NO_INLINE_ASM 1 +#endif +#endif +#if !defined(LZO_CFG_NO_UNALIGNED) +#if defined(LZO_ABI_NEUTRAL_ENDIAN) || defined(LZO_ARCH_GENERIC) +# define LZO_CFG_NO_UNALIGNED 1 +#endif +#endif +#if defined(LZO_CFG_NO_UNALIGNED) +# undef LZO_OPT_UNALIGNED16 +# undef LZO_OPT_UNALIGNED32 +# undef LZO_OPT_UNALIGNED64 +#endif +#if defined(LZO_CFG_NO_INLINE_ASM) +#elif (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) +# define LZO_ASM_SYNTAX_MSC 1 +#elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) +#elif (LZO_ARCH_I386 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) +# define LZO_ASM_SYNTAX_GNUC 1 +#elif (LZO_ARCH_AMD64 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) +# define LZO_ASM_SYNTAX_GNUC 1 +#endif +#if (LZO_ASM_SYNTAX_GNUC) +#if (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC < 0x020000ul)) +# define __LZO_ASM_CLOBBER "ax" +#elif (LZO_CC_INTELC) +# define __LZO_ASM_CLOBBER "memory" +#else +# define __LZO_ASM_CLOBBER "cc", "memory" +#endif +#endif +#if defined(__LZO_INFOSTR_MM) +#elif (LZO_MM_FLAT) && (defined(__LZO_INFOSTR_PM) || defined(LZO_INFO_ABI_PM)) +# define __LZO_INFOSTR_MM "" +#elif defined(LZO_INFO_MM) +# define __LZO_INFOSTR_MM "." LZO_INFO_MM +#else +# define __LZO_INFOSTR_MM "" +#endif +#if defined(__LZO_INFOSTR_PM) +#elif defined(LZO_INFO_ABI_PM) +# define __LZO_INFOSTR_PM "." LZO_INFO_ABI_PM +#else +# define __LZO_INFOSTR_PM "" +#endif +#if defined(__LZO_INFOSTR_ENDIAN) +#elif defined(LZO_INFO_ABI_ENDIAN) +# define __LZO_INFOSTR_ENDIAN "." LZO_INFO_ABI_ENDIAN +#else +# define __LZO_INFOSTR_ENDIAN "" +#endif +#if defined(__LZO_INFOSTR_OSNAME) +#elif defined(LZO_INFO_OS_CONSOLE) +# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_CONSOLE +#elif defined(LZO_INFO_OS_POSIX) +# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_POSIX +#else +# define __LZO_INFOSTR_OSNAME LZO_INFO_OS +#endif +#if defined(__LZO_INFOSTR_LIBC) +#elif defined(LZO_INFO_LIBC) +# define __LZO_INFOSTR_LIBC "." LZO_INFO_LIBC +#else +# define __LZO_INFOSTR_LIBC "" +#endif +#if defined(__LZO_INFOSTR_CCVER) +#elif defined(LZO_INFO_CCVER) +# define __LZO_INFOSTR_CCVER " " LZO_INFO_CCVER +#else +# define __LZO_INFOSTR_CCVER "" +#endif +#define LZO_INFO_STRING \ + LZO_INFO_ARCH __LZO_INFOSTR_MM __LZO_INFOSTR_PM __LZO_INFOSTR_ENDIAN \ + " " __LZO_INFOSTR_OSNAME __LZO_INFOSTR_LIBC " " LZO_INFO_CC __LZO_INFOSTR_CCVER + +#endif /* already included */ + +/* vim:set ts=4 et: */ diff --git a/minilzo.c b/minilzo.c new file mode 100644 index 0000000..6a62b31 --- /dev/null +++ b/minilzo.c @@ -0,0 +1,4112 @@ +/* minilzo.c -- mini subset of the LZO real-time data compression library + + This file is part of the LZO real-time data compression library. + + Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + The LZO library 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. + + The LZO library 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 the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Markus F.X.J. Oberhumer + + http://www.oberhumer.com/opensource/lzo/ + */ + +/* + * NOTE: + * the full LZO package can be found at + * http://www.oberhumer.com/opensource/lzo/ + */ + +#define __LZO_IN_MINILZO +#define LZO_BUILD + +#if defined(LZO_CFG_FREESTANDING) +# undef MINILZO_HAVE_CONFIG_H +# define LZO_LIBC_FREESTANDING 1 +# define LZO_OS_FREESTANDING 1 +#endif + +#ifdef MINILZO_HAVE_CONFIG_H +# include +#endif +#include +#include +#if defined(MINILZO_CFG_USE_INTERNAL_LZODEFS) + +#ifndef __LZODEFS_H_INCLUDED +#define __LZODEFS_H_INCLUDED 1 + +#if defined(__CYGWIN32__) && !defined(__CYGWIN__) +# define __CYGWIN__ __CYGWIN32__ +#endif +#if defined(__IBMCPP__) && !defined(__IBMC__) +# define __IBMC__ __IBMCPP__ +#endif +#if defined(__ICL) && defined(_WIN32) && !defined(__INTEL_COMPILER) +# define __INTEL_COMPILER __ICL +#endif +#if 1 && defined(__INTERIX) && defined(__GNUC__) && !defined(_ALL_SOURCE) +# define _ALL_SOURCE 1 +#endif +#if defined(__mips__) && defined(__R5900__) +# if !defined(__LONG_MAX__) +# define __LONG_MAX__ 9223372036854775807L +# endif +#endif +#if defined(__INTEL_COMPILER) && defined(__linux__) +# pragma warning(disable: 193) +#endif +#if defined(__KEIL__) && defined(__C166__) +# pragma warning disable = 322 +#elif 0 && defined(__C251__) +# pragma warning disable = 322 +#endif +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__MWERKS__) +# if (_MSC_VER >= 1300) +# pragma warning(disable: 4668) +# endif +#endif +#if 0 && defined(__WATCOMC__) +# if (__WATCOMC__ >= 1050) && (__WATCOMC__ < 1060) +# pragma warning 203 9 +# endif +#endif +#if defined(__BORLANDC__) && defined(__MSDOS__) && !defined(__FLAT__) +# pragma option -h +#endif +#if 0 +#define LZO_0xffffL 0xfffful +#define LZO_0xffffffffL 0xfffffffful +#else +#define LZO_0xffffL 65535ul +#define LZO_0xffffffffL 4294967295ul +#endif +#if (LZO_0xffffL == LZO_0xffffffffL) +# error "your preprocessor is broken 1" +#endif +#if (16ul * 16384ul != 262144ul) +# error "your preprocessor is broken 2" +#endif +#if 0 +#if (32767 >= 4294967295ul) +# error "your preprocessor is broken 3" +#endif +#if (65535u >= 4294967295ul) +# error "your preprocessor is broken 4" +#endif +#endif +#if (UINT_MAX == LZO_0xffffL) +#if defined(__ZTC__) && defined(__I86__) && !defined(__OS2__) +# if !defined(MSDOS) +# define MSDOS 1 +# endif +# if !defined(_MSDOS) +# define _MSDOS 1 +# endif +#elif 0 && defined(__VERSION) && defined(MB_LEN_MAX) +# if (__VERSION == 520) && (MB_LEN_MAX == 1) +# if !defined(__AZTEC_C__) +# define __AZTEC_C__ __VERSION +# endif +# if !defined(__DOS__) +# define __DOS__ 1 +# endif +# endif +#endif +#endif +#if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL) +# define ptrdiff_t long +# define _PTRDIFF_T_DEFINED +#endif +#if (UINT_MAX == LZO_0xffffL) +# undef __LZO_RENAME_A +# undef __LZO_RENAME_B +# if defined(__AZTEC_C__) && defined(__DOS__) +# define __LZO_RENAME_A 1 +# elif defined(_MSC_VER) && defined(MSDOS) +# if (_MSC_VER < 600) +# define __LZO_RENAME_A 1 +# elif (_MSC_VER < 700) +# define __LZO_RENAME_B 1 +# endif +# elif defined(__TSC__) && defined(__OS2__) +# define __LZO_RENAME_A 1 +# elif defined(__MSDOS__) && defined(__TURBOC__) && (__TURBOC__ < 0x0410) +# define __LZO_RENAME_A 1 +# elif defined(__PACIFIC__) && defined(DOS) +# if !defined(__far) +# define __far far +# endif +# if !defined(__near) +# define __near near +# endif +# endif +# if defined(__LZO_RENAME_A) +# if !defined(__cdecl) +# define __cdecl cdecl +# endif +# if !defined(__far) +# define __far far +# endif +# if !defined(__huge) +# define __huge huge +# endif +# if !defined(__near) +# define __near near +# endif +# if !defined(__pascal) +# define __pascal pascal +# endif +# if !defined(__huge) +# define __huge huge +# endif +# elif defined(__LZO_RENAME_B) +# if !defined(__cdecl) +# define __cdecl _cdecl +# endif +# if !defined(__far) +# define __far _far +# endif +# if !defined(__huge) +# define __huge _huge +# endif +# if !defined(__near) +# define __near _near +# endif +# if !defined(__pascal) +# define __pascal _pascal +# endif +# elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) +# if !defined(__cdecl) +# define __cdecl cdecl +# endif +# if !defined(__pascal) +# define __pascal pascal +# endif +# endif +# undef __LZO_RENAME_A +# undef __LZO_RENAME_B +#endif +#if (UINT_MAX == LZO_0xffffL) +#if defined(__AZTEC_C__) && defined(__DOS__) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +#elif defined(_MSC_VER) && defined(MSDOS) +# if (_MSC_VER < 600) +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +# endif +# if (_MSC_VER < 700) +# define LZO_BROKEN_INTEGRAL_PROMOTION 1 +# define LZO_BROKEN_SIZEOF 1 +# endif +#elif defined(__PACIFIC__) && defined(DOS) +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +#elif defined(__TURBOC__) && defined(__MSDOS__) +# if (__TURBOC__ < 0x0150) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +# define LZO_BROKEN_INTEGRAL_PROMOTION 1 +# endif +# if (__TURBOC__ < 0x0200) +# define LZO_BROKEN_SIZEOF 1 +# endif +# if (__TURBOC__ < 0x0400) && defined(__cplusplus) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +# endif +#elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +# define LZO_BROKEN_SIZEOF 1 +#endif +#endif +#if defined(__WATCOMC__) && (__WATCOMC__ < 900) +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +#endif +#if defined(_CRAY) && defined(_CRAY1) +# define LZO_BROKEN_SIGNED_RIGHT_SHIFT 1 +#endif +#define LZO_PP_STRINGIZE(x) #x +#define LZO_PP_MACRO_EXPAND(x) LZO_PP_STRINGIZE(x) +#define LZO_PP_CONCAT2(a,b) a ## b +#define LZO_PP_CONCAT3(a,b,c) a ## b ## c +#define LZO_PP_CONCAT4(a,b,c,d) a ## b ## c ## d +#define LZO_PP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e +#define LZO_PP_ECONCAT2(a,b) LZO_PP_CONCAT2(a,b) +#define LZO_PP_ECONCAT3(a,b,c) LZO_PP_CONCAT3(a,b,c) +#define LZO_PP_ECONCAT4(a,b,c,d) LZO_PP_CONCAT4(a,b,c,d) +#define LZO_PP_ECONCAT5(a,b,c,d,e) LZO_PP_CONCAT5(a,b,c,d,e) +#if 1 +#define LZO_CPP_STRINGIZE(x) #x +#define LZO_CPP_MACRO_EXPAND(x) LZO_CPP_STRINGIZE(x) +#define LZO_CPP_CONCAT2(a,b) a ## b +#define LZO_CPP_CONCAT3(a,b,c) a ## b ## c +#define LZO_CPP_CONCAT4(a,b,c,d) a ## b ## c ## d +#define LZO_CPP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e +#define LZO_CPP_ECONCAT2(a,b) LZO_CPP_CONCAT2(a,b) +#define LZO_CPP_ECONCAT3(a,b,c) LZO_CPP_CONCAT3(a,b,c) +#define LZO_CPP_ECONCAT4(a,b,c,d) LZO_CPP_CONCAT4(a,b,c,d) +#define LZO_CPP_ECONCAT5(a,b,c,d,e) LZO_CPP_CONCAT5(a,b,c,d,e) +#endif +#define __LZO_MASK_GEN(o,b) (((((o) << ((b)-1)) - (o)) << 1) + (o)) +#if 1 && defined(__cplusplus) +# if !defined(__STDC_CONSTANT_MACROS) +# define __STDC_CONSTANT_MACROS 1 +# endif +# if !defined(__STDC_LIMIT_MACROS) +# define __STDC_LIMIT_MACROS 1 +# endif +#endif +#if defined(__cplusplus) +# define LZO_EXTERN_C extern "C" +#else +# define LZO_EXTERN_C extern +#endif +#if !defined(__LZO_OS_OVERRIDE) +#if defined(LZO_OS_FREESTANDING) +# define LZO_INFO_OS "freestanding" +#elif defined(LZO_OS_EMBEDDED) +# define LZO_INFO_OS "embedded" +#elif 1 && defined(__IAR_SYSTEMS_ICC__) +# define LZO_OS_EMBEDDED 1 +# define LZO_INFO_OS "embedded" +#elif defined(__CYGWIN__) && defined(__GNUC__) +# define LZO_OS_CYGWIN 1 +# define LZO_INFO_OS "cygwin" +#elif defined(__EMX__) && defined(__GNUC__) +# define LZO_OS_EMX 1 +# define LZO_INFO_OS "emx" +#elif defined(__BEOS__) +# define LZO_OS_BEOS 1 +# define LZO_INFO_OS "beos" +#elif defined(__Lynx__) +# define LZO_OS_LYNXOS 1 +# define LZO_INFO_OS "lynxos" +#elif defined(__OS400__) +# define LZO_OS_OS400 1 +# define LZO_INFO_OS "os400" +#elif defined(__QNX__) +# define LZO_OS_QNX 1 +# define LZO_INFO_OS "qnx" +#elif defined(__BORLANDC__) && defined(__DPMI32__) && (__BORLANDC__ >= 0x0460) +# define LZO_OS_DOS32 1 +# define LZO_INFO_OS "dos32" +#elif defined(__BORLANDC__) && defined(__DPMI16__) +# define LZO_OS_DOS16 1 +# define LZO_INFO_OS "dos16" +#elif defined(__ZTC__) && defined(DOS386) +# define LZO_OS_DOS32 1 +# define LZO_INFO_OS "dos32" +#elif defined(__OS2__) || defined(__OS2V2__) +# if (UINT_MAX == LZO_0xffffL) +# define LZO_OS_OS216 1 +# define LZO_INFO_OS "os216" +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_OS_OS2 1 +# define LZO_INFO_OS "os2" +# else +# error "check your limits.h header" +# endif +#elif defined(__WIN64__) || defined(_WIN64) || defined(WIN64) +# define LZO_OS_WIN64 1 +# define LZO_INFO_OS "win64" +#elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WINDOWS_386__) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +#elif defined(__MWERKS__) && defined(__INTEL__) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +#elif defined(__WINDOWS__) || defined(_WINDOWS) || defined(_Windows) +# if (UINT_MAX == LZO_0xffffL) +# define LZO_OS_WIN16 1 +# define LZO_INFO_OS "win16" +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +# else +# error "check your limits.h header" +# endif +#elif defined(__DOS__) || defined(__MSDOS__) || defined(_MSDOS) || defined(MSDOS) || (defined(__PACIFIC__) && defined(DOS)) +# if (UINT_MAX == LZO_0xffffL) +# define LZO_OS_DOS16 1 +# define LZO_INFO_OS "dos16" +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_OS_DOS32 1 +# define LZO_INFO_OS "dos32" +# else +# error "check your limits.h header" +# endif +#elif defined(__WATCOMC__) +# if defined(__NT__) && (UINT_MAX == LZO_0xffffL) +# define LZO_OS_DOS16 1 +# define LZO_INFO_OS "dos16" +# elif defined(__NT__) && (__WATCOMC__ < 1100) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +# elif defined(__linux__) || defined(__LINUX__) +# define LZO_OS_POSIX 1 +# define LZO_INFO_OS "posix" +# else +# error "please specify a target using the -bt compiler option" +# endif +#elif defined(__palmos__) +# define LZO_OS_PALMOS 1 +# define LZO_INFO_OS "palmos" +#elif defined(__TOS__) || defined(__atarist__) +# define LZO_OS_TOS 1 +# define LZO_INFO_OS "tos" +#elif defined(macintosh) && !defined(__ppc__) +# define LZO_OS_MACCLASSIC 1 +# define LZO_INFO_OS "macclassic" +#elif defined(__VMS) +# define LZO_OS_VMS 1 +# define LZO_INFO_OS "vms" +#elif ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) +# define LZO_OS_CONSOLE 1 +# define LZO_OS_CONSOLE_PS2 1 +# define LZO_INFO_OS "console" +# define LZO_INFO_OS_CONSOLE "ps2" +#elif (defined(__mips__) && defined(__psp__)) +# define LZO_OS_CONSOLE 1 +# define LZO_OS_CONSOLE_PSP 1 +# define LZO_INFO_OS "console" +# define LZO_INFO_OS_CONSOLE "psp" +#else +# define LZO_OS_POSIX 1 +# define LZO_INFO_OS "posix" +#endif +#if (LZO_OS_POSIX) +# if defined(_AIX) || defined(__AIX__) || defined(__aix__) +# define LZO_OS_POSIX_AIX 1 +# define LZO_INFO_OS_POSIX "aix" +# elif defined(__FreeBSD__) +# define LZO_OS_POSIX_FREEBSD 1 +# define LZO_INFO_OS_POSIX "freebsd" +# elif defined(__hpux__) || defined(__hpux) +# define LZO_OS_POSIX_HPUX 1 +# define LZO_INFO_OS_POSIX "hpux" +# elif defined(__INTERIX) +# define LZO_OS_POSIX_INTERIX 1 +# define LZO_INFO_OS_POSIX "interix" +# elif defined(__IRIX__) || defined(__irix__) +# define LZO_OS_POSIX_IRIX 1 +# define LZO_INFO_OS_POSIX "irix" +# elif defined(__linux__) || defined(__linux) || defined(__LINUX__) +# define LZO_OS_POSIX_LINUX 1 +# define LZO_INFO_OS_POSIX "linux" +# elif defined(__APPLE__) || defined(__MACOS__) +# define LZO_OS_POSIX_MACOSX 1 +# define LZO_INFO_OS_POSIX "macosx" +# elif defined(__minix__) || defined(__minix) +# define LZO_OS_POSIX_MINIX 1 +# define LZO_INFO_OS_POSIX "minix" +# elif defined(__NetBSD__) +# define LZO_OS_POSIX_NETBSD 1 +# define LZO_INFO_OS_POSIX "netbsd" +# elif defined(__OpenBSD__) +# define LZO_OS_POSIX_OPENBSD 1 +# define LZO_INFO_OS_POSIX "openbsd" +# elif defined(__osf__) +# define LZO_OS_POSIX_OSF 1 +# define LZO_INFO_OS_POSIX "osf" +# elif defined(__solaris__) || defined(__sun) +# if defined(__SVR4) || defined(__svr4__) +# define LZO_OS_POSIX_SOLARIS 1 +# define LZO_INFO_OS_POSIX "solaris" +# else +# define LZO_OS_POSIX_SUNOS 1 +# define LZO_INFO_OS_POSIX "sunos" +# endif +# elif defined(__ultrix__) || defined(__ultrix) +# define LZO_OS_POSIX_ULTRIX 1 +# define LZO_INFO_OS_POSIX "ultrix" +# elif defined(_UNICOS) +# define LZO_OS_POSIX_UNICOS 1 +# define LZO_INFO_OS_POSIX "unicos" +# else +# define LZO_OS_POSIX_UNKNOWN 1 +# define LZO_INFO_OS_POSIX "unknown" +# endif +#endif +#endif +#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +# if (UINT_MAX != LZO_0xffffL) +# error "this should not happen" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +#endif +#if (LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_WIN32 || LZO_OS_WIN64) +# if (UINT_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +#endif +#if defined(CIL) && defined(_GNUCC) && defined(__GNUC__) +# define LZO_CC_CILLY 1 +# define LZO_INFO_CC "Cilly" +# if defined(__CILLY__) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CILLY__) +# else +# define LZO_INFO_CCVER "unknown" +# endif +#elif 0 && defined(SDCC) && defined(__VERSION__) && !defined(__GNUC__) +# define LZO_CC_SDCC 1 +# define LZO_INFO_CC "sdcc" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(SDCC) +#elif defined(__PATHSCALE__) && defined(__PATHCC_PATCHLEVEL__) +# define LZO_CC_PATHSCALE (__PATHCC__ * 0x10000L + __PATHCC_MINOR__ * 0x100 + __PATHCC_PATCHLEVEL__) +# define LZO_INFO_CC "Pathscale C" +# define LZO_INFO_CCVER __PATHSCALE__ +#elif defined(__INTEL_COMPILER) +# define LZO_CC_INTELC 1 +# define LZO_INFO_CC "Intel C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__INTEL_COMPILER) +# if defined(_WIN32) || defined(_WIN64) +# define LZO_CC_SYNTAX_MSC 1 +# else +# define LZO_CC_SYNTAX_GNUC 1 +# endif +#elif defined(__POCC__) && defined(_WIN32) +# define LZO_CC_PELLESC 1 +# define LZO_INFO_CC "Pelles C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__POCC__) +#elif defined(__llvm__) && defined(__GNUC__) && defined(__VERSION__) +# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) +# else +# define LZO_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) +# endif +# define LZO_INFO_CC "llvm-gcc" +# define LZO_INFO_CCVER __VERSION__ +#elif defined(__GNUC__) && defined(__VERSION__) +# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) +# elif defined(__GNUC_MINOR__) +# define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) +# else +# define LZO_CC_GNUC (__GNUC__ * 0x10000L) +# endif +# define LZO_INFO_CC "gcc" +# define LZO_INFO_CCVER __VERSION__ +#elif defined(__ACK__) && defined(_ACK) +# define LZO_CC_ACK 1 +# define LZO_INFO_CC "Amsterdam Compiler Kit C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__AZTEC_C__) +# define LZO_CC_AZTECC 1 +# define LZO_INFO_CC "Aztec C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__AZTEC_C__) +#elif defined(__BORLANDC__) +# define LZO_CC_BORLANDC 1 +# define LZO_INFO_CC "Borland C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__BORLANDC__) +#elif defined(_CRAYC) && defined(_RELEASE) +# define LZO_CC_CRAYC 1 +# define LZO_INFO_CC "Cray C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_RELEASE) +#elif defined(__DMC__) && defined(__SC__) +# define LZO_CC_DMC 1 +# define LZO_INFO_CC "Digital Mars C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DMC__) +#elif defined(__DECC) +# define LZO_CC_DECC 1 +# define LZO_INFO_CC "DEC C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DECC) +#elif defined(__HIGHC__) +# define LZO_CC_HIGHC 1 +# define LZO_INFO_CC "MetaWare High C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__IAR_SYSTEMS_ICC__) +# define LZO_CC_IARC 1 +# define LZO_INFO_CC "IAR C" +# if defined(__VER__) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__VER__) +# else +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__IBMC__) +# define LZO_CC_IBMC 1 +# define LZO_INFO_CC "IBM C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__IBMC__) +#elif defined(__KEIL__) && defined(__C166__) +# define LZO_CC_KEILC 1 +# define LZO_INFO_CC "Keil C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__C166__) +#elif defined(__LCC__) && defined(_WIN32) && defined(__LCCOPTIMLEVEL) +# define LZO_CC_LCCWIN32 1 +# define LZO_INFO_CC "lcc-win32" +# define LZO_INFO_CCVER "unknown" +#elif defined(__LCC__) +# define LZO_CC_LCC 1 +# define LZO_INFO_CC "lcc" +# if defined(__LCC_VERSION__) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__LCC_VERSION__) +# else +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(_MSC_VER) +# define LZO_CC_MSC 1 +# define LZO_INFO_CC "Microsoft C" +# if defined(_MSC_FULL_VER) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) "." LZO_PP_MACRO_EXPAND(_MSC_FULL_VER) +# else +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) +# endif +#elif defined(__MWERKS__) +# define LZO_CC_MWERKS 1 +# define LZO_INFO_CC "Metrowerks C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__MWERKS__) +#elif (defined(__NDPC__) || defined(__NDPX__)) && defined(__i386) +# define LZO_CC_NDPC 1 +# define LZO_INFO_CC "Microway NDP C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__PACIFIC__) +# define LZO_CC_PACIFICC 1 +# define LZO_INFO_CC "Pacific C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PACIFIC__) +#elif defined(__PGI) && (defined(__linux__) || defined(__WIN32__)) +# define LZO_CC_PGI 1 +# define LZO_INFO_CC "Portland Group PGI C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__PUREC__) && defined(__TOS__) +# define LZO_CC_PUREC 1 +# define LZO_INFO_CC "Pure C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PUREC__) +#elif defined(__SC__) && defined(__ZTC__) +# define LZO_CC_SYMANTECC 1 +# define LZO_INFO_CC "Symantec C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SC__) +#elif defined(__SUNPRO_C) +# define LZO_INFO_CC "SunPro C" +# if ((__SUNPRO_C)+0 > 0) +# define LZO_CC_SUNPROC __SUNPRO_C +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_C) +# else +# define LZO_CC_SUNPROC 1 +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__SUNPRO_CC) +# define LZO_INFO_CC "SunPro C" +# if ((__SUNPRO_CC)+0 > 0) +# define LZO_CC_SUNPROC __SUNPRO_CC +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_CC) +# else +# define LZO_CC_SUNPROC 1 +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__TINYC__) +# define LZO_CC_TINYC 1 +# define LZO_INFO_CC "Tiny C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TINYC__) +#elif defined(__TSC__) +# define LZO_CC_TOPSPEEDC 1 +# define LZO_INFO_CC "TopSpeed C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TSC__) +#elif defined(__WATCOMC__) +# define LZO_CC_WATCOMC 1 +# define LZO_INFO_CC "Watcom C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__WATCOMC__) +#elif defined(__TURBOC__) +# define LZO_CC_TURBOC 1 +# define LZO_INFO_CC "Turbo C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TURBOC__) +#elif defined(__ZTC__) +# define LZO_CC_ZORTECHC 1 +# define LZO_INFO_CC "Zortech C" +# if (__ZTC__ == 0x310) +# define LZO_INFO_CCVER "0x310" +# else +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__ZTC__) +# endif +#else +# define LZO_CC_UNKNOWN 1 +# define LZO_INFO_CC "unknown" +# define LZO_INFO_CCVER "unknown" +#endif +#if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER) +# error "LZO_CC_MSC: _MSC_FULL_VER is not defined" +#endif +#if !defined(__LZO_ARCH_OVERRIDE) && !defined(LZO_ARCH_GENERIC) && defined(_CRAY) +# if (UINT_MAX > LZO_0xffffffffL) && defined(_CRAY) +# if defined(_CRAYMPP) || defined(_CRAYT3D) || defined(_CRAYT3E) +# define LZO_ARCH_CRAY_MPP 1 +# elif defined(_CRAY1) +# define LZO_ARCH_CRAY_PVP 1 +# endif +# endif +#endif +#if !defined(__LZO_ARCH_OVERRIDE) +#if defined(LZO_ARCH_GENERIC) +# define LZO_INFO_ARCH "generic" +#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +# define LZO_ARCH_I086 1 +# define LZO_ARCH_IA16 1 +# define LZO_INFO_ARCH "i086" +#elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA) +# define LZO_ARCH_ALPHA 1 +# define LZO_INFO_ARCH "alpha" +#elif (LZO_ARCH_CRAY_MPP) && (defined(_CRAYT3D) || defined(_CRAYT3E)) +# define LZO_ARCH_ALPHA 1 +# define LZO_INFO_ARCH "alpha" +#elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64) +# define LZO_ARCH_AMD64 1 +# define LZO_INFO_ARCH "amd64" +#elif defined(__thumb__) || (defined(_M_ARM) && defined(_M_THUMB)) +# define LZO_ARCH_ARM 1 +# define LZO_ARCH_ARM_THUMB 1 +# define LZO_INFO_ARCH "arm_thumb" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__) +# define LZO_ARCH_ARM 1 +# if defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 1) +# define LZO_ARCH_ARM_THUMB 1 +# define LZO_INFO_ARCH "arm_thumb" +# elif defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 2) +# define LZO_INFO_ARCH "arm" +# else +# define LZO_INFO_ARCH "arm" +# endif +#elif defined(__arm__) || defined(_M_ARM) +# define LZO_ARCH_ARM 1 +# define LZO_INFO_ARCH "arm" +#elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__) +# define LZO_ARCH_AVR 1 +# define LZO_INFO_ARCH "avr" +#elif defined(__bfin__) +# define LZO_ARCH_BLACKFIN 1 +# define LZO_INFO_ARCH "blackfin" +#elif (UINT_MAX == LZO_0xffffL) && defined(__C166__) +# define LZO_ARCH_C166 1 +# define LZO_INFO_ARCH "c166" +#elif defined(__cris__) +# define LZO_ARCH_CRIS 1 +# define LZO_INFO_ARCH "cris" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCEZ80__) +# define LZO_ARCH_EZ80 1 +# define LZO_INFO_ARCH "ez80" +#elif defined(__H8300__) || defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) +# define LZO_ARCH_H8300 1 +# define LZO_INFO_ARCH "h8300" +#elif defined(__hppa__) || defined(__hppa) +# define LZO_ARCH_HPPA 1 +# define LZO_INFO_ARCH "hppa" +#elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386) +# define LZO_ARCH_I386 1 +# define LZO_ARCH_IA32 1 +# define LZO_INFO_ARCH "i386" +#elif (LZO_CC_ZORTECHC && defined(__I86__)) +# define LZO_ARCH_I386 1 +# define LZO_ARCH_IA32 1 +# define LZO_INFO_ARCH "i386" +#elif (LZO_OS_DOS32 && LZO_CC_HIGHC) && defined(_I386) +# define LZO_ARCH_I386 1 +# define LZO_ARCH_IA32 1 +# define LZO_INFO_ARCH "i386" +#elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64) +# define LZO_ARCH_IA64 1 +# define LZO_INFO_ARCH "ia64" +#elif (UINT_MAX == LZO_0xffffL) && defined(__m32c__) +# define LZO_ARCH_M16C 1 +# define LZO_INFO_ARCH "m16c" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCM16C__) +# define LZO_ARCH_M16C 1 +# define LZO_INFO_ARCH "m16c" +#elif defined(__m32r__) +# define LZO_ARCH_M32R 1 +# define LZO_INFO_ARCH "m32r" +#elif (LZO_OS_TOS) || defined(__m68k__) || defined(__m68000__) || defined(__mc68000__) || defined(__mc68020__) || defined(_M_M68K) +# define LZO_ARCH_M68K 1 +# define LZO_INFO_ARCH "m68k" +#elif (UINT_MAX == LZO_0xffffL) && defined(__C251__) +# define LZO_ARCH_MCS251 1 +# define LZO_INFO_ARCH "mcs251" +#elif (UINT_MAX == LZO_0xffffL) && defined(__C51__) +# define LZO_ARCH_MCS51 1 +# define LZO_INFO_ARCH "mcs51" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC8051__) +# define LZO_ARCH_MCS51 1 +# define LZO_INFO_ARCH "mcs51" +#elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000) +# define LZO_ARCH_MIPS 1 +# define LZO_INFO_ARCH "mips" +#elif (UINT_MAX == LZO_0xffffL) && defined(__MSP430__) +# define LZO_ARCH_MSP430 1 +# define LZO_INFO_ARCH "msp430" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC430__) +# define LZO_ARCH_MSP430 1 +# define LZO_INFO_ARCH "msp430" +#elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR) +# define LZO_ARCH_POWERPC 1 +# define LZO_INFO_ARCH "powerpc" +#elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x) +# define LZO_ARCH_S390 1 +# define LZO_INFO_ARCH "s390" +#elif defined(__sh__) || defined(_M_SH) +# define LZO_ARCH_SH 1 +# define LZO_INFO_ARCH "sh" +#elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8) +# define LZO_ARCH_SPARC 1 +# define LZO_INFO_ARCH "sparc" +#elif defined(__SPU__) +# define LZO_ARCH_SPU 1 +# define LZO_INFO_ARCH "spu" +#elif (UINT_MAX == LZO_0xffffL) && defined(__z80) +# define LZO_ARCH_Z80 1 +# define LZO_INFO_ARCH "z80" +#elif (LZO_ARCH_CRAY_PVP) +# if defined(_CRAYSV1) +# define LZO_ARCH_CRAY_SV1 1 +# define LZO_INFO_ARCH "cray_sv1" +# elif (_ADDR64) +# define LZO_ARCH_CRAY_T90 1 +# define LZO_INFO_ARCH "cray_t90" +# elif (_ADDR32) +# define LZO_ARCH_CRAY_YMP 1 +# define LZO_INFO_ARCH "cray_ymp" +# else +# define LZO_ARCH_CRAY_XMP 1 +# define LZO_INFO_ARCH "cray_xmp" +# endif +#else +# define LZO_ARCH_UNKNOWN 1 +# define LZO_INFO_ARCH "unknown" +#endif +#endif +#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_DOS32 || LZO_OS_OS2) +# error "FIXME - missing define for CPU architecture" +#endif +#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN32) +# error "FIXME - missing WIN32 define for CPU architecture" +#endif +#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN64) +# error "FIXME - missing WIN64 define for CPU architecture" +#endif +#if (LZO_OS_OS216 || LZO_OS_WIN16) +# define LZO_ARCH_I086PM 1 +# define LZO_ARCH_IA16PM 1 +#elif 1 && (LZO_OS_DOS16 && defined(BLX286)) +# define LZO_ARCH_I086PM 1 +# define LZO_ARCH_IA16PM 1 +#elif 1 && (LZO_OS_DOS16 && defined(DOSX286)) +# define LZO_ARCH_I086PM 1 +# define LZO_ARCH_IA16PM 1 +#elif 1 && (LZO_OS_DOS16 && LZO_CC_BORLANDC && defined(__DPMI16__)) +# define LZO_ARCH_I086PM 1 +# define LZO_ARCH_IA16PM 1 +#endif +#if defined(LZO_ARCH_ARM_THUMB) && !defined(LZO_ARCH_ARM) +# error "this should not happen" +#endif +#if defined(LZO_ARCH_I086PM) && !defined(LZO_ARCH_I086) +# error "this should not happen" +#endif +#if (LZO_ARCH_I086) +# if (UINT_MAX != LZO_0xffffL) +# error "this should not happen" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +#endif +#if (LZO_ARCH_I386) +# if (UINT_MAX != LZO_0xffffL) && defined(__i386_int16__) +# error "this should not happen" +# endif +# if (UINT_MAX != LZO_0xffffffffL) && !defined(__i386_int16__) +# error "this should not happen" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +#endif +#if !defined(__LZO_MM_OVERRIDE) +#if (LZO_ARCH_I086) +#if (UINT_MAX != LZO_0xffffL) +# error "this should not happen" +#endif +#if defined(__TINY__) || defined(M_I86TM) || defined(_M_I86TM) +# define LZO_MM_TINY 1 +#elif defined(__HUGE__) || defined(_HUGE_) || defined(M_I86HM) || defined(_M_I86HM) +# define LZO_MM_HUGE 1 +#elif defined(__SMALL__) || defined(M_I86SM) || defined(_M_I86SM) || defined(SMALL_MODEL) +# define LZO_MM_SMALL 1 +#elif defined(__MEDIUM__) || defined(M_I86MM) || defined(_M_I86MM) +# define LZO_MM_MEDIUM 1 +#elif defined(__COMPACT__) || defined(M_I86CM) || defined(_M_I86CM) +# define LZO_MM_COMPACT 1 +#elif defined(__LARGE__) || defined(M_I86LM) || defined(_M_I86LM) || defined(LARGE_MODEL) +# define LZO_MM_LARGE 1 +#elif (LZO_CC_AZTECC) +# if defined(_LARGE_CODE) && defined(_LARGE_DATA) +# define LZO_MM_LARGE 1 +# elif defined(_LARGE_CODE) +# define LZO_MM_MEDIUM 1 +# elif defined(_LARGE_DATA) +# define LZO_MM_COMPACT 1 +# else +# define LZO_MM_SMALL 1 +# endif +#elif (LZO_CC_ZORTECHC && defined(__VCM__)) +# define LZO_MM_LARGE 1 +#else +# error "unknown memory model" +#endif +#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +#define LZO_HAVE_MM_HUGE_PTR 1 +#define LZO_HAVE_MM_HUGE_ARRAY 1 +#if (LZO_MM_TINY) +# undef LZO_HAVE_MM_HUGE_ARRAY +#endif +#if (LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_ZORTECHC) +# undef LZO_HAVE_MM_HUGE_PTR +# undef LZO_HAVE_MM_HUGE_ARRAY +#elif (LZO_CC_DMC || LZO_CC_SYMANTECC) +# undef LZO_HAVE_MM_HUGE_ARRAY +#elif (LZO_CC_MSC && defined(_QC)) +# undef LZO_HAVE_MM_HUGE_ARRAY +# if (_MSC_VER < 600) +# undef LZO_HAVE_MM_HUGE_PTR +# endif +#elif (LZO_CC_TURBOC && (__TURBOC__ < 0x0295)) +# undef LZO_HAVE_MM_HUGE_ARRAY +#endif +#if (LZO_ARCH_I086PM) && !defined(LZO_HAVE_MM_HUGE_PTR) +# if (LZO_OS_DOS16) +# error "this should not happen" +# elif (LZO_CC_ZORTECHC) +# else +# error "this should not happen" +# endif +#endif +#ifdef __cplusplus +extern "C" { +#endif +#if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0200)) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif (LZO_CC_MSC || LZO_CC_TOPSPEEDC) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif (LZO_CC_TURBOC && (__TURBOC__ >= 0x0295)) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif ((LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_TURBOC) && LZO_OS_DOS16) +# define LZO_MM_AHSHIFT 12 +#elif (LZO_CC_WATCOMC) + extern unsigned char _HShift; +# define LZO_MM_AHSHIFT ((unsigned) _HShift) +#else +# error "FIXME - implement LZO_MM_AHSHIFT" +#endif +#ifdef __cplusplus +} +#endif +#endif +#elif (LZO_ARCH_C166) +#if !defined(__MODEL__) +# error "FIXME - C166 __MODEL__" +#elif ((__MODEL__) == 0) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 1) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 2) +# define LZO_MM_LARGE 1 +#elif ((__MODEL__) == 3) +# define LZO_MM_TINY 1 +#elif ((__MODEL__) == 4) +# define LZO_MM_XTINY 1 +#elif ((__MODEL__) == 5) +# define LZO_MM_XSMALL 1 +#else +# error "FIXME - C166 __MODEL__" +#endif +#elif (LZO_ARCH_MCS251) +#if !defined(__MODEL__) +# error "FIXME - MCS251 __MODEL__" +#elif ((__MODEL__) == 0) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 2) +# define LZO_MM_LARGE 1 +#elif ((__MODEL__) == 3) +# define LZO_MM_TINY 1 +#elif ((__MODEL__) == 4) +# define LZO_MM_XTINY 1 +#elif ((__MODEL__) == 5) +# define LZO_MM_XSMALL 1 +#else +# error "FIXME - MCS251 __MODEL__" +#endif +#elif (LZO_ARCH_MCS51) +#if !defined(__MODEL__) +# error "FIXME - MCS51 __MODEL__" +#elif ((__MODEL__) == 1) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 2) +# define LZO_MM_LARGE 1 +#elif ((__MODEL__) == 3) +# define LZO_MM_TINY 1 +#elif ((__MODEL__) == 4) +# define LZO_MM_XTINY 1 +#elif ((__MODEL__) == 5) +# define LZO_MM_XSMALL 1 +#else +# error "FIXME - MCS51 __MODEL__" +#endif +#elif (LZO_ARCH_CRAY_PVP) +# define LZO_MM_PVP 1 +#else +# define LZO_MM_FLAT 1 +#endif +#if (LZO_MM_COMPACT) +# define LZO_INFO_MM "compact" +#elif (LZO_MM_FLAT) +# define LZO_INFO_MM "flat" +#elif (LZO_MM_HUGE) +# define LZO_INFO_MM "huge" +#elif (LZO_MM_LARGE) +# define LZO_INFO_MM "large" +#elif (LZO_MM_MEDIUM) +# define LZO_INFO_MM "medium" +#elif (LZO_MM_PVP) +# define LZO_INFO_MM "pvp" +#elif (LZO_MM_SMALL) +# define LZO_INFO_MM "small" +#elif (LZO_MM_TINY) +# define LZO_INFO_MM "tiny" +#else +# error "unknown memory model" +#endif +#endif +#if defined(SIZEOF_SHORT) +# define LZO_SIZEOF_SHORT (SIZEOF_SHORT) +#endif +#if defined(SIZEOF_INT) +# define LZO_SIZEOF_INT (SIZEOF_INT) +#endif +#if defined(SIZEOF_LONG) +# define LZO_SIZEOF_LONG (SIZEOF_LONG) +#endif +#if defined(SIZEOF_LONG_LONG) +# define LZO_SIZEOF_LONG_LONG (SIZEOF_LONG_LONG) +#endif +#if defined(SIZEOF___INT16) +# define LZO_SIZEOF___INT16 (SIZEOF___INT16) +#endif +#if defined(SIZEOF___INT32) +# define LZO_SIZEOF___INT32 (SIZEOF___INT32) +#endif +#if defined(SIZEOF___INT64) +# define LZO_SIZEOF___INT64 (SIZEOF___INT64) +#endif +#if defined(SIZEOF_VOID_P) +# define LZO_SIZEOF_VOID_P (SIZEOF_VOID_P) +#endif +#if defined(SIZEOF_SIZE_T) +# define LZO_SIZEOF_SIZE_T (SIZEOF_SIZE_T) +#endif +#if defined(SIZEOF_PTRDIFF_T) +# define LZO_SIZEOF_PTRDIFF_T (SIZEOF_PTRDIFF_T) +#endif +#define __LZO_LSR(x,b) (((x)+0ul) >> (b)) +#if !defined(LZO_SIZEOF_SHORT) +# if (LZO_ARCH_CRAY_PVP) +# define LZO_SIZEOF_SHORT 8 +# elif (USHRT_MAX == LZO_0xffffL) +# define LZO_SIZEOF_SHORT 2 +# elif (__LZO_LSR(USHRT_MAX,7) == 1) +# define LZO_SIZEOF_SHORT 1 +# elif (__LZO_LSR(USHRT_MAX,15) == 1) +# define LZO_SIZEOF_SHORT 2 +# elif (__LZO_LSR(USHRT_MAX,31) == 1) +# define LZO_SIZEOF_SHORT 4 +# elif (__LZO_LSR(USHRT_MAX,63) == 1) +# define LZO_SIZEOF_SHORT 8 +# elif (__LZO_LSR(USHRT_MAX,127) == 1) +# define LZO_SIZEOF_SHORT 16 +# else +# error "LZO_SIZEOF_SHORT" +# endif +#endif +#if !defined(LZO_SIZEOF_INT) +# if (LZO_ARCH_CRAY_PVP) +# define LZO_SIZEOF_INT 8 +# elif (UINT_MAX == LZO_0xffffL) +# define LZO_SIZEOF_INT 2 +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_SIZEOF_INT 4 +# elif (__LZO_LSR(UINT_MAX,7) == 1) +# define LZO_SIZEOF_INT 1 +# elif (__LZO_LSR(UINT_MAX,15) == 1) +# define LZO_SIZEOF_INT 2 +# elif (__LZO_LSR(UINT_MAX,31) == 1) +# define LZO_SIZEOF_INT 4 +# elif (__LZO_LSR(UINT_MAX,63) == 1) +# define LZO_SIZEOF_INT 8 +# elif (__LZO_LSR(UINT_MAX,127) == 1) +# define LZO_SIZEOF_INT 16 +# else +# error "LZO_SIZEOF_INT" +# endif +#endif +#if !defined(LZO_SIZEOF_LONG) +# if (ULONG_MAX == LZO_0xffffffffL) +# define LZO_SIZEOF_LONG 4 +# elif (__LZO_LSR(ULONG_MAX,7) == 1) +# define LZO_SIZEOF_LONG 1 +# elif (__LZO_LSR(ULONG_MAX,15) == 1) +# define LZO_SIZEOF_LONG 2 +# elif (__LZO_LSR(ULONG_MAX,31) == 1) +# define LZO_SIZEOF_LONG 4 +# elif (__LZO_LSR(ULONG_MAX,63) == 1) +# define LZO_SIZEOF_LONG 8 +# elif (__LZO_LSR(ULONG_MAX,127) == 1) +# define LZO_SIZEOF_LONG 16 +# else +# error "LZO_SIZEOF_LONG" +# endif +#endif +#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) +#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) +# if defined(__LONG_MAX__) && defined(__LONG_LONG_MAX__) +# if (LZO_CC_GNUC >= 0x030300ul) +# if ((__LONG_MAX__)+0 == (__LONG_LONG_MAX__)+0) +# define LZO_SIZEOF_LONG_LONG LZO_SIZEOF_LONG +# elif (__LZO_LSR(__LONG_LONG_MAX__,30) == 1) +# define LZO_SIZEOF_LONG_LONG 4 +# endif +# endif +# endif +#endif +#endif +#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) +#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) +#if (LZO_ARCH_I086 && LZO_CC_DMC) +#elif (LZO_CC_CILLY) && defined(__GNUC__) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_SIZEOF_LONG_LONG 8 +#elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_OS_WIN64 || defined(_WIN64)) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_ARCH_I386 && (LZO_CC_DMC)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_SYMANTECC && (__SC__ >= 0x700))) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_INTELC && defined(__linux__))) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_MWERKS || LZO_CC_PELLESC || LZO_CC_PGI || LZO_CC_SUNPROC)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_INTELC || LZO_CC_MSC)) +# define LZO_SIZEOF___INT64 8 +#elif ((LZO_OS_WIN32 || defined(_WIN32)) && (LZO_CC_MSC)) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_ARCH_I386 && (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0520))) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_ARCH_I386 && (LZO_CC_WATCOMC && (__WATCOMC__ >= 1100))) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_CC_WATCOMC && defined(_INTEGRAL_MAX_BITS) && (_INTEGRAL_MAX_BITS == 64)) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_CC_SDCC) && (LZO_SIZEOF_INT == 2) +#elif 1 && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define LZO_SIZEOF_LONG_LONG 8 +#endif +#endif +#endif +#if defined(__cplusplus) && defined(LZO_CC_GNUC) +# if (LZO_CC_GNUC < 0x020800ul) +# undef LZO_SIZEOF_LONG_LONG +# endif +#endif +#if defined(LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG) +# undef LZO_SIZEOF_LONG_LONG +#endif +#if !defined(LZO_SIZEOF_VOID_P) +#if (LZO_ARCH_I086) +# define __LZO_WORDSIZE 2 +# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM) +# define LZO_SIZEOF_VOID_P 2 +# elif (LZO_MM_COMPACT || LZO_MM_LARGE || LZO_MM_HUGE) +# define LZO_SIZEOF_VOID_P 4 +# else +# error "LZO_MM" +# endif +#elif (LZO_ARCH_AVR || LZO_ARCH_Z80) +# define __LZO_WORDSIZE 1 +# define LZO_SIZEOF_VOID_P 2 +#elif (LZO_ARCH_C166 || LZO_ARCH_MCS51 || LZO_ARCH_MCS251 || LZO_ARCH_MSP430) +# define LZO_SIZEOF_VOID_P 2 +#elif (LZO_ARCH_H8300) +# if defined(__NORMAL_MODE__) +# define __LZO_WORDSIZE 4 +# define LZO_SIZEOF_VOID_P 2 +# elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) +# define __LZO_WORDSIZE 4 +# define LZO_SIZEOF_VOID_P 4 +# else +# define __LZO_WORDSIZE 2 +# define LZO_SIZEOF_VOID_P 2 +# endif +# if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_SIZEOF_INT == 4) +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_INT +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_INT +# endif +#elif (LZO_ARCH_M16C) +# define __LZO_WORDSIZE 2 +# if defined(__m32c_cpu__) || defined(__m32cm_cpu__) +# define LZO_SIZEOF_VOID_P 4 +# else +# define LZO_SIZEOF_VOID_P 2 +# endif +#elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) +# define __LZO_WORDSIZE 8 +# define LZO_SIZEOF_VOID_P 4 +#elif defined(__LLP64__) || defined(__LLP64) || defined(_LLP64) || defined(_WIN64) +# define __LZO_WORDSIZE 8 +# define LZO_SIZEOF_VOID_P 8 +#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__) +# define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG +#elif (LZO_OS_OS400 || defined(__OS400__)) +# define __LZO_WORDSIZE LZO_SIZEOF_LONG +# define LZO_SIZEOF_VOID_P 16 +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG +#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) +# define LZO_SIZEOF_VOID_P 8 +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG +#elif (LZO_ARCH_SPU) +# if 0 +# define __LZO_WORDSIZE 16 +# endif +# define LZO_SIZEOF_VOID_P 4 +#else +# define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG +#endif +#endif +#if !defined(LZO_WORDSIZE) +# if defined(__LZO_WORDSIZE) +# define LZO_WORDSIZE __LZO_WORDSIZE +# else +# define LZO_WORDSIZE LZO_SIZEOF_VOID_P +# endif +#endif +#if !defined(LZO_SIZEOF_SIZE_T) +#if (LZO_ARCH_I086 || LZO_ARCH_M16C) +# define LZO_SIZEOF_SIZE_T 2 +#else +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_VOID_P +#endif +#endif +#if !defined(LZO_SIZEOF_PTRDIFF_T) +#if (LZO_ARCH_I086) +# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM || LZO_MM_HUGE) +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_VOID_P +# elif (LZO_MM_COMPACT || LZO_MM_LARGE) +# if (LZO_CC_BORLANDC || LZO_CC_TURBOC) +# define LZO_SIZEOF_PTRDIFF_T 4 +# else +# define LZO_SIZEOF_PTRDIFF_T 2 +# endif +# else +# error "LZO_MM" +# endif +#else +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_SIZE_T +#endif +#endif +#if defined(LZO_ABI_NEUTRAL_ENDIAN) +# undef LZO_ABI_BIG_ENDIAN +# undef LZO_ABI_LITTLE_ENDIAN +#elif !defined(LZO_ABI_BIG_ENDIAN) && !defined(LZO_ABI_LITTLE_ENDIAN) +#if (LZO_ARCH_ALPHA) && (LZO_ARCH_CRAY_MPP) +# define LZO_ABI_BIG_ENDIAN 1 +#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif (LZO_ARCH_M68K || LZO_ARCH_S390) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__) +# if (__LITTLE_ENDIAN__ == 1) +# define LZO_ABI_LITTLE_ENDIAN 1 +# else +# define LZO_ABI_BIG_ENDIAN 1 +# endif +#elif 1 && defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEB__) && !defined(__ARMEL__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEL__) && !defined(__ARMEB__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#endif +#endif +#if defined(LZO_ABI_BIG_ENDIAN) && defined(LZO_ABI_LITTLE_ENDIAN) +# error "this should not happen" +#endif +#if defined(LZO_ABI_BIG_ENDIAN) +# define LZO_INFO_ABI_ENDIAN "be" +#elif defined(LZO_ABI_LITTLE_ENDIAN) +# define LZO_INFO_ABI_ENDIAN "le" +#elif defined(LZO_ABI_NEUTRAL_ENDIAN) +# define LZO_INFO_ABI_ENDIAN "neutral" +#endif +#if (LZO_SIZEOF_INT == 1 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) +# define LZO_ABI_I8LP16 1 +# define LZO_INFO_ABI_PM "i8lp16" +#elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) +# define LZO_ABI_ILP16 1 +# define LZO_INFO_ABI_PM "ilp16" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4) +# define LZO_ABI_ILP32 1 +# define LZO_INFO_ABI_PM "ilp32" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 8 && LZO_SIZEOF_SIZE_T == 8) +# define LZO_ABI_LLP64 1 +# define LZO_INFO_ABI_PM "llp64" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) +# define LZO_ABI_LP64 1 +# define LZO_INFO_ABI_PM "lp64" +#elif (LZO_SIZEOF_INT == 8 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) +# define LZO_ABI_ILP64 1 +# define LZO_INFO_ABI_PM "ilp64" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 4) +# define LZO_ABI_IP32L64 1 +# define LZO_INFO_ABI_PM "ip32l64" +#endif +#if !defined(__LZO_LIBC_OVERRIDE) +#if defined(LZO_LIBC_NAKED) +# define LZO_INFO_LIBC "naked" +#elif defined(LZO_LIBC_FREESTANDING) +# define LZO_INFO_LIBC "freestanding" +#elif defined(LZO_LIBC_MOSTLY_FREESTANDING) +# define LZO_INFO_LIBC "mfreestanding" +#elif defined(LZO_LIBC_ISOC90) +# define LZO_INFO_LIBC "isoc90" +#elif defined(LZO_LIBC_ISOC99) +# define LZO_INFO_LIBC "isoc99" +#elif defined(__dietlibc__) +# define LZO_LIBC_DIETLIBC 1 +# define LZO_INFO_LIBC "dietlibc" +#elif defined(_NEWLIB_VERSION) +# define LZO_LIBC_NEWLIB 1 +# define LZO_INFO_LIBC "newlib" +#elif defined(__UCLIBC__) && defined(__UCLIBC_MAJOR__) && defined(__UCLIBC_MINOR__) +# if defined(__UCLIBC_SUBLEVEL__) +# define LZO_LIBC_UCLIBC (__UCLIBC_MAJOR__ * 0x10000L + __UCLIBC_MINOR__ * 0x100 + __UCLIBC_SUBLEVEL__) +# else +# define LZO_LIBC_UCLIBC 0x00090bL +# endif +# define LZO_INFO_LIBC "uclibc" +#elif defined(__GLIBC__) && defined(__GLIBC_MINOR__) +# define LZO_LIBC_GLIBC (__GLIBC__ * 0x10000L + __GLIBC_MINOR__ * 0x100) +# define LZO_INFO_LIBC "glibc" +#elif (LZO_CC_MWERKS) && defined(__MSL__) +# define LZO_LIBC_MSL __MSL__ +# define LZO_INFO_LIBC "msl" +#elif 1 && defined(__IAR_SYSTEMS_ICC__) +# define LZO_LIBC_ISOC90 1 +# define LZO_INFO_LIBC "isoc90" +#else +# define LZO_LIBC_DEFAULT 1 +# define LZO_INFO_LIBC "default" +#endif +#endif +#if !defined(__lzo_gnuc_extension__) +#if (LZO_CC_GNUC >= 0x020800ul) +# define __lzo_gnuc_extension__ __extension__ +#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_gnuc_extension__ __extension__ +#else +# define __lzo_gnuc_extension__ +#endif +#endif +#if !defined(__lzo_ua_volatile) +# define __lzo_ua_volatile volatile +#endif +#if !defined(__lzo_alignof) +#if (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +# define __lzo_alignof(e) __alignof__(e) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700)) +# define __lzo_alignof(e) __alignof__(e) +#elif (LZO_CC_MSC && (_MSC_VER >= 1300)) +# define __lzo_alignof(e) __alignof(e) +#endif +#endif +#if defined(__lzo_alignof) +# define __lzo_HAVE_alignof 1 +#endif +#if !defined(__lzo_constructor) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_constructor __attribute__((__constructor__,__used__)) +#elif (LZO_CC_GNUC >= 0x020700ul) +# define __lzo_constructor __attribute__((__constructor__)) +#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_constructor __attribute__((__constructor__)) +#endif +#endif +#if defined(__lzo_constructor) +# define __lzo_HAVE_constructor 1 +#endif +#if !defined(__lzo_destructor) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_destructor __attribute__((__destructor__,__used__)) +#elif (LZO_CC_GNUC >= 0x020700ul) +# define __lzo_destructor __attribute__((__destructor__)) +#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_destructor __attribute__((__destructor__)) +#endif +#endif +#if defined(__lzo_destructor) +# define __lzo_HAVE_destructor 1 +#endif +#if defined(__lzo_HAVE_destructor) && !defined(__lzo_HAVE_constructor) +# error "this should not happen" +#endif +#if !defined(__lzo_inline) +#if (LZO_CC_TURBOC && (__TURBOC__ <= 0x0295)) +#elif defined(__cplusplus) +# define __lzo_inline inline +#elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550)) +# define __lzo_inline __inline +#elif (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +# define __lzo_inline __inline__ +#elif (LZO_CC_DMC) +# define __lzo_inline __inline +#elif (LZO_CC_INTELC) +# define __lzo_inline __inline +#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x2405)) +# define __lzo_inline __inline +#elif (LZO_CC_MSC && (_MSC_VER >= 900)) +# define __lzo_inline __inline +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define __lzo_inline inline +#endif +#endif +#if defined(__lzo_inline) +# define __lzo_HAVE_inline 1 +#else +# define __lzo_inline +#endif +#if !defined(__lzo_forceinline) +#if (LZO_CC_GNUC >= 0x030200ul) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) +# define __lzo_forceinline __forceinline +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) +# define __lzo_forceinline __forceinline +#endif +#endif +#if defined(__lzo_forceinline) +# define __lzo_HAVE_forceinline 1 +#else +# define __lzo_forceinline +#endif +#if !defined(__lzo_noinline) +#if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul) +# define __lzo_noinline __attribute__((__noinline__,__used__)) +#elif (LZO_CC_GNUC >= 0x030200ul) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_MSC) +# define __lzo_noinline __declspec(noinline) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1300)) +# define __lzo_noinline __declspec(noinline) +#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x3200) && (LZO_OS_WIN32 || LZO_OS_WIN64)) +# if defined(__cplusplus) +# else +# define __lzo_noinline __declspec(noinline) +# endif +#endif +#endif +#if defined(__lzo_noinline) +# define __lzo_HAVE_noinline 1 +#else +# define __lzo_noinline +#endif +#if (defined(__lzo_HAVE_forceinline) || defined(__lzo_HAVE_noinline)) && !defined(__lzo_HAVE_inline) +# error "this should not happen" +#endif +#if !defined(__lzo_noreturn) +#if (LZO_CC_GNUC >= 0x020700ul) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) +# define __lzo_noreturn __declspec(noreturn) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) +# define __lzo_noreturn __declspec(noreturn) +#endif +#endif +#if defined(__lzo_noreturn) +# define __lzo_HAVE_noreturn 1 +#else +# define __lzo_noreturn +#endif +#if !defined(__lzo_nothrow) +#if (LZO_CC_GNUC >= 0x030300ul) +# define __lzo_nothrow __attribute__((__nothrow__)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) && defined(__cplusplus) +# define __lzo_nothrow __declspec(nothrow) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) +# define __lzo_nothrow __attribute__((__nothrow__)) +#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_nothrow __attribute__((__nothrow__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus) +# define __lzo_nothrow __declspec(nothrow) +#endif +#endif +#if defined(__lzo_nothrow) +# define __lzo_HAVE_nothrow 1 +#else +# define __lzo_nothrow +#endif +#if !defined(__lzo_restrict) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_LLVM) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_MSC && (_MSC_VER >= 1400)) +# define __lzo_restrict __restrict +#endif +#endif +#if defined(__lzo_restrict) +# define __lzo_HAVE_restrict 1 +#else +# define __lzo_restrict +#endif +#if !defined(__lzo_likely) && !defined(__lzo_unlikely) +#if (LZO_CC_GNUC >= 0x030200ul) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800)) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#endif +#endif +#if defined(__lzo_likely) +# define __lzo_HAVE_likely 1 +#else +# define __lzo_likely(e) (e) +#endif +#if defined(__lzo_unlikely) +# define __lzo_HAVE_unlikely 1 +#else +# define __lzo_unlikely(e) (e) +#endif +#if !defined(LZO_UNUSED) +# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) +# define LZO_UNUSED(var) ((void) &var) +# elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC) +# define LZO_UNUSED(var) if (&var) ; else +# elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_UNUSED(var) ((void) var) +# elif (LZO_CC_MSC && (_MSC_VER < 900)) +# define LZO_UNUSED(var) if (&var) ; else +# elif (LZO_CC_KEILC) +# define LZO_UNUSED(var) {extern int __lzo_unused[1-2*!(sizeof(var)>0)];} +# elif (LZO_CC_PACIFICC) +# define LZO_UNUSED(var) ((void) sizeof(var)) +# elif (LZO_CC_WATCOMC) && defined(__cplusplus) +# define LZO_UNUSED(var) ((void) var) +# else +# define LZO_UNUSED(var) ((void) &var) +# endif +#endif +#if !defined(LZO_UNUSED_FUNC) +# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) +# define LZO_UNUSED_FUNC(func) ((void) func) +# elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC) +# define LZO_UNUSED_FUNC(func) if (func) ; else +# elif (LZO_CC_LLVM) +# define LZO_UNUSED_FUNC(func) ((void) &func) +# elif (LZO_CC_MSC && (_MSC_VER < 900)) +# define LZO_UNUSED_FUNC(func) if (func) ; else +# elif (LZO_CC_MSC) +# define LZO_UNUSED_FUNC(func) ((void) &func) +# elif (LZO_CC_KEILC || LZO_CC_PELLESC) +# define LZO_UNUSED_FUNC(func) {extern int __lzo_unused[1-2*!(sizeof((int)func)>0)];} +# else +# define LZO_UNUSED_FUNC(func) ((void) func) +# endif +#endif +#if !defined(LZO_UNUSED_LABEL) +# if (LZO_CC_WATCOMC) && defined(__cplusplus) +# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l +# elif (LZO_CC_INTELC || LZO_CC_WATCOMC) +# define LZO_UNUSED_LABEL(l) if (0) goto l +# else +# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l +# endif +#endif +#if !defined(LZO_DEFINE_UNINITIALIZED_VAR) +# if 0 +# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var +# elif 0 && (LZO_CC_GNUC) +# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = var +# else +# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = init +# endif +#endif +#if !defined(LZO_COMPILE_TIME_ASSERT_HEADER) +# if (LZO_CC_AZTECC || LZO_CC_ZORTECHC) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)]; +# elif (LZO_CC_DMC || LZO_CC_SYMANTECC) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1u-2*!(e)]; +# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)]; +# else +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-2*!(e)]; +# endif +#endif +#if !defined(LZO_COMPILE_TIME_ASSERT) +# if (LZO_CC_AZTECC) +# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-!(e)];} +# elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) +# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; +# elif (LZO_CC_MSC && (_MSC_VER < 900)) +# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; +# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) +# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; +# else +# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-2*!(e)];} +# endif +#endif +#if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64) +# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC) +# elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) +# define __lzo_cdecl __cdecl +# define __lzo_cdecl_atexit +# define __lzo_cdecl_main __cdecl +# if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) +# define __lzo_cdecl_qsort __pascal +# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) +# define __lzo_cdecl_qsort _stdcall +# else +# define __lzo_cdecl_qsort __cdecl +# endif +# elif (LZO_CC_WATCOMC) +# define __lzo_cdecl __cdecl +# else +# define __lzo_cdecl __cdecl +# define __lzo_cdecl_atexit __cdecl +# define __lzo_cdecl_main __cdecl +# define __lzo_cdecl_qsort __cdecl +# endif +# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC || LZO_CC_WATCOMC) +# elif (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) +# define __lzo_cdecl_sighandler __pascal +# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) +# define __lzo_cdecl_sighandler _stdcall +# elif (LZO_CC_MSC && (_MSC_VER >= 1400)) && defined(_M_CEE_PURE) +# define __lzo_cdecl_sighandler __clrcall +# elif (LZO_CC_MSC && (_MSC_VER >= 600 && _MSC_VER < 700)) +# if defined(_DLL) +# define __lzo_cdecl_sighandler _far _cdecl _loadds +# elif defined(_MT) +# define __lzo_cdecl_sighandler _far _cdecl +# else +# define __lzo_cdecl_sighandler _cdecl +# endif +# else +# define __lzo_cdecl_sighandler __cdecl +# endif +#elif (LZO_ARCH_I386) && (LZO_CC_WATCOMC) +# define __lzo_cdecl __cdecl +#elif (LZO_ARCH_M68K && LZO_OS_TOS && (LZO_CC_PUREC || LZO_CC_TURBOC)) +# define __lzo_cdecl cdecl +#endif +#if !defined(__lzo_cdecl) +# define __lzo_cdecl +#endif +#if !defined(__lzo_cdecl_atexit) +# define __lzo_cdecl_atexit +#endif +#if !defined(__lzo_cdecl_main) +# define __lzo_cdecl_main +#endif +#if !defined(__lzo_cdecl_qsort) +# define __lzo_cdecl_qsort +#endif +#if !defined(__lzo_cdecl_sighandler) +# define __lzo_cdecl_sighandler +#endif +#if !defined(__lzo_cdecl_va) +# define __lzo_cdecl_va __lzo_cdecl +#endif +#if !defined(LZO_CFG_NO_WINDOWS_H) +#if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64) +# if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000)) +# elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__) +# elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul))) +# else +# define LZO_HAVE_WINDOWS_H 1 +# endif +#endif +#endif +#if (LZO_ARCH_ALPHA) +# define LZO_OPT_AVOID_UINT_INDEX 1 +# define LZO_OPT_AVOID_SHORT 1 +# define LZO_OPT_AVOID_USHORT 1 +#elif (LZO_ARCH_AMD64) +# define LZO_OPT_AVOID_INT_INDEX 1 +# define LZO_OPT_AVOID_UINT_INDEX 1 +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +# define LZO_OPT_UNALIGNED64 1 +#elif (LZO_ARCH_ARM && LZO_ARCH_ARM_THUMB) +#elif (LZO_ARCH_ARM) +# define LZO_OPT_AVOID_SHORT 1 +# define LZO_OPT_AVOID_USHORT 1 +#elif (LZO_ARCH_CRIS) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +#elif (LZO_ARCH_I386) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +#elif (LZO_ARCH_IA64) +# define LZO_OPT_AVOID_INT_INDEX 1 +# define LZO_OPT_AVOID_UINT_INDEX 1 +# define LZO_OPT_PREFER_POSTINC 1 +#elif (LZO_ARCH_M68K) +# define LZO_OPT_PREFER_POSTINC 1 +# define LZO_OPT_PREFER_PREDEC 1 +# if defined(__mc68020__) && !defined(__mcoldfire__) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +# endif +#elif (LZO_ARCH_MIPS) +# define LZO_OPT_AVOID_UINT_INDEX 1 +#elif (LZO_ARCH_POWERPC) +# define LZO_OPT_PREFER_PREINC 1 +# define LZO_OPT_PREFER_PREDEC 1 +# if defined(LZO_ABI_BIG_ENDIAN) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +# endif +#elif (LZO_ARCH_S390) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +# if (LZO_SIZEOF_SIZE_T == 8) +# define LZO_OPT_UNALIGNED64 1 +# endif +#elif (LZO_ARCH_SH) +# define LZO_OPT_PREFER_POSTINC 1 +# define LZO_OPT_PREFER_PREDEC 1 +#endif +#if !defined(LZO_CFG_NO_INLINE_ASM) +#if defined(LZO_CC_LLVM) +# define LZO_CFG_NO_INLINE_ASM 1 +#endif +#endif +#if !defined(LZO_CFG_NO_UNALIGNED) +#if defined(LZO_ABI_NEUTRAL_ENDIAN) || defined(LZO_ARCH_GENERIC) +# define LZO_CFG_NO_UNALIGNED 1 +#endif +#endif +#if defined(LZO_CFG_NO_UNALIGNED) +# undef LZO_OPT_UNALIGNED16 +# undef LZO_OPT_UNALIGNED32 +# undef LZO_OPT_UNALIGNED64 +#endif +#if defined(LZO_CFG_NO_INLINE_ASM) +#elif (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) +# define LZO_ASM_SYNTAX_MSC 1 +#elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) +#elif (LZO_ARCH_I386 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) +# define LZO_ASM_SYNTAX_GNUC 1 +#elif (LZO_ARCH_AMD64 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) +# define LZO_ASM_SYNTAX_GNUC 1 +#endif +#if (LZO_ASM_SYNTAX_GNUC) +#if (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC < 0x020000ul)) +# define __LZO_ASM_CLOBBER "ax" +#elif (LZO_CC_INTELC) +# define __LZO_ASM_CLOBBER "memory" +#else +# define __LZO_ASM_CLOBBER "cc", "memory" +#endif +#endif +#if defined(__LZO_INFOSTR_MM) +#elif (LZO_MM_FLAT) && (defined(__LZO_INFOSTR_PM) || defined(LZO_INFO_ABI_PM)) +# define __LZO_INFOSTR_MM "" +#elif defined(LZO_INFO_MM) +# define __LZO_INFOSTR_MM "." LZO_INFO_MM +#else +# define __LZO_INFOSTR_MM "" +#endif +#if defined(__LZO_INFOSTR_PM) +#elif defined(LZO_INFO_ABI_PM) +# define __LZO_INFOSTR_PM "." LZO_INFO_ABI_PM +#else +# define __LZO_INFOSTR_PM "" +#endif +#if defined(__LZO_INFOSTR_ENDIAN) +#elif defined(LZO_INFO_ABI_ENDIAN) +# define __LZO_INFOSTR_ENDIAN "." LZO_INFO_ABI_ENDIAN +#else +# define __LZO_INFOSTR_ENDIAN "" +#endif +#if defined(__LZO_INFOSTR_OSNAME) +#elif defined(LZO_INFO_OS_CONSOLE) +# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_CONSOLE +#elif defined(LZO_INFO_OS_POSIX) +# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_POSIX +#else +# define __LZO_INFOSTR_OSNAME LZO_INFO_OS +#endif +#if defined(__LZO_INFOSTR_LIBC) +#elif defined(LZO_INFO_LIBC) +# define __LZO_INFOSTR_LIBC "." LZO_INFO_LIBC +#else +# define __LZO_INFOSTR_LIBC "" +#endif +#if defined(__LZO_INFOSTR_CCVER) +#elif defined(LZO_INFO_CCVER) +# define __LZO_INFOSTR_CCVER " " LZO_INFO_CCVER +#else +# define __LZO_INFOSTR_CCVER "" +#endif +#define LZO_INFO_STRING \ + LZO_INFO_ARCH __LZO_INFOSTR_MM __LZO_INFOSTR_PM __LZO_INFOSTR_ENDIAN \ + " " __LZO_INFOSTR_OSNAME __LZO_INFOSTR_LIBC " " LZO_INFO_CC __LZO_INFOSTR_CCVER + +#endif + +#endif + +#undef LZO_HAVE_CONFIG_H +#include "minilzo.h" + +#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x2030) +# error "version mismatch in miniLZO source files" +#endif + +#ifdef MINILZO_HAVE_CONFIG_H +# define LZO_HAVE_CONFIG_H +#endif + +#ifndef __LZO_CONF_H +#define __LZO_CONF_H + +#if !defined(__LZO_IN_MINILZO) +#if defined(LZO_CFG_FREESTANDING) +# define LZO_LIBC_FREESTANDING 1 +# define LZO_OS_FREESTANDING 1 +# define ACC_LIBC_FREESTANDING 1 +# define ACC_OS_FREESTANDING 1 +#endif +#if defined(LZO_CFG_NO_UNALIGNED) +# define ACC_CFG_NO_UNALIGNED 1 +#endif +#if defined(LZO_ARCH_GENERIC) +# define ACC_ARCH_GENERIC 1 +#endif +#if defined(LZO_ABI_NEUTRAL_ENDIAN) +# define ACC_ABI_NEUTRAL_ENDIAN 1 +#endif +#if defined(LZO_HAVE_CONFIG_H) +# define ACC_CONFIG_NO_HEADER 1 +#endif +#if defined(LZO_CFG_EXTRA_CONFIG_HEADER) +# include LZO_CFG_EXTRA_CONFIG_HEADER +#endif +#if defined(__LZOCONF_H) || defined(__LZOCONF_H_INCLUDED) +# error "include this file first" +#endif +#include "lzo/lzoconf.h" +#endif + +#if (LZO_VERSION < 0x02000) || !defined(__LZOCONF_H_INCLUDED) +# error "version mismatch" +#endif + +#if (LZO_CC_BORLANDC && LZO_ARCH_I086) +# pragma option -h +#endif + +#if (LZO_CC_MSC && (_MSC_VER >= 1000)) +# pragma warning(disable: 4127 4701) +#endif +#if (LZO_CC_MSC && (_MSC_VER >= 1300)) +# pragma warning(disable: 4820) +# pragma warning(disable: 4514 4710 4711) +#endif + +#if (LZO_CC_SUNPROC) +# pragma error_messages(off,E_END_OF_LOOP_CODE_NOT_REACHED) +# pragma error_messages(off,E_LOOP_NOT_ENTERED_AT_TOP) +#endif + +#if defined(__LZO_MMODEL_HUGE) && (!LZO_HAVE_MM_HUGE_PTR) +# error "this should not happen - check defines for __huge" +#endif + +#if defined(__LZO_IN_MINILZO) || defined(LZO_CFG_FREESTANDING) +#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +# define ACC_WANT_ACC_INCD_H 1 +# define ACC_WANT_ACC_INCE_H 1 +# define ACC_WANT_ACC_INCI_H 1 +#elif 1 +# include +#else +# define ACC_WANT_ACC_INCD_H 1 +#endif + +#if (LZO_ARCH_I086) +# define ACC_MM_AHSHIFT LZO_MM_AHSHIFT +# define ACC_PTR_FP_OFF(x) (((const unsigned __far*)&(x))[0]) +# define ACC_PTR_FP_SEG(x) (((const unsigned __far*)&(x))[1]) +# define ACC_PTR_MK_FP(s,o) ((void __far*)(((unsigned long)(s)<<16)+(unsigned)(o))) +#endif + +#if !defined(lzo_uintptr_t) +# if defined(__LZO_MMODEL_HUGE) +# define lzo_uintptr_t unsigned long +# elif 1 && defined(LZO_OS_OS400) && (LZO_SIZEOF_VOID_P == 16) +# define __LZO_UINTPTR_T_IS_POINTER 1 + typedef char* lzo_uintptr_t; +# define lzo_uintptr_t lzo_uintptr_t +# elif (LZO_SIZEOF_SIZE_T == LZO_SIZEOF_VOID_P) +# define lzo_uintptr_t size_t +# elif (LZO_SIZEOF_LONG == LZO_SIZEOF_VOID_P) +# define lzo_uintptr_t unsigned long +# elif (LZO_SIZEOF_INT == LZO_SIZEOF_VOID_P) +# define lzo_uintptr_t unsigned int +# elif (LZO_SIZEOF_LONG_LONG == LZO_SIZEOF_VOID_P) +# define lzo_uintptr_t unsigned long long +# else +# define lzo_uintptr_t size_t +# endif +#endif +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp)) + +#if 1 && !defined(LZO_CFG_FREESTANDING) +#if 1 && !defined(HAVE_STRING_H) +#define HAVE_STRING_H 1 +#endif +#if 1 && !defined(HAVE_MEMCMP) +#define HAVE_MEMCMP 1 +#endif +#if 1 && !defined(HAVE_MEMCPY) +#define HAVE_MEMCPY 1 +#endif +#if 1 && !defined(HAVE_MEMMOVE) +#define HAVE_MEMMOVE 1 +#endif +#if 1 && !defined(HAVE_MEMSET) +#define HAVE_MEMSET 1 +#endif +#endif + +#if 1 && defined(HAVE_STRING_H) +#include +#endif + +#if defined(LZO_CFG_FREESTANDING) +# undef HAVE_MEMCMP +# undef HAVE_MEMCPY +# undef HAVE_MEMMOVE +# undef HAVE_MEMSET +#endif + +#if !defined(HAVE_MEMCMP) +# undef memcmp +# define memcmp(a,b,c) lzo_memcmp(a,b,c) +#elif !defined(__LZO_MMODEL_HUGE) +# define lzo_memcmp(a,b,c) memcmp(a,b,c) +#endif +#if !defined(HAVE_MEMCPY) +# undef memcpy +# define memcpy(a,b,c) lzo_memcpy(a,b,c) +#elif !defined(__LZO_MMODEL_HUGE) +# define lzo_memcpy(a,b,c) memcpy(a,b,c) +#endif +#if !defined(HAVE_MEMMOVE) +# undef memmove +# define memmove(a,b,c) lzo_memmove(a,b,c) +#elif !defined(__LZO_MMODEL_HUGE) +# define lzo_memmove(a,b,c) memmove(a,b,c) +#endif +#if !defined(HAVE_MEMSET) +# undef memset +# define memset(a,b,c) lzo_memset(a,b,c) +#elif !defined(__LZO_MMODEL_HUGE) +# define lzo_memset(a,b,c) memset(a,b,c) +#endif + +#undef NDEBUG +#if defined(LZO_CFG_FREESTANDING) +# undef LZO_DEBUG +# define NDEBUG 1 +# undef assert +# define assert(e) ((void)0) +#else +# if !defined(LZO_DEBUG) +# define NDEBUG 1 +# endif +# include +#endif + +#if 0 && defined(__BOUNDS_CHECKING_ON) +# include +#else +# define BOUNDS_CHECKING_OFF_DURING(stmt) stmt +# define BOUNDS_CHECKING_OFF_IN_EXPR(expr) (expr) +#endif + +#if !defined(__lzo_inline) +# define __lzo_inline +#endif +#if !defined(__lzo_forceinline) +# define __lzo_forceinline +#endif +#if !defined(__lzo_noinline) +# define __lzo_noinline +#endif + +#if 1 +# define LZO_BYTE(x) ((unsigned char) (x)) +#else +# define LZO_BYTE(x) ((unsigned char) ((x) & 0xff)) +#endif + +#define LZO_MAX(a,b) ((a) >= (b) ? (a) : (b)) +#define LZO_MIN(a,b) ((a) <= (b) ? (a) : (b)) +#define LZO_MAX3(a,b,c) ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c)) +#define LZO_MIN3(a,b,c) ((a) <= (b) ? LZO_MIN(a,c) : LZO_MIN(b,c)) + +#define lzo_sizeof(type) ((lzo_uint) (sizeof(type))) + +#define LZO_HIGH(array) ((lzo_uint) (sizeof(array)/sizeof(*(array)))) + +#define LZO_SIZE(bits) (1u << (bits)) +#define LZO_MASK(bits) (LZO_SIZE(bits) - 1) + +#define LZO_LSIZE(bits) (1ul << (bits)) +#define LZO_LMASK(bits) (LZO_LSIZE(bits) - 1) + +#define LZO_USIZE(bits) ((lzo_uint) 1 << (bits)) +#define LZO_UMASK(bits) (LZO_USIZE(bits) - 1) + +#if !defined(DMUL) +#if 0 + +# define DMUL(a,b) ((lzo_xint) ((lzo_uint32)(a) * (lzo_uint32)(b))) +#else +# define DMUL(a,b) ((lzo_xint) ((a) * (b))) +#endif +#endif + +#if 1 && !defined(LZO_CFG_NO_UNALIGNED) +#if 1 && (LZO_ARCH_AMD64 || LZO_ARCH_I386) +# if (LZO_SIZEOF_SHORT == 2) +# define LZO_UNALIGNED_OK_2 +# endif +# if (LZO_SIZEOF_INT == 4) +# define LZO_UNALIGNED_OK_4 +# endif +#endif +#endif + +#if defined(LZO_UNALIGNED_OK_2) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(short) == 2) +#endif +#if defined(LZO_UNALIGNED_OK_4) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint32) == 4) +#elif defined(LZO_ALIGNED_OK_4) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint32) == 4) +#endif + +#define MEMCPY8_DS(dest,src,len) \ + lzo_memcpy(dest,src,len); dest += len; src += len + +#define BZERO8_PTR(s,l,n) \ + lzo_memset((lzo_voidp)(s),0,(lzo_uint)(l)*(n)) + +#define MEMCPY_DS(dest,src,len) \ + do *dest++ = *src++; while (--len > 0) + +__LZO_EXTERN_C int __lzo_init_done; +__LZO_EXTERN_C const char __lzo_copyright[]; +LZO_EXTERN(const lzo_bytep) lzo_copyright(void); + +#ifndef __LZO_PTR_H +#define __LZO_PTR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(lzo_uintptr_t) +# if defined(__LZO_MMODEL_HUGE) +# define lzo_uintptr_t unsigned long +# else +# define lzo_uintptr_t acc_uintptr_t +# ifdef __ACC_INTPTR_T_IS_POINTER +# define __LZO_UINTPTR_T_IS_POINTER 1 +# endif +# endif +#endif + +#if (LZO_ARCH_I086) +#define PTR(a) ((lzo_bytep) (a)) +#define PTR_ALIGNED_4(a) ((ACC_PTR_FP_OFF(a) & 3) == 0) +#define PTR_ALIGNED2_4(a,b) (((ACC_PTR_FP_OFF(a) | ACC_PTR_FP_OFF(b)) & 3) == 0) +#elif (LZO_MM_PVP) +#define PTR(a) ((lzo_bytep) (a)) +#define PTR_ALIGNED_8(a) ((((lzo_uintptr_t)(a)) >> 61) == 0) +#define PTR_ALIGNED2_8(a,b) ((((lzo_uintptr_t)(a)|(lzo_uintptr_t)(b)) >> 61) == 0) +#else +#define PTR(a) ((lzo_uintptr_t) (a)) +#define PTR_LINEAR(a) PTR(a) +#define PTR_ALIGNED_4(a) ((PTR_LINEAR(a) & 3) == 0) +#define PTR_ALIGNED_8(a) ((PTR_LINEAR(a) & 7) == 0) +#define PTR_ALIGNED2_4(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 3) == 0) +#define PTR_ALIGNED2_8(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 7) == 0) +#endif + +#define PTR_LT(a,b) (PTR(a) < PTR(b)) +#define PTR_GE(a,b) (PTR(a) >= PTR(b)) +#define PTR_DIFF(a,b) (PTR(a) - PTR(b)) +#define pd(a,b) ((lzo_uint) ((a)-(b))) + +LZO_EXTERN(lzo_uintptr_t) +__lzo_ptr_linear(const lzo_voidp ptr); + +typedef union +{ + char a_char; + unsigned char a_uchar; + short a_short; + unsigned short a_ushort; + int a_int; + unsigned int a_uint; + long a_long; + unsigned long a_ulong; + lzo_int a_lzo_int; + lzo_uint a_lzo_uint; + lzo_int32 a_lzo_int32; + lzo_uint32 a_lzo_uint32; + ptrdiff_t a_ptrdiff_t; + lzo_uintptr_t a_lzo_uintptr_t; + lzo_voidp a_lzo_voidp; + void * a_void_p; + lzo_bytep a_lzo_bytep; + lzo_bytepp a_lzo_bytepp; + lzo_uintp a_lzo_uintp; + lzo_uint * a_lzo_uint_p; + lzo_uint32p a_lzo_uint32p; + lzo_uint32 * a_lzo_uint32_p; + unsigned char * a_uchar_p; + char * a_char_p; +} +lzo_full_align_t; + +#ifdef __cplusplus +} +#endif + +#endif + +#define LZO_DETERMINISTIC + +#define LZO_DICT_USE_PTR +#if 0 && (LZO_ARCH_I086) +# undef LZO_DICT_USE_PTR +#endif + +#if defined(LZO_DICT_USE_PTR) +# define lzo_dict_t const lzo_bytep +# define lzo_dict_p lzo_dict_t __LZO_MMODEL * +#else +# define lzo_dict_t lzo_uint +# define lzo_dict_p lzo_dict_t __LZO_MMODEL * +#endif + +#endif + +#if !defined(MINILZO_CFG_SKIP_LZO_PTR) + +LZO_PUBLIC(lzo_uintptr_t) +__lzo_ptr_linear(const lzo_voidp ptr) +{ + lzo_uintptr_t p; + +#if (LZO_ARCH_I086) + p = (((lzo_uintptr_t)(ACC_PTR_FP_SEG(ptr))) << (16 - ACC_MM_AHSHIFT)) + (ACC_PTR_FP_OFF(ptr)); +#elif (LZO_MM_PVP) + p = (lzo_uintptr_t) (ptr); + p = (p << 3) | (p >> 61); +#else + p = (lzo_uintptr_t) PTR_LINEAR(ptr); +#endif + + return p; +} + +LZO_PUBLIC(unsigned) +__lzo_align_gap(const lzo_voidp ptr, lzo_uint size) +{ +#if defined(__LZO_UINTPTR_T_IS_POINTER) + size_t n = (size_t) ptr; + n = (((n + size - 1) / size) * size) - n; +#else + lzo_uintptr_t p, n; + p = __lzo_ptr_linear(ptr); + n = (((p + size - 1) / size) * size) - p; +#endif + + assert(size > 0); + assert((long)n >= 0); + assert(n <= size); + return (unsigned)n; +} + +#endif + +/* If you use the LZO library in a product, I would appreciate that you + * keep this copyright string in the executable of your product. + */ + +const char __lzo_copyright[] = +#if !defined(__LZO_IN_MINLZO) + LZO_VERSION_STRING; +#else + "\r\n\n" + "LZO data compression library.\n" + "$Copyright: LZO (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Markus Franz Xaver Johannes Oberhumer\n" + "\n" + "http://www.oberhumer.com $\n\n" + "$Id: LZO version: v" LZO_VERSION_STRING ", " LZO_VERSION_DATE " $\n" + "$Built: " __DATE__ " " __TIME__ " $\n" + "$Info: " LZO_INFO_STRING " $\n"; +#endif + +LZO_PUBLIC(const lzo_bytep) +lzo_copyright(void) +{ +#if (LZO_OS_DOS16 && LZO_CC_TURBOC) + return (lzo_voidp) __lzo_copyright; +#else + return (const lzo_bytep) __lzo_copyright; +#endif +} + +LZO_PUBLIC(unsigned) +lzo_version(void) +{ + return LZO_VERSION; +} + +LZO_PUBLIC(const char *) +lzo_version_string(void) +{ + return LZO_VERSION_STRING; +} + +LZO_PUBLIC(const char *) +lzo_version_date(void) +{ + return LZO_VERSION_DATE; +} + +LZO_PUBLIC(const lzo_charp) +_lzo_version_string(void) +{ + return LZO_VERSION_STRING; +} + +LZO_PUBLIC(const lzo_charp) +_lzo_version_date(void) +{ + return LZO_VERSION_DATE; +} + +#define LZO_BASE 65521u +#define LZO_NMAX 5552 + +#define LZO_DO1(buf,i) s1 += buf[i]; s2 += s1 +#define LZO_DO2(buf,i) LZO_DO1(buf,i); LZO_DO1(buf,i+1); +#define LZO_DO4(buf,i) LZO_DO2(buf,i); LZO_DO2(buf,i+2); +#define LZO_DO8(buf,i) LZO_DO4(buf,i); LZO_DO4(buf,i+4); +#define LZO_DO16(buf,i) LZO_DO8(buf,i); LZO_DO8(buf,i+8); + +LZO_PUBLIC(lzo_uint32) +lzo_adler32(lzo_uint32 adler, const lzo_bytep buf, lzo_uint len) +{ + lzo_uint32 s1 = adler & 0xffff; + lzo_uint32 s2 = (adler >> 16) & 0xffff; + unsigned k; + + if (buf == NULL) + return 1; + + while (len > 0) + { + k = len < LZO_NMAX ? (unsigned) len : LZO_NMAX; + len -= k; + if (k >= 16) do + { + LZO_DO16(buf,0); + buf += 16; + k -= 16; + } while (k >= 16); + if (k != 0) do + { + s1 += *buf++; + s2 += s1; + } while (--k > 0); + s1 %= LZO_BASE; + s2 %= LZO_BASE; + } + return (s2 << 16) | s1; +} + +#undef LZO_DO1 +#undef LZO_DO2 +#undef LZO_DO4 +#undef LZO_DO8 +#undef LZO_DO16 + +#if !defined(MINILZO_CFG_SKIP_LZO_STRING) +#undef lzo_memcmp +#undef lzo_memcpy +#undef lzo_memmove +#undef lzo_memset +#if !defined(__LZO_MMODEL_HUGE) +# undef LZO_HAVE_MM_HUGE_PTR +#endif +#define lzo_hsize_t lzo_uint +#define lzo_hvoid_p lzo_voidp +#define lzo_hbyte_p lzo_bytep +#define LZOLIB_PUBLIC(r,f) LZO_PUBLIC(r) f +#define lzo_hmemcmp lzo_memcmp +#define lzo_hmemcpy lzo_memcpy +#define lzo_hmemmove lzo_memmove +#define lzo_hmemset lzo_memset +#define __LZOLIB_HMEMCPY_CH_INCLUDED 1 +#if !defined(LZOLIB_PUBLIC) +# define LZOLIB_PUBLIC(r,f) r __LZOLIB_FUNCNAME(f) +#endif +LZOLIB_PUBLIC(int, lzo_hmemcmp) (const lzo_hvoid_p s1, const lzo_hvoid_p s2, lzo_hsize_t len) +{ +#if (LZO_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMCMP) + const lzo_hbyte_p p1 = (const lzo_hbyte_p) s1; + const lzo_hbyte_p p2 = (const lzo_hbyte_p) s2; + if __lzo_likely(len > 0) do + { + int d = *p1 - *p2; + if (d != 0) + return d; + p1++; p2++; + } while __lzo_likely(--len > 0); + return 0; +#else + return memcmp(s1, s2, len); +#endif +} +LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemcpy) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len) +{ +#if (LZO_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMCPY) + lzo_hbyte_p p1 = (lzo_hbyte_p) dest; + const lzo_hbyte_p p2 = (const lzo_hbyte_p) src; + if (!(len > 0) || p1 == p2) + return dest; + do + *p1++ = *p2++; + while __lzo_likely(--len > 0); + return dest; +#else + return memcpy(dest, src, len); +#endif +} +LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemmove) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len) +{ +#if (LZO_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMMOVE) + lzo_hbyte_p p1 = (lzo_hbyte_p) dest; + const lzo_hbyte_p p2 = (const lzo_hbyte_p) src; + if (!(len > 0) || p1 == p2) + return dest; + if (p1 < p2) + { + do + *p1++ = *p2++; + while __lzo_likely(--len > 0); + } + else + { + p1 += len; + p2 += len; + do + *--p1 = *--p2; + while __lzo_likely(--len > 0); + } + return dest; +#else + return memmove(dest, src, len); +#endif +} +LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemset) (lzo_hvoid_p s, int c, lzo_hsize_t len) +{ +#if (LZO_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMSET) + lzo_hbyte_p p = (lzo_hbyte_p) s; + if __lzo_likely(len > 0) do + *p++ = (unsigned char) c; + while __lzo_likely(--len > 0); + return s; +#else + return memset(s, c, len); +#endif +} +#undef LZOLIB_PUBLIC +#endif + +#if !defined(__LZO_IN_MINILZO) + +#define ACC_WANT_ACC_CHK_CH 1 +#undef ACCCHK_ASSERT + + ACCCHK_ASSERT_IS_SIGNED_T(lzo_int) + ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint) + + ACCCHK_ASSERT_IS_SIGNED_T(lzo_int32) + ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint32) + ACCCHK_ASSERT((LZO_UINT32_C(1) << (int)(8*sizeof(LZO_UINT32_C(1))-1)) > 0) + ACCCHK_ASSERT(sizeof(lzo_uint32) >= 4) + +#if !defined(__LZO_UINTPTR_T_IS_POINTER) + ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uintptr_t) +#endif + ACCCHK_ASSERT(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp)) + + ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_xint) + ACCCHK_ASSERT(sizeof(lzo_xint) >= sizeof(lzo_uint32)) + ACCCHK_ASSERT(sizeof(lzo_xint) >= sizeof(lzo_uint)) + ACCCHK_ASSERT(sizeof(lzo_xint) == sizeof(lzo_uint32) || sizeof(lzo_xint) == sizeof(lzo_uint)) + +#endif +#undef ACCCHK_ASSERT + +LZO_PUBLIC(int) +_lzo_config_check(void) +{ + lzo_bool r = 1; + union { unsigned char c[2*sizeof(lzo_xint)]; lzo_xint l[2]; } u; + lzo_uintptr_t p; + +#if !defined(LZO_CFG_NO_CONFIG_CHECK) +#if defined(LZO_ABI_BIG_ENDIAN) + u.l[0] = u.l[1] = 0; u.c[sizeof(lzo_xint) - 1] = 128; + r &= (u.l[0] == 128); +#endif +#if defined(LZO_ABI_LITTLE_ENDIAN) + u.l[0] = u.l[1] = 0; u.c[0] = 128; + r &= (u.l[0] == 128); +#endif +#if defined(LZO_UNALIGNED_OK_2) + p = (lzo_uintptr_t) (const lzo_voidp) &u.c[0]; + u.l[0] = u.l[1] = 0; + r &= ((* (const lzo_ushortp) (p+1)) == 0); +#endif +#if defined(LZO_UNALIGNED_OK_4) + p = (lzo_uintptr_t) (const lzo_voidp) &u.c[0]; + u.l[0] = u.l[1] = 0; + r &= ((* (const lzo_uint32p) (p+1)) == 0); +#endif +#endif + + LZO_UNUSED(u); LZO_UNUSED(p); + return r == 1 ? LZO_E_OK : LZO_E_ERROR; +} + +int __lzo_init_done = 0; + +LZO_PUBLIC(int) +__lzo_init_v2(unsigned v, int s1, int s2, int s3, int s4, int s5, + int s6, int s7, int s8, int s9) +{ + int r; + +#if defined(__LZO_IN_MINILZO) +#elif (LZO_CC_MSC && ((_MSC_VER) < 700)) +#else +#define ACC_WANT_ACC_CHK_CH 1 +#undef ACCCHK_ASSERT +#define ACCCHK_ASSERT(expr) LZO_COMPILE_TIME_ASSERT(expr) +#endif +#undef ACCCHK_ASSERT + + __lzo_init_done = 1; + + if (v == 0) + return LZO_E_ERROR; + + r = (s1 == -1 || s1 == (int) sizeof(short)) && + (s2 == -1 || s2 == (int) sizeof(int)) && + (s3 == -1 || s3 == (int) sizeof(long)) && + (s4 == -1 || s4 == (int) sizeof(lzo_uint32)) && + (s5 == -1 || s5 == (int) sizeof(lzo_uint)) && + (s6 == -1 || s6 == (int) lzo_sizeof_dict_t) && + (s7 == -1 || s7 == (int) sizeof(char *)) && + (s8 == -1 || s8 == (int) sizeof(lzo_voidp)) && + (s9 == -1 || s9 == (int) sizeof(lzo_callback_t)); + if (!r) + return LZO_E_ERROR; + + r = _lzo_config_check(); + if (r != LZO_E_OK) + return r; + + return r; +} + +#if !defined(__LZO_IN_MINILZO) + +#if (LZO_OS_WIN16 && LZO_CC_WATCOMC) && defined(__SW_BD) + +#if 0 +BOOL FAR PASCAL LibMain ( HANDLE hInstance, WORD wDataSegment, + WORD wHeapSize, LPSTR lpszCmdLine ) +#else +int __far __pascal LibMain ( int a, short b, short c, long d ) +#endif +{ + LZO_UNUSED(a); LZO_UNUSED(b); LZO_UNUSED(c); LZO_UNUSED(d); + return 1; +} + +#endif + +#endif + +#define do_compress _lzo1x_1_do_compress + +#if !defined(MINILZO_CFG_SKIP_LZO1X_1_COMPRESS) + +#define LZO_NEED_DICT_H +#define D_BITS 14 +#define D_INDEX1(d,p) d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5) +#define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f) + +#ifndef __LZO_CONFIG1X_H +#define __LZO_CONFIG1X_H + +#if !defined(LZO1X) && !defined(LZO1Y) && !defined(LZO1Z) +# define LZO1X +#endif + +#if !defined(__LZO_IN_MINILZO) +#include "lzo/lzo1x.h" +#endif + +#define LZO_EOF_CODE +#undef LZO_DETERMINISTIC + +#define M1_MAX_OFFSET 0x0400 +#ifndef M2_MAX_OFFSET +#define M2_MAX_OFFSET 0x0800 +#endif +#define M3_MAX_OFFSET 0x4000 +#define M4_MAX_OFFSET 0xbfff + +#define MX_MAX_OFFSET (M1_MAX_OFFSET + M2_MAX_OFFSET) + +#define M1_MIN_LEN 2 +#define M1_MAX_LEN 2 +#define M2_MIN_LEN 3 +#ifndef M2_MAX_LEN +#define M2_MAX_LEN 8 +#endif +#define M3_MIN_LEN 3 +#define M3_MAX_LEN 33 +#define M4_MIN_LEN 3 +#define M4_MAX_LEN 9 + +#define M1_MARKER 0 +#define M2_MARKER 64 +#define M3_MARKER 32 +#define M4_MARKER 16 + +#ifndef MIN_LOOKAHEAD +#define MIN_LOOKAHEAD (M2_MAX_LEN + 1) +#endif + +#if defined(LZO_NEED_DICT_H) + +#ifndef LZO_HASH +#define LZO_HASH LZO_HASH_LZO_INCREMENTAL_B +#endif +#define DL_MIN_LEN M2_MIN_LEN + +#ifndef __LZO_DICT_H +#define __LZO_DICT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(D_BITS) && defined(DBITS) +# define D_BITS DBITS +#endif +#if !defined(D_BITS) +# error "D_BITS is not defined" +#endif +#if (D_BITS < 16) +# define D_SIZE LZO_SIZE(D_BITS) +# define D_MASK LZO_MASK(D_BITS) +#else +# define D_SIZE LZO_USIZE(D_BITS) +# define D_MASK LZO_UMASK(D_BITS) +#endif +#define D_HIGH ((D_MASK >> 1) + 1) + +#if !defined(DD_BITS) +# define DD_BITS 0 +#endif +#define DD_SIZE LZO_SIZE(DD_BITS) +#define DD_MASK LZO_MASK(DD_BITS) + +#if !defined(DL_BITS) +# define DL_BITS (D_BITS - DD_BITS) +#endif +#if (DL_BITS < 16) +# define DL_SIZE LZO_SIZE(DL_BITS) +# define DL_MASK LZO_MASK(DL_BITS) +#else +# define DL_SIZE LZO_USIZE(DL_BITS) +# define DL_MASK LZO_UMASK(DL_BITS) +#endif + +#if (D_BITS != DL_BITS + DD_BITS) +# error "D_BITS does not match" +#endif +#if (D_BITS < 8 || D_BITS > 18) +# error "invalid D_BITS" +#endif +#if (DL_BITS < 8 || DL_BITS > 20) +# error "invalid DL_BITS" +#endif +#if (DD_BITS < 0 || DD_BITS > 6) +# error "invalid DD_BITS" +#endif + +#if !defined(DL_MIN_LEN) +# define DL_MIN_LEN 3 +#endif +#if !defined(DL_SHIFT) +# define DL_SHIFT ((DL_BITS + (DL_MIN_LEN - 1)) / DL_MIN_LEN) +#endif + +#define LZO_HASH_GZIP 1 +#define LZO_HASH_GZIP_INCREMENTAL 2 +#define LZO_HASH_LZO_INCREMENTAL_A 3 +#define LZO_HASH_LZO_INCREMENTAL_B 4 + +#if !defined(LZO_HASH) +# error "choose a hashing strategy" +#endif + +#undef DM +#undef DX + +#if (DL_MIN_LEN == 3) +# define _DV2_A(p,shift1,shift2) \ + (((( (lzo_xint)((p)[0]) << shift1) ^ (p)[1]) << shift2) ^ (p)[2]) +# define _DV2_B(p,shift1,shift2) \ + (((( (lzo_xint)((p)[2]) << shift1) ^ (p)[1]) << shift2) ^ (p)[0]) +# define _DV3_B(p,shift1,shift2,shift3) \ + ((_DV2_B((p)+1,shift1,shift2) << (shift3)) ^ (p)[0]) +#elif (DL_MIN_LEN == 2) +# define _DV2_A(p,shift1,shift2) \ + (( (lzo_xint)(p[0]) << shift1) ^ p[1]) +# define _DV2_B(p,shift1,shift2) \ + (( (lzo_xint)(p[1]) << shift1) ^ p[2]) +#else +# error "invalid DL_MIN_LEN" +#endif +#define _DV_A(p,shift) _DV2_A(p,shift,shift) +#define _DV_B(p,shift) _DV2_B(p,shift,shift) +#define DA2(p,s1,s2) \ + (((((lzo_xint)((p)[2]) << (s2)) + (p)[1]) << (s1)) + (p)[0]) +#define DS2(p,s1,s2) \ + (((((lzo_xint)((p)[2]) << (s2)) - (p)[1]) << (s1)) - (p)[0]) +#define DX2(p,s1,s2) \ + (((((lzo_xint)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0]) +#define DA3(p,s1,s2,s3) ((DA2((p)+1,s2,s3) << (s1)) + (p)[0]) +#define DS3(p,s1,s2,s3) ((DS2((p)+1,s2,s3) << (s1)) - (p)[0]) +#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0]) +#define DMS(v,s) ((lzo_uint) (((v) & (D_MASK >> (s))) << (s))) +#define DM(v) DMS(v,0) + +#if (LZO_HASH == LZO_HASH_GZIP) +# define _DINDEX(dv,p) (_DV_A((p),DL_SHIFT)) + +#elif (LZO_HASH == LZO_HASH_GZIP_INCREMENTAL) +# define __LZO_HASH_INCREMENTAL +# define DVAL_FIRST(dv,p) dv = _DV_A((p),DL_SHIFT) +# define DVAL_NEXT(dv,p) dv = (((dv) << DL_SHIFT) ^ p[2]) +# define _DINDEX(dv,p) (dv) +# define DVAL_LOOKAHEAD DL_MIN_LEN + +#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_A) +# define __LZO_HASH_INCREMENTAL +# define DVAL_FIRST(dv,p) dv = _DV_A((p),5) +# define DVAL_NEXT(dv,p) \ + dv ^= (lzo_xint)(p[-1]) << (2*5); dv = (((dv) << 5) ^ p[2]) +# define _DINDEX(dv,p) ((DMUL(0x9f5f,dv)) >> 5) +# define DVAL_LOOKAHEAD DL_MIN_LEN + +#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_B) +# define __LZO_HASH_INCREMENTAL +# define DVAL_FIRST(dv,p) dv = _DV_B((p),5) +# define DVAL_NEXT(dv,p) \ + dv ^= p[-1]; dv = (((dv) >> 5) ^ ((lzo_xint)(p[2]) << (2*5))) +# define _DINDEX(dv,p) ((DMUL(0x9f5f,dv)) >> 5) +# define DVAL_LOOKAHEAD DL_MIN_LEN + +#else +# error "choose a hashing strategy" +#endif + +#ifndef DINDEX +#define DINDEX(dv,p) ((lzo_uint)((_DINDEX(dv,p)) & DL_MASK) << DD_BITS) +#endif +#if !defined(DINDEX1) && defined(D_INDEX1) +#define DINDEX1 D_INDEX1 +#endif +#if !defined(DINDEX2) && defined(D_INDEX2) +#define DINDEX2 D_INDEX2 +#endif + +#if !defined(__LZO_HASH_INCREMENTAL) +# define DVAL_FIRST(dv,p) ((void) 0) +# define DVAL_NEXT(dv,p) ((void) 0) +# define DVAL_LOOKAHEAD 0 +#endif + +#if !defined(DVAL_ASSERT) +#if defined(__LZO_HASH_INCREMENTAL) && !defined(NDEBUG) +static void DVAL_ASSERT(lzo_xint dv, const lzo_bytep p) +{ + lzo_xint df; + DVAL_FIRST(df,(p)); + assert(DINDEX(dv,p) == DINDEX(df,p)); +} +#else +# define DVAL_ASSERT(dv,p) ((void) 0) +#endif +#endif + +#if defined(LZO_DICT_USE_PTR) +# define DENTRY(p,in) (p) +# define GINDEX(m_pos,m_off,dict,dindex,in) m_pos = dict[dindex] +#else +# define DENTRY(p,in) ((lzo_uint) ((p)-(in))) +# define GINDEX(m_pos,m_off,dict,dindex,in) m_off = dict[dindex] +#endif + +#if (DD_BITS == 0) + +# define UPDATE_D(dict,drun,dv,p,in) dict[ DINDEX(dv,p) ] = DENTRY(p,in) +# define UPDATE_I(dict,drun,index,p,in) dict[index] = DENTRY(p,in) +# define UPDATE_P(ptr,drun,p,in) (ptr)[0] = DENTRY(p,in) + +#else + +# define UPDATE_D(dict,drun,dv,p,in) \ + dict[ DINDEX(dv,p) + drun++ ] = DENTRY(p,in); drun &= DD_MASK +# define UPDATE_I(dict,drun,index,p,in) \ + dict[ (index) + drun++ ] = DENTRY(p,in); drun &= DD_MASK +# define UPDATE_P(ptr,drun,p,in) \ + (ptr) [ drun++ ] = DENTRY(p,in); drun &= DD_MASK + +#endif + +#if defined(LZO_DICT_USE_PTR) + +#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \ + (m_pos == NULL || (m_off = pd(ip, m_pos)) > max_offset) + +#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \ + (BOUNDS_CHECKING_OFF_IN_EXPR(( \ + m_pos = ip - (lzo_uint) PTR_DIFF(ip,m_pos), \ + PTR_LT(m_pos,in) || \ + (m_off = (lzo_uint) PTR_DIFF(ip,m_pos)) <= 0 || \ + m_off > max_offset ))) + +#else + +#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \ + (m_off == 0 || \ + ((m_off = pd(ip, in) - m_off) > max_offset) || \ + (m_pos = (ip) - (m_off), 0) ) + +#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \ + (pd(ip, in) <= m_off || \ + ((m_off = pd(ip, in) - m_off) > max_offset) || \ + (m_pos = (ip) - (m_off), 0) ) + +#endif + +#if defined(LZO_DETERMINISTIC) +# define LZO_CHECK_MPOS LZO_CHECK_MPOS_DET +#else +# define LZO_CHECK_MPOS LZO_CHECK_MPOS_NON_DET +#endif + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +#endif + +#define DO_COMPRESS lzo1x_1_compress + +static __lzo_noinline lzo_uint +do_compress ( const lzo_bytep in , lzo_uint in_len, + lzo_bytep out, lzo_uintp out_len, + lzo_voidp wrkmem ) +{ + register const lzo_bytep ip; + lzo_bytep op; + const lzo_bytep const in_end = in + in_len; + const lzo_bytep const ip_end = in + in_len - M2_MAX_LEN - 5; + const lzo_bytep ii; + lzo_dict_p const dict = (lzo_dict_p) wrkmem; + + op = out; + ip = in; + ii = ip; + + ip += 4; + for (;;) + { + register const lzo_bytep m_pos; + lzo_uint m_off; + lzo_uint m_len; + lzo_uint dindex; + + DINDEX1(dindex,ip); + GINDEX(m_pos,m_off,dict,dindex,in); + if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) + goto literal; +#if 1 + if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) + goto try_match; + DINDEX2(dindex,ip); +#endif + GINDEX(m_pos,m_off,dict,dindex,in); + if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) + goto literal; + if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) + goto try_match; + goto literal; + +try_match: +#if 1 && defined(LZO_UNALIGNED_OK_2) + if (* (const lzo_ushortp) m_pos != * (const lzo_ushortp) ip) +#else + if (m_pos[0] != ip[0] || m_pos[1] != ip[1]) +#endif + { + } + else + { + if __lzo_likely(m_pos[2] == ip[2]) + { +#if 0 + if (m_off <= M2_MAX_OFFSET) + goto match; + if (lit <= 3) + goto match; + if (lit == 3) + { + assert(op - 2 > out); op[-2] |= LZO_BYTE(3); + *op++ = *ii++; *op++ = *ii++; *op++ = *ii++; + goto code_match; + } + if (m_pos[3] == ip[3]) +#endif + goto match; + } + else + { +#if 0 +#if 0 + if (m_off <= M1_MAX_OFFSET && lit > 0 && lit <= 3) +#else + if (m_off <= M1_MAX_OFFSET && lit == 3) +#endif + { + register lzo_uint t; + + t = lit; + assert(op - 2 > out); op[-2] |= LZO_BYTE(t); + do *op++ = *ii++; while (--t > 0); + assert(ii == ip); + m_off -= 1; + *op++ = LZO_BYTE(M1_MARKER | ((m_off & 3) << 2)); + *op++ = LZO_BYTE(m_off >> 2); + ip += 2; + goto match_done; + } +#endif + } + } + +literal: + UPDATE_I(dict,0,dindex,ip,in); + ++ip; + if __lzo_unlikely(ip >= ip_end) + break; + continue; + +match: + UPDATE_I(dict,0,dindex,ip,in); + if (pd(ip,ii) > 0) + { + register lzo_uint t = pd(ip,ii); + + if (t <= 3) + { + assert(op - 2 > out); + op[-2] |= LZO_BYTE(t); + } + else if (t <= 18) + *op++ = LZO_BYTE(t - 3); + else + { + register lzo_uint tt = t - 18; + + *op++ = 0; + while (tt > 255) + { + tt -= 255; + *op++ = 0; + } + assert(tt > 0); + *op++ = LZO_BYTE(tt); + } + do *op++ = *ii++; while (--t > 0); + } + + assert(ii == ip); + ip += 3; + if (m_pos[3] != *ip++ || m_pos[4] != *ip++ || m_pos[5] != *ip++ || + m_pos[6] != *ip++ || m_pos[7] != *ip++ || m_pos[8] != *ip++ +#ifdef LZO1Y + || m_pos[ 9] != *ip++ || m_pos[10] != *ip++ || m_pos[11] != *ip++ + || m_pos[12] != *ip++ || m_pos[13] != *ip++ || m_pos[14] != *ip++ +#endif + ) + { + --ip; + m_len = pd(ip, ii); + assert(m_len >= 3); assert(m_len <= M2_MAX_LEN); + + if (m_off <= M2_MAX_OFFSET) + { + m_off -= 1; +#if defined(LZO1X) + *op++ = LZO_BYTE(((m_len - 1) << 5) | ((m_off & 7) << 2)); + *op++ = LZO_BYTE(m_off >> 3); +#elif defined(LZO1Y) + *op++ = LZO_BYTE(((m_len + 1) << 4) | ((m_off & 3) << 2)); + *op++ = LZO_BYTE(m_off >> 2); +#endif + } + else if (m_off <= M3_MAX_OFFSET) + { + m_off -= 1; + *op++ = LZO_BYTE(M3_MARKER | (m_len - 2)); + goto m3_m4_offset; + } + else +#if defined(LZO1X) + { + m_off -= 0x4000; + assert(m_off > 0); assert(m_off <= 0x7fff); + *op++ = LZO_BYTE(M4_MARKER | + ((m_off & 0x4000) >> 11) | (m_len - 2)); + goto m3_m4_offset; + } +#elif defined(LZO1Y) + goto m4_match; +#endif + } + else + { + { + const lzo_bytep end = in_end; + const lzo_bytep m = m_pos + M2_MAX_LEN + 1; + while (ip < end && *m == *ip) + m++, ip++; + m_len = pd(ip, ii); + } + assert(m_len > M2_MAX_LEN); + + if (m_off <= M3_MAX_OFFSET) + { + m_off -= 1; + if (m_len <= 33) + *op++ = LZO_BYTE(M3_MARKER | (m_len - 2)); + else + { + m_len -= 33; + *op++ = M3_MARKER | 0; + goto m3_m4_len; + } + } + else + { +#if defined(LZO1Y) +m4_match: +#endif + m_off -= 0x4000; + assert(m_off > 0); assert(m_off <= 0x7fff); + if (m_len <= M4_MAX_LEN) + *op++ = LZO_BYTE(M4_MARKER | + ((m_off & 0x4000) >> 11) | (m_len - 2)); + else + { + m_len -= M4_MAX_LEN; + *op++ = LZO_BYTE(M4_MARKER | ((m_off & 0x4000) >> 11)); +m3_m4_len: + while (m_len > 255) + { + m_len -= 255; + *op++ = 0; + } + assert(m_len > 0); + *op++ = LZO_BYTE(m_len); + } + } + +m3_m4_offset: + *op++ = LZO_BYTE((m_off & 63) << 2); + *op++ = LZO_BYTE(m_off >> 6); + } + +#if 0 +match_done: +#endif + ii = ip; + if __lzo_unlikely(ip >= ip_end) + break; + } + + *out_len = pd(op, out); + return pd(in_end,ii); +} + +LZO_PUBLIC(int) +DO_COMPRESS ( const lzo_bytep in , lzo_uint in_len, + lzo_bytep out, lzo_uintp out_len, + lzo_voidp wrkmem ) +{ + lzo_bytep op = out; + lzo_uint t; + + if __lzo_unlikely(in_len <= M2_MAX_LEN + 5) + t = in_len; + else + { + t = do_compress(in,in_len,op,out_len,wrkmem); + op += *out_len; + } + + if (t > 0) + { + const lzo_bytep ii = in + in_len - t; + + if (op == out && t <= 238) + *op++ = LZO_BYTE(17 + t); + else if (t <= 3) + op[-2] |= LZO_BYTE(t); + else if (t <= 18) + *op++ = LZO_BYTE(t - 3); + else + { + lzo_uint tt = t - 18; + + *op++ = 0; + while (tt > 255) + { + tt -= 255; + *op++ = 0; + } + assert(tt > 0); + *op++ = LZO_BYTE(tt); + } + do *op++ = *ii++; while (--t > 0); + } + + *op++ = M4_MARKER | 1; + *op++ = 0; + *op++ = 0; + + *out_len = pd(op, out); + return LZO_E_OK; +} + +#endif + +#undef do_compress +#undef DO_COMPRESS +#undef LZO_HASH + +#undef LZO_TEST_OVERRUN +#undef DO_DECOMPRESS +#define DO_DECOMPRESS lzo1x_decompress + +#if !defined(MINILZO_CFG_SKIP_LZO1X_DECOMPRESS) + +#if defined(LZO_TEST_OVERRUN) +# if !defined(LZO_TEST_OVERRUN_INPUT) +# define LZO_TEST_OVERRUN_INPUT 2 +# endif +# if !defined(LZO_TEST_OVERRUN_OUTPUT) +# define LZO_TEST_OVERRUN_OUTPUT 2 +# endif +# if !defined(LZO_TEST_OVERRUN_LOOKBEHIND) +# define LZO_TEST_OVERRUN_LOOKBEHIND +# endif +#endif + +#undef TEST_IP +#undef TEST_OP +#undef TEST_LB +#undef TEST_LBO +#undef NEED_IP +#undef NEED_OP +#undef HAVE_TEST_IP +#undef HAVE_TEST_OP +#undef HAVE_NEED_IP +#undef HAVE_NEED_OP +#undef HAVE_ANY_IP +#undef HAVE_ANY_OP + +#if defined(LZO_TEST_OVERRUN_INPUT) +# if (LZO_TEST_OVERRUN_INPUT >= 1) +# define TEST_IP (ip < ip_end) +# endif +# if (LZO_TEST_OVERRUN_INPUT >= 2) +# define NEED_IP(x) \ + if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x)) goto input_overrun +# endif +#endif + +#if defined(LZO_TEST_OVERRUN_OUTPUT) +# if (LZO_TEST_OVERRUN_OUTPUT >= 1) +# define TEST_OP (op <= op_end) +# endif +# if (LZO_TEST_OVERRUN_OUTPUT >= 2) +# undef TEST_OP +# define NEED_OP(x) \ + if ((lzo_uint)(op_end - op) < (lzo_uint)(x)) goto output_overrun +# endif +#endif + +#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) +# define TEST_LB(m_pos) if (m_pos < out || m_pos >= op) goto lookbehind_overrun +# define TEST_LBO(m_pos,o) if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun +#else +# define TEST_LB(m_pos) ((void) 0) +# define TEST_LBO(m_pos,o) ((void) 0) +#endif + +#if !defined(LZO_EOF_CODE) && !defined(TEST_IP) +# define TEST_IP (ip < ip_end) +#endif + +#if defined(TEST_IP) +# define HAVE_TEST_IP +#else +# define TEST_IP 1 +#endif +#if defined(TEST_OP) +# define HAVE_TEST_OP +#else +# define TEST_OP 1 +#endif + +#if defined(NEED_IP) +# define HAVE_NEED_IP +#else +# define NEED_IP(x) ((void) 0) +#endif +#if defined(NEED_OP) +# define HAVE_NEED_OP +#else +# define NEED_OP(x) ((void) 0) +#endif + +#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP) +# define HAVE_ANY_IP +#endif +#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP) +# define HAVE_ANY_OP +#endif + +#undef __COPY4 +#define __COPY4(dst,src) * (lzo_uint32p)(dst) = * (const lzo_uint32p)(src) + +#undef COPY4 +#if defined(LZO_UNALIGNED_OK_4) +# define COPY4(dst,src) __COPY4(dst,src) +#elif defined(LZO_ALIGNED_OK_4) +# define COPY4(dst,src) __COPY4((lzo_uintptr_t)(dst),(lzo_uintptr_t)(src)) +#endif + +#if defined(DO_DECOMPRESS) +LZO_PUBLIC(int) +DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len, + lzo_bytep out, lzo_uintp out_len, + lzo_voidp wrkmem ) +#endif +{ + register lzo_bytep op; + register const lzo_bytep ip; + register lzo_uint t; +#if defined(COPY_DICT) + lzo_uint m_off; + const lzo_bytep dict_end; +#else + register const lzo_bytep m_pos; +#endif + + const lzo_bytep const ip_end = in + in_len; +#if defined(HAVE_ANY_OP) + lzo_bytep const op_end = out + *out_len; +#endif +#if defined(LZO1Z) + lzo_uint last_m_off = 0; +#endif + + LZO_UNUSED(wrkmem); + +#if defined(COPY_DICT) + if (dict) + { + if (dict_len > M4_MAX_OFFSET) + { + dict += dict_len - M4_MAX_OFFSET; + dict_len = M4_MAX_OFFSET; + } + dict_end = dict + dict_len; + } + else + { + dict_len = 0; + dict_end = NULL; + } +#endif + + *out_len = 0; + + op = out; + ip = in; + + if (*ip > 17) + { + t = *ip++ - 17; + if (t < 4) + goto match_next; + assert(t > 0); NEED_OP(t); NEED_IP(t+1); + do *op++ = *ip++; while (--t > 0); + goto first_literal_run; + } + + while (TEST_IP && TEST_OP) + { + t = *ip++; + if (t >= 16) + goto match; + if (t == 0) + { + NEED_IP(1); + while (*ip == 0) + { + t += 255; + ip++; + NEED_IP(1); + } + t += 15 + *ip++; + } + assert(t > 0); NEED_OP(t+3); NEED_IP(t+4); +#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +#if !defined(LZO_UNALIGNED_OK_4) + if (PTR_ALIGNED2_4(op,ip)) + { +#endif + COPY4(op,ip); + op += 4; ip += 4; + if (--t > 0) + { + if (t >= 4) + { + do { + COPY4(op,ip); + op += 4; ip += 4; t -= 4; + } while (t >= 4); + if (t > 0) do *op++ = *ip++; while (--t > 0); + } + else + do *op++ = *ip++; while (--t > 0); + } +#if !defined(LZO_UNALIGNED_OK_4) + } + else +#endif +#endif +#if !defined(LZO_UNALIGNED_OK_4) + { + *op++ = *ip++; *op++ = *ip++; *op++ = *ip++; + do *op++ = *ip++; while (--t > 0); + } +#endif + +first_literal_run: + + t = *ip++; + if (t >= 16) + goto match; +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(3); + t = 3; COPY_DICT(t,m_off) +#else +#if defined(LZO1Z) + t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - (1 + M2_MAX_OFFSET); + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LB(m_pos); NEED_OP(3); + *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos; +#endif + goto match_done; + + do { +match: + if (t >= 64) + { +#if defined(COPY_DICT) +#if defined(LZO1X) + m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3); + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2); + t = (t >> 4) - 3; +#elif defined(LZO1Z) + m_off = t & 0x1f; + if (m_off >= 0x1c) + m_off = last_m_off; + else + { + m_off = 1 + (m_off << 6) + (*ip++ >> 2); + last_m_off = m_off; + } + t = (t >> 5) - 1; +#endif +#else +#if defined(LZO1X) + m_pos = op - 1; + m_pos -= (t >> 2) & 7; + m_pos -= *ip++ << 3; + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_pos = op - 1; + m_pos -= (t >> 2) & 3; + m_pos -= *ip++ << 2; + t = (t >> 4) - 3; +#elif defined(LZO1Z) + { + lzo_uint off = t & 0x1f; + m_pos = op; + if (off >= 0x1c) + { + assert(last_m_off > 0); + m_pos -= last_m_off; + } + else + { + off = 1 + (off << 6) + (*ip++ >> 2); + m_pos -= off; + last_m_off = off; + } + } + t = (t >> 5) - 1; +#endif + TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); + goto copy_match; +#endif + } + else if (t >= 32) + { + t &= 31; + if (t == 0) + { + NEED_IP(1); + while (*ip == 0) + { + t += 255; + ip++; + NEED_IP(1); + } + t += 31 + *ip++; + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (ip[0] << 6) + (ip[1] >> 2); + last_m_off = m_off; +#else + m_off = 1 + (ip[0] >> 2) + (ip[1] << 6); +#endif +#else +#if defined(LZO1Z) + { + lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2); + m_pos = op - off; + last_m_off = off; + } +#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) + m_pos = op - 1; + m_pos -= (* (const lzo_ushortp) ip) >> 2; +#else + m_pos = op - 1; + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif +#endif + ip += 2; + } + else if (t >= 16) + { +#if defined(COPY_DICT) + m_off = (t & 8) << 11; +#else + m_pos = op; + m_pos -= (t & 8) << 11; +#endif + t &= 7; + if (t == 0) + { + NEED_IP(1); + while (*ip == 0) + { + t += 255; + ip++; + NEED_IP(1); + } + t += 7 + *ip++; + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off += (ip[0] << 6) + (ip[1] >> 2); +#else + m_off += (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_off == 0) + goto eof_found; + m_off += 0x4000; +#if defined(LZO1Z) + last_m_off = m_off; +#endif +#else +#if defined(LZO1Z) + m_pos -= (ip[0] << 6) + (ip[1] >> 2); +#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) + m_pos -= (* (const lzo_ushortp) ip) >> 2; +#else + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_pos == op) + goto eof_found; + m_pos -= 0x4000; +#if defined(LZO1Z) + last_m_off = pd((const lzo_bytep)op, m_pos); +#endif +#endif + } + else + { +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = 1 + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(2); + t = 2; COPY_DICT(t,m_off) +#else +#if defined(LZO1Z) + t = 1 + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - 1; + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LB(m_pos); NEED_OP(2); + *op++ = *m_pos++; *op++ = *m_pos; +#endif + goto match_done; + } + +#if defined(COPY_DICT) + + NEED_OP(t+3-1); + t += 3-1; COPY_DICT(t,m_off) + +#else + + TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); +#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +#if !defined(LZO_UNALIGNED_OK_4) + if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) + { + assert((op - m_pos) >= 4); +#else + if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) + { +#endif + COPY4(op,m_pos); + op += 4; m_pos += 4; t -= 4 - (3 - 1); + do { + COPY4(op,m_pos); + op += 4; m_pos += 4; t -= 4; + } while (t >= 4); + if (t > 0) do *op++ = *m_pos++; while (--t > 0); + } + else +#endif + { +copy_match: + *op++ = *m_pos++; *op++ = *m_pos++; + do *op++ = *m_pos++; while (--t > 0); + } + +#endif + +match_done: +#if defined(LZO1Z) + t = ip[-1] & 3; +#else + t = ip[-2] & 3; +#endif + if (t == 0) + break; + +match_next: + assert(t > 0); assert(t < 4); NEED_OP(t); NEED_IP(t+1); +#if 0 + do *op++ = *ip++; while (--t > 0); +#else + *op++ = *ip++; + if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } } +#endif + t = *ip++; + } while (TEST_IP && TEST_OP); + } + +#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP) + *out_len = pd(op, out); + return LZO_E_EOF_NOT_FOUND; +#endif + +eof_found: + assert(t == 1); + *out_len = pd(op, out); + return (ip == ip_end ? LZO_E_OK : + (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); + +#if defined(HAVE_NEED_IP) +input_overrun: + *out_len = pd(op, out); + return LZO_E_INPUT_OVERRUN; +#endif + +#if defined(HAVE_NEED_OP) +output_overrun: + *out_len = pd(op, out); + return LZO_E_OUTPUT_OVERRUN; +#endif + +#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) +lookbehind_overrun: + *out_len = pd(op, out); + return LZO_E_LOOKBEHIND_OVERRUN; +#endif +} + +#endif + +#define LZO_TEST_OVERRUN +#undef DO_DECOMPRESS +#define DO_DECOMPRESS lzo1x_decompress_safe + +#if !defined(MINILZO_CFG_SKIP_LZO1X_DECOMPRESS_SAFE) + +#if defined(LZO_TEST_OVERRUN) +# if !defined(LZO_TEST_OVERRUN_INPUT) +# define LZO_TEST_OVERRUN_INPUT 2 +# endif +# if !defined(LZO_TEST_OVERRUN_OUTPUT) +# define LZO_TEST_OVERRUN_OUTPUT 2 +# endif +# if !defined(LZO_TEST_OVERRUN_LOOKBEHIND) +# define LZO_TEST_OVERRUN_LOOKBEHIND +# endif +#endif + +#undef TEST_IP +#undef TEST_OP +#undef TEST_LB +#undef TEST_LBO +#undef NEED_IP +#undef NEED_OP +#undef HAVE_TEST_IP +#undef HAVE_TEST_OP +#undef HAVE_NEED_IP +#undef HAVE_NEED_OP +#undef HAVE_ANY_IP +#undef HAVE_ANY_OP + +#if defined(LZO_TEST_OVERRUN_INPUT) +# if (LZO_TEST_OVERRUN_INPUT >= 1) +# define TEST_IP (ip < ip_end) +# endif +# if (LZO_TEST_OVERRUN_INPUT >= 2) +# define NEED_IP(x) \ + if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x)) goto input_overrun +# endif +#endif + +#if defined(LZO_TEST_OVERRUN_OUTPUT) +# if (LZO_TEST_OVERRUN_OUTPUT >= 1) +# define TEST_OP (op <= op_end) +# endif +# if (LZO_TEST_OVERRUN_OUTPUT >= 2) +# undef TEST_OP +# define NEED_OP(x) \ + if ((lzo_uint)(op_end - op) < (lzo_uint)(x)) goto output_overrun +# endif +#endif + +#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) +# define TEST_LB(m_pos) if (m_pos < out || m_pos >= op) goto lookbehind_overrun +# define TEST_LBO(m_pos,o) if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun +#else +# define TEST_LB(m_pos) ((void) 0) +# define TEST_LBO(m_pos,o) ((void) 0) +#endif + +#if !defined(LZO_EOF_CODE) && !defined(TEST_IP) +# define TEST_IP (ip < ip_end) +#endif + +#if defined(TEST_IP) +# define HAVE_TEST_IP +#else +# define TEST_IP 1 +#endif +#if defined(TEST_OP) +# define HAVE_TEST_OP +#else +# define TEST_OP 1 +#endif + +#if defined(NEED_IP) +# define HAVE_NEED_IP +#else +# define NEED_IP(x) ((void) 0) +#endif +#if defined(NEED_OP) +# define HAVE_NEED_OP +#else +# define NEED_OP(x) ((void) 0) +#endif + +#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP) +# define HAVE_ANY_IP +#endif +#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP) +# define HAVE_ANY_OP +#endif + +#undef __COPY4 +#define __COPY4(dst,src) * (lzo_uint32p)(dst) = * (const lzo_uint32p)(src) + +#undef COPY4 +#if defined(LZO_UNALIGNED_OK_4) +# define COPY4(dst,src) __COPY4(dst,src) +#elif defined(LZO_ALIGNED_OK_4) +# define COPY4(dst,src) __COPY4((lzo_uintptr_t)(dst),(lzo_uintptr_t)(src)) +#endif + +#if defined(DO_DECOMPRESS) +LZO_PUBLIC(int) +DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len, + lzo_bytep out, lzo_uintp out_len, + lzo_voidp wrkmem ) +#endif +{ + register lzo_bytep op; + register const lzo_bytep ip; + register lzo_uint t; +#if defined(COPY_DICT) + lzo_uint m_off; + const lzo_bytep dict_end; +#else + register const lzo_bytep m_pos; +#endif + + const lzo_bytep const ip_end = in + in_len; +#if defined(HAVE_ANY_OP) + lzo_bytep const op_end = out + *out_len; +#endif +#if defined(LZO1Z) + lzo_uint last_m_off = 0; +#endif + + LZO_UNUSED(wrkmem); + +#if defined(COPY_DICT) + if (dict) + { + if (dict_len > M4_MAX_OFFSET) + { + dict += dict_len - M4_MAX_OFFSET; + dict_len = M4_MAX_OFFSET; + } + dict_end = dict + dict_len; + } + else + { + dict_len = 0; + dict_end = NULL; + } +#endif + + *out_len = 0; + + op = out; + ip = in; + + if (*ip > 17) + { + t = *ip++ - 17; + if (t < 4) + goto match_next; + assert(t > 0); NEED_OP(t); NEED_IP(t+1); + do *op++ = *ip++; while (--t > 0); + goto first_literal_run; + } + + while (TEST_IP && TEST_OP) + { + t = *ip++; + if (t >= 16) + goto match; + if (t == 0) + { + NEED_IP(1); + while (*ip == 0) + { + t += 255; + ip++; + NEED_IP(1); + } + t += 15 + *ip++; + } + assert(t > 0); NEED_OP(t+3); NEED_IP(t+4); +#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +#if !defined(LZO_UNALIGNED_OK_4) + if (PTR_ALIGNED2_4(op,ip)) + { +#endif + COPY4(op,ip); + op += 4; ip += 4; + if (--t > 0) + { + if (t >= 4) + { + do { + COPY4(op,ip); + op += 4; ip += 4; t -= 4; + } while (t >= 4); + if (t > 0) do *op++ = *ip++; while (--t > 0); + } + else + do *op++ = *ip++; while (--t > 0); + } +#if !defined(LZO_UNALIGNED_OK_4) + } + else +#endif +#endif +#if !defined(LZO_UNALIGNED_OK_4) + { + *op++ = *ip++; *op++ = *ip++; *op++ = *ip++; + do *op++ = *ip++; while (--t > 0); + } +#endif + +first_literal_run: + + t = *ip++; + if (t >= 16) + goto match; +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(3); + t = 3; COPY_DICT(t,m_off) +#else +#if defined(LZO1Z) + t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - (1 + M2_MAX_OFFSET); + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LB(m_pos); NEED_OP(3); + *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos; +#endif + goto match_done; + + do { +match: + if (t >= 64) + { +#if defined(COPY_DICT) +#if defined(LZO1X) + m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3); + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2); + t = (t >> 4) - 3; +#elif defined(LZO1Z) + m_off = t & 0x1f; + if (m_off >= 0x1c) + m_off = last_m_off; + else + { + m_off = 1 + (m_off << 6) + (*ip++ >> 2); + last_m_off = m_off; + } + t = (t >> 5) - 1; +#endif +#else +#if defined(LZO1X) + m_pos = op - 1; + m_pos -= (t >> 2) & 7; + m_pos -= *ip++ << 3; + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_pos = op - 1; + m_pos -= (t >> 2) & 3; + m_pos -= *ip++ << 2; + t = (t >> 4) - 3; +#elif defined(LZO1Z) + { + lzo_uint off = t & 0x1f; + m_pos = op; + if (off >= 0x1c) + { + assert(last_m_off > 0); + m_pos -= last_m_off; + } + else + { + off = 1 + (off << 6) + (*ip++ >> 2); + m_pos -= off; + last_m_off = off; + } + } + t = (t >> 5) - 1; +#endif + TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); + goto copy_match; +#endif + } + else if (t >= 32) + { + t &= 31; + if (t == 0) + { + NEED_IP(1); + while (*ip == 0) + { + t += 255; + ip++; + NEED_IP(1); + } + t += 31 + *ip++; + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (ip[0] << 6) + (ip[1] >> 2); + last_m_off = m_off; +#else + m_off = 1 + (ip[0] >> 2) + (ip[1] << 6); +#endif +#else +#if defined(LZO1Z) + { + lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2); + m_pos = op - off; + last_m_off = off; + } +#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) + m_pos = op - 1; + m_pos -= (* (const lzo_ushortp) ip) >> 2; +#else + m_pos = op - 1; + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif +#endif + ip += 2; + } + else if (t >= 16) + { +#if defined(COPY_DICT) + m_off = (t & 8) << 11; +#else + m_pos = op; + m_pos -= (t & 8) << 11; +#endif + t &= 7; + if (t == 0) + { + NEED_IP(1); + while (*ip == 0) + { + t += 255; + ip++; + NEED_IP(1); + } + t += 7 + *ip++; + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off += (ip[0] << 6) + (ip[1] >> 2); +#else + m_off += (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_off == 0) + goto eof_found; + m_off += 0x4000; +#if defined(LZO1Z) + last_m_off = m_off; +#endif +#else +#if defined(LZO1Z) + m_pos -= (ip[0] << 6) + (ip[1] >> 2); +#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) + m_pos -= (* (const lzo_ushortp) ip) >> 2; +#else + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_pos == op) + goto eof_found; + m_pos -= 0x4000; +#if defined(LZO1Z) + last_m_off = pd((const lzo_bytep)op, m_pos); +#endif +#endif + } + else + { +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = 1 + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(2); + t = 2; COPY_DICT(t,m_off) +#else +#if defined(LZO1Z) + t = 1 + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - 1; + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LB(m_pos); NEED_OP(2); + *op++ = *m_pos++; *op++ = *m_pos; +#endif + goto match_done; + } + +#if defined(COPY_DICT) + + NEED_OP(t+3-1); + t += 3-1; COPY_DICT(t,m_off) + +#else + + TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); +#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +#if !defined(LZO_UNALIGNED_OK_4) + if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) + { + assert((op - m_pos) >= 4); +#else + if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) + { +#endif + COPY4(op,m_pos); + op += 4; m_pos += 4; t -= 4 - (3 - 1); + do { + COPY4(op,m_pos); + op += 4; m_pos += 4; t -= 4; + } while (t >= 4); + if (t > 0) do *op++ = *m_pos++; while (--t > 0); + } + else +#endif + { +copy_match: + *op++ = *m_pos++; *op++ = *m_pos++; + do *op++ = *m_pos++; while (--t > 0); + } + +#endif + +match_done: +#if defined(LZO1Z) + t = ip[-1] & 3; +#else + t = ip[-2] & 3; +#endif + if (t == 0) + break; + +match_next: + assert(t > 0); assert(t < 4); NEED_OP(t); NEED_IP(t+1); +#if 0 + do *op++ = *ip++; while (--t > 0); +#else + *op++ = *ip++; + if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } } +#endif + t = *ip++; + } while (TEST_IP && TEST_OP); + } + +#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP) + *out_len = pd(op, out); + return LZO_E_EOF_NOT_FOUND; +#endif + +eof_found: + assert(t == 1); + *out_len = pd(op, out); + return (ip == ip_end ? LZO_E_OK : + (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); + +#if defined(HAVE_NEED_IP) +input_overrun: + *out_len = pd(op, out); + return LZO_E_INPUT_OVERRUN; +#endif + +#if defined(HAVE_NEED_OP) +output_overrun: + *out_len = pd(op, out); + return LZO_E_OUTPUT_OVERRUN; +#endif + +#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) +lookbehind_overrun: + *out_len = pd(op, out); + return LZO_E_LOOKBEHIND_OVERRUN; +#endif +} + +#endif + +/***** End of minilzo.c *****/ + diff --git a/minilzo.h b/minilzo.h new file mode 100644 index 0000000..0aff50e --- /dev/null +++ b/minilzo.h @@ -0,0 +1,106 @@ +/* minilzo.h -- mini subset of the LZO real-time data compression library + + This file is part of the LZO real-time data compression library. + + Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + The LZO library 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. + + The LZO library 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 the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Markus F.X.J. Oberhumer + + http://www.oberhumer.com/opensource/lzo/ + */ + +/* + * NOTE: + * the full LZO package can be found at + * http://www.oberhumer.com/opensource/lzo/ + */ + + +#ifndef __MINILZO_H +#define __MINILZO_H + +#define MINILZO_VERSION 0x2030 + +#ifdef __LZOCONF_H +# error "you cannot use both LZO and miniLZO" +#endif + +#undef LZO_HAVE_CONFIG_H +#include "lzoconf.h" + +#if !defined(LZO_VERSION) || (LZO_VERSION != MINILZO_VERSION) +# error "version mismatch in header files" +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + + +/*********************************************************************** +// +************************************************************************/ + +/* Memory required for the wrkmem parameter. + * When the required size is 0, you can also pass a NULL pointer. + */ + +#define LZO1X_MEM_COMPRESS LZO1X_1_MEM_COMPRESS +#define LZO1X_1_MEM_COMPRESS ((lzo_uint32) (16384L * lzo_sizeof_dict_t)) +#define LZO1X_MEM_DECOMPRESS (0) + + +/* compression */ +LZO_EXTERN(int) +lzo1x_1_compress ( const lzo_bytep src, lzo_uint src_len, + lzo_bytep dst, lzo_uintp dst_len, + lzo_voidp wrkmem ); + +/* decompression */ +LZO_EXTERN(int) +lzo1x_decompress ( const lzo_bytep src, lzo_uint src_len, + lzo_bytep dst, lzo_uintp dst_len, + lzo_voidp wrkmem /* NOT USED */ ); + +/* safe decompression with overrun testing */ +LZO_EXTERN(int) +lzo1x_decompress_safe ( const lzo_bytep src, lzo_uint src_len, + lzo_bytep dst, lzo_uintp dst_len, + lzo_voidp wrkmem /* NOT USED */ ); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* already included */ + diff --git a/n2n.c b/n2n.c new file mode 100644 index 0000000..ac98ad6 --- /dev/null +++ b/n2n.c @@ -0,0 +1,455 @@ +/* + * (C) 2007-09 - Luca Deri + * Richard Andrews + * + * 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 3 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, see + * + * Code contributions courtesy of: + * Massimo Torquati + * Matt Gilg + * + */ + +#include "n2n.h" + +#include "minilzo.h" + +#include + +#if defined(DEBUG) +# define PURGE_REGISTRATION_FREQUENCY 60 +# define REGISTRATION_TIMEOUT 120 +#else /* #if defined(DEBUG) */ +# define PURGE_REGISTRATION_FREQUENCY 60 +# define REGISTRATION_TIMEOUT (60*20) +#endif /* #if defined(DEBUG) */ + + +const uint8_t broadcast_addr[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +const uint8_t multicast_addr[6] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0x00 }; /* First 3 bytes are meaningful */ +const uint8_t ipv6_multicast_addr[6] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 }; /* First 2 bytes are meaningful */ + +/* ************************************** */ + +SOCKET open_socket(int local_port, int bind_any) { + SOCKET sock_fd; + struct sockaddr_in local_address; + int sockopt = 1; + + if((sock_fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { + traceEvent(TRACE_ERROR, "Unable to create socket [%s][%d]\n", + strerror(errno), sock_fd); + return(-1); + } + +#ifndef WIN32 + /* fcntl(sock_fd, F_SETFL, O_NONBLOCK); */ +#endif + + setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&sockopt, sizeof(sockopt)); + + memset(&local_address, 0, sizeof(local_address)); + local_address.sin_family = AF_INET; + local_address.sin_port = htons(local_port); + local_address.sin_addr.s_addr = htonl(bind_any?INADDR_ANY:INADDR_LOOPBACK); + if(bind(sock_fd, (struct sockaddr*) &local_address, sizeof(local_address)) == -1) { + traceEvent(TRACE_ERROR, "Bind error [%s]\n", strerror(errno)); + return(-1); + } + + return(sock_fd); +} + + + + + +int traceLevel = 2 /* NORMAL */; +int useSyslog = 0, syslog_opened = 0; + +#define N2N_TRACE_DATESIZE 32 +void traceEvent(int eventTraceLevel, char* file, int line, char * format, ...) { + va_list va_ap; + + if(eventTraceLevel <= traceLevel) { + char buf[2048]; + char out_buf[640]; + char theDate[N2N_TRACE_DATESIZE]; + char *extra_msg = ""; + time_t theTime = time(NULL); +#ifdef WIN32 + int i; +#endif + + /* We have two paths - one if we're logging, one if we aren't + * Note that the no-log case is those systems which don't support it (WIN32), + * those without the headers !defined(USE_SYSLOG) + * those where it's parametrically off... + */ + + memset(buf, 0, sizeof(buf)); + strftime(theDate, N2N_TRACE_DATESIZE, "%d/%b/%Y %H:%M:%S", localtime(&theTime)); + + va_start (va_ap, format); + vsnprintf(buf, sizeof(buf)-1, format, va_ap); + va_end(va_ap); + + if(eventTraceLevel == 0 /* TRACE_ERROR */) + extra_msg = "ERROR: "; + else if(eventTraceLevel == 1 /* TRACE_WARNING */) + extra_msg = "WARNING: "; + + while(buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; + +#ifndef WIN32 + if(useSyslog) { + if(!syslog_opened) { + openlog("n2n", LOG_PID, LOG_DAEMON); + syslog_opened = 1; + } + + snprintf(out_buf, sizeof(out_buf), "%s%s", extra_msg, buf); + syslog(LOG_INFO, "%s", out_buf); + } else { + snprintf(out_buf, sizeof(out_buf), "%s [%11s:%4d] %s%s", theDate, file, line, extra_msg, buf); + printf("%s\n", out_buf); + fflush(stdout); + } +#else + /* this is the WIN32 code */ + for(i=strlen(file)-1; i>0; i--) if(file[i] == '\\') { i++; break; }; + snprintf(out_buf, sizeof(out_buf), "%s [%11s:%4d] %s%s", theDate, &file[i], line, extra_msg, buf); + printf("%s\n", out_buf); + fflush(stdout); +#endif + } + +} + +/* *********************************************** */ + +/* addr should be in network order. Things are so much simpler that way. */ +char* intoa(uint32_t /* host order */ addr, char* buf, uint16_t buf_len) { + char *cp, *retStr; + uint8_t byteval; + int n; + + cp = &buf[buf_len]; + *--cp = '\0'; + + n = 4; + do { + byteval = addr & 0xff; + *--cp = byteval % 10 + '0'; + byteval /= 10; + if (byteval > 0) { + *--cp = byteval % 10 + '0'; + byteval /= 10; + if (byteval > 0) + *--cp = byteval + '0'; + } + *--cp = '.'; + addr >>= 8; + } while (--n > 0); + + /* Convert the string to lowercase */ + retStr = (char*)(cp+1); + + return(retStr); +} + +/* *********************************************** */ + +char * macaddr_str( macstr_t buf, + const n2n_mac_t mac ) +{ + snprintf(buf, N2N_MACSTR_SIZE, "%02X:%02X:%02X:%02X:%02X:%02X", + mac[0] & 0xFF, mac[1] & 0xFF, mac[2] & 0xFF, + mac[3] & 0xFF, mac[4] & 0xFF, mac[5] & 0xFF); + return(buf); +} + +/* *********************************************** */ + +uint8_t is_multi_broadcast(const uint8_t * dest_mac) { + + int is_broadcast = ( memcmp(broadcast_addr, dest_mac, 6) == 0 ); + int is_multicast = ( memcmp(multicast_addr, dest_mac, 3) == 0 ); + int is_ipv6_multicast = ( memcmp(ipv6_multicast_addr, dest_mac, 2) == 0 ); + + return is_broadcast || is_multicast || is_ipv6_multicast; + +} + +/* http://www.faqs.org/rfcs/rfc908.html */ + + +/* *********************************************** */ + +char* msg_type2str(uint16_t msg_type) { + switch(msg_type) { + case MSG_TYPE_REGISTER: return("MSG_TYPE_REGISTER"); + case MSG_TYPE_DEREGISTER: return("MSG_TYPE_DEREGISTER"); + case MSG_TYPE_PACKET: return("MSG_TYPE_PACKET"); + case MSG_TYPE_REGISTER_ACK: return("MSG_TYPE_REGISTER_ACK"); + case MSG_TYPE_REGISTER_SUPER: return("MSG_TYPE_REGISTER_SUPER"); + case MSG_TYPE_REGISTER_SUPER_ACK: return("MSG_TYPE_REGISTER_SUPER_ACK"); + case MSG_TYPE_REGISTER_SUPER_NAK: return("MSG_TYPE_REGISTER_SUPER_NAK"); + case MSG_TYPE_FEDERATION: return("MSG_TYPE_FEDERATION"); + default: return("???"); + } + + return("???"); +} + +/* *********************************************** */ + +void hexdump(const uint8_t * buf, size_t len) +{ + size_t i; + + if ( 0 == len ) { return; } + + for(i=0; i 0) && ((i % 16) == 0)) { printf("\n"); } + printf("%02X ", buf[i] & 0xFF); + } + + printf("\n"); +} + +/* *********************************************** */ + +void print_n2n_version() { + printf("Welcome to n2n v.%s for %s\n" + "Built on %s\n" + "Copyright 2007-09 - http://www.ntop.org\n\n", + n2n_sw_version, n2n_sw_osName, n2n_sw_buildDate); +} + + + + +/** Find the peer entry in list with mac_addr equal to mac. + * + * Does not modify the list. + * + * @return NULL if not found; otherwise pointer to peer entry. + */ +struct peer_info * find_peer_by_mac( struct peer_info * list, const n2n_mac_t mac ) +{ + while(list != NULL) + { + if( 0 == memcmp(mac, list->mac_addr, 6) ) + { + return list; + } + list = list->next; + } + + return NULL; +} + + +/** Return the number of elements in the list. + * + */ +size_t peer_list_size( const struct peer_info * list ) +{ + size_t retval=0; + + while ( list ) + { + ++retval; + list = list->next; + } + + return retval; +} + +/** Add new to the head of list. If list is NULL; create it. + * + * The item new is added to the head of the list. New is modified during + * insertion. list takes ownership of new. + */ +void peer_list_add( struct peer_info * * list, + struct peer_info * new ) +{ + new->next = *list; + new->last_seen = time(NULL); + *list = new; +} + + +size_t purge_expired_registrations( struct peer_info ** peer_list ) { + static time_t last_purge = 0; + time_t now = time(NULL); + size_t num_reg = 0; + + if((now - last_purge) < PURGE_REGISTRATION_FREQUENCY) return 0; + + traceEvent(TRACE_INFO, "Purging old registrations"); + + num_reg = purge_peer_list( peer_list, now-REGISTRATION_TIMEOUT ); + + last_purge = now; + traceEvent(TRACE_INFO, "Remove %ld registrations", num_reg); + + return num_reg; +} + +/** Purge old items from the peer_list and return the number of items that were removed. */ +size_t purge_peer_list( struct peer_info ** peer_list, + time_t purge_before ) +{ + struct peer_info *scan; + struct peer_info *prev; + size_t retval=0; + + scan = *peer_list; + prev = NULL; + while(scan != NULL) + { + if(scan->last_seen < purge_before) + { + struct peer_info *next = scan->next; + + if(prev == NULL) + { + *peer_list = next; + } + else + { + prev->next = next; + } + + ++retval; + free(scan); + scan = next; + } + else + { + prev = scan; + scan = scan->next; + } + } + + return retval; +} + +/** Purge all items from the peer_list and return the number of items that were removed. */ +size_t clear_peer_list( struct peer_info ** peer_list ) +{ + struct peer_info *scan; + struct peer_info *prev; + size_t retval=0; + + scan = *peer_list; + prev = NULL; + while(scan != NULL) + { + struct peer_info *next = scan->next; + + if(prev == NULL) + { + *peer_list = next; + } + else + { + prev->next = next; + } + + ++retval; + free(scan); + scan = next; + } + + return retval; +} + +static uint8_t hex2byte( const char * s ) +{ + char tmp[3]; + tmp[0]=s[0]; + tmp[1]=s[1]; + tmp[2]=0; /* NULL term */ + + return((uint8_t)strtol( s, NULL, 16 )); +} + +extern int str2mac( uint8_t * outmac /* 6 bytes */, const char * s ) +{ + size_t i; + + /* break it down as one case for the first "HH", the 5 x through loop for + * each ":HH" where HH is a two hex nibbles in ASCII. */ + + *outmac=hex2byte(s); + ++outmac; + s+=2; /* don't skip colon yet - helps generalise loop. */ + + for (i=1; i<6; ++i ) + { + s+=1; + *outmac=hex2byte(s); + ++outmac; + s+=2; + } + + return 0; /* ok */ +} + +extern char * sock_to_cstr( n2n_sock_str_t out, + const n2n_sock_t * sock ) +{ + int r; + + if ( NULL == out ) { return NULL; } + memset(out, 0, N2N_SOCKBUF_SIZE); + + if ( AF_INET6 == sock->family ) + { + /* INET6 not written yet */ + r = snprintf( out, N2N_SOCKBUF_SIZE, "XXXX:%hu", sock->port ); + return out; + } + else + { + const uint8_t * a = sock->addr.v4; + r = snprintf( out, N2N_SOCKBUF_SIZE, "%hu.%hu.%hu.%hu:%hu", + (a[0] & 0xff), (a[1] & 0xff), (a[2] & 0xff), (a[3] & 0xff), sock->port ); + return out; + } +} + +/* @return zero if the two sockets are equivalent. */ +int sock_equal( const n2n_sock_t * a, + const n2n_sock_t * b ) +{ + if ( a->port != b->port ) { return 1; } + if ( a->family != b->family ) { return 1; } + switch (a->family) /* they are the same */ + { + case AF_INET: + if ( 0 != memcmp( a->addr.v4, b->addr.v4, IPV4_SIZE ) ) { return 1;}; + break; + default: + if ( 0 != memcmp( a->addr.v6, b->addr.v6, IPV6_SIZE ) ) { return 1;}; + break; + } + + return 0; +} + diff --git a/n2n.h b/n2n.h new file mode 100644 index 0000000..4801bf7 --- /dev/null +++ b/n2n.h @@ -0,0 +1,254 @@ +/* + * (C) 2007-09 - Luca Deri + * Richard Andrews + * + * 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 3 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, see + * + * Code contributions courtesy of: + * Babak Farrokhi [FreeBSD port] + * Lukasz Taczuk + * + */ + +#ifndef _N2N_H_ +#define _N2N_H_ + +/* + tunctl -t tun0 + tunctl -t tun1 + ifconfig tun0 1.2.3.4 up + ifconfig tun1 1.2.3.5 up + ./edge -d tun0 -l 2000 -r 127.0.0.1:3000 -c hello + ./edge -d tun1 -l 3000 -r 127.0.0.1:2000 -c hello + + + tunctl -u UID -t tunX +*/ + +#if defined(__APPLE__) && defined(__MACH__) +#define _DARWIN_ +#endif + + +/* Some capability defaults which can be reset for particular platforms. */ +#define N2N_HAVE_DAEMON 1 +#define N2N_HAVE_SETUID 1 +/* #define N2N_CAN_NAME_IFACE */ + +/* Moved here to define _CRT_SECURE_NO_WARNINGS before all the including takes place */ +#ifdef WIN32 +#include "win32/n2n_win32.h" +#undef N2N_HAVE_DAEMON +#undef N2N_HAVE_SETUID +#endif + +#include +#include +#include + +#ifndef WIN32 +#include +#endif + +#ifndef _MSC_VER +#include +#endif /* #ifndef _MSC_VER */ + +#include +#include +#include + +#ifndef WIN32 +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include +#include +#define N2N_CAN_NAME_IFACE 1 +#endif /* #ifdef __linux__ */ + +#ifdef __FreeBSD__ +#include +#endif /* #ifdef __FreeBSD__ */ + +#include +#include + +#define ETH_ADDR_LEN 6 +struct ether_hdr +{ + uint8_t dhost[ETH_ADDR_LEN]; + uint8_t shost[ETH_ADDR_LEN]; + uint16_t type; /* higher layer protocol encapsulated */ +} __attribute__ ((__packed__)); + +typedef struct ether_hdr ether_hdr_t; + +#ifdef __sun__ +#include /* MIN() and MAX() declared here */ +#undef N2N_HAVE_DAEMON +#endif /* #ifdef __sun__ */ + +#include +#include +#include +#include +#include +#include +#include + +#define closesocket(a) close(a) +#endif /* #ifndef WIN32 */ + +#include + +#include + +#ifdef WIN32 +#include "win32/wintap.h" +#endif /* #ifdef WIN32 */ + +#include "n2n_wire.h" + +/* N2N_IFNAMSIZ is needed on win32 even if dev_name is not used after declaration */ +#define N2N_IFNAMSIZ 16 /* 15 chars * NULL */ +#ifndef WIN32 +typedef struct tuntap_dev { + int fd; + uint8_t mac_addr[6]; + uint32_t ip_addr, device_mask; + uint16_t mtu; + char dev_name[N2N_IFNAMSIZ]; +} tuntap_dev; + +#define SOCKET int +#endif /* #ifndef WIN32 */ + +#define QUICKLZ 1 + +/* N2N packet header indicators. */ +#define MSG_TYPE_REGISTER 1 +#define MSG_TYPE_DEREGISTER 2 +#define MSG_TYPE_PACKET 3 +#define MSG_TYPE_REGISTER_ACK 4 +#define MSG_TYPE_REGISTER_SUPER 5 +#define MSG_TYPE_REGISTER_SUPER_ACK 6 +#define MSG_TYPE_REGISTER_SUPER_NAK 7 +#define MSG_TYPE_FEDERATION 8 + +/* Set N2N_COMPRESSION_ENABLED to 0 to disable lzo1x compression of ethernet + * frames. Doing this will break compatibility with the standard n2n packet + * format so do it only for experimentation. All edges must be built with the + * same value if they are to understand each other. */ +#define N2N_COMPRESSION_ENABLED 1 + +#define DEFAULT_MTU 1400 + +/** Common type used to hold stringified IP addresses. */ +typedef char ipstr_t[32]; + +/** Common type used to hold stringified MAC addresses. */ +#define N2N_MACSTR_SIZE 32 +typedef char macstr_t[N2N_MACSTR_SIZE]; + +struct peer_info { + struct peer_info * next; + n2n_community_t community_name; + n2n_mac_t mac_addr; + n2n_sock_t sock; + time_t last_seen; +}; + +struct n2n_edge; /* defined in edge.c */ +typedef struct n2n_edge n2n_edge_t; + + +/* ************************************** */ + +#define TRACE_ERROR 0, __FILE__, __LINE__ +#define TRACE_WARNING 1, __FILE__, __LINE__ +#define TRACE_NORMAL 2, __FILE__, __LINE__ +#define TRACE_INFO 3, __FILE__, __LINE__ +#define TRACE_DEBUG 4, __FILE__, __LINE__ + +/* ************************************** */ + +#define SUPERNODE_IP "127.0.0.1" +#define SUPERNODE_PORT 1234 + +/* ************************************** */ + +#ifndef max +#define max(a, b) ((a < b) ? b : a) +#endif + +#ifndef min +#define min(a, b) ((a > b) ? b : a) +#endif + +/* ************************************** */ + +/* Variables */ +/* extern TWOFISH *tf; */ +extern int traceLevel; +extern int useSyslog; +extern const uint8_t broadcast_addr[6]; +extern const uint8_t multicast_addr[6]; + +/* Functions */ +extern void traceEvent(int eventTraceLevel, char* file, int line, char * format, ...); +extern int tuntap_open(tuntap_dev *device, char *dev, const char *address_mode, char *device_ip, + char *device_mask, const char * device_mac, int mtu); +extern int tuntap_read(struct tuntap_dev *tuntap, unsigned char *buf, int len); +extern int tuntap_write(struct tuntap_dev *tuntap, unsigned char *buf, int len); +extern void tuntap_close(struct tuntap_dev *tuntap); +extern void tuntap_get_address(struct tuntap_dev *tuntap); + +extern SOCKET open_socket(int local_port, int bind_any); + +extern char* intoa(uint32_t addr, char* buf, uint16_t buf_len); +extern char* macaddr_str(macstr_t buf, const n2n_mac_t mac); +extern int str2mac( uint8_t * outmac /* 6 bytes */, const char * s ); +extern char * sock_to_cstr( n2n_sock_str_t out, + const n2n_sock_t * sock ); + +extern int sock_equal( const n2n_sock_t * a, + const n2n_sock_t * b ); + +extern uint8_t is_multi_broadcast(const uint8_t * dest_mac); +extern char* msg_type2str(uint16_t msg_type); +extern void hexdump(const uint8_t * buf, size_t len); + +void print_n2n_version(); + + +/* Operations on peer_info lists. */ +struct peer_info * find_peer_by_mac( struct peer_info * list, + const n2n_mac_t mac ); +void peer_list_add( struct peer_info * * list, + struct peer_info * new ); +size_t peer_list_size( const struct peer_info * list ); +size_t purge_peer_list( struct peer_info ** peer_list, + time_t purge_before ); +size_t clear_peer_list( struct peer_info ** peer_list ); +size_t purge_expired_registrations( struct peer_info ** peer_list ); + +/* version.c */ +extern char *n2n_sw_version, *n2n_sw_osName, *n2n_sw_buildDate; + +#endif /* _N2N_H_ */ diff --git a/n2n.spec b/n2n.spec new file mode 100644 index 0000000..f5ee7d8 --- /dev/null +++ b/n2n.spec @@ -0,0 +1,52 @@ +Summary: N2N peer-to-peer virtual private network system. +Name: n2n +Version: 2.1.0 +Release: 1 +License: GPLv3 +Vendor: ntop.org +Group: None +URL: http://www.ntop.org/n2n +Source0: %{name}-%{version}.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root + +%description +N2N is a peer-to-peer virtual private network system. N2N uses the universal +TUNTAP interface to create TAP network interfaces to an encrypted virtual +LAN. Members of a community share encryption keys which allow exchange of +data. The supernode is used for peer discovery and initial packet relay before +direct peer-to-peer exchange is established. Once direct packet exchange is +established, the supernode is not required. + +N2N-2 introduces additional security features and multiple supernodes. + +%prep + +%setup -q + +echo -e "\n *** Building ${RPM_PACKAGE_NAME}-${RPM_PACKAGE_VERSION}-${RPM_PACKAGE_RELEASE} ***\n" + +%build +make + +%install +make PREFIX=${RPM_BUILD_ROOT}/usr install + +%clean +rm -rf $RPM_BUILD_ROOT + + +%files +%defattr(-,root,root,-) + /usr/sbin/supernode + /usr/sbin/edge +%doc /usr/share/man/man1/supernode.1.gz +%doc /usr/share/man/man8/edge.8.gz +%doc /usr/share/man/man7/n2n_v2.7.gz + + +%changelog +* Fri Oct 30 2009 Richard Andrews - +- First beta for n2n-2 +* Sat May 3 2008 Richard Andrews - +- Initial build. + diff --git a/n2n_keyfile.c b/n2n_keyfile.c new file mode 100644 index 0000000..56de3a1 --- /dev/null +++ b/n2n_keyfile.c @@ -0,0 +1,203 @@ +/* (c) 2009 Richard Andrews */ +/* Contributions from: + * - Jozef Kralik + */ + +#include "n2n.h" +#include "n2n_keyfile.h" +#include +#include +#include +#include + + +#ifdef WIN32 +char *strsep( char **ppsz_string, const char *psz_delimiters ) +{ + char *p; + char *psz_string = *ppsz_string; + if( !psz_string ) + return NULL; + + p = strpbrk( psz_string, psz_delimiters ); + if( !p ) + { + *ppsz_string = NULL; + return psz_string; + } + *p++ = '\0'; + + *ppsz_string = p; + return psz_string; +} +#endif + + +/* Parse hex nibbles in ascii until a non-nibble character is found. Nibble + * characters are 0-9, a-f and A-F. + * + * Return number of bytes parsed into keyBuf or a negative error code. + */ +ssize_t n2n_parse_hex( uint8_t * keyBuf, + size_t keyLen, + const char * textKey, + size_t textLen) +{ + ssize_t retval=0; + uint8_t * pout=keyBuf; + size_t octet=0; + const char * textEnd; + const char * pbeg; + + textEnd = textKey+textLen; + pbeg=textKey; + + while ( ( pbeg + 1 < textEnd ) && ( retval < (ssize_t)keyLen ) ) + { + if ( 1 != sscanf( pbeg, "%02x", (unsigned int*)&octet ) ) + { + retval=-1; + break; + } + + *pout = (octet & 0xff); + ++pout; + ++retval; + pbeg += 2; + } + + return retval; +} + + +static int parseKeyLine( n2n_cipherspec_t * spec, + const char * linein ) +{ + /* parameters are separated by whitespace */ + char line[N2N_KEYFILE_LINESIZE]; + char * lp=line; + const char * token; + strncpy( line, linein, N2N_KEYFILE_LINESIZE ); + + memset( spec, 0, sizeof( n2n_cipherspec_t ) ); + + /* decode valid_from time */ + token = strsep( &lp, DELIMITERS ); + if ( !token ) { goto error; } + spec->valid_from = atol(token); + + /* decode valid_until time */ + token = strsep( &lp, DELIMITERS ); + if ( !token ) { goto error; } + spec->valid_until = atol(token); + + /* decode the transform number */ + token = strsep( &lp, DELIMITERS ); + if ( !token ) { goto error; } + spec->t = atoi(token); + + /* The reset if opaque key data */ + token = strsep( &lp, DELIMITERS ); + if ( !token ) { goto error; } + strncpy( (char *)spec->opaque, token, N2N_MAX_KEYSIZE ); + spec->opaque_size=strlen( (char *)spec->opaque); + + return 0; + +error: + return -1; +} + + +#define SEP "/" + + +int validCipherSpec( const n2n_cipherspec_t * k, + time_t now ) +{ + if ( k->valid_until < k->valid_from ) { goto bad; } + if ( k->valid_from > now ) { goto bad; } + if ( k->valid_until < now ) { goto bad; } + + return 0; + +bad: + return -1; +} + +/* Read key control file and return the number of specs stored or a negative + * error code. + * + * As the specs are read in the from and until time values are compared to + * present time. Only those keys which are valid are stored. + */ +int n2n_read_keyfile( n2n_cipherspec_t * specs, /* fill out this array of cipherspecs */ + size_t numspecs, /* number of slots in the array. */ + const char * ctrlfile_path ) /* path to control file */ +{ + /* Each line contains one cipherspec. */ + + int retval=0; + FILE * fp=NULL; + size_t idx=0; + time_t now = time(NULL); + + traceEvent( TRACE_DEBUG, "Reading '%s'\n", ctrlfile_path ); + + fp = fopen( ctrlfile_path, "r" ); + if ( fp ) + { + /* Read the file a line a time with fgets. */ + char line[N2N_KEYFILE_LINESIZE]; + size_t lineNum=0; + + while ( idx < numspecs ) + { + n2n_cipherspec_t * k = &(specs[idx]); + fgets( line, N2N_KEYFILE_LINESIZE, fp ); + ++lineNum; + + if ( strlen(line) > 1 ) + { + if ( 0 == parseKeyLine( k, line ) ) + { + if ( k->valid_until > now ) + { + traceEvent( TRACE_INFO, " --> [%u] from %lu, until %lu, transform=%hu, data=%s\n", + idx, k->valid_from, k->valid_until, k->t, k->opaque ); + + ++retval; + ++idx; + } + else + { + traceEvent( TRACE_INFO, " --X [%u] from %lu, until %lu, transform=%hu, data=%s\n", + idx, k->valid_from, k->valid_until, k->t, k->opaque ); + + } + } + else + { + traceEvent( TRACE_WARNING, "Failed to decode line %u\n", lineNum ); + } + } + + if ( feof(fp) ) + { + break; + } + + line[0]=0; /* this line has been consumed */ + } + + fclose( fp); + fp=NULL; + } + else + { + traceEvent( TRACE_ERROR, "Failed to open '%s'\n", ctrlfile_path ); + retval = -1; + } + + return retval; +} diff --git a/n2n_keyfile.h b/n2n_keyfile.h new file mode 100644 index 0000000..6068df1 --- /dev/null +++ b/n2n_keyfile.h @@ -0,0 +1,101 @@ +/* (c) 2009 Richard Andrews */ + +/** Key files + * + * Edge implements a very simple interface for getting instructions about + * rolling keys. + * + * Key definitions are written as individual files in /.key. The + * format of each key is a single line of hex nibbles as follows: + * + * 0102030405060708090a0b0c0d0e0f + * + * Any external key exchange mechanism can receive the key data write it into + * the keyfiles. + * + * To control which keys are active at what times the key control file is + * used. This is a single file which is periodically reread. It contains key + * definitions in chronological order with one line per key definition as + * follows: + * + * + * + * edge reads the key control file periodically to get updates in policy. edge + * holds a number of keys in memory. Data can be decoded if it was encoded by + * any of the keys still in memory. By having at least 2 keys in memory it + * allows for clock skew and transmission delay when encoder and decoder roll + * keys at slightly different times. The amount of overlap in the valid time + * ranges provides the tolerance to timing skews in the system. + * + * The keys have the same level of secrecy as any other user file. Existing + * UNIX permission systems can be used to provide access controls. + * + */ + +/** How Edge Uses The Key Schedule + * + * Edge provides state space for a number of transform algorithms. Each + * transform uses its state space to store the SA information for its keys as + * found in the key file. When a packet is received the transform ID is in + * plain text. The packets is then sent to that transform for decoding. Each + * transform can store its SA numbers differently (or not at all). The + * transform code then finds the SA number, then finds the cipher (with key) in + * the state space and uses this to decode the packet. + * + * To support this, as edge reads each key line, it passes it to the + * appropriate transform to parse the line and store the SA information in its + * state space. + * + * When encoding a packet, edge has several transforms and potentially valid + * SAs to choose from. To keep track of which one to use for encoding edge does + * its own book-keeping as each key line is passed to the transform code: it + * stores a lookup of valid_from -> transform. When encoding a packet it then + * just calls the transform with the best valid_from in the table. The + * transform's own state space has all the SAs for its keys and the best of + * those is chosen. + */ + +#if !defined( N2N_KEYFILE_H_ ) +#define N2N_KEYFILE_H_ + + +#include "n2n_wire.h" +#include + +#define N2N_MAX_KEYSIZE 256 /* bytes */ +#define N2N_MAX_NUM_CIPHERSPECS 8 +#define N2N_KEYPATH_SIZE 256 +#define N2N_KEYFILE_LINESIZE 256 + +/** This structure stores an encryption cipher spec. */ +struct n2n_cipherspec +{ + n2n_transform_t t; /* N2N_TRANSFORM_ID_xxx for this spec. */ + time_t valid_from; /* Start using the key at this time. */ + time_t valid_until; /* Key is valid if time < valid_until. */ + uint16_t opaque_size; /* Size in bytes of key. */ + uint8_t opaque[N2N_MAX_KEYSIZE];/* Key matter. */ +}; + +typedef struct n2n_cipherspec n2n_cipherspec_t; + + +static const char * const DELIMITERS=" \t\n\r"; + + +/** @return number of cipherspec items filled. */ +int n2n_read_keyfile( n2n_cipherspec_t * specs, /* fill out this array of cipherspecs */ + size_t numspecs, /* number of slots in the array. */ + const char * ctrlfile_path ); /* path to control file */ + +int validCipherSpec( const n2n_cipherspec_t * k, + time_t now ); + +ssize_t n2n_parse_hex( uint8_t * keyBuf, + size_t keyMax, + const char * textKey, + size_t textLen ); + +/*----------------------------------------------------------------------------*/ + +#endif /* #if !defined( N2N_KEYFILE_H_ ) */ diff --git a/n2n_transforms.h b/n2n_transforms.h new file mode 100644 index 0000000..effbc50 --- /dev/null +++ b/n2n_transforms.h @@ -0,0 +1,78 @@ +/* (c) 2009 Richard Andrews */ + +#if !defined(N2N_TRANSFORMS_H_) +#define N2N_TRANSFORMS_H_ + +#include "n2n_keyfile.h" +#include "n2n_wire.h" + + +#define N2N_TRANSFORM_ID_INVAL 0 /* marks uninitialised data */ +#define N2N_TRANSFORM_ID_NULL 1 +#define N2N_TRANSFORM_ID_TWOFISH 2 +#define N2N_TRANSFORM_ID_AESCBC 3 +#define N2N_TRANSFORM_ID_LZO 4 +#define N2N_TRANSFORM_ID_TWOFISH_LZO 5 +#define N2N_TRANSFORM_ID_AESCBC_LZO 6 +#define N2N_TRANSFORM_ID_USER_START 64 +#define N2N_TRANSFORM_ID_MAX 65535 + + +struct n2n_trans_op; +typedef struct n2n_trans_op n2n_trans_op_t; + +struct n2n_tostat +{ + uint8_t can_tx; /* Does this transop have a valid SA for encoding. */ + n2n_cipherspec_t tx_spec; /* If can_tx, the spec used to encode. */ +}; + +typedef struct n2n_tostat n2n_tostat_t; + + +typedef int (*n2n_transdeinit_f)( n2n_trans_op_t * arg ); +typedef int (*n2n_transaddspec_f)( n2n_trans_op_t * arg, + const n2n_cipherspec_t * cspec ); +typedef n2n_tostat_t (*n2n_transtick_f)( n2n_trans_op_t * arg, + time_t now ); + +typedef int (*n2n_transform_f)( n2n_trans_op_t * arg, + uint8_t * outbuf, + size_t out_len, + const uint8_t * inbuf, + size_t in_len ); + +/** Holds the info associated with a data transform plugin. + * + * When a packet arrives the transform ID is extracted. This defines the code + * to use to decode the packet content. The transform code then decodes the + * packet and consults its internal key lookup. + */ +struct n2n_trans_op +{ + void * priv; /* opaque data. Key schedule goes here. */ + + n2n_transform_t transform_id; /* link header enum to a transform */ + size_t tx_cnt; + size_t rx_cnt; + + n2n_transdeinit_f deinit; /* destructor function */ + n2n_transaddspec_f addspec; /* parse opaque data from a key schedule file. */ + n2n_transtick_f tick; /* periodic maintenance */ + n2n_transform_f fwd; /* encode a payload */ + n2n_transform_f rev; /* decode a payload */ +}; + +/* Setup a single twofish SA for single-key operation. */ +int transop_twofish_setup( n2n_trans_op_t * ttt, + n2n_sa_t sa_num, + uint8_t * encrypt_pwd, + uint32_t encrypt_pwd_len ); + +/* Initialise an empty transop ready to receive cipherspec elements. */ +int transop_twofish_init( n2n_trans_op_t * ttt ); +int transop_aes_init( n2n_trans_op_t * ttt ); +void transop_null_init( n2n_trans_op_t * ttt ); + +#endif /* #if !defined(N2N_TRANSFORMS_H_) */ + diff --git a/n2n_v2.7 b/n2n_v2.7 new file mode 100644 index 0000000..092f2d3 --- /dev/null +++ b/n2n_v2.7 @@ -0,0 +1,156 @@ +.TH "n2n_v2" 7 "Sep 21, 2009" "revision 3909" "Background" +.SH NAME +N2n Version 2 \- version 2 of the n2n decentralised peer-to-peer network overlay +VPN. +.SH DESCRIPTION +N2n is a peer-to-peer network overlay or VPN system that provides layer 2 over +layer 3 encapsulation with data transform capabilities such as encryption and +compression. This guide discusses the differences of version 2 or n2n from +version 1. +.SH PROTOCOLS +N2n-2 uses a different set of messages to communicate with edges and +supernodes. The n2n-2 messages are not compatible with n2n-1. There is no +backward compatibility for n2n-1. +.SH ENCRYPTION +N2n-2 offers a new way of handling encryption compared to n2n-1. N2n-1 provided +facility for a single community password with no expiration. In n2n-2 this +method is preserved but a new mechanism has been added using a key schedule +file. +.TP +Key Schedule +A key schedule file lists a number of keys with the period for which each is +valid along with the encryption type identifier and the actual key value. This +allows the user to define up to 32 keys in advance with a pre-set time at which +they keys will change. The key schedule file can be reloaded while the edge is +running to allow new keys to be loaded and unused keys expunged. +.TP +Timing Requirements When a key rolls over to the next in the schedule, the new +key is used for all transmitted packets; however any packets received using an +older key can still be decoded as the keys from the key schedule are still +known. As a result edges do not need to have accurate time synchronisation. The +accuracy of required synchronisation depends to a large degree on the key +schedule. Rapid key roll-overs requires more accurate time synchronisation. +.P +N2n-2 provides the following encryption ciphers; more can be added as required: +.TP +.B (1) NULL +Data is encapsulated unchanged. Useful for testing and high-performance, low +sensitivity applications. +.TP +.B (2) TF +Twofish AES candidate. +.P +The following additional ciphers are specified but not yet implemented: +.TP +.B (3) AES-CBC +AES in CBC mode with 256-bit key. +.TP +.B (4) LZO +LZO compression of data (no encryption). +.TP +.B (5) TF-LZO +TF cipher with LZO compression of data prior to encryption. +.TP +.B (6) AES-CBC-LZO +AES-CBC ciper with LZO compression of data prior to encryption. + +.SH EXTENSIBILITY +N2n-2 decouples the data transform system from the core of the edge +operation. This allows for easier addition of new data transform +operations. N2n-2 reserves 64 standard transform identifiers (such as TwoFish +encryption) but allocates transform identifiers 64 - 65536 for user-defined +transforms. This allows anyone to add to n2n new private transforms without +breaking compatibility with the standard offering. + +.SH MULTIPLE SUPERNODES +N2n-2 introduces the capability of multiple supernodes to be used by an +edge. N2n-2 offers supernode in several flavours: +.TP +Stand-alone supernode + +This is the same concept as from n2n-1. Supernode is a small efficient C program +which operates in isolation. +.TP +Federated supernodes + +This is a cluster of supernodes which share information. Edges registered to any +of the cooperating supernodes can relay packets through the supernode federation +and switch supernodes if required. Supernodes can send PACKET or REGISTER +messages to other supernodes to try and find the destination edge. + +.P +The n2n-2 edge implementation allows multiple supernodes to be specified on the +command line. Edges monitor the current supernode for responses to +REGISTER_SUPER messages. If 3 responses are missed then the edge starts looking +for a new supernode. It cycles through the list of supernodes specified until it +finds a working one. + +.SH EFFICIENCY +The n2n-2 message formats have been made more efficient. The amount of data +overhead has been reduced by ensuring the messages contain only the data fields +required. Some optional fields do not consume data if they are not present. + +.SH DAEMON OPERATION +The supernode and edge use daemon mode of operation by default. This sense is +inverted from n2n-1 where they ran in the foreground by default. They can be +made to run in the foreground so tools such a DJB's daemontools can work with +them. See the +.B -f +option + +.SH MANAGEMENT CONSOLE +Edge and supernode in n2n-2 provide a UDP-based management console. Both listen +on the localhost address 127.0.0.1. Commands can be sent to the programs by +sending to the UDP socket. Responses are returned to the socket from which +commands were issued. This only works from the computer on which the programs +are running. Statistics can be retrieved and commands issued. The netcat utility +is all that is required; but more sophisticated tools could be built on the +interface. + +.SH SUPERNODE AUTHENTICATION +.B (To be implemented) +Space has been reserved in the supernode registration messages for an +authentication mechanism. + +.SH MESSAGE SUMMARY +The following message types work within n2n-2. +.TP +REGISTER_SUPER +Sent from an edge to its local supernode to register its MAC with the community. +.TP +REGISTER_SUPER_ACK +Sent from a supernode to an edge to confirm registration. This also carries the +definition of the edge socket as seen at the supernode so NAT can be detected +and described. +.TP +REGISTER_SUPER_NAK +Supernode refusing to register an edge. +.TP +PACKET +Encapsulated ethernet packets sent between edges. Supernodes forward or +broadcast these and edges send them direct in peer-to-peer mode. +.TP +REGISTER +A peer-to-peer mode registration request from one edge to another. Supernodes +forward these to facilitate NAT crossing introductions. +.TP +REGISTER_ACK +Complete peer-to-peer mode setup between two edges. These messages need to +travel direct between edges. +.TP +FEDERATION +Federated supernodes exchanging community information. + +.SH OTHER DIFFERENCES +.TP +HTTP Tunneling +This experimental feature (-t option in n2n_v1) of n2n_v1 has been removed +entirely from n2n_v2. +.SH AUTHORS +.TP +Richard Andrews andrews (at) ntop.org - main author of n2n-2 +.TP +Luca Deri +deri (at) ntop.org - code inherited from n2n-1 +.SH SEE ALSO +ifconfig(8) edge(8) supernode(1) diff --git a/n2n_wire.h b/n2n_wire.h new file mode 100644 index 0000000..8a3dfdf --- /dev/null +++ b/n2n_wire.h @@ -0,0 +1,321 @@ +/* (c) 2009 Richard Andrews + * + * Contributions by: + * Luca Deri + * Lukasz Taczuk + */ + +#if !defined( N2N_WIRE_H_ ) +#define N2N_WIRE_H_ + +#include + +#if defined(WIN32) +#include "win32/n2n_win32.h" + +#if defined(__MINGW32__) +#include +#endif /* #ifdef __MINGW32__ */ + +#else /* #if defined(WIN32) */ +#include +#include +#include /* AF_INET and AF_INET6 */ +#endif /* #if defined(WIN32) */ + +#define N2N_PKT_VERSION 2 +#define N2N_DEFAULT_TTL 2 /* can be forwarded twice at most */ +#define N2N_COMMUNITY_SIZE 16 +#define N2N_MAC_SIZE 6 +#define N2N_COOKIE_SIZE 4 +#define N2N_PKT_BUF_SIZE 2048 +#define N2N_SOCKBUF_SIZE 64 /* string representation of INET or INET6 sockets */ + +typedef uint8_t n2n_community_t[N2N_COMMUNITY_SIZE]; +typedef uint8_t n2n_mac_t[N2N_MAC_SIZE]; +typedef uint8_t n2n_cookie_t[N2N_COOKIE_SIZE]; + +typedef char n2n_sock_str_t[N2N_SOCKBUF_SIZE]; /* tracing string buffer */ + +enum n2n_pc +{ + n2n_ping=0, /* Not used */ + n2n_register=1, /* Register edge to edge */ + n2n_deregister=2, /* Deregister this edge */ + n2n_packet=3, /* PACKET data content */ + n2n_register_ack=4, /* ACK of a registration from edge to edge */ + n2n_register_super=5, /* Register edge to supernode */ + n2n_register_super_ack=6, /* ACK from supernode to edge */ + n2n_register_super_nak=7, /* NAK from supernode to edge - registration refused */ + n2n_federation=8 /* Not used by edge */ +}; + +typedef enum n2n_pc n2n_pc_t; + +#define N2N_FLAGS_OPTIONS 0x0080 +#define N2N_FLAGS_SOCKET 0x0040 +#define N2N_FLAGS_FROM_SUPERNODE 0x0020 + +/* The bits in flag that are the packet type */ +#define N2N_FLAGS_TYPE_MASK 0x001f /* 0 - 31 */ +#define N2N_FLAGS_BITS_MASK 0xffe0 + +#define IPV4_SIZE 4 +#define IPV6_SIZE 16 + + +#define N2N_AUTH_TOKEN_SIZE 32 /* bytes */ + + +#define N2N_EUNKNOWN -1 +#define N2N_ENOTIMPL -2 +#define N2N_EINVAL -3 +#define N2N_ENOSPACE -4 + + +typedef uint16_t n2n_flags_t; +typedef uint16_t n2n_transform_t; /* Encryption, compression type. */ +typedef uint32_t n2n_sa_t; /* security association number */ + +struct n2n_sock +{ + uint8_t family; /* AF_INET or AF_INET6; or 0 if invalid */ + uint16_t port; /* host order */ + union + { + uint8_t v6[IPV6_SIZE]; /* byte sequence */ + uint8_t v4[IPV4_SIZE]; /* byte sequence */ + } addr; +}; + +typedef struct n2n_sock n2n_sock_t; + +struct n2n_auth +{ + uint16_t scheme; /* What kind of auth */ + uint16_t toksize; /* Size of auth token */ + uint8_t token[N2N_AUTH_TOKEN_SIZE]; /* Auth data interpreted based on scheme */ +}; + +typedef struct n2n_auth n2n_auth_t; + + +struct n2n_common +{ + /* int version; */ + uint8_t ttl; + n2n_pc_t pc; + n2n_flags_t flags; + n2n_community_t community; +}; + +typedef struct n2n_common n2n_common_t; + +struct n2n_REGISTER +{ + n2n_cookie_t cookie; /* Link REGISTER and REGISTER_ACK */ + n2n_mac_t srcMac; /* MAC of registering party */ + n2n_mac_t dstMac; /* MAC of target edge */ + n2n_sock_t sock; /* REVISIT: unused? */ +}; + +typedef struct n2n_REGISTER n2n_REGISTER_t; + +struct n2n_REGISTER_ACK +{ + n2n_cookie_t cookie; /* Return cookie from REGISTER */ + n2n_mac_t srcMac; /* MAC of acknowledging party (supernode or edge) */ + n2n_mac_t dstMac; /* Reflected MAC of registering edge from REGISTER */ + n2n_sock_t sock; /* Supernode's view of edge socket (IP Addr, port) */ +}; + +typedef struct n2n_REGISTER_ACK n2n_REGISTER_ACK_t; + +struct n2n_PACKET +{ + n2n_mac_t srcMac; + n2n_mac_t dstMac; + n2n_sock_t sock; + n2n_transform_t transform; +}; + +typedef struct n2n_PACKET n2n_PACKET_t; + + +/* Linked with n2n_register_super in n2n_pc_t. Only from edge to supernode. */ +struct n2n_REGISTER_SUPER +{ + n2n_cookie_t cookie; /* Link REGISTER_SUPER and REGISTER_SUPER_ACK */ + n2n_mac_t edgeMac; /* MAC to register with edge sending socket */ + n2n_auth_t auth; /* Authentication scheme and tokens */ +}; + +typedef struct n2n_REGISTER_SUPER n2n_REGISTER_SUPER_t; + + +/* Linked with n2n_register_super_ack in n2n_pc_t. Only from supernode to edge. */ +struct n2n_REGISTER_SUPER_ACK +{ + n2n_cookie_t cookie; /* Return cookie from REGISTER_SUPER */ + n2n_mac_t edgeMac; /* MAC registered to edge sending socket */ + uint16_t lifetime; /* How long the registration will live */ + n2n_sock_t sock; /* Sending sockets associated with edgeMac */ + + /* The packet format provides additional supernode definitions here. + * uint8_t count, then for each count there is one + * n2n_sock_t. + */ + uint8_t num_sn; /* Number of supernodes that were send + * even if we cannot store them all. If + * non-zero then sn_bak is valid. */ + n2n_sock_t sn_bak; /* Socket of the first backup supernode */ + +}; + +typedef struct n2n_REGISTER_SUPER_ACK n2n_REGISTER_SUPER_ACK_t; + + +/* Linked with n2n_register_super_ack in n2n_pc_t. Only from supernode to edge. */ +struct n2n_REGISTER_SUPER_NAK +{ + n2n_cookie_t cookie; /* Return cookie from REGISTER_SUPER */ +}; + +typedef struct n2n_REGISTER_SUPER_NAK n2n_REGISTER_SUPER_NAK_t; + + + +struct n2n_buf +{ + uint8_t * data; + size_t size; +}; + +typedef struct n2n_buf n2n_buf_t; + +int encode_uint8( uint8_t * base, + size_t * idx, + const uint8_t v ); + +int decode_uint8( uint8_t * out, + const uint8_t * base, + size_t * rem, + size_t * idx ); + +int encode_uint16( uint8_t * base, + size_t * idx, + const uint16_t v ); + +int decode_uint16( uint16_t * out, + const uint8_t * base, + size_t * rem, + size_t * idx ); + +int encode_uint32( uint8_t * base, + size_t * idx, + const uint32_t v ); + +int decode_uint32( uint32_t * out, + const uint8_t * base, + size_t * rem, + size_t * idx ); + +int encode_buf( uint8_t * base, + size_t * idx, + const void * p, + size_t s); + +int decode_buf( uint8_t * out, + size_t bufsize, + const uint8_t * base, + size_t * rem, + size_t * idx ); + +int encode_mac( uint8_t * base, + size_t * idx, + const n2n_mac_t m ); + +int decode_mac( uint8_t * out, /* of size N2N_MAC_SIZE. This clearer than passing a n2n_mac_t */ + const uint8_t * base, + size_t * rem, + size_t * idx ); + +int encode_common( uint8_t * base, + size_t * idx, + const n2n_common_t * common ); + +int decode_common( n2n_common_t * out, + const uint8_t * base, + size_t * rem, + size_t * idx ); + +int encode_sock( uint8_t * base, + size_t * idx, + const n2n_sock_t * sock ); + +int decode_sock( n2n_sock_t * sock, + const uint8_t * base, + size_t * rem, + size_t * idx ); + +int encode_REGISTER( uint8_t * base, + size_t * idx, + const n2n_common_t * common, + const n2n_REGISTER_t * reg ); + +int decode_REGISTER( n2n_REGISTER_t * pkt, + const n2n_common_t * cmn, /* info on how to interpret it */ + const uint8_t * base, + size_t * rem, + size_t * idx ); + +int encode_REGISTER_SUPER( uint8_t * base, + size_t * idx, + const n2n_common_t * common, + const n2n_REGISTER_SUPER_t * reg ); + +int decode_REGISTER_SUPER( n2n_REGISTER_SUPER_t * pkt, + const n2n_common_t * cmn, /* info on how to interpret it */ + const uint8_t * base, + size_t * rem, + size_t * idx ); + +int encode_REGISTER_ACK( uint8_t * base, + size_t * idx, + const n2n_common_t * common, + const n2n_REGISTER_ACK_t * reg ); + +int decode_REGISTER_ACK( n2n_REGISTER_ACK_t * pkt, + const n2n_common_t * cmn, /* info on how to interpret it */ + const uint8_t * base, + size_t * rem, + size_t * idx ); + +int encode_REGISTER_SUPER_ACK( uint8_t * base, + size_t * idx, + const n2n_common_t * cmn, + const n2n_REGISTER_SUPER_ACK_t * reg ); + +int decode_REGISTER_SUPER_ACK( n2n_REGISTER_SUPER_ACK_t * reg, + const n2n_common_t * cmn, /* info on how to interpret it */ + const uint8_t * base, + size_t * rem, + size_t * idx ); + +int fill_sockaddr( struct sockaddr * addr, + size_t addrlen, + const n2n_sock_t * sock ); + +int encode_PACKET( uint8_t * base, + size_t * idx, + const n2n_common_t * common, + const n2n_PACKET_t * pkt ); + +int decode_PACKET( n2n_PACKET_t * pkt, + const n2n_common_t * cmn, /* info on how to interpret it */ + const uint8_t * base, + size_t * rem, + size_t * idx ); + + +#endif /* #if !defined( N2N_WIRE_H_ ) */ diff --git a/openwrt/kamikaze/Makefile b/openwrt/kamikaze/Makefile new file mode 100644 index 0000000..ddcc7c1 --- /dev/null +++ b/openwrt/kamikaze/Makefile @@ -0,0 +1,55 @@ +# +# Copyright (C) 2008 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. + + +include $(TOPDIR)/rules.mk + +PKG_BRANCH:=trunk +PKG_SOURCE_URL:=https://svn.ntop.org/svn/ntop/trunk/n2n +PKG_REV:=$(shell LC_ALL=C svn info ${PKG_SOURCE_URL} | sed -ne's/^Last Changed Rev: //p') + +PKG_NAME:=n2n +PKG_VERSION:=svn$(PKG_REV) +PKG_RELEASE:=1 + +PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) +PKG_SOURCE:=$(PKG_SOURCE_SUBDIR).tar.gz +PKG_SOURCE_PROTO:=svn +PKG_SOURCE_VERSION:=$(PKG_REV) + +PKG_BUILD_DEPENDS:= + +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) +PKG_INSTALL_DIR:=$(PKG_BUILD_DIR) + + + +include $(INCLUDE_DIR)/package.mk + +define Package/n2n + SECTION:=net + CATEGORY:=Network + TITLE:=VPN tunneling daemon + URL:=http://www.ntop.org/n2n/ + SUBMENU:=VPN + DEPENDS:=libpthread +endef + + +define Build/Configure +endef + +define Build/Compile + $(MAKE) CC="$(TARGET_CC)" -C $(PKG_BUILD_DIR) +endef + + +define Package/n2n/install + $(INSTALL_DIR) $(1)/usr/sbin + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/edge $(1)/usr/sbin/ + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/supernode $(1)/usr/sbin/ +endef + +$(eval $(call BuildPackage,n2n)) diff --git a/scripts/mk_SRPM.sh b/scripts/mk_SRPM.sh new file mode 100755 index 0000000..2b1b374 --- /dev/null +++ b/scripts/mk_SRPM.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +# This script makes a SRPM - a source RPM file which can be built into the +# appropriate distro specific RPM for any platform. +# +# To build the binary package: +# rpm -i n2n-.src.rpm +# rpmbuild -bb n2n.spec +# +# Look for the "Wrote:" line to see where the final RPM is. +# +# To run this script cd to the n2n directory and run it as follows +# scripts/mk_SRPMS.sh +# + +set -e + +set -x + +BASE=`pwd` + +TARFILE=`${BASE}/scripts/mk_tar.sh` + +test -f ${TARFILE} + +echo "Building SRPM" +# -ts means build source RPM from tarfile +rpmbuild -ts ${TARFILE} + +echo "Done" diff --git a/scripts/mk_deb.sh b/scripts/mk_deb.sh new file mode 100755 index 0000000..42d8691 --- /dev/null +++ b/scripts/mk_deb.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +# This script makes a SRPM - a source RPM file which can be built into the +# appropriate distro specific RPM for any platform. +# +# To build the binary package: +# rpm -i n2n-.src.rpm +# rpmbuild -bb n2n.spec +# +# Look for the "Wrote:" line to see where the final RPM is. +# +# To run this script cd to the n2n directory and run it as follows +# scripts/mk_SRPMS.sh +# + +set -e + +set -x + +BASE=`pwd` + +TARFILE=`${BASE}/scripts/mk_tar.sh` +TEMPDIR="build_deb" + +test -f ${TARFILE} + +echo "Building .deb" + +if [ -d ${TEMPDIR} ]; then + echo "Removing ${TEMPDIR} directory" + rm -rf ${TEMPDIR} >&2 +fi + +mkdir ${TEMPDIR} + +pushd ${TEMPDIR} + +tar xzf ${TARFILE} #At original location + +cd n2n* + +dpkg-buildpackage -rfakeroot + +popd + +echo "Done" diff --git a/scripts/mk_tar.sh b/scripts/mk_tar.sh new file mode 100755 index 0000000..0e84331 --- /dev/null +++ b/scripts/mk_tar.sh @@ -0,0 +1,116 @@ +#!/bin/bash + +# This script makes a SRPM - a source RPM file which can be built into the +# appropriate distro specific RPM for any platform. +# +# To build the binary package: +# rpm -i n2n-.src.rpm +# rpmbuild -bb n2n.spec +# +# Look for the "Wrote:" line to see where the final RPM is. +# +# To run this script cd to the n2n directory and run it as follows +# scripts/mk_SRPMS.sh +# + +set -e + +function exit_fail() +{ + echo "$1" + exit 1 +} + +PACKAGE="n2n" +PKG_VERSION="2.1.0" +PKG_AND_VERSION="${PACKAGE}-${PKG_VERSION}" + +TEMPDIR="tmp" + +SOURCE_MANIFEST=" +README +edge.c +lzoconf.h +lzodefs.h +Makefile +minilzo.c +minilzo.h +n2n.c +n2n.h +n2n_keyfile.c +n2n_keyfile.h +n2n.spec +n2n_transforms.h +n2n_wire.h +sn.c +transform_aes.c +transform_null.c +transform_tf.c +tuntap_linux.c +tuntap_freebsd.c +tuntap_netbsd.c +tuntap_osx.c +twofish.c +twofish.h +version.c +wire.c +edge.8 +supernode.1 +n2n_v2.7 +debian/changelog +debian/compat +debian/control +debian/copyright +debian/n2n-edge.docs +debian/n2n-edge.install +debian/n2n-supernode.install +debian/n2n-edge.manpages +debian/n2n-supernode.manpages +debian/README.Debian +debian/rules +" + +BASE=`pwd` + +for F in ${SOURCE_MANIFEST}; do + test -e $F || exit_fail "Cannot find $F. Maybe you're in the wrong directory. Please execute from n2n directory."; >&2 +done + +echo "Found critical files. Proceeding." >&2 + +if [ -d ${TEMPDIR} ]; then + echo "Removing ${TEMPDIR} directory" + rm -rf ${TEMPDIR} >&2 +fi + +mkdir ${TEMPDIR} >&2 + +pushd ${TEMPDIR} >&2 + +echo "Creating staging directory ${PWD}/${PKG_AND_VERSION}" >&2 + +if [ -d ${PKG_AND_VERSION} ] ; then + echo "Removing ${PKG_AND_VERSION} directory" + rm -rf ${PKG_AND_VERSION} >&2 +fi + +mkdir ${PKG_AND_VERSION} + +pushd ${BASE} >&2 + +echo "Copying in files" >&2 +for F in ${SOURCE_MANIFEST}; do + cp --parents -a $F ${TEMPDIR}/${PKG_AND_VERSION}/ +done + +popd >&2 + +TARFILE="${PKG_AND_VERSION}.tar.gz" +echo "Creating ${TARFILE}" >&2 +tar czf ${BASE}/${TARFILE} ${PKG_AND_VERSION} + +popd >&2 + +rm -rf ${TEMPDIR} >&2 + +echo ${BASE}/${TARFILE} diff --git a/sn.c b/sn.c new file mode 100644 index 0000000..7df4729 --- /dev/null +++ b/sn.c @@ -0,0 +1,793 @@ +/* Supernode for n2n-2.x */ + +/* (c) 2009 Richard Andrews + * + * Contributions by: + * Lukasz Taczuk + * Struan Bartlett + */ + + +#include "n2n.h" + + +#define N2N_SN_LPORT_DEFAULT 7654 +#define N2N_SN_PKTBUF_SIZE 2048 + +#define N2N_SN_MGMT_PORT 5645 + + +struct sn_stats +{ + size_t errors; /* Number of errors encountered. */ + size_t reg_super; /* Number of REGISTER_SUPER requests received. */ + size_t reg_super_nak; /* Number of REGISTER_SUPER requests declined. */ + size_t fwd; /* Number of messages forwarded. */ + size_t broadcast; /* Number of messages broadcast to a community. */ + time_t last_fwd; /* Time when last message was forwarded. */ + time_t last_reg_super; /* Time when last REGISTER_SUPER was received. */ +}; + +typedef struct sn_stats sn_stats_t; + +struct n2n_sn +{ + time_t start_time; /* Used to measure uptime. */ + sn_stats_t stats; + int daemon; /* If non-zero then daemonise. */ + uint16_t lport; /* Local UDP port to bind to. */ + int sock; /* Main socket for UDP traffic with edges. */ + int mgmt_sock; /* management socket. */ + struct peer_info * edges; /* Link list of registered edges. */ +}; + +typedef struct n2n_sn n2n_sn_t; + + +static int try_forward( n2n_sn_t * sss, + const n2n_common_t * cmn, + const n2n_mac_t dstMac, + const uint8_t * pktbuf, + size_t pktsize ); + +static int try_broadcast( n2n_sn_t * sss, + const n2n_common_t * cmn, + const n2n_mac_t srcMac, + const uint8_t * pktbuf, + size_t pktsize ); + + + +/** Initialise the supernode structure */ +static int init_sn( n2n_sn_t * sss ) +{ +#ifdef WIN32 + initWin32(); +#endif + memset( sss, 0, sizeof(n2n_sn_t) ); + + sss->daemon = 1; /* By defult run as a daemon. */ + sss->lport = N2N_SN_LPORT_DEFAULT; + sss->sock = -1; + sss->mgmt_sock = -1; + sss->edges = NULL; + + return 0; /* OK */ +} + +/** Deinitialise the supernode structure and deallocate any memory owned by + * it. */ +static void deinit_sn( n2n_sn_t * sss ) +{ + if (sss->sock >= 0) + { + closesocket(sss->sock); + } + sss->sock=-1; + + if ( sss->mgmt_sock >= 0 ) + { + closesocket(sss->mgmt_sock); + } + sss->mgmt_sock=-1; + + purge_peer_list( &(sss->edges), 0xffffffff ); +} + + +/** Determine the appropriate lifetime for new registrations. + * + * If the supernode has been put into a pre-shutdown phase then this lifetime + * should not allow registrations to continue beyond the shutdown point. + */ +static uint16_t reg_lifetime( n2n_sn_t * sss ) +{ + return 120; +} + + +/** Update the edge table with the details of the edge which contacted the + * supernode. */ +static int update_edge( n2n_sn_t * sss, + const n2n_mac_t edgeMac, + const n2n_community_t community, + const n2n_sock_t * sender_sock, + time_t now) +{ + macstr_t mac_buf; + n2n_sock_str_t sockbuf; + struct peer_info * scan; + + traceEvent( TRACE_DEBUG, "update_edge for %s [%s]", + macaddr_str( mac_buf, edgeMac ), + sock_to_cstr( sockbuf, sender_sock ) ); + + scan = find_peer_by_mac( sss->edges, edgeMac ); + + if ( NULL == scan ) + { + /* Not known */ + + scan = (struct peer_info*)calloc(1, sizeof(struct peer_info)); /* deallocated in purge_expired_registrations */ + + memcpy(scan->community_name, community, sizeof(n2n_community_t) ); + memcpy(&(scan->mac_addr), edgeMac, sizeof(n2n_mac_t)); + memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t)); + + /* insert this guy at the head of the edges list */ + scan->next = sss->edges; /* first in list */ + sss->edges = scan; /* head of list points to new scan */ + + traceEvent( TRACE_INFO, "update_edge created %s ==> %s", + macaddr_str( mac_buf, edgeMac ), + sock_to_cstr( sockbuf, sender_sock ) ); + } + else + { + /* Known */ + if ( (0 != memcmp(community, scan->community_name, sizeof(n2n_community_t))) || + (0 != sock_equal(sender_sock, &(scan->sock) )) ) + { + memcpy(scan->community_name, community, sizeof(n2n_community_t) ); + memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t)); + + traceEvent( TRACE_INFO, "update_edge updated %s ==> %s", + macaddr_str( mac_buf, edgeMac ), + sock_to_cstr( sockbuf, sender_sock ) ); + } + else + { + traceEvent( TRACE_DEBUG, "update_edge unchanged %s ==> %s", + macaddr_str( mac_buf, edgeMac ), + sock_to_cstr( sockbuf, sender_sock ) ); + } + + } + + scan->last_seen = now; + return 0; +} + + +/** Send a datagram to the destination embodied in a n2n_sock_t. + * + * @return -1 on error otherwise number of bytes sent + */ +static ssize_t sendto_sock(n2n_sn_t * sss, + const n2n_sock_t * sock, + const uint8_t * pktbuf, + size_t pktsize) +{ + n2n_sock_str_t sockbuf; + + if ( AF_INET == sock->family ) + { + struct sockaddr_in udpsock; + + udpsock.sin_family = AF_INET; + udpsock.sin_port = htons( sock->port ); + memcpy( &(udpsock.sin_addr.s_addr), &(sock->addr.v4), IPV4_SIZE ); + + traceEvent( TRACE_DEBUG, "sendto_sock %lu to [%s]", + pktsize, + sock_to_cstr( sockbuf, sock ) ); + + return sendto( sss->sock, pktbuf, pktsize, 0, + (const struct sockaddr *)&udpsock, sizeof(struct sockaddr_in) ); + } + else + { + /* AF_INET6 not implemented */ + errno = EAFNOSUPPORT; + return -1; + } +} + + + +/** Try to forward a message to a unicast MAC. If the MAC is unknown then + * broadcast to all edges in the destination community. + */ +static int try_forward( n2n_sn_t * sss, + const n2n_common_t * cmn, + const n2n_mac_t dstMac, + const uint8_t * pktbuf, + size_t pktsize ) +{ + struct peer_info * scan; + macstr_t mac_buf; + n2n_sock_str_t sockbuf; + + scan = find_peer_by_mac( sss->edges, dstMac ); + + if ( NULL != scan ) + { + int data_sent_len; + data_sent_len = sendto_sock( sss, &(scan->sock), pktbuf, pktsize ); + + if ( data_sent_len == pktsize ) + { + ++(sss->stats.fwd); + traceEvent(TRACE_DEBUG, "unicast %lu to [%s] %s", + pktsize, + sock_to_cstr( sockbuf, &(scan->sock) ), + macaddr_str(mac_buf, scan->mac_addr)); + } + else + { + ++(sss->stats.errors); + traceEvent(TRACE_ERROR, "unicast %lu to [%s] %s FAILED (%d: %s)", + pktsize, + sock_to_cstr( sockbuf, &(scan->sock) ), + macaddr_str(mac_buf, scan->mac_addr), + errno, strerror(errno) ); + } + } + else + { + traceEvent( TRACE_DEBUG, "try_forward unknown MAC" ); + + /* Not a known MAC so drop. */ + } + + return 0; +} + + +/** Try and broadcast a message to all edges in the community. + * + * This will send the exact same datagram to zero or more edges registered to + * the supernode. + */ +static int try_broadcast( n2n_sn_t * sss, + const n2n_common_t * cmn, + const n2n_mac_t srcMac, + const uint8_t * pktbuf, + size_t pktsize ) +{ + struct peer_info * scan; + macstr_t mac_buf; + n2n_sock_str_t sockbuf; + + traceEvent( TRACE_DEBUG, "try_broadcast" ); + + scan = sss->edges; + while(scan != NULL) + { + if( 0 == (memcmp(scan->community_name, cmn->community, sizeof(n2n_community_t)) ) + && (0 != memcmp(srcMac, scan->mac_addr, sizeof(n2n_mac_t)) ) ) + /* REVISIT: exclude if the destination socket is where the packet came from. */ + { + int data_sent_len; + + data_sent_len = sendto_sock(sss, &(scan->sock), pktbuf, pktsize); + + if(data_sent_len != pktsize) + { + ++(sss->stats.errors); + traceEvent(TRACE_WARNING, "multicast %lu to [%s] %s failed %s", + pktsize, + sock_to_cstr( sockbuf, &(scan->sock) ), + macaddr_str(mac_buf, scan->mac_addr), + strerror(errno)); + } + else + { + ++(sss->stats.broadcast); + traceEvent(TRACE_DEBUG, "multicast %lu to [%s] %s", + pktsize, + sock_to_cstr( sockbuf, &(scan->sock) ), + macaddr_str(mac_buf, scan->mac_addr)); + } + } + + scan = scan->next; + } /* while */ + + return 0; +} + + +static int process_mgmt( n2n_sn_t * sss, + const struct sockaddr_in * sender_sock, + const uint8_t * mgmt_buf, + size_t mgmt_size, + time_t now) +{ + char resbuf[N2N_SN_PKTBUF_SIZE]; + size_t ressize=0; + ssize_t r; + + traceEvent( TRACE_DEBUG, "process_mgmt" ); + + ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize, + "----------------\n" ); + + ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize, + "uptime %lu\n", (now - sss->start_time) ); + + ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize, + "edges %u\n", + (unsigned int)peer_list_size( sss->edges ) ); + + ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize, + "errors %u\n", + (unsigned int)sss->stats.errors ); + + ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize, + "reg_sup %u\n", + (unsigned int)sss->stats.reg_super ); + + ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize, + "reg_nak %u\n", + (unsigned int)sss->stats.reg_super_nak ); + + ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize, + "fwd %u\n", + (unsigned int) sss->stats.fwd ); + + ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize, + "broadcast %u\n", + (unsigned int) sss->stats.broadcast ); + + ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize, + "last fwd %lu sec ago\n", + (long unsigned int)(now - sss->stats.last_fwd) ); + + ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize, + "last reg %lu sec ago\n", + (long unsigned int) (now - sss->stats.last_reg_super) ); + + + r = sendto( sss->mgmt_sock, resbuf, ressize, 0/*flags*/, + (struct sockaddr *)sender_sock, sizeof(struct sockaddr_in) ); + + if ( r <= 0 ) + { + ++(sss->stats.errors); + traceEvent( TRACE_ERROR, "process_mgmt : sendto failed. %s", strerror(errno) ); + } + + return 0; +} + + +/** Examine a datagram and determine what to do with it. + * + */ +static int process_udp( n2n_sn_t * sss, + const struct sockaddr_in * sender_sock, + const uint8_t * udp_buf, + size_t udp_size, + time_t now) +{ + n2n_common_t cmn; /* common fields in the packet header */ + size_t rem; + size_t idx; + size_t msg_type; + uint8_t from_supernode; + macstr_t mac_buf; + macstr_t mac_buf2; + n2n_sock_str_t sockbuf; + + + traceEvent( TRACE_DEBUG, "process_udp(%lu)", udp_size ); + + /* Use decode_common() to determine the kind of packet then process it: + * + * REGISTER_SUPER adds an edge and generate a return REGISTER_SUPER_ACK + * + * REGISTER, REGISTER_ACK and PACKET messages are forwarded to their + * destination edge. If the destination is not known then PACKETs are + * broadcast. + */ + + rem = udp_size; /* Counts down bytes of packet to protect against buffer overruns. */ + idx = 0; /* marches through packet header as parts are decoded. */ + if ( decode_common(&cmn, udp_buf, &rem, &idx) < 0 ) + { + traceEvent( TRACE_ERROR, "Failed to decode common section" ); + return -1; /* failed to decode packet */ + } + + msg_type = cmn.pc; /* packet code */ + from_supernode= cmn.flags & N2N_FLAGS_FROM_SUPERNODE; + + if ( cmn.ttl < 1 ) + { + traceEvent( TRACE_WARNING, "Expired TTL" ); + return 0; /* Don't process further */ + } + + --(cmn.ttl); /* The value copied into all forwarded packets. */ + + if ( msg_type == MSG_TYPE_PACKET ) + { + /* PACKET from one edge to another edge via supernode. */ + + /* pkt will be modified in place and recoded to an output of potentially + * different size due to addition of the socket.*/ + n2n_PACKET_t pkt; + n2n_common_t cmn2; + uint8_t encbuf[N2N_SN_PKTBUF_SIZE]; + size_t encx=0; + int unicast; /* non-zero if unicast */ + const uint8_t * rec_buf; /* either udp_buf or encbuf */ + + + sss->stats.last_fwd=now; + decode_PACKET( &pkt, &cmn, udp_buf, &rem, &idx ); + + unicast = (0 == is_multi_broadcast(pkt.dstMac) ); + + traceEvent( TRACE_DEBUG, "Rx PACKET (%s) %s -> %s %s", + (unicast?"unicast":"multicast"), + macaddr_str( mac_buf, pkt.srcMac ), + macaddr_str( mac_buf2, pkt.dstMac ), + (from_supernode?"from sn":"local") ); + + if ( !from_supernode ) + { + memcpy( &cmn2, &cmn, sizeof( n2n_common_t ) ); + + /* We are going to add socket even if it was not there before */ + cmn2.flags |= N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE; + + pkt.sock.family = AF_INET; + pkt.sock.port = ntohs(sender_sock->sin_port); + memcpy( pkt.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE ); + + rec_buf = encbuf; + + /* Re-encode the header. */ + encode_PACKET( encbuf, &encx, &cmn2, &pkt ); + + /* Copy the original payload unchanged */ + encode_buf( encbuf, &encx, (udp_buf + idx), (udp_size - idx ) ); + } + else + { + /* Already from a supernode. Nothing to modify, just pass to + * destination. */ + + traceEvent( TRACE_DEBUG, "Rx PACKET fwd unmodified" ); + + rec_buf = udp_buf; + encx = udp_size; + } + + /* Common section to forward the final product. */ + if ( unicast ) + { + try_forward( sss, &cmn, pkt.dstMac, rec_buf, encx ); + } + else + { + try_broadcast( sss, &cmn, pkt.srcMac, rec_buf, encx ); + } + }/* MSG_TYPE_PACKET */ + else if ( msg_type == MSG_TYPE_REGISTER ) + { + /* Forwarding a REGISTER from one edge to the next */ + + n2n_REGISTER_t reg; + n2n_common_t cmn2; + uint8_t encbuf[N2N_SN_PKTBUF_SIZE]; + size_t encx=0; + int unicast; /* non-zero if unicast */ + const uint8_t * rec_buf; /* either udp_buf or encbuf */ + + sss->stats.last_fwd=now; + decode_REGISTER( ®, &cmn, udp_buf, &rem, &idx ); + + unicast = (0 == is_multi_broadcast(reg.dstMac) ); + + if ( unicast ) + { + traceEvent( TRACE_DEBUG, "Rx REGISTER %s -> %s %s", + macaddr_str( mac_buf, reg.srcMac ), + macaddr_str( mac_buf2, reg.dstMac ), + ((cmn.flags & N2N_FLAGS_FROM_SUPERNODE)?"from sn":"local") ); + + if ( 0 != (cmn.flags & N2N_FLAGS_FROM_SUPERNODE) ) + { + memcpy( &cmn2, &cmn, sizeof( n2n_common_t ) ); + + /* We are going to add socket even if it was not there before */ + cmn2.flags |= N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE; + + reg.sock.family = AF_INET; + reg.sock.port = ntohs(sender_sock->sin_port); + memcpy( reg.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE ); + + rec_buf = encbuf; + + /* Re-encode the header. */ + encode_REGISTER( encbuf, &encx, &cmn2, ® ); + + /* Copy the original payload unchanged */ + encode_buf( encbuf, &encx, (udp_buf + idx), (udp_size - idx ) ); + } + else + { + /* Already from a supernode. Nothing to modify, just pass to + * destination. */ + + rec_buf = udp_buf; + encx = udp_size; + } + + try_forward( sss, &cmn, reg.dstMac, rec_buf, encx ); /* unicast only */ + } + else + { + traceEvent( TRACE_ERROR, "Rx REGISTER with multicast destination" ); + } + + } + else if ( msg_type == MSG_TYPE_REGISTER_ACK ) + { + traceEvent( TRACE_DEBUG, "Rx REGISTER_ACK (NOT IMPLEMENTED) SHould not be via supernode" ); + } + else if ( msg_type == MSG_TYPE_REGISTER_SUPER ) + { + n2n_REGISTER_SUPER_t reg; + n2n_REGISTER_SUPER_ACK_t ack; + n2n_common_t cmn2; + uint8_t ackbuf[N2N_SN_PKTBUF_SIZE]; + size_t encx=0; + + /* Edge requesting registration with us. */ + + sss->stats.last_reg_super=now; + ++(sss->stats.reg_super); + decode_REGISTER_SUPER( ®, &cmn, udp_buf, &rem, &idx ); + + cmn2.ttl = N2N_DEFAULT_TTL; + cmn2.pc = n2n_register_super_ack; + cmn2.flags = N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE; + memcpy( cmn2.community, cmn.community, sizeof(n2n_community_t) ); + + memcpy( &(ack.cookie), &(reg.cookie), sizeof(n2n_cookie_t) ); + memcpy( ack.edgeMac, reg.edgeMac, sizeof(n2n_mac_t) ); + ack.lifetime = reg_lifetime( sss ); + + ack.sock.family = AF_INET; + ack.sock.port = ntohs(sender_sock->sin_port); + memcpy( ack.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE ); + + ack.num_sn=0; /* No backup */ + memset( &(ack.sn_bak), 0, sizeof(n2n_sock_t) ); + + traceEvent( TRACE_DEBUG, "Rx REGISTER_SUPER for %s [%s]", + macaddr_str( mac_buf, reg.edgeMac ), + sock_to_cstr( sockbuf, &(ack.sock) ) ); + + update_edge( sss, reg.edgeMac, cmn.community, &(ack.sock), now ); + + encode_REGISTER_SUPER_ACK( ackbuf, &encx, &cmn2, &ack ); + + sendto( sss->sock, ackbuf, encx, 0, + (struct sockaddr *)sender_sock, sizeof(struct sockaddr_in) ); + + traceEvent( TRACE_DEBUG, "Tx REGISTER_SUPER_ACK for %s [%s]", + macaddr_str( mac_buf, reg.edgeMac ), + sock_to_cstr( sockbuf, &(ack.sock) ) ); + + } + + + return 0; +} + + +/** Help message to print if the command line arguments are not valid. */ +static void exit_help(int argc, char * const argv[]) +{ + fprintf( stderr, "%s usage\n", argv[0] ); + fprintf( stderr, "-l \tSet UDP main listen port to \n" ); + +#if defined(N2N_HAVE_DAEMON) + fprintf( stderr, "-f \tRun in foreground.\n" ); +#endif /* #if defined(N2N_HAVE_DAEMON) */ + fprintf( stderr, "-v \tIncrease verbosity. Can be used multiple times.\n" ); + fprintf( stderr, "-h \tThis help message.\n" ); + fprintf( stderr, "\n" ); + exit(1); +} + +static int run_loop( n2n_sn_t * sss ); + +/* *********************************************** */ + +static const struct option long_options[] = { + { "foreground", no_argument, NULL, 'f' }, + { "local-port", required_argument, NULL, 'l' }, + { "help" , no_argument, NULL, 'h' }, + { "verbose", no_argument, NULL, 'v' }, + { NULL, 0, NULL, 0 } +}; + +/** Main program entry point from kernel. */ +int main( int argc, char * const argv[] ) +{ + n2n_sn_t sss; + + init_sn( &sss ); + + { + int opt; + + while((opt = getopt_long(argc, argv, "fl:vh", long_options, NULL)) != -1) + { + switch (opt) + { + case 'l': /* local-port */ + sss.lport = atoi(optarg); + break; + case 'f': /* foreground */ + sss.daemon = 0; + break; + case 'h': /* help */ + exit_help(argc, argv); + break; + case 'v': /* verbose */ + ++traceLevel; + break; + } + } + + } + +#if defined(N2N_HAVE_DAEMON) + if (sss.daemon) + { + useSyslog=1; /* traceEvent output now goes to syslog. */ + if ( -1 == daemon( 0, 0 ) ) + { + traceEvent( TRACE_ERROR, "Failed to become daemon." ); + exit(-5); + } + } +#endif /* #if defined(N2N_HAVE_DAEMON) */ + + traceEvent( TRACE_DEBUG, "traceLevel is %d", traceLevel); + + sss.sock = open_socket(sss.lport, 1 /*bind ANY*/ ); + if ( -1 == sss.sock ) + { + traceEvent( TRACE_ERROR, "Failed to open main socket. %s", strerror(errno) ); + exit(-2); + } + else + { + traceEvent( TRACE_NORMAL, "supernode is listening on UDP %u (main)", sss.lport ); + } + + sss.mgmt_sock = open_socket(N2N_SN_MGMT_PORT, 0 /* bind LOOPBACK */ ); + if ( -1 == sss.mgmt_sock ) + { + traceEvent( TRACE_ERROR, "Failed to open management socket. %s", strerror(errno) ); + exit(-2); + } + else + { + traceEvent( TRACE_NORMAL, "supernode is listening on UDP %u (management)", N2N_SN_MGMT_PORT ); + } + + traceEvent(TRACE_NORMAL, "supernode started"); + + return run_loop(&sss); +} + + +/** Long lived processing entry point. Split out from main to simply + * daemonisation on some platforms. */ +static int run_loop( n2n_sn_t * sss ) +{ + uint8_t pktbuf[N2N_SN_PKTBUF_SIZE]; + int keep_running=1; + + sss->start_time = time(NULL); + + while(keep_running) + { + int rc; + ssize_t bread; + int max_sock; + fd_set socket_mask; + struct timeval wait_time; + time_t now=0; + + FD_ZERO(&socket_mask); + max_sock = MAX(sss->sock, sss->mgmt_sock); + + FD_SET(sss->sock, &socket_mask); + FD_SET(sss->mgmt_sock, &socket_mask); + + wait_time.tv_sec = 10; wait_time.tv_usec = 0; + rc = select(max_sock+1, &socket_mask, NULL, NULL, &wait_time); + + now = time(NULL); + + if(rc > 0) + { + if (FD_ISSET(sss->sock, &socket_mask)) + { + struct sockaddr_in sender_sock; + socklen_t i; + + i = sizeof(sender_sock); + bread = recvfrom( sss->sock, pktbuf, N2N_SN_PKTBUF_SIZE, 0/*flags*/, + (struct sockaddr *)&sender_sock, (socklen_t*)&i); + + if ( bread < 0 ) /* For UDP bread of zero just means no data (unlike TCP). */ + { + /* The fd is no good now. Maybe we lost our interface. */ + traceEvent( TRACE_ERROR, "recvfrom() failed %d errno %d (%s)", bread, errno, strerror(errno) ); + keep_running=0; + break; + } + + /* We have a datagram to process */ + if ( bread > 0 ) + { + /* And the datagram has data (not just a header) */ + process_udp( sss, &sender_sock, pktbuf, bread, now ); + } + } + + if (FD_ISSET(sss->mgmt_sock, &socket_mask)) + { + struct sockaddr_in sender_sock; + size_t i; + + i = sizeof(sender_sock); + bread = recvfrom( sss->mgmt_sock, pktbuf, N2N_SN_PKTBUF_SIZE, 0/*flags*/, + (struct sockaddr *)&sender_sock, (socklen_t*)&i); + + if ( bread <= 0 ) + { + traceEvent( TRACE_ERROR, "recvfrom() failed %d errno %d (%s)", bread, errno, strerror(errno) ); + keep_running=0; + break; + } + + /* We have a datagram to process */ + process_mgmt( sss, &sender_sock, pktbuf, bread, now ); + } + } + else + { + traceEvent( TRACE_DEBUG, "timeout" ); + } + + purge_expired_registrations( &(sss->edges) ); + + } /* while */ + + deinit_sn( sss ); + + return 0; +} + diff --git a/supernode.1 b/supernode.1 new file mode 100644 index 0000000..26b1f70 --- /dev/null +++ b/supernode.1 @@ -0,0 +1,43 @@ +.TH supernode 1 "Jan 3, 2009" "revision 3679" "USER COMMANDS" +.SH NAME +supernode \- n2n supernode daemon +.SH SYNOPSIS +.B supernode \-l [\-v] +.SH DESCRIPTION +N2N is a peer-to-peer VPN system. Supernode is a node introduction registry, +broadcast conduit and packet relay node for the n2n system. On startup supernode +begins listening on the specified UDP port for node registrations, and other +packets to route. The supernode can service any number of communities and routes +packets only between members of the same community. The supernode does not hold +the community encryption key and so cannot snoop or inject packets into the +community. +.PP +Supernode can service a number of n2n communities concurrently. Traffic does not +cross between communities. +.PP +All logging goes to stdout. +.SH OPTIONS +.TP +\-l +listen on the given UDP port +.TP +\-v +use verbose logging +.TP +\-f +disable daemon mode (UNIX) and run in foreground. +.SH EXAMPLES +.TP +.B supernode -l 7654 -v +Start supernode listening on UDP port 7654 with verbose output. +.PP +.SH RESTART +When suprenode restarts it loses all registration information from associated +edge nodes. It can take up to five minutes for the edge nodes to re-register and +normal traffic flow to resume. +.SH EXIT STATUS +supernode is a daemon and any exit is an error +.SH AUTHOR +Luca Deri ( deri (at) ntop.org ), Richard Andrews ( andrews (at) ntop.org ), Don Bindner +.SH SEE ALSO +ifconfig(8) edge(8) diff --git a/test.c b/test.c new file mode 100644 index 0000000..97ec91b --- /dev/null +++ b/test.c @@ -0,0 +1,24 @@ +#include "n2n.h" +#include "n2n_keyfile.h" +#include +#include +#include + +int main(int arc, const char * argv[] ) +{ + int e; + n2n_cipherspec_t specs[N2N_MAX_NUM_CIPHERSPECS]; + + e = n2n_read_keyfile( specs, N2N_MAX_NUM_CIPHERSPECS, "keyctrl.conf" ); + + if ( e < 0 ) + { + perror( "Failed to read keyfile" ); + } + else + { + fprintf( stderr, "Stored %d keys.\n", e ); + } + + return 0; +} diff --git a/transform_aes.c b/transform_aes.c new file mode 100644 index 0000000..a8c4969 --- /dev/null +++ b/transform_aes.c @@ -0,0 +1,597 @@ +/* (c) 2009 Richard Andrews */ +/* Contributions from: + * - Jozef Kralik + */ + +#include "n2n.h" +#include "n2n_transforms.h" + +#if defined(N2N_HAVE_AES) + + +#include "openssl/aes.h" +#ifndef _MSC_VER +/* Not included in Visual Studio 2008 */ +#include /* index() */ +#endif + +#define N2N_AES_NUM_SA 32 /* space for SAa */ + +#define N2N_AES_TRANSFORM_VERSION 1 /* version of the transform encoding */ +#define N2N_AES_IVEC_SIZE 32 /* Enough space for biggest AES ivec */ + +typedef unsigned char n2n_aes_ivec_t[N2N_AES_IVEC_SIZE]; + +struct sa_aes +{ + n2n_cipherspec_t spec; /* cipher spec parameters */ + n2n_sa_t sa_id; /* security association index */ + AES_KEY enc_key; /* tx key */ + n2n_aes_ivec_t enc_ivec; /* tx CBC state */ + AES_KEY dec_key; /* tx key */ + n2n_aes_ivec_t dec_ivec; /* tx CBC state */ +}; + +typedef struct sa_aes sa_aes_t; + + +/** Aes transform state data. + * + * With a key-schedule in place this will be populated with a number of + * SAs. Each SA has a lifetime and some opque data. The opaque data for aes + * consists of the SA number and key material. + * + */ +struct transop_aes +{ + ssize_t tx_sa; + size_t num_sa; + sa_aes_t sa[N2N_AES_NUM_SA]; +}; + +typedef struct transop_aes transop_aes_t; + +static int transop_deinit_aes( n2n_trans_op_t * arg ) +{ + transop_aes_t * priv = (transop_aes_t *)arg->priv; + size_t i; + + if ( priv ) + { + /* Memory was previously allocated */ + for (i=0; isa[i]); + + sa->sa_id=0; + } + + priv->num_sa=0; + priv->tx_sa=-1; + + free(priv); + } + + arg->priv=NULL; /* return to fully uninitialised state */ + + return 0; +} + +static size_t aes_choose_tx_sa( transop_aes_t * priv ) +{ + return priv->tx_sa; /* set in tick */ +} + +#define TRANSOP_AES_VER_SIZE 1 /* Support minor variants in encoding in one module. */ +#define TRANSOP_AES_NONCE_SIZE 4 +#define TRANSOP_AES_SA_SIZE 4 + + +#define AES256_KEY_BYTES (256/8) +#define AES192_KEY_BYTES (192/8) +#define AES128_KEY_BYTES (128/8) + +/* Return the best acceptable AES key size (in bytes) given an input keysize. + * + * The value returned will be one of AES128_KEY_BYTES, AES192_KEY_BYTES or + * AES256_KEY_BYTES. + */ +static size_t aes_best_keysize(size_t numBytes) +{ + if (numBytes >= AES256_KEY_BYTES ) + { + return AES256_KEY_BYTES; + } + else if (numBytes >= AES192_KEY_BYTES) + { + return AES192_KEY_BYTES; + } + else + { + return AES128_KEY_BYTES; + } +} + +/** The aes packet format consists of: + * + * - a 8-bit aes encoding version in clear text + * - a 32-bit SA number in clear text + * - ciphertext encrypted from a 32-bit nonce followed by the payload. + * + * [V|SSSS|nnnnDDDDDDDDDDDDDDDDDDDDD] + * |<------ encrypted ------>| + */ +static int transop_encode_aes( n2n_trans_op_t * arg, + uint8_t * outbuf, + size_t out_len, + const uint8_t * inbuf, + size_t in_len ) +{ + int len2=-1; + transop_aes_t * priv = (transop_aes_t *)arg->priv; + uint8_t assembly[N2N_PKT_BUF_SIZE]; + uint32_t * pnonce; + + if ( (in_len + TRANSOP_AES_NONCE_SIZE) <= N2N_PKT_BUF_SIZE ) + { + if ( (in_len + TRANSOP_AES_NONCE_SIZE + TRANSOP_AES_SA_SIZE + TRANSOP_AES_VER_SIZE) <= out_len ) + { + int len=-1; + size_t idx=0; + sa_aes_t * sa; + size_t tx_sa_num = 0; + + /* The transmit sa is periodically updated */ + tx_sa_num = aes_choose_tx_sa( priv ); + + sa = &(priv->sa[tx_sa_num]); /* Proper Tx SA index */ + + traceEvent( TRACE_DEBUG, "encode_aes %lu with SA %lu.", in_len, sa->sa_id ); + + /* Encode the aes format version. */ + encode_uint8( outbuf, &idx, N2N_AES_TRANSFORM_VERSION ); + + /* Encode the security association (SA) number */ + encode_uint32( outbuf, &idx, sa->sa_id ); + + /* Encrypt the assembly contents and write the ciphertext after the SA. */ + len = in_len + TRANSOP_AES_NONCE_SIZE; + + /* The assembly buffer is a source for encrypting data. The nonce is + * written in first followed by the packet payload. The whole + * contents of assembly are encrypted. */ + pnonce = (uint32_t *)assembly; + *pnonce = rand(); + memcpy( assembly + TRANSOP_AES_NONCE_SIZE, inbuf, in_len ); + + /* Need at least one encrypted byte at the end for the padding. */ + len2 = ( (len / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE; /* Round up to next whole AES adding at least one byte. */ + assembly[ len2-1 ]=(len2-len); + traceEvent( TRACE_DEBUG, "padding = %u", assembly[ len2-1 ] ); + + memset( &(sa->enc_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) ); + AES_cbc_encrypt( assembly, /* source */ + outbuf + TRANSOP_AES_VER_SIZE + TRANSOP_AES_SA_SIZE, /* dest */ + len2, /* enc size */ + &(sa->enc_key), sa->enc_ivec, 1 /* encrypt */ ); + + len2 += TRANSOP_AES_VER_SIZE + TRANSOP_AES_SA_SIZE; /* size of data carried in UDP. */ + } + else + { + traceEvent( TRACE_ERROR, "encode_aes outbuf too small." ); + } + } + else + { + traceEvent( TRACE_ERROR, "encode_aes inbuf too big to encrypt." ); + } + + return len2; +} + + +/* Search through the array of SAs to find the one with the required ID. + * + * @return array index where found or -1 if not found + */ +static ssize_t aes_find_sa( const transop_aes_t * priv, const n2n_sa_t req_id ) +{ + size_t i; + + for (i=0; i < priv->num_sa; ++i) + { + const sa_aes_t * sa=NULL; + + sa = &(priv->sa[i]); + if (req_id == sa->sa_id) + { + return i; + } + } + + return -1; +} + + +/** The aes packet format consists of: + * + * - a 8-bit aes encoding version in clear text + * - a 32-bit SA number in clear text + * - ciphertext encrypted from a 32-bit nonce followed by the payload. + * + * [V|SSSS|nnnnDDDDDDDDDDDDDDDDDDDDD] + * |<------ encrypted ------>| + */ +static int transop_decode_aes( n2n_trans_op_t * arg, + uint8_t * outbuf, + size_t out_len, + const uint8_t * inbuf, + size_t in_len ) +{ + int len=0; + transop_aes_t * priv = (transop_aes_t *)arg->priv; + uint8_t assembly[N2N_PKT_BUF_SIZE]; + + if ( ( (in_len - (TRANSOP_AES_VER_SIZE + TRANSOP_AES_SA_SIZE)) <= N2N_PKT_BUF_SIZE ) /* Cipher text fits in assembly */ + && (in_len >= (TRANSOP_AES_VER_SIZE + TRANSOP_AES_SA_SIZE + TRANSOP_AES_NONCE_SIZE) ) /* Has at least version, SA and nonce */ + ) + { + n2n_sa_t sa_rx; + ssize_t sa_idx=-1; + size_t rem=in_len; + size_t idx=0; + uint8_t aes_enc_ver=0; + + /* Get the encoding version to make sure it is supported */ + decode_uint8( &aes_enc_ver, inbuf, &rem, &idx ); + + if ( N2N_AES_TRANSFORM_VERSION == aes_enc_ver ) + { + /* Get the SA number and make sure we are decrypting with the right one. */ + decode_uint32( &sa_rx, inbuf, &rem, &idx ); + + sa_idx = aes_find_sa(priv, sa_rx); + if ( sa_idx >= 0 ) + { + sa_aes_t * sa = &(priv->sa[sa_idx]); + + traceEvent( TRACE_DEBUG, "decode_aes %lu with SA %lu.", in_len, sa_rx, sa->sa_id ); + + len = (in_len - (TRANSOP_AES_VER_SIZE + TRANSOP_AES_SA_SIZE)); + + if ( 0 == (len % AES_BLOCK_SIZE ) ) + { + uint8_t padding; + + memset( &(sa->dec_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) ); + AES_cbc_encrypt( (inbuf + TRANSOP_AES_VER_SIZE + TRANSOP_AES_SA_SIZE), + assembly, /* destination */ + len, + &(sa->dec_key), + sa->dec_ivec, 0 /* decrypt */ ); + + /* last byte is how much was padding: max value should be + * AES_BLOCKSIZE-1 */ + padding = assembly[ len-1 ] & 0xff; + + if ( len >= (padding + TRANSOP_AES_NONCE_SIZE)) + { + /* strictly speaking for this to be an ethernet packet + * it is going to need to be even bigger; but this is + * enough to prevent segfaults. */ + traceEvent( TRACE_DEBUG, "padding = %u", padding ); + len -= padding; + + len -= TRANSOP_AES_NONCE_SIZE; /* size of ethernet packet */ + + /* Step over 4-byte random nonce value */ + memcpy( outbuf, + assembly + TRANSOP_AES_NONCE_SIZE, + len ); + } + else + { + traceEvent( TRACE_WARNING, "UDP payload decryption failed." ); + } + } + else + { + traceEvent( TRACE_WARNING, "Encrypted length %d is not a multiple of AES_BLOCK_SIZE (%d)", len, AES_BLOCK_SIZE ); + len = 0; + } + + } + else + { + /* Wrong security association; drop the packet as it is undecodable. */ + traceEvent( TRACE_ERROR, "decode_aes SA number %lu not found.", sa_rx ); + + /* REVISIT: should be able to load a new SA at this point to complete the decoding. */ + } + } + else + { + /* Wrong security association; drop the packet as it is undecodable. */ + traceEvent( TRACE_ERROR, "decode_aes unsupported aes version %u.", aes_enc_ver ); + + /* REVISIT: should be able to load a new SA at this point to complete the decoding. */ + } + } + else + { + traceEvent( TRACE_ERROR, "decode_aes inbuf wrong size (%ul) to decrypt.", in_len ); + } + + return len; +} + +static int transop_addspec_aes( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec ) +{ + int retval = 1; + ssize_t pstat=-1; + transop_aes_t * priv = (transop_aes_t *)arg->priv; + uint8_t keybuf[N2N_MAX_KEYSIZE]; + + if ( priv->num_sa < N2N_AES_NUM_SA ) + { + const char * op = (const char *)cspec->opaque; + const char * sep = index( op, '_' ); + + if ( sep ) + { + char tmp[256]; + size_t s; + + s = sep - op; + memcpy( tmp, cspec->opaque, s ); + tmp[s]=0; + + s = strlen(sep+1); /* sep is the _ which might be immediately followed by NULL */ + + priv->sa[priv->num_sa].spec = *cspec; + priv->sa[priv->num_sa].sa_id = strtoul(tmp, NULL, 10); + + memset( keybuf, 0, N2N_MAX_KEYSIZE ); + pstat = n2n_parse_hex( keybuf, N2N_MAX_KEYSIZE, sep+1, s ); + if ( pstat > 0 ) + { + /* pstat is number of bytes read into keybuf. */ + sa_aes_t * sa = &(priv->sa[priv->num_sa]); + size_t aes_keysize_bytes; + size_t aes_keysize_bits; + + /* Clear out any old possibly longer key matter. */ + memset( &(sa->enc_key), 0, sizeof(AES_KEY) ); + memset( &(sa->dec_key), 0, sizeof(AES_KEY) ); + + memset( &(sa->enc_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) ); + memset( &(sa->dec_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) ); + + aes_keysize_bytes = aes_best_keysize(pstat); + aes_keysize_bits = 8 * aes_keysize_bytes; + + /* Use N2N_MAX_KEYSIZE because the AES key needs to be of fixed + * size. If fewer bits specified then the rest will be + * zeroes. AES acceptable key sizes are 128, 192 and 256 + * bits. */ + AES_set_encrypt_key( keybuf, aes_keysize_bits, &(sa->enc_key)); + AES_set_decrypt_key( keybuf, aes_keysize_bits, &(sa->dec_key)); + /* Leave ivecs set to all zeroes */ + + traceEvent( TRACE_DEBUG, "transop_addspec_aes sa_id=%u, %u bits data=%s.\n", + priv->sa[priv->num_sa].sa_id, aes_keysize_bits, sep+1); + + ++(priv->num_sa); + retval = 0; + } + } + else + { + traceEvent( TRACE_ERROR, "transop_addspec_aes : bad key data - missing '_'.\n"); + } + } + else + { + traceEvent( TRACE_ERROR, "transop_addspec_aes : full.\n"); + } + + return retval; +} + + +static n2n_tostat_t transop_tick_aes( n2n_trans_op_t * arg, time_t now ) +{ + transop_aes_t * priv = (transop_aes_t *)arg->priv; + size_t i; + int found=0; + n2n_tostat_t r; + + memset( &r, 0, sizeof(r) ); + + traceEvent( TRACE_DEBUG, "transop_aes tick num_sa=%u now=%lu", priv->num_sa, now ); + + for ( i=0; i < priv->num_sa; ++i ) + { + if ( 0 == validCipherSpec( &(priv->sa[i].spec), now ) ) + { + time_t remaining = priv->sa[i].spec.valid_until - now; + + traceEvent( TRACE_INFO, "transop_aes choosing tx_sa=%u (valid for %lu sec)", priv->sa[i].sa_id, remaining ); + priv->tx_sa=i; + found=1; + break; + } + else + { + traceEvent( TRACE_DEBUG, "transop_aes tick rejecting sa=%u %lu -> %lu", + priv->sa[i].sa_id, priv->sa[i].spec.valid_from, priv->sa[i].spec.valid_until ); + } + } + + if ( 0==found) + { + traceEvent( TRACE_INFO, "transop_aes no keys are currently valid. Keeping tx_sa=%u", priv->tx_sa ); + } + else + { + r.can_tx = 1; + r.tx_spec.t = N2N_TRANSFORM_ID_AESCBC; + r.tx_spec = priv->sa[priv->tx_sa].spec; + } + + return r; +} + + +int transop_aes_init( n2n_trans_op_t * ttt ) +{ + int retval = 1; + transop_aes_t * priv = NULL; + + if ( ttt->priv ) + { + transop_deinit_aes( ttt ); + } + + memset( ttt, 0, sizeof( n2n_trans_op_t ) ); + + priv = (transop_aes_t *) malloc( sizeof(transop_aes_t) ); + + if ( NULL != priv ) + { + size_t i; + sa_aes_t * sa=NULL; + + /* install the private structure. */ + ttt->priv = priv; + priv->num_sa=0; + priv->tx_sa=0; /* We will use this sa index for encoding. */ + + ttt->transform_id = N2N_TRANSFORM_ID_AESCBC; + ttt->addspec = transop_addspec_aes; + ttt->tick = transop_tick_aes; /* chooses a new tx_sa */ + ttt->deinit = transop_deinit_aes; + ttt->fwd = transop_encode_aes; + ttt->rev = transop_decode_aes; + + for(i=0; isa[i]); + sa->sa_id=0; + memset( &(sa->spec), 0, sizeof(n2n_cipherspec_t) ); + memset( &(sa->enc_key), 0, sizeof(AES_KEY) ); + memset( &(sa->enc_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) ); + memset( &(sa->dec_key), 0, sizeof(AES_KEY) ); + memset( &(sa->dec_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) ); + } + + retval = 0; + } + else + { + memset( ttt, 0, sizeof(n2n_trans_op_t) ); + traceEvent( TRACE_ERROR, "Failed to allocate priv for aes" ); + } + + return retval; +} + +#else /* #if defined(N2N_HAVE_AES) */ + +struct transop_aes +{ + ssize_t tx_sa; +}; + +typedef struct transop_aes transop_aes_t; + + +static int transop_deinit_aes( n2n_trans_op_t * arg ) +{ + transop_aes_t * priv = (transop_aes_t *)arg->priv; + + if ( priv ) + { + free(priv); + } + + arg->priv=NULL; /* return to fully uninitialised state */ + + return 0; +} + +static int transop_encode_aes( n2n_trans_op_t * arg, + uint8_t * outbuf, + size_t out_len, + const uint8_t * inbuf, + size_t in_len ) +{ + return -1; +} + +static int transop_decode_aes( n2n_trans_op_t * arg, + uint8_t * outbuf, + size_t out_len, + const uint8_t * inbuf, + size_t in_len ) +{ + return -1; +} + +static int transop_addspec_aes( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec ) +{ + traceEvent( TRACE_DEBUG, "transop_addspec_aes AES not built into edge.\n"); + + return -1; +} + +static n2n_tostat_t transop_tick_aes( n2n_trans_op_t * arg, time_t now ) +{ + n2n_tostat_t r; + + memset( &r, 0, sizeof(r) ); + + return r; +} + +int transop_aes_init( n2n_trans_op_t * ttt ) +{ + int retval = 1; + transop_aes_t * priv = NULL; + + if ( ttt->priv ) + { + transop_deinit_aes( ttt ); + } + + memset( ttt, 0, sizeof( n2n_trans_op_t ) ); + + priv = (transop_aes_t *) malloc( sizeof(transop_aes_t) ); + + if ( NULL != priv ) + { + /* install the private structure. */ + ttt->priv = priv; + priv->tx_sa=0; /* We will use this sa index for encoding. */ + + ttt->transform_id = N2N_TRANSFORM_ID_AESCBC; + ttt->addspec = transop_addspec_aes; + ttt->tick = transop_tick_aes; /* chooses a new tx_sa */ + ttt->deinit = transop_deinit_aes; + ttt->fwd = transop_encode_aes; + ttt->rev = transop_decode_aes; + + retval = 0; + } + else + { + memset( ttt, 0, sizeof(n2n_trans_op_t) ); + traceEvent( TRACE_ERROR, "Failed to allocate priv for aes" ); + } + + return retval; +} + +#endif /* #if defined(N2N_HAVE_AES) */ + diff --git a/transform_null.c b/transform_null.c new file mode 100644 index 0000000..b486989 --- /dev/null +++ b/transform_null.c @@ -0,0 +1,84 @@ +/* (c) 2009 Richard Andrews */ + +#include "n2n.h" +#include "n2n_transforms.h" + +static int transop_deinit_null( n2n_trans_op_t * arg ) +{ + /* nothing to deallocate, nothing to release. */ + return 0; +} + +static int transop_encode_null( n2n_trans_op_t * arg, + uint8_t * outbuf, + size_t out_len, + const uint8_t * inbuf, + size_t in_len ) +{ + int retval = -1; + + traceEvent( TRACE_DEBUG, "encode_null %lu", in_len ); + if ( out_len >= in_len ) + { + memcpy( outbuf, inbuf, in_len ); + retval = in_len; + } + else + { + traceEvent( TRACE_DEBUG, "encode_null %lu too big for packet buffer", in_len ); + } + + return retval; +} + +static int transop_decode_null( n2n_trans_op_t * arg, + uint8_t * outbuf, + size_t out_len, + const uint8_t * inbuf, + size_t in_len ) +{ + int retval = -1; + + traceEvent( TRACE_DEBUG, "decode_null %lu", in_len ); + if ( out_len >= in_len ) + { + memcpy( outbuf, inbuf, in_len ); + retval = in_len; + } + else + { + traceEvent( TRACE_DEBUG, "decode_null %lu too big for packet buffer", in_len ); + } + + return retval; +} + +static int transop_addspec_null( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec ) +{ + return 0; +} + +static n2n_tostat_t transop_tick_null( n2n_trans_op_t * arg, time_t now ) +{ + n2n_tostat_t r; + + r.can_tx=1; + r.tx_spec.t = N2N_TRANSFORM_ID_NULL; + r.tx_spec.valid_from = 0; + r.tx_spec.valid_until = (time_t)(-1); + r.tx_spec.opaque_size=0; + + return r; +} + +void transop_null_init( n2n_trans_op_t * ttt ) +{ + memset(ttt, 0, sizeof(n2n_trans_op_t) ); + + ttt->transform_id = N2N_TRANSFORM_ID_NULL; + ttt->deinit = transop_deinit_null; + ttt->addspec = transop_addspec_null; + ttt->tick = transop_tick_null; + ttt->fwd = transop_encode_null; + ttt->rev = transop_decode_null; +} diff --git a/transform_tf.c b/transform_tf.c new file mode 100644 index 0000000..1ae5bc5 --- /dev/null +++ b/transform_tf.c @@ -0,0 +1,487 @@ +/* (c) 2009 Richard Andrews */ + +#include "n2n.h" +#include "n2n_transforms.h" +#include "twofish.h" +#ifndef _MSC_VER +/* Not included in Visual Studio 2008 */ +#include /* index() */ +#endif + +#define N2N_TWOFISH_NUM_SA 32 /* space for SAa */ + +#define N2N_TWOFISH_TRANSFORM_VERSION 1 /* version of the transform encoding */ + +struct sa_twofish +{ + n2n_cipherspec_t spec; /* cipher spec parameters */ + n2n_sa_t sa_id; /* security association index */ + TWOFISH * enc_tf; /* tx state */ + TWOFISH * dec_tf; /* rx state */ +}; + +typedef struct sa_twofish sa_twofish_t; + + +/** Twofish transform state data. + * + * With a key-schedule in place this will be populated with a number of + * SAs. Each SA has a lifetime and some opque data. The opaque data for twofish + * consists of the SA number and key material. + * + */ +struct transop_tf +{ + ssize_t tx_sa; + size_t num_sa; + sa_twofish_t sa[N2N_TWOFISH_NUM_SA]; +}; + +typedef struct transop_tf transop_tf_t; + +static int transop_deinit_twofish( n2n_trans_op_t * arg ) +{ + transop_tf_t * priv = (transop_tf_t *)arg->priv; + size_t i; + + if ( priv ) + { + /* Memory was previously allocated */ + for (i=0; isa[i]); + + TwoFishDestroy(sa->enc_tf); /* deallocate TWOFISH */ + sa->enc_tf=NULL; + + TwoFishDestroy(sa->dec_tf); /* deallocate TWOFISH */ + sa->dec_tf=NULL; + + sa->sa_id=0; + } + + priv->num_sa=0; + priv->tx_sa=-1; + + free(priv); + } + + arg->priv=NULL; /* return to fully uninitialised state */ + + return 0; +} + +static size_t tf_choose_tx_sa( transop_tf_t * priv ) +{ + return priv->tx_sa; /* set in tick */ +} + +#define TRANSOP_TF_VER_SIZE 1 /* Support minor variants in encoding in one module. */ +#define TRANSOP_TF_NONCE_SIZE 4 +#define TRANSOP_TF_SA_SIZE 4 + +/** The twofish packet format consists of: + * + * - a 8-bit twofish encoding version in clear text + * - a 32-bit SA number in clear text + * - ciphertext encrypted from a 32-bit nonce followed by the payload. + * + * [V|SSSS|nnnnDDDDDDDDDDDDDDDDDDDDD] + * |<------ encrypted ------>| + */ +static int transop_encode_twofish( n2n_trans_op_t * arg, + uint8_t * outbuf, + size_t out_len, + const uint8_t * inbuf, + size_t in_len ) +{ + int len=-1; + transop_tf_t * priv = (transop_tf_t *)arg->priv; + uint8_t assembly[N2N_PKT_BUF_SIZE]; + uint32_t * pnonce; + + if ( (in_len + TRANSOP_TF_NONCE_SIZE) <= N2N_PKT_BUF_SIZE ) + { + if ( (in_len + TRANSOP_TF_NONCE_SIZE + TRANSOP_TF_SA_SIZE + TRANSOP_TF_VER_SIZE) <= out_len ) + { + size_t idx=0; + sa_twofish_t * sa; + size_t tx_sa_num = 0; + + /* The transmit sa is periodically updated */ + tx_sa_num = tf_choose_tx_sa( priv ); + + sa = &(priv->sa[tx_sa_num]); /* Proper Tx SA index */ + + traceEvent( TRACE_DEBUG, "encode_twofish %lu with SA %lu.", in_len, sa->sa_id ); + + /* Encode the twofish format version. */ + encode_uint8( outbuf, &idx, N2N_TWOFISH_TRANSFORM_VERSION ); + + /* Encode the security association (SA) number */ + encode_uint32( outbuf, &idx, sa->sa_id ); + + /* The assembly buffer is a source for encrypting data. The nonce is + * written in first followed by the packet payload. The whole + * contents of assembly are encrypted. */ + pnonce = (uint32_t *)assembly; + *pnonce = rand(); + memcpy( assembly + TRANSOP_TF_NONCE_SIZE, inbuf, in_len ); + + /* Encrypt the assembly contents and write the ciphertext after the SA. */ + len = TwoFishEncryptRaw( assembly, /* source */ + outbuf + TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE, + in_len + TRANSOP_TF_NONCE_SIZE, /* enc size */ + sa->enc_tf); + if ( len > 0 ) + { + len += TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE; /* size of data carried in UDP. */ + } + else + { + traceEvent( TRACE_ERROR, "encode_twofish encryption failed." ); + } + + } + else + { + traceEvent( TRACE_ERROR, "encode_twofish outbuf too small." ); + } + } + else + { + traceEvent( TRACE_ERROR, "encode_twofish inbuf too big to encrypt." ); + } + + return len; +} + + +/* Search through the array of SAs to find the one with the required ID. + * + * @return array index where found or -1 if not found + */ +static ssize_t twofish_find_sa( const transop_tf_t * priv, const n2n_sa_t req_id ) +{ + size_t i; + + for (i=0; i < priv->num_sa; ++i) + { + const sa_twofish_t * sa=NULL; + + sa = &(priv->sa[i]); + if (req_id == sa->sa_id) + { + return i; + } + } + + return -1; +} + + +/** The twofish packet format consists of: + * + * - a 8-bit twofish encoding version in clear text + * - a 32-bit SA number in clear text + * - ciphertext encrypted from a 32-bit nonce followed by the payload. + * + * [V|SSSS|nnnnDDDDDDDDDDDDDDDDDDDDD] + * |<------ encrypted ------>| + */ +static int transop_decode_twofish( n2n_trans_op_t * arg, + uint8_t * outbuf, + size_t out_len, + const uint8_t * inbuf, + size_t in_len ) +{ + int len=0; + transop_tf_t * priv = (transop_tf_t *)arg->priv; + uint8_t assembly[N2N_PKT_BUF_SIZE]; + + if ( ( (in_len - (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE)) <= N2N_PKT_BUF_SIZE ) /* Cipher text fits in assembly */ + && (in_len >= (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE + TRANSOP_TF_NONCE_SIZE) ) /* Has at least version, SA and nonce */ + ) + { + n2n_sa_t sa_rx; + ssize_t sa_idx=-1; + size_t rem=in_len; + size_t idx=0; + uint8_t tf_enc_ver=0; + + /* Get the encoding version to make sure it is supported */ + decode_uint8( &tf_enc_ver, inbuf, &rem, &idx ); + + if ( N2N_TWOFISH_TRANSFORM_VERSION == tf_enc_ver ) + { + /* Get the SA number and make sure we are decrypting with the right one. */ + decode_uint32( &sa_rx, inbuf, &rem, &idx ); + + sa_idx = twofish_find_sa(priv, sa_rx); + if ( sa_idx >= 0 ) + { + sa_twofish_t * sa = &(priv->sa[sa_idx]); + + traceEvent( TRACE_DEBUG, "decode_twofish %lu with SA %lu.", in_len, sa_rx, sa->sa_id ); + + len = TwoFishDecryptRaw( (void *)(inbuf + TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE), + assembly, /* destination */ + (in_len - (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE)), + sa->dec_tf); + + if ( len > 0 ) + { + /* Step over 4-byte random nonce value */ + len -= TRANSOP_TF_NONCE_SIZE; /* size of ethernet packet */ + + memcpy( outbuf, + assembly + TRANSOP_TF_NONCE_SIZE, + len ); + } + else + { + traceEvent( TRACE_ERROR, "decode_twofish decryption failed." ); + } + + } + else + { + /* Wrong security association; drop the packet as it is undecodable. */ + traceEvent( TRACE_ERROR, "decode_twofish SA number %lu not found.", sa_rx ); + + /* REVISIT: should be able to load a new SA at this point to complete the decoding. */ + } + } + else + { + /* Wrong security association; drop the packet as it is undecodable. */ + traceEvent( TRACE_ERROR, "decode_twofish unsupported twofish version %u.", tf_enc_ver ); + + /* REVISIT: should be able to load a new SA at this point to complete the decoding. */ + } + } + else + { + traceEvent( TRACE_ERROR, "decode_twofish inbuf wrong size (%ul) to decrypt.", in_len ); + } + + return len; +} + +static int transop_addspec_twofish( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec ) +{ + int retval = 1; + ssize_t pstat=-1; + transop_tf_t * priv = (transop_tf_t *)arg->priv; + uint8_t keybuf[N2N_MAX_KEYSIZE]; + + if ( priv->num_sa < N2N_TWOFISH_NUM_SA ) + { + const char * op = (const char *)cspec->opaque; + const char * sep = index( op, '_' ); + + if ( sep ) + { + char tmp[256]; + size_t s; + + s = sep - op; + memcpy( tmp, cspec->opaque, s ); + tmp[s]=0; + + s = strlen(sep+1); /* sep is the _ which might be immediately followed by NULL */ + + priv->sa[priv->num_sa].spec = *cspec; + priv->sa[priv->num_sa].sa_id = strtoul(tmp, NULL, 10); + + pstat = n2n_parse_hex( keybuf, N2N_MAX_KEYSIZE, sep+1, s ); + if ( pstat > 0 ) + { + priv->sa[priv->num_sa].enc_tf = TwoFishInit( keybuf, pstat); + priv->sa[priv->num_sa].dec_tf = TwoFishInit( keybuf, pstat); + + traceEvent( TRACE_DEBUG, "transop_addspec_twofish sa_id=%u data=%s.\n", + priv->sa[priv->num_sa].sa_id, sep+1); + + ++(priv->num_sa); + retval = 0; + } + } + else + { + traceEvent( TRACE_ERROR, "transop_addspec_twofish : bad key data - missing '_'.\n"); + } + } + else + { + traceEvent( TRACE_ERROR, "transop_addspec_twofish : full.\n"); + } + + return retval; +} + + +static n2n_tostat_t transop_tick_twofish( n2n_trans_op_t * arg, time_t now ) +{ + transop_tf_t * priv = (transop_tf_t *)arg->priv; + size_t i; + int found=0; + n2n_tostat_t r; + + memset( &r, 0, sizeof(r) ); + + traceEvent( TRACE_DEBUG, "transop_tf tick num_sa=%u", priv->num_sa ); + + for ( i=0; i < priv->num_sa; ++i ) + { + if ( 0 == validCipherSpec( &(priv->sa[i].spec), now ) ) + { + time_t remaining = priv->sa[i].spec.valid_until - now; + + traceEvent( TRACE_INFO, "transop_tf choosing tx_sa=%u (valid for %lu sec)", priv->sa[i].sa_id, remaining ); + priv->tx_sa=i; + found=1; + break; + } + else + { + traceEvent( TRACE_DEBUG, "transop_tf tick rejecting sa=%u %lu -> %lu", + priv->sa[i].sa_id, priv->sa[i].spec.valid_from, priv->sa[i].spec.valid_until ); + } + } + + if ( 0==found) + { + traceEvent( TRACE_INFO, "transop_tf no keys are currently valid. Keeping tx_sa=%u", priv->tx_sa ); + } + else + { + r.can_tx = 1; + r.tx_spec.t = N2N_TRANSFORM_ID_TWOFISH; + r.tx_spec = priv->sa[priv->tx_sa].spec; + } + + return r; +} + + +int transop_twofish_setup( n2n_trans_op_t * ttt, + n2n_sa_t sa_num, + uint8_t * encrypt_pwd, + uint32_t encrypt_pwd_len ) +{ + int retval = 1; + transop_tf_t * priv = NULL; + + if ( ttt->priv ) + { + transop_deinit_twofish( ttt ); + } + + memset( ttt, 0, sizeof( n2n_trans_op_t ) ); + + priv = (transop_tf_t *) malloc( sizeof(transop_tf_t) ); + + if ( NULL != priv ) + { + size_t i; + sa_twofish_t * sa=NULL; + + /* install the private structure. */ + ttt->priv = priv; + + for(i=0; isa[i]); + sa->sa_id=0; + memset( &(sa->spec), 0, sizeof(n2n_cipherspec_t) ); + sa->enc_tf=NULL; + sa->dec_tf=NULL; + } + + priv->num_sa=1; /* There is one SA in the array. */ + priv->tx_sa=0; + sa = &(priv->sa[priv->tx_sa]); + sa->sa_id=sa_num; + sa->spec.valid_until = 0x7fffffff; + + /* This is a preshared key setup. Both Tx and Rx are using the same security association. */ + + sa->enc_tf = TwoFishInit(encrypt_pwd, encrypt_pwd_len); + sa->dec_tf = TwoFishInit(encrypt_pwd, encrypt_pwd_len); + + if ( (sa->enc_tf) && (sa->dec_tf) ) + { + ttt->transform_id = N2N_TRANSFORM_ID_TWOFISH; + ttt->deinit = transop_deinit_twofish; + ttt->addspec = transop_addspec_twofish; + ttt->tick = transop_tick_twofish; /* chooses a new tx_sa */ + ttt->fwd = transop_encode_twofish; + ttt->rev = transop_decode_twofish; + + retval = 0; + } + else + { + traceEvent( TRACE_ERROR, "TwoFishInit failed" ); + } + } + else + { + memset( ttt, 0, sizeof(n2n_trans_op_t) ); + traceEvent( TRACE_ERROR, "Failed to allocate priv for twofish" ); + } + + return retval; +} + +int transop_twofish_init( n2n_trans_op_t * ttt ) +{ + int retval = 1; + transop_tf_t * priv = NULL; + + if ( ttt->priv ) + { + transop_deinit_twofish( ttt ); + } + + memset( ttt, 0, sizeof( n2n_trans_op_t ) ); + + priv = (transop_tf_t *) malloc( sizeof(transop_tf_t) ); + + if ( NULL != priv ) + { + size_t i; + sa_twofish_t * sa=NULL; + + /* install the private structure. */ + ttt->priv = priv; + priv->num_sa=0; + priv->tx_sa=0; /* We will use this sa index for encoding. */ + + ttt->transform_id = N2N_TRANSFORM_ID_TWOFISH; + ttt->addspec = transop_addspec_twofish; + ttt->tick = transop_tick_twofish; /* chooses a new tx_sa */ + ttt->deinit = transop_deinit_twofish; + ttt->fwd = transop_encode_twofish; + ttt->rev = transop_decode_twofish; + + for(i=0; isa[i]); + sa->sa_id=0; + memset( &(sa->spec), 0, sizeof(n2n_cipherspec_t) ); + sa->enc_tf=NULL; + sa->dec_tf=NULL; + } + + retval = 0; + } + else + { + memset( ttt, 0, sizeof(n2n_trans_op_t) ); + traceEvent( TRACE_ERROR, "Failed to allocate priv for twofish" ); + } + + return retval; +} diff --git a/tuntap_freebsd.c b/tuntap_freebsd.c new file mode 100644 index 0000000..7d9096a --- /dev/null +++ b/tuntap_freebsd.c @@ -0,0 +1,132 @@ +/* + * (C) 2007-09 - Luca Deri + * + * 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 3 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 see see + */ + +#include "n2n.h" + +#ifdef __FreeBSD__ + +void tun_close(tuntap_dev *device); + +/* ********************************** */ + +#define N2N_FREEBSD_TAPDEVICE_SIZE 32 +int tuntap_open(tuntap_dev *device /* ignored */, + char *dev, + const char *address_mode, /* static or dhcp */ + char *device_ip, + char *device_mask, + const char * device_mac, + int mtu) { + int i; + char tap_device[N2N_FREEBSD_TAPDEVICE_SIZE]; + + for (i = 0; i < 255; i++) { + snprintf(tap_device, sizeof(tap_device), "/dev/tap%d", i); + + device->fd = open(tap_device, O_RDWR); + if(device->fd > 0) { + traceEvent(TRACE_NORMAL, "Succesfully open %s", tap_device); + break; + } + } + + if(device->fd < 0) { + traceEvent(TRACE_ERROR, "Unable to open tap device"); + return(-1); + } else { + char buf[256]; + FILE *fd; + + device->ip_addr = inet_addr(device_ip); + + if ( device_mac && device_mac[0] != '\0' ) + { + /* FIXME - This is not tested. Might be wrong syntax for OS X */ + + /* Set the hw address before bringing the if up. */ + snprintf(buf, sizeof(buf), "ifconfig tap%d ether %s", + i, device_mac); + system(buf); + } + + snprintf(buf, sizeof(buf), "ifconfig tap%d %s netmask %s mtu %d up", + i, device_ip, device_mask, mtu); + system(buf); + + traceEvent(TRACE_NORMAL, "Interface tap%d up and running (%s/%s)", + i, device_ip, device_mask); + + /* Read MAC address */ + + snprintf(buf, sizeof(buf), "ifconfig tap%d |grep ether|cut -c 8-24", i); + /* traceEvent(TRACE_INFO, "%s", buf); */ + + fd = popen(buf, "r"); + if(fd < 0) { + tun_close(device); + return(-1); + } else { + int a, b, c, d, e, f; + + buf[0] = 0; + fgets(buf, sizeof(buf), fd); + pclose(fd); + + if(buf[0] == '\0') { + traceEvent(TRACE_ERROR, "Unable to read tap%d interface MAC address"); + exit(0); + } + + traceEvent(TRACE_NORMAL, "Interface tap%d mac %s", i, buf); + if(sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", &a, &b, &c, &d, &e, &f) == 6) { + device->mac_addr[0] = a, device->mac_addr[1] = b; + device->mac_addr[2] = c, device->mac_addr[3] = d; + device->mac_addr[4] = e, device->mac_addr[5] = f; + } + } + } + + + /* read_mac(dev, device->mac_addr); */ + return(device->fd); +} + +/* ********************************** */ + +int tuntap_read(struct tuntap_dev *tuntap, unsigned char *buf, int len) { + return(read(tuntap->fd, buf, len)); +} + +/* ********************************** */ + +int tuntap_write(struct tuntap_dev *tuntap, unsigned char *buf, int len) { + return(write(tuntap->fd, buf, len)); +} + +/* ********************************** */ + +void tuntap_close(struct tuntap_dev *tuntap) { + close(tuntap->fd); +} + +/* Fill out the ip_addr value from the interface. Called to pick up dynamic + * address changes. */ +void tuntap_get_address(struct tuntap_dev *tuntap) +{ +} + +#endif /* #ifdef __FreeBSD__ */ diff --git a/tuntap_linux.c b/tuntap_linux.c new file mode 100644 index 0000000..66b3dd8 --- /dev/null +++ b/tuntap_linux.c @@ -0,0 +1,165 @@ +/* + * (C) 2007-09 - Luca Deri + * + * 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 3 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, see +*/ + +#include "n2n.h" + +#ifdef __linux__ + +static void read_mac(char *ifname, n2n_mac_t mac_addr) { + int _sock, res; + struct ifreq ifr; + macstr_t mac_addr_buf; + + memset (&ifr,0,sizeof(struct ifreq)); + + /* Dummy socket, just to make ioctls with */ + _sock=socket(PF_INET, SOCK_DGRAM, 0); + strcpy(ifr.ifr_name, ifname); + res = ioctl(_sock,SIOCGIFHWADDR,&ifr); + if (res<0) { + perror ("Get hw addr"); + } else + memcpy(mac_addr, ifr.ifr_ifru.ifru_hwaddr.sa_data, 6); + + traceEvent(TRACE_NORMAL, "Interface %s has MAC %s", + ifname, + macaddr_str(mac_addr_buf, mac_addr )); + close(_sock); +} + +/* ********************************** */ + +/** @brief Open and configure the TAP device for packet read/write. + * + * This routine creates the interface via the tuntap driver then uses ifconfig + * to configure address/mask and MTU. + * + * @param device - [inout] a device info holder object + * @param dev - user-defined name for the new iface, + * if NULL system will assign a name + * @param device_ip - address of iface + * @param device_mask - netmask for device_ip + * @param mtu - MTU for device_ip + * + * @return - negative value on error + * - non-negative file-descriptor on success + */ +int tuntap_open(tuntap_dev *device, + char *dev, /* user-definable interface name, eg. edge0 */ + const char *address_mode, /* static or dhcp */ + char *device_ip, + char *device_mask, + const char * device_mac, + int mtu) { + char *tuntap_device = "/dev/net/tun"; +#define N2N_LINUX_SYSTEMCMD_SIZE 128 + char buf[N2N_LINUX_SYSTEMCMD_SIZE]; + struct ifreq ifr; + int rc; + + device->fd = open(tuntap_device, O_RDWR); + if(device->fd < 0) { + printf("ERROR: ioctl() [%s][%d]\n", strerror(errno), errno); + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_TAP|IFF_NO_PI; /* Want a TAP device for layer 2 frames. */ + strncpy(ifr.ifr_name, dev, IFNAMSIZ); + rc = ioctl(device->fd, TUNSETIFF, (void *)&ifr); + + if(rc < 0) { + traceEvent(TRACE_ERROR, "ioctl() [%s][%d]\n", strerror(errno), rc); + close(device->fd); + return -1; + } + + /* Store the device name for later reuse */ + strncpy(device->dev_name, ifr.ifr_name, MIN(IFNAMSIZ, N2N_IFNAMSIZ) ); + + if ( device_mac && device_mac[0] != '\0' ) + { + /* Set the hw address before bringing the if up. */ + snprintf(buf, sizeof(buf), "/sbin/ifconfig %s hw ether %s", + ifr.ifr_name, device_mac ); + system(buf); + traceEvent(TRACE_INFO, "Setting MAC: %s", buf); + } + + if ( 0 == strncmp( "dhcp", address_mode, 5 ) ) + { + snprintf(buf, sizeof(buf), "/sbin/ifconfig %s %s mtu %d up", + ifr.ifr_name, device_ip, mtu); + } + else + { + snprintf(buf, sizeof(buf), "/sbin/ifconfig %s %s netmask %s mtu %d up", + ifr.ifr_name, device_ip, device_mask, mtu); + } + + system(buf); + traceEvent(TRACE_INFO, "Bringing up: %s", buf); + + device->ip_addr = inet_addr(device_ip); + device->device_mask = inet_addr(device_mask); + read_mac(dev, device->mac_addr); + return(device->fd); +} + +int tuntap_read(struct tuntap_dev *tuntap, unsigned char *buf, int len) { + return(read(tuntap->fd, buf, len)); +} + +int tuntap_write(struct tuntap_dev *tuntap, unsigned char *buf, int len) { + return(write(tuntap->fd, buf, len)); +} + +void tuntap_close(struct tuntap_dev *tuntap) { + close(tuntap->fd); +} + +/* Fill out the ip_addr value from the interface. Called to pick up dynamic + * address changes. */ +void tuntap_get_address(struct tuntap_dev *tuntap) +{ + FILE * fp=NULL; + ssize_t nread=0; + char buf[N2N_LINUX_SYSTEMCMD_SIZE]; + + /* Would rather have a more direct way to get the inet address but a netlink + * socket is overkill and probably less portable than ifconfig and sed. */ + + /* If the interface has no address (0.0.0.0) there will be no inet addr + * line and the returned string will be empty. */ + snprintf( buf, sizeof(buf), "/sbin/ifconfig %s | /bin/sed -e '/inet addr:/!d' -e 's/^.*inet addr://' -e 's/ .*$//'", + tuntap->dev_name ); + fp=popen(buf, "r"); + if (fp ) + { + memset(buf,0,N2N_LINUX_SYSTEMCMD_SIZE); /* make sure buf is NULL terminated. */ + nread=fread(buf, 1, 15, fp); + fclose(fp); + fp=NULL; + + traceEvent(TRACE_INFO, "ifconfig address = %s", buf); + + tuntap->ip_addr = inet_addr(buf); + } +} + + +#endif /* #ifdef __linux__ */ diff --git a/tuntap_netbsd.c b/tuntap_netbsd.c new file mode 100644 index 0000000..011f7df --- /dev/null +++ b/tuntap_netbsd.c @@ -0,0 +1,146 @@ +/* + * (C) 2007-09 - Luca Deri + * (C) 2009 - Alaric Snell-Pym + * + * 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 3 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 see see + */ + +#include "n2n.h" + +#ifdef __NetBSD__ + +#include +#include +#include + +void tun_close(tuntap_dev *device); + +/* ********************************** */ + +#define N2N_NETBSD_TAPDEVICE_SIZE 32 +int tuntap_open(tuntap_dev *device /* ignored */, + char *dev, + const char *address_mode, /* static or dhcp */ + char *device_ip, + char *device_mask, + const char * device_mac, + int mtu) { + char tap_device[N2N_NETBSD_TAPDEVICE_SIZE]; + struct ifreq req; + + if (dev) { + snprintf(tap_device, sizeof(tap_device), "/dev/%s", dev); + device->fd = open(tap_device, O_RDWR); + snprintf(tap_device, sizeof(tap_device), "%s", dev); + } + else { + device->fd = open("/dev/tap", O_RDWR); + if(device->fd >= 0) { + if (ioctl(device->fd, TAPGIFNAME, &req) == -1) { + traceEvent(TRACE_ERROR, "Unable to obtain name of tap device (%s)", strerror(errno)); + close(device->fd); + return(-1); + } + else { + snprintf(tap_device, sizeof(tap_device), req.ifr_name); + } + } + } + + if(device->fd < 0) { + traceEvent(TRACE_ERROR, "Unable to open tap device (%s)", strerror(errno)); + return(-1); + } else { + char buf[256]; + FILE *fd; + + traceEvent(TRACE_NORMAL, "Succesfully open %s", tap_device); + + device->ip_addr = inet_addr(device_ip); + + if ( device_mac && device_mac[0] != '\0' ) + { + /* Set the hw address before bringing the if up. */ + snprintf(buf, sizeof(buf), "ifconfig %s link %s active", + tap_device, device_mac); + system(buf); + } + + snprintf(buf, sizeof(buf), "ifconfig %s %s netmask %s mtu %d up", + tap_device, device_ip, device_mask, mtu); + system(buf); + + traceEvent(TRACE_NORMAL, "Interface %s up and running (%s/%s)", + tap_device, device_ip, device_mask); + + /* Read MAC address */ + + snprintf(buf, sizeof(buf), "ifconfig %s |grep address|cut -c 11-28", tap_device); + /* traceEvent(TRACE_INFO, "%s", buf); */ + + fd = popen(buf, "r"); + if(fd < 0) { + tun_close(device); + return(-1); + } else { + int a, b, c, d, e, f; + + buf[0] = 0; + fgets(buf, sizeof(buf), fd); + pclose(fd); + + if(buf[0] == '\0') { + traceEvent(TRACE_ERROR, "Unable to read %s interface MAC address", tap_device); + exit(0); + } + + traceEvent(TRACE_NORMAL, "Interface %s mac %s", tap_device, buf); + if(sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", &a, &b, &c, &d, &e, &f) == 6) { + device->mac_addr[0] = a, device->mac_addr[1] = b; + device->mac_addr[2] = c, device->mac_addr[3] = d; + device->mac_addr[4] = e, device->mac_addr[5] = f; + } + } + } + + + /* read_mac(dev, device->mac_addr); */ + return(device->fd); +} + +/* ********************************** */ + +int tuntap_read(struct tuntap_dev *tuntap, unsigned char *buf, int len) { + return(read(tuntap->fd, buf, len)); +} + +/* ********************************** */ + +int tuntap_write(struct tuntap_dev *tuntap, unsigned char *buf, int len) { + return(write(tuntap->fd, buf, len)); +} + +/* ********************************** */ + +void tuntap_close(struct tuntap_dev *tuntap) { + close(tuntap->fd); +} + +/* Fill out the ip_addr value from the interface. Called to pick up dynamic + * address changes. */ +void tuntap_get_address(struct tuntap_dev *tuntap) +{ +} + +#endif /* #ifdef __NetBSD__ */ diff --git a/tuntap_osx.c b/tuntap_osx.c new file mode 100644 index 0000000..6b37b1f --- /dev/null +++ b/tuntap_osx.c @@ -0,0 +1,132 @@ +/* + * (C) 2007-09 - Luca Deri + * + * 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 3 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 see see + */ + +#include "n2n.h" + +#ifdef _DARWIN_ + +void tun_close(tuntap_dev *device); + +/* ********************************** */ + +#define N2N_OSX_TAPDEVICE_SIZE 32 +int tuntap_open(tuntap_dev *device /* ignored */, + char *dev, + const char *address_mode, /* static or dhcp */ + char *device_ip, + char *device_mask, + const char * device_mac, + int mtu) { + int i; + char tap_device[N2N_OSX_TAPDEVICE_SIZE]; + + for (i = 0; i < 255; i++) { + snprintf(tap_device, sizeof(tap_device), "/dev/tap%d", i); + + device->fd = open(tap_device, O_RDWR); + if(device->fd > 0) { + traceEvent(TRACE_NORMAL, "Succesfully open %s", tap_device); + break; + } + } + + if(device->fd < 0) { + traceEvent(TRACE_ERROR, "Unable to open tap device"); + return(-1); + } else { + char buf[256]; + FILE *fd; + + device->ip_addr = inet_addr(device_ip); + + if ( device_mac && device_mac[0] != '\0' ) + { + /* FIXME - This is not tested. Might be wrong syntax for OS X */ + + /* Set the hw address before bringing the if up. */ + snprintf(buf, sizeof(buf), "ifconfig tap%d ether %s", + i, device_mac); + system(buf); + } + + snprintf(buf, sizeof(buf), "ifconfig tap%d %s netmask %s mtu %d up", + i, device_ip, device_mask, mtu); + system(buf); + + traceEvent(TRACE_NORMAL, "Interface tap%d up and running (%s/%s)", + i, device_ip, device_mask); + + /* Read MAC address */ + + snprintf(buf, sizeof(buf), "ifconfig tap%d |grep ether|cut -c 8-24", i); + /* traceEvent(TRACE_INFO, "%s", buf); */ + + fd = popen(buf, "r"); + if(fd < 0) { + tun_close(device); + return(-1); + } else { + int a, b, c, d, e, f; + + buf[0] = 0; + fgets(buf, sizeof(buf), fd); + pclose(fd); + + if(buf[0] == '\0') { + traceEvent(TRACE_ERROR, "Unable to read tap%d interface MAC address"); + exit(0); + } + + traceEvent(TRACE_NORMAL, "Interface tap%d [MTU %d] mac %s", i, mtu, buf); + if(sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", &a, &b, &c, &d, &e, &f) == 6) { + device->mac_addr[0] = a, device->mac_addr[1] = b; + device->mac_addr[2] = c, device->mac_addr[3] = d; + device->mac_addr[4] = e, device->mac_addr[5] = f; + } + } + } + + + /* read_mac(dev, device->mac_addr); */ + return(device->fd); +} + +/* ********************************** */ + +int tuntap_read(struct tuntap_dev *tuntap, unsigned char *buf, int len) { + return(read(tuntap->fd, buf, len)); +} + +/* ********************************** */ + +int tuntap_write(struct tuntap_dev *tuntap, unsigned char *buf, int len) { + return(write(tuntap->fd, buf, len)); +} + +/* ********************************** */ + +void tuntap_close(struct tuntap_dev *tuntap) { + close(tuntap->fd); +} + +/* Fill out the ip_addr value from the interface. Called to pick up dynamic + * address changes. */ +void tuntap_get_address(struct tuntap_dev *tuntap) +{ +} + +#endif /* _DARWIN_ */ diff --git a/twofish.c b/twofish.c new file mode 100644 index 0000000..57661d7 --- /dev/null +++ b/twofish.c @@ -0,0 +1,1031 @@ +/* $Id: twofish.c,v 2.0 2002/08/11 22:32:25 fknobbe Exp $ + * + * + * Copyright (C) 1997-2000 The Cryptix Foundation Limited. + * Copyright (C) 2000 Farm9. + * Copyright (C) 2001 Frank Knobbe. + * All rights reserved. + * + * For Cryptix code: + * Use, modification, copying and distribution of this software is subject + * the terms and conditions of the Cryptix General Licence. You should have + * received a copy of the Cryptix General Licence along with this library; + * if not, you can download a copy from http://www.cryptix.org/ . + * + * For Farm9: + * --- jojo@farm9.com, August 2000, converted from Java to C++, added CBC mode and + * ciphertext stealing technique, added AsciiTwofish class for easy encryption + * decryption of text strings + * + * Frank Knobbe : + * --- April 2001, converted from C++ to C, prefixed global variables + * with TwoFish, substituted some defines, changed functions to make use of + * variables supplied in a struct, modified and added routines for modular calls. + * Cleaned up the code so that defines are used instead of fixed 16's and 32's. + * Created two general purpose crypt routines for one block and multiple block + * encryption using Joh's CBC code. + * Added crypt routines that use a header (with a magic and data length). + * (Basically a major rewrite). + * + * Note: Routines labeled _TwoFish are private and should not be used + * (or with extreme caution). + * + */ + +#ifndef __TWOFISH_LIBRARY_SOURCE__ +#define __TWOFISH_LIBRARY_SOURCE__ + +#include +#include +#include +#include +#include +#include "twofish.h" + + +bool TwoFish_srand=TRUE; /* if TRUE, first call of TwoFishInit will seed rand(); */ +/* of TwoFishInit */ + +/* Fixed 8x8 permutation S-boxes */ +static const uint8_t TwoFish_P[2][256] = + { + { /* p0 */ + 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78, + 0xE4, 0xDD, 0xD1, 0x38, 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C, + 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, 0xF2, 0xD0, 0x8B, 0x30, + 0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82, + 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE, + 0x16, 0x0C, 0xE3, 0x61, 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B, + 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, 0xE1, 0xE6, 0xBD, 0x45, + 0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7, + 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF, + 0x33, 0xC9, 0x62, 0x71, 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8, + 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, 0xA1, 0x1D, 0xAA, 0xED, + 0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90, + 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B, + 0x5F, 0x93, 0x0A, 0xEF, 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B, + 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, 0x2A, 0xCE, 0xCB, 0x2F, + 0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A, + 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17, + 0x55, 0x1F, 0x8A, 0x7D, 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72, + 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, 0x6E, 0x50, 0xDE, 0x68, + 0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4, + 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42, + 0x4A, 0x5E, 0xC1, 0xE0 + }, + { /* p1 */ + 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B, + 0x45, 0x7D, 0xE8, 0x4B, 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1, + 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, 0x5E, 0xBA, 0xAE, 0x5B, + 0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5, + 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54, + 0x92, 0x74, 0x36, 0x51, 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96, + 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, 0x13, 0x95, 0x9C, 0xC7, + 0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8, + 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF, + 0x40, 0xE7, 0x2B, 0xE2, 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9, + 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, 0x66, 0x94, 0xA1, 0x1D, + 0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E, + 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21, + 0xC4, 0x1A, 0xEB, 0xD9, 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01, + 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, 0x4F, 0xF2, 0x65, 0x8E, + 0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64, + 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44, + 0xE0, 0x4D, 0x43, 0x69, 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E, + 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, 0x22, 0xC9, 0xC0, 0x9B, + 0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9, + 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56, + 0x55, 0x09, 0xBE, 0x91 + } + }; + +static bool TwoFish_MDSready=FALSE; +static uint32_t TwoFish_MDS[4][256]; /* TwoFish_MDS matrix */ + + +#define TwoFish_LFSR1(x) (((x)>>1)^(((x)&0x01)?TwoFish_MDS_GF_FDBK/2:0)) +#define TwoFish_LFSR2(x) (((x)>>2)^(((x)&0x02)?TwoFish_MDS_GF_FDBK/2:0)^(((x)&0x01)?TwoFish_MDS_GF_FDBK/4:0)) + +#define TwoFish_Mx_1(x) ((uint32_t)(x)) /* force result to dword so << will work */ +#define TwoFish_Mx_X(x) ((uint32_t)((x)^TwoFish_LFSR2(x))) /* 5B */ +#define TwoFish_Mx_Y(x) ((uint32_t)((x)^TwoFish_LFSR1(x)^TwoFish_LFSR2(x))) /* EF */ +#define TwoFish_RS_rem(x) { uint8_t b=(uint8_t)(x>>24); uint32_t g2=((b<<1)^((b&0x80)?TwoFish_RS_GF_FDBK:0))&0xFF; uint32_t g3=((b>>1)&0x7F)^((b&1)?TwoFish_RS_GF_FDBK>>1:0)^g2; x=(x<<8)^(g3<<24)^(g2<<16)^(g3<<8)^b; } + +/*#define TwoFish__b(x,N) (((uint8_t *)&x)[((N)&3)^TwoFish_ADDR_XOR])*/ /* pick bytes out of a dword */ + +#define TwoFish_b0(x) TwoFish__b(x,0) /* extract LSB of uint32_t */ +#define TwoFish_b1(x) TwoFish__b(x,1) +#define TwoFish_b2(x) TwoFish__b(x,2) +#define TwoFish_b3(x) TwoFish__b(x,3) /* extract MSB of uint32_t */ + +uint8_t TwoFish__b(uint32_t x,int n) +{ n&=3; + while(n-->0) + x>>=8; + return (uint8_t)x; +} + + +/* TwoFish Initialization + * + * This routine generates a global data structure for use with TwoFish, + * initializes important values (such as subkeys, sBoxes), generates subkeys + * and precomputes the MDS matrix if not already done. + * + * Input: User supplied password (will be appended by default password of 'SnortHas2FishEncryptionRoutines!') + * + * Output: Pointer to TWOFISH structure. This data structure contains key dependent data. + * This pointer is used with all other crypt functions. + */ + +TWOFISH *TwoFishInit(const uint8_t *userkey, uint32_t keysize) +{ TWOFISH *tfdata; + int i,x,m; + uint8_t tkey[TwoFish_KEY_LENGTH+40]; + + memset( tkey, 0, TwoFish_KEY_LENGTH+40 ); + tfdata=(TWOFISH *)malloc(sizeof(TWOFISH)); /* allocate the TwoFish structure */ + if(tfdata!=NULL) + { + + /* Changes here prevented a dangerous random key segment for keys of length < TwoFish_KEY_LENGTH */ + if(keysize > 0) + { + memcpy( tkey, userkey, keysize ); /* The rest will be zeros */ + } + else + { + memcpy( tkey, TwoFish_DEFAULT_PW, TwoFish_DEFAULT_PW_LEN ); /* if no key defined, use default password */ + } + + /* This loop is awful - surely a loop on memcpy() would be clearer and more efficient */ + for(i=0,x=0,m=keysize;ikey[i]=tkey[x++]; /* fill the whole keyspace with repeating key. */ + if(x==m) + x=0; + } + + if(!TwoFish_MDSready) + _TwoFish_PrecomputeMDSmatrix(); /* "Wake Up, Neo" */ + _TwoFish_MakeSubKeys(tfdata); /* generate subkeys */ + _TwoFish_ResetCBC(tfdata); /* reset the CBC */ + tfdata->output=NULL; /* nothing to output yet */ + tfdata->dontflush=FALSE; /* reset decrypt skip block flag */ + if(TwoFish_srand) + { + TwoFish_srand=FALSE; + /* REVISIT: BbMaj7 : Should choose something with less predictability + * particularly for embedded targets with no real-time clock. */ + srand((unsigned int)time(NULL)); + } + } + return tfdata; /* return the data pointer */ +} + + +void TwoFishDestroy(TWOFISH *tfdata) +{ if(tfdata!=NULL) + free(tfdata); +} + + +/* en/decryption with CBC mode */ +uint32_t _TwoFish_CryptRawCBC(uint8_t *in,uint8_t *out,uint32_t len,bool decrypt,TWOFISH *tfdata) +{ uint32_t rl; + + rl=len; /* remember how much data to crypt. */ + while(len>TwoFish_BLOCK_SIZE) /* and now we process block by block. */ + { _TwoFish_BlockCrypt(in,out,TwoFish_BLOCK_SIZE,decrypt,tfdata); /* de/encrypt it. */ + in+=TwoFish_BLOCK_SIZE; /* adjust pointers. */ + out+=TwoFish_BLOCK_SIZE; + len-=TwoFish_BLOCK_SIZE; + } + if(len>0) /* if we have less than a block left... */ + _TwoFish_BlockCrypt(in,out,len,decrypt,tfdata); /* ...then we de/encrypt that too. */ + if(tfdata->qBlockDefined && !tfdata->dontflush) /* in case len was exactly one block... */ + _TwoFish_FlushOutput(tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE,tfdata); /* ...we need to write the... */ + /* ...remaining bytes of the buffer */ + return rl; +} + +/* en/decryption on one block only */ +uint32_t _TwoFish_CryptRaw16(uint8_t *in,uint8_t *out,uint32_t len,bool decrypt,TWOFISH *tfdata) +{ /* qBlockPlain already zero'ed through ResetCBC */ + memcpy(tfdata->qBlockPlain,in,len); /* toss the data into it. */ + _TwoFish_BlockCrypt16(tfdata->qBlockPlain,tfdata->qBlockCrypt,decrypt,tfdata); /* encrypt just that block without CBC. */ + memcpy(out,tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE); /* and return what we got */ + return TwoFish_BLOCK_SIZE; +} + +/* en/decryption without reset of CBC and output assignment */ +uint32_t _TwoFish_CryptRaw(uint8_t *in,uint8_t *out,uint32_t len,bool decrypt,TWOFISH *tfdata) +{ + if(in!=NULL && out!=NULL && len>0 && tfdata!=NULL) /* if we have valid data, then... */ + { if(len>TwoFish_BLOCK_SIZE) /* ...check if we have more than one block. */ + return _TwoFish_CryptRawCBC(in,out,len,decrypt,tfdata); /* if so, use the CBC routines... */ + else + return _TwoFish_CryptRaw16(in,out,len,decrypt,tfdata); /* ...otherwise just do one block. */ + } + return 0; +} + + +/* TwoFish Raw Encryption + * + * Does not use header, but does use CBC (if more than one block has to be encrypted). + * + * Input: Pointer to the buffer of the plaintext to be encrypted. + * Pointer to the buffer receiving the ciphertext. + * The length of the plaintext buffer. + * The TwoFish structure. + * + * Output: The amount of bytes encrypted if successful, otherwise 0. + */ + +uint32_t TwoFishEncryptRaw(uint8_t *in, + uint8_t *out, + uint32_t len, + TWOFISH *tfdata) +{ _TwoFish_ResetCBC(tfdata); /* reset CBC flag. */ + tfdata->output=out; /* output straight into output buffer. */ + return _TwoFish_CryptRaw(in,out,len,FALSE,tfdata); /* and go for it. */ +} + +/* TwoFish Raw Decryption + * + * Does not use header, but does use CBC (if more than one block has to be decrypted). + * + * Input: Pointer to the buffer of the ciphertext to be decrypted. + * Pointer to the buffer receiving the plaintext. + * The length of the ciphertext buffer (at least one cipher block). + * The TwoFish structure. + * + * Output: The amount of bytes decrypted if successful, otherwise 0. + */ + +uint32_t TwoFishDecryptRaw(uint8_t *in, + uint8_t *out, + uint32_t len, + TWOFISH *tfdata) +{ _TwoFish_ResetCBC(tfdata); /* reset CBC flag. */ + tfdata->output=out; /* output straight into output buffer. */ + return _TwoFish_CryptRaw(in,out,len,TRUE,tfdata); /* and go for it. */ +} + +/* TwoFish Free + * + * Free's the allocated buffer. + * + * Input: Pointer to the TwoFish structure + * + * Output: (none) + */ + +void TwoFishFree(TWOFISH *tfdata) +{ if(tfdata->output!=NULL) /* if a valid buffer is present... */ + { free(tfdata->output); /* ...then we free it for you... */ + tfdata->output=NULL; /* ...and mark as such. */ + } +} + +/* TwoFish Set Output + * + * If you want to allocate the output buffer yourself, + * then you can set it with this function. + * + * Input: Pointer to your output buffer + * Pointer to the TwoFish structure + * + * Output: (none) + */ + +void TwoFishSetOutput(uint8_t *outp,TWOFISH *tfdata) +{ tfdata->output=outp; /* (do we really need a function for this?) */ +} + +/* TwoFish Alloc + * + * Allocates enough memory for the output buffer that would be required + * + * Input: Length of the plaintext. + * Boolean flag for BinHex Output. + * Pointer to the TwoFish structure. + * + * Output: Returns a pointer to the memory allocated. + */ + +void *TwoFishAlloc(uint32_t len,bool binhex,bool decrypt,TWOFISH *tfdata) +{ + /* TwoFishFree(tfdata); */ /* (don't for now) discard whatever was allocated earlier. */ + if(decrypt) /* if decrypting... */ + { if(binhex) /* ...and input is binhex encoded... */ + len/=2; /* ...use half as much for output. */ + len-=TwoFish_BLOCK_SIZE; /* Also, subtract the size of the header. */ + } + else + { len+=TwoFish_BLOCK_SIZE; /* the size is just increased by the header... */ + if(binhex) + len*=2; /* ...and doubled if output is to be binhexed. */ + } + tfdata->output=malloc(len+TwoFish_BLOCK_SIZE);/* grab some memory...plus some extra (it's running over somewhere, crashes without extra padding) */ + + return tfdata->output; /* ...and return to caller. */ +} + +/* bin2hex and hex2bin conversion */ +void _TwoFish_BinHex(uint8_t *buf,uint32_t len,bool bintohex) +{ uint8_t *pi,*po,c; + + if(bintohex) + { for(pi=buf+len-1,po=buf+(2*len)-1;len>0;pi--,po--,len--) /* let's start from the end of the bin block. */ + { c=*pi; /* grab value. */ + c&=15; /* use lower 4 bits. */ + if(c>9) /* convert to ascii. */ + c+=('a'-10); + else + c+='0'; + *po--=c; /* set the lower nibble. */ + c=*pi; /* grab value again. */ + c>>=4; /* right shift 4 bits. */ + c&=15; /* make sure we only have 4 bits. */ + if(c>9) /* convert to ascii. */ + c+=('a'-10); + else + c+='0'; + *po=c; /* set the higher nibble. */ + } /* and keep going. */ + } + else + { for(pi=buf,po=buf;len>0;pi++,po++,len-=2) /* let's start from the beginning of the hex block. */ + { c=tolower(*pi++)-'0'; /* grab higher nibble. */ + if(c>9) /* convert to value. */ + c-=('0'-9); + *po=c<<4; /* left shit 4 bits. */ + c=tolower(*pi)-'0'; /* grab lower nibble. */ + if(c>9) /* convert to value. */ + c-=('0'-9); + *po|=c; /* and add to value. */ + } + } +} + + +/* TwoFish Encryption + * + * Uses header and CBC. If the output area has not been intialized with TwoFishAlloc, + * this routine will alloc the memory. In addition, it will include a small 'header' + * containing the magic and some salt. That way the decrypt routine can check if the + * packet got decrypted successfully, and return 0 instead of garbage. + * + * Input: Pointer to the buffer of the plaintext to be encrypted. + * Pointer to the pointer to the buffer receiving the ciphertext. + * The pointer either points to user allocated output buffer space, or to NULL, in which case + * this routine will set the pointer to the buffer allocated through the struct. + * The length of the plaintext buffer. + * Can be -1 if the input is a null terminated string, in which case we'll count for you. + * Boolean flag for BinHex Output (if used, output will be twice as large as input). + * Note: BinHex conversion overwrites (converts) input buffer! + * The TwoFish structure. + * + * Output: The amount of bytes encrypted if successful, otherwise 0. + */ + +uint32_t TwoFishEncrypt(uint8_t *in, + uint8_t **out, + signed long len, + bool binhex, + TWOFISH *tfdata) +{ uint32_t ilen,olen; + + +#if 0 +/* This is so broken it doesn't deserve to live. */ + if(len== -1) /* if we got -1 for len, we'll assume IN is a... */ + ilen=strlen(in); /* ...\0 terminated string and figure len out ourselves... */ + else + ilen=len; /* ...otherwise we trust you supply a correct length. */ +#endif + + ilen = len; + + if(in!=NULL && out!=NULL && ilen>0 && tfdata!=NULL) /* if we got usable stuff, we'll do it. */ + { if(*out==NULL) /* if OUT points to a NULL pointer... */ + *out=TwoFishAlloc(ilen,binhex,FALSE,tfdata); /* ...we'll (re-)allocate buffer space. */ + if(*out!=NULL) + { tfdata->output=*out; /* set output buffer. */ + tfdata->header.salt=rand()*65536+rand(); /* toss in some salt. */ + tfdata->header.length[0]= (uint8_t)(ilen); + tfdata->header.length[1]= (uint8_t)(ilen>>8); + tfdata->header.length[2]= (uint8_t)(ilen>>16); + tfdata->header.length[3]= (uint8_t)(ilen>>24); + memcpy(tfdata->header.magic,TwoFish_MAGIC,TwoFish_MAGIC_LEN); /* set the magic. */ + olen=TwoFish_BLOCK_SIZE; /* set output counter. */ + _TwoFish_ResetCBC(tfdata); /* reset the CBC flag */ + _TwoFish_BlockCrypt((uint8_t *)&(tfdata->header),*out,olen,FALSE,tfdata); /* encrypt first block (without flush on 16 byte boundary). */ + olen+=_TwoFish_CryptRawCBC(in,*out+TwoFish_BLOCK_SIZE,ilen,FALSE,tfdata); /* and encrypt the rest (we do not reset the CBC flag). */ + if(binhex) /* if binhex... */ + { _TwoFish_BinHex(*out,olen,TRUE); /* ...convert output to binhex... */ + olen*=2; /* ...and size twice as large. */ + } + tfdata->output=*out; + return olen; + } + } + return 0; +} + +/* TwoFish Decryption + * + * Uses header and CBC. If the output area has not been intialized with TwoFishAlloc, + * this routine will alloc the memory. In addition, it will check the small 'header' + * containing the magic. If magic does not match we return 0. Otherwise we return the + * amount of bytes decrypted (should be the same as the length in the header). + * + * Input: Pointer to the buffer of the ciphertext to be decrypted. + * Pointer to the pointer to the buffer receiving the plaintext. + * The pointer either points to user allocated output buffer space, or to NULL, in which case + * this routine will set the pointer to the buffer allocated through the struct. + * The length of the ciphertext buffer. + * Can be -1 if the input is a null terminated binhex string, in which case we'll count for you. + * Boolean flag for BinHex Input (if used, plaintext will be half as large as input). + * Note: BinHex conversion overwrites (converts) input buffer! + * The TwoFish structure. + * + * Output: The amount of bytes decrypted if successful, otherwise 0. + */ + +uint32_t TwoFishDecrypt(uint8_t *in, + uint8_t **out, + signed long len, + bool binhex, + TWOFISH *tfdata) +{ uint32_t ilen,elen,olen; + const uint8_t cmagic[TwoFish_MAGIC_LEN]=TwoFish_MAGIC; + uint8_t *tbuf; + + + +#if 0 +/* This is so broken it doesn't deserve to live. */ + if(len== -1) /* if we got -1 for len, we'll assume IN is a... */ + ilen=strlen(in); /* ...\0 terminated string and figure len out ourselves... */ + else + ilen=len; /* ...otherwise we trust you supply a correct length. */ +#endif + + ilen = len; + + if(in!=NULL && out!=NULL && ilen>0 && tfdata!=NULL) /* if we got usable stuff, we'll do it. */ + { if(*out==NULL) /* if OUT points to a NULL pointer... */ + *out=TwoFishAlloc(ilen,binhex,TRUE,tfdata); /* ...we'll (re-)allocate buffer space. */ + if(*out!=NULL) + { if(binhex) /* if binhex... */ + { _TwoFish_BinHex(in,ilen,FALSE); /* ...convert input to values... */ + ilen/=2; /* ...and size half as much. */ + } + _TwoFish_ResetCBC(tfdata); /* reset the CBC flag. */ + + tbuf=(uint8_t *)malloc(ilen+TwoFish_BLOCK_SIZE); /* get memory for data and header. */ + if(tbuf==NULL) + return 0; + tfdata->output=tbuf; /* set output to temp buffer. */ + + olen=_TwoFish_CryptRawCBC(in,tbuf,ilen,TRUE,tfdata)-TwoFish_BLOCK_SIZE; /* decrypt the whole thing. */ + memcpy(&(tfdata->header),tbuf,TwoFish_BLOCK_SIZE); /* copy first block into header. */ + tfdata->output=*out; + for(elen=0;elenheader.magic[elen]!=cmagic[elen]) + break; + if(elen==TwoFish_MAGIC_LEN) /* if magic matches then... */ + { elen=(tfdata->header.length[0]) | + (tfdata->header.length[1])<<8 | + (tfdata->header.length[2])<<16 | + (tfdata->header.length[3])<<24; /* .. we know how much to expect. */ + if(elen>olen) /* adjust if necessary. */ + elen=olen; + memcpy(*out,tbuf+TwoFish_BLOCK_SIZE,elen); /* copy data into intended output. */ + free(tbuf); + return elen; + } + free(tbuf); + } + } + return 0; +} + +void _TwoFish_PrecomputeMDSmatrix(void) /* precompute the TwoFish_MDS matrix */ +{ uint32_t m1[2]; + uint32_t mX[2]; + uint32_t mY[2]; + uint32_t i, j; + + for (i = 0; i < 256; i++) + { j = TwoFish_P[0][i] & 0xFF; /* compute all the matrix elements */ + m1[0] = j; + mX[0] = TwoFish_Mx_X( j ) & 0xFF; + mY[0] = TwoFish_Mx_Y( j ) & 0xFF; + + j = TwoFish_P[1][i] & 0xFF; + m1[1] = j; + mX[1] = TwoFish_Mx_X( j ) & 0xFF; + mY[1] = TwoFish_Mx_Y( j ) & 0xFF; + + TwoFish_MDS[0][i] = m1[TwoFish_P_00] | /* fill matrix w/ above elements */ + mX[TwoFish_P_00] << 8 | + mY[TwoFish_P_00] << 16 | + mY[TwoFish_P_00] << 24; + TwoFish_MDS[1][i] = mY[TwoFish_P_10] | + mY[TwoFish_P_10] << 8 | + mX[TwoFish_P_10] << 16 | + m1[TwoFish_P_10] << 24; + TwoFish_MDS[2][i] = mX[TwoFish_P_20] | + mY[TwoFish_P_20] << 8 | + m1[TwoFish_P_20] << 16 | + mY[TwoFish_P_20] << 24; + TwoFish_MDS[3][i] = mX[TwoFish_P_30] | + m1[TwoFish_P_30] << 8 | + mY[TwoFish_P_30] << 16 | + mX[TwoFish_P_30] << 24; + } + TwoFish_MDSready=TRUE; +} + + +void _TwoFish_MakeSubKeys(TWOFISH *tfdata) /* Expand a user-supplied key material into a session key. */ +{ uint32_t k64Cnt = TwoFish_KEY_LENGTH / 8; + uint32_t k32e[4]; /* even 32-bit entities */ + uint32_t k32o[4]; /* odd 32-bit entities */ + uint32_t sBoxKey[4]; + uint32_t offset,i,j; + uint32_t A, B, q=0; + uint32_t k0,k1,k2,k3; + uint32_t b0,b1,b2,b3; + + /* split user key material into even and odd 32-bit entities and */ + /* compute S-box keys using (12, 8) Reed-Solomon code over GF(256) */ + + + for (offset=0,i=0,j=k64Cnt-1;i<4 && offsetkey[offset++]; + k32e[i]|= tfdata->key[offset++]<<8; + k32e[i]|= tfdata->key[offset++]<<16; + k32e[i]|= tfdata->key[offset++]<<24; + k32o[i] = tfdata->key[offset++]; + k32o[i]|= tfdata->key[offset++]<<8; + k32o[i]|= tfdata->key[offset++]<<16; + k32o[i]|= tfdata->key[offset++]<<24; + sBoxKey[j] = _TwoFish_RS_MDS_Encode( k32e[i], k32o[i] ); /* reverse order */ + } + + /* compute the round decryption subkeys for PHT. these same subkeys */ + /* will be used in encryption but will be applied in reverse order. */ + i=0; + while(i < TwoFish_TOTAL_SUBKEYS) + { A = _TwoFish_F32( k64Cnt, q, k32e ); /* A uses even key entities */ + q += TwoFish_SK_BUMP; + + B = _TwoFish_F32( k64Cnt, q, k32o ); /* B uses odd key entities */ + q += TwoFish_SK_BUMP; + + B = B << 8 | B >> 24; + + A += B; + tfdata->subKeys[i++] = A; /* combine with a PHT */ + + A += B; + tfdata->subKeys[i++] = A << TwoFish_SK_ROTL | A >> (32-TwoFish_SK_ROTL); + } + + /* fully expand the table for speed */ + k0 = sBoxKey[0]; + k1 = sBoxKey[1]; + k2 = sBoxKey[2]; + k3 = sBoxKey[3]; + + for (i = 0; i < 256; i++) + { b0 = b1 = b2 = b3 = i; + switch (k64Cnt & 3) + { case 1: /* 64-bit keys */ + tfdata->sBox[ 2*i ] = TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][b0]) ^ TwoFish_b0(k0)]; + tfdata->sBox[ 2*i+1] = TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][b1]) ^ TwoFish_b1(k0)]; + tfdata->sBox[0x200+2*i ] = TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][b2]) ^ TwoFish_b2(k0)]; + tfdata->sBox[0x200+2*i+1] = TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][b3]) ^ TwoFish_b3(k0)]; + break; + case 0: /* 256-bit keys (same as 4) */ + b0 = (TwoFish_P[TwoFish_P_04][b0]) ^ TwoFish_b0(k3); + b1 = (TwoFish_P[TwoFish_P_14][b1]) ^ TwoFish_b1(k3); + b2 = (TwoFish_P[TwoFish_P_24][b2]) ^ TwoFish_b2(k3); + b3 = (TwoFish_P[TwoFish_P_34][b3]) ^ TwoFish_b3(k3); + case 3: /* 192-bit keys */ + b0 = (TwoFish_P[TwoFish_P_03][b0]) ^ TwoFish_b0(k2); + b1 = (TwoFish_P[TwoFish_P_13][b1]) ^ TwoFish_b1(k2); + b2 = (TwoFish_P[TwoFish_P_23][b2]) ^ TwoFish_b2(k2); + b3 = (TwoFish_P[TwoFish_P_33][b3]) ^ TwoFish_b3(k2); + case 2: /* 128-bit keys */ + tfdata->sBox[ 2*i ]= + TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][(TwoFish_P[TwoFish_P_02][b0]) ^ + TwoFish_b0(k1)]) ^ TwoFish_b0(k0)]; + + tfdata->sBox[ 2*i+1]= + TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][(TwoFish_P[TwoFish_P_12][b1]) ^ + TwoFish_b1(k1)]) ^ TwoFish_b1(k0)]; + + tfdata->sBox[0x200+2*i ]= + TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][(TwoFish_P[TwoFish_P_22][b2]) ^ + TwoFish_b2(k1)]) ^ TwoFish_b2(k0)]; + + tfdata->sBox[0x200+2*i+1]= + TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][(TwoFish_P[TwoFish_P_32][b3]) ^ + TwoFish_b3(k1)]) ^ TwoFish_b3(k0)]; + } + } +} + + +/** + * Encrypt or decrypt exactly one block of plaintext in CBC mode. + * Use "ciphertext stealing" technique described on pg. 196 + * of "Applied Cryptography" to encrypt the final partial + * (i.e. <16 byte) block if necessary. + * + * jojo: the "ciphertext stealing" requires we read ahead and have + * special handling for the last two blocks. Because of this, the + * output from the TwoFish algorithm is handled internally here. + * It would be better to have a higher level handle this as well as + * CBC mode. Unfortunately, I've mixed the two together, which is + * pretty crappy... The Java version separates these out correctly. + * + * fknobbe: I have reduced the CBC mode to work on memory buffer only. + * Higher routines should use an intermediate buffer and handle + * their output seperately (mainly so the data can be flushed + * in one chunk, not seperate 16 byte blocks...) + * + * @param in The plaintext. + * @param out The ciphertext + * @param size how much to encrypt + * @param tfdata: Pointer to the global data structure containing session keys. + * @return none + */ +void _TwoFish_BlockCrypt(uint8_t *in,uint8_t *out,uint32_t size,int decrypt,TWOFISH *tfdata) +{ uint8_t PnMinusOne[TwoFish_BLOCK_SIZE]; + uint8_t CnMinusOne[TwoFish_BLOCK_SIZE]; + uint8_t CBCplusCprime[TwoFish_BLOCK_SIZE]; + uint8_t Pn[TwoFish_BLOCK_SIZE]; + uint8_t *p,*pout; + uint32_t i; + + /* here is where we implement CBC mode and cipher block stealing */ + if(size==TwoFish_BLOCK_SIZE) + { /* if we are encrypting, CBC means we XOR the plain text block with the */ + /* previous cipher text block before encrypting */ + if(!decrypt && tfdata->qBlockDefined) + { for(p=in,i=0;iqBlockCrypt[i]; /* FK: I'm copying the xor'ed input into Pn... */ + } + else + memcpy(Pn,in,TwoFish_BLOCK_SIZE); /* FK: same here. we work of Pn all the time. */ + + /* TwoFish block level encryption or decryption */ + _TwoFish_BlockCrypt16(Pn,out,decrypt,tfdata); + + /* if we are decrypting, CBC means we XOR the result of the decryption */ + /* with the previous cipher text block to get the resulting plain text */ + if(decrypt && tfdata->qBlockDefined) + { for (p=out,i=0;iqBlockPlain[i]; + } + + /* save the input and output blocks, since CBC needs these for XOR */ + /* operations */ + _TwoFish_qBlockPush(Pn,out,tfdata); + } + else + { /* cipher block stealing, we are at Pn, */ + /* but since Cn-1 must now be replaced with CnC' */ + /* we pop it off, and recalculate Cn-1 */ + + if(decrypt) + { /* We are on an odd block, and had to do cipher block stealing, */ + /* so the PnMinusOne has to be derived differently. */ + + /* First we decrypt it into CBC and C' */ + _TwoFish_qBlockPop(CnMinusOne,PnMinusOne,tfdata); + _TwoFish_BlockCrypt16(CnMinusOne,CBCplusCprime,decrypt,tfdata); + + /* we then xor the first few bytes with the "in" bytes (Cn) */ + /* to recover Pn, which we put in out */ + for(p=in,pout=out,i=0;iprevCipher[i]; + + /* So at this point, out has PnMinusOne */ + _TwoFish_qBlockPush(CnMinusOne,PnMinusOne,tfdata); + _TwoFish_FlushOutput(tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE,tfdata); + _TwoFish_FlushOutput(out,size,tfdata); + } + else + { _TwoFish_qBlockPop(PnMinusOne,CnMinusOne,tfdata); + memset(Pn,0,TwoFish_BLOCK_SIZE); + memcpy(Pn,in,size); + for(i=0;iqBlockCrypt,TwoFish_BLOCK_SIZE,tfdata); + _TwoFish_FlushOutput(CnMinusOne,size,tfdata); /* old Cn-1 becomes new partial Cn */ + } + tfdata->qBlockDefined=FALSE; + } +} + +void _TwoFish_qBlockPush(uint8_t *p,uint8_t *c,TWOFISH *tfdata) +{ if(tfdata->qBlockDefined) + _TwoFish_FlushOutput(tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE,tfdata); + memcpy(tfdata->prevCipher,tfdata->qBlockPlain,TwoFish_BLOCK_SIZE); + memcpy(tfdata->qBlockPlain,p,TwoFish_BLOCK_SIZE); + memcpy(tfdata->qBlockCrypt,c,TwoFish_BLOCK_SIZE); + tfdata->qBlockDefined=TRUE; +} + +void _TwoFish_qBlockPop(uint8_t *p,uint8_t *c,TWOFISH *tfdata) +{ memcpy(p,tfdata->qBlockPlain,TwoFish_BLOCK_SIZE ); + memcpy(c,tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE ); + tfdata->qBlockDefined=FALSE; +} + +/* Reset's the CBC flag and zero's PrevCipher (through qBlockPlain) (important) */ +void _TwoFish_ResetCBC(TWOFISH *tfdata) +{ tfdata->qBlockDefined=FALSE; + memset(tfdata->qBlockPlain,0,TwoFish_BLOCK_SIZE); +} + +void _TwoFish_FlushOutput(uint8_t *b,uint32_t len,TWOFISH *tfdata) +{ uint32_t i; + + for(i=0;idontflush;i++) + *tfdata->output++ = *b++; + tfdata->dontflush=FALSE; +} + +void _TwoFish_BlockCrypt16(uint8_t *in,uint8_t *out,bool decrypt,TWOFISH *tfdata) +{ uint32_t x0,x1,x2,x3; + uint32_t k,t0,t1,R; + + + x0=*in++; + x0|=(*in++ << 8 ); + x0|=(*in++ << 16); + x0|=(*in++ << 24); + x1=*in++; + x1|=(*in++ << 8 ); + x1|=(*in++ << 16); + x1|=(*in++ << 24); + x2=*in++; + x2|=(*in++ << 8 ); + x2|=(*in++ << 16); + x2|=(*in++ << 24); + x3=*in++; + x3|=(*in++ << 8 ); + x3|=(*in++ << 16); + x3|=(*in++ << 24); + + if(decrypt) + { x0 ^= tfdata->subKeys[4]; /* swap input and output whitening keys when decrypting */ + x1 ^= tfdata->subKeys[5]; + x2 ^= tfdata->subKeys[6]; + x3 ^= tfdata->subKeys[7]; + + k = 7+(TwoFish_ROUNDS*2); + for (R = 0; R < TwoFish_ROUNDS; R += 2) + { t0 = _TwoFish_Fe320( tfdata->sBox, x0); + t1 = _TwoFish_Fe323( tfdata->sBox, x1); + x3 ^= t0 + (t1<<1) + tfdata->subKeys[k--]; + x3 = x3 >> 1 | x3 << 31; + x2 = x2 << 1 | x2 >> 31; + x2 ^= t0 + t1 + tfdata->subKeys[k--]; + + t0 = _TwoFish_Fe320( tfdata->sBox, x2); + t1 = _TwoFish_Fe323( tfdata->sBox, x3); + x1 ^= t0 + (t1<<1) + tfdata->subKeys[k--]; + x1 = x1 >> 1 | x1 << 31; + x0 = x0 << 1 | x0 >> 31; + x0 ^= t0 + t1 + tfdata->subKeys[k--]; + } + + x2 ^= tfdata->subKeys[0]; + x3 ^= tfdata->subKeys[1]; + x0 ^= tfdata->subKeys[2]; + x1 ^= tfdata->subKeys[3]; + } + else + { x0 ^= tfdata->subKeys[0]; + x1 ^= tfdata->subKeys[1]; + x2 ^= tfdata->subKeys[2]; + x3 ^= tfdata->subKeys[3]; + + k = 8; + for (R = 0; R < TwoFish_ROUNDS; R += 2) + { t0 = _TwoFish_Fe320( tfdata->sBox, x0); + t1 = _TwoFish_Fe323( tfdata->sBox, x1); + x2 ^= t0 + t1 + tfdata->subKeys[k++]; + x2 = x2 >> 1 | x2 << 31; + x3 = x3 << 1 | x3 >> 31; + x3 ^= t0 + (t1<<1) + tfdata->subKeys[k++]; + + t0 = _TwoFish_Fe320( tfdata->sBox, x2); + t1 = _TwoFish_Fe323( tfdata->sBox, x3); + x0 ^= t0 + t1 + tfdata->subKeys[k++]; + x0 = x0 >> 1 | x0 << 31; + x1 = x1 << 1 | x1 >> 31; + x1 ^= t0 + (t1<<1) + tfdata->subKeys[k++]; + } + + x2 ^= tfdata->subKeys[4]; + x3 ^= tfdata->subKeys[5]; + x0 ^= tfdata->subKeys[6]; + x1 ^= tfdata->subKeys[7]; + } + + *out++ = (uint8_t)(x2 ); + *out++ = (uint8_t)(x2 >> 8); + *out++ = (uint8_t)(x2 >> 16); + *out++ = (uint8_t)(x2 >> 24); + + *out++ = (uint8_t)(x3 ); + *out++ = (uint8_t)(x3 >> 8); + *out++ = (uint8_t)(x3 >> 16); + *out++ = (uint8_t)(x3 >> 24); + + *out++ = (uint8_t)(x0 ); + *out++ = (uint8_t)(x0 >> 8); + *out++ = (uint8_t)(x0 >> 16); + *out++ = (uint8_t)(x0 >> 24); + + *out++ = (uint8_t)(x1 ); + *out++ = (uint8_t)(x1 >> 8); + *out++ = (uint8_t)(x1 >> 16); + *out++ = (uint8_t)(x1 >> 24); +} + +/** + * Use (12, 8) Reed-Solomon code over GF(256) to produce a key S-box + * 32-bit entity from two key material 32-bit entities. + * + * @param k0 1st 32-bit entity. + * @param k1 2nd 32-bit entity. + * @return Remainder polynomial generated using RS code + */ +uint32_t _TwoFish_RS_MDS_Encode(uint32_t k0,uint32_t k1) +{ uint32_t i,r; + + for(r=k1,i=0;i<4;i++) /* shift 1 byte at a time */ + TwoFish_RS_rem(r); + r ^= k0; + for(i=0;i<4;i++) + TwoFish_RS_rem(r); + + return r; +} + +uint32_t _TwoFish_F32(uint32_t k64Cnt,uint32_t x,uint32_t *k32) +{ uint8_t b0,b1,b2,b3; + uint32_t k0,k1,k2,k3,result = 0; + + b0=TwoFish_b0(x); + b1=TwoFish_b1(x); + b2=TwoFish_b2(x); + b3=TwoFish_b3(x); + k0=k32[0]; + k1=k32[1]; + k2=k32[2]; + k3=k32[3]; + + switch (k64Cnt & 3) + { case 1: /* 64-bit keys */ + result = + TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][b0] & 0xFF) ^ TwoFish_b0(k0)] ^ + TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][b1] & 0xFF) ^ TwoFish_b1(k0)] ^ + TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][b2] & 0xFF) ^ TwoFish_b2(k0)] ^ + TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][b3] & 0xFF) ^ TwoFish_b3(k0)]; + break; + case 0: /* 256-bit keys (same as 4) */ + b0 = (TwoFish_P[TwoFish_P_04][b0] & 0xFF) ^ TwoFish_b0(k3); + b1 = (TwoFish_P[TwoFish_P_14][b1] & 0xFF) ^ TwoFish_b1(k3); + b2 = (TwoFish_P[TwoFish_P_24][b2] & 0xFF) ^ TwoFish_b2(k3); + b3 = (TwoFish_P[TwoFish_P_34][b3] & 0xFF) ^ TwoFish_b3(k3); + + case 3: /* 192-bit keys */ + b0 = (TwoFish_P[TwoFish_P_03][b0] & 0xFF) ^ TwoFish_b0(k2); + b1 = (TwoFish_P[TwoFish_P_13][b1] & 0xFF) ^ TwoFish_b1(k2); + b2 = (TwoFish_P[TwoFish_P_23][b2] & 0xFF) ^ TwoFish_b2(k2); + b3 = (TwoFish_P[TwoFish_P_33][b3] & 0xFF) ^ TwoFish_b3(k2); + case 2: /* 128-bit keys (optimize for this case) */ + result = + TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][(TwoFish_P[TwoFish_P_02][b0] & 0xFF) ^ TwoFish_b0(k1)] & 0xFF) ^ TwoFish_b0(k0)] ^ + TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][(TwoFish_P[TwoFish_P_12][b1] & 0xFF) ^ TwoFish_b1(k1)] & 0xFF) ^ TwoFish_b1(k0)] ^ + TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][(TwoFish_P[TwoFish_P_22][b2] & 0xFF) ^ TwoFish_b2(k1)] & 0xFF) ^ TwoFish_b2(k0)] ^ + TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][(TwoFish_P[TwoFish_P_32][b3] & 0xFF) ^ TwoFish_b3(k1)] & 0xFF) ^ TwoFish_b3(k0)]; + break; + } + return result; +} + +uint32_t _TwoFish_Fe320(uint32_t *lsBox,uint32_t x) +{ return lsBox[ TwoFish_b0(x)<<1 ]^ + lsBox[ ((TwoFish_b1(x)<<1)|1)]^ + lsBox[0x200+ (TwoFish_b2(x)<<1) ]^ + lsBox[0x200+((TwoFish_b3(x)<<1)|1)]; +} + +uint32_t _TwoFish_Fe323(uint32_t *lsBox,uint32_t x) +{ return lsBox[ (TwoFish_b3(x)<<1) ]^ + lsBox[ ((TwoFish_b0(x)<<1)|1)]^ + lsBox[0x200+ (TwoFish_b1(x)<<1) ]^ + lsBox[0x200+((TwoFish_b2(x)<<1)|1)]; +} + +uint32_t _TwoFish_Fe32(uint32_t *lsBox,uint32_t x,uint32_t R) +{ return lsBox[ 2*TwoFish__b(x,R ) ]^ + lsBox[ 2*TwoFish__b(x,R+1)+1]^ + lsBox[0x200+2*TwoFish__b(x,R+2) ]^ + lsBox[0x200+2*TwoFish__b(x,R+3)+1]; +} + + +#endif + +/* ******************************************* */ +#if defined TWOFISH_UNIT_TEST +#include + +#define TEST_DATA_SIZE 327 + +int main(int argc, char* argv[]) +{ + int i; + int n; + + char outbuf[4096]; + char * outp = outbuf; + + uint8_t key[] = { 0xfc, 0x77, 0x1a, 0xda, 0xaa }; + TWOFISH *tfa = TwoFishInit( key, 5 ); + TWOFISH *tfb = TwoFishInit( key, 5 ); + + uint8_t out[2048], out2[2048]; + uint8_t in[TEST_DATA_SIZE]; + + for ( i=0; i: + * --- April 2001, converted from C++ to C, prefixed global variables + * with TwoFish, substituted some defines, changed functions to make use of + * variables supplied in a struct, modified and added routines for modular calls. + * Cleaned up the code so that defines are used instead of fixed 16's and 32's. + * Created two general purpose crypt routines for one block and multiple block + * encryption using Joh's CBC code. + * Added crypt routines that use a header (with a magic and data length). + * (Basically a major rewrite). + * + * Note: Routines labeled _TwoFish are private and should not be used + * (or with extreme caution). + * + */ + +#ifndef __TWOFISH_LIBRARY_HEADER__ +#define __TWOFISH_LIBRARY_HEADER__ + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE !FALSE +#endif +#ifndef bool +#define bool int +#endif + +#ifdef WIN32 +#include "win32/n2n_win32.h" +#endif + +#ifndef _MSC_VER +/* Not shipped with Visual Studio (as stated by the stdint.h wikipedia page) */ +#include /* defines uintN_t types */ +#endif + +#ifdef __sun__ /* Should be HAVE_SYS_TYPES */ +/* The following are redefinitions if sys/types.h has been included too.*/ +typedef uint32_t uint32_t; +typedef uint8_t uint8_t; +#endif /* #ifdef __sun__ */ + +/* Constants */ + +#define TwoFish_DEFAULT_PW "SnortHas2FishEncryptionRoutines!" /* default password (not more than 32 chars) */ +#define TwoFish_DEFAULT_PW_LEN 32 +#define TwoFish_MAGIC "TwoFish" /* to indentify a successful decryption */ + +enum +{ TwoFish_KEY_SIZE = 256, /* Valid values: 64, 128, 192, 256 */ + /* User 256, other key sizes have not been tested. */ + /* (But should work. I substitutes as much as */ + /* I could with this define.) */ + TwoFish_ROUNDS = 16, + TwoFish_BLOCK_SIZE = 16, /* bytes in a data-block */ + TwoFish_KEY_LENGTH = TwoFish_KEY_SIZE/8, /* 32= 256-bit key */ + TwoFish_TOTAL_SUBKEYS = 4+4+2*TwoFish_ROUNDS, + TwoFish_MAGIC_LEN = TwoFish_BLOCK_SIZE-8, + TwoFish_SK_BUMP = 0x01010101, + TwoFish_SK_ROTL = 9, + TwoFish_P_00 = 1, + TwoFish_P_01 = 0, + TwoFish_P_02 = 0, + TwoFish_P_03 = TwoFish_P_01 ^ 1, + TwoFish_P_04 = 1, + TwoFish_P_10 = 0, + TwoFish_P_11 = 0, + TwoFish_P_12 = 1, + TwoFish_P_13 = TwoFish_P_11 ^ 1, + TwoFish_P_14 = 0, + TwoFish_P_20 = 1, + TwoFish_P_21 = 1, + TwoFish_P_22 = 0, + TwoFish_P_23 = TwoFish_P_21 ^ 1, + TwoFish_P_24 = 0, + TwoFish_P_30 = 0, + TwoFish_P_31 = 1, + TwoFish_P_32 = 1, + TwoFish_P_33 = TwoFish_P_31 ^ 1, + TwoFish_P_34 = 1, + TwoFish_GF256_FDBK = 0x169, + TwoFish_GF256_FDBK_2 = 0x169 / 2, + TwoFish_GF256_FDBK_4 = 0x169 / 4, + TwoFish_RS_GF_FDBK = 0x14D, /* field generator */ + TwoFish_MDS_GF_FDBK = 0x169 /* primitive polynomial for GF(256) */ +}; + + +/* Global data structure for callers */ + +typedef struct +{ + uint32_t sBox[4 * 256]; /* Key dependent S-box */ + uint32_t subKeys[TwoFish_TOTAL_SUBKEYS]; /* Subkeys */ + uint8_t key[TwoFish_KEY_LENGTH]; /* Encryption Key */ + uint8_t *output; /* Pointer to output buffer */ + uint8_t qBlockPlain[TwoFish_BLOCK_SIZE]; /* Used by CBC */ + uint8_t qBlockCrypt[TwoFish_BLOCK_SIZE]; + uint8_t prevCipher[TwoFish_BLOCK_SIZE]; + struct /* Header for crypt functions. Has to be at least one block long. */ + { uint32_t salt; /* Random salt in first block (will salt the rest through CBC) */ + uint8_t length[4]; /* The amount of data following the header */ + uint8_t magic[TwoFish_MAGIC_LEN]; /* Magic to identify successful decryption */ + } header; + bool qBlockDefined; + bool dontflush; +} TWOFISH; + +#ifndef __TWOFISH_LIBRARY_SOURCE__ + +extern bool TwoFish_srand; /* if set to TRUE (default), first call of TwoFishInit will seed rand(); */ + /* call of TwoFishInit */ +#endif + + +/**** Public Functions ****/ + +/* TwoFish Initialization + * + * This routine generates a global data structure for use with TwoFish, + * initializes important values (such as subkeys, sBoxes), generates subkeys + * and precomputes the MDS matrix if not already done. + * + * Input: User supplied password (will be appended by default password of 'SnortHas2FishEncryptionRoutines!') + * + * Output: Pointer to TWOFISH structure. This data structure contains key dependent data. + * This pointer is used with all other crypt functions. + */ +TWOFISH *TwoFishInit(const uint8_t *userkey, uint32_t keysize ); + + +/* TwoFish Destroy + * + * Nothing else but a free... + * + * Input: Pointer to the TwoFish structure. + * + */ +void TwoFishDestroy(TWOFISH *tfdata); + + +/* TwoFish Alloc + * + * Allocates enough memory for the output buffer as required. + * + * Input: Length of the plaintext. + * Boolean flag for BinHex Output. + * Pointer to the TwoFish structure. + * + * Output: Returns a pointer to the memory allocated. + */ +void *TwoFishAlloc(uint32_t len,bool binhex,bool decrypt,TWOFISH *tfdata); + + +/* TwoFish Free + * + * Free's the allocated buffer. + * + * Input: Pointer to the TwoFish structure + * + * Output: (none) + */ +void TwoFishFree(TWOFISH *tfdata); + + +/* TwoFish Set Output + * + * If you want to allocate the output buffer yourself, + * then you can set it with this function. + * + * Input: Pointer to your output buffer + * Pointer to the TwoFish structure + * + * Output: (none) + */ +void TwoFishSetOutput(uint8_t *outp,TWOFISH *tfdata); + + +/* TwoFish Raw Encryption + * + * Does not use header, but does use CBC (if more than one block has to be encrypted). + * + * Input: Pointer to the buffer of the plaintext to be encrypted. + * Pointer to the buffer receiving the ciphertext. + * The length of the plaintext buffer. + * The TwoFish structure. + * + * Output: The amount of bytes encrypted if successful, otherwise 0. + */ +uint32_t TwoFishEncryptRaw(uint8_t *in,uint8_t *out,uint32_t len,TWOFISH *tfdata); + +/* TwoFish Raw Decryption + * + * Does not use header, but does use CBC (if more than one block has to be decrypted). + * + * Input: Pointer to the buffer of the ciphertext to be decrypted. + * Pointer to the buffer receiving the plaintext. + * The length of the ciphertext buffer (at least one cipher block). + * The TwoFish structure. + * + * Output: The amount of bytes decrypted if successful, otherwise 0. + */ +uint32_t TwoFishDecryptRaw(uint8_t *in,uint8_t *out,uint32_t len,TWOFISH *tfdata); + + +/* TwoFish Encryption + * + * Uses header and CBC. If the output area has not been intialized with TwoFishAlloc, + * this routine will alloc the memory. In addition, it will include a small 'header' + * containing the magic and some salt. That way the decrypt routine can check if the + * packet got decrypted successfully, and return 0 instead of garbage. + * + * Input: Pointer to the buffer of the plaintext to be encrypted. + * Pointer to the pointer to the buffer receiving the ciphertext. + * The pointer either points to user allocated output buffer space, or to NULL, in which case + * this routine will set the pointer to the buffer allocated through the struct. + * The length of the plaintext buffer. + * Can be -1 if the input is a null terminated string, in which case we'll count for you. + * Boolean flag for BinHex Output (if used, output will be twice as large as input). + * Note: BinHex conversion overwrites (converts) input buffer! + * The TwoFish structure. + * + * Output: The amount of bytes encrypted if successful, otherwise 0. + */ +uint32_t TwoFishEncrypt(uint8_t *in,uint8_t **out,signed long len,bool binhex,TWOFISH *tfdata); + + +/* TwoFish Decryption + * + * Uses header and CBC. If the output area has not been intialized with TwoFishAlloc, + * this routine will alloc the memory. In addition, it will check the small 'header' + * containing the magic. If magic does not match we return 0. Otherwise we return the + * amount of bytes decrypted (should be the same as the length in the header). + * + * Input: Pointer to the buffer of the ciphertext to be decrypted. + * Pointer to the pointer to the buffer receiving the plaintext. + * The pointer either points to user allocated output buffer space, or to NULL, in which case + * this routine will set the pointer to the buffer allocated through the struct. + * The length of the ciphertext buffer. + * Can be -1 if the input is a null terminated binhex string, in which case we'll count for you. + * Boolean flag for BinHex Input (if used, plaintext will be half as large as input). + * Note: BinHex conversion overwrites (converts) input buffer! + * The TwoFish structure. + * + * Output: The amount of bytes decrypted if successful, otherwise 0. + */ +uint32_t TwoFishDecrypt(uint8_t *in,uint8_t **out,signed long len,bool binhex,TWOFISH *tfdata); + + +/**** Private Functions ****/ + +uint8_t TwoFish__b(uint32_t x,int n); +void _TwoFish_BinHex(uint8_t *buf,uint32_t len,bool bintohex); +uint32_t _TwoFish_CryptRawCBC(uint8_t *in,uint8_t *out,uint32_t len,bool decrypt,TWOFISH *tfdata); +uint32_t _TwoFish_CryptRaw16(uint8_t *in,uint8_t *out,uint32_t len,bool decrypt,TWOFISH *tfdata); +uint32_t _TwoFish_CryptRaw(uint8_t *in,uint8_t *out,uint32_t len,bool decrypt,TWOFISH *tfdata); +void _TwoFish_PrecomputeMDSmatrix(void); +void _TwoFish_MakeSubKeys(TWOFISH *tfdata); +void _TwoFish_qBlockPush(uint8_t *p,uint8_t *c,TWOFISH *tfdata); +void _TwoFish_qBlockPop(uint8_t *p,uint8_t *c,TWOFISH *tfdata); +void _TwoFish_ResetCBC(TWOFISH *tfdata); +void _TwoFish_FlushOutput(uint8_t *b,uint32_t len,TWOFISH *tfdata); +void _TwoFish_BlockCrypt(uint8_t *in,uint8_t *out,uint32_t size,int decrypt,TWOFISH *tfdata); +void _TwoFish_BlockCrypt16(uint8_t *in,uint8_t *out,bool decrypt,TWOFISH *tfdata); +uint32_t _TwoFish_RS_MDS_Encode(uint32_t k0,uint32_t k1); +uint32_t _TwoFish_F32(uint32_t k64Cnt,uint32_t x,uint32_t *k32); +uint32_t _TwoFish_Fe320(uint32_t *lsBox,uint32_t x); +uint32_t _TwoFish_Fe323(uint32_t *lsBox,uint32_t x); +uint32_t _TwoFish_Fe32(uint32_t *lsBox,uint32_t x,uint32_t R); + + +#endif diff --git a/version.c b/version.c new file mode 100644 index 0000000..0963b8f --- /dev/null +++ b/version.c @@ -0,0 +1,3 @@ +const char * n2n_sw_version = N2N_VERSION; +const char * n2n_sw_osName = N2N_OSNAME; +const char * n2n_sw_buildDate = __DATE__ " " __TIME__; diff --git a/win32/CMakeLists.txt b/win32/CMakeLists.txt new file mode 100644 index 0000000..0d97194 --- /dev/null +++ b/win32/CMakeLists.txt @@ -0,0 +1,4 @@ +add_library(n2n_win32 + win32/getopt1.c + win32/getopt.c + win32/wintap.c) diff --git a/win32/DotNet/n2n.sln b/win32/DotNet/n2n.sln new file mode 100644 index 0000000..c8cfda1 --- /dev/null +++ b/win32/DotNet/n2n.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual C++ Express 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "edge", "n2n.vcproj", "{4911ADD4-08A3-4C9F-B9C9-9492DA10D01D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "supernode", "supernode.vcproj", "{BDB93CAB-BE22-4ED6-9A05-2E4D6F1D76E1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4911ADD4-08A3-4C9F-B9C9-9492DA10D01D}.Debug|Win32.ActiveCfg = Debug|Win32 + {4911ADD4-08A3-4C9F-B9C9-9492DA10D01D}.Debug|Win32.Build.0 = Debug|Win32 + {4911ADD4-08A3-4C9F-B9C9-9492DA10D01D}.Release|Win32.ActiveCfg = Release|Win32 + {4911ADD4-08A3-4C9F-B9C9-9492DA10D01D}.Release|Win32.Build.0 = Release|Win32 + {BDB93CAB-BE22-4ED6-9A05-2E4D6F1D76E1}.Debug|Win32.ActiveCfg = Debug|Win32 + {BDB93CAB-BE22-4ED6-9A05-2E4D6F1D76E1}.Debug|Win32.Build.0 = Debug|Win32 + {BDB93CAB-BE22-4ED6-9A05-2E4D6F1D76E1}.Release|Win32.ActiveCfg = Release|Win32 + {BDB93CAB-BE22-4ED6-9A05-2E4D6F1D76E1}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/win32/DotNet/n2n.suo b/win32/DotNet/n2n.suo new file mode 100644 index 0000000000000000000000000000000000000000..aae212bdc7603fcc776941462dec540d87901d0e GIT binary patch literal 24576 zcmeI43A|TTwZ{)42u>jQaK_8z%oQ%kpr~B9Aeaa_fE9)yC@Nfti!++}URvgy4K`_| zmN{FRRxfAMG%@qNQqwdo&8ImunWnz)_nfumaN+*{cc6T}j|+bPz5c(m&e`+YYwz=i z2bXX3)x*0scULKnI8%(AsmI)k^~e*5i$%reyXAX!r7hr#P1M7hGKzFb%*Z`~#wgel39)KZ`Z3KFO-e6i^iwguaP?ZFOUM=%&T))L-B&HR71sQYD$__LJ0n2$jb&N}5aMR3G5{w~Wqzujva+>qzao*35r> zien0rXPuP2;d)!V?jMg`89+-k#w)nCzI|CJ^=OsQ^3ApDwqa72=)W}g9E^UU^LQgf~W*r>D zedGD&GZs;gk$j(w&zL}Z3{UgB{$c^w59525ozTWIH1|K_DB(Pwc@(X;Dg>1dGYnc4(}ayM5nw|8JkS-=`RUtJHr*{>Rg&b121vmF{i+r9Ji67o_LZ;H^471|8Q+ z(<9rQI(M2&N4VzCs`R~U*2$iD&M`?4d%@bh)*{@+SFaTgBFnD*$kCndnR#?>mmOUj z9TyMn$_~gY>w;c!>1S6A@AcAKe|)>RBMeDa#~VLSVWcg{$GaY2cHWjpGXqj=)C zb8uz1m0DlE1#JE%kRVw@*AxKevGTr#iaY7>OT2JgWb5bt(Mt zYO`m5*LMHw3fvg=pNfw=k{RGyS>(NGc{j*%U)+s?pTvvr2@HNJ1wT!-T`M7fzG!Cn| z1R=ssZTxo@BT+Va~kaa)YPes<$Q4_z~0z+N~0?x~ZuowLy4hwPt?I&9v@FU#klywL?I`}GM%@Z$)`of8U8c z+Oz&mBD$EH=iSIyUO;IkQW|}}tKdIB|EYQGvw%`G<~TgOt1E8<%#syVU9IN&n_{ol z)_)*RxwYTCmgMhJ?*5>)`47U@vo$51bEfmp{aJI3K|F&rDy-H6#y@SX zzvne+|6Qs5J;SRe?K%JS-NH8_{+Uh<51_`5Id|K~(f^LTW9WO&A*zY-XAMTF4XW9D zy%t3G6KmPZs~>-!V^$OD-^qB^_b#pNf6s`<#DhPx_ScVBjphipc;_Q$Io+e$7sj}9 zo}IhrQ99y(=5zlG-LL$Z&q-xZ?J^FoTqe($#+U4t$MsQF{okryzwqAQyZrng@sM|N zR#!F$=4@@RA2_|BEot&~Oxg zM#2_hph3dKoY@6-G|f}TMu3+Zb?rKfih(qQw(M9?I+0RMWEc#iG|T8}kFJ|&ofU^O zd%(Y2L$7FW!|EcW-i4BkphazeH&$-E+>F`YqhUwn?LCaEBl7EYw6dEo+bFg7u;IJl zZF^^5>3mtI>gRt3j4Mm8_r&T@ybQXZOXK97bK+`FrC2xGzdxz|e2QF1>)S4E#pY+r zI=X(X?u}LJR*)i&X#e_cKc;qVV09VKyVog9{F9mZGwI<5zD?#`?c`u4^L-k2`?ER~ zHV4rA3mI}V`F;!zZWxZDmT_?$C?cPZL^tjbeJj*Zby+D-%c5&$mEK#r+7`dH>PTsP zhHq+js#=;fI4r+WSL^RE4VLjm*BLyvOF!8^u1X zh&DWXb}!`$ezvEbN`CA)6X6rEf>3qcD&5$i2oUTf6rM|I_&_8 zW1TjxgPU-FCt&OOn-70;;_p7>3=_T$?Aa@UoO^G76QkS!O(8++N_O(0>*w zN%nvrNZS8QLVqx4*h`V7=e-!*AA=i0`f_l83eK;84(>0(xvTkWaDNZZudfI9MsPKx zZwBYPZ1c6A|0r?Ap3XP<<@5WFtiO3AXVknRa?bNh>ptFKW zWzY2f`sX?1`|Drx)iaHi|9|UWvEr`kxl)Z+e&_J>eQ(JZ%XD70W}?eG>mQ%3BTY{= zQXB{-06n{>i^hVAD~?U?%i~o_oaN=5?vbUe0bj6hgZIT&8`2bPMuM#YZp>E zqpPkc{Ycjd&XukkdVgkW^Mj_950#2%w10i7_WYLjPi3#Vx_I-OA8CA~<==;%P7OZ= zJ`K(Qp8;orv%uNl9B?i;51bD^3oZbk1D^+90ABr_kerBPr-fQ zeqbz?%2Fx6Ut;$wKoe(=g2%wG!Q_3WmR{NcV1yZeRB+ zal?WeUgAauH@d`)3C>ZLo;NNyM_J#-O( z4wnSy7;Osf=-{m5$3s6YQtvq z<$Xq~aOL^qFLmFyk~?$MInOX!2Jd%0xyN^q~1?AGgC%-i)z)BM>WxDA8TXa0qI zTo-x-XPLJ{w=CNSr|;S!xE)J&W6>>3eaUWIaN|pM(}SB)vO6fa50&f|pgTtwmh2jX zTU4?;2fZJ5=a%fw3-0`q-IeH;@2ZmB)xlj;vbz<10Cu+pXMJxE?vCJ~vb)h~uI!%R zY^%r62b2CfIPZNtxFe?!+lzE-mPdvLFp?ABYmDD(QH@AO-68wO{-{m^ZL{w2Es z!3`|g?HSzIl3jgp<4Sf1qwmP`K3cMy72F{uyW`Mp)8k8aCj@t5aQc;dsgrV2aO$U^ z+kU48XFa}%?)q|JaJJusiR+2p11LkWOTJ7S<#GyXH(X6BC;kh)qx=7kzc+c~!fgx) z^AZ^;3s)pPlBL`LxH_8l1#&f0x3f;wSm%`I@&<(Ks%CoK!EZ zRLb9<4OSC>f2qvcZ#5npbdH1loe^A=rx@Xm>Yl)nqE~em$>|xl z1B$aEjs7t?Q~b{qa`j+*aQl)byX5=LSWd67A5dn4WH%>gGJXwFaLzhc3Z>FYurt@2 za;xIBJ3Y^n9p!64&e4AnP`(Y4-Q_t`oOsJwhbw~nA!)Kp-uyp_CR;$?G;=X^hseiCAb>6-GiGJ98~r}^v$KCEv#G18|U(jHa4A-IWQXB@Lva1R8h-E#EG{>S-IS@b{sFfqnx zxt1$G<4V4+9j#M2eV*civq_TB!^}k8R7-l1t^RFw6DtxB=?Jmnu!StO=e??nH z{H#>YzxoP9{&~J_ssAU)S5KPc=cRG-ix?;F`|Tn<+LNI_AE~4Np=O-VdJ#_fV_b9n zekr)ksc&?7wnfyvZ*Z<(gV3Ep+XZJHW6+&_?lrtuyD8{;rGtZW_ANx$esPI&U+(k% zJvi_E47#hy*(L4*bc>kw=h|H#T-sy%>|5ZrAiXv2wZGkW>z(ci&U+t1ch)={ocI0~ z-LgDgvU?Vtzx-D6U-yf(|?^uwylY=`w zIOB!0z-VxGa3uMgXYaivxE`dJ0p)6to_7tpcGm}IS-uODn}K%rylb&Ne+!UvWZVjN z2e$(`^Ke(D+y&$u!FL1YJ|L&u56t%$AaPFx_jHMSCAdG8xYvXGM~PdDhxj}_ug|kx zx&^mEa8Oy#;Chuf;{xw>{pW8k!-Gp}y!|^eF1j|W+Aa+!4WyHUvt9h(2L_W)4XzKm zZ;JSvui>W3fhguXBd*EK5AKNI?2jYSmBy0YqOd!*#QFBf=bcpI+?mR`E9Gx4zCDur zT#36lxNnrWD}zgKl)U+S!5Js;HTsmKiSou4sJ!H@nTriaAj+Br3cNEEcD)<`K_jOkO4z4io$~S#* zx`P%d-9H~A*We>aZ50|WTYzp4d@O%}?7!mtZd39(7bsr@=Igk>6e!7O+vnHi45#Fz z+UZ|z3hq|Y#N83xy}^0!a-bjod2rVBq2L}4Zavbc!2s|~iF-D<=Yn(onzynOnXYK# zf-|RTzyDj^FCH&^{%>db1nW_jetePJ1{@a`J|3K3PXUh8Gk|u^1>0(Ga6OP43(f>e zTHgkur*$i>Z;qJO8nfq@Ry_o#$u8y{;pnW;dXC?@xmB-iOh> z_mSYd_h;xz=kRaaqOa|gMLgB?vR{Yuu@~ts`F|deM+RInGUx)jf^|T(-^^!^g}AiCvzD7abZ#t(|WBw!F{^}y3^<@Mmk zqQ4QGmC??*vX&VkU4v^tUnjT?gWDgjM{rAm^PVPj=@Ww64gEw3Bco=obonp>m&acZ(?dq literal 0 HcmV?d00001 diff --git a/win32/DotNet/n2n.vcproj b/win32/DotNet/n2n.vcproj new file mode 100644 index 0000000..650e694 --- /dev/null +++ b/win32/DotNet/n2n.vcproj @@ -0,0 +1,300 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win32/DotNet/supernode.vcproj b/win32/DotNet/supernode.vcproj new file mode 100644 index 0000000..c54e95b --- /dev/null +++ b/win32/DotNet/supernode.vcproj @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win32/getopt.c b/win32/getopt.c new file mode 100644 index 0000000..c938ea3 --- /dev/null +++ b/win32/getopt.c @@ -0,0 +1,1074 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to drepper@gnu.org + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000 + Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in . + Ditto for AIX 3.2 and . */ +#ifndef _NO_PROTO +# define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +# ifndef const +# define const +# endif +#endif + +#include +#ifdef WIN32 +#include +#endif + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +# include +# if _GNU_GETOPT<_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +# define ELIDE_CODE +# endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +# include +# include +#endif /* GNU C library. */ + +#ifdef VMS +# include +# if HAVE_STRING_H - 0 +# include +# endif +#endif + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. + When compiling libc, the _ macro is predefined. */ +# ifdef HAVE_LIBINTL_H +# include +# define _(msgid) gettext (msgid) +# else +# define _(msgid) (msgid) +# endif +#endif + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +#ifndef DARWIN +char *optarg; +#endif + + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* 1003.2 says this must be 1 before any call. */ +#ifndef DARWIN +int optind = 1; +#endif + +/* Formerly, initialization of getopt depended on optind==0, which + causes problems with re-calling getopt as programs generally don't + know that. */ + +int __getopt_initialized; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +#ifndef DARWIN +#ifdef WIN32 +int opterr = 0; +#else +int opterr = 1; +#endif +#endif + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ +#ifndef DARWIN +int optopt = '?'; +#endif + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return -1 with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +# include +# define my_index strchr +#else + +#ifndef WIN32 +# if HAVE_STRING_H +# include +# else +# include +# endif +#endif + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +#ifndef getenv +extern char *getenv (); +#endif + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +# if (!defined __STDC__ || !__STDC__) && !defined strlen +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +# endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +#ifdef _LIBC +/* Bash 2.0 gives us an environment variable containing flags + indicating ARGV elements that should not be considered arguments. */ + +/* Defined in getopt_init.c */ +extern char *__getopt_nonoption_flags; + +static int nonoption_flags_max_len; +static int nonoption_flags_len; + +static int original_argc; +static char *const *original_argv; + +/* Make sure the environment variable bash 2.0 puts in the environment + is valid for the getopt call we must make sure that the ARGV passed + to getopt is that one passed to the process. */ +static void +__attribute__ ((unused)) +store_args_and_env (int argc, char *const *argv) +{ + /* XXX This is no good solution. We should rather copy the args so + that we can compare them later. But we must not use malloc(3). */ + original_argc = argc; + original_argv = argv; +} +# ifdef text_set_element +text_set_element (__libc_subinit, store_args_and_env); +# endif /* text_set_element */ + +# define SWAP_FLAGS(ch1, ch2) \ + if (nonoption_flags_len > 0) \ + { \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ + } +#else /* !_LIBC */ +# define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +#if defined __STDC__ && __STDC__ +static void exchange (char **); +#endif + +static void +exchange (argv) + char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + +#ifdef _LIBC + /* First make sure the handling of the `__getopt_nonoption_flags' + string can work normally. Our top argument must be in the range + of the string. */ + if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) + { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char *new_str = malloc (top + 1); + if (new_str == NULL) + nonoption_flags_len = nonoption_flags_max_len = 0; + else + { + memset (__mempcpy (new_str, __getopt_nonoption_flags, + nonoption_flags_max_len), + '\0', top + 1 - nonoption_flags_max_len); + nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } + } +#endif + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS (bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +#if defined __STDC__ && __STDC__ +static const char *_getopt_initialize (int, char *const *, const char *); +#endif +static const char * +_getopt_initialize (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + +#ifdef _LIBC + if (posixly_correct == NULL + && argc == original_argc && argv == original_argv) + { + if (nonoption_flags_max_len == 0) + { + if (__getopt_nonoption_flags == NULL + || __getopt_nonoption_flags[0] == '\0') + nonoption_flags_max_len = -1; + else + { + const char *orig_str = __getopt_nonoption_flags; + int len = nonoption_flags_max_len = strlen (orig_str); + if (nonoption_flags_max_len < argc) + nonoption_flags_max_len = argc; + __getopt_nonoption_flags = + (char *) malloc (nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + nonoption_flags_max_len = -1; + else + memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), + '\0', nonoption_flags_max_len - len); + } + } + nonoption_flags_len = nonoption_flags_max_len; + } + else + nonoption_flags_len = 0; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns -1. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + int print_errors = opterr; + if (optstring[0] == ':') + print_errors = 0; + + optarg = NULL; + + if (optind == 0 || !__getopt_initialized) + { + if (optind == 0) + optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize (argc, argv, optstring); + __getopt_initialized = 1; + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ +#ifdef _LIBC +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ + || (optind < nonoption_flags_len \ + && __getopt_nonoption_flags[optind] == '1')) +#else +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') +#endif + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc && NONOPTION_P) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + return -1; + + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) + == (unsigned int) strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (print_errors) + fprintf (stderr, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (print_errors) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + _("%s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + _("%s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], pfound->name); + } + + nextchar += strlen (nextchar); + + optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (print_errors) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (print_errors) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (print_errors) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: illegal option -- %c\n"), + argv[0], c); + else + fprintf (stderr, _("%s: invalid option -- %c\n"), + argv[0], c); + } + optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (print_errors) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (print_errors) + fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (print_errors) + fprintf (stderr, _("\ +%s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); + + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (print_errors) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (print_errors) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt____ (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == -1) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ + diff --git a/win32/getopt.h b/win32/getopt.h new file mode 100644 index 0000000..91eb54e --- /dev/null +++ b/win32/getopt.h @@ -0,0 +1,169 @@ +/* Declarations for getopt. + Copyright (C) 1989,90,91,92,93,94,96,97,98 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _GETOPT_H + +#ifndef __need_getopt +# define _GETOPT_H 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +#ifndef __need_getopt +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +# if defined __STDC__ && __STDC__ + const char *name; +# else + char *name; +# endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +# define no_argument 0 +# define required_argument 1 +# define optional_argument 2 +#endif /* need getopt */ + + +/* Get definitions and prototypes for functions to process the + arguments in ARGV (ARGC of them, minus the program name) for + options given in OPTS. + + Return the option character from OPTS just read. Return -1 when + there are no more options. For unrecognized options, or options + missing arguments, `optopt' is set to the option letter, and '?' is + returned. + + The OPTS string is a list of characters which are recognized option + letters, optionally followed by colons, specifying that that letter + takes an argument, to be placed in `optarg'. + + If a letter in OPTS is followed by two colons, its argument is + optional. This behavior is specific to the GNU `getopt'. + + The argument `--' causes premature termination of argument + scanning, explicitly telling `getopt' that there are no more + options. + + If OPTS begins with `--', then non-option arguments are treated as + arguments to the option '\0'. This behavior is specific to the GNU + `getopt'. */ + +#if defined __STDC__ && __STDC__ +# ifdef __GNU_LIBRARY__ +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int __argc, char *const *__argv, const char *__shortopts); +# else /* not __GNU_LIBRARY__ */ +extern int getopt (); +# endif /* __GNU_LIBRARY__ */ + +# ifndef __need_getopt +extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts, + const struct option *__longopts, int *__longind); +extern int getopt_long_only (int __argc, char *const *__argv, + const char *__shortopts, + const struct option *__longopts, int *__longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int __argc, char *const *__argv, + const char *__shortopts, + const struct option *__longopts, int *__longind, + int __long_only); +# endif +#else /* not __STDC__ */ +extern int getopt (); +# ifndef __need_getopt +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +# endif +#endif /* __STDC__ */ + +#ifdef __cplusplus +} +#endif + +/* Make sure we later can get all the definitions and declarations. */ +#undef __need_getopt + +#endif /* getopt.h */ diff --git a/win32/getopt1.c b/win32/getopt1.c new file mode 100644 index 0000000..f7ca91c --- /dev/null +++ b/win32/getopt1.c @@ -0,0 +1,188 @@ +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "getopt.h" + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +#include +#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +#include + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == -1) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/win32/n2n_win32.h b/win32/n2n_win32.h new file mode 100644 index 0000000..713933a --- /dev/null +++ b/win32/n2n_win32.h @@ -0,0 +1,109 @@ +/* + + (C) 2007-09 - Luca Deri + +*/ + +#ifndef _N2N_WIN32_H_ +#define _N2N_WIN32_H_ + +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#if defined(__MINGW32__) +/* should be defined here and before winsock gets included */ +#define _WIN32_WINNT 0x501 //Otherwise the linker doesnt find getaddrinfo +#include +#endif /* #if defined(__MINGW32__) */ + +#include +#include +#include + + +#include "wintap.h" + +#ifdef _MSC_VER +#include "getopt.h" + +/* Other Win environments are expected to support stdint.h */ + +/* stdint.h typedefs (C99) (not present in Visual Studio) */ +typedef unsigned int uint32_t; +typedef unsigned short uint16_t; +typedef unsigned char uint8_t; + +/* sys/types.h typedefs (not present in Visual Studio) */ +typedef unsigned int u_int32_t; +typedef unsigned short u_int16_t; +typedef unsigned char u_int8_t; + +typedef int ssize_t; +#endif /* #ifdef _MSC_VER */ + +typedef unsigned long in_addr_t; + + +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#define MAX(a,b) (a > b ? a : b) +#define MIN(a,b) (a < b ? a : b) + +#define snprintf _snprintf +#define strdup _strdup + +#define socklen_t int + +#define ETH_ADDR_LEN 6 +/* + * Structure of a 10Mb/s Ethernet header. + */ +struct ether_hdr +{ + uint8_t dhost[ETH_ADDR_LEN]; + uint8_t shost[ETH_ADDR_LEN]; + uint16_t type; /* higher layer protocol encapsulated */ +}; + +typedef struct ether_hdr ether_hdr_t; + +/* ************************************* */ + +struct ip { +#if BYTE_ORDER == LITTLE_ENDIAN + u_char ip_hl:4, /* header length */ + ip_v:4; /* version */ +#else + u_char ip_v:4, /* version */ + ip_hl:4; /* header length */ +#endif + u_char ip_tos; /* type of service */ + short ip_len; /* total length */ + u_short ip_id; /* identification */ + short ip_off; /* fragment offset field */ +#define IP_DF 0x4000 /* dont fragment flag */ +#define IP_MF 0x2000 /* more fragments flag */ +#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ + u_char ip_ttl; /* time to live */ + u_char ip_p; /* protocol */ + u_short ip_sum; /* checksum */ + struct in_addr ip_src,ip_dst; /* source and dest address */ +}; + + +/* ************************************* */ + +typedef struct tuntap_dev { + HANDLE device_handle; + char *device_name; + char *ifName; + OVERLAPPED overlap_read, overlap_write; + uint8_t mac_addr[6]; + uint32_t ip_addr, device_mask; + unsigned int mtu; +} tuntap_dev; + +#define index(a, b) strchr(a, b) + + +#endif diff --git a/win32/version-msvc.c b/win32/version-msvc.c new file mode 100644 index 0000000..92cce06 --- /dev/null +++ b/win32/version-msvc.c @@ -0,0 +1,3 @@ +const char * n2n_sw_version = "2.0.0"; +const char * n2n_sw_osName = "Win32"; +const char * n2n_sw_buildDate = __DATE__ " " __TIME__; diff --git a/win32/wintap.c b/win32/wintap.c new file mode 100644 index 0000000..e2e96bb --- /dev/null +++ b/win32/wintap.c @@ -0,0 +1,310 @@ +/* + (C) 2007-09 - Luca Deri +*/ + +#include "../n2n.h" +#include "n2n_win32.h" + +/* 1500 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */ +#define MTU 1518 + +void initWin32() { + WSADATA wsaData; + int err; + + err = WSAStartup(MAKEWORD(2, 2), &wsaData ); + if( err != 0 ) { + /* Tell the user that we could not find a usable */ + /* WinSock DLL. */ + printf("FATAL ERROR: unable to initialise Winsock 2.x."); + exit(-1); + } +} + +int open_wintap(struct tuntap_dev *device, + const char * address_mode, /* "static" or "dhcp" */ + char *device_ip, + char *device_mask, + const char *device_mac, + int mtu) { + HKEY key, key2; + LONG rc; + char regpath[1024], cmd[256]; + char adapterid[1024]; + char adaptername[1024]; + char tapname[1024]; + long len; + int found = 0; + int err, i; + ULONG status = TRUE; + + memset(device, 0, sizeof(struct tuntap_dev)); + device->device_handle = INVALID_HANDLE_VALUE; + device->device_name = NULL; + device->ifName = NULL; + device->ip_addr = inet_addr(device_ip); + + /* Open registry and look for network adapters */ + if((rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key))) { + printf("Unable to read registry: [rc=%d]\n", rc); + exit(-1); + /* MSVC Note: If you keep getting rc=2 errors, make sure you set: + Project -> Properties -> Configuration Properties -> General -> Character set + to: "Use Multi-Byte Character Set" + */ + } + + for (i = 0; ; i++) { + len = sizeof(adapterid); + if(RegEnumKeyEx(key, i, (LPTSTR)adapterid, &len, 0, 0, 0, NULL)) + break; + + /* Find out more about this adapter */ + + _snprintf(regpath, sizeof(regpath), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, adapterid); + if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCSTR)regpath, 0, KEY_READ, &key2)) + continue; + + len = sizeof(adaptername); + err = RegQueryValueEx(key2, "Name", 0, 0, adaptername, &len); + + RegCloseKey(key2); + + if(err) + continue; + + if(device->device_name) { + if(!strcmp(device->device_name, adapterid)) { + found = 1; + break; + } else + continue; + } + + if(device->ifName) { + if(!strcmp(device->ifName, adaptername)) { + found = 1; + break; + } else + continue; + } + + _snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid); + device->device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, + 0, /* Don't let other processes share or open + the resource until the handle's been closed */ + 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0); + if(device->device_handle != INVALID_HANDLE_VALUE) { + found = 1; + break; + } + } + + RegCloseKey(key); + + if(!found) { + printf("No Windows tap device found!\n"); + exit(0); + } + + /* ************************************** */ + + if(!device->device_name) + device->device_name = _strdup(adapterid); + + if(!device->ifName) + device->ifName = _strdup(adaptername); + + /* Try to open the corresponding tap device->device_name */ + + if(device->device_handle == INVALID_HANDLE_VALUE) { + _snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, device->device_name); + device->device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, + OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0); + } + + if(device->device_handle == INVALID_HANDLE_VALUE) { + printf("%s (%s) is not a usable Windows tap device\n", device->device_name, device->ifName); + exit(-1); + } + + /* Get MAC address from tap device->device_name */ + + if(!DeviceIoControl(device->device_handle, TAP_IOCTL_GET_MAC, + device->mac_addr, sizeof(device->mac_addr), + device->mac_addr, sizeof(device->mac_addr), &len, 0)) { + printf("Could not get MAC address from Windows tap %s (%s)\n", + device->device_name, device->ifName); + return -1; + } + + device->mtu = mtu; + + printf("Open device [name=%s][ip=%s][ifName=%s][MTU=%d][mac=%02X:%02X:%02X:%02X:%02X:%02X]\n", + device->device_name, device_ip, device->ifName, device->mtu, + device->mac_addr[0] & 0xFF, + device->mac_addr[1] & 0xFF, + device->mac_addr[2] & 0xFF, + device->mac_addr[3] & 0xFF, + device->mac_addr[4] & 0xFF, + device->mac_addr[5] & 0xFF); + + /* ****************** */ + + printf("Setting %s device address...\n", device->ifName); + + if ( 0 == strcmp("dhcp", address_mode) ) + { + _snprintf(cmd, sizeof(cmd), + "netsh interface ip set address \"%s\" dhcp", + device->ifName); + } + else + { + _snprintf(cmd, sizeof(cmd), + "netsh interface ip set address \"%s\" static %s %s", + device->ifName, device_ip, device_mask); + } + + if(system(cmd) == 0) { + device->ip_addr = inet_addr(device_ip); + device->device_mask = inet_addr(device_mask); + printf("Device %s set to %s/%s\n", + device->ifName, device_ip, device_mask); + } else + printf("WARNING: Unable to set device %s IP address [%s]\n", + device->ifName, cmd); + + /* ****************** */ + + if(device->mtu != DEFAULT_MTU) + printf("WARNING: MTU set is not supported on Windows\n"); + + /* set driver media status to 'connected' (i.e. set the interface up) */ + if (!DeviceIoControl (device->device_handle, TAP_IOCTL_SET_MEDIA_STATUS, + &status, sizeof (status), + &status, sizeof (status), &len, NULL)) + printf("WARNING: Unable to enable TAP adapter\n"); + + /* + * Initialize overlapped structures + */ + device->overlap_read.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + device->overlap_write.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!device->overlap_read.hEvent || !device->overlap_write.hEvent) { + return -1; + } + + return(0); +} + +/* ************************************************ */ + +int tuntap_read(struct tuntap_dev *tuntap, unsigned char *buf, int len) +{ + DWORD read_size, last_err; + + ResetEvent(tuntap->overlap_read.hEvent); + if (ReadFile(tuntap->device_handle, buf, len, &read_size, &tuntap->overlap_read)) { + //printf("tun_read(len=%d)\n", read_size); + return read_size; + } + switch (last_err = GetLastError()) { + case ERROR_IO_PENDING: + WaitForSingleObject(tuntap->overlap_read.hEvent, INFINITE); + GetOverlappedResult(tuntap->device_handle, &tuntap->overlap_read, &read_size, FALSE); + return read_size; + break; + default: + printf("GetLastError() returned %d\n", last_err); + break; + } + + return -1; +} +/* ************************************************ */ + +int tuntap_write(struct tuntap_dev *tuntap, unsigned char *buf, int len) +{ + DWORD write_size; + + //printf("tun_write(len=%d)\n", len); + + ResetEvent(tuntap->overlap_write.hEvent); + if (WriteFile(tuntap->device_handle, + buf, + len, + &write_size, + &tuntap->overlap_write)) { + //printf("DONE tun_write(len=%d)\n", write_size); + return write_size; + } + switch (GetLastError()) { + case ERROR_IO_PENDING: + WaitForSingleObject(tuntap->overlap_write.hEvent, INFINITE); + GetOverlappedResult(tuntap->device_handle, &tuntap->overlap_write, + &write_size, FALSE); + return write_size; + break; + default: + break; + } + + return -1; +} + +/* ************************************************ */ + +int tuntap_open(struct tuntap_dev *device, + char *dev, + const char *address_mode, /* static or dhcp */ + char *device_ip, + char *device_mask, + const char * device_mac, + int mtu) { + return(open_wintap(device, address_mode, device_ip, device_mask, device_mac, mtu)); +} + +/* ************************************************ */ + +void tuntap_close(struct tuntap_dev *tuntap) { + CloseHandle(tuntap->device_handle); +} + +/* Fill out the ip_addr value from the interface. Called to pick up dynamic + * address changes. */ +void tuntap_get_address(struct tuntap_dev *tuntap) +{ +} + +/* ************************************************ */ + +#if 0 +int main(int argc, char* argv[]) { + struct tuntap_dev tuntap; + int i; + int mtu = 1400; + + printf("Welcome to n2n\n"); + initWin32(); + open_wintap(&tuntap, "static", "1.2.3.20", "255.255.255.0", mtu); + + for(i=0; i<10; i++) { + u_char buf[MTU]; + int rc; + + rc = tun_read(&tuntap, buf, sizeof(buf)); + buf[0]=2; + buf[1]=3; + buf[2]=4; + + printf("tun_read returned %d\n", rc); + rc = tun_write(&tuntap, buf, rc); + printf("tun_write returned %d\n", rc); + } + // rc = tun_open (device->device_name, IF_MODE_TUN); + WSACleanup (); + return(0); +} + +#endif diff --git a/win32/wintap.h b/win32/wintap.h new file mode 100644 index 0000000..0eef8f0 --- /dev/null +++ b/win32/wintap.h @@ -0,0 +1,67 @@ +/* + (C) 2007 - Luca Deri +*/ + +#ifndef _WINTAP_H_ +#define _WINTAP_H_ + +#undef UNICODE +#undef _UNICODE +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include + + + +//=============================================== +// This file is included both by OpenVPN and +// the TAP-Win32 driver and contains definitions +// common to both. +//=============================================== + +//============= +// TAP IOCTLs +//============= + +#define TAP_CONTROL_CODE(request,method) \ + CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS) + +#define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE (1, METHOD_BUFFERED) +#define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE (2, METHOD_BUFFERED) +#define TAP_IOCTL_GET_MTU TAP_CONTROL_CODE (3, METHOD_BUFFERED) +#define TAP_IOCTL_GET_INFO TAP_CONTROL_CODE (4, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED) +#define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE (6, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_DHCP_MASQ TAP_CONTROL_CODE (7, METHOD_BUFFERED) +#define TAP_IOCTL_GET_LOG_LINE TAP_CONTROL_CODE (8, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_DHCP_SET_OPT TAP_CONTROL_CODE (9, METHOD_BUFFERED) + +//================= +// Registry keys +//================= + +#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}" +#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}" + +//====================== +// Filesystem prefixes +//====================== + +#define USERMODEDEVICEDIR "\\\\.\\Global\\" +#define SYSDEVICEDIR "\\Device\\" +#define USERDEVICEDIR "\\DosDevices\\Global\\" +#define TAPSUFFIX ".tap" + +//========================================================= +// TAP_COMPONENT_ID -- This string defines the TAP driver +// type -- different component IDs can reside in the system +// simultaneously. +//========================================================= + +#define TAP_COMPONENT_ID "tap0801" + +extern void initWin32(); + +#endif \ No newline at end of file diff --git a/wire.c b/wire.c new file mode 100644 index 0000000..6490c9d --- /dev/null +++ b/wire.c @@ -0,0 +1,461 @@ +/* (c) 2009 Richard Andrews */ + +/** Routines for encoding and decoding n2n packets on the wire. + * + * encode_X(base,idx,v) prototypes are inspired by the erlang internal + * encoding model. Passing the start of a buffer in base and a pointer to an + * integer (initially set to zero). Each encode routine increases idx by the + * amount written and returns the amount written. In this way complex sequences + * of encodings can be represented cleanly. See encode_register() for an + * example. + */ + +#include "n2n_wire.h" +#include + +int encode_uint8( uint8_t * base, + size_t * idx, + const uint8_t v ) +{ + *(base + (*idx)) = (v & 0xff); + ++(*idx); + return 1; +} + +int decode_uint8( uint8_t * out, + const uint8_t * base, + size_t * rem, + size_t * idx ) +{ + if (*rem < 1 ) { return 0; } + + *out = ( base[*idx] & 0xff ); + ++(*idx); + --(*rem); + return 1; +} + +int encode_uint16( uint8_t * base, + size_t * idx, + const uint16_t v ) +{ + *(base + (*idx)) = ( v >> 8) & 0xff; + *(base + (1 + *idx)) = ( v & 0xff ); + *idx += 2; + return 2; +} + +int decode_uint16( uint16_t * out, + const uint8_t * base, + size_t * rem, + size_t * idx ) +{ + if (*rem < 2 ) { return 0; } + + *out = ( base[*idx] & 0xff ) << 8; + *out |= ( base[1 + *idx] & 0xff ); + *idx += 2; + *rem -= 2; + return 2; +} + +int encode_uint32( uint8_t * base, + size_t * idx, + const uint32_t v ) +{ + *(base + (0 + *idx)) = ( v >> 24) & 0xff; + *(base + (1 + *idx)) = ( v >> 16) & 0xff; + *(base + (2 + *idx)) = ( v >> 8) & 0xff; + *(base + (3 + *idx)) = ( v & 0xff ); + *idx += 4; + return 4; +} + +int decode_uint32( uint32_t * out, + const uint8_t * base, + size_t * rem, + size_t * idx ) +{ + if (*rem < 4 ) { return 0; } + + *out = ( base[0 + *idx] & 0xff ) << 24; + *out |= ( base[1 + *idx] & 0xff ) << 16; + *out |= ( base[2 + *idx] & 0xff ) << 8; + *out |= ( base[3 + *idx] & 0xff ); + *idx += 4; + *rem -= 4; + return 4; +} + +int encode_buf( uint8_t * base, + size_t * idx, + const void * p, + size_t s) +{ + memcpy( (base + (*idx)), p, s ); + *idx += s; + return s; +} + +/* Copy from base to out of size bufsize */ +int decode_buf( uint8_t * out, + size_t bufsize, + const uint8_t * base, + size_t * rem, + size_t * idx ) +{ + if (*rem < bufsize ) { return 0; } + + memcpy( out, (base + *idx), bufsize ); + *idx += bufsize; + *rem -= bufsize; + return bufsize; +} + + + +int encode_mac( uint8_t * base, + size_t * idx, + const n2n_mac_t m ) +{ + return encode_buf( base, idx, m, N2N_MAC_SIZE ); +} + +int decode_mac( uint8_t * out, /* of size N2N_MAC_SIZE. This clearer than passing a n2n_mac_t */ + const uint8_t * base, + size_t * rem, + size_t * idx ) +{ + return decode_buf( out, N2N_MAC_SIZE, base, rem, idx ); +} + + + +int encode_common( uint8_t * base, + size_t * idx, + const n2n_common_t * common ) +{ + uint16_t flags=0; + encode_uint8( base, idx, N2N_PKT_VERSION ); + encode_uint8( base, idx, common->ttl ); + + flags = common->pc & N2N_FLAGS_TYPE_MASK; + flags |= common->flags & N2N_FLAGS_BITS_MASK; + + encode_uint16( base, idx, flags ); + encode_buf( base, idx, common->community, N2N_COMMUNITY_SIZE ); + + return -1; +} + +int decode_common( n2n_common_t * out, + const uint8_t * base, + size_t * rem, + size_t * idx ) +{ + size_t idx0=*idx; + uint8_t dummy=0; + decode_uint8( &dummy, base, rem, idx ); + + if ( N2N_PKT_VERSION != dummy ) + { + return -1; + } + + decode_uint8( &(out->ttl), base, rem, idx ); + decode_uint16( &(out->flags), base, rem, idx ); + out->pc = ( out->flags & N2N_FLAGS_TYPE_MASK ); + out->flags &= N2N_FLAGS_BITS_MASK; + + decode_buf( out->community, N2N_COMMUNITY_SIZE, base, rem, idx ); + + return (*idx - idx0); +} + + +int encode_sock( uint8_t * base, + size_t * idx, + const n2n_sock_t * sock ) +{ + int retval=0; + uint16_t f; + + switch (sock->family) + { + case AF_INET: + { + f = 0; + retval += encode_uint16(base,idx,f); + retval += encode_uint16(base,idx,sock->port); + retval += encode_buf(base,idx,sock->addr.v4,IPV4_SIZE); + break; + } + case AF_INET6: + { + f = 0x8000; + retval += encode_uint16(base,idx,f); + retval += encode_uint16(base,idx,sock->port); + retval += encode_buf(base,idx,sock->addr.v6,IPV6_SIZE); + break; + } + default: + retval=-1; + } + + return retval; +} + + +int decode_sock( n2n_sock_t * sock, + const uint8_t * base, + size_t * rem, + size_t * idx ) +{ + size_t * idx0=idx; + uint16_t f; + + decode_uint16( &f, base, rem, idx ); + + if( f & 0x8000 ) + { + /* IPv6 */ + sock->family = AF_INET6; + decode_uint16( &(sock->port), base, rem, idx ); + decode_buf( sock->addr.v6, IPV6_SIZE, base, rem, idx ); + } + else + { + /* IPv4 */ + sock->family = AF_INET; + decode_uint16( &(sock->port), base, rem, idx ); + memset( sock->addr.v6, 0, IPV6_SIZE ); /* so memcmp() works for equality. */ + decode_buf( sock->addr.v4, IPV4_SIZE, base, rem, idx ); + } + + return (idx-idx0); +} + +int encode_REGISTER( uint8_t * base, + size_t * idx, + const n2n_common_t * common, + const n2n_REGISTER_t * reg ) +{ + int retval=0; + retval += encode_common( base, idx, common ); + retval += encode_buf( base, idx, reg->cookie, N2N_COOKIE_SIZE ); + retval += encode_mac( base, idx, reg->srcMac ); + retval += encode_mac( base, idx, reg->dstMac ); + if ( 0 != reg->sock.family ) + { + retval += encode_sock( base, idx, &(reg->sock) ); + } + + return retval; +} + +int decode_REGISTER( n2n_REGISTER_t * reg, + const n2n_common_t * cmn, /* info on how to interpret it */ + const uint8_t * base, + size_t * rem, + size_t * idx ) +{ + size_t retval=0; + memset( reg, 0, sizeof(n2n_REGISTER_t) ); + retval += decode_buf( reg->cookie, N2N_COOKIE_SIZE, base, rem, idx ); + retval += decode_mac( reg->srcMac, base, rem, idx ); + retval += decode_mac( reg->dstMac, base, rem, idx ); + + if ( cmn->flags & N2N_FLAGS_SOCKET ) + { + retval += decode_sock( &(reg->sock), base, rem, idx ); + } + + return retval; +} + +int encode_REGISTER_SUPER( uint8_t * base, + size_t * idx, + const n2n_common_t * common, + const n2n_REGISTER_SUPER_t * reg ) +{ + int retval=0; + retval += encode_common( base, idx, common ); + retval += encode_buf( base, idx, reg->cookie, N2N_COOKIE_SIZE ); + retval += encode_mac( base, idx, reg->edgeMac ); + retval += encode_uint16( base, idx, 0 ); /* NULL auth scheme */ + retval += encode_uint16( base, idx, 0 ); /* No auth data */ + + return retval; +} + +int decode_REGISTER_SUPER( n2n_REGISTER_SUPER_t * reg, + const n2n_common_t * cmn, /* info on how to interpret it */ + const uint8_t * base, + size_t * rem, + size_t * idx ) +{ + size_t retval=0; + memset( reg, 0, sizeof(n2n_REGISTER_SUPER_t) ); + retval += decode_buf( reg->cookie, N2N_COOKIE_SIZE, base, rem, idx ); + retval += decode_mac( reg->edgeMac, base, rem, idx ); + retval += decode_uint16( &(reg->auth.scheme), base, rem, idx ); + retval += decode_uint16( &(reg->auth.toksize), base, rem, idx ); + retval += decode_buf( reg->auth.token, reg->auth.toksize, base, rem, idx ); + return retval; +} + +int encode_REGISTER_ACK( uint8_t * base, + size_t * idx, + const n2n_common_t * common, + const n2n_REGISTER_ACK_t * reg ) +{ + int retval=0; + retval += encode_common( base, idx, common ); + retval += encode_buf( base, idx, reg->cookie, N2N_COOKIE_SIZE ); + retval += encode_mac( base, idx, reg->dstMac ); + retval += encode_mac( base, idx, reg->srcMac ); + + /* The socket in REGISTER_ACK is the socket from which the REGISTER + * arrived. This is sent back to the sender so it knows what its public + * socket is. */ + if ( 0 != reg->sock.family ) + { + retval += encode_sock( base, idx, &(reg->sock) ); + } + + return retval; +} + +int decode_REGISTER_ACK( n2n_REGISTER_ACK_t * reg, + const n2n_common_t * cmn, /* info on how to interpret it */ + const uint8_t * base, + size_t * rem, + size_t * idx ) +{ + size_t retval=0; + memset( reg, 0, sizeof(n2n_REGISTER_ACK_t) ); + retval += decode_buf( reg->cookie, N2N_COOKIE_SIZE, base, rem, idx ); + retval += decode_mac( reg->dstMac, base, rem, idx ); + retval += decode_mac( reg->srcMac, base, rem, idx ); + + /* The socket in REGISTER_ACK is the socket from which the REGISTER + * arrived. This is sent back to the sender so it knows what its public + * socket is. */ + if ( cmn->flags & N2N_FLAGS_SOCKET ) + { + retval += decode_sock( &(reg->sock), base, rem, idx ); + } + + return retval; +} + +int encode_REGISTER_SUPER_ACK( uint8_t * base, + size_t * idx, + const n2n_common_t * common, + const n2n_REGISTER_SUPER_ACK_t * reg ) +{ + int retval=0; + retval += encode_common( base, idx, common ); + retval += encode_buf( base, idx, reg->cookie, N2N_COOKIE_SIZE ); + retval += encode_mac( base, idx, reg->edgeMac ); + retval += encode_uint16( base, idx, reg->lifetime ); + retval += encode_sock( base, idx, &(reg->sock) ); + retval += encode_uint8( base, idx, reg->num_sn ); + if ( reg->num_sn > 0 ) + { + /* We only support 0 or 1 at this stage */ + retval += encode_sock( base, idx, &(reg->sn_bak) ); + } + + return retval; +} + +int decode_REGISTER_SUPER_ACK( n2n_REGISTER_SUPER_ACK_t * reg, + const n2n_common_t * cmn, /* info on how to interpret it */ + const uint8_t * base, + size_t * rem, + size_t * idx ) +{ + size_t retval=0; + + memset( reg, 0, sizeof(n2n_REGISTER_SUPER_ACK_t) ); + retval += decode_buf( reg->cookie, N2N_COOKIE_SIZE, base, rem, idx ); + retval += decode_mac( reg->edgeMac, base, rem, idx ); + retval += decode_uint16( &(reg->lifetime), base, rem, idx ); + + /* Socket is mandatory in this message type */ + retval += decode_sock( &(reg->sock), base, rem, idx ); + + /* Following the edge socket are an array of backup supernodes. */ + retval += decode_uint8( &(reg->num_sn), base, rem, idx ); + if ( reg->num_sn > 0 ) + { + /* We only support 0 or 1 at this stage */ + retval += decode_sock( &(reg->sn_bak), base, rem, idx ); + } + + return retval; +} + +int fill_sockaddr( struct sockaddr * addr, + size_t addrlen, + const n2n_sock_t * sock ) +{ + int retval=-1; + + if ( AF_INET == sock->family ) + { + if ( addrlen >= sizeof(struct sockaddr_in) ) + { + struct sockaddr_in * si = (struct sockaddr_in *)addr; + si->sin_family = sock->family; + si->sin_port = htons( sock->port ); + memcpy( &(si->sin_addr.s_addr), sock->addr.v4, IPV4_SIZE ); + retval=0; + } + } + + return retval; +} + + +int encode_PACKET( uint8_t * base, + size_t * idx, + const n2n_common_t * common, + const n2n_PACKET_t * pkt ) +{ + int retval=0; + retval += encode_common( base, idx, common ); + retval += encode_mac( base, idx, pkt->srcMac ); + retval += encode_mac( base, idx, pkt->dstMac ); + if ( 0 != pkt->sock.family ) + { + retval += encode_sock( base, idx, &(pkt->sock) ); + } + retval += encode_uint16( base, idx, pkt->transform ); + + return retval; +} + + +int decode_PACKET( n2n_PACKET_t * pkt, + const n2n_common_t * cmn, /* info on how to interpret it */ + const uint8_t * base, + size_t * rem, + size_t * idx ) +{ + size_t retval=0; + memset( pkt, 0, sizeof(n2n_PACKET_t) ); + retval += decode_mac( pkt->srcMac, base, rem, idx ); + retval += decode_mac( pkt->dstMac, base, rem, idx ); + + if ( cmn->flags & N2N_FLAGS_SOCKET ) + { + retval += decode_sock( &(pkt->sock), base, rem, idx ); + } + + retval += decode_uint16( &(pkt->transform), base, rem, idx ); + + return retval; +} +