diff --git a/dap-sdk/net/client/libev/.travis.yml b/3rdparty/libev/.travis.yml similarity index 100% rename from dap-sdk/net/client/libev/.travis.yml rename to 3rdparty/libev/.travis.yml diff --git a/dap-sdk/net/client/libev/CMakeLists.txt b/3rdparty/libev/CMakeLists.txt similarity index 100% rename from dap-sdk/net/client/libev/CMakeLists.txt rename to 3rdparty/libev/CMakeLists.txt diff --git a/dap-sdk/net/client/libev/Changes b/3rdparty/libev/Changes similarity index 100% rename from dap-sdk/net/client/libev/Changes rename to 3rdparty/libev/Changes diff --git a/dap-sdk/net/client/libev/LICENSE b/3rdparty/libev/LICENSE similarity index 100% rename from dap-sdk/net/client/libev/LICENSE rename to 3rdparty/libev/LICENSE diff --git a/dap-sdk/net/client/libev/Makefile.am b/3rdparty/libev/Makefile.am similarity index 100% rename from dap-sdk/net/client/libev/Makefile.am rename to 3rdparty/libev/Makefile.am diff --git a/dap-sdk/net/client/libev/Makefile.in b/3rdparty/libev/Makefile.in similarity index 100% rename from dap-sdk/net/client/libev/Makefile.in rename to 3rdparty/libev/Makefile.in diff --git a/dap-sdk/net/client/libev/README b/3rdparty/libev/README similarity index 100% rename from dap-sdk/net/client/libev/README rename to 3rdparty/libev/README diff --git a/dap-sdk/net/client/libev/Symbols.ev b/3rdparty/libev/Symbols.ev similarity index 100% rename from dap-sdk/net/client/libev/Symbols.ev rename to 3rdparty/libev/Symbols.ev diff --git a/dap-sdk/net/client/libev/Symbols.event b/3rdparty/libev/Symbols.event similarity index 100% rename from dap-sdk/net/client/libev/Symbols.event rename to 3rdparty/libev/Symbols.event diff --git a/dap-sdk/net/client/libev/aclocal.m4 b/3rdparty/libev/aclocal.m4 similarity index 100% rename from dap-sdk/net/client/libev/aclocal.m4 rename to 3rdparty/libev/aclocal.m4 diff --git a/dap-sdk/net/client/libev/autogen.sh b/3rdparty/libev/autogen.sh similarity index 100% rename from dap-sdk/net/client/libev/autogen.sh rename to 3rdparty/libev/autogen.sh diff --git a/dap-sdk/net/client/libev/cmake/configure.cmake b/3rdparty/libev/cmake/configure.cmake similarity index 100% rename from dap-sdk/net/client/libev/cmake/configure.cmake rename to 3rdparty/libev/cmake/configure.cmake diff --git a/dap-sdk/net/client/libev/cmake/dist.cmake b/3rdparty/libev/cmake/dist.cmake similarity index 100% rename from dap-sdk/net/client/libev/cmake/dist.cmake rename to 3rdparty/libev/cmake/dist.cmake diff --git a/dap-sdk/net/client/libev/config.guess.cdbs-orig b/3rdparty/libev/config.guess.cdbs-orig similarity index 100% rename from dap-sdk/net/client/libev/config.guess.cdbs-orig rename to 3rdparty/libev/config.guess.cdbs-orig diff --git a/dap-sdk/net/client/libev/config.h.cmake b/3rdparty/libev/config.h.cmake similarity index 100% rename from dap-sdk/net/client/libev/config.h.cmake rename to 3rdparty/libev/config.h.cmake diff --git a/dap-sdk/net/client/libev/config.h.in b/3rdparty/libev/config.h.in similarity index 100% rename from dap-sdk/net/client/libev/config.h.in rename to 3rdparty/libev/config.h.in diff --git a/dap-sdk/net/client/libev/config.sub.cdbs-orig b/3rdparty/libev/config.sub.cdbs-orig similarity index 100% rename from dap-sdk/net/client/libev/config.sub.cdbs-orig rename to 3rdparty/libev/config.sub.cdbs-orig diff --git a/dap-sdk/net/client/libev/configure b/3rdparty/libev/configure similarity index 100% rename from dap-sdk/net/client/libev/configure rename to 3rdparty/libev/configure diff --git a/dap-sdk/net/client/libev/configure.ac b/3rdparty/libev/configure.ac similarity index 100% rename from dap-sdk/net/client/libev/configure.ac rename to 3rdparty/libev/configure.ac diff --git a/dap-sdk/net/client/libev/depcomp b/3rdparty/libev/depcomp similarity index 100% rename from dap-sdk/net/client/libev/depcomp rename to 3rdparty/libev/depcomp diff --git a/dap-sdk/net/client/libev/dist.info b/3rdparty/libev/dist.info similarity index 100% rename from dap-sdk/net/client/libev/dist.info rename to 3rdparty/libev/dist.info diff --git a/dap-sdk/net/client/libev/ev++.h b/3rdparty/libev/ev++.h similarity index 100% rename from dap-sdk/net/client/libev/ev++.h rename to 3rdparty/libev/ev++.h diff --git a/dap-sdk/net/client/libev/ev.3 b/3rdparty/libev/ev.3 similarity index 100% rename from dap-sdk/net/client/libev/ev.3 rename to 3rdparty/libev/ev.3 diff --git a/dap-sdk/net/client/libev/ev.c b/3rdparty/libev/ev.c similarity index 100% rename from dap-sdk/net/client/libev/ev.c rename to 3rdparty/libev/ev.c diff --git a/dap-sdk/net/client/libev/ev.h b/3rdparty/libev/ev.h similarity index 100% rename from dap-sdk/net/client/libev/ev.h rename to 3rdparty/libev/ev.h diff --git a/dap-sdk/net/client/libev/ev.pod b/3rdparty/libev/ev.pod similarity index 100% rename from dap-sdk/net/client/libev/ev.pod rename to 3rdparty/libev/ev.pod diff --git a/dap-sdk/net/client/libev/ev_epoll.c b/3rdparty/libev/ev_epoll.c similarity index 100% rename from dap-sdk/net/client/libev/ev_epoll.c rename to 3rdparty/libev/ev_epoll.c diff --git a/dap-sdk/net/client/libev/ev_kqueue.c b/3rdparty/libev/ev_kqueue.c similarity index 100% rename from dap-sdk/net/client/libev/ev_kqueue.c rename to 3rdparty/libev/ev_kqueue.c diff --git a/dap-sdk/net/client/libev/ev_poll.c b/3rdparty/libev/ev_poll.c similarity index 100% rename from dap-sdk/net/client/libev/ev_poll.c rename to 3rdparty/libev/ev_poll.c diff --git a/dap-sdk/net/client/libev/ev_port.c b/3rdparty/libev/ev_port.c similarity index 100% rename from dap-sdk/net/client/libev/ev_port.c rename to 3rdparty/libev/ev_port.c diff --git a/dap-sdk/net/client/libev/ev_select.c b/3rdparty/libev/ev_select.c similarity index 100% rename from dap-sdk/net/client/libev/ev_select.c rename to 3rdparty/libev/ev_select.c diff --git a/dap-sdk/net/client/libev/ev_vars.h b/3rdparty/libev/ev_vars.h similarity index 100% rename from dap-sdk/net/client/libev/ev_vars.h rename to 3rdparty/libev/ev_vars.h diff --git a/dap-sdk/net/client/libev/ev_win32.c b/3rdparty/libev/ev_win32.c similarity index 100% rename from dap-sdk/net/client/libev/ev_win32.c rename to 3rdparty/libev/ev_win32.c diff --git a/dap-sdk/net/client/libev/ev_wrap.h b/3rdparty/libev/ev_wrap.h similarity index 100% rename from dap-sdk/net/client/libev/ev_wrap.h rename to 3rdparty/libev/ev_wrap.h diff --git a/dap-sdk/net/client/libev/event.c b/3rdparty/libev/event.c similarity index 100% rename from dap-sdk/net/client/libev/event.c rename to 3rdparty/libev/event.c diff --git a/dap-sdk/net/client/libev/event.h b/3rdparty/libev/event.h similarity index 100% rename from dap-sdk/net/client/libev/event.h rename to 3rdparty/libev/event.h diff --git a/dap-sdk/net/client/libev/install-sh b/3rdparty/libev/install-sh similarity index 100% rename from dap-sdk/net/client/libev/install-sh rename to 3rdparty/libev/install-sh diff --git a/dap-sdk/net/client/libev/libev.m4 b/3rdparty/libev/libev.m4 similarity index 100% rename from dap-sdk/net/client/libev/libev.m4 rename to 3rdparty/libev/libev.m4 diff --git a/dap-sdk/net/client/libev/ltmain.sh b/3rdparty/libev/ltmain.sh similarity index 100% rename from dap-sdk/net/client/libev/ltmain.sh rename to 3rdparty/libev/ltmain.sh diff --git a/dap-sdk/net/client/libev/missing b/3rdparty/libev/missing similarity index 100% rename from dap-sdk/net/client/libev/missing rename to 3rdparty/libev/missing diff --git a/dap-sdk/net/client/libev/mkinstalldirs b/3rdparty/libev/mkinstalldirs similarity index 100% rename from dap-sdk/net/client/libev/mkinstalldirs rename to 3rdparty/libev/mkinstalldirs diff --git a/dap-sdk/net/client/libev/tmp/config.h b/3rdparty/libev/tmp/config.h similarity index 100% rename from dap-sdk/net/client/libev/tmp/config.h rename to 3rdparty/libev/tmp/config.h diff --git a/CMakeLists.txt b/CMakeLists.txt index bd08eb0f362882d6fd40e075b9fb0cb6f8051f86..bbe7fb7e2160df35f771379001282c1aa9cf83e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,8 @@ include(cmake/OS_Detection.cmake) add_definitions ("-DCELLFRAME_SDK_VERSION=\"${CELLFRAME_SDK_NATIVE_VERSION}\"") add_subdirectory(dap-sdk) +add_subdirectory(3rdparty/monero_crypto) +add_subdirectory(3rdparty/cuttdb) add_subdirectory(modules/) add_library(${PROJECT_NAME} STATIC cellframe-sdk.c) @@ -19,7 +21,7 @@ if(NOT (WIN32)) dap_chain_net dap_chain_net_srv dap_chain_net_srv_vpn dap_chain_net_srv_app dap_chain_net_srv_app_db dap_chain_net_srv_datum dap_chain_net_srv_datum_pool - dap_chain_wallet dap_chain_global_db dap_chain_mempool dap_chain_gdb m magic + dap_chain_wallet dap_chain_global_db dap_chain_mempool dap_chain_cs_none m magic ) else() target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_crypto dap_server_core dap_enc_server dap_udp_server dap_session @@ -29,7 +31,7 @@ else() dap_chain_net dap_chain_net_srv dap_chain_net_srv_app dap_chain_net_srv_app_db dap_chain_net_srv_datum dap_chain_net_srv_datum_pool - dap_chain_wallet dap_chain_global_db dap_chain_mempool dap_chain_gdb + dap_chain_wallet dap_chain_global_db dap_chain_mempool dap_chain_cs_none ) endif() #target_link_libraries(${PROJECT_NAME} dap_core dap_crypto) diff --git a/dap-sdk/CMakeLists.txt b/dap-sdk/CMakeLists.txt index 390da539f5a74786caf6f6add9ff7567b9e795bc..c8f8276289370a22a3b1da81b58a62b64dbe43d5 100644 --- a/dap-sdk/CMakeLists.txt +++ b/dap-sdk/CMakeLists.txt @@ -1,33 +1,12 @@ -add_subdirectory(libdap) -add_subdirectory(libdap-app-cli) -add_subdirectory(libdap-crypto) -add_subdirectory(libdap-chain) -add_subdirectory(libdap-chain-common) -add_subdirectory(libdap-chain-crypto) -add_subdirectory(libdap-chain-wallet) -add_subdirectory(libdap-chain-mempool) -add_subdirectory(libdap-chain-net) -add_subdirectory(libdap-server-core) -add_subdirectory(libdap-chain-global-db) -add_subdirectory(libdap-client) -add_subdirectory(libdap-server) -add_subdirectory(libdap-stream) -add_subdirectory(libdap-stream-ch) -add_subdirectory(libdap-stream-ch-chain-net) -add_subdirectory(libdap-stream-ch-chain) -add_subdirectory(libdap-server-udp) -add_subdirectory(libdap-chain-net-srv) -add_subdirectory(libdap-chain-net-srv-app) -add_subdirectory(libdap-chain-net-srv-app-db) -add_subdirectory(libdap-chain-net-srv-datum) -add_subdirectory(libdap-chain-net-srv-datum-pool) -if(NOT (WIN32)) - add_subdirectory(libdap-chain-net-srv-vpn) -endif() +# Core +add_subdirectory(core) -add_subdirectory(libdap-chain-gdb) -add_subdirectory(libdap-stream-ch-chain-net-srv) -add_subdirectory(libdap-chain-cs-dag) -add_subdirectory(libdap-chain-cs-dag-poa) -add_subdirectory(libdap-chain-cs-dag-pos) +# Cryptography +add_subdirectory(crypto) +# Networking +add_subdirectory(net/core) +add_subdirectory(net/client) +add_subdirectory(net/server) +add_subdirectory(net/server-udp) +add_subdirectory(net/stream) diff --git a/dap-sdk/core/.gitignore b/dap-sdk/core/.gitignore deleted file mode 100755 index ef34ab163699ede25ec1b4a8717e6f4a33bce0a9..0000000000000000000000000000000000000000 --- a/dap-sdk/core/.gitignore +++ /dev/null @@ -1,60 +0,0 @@ -# Prerequisites -build/* -test/build -*.d -*.txt.user -*.txt.user.* -*.autosave -# Object files -*.o -*.ko -*.obj -*.elf - -# Linker output -*.ilk -*.map -*.exp - -# Precompiled Headers -*.gch -*.pch - -# Libraries -*.lib -*.a -*.la -*.lo - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - -# Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex - -# Debug files -*.dSYM/ -*.su -*.idb -*.pdb - -# Kernel Module Compile Results -*.mod* -*.cmd -.tmp_versions/ -modules.order -Module.symvers -Mkfile.old -dkms.conf -/.project -/.cproject -/kelvin-node_logs.txt -/build/ diff --git a/dap-sdk/core/.travis.yml b/dap-sdk/core/.travis.yml deleted file mode 100755 index d09034d2bf073b6f7ea4384f99c4665df5c6b77a..0000000000000000000000000000000000000000 --- a/dap-sdk/core/.travis.yml +++ /dev/null @@ -1,26 +0,0 @@ -sudo: required -language: cpp -compiler: gcc -dist: xenial -notifications: - email: false - -before_install: - - git submodule init - - git submodule update --recursive - -script: - - sudo service network-manager start - - mkdir build - - cd build - - cmake -DBUILD_DAP_TESTS=ON ../ - - make - - ctest --verbose - -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - network-manager - diff --git a/dap-sdk/core/LICENSE b/dap-sdk/core/LICENSE deleted file mode 100755 index 65c5ca88a67c30becee01c5a8816d964b03862f9..0000000000000000000000000000000000000000 --- a/dap-sdk/core/LICENSE +++ /dev/null @@ -1,165 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - 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 that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU 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 as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/dap-sdk/core/README.md b/dap-sdk/core/README.md deleted file mode 100755 index c25194558d83883254ed20f723f59fa689697a29..0000000000000000000000000000000000000000 --- a/dap-sdk/core/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# libdap -Deus Applications Prototypes: core library - -[](https://travis-ci.com/kelvinblockchain/libdap) - -## Build and Run tests: -``` -mkdir build -cd build -cmake -DBUILD_DAP_TESTS=ON ../ -make -ctest --verbose -``` - diff --git a/dap-sdk/crypto/.gitignore b/dap-sdk/crypto/.gitignore deleted file mode 100755 index c6127b38c1aa25968a88db3940604d41529e4cf5..0000000000000000000000000000000000000000 --- a/dap-sdk/crypto/.gitignore +++ /dev/null @@ -1,52 +0,0 @@ -# Prerequisites -*.d - -# Object files -*.o -*.ko -*.obj -*.elf - -# Linker output -*.ilk -*.map -*.exp - -# Precompiled Headers -*.gch -*.pch - -# Libraries -*.lib -*.a -*.la -*.lo - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - -# Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex - -# Debug files -*.dSYM/ -*.su -*.idb -*.pdb - -# Kernel Module Compile Results -*.mod* -*.cmd -.tmp_versions/ -modules.order -Module.symvers -Mkfile.old -dkms.conf diff --git a/dap-sdk/crypto/.travis.yml b/dap-sdk/crypto/.travis.yml deleted file mode 100755 index a79b9f067d1021b51a94246a142a3dbcda6612d4..0000000000000000000000000000000000000000 --- a/dap-sdk/crypto/.travis.yml +++ /dev/null @@ -1,26 +0,0 @@ -sudo: required -language: cpp -compiler: gcc -dist: xenial -notifications: - email: false - -before_install: - - git submodule init - - git submodule update --recursive - -script: - - sudo service network-manager start - - mkdir build - - cd build - - cmake -DBUILD_CRYPTO_TESTS=ON ../ - - make - - ctest --verbose - -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - network-manager - diff --git a/dap-sdk/crypto/CMakeLists.txt.user b/dap-sdk/crypto/CMakeLists.txt.user deleted file mode 100644 index 82fe0bb1172c4d372887e194a384ea4dc35889fe..0000000000000000000000000000000000000000 --- a/dap-sdk/crypto/CMakeLists.txt.user +++ /dev/null @@ -1,424 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE QtCreatorProject> -<!-- Written by QtCreator 4.11.2, 2020-04-29T10:52:27. --> -<qtcreator> - <data> - <variable>EnvironmentId</variable> - <value type="QByteArray">{11b3ace2-edb6-4ae7-8e1b-fce9fa91893f}</value> - </data> - <data> - <variable>ProjectExplorer.Project.ActiveTarget</variable> - <value type="int">0</value> - </data> - <data> - <variable>ProjectExplorer.Project.EditorSettings</variable> - <valuemap type="QVariantMap"> - <value type="bool" key="EditorConfiguration.AutoIndent">true</value> - <value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value> - <value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value> - <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0"> - <value type="QString" key="language">Cpp</value> - <valuemap type="QVariantMap" key="value"> - <value type="QByteArray" key="CurrentPreferences">CppGlobal</value> - </valuemap> - </valuemap> - <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1"> - <value type="QString" key="language">QmlJS</value> - <valuemap type="QVariantMap" key="value"> - <value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value> - </valuemap> - </valuemap> - <value type="int" key="EditorConfiguration.CodeStyle.Count">2</value> - <value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value> - <value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value> - <value type="int" key="EditorConfiguration.IndentSize">4</value> - <value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value> - <value type="int" key="EditorConfiguration.MarginColumn">80</value> - <value type="bool" key="EditorConfiguration.MouseHiding">true</value> - <value type="bool" key="EditorConfiguration.MouseNavigation">true</value> - <value type="int" key="EditorConfiguration.PaddingMode">1</value> - <value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value> - <value type="bool" key="EditorConfiguration.ShowMargin">false</value> - <value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value> - <value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value> - <value type="bool" key="EditorConfiguration.SpacesForTabs">true</value> - <value type="int" key="EditorConfiguration.TabKeyBehavior">0</value> - <value type="int" key="EditorConfiguration.TabSize">8</value> - <value type="bool" key="EditorConfiguration.UseGlobal">true</value> - <value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value> - <value type="bool" key="EditorConfiguration.addFinalNewLine">true</value> - <value type="bool" key="EditorConfiguration.cleanIndentation">true</value> - <value type="bool" key="EditorConfiguration.cleanWhitespace">true</value> - <value type="bool" key="EditorConfiguration.inEntireDocument">false</value> - </valuemap> - </data> - <data> - <variable>ProjectExplorer.Project.PluginSettings</variable> - <valuemap type="QVariantMap"> - <valuelist type="QVariantList" key="ClangCodeModel.CustomCommandLineKey"> - <value type="QString">-fno-delayed-template-parsing</value> - </valuelist> - <value type="bool" key="ClangCodeModel.UseGlobalConfig">true</value> - </valuemap> - </data> - <data> - <variable>ProjectExplorer.Project.Target.0</variable> - <valuemap type="QVariantMap"> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop Qt 5.14.2 MinGW 32-bit</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop Qt 5.14.2 MinGW 32-bit</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">qt.qt5.5142.win32_mingw73_kit</value> - <value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value> - <value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value> - <value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value> - <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0"> - <valuelist type="QVariantList" key="CMake.Configuration"> - <value type="QString">BUILD_CRYPTO_TESTS:BOOL=ON</value> - <value type="QString">CMAKE_BUILD_TYPE:STRING=Debug</value> - <value type="QString">CMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx}</value> - <value type="QString">CMAKE_C_COMPILER:STRING=%{Compiler:Executable:C}</value> - <value type="QString">CMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX}</value> - <value type="QString">QT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable}</value> - </valuelist> - <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:/qt_proj/build-libdap-crypto_new-Desktop_Qt_5_14_2_MinGW_32_bit-Debug</value> - <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0"> - <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> - <value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value> - <valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets"> - <value type="QString">all</value> - </valuelist> - <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value> - </valuemap> - <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value> - </valuemap> - <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1"> - <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> - <value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value> - <valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets"> - <value type="QString">clean</value> - </valuelist> - <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value> - </valuemap> - <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value> - </valuemap> - <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value> - <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value> - <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value> - </valuemap> - <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1"> - <valuelist type="QVariantList" key="CMake.Configuration"> - <value type="QString">CMAKE_BUILD_TYPE:STRING=Release</value> - <value type="QString">CMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx}</value> - <value type="QString">CMAKE_C_COMPILER:STRING=%{Compiler:Executable:C}</value> - <value type="QString">CMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX}</value> - <value type="QString">QT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable}</value> - </valuelist> - <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:/qt_proj/build-libdap-crypto_new-Desktop_Qt_5_14_2_MinGW_32_bit-Release</value> - <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0"> - <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> - <value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value> - <valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets"> - <value type="QString">all</value> - </valuelist> - <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value> - </valuemap> - <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value> - </valuemap> - <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1"> - <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> - <value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value> - <valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets"> - <value type="QString">clean</value> - </valuelist> - <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value> - </valuemap> - <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value> - </valuemap> - <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value> - <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value> - <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value> - </valuemap> - <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2"> - <valuelist type="QVariantList" key="CMake.Configuration"> - <value type="QString">CMAKE_BUILD_TYPE:STRING=RelWithDebInfo</value> - <value type="QString">CMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx}</value> - <value type="QString">CMAKE_C_COMPILER:STRING=%{Compiler:Executable:C}</value> - <value type="QString">CMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX}</value> - <value type="QString">QT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable}</value> - </valuelist> - <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:/qt_proj/build-libdap-crypto_new-Desktop_Qt_5_14_2_MinGW_32_bit-RelWithDebInfo</value> - <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0"> - <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> - <value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value> - <valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets"> - <value type="QString">all</value> - </valuelist> - <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value> - </valuemap> - <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value> - </valuemap> - <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1"> - <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> - <value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value> - <valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets"> - <value type="QString">clean</value> - </valuelist> - <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value> - </valuemap> - <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value> - </valuemap> - <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value> - <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value> - <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release with Debug Information</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value> - </valuemap> - <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.3"> - <valuelist type="QVariantList" key="CMake.Configuration"> - <value type="QString">CMAKE_BUILD_TYPE:STRING=MinSizeRel</value> - <value type="QString">CMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx}</value> - <value type="QString">CMAKE_C_COMPILER:STRING=%{Compiler:Executable:C}</value> - <value type="QString">CMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX}</value> - <value type="QString">QT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable}</value> - </valuelist> - <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:/qt_proj/build-libdap-crypto_new-Desktop_Qt_5_14_2_MinGW_32_bit-MinSizeRel</value> - <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0"> - <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> - <value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value> - <valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets"> - <value type="QString">all</value> - </valuelist> - <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value> - </valuemap> - <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value> - </valuemap> - <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1"> - <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> - <value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value> - <valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets"> - <value type="QString">clean</value> - </valuelist> - <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value> - </valuemap> - <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value> - </valuemap> - <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value> - <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value> - <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Minimum Size Release</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value> - </valuemap> - <value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">4</value> - <valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0"> - <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0"> - <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value> - </valuemap> - <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value> - </valuemap> - <value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value> - <valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/> - <valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0"> - <value type="QString" key="Analyzer.Perf.CallgraphMode">dwarf</value> - <valuelist type="QVariantList" key="Analyzer.Perf.Events"> - <value type="QString">cpu-cycles</value> - </valuelist> - <valuelist type="QVariantList" key="Analyzer.Perf.ExtraArguments"/> - <value type="int" key="Analyzer.Perf.Frequency">250</value> - <valuelist type="QVariantList" key="Analyzer.Perf.RecordArguments"> - <value type="QString">-e</value> - <value type="QString">cpu-cycles</value> - <value type="QString">--call-graph</value> - <value type="QString">dwarf,4096</value> - <value type="QString">-F</value> - <value type="QString">250</value> - </valuelist> - <value type="QString" key="Analyzer.Perf.SampleMode">-F</value> - <value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value> - <value type="int" key="Analyzer.Perf.StackSize">4096</value> - <value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value> - <value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value> - <value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value> - <value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value> - <value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value> - <valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/> - <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value> - <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value> - <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value> - <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value> - <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value> - <value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value> - <value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value> - <value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value> - <value type="QString" key="Analyzer.Valgrind.KCachegrindExecutable">kcachegrind</value> - <value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value> - <value type="int" key="Analyzer.Valgrind.NumCallers">25</value> - <valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/> - <value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value> - <value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value> - <value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value> - <value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value> - <value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value> - <valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds"> - <value type="int">0</value> - <value type="int">1</value> - <value type="int">2</value> - <value type="int">3</value> - <value type="int">4</value> - <value type="int">5</value> - <value type="int">6</value> - <value type="int">7</value> - <value type="int">8</value> - <value type="int">9</value> - <value type="int">10</value> - <value type="int">11</value> - <value type="int">12</value> - <value type="int">13</value> - <value type="int">14</value> - </valuelist> - <value type="int" key="PE.EnvironmentAspect.Base">2</value> - <valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">crypto-test</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.crypto-test</value> - <value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">crypto-test</value> - <value type="QString" key="RunConfiguration.Arguments"></value> - <value type="bool" key="RunConfiguration.Arguments.multi">false</value> - <value type="QString" key="RunConfiguration.OverrideDebuggerStartup"></value> - <value type="bool" key="RunConfiguration.UseCppDebugger">false</value> - <value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value> - <value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value> - <value type="bool" key="RunConfiguration.UseMultiProcess">false</value> - <value type="bool" key="RunConfiguration.UseQmlDebugger">false</value> - <value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value> - <value type="QString" key="RunConfiguration.WorkingDirectory"></value> - <value type="QString" key="RunConfiguration.WorkingDirectory.default"></value> - </valuemap> - <valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.1"> - <value type="QString" key="Analyzer.Perf.CallgraphMode">dwarf</value> - <valuelist type="QVariantList" key="Analyzer.Perf.Events"> - <value type="QString">cpu-cycles</value> - </valuelist> - <valuelist type="QVariantList" key="Analyzer.Perf.ExtraArguments"/> - <value type="int" key="Analyzer.Perf.Frequency">250</value> - <valuelist type="QVariantList" key="Analyzer.Perf.RecordArguments"> - <value type="QString">-e</value> - <value type="QString">cpu-cycles</value> - <value type="QString">--call-graph</value> - <value type="QString">dwarf,4096</value> - <value type="QString">-F</value> - <value type="QString">250</value> - </valuelist> - <value type="QString" key="Analyzer.Perf.SampleMode">-F</value> - <value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value> - <value type="int" key="Analyzer.Perf.StackSize">4096</value> - <value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value> - <value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value> - <value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value> - <value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value> - <value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value> - <valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/> - <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value> - <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value> - <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value> - <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value> - <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value> - <value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value> - <value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value> - <value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value> - <value type="QString" key="Analyzer.Valgrind.KCachegrindExecutable">kcachegrind</value> - <value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value> - <value type="int" key="Analyzer.Valgrind.NumCallers">25</value> - <valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/> - <value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value> - <value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value> - <value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value> - <value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value> - <value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value> - <valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds"> - <value type="int">0</value> - <value type="int">1</value> - <value type="int">2</value> - <value type="int">3</value> - <value type="int">4</value> - <value type="int">5</value> - <value type="int">6</value> - <value type="int">7</value> - <value type="int">8</value> - <value type="int">9</value> - <value type="int">10</value> - <value type="int">11</value> - <value type="int">12</value> - <value type="int">13</value> - <value type="int">14</value> - </valuelist> - <value type="int" key="PE.EnvironmentAspect.Base">2</value> - <valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">crypto_cert_test</value> - <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.crypto_cert_test</value> - <value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">crypto_cert_test</value> - <value type="QString" key="RunConfiguration.Arguments"></value> - <value type="bool" key="RunConfiguration.Arguments.multi">false</value> - <value type="QString" key="RunConfiguration.OverrideDebuggerStartup"></value> - <value type="bool" key="RunConfiguration.UseCppDebugger">false</value> - <value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value> - <value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value> - <value type="bool" key="RunConfiguration.UseMultiProcess">false</value> - <value type="bool" key="RunConfiguration.UseQmlDebugger">false</value> - <value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value> - <value type="QString" key="RunConfiguration.WorkingDirectory"></value> - <value type="QString" key="RunConfiguration.WorkingDirectory.default"></value> - </valuemap> - <value type="int" key="ProjectExplorer.Target.RunConfigurationCount">2</value> - </valuemap> - </data> - <data> - <variable>ProjectExplorer.Project.TargetCount</variable> - <value type="int">1</value> - </data> - <data> - <variable>ProjectExplorer.Project.Updater.FileVersion</variable> - <value type="int">22</value> - </data> - <data> - <variable>Version</variable> - <value type="int">22</value> - </data> -</qtcreator> diff --git a/dap-sdk/crypto/LICENSE b/dap-sdk/crypto/LICENSE deleted file mode 100755 index 0a041280bd00a9d068f503b8ee7ce35214bd24a1..0000000000000000000000000000000000000000 --- a/dap-sdk/crypto/LICENSE +++ /dev/null @@ -1,165 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - 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 that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU 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 as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/dap-sdk/crypto/Post-Quantum Key Exchange for the Internet.pdf b/dap-sdk/crypto/Post-Quantum Key Exchange for the Internet.pdf deleted file mode 100755 index a77225afa8a781d0df5e21bbaf4bf32c314299a8..0000000000000000000000000000000000000000 Binary files a/dap-sdk/crypto/Post-Quantum Key Exchange for the Internet.pdf and /dev/null differ diff --git a/dap-sdk/crypto/README.md b/dap-sdk/crypto/README.md deleted file mode 100755 index 8f6b07c1469e6116aaa8cc738f6c855779728f33..0000000000000000000000000000000000000000 --- a/dap-sdk/crypto/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# libdap -Deus Applications Prototypes: core library - -[](https://travis-ci.com/cellframe/libdap) - -## Build and Run tests: -``` -mkdir build -cd build -cmake -DBUILD_DAP_TESTS=ON ../ -make -ctest --verbose -``` - diff --git a/dap-sdk/net/client/.gitignore b/dap-sdk/net/client/.gitignore deleted file mode 100755 index 682ea68a9b8d40ade2bb762dc162848d98d6287d..0000000000000000000000000000000000000000 --- a/dap-sdk/net/client/.gitignore +++ /dev/null @@ -1,55 +0,0 @@ -# Prerequisites -*.d - -# Object files -*.o -*.ko -*.obj -*.elf - -# Linker output -*.ilk -*.map -*.exp - -# Precompiled Headers -*.gch -*.pch - -# Libraries -*.lib -*.a -*.la -*.lo - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - -# Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex - -# Debug files -*.dSYM/ -*.su -*.idb -*.pdb - -# Kernel Module Compile Results -*.mod* -*.cmd -.tmp_versions/ -modules.order -Module.symvers -Mkfile.old -dkms.conf -/build/ -/.cproject -/.project diff --git a/dap-sdk/net/client/.travis.yml b/dap-sdk/net/client/.travis.yml deleted file mode 100755 index e7bbd5baf1095dcbd0ab5679409cda3224a8383d..0000000000000000000000000000000000000000 --- a/dap-sdk/net/client/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -sudo: required -language: c -compiler: gcc -dist: xenial -notifications: - email: false - -before_install: - - git submodule init - - git submodule update - -script: - - mkdir build - - cd build - - cmake -DBUILD_DAP_CLIENT_TESTS=ON ../ - - make - - ctest --verbose - -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - libjson-c-dev - - libev-dev - - libmagic-dev - diff --git a/dap-sdk/net/client/CMakeLists.txt b/dap-sdk/net/client/CMakeLists.txt old mode 100755 new mode 100644 index b6b49e7b8f03e8145a5dbb7b26d9738fc296cc99..82df978c4995d6b69d1640134cbebe8d2383c941 --- a/dap-sdk/net/client/CMakeLists.txt +++ b/dap-sdk/net/client/CMakeLists.txt @@ -2,46 +2,12 @@ cmake_minimum_required(VERSION 3.0) project(dap_client) add_definitions ("-D_GNU_SOURCE") -if(NOT SUBMODULES_NO_BUILD) - if ( NOT ( TARGET dap_core ) ) - add_subdirectory(libdap) - endif() - - if ( NOT ( TARGET dap_crypto ) ) - add_subdirectory(libdap-crypto) - endif() - - if ( NOT ( TARGET dap_server_core ) ) - add_subdirectory(libdap-server-core) - endif() - - if ( NOT ( TARGET dap_server ) ) - add_subdirectory(libdap-server) - endif() - - if ( NOT ( TARGET dap_udp_server ) ) - add_subdirectory(libdap-server-udp) - endif() - - if ( NOT ( TARGET libdap-stream ) ) - add_subdirectory(libdap-stream) - endif() - - if ( NOT ( TARGET dap_stream_ch ) ) - add_subdirectory(libdap-stream-ch) - endif() - - -endif() - -file(GLOB DAP_CLIENT_SOURCES src/*.c) -file(GLOB DAP_CLIENT_HEADERS include/*.h) +file(GLOB DAP_CLIENT_SOURCES FILES *.c) +file(GLOB DAP_CLIENT_HEADERS FILES include/*.h) if(WIN32) - include_directories(../3rdparty/wepoll/) - include_directories(../3rdparty/uthash/src/) - #include_directories(../3rdparty/curl/include/) - #add_subdirectory(libev) + include_directories(../../../3rdparty/wepoll/) + include_directories(../../../3rdparty/uthash/src/) endif() add_library(${PROJECT_NAME} STATIC ${DAP_CLIENT_HEADERS} ${DAP_CLIENT_SOURCES}) @@ -54,7 +20,7 @@ endif() target_include_directories(${PROJECT_NAME} PUBLIC include) -target_include_directories(${PROJECT_NAME} PRIVATE src) +target_include_directories(${PROJECT_NAME} PRIVATE .) if (${BUILD_DAP_CLIENT_TESTS} MATCHES ON) diff --git a/dap-sdk/net/client/LICENSE b/dap-sdk/net/client/LICENSE deleted file mode 100755 index 0a041280bd00a9d068f503b8ee7ce35214bd24a1..0000000000000000000000000000000000000000 --- a/dap-sdk/net/client/LICENSE +++ /dev/null @@ -1,165 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - 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 that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU 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 as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/dap-sdk/net/client/README.md b/dap-sdk/net/client/README.md deleted file mode 100755 index a177e1fdd045267fc5b8e3cc670428906a5f8c97..0000000000000000000000000000000000000000 --- a/dap-sdk/net/client/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# libdap-client - -[](https://travis-ci.com/kelvinblockchain/libdap-client) - -DAP client diff --git a/dap-sdk/net/client/src/dap_client.c b/dap-sdk/net/client/dap_client.c similarity index 100% rename from dap-sdk/net/client/src/dap_client.c rename to dap-sdk/net/client/dap_client.c diff --git a/dap-sdk/net/client/src/dap_client_http.c b/dap-sdk/net/client/dap_client_http.c similarity index 100% rename from dap-sdk/net/client/src/dap_client_http.c rename to dap-sdk/net/client/dap_client_http.c diff --git a/dap-sdk/net/client/src/dap_client_pool.c b/dap-sdk/net/client/dap_client_pool.c similarity index 100% rename from dap-sdk/net/client/src/dap_client_pool.c rename to dap-sdk/net/client/dap_client_pool.c diff --git a/dap-sdk/net/client/src/dap_client_pvt.c b/dap-sdk/net/client/dap_client_pvt.c similarity index 100% rename from dap-sdk/net/client/src/dap_client_pvt.c rename to dap-sdk/net/client/dap_client_pvt.c diff --git a/dap-sdk/net/client/src/dap_client_pvt_hh.c b/dap-sdk/net/client/dap_client_pvt_hh.c similarity index 100% rename from dap-sdk/net/client/src/dap_client_pvt_hh.c rename to dap-sdk/net/client/dap_client_pvt_hh.c diff --git a/dap-sdk/net/client/include/dap_client.h b/dap-sdk/net/client/include/dap_client.h old mode 100755 new mode 100644 diff --git a/dap-sdk/net/client/include/dap_client_http.h b/dap-sdk/net/client/include/dap_client_http.h old mode 100755 new mode 100644 diff --git a/dap-sdk/net/client/include/dap_client_pool.h b/dap-sdk/net/client/include/dap_client_pool.h old mode 100755 new mode 100644 diff --git a/dap-sdk/net/client/include/dap_client_pvt.h b/dap-sdk/net/client/include/dap_client_pvt.h old mode 100755 new mode 100644 diff --git a/dap-sdk/net/core/.gitignore b/dap-sdk/net/core/.gitignore deleted file mode 100755 index ea462b27ee244839d596fea3b43f21e69e915b2b..0000000000000000000000000000000000000000 --- a/dap-sdk/net/core/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -build -*.txt.user - diff --git a/dap-sdk/net/core/.travis.yml b/dap-sdk/net/core/.travis.yml deleted file mode 100755 index c5aba3c2c639d08a8bc6f07069cad3e2b9b667a7..0000000000000000000000000000000000000000 --- a/dap-sdk/net/core/.travis.yml +++ /dev/null @@ -1,24 +0,0 @@ -language: c -compiler: gcc -dist: xenial -notifications: - email: false - -before_install: - - git submodule init - - git submodule update - -script: - - mkdir build - - cd build - - cmake -DBUILD_DAP_SERVER_CORE_TESTS=ON ../ - - make - - ctest --verbose - -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - libev-dev - - libmemcached-dev diff --git a/dap-sdk/net/core/CMakeLists.txt b/dap-sdk/net/core/CMakeLists.txt old mode 100755 new mode 100644 index fa70477e070998bd926da9c0365694fa2cc07485..3fee1612274f4bc85c73d8ae08951e48c19e1219 --- a/dap-sdk/net/core/CMakeLists.txt +++ b/dap-sdk/net/core/CMakeLists.txt @@ -5,36 +5,24 @@ set(CMAKE_C_STANDARD 11) add_definitions ("-D_GNU_SOURCE") -if(NOT SUBMODULES_NO_BUILD) - if ( NOT ( TARGET dap_core ) ) - add_subdirectory(libdap) - endif() - - if ( NOT ( TARGET dap_crypto ) ) - add_subdirectory(libdap-crypto) - endif() - -endif() - if(WIN32) - file(GLOB DAP_SERVER_CORE_SOURCES src/*.c ../3rdparty/wepoll/*.c) - file(GLOB DAP_SERVER_CORE_HEADERS include/*.h ../3rdparty/wepoll/*.h) + file(GLOB DAP_SERVER_CORE_SOURCES *.c ../../../3rdparty/wepoll/*.c) + file(GLOB DAP_SERVER_CORE_HEADERS include/*.h ../../../3rdparty/wepoll/*.h) else() - file(GLOB DAP_SERVER_CORE_SOURCES src/*.c) + file(GLOB DAP_SERVER_CORE_SOURCES *.c) file(GLOB DAP_SERVER_CORE_HEADERS include/*.h) endif() if(WIN32) - include_directories(../3rdparty/uthash/src/) - #include_directories(../3rdparty/curl/include/) - include_directories(../3rdparty/wepoll/) + include_directories(../../../3rdparty/uthash/src/) + include_directories(../../../3rdparty/wepoll/) endif() add_library(${PROJECT_NAME} STATIC ${DAP_SERVER_CORE_HEADERS} ${DAP_SERVER_CORE_SOURCES}) if(WIN32) target_link_libraries(${PROJECT_NAME} dap_core dap_crypto) - target_include_directories(${PROJECT_NAME} INTERFACE ../3rdparty/wepoll) + target_include_directories(${PROJECT_NAME} INTERFACE ../../../3rdparty/wepoll) endif() if(UNIX) diff --git a/dap-sdk/net/core/README.md b/dap-sdk/net/core/README.md deleted file mode 100755 index 6195103d43d2d68374b1decf37a0ef3f688c6c94..0000000000000000000000000000000000000000 --- a/dap-sdk/net/core/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# libdap-server-core - -[](https://travis-ci.com/kelvinblockchain/libdap-server-core) diff --git a/dap-sdk/net/core/src/dap_client_remote.c b/dap-sdk/net/core/dap_client_remote.c old mode 100755 new mode 100644 similarity index 100% rename from dap-sdk/net/core/src/dap_client_remote.c rename to dap-sdk/net/core/dap_client_remote.c diff --git a/dap-sdk/net/core/src/dap_events.c b/dap-sdk/net/core/dap_events.c old mode 100755 new mode 100644 similarity index 100% rename from dap-sdk/net/core/src/dap_events.c rename to dap-sdk/net/core/dap_events.c diff --git a/dap-sdk/net/core/src/dap_events_socket.c b/dap-sdk/net/core/dap_events_socket.c old mode 100755 new mode 100644 similarity index 100% rename from dap-sdk/net/core/src/dap_events_socket.c rename to dap-sdk/net/core/dap_events_socket.c diff --git a/dap-sdk/net/core/src/dap_server.c b/dap-sdk/net/core/dap_server.c old mode 100755 new mode 100644 similarity index 100% rename from dap-sdk/net/core/src/dap_server.c rename to dap-sdk/net/core/dap_server.c diff --git a/dap-sdk/net/core/src/dap_traffic_track.c b/dap-sdk/net/core/dap_traffic_track.c old mode 100755 new mode 100644 similarity index 100% rename from dap-sdk/net/core/src/dap_traffic_track.c rename to dap-sdk/net/core/dap_traffic_track.c diff --git a/dap-sdk/net/core/include/dap_client_remote.h b/dap-sdk/net/core/include/dap_client_remote.h old mode 100755 new mode 100644 diff --git a/dap-sdk/net/core/include/dap_events.h b/dap-sdk/net/core/include/dap_events.h old mode 100755 new mode 100644 diff --git a/dap-sdk/net/core/include/dap_events_socket.h b/dap-sdk/net/core/include/dap_events_socket.h old mode 100755 new mode 100644 diff --git a/dap-sdk/net/core/include/dap_server.h b/dap-sdk/net/core/include/dap_server.h old mode 100755 new mode 100644 diff --git a/dap-sdk/net/core/include/dap_traffic_track.h b/dap-sdk/net/core/include/dap_traffic_track.h old mode 100755 new mode 100644 diff --git a/dap-sdk/net/server-udp/.gitignore b/dap-sdk/net/server-udp/.gitignore deleted file mode 100755 index e8451f4157a6dbae7124d7380a2ebf1a0119f53f..0000000000000000000000000000000000000000 --- a/dap-sdk/net/server-udp/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -CMakeLists.txt.user -test/build diff --git a/dap-sdk/net/server-udp/.travis.yml b/dap-sdk/net/server-udp/.travis.yml deleted file mode 100755 index 256452d22b659f80791b9ef389c823db745803da..0000000000000000000000000000000000000000 --- a/dap-sdk/net/server-udp/.travis.yml +++ /dev/null @@ -1,25 +0,0 @@ -sudo: required -language: cpp -compiler: c -dist: xenial -notifications: - email: false - -before_install: - - git submodule init - - git submodule update --recursive - -script: - - mkdir build - - cd build - - cmake -DBUILD_DAP_UDP_SERVER_TESTS=ON ../ - - make - - ctest --verbose - -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - libev-dev - diff --git a/dap-sdk/net/server-udp/CMakeLists.txt b/dap-sdk/net/server-udp/CMakeLists.txt old mode 100755 new mode 100644 index 6e1e123bf79ab592cae3ac2d82494833fdb172fa..94dda44efb3ce2c785538f7a561881557d07ecdb --- a/dap-sdk/net/server-udp/CMakeLists.txt +++ b/dap-sdk/net/server-udp/CMakeLists.txt @@ -1,30 +1,13 @@ cmake_minimum_required(VERSION 3.1) project (dap_udp_server C) -if(NOT SUBMODULES_NO_BUILD) -# if ( NOT ( TARGET dap_server_core ) ) -# add_subdirectory(libdap-server-core) -# endif() - - if ( NOT ( TARGET dap_core ) ) - add_subdirectory(libdap) - endif() - - if ( NOT ( TARGET dap_server_core ) ) - add_subdirectory(libdap-server-core) - endif() - - enable_testing() - add_subdirectory(test) -endif() - -set(DAP_UDP_SERVER_SRCS dap_udp_server.c dap_udp_client.c dap_dns_server.c) -set(DAP_UDP_SERVER_HEADERS dap_udp_server.h dap_udp_client.h dap_dns_server.h) +file(GLOB DAP_UDP_SERVER_SRCS *.c) +file(GLOB DAP_UDP_SERVER_HEADERS include/*.h) if(WIN32) - include_directories(../3rdparty/wepoll/) - include_directories(../3rdparty/uthash/src/) + include_directories(../../../3rdparty/wepoll/) + include_directories(../../../3rdparty/uthash/src/) #include_directories(../3rdparty/curl/include/) endif() @@ -33,3 +16,4 @@ add_library(${PROJECT_NAME} STATIC ${DAP_UDP_SERVER_SRCS}) target_link_libraries(${PROJECT_NAME} dap_core dap_server_core dap_chain_net) target_include_directories(${PROJECT_NAME} INTERFACE .) +target_include_directories(${PROJECT_NAME} PUBLIC include) diff --git a/dap-sdk/net/server-udp/README.md b/dap-sdk/net/server-udp/README.md deleted file mode 100755 index fd721b1b5275b5e23bf6e83fb70f3dad69b08b0d..0000000000000000000000000000000000000000 --- a/dap-sdk/net/server-udp/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# libdap-server-udp - -[](https://travis-ci.com/kelvinblockchain/libdap-server-udp) diff --git a/dap-sdk/net/server-udp/dap_dns_server.c b/dap-sdk/net/server-udp/dap_dns_server.c old mode 100755 new mode 100644 diff --git a/dap-sdk/net/server-udp/dap_udp_client.c b/dap-sdk/net/server-udp/dap_udp_client.c old mode 100755 new mode 100644 diff --git a/dap-sdk/net/server-udp/dap_dns_server.h b/dap-sdk/net/server-udp/include/dap_dns_server.h old mode 100755 new mode 100644 similarity index 100% rename from dap-sdk/net/server-udp/dap_dns_server.h rename to dap-sdk/net/server-udp/include/dap_dns_server.h diff --git a/dap-sdk/net/server-udp/dap_udp_client.h b/dap-sdk/net/server-udp/include/dap_udp_client.h old mode 100755 new mode 100644 similarity index 100% rename from dap-sdk/net/server-udp/dap_udp_client.h rename to dap-sdk/net/server-udp/include/dap_udp_client.h diff --git a/dap-sdk/net/server-udp/dap_udp_server.h b/dap-sdk/net/server-udp/include/dap_udp_server.h old mode 100755 new mode 100644 similarity index 100% rename from dap-sdk/net/server-udp/dap_udp_server.h rename to dap-sdk/net/server-udp/include/dap_udp_server.h diff --git a/dap-sdk/net/server-udp/test/CMakeLists.txt b/dap-sdk/net/server-udp/test/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/dap-sdk/net/server-udp/test/main.c b/dap-sdk/net/server-udp/test/main.c old mode 100755 new mode 100644 diff --git a/dap-sdk/net/server/CMakeLists.txt b/dap-sdk/net/server/CMakeLists.txt old mode 100755 new mode 100644 index 47bfd5431cc43b87a279e8cbd0c756546caf19ae..dfc4ed963be9cd4d6bfd7e7d7dbaa46d5bbf32e8 --- a/dap-sdk/net/server/CMakeLists.txt +++ b/dap-sdk/net/server/CMakeLists.txt @@ -1,28 +1,8 @@ project(libdap-server C) cmake_minimum_required(VERSION 3.0) -if(NOT SUBMODULES_NO_BUILD) - if ( NOT ( TARGET dap_core ) ) - add_subdirectory(libdap) - endif() - - if ( NOT ( TARGET dap_crypto ) ) - add_subdirectory(libdap-crypto) - endif() - - if ( NOT ( TARGET dap_server_core ) ) - add_subdirectory(libdap-server-core) - endif() - -# if ( NOT ( TARGET dap_server_udp ) ) -# add_subdirectory(libdap-server-udp) -# endif() - -endif() - if (ANDROID) - add_subdirectory(libmagic) - add_subdirectory(curl) + add_subdirectory(../../../3rdparty/libmagic) endif() add_subdirectory(http_server) diff --git a/dap-sdk/net/server/enc_server/CMakeLists.txt b/dap-sdk/net/server/enc_server/CMakeLists.txt old mode 100755 new mode 100644 index 56365e5fe8532279a9aa35c7a338e0b50f79434f..5269d02b73514d27b09a7a4df058f5e4705d7f04 --- a/dap-sdk/net/server/enc_server/CMakeLists.txt +++ b/dap-sdk/net/server/enc_server/CMakeLists.txt @@ -1,7 +1,8 @@ cmake_minimum_required(VERSION 3.0) project(dap_enc_server C) -set(DAP_ENC_SERVER_SRCS dap_enc_http.c dap_enc_ks.c) +file(GLOB DAP_ENC_SERVER_SRCS FILES *.c) +file(GLOB DAP_ENC_SERVER_HDRS FILES include/*.h) if(WIN32) add_definitions ("-DUNDEBUG") @@ -12,11 +13,13 @@ if(WIN32) add_definitions ("-D_CRT_SECURE_NO_WARNINGS") add_definitions ("-DCURL_STATICLIB") - include_directories(../../3rdparty/wepoll/) - include_directories(../../3rdparty/uthash/src/) + include_directories(../../../../3rdparty/wepoll/) + include_directories(../../../../3rdparty/uthash/src/) endif() -add_library(${PROJECT_NAME} STATIC ${DAP_ENC_SERVER_SRCS}) +add_library(${PROJECT_NAME} STATIC ${DAP_ENC_SERVER_SRCS} ${DAP_ENC_SERVER_HDRS}) +target_include_directories(${PROJECT_NAME} INTERFACE . include/) +target_include_directories(${PROJECT_NAME} PUBLIC include) if(WIN32) target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_server_core dap_http_server json-c @@ -44,4 +47,3 @@ if(UNIX) target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_server_core dap_http_server json-c ) endif() -target_include_directories(${PROJECT_NAME} INTERFACE .) diff --git a/dap-sdk/net/server/enc_server/dap_enc_http.c b/dap-sdk/net/server/enc_server/dap_enc_http.c old mode 100755 new mode 100644 index 9c91111e3bcb77187e1eeb4ed3b0b1c6f3da68da..e5513c121635f35a4749ae377c8983717ba23bc5 --- a/dap-sdk/net/server/enc_server/dap_enc_http.c +++ b/dap-sdk/net/server/enc_server/dap_enc_http.c @@ -38,18 +38,18 @@ #include "dap_common.h" -#include "dap_http.h" +#include "include/dap_http.h" #include "dap_http_client.h" -#include "dap_http_simple.h" +#include "include/dap_http_simple.h" #include "dap_enc.h" -#include "dap_enc_ks.h" +#include "include/dap_enc_ks.h" #include "dap_enc_key.h" #include "dap_enc_iaes.h" -#include "dap_enc_http.h" +#include "include/dap_enc_http.h" #include "dap_enc_base64.h" #include "dap_enc_msrln.h" -#include "http_status_code.h" +#include "include/http_status_code.h" #include <json-c/json.h> diff --git a/dap-sdk/net/server/enc_server/dap_enc_ks.c b/dap-sdk/net/server/enc_server/dap_enc_ks.c old mode 100755 new mode 100644 index fe0d329af4aeab12312437850b9f34d53eaa227d..4b8efc5bf3aa5099b8483dd4ae0794f9aa233382 --- a/dap-sdk/net/server/enc_server/dap_enc_ks.c +++ b/dap-sdk/net/server/enc_server/dap_enc_ks.c @@ -32,11 +32,11 @@ #include "uthash.h" #include "dap_common.h" -#include "../http_server/http_client/dap_http_client.h" -#include "../http_server/http_client/dap_http_header.h" +#include "../http_server/http_client/include/dap_http_client.h" +#include "../http_server/http_client/include/dap_http_header.h" #include "dap_enc.h" -#include "dap_enc_ks.h" +#include "include/dap_enc_ks.h" #include "dap_enc_key.h" #define LOG_TAG "dap_enc_ks" diff --git a/dap-sdk/net/server/enc_server/dap_enc_http.h b/dap-sdk/net/server/enc_server/include/dap_enc_http.h old mode 100755 new mode 100644 similarity index 100% rename from dap-sdk/net/server/enc_server/dap_enc_http.h rename to dap-sdk/net/server/enc_server/include/dap_enc_http.h diff --git a/dap-sdk/net/server/enc_server/dap_enc_ks.h b/dap-sdk/net/server/enc_server/include/dap_enc_ks.h old mode 100755 new mode 100644 similarity index 100% rename from dap-sdk/net/server/enc_server/dap_enc_ks.h rename to dap-sdk/net/server/enc_server/include/dap_enc_ks.h diff --git a/dap-sdk/net/server/http_server/CMakeLists.txt b/dap-sdk/net/server/http_server/CMakeLists.txt old mode 100755 new mode 100644 index ed5267eeaf9d8cb145939ce7b6c66dbb98b1b834..48700be8218d42600b1ff161239dfd5f51c652d8 --- a/dap-sdk/net/server/http_server/CMakeLists.txt +++ b/dap-sdk/net/server/http_server/CMakeLists.txt @@ -1,15 +1,10 @@ cmake_minimum_required(VERSION 3.0) project (dap_http_server C) -include_directories(http_client) +include_directories(http_client/include) -set(HTTP_SERVER_SRCS - dap_http.c - dap_http_folder.c - dap_http_simple.c - http_client/dap_http_client.c - http_client/dap_http_header.c - http_client/dap_http_user_agent.c) +file(GLOB HTTP_SERVER_SRCS FILES *.c http_client/*.c) +file(GLOB HTTP_SERVER_HDRS FILES include/*.h http_client/include/*.h) if(WIN32) add_definitions ("-DUNDEBUG") @@ -20,14 +15,15 @@ if(WIN32) add_definitions ("-D_CRT_SECURE_NO_WARNINGS") add_definitions ("-DCURL_STATICLIB") - include_directories(../../3rdparty/wepoll/) - include_directories(../../3rdparty/uthash/src/) + include_directories(../../../../3rdparty/wepoll/) + include_directories(../../../../3rdparty/uthash/src/) #include_directories(../../3rdparty/curl/include/) endif() -add_library(${PROJECT_NAME} STATIC ${HTTP_SERVER_SRCS}) - -target_include_directories(dap_http_server INTERFACE . http_client) +include_directories(${PROJECT_NAME} include/) +add_library(${PROJECT_NAME} STATIC ${HTTP_SERVER_SRCS} ${HTTP_SERVER_HDRS}) +target_include_directories(${PROJECT_NAME} INTERFACE . http_client/include/) +target_include_directories(${PROJECT_NAME} PUBLIC include) if(WIN32) target_link_libraries(dap_http_server dap_core dap_crypto dap_server_core magic regex tre intl iconv diff --git a/dap-sdk/net/server/http_server/dap_http.c b/dap-sdk/net/server/http_server/dap_http.c old mode 100755 new mode 100644 index 72b52ef92d50d84d2fc62e844cb760c796981ab3..51fe57a57e4b8fbc14e776666dd1ffe1012d2d10 --- a/dap-sdk/net/server/http_server/dap_http.c +++ b/dap-sdk/net/server/http_server/dap_http.c @@ -1,171 +1,171 @@ -/* - Copyright (c) 2017-2018 (c) Project "DeM Labs Inc" https://github.com/demlabsinc - All rights reserved. - - This file is part of DAP (Deus Applications Prototypes) the open source project - - DAP (Deus Applicaions Prototypes) 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 3 of the License, or - (at your option) any later version. - - DAP 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 any DAP based project. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <dirent.h> - -#ifndef _WIN32 -#include <netinet/in.h> -#include <sys/socket.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <netdb.h> -#else -#include <winsock2.h> -#include <windows.h> -#include <mswsock.h> -#include <ws2tcpip.h> -#include <io.h> -#include <time.h> -#endif - -#include <pthread.h> - -#include "dap_common.h" -#include "dap_server.h" -#include "dap_client_remote.h" -#include "dap_http.h" -#include "dap_http_header.h" -#include "dap_http_client.h" - -#define LOG_TAG "dap_http" - - -/** - * @brief dap_http_init // Init HTTP module - * @return Zero if ok others if not - */ -int dap_http_init( ) -{ - if ( dap_http_header_init() != 0 ) { // Init submodule for headers manipulations - log_it(L_CRITICAL,"Can't init HTTP headers processing submodule"); - return -1; - } - - if ( dap_http_client_init() !=0 ) { // Init submodule for HTTP client event processing - log_it(L_CRITICAL,"Can't init HTTP client submodule"); - return -2; - } - - log_it( L_NOTICE, "Initialized HTTP server module" ); - return 0; -} - -/** - * @brief dap_http_deinit Deinit HTTP module - */ -void dap_http_deinit() -{ - dap_http_header_deinit( ); - dap_http_client_deinit( ); -} - - -/** - * @brief dap_server_http_init Init HTTP server - * @param sh Server instance - * @return 0 if ok lesser number if error - */ -int dap_http_new( dap_server_t *sh, const char * server_name ) -{ - sh->_inheritor = calloc( 1, sizeof(dap_http_t) ); - - dap_http_t *shttp = DAP_HTTP( sh ); - - shttp->server = sh; - strncpy( shttp->server_name, server_name, sizeof(shttp->server_name)-1 ); - - sh->client_new_callback = dap_http_client_new; - sh->client_delete_callback = dap_http_client_delete; - sh->client_read_callback = dap_http_client_read; - sh->client_write_callback = dap_http_client_write; - sh->client_error_callback = dap_http_client_error; - - return 0; -} - -/** - * @brief dap_http_delete Clear dap_http structure in the internal data field of dap_server_t instance - * @param sh Server's instance - * @param arg Non-used argument - */ -void dap_http_delete( dap_server_t *sh, void * arg ) -{ - (void) arg; - (void) sh; - dap_http_t *shttp = DAP_HTTP( sh ); - dap_http_url_proc_t *up, *tmp; - - HASH_ITER( hh, shttp->url_proc ,up, tmp ) { - HASH_DEL(shttp->url_proc, up); - if( up->_inheritor ) - free( up->_inheritor ); - free( up ); - } -} - - -/** - * @brief dap_http_add_proc Add custom procesor for the HTTP server - * @param sh Server's instance - * @param url_path Part of URL to be processed - * @param read_callback Callback for read in DATA state - * @param write_callback Callback for write in DATA state - * @param error_callback Callback for error processing - */ -void dap_http_add_proc(dap_http_t *sh, const char *url_path, void *internal - ,dap_http_client_callback_t new_callback - ,dap_http_client_callback_t delete_callback - ,dap_http_client_callback_t headers_read_callback - ,dap_http_client_callback_t headers_write_callback - ,dap_http_client_callback_t data_read_callback - ,dap_http_client_callback_t data_write_callback - ,dap_http_client_callback_t error_callback - - ) -{ - dap_http_url_proc_t *up = (dap_http_url_proc_t *) calloc( 1, sizeof(dap_http_url_proc_t) ); - - strncpy( up->url, url_path, sizeof(up->url)-1 ); - - up->new_callback = new_callback; - up->delete_callback = delete_callback; - - up->data_read_callback = data_read_callback; - up->data_write_callback = data_write_callback; - up->headers_read_callback = headers_read_callback; - up->headers_write_callback = headers_write_callback; - up->error_callback = error_callback; - - up->_inheritor = internal; - - HASH_ADD_STR( sh->url_proc, url, up ); - - log_it( L_DEBUG, "Added URL processor for '%s' path", up->url ); -} - - +/* + Copyright (c) 2017-2018 (c) Project "DeM Labs Inc" https://github.com/demlabsinc + All rights reserved. + + This file is part of DAP (Deus Applications Prototypes) the open source project + + DAP (Deus Applicaions Prototypes) 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 3 of the License, or + (at your option) any later version. + + DAP 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 any DAP based project. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <dirent.h> + +#ifndef _WIN32 +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <netdb.h> +#else +#include <winsock2.h> +#include <windows.h> +#include <mswsock.h> +#include <ws2tcpip.h> +#include <io.h> +#include <time.h> +#endif + +#include <pthread.h> + +#include "dap_common.h" +#include "dap_server.h" +#include "dap_client_remote.h" +#include "dap_http.h" +#include "dap_http_header.h" +#include "dap_http_client.h" + +#define LOG_TAG "dap_http" + + +/** + * @brief dap_http_init // Init HTTP module + * @return Zero if ok others if not + */ +int dap_http_init( ) +{ + if ( dap_http_header_init() != 0 ) { // Init submodule for headers manipulations + log_it(L_CRITICAL,"Can't init HTTP headers processing submodule"); + return -1; + } + + if ( dap_http_client_init() !=0 ) { // Init submodule for HTTP client event processing + log_it(L_CRITICAL,"Can't init HTTP client submodule"); + return -2; + } + + log_it( L_NOTICE, "Initialized HTTP server module" ); + return 0; +} + +/** + * @brief dap_http_deinit Deinit HTTP module + */ +void dap_http_deinit() +{ + dap_http_header_deinit( ); + dap_http_client_deinit( ); +} + + +/** + * @brief dap_server_http_init Init HTTP server + * @param sh Server instance + * @return 0 if ok lesser number if error + */ +int dap_http_new( dap_server_t *sh, const char * server_name ) +{ + sh->_inheritor = calloc( 1, sizeof(dap_http_t) ); + + dap_http_t *shttp = DAP_HTTP( sh ); + + shttp->server = sh; + strncpy( shttp->server_name, server_name, sizeof(shttp->server_name)-1 ); + + sh->client_new_callback = dap_http_client_new; + sh->client_delete_callback = dap_http_client_delete; + sh->client_read_callback = dap_http_client_read; + sh->client_write_callback = dap_http_client_write; + sh->client_error_callback = dap_http_client_error; + + return 0; +} + +/** + * @brief dap_http_delete Clear dap_http structure in the internal data field of dap_server_t instance + * @param sh Server's instance + * @param arg Non-used argument + */ +void dap_http_delete( dap_server_t *sh, void * arg ) +{ + (void) arg; + (void) sh; + dap_http_t *shttp = DAP_HTTP( sh ); + dap_http_url_proc_t *up, *tmp; + + HASH_ITER( hh, shttp->url_proc ,up, tmp ) { + HASH_DEL(shttp->url_proc, up); + if( up->_inheritor ) + free( up->_inheritor ); + free( up ); + } +} + + +/** + * @brief dap_http_add_proc Add custom procesor for the HTTP server + * @param sh Server's instance + * @param url_path Part of URL to be processed + * @param read_callback Callback for read in DATA state + * @param write_callback Callback for write in DATA state + * @param error_callback Callback for error processing + */ +void dap_http_add_proc(dap_http_t *sh, const char *url_path, void *internal + ,dap_http_client_callback_t new_callback + ,dap_http_client_callback_t delete_callback + ,dap_http_client_callback_t headers_read_callback + ,dap_http_client_callback_t headers_write_callback + ,dap_http_client_callback_t data_read_callback + ,dap_http_client_callback_t data_write_callback + ,dap_http_client_callback_t error_callback + + ) +{ + dap_http_url_proc_t *up = (dap_http_url_proc_t *) calloc( 1, sizeof(dap_http_url_proc_t) ); + + strncpy( up->url, url_path, sizeof(up->url)-1 ); + + up->new_callback = new_callback; + up->delete_callback = delete_callback; + + up->data_read_callback = data_read_callback; + up->data_write_callback = data_write_callback; + up->headers_read_callback = headers_read_callback; + up->headers_write_callback = headers_write_callback; + up->error_callback = error_callback; + + up->_inheritor = internal; + + HASH_ADD_STR( sh->url_proc, url, up ); + + log_it( L_DEBUG, "Added URL processor for '%s' path", up->url ); +} + + diff --git a/dap-sdk/net/server/http_server/dap_http_folder.c b/dap-sdk/net/server/http_server/dap_http_folder.c old mode 100755 new mode 100644 diff --git a/dap-sdk/net/server/http_server/dap_http_simple.c b/dap-sdk/net/server/http_server/dap_http_simple.c old mode 100755 new mode 100644 index 518e4cdcde95fce55b43d2bcafc07f2b9f317152..12345d2c3caa2a368288c5e482f397f31a9d4f5d --- a/dap-sdk/net/server/http_server/dap_http_simple.c +++ b/dap-sdk/net/server/http_server/dap_http_simple.c @@ -52,8 +52,8 @@ See more details here <http://www.gnu.org/licenses/>. #include "dap_http_user_agent.h" -#include "../enc_server/dap_enc_ks.h" -#include "../enc_server/dap_enc_http.h" +#include "../enc_server/include/dap_enc_ks.h" +#include "../enc_server/include/dap_enc_http.h" #include "http_status_code.h" diff --git a/dap-sdk/net/server/http_server/http_client/CMakeLists.txt b/dap-sdk/net/server/http_server/http_client/CMakeLists.txt old mode 100755 new mode 100644 index 7d3b34e161a5b815a9a704d25d7a61c7663bbf41..b3633d72034eddd642958862c19b0c10d4bcd206 --- a/dap-sdk/net/server/http_server/http_client/CMakeLists.txt +++ b/dap-sdk/net/server/http_server/http_client/CMakeLists.txt @@ -1,18 +1,15 @@ cmake_minimum_required(VERSION 3.0) project (dap_http_client) -set(HTTP_SRCS dap_http_client.c dap_http_header.c) +set(HTTP_SRCS FILES *.c) +set(HTTP_HDRS FILES include/*.h) if(WIN32) - include_directories(../../../libdap/src/win32/) - include_directories(../../../3rdparty/libmemcached/) - include_directories(../../../3rdparty/libmemcached/win32/) - include_directories(../../../3rdparty/wepoll/include/) - include_directories(../../../3rdparty/uthash/src/) - include_directories(../../../3rdparty/libjson-c/) - include_directories(../../../3rdparty/libmagic/src/) - include_directories(../../../3rdparty/curl/include/) + include_directories(../../../../os/win32/) + include_directories(../../../../3rdparty/wepoll/include/) + include_directories(../../../../3rdparty/uthash/src/) + include_directories(../../../../3rdparty/libmagic/src/) endif() -add_library(${PROJECT_NAME} STATIC ${HTTP_SRCS}) +add_library(${PROJECT_NAME} STATIC ${HTTP_SRCS} ${HTTP_HDRS}) diff --git a/dap-sdk/net/server/http_server/http_client/dap_http_client.c b/dap-sdk/net/server/http_server/http_client/dap_http_client.c old mode 100755 new mode 100644 index 4ecdcd568772cf2d7b55bac93f1390383225f49d..e7944d411b5895fcf7156e8a2585b22e51c3bc64 --- a/dap-sdk/net/server/http_server/http_client/dap_http_client.c +++ b/dap-sdk/net/server/http_server/http_client/dap_http_client.c @@ -38,8 +38,8 @@ #include "dap_common.h" #include "dap_client_remote.h" -#include "../dap_http.h" -#include "../http_status_code.h" +#include "dap_http.h" +#include "http_status_code.h" #include "dap_http_header.h" #include "dap_http_client.h" diff --git a/dap-sdk/net/server/http_server/http_client/dap_http_header.c b/dap-sdk/net/server/http_server/http_client/dap_http_header.c old mode 100755 new mode 100644 diff --git a/dap-sdk/net/server/http_server/http_client/dap_http_user_agent.c b/dap-sdk/net/server/http_server/http_client/dap_http_user_agent.c old mode 100755 new mode 100644 diff --git a/dap-sdk/net/server/http_server/http_client/http.pri b/dap-sdk/net/server/http_server/http_client/http.pri old mode 100755 new mode 100644 index 4c888649076a49440c884c27cfdf130528b5e3b4..2feda484615fa0e8ce2d4f90b4d5400379a2fadc --- a/dap-sdk/net/server/http_server/http_client/http.pri +++ b/dap-sdk/net/server/http_server/http_client/http.pri @@ -1,15 +1,10 @@ HEADERS += $$PWD/dap_http_client.h \ - $$PWD/dap_http_client_simple.h \ - $$PWD/dap_http_header.h + $$PWD/include/dap_http_client_simple.h \ + $$PWD/include/dap_http_header.h SOURCES += $$PWD/dap_http_client.c \ $$PWD/dap_http_client_simple.c \ $$PWD/dap_http_header.c - -linux-* { - LIBS += -lcurl -} - INCLUDEPATH += $$PWD diff --git a/dap-sdk/net/server/http_server/http_client/dap_http_client.h b/dap-sdk/net/server/http_server/http_client/include/dap_http_client.h old mode 100755 new mode 100644 similarity index 100% rename from dap-sdk/net/server/http_server/http_client/dap_http_client.h rename to dap-sdk/net/server/http_server/http_client/include/dap_http_client.h diff --git a/dap-sdk/net/server/http_server/http_client/dap_http_header.h b/dap-sdk/net/server/http_server/http_client/include/dap_http_header.h old mode 100755 new mode 100644 similarity index 100% rename from dap-sdk/net/server/http_server/http_client/dap_http_header.h rename to dap-sdk/net/server/http_server/http_client/include/dap_http_header.h diff --git a/dap-sdk/net/server/http_server/http_client/dap_http_user_agent.h b/dap-sdk/net/server/http_server/http_client/include/dap_http_user_agent.h old mode 100755 new mode 100644 similarity index 100% rename from dap-sdk/net/server/http_server/http_client/dap_http_user_agent.h rename to dap-sdk/net/server/http_server/http_client/include/dap_http_user_agent.h diff --git a/dap-sdk/net/server/http_server/dap_http.h b/dap-sdk/net/server/http_server/include/dap_http.h old mode 100755 new mode 100644 similarity index 94% rename from dap-sdk/net/server/http_server/dap_http.h rename to dap-sdk/net/server/http_server/include/dap_http.h index 9c7ee75cb247ad252c3269acf1930e70c5fcb3c6..646811940151ee8b8d46f158e90fa6b48165d153 --- a/dap-sdk/net/server/http_server/dap_http.h +++ b/dap-sdk/net/server/http_server/include/dap_http.h @@ -1,79 +1,79 @@ -/* -* Authors: -* Dmitrii Gerasimov <naeper@demlabs.net> -* DeM Labs Inc. https://demlabs.net -* Cellframe https://cellframe.net -* Copyright (c) 2017-2019 -* All rights reserved. - -This file is part of DAP the open source project. - -DAP is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -DAP 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. - -See more details here <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include "dap_server.h" -#include "dap_client_remote.h" -#include "http_client/dap_http_header.h" -#include "http_client/dap_http_client.h" -#include "uthash.h" - -struct dap_http; -struct dap_http_url_processor; -//Structure for internal data of dap_server_t structure for holding special HTTP data - -// Structure for holding URL processors -typedef struct dap_http_url_proc{ - char url[512]; // First part of URL that will be processed - struct dap_http * http; // Pointer to HTTP server instance - - dap_http_client_callback_t new_callback; // Init internal structure - dap_http_client_callback_t delete_callback; // Delete internal structure - - dap_http_client_callback_t headers_read_callback; - dap_http_client_callback_t headers_write_callback; - - dap_http_client_callback_t data_read_callback; - dap_http_client_callback_t data_write_callback; - dap_http_client_callback_t error_callback; - - dap_http_client_callback_t access_callback; - - void *_inheritor; // Internal data specific to the current URL processor - UT_hash_handle hh; // makes this structure hashable with UTHASH library -} dap_http_url_proc_t; - -// Internal server structure for HTTP server -typedef struct dap_http { - dap_server_t *server; - char server_name[256]; - dap_http_url_proc_t * url_proc; -} dap_http_t; - -#define DAP_HTTP(a) ((dap_http_t *) (a)->_inheritor) - -int dap_http_init( ); // Init module -void dap_http_deinit( ); // Deinit module - -int dap_http_new( dap_server_t *sh, const char *server_name ); // Create dap_http structure in the internal data field of dap_server_t instance -void dap_http_delete( dap_server_t *sh, void *arg ); // Clear dap_http structure in the internal data field of dap_server_t instance - -void dap_http_add_proc(dap_http_t *sh, const char *url_path, void *internal - ,dap_http_client_callback_t new_callback - ,dap_http_client_callback_t delete_callback - ,dap_http_client_callback_t headers_read_callback - ,dap_http_client_callback_t headers_write_callback - ,dap_http_client_callback_t data_read_callback - ,dap_http_client_callback_t data_write_callback - ,dap_http_client_callback_t error_callback ); // Add custom procesor for the HTTP server - +/* +* Authors: +* Dmitrii Gerasimov <naeper@demlabs.net> +* DeM Labs Inc. https://demlabs.net +* Cellframe https://cellframe.net +* Copyright (c) 2017-2019 +* All rights reserved. + +This file is part of DAP the open source project. + +DAP is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +DAP 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. + +See more details here <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "dap_server.h" +#include "dap_client_remote.h" +#include "dap_http_header.h" +#include "dap_http_client.h" +#include "uthash.h" + +struct dap_http; +struct dap_http_url_processor; +//Structure for internal data of dap_server_t structure for holding special HTTP data + +// Structure for holding URL processors +typedef struct dap_http_url_proc{ + char url[512]; // First part of URL that will be processed + struct dap_http * http; // Pointer to HTTP server instance + + dap_http_client_callback_t new_callback; // Init internal structure + dap_http_client_callback_t delete_callback; // Delete internal structure + + dap_http_client_callback_t headers_read_callback; + dap_http_client_callback_t headers_write_callback; + + dap_http_client_callback_t data_read_callback; + dap_http_client_callback_t data_write_callback; + dap_http_client_callback_t error_callback; + + dap_http_client_callback_t access_callback; + + void *_inheritor; // Internal data specific to the current URL processor + UT_hash_handle hh; // makes this structure hashable with UTHASH library +} dap_http_url_proc_t; + +// Internal server structure for HTTP server +typedef struct dap_http { + dap_server_t *server; + char server_name[256]; + dap_http_url_proc_t * url_proc; +} dap_http_t; + +#define DAP_HTTP(a) ((dap_http_t *) (a)->_inheritor) + +int dap_http_init( ); // Init module +void dap_http_deinit( ); // Deinit module + +int dap_http_new( dap_server_t *sh, const char *server_name ); // Create dap_http structure in the internal data field of dap_server_t instance +void dap_http_delete( dap_server_t *sh, void *arg ); // Clear dap_http structure in the internal data field of dap_server_t instance + +void dap_http_add_proc(dap_http_t *sh, const char *url_path, void *internal + ,dap_http_client_callback_t new_callback + ,dap_http_client_callback_t delete_callback + ,dap_http_client_callback_t headers_read_callback + ,dap_http_client_callback_t headers_write_callback + ,dap_http_client_callback_t data_read_callback + ,dap_http_client_callback_t data_write_callback + ,dap_http_client_callback_t error_callback ); // Add custom procesor for the HTTP server + diff --git a/dap-sdk/net/server/http_server/dap_http_folder.h b/dap-sdk/net/server/http_server/include/dap_http_folder.h old mode 100755 new mode 100644 similarity index 97% rename from dap-sdk/net/server/http_server/dap_http_folder.h rename to dap-sdk/net/server/http_server/include/dap_http_folder.h index 05d0eedec0f203267502cabd4a312bcf63dfe26a..3dec0498a19076fff6cf71e8b4eed3f10ce7c3bc --- a/dap-sdk/net/server/http_server/dap_http_folder.h +++ b/dap-sdk/net/server/http_server/include/dap_http_folder.h @@ -1,31 +1,31 @@ -/* - Copyright (c) 2017-2018 (c) Project "DeM Labs Inc" https://github.com/demlabsinc - All rights reserved. - - This file is part of DAP (Deus Applications Prototypes) the open source project - - DAP (Deus Applicaions Prototypes) 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 3 of the License, or - (at your option) any later version. - - DAP 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 any DAP based project. If not, see <http://www.gnu.org/licenses/>. -*/ - -#ifndef _DAP_HTTP_FOLDER_H_ -#define _DAP_HTTP_FOLDER_H_ - -struct dap_http; - -extern int dap_http_folder_init(); -extern void dap_http_folder_deinit(); - -extern int dap_http_folder_add(struct dap_http *sh, const char * url_path, const char * local_path); // Add folder for reading to the HTTP server - -#endif +/* + Copyright (c) 2017-2018 (c) Project "DeM Labs Inc" https://github.com/demlabsinc + All rights reserved. + + This file is part of DAP (Deus Applications Prototypes) the open source project + + DAP (Deus Applicaions Prototypes) 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 3 of the License, or + (at your option) any later version. + + DAP 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 any DAP based project. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _DAP_HTTP_FOLDER_H_ +#define _DAP_HTTP_FOLDER_H_ + +struct dap_http; + +extern int dap_http_folder_init(); +extern void dap_http_folder_deinit(); + +extern int dap_http_folder_add(struct dap_http *sh, const char * url_path, const char * local_path); // Add folder for reading to the HTTP server + +#endif diff --git a/dap-sdk/net/server/http_server/dap_http_simple.h b/dap-sdk/net/server/http_server/include/dap_http_simple.h old mode 100755 new mode 100644 similarity index 100% rename from dap-sdk/net/server/http_server/dap_http_simple.h rename to dap-sdk/net/server/http_server/include/dap_http_simple.h diff --git a/dap-sdk/net/server/http_server/http_status_code.h b/dap-sdk/net/server/http_server/include/http_status_code.h old mode 100755 new mode 100644 similarity index 100% rename from dap-sdk/net/server/http_server/http_status_code.h rename to dap-sdk/net/server/http_server/include/http_status_code.h diff --git a/dap-sdk/net/server/test/CMakeLists.txt b/dap-sdk/net/server/test/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/dap-sdk/net/server/test/enc_server/CMakeLists.txt b/dap-sdk/net/server/test/enc_server/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/dap-sdk/net/server/test/enc_server/main.c b/dap-sdk/net/server/test/enc_server/main.c old mode 100755 new mode 100644 diff --git a/dap-sdk/net/server/test/http_server/CMakeLists.txt b/dap-sdk/net/server/test/http_server/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/dap-sdk/net/server/test/http_server/dap_http_simple_test.c b/dap-sdk/net/server/test/http_server/dap_http_simple_test.c old mode 100755 new mode 100644 diff --git a/dap-sdk/net/server/test/http_server/dap_http_simple_test.h b/dap-sdk/net/server/test/http_server/dap_http_simple_test.h old mode 100755 new mode 100644 diff --git a/dap-sdk/net/server/test/http_server/dap_http_user_agent_test.c b/dap-sdk/net/server/test/http_server/dap_http_user_agent_test.c old mode 100755 new mode 100644 diff --git a/dap-sdk/net/server/test/http_server/dap_http_user_agent_test.h b/dap-sdk/net/server/test/http_server/dap_http_user_agent_test.h old mode 100755 new mode 100644 diff --git a/dap-sdk/net/server/test/http_server/main.c b/dap-sdk/net/server/test/http_server/main.c old mode 100755 new mode 100644 diff --git a/dap-sdk/net/server/test/main.c b/dap-sdk/net/server/test/main.c old mode 100755 new mode 100644 diff --git a/dap-sdk/net/stream/.gitignore b/dap-sdk/net/stream/.gitignore deleted file mode 100755 index 15cef3cea89f1889fb9e7788be912afa92240236..0000000000000000000000000000000000000000 --- a/dap-sdk/net/stream/.gitignore +++ /dev/null @@ -1,54 +0,0 @@ -# Prerequisites -*.d -build/ -# Object files -*.o -*.ko -*.obj -*.elf - -# Linker output -*.ilk -*.map -*.exp - -# Precompiled Headers -*.gch -*.pch - -# Libraries -*.lib -*.a -*.la -*.lo - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - -# Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex - -# Debug files -*.dSYM/ -*.su -*.idb -*.pdb - -# Kernel Module Compile Results -*.mod* -*.cmd -.tmp_versions/ -modules.order -Module.symvers -Mkfile.old -dkms.conf - -*.txt.user diff --git a/dap-sdk/net/stream/.travis.yml b/dap-sdk/net/stream/.travis.yml deleted file mode 100755 index ff468b80fc6b94d0f13473bfcd4a9966403539f2..0000000000000000000000000000000000000000 --- a/dap-sdk/net/stream/.travis.yml +++ /dev/null @@ -1,25 +0,0 @@ -language: c -compiler: gcc -dist: xenial -notifications: - email: false - -before_install: - - git submodule init - - git submodule update - -script: - - mkdir build - - cd build - - cmake -DBUILD_DAP_STREAM_TESTS=ON ../ - - make - - ctest --verbose - -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - libjson-c-dev - - libev-dev - - libmagic-dev diff --git a/dap-sdk/net/stream/CMakeLists.txt b/dap-sdk/net/stream/CMakeLists.txt old mode 100755 new mode 100644 index 3e477f95a24380f3ae2552163e8dff0b3986fe96..87d7d736450b46cba9d91e5d5d05abb88cb4fdee --- a/dap-sdk/net/stream/CMakeLists.txt +++ b/dap-sdk/net/stream/CMakeLists.txt @@ -1,35 +1,6 @@ project(libdap-stream C) cmake_minimum_required(VERSION 3.0) -if(NOT SUBMODULES_NO_BUILD) - if ( NOT ( TARGET dap_core ) ) - add_subdirectory(libdap) - endif() - if ( NOT ( TARGET dap_crypto ) ) - add_subdirectory(libdap-crypto) - endif() - - if ( NOT ( TARGET libdap-server ) ) - add_subdirectory(libdap-server) - endif() - - if ( NOT ( TARGET dap_server_core ) ) - add_subdirectory(libdap-server-core) - endif() - - if ( NOT ( TARGET dap_server_udp ) ) - add_subdirectory(libdap-server-udp) - endif() - - if ( NOT ( TARGET dap_stream_ch ) ) - add_subdirectory(libdap-stream-ch) - endif() -endif() - -if(BUILD_DAP_STREAM_TESTS) - enable_testing() - add_subdirectory(test) -endif() - add_subdirectory(session) add_subdirectory(stream) +add_subdirectory(ch) diff --git a/dap-sdk/net/stream/LICENSE b/dap-sdk/net/stream/LICENSE deleted file mode 100755 index 65c5ca88a67c30becee01c5a8816d964b03862f9..0000000000000000000000000000000000000000 --- a/dap-sdk/net/stream/LICENSE +++ /dev/null @@ -1,165 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - 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 that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU 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 as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/dap-sdk/net/stream/README.md b/dap-sdk/net/stream/README.md deleted file mode 100755 index e0b4a683183628c22ea0cba8ec8a42579e2e01f3..0000000000000000000000000000000000000000 --- a/dap-sdk/net/stream/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# libdap-stream -Deus Applications Prototypes: multichannel stream - -[](https://travis-ci.com/kelvinblockchain/libdap-stream) diff --git a/dap-sdk/net/stream/ch/.gitignore b/dap-sdk/net/stream/ch/.gitignore deleted file mode 100755 index c6127b38c1aa25968a88db3940604d41529e4cf5..0000000000000000000000000000000000000000 --- a/dap-sdk/net/stream/ch/.gitignore +++ /dev/null @@ -1,52 +0,0 @@ -# Prerequisites -*.d - -# Object files -*.o -*.ko -*.obj -*.elf - -# Linker output -*.ilk -*.map -*.exp - -# Precompiled Headers -*.gch -*.pch - -# Libraries -*.lib -*.a -*.la -*.lo - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - -# Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex - -# Debug files -*.dSYM/ -*.su -*.idb -*.pdb - -# Kernel Module Compile Results -*.mod* -*.cmd -.tmp_versions/ -modules.order -Module.symvers -Mkfile.old -dkms.conf diff --git a/dap-sdk/net/stream/ch/CMakeLists.txt b/dap-sdk/net/stream/ch/CMakeLists.txt old mode 100755 new mode 100644 index d3be99c04178387ecec87a1736805a7a77d7a05f..8a2c0d822b136fabccb974a879fb19154596e696 --- a/dap-sdk/net/stream/ch/CMakeLists.txt +++ b/dap-sdk/net/stream/ch/CMakeLists.txt @@ -1,16 +1,17 @@ cmake_minimum_required(VERSION 3.0) project (dap_stream_ch) -set(DAP_STREAM_CH_SRCS dap_stream_ch.c dap_stream_ch_pkt.c dap_stream_ch_proc.c) +file(GLOB DAP_STREAM_CH_SRCS *.c) +file(GLOB DAP_STREAM_CH_HDRS include/*.h) if(WIN32) include_directories(../3rdparty/wepoll/) include_directories(../3rdparty/uthash/src/) - #include_directories(../3rdparty/curl/include/) endif() -add_library(${PROJECT_NAME} STATIC ${DAP_STREAM_CH_SRCS}) +add_library(${PROJECT_NAME} STATIC ${DAP_STREAM_CH_SRCS} ${DAP_STREAM_CH_HDRS}) target_link_libraries(dap_stream_ch dap_core dap_crypto dap_stream) target_include_directories(dap_stream_ch INTERFACE .) +target_include_directories(${PROJECT_NAME} PUBLIC include) diff --git a/dap-sdk/net/stream/ch/LICENSE b/dap-sdk/net/stream/ch/LICENSE deleted file mode 100755 index 94a9ed024d3859793618152ea559a168bbcbb5e2..0000000000000000000000000000000000000000 --- a/dap-sdk/net/stream/ch/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - <program> Copyright (C) <year> <name of author> - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -<http://www.gnu.org/licenses/>. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/dap-sdk/net/stream/ch/README.md b/dap-sdk/net/stream/ch/README.md deleted file mode 100755 index be612fe2e6cfa89f046ee8e9ee32c345652b3083..0000000000000000000000000000000000000000 --- a/dap-sdk/net/stream/ch/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# libdap-stream-ch -Channels managment diff --git a/dap-sdk/net/stream/ch/dap_stream_ch.c b/dap-sdk/net/stream/ch/dap_stream_ch.c old mode 100755 new mode 100644 diff --git a/dap-sdk/net/stream/ch/dap_stream_ch_pkt.c b/dap-sdk/net/stream/ch/dap_stream_ch_pkt.c old mode 100755 new mode 100644 diff --git a/dap-sdk/net/stream/ch/dap_stream_ch_proc.c b/dap-sdk/net/stream/ch/dap_stream_ch_proc.c old mode 100755 new mode 100644 diff --git a/dap-sdk/net/stream/ch/dap_stream_ch.h b/dap-sdk/net/stream/ch/include/dap_stream_ch.h old mode 100755 new mode 100644 similarity index 100% rename from dap-sdk/net/stream/ch/dap_stream_ch.h rename to dap-sdk/net/stream/ch/include/dap_stream_ch.h diff --git a/dap-sdk/net/stream/ch/dap_stream_ch_pkt.h b/dap-sdk/net/stream/ch/include/dap_stream_ch_pkt.h old mode 100755 new mode 100644 similarity index 100% rename from dap-sdk/net/stream/ch/dap_stream_ch_pkt.h rename to dap-sdk/net/stream/ch/include/dap_stream_ch_pkt.h diff --git a/dap-sdk/net/stream/ch/dap_stream_ch_proc.h b/dap-sdk/net/stream/ch/include/dap_stream_ch_proc.h old mode 100755 new mode 100644 similarity index 100% rename from dap-sdk/net/stream/ch/dap_stream_ch_proc.h rename to dap-sdk/net/stream/ch/include/dap_stream_ch_proc.h diff --git a/dap-sdk/net/stream/session/CMakeLists.txt b/dap-sdk/net/stream/session/CMakeLists.txt old mode 100755 new mode 100644 index 4c702cfbd85a65283c50b5641961e8a486b4d193..ffda4c0ca46430dafe8c3f2c2ac48a90f9d002c2 --- a/dap-sdk/net/stream/session/CMakeLists.txt +++ b/dap-sdk/net/stream/session/CMakeLists.txt @@ -1,16 +1,16 @@ cmake_minimum_required(VERSION 2.8) project (dap_session) -set(SESSION_SRCS dap_stream_session.c) +file(GLOB SESSION_SRCS *.c) +file(GLOB SESSION_HDRS include/*.h) if(WIN32) - include_directories(../../3rdparty/wepoll/) include_directories(../../3rdparty/uthash/src/) - #include_directories(../../3rdparty/curl/include/) endif() add_library(${PROJECT_NAME} STATIC ${SESSION_SRCS}) +include_directories(include/) target_link_libraries(dap_session dap_core dap_crypto) - -target_include_directories(dap_session INTERFACE .) +target_include_directories(dap_session INTERFACE . include/) +target_include_directories(${PROJECT_NAME} PUBLIC include) diff --git a/dap-sdk/net/stream/session/dap_stream_session.h b/dap-sdk/net/stream/session/include/dap_stream_session.h old mode 100755 new mode 100644 similarity index 100% rename from dap-sdk/net/stream/session/dap_stream_session.h rename to dap-sdk/net/stream/session/include/dap_stream_session.h diff --git a/dap-sdk/net/stream/stream/CMakeLists.txt b/dap-sdk/net/stream/stream/CMakeLists.txt index 7bb630e624b006c673cd95eff672d713a1c66001..1b4ed0617c2f8cbe2b0ef1838a3bdbdc25daea5e 100755 --- a/dap-sdk/net/stream/stream/CMakeLists.txt +++ b/dap-sdk/net/stream/stream/CMakeLists.txt @@ -1,20 +1,19 @@ cmake_minimum_required(VERSION 2.8) project (dap_stream) -set(STREAM_SRCS - dap_stream.c - dap_stream_ctl.c - dap_stream_pkt.c ) +file(GLOB STREAM_SRCS *.c) +file(GLOB STREAM_HDRS include/*.h) if(WIN32) - include_directories(../../3rdparty/wepoll/) - include_directories(../../3rdparty/uthash/src/) + include_directories(../../../3rdparty/wepoll/) + include_directories(../../../3rdparty/uthash/src/) #include_directories(../../3rdparty/curl/include/) endif() -add_library(${PROJECT_NAME} STATIC ${STREAM_SRCS}) +add_library(${PROJECT_NAME} STATIC ${STREAM_SRCS} ${STREAM_HDRS}) target_link_libraries(dap_stream dap_core dap_server_core dap_udp_server dap_crypto dap_http_server dap_enc_server dap_session dap_stream_ch) target_include_directories(dap_stream INTERFACE .) +target_include_directories(${PROJECT_NAME} PUBLIC include) diff --git a/dap-sdk/net/stream/stream/dap_stream.h b/dap-sdk/net/stream/stream/include/dap_stream.h similarity index 100% rename from dap-sdk/net/stream/stream/dap_stream.h rename to dap-sdk/net/stream/stream/include/dap_stream.h diff --git a/dap-sdk/net/stream/stream/dap_stream_ctl.h b/dap-sdk/net/stream/stream/include/dap_stream_ctl.h similarity index 100% rename from dap-sdk/net/stream/stream/dap_stream_ctl.h rename to dap-sdk/net/stream/stream/include/dap_stream_ctl.h diff --git a/dap-sdk/net/stream/stream/dap_stream_pkt.h b/dap-sdk/net/stream/stream/include/dap_stream_pkt.h similarity index 100% rename from dap-sdk/net/stream/stream/dap_stream_pkt.h rename to dap-sdk/net/stream/stream/include/dap_stream_pkt.h diff --git a/dap-sdk/net/stream/test/CMakeLists.txt b/dap-sdk/net/stream/test/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/dap-sdk/net/stream/test/main.c b/dap-sdk/net/stream/test/main.c old mode 100755 new mode 100644 diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index 35b0e0cf8940b24e8b7f31d45f9c6ee4f0555eee..d9dbd649e8a29f39d777ecd966d08847bdf12c53 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -1,7 +1,7 @@ add_subdirectory(app-cli) add_subdirectory(chain) add_subdirectory(common) -add_subdirectory(crypto) +add_subdirectory(mining) add_subdirectory(wallet) add_subdirectory(mempool) add_subdirectory(net) @@ -9,13 +9,13 @@ add_subdirectory(net/srv) add_subdirectory(global-db) # Consensus types -add_subdirectory(types/dag) -add_subdirectory(types/block) -add_subdirectory(types/no-consensus) +add_subdirectory(type/dag) +#add_subdirectory(type/block) # Consensuses -add_subdirectory(consensus/block-pow) -add_subdirectory(consensus/block-poa) +add_subdirectory(consensus/none) +#add_subdirectory(consensus/block-pow) +#add_subdirectory(consensus/block-poa) add_subdirectory(consensus/dag-pos) add_subdirectory(consensus/dag-poa) @@ -29,4 +29,9 @@ if(NOT (WIN32)) add_subdirectory(service/vpn) endif() +add_subdirectory(service/app) +add_subdirectory(service/app-db) +add_subdirectory(service/datum) +add_subdirectory(service/mining-pool) + diff --git a/modules/app-cli/CMakeLists.txt b/modules/app-cli/CMakeLists.txt index 7ca7367a4742324d8576c9a8914d649989bde1a5..d03500dfa560b84156aa05321f6f3bb5910a78a2 100644 --- a/modules/app-cli/CMakeLists.txt +++ b/modules/app-cli/CMakeLists.txt @@ -1,22 +1,9 @@ cmake_minimum_required(VERSION 2.8) project (dap_app_cli) -set(DAP_APP_CLI_SRCS - src/dap_app_cli.c - src/dap_app_cli_net.c - src/dap_app_cli_shell.c - ) +file(GLOB DAP_APP_CLI_SRCS *.c) -set(DAP_APP_CLI_HEADERS - include/dap_app_cli.h - include/dap_app_cli_net.h - include/dap_app_cli_shell.h - ) - - -if(WIN32) - #include_directories(../3rdparty/curl/include/) -endif() +file(GLOB DAP_APP_CLI_HEADERS include/*.h) add_library(${PROJECT_NAME} STATIC ${DAP_APP_CLI_SRCS} ${DAP_APP_CLI_HEADERS} ) diff --git a/modules/chain/CMakeLists.txt b/modules/chain/CMakeLists.txt index 493975f6a65802206da74d857f255c8eba8432c0..ed93dd69ebb39b5692d8dc17dd6c826a98e658ab 100644 --- a/modules/chain/CMakeLists.txt +++ b/modules/chain/CMakeLists.txt @@ -1,9 +1,9 @@ cmake_minimum_required(VERSION 2.8) project (dap_chain) -set(DAP_CHAIN_SRCS *.c) +file(GLOB DAP_CHAIN_SRCS *.c) -set(DAP_CHAIN_HEADERS include/*.h) +file(GLOB DAP_CHAIN_HEADERS include/*.h) if(WIN32) include_directories(../../../3rdparty/wepoll/) @@ -16,4 +16,5 @@ add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_SRCS} ${DAP_CHAIN_HEADERS}) #pkg_search_module(GLIB REQUIRED glib-2.0) target_link_libraries(dap_chain dap_core dap_chain_common dap_chain_crypto dap_chain_mempool dap_chain_global_db ${GLIB_LDFLAGS}) -target_include_directories(dap_chain INTERFACE . ${GLIB_INCLUDE_DIRS}) +target_include_directories(dap_chain INTERFACE . include/ ${GLIB_INCLUDE_DIRS}) +target_include_directories(${PROJECT_NAME} PUBLIC include) diff --git a/modules/channel/chain-net-srv/CMakeLists.txt b/modules/channel/chain-net-srv/CMakeLists.txt index 0be2199dfcf88f1d908636baefbd44eb16a64307..257582d017a7cd780fe856d7e0461a1ef879264e 100644 --- a/modules/channel/chain-net-srv/CMakeLists.txt +++ b/modules/channel/chain-net-srv/CMakeLists.txt @@ -1,8 +1,8 @@ cmake_minimum_required(VERSION 3.0) project (dap_stream_ch_chain_net_srv) -set(DAP_STREAM_CH_CHAIN_NET_SRV_SRCS *.c) -set(DAP_STREAM_CH_CHAIN_NET_SRV_HDRS include/*.h) +file(GLOB DAP_STREAM_CH_CHAIN_NET_SRV_SRCS *.c) +file(GLOB DAP_STREAM_CH_CHAIN_NET_SRV_HDRS include/*.h) if(WIN32) include_directories(../../../3rdparty/wepoll/) @@ -14,3 +14,4 @@ add_library(${PROJECT_NAME} STATIC ${DAP_STREAM_CH_CHAIN_NET_SRV_SRCS} ${DAP_STR target_link_libraries(dap_stream_ch_chain_net_srv dap_core dap_crypto dap_chain_common dap_chain dap_chain_mempool dap_chain_net dap_chain_net_srv dap_server_core dap_stream dap_stream_ch dap_stream_ch_chain dap_stream_ch_chain_net) target_include_directories(dap_stream_ch_chain_net_srv INTERFACE .) +target_include_directories(${PROJECT_NAME} PUBLIC include) diff --git a/modules/channel/chain-net/CMakeLists.txt b/modules/channel/chain-net/CMakeLists.txt index 44a24c1b9ecdc272036087fb3f7cff7d124bc811..62f2a5c4b245f7c271ae83da6bc27236b238b0df 100644 --- a/modules/channel/chain-net/CMakeLists.txt +++ b/modules/channel/chain-net/CMakeLists.txt @@ -1,8 +1,8 @@ cmake_minimum_required(VERSION 3.0) project (dap_stream_ch_chain_net) -set(DAP_STREAM_CH_CHAIN_NET_SRCS *.c) -set(DAP_STREAM_CH_CHAIN_NET_HDRS include/*.h) +file(GLOB DAP_STREAM_CH_CHAIN_NET_SRCS *.c) +file(GLOB DAP_STREAM_CH_CHAIN_NET_HDRS include/*.h) if(WIN32) include_directories(../../../3rdparty/wepoll/) @@ -15,3 +15,4 @@ target_link_libraries(dap_stream_ch_chain_net dap_core dap_crypto dap_stream dap dap_chain_net) target_include_directories(dap_stream_ch_chain_net INTERFACE .) +target_include_directories(${PROJECT_NAME} PUBLIC include) diff --git a/modules/channel/chain/CMakeLists.txt b/modules/channel/chain/CMakeLists.txt index 93bbfbb0555c7ed59cdd5a6db25dd7514a7e1a48..2c31b0a784978062bfe4ecb65cdd74d519e26d14 100644 --- a/modules/channel/chain/CMakeLists.txt +++ b/modules/channel/chain/CMakeLists.txt @@ -1,8 +1,8 @@ cmake_minimum_required(VERSION 3.0) project (dap_stream_ch_chain) -set(DAP_STREAM_CH_CHAIN_SRCS *.c) -set(DAP_STREAM_CH_CHAIN_SRCS include/*.h) +file(GLOB DAP_STREAM_CH_CHAIN_SRCS *.c) +file(GLOB DAP_STREAM_CH_CHAIN_HDRS include/*.h) if(WIN32) include_directories(../../../3rdparty/wepoll/) @@ -14,4 +14,4 @@ add_library(${PROJECT_NAME} STATIC ${DAP_STREAM_CH_CHAIN_SRCS} ${DAP_STREAM_CH_C target_link_libraries(dap_stream_ch_chain dap_core dap_crypto dap_chain dap_stream dap_stream_ch) target_include_directories(dap_stream_ch_chain INTERFACE .) - +target_include_directories(${PROJECT_NAME} PUBLIC include) \ No newline at end of file diff --git a/modules/common/CMakeLists.txt b/modules/common/CMakeLists.txt index b9a1e49823af7f73040ba77b31fc7c41d027c899..ca8333ab03e16b5ae470fe7bcf8680960d651d28 100644 --- a/modules/common/CMakeLists.txt +++ b/modules/common/CMakeLists.txt @@ -1,8 +1,8 @@ cmake_minimum_required(VERSION 2.8) project (dap_chain_common) -set(DAP_CHAIN_COMMON_SRCS *.c) -set(DAP_CHAIN_COMMON_HEADERS include/*.h) +file(GLOB DAP_CHAIN_COMMON_SRCS *.c) +file(GLOB DAP_CHAIN_COMMON_HEADERS include/*.h) add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_COMMON_SRCS} ${DAP_CHAIN_COMMON_HEADERS}) diff --git a/modules/consensus/block-poa/CMakeLists.txt b/modules/consensus/block-poa/CMakeLists.txt index 5a5d36de804ade34f049b5c35024691e4bf947a9..2d2fbe8bf0d258286ada2295a72b1d9e214cf162 100644 --- a/modules/consensus/block-poa/CMakeLists.txt +++ b/modules/consensus/block-poa/CMakeLists.txt @@ -1,8 +1,8 @@ cmake_minimum_required(VERSION 2.8) project (dap_chain_cs_block_poa) -set(DAP_CHAIN_BLOCK_CS_POA_SRCS *.c) -set(DAP_CHAIN_BLOCK_CS_POA_HEADERS include/*.h) +file(GLOB DAP_CHAIN_BLOCK_CS_POA_SRCS *.c) +file(GLOB DAP_CHAIN_BLOCK_CS_POA_HEADERS include/*.h) add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_BLOCK_CS_POA_SRCS} ${DAP_CHAIN_BLOCK_CS_POA_HEADERS}) add_definitions ("-DDAP_CHAIN_BLOCK_CS_POA") diff --git a/modules/consensus/block-pow/CMakeLists.txt b/modules/consensus/block-pow/CMakeLists.txt index 4d9b13ae148f278507a3d005b1ac671a8e93c599..944079a1dffa2d3f126c1a9ff782bd020f902dfc 100644 --- a/modules/consensus/block-pow/CMakeLists.txt +++ b/modules/consensus/block-pow/CMakeLists.txt @@ -1,8 +1,8 @@ cmake_minimum_required(VERSION 2.8) project (dap_chain_cs_block_pow) -set(DAP_CHAIN_BLOCK_CS_POW_SRCS *.c) -set(DAP_CHAIN_BLOCK_CS_POW_HEADERS include/*.h) +file(GLOB DAP_CHAIN_BLOCK_CS_POW_SRCS *.c) +file(GLOB DAP_CHAIN_BLOCK_CS_POW_HEADERS include/*.h) add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_BLOCK_CS_POW_SRCS} ${DAP_CHAIN_BLOCK_CS_POW_HEADERS}) diff --git a/modules/consensus/dag-poa/CMakeLists.txt b/modules/consensus/dag-poa/CMakeLists.txt index 0cea39c868959f3d6d31a657ca0f895ec372cb55..48c8e1e6f2b99e73b3a3f1725f7c1c37128e6495 100644 --- a/modules/consensus/dag-poa/CMakeLists.txt +++ b/modules/consensus/dag-poa/CMakeLists.txt @@ -1,8 +1,8 @@ cmake_minimum_required(VERSION 2.8) project (dap_chain_cs_dag_poa) -set(DAP_CHAIN_DAG_CS_POA_SRCS *.c) -set(DAP_CHAIN_DAG_CS_POA_HEADERS include/*.h) +file(GLOB DAP_CHAIN_DAG_CS_POA_SRCS *.c) +file(GLOB DAP_CHAIN_DAG_CS_POA_HEADERS include/*.h) if(WIN32) include_directories(../../../3rdparty/wepoll/) @@ -13,3 +13,4 @@ add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_DAG_CS_POA_SRCS} ${DAP_CHAIN_DAG_ target_link_libraries(dap_chain_cs_dag_poa dap_core dap_crypto dap_chain dap_chain_crypto dap_chain_cs_dag ) target_include_directories(dap_chain_cs_dag_poa INTERFACE .) +target_include_directories(${PROJECT_NAME} PUBLIC include) diff --git a/modules/consensus/dag-pos/CMakeLists.txt b/modules/consensus/dag-pos/CMakeLists.txt index 36d0f5c44f82e86cdd692b517e380339873ca9d1..7f35421cd0cacd349b318fb67ab3e5f48e135227 100644 --- a/modules/consensus/dag-pos/CMakeLists.txt +++ b/modules/consensus/dag-pos/CMakeLists.txt @@ -1,8 +1,8 @@ cmake_minimum_required(VERSION 2.8) project (dap_chain_cs_dag_pos) -set(DAP_CHAIN_CS_DAG_POS_SRCS *.c) -set(DAP_CHAIN_CS_DAG_POS_HEADERS include/*.h) +file(GLOB DAP_CHAIN_CS_DAG_POS_SRCS *.c) +file(GLOB DAP_CHAIN_CS_DAG_POS_HEADERS include/*.h) if(WIN32) include_directories(../../../3rdparty/wepoll/) @@ -13,3 +13,4 @@ add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_CS_DAG_POS_SRCS} ${DAP_CHAIN_CS_D target_link_libraries(dap_chain_cs_dag_pos dap_core dap_crypto dap_chain dap_chain_crypto dap_chain_cs_dag ) target_include_directories(dap_chain_cs_dag_pos INTERFACE .) +target_include_directories(${PROJECT_NAME} PUBLIC include) diff --git a/modules/consensus/none/CMakeLists.txt b/modules/consensus/none/CMakeLists.txt index ec4118ffeda3111d50c15e910a9fac1e1a6285c7..eb679fd4b57145aea84f370a0d5dda4150f47efd 100644 --- a/modules/consensus/none/CMakeLists.txt +++ b/modules/consensus/none/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 2.8) -project (dap_chain_cs_no_consensus) +project (dap_chain_cs_none) file(GLOB DAP_CHAIN_CS_NO_CONSENSUS_SRC *.c) file(GLOB DAP_CHAIN_CS_NO_CONSENSUS_HDR include/*.h) @@ -10,5 +10,6 @@ endif() add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_CS_NO_CONSENSUS_SRC} ${DAP_CHAIN_CS_NO_CONSENSUS_HDR}) -target_link_libraries(dap_chain_gdb dap_core dap_chain dap_chain_global_db dap_chain_mempool dap_chain_net) -target_include_directories(dap_chain_gdb INTERFACE .) +target_link_libraries(${PROJECT_NAME} dap_core dap_chain dap_chain_global_db dap_chain_mempool dap_chain_net) +target_include_directories(${PROJECT_NAME} INTERFACE .) +target_include_directories(${PROJECT_NAME} PUBLIC include) diff --git a/modules/global-db/CMakeLists.txt b/modules/global-db/CMakeLists.txt index e837ab4541351114e1574117653d0b7a5c243db3..c918ddaddc34b006a8ceffd1653c97ba5328c64b 100644 --- a/modules/global-db/CMakeLists.txt +++ b/modules/global-db/CMakeLists.txt @@ -5,19 +5,14 @@ file(GLOB DAP_CHAIN_GLOBAL_DB_SRC *.c) file(GLOB DAP_CHAIN_GLOBAL_DB_HDR include/*.h) if(WIN32) - include_directories(../../../3rdparty/wepoll/) - include_directories(../../../3rdparty/uthash/src/) + include_directories(../../3rdparty/wepoll/) + include_directories(../../3rdparty/uthash/src/) endif() - add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_GLOBAL_DB_SRC} ${DAP_CHAIN_GLOBAL_DB_HDR}) -add_subdirectory(../../../3rdparty/cuttdb) - target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_chain dap_chain_crypto sqlite3 dap_cuttdb json-c) target_include_directories(dap_chain_global_db INTERFACE .) +target_include_directories(${PROJECT_NAME} PUBLIC include) -#set(${PROJECT_NAME}_DEFINITIONS CACHE INTERNAL "${PROJECT_NAME}: Definitions" FORCE) - -#set(${PROJECT_NAME}_INCLUDE_DIRS ${PROJECT_SOURCE_DIR} CACHE INTERNAL "${PROJECT_NAME}: Include Directories" FORCE) diff --git a/modules/mempool/CMakeLists.txt b/modules/mempool/CMakeLists.txt index aa680dd6b6592399998b98e3ca7618b542c750b0..004d63d8621716ccaa83c5d7f1cf40e1bd40c3b9 100644 --- a/modules/mempool/CMakeLists.txt +++ b/modules/mempool/CMakeLists.txt @@ -13,3 +13,4 @@ add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_MEMPOOL_SRC} ${DAP_CHAIN_MEMPOOL_ target_link_libraries(dap_chain_mempool dap_http_server dap_client dap_chain_net dap_chain_global_db dap_core) target_include_directories(dap_chain_mempool INTERFACE .) +target_include_directories(${PROJECT_NAME} PUBLIC include) diff --git a/modules/mining/CMakeLists.txt b/modules/mining/CMakeLists.txt index b3b2f16de36e0405d45831a3f739de6312fe2a84..d42442f1fd37ed497deb13689a973741e7546601 100644 --- a/modules/mining/CMakeLists.txt +++ b/modules/mining/CMakeLists.txt @@ -1,11 +1,9 @@ cmake_minimum_required(VERSION 2.8) project (dap_chain_crypto) -set(DAP_CHAIN_CRYPTO_SRCS *.c) +file(GLOB DAP_CHAIN_CRYPTO_SRCS *.c) -set(DAP_CHAIN_CRYPTO_HEADERS include/*.h) - -add_subdirectory(../../../3rdparty/monero_crypto) +file(GLOB DAP_CHAIN_CRYPTO_HEADERS include/*.h) include_directories("${monero_crypto_INCLUDE_DIRS}") add_definitions ("${monero_crypto_DEFINITIONS}") @@ -13,6 +11,7 @@ add_definitions ("${monero_crypto_DEFINITIONS}") add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_CRYPTO_SRCS} ${DAP_CHAIN_CRYPTO_HEADERS}) target_include_directories(dap_chain_crypto INTERFACE .) +target_include_directories(${PROJECT_NAME} PUBLIC include) target_link_libraries(dap_chain_crypto dap_core dap_crypto dap_chain monero_crypto) set(${PROJECT_NAME}_DEFINITIONS CACHE INTERNAL "${PROJECT_NAME}: Definitions" FORCE) diff --git a/modules/net/CMakeLists.txt b/modules/net/CMakeLists.txt index e4d7c5e545a696965dd0a3e62654794e22cf0cf7..2f19f6a87b6180974d7263ed0ec3f625b39a76e2 100644 --- a/modules/net/CMakeLists.txt +++ b/modules/net/CMakeLists.txt @@ -2,9 +2,9 @@ cmake_minimum_required(VERSION 3.0) project (dap_chain_net) -set(DAP_CHAIN_NET_SRCS *.c) +file(GLOB DAP_CHAIN_NET_SRCS *.c) -set(DAP_CHAIN_NET_HEADERS *.h) +file(GLOB DAP_CHAIN_NET_HEADERS *.h) #if (ANDROID) # set(DAP_CHAIN_NET_HEADERS ${DAP_CHAIN_NET_HEADERS} @@ -50,6 +50,7 @@ if(UNIX) endif() target_include_directories(${PROJECT_NAME} INTERFACE . ) +target_include_directories(${PROJECT_NAME} PUBLIC include) if (!WIN32) target_include_directories(${PROJECT_NAME} PUBLIC ${IPUTILS_INCLUDE_DIRS}) diff --git a/modules/net/iputils/iputils.c b/modules/net/iputils/iputils.c new file mode 100755 index 0000000000000000000000000000000000000000..263590139c76977ee7e4f7ce37800825fd27e542 --- /dev/null +++ b/modules/net/iputils/iputils.c @@ -0,0 +1,49 @@ +/* + * Set utilities for networking + */ + +#include <stdio.h> +#include <stdbool.h> +#include "dap_common.h" +#include "dap_strfuncs.h" + +static bool LOG_VERBOSE = false; + +/** + * Set verbose mode + */ +void iputils_set_verbose(void) +{ + LOG_VERBOSE = true; +} + +/** + * Reset verbose mode + */ +void iputils_reset_verbose(void) +{ + LOG_VERBOSE = false; +} + +// analog printf() +int log_printf(const char *format, ...) +{ + int ret = 0; + if(LOG_VERBOSE) + { + char *log_str = NULL; + va_list args; + + va_start(args, format); + log_str = dap_strdup_vprintf(format, args); + va_end(args); + + if(log_str) + { + + ret = printf("%s", log_str); + DAP_DELETE(log_str); + } + } + return ret; +} diff --git a/modules/net/iputils/iputils.h b/modules/net/iputils/iputils.h new file mode 100644 index 0000000000000000000000000000000000000000..0330b548f1a23b5b677a4218683a933a169669e5 --- /dev/null +++ b/modules/net/iputils/iputils.h @@ -0,0 +1,189 @@ +/* + * Set utilities for networking + */ + +#ifndef _IPUTILS_H +#define _IPUTILS_H + +#include <stdint.h> +#include <stdlib.h> +#ifndef _WIN32 +#include <netinet/ip.h> +#else +#include <winsock2.h> +#include <windows.h> +#include <mswsock.h> +#include <ws2tcpip.h> +#include <io.h> +#include "win32/iphdr.h" +#include "win32/ip.h" +#define uid_t uint32_t +#endif +#include <setjmp.h> +#include <sys/time.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAXPACKET 128000 /* max packet size */ + +#define MAX_DUP_CHK 0x10000 + +#ifdef USE_BITMAP64 +typedef uint64_t bitmap_t; +# define BITMAP_SHIFT 6 +#else +typedef uint32_t bitmap_t; +# define BITMAP_SHIFT 5 +#endif + +struct rcvd_table { + bitmap_t bitmap[MAX_DUP_CHK / (sizeof(bitmap_t) * 8)]; +}; + +typedef struct ping_handle{ + int ts_type; + int nroute; + uint32_t route[10]; + + struct sockaddr_in whereto; /* who to ping */ + int optlen; + int settos; /* Set TOS, Precendence or other QOS options */ + + int broadcast_pings; + + struct sockaddr_in source; + char *device; + int pmtudisc; + struct { + + int options; + + int mark; + int sndbuf; + int ttl; + int rtt; + int rtt_addend; + uint16_t acked; + + unsigned char outpack[MAXPACKET]; + struct rcvd_table rcvd_tbl; + + // counters + long npackets; // max packets to transmit + long nreceived; // # of packets we got back + long nrepeats; // number of duplicates + long ntransmitted; // sequence # for outbound packets = #sent + long nchecksum; // replies with bad checksum + long nerrors; // icmp errors + int interval; // interval between packets (msec) + int preload; + int deadline; // time to die + int lingertime; + struct timeval start_time, cur_time; + //volatile int exiting; + //volatile int status_snapshot; + int confirm; + volatile int in_pr_addr; // pr_addr() is executing + jmp_buf pr_addr_jmp; + + /* Stupid workarounds for bugs/missing functionality in older linuces. + * confirm_flag fixes refusing service of kernels without MSG_CONFIRM. + * i.e. for linux-2.2 */ + int confirm_flag; + + // timing + int timing; // flag to do timing + long tmin; // minimum round trip time + long tmax; // maximum round trip time + /* Message for rpm maintainers: have _shame_. If you want + * to fix something send the patch to me for sanity checking. + * "sparcfix" patch is a complete non-sense, apparenly the person + * prepared it was stoned. + */ + long long tsum; // sum of all times, for doing average + long long tsum2; + int pipesize; + + int datalen; + + char *hostname; + int uid; + uid_t euid; + int ident; // process id to identify our packets + + int screen_width; + + #ifdef HAVE_LIBCAP + cap_value_t cap_raw; + cap_value_t cap_admin; + #endif + } ping_common; +}ping_handle_t; + +ping_handle_t* ping_handle_create(void); + +/** + * Send ping for ipv4 + * + * @addr host name or IP address + * @count number of packets to transmit + * @return ping time in microsecond or -1 if error + */ +int ping_util(ping_handle_t *a_ping_handle, const char *addr, int count); + +/** + * Send ping for ipv6 + * + * @addr host name or IP address + * @count number of packets to transmit + * @return ping time in microsecond or -1 if error + */ +int ping_util6(ping_handle_t *a_ping_handle, const char *addr, int count); + + +/** + * Tracepath host + * + * @addr[in] host name or IP address + * @hops[out] hops count + * @time_usec[out] latency in microseconds + * @return 0 Ok, -1 error + */ +int tracepath_util(const char *addr, int *hops, int *time_usec); + +/** + * Traceroute host + * + * @addr[in] host name or IP address + * @hops[out] hops count + * @time_usec[out] latency in microseconds + * @return 0 Ok, -1 error + */ +int traceroute_util(const char *addr, int *hops, int *time_usec); + + +/** + * Set verbose mode + */ +void iputils_set_verbose(void); +/** + * Reset verbose mode + */ +void iputils_reset_verbose(void); + + +// analog printf() +int log_printf(const char *format, ...); + +#define PACKAGE_NAME "iputils" +#define PACKAGE_VERSION "0.1" +#define IPUTILS_VERSION(_prog) "%s from %s %s\n", _prog, PACKAGE_NAME, PACKAGE_VERSION +#define UNUSED(x) (void)(x) + +#ifdef __cplusplus +} +#endif + +#endif // _IPUTILS_H diff --git a/modules/net/iputils/ping.c b/modules/net/iputils/ping.c new file mode 100644 index 0000000000000000000000000000000000000000..e634a606e8bde2c67697719a6d1295cbc4960a1d --- /dev/null +++ b/modules/net/iputils/ping.c @@ -0,0 +1,1694 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Mike Muuss. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * P I N G . C + * + * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility, + * measure round-trip-delays and packet loss across network paths. + * + * Author - + * Mike Muuss + * U. S. Army Ballistic Research Laboratory + * December, 1983 + * + * Status - + * Public Domain. Distribution Unlimited. + * Bugs - + * More statistics could always be gathered. + * If kernel does not support non-raw ICMP sockets, + * this program has to run SUID to ROOT or with + * net_cap_raw enabled. + */ + +#include "ping.h" + +#include <assert.h> +#include <netinet/ip_icmp.h> +#include <ifaddrs.h> +#include <math.h> +#include "dap_common.h" +#include "dap_strfuncs.h" +#include "iputils.h" + +#ifndef ICMP_FILTER +#define ICMP_FILTER 1 +struct icmp_filter { + uint32_t data; +}; +#endif + +ping_func_set_st ping4_func_set = { + .send_probe = ping4_send_probe, + .receive_error_msg = ping4_receive_error_msg, + .parse_reply = ping4_parse_reply, + .install_filter = ping4_install_filter +}; + +#define MAXIPLEN 60 +#define MAXICMPLEN 76 +#define NROUTES 9 /* number of record route slots */ +#define TOS_MAX 255 /* 8-bit TOS field */ + +/* +static int ts_type; +static int nroute = 0; +static uint32_t route[10]; + +static struct sockaddr_in whereto; // who to ping +static int optlen = 0; +static int settos = 0; // Set TOS, Precendence or other QOS options + +static int broadcast_pings = 0; + +static struct sockaddr_in source = { .sin_family = AF_INET }; +char *device; +int pmtudisc = -1; +*/ + +static void pr_options(ping_handle_t *a_ping_handle, unsigned char * cp, int hlen); +static void pr_iph(ping_handle_t *a_ping_handle, struct iphdr *ip); +static unsigned short in_cksum(const unsigned short *addr, int len, unsigned short salt); +static void pr_icmph(ping_handle_t *a_ping_handle, uint8_t type, uint8_t code, uint32_t info, struct icmphdr *icp); +static int parsetos(char *str); +static int parseflow(char *str); + +ping_handle_t* ping_handle_create(void) +{ + ping_handle_t *lping = DAP_NEW_Z(ping_handle_t); + lping->source.sin_family = AF_INET; + lping->pmtudisc = -1; + + lping->ping_common.interval = 1000; // interval between packets (msec) + lping->ping_common.preload = 1; + lping->ping_common.lingertime = MAXWAIT * 1000; + + + lping->ping_common.confirm_flag = MSG_CONFIRM; + + lping->ping_common.tmin = LONG_MAX; // minimum round trip time + lping->ping_common.pipesize = -1; + + lping->ping_common.datalen = DEFDATALEN; + + lping->ping_common.screen_width = INT_MAX; + +#ifdef HAVE_LIBCAP + lping->ping_common.cap_raw = CAP_NET_RAW; + lping->ping_common.cap_admin = CAP_NET_ADMIN; +#endif + + return lping; +} + +static void create_socket(ping_handle_t *a_ping_handle, socket_st *sock, int family, int socktype, int protocol, int requisite) +{ + int do_fallback = 0; + + errno = 0; + + assert(sock->fd == -1); + assert(socktype == SOCK_DGRAM || socktype == SOCK_RAW); + + /* Attempt to create a ping socket if requested. Attempt to create a raw + * socket otherwise or as a fallback. Well known errno values follow. + * + * 1) EACCES + * + * Kernel returns EACCES for all ping socket creation attempts when the + * user isn't allowed to use ping socket. A range of group ids is + * configured using the `net.ipv4.ping_group_range` sysctl. Fallback + * to raw socket is necessary. + * + * Kernel returns EACCES for all raw socket creation attempts when the + * process doesn't have the `CAP_NET_RAW` capability. + * + * 2) EAFNOSUPPORT + * + * Kernel returns EAFNOSUPPORT for IPv6 ping or raw socket creation + * attempts when run with IPv6 support disabled (e.g. via `ipv6.disable=1` + * kernel command-line option. + * + * https://github.com/iputils/iputils/issues/32 + * + * OpenVZ 2.6.32-042stab113.11 and possibly other older kernels return + * EAFNOSUPPORT for all IPv4 ping socket creation attempts due to lack + * of support in the kernel. Fallback to raw socket is necessary. + * + * https://github.com/iputils/iputils/issues/54 + * + * 3) EPROTONOSUPPORT + * + * OpenVZ 2.6.32-042stab113.11 and possibly other older kernels return + * EPROTONOSUPPORT for all IPv6 ping socket creation attempts due to lack + * of support in the kernel [1]. Debian 9.5 based container with kernel 4.10 + * returns EPROTONOSUPPORT also for IPv4 [2]. Fallback to raw socket is + * necessary. + * + * [1] https://github.com/iputils/iputils/issues/54 + * [2] https://github.com/iputils/iputils/issues/129 + */ + if(socktype == SOCK_DGRAM) + sock->fd = socket(family, socktype, protocol); + + /* Kernel doesn't support ping sockets. */ + if(sock->fd == -1 && errno == EAFNOSUPPORT && family == AF_INET) + do_fallback = 1; + if(sock->fd == -1 && errno == EPROTONOSUPPORT) + do_fallback = 1; + + /* User is not allowed to use ping sockets. */ + if(sock->fd == -1 && errno == EACCES) + do_fallback = 1; + + if(socktype == SOCK_RAW || do_fallback) { + socktype = SOCK_RAW; + sock->fd = socket(family, SOCK_RAW, protocol); + } + + if(sock->fd == -1) { + /* Report error related to disabled IPv6 only when IPv6 also failed or in + * verbose mode. Report other errors always. + */ + if((errno == EAFNOSUPPORT && socktype == AF_INET6) || (a_ping_handle->ping_common.options & F_VERBOSE) || requisite) + error(0, errno, "socket"); + if(requisite) + exit(2); + } else + sock->socktype = socktype; +} + +static void set_socket_option(socket_st *sock, int level, int optname, const void *optval, socklen_t olen) +{ + if(sock->fd == -1) + return; + + if(setsockopt(sock->fd, level, optname, optval, olen) == -1) + error(2, errno, "setsockopt"); +} + +/* Much like stdtod(3, but will fails if str is not valid number. */ +static double ping_strtod(const char *str, const char *err_msg) +{ + double num; + char *end = NULL; + + if(str == NULL || *str == '\0') + goto err; + errno = 0; +#ifdef USE_IDN + setlocale(LC_ALL, "C"); +#endif + num = strtod(str, &end); +#ifdef USE_IDN + setlocale(LC_ALL, ""); +#endif + if(errno || str == end || (end && *end)) + goto err; + switch (fpclassify(num)) { + case FP_NORMAL: + case FP_ZERO: + break; + default: + errno = ERANGE; + goto err; + } + return num; + err: + error(2, errno, "%s: %s", err_msg, str); + abort(); /* cannot be reached, above error() will exit */ + return 0.0; +} + +static int ping_main(ping_handle_t *a_ping_handle, int argc, char **argv) +{ + struct addrinfo hints = { .ai_family = AF_UNSPEC, .ai_protocol = IPPROTO_UDP, .ai_socktype = SOCK_DGRAM, .ai_flags = + getaddrinfo_flags }; + struct addrinfo *result, *ai; + int status; + int ch; + socket_st sock4 = { .fd = -1 }; + socket_st sock6 = { .fd = -1 }; + char *target; + + limit_capabilities(a_ping_handle); + +#ifdef USE_IDN + setlocale(LC_ALL, ""); + if (!strcmp(setlocale(LC_ALL, NULL), "C")) + hints.ai_flags &= ~ AI_CANONIDN; +#endif + + /* Support being called using `ping4` or `ping6` symlinks */ + if(argv[0][strlen(argv[0]) - 1] == '4') + hints.ai_family = AF_INET; + else if(argv[0][strlen(argv[0]) - 1] == '6') + hints.ai_family = AF_INET6; + + /* Parse command line options */ + while((ch = getopt(argc, argv, "h?" "4bRT:" "6F:N:" "aABc:dDfi:I:l:Lm:M:nOp:qQ:rs:S:t:UvVw:W:")) != EOF) { + switch (ch) { + /* IPv4 specific options */ + case '4': + if(hints.ai_family != AF_UNSPEC) + error(2, 0, "only one -4 or -6 option may be specified"); + hints.ai_family = AF_INET; + break; + case 'b': + a_ping_handle->broadcast_pings = 1; + break; + case 'R': + if(a_ping_handle->ping_common.options & F_TIMESTAMP) + error(2, 0, "only one of -T or -R may be used"); + a_ping_handle->ping_common.options |= F_RROUTE; + break; + case 'T': + if(a_ping_handle->ping_common.options & F_RROUTE) + error(2, 0, "only one of -T or -R may be used"); + a_ping_handle->ping_common.options |= F_TIMESTAMP; + if(strcmp(optarg, "tsonly") == 0) + a_ping_handle->ts_type = IPOPT_TS_TSONLY; + else if(strcmp(optarg, "tsandaddr") == 0) + a_ping_handle->ts_type = IPOPT_TS_TSANDADDR; + else if(strcmp(optarg, "tsprespec") == 0) + a_ping_handle->ts_type = IPOPT_TS_PRESPEC; + else + error(2, 0, "invalid timestamp type: %s", optarg); + break; + /* IPv6 specific options */ + case '6': + if(hints.ai_family != AF_UNSPEC) + error(2, 0, "only one -4 or -6 option may be specified"); + hints.ai_family = AF_INET6; + break; + case 'F': + flowlabel = parseflow(optarg); + a_ping_handle->ping_common.options |= F_FLOWINFO; + break; + case 'N': + if(niquery_option_handler(optarg) < 0) + usage(); + hints.ai_socktype = SOCK_RAW; + break; + /* Common options */ + case 'a': + a_ping_handle->ping_common.options |= F_AUDIBLE; + break; + case 'A': + a_ping_handle->ping_common.options |= F_ADAPTIVE; + break; + case 'B': + a_ping_handle->ping_common.options |= F_STRICTSOURCE; + break; + case 'c': + a_ping_handle->ping_common.npackets = atoi(optarg); + if(a_ping_handle->ping_common.npackets <= 0) + error(2, 0, "bad number of packets to transmit: %ld", a_ping_handle->ping_common.npackets); + break; + case 'd': + a_ping_handle->ping_common.options |= F_SO_DEBUG; + break; + case 'D': + a_ping_handle->ping_common.options |= F_PTIMEOFDAY; + break; + case 'i': + { + double optval; + + optval = ping_strtod(optarg, "bad timing interval"); + if(isgreater(optval, (double)(INT_MAX / 1000))) + error(2, 0, "bad timing interval: %s", optarg); + a_ping_handle->ping_common.interval = (int) (optval * 1000); + a_ping_handle->ping_common.options |= F_INTERVAL; + } + break; + case 'I': + /* IPv6 */ + if(strchr(optarg, ':')) { + char *p, *addr = strdup(optarg); + + if(!addr) + error(2, errno, "cannot copy: %s", optarg); + + p = strchr(addr, SCOPE_DELIMITER); + if(p) { + *p = '\0'; + a_ping_handle->device = optarg + (p - addr) + 1; + } + + if(inet_pton(AF_INET6, addr, (char*) &source6.sin6_addr) <= 0) + error(2, 0, "invalid source address: %s", optarg); + + a_ping_handle->ping_common.options |= F_STRICTSOURCE; + + free(addr); + } else if(inet_pton(AF_INET, optarg, &a_ping_handle->source.sin_addr) > 0) { + a_ping_handle->ping_common.options |= F_STRICTSOURCE; + } else { + a_ping_handle->device = optarg; + } + break; + case 'l': + a_ping_handle->ping_common.preload = atoi(optarg); + if(a_ping_handle->ping_common.preload <= 0) + error(2, 0, "bad preload value: %s, should be 1..%d", optarg, MAX_DUP_CHK); + if(a_ping_handle->ping_common.preload > MAX_DUP_CHK) + a_ping_handle->ping_common.preload = MAX_DUP_CHK; + if(a_ping_handle->ping_common.uid && a_ping_handle->ping_common.preload > 3) + error(2, 0, "cannot set preload to value greater than 3: %d", a_ping_handle->ping_common.preload); + break; + case 'L': + a_ping_handle->ping_common.options |= F_NOLOOP; + break; + case 'm': + { + char *endp; + a_ping_handle->ping_common.mark = (int) strtoul(optarg, &endp, 10); + if(a_ping_handle->ping_common.mark < 0 || *endp != '\0') + error(2, 0, "mark cannot be negative: %s", optarg); + a_ping_handle->ping_common.options |= F_MARK; + break; + } + case 'M': + if(strcmp(optarg, "do") == 0) + a_ping_handle->pmtudisc = IP_PMTUDISC_DO; + else if(strcmp(optarg, "dont") == 0) + a_ping_handle->pmtudisc = IP_PMTUDISC_DONT; + else if(strcmp(optarg, "want") == 0) + a_ping_handle->pmtudisc = IP_PMTUDISC_WANT; + else + error(2, 0, "invalid -M argument: %s", optarg); + break; + case 'n': + a_ping_handle->ping_common.options |= F_NUMERIC; + break; + case 'O': + a_ping_handle->ping_common.options |= F_OUTSTANDING; + break; + case 'f': + /* avoid `getaddrinfo()` during flood */ + a_ping_handle->ping_common.options |= F_FLOOD | F_NUMERIC; + setbuf(stdout, (char *) NULL); + break; + case 'p': + a_ping_handle->ping_common.options |= F_PINGFILLED; + fill(a_ping_handle, optarg, a_ping_handle->ping_common.outpack, sizeof(a_ping_handle->ping_common.outpack)); + break; + case 'q': + a_ping_handle->ping_common.options |= F_QUIET; + break; + case 'Q': + a_ping_handle->settos = parsetos(optarg); /* IPv4 */ + tclass = a_ping_handle->settos; /* IPv6 */ + break; + case 'r': + a_ping_handle->ping_common.options |= F_SO_DONTROUTE; + break; + case 's': + a_ping_handle->ping_common.datalen = atoi(optarg); + if(a_ping_handle->ping_common.datalen < 0) + error(2, 0, "illegal packet size: %d", a_ping_handle->ping_common.datalen); + if(a_ping_handle->ping_common.datalen > MAXPACKET - 8) + error(2, 0, "packet size too large: %d", a_ping_handle->ping_common.datalen); + break; + case 'S': + a_ping_handle->ping_common.sndbuf = atoi(optarg); + if(a_ping_handle->ping_common.sndbuf <= 0) + error(2, 0, "bad sndbuf value: %s", optarg); + break; + case 't': + a_ping_handle->ping_common.options |= F_TTL; + a_ping_handle->ping_common.ttl = atoi(optarg); + if(a_ping_handle->ping_common.ttl < 0 || a_ping_handle->ping_common.ttl > 255) + error(2, 0, "ttl out of range: %s", optarg); + break; + case 'U': + a_ping_handle->ping_common.options |= F_LATENCY; + break; + case 'v': + a_ping_handle->ping_common.options |= F_VERBOSE; + break; + case 'V': + printf(IPUTILS_VERSION("ping")); + exit(0); + case 'w': + a_ping_handle->ping_common.deadline = atoi(optarg); + if(a_ping_handle->ping_common.deadline < 0) + error(2, 0, "bad wait time: %s", optarg); + break; + case 'W': + { + double optval; + + optval = ping_strtod(optarg, "bad linger time"); + if(isless(optval, 0.001) || isgreater(optval, (double)(INT_MAX / 1000))) + error(2, 0, "bad linger time: %s", optarg); + /* lingertime will be converted to usec later */ + a_ping_handle->ping_common.lingertime = (int) (optval * 1000); + } + break; + default: + usage(); + break; + } + } + + argc -= optind; + argv += optind; + optind = 0; + + if(!argc) + { + //error(1, EDESTADDRREQ, "usage error"); + return -EDESTADDRREQ;// 89 Destination address required + } + + target = argv[argc - 1]; + + /* Create sockets */ + enable_capability_raw(a_ping_handle); + if(hints.ai_family != AF_INET6) + create_socket(a_ping_handle, &sock4, AF_INET, hints.ai_socktype, IPPROTO_ICMP, hints.ai_family == AF_INET); + if(hints.ai_family != AF_INET) { + create_socket(a_ping_handle, &sock6, AF_INET6, hints.ai_socktype, IPPROTO_ICMPV6, sock4.fd == -1); + /* This may not be needed if both protocol versions always had the same value, but + * since I don't know that, it's better to be safe than sorry. */ + a_ping_handle->pmtudisc = a_ping_handle->pmtudisc == IP_PMTUDISC_DO ? IPV6_PMTUDISC_DO : + a_ping_handle->pmtudisc == IP_PMTUDISC_DONT ? IPV6_PMTUDISC_DONT : + a_ping_handle->pmtudisc == IP_PMTUDISC_WANT ? IPV6_PMTUDISC_WANT : a_ping_handle->pmtudisc; + } + disable_capability_raw(a_ping_handle); + + /* Limit address family on single-protocol systems */ + if(hints.ai_family == AF_UNSPEC) { + if(sock4.fd == -1) + hints.ai_family = AF_INET6; + else if(sock6.fd == -1) + hints.ai_family = AF_INET; + } + + /* Set socket options */ + if(a_ping_handle->settos) + set_socket_option(&sock4, IPPROTO_IP, IP_TOS, &a_ping_handle->settos, sizeof (a_ping_handle->settos)); + if(tclass) + set_socket_option(&sock6, IPPROTO_IPV6, IPV6_TCLASS, &tclass, sizeof tclass); + + status = getaddrinfo(target, NULL, &hints, &result); + if(status) + { + //error(2, 0, "%s: %s", target, gai_strerror(status)); + return -EADDRNOTAVAIL;// + } + + for(ai = result; ai; ai = ai->ai_next) { + switch (ai->ai_family) { + case AF_INET: + status = ping4_run(a_ping_handle, argc, argv, ai, &sock4); + break; + case AF_INET6: + status = ping6_run(a_ping_handle, argc, argv, ai, &sock6); + break; + default: + { + //error(2, 0, "unknown protocol family: %d", ai->ai_family); + return -EPFNOSUPPORT; + } + } + + if(status == 0) + break; + } + + freeaddrinfo(result); + + return status; +} + +/** + * Send ping + * + * @type for ipv4=4, for ipv6=6 + * @addr host name or IP address + * @count number of packets to transmit + * @return ping time in microsecond or -1 if error + */ +int ping_util_common(ping_handle_t *a_ping_handle, int type, const char *addr, int count) +{ + + /* + rights for /bin/ping: -rwsr-xr-x 1 root root + current parametr: + # sysctl net.ipv4.ping_group_range + net.ipv4.ping_group_range = 1 0 + Need change range for other users: + # sysctl net.ipv4.ping_group_range="1 65000" + */ + a_ping_handle->ping_common.tsum = a_ping_handle->ping_common.ntransmitted = a_ping_handle->ping_common.nreceived = exiting = 0; + int argc = 3; + const char *argv[argc]; + if(type != 4) + argv[0] = "ping6"; + else + argv[0] = "ping4"; + argv[1] = dap_strdup_printf("-c%d", count); + argv[2] = addr; + int status = ping_main(a_ping_handle, argc, (char**) argv); + DAP_DELETE((char*) argv[1]); + if(a_ping_handle->ping_common.ntransmitted >= 1 && a_ping_handle->ping_common.nreceived >= 1) + return a_ping_handle->ping_common.tsum; + return status; +} + +/** + * Send ping for ipv4 + * + * @addr host name or IP address + * @count number of packets to transmit + * @return ping time in microsecond or -1 if error + */ +int ping_util(ping_handle_t *a_ping_handle, const char *addr, int count) +{ + return ping_util_common(a_ping_handle, 4, addr, count); +} + +/** + * Send ping for ipv6 + * + * @addr host name or IP address + * @count number of packets to transmit + * @return ping time in microsecond or -1 if error + */ +int ping_util6(ping_handle_t *a_ping_handle, const char *addr, int count) +{ + return ping_util_common(a_ping_handle, 6, addr, count); +} + +int ping4_run(ping_handle_t *a_ping_handle, int argc, char **argv, struct addrinfo *ai, socket_st *sock) +{ + static const struct addrinfo hints = { .ai_family = AF_INET, .ai_protocol = IPPROTO_UDP, .ai_flags = + getaddrinfo_flags }; + int hold, packlen; + unsigned char *packet; + char *target; + char hnamebuf[NI_MAXHOST]; + unsigned char rspace[3 + 4 * NROUTES + 1]; /* record route space */ + uint32_t *tmp_rspace; + + if(argc > 1) { + if(a_ping_handle->ping_common.options & F_RROUTE) + usage(); + else if(a_ping_handle->ping_common.options & F_TIMESTAMP) { + if(a_ping_handle->ts_type != IPOPT_TS_PRESPEC) + usage(); + if(argc > 5) + usage(); + } else { + if(argc > 10) + usage(); + a_ping_handle->ping_common.options |= F_SOURCEROUTE; + } + } + while(argc > 0) { + target = *argv; + + memset((char *) &a_ping_handle->whereto, 0, sizeof(a_ping_handle->whereto)); + a_ping_handle->whereto.sin_family = AF_INET; + if(inet_aton(target, &a_ping_handle->whereto.sin_addr) == 1) { + a_ping_handle->ping_common.hostname = target; + if(argc == 1) + a_ping_handle->ping_common.options |= F_NUMERIC; + } else { + struct addrinfo *result = NULL; + int status; + + if(argc > 1 || !ai) { + status = getaddrinfo(target, NULL, &hints, &result); + if(status) + error(2, 0, "%s: %s", target, gai_strerror(status)); + ai = result; + } + + memcpy(&a_ping_handle->whereto, ai->ai_addr, sizeof (a_ping_handle->whereto)); + memset(hnamebuf, 0, sizeof hnamebuf); + if(ai->ai_canonname) + strncpy(hnamebuf, ai->ai_canonname, sizeof hnamebuf - 1); + a_ping_handle->ping_common.hostname = hnamebuf; + + if(result) + freeaddrinfo(result); + } + if(argc > 1) + a_ping_handle->route[a_ping_handle->nroute++] = a_ping_handle->whereto.sin_addr.s_addr; + argc--; + argv++; + } + + if(a_ping_handle->source.sin_addr.s_addr == 0) { + socklen_t alen; + struct sockaddr_in dst = a_ping_handle->whereto; + int probe_fd = socket(AF_INET, SOCK_DGRAM, 0); + + if(probe_fd < 0) + error(2, errno, "socket"); + if(a_ping_handle->device) { + struct ifreq ifr; + int i; + int fds[2] = { probe_fd, sock->fd }; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, a_ping_handle->device, IFNAMSIZ - 1); + + for(i = 0; i < 2; i++) { + int fd = fds[i]; + int rc; + int errno_save; + + enable_capability_raw(a_ping_handle); + rc = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, a_ping_handle->device, strlen(a_ping_handle->device) + 1); + errno_save = errno; + disable_capability_raw(a_ping_handle); + + if(rc == -1) { + if(IN_MULTICAST(ntohl(dst.sin_addr.s_addr))) { + struct ip_mreqn imr; + if(ioctl(fd, SIOCGIFINDEX, &ifr) < 0) + error(2, 0, "unknown iface: %s", a_ping_handle->device); + memset(&imr, 0, sizeof(imr)); + imr.imr_ifindex = ifr.ifr_ifindex; + if(setsockopt(fd, SOL_IP, IP_MULTICAST_IF, &imr, sizeof(imr)) == -1) + error(2, errno, "IP_MULTICAST_IF"); + } else + error(2, errno_save, "SO_BINDTODEVICE %s", a_ping_handle->device); + } + } + } + + if(a_ping_handle->settos && + setsockopt(probe_fd, IPPROTO_IP, IP_TOS, (char *) &a_ping_handle->settos, sizeof(int)) < 0) + error(0, errno, "warning: QOS sockopts"); + + dst.sin_port = htons(1025); + if(a_ping_handle->nroute) + dst.sin_addr.s_addr = a_ping_handle->route[0]; + if(connect(probe_fd, (struct sockaddr*) &dst, sizeof(dst)) == -1) { + if(errno == EACCES) { + if(a_ping_handle->broadcast_pings == 0) + error(2, 0, + "Do you want to ping broadcast? Then -b. If not, check your local firewall rules"); + fprintf(stderr, "WARNING: pinging broadcast address\n"); + if(setsockopt(probe_fd, SOL_SOCKET, SO_BROADCAST, + &a_ping_handle->broadcast_pings, sizeof(a_ping_handle->broadcast_pings)) < 0) + error(2, errno, "cannot set broadcasting"); + if(connect(probe_fd, (struct sockaddr*) &dst, sizeof(dst)) == -1) + error(2, errno, "connect"); + } else + error(2, errno, "connect"); + } + alen = sizeof(a_ping_handle->source); + if(getsockname(probe_fd, (struct sockaddr*) &a_ping_handle->source, &alen) == -1) + error(2, errno, "getsockname"); + a_ping_handle->source.sin_port = 0; + + if(a_ping_handle->device) { + struct ifaddrs *ifa0, *ifa; + int ret; + + ret = getifaddrs(&ifa0); + if(ret) + error(2, errno, "gatifaddrs failed"); + for(ifa = ifa0; ifa; ifa = ifa->ifa_next) { + if(!ifa->ifa_name || !ifa->ifa_addr || + ifa->ifa_addr->sa_family != AF_INET) + continue; + if(!strcmp(ifa->ifa_name, a_ping_handle->device) && + !memcmp(&((struct sockaddr_in *) ifa->ifa_addr)->sin_addr, + &a_ping_handle->source.sin_addr, sizeof(a_ping_handle->source.sin_addr))) + break; + } + if(ifa && !memcmp(&((struct sockaddr_in *) ifa->ifa_addr)->sin_addr, + &dst.sin_addr, sizeof(a_ping_handle->source.sin_addr))) { + enable_capability_raw(a_ping_handle); + setsockopt(sock->fd, SOL_SOCKET, SO_BINDTODEVICE, "", 0); + disable_capability_raw(a_ping_handle); + } + freeifaddrs(ifa0); + if(!ifa) + error(0, 0, "Warning: source address might be selected on device other than: %s", a_ping_handle->device); + } + close(probe_fd); + } + while(0) + ; + + if(a_ping_handle->whereto.sin_addr.s_addr == 0) + a_ping_handle->whereto.sin_addr.s_addr = a_ping_handle->source.sin_addr.s_addr; + + if(a_ping_handle->device) { + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, a_ping_handle->device, IFNAMSIZ - 1); + if(ioctl(sock->fd, SIOCGIFINDEX, &ifr) < 0) + error(2, 0, "unknown iface: %s", a_ping_handle->device); + } + + if(a_ping_handle->broadcast_pings || IN_MULTICAST(ntohl(a_ping_handle->whereto.sin_addr.s_addr))) { + if(a_ping_handle->ping_common.uid) { + if(a_ping_handle->ping_common.interval < 1000) + error(2, 0, "broadcast ping with too short interval: %d", a_ping_handle->ping_common.interval); + if(a_ping_handle->pmtudisc >= 0 && a_ping_handle->pmtudisc != IP_PMTUDISC_DO) + error(2, 0, "broadcast ping does not fragment"); + } + if(a_ping_handle->pmtudisc < 0) + a_ping_handle->pmtudisc = IP_PMTUDISC_DO; + } + + if(a_ping_handle->pmtudisc >= 0) { + if(setsockopt(sock->fd, SOL_IP, IP_MTU_DISCOVER, &a_ping_handle->pmtudisc, sizeof (a_ping_handle->pmtudisc)) == -1) + error(2, errno, "IP_MTU_DISCOVER"); + } + + if((a_ping_handle->ping_common.options & F_STRICTSOURCE) && + bind(sock->fd, (struct sockaddr *) &a_ping_handle->source, sizeof (a_ping_handle->source)) == -1) + error(2, errno, "bind"); + + if(sock->socktype == SOCK_RAW) { + struct icmp_filter filt; + filt.data = ~((1 << ICMP_SOURCE_QUENCH) | + (1 << ICMP_DEST_UNREACH) | + (1 << ICMP_TIME_EXCEEDED) | + (1 << ICMP_PARAMETERPROB) | + (1 << ICMP_REDIRECT) | + (1 << ICMP_ECHOREPLY)); + if(setsockopt(sock->fd, SOL_RAW, ICMP_FILTER, &filt, sizeof filt) == -1) + error(0, errno, "WARNING: setsockopt(ICMP_FILTER)"); + } + + hold = 1; + if(setsockopt(sock->fd, SOL_IP, IP_RECVERR, &hold, sizeof hold)) + error(0, 0, "WARNING: your kernel is veeery old. No problems."); + + if(sock->socktype == SOCK_DGRAM) { + if(setsockopt(sock->fd, SOL_IP, IP_RECVTTL, &hold, sizeof hold)) + error(0, errno, "WARNING: setsockopt(IP_RECVTTL)"); + if(setsockopt(sock->fd, SOL_IP, IP_RETOPTS, &hold, sizeof hold)) + error(0, errno, "WARNING: setsockopt(IP_RETOPTS)"); + } + + /* record route option */ + if(a_ping_handle->ping_common.options & F_RROUTE) { + memset(rspace, 0, sizeof(rspace)); + rspace[0] = IPOPT_NOP; + rspace[1 + IPOPT_OPTVAL] = IPOPT_RR; + rspace[1 + IPOPT_OLEN] = sizeof(rspace) - 1; + rspace[1 + IPOPT_OFFSET] = IPOPT_MINOFF; + a_ping_handle->optlen = 40; + if(setsockopt(sock->fd, IPPROTO_IP, IP_OPTIONS, rspace, sizeof rspace) < 0) + error(2, errno, "record route"); + } + if(a_ping_handle->ping_common.options & F_TIMESTAMP) { + memset(rspace, 0, sizeof(rspace)); + rspace[0] = IPOPT_TIMESTAMP; + rspace[1] = (a_ping_handle->ts_type == IPOPT_TS_TSONLY ? 40 : 36); + rspace[2] = 5; + rspace[3] = a_ping_handle->ts_type; + if(a_ping_handle->ts_type == IPOPT_TS_PRESPEC) { + int i; + rspace[1] = 4 + a_ping_handle->nroute * 8; + for(i = 0; i < a_ping_handle->nroute; i++) { + tmp_rspace = (uint32_t*) &rspace[4 + i * 8]; + *tmp_rspace = a_ping_handle->route[i]; + } + } + if(setsockopt(sock->fd, IPPROTO_IP, IP_OPTIONS, rspace, rspace[1]) < 0) { + rspace[3] = 2; + if(setsockopt(sock->fd, IPPROTO_IP, IP_OPTIONS, rspace, rspace[1]) < 0) + error(2, errno, "ts option"); + } + a_ping_handle->optlen = 40; + } + if(a_ping_handle->ping_common.options & F_SOURCEROUTE) { + int i; + memset(rspace, 0, sizeof(rspace)); + rspace[0] = IPOPT_NOOP; + rspace[1 + IPOPT_OPTVAL] = (a_ping_handle->ping_common.options & F_SO_DONTROUTE) ? IPOPT_SSRR + : + IPOPT_LSRR; + rspace[1 + IPOPT_OLEN] = 3 + a_ping_handle->nroute * 4; + rspace[1 + IPOPT_OFFSET] = IPOPT_MINOFF; + for(i = 0; i < a_ping_handle->nroute; i++) { + tmp_rspace = (uint32_t*) &rspace[4 + i * 4]; + *tmp_rspace = a_ping_handle->route[i]; + } + + if(setsockopt(sock->fd, IPPROTO_IP, IP_OPTIONS, rspace, 4 + a_ping_handle->nroute * 4) < 0) + error(2, errno, "record route"); + a_ping_handle->optlen = 40; + } + + /* Estimate memory eaten by single packet. It is rough estimate. + * Actually, for small datalen's it depends on kernel side a lot. */ + hold = a_ping_handle->ping_common.datalen + 8; + hold += ((hold + 511) / 512) * (a_ping_handle->optlen + 20 + 16 + 64 + 160); + sock_setbufs(a_ping_handle, sock, hold); + + if(a_ping_handle->broadcast_pings) { + if(setsockopt(sock->fd, SOL_SOCKET, SO_BROADCAST, &a_ping_handle->broadcast_pings, sizeof (a_ping_handle->broadcast_pings)) < 0) + error(2, errno, "cannot set broadcasting"); + } + + if(a_ping_handle->ping_common.options & F_NOLOOP) { + int loop = 0; + if(setsockopt(sock->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof loop) == -1) + error(2, errno, "cannot disable multicast loopback"); + } + if(a_ping_handle->ping_common.options & F_TTL) { + int ittl = a_ping_handle->ping_common.ttl; + if(setsockopt(sock->fd, IPPROTO_IP, IP_MULTICAST_TTL, &a_ping_handle->ping_common.ttl, sizeof (a_ping_handle->ping_common.ttl)) == -1) + error(2, errno, "cannot set multicast time-to-live"); + if(setsockopt(sock->fd, IPPROTO_IP, IP_TTL, &ittl, sizeof ittl) == -1) + error(2, errno, "cannot set unicast time-to-live"); + } + + if(a_ping_handle->ping_common.datalen > 0xFFFF - 8 - a_ping_handle->optlen - 20) + error(2, 0, "packet size %d is too large. Maximum is %d", + a_ping_handle->ping_common.datalen, 0xFFFF - 8 - 20 - a_ping_handle->optlen); + + if(a_ping_handle->ping_common.datalen >= (int) sizeof(struct timeval)) /* can we time transfer */ + a_ping_handle->ping_common.timing = 1; + packlen = a_ping_handle->ping_common.datalen + MAXIPLEN + MAXICMPLEN; + if(!(packet = (unsigned char *) malloc((unsigned int) packlen))) + error(2, errno, "memory allocation failed"); + +//printf("PING %s (%s) ", hostname, inet_ntoa(whereto.sin_addr)); + if(a_ping_handle->device || (a_ping_handle->ping_common.options & F_STRICTSOURCE)) + printf("from %s %s: ", inet_ntoa(a_ping_handle->source.sin_addr), a_ping_handle->device ? a_ping_handle->device : ""); +//printf("%d(%d) bytes of data.\n", datalen, datalen + 8 + optlen + 20); + + setup(a_ping_handle, sock); + log_printf("main_loop start %s (%s)\n", a_ping_handle->ping_common.hostname, inet_ntoa(a_ping_handle->whereto.sin_addr)); + main_loop(a_ping_handle, &ping4_func_set, sock, packet, packlen); + log_printf("main_loop end\n"); + return 0; +} + +int ping4_receive_error_msg(ping_handle_t *a_ping_handle, socket_st *sock) +{ + ssize_t res; + char cbuf[512]; + struct iovec iov; + struct msghdr msg; + struct cmsghdr *cmsgh; + struct sock_extended_err *e; + struct icmphdr icmph; + struct sockaddr_in target; + int net_errors = 0; + int local_errors = 0; + int saved_errno = errno; + + iov.iov_base = &icmph; + iov.iov_len = sizeof(icmph); + msg.msg_name = (void*) ⌖ + msg.msg_namelen = sizeof(target); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_flags = 0; + msg.msg_control = cbuf; + msg.msg_controllen = sizeof(cbuf); + if(!sock) + return net_errors; + res = recvmsg(sock->fd, &msg, MSG_ERRQUEUE | MSG_DONTWAIT); + if(res < 0) + goto out; + + e = NULL; + for(cmsgh = CMSG_FIRSTHDR(&msg); cmsgh; cmsgh = CMSG_NXTHDR(&msg, cmsgh)) { + if(cmsgh->cmsg_level == SOL_IP) { + if(cmsgh->cmsg_type == IP_RECVERR) + e = (struct sock_extended_err *) CMSG_DATA(cmsgh); + } + } + if(e == NULL) + abort(); + + if(e->ee_origin == SO_EE_ORIGIN_LOCAL) { + local_errors++; + if(a_ping_handle->ping_common.options & F_QUIET) + goto out; + if(a_ping_handle->ping_common.options & F_FLOOD) + write_stdout("E", 1); + else if(e->ee_errno != EMSGSIZE) + error(0, 0, "local error: %s", strerror(e->ee_errno)); + else + error(0, 0, "local error: message too long, mtu=%u", e->ee_info); + a_ping_handle->ping_common.nerrors++; + } else if(e->ee_origin == SO_EE_ORIGIN_ICMP) { + struct sockaddr_in *sin = (struct sockaddr_in*) (e + 1); + + if(res < (ssize_t) sizeof(icmph) || + target.sin_addr.s_addr != a_ping_handle->whereto.sin_addr.s_addr || + icmph.type != ICMP_ECHO || + !is_ours(a_ping_handle, sock, icmph.un.echo.id)) { + /* Not our error, not an error at all. Clear. */ + saved_errno = 0; + goto out; + } + + acknowledge(a_ping_handle, ntohs(icmph.un.echo.sequence)); + + net_errors++; + a_ping_handle->ping_common.nerrors++; + if(a_ping_handle->ping_common.options & F_QUIET) + goto out; + if(a_ping_handle->ping_common.options & F_FLOOD) { + write_stdout("\bE", 2); + } else { + print_timestamp(a_ping_handle); + printf("From %s icmp_seq=%u ", pr_addr(a_ping_handle, sin, sizeof *sin), ntohs(icmph.un.echo.sequence)); + pr_icmph(a_ping_handle, e->ee_type, e->ee_code, e->ee_info, NULL); + fflush(stdout); + } + } + + out: + errno = saved_errno; + return net_errors ? net_errors : -local_errors; +} + +/* + * pinger -- + * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet + * will be added on by the kernel. The ID field is our UNIX process ID, + * and the sequence number is an ascending integer. The first several bytes + * of the data portion are used to hold a UNIX "timeval" struct in VAX + * byte-order, to compute the round-trip time. + */ +int ping4_send_probe(ping_handle_t *a_ping_handle, socket_st *sock, void *packet, unsigned packet_size __attribute__((__unused__))) +{ + struct icmphdr *icp; + int cc; + int i; + + icp = (struct icmphdr *) packet; + icp->type = ICMP_ECHO; + icp->code = 0; + icp->checksum = 0; + icp->un.echo.sequence = htons(a_ping_handle->ping_common.ntransmitted + 1); + icp->un.echo.id = a_ping_handle->ping_common.ident; /* ID */ + + rcvd_clear(a_ping_handle, a_ping_handle->ping_common.ntransmitted + 1); + + if(a_ping_handle->ping_common.timing) { + if(a_ping_handle->ping_common.options & F_LATENCY) { + struct timeval tmp_tv; + gettimeofday(&tmp_tv, NULL); + memcpy(icp + 1, &tmp_tv, sizeof(tmp_tv)); + } else { + memset(icp + 1, 0, sizeof(struct timeval)); + } + } + + cc = a_ping_handle->ping_common.datalen + 8; /* skips ICMP portion */ + + /* compute ICMP checksum here */ + icp->checksum = in_cksum((unsigned short *) icp, cc, 0); + + if(a_ping_handle->ping_common.timing && !(a_ping_handle->ping_common.options & F_LATENCY)) { + struct timeval tmp_tv; + gettimeofday(&tmp_tv, NULL); + memcpy(icp + 1, &tmp_tv, sizeof(tmp_tv)); + icp->checksum = in_cksum((unsigned short *) &tmp_tv, sizeof(tmp_tv), ~icp->checksum); + } + + i = sendto(sock->fd, icp, cc, 0, (struct sockaddr*) &a_ping_handle->whereto, sizeof(a_ping_handle->whereto)); + //log_printf("**sendto(fd=%d,icp=0x%x,cc=%d)=%d\n",sock->fd,&icp,cc,i); + return (cc == i ? 0 : i); +} + +/* + * parse_reply -- + * Print out the packet, if it came from us. This logic is necessary + * because ALL readers of the ICMP socket get a copy of ALL ICMP packets + * which arrive ('tis only fair). This permits multiple copies of this + * program to be run without having intermingled output (or statistics!). + */ +static +void pr_echo_reply(uint8_t *_icp, int len __attribute__((__unused__))) +{ + struct icmphdr *icp = (struct icmphdr *) _icp; + log_printf(" icmp_seq=%u", ntohs(icp->un.echo.sequence)); +} + +int +ping4_parse_reply(ping_handle_t *a_ping_handle, struct socket_st *sock, struct msghdr *msg, int cc, void *addr, struct timeval *tv) +{ + struct sockaddr_in *from = addr; + uint8_t *buf = msg->msg_iov->iov_base; + struct icmphdr *icp; + struct iphdr *ip; + int hlen; + int csfailed; + struct cmsghdr *cmsgh; + int reply_ttl; + uint8_t *opts, *tmp_ttl; + int olen; + + /* Check the IP header */ + ip = (struct iphdr *) buf; + if(sock->socktype == SOCK_RAW) { + hlen = ip->ihl * 4; + if(cc < hlen + 8 || ip->ihl < 5) { + if(a_ping_handle->ping_common.options & F_VERBOSE) + error(0, 0, "packet too short (%d bytes) from %s", cc, + pr_addr(a_ping_handle, from, sizeof *from)); + return 1; + } + reply_ttl = ip->ttl; + opts = buf + sizeof(struct iphdr); + olen = hlen - sizeof(struct iphdr); + } else { + hlen = 0; + reply_ttl = 0; + opts = buf; + olen = 0; + for(cmsgh = CMSG_FIRSTHDR(msg); cmsgh; cmsgh = CMSG_NXTHDR(msg, cmsgh)) { + if(cmsgh->cmsg_level != SOL_IP) + continue; + if(cmsgh->cmsg_type == IP_TTL) { + if(cmsgh->cmsg_len < sizeof(int)) + continue; + tmp_ttl = (uint8_t *) CMSG_DATA(cmsgh); + reply_ttl = (int) *tmp_ttl; + } else if(cmsgh->cmsg_type == IP_RETOPTS) { + opts = (uint8_t *) CMSG_DATA(cmsgh); + olen = cmsgh->cmsg_len; + } + } + } + + /* Now the ICMP part */ + cc -= hlen; + icp = (struct icmphdr *) (buf + hlen); + csfailed = in_cksum((unsigned short *) icp, cc, 0); + + if(icp->type == ICMP_ECHOREPLY) { + //log_printf("in ping4_parse_reply00\n"); + if(!is_ours(a_ping_handle, sock, icp->un.echo.id)) + return 1; /* 'Twas not our ECHO */ + if(!contains_pattern_in_payload(a_ping_handle, (uint8_t*) (icp + 1))) + return 1; /* 'Twas really not our ECHO */ + if(gather_statistics(a_ping_handle, (uint8_t*) icp, sizeof(*icp), cc, + ntohs(icp->un.echo.sequence), + reply_ttl, 0, tv, pr_addr(a_ping_handle, from, sizeof *from), + pr_echo_reply)) { + fflush(stdout); + return 0; + } + //log_printf("in ping4_parse_reply01\n"); + } else { + /* We fall here when a redirect or source quench arrived. */ + switch (icp->type) { + case ICMP_ECHO: + /* MUST NOT */ + return 1; + case ICMP_SOURCE_QUENCH: + case ICMP_REDIRECT: + case ICMP_DEST_UNREACH: + case ICMP_TIME_EXCEEDED: + case ICMP_PARAMETERPROB: + { + struct iphdr * iph = (struct iphdr *) (&icp[1]); + struct icmphdr *icp1 = (struct icmphdr*) ((unsigned char *) iph + iph->ihl * 4); + int error_pkt; + if(cc < (int) (8 + sizeof(struct iphdr) + 8) || + cc < 8 + iph->ihl * 4 + 8) + return 1; + if(icp1->type != ICMP_ECHO || + iph->daddr != a_ping_handle->whereto.sin_addr.s_addr || + !is_ours(a_ping_handle, sock, icp1->un.echo.id)) + return 1; + error_pkt = (icp->type != ICMP_REDIRECT && + icp->type != ICMP_SOURCE_QUENCH); + if(error_pkt) { + acknowledge(a_ping_handle, ntohs(icp1->un.echo.sequence)); + return 0; + } + if(a_ping_handle->ping_common.options & (F_QUIET | F_FLOOD)) + return 1; + print_timestamp(a_ping_handle); + log_printf("From %s: icmp_seq=%u ", + pr_addr(a_ping_handle, from, sizeof *from), + ntohs(icp1->un.echo.sequence)); + if(csfailed) + log_printf("(BAD CHECKSUM)"); + pr_icmph(a_ping_handle, icp->type, icp->code, ntohl(icp->un.gateway), icp); + return 1; + } + default: + /* MUST NOT */ + break; + } + if((a_ping_handle->ping_common.options & F_FLOOD) && !(a_ping_handle->ping_common.options & (F_VERBOSE | F_QUIET))) { + if(!csfailed) + write_stdout("!E", 2); + else + write_stdout("!EC", 3); + return 0; + } + if(!(a_ping_handle->ping_common.options & F_VERBOSE) || a_ping_handle->ping_common.uid) + return 0; + if(a_ping_handle->ping_common.options & F_PTIMEOFDAY) { + struct timeval recv_time; + gettimeofday(&recv_time, NULL); + log_printf("%lu.%06lu ", (unsigned long) recv_time.tv_sec, (unsigned long) recv_time.tv_usec); + } + printf("From %s: ", pr_addr(a_ping_handle, from, sizeof *from)); + if(csfailed) { + log_printf("(BAD CHECKSUM)\n"); + return 0; + } + pr_icmph(a_ping_handle, icp->type, icp->code, ntohl(icp->un.gateway), icp); + return 0; + } + + if(a_ping_handle->ping_common.options & F_AUDIBLE) { + log_printf("\a"); //putchar('\a'); + if(a_ping_handle->ping_common.options & F_FLOOD) + fflush(stdout); + } + if(!(a_ping_handle->ping_common.options & F_FLOOD)) { + pr_options(a_ping_handle, opts, olen + sizeof(struct iphdr)); + + log_printf("\n"); //putchar('\n'); + fflush(stdout); + } + return 0; +} + +#if BYTE_ORDER == LITTLE_ENDIAN +# define ODDBYTE(v) (v) +#elif BYTE_ORDER == BIG_ENDIAN +# define ODDBYTE(v) ((unsigned short)(v) << 8) +#else +# define ODDBYTE(v) htons((unsigned short)(v) << 8) +#endif + +unsigned short +in_cksum(const unsigned short *addr, int len, unsigned short csum) +{ + int nleft = len; + const unsigned short *w = addr; + unsigned short answer; + int sum = csum; + + /* + * Our algorithm is simple, using a 32 bit accumulator (sum), + * we add sequential 16 bit words to it, and at the end, fold + * back all the carry bits from the top 16 bits into the lower + * 16 bits. + */ + while(nleft > 1) { + sum += *w++; + nleft -= 2; + } + + /* mop up an odd byte, if necessary */ + if(nleft == 1) + sum += ODDBYTE(*(unsigned char * )w); /* le16toh() may be unavailable on old systems */ + + /* + * add back carry outs from top 16 bits to low 16 bits + */ + sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ + sum += (sum >> 16); /* add carry */ + answer = ~sum; /* truncate to 16 bits */ + return (answer); +} + +/* + * pr_icmph -- + * Print a descriptive string about an ICMP header. + */ +void pr_icmph(ping_handle_t *a_ping_handle, uint8_t type, uint8_t code, uint32_t info, struct icmphdr *icp) +{ + switch (type) { + case ICMP_ECHOREPLY: + printf("Echo Reply\n"); + /* XXX ID + Seq + Data */ + break; + case ICMP_DEST_UNREACH: + switch (code) { + case ICMP_NET_UNREACH: + printf("Destination Net Unreachable\n"); + break; + case ICMP_HOST_UNREACH: + printf("Destination Host Unreachable\n"); + break; + case ICMP_PROT_UNREACH: + printf("Destination Protocol Unreachable\n"); + break; + case ICMP_PORT_UNREACH: + printf("Destination Port Unreachable\n"); + break; + case ICMP_FRAG_NEEDED: + printf("Frag needed and DF set (mtu = %u)\n", info); + break; + case ICMP_SR_FAILED: + printf("Source Route Failed\n"); + break; + case ICMP_NET_UNKNOWN: + printf("Destination Net Unknown\n"); + break; + case ICMP_HOST_UNKNOWN: + printf("Destination Host Unknown\n"); + break; + case ICMP_HOST_ISOLATED: + printf("Source Host Isolated\n"); + break; + case ICMP_NET_ANO: + printf("Destination Net Prohibited\n"); + break; + case ICMP_HOST_ANO: + printf("Destination Host Prohibited\n"); + break; + case ICMP_NET_UNR_TOS: + printf("Destination Net Unreachable for Type of Service\n"); + break; + case ICMP_HOST_UNR_TOS: + printf("Destination Host Unreachable for Type of Service\n"); + break; + case ICMP_PKT_FILTERED: + printf("Packet filtered\n"); + break; + case ICMP_PREC_VIOLATION: + printf("Precedence Violation\n"); + break; + case ICMP_PREC_CUTOFF: + printf("Precedence Cutoff\n"); + break; + default: + printf("Dest Unreachable, Bad Code: %d\n", code); + break; + } + if(icp && (a_ping_handle->ping_common.options & F_VERBOSE)) + pr_iph(a_ping_handle, (struct iphdr*) (icp + 1)); + break; + case ICMP_SOURCE_QUENCH: + printf("Source Quench\n"); + if(icp && (a_ping_handle->ping_common.options & F_VERBOSE)) + pr_iph(a_ping_handle, (struct iphdr*) (icp + 1)); + break; + case ICMP_REDIRECT: + switch (code) { + case ICMP_REDIR_NET: + printf("Redirect Network"); + break; + case ICMP_REDIR_HOST: + printf("Redirect Host"); + break; + case ICMP_REDIR_NETTOS: + printf("Redirect Type of Service and Network"); + break; + case ICMP_REDIR_HOSTTOS: + printf("Redirect Type of Service and Host"); + break; + default: + printf("Redirect, Bad Code: %d", code); + break; + } + { + struct sockaddr_in sin = { .sin_family = AF_INET, .sin_addr = { icp ? icp->un.gateway : info } }; + + printf("(New nexthop: %s)\n", pr_addr(a_ping_handle, &sin, sizeof sin)); + } + if(icp && (a_ping_handle->ping_common.options & F_VERBOSE)) + pr_iph(a_ping_handle, (struct iphdr*) (icp + 1)); + break; + case ICMP_ECHO: + printf("Echo Request\n"); + /* XXX ID + Seq + Data */ + break; + case ICMP_TIME_EXCEEDED: + switch (code) { + case ICMP_EXC_TTL: + printf("Time to live exceeded\n"); + break; + case ICMP_EXC_FRAGTIME: + printf("Frag reassembly time exceeded\n"); + break; + default: + printf("Time exceeded, Bad Code: %d\n", code); + break; + } + if(icp && (a_ping_handle->ping_common.options & F_VERBOSE)) + pr_iph(a_ping_handle, (struct iphdr*) (icp + 1)); + break; + case ICMP_PARAMETERPROB: + printf("Parameter problem: pointer = %u\n", icp ? (ntohl(icp->un.gateway) >> 24) : info); + if(icp && (a_ping_handle->ping_common.options & F_VERBOSE)) + pr_iph(a_ping_handle, (struct iphdr*) (icp + 1)); + break; + case ICMP_TIMESTAMP: + printf("Timestamp\n"); + /* XXX ID + Seq + 3 timestamps */ + break; + case ICMP_TIMESTAMPREPLY: + printf("Timestamp Reply\n"); + /* XXX ID + Seq + 3 timestamps */ + break; + case ICMP_INFO_REQUEST: + printf("Information Request\n"); + /* XXX ID + Seq */ + break; + case ICMP_INFO_REPLY: + printf("Information Reply\n"); + /* XXX ID + Seq */ + break; +#ifdef ICMP_MASKREQ + case ICMP_MASKREQ: + printf("Address Mask Request\n"); + break; +#endif +#ifdef ICMP_MASKREPLY + case ICMP_MASKREPLY: + printf("Address Mask Reply\n"); + break; +#endif + default: + printf("Bad ICMP type: %d\n", type); + } +} + +void pr_options(ping_handle_t *a_ping_handle, unsigned char * cp, int hlen) +{ + int i, j; + int olen, totlen; + unsigned char * optptr; + static int old_rrlen; + static char old_rr[MAX_IPOPTLEN]; + + totlen = hlen - sizeof(struct iphdr); + optptr = cp; + + while(totlen > 0) { + if(*optptr == IPOPT_EOL) + break; + if(*optptr == IPOPT_NOP) { + totlen--; + optptr++; + printf("\nNOP"); + continue; + } + cp = optptr; + olen = optptr[1]; + if(olen < 2 || olen > totlen) + break; + + switch (*cp) { + case IPOPT_SSRR: + case IPOPT_LSRR: + printf("\n%cSRR: ", *cp == IPOPT_SSRR ? 'S' : 'L'); + j = *++cp; + cp++; + if(j > IPOPT_MINOFF) { + for(;;) { + uint32_t address; + memcpy(&address, cp, 4); + cp += 4; + if(address == 0) + printf("\t0.0.0.0"); + else { + struct sockaddr_in sin = { .sin_family = AF_INET, .sin_addr = { address } }; + + printf("\t%s", pr_addr(a_ping_handle, &sin, sizeof sin)); + } + j -= 4; + putchar('\n'); + if(j <= IPOPT_MINOFF) + break; + } + } + break; + case IPOPT_RR: + j = *++cp; /* get length */ + i = *++cp; /* and pointer */ + if(i > j) + i = j; + i -= IPOPT_MINOFF; + if(i <= 0) + break; + if(i == old_rrlen + && !memcmp(cp, old_rr, i) + && !(a_ping_handle->ping_common.options & F_FLOOD)) { + printf("\t(same route)"); + break; + } + old_rrlen = i; + memcpy(old_rr, (char *) cp, i); + printf("\nRR: "); + cp++; + for(;;) { + uint32_t address; + memcpy(&address, cp, 4); + cp += 4; + if(address == 0) + printf("\t0.0.0.0"); + else { + struct sockaddr_in sin = { .sin_family = AF_INET, .sin_addr = { address } }; + + printf("\t%s", pr_addr(a_ping_handle, &sin, sizeof sin)); + } + i -= 4; + putchar('\n'); + if(i <= 0) + break; + } + break; + case IPOPT_TS: + { + int stdtime = 0, nonstdtime = 0; + uint8_t flags; + j = *++cp; /* get length */ + i = *++cp; /* and pointer */ + if(i > j) + i = j; + i -= 5; + if(i <= 0) + break; + flags = *++cp; + printf("\nTS: "); + cp++; + for(;;) { + long l; + + if((flags & 0xF) != IPOPT_TS_TSONLY) { + uint32_t address; + memcpy(&address, cp, 4); + cp += 4; + if(address == 0) + printf("\t0.0.0.0"); + else { + struct sockaddr_in sin = { .sin_family = AF_INET, .sin_addr = { address } }; + + printf("\t%s", pr_addr(a_ping_handle, &sin, sizeof sin)); + } + i -= 4; + if(i <= 0) + break; + } + l = *cp++; + l = (l << 8) + *cp++; + l = (l << 8) + *cp++; + l = (l << 8) + *cp++; + + if(l & 0x80000000) { + if(nonstdtime == 0) + printf("\t%ld absolute not-standard", l & 0x7fffffff); + else + printf("\t%ld not-standard", (l & 0x7fffffff) - nonstdtime); + nonstdtime = l & 0x7fffffff; + } else { + if(stdtime == 0) + printf("\t%ld absolute", l); + else + printf("\t%ld", l - stdtime); + stdtime = l; + } + i -= 4; + putchar('\n'); + if(i <= 0) + break; + } + if(flags >> 4) + printf("Unrecorded hops: %d\n", flags >> 4); + break; + } + default: + printf("\nunknown option %x", *cp); + break; + } + totlen -= olen; + optptr += olen; + } +} + +/* + * pr_iph -- + * Print an IP header with options. + */ +void pr_iph(ping_handle_t *a_ping_handle, struct iphdr *ip) +{ + int hlen; + unsigned char *cp; + + hlen = ip->ihl << 2; + cp = (unsigned char *) ip + 20; /* point to options */ + + printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst Data\n"); + printf(" %1x %1x %02x %04x %04x", + ip->version, ip->ihl, ip->tos, ip->tot_len, ip->id); + printf(" %1x %04x", ((ip->frag_off) & 0xe000) >> 13, + (ip->frag_off) & 0x1fff); + printf(" %02x %02x %04x", ip->ttl, ip->protocol, ip->check); + printf(" %s ", inet_ntoa(*(struct in_addr *) &ip->saddr)); + printf(" %s ", inet_ntoa(*(struct in_addr *) &ip->daddr)); + printf("\n"); + pr_options(a_ping_handle, cp, hlen); +} + +/* + * pr_addr -- + * + * Return an ascii host address optionally with a hostname. + */ +char * +pr_addr(ping_handle_t *a_ping_handle, void *sa, socklen_t salen) +{ + static char buffer[4096] = ""; + static struct sockaddr_storage last_sa = { 0, { 0 }, 0 }; + static socklen_t last_salen = 0; + char name[NI_MAXHOST] = ""; + char address[NI_MAXHOST] = ""; + + if(salen == last_salen && !memcmp(sa, &last_sa, salen)) + return buffer; + + memcpy(&last_sa, sa, (last_salen = salen)); + + a_ping_handle->ping_common.in_pr_addr = !setjmp(a_ping_handle->ping_common.pr_addr_jmp); + + getnameinfo(sa, salen, address, sizeof address, NULL, 0, getnameinfo_flags | NI_NUMERICHOST); + if(!exiting && !(a_ping_handle->ping_common.options & F_NUMERIC)) + getnameinfo(sa, salen, name, sizeof name, NULL, 0, getnameinfo_flags); + + if(*name) + snprintf(buffer, sizeof buffer, "%s (%s)", name, address); + else + snprintf(buffer, sizeof buffer, "%s", address); + + a_ping_handle->ping_common.in_pr_addr = 0; + + return (buffer); +} + +/* Set Type of Service (TOS) and other Quality of Service relating bits */ +int parsetos(char *str) +{ + const char *cp; + int tos; + char *ep; + + /* handle both hex and decimal values */ + if(str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) { + cp = str + 2; + tos = (int) strtol(cp, &ep, 16); + } else + tos = (int) strtol(str, &ep, 10); + + /* doesn't look like decimal or hex, eh? */ + if(*ep != '\0') + error(2, 0, "bad TOS value: %s", str); + + if(tos > TOS_MAX) + error(2, 0, "the decimal value of TOS bits must be in range 0-255: %d", tos); + return (tos); +} + +int parseflow(char *str) +{ + const char *cp; + unsigned long val; + char *ep; + + /* handle both hex and decimal values */ + if(str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) { + cp = str + 2; + val = (int) strtoul(cp, &ep, 16); + } else + val = (int) strtoul(str, &ep, 10); + + /* doesn't look like decimal or hex, eh? */ + if(*ep != '\0') + error(2, 0, "bad value for flowinfo: %s", str); + + if(val & ~IPV6_FLOWINFO_FLOWLABEL) + error(2, 0, "flow value is greater than 20 bits: %s", str); + return (val); +} + +void ping4_install_filter(ping_handle_t *a_ping_handle, socket_st *sock) +{ + static int once; + static struct sock_filter insns[] = { + BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), /* Skip IP header. F..g BSD... Look into ping6. */ + BPF_STMT(BPF_LD|BPF_H|BPF_IND, 4), /* Load icmp echo ident */ + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0xAAAA, 0, 1), /* Ours? */ + BPF_STMT(BPF_RET|BPF_K, ~0U), /* Yes, it passes. */ + BPF_STMT(BPF_LD|BPF_B|BPF_IND, 0), /* Load icmp type */ + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, ICMP_ECHOREPLY, 1, 0), /* Echo? */ + BPF_STMT(BPF_RET|BPF_K, 0xFFFFFFF), /* No. It passes. */ + BPF_STMT(BPF_RET|BPF_K, 0) /* Echo with wrong ident. Reject. */ + }; + static struct sock_fprog filter = { + sizeof insns / sizeof(insns[0]), + insns + }; + + if(once) + return; + once = 1; + + /* Patch bpflet for current identifier. */ + insns[2] = (struct sock_filter )BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(a_ping_handle->ping_common.ident), 0, 1); + + if(setsockopt(sock->fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) + error(0, errno, "WARNING: failed to install socket filter"); +} diff --git a/modules/net/iputils/ping.h b/modules/net/iputils/ping.h new file mode 100644 index 0000000000000000000000000000000000000000..651455289f18f42a956cd9cfc8cf61d4f059ecfa --- /dev/null +++ b/modules/net/iputils/ping.h @@ -0,0 +1,436 @@ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <time.h> +#include <signal.h> +#include <poll.h> + +#include <sys/param.h> +#include <sys/socket.h> + +#define __USE_GNU + +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/ip6.h> +#include <netinet/ip_icmp.h> +#include <netinet/icmp6.h> + +#include <linux/filter.h> +#include <linux/types.h> +#include <linux/sockios.h> + +#include <sys/file.h> +#include <sys/time.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <sys/uio.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <netdb.h> +#include <setjmp.h> + +#include <asm/byteorder.h> +#include <sched.h> +#include <math.h> + +#include <resolv.h> + +#include "iputils.h" + +#ifdef HAVE_ERROR_H +#include <error.h> +#else +#include <stdarg.h> +#endif + +#ifdef HAVE_LIBCAP +#include <sys/prctl.h> +#include <sys/capability.h> +#endif + +#ifdef USE_IDN +#include <locale.h> +#include <idn2.h> + +#ifndef AI_IDN +#define AI_IDN 0x0040 +#endif +#ifndef AI_CANONIDN +#define AI_CANONIDN 0x0080 +#endif +#ifndef NI_IDN +#define NI_IDN 32 +#endif + +#define getaddrinfo_flags (AI_CANONNAME | AI_IDN | AI_CANONIDN) +#define getnameinfo_flags NI_IDN +#else +#define getaddrinfo_flags (AI_CANONNAME) +#define getnameinfo_flags 0 +#endif + +#include <ifaddrs.h> +#include <netinet/in.h> +#include <linux/ipv6.h> +#include <arpa/inet.h> +#include <linux/types.h> +#include <linux/errqueue.h> +#include <linux/in6.h> + +#ifndef SCOPE_DELIMITER +#define SCOPE_DELIMITER '%' +#endif + +#define DEFDATALEN (64 - 8) /* default data length */ + +#define MAXWAIT 10 /* max seconds to wait for response */ +#define MININTERVAL 10 /* Minimal interpacket gap */ +#define MINUSERINTERVAL 200 /* Minimal allowed interval for non-root */ + +#define SCHINT(a) (((a) <= MININTERVAL) ? MININTERVAL : (a)) + +/* various options */ +//extern int options; +#define F_FLOOD 0x001 +#define F_INTERVAL 0x002 +#define F_NUMERIC 0x004 +#define F_PINGFILLED 0x008 +#define F_QUIET 0x010 +#define F_RROUTE 0x020 +#define F_SO_DEBUG 0x040 +#define F_SO_DONTROUTE 0x080 +#define F_VERBOSE 0x100 +#define F_TIMESTAMP 0x200 +#define F_SOURCEROUTE 0x400 +#define F_FLOOD_POLL 0x800 +#define F_LATENCY 0x1000 +#define F_AUDIBLE 0x2000 +#define F_ADAPTIVE 0x4000 +#define F_STRICTSOURCE 0x8000 +#define F_NOLOOP 0x10000 +#define F_TTL 0x20000 +#define F_MARK 0x40000 +#define F_PTIMEOFDAY 0x80000 +#define F_OUTSTANDING 0x100000 +#define F_FLOWINFO 0x200000 +#define F_TCLASS 0x400000 + +/* + * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum + * number of received sequence numbers we can keep track of. + */ + + +#if defined(__WORDSIZE) && __WORDSIZE == 64 +# define USE_BITMAP64 +#endif + + + +#if ((MAX_DUP_CHK >> (BITMAP_SHIFT + 3)) << (BITMAP_SHIFT + 3)) != MAX_DUP_CHK +# error Please MAX_DUP_CHK and/or BITMAP_SHIFT +#endif + + + +//extern struct rcvd_table rcvd_tbl; + +//#define A(a_ping_handle, bit) (a_ping_handle->ping_common.rcvd_tbl.bitmap[(bit) >> BITMAP_SHIFT]) /* identify word in array */ +#define B(bit) (((bitmap_t)1) << ((bit) & ((1 << BITMAP_SHIFT) - 1))) /* identify bit in word */ + +static inline void rcvd_set(ping_handle_t *a_ping_handle, uint16_t seq) +{ + unsigned bit = seq % MAX_DUP_CHK; + a_ping_handle->ping_common.rcvd_tbl.bitmap[(bit) >> BITMAP_SHIFT] |= B(bit); + //A(a_ping_handle, bit) |= B(bit); +} + +static inline void rcvd_clear(ping_handle_t *a_ping_handle, uint16_t seq) +{ + unsigned bit = seq % MAX_DUP_CHK; + a_ping_handle->ping_common.rcvd_tbl.bitmap[(bit) >> BITMAP_SHIFT] &= ~B(bit); + //A(a_ping_handle, bit) &= ~B(bit); +} + +static inline bitmap_t rcvd_test(ping_handle_t *a_ping_handle, uint16_t seq) +{ + unsigned bit = seq % MAX_DUP_CHK; + return (a_ping_handle->ping_common.rcvd_tbl.bitmap[(bit) >> BITMAP_SHIFT] & B(bit)); + //return A(a_ping_handle, bit) & B(bit); +} + +#ifndef HAVE_ERROR_H +static void error(int status, int errnum, const char *format, ...) +{ + va_list ap; + + fprintf(stderr, "ping: "); + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + if (errnum) + fprintf(stderr, ": %s\n", strerror(errnum)); + else + fprintf(stderr, "\n"); + if (status) + exit(status); +} +#endif + +/* +extern int datalen; +extern char *hostname; +extern int uid; +extern int ident; // process id to identify our packets + +extern int sndbuf; +extern int ttl; + +extern long npackets; // max packets to transmit +extern long nreceived; // # of packets we got back +extern long nrepeats; // number of duplicates +extern long ntransmitted; // sequence # for outbound packets = #sent +extern long nchecksum; // replies with bad checksum +extern long nerrors; // icmp errors +extern int interval; // interval between packets (msec) +extern int preload; +extern int deadline; // time to die +extern int lingertime; +extern struct timeval start_time, cur_time; +extern int confirm; +extern int confirm_flag; +extern char *device; +extern int pmtudisc; + +extern volatile int in_pr_addr; // pr_addr() is executing +extern jmp_buf pr_addr_jmp; +*/ + +extern volatile int exiting; +extern volatile int status_snapshot; + +#ifndef MSG_CONFIRM +#define MSG_CONFIRM 0 +#endif + + +/* timing */ +/* +extern int timing; // flag to do timing +extern long tmin; // minimum round trip time +extern long tmax; // maximum round trip time +extern long long tsum; // sum of all times, for doing average +extern long long tsum2; +extern int rtt; +extern uint16_t acked; +extern int pipesize; +*/ + +/* + * Write to stdout + */ +static inline void write_stdout(const char *str, size_t len) +{ + size_t o = 0; + ssize_t cc; + do { + cc = write(STDOUT_FILENO, str + o, len - o); + o += cc; + } while (len > o || cc < 0); +} + +/* + * tvsub -- + * Subtract 2 timeval structs: out = out - in. Out is assumed to + * be >= in. + */ +static inline void tvsub(struct timeval *out, struct timeval *in) +{ + if ((out->tv_usec -= in->tv_usec) < 0) { + --out->tv_sec; + out->tv_usec += 1000000; + } + out->tv_sec -= in->tv_sec; +} + +static inline void set_signal(int signo, void (*handler)(int)) +{ + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + + sa.sa_handler = (void (*)(int))handler; + sigaction(signo, &sa, NULL); +} + +extern int __schedule_exit(ping_handle_t *a_ping_handle, int next); + +static inline int schedule_exit(ping_handle_t *a_ping_handle, int next) +{ + if (a_ping_handle->ping_common.npackets && a_ping_handle->ping_common.ntransmitted >= a_ping_handle->ping_common.npackets + && !a_ping_handle->ping_common.deadline) + next = __schedule_exit(a_ping_handle, next); + return next; +} + +static inline int in_flight(ping_handle_t *a_ping_handle) +{ + uint16_t diff = (uint16_t)a_ping_handle->ping_common.ntransmitted - a_ping_handle->ping_common.acked; + return (diff<=0x7FFF) ? diff : a_ping_handle->ping_common.ntransmitted-a_ping_handle->ping_common.nreceived-a_ping_handle->ping_common.nerrors; +} + +static inline void acknowledge(ping_handle_t *a_ping_handle, uint16_t seq) +{ + uint16_t diff = (uint16_t)a_ping_handle->ping_common.ntransmitted - seq; + if (diff <= 0x7FFF) { + if ((int)diff+1 > a_ping_handle->ping_common.pipesize) + a_ping_handle->ping_common.pipesize = (int)diff+1; + if ((int16_t)(seq - a_ping_handle->ping_common.acked) > 0 || + (uint16_t)a_ping_handle->ping_common.ntransmitted - a_ping_handle->ping_common.acked > 0x7FFF) + a_ping_handle->ping_common.acked = seq; + } +} + +static inline void advance_ntransmitted(ping_handle_t *a_ping_handle) +{ + a_ping_handle->ping_common.ntransmitted++; + /* Invalidate acked, if 16 bit seq overflows. */ + if ((uint16_t)a_ping_handle->ping_common.ntransmitted - a_ping_handle->ping_common.acked > 0x7FFF) + a_ping_handle->ping_common.acked = (uint16_t)a_ping_handle->ping_common.ntransmitted + 1; +} + +extern void usage(void) __attribute__((noreturn)); +extern void limit_capabilities(ping_handle_t *a_ping_handle); +static int enable_capability_raw(ping_handle_t *a_ping_handle); +static int disable_capability_raw(ping_handle_t *a_ping_handle); +static int enable_capability_admin(ping_handle_t *a_ping_handle); +static int disable_capability_admin(ping_handle_t *a_ping_handle); +#ifdef HAVE_LIBCAP +extern int modify_capability(cap_value_t, cap_flag_value_t); +static inline int enable_capability_raw(void) { return modify_capability(CAP_NET_RAW, CAP_SET); } +static inline int disable_capability_raw(void) { return modify_capability(CAP_NET_RAW, CAP_CLEAR); } +static inline int enable_capability_admin(void) { return modify_capability(CAP_NET_ADMIN, CAP_SET); } +static inline int disable_capability_admin(void) { return modify_capability(CAP_NET_ADMIN, CAP_CLEAR); } +#else +extern int modify_capability(ping_handle_t *a_ping_handle, int); +static inline int enable_capability_raw(ping_handle_t *a_ping_handle) { return modify_capability(a_ping_handle, 1); } +static inline int disable_capability_raw(ping_handle_t *a_ping_handle) { return modify_capability(a_ping_handle, 0); } +static inline int enable_capability_admin(ping_handle_t *a_ping_handle) { return modify_capability(a_ping_handle, 1); } +static inline int disable_capability_admin(ping_handle_t *a_ping_handle) { return modify_capability(a_ping_handle, 0); } +#endif +extern void drop_capabilities(void); + +typedef struct socket_st { + int fd; + int socktype; +} socket_st; + +char *pr_addr(ping_handle_t *a_ping_handle, void *sa, socklen_t salen); + +int is_ours(ping_handle_t *a_ping_handle, socket_st *sock, uint16_t id); + +int ping4_run(ping_handle_t *a_ping_handle, int argc, char **argv, struct addrinfo *ai, socket_st *sock); +int ping4_send_probe(ping_handle_t *a_ping_handle, socket_st *, void *packet, unsigned packet_size); +int ping4_receive_error_msg(ping_handle_t *a_ping_handle, socket_st *sock); +int ping4_parse_reply(ping_handle_t *a_ping_handle, socket_st *, struct msghdr *msg, int len, void *addr, struct timeval *); +void ping4_install_filter( ping_handle_t *a_ping_handle, socket_st *); + +typedef struct ping_func_set_st { + int (*send_probe)(ping_handle_t *a_ping_handle, socket_st *, void *packet, unsigned packet_size); + int (*receive_error_msg)(ping_handle_t *a_ping_handle, socket_st *sock); + int (*parse_reply)(ping_handle_t *a_ping_handle, socket_st *, struct msghdr *msg, int len, void *addr, struct timeval *); + void (*install_filter)(ping_handle_t *a_ping_handle, socket_st *); +} ping_func_set_st; + +extern ping_func_set_st ping4_func_set; + +extern int pinger(ping_handle_t *a_ping_handle, ping_func_set_st *fset, socket_st *sock); +extern void sock_setbufs(ping_handle_t *a_ping_handle, socket_st*, int alloc); +extern void setup(ping_handle_t *a_ping_handle, socket_st *); +extern int contains_pattern_in_payload(ping_handle_t *a_ping_handle, uint8_t *ptr); +extern void main_loop(ping_handle_t *a_ping_handle, ping_func_set_st *fset, socket_st*, uint8_t *buf, int buflen);// __attribute__((noreturn)); +extern void finish(ping_handle_t *a_ping_handle);// __attribute__((noreturn)); +extern void status(ping_handle_t *a_ping_handle); +extern void common_options(int ch); +extern int gather_statistics(ping_handle_t *a_ping_handle, uint8_t *ptr, int icmplen, + int cc, uint16_t seq, int hops, + int csfailed, struct timeval *tv, char *from, + void (*pr_reply)(uint8_t *ptr, int cc)); +extern void print_timestamp(ping_handle_t *a_ping_handle); +void fill(ping_handle_t *a_ping_handle, char *patp, unsigned char *packet, unsigned packet_size); + +//extern int mark; +//extern unsigned char outpack[MAXPACKET]; + +/* IPv6 */ + +int ping6_run(ping_handle_t *a_ping_handle, int argc, char **argv, struct addrinfo *ai, socket_st *sock); +void ping6_usage(unsigned from_ping); + +int ping6_send_probe(ping_handle_t *a_ping_handle, socket_st *sockets, void *packet, unsigned packet_size); +int ping6_receive_error_msg(ping_handle_t *a_ping_handle, socket_st *sock); +int ping6_parse_reply(ping_handle_t *a_ping_handle, socket_st *, struct msghdr *msg, int len, void *addr, struct timeval *); +void ping6_install_filter(ping_handle_t *a_ping_handle, socket_st *sockets); + +extern ping_func_set_st ping6_func_set; + +int niquery_option_handler(const char *opt_arg); + +extern uint32_t tclass; +extern uint32_t flowlabel; +extern struct sockaddr_in6 source6; +extern struct sockaddr_in6 whereto6; +extern struct sockaddr_in6 firsthop6; + +/* IPv6 node information query */ + +#define NI_NONCE_SIZE 8 + +struct ni_hdr { + struct icmp6_hdr ni_u; + uint8_t ni_nonce[NI_NONCE_SIZE]; +}; + +#define ni_type ni_u.icmp6_type +#define ni_code ni_u.icmp6_code +#define ni_cksum ni_u.icmp6_cksum +#define ni_qtype ni_u.icmp6_data16[0] +#define ni_flags ni_u.icmp6_data16[1] + +/* Types */ +#ifndef ICMPV6_NI_QUERY +# define ICMPV6_NI_QUERY 139 +# define ICMPV6_NI_REPLY 140 +#endif + +/* Query Codes */ +#define NI_SUBJ_IPV6 0 +#define NI_SUBJ_NAME 1 +#define NI_SUBJ_IPV4 2 + +/* Reply Codes */ +#define NI_SUCCESS 0 +#define NI_REFUSED 1 +#define NI_UNKNOWN 2 + +/* Qtypes */ +#define NI_QTYPE_NOOP 0 +#define NI_QTYPE_NAME 2 +#define NI_QTYPE_IPV6ADDR 3 +#define NI_QTYPE_IPV4ADDR 4 + +/* Flags */ +#define NI_IPV6ADDR_F_TRUNCATE __constant_cpu_to_be16(0x0001) +#define NI_IPV6ADDR_F_ALL __constant_cpu_to_be16(0x0002) +#define NI_IPV6ADDR_F_COMPAT __constant_cpu_to_be16(0x0004) +#define NI_IPV6ADDR_F_LINKLOCAL __constant_cpu_to_be16(0x0008) +#define NI_IPV6ADDR_F_SITELOCAL __constant_cpu_to_be16(0x0010) +#define NI_IPV6ADDR_F_GLOBAL __constant_cpu_to_be16(0x0020) + +#define NI_IPV4ADDR_F_TRUNCATE NI_IPV6ADDR_F_TRUNCATE +#define NI_IPV4ADDR_F_ALL NI_IPV6ADDR_F_ALL + + diff --git a/modules/net/iputils/ping6_common.c b/modules/net/iputils/ping6_common.c new file mode 100644 index 0000000000000000000000000000000000000000..3bb143fadd3c39f6bc58b146e380892f50e365aa --- /dev/null +++ b/modules/net/iputils/ping6_common.c @@ -0,0 +1,1398 @@ +/* + * + * Modified for AF_INET6 by Pedro Roque + * + * <roque@di.fc.ul.pt> + * + * Original copyright notice included bellow + */ + +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Mike Muuss. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * P I N G . C + * + * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility, + * measure round-trip-delays and packet loss across network paths. + * + * Author - + * Mike Muuss + * U. S. Army Ballistic Research Laboratory + * December, 1983 + * + * Status - + * Public Domain. Distribution Unlimited. + * Bugs - + * More statistics could always be gathered. + * If kernel does not support non-raw ICMP sockets or + * if -N option is used, this program has to run SUID to ROOT or + * with net_cap_raw enabled. + */ + +#include "ping.h" + +/* IPv6 packet information. */ +//struct in6_pktinfo +// { +// struct in6_addr ipi6_addr; /* src/dst IPv6 address */ +// unsigned int ipi6_ifindex; /* send/recv interface index */ +// }; + +ping_func_set_st ping6_func_set = { + .send_probe = ping6_send_probe, + .receive_error_msg = ping6_receive_error_msg, + .parse_reply = ping6_parse_reply, + .install_filter = ping6_install_filter +}; + +#ifndef SCOPE_DELIMITER +# define SCOPE_DELIMITER '%' +#endif + +uint32_t flowlabel; +uint32_t tclass; + +static struct sockaddr_in6 whereto; +static struct sockaddr_in6 firsthop; + +static unsigned char cmsgbuf[4096]; +static size_t cmsglen = 0; + +static int pr_icmph(uint8_t type, uint8_t code, uint32_t info); + +struct sockaddr_in6 source6 = { .sin6_family = AF_INET6 }; +//extern char *device; + +#if defined(USE_GCRYPT) || defined(USE_OPENSSL) || defined(USE_NETTLE) +#include "iputils_md5dig.h" +#define USE_CRYPTO +#endif + +/* Node Information query */ +int ni_query = -1; +int ni_flag = 0; +void *ni_subject = NULL; +int ni_subject_len = 0; +int ni_subject_type = -1; +char *ni_group; + +static inline int ntohsp(uint16_t *p) +{ + uint16_t v; + memcpy(&v, p, sizeof(v)); + return ntohs(v); +} + +unsigned int if_name2index(const char *ifname) +{ + unsigned int i = if_nametoindex(ifname); + if(!i) + error(2, 0, "unknown iface: %s", ifname); + return i; +} + +struct niquery_option { + char *name; + int namelen; + int has_arg; + int data; + int (*handler)(int index, const char *arg); +}; + +#define NIQUERY_OPTION(_name, _has_arg, _data, _handler) \ + { \ + .name = _name, \ + .namelen = sizeof(_name) - 1, \ + .has_arg = _has_arg, \ + .data = _data, \ + .handler = _handler \ + } + +static int niquery_option_name_handler(int index __attribute__((__unused__)), + const char *arg __attribute__((__unused__))); +static int niquery_option_ipv6_handler(int index __attribute__((__unused__)), + const char *arg __attribute__((__unused__))); +static int niquery_option_ipv6_flag_handler(int index, const char *arg); +static int niquery_option_ipv4_handler(int index, const char *arg); +static int niquery_option_ipv4_flag_handler(int index, const char *arg); +static int niquery_option_subject_addr_handler(int index, const char *arg); +static int niquery_option_subject_name_handler(int index, const char *arg); +static int niquery_option_help_handler(int index, const char *arg); + +struct niquery_option niquery_options[] = { +NIQUERY_OPTION("name", 0, 0, niquery_option_name_handler), +NIQUERY_OPTION("fqdn", 0, 0, niquery_option_name_handler), +NIQUERY_OPTION("ipv6", 0, 0, niquery_option_ipv6_handler), +NIQUERY_OPTION("ipv6-all", 0, NI_IPV6ADDR_F_ALL, niquery_option_ipv6_flag_handler), +NIQUERY_OPTION("ipv6-compatible", 0, NI_IPV6ADDR_F_COMPAT, niquery_option_ipv6_flag_handler), +NIQUERY_OPTION("ipv6-linklocal", 0, NI_IPV6ADDR_F_LINKLOCAL, niquery_option_ipv6_flag_handler), +NIQUERY_OPTION("ipv6-sitelocal", 0, NI_IPV6ADDR_F_SITELOCAL, niquery_option_ipv6_flag_handler), +NIQUERY_OPTION("ipv6-global", 0, NI_IPV6ADDR_F_GLOBAL, niquery_option_ipv6_flag_handler), +NIQUERY_OPTION("ipv4", 0, 0, niquery_option_ipv4_handler), +NIQUERY_OPTION("ipv4-all", 0, NI_IPV4ADDR_F_ALL, niquery_option_ipv4_flag_handler), +NIQUERY_OPTION("subject-ipv6", 1, NI_SUBJ_IPV6, niquery_option_subject_addr_handler), +NIQUERY_OPTION("subject-ipv4", 1, NI_SUBJ_IPV4, niquery_option_subject_addr_handler), +NIQUERY_OPTION("subject-name", 1, 0, niquery_option_subject_name_handler), +NIQUERY_OPTION("subject-fqdn", 1, -1, niquery_option_subject_name_handler), +NIQUERY_OPTION("help", 0, 0, niquery_option_help_handler), + { NULL, 0, 0, 0, NULL } +}; + +static inline int niquery_is_enabled(void) +{ + return ni_query >= 0; +} + +#if PING6_NONCE_MEMORY +uint8_t *ni_nonce_ptr; +#else +struct { + struct timeval tv; + pid_t pid; +} ni_nonce_secret; +#endif + +static void niquery_init_nonce(void) +{ +#if PING6_NONCE_MEMORY + struct timeval tv; + unsigned long seed; + + seed = (unsigned long)getpid(); + if (!gettimeofday(&tv, NULL)) + seed ^= tv.tv_usec; + srand(seed); + + ni_nonce_ptr = calloc(NI_NONCE_SIZE, MAX_DUP_CHK); + if (!ni_nonce_ptr) + error(2, errno, "calloc"); + + ni_nonce_ptr[0] = ~0; +#else + gettimeofday(&ni_nonce_secret.tv, NULL); + ni_nonce_secret.pid = getpid(); +#endif +} + +#if !PING6_NONCE_MEMORY +static int niquery_nonce(uint8_t *nonce, int fill) +{ +# ifdef USE_CRYPTO + static uint8_t digest[MD5_DIGEST_LENGTH]; + static int seq = -1; + + if (fill || seq != *(uint16_t *)nonce || seq < 0) { + MD5_CTX ctxt; + + MD5_Init(&ctxt); + MD5_Update(&ctxt, &ni_nonce_secret, sizeof(ni_nonce_secret)); + MD5_Update(&ctxt, nonce, sizeof(uint16_t)); + MD5_Final(digest, &ctxt); + + seq = *(uint16_t *)nonce; + } + + if (fill) { + memcpy(nonce + sizeof(uint16_t), digest, NI_NONCE_SIZE - sizeof(uint16_t)); + return 0; + } else { + if (memcmp(nonce + sizeof(uint16_t), digest, NI_NONCE_SIZE - sizeof(uint16_t))) + return -1; + return ntohsp((uint16_t *)nonce); + } +# else + error(3, ENOSYS, "niquery_nonce() crypto disabled"); +# endif + if(nonce || fill) + return -1; + return -1; +} +#endif + +static inline void niquery_fill_nonce(uint16_t seq, uint8_t *nonce) +{ + uint16_t v = htons(seq); +#if PING6_NONCE_MEMORY + int i; + + memcpy(&ni_nonce_ptr[NI_NONCE_SIZE * (seq % MAX_DUP_CHK)], &v, sizeof(v)); + + for (i = sizeof(v); i < NI_NONCE_SIZE; i++) + ni_nonce_ptr[NI_NONCE_SIZE * (seq % MAX_DUP_CHK) + i] = 0x100 * (rand() / (RAND_MAX + 1.0)); + + memcpy(nonce, &ni_nonce_ptr[NI_NONCE_SIZE * (seq % MAX_DUP_CHK)], NI_NONCE_SIZE); +#else + memcpy(nonce, &v, sizeof(v)); + niquery_nonce(nonce, 1); +#endif +} + +static inline int niquery_check_nonce(uint8_t *nonce) +{ +#if PING6_NONCE_MEMORY + uint16_t seq = ntohsp((uint16_t *)nonce); + if (memcmp(nonce, &ni_nonce_ptr[NI_NONCE_SIZE * (seq % MAX_DUP_CHK)], NI_NONCE_SIZE)) + return -1; + return seq; +#else + return niquery_nonce(nonce, 0); +#endif +} + +static int niquery_set_qtype(int type) +{ + if(niquery_is_enabled() && ni_query != type) { + printf("Qtype conflict\n"); + return -1; + } + ni_query = type; + return 0; +} + +static int niquery_option_name_handler(int index __attribute__((__unused__)), + const char *arg __attribute__((__unused__))) +{ + if(niquery_set_qtype(NI_QTYPE_NAME) < 0) + return -1; + return 0; +} + +static int niquery_option_ipv6_handler(int index __attribute__((__unused__)), + const char *arg __attribute__((__unused__))) +{ + if(niquery_set_qtype(NI_QTYPE_IPV6ADDR) < 0) + return -1; + return 0; +} + +static int niquery_option_ipv6_flag_handler(int index, const char *arg __attribute__((__unused__))) +{ + if(niquery_set_qtype(NI_QTYPE_IPV6ADDR) < 0) + return -1; + ni_flag |= niquery_options[index].data; + return 0; +} + +static int niquery_option_ipv4_handler(int index __attribute__((__unused__)), + const char *arg __attribute__((__unused__))) +{ + if(niquery_set_qtype(NI_QTYPE_IPV4ADDR) < 0) + return -1; + return 0; +} + +static int niquery_option_ipv4_flag_handler(int index, const char *arg __attribute__((__unused__))) +{ + if(niquery_set_qtype(NI_QTYPE_IPV4ADDR) < 0) + return -1; + ni_flag |= niquery_options[index].data; + return 0; +} + +static inline int niquery_is_subject_valid(void) +{ + return ni_subject_type >= 0 && ni_subject; +} + +static int niquery_set_subject_type(int type) +{ + if(niquery_is_subject_valid() && ni_subject_type != type) { + printf("Subject type conflict\n"); + return -1; + } + ni_subject_type = type; + return 0; +} + +#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) +#define OFFSET_OF(type,elem) ((size_t)&((type *)0)->elem) + +static int niquery_option_subject_addr_handler(int index, const char *arg) +{ + struct addrinfo hints = { .ai_family = AF_UNSPEC, .ai_socktype = SOCK_DGRAM, .ai_flags = getaddrinfo_flags }; + struct addrinfo *result, *ai; + int status; + int offset; + + if(niquery_set_subject_type(niquery_options[index].data) < 0) + return -1; + + ni_subject_type = niquery_options[index].data; + + switch (niquery_options[index].data) { + case NI_SUBJ_IPV6: + ni_subject_len = sizeof(struct in6_addr); + offset = OFFSET_OF(struct sockaddr_in6, sin6_addr); + hints.ai_family = AF_INET6; + break; + case NI_SUBJ_IPV4: + ni_subject_len = sizeof(struct in_addr); + offset = OFFSET_OF(struct sockaddr_in, sin_addr); + hints.ai_family = AF_INET; + break; + default: + /* should not happen. */ + offset = -1; + } + + status = getaddrinfo(arg, 0, &hints, &result); + if(status) { + error(0, 0, "%s: %s", arg, gai_strerror(status)); + return -1; + } + + for(ai = result; ai; ai = ai->ai_next) { + void *p = malloc(ni_subject_len); + if(!p) + continue; + memcpy(p, (uint8_t *) ai->ai_addr + offset, ni_subject_len); + free(ni_subject); + ni_subject = p; + break; + } + freeaddrinfo(result); + + return 0; +} + +#ifdef USE_IDN +# if IDN2_VERSION_NUMBER >= 0x02000000 +# define IDN2_FLAGS IDN2_NONTRANSITIONAL +# else +# define IDN2_FLAGS 0 +# endif +#endif + +#ifdef USE_CRYPTO +static int niquery_option_subject_name_handler(int index, const char *name) +{ + static char nigroup_buf[INET6_ADDRSTRLEN + 1 + IFNAMSIZ]; + unsigned char *dnptrs[2], **dpp, **lastdnptr; + int n; + size_t i; + char *p; + char *canonname = NULL, *idn = NULL; + unsigned char *buf = NULL; + size_t namelen; + size_t buflen; + int dots, fqdn = niquery_options[index].data; + MD5_CTX ctxt; + uint8_t digest[MD5_DIGEST_LENGTH]; +#ifdef USE_IDN + int rc; +#endif + + if (niquery_set_subject_type(NI_SUBJ_NAME) < 0) + return -1; + +#ifdef USE_IDN + rc = idn2_lookup_ul(name, &idn, IDN2_FLAGS); + if (rc) + error(2, 0, "IDN encoding error: %s", idn2_strerror(rc)); +#else + idn = strdup(name); + if (!idn) + goto oomexit; +#endif + + p = strchr(idn, SCOPE_DELIMITER); + if (p) { + *p = '\0'; + if (strlen(p + 1) >= IFNAMSIZ) + error(1, 0, "too long scope name"); + } + + namelen = strlen(idn); + canonname = malloc(namelen + 1); + if (!canonname) + goto oomexit; + + dots = 0; + for (i = 0; i < namelen + 1; i++) { + canonname[i] = isupper(idn[i]) ? tolower(idn[i]) : idn[i]; + if (idn[i] == '.') + dots++; + } + + if (fqdn == 0) { + /* guess if hostname is FQDN */ + fqdn = dots ? 1 : -1; + } + + buflen = namelen + 3 + 1; /* dn_comp() requrires strlen() + 3, + plus non-fqdn indicator. */ + buf = malloc(buflen); + if (!buf) { + error(0, errno, "memory allocation failed"); + goto errexit; + } + + dpp = dnptrs; + lastdnptr = &dnptrs[ARRAY_SIZE(dnptrs)]; + + *dpp++ = (unsigned char *)buf; + *dpp++ = NULL; + + n = dn_comp(canonname, (unsigned char *)buf, buflen, dnptrs, lastdnptr); + if (n < 0) { + error(0, 0, "inappropriate subject name: %s", canonname); + goto errexit; + } else if ((size_t) n >= buflen) { + error(0, 0, "dn_comp() returned too long result"); + goto errexit; + } + + MD5_Init(&ctxt); + MD5_Update(&ctxt, buf, buf[0]); + MD5_Final(digest, &ctxt); + + sprintf(nigroup_buf, "ff02::2:%02x%02x:%02x%02x%s%s", + digest[0], digest[1], digest[2], digest[3], + p ? "%" : "", + p ? p + 1 : ""); + + if (fqdn < 0) + buf[n] = 0; + + free(ni_subject); + + ni_group = nigroup_buf; + ni_subject = buf; + ni_subject_len = n + (fqdn < 0); + ni_group = nigroup_buf; + + free(canonname); + free(idn); + + return 0; + oomexit: + error(0, errno, "memory allocation failed"); + errexit: + free(buf); + free(canonname); + free(idn); + exit(1); +} +#else +static int niquery_option_subject_name_handler(int index __attribute__((__unused__)), + const char *name __attribute__((__unused__))) +{ + error(3, ENOSYS, "niquery_option_subject_name_handler() crypto disabled"); + return -1; +} +#endif + +int niquery_option_help_handler(int index __attribute__((__unused__)), const char *arg __attribute__((__unused__))) +{ + fprintf(stderr, "ping -6 -N <nodeinfo opt>\n" + "Help:\n" + " help\n" + "Query:\n" + " name\n" + " ipv6\n" + " ipv6-all\n" + " ipv6-compatible\n" + " ipv6-global\n" + " ipv6-linklocal\n" + " ipv6-sitelocal\n" + " ipv4\n" + " ipv4-all\n" + "Subject:\n" + " subject-ipv6=addr\n" + " subject-ipv4=addr\n" + " subject-name=name\n" + " subject-fqdn=name\n" + ); + exit(2); +} + +int niquery_option_handler(const char *opt_arg) +{ + struct niquery_option *p; + int i; + int ret = -1; + for(i = 0, p = niquery_options; p->name; i++, p++) { + if(strncmp(p->name, opt_arg, p->namelen)) + continue; + if(!p->has_arg) { + if(opt_arg[p->namelen] == '\0') { + ret = p->handler(i, NULL); + if(ret >= 0) + break; + } + } else { + if(opt_arg[p->namelen] == '=') { + ret = p->handler(i, &opt_arg[p->namelen] + 1); + if(ret >= 0) + break; + } + } + } + if(!p->name) + ret = niquery_option_help_handler(0, NULL); + return ret; +} + +int ping6_run(ping_handle_t *a_ping_handle, int argc, char **argv, struct addrinfo *ai, struct socket_st *sock) +{ + static const struct addrinfo hints = { .ai_family = AF_INET6, .ai_flags = getaddrinfo_flags }; + struct addrinfo *result = NULL; + int status; + int hold, packlen; + unsigned char *packet; + char *target; + struct icmp6_filter filter; + int err; + static uint32_t scope_id = 0; + + if(niquery_is_enabled()) { + niquery_init_nonce(); + + if(!niquery_is_subject_valid()) { + ni_subject = &whereto.sin6_addr; + ni_subject_len = sizeof(whereto.sin6_addr); + ni_subject_type = NI_SUBJ_IPV6; + } + } + + if(argc > 1) { + usage(); + } else if(argc == 1) { + target = *argv; + } else { + if(ni_query < 0 && ni_subject_type != NI_SUBJ_NAME) + usage(); + target = ni_group; + } + + if(!ai) { + status = getaddrinfo(target, NULL, &hints, &result); + if(status) + error(2, 0, "%s: %s", target, gai_strerror(status)); + ai = result; + } + + memcpy(&whereto, ai->ai_addr, sizeof(whereto)); + whereto.sin6_port = htons(IPPROTO_ICMPV6); + + if(result) + freeaddrinfo(result); + + if(memchr(target, ':', strlen(target))) + a_ping_handle->ping_common.options |= F_NUMERIC; + + if(IN6_IS_ADDR_UNSPECIFIED(&firsthop.sin6_addr)) { + memcpy(&firsthop.sin6_addr, &whereto.sin6_addr, 16); + firsthop.sin6_scope_id = whereto.sin6_scope_id; + /* Verify scope_id is the same as intermediate nodes */ + if(firsthop.sin6_scope_id && scope_id && firsthop.sin6_scope_id != scope_id) + error(2, 0, "scope discrepancy among the nodes"); + else if(!scope_id) + scope_id = firsthop.sin6_scope_id; + } + + a_ping_handle->ping_common.hostname = target; + + if(IN6_IS_ADDR_UNSPECIFIED(&source6.sin6_addr)) { + socklen_t alen; + int probe_fd = socket(AF_INET6, SOCK_DGRAM, 0); + + if(probe_fd < 0) + error(2, errno, "socket"); + if(a_ping_handle->device) { + unsigned int iface = if_name2index(a_ping_handle->device); +#ifdef IPV6_RECVPKTINFO + struct in6_pktinfo ipi; + + memset(&ipi, 0, sizeof(ipi)); + ipi.ipi6_ifindex = iface; +#endif + + if(IN6_IS_ADDR_LINKLOCAL(&firsthop.sin6_addr) || + IN6_IS_ADDR_MC_LINKLOCAL(&firsthop.sin6_addr)) + firsthop.sin6_scope_id = iface; + enable_capability_raw(a_ping_handle); +#ifdef IPV6_RECVPKTINFO + if( + setsockopt(probe_fd, IPPROTO_IPV6, IPV6_PKTINFO, &ipi, sizeof ipi) == -1 || + setsockopt(sock->fd, IPPROTO_IPV6, IPV6_PKTINFO, &ipi, sizeof ipi) == -1) { + perror("setsockopt(IPV6_PKTINFO)"); + exit(2); + } +#endif + if( + setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, a_ping_handle->device, strlen(a_ping_handle->device) + 1) == -1 || + setsockopt(sock->fd, SOL_SOCKET, SO_BINDTODEVICE, a_ping_handle->device, strlen(a_ping_handle->device) + 1) == -1) { + error(2, errno, "setsockopt(SO_BINDTODEVICE) %s", a_ping_handle->device); + } + disable_capability_raw(a_ping_handle); + } + + if(!IN6_IS_ADDR_LINKLOCAL(&firsthop.sin6_addr) && + !IN6_IS_ADDR_MC_LINKLOCAL(&firsthop.sin6_addr)) + firsthop.sin6_family = AF_INET6; + + firsthop.sin6_port = htons(1025); + if(connect(probe_fd, (struct sockaddr*) &firsthop, sizeof(firsthop)) == -1) + error(2, errno, "connect"); + alen = sizeof source6; + if(getsockname(probe_fd, (struct sockaddr *) &source6, &alen) == -1) + error(2, errno, "getsockname"); + source6.sin6_port = 0; + close(probe_fd); + + if(a_ping_handle->device) { + struct ifaddrs *ifa0, *ifa; + + if(getifaddrs(&ifa0)) + error(2, errno, "getifaddrs"); + + for(ifa = ifa0; ifa; ifa = ifa->ifa_next) { + if(!ifa->ifa_name || !ifa->ifa_addr || + ifa->ifa_addr->sa_family != AF_INET6) + continue; + if(!strcmp(ifa->ifa_name, a_ping_handle->device) && + IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 * )ifa->ifa_addr)->sin6_addr, + &source6.sin6_addr)) + break; + } + if(!ifa) + error(0, 0, "Warning: source address might be selected on device other than: %s", a_ping_handle->device); + + freeifaddrs(ifa0); + } + } + else if(a_ping_handle->device && (IN6_IS_ADDR_LINKLOCAL(&source6.sin6_addr) || + IN6_IS_ADDR_MC_LINKLOCAL(&source6.sin6_addr))) + source6.sin6_scope_id = if_name2index(a_ping_handle->device); + + if(a_ping_handle->device) { + struct cmsghdr *cmsg; + struct in6_pktinfo *ipi; + + cmsg = (struct cmsghdr*) (cmsgbuf + cmsglen); + cmsglen += CMSG_SPACE(sizeof(*ipi)); + cmsg->cmsg_len = CMSG_LEN(sizeof(*ipi)); + cmsg->cmsg_level = IPPROTO_IPV6; + cmsg->cmsg_type = IPV6_PKTINFO; + + ipi = (struct in6_pktinfo*) CMSG_DATA(cmsg); + memset(ipi, 0, sizeof(*ipi)); + ipi->ipi6_ifindex = if_name2index(a_ping_handle->device); + } + + if((whereto.sin6_addr.s6_addr16[0] & htons(0xff00)) == htons(0xff00)) { + if(a_ping_handle->ping_common.uid) { + if(a_ping_handle->ping_common.interval < 1000) + error(2, 0, "multicast ping with too short interval: %d", a_ping_handle->ping_common.interval); + if(a_ping_handle->pmtudisc >= 0 && a_ping_handle->pmtudisc != IPV6_PMTUDISC_DO) + error(2, 0, "multicast ping does not fragment"); + } + if(a_ping_handle->pmtudisc < 0) + a_ping_handle->pmtudisc = IPV6_PMTUDISC_DO; + } + + if(a_ping_handle->pmtudisc >= 0) { + if(setsockopt(sock->fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &a_ping_handle->pmtudisc, sizeof (a_ping_handle->pmtudisc)) == -1) + error(2, errno, "IPV6_MTU_DISCOVER"); + } + + if((a_ping_handle->ping_common.options & F_STRICTSOURCE) && + bind(sock->fd, (struct sockaddr *) &source6, sizeof source6) == -1) + error(2, errno, "bind icmp socket"); + + if((ssize_t) a_ping_handle->ping_common.datalen >= (ssize_t) sizeof(struct timeval) && (ni_query < 0)) { + /* can we time transfer */ + a_ping_handle->ping_common.timing = 1; + } + packlen = a_ping_handle->ping_common.datalen + 8 + 4096 + 40 + 8; /* 4096 for rthdr */ + if(!(packet = (unsigned char *) malloc((unsigned int) packlen))) + error(2, errno, "memory allocation failed"); + + hold = 1; + + /* Estimate memory eaten by single packet. It is rough estimate. + * Actually, for small datalen's it depends on kernel side a lot. */ + hold = a_ping_handle->ping_common.datalen + 8; + hold += ((hold + 511) / 512) * (40 + 16 + 64 + 160); + sock_setbufs(a_ping_handle,sock, hold); + +#ifdef __linux__ + if(sock->socktype == SOCK_RAW) { + int csum_offset = 2; + int sz_opt = sizeof(int); + + err = setsockopt(sock->fd, SOL_RAW, IPV6_CHECKSUM, &csum_offset, sz_opt); + if(err < 0) { + /* checksum should be enabled by default and setting this + * option might fail anyway. + */ + error(0, errno, "setsockopt(RAW_CHECKSUM) failed - try to continue"); + } +#else + { +#endif + + /* + * select icmp echo reply as icmp type to receive + */ + + ICMP6_FILTER_SETBLOCKALL(&filter); + + ICMP6_FILTER_SETPASS(ICMP6_DST_UNREACH, &filter); + ICMP6_FILTER_SETPASS(ICMP6_PACKET_TOO_BIG, &filter); + ICMP6_FILTER_SETPASS(ICMP6_TIME_EXCEEDED, &filter); + ICMP6_FILTER_SETPASS(ICMP6_PARAM_PROB, &filter); + + if(niquery_is_enabled()) + ICMP6_FILTER_SETPASS(ICMPV6_NI_REPLY, &filter); + else + ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter); + + err = setsockopt(sock->fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof filter); + + if(err < 0) + error(2, errno, "setsockopt(ICMP6_FILTER)"); + } + + if(a_ping_handle->ping_common.options & F_NOLOOP) { + int loop = 0; + if(setsockopt(sock->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop, sizeof loop) == -1) + error(2, errno, "can't disable multicast loopback"); + } + if(a_ping_handle->ping_common.options & F_TTL) { + if(setsockopt(sock->fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &a_ping_handle->ping_common.ttl, sizeof (a_ping_handle->ping_common.ttl)) == -1) + error(2, errno, "can't set multicast hop limit"); + if(setsockopt(sock->fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &a_ping_handle->ping_common.ttl, sizeof (a_ping_handle->ping_common.ttl)) == -1) + error(2, errno, "can't set unicast hop limit"); + } + + const int on = 1; + if( + #ifdef IPV6_RECVHOPLIMIT + setsockopt(sock->fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof on) == -1 && + setsockopt(sock->fd, IPPROTO_IPV6, IPV6_2292HOPLIMIT, &on, sizeof on) == -1 + #else + setsockopt(sock->fd, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof on) == -1 +#endif + ) + error(2, errno, "can't receive hop limit"); + + if(a_ping_handle->ping_common.options & F_TCLASS) { +#ifdef IPV6_TCLASS + if(setsockopt(sock->fd, IPPROTO_IPV6, IPV6_TCLASS, &tclass, sizeof tclass) == -1) + error(2, errno, "setsockopt(IPV6_TCLASS)"); +#else + error(0, 0, "traffic class is not supported"); +#endif + } + + if(a_ping_handle->ping_common.options & F_FLOWINFO) { +#ifdef IPV6_FLOWLABEL_MGR + char freq_buf[CMSG_ALIGN(sizeof(struct in6_flowlabel_req)) + cmsglen]; + struct in6_flowlabel_req *freq = (struct in6_flowlabel_req *)freq_buf; + int freq_len = sizeof(*freq); + memset(freq, 0, sizeof(*freq)); + freq->flr_label = htonl(flowlabel & IPV6_FLOWINFO_FLOWLABEL); + freq->flr_action = IPV6_FL_A_GET; + freq->flr_flags = IPV6_FL_F_CREATE; + freq->flr_share = IPV6_FL_S_EXCL; + memcpy(&freq->flr_dst, &whereto.sin6_addr, 16); + if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_FLOWLABEL_MGR, freq, freq_len) == -1) + error(2, errno, "can't set flowlabel"); + flowlabel = freq->flr_label; +#else + error(2, 0, "flow labels are not supported"); +#endif + +#ifdef IPV6_FLOWINFO_SEND + whereto.sin6_flowinfo = flowlabel; + if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_FLOWINFO_SEND, &on, sizeof on) == -1) + error(2, errno, "can't send flowinfo"); +#else + error(2, 0, "flowinfo is not supported"); +#endif + } + + printf("PING %s(%s) ", a_ping_handle->ping_common.hostname, pr_addr(a_ping_handle, &whereto, sizeof whereto)); + if(flowlabel) + printf(", flow 0x%05x, ", (unsigned) ntohl(flowlabel)); + if(a_ping_handle->device || (a_ping_handle->ping_common.options & F_STRICTSOURCE)) { + int saved_options = a_ping_handle->ping_common.options; + + a_ping_handle->ping_common.options |= F_NUMERIC; + printf("from %s %s: ", pr_addr(a_ping_handle, &source6, sizeof source6), a_ping_handle->device ? a_ping_handle->device : ""); + a_ping_handle->ping_common.options = saved_options; + } + printf("%d data bytes\n", a_ping_handle->ping_common.datalen); + + setup(a_ping_handle, sock); + + drop_capabilities(); + + main_loop(a_ping_handle, &ping6_func_set, sock, packet, packlen); + return 0; +} + +int ping6_receive_error_msg(ping_handle_t *a_ping_handle, socket_st *sock) +{ + ssize_t res; + char cbuf[512]; + struct iovec iov; + struct msghdr msg; + struct cmsghdr *cmsg; + struct sock_extended_err *e; + struct icmp6_hdr icmph; + struct sockaddr_in6 target; + int net_errors = 0; + int local_errors = 0; + int saved_errno = errno; + + iov.iov_base = &icmph; + iov.iov_len = sizeof(icmph); + msg.msg_name = (void*) ⌖ + msg.msg_namelen = sizeof(target); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_flags = 0; + msg.msg_control = cbuf; + msg.msg_controllen = sizeof(cbuf); + + res = recvmsg(sock->fd, &msg, MSG_ERRQUEUE | MSG_DONTWAIT); + if(res < 0) + goto out; + + e = NULL; + for(cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if(cmsg->cmsg_level == IPPROTO_IPV6) { + if(cmsg->cmsg_type == IPV6_RECVERR) + e = (struct sock_extended_err *) CMSG_DATA(cmsg); + } + } + if(e == NULL) + abort(); + + if(e->ee_origin == SO_EE_ORIGIN_LOCAL) { + local_errors++; + if(a_ping_handle->ping_common.options & F_QUIET) + goto out; + if(a_ping_handle->ping_common.options & F_FLOOD) + write_stdout("E", 1); + else if(e->ee_errno != EMSGSIZE) + error(0, e->ee_errno, "local error"); + else + error(0, 0, "local error: message too long, mtu: %u", e->ee_info); + a_ping_handle->ping_common.nerrors++; + } else if(e->ee_origin == SO_EE_ORIGIN_ICMP6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6*) (e + 1); + + if((size_t) res < sizeof(icmph) || + memcmp(&target.sin6_addr, &whereto.sin6_addr, 16) || + icmph.icmp6_type != ICMP6_ECHO_REQUEST || + !is_ours(a_ping_handle, sock, icmph.icmp6_id)) { + /* Not our error, not an error at all. Clear. */ + saved_errno = 0; + goto out; + } + + net_errors++; + a_ping_handle->ping_common.nerrors++; + if(a_ping_handle->ping_common.options & F_QUIET) + goto out; + if(a_ping_handle->ping_common.options & F_FLOOD) { + write_stdout("\bE", 2); + } else { + print_timestamp(a_ping_handle); + printf("From %s icmp_seq=%u ", pr_addr(a_ping_handle, sin6, sizeof *sin6), ntohs(icmph.icmp6_seq)); + pr_icmph(e->ee_type, e->ee_code, e->ee_info); + putchar('\n'); + fflush(stdout); + } + } + + out: + errno = saved_errno; + return net_errors ? net_errors : -local_errors; +} + +/* + * pinger -- + * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet + * will be added on by the kernel. The ID field is our UNIX process ID, + * and the sequence number is an ascending integer. The first several bytes + * of the data portion are used to hold a UNIX "timeval" struct in VAX + * byte-order, to compute the round-trip time. + */ +static int build_echo(ping_handle_t *a_ping_handle, uint8_t *_icmph, unsigned packet_size __attribute__((__unused__))) +{ + struct icmp6_hdr *icmph; + int cc; + + icmph = (struct icmp6_hdr *) _icmph; + icmph->icmp6_type = ICMP6_ECHO_REQUEST; + icmph->icmp6_code = 0; + icmph->icmp6_cksum = 0; + icmph->icmp6_seq= htons(a_ping_handle->ping_common.ntransmitted+1); + icmph->icmp6_id= a_ping_handle->ping_common.ident; + + if(a_ping_handle->ping_common.timing) + gettimeofday((struct timeval *) &_icmph[8], + (struct timezone *) NULL); + + cc = a_ping_handle->ping_common.datalen + 8; /* skips ICMP portion */ + + return cc; +} + +static int build_niquery(ping_handle_t *a_ping_handle, uint8_t *_nih, unsigned packet_size __attribute__((__unused__))) +{ + struct ni_hdr *nih; + int cc; + + nih = (struct ni_hdr *) _nih; + nih->ni_cksum = 0; + + nih->ni_type = ICMPV6_NI_QUERY; + cc = sizeof(*nih); + a_ping_handle->ping_common.datalen = 0; + + niquery_fill_nonce(a_ping_handle->ping_common.ntransmitted + 1, nih->ni_nonce); + nih->ni_code = ni_subject_type; + nih->ni_qtype= htons(ni_query); + nih->ni_flags= ni_flag; + memcpy(nih + 1, ni_subject, ni_subject_len); + cc += ni_subject_len; + + return cc; +} + +int ping6_send_probe(ping_handle_t *a_ping_handle, socket_st *sock, void *packet, unsigned packet_size) +{ + int len, cc; + + rcvd_clear(a_ping_handle, a_ping_handle->ping_common.ntransmitted + 1); + + if(niquery_is_enabled()) + len = build_niquery(a_ping_handle, packet, packet_size); + else + len = build_echo(a_ping_handle, packet, packet_size); + + if(cmsglen == 0) { + cc = sendto(sock->fd, (char *) packet, len, a_ping_handle->ping_common.confirm, + (struct sockaddr *) &whereto, + sizeof(struct sockaddr_in6)); + } else { + struct msghdr mhdr; + struct iovec iov; + + iov.iov_len = len; + iov.iov_base = packet; + + memset(&mhdr, 0, sizeof(mhdr)); + mhdr.msg_name = &whereto; + mhdr.msg_namelen = sizeof(struct sockaddr_in6); + mhdr.msg_iov = &iov; + mhdr.msg_iovlen = 1; + mhdr.msg_control = cmsgbuf; + mhdr.msg_controllen = cmsglen; + + cc = sendmsg(sock->fd, &mhdr, a_ping_handle->ping_common.confirm); + } + a_ping_handle->ping_common.confirm = 0; + + return (cc == len ? 0 : cc); +} + +void pr_echo_reply(uint8_t *_icmph, int cc __attribute__((__unused__))) +{ + struct icmp6_hdr *icmph = (struct icmp6_hdr *) _icmph; + log_printf(" icmp_seq=%u", ntohs(icmph->icmp6_seq)); +} + +static void putchar_safe(char c) +{ + if(isprint(c)) + putchar(c); + else + printf("\\%03o", c); +} + +static +void pr_niquery_reply_name(struct ni_hdr *nih, int len) +{ + uint8_t *h = (uint8_t *) (nih + 1); + uint8_t *p = h + 4; + uint8_t *end = (uint8_t *) nih + len; + int continued = 0; + char buf[1024]; + int ret; + + len -= sizeof(struct ni_hdr) + 4; + + if(len < 0) { + printf(" parse error (too short)"); + return; + } + while(p < end) { + int fqdn = 1; + size_t i; + + memset(buf, 0xff, sizeof(buf)); + + if(continued) + putchar(','); + + ret = dn_expand(h, end, p, buf, sizeof(buf)); + if(ret < 0) { + printf(" parse error (truncated)"); + break; + } + if(p + ret < end && *(p + ret) == '\0') + fqdn = 0; + + putchar(' '); + for(i = 0; i < strlen(buf); i++) + putchar_safe(buf[i]); + if(fqdn) + putchar('.'); + + p += ret + !fqdn; + + continued = 1; + } +} + +static +void pr_niquery_reply_addr(struct ni_hdr *nih, int len) +{ + uint8_t *h = (uint8_t *) (nih + 1); + uint8_t *p; + uint8_t *end = (uint8_t *) nih + len; + int af; + int aflen; + int continued = 0; + int truncated; + char buf[1024]; + + switch (ntohs(nih->ni_qtype)) { + case NI_QTYPE_IPV4ADDR: + af = AF_INET; + aflen = sizeof(struct in_addr); + truncated = nih->ni_flags & NI_IPV6ADDR_F_TRUNCATE; + break; + case NI_QTYPE_IPV6ADDR: + af = AF_INET6; + aflen = sizeof(struct in6_addr); + truncated = nih->ni_flags & NI_IPV4ADDR_F_TRUNCATE; + break; + default: + /* should not happen */ + af = aflen = truncated = 0; + } + p = h; + if(len < 0) { + printf(" parse error (too short)"); + return; + } + + while(p < end) { + if(continued) + putchar(','); + + if(p + sizeof(uint32_t) + aflen > end) { + printf(" parse error (truncated)"); + break; + } + if(!inet_ntop(af, p + sizeof(uint32_t), buf, sizeof(buf))) + printf(" unexpeced error in inet_ntop(%s)", + strerror(errno)); + else + printf(" %s", buf); + p += sizeof(uint32_t) + aflen; + + continued = 1; + } + if(truncated) + printf(" (truncated)"); +} + +static +void pr_niquery_reply(uint8_t *_nih, int len) +{ + struct ni_hdr *nih = (struct ni_hdr *) _nih; + + switch (nih->ni_code) { + case NI_SUCCESS: + switch (ntohs(nih->ni_qtype)) { + case NI_QTYPE_NAME: + pr_niquery_reply_name(nih, len); + break; + case NI_QTYPE_IPV4ADDR: + case NI_QTYPE_IPV6ADDR: + pr_niquery_reply_addr(nih, len); + break; + default: + printf(" unknown qtype(0x%02x)", ntohs(nih->ni_qtype)); + } + break; + case NI_REFUSED: + printf(" refused"); + break; + case NI_UNKNOWN: + printf(" unknown"); + break; + default: + printf(" unknown code(%02x)", ntohs(nih->ni_code)); + } + printf("; seq=%u;", ntohsp((uint16_t*) nih->ni_nonce)); +} + +/* + * parse_reply -- + * Print out the packet, if it came from us. This logic is necessary + * because ALL readers of the ICMP socket get a copy of ALL ICMP packets + * which arrive ('tis only fair). This permits multiple copies of this + * program to be run without having intermingled output (or statistics!). + */ +int +ping6_parse_reply(ping_handle_t *a_ping_handle, socket_st *sock, struct msghdr *msg, int cc, void *addr, struct timeval *tv) +{ + struct sockaddr_in6 *from = addr; + uint8_t *buf = msg->msg_iov->iov_base; + struct cmsghdr *c; + struct icmp6_hdr *icmph; + int hops = -1; + + for(c = CMSG_FIRSTHDR(msg); c; c = CMSG_NXTHDR(msg, c)) { + if(c->cmsg_level != IPPROTO_IPV6) + continue; + switch (c->cmsg_type) { + case IPV6_HOPLIMIT: + #ifdef IPV6_2292HOPLIMIT + case IPV6_2292HOPLIMIT: + #endif + if(c->cmsg_len < CMSG_LEN(sizeof(int))) + continue; + memcpy(&hops, CMSG_DATA(c), sizeof(hops)); + } + } + + /* Now the ICMP part */ + + icmph = (struct icmp6_hdr *) buf; + if(cc < 8) { + if(a_ping_handle->ping_common.options & F_VERBOSE) + error(0, 0, "packet too short: %d bytes", cc); + return 1; + } + + if(icmph->icmp6_type == ICMP6_ECHO_REPLY) { + if(!is_ours(a_ping_handle, sock, icmph->icmp6_id)) + return 1; + if (!contains_pattern_in_payload(a_ping_handle, (uint8_t*)(icmph+1))) + return 1; /* 'Twas really not our ECHO */ + if (gather_statistics(a_ping_handle, (uint8_t*)icmph, sizeof(*icmph), cc, + ntohs(icmph->icmp6_seq), + hops, 0, tv, pr_addr(a_ping_handle, from, sizeof *from), + pr_echo_reply)) { + fflush(stdout); + return 0; + } + } else if (icmph->icmp6_type == ICMPV6_NI_REPLY) { + struct ni_hdr *nih = (struct ni_hdr *)icmph; + int seq = niquery_check_nonce(nih->ni_nonce); + if (seq < 0) + return 1; + if (gather_statistics(a_ping_handle, (uint8_t*)icmph, sizeof(*icmph), cc, + seq, + hops, 0, tv, pr_addr(a_ping_handle, from, sizeof *from), + pr_niquery_reply)) + return 0; + } else { + int nexthdr; + struct ip6_hdr *iph1 = (struct ip6_hdr*)(icmph+1); + struct icmp6_hdr *icmph1 = (struct icmp6_hdr *)(iph1+1); + + /* We must not ever fall here. All the messages but + * echo reply are blocked by filter and error are + * received with IPV6_RECVERR. Ugly code is preserved + * however, just to remember what crap we avoided + * using RECVRERR. :-) + */ + + if (cc < (int) (8 + sizeof(struct ip6_hdr) + 8)) + return 1; + + if (memcmp(&iph1->ip6_dst, &whereto.sin6_addr, 16)) + return 1; + + nexthdr = iph1->ip6_nxt; + + if (nexthdr == 44) { + nexthdr = *(uint8_t*)icmph1; + icmph1++; + } + if (nexthdr == IPPROTO_ICMPV6) { + if (icmph1->icmp6_type != ICMP6_ECHO_REQUEST || + !is_ours(a_ping_handle, sock, icmph1->icmp6_id)) + return 1; + acknowledge(a_ping_handle, ntohs(icmph1->icmp6_seq)); + a_ping_handle->ping_common.nerrors++; + if (a_ping_handle->ping_common.options & F_FLOOD) { + write_stdout("\bE", 2); + return 0; + } + print_timestamp(a_ping_handle); + printf("From %s: icmp_seq=%u ", pr_addr(a_ping_handle, from, sizeof *from), ntohs(icmph1->icmp6_seq)); + } else { + /* We've got something other than an ECHOREPLY */ + if (!(a_ping_handle->ping_common.options & F_VERBOSE) || a_ping_handle->ping_common.uid) + return 1; + print_timestamp(a_ping_handle); + printf("From %s: ", pr_addr(a_ping_handle, from, sizeof *from)); + } + pr_icmph(icmph->icmp6_type, icmph->icmp6_code, ntohl(icmph->icmp6_mtu)); + } + + if(a_ping_handle->ping_common.options & F_AUDIBLE) { + putchar('\a'); + if(a_ping_handle->ping_common.options & F_FLOOD) + fflush(stdout); + } + if(!(a_ping_handle->ping_common.options & F_FLOOD)) { + putchar('\n'); + fflush(stdout); + } + return 0; +} + +int pr_icmph(uint8_t type, uint8_t code, uint32_t info) +{ + switch (type) { + case ICMP6_DST_UNREACH: + printf("Destination unreachable: "); + switch (code) { + case ICMP6_DST_UNREACH_NOROUTE: + printf("No route"); + break; + case ICMP6_DST_UNREACH_ADMIN: + printf("Administratively prohibited"); + break; + case ICMP6_DST_UNREACH_BEYONDSCOPE: + printf("Beyond scope of source address"); + break; + case ICMP6_DST_UNREACH_ADDR: + printf("Address unreachable"); + break; + case ICMP6_DST_UNREACH_NOPORT: + printf("Port unreachable"); + break; + default: + printf("Unknown code %d", code); + break; + } + break; + case ICMP6_PACKET_TOO_BIG: + printf("Packet too big: mtu=%u", info); + if(code) + printf(", code=%d", code); + break; + case ICMP6_TIME_EXCEEDED: + printf("Time exceeded: "); + if(code == ICMP6_TIME_EXCEED_TRANSIT) + printf("Hop limit"); + else if(code == ICMP6_TIME_EXCEED_REASSEMBLY) + printf("Defragmentation failure"); + else + printf("code %d", code); + break; + case ICMP6_PARAM_PROB: + printf("Parameter problem: "); + if(code == ICMP6_PARAMPROB_HEADER) + printf("Wrong header field "); + else if(code == ICMP6_PARAMPROB_NEXTHEADER) + printf("Unknown header "); + else if(code == ICMP6_PARAMPROB_OPTION) + printf("Unknown option "); + else + printf("code %d ", code); + printf("at %u", info); + break; + case ICMP6_ECHO_REQUEST: + printf("Echo request"); + break; + case ICMP6_ECHO_REPLY: + printf("Echo reply"); + break; + case MLD_LISTENER_QUERY: + printf("MLD Query"); + break; + case MLD_LISTENER_REPORT: + printf("MLD Report"); + break; + case MLD_LISTENER_REDUCTION: + printf("MLD Reduction"); + break; + default: + printf("unknown icmp type: %u", type); + + } + return 0; +} + +void ping6_install_filter(ping_handle_t *a_ping_handle, socket_st *sock) +{ + static int once; + static struct sock_filter insns[] = { + BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 4), /* Load icmp echo ident */ + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0xAAAA, 0, 1), /* Ours? */ + BPF_STMT(BPF_RET|BPF_K, ~0U), /* Yes, it passes. */ + BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 0), /* Load icmp type */ + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, ICMP6_ECHO_REPLY, 1, 0), /* Echo? */ + BPF_STMT(BPF_RET|BPF_K, ~0U), /* No. It passes. This must not happen. */ + BPF_STMT(BPF_RET|BPF_K, 0), /* Echo with wrong ident. Reject. */ + }; + static struct sock_fprog filter = { + sizeof insns / sizeof(insns[0]), + insns + }; + + if(once) + return; + once = 1; + + /* Patch bpflet for current identifier. */ + insns[1] = (struct sock_filter )BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(a_ping_handle->ping_common.ident), 0, 1); + + if(setsockopt(sock->fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) + error(0, errno, "WARNING: failed to install socket filter"); +} diff --git a/modules/net/iputils/ping_common.c b/modules/net/iputils/ping_common.c new file mode 100644 index 0000000000000000000000000000000000000000..566fdc755ee685ccff49f24f34d3450fb8590779 --- /dev/null +++ b/modules/net/iputils/ping_common.c @@ -0,0 +1,1030 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Mike Muuss. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ping.h" + +#ifndef HZ +#define HZ sysconf(_SC_CLK_TCK) +#endif + +/* +int options; + +int mark; +int sndbuf; +int ttl; +int rtt; +int rtt_addend; +uint16_t acked; + +unsigned char outpack[MAXPACKET]; +struct rcvd_table rcvd_tbl; + +// counters +long npackets; // max packets to transmit +long nreceived; // # of packets we got back +long nrepeats; // number of duplicates +long ntransmitted; // sequence # for outbound packets = #sent +long nchecksum; // replies with bad checksum +long nerrors; // icmp errors +int interval = 1000; // interval between packets (msec) +int preload = 1; +int deadline = 0; // time to die +int lingertime = MAXWAIT * 1000; +struct timeval start_time, cur_time; +int confirm = 0; +volatile int in_pr_addr = 0; // pr_addr() is executing +jmp_buf pr_addr_jmp; +*/ + +volatile int exiting; +volatile int status_snapshot; + +/* Stupid workarounds for bugs/missing functionality in older linuces. + * confirm_flag fixes refusing service of kernels without MSG_CONFIRM. + * i.e. for linux-2.2 */ +/* + +int confirm_flag = MSG_CONFIRM; + +// timing +int timing; // flag to do timing +long tmin = LONG_MAX; // minimum round trip time +long tmax; // maximum round trip time +*/ +/* Message for rpm maintainers: have _shame_. If you want + * to fix something send the patch to me for sanity checking. + * "sparcfix" patch is a complete non-sense, apparenly the person + * prepared it was stoned. + */ +/* +long long tsum; // sum of all times, for doing average +long long tsum2; +int pipesize = -1; + +int datalen = DEFDATALEN; + +char *hostname; +int uid; +uid_t euid; +int ident; // process id to identify our packets + +static int screen_width = INT_MAX; + +#ifdef HAVE_LIBCAP +static cap_value_t cap_raw = CAP_NET_RAW; +static cap_value_t cap_admin = CAP_NET_ADMIN; +#endif +*/ + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + + +void usage(void) +{ + fprintf(stderr, + "\nUsage\n" + " ping [options] <destination>\n" + "\nOptions:\n" + " <destination> dns name or ip address\n" + " -a use audible ping\n" + " -A use adaptive ping\n" + " -B sticky source address\n" + " -c <count> stop after <count> replies\n" + " -D print timestamps\n" + " -d use SO_DEBUG socket option\n" + " -f flood ping\n" + " -h print help and exit\n" + " -I <interface> either interface name or address\n" + " -i <interval> seconds between sending each packet\n" + " -L suppress loopback of multicast packets\n" + " -l <preload> send <preload> number of packages while waiting replies\n" + " -m <mark> tag the packets going out\n" + " -M <pmtud opt> define mtu discovery, can be one of <do|dont|want>\n" + " -n no dns name resolution\n" + " -O report outstanding replies\n" + " -p <pattern> contents of padding byte\n" + " -q quiet output\n" + " -Q <tclass> use quality of service <tclass> bits\n" + " -s <size> use <size> as number of data bytes to be sent\n" + " -S <size> use <size> as SO_SNDBUF socket option value\n" + " -t <ttl> define time to live\n" + " -U print user-to-user latency\n" + " -v verbose output\n" + " -V print version and exit\n" + " -w <deadline> reply wait <deadline> in seconds\n" + " -W <timeout> time to wait for response\n" + "\nIPv4 options:\n" + " -4 use IPv4\n" + " -b allow pinging broadcast\n" + " -R record route\n" + " -T <timestamp> define timestamp, can be one of <tsonly|tsandaddr|tsprespec>\n" + "\nIPv6 options:\n" + " -6 use IPv6\n" + " -F <flowlabel> define flow label, default is random\n" + " -N <nodeinfo opt> use icmp6 node info query, try <help> as argument\n" + "\nFor more details see ping(8).\n" + ); + //exit(2); + exit(2); +} + +void limit_capabilities(ping_handle_t *a_ping_handle) +{ +#ifdef HAVE_LIBCAP + cap_t cap_cur_p; + cap_t cap_p; + cap_flag_value_t cap_ok; + + cap_cur_p = cap_get_proc(); + if (!cap_cur_p) + error(-1, errno, "cap_get_proc"); + cap_p = cap_init(); + if (!cap_p) + error(-1, errno, "cap_init"); + cap_ok = CAP_CLEAR; + cap_get_flag(cap_cur_p, CAP_NET_ADMIN, CAP_PERMITTED, &cap_ok); + if (cap_ok != CAP_CLEAR) + cap_set_flag(cap_p, CAP_PERMITTED, 1, &cap_admin, CAP_SET); + cap_ok = CAP_CLEAR; + cap_get_flag(cap_cur_p, CAP_NET_RAW, CAP_PERMITTED, &cap_ok); + if (cap_ok != CAP_CLEAR) + cap_set_flag(cap_p, CAP_PERMITTED, 1, &cap_raw, CAP_SET); + if (cap_set_proc(cap_p) < 0) + error(-1, errno, "cap_set_proc"); + if (prctl(PR_SET_KEEPCAPS, 1) < 0) + error(-1, errno, "prctl"); + if (setuid(getuid()) < 0) + error(-1, errno, "setuid"); + if (prctl(PR_SET_KEEPCAPS, 0) < 0) + error(-1, errno, "prctl"); + cap_free(cap_p); + cap_free(cap_cur_p); +#endif + a_ping_handle->ping_common.uid = getuid(); + a_ping_handle->ping_common.euid = geteuid(); +#ifndef HAVE_LIBCAP + if(seteuid(a_ping_handle->ping_common.uid)) + error(-1, errno, "setuid"); +#endif +} + +#ifdef HAVE_LIBCAP +int modify_capability(cap_value_t cap, cap_flag_value_t on) +{ + cap_t cap_p = cap_get_proc(); + cap_flag_value_t cap_ok; + int rc = -1; + + if (!cap_p) { + error(0, errno, "cap_get_proc"); + goto out; + } + + cap_ok = CAP_CLEAR; + cap_get_flag(cap_p, cap, CAP_PERMITTED, &cap_ok); + if (cap_ok == CAP_CLEAR) { + rc = on ? -1 : 0; + goto out; + } + + cap_set_flag(cap_p, CAP_EFFECTIVE, 1, &cap, on); + + if (cap_set_proc(cap_p) < 0) { + error(0, errno, "cap_set_proc"); + goto out; + } + + cap_free(cap_p); + cap_p = NULL; + + rc = 0; + out: + if (cap_p) + cap_free(cap_p); + return rc; +} +#else +int modify_capability(ping_handle_t *a_ping_handle, int on) +{ + if(seteuid(on ? a_ping_handle->ping_common.euid : getuid())) { + error(0, errno, "seteuid"); + return -1; + } + + return 0; +} +#endif + +void drop_capabilities(void) +{ +#ifdef HAVE_LIBCAP + cap_t cap = cap_init(); + if (cap_set_proc(cap) < 0) + error(-1, errno, "cap_set_proc"); + cap_free(cap); +#else + if(setuid(getuid())) + error(-1, errno, "setuid"); +#endif +} + +/* Fills all the outpack, excluding ICMP header, but _including_ + * timestamp area with supplied pattern. + */ +void fill(ping_handle_t *a_ping_handle, char *patp, unsigned char *packet, unsigned packet_size) +{ + int ii, jj; + unsigned int pat[16]; + char *cp; + unsigned char *bp = packet + 8; + +#ifdef USE_IDN + setlocale(LC_ALL, "C"); +#endif + + for(cp = patp; *cp; cp++) { + if(!isxdigit(*cp)) + error(2, 0, "patterns must be specified as hex digits: %s", cp); + } + ii = sscanf(patp, + "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", + &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6], + &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12], + &pat[13], &pat[14], &pat[15]); + + if(ii > 0) { + unsigned kk; + for(kk = 0; kk <= packet_size - (8 + ii); kk += ii) + for(jj = 0; jj < ii; ++jj) + bp[jj + kk] = pat[jj]; + } + if(!(a_ping_handle->ping_common.options & F_QUIET)) { + printf("PATTERN: 0x"); + for(jj = 0; jj < ii; ++jj) + printf("%02x", bp[jj] & 0xFF); + printf("\n"); + } + +#ifdef USE_IDN + setlocale(LC_ALL, ""); +#endif +} + +static void sigexit(int signo __attribute__((__unused__))) +{ + //exiting = 1; + //if(in_pr_addr) + // longjmp(pr_addr_jmp, 0); +} + +static void sigstatus(int signo __attribute__((__unused__))) +{ + //status_snapshot = 1; +} + +int __schedule_exit(ping_handle_t *a_ping_handle, int next) +{ + static unsigned long waittime; + struct itimerval it; + + if(waittime) + return next; + + if(a_ping_handle->ping_common.nreceived) { + waittime = 2 * a_ping_handle->ping_common.tmax; + if(waittime < (unsigned long) (1000 * a_ping_handle->ping_common.interval)) + waittime = 1000 * a_ping_handle->ping_common.interval; + } else + waittime = a_ping_handle->ping_common.lingertime * 1000; + + if(next < 0 || (unsigned long) next < waittime / 1000) + next = waittime / 1000; + + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = 0; + it.it_value.tv_sec = waittime / 1000000; + it.it_value.tv_usec = waittime % 1000000; + setitimer(ITIMER_REAL, &it, NULL); + return next; +} + +static inline void update_interval(ping_handle_t *a_ping_handle) +{ + int est = a_ping_handle->ping_common.rtt ? a_ping_handle->ping_common.rtt / 8 : a_ping_handle->ping_common.interval * 1000; + + a_ping_handle->ping_common.interval = (est + a_ping_handle->ping_common.rtt_addend + 500) / 1000; + if(a_ping_handle->ping_common.uid && a_ping_handle->ping_common.interval < MINUSERINTERVAL) + a_ping_handle->ping_common.interval = MINUSERINTERVAL; +} + +/* + * Print timestamp + */ +void print_timestamp(ping_handle_t *a_ping_handle) +{ + if(a_ping_handle->ping_common.options & F_PTIMEOFDAY) { + struct timeval tv; + gettimeofday(&tv, NULL); + printf("[%lu.%06lu] ", + (unsigned long) tv.tv_sec, (unsigned long) tv.tv_usec); + } +} + +/* + * pinger -- + * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet + * will be added on by the kernel. The ID field is our UNIX process ID, + * and the sequence number is an ascending integer. The first several bytes + * of the data portion are used to hold a UNIX "timeval" struct in VAX + * byte-order, to compute the round-trip time. + */ +int pinger(ping_handle_t *a_ping_handle, ping_func_set_st *fset, socket_st *sock) +{ + static int oom_count; + static int tokens; + int i; + + /* Have we already sent enough? If we have, return an arbitrary positive value. */ + if(exiting || (a_ping_handle->ping_common.npackets && a_ping_handle->ping_common.ntransmitted >= a_ping_handle->ping_common.npackets && !a_ping_handle->ping_common.deadline)) + return 1000; + + /* Check that packets < rate*time + preload */ + if(a_ping_handle->ping_common.cur_time.tv_sec == 0) { + gettimeofday(&a_ping_handle->ping_common.cur_time, NULL); + tokens = a_ping_handle->ping_common.interval * (a_ping_handle->ping_common.preload - 1); + } else { + long ntokens; + struct timeval tv; + + gettimeofday(&tv, NULL); + ntokens = (tv.tv_sec - a_ping_handle->ping_common.cur_time.tv_sec) * 1000 + + (tv.tv_usec - a_ping_handle->ping_common.cur_time.tv_usec) / 1000; + if(!a_ping_handle->ping_common.interval) { + /* Case of unlimited flood is special; + * if we see no reply, they are limited to 100pps */ + if(ntokens < MININTERVAL && in_flight(a_ping_handle) >= a_ping_handle->ping_common.preload) + return MININTERVAL - ntokens; + } + ntokens += tokens; + if(ntokens > a_ping_handle->ping_common.interval * a_ping_handle->ping_common.preload) + ntokens = a_ping_handle->ping_common.interval * a_ping_handle->ping_common.preload; + if(ntokens < a_ping_handle->ping_common.interval) + return a_ping_handle->ping_common.interval - ntokens; + + a_ping_handle->ping_common.cur_time = tv; + tokens = ntokens - a_ping_handle->ping_common.interval; + } + + if(a_ping_handle->ping_common.options & F_OUTSTANDING) { + if(a_ping_handle->ping_common.ntransmitted > 0 && !rcvd_test(a_ping_handle, a_ping_handle->ping_common.ntransmitted)) { + print_timestamp(a_ping_handle); + printf("no answer yet for icmp_seq=%lu\n", (a_ping_handle->ping_common.ntransmitted % MAX_DUP_CHK)); + fflush(stdout); + } + } + + resend: + i = fset->send_probe(a_ping_handle, sock, a_ping_handle->ping_common.outpack, sizeof(a_ping_handle->ping_common.outpack)); + + if(i == 0) { + oom_count = 0; + advance_ntransmitted(a_ping_handle); + if(!(a_ping_handle->ping_common.options & F_QUIET) && (a_ping_handle->ping_common.options & F_FLOOD)) { + /* Very silly, but without this output with + * high preload or pipe size is very confusing. */ + if((a_ping_handle->ping_common.preload < a_ping_handle->ping_common.screen_width && a_ping_handle->ping_common.pipesize < a_ping_handle->ping_common.screen_width) || + in_flight(a_ping_handle) < a_ping_handle->ping_common.screen_width) + write_stdout(".", 1); + } + return a_ping_handle->ping_common.interval - tokens; + } + + /* And handle various errors... */ + if(i > 0) { + /* Apparently, it is some fatal bug. */ + abort(); + } else if(errno == ENOBUFS || errno == ENOMEM) { + int nores_interval; + + /* Device queue overflow or OOM. Packet is not sent. */ + tokens = 0; + /* Slowdown. This works only in adaptive mode (option -A) */ + a_ping_handle->ping_common.rtt_addend += (a_ping_handle->ping_common.rtt < 8 * 50000 ? a_ping_handle->ping_common.rtt / 8 : 50000); + if(a_ping_handle->ping_common.options & F_ADAPTIVE) + update_interval(a_ping_handle); + nores_interval = SCHINT(a_ping_handle->ping_common.interval / 2); + if(nores_interval > 500) + nores_interval = 500; + oom_count++; + if(oom_count * nores_interval < a_ping_handle->ping_common.lingertime) + return nores_interval; + i = 0; + /* Fall to hard error. It is to avoid complete deadlock + * on stuck output device even when dealine was not requested. + * Expected timings are screwed up in any case, but we will + * exit some day. :-) */ + } else if(errno == EAGAIN) { + /* Socket buffer is full. */ + tokens += a_ping_handle->ping_common.interval; + return MININTERVAL; + } else { + if((i = fset->receive_error_msg(a_ping_handle, sock)) > 0) { + /* An ICMP error arrived. In this case, we've received + * an error from sendto(), but we've also received an + * ICMP message, which means the packet did in fact + * send in some capacity. So, in this odd case, report + * the more specific errno as the error, and treat this + * as a hard local error. */ + i = 0; + goto hard_local_error; + } + /* Compatibility with old linuces. */ + if(i == 0 && a_ping_handle->ping_common.confirm_flag && errno == EINVAL) { + a_ping_handle->ping_common.confirm_flag = 0; + errno = 0; + } + if(!errno) + goto resend; + } + + hard_local_error: + /* Hard local error. Pretend we sent packet. */ + advance_ntransmitted(a_ping_handle); + + if(i == 0 && !(a_ping_handle->ping_common.options & F_QUIET)) { + if(a_ping_handle->ping_common.options & F_FLOOD) + write_stdout("E", 1); + else + perror("ping: sendmsg"); + } + tokens = 0; + return SCHINT(a_ping_handle->ping_common.interval); +} + +/* Set socket buffers, "alloc" is an estimate of memory taken by single packet. */ + +void sock_setbufs(ping_handle_t *a_ping_handle, socket_st *sock, int alloc) +{ + int rcvbuf, hold; + socklen_t tmplen = sizeof(hold); + + if(!a_ping_handle->ping_common.sndbuf) + a_ping_handle->ping_common.sndbuf = alloc; + setsockopt(sock->fd, SOL_SOCKET, SO_SNDBUF, (char *) &a_ping_handle->ping_common.sndbuf, sizeof(a_ping_handle->ping_common.sndbuf)); + + rcvbuf = hold = alloc * a_ping_handle->ping_common.preload; + if(hold < 65536) + hold = 65536; + setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF, (char *) &hold, sizeof(hold)); + if(getsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF, (char *) &hold, &tmplen) == 0) { + if(hold < rcvbuf) + error(0, 0, "WARNING: probably, rcvbuf is not enough to hold preload"); + } +} + +/* Protocol independent setup and parameter checks. */ + +void setup(ping_handle_t *a_ping_handle, socket_st *sock) +{ + int hold; + struct timeval tv; + sigset_t sset; + + if((a_ping_handle->ping_common.options & F_FLOOD) && !(a_ping_handle->ping_common.options & F_INTERVAL)) + a_ping_handle->ping_common.interval = 0; + + if(a_ping_handle->ping_common.uid && a_ping_handle->ping_common.interval < MINUSERINTERVAL) + error(2, 0, "cannot flood; minimal interval allowed for user is %dms", MINUSERINTERVAL); + + if(a_ping_handle->ping_common.interval >= INT_MAX / a_ping_handle->ping_common.preload) + error(2, 0, "illegal preload and/or interval: %d", a_ping_handle->ping_common.interval); + + hold = 1; + if(a_ping_handle->ping_common.options & F_SO_DEBUG) + setsockopt(sock->fd, SOL_SOCKET, SO_DEBUG, (char *) &hold, sizeof(hold)); + if(a_ping_handle->ping_common.options & F_SO_DONTROUTE) + setsockopt(sock->fd, SOL_SOCKET, SO_DONTROUTE, (char *) &hold, sizeof(hold)); + +#ifdef SO_TIMESTAMP + if(!(a_ping_handle->ping_common.options & F_LATENCY)) { + int on = 1; + if(setsockopt(sock->fd, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on))) + error(0, 0, "Warning: no SO_TIMESTAMP support, falling back to SIOCGSTAMP"); + } +#endif +#ifdef SO_MARK + if(a_ping_handle->ping_common.options & F_MARK) { + int ret; + int errno_save; + + enable_capability_admin(a_ping_handle); + ret = setsockopt(sock->fd, SOL_SOCKET, SO_MARK, &a_ping_handle->ping_common.mark, sizeof(a_ping_handle->ping_common.mark)); + errno_save = errno; + disable_capability_admin(a_ping_handle); + + if(ret == -1) { + /* we probably dont wanna exit since old kernels + * dont support mark .. + */ + error(0, errno_save, "Warning: Failed to set mark: %d", a_ping_handle->ping_common.mark); + } + } +#endif + + /* Set some SNDTIMEO to prevent blocking forever + * on sends, when device is too slow or stalls. Just put limit + * of one second, or "interval", if it is less. + */ + tv.tv_sec = 1; + tv.tv_usec = 0; + if(a_ping_handle->ping_common.interval < 1000) { + tv.tv_sec = 0; + tv.tv_usec = 1000 * SCHINT(a_ping_handle->ping_common.interval); + } + setsockopt(sock->fd, SOL_SOCKET, SO_SNDTIMEO, (char*) &tv, sizeof(tv)); + + /* Set RCVTIMEO to "interval". Note, it is just an optimization + * allowing to avoid redundant poll(). */ + tv.tv_sec = SCHINT(a_ping_handle->ping_common.interval) / 1000; + tv.tv_usec = 1000 * (SCHINT(a_ping_handle->ping_common.interval) % 1000); + if(setsockopt(sock->fd, SOL_SOCKET, SO_RCVTIMEO, (char*) &tv, sizeof(tv))) + a_ping_handle->ping_common.options |= F_FLOOD_POLL; + + if(!(a_ping_handle->ping_common.options & F_PINGFILLED)) { + int i; + unsigned char *p = a_ping_handle->ping_common.outpack + 8; + + /* Do not forget about case of small datalen, + * fill timestamp area too! + */ + for(i = 0; i < a_ping_handle->ping_common.datalen; ++i) + *p++ = i; + } + + if(sock->socktype == SOCK_RAW) + a_ping_handle->ping_common.ident = htons(getpid() & 0xFFFF); + + set_signal(SIGINT, sigexit); + set_signal(SIGALRM, sigexit); + set_signal(SIGQUIT, sigstatus); + + sigemptyset(&sset); + sigprocmask(SIG_SETMASK, &sset, NULL); + + gettimeofday(&a_ping_handle->ping_common.start_time, NULL); + + if(a_ping_handle->ping_common.deadline) { + struct itimerval it; + + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = 0; + it.it_value.tv_sec = a_ping_handle->ping_common.deadline; + it.it_value.tv_usec = 0; + setitimer(ITIMER_REAL, &it, NULL); + } + + if(isatty(STDOUT_FILENO)) { + struct winsize w; + + if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) { + if(w.ws_col > 0) + a_ping_handle->ping_common.screen_width = w.ws_col; + } + } +} + +/* + * Return 0 if pattern in payload point to be ptr did not match the pattern that was sent + */ +int contains_pattern_in_payload(ping_handle_t *a_ping_handle, uint8_t *ptr) +{ + int i; + uint8_t *cp, *dp; + + /* check the data */ + cp = ((u_char*) ptr) + sizeof(struct timeval); + dp = &a_ping_handle->ping_common.outpack[8 + sizeof(struct timeval)]; + for(i = sizeof(struct timeval); i < a_ping_handle->ping_common.datalen; ++i, ++cp, ++dp) { + if(*cp != *dp) + return 0; + } + return 1; +} + +void main_loop(ping_handle_t *a_ping_handle, ping_func_set_st *fset, socket_st *sock, uint8_t *packet, int packlen) +{ + char addrbuf[128]; + char ans_data[4096]; + struct iovec iov; + struct msghdr msg; + struct cmsghdr *c; + int cc; + int next; + int polling; + int recv_error; + + iov.iov_base = (char *) packet; + + for(;;) { + /* Check exit conditions. */ + if(exiting) + break; + if(a_ping_handle->ping_common.npackets && a_ping_handle->ping_common.nreceived + a_ping_handle->ping_common.nerrors >= a_ping_handle->ping_common.npackets) + break; + if(a_ping_handle->ping_common.deadline && a_ping_handle->ping_common.nerrors) + break; + /* Check for and do special actions. */ + if(status_snapshot) + status(a_ping_handle); + + /* Send probes scheduled to this time. */ + do { + next = pinger(a_ping_handle, fset, sock); + next = schedule_exit(a_ping_handle, next); + } while(next <= 0); + + /* "next" is time to send next probe, if positive. + * If next<=0 send now or as soon as possible. */ + + /* Technical part. Looks wicked. Could be dropped, + * if everyone used the newest kernel. :-) + * Its purpose is: + * 1. Provide intervals less than resolution of scheduler. + * Solution: spinning. + * 2. Avoid use of poll(), when recvmsg() can provide + * timed waiting (SO_RCVTIMEO). */ + polling = 0; + recv_error = 0; + if((a_ping_handle->ping_common.options & (F_ADAPTIVE | F_FLOOD_POLL)) || next < SCHINT(a_ping_handle->ping_common.interval)) { + int recv_expected = in_flight(a_ping_handle); + + /* If we are here, recvmsg() is unable to wait for + * required timeout. */ + if(1000 % HZ == 0 ? next <= 1000 / HZ : (next < INT_MAX / HZ && next * HZ <= 1000)) { + /* Very short timeout... So, if we wait for + * something, we sleep for MININTERVAL. + * Otherwise, spin! */ + if(recv_expected) { + next = MININTERVAL; + } else { + next = 0; + /* When spinning, no reasons to poll. + * Use nonblocking recvmsg() instead. */ + polling = MSG_DONTWAIT; + /* But yield yet. */ + sched_yield(); + } + } + + if(!polling && + ((a_ping_handle->ping_common.options & (F_ADAPTIVE | F_FLOOD_POLL)) || a_ping_handle->ping_common.interval)) { + struct pollfd pset; + pset.fd = sock->fd; + pset.events = POLLIN; + pset.revents = 0; + if(poll(&pset, 1, next) < 1 || + !(pset.revents & (POLLIN | POLLERR))) + continue; + polling = MSG_DONTWAIT; + recv_error = pset.revents & POLLERR; + } + } + + for(;;) { + struct timeval *recv_timep = NULL; + struct timeval recv_time; + int not_ours = 0; /* Raw socket can receive messages + * destined to other running pings. */ + + iov.iov_len = packlen; + memset(&msg, 0, sizeof(msg)); + msg.msg_name = addrbuf; + msg.msg_namelen = sizeof(addrbuf); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = ans_data; + msg.msg_controllen = sizeof(ans_data); + + cc = recvmsg(sock->fd, &msg, polling); + //log_printf("**recvmsg(fd=%d,msg=0x%x,polling=%d)=%d\n",sock->fd,&msg,polling,cc); + polling = MSG_DONTWAIT; + + if(cc < 0) { + /* If there was a POLLERR and there is no packet + * on the socket, try to read the error queue. + * Otherwise, give up. + */ + if((errno == EAGAIN && !recv_error) || + errno == EINTR) + break; + recv_error = 0; + if(!fset->receive_error_msg(a_ping_handle, sock)) { + if(errno) { + error(0, errno, "recvmsg"); + break; + } + not_ours = 1; + } + } else { + +#ifdef SO_TIMESTAMP + for(c = CMSG_FIRSTHDR(&msg); c; c = CMSG_NXTHDR(&msg, c)) { + if(c->cmsg_level != SOL_SOCKET || + c->cmsg_type != SO_TIMESTAMP) + continue; + if(c->cmsg_len < CMSG_LEN(sizeof(struct timeval))) + continue; + recv_timep = (struct timeval*) CMSG_DATA(c); + } +#endif + + if((a_ping_handle->ping_common.options & F_LATENCY) || recv_timep == NULL) { + if((a_ping_handle->ping_common.options & F_LATENCY) || + ioctl(sock->fd, SIOCGSTAMP, &recv_time)) + gettimeofday(&recv_time, NULL); + recv_timep = &recv_time; + } + not_ours = fset->parse_reply(a_ping_handle, sock, &msg, cc, addrbuf, recv_timep); + } + + /* See? ... someone runs another ping on this host. */ + if(not_ours && sock->socktype == SOCK_RAW) + fset->install_filter(a_ping_handle, sock); + + /* If nothing is in flight, "break" returns us to pinger. */ + if(in_flight(a_ping_handle) == 0) + break; + + /* Otherwise, try to recvmsg() again. recvmsg() + * is nonblocking after the first iteration, so that + * if nothing is queued, it will receive EAGAIN + * and return to pinger. */ + } + } + // here present exit() from app + finish(a_ping_handle); +} + +int gather_statistics(ping_handle_t *a_ping_handle, uint8_t *icmph, int icmplen, + int cc, uint16_t seq, int hops, + int csfailed, struct timeval *tv, char *from, + void (*pr_reply)(uint8_t *icmph, int cc)) +{ + int dupflag = 0; + long triptime = 0; + uint8_t *ptr = icmph + icmplen; + + ++a_ping_handle->ping_common.nreceived; + if(!csfailed) + acknowledge(a_ping_handle, seq); + + if(a_ping_handle->ping_common.timing && cc >= (int) (8 + sizeof(struct timeval))) { + struct timeval tmp_tv; + memcpy(&tmp_tv, ptr, sizeof(tmp_tv)); + + restamp: + tvsub(tv, &tmp_tv); + triptime = tv->tv_sec * 1000000 + tv->tv_usec; + if(triptime < 0) { + error(0, 0, "Warning: time of day goes back (%ldus), taking countermeasures", triptime); + triptime = 0; + if(!(a_ping_handle->ping_common.options & F_LATENCY)) { + gettimeofday(tv, NULL); + a_ping_handle->ping_common.options |= F_LATENCY; + goto restamp; + } + } + if(!csfailed) { + a_ping_handle->ping_common.tsum += triptime; + a_ping_handle->ping_common.tsum2 += (long long) triptime * (long long) triptime; + if(triptime < a_ping_handle->ping_common.tmin) + a_ping_handle->ping_common.tmin = triptime; + if(triptime > a_ping_handle->ping_common.tmax) + a_ping_handle->ping_common.tmax = triptime; + if(!a_ping_handle->ping_common.rtt) + a_ping_handle->ping_common.rtt = triptime * 8; + else + a_ping_handle->ping_common.rtt += triptime - a_ping_handle->ping_common.rtt / 8; + if(a_ping_handle->ping_common.options & F_ADAPTIVE) + update_interval(a_ping_handle); + } + } + + if(csfailed) { + ++a_ping_handle->ping_common.nchecksum; + --a_ping_handle->ping_common.nreceived; + } else if(rcvd_test(a_ping_handle, seq)) { + ++a_ping_handle->ping_common.nrepeats; + --a_ping_handle->ping_common.nreceived; + dupflag = 1; + } else { + rcvd_set(a_ping_handle, seq); + dupflag = 0; + } + a_ping_handle->ping_common.confirm = a_ping_handle->ping_common.confirm_flag; + + if(a_ping_handle->ping_common.options & F_QUIET) + return 1; + + if(a_ping_handle->ping_common.options & F_FLOOD) { + if(!csfailed) + write_stdout("\b \b", 3); + else + write_stdout("\bC", 2); + } else { + int i; + uint8_t *cp, *dp; + + print_timestamp(a_ping_handle); + log_printf("%d bytes from %s:", cc, from); + + if(pr_reply) + pr_reply(icmph, cc); + + if(hops >= 0) + log_printf(" ttl=%d", hops); + + if(cc < a_ping_handle->ping_common.datalen + 8) { + log_printf(" (truncated)\n"); + return 1; + } + if(a_ping_handle->ping_common.timing) { + if(triptime >= 100000) + log_printf(" time=%ld ms", (triptime + 500) / 1000); + else if(triptime >= 10000) + log_printf(" time=%ld.%01ld ms", (triptime + 50) / 1000, + ((triptime + 50) % 1000) / 100); + else if(triptime >= 1000) + log_printf(" time=%ld.%02ld ms", (triptime + 5) / 1000, + ((triptime + 5) % 1000) / 10); + else + log_printf(" time=%ld.%03ld ms", triptime / 1000, + triptime % 1000); + log_printf(" tsum=%d ", a_ping_handle->ping_common.tsum); + } + if(dupflag) + log_printf(" (DUP!)"); + if(csfailed) + log_printf(" (BAD CHECKSUM!)"); + + /* check the data */ + cp = ((unsigned char*) ptr) + sizeof(struct timeval); + dp = &a_ping_handle->ping_common.outpack[8 + sizeof(struct timeval)]; + for(i = sizeof(struct timeval); i < a_ping_handle->ping_common.datalen; ++i, ++cp, ++dp) { + if(*cp != *dp) { + log_printf("\nwrong data byte #%d should be 0x%x but was 0x%x", + i, *dp, *cp); + cp = (unsigned char*) ptr + sizeof(struct timeval); + for(i = sizeof(struct timeval); i < a_ping_handle->ping_common.datalen; ++i, ++cp) { + if((i % 32) == sizeof(struct timeval)) + log_printf("\n#%d\t", i); + log_printf("%x ", *cp); + } + break; + } + } + } + return 0; +} +#ifdef PING_DBG +static long llsqrt(long long a) +{ + long long prev = LLONG_MAX; + long long x = a; + + if (x > 0) { + while (x < prev) { + prev = x; + x = (x+(a/x))/2; + } + } + + return (long)x; +} +#endif + +/* + * finish -- + * Print out statistics, and give up. + */ +void finish(ping_handle_t *a_ping_handle) +{ + struct timeval tv = a_ping_handle->ping_common.cur_time; +#ifdef PING_DBG + char *comma = ""; +#endif + + tvsub(&tv, &a_ping_handle->ping_common.start_time); +#ifdef PING_DBG + putchar('\n'); + fflush(stdout); + printf("--- %s ping statistics ---\n", hostname); + printf("%ld packets transmitted, ", ntransmitted); + printf("%ld received", nreceived); + if (nrepeats) + log_printf(", +%ld duplicates", nrepeats); + if (nchecksum) + printf(", +%ld corrupted", nchecksum); + if (nerrors) + printf(", +%ld errors", nerrors); + if (ntransmitted) { +#ifdef USE_IDN + setlocale(LC_ALL, "C"); +#endif + printf(", %g%% packet loss", + (float) ((((long long)(ntransmitted - nreceived)) * 100.0) / + ntransmitted)); + printf(", time %ldms", 1000*tv.tv_sec+(tv.tv_usec+500)/1000); + } + putchar('\n'); +#endif + + if(a_ping_handle->ping_common.nreceived && a_ping_handle->ping_common.timing) { + + a_ping_handle->ping_common.tsum /= a_ping_handle->ping_common.nreceived + a_ping_handle->ping_common.nrepeats; + a_ping_handle->ping_common.tsum2 /= a_ping_handle->ping_common.nreceived + a_ping_handle->ping_common.nrepeats; +#ifdef PING_DBG + long tmdev; + tmdev = llsqrt(tsum2 - tsum * tsum); + printf("rtt min/avg/max/mdev = %ld.%03ld/%lu.%03ld/%ld.%03ld/%ld.%03ld ms", + (long)tmin/1000, (long)tmin%1000, + (unsigned long)(tsum/1000), (long)(tsum%1000), + (long)tmax/1000, (long)tmax%1000, + (long)tmdev/1000, (long)tmdev%1000 + ); + comma = ", "; +#endif + } +#ifdef PING_DBG + if (pipesize > 1) { + printf("%spipe %d", comma, pipesize); + comma = ", "; + } + if (nreceived && (!interval || (a_ping_handle->ping_common.options&(F_FLOOD|F_ADAPTIVE))) && ntransmitted > 1) { + int ipg = (1000000*(long long)tv.tv_sec+tv.tv_usec)/(ntransmitted-1); + printf("%sipg/ewma %d.%03d/%d.%03d ms", + comma, ipg/1000, ipg%1000, rtt/8000, (rtt/8)%1000); + } + putchar('\n'); + //exit(!nreceived || (deadline && nreceived < npackets)); +#endif +} + +void status(ping_handle_t *a_ping_handle) +{ + int loss = 0; + long tavg = 0; + + status_snapshot = 0; + + if(a_ping_handle->ping_common.ntransmitted) + loss = (((long long) (a_ping_handle->ping_common.ntransmitted - a_ping_handle->ping_common.nreceived)) * 100) / a_ping_handle->ping_common.ntransmitted; + + fprintf(stderr, "\r%ld/%ld packets, %d%% loss", a_ping_handle->ping_common.nreceived, a_ping_handle->ping_common.ntransmitted, loss); + + if(a_ping_handle->ping_common.nreceived && a_ping_handle->ping_common.timing) { + tavg = a_ping_handle->ping_common.tsum / (a_ping_handle->ping_common.nreceived + a_ping_handle->ping_common.nrepeats); + + fprintf(stderr, ", min/avg/ewma/max = %ld.%03ld/%lu.%03ld/%d.%03d/%ld.%03ld ms", + (long) a_ping_handle->ping_common.tmin / 1000, (long) a_ping_handle->ping_common.tmin % 1000, + tavg / 1000, tavg % 1000, + a_ping_handle->ping_common.rtt / 8000, (a_ping_handle->ping_common.rtt / 8) % 1000, + (long) a_ping_handle->ping_common.tmax / 1000, (long) a_ping_handle->ping_common.tmax % 1000 + ); + } + fprintf(stderr, "\n"); +} + +inline int is_ours(ping_handle_t *a_ping_handle, socket_st *sock, uint16_t id) { + return sock->socktype == SOCK_DGRAM || id == a_ping_handle->ping_common.ident; +} diff --git a/modules/net/iputils/tracepath.c b/modules/net/iputils/tracepath.c new file mode 100755 index 0000000000000000000000000000000000000000..2dce76420ca7396496ba18068819f85011b0a0a7 --- /dev/null +++ b/modules/net/iputils/tracepath.c @@ -0,0 +1,783 @@ +/* + * tracepath.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> + */ + +#include <arpa/inet.h> +#include <errno.h> +#include <limits.h> +#include <time.h> +#include <linux/errqueue.h> +#include <linux/icmp.h> +#include <linux/icmpv6.h> +#include <linux/types.h> +#include <netdb.h> +#include <netinet/in.h> +#include <resolv.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/uio.h> +#include <unistd.h> +//#include <glib.h> + +#include "iputils.h" + +#ifdef USE_IDN +# include <locale.h> +# ifndef AI_IDN +# define AI_IDN 0x0040 +# endif +# ifndef NI_IDN +# define NI_IDN 32 +# endif +# define getnameinfo_flags NI_IDN +#else +# define getnameinfo_flags 0 +#endif + +#ifndef SOL_IPV6 +# define SOL_IPV6 IPPROTO_IPV6 +#endif + +#ifndef IP_PMTUDISC_DO +# define IP_PMTUDISC_DO 3 +#endif +#ifndef IPV6_PMTUDISC_DO +# define IPV6_PMTUDISC_DO 3 +#endif + +enum { + MAX_PROBES = 10, + + MAX_HOPS_DEFAULT = 30, + MAX_HOPS_LIMIT = 255, + + HOST_COLUMN_SIZE = 52, + + HIS_ARRAY_SIZE = 64, + + DEFAULT_OVERHEAD_IPV4 = 28, + DEFAULT_OVERHEAD_IPV6 = 48, + + DEFAULT_MTU_IPV4 = 65535, + DEFAULT_MTU_IPV6 = 128000, + + DEFAULT_BASEPORT = 44444, + + ANCILLARY_DATA_LEN = 512, +}; + +struct hhistory { + int hops; + struct timeval sendtime; + struct timeval deltatime; + int hop; + char *host_namea; + char *host_nameb; +}; + +struct probehdr { + uint32_t ttl; + struct timeval tv; +}; + +struct run_state { + struct hhistory his[HIS_ARRAY_SIZE]; + int hisptr; + struct sockaddr_storage target; + struct addrinfo *ai; + int socket_fd; + socklen_t targetlen; + uint16_t base_port; + uint8_t ttl; + int max_hops; + int overhead; + int mtu; + void *pktbuf; + int hops_to; + int hops_from; + unsigned int + no_resolve :1, + show_both :1, + mapped :1; +}; + +/* + * All includes, definitions, struct declarations, and global variables are + * above. After this comment all you can find is functions. + */ + +static void data_wait(struct run_state const * const ctl) +{ + fd_set fds; + struct timeval tv = { + .tv_sec = 1, + .tv_usec = 0 + }; + + FD_ZERO(&fds); + FD_SET(ctl->socket_fd, &fds); + select(ctl->socket_fd + 1, &fds, NULL, NULL, &tv); +} + +static void print_host(struct run_state const * const ctl, char const * const a, + char const * const b) +{ + int plen; + + plen = log_printf("%s", a); + if(ctl->show_both) + plen += log_printf(" (%s)", b); + if(plen >= HOST_COLUMN_SIZE) + plen = HOST_COLUMN_SIZE - 1; + log_printf("%*s", HOST_COLUMN_SIZE - plen, ""); +} + +static int recverr(struct run_state * const ctl) +{ + ssize_t recv_size; + struct probehdr rcvbuf; + char cbuf[ANCILLARY_DATA_LEN]; + struct cmsghdr *cmsg; + struct sock_extended_err *e; + struct sockaddr_storage addr; + struct timeval tv; + struct timeval *rettv; + struct timeval *deltatv; + int slot = 0; + int rethops; + int sndhops; + int progress = -1; + int broken_router; + char hnamebuf[NI_MAXHOST] = ""; + struct iovec iov = { + .iov_base = &rcvbuf, + .iov_len = sizeof(rcvbuf) + }; + struct msghdr msg; + const struct msghdr reset = { + .msg_name = (uint8_t *) &addr, + .msg_namelen = sizeof(addr), + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = cbuf, + .msg_controllen = sizeof(cbuf), + 0 + }; + + restart: + memset(&rcvbuf, -1, sizeof(rcvbuf)); + msg = reset; + + gettimeofday(&tv, NULL); + recv_size = recvmsg(ctl->socket_fd, &msg, MSG_ERRQUEUE); + if(recv_size < 0) { + if(errno == EAGAIN) + return progress; + goto restart; + } + + progress = ctl->mtu; + + rethops = -1; + sndhops = -1; + e = NULL; + rettv = NULL; + deltatv = NULL; + broken_router = 0; + + slot = -ctl->base_port; + switch (ctl->ai->ai_family) { + case AF_INET6: + slot += ntohs(((struct sockaddr_in6 *) &addr)->sin6_port); + break; + case AF_INET: + slot += ntohs(((struct sockaddr_in *) &addr)->sin_port); + break; + } + + if(slot >= 0 && slot < (HIS_ARRAY_SIZE - 1) && ctl->his[slot].hops) { + sndhops = ctl->his[slot].hops; + rettv = &ctl->his[slot].sendtime; + deltatv = &ctl->his[slot].deltatime; + ctl->his[slot].hop = sndhops; + ctl->his[slot].hops = 0; + } + if(recv_size == sizeof(rcvbuf)) { + if(rcvbuf.ttl == 0 || rcvbuf.tv.tv_sec == 0) + broken_router = 1; + else { + sndhops = rcvbuf.ttl; + rettv = &rcvbuf.tv; + } + } + + for(cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { + switch (cmsg->cmsg_level) { + case SOL_IPV6: + switch (cmsg->cmsg_type) { + case IPV6_RECVERR: + e = (struct sock_extended_err *) CMSG_DATA(cmsg); + break; + case IPV6_HOPLIMIT: + #ifdef IPV6_2292HOPLIMIT + case IPV6_2292HOPLIMIT: + #endif + memcpy(&rethops, CMSG_DATA(cmsg), sizeof(rethops)); + break; + default: + log_printf("cmsg6:%d\n ", cmsg->cmsg_type); + } + break; + case SOL_IP: + switch (cmsg->cmsg_type) { + case IP_RECVERR: + e = (struct sock_extended_err *) CMSG_DATA(cmsg); + break; + case IP_TTL: + rethops = *(uint8_t *) CMSG_DATA(cmsg); + break; + default: + log_printf("cmsg4:%d\n ", cmsg->cmsg_type); + } + } + } + if(e == NULL) { + log_printf("no info\n"); + return 0; + } + if(e->ee_origin == SO_EE_ORIGIN_LOCAL) + log_printf("%2d?: %-32s ", ctl->ttl, "[LOCALHOST]"); + else if(e->ee_origin == SO_EE_ORIGIN_ICMP6 || + e->ee_origin == SO_EE_ORIGIN_ICMP) { + char abuf[NI_MAXHOST]; + struct sockaddr *sa = (struct sockaddr *) (e + 1); + socklen_t salen; + + if(sndhops > 0) + log_printf("%2d: ", sndhops); + else + log_printf("%2d?: ", ctl->ttl); + + switch (sa->sa_family) { + case AF_INET6: + salen = sizeof(struct sockaddr_in6); + break; + case AF_INET: + salen = sizeof(struct sockaddr_in); + break; + default: + salen = 0; + } + + if(ctl->no_resolve || ctl->show_both) + { + if(getnameinfo(sa, salen, abuf, sizeof(abuf), NULL, 0, + NI_NUMERICHOST)) + strcpy(abuf, "???"); + ctl->his[slot].host_namea = strdup(abuf); + } else + abuf[0] = 0; + + if(!ctl->no_resolve || ctl->show_both) + { + fflush(stdout); + if(getnameinfo(sa, salen, hnamebuf, sizeof hnamebuf, NULL, 0, + getnameinfo_flags)) + strcpy(hnamebuf, "???"); + ctl->his[slot].host_nameb = strdup(hnamebuf); + } else + hnamebuf[0] = 0; + + if(ctl->no_resolve) { + print_host(ctl, abuf, hnamebuf); + } + else { + print_host(ctl, hnamebuf, abuf); + } + } + + if(rettv) { + struct timeval res; + + timersub(&tv, rettv, &res); + if(deltatv) + memcpy(deltatv, &res, sizeof(struct timeval)); + log_printf("%3ld.%03ldms ", res.tv_sec * 1000 + res.tv_usec / 1000, res.tv_usec % 1000); + if(broken_router) + log_printf("(This broken router returned corrupted payload) "); + } + + if(rethops <= 64) + rethops = 65 - rethops; + else if(rethops <= 128) + rethops = 129 - rethops; + else + rethops = 256 - rethops; + + //log_printf("ERROR=%d ", e->ee_errno); + switch (e->ee_errno) { + case ETIMEDOUT: + log_printf("\n"); + break; + case EMSGSIZE: + log_printf("pmtu %d\n", e->ee_info); + ctl->mtu = e->ee_info; + progress = ctl->mtu; + break; + case ECONNREFUSED: + log_printf("reached\n"); + ctl->hops_to = sndhops < 0 ? ctl->ttl : sndhops; + ctl->hops_from = rethops; + return 0; + case EPROTO: + log_printf("!P\n"); + return 0; + case EHOSTUNREACH: + if((e->ee_origin == SO_EE_ORIGIN_ICMP && + e->ee_type == ICMP_TIME_EXCEEDED && + e->ee_code == ICMP_EXC_TTL) || + (e->ee_origin == SO_EE_ORIGIN_ICMP6 && + e->ee_type == ICMPV6_TIME_EXCEED && + e->ee_code == ICMPV6_EXC_HOPLIMIT)) { + if(rethops >= 0) { + if(sndhops >= 0 && rethops != sndhops) + log_printf("asymm %2d ", rethops); + else if(sndhops < 0 && rethops != ctl->ttl) + log_printf("asymm %2d ", rethops); + } + //log_printf("hops=->%2d, <-%2d ", sndhops, rethops); + log_printf("\n"); + break; + } + printf("!H\n"); + return 0; + case ENETUNREACH: + log_printf("!N\n"); + return 0; + case EACCES: + log_printf("!A\n"); + return 0; + default: + printf("\n"); + errno = e->ee_errno; + perror("NET ERROR"); + return 0; + } + goto restart; + return 0; +} + +static int probe_ttl(struct run_state * const ctl) +{ + int i; + struct probehdr *hdr = ctl->pktbuf; + + memset(ctl->pktbuf, 0, ctl->mtu); + restart: + for(i = 0; i < MAX_PROBES; i++) { + int res; + + hdr->ttl = ctl->ttl; + switch (ctl->ai->ai_family) { + case AF_INET6: + ((struct sockaddr_in6 *) &ctl->target)->sin6_port = + htons(ctl->base_port + ctl->hisptr); + break; + case AF_INET: + ((struct sockaddr_in *) &ctl->target)->sin_port = + htons(ctl->base_port + ctl->hisptr); + break; + } + gettimeofday(&hdr->tv, NULL); + ctl->his[ctl->hisptr].hops = ctl->ttl; + ctl->his[ctl->hisptr].sendtime = hdr->tv; + if(sendto(ctl->socket_fd, ctl->pktbuf, ctl->mtu - ctl->overhead, 0, + (struct sockaddr *) &ctl->target, ctl->targetlen) > 0) + break; + res = recverr(ctl); + ctl->his[ctl->hisptr].hops = 0; + if(res == 0) + return 0; + if(res > 0) + goto restart; + } + ctl->hisptr = (ctl->hisptr + 1) & (HIS_ARRAY_SIZE - 1); + + if(i < MAX_PROBES) { + data_wait(ctl); + if(recv(ctl->socket_fd, ctl->pktbuf, ctl->mtu, MSG_DONTWAIT) > 0) { + log_printf("%2d?: reply received 8)\n", ctl->ttl); + return 0; + } + return recverr(ctl); + } + + log_printf("%2d: send failed\n", ctl->ttl); + return 0; +} + +static void usage(void) +{ + fprintf(stderr, + "\nUsage\n" + " tracepath [options] <destination>\n" + "\nOptions:\n" + " -4 use IPv4\n" + " -6 use IPv6\n" + " -b print both name and ip\n" + " -l <length> use packet <length>\n" + " -m <hops> use maximum <hops>\n" + " -n no dns name resolution\n" + " -p <port> use destination <port>\n" + " -V print version and exit\n" + " <destination> dns name or ip address\n" + "\nFor more details see tracepath(8).\n"); + exit(-1); +} + +int tracepath_main(int argc, char **argv, struct run_state *ctl) +{ + int ret = -1; + struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_DGRAM, + .ai_protocol = IPPROTO_UDP, +#ifdef USE_IDN + .ai_flags = AI_IDN | AI_CANONNAME, +#endif + }; + struct addrinfo *result; + int ch; + int status; + int on; + char *p; + char pbuf[NI_MAXSERV]; + +#ifdef USE_IDN + setlocale(LC_ALL, ""); +#endif + + /* Support being called using `tracepath4` or `tracepath6` symlinks */ + if(argv[0][strlen(argv[0]) - 1] == '4') + hints.ai_family = AF_INET; + else if(argv[0][strlen(argv[0]) - 1] == '6') + hints.ai_family = AF_INET6; + + while((ch = getopt(argc, argv, "46nbh?l:m:p:V")) != EOF) { + switch (ch) { + case '4': + if(hints.ai_family == AF_INET6) { + fprintf(stderr, + "tracepath: Only one -4 or -6 option may be specified\n"); + return -1; //exit(2); + } + hints.ai_family = AF_INET; + break; + case '6': + if(hints.ai_family == AF_INET) { + fprintf(stderr, + "tracepath: Only one -4 or -6 option may be specified\n"); + return -1; //exit(2); + } + hints.ai_family = AF_INET6; + break; + case 'n': + ctl->no_resolve = 1; + break; + case 'b': + ctl->show_both = 1; + break; + case 'l': + if((ctl->mtu = atoi(optarg)) <= ctl->overhead) { + fprintf(stderr, + "Error: pktlen must be > %d and <= %d.\n", + ctl->overhead, INT_MAX); + return -1; //exit(1); + } + break; + case 'm': + ctl->max_hops = atoi(optarg); + if(ctl->max_hops < 0 || ctl->max_hops > MAX_HOPS_LIMIT) { + fprintf(stderr, + "Error: max hops must be 0 .. %d (inclusive).\n", + MAX_HOPS_LIMIT); + return -1; //exit(1); + } + break; + case 'p': + ctl->base_port = atoi(optarg); + break; + case 'V': + printf(IPUTILS_VERSION("tracepath")); + return 0; + default: + usage(); + } + } + + argc -= optind; + argv += optind; + optind = 0; + + if(argc != 1) + usage(); + + /* Backward compatibility */ + if(!ctl->base_port) { + p = strchr(argv[0], '/'); + if(p) { + *p = 0; + ctl->base_port = atoi(p + 1); + } else + ctl->base_port = DEFAULT_BASEPORT; + } + sprintf(pbuf, "%u", ctl->base_port); + + status = getaddrinfo(argv[0], pbuf, &hints, &result); + if(status) { + fprintf(stderr, "tracepath: %s: %s\n", argv[0], + gai_strerror(status)); + return -EADDRNOTAVAIL;//exit(1); + } + + for(ctl->ai = result; ctl->ai; ctl->ai = ctl->ai->ai_next) { + if(ctl->ai->ai_family != AF_INET6 && ctl->ai->ai_family != AF_INET) + continue; + ctl->socket_fd = socket(ctl->ai->ai_family, ctl->ai->ai_socktype, ctl->ai->ai_protocol); + if(ctl->socket_fd < 0) + continue; + memcpy(&ctl->target, ctl->ai->ai_addr, ctl->ai->ai_addrlen); + ctl->targetlen = ctl->ai->ai_addrlen; + break; + } + if(ctl->socket_fd < 0) { + perror("socket/connect"); + return -ESOCKTNOSUPPORT;//exit(1); + } + + switch (ctl->ai->ai_family) { + case AF_INET6: + ctl->overhead = DEFAULT_OVERHEAD_IPV6; + if(!ctl->mtu) + ctl->mtu = DEFAULT_MTU_IPV6; + if(ctl->mtu <= ctl->overhead) + goto pktlen_error; + + on = IPV6_PMTUDISC_DO; + if(setsockopt(ctl->socket_fd, SOL_IPV6, IPV6_MTU_DISCOVER, &on, sizeof(on)) && + (on = IPV6_PMTUDISC_DO, setsockopt(ctl->socket_fd, SOL_IPV6, + IPV6_MTU_DISCOVER, &on, sizeof(on)))) { + perror("IPV6_MTU_DISCOVER"); + return -2;//exit(1); + } + on = 1; + if(setsockopt(ctl->socket_fd, SOL_IPV6, IPV6_RECVERR, &on, sizeof(on))) { + perror("IPV6_RECVERR"); + return -3;//exit(1); + } + if(setsockopt(ctl->socket_fd, SOL_IPV6, IPV6_HOPLIMIT, &on, sizeof(on)) + #ifdef IPV6_RECVHOPLIMIT + && setsockopt(ctl->socket_fd, SOL_IPV6, IPV6_2292HOPLIMIT, &on, sizeof(on)) + #endif + ) { + perror("IPV6_HOPLIMIT"); + return -4;//exit(1); + } + if(!IN6_IS_ADDR_V4MAPPED(&(((struct sockaddr_in6 * )&ctl->target)->sin6_addr))) + break; + ctl->mapped = 1; + /*FALLTHROUGH*/ + case AF_INET: + ctl->overhead = DEFAULT_OVERHEAD_IPV4; + if(!ctl->mtu) + ctl->mtu = DEFAULT_MTU_IPV4; + if(ctl->mtu <= ctl->overhead) + goto pktlen_error; + + on = IP_PMTUDISC_DO; + if(setsockopt(ctl->socket_fd, SOL_IP, IP_MTU_DISCOVER, &on, sizeof(on))) { + perror("IP_MTU_DISCOVER"); + return -5;//exit(1); + } + on = 1; + if(setsockopt(ctl->socket_fd, SOL_IP, IP_RECVERR, &on, sizeof(on))) { + perror("IP_RECVERR"); + return -6;//exit(1); + } + if(setsockopt(ctl->socket_fd, SOL_IP, IP_RECVTTL, &on, sizeof(on))) { + perror("IP_RECVTTL"); + return -7;//exit(1); + } + } + + ctl->pktbuf = malloc(ctl->mtu); + if(!ctl->pktbuf) { + perror("malloc"); + return -8; //exit(1); + } + +// struct sockaddr sa; +// int salen6 = sizeof(struct sockaddr_in6); +// int salen = sizeof(struct sockaddr_in); + char target_ip[NI_MAXHOST]; + char *target_name = argv[0]; + memset(&target_ip, 0, sizeof(target_ip)); + getnameinfo((struct sockaddr *) &ctl->target, ctl->targetlen, target_ip, sizeof(target_ip), NULL, 0, + NI_NUMERICHOST); + log_printf("START target_name=%s target_ip=%s\n", target_name, target_ip); + + for(ctl->ttl = 1; ctl->ttl <= ctl->max_hops; ctl->ttl++) { + int res; + int i; + + on = ctl->ttl; + switch (ctl->ai->ai_family) { + case AF_INET6: + if(setsockopt(ctl->socket_fd, SOL_IPV6, IPV6_UNICAST_HOPS, &on, sizeof(on))) { + perror("IPV6_UNICAST_HOPS"); + return -9; //exit(1); + } + if(!ctl->mapped) + break; + /*FALLTHROUGH*/ + case AF_INET: + if(setsockopt(ctl->socket_fd, SOL_IP, IP_TTL, &on, sizeof(on))) { + perror("IP_TTL"); + return -10; //exit(1); + } + } + + restart: + for(i = 0; i < 2; i++) { + int old_mtu; + + old_mtu = ctl->mtu; + res = probe_ttl(ctl); + if(ctl->mtu != old_mtu) + goto restart; + if(res == 0) + goto done; + if(res > 0) + break; + } + // if already find need name, make ret>=0 and break + { + int i = ctl->hisptr - 1; + //for(int i = 0; i < MAX_HOPS_DEFAULT; i++) + { + char *host_namea = (ctl->his[i].host_namea); + char *host_nameb = (ctl->his[i].host_nameb); + if(host_namea) { + if(!strcmp(host_namea, target_name) || !strcmp(host_namea, target_ip)) { + ctl->ttl = ctl->max_hops; + ret = i; + break; + } + } + if(host_nameb) { + if(!strcmp(host_nameb, target_name) || !strcmp(host_nameb, target_ip)) { + ctl->ttl = ctl->max_hops; + ret = i; + break; + } + } + } + } + if(res < 0) + log_printf("%2d: no reply\n", ctl->ttl); + } + log_printf(" Too many hops: pmtu %d\n", ctl->mtu); + + done: + freeaddrinfo(result); + + log_printf(" Resume: pmtu %d ", ctl->mtu); + if(ctl->hops_to >= 0) + { + ret = ctl->hisptr - 1; + log_printf("hops %d ", ctl->hops_to); + } + if(ctl->hops_from >= 0) + log_printf("back %d ", ctl->hops_from); + log_printf("\n"); + return ret; //exit(0); + + pktlen_error: + fprintf(stderr, "Error: pktlen must be > %d and <= %d\n", + ctl->overhead, INT_MAX); + return -1; //exit(1); +} + +/** + * Tracepath host + * + * @addr[in] host name or IP address + * @hops[out] hops count + * @time_usec[out] latency in microseconds + * @return 0 Ok, -1 error + */ +int tracepath_util(const char *addr, int *hops, int *time_usec) +{ + int type = 4; // 4 or 6 + int total_hops = 0; + long int total_time_usec = 0; // latency in microseconds + int argc = 4; + const char *argv[argc]; + if(type != 4) + argv[0] = "tracepath6"; + else + argv[0] = "tracepath4"; + argv[1] = "-b"; // print both name and ip + argv[2] = "-m 26"; // -n -m 16 + argv[3] = addr; + struct run_state ctl = { + .max_hops = MAX_HOPS_DEFAULT, + .hops_to = -1, + .hops_from = -1, + 0 + }; + int ret = tracepath_main(argc, (char**) argv, &ctl); + for(int i = 0; i < MAX_HOPS_DEFAULT; i++) { + free(ctl.his[i].host_namea); + free(ctl.his[i].host_nameb); + } + if(ret >= 0) + { + struct timeval *deltatime = &(ctl.his[ret].deltatime); + total_hops = ctl.his[ret].hop; + total_time_usec = deltatime->tv_sec * 1000000 + deltatime->tv_usec; + } + else + for(int i = 0; i < MAX_HOPS_DEFAULT; i++) { + struct timeval *deltatime = &(ctl.his[i].deltatime); + if(ctl.his[i].hop) { //if(!ctl.his[i].hops && (deltatime->tv_sec > 0 || deltatime->tv_usec > 0)) { + total_hops = ctl.his[i].hop; + total_time_usec = deltatime->tv_sec * 1000000 + deltatime->tv_usec; + } + /*if(ctl.his[i].hop > 0) + { + char *host_name = (ctl.his[i].host_name) ? ctl.his[i].host_name : "-"; + printf("%d %d: %s %ld\n", ctl.his[i].hops, ctl.his[i].hop, host_name, + deltatime->tv_sec * 1000000 + deltatime->tv_usec); + }*/ + } + if(hops) { + *hops = total_hops; + } + if(time_usec) { + *time_usec = total_time_usec; + } + return (ret >= 0) ? 0 : ret; + +} + diff --git a/modules/net/iputils/traceroute/as_lookups.c b/modules/net/iputils/traceroute/as_lookups.c new file mode 100644 index 0000000000000000000000000000000000000000..873180375802bce154e491966ea68f81eab98522 --- /dev/null +++ b/modules/net/iputils/traceroute/as_lookups.c @@ -0,0 +1,128 @@ +/* + Copyright (c) 2006, 2007 Dmitry Butskoy + <buc@citadel.stu.neva.ru> + License: GPL v2 or any later + + See COPYING for the status of this software. +*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <unistd.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> + +#include "traceroute.h" + + +#define DEF_RADB_SERVER "whois.radb.net" +#define DEF_RADB_SERVICE "nicname" + + +static sockaddr_any ra_addr = {{ 0, }, }; +static char ra_buf[512] = { 0, }; + + +const char *get_as_path (const char *query) { + int sk, n; + FILE *fp; + char buf[1024]; + int prefix = 0, best_prefix = 0; + char *rb, *re = &ra_buf[sizeof (ra_buf) / sizeof (*ra_buf) - 1]; + + + if (!ra_addr.sa.sa_family) { + const char *server, *service; + struct addrinfo *res; + int ret; + + server = getenv ("RA_SERVER"); + if (!server) server = DEF_RADB_SERVER; + + service = getenv ("RA_SERVICE"); + if (!service) service = DEF_RADB_SERVICE; + + + ret = getaddrinfo (server, service, NULL, &res); + if (ret) { + fprintf (stderr, "%s/%s: %s\n", server, service, + gai_strerror(ret)); + exit (2); + } + + memcpy (&ra_addr, res->ai_addr, res->ai_addrlen); + + freeaddrinfo (res); + } + + + sk = socket (ra_addr.sa.sa_family, SOCK_STREAM, 0); + if (sk < 0) error ("socket"); + + if (connect (sk, &ra_addr.sa, sizeof (ra_addr)) < 0) + goto err_sk; + + n = snprintf (buf, sizeof (buf), "%s\r\n", query); + if (n >= (int)sizeof (buf)) goto err_sk; + + if (write (sk, buf, n) < n) + goto err_sk; + + fp = fdopen (sk, "r"); + if (!fp) goto err_sk; + + + strcpy (ra_buf, "*"); + rb = ra_buf; + + while (fgets (buf, sizeof (buf), fp) != NULL) { + + if (!strncmp (buf, "route:", sizeof ("route:") - 1) || + !strncmp (buf, "route6:", sizeof ("route6:") - 1) + ) { + char *p = strchr (buf, '/'); + + if (p) prefix = strtoul (++p, NULL, 10); + else prefix = 0; /* Hmmm... */ + + } + else if (!strncmp (buf, "origin:", sizeof ("origin:") -1)) { + char *p, *as; + + p = buf + (sizeof ("origin:") - 1); + + while (isspace (*p)) p++; + as = p; + while (*p && !isspace (*p)) p++; + *p = '\0'; + + if (prefix > best_prefix) { + best_prefix = prefix; + + rb = ra_buf; + while (rb < re && (*rb++ = *as++)) ; + } + else if (prefix == best_prefix) { + char *q = strstr (ra_buf, as); + + if (!q || (*(q += strlen (as)) != '\0' && *q != '/')) { + if (rb > ra_buf) rb[-1] = '/'; + while (rb < re && (*rb++ = *as++)) ; + } + } + /* else just ignore it */ + } + } + + fclose (fp); + + return ra_buf; + + +err_sk: + close (sk); + return "!!"; +} diff --git a/modules/net/iputils/traceroute/clif.c b/modules/net/iputils/traceroute/clif.c new file mode 100644 index 0000000000000000000000000000000000000000..4380e8ecd061e5becee1f296c89a8c8bbf127b51 --- /dev/null +++ b/modules/net/iputils/traceroute/clif.c @@ -0,0 +1,1284 @@ +/* + Copyright (c) 2000, 2003 Dmitry Butskoy + <buc@citadel.stu.neva.ru> + License: LGPL v2.1 or any later + + See COPYING.LIB for the status of this software. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> + +#include "../iputils.h" +#include "clif.h" + +#if 1 /* Bad idea, anyway... */ +#define MAX_ARGC_NUMBER 256 +typedef unsigned char _CLIF_index; +#else +#define MAX_ARGC_NUMBER (4096 / 5 + 1) /* POSIX ARG_MAX >= 4096 ... */ +typedef unsigned short _CLIF_index; +#endif + +/* This is needed for some print info functions. + This is ugly for thread-safe (is it really actual on program invoking?), + and for several CLIF_parse_cmdline invoking... But foo on this. Yeah... + */ +static struct { + int argc; + char **argv; + CLIF_option *option_list; + CLIF_argument *argument_list; + unsigned int parse_flags; +} curr = { 0, }; + +static void err_report(const char *format, ...) { + va_list ap; + + if(curr.parse_flags & CLIF_SILENT) + return; + + va_start(ap, format); + + vfprintf(stderr, format, ap); + + va_end(ap); + + fprintf(stderr, "\n"); + + return; +} + +/* info generation stuff... */ + +#define SHORT_PLUS_MINUS "+/-" +#define LONG_PLUS_MINUS "++/--" +#define EXCL_DLM " | " + +static char *show_short(const CLIF_option *optn) { + static char buf[80]; + char *p = buf; + unsigned int flags = optn->flags | curr.parse_flags; + + if(optn->function_plus) { + if(!optn->function) + *p++ = '+'; + else { + strcpy(p, SHORT_PLUS_MINUS); + p += sizeof(SHORT_PLUS_MINUS) - 1; + } + } else + *p++ = '-'; + + *p++ = optn->short_opt[0]; + + if(optn->arg_name) { + char *endp = buf + sizeof(buf) - sizeof(",...]"); + const char *s; + + if(!(flags & _CLIF_STRICT_JOIN_ARG)) + *p++ = ' '; + if(flags & CLIF_OPTARG) + *p++ = '['; + + s = optn->arg_name; + while(*s && p < endp) + *p++ = *s++; + + if(flags & CLIF_SEVERAL) { + strcpy(p, ",..."); + p += sizeof(",...") - 1; /* last '\0' ... */ + } + + if(flags & CLIF_OPTARG) + *p++ = ']'; + } + + *p = '\0'; + + return buf; +} + +static char *show_long(const CLIF_option *optn) { + static char buf[80]; + char *p = buf; + char *endp; + const char *s; + unsigned int flags = optn->flags | curr.parse_flags; + + if(!(flags & _CLIF_STRICT_KEYWORD)) { + + if(!(flags & _CLIF_STRICT_ONEDASH)) { + if(optn->function_plus) { + if(!optn->function) { + *p++ = '+'; + *p++ = '+'; + } + else { + strcpy(p, LONG_PLUS_MINUS); + p += sizeof(LONG_PLUS_MINUS) - 1; + } + } else { + *p++ = '-'; + *p++ = '-'; + } + + } else { + if(optn->function_plus) { + if(!optn->function) + *p++ = '+'; + else { + strcpy(p, SHORT_PLUS_MINUS); + p += sizeof(SHORT_PLUS_MINUS) - 1; + } + } else + *p++ = '-'; + } + } + + s = optn->long_opt; + endp = buf + sizeof(buf) - sizeof(" ["); + while(*s && p < endp) + *p++ = *s++; + + if(optn->arg_name) { + + if(flags & _CLIF_STRICT_NOEQUAL) { + *p++ = ' '; + if(flags & CLIF_OPTARG) + *p++ = '['; + } else { + if(flags & CLIF_OPTARG) + *p++ = '['; + *p++ = '='; + } + + s = optn->arg_name; + endp = buf + sizeof(buf) - sizeof(",...]"); + while(*s && p < endp) + *p++ = *s++; + + if(flags & CLIF_SEVERAL) { + strcpy(p, ",..."); + p += sizeof(",...") - 1; /* last '\0' ... */ + } + + if(flags & CLIF_OPTARG) + *p++ = ']'; + } + + *p = '\0'; + + return buf; +} + +static char *show_excl(const CLIF_option *option_list, int *cnt_p) { + static char buf[256]; + const CLIF_option *optn; + char *p = buf; + char *endp = buf + sizeof(buf) - sizeof(EXCL_DLM); + int excl_cnt = 0; + + *p = '\0'; + if(cnt_p) + *cnt_p = 0; + if(!option_list) + return buf; + + for(optn = option_list; optn->short_opt || optn->long_opt; optn++) { + char *s; + + if(!(optn->flags & CLIF_EXCL)) + continue; + + if(optn->short_opt) + s = show_short(optn); + else + s = show_long(optn); + + if(excl_cnt > 0) { /* i.e., second etc... */ + strcpy(p, EXCL_DLM); + p += sizeof(EXCL_DLM) - 1; + } + + while(*s && p < endp) + *p++ = *s++; + + excl_cnt++; + } + + *p = '\0'; + + if(cnt_p) + *cnt_p = excl_cnt; + + return buf; +} + +static int is_keyword(const CLIF_option *optn) { + unsigned int flags = optn->flags | curr.parse_flags; + + return (flags & _CLIF_STRICT_KEYWORD) != 0; +} + +static void err_bad_opt(const char *arg, char c, int n) { + char sym = (*arg == '+') ? '+' : '-'; + + if(c) + err_report("Bad option `%c%c' (argc %d)", sym, c, n); + else { + char *p = strchr(arg, '='); + const char *type = (*arg == sym) ? "option" : "keyword"; + + if(p) + err_report("Bad %s `%s' (with arg `%s') (argc %d)", + type, arg, p + 1, n); + else + err_report("Bad %s `%s' (argc %d)", type, arg, n); + } +} + +static void err_bad_arg(const CLIF_option *optn, char c, int n) { + CLIF_option tmp = *optn; + char ss[80]; + char *s; + + tmp.arg_name = NULL; + + if(c) { + s = show_short(&tmp); /* always without arg... */ + strncpy(ss, s, sizeof(ss)); + s = show_short(optn); + } else { + s = show_long(&tmp); /* always without arg... */ + strncpy(ss, s, sizeof(ss)); + s = show_long(optn); + } + + err_report("%s `%s' (argc %d) requires an argument: `%s'", + (c || !is_keyword(optn)) ? "Option" : "Keyword", ss, n, s); +} + +static void err_bad_res(const CLIF_option *optn, char c, + const char *opt_arg, int n) { + CLIF_option tmp = *optn; + char *ss; + const char *type; + + tmp.arg_name = NULL; + + if(c) { + ss = show_short(&tmp); + type = "option"; + } else { + ss = show_long(&tmp); + type = is_keyword(optn) ? "keyword" : "option"; + } + + if(optn->arg_name) + err_report("Cannot handle `%s' %s with arg `%s' (argc %d)", + ss, type, opt_arg, n); + else + err_report("Cannot handle `%s' %s (argc %d)", ss, type, n); +} + +static void err_bad_excl(const CLIF_option *optn, char c, int n) { + CLIF_option tmp = *optn; + char *ss; + char *excl = show_excl(curr.option_list, 0); + /* Note: show_(short|long)() nested!!! */ + + tmp.arg_name = NULL; + + if(c) + ss = show_short(&tmp); + else + ss = show_long(&tmp); + + err_report("%s `%s' (argc %d): Only one of:\n %s\n" + "may be specified.", + (c || !is_keyword(optn)) ? "Option" : "Keyword", + ss, n, excl); +} + +static CLIF_option *find_long(char *arg, char **arg_p, + unsigned int match, unsigned int nomatch) { + CLIF_option *optn; + CLIF_option *abbrev = NULL; + char *abbrev_arg = NULL; + int abbrev_found = 0; + + for(optn = curr.option_list; + optn->short_opt || optn->long_opt; + optn++ + ) { + char *a; + const char *o; + unsigned int flags; + + if(!optn->long_opt) + continue; + + flags = curr.parse_flags | optn->flags; + if(flags & nomatch) + continue; + if(match && !(flags & match)) + continue; /* XXX: optimize it */ + + for(a = arg, o = optn->long_opt; *o && *a == *o; a++, o++) + ; + + if(*a == '\0' || + (*a == '=' && optn->arg_name && !(flags & _CLIF_STRICT_NOEQUAL)) + ) { /* looks like end of option... */ + + if(!*o) { /* explicit match found */ + if(*a == '=' && arg_p) + *arg_p = a + 1; + return optn; + } + + if((flags & CLIF_ABBREV) && + (a - arg >= CLIF_MIN_ABBREV) + ) { + if(!abbrev_found) { + abbrev_found = 1; + abbrev = optn; + if(*a == '=') + abbrev_arg = a + 1; + } else + /* several possibility case... */ + abbrev = NULL; + } + } + } + + if(abbrev) { /* implicit match found */ + if(abbrev_arg && arg_p) + *arg_p = abbrev_arg; + return abbrev; + } else + /* no match found */ + return NULL; +} + +static int check_sym(const CLIF_option *optn, char sym) { + + if(sym == '+') { + if(!optn->function_plus) + return -1; + } + else if(sym == '-') { + if(!optn->function && optn->function_plus) + return -1; + } + + return 0; +} + +static int call_function(CLIF_option *optn, char *opt_arg, char sym) { + int (*function)(CLIF_option *, char *); + + function = (sym == '+') ? optn->function_plus : optn->function; + + if(!function) + return 0; + + if(opt_arg && ((optn->flags | curr.parse_flags) & CLIF_SEVERAL)) { + char tmp[80]; + char *t; + char *endt = tmp + sizeof(tmp); + + while(*opt_arg) { + + t = tmp; + while(t < endt && *opt_arg && + *opt_arg != ' ' && *opt_arg != '\t' && *opt_arg != ',' + ) + *t++ = *opt_arg++; + + if(t >= endt) + return -1; + + *t = '\0'; + + if(function(optn, tmp) < 0) + return -1; + + while(*opt_arg == ' ' || *opt_arg == '\t' || *opt_arg == ',') + opt_arg++; + } + + return 0; + } + + return function(optn, opt_arg); +} + +int CLIF_parse_cmdline (int argc, char *argv[], + CLIF_option *option_list, + CLIF_argument *argument_list, + unsigned int parse_flags){ +int i, j; +CLIF_option *optn; +CLIF_argument *argm; +int num_args = 0; +int num_argm = 0, strict_beg = 0, strict_end = 0; +_CLIF_index arg_n[MAX_ARGC_NUMBER]; +unsigned int dirty_flags = 0; +int dirty_plus = 0; +int exclusive_cnt = 0; +int posix = getenv ("POSIXLY_CORRECT") != NULL || +(parse_flags & CLIF_POSIX); + +curr.argc = argc; +curr.argv = argv; +curr.option_list = option_list; +curr.argument_list = argument_list; +curr.parse_flags = parse_flags; + +if (argc <= 1 && (parse_flags & CLIF_HELP_EMPTY)) { + CLIF_current_help (); + exit (0); +} + +/* Scan argument_list for check and some info. */ + +if (argument_list) { + enum stages {STRICT_BEG, OPTIONAL, STRICT_END}; + int stage = STRICT_BEG; + + for (argm = argument_list; argm->name; argm++) { + + if (argm->flags & CLIF_STRICT) { + + if (stage == STRICT_BEG) strict_beg++; + else if (stage == OPTIONAL) { + stage = STRICT_END; + strict_end++; + } + else if (stage == STRICT_END) + strict_end++; + } else { + if (stage == STRICT_BEG) stage = OPTIONAL; + else if (stage == STRICT_END) { + err_report ("Incorrect argument list set in program " + "source: more than one optional area."); + return -1; + } + } + + num_argm++; + } +} + +/* Scan option_list for some info. */ +if (option_list) { + + dirty_flags = parse_flags; + + for (optn = option_list; + optn->short_opt || optn->long_opt; + optn++ + ) { + dirty_flags |= optn->flags; + if (optn->function_plus) dirty_plus = 1; + } +} + +if (dirty_flags & CLIF_EXCL) +exclusive_cnt = 1; /* only one is allowed... */ + +/* Go ! Store arguments, parse options. */ + +for (i = 1; i < argc; i++) { + char *arg = argv[i]; + char *opt_arg = NULL; + char sym = '-'; + + if (!option_list) + goto handle_arg; + + if (*arg == '+' && dirty_plus) + sym = '+'; + + if (*arg != sym) { /* argument or keyword */ + + if (dirty_flags & CLIF_MAY_KEYWORD) { + optn = find_long (arg, &opt_arg, CLIF_MAY_KEYWORD, 0); + if (optn) goto long_found; + } + + if (num_args == 0 && (parse_flags & CLIF_FIRST_GROUP)) { + /* ugly... */ + parse_flags &= ~CLIF_FIRST_GROUP; + dirty_flags &= ~CLIF_FIRST_GROUP; /* to be correct */ + + goto handle_short; + } + + /* else it is an argument */ + goto handle_arg; + + } + else if (*++arg == sym) { /* `--' - long option */ + arg++; + + if (*arg == sym || /* `---' - let it be not option... */ + (parse_flags & (_CLIF_STRICT_KEYWORD|_CLIF_STRICT_ONEDASH)) + ) { + arg -= 2; + goto handle_arg; /* not option anyway */ + } + + optn = find_long (arg, &opt_arg, 0, + _CLIF_STRICT_KEYWORD | _CLIF_STRICT_ONEDASH); + if (optn) goto long_found; + + /* XXX: May be allow only for `--', not `++' too... */ + if (!*arg && sym == '-') { /* `--' and no empty longoption */ + option_list = NULL; /* POSIX way... */ + continue; + } + + /* XXX: or treat as an argument sometimes??? */ + err_bad_opt (argv[i], 0, i); + return -1; + } + else { /* short option, or several short options... */ + + if (dirty_flags & CLIF_MAY_ONEDASH) { + optn = find_long (arg, &opt_arg, CLIF_MAY_ONEDASH, 0); + if (optn) goto long_found; + } + + if (!*arg) { /* POSIX say: only "stdout specification"... */ + arg--; + goto handle_arg; + } + + goto handle_short; + } + + long_found: + if (check_sym (optn, sym) < 0) { /* Oops... */ + err_bad_opt (argv[i], 0, i); + return -1; + } + + if (optn->flags & CLIF_EXCL) { + if (!exclusive_cnt) { + err_bad_excl (optn, 0, i); + return -1; + } + exclusive_cnt--; + } + + if (optn->arg_name && !opt_arg) { + unsigned int flags = optn->flags | parse_flags; + + if (++i >= argc || + !(flags & CLIF_MAY_NOEQUAL) + ) { /* missing opt arg */ + i--; + + if (!(flags & CLIF_OPTARG)) { + err_bad_arg (optn, 0, i); + return -1; + } + + opt_arg = NULL; + } else + opt_arg = argv[i]; + + } + + if (call_function (optn, opt_arg, sym) < 0) { + err_bad_res (optn, 0, opt_arg, i); + return -1; + } + + if (optn->flags & CLIF_EXIT) + exit (0); + + continue; + + handle_arg: + if (argument_list) { + if (i < MAX_ARGC_NUMBER) /* XXX: ugly, better report */ + arg_n[num_args++] = i; + } else { + err_report ("`%s' (argc %d): arguments are not allowed", + argv[i], i); + return -1; + } + + /* POSIX say: No more options after args... */ + if (posix) option_list = NULL; /* geniously... */ + + continue; + + handle_short: + + opt_arg = NULL; + + do { + + for (optn = option_list; + optn->short_opt || optn->long_opt; + optn++ + ) { + if (optn->short_opt && optn->short_opt[0] == *arg) + break; + } + if (!optn->short_opt || + check_sym (optn, sym) < 0 + ) { + err_bad_opt (argv[i], *arg, i); + return -1; + } + + if (optn->flags & CLIF_EXCL) { + if (!exclusive_cnt) { + err_bad_excl (optn, *arg, i); + return -1; + } + exclusive_cnt--; + } + + if (optn->arg_name) { + unsigned int flags = parse_flags | optn->flags; + + if (arg[1] == '\0') { /* a last one */ + + /* POSIX say: an option with arg cannot be grouped. */ + if (posix && arg != argv[i] && arg[-1] != sym) { + err_bad_arg (optn, *arg, i); /* good way? */ + return -1; + } + + if (++i >= argc || + (flags & _CLIF_STRICT_JOIN_ARG) + ) { + i--; + + if (!(flags & CLIF_OPTARG)) { + err_bad_arg (optn, *arg, i); + return -1; + } + + opt_arg = NULL; + } else + opt_arg = argv[i]; + } + else if ((arg == argv[i] || arg[-1] == sym) && + (flags & CLIF_MAY_JOIN_ARG) + ) { + opt_arg = ++arg; + } + else { /* inside a group... */ + if (!(flags & CLIF_OPTARG) || + (flags & CLIF_MAY_JOIN_ARG) + ) { + err_bad_arg (optn, *arg, i); + return -1; + } + + opt_arg = NULL; + } + } + + if (call_function (optn, opt_arg, sym) < 0) { + err_bad_res (optn, optn->short_opt[0], opt_arg, i); + return -1; + } + + if (optn->flags & CLIF_EXIT) + exit (0); + + }while (!opt_arg && *++arg); + +} /* for ( ... ) */ + +if ((parse_flags & CLIF_STRICT_EXCL) && exclusive_cnt != 0) { + err_report ("One of these must be specified:\n %s\n", + show_excl (option_list, 0)); + return -1; +} + +/* Now, after *ALL* options, handle arguments, if any. */ + +if (num_args < strict_beg + strict_end) { + /* Missing some needed arguments. */ + + if (num_args < strict_beg) argm = argument_list + num_args; + else + argm = argument_list + + ((num_args - strict_beg) + (num_argm - strict_end)); + + if (num_args == strict_beg + strict_end - 1) + err_report ("Specify \"%s\" missing argument.", argm->name); + else + err_report ("Specify \"%s\" and other missing arguments.", + argm->name); + return -1; +} + +if (num_args > 0) { + _CLIF_index argm_index[MAX_ARGC_NUMBER]; + + /* assing argm (by index) for each arg... */ + + for (i = 0, j = 0; i < strict_beg; i++, j++) + argm_index[i] = j; + for (i = num_args - strict_end, j = num_argm - strict_end; + i < num_args; i++, j++ + ) argm_index[i] = j; + for (i = strict_beg, j = strict_beg; + i < num_args - strict_end && j < num_argm - strict_end; + i++ + ) { + argm_index[i] = j; + if (!(argument_list[j].flags & CLIF_MORE)) + j++; + } + + if (i < num_args - strict_end) { /* there are extra args... */ + err_report ("Extra arg `%s' (position %d, argc %d)", + argv[arg_n[i]], i + 1, arg_n[i]); + return -1; + } + + if (j < num_argm - strict_end && + !(argument_list[j].flags & CLIF_MORE) && + /* ...i.e, there are some missing optional args... */ + (argument_list[j].flags & CLIF_ACC_PREV) + ) { + if (j == 0) + err_report ("Incorrect argument list set: first arg " + "cannot be `accompanied with previous'."); + else + err_report ("Arg \"%s\" must be specified because " + "\"%s\" `%s' is used.", argument_list[j].name, + argument_list[j - 1].name, argv[arg_n[i - 1]]); + return -1; + } + + if (argm_index[--i] == j && + /* above is true only after OPTIONAL area scan + and when `j' is stopped on CLIF_MORE */ + ++j < num_argm - strict_end + /* i.e: there is a *last* one (after CLIF_MORE) + in the OPTIONAL area */ + ) argm_index[i] = j; /* *last* is better than *more* */ + + /* ...and work now */ + + for (i = 0; i < num_args; i++) { + argm = argument_list + argm_index[i]; + + if (argm->function && + argm->function (argm, argv[arg_n[i]], i) < 0 + ) { + err_report ("Cannot handle \"%s\" cmdline arg `%s' " + "on position %d (argc %d)", + argm->name, argv[arg_n[i]], i + 1, arg_n[i]); + return -1; + } + } + + /* That`s all. */ +} + +return 0; +} + +static void box_output(int start, int left, int width, const char *str, + const char *arg_name) { + char *p, *endp, *s; + int l; + char buf[1024]; + char spacer[128]; /* assume it is enough */ + + if(left > (int) sizeof(spacer) - 2) + left = (int) sizeof(spacer) - 2; + if(width > (int) sizeof(buf) - 1) + width = (int) sizeof(buf) - 1; + + spacer[0] = '\n'; + memset(spacer + 1, ' ', left); + spacer[left + 1] = '\0'; + + l = left - start; + if(l > 0) { + memset(buf, ' ', l); + buf[l] = '\0'; + fprintf(stderr, "%s", buf); + } else + fprintf(stderr, "%s", spacer); + + endp = buf + width; + + p = buf; + + while(*str) { + + while(*str && p < endp) { + + if(*str == '%' && arg_name) { + if(str[1] == '%') { + *p++ = '%'; + str += 2; + continue; + } + else if(str[1] == 's') { + const char *a = arg_name; + + while(*a && p < endp) + *p++ = *a++; + str += 2; + continue; + } + } + + *p++ = *str++; + } + + *p = '\0'; + + if(p < endp) + break; + + while(p > buf && *p != ' ' && *p != '\t') + p--; + if(p <= buf) + return; /* foo on you */ + + *p = '\0'; + fprintf(stderr, "%s", buf); + fprintf(stderr, "%s", spacer); + + p++; + for(s = buf; *p; *s++ = *p++) + ; + *s = '\0'; + p = s; + } + + fprintf(stderr, "%s", buf); + + return; +} + +#define SHORT_LONG_DLM " " +#define OPT_START_DLM " " +#define OPT_FIELD_WIDTH 30 + +#define ARG_MARK_STRICT "+ " +#define ARG_MARK_GROUP0 " . " +#define ARG_MARK_GROUP " ' " +#define ARG_MARK_OPT " " +#define ARG_FIELD_WIDTH 20 + +#define SCREEN_WIDTH 80 + +void CLIF_print_options(const char *header, + const CLIF_option *option_list) { + const CLIF_option *optn; + char *excl; + int excl_cnt = 0; + + /* Print a header string, if present... */ + if(header) + fprintf(stderr, "%s\n", header); + + if(!option_list) + return; + + for(optn = option_list; optn->short_opt || optn->long_opt; optn++) { + int len; + + /* generate and print an option usage */ + + if(optn->short_opt) { + if(optn->long_opt) + len = fprintf(stderr, OPT_START_DLM "%s" + SHORT_LONG_DLM "%s", + show_short(optn), show_long(optn)); + else + len = fprintf(stderr, OPT_START_DLM "%s", + show_short(optn)); + } else + len = fprintf(stderr, OPT_START_DLM "%s", show_long(optn)); + + /* print a help string, if present */ + + if(optn->help_string) + box_output(len, OPT_FIELD_WIDTH, + SCREEN_WIDTH - OPT_FIELD_WIDTH, + optn->help_string, optn->arg_name); + + fprintf(stderr, "\n"); /* a last one */ + } + + excl = show_excl(option_list, &excl_cnt); + if(excl_cnt > 0) { + + if(excl_cnt == 1) { + if((curr.parse_flags & CLIF_STRICT_EXCL) && + curr.option_list == option_list + ) + fprintf(stderr, "Anyway `%s' must be specified.\n", excl); + //else /* simple ordinary option, because excl_cnt == 1 ... */ + } else + fprintf(stderr, "Only one of these may be specified:\n" + " %s\n", excl); + } + + return; +} + +void CLIF_print_arguments(const char *header, + const CLIF_argument *argument_list) { + const CLIF_argument *argm; + + if(!argument_list) + return; + + /* Print a header string, if present... */ + if(header) + fprintf(stderr, "%s\n", header); + + for(argm = argument_list; argm->name; argm++) { + int len; + + if(argm->flags & CLIF_STRICT) + len = fprintf(stderr, ARG_MARK_STRICT "%s", argm->name); + else if(argm->flags & CLIF_MORE) + len = fprintf(stderr, ARG_MARK_OPT "%s ...", argm->name); + else if(argm->flags & CLIF_ACC_PREV) + len = fprintf(stderr, ARG_MARK_GROUP "%s", argm->name); + else if((argm + 1)->name && ((argm + 1)->flags & CLIF_ACC_PREV)) + len = fprintf(stderr, ARG_MARK_GROUP0 "%s", argm->name); + else + len = fprintf(stderr, ARG_MARK_OPT "%s", argm->name); + + if(argm->help_string) + box_output(len, ARG_FIELD_WIDTH, + SCREEN_WIDTH - ARG_FIELD_WIDTH, + argm->help_string, argm->name); + + fprintf(stderr, "\n"); + } + + return; +} + +void CLIF_print_usage(const char *header, const char *progname, + const CLIF_option *option_list, + const CLIF_argument *argument_list) { + + if(!progname && curr.argv) + progname = curr.argv[0]; + + if(!header) { + if(progname) + fprintf(stderr, "Usage: %s", progname); + else + fprintf(stderr, "Command line options:"); + } else { + if(progname) + fprintf(stderr, "%s\n" OPT_START_DLM "%s", header, progname); + else + fprintf(stderr, "%s", header); + } + + if(option_list) { + const CLIF_option *optn; + char m_buf[256], p_buf[256], mp_buf[256]; + char *m = m_buf, *p = p_buf, *mp = mp_buf; + char *end_m = m_buf + sizeof(m_buf) - 1; + char *end_p = p_buf + sizeof(p_buf) - 1; + char *end_mp = mp_buf + sizeof(mp_buf) - 1; + char *excl; + int excl_cnt = 0; + + /* first, show exclusive option list, if any... */ + + excl = show_excl(option_list, &excl_cnt); + if(excl_cnt > 0) { + if((curr.parse_flags & CLIF_STRICT_EXCL) && + curr.option_list == option_list + ) { + if(excl_cnt == 1) + fprintf(stderr, " %s", excl); + else + fprintf(stderr, " { %s }", excl); + } else + fprintf(stderr, " [ %s ]", excl); + } + + /* second, find short options without arguments... */ + + for(optn = option_list; + optn->short_opt || optn->long_opt; + optn++ + ) { + /* We don`t exclude CLIF_EXTRA hear: + simple one char don`t eat a lot of space... + */ + + if(!optn->short_opt || + optn->arg_name || + (optn->flags & CLIF_EXCL) + ) + continue; + + if(optn->function_plus) { + if(optn->function) { + if(mp < end_mp) + *mp++ = optn->short_opt[0]; + } else { + if(p < end_p) + *p++ = optn->short_opt[0]; + } + } else { + if(m < end_m) + *m++ = optn->short_opt[0]; + } + } + + if(m > (char *) m_buf) { + *m = '\0'; + fprintf(stderr, " [ -%s ]", m_buf); + } + if(p > (char *) p_buf) { + *p = '\0'; + fprintf(stderr, " [ +%s ]", p_buf); + } + if(mp > (char *) mp_buf) { + *mp = '\0'; + fprintf(stderr, " [ " SHORT_PLUS_MINUS "%s ]", mp_buf); + } + + /* third, print all another... */ + + for(optn = option_list; + optn->short_opt || optn->long_opt; + optn++ + ) { + if(optn->flags & CLIF_EXTRA) + continue; + + if(optn->flags & CLIF_EXCL) + continue; /* already handled */ + + if(optn->short_opt) { + if(optn->arg_name) + fprintf(stderr, " [ %s ]", show_short(optn)); + //else + /* already handled */ + } else + fprintf(stderr, " [ %s ]", show_long(optn)); + } + } + + if(argument_list) { + const CLIF_argument *argm; + int deep = 0; + + for(argm = argument_list; argm->name; argm++) { + + if(argm->flags & CLIF_STRICT) { + if(deep > 0) { + fputc(' ', stderr); + while(deep--) + fputc(']', stderr); + deep = 0; + } + + fprintf(stderr, " %s", argm->name); + } else { + if(argm->flags & CLIF_MORE) + fprintf(stderr, " [ %s ...", argm->name); + else if(argm->flags & CLIF_ACC_PREV) { + fprintf(stderr, " %s", argm->name); + --deep; /* ugly, but easy */ + } else + fprintf(stderr, " [ %s", argm->name); + + deep++; + } + } + + if(deep > 0) { + fputc(' ', stderr); + while(deep--) + fputc(']', stderr); + } + } + + fprintf(stderr, "\n"); +} + +int CLIF_current_help(void) { + + if(!curr.argc) + return -1; /* i.e., not inited... */ + + CLIF_print_usage("Usage:", curr.argv[0], curr.option_list, + curr.argument_list); + + if(curr.option_list) + CLIF_print_options("Options:", curr.option_list); + + if(curr.argument_list) + CLIF_print_arguments("\nArguments:", curr.argument_list); + + return 0; +} + +/* Common useful option handlers. */ + +int CLIF_version_handler(CLIF_option *optn, char *arg) { + UNUSED(arg); + if(!optn->data) + return -1; + + fprintf(stderr, "%s\n", ((char *) optn->data)); + + return 0; /* be happy */ +} + +int CLIF_set_flag(CLIF_option *optn, char *arg) { + UNUSED(arg); + if(!optn->data) + return -1; + + *((int *) optn->data) = 1; + + return 0; +} + +int CLIF_unset_flag(CLIF_option *optn, char *arg) { + UNUSED(arg); + if(!optn->data) + return -1; + + *((int *) optn->data) = 0; + + return 0; +} + +static int set_string(char **data, char *arg) { + + if(!data) + return -1; + + *data = arg; + + return 0; +} + +int CLIF_set_string(CLIF_option *optn, char *arg) { + + return set_string(optn->data, arg); +} + +int CLIF_arg_string(CLIF_argument *argm, char *arg, int index) { + UNUSED(index); + return set_string(argm->data, arg); +} + +static int set_int(int *data, char *arg) { + char *q; + + if(!data) + return -1; + + *data = (int) strtol(arg, &q, 0); + + return (q == arg || *q) ? -1 : 0; +} + +static int set_uint(unsigned int *data, char *arg) { + char *q; + + if(!data) + return -1; + + *data = (unsigned int) strtoul(arg, &q, 0); + + return (q == arg || *q) ? -1 : 0; +} + +static int set_double(double *data, char *arg) { + char *q; + + if(!data) + return -1; + + *data = strtod(arg, &q); + + return (q == arg || *q) ? -1 : 0; +} + +int CLIF_set_int(CLIF_option *optn, char *arg) { + + return set_int(optn->data, arg); +} + +int CLIF_set_uint(CLIF_option *optn, char *arg) { + + return set_uint(optn->data, arg); +} + +int CLIF_set_double(CLIF_option *optn, char *arg) { + + return set_double(optn->data, arg); +} + +int CLIF_arg_int(CLIF_argument *argm, char *arg, int index) { + UNUSED(index); + return set_int(argm->data, arg); +} + +int CLIF_arg_uint(CLIF_argument *argm, char *arg, int index) { + UNUSED(index); + return set_uint(argm->data, arg); +} + +int CLIF_arg_double(CLIF_argument *argm, char *arg, int index) { + UNUSED(index); + return set_double(argm->data, arg); +} + +int CLIF_call_func(CLIF_option *optn, char *arg) { + + if(!optn->data) + return -1; + + if(optn->arg_name) { + int (*func)(char *) = optn->data; + + return func(arg); + } else { + int (*func)(void) = optn->data; + + return func(); + } +} + +int CLIF_arg_func(CLIF_argument *argm, char *arg, int index) { + int (*func)(char *, int); + + if(!argm->data) + return -1; + + func = (int (*)(char *, int)) argm->data; + + return func(arg, index); +} + diff --git a/modules/net/iputils/traceroute/clif.h b/modules/net/iputils/traceroute/clif.h new file mode 100644 index 0000000000000000000000000000000000000000..c798a8df8fbfee7b7450b6e6ec0a46c08443c66f --- /dev/null +++ b/modules/net/iputils/traceroute/clif.h @@ -0,0 +1,121 @@ +/* + Copyright (c) 2000, 2003 Dmitry Butskoy + <buc@citadel.stu.neva.ru> + License: LGPL v2.1 or any later + + See COPYING.LIB for the status of this software. +*/ + +#ifndef _CLIF_H +#define _CLIF_H + + +typedef struct CLIF_option_struct CLIF_option; +struct CLIF_option_struct { + const char *short_opt; + const char *long_opt; + const char *arg_name; + const char *help_string; + int (*function) (CLIF_option *optn, char *arg); + void *data; + int (*function_plus) (CLIF_option *optn, char *arg); + unsigned int flags; +}; +#define CLIF_END_OPTION { 0, 0, 0, 0, 0, 0, 0, 0 } + +typedef struct CLIF_argument_struct CLIF_argument; +struct CLIF_argument_struct { + const char *name; + const char *help_string; + int (*function) (CLIF_argument *argm, char *arg, int index); + void *data; + unsigned int flags; +}; +#define CLIF_END_ARGUMENT { 0, 0, 0, 0, 0 } + +/* Argument flag bits. */ +#define CLIF_MORE (0x01) /* null or several */ +#define CLIF_STRICT (0x02) /* arg must be present */ +#define CLIF_ACC_PREV (0x04) /* arg must be accompanied with previous */ + + +/* Option flag bits. */ + +/* affected only by per-option flags */ +#define CLIF_EXTRA (0x0001) /* don`t show in usage line */ +#define CLIF_EXIT (0x0002) /* exit after handler return */ +#define CLIF_EXCL (0x0004) /* at exclusive area */ + +/* affected by per-option flags and by common `parse_flags' argument + of CLIF_parse_cmdline(). In last case appropriate bits are translated + for all the options. +*/ +#define CLIF_MAY_JOIN_ARG (0x0010) +#define _CLIF_STRICT_JOIN_ARG (0x0020) +#define CLIF_JOIN_ARG (CLIF_MAY_JOIN_ARG|_CLIF_STRICT_JOIN_ARG) +#define CLIF_MAY_NOEQUAL (0x0040) +#define _CLIF_STRICT_NOEQUAL (0x0080) +#define CLIF_NOEQUAL (CLIF_MAY_NOEQUAL|_CLIF_STRICT_NOEQUAL) +#define CLIF_MAY_KEYWORD (0x0100) +#define _CLIF_STRICT_KEYWORD (0x0200) +#define CLIF_KEYWORD (CLIF_MAY_KEYWORD|_CLIF_STRICT_KEYWORD) +#define CLIF_MAY_ONEDASH (0x0400) +#define _CLIF_STRICT_ONEDASH (0x0800) +#define CLIF_ONEDASH (CLIF_MAY_ONEDASH|_CLIF_STRICT_ONEDASH) +#define CLIF_OPTARG (0x1000) /* allow missing optarg */ +#define CLIF_ABBREV (0x2000) /* allow long opt abbreviation */ +#define CLIF_SEVERAL (0x4000) /* several args in one opt`s arg */ + +/* affected only by common `parse_flags' arg of CLIF_parse_cmdline() . */ +#define CLIF_HELP_EMPTY (0x10000) /* print help on empty cmdline */ +#define CLIF_POSIX (0x20000) /* follow POSIX standard */ +#define CLIF_FIRST_GROUP (0x40000) /* first arg - options` group */ +#define CLIF_STRICT_EXCL (0x80000) /* at least one exclusive */ +#define CLIF_SILENT (0x100000) /* no errors on stderr */ + +#define CLIF_MIN_ABBREV 2 /* a minimal match length in abbrev */ + + +extern int CLIF_parse (int argc, char **argv, CLIF_option *option_list, + CLIF_argument *arg_list, unsigned int parse_flags); +/* history compatibility... */ +#define CLIF_parse_cmdline(ARGC,ARGV,OPTN,ARGS,FLAGS) \ + CLIF_parse (ARGC, ARGV, OPTN, ARGS, FLAGS) + +extern void CLIF_print_options (const char *header, + const CLIF_option *option_list); +extern void CLIF_print_arguments (const char *header, + const CLIF_argument *argument_list); +extern void CLIF_print_usage (const char *header, const char *progname, + const CLIF_option *option_list, + const CLIF_argument *argument_list); + +extern int CLIF_current_help (void); + +/* Common useful option handlers. */ +extern int CLIF_version_handler (CLIF_option *optn, char *arg); +extern int CLIF_set_flag (CLIF_option *optn, char *arg); +extern int CLIF_unset_flag (CLIF_option *optn, char *arg); +extern int CLIF_set_string (CLIF_option *optn, char *arg); +extern int CLIF_set_int (CLIF_option *optn, char *arg); +extern int CLIF_set_uint (CLIF_option *optn, char *arg); +extern int CLIF_set_double (CLIF_option *optn, char *arg); +extern int CLIF_call_func (CLIF_option *optn, char *arg); + +extern int CLIF_arg_string (CLIF_argument *argm, char *arg, int index); +extern int CLIF_arg_int (CLIF_argument *argm, char *arg, int index); +extern int CLIF_arg_uint (CLIF_argument *argm, char *arg, int index); +extern int CLIF_arg_double (CLIF_argument *argm, char *arg, int index); +extern int CLIF_arg_func (CLIF_argument *argm, char *arg, int index); + + +/* Some useful macros. */ + +#define CLIF_HELP_OPTION \ + { 0, "help", 0, "Read this help and exit", \ + CLIF_call_func, CLIF_current_help, 0, CLIF_EXTRA | CLIF_EXIT } +#define CLIF_VERSION_OPTION(STR) \ + { "V", "version", 0, "Print version info and exit", \ + CLIF_version_handler, STR, 0, CLIF_EXTRA | CLIF_EXIT } + +#endif /* _CLIF_H */ diff --git a/modules/net/iputils/traceroute/csum.c b/modules/net/iputils/traceroute/csum.c new file mode 100644 index 0000000000000000000000000000000000000000..ea3a50da0430d19582941d72cded69fb09e45127 --- /dev/null +++ b/modules/net/iputils/traceroute/csum.c @@ -0,0 +1,34 @@ +/* + Copyright (c) 2006, 2007 Dmitry Butskoy + <buc@citadel.stu.neva.ru> + License: GPL v2 or any later + + See COPYING for the status of this software. +*/ + +#include <stdlib.h> +#include <unistd.h> + +#include "traceroute.h" + + +uint16_t in_csum (const void *ptr, size_t len) { + const uint16_t *p = (const uint16_t *) ptr; + size_t nw = len / 2; + unsigned int sum = 0; + uint16_t res; + + while (nw--) sum += *p++; + + if (len & 0x1) + sum += htons (*((unsigned char *) p) << 8); + + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + + res = ~sum; + if (!res) res = ~0; + + return res; +} + diff --git a/modules/net/iputils/traceroute/extension.c b/modules/net/iputils/traceroute/extension.c new file mode 100644 index 0000000000000000000000000000000000000000..515a8dbed7da85addd25543a3bbcfd303944f667 --- /dev/null +++ b/modules/net/iputils/traceroute/extension.c @@ -0,0 +1,132 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "traceroute.h" + + +struct icmp_ext_header { +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned int version:4; + unsigned int reserved:4; +#else + unsigned int reserved:4; + unsigned int version:4; +#endif + uint8_t reserved1; + uint16_t checksum; +} __attribute__ ((packed)); + + +struct icmp_ext_object { + uint16_t length; + uint8_t class; + uint8_t c_type; + uint8_t data[0]; +}; + +#define MPLS_CLASS 1 +#define MPLS_C_TYPE 1 + + +#define do_snprintf(CURR, END, FMT, ARGS...) \ + do { \ + CURR += snprintf (CURR, END - CURR, (FMT), ## ARGS);\ + if (CURR > END) CURR = END; \ + } while (0) + + +static int try_extension (probe *pb, char *buf, size_t len) { + struct icmp_ext_header *iext = (struct icmp_ext_header *) buf; + char str[1024]; + char *curr = str; + char *end = str + sizeof (str) / sizeof (*str); + + + /* a check for len >= 8 already done for all cases */ + + if (iext->version != 2) return -1; + + if (iext->checksum && + in_csum (iext, len) != (uint16_t) ~0 + ) return -1; + + buf += sizeof (*iext); + len -= sizeof (*iext); + + + while (len >= sizeof (struct icmp_ext_object)) { + struct icmp_ext_object *obj = (struct icmp_ext_object *) buf; + size_t objlen = ntohs (obj->length); + size_t data_len; + uint32_t *ui = (uint32_t *) obj->data; + int i, n; + + if (objlen < sizeof (*obj) || + objlen > len + ) return -1; + + data_len = objlen - sizeof (*obj); + if (data_len % sizeof (uint32_t)) + return -1; /* must be 32bit rounded... */ + + n = data_len / sizeof (*ui); + + + if (curr > (char *) str && curr < end) + *curr++ = ';'; /* a separator */ + + if (obj->class == MPLS_CLASS && + obj->c_type == MPLS_C_TYPE && + n >= 1 + ) { /* people prefer MPLS to be parsed... */ + + do_snprintf (curr, end, "MPLS:"); + + for (i = 0; i < n; i++, ui++) { + uint32_t mpls = ntohl (*ui); + + do_snprintf (curr, end, "%sL=%u,E=%u,S=%u,T=%u", + i ? "/" : "", + mpls >> 12, + (mpls >> 9) & 0x7, + (mpls >> 8) & 0x1, + mpls & 0xff); + } + + } + else { /* common case... */ + + do_snprintf (curr, end, "%u/%u:", obj->class, obj->c_type); + + for (i = 0; i < n && curr < end; i++, ui++) + do_snprintf (curr, end, "%s%08x", i ? "," : "", ntohl(*ui)); + } + + buf += objlen; + len -= objlen; + } + + if (len) return -1; + + + pb->ext = strdup (str); + + return 0; +} + + +void handle_extensions (probe *pb, char *buf, int len, int step) { + + if (!step) + try_extension (pb, buf, len); + else { + for ( ; len >= 8; buf += step, len -= step) + if (try_extension (pb, buf, len) == 0) + break; + } + + return; +} + diff --git a/modules/net/iputils/traceroute/flowlabel.h b/modules/net/iputils/traceroute/flowlabel.h new file mode 100755 index 0000000000000000000000000000000000000000..e6241c4f8e9cdd00558ffd3494cfe1b5d40a1c80 --- /dev/null +++ b/modules/net/iputils/traceroute/flowlabel.h @@ -0,0 +1,40 @@ +/* + It is just a stripped copy of the kernel header "linux/in6.h" + + "Flow label" things are still not defined in "netinet/in*.h" headers, + but we cannot use "linux/in6.h" immediately because it currently + conflicts with "netinet/in.h" . +*/ + +struct in6_flowlabel_req_ +{ + struct in6_addr flr_dst; + __u32 flr_label; + __u8 flr_action; + __u8 flr_share; + __u16 flr_flags; + __u16 flr_expires; + __u16 flr_linger; + __u32 __flr_pad; + /* Options in format of IPV6_PKTOPTIONS */ +}; + +#define IPV6_FL_A_GET 0 +#define IPV6_FL_A_PUT 1 +#define IPV6_FL_A_RENEW 2 + +#define IPV6_FL_F_CREATE 1 +#define IPV6_FL_F_EXCL 2 + +#define IPV6_FL_S_NONE 0 +#define IPV6_FL_S_EXCL 1 +#define IPV6_FL_S_PROCESS 2 +#define IPV6_FL_S_USER 3 +#define IPV6_FL_S_ANY 255 + +#define IPV6_FLOWINFO_FLOWLABEL 0x000fffff +#define IPV6_FLOWINFO_PRIORITY 0x0ff00000 + +#define IPV6_FLOWLABEL_MGR 32 +#define IPV6_FLOWINFO_SEND 33 + diff --git a/modules/net/iputils/traceroute/mod-dccp.c b/modules/net/iputils/traceroute/mod-dccp.c new file mode 100644 index 0000000000000000000000000000000000000000..26f2c653bf0fd3af1faeb911cd943e493edd93e9 --- /dev/null +++ b/modules/net/iputils/traceroute/mod-dccp.c @@ -0,0 +1,295 @@ +/* + Copyright (c) 2012 Samuel Jero <sj323707@ohio.edu> + License: GPL v2 or any later + + See COPYING for the status of this software. +*/ + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/socket.h> +#include <poll.h> +#include <netinet/ip.h> +#include <netinet/ip6.h> +#include <linux/dccp.h> + + +#include "traceroute.h" + + +#define DEF_SERVICE_CODE 1885957735 + +#define DCCP_HEADER_LEN (sizeof (struct dccp_hdr) + \ + sizeof (struct dccp_hdr_ext) \ + + sizeof (struct dccp_hdr_request)) + +static sockaddr_any dest_addr = {{ 0, }, }; +static unsigned int dest_port = 0; + +static int raw_sk = -1; +static int last_ttl = 0; + +static uint8_t buf[1024]; /* enough, enough... */ +static size_t csum_len = 0; +static struct dccp_hdr *dh = NULL; +static struct dccp_hdr_ext *dhe = NULL; +static struct dccp_hdr_request *dhr = NULL; +static unsigned int service_code = DEF_SERVICE_CODE; + + +static CLIF_option dccp_options[] = { + { 0, "service", "NUM", "Set DCCP service code to %s (default is " + _TEXT (DEF_SERVICE_CODE) ")", + CLIF_set_uint, &service_code, 0, CLIF_ABBREV }, + CLIF_END_OPTION +}; + + +static int dccp_init (const sockaddr_any *dest, + unsigned int port_seq, size_t *packet_len_p) { + int af = dest->sa.sa_family; + sockaddr_any src; + socklen_t len; + uint8_t *ptr; + uint16_t *lenp; + + + dest_addr = *dest; + dest_addr.sin.sin_port = 0; /* raw sockets can be confused */ + + if (!port_seq) port_seq = DEF_DCCP_PORT; + dest_port = htons (port_seq); + + + /* Create raw socket for DCCP */ + raw_sk = socket (af, SOCK_RAW, IPPROTO_DCCP); + if (raw_sk < 0) + error_or_perm ("socket"); + + tune_socket (raw_sk); /* including bind, if any */ + + if (connect (raw_sk, &dest_addr.sa, sizeof (dest_addr)) < 0) + error ("connect"); + + len = sizeof (src); + if (getsockname (raw_sk, &src.sa, &len) < 0) + error ("getsockname"); + + + if (!raw_can_connect ()) { /* work-around for buggy kernels */ + close (raw_sk); + raw_sk = socket (af, SOCK_RAW, IPPROTO_DCCP); + if (raw_sk < 0) error ("socket"); + tune_socket (raw_sk); + /* but do not connect it... */ + } + + + use_recverr (raw_sk); + + add_poll (raw_sk, POLLIN | POLLERR); + + + /* Now create the sample packet. */ + + /* For easy checksum computing: + saddr + daddr + length + protocol + dccphdr + */ + + ptr = buf; + + if (af == AF_INET) { + len = sizeof (src.sin.sin_addr); + memcpy (ptr, &src.sin.sin_addr, len); + ptr += len; + memcpy (ptr, &dest_addr.sin.sin_addr, len); + ptr += len; + } else { + len = sizeof (src.sin6.sin6_addr); + memcpy (ptr, &src.sin6.sin6_addr, len); + ptr += len; + memcpy (ptr, &dest_addr.sin6.sin6_addr, len); + ptr += len; + } + + lenp = (uint16_t *) ptr; + ptr += sizeof (uint16_t); + *((uint16_t *) ptr) = htons ((uint16_t) IPPROTO_DCCP); + ptr += sizeof (uint16_t); + + + /* Construct DCCP header */ + dh = (struct dccp_hdr *) ptr; + + dh->dccph_ccval = 0; + dh->dccph_checksum = 0; + dh->dccph_cscov = 0; + dh->dccph_dport = dest_port; + dh->dccph_reserved = 0; + dh->dccph_sport = 0; /* temporary */ + dh->dccph_x = 1; + dh->dccph_type = DCCP_PKT_REQUEST; + dh->dccph_seq2 = 0; /* reserved if using 48 bit sequence numbers */ + /* high 16 bits of sequence number. Always make 0 for simplicity. */ + dh->dccph_seq = 0; + ptr += sizeof (struct dccp_hdr); + + dhe = (struct dccp_hdr_ext *) ptr; + dhe->dccph_seq_low = 0; /* temporary */ + ptr += sizeof (struct dccp_hdr_ext); + + dhr = (struct dccp_hdr_request *) ptr; + dhr->dccph_req_service = htonl (service_code); + ptr += sizeof (struct dccp_hdr_request); + + + csum_len = ptr - buf; + + if (csum_len > sizeof (buf)) + error ("impossible"); /* paranoia */ + + len = ptr - (uint8_t *) dh; + if (len & 0x03) error ("impossible"); /* as >>2 ... */ + + *lenp = htons (len); + dh->dccph_doff = len >> 2; + + + *packet_len_p = len; + + return 0; +} + + +static void dccp_send_probe (probe *pb, int ttl) { + int sk; + int af = dest_addr.sa.sa_family; + sockaddr_any addr; + socklen_t len = sizeof (addr); + + + /* To make sure we have chosen a free unused "source port", + just create, (auto)bind and hold a socket while the port is needed. + */ + + sk = socket (af, SOCK_DCCP, IPPROTO_DCCP); + if (sk < 0) error ("socket"); + + bind_socket (sk); + + if (getsockname (sk, &addr.sa, &len) < 0) + error ("getsockname"); + + /* When we reach the target host, it can send us either Reset or Response. + For Reset all is OK (we and kernel just answer nothing), but + for Response we should reply with our Close. + It is well-known "half-open technique", used by port scanners etc. + This way we do not touch remote applications at all, unlike + the ordinary connect(2) call. + As the port-holding socket neither connect() nor listen(), + it means "no such port yet" for remote ends, and kernel always + send Reset in such a situation automatically (we have to do nothing). + */ + + + dh->dccph_sport = addr.sin.sin_port; + + dhe->dccph_seq_low = random_seq (); + + dh->dccph_checksum = 0; + dh->dccph_checksum = in_csum (buf, csum_len); + + + if (ttl != last_ttl) { + set_ttl (raw_sk, ttl); + last_ttl = ttl; + } + + + pb->send_time = get_time (); + + if (do_send (raw_sk, dh, dh->dccph_doff << 2, &dest_addr) < 0) { + close (sk); + pb->send_time = 0; + return; + } + + + pb->seq = dh->dccph_sport; + + pb->sk = sk; + + return; +} + + +static probe *dccp_check_reply (int sk, int err, sockaddr_any *from, + char *buf, size_t len) { + UNUSED(sk); + probe *pb; + struct dccp_hdr *ndh = (struct dccp_hdr *) buf; + uint16_t sport, dport; + + + if (len < 8) return NULL; /* too short */ + + + if (err) { + sport = ndh->dccph_sport; + dport = ndh->dccph_dport; + } else { + sport = ndh->dccph_dport; + dport = ndh->dccph_sport; + } + + + if (dport != dest_port) + return NULL; + + if (!equal_addr (&dest_addr, from)) + return NULL; + + pb = probe_by_seq (sport); + if (!pb) return NULL; + + if (!err) pb->final = 1; + + return pb; +} + + +static void dccp_recv_probe (int sk, int revents) { + + if (!(revents & (POLLIN | POLLERR))) + return; + + recv_reply (sk, !!(revents & POLLERR), dccp_check_reply); +} + + +static void dccp_expire_probe (probe *pb) { + + probe_done (pb); +} + + +static tr_module dccp_ops = { + .name = "dccp", + .init = dccp_init, + .send_probe = dccp_send_probe, + .recv_probe = dccp_recv_probe, + .expire_probe = dccp_expire_probe, + .options = dccp_options, +}; + +TR_MODULE (dccp_ops); + +void tr_module_dccp_insert() +{ + +} diff --git a/modules/net/iputils/traceroute/mod-icmp.c b/modules/net/iputils/traceroute/mod-icmp.c new file mode 100644 index 0000000000000000000000000000000000000000..e2194d9aa4563b22b48d66f324de9f8cedf61b00 --- /dev/null +++ b/modules/net/iputils/traceroute/mod-icmp.c @@ -0,0 +1,240 @@ +/* + Copyright (c) 2006, 2007 Dmitry Butskoy + <buc@citadel.stu.neva.ru> + License: GPL v2 or any later + + See COPYING for the status of this software. + */ + +#include <stdlib.h> +#include <unistd.h> +#include <sys/socket.h> +#include <poll.h> +#include <netinet/icmp6.h> +#include <netinet/ip_icmp.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/ip6.h> + +#include "traceroute.h" + +static sockaddr_any dest_addr = { { 0, }, }; +static uint16_t seq = 1; +static uint16_t ident = 0; + +static char *data; +static size_t *length_p; + +static int icmp_sk = -1; +static int last_ttl = 0; + +static int raw = 0; +static int dgram = 0; + +static CLIF_option icmp_options[] = { + { 0, "raw", 0, "Use raw sockets way only. Default is try this way " + "first (probably not allowed for unprivileged users), " + "then try dgram", + CLIF_set_flag, &raw, 0, CLIF_EXCL }, + { 0, "dgram", 0, "Use dgram sockets way only. May be not implemented " + "by old kernels or restricted by sysadmins", + CLIF_set_flag, &dgram, 0, CLIF_EXCL }, + CLIF_END_OPTION + }; + +static int icmp_init(const sockaddr_any *dest, + unsigned int port_seq, size_t *packet_len_p) { + int i; + int af = dest->sa.sa_family; + int protocol; + + dest_addr = *dest; + dest_addr.sin.sin_port = 0; + + if(port_seq) + seq = port_seq; + + length_p = packet_len_p; + if(*length_p < sizeof(struct icmphdr)) + *length_p = sizeof(struct icmphdr); + + data = malloc(*length_p); + if(!data) + error("malloc"); + + for(i = (int) sizeof(struct icmphdr); i < (int)*length_p; i++) + data[i] = 0x40 + (i & 0x3f); + + protocol = (af == AF_INET) ? IPPROTO_ICMP : IPPROTO_ICMPV6; + + if(!raw) { + icmp_sk = socket(af, SOCK_DGRAM, protocol); + if(icmp_sk < 0 && dgram) + error("socket"); + } + + if(!dgram) { + int raw_sk = socket(af, SOCK_RAW, protocol); + if(raw_sk < 0) { + if(raw || icmp_sk < 0) + error_or_perm("socket"); + dgram = 1; + } else { + /* prefer the traditional "raw" way when possible */ + close(icmp_sk); + icmp_sk = raw_sk; + } + } + + tune_socket(icmp_sk); + + /* Don't want to catch packets from another hosts */ + if(raw_can_connect() && + connect(icmp_sk, &dest_addr.sa, sizeof(dest_addr)) < 0 + ) + error("connect"); + + use_recverr(icmp_sk); + + if(dgram) { + sockaddr_any addr; + socklen_t len = sizeof(addr); + + if(getsockname(icmp_sk, &addr.sa, &len) < 0) + error("getsockname"); + ident = ntohs(addr.sin.sin_port); /* both IPv4 and IPv6 */ + + } else + ident = getpid() & 0xffff; + + add_poll(icmp_sk, POLLIN | POLLERR); + + return 0; +} + +static void icmp_send_probe(probe *pb, int ttl) { + int af = dest_addr.sa.sa_family; + + if(ttl != last_ttl) { + + set_ttl(icmp_sk, ttl); + + last_ttl = ttl; + } + + if(af == AF_INET) { + struct icmp *icmp = (struct icmp *) data; + + icmp->icmp_type = ICMP_ECHO; + icmp->icmp_code = 0; + icmp->icmp_cksum = 0; + icmp->icmp_id = htons(ident); + icmp->icmp_seq = htons(seq); + + icmp->icmp_cksum = in_csum(data, *length_p); + } + else if(af == AF_INET6) { + struct icmp6_hdr *icmp6 = (struct icmp6_hdr *) data; + + icmp6->icmp6_type = ICMP6_ECHO_REQUEST; + icmp6->icmp6_code = 0; + icmp6->icmp6_cksum = 0; + icmp6->icmp6_id= htons (ident); + icmp6->icmp6_seq= htons(seq); + + /* icmp6->icmp6_cksum always computed by kernel internally */ + } + + pb->send_time = get_time(); + + if(do_send(icmp_sk, data, *length_p, &dest_addr) < 0) { + pb->send_time = 0; + return; + } + + pb->seq = seq; + + seq++; + + return; +} + +static probe *icmp_check_reply(int sk, int err, sockaddr_any *from, + char *buf, size_t len) { + UNUSED(sk); + UNUSED(from); + int af = dest_addr.sa.sa_family; + int type; + uint16_t recv_id, recv_seq; + probe *pb; + + if(len < sizeof(struct icmphdr)) + return NULL; + + if(af == AF_INET) { + struct icmp *icmp = (struct icmp *) buf; + + type = icmp->icmp_type; + + recv_id = ntohs(icmp->icmp_id); + recv_seq = ntohs(icmp->icmp_seq); + + } + else { /* AF_INET6 */ + struct icmp6_hdr *icmp6 = (struct icmp6_hdr *) buf; + + type = icmp6->icmp6_type; + + recv_id = ntohs(icmp6->icmp6_id); + recv_seq = ntohs(icmp6->icmp6_seq); + } + + if(recv_id != ident) + return NULL; + + pb = probe_by_seq(recv_seq); + if(!pb) + return NULL; + + if(!err) { + + if(!(af == AF_INET && type == ICMP_ECHOREPLY) && + !(af == AF_INET6 && type == ICMP6_ECHO_REPLY) + ) + return NULL; + + pb->final = 1; + } + + return pb; +} + +static void icmp_recv_probe(int sk, int revents) { + + if(!(revents & (POLLIN | POLLERR))) + return; + + recv_reply(sk, !!(revents & POLLERR), icmp_check_reply); +} + +static void icmp_expire_probe(probe *pb) { + + probe_done(pb); +} + +static tr_module icmp_ops = { + .name = "icmp", + .init = icmp_init, + .send_probe = icmp_send_probe, + .recv_probe = icmp_recv_probe, + .expire_probe = icmp_expire_probe, + .options = icmp_options, +}; + +TR_MODULE(icmp_ops); + +void tr_module_icmp_insert() +{ + +} + diff --git a/modules/net/iputils/traceroute/mod-raw.c b/modules/net/iputils/traceroute/mod-raw.c new file mode 100644 index 0000000000000000000000000000000000000000..bd9f05ba612569e5fbfdb1a3aec01990a55dd8a0 --- /dev/null +++ b/modules/net/iputils/traceroute/mod-raw.c @@ -0,0 +1,172 @@ +/* + Copyright (c) 2006, 2007 Dmitry Butskoy + <buc@citadel.stu.neva.ru> + License: GPL v2 or any later + + See COPYING for the status of this software. +*/ + +#include <stdlib.h> +#include <unistd.h> +#include <sys/socket.h> +#include <poll.h> +#include <netinet/icmp6.h> +#include <netinet/ip_icmp.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/ip6.h> +#include <netdb.h> + +#include "traceroute.h" + + +static sockaddr_any dest_addr = {{ 0, }, }; +static int protocol = DEF_RAW_PROT; + +static char *data = NULL; +static size_t *length_p; + +static int raw_sk = -1; +static int last_ttl = 0; +static int seq = 0; + + +static int set_protocol (CLIF_option *optn, char *arg) { + UNUSED(optn); + char *q; + + protocol = strtoul (arg, &q, 0); + if (q == arg) { + struct protoent *p = getprotobyname (arg); + + if (!p) return -1; + protocol = p->p_proto; + } + + return 0; +} + + +static CLIF_option raw_options[] = { + { 0, "protocol", "PROT", "Use protocol %s (default is " + _TEXT (DEF_RAW_PROT) ")", + set_protocol, 0, 0, CLIF_ABBREV }, + CLIF_END_OPTION +}; + + +static int raw_init (const sockaddr_any *dest, + unsigned int port_seq, size_t *packet_len_p) { + int i; + int af = dest->sa.sa_family; + + dest_addr = *dest; + dest_addr.sin.sin_port = 0; + + if (port_seq) protocol = port_seq; + + + length_p = packet_len_p; + + if (*length_p && + !(data = malloc (*length_p)) + ) error ("malloc"); + + for (i = 0; i < (int)*length_p; i++) + data[i] = 0x40 + (i & 0x3f); + + + raw_sk = socket (af, SOCK_RAW, protocol); + if (raw_sk < 0) + error_or_perm ("socket"); + + tune_socket (raw_sk); + + /* Don't want to catch packets from another hosts */ + if (raw_can_connect () && + connect (raw_sk, &dest_addr.sa, sizeof (dest_addr)) < 0 + ) error ("connect"); + + use_recverr (raw_sk); + + + add_poll (raw_sk, POLLIN | POLLERR); + + return 0; +} + + +static void raw_send_probe (probe *pb, int ttl) { + + if (ttl != last_ttl) { + + set_ttl (raw_sk, ttl); + + last_ttl = ttl; + } + + + pb->send_time = get_time (); + + if (do_send (raw_sk, data, *length_p, &dest_addr) < 0) { + pb->send_time = 0; + return; + } + + + pb->seq = ++seq; + + return; +} + + +static probe *raw_check_reply (int sk, int err, sockaddr_any *from, + char *buf, size_t len) { + UNUSED(sk); + UNUSED(len); + UNUSED(buf); + probe *pb; + + if (!equal_addr (&dest_addr, from)) + return NULL; + + pb = probe_by_seq (seq); + if (!pb) return NULL; + + if (!err) pb->final = 1; + + return pb; +} + + +static void raw_recv_probe (int sk, int revents) { + + if (!(revents & (POLLIN | POLLERR))) + return; + + recv_reply (sk, !!(revents & POLLERR), raw_check_reply); +} + + +static void raw_expire_probe (probe *pb) { + + probe_done (pb); +} + + +static tr_module raw_ops = { + .name = "raw", + .init = raw_init, + .send_probe = raw_send_probe, + .recv_probe = raw_recv_probe, + .expire_probe = raw_expire_probe, + .options = raw_options, + .one_per_time = 1, +}; + +TR_MODULE (raw_ops); + +void tr_module_raw_insert() +{ + +} diff --git a/modules/net/iputils/traceroute/mod-tcp.c b/modules/net/iputils/traceroute/mod-tcp.c new file mode 100644 index 0000000000000000000000000000000000000000..32d2f1027e88db3ff623150cfcca5b7aad7ccf8d --- /dev/null +++ b/modules/net/iputils/traceroute/mod-tcp.c @@ -0,0 +1,515 @@ +/* + Copyright (c) 2006, 2007 Dmitry Butskoy + <buc@citadel.stu.neva.ru> + License: GPL v2 or any later + + See COPYING for the status of this software. +*/ + +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/socket.h> +#include <poll.h> +#include <netinet/icmp6.h> +#include <netinet/ip_icmp.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/ip6.h> +#include <netinet/tcp.h> + + +#include "traceroute.h" + + +#ifndef IP_MTU +#define IP_MTU 14 +#endif + + +static sockaddr_any dest_addr = {{ 0, }, }; +static unsigned int dest_port = 0; + +static int raw_sk = -1; +static int last_ttl = 0; + +static uint8_t buf[1024]; /* enough, enough... */ +static size_t csum_len = 0; +static struct tcphdr *th = NULL; + +#define TH_FLAGS(TH) (((uint8_t *) (TH))[13]) +#define TH_FIN 0x01 +#define TH_SYN 0x02 +#define TH_RST 0x04 +#define TH_PSH 0x08 +#define TH_ACK 0x10 +#define TH_URG 0x20 +#define TH_ECE 0x40 +#define TH_CWR 0x80 + + +static int flags = 0; /* & 0xff == tcp_flags ... */ +static int sysctl = 0; +static int reuse = 0; +static unsigned int mss = 0; +static int info = 0; + +#define FL_FLAGS 0x0100 +#define FL_ECN 0x0200 +#define FL_SACK 0x0400 +#define FL_TSTAMP 0x0800 +#define FL_WSCALE 0x1000 + + +static struct { + const char *name; + unsigned int flag; +} tcp_flags[] = { + { "fin", TH_FIN }, + { "syn", TH_SYN }, + { "rst", TH_RST }, + { "psh", TH_PSH }, + { "ack", TH_ACK }, + { "urg", TH_URG }, + { "ece", TH_ECE }, + { "cwr", TH_CWR }, +}; + +static char *names_by_flags (unsigned int flags) { + int i; + char str[64]; /* enough... */ + char *curr = str; + char *end = str + sizeof (str) / sizeof (*str); + + for (i = 0; i < (int)(sizeof (tcp_flags) / sizeof (*tcp_flags)); i++) { + const char *p; + + if (!(flags & tcp_flags[i].flag)) continue; + + if (curr > str && curr < end) *curr++ = ','; + for (p = tcp_flags[i].name; *p && curr < end; *curr++ = *p++) ; + } + + *curr = '\0'; + + return strdup (str); +} + +static int set_tcp_flag (CLIF_option *optn, char *arg) { + UNUSED(arg); + int i; + + for (i = 0; i < (int)(sizeof (tcp_flags) / sizeof (*tcp_flags)); i++) { + if (!strcmp (optn->long_opt, tcp_flags[i].name)) { + flags |= tcp_flags[i].flag; + return 0; + } + } + + return -1; +} + +static int set_tcp_flags (CLIF_option *optn, char *arg) { + UNUSED(optn); + char *q; + unsigned long value; + + value = strtoul (arg, &q, 0); + if (q == arg) return -1; + + flags = (flags & ~0xff) | (value & 0xff) | FL_FLAGS; + return 0; +} + +static int set_flag (CLIF_option *optn, char *arg) { + UNUSED(arg); + flags |= (unsigned long) optn->data; + + return 0; +} + +static CLIF_option tcp_options[] = { + { 0, "syn", 0, "Set tcp flag SYN (default if no other " + "tcp flags specified)", set_tcp_flag, 0, 0, 0 }, + { 0, "ack", 0, "Set tcp flag ACK,", set_tcp_flag, 0, 0, 0 }, + { 0, "fin", 0, "FIN,", set_tcp_flag, 0, 0, 0 }, + { 0, "rst", 0, "RST,", set_tcp_flag, 0, 0, 0 }, + { 0, "psh", 0, "PSH,", set_tcp_flag, 0, 0, 0 }, + { 0, "urg", 0, "URG,", set_tcp_flag, 0, 0, 0 }, + { 0, "ece", 0, "ECE,", set_tcp_flag, 0, 0, 0 }, + { 0, "cwr", 0, "CWR", set_tcp_flag, 0, 0, 0 }, + { 0, "flags", "NUM", "Set tcp flags exactly to value %s", + set_tcp_flags, 0, 0, CLIF_ABBREV }, + { 0, "ecn", 0, "Send syn packet with tcp flags ECE and CWR " + "(for Explicit Congestion Notification, rfc3168)", + set_flag, (void *) FL_ECN, 0, 0 }, + { 0, "sack", 0, "Use sack,", + set_flag, (void *) FL_SACK, 0, 0 }, + { 0, "timestamps", 0, "timestamps,", + set_flag, (void *) FL_TSTAMP, 0, CLIF_ABBREV }, + { 0, "window_scaling", 0, "window_scaling option for tcp", + set_flag, (void *) FL_WSCALE, 0, CLIF_ABBREV }, + { 0, "sysctl", 0, "Use current sysctl (/proc/sys/net/*) setting " + "for the tcp options and ecn. Always set by default " + "(with \"syn\") if nothing else specified", + CLIF_set_flag, &sysctl, 0, 0 }, + { 0, "reuse", 0, "Allow to reuse local port numbers " + "for the huge workloads (SO_REUSEADDR)", + CLIF_set_flag, &reuse, 0, 0 }, + { 0, "mss", "NUM", "Use value of %s for maxseg tcp option (when syn)", + CLIF_set_uint, &mss, 0, 0 }, + { 0, "info", 0, "Print tcp flags of final tcp replies when target " + "host is reached. Useful to determine whether " + "an application listens the port etc.", + CLIF_set_flag, &info, 0, 0 }, + CLIF_END_OPTION +}; + + +#define SYSCTL_PREFIX "/proc/sys/net/ipv4/tcp_" +static int check_sysctl (const char *name) { + int fd, res; + char buf[sizeof (SYSCTL_PREFIX) + strlen (name) + 1]; + uint8_t ch; + + strcpy (buf, SYSCTL_PREFIX); + strcat (buf, name); + + fd = open (buf, O_RDONLY, 0); + if (fd < 0) return 0; + + res = read (fd, &ch, sizeof (ch)); + close (fd); + + if (res != sizeof (ch)) + return 0; + + /* since kernel 2.6.31 "tcp_ecn" can have value of '2'... */ + if (ch == '1') return 1; + + return 0; +} + + +static int tcp_init (const sockaddr_any *dest, + unsigned int port_seq, size_t *packet_len_p) { + int af = dest->sa.sa_family; + sockaddr_any src; + int mtu; + socklen_t len; + uint8_t *ptr; + uint16_t *lenp; + + + dest_addr = *dest; + dest_addr.sin.sin_port = 0; /* raw sockets can be confused */ + + if (!port_seq) port_seq = DEF_TCP_PORT; + dest_port = htons (port_seq); + + + /* Create raw socket for tcp */ + + raw_sk = socket (af, SOCK_RAW, IPPROTO_TCP); + if (raw_sk < 0) + error_or_perm ("socket"); + + tune_socket (raw_sk); /* including bind, if any */ + + if (connect (raw_sk, &dest_addr.sa, sizeof (dest_addr)) < 0) + error ("connect"); + + len = sizeof (src); + if (getsockname (raw_sk, &src.sa, &len) < 0) + error ("getsockname"); + + + len = sizeof (mtu); + if (getsockopt (raw_sk, af == AF_INET ? SOL_IP : SOL_IPV6, + af == AF_INET ? IP_MTU : IPV6_MTU, + &mtu, &len) < 0 || mtu < 576 + ) mtu = 576; + + /* mss = mtu - headers */ + mtu -= af == AF_INET ? sizeof (struct iphdr) : sizeof (struct ip6_hdr); + mtu -= sizeof (struct tcphdr); + + + if (!raw_can_connect ()) { /* work-around for buggy kernels */ + close (raw_sk); + raw_sk = socket (af, SOCK_RAW, IPPROTO_TCP); + if (raw_sk < 0) error ("socket"); + tune_socket (raw_sk); + /* but do not connect it... */ + } + + + use_recverr (raw_sk); + + add_poll (raw_sk, POLLIN | POLLERR); + + + /* Now create the sample packet. */ + + if (!flags) sysctl = 1; + + if (sysctl) { + if (check_sysctl ("ecn")) flags |= FL_ECN; + if (check_sysctl ("sack")) flags |= FL_SACK; + if (check_sysctl ("timestamps")) flags |= FL_TSTAMP; + if (check_sysctl ("window_scaling")) flags |= FL_WSCALE; + } + + if (!(flags & (FL_FLAGS | 0xff))) { /* no any tcp flag set */ + flags |= TH_SYN; + if (flags & FL_ECN) + flags |= TH_ECE | TH_CWR; + } + + + /* For easy checksum computing: + saddr + daddr + length + protocol + tcphdr + tcpoptions + */ + + ptr = buf; + + if (af == AF_INET) { + len = sizeof (src.sin.sin_addr); + memcpy (ptr, &src.sin.sin_addr, len); + ptr += len; + memcpy (ptr, &dest_addr.sin.sin_addr, len); + ptr += len; + } else { + len = sizeof (src.sin6.sin6_addr); + memcpy (ptr, &src.sin6.sin6_addr, len); + ptr += len; + memcpy (ptr, &dest_addr.sin6.sin6_addr, len); + ptr += len; + } + + lenp = (uint16_t *) ptr; + ptr += sizeof (uint16_t); + *((uint16_t *) ptr) = htons ((uint16_t) IPPROTO_TCP); + ptr += sizeof (uint16_t); + + + /* Construct TCP header */ + + th = (struct tcphdr *) ptr; + + th->source = 0; /* temporary */ + th->dest = dest_port; + th->seq = 0; /* temporary */ + th->ack_seq = 0; + th->doff = 0; /* later... */ + TH_FLAGS(th) = flags & 0xff; + th->window = htons (4 * mtu); + th->check = 0; + th->urg_ptr = 0; + + + /* Build TCP options */ + + ptr = (uint8_t *) (th + 1); + + if (flags & TH_SYN) { + *ptr++ = TCPOPT_MAXSEG; /* 2 */ + *ptr++ = TCPOLEN_MAXSEG; /* 4 */ + *((uint16_t *) ptr) = htons (mss ? mss : (unsigned int)mtu); + ptr += sizeof (uint16_t); + } + + if (flags & FL_TSTAMP) { + + if (flags & FL_SACK) { + *ptr++ = TCPOPT_SACK_PERMITTED; /* 4 */ + *ptr++ = TCPOLEN_SACK_PERMITTED;/* 2 */ + } else { + *ptr++ = TCPOPT_NOP; /* 1 */ + *ptr++ = TCPOPT_NOP; /* 1 */ + } + *ptr++ = TCPOPT_TIMESTAMP; /* 8 */ + *ptr++ = TCPOLEN_TIMESTAMP; /* 10 */ + + *((uint32_t *) ptr) = random_seq (); /* really! */ + ptr += sizeof (uint32_t); + *((uint32_t *) ptr) = (flags & TH_ACK) ? random_seq () : 0; + ptr += sizeof (uint32_t); + } + else if (flags & FL_SACK) { + *ptr++ = TCPOPT_NOP; /* 1 */ + *ptr++ = TCPOPT_NOP; /* 1 */ + *ptr++ = TCPOPT_SACK_PERMITTED; /* 4 */ + *ptr++ = TCPOLEN_SACK_PERMITTED; /* 2 */ + } + + if (flags & FL_WSCALE) { + *ptr++ = TCPOPT_NOP; /* 1 */ + *ptr++ = TCPOPT_WINDOW; /* 3 */ + *ptr++ = TCPOLEN_WINDOW; /* 3 */ + *ptr++ = 2; /* assume some corect value... */ + } + + + csum_len = ptr - buf; + + if (csum_len > sizeof (buf)) + error ("impossible"); /* paranoia */ + + len = ptr - (uint8_t *) th; + if (len & 0x03) error ("impossible"); /* as >>2 ... */ + + *lenp = htons (len); + th->doff = len >> 2; + + + *packet_len_p = len; + + return 0; +} + + +static void tcp_send_probe (probe *pb, int ttl) { + int sk; + int af = dest_addr.sa.sa_family; + sockaddr_any addr; + socklen_t len = sizeof (addr); + + + /* To make sure we have chosen a free unused "source port", + just create, (auto)bind and hold a socket while the port is needed. + */ + + sk = socket (af, SOCK_STREAM, 0); + if (sk < 0) error ("socket"); + + if (reuse && setsockopt (sk, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) + error ("setsockopt SO_REUSEADDR"); + + bind_socket (sk); + + if (getsockname (sk, &addr.sa, &len) < 0) + error ("getsockname"); + + /* When we reach the target host, it can send us either RST or SYN+ACK. + For RST all is OK (we and kernel just answer nothing), but + for SYN+ACK we should reply with our RST. + It is well-known "half-open technique", used by port scanners etc. + This way we do not touch remote applications at all, unlike + the ordinary connect(2) call. + As the port-holding socket neither connect() nor listen(), + it means "no such port yet" for remote ends, and kernel always + send RST in such a situation automatically (we have to do nothing). + */ + + + th->source = addr.sin.sin_port; + + th->seq = random_seq (); + + th->check = 0; + th->check = in_csum (buf, csum_len); + + + if (ttl != last_ttl) { + + set_ttl (raw_sk, ttl); + + last_ttl = ttl; + } + + + pb->send_time = get_time (); + + if (do_send (raw_sk, th, th->doff << 2, &dest_addr) < 0) { + close (sk); + pb->send_time = 0; + return; + } + + + pb->seq = th->source; + + pb->sk = sk; + + return; +} + + +static probe *tcp_check_reply (int sk, int err, sockaddr_any *from, + char *buf, size_t len) { + UNUSED(sk); + probe *pb; + struct tcphdr *tcp = (struct tcphdr *) buf; + uint16_t sport, dport; + + + if (len < 8) return NULL; /* too short */ + + + if (err) { + sport = tcp->source; + dport = tcp->dest; + } else { + sport = tcp->dest; + dport = tcp->source; + } + + + if (dport != dest_port) + return NULL; + + if (!equal_addr (&dest_addr, from)) + return NULL; + + pb = probe_by_seq (sport); + if (!pb) return NULL; + + + if (!err) { + + pb->final = 1; + + if (info) + pb->ext = names_by_flags (TH_FLAGS(tcp)); + } + + return pb; +} + + +static void tcp_recv_probe (int sk, int revents) { + + if (!(revents & (POLLIN | POLLERR))) + return; + + recv_reply (sk, !!(revents & POLLERR), tcp_check_reply); +} + + +static void tcp_expire_probe (probe *pb) { + + probe_done (pb); +} + + +static tr_module tcp_ops = { + .name = "tcp", + .init = tcp_init, + .send_probe = tcp_send_probe, + .recv_probe = tcp_recv_probe, + .expire_probe = tcp_expire_probe, + .options = tcp_options, +}; + +TR_MODULE (tcp_ops); + +void tr_module_tcp_insert() +{ + +} diff --git a/modules/net/iputils/traceroute/mod-tcpconn.c b/modules/net/iputils/traceroute/mod-tcpconn.c new file mode 100644 index 0000000000000000000000000000000000000000..13e239864756de3639330189389933df570e8bf6 --- /dev/null +++ b/modules/net/iputils/traceroute/mod-tcpconn.c @@ -0,0 +1,237 @@ +/* + Copyright (c) 2006, 2007 Dmitry Butskoy + <buc@citadel.stu.neva.ru> + License: GPL v2 or any later + + See COPYING for the status of this software. +*/ + +#include <stdlib.h> +#include <unistd.h> +#include <sys/socket.h> +#include <poll.h> +#include <netinet/icmp6.h> +#include <netinet/ip_icmp.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/ip6.h> +#include <netinet/tcp.h> +#include <errno.h> + +#include "traceroute.h" + + +static sockaddr_any dest_addr = {{ 0, }, }; + +static int icmp_sk = -1; + + +static int tcp_init (const sockaddr_any *dest, + unsigned int port_seq, size_t *packet_len_p) { + UNUSED(packet_len_p); + int af = dest->sa.sa_family; + + dest_addr = *dest; + dest_addr.sin.sin_port = htons (DEF_TCP_PORT); + + if (port_seq) + dest_addr.sin.sin_port = htons (port_seq); + + + /* Currently an ICMP socket is the only way + to obtain the needed info... + */ + icmp_sk = socket (af, SOCK_RAW, (af == AF_INET) ? IPPROTO_ICMP + : IPPROTO_ICMPV6); + if (icmp_sk < 0) + error_or_perm ("socket"); + + /* icmp_sk not need full tune_socket() here, just a receiving one */ + bind_socket (icmp_sk); + use_timestamp (icmp_sk); + use_recv_ttl (icmp_sk); + + add_poll (icmp_sk, POLLIN); + + return 0; +} + + +static void tcp_send_probe (probe *pb, int ttl) { + int sk; + int af = dest_addr.sa.sa_family; + sockaddr_any addr; + socklen_t length = sizeof (addr); + + + sk = socket (af, SOCK_STREAM, 0); + if (sk < 0) error ("socket"); + + tune_socket (sk); /* common stuff */ + + set_ttl (sk, ttl); + + + pb->send_time = get_time (); + + if (connect (sk, &dest_addr.sa, sizeof (dest_addr)) < 0) { + if (errno != EINPROGRESS) + error ("connect"); + } + + + if (getsockname (sk, &addr.sa, &length) < 0) + error ("getsockname"); + + pb->seq = addr.sin.sin_port; /* both ipv4/ipv6 */ + + pb->sk = sk; + + add_poll (sk, POLLERR | POLLHUP | POLLOUT); + + return; +} + + +static probe *tcp_check_reply (int sk, int err, sockaddr_any *from, + char *buf, size_t len) { + UNUSED(sk); + UNUSED(err); + UNUSED(from); + int af = dest_addr.sa.sa_family; + int type, code, info; + probe *pb; + struct tcphdr *tcp; + + + if (len < sizeof (struct icmphdr)) + return NULL; + + + if (af == AF_INET) { + struct icmp *icmp = (struct icmp *) buf; + struct iphdr *ip; + int hlen; + + type = icmp->icmp_type; + code = icmp->icmp_code; + info = icmp->icmp_void; + + if (type != ICMP_TIME_EXCEEDED && type != ICMP_DEST_UNREACH) + return NULL; + + if (len < sizeof (struct icmphdr) + sizeof (struct iphdr) + 8) + /* `8' - rfc1122: 3.2.2 */ + return NULL; + + ip = (struct iphdr *) (((char *)icmp) + sizeof(struct icmphdr)); + hlen = ip->ihl << 2; + + if (len < sizeof (struct icmphdr) + hlen + 8) + return NULL; + if (ip->protocol != IPPROTO_TCP) + return NULL; + + tcp = (struct tcphdr *) (((char *) ip) + hlen); + + } + else { /* AF_INET6 */ + struct icmp6_hdr *icmp6 = (struct icmp6_hdr *) buf; + struct ip6_hdr *ip6; + + type = icmp6->icmp6_type; + code = icmp6->icmp6_code; + info = icmp6->icmp6_mtu; + + if (type != ICMP6_TIME_EXCEEDED && + type != ICMP6_DST_UNREACH && + type != ICMP6_PACKET_TOO_BIG + ) return NULL; + + if (len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr) + 8) + return NULL; + + ip6 = (struct ip6_hdr *) (icmp6 + 1); + if (ip6->ip6_nxt != IPPROTO_TCP) + return NULL; + + tcp = (struct tcphdr *) (ip6 + 1); + + } + + + if (tcp->dest != dest_addr.sin.sin_port) + return NULL; + + pb = probe_by_seq (tcp->source); + if (!pb) return NULL; + + + /* here only, high level has no data to do this */ + parse_icmp_res (pb, type, code, info); + + return pb; +} + + +static void tcp_recv_probe (int sk, int revents) { + + if (sk != icmp_sk) { /* a tcp socket */ + probe *pb; + + pb = probe_by_sk (sk); + if (!pb) { + del_poll (sk); + return; + } + + + /* do connect() again and check errno, regardless of revents */ + if (connect (sk, &dest_addr.sa, sizeof (dest_addr)) < 0) { + if (errno != EISCONN && errno != ECONNREFUSED) + return; /* ICMP say more */ + } + + /* we have reached the dest host (either connected or refused) */ + + memcpy (&pb->res, &dest_addr, sizeof (pb->res)); + + pb->final = 1; + + pb->recv_time = get_time (); + + probe_done (pb); + + return; + } + + + /* ICMP stuff */ + + if (!(revents & POLLIN)) + return; + + recv_reply (icmp_sk, 0, tcp_check_reply); +} + + +static void tcp_expire_probe (probe *pb) { + + probe_done (pb); +} + + +static tr_module tcp_ops = { + .name = "tcpconn", + .init = tcp_init, + .send_probe = tcp_send_probe, + .recv_probe = tcp_recv_probe, + .expire_probe = tcp_expire_probe, +}; + +TR_MODULE (tcp_ops); + +void tr_module_tcpconn_insert() +{ + +} diff --git a/modules/net/iputils/traceroute/mod-udp.c b/modules/net/iputils/traceroute/mod-udp.c new file mode 100644 index 0000000000000000000000000000000000000000..e24d0271c8c6e60f40592f0be18e3e7c7b482379 --- /dev/null +++ b/modules/net/iputils/traceroute/mod-udp.c @@ -0,0 +1,241 @@ +/* + Copyright (c) 2006, 2007 Dmitry Butskoy + <buc@citadel.stu.neva.ru> + License: GPL v2 or any later + + See COPYING for the status of this software. +*/ + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/socket.h> +#include <poll.h> +#include <netinet/in.h> +#include <netinet/udp.h> + +#include "traceroute.h" + + +#ifndef IPPROTO_UDPLITE +#define IPPROTO_UDPLITE 136 +#endif + +#ifndef UDPLITE_SEND_CSCOV +#define UDPLITE_SEND_CSCOV 10 +#define UDPLITE_RECV_CSCOV 11 +#endif + + +static sockaddr_any dest_addr = {{ 0, }, }; +static unsigned int curr_port = 0; +static unsigned int protocol = IPPROTO_UDP; + + +static char *data = NULL; +static size_t *length_p; + +static void fill_data (size_t *packet_len_p) { + int i; + + length_p = packet_len_p; + + if (*length_p && + !(data = malloc (*length_p)) + ) error ("malloc"); + + for (i = 0; i < (int)*length_p; i++) + data[i] = 0x40 + (i & 0x3f); + + return; +} + + +static int udp_default_init (const sockaddr_any *dest, + unsigned int port_seq, size_t *packet_len_p) { + + curr_port = port_seq ? port_seq : DEF_START_PORT; + + dest_addr = *dest; + dest_addr.sin.sin_port = htons (curr_port); + + fill_data (packet_len_p); + + return 0; +} + + +static int udp_init (const sockaddr_any *dest, + unsigned int port_seq, size_t *packet_len_p) { + + dest_addr = *dest; + + if (!port_seq) port_seq = DEF_UDP_PORT; + dest_addr.sin.sin_port = htons ((uint16_t) port_seq); + + fill_data (packet_len_p); + + return 0; +} + + +static unsigned int coverage = 0; +#define MIN_COVERAGE (sizeof (struct udphdr)) + +static void set_coverage (int sk) { + int val = MIN_COVERAGE; + + if (setsockopt (sk, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV, + &coverage, sizeof (coverage)) < 0 + ) error ("UDPLITE_SEND_CSCOV"); + + if (setsockopt (sk, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV, + &val, sizeof (val)) < 0 + ) error ("UDPLITE_RECV_CSCOV"); +} + +static CLIF_option udplite_options[] = { + { 0, "coverage", "NUM", "Set udplite send coverage to %s (default is " + _TEXT(MIN_COVERAGE) ")", + CLIF_set_uint, &coverage, 0, CLIF_ABBREV }, + CLIF_END_OPTION +}; + +static int udplite_init (const sockaddr_any *dest, + unsigned int port_seq, size_t *packet_len_p) { + + dest_addr = *dest; + + if (!port_seq) port_seq = DEF_UDP_PORT; /* XXX: Hmmm... */ + dest_addr.sin.sin_port = htons ((uint16_t) port_seq); + + protocol = IPPROTO_UDPLITE; + + if (!coverage) coverage = MIN_COVERAGE; + + fill_data (packet_len_p); + + return 0; +} + + +static void udp_send_probe (probe *pb, int ttl) { + int sk; + int af = dest_addr.sa.sa_family; + + + sk = socket (af, SOCK_DGRAM, protocol); + if (sk < 0) error ("socket"); + + tune_socket (sk); /* common stuff */ + + if (coverage) set_coverage (sk); /* udplite case */ + + set_ttl (sk, ttl); + + + if (connect (sk, &dest_addr.sa, sizeof (dest_addr)) < 0) + error ("connect"); + + use_recverr (sk); + + + pb->send_time = get_time (); + + if (do_send (sk, data, *length_p, NULL) < 0) { + close (sk); + pb->send_time = 0; + return; + } + + + pb->sk = sk; + + add_poll (sk, POLLIN | POLLERR); + + pb->seq = dest_addr.sin.sin_port; + + if (curr_port) { /* traditional udp method */ + curr_port++; + dest_addr.sin.sin_port = htons (curr_port); /* both ipv4 and ipv6 */ + } + + return; +} + + +static probe *udp_check_reply (int sk, int err, sockaddr_any *from, + char *buf, size_t len) { + UNUSED(buf); + UNUSED(len); + probe *pb; + + pb = probe_by_sk (sk); + if (!pb) return NULL; + + if (pb->seq != from->sin.sin_port) + return NULL; + + if (!err) pb->final = 1; + + return pb; +} + + +static void udp_recv_probe (int sk, int revents) { + + if (!(revents & (POLLIN | POLLERR))) + return; + + recv_reply (sk, !!(revents & POLLERR), udp_check_reply); +} + + +static void udp_expire_probe (probe *pb) { + + probe_done (pb); +} + + +/* All three modules share the same methods except the init... */ + +static tr_module default_ops = { + .name = "default", + .init = udp_default_init, + .send_probe = udp_send_probe, + .recv_probe = udp_recv_probe, + .expire_probe = udp_expire_probe, + .header_len = sizeof (struct udphdr), +}; + +TR_MODULE (default_ops); + + +static tr_module udp_ops = { + .name = "udp", + .init = udp_init, + .send_probe = udp_send_probe, + .recv_probe = udp_recv_probe, + .expire_probe = udp_expire_probe, + .header_len = sizeof (struct udphdr), +}; + +TR_MODULE (udp_ops); + + +static tr_module udplite_ops = { + .name = "udplite", + .init = udplite_init, + .send_probe = udp_send_probe, + .recv_probe = udp_recv_probe, + .expire_probe = udp_expire_probe, + .header_len = sizeof (struct udphdr), + .options = udplite_options, +}; + +TR_MODULE (udplite_ops); + +void tr_module_udp_insert() +{ + +} diff --git a/modules/net/iputils/traceroute/module.c b/modules/net/iputils/traceroute/module.c new file mode 100644 index 0000000000000000000000000000000000000000..f8f228ef635758a62b036a87986cdfae27f210bb --- /dev/null +++ b/modules/net/iputils/traceroute/module.c @@ -0,0 +1,51 @@ +/* + Copyright (c) 2006, 2007 Dmitry Butskoy + <buc@citadel.stu.neva.ru> + License: GPL v2 or any later + + See COPYING for the status of this software. + */ + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <stdio.h> + +#include "traceroute.h" + +void tr_module_icmp_insert(); +void tr_module_udp_insert(); +void tr_module_tcp_insert(); +void tr_module_tcpconn_insert(); +void tr_module_raw_insert(); +void tr_module_dccp_insert(); + +static tr_module *base = NULL; + +void tr_register_module(tr_module *ops) { + + ops->next = base; + base = ops; +// printf("tr_register_module name=%s\n", ops->name); +} + +const tr_module *tr_get_module(const char *name) { + const tr_module *ops; + + tr_module_icmp_insert(); + tr_module_udp_insert(); + tr_module_tcp_insert(); + tr_module_tcpconn_insert(); + tr_module_raw_insert(); + tr_module_dccp_insert(); + + if(!name) + return 0; + + for(ops = base; ops; ops = ops->next) { + if(!strcasecmp(name, ops->name)) + return ops; + } + + return NULL; +} diff --git a/modules/net/iputils/traceroute/poll.c b/modules/net/iputils/traceroute/poll.c new file mode 100644 index 0000000000000000000000000000000000000000..232a83395bc600ab54bddb1d8ea7c98e3ceb8526 --- /dev/null +++ b/modules/net/iputils/traceroute/poll.c @@ -0,0 +1,93 @@ +/* + Copyright (c) 2006, 2007 Dmitry Butskoy + <buc@citadel.stu.neva.ru> + License: GPL v2 or any later + + See COPYING for the status of this software. +*/ + +#include <stdlib.h> +#include <unistd.h> +#include <poll.h> +#include <errno.h> +#include <math.h> + +#include "traceroute.h" + + +static struct pollfd *pfd = NULL; +static unsigned int num_polls = 0; + + +void add_poll (int fd, int events) { + int i; + + for (i = 0; i < (int)num_polls && pfd[i].fd > 0; i++) ; + + if (i == (int)num_polls) { + pfd = realloc (pfd, ++num_polls * sizeof (*pfd)); + if (!pfd) error ("realloc"); + } + + pfd[i].fd = fd; + pfd[i].events = events; +} + + +void del_poll (int fd) { + int i; + + for (i = 0; i < (int)num_polls && pfd[i].fd != fd; i++) ; + + if (i < (int)num_polls) pfd[i].fd = -1; /* or just zero it... */ +} + + +static int cleanup_polls (void) { + int i; + + for (i = 0; i < (int)num_polls && pfd[i].fd > 0; i++) ; + + if (i < (int)num_polls) { /* a hole have found */ + int j; + + for (j = i + 1; j < (int)num_polls; j++) { + if (pfd[j].fd > 0) { + pfd[i++] = pfd[j]; + pfd[j].fd = -1; + } + } + } + + return i; +} + + +void do_poll (double timeout, void (*callback) (int fd, int revents)) { + int nfds; + int msecs = ceil (timeout * 1000); + + while ((nfds = cleanup_polls ()) > 0) { + int i, n; + + n = poll (pfd, nfds, msecs); + + if (n <= 0) { + if (n == 0 || errno == EINTR) + return; + error ("poll"); + } + + for (i = 0; n && i < (int)num_polls; i++) { + if (pfd[i].revents) { + callback (pfd[i].fd, pfd[i].revents); + n--; + } + } + + msecs = 0; /* no more wait, just eat all the pending */ + } + + return; +} + diff --git a/modules/net/iputils/traceroute/random.c b/modules/net/iputils/traceroute/random.c new file mode 100644 index 0000000000000000000000000000000000000000..5a8f911e1463b797559b263b5d9cd7081a82a428 --- /dev/null +++ b/modules/net/iputils/traceroute/random.c @@ -0,0 +1,28 @@ +/* + Copyright (c) 2006, 2007 Dmitry Butskoy + <buc@citadel.stu.neva.ru> + License: GPL v2 or any later + + See COPYING for the status of this software. +*/ + +#include <stdlib.h> +#include <unistd.h> +#include <sys/times.h> + +#include "traceroute.h" + + +static void __init_random_seq (void) __attribute__ ((constructor)); +static void __init_random_seq (void) { + + srand (times (NULL) + getpid ()); +} + + +unsigned int random_seq (void) { + + /* To not worry about RANDOM_MAX and precision... */ + return (rand () << 16) ^ (rand () << 8) ^ rand () ^ (rand () >> 8); +} + diff --git a/modules/net/iputils/traceroute/time.c b/modules/net/iputils/traceroute/time.c new file mode 100644 index 0000000000000000000000000000000000000000..16ea82483cc3483ada3a62c81c8436f820667191 --- /dev/null +++ b/modules/net/iputils/traceroute/time.c @@ -0,0 +1,27 @@ +/* + Copyright (c) 2006, 2007 Dmitry Butskoy + <buc@citadel.stu.neva.ru> + License: GPL v2 or any later + + See COPYING for the status of this software. +*/ + +#include <stdlib.h> +#include <unistd.h> +#include <sys/time.h> + +#include "traceroute.h" + + +/* Just returns current time as double, with most possible precision... */ + +double get_time (void) { + struct timeval tv; + double d; + + gettimeofday (&tv, NULL); + + d = ((double) tv.tv_usec) / 1000000. + (unsigned long) tv.tv_sec; + + return d; +} diff --git a/modules/net/iputils/traceroute/traceroute.c b/modules/net/iputils/traceroute/traceroute.c new file mode 100755 index 0000000000000000000000000000000000000000..a0dbeb2e233478034ab0b0fb6caec1a7285f74ed --- /dev/null +++ b/modules/net/iputils/traceroute/traceroute.c @@ -0,0 +1,1758 @@ +/* + Copyright (c) 2006, 2007 Dmitry Butskoy + <buc@citadel.stu.neva.ru> + License: GPL v2 or any later + + See COPYING for the status of this software. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/socket.h> +#include <poll.h> +#include <netinet/icmp6.h> +#include <netinet/ip_icmp.h> +#include <netinet/in.h> +#include <netinet/ip6.h> +#include <netdb.h> +#include <errno.h> +#include <locale.h> +#include <sys/utsname.h> +#include <linux/types.h> +#include <linux/errqueue.h> + +/* XXX: Remove this when things will be defined properly in netinet/ ... */ +#include "flowlabel.h" + +//#include "version.h" +#include <stdbool.h> +//#include <glib.h> +#include "traceroute.h" + +#ifndef ICMP6_DST_UNREACH_BEYONDSCOPE +#ifdef ICMP6_DST_UNREACH_NOTNEIGHBOR +#define ICMP6_DST_UNREACH_BEYONDSCOPE ICMP6_DST_UNREACH_NOTNEIGHBOR +#else +#define ICMP6_DST_UNREACH_BEYONDSCOPE 2 +#endif +#endif + +#ifndef IPV6_RECVHOPLIMIT +#define IPV6_RECVHOPLIMIT IPV6_HOPLIMIT +#endif + +#ifndef IP_PMTUDISC_PROBE +#define IP_PMTUDISC_PROBE 3 +#endif + +#ifndef IPV6_PMTUDISC_PROBE +#define IPV6_PMTUDISC_PROBE 3 +#endif + +#ifndef AI_IDN +#define AI_IDN 0 +#endif + +#ifndef NI_IDN +#define NI_IDN 0 +#endif + +#define MAX_HOPS 255 +#define MAX_PROBES 10 +#define MAX_GATEWAYS_4 8 +#define MAX_GATEWAYS_6 127 +#define DEF_HOPS 30 +#define DEF_SIM_PROBES 16 /* including several hops */ +#define DEF_NUM_PROBES 3 //1 +#define DEF_WAIT_SECS 5.0 +#define DEF_HERE_FACTOR 3 +#define DEF_NEAR_FACTOR 10 +#ifndef DEF_WAIT_PREC +#define DEF_WAIT_PREC 0.001 /* +1 ms to avoid precision issues */ +#endif +#define DEF_SEND_SECS 0 +#define DEF_DATA_LEN 40 /* all but IP header... */ +#define MAX_PACKET_LEN 65000 +#ifndef DEF_AF +#define DEF_AF AF_INET +#endif + +#define ttl2hops(X) (((X) <= 64 ? 65 : ((X) <= 128 ? 129 : 256)) - (X)) + +static char version_string[] = "Modern traceroute for Linux, " + "version " _TEXT(VERSION) +"\nCopyright (c) 2016 Dmitry Butskoy, " +" License: GPL v2 or any later"; +static int debug = 0; +static unsigned int first_hop = 1; +static unsigned int max_hops = DEF_HOPS; +static unsigned int sim_probes = DEF_SIM_PROBES; +static unsigned int probes_per_hop = DEF_NUM_PROBES; + +static char **gateways = NULL; +static int num_gateways = 0; +static unsigned char *rtbuf = NULL; +static size_t rtbuf_len = 0; +static unsigned int ipv6_rthdr_type = 2; /* IPV6_RTHDR_TYPE_2 */ + +static size_t header_len = 0; +static size_t data_len = 0; + +static int dontfrag = 0; +static int noresolve = 0; +static int extension = 0; +static int as_lookups = 0; +static unsigned int dst_port_seq = 0; +static unsigned int tos = 0; +static unsigned int flow_label = 0; +static int noroute = 0; +static unsigned int fwmark = 0; +static int packet_len = -1; +static double wait_secs = DEF_WAIT_SECS; +static double here_factor = DEF_HERE_FACTOR; +static double near_factor = DEF_NEAR_FACTOR; +static double send_secs = DEF_SEND_SECS; +static int mtudisc = 0; +static int backward = 0; + +static sockaddr_any dst_addr = { { 0, }, }; +static char *dst_name = NULL; +static char *device = NULL; +static sockaddr_any src_addr = { { 0, }, }; +static unsigned int src_port = 0; + +static const char *module = "default"; +static const tr_module *ops = NULL; + +static char *opts[16] = { NULL, }; /* assume enough */ +static unsigned int opts_idx = 1; /* first one reserved... */ + +static int af = 0; + +static probe *probes = NULL; +static unsigned int num_probes = 0; + +static void ex_error(const char *format, ...) { + va_list ap; + + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + + fprintf(stderr, "\n"); + + //exit(2); +} + +void error(const char *str) { + + fprintf(stderr, "\n"); + + perror(str); + + exit(1); +} + +void error_or_perm(const char *str) { + + if(errno == EPERM) + fprintf(stderr, "You do not have enough privileges to use " + "this traceroute method."); + error(str); +} + +/* Set initial parameters according to how we was called */ + +static void check_progname(const char *name) { + const char *p; + int l; + + p = strrchr(name, '/'); + if(p) + p++; + else + p = name; + + l = strlen(p); + if(l <= 0) + return; + l--; + + if(p[l] == '6') + af = AF_INET6; + else if(p[l] == '4') + af = AF_INET; + + if(!strncmp(p, "tcp", 3)) + module = "tcp"; + if(!strncmp(p, "tracert", 7)) + module = "icmp"; + + return; +} + +static int getaddr(const char *name, sockaddr_any *addr) { + int ret; + struct addrinfo hints, *ai, *res = NULL; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = af; + hints.ai_flags = AI_IDN; + + ret = getaddrinfo(name, NULL, &hints, &res); + if(ret) { + fprintf(stderr, "%s: %s\n", name, gai_strerror(ret)); + return -1; + } + + for(ai = res; ai; ai = ai->ai_next) { + if(ai->ai_family == af) + break; + /* when af not specified, choose DEF_AF if present */ + if(!af && ai->ai_family == DEF_AF) + break; + } + if(!ai) + ai = res; /* anything... */ + + if(ai->ai_addrlen > sizeof(*addr)) + return -1; /* paranoia */ + memcpy(addr, ai->ai_addr, ai->ai_addrlen); + + freeaddrinfo(res); + + return 0; +} + +static void make_fd_used(int fd) { + int nfd; + + if(fcntl(fd, F_GETFL) != -1) + return; + + if(errno != EBADF) + error("fcntl F_GETFL"); + + nfd = open("/dev/null", O_RDONLY); + if(nfd < 0) + error("open /dev/null"); + + if(nfd != fd) { + dup2(nfd, fd); + close(nfd); + } + + return; +} + +static char addr2str_buf[INET6_ADDRSTRLEN]; + +static const char *addr2str(const sockaddr_any *addr) { + + getnameinfo(&addr->sa, sizeof(*addr), + addr2str_buf, sizeof(addr2str_buf), 0, 0, NI_NUMERICHOST); + + return addr2str_buf; +} + +/* IP options stuff */ + +static int init_ip_options(void) { + sockaddr_any *gates; + int i, max; + + if(!num_gateways) + return 0; + + /* check for TYPE,ADDR,ADDR... form */ + if(af == AF_INET6 && num_gateways > 1 && gateways[0]) { + char *q; + unsigned int value = strtoul(gateways[0], &q, 0); + + if(!*q) { + ipv6_rthdr_type = value; + num_gateways--; + for(i = 0; i < num_gateways; i++) + gateways[i] = gateways[i + 1]; + } + } + + max = af == AF_INET ? MAX_GATEWAYS_4 : MAX_GATEWAYS_6; + if(num_gateways > max) { + ex_error("Too many gateways specified. No more than %d", max); + return -1; + } + + gates = alloca(num_gateways * sizeof(*gates)); + + for(i = 0; i < num_gateways; i++) { + + if(!gateways[i]) + error("strdup"); + + if(getaddr(gateways[i], &gates[i]) < 0) { + ex_error(""); /* already reported */ + return -1; + } + if(gates[i].sa.sa_family != af) { + ex_error("IP versions mismatch in gateway addresses"); + return -1; + } + + free(gateways[i]); + } + + free(gateways); + gateways = NULL; + + if(af == AF_INET) { + struct in_addr *in; + + rtbuf_len = 4 + (num_gateways + 1) * sizeof(*in); + rtbuf = malloc(rtbuf_len); + if(!rtbuf) + error("malloc"); + + in = (struct in_addr *) &rtbuf[4]; + for(i = 0; i < num_gateways; i++) + memcpy(&in[i], &gates[i].sin.sin_addr, sizeof(*in)); + /* final hop */ + memcpy(&in[i], &dst_addr.sin.sin_addr, sizeof(*in)); + i++; + + rtbuf[0] = IPOPT_NOP; + rtbuf[1] = IPOPT_LSRR; + rtbuf[2] = (i * sizeof(*in)) + 3; + rtbuf[3] = IPOPT_MINOFF; + + } + else if(af == AF_INET6) { + struct in6_addr *in6; + struct ip6_rthdr *rth; + + /* IPV6_RTHDR_TYPE_0 length is 8 */ + rtbuf_len = 8 + num_gateways * sizeof(*in6); + rtbuf = malloc(rtbuf_len); + if(!rtbuf) + error("malloc"); + + rth = (struct ip6_rthdr *) rtbuf; + rth->ip6r_nxt = 0; + rth->ip6r_len = 2 * num_gateways; + rth->ip6r_type = ipv6_rthdr_type; + rth->ip6r_segleft = num_gateways; + + *((uint32_t *) (rth + 1)) = 0; + + in6 = (struct in6_addr *) (rtbuf + 8); + for(i = 0; i < num_gateways; i++) + memcpy(&in6[i], &gates[i].sin6.sin6_addr, sizeof(*in6)); + } + + return 0; +} + +/* Command line stuff */ +__attribute__((unused)) +static int set_af(CLIF_option *optn, char *arg) { + UNUSED(arg); + int vers = (long) optn->data; + + if(vers == 4) + af = AF_INET; + else if(vers == 6) + af = AF_INET6; + else + return -1; + + return 0; +} + +static int add_gateway(CLIF_option *optn, char *arg) { + UNUSED(optn); + if(num_gateways >= MAX_GATEWAYS_6) { /* 127 > 8 ... :) */ + fprintf(stderr, "Too many gateways specified."); + return -1; + } + + gateways = realloc(gateways, (num_gateways + 1) * sizeof(*gateways)); + if(!gateways) + error("malloc"); + gateways[num_gateways++] = strdup(arg); + + return 0; +} + +static int set_source(CLIF_option *optn, char *arg) { + UNUSED(optn); + return getaddr(arg, &src_addr); +} + +static int set_port(CLIF_option *optn, char *arg) { + unsigned int *up = (unsigned int *) optn->data; + char *q; + + *up = strtoul(arg, &q, 0); + if(q == arg) { + struct servent *s = getservbyname(arg, NULL); + + if(!s) + return -1; + *up = ntohs(s->s_port); + } + + return 0; +} + +static int set_module(CLIF_option *optn, char *arg) { + UNUSED(arg); + module = (char *) optn->data; + + return 0; +} + +static int set_mod_option(CLIF_option *optn, char *arg) { + UNUSED(optn); + if(!strcmp(arg, "help")) { + const tr_module *mod = tr_get_module(module); + + if(mod && mod->options) { + /* just to set common keyword flag... */ + CLIF_parse(1, &arg, 0, 0, CLIF_KEYWORD); + CLIF_print_options(NULL, mod->options); + } else + fprintf(stderr, "No options for module `%s'\n", module); + + exit(0); + } + + if(opts_idx >= sizeof(opts) / sizeof(*opts)) { + fprintf(stderr, "Too many module options\n"); + return -1; + } + + opts[opts_idx] = strdup(arg); + if(!opts[opts_idx]) + error("strdup"); + opts_idx++; + + return 0; +} + +static int set_raw(CLIF_option *optn, char *arg) { + char buf[1024]; + + module = "raw"; + + snprintf(buf, sizeof(buf), "protocol=%s", arg); + return set_mod_option(optn, buf); +} + +static int set_wait_specs(CLIF_option *optn, char *arg) { + UNUSED(optn); + char *p, *q; + + here_factor = near_factor = 0; + + wait_secs = strtod(p = arg, &q); + if(q == p) + return -1; + if(!*q++) + return 0; + + here_factor = strtod(p = q, &q); + if(q == p) + return -1; + if(!*q++) + return 0; + + near_factor = strtod(p = q, &q); + if(q == p || *q) + return -1; + + return 0; +} + +static int set_host(CLIF_argument *argm, char *arg, int index) { + UNUSED(argm); + UNUSED(index); + if(getaddr(arg, &dst_addr) < 0) + return -1; + + dst_name = arg; + + /* i.e., guess it by the addr in cmdline... */ + if(!af) + af = dst_addr.sa.sa_family; + + return 0; +} + +static CLIF_option option_list[] = { + { "4", 0, 0, "Use IPv4", set_af, (void *) 4, 0, CLIF_EXTRA }, + { "6", 0, 0, "Use IPv6", set_af, (void *) 6, 0, 0 }, + { "d", "debug", 0, "Enable socket level debugging", + CLIF_set_flag, &debug, 0, 0 }, + { "F", "dont-fragment", 0, "Do not fragment packets", + CLIF_set_flag, &dontfrag, 0, CLIF_ABBREV }, + { "f", "first", "first_ttl", "Start from the %s hop (instead from 1)", + CLIF_set_uint, &first_hop, 0, 0 }, + { "g", "gateway", "gate", "Route packets through the specified gateway " + "(maximum " _TEXT(MAX_GATEWAYS_4) " for IPv4 and " + _TEXT(MAX_GATEWAYS_6) " for IPv6)", + add_gateway, 0, 0, CLIF_SEVERAL }, + { "I", "icmp", 0, "Use ICMP ECHO for tracerouting", + set_module, "icmp", 0, 0 }, + { "T", "tcp", 0, "Use TCP SYN for tracerouting (default " + "port is " _TEXT(DEF_TCP_PORT) ")", + set_module, "tcp", 0, 0 }, + { "i", "interface", "device", "Specify a network interface " + "to operate with", + CLIF_set_string, &device, 0, 0 }, + { "m", "max-hops", "max_ttl", "Set the max number of hops (max TTL " + "to be reached). Default is " _TEXT(DEF_HOPS), + CLIF_set_uint, &max_hops, 0, 0 }, + { "N", "sim-queries", "squeries", "Set the number of probes " + "to be tried simultaneously (default is " + _TEXT(DEF_SIM_PROBES) ")", + CLIF_set_uint, &sim_probes, 0, 0 }, + { "n", 0, 0, "Do not resolve IP addresses to their domain names", + CLIF_set_flag, &noresolve, 0, 0 }, + { "p", "port", "port", "Set the destination port to use. " + "It is either initial udp port value for " + "\"default\" method (incremented by each probe, " + "default is " _TEXT(DEF_START_PORT) "), " + "or initial seq for \"icmp\" (incremented as well, " + "default from 1), or some constant destination port" + " for other methods (with default of " + _TEXT(DEF_TCP_PORT) " for \"tcp\", " + _TEXT(DEF_UDP_PORT) " for \"udp\", etc.)", + set_port, &dst_port_seq, 0, 0 }, + { "t", "tos", "tos", "Set the TOS (IPv4 type of service) or TC " + "(IPv6 traffic class) value for outgoing packets", + CLIF_set_uint, &tos, 0, 0 }, + { "l", "flowlabel", "flow_label", "Use specified %s for IPv6 packets", + CLIF_set_uint, &flow_label, 0, 0 }, + { "w", "wait", "MAX,HERE,NEAR", "Wait for a probe no more than HERE " + "(default " _TEXT(DEF_HERE_FACTOR) ") times longer " + "than a response from the same hop, or no more " + "than NEAR (default " _TEXT(DEF_NEAR_FACTOR) ") " + "times than some next hop, or MAX (default " + _TEXT(DEF_WAIT_SECS) ") seconds " + "(float point values allowed too)", + set_wait_specs, 0, 0, 0 }, + { "q", "queries", "nqueries", "Set the number of probes per each hop. " + "Default is " _TEXT(DEF_NUM_PROBES), + CLIF_set_uint, &probes_per_hop, 0, 0 }, + { "r", 0, 0, "Bypass the normal routing and send directly to a host " + "on an attached network", + CLIF_set_flag, &noroute, 0, 0 }, + { "s", "source", "src_addr", "Use source %s for outgoing packets", + set_source, 0, 0, 0 }, + { "z", "sendwait", "sendwait", "Minimal time interval between probes " + "(default " _TEXT(DEF_SEND_SECS) "). If the value " + "is more than 10, then it specifies a number " + "in milliseconds, else it is a number of seconds " + "(float point values allowed too)", + CLIF_set_double, &send_secs, 0, 0 }, + { "e", "extensions", 0, "Show ICMP extensions (if present), " + "including MPLS", + CLIF_set_flag, &extension, 0, CLIF_ABBREV }, + { "A", "as-path-lookups", 0, "Perform AS path lookups in routing " + "registries and print results directly after " + "the corresponding addresses", + CLIF_set_flag, &as_lookups, 0, 0 }, + { "M", "module", "name", "Use specified module (either builtin or " + "external) for traceroute operations. Most methods " + "have their shortcuts (`-I' means `-M icmp' etc.)", + CLIF_set_string, &module, 0, CLIF_EXTRA }, + { "O", "options", "OPTS", "Use module-specific option %s for the " + "traceroute module. Several %s allowed, separated " + "by comma. If %s is \"help\", print info about " + "available options", + set_mod_option, 0, 0, CLIF_SEVERAL | CLIF_EXTRA }, + { 0, "sport", "num", "Use source port %s for outgoing packets. " + "Implies `-N 1'", + set_port, &src_port, 0, CLIF_EXTRA }, + #ifdef SO_MARK + { 0, "fwmark", "num", "Set firewall mark for outgoing packets", + CLIF_set_uint, &fwmark, 0, 0 }, + #endif + { "U", "udp", 0, "Use UDP to particular port for tracerouting " + "(instead of increasing the port per each probe), " + "default port is " _TEXT(DEF_UDP_PORT), + set_module, "udp", 0, CLIF_EXTRA }, + { 0, "UL", 0, "Use UDPLITE for tracerouting (default dest port is " + _TEXT(DEF_UDP_PORT) ")", + set_module, "udplite", 0, CLIF_ONEDASH | CLIF_EXTRA }, + { "D", "dccp", 0, "Use DCCP Request for tracerouting (default " + "port is " _TEXT(DEF_DCCP_PORT) ")", + set_module, "dccp", 0, CLIF_EXTRA }, + { "P", "protocol", "prot", "Use raw packet of protocol %s " + "for tracerouting", + set_raw, 0, 0, CLIF_EXTRA }, + { 0, "mtu", 0, "Discover MTU along the path being traced. " + "Implies `-F -N 1'", + CLIF_set_flag, &mtudisc, 0, CLIF_EXTRA }, + { 0, "back", 0, "Guess the number of hops in the backward path " + "and print if it differs", + CLIF_set_flag, &backward, 0, CLIF_EXTRA }, + CLIF_VERSION_OPTION (version_string), + CLIF_HELP_OPTION, + CLIF_END_OPTION + }; + +static CLIF_argument arg_list[] = { + { "host", "The host to traceroute to", + set_host, 0, CLIF_STRICT }, + { "packetlen", "The full packet length (default is the length of " + "an IP header plus " _TEXT(DEF_DATA_LEN) "). Can be " + "ignored or increased to a minimal allowed value", + CLIF_arg_int, &packet_len, 0 }, + CLIF_END_ARGUMENT + }; + +static void do_it(void); + +int traceroute_main(int argc, char *argv[]) { + + setlocale(LC_ALL, ""); + setlocale(LC_NUMERIC, "C"); /* avoid commas in msec printed */ + + check_progname(argv[0]); + + if(CLIF_parse(argc, argv, option_list, arg_list, + CLIF_MAY_JOIN_ARG | CLIF_HELP_EMPTY) < 0 + ) + return -EADDRNOTAVAIL; //exit(2); + + ops = tr_get_module(module); + if(!ops) { + ex_error("Unknown traceroute module %s", module); + return -2; + } + + if(!first_hop || first_hop > max_hops) { + ex_error("first hop out of range"); + return -3; + } + if(max_hops > MAX_HOPS) { + ex_error("max hops cannot be more than " _TEXT(MAX_HOPS)); + return -4; + } + if(!probes_per_hop || probes_per_hop > MAX_PROBES) { + ex_error("no more than " _TEXT(MAX_PROBES) " probes per hop"); + return -5; + } + if(wait_secs < 0 || here_factor < 0 || near_factor < 0) { + ex_error("bad wait specifications `%g,%g,%g' used", + wait_secs, here_factor, near_factor); + return -6; + } + if(packet_len > MAX_PACKET_LEN) { + ex_error("too big packetlen %d specified", packet_len); + return -7; + } + if(src_addr.sa.sa_family && src_addr.sa.sa_family != af) { + ex_error("IP version mismatch in addresses specified"); + return -8; + } + if(send_secs < 0) { + ex_error("bad sendtime `%g' specified", send_secs); + return -9; + } + if(send_secs >= 10) /* it is milliseconds */ + send_secs /= 1000; + + if(af == AF_INET6 && (tos || flow_label)) + dst_addr.sin6.sin6_flowinfo = + htonl(((tos & 0xff) << 20) | (flow_label & 0x000fffff)); + + if(src_port) { + src_addr.sin.sin_port = htons((uint16_t) src_port); + src_addr.sa.sa_family = af; + } + + if(src_port || ops->one_per_time) { + sim_probes = 1; + here_factor = near_factor = 0; + } + + /* make sure we don't std{in,out,err} to open sockets */ + make_fd_used(0); + make_fd_used(1); + make_fd_used(2); + + if(init_ip_options() == -1) + return -10; + + header_len = (af == AF_INET ? sizeof(struct iphdr) + : + sizeof(struct ip6_hdr)) + + rtbuf_len + ops->header_len; + + if(mtudisc) { + dontfrag = 1; + sim_probes = 1; + if(packet_len < 0) + packet_len = MAX_PACKET_LEN; + } + + if(packet_len < 0) { + if(DEF_DATA_LEN >= ops->header_len) + data_len = DEF_DATA_LEN - ops->header_len; + } else { + if(packet_len >= (int) header_len) + data_len = packet_len - header_len; + } + + num_probes = max_hops * probes_per_hop; + probes = calloc(num_probes, sizeof(*probes)); + if(!probes) { + error("calloc"); + return -11; + } + + if(ops->options && opts_idx > 1) { + opts[0] = strdup(module); /* aka argv[0] ... */ + if(CLIF_parse(opts_idx, opts, ops->options, 0, CLIF_KEYWORD) < 0) + return -12; //exit(2); + } + + if(ops->init(&dst_addr, dst_port_seq, &data_len) < 0) { + ex_error("trace method's init failed"); + return -13; + } + + do_it(); + return 0; +} + +/* PRINT STUFF */ + +static void print_header(void) { + + /* Note, without ending new-line! */ + log_printf("traceroute to %s (%s), %u hops max, %zu byte packets", + dst_name, addr2str(&dst_addr), max_hops, + header_len + data_len); + fflush(stdout); +} + +static bool print_addr(sockaddr_any *res) { + bool is_final = false; + const char *str; + + if(!res->sa.sa_family) + return is_final; + + str = addr2str(res); + + if(noresolve) { + log_printf("%s", str); + if(str && !strcmp(dst_name, str)) + is_final = true; + } + else { + char buf[1024]; + + buf[0] = '\0'; + getnameinfo(&res->sa, sizeof(*res), buf, sizeof(buf), + 0, 0, NI_IDN); + log_printf(" %s (%s)", buf[0] ? buf : str, str); + if(buf[0] && !strcmp(dst_name, buf)) + is_final = true; + else + if(str && !strcmp(dst_name, str)) + is_final = true; + } + + if(as_lookups) + log_printf(" [%s]", get_as_path(str)); + + return is_final; +} + +static bool print_probe(probe *pb) { + bool is_final = false; + unsigned int idx = (pb - probes); + unsigned int ttl = idx / probes_per_hop + 1; + unsigned int np = idx % probes_per_hop; + + if(np == 0) + log_printf("\n%2u ", ttl); + + if(!pb->res.sa.sa_family) + log_printf(" *"); + else { + int prn = !np; /* print if the first... */ + + if(np) { /* ...and if differs with previous */ + probe *p; + + /* skip expired */ + for(p = pb - 1; np && !p->res.sa.sa_family; p--, np--) + ; + + if(!np || + !equal_addr(&p->res, &pb->res) || + (p->ext != pb->ext && + !(p->ext && pb->ext && !strcmp(p->ext, pb->ext))) || + (backward && p->recv_ttl != pb->recv_ttl) + ) + prn = 1; + } + + if(prn) { + is_final = print_addr(&pb->res); + if(pb->ext) + log_printf(" <%s>", pb->ext); + + if(backward && pb->recv_ttl) { + int hops = ttl2hops(pb->recv_ttl); + if(hops != (int) ttl) + log_printf(" '-%d'", hops); + } + } + } + + if(pb->recv_time) { + double diff = pb->recv_time - pb->send_time; + + log_printf(" %.3f ms", diff * 1000); + } + + if(pb->err_str[0]) + log_printf(" %s", pb->err_str); + + fflush(stdout); + + return is_final; +} + +static void print_end(void) { + + log_printf("\n"); +} + +/* Compute timeout stuff */ + +static double get_timeout(probe *pb) { + double value; + + if(here_factor) { + /* check for already replied from the same hop */ + int i, idx = (pb - probes); + probe *p = &probes[idx - (idx % probes_per_hop)]; + + for(i = 0; i < (int) probes_per_hop; i++, p++) { + /* `p == pb' skipped since !pb->done */ + + if(p->done && (value = p->recv_time - p->send_time) > 0) { + value += DEF_WAIT_PREC; + value *= here_factor; + return value < wait_secs ? value : wait_secs; + } + } + } + + if(near_factor) { + /* check forward for already replied */ + probe *p, *endp = probes + num_probes; + + for(p = pb + 1; p < endp && p->send_time; p++) { + + if(p->done && (value = p->recv_time - p->send_time) > 0) { + value += DEF_WAIT_PREC; + value *= near_factor; + return value < wait_secs ? value : wait_secs; + } + } + } + + return wait_secs; +} + +/* Check expiration stuff */ + +static void check_expired(probe *pb) { + int idx = (pb - probes); + probe *p, *endp = probes + num_probes; + probe *fp = NULL, *pfp = NULL; + + if(!pb->done) /* an ops method still not release it */ + return; + + /* check all the previous in the same hop */ + for(p = &probes[idx - (idx % probes_per_hop)]; p < pb; p++) { + + if(!p->done || /* too early to decide something */ + !p->final /* already ttl-exceeded in the same hop */ + ) + return; + + pfp = p; /* some of the previous probes is final */ + } + + /* check forward all the sent probes */ + for(p = pb + 1; p < endp && p->send_time; p++) { + + if(p->done) { /* some next probe already done... */ + if(!p->final) /* ...was ttl-exceeded. OK, we are expired. */ + return; + else { + fp = p; + break; + } + } + } + + if(!fp) /* no any final probe found. Assume expired. */ + return; + + /* Well. There is a situation "*(this) * * * * ... * * final" + We cannot guarantee that "final" is in its right place. + We've sent "sim_probes" simultaneously, and the final hop + can drop some of them and answer only for latest ones. + If we can detect/assume that it so, then just put "final" + to the (pseudo-expired) "this" place. + */ + + /* It seems that the case of "answers for latest ones only" + occurs mostly with icmp_unreach error answers ("!H" etc.). + Icmp_echoreply, tcp_reset and even icmp_port_unreach looks + like going in the right order. + */ + if(!fp->err_str[0]) /* not an icmp_unreach error report... */ + return; + + if(pfp || + (idx % probes_per_hop) + (fp - pb) < probes_per_hop + ) { + /* Either some previous (pfp) or some next probe + in this hop is final. It means that the whole hop is final. + Do the replace (it also causes further "final"s to be shifted + here too). + */ + goto replace_by_final; + } + + /* If the final probe is an icmp_unreachable report + (either in a case of some error, like "!H", or just port_unreach), + it could follow the "time-exceed" report from the *same* hop. + */ + for(p = pb - 1; p >= probes; p--) { + if(equal_addr(&p->res, &fp->res)) { + /* ...Yes. Put "final" to the "this" place. */ + goto replace_by_final; + } + } + + if(fp->recv_ttl) { + /* Consider the ttl value of the report packet and guess where + the "final" should be. If it seems that it should be + in the same hop as "this", then do replace. + */ + int back_hops, ttl; + + /* We assume that the reporting one has an initial ttl value + of either 64, or 128, or 255. It is most widely used + in the modern routers and computers. + The idea comes from tracepath(1) routine. + */ + back_hops = ttl2hops(fp->recv_ttl); + + /* It is possible that the back path differs from the forward + and therefore has different number of hops. To minimize + such an influence, get the nearest previous time-exceeded + probe and compare with it. + */ + for(p = pb - 1; p >= probes; p--) { + if(p->done && !p->final && p->recv_ttl) { + int hops = ttl2hops(p->recv_ttl); + + if(hops < back_hops) { + ttl = (p - probes) / probes_per_hop + 1; + back_hops = (back_hops - hops) + ttl; + break; + } + } + } + + ttl = idx / probes_per_hop + 1; + if(back_hops == ttl) + /* Yes! It seems that "final" should be at "this" place */ + goto replace_by_final; + else if(back_hops < ttl) + /* Hmmm... Assume better to replace here too... */ + goto replace_by_final; + + } + + /* No idea what to do. Assume expired. */ + + return; + + replace_by_final: + + *pb = *fp; + + memset(fp, 0, sizeof(*fp)); + /* block extra re-send */ + fp->send_time = 1.; + + return; +} + +probe *probe_by_seq(int seq) { + int n; + + if(seq <= 0) + return NULL; + + for(n = 0; n < (int) num_probes; n++) { + if(probes[n].seq == seq) + return &probes[n]; + } + + return NULL; +} + +probe *probe_by_sk(int sk) { + int n; + + if(sk <= 0) + return NULL; + + for(n = 0; n < (int) num_probes; n++) { + if(probes[n].sk == sk) + return &probes[n]; + } + + return NULL; +} + +static void poll_callback(int fd, int revents) { + + ops->recv_probe(fd, revents); +} + +static void do_it(void) { + int start = (first_hop - 1) * probes_per_hop; + int end = num_probes; + double last_send = 0; + + print_header(); + + while(start < end) { + int n, num = 0; + double next_time = 0; + double now_time = get_time(); + + for(n = start; n < end; n++) { + probe *pb = &probes[n]; + + if(n == start && /* probably time to print... */ + !pb->done && pb->send_time /* ...but yet not replied */ + ) { + double expire_time = pb->send_time + get_timeout(pb); + + if(expire_time > now_time) + next_time = expire_time; + else { + ops->expire_probe(pb); + check_expired(pb); + } + } + + if(pb->done) { + + if(n == start) { /* can print it now */ + if(print_probe(pb)) { + pb->final = 1; + } + //log_printf("(host=%s,%s recv_ttl=%d)", dst_name, (host) ? host : "-", pb->recv_ttl); + start++; + } + + /* { + char buf[1024]; + buf[0] = '\0'; + getnameinfo(&(pb->res.sa), sizeof((pb->res)), buf, sizeof(buf),0, 0, NI_IDN); + if(buf[0] && !strcmp(dst_name, buf)) + pb->real_final = true; + //else + //if(str && !strcmp(dst_name, str)) + // pb->real_final = true; + }*/ + + if(pb->final) + end = (n / probes_per_hop + 1) * probes_per_hop; + + continue; + } + + if(!pb->send_time) { + int ttl; + double next; + + if(send_secs && (next = last_send + send_secs) > now_time) { + next_time = next; + break; + } + + ttl = n / probes_per_hop + 1; + + ops->send_probe(pb, ttl); + + if(!pb->send_time) { + if(next_time) + break; /* have chances later */ + else + error("send probe"); + } + + last_send = pb->send_time; + } + + if(!next_time) + next_time = pb->send_time + get_timeout(pb); + + num++; + if(num >= (int) sim_probes) + break; + } + + if(next_time) { + double timeout = next_time - get_time(); + + if(timeout < 0) + timeout = 0; + + do_poll(timeout, poll_callback); + } + + } + + print_end(); + + return; +} + +void tune_socket(int sk) { + int i = 0; + + if(debug) { + i = 1; + if(setsockopt(sk, SOL_SOCKET, SO_DEBUG, &i, sizeof(i)) < 0) + error("setsockopt SO_DEBUG"); + } + +#ifdef SO_MARK + if(fwmark) { + if(setsockopt(sk, SOL_SOCKET, SO_MARK, + &fwmark, sizeof(fwmark)) < 0 + ) + error("setsockopt SO_MARK"); + } +#endif + + if(rtbuf && rtbuf_len) { + if(af == AF_INET) { + if(setsockopt(sk, IPPROTO_IP, IP_OPTIONS, + rtbuf, rtbuf_len) < 0 + ) + error("setsockopt IP_OPTIONS"); + } + else if(af == AF_INET6) { + if(setsockopt(sk, IPPROTO_IPV6, IPV6_RTHDR, + rtbuf, rtbuf_len) < 0 + ) + error("setsockopt IPV6_RTHDR"); + } + } + + bind_socket(sk); + + if(af == AF_INET) { + + i = dontfrag ? IP_PMTUDISC_PROBE : IP_PMTUDISC_DONT; + if(setsockopt(sk, SOL_IP, IP_MTU_DISCOVER, &i, sizeof(i)) < 0 && + (!dontfrag || (i = IP_PMTUDISC_DO, + setsockopt(sk, SOL_IP, IP_MTU_DISCOVER, &i, sizeof(i)) < 0)) + ) + error("setsockopt IP_MTU_DISCOVER"); + + if(tos) { + i = tos; + if(setsockopt(sk, SOL_IP, IP_TOS, &i, sizeof(i)) < 0) + error("setsockopt IP_TOS"); + } + + } + else if(af == AF_INET6) { + + i = dontfrag ? IPV6_PMTUDISC_PROBE : IPV6_PMTUDISC_DONT; + if(setsockopt(sk, SOL_IPV6, IPV6_MTU_DISCOVER, &i, sizeof(i)) < 0 && + (!dontfrag || (i = IPV6_PMTUDISC_DO, + setsockopt(sk, SOL_IPV6, IPV6_MTU_DISCOVER, &i, sizeof(i)) < 0)) + ) + error("setsockopt IPV6_MTU_DISCOVER"); + + if(flow_label) { + struct in6_flowlabel_req_ flr; + + memset(&flr, 0, sizeof(flr)); + flr.flr_label = htonl(flow_label & 0x000fffff); + flr.flr_action = IPV6_FL_A_GET; + flr.flr_flags = IPV6_FL_F_CREATE; + flr.flr_share = IPV6_FL_S_ANY; + memcpy(&flr.flr_dst, &dst_addr.sin6.sin6_addr, + sizeof(flr.flr_dst)); + + if(setsockopt(sk, IPPROTO_IPV6, IPV6_FLOWLABEL_MGR, + &flr, sizeof(flr)) < 0 + ) + error("setsockopt IPV6_FLOWLABEL_MGR"); + } + + if(tos) { + i = tos; + if(setsockopt(sk, IPPROTO_IPV6, IPV6_TCLASS, + &i, sizeof(i)) < 0 + ) + error("setsockopt IPV6_TCLASS"); + } + + if(tos || flow_label) { + i = 1; + if(setsockopt(sk, IPPROTO_IPV6, IPV6_FLOWINFO_SEND, + &i, sizeof(i)) < 0 + ) + error("setsockopt IPV6_FLOWINFO_SEND"); + } + } + + if(noroute) { + i = noroute; + if(setsockopt(sk, SOL_SOCKET, SO_DONTROUTE, &i, sizeof(i)) < 0) + error("setsockopt SO_DONTROUTE"); + } + + use_timestamp(sk); + + use_recv_ttl(sk); + + fcntl(sk, F_SETFL, O_NONBLOCK); + + return; +} + +void parse_icmp_res(probe *pb, int type, int code, int info) { + char *str = NULL; + char buf[sizeof(pb->err_str)]; + + if(af == AF_INET) { + + if(type == ICMP_TIME_EXCEEDED) { + if(code == ICMP_EXC_TTL) + return; + } + else if(type == ICMP_DEST_UNREACH) { + + switch (code) { + case ICMP_UNREACH_NET: + case ICMP_UNREACH_NET_UNKNOWN: + case ICMP_UNREACH_ISOLATED: + case ICMP_UNREACH_TOSNET: + str = "!N"; + break; + + case ICMP_UNREACH_HOST: + case ICMP_UNREACH_HOST_UNKNOWN: + case ICMP_UNREACH_TOSHOST: + str = "!H"; + break; + + case ICMP_UNREACH_NET_PROHIB: + case ICMP_UNREACH_HOST_PROHIB: + case ICMP_UNREACH_FILTER_PROHIB: + str = "!X"; + break; + + case ICMP_UNREACH_PORT: + /* dest host is reached */ + str = ""; + break; + + case ICMP_UNREACH_PROTOCOL: + str = "!P"; + break; + + case ICMP_UNREACH_NEEDFRAG: + snprintf(buf, sizeof(buf), "!F-%d", info); + str = buf; + break; + + case ICMP_UNREACH_SRCFAIL: + str = "!S"; + break; + + case ICMP_UNREACH_HOST_PRECEDENCE: + str = "!V"; + break; + + case ICMP_UNREACH_PRECEDENCE_CUTOFF: + str = "!C"; + break; + + default: + snprintf(buf, sizeof(buf), "!<%u>", code); + str = buf; + break; + } + } + + } + else if(af == AF_INET6) { + + if(type == ICMP6_TIME_EXCEEDED) { + if(code == ICMP6_TIME_EXCEED_TRANSIT) + return; + } + else if(type == ICMP6_DST_UNREACH) { + + switch (code) { + + case ICMP6_DST_UNREACH_NOROUTE: + str = "!N"; + break; + + case ICMP6_DST_UNREACH_BEYONDSCOPE: + case ICMP6_DST_UNREACH_ADDR: + str = "!H"; + break; + + case ICMP6_DST_UNREACH_ADMIN: + str = "!X"; + break; + + case ICMP6_DST_UNREACH_NOPORT: + /* dest host is reached */ + str = ""; + break; + + default: + snprintf(buf, sizeof(buf), "!<%u>", code); + str = buf; + break; + } + } + else if(type == ICMP6_PACKET_TOO_BIG) { + snprintf(buf, sizeof(buf), "!F-%d", info); + str = buf; + } + } + + if(!str) { + snprintf(buf, sizeof(buf), "!<%u-%u>", type, code); + str = buf; + } + + if(*str) { + strncpy(pb->err_str, str, sizeof(pb->err_str)); + pb->err_str[sizeof(pb->err_str) - 1] = '\0'; + } + // final present + pb->final = 1; + + return; +} + +static void parse_local_res(probe *pb, int ee_errno, int info) { + + if(ee_errno == EMSGSIZE && info != 0) { + snprintf(pb->err_str, sizeof(pb->err_str) - 1, "!F-%d", info); + pb->final = 1; + return; + } + + errno = ee_errno; + error("local recverr"); +} + +void probe_done(probe *pb) { + + if(pb->sk) { + del_poll(pb->sk); + close(pb->sk); + pb->sk = 0; + } + + pb->seq = 0; + + pb->done = 1; +} + +void recv_reply(int sk, int err, check_reply_t check_reply) { + struct msghdr msg; + sockaddr_any from; + struct iovec iov; + int n; + probe *pb; + char buf[1280]; /* min mtu for ipv6 ( >= 576 for ipv4) */ + char *bufp = buf; + char control[1024]; + struct cmsghdr *cm; + double recv_time = 0; + int recv_ttl = 0; + struct sock_extended_err *ee = NULL; + + memset(&msg, 0, sizeof(msg)); + msg.msg_name = &from; + msg.msg_namelen = sizeof(from); + msg.msg_control = control; + msg.msg_controllen = sizeof(control); + iov.iov_base = buf; + iov.iov_len = sizeof(buf); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + n = recvmsg(sk, &msg, err ? MSG_ERRQUEUE : 0); + if(n < 0) + return; + + /* when not MSG_ERRQUEUE, AF_INET returns full ipv4 header + on raw sockets... + */ + + if(!err && + af == AF_INET && + /* XXX: Assume that the presence of an extra header means + that it is not a raw socket... + */ + ops->header_len == 0 + ) { + struct iphdr *ip = (struct iphdr *) bufp; + int hlen; + + if(n < (int) sizeof(struct iphdr)) + return; + + hlen = ip->ihl << 2; + if(n < hlen) + return; + + bufp += hlen; + n -= hlen; + } + + pb = check_reply(sk, err, &from, bufp, n); + if(!pb) { + + /* for `frag needed' case at the local host, + kernel >= 3.13 sends local error (no more icmp) + */ + if(!n && err && dontfrag) { + pb = &probes[(first_hop - 1) * probes_per_hop]; + if(pb->done) + return; + } else + return; + } + + /* Parse CMSG stuff */ + + for(cm = CMSG_FIRSTHDR(&msg); cm; cm = CMSG_NXTHDR(&msg, cm)) { + void *ptr = CMSG_DATA(cm); + + if(cm->cmsg_level == SOL_SOCKET) { + + if(cm->cmsg_type == SO_TIMESTAMP) { + struct timeval *tv = (struct timeval *) ptr; + + recv_time = tv->tv_sec + tv->tv_usec / 1000000.; + } + } + else if(cm->cmsg_level == SOL_IP) { + + if(cm->cmsg_type == IP_TTL) + recv_ttl = *((int *) ptr); + else if(cm->cmsg_type == IP_RECVERR) { + + ee = (struct sock_extended_err *) ptr; + + if(ee->ee_origin != SO_EE_ORIGIN_ICMP && + ee->ee_origin != SO_EE_ORIGIN_LOCAL + ) + return; + + /* dgram icmp sockets might return extra things... */ + if(ee->ee_origin == SO_EE_ORIGIN_ICMP && + (ee->ee_type == ICMP_SOURCE_QUENCH || + ee->ee_type == ICMP_REDIRECT) + ) + return; + } + } + else if(cm->cmsg_level == SOL_IPV6) { + + if(cm->cmsg_type == IPV6_HOPLIMIT) + recv_ttl = *((int *) ptr); + else if(cm->cmsg_type == IPV6_RECVERR) { + + ee = (struct sock_extended_err *) ptr; + + if(ee->ee_origin != SO_EE_ORIGIN_ICMP6 && + ee->ee_origin != SO_EE_ORIGIN_LOCAL + ) + return; + } + } + } + + if(!recv_time) + recv_time = get_time(); + + if(!err) + memcpy(&pb->res, &from, sizeof(pb->res)); + + pb->recv_time = recv_time; + + pb->recv_ttl = recv_ttl; + + if(ee && ee->ee_origin != SO_EE_ORIGIN_LOCAL) { /* icmp or icmp6 */ + memcpy(&pb->res, SO_EE_OFFENDER(ee), sizeof(pb->res)); + parse_icmp_res(pb, ee->ee_type, ee->ee_code, ee->ee_info); + } + + if(ee && ee->ee_origin == SO_EE_ORIGIN_LOCAL) + parse_local_res(pb, ee->ee_errno, ee->ee_info); + + if(ee && + mtudisc && + ee->ee_info >= header_len && + ee->ee_info < header_len + data_len + ) { + data_len = ee->ee_info - header_len; + + probe_done(pb); + + /* clear this probe (as actually the previous hop answers here) + but fill its `err_str' by the info obtained. Ugly, but easy... + */ + memset(pb, 0, sizeof(*pb)); + snprintf(pb->err_str, sizeof(pb->err_str) - 1, "F=%d", ee->ee_info); + + return; + } + + if(ee && + extension && + header_len + n >= (128 + 8) && /* at least... (rfc4884) */ + header_len <= 128 && /* paranoia */ + ((af == AF_INET && (ee->ee_type == ICMP_TIME_EXCEEDED || + ee->ee_type == ICMP_DEST_UNREACH || + ee->ee_type == ICMP_PARAMETERPROB)) || + (af == AF_INET6 && (ee->ee_type == ICMP6_TIME_EXCEEDED || + ee->ee_type == ICMP6_DST_UNREACH)) + ) + ) { + int step; + int offs = 128 - header_len; + + if(n > (int) data_len) + step = 0; /* guaranteed at 128 ... */ + else + step = af == AF_INET ? 4 : 8; + + handle_extensions(pb, bufp + offs, n - offs, step); + } + + probe_done(pb); +} + +int equal_addr(const sockaddr_any *a, const sockaddr_any *b) { + + if(!a->sa.sa_family) + return 0; + + if(a->sa.sa_family != b->sa.sa_family) + return 0; + + if(a->sa.sa_family == AF_INET6) + return !memcmp(&a->sin6.sin6_addr, &b->sin6.sin6_addr, + sizeof(a->sin6.sin6_addr)); + else + return !memcmp(&a->sin.sin_addr, &b->sin.sin_addr, + sizeof(a->sin.sin_addr)); + return 0; /* not reached */ +} + +void bind_socket(int sk) { + sockaddr_any *addr, tmp; + + if(device) { + if(setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE, + device, strlen(device) + 1) < 0 + ) + error("setsockopt SO_BINDTODEVICE"); + } + + if(!src_addr.sa.sa_family) { + memset(&tmp, 0, sizeof(tmp)); + tmp.sa.sa_family = af; + addr = &tmp; + } else + addr = &src_addr; + + if(bind(sk, &addr->sa, sizeof(*addr)) < 0) + error("bind"); + + return; +} + +void use_timestamp(int sk) { + int n = 1; + + setsockopt(sk, SOL_SOCKET, SO_TIMESTAMP, &n, sizeof(n)); + /* foo on errors... */ +} + +void use_recv_ttl(int sk) { + int n = 1; + + if(af == AF_INET) + setsockopt(sk, SOL_IP, IP_RECVTTL, &n, sizeof(n)); + else if(af == AF_INET6) + setsockopt(sk, SOL_IPV6, IPV6_RECVHOPLIMIT, &n, sizeof(n)); + /* foo on errors */ +} + +void use_recverr(int sk) { + int val = 1; + + if(af == AF_INET) { + if(setsockopt(sk, SOL_IP, IP_RECVERR, &val, sizeof(val)) < 0) + error("setsockopt IP_RECVERR"); + } + else if(af == AF_INET6) { + if(setsockopt(sk, SOL_IPV6, IPV6_RECVERR, &val, sizeof(val)) < 0) + error("setsockopt IPV6_RECVERR"); + } +} + +void set_ttl(int sk, int ttl) { + + if(af == AF_INET) { + if(setsockopt(sk, SOL_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) + error("setsockopt IP_TTL"); + } + else if(af == AF_INET6) { + if(setsockopt(sk, SOL_IPV6, IPV6_UNICAST_HOPS, + &ttl, sizeof(ttl)) < 0 + ) + error("setsockopt IPV6_UNICAST_HOPS"); + } +} + +int do_send(int sk, const void *data, size_t len, const sockaddr_any *addr) { + int res; + + if(!addr || raw_can_connect()) + res = send(sk, data, len, 0); + else + res = sendto(sk, data, len, 0, &addr->sa, sizeof(*addr)); + + if(res < 0) { + if(errno == ENOBUFS || errno == EAGAIN) + return res; + if(errno == EMSGSIZE) + return 0; /* recverr will say more... */ + error("send"); /* not recoverable */ + } + + return res; +} + +/* There is a bug in the kernel before 2.6.25, which prevents icmp errors + to be obtained by MSG_ERRQUEUE for ipv6 connected raw sockets. + */ +static int can_connect = -1; + +#define VER(A,B,C,D) (((((((A) << 8) | (B)) << 8) | (C)) << 8) | (D)) + +int raw_can_connect(void) { + + if(can_connect < 0) { + + if(af == AF_INET) + can_connect = 1; + else { /* AF_INET6 */ + struct utsname uts; + int n; + unsigned int a, b, c, d = 0; + + if(uname(&uts) < 0) + return 0; + + n = sscanf(uts.release, "%u.%u.%u.%u", &a, &b, &c, &d); + can_connect = (n >= 3 && VER (a, b, c, d) >= VER(2, 6, 25, 0)); + } + } + + return can_connect; +} + +/** + * Traceroute host + * + * @addr[in] host name or IP address + * @hops[out] hops count + * @time_usec[out] latency in microseconds + * @return 0 Ok, -1 error + */ +int traceroute_util(const char *addr, int *hops, int *time_usec) +{ + UNUSED(hops); + int type = 6; // ipv4 or ipv6 + int argc = 3; + const char *argv[argc]; + if(type != 4) + argv[0] = "traceroute6"; + else + argv[0] = "traceroute4"; + argv[1] = "-4"; // ipv4 + argv[2] = addr; + + *hops = 0; + *time_usec = 0; + + int ret = traceroute_main(argc, (char**) argv); + if(!ret) { + ret = -1; + for(int i = 0; i < (int) num_probes; i++) { + probe *one_probe = probes + i; + if(one_probe->done && one_probe->final && one_probe->recv_ttl) { + *hops = i / DEF_NUM_PROBES + 1; + *time_usec = (int) ((one_probe->recv_time - one_probe->send_time) * 1000000); + // if error -> not found host + if(!strlen(one_probe->err_str)) + ret = 1; + break; + } + } + /*if(one_probe->done) + printf("%d(%d) dseq=%d sk=%d done=%d final=%d recv_ttl=%d dt=%lf err='%s'\n", i + 1, + i / DEF_NUM_PROBES + 1, + one_probe->seq, one_probe->sk, one_probe->done, + one_probe->final, one_probe->recv_ttl, one_probe->recv_time - one_probe->send_time, + one_probe->err_str);*/ + } + free(probes); + + return (ret == 1) ? 0 : ret; +} diff --git a/modules/net/iputils/traceroute/traceroute.h b/modules/net/iputils/traceroute/traceroute.h new file mode 100644 index 0000000000000000000000000000000000000000..0db40c544ed51febe2379ba64de5bbfe1b689057 --- /dev/null +++ b/modules/net/iputils/traceroute/traceroute.h @@ -0,0 +1,107 @@ +/* + Copyright (c) 2006, 2007 Dmitry Butskoy + <buc@citadel.stu.neva.ru> + License: GPL v2 or any later + + See COPYING for the status of this software. +*/ + +#include <netinet/in.h> + +#include "clif.h" +#include "../iputils.h" + +union common_sockaddr { + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; +}; +typedef union common_sockaddr sockaddr_any; + +struct probe_struct { + int done; + int final; + sockaddr_any res; + double send_time; + double recv_time; + int recv_ttl; + int sk; + int seq; + char *ext; + char err_str[16]; /* assume enough */ +}; +typedef struct probe_struct probe; + + +struct tr_module_struct { + struct tr_module_struct *next; + const char *name; + int (*init) (const sockaddr_any *dest, + unsigned int port_seq, size_t *packet_len); + void (*send_probe) (probe *pb, int ttl); + void (*recv_probe) (int fd, int revents); + void (*expire_probe) (probe *pb); + CLIF_option *options; /* per module options, if any */ + int one_per_time; /* no simultaneous probes */ + size_t header_len; /* additional header length (aka for udp) */ +}; +typedef struct tr_module_struct tr_module; + + +#define __TEXT(X) #X +#define _TEXT(X) __TEXT(X) + +#define DEF_START_PORT 33434 /* start for traditional udp method */ +#define DEF_UDP_PORT 53 /* dns */ +#define DEF_TCP_PORT 80 /* web */ +#define DEF_DCCP_PORT DEF_START_PORT /* is it a good choice?... */ +#define DEF_RAW_PROT 253 /* for experimentation and testing, rfc3692 */ + + +void error (const char *str) __attribute__((noreturn)); +void error_or_perm (const char *str) __attribute__((noreturn)); + +double get_time (void); +void tune_socket (int sk); +void parse_icmp_res (probe *pb, int type, int code, int info); +void probe_done (probe *pb); + +typedef probe *(*check_reply_t) (int sk, int err, sockaddr_any *from, + char *buf, size_t len); +void recv_reply (int sk, int err, check_reply_t check_reply); + +int equal_addr (const sockaddr_any *a, const sockaddr_any *b); + +probe *probe_by_seq (int seq); +probe *probe_by_sk (int sk); + +void bind_socket (int sk); +void use_timestamp (int sk); +void use_recv_ttl (int sk); +void use_recverr (int sk); +void set_ttl (int sk, int ttl); +int do_send (int sk, const void *data, size_t len, const sockaddr_any *addr); + +void add_poll (int fd, int events); +void del_poll (int fd); +void do_poll (double timeout, void (*callback) (int fd, int revents)); + +void handle_extensions (probe *pb, char *buf, int len, int step); +const char *get_as_path (const char *query); + +int raw_can_connect (void); + +unsigned int random_seq (void); +uint16_t in_csum (const void *ptr, size_t len); + + +void tr_register_module (tr_module *module); +const tr_module *tr_get_module (const char *name); + +#define TR_MODULE(MOD) \ +static void __init_ ## MOD (void) __attribute__ ((constructor)); \ +static void __init_ ## MOD (void) { \ + \ + tr_register_module (&MOD); \ +} + diff --git a/modules/net/srv/CMakeLists.txt b/modules/net/srv/CMakeLists.txt index a59328f7d37bf096e0715bcd14fcc5bac8683407..2e61dfc24495455bd746aa45f2a7f8a66c6b6fbb 100644 --- a/modules/net/srv/CMakeLists.txt +++ b/modules/net/srv/CMakeLists.txt @@ -1,12 +1,13 @@ cmake_minimum_required(VERSION 2.8) project (dap_chain_net_srv) -set(DAP_CHAIN_NET_SRV_SRCS *.c) +file(GLOB DAP_CHAIN_NET_SRV_SRCS *.c) -set(DAP_CHAIN_NET_SRV_HEADERS include/*.h) +file(GLOB DAP_CHAIN_NET_SRV_HEADERS include/*.h) add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_NET_SRV_SRCS} ${DAP_CHAIN_NET_SRV_HEADERS}) target_link_libraries(dap_chain_net_srv dap_core dap_crypto dap_chain dap_chain_crypto dap_chain_net dap_chain_wallet) target_include_directories(dap_chain_net_srv INTERFACE .) +target_include_directories(${PROJECT_NAME} PUBLIC include) diff --git a/modules/net/win32/ip.h b/modules/net/win32/ip.h new file mode 100644 index 0000000000000000000000000000000000000000..df3d54a8345b77e0aa00585583c68806b6b8fa0e --- /dev/null +++ b/modules/net/win32/ip.h @@ -0,0 +1,301 @@ +#pragma once + +/* Copyright (C) 1991-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU 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. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef __NETINET_IP_H +#define __NETINET_IP_H 1 + +//#include <features.h> +//#include <sys/types.h> + +//#include <netinet/in.h> + +struct timestamp + { + uint8_t len; + uint8_t ptr; +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int flags:4; + unsigned int overflow:4; +#elif __BYTE_ORDER == __BIG_ENDIAN + unsigned int overflow:4; + unsigned int flags:4; +#else +# error "Please fix <bits/endian.h>" +#endif + uint32_t data[9]; + }; + +struct iphdr + { +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int ihl:4; + unsigned int version:4; +#elif __BYTE_ORDER == __BIG_ENDIAN + unsigned int version:4; + unsigned int ihl:4; +#else +# error "Please fix <bits/endian.h>" +#endif + uint8_t tos; + uint16_t tot_len; + uint16_t id; + uint16_t frag_off; + uint8_t ttl; + uint8_t protocol; + uint16_t check; + uint32_t saddr; + uint32_t daddr; + /*The options start here. */ + }; + +#ifdef __USE_MISC +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ip.h 8.1 (Berkeley) 6/10/93 + */ + +/* + * Definitions for internet protocol version 4. + * Per RFC 791, September 1981. + */ + +/* + * Structure of an internet header, naked of options. + */ +struct ip + { +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int ip_hl:4; /* header length */ + unsigned int ip_v:4; /* version */ +#endif +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned int ip_v:4; /* version */ + unsigned int ip_hl:4; /* header length */ +#endif + uint8_t ip_tos; /* type of service */ + unsigned short ip_len; /* total length */ + unsigned short ip_id; /* identification */ + unsigned short ip_off; /* fragment offset field */ +#define IP_RF 0x8000 /* reserved fragment flag */ +#define IP_DF 0x4000 /* dont fragment flag */ +#define IP_MF 0x2000 /* more fragments flag */ +#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ + uint8_t ip_ttl; /* time to live */ + uint8_t ip_p; /* protocol */ + unsigned short ip_sum; /* checksum */ + struct in_addr ip_src, ip_dst; /* source and dest address */ + }; + +/* + * Time stamp option structure. + */ +struct ip_timestamp + { + uint8_t ipt_code; /* IPOPT_TS */ + uint8_t ipt_len; /* size of structure (variable) */ + uint8_t ipt_ptr; /* index of current entry */ +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int ipt_flg:4; /* flags, see below */ + unsigned int ipt_oflw:4; /* overflow counter */ +#endif +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned int ipt_oflw:4; /* overflow counter */ + unsigned int ipt_flg:4; /* flags, see below */ +#endif + uint32_t data[9]; + }; +#endif /* __USE_MISC */ + +#define IPVERSION 4 /* IP version number */ +#define IP_MAXPACKET 65535 /* maximum packet size */ + +/* + * Definitions for Explicit Congestion Notification (ECN) + * + * Taken from RFC-3168, Section 5. + */ + +#define IPTOS_ECN_MASK 0x03 +#define IPTOS_ECN(x) ((x) & IPTOS_ECN_MASK) +#define IPTOS_ECN_NOT_ECT 0x00 +#define IPTOS_ECN_ECT1 0x01 +#define IPTOS_ECN_ECT0 0x02 +#define IPTOS_ECN_CE 0x03 + +/* + * Definitions for IP differentiated services code points (DSCP) + * + * Taken from RFC-2597, Section 6 and RFC-2598, Section 2.3. + */ + +#define IPTOS_DSCP_MASK 0xfc +#define IPTOS_DSCP(x) ((x) & IPTOS_DSCP_MASK) +#define IPTOS_DSCP_AF11 0x28 +#define IPTOS_DSCP_AF12 0x30 +#define IPTOS_DSCP_AF13 0x38 +#define IPTOS_DSCP_AF21 0x48 +#define IPTOS_DSCP_AF22 0x50 +#define IPTOS_DSCP_AF23 0x58 +#define IPTOS_DSCP_AF31 0x68 +#define IPTOS_DSCP_AF32 0x70 +#define IPTOS_DSCP_AF33 0x78 +#define IPTOS_DSCP_AF41 0x88 +#define IPTOS_DSCP_AF42 0x90 +#define IPTOS_DSCP_AF43 0x98 +#define IPTOS_DSCP_EF 0xb8 + +/* + * In RFC 2474, Section 4.2.2.1, the Class Selector Codepoints subsume + * the old ToS Precedence values. + */ + +#define IPTOS_CLASS_MASK 0xe0 +#define IPTOS_CLASS(class) ((class) & IPTOS_CLASS_MASK) +#define IPTOS_CLASS_CS0 0x00 +#define IPTOS_CLASS_CS1 0x20 +#define IPTOS_CLASS_CS2 0x40 +#define IPTOS_CLASS_CS3 0x60 +#define IPTOS_CLASS_CS4 0x80 +#define IPTOS_CLASS_CS5 0xa0 +#define IPTOS_CLASS_CS6 0xc0 +#define IPTOS_CLASS_CS7 0xe0 + +#define IPTOS_CLASS_DEFAULT IPTOS_CLASS_CS0 + +/* + * Definitions for IP type of service (ip_tos) [deprecated; use DSCP + * and CS definitions above instead.] + */ +#define IPTOS_TOS_MASK 0x1E +#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK) +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 +#define IPTOS_LOWCOST 0x02 +#define IPTOS_MINCOST IPTOS_LOWCOST + +/* + * Definitions for IP precedence (also in ip_tos) [also deprecated.] + */ +#define IPTOS_PREC_MASK IPTOS_CLASS_MASK +#define IPTOS_PREC(tos) IPTOS_CLASS(tos) +#define IPTOS_PREC_NETCONTROL IPTOS_CLASS_CS7 +#define IPTOS_PREC_INTERNETCONTROL IPTOS_CLASS_CS6 +#define IPTOS_PREC_CRITIC_ECP IPTOS_CLASS_CS5 +#define IPTOS_PREC_FLASHOVERRIDE IPTOS_CLASS_CS4 +#define IPTOS_PREC_FLASH IPTOS_CLASS_CS3 +#define IPTOS_PREC_IMMEDIATE IPTOS_CLASS_CS2 +#define IPTOS_PREC_PRIORITY IPTOS_CLASS_CS1 +#define IPTOS_PREC_ROUTINE IPTOS_CLASS_CS0 + +/* + * Definitions for options. + */ +#define IPOPT_COPY 0x80 +#define IPOPT_CLASS_MASK 0x60 +#define IPOPT_NUMBER_MASK 0x1f + +#define IPOPT_COPIED(o) ((o) & IPOPT_COPY) +#define IPOPT_CLASS(o) ((o) & IPOPT_CLASS_MASK) +#define IPOPT_NUMBER(o) ((o) & IPOPT_NUMBER_MASK) + +#define IPOPT_CONTROL 0x00 +#define IPOPT_RESERVED1 0x20 +#define IPOPT_DEBMEAS 0x40 +#define IPOPT_MEASUREMENT IPOPT_DEBMEAS +#define IPOPT_RESERVED2 0x60 + +#define IPOPT_EOL 0 /* end of option list */ +#define IPOPT_END IPOPT_EOL +#define IPOPT_NOP 1 /* no operation */ +#define IPOPT_NOOP IPOPT_NOP + +#define IPOPT_RR 7 /* record packet route */ +#define IPOPT_TS 68 /* timestamp */ +#define IPOPT_TIMESTAMP IPOPT_TS +#define IPOPT_SECURITY 130 /* provide s,c,h,tcc */ +#define IPOPT_SEC IPOPT_SECURITY +#define IPOPT_LSRR 131 /* loose source route */ +#define IPOPT_SATID 136 /* satnet id */ +#define IPOPT_SID IPOPT_SATID +#define IPOPT_SSRR 137 /* strict source route */ +#define IPOPT_RA 148 /* router alert */ + +/* + * Offsets to fields in options other than EOL and NOP. + */ +#define IPOPT_OPTVAL 0 /* option ID */ +#define IPOPT_OLEN 1 /* option length */ +#define IPOPT_OFFSET 2 /* offset within option */ +#define IPOPT_MINOFF 4 /* min value of above */ + +#define MAX_IPOPTLEN 40 + +/* flag bits for ipt_flg */ +#define IPOPT_TS_TSONLY 0 /* timestamps only */ +#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ +#define IPOPT_TS_PRESPEC 3 /* specified modules only */ + +/* bits for security (not byte swapped) */ +#define IPOPT_SECUR_UNCLASS 0x0000 +#define IPOPT_SECUR_CONFID 0xf135 +#define IPOPT_SECUR_EFTO 0x789a +#define IPOPT_SECUR_MMMM 0xbc4d +#define IPOPT_SECUR_RESTR 0xaf13 +#define IPOPT_SECUR_SECRET 0xd788 +#define IPOPT_SECUR_TOPSECRET 0x6bc5 + +/* + * Internet implementation parameters. + */ +#define MAXTTL 255 /* maximum time to live (seconds) */ +#define IPDEFTTL 64 /* default ttl, from RFC 1340 */ +#define IPFRAGTTL 60 /* time to live for frags, slowhz */ +#define IPTTLDEC 1 /* subtracted when forwarding */ + +#define IP_MSS 576 /* default maximum segment size */ + + +#endif /* netinet/ip.h */ diff --git a/modules/net/win32/iphdr.h b/modules/net/win32/iphdr.h new file mode 100644 index 0000000000000000000000000000000000000000..f2533f910cce0e5c6f35a56018a4bea307313b27 --- /dev/null +++ b/modules/net/win32/iphdr.h @@ -0,0 +1,112 @@ +#pragma once + +// Align on a 1-byte boundary +//#include <pshpack1.h> + +#pragma pack(push,1) + +// IPv4 header +typedef struct ip_hdr +{ + unsigned char ip_verlen; // 4-bit IPv4 version + // 4-bit header length (in 32-bit words) + unsigned char ip_tos; // IP type of service + unsigned short ip_totallength; // Total length + unsigned short ip_id; // Unique identifier + unsigned short ip_offset; // Fragment offset field + unsigned char ip_ttl; // Time to live + unsigned char ip_protocol; // Protocol(TCP,UDP etc) + unsigned short ip_checksum; // IP checksum + unsigned int ip_srcaddr; // Source address + unsigned int ip_destaddr; // Source address + +} IPV4_HDR, *PIPV4_HDR, FAR * LPIPV4_HDR; + +// IPv4 option header +typedef struct ipv4_option_hdr +{ + unsigned char opt_code; // option type + unsigned char opt_len; // length of the option header + unsigned char opt_ptr; // offset into options + unsigned long opt_addr[9]; // list of IPv4 addresses +} IPV4_OPTION_HDR, *PIPV4_OPTION_HDR, FAR *LPIPV4_OPTION_HDR; + +// ICMP header +typedef struct icmp_hdr +{ + unsigned char icmp_type; + unsigned char icmp_code; + unsigned short icmp_checksum; + unsigned short icmp_id; + unsigned short icmp_sequence; +} ICMP_HDR, *PICMP_HDR, FAR *LPICMP_HDR; + +// IPv6 protocol header +typedef struct ipv6_hdr +{ + unsigned long ipv6_vertcflow; // 4-bit IPv6 version + // 8-bit traffic class + // 20-bit flow label + unsigned short ipv6_payloadlen; // payload length + unsigned char ipv6_nexthdr; // next header protocol value + unsigned char ipv6_hoplimit; // TTL + struct in6_addr ipv6_srcaddr; // Source address + struct in6_addr ipv6_destaddr; // Destination address +} IPV6_HDR, *PIPV6_HDR, FAR * LPIPV6_HDR; + +// IPv6 fragment header +typedef struct ipv6_fragment_hdr +{ + unsigned char ipv6_frag_nexthdr; + unsigned char ipv6_frag_reserved; + unsigned short ipv6_frag_offset; + unsigned long ipv6_frag_id; +} IPV6_FRAGMENT_HDR, *PIPV6_FRAGMENT_HDR, FAR * LPIPV6_FRAGMENT_HDR; + +// ICMPv6 header +typedef struct icmpv6_hdr { + unsigned char icmp6_type; + unsigned char icmp6_code; + unsigned short icmp6_checksum; +} ICMPV6_HDR; + +// ICMPv6 echo request body +typedef struct icmpv6_echo_request +{ + unsigned short icmp6_echo_id; + unsigned short icmp6_echo_sequence; +} ICMPV6_ECHO_REQUEST; + +// Define the UDP header +typedef struct udp_hdr +{ + unsigned short src_portno; // Source port no. + unsigned short dst_portno; // Dest. port no. + unsigned short udp_length; // Udp packet length + unsigned short udp_checksum; // Udp checksum (optional) +} UDP_HDR, *PUDP_HDR; + +// IPv4 option for record route +#define IP_RECORD_ROUTE 0x7 + +// ICMP6 protocol value (used in the socket call and IPv6 header) +#define IPPROTO_ICMP6 58 + +// ICMP types and codes +#define ICMPV4_ECHO_REQUEST_TYPE 8 +#define ICMPV4_ECHO_REQUEST_CODE 0 +#define ICMPV4_ECHO_REPLY_TYPE 0 +#define ICMPV4_ECHO_REPLY_CODE 0 +#define ICMPV4_MINIMUM_HEADER 8 + +// ICPM6 types and codes +#define ICMPV6_ECHO_REQUEST_TYPE 128 +#define ICMPV6_ECHO_REQUEST_CODE 0 +#define ICMPV6_ECHO_REPLY_TYPE 129 +#define ICMPV6_ECHO_REPLY_CODE 0 + +#pragma pack(pop) + +// Restore byte alignment back to default + +//#include <poppack.h> diff --git a/modules/service/app-db/CMakeLists.txt b/modules/service/app-db/CMakeLists.txt index f985c4768b86b1013d910d6d0fae5ea97aa23cc5..07e2032d562fe8b001b9fcf9d999d9ff09de3cfe 100644 --- a/modules/service/app-db/CMakeLists.txt +++ b/modules/service/app-db/CMakeLists.txt @@ -1,12 +1,13 @@ cmake_minimum_required(VERSION 2.8) project (dap_chain_net_srv_app_db) -set(DAP_CHAIN_NET_SRV_APP_DB_SRCS *.c) +file(GLOB DAP_CHAIN_NET_SRV_APP_DB_SRCS *.c) -set(DAP_CHAIN_NET_SRV_APP_DB_HEADERS include/*.h) +file(GLOB DAP_CHAIN_NET_SRV_APP_DB_HEADERS include/*.h) add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_NET_SRV_APP_DB_SRCS} ${DAP_CHAIN_NET_SRV_APP_DB_HEADERS}) target_link_libraries(dap_chain_net_srv_app_db dap_chain_net_srv dap_chain_net_srv_app) target_include_directories(dap_chain_net_srv_app_db INTERFACE .) +target_include_directories(${PROJECT_NAME} PUBLIC include) diff --git a/modules/service/app/CMakeLists.txt b/modules/service/app/CMakeLists.txt index 9e3e5248f7ae721a5d2d3f19fd160f6ed6ac61db..1c01d2e7eb5c9d4b270e64964beec690463c14ca 100644 --- a/modules/service/app/CMakeLists.txt +++ b/modules/service/app/CMakeLists.txt @@ -1,12 +1,12 @@ cmake_minimum_required(VERSION 2.8) project (dap_chain_net_srv_app) -set(DAP_CHAIN_NET_SRV_APP_SRCS *.c) +file(GLOB DAP_CHAIN_NET_SRV_APP_SRCS *.c) -set(DAP_CHAIN_NET_SRV_APP_HEADERS include/*.h) +file(GLOB DAP_CHAIN_NET_SRV_APP_HEADERS include/*.h) add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_NET_SRV_APP_SRCS} ${DAP_CHAIN_NET_SRV_APP_HEADERS}) target_link_libraries(dap_chain_net_srv_app dap_core dap_crypto dap_chain dap_chain_crypto dap_chain_net dap_chain_net_srv) target_include_directories(dap_chain_net_srv_app INTERFACE .) - +target_include_directories(${PROJECT_NAME} PUBLIC include) diff --git a/modules/service/datum/CMakeLists.txt b/modules/service/datum/CMakeLists.txt index fdd050dd60211b8436ac4bd5401f028ca367e587..63a0dcfb2e0869110192fc05fe70642b778f4e6f 100644 --- a/modules/service/datum/CMakeLists.txt +++ b/modules/service/datum/CMakeLists.txt @@ -1,12 +1,13 @@ cmake_minimum_required(VERSION 2.8) project (dap_chain_net_srv_datum) -set(DAP_CHAIN_NET_SRV_DATUM_SRCS *.c) +file(GLOB DAP_CHAIN_NET_SRV_DATUM_SRCS *.c) -set(DAP_CHAIN_NET_SRV_DATUM_HEADERS include/*.h) +file(GLOB DAP_CHAIN_NET_SRV_DATUM_HEADERS include/*.h) add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_NET_SRV_DATUM_SRCS} ${DAP_CHAIN_NET_SRV_DATUM_HEADERS}) target_link_libraries(dap_chain_net_srv_datum dap_chain_net_srv) target_include_directories(dap_chain_net_srv_datum INTERFACE .) +target_include_directories(${PROJECT_NAME} PUBLIC include) diff --git a/modules/service/mining-pool/CMakeLists.txt b/modules/service/mining-pool/CMakeLists.txt index 275db1112051cfa0348938a06430676b0e5c22f2..449cc79415cb2064ace36198131a21ce364b9053 100644 --- a/modules/service/mining-pool/CMakeLists.txt +++ b/modules/service/mining-pool/CMakeLists.txt @@ -1,11 +1,12 @@ cmake_minimum_required(VERSION 2.8) project (dap_chain_net_srv_datum_pool) -set(DAP_CHAIN_NET_SRV_DATUM_POOL_SRCS *.c) -set(DAP_CHAIN_NET_SRV_DATUM_POOL_HEADERS include/*.h) +file(GLOB DAP_CHAIN_NET_SRV_DATUM_POOL_SRCS *.c) +file(GLOB DAP_CHAIN_NET_SRV_DATUM_POOL_HEADERS include/*.h) add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_NET_SRV_DATUM_POOL_SRCS} ${DAP_CHAIN_NET_SRV_DATUM_POOL_HEADERS}) target_link_libraries(dap_chain_net_srv_datum_pool dap_chain_net_srv dap_chain_net_srv_datum) target_include_directories(dap_chain_net_srv_datum_pool INTERFACE .) +target_include_directories(${PROJECT_NAME} PUBLIC include) diff --git a/modules/service/vpn/CMakeLists.txt b/modules/service/vpn/CMakeLists.txt index 3f295e39c7e75039bcb684d7b867b50611b16418..b5aff036848642477f65d519763f43ac7e43fffc 100644 --- a/modules/service/vpn/CMakeLists.txt +++ b/modules/service/vpn/CMakeLists.txt @@ -1,9 +1,9 @@ cmake_minimum_required(VERSION 2.8) project (dap_chain_net_srv_vpn) -set(DAP_CHAIN_NET_SRV_VPN_SRCS *.c) +file(GLOB DAP_CHAIN_NET_SRV_VPN_SRCS *.c) -set(DAP_CHAIN_NET_SRV_VPN_HEADERS include/*.h) +file(GLOB DAP_CHAIN_NET_SRV_VPN_HEADERS include/*.h) if(WIN32) include_directories(../../../os/win32/) @@ -15,7 +15,8 @@ endif() add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_NET_SRV_VPN_SRCS} ${DAP_CHAIN_NET_SRV_VPN_HEADERS}) -target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_chain dap_chain_crypto dap_chain_net dap_chain_net_srv) +target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_stream dap_chain dap_chain_crypto dap_chain_net dap_chain_net_srv) target_include_directories(${PROJECT_NAME} INTERFACE .) +target_include_directories(${PROJECT_NAME} PUBLIC include) diff --git a/modules/type/block/CMakeLists.txt b/modules/type/block/CMakeLists.txt index 054678eae7cfe08fdfe52116eb300da7f90b1188..9ad9afa0a1947cbf544111cbc2c614eea395a577 100644 --- a/modules/type/block/CMakeLists.txt +++ b/modules/type/block/CMakeLists.txt @@ -1,12 +1,12 @@ cmake_minimum_required(VERSION 2.8) project (dap_chain_cs_block) -set(DAP_CHAIN_BLOCK_SRCS *.c) -set(DAP_CHAIN_BLOCK_HEADERS include/*.h) +file(GLOB DAP_CHAIN_BLOCK_SRCS *.c) +file(GLOB DAP_CHAIN_BLOCK_HEADERS include/*.h) add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_BLOCK_SRCS} ${DAP_CHAIN_BLOCK_HEADERS}) target_link_libraries(dap_chain_cs_block dap_core dap_crypto dap_chain dap_chain_crypto ) target_include_directories(dap_chain_cs_block INTERFACE .) - +target_include_directories(${PROJECT_NAME} PUBLIC include) diff --git a/modules/type/dag/CMakeLists.txt b/modules/type/dag/CMakeLists.txt index 6bc479d7566e341b1f43a589e7c1f831b2a014b7..9682f2ec103d78beac964e643c8305753d5995e2 100644 --- a/modules/type/dag/CMakeLists.txt +++ b/modules/type/dag/CMakeLists.txt @@ -1,10 +1,10 @@ cmake_minimum_required(VERSION 2.8) project (dap_chain_cs_dag) -set(DAP_CHAIN_DAG_SRCS *.c) -set(DAP_CHAIN_DAG_HEADERS include/*.h) +file(GLOB DAP_CHAIN_DAG_SRCS *.c) +file(GLOB DAP_CHAIN_DAG_HEADERS include/*.h) add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_DAG_SRCS} ${DAP_CHAIN_DAG_HEADERS}) target_link_libraries(dap_chain_cs_dag dap_core dap_crypto dap_chain dap_chain_net dap_chain_crypto dap_chain_global_db) target_include_directories(dap_chain_cs_dag INTERFACE .) - +target_include_directories(${PROJECT_NAME} PUBLIC include) \ No newline at end of file diff --git a/modules/wallet/CMakeLists.txt b/modules/wallet/CMakeLists.txt index 5ca6539127b119601eda216412349acadb9b5224..534f7e44fc57278eed44d765415f37618e6999fa 100644 --- a/modules/wallet/CMakeLists.txt +++ b/modules/wallet/CMakeLists.txt @@ -1,11 +1,12 @@ cmake_minimum_required(VERSION 2.8) project (dap_chain_wallet) -set(DAP_CHAIN_WALLET_SRCS *.c) -set(DAP_CHAIN_WALLET_HEADERS include/*.h) +file(GLOB DAP_CHAIN_WALLET_SRCS *.c) +file(GLOB DAP_CHAIN_WALLET_HEADERS include/*.h) add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_WALLET_SRCS} ${DAP_CHAIN_WALLET_HEADERS}) target_link_libraries(dap_chain_wallet dap_core dap_crypto dap_chain dap_chain_crypto dap_chain_net) target_include_directories(dap_chain_wallet INTERFACE .) +target_include_directories(${PROJECT_NAME} PUBLIC include)