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 0000000..aae212b Binary files /dev/null and b/win32/DotNet/n2n.suo differ 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; +} +