pax_global_header00006660000000000000000000000064137413642120014515gustar00rootroot0000000000000052 comment=d482de1719ba198d020e756a9c81fb436f601267 vdeplug4-4.0.1/000077500000000000000000000000001374136421200132515ustar00rootroot00000000000000vdeplug4-4.0.1/CMakeLists.txt000066400000000000000000000016161374136421200160150ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.13) project(vdeplug4 VERSION 4.0.0 DESCRIPTION "Virtual Distributed Ethernet. Plug your VM directly to the cloud." HOMEPAGE_URL "https://github.com/rd235/vdeplug4" LANGUAGES C) include(GNUInstallDirs) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic") include_directories( ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/srcvdeplug4 ) include(CheckIncludeFile) set(LIBS_REQUIRED execs) foreach(THISLIB IN LISTS LIBS_REQUIRED) find_library(LIB${THISLIB}_OK ${THISLIB}) if(NOT LIB${THISLIB}_OK) message(FATAL_ERROR "library lib${THISLIB} not found") endif() endforeach(THISLIB) add_subdirectory(libvdeplug4) add_subdirectory(srcvdeplug4) add_subdirectory(libvdeplug4_static) add_subdirectory(include) add_subdirectory(doc) add_subdirectory(man) add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${PROJECT_SOURCE_DIR}/Uninstall.cmake") vdeplug4-4.0.1/COPYING000066400000000000000000000431231374136421200143070ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. vdeplug4-4.0.1/COPYING.libvdeplug4000066400000000000000000000635041374136421200165340ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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 Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! vdeplug4-4.0.1/README.md000066400000000000000000000051331374136421200145320ustar00rootroot00000000000000# vdeplug4 VDE: Virtual Distributed Ethernet. Plug your VM directly to the cloud. Vdeplug4 is a new perspective on virtual networking. ## hello vxvde world Install vdeplug4: ``` $ mkdir build $ cd build $ cmake .. $ make $ sudo make install ``` Start several VM *on different hosts on the same LAN* (IP ttl must be 1). (VM virtual controllers must have different MAC addresses). e.g. kvm: ``` kvm .... -net nic,macaddr=52:54:00:11:22:11 -net vde,sock=vxvde:// kvm .... -net nic,macaddr=52:54:00:11:22:22 -net vde,sock=vxvde:// kvm .... -net nic,macaddr=52:54:00:11:22:33 -net vde,sock=vxvde:// kvm .... -net nic,macaddr=52:54:00:11:22:44 -net vde,sock=vxvde:// kvm .... -net nic,macaddr=52:54:00:11:22:55 -net vde,sock=vxvde:// ``` All the VM will be automagically on the same Virtual LAN. (similarly, it is possible to add virtualbox, qemu-system-\* and user-mode-linux VMs). It is possible to connect the virtual newtork to a tuntap interface and manage in this way the routing towards real networks (maybe the Internet). The command (to run on any host on the LAN) is: ``` $ sudo vde_plug vxvde:// tap://mytap ``` The tap can be defined on a remote host: ``` $ vde_plug vxvde:// = ssh fqdn.of.remote.host,org vde_plug tap:// ``` ## what is vdeplug4 This software package includes a modular library (libvdeplug) and some utility tools (vde\_plug and dpipe) The new libvdeplug library is backwards compatible with the previous versions (so it is already supported by qemu, kvm, virtualbox, user-mode-linux, view-os, lwipv6, picotcp and all the other VM or virtual stacks supporting vde2). The new library supports plug-ins so it is open to new developments in vrtual networking. Several plug-ins are provided as standard extensions of the library (batteries included): - vde: connect to legacy vde\_switch (provided by vde2) - ptp: peer to peer connection between two VM - tap: connect a VM or a virtual network to - vxlan: connect vde switches or other vde networks to vxlan - vxvde: this plug-in implements distributed virtual switches - udp: udp tunnelling The address of a virtual network is defined by a syntax similar to web URLs. examples: ``` vxvde://239.1.2.3/ttl=2 tap://mytap vde:///tmp/myswitch myplugin://my.syntax/myarg=myvalue ``` This latter example will work provided there is a dynamic library named libvdeplug\_myplugin.so available and accepting the syntax of the parameters after '//' Other modules can be added. Vdeplug4 includes the header file and a support library to implement further plugins. ## Credits: Mattia Biondi largely contibuted to the conversion from autotools to cmake. (2019) vdeplug4-4.0.1/Uninstall.cmake000066400000000000000000000010361374136421200162240ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.13) set(MANIFEST "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt") if(NOT EXISTS ${MANIFEST}) message(FATAL_ERROR "Cannot find install manifest: '${MANIFEST}'") endif() file(STRINGS ${MANIFEST} files) foreach(file ${files}) if(EXISTS ${file} OR IS_SYMLINK ${file}) message(STATUS "Removing: ${file}") execute_process( COMMAND rm -f ${file} RESULT_VARIABLE retcode ) if(NOT "${retcode}" STREQUAL "0") message(WARNING "Failed to remove: ${file}") endif() endif() endforeach(file) vdeplug4-4.0.1/doc/000077500000000000000000000000001374136421200140165ustar00rootroot00000000000000vdeplug4-4.0.1/doc/CMakeLists.txt000066400000000000000000000001671374136421200165620ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.13) install(FILES howto_create_a_vdeplug_plugin DESTINATION ${CMAKE_INSTALL_DOCDIR}) vdeplug4-4.0.1/doc/howto_create_a_vdeplug_plugin000066400000000000000000000162771374136421200220450ustar00rootroot00000000000000HOW TO CREATE A VDEPLUG PLUGIN May 21, 2017 Renzo Davoli This brief document is for developers who aim to add new VDE implementations. Vdeplug4 provides a library to implement new plugins: libvdeplug_mod.so: add: #include in your source files and link your objects with: -l vdeplug_mod This library includes three main features: * The structure needed by libvdeplug to run the specific implementation functions * Functions to parse the options in vde_urls. * A generic hash table for Ethernet packet dispatching plus some utility functions. +++ struct vdeplug_module +++ A plugin for vdeplug need: * to have a prefix "libvdeplug_" in its name. "libvdeplug_foo.so" will be loaded when a program uses a vde_url beginning by "foo://". Foo will be the name used in the following examples. * to export a non-static global variable named vdeplug_ops of type struct vdeplug_module. struct vdeplug_module vdeplug_ops={ .vde_open_real=vde_foo_open, .vde_recv=vde_foo_recv, .vde_send=vde_foo_send, .vde_datafd=vde_foo_datafd, .vde_ctlfd=vde_foo_ctlfd, .vde_close=vde_foo_close}; vde_foo_open returns a pointer to a struct vdeconn. Actually each module can cast struct vdeconn to an implementation specific structure provided the first two fields are preserved (i.e. all specific data will be stored in the unsized field named "data" of struct vdeconn). Please note that vde_foo_open receives a copy of the vde_url provided by the calling program. THe copy is allocated on the stack, so the value can be safely modified to parse the url but if the string (or part of of it) should be stored for a later retrieval the contents needs to be duplicated. (do not store pointers addressing bytes of vde_url). vde_foo_recv, vde_foo_send, vde_foo_datafd, vde_foo_ctlfd, vde_foo_close are the implementation specific function corresponding to those described in libvdeplug(3) man page. +++ vde_url arguments parsing +++ libvdeplug_mod library provides two functions: int vde_parseparms(char *str,struct vdeparms *parms); int vde_parsepathparms(char *str,struct vdeparms *parms); The former has been designed for plug-ins which need IP addresses or fully qualified domain names as parameters. The latter is specific for plug-ins using pathnames. Using vde_parseparms it is possible to parse vde_urls like; vxvde:// vxvde://239.0.0.1 vxvde://239.0.0.1/iface=eth0 vxvde://2001:760::1/iface=eth0 vxvde://239.0.0.1/ipv4/iface=eth0 vxvde://vde.mycompany.com/ipv4/iface=eth0 arguments are separated by slashes and may or may not have values. Using vde_parsepathparms it is possible to parse vde_urls like; vde:// vde:///tmp/vde.ctl vde:///tmp/vde.ctl[2] vde://[3] vde:///var/run/grpsw[group=grp/port=2] arguments are provided within square brackets and separated by slashes. Both vde_parseparms and vde_parsepathparms require two arguments, the first is the string to be parsed, the second is an array of struct vdeparms. A struct vdeparms element is a pair tag, pointer to the value. When the tag matches, the value is stored using the pointer. The array must terminate with an empty element {NULL, NULL}. The return value for both functions is 0 in case of success, -1 in case of error. The examples here above of possible values parseable by vde_parseparms can be processed using the following code. char *ipv4str = NULL; char *ifacestr = "lo"; struct vdeparms parms[] = { {"ipv4",&ipv4str}, {"iface",&ifacestr}, {NULL, NULL}}; ... if (vde_parseparms(vde_url,parms) < 0) .... error management after vde_parseparms completion vde_url contains the IP address or fully qualified domain name without the options, ipv4str points to a NULL string (but it is not null) if "ipv4" is one of the url arguments, and if the argument "iface=eth0" is present ifacestr points to "eth0" (the seventh char of the argument itself). It is possible to assign default values. In the example above ifacestr is "lo" if no "iface=something" argument is present. Please note that each argument-key can occur just once (otherwise the second value overwrites the first) The examples of vde_parsepathparms values can be processed using the following code: char *portstr = "0"; char *groupstr = NULL; struct vdeparms parms[] = { {"",&port}, {"port",&portstr}, {"group",&groupstr}, {NULL, NULL}}; ... if (vde_parsepathparms(vde_url,parms) < 0) .... error management after vde_parsepathparms completion vde_url contains the path only (without square brackets and arguments). Like vde_parseparms, portstr and groupstr point to the value after "port=" or "group=" arguments, respectively. If the first struct vdeparms has an empty string as its key (only for vde_parsepathparms) it gets the arguments not matching any other key. It means in this case that: vde:///tmp/vde.ctl[2] vde:///tmp/vde.ctl[port=2] have the same meaning. Examples of arguments managements can be found in libvdeplug_*.so in the libvdeplug4 of the source tree of vdeplug4. +++ A generic hash table for Ethernet packet dispatching +++ Given that VDE handles ethernet packets many plugins need a hash table to dispatch ethernet packets. The key of the dispatching table is the pair (MAC address, VLAN number), the corrisponding value (the payload) changes depending upon the implementation of VDE (a local switch may use an integer like a file descriptor or a port number while distributed implementations like vxvde use socket address, like sockaddr_in or sockaddr_in6). The macro to create a hash table is: struct vde_hashtable *vde_hash_init(type, unsigned int hashsize, unsigned int seed) where type is the type of the payload, hashsize is the number of element of the hash table and seed is an optional value to perturbate the hash function computation in case too many collisions occur. vde_hash_init returns a descriptor of the hash table which will be used as the first argument of all the other functions. void vde_hash_fini(struct vde_hashtable *table); deallocate the hash table. void vde_find_in_hash_update(struct vde_hashtable *table, unsigned char *src, int vlan, void *payload, time_t now); This function should be used when a packet is reeceived to update (or renew) the hash entry for this source of ethernet packets. The payload (shich should be a pointer to the type specified in vde_hash_fini) is copied in the hash table and the value now is the (new) timestamp of this match. void *vde_find_in_hash(struct vde_hashtable *table, unsigned char *dst, int vlan, time_t too_old); this function searches in the hash table the destination address. If the entry exists but it has a timestamp older than the value of the parameter too_old, it is ignored. So the return value is NULL if the key does not exist or its match validity has expired otherwise it is a pointer to the payload corresponding to the key. void vde_hash_delete(struct vde_hashtable *table, void *payload); this function deletes an element from the hash table. +++ utility functions +++ unsigned long long strtoullm(const char *numstr); converts a string in a unsigned long long value (like strtoull). This functions allows multipliers like K, M, G, T meaning kilo, mega, giga, tera. e.g. "1K" is converted to 1024. gid_t vde_grnam2gid(const char *name); gets the gid of a group given its name. It returns -1 if such a group does not exist. vdeplug4-4.0.1/include/000077500000000000000000000000001374136421200146745ustar00rootroot00000000000000vdeplug4-4.0.1/include/CMakeLists.txt000066400000000000000000000005341374136421200174360ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.13) set_target_properties(vdeplug PROPERTIES PUBLIC_HEADER libvdeplug.h) set_target_properties(vdeplug_mod PROPERTIES PUBLIC_HEADER libvdeplug_mod.h) install( TARGETS vdeplug vdeplug_mod LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) vdeplug4-4.0.1/include/libvdeplug.h000066400000000000000000000054431374136421200172100ustar00rootroot00000000000000/* * libvdeplug - A library to connect to a VDE Switch. * Copyright (C) 2006 Renzo Davoli, University of Bologna * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation version 2.1 of the License, or (at * your option) any later version. * * This 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 Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef _VDELIB_H #define _VDELIB_H #include #define LIBVDEPLUG_INTERFACE_VERSION 1 #define VDE_MAXMTU 9216 #define VDE_ETHBUFSIZE (VDE_MAXMTU + 14 + 4) // + Ethernet header + 802.1Q header struct vdeconn; typedef struct vdeconn VDECONN; /* Open a VDE connection. * vde_open_options: * port: connect to a specific port of the switch (0=any) * group: change the ownership of the communication port to a specific group * (NULL=no change) * mode: set communication port mode (if 0 standard socket mode applies) */ struct vde_open_args { int port; char *group; mode_t mode; }; /* vde_open args: * vde_url: switch id (module://parameters or path) * e.g. vde:// vde:///var/run/vde.ctl vxvde:// tap://tap0 * descr: description (it will appear in the port description on the switch) */ #define vde_open(vde_url,descr,open_args) \ vde_open_real((vde_url),(descr),LIBVDEPLUG_INTERFACE_VERSION,(open_args)) VDECONN *vde_open_real(char *vde_url,char *descr,int interface_version, struct vde_open_args *open_args); ssize_t vde_recv(VDECONN *conn,void *buf,size_t len,int flags); ssize_t vde_send(VDECONN *conn,const void *buf,size_t len,int flags); /* for select/poll when this fd receive data, there are packets to recv * (call vde_recv) */ int vde_datafd(VDECONN *conn); /* for select/poll. the ctl socket is silent after the initial handshake. * when EOF the switch has closed the connection */ int vde_ctlfd(VDECONN *conn); int vde_close(VDECONN *conn); /* vdestream */ struct vdestream; typedef struct vdestream VDESTREAM; #define PACKET_LENGTH_ERROR 1 VDESTREAM *vdestream_open(void *opaque, int fdout, ssize_t (*frecv)(void *opaque, void *buf, size_t count), void (*ferr)(void *opaque, int type, char *format, ...) ); ssize_t vdestream_send(VDESTREAM *vdestream, const void *buf, size_t len); void vdestream_recv(VDESTREAM *vdestream, unsigned char *buf, size_t len); void vdestream_close(VDESTREAM *vdestream); #endif vdeplug4-4.0.1/include/libvdeplug_mod.h000066400000000000000000000027561374136421200200530ustar00rootroot00000000000000#ifndef VDE_PLUG_H #define VDE_PLUG_H #define MAXDESCR 128 #define CONNECTED_P2P #include #include #include struct vdeplug_module; struct vdeconn { void *handle; struct vdeplug_module *module; unsigned char data[]; }; struct vdeplug_module { int flags; VDECONN *(* vde_open_real)(char *given_vde_url, char *descr,int interface_version, struct vde_open_args *open_args); ssize_t (* vde_recv)(VDECONN *conn,void *buf,size_t len,int flags); ssize_t (* vde_send)(VDECONN *conn,const void *buf,size_t len,int flags); int (* vde_datafd)(VDECONN *conn); int (* vde_ctlfd)(VDECONN *conn); int (* vde_close)(VDECONN *conn); }; struct vdeparms { char *tag; char **value; }; int vde_parseparms(char *str,struct vdeparms *parms); int vde_parsepathparms(char *str,struct vdeparms *parms); char *vde_parsenestparms(char *str); struct vde_hashtable; void *vde_find_in_hash(struct vde_hashtable *table, unsigned char *dst, int vlan, time_t too_old); void vde_find_in_hash_update(struct vde_hashtable *table, unsigned char *src, int vlan, void *payload, time_t now); void vde_hash_delete(struct vde_hashtable *table, void *payload); #define vde_hash_init(type, hashsize, seed) _vde_hash_init(sizeof(type), (hashsize), (seed)) struct vde_hashtable *_vde_hash_init(size_t payload_size, unsigned int hashsize, uint64_t seed); void vde_hash_fini(struct vde_hashtable *table); unsigned long long strtoullm(const char *numstr); gid_t vde_grnam2gid(const char *name); #endif vdeplug4-4.0.1/libvdeplug4/000077500000000000000000000000001374136421200154725ustar00rootroot00000000000000vdeplug4-4.0.1/libvdeplug4/CMakeLists.txt000066400000000000000000000045561374136421200202440ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.13) set(VDEPLUG_SOVERSION 2) add_library(vdeplug SHARED libvdeplug.c libvdestream.c) set_target_properties(vdeplug PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${VDEPLUG_SOVERSION}) target_link_libraries(vdeplug -ldl) target_link_libraries(vdeplug -export-dynamic) add_library(vdeplug_mod SHARED parseparms.c vde_hashtable.c) set_target_properties(vdeplug_mod PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${VDEPLUG_SOVERSION}) target_link_libraries(vdeplug_mod -ldl) target_link_libraries(vdeplug_mod -export-dynamic) add_library(vdeplug_vde SHARED libvdeplug_vde.c) target_link_libraries(vdeplug_vde vdeplug_mod) add_library(vdeplug_ptp SHARED libvdeplug_ptp.c) target_link_libraries(vdeplug_ptp vdeplug_mod) add_library(vdeplug_tap SHARED libvdeplug_tap.c) target_link_libraries(vdeplug_tap vdeplug_mod) add_library(vdeplug_udp SHARED libvdeplug_udp.c) target_link_libraries(vdeplug_udp vdeplug_mod) add_library(vdeplug_vxlan SHARED libvdeplug_vxlan.c) target_link_libraries(vdeplug_vxlan vdeplug_mod) add_library(vdeplug_vxvde SHARED libvdeplug_vxvde.c) target_link_libraries(vdeplug_vxvde vdeplug_mod) add_library(vdeplug_cmd SHARED libvdeplug_cmd.c) target_link_libraries(vdeplug_cmd vdeplug_mod -lexecs) add_library(vdeplug_null SHARED libvdeplug_null.c) target_link_libraries(vdeplug_null vdeplug_mod) add_library(vdeplug_hub SHARED libvdeplug_hub.c libvdeplug_netnode.c) target_link_libraries(vdeplug_hub vdeplug_mod) add_library(vdeplug_switch SHARED libvdeplug_switch.c libvdeplug_netnode.c) target_link_libraries(vdeplug_switch vdeplug_mod) add_library(vdeplug_multi SHARED libvdeplug_multi.c libvdeplug_netnode.c) target_link_libraries(vdeplug_multi vdeplug_mod) add_library(vdeplug_bonding SHARED libvdeplug_bonding.c libvdeplug_netnode.c) target_link_libraries(vdeplug_bonding vdeplug_mod) add_library(vdeplug_seqpacket SHARED libvdeplug_seqpacket.c) target_link_libraries(vdeplug_seqpacket vdeplug_mod) install( TARGETS vdeplug_mod vdeplug LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ) install( TARGETS vdeplug_vde vdeplug_ptp vdeplug_tap vdeplug_udp vdeplug_vxlan vdeplug_vxvde vdeplug_cmd vdeplug_null vdeplug_hub vdeplug_switch vdeplug_multi vdeplug_bonding vdeplug_seqpacket LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/vdeplug ) vdeplug4-4.0.1/libvdeplug4/libvdeplug.c000066400000000000000000000173441374136421200200040ustar00rootroot00000000000000/* * libvdeplug - A library to connect to a VDE Switch. * Copyright (C) 2013-2016 Renzo Davoli, University of Bologna * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation version 2.1 of the License, or (at * your option) any later version. * * This 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 Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include "libvdeplug_mod.h" /* Per-User standard switch definition */ /* This will be prefixed by getenv("HOME") */ /* it can be a symbolic link to the switch dir */ #define STDSWITCH "/.vdeplug/default" #define OLDSTDSWITCH "/.vde2/default.switch" #define STD_LIB_PATH "/lib:/usr/lib" #define LIBVDEPLUG "libvdeplug_" #define LIBVDEPLUGIN "/vdeplug/" LIBVDEPLUG #define DEFAULT_MODULE "vde" uint64_t __vde_version_tag = 4; struct vde_open_parms { char *vde_args; char *descr; int interface_version; struct vde_open_args *open_args; }; static VDECONN *vde_open_module_lib(char *filename, struct vde_open_parms *parms) { void *handle=dlopen(filename, RTLD_NOW | RTLD_DEEPBIND); //printf("TRY %s %s\n", filename, parms->vde_args); if (handle) { struct vdeplug_module *module=dlsym(handle, "vdeplug_ops"); if (module) { VDECONN *rv = module->vde_open_real(parms->vde_args, parms->descr, parms->interface_version, parms->open_args); if (rv) { rv->handle = handle; rv->module = module; return rv; } } else errno = EPROTONOSUPPORT; dlclose(handle); } else errno = EPROTONOSUPPORT; return NULL; } static VDECONN *vde_open_samedir(char *modname, char *subdir, struct vde_open_parms *parms) { char path[PATH_MAX]; Dl_info info; if (dladdr(&__vde_version_tag, &info) != 0) { const char *libpath = info.dli_fname; char *slash = strrchr(libpath, '/'); if (slash) { int len = slash - libpath; snprintf(path, PATH_MAX, "%*.*s%s%s.so", len, len, libpath, subdir, modname); return vde_open_module_lib(path, parms); } } return errno = EPROTONOSUPPORT, NULL; } static VDECONN *vde_open_dirlist(char *modname, char *dirlist, char *subdir, struct vde_open_parms *parms) { char path[PATH_MAX]; VDECONN *retval; if (dirlist) { while (*dirlist != 0) { int len = strchrnul(dirlist, ':') - dirlist; snprintf(path, PATH_MAX, "%*.*s%s%s.so", len, len, dirlist, subdir, modname); retval = vde_open_module_lib(path, parms); if (retval != NULL || errno != EPROTONOSUPPORT) return retval; dirlist += len + (dirlist[len] == ':'); } } return errno = EPROTONOSUPPORT, NULL; } static VDECONN *vde_open_default(char *modname, struct vde_open_parms *parms) { char path[PATH_MAX]; snprintf(path, PATH_MAX, LIBVDEPLUG "%s.so", modname); return vde_open_module_lib(path, parms); } static VDECONN *vde_open_module(char *modname, struct vde_open_parms *parms) { char *vdeplugin_path = getenv("VDEPLUGIN_PATH"); // creata a copy of parms->vde_args size_t vde_args_len = strlen(parms->vde_args); char vde_args_copy[vde_args_len + 1]; strcpy(vde_args_copy, parms->vde_args); parms->vde_args = vde_args_copy; // if VDEPLUGIN_PATH exists it defines the search path for plugins if (vdeplugin_path) return vde_open_dirlist(modname, vdeplugin_path, "/" LIBVDEPLUG, parms); else { VDECONN *retval; retval = vde_open_samedir(modname, LIBVDEPLUGIN, parms); if (retval != NULL || errno != EPROTONOSUPPORT) return retval; retval = vde_open_samedir(modname, "/" LIBVDEPLUG, parms); if (retval != NULL || errno != EPROTONOSUPPORT) return retval; retval = vde_open_dirlist(modname, getenv("LD_LIBRARY_PATH"), LIBVDEPLUGIN, parms); if (retval != NULL || errno != EPROTONOSUPPORT) return retval; retval = vde_open_dirlist(modname, STD_LIB_PATH, LIBVDEPLUGIN, parms); if (retval != NULL || errno != EPROTONOSUPPORT) return retval; return vde_open_default(modname, parms); } } static inline size_t getpw_bufsize(void) { size_t bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); return bufsize > 0 ? bufsize : PATH_MAX; } static void set_newdescr(const char *descr, char *newdescr, size_t newdescrlen) { char *ssh_client = getenv("SSH_CLIENT"); int pid = getpid(); uid_t uid = geteuid(); struct passwd pwd; struct passwd *callerpwd; size_t bufsize = getpw_bufsize(); char buf[bufsize]; FILE *f = fmemopen(newdescr, newdescrlen, "w"); fprintf(f, "%s ", descr); getpwuid_r(uid, &pwd, buf, bufsize, &callerpwd); if (callerpwd) fprintf(f, "user=%s", callerpwd->pw_name); else fprintf(f, "user=%d", uid); fprintf(f, " pid=%d", pid); if (ssh_client) { int len = strchrnul(ssh_client,' ') - ssh_client; fprintf(f, " SSH=%*.*s", len, len, ssh_client); } fclose(f); newdescr[newdescrlen - 1] = 0; //printf("%s %d\n", newdescr, bufsize); } VDECONN *vde_open_real(char *vde_url, char *descr, int interface_version, struct vde_open_args *open_args) { char std_vde_url[PATH_MAX]; struct stat statbuf; char newdescr[MAXDESCR]; char *tag; struct vde_open_parms parms = { .descr = newdescr, .interface_version = interface_version, .open_args = open_args }; if (vde_url == NULL) vde_url = ""; tag = strstr(vde_url, "://"); set_newdescr(descr, newdescr, MAXDESCR); if (tag == NULL) { if (*vde_url == '\0') { char *homedir = getenv("HOME"); if (homedir) { snprintf(std_vde_url, PATH_MAX, "%s%s", homedir, STDSWITCH); if (lstat(std_vde_url, &statbuf) >= 0) vde_url = std_vde_url; else { snprintf(std_vde_url, PATH_MAX, "%s%s", homedir, OLDSTDSWITCH); if (lstat(std_vde_url, &statbuf) >= 0) vde_url = std_vde_url; } } } if (stat(vde_url, &statbuf) >= 0) { if (S_ISREG(statbuf.st_mode)) { FILE *f=fopen(vde_url,"r"); if (f != NULL) { if (fgets(std_vde_url, PATH_MAX, f) != NULL) { std_vde_url[strlen(std_vde_url) - 1] = 0; vde_url = std_vde_url; } tag = strstr(vde_url, "://"); fclose(f); } } } } if (vde_url == NULL || tag == NULL) { parms.vde_args = vde_url; return vde_open_module(DEFAULT_MODULE, &parms); } else { int modlen=tag - vde_url; char modname[modlen + 1]; snprintf(modname, modlen + 1, "%*.*s", modlen, modlen, vde_url); parms.vde_args = vde_url + (modlen + 3); return vde_open_module(modname, &parms); } } ssize_t vde_recv(VDECONN *conn,void *buf,size_t len,int flags) { if (__builtin_expect(conn!=0,1)) return conn->module->vde_recv(conn,buf,len,flags); else { errno=EBADF; return -1; } } ssize_t vde_send(VDECONN *conn,const void *buf,size_t len,int flags) { if (__builtin_expect(conn!=0,1)) return conn->module->vde_send(conn,buf,len,flags); else { errno=EBADF; return -1; } } int vde_datafd(VDECONN *conn) { if (__builtin_expect(conn!=0,1)) return conn->module->vde_datafd(conn); else { errno=EBADF; return -1; } } int vde_ctlfd(VDECONN *conn) { if (__builtin_expect(conn!=0,1)) return conn->module->vde_ctlfd(conn); else { errno=EBADF; return -1; } } int vde_close(VDECONN *conn) { if (__builtin_expect(conn!=0,1)) { void *handle=conn->handle; /* vde_close frees the struct conn */ int rv=conn->module->vde_close(conn); if (rv==0) dlclose(handle); return rv; } else { errno=EBADF; return -1; } } vdeplug4-4.0.1/libvdeplug4/libvdeplug_bonding.c000066400000000000000000000017761374136421200215060ustar00rootroot00000000000000/* * libvdeplug - A library to connect to a VDE Switch. * Copyright (C) 2013-2016 Renzo Davoli, University of Bologna * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation version 2.1 of the License, or (at * your option) any later version. * * This 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 Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "libvdeplug_netnode.h" struct vdeplug_module vdeplug_ops; static __attribute__ ((constructor)) void __init__(void) { vdeplug_ops = vdeplug_bonding_ops; } vdeplug4-4.0.1/libvdeplug4/libvdeplug_cmd.c000066400000000000000000000106271374136421200206240ustar00rootroot00000000000000/* * libvdeplug - A library to connect to a VDE Switch. * Copyright (C) 2017 Renzo Davoli, University of Bologna * * Stream vde to a command * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation version 2.1 of the License, or (at * your option) any later version. * * This 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 Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libvdeplug_mod.h" static VDECONN *vde_cmd_open(char *given_vde_url, char *descr,int interface_version, struct vde_open_args *open_args); static ssize_t vde_cmd_recv(VDECONN *conn,void *buf,size_t len,int flags); static ssize_t vde_cmd_send(VDECONN *conn,const void *buf,size_t len,int flags); static int vde_cmd_datafd(VDECONN *conn); static int vde_cmd_ctlfd(VDECONN *conn); static int vde_cmd_close(VDECONN *conn); struct vdeplug_module vdeplug_ops={ .vde_open_real=vde_cmd_open, .vde_recv=vde_cmd_recv, .vde_send=vde_cmd_send, .vde_datafd=vde_cmd_datafd, .vde_ctlfd=vde_cmd_ctlfd, .vde_close=vde_cmd_close}; struct vde_cmd_conn { void *handle; struct vdeplug_module *module; char *cmdstring; pid_t cmd_pid; int cmd_fd[2]; }; static VDECONN *vde_cmd_open(char *cmdstring, char *descr,int interface_version, struct vde_open_args *open_args) { struct vde_cmd_conn *newconn; if ((newconn=calloc(1,sizeof(struct vde_cmd_conn)))==NULL) { errno=ENOMEM; goto abort; } newconn->cmdstring = strdup(cmdstring); if ((newconn->cmd_pid = coprocsp(cmdstring, newconn->cmd_fd)) < 0) goto free_abort; return (VDECONN *)newconn; free_abort: free(newconn); abort: return NULL; } static ssize_t vde_cmd_recv(VDECONN *conn,void *buf,size_t len,int flags) { struct vde_cmd_conn *vde_conn = (struct vde_cmd_conn *)conn; unsigned char header[2]; unsigned int pktlen; ssize_t rv; struct pollfd pollok = {vde_conn->cmd_fd[0], POLLIN, 0}; if ((rv = read(vde_conn->cmd_fd[0], header, 2)) != 2) goto error; pktlen = (header[0]<<8) + header[1]; if (pktlen > VDE_ETHBUFSIZE) goto error; if (poll(&pollok,1,0) <= 0) goto error; if (pktlen <= len) { if ((rv = read(vde_conn->cmd_fd[0], buf, pktlen)) != pktlen) goto error; return rv; } else { ssize_t taillen = pktlen - len; unsigned char tail[taillen]; struct iovec iov[2]={{buf, len}, {tail, taillen}}; if ((rv = readv(vde_conn->cmd_fd[0], iov, 2)) != pktlen) goto error; return len; } error: if (rv < 0) { return rv; } else if (rv == 0) { // the command terminated int fd[2]; int status; pipe(fd); dup2(fd[0], vde_conn->cmd_fd[0]); dup2(fd[1], vde_conn->cmd_fd[1]); waitpid(vde_conn->cmd_pid, &status, WNOHANG); /* discard exit status */ fprintf(stderr, "VDE terminated: cmd://%s\n",vde_conn->cmdstring); return rv; } else { errno = EAGAIN; return 1; } } static ssize_t vde_cmd_send(VDECONN *conn,const void *buf,size_t len,int flags) { struct vde_cmd_conn *vde_conn = (struct vde_cmd_conn *)conn; if (len <= VDE_ETHBUFSIZE) { unsigned char header[2]; struct iovec iov[2]={{header,2},{(void *)buf,len}}; header[0]=len >> 8; header[1]=len & 0xff; return writev(vde_conn->cmd_fd[1],iov,2); } else return 0; } static int vde_cmd_datafd(VDECONN *conn) { struct vde_cmd_conn *vde_conn = (struct vde_cmd_conn *)conn; return vde_conn->cmd_fd[0]; } static int vde_cmd_ctlfd(VDECONN *conn) { return -1; } static int vde_cmd_close(VDECONN *conn) { struct vde_cmd_conn *vde_conn = (struct vde_cmd_conn *)conn; int status; close(vde_conn->cmd_fd[1]); close(vde_conn->cmd_fd[0]); kill(SIGTERM, vde_conn->cmd_pid); waitpid(vde_conn->cmd_pid, &status, 0); /* discard exit status */ if (vde_conn->cmdstring) free(vde_conn->cmdstring); free(vde_conn); return 0; } vdeplug4-4.0.1/libvdeplug4/libvdeplug_hub.c000066400000000000000000000017721374136421200206400ustar00rootroot00000000000000/* * libvdeplug - A library to connect to a VDE Switch. * Copyright (C) 2013-2016 Renzo Davoli, University of Bologna * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation version 2.1 of the License, or (at * your option) any later version. * * This 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 Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "libvdeplug_netnode.h" struct vdeplug_module vdeplug_ops; static __attribute__ ((constructor)) void __init__(void) { vdeplug_ops = vdeplug_hub_ops; } vdeplug4-4.0.1/libvdeplug4/libvdeplug_multi.c000066400000000000000000000017741374136421200212160ustar00rootroot00000000000000/* * libvdeplug - A library to connect to a VDE Switch. * Copyright (C) 2013-2016 Renzo Davoli, University of Bologna * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation version 2.1 of the License, or (at * your option) any later version. * * This 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 Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "libvdeplug_netnode.h" struct vdeplug_module vdeplug_ops; static __attribute__ ((constructor)) void __init__(void) { vdeplug_ops = vdeplug_multi_ops; } vdeplug4-4.0.1/libvdeplug4/libvdeplug_netnode.c000066400000000000000000000451721374136421200215200ustar00rootroot00000000000000/* * libvdeplug - A library to connect to a VDE Switch. * Copyright (C) 2017 Renzo Davoli, University of Bologna * * libvdeplug_netnode.c common implementation of a networking node as a vdeplug plugin. * a netnode supports the connection of a virtual machine, namespace, wire-end (here named host) * to several nodes. * this module provides the following services: * - hub: deliver packets to all the nodes but the sender (including the host) * - multi: deliver packets from the host to all the connected nodes, * but packets from the connected nodes to the host only. * - bundling: deliver packets from the host to one connected node (in round robin manner), * and packets from any of the connected nodes to the host only. * - switch: it is an ethernet switch connecting all the nodes including the host. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation version 2.1 of the License, or (at * your option) any later version. * * This 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 Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libvdeplug_mod.h" #define SWITCH #define SWITCH_MAGIC 0xfeedface #define REQBUFLEN 256 #define PORTTAB_STEP 4 #define STDHASHSIZE 256 #define STDEXPIRETIME 120 #define STDMODE 0600 #define STDDIRMODE 02700 #define STDPATH "/tmp/vdenode_" #define HOSTFAKEFD -1 enum request_type { REQ_NEW_CONTROL, REQ_NEW_PORT0 }; struct request_v3 { uint32_t magic; uint32_t version; enum request_type type; struct sockaddr_un sock; char description[]; } __attribute__((packed)); static VDECONN *vde_hub_open(char *vde_url, char *descr,int interface_version, struct vde_open_args *open_args); static VDECONN *vde_multi_open(char *vde_url, char *descr,int interface_version, struct vde_open_args *open_args); static VDECONN *vde_switch_open(char *vde_url, char *descr,int interface_version, struct vde_open_args *open_args); static VDECONN *vde_bonding_open(char *vde_url, char *descr,int interface_version, struct vde_open_args *open_args); static ssize_t vde_netnode_recv(VDECONN *conn, void *buf, size_t len, int flags); static ssize_t vde_netnode_send(VDECONN *conn, const void *buf, size_t len, int flags); static int vde_netnode_datafd(VDECONN *conn); static int vde_netnode_ctlfd(VDECONN *conn); static int vde_netnode_close(VDECONN *conn); struct vdeplug_module vdeplug_hub_ops={ .vde_open_real=vde_hub_open, .vde_recv=vde_netnode_recv, .vde_send=vde_netnode_send, .vde_datafd=vde_netnode_datafd, .vde_ctlfd=vde_netnode_ctlfd, .vde_close=vde_netnode_close}; struct vdeplug_module vdeplug_multi_ops={ .vde_open_real=vde_multi_open, .vde_recv=vde_netnode_recv, .vde_send=vde_netnode_send, .vde_datafd=vde_netnode_datafd, .vde_ctlfd=vde_netnode_ctlfd, .vde_close=vde_netnode_close}; struct vdeplug_module vdeplug_switch_ops={ .vde_open_real=vde_switch_open, .vde_recv=vde_netnode_recv, .vde_send=vde_netnode_send, .vde_datafd=vde_netnode_datafd, .vde_ctlfd=vde_netnode_ctlfd, .vde_close=vde_netnode_close}; struct vdeplug_module vdeplug_bonding_ops={ .vde_open_real=vde_bonding_open, .vde_recv=vde_netnode_recv, .vde_send=vde_netnode_send, .vde_datafd=vde_netnode_datafd, .vde_ctlfd=vde_netnode_ctlfd, .vde_close=vde_netnode_close}; enum netnode_type { HUBNODE, MULTINODE, SWITCHNODE, BONDINGNODE }; struct vde_netnode_conn { void *handle; struct vdeplug_module *module; enum netnode_type nettype; char *path; int epfd; int ctl_fd; mode_t mode; uint64_t *porttab; int porttablen, porttabmax; struct vde_hashtable *hashtable; int expiretime; int lastbonding; }; /* porttab management. A port is a uint64_t. porttab_add adds an element in the array conn->porttab. It reallocs the array if there is no space for the new elements (it adds PORTTAB_STEP elements). porttab_del deletes an element from conn->porttab. The valid elements of the array are kept contiguous by swapping the last and the deleted element. */ void porttab_add(struct vde_netnode_conn *conn, uint64_t fd) { if (conn->porttablen == conn->porttabmax) { int porttabnewmax = conn->porttabmax + PORTTAB_STEP; uint64_t *portnewtab = realloc(conn->porttab, porttabnewmax * sizeof(uint64_t)); if (portnewtab == NULL) return; conn->porttab = portnewtab; conn->porttabmax = porttabnewmax; } conn->porttab[conn->porttablen++]=fd; } void porttab_del(struct vde_netnode_conn *conn, uint64_t fd) { int i; for (i = 0; i < conn->porttablen; i++) { if (conn->porttab[i] == fd) break; } if (i < conn->porttablen) { conn->porttablen--; if (conn->porttablen > 0) conn->porttab[i] = conn->porttab[conn->porttablen]; } } /* datasock_open: create a "control dir" compatible with vde-2 switches, so that libvdeplug_vde can connect to this */ static int datasock_open(char *path, gid_t gid, int mode, int dirmode) { int connect_fd; struct sockaddr_un sun; int one = 1; if ((connect_fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) < 0) goto abort; if (setsockopt(connect_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) < 0) goto abort_connect_fd; if (mkdir(path, 02777) < 0) goto abort_connect_fd; if (gid >= 0 && chown(path, -1, gid) < 0) goto abort_mkdir; if (dirmode > 0 && chmod(path, dirmode) < 0) goto abort_mkdir; sun.sun_family = AF_UNIX; snprintf(sun.sun_path,sizeof(sun.sun_path),"%s/ctl",path); unlink(sun.sun_path); /* this should fail */ if (bind(connect_fd, (struct sockaddr *) &sun, sizeof(sun)) < 0) goto abort_mkdir; if (gid >= 0 && chown(sun.sun_path, -1, gid) < 0) goto abort_unlink; if (mode > 0 && chmod(sun.sun_path, mode) < 0) goto abort_unlink; if (listen(connect_fd, 15) < 0) goto abort_unlink; return connect_fd; abort_unlink: unlink(sun.sun_path); abort_mkdir: rmdir(path); abort_connect_fd: close(connect_fd); abort: return -1; } static void datasock_close(char *path) { struct sockaddr_un sun; sun.sun_family = AF_UNIX; snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/ctl", path); unlink(sun.sun_path); rmdir(path); } /* accept a new connection */ static int ctl_in(char *path, int ctl_fd) { struct sockaddr_un addr; socklen_t len; int new; len = sizeof(addr); new = accept(ctl_fd, (struct sockaddr *) &addr, &len); return new; } /* open a new connection on an accepted connection */ static int conn_in(char *path, int conn_fd, mode_t mode) { char reqbuf[REQBUFLEN+1]; struct request_v3 *req=(struct request_v3 *)reqbuf; int len; len = read(conn_fd, reqbuf, REQBUFLEN); /* backwards compatility: type can have embedded port# (type >> 8) */ if (len > 0 && req->magic == SWITCH_MAGIC && req->version == 3 && (req->type & 0xff) == REQ_NEW_CONTROL) { int data_fd; struct sockaddr_un sunc = req->sock; struct sockaddr_un sun; sun.sun_family = AF_UNIX; data_fd = socket(PF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); connect(data_fd, (struct sockaddr *) &sunc, sizeof(sunc)); snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/fd%d", path, conn_fd); unlink(sun.sun_path); bind(data_fd, (struct sockaddr *) &sun, sizeof(sun)); if (mode > 0) chmod(sun.sun_path, mode); write(conn_fd, &sun, sizeof(sun)); return data_fd; } return -1; } /* compute the size needed to store a struct passwd */ static inline long sysconf_getpw_r_size_max(void) { long retval = sysconf(_SC_GETPW_R_SIZE_MAX); if (retval < 0) retval = 16384; return retval; } /* compute the size needed to store a struct passwd */ static inline long sysconf_getgr_r_size_max(void) { long retval = sysconf(_SC_GETGR_R_SIZE_MAX); if (retval < 0) retval = 16384; return retval; } /* PORT is a uint64_t. A port stores two file descriptors. There are several cases: HI LO ctl_fd ctl_fd -> ctl_fd, the stream socket waiting to accept a new connection ctl_fd connfd -> (connfd != ctl_fd) accepted connection, waiting for a struct request datafd connfd -> (connfd != datafd != ctl_fd) established connection (ctl socket. no data should be received on this socket. just EOF to close). datafd datafd -> (datafd != ctl_fd) data socket. */ #define dualint(hi, lo) (((uint64_t)(hi) << 32) | (lo)) #define dualgetlo(x) ((uint32_t) x) #define dualgethi(x) ((uint32_t) (x >> 32)) /* COMMON function to open a netnode */ static VDECONN *vde_netnode_open(char *vde_url, char *descr,int interface_version, struct vde_open_args *open_args, enum netnode_type nettype) { char *path = vde_url; char userpath[PATH_MAX]; struct vde_netnode_conn *newconn; int epfd; int ctl_fd; struct epoll_event event = {.events = EPOLLIN}; char *modestr = NULL; char *dirmodestr = NULL; char *grpstr = NULL; char *hashsizestr = NULL; char *hashseedstr = NULL; char *expiretimestr = NULL; struct vdeparms parms[] = { {"mode", &modestr}, {"dirmode", &dirmodestr}, {"grp", &grpstr}, {"hashsize", &hashsizestr}, {"hashseed", &hashseedstr}, {"expiretime", &expiretimestr}, {NULL, NULL}}; int mode = STDMODE; int dirmode = STDDIRMODE; gid_t gid = -1; if (vde_parsepathparms(vde_url, parms) != 0) return NULL; /* if path==0, the standard path is /tmp/vdenode_${USERNAME} or /tmp/vdenode_u${EUID} if the euid is not in /etc/passwd. e.g. /tmp/vdenode_renzo or /tmp/vdenode_u1000 */ if (*path == 0) { size_t bufsize = sysconf_getpw_r_size_max(); char buf[bufsize]; struct passwd pwd; struct passwd *result; uid_t euid = geteuid(); getpwuid_r(euid, &pwd, buf, bufsize, &result); if (result) snprintf(userpath, PATH_MAX, STDPATH "%s", pwd.pw_name); else snprintf(userpath, PATH_MAX, STDPATH "u%d", euid); userpath[PATH_MAX-1] = 0; path = userpath; } else { char *filename=basename(path); char *dir=dirname(path); if ((path = realpath(dir, userpath)) == NULL) return NULL; strncat(path, "/", PATH_MAX); strncat(path, filename, PATH_MAX); } if (grpstr != NULL) { size_t bufsize = sysconf_getgr_r_size_max(); char buf[bufsize]; struct group grp; struct group *result; getgrnam_r(grpstr, &grp, buf, bufsize, &result); if (result) gid = grp.gr_gid; else if (isdigit(*grpstr)) gid = strtol(grpstr, NULL, 0); } /* management of mode and dirmode. */ if (modestr) mode = strtol(modestr, NULL, 8) & ~0111; if (dirmodestr) dirmode = strtol(dirmodestr, NULL, 8); else if (modestr) dirmode = 02000 | mode | (mode & 0444) >> 2 | (mode & 0222) >> 1; /* epoll (a vdeplug has one fddata, so an epoll file descriptor can can summarize the events coming from many fd) */ if ((epfd = epoll_create1(EPOLL_CLOEXEC)) < 0) goto abort; if ((ctl_fd = datasock_open(path, gid, mode, dirmode)) < 0) goto abort_epoll; event.data.u64 = dualint(ctl_fd, ctl_fd); if (epoll_ctl(epfd, EPOLL_CTL_ADD, ctl_fd, &event) < 0) goto abort_datasock; if ((newconn=calloc(1,sizeof(struct vde_netnode_conn)))==NULL) { errno=ENOMEM; goto abort_datasock; } newconn->nettype=nettype; newconn->epfd=epfd; newconn->ctl_fd=ctl_fd; newconn->mode=mode; newconn->path=strdup(path); newconn->porttab=NULL; newconn->porttablen=newconn->porttabmax=0; newconn->expiretime = expiretimestr ? atoi(expiretimestr) : STDEXPIRETIME; newconn->lastbonding = 0; if (nettype == SWITCHNODE) newconn->hashtable = vde_hash_init(int, hashsizestr ? atoi(hashsizestr) : STDHASHSIZE, hashseedstr ? atoi(hashseedstr) : 0); else newconn->hashtable = NULL; return (VDECONN *)newconn; abort_datasock: close(ctl_fd); datasock_close(path); abort_epoll: close(epfd); abort: return NULL; } static VDECONN *vde_hub_open(char *vde_url, char *descr,int interface_version, struct vde_open_args *open_args) { return vde_netnode_open(vde_url, descr, interface_version, open_args, HUBNODE); } static VDECONN *vde_multi_open(char *vde_url, char *descr,int interface_version, struct vde_open_args *open_args) { return vde_netnode_open(vde_url, descr, interface_version, open_args, MULTINODE); } static VDECONN *vde_switch_open(char *vde_url, char *descr,int interface_version, struct vde_open_args *open_args) { return vde_netnode_open(vde_url, descr, interface_version, open_args, SWITCHNODE); } static VDECONN *vde_bonding_open(char *vde_url, char *descr,int interface_version, struct vde_open_args *open_args) { return vde_netnode_open(vde_url, descr, interface_version, open_args, BONDINGNODE); } /* get the vlan id from an Ethernet packet */ static inline int eth_vlan(const void *buf,size_t len) { if (__builtin_expect(len >= sizeof(struct ether_header) + 4, 1)) { struct ether_header *ethh = (void *) buf; uint16_t *vlanhdr = (void *) (ethh + 1); if (ntohs(ethh->ether_type) == ETHERTYPE_VLAN) return ntohs(*vlanhdr) & 0x3ff; } return 0; } /* get the source MAC from an Ethernet packet */ static inline uint8_t *eth_shost(const void *buf, size_t len) { struct ether_header *ethh = (void *) buf; return ethh->ether_shost; } /* get the destination MAC from an Ethernet packet */ static inline uint8_t *eth_dhost(const void *buf, size_t len) { struct ether_header *ethh = (void *) buf; return ethh->ether_dhost; } /* receive a packet (from one of the connected node, i.e. there is a pending epoll event */ static ssize_t vde_netnode_recv(VDECONN *conn, void *buf, size_t len, int flags) { struct epoll_event event; ssize_t retval = 1; struct vde_netnode_conn *vde_conn = (struct vde_netnode_conn *)conn; if (epoll_wait(vde_conn->epfd, &event, 1, -1) > 0) { int fd = dualgetlo(event.data.u64); int fd2 = dualgethi(event.data.u64); if (fd == fd2) { if (fd == vde_conn->ctl_fd) { /* CTL IN */ int conn_fd = ctl_in(vde_conn->path, vde_conn->ctl_fd); if (conn_fd >= 0) { event.events = EPOLLIN; event.data.u64 = dualint(vde_conn->ctl_fd, conn_fd); epoll_ctl(vde_conn->epfd, EPOLL_CTL_ADD, conn_fd, &event); } } else { /* DATA IN */ len = read(fd, buf, len); if (__builtin_expect(len >= sizeof(struct ether_header), 1)) { if (vde_conn->nettype == MULTINODE || vde_conn->nettype == BONDINGNODE) /* MULTINODE or BONDINGNODE -> to the host only */ retval = len; else { int i; int *outfdp; time_t now = time(NULL); if (vde_conn->hashtable) vde_find_in_hash_update(vde_conn->hashtable, eth_shost(buf, len), eth_vlan(buf, len), &fd, now); if (vde_conn->hashtable && (outfdp = vde_find_in_hash(vde_conn->hashtable, eth_dhost(buf, len), eth_vlan(buf, len), now - vde_conn->expiretime)) != NULL) { if (*outfdp == HOSTFAKEFD) retval = len; /* to the host */ else if (*outfdp != fd) /* avoid back delivery to the sender */ write(*outfdp, buf, len); } else { /* HUB or BUM (broadcast, unknown receipient, multicast) */ for (i = 0; i < vde_conn->porttablen; i++) { int outfd = dualgethi(vde_conn->porttab[i]); if (outfd != fd) write(outfd, buf, len); } retval = len; } } } } } else { if (fd2 == vde_conn->ctl_fd) { /* CONN_IN */ int data_fd = conn_in(vde_conn->path, fd, vde_conn->mode); if (data_fd >= 0) { event.events = EPOLLIN; event.data.u64 = dualint(data_fd, fd); porttab_add(vde_conn, event.data.u64); epoll_ctl(vde_conn->epfd, EPOLL_CTL_MOD, fd, &event); event.data.u64 = dualint(data_fd, data_fd); epoll_ctl(vde_conn->epfd, EPOLL_CTL_ADD, data_fd, &event); } } else { /* close connection, EOF on the control socket */ struct sockaddr_un sun; if (vde_conn->hashtable) vde_hash_delete(vde_conn->hashtable, &fd2); porttab_del(vde_conn, event.data.u64); epoll_ctl(vde_conn->epfd, EPOLL_CTL_DEL, fd, NULL); epoll_ctl(vde_conn->epfd, EPOLL_CTL_DEL, fd2, NULL); close(fd); close(fd2); sun.sun_family = AF_UNIX; snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/fd%d",vde_conn->path,fd); unlink(sun.sun_path); } } } return retval; } /* There is an avent coming from the host */ static ssize_t vde_netnode_send(VDECONN *conn, const void *buf, size_t len, int flags) { if (__builtin_expect(len >= sizeof(struct ether_header), 1)) { int i; struct vde_netnode_conn *vde_conn = (struct vde_netnode_conn *)conn; int *outfdp; int infd = HOSTFAKEFD; time_t now = time(NULL); if (vde_conn->hashtable) vde_find_in_hash_update(vde_conn->hashtable, eth_shost(buf, len), eth_vlan(buf, len), &infd, now); if (vde_conn->hashtable && (outfdp = vde_find_in_hash(vde_conn->hashtable, eth_dhost(buf, len), eth_vlan(buf, len), now - vde_conn->expiretime)) != NULL) { if (*outfdp != HOSTFAKEFD) /* avoid back delivery to the host */ write(*outfdp, buf, len); } else { if (vde_conn->nettype == BONDINGNODE) { /* bonding: roung robind send packets on one available connection */ if (vde_conn->porttablen > 0) { int outfd; vde_conn->lastbonding = (vde_conn->lastbonding + 1) % vde_conn->porttablen; outfd = dualgethi(vde_conn->porttab[vde_conn->lastbonding]); write(outfd, buf, len); } } else { /* HUB, MULTI or BUM (broadcast, unknown receipient, multicast) */ for (i = 0; i < vde_conn->porttablen; i++) { int outfd = dualgethi(vde_conn->porttab[i]); write(outfd, buf, len); } } } } return len; } static int vde_netnode_datafd(VDECONN *conn) { struct vde_netnode_conn *vde_conn = (struct vde_netnode_conn *)conn; return vde_conn->epfd; } static int vde_netnode_ctlfd(VDECONN *conn) { return -1; } static int vde_netnode_close(VDECONN *conn) { int i; struct vde_netnode_conn *vde_conn = (struct vde_netnode_conn *)conn; for (i = 0; i < vde_conn->porttablen; i++) { int fd = dualgetlo(vde_conn->porttab[i]); int fd2 = dualgethi(vde_conn->porttab[i]); struct sockaddr_un sun; close(fd); close(fd2); sun.sun_family = AF_UNIX; snprintf(sun.sun_path,sizeof(sun.sun_path), "%s/fd%d", vde_conn->path,fd); unlink(sun.sun_path); } datasock_close(vde_conn->path); close(vde_conn->ctl_fd); close(vde_conn->epfd); if (vde_conn->porttab) free(vde_conn->porttab); if (vde_conn->hashtable) vde_hash_fini(vde_conn->hashtable); free(vde_conn->path); free(vde_conn); return 0; } vdeplug4-4.0.1/libvdeplug4/libvdeplug_netnode.h000066400000000000000000000004711374136421200215160ustar00rootroot00000000000000#ifndef LIBVDEPLUG_NETNODE_H #define LIBVDEPLUG_NETNODE_H #include #include "libvdeplug_mod.h" extern struct vdeplug_module vdeplug_hub_ops; extern struct vdeplug_module vdeplug_multi_ops; extern struct vdeplug_module vdeplug_switch_ops; extern struct vdeplug_module vdeplug_bonding_ops; #endif vdeplug4-4.0.1/libvdeplug4/libvdeplug_null.c000066400000000000000000000055071374136421200210340ustar00rootroot00000000000000/* * libvdeplug - A library to connect to a VDE Switch. * Copyright (C) 2013-2016 Renzo Davoli, University of Bologna * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation version 2.1 of the License, or (at * your option) any later version. * * This 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 Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include "libvdeplug_mod.h" static VDECONN *vde_null_open(char *given_vde_url, char *descr,int interface_version, struct vde_open_args *open_args); static ssize_t vde_null_recv(VDECONN *conn,void *buf,size_t len,int flags); static ssize_t vde_null_send(VDECONN *conn,const void *buf,size_t len,int flags); static int vde_null_datafd(VDECONN *conn); static int vde_null_ctlfd(VDECONN *conn); static int vde_null_close(VDECONN *conn); struct vdeplug_module vdeplug_ops={ .vde_open_real=vde_null_open, .vde_recv=vde_null_recv, .vde_send=vde_null_send, .vde_datafd=vde_null_datafd, .vde_ctlfd=vde_null_ctlfd, .vde_close=vde_null_close}; struct vde_null_conn { void *handle; struct vdeplug_module *module; int fddata; }; static VDECONN *vde_null_open(char *given_vde_url, char *descr,int interface_version, struct vde_open_args *open_args) { struct vde_null_conn *newconn; int fddata = eventfd(0, EFD_CLOEXEC); if (fddata < 0) goto abort; if ((newconn=calloc(1,sizeof(struct vde_null_conn)))==NULL) { errno=ENOMEM; goto abort; } newconn->fddata=fddata; return (VDECONN *)newconn; abort: if (fddata >= 0) close(fddata); return NULL; } static ssize_t vde_null_recv(VDECONN *conn,void *buf,size_t len,int flags) { //struct vde_null_conn *vde_conn = (struct vde_null_conn *)conn; return 1; } static ssize_t vde_null_send(VDECONN *conn,const void *buf,size_t len,int flags) { //struct vde_null_conn *vde_conn = (struct vde_null_conn *)conn; return len; } static int vde_null_datafd(VDECONN *conn) { struct vde_null_conn *vde_conn = (struct vde_null_conn *)conn; return vde_conn->fddata; } static int vde_null_ctlfd(VDECONN *conn) { return -1; } static int vde_null_close(VDECONN *conn) { struct vde_null_conn *vde_conn = (struct vde_null_conn *)conn; close(vde_conn->fddata); free(vde_conn); return 0; } vdeplug4-4.0.1/libvdeplug4/libvdeplug_ptp.c000066400000000000000000000174001374136421200206600ustar00rootroot00000000000000/* * libvdeplug - A library to connect to a VDE Switch. * Copyright (C) 2013-2016 Renzo Davoli, University of Bologna * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation version 2.1 of the License, or (at * your option) any later version. * * This 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 Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libvdeplug_mod.h" static VDECONN *vde_ptp_open(char *given_vde_url, char *descr,int interface_version, struct vde_open_args *open_args); static ssize_t vde_ptp_recv(VDECONN *conn,void *buf,size_t len,int flags); static ssize_t vde_ptp_send(VDECONN *conn,const void *buf,size_t len,int flags); static int vde_ptp_datafd(VDECONN *conn); static int vde_ptp_ctlfd(VDECONN *conn); static int vde_ptp_close(VDECONN *conn); struct vdeplug_module vdeplug_ops={ .vde_open_real=vde_ptp_open, .vde_recv=vde_ptp_recv, .vde_send=vde_ptp_send, .vde_datafd=vde_ptp_datafd, .vde_ctlfd=vde_ptp_ctlfd, .vde_close=vde_ptp_close}; struct vde_ptp_conn { void *handle; struct vdeplug_module *module; int fddata; char *inpath; struct sockaddr *outsock; size_t outlen; }; #define UNUSED(...) (void)(__VA_ARGS__) static VDECONN *vde_ptpf_open(char *given_vde_url, char *descr,int interface_version, struct vde_open_args *open_args) { int port=0; char *group=NULL; mode_t mode=0700; int fddata=-1; struct sockaddr_un sockun; struct sockaddr_un sockout; struct stat sockstat; int res; struct vde_ptp_conn *newconn; if (open_args != NULL) { if (interface_version == 1) { port=open_args->port; group=open_args->group; mode=open_args->mode; } else { errno=EINVAL; goto abort; } } UNUSED(port); memset(&sockun, 0, sizeof(sockun)); if((fddata = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0)) < 0) goto abort; sockun.sun_family = AF_UNIX; snprintf(sockun.sun_path, sizeof(sockun.sun_path)-1, "%s", given_vde_url); /* the socket already exists */ if(stat(sockun.sun_path,&sockstat) == 0) { if (S_ISSOCK(sockstat.st_mode)) { /* the socket is already in use */ res = connect(fddata, (struct sockaddr *) &sockun, sizeof(sockun)); if (res >= 0) { errno = EADDRINUSE; goto abort; } if (errno == ECONNREFUSED) unlink(sockun.sun_path); } } res = bind(fddata, (struct sockaddr *) &sockun, sizeof(sockun)); if (res < 0) goto abort; memset(&sockout, 0, sizeof(sockun)); sockout.sun_family = AF_UNIX; snprintf(sockout.sun_path, sizeof(sockun.sun_path), "%s+", given_vde_url); if (group) { struct group *gs; gid_t gid; if ((gs=getgrnam(group)) == NULL) gid=atoi(group); else gid=gs->gr_gid; if (chown(sockun.sun_path,-1,gid) < 0) goto abort; } chmod(sockun.sun_path,mode); if ((newconn=calloc(1,sizeof(struct vde_ptp_conn)))==NULL) { errno=ENOMEM; goto abort; } newconn->fddata=fddata; newconn->inpath=strdup(sockun.sun_path); newconn->outlen = sizeof(struct sockaddr_un); newconn->outsock=malloc(newconn->outlen); memcpy(newconn->outsock,&sockout,sizeof(struct sockaddr_un)); return (VDECONN *)newconn; abort: if (fddata >= 0) close(fddata); return NULL; } static VDECONN *vde_ptpm_open(char *given_vde_url, char *descr,int interface_version, struct vde_open_args *open_args) { int port=0; char *group=NULL; mode_t mode=0700; int fddata=-1; struct sockaddr_un sockun; struct sockaddr_un sockout; struct stat sockstat; int res; struct vde_ptp_conn *newconn; if (open_args != NULL) { if (interface_version == 1) { port=open_args->port; group=open_args->group; mode=open_args->mode; } else { errno=EINVAL; goto abort; } } UNUSED(port); memset(&sockun, 0, sizeof(sockun)); memset(&sockout, 0, sizeof(sockun)); sockun.sun_family = AF_UNIX; sockout.sun_family = AF_UNIX; if((fddata = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0)) < 0) goto abort; snprintf(sockout.sun_path, sizeof(sockout.sun_path)-1, "%s", given_vde_url); res = connect(fddata, (struct sockaddr *) &sockout, sizeof(sockout)); if (res < 0) goto abort; snprintf(sockun.sun_path, sizeof(sockun.sun_path)-1, "%s+", given_vde_url); /* the socket already exists */ if(stat(sockun.sun_path,&sockstat) == 0) { if (S_ISSOCK(sockstat.st_mode)) { /* the socket is already in use */ res = connect(fddata, (struct sockaddr *) &sockun, sizeof(sockun)); if (res >= 0) { errno = EADDRINUSE; goto abort; } if (errno == ECONNREFUSED) unlink(sockun.sun_path); } } res = bind(fddata, (struct sockaddr *) &sockun, sizeof(sockun)); if (res < 0) goto abort; if (group) { struct group *gs; gid_t gid; if ((gs=getgrnam(group)) == NULL) gid=atoi(group); else gid=gs->gr_gid; if (chown(sockun.sun_path,-1,gid) < 0) goto abort; } chmod(sockun.sun_path,mode); if ((newconn=calloc(1,sizeof(struct vde_ptp_conn)))==NULL) { errno=ENOMEM; goto abort; } newconn->fddata=fddata; newconn->inpath=strdup(sockun.sun_path); newconn->outlen = sizeof(struct sockaddr_un); newconn->outsock=malloc(newconn->outlen); memcpy(newconn->outsock,&sockout,sizeof(struct sockaddr_un)); return (VDECONN *)newconn; abort: if (fddata >= 0) close(fddata); return NULL; } static VDECONN *vde_ptp_open(char *given_vde_url, char *descr,int interface_version, struct vde_open_args *open_args) { VDECONN *rv; rv=vde_ptpf_open(given_vde_url, descr, interface_version, open_args); if (!rv) rv=vde_ptpm_open(given_vde_url, descr, interface_version, open_args); return rv; } static ssize_t vde_ptp_recv(VDECONN *conn,void *buf,size_t len,int flags) { struct vde_ptp_conn *vde_conn = (struct vde_ptp_conn *)conn; #ifdef CONNECTED_P2P ssize_t retval; if (__builtin_expect(((retval=recv(vde_conn->fddata,buf,len,0)) > 0), 1)) return retval; else { if (retval == 0 && vde_conn->outsock != NULL) { static struct sockaddr unspec={AF_UNSPEC}; connect(vde_conn->fddata,&unspec,sizeof(unspec)); } return retval; } #else return recv(vde_conn->fddata,buf,len,0); #endif } static ssize_t vde_ptp_send(VDECONN *conn,const void *buf,size_t len,int flags) { struct vde_ptp_conn *vde_conn = (struct vde_ptp_conn *)conn; #ifdef CONNECTED_P2P ssize_t retval; if (__builtin_expect(((retval=send(vde_conn->fddata,buf,len,0)) >= 0),1)) return retval; else { if (__builtin_expect(errno == ENOTCONN || errno == EDESTADDRREQ,0)) { if (__builtin_expect(vde_conn->outsock != NULL,1)) { connect(vde_conn->fddata, vde_conn->outsock,vde_conn->outlen); return send(vde_conn->fddata,buf,len,0); } else return retval; } else return retval; } #else return sendto(vde_conn->fddata,buf,len,0, vde_conn->outsock,vde_conn->outlen); #endif } static int vde_ptp_datafd(VDECONN *conn) { struct vde_ptp_conn *vde_conn = (struct vde_ptp_conn *)conn; return vde_conn->fddata; } static int vde_ptp_ctlfd(VDECONN *conn) { return -1; } static int vde_ptp_close(VDECONN *conn) { struct vde_ptp_conn *vde_conn = (struct vde_ptp_conn *)conn; close(vde_conn->fddata); if (vde_conn->inpath != NULL) { unlink(vde_conn->inpath); free(vde_conn->inpath); } if (vde_conn->outsock != NULL) free(vde_conn->outsock); free(vde_conn); return 0; } vdeplug4-4.0.1/libvdeplug4/libvdeplug_seqpacket.c000066400000000000000000000064211374136421200220360ustar00rootroot00000000000000/* * libvdeplug - A library to connect to a VDE Switch. * Copyright (C) 2013-2016 Renzo Davoli, University of Bologna * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation version 2.1 of the License, or (at * your option) any later version. * * This 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 Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libvdeplug_mod.h" static VDECONN *vde_seqpacket_open(char *vde_url, char *descr, int interface_version, struct vde_open_args *open_args); static ssize_t vde_seqpacket_recv(VDECONN *conn, void *buf, size_t len, int flags); static ssize_t vde_seqpacket_send(VDECONN *conn, const void *buf, size_t len, int flags); static int vde_seqpacket_datafd(VDECONN *conn); static int vde_seqpacket_ctlfd(VDECONN *conn); static int vde_seqpacket_close(VDECONN *conn); struct vdeplug_module vdeplug_ops={ .vde_open_real=vde_seqpacket_open, .vde_recv=vde_seqpacket_recv, .vde_send=vde_seqpacket_send, .vde_datafd=vde_seqpacket_datafd, .vde_ctlfd=vde_seqpacket_ctlfd, .vde_close=vde_seqpacket_close}; struct vde_seqpacket_conn { void *handle; struct vdeplug_module *module; int fddata; }; static VDECONN *vde_seqpacket_open(char *vde_url, char *descr, int interface_version, struct vde_open_args *open_args) { long fddata=-1; struct vde_seqpacket_conn *newconn; errno = 0; fddata = strtol(vde_url, NULL, 0); if (errno != 0) return NULL; if (fddata < 0) { errno = EINVAL; return NULL; } if ((newconn = calloc(1, sizeof(struct vde_seqpacket_conn))) == NULL) { close(fddata); errno = ENOMEM; return NULL; } newconn->fddata=fddata; return (VDECONN *)newconn; } static ssize_t vde_seqpacket_recv(VDECONN *conn, void *buf, size_t len, int flags) { struct vde_seqpacket_conn *vde_conn = (struct vde_seqpacket_conn *)conn; return recv(vde_conn->fddata, buf, len, 0); } static ssize_t vde_seqpacket_send(VDECONN *conn, const void *buf, size_t len, int flags) { struct vde_seqpacket_conn *vde_conn = (struct vde_seqpacket_conn *)conn; /* never send zero length packets */ if (__builtin_expect(len > 0, 1)) return send(vde_conn->fddata, buf, len, 0); else return len; } static int vde_seqpacket_datafd(VDECONN *conn) { struct vde_seqpacket_conn *vde_conn = (struct vde_seqpacket_conn *)conn; return vde_conn->fddata; } static int vde_seqpacket_ctlfd(VDECONN *conn) { return -1; } static int vde_seqpacket_close(VDECONN *conn) { struct vde_seqpacket_conn *vde_conn = (struct vde_seqpacket_conn *)conn; close(vde_conn->fddata); free(vde_conn); return 0; } vdeplug4-4.0.1/libvdeplug4/libvdeplug_switch.c000066400000000000000000000017751374136421200213660ustar00rootroot00000000000000/* * libvdeplug - A library to connect to a VDE Switch. * Copyright (C) 2013-2016 Renzo Davoli, University of Bologna * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation version 2.1 of the License, or (at * your option) any later version. * * This 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 Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "libvdeplug_netnode.h" struct vdeplug_module vdeplug_ops; static __attribute__ ((constructor)) void __init__(void) { vdeplug_ops = vdeplug_switch_ops; } vdeplug4-4.0.1/libvdeplug4/libvdeplug_tap.c000066400000000000000000000062531374136421200206450ustar00rootroot00000000000000/* * libvdeplug - A library to connect to a VDE Switch. * Copyright (C) 2013-2016 Renzo Davoli, University of Bologna * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation version 2.1 of the License, or (at * your option) any later version. * * This 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 Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include "libvdeplug_mod.h" #include #include #include static VDECONN *vde_tap_open(char *given_vde_url, char *descr,int interface_version, struct vde_open_args *open_args); static ssize_t vde_tap_recv(VDECONN *conn,void *buf,size_t len,int flags); static ssize_t vde_tap_send(VDECONN *conn,const void *buf,size_t len,int flags); static int vde_tap_datafd(VDECONN *conn); static int vde_tap_ctlfd(VDECONN *conn); static int vde_tap_close(VDECONN *conn); struct vdeplug_module vdeplug_ops={ .vde_open_real=vde_tap_open, .vde_recv=vde_tap_recv, .vde_send=vde_tap_send, .vde_datafd=vde_tap_datafd, .vde_ctlfd=vde_tap_ctlfd, .vde_close=vde_tap_close}; struct vde_tap_conn { void *handle; struct vdeplug_module *module; int fddata; }; static VDECONN *vde_tap_open(char *given_vde_url, char *descr,int interface_version, struct vde_open_args *open_args) { struct ifreq ifr; int fddata=-1; struct vde_tap_conn *newconn; if((fddata = open("/dev/net/tun", O_RDWR)) < 0) goto abort; memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; strncpy(ifr.ifr_name, given_vde_url, sizeof(ifr.ifr_name) - 1); //printf("tap dev=\"%s\", ifr.ifr_name=\"%s\"\n", ifr.ifr_name, given_vde_url); if(ioctl(fddata, TUNSETIFF, (void *) &ifr) < 0) goto abort; if ((newconn=calloc(1,sizeof(struct vde_tap_conn)))==NULL) { errno=ENOMEM; goto abort; } newconn->fddata=fddata; return (VDECONN *)newconn; abort: if (fddata >= 0) close(fddata); return NULL; } static ssize_t vde_tap_recv(VDECONN *conn,void *buf,size_t len,int flags) { struct vde_tap_conn *vde_conn = (struct vde_tap_conn *)conn; return read(vde_conn->fddata,buf,len); } static ssize_t vde_tap_send(VDECONN *conn,const void *buf,size_t len,int flags) { struct vde_tap_conn *vde_conn = (struct vde_tap_conn *)conn; return write(vde_conn->fddata,buf,len); } static int vde_tap_datafd(VDECONN *conn) { struct vde_tap_conn *vde_conn = (struct vde_tap_conn *)conn; return vde_conn->fddata; } static int vde_tap_ctlfd(VDECONN *conn) { return -1; } static int vde_tap_close(VDECONN *conn) { struct vde_tap_conn *vde_conn = (struct vde_tap_conn *)conn; close(vde_conn->fddata); free(vde_conn); return 0; } vdeplug4-4.0.1/libvdeplug4/libvdeplug_udp.c000066400000000000000000000127131374136421200206470ustar00rootroot00000000000000/* * libvdeplug - A library to connect to a VDE Switch. * Copyright (C) 2013-2016 Renzo Davoli, University of Bologna * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation version 2.1 of the License, or (at * your option) any later version. * * This 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 Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libvdeplug_mod.h" static VDECONN *vde_udp_open(char *vde_url, char *descr,int interface_version, struct vde_open_args *open_args); static ssize_t vde_udp_recv(VDECONN *conn,void *buf,size_t len,int flags); static ssize_t vde_udp_send(VDECONN *conn,const void *buf,size_t len,int flags); static int vde_udp_datafd(VDECONN *conn); static int vde_udp_ctlfd(VDECONN *conn); static int vde_udp_close(VDECONN *conn); struct vdeplug_module vdeplug_ops={ .vde_open_real=vde_udp_open, .vde_recv=vde_udp_recv, .vde_send=vde_udp_send, .vde_datafd=vde_udp_datafd, .vde_ctlfd=vde_udp_ctlfd, .vde_close=vde_udp_close}; struct vde_udp_conn { void *handle; struct vdeplug_module *module; int fddata; struct sockaddr *outsock; size_t outlen; }; static VDECONN *vde_udp_open(char *vde_url, char *descr,int interface_version, struct vde_open_args *open_args) { int fddata=-1; struct addrinfo hints; struct addrinfo *srcresult=NULL; struct addrinfo *dstresult=NULL; struct addrinfo *rp; int s; char *dst; char *src=vde_url; char *srcport; char *dstport; struct vde_udp_conn *newconn; dst=strstr(vde_url,"->"); //printf("%s\n",vde_url); if (dst == NULL) return NULL; memset(&hints,0,sizeof(hints)); hints.ai_socktype=SOCK_DGRAM; *dst=0; dst+=2; dstport=rindex(dst,':'); if (dstport==NULL) { errno=EINVAL; goto abort; } *dstport=0; dstport++; srcport=rindex(src,':'); if (srcport==NULL) { srcport=src; src=NULL; } else { if (srcport==src) src=NULL; *srcport=0; srcport++; } if ((s = getaddrinfo(dst, dstport, &hints, &dstresult)) != 0) { //fprintf(stderr,"%s: %s\n",dst,gai_strerror(s)); errno=ECONNABORTED; goto abort; } hints.ai_flags = AI_PASSIVE; hints.ai_family = dstresult->ai_family; s = getaddrinfo(src, srcport, &hints, &srcresult); if (s != 0) { //fprintf(stderr,"%s: %s\n",src,gai_strerror(s)); errno=ECONNABORTED; goto abort; } for (rp = srcresult; rp != NULL; rp = rp->ai_next) { fddata = socket(rp->ai_family, rp->ai_socktype | SOCK_CLOEXEC, rp->ai_protocol); if (fddata == -1) continue; if (bind(fddata, rp->ai_addr, rp->ai_addrlen) == 0) break; /* Success */ close(fddata); } if (rp == NULL) { errno=ECONNABORTED; goto abort; } freeaddrinfo(srcresult); //fprintf(stderr,"UDP!%s:%s -> %s:%s \n",src,srcport,dst,dstport); if ((newconn=calloc(1,sizeof(struct vde_udp_conn)))==NULL) { errno=ENOMEM; goto abort; } newconn->fddata=fddata; newconn->outsock = malloc(dstresult->ai_addrlen); newconn->outlen = dstresult->ai_addrlen; memcpy(newconn->outsock, dstresult->ai_addr, dstresult->ai_addrlen); freeaddrinfo(dstresult); return (VDECONN *)newconn; abort: if (fddata >= 0) close(fddata); if (dstresult) freeaddrinfo(dstresult); if (srcresult) freeaddrinfo(srcresult); return NULL; } static ssize_t vde_udp_recv(VDECONN *conn,void *buf,size_t len,int flags) { struct vde_udp_conn *vde_conn = (struct vde_udp_conn *)conn; #ifdef CONNECTED_P2P ssize_t retval; if (__builtin_expect(((retval=recv(vde_conn->fddata,buf,len,0)) > 0), 1)) return retval; else { if (retval == 0 && vde_conn->outsock != NULL) { static struct sockaddr unspec={AF_UNSPEC}; connect(vde_conn->fddata,&unspec,sizeof(unspec)); } return retval; } #else return recv(vde_conn->fddata,buf,len,0); #endif } static ssize_t vde_udp_send(VDECONN *conn,const void *buf,size_t len,int flags) { struct vde_udp_conn *vde_conn = (struct vde_udp_conn *)conn; #ifdef CONNECTED_P2P ssize_t retval; if (__builtin_expect(((retval=send(vde_conn->fddata,buf,len,0)) >= 0),1)) return retval; else { if (__builtin_expect(errno == ENOTCONN || errno == EDESTADDRREQ,0)) { if (__builtin_expect(vde_conn->outsock != NULL,1)) { connect(vde_conn->fddata, vde_conn->outsock,vde_conn->outlen); return send(vde_conn->fddata,buf,len,0); } else return retval; } else return retval; } #else return sendto(vde_conn->fddata,buf,len,0, vde_conn->outsock,vde_conn->outlen); #endif } static int vde_udp_datafd(VDECONN *conn) { struct vde_udp_conn *vde_conn = (struct vde_udp_conn *)conn; return vde_conn->fddata; } static int vde_udp_ctlfd(VDECONN *conn) { return -1; } static int vde_udp_close(VDECONN *conn) { struct vde_udp_conn *vde_conn = (struct vde_udp_conn *)conn; if (vde_conn->outsock != NULL) free(vde_conn->outsock); close(vde_conn->fddata); free(vde_conn); return 0; } vdeplug4-4.0.1/libvdeplug4/libvdeplug_vde.c000066400000000000000000000233511374136421200206350ustar00rootroot00000000000000/* * libvdeplug - A library to connect to a VDE Switch. * Copyright (C) 2013-2017 Renzo Davoli, University of Bologna * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation version 2.1 of the License, or (at * your option) any later version. * * This 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 Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libvdeplug_mod.h" static VDECONN *vde_vde_open(char *given_vde_url, char *descr, int interface_version, struct vde_open_args *open_args); static ssize_t vde_vde_recv(VDECONN *conn, void *buf, size_t len, int flags); static ssize_t vde_vde_send(VDECONN *conn, const void *buf, size_t len, int flags); static int vde_vde_datafd(VDECONN *conn); static int vde_vde_ctlfd(VDECONN *conn); static int vde_vde_close(VDECONN *conn); struct vdeplug_module vdeplug_ops={ .vde_open_real=vde_vde_open, .vde_recv=vde_vde_recv, .vde_send=vde_vde_send, .vde_datafd=vde_vde_datafd, .vde_ctlfd=vde_vde_ctlfd, .vde_close=vde_vde_close}; struct vde_vde_conn { void *hadle; struct vdeplug_module *module; int fdctl; int fddata; }; /* Fallback names for the control socket, NULL-terminated array of absolute * filenames. */ static const char *fallback_vde_url[] = { "/var/run/vde.ctl", "/tmp/vde.ctl", NULL, }; /* Fallback directories for the data socket, NULL-terminated array of absolute * directory names, with no trailing /. */ static const char *fallback_dirname[] = { "/var/run", "/var/tmp", "/tmp", NULL, }; #define SWITCH_MAGIC 0xfeedface enum request_type { REQ_NEW_CONTROL, REQ_NEW_PORT0 }; struct request_v3 { uint32_t magic; uint32_t version; enum request_type type; struct sockaddr_un sock; char description[MAXDESCR]; } __attribute__((packed)); /* return value: -1=error; 0=portgroup socket okay; 1=connected to generic "ctl" port */ static int try2connect(int fdctl, const char *url, char *portgroup, int port, struct sockaddr_un *ctlsock) { int res = -1; memset(ctlsock, 0, sizeof(*ctlsock)); ctlsock->sun_family = AF_UNIX; if (portgroup) { snprintf(ctlsock->sun_path, sizeof(ctlsock->sun_path), "%s/%s", url, portgroup); res = connect(fdctl, (struct sockaddr *) ctlsock, sizeof(*ctlsock)); } if (res < 0 || port != 0) { snprintf(ctlsock->sun_path, sizeof(ctlsock->sun_path), "%s/ctl", url); res = connect(fdctl, (struct sockaddr *) ctlsock, sizeof(*ctlsock)); if (res == 0) res = 1; } return res; } static VDECONN *vde_vde_open(char *given_vde_url, char *descr,int interface_version, struct vde_open_args *open_args) { struct request_v3 req; int port=0; char *portgroup=NULL; char str_lenofint = snprintf(NULL, 0, "%d ", INT_MIN); // # of char to store a int char numeric_portgroup[str_lenofint]; char *group=NULL; char *modestr=NULL; mode_t mode=0700; char real_vde_url[PATH_MAX]; int fdctl=-1; int fddata=-1; struct sockaddr_un sockun; struct sockaddr_un datasock; const char *vde_url=NULL; int res; int pid=getpid(); int sockno=0; struct vde_vde_conn *newconn; struct vdeparms parms[] = {{"", &portgroup}, {"port", &portgroup}, {"portgroup", &portgroup}, {"group", &group}, {"mode", &modestr}, {NULL, NULL}}; if (open_args != NULL) { if (interface_version == 1) { port=open_args->port; group=open_args->group; mode=open_args->mode; } else { errno=EINVAL; goto abort; } } if (vde_parsepathparms(given_vde_url, parms) < 0) { errno=EINVAL; goto abort; } if (modestr) mode = strtol(modestr, NULL, 8); /* Canonicalize the sockname: we need to send an absolute pathname to the * switch (we don't know its cwd) for the data socket. Appending * given_sockname to getcwd() would be enough, but we could end up with a * name longer than PATH_MAX that couldn't be used as sun_path. */ if (*given_vde_url && realpath(given_vde_url, real_vde_url) == NULL) goto abort; vde_url=real_vde_url; /* if port is given as a open_arg, convert it to portgroup */ if ((portgroup == NULL || *portgroup == 0) && port != 0) { snprintf(numeric_portgroup, str_lenofint, "%d", port < 0 ? 0 : port); portgroup = numeric_portgroup; } else if (portgroup != NULL && isdigit(*portgroup)) { /* else if portgroup is a number, convert it to port (and override port) */ char *endptr; int portgroup2port = strtol(portgroup, &endptr, 10); if (*endptr == 0) { port = portgroup2port; if (port == 0) port = -1; } } /* connection to a vde_switch */ if((fdctl = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) < 0) goto abort; if((fddata = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0)) < 0) goto abort; /* If we're given a vde_url, just try it (remember: vde_url is the * canonicalized version of given_vde_url - though we don't strictly need * the canonicalized version here). vde_url should be the name of a * *directory* which contains the control socket, named ctl. Older * versions of VDE used a socket instead of a directory (so an additional * attempt with %s instead of %s/ctl could be made), but they should * really not be used anymore. */ if (*given_vde_url) res = try2connect(fdctl, vde_url, portgroup, port, &sockun); /* Else try all the fallback vde_url, one by one */ else { int i; for (i = 0, res = -1; fallback_vde_url[i] && (res < 0); i++) { vde_url = fallback_vde_url[i]; res = try2connect(fdctl, vde_url, portgroup, port, &sockun); } } if (res < 0) goto abort; req.magic=SWITCH_MAGIC; req.version=3; req.type = REQ_NEW_CONTROL; /* bw compatibility, port embedded on type if connected to ctl */ if (res > 0 && port != 0) { if (port < 0) req.type = REQ_NEW_PORT0; else req.type=req.type+(port << 8); } strncpy(req.description, descr, MAXDESCR); datasock.sun_family = AF_UNIX; memset(datasock.sun_path, 0, sizeof(datasock.sun_path)); do { /* Here vde_url is the last successful one in the previous step. */ snprintf(datasock.sun_path, sizeof(datasock.sun_path), "%s/.%05d-%05d", vde_url, pid, sockno++); res=bind(fddata, (struct sockaddr *) &datasock, sizeof (datasock)); } while (res < 0 && errno == EADDRINUSE); /* It didn't work. So we cycle on the fallback directories until we find a * suitable one (or the list ends). */ if (res < 0) { int i; for (i = 0, res = -1, sockno = 0; fallback_dirname[i] && (res != 0); i++) { memset(datasock.sun_path, 0, sizeof(datasock.sun_path)); do { sprintf(datasock.sun_path, "%s/vde.%05d-%05d", fallback_dirname[i], pid, sockno++); res = bind(fddata, (struct sockaddr *) &datasock, sizeof (datasock)); } while (res < 0 && errno == EADDRINUSE); } } /* Nothing worked, so cleanup and return with an error. */ if (res < 0) goto abort; if (group) { struct group *gs; gid_t gid; if ((gs=getgrnam(group)) == NULL) gid=atoi(group); else gid=gs->gr_gid; if (chown(datasock.sun_path, -1, gid) < 0) goto abort_deletesock; } else { /* when group is not defined, set permission for the reverse channel */ struct stat ctlstat; /* if no permission gets "voluntarily" granted to the socket */ if ((mode & 077) == 0) { if (stat(sockun.sun_path, &ctlstat) == 0) { /* if the switch is owned by root or by the same user it should work 0700 */ if (ctlstat.st_uid != 0 && ctlstat.st_uid != geteuid()) { /* try to change the group ownership to the same of the switch */ /* this call succeeds if the vde user and the owner of the switch belong to the group */ if (chown(datasock.sun_path, -1, ctlstat.st_gid) == 0) mode |= 070; else mode |= 077; } } } } chmod(datasock.sun_path, mode); req.sock = datasock; if (send(fdctl, &req, sizeof(req) - MAXDESCR + strlen(req.description), 0) < 0) goto abort_deletesock; if (recv(fdctl, &datasock, sizeof(struct sockaddr_un), 0) <= 0) goto abort_deletesock; if (connect(fddata, (struct sockaddr *)&datasock, sizeof(struct sockaddr_un)) < 0) goto abort_deletesock; chmod(datasock.sun_path, mode); if ((newconn=calloc(1, sizeof(struct vde_vde_conn)))==NULL) { errno=ENOMEM; goto abort_deletesock; } newconn->fdctl=fdctl; newconn->fddata=fddata; unlink(req.sock.sun_path); return (VDECONN *)newconn; abort_deletesock: unlink(req.sock.sun_path); abort: if (fdctl >= 0) close(fdctl); if (fddata >= 0) close(fddata); return NULL; } static ssize_t vde_vde_recv(VDECONN *conn, void *buf, size_t len, int flags) { struct vde_vde_conn *vde_conn = (struct vde_vde_conn *)conn; return recv(vde_conn->fddata, buf, len, 0); } static ssize_t vde_vde_send(VDECONN *conn, const void *buf, size_t len, int flags) { struct vde_vde_conn *vde_conn = (struct vde_vde_conn *)conn; return send(vde_conn->fddata, buf, len, 0); } static int vde_vde_datafd(VDECONN *conn) { struct vde_vde_conn *vde_conn = (struct vde_vde_conn *)conn; return vde_conn->fddata; } static int vde_vde_ctlfd(VDECONN *conn) { struct vde_vde_conn *vde_conn = (struct vde_vde_conn *)conn; return vde_conn->fdctl; } static int vde_vde_close(VDECONN *conn) { struct vde_vde_conn *vde_conn = (struct vde_vde_conn *)conn; close(vde_conn->fddata); close(vde_conn->fdctl); free(vde_conn); return 0; } vdeplug4-4.0.1/libvdeplug4/libvdeplug_vxlan.c000066400000000000000000000300311374136421200212000ustar00rootroot00000000000000/* * VDE - libvdeplug_vx modules * Copyright (C) 2014-2016 Renzo Davoli VirtualSquare * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation version 2.1 of the License, or (at * your option) any later version. * * This 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 Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libvdeplug_mod.h" #define DEFADDRV4 "239.0.0.1" #define DEFADDRV6 "ff05:56de::1" #define STDPORTSTR "4789" #define STDTTLSTR "1" #define STDVNISTR "1" #define STDHASHSIZE 1024 #define STDEXPIRETIME 128 #define ETH_ALEN 6 #define ETH_HEADER_SIZE 14 #define IS_BROADCAST(addr) ((addr[0] & 1) == 1) #define ntoh24(p) (((p)[0] << 16) | ((p)[1] << 8) | ((p)[2])) #define hton24(p, v) { \ p[0] = (((v) >> 16) & 0xFF); \ p[1] = (((v) >> 8) & 0xFF); \ p[2] = ((v) & 0xFF); \ } struct eth_hdr { unsigned char dest[ETH_ALEN]; unsigned char src[ETH_ALEN]; unsigned char proto[2]; }; struct vxlan_hdr { unsigned char flags; unsigned char priv1[3]; unsigned char id[3]; unsigned char priv2[1]; }; static VDECONN *vde_vxlan_open(char *given_vde_url, char *descr,int interface_version, struct vde_open_args *open_args); static ssize_t vde_vxlan_recv(VDECONN *conn,void *buf,size_t len,int flags); static ssize_t vde_vxlan_send(VDECONN *conn,const void *buf,size_t len,int flags); static int vde_vxlan_datafd(VDECONN *conn); static int vde_vxlan_ctlfd(VDECONN *conn); static int vde_vxlan_close(VDECONN *conn); union sockaddr46 { struct sockaddr vx; struct sockaddr_in v4; struct sockaddr_in6 v6; }; struct vde_vxlan_conn { void *handle; struct vdeplug_module *module; struct vde_hashtable *table; int vni; union sockaddr46 multiaddr; in_port_t multiport; int multifd; int expiretime; }; struct vdeplug_module vdeplug_ops={ .vde_open_real=vde_vxlan_open, .vde_recv=vde_vxlan_recv, .vde_send=vde_vxlan_send, .vde_datafd=vde_vxlan_datafd, .vde_ctlfd=vde_vxlan_ctlfd, .vde_close=vde_vxlan_close }; static inline socklen_t fam2socklen(void *sockaddr) { struct sockaddr *s=sockaddr; switch (s->sa_family) { case AF_INET: return sizeof(struct sockaddr_in); case AF_INET6: return sizeof(struct sockaddr_in6); default: return 0; } } static inline void setport(void *sockaddr, in_port_t port) { struct sockaddr *s=sockaddr; switch (s->sa_family) { case AF_INET: ((struct sockaddr_in *) s)->sin_port = port; return; case AF_INET6: ((struct sockaddr_in6 *) s)->sin6_port = port; return; } } static VDECONN *vde_vxlan_open(char *vde_url, char *descr,int interface_version, struct vde_open_args *open_args) { struct vde_vxlan_conn *newconn; struct addrinfo hints; struct addrinfo *result,*rp; int s; unsigned int hashsize = STDHASHSIZE; char *portstr = STDPORTSTR; char *vnistr = STDVNISTR; char *ttlstr = STDTTLSTR; char *rcvbufstr = NULL; char *v6str = NULL; char *v4str = NULL; char *hashsizestr = NULL; char *expiretimestr = NULL; char *ifstr = NULL; struct vdeparms parms[] = { {"port",&portstr}, {"vni",&vnistr}, {"ttl",&ttlstr}, {"rcvbuf",&rcvbufstr}, {"v6",&v6str}, {"v4",&v4str}, {"hashsize",&hashsizestr}, {"expiretime",&expiretimestr}, {"if",&ifstr}, {NULL, NULL}}; struct sockaddr *multiaddr=NULL; int multifd=-1; int ttl; in_port_t multiport; unsigned int ifindex = 0; memset(&hints, 0, sizeof(struct addrinfo)); /* Allow IPv4 or IPv6 if either none or both options v4/v6 were selected*/ switch (((!!v6str) << 1) | (!!v4str)) { case 0: hints.ai_family = AF_UNSPEC; break; case 1: hints.ai_family = AF_INET; break; case 2: hints.ai_family = AF_INET6; break; case 3: hints.ai_family = AF_UNSPEC; break; } hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ hints.ai_protocol = 0; /* Any protocol */ if (vde_parseparms(vde_url, parms) != 0) return NULL; ttl = atoi(ttlstr); if (*vde_url == 0) vde_url = v6str != NULL ? DEFADDRV6 : DEFADDRV4; if (ifstr != NULL) ifindex = if_nametoindex(ifstr); s = getaddrinfo(vde_url, portstr, &hints, &result); if (s < 0) { fprintf(stderr, "vxlan getaddrinfo: %s\n", gai_strerror(s)); errno=ENOENT; return NULL; } for (rp = result; rp != NULL && multifd < 0; rp = rp->ai_next) { switch (rp->ai_family) { case AF_INET6: { struct sockaddr_in6 *addr=(struct sockaddr_in6 *)(rp->ai_addr); struct ipv6_mreq mc_req; multiaddr = (struct sockaddr *) addr; struct sockaddr_in6 bindaddr; int loop = 0; if ((multifd=socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP)) < 0) goto error; if (rcvbufstr) { unsigned int rcvbuf = strtoullm(rcvbufstr); if ((setsockopt(multifd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf))) < 0) goto error; } if ((setsockopt(multifd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl))) < 0) goto error; if ((setsockopt(multifd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop, sizeof(loop))) < 0) goto error; /* bind to in6addr_any to receive both unicast and multicast */ memset(&bindaddr, 0, sizeof(bindaddr)); bindaddr.sin6_family = AF_INET6; memcpy(&bindaddr.sin6_addr, &in6addr_any, sizeof(in6addr_any)); bindaddr.sin6_port = multiport = addr->sin6_port; if ((bind(multifd, (struct sockaddr *) &bindaddr, sizeof(bindaddr))) < 0) { close(multifd); multifd=-1; continue; } memcpy(&mc_req.ipv6mr_multiaddr, &addr->sin6_addr, sizeof(addr->sin6_addr)); mc_req.ipv6mr_interface = ifindex; if ((setsockopt(multifd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mc_req, sizeof(mc_req))) < 0) goto error; if (ifindex > 0) { if ((setsockopt(multifd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex))) < 0) goto error; } break; } case AF_INET: { struct sockaddr_in *addr=(struct sockaddr_in *)(rp->ai_addr); struct ip_mreqn mc_req; multiaddr = (struct sockaddr *) addr; struct sockaddr_in bindaddr; int loop = 0; if ((multifd=socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP)) < 0) goto error; if (rcvbufstr) { unsigned int rcvbuf = strtoullm(rcvbufstr); if ((setsockopt(multifd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf))) < 0) goto error; } if ((setsockopt(multifd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl))) < 0) goto error; if ((setsockopt(multifd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop))) < 0) goto error; memset(&bindaddr, 0, sizeof(bindaddr)); bindaddr.sin_family = AF_INET; bindaddr.sin_addr.s_addr = htonl(INADDR_ANY); bindaddr.sin_port = multiport = addr->sin_port; if ((bind(multifd, (struct sockaddr *) &bindaddr, sizeof(bindaddr))) < 0) { close(multifd); multifd=-1; continue; } mc_req.imr_multiaddr.s_addr = addr->sin_addr.s_addr; mc_req.imr_address.s_addr = htonl(INADDR_ANY); mc_req.imr_ifindex = ifindex; if ((setsockopt(multifd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mc_req, sizeof(mc_req))) < 0) goto error; if (ifindex > 0) { mc_req.imr_multiaddr.s_addr = htonl(INADDR_ANY); mc_req.imr_address.s_addr = htonl(INADDR_ANY); mc_req.imr_ifindex = ifindex; if ((setsockopt(multifd, IPPROTO_IP, IP_MULTICAST_IF, &mc_req, sizeof(mc_req))) < 0) goto error; } break; } } } if (multifd < 0) { errno = ENETUNREACH; goto error; } if ((newconn=calloc(1,sizeof(struct vde_vxlan_conn)))==NULL) { errno = ENOMEM; goto error; } if (hashsizestr != NULL) hashsize = atoi(hashsizestr); switch (multiaddr->sa_family) { case AF_INET6: newconn->table = vde_hash_init(struct sockaddr_in6 , hashsize, 0); break; case AF_INET: newconn->table = vde_hash_init(struct sockaddr_in , hashsize, 0); break; default: newconn->table = NULL; break; } newconn->vni=atoi(vnistr); if (expiretimestr != NULL) { newconn->expiretime = atoi(expiretimestr); if (newconn->expiretime <= 0) newconn->expiretime = STDEXPIRETIME; } else newconn->expiretime = STDEXPIRETIME; memcpy(&(newconn->multiaddr.vx), multiaddr, fam2socklen(multiaddr)); newconn->multiport = multiport; newconn->multifd = multifd; freeaddrinfo(result); return (VDECONN *) newconn; error: freeaddrinfo(result); if (multifd >= 0) close(multifd); if (newconn != NULL) free(newconn); return NULL; } static ssize_t vde_vxlan_recv(VDECONN *conn,void *buf,size_t len,int flags) { struct vde_vxlan_conn *vde_conn = (struct vde_vxlan_conn *)conn; struct vxlan_hdr vhdr; struct iovec iov[]={{&vhdr, sizeof(vhdr)},{buf, len}}; struct msghdr msg; struct sockaddr_in6 sender; ssize_t retval; msg.msg_name=&sender; msg.msg_namelen = fam2socklen(msg.msg_name); msg.msg_iov=iov; msg.msg_iovlen=2; msg.msg_control=NULL; msg.msg_controllen=0; msg.msg_flags=0; retval=recvmsg(vde_conn->multifd, &msg, 0)-sizeof(struct vxlan_hdr); if (__builtin_expect((retval > ETH_HEADER_SIZE), 1)) { struct eth_hdr *ehdr=(struct eth_hdr *) buf; if (vhdr.flags != (1 << 3) || ntoh24(vhdr.id) != vde_conn->vni) goto error; /* VXLAN always sends packets to the multicast port */ setport(msg.msg_name, vde_conn->multiport); vde_find_in_hash_update(vde_conn->table, ehdr->src, 1, msg.msg_name, time(NULL)); return retval; } error: errno = EAGAIN; *((unsigned char *)buf)=0; return 1; } static ssize_t vde_vxlan_send(VDECONN *conn,const void *buf, size_t len,int flags) { struct vde_vxlan_conn *vde_conn = (struct vde_vxlan_conn *)conn; struct vxlan_hdr vhdr; struct iovec iov[]={{&vhdr, sizeof(vhdr)},{(char *)buf, len}}; struct sockaddr *destaddr; static struct msghdr msg; ssize_t retval; msg.msg_iov=iov; msg.msg_iovlen=2; struct eth_hdr *ehdr=(struct eth_hdr *) buf; if (len < ETH_HEADER_SIZE) return len; // discard packets shorter than an ethernet header if (IS_BROADCAST(ehdr->dest) || (destaddr = vde_find_in_hash(vde_conn->table, ehdr->dest, 1, time(NULL)- vde_conn->expiretime)) == NULL) /* MULTICAST */ msg.msg_name = &(vde_conn->multiaddr.vx); else /* UNICAST */ msg.msg_name = destaddr; msg.msg_namelen = fam2socklen(msg.msg_name); memset(&vhdr, 0, sizeof(vhdr)); vhdr.flags = (1 << 3); hton24(vhdr.id, vde_conn->vni); if ((retval=sendmsg(vde_conn->multifd, &msg, 0)) < 0) return -1; retval -= sizeof(struct vxlan_hdr); if (retval < 0) retval = 0; return retval; } static int vde_vxlan_datafd(VDECONN *conn) { struct vde_vxlan_conn *vde_conn = (struct vde_vxlan_conn *)conn; return vde_conn->multifd; } static int vde_vxlan_ctlfd(VDECONN *conn) { return -1; } static int vde_vxlan_close(VDECONN *conn) { struct vde_vxlan_conn *vde_conn = (struct vde_vxlan_conn *)conn; close(vde_conn->multifd); vde_hash_fini(vde_conn->table); free(vde_conn); return 0; } vdeplug4-4.0.1/libvdeplug4/libvdeplug_vxvde.c000066400000000000000000000462421374136421200212170ustar00rootroot00000000000000/* * VDE - libvdeplug_vx modules * Copyright (C) 2016 Renzo Davoli VirtualSquare * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation version 2.1 of the License, or (at * your option) any later version. * * This 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 Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #include #define __USE_GNU #include #include #include #include #include #include "libvdeplug_mod.h" /* two alternatives to check whether an ip addr is local: LOCALBIND: try to open and bind a socket to the same addr (any port), if it succeeds it is local! !LOCALBIND: use getifaddrs and look through the list */ //#define LOCALBIND #ifndef LOCALBIND #include #endif //#define DEBUGADDR #define DEFADDRV4 "239.0.0.1" #define DEFADDRV6 "ff05:56de::1" #define STDPORTSTR "14789" #define STDTTLSTR "1" #define STDVNI 1 #define STDHASHSIZE 1024 #define STDEXPIRETIME 128 #define ETH_ALEN 6 #define ETH_HEADER_SIZE 14 #define IS_BROADCAST(addr) ((addr[0] & 1) == 1) #define ntoh24(p) (((p)[0] << 16) | ((p)[1] << 8) | ((p)[2])) #define hton24(p, v) { \ p[0] = (((v) >> 16) & 0xFF); \ p[1] = (((v) >> 8) & 0xFF); \ p[2] = ((v) & 0xFF); \ } struct eth_hdr { unsigned char dest[ETH_ALEN]; unsigned char src[ETH_ALEN]; unsigned char proto[2]; }; struct vxvde_hdr { unsigned char flags; unsigned char priv1[3]; unsigned char id[3]; unsigned char priv2[1]; }; static VDECONN *vde_vxvde_open(char *vde_url, char *descr,int interface_version, struct vde_open_args *open_args); static ssize_t vde_vxvde_recv(VDECONN *conn,void *buf,size_t len,int flags); static ssize_t vde_vxvde_send(VDECONN *conn,const void *buf,size_t len,int flags); static int vde_vxvde_datafd(VDECONN *conn); static int vde_vxvde_ctlfd(VDECONN *conn); static int vde_vxvde_close(VDECONN *conn); union sockaddr46 { struct sockaddr vx; struct sockaddr_in v4; struct sockaddr_in6 v6; }; struct vde_vxvde_conn { void *handle; struct vdeplug_module *module; struct vde_hashtable *table; union { struct vxvde_hdr connhdr; uint64_t connhdr64; }; union sockaddr46 multiaddr; union sockaddr46 localaddr; in_port_t uniport; int multifd; int unifd; int pollfd; int expiretime; }; struct vdeplug_module vdeplug_ops={ .vde_open_real=vde_vxvde_open, .vde_recv=vde_vxvde_recv, .vde_send=vde_vxvde_send, .vde_datafd=vde_vxvde_datafd, .vde_ctlfd=vde_vxvde_ctlfd, .vde_close=vde_vxvde_close }; static inline socklen_t fam2socklen(void *sockaddr) { struct sockaddr *s=sockaddr; switch (s->sa_family) { case AF_INET: return sizeof(struct sockaddr_in); case AF_INET6: return sizeof(struct sockaddr_in6); default: return 0; } } static inline void grpsetaddr(gid_t gid, void *addr, size_t len) { if (gid != -1) { unsigned char *s = addr; s[--len] = gid; s[--len] = gid >> 8; s[--len] = gid >> 16; } } static int is_a_localaddr(void *sockaddr) { struct sockaddr *s=sockaddr; int retval=0; #ifdef LOCALBIND switch (s->sa_family) { case AF_INET: { int tmpfd=socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP); if (tmpfd >= 0) { struct sockaddr_in s4=*((struct sockaddr_in *)s); s4.sin_port = 0; if (bind(tmpfd, (struct sockaddr *) &s4, sizeof(s4))==0) retval=1; close(tmpfd); } } break; case AF_INET6: { int tmpfd=socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP); if (tmpfd >= 0) { struct sockaddr_in6 s6=*((struct sockaddr_in6 *)s); s6.sin6_port = 0; if (bind(tmpfd, (struct sockaddr *) &s6, sizeof(s6))==0) retval=1; close(tmpfd); } } break; } #else /* GETIFADDRS */ struct ifaddrs *addrs; if (getifaddrs(&addrs) == 0) { struct ifaddrs *ifa; for (ifa = addrs; ifa != NULL && retval == 0; ifa = ifa->ifa_next){ if (s->sa_family == ifa->ifa_addr->sa_family) { switch (s->sa_family) { case AF_INET: { struct sockaddr_in *s6=(struct sockaddr_in *)s; struct sockaddr_in *i6=(struct sockaddr_in *)ifa->ifa_addr; if (s6->sin_addr.s_addr == i6->sin_addr.s_addr) retval=1; } break; case AF_INET6: { struct sockaddr_in6 *s6=(struct sockaddr_in6 *)s; struct sockaddr_in6 *i6=(struct sockaddr_in6 *)ifa->ifa_addr; if (memcmp(&s6->sin6_addr,&i6->sin6_addr,sizeof(struct in6_addr)) == 0) retval=1; } break; } } } freeifaddrs(addrs); } #endif return retval; } #ifdef DEBUGADDR static inline void printaddr(char *msg, void *sockaddr) { struct sockaddr *s=sockaddr; struct sockaddr_in *s4=sockaddr; struct sockaddr_in6 *s6=sockaddr; char saddr[INET6_ADDRSTRLEN]; switch (s->sa_family) { case AF_INET: fprintf(stderr,"%s %s\n",msg,inet_ntop(AF_INET, &s4->sin_addr, saddr, sizeof(*s4))); break; case AF_INET6: fprintf(stderr,"%s %s\n",msg,inet_ntop(AF_INET6, &s6->sin6_addr, saddr, sizeof(*s6))); break; default: fprintf(stderr,"%s UNKNOWN FAMILY %d\n",msg,s->sa_family); break; } } #endif static int getbindaddr(const char *bindstr, int family, void *addr) { int s; struct addrinfo hints; struct addrinfo *result; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = family; hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = AI_PASSIVE; s = getaddrinfo(bindstr, "0", &hints, &result); if (s == 0) { memcpy(addr, result->ai_addr, result->ai_addrlen); freeaddrinfo(result); } return s; } static VDECONN *vde_vxvde_open(char *vde_url, char *descr,int interface_version, struct vde_open_args *open_args) { struct vde_vxvde_conn *newconn=NULL; struct addrinfo hints; struct addrinfo *result,*rp; int s; unsigned int hashsize = STDHASHSIZE; char *portstr = STDPORTSTR; char *vnistr = NULL; char *grpstr = NULL; char *ttlstr = STDTTLSTR; char *rcvbufstr = NULL; char *v6str = NULL; char *v4str = NULL; char *hashsizestr = NULL; char *expiretimestr = NULL; char *ifstr = NULL; char *bindstr = NULL; struct vdeparms parms[] = { {"port",&portstr}, {"vni",&vnistr}, {"grp",&grpstr}, {"ttl",&ttlstr}, {"rcvbuf",&rcvbufstr}, {"v6",&v6str}, {"v4",&v4str}, {"hashsize",&hashsizestr}, {"expiretime",&expiretimestr}, {"if",&ifstr}, {"bind",&bindstr}, {NULL, NULL}}; struct sockaddr *multiaddr = NULL; int multifd=-1; int unifd=-1; int pollfd=-1; gid_t vni; gid_t grp; int ttl; in_port_t uniport; unsigned int ifindex = 0; if (vde_parseparms(vde_url, parms) != 0) return NULL; memset(&hints, 0, sizeof(struct addrinfo)); /* Allow IPv4 or IPv6 if either none or both options v4/v6 were selected*/ switch (((!!v6str) << 1) | (!!v4str)) { case 0: hints.ai_family = AF_UNSPEC; break; case 1: hints.ai_family = AF_INET; break; case 2: hints.ai_family = AF_INET6; break; case 3: hints.ai_family = AF_UNSPEC; break; } hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ hints.ai_protocol = 0; /* Any protocol */ ttl = atoi(ttlstr); vni = vde_grnam2gid(vnistr); grp = vde_grnam2gid(grpstr); if (vni == -1) vni = grp == -1 ? STDVNI : grp; if (*vde_url == 0) vde_url = v6str != NULL ? DEFADDRV6 : DEFADDRV4; if (ifstr != NULL) ifindex = if_nametoindex(ifstr); s = getaddrinfo(vde_url, portstr, &hints, &result); if (s < 0) { fprintf(stderr, "vxvde getaddrinfo: %s\n", gai_strerror(s)); errno=ENOENT; return NULL; } for (rp = result; rp != NULL && multifd < 0; rp = rp->ai_next) { switch (rp->ai_family) { case AF_INET6: { struct sockaddr_in6 *addr=(struct sockaddr_in6 *)(rp->ai_addr); struct ipv6_mreq mc_req; struct sockaddr_in6 bindaddr; socklen_t bindaddrlen; int one = 1; multiaddr = (struct sockaddr *) addr; if ((multifd=socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP)) < 0) goto error; if ((unifd=socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP)) < 0) goto error; if (rcvbufstr) { unsigned int rcvbuf = strtoullm(rcvbufstr); if ((setsockopt(unifd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf))) < 0) goto error; } if ((setsockopt(unifd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl))) < 0) goto error; if ((setsockopt(multifd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one))) < 0) goto error; #ifdef SO_REUSEADDR if ((setsockopt(multifd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) < 0) goto error; #endif grpsetaddr(grp, &addr->sin6_addr, sizeof(addr->sin6_addr)); if ((bind(multifd, (struct sockaddr *) addr, sizeof(*addr))) < 0) { close(multifd); close(unifd); multifd=unifd=-1; continue; } memcpy(&mc_req.ipv6mr_multiaddr, &addr->sin6_addr, sizeof(addr->sin6_addr)); mc_req.ipv6mr_interface = ifindex; if ((setsockopt(multifd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mc_req, sizeof(mc_req))) < 0) goto error; if (getbindaddr(bindstr, AF_INET6, &bindaddr) != 0) { errno = ENOENT; goto error; } if ((bind(unifd, (struct sockaddr *) &bindaddr, sizeof(bindaddr))) < 0) { close(multifd); close(unifd); multifd=unifd=-1; continue; } if (ifindex > 0) { if ((setsockopt(unifd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex))) < 0) goto error; } bindaddrlen=sizeof(bindaddr); if (getsockname(unifd, (struct sockaddr *) &bindaddr, &bindaddrlen) < 0) goto error; uniport=bindaddr.sin6_port; } break; case AF_INET: { struct sockaddr_in *addr=(struct sockaddr_in *)(rp->ai_addr); struct ip_mreqn mc_req; struct sockaddr_in bindaddr; socklen_t bindaddrlen; int one = 1; multiaddr = (struct sockaddr *) addr; if ((multifd=socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP)) < 0) goto error; if ((unifd=socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP)) < 0) goto error; if (rcvbufstr) { unsigned int rcvbuf = strtoullm(rcvbufstr); if ((setsockopt(unifd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf))) < 0) goto error; } if ((setsockopt(unifd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl))) < 0) goto error; if ((setsockopt(unifd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl))) < 0) goto error; if ((setsockopt(multifd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one))) < 0) goto error; #ifdef SO_REUSEADDR if ((setsockopt(multifd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) < 0) goto error; #endif grpsetaddr(grp, &addr->sin_addr, sizeof(addr->sin_addr)); if ((bind(multifd, (struct sockaddr *) addr, sizeof(*addr))) < 0) { close(multifd); close(unifd); multifd=unifd=-1; continue; } mc_req.imr_multiaddr.s_addr = addr->sin_addr.s_addr; mc_req.imr_address.s_addr = htonl(INADDR_ANY); mc_req.imr_ifindex = ifindex; if ((setsockopt(multifd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mc_req, sizeof(mc_req))) < 0) goto error; if (getbindaddr(bindstr, AF_INET, &bindaddr) != 0) { errno = ENOENT; goto error; } if ((bind(unifd, (struct sockaddr *) &bindaddr, sizeof(bindaddr))) < 0) { close(multifd); close(unifd); multifd=unifd=-1; continue; } if (ifindex > 0) { mc_req.imr_multiaddr.s_addr = htonl(INADDR_ANY); mc_req.imr_address.s_addr = htonl(INADDR_ANY); mc_req.imr_ifindex = ifindex; if ((setsockopt(unifd, IPPROTO_IP, IP_MULTICAST_IF, &mc_req, sizeof(mc_req))) < 0) goto error; } bindaddrlen=sizeof(bindaddr); if (getsockname(unifd, (struct sockaddr *) &bindaddr, &bindaddrlen) < 0) goto error; uniport=bindaddr.sin_port; //fprintf(stderr,"local port %d\n",ntohs(bindaddr.sin_port)); } break; } } if (multifd < 0) { errno = ENETUNREACH; goto error; } if ((pollfd = epoll_create1(EPOLL_CLOEXEC)) < 0) { goto error; } else { struct epoll_event ev; ev.events = EPOLLIN; ev.data.fd = multifd; if (epoll_ctl(pollfd, EPOLL_CTL_ADD, multifd, &ev) < 0) goto error; ev.data.fd = unifd; if (epoll_ctl(pollfd, EPOLL_CTL_ADD, unifd, &ev) < 0) goto error; } if ((newconn=calloc(1,sizeof(struct vde_vxvde_conn)))==NULL) { errno = ENOMEM; goto error; } if (hashsizestr != NULL) hashsize = atoi(hashsizestr); switch (multiaddr->sa_family) { case AF_INET6: newconn->table = vde_hash_init(struct sockaddr_in6 , hashsize, 0); break; case AF_INET: newconn->table = vde_hash_init(struct sockaddr_in , hashsize, 0); break; default: newconn->table = NULL; break; } memset(&newconn->connhdr, 0, sizeof(struct vxvde_hdr)); newconn->connhdr.flags = (1 << 3); hton24(newconn->connhdr.id, vni); if (expiretimestr != NULL) { newconn->expiretime = atoi(expiretimestr); if (newconn->expiretime <= 0) newconn->expiretime=STDEXPIRETIME; } else newconn->expiretime=STDEXPIRETIME; memcpy(&(newconn->multiaddr.vx), multiaddr, fam2socklen(multiaddr)); memcpy(&(newconn->localaddr.vx), multiaddr, fam2socklen(multiaddr)); newconn->multifd=multifd; newconn->unifd=unifd; newconn->uniport=uniport; newconn->pollfd=pollfd; freeaddrinfo(result); return (VDECONN *) newconn; error: if (multifd >= 0) close(multifd); if (unifd >= 0) close(unifd); if (pollfd >= 0) close(pollfd); if (newconn != NULL) free(newconn); freeaddrinfo(result); return NULL; } static ssize_t vde_vxvde_recv(VDECONN *conn,void *buf,size_t len,int flags) { struct vde_vxvde_conn *vde_conn = (struct vde_vxvde_conn *)conn; struct epoll_event events[1]; int nfd = epoll_wait(vde_conn->pollfd, events, 1, -1); if (nfd > 0) { uint64_t vhdr64; struct iovec iov[]={{&vhdr64, sizeof(vhdr64)},{buf, len}}; struct sockaddr_storage sender; char cmsg[CMSG_SPACE(sizeof(struct in6_pktinfo)+sizeof(struct in_pktinfo))]; struct msghdr msg={ .msg_name=&sender, .msg_namelen=sizeof(sender), .msg_iov=iov, .msg_iovlen=2, .msg_control=cmsg, .msg_controllen=sizeof(cmsg), .msg_flags=0}; ssize_t retval=recvmsg(events[0].data.fd, &msg, 0)-sizeof(struct vxvde_hdr); if (__builtin_expect((retval > ETH_HEADER_SIZE), 1)) { struct eth_hdr *ehdr=(struct eth_hdr *) buf; if (vhdr64 != vde_conn->connhdr64) { //fprintf(stderr,"wrong net id or flags: rejected \n"); goto error; } if (events[0].data.fd == vde_conn->multifd) { switch (sender.ss_family) { case AF_INET: { struct sockaddr_in *sender4=(struct sockaddr_in *)&sender; if (sender4->sin_port == vde_conn->uniport) { struct cmsghdr *cmsgptr=CMSG_FIRSTHDR(&msg); struct in_pktinfo *pki=(struct in_pktinfo *)(CMSG_DATA(cmsgptr)); if (sender4->sin_addr.s_addr == pki->ipi_spec_dst.s_addr) { //fprintf(stderr,"self packet, rejected \n"); goto error; } } } break; case AF_INET6: { /* workaround: there is not (yet) an ancillary msg for IPv6 returning the IP address of the local interface where the packet was received, i.e. the IPV6 counterpart of ipi_spec_dst */ struct sockaddr_in6 *sender6=(struct sockaddr_in6 *)&sender; if (sender6->sin6_port == vde_conn->uniport) { if (memcmp(&sender6->sin6_addr, &vde_conn->localaddr.v6.sin6_addr, sizeof(struct in6_addr)) == 0) { //fprintf(stderr,"self packet short path, rejected \n"); goto error; } else if (is_a_localaddr(sender6)) { memcpy(&vde_conn->localaddr, sender6, sizeof(struct sockaddr_in6)); //fprintf(stderr,"self packet long path, rejected \n"); goto error; } } } break; } } vde_find_in_hash_update(vde_conn->table, ehdr->src, 1, msg.msg_name, time(NULL)); return retval; } else if (retval == 0) { if (vhdr64 == vde_conn->connhdr64) vde_hash_delete(vde_conn->table, msg.msg_name); } } error: errno = EAGAIN; return 1; } static ssize_t vde_vxvde_send(VDECONN *conn,const void *buf, size_t len,int flags) { struct vde_vxvde_conn *vde_conn = (struct vde_vxvde_conn *)conn; struct eth_hdr *ehdr=(struct eth_hdr *) buf; ssize_t retval; struct iovec iov[]={{&vde_conn->connhdr, sizeof(struct vxvde_hdr)},{(char *)buf, len}}; struct msghdr msg={ .msg_iov=iov, .msg_iovlen=2, .msg_control = NULL, .msg_controllen = 0, .msg_flags = 0}; if (len < ETH_HEADER_SIZE) return len; // discard packets shorter than an ethernet header if (__builtin_expect( (IS_BROADCAST(ehdr->dest) || (msg.msg_name = vde_find_in_hash(vde_conn->table, ehdr->dest, 1, time(NULL)- vde_conn->expiretime)) == NULL), 0)) { msg.msg_name=&(vde_conn->multiaddr.vx); //printaddr("send multi",destaddr); } msg.msg_namelen = fam2socklen(msg.msg_name); if ((retval=sendmsg(vde_conn->unifd, &msg, 0)) < 0) return -1; retval -= sizeof(struct vxvde_hdr); if (retval < 0) retval = 0; return retval; } static int vde_vxvde_datafd(VDECONN *conn) { struct vde_vxvde_conn *vde_conn = (struct vde_vxvde_conn *)conn; return vde_conn->pollfd; } static int vde_vxvde_ctlfd(VDECONN *conn) { return -1; } static int vde_vxvde_close(VDECONN *conn) { struct vde_vxvde_conn *vde_conn = (struct vde_vxvde_conn *)conn; sendto(vde_conn->unifd, &vde_conn->connhdr, sizeof(struct vxvde_hdr), 0, &vde_conn->multiaddr.vx, fam2socklen(&vde_conn->multiaddr.vx)); close(vde_conn->unifd); close(vde_conn->multifd); vde_hash_fini(vde_conn->table); free(vde_conn); return 0; } vdeplug4-4.0.1/libvdeplug4/libvdestream.c000066400000000000000000000072361374136421200203270ustar00rootroot00000000000000/* * libvdeplug - A library to connect to a VDE Switch. * Copyright (C) 2013 Renzo Davoli, University of Bologna * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation version 2.1 of the License, or (at * your option) any later version. * * This 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 Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #define MAXPACKET (VDE_ETHBUFSIZE + 2) #ifndef MIN #define MIN(X,Y) (((X)<(Y))?(X):(Y)) #endif struct vdestream { void *opaque; int fdout; ssize_t (*frecv)(void *opaque, void *buf, size_t count); void (*ferr)(void *opaque, int type, char *format, ...); char fragment[MAXPACKET]; char *fragp; unsigned int rnx,remaining; }; VDESTREAM *vdestream_open(void *opaque, int fdout, ssize_t (*frecv)(void *opaque, void *buf, size_t count), void (*ferr)(void *opaque, int type, char *format, ...) ) { VDESTREAM *vdestream; if ((vdestream=calloc(1,sizeof(struct vdestream)))==NULL) { errno=ENOMEM; return NULL; } else { vdestream->opaque=opaque; vdestream->fdout=fdout; vdestream->frecv=frecv; vdestream->ferr=ferr; return vdestream; } } ssize_t vdestream_send(VDESTREAM *vdestream, const void *buf, size_t len) { if (len <= MAXPACKET) { unsigned char header[2]; struct iovec iov[2]={{header,2},{(void *)buf,len}}; header[0]=len >> 8; header[1]=len & 0xff; return writev(vdestream->fdout,iov,2); } else return 0; } void vdestream_recv(VDESTREAM *vdestream, unsigned char *buf, size_t len) { //fprintf(stderr,"%s: splitpacket rnx=%d remaining=%d size=%d\n",myname,rnx,vdestream->remaining,len); if (len==0) return; if (vdestream->rnx>0) { register int amount=MIN(vdestream->remaining,len); //fprintf(stderr,"%s: fragment amount %d\n",myname,amount); memcpy(vdestream->fragp,buf,amount); vdestream->remaining-=amount; vdestream->fragp+=amount; buf+=amount; len-=amount; if (vdestream->remaining==0) { //fprintf(stderr,"%s: delivered defrag %d\n",myname,vdestream->rnx); vdestream->frecv(vdestream->opaque,vdestream->fragment,vdestream->rnx); vdestream->rnx=0; } } while (len > 1) { vdestream->rnx=(buf[0]<<8)+buf[1]; len-=2; //fprintf(stderr,"%s %d: packet %d size %d %x %x\n",myname,getpid(),vdestream->rnx,len,buf[0],buf[1]); buf+=2; if (vdestream->rnx == 0) continue; if (vdestream->rnx > MAXPACKET) { if (vdestream->ferr != NULL) vdestream->ferr(vdestream->opaque,PACKET_LENGTH_ERROR, "size %d expected size %d",len,vdestream->rnx); vdestream->rnx=0; return; } if (vdestream->rnx > len) { //fprintf(stderr,"%s: begin defrag %d\n",myname,vdestream->rnx); vdestream->fragp=vdestream->fragment; memcpy(vdestream->fragp,buf,len); vdestream->remaining=vdestream->rnx-len; vdestream->fragp+=len; len=0; } else { //fprintf(stderr,"%s: deliver %d\n",myname,vdestream->rnx); vdestream->frecv(vdestream->opaque,buf,vdestream->rnx); buf+=vdestream->rnx; len-=vdestream->rnx; vdestream->rnx=0; } } } void vdestream_close(VDESTREAM *vdestream) { free(vdestream); } vdeplug4-4.0.1/libvdeplug4/parseparms.c000066400000000000000000000161671374136421200200260ustar00rootroot00000000000000/* * Copyright (C) 2016 Renzo Davoli, University of Bologna * * parse parameters for vdeplug modules. * * VDE is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; If not, see . * */ #include #include #include #include #include #include #include #include #include #include #if 0 // defined in libvdeplug_mod.h. struct vdeparms { char *tag; char **value; }; #endif static inline int isnumber(const char *s) { while (1) { if (!isdigit(*s++)) return 0; /* an empty string is *not* a number */ if (*s == 0) return 1; } } unsigned long long strtoullm(const char *numstr) { char *tail; unsigned long long rval = strtoull(numstr, &tail, 0); for (; *tail; tail++) { switch (*tail) { case 'k': case 'K': rval *= 1ULL<<10; break; case 'm': case 'M': rval *= 1ULL<<20; break; case 'g': case 'G': rval *= 1ULL<<30; break; case 't': case 'T': rval *= 1ULL<<40; break; } } return rval; } gid_t vde_grnam2gid(const char *name) { if (name) { if (*name == 0) return getegid(); else if (isnumber(name)) return atoi(name); else { struct group grp; struct group *rgrp; size_t buflen = sysconf(_SC_GETGR_R_SIZE_MAX); char buf[buflen]; getgrnam_r(name, &grp, buf, buflen, &rgrp); return rgrp ? grp.gr_gid : -1; } } return -1; } #define CHAR 0 #define QUOTE 1 #define DOUBLEQ 2 #define ESC 3 #define PERC 4 #define PER2 5 #define DELIM 6 #define END 7 #define TSIZE (END + 1) #define COPY 1 #define CPER 3 static char nextstate[TSIZE - 1][TSIZE] = { {CHAR, QUOTE, DOUBLEQ, ESC, PERC, 0, DELIM, END}, {QUOTE, CHAR, QUOTE, QUOTE, QUOTE, 0, QUOTE, END}, {DOUBLEQ, DOUBLEQ, CHAR, DOUBLEQ, DOUBLEQ, 0, DOUBLEQ, END}, {CHAR, CHAR, CHAR, CHAR, CHAR, 0, CHAR, END}, {PER2, QUOTE, DOUBLEQ, ESC, PERC, 0, DELIM, END}, {CHAR, QUOTE, DOUBLEQ, ESC, PERC, 0, DELIM, END}, {CHAR, QUOTE, DOUBLEQ, ESC, PERC, 0, DELIM, END}, }; static char action[TSIZE - 2][TSIZE] = { {COPY, 0, 0, 0, COPY, 0, 0, 0}, //char {COPY, 0, COPY, COPY, COPY, 0, COPY, 0}, //quote {COPY, COPY, 0, COPY, COPY, 0, COPY, 0}, //doubleq {COPY, COPY, COPY, COPY, COPY, 0, COPY, 0}, //esc {COPY, 0, 0, 0, COPY, 0, 0, 0}, //perc {CPER, 0, 0, 0, COPY, 0, 0, 0}, //per2 }; static const char *hexchars = "0123456789ABCDEF0123456789abcdef"; static inline int ch2n(char x) { char *n = strchr(hexchars, x); return n ? (n - hexchars) % 16 : -1; } static int token(char c, const char *delim) { int this; switch (c) { case 0: this = END; break; case '\'': this = QUOTE; break; case '\"': this = DOUBLEQ; break; case '\\': this = ESC; break; case '%': this = PERC; break; default: this = strchr(delim, c) == NULL ? CHAR : DELIM; } return this; } /* like strtok_r(3) + this function supports quoting with ' " and char protection \ */ static char *strtokq_r(char *s, const char *delim, char **saveptr) { char *begin, *from, *to; int status = CHAR; begin = from = to = (s == NULL) ? *saveptr : s; if (from == NULL) return NULL; while (status != DELIM && status != END) { int this = token(*from, delim); int todo = action[status][this]; // printf("%c %d -> %d\n", *from, status, nextstate[status][this]); if (todo & COPY) { *to = *from; if (todo == CPER) { char *perc = to - 2; int hex1 = ch2n(perc[1]); int hex2 = ch2n(perc[2]); if (hex1 >= 0 && hex2 >= 0) { *perc = hex1 * 0x10 + hex2; to = perc; } } to++; } from++; status = nextstate[status][this]; } *to = 0; *saveptr = (status == END) ? NULL : from; return begin; } static char *strtokq_nostrip_r(char *s, const char *delim, char **saveptr) { char *begin, *from, *to; int status = CHAR; begin = from = to = (s == NULL) ? *saveptr : s; if (from == NULL) return NULL; while (status != DELIM && status != END) { int this = token(*from, delim); if (this != DELIM) to++; from++; status = nextstate[status][this]; } *to = 0; *saveptr = (status == END) ? NULL : from; return begin; } /* this function splits the token using the last (non quoted) occurence of the delimiter */ static char *strtokq_rev_r(char *s, const char *delim) { char *begin, *scan, *to; int status = CHAR; scan = begin = s; to = NULL; if (scan == NULL) return NULL; for (;status != END; scan++) { int this = token(*scan, delim); status = nextstate[status][this]; if (status == DELIM) to = scan; } if (to != NULL) *to = 0; return begin; } int vde_parseparms(char *str, struct vdeparms *parms){ if (*str != 0) { char *sp; char *elem; elem = strtokq_r(str, "/", &sp); while((elem = strtokq_r(NULL, "/", &sp)) != NULL) { char *eq = strchr(elem, '='); int taglen=eq ? eq-elem : strlen(elem); if (taglen > 0) { struct vdeparms *scan; for (scan = parms; scan->tag; scan++) { if (strncmp(elem, scan->tag, taglen) == 0) { *(scan->value)=eq ? eq+1 : ""; break; } } if (scan->tag == NULL) { fprintf(stderr, "unknwown key: %*.*s\n", taglen, taglen, elem); errno = EINVAL; return -1; } } } } return 0; } int vde_parsepathparms(char *str, struct vdeparms *parms){ if (*str != 0) { char *sp; char *elem; char *bracket; elem = strtokq_r(str, "[", &sp); for (bracket = strtokq_rev_r(sp, "]"); (elem = strtokq_r(bracket, "/", &sp)) != NULL; bracket = NULL) { char *eq = strchr(elem, '='); int taglen=eq ? eq-elem : strlen(elem); if (taglen > 0) { struct vdeparms *scan; for (scan = parms; scan->tag; scan++) { if (strncmp(elem, scan->tag, taglen) == 0) { *(scan->value)=eq ? eq+1 : ""; break; } } if (scan->tag == NULL) { if (eq == NULL && parms->tag != NULL && parms->tag[0] == 0) *(parms->value) = elem; else { fprintf(stderr, "unknwown key: %*.*s\n", taglen, taglen, elem); errno = EINVAL; return -1; } } } } } return 0; } char *vde_parsenestparms(char *str){ if (*str != 0) { char *sp; char *bracket; strtokq_nostrip_r(str, "{", &sp); bracket = strtokq_rev_r(sp, "}"); return bracket; } return NULL; } #if 0 int main(int argc, char *argv[]) { char *portstr="12345"; char *vnistr="1"; char *ttlstr="1"; struct vdeparms parms[] = {{"port", &portstr}, {"vni", &vnistr}, {"ttl", &ttlstr}, {NULL, NULL}}; printf("%s\n", argv[1]); vde_parseparms(argv[1], parms); printf("%s\n", argv[1]); struct vdeparms *scan; for (scan = parms; scan->tag; scan++) printf("%s %s\n", scan->tag, *(scan->value)); } #endif vdeplug4-4.0.1/libvdeplug4/vde_hashtable.c000066400000000000000000000067741374136421200204450ustar00rootroot00000000000000#include #include #include #include #include #include struct vde_hashtable { size_t payload_size; unsigned int hash_mask; uint64_t seed; /* plus the table here */ char ht[]; }; struct ht_elem { uint64_t edst; time_t last_seen; char payload[]; }; #define sizeof_ht_elem(payload_size) (sizeof(struct ht_elem) + payload_size) static inline __attribute__((always_inline)) struct ht_elem *ht_get(struct vde_hashtable *table, int index) { return (void *) (table->ht + index * sizeof_ht_elem(table->payload_size)); } static inline __attribute__((always_inline)) int calc_hash(uint64_t src, unsigned int hash_mask, uint64_t seed) { src ^= src >> 33 ^ seed; src *= 0xff51afd7ed558ccd; src ^= src >> 33; src *= 0xc4ceb9fe1a85ec53; src ^= src >> 33; return src & hash_mask; } #define extmac(MAC,VLAN) \ ((*(uint32_t *) &((MAC)[0])) + ((uint64_t) ((*(uint16_t *) &((MAC)[4]))+ ((uint64_t) (VLAN) << 16)) << 32)) /* look in global hash table for given address, and return associated address */ void *vde_find_in_hash(struct vde_hashtable *table, unsigned char *dst, int vlan, time_t too_old) { if (__builtin_expect(table == NULL, 0)) return NULL; else { uint64_t edst; int index; struct ht_elem *entry; if ((dst[0] & 1) == 1) /* broadcast */ return NULL; edst = extmac(dst,vlan); index = calc_hash(edst, table->hash_mask, table->seed); //printf("index %d\n",index); entry = ht_get(table, index); if (entry->edst == edst && entry->last_seen >= too_old) return &(entry->payload); else return NULL; } } void vde_find_in_hash_update(struct vde_hashtable *table, unsigned char *src, int vlan, void *payload, time_t now) { if (__builtin_expect(table == NULL, 0)) return; else { uint64_t esrc; int index; struct ht_elem *entry; if ((src[0] & 1) == 1) /* broadcast */ return; esrc = extmac(src,vlan); index = calc_hash(esrc, table->hash_mask, table->seed); //printf("index %d\n",index); entry = ht_get(table, index); entry->edst = esrc; memcpy(&(entry->payload),payload,table->payload_size); entry->last_seen = now; } } void vde_hash_delete(struct vde_hashtable *table, void *payload) { if (__builtin_expect(table == NULL, 0)) return; else { unsigned int i; for (i = 0; i < table->hash_mask + 1; i++) { struct ht_elem *entry = ht_get(table, i); if (memcmp(entry->payload, payload, table->payload_size) == 0) entry->last_seen = 0; } } } // #define vde_hash_init(type, hash_mask, seed) _vde_hash_init(sizeof(type), (hash_mask), (seed)) struct vde_hashtable *_vde_hash_init(size_t payload_size, unsigned int hashsize, uint64_t seed) { struct vde_hashtable *retval; if (hashsize == 0) return NULL; hashsize = (2 << (sizeof(hashsize) * 8 - __builtin_clz(hashsize - 1) - 1)); retval = calloc(1, sizeof(struct vde_hashtable) + hashsize * sizeof_ht_elem(payload_size)); if (retval) { retval->payload_size = payload_size; retval->hash_mask = hashsize - 1; retval->seed = seed; } return retval; } void vde_hash_fini(struct vde_hashtable *table) { free(table); } #if 0 int main() { struct vde_hashtable *ht = vde_hash_init(int, 15, 0); while(1) { unsigned char mac[7]; unsigned int port; scanf("%6s %u",mac,&port); printf("%s %d \n",mac,port); if (port == 0) { int *pport = vde_find_in_hash(ht, mac, 0, time(NULL)-20); if (pport) printf("-> %d\n", *pport); else printf("-> not found\n"); } else vde_find_in_hash_update(ht, mac, 0, &port, time(NULL)); } } #endif vdeplug4-4.0.1/libvdeplug4_static/000077500000000000000000000000001374136421200170415ustar00rootroot00000000000000vdeplug4-4.0.1/libvdeplug4_static/CMakeLists.txt000066400000000000000000000003761374136421200216070ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.13) add_library(libvdeplug_a STATIC libvdeplug.c) set_target_properties(libvdeplug_a PROPERTIES OUTPUT_NAME vdeplug) install( TARGETS libvdeplug_a ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) vdeplug4-4.0.1/libvdeplug4_static/libvdeplug.c000066400000000000000000000123401374136421200213420ustar00rootroot00000000000000/* * libvdeplug - A library to connect to a VDE Switch. * static library (using vde_plug as a helper) * Copyright (C) 2019 Renzo Davoli, University of Bologna * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation version 2.1 of the License, or (at * your option) any later version. * * This 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 Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include struct vdeconn { int fddata; }; /* enough char to store an int type */ #define ENOUGH(type) ((CHAR_BIT * sizeof(type) - 1) / 3 + 2) #define ENOUGH_OCTAL(type) ((CHAR_BIT * sizeof(type) + 2) / 3) /* vde_plug --descr xx --port2 xx --mod2 xx --group2 xx seqpacket://NN vdeurl (NULL) */ #define VDE_MAX_ARGC 12 #define SEQPACKET_HEAD "seqpacket://" #define SEQPACKET_HEAD_LEN (sizeof(SEQPACKET_HEAD) - 1) #define DEFAULT_DESCRIPTION "libvdeplug" #define CHILDSTACKSIZE 4096 #define err_goto(err, label) do { \ (err) = errno; \ goto label; \ } while(0) struct child_data { char **argv; int fd; }; static int child(void *arg) { struct child_data *data = arg; int err; execvp(data->argv[0], data->argv); err = errno; write(data->fd, &err, sizeof(err)); close(data->fd); return 0; } VDECONN *vde_open_real(char *given_vde_url, char *descr,int interface_version, struct vde_open_args *open_args) { int sv[2]; struct vdeconn *conn; char *description = (descr != NULL && *descr != 0) ? descr : DEFAULT_DESCRIPTION; char *vde_url = (given_vde_url == NULL) ? "" : given_vde_url; char seqpacketurl[SEQPACKET_HEAD_LEN + ENOUGH(int) + 1] = SEQPACKET_HEAD; char port_str[ENOUGH(int) + 1]; char mode_str[ENOUGH_OCTAL(mode_t) + 2]; char *argv[VDE_MAX_ARGC] = {"vde_plug", "--descr", description, seqpacketurl, vde_url, NULL}; int argc = 3; int rv, err; struct child_data data; char childstack[CHILDSTACKSIZE]; int fds[2]; int pid; if (open_args != NULL) { if (open_args->port != 0) { snprintf(port_str, ENOUGH(int) + 1, "%d", open_args->port); argv[argc++] = "--port2"; argv[argc++] = port_str; } if (open_args->group != 0) { argv[argc++] = "--group2"; argv[argc++] = open_args->group; } if (open_args->mode != 0) { snprintf(mode_str, ENOUGH_OCTAL(mode_t) + 2, "0%o", open_args->mode); argv[argc++] = "--mod2"; argv[argc++] = mode_str; } } argv[argc++] = seqpacketurl; argv[argc++] = vde_url; argv[argc++] = NULL; /* synch socketpair: fds[0] is for the parent, fds[1] is close_on_exec inherited by the child */ rv = socketpair(AF_UNIX, SOCK_STREAM, 0, fds); if (rv < 0) err_goto(err, leave); data.argv = argv; data.fd = fds[1]; rv = fcntl(fds[1], F_SETFD, FD_CLOEXEC); if (rv < 0) err_goto(err, close_fds); /* This socketpair is for vde packets: sv[0] is for the parent (e.g. User-Mode Linux) sv[1] is forthe helper command (vde_plug) */ rv = socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sv); if (rv < 0) err_goto(err, close_fds); rv = fcntl(sv[0], F_SETFD, FD_CLOEXEC); if (rv < 0) err_goto(err, close_sv); conn = (VDECONN *) malloc(sizeof(VDECONN)); if (conn == NULL) err_goto(err, close_sv); snprintf(seqpacketurl + SEQPACKET_HEAD_LEN, SEQPACKET_HEAD_LEN, "%d", sv[1]); /* use clone instead of fork. User-mode linux cannot fork */ pid = clone(child, (void *) (childstack + CHILDSTACKSIZE), CLONE_VM, &data); if (pid < 0) err_goto(err, free_conn); /* close the descriptors used by the child */ close(fds[1]); close(sv[1]); conn->fddata = sv[0]; /* wait for child's execvp */ rv = read(fds[0], &err, sizeof(err)); close(fds[0]); if (rv > 0) { close(sv[0]); free(conn); errno = err; return NULL; } else return conn; free_conn: free(conn); close_sv: close(sv[0]); close(sv[1]); close_fds: close(fds[0]); close(fds[1]); leave: errno = err; return NULL; } ssize_t vde_recv(VDECONN *conn,void *buf,size_t len,int flags) { if (__builtin_expect(conn!=0,1)) return recv(conn->fddata,buf,len,0); else { errno=EBADF; return -1; } } ssize_t vde_send(VDECONN *conn,const void *buf,size_t len,int flags) { if (__builtin_expect(conn!=0,1)) { /* never send zero length packets */ if (__builtin_expect(len > 0, 1)) return send(conn->fddata,buf,len,0); else return len; } else { errno=EBADF; return -1; } } int vde_datafd(VDECONN *conn) { if (__builtin_expect(conn!=0,1)) return conn->fddata; else { errno=EBADF; return -1; } } int vde_ctlfd(VDECONN *conn) { return -1; } int vde_close(VDECONN *conn) { if (__builtin_expect(conn!=0,1)) { return close(conn->fddata); } else { errno=EBADF; return -1; } } vdeplug4-4.0.1/man/000077500000000000000000000000001374136421200140245ustar00rootroot00000000000000vdeplug4-4.0.1/man/CMakeLists.txt000066400000000000000000000020071374136421200165630ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.7) set(RONN_ORGANIZATION "VirtualSquare") set(RONN_ARGS --organization=${RONN_ORGANIZATION}) # #ronn pages file(GLOB VU_RONN_PAGES ${CMAKE_CURRENT_SOURCE_DIR}/*.[1-8].ronn) set(VU_MAN_FILES) foreach(VU_RONN_PATH IN LISTS VU_RONN_PAGES) # VU_RONNPAGE: basename of VU_RONN_PATH get_filename_component(VU_RONNPAGE ${VU_RONN_PATH} NAME) # VU_MANPAGE: VU_RONNPAGE without the suffix string(REGEX REPLACE "\.ronn$" "" VU_MANPAGE ${VU_RONNPAGE}) list(APPEND VU_MAN_FILES ${VU_MANPAGE}) endforeach(VU_RONN_PATH) add_custom_target(${PROJECT_NAME}_manpages ALL make RONN_ARGS="${RONN_ARGS}" ${VU_MAN_FILES} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) ### man pages file(GLOB VU_MAN_PAGES ${CMAKE_CURRENT_SOURCE_DIR}/*.[1-8]) foreach(VU_MAN_PATH IN LISTS VU_MAN_PAGES) get_filename_component(VU_MANPAGE ${VU_MAN_PATH} NAME) string(REGEX REPLACE ".*\\." "" MAN_CHAPTER ${VU_MANPAGE}) install(FILES ${VU_MAN_PATH} DESTINATION ${CMAKE_INSTALL_MANDIR}/man${MAN_CHAPTER}) endforeach(VU_MAN_PATH) vdeplug4-4.0.1/man/Makefile000066400000000000000000000005551374136421200154710ustar00rootroot00000000000000RONN=ronn RONNOK := $(shell command -v ${RONN} 2> /dev/null) none: % : %.ronn ifdef RONNOK # copy copyright notice grep "^\.\\\\\"" $< > $@ || true # run ronn $(RONN) -r ${RONN_ARGS} --pipe $< >> $@ # delete useless trailing "" in .TH sed -i '/^\.TH /s/ ""$$//' $@ else echo "${RONN} is not available. Manpage $@ cannot be updated" >/dev/stderr >&2 endif vdeplug4-4.0.1/man/dpipe.1000066400000000000000000000063151374136421200152140ustar00rootroot00000000000000.TH DPIPE 1 "August 23, 2016" "Virtual Distributed Ethernet" .SH NAME dpipe \- bi-directional pipe command .SH SYNOPSIS .B dpipe [ .I OPTIONS ] .I command [ .I args ] .BI = .I command [ .I args ] [ .BI = [ .I command [ .I args ] ] ] \&... .br .SH DESCRIPTION \fBdpipe\fP is a general tool to run two commands diverting the standard output of the first command into the standard input of the second and vice-versa. It is the bi-directional extension of the \fB|\fP (pipe) syntax used by all the shells. The \fB=\fP has been chosen as a metaphor of two parallel communication lines between the commands. It is also possible to concatenate several tools. Intermediate programs communicate using standard input and standard output with the preceding tool and alternate standard input and output towards the following tool. The number of the file descriptors is use as alternate standard input and output can be retrieved from the envirnonment variables ALTERNATE_STDIN and ALTERNATE_STDOUT using \fBgetenv(3)\fR or \fBgetenv(1)\fR. If an intermediate tool should process only the data flowing in one direction use \fB{\fP or \fB}\fP as suffix for the preceding \fB=\fP and prefix of the following one. .br This tool has been written as a tool for the Virtual Distributed Ethernet. .SH OPTIONS .B dpipe accepts the following options: .TP \fB\-n .TQ \fB\-\-nowrapproc create only one process per command, the last one being the parent of all the others (the standard behavior of dpipe is to create a process for dpipe and all the processes running the commands are children of dpipe). .TP \fB\-d .TQ \fB\-\-daemon run as a daemon. .TP \fB\-p\fR \fIPIDFILE .TQ \fB\-\-pidfile\fR \fIPIDFILE write the process id of the dpipe process (or the id of the last command if \fB-r\fR) to the file \fIPIDFILE\fR .TP \fB\-P\fR \fIPGRPFILE .TQ \fB\-\-pgrpfile\fR \fIPGRPFILE write the process group id (negative) including all the processes launched by dpipe to the file \fIPGRPFILE\fR .TP \fB\-N .TQ \fB\-\-nowrapnoclean Like -n but it does not remove PIDFILE or PGRPFILE. (when \fB-n\fR is used together with \fB-p\fR or \fB-P\fR, dpipe creates a cleanup process to wait for the processes to terminate and remove the files. \fB-N\fR avoids the creation of the cleanup process) .SH EXAMPLES .B dpipe a = b .br processes a and b are bidirectionally connected: stdin of a is connected to stdout of b and vice-versa .br .B dpipe a = b = c .br a and b are connected as above. Alternate stdin of b is connected to stdout of c and alternate stdout of b to stdin of c .br .B dpipe a =} b }= c .br This is a cycle of pipes: stdout of a is connected to stdin of b, stdout of b with stdin of c, and stdout of c to stdin of a .br .B dpipe a =} b }={ c {= d = e .br all the notations can be mixed together. this is a -> b -> d -> c and back to a; alternate ports of d are connected to e .SH NOTICE Virtual Distributed Ethernet is not related in any way with www.vde.com ("Verband der Elektrotechnik, Elektronik und Informationstechnik" i.e. the German "Association for Electrical, Electronic & Information Technologies"). .SH SEE ALSO \fBvde_switch\fP(1), \fBvde_plug\fP(1), \fBvde_plug2tap\fP(1), \fBvdeq\fP(1). \fBwirefilter\fP(1). .br .SH AUTHOR VDE is a project by Renzo Davoli . vdeplug4-4.0.1/man/libvdeplug.3000066400000000000000000000106561374136421200162550ustar00rootroot00000000000000.\"* libvdeplug: a network namespace as a user library .\" Copyright (C) 2017 Renzo Davoli. University of Bologna. .\" .\" This library is free software; you can redistribute it and/or .\" modify it under the terms of the GNU Lesser General Public .\" License as published by the Free Software Foundation; either .\" version 2.1 of the License, or (at your option) any later version. .\" .\" This 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 .\" Lesser General Public License for more details. .\" .\" You should have received a copy of the GNU Lesser General Public .\" License along with this library; if not, write to the Free Software .\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA .TH libvdeplug 3 2017-05-21 "VirtualSquare" "Linux Programmer's Manual" .SH NAME vde_open, vde_recv, vde_send, vde_send, vde_recv, vde_close \- connect clients to a VDE (virtual distributed ethernet) network .SH SYNOPSIS .B #include .br .BI "VDECONN *vde_open(char *vde_url,char *descr, struct vde_open_args *open_args);" .br .BI "ssize_t vde_recv(VDECONN *conn,void *buf,size_t len,int flags);" .br .BI "ssize_t vde_send(VDECONN *conn,const void *buf,size_t len,int flags);" .br .BI "int vde_datafd(VDECONN *conn);" .br .BI "int vde_ctlfd(VDECONN *conn);" .br .BI "int vde_close(VDECONN *conn);" .sp These functions are provided by libvdeplug. Link with \fI-lvdeplug\fR. .SH DESCRIPTION Libvdeplug is the library used by clients to join a VDE network. It is a generic library which can use several different implementations for virtual distributed networks. In fact \fIvde_url\fR has the syntax \fImodule\fB://\fIspecific_address\fR. e.g. \fBvde:///home/user/myswitch\fR or \fBvxvde://239.0.0.1\fR. The default module is \fBlibvdeplug_vde(1)\fR (connection to a \fBvde_switch(1)\fR) and can be omitted. e.g. \fB/home/user/myswitch\fR means \fBvde:///home/user/myswitch\fR \fBvde_open\fR opens a VDE connection: \fIvde_url\fR is the vde network identifier as described here above and \fIdescr\fR is a description of this connection (it can be useful to identify this connection in the port list of a switch). \fRopen_args\fR has been left for backwards compatibility but can be safely set to NULL as all the options previosly defined as fields of \fIstruct vde_open_args\fR are now parameters of the VDE modules (can be defined using a module specific syntax in vde_url). \fBvde_recv\fR receives a packet from the VDE connection. \fBvde_send\fR sends a packet to the VDE connection. \fBvde_datafd\fR returns the data file descriptor of the connection: this descriptor can be used in \fBpoll(2)\fR or \fBselect(2)\fR (or similar) system calls. When this descriptor signals data available for reading \fBvde_recv\fR will not block. \fBvde_ctlfd\fR returns the control file descriptor of the connection. Not all the modules support control descritors, but when it is valid descriptor (greater or equal than 0) can be used to check if the remote endpoint (switch or peer) hanged up. No data can be sent or received using the control file descriptor, it returns an end-of-file condition when the connection get closed (zero length on reading). \fBvde_close\fR closes a vde connections. .SH RETURN VALUE \fBvde_open\fR returns the descriptor of the VDE connection which is used as a parameter of all the other functions. NULL is returned in case of error. \fBvde_recv\fR returns the length of the packet received. It should never be less then 14 bytes (the length of an ethernet header). It returns -1 in case of error, it may return 1 to notify that a packet has been received but it must be dropped (e.g. the sender was not allowed to send that packet). \fBvde_send\fR returns the number of bytes sent. It returns -1 in case of error. \fBvde_datafd\fR and \fBvde_ctlfd\fR returns a file descriptor and -1 in case of error. \fBvde_datafd\fR returns 0 in case of success and -1 in case of error. .SH NOTICE Virtual Distributed Ethernet is not related in any way with www.vde.com ("Verband der Elektrotechnik, Elektronik und Informationstechnik" i.e. the German "Association for Electrical, Electronic & Information Technologies"). .SH SEE ALSO \fBvde_plug\fR(1), \fBvde_switch\fR(1) .SH BUGS Bug reports should be addressed to .SH AUTHOR Renzo Davoli vdeplug4-4.0.1/man/libvdeplug_bonding.1000066400000000000000000000051561374136421200177520ustar00rootroot00000000000000.TH LIBVDEPLUG_BONDING 1 "April 30, 2017" "Virtual Distributed Ethernet" .SH NAME libvdeplug_bonding - multiplexing vdeplug module: bonding links .SH SYNOPSIS libvdeplug_bonding.so .SH DESCRIPTION This is a libvdeplug multiplex module implementing the bonding of multiple links. The common usage of this module is to support multiple links between virtual machines or switches. This module transmit packets on all the available links in a round-robin manner. If the links use several paths and channels it is possible to reach a higher bandwidth. This module of libvdeplug4 can be used in any program supporting vde like \fBvde_plug\fR, \fBkvm\fR, \fBqemu\fR, \fBuser-mode-linux\fR and \fBvirtualbox\fR. The vde_plug_url syntax of this module is the following: .RS .B bonding://\fR[\fIpath\fR] .br .B bonding://\fR[\fIpath\fR]\fB[\fR[\fIOPTION\fR][\fB/\fIOPTION\fR][\fB/\fIOPTION\fR]...\fB] .br .RE If \fIpath\fR is omitted the path of the bonding is /tmp/vdenode_$USERNAME (e.g. /tmp/vdenode_john if the username is john). .SH OPTIONS .TP \fBmode=\fR\fIMODE define the permissions for the bonding node (see chmod). MODE is an octal number. The standard permission mask is: 0600 (only processes owning to the same user can join the network). .TP \fBdirmode=\fR\fIDIRMODE define the permissions for the bonding node control directory(see chmod). MODE is an octal number. If omitted, is computed from mode. .TP \fBgrp=\fR\fIGROUP define the group ownership of the bonding node. .SH EXAMPLES .B bonding:///tmp/bonding .br Other virtual machines, namespaces or vde_plug can join this bondinglink using \fBvde:///tmp/hub\fR or simply \fB/tmp/hub\fR .br Given two virtual machines using \fBbonding:///tmp/vm1\fR and \fBbonding:///tmp/vm2\fR respectively, it is possible to connect them using \fBvde_plug /tmp/vm1 /tmp/vm2\fR. If the second virtual machine is running on a remote hosts; \fBip1.vm2.domain.org\fR and \fBip2.vm2.domain.org\fR are two ip addresses permitting to reach that remote host using different paths, the commands \fBvde_plug /tmp/vm1 = ssh ip1.vm2.domain.org vde_plug /tmp/vm2\fR and \fBvde_plug /tmp/vm1 = ssh ip2.vm2.domain.org vde_plug /tmp/vm2\fR create two channels between the two virtual machines. Packets are sent in turns on one or the other link. .br .B bonding:///tmp/bonding[mode=0666] .br It is the same bondinglink, but everybody is allowed to connect their processes. .SH NOTICE Virtual Distributed Ethernet is not related in any way with www.vde.com ("Verband der Elektrotechnik, Elektronik und Informationstechnik" i.e. the German "Association for Electrical, Electronic & Information Technologies"). .SH SEE ALSO \fBvde_plug\fP(1), vdeplug4-4.0.1/man/libvdeplug_cmd.1000066400000000000000000000021641374136421200170710ustar00rootroot00000000000000.TH LIBVDEPLUG_VDE 1 "August 23, 2016" "Virtual Distributed Ethernet" .SH NAME libvdeplug_cmd - vdeplug module: stream a VDE network through a command .SH SYNOPSIS libvdeplug_cmd.so .SH DESCRIPTION This is the standard vdeplug module to stream a VDE network using a command. This module of libvdeplug4 can be used in any program supporting vde like \fBvde_plug\fR, \fBkvm\fR, \fBqemu\fR, \fBuser-mode-linux\fR and \fBvirtualbox\fR. The vde_plug_url syntax of this module is the following: .RS .br \fBcmd://\fIcommand\fR .RE .SH EXAMPLES Appropriate shell quoting is needed. .B cmd://"ssh remote.host.org vde_plug vxvde://" .br .B kvm .... -net vde,sock=cmd://"ssh remote.host.org vde_plug vxvde://" ... .br In these cases ssh should have been configured to require no foreground authentication (see how to set up public key authentication: ssh(1) and ssh-keygen(1)). .SH NOTICE Virtual Distributed Ethernet is not related in any way with www.vde.com ("Verband der Elektrotechnik, Elektronik und Informationstechnik" i.e. the German "Association for Electrical, Electronic & Information Technologies"). .SH SEE ALSO \fBvde_plug\fP(1), vdeplug4-4.0.1/man/libvdeplug_hub.1000066400000000000000000000032131374136421200171000ustar00rootroot00000000000000.TH LIBVDEPLUG_HUB 1 "April 30, 2017" "Virtual Distributed Ethernet" .SH NAME libvdeplug_hub - multiplexing vdeplug module: hub .SH SYNOPSIS libvdeplug_hub.so .SH DESCRIPTION This is a libvdeplug multiplex module implementing a virtual networking hub. This module of libvdeplug4 can be used in any program supporting vde like \fBvde_plug\fR, \fBkvm\fR, \fBqemu\fR, \fBuser-mode-linux\fR and \fBvirtualbox\fR. The vde_plug_url syntax of this module is the following: .RS .B hub://\fR[\fIpath\fR] .br .B hub://\fR[\fIpath\fR]\fB[\fR[\fIOPTION\fR][\fB/\fIOPTION\fR][\fB/\fIOPTION\fR]...\fB] .br .RE If \fIpath\fR is omitted the path of the hub is /tmp/vdenode_$USERNAME (e.g. /tmp/vdenode_john if the username is john). .SH OPTIONS .TP \fBmode=\fR\fIMODE define the permissions for the hub (see chmod). MODE is an octal number. The standard permission mask is: 0600 (only processes owning to the same user can join the network). .TP \fBdirmode=\fR\fIDIRMODE define the permissions for the hub control directory(see chmod). MODE is an octal number. If omitted, is computed from mode. .TP \fBgrp=\fR\fIGROUP define the group ownership of the hub. .SH EXAMPLES .B hub:///tmp/hub .br Other virtual machines, namespaces or vde_plug can join this hub using \fBvde:///tmp/hub\fR or simply \fB/tmp/hub\fR .br .B hub:///tmp/hub[mode=0666] .br It is the same hub, but everybody is allowed to connect their processes. .SH NOTICE Virtual Distributed Ethernet is not related in any way with www.vde.com ("Verband der Elektrotechnik, Elektronik und Informationstechnik" i.e. the German "Association for Electrical, Electronic & Information Technologies"). .SH SEE ALSO \fBvde_plug\fP(1), vdeplug4-4.0.1/man/libvdeplug_multi.1000066400000000000000000000054761374136421200174710ustar00rootroot00000000000000.TH LIBVDEPLUG_MULTI 1 "April 30, 2017" "Virtual Distributed Ethernet" .SH NAME libvdeplug_multi - multiplexing vdeplug module: multilink .SH SYNOPSIS libvdeplug_multi.so .SH DESCRIPTION This is a libvdeplug multiplex module implementing a multilink. The common usage of this module is to support (usually temporary) multiple links between virtual machines or switches. This module can be used to implement hand-offs betweek links: a new link can be set-up and then the old one is closed. When both links are active, packets can be duplicated. This module of libvdeplug4 can be used in any program supporting vde like \fBvde_plug\fR, \fBkvm\fR, \fBqemu\fR, \fBuser-mode-linux\fR and \fBvirtualbox\fR. The vde_plug_url syntax of this module is the following: .RS .B multi://\fR[\fIpath\fR] .br .B multi://\fR[\fIpath\fR]\fB[\fR[\fIOPTION\fR][\fB/\fIOPTION\fR][\fB/\fIOPTION\fR]...\fB] .br .RE If \fIpath\fR is omitted the path of the multi is /tmp/vdenode_$USERNAME (e.g. /tmp/vdenode_john if the username is john). .SH OPTIONS .TP \fBmode=\fR\fIMODE define the permissions for the multilink (see chmod). MODE is an octal number. The standard permission mask is: 0600 (only processes owning to the same user can join the network). .TP \fBdirmode=\fR\fIDIRMODE define the permissions for the multilink control directory(see chmod). MODE is an octal number. If omitted, is computed from mode. .TP \fBgrp=\fR\fIGROUP define the group ownership of the multilink. .SH EXAMPLES .B multi:///tmp/multi .br Other virtual machines, namespaces or vde_plug can join this multilink using \fBvde:///tmp/hub\fR or simply \fB/tmp/hub\fR .br Given two virtual machines using \fBmulti:///tmp/vm1\fR and \fBmulti:///tmp/vm2\fR respectively, it is possible to connect them using \fBvde_plug /tmp/vm1 /tmp/vm2\fR. If the second virtual machine is running on a remote hosts; \fBip1.vm2.domain.org\fR and \fBip2.vm2.domain.org\fR are two ip addresses permitting to reach that remote host using different paths, the command \fBvde_plug /tmp/vm1 = ssh ip1.vm2.domain.org vde_plug /tmp/vm2\fR connects the two vms. In a second time is possible to run \fBvde_plug /tmp/vm1 = ssh ip2.vm2.domain.org vde_plug /tmp/vm2\fR to create another channel on the other path. When both connections are in place packets can arrive duplicated (the upper protocols can manage the problem). Then the process connecting the remotevm using \fBip1.vm2.domain.org\fR can be killed, completing in this way the (hiccup-less) handoff. .br .B multi:///tmp/multi[mode=0666] .br It is the same multilink, but everybody is allowed to connect their processes. .SH NOTICE Virtual Distributed Ethernet is not related in any way with www.vde.com ("Verband der Elektrotechnik, Elektronik und Informationstechnik" i.e. the German "Association for Electrical, Electronic & Information Technologies"). .SH SEE ALSO \fBvde_plug\fP(1), vdeplug4-4.0.1/man/libvdeplug_null.1000066400000000000000000000020161374136421200172740ustar00rootroot00000000000000.TH LIBVDEPLUG_NULL 1 "April 30, 2017" "Virtual Distributed Ethernet" .SH NAME libvdeplug_null - network terminator plug .SH SYNOPSIS libvdeplug_null.so .SH DESCRIPTION This is a libvdeplug module implementing a networking sink/terminator. This module of libvdeplug4 can be used in any program supporting vde like \fBvde_plug\fR, \fBkvm\fR, \fBqemu\fR, \fBuser-mode-linux\fR and \fBvirtualbox\fR. The vde_plug_url syntax of this module is the following: .RS .B null:// .br .RE This plug does not generate any networking traffic and all the packets sent to this plug get dropped. .SH EXAMPLES This command creates a switch (without the null plug the command vde_plug adds the stream stdin/stdout as a node of the switch). .B vde_plug null:// switch://tmp/myswitch .br .SH NOTICE Virtual Distributed Ethernet is not related in any way with www.vde.com ("Verband der Elektrotechnik, Elektronik und Informationstechnik" i.e. the German "Association for Electrical, Electronic & Information Technologies"). .SH SEE ALSO \fBvde_plug\fP(1), vdeplug4-4.0.1/man/libvdeplug_ptp.1000066400000000000000000000020471374136421200171310ustar00rootroot00000000000000.TH LIBVDEPLUG_P2P 1 "August 23, 2016" "Virtual Distributed Ethernet" .SH NAME libvdeplug_ptp - vdeplug module for point to point connections .SH SYNOPSIS libvdeplug_ptp.so .SH DESCRIPTION This module interconnects two vde supporting tools by a point to point communication line. This module of libvdeplug4 can be used in any program supporting vde like \fBvde_plug\fR, \fBkvm\fR, \fBqemu\fR, \fBuser-mode-linux\fR and \fBvirtualbox\fR. The vde_plug_url syntax of this module is the following: .RS .br \fBptp://\fIpath_of_the_socket\fR .RE .SH EXAMPLES .B ptp:///tmp/sock .br The same vde_plug_url can be used at both ends of the connection. The first program creates the socket \fB/tmp/sock\fR. The second program connects to \fB/tmp/sock\fR, when it discovers that the socket already exists. .SH NOTICE Virtual Distributed Ethernet is not related in any way with www.vde.com ("Verband der Elektrotechnik, Elektronik und Informationstechnik" i.e. the German "Association for Electrical, Electronic & Information Technologies"). .SH SEE ALSO \fBvde_plug\fP(1), vdeplug4-4.0.1/man/libvdeplug_switch.1000066400000000000000000000047011374136421200176260ustar00rootroot00000000000000.TH LIBVDEPLUG_SWITCH 1 "April 30, 2017" "Virtual Distributed Ethernet" .SH NAME libvdeplug_switch - multiplexing vdeplug module: switch .SH SYNOPSIS libvdeplug_switch.so .SH DESCRIPTION This is a libvdeplug multiplex module implementing a vde switch. This module of libvdeplug4 can be used in any program supporting vde like \fBvde_plug\fR, \fBkvm\fR, \fBqemu\fR, \fBuser-mode-linux\fR and \fBvirtualbox\fR. The vde_plug_url syntax of this module is the following: .RS \fBswitch://\fR[\fIpath\fR] .br \fBswitch://\fR[\fIpath\fR]\fB[\fR[\fIOPTION\fR][\fB/\fIOPTION\fR][\fB/\fIOPTION\fR]...\fB]\fR .br .RE If \fIpath\fR is omitted the path of the switch is /tmp/vdenode_$USERNAME (e.g. /tmp/vdenode_john if the username is john). This switch supports 801.1Q vlan as a trunk switch, i.e. all the VLAN tagged packets are forwarded as such. The forwarding table uses a key including both the MAC address and th VLAN id. .SH OPTIONS .TP \fBhashsize=\fR\fINUM set the size of the forwarding hash table. (default value 256) .TP \fBexpiretime=\fR\fISECONDS set the expire time of the forwarding table entries. (default value 120) .TP \fBhashseed=\fR\fINUM set a hash seed, in case the hash function generates too many collisions. .TP \fBmode=\fR\fIMODE define the permissions for the switch (see chmod). MODE is an octal number. The standard permission mask is: 0600 (only processes owning to the same user can join the network). .TP \fBdirmode=\fR\fIDIRMODE define the permissions for the switch control directory(see chmod). MODE is an octal number. If omitted, is computed from mode. .TP \fBgrp=\fR\fIGROUP define the group ownership of the switch. .SH EXAMPLES .B switch:///tmp/switch .br Other virtual machines, namespaces or vde_plug can join this switch using \fBvde:///tmp/switch\fR or simply \fB/tmp/switch\fR .br .B switch:///tmp/switch[mode=0666/hashsize=1024] .br It is the same switch, but everybody is allowed to connect their processes and the hash table has 1024 entries. .br The null plug can be used to create a stand-alone vde switch: .br .B vde_plug null:// switch:///tmp/myswitch .br The following command creates a switch connected to a tap virtual interface .br .B vde_plug tap://mytap switch:///tmp/myswitch .SH NOTICE Virtual Distributed Ethernet is not related in any way with www.vde.com ("Verband der Elektrotechnik, Elektronik und Informationstechnik" i.e. the German "Association for Electrical, Electronic & Information Technologies"). .SH SEE ALSO \fBvde_plug\fP(1), vdeplug4-4.0.1/man/libvdeplug_tap.1000066400000000000000000000017571374136421200171210ustar00rootroot00000000000000.TH LIBVDEPLUG_VDE 1 "August 23, 2016" "Virtual Distributed Ethernet" .SH NAME libvdeplug_tap - vdeplug module: tap interface .SH SYNOPSIS libvdeplug_tap.so .SH DESCRIPTION This is the standard vdeplug module to connect a TAP interface. This module of libvdeplug4 can be used in any program supporting vde like \fBvde_plug\fR, \fBkvm\fR, \fBqemu\fR, \fBuser-mode-linux\fR and \fBvirtualbox\fR. \fBtunctl\fR or \fBvde_tunctl\fR can be used to preconfigure a TAP device for use by a particular user. The vde_plug_url syntax of this module is the following: .RS .br \fBtap://\fIname_of_tap_interface\fR .RE .SH EXAMPLES .B tap://mytap .br This vde_plug_url refers the tap interface named \fBmytap\fR. .SH NOTICE Virtual Distributed Ethernet is not related in any way with www.vde.com ("Verband der Elektrotechnik, Elektronik und Informationstechnik" i.e. the German "Association for Electrical, Electronic & Information Technologies"). .SH SEE ALSO \fBvde_plug\fP(1), \fBtunctl\fP(1), \fBvde_tunctl\fP(1), vdeplug4-4.0.1/man/libvdeplug_udp.1000066400000000000000000000024461374136421200171210ustar00rootroot00000000000000.TH LIBVDEPLUG_UDP 1 "August 23, 2016" "Virtual Distributed Ethernet" .SH NAME libvdeplug_udp - vdeplug module for point to point connections using UDP .SH SYNOPSIS libvdeplug_udp.so .SH DESCRIPTION \fBlibvdeplug_udp\fR creates a point to point connection between two vde supporting tools using UDP. This module of libvdeplug4 can be used in any program supporting vde like \fBvde_plug\fR, \fBkvm\fR, \fBqemu\fR, \fBuser-mode-linux\fR and \fBvirtualbox\fR. The network connection created by this module is not encrypted so the data transferred can be intercepted by network analyzer programs. The vde_plug_url syntax of this module is the following: .RS .br \fBudp://\fR"[\fIsrc_address\fB:\fR]\fIsrc_port\fB->\fIdest_address\fB:\fIdest_port\fR" .RE .SH EXAMPLES .B udp://"2000->host_b.domain_b.org:3000" .br .B udp://"3000->host_a.domain_a.org:2000" .br These are the vde_plug_urls to use at host_a.domain_a.org and host_b.domain_b.org respectively to create a connection between port 2000 at host_a and port 3000 at port_b. .SH NOTICE Virtual Distributed Ethernet is not related in any way with www.vde.com ("Verband der Elektrotechnik, Elektronik und Informationstechnik" i.e. the German "Association for Electrical, Electronic & Information Technologies"). .SH SEE ALSO \fBvde_switch\fP(1), \fBvde_plug\fP(1), vdeplug4-4.0.1/man/libvdeplug_vde.1000066400000000000000000000030441374136421200171020ustar00rootroot00000000000000.TH LIBVDEPLUG_VDE 1 "August 23, 2016" "Virtual Distributed Ethernet" .SH NAME libvdeplug_vde - vdeplug module for vde_switch based networks .SH SYNOPSIS libvdeplug_vde.so .SH DESCRIPTION This is the standard vdeplug module for vde_switch based networks. This module of libvdeplug4 can be used in any program supporting vde like \fBvde_plug\fR, \fBkvm\fR, \fBqemu\fR, \fBuser-mode-linux\fR and \fBvirtualbox\fR. The vde_plug_url syntax of the module is the following: .RS .br \fBvde://\fIpath_of_the_switch\fR[\fB[\fIport#_or_portgroup\fB]\fR] .RE This is the default module for libvdeplug, any string not containing '://' (like a path) is processes by libvdeplug_vde. (e.g. /tmp/vde.ctl is equivalent to vde:///tmp/vde.ctl). .SH EXAMPLES .B vde:///tmp/myswitch .br This vde_plug_url refers to the vde_switch identified by the directory \fB/tmp/vde_switch\fR. Please note that there are three slashes '///' as 'vde://' is the prefix and the third slash is the first character of the absolute path. .br .B vde://thisswitch[3] .br this means the port #3 of the switch whose identifier is \fBthisswitch\fR in the current directory .br .B vde:///var/run/vde.ctl[privatelan] .br this is used to create a connetion to the pertgroup \fBprivatelan\fR of the switch \fB/var/run/vde.ctl\fR. .SH NOTICE Virtual Distributed Ethernet is not related in any way with www.vde.com ("Verband der Elektrotechnik, Elektronik und Informationstechnik" i.e. the German "Association for Electrical, Electronic & Information Technologies"). .SH SEE ALSO \fBvde_switch\fP(1), \fBvde_plug\fP(1), vdeplug4-4.0.1/man/libvdeplug_vxlan.1000066400000000000000000000034051374136421200174550ustar00rootroot00000000000000.TH LIBVDEPLUG_VXLAN 1 "August 23, 2016" "Virtual Distributed Ethernet" .SH NAME libvdeplug_vxlan - vxlan vdeplug module .SH SYNOPSIS libvdeplug_vxlan.so .SH DESCRIPTION This is the libvdeplug module to join vxlan networks. Only one process per host can join each vxlan network. This module of libvdeplug4 can be used in any program supporting vde like \fBvde_plug\fR, \fBkvm\fR, \fBqemu\fR, \fBuser-mode-linux\fR and \fBvirtualbox\fR. The vde_plug_url syntax of this module is the following: .RS .br \fBvxlan://\fR[\fImulticast_addr\fR][\fB/\fIOPTION\fR][\fB/\fIOPTION\fR] .RE If \fImulticast_addr\fR is omitted libvdeplug_vxlan uses the default addresses: \fB239.0.0.1\fR for IPv4 and \fBff05:56de::1\fR for IPv6. .SH OPTIONS .TP \fBv4\fR use IPv4 .TP \fBv6\fR use IPv6 .TP \fBport=\fR \fIPORT define the multicast port (default value 4789) .TP \fBvni=\fR \fIVNI define the virtual network identifier (default value 1) .TP \fBttl=\fR \fITTL define the time-to-live (default value 1). \fBhashsize=\fR\fIHASHSIZE set the size of the hash table for packet switching .TP \fBexpiretime=\fR\fIEXPIRETIME set the maximum age in seconds of valid packet switching entries .TP \fBif=\fR\fIINTERFACE set the (real) network interface to use. .SH EXAMPLES .B vxlan://239.0.0.1 .br This vde_plug_url refers to the vxlan network defined on the multicast address 239.0.0.1, vni=1. .sp Programs using .br .B vxlan://ff15::3/port=12345/vni=42 .br join the same vxlan network defined by the multicast address ff15::1, port 12345, vni is 42. .SH NOTICE Virtual Distributed Ethernet is not related in any way with www.vde.com ("Verband der Elektrotechnik, Elektronik und Informationstechnik" i.e. the German "Association for Electrical, Electronic & Information Technologies"). .SH SEE ALSO \fBvde_plug\fP(1), vdeplug4-4.0.1/man/libvdeplug_vxvde.1000066400000000000000000000040261374136421200174610ustar00rootroot00000000000000.TH LIBVDEPLUG_VXVDE 1 "August 23, 2016" "Virtual Distributed Ethernet" .SH NAME libvdeplug_vxvde - vdeplug module for vde_switch based networks .SH SYNOPSIS libvdeplug_vxvde.so .SH DESCRIPTION This is the libvdeplug module to join vxvde networks. Vxvde is a distributed implementation of virtual networks. There is no need for extra processes like virtual switches. This module of libvdeplug4 can be used in any program supporting vde like \fBvde_plug\fR, \fBkvm\fR, \fBqemu\fR, \fBuser-mode-linux\fR and \fBvirtualbox\fR. The vde_plug_url syntax of this module is the following: .RS .br \fBvxvde://\fR[\fImulticast_addr\fR][\fB/\fIOPTION\fR][\fB/\fIOPTION\fR] .RE If \fImulticast_addr\fR is omitted libvdeplug_vxvde uses the default addresses: \fB239.0.0.1\fR for IPv4 and \fBff05:56de::1\fR for IPv6. .SH OPTIONS .TP \fBv4\fR use IPv4 .TP \fBv6\fR use IPv6 .TP \fBport=\fR\fIPORT define the multicast port (default value 14789) .TP \fBvni=\fR\fIVNI define the virtual network identifier (default value 1). (a group name can be used as VNI, in that case the vni is the group id). .TP \fBttl=\fR\fITTL define the time-to-live (default value 1). .TP \fBgrp=\fR\fIgroup_name_or_number Set the VNI and the last three bytes of the IP address to the group id. .TP \fBhashsize=\fR\fIHASHSIZE set the size of the hash table for packet switching .TP \fBexpiretime=\fR\fIEXPIRETIME set the maximum age in seconds of valid packet switching entries .TP \fBif=\fR\fIINTERFACE set the (real) network interface to use. .SH EXAMPLES .B vxvde://239.0.0.1 .br This vde_plug_url refers to the vxvde network defined on the multicast address 239.0.0.1, vni=1. .sp Programs using .br .B vxvde://ff15::3/port=12345/vni=42 .br join the same vxvde network defined by the multicast address ff15::1, port 12345, vni is 42. .SH NOTICE Virtual Distributed Ethernet is not related in any way with www.vde.com ("Verband der Elektrotechnik, Elektronik und Informationstechnik" i.e. the German "Association for Electrical, Electronic & Information Technologies"). .SH SEE ALSO \fBvde_plug\fP(1), vdeplug4-4.0.1/man/vde_close.3000077700000000000000000000000001374136421200202672libvdeplug.3ustar00rootroot00000000000000vdeplug4-4.0.1/man/vde_ctlfd.3000077700000000000000000000000001374136421200202562libvdeplug.3ustar00rootroot00000000000000vdeplug4-4.0.1/man/vde_datafd.3000077700000000000000000000000001374136421200204052libvdeplug.3ustar00rootroot00000000000000vdeplug4-4.0.1/man/vde_open.3000077700000000000000000000000001374136421200201232libvdeplug.3ustar00rootroot00000000000000vdeplug4-4.0.1/man/vde_plug.1000066400000000000000000000140411374136421200157130ustar00rootroot00000000000000.TH VDE_PLUG 1 "August 23, 2016" "Virtual Distributed Ethernet" .SH NAME vde_plug \- Virtual Distributed Ethernet plug (two plugs creates a vde cable) .SH SYNOPSIS .B vde_plug [ .I OPTIONS ] [ .I vde_plug_url ] .br .B vde_plug [ .I OPTIONS ] .I vde_plug_url .I vde_plug_url .br .B vde_plug [ .I OPTIONS ] .B = .I command [ .I args ] .br .B vde_plug [ .I OPTIONS ] .I vde_plug_url .B = .I command [ .I args ] .br .SH DESCRIPTION A \fBvde_plug\fR is a plug to be connected into a VDE network. VDE network sockets are named using the vde_plug_url syntax, i.e. \fImodule\fB://\fIspecific_address\fR. e.g. \fBvde:///home/user/myswitch\fR or \fBvxvde://239.0.0.1\fR. The default module is \fBlibvdeplug_vde(1)\fR (connection to a \fBvde_switch(1)\fR) and can be omitted. e.g. \fB/home/user/myswitch\fR means \fBvde:///home/user/myswitch\fR \fBvde_plug\fR can have zero, one or two vde_plug_url arguments. In case of zero or one argument the network communication is converted in a byte stream. Packets from the VDE network are sent to stdout and bytes from stdin are converted into packets and injected in the VDE network. When a vde_plug_url is omitted or it is an empty argument (\fB''\fR) \fBvde_plug\fR tries to connect to a default network (defined by the user in \fB$HOME/.vde2/default.switch\fR otherwise \fBvde:///run/vde.ctl\fR or \fBvde:///tmp/vde.ctl\fR). This tool has been designed to be used together with .B dpipe (1) to interconnect a second vde_plug to another switch, working as a virtual ethernet crossed cable between the two switches. The command .RS .br .B dpipe vde_plug = vde_plug vde:///tmp/vde2.ctl .RE connects two local switches: the former is using the standard control socket /tmp/vde.ctl (or /var/run/vde.ctl) while the latter is using /tmp/vde2.ctl. \fBvde_plug\fR creates a virtual cable between to VDE networks when two vde_plug_url arguments are present in the command line. The previous command is equivalent to: .RS .br .B vde_plug /tmp/vde.ctl /tmp/vde2.ctl .RE The following example connects a vxvde network to a tap interfave .RS .br .B vde_plug vxvde://239.1.2.3 tap://mytap .RE The command .RS .br .B dpipe vde_plug = ssh remote.machine.org vde_plug .RE connects two remote switches. If for example the two vde_switches run as daemon and they are connected to tap interfaces a level 2 encrypted tunnel is established. While \fBdpipe\fR supports more complex vitrual network structures (e.g. including \fBwirefilter(1)\fR to emulate network conditions) \fBvde_plug\fR has been designed to provide simple syntax options to implement the most common virtual network scenarios. It is possible to use an equal sign (\fB=\fR) followed by a command and its optional arguments in place of the second vde_plug_url. In this case the packets from/to the network are converted into a bidirectional byte stream provided as stdin and stdout to the command. The previous command have the same effect of: .RS .br .B vde_plug = ssh remote.machine.org vde_plug .RE (the first vde_plug_url is omitted). This example: .RS .br .B vde_plug vxvde://239.1.2.3 = ssh vde_plug tap://remotetap .RE connects a vxvde network to a tap interface of a remote host. vde_plug can also be established as a login shell for users. The following command works as in the previous example .RS .br .B vde_plug = ssh vdeuser@remote.machine.org vde_plug .RE where vdeuser is the user with vde_plug as standard shell. All the remote accesses are logged by syslog at the beginning and at the end of each session and the IP address used are logged if \fBvdeuser\fR belongs to the \fBvdeplug_iplog\fR group. Attempts to login without the command vde_plug at the end or to run on the remote host other commands but vde_plug are blocked and the violation is logged by syslog. .SH OPTIONS .TP \fB\-d .TQ \fB\-\-daemon run as a daemon. .TP \fB\-p\fR \fIPIDFILE .TQ \fB\-\-pidfile\fR \fIPIDFILE write the process id to the file \fIPIDFILE\fR .TP \fB\-l .TQ \fB\-\-log log START/STOP of vde_plug on syslog .TP \fB\-L .TQ \fB\-\-iplog log START/STOP of vde_plug and the IP addresses of hosts seen on the stream (or on the second vde_plug_url) on syslog. .TP \fB\-\-port "\fIportnum\fP" Obsolete option, use the syntax of the libvdeplug_vde module instead, add the port number in square brackets suffix (e.g. \fBvde://tmp/myswitch[10]\fR). It is possible to decide which port of the switch to use. When this option is not specified the switch assigns the first available unused port (if any). It is possible to connect several cables in the same switch port: in this way all this cables work concurrently. It means that packet can result as duplicate but no ARP table loops are generated. Is useful when vde is used for mobility. Several physical interfaces can be used at a time during handoffs to prevent hichups in connectivity. log START/STOP of vde_plug on syslog .TP \fB\-g \fIgroup .TQ \fB\-\-group \fIgroup group ownership of the communication socket. For security when more want to share a switch it is better to use a unix group to own the comm sockets so that the network traffic cannot be sniffed. .TP \fB\-m \fIoctal-mode\fR .TQ \fB\-\-mod \fIoctal-mode\fR octal chmod like permissions for the comm sockets .TP \fB\-G \-M .TQ \fB\-\-port2 \-\-group2 \-\-mod2 These options, valid in the syntax with two vde_plug_urls, have the the same meaning of \-p \-g \-m. The uppercase options or the long options with a trailing 2 refer to the second vde_plug_url. .TP \fB\-D\fR \fIDESCR .TQ \fB\-\-descr\fR \fIDESCR set the description of this connection to \fIDESCR\fR (e.g. port/print command on a vde_switch shows this description). .SH NOTICE Virtual Distributed Ethernet is not related in any way with www.vde.com ("Verband der Elektrotechnik, Elektronik und Informationstechnik" i.e. the German "Association for Electrical, Electronic & Information Technologies"). .SH SEE ALSO \fBvde_switch\fP(1), \fBvdeq\fP(1), \fBdpipe\fP(1), \fBlibvdeplug_p2p.1\fR, \fBlibvdeplug_udp.1\fR, \fBlibvdeplug_vxlan.1\fR, \fBlibvdeplug_tap.1\fR, \fBlibvdeplug_vde.1\fR, \fBlibvdeplug_vxvde.1\fR. .br .SH AUTHOR VDE is a project by Renzo Davoli vdeplug4-4.0.1/man/vde_recv.3000077700000000000000000000000001374136421200201212libvdeplug.3ustar00rootroot00000000000000vdeplug4-4.0.1/man/vde_send.3000077700000000000000000000000001374136421200201132libvdeplug.3ustar00rootroot00000000000000vdeplug4-4.0.1/srcvdeplug4/000077500000000000000000000000001374136421200155135ustar00rootroot00000000000000vdeplug4-4.0.1/srcvdeplug4/CMakeLists.txt000066400000000000000000000005651374136421200202610ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.13) add_executable( vde_plug vde_plug.c vde_plug_log.c vde_plug_iplog.c openclosepidfile.c selfsighandler.c ) target_link_libraries(vde_plug vdeplug) add_executable(dpipe dpipe.c openclosepidfile.c selfsighandler.c) install( TARGETS vde_plug dpipe RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) vdeplug4-4.0.1/srcvdeplug4/dpipe.c000066400000000000000000000212551374136421200167650ustar00rootroot00000000000000/* * Copyright (C) 2003-2016 Renzo Davoli, University of Bologna * * dpipe: dual pipe * * VDE is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; If not, see . * */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #define DAEMONIZE 0x1 #define NO_WRAPPROC 0x2 #define CLEANUP_NEEDED 0x4 #define NO_CLEANUP 0x8 #if 0 /* debug */ #define execvp(X,Y) \ ({ char **y; \ fprintf(stderr,"execvp \"%s\" -",(X)); \ for (y=(Y); *y != NULL; y++) \ fprintf(stderr,"\"%s\"",*y); \ fprintf(stderr,"\n"); \ sleep (10); \ }) #endif static char *progname; pid_t lastpid = -1; static void cleanup(void) { openclosepidfile(NULL); openclosepgrpfile(NULL); } static void sigcleanup(void) { cleanup(); if (lastpid >= 0) kill(lastpid,SIGTERM); } int waitfortermination(pid_t last) { int status; int rval = -1; pid_t pid; lastpid = last; while ((pid = waitpid(-1, &status, 0)) >= 0) { if (pid == last) rval = WEXITSTATUS(status); } return rval; } /* return the index of the next '=' (maybe with { } before or after) if there is { or } before =, this must match dirchar i.e. the symbol following the previous = dirchar is updated for the next split. */ int splitindex(int argc, char *argv[], int *dirchar) { register int i; for (i=0; i= argc) { pid_t last; if (newdirchar != 0) usage_and_exit(); if (flags & NO_WRAPPROC) { if ((flags & CLEANUP_NEEDED) && fork() == 0) { pid_t ppid = getppid(); close(STDIN_FILENO); close(STDOUT_FILENO); while (1) { if (kill(ppid,0) < 0) break; sleep(1); } exit(0); } else { execvp(argv[0],argv); exit(127); } } else { if ((last = fork()) == 0) { execvp(argv[0],argv); exit(127); } else { close(STDIN_FILENO); close(STDOUT_FILENO); return last; } } } else { /* the chain has more than one elements. */ char **argv1,**argv2; int p1[2],p2[2]; if (argc < 3 || split == 0 || split == argc-1) usage_and_exit(); if (pipe(p1) < 0) { perror("pipe"); exit(1); } /* ..chain already processed.. = this =.... two pipes needed */ if (olddirchar == 0) { if (pipe(p2) < 0) { perror("second pipe"); exit(1); } } argv[split]=NULL; argv1=argv; argv2=argv+(split+1); if (fork() == 0) { /* child prepare to run the program */ switch (olddirchar) { case 0: /* ... = this = ... */ close(p1[1]); close(p2[0]); if (p1[0] != alternate_stdin){ dup2(p1[0],alternate_stdin); close(p1[0]); } if (p2[1] != alternate_stdout){ dup2(p2[1],alternate_stdout); close(p2[1]); } break; case '{': /* ... ={ this {= ... */ close(p1[1]); dup2(p1[0],STDIN_FILENO); close(p1[0]); break; case '}': /* ... =} this }= ... */ close(p1[0]); dup2(p1[1],STDOUT_FILENO); close(p1[1]); break; default: fprintf(stderr,"Error\n"); } execvp(argv1[0],argv1); exit(127); } else { /* parent rename the pipes as STDIN_FILENO and STDOUT_FILENO and process the remaining part of the chain */ switch (olddirchar) { case 0: /* ... = this = ... */ close(p2[1]); close(p1[0]); dup2(p2[0],STDIN_FILENO); dup2(p1[1],STDOUT_FILENO); close(p2[0]); close(p1[1]); break; case '{': /* ... ={ this {= ... */ close(p1[0]); dup2(p1[1],STDOUT_FILENO); close(p1[1]); break; case '}': /* ... =} this }= ... */ close(p1[1]); dup2(p1[0],STDIN_FILENO); close(p1[0]); break; default: fprintf(stderr,"Error\n"); } return rec_dpipe(argc-split-1,argv2,newdirchar,flags); } } return 0; } /* start the first process of the dpipe chain */ pid_t start_dpipe(int argc, char *argv[], unsigned int flags) { int split; char **argv1,**argv2; int p1[2],p2[2]; int dirchar=0; alternate_fd(); split=splitindex(argc,argv,&dirchar); if (argc < 3 || split == 0 || split >= argc-1) usage_and_exit(); if (pipe(p1) < 0 || pipe(p2) < 0) { perror("pipe"); exit(1); } argv[split]=NULL; argv1=argv; argv2=argv+(split+1); if (fork() == 0) { close(p1[1]); close(p2[0]); dup2(p1[0],STDIN_FILENO); dup2(p2[1],STDOUT_FILENO); close(p1[0]); close(p2[1]); execvp(argv1[0],argv1); exit(127); } else { close(p2[1]); close(p1[0]); dup2(p2[0],STDIN_FILENO); dup2(p1[1],STDOUT_FILENO); close(p1[1]); close(p2[0]); return rec_dpipe(argc-split-1,argv2,dirchar,flags); } } char *short_options = "+dp:P:hnN"; struct option long_options[] = { {"nowrapproc", no_argument, 0, 'n' }, {"nowrapnoclean", no_argument, 0, 'N' }, {"pidfile", required_argument, 0, 'p' }, {"pgrpfile", required_argument, 0, 'P' }, {"daemon", no_argument, 0, 'd' }, {"help", no_argument, 0, 'h' }, {0, 0, 0, 0} }; int main(int argc, char *argv[]) { unsigned int flags = 0; char *pidfile = NULL; char *pgrpfile = NULL; int rval; progname = argv[0]; while (1) { int option_index = 0; int c; c = getopt_long(argc, argv, short_options, long_options, &option_index); if (c == -1) break; switch (c) { case 'p' : pidfile = optarg; flags |= CLEANUP_NEEDED; break; case 'P' : pgrpfile = optarg; flags |= CLEANUP_NEEDED; break; case 'd' : flags |= DAEMONIZE; break; case 'n' : flags |= NO_WRAPPROC; break; case 'N' : flags |= NO_WRAPPROC | NO_CLEANUP; break; case 'h' : usage_and_exit(); } } if (flags & NO_CLEANUP) flags &= ~CLEANUP_NEEDED; argc -= optind; argv += optind; if ((flags & DAEMONIZE) != 0) { if (daemon(0,0) < 0) { fprintf(stderr,"%s daemonize: %s\n", progname, strerror(errno)); exit(1); } } else if (setpgrp() != 0) { fprintf(stderr,"Err: cannot create pgrp\n"); exit(1); } atexit(cleanup); setsighandlers(sigcleanup); if (pidfile != NULL) openclosepidfile(pidfile); if (pgrpfile != NULL) openclosepgrpfile(pgrpfile); rval = waitfortermination(start_dpipe(argc, argv, flags)); return rval; } vdeplug4-4.0.1/srcvdeplug4/openclosepidfile.c000066400000000000000000000025221374136421200212040ustar00rootroot00000000000000/* * Copyright (C) 2016 Renzo Davoli, University of Bologna * * openclosepidfile * * VDE is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; If not, see . * */ #include #include #include void openclosepidfile(char *pidfile) { static char *savepidfile; if (pidfile != NULL) { FILE *f = fopen(pidfile,"w"); if (f != NULL) { savepidfile = pidfile; fprintf(f,"%d\n", getpid()); fclose(f); } } else if (savepidfile != NULL) unlink(savepidfile); } void openclosepgrpfile(char *pidfile) { static char *savepidfile; if (pidfile != NULL) { FILE *f = fopen(pidfile,"w"); if (f != NULL) { savepidfile = pidfile; fprintf(f,"-%d\n", getpgrp()); fclose(f); } } else if (savepidfile != NULL) unlink(savepidfile); } vdeplug4-4.0.1/srcvdeplug4/openclosepidfile.h000066400000000000000000000002161374136421200212070ustar00rootroot00000000000000#ifndef OPENCLOSEPIDFILE_H #define OPENCLOSEPIDFILE_H void openclosepidfile(char *pidfile); void openclosepgrpfile(char *pidfile); #endif vdeplug4-4.0.1/srcvdeplug4/selfsighandler.c000066400000000000000000000044271374136421200206600ustar00rootroot00000000000000/* * Copyright (C) 2003-2016 Renzo Davoli, Ludovico Gardenghi. University of Bologna * * signal handler * * VDE is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; If not, see . * */ #include #include #include #include #include static void (*cleanupcopy)(void); static void sig_handler(int sig) { cleanupcopy(); signal(sig, SIG_DFL); if (sig == SIGTERM) _exit(0); else kill(-getpgrp(), sig); } void setsighandlers(void (*cleanup)(void)) { /* setting signal handlers. * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply * ignores all the others signals which could cause termination. */ struct { int sig; const char *name; int ignore; } signals[] = { { SIGHUP, "SIGHUP", 0 }, { SIGINT, "SIGINT", 0 }, { SIGPIPE, "SIGPIPE", 1 }, { SIGALRM, "SIGALRM", 1 }, { SIGTERM, "SIGTERM", 0 }, { SIGUSR1, "SIGUSR1", 1 }, { SIGUSR2, "SIGUSR2", 1 }, { SIGPROF, "SIGPROF", 1 }, { SIGVTALRM, "SIGVTALRM", 1 }, #ifdef SIGPOLL { SIGPOLL, "SIGPOLL", 1 }, #ifdef SIGSTKFLT { SIGSTKFLT, "SIGSTKFLT", 1 }, #endif { SIGIO, "SIGIO", 1 }, { SIGPWR, "SIGPWR", 1 }, #ifdef SIGUNUSED { SIGUNUSED, "SIGUNUSED", 1 }, #endif #endif #ifdef VDE_DARWIN { SIGXCPU, "SIGXCPU", 1 }, { SIGXFSZ, "SIGXFSZ", 1 }, #endif { 0, NULL, 0 } }; int i; struct sigaction sa = { .sa_handler = sig_handler, .sa_flags = 0}; sigfillset(&sa.sa_mask); for(i = 0; signals[i].sig != 0; i++) if (!signals[i].ignore) if (sigaction(signals[i].sig, &sa, NULL) < 0) perror("Setting handler"); for(i = 0; signals[i].sig != 0; i++) if (signals[i].ignore) if (signal(signals[i].sig, SIG_IGN) == SIG_ERR) perror("Setting handler"); cleanupcopy = cleanup; } vdeplug4-4.0.1/srcvdeplug4/selfsighandler.h000066400000000000000000000001721374136421200206560ustar00rootroot00000000000000#ifndef SELFSIGHANDLER_H #define SELFSIGHANDLER_H void setsighandlers(void (*cleanup)(void)); #endif //SELFSIGHANDLER_H vdeplug4-4.0.1/srcvdeplug4/vde_plug.c000066400000000000000000000254521374136421200174740ustar00rootroot00000000000000/* * Copyright (C) 2002-2016 Renzo Davoli, University of Bologna * Modified by Ludovico Gardenghi 2005 * * vde_plug: connect vde network together * * VDE is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; If not, see . * */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define VDE_IP_LOG_GROUP "vdeplug_iplog" #define DEFAULT_DESCRIPTION "vdeplug:" int vde_ip_log; VDECONN *conn; VDECONN *conn2; VDESTREAM *vdestream; #define ETH_ALEN 6 #define ETH_HDRLEN (ETH_ALEN+ETH_ALEN+2) struct utsname me; #define myname me.nodename void vdeplug_err(void *opaque, int type, char *format,...) { va_list args; if (isatty(STDERR_FILENO)) { fprintf(stderr, "%s: Packet length error ",myname); va_start(args, format); vfprintf(stderr, format, args); va_end(args); fprintf(stderr,"\n"); } } ssize_t vdeplug_recv(void *opaque, void *buf, size_t count) { VDECONN *conn=opaque; if (__builtin_expect(vde_ip_log != 0, 0)) vde_ip_check(buf,count); return vde_send(conn,(char *)buf,count,0); } int checkuidgroup(uid_t uid, const char *group) { struct passwd *pw=getpwuid(uid); int ngroups=0; if (pw == NULL) return -1; if (getgrouplist(pw->pw_name, pw->pw_gid, NULL, &ngroups) < 0) { gid_t gids[ngroups]; if (getgrouplist(pw->pw_name, pw->pw_gid, gids, &ngroups) == ngroups) { struct group *grp; int i; while ((grp=getgrent()) != NULL) { for (i=0; igr_gid == gids[i] && strcmp(grp->gr_name,group) == 0) { endgrent(); return 1; } } } endgrent(); return 0; } } return -1; } static void cleanup(void) { vde_close(conn); if (conn2 != NULL) vde_close(conn2); if (vdestream != NULL) vdestream_close(vdestream); openclosepidfile(NULL); } unsigned char bufin[VDE_ETHBUFSIZE]; int plug2stream(void) { register ssize_t nx; struct pollfd pollv[] = { {STDIN_FILENO, POLLIN|POLLHUP}, {vde_datafd(conn), POLLIN|POLLHUP}, {vde_ctlfd(conn), POLLIN|POLLHUP}, }; vdestream = vdestream_open(conn,STDOUT_FILENO,vdeplug_recv,vdeplug_err); for(;;) { poll(pollv,3,-1); if (__builtin_expect(((pollv[0].revents | pollv[1].revents | pollv[2].revents) & POLLHUP || pollv[2].revents & POLLIN),0)) break; if (pollv[0].revents & POLLIN) { nx = read(STDIN_FILENO,bufin,sizeof(bufin)); /* if POLLIN but not data it means that the stream has been * closed at the other end */ /*fprintf(stderr,"%s: RECV %d %x %x \n",myname,nx,bufin[0],bufin[1]);*/ if (nx == 0) break; vdestream_recv(vdestream, bufin, nx); } if (pollv[1].revents & POLLIN) { nx = vde_recv(conn,bufin,VDE_ETHBUFSIZE,0); if (__builtin_expect((nx >= ETH_HDRLEN),1)) { vdestream_send(vdestream, bufin, nx); /*fprintf(stderr,"%s: SENT %d %x %x \n",myname,nx,bufin[0],bufin[1]);*/ } else if (nx<0) perror("vde_plug: recvfrom "); } } return(0); } int plug2cmd(char **argv) { int p2c[2],c2p[2]; pid_t pid; if (pipe(p2c) < 0 || pipe(c2p) < 0) { perror("pipe open"); return(1); } pid=fork(); if (pid < 0) { perror("fork"); exit(1); } else if (pid == 0) { dup2(p2c[0], STDIN_FILENO); dup2(c2p[1], STDOUT_FILENO); close(p2c[0]); close(p2c[1]); close(c2p[0]); close(c2p[1]); execvp(*argv, argv); exit(1); } dup2(c2p[0], STDIN_FILENO); dup2(p2c[1], STDOUT_FILENO); close(p2c[0]); close(p2c[1]); close(c2p[0]); close(c2p[1]); return plug2stream(); } int plug2plug(void) { register ssize_t nx; struct pollfd pollv[] = { {vde_datafd(conn), POLLIN|POLLHUP}, {vde_datafd(conn2), POLLIN|POLLHUP}, {vde_ctlfd(conn), POLLIN|POLLHUP}, {vde_ctlfd(conn2), POLLIN|POLLHUP} }; for(;;) { poll(pollv,4,-1); if ((pollv[0].revents | pollv[1].revents | pollv[2].revents | pollv[2].revents) & POLLHUP || (pollv[2].revents | pollv[3].revents) & POLLIN) break; if (pollv[0].revents & POLLIN) { nx = vde_recv(conn, bufin, VDE_ETHBUFSIZE,0); if (__builtin_expect((nx >= ETH_HDRLEN),1)) { vde_send(conn2, bufin, nx, 0); /*fprintf(stderr,"0->1 %d ",nx);*/ } else if (nx<0) break; } if (pollv[1].revents & POLLIN) { nx = vde_recv(conn2,bufin,VDE_ETHBUFSIZE,0); if (__builtin_expect((nx >= ETH_HDRLEN),1)) { vde_send(conn, bufin, nx, 0); /*fprintf(stderr,"1->0 %d ",nx);*/ } else if (nx<0) break; } } return(0); } static void netusage_and_exit() { vdeplug_openlog("FAILED"); fprintf (stderr,"This is a Virtual Distributed Ethernet (vde) tunnel broker. \n" "This is not a login shell, only vde_plug can be executed\n"); exit(-1); } static void usage_and_exit(char *progname) { fprintf (stderr,"Usage:\n" " %s [ OPTIONS ] \n" " %s [ OPTIONS ] vde_plug_url\n" " %s [ OPTIONS ] vde_plug_url vde_plug_url\n" " %s [ OPTIONS ] = command [args ...]\n" " %s [ OPTIONS ] vde_plug_url = command [args ...]\n" " an omitted or empty '' vde_plug_url refer to the default vde service\n" " i.e. what defined in \"~/.vde2/default.switch\" or\n" " a standard switch defined by libvdeplug_vde.so (e.g. /var/run/vde.ctl)\n" "Options:\n" " -d | --daemon: daemonize the program\n" " -p PIDFILE | --pidfile PIDFILE: \n" " write pid of daemon to PIDFILE\n" " -l | --log: log START/STOP of vde_plug on syslog\n" " -L | --iplog: -l plus log the IP addresses used\n" " -h | --help: show this short summary\n" " -g GROUP | -group GROUP: set the group ownership (for vde://...)\n" " -G GROUP | -group2 GROUP: like -g, for the second plug\n" " -m MODE | -mod MODE: comm socket protection mode (see chmod) (for vde://...)\n" " -M MODE | -mod2 MODE: like -m, for the second plug\n" " --port PORT1, --port2 PORT2:\n" " obsolete options, set the vde switch port,\n" " use [port] suffix in the vde_plug_url instead\n" " -D DESCR | --descr DESCR set the description of this connection to DESCR\n" " (the default value is \"" DEFAULT_DESCRIPTION "\"\n" "\n",progname,progname,progname,progname,progname); exit(-1); } char short_options[] = "c:hp:dm:M:g:G:lLD:"; struct option long_options[] = { {"pidfile", required_argument, 0, 'p' }, {"daemon", no_argument, 0, 'd' }, {"port", required_argument, 0, 0x100 + 'p'}, {"port2", required_argument, 0, 0x100 + 'P'}, {"mod", required_argument, 0, 'm'}, {"mod2", required_argument, 0, 'M'}, {"group", required_argument, 0, 'g'}, {"group2", required_argument, 0, 'G'}, {"descr", required_argument, 0, 'D' }, {"log", no_argument, 0, 'l' }, {"iplog", no_argument, 0, 'L' }, {"help", no_argument, 0, 'h' }, {0, 0, 0, 0} }; #include int main(int argc, char *argv[]) { char *progname = basename(argv[0]); static char *vde_url = NULL; static char *vde_url2 = NULL; static char **cmdargv = NULL; struct vde_open_args open_args = {.port = 0,.group = NULL,.mode = 0700}; struct vde_open_args open_args2 = {.port = 0,.group = NULL,.mode = 0700}; int daemonize = 0; char *pidfile = NULL; char *description = DEFAULT_DESCRIPTION; uname(&me); if (argv[0][0] == '-') netusage_and_exit(); //implies exit /* option parsing */ while (1) { int option_index = 0; int c; c = getopt_long(argc, argv, short_options, long_options, &option_index); if (c == -1) break; switch (c) { case 'c': if (strcmp(optarg,"vde_plug") == 0) { vdeplug_openlog(NULL); atexit(vdeplug_closelog); if (checkuidgroup(getuid(), VDE_IP_LOG_GROUP) == 1) vde_ip_log = 1; } else netusage_and_exit(); //implies exit break; case 0x100 + 'p': open_args.port = atoi(optarg); if (open_args.port <= 0) usage_and_exit(progname); //implies exit break; case 0x100 + 'P': open_args2.port = atoi(optarg); if (open_args2.port <= 0) usage_and_exit(progname); //implies exit break; case 'h': usage_and_exit(progname); //implies exit break; case 'm': sscanf(optarg,"%o",(unsigned int *)&(open_args.mode)); break; case 'M': sscanf(optarg,"%o",(unsigned int *)&(open_args2.mode)); break; case 'g': open_args.group = optarg; break; case 'G': open_args2.group = optarg; break; case 'L': vde_ip_log = 1; case 'l': vdeplug_openlog(NULL); atexit(vdeplug_closelog); break; case 'p' : pidfile = optarg; break; case 'd' : daemonize = 1; break; case 'D' : if (*optarg != 0) description = optarg; break; default: usage_and_exit(progname); //implies exit } } argv += optind; argc -= optind; switch (argc) { case 0: break; case 1: vde_url = *argv; break; case 2: if (strcmp(argv[0],"=") == 0) cmdargv = argv+1; else { vde_url = argv[0]; vde_url2 = argv[1]; } break; default: if (strcmp(argv[0],"=") == 0) cmdargv = argv+1; else if (strcmp(argv[1],"=") == 0) { vde_url = argv[0]; cmdargv = argv+2; } else usage_and_exit(progname); //implies exit break; } if (daemonize != 0) { if (daemon(0,0) < 0) { fprintf(stderr,"%s daemonize: %s\n", progname, strerror(errno)); exit(1); } } if (pidfile != NULL) openclosepidfile(pidfile); atexit(cleanup); setsighandlers(cleanup); conn = vde_open(vde_url, description, &open_args); if (conn == NULL) { fprintf(stderr,"vde_open %s: %s\n",vde_url && *vde_url ? vde_url : "default switch", strerror(errno)); exit(1); } if (vde_url2 != NULL) { conn2 = vde_open(vde_url2, description, &open_args2); if (conn2 == NULL) { fprintf(stderr,"vde_open %s: %s\n",vde_url2 && *vde_url2 ? vde_url2 : "default switch", strerror(errno)); exit(1); } return plug2plug(); } else if (cmdargv != NULL) return plug2cmd(cmdargv); else return plug2stream(); } vdeplug4-4.0.1/srcvdeplug4/vde_plug_iplog.c000066400000000000000000000071251374136421200206630ustar00rootroot00000000000000/* * Copyright (C) 2002-2016 Renzo Davoli, University of Bologna * Modified by Ludovico Gardenghi 2005 * * iplog: log unique IP addresses seen on a line * * VDE is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; If not, see . * */ #define _GNU_SOURCE #include #include #include #include #include #define ETH_ALEN 6 struct header { unsigned char dest[ETH_ALEN]; unsigned char src[ETH_ALEN]; unsigned char proto[2]; }; union body { struct { unsigned char version; unsigned char filler[11]; unsigned char ip4src[4]; unsigned char ip4dst[4]; } v4; struct { unsigned char version; unsigned char filler[7]; unsigned char ip6src[16]; unsigned char ip6dst[16]; } v6; struct { unsigned char priovlan[2]; } vlan; }; struct addrelem { struct addrelem *next; unsigned int len; char addr[]; }; static unsigned long hash(unsigned int len, unsigned char *addr) { unsigned long hash = 5381; int i; for (i = 0; i < len; i++) hash = ((hash << 5) + hash) + addr[i]; return hash; } static int search_n_add(struct addrelem **scan, unsigned int len, unsigned char *addr) { struct addrelem *new; for (; *scan != NULL ; scan = &((*scan)->next)) if ((*scan)->len == len && memcmp((*scan)->addr,addr,len) == 0) return 0; new = malloc(sizeof(struct addrelem) + len); if (new) { new->next = NULL; new->len = len; memcpy(new->addr, addr, len); *scan = new; return 1; } return -1; } #define HASH_MASK 511 void hash_add_n_run(unsigned int len, unsigned char *addr, void *arg, void (*f)(unsigned int len, unsigned char *addr, void *arg)) { static struct addrelem **htable; unsigned long hashkey; if (__builtin_expect(htable == NULL, 0)) htable = calloc(HASH_MASK + 1, sizeof(struct addrelem *)); hashkey = hash(len, addr) % HASH_MASK; if (search_n_add(&(htable[hashkey]), len, addr) == 1) f(len, addr, arg); } void printlogv4(unsigned int len, unsigned char *addr, void *arg) { char straddr[256]; int *pvlan = arg; syslog(LOG_INFO, "user %s Real-IP %s has got VDE-IP4 %s on vlan %d", username, sshremotehost, inet_ntop(AF_INET, addr, straddr, 256), *pvlan); } void printlogv6(unsigned int len, unsigned char *addr, void *arg) { char straddr[256]; int *pvlan = arg; syslog(LOG_INFO, "user %s Real-IP %s has got VDE-IP6 %s on vlan %d", username, sshremotehost, inet_ntop(AF_INET6, addr, straddr, 256), *pvlan); } void vde_ip_check(const unsigned char *buf, int rnx) { struct header *ph = (struct header *) buf; int vlan = 0; union body *pb; pb = (union body *)(ph+1); if (ph->proto[0] == 0x81 && ph->proto[1] == 0x00) { /*VLAN*/ vlan = ((pb->vlan.priovlan[0] << 8) + pb->vlan.priovlan[1]) & 0xfff; pb = (union body *)(((char *)pb)+4); } if (ph->proto[0] == 0x08 && ph->proto[1] == 0x00 && pb->v4.version == 0x45) { /*v4 */ hash_add_n_run(4, pb->v4.ip4src, &vlan, printlogv4); } else if (ph->proto[0] == 0x86 && ph->proto[1] == 0xdd && pb->v4.version == 0x60) { /* v6 */ hash_add_n_run(16, pb->v6.ip6src, &vlan, printlogv6); } } vdeplug4-4.0.1/srcvdeplug4/vde_plug_iplog.h000066400000000000000000000001601374136421200206600ustar00rootroot00000000000000#ifndef VDE_PLUG_IPLOG_H #define VDE_PLUG_IPLOG_H void vde_ip_check(const unsigned char *buf, int rnx); #endif vdeplug4-4.0.1/srcvdeplug4/vde_plug_log.c000066400000000000000000000040251374136421200203260ustar00rootroot00000000000000/* * Copyright (C) 2002-2016 Renzo Davoli, University of Bologna * Modified by Ludovico Gardenghi 2005 * * log: vde_plug logging facilities * * VDE is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; If not, see . * */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include char sshremotehost[256]; char *username; static void vdeplug_getdata(void) { char *ssh_client; size_t ip_length; //get the login name struct passwd *callerpwd = getpwuid(getuid()); username = callerpwd->pw_name; openlog("vde_plug", 0, LOG_USER); //get the caller IP address //TNX Giordani-Macchia code from vish.c if ((ssh_client = getenv("SSH_CLIENT"))!=NULL) { for (ip_length = 0; ip_length=sizeof(sshremotehost)) ip_length = sizeof(sshremotehost)-1; memcpy(sshremotehost,ssh_client,ip_length); sshremotehost[ip_length] = 0; } else strcpy(sshremotehost,"UNKNOWN_IP_ADDRESS"); } void vdeplug_openlog(char *message) { openlog("vde_plug", 0, LOG_USER); vdeplug_getdata(); syslog(LOG_INFO,"%s: user %s IP %s",message ?message : "START",username,sshremotehost); if (message) closelog(); } void vdeplug_closelog(void) { syslog(LOG_INFO,"%s: user %s IP %s","STOP",username,sshremotehost); closelog(); } vdeplug4-4.0.1/srcvdeplug4/vde_plug_log.h000066400000000000000000000002621374136421200203320ustar00rootroot00000000000000#ifndef VDE_PLUG_LOG_H #define VDE_PLUG_LOG_H extern char sshremotehost[256]; extern char *username; void vdeplug_openlog(char *message); void vdeplug_closelog(void); #endif