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
-
-[![Build Status](https://travis-ci.com/kelvinblockchain/libdap.svg?branch=master)](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
-
-[![Build Status](https://travis-ci.com/cellframe/libdap.svg?branch=master)](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
-
-[![Build Status](https://travis-ci.com/kelvinblockchain/libdap-client.svg?branch=master)](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
-
-[![Build Status](https://travis-ci.com/kelvinblockchain/libdap-server-core.svg?branch=master)](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
-
-[![Build Status](https://travis-ci.com/kelvinblockchain/libdap-server-udp.svg?branch=master)](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
-
-[![Build Status](https://travis-ci.com/kelvinblockchain/libdap-stream.svg?branch=master)](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*) &target;
+    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*) &target;
+    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)