├── .gitignore ├── .travis.yml ├── BUILD ├── LICENSE ├── README.md ├── WORKSPACE ├── example.gif ├── examples └── sample_scan.conf ├── external ├── glog.BUILD └── gmock.BUILD ├── flashroute ├── .clang-format ├── BUILD ├── address.cc ├── address.h ├── blacklist.cc ├── blacklist.h ├── blacklist_test.cc ├── bogon_filter.cc ├── bogon_filter.h ├── bounded_buffer.cc ├── bounded_buffer.h ├── dcb.cc ├── dcb.h ├── dcb_manager.cc ├── dcb_manager.h ├── dump_result.cc ├── dump_result.h ├── experiment.h ├── hitlist.cc ├── hitlist.h ├── main.cc ├── network.cc ├── network.h ├── output_parser.cc ├── output_parser.h ├── prober.h ├── single_host.cc ├── single_host.h ├── targets.cc ├── targets.h ├── traceroute.cc ├── traceroute.h ├── trie.cc ├── trie.h ├── trie_test.cc ├── udp_idempotent_prober.cc ├── udp_idempotent_prober.h ├── udp_prober.cc ├── udp_prober.h ├── udp_prober_test.cc ├── udp_prober_v6.cc ├── udp_prober_v6.h ├── utils.cc ├── utils.h └── utils_test.cc ├── lint-check.ssh ├── parsers ├── BUILD ├── example.py ├── example_jupyter.ipynb ├── jupyter.py ├── output_parser.py ├── requirements.txt └── utils │ ├── BUILD │ ├── dataset_comparison.cc │ ├── frequency_analysis.cc │ ├── hot_branch_analyzer.cc │ ├── reprobe_list_generator.cc │ ├── route_generator.cc │ ├── route_similarity_analysis.cc │ ├── unique_interface_counter.cc │ ├── utils.cc │ └── utils.h └── tools ├── BUILD ├── continuous_runner.py └── discovery_optimize_mode_runner.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | 53 | # Translations 54 | *.mo 55 | *.pot 56 | 57 | # Django stuff: 58 | *.log 59 | local_settings.py 60 | db.sqlite3 61 | 62 | # Flask stuff: 63 | instance/ 64 | .webassets-cache 65 | 66 | # Scrapy stuff: 67 | .scrapy 68 | 69 | # Sphinx documentation 70 | docs/_build/ 71 | 72 | # PyBuilder 73 | target/ 74 | 75 | # Jupyter Notebook 76 | .ipynb_checkpoints 77 | 78 | # IPython 79 | profile_default/ 80 | ipython_config.py 81 | 82 | # pyenv 83 | .python-version 84 | 85 | # pipenv 86 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 87 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 88 | # having no cross-platform support, pipenv may install dependencies that don’t work, or not 89 | # install all needed dependencies. 90 | #Pipfile.lock 91 | 92 | # celery beat schedule file 93 | celerybeat-schedule 94 | 95 | # SageMath parsed files 96 | *.sage.py 97 | 98 | # Environments 99 | .env 100 | .venv 101 | env/ 102 | venv/ 103 | ENV/ 104 | env.bak/ 105 | venv.bak/ 106 | 107 | # Spyder project settings 108 | .spyderproject 109 | .spyproject 110 | 111 | # Rope project settings 112 | .ropeproject 113 | 114 | # mkdocs documentation 115 | /site 116 | 117 | # mypy 118 | .mypy_cache/ 119 | .dmypy.json 120 | dmypy.json 121 | 122 | # Pyre type checker 123 | .pyre/ 124 | 125 | # Ark file 126 | cycle-20180101 127 | 128 | # Prerequisites 129 | *.d 130 | 131 | # Object files 132 | *.o 133 | *.ko 134 | *.obj 135 | *.elf 136 | 137 | # Linker output 138 | *.ilk 139 | *.map 140 | *.exp 141 | 142 | # Precompiled Headers 143 | *.gch 144 | *.pch 145 | 146 | # Libraries 147 | *.lib 148 | *.a 149 | *.la 150 | *.lo 151 | 152 | # Shared objects (inc. Windows DLLs) 153 | *.dll 154 | *.so 155 | *.so.* 156 | *.dylib 157 | 158 | # Executables 159 | *.exe 160 | *.out 161 | *.app 162 | *.i*86 163 | *.x86_64 164 | *.hex 165 | 166 | # Debug files 167 | *.dSYM/ 168 | *.su 169 | *.idb 170 | *.pdb 171 | 172 | # Kernel Module Compile Results 173 | *.mod* 174 | *.cmd 175 | .tmp_versions/ 176 | modules.order 177 | Module.symvers 178 | Mkfile.old 179 | dkms.conf 180 | 181 | # Mac 182 | .DS_Store 183 | .vscode/ 184 | 185 | # ============= Bazel temporary or config files ============= 186 | # Ignore backup files. 187 | *~ 188 | # Ignore Vim swap files. 189 | .*.swp 190 | # Ignore files generated by IDEs. 191 | /.classpath 192 | /.factorypath 193 | /.idea/ 194 | /.ijwb/ 195 | /.project 196 | /.settings 197 | /.vscode/ 198 | /bazel.iml 199 | # Ignore all bazel-* symlinks. There is no full list since this can change 200 | # based on the name of the directory bazel is cloned into. 201 | /bazel-* 202 | # Ignore outputs generated during Bazel bootstrapping. 203 | /output/ 204 | # Ignore jekyll build output. 205 | /production 206 | /.sass-cache 207 | # Bazelisk version file 208 | .bazelversion 209 | # ============= Bazel temporary or config files ============= 210 | 211 | # hitlist 212 | *.fsdb 213 | 214 | # executable 215 | traceroute/traceroute -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: bionic 2 | language: python 3 | python: 4 | - "3.6" 5 | addons: 6 | apt: 7 | sources: 8 | - ubuntu-toolchain-r-test 9 | packages: 10 | - wget 11 | - pkg-config 12 | - build-essential 13 | - gcc 14 | 15 | before_install: 16 | - wget https://github.com/bazelbuild/bazel/releases/download/3.7.2/bazel_3.7.2-linux-x86_64.deb 17 | - sudo dpkg -i bazel_3.7.2-linux-x86_64.deb 18 | 19 | script: 20 | - bazel build --cxxopt="--std=c++14" flashroute -------------------------------------------------------------------------------- /BUILD: -------------------------------------------------------------------------------- 1 | platform( 2 | name = "linux_x86", 3 | constraint_values = [ 4 | "@platforms//os:linux", 5 | "@platforms//cpu:x86_32", 6 | ":glibc_2_25", 7 | ], 8 | ) 9 | 10 | constraint_setting(name = "glibc_version") 11 | 12 | constraint_value( 13 | name = "glibc_2_25", 14 | constraint_setting = ":glibc_version", 15 | ) 16 | 17 | constraint_value( 18 | name = "glibc_2_26", 19 | constraint_setting = ":glibc_version", 20 | ) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-2019 Yuchen Huang 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. The names of the authors and copyright holders may not be used to 14 | endorse or promote products derived from this software without 15 | specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 18 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 20 | NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 22 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /WORKSPACE: -------------------------------------------------------------------------------- 1 | load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository", "new_git_repository") 2 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 3 | 4 | http_archive( 5 | name = "io_bazel_rules_go", 6 | urls = [ 7 | "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.22.2/rules_go-v0.22.2.tar.gz", 8 | "https://github.com/bazelbuild/rules_go/releases/download/v0.22.2/rules_go-v0.22.2.tar.gz", 9 | ], 10 | sha256 = "142dd33e38b563605f0d20e89d9ef9eda0fc3cb539a14be1bdb1350de2eda659", 11 | ) 12 | 13 | load("@io_bazel_rules_go//go:deps.bzl", "go_rules_dependencies", "go_register_toolchains") 14 | 15 | go_rules_dependencies() 16 | 17 | go_register_toolchains() 18 | 19 | http_archive( 20 | name = "bazel_gazelle", 21 | urls = [ 22 | "https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/bazel-gazelle/releases/download/v0.20.0/bazel-gazelle-v0.20.0.tar.gz", 23 | "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.20.0/bazel-gazelle-v0.20.0.tar.gz", 24 | ], 25 | sha256 = "d8c45ee70ec39a57e7a05e5027c32b1576cc7f16d9dd37135b0eddde45cf1b10", 26 | ) 27 | 28 | load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository") 29 | 30 | gazelle_dependencies() 31 | 32 | go_repository( 33 | name = "com_github_golang_glog", 34 | importpath = "github.com/golang/glog", 35 | commit = "23def4e6c14b4da8ac2ed8007337bc5eb5007998", 36 | ) 37 | 38 | git_repository( 39 | name = "com_github_nelhage_rules_boost", 40 | commit = "fb9f3c9a6011f966200027843d894923ebc9cd0b", 41 | remote = "https://github.com/nelhage/rules_boost", 42 | shallow_since = "1626494016 -0700", 43 | ) 44 | 45 | load("@com_github_nelhage_rules_boost//:boost/boost.bzl", "boost_deps") 46 | boost_deps() 47 | 48 | git_repository( 49 | name = "com_google_absl", 50 | commit = "278e0a071885a22dcd2fd1b5576cc44757299343", 51 | remote = "https://github.com/abseil/abseil-cpp.git", 52 | shallow_since = "1622559169 -0400", 53 | ) 54 | 55 | new_git_repository( 56 | name = "glog_repo", 57 | remote = "https://github.com/google/glog.git", 58 | commit = "b6a5e0524c28178985f0d228e9eaa43808dbec3c", 59 | build_file = "glog.BUILD", 60 | shallow_since = "1476946406 +0900", 61 | ) 62 | 63 | bind( 64 | name = "glog", 65 | actual = "@glog_repo//:glog" 66 | ) 67 | 68 | git_repository( 69 | name = "com_github_gflags", 70 | remote = "https://github.com/gflags/gflags.git", 71 | commit = "addd749114fab4f24b7ea1e0f2f837584389e52c", 72 | shallow_since = "1584534678 +0000", 73 | ) 74 | 75 | bind( 76 | name = "gflags", 77 | actual = "@com_github_gflags//:gflags", 78 | ) 79 | 80 | # Python Components Configuration 81 | http_archive( 82 | name = "rules_python", 83 | url = "https://github.com/bazelbuild/rules_python/releases/download/0.1.0/rules_python-0.1.0.tar.gz", 84 | sha256 = "b6d46438523a3ec0f3cead544190ee13223a52f6a6765a29eae7b7cc24cc83a0", 85 | ) 86 | 87 | # Only needed for PIP support: 88 | load("@rules_python//python:pip.bzl", "pip_install") 89 | 90 | pip_install( 91 | name = "parsers_deps", 92 | requirements = "//parsers:requirements.txt", 93 | python_interpreter = "python3" 94 | ) 95 | 96 | new_git_repository( 97 | name = "googletest", 98 | build_file = "gmock.BUILD", 99 | remote = "https://github.com/google/googletest", 100 | tag = "release-1.10.0", 101 | ) 102 | -------------------------------------------------------------------------------- /example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambdahuang/FlashRoute/1fe02b27e8af27eff0351d3b4fd02897ed2452bf/example.gif -------------------------------------------------------------------------------- /examples/sample_scan.conf: -------------------------------------------------------------------------------- 1 | # example global scans 2 | 3 | # General Configs 4 | --recommended_mode=false 5 | --sequential_scan=false 6 | --prober_type=udp 7 | --ttl_offset=0 8 | --split_ttl=16 9 | --granularity=24 10 | --probing_rate=100 11 | --default_payload_message="flashroute" 12 | 13 | # Preprobing Configurations 14 | --preprobing=true 15 | --distance_prediction=true 16 | --distance_prediction_prefix=24 17 | --proximity_span=5 18 | 19 | # forward probing 20 | --forward_probing=true 21 | --gaplimit=5 22 | 23 | # backward probing 24 | --remove_redundancy=true 25 | 26 | # Optimization: Read route length information from history probing result. 27 | --history_probing_result="" 28 | 29 | # Miscellaneous 30 | --bogon_filter_potaroo="" 31 | 32 | --scan_count=1 33 | --remove_redundancy=true 34 | 35 | --seed=0 36 | --remove_reserved_addresses=true -------------------------------------------------------------------------------- /external/glog.BUILD: -------------------------------------------------------------------------------- 1 | # Derived from https://github.com/google/glog/files/393474/BUILD.txt 2 | # 3 | # Currently gflags is not included, since having deps 4 | # of ["//external:gflags"] does not seem to let it find 5 | # "gflags/gflags.h". 6 | # 7 | # Currently we need to do 8 | # expoert GLOG_logtostderr=1 9 | # 10 | # To allow logging to stderr. 11 | cc_library( 12 | visibility = ["//visibility:public"], 13 | name = "glog", 14 | includes = ["src"], 15 | srcs = ["src/base/commandlineflags.h", 16 | "src/base/googleinit.h", 17 | "src/demangle.cc", 18 | "src/logging.cc", 19 | "src/symbolize.cc", 20 | "src/vlog_is_on.cc", 21 | "src/raw_logging.cc", 22 | "src/utilities.cc"], 23 | hdrs = ["src/base/mutex.h", 24 | "src/utilities.h", 25 | "src/demangle.h", 26 | "src/symbolize.h", 27 | "src/glog/log_severity.h", 28 | ":stl_logging_h", 29 | ":config_h", 30 | ":logging_h", 31 | ":vlog_is_on_h", 32 | ":raw_logging_h"], 33 | copts = [ 34 | # Disable warnings that exists in glog 35 | "-Wno-sign-compare", 36 | "-Wno-unused-local-typedefs", 37 | # Inject google namespace as "google" 38 | "-D_START_GOOGLE_NAMESPACE_='namespace google {'", 39 | "-D_END_GOOGLE_NAMESPACE_='}'", 40 | "-DGOOGLE_NAMESPACE='google'", 41 | # Allows src/base/mutex.h to include pthread.h. 42 | "-DHAVE_PTHREAD", 43 | # Allows src/logging.cc to determine the host name. 44 | "-DHAVE_SYS_UTSNAME_H", 45 | # System header files enabler for src/utilities.cc 46 | # Enable system calls from syscall.h 47 | "-DHAVE_SYS_SYSCALL_H", 48 | # Enable system calls from sys/time.h 49 | "-DHAVE_SYS_TIME_H", 50 | "-DHAVE_STDINT_H", 51 | "-DHAVE_STRING_H", 52 | # For logging.cc 53 | "-DHAVE_PREAD", 54 | ], 55 | ) 56 | 57 | # Below are the generation rules that generates the necessary header 58 | # files for glog. Originally they are generated by CMAKE 59 | # configure_file() command, which replaces certain template 60 | # placeholders in the .in files with provided values. 61 | 62 | # gen_sh is a bash script that provides the values for generated 63 | # header files. Under the hood it is just a wrapper over sed. 64 | genrule( 65 | name = "gen_sh", 66 | outs = [ 67 | "gen.sh", 68 | ], 69 | cmd = """ 70 | cat > $@ <<"EOF" 71 | #! /bin/sh 72 | sed -e 's/@ac_cv_have_unistd_h@/1/g' \ 73 | -e 's/@ac_cv_have_stdint_h@/1/g' \ 74 | -e 's/@ac_cv_have_systypes_h@/1/g' \ 75 | -e 's/@ac_cv_have_libgflags_h@/1/g' \ 76 | -e 's/@ac_cv_have_uint16_t@/1/g' \ 77 | -e 's/@ac_cv_have___builtin_expect@/1/g' \ 78 | -e 's/@ac_cv_have_.*@/0/g' \ 79 | -e 's/@ac_google_start_namespace@/namespace google {/g' \ 80 | -e 's/@ac_google_end_namespace@/}/g' \ 81 | -e 's/@ac_google_namespace@/google/g' \ 82 | -e 's/@ac_cv___attribute___noinline@/__attribute__((noinline))/g' \ 83 | -e 's/@ac_cv___attribute___noreturn@/__attribute__((noreturn))/g' \ 84 | -e 's/@ac_cv___attribute___printf_4_5@/__attribute__((__format__ (__printf__, 4, 5)))/g' 85 | EOF""" 86 | ) 87 | 88 | genrule( 89 | name = "config_h", 90 | srcs = [ 91 | "src/config.h.cmake.in", 92 | ], 93 | outs = [ 94 | "config.h", 95 | ], 96 | cmd = "awk '{ gsub(/^#cmakedefine/, \"//cmakedefine\"); print; }' $(<) > $(@)", 97 | ) 98 | 99 | genrule( 100 | name = "logging_h", 101 | srcs = [ 102 | "src/glog/logging.h.in", 103 | ], 104 | outs = [ 105 | "glog/logging.h", 106 | ], 107 | cmd = "$(location :gen_sh) < $(<) > $(@)", 108 | tools = [":gen_sh"], 109 | ) 110 | 111 | genrule( 112 | name = "raw_logging_h", 113 | srcs = [ 114 | "src/glog/raw_logging.h.in", 115 | ], 116 | outs = [ 117 | "glog/raw_logging.h", 118 | ], 119 | cmd = "$(location :gen_sh) < $(<) > $(@)", 120 | tools = [":gen_sh"], 121 | ) 122 | 123 | genrule( 124 | name = "stl_logging_h", 125 | srcs = [ 126 | "src/glog/stl_logging.h.in", 127 | ], 128 | outs = [ 129 | "glog/stl_logging.h", 130 | ], 131 | cmd = "$(location :gen_sh) < $(<) > $(@)", 132 | tools = [":gen_sh"], 133 | ) 134 | 135 | genrule( 136 | name = "vlog_is_on_h", 137 | srcs = [ 138 | "src/glog/vlog_is_on.h.in", 139 | ], 140 | outs = [ 141 | "glog/vlog_is_on.h", 142 | ], 143 | cmd = "$(location :gen_sh) < $(<) > $(@)", 144 | tools = [":gen_sh"], 145 | ) -------------------------------------------------------------------------------- /external/gmock.BUILD: -------------------------------------------------------------------------------- 1 | cc_library( 2 | name = "gtest", 3 | srcs = [ 4 | "googletest/src/gtest-all.cc", 5 | "googlemock/src/gmock-all.cc", 6 | ], 7 | hdrs = glob([ 8 | "**/*.h", 9 | "googletest/src/*.cc", 10 | "googlemock/src/*.cc", 11 | ]), 12 | includes = [ 13 | "googlemock", 14 | "googletest", 15 | "googletest/include", 16 | "googlemock/include", 17 | ], 18 | linkopts = ["-pthread"], 19 | visibility = ["//visibility:public"], 20 | ) 21 | 22 | cc_library( 23 | name = "gtest_main", 24 | srcs = ["googlemock/src/gmock_main.cc"], 25 | linkopts = ["-pthread"], 26 | visibility = ["//visibility:public"], 27 | deps = [":gtest"], 28 | ) -------------------------------------------------------------------------------- /flashroute/.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | MaxEmptyLinesToKeep: 1 -------------------------------------------------------------------------------- /flashroute/BUILD: -------------------------------------------------------------------------------- 1 | cc_library( 2 | name = "blacklist", 3 | srcs = ["blacklist.cc"], 4 | hdrs = ["blacklist.h"], 5 | copts = ["-std=c++14"], 6 | deps = [ 7 | ":address", 8 | ":utils", 9 | ":traceroute", 10 | "@boost//:format", 11 | "@com_google_absl//absl/strings", 12 | ] 13 | ) 14 | 15 | # cc_test( 16 | # name = "blacklist_test", 17 | # srcs = ["blacklist_test.cc"], 18 | # deps = [ 19 | # ":blacklist", 20 | # ":traceroute", 21 | # "@googletest//:gtest_main", 22 | # "@googletest//:gtest", 23 | # ], 24 | # ) 25 | 26 | cc_library( 27 | name = "network", 28 | hdrs = ["network.h"], 29 | srcs = ["network.cc"], 30 | copts = ["-std=c++14"], 31 | deps = [ 32 | ":address", 33 | ":prober", 34 | ":bounded_buffer", 35 | ":utils", 36 | "@boost//:asio", 37 | "@boost//:circular_buffer", 38 | "//external:glog", 39 | ], 40 | ) 41 | 42 | cc_library( 43 | name = "dcb_manager", 44 | hdrs = [ 45 | "dcb_manager.h" 46 | ], 47 | srcs = [ 48 | "dcb_manager.cc" 49 | ], 50 | copts = ["-std=c++14"], 51 | deps = [ 52 | ":address", 53 | ":dcb", 54 | ":utils", 55 | ], 56 | ) 57 | 58 | cc_library( 59 | name = "dcb", 60 | hdrs = [ 61 | "dcb.h" 62 | ], 63 | srcs = [ 64 | "dcb.cc" 65 | ], 66 | copts = ["-std=c++14"], 67 | deps = [ 68 | ":address", 69 | ":utils", 70 | ], 71 | ) 72 | 73 | 74 | cc_library( 75 | name = "traceroute", 76 | hdrs = [ 77 | "traceroute.h", 78 | ], 79 | srcs = [ 80 | "traceroute.cc", 81 | ], 82 | copts = ["-std=c++14"], 83 | deps = [ 84 | ":address", 85 | ":dcb", 86 | ":dcb_manager", 87 | ":utils", 88 | ":network", 89 | ":prober", 90 | ":dump_result", 91 | "@boost//:asio", 92 | "@boost//:format", 93 | "@com_google_absl//absl/strings", 94 | "//external:glog", 95 | ], 96 | ) 97 | 98 | cc_library( 99 | name = "address", 100 | hdrs = [ 101 | "address.h", 102 | ], 103 | srcs = [ 104 | "address.cc", 105 | ], 106 | deps = [ 107 | "@com_google_absl//absl/random", 108 | ], 109 | visibility = ["//visibility:public"], 110 | copts = ["-std=c++14"], 111 | ) 112 | 113 | cc_library( 114 | name = "utils", 115 | hdrs = ["utils.h"], 116 | srcs = ["utils.cc"], 117 | copts = ["-std=c++14"], 118 | visibility = ["//visibility:public"], 119 | deps = [ 120 | ":address", 121 | "@boost//:process", 122 | "@com_google_absl//absl/strings", 123 | "//external:glog", 124 | ], 125 | ) 126 | 127 | cc_library( 128 | name = "bounded_buffer", 129 | hdrs = ["bounded_buffer.h"], 130 | srcs = ["bounded_buffer.cc"], 131 | copts = ["-std=c++14"], 132 | deps = [ 133 | "@boost//:circular_buffer", 134 | "@boost//:bind", 135 | "@boost//:thread", 136 | "@boost//:timer", 137 | ], 138 | ) 139 | 140 | cc_library( 141 | name = "hitlist", 142 | hdrs = ["hitlist.h"], 143 | srcs = ["hitlist.cc"], 144 | copts = ["-std=c++14"], 145 | deps = [ 146 | "utils", 147 | ":traceroute", 148 | "@boost//:format", 149 | "@com_google_absl//absl/strings", 150 | ], 151 | ) 152 | 153 | cc_library( 154 | name = "targets", 155 | hdrs = ["targets.h"], 156 | srcs = ["targets.cc"], 157 | copts = ["-std=c++14"], 158 | deps = [ 159 | ":address", 160 | ":blacklist", 161 | ":bogon_filter", 162 | ":dcb_manager", 163 | ":utils", 164 | "//external:glog", 165 | "@boost//:format", 166 | ], 167 | ) 168 | 169 | cc_binary( 170 | name = "flashroute", 171 | srcs = ["main.cc"], 172 | copts = ["-std=c++14"], 173 | deps = [ 174 | ":dcb_manager", 175 | ":prober", 176 | ":blacklist", 177 | "hitlist", 178 | ":targets", 179 | ":utils", 180 | ":single_host", 181 | ":output_parser", 182 | ":bogon_filter", 183 | "@boost//:asio", 184 | "@boost//:format", 185 | "@com_google_absl//absl/flags:flag", 186 | "@com_google_absl//absl/flags:parse", 187 | "//external:gflags", 188 | "//external:glog", 189 | ], 190 | ) 191 | 192 | cc_test( 193 | name = "utils_tests", 194 | srcs = ["utils_test.cc"], 195 | deps = [ 196 | ":utils", 197 | ":address", 198 | "@googletest//:gtest_main", 199 | ], 200 | ) 201 | 202 | cc_library( 203 | name = "prober", 204 | hdrs = [ 205 | "prober.h", 206 | "udp_prober.h", 207 | "udp_prober_v6.h", 208 | "udp_idempotent_prober.h"], 209 | srcs = [ 210 | "udp_prober.cc", 211 | "udp_prober_v6.cc", 212 | "udp_idempotent_prober.cc"], 213 | copts = ["-std=c++14"], 214 | deps = [ 215 | ":address", 216 | ":utils", 217 | "//external:glog", 218 | ], 219 | ) 220 | 221 | cc_test( 222 | name = "prober_test", 223 | srcs = ["udp_prober_test.cc"], 224 | deps = [ 225 | ":prober", 226 | "@googletest//:gtest_main", 227 | ], 228 | ) 229 | 230 | cc_library( 231 | name = "dump_result", 232 | hdrs = ["dump_result.h"], 233 | srcs = ["dump_result.cc"], 234 | copts = ["-std=c++14"], 235 | visibility = ["//visibility:public"], 236 | deps = [ 237 | ":address", 238 | ":utils", 239 | ":bounded_buffer", 240 | "//external:glog", 241 | ], 242 | ) 243 | 244 | cc_library( 245 | name = "single_host", 246 | hdrs = ["single_host.h"], 247 | srcs = ["single_host.cc"], 248 | copts = ["-std=c++14"], 249 | deps = [ 250 | ":address", 251 | ":utils", 252 | ":network", 253 | ":prober", 254 | ":dcb_manager", 255 | "//external:glog", 256 | "@boost//:format", 257 | ], 258 | ) 259 | 260 | cc_library( 261 | name = "output_parser", 262 | hdrs = ["output_parser.h"], 263 | srcs = ["output_parser.cc"], 264 | copts = ["-std=c++14"], 265 | deps = [ 266 | ":utils", 267 | ":dcb_manager", 268 | "//external:glog", 269 | ], 270 | ) 271 | 272 | cc_library( 273 | name = "trie", 274 | hdrs = ["trie.h"], 275 | srcs = ["trie.cc"], 276 | copts = ["-std=c++14"], 277 | deps = [ 278 | ":utils", 279 | ":address", 280 | "//external:glog", 281 | ], 282 | ) 283 | 284 | cc_library( 285 | name = "bogon_filter", 286 | hdrs = ["bogon_filter.h"], 287 | srcs = ["bogon_filter.cc"], 288 | copts = ["-std=c++14"], 289 | deps = [ 290 | ":utils", 291 | ":trie", 292 | "//external:glog", 293 | "@com_google_absl//absl/strings", 294 | ], 295 | ) 296 | 297 | cc_test( 298 | name = "trie_test", 299 | srcs = ["trie_test.cc"], 300 | deps = [ 301 | ":utils", 302 | ":trie", 303 | "@googletest//:gtest_main", 304 | ], 305 | ) -------------------------------------------------------------------------------- /flashroute/address.cc: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #include "flashroute/address.h" 3 | 4 | #include 5 | #include 6 | 7 | #include "absl/random/random.h" 8 | 9 | 10 | namespace flashroute { 11 | Ipv4Address::Ipv4Address() { 12 | address_ = 0; 13 | } 14 | 15 | Ipv4Address::Ipv4Address(uint32_t ipv4) { 16 | address_ = ipv4; 17 | } 18 | 19 | Ipv4Address::Ipv4Address(const Ipv4Address& copy) { 20 | address_ = copy.address_; 21 | } 22 | 23 | Ipv4Address* Ipv4Address::clone() const { return new Ipv4Address(*this); } 24 | 25 | uint32_t Ipv4Address::getIpv4Address() const { 26 | return address_; 27 | } 28 | 29 | absl::uint128 Ipv4Address::getIpv6Address() const { 30 | return 0; 31 | } 32 | 33 | absl::uint128 Ipv4Address::getPrefix(uint8_t length) const { 34 | return address_ >> (32-length); 35 | } 36 | 37 | void Ipv4Address::randomizeAddress(uint8_t length) { 38 | uint32_t blockFactor = static_cast(std::pow(2, 32 - length)); 39 | absl::BitGen bitgen; 40 | address_ = (address_ >> (32 - length)) << (32 - length) | 41 | absl::uniform_int_distribution(0, blockFactor)(bitgen); 42 | } 43 | 44 | bool Ipv4Address::equal_to(const IpAddress& rhs) const { 45 | if (!rhs.isIpv4()) return false; 46 | return address_ == 47 | dynamic_cast(const_cast(rhs)).address_; 48 | } 49 | 50 | bool Ipv4Address::compare_to(const IpAddress& rhs) const { 51 | return address_ > rhs.getIpv4Address(); 52 | } 53 | 54 | IpAddress& Ipv4Address::set_to(const IpAddress& rhs) { 55 | this->address_ = rhs.getIpv4Address(); 56 | return *this; 57 | } 58 | 59 | bool Ipv4Address::isIpv4() const { 60 | return true; 61 | } 62 | 63 | size_t Ipv4Address::hash() const { return (address_) % __SIZE_MAX__; } 64 | 65 | // Ipv6 implementation 66 | 67 | Ipv6Address::Ipv6Address() { 68 | address_ = 0; 69 | } 70 | 71 | Ipv6Address::Ipv6Address(absl::uint128 address) { 72 | address_ = address; 73 | } 74 | 75 | 76 | Ipv6Address::Ipv6Address(const Ipv6Address& copy) { 77 | address_ = copy.address_; 78 | } 79 | 80 | Ipv6Address* Ipv6Address::clone() const { return new Ipv6Address(*this); } 81 | 82 | uint32_t Ipv6Address::getIpv4Address() const { 83 | return 0; 84 | } 85 | 86 | absl::uint128 Ipv6Address::getIpv6Address() const { 87 | return address_; 88 | } 89 | 90 | absl::uint128 Ipv6Address::getPrefix(uint8_t length) const { 91 | return address_ >> (128 - length); 92 | } 93 | 94 | void Ipv6Address::randomizeAddress(uint8_t length) { 95 | absl::BitGen bitgen; 96 | if (length >= 64) { 97 | uint64_t blockFactor_ = static_cast(std::pow(2, 128 - length)); 98 | uint64_t addressSuffix_ = 99 | (absl::Uint128Low64(address_) >> (128 - length)) << (128 - length) | 100 | absl::uniform_int_distribution(0, blockFactor_-1)(bitgen); 101 | address_ = ((address_ >> (128 - length)) << (128 - length)) | 102 | static_cast(addressSuffix_); 103 | } else { 104 | uint64_t blockFactor_ = static_cast(std::pow(2, 64 - length)); 105 | uint64_t addressSuffix_ = absl::uniform_int_distribution( 106 | 0, static_cast(std::pow(2, 64) - 1))(bitgen); 107 | uint64_t addressPrefix_ = 108 | (absl::Uint128High64(address_) >> (64 - length)) << (64 - length) | 109 | absl::uniform_int_distribution(0, blockFactor_ - 1)(bitgen); 110 | 111 | address_ = static_cast(addressPrefix_) | 112 | static_cast(addressSuffix_); 113 | } 114 | } 115 | 116 | bool Ipv6Address::equal_to(const IpAddress& rhs) const { 117 | if (rhs.isIpv4()) return false; 118 | Ipv6Address& temp = dynamic_cast(const_cast(rhs)); 119 | return address_ == temp.address_; 120 | } 121 | 122 | bool Ipv6Address::compare_to(const IpAddress& rhs) const { 123 | return address_ > rhs.getIpv6Address(); 124 | } 125 | 126 | IpAddress& Ipv6Address::set_to(const IpAddress& rhs) { 127 | this->address_ = rhs.getIpv6Address(); 128 | return *this; 129 | } 130 | 131 | bool Ipv6Address::isIpv4() const { 132 | return false; 133 | } 134 | 135 | size_t Ipv6Address::hash() const { 136 | return (absl::Uint128High64(address_) ^ absl::Uint128Low64(address_)) % 137 | __SIZE_MAX__; 138 | } 139 | 140 | // Ipv network implementation 141 | 142 | IpNetwork::IpNetwork(const IpAddress& addr, const uint32_t prefix) { 143 | addr_ = std::unique_ptr(addr.clone()); 144 | prefix_ = prefix; 145 | } 146 | 147 | IpNetwork::IpNetwork(const IpNetwork& copy) { 148 | this->addr_.reset(copy.addr_->clone()); 149 | this->prefix_ = copy.prefix_; 150 | } 151 | 152 | bool IpNetwork::contains(const IpAddress& addr) const { 153 | if (addr.isIpv4()) { 154 | if ((addr_->getIpv4Address() >> (32 - prefix_)) == 155 | (addr.getIpv4Address() >> (32 - prefix_))) 156 | return true; 157 | else 158 | return false; 159 | } else { 160 | if ((addr_->getIpv6Address() >> (128 - prefix_)) == 161 | (addr.getIpv6Address() >> (128 - prefix_))) 162 | return true; 163 | else 164 | return false; 165 | } 166 | } 167 | 168 | IpNetwork* IpNetwork::clone() const { 169 | return new IpNetwork(*this); 170 | } 171 | 172 | absl::uint128 IpNetwork::getPrefix() const { 173 | if (addr_->isIpv4()) { 174 | return addr_->getIpv4Address() >> (32 - prefix_); 175 | } else { 176 | return addr_->getIpv6Address() >> (128 - prefix_); 177 | } 178 | } 179 | 180 | } // namespace flashroute 181 | -------------------------------------------------------------------------------- /flashroute/address.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "absl/numeric/int128.h" 11 | 12 | namespace flashroute { 13 | 14 | class IpAddress { 15 | public: 16 | virtual IpAddress* clone() const = 0; 17 | 18 | // return ipv4 decimal address if there is one. 19 | virtual uint32_t getIpv4Address() const = 0; 20 | 21 | // return the first 64 bits of ipv6 decimal address if there is one. 22 | virtual absl::uint128 getIpv6Address() const = 0; 23 | 24 | // return the prefix of the address. 25 | virtual absl::uint128 getPrefix(uint8_t length) const = 0; 26 | 27 | // randomize the suffix of address but keep prefix unchanged. Length is the 28 | // length of the unchanged prefix. 29 | virtual void randomizeAddress(uint8_t length) = 0; 30 | 31 | // return a boolean value telling whether this is a ipv4 address (only for 32 | // IpAddress). 33 | virtual bool isIpv4() const = 0; 34 | 35 | // return a size_t hash value of address. 36 | virtual size_t hash() const = 0; 37 | 38 | // overload assignment operator. 39 | virtual IpAddress& operator=(const IpAddress& rhs) { 40 | return set_to(rhs); 41 | } 42 | 43 | // overload comparison operator. 44 | virtual bool operator==(const IpAddress& rhs) const { 45 | return equal_to(rhs); 46 | } 47 | 48 | virtual bool operator!=(const IpAddress& rhs) const { 49 | return !equal_to(rhs); 50 | } 51 | 52 | virtual bool operator>(const IpAddress& rhs) const { 53 | return compare_to(rhs); 54 | } 55 | 56 | virtual bool operator>=(const IpAddress& rhs) const { 57 | return compare_to(rhs) || equal_to(rhs); 58 | } 59 | 60 | virtual bool operator<(const IpAddress& rhs) const { 61 | return !compare_to(rhs); 62 | } 63 | 64 | virtual bool operator<=(const IpAddress& rhs) const { 65 | return !compare_to(rhs) || equal_to(rhs); 66 | } 67 | 68 | protected: 69 | // compare with anohter IpAddress object return true if content is the same. 70 | virtual bool equal_to(const IpAddress& rhs) const = 0; 71 | virtual bool compare_to(const IpAddress& rhs) const = 0; 72 | 73 | // set the current address based on the content of another IpAddress object. 74 | virtual IpAddress& set_to(const IpAddress& rhs) = 0; 75 | }; 76 | 77 | class Ipv4Address : public IpAddress { 78 | public: 79 | Ipv4Address(); 80 | explicit Ipv4Address(uint32_t ipv4); 81 | Ipv4Address(const Ipv4Address& copy); 82 | // vitrual constructor (copy) 83 | virtual Ipv4Address* clone() const; 84 | 85 | uint32_t getIpv4Address() const override; 86 | absl::uint128 getIpv6Address() const override; 87 | absl::uint128 getPrefix(uint8_t length) const override; 88 | void randomizeAddress(uint8_t length) override; 89 | bool isIpv4() const override; 90 | 91 | size_t hash() const override; 92 | 93 | Ipv4Address& operator=(const Ipv4Address& rhs) { 94 | this->address_ = rhs.getIpv4Address(); 95 | return *this; 96 | } 97 | 98 | protected: 99 | bool equal_to(const IpAddress& rhs) const override; 100 | bool compare_to(const IpAddress& rhs) const override; 101 | 102 | IpAddress& set_to(const IpAddress& rhs) override; 103 | 104 | private: 105 | uint32_t address_; 106 | }; 107 | 108 | class Ipv6Address : public IpAddress { 109 | public: 110 | Ipv6Address(); 111 | explicit Ipv6Address(absl::uint128 address); 112 | Ipv6Address(const Ipv6Address& copy); 113 | // vitrual constructor (copy) 114 | virtual Ipv6Address* clone() const; 115 | 116 | uint32_t getIpv4Address() const override; 117 | absl::uint128 getIpv6Address() const override; 118 | absl::uint128 getPrefix(uint8_t length) const override; 119 | void randomizeAddress(uint8_t length) override; 120 | bool isIpv4() const override; 121 | 122 | size_t hash() const override; 123 | 124 | Ipv6Address& operator=(const Ipv6Address& rhs) { 125 | this->address_ = rhs.getIpv6Address(); 126 | return *this; 127 | } 128 | 129 | protected: 130 | bool equal_to(const IpAddress& rhs) const override; 131 | bool compare_to(const IpAddress& rhs) const override; 132 | 133 | IpAddress& set_to(const IpAddress& rhs) override; 134 | 135 | private: 136 | absl::uint128 address_; 137 | }; 138 | 139 | // customize hash and equality function for IpAddress object 140 | struct IpAddressHash { 141 | std::size_t operator()(const IpAddress* tmp) const { return tmp->hash(); } 142 | }; 143 | 144 | struct IpAddressEquality { 145 | std::size_t operator()(const IpAddress* lhs, const IpAddress* rhs) const { 146 | return *lhs == *rhs; 147 | } 148 | }; 149 | 150 | class IpNetwork { 151 | public: 152 | IpNetwork(const IpAddress& addr, const uint32_t prefix); 153 | 154 | // copy constructor 155 | IpNetwork(const IpNetwork& copy); 156 | 157 | bool contains(const IpAddress& addr) const; 158 | IpNetwork* clone() const; 159 | absl::uint128 getPrefix() const; 160 | private: 161 | std::unique_ptr addr_; 162 | uint32_t prefix_; 163 | }; 164 | 165 | // customize hash and equality function for IpAddress object 166 | struct IpNetworkHash { 167 | std::size_t operator()(const IpNetwork* tmp) const { 168 | return static_cast(tmp->getPrefix() % __SIZE_MAX__); 169 | } 170 | }; 171 | 172 | struct IpNetworkEquality { 173 | std::size_t operator()(const IpNetwork* lhs, const IpNetwork* rhs) const { 174 | return lhs->getPrefix() == lhs->getPrefix(); 175 | } 176 | }; 177 | 178 | } // namespace flashroute 179 | -------------------------------------------------------------------------------- /flashroute/blacklist.cc: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #include "flashroute/blacklist.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include "absl/strings/numbers.h" 11 | #include "absl/strings/str_split.h" 12 | #include "absl/strings/string_view.h" 13 | #include "glog/logging.h" 14 | 15 | #include "flashroute/address.h" 16 | #include "flashroute/utils.h" 17 | 18 | namespace flashroute { 19 | 20 | Blacklist::~Blacklist() { 21 | LOG(INFO) << "Free the blacklist."; 22 | for (auto it = rules_.begin(); it != rules_.end(); ++it) { 23 | free(*it); 24 | } 25 | } 26 | 27 | void Blacklist::insert(IpNetwork* network) { 28 | rules_.push_back(network->clone()); 29 | } 30 | 31 | bool Blacklist::contains(const IpAddress& addr) { 32 | for (auto it = rules_.begin(); it != rules_.end(); ++it) { 33 | if ((*it)->contains(addr)) return true; 34 | } 35 | return false; 36 | } 37 | 38 | void Blacklist::loadRulesFromFile(const std::string& filePath) { 39 | if (filePath.empty()) { 40 | LOG(INFO) << "Blacklist disabled."; 41 | return; 42 | } 43 | LOG(INFO) << "Load blacklist from file: " << filePath; 44 | std::ifstream in(filePath); 45 | if (!in) { 46 | LOG(ERROR) << "Failed to load blacklist."; 47 | } 48 | for (std::string line; getline(in, line);) { 49 | insertByString(line); 50 | } 51 | in.close(); 52 | } 53 | 54 | void Blacklist::loadRulesFromReservedAddress() { 55 | std::vector reservedAddresses = { 56 | "0.0.0.0/8", "10.0.0.0/8", "100.64.0.0/10", "127.0.0.0/8", 57 | "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24", "192.0.2.0/24", 58 | "192.88.99.0/24", "192.168.0.0/16", "198.18.0.0/15", "198.51.100.0/24", 59 | "203.0.113.0/24", "224.0.0.0/4", "240.0.0.0/4"}; 60 | 61 | for (const auto& reservedBlock : reservedAddresses) { 62 | insertByString(reservedBlock); 63 | } 64 | } 65 | 66 | size_t Blacklist::size() { return rules_.size(); } 67 | 68 | void Blacklist::insertByString(const std::string& sAddr) { 69 | IpNetwork* parsedNetwork = parseNetworkFromStringToNetworkAddress(sAddr); 70 | if (parsedNetwork != NULL) { 71 | insert(parsedNetwork); 72 | free(parsedNetwork); 73 | } 74 | } 75 | 76 | } // namespace flashroute 77 | -------------------------------------------------------------------------------- /flashroute/blacklist.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | #include "flashroute/address.h" 8 | 9 | namespace flashroute { 10 | 11 | /** 12 | * Blacklist 13 | * Load various blacklists and remove corresponding ip-blocks from the probing 14 | * list. 15 | * 16 | * Example: 17 | * Remove the blacklisted Ipv4 addresses from file: 18 | * Blacklist::removeAddressFromFile(FLAGS_blacklist, &traceRouter); 19 | * 20 | * Remove the reserved Ipv4 addresses per 21 | * https://en.wikipedia.org/wiki/Reserved_IP_addresses 22 | * 23 | * Blacklist::removeReservedAddress(&traceRouter); 24 | */ 25 | 26 | class Blacklist { 27 | public: 28 | ~Blacklist(); 29 | void loadRulesFromFile(const std::string& filePath); 30 | 31 | void loadRulesFromReservedAddress(); 32 | 33 | void insert(IpNetwork* network); 34 | 35 | bool contains(const IpAddress& addr); 36 | 37 | size_t size(); 38 | 39 | private: 40 | std::vector rules_; 41 | 42 | void insertByString(const std::string& addr); 43 | }; 44 | 45 | } // namespace flashroute 46 | -------------------------------------------------------------------------------- /flashroute/blacklist_test.cc: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #include "gtest/gtest.h" 3 | #include "gmock/gmock.h" 4 | 5 | #include "flashroute/blacklist.h" 6 | #include "flashroute/traceroute.h" 7 | 8 | using namespace flashroute; 9 | 10 | class MockTracerouter : public Tracerouter { 11 | public: 12 | MOCK_METHOD2(getDcbByIpAddress, int64_t(uint32_t address, bool accuracy)); 13 | MOCK_METHOD1(removeDcbElement, int64_t(uint32_t x)); 14 | }; 15 | 16 | TEST(removeAddressBlock, removeAddressTest) { 17 | MockTracerouter tracerouter; 18 | EXPECT_CALL(tracerouter, getDcbByIpAddress) 19 | .WillOnce(testing::Return(110)) 20 | .WillOnce(testing::Return(120)); 21 | 22 | EXPECT_CALL(tracerouter, removeDcbElement) 23 | .Times(11) 24 | .WillRepeatedly(testing::Return(1)); 25 | 26 | std::string target = "192.168.1.1/24"; 27 | EXPECT_EQ(Blacklist::removeAddressBlock(&tracerouter, target), 11); 28 | } 29 | 30 | int main(int argc, char** argv) { 31 | // The following line must be executed to initialize Google Mock 32 | // (and Google Test) before running the tests. 33 | ::testing::InitGoogleMock(&argc, argv); 34 | return RUN_ALL_TESTS(); 35 | } 36 | -------------------------------------------------------------------------------- /flashroute/bogon_filter.cc: -------------------------------------------------------------------------------- 1 | #include "bogon_filter.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "absl/strings/numbers.h" 7 | #include "absl/strings/str_split.h" 8 | #include "flashroute/utils.h" 9 | #include "glog/logging.h" 10 | 11 | namespace flashroute { 12 | 13 | const uint32_t kNormalizeBgpPrefix = 32; 14 | 15 | BogonFilter::BogonFilter(const std::string& filePath) { 16 | initialized_ = false; 17 | trie_ = std::make_unique(true); 18 | if (filePath.empty()) return; 19 | std::ifstream inFile(filePath, std::ios::in); 20 | 21 | std::string line; 22 | while (std::getline(inFile, line)) { 23 | if (line.at(0) == '>') { 24 | auto tmpLine = line.substr(1); 25 | 26 | std::vector elements = absl::StrSplit(tmpLine, " "); 27 | auto network = elements[0]; 28 | std::vector parts = absl::StrSplit(network, "/"); 29 | if (parts.size() != 2) { 30 | LOG(FATAL) << "Target network format is incorrect!!! " << elements[0]; 31 | } 32 | 33 | uint32_t subnetPrefixLength = 0; 34 | if (!absl::SimpleAtoi(parts[1], &subnetPrefixLength)) { 35 | LOG(FATAL) << "Failed to parse the target network."; 36 | } 37 | 38 | std::unique_ptr targetBaseAddress{ 39 | parseIpFromStringToIpAddress(std::string(parts[0]))}; 40 | 41 | subnetPrefixLength = std::min(kNormalizeBgpPrefix, subnetPrefixLength); 42 | trie_->insert(*targetBaseAddress, subnetPrefixLength); 43 | } 44 | } 45 | initialized_ = true; 46 | } 47 | 48 | bool BogonFilter::isBogonAddress(const IpAddress& ip) { 49 | if (initialized_) { 50 | return !trie_->checkAddressContained(ip); 51 | } else { 52 | return false; 53 | } 54 | } 55 | 56 | 57 | } // namespace flashroute 58 | -------------------------------------------------------------------------------- /flashroute/bogon_filter.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | #include "flashroute/address.h" 8 | #include "flashroute/trie.h" 9 | 10 | namespace flashroute { 11 | 12 | class BogonFilter { 13 | public: 14 | explicit BogonFilter(const std::string& filePath); 15 | 16 | bool isBogonAddress(const IpAddress& ip); 17 | 18 | private: 19 | std::unique_ptr trie_; 20 | bool initialized_; 21 | }; 22 | 23 | } // namespace flashroute 24 | -------------------------------------------------------------------------------- /flashroute/bounded_buffer.cc: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #include "flashroute/bounded_buffer.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace flashroute { 9 | 10 | } // namespace flashroute 11 | -------------------------------------------------------------------------------- /flashroute/bounded_buffer.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include // for auto_cpu_timer 12 | 13 | namespace flashroute { 14 | 15 | template 16 | class BoundedBuffer { 17 | public: 18 | typedef boost::circular_buffer ContainerType; 19 | typedef typename ContainerType::size_type SizeType; 20 | typedef typename ContainerType::value_type ValueType; 21 | typedef typename boost::call_traits::param_type param_type; 22 | 23 | explicit BoundedBuffer(SizeType capacity) 24 | : mUnread(0), mContainer(capacity) {} 25 | 26 | void pushFront(typename boost::call_traits::param_type item) { 27 | boost::mutex::scoped_lock lock(mMutex); 28 | mNotFull.wait( 29 | lock, boost::bind(&BoundedBuffer::isNotFull, this)); 30 | mContainer.push_front(item); 31 | ++mUnread; 32 | lock.unlock(); 33 | mNotEmpty.notify_one(); 34 | } 35 | void popBack(ValueType* pItem) { 36 | boost::mutex::scoped_lock lock(mMutex); 37 | mNotEmpty.wait( 38 | lock, boost::bind(&BoundedBuffer::isNotEmpty, this)); 39 | *pItem = mContainer[--mUnread]; 40 | lock.unlock(); 41 | mNotFull.notify_one(); 42 | } 43 | 44 | bool empty() { return mUnread == 0; } 45 | SizeType size() { return mUnread; } 46 | 47 | private: 48 | BoundedBuffer(const BoundedBuffer&); // Disabled copy constructor. 49 | BoundedBuffer& operator=( 50 | const BoundedBuffer&); // Disabled assign operator. 51 | 52 | bool isNotEmpty() const { return mUnread > 0; } 53 | bool isNotFull() const { return mUnread < mContainer.capacity(); } 54 | 55 | SizeType mUnread; 56 | ContainerType mContainer; 57 | boost::mutex mMutex; 58 | boost::condition mNotEmpty; 59 | boost::condition mNotFull; 60 | }; 61 | 62 | } // namespace flashroute 63 | -------------------------------------------------------------------------------- /flashroute/dcb.cc: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #include "flashroute/dcb.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | namespace flashroute { 10 | 11 | DestinationControlBlock::DestinationControlBlock( 12 | const IpAddress* ip, DestinationControlBlock* _nextElement, 13 | DestinationControlBlock* _previousElement, const uint8_t initialTtl) 14 | : nextElement(_nextElement), 15 | previousElement(_previousElement), 16 | removed(false), 17 | initialBackwardProbingTtl(initialTtl), 18 | nextBackwardHop_(initialTtl), 19 | preprobedMark_(false), 20 | accurateDistanceMark_(false), 21 | nextForwardHop_(initialTtl + 1), 22 | forwardHorizon_(initialTtl) { 23 | ipAddress.reset(ip->clone()); 24 | testAndSet = std::make_unique(); 25 | (*testAndSet).clear(); 26 | } 27 | 28 | bool DestinationControlBlock::updateSplitTtl(uint8_t ttlToUpdate, 29 | bool confirmResult) { 30 | while (testAndSet->test_and_set(std::memory_order_acquire)) {} 31 | bool result = !preprobedMark_; 32 | // If the target does not have any confirmed hop-distance, we are allowed to 33 | // update it. 34 | if (!accurateDistanceMark_) { 35 | nextBackwardHop_ = ttlToUpdate; 36 | // update the initial TTL for backward probing. 37 | initialBackwardProbingTtl = ttlToUpdate; 38 | // Also update the next forward hop. 39 | nextForwardHop_ = ttlToUpdate + 1; 40 | forwardHorizon_ = ttlToUpdate; 41 | // If the updated TTL is from an accurate preprobing result, we lock the 42 | // future update. 43 | if (confirmResult) { 44 | accurateDistanceMark_ = true; 45 | } 46 | preprobedMark_ = true; 47 | } 48 | testAndSet->clear(std::memory_order_release); 49 | return result; 50 | } 51 | 52 | uint8_t DestinationControlBlock::stopBackwardProbing() { 53 | while (testAndSet->test_and_set(std::memory_order_acquire)) {} 54 | uint8_t remains = nextBackwardHop_; 55 | nextBackwardHop_ = 0; 56 | testAndSet->clear(std::memory_order_release); 57 | return remains; 58 | } 59 | 60 | uint8_t DestinationControlBlock::pullBackwardTask(int16_t ttlOffset) { 61 | while (testAndSet->test_and_set(std::memory_order_acquire)) {} 62 | if (nextBackwardHop_ > ttlOffset) { 63 | auto tmp = nextBackwardHop_--; 64 | testAndSet->clear(std::memory_order_release); 65 | return tmp; 66 | } else { 67 | testAndSet->clear(std::memory_order_release); 68 | return 0; 69 | } 70 | } 71 | 72 | bool DestinationControlBlock::hasBackwardTask() { 73 | while (testAndSet->test_and_set(std::memory_order_acquire)) { 74 | } 75 | auto tmp = nextBackwardHop_ > 0; 76 | testAndSet->clear(std::memory_order_release); 77 | return tmp; 78 | } 79 | 80 | uint8_t DestinationControlBlock::peekBackwardTask() { 81 | while (testAndSet->test_and_set(std::memory_order_acquire)) { 82 | } 83 | auto tmp = nextBackwardHop_; 84 | testAndSet->clear(std::memory_order_release); 85 | return tmp; 86 | } 87 | 88 | bool DestinationControlBlock::hasForwardTask() { 89 | while (testAndSet->test_and_set(std::memory_order_acquire)) { 90 | } 91 | auto tmp = forwardHorizon_ >= nextForwardHop_; 92 | testAndSet->clear(std::memory_order_release); 93 | return tmp; 94 | } 95 | 96 | uint8_t DestinationControlBlock::pullForwardTask() { 97 | while (testAndSet->test_and_set(std::memory_order_acquire)) { 98 | } 99 | if (forwardHorizon_ >= nextForwardHop_) { 100 | auto tmp = nextForwardHop_++; 101 | testAndSet->clear(std::memory_order_release); 102 | return tmp; 103 | } else { 104 | testAndSet->clear(std::memory_order_release); 105 | return 0; 106 | } 107 | } 108 | 109 | void DestinationControlBlock::stopForwardProbing() { 110 | while (testAndSet->test_and_set(std::memory_order_acquire)) { 111 | } 112 | forwardHorizon_ = 0; 113 | testAndSet->clear(std::memory_order_release); 114 | } 115 | 116 | int16_t DestinationControlBlock::getMaxProbedDistance() { 117 | while (testAndSet->test_and_set(std::memory_order_acquire)) { 118 | } 119 | auto tmp = nextForwardHop_ - 1; 120 | testAndSet->clear(std::memory_order_release); 121 | return tmp; 122 | } 123 | 124 | void DestinationControlBlock::setForwardHorizon(uint8_t forwardExploredHop) { 125 | while (testAndSet->test_and_set(std::memory_order_acquire)) { 126 | } 127 | // forwardHorizon_ == 0 means that the forward probing is done; 128 | // therefore, we will not update the variable regarding the forward probing. 129 | if (forwardHorizon_ == 0) { 130 | testAndSet->clear(std::memory_order_release); 131 | return; 132 | } 133 | if (forwardExploredHop > forwardHorizon_) { 134 | forwardHorizon_ = forwardExploredHop; 135 | } 136 | testAndSet->clear(std::memory_order_release); 137 | } 138 | 139 | void DestinationControlBlock::resetProbingProgress(uint8_t ttl) { 140 | nextBackwardHop_ = ttl; 141 | initialBackwardProbingTtl = ttl; 142 | nextForwardHop_ = ttl + 1; 143 | forwardHorizon_ = ttl; 144 | removed = false; 145 | } 146 | 147 | bool DestinationControlBlock::isPreprobed() const { return preprobedMark_; } 148 | 149 | uint8_t DestinationControlBlock::peekForwardHop() const { 150 | return nextForwardHop_; 151 | }; 152 | 153 | } // namespace flashroute 154 | 155 | 156 | -------------------------------------------------------------------------------- /flashroute/dcb.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | #include "flashroute/address.h" 8 | 9 | namespace flashroute { 10 | 11 | class DestinationControlBlock { 12 | public: 13 | std::unique_ptr ipAddress; 14 | DestinationControlBlock* nextElement; 15 | DestinationControlBlock* previousElement; 16 | bool removed; 17 | // the initial TTL when we start backward probing. This value will be used to 18 | // prevent the traceroute to put router interfaces discovered in 19 | // forward-probing into the stop set. 20 | uint8_t initialBackwardProbingTtl; 21 | 22 | DestinationControlBlock(const IpAddress* ip, 23 | DestinationControlBlock* _nextElement, 24 | DestinationControlBlock* _previousElement, 25 | const uint8_t initialTtl); 26 | 27 | /** 28 | * set the split-TTL, if the given TTL is confirmed, the second variabble 29 | * should be true, otherwise, false; this is to distinguish accurate TTL vs 30 | * predicted TTL. 31 | */ 32 | bool updateSplitTtl(uint8_t ttlToUpdate, bool confirmResult); 33 | 34 | /** 35 | * stop backward probing by setting the nextBackwardHop to 0, and remains the 36 | * current backward ttl. 37 | */ 38 | uint8_t stopBackwardProbing(); 39 | 40 | /** 41 | * return current backward ttl and move backward. 42 | */ 43 | uint8_t pullBackwardTask(int16_t ttlOffset); 44 | 45 | /** 46 | * return true if there is backward probing task. 47 | */ 48 | bool hasBackwardTask(); 49 | 50 | /** 51 | * return current backward ttl. 52 | */ 53 | uint8_t peekBackwardTask(); 54 | 55 | /** 56 | * return true if there is forward probing task. 57 | */ 58 | bool hasForwardTask(); 59 | 60 | /** 61 | * return current forward ttl and move forward, 0 if there is no forward task. 62 | */ 63 | uint8_t pullForwardTask(); 64 | 65 | /** 66 | * return current forward ttl and move forward, 0 if there is no forward task. 67 | */ 68 | void stopForwardProbing(); 69 | 70 | /** 71 | * return the maximum TTL that is probed already. 72 | */ 73 | int16_t getMaxProbedDistance(); 74 | 75 | /** 76 | * set forward probing horizon. 77 | */ 78 | void setForwardHorizon(uint8_t forwardExploredHop); 79 | 80 | /** 81 | * reset the probing progress. Will be deployed in discovery-optimized mode. 82 | */ 83 | void resetProbingProgress(uint8_t ttl); 84 | 85 | bool isPreprobed() const; 86 | 87 | uint8_t peekForwardHop() const; 88 | 89 | private: 90 | uint8_t nextBackwardHop_; 91 | // std::unique_ptr ttlToProbeMutex_; 92 | 93 | bool preprobedMark_; 94 | // if true, the current initial TTL is from the accurate distance measurement 95 | // result, otherwise, false. 96 | bool accurateDistanceMark_; 97 | // std::unique_ptr preprobedMarkMutex_; 98 | 99 | // The maximal hop-distance that is probed already. 100 | uint8_t nextForwardHop_; 101 | // std::unique_ptr maxProbedHopMutex_; 102 | 103 | // The maximal hop-distance that is expected to be explored by forward 104 | // probbing. We probe router 105 | uint8_t forwardHorizon_; 106 | // std::unique_ptr forwardExploredHopMutex_; 107 | std::unique_ptr testAndSet; 108 | }; 109 | 110 | } // namespace flashroute 111 | -------------------------------------------------------------------------------- /flashroute/dcb_manager.cc: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #include "flashroute/dcb_manager.h" 3 | 4 | #include 5 | 6 | #include "glog/logging.h" 7 | 8 | namespace flashroute { 9 | 10 | // When granularity has been set to 0, it will be updated based on the type of 11 | // the first inserted address. 12 | DcbManager::DcbManager(const uint64_t reservedSpace, const uint32_t granularity, 13 | const uint32_t seed, const bool coarseFind) 14 | : scanRound(0), 15 | liveDcbCount_(0), 16 | granularity_(granularity), 17 | seed_(seed), 18 | currentDcb_(NULL), 19 | lastAddedDcb_(NULL), 20 | firstAddedDcb_(NULL), 21 | specialDcb_(NULL) { 22 | map_ = 23 | std::unique_ptr>( 25 | new std::unordered_map()); 27 | map_->reserve(reservedSpace); 28 | 29 | if (coarseFind) { 30 | coarseMap_ = std::unique_ptr< 31 | std::unordered_map, 32 | IpNetworkHash, IpNetworkEquality>>( 33 | new std::unordered_map, 35 | IpNetworkHash, IpNetworkEquality>()); 36 | coarseMap_->reserve(reservedSpace); 37 | } 38 | 39 | 40 | // insert the special dcb. 41 | specialDcb_ = addDcb(Ipv4Address(0), 0); 42 | currentDcb_ = specialDcb_; 43 | // reset live Dcb count to 0 44 | liveDcbCount_ = 0; 45 | } 46 | 47 | void DcbManager::releaseCoarseMapping() { 48 | if (coarseMap_.get() != nullptr) { 49 | while (!coarseMap_->empty()) { 50 | auto element = coarseMap_->begin(); 51 | auto keyAddress = element->first; 52 | coarseMap_->erase(keyAddress); 53 | delete keyAddress; 54 | } 55 | VLOG(2) << "DcbManager: coarse address mapping is released."; 56 | } 57 | } 58 | 59 | void DcbManager::releaseAccurateMapping() { 60 | if (map_.get() != nullptr) { 61 | while (!map_->empty()) { 62 | auto element = map_->begin(); 63 | auto keyAddress = element->first; 64 | map_->erase(keyAddress); 65 | delete keyAddress; 66 | } 67 | 68 | VLOG(2) << "DcbManager: accurate address mapping is released."; 69 | } 70 | } 71 | 72 | DcbManager::~DcbManager() { 73 | releaseCoarseMapping(); 74 | releaseAccurateMapping(); 75 | VLOG(2) << "DcbManager: cleanup is finished."; 76 | } 77 | 78 | bool DcbManager::hasNext() { 79 | if (liveDcbCount_ == 0) 80 | return false; 81 | else 82 | return true; 83 | } 84 | 85 | DestinationControlBlock* DcbManager::next() { 86 | if (liveDcbCount_ == 0) return nullptr; 87 | currentDcb_ = currentDcb_->nextElement; 88 | // jump special dcb 89 | if (currentDcb_ == specialDcb_) { 90 | currentDcb_ = currentDcb_->nextElement; 91 | scanRound++; 92 | } 93 | return currentDcb_; 94 | } 95 | 96 | DestinationControlBlock* DcbManager::peek() const { 97 | if (liveDcbCount_ == 0) return nullptr; 98 | DestinationControlBlock* tmp = currentDcb_->nextElement; 99 | // jump special dcb 100 | if (tmp == specialDcb_) { 101 | tmp = currentDcb_->nextElement; 102 | } 103 | return tmp; 104 | } 105 | 106 | void DcbManager::resetIterator() { 107 | currentDcb_ = specialDcb_; 108 | } 109 | 110 | void DcbManager::shuffleOrder() { 111 | // TODO(neohuang): add logic to shuffle the order of iteration. 112 | // we can put everything in an temp array first and shuffle the order from the 113 | // array. 114 | 115 | if (map_->size() > RAND_MAX) { 116 | LOG(FATAL) << "Randomization failed: the sequence range is larger than " 117 | "the range of randomization function"; 118 | } 119 | 120 | std::vector tmpArray; 121 | { 122 | for (auto it = map_->begin(); it != map_->end(); it++) { 123 | tmpArray.push_back(it->second); 124 | } 125 | } 126 | 127 | srand(seed_); 128 | for (uint64_t i = 0; i < map_->size(); i++) { 129 | swapDcbElementSequence(tmpArray[i], tmpArray[rand() % map_->size()]); 130 | } 131 | } 132 | 133 | void DcbManager::randomizeAddress() { 134 | for (uint64_t i = 0; i < map_->size() - 1; i++) { 135 | DestinationControlBlock* dcb = this->next(); 136 | dcb->ipAddress->randomizeAddress(granularity_); 137 | } 138 | } 139 | 140 | DestinationControlBlock* DcbManager::getDcbByAddress( 141 | const IpAddress& addr) const { 142 | auto result = map_->find(&(const_cast(addr))); 143 | if (result != map_->end()) { 144 | return result->second; 145 | } 146 | return nullptr; 147 | } 148 | 149 | std::vector* DcbManager::getDcbsByAddress( 150 | const IpAddress& pseudo) const { 151 | if (coarseMap_.get() == nullptr) return nullptr; 152 | IpNetwork ipNetwork(pseudo, granularity_); 153 | auto result = coarseMap_->find(&ipNetwork); 154 | if (result != coarseMap_->end()) { 155 | return &result->second; 156 | } 157 | return nullptr; 158 | } 159 | 160 | DestinationControlBlock* DcbManager::addDcb(const IpAddress& addr, 161 | const uint8_t initialTtl) { 162 | // if granularity is not set, update granularity based on the dcb. 163 | if (map_->size() != 0 && granularity_ == 0) { 164 | if (addr.isIpv4()) 165 | granularity_ = 32; 166 | else 167 | granularity_ = 128; 168 | } 169 | 170 | if (map_->find(&(const_cast(addr))) != map_->end()) { 171 | return nullptr; 172 | } 173 | 174 | DestinationControlBlock* tmp = 175 | new DestinationControlBlock(&addr, NULL, NULL, initialTtl); 176 | map_->insert({addr.clone(), tmp}); 177 | 178 | if (lastAddedDcb_ == NULL && firstAddedDcb_ == NULL) { 179 | lastAddedDcb_ = tmp; 180 | firstAddedDcb_ = tmp; 181 | } else { 182 | tmp->nextElement = firstAddedDcb_; 183 | tmp->previousElement = lastAddedDcb_; 184 | lastAddedDcb_->nextElement = tmp; 185 | firstAddedDcb_->previousElement = tmp; 186 | lastAddedDcb_ = tmp; 187 | } 188 | 189 | liveDcbCount_++; 190 | // add to corse map for distance prediction. 191 | addToCoarseMap(tmp); 192 | return tmp; 193 | } 194 | 195 | void DcbManager::removeDcbFromIteration(DestinationControlBlock* dcb) { 196 | DestinationControlBlock* previous = dcb->previousElement; 197 | DestinationControlBlock* next = dcb->nextElement; 198 | previous->nextElement = next; 199 | next->previousElement = previous; 200 | liveDcbCount_--; 201 | } 202 | 203 | void DcbManager::removeDcbFromIteration(const IpAddress& addr) { 204 | auto result = map_->find(&(const_cast(addr))); 205 | if (result == map_->end()) { 206 | return; 207 | } 208 | DestinationControlBlock* previous = result->second->previousElement; 209 | DestinationControlBlock* next = result->second->nextElement; 210 | previous->nextElement = next; 211 | next->previousElement = previous; 212 | liveDcbCount_--; 213 | } 214 | 215 | // remove DCB permanently. This is for blacklist. 216 | void DcbManager::deleteDcb(const IpAddress& addr) { 217 | auto result = map_->find(&(const_cast(addr))); 218 | if (result == map_->end()) { 219 | return; 220 | } 221 | 222 | IpAddress* tmpKey = result->first; 223 | DestinationControlBlock* tmpValue = result->second; 224 | map_->erase(result); 225 | free(tmpKey); 226 | free(tmpValue); 227 | liveDcbCount_--; 228 | return; 229 | } 230 | 231 | void DcbManager::snapshot() { 232 | // TODO(neohuang): implement snapshot. 233 | } 234 | 235 | void DcbManager::reset() { 236 | DestinationControlBlock* tmp = nullptr; 237 | DestinationControlBlock* first = nullptr; 238 | for (auto it = map_->begin(); it != map_->end(); ++it) { 239 | if (tmp == nullptr) { 240 | tmp = it->second; 241 | first = tmp; 242 | } else { 243 | it->second->previousElement = tmp; 244 | tmp->nextElement = it->second; 245 | tmp = it->second; 246 | } 247 | // Reset split TTL. 248 | if (it->second != specialDcb_) { 249 | if (it->second->isPreprobed()) { 250 | // If dcb has preprobing result, new TTL is generated based on the 251 | // preprobing result. 252 | it->second->resetProbingProgress( 253 | rand() % it->second->initialBackwardProbingTtl + 1); 254 | } else { 255 | // If dcb does not have preprobing result, new TTL is generated based on 256 | // the lastest forward probed hop. 257 | it->second->resetProbingProgress(rand() % it->second->peekForwardHop() + 258 | 1); 259 | } 260 | } 261 | } 262 | tmp->nextElement = first; 263 | first->previousElement = tmp; 264 | currentDcb_ = specialDcb_; 265 | 266 | liveDcbCount_ = map_->size() - 1; 267 | VLOG(2) << "DcbManager has been reset."; 268 | } 269 | 270 | void DcbManager::shuffleAddress() { 271 | for (auto it = map_->begin(); it != map_->end(); ++it) { 272 | // Shuffle address. 273 | if (it->second != specialDcb_) { 274 | it->second->ipAddress->randomizeAddress(granularity_); 275 | } 276 | } 277 | } 278 | 279 | uint64_t DcbManager::size() { 280 | return map_->size() - 1; 281 | } 282 | 283 | uint64_t DcbManager::liveDcbSize() { 284 | return liveDcbCount_; 285 | } 286 | 287 | void DcbManager::swapDcbElementSequence(DestinationControlBlock* x, 288 | DestinationControlBlock* y) { 289 | DestinationControlBlock* nextX = x->nextElement; 290 | DestinationControlBlock* previousX = x->previousElement; 291 | DestinationControlBlock* nextY = y->nextElement; 292 | DestinationControlBlock* previousY = y->previousElement; 293 | if (x == y || nextX == y || nextY == x || previousX == y || previousY == x) { 294 | return; 295 | } 296 | 297 | // Not swap element with removed element. 298 | if (x->removed == true || y->removed == true) { 299 | return; 300 | } 301 | 302 | x->nextElement = nextY; 303 | x->previousElement = previousY; 304 | y->nextElement = nextX; 305 | y->previousElement = previousX; 306 | 307 | nextY->previousElement = x; 308 | nextX->previousElement = y; 309 | 310 | previousY->nextElement = x; 311 | previousX->nextElement = y; 312 | } 313 | 314 | void DcbManager::addToCoarseMap(DestinationControlBlock* dcb) { 315 | if (coarseMap_.get() == nullptr) return; 316 | IpNetwork* ipNetwork = new IpNetwork(*dcb->ipAddress, granularity_); 317 | auto result = coarseMap_->find(ipNetwork); 318 | if (result != coarseMap_->end()) { 319 | result->second.push_back(dcb); 320 | free(ipNetwork); 321 | return; 322 | } else { 323 | coarseMap_->insert({ipNetwork, {dcb}}); 324 | } 325 | return; 326 | } 327 | 328 | } // namespace flashroute 329 | 330 | -------------------------------------------------------------------------------- /flashroute/dcb_manager.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "flashroute/address.h" 11 | #include "flashroute/dcb.h" 12 | 13 | 14 | namespace flashroute { 15 | 16 | class DcbManager { 17 | public: 18 | int32_t scanRound = 0; 19 | 20 | explicit DcbManager(const uint64_t reservedSpace, const uint32_t granularity, 21 | const uint32_t seed, const bool coarseFind); 22 | 23 | ~DcbManager(); 24 | 25 | // return true if there is any dcb in iteration list. 26 | bool hasNext(); 27 | 28 | // get next address. 29 | DestinationControlBlock* next(); 30 | 31 | // peek the next address. 32 | DestinationControlBlock* peek() const; 33 | 34 | // reset iterator position. 35 | void resetIterator(); 36 | 37 | // shuffle the order of iteration. 38 | void shuffleOrder(); 39 | 40 | // randomize addresses. 41 | void randomizeAddress(); 42 | 43 | // get DCB based on the address. 44 | DestinationControlBlock* getDcbByAddress(const IpAddress& pseudo) const; 45 | 46 | // get all DCBs fall in prefix. 47 | std::vector* getDcbsByAddress( 48 | const IpAddress& pseudo) const; 49 | 50 | // insert address. 51 | DestinationControlBlock* addDcb(const IpAddress& addr, 52 | const uint8_t initialTtl); 53 | 54 | void removeDcbFromIteration(DestinationControlBlock* dcb); 55 | 56 | // remove DCB from future iteration. 57 | void removeDcbFromIteration(const IpAddress& addr); 58 | 59 | // remove DCB permanently. This is for blacklist. 60 | void deleteDcb(const IpAddress& addr); 61 | 62 | // snapshot the current status. 63 | void snapshot(); 64 | 65 | // recover to the snapshot. 66 | void reset(); 67 | 68 | // Shuffle address using the method. 69 | void shuffleAddress(); 70 | 71 | // return the number of the DCBs that are in iteration. 72 | uint64_t liveDcbSize(); 73 | 74 | // return the number of the DCBs. 75 | uint64_t size(); 76 | 77 | // release the resource allocated for coase address look up. 78 | void releaseCoarseMapping(); 79 | 80 | private: 81 | uint64_t liveDcbCount_ = 0; 82 | uint32_t granularity_; 83 | uint32_t seed_; 84 | 85 | std::unique_ptr> 87 | map_; 88 | 89 | std::unique_ptr< 90 | std::unordered_map, 91 | IpNetworkHash, IpNetworkEquality>> 92 | coarseMap_; 93 | 94 | DestinationControlBlock* currentDcb_; 95 | DestinationControlBlock* lastAddedDcb_; 96 | DestinationControlBlock* firstAddedDcb_; 97 | 98 | // specialDcb helps identify the beginning of iteration. 99 | DestinationControlBlock* specialDcb_; 100 | 101 | void swapDcbElementSequence(DestinationControlBlock* x, 102 | DestinationControlBlock* y); 103 | 104 | void addToCoarseMap(DestinationControlBlock* dcb); 105 | 106 | void releaseAccurateMapping(); 107 | }; 108 | 109 | } // namespace flashroute 110 | -------------------------------------------------------------------------------- /flashroute/dump_result.cc: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #include "flashroute/dump_result.h" 3 | 4 | #include "glog/logging.h" 5 | #include "absl/numeric/int128.h" 6 | 7 | #include "flashroute/address.h" 8 | #include "flashroute/utils.h" 9 | 10 | namespace flashroute { 11 | 12 | const uint32_t kThreadPoolSize = 2; // Default thread pool size. 13 | const uint32_t kDumpingTmpBufferSize = 128; // Char buffer size to dump. 14 | const uint32_t kDumpingIntervalMs = 100; // Sleep interval. 15 | const uint32_t kDumpingBufferSize = 100000; 16 | 17 | ResultDumper::ResultDumper(const std::string& resultFilepath) 18 | : resultFilepath_(resultFilepath), 19 | stopDumping_(false), 20 | dumpedCount_(0), 21 | scheduledCount_(0) { 22 | resultFilepath_ = resultFilepath; 23 | threadPool_ = std::make_unique(kThreadPoolSize); 24 | dumpingBuffer_ = 25 | std::make_unique>(kDumpingBufferSize); 26 | 27 | if (resultFilepath_.size() == 0) { 28 | stopDumping_ = true; 29 | VLOG(2) << "ResultDumper: ResultDumper disabled."; 30 | } else { 31 | VLOG(2) << "ResultDumper: ResultDumper enabled."; 32 | } 33 | std::ofstream dumpFile; 34 | dumpFile.open(resultFilepath_, std::ofstream::binary); 35 | dumpFile.close(); 36 | 37 | // Initialize dumping thread. 38 | boost::asio::post(*threadPool_.get(), [this]() { runDumpingThread(); }); 39 | } 40 | 41 | ResultDumper::~ResultDumper() { 42 | while (!dumpingBuffer_->empty()) { 43 | std::this_thread::sleep_for( 44 | std::chrono::milliseconds(100)); 45 | } 46 | stopDumping_ = true; 47 | 48 | threadPool_->join(); 49 | VLOG(2) << "ResultDumper: ResultDumper recycled."; 50 | VLOG(2) << "ResultDumper:" << scheduledCount_ << " scheduled " << dumpedCount_ 51 | << " dumped."; 52 | } 53 | 54 | void ResultDumper::scheduleDumpData(const IpAddress& destination, 55 | const IpAddress& responder, 56 | uint8_t distance, uint32_t rtt, 57 | bool fromDestination, bool ipv4, 58 | void* buffer, size_t size) { 59 | scheduledCount_++; 60 | if (!stopDumping_) { 61 | absl::uint128 destinationAddr = 0; 62 | absl::uint128 responderAddr = 0; 63 | if (destination.isIpv4()) { 64 | destinationAddr = destination.getIpv4Address(); 65 | responderAddr = responder.getIpv4Address(); 66 | } else { 67 | destinationAddr = ntohll(destination.getIpv6Address()); 68 | responderAddr = ntohll(responder.getIpv6Address()); 69 | } 70 | 71 | dumpingBuffer_->pushFront({destinationAddr, responderAddr, rtt, distance, 72 | static_cast(fromDestination ? 1 : 0), 73 | static_cast(ipv4 ? 1 : 0)}); 74 | } 75 | } 76 | 77 | void ResultDumper::runDumpingThread() { 78 | VLOG(2) << "ResultDumper: Dumping thread initialized."; 79 | while (!stopDumping_) { 80 | std::ofstream dumpFile; 81 | dumpFile.open(resultFilepath_, std::ofstream::binary | std::ofstream::app); 82 | uint8_t buffer[kDumpingTmpBufferSize]; 83 | DataElement tmp; 84 | int64_t size = dumpingBuffer_->size(); 85 | for (int64_t i = 0; i < size; i++) { 86 | dumpingBuffer_->popBack(&tmp); 87 | size_t dumpedSize = binaryDumping(buffer, kDumpingTmpBufferSize, tmp); 88 | dumpFile.write(reinterpret_cast(buffer), dumpedSize); 89 | dumpedCount_++; 90 | } 91 | dumpFile.close(); 92 | std::this_thread::sleep_for(std::chrono::milliseconds(kDumpingIntervalMs)); 93 | } 94 | VLOG(2) << "ResultDumper: Dumping thread recycled."; 95 | } 96 | 97 | size_t ResultDumper::binaryDumping(uint8_t* buffer, const size_t maxSize, 98 | const DataElement& dataElement) { 99 | if (maxSize < 39) return 0; 100 | *reinterpret_cast(buffer + 0) = dataElement.destination; 101 | *reinterpret_cast(buffer + 16) = dataElement.responder; 102 | 103 | *reinterpret_cast(buffer + 32) = dataElement.rtt; 104 | *reinterpret_cast(buffer + 36) = dataElement.distance; 105 | *reinterpret_cast(buffer + 37) = dataElement.fromDestination; 106 | *reinterpret_cast(buffer + 38) = dataElement.ipv4; 107 | return 39; 108 | } 109 | 110 | } // namespace flashroute 111 | -------------------------------------------------------------------------------- /flashroute/dump_result.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include "absl/strings/string_view.h" 10 | #include "absl/numeric/int128.h" 11 | 12 | #include "flashroute/address.h" 13 | #include "flashroute/bounded_buffer.h" 14 | 15 | namespace flashroute { 16 | 17 | struct DataElement { 18 | absl::uint128 destination; 19 | absl::uint128 responder; 20 | uint32_t rtt; 21 | uint8_t distance; 22 | uint8_t fromDestination; 23 | uint8_t ipv4; 24 | }; 25 | 26 | 27 | class ResultDumper { 28 | public: 29 | explicit ResultDumper(const std::string& resultFilepath); 30 | ~ResultDumper(); 31 | 32 | void scheduleDumpData(const IpAddress& destination, 33 | const IpAddress& responder, uint8_t distance, 34 | uint32_t rtt, bool fromDestination, bool ipv4, 35 | void* buffer, size_t size); 36 | 37 | private: 38 | // File path to dump the result. 39 | std::string resultFilepath_; 40 | 41 | // Thread pool 42 | std::unique_ptr threadPool_; 43 | 44 | std::unique_ptr> dumpingBuffer_; 45 | 46 | bool stopDumping_; 47 | 48 | uint64_t dumpedCount_; 49 | uint64_t scheduledCount_; 50 | 51 | // Dumping thread. 52 | void runDumpingThread(); 53 | 54 | 55 | // Dumping logic 56 | size_t binaryDumping(uint8_t* buffer, const size_t maxSize, 57 | const DataElement& dataElement); 58 | }; 59 | 60 | } // namespace flashroute 61 | -------------------------------------------------------------------------------- /flashroute/experiment.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #pragma once 3 | 4 | #include "glog/logging.h" 5 | 6 | void logIpAddress(uint32_t ip) { 7 | uint32_t section[4]; 8 | section[0] = ip & 0xFF; 9 | section[1] = (ip >> 8) & 0xFF; 10 | section[2] = (ip >> 16) & 0xFF; 11 | section[3] = (ip >> 24) & 0xFF; 12 | LOG(INFO) << section[3] << "." << section[2] << "." << section[1] << "." 13 | << section[0]; 14 | } 15 | -------------------------------------------------------------------------------- /flashroute/hitlist.cc: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | 3 | #include "flashroute/hitlist.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "absl/strings/str_split.h" 12 | #include "flashroute/traceroute.h" 13 | #include "flashroute/utils.h" 14 | 15 | namespace flashroute { 16 | 17 | void Hitlist::loadHitlist(const std::string& filePath, 18 | Tracerouter* tracerouter) { 19 | if (filePath.empty()) { 20 | LOG(INFO) << "Hitlist disabled."; 21 | return; 22 | } 23 | 24 | LOG(INFO) << "Load hitlist from file: " << filePath; 25 | std::ifstream in(filePath); 26 | int64_t count = 0; 27 | for (std::string line; getline(in, line);) { 28 | if (!line.empty()) { 29 | std::vector subs = 30 | absl::StrSplit(line, "\t"); 31 | // The minimum length of IP addresses is greater/equal than 7 (1.1.1.1) 32 | if (subs.size() != 3 || subs[subs.size() - 1].size() < 7) continue; 33 | int32_t confidence = std::stoi(subs[subs.size()-2]); 34 | auto ip = std::unique_ptr( 35 | parseIpFromStringToIpAddress(subs[subs.size() - 1])); 36 | if (confidence > 0) { 37 | // tracerouter->setDcbIpAddress(*ip); 38 | count++; 39 | } 40 | } 41 | } 42 | in.close(); 43 | LOG(INFO) << count << " load addresses from hitlist."; 44 | } 45 | 46 | } // namespace flashroute 47 | -------------------------------------------------------------------------------- /flashroute/hitlist.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #pragma once 3 | 4 | #include 5 | 6 | #include "flashroute/traceroute.h" 7 | 8 | namespace flashroute { 9 | 10 | // Hitlist 11 | // Load Hitlist and, for each target block, use Hitlist to select the IP 12 | // addresses that are likly to be active. 13 | 14 | class Hitlist { 15 | public: 16 | static void loadHitlist(const std::string& filePath, 17 | Tracerouter* tracerouter); 18 | }; 19 | 20 | } // namespace flashroute 21 | -------------------------------------------------------------------------------- /flashroute/network.cc: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #include "flashroute/network.h" 3 | 4 | #include 5 | #include 6 | 7 | #include "glog/logging.h" 8 | #include 9 | #include 10 | 11 | #include "flashroute/bounded_buffer.h" 12 | #include "flashroute/prober.h" 13 | #include "flashroute/utils.h" 14 | 15 | namespace flashroute { 16 | 17 | const uint16_t kPacketBufferSize = 2048; // Default sending buffer size which 18 | // will be used to generate packets. 19 | const uint16_t kReceivingBufferSize = 20 | 2000; // Default receiving buffer size which will be used to store received 21 | // packets. 22 | const uint32_t kThreadPoolSize = 4; // Default thread pool size. 23 | 24 | NetworkManager::NetworkManager(Prober* prober, const std::string& interface, 25 | const uint64_t sendingRate, const bool ipv4) 26 | : prober_(prober), 27 | ipv4_(ipv4), 28 | interface_(interface), 29 | stopReceiving_(false), 30 | expectedRate_(static_cast(sendingRate)), 31 | sentPackets_(0), 32 | receivedPackets_(0) { 33 | createRawSocket(); 34 | 35 | if (!interface.empty()) { 36 | localIpAddress_ = std::unique_ptr( 37 | parseIpFromStringToIpAddress(getAddressByInterface(interface, ipv4_))); 38 | } else { 39 | LOG(FATAL) << "Network Module: Local address is not configured."; 40 | } 41 | 42 | // Initialize sending buffer 43 | if (ipv4_) { 44 | sendingBuffer_ = 45 | std::make_unique>(expectedRate_); 46 | } else { 47 | sendingBuffer6_ = 48 | std::make_unique>(expectedRate_); 49 | } 50 | 51 | if (expectedRate_ < 1) { 52 | VLOG(2) << "Network Module: Sendg rate limit is disabled since expected " 53 | "rate is " 54 | << expectedRate_; 55 | } 56 | } 57 | 58 | NetworkManager::~NetworkManager() { 59 | stopListening(); 60 | close(sendingSocket_); 61 | } 62 | 63 | void NetworkManager::resetProber(Prober* prober) { 64 | prober_ = prober; 65 | } 66 | 67 | void NetworkManager::probeRemoteHost(const IpAddress& destinationIp, 68 | const uint8_t ttl) { 69 | static uint8_t buffer[kPacketBufferSize]; 70 | size_t packetSize = 71 | prober_->packProbe(destinationIp, *localIpAddress_, ttl, buffer); 72 | 73 | sendRawPacket(buffer, packetSize); 74 | } 75 | 76 | void NetworkManager::scheduleProbeRemoteHost(const IpAddress& destinationIp, 77 | const uint8_t ttl) { 78 | if (expectedRate_ >= 1) { 79 | if (destinationIp.isIpv4()) { 80 | ProbeUnitIpv4 tmp(dynamic_cast(destinationIp), ttl); 81 | sendingBuffer_->pushFront(tmp); 82 | } else { 83 | // TODO(neohuang): handle IPv6. 84 | ProbeUnitIpv6 tmp(dynamic_cast(destinationIp), ttl); 85 | sendingBuffer6_->pushFront(tmp); 86 | } 87 | } else { 88 | // if we disable rate limit. 89 | probeRemoteHost(destinationIp, ttl); 90 | } 91 | } 92 | 93 | void NetworkManager::startListening() { 94 | stopReceiving_ = false; 95 | createIcmpSocket(); 96 | 97 | threadPool_.reset(new boost::asio::thread_pool(kThreadPoolSize)); 98 | // Initialize sending thread. Sending thread is to drain the sending buffer 99 | // and put the packet on wire. 100 | boost::asio::post(*threadPool_.get(), [this]() { runSendingThread(); }); 101 | 102 | boost::asio::post(*threadPool_.get(), [this]() { receiveIcmpPacket(); }); 103 | 104 | VLOG(2) << "Network Module: Start capturing incoming ICMP packets."; 105 | } 106 | 107 | void NetworkManager::stopListening() { 108 | if (mainReceivingSocket_ != 0) { 109 | shutdown(mainReceivingSocket_, SHUT_RDWR); 110 | { 111 | std::lock_guard guard(stopReceivingMutex_); 112 | stopReceiving_ = true; 113 | } 114 | threadPool_->join(); 115 | close(mainReceivingSocket_); 116 | } 117 | VLOG(2) << "Network Module: All working threads are recycled."; 118 | } 119 | 120 | bool NetworkManager::createIcmpSocket() { 121 | // create raw socket return -1 if failed 122 | 123 | int on = 1; 124 | if (ipv4_) { 125 | mainReceivingSocket_ = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 126 | if (mainReceivingSocket_ < 0 || 127 | setsockopt(mainReceivingSocket_, IPPROTO_IP, IP_HDRINCL, 128 | reinterpret_cast(&on), sizeof(on)) < 0) { 129 | LOG(FATAL) 130 | << "Network Module: Raw ICMP receiving socket failed to initialize."; 131 | return false; 132 | } 133 | } else { 134 | mainReceivingSocket_ = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IPV6)); 135 | // Bind socket to the device. 136 | if (mainReceivingSocket_ < 0 || 137 | setsockopt(mainReceivingSocket_, SOL_SOCKET, SO_BINDTODEVICE, 138 | interface_.c_str(), interface_.length() + 1) < 0) { 139 | LOG(FATAL) 140 | << "Network Module: Raw ICMP receiving socket failed to initialize."; 141 | return false; 142 | } 143 | } 144 | 145 | int optval = 0; 146 | int socklen = sizeof(optval); 147 | int bufsize = 400 * 1024; 148 | if (getsockopt(mainReceivingSocket_, SOL_SOCKET, SO_RCVBUF, 149 | reinterpret_cast(&optval), 150 | reinterpret_cast(&socklen)) < 0) { 151 | VLOG(2) << "Network Module: Failed to get receiving buffer size."; 152 | } else { 153 | VLOG(2) << "Network Module: Receiving buffer size is " << optval; 154 | } 155 | if (setsockopt(mainReceivingSocket_, SOL_SOCKET, SO_RCVBUF, &bufsize, 156 | sizeof(bufsize)) < 0) { 157 | VLOG(2) << "Network Module: Failed to set receiving buffer size."; 158 | } else { 159 | VLOG(2) << "Network Module: Receiving buffer has been set to " << bufsize; 160 | } 161 | VLOG(2) << "Network Module: Raw ICMP receiving socket initialized."; 162 | return true; 163 | } 164 | 165 | bool NetworkManager::createRawSocket() { 166 | // create raw socket return -1 if failed 167 | if (ipv4_) { 168 | sendingSocket_ = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 169 | int on = 1; 170 | if (sendingSocket_ < 0 || 171 | setsockopt(sendingSocket_, IPPROTO_IP, IP_HDRINCL, 172 | reinterpret_cast(&on), sizeof(on)) < 0) { 173 | LOG(FATAL) << "The sending socket initialize failed."; 174 | return false; 175 | } 176 | VLOG(2) << "Network Module: Raw Ipv4 sending socket initialized."; 177 | } else { 178 | sendingSocket_ = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW); 179 | int on = 1; 180 | #ifdef IPV6_HDRINCL 181 | if (sendingSocket_ < 0 || 182 | setsockopt(sendingSocket_, IPPROTO_IPV6, IPV6_HDRINCL, 183 | reinterpret_cast(&on), sizeof(on)) < 0) { 184 | LOG(FATAL) << "The sending socket initialize failed."; 185 | return false; 186 | } 187 | #else 188 | LOG(FATAL) << "Flashroute's IPv6 scan is not competible with the OS."; 189 | #endif 190 | VLOG(2) << "Network Module: Raw Ipv6 sending socket initialized."; 191 | } 192 | return true; 193 | } 194 | 195 | void NetworkManager::runSendingThread() { 196 | if (expectedRate_ < 1) { 197 | VLOG(2) << "Network module: sending thread disabled."; 198 | } 199 | VLOG(2) << "Network module: Sending thread initialized."; 200 | ProbeUnitIpv4 tmp; 201 | ProbeUnitIpv6 tmp6; 202 | 203 | uint64_t sentProbes = 0; 204 | auto lastSeenTimestamp = std::chrono::steady_clock::now(); 205 | while (!isStopReceiving()) { 206 | if ((ipv4_ && sendingBuffer_->empty()) || 207 | (!ipv4_ && sendingBuffer6_->empty())) { 208 | continue; 209 | } 210 | double timeDifference = 211 | std::chrono::duration_cast( 212 | std::chrono::steady_clock::now() - lastSeenTimestamp) 213 | .count(); 214 | if (timeDifference >= 1000) { 215 | sentProbes = 0; 216 | lastSeenTimestamp = std::chrono::steady_clock::now(); 217 | } 218 | if (sentProbes >= expectedRate_) { 219 | continue; 220 | } 221 | if (ipv4_) { 222 | sendingBuffer_->popBack(&tmp); 223 | probeRemoteHost(tmp.ip, tmp.ttl); 224 | } else { 225 | sendingBuffer6_->popBack(&tmp6); 226 | probeRemoteHost(tmp6.ip, tmp6.ttl); 227 | } 228 | sentProbes += 1; 229 | } 230 | VLOG(2) << "Network module: Sending thread recycled."; 231 | } 232 | 233 | void NetworkManager::receiveIcmpPacket() { 234 | VLOG(2) << "Network module: Receiving thread initialized."; 235 | uint8_t buffer[kReceivingBufferSize]; 236 | while (!isStopReceiving()) { 237 | int32_t packetSize = recv(mainReceivingSocket_, &buffer, sizeof(buffer), 0); 238 | // an icmp packet has to have an 8-byte ip header and a 20-byte icmp 239 | // header 240 | if (ipv4_) { 241 | if (packetSize < 28) { 242 | continue; 243 | } 244 | 245 | { 246 | std::lock_guard guard(receivedPacketMutex_); 247 | receivedPackets_ += 1; 248 | } 249 | prober_->parseResponse(buffer, packetSize, SocketType::ICMP); 250 | } else { 251 | if (packetSize < 48) { 252 | continue; 253 | } 254 | 255 | { 256 | std::lock_guard guard(receivedPacketMutex_); 257 | receivedPackets_ += 1; 258 | } 259 | // Currently the IPv6 socket returns the entire ethernet frame. 260 | prober_->parseResponse(buffer + 14, packetSize - 14, SocketType::ICMP); 261 | } 262 | } 263 | VLOG(2) << "Network module: Receiving thread recycled."; 264 | } 265 | 266 | void NetworkManager::sendRawPacket(uint8_t* buffer, size_t length) { 267 | if (ipv4_) { 268 | struct sockaddr_in sin; 269 | sin.sin_family = AF_INET; 270 | sin.sin_port = 80; 271 | sin.sin_addr.s_addr = 1; 272 | if (sendto(sendingSocket_, buffer, length, 0, (struct sockaddr*)&sin, 273 | sizeof(sin)) < 0) { 274 | LOG(ERROR) << "Send packet failed. Errno: " << errno; 275 | } else { 276 | std::lock_guard guard(sentPacketsMutex_); 277 | sentPackets_ += 1; 278 | } 279 | } else { 280 | struct sockaddr_in6 sin; 281 | sin.sin6_family = AF_INET6; 282 | sin.sin6_port = 0; 283 | if (sendto(sendingSocket_, buffer, length, 0, (struct sockaddr*)&sin, 284 | sizeof(sin)) < 0) { 285 | LOG(ERROR) << "Send packet failed. Errno: " << errno; 286 | } else { 287 | std::lock_guard guard(sentPacketsMutex_); 288 | sentPackets_ += 1; 289 | } 290 | } 291 | } 292 | 293 | uint64_t NetworkManager::getSentPacketCount() { 294 | std::lock_guard guard(sentPacketsMutex_); 295 | return sentPackets_; 296 | } 297 | 298 | uint64_t NetworkManager::getReceivedPacketCount() { 299 | std::lock_guard guard(receivedPacketMutex_); 300 | return receivedPackets_; 301 | } 302 | 303 | bool NetworkManager::isStopReceiving() { 304 | std::lock_guard guard(stopReceivingMutex_); 305 | return stopReceiving_; 306 | } 307 | 308 | } // namespace flashroute 309 | -------------------------------------------------------------------------------- /flashroute/network.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #pragma once 3 | 4 | #include 5 | 6 | #include // ETH_P_IP = 0x0800, ETH_P_IPV6 = 0x86DD 7 | #include // struct sockaddr_ll (see man 7 packet) 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "flashroute/address.h" 15 | #include 16 | #include "flashroute/bounded_buffer.h" 17 | #include "flashroute/prober.h" 18 | 19 | namespace flashroute { 20 | 21 | class ProbeUnitIpv4 { 22 | public: 23 | Ipv4Address ip; 24 | uint8_t ttl; 25 | ProbeUnitIpv4() : ip(0), ttl(0) {} 26 | ProbeUnitIpv4(const Ipv4Address& _ip, const uint8_t _ttl) 27 | : ip(_ip), ttl(_ttl) {} 28 | }; 29 | 30 | class ProbeUnitIpv6 { 31 | public: 32 | Ipv6Address ip; 33 | uint8_t ttl; 34 | ProbeUnitIpv6() : ip(0), ttl(0) {} 35 | ProbeUnitIpv6(const Ipv6Address& _ip, const uint8_t _ttl) 36 | : ip(_ip), ttl(_ttl) {} 37 | }; 38 | 39 | /** 40 | * Network manager handles sending and receiving packets. 41 | * 42 | * Example: 43 | * 44 | * PacketReceiverCallback callback = 45 | * [](uint32_t destination, uint32_t responder, 46 | * uint8_t distance, bool fromDestination) { 47 | * // The tracerouting logic on response. 48 | * }; 49 | * 50 | * UdpProber prober(...); 51 | * 52 | * NetworkManager networkManager( 53 | * &prober, // The prober to process packets. 54 | * "eth0", // The interface to send the probe. 55 | * 100000, // The packet sending rate. 56 | * true // Tell network manager to use ipv4 or ipv6 sockets. 57 | * ); 58 | * 59 | * // Start capturing the incoming packets. 60 | * networkManager.startListening(); 61 | * 62 | * // Stop capturing; 63 | * networkManager.stopListening(); 64 | * 65 | * // Print the number of sent packet. 66 | * LOG(INFO) << networkManager.getSentPacketCount(); 67 | * 68 | * // Print the number of received packet. 69 | * LOG(INFO) << networkManager.getReceivedPacketCount(); 70 | * 71 | */ 72 | 73 | class NetworkManager { 74 | public: 75 | NetworkManager(Prober* prober, const std::string& interface, 76 | const uint64_t sendingRate, const bool ipv4); 77 | 78 | ~NetworkManager(); 79 | 80 | // Scheduale to send a probe. Sending accords to the pre-determined sending 81 | // rate. 82 | void scheduleProbeRemoteHost(const IpAddress& destinationIp, 83 | const uint8_t ttl); 84 | 85 | // Start capturing the packets. 86 | void startListening(); 87 | 88 | // Stop capturing the packets. 89 | void stopListening(); 90 | 91 | // Return the statistics of sent/received packets. 92 | uint64_t getSentPacketCount(); 93 | 94 | uint64_t getReceivedPacketCount(); 95 | 96 | void resetProber(Prober* prober); 97 | 98 | private: 99 | Prober* prober_; 100 | std::unique_ptr localIpAddress_; 101 | 102 | bool ipv4_; 103 | 104 | // The socket to receive Icmp packets 105 | int mainReceivingSocket_; 106 | int sendingSocket_; 107 | 108 | // Ethernet for Ipv6 109 | std::string interface_; 110 | sockaddr_ll device_; 111 | uint8_t destMacAddress_[6]; 112 | 113 | // Thread pool 114 | std::unique_ptr threadPool_; 115 | 116 | bool stopReceiving_; 117 | std::mutex stopReceivingMutex_; 118 | 119 | // Sending buffer 120 | std::unique_ptr> sendingBuffer_; 121 | std::unique_ptr> sendingBuffer6_; 122 | 123 | // Rate control 124 | double expectedRate_; 125 | 126 | // Statistic 127 | uint64_t sentPackets_; 128 | std::mutex sentPacketsMutex_; 129 | uint64_t receivedPackets_; 130 | std::mutex receivedPacketMutex_; 131 | 132 | bool createIcmpSocket(); 133 | 134 | bool createRawSocket(); 135 | 136 | void runSendingThread(); 137 | 138 | // Send the probe immediately. 139 | void probeRemoteHost(const IpAddress& destinationIp, const uint8_t ttl); 140 | 141 | void receiveIcmpPacket(); 142 | 143 | void sendRawPacket(uint8_t* buffer, size_t len); 144 | 145 | bool isStopReceiving(); 146 | }; 147 | 148 | } // namespace flashroute 149 | -------------------------------------------------------------------------------- /flashroute/output_parser.cc: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #include "flashroute/output_parser.h" 3 | 4 | #include 5 | 6 | namespace flashroute { 7 | 8 | uint32_t kDataElementLength = 39; 9 | 10 | void updateDcbsBasedOnHistory(const std::string& filepath, 11 | DcbManager* dcbManager) { 12 | OutputParser outputParser{filepath}; 13 | 14 | std::unordered_map 15 | maxObservedRouteLength; 16 | // Loads the outputs and update the analysis program. 17 | while (outputParser.hasNext()) { 18 | ParsedElement& element = outputParser.next(); 19 | auto result = maxObservedRouteLength.find(element.destination); 20 | if (result == maxObservedRouteLength.end()) { 21 | maxObservedRouteLength.insert( 22 | {element.destination->clone(), element.distance}); 23 | } else { 24 | // Update the max distance for each destiantion. 25 | maxObservedRouteLength[element.destination] = std::max( 26 | maxObservedRouteLength[element.destination], element.distance); 27 | } 28 | } 29 | 30 | for (auto element : maxObservedRouteLength) { 31 | // Searchs the dcbs based on prefix and update. 32 | auto* result = dcbManager->getDcbsByAddress(*element.first); 33 | if (result == nullptr) continue; 34 | for (auto* dcb : *result) { 35 | dcb->updateSplitTtl(element.second, true); 36 | } 37 | } 38 | 39 | // Clean up 40 | while (maxObservedRouteLength.size() > 0) { 41 | auto element = maxObservedRouteLength.begin(); 42 | auto keyAddress = element->first; 43 | maxObservedRouteLength.erase(keyAddress); 44 | delete keyAddress; 45 | } 46 | } 47 | 48 | OutputParser::OutputParser(const std::string& output) { 49 | inFile_.open(output, std::ios::in | std::ios::binary); 50 | } 51 | 52 | OutputParser::~OutputParser() { 53 | if (inFile_.is_open()) { 54 | inFile_.close(); 55 | } 56 | } 57 | 58 | bool OutputParser::hasNext() { 59 | return (inFile_.is_open() && inFile_.peek() != EOF); 60 | } 61 | 62 | ParsedElement& OutputParser::next() { 63 | if (hasNext()) { 64 | inFile_.read(reinterpret_cast(&rawNext_), kDataElementLength); 65 | if (inFile_.gcount() != kDataElementLength) { 66 | // Underflow 67 | } else { 68 | if (rawNext_.ipv4) { 69 | next_.destination = &next_.destinationV4; 70 | next_.responder = &next_.responderV4; 71 | next_.destinationV4 = Ipv4Address(rawNext_.destination[0]); 72 | next_.responderV4 = Ipv4Address(rawNext_.responder[0]); 73 | } else { 74 | next_.destination = &next_.destinationV6; 75 | next_.responder = &next_.responderV6; 76 | next_.destinationV6 = Ipv6Address( 77 | *reinterpret_cast(rawNext_.destination)); 78 | next_.responderV6 = 79 | Ipv6Address(*reinterpret_cast(rawNext_.responder)); 80 | } 81 | next_.distance = rawNext_.distance; 82 | next_.fromDestination = rawNext_.fromDestination; 83 | next_.rtt = rawNext_.rtt; 84 | } 85 | } 86 | return next_; 87 | } 88 | 89 | } // namespace flashroute 90 | -------------------------------------------------------------------------------- /flashroute/output_parser.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "flashroute/address.h" 10 | #include "flashroute/dcb_manager.h" 11 | 12 | namespace flashroute { 13 | 14 | void updateDcbsBasedOnHistory(const std::string& filepath, 15 | DcbManager* dcbManager); 16 | 17 | // This is used to cast the response element stored in a binary file. 18 | struct DataElementCast { 19 | uint32_t destination[4]; 20 | uint32_t responder[4]; 21 | uint32_t rtt; 22 | uint8_t distance; 23 | uint8_t fromDestination; 24 | uint8_t ipv4; 25 | } __attribute__((packed)); 26 | 27 | struct ParsedElement { 28 | IpAddress* destination; 29 | IpAddress* responder; 30 | Ipv4Address destinationV4; 31 | Ipv4Address responderV4; 32 | Ipv6Address destinationV6; 33 | Ipv6Address responderV6; 34 | uint32_t rtt; 35 | uint8_t distance; 36 | bool fromDestination; 37 | bool ipv4; 38 | }; 39 | 40 | // Update splitting point for each dcb based on the history probing results. 41 | void updateDcbsBasedOnHistory(const std::string& filepath, 42 | DcbManager* dcbManager); 43 | 44 | class OutputParser { 45 | public: 46 | explicit OutputParser(const std::string& output); 47 | ~OutputParser(); 48 | 49 | ParsedElement& next(); 50 | 51 | bool hasNext(); 52 | 53 | private: 54 | std::ifstream inFile_; 55 | ParsedElement next_; 56 | DataElementCast rawNext_; 57 | bool isEnd_; 58 | 59 | void readOneElement(); 60 | }; 61 | 62 | } // namespace flashroute 63 | -------------------------------------------------------------------------------- /flashroute/prober.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include // ip header 11 | #include // icmp header 12 | #include 13 | #include // udp header 14 | 15 | #include "flashroute/address.h" 16 | 17 | namespace flashroute { 18 | 19 | enum class SocketType { UDP, ICMP, TCP }; 20 | 21 | const uint32_t kPacketMessageDefaultPayloadSize = 1500; 22 | 23 | struct PacketIcmp { 24 | struct ip ip; 25 | struct icmp icmp; 26 | } __attribute__((packed)); 27 | 28 | struct PacketUdp { 29 | struct ip ip; 30 | struct udphdr udp; 31 | char payload[kPacketMessageDefaultPayloadSize]; 32 | } __attribute__((packed)); 33 | 34 | struct PacketTcp { 35 | struct ip ip; 36 | struct tcphdr tcp; 37 | char payload[kPacketMessageDefaultPayloadSize]; 38 | } __attribute__((packed)); 39 | 40 | using PacketReceiverCallback = 41 | std::function; 44 | 45 | class Prober { 46 | public: 47 | virtual size_t packProbe(const IpAddress& destinationIp, 48 | const IpAddress& sourceIp, const uint8_t ttl, 49 | uint8_t* packetBuffer) = 0; 50 | 51 | virtual void parseResponse(uint8_t* buffer, size_t size, 52 | SocketType socketType) = 0; 53 | 54 | virtual void setChecksumOffset(int32_t checksumOffset) = 0; 55 | 56 | virtual uint64_t getChecksumMismatches() = 0; 57 | virtual uint64_t getDistanceAbnormalities() = 0; 58 | virtual uint64_t getOtherMismatches() = 0; 59 | }; 60 | 61 | } // namespace flashroute 62 | -------------------------------------------------------------------------------- /flashroute/single_host.cc: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #include "flashroute/single_host.h" 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include "glog/logging.h" 9 | 10 | #include "flashroute/utils.h" 11 | #include "flashroute/udp_prober.h" 12 | #include "flashroute/udp_prober_v6.h" 13 | 14 | namespace flashroute { 15 | 16 | SingleHost::SingleHost(const uint16_t srcPort, const uint16_t dstPort, 17 | const uint8_t ttlOffset) 18 | : srcPort_(srcPort), dstPort_(dstPort), ttlOffset_(ttlOffset) { 19 | results_ = new std::unordered_map< 20 | uint8_t, std::tuple, uint32_t>>(); 21 | } 22 | 23 | SingleHost::~SingleHost() { 24 | delete results_; 25 | } 26 | 27 | void SingleHost::startScan(const std::string& target, 28 | const std::string& interface) { 29 | auto remoteHost = 30 | std::unique_ptr(parseIpFromStringToIpAddress(target)); 31 | 32 | std::string localIpAddress = 33 | getAddressByInterface(interface, remoteHost->isIpv4()); 34 | 35 | 36 | PacketReceiverCallback response_handler = 37 | [this](const IpAddress& destination, const IpAddress& responder, 38 | uint8_t distance, uint32_t rtt, bool fromDestination, bool ipv4, 39 | void* packetBuffer, uint32_t packetLen) { 40 | parseIcmpProbing(destination, responder, distance, rtt, fromDestination, 41 | ipv4, packetBuffer, packetLen); 42 | }; 43 | 44 | Prober* prober; 45 | if (remoteHost->isIpv4()) { 46 | prober = new UdpProber(&response_handler, 0, 0, dstPort_, "test", true, 47 | ttlOffset_); 48 | } else { 49 | prober = new UdpProberIpv6(&response_handler, 0, 0, dstPort_, "test", 50 | ttlOffset_); 51 | } 52 | NetworkManager networkManager(prober, interface, 100, remoteHost->isIpv4()); 53 | networkManager.startListening(); 54 | 55 | for (uint8_t i = 1 + ttlOffset_; i <= 32 + ttlOffset_; i ++) { 56 | networkManager.scheduleProbeRemoteHost(*remoteHost, i); 57 | } 58 | 59 | sleep(3); 60 | 61 | for (uint8_t i = 1 + ttlOffset_; i <= 32 + ttlOffset_; i++) { 62 | if (results_->find(i) == results_->end()) { 63 | LOG(INFO) << boost::format("%1% %|5t|*") % static_cast(i); 64 | } else { 65 | LOG(INFO) << boost::format("%1% %|5t|%2% %|5t|%3% ms") % 66 | static_cast(i) % 67 | parseIpFromIpAddressToString( 68 | *std::get<0>(results_->find(i)->second)) % 69 | std::get<1>(results_->find(i)->second); 70 | } 71 | } 72 | 73 | LOG(INFO) << " ============================="; 74 | 75 | LOG(INFO) << "Checksum Mismatches: " << prober->getChecksumMismatches(); 76 | LOG(INFO) << "Distance Abnormalities: " << prober->getDistanceAbnormalities(); 77 | LOG(INFO) << "Other Mismatches: " << prober->getOtherMismatches(); 78 | } 79 | 80 | bool SingleHost::parseIcmpProbing(const IpAddress& destination, 81 | const IpAddress& responder, uint8_t distance, 82 | uint32_t rtt, bool fromDestination, bool ipv4, 83 | void* packetBuffer, uint32_t packetLen) { 84 | results_->insert( 85 | {distance, 86 | std::make_tuple(std::shared_ptr(responder.clone()), rtt)}); 87 | return true; 88 | } 89 | 90 | } // namespace flashroute 91 | -------------------------------------------------------------------------------- /flashroute/single_host.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "flashroute/dcb_manager.h" 10 | #include "flashroute/network.h" 11 | #include "flashroute/address.h" 12 | 13 | namespace flashroute { 14 | 15 | class SingleHost { 16 | public: 17 | SingleHost(const uint16_t srcPort, const uint16_t dstPort, 18 | const uint8_t ttlOffset); 19 | 20 | ~SingleHost(); 21 | 22 | void startScan(const std::string& target, const std::string& interface); 23 | 24 | bool parseIcmpProbing(const IpAddress& destination, 25 | const IpAddress& responder, uint8_t distance, 26 | uint32_t rtt, bool fromDestination, bool ipv4, 27 | void* packetBuffer, uint32_t packetLen); 28 | 29 | private: 30 | uint16_t srcPort_; 31 | uint16_t dstPort_; 32 | uint8_t ttlOffset_; 33 | 34 | std::unordered_map, uint32_t>>* 35 | results_; 36 | }; 37 | 38 | } // namespace flashroute 39 | 40 | -------------------------------------------------------------------------------- /flashroute/targets.cc: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | 3 | #include "flashroute/targets.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "absl/strings/numbers.h" 11 | #include "absl/strings/str_split.h" 12 | #include "absl/strings/string_view.h" 13 | #include "flashroute/blacklist.h" 14 | #include "flashroute/dcb_manager.h" 15 | #include "flashroute/utils.h" 16 | #include "glog/logging.h" 17 | #include 18 | 19 | namespace flashroute { 20 | 21 | Targets::Targets(const uint8_t defaultSplitTtl, const uint32_t seed, 22 | Blacklist* blacklist, BogonFilter* bogerFilter) 23 | : blacklist_(blacklist), 24 | bogerFilter_(bogerFilter), 25 | defaultSplitTtl_(defaultSplitTtl), 26 | seed_(seed) {} 27 | 28 | DcbManager* Targets::loadTargetsFromFile( 29 | absl::string_view filePath, const uint8_t granularity, 30 | const bool LookupByPrefixSupport) const { 31 | DcbManager* dcbManager = 32 | new DcbManager(1000, granularity, seed_, LookupByPrefixSupport); 33 | if (filePath.empty()) { 34 | VLOG(2) << "Targets disabled."; 35 | return dcbManager; 36 | } 37 | 38 | VLOG(2) << "Load targets from file: " << filePath; 39 | auto filePathStr = std::string(filePath); 40 | std::ifstream in(filePathStr); 41 | int64_t count = 0; 42 | for (std::string line; std::getline(in, line);) { 43 | if (!line.empty()) { 44 | // Example 45 | // 127.0.0.1:10 IPAddress is 127.0.0.1 and split ttl is 10 46 | std::vector parts = absl::StrSplit(line, ":"); 47 | auto result = parseIpFromStringToIpAddress(std::string(parts[0])); 48 | int splitTtl = defaultSplitTtl_; 49 | if (parts.size() == 2) { 50 | if (!absl::SimpleAtoi(parts[1], &splitTtl)) { 51 | LOG(FATAL) << "split ttl convert fails."; 52 | } 53 | } 54 | 55 | if (result == NULL) continue; 56 | auto ip = std::unique_ptr(result); 57 | // Set ip address 58 | if ((blacklist_ == nullptr || !blacklist_->contains(*ip)) && 59 | (bogerFilter_ == nullptr || !bogerFilter_->isBogonAddress(*ip))) { 60 | dcbManager->addDcb(*ip, static_cast(splitTtl)); 61 | } 62 | count++; 63 | } 64 | } 65 | in.close(); 66 | VLOG(2) << "Load " << count << " addresses from file."; 67 | 68 | return dcbManager; 69 | } 70 | 71 | DcbManager* Targets::generateTargetsFromNetwork( 72 | absl::string_view targetNetwork, const uint8_t granularity, 73 | const bool LookupByPrefixSupport) const { 74 | DcbManager* dcbManager = 75 | new DcbManager(1000, granularity, seed_, LookupByPrefixSupport); 76 | 77 | std::vector parts = absl::StrSplit(targetNetwork, "/"); 78 | if (parts.size() != 2) { 79 | LOG(FATAL) << "Target network format is incorrect!!! " << targetNetwork; 80 | } 81 | 82 | uint32_t subnetPrefixLength = 0; 83 | 84 | if (!absl::SimpleAtoi(parts[1], &subnetPrefixLength)) { 85 | LOG(FATAL) << "Failed to parse the target network."; 86 | } 87 | 88 | IpAddress* targetBaseAddress = 89 | parseIpFromStringToIpAddress(std::string(parts[0])); 90 | 91 | IpAddress* targetNetworkFirstAddress_ = 92 | getFirstAddressOfBlock(*targetBaseAddress, subnetPrefixLength); 93 | IpAddress* targetNetworkLastAddress_ = 94 | getLastAddressOfBlock(*targetBaseAddress, subnetPrefixLength); 95 | 96 | if (*targetNetworkFirstAddress_ >= *targetNetworkLastAddress_) { 97 | LOG(FATAL) << "Ip address range is incorrect."; 98 | } 99 | 100 | LOG(INFO) << boost::format("The target network is from %1% to %2%.") % 101 | parseIpFromIpAddressToString(*targetNetworkFirstAddress_) % 102 | parseIpFromIpAddressToString(*targetNetworkLastAddress_); 103 | 104 | if (targetBaseAddress->isIpv4()) { 105 | uint64_t targetNetworkSize = 106 | static_cast(targetNetworkLastAddress_->getIpv4Address()) - 107 | static_cast(targetNetworkFirstAddress_->getIpv4Address()) + 1; 108 | 109 | uint64_t blockFactor_ = 110 | static_cast(std::pow(2, 32 - granularity)); 111 | uint64_t dcbCount = static_cast(targetNetworkSize / blockFactor_); 112 | 113 | // set random seed. 114 | std::srand(seed_); 115 | uint32_t actualCount = 0; 116 | uint32_t bogonCount = 0; 117 | for (uint64_t i = 0; i < dcbCount; i++) { 118 | // randomly generate IP addresse avoid the first and last ip address 119 | // in the block. 120 | Ipv4Address tmp(targetNetworkFirstAddress_->getIpv4Address() + 121 | ((i) << (32 - granularity)) + 122 | (rand() % (blockFactor_ - 3)) + 2); 123 | 124 | if ((blacklist_ == nullptr || !blacklist_->contains(tmp)) && 125 | (bogerFilter_ == nullptr || !bogerFilter_->isBogonAddress(tmp))) { 126 | dcbManager->addDcb(tmp, defaultSplitTtl_); 127 | actualCount++; 128 | } else if (bogerFilter_ != nullptr && bogerFilter_->isBogonAddress(tmp)) { 129 | bogonCount ++; 130 | } 131 | } 132 | VLOG(2) << boost::format("Created %1% entries (1 reserved dcb).") % 133 | actualCount; 134 | VLOG(2) << "Bogon filter removes addresses " << bogonCount; 135 | } else { 136 | absl::uint128 targetNetworkSize = 137 | ntohll(targetNetworkLastAddress_->getIpv6Address()) - 138 | ntohll(targetNetworkFirstAddress_->getIpv6Address()) + 1; 139 | 140 | absl::uint128 blockFactor_ = 141 | static_cast(std::pow(2, 128 - granularity)); 142 | absl::uint128 dcbCount = 143 | static_cast(targetNetworkSize / blockFactor_); 144 | 145 | // set random seed. 146 | absl::uint128 actualCount = 0; 147 | std::srand(seed_); 148 | for (absl::uint128 i = 0; i < dcbCount; i++) { 149 | // randomly generate IP addresse avoid the first and last ip address 150 | // in the block. 151 | Ipv6Address tmp(htonll( 152 | ntohll(targetNetworkFirstAddress_->getIpv6Address()) + 153 | ((i) << (128 - granularity)) + (rand() % (blockFactor_ - 3)) + 2)); 154 | if (blacklist_ != nullptr && !blacklist_->contains(tmp)) { 155 | dcbManager->addDcb(tmp, defaultSplitTtl_); 156 | actualCount++; 157 | } 158 | } 159 | VLOG(2) << "Created " << actualCount << " entries (1 reserved dcb)."; 160 | } 161 | 162 | return dcbManager; 163 | } 164 | 165 | } // namespace flashroute 166 | -------------------------------------------------------------------------------- /flashroute/targets.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #pragma once 3 | 4 | #include 5 | 6 | #include "absl/strings/string_view.h" 7 | 8 | #include "flashroute/blacklist.h" 9 | #include "flashroute/dcb_manager.h" 10 | #include "flashroute/bogon_filter.h" 11 | 12 | namespace flashroute { 13 | 14 | class Targets { 15 | public: 16 | Targets(const uint8_t defaultSplitTtl, const uint32_t seed, 17 | Blacklist* blacklist, BogonFilter* bogerFilter); 18 | 19 | // Load targets from file. 20 | DcbManager* loadTargetsFromFile(absl::string_view filePath, 21 | const uint8_t granularity, 22 | const bool LookupByPrefixSupport) const; 23 | 24 | // Generate targets from a range. 25 | DcbManager* generateTargetsFromNetwork(absl::string_view targetNetwork, 26 | const uint8_t granularity, 27 | const bool LookupByPrefixSupport) const; 28 | 29 | private: 30 | Blacklist* blacklist_; 31 | BogonFilter* bogerFilter_; 32 | uint8_t defaultSplitTtl_; 33 | uint32_t seed_; 34 | uint32_t granularity_; 35 | 36 | }; 37 | 38 | } // namespace flashroute 39 | -------------------------------------------------------------------------------- /flashroute/traceroute.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "absl/strings/string_view.h" 15 | #include 16 | #include "glog/logging.h" 17 | 18 | #include "flashroute/address.h" 19 | #include "flashroute/dcb.h" 20 | #include "flashroute/dcb_manager.h" 21 | #include "flashroute/dump_result.h" 22 | #include "flashroute/network.h" 23 | #include "flashroute/prober.h" 24 | 25 | namespace flashroute { 26 | 27 | enum class ProbePhase { PREPROBE, PROBE, NONE }; 28 | 29 | enum class ProberType { UDP_PROBER, UDP_IDEMPOTENT_PROBER }; 30 | 31 | class NonstopSet { 32 | public: 33 | void loadFromFile(absl::string_view filePath); 34 | bool contains(const IpAddress* addr); 35 | 36 | private: 37 | std::unordered_set 38 | internalSet_; 39 | }; 40 | 41 | /** 42 | * Traceroute module contains the major logics and strategies of probing. 43 | * Examples: 44 | * Tracerouter tracerouter( 45 | * dcbManager, // an instance of DcbManager 46 | * networkManager, // an instance of NetworkManager 47 | * nonstopSet, // a set of addresses that backward probing 48 | * // should not stop when hitting. 49 | * 16, // Split TTL 50 | * 32, // Preprobing TTL 51 | * true, // Forward probing switch. 52 | * 5, // Forward Probing gaplimit. 53 | * true, // Remove redundancy in backward probing. 54 | * true, // Perform preprobing to measure distances. 55 | * true, // Perform distance prediction in preprobing. 56 | * 5, // Set the proximity span to appy prediction. 57 | * 1, // Set the number of scans. The scans after 58 | * // first round of scan will be treated as 59 | * // discovery-optimized mode. 60 | * 3, // Set the seed for guiding random processes, 61 | * // for example, destination generation or 62 | * // probing sequence randomization. 63 | * 53, // Set the expected source port (can be 64 | * // overrided by algorithm). 65 | * 53, // Set the expected destination port. 66 | * "test", // Message to encode into the payload of each 67 | * // probe. 68 | * true, // Control whether to encode timestamp to each 69 | * // probe. (Test function). 70 | * 0, // ttl offset to shift the range of ttl 71 | * true // Randomize addresses in following scans. 72 | * ); 73 | * 74 | * // startScan accepts two parameters: 75 | * // regenerateDestinationAfterPreprobing: control whether or not to 76 | * // regenerate destinations after preprobing. 77 | * // withTimestamp: 78 | * 79 | * tracerouter.startScan(false, true); 80 | * tracerouter.stopScan(); 81 | * 82 | */ 83 | 84 | class Tracerouter { 85 | public: 86 | // Define the constructor for mock testing. 87 | Tracerouter() {} 88 | Tracerouter(DcbManager* dcbManager, NetworkManager* networkManager, 89 | ResultDumper* resultDumper, NonstopSet* nonstopSet, 90 | const uint8_t defaultSplitTTL, const uint8_t defaultPreprobingTTL, 91 | const bool forwardProbing, const uint8_t forwardProbingGapLimit, 92 | const bool redundancyRemoval, const bool preprobing, 93 | const bool preprobingPrediction, 94 | const int32_t predictionProximitySpan, const int32_t scanCount, 95 | const uint16_t srcPort, const uint16_t dstPort, 96 | const std::string& defaultPayloadMessage, 97 | const bool encodeTimestamp, const uint8_t ttlOffset, 98 | const bool randomizeAddressinExtraScans); 99 | 100 | ~Tracerouter(); 101 | 102 | void startScan(ProberType proberType, bool ipv4, 103 | bool randomizeAddressAfterPreprobing); 104 | 105 | void stopScan() { stopProbing_ = true; } 106 | 107 | private: 108 | DcbManager* dcbManager_; 109 | // Control probing to stop 110 | bool stopProbing_; 111 | // Record the current probe phase which will be used for logging 112 | ProbePhase probePhase_; 113 | 114 | ResultDumper* resultDumper_; 115 | 116 | std::unique_ptr threadPool_; 117 | 118 | std::unique_ptr prober_; 119 | NetworkManager* networkManager_; 120 | 121 | NonstopSet* nonstopSet_; 122 | 123 | // The default max ttl which is also the starting hop-distance of probing. 124 | uint8_t defaultSplitTTL_; 125 | 126 | // The ttl to preprobe targets. 127 | uint8_t defaultPreprobingTTL_; 128 | 129 | // The offset of ttl. 130 | uint8_t ttlOffset_; 131 | 132 | // Control whether or not to forward probe. Per our design, we can forward 133 | // probe the router interfaces at a hop-distance further if tailing N nodes 134 | // repond TTL-expired message. 135 | bool forwardProbingMark_; 136 | // If tailing forwardProbingGapLimit_ nodes on the route respond a 137 | // TTL-expired message, we do the forward probing. 138 | uint8_t forwardProbingGapLimit_; 139 | 140 | // For each target, the program probes from the edge, the furthest distance, 141 | // back to the root so long as the no discovered router is found on the path. 142 | // Doing so let the tracerouter only works on the undiscovered part of path. 143 | bool redundancyRemovalMark_; 144 | 145 | bool preprobingMark_; 146 | bool preprobingPredictionMark_; 147 | int32_t preprobingPredictionProximitySpan_; 148 | 149 | int32_t scanCount_; 150 | bool randomizeAddressInExtraScans_; 151 | 152 | // Metrics 153 | uint64_t sentPreprobes_; 154 | uint64_t preprobeUpdatedCount_; 155 | 156 | uint64_t sentProbes_; 157 | uint64_t receivedResponses_; 158 | bool stopMonitoringMark_; 159 | uint32_t probingIterationRounds_; 160 | 161 | uint64_t droppedResponses_; 162 | uint64_t checksumMismatches_; 163 | uint64_t distanceAbnormalities_; 164 | uint64_t hitNonstopCount_; 165 | 166 | // Record all observed interfaces in backward probing. 167 | std::unordered_set 169 | backwardProbingStopSet_; 170 | 171 | // Record all observed interfaces in forward probing. 172 | std::unordered_set 174 | forwardProbingDiscoverySet_; 175 | 176 | // Seed for randomization. 177 | uint32_t seed_; 178 | 179 | // Network 180 | // Source port number will be override if packet encoding needs to use source 181 | // port to store information. 182 | 183 | uint16_t srcPort_; 184 | uint16_t dstPort_; 185 | 186 | std::string defaultPayloadMessage_; 187 | 188 | // The traversing sequence of Dcbs. 189 | std::vector> dcbLinkSnapshot_; 190 | 191 | // The variable to encode timestamp. 192 | bool encodeTimestamp_; 193 | 194 | void startPreprobing(ProberType proberType, bool ipv4); 195 | 196 | void startProbing(ProberType proberType, bool ipv4); 197 | 198 | bool parseIcmpPreprobing(const IpAddress& destination, 199 | const IpAddress& responder, uint8_t distance, 200 | bool fromDestination); 201 | 202 | bool parseIcmpProbing(const IpAddress& destination, 203 | const IpAddress& responder, uint8_t distance, 204 | bool fromDestination); 205 | 206 | void startMetricMonitoring(); 207 | 208 | void stopMetricMonitoring(); 209 | 210 | void calculateStatistic(uint64_t elapsedTime); 211 | }; 212 | 213 | } // namespace flashroute 214 | -------------------------------------------------------------------------------- /flashroute/trie.cc: -------------------------------------------------------------------------------- 1 | #include "trie.h" 2 | 3 | #include "glog/logging.h" 4 | 5 | namespace flashroute { 6 | 7 | bool getSignificantBitFromIpv4AddressByIndex(const IpAddress& addr, int position) { 8 | auto decimalAddr = addr.getIpv4Address(); 9 | return (decimalAddr >> (32 - position)) & 1; 10 | } 11 | 12 | TrieManager::TrieManager(bool ipv4) 13 | : ipv4_(ipv4), root_(std::make_unique(false)) {} 14 | 15 | bool TrieManager::checkAddressContained(const IpAddress& dest) { 16 | TrieNode* tmp = root_.get(); 17 | if (ipv4_) { 18 | for (int i = 1; i <= 32; i++) { 19 | if (tmp->end == true) return true; 20 | bool result = getSignificantBitFromIpv4AddressByIndex(dest, i); 21 | if (result) { 22 | if (tmp->one.get() == nullptr) { 23 | return tmp->end; 24 | } 25 | tmp = tmp->one.get(); 26 | } else { 27 | if (tmp->zero.get() == nullptr) { 28 | return tmp->end; 29 | } 30 | tmp = tmp->zero.get(); 31 | } 32 | } 33 | } 34 | return false; 35 | } 36 | 37 | void TrieManager::insert(const IpAddress& dest, const uint32_t length) { 38 | if (dest.isIpv4() != ipv4_) { 39 | // LOG(FATAL) << "Address type mismatch."; 40 | return; 41 | } 42 | TrieNode* tmp = root_.get(); 43 | if (ipv4_) { 44 | if (length > 32) 45 | LOG(FATAL) << "Prefix length is greater than the max length of address."; 46 | for (uint32_t i = 1; i <= length; i++) { 47 | bool result = getSignificantBitFromIpv4AddressByIndex(dest, i); 48 | if (result) { 49 | if (tmp->one.get() == nullptr) { 50 | tmp->one = std::make_unique(false); 51 | } 52 | tmp = tmp->one.get(); 53 | } else { 54 | if (tmp->zero.get() == nullptr) { 55 | tmp->zero = std::make_unique(false); 56 | } 57 | tmp = tmp->zero.get(); 58 | } 59 | } 60 | tmp->end = true; 61 | } 62 | } 63 | 64 | } // namespace flashroute -------------------------------------------------------------------------------- /flashroute/trie.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "flashroute/address.h" 9 | 10 | namespace flashroute { 11 | 12 | struct TrieNode { 13 | explicit TrieNode(bool isEnd) : end(isEnd) {} 14 | // The current bit 15 | bool bit; 16 | // Whether this is an end node. 17 | bool end; 18 | 19 | // Two branches. 20 | std::unique_ptr zero; 21 | std::unique_ptr one; 22 | }; 23 | 24 | class TrieManager { 25 | public: 26 | TrieManager(bool ipv4); 27 | void insert(const IpAddress& dest, const uint32_t length); 28 | 29 | // Check whether the address is contained by a prefix in the tree. 30 | bool checkAddressContained(const IpAddress& dest); 31 | 32 | private: 33 | bool ipv4_; 34 | std::unique_ptr root_; 35 | std::unique_ptr< 36 | std::unordered_set> 37 | coarseMap_; 38 | }; 39 | 40 | } // namespace flashroute 41 | -------------------------------------------------------------------------------- /flashroute/trie_test.cc: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #include "gtest/gtest.h" 3 | #include "gmock/gmock.h" 4 | 5 | #include "flashroute/trie.h" 6 | #include "flashroute/utils.h" 7 | 8 | using namespace flashroute; 9 | 10 | TEST(Trie, CheckPrefixLength24Contained) { 11 | // Ipv4 Trie 12 | TrieManager trie{true}; 13 | auto addr1 = std::unique_ptr( 14 | parseIpFromStringToIpAddress("123.123.123.123")); 15 | 16 | auto addr2 = std::unique_ptr( 17 | parseIpFromStringToIpAddress("123.123.123.124")); 18 | 19 | auto addr3 = std::unique_ptr( 20 | parseIpFromStringToIpAddress("123.123.123.0")); 21 | 22 | auto addr4 = std::unique_ptr( 23 | parseIpFromStringToIpAddress("123.123.123.255")); 24 | trie.insert(*addr1, 24); 25 | 26 | EXPECT_EQ(trie.checkAddressContained(*addr1), true); 27 | 28 | EXPECT_EQ(trie.checkAddressContained(*addr2), true); 29 | 30 | EXPECT_EQ(trie.checkAddressContained(*addr3), true); 31 | 32 | EXPECT_EQ(trie.checkAddressContained(*addr4), true); 33 | } 34 | 35 | TEST(Trie, CheckPrefixLength1Contained) { 36 | // Ipv4 Trie 37 | TrieManager trie{true}; 38 | auto addr1 = std::unique_ptr( 39 | parseIpFromStringToIpAddress("123.123.123.123")); 40 | 41 | auto addr2 = std::unique_ptr( 42 | parseIpFromStringToIpAddress("0.0.0.0")); 43 | 44 | auto addr3 = std::unique_ptr( 45 | parseIpFromStringToIpAddress("255.255.255.255")); 46 | 47 | auto addr4 = std::unique_ptr( 48 | parseIpFromStringToIpAddress("127.255.255.255")); 49 | 50 | auto addr5 = std::unique_ptr( 51 | parseIpFromStringToIpAddress("128.0.0.1")); 52 | trie.insert(*addr1, 1); 53 | 54 | EXPECT_EQ(trie.checkAddressContained(*addr1), true); 55 | 56 | EXPECT_EQ(trie.checkAddressContained(*addr2), true); 57 | 58 | EXPECT_EQ(trie.checkAddressContained(*addr3), false); 59 | 60 | EXPECT_EQ(trie.checkAddressContained(*addr4), true); 61 | 62 | EXPECT_EQ(trie.checkAddressContained(*addr5), false); 63 | } -------------------------------------------------------------------------------- /flashroute/udp_idempotent_prober.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | #include "flashroute/prober.h" 8 | 9 | namespace flashroute { 10 | 11 | /** 12 | * UDP Idempotent Prober handles packet construction and response parsing. The 13 | * difference of this from the regular UDP prober is that Idempotent Prober will 14 | * keep fields the same between two individual scan by removing timestamp 15 | * encoding. 16 | * 17 | * Example: 18 | * 19 | * // Callback function to parse the data. 20 | * PacketReceiverCallback callback = 21 | * [](const IpAddress& destination, const IpAddress& responder, 22 | * uint8_t distance, uint32_t rtt, bool fromDestination, 23 | * bool ipv4, void* packetHeader, size_t headerLen) { 24 | * // Handle response. 25 | * }; 26 | * 27 | * UdpProber prober( 28 | * callback, // Callback function to handle responses. 29 | * 0, // Checksum offset to support discovery-optimized mode. 30 | * 1, // 0 stands for preprobing, 1 stands for main probing. 31 | * 53, // Destination port number. 32 | * "message payload", //payload message. 33 | * false // Not encode timestamp into probe so scan is idempotent. 34 | * ); 35 | * 36 | * // Pass prober instance to network manager, so users can call 37 | * scheduleProbeRemoteHost to issue probe or process responses in callback func. 38 | * NetworkManager networkManager( 39 | * &prober, // The prober to process packets. 40 | * "eth0", // The interface to send the probe. 41 | * 100000, // The packet sending rate. 42 | * true // Tell network manager to use ipv4 or ipv6 sockets. 43 | * ); 44 | * 45 | */ 46 | class UdpIdempotentProber : public virtual Prober { 47 | public: 48 | UdpIdempotentProber(PacketReceiverCallback* callback, 49 | const int32_t checksumOffset, 50 | const uint8_t probePhaseCode, 51 | const uint16_t destinationPort, 52 | const std::string& payloadMessage, 53 | const bool encodeTimestamp, const uint8_t ttlOffset); 54 | 55 | // Construct probe. 56 | size_t packProbe(const IpAddress& destinationIp, const IpAddress& sourceIp, 57 | const uint8_t ttl, uint8_t* packetBuffer) override; 58 | 59 | // Parse responses. 60 | void parseResponse(uint8_t* buffer, size_t size, 61 | SocketType socketType) override; 62 | 63 | // Change checksum offset (support discovery-optimized mode.) 64 | void setChecksumOffset(int32_t checksumOffset); 65 | 66 | // Get metrics information 67 | uint64_t getChecksumMismatches() override; 68 | uint64_t getDistanceAbnormalities() override; 69 | uint64_t getOtherMismatches() override; 70 | 71 | private: 72 | PacketReceiverCallback* callback_; 73 | int32_t checksumOffset_; 74 | uint8_t probePhaseCode_; 75 | uint16_t destinationPort_; 76 | uint8_t ttlOffset_; 77 | std::string payloadMessage_; 78 | bool encodeTimestamp_; 79 | 80 | // Metrics 81 | uint64_t checksumMismatches_; 82 | uint64_t distanceAbnormalities_; 83 | uint64_t otherMismatches_; 84 | 85 | // Calculate checksum of ip address. 86 | uint16_t getDestAddrChecksum(const uint16_t* ipaddress, 87 | const uint16_t offset) const; 88 | 89 | // Calculate checksum of packet. 90 | uint16_t getChecksum(const uint8_t protocolValue, size_t packetLength, 91 | const uint16_t* src_addr, const uint16_t* dest_addr, 92 | uint16_t* buff) const; 93 | 94 | uint16_t getChecksum(uint16_t* buff, uint16_t offset) const; 95 | }; 96 | 97 | } // namespace flashroute 98 | -------------------------------------------------------------------------------- /flashroute/udp_prober.cc: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #include "flashroute/udp_prober.h" 3 | 4 | #include // ip header 5 | #include // icmp header 6 | #include 7 | #include // udp header 8 | 9 | #include 10 | #include 11 | 12 | #include "glog/logging.h" 13 | #include "flashroute/address.h" 14 | 15 | namespace flashroute { 16 | 17 | const uint8_t kUdpProtocol = 17; // Default UDP protocol id. 18 | 19 | // The maximum ttl we will explore. 20 | const uint8_t kMaxTtl = 32; 21 | 22 | UdpProber::UdpProber(PacketReceiverCallback* callback, 23 | const int32_t checksumOffset, const uint8_t probePhaseCode, 24 | const uint16_t destinationPort, 25 | const std::string& payloadMessage, 26 | const bool encodeTimestamp, const uint8_t ttlOffset) { 27 | probePhaseCode_ = probePhaseCode; 28 | callback_ = callback; 29 | checksumOffset_ = checksumOffset; 30 | payloadMessage_ = payloadMessage; 31 | destinationPort_ = htons(destinationPort); 32 | encodeTimestamp_ = encodeTimestamp; 33 | ttlOffset_ = ttlOffset; 34 | checksumMismatches_ = 0; 35 | distanceAbnormalities_ = 0; 36 | otherMismatches_ = 0; 37 | VLOG(2) << "UdpProber is initialized"; 38 | } 39 | 40 | size_t UdpProber::packProbe(const IpAddress& destinationIp, 41 | const IpAddress& sourceIp, const uint8_t ttl, 42 | uint8_t* packetBuffer) { 43 | uint32_t destinationIpDecimal = 44 | htonl((dynamic_cast(destinationIp)).getIpv4Address()); 45 | uint32_t sourceIpDecimal = 46 | htonl((dynamic_cast(sourceIp)).getIpv4Address()); 47 | 48 | struct PacketUdp* packet = 49 | reinterpret_cast(packetBuffer); 50 | 51 | uint16_t timestamp = getTimestamp(); 52 | // Fabricate the IP header or we can use the 53 | // standard header structures but assign our own values. 54 | memset(&packet->ip, 0, sizeof(packet->ip)); 55 | packet->ip.ip_v = 4; 56 | packet->ip.ip_hl = sizeof(packet->ip) >> 2; 57 | packet->ip.ip_dst = 58 | *(reinterpret_cast(&destinationIpDecimal)); 59 | packet->ip.ip_src = *(reinterpret_cast(&sourceIpDecimal)); 60 | packet->ip.ip_p = kUdpProtocol; // UDP protocol 61 | packet->ip.ip_ttl = ttl; 62 | // ipid: 5-bit for encoding intiial TTL, 1 bit for encoding probeType, 10-bit 63 | // for encoding timestamp. 64 | // 0x3FF = 2^10 to extract first 10-bit of timestamp 65 | uint16_t ipid = ((ttl - ttlOffset_) & 0x1F) | ((probePhaseCode_ & 0x1) << 5); 66 | int32_t packetExpectedSize = 128; 67 | 68 | if (encodeTimestamp_) { 69 | ipid = ipid | ((timestamp & 0x3FF) << 6); 70 | // packet-size encode 6-bit timestamp 71 | // (((timestamp >> 10) & 0x3F) << 6): the rest 6-bit of timestamp 72 | packetExpectedSize = packetExpectedSize | (((timestamp >> 10) & 0x3F) << 1); 73 | } 74 | // In OSX, please use: packet->ip.ip_len = packetExpectedSize; 75 | // Otherwise, you will have an Errno-22. 76 | #if defined(__APPLE__) || defined(__MACH__) 77 | packet->ip.ip_len = packetExpectedSize; 78 | packet->ip.ip_id = ipid; 79 | #else 80 | packet->ip.ip_len = htons(packetExpectedSize); 81 | packet->ip.ip_id = htons(ipid); 82 | #endif 83 | 84 | 85 | memset(&packet->udp, '\0', sizeof(packet->udp)); 86 | memcpy(packet->payload, payloadMessage_.c_str(), payloadMessage_.size()); 87 | 88 | #ifdef __FAVOR_BSD 89 | packet->udp.uh_dport = destinationPort_; 90 | packet->udp.uh_sport = getChecksum( 91 | reinterpret_cast(&destinationIpDecimal), checksumOffset_); 92 | packet->udp.uh_ulen = htons(packetExpectedSize - sizeof(packet->ip)); 93 | 94 | // if you set a checksum to zero, your kernel's IP stack should fill in 95 | // the correct checksum during transmission 96 | // packet->udp.uh_sum = 0; 97 | packet->udp.uh_sum = getChecksum( 98 | kUdpProtocol, packetExpectedSize - sizeof(packet->ip), 99 | reinterpret_cast(&sourceIpDecimal), 100 | reinterpret_cast(&destinationIpDecimal), 101 | reinterpret_cast(packetBuffer + sizeof(struct ip))); 102 | #else 103 | packet->udp.dest = destinationPort_; 104 | packet->udp.source = getChecksum( 105 | reinterpret_cast(&destinationIpDecimal), checksumOffset_); 106 | packet->udp.len = htons(packetExpectedSize - sizeof(packet->ip)); 107 | 108 | // if you set a checksum to zero, your kernel's IP stack should fill in 109 | // the correct checksum during transmission 110 | // packet->udp.uh_sum = 0; 111 | packet->udp.check = getChecksum( 112 | kUdpProtocol, packetExpectedSize - sizeof(packet->ip), 113 | reinterpret_cast(&sourceIpDecimal), 114 | reinterpret_cast(&destinationIpDecimal), 115 | reinterpret_cast(packetBuffer + sizeof(struct ip))); 116 | #endif 117 | 118 | return packetExpectedSize; 119 | } 120 | 121 | void UdpProber::setChecksumOffset(int32_t checksumOffset) { 122 | checksumOffset_ = checksumOffset; 123 | } 124 | 125 | void UdpProber::parseResponse(uint8_t* buffer, size_t size, 126 | SocketType socketType) { 127 | if (socketType != SocketType::ICMP || size < 56) return; 128 | struct PacketIcmp* parsedPacket = 129 | reinterpret_cast(buffer); 130 | struct PacketUdp* residualUdpPacket = 131 | reinterpret_cast(buffer + 28); 132 | 133 | uint32_t destination = 0; 134 | uint32_t responder = 0; 135 | int16_t distance = 0; 136 | bool fromDestination = false; 137 | 138 | #ifdef __FAVOR_BSD 139 | if (getChecksum( 140 | reinterpret_cast(&residualUdpPacket->ip.ip_dst.s_addr), 141 | checksumOffset_) != residualUdpPacket->udp.uh_sport) { 142 | // Checksum unmatched. 143 | checksumMismatches += 1; 144 | return; 145 | } 146 | #else 147 | if (getChecksum( 148 | reinterpret_cast(&residualUdpPacket->ip.ip_dst.s_addr), 149 | checksumOffset_) != residualUdpPacket->udp.source) { 150 | // Checksum unmatched. 151 | checksumMismatches_ += 1; 152 | return; 153 | } 154 | #endif 155 | destination = ntohl(residualUdpPacket->ip.ip_dst.s_addr); 156 | responder = ntohl(parsedPacket->ip.ip_src.s_addr); 157 | 158 | #if defined(__APPLE__) || defined(__MACH__) 159 | uint16_t replyIpId = parsedPacket->ip.ip_id; 160 | uint16_t replyIpLen = parsedPacket->ip.ip_len; 161 | uint16_t probeIpLen = residualUdpPacket->ip.ip_len; 162 | uint16_t probeIpId = residualUdpPacket->ip.ip_id; 163 | #else 164 | uint16_t replyIpId = ntohs(parsedPacket->ip.ip_id); 165 | uint16_t replyIpLen = ntohs(parsedPacket->ip.ip_len); 166 | uint16_t probeIpLen = ntohs(residualUdpPacket->ip.ip_len); 167 | uint16_t probeIpId = ntohs(residualUdpPacket->ip.ip_id); 168 | #endif 169 | 170 | uint32_t sentTimestamp = ((probeIpId >> 6) & 0x3FF) | 171 | (((probeIpLen >> 1) & 0x3F) << 10); 172 | uint8_t probePhase = (probeIpId >> 5) & 0x1; 173 | 174 | int64_t receivedTimestamp = getTimestamp(); 175 | uint32_t rtt = static_cast(receivedTimestamp - sentTimestamp + 176 | kTimestampSlot) % 177 | kTimestampSlot; 178 | 179 | int16_t initialTTL = static_cast(probeIpId & 0x1F); 180 | if (initialTTL == 0) initialTTL = 32; 181 | initialTTL += ttlOffset_; 182 | 183 | if (parsedPacket->icmp.icmp_type == 3 && 184 | (parsedPacket->icmp.icmp_code == 3 || parsedPacket->icmp.icmp_code == 2 || 185 | parsedPacket->icmp.icmp_code == 1)) { 186 | // Unreachable from Destination 187 | fromDestination = true; 188 | // Distance = initial distance - remaining distance + 1 189 | distance = initialTTL - residualUdpPacket->ip.ip_ttl + 1; 190 | } else if (parsedPacket->icmp.icmp_type == 3) { 191 | // Other Unreachable 192 | fromDestination = false; 193 | distance = initialTTL - residualUdpPacket->ip.ip_ttl + 1; 194 | return; 195 | } else if (parsedPacket->icmp.icmp_type == 11 && 196 | parsedPacket->icmp.icmp_code == 0) { 197 | // Time Exceeded 198 | fromDestination = false; 199 | distance = initialTTL; 200 | } else { 201 | // Other packets. 202 | otherMismatches_++; 203 | return; 204 | } 205 | 206 | if (distance <= ttlOffset_ || distance > (kMaxTtl + ttlOffset_)) { 207 | distanceAbnormalities_ += 1; 208 | return; 209 | } 210 | 211 | Ipv4Address ipv4Destination(destination); 212 | Ipv4Address ipv4Responder(responder); 213 | 214 | (*callback_)(ipv4Destination, ipv4Responder, static_cast(distance), 215 | rtt, fromDestination, true, buffer, size); 216 | } 217 | 218 | uint16_t UdpProber::getTimestamp() const { 219 | int64_t millisecond = std::chrono::duration_cast( 220 | std::chrono::steady_clock::now().time_since_epoch()) 221 | .count(); 222 | millisecond = millisecond % kTimestampSlot; 223 | return static_cast(millisecond); 224 | } 225 | 226 | uint16_t UdpProber::getChecksum(const uint16_t* ipAddress, 227 | uint16_t offset) const { 228 | uint32_t sum = 0; 229 | sum += ntohs(ipAddress[0]); 230 | sum += ntohs(ipAddress[1]); 231 | 232 | // keep only the last 16 bits of the 32 bit calculated sum and add the 233 | // carries 234 | sum = (sum & 0xFFFF) + (sum >> 16); 235 | 236 | // Take the bitwise complement of sum 237 | sum = ~sum; 238 | return htons(((uint16_t)sum + offset)); 239 | } 240 | 241 | uint16_t UdpProber::getChecksum(const uint8_t protocolValue, 242 | size_t packetLength, 243 | const uint16_t* sourceIpAddress, 244 | const uint16_t* destinationIpAddress, 245 | uint16_t* buff) const { 246 | /* Check if the tcp length is even or odd. Add padding if odd. */ 247 | if ((packetLength % 2) == 1) { 248 | // Empty space in the ip buffer should be 0 anyway. 249 | buff[packetLength] = 0; 250 | packetLength += 1; // incrase length to make even. 251 | } 252 | 253 | uint32_t sum = 0; 254 | /* add the pseudo header */ 255 | sum += ntohs(sourceIpAddress[0]); 256 | sum += ntohs(sourceIpAddress[1]); 257 | sum += ntohs(destinationIpAddress[0]); 258 | sum += ntohs(destinationIpAddress[1]); 259 | sum += packetLength; // already in host format. 260 | sum += protocolValue; // already in host format. 261 | 262 | /* 263 | * calculate the checksum for the tcp header and payload 264 | * len_tcp represents number of 8-bit bytes, 265 | * we are working with 16-bit words so divide len_tcp by 2. 266 | */ 267 | for (uint32_t i = 0; i < (packetLength / 2); i++) { 268 | sum += ntohs(buff[i]); 269 | } 270 | 271 | // keep only the last 16 bits of the 32 bit calculated sum and add the 272 | // carries 273 | sum = (sum & 0xFFFF) + (sum >> 16); 274 | // sum += (sum >> 16); 275 | 276 | // Take the bitwise complement of sum 277 | sum = ~sum; 278 | return htons(((uint16_t)sum)); 279 | } 280 | 281 | // Get metrics information 282 | 283 | uint64_t UdpProber::getChecksumMismatches() { 284 | return checksumMismatches_; 285 | } 286 | 287 | uint64_t UdpProber::getDistanceAbnormalities() { 288 | return distanceAbnormalities_; 289 | } 290 | 291 | uint64_t UdpProber::getOtherMismatches() { 292 | return otherMismatches_; 293 | } 294 | 295 | } // namespace flashroute 296 | -------------------------------------------------------------------------------- /flashroute/udp_prober.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | #include "flashroute/address.h" 8 | #include "flashroute/prober.h" 9 | 10 | namespace flashroute { 11 | 12 | // 2^16 wrap-around interval for timestamp of UDP probe. 13 | const uint32_t kTimestampSlot = 65536; 14 | 15 | /** 16 | * UDP Prober handles packet construction and response parsing. 17 | * 18 | * Example: 19 | * 20 | * // Callback function to parse the data. 21 | * PacketReceiverCallback callback = 22 | * [](const IpAddress& destination, const IpAddress& responder, 23 | * uint8_t distance, uint32_t rtt, bool fromDestination, 24 | * bool ipv4, void* packetHeader, size_t headerLen) { 25 | * // Handle response. 26 | * }; 27 | * 28 | * UdpProber prober( 29 | * callback, // Callback function to handle responses. 30 | * 0, // Checksum offset to support discovery-optimized mode. 31 | * 1, // 0 stands for preprobing, 1 stands for main probing. 32 | * 53, // Destination port number. 33 | * "message payload", //payload message. 34 | * false // Not encode timestamp into probe so scan is idempotent. 35 | * ); 36 | * 37 | * // Pass prober instance to network manager, so users can call 38 | * scheduleProbeRemoteHost to issue probe or process responses in callback func. 39 | * NetworkManager networkManager( 40 | * &prober, // The prober to process packets. 41 | * "eth0", // The interface to send the probe. 42 | * 100000, // The packet sending rate. 43 | * true // Tell network manager to use ipv4 or ipv6 sockets. 44 | * ); 45 | * 46 | */ 47 | class UdpProber : public virtual Prober { 48 | public: 49 | UdpProber(PacketReceiverCallback* callback, const int32_t checksumOffset, 50 | const uint8_t probePhaseCode, const uint16_t destinationPort, 51 | const std::string& payloadMessage, const bool encodeTimestamp, 52 | const uint8_t ttlOffset); 53 | 54 | // Construct probe. 55 | size_t packProbe(const IpAddress& destinationIp, const IpAddress& sourceIp, 56 | const uint8_t ttl, uint8_t* packetBuffer) override; 57 | 58 | // Parse responses. 59 | void parseResponse(uint8_t* buffer, size_t size, 60 | SocketType socketType) override; 61 | 62 | // Change checksum offset (support discovery-optimized mode.) 63 | void setChecksumOffset(int32_t checksumOffset); 64 | 65 | // Calculate checksum of ip address. 66 | uint16_t getChecksum(const uint16_t* ipaddress, uint16_t offset) const; 67 | 68 | // Calculate checksum of packet. 69 | uint16_t getChecksum(const uint8_t protocolValue, size_t packetLength, 70 | const uint16_t* src_addr, const uint16_t* dest_addr, 71 | uint16_t* buff) const; 72 | 73 | // Put here for testing purpose. 74 | uint16_t getTimestamp() const; 75 | 76 | // Get metrics information 77 | uint64_t getChecksumMismatches() override; 78 | uint64_t getDistanceAbnormalities() override; 79 | uint64_t getOtherMismatches() override; 80 | 81 | private: 82 | PacketReceiverCallback* callback_; 83 | int32_t checksumOffset_; 84 | uint16_t destinationPort_; 85 | uint8_t probePhaseCode_; 86 | uint8_t ttlOffset_; 87 | std::string payloadMessage_; 88 | bool encodeTimestamp_; 89 | 90 | // Metrics 91 | uint64_t checksumMismatches_; 92 | uint64_t distanceAbnormalities_; 93 | uint64_t otherMismatches_; 94 | }; 95 | 96 | } // namespace flashroute 97 | -------------------------------------------------------------------------------- /flashroute/udp_prober_test.cc: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #include "gtest/gtest.h" 3 | 4 | #include "flashroute/prober.h" 5 | #include "flashroute/udp_prober.h" 6 | 7 | using namespace flashroute; 8 | 9 | const uint16_t kTestBufferSize = 512; 10 | 11 | TEST(UdpProber, PackProbeTest) { 12 | Ipv4Address destinationIp{12456}; 13 | Ipv4Address sourceIp{6789}; 14 | uint8_t initialTtl = 17; 15 | PacketReceiverCallback response_handler = 16 | [](const IpAddress& destination, const IpAddress& responder, 17 | uint8_t distance, uint32_t rtt, bool fromDestination, bool ipv4, 18 | void* packetHeader, size_t headerLen) {}; 19 | 20 | UdpProber prober(&response_handler, 0, 1, 0, "test", true, 0); 21 | 22 | uint8_t buffer[kTestBufferSize]; 23 | size_t size = prober.packProbe(destinationIp, sourceIp, initialTtl, buffer); 24 | prober.parseResponse(buffer, size, SocketType::ICMP); 25 | 26 | #if defined(__APPLE__) || defined(__MACH__) 27 | uint16_t packetIPID = *(reinterpret_cast(buffer+4)); 28 | #else 29 | uint16_t packetIPID = ntohs(*(reinterpret_cast(buffer+4))); 30 | #endif 31 | uint8_t packetTtl = *(reinterpret_cast(buffer+8)); 32 | uint32_t packetSourceIp = *(reinterpret_cast(buffer+12)); 33 | uint32_t packetDestinationIp = *(reinterpret_cast(buffer+16)); 34 | uint8_t probePhase = (packetIPID >> 5) & 1; 35 | 36 | EXPECT_EQ((packetIPID & 0x1F), 17); 37 | EXPECT_EQ(packetTtl, 17); 38 | EXPECT_EQ(packetSourceIp, htonl(sourceIp.getIpv4Address())); 39 | EXPECT_EQ(packetDestinationIp, htonl(destinationIp.getIpv4Address())); 40 | EXPECT_EQ(probePhase, 1); 41 | } 42 | -------------------------------------------------------------------------------- /flashroute/udp_prober_v6.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #pragma once 3 | 4 | #include // icmp header 5 | #include // struct ip6_hdr 6 | #include 7 | #include 8 | 9 | #include "flashroute/address.h" 10 | #include "flashroute/prober.h" 11 | 12 | namespace flashroute { 13 | 14 | struct FlashRouteHeader { 15 | uint8_t initialTtl; 16 | uint8_t probeStatus; 17 | uint16_t destinationChecksum; 18 | uint32_t timestamp; 19 | }; 20 | 21 | 22 | struct PacketUdpIpv6 { 23 | struct ip6_hdr ip; 24 | struct udphdr udp; 25 | union { 26 | uint8_t payload[kPacketMessageDefaultPayloadSize]; 27 | struct FlashRouteHeader flashrouteHeader; 28 | }; 29 | } __attribute__((packed)); 30 | 31 | struct PacketIcmpIpv6 { 32 | struct ip6_hdr ip; 33 | struct icmp6_hdr icmp; 34 | char payload[kPacketMessageDefaultPayloadSize]; 35 | } __attribute__((packed)); 36 | 37 | /** 38 | * UDP Prober for IPv6 handles packet construction and response parsing. 39 | * 40 | * Example: 41 | * 42 | * // Callback function to parse the data. 43 | * PacketReceiverCallback callback = 44 | * [](const IpAddress& destination, const IpAddress& responder, 45 | * uint8_t distance, uint32_t rtt, bool fromDestination, 46 | * bool ipv4, void* packetHeader, size_t headerLen) { 47 | * // Handle response. 48 | * }; 49 | * 50 | * UdpProber prober( 51 | * callback, // Callback function to handle responses. 52 | * 0, // Checksum offset to support discovery-optimized mode. 53 | * 1, // 0 stands for preprobing, 1 stands for main probing. 54 | * 53, // Destination port number. 55 | * "message payload", //payload message. 56 | * false // Not encode timestamp into probe so scan is idempotent. 57 | * ); 58 | * 59 | * // Pass prober instance to network manager, so users can call 60 | * scheduleProbeRemoteHost to issue probe or process responses in callback func. 61 | * NetworkManager networkManager( 62 | * &prober, // The prober to process packets. 63 | * "eth0", // The interface to send the probe. 64 | * 100000, // The packet sending rate. 65 | * true // Tell network manager to use ipv4 or ipv6 sockets. 66 | * ); 67 | * 68 | */ 69 | class UdpProberIpv6 : public virtual Prober { 70 | public: 71 | UdpProberIpv6(PacketReceiverCallback* callback, const int32_t checksumOffset, 72 | const uint8_t probePhaseCode, const uint16_t destinationPort, 73 | const std::string& payloadMessage, const uint8_t ttlOffset); 74 | 75 | // Construct probe. 76 | size_t packProbe(const IpAddress& destinationIp, const IpAddress& sourceIp, 77 | const uint8_t ttl, uint8_t* packetBuffer) override; 78 | 79 | // Parse responses. 80 | void parseResponse(uint8_t* buffer, size_t size, 81 | SocketType socketType) override; 82 | 83 | // Change checksum offset (support discovery-optimized mode.) 84 | void setChecksumOffset(int32_t checksumOffset); 85 | 86 | 87 | // Put here for testing purpose. 88 | uint16_t getTimestamp() const; 89 | 90 | // Get metrics information 91 | uint64_t getChecksumMismatches() override; 92 | uint64_t getDistanceAbnormalities() override; 93 | uint64_t getOtherMismatches() override; 94 | 95 | private: 96 | PacketReceiverCallback* callback_; 97 | int32_t checksumOffset_; 98 | uint8_t probePhaseCode_; 99 | uint8_t ttlOffset_; 100 | uint16_t destinationPort_; 101 | std::string payloadMessage_; 102 | bool encodeTimestamp_; 103 | 104 | // Metrics 105 | uint64_t checksumMismatches_; 106 | uint64_t distanceAbnormalities_; 107 | uint64_t otherMismatches_; 108 | 109 | // Calculate checksum of ip address. 110 | uint16_t getChecksum(const uint16_t* ipaddress, 111 | uint16_t offset) const; 112 | 113 | // Calculate checksum of packet. 114 | uint16_t getChecksum(const uint8_t protocolValue, size_t packetLength, 115 | const uint16_t* sourceIpAddress, 116 | const uint16_t* destinationIpAddress, 117 | uint16_t* buff) const; 118 | }; 119 | 120 | } // namespace flashroute 121 | -------------------------------------------------------------------------------- /flashroute/utils.cc: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #include "flashroute/utils.h" 3 | 4 | #include "glog/logging.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include "absl/strings/str_cat.h" 15 | #include "absl/strings/str_split.h" 16 | #include "absl/strings/string_view.h" 17 | 18 | #include "flashroute/address.h" 19 | namespace flashroute { 20 | 21 | const uint32_t kThreadPoolSize = 1; 22 | 23 | using namespace boost::process; 24 | 25 | CommandExecutor::CommandExecutor() {} 26 | 27 | void CommandExecutor::run(const std::string& command) { 28 | child_process_ = std::make_unique(command); 29 | LOG(INFO) << "Child process is running."; 30 | } 31 | 32 | void CommandExecutor::stop() { 33 | if (child_process_.get() != nullptr) { 34 | child_process_->terminate(); 35 | } 36 | LOG(INFO) << "Child process teminated."; 37 | } 38 | 39 | IpNetwork* parseNetworkFromStringToNetworkAddress( 40 | absl::string_view stringNetwork) { 41 | std::vector parts = absl::StrSplit(stringNetwork, "/"); 42 | IpAddress* baseAddr = parseIpFromStringToIpAddress(std::string(parts[0])); 43 | uint32_t subnetPrefixLength = 0; 44 | if (parts.size() == 2) { 45 | if (!absl::SimpleAtoi(parts[1], &subnetPrefixLength)) { 46 | return NULL; 47 | } 48 | } else if (parts.size() == 1) { 49 | if (baseAddr->isIpv4()) 50 | subnetPrefixLength = 32; 51 | else 52 | subnetPrefixLength = 128; 53 | } else { 54 | return NULL; 55 | } 56 | 57 | IpNetwork* ret = new IpNetwork(*baseAddr, subnetPrefixLength); 58 | free(baseAddr); 59 | return ret; 60 | } 61 | 62 | uint32_t parseIpFromStringToInt(const std::string& stringIp) { 63 | return ntohl(inet_addr(stringIp.c_str())); 64 | } 65 | 66 | IpAddress* parseIpFromStringToIpAddress(const std::string& stringIp) { 67 | if (absl::StrContains(absl::string_view(stringIp), ":")) { 68 | // IPv6 69 | struct in6_addr result; 70 | if (inet_pton(AF_INET6, stringIp.c_str(), &result) == 1) { 71 | // successfully parsed string into "result" 72 | absl::uint128 addr_ = 0; 73 | memcpy(&addr_, &result, sizeof(result)); 74 | return new Ipv6Address(addr_); 75 | } else { 76 | VLOG(2) << "Failed to parse: " << stringIp; 77 | return NULL; 78 | } 79 | 80 | } else { 81 | // IPv4 82 | return new Ipv4Address(ntohl(inet_addr(stringIp.c_str()))); 83 | } 84 | } 85 | 86 | std::string parseIpv4FromIntToString(const uint32_t ip) { 87 | uint32_t section[4]; 88 | section[0] = ip & 0xFF; 89 | section[1] = (ip >> 8) & 0xFF; 90 | section[2] = (ip >> 16) & 0xFF; 91 | section[3] = (ip >> 24) & 0xFF; 92 | std::string result = ""; 93 | absl::StrAppend(&result, section[3], ".", section[2], ".", section[1], ".", 94 | section[0]); 95 | return result; 96 | } 97 | 98 | std::string parseIpFromIpAddressToString(const IpAddress& ip) { 99 | if (ip.isIpv4()) { 100 | return parseIpv4FromIntToString(ip.getIpv4Address()); 101 | } else { 102 | char interfaceTmp[256]; 103 | absl::uint128 tempAddr = ip.getIpv6Address(); 104 | inet_ntop(AF_INET6, &tempAddr, interfaceTmp, 105 | sizeof(interfaceTmp)); 106 | std::string ip = interfaceTmp; 107 | return ip; 108 | } 109 | } 110 | 111 | std::string getAddressByInterface(const std::string& interface, bool ipv4) { 112 | struct ifaddrs *addrs, *iap; 113 | char interfaceTmp[256]; 114 | std::string ip; 115 | getifaddrs(&addrs); 116 | for (iap = addrs; iap != NULL; iap = iap->ifa_next) { 117 | if (iap->ifa_addr && (iap->ifa_flags & IFF_UP)) { 118 | if (ipv4 && iap->ifa_addr->sa_family == AF_INET) { 119 | struct sockaddr_in* sa = (struct sockaddr_in*)(iap->ifa_addr); 120 | inet_ntop(iap->ifa_addr->sa_family, (void*)&(sa->sin_addr), 121 | interfaceTmp, sizeof(interfaceTmp)); 122 | std::string tmp = iap->ifa_name; 123 | if (!tmp.compare(interface)) { 124 | ip = interfaceTmp; 125 | VLOG(2) << "Interface: " << interface << " IPv4 address: " << ip; 126 | break; 127 | } 128 | } else if (!ipv4 && iap->ifa_addr->sa_family == AF_INET6){ 129 | struct sockaddr_in6* in6 = (struct sockaddr_in6*)iap->ifa_addr; 130 | inet_ntop(AF_INET6, &in6->sin6_addr, interfaceTmp, 131 | sizeof(interfaceTmp)); 132 | std::string tmp = iap->ifa_name; 133 | if (!tmp.compare(interface)) { 134 | ip = interfaceTmp; 135 | VLOG(2) << "Interface: " << interface << " IPv6 address: " << ip; 136 | break; 137 | } 138 | } 139 | } 140 | } 141 | freeifaddrs(addrs); 142 | return ip; 143 | } 144 | 145 | IpAddress* getFirstAddressOfBlock(const IpAddress& address, 146 | const int32_t prefixLength) { 147 | if (address.isIpv4()) { 148 | if (prefixLength > 32 || prefixLength < 0) { 149 | LOG(FATAL) << "network prefix length is incorrect!!!"; 150 | } 151 | int64_t result = address.getIpv4Address(); 152 | for (int32_t i = 0; i < 32 - prefixLength; i++) { 153 | result = result & (~static_cast(1UL << i)); 154 | } 155 | return new Ipv4Address(static_cast(result)); 156 | } else { 157 | if (prefixLength > 128 || prefixLength < 0) { 158 | LOG(FATAL) << "network prefix length is incorrect!!!"; 159 | } 160 | absl::uint128 result = ntohll(address.getIpv6Address()); 161 | for (int32_t i = 0; i < 128 - prefixLength; i++) { 162 | result = result & (~(static_cast(1) << i)); 163 | } 164 | return new Ipv6Address(htonll(result)); 165 | } 166 | } 167 | 168 | IpAddress* getLastAddressOfBlock(const IpAddress& address, 169 | const int32_t prefixLength) { 170 | if (address.isIpv4()) { 171 | if (prefixLength > 32 || prefixLength < 0) { 172 | LOG(FATAL) << "network prefix length is incorrect!!!"; 173 | } 174 | int64_t result = address.getIpv4Address(); 175 | for (int32_t i = 0; i < 32 - prefixLength; i++) { 176 | result = result | (1UL << i); 177 | } 178 | return new Ipv4Address(static_cast(result)); 179 | } else { 180 | if (prefixLength > 128 || prefixLength < 0) { 181 | LOG(FATAL) << "network prefix length is incorrect!!!"; 182 | } 183 | absl::uint128 result = ntohll(address.getIpv6Address()); 184 | for (int32_t i = 0; i < 128 - prefixLength; i++) { 185 | result = result | (static_cast(1) << i); 186 | } 187 | return new Ipv6Address(htonll(result)); 188 | } 189 | } 190 | 191 | absl::uint128 htonll(absl::uint128 in) { 192 | absl::uint128 result; 193 | uint8_t* srcPtr = reinterpret_cast(&in); 194 | uint8_t* dstPtr = reinterpret_cast(&result); 195 | for (uint32_t i = 0; i < sizeof(absl::uint128); i++) { 196 | dstPtr[sizeof(absl::uint128) - i - 1] = srcPtr[i]; 197 | } 198 | return result; 199 | } 200 | 201 | absl::uint128 ntohll(absl::uint128 in) { 202 | absl::uint128 result; 203 | uint8_t* srcPtr = reinterpret_cast(&in); 204 | uint8_t* dstPtr = reinterpret_cast(&result); 205 | for (uint32_t i = 0; i < sizeof(absl::uint128); i++) { 206 | dstPtr[sizeof(absl::uint128) - i - 1] = srcPtr[i]; 207 | } 208 | return result; 209 | } 210 | 211 | bool isNetwork(const std::string& input) { 212 | std::vector parts = absl::StrSplit(input, "/"); 213 | if (parts.size() == 2) { 214 | return true; 215 | } else { 216 | return false; 217 | } 218 | } 219 | 220 | bool isValidDestiantion(const std::string& input) { 221 | std::vector parts = absl::StrSplit(input, "."); 222 | if (parts.size() != 4) { 223 | return false; 224 | } else { 225 | return true; 226 | } 227 | } 228 | 229 | std::string getDefaultInterface() { 230 | struct ifaddrs *addrs, *iap; 231 | struct sockaddr_in *sa; 232 | char interfaceTmp[256]; 233 | getifaddrs(&addrs); 234 | std::string tmp; 235 | for (iap = addrs; iap != NULL; iap = iap->ifa_next) { 236 | if (iap->ifa_addr && (iap->ifa_flags & IFF_UP) && 237 | iap->ifa_addr->sa_family == AF_INET) { 238 | sa = (struct sockaddr_in *)(iap->ifa_addr); 239 | inet_ntop(iap->ifa_addr->sa_family, (void *)&(sa->sin_addr), interfaceTmp, 240 | sizeof(interfaceTmp)); 241 | tmp = iap->ifa_name; 242 | } 243 | } 244 | freeifaddrs(addrs); 245 | return tmp; 246 | } 247 | 248 | } // namespace flashroute 249 | -------------------------------------------------------------------------------- /flashroute/utils.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include "absl/strings/string_view.h" 10 | 11 | #include "flashroute/address.h" 12 | 13 | namespace flashroute { 14 | 15 | class CommandExecutor { 16 | public: 17 | CommandExecutor(); 18 | void run(const std::string& command); 19 | void stop(); 20 | 21 | private: 22 | std::unique_ptr child_process_; 23 | }; 24 | 25 | // Translate string network to IpNetowrk. (Currently only support Ipv4) 26 | IpNetwork* parseNetworkFromStringToNetworkAddress( 27 | absl::string_view stringNetwork); 28 | 29 | // Translate string IP to integer IP. 30 | uint32_t parseIpFromStringToInt(const std::string& stringIp); 31 | 32 | // Translate string IP to IpAddress. (Currently only support Ipv4) 33 | IpAddress* parseIpFromStringToIpAddress(const std::string& stringIp); 34 | 35 | // Convert decimal IP to string. 36 | std::string parseIpv4FromIntToString(const uint32_t ip); 37 | 38 | // Convert decimal IP to string. 39 | std::string parseIpFromIpAddressToString(const IpAddress& ip); 40 | 41 | // Get IP address by interface name. Return empty string, if interface does not 42 | // exist. 43 | std::string getAddressByInterface(const std::string& interface, bool ipv4); 44 | 45 | // Get first address of a IP block. 46 | IpAddress* getFirstAddressOfBlock(const IpAddress& address, 47 | const int32_t prefixLength); 48 | 49 | // Get last address of a IP block. 50 | IpAddress* getLastAddressOfBlock(const IpAddress& address, 51 | const int32_t prefixLength); 52 | 53 | // Similar to htonl but designed for absl::uint128 ipv6 address. 54 | absl::uint128 htonll(absl::uint128 in); 55 | 56 | // Similar to ntohl but designed for absl::uint128 ipv6 address. 57 | absl::uint128 ntohll(absl::uint128 in); 58 | 59 | bool isNetwork(const std::string& input); 60 | 61 | bool isValidDestiantion(const std::string& input); 62 | 63 | std::string getDefaultInterface(); 64 | 65 | } // namespace flashroute 66 | -------------------------------------------------------------------------------- /flashroute/utils_test.cc: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2019 Neo Huang - All Rights Reserved */ 2 | #include "gtest/gtest.h" 3 | 4 | #include 5 | 6 | #include "flashroute/utils.h" 7 | #include "flashroute/address.h" 8 | 9 | using namespace flashroute; 10 | 11 | TEST(getFirstAddressOfBlock, RegularNumberTeset) { 12 | // 192.168.1.223 -> 192.168.1.0 13 | EXPECT_EQ(std::unique_ptr( 14 | getFirstAddressOfBlock(Ipv4Address{3232235999}, 24)) 15 | ->getIpv4Address(), 16 | 3232235776); 17 | 18 | EXPECT_EQ(std::unique_ptr( 19 | getFirstAddressOfBlock(Ipv4Address{3232235993}, 24)) 20 | ->getIpv4Address(), 21 | 3232235776); 22 | 23 | EXPECT_EQ(std::unique_ptr( 24 | getFirstAddressOfBlock(Ipv4Address{3232235993}, 16)) 25 | ->getIpv4Address(), 26 | 3232235520); 27 | 28 | EXPECT_EQ(std::unique_ptr( 29 | getFirstAddressOfBlock(Ipv4Address{3232235993}, 8)) 30 | ->getIpv4Address(), 31 | 3221225472); 32 | 33 | EXPECT_EQ(std::unique_ptr( 34 | getFirstAddressOfBlock(Ipv4Address{3232235993}, 0)) 35 | ->getIpv4Address(), 36 | 0); 37 | } 38 | 39 | TEST(getLastAddressOfBlock, RegularNumberTeset) { 40 | 41 | EXPECT_EQ(std::unique_ptr( 42 | getLastAddressOfBlock(Ipv4Address{3232235999}, 24)) 43 | ->getIpv4Address(), 44 | 3232236031); 45 | 46 | EXPECT_EQ(std::unique_ptr( 47 | getLastAddressOfBlock(Ipv4Address{3232235788}, 24)) 48 | ->getIpv4Address(), 49 | 3232236031); 50 | 51 | EXPECT_EQ(std::unique_ptr( 52 | getLastAddressOfBlock(Ipv4Address{3232235993}, 16)) 53 | ->getIpv4Address(), 54 | 3232301055); 55 | 56 | EXPECT_EQ(std::unique_ptr( 57 | getLastAddressOfBlock(Ipv4Address{3232235993}, 8)) 58 | ->getIpv4Address(), 59 | 3238002687); 60 | 61 | EXPECT_EQ(std::unique_ptr( 62 | getLastAddressOfBlock(Ipv4Address{3232235993}, 0)) 63 | ->getIpv4Address(), 64 | 4294967295); 65 | } 66 | 67 | TEST(parseIpFromStringToInt, convertStringToDecimal) { 68 | EXPECT_EQ(parseIpFromStringToInt("192.168.1.255"), 3232236031); 69 | EXPECT_EQ(parseIpFromStringToInt("255.255.255.255"), 4294967295); 70 | } -------------------------------------------------------------------------------- /lint-check.ssh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | EXIT_CODE=5 3 | 4 | cppcheck --language=c++ --error-exitcode=$EXIT_CODE --enable=warning,performance,portability,style flashroute/*.cc 5 | if [ “$?” -eq “$EXIT_CODE” ]; then 6 | echo “== STATUS: static analysis error.” 7 | fi -------------------------------------------------------------------------------- /parsers/BUILD: -------------------------------------------------------------------------------- 1 | load("@parsers_deps//:requirements.bzl", "requirement") 2 | 3 | py_library( 4 | name = "output_parser", 5 | srcs = ["output_parser.py"], 6 | ) 7 | 8 | 9 | py_binary( 10 | name = "example", 11 | srcs = ["example.py"], 12 | python_version = "PY3", 13 | deps = [ 14 | requirement("glog"), 15 | ":output_parser" 16 | ], 17 | ) 18 | 19 | py_binary( 20 | name = "jupyter", 21 | srcs = ["jupyter.py"], 22 | python_version = "PY3", 23 | deps = [ 24 | requirement("notebook"), 25 | requirement("glog"), 26 | requirement("pandas"), 27 | requirement("matplotlib"), 28 | ":output_parser" 29 | ], 30 | ) 31 | -------------------------------------------------------------------------------- /parsers/example.py: -------------------------------------------------------------------------------- 1 | from output_parser import FlashRouteParser 2 | import glog 3 | import argparse 4 | import glog 5 | 6 | if __name__ == "__main__": 7 | argument_parser = argparse.ArgumentParser( 8 | description='Parse output of FlashRoute.') 9 | argument_parser.add_argument("-f", type=str, required=True, 10 | help='Parse output of FlashRoute.') 11 | args = argument_parser.parse_args() 12 | flashroute_parser = FlashRouteParser(args.f) 13 | glog.info(f"Start to read data from {args.f}") 14 | i = 0 15 | while(True): 16 | result = flashroute_parser.next() 17 | i += 1 18 | if result is None: 19 | break 20 | 21 | glog.info(f"Finished. Read {i} records.") 22 | 23 | -------------------------------------------------------------------------------- /parsers/example_jupyter.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "id": "8115d012", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "from output_parser import FlashRouteParser\n", 11 | "import glog\n", 12 | "import pandas as pd" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": null, 18 | "id": "fef99ba2", 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "def load_records_to_dataframe(filepath):\n", 23 | " flashroute_parser = FlashRouteParser(filepath)\n", 24 | " interface_set = list()\n", 25 | " i = 0\n", 26 | " while(True):\n", 27 | " result = flashroute_parser.next()\n", 28 | " if result is None:\n", 29 | " break\n", 30 | " interface_set.append([result.resp_ip, result.dest_ip , result.distance, result.from_dest, result.ipv4_addr])\n", 31 | " i += 1\n", 32 | " \n", 33 | "\n", 34 | " glog.info(f'Load {i} records. Now transform the data to dataframe')\n", 35 | " interface_set_df = pd.DataFrame(interface_set, columns=['Interface', 'Destination', 'HopFromSource', 'FromDestination', 'IPv4Addr'])\n", 36 | " glog.info('Finished.')\n", 37 | " return interface_set_df" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": null, 43 | "id": "e20c4901", 44 | "metadata": {}, 45 | "outputs": [], 46 | "source": [ 47 | "# You need to replace example to the path to your output\n", 48 | "interface_df = load_records_to_dataframe('example_output')" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": null, 54 | "id": "8f17ff17", 55 | "metadata": {}, 56 | "outputs": [], 57 | "source": [ 58 | "# Select Unique Interface. \n", 59 | "# If an interface appears at different hop distance, we select the one closest to the vantage point \n", 60 | "unique_interface = interface_df.groupby(['Interface']).agg(\n", 61 | " Hop=pd.NamedAgg(column='HopFromSource', aggfunc='min'))" 62 | ] 63 | }, 64 | { 65 | "cell_type": "code", 66 | "execution_count": null, 67 | "id": "7b94f10a", 68 | "metadata": {}, 69 | "outputs": [], 70 | "source": [ 71 | "# Draw Histogram Graph\n", 72 | "unique_interface['Hop'].hist( figsize=(16, 5), bins=32)" 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": null, 78 | "id": "89afb70c", 79 | "metadata": {}, 80 | "outputs": [], 81 | "source": [] 82 | } 83 | ], 84 | "metadata": { 85 | "kernelspec": { 86 | "display_name": "Python 3", 87 | "language": "python", 88 | "name": "python3" 89 | }, 90 | "language_info": { 91 | "codemirror_mode": { 92 | "name": "ipython", 93 | "version": 3 94 | }, 95 | "file_extension": ".py", 96 | "mimetype": "text/x-python", 97 | "name": "python", 98 | "nbconvert_exporter": "python", 99 | "pygments_lexer": "ipython3", 100 | "version": "3.6.9" 101 | } 102 | }, 103 | "nbformat": 4, 104 | "nbformat_minor": 5 105 | } 106 | -------------------------------------------------------------------------------- /parsers/jupyter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import re 3 | import sys 4 | 5 | from notebook.notebookapp import main 6 | 7 | if __name__ == '__main__': 8 | sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) 9 | sys.exit(main()) -------------------------------------------------------------------------------- /parsers/output_parser.py: -------------------------------------------------------------------------------- 1 | from struct import unpack 2 | import ipaddress 3 | 4 | class Result: 5 | def __init__(self, dest_ip: int, resp_ip: int, rtt: int, distance: int, 6 | from_dest: bool, ipv4_addr: bool): 7 | self.dest_ip = dest_ip 8 | self.resp_ip = resp_ip 9 | self.rtt = rtt 10 | self.distance = distance 11 | self.from_dest = from_dest 12 | self.ipv4_addr = ipv4_addr 13 | def __repr__(self): 14 | return f"Destination: {ipaddress.ip_address(self.dest_ip)}\n" +\ 15 | f"Responder: {ipaddress.ip_address(self.resp_ip)}\n" +\ 16 | f"distance: {self.distance}\n" +\ 17 | f"rtt: {self.rtt}\n" +\ 18 | f"from_dest: {self.from_dest}\n" +\ 19 | f"ipv4: {self.ipv4_addr}\n" 20 | 21 | 22 | class FlashRouteParser: 23 | def __init__(self, filepath: str): 24 | self.file = open(filepath, mode='rb') 25 | 26 | def next(self) -> Result: 27 | file_content = self.file.read(39) 28 | if (len(file_content) < 39): 29 | return None 30 | [dest_ip, _, _, _, resp_ip, _, _, _, rtt, 31 | distance, from_dest, ipv4_addr] = unpack("IIIIIIIIIB??", file_content) 32 | return Result(dest_ip, resp_ip, rtt, distance, from_dest, ipv4_addr) 33 | 34 | 35 | if __name__ == "__main__": 36 | argument_parser = argparse.ArgumentParser( 37 | description='Parse output of FlashRoute.') 38 | argument_parser.add_argument("-f", type=str, required=True, 39 | help='Parse output of FlashRoute.') 40 | args = argument_parser.parse_args() 41 | flashroute_parser = FlashRouteParser(args.f) 42 | while(True): 43 | result = flashroute_parser.next() 44 | if result is None: 45 | break 46 | print(result) 47 | import pdb 48 | pdb.set_trace() 49 | 50 | 51 | -------------------------------------------------------------------------------- /parsers/requirements.txt: -------------------------------------------------------------------------------- 1 | glog 2 | notebook 3 | pandas 4 | matplotlib -------------------------------------------------------------------------------- /parsers/utils/BUILD: -------------------------------------------------------------------------------- 1 | cc_library( 2 | name = "utils", 3 | srcs = ["utils.cc"], 4 | hdrs= ["utils.h"], 5 | deps = [ 6 | "@boost//:filesystem", 7 | "//external:glog", 8 | "//flashroute:address", 9 | ], 10 | ) 11 | 12 | cc_binary( 13 | name = "unique_interface_counter", 14 | srcs = ["unique_interface_counter.cc"], 15 | deps = [ 16 | "//external:glog", 17 | "//external:gflags", 18 | "@com_google_absl//absl/flags:flag", 19 | "@com_google_absl//absl/flags:parse", 20 | "//flashroute:dump_result", 21 | "//flashroute:address", 22 | ":utils", 23 | ], 24 | ) 25 | 26 | cc_binary( 27 | name = "dataset_comparison", 28 | srcs = ["dataset_comparison.cc"], 29 | deps = [ 30 | "//external:glog", 31 | "//external:gflags", 32 | "@com_google_absl//absl/flags:flag", 33 | "@com_google_absl//absl/flags:parse", 34 | "//flashroute:dump_result", 35 | "//flashroute:address", 36 | ":utils", 37 | ], 38 | ) 39 | 40 | cc_binary( 41 | name = "frequency_analysis", 42 | srcs = ["frequency_analysis.cc"], 43 | deps = [ 44 | "//external:glog", 45 | "//external:gflags", 46 | "@com_google_absl//absl/flags:flag", 47 | "@com_google_absl//absl/flags:parse", 48 | "//flashroute:dump_result", 49 | "//flashroute:address", 50 | ":utils", 51 | ], 52 | ) 53 | 54 | cc_binary( 55 | name = "route_similarity", 56 | srcs = ["route_similarity_analysis.cc"], 57 | deps = [ 58 | "//external:glog", 59 | "//external:gflags", 60 | "@com_google_absl//absl/flags:flag", 61 | "@com_google_absl//absl/flags:parse", 62 | "//flashroute:dump_result", 63 | "//flashroute:address", 64 | ":utils", 65 | "//flashroute:utils", 66 | ], 67 | ) 68 | 69 | 70 | cc_binary( 71 | name = "route_generator", 72 | srcs = ["route_generator.cc"], 73 | deps = [ 74 | "//external:glog", 75 | "//external:gflags", 76 | "@com_google_absl//absl/flags:flag", 77 | "@com_google_absl//absl/flags:parse", 78 | "//flashroute:dump_result", 79 | "//flashroute:address", 80 | ":utils", 81 | "//flashroute:utils", 82 | ], 83 | ) 84 | 85 | cc_binary( 86 | name = "hot_branch_analyzer", 87 | srcs = ["hot_branch_analyzer.cc"], 88 | deps = [ 89 | "//external:glog", 90 | "//external:gflags", 91 | "@com_google_absl//absl/flags:flag", 92 | "@com_google_absl//absl/flags:parse", 93 | "//flashroute:dump_result", 94 | "//flashroute:address", 95 | ":utils", 96 | ], 97 | ) 98 | 99 | 100 | cc_binary( 101 | name = "reprobe_list_generator", 102 | srcs = ["reprobe_list_generator.cc"], 103 | deps = [ 104 | "//external:glog", 105 | "//external:gflags", 106 | "@com_google_absl//absl/flags:flag", 107 | "@com_google_absl//absl/flags:parse", 108 | "//flashroute:dump_result", 109 | "//flashroute:address", 110 | ":utils", 111 | ], 112 | ) 113 | -------------------------------------------------------------------------------- /parsers/utils/dataset_comparison.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "glog/logging.h" 6 | #include "absl/flags/usage.h" 7 | #include "absl/flags/flag.h" 8 | #include "absl/flags/parse.h" 9 | #include "absl/strings/str_cat.h" 10 | #include "absl/numeric/int128.h" 11 | 12 | #include "flashroute/address.h" 13 | #include "flashroute/dump_result.h" 14 | #include "parsers/utils/utils.h" 15 | 16 | ABSL_FLAG(std::string, directory, "", "Path to the directory of output files"); 17 | ABSL_FLAG(std::string, label, "", "Label of the data set"); 18 | ABSL_FLAG(int, start, 0, "Starting index of the outputs"); 19 | ABSL_FLAG(int, end, 0, "Ending index of the outputs"); 20 | ABSL_FLAG(int, step, 0, "Step to read outputs"); 21 | ABSL_FLAG(int, offset, 0, "Comparing offset"); 22 | ABSL_FLAG(bool, formatted, false, "Output machine-readable format."); 23 | ABSL_FLAG(std::string, output, "", "Directory of output"); 24 | 25 | using flashroute::IpAddress; 26 | using flashroute::Ipv4Address; 27 | using flashroute::IpAddressHash; 28 | using flashroute::IpAddressEquality; 29 | 30 | template 31 | double JaccardSimilarity(std::unordered_set set1, std::unordered_set set2) { 32 | uint32_t intersect = 0; 33 | for (const auto& element : set1) { 34 | if (set2.find(element) != set2.end()) 35 | intersect++; 36 | } 37 | set1.insert(set2.begin(), set2.end()); 38 | return static_cast(intersect) / static_cast(set1.size()); 39 | } 40 | 41 | int main(int argc, char* argv[]) { 42 | LOG(INFO) << "Program starts."; 43 | FLAGS_alsologtostderr = 1; 44 | absl::SetProgramUsageMessage("This program does nothing."); 45 | absl::ParseCommandLine(argc, argv); 46 | 47 | std::string logOutput = absl::GetFlag(FLAGS_output) + 48 | absl::GetFlag(FLAGS_label) + 49 | std::to_string(absl::GetFlag(FLAGS_start)) + "_" + 50 | std::to_string(absl::GetFlag(FLAGS_end)) + "_log"; 51 | 52 | google::InitGoogleLogging(argv[0]); 53 | if (!absl::GetFlag(FLAGS_output).empty()) { 54 | google::SetLogDestination(0, logOutput.c_str()); 55 | } 56 | 57 | std::vector> targetFiles; 58 | 59 | std::string prefix = 60 | absl::GetFlag(FLAGS_directory) + absl::GetFlag(FLAGS_label) + "_"; 61 | int start = absl::GetFlag(FLAGS_start); 62 | int end = 63 | absl::GetFlag(FLAGS_end) == 0 ? start + 1 : absl::GetFlag(FLAGS_end); 64 | 65 | int step = absl::GetFlag(FLAGS_step); 66 | int offset = absl::GetFlag(FLAGS_offset); 67 | for (int i = start; i < end; i += step) { 68 | targetFiles.push_back( 69 | {prefix + std::to_string(i), prefix + std::to_string(i + offset)}); 70 | } 71 | 72 | double avgInterfaceJaccardIndex = 0; 73 | double avgEdgeJaccardIndex = 0; 74 | for (auto combo : targetFiles) { 75 | std::string set1 = combo.first; 76 | std::string set2 = combo.second; 77 | 78 | RouteMap edgeMap1; 79 | RouteMap edgeMap2; 80 | InterfaceSet interfaceSet1; 81 | InterfaceSet interfaceSet2; 82 | readDataset(set1, edgeMap1, interfaceSet1); 83 | readDataset(set2, edgeMap2, interfaceSet2); 84 | 85 | auto genericEdgeSet1 = edgeMapToGenericEdgeSet(edgeMap1); 86 | auto genericEdgeSet2 = edgeMapToGenericEdgeSet(edgeMap2); 87 | 88 | auto genericInterfaceSet1 = 89 | interfaceSetToGenericInterfaceSet(interfaceSet1); 90 | auto genericInterfaceSet2 = 91 | interfaceSetToGenericInterfaceSet(interfaceSet2); 92 | 93 | cleanEdgeMap(edgeMap1); 94 | cleanEdgeMap(edgeMap2); 95 | 96 | cleanInterfaceSet(interfaceSet1); 97 | cleanInterfaceSet(interfaceSet2); 98 | 99 | auto edgeJaccardIndex = JaccardSimilarity(genericEdgeSet1, genericEdgeSet2); 100 | auto interfaceJaccardIndex = 101 | JaccardSimilarity(genericInterfaceSet1, genericInterfaceSet2); 102 | 103 | auto logFilenameSet1 = getLogFileName(absl::GetFlag(FLAGS_directory), set1); 104 | auto logFilenameSet2 = getLogFileName(absl::GetFlag(FLAGS_directory), set2); 105 | auto createdTime1 = getStartingTime(logFilenameSet1); 106 | auto createdTime2 = getStartingTime(logFilenameSet2); 107 | 108 | // LOG(INFO) << "Set1: " << set1 << " Set2: " << set2; 109 | // LOG(INFO) << "Set1: " << createdTime1 << " Set2: " << createdTime2 110 | // << " Edge Jaccard Index: " << edgeJaccardIndex 111 | // << " Interface Jaccard Index: " << interfaceJaccardIndex; 112 | avgInterfaceJaccardIndex += interfaceJaccardIndex; 113 | avgEdgeJaccardIndex += edgeJaccardIndex; 114 | } 115 | LOG(INFO) << " Edge Jaccard Index: " << avgEdgeJaccardIndex/targetFiles.size() 116 | << " Interface Jaccard Index: " << avgInterfaceJaccardIndex/targetFiles.size(); 117 | } -------------------------------------------------------------------------------- /parsers/utils/frequency_analysis.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "absl/flags/flag.h" 6 | #include "absl/flags/parse.h" 7 | #include "absl/flags/usage.h" 8 | #include "absl/numeric/int128.h" 9 | #include "absl/strings/str_cat.h" 10 | #include "glog/logging.h" 11 | 12 | #include "flashroute/address.h" 13 | #include "flashroute/dump_result.h" 14 | #include "parsers/utils/utils.h" 15 | 16 | ABSL_FLAG(std::string, directory, "", "Path to the directory of output files"); 17 | ABSL_FLAG(std::string, label, "", "Label of the data set"); 18 | ABSL_FLAG(int, start, 0, "Starting index of the outputs"); 19 | ABSL_FLAG(int, end, 0, "Ending index of the outputs"); 20 | ABSL_FLAG(int, step, 0, "Step to read outputs"); 21 | ABSL_FLAG(bool, formatted, false, "Output machine-readable format."); 22 | ABSL_FLAG(std::string, output, "", "Directory of output"); 23 | 24 | using flashroute::IpAddress; 25 | using flashroute::IpAddressEquality; 26 | using flashroute::IpAddressHash; 27 | using flashroute::Ipv4Address; 28 | 29 | using GenericEdgeMap = std::unordered_map; 30 | using GenericInterfaceMap = std::unordered_map; 31 | 32 | template 33 | void getFrequencyDistribution( 34 | std::unordered_map input, 35 | std::unordered_map &frequency) { 36 | for (auto &pair : input) { 37 | auto result = frequency.find(pair.second); 38 | if (result == frequency.end()) { 39 | frequency.insert({pair.second, 1}); 40 | } else { 41 | frequency[pair.second] = result->second + 1; 42 | } 43 | } 44 | } 45 | 46 | void printFrequency(std::unordered_map &frequency) { 47 | LOG(INFO) << "----"; 48 | for (auto &pair : frequency) { 49 | LOG(INFO) << pair.first << " " << pair.second; 50 | } 51 | } 52 | 53 | int main(int argc, char *argv[]) { 54 | LOG(INFO) << "Program starts."; 55 | FLAGS_alsologtostderr = 1; 56 | absl::SetProgramUsageMessage("This program does nothing."); 57 | absl::ParseCommandLine(argc, argv); 58 | 59 | std::string logOutput = 60 | absl::GetFlag(FLAGS_output) + absl::GetFlag(FLAGS_label) + 61 | std::to_string(absl::GetFlag(FLAGS_start)) + "_" + 62 | std::to_string(absl::GetFlag(FLAGS_end)) + "_frequency_analysis_log"; 63 | 64 | google::InitGoogleLogging(argv[0]); 65 | if (!absl::GetFlag(FLAGS_output).empty()) { 66 | google::SetLogDestination(0, logOutput.c_str()); 67 | } 68 | 69 | std::vector targetFiles; 70 | 71 | std::string prefix = 72 | absl::GetFlag(FLAGS_directory) + absl::GetFlag(FLAGS_label) + "_"; 73 | int start = absl::GetFlag(FLAGS_start); 74 | int end = 75 | absl::GetFlag(FLAGS_end) == 0 ? start + 1 : absl::GetFlag(FLAGS_end); 76 | 77 | int step = absl::GetFlag(FLAGS_step); 78 | for (int i = start; i < end; i += step) { 79 | targetFiles.push_back(prefix + std::to_string(i)); 80 | } 81 | 82 | int datasetCount = 0; 83 | GenericEdgeMap frequencyEdgeMap; 84 | GenericInterfaceMap frequencyInterfaceMap; 85 | for (auto &dataset : targetFiles) { 86 | 87 | RouteMap edgeMap; 88 | InterfaceSet interfaceSet; 89 | readDataset(dataset, edgeMap, interfaceSet); 90 | 91 | auto genericEdgeSet = edgeMapToGenericEdgeSet(edgeMap); 92 | auto genericInterfaceSet = interfaceSetToGenericInterfaceSet(interfaceSet); 93 | 94 | cleanEdgeMap(edgeMap); 95 | cleanInterfaceSet(interfaceSet); 96 | 97 | auto logFilename = getLogFileName(absl::GetFlag(FLAGS_directory), dataset); 98 | auto createdTime = getStartingTime(logFilename); 99 | 100 | // Add edge to generic edge set and update its frequency 101 | for (auto edge : genericEdgeSet) { 102 | auto result = frequencyEdgeMap.find(edge); 103 | if (result == frequencyEdgeMap.end()) { 104 | frequencyEdgeMap.insert({edge, 1}); 105 | } else { 106 | frequencyEdgeMap[edge] = result->second + 1; 107 | } 108 | } 109 | 110 | // Add interface to generic interface set and update its frequency 111 | for (auto interface : genericInterfaceSet) { 112 | auto result = frequencyInterfaceMap.find(interface); 113 | if (result == frequencyInterfaceMap.end()) { 114 | frequencyInterfaceMap.insert({interface, 1}); 115 | } else { 116 | frequencyInterfaceMap[interface] = result->second + 1; 117 | } 118 | } 119 | datasetCount += 1; 120 | LOG(INFO) << datasetCount << " " << logFilename; 121 | } 122 | 123 | std::unordered_map edgeFrequencyDistribution; 124 | std::unordered_map interfaceFrequencyDistribution; 125 | 126 | getFrequencyDistribution(frequencyEdgeMap, edgeFrequencyDistribution); 127 | getFrequencyDistribution(frequencyInterfaceMap, 128 | interfaceFrequencyDistribution); 129 | printFrequency(edgeFrequencyDistribution); 130 | printFrequency(interfaceFrequencyDistribution); 131 | } -------------------------------------------------------------------------------- /parsers/utils/hot_branch_analyzer.cc: -------------------------------------------------------------------------------- 1 | #include // for std::size_t -> is a typedef on an unsinged int 2 | #include // for std::strlen 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "absl/flags/flag.h" 9 | #include "absl/flags/parse.h" 10 | #include "absl/flags/usage.h" 11 | #include "absl/numeric/int128.h" 12 | #include "absl/strings/str_cat.h" 13 | #include "glog/logging.h" 14 | 15 | #include "flashroute/address.h" 16 | #include "flashroute/dump_result.h" 17 | #include "parsers/utils/utils.h" 18 | 19 | using flashroute::IpAddress; 20 | using flashroute::IpAddressEquality; 21 | using flashroute::IpAddressHash; 22 | using flashroute::Ipv4Address; 23 | 24 | ABSL_FLAG( 25 | std::vector, targets, std::vector{}, 26 | "Outputs of flashroute. If there are multiple files, split by comma."); 27 | 28 | // Example: 29 | // bazel run parsers/utils/unique_interface_counter -- --directory 30 | // /data/directory/ --label 7_25_fast_scan --start 1 --end 100 31 | // --step 5 --formatted true --output ~/prefix_ 32 | 33 | ABSL_FLAG(std::string, directory, "", "Path to the directory of output files"); 34 | ABSL_FLAG(std::string, label, "", "Label of the data set"); 35 | ABSL_FLAG(int, start, 0, "Starting index of the outputs"); 36 | ABSL_FLAG(int, end, 0, "Ending index of the outputs"); 37 | ABSL_FLAG(int, step, 1, "Step to read outputs"); 38 | ABSL_FLAG(int, threshold, 2, "Hot branch threshold"); 39 | ABSL_FLAG(bool, formatted, false, "Output machine-readable format."); 40 | ABSL_FLAG(std::string, output, "", "Directory of output"); 41 | 42 | using EdgeMap = std::unordered_map< 43 | IpAddress *, std::shared_ptr>, 44 | IpAddressHash, IpAddressEquality>; 45 | void cleanEdgeMap(EdgeMap &map) { 46 | while (!map.empty()) { 47 | auto element = map.begin(); 48 | auto keyAddress = element->first; 49 | auto routeMap = element->second; 50 | while (!routeMap->empty()) { 51 | auto pair = routeMap->begin(); 52 | delete pair->second; 53 | routeMap->erase(pair->first); 54 | } 55 | map.erase(keyAddress); 56 | delete keyAddress; 57 | } 58 | } 59 | 60 | int main(int argc, char *argv[]) { 61 | FLAGS_alsologtostderr = 1; 62 | absl::SetProgramUsageMessage("This program does nothing."); 63 | absl::ParseCommandLine(argc, argv); 64 | 65 | std::string logOutput = absl::GetFlag(FLAGS_output) + 66 | absl::GetFlag(FLAGS_label) + 67 | std::to_string(absl::GetFlag(FLAGS_start)) + "_" + 68 | std::to_string(absl::GetFlag(FLAGS_end)) + "_log"; 69 | 70 | google::InitGoogleLogging(argv[0]); 71 | if (!absl::GetFlag(FLAGS_output).empty()) { 72 | google::SetLogDestination(0, logOutput.c_str()); 73 | } 74 | 75 | std::unordered_set 76 | observedInterface; 77 | 78 | EdgeMap observedEdges; 79 | std::unordered_set edges; 80 | // Hot branch describes for each destination, the number of changes we 81 | // observed. 82 | std::unordered_map hotBranch; 83 | uint32_t hotBranchThreshold = absl::GetFlag(FLAGS_threshold); 84 | 85 | std::ifstream inFile; 86 | std::vector targetFiles; 87 | if (absl::GetFlag(FLAGS_targets).size() != 0) { 88 | targetFiles = absl::GetFlag(FLAGS_targets); 89 | } else if (!absl::GetFlag(FLAGS_label).empty() && 90 | !absl::GetFlag(FLAGS_directory).empty()) { 91 | std::string prefix = 92 | absl::GetFlag(FLAGS_directory) + absl::GetFlag(FLAGS_label) + "_"; 93 | int start = absl::GetFlag(FLAGS_start); 94 | int end = 95 | absl::GetFlag(FLAGS_end) == 0 ? start + 1 : absl::GetFlag(FLAGS_end); 96 | for (int i = start; i < end; i += absl::GetFlag(FLAGS_step)) { 97 | targetFiles.push_back(prefix + std::to_string(i)); 98 | } 99 | } else { 100 | LOG(ERROR) << "No valid input."; 101 | } 102 | uint64_t records = 0; 103 | uint64_t interface = 0; 104 | uint64_t previousInterface = 0; 105 | uint64_t previousEdge = 0; 106 | uint32_t destinations = 0; 107 | 108 | for (auto file : targetFiles) { 109 | if (!absl::GetFlag(FLAGS_formatted)) { 110 | LOG(INFO) << "Start to read data from: " << file; 111 | } 112 | auto logFilename = getLogFileName(absl::GetFlag(FLAGS_directory), file); 113 | 114 | auto createdTime = getStartingTime(logFilename); 115 | inFile.open(file, std::ios::in | std::ios::binary); 116 | DataElement buffer; 117 | // {destination, {hopDistance, Interface}} 118 | std::unordered_map< 119 | IpAddress *, std::shared_ptr>, 120 | IpAddressHash, IpAddressEquality> 121 | observedEdges; 122 | 123 | std::unordered_set changedRoutesDestination; 124 | while (inFile.peek() != EOF) { 125 | inFile.read(reinterpret_cast(&buffer), 39); 126 | records++; 127 | if (buffer.ipv4 == 1) { 128 | // IPv4 address handling. 129 | auto addr = new Ipv4Address(buffer.responder[0]); 130 | if (buffer.fromDestination == true) { 131 | // Do nothing 132 | } else if (observedInterface.find(addr) == observedInterface.end()) { 133 | observedInterface.insert(addr); 134 | if (buffer.fromDestination == 0) 135 | interface += 1; 136 | } else { 137 | delete addr; 138 | } 139 | 140 | auto dest = new Ipv4Address(buffer.destination[0]); 141 | if (observedEdges.find(dest) == observedEdges.end()) { 142 | auto tmp = 143 | std::make_shared>(); 144 | observedEdges.insert({dest, tmp}); 145 | } 146 | // tmp = 147 | auto tmp = observedEdges.find(dest)->second; 148 | if (tmp->find(buffer.distance) == tmp->end()) { 149 | tmp->insert({buffer.distance, new Ipv4Address(buffer.responder[0])}); 150 | } else { 151 | // Mark the destination has changed. 152 | changedRoutesDestination.insert(dest->getIpv4Address()); 153 | } 154 | } else { 155 | // IPv6 address handling 156 | // TODO: we need to add the code logic handle IPv6 Address. 157 | } 158 | } 159 | inFile.clear(); 160 | inFile.seekg(0); 161 | inFile.close(); 162 | for (const auto &key : observedEdges) { 163 | // 164 | auto route = key.second; 165 | uint64_t edge = 0; 166 | for (const auto &node : *route) { 167 | if (route->find(node.first - 1) != route->end()) { 168 | uint64_t current = node.second->getIpv4Address(); 169 | uint64_t previous = 170 | route->find(node.first - 1)->second->getIpv4Address(); 171 | edge = previous | current >> 32; 172 | edges.insert(edge); 173 | } 174 | } 175 | } 176 | 177 | for (const uint32_t destination : changedRoutesDestination) { 178 | if (hotBranch.find(destination) == hotBranch.end()) { 179 | hotBranch.insert({destination, 1}); 180 | } else { 181 | hotBranch[destination] = hotBranch[destination] + 1; 182 | } 183 | } 184 | 185 | destinations = observedEdges.size(); 186 | cleanEdgeMap(observedEdges); 187 | if (!absl::GetFlag(FLAGS_formatted)) { 188 | LOG(INFO) << "Created " << createdTime 189 | << " Unique interface: " << interface << "(+" 190 | << interface - previousInterface 191 | << ") Unique edges: " << edges.size() << "(+" 192 | << edges.size() - previousEdge << ")"; 193 | } else { 194 | LOG(INFO) << createdTime << " " << interface << " " 195 | << interface - previousInterface << " " << edges.size() << " " 196 | << edges.size() - previousEdge; 197 | } 198 | previousInterface = interface; 199 | previousEdge = edges.size(); 200 | } 201 | 202 | uint32_t numberOfHotbranch = 0; 203 | for (auto &it : hotBranch) { 204 | if (it.second >= hotBranchThreshold) { 205 | numberOfHotbranch++; 206 | } 207 | } 208 | 209 | LOG(INFO) << "Processed " << records << " records."; 210 | LOG(INFO) << "There are " << interface << " unique interfaces."; 211 | LOG(INFO) << "There are " << edges.size() << " unique edges."; 212 | LOG(INFO) << "There are " << destinations << " desintaions."; 213 | LOG(INFO) << "There are " << numberOfHotbranch << "(" 214 | << static_cast(numberOfHotbranch) / destinations 215 | << "%) hot branches."; 216 | } 217 | -------------------------------------------------------------------------------- /parsers/utils/route_generator.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "absl/flags/flag.h" 7 | #include "absl/flags/parse.h" 8 | #include "absl/flags/usage.h" 9 | #include "absl/numeric/int128.h" 10 | #include "absl/strings/str_cat.h" 11 | #include "glog/logging.h" 12 | 13 | #include "flashroute/address.h" 14 | #include "flashroute/dump_result.h" 15 | #include "flashroute/utils.h" 16 | #include "parsers/utils/utils.h" 17 | 18 | ABSL_FLAG(std::string, file, "", "Path to the directory of output files"); 19 | 20 | int main(int argc, char *argv[]) { 21 | LOG(INFO) << "Program starts."; 22 | FLAGS_alsologtostderr = 1; 23 | absl::SetProgramUsageMessage("This program does nothing."); 24 | absl::ParseCommandLine(argc, argv); 25 | 26 | google::InitGoogleLogging(argv[0]); 27 | 28 | RouteFullMap routeFullMap; 29 | std::unordered_map> routeMap; 30 | readDataset(absl::GetFlag(FLAGS_file), routeFullMap, routeMap); 31 | LOG(INFO) << "Finished"; 32 | 33 | int similarRoute = 0; 34 | std::string buf; 35 | for (const auto &p : routeMap) { 36 | uint32_t dest = p.first; 37 | uint32_t addr = p.second->address; 38 | uint32_t dist = p.second->distances[dest]; 39 | 40 | std::vector routes; 41 | std::vector route; 42 | std::unordered_set visited; 43 | 44 | findRouteBack(addr, dest, route, routes, visited, routeFullMap, 0); 45 | LOG(INFO) << "Destination: " << flashroute::parseIpv4FromIntToString(dest) 46 | << " Distance: " << static_cast(dist); 47 | LOG(INFO) << "Find routes:" << routes.size(); 48 | int i = 0; 49 | for (auto &r : routes) { 50 | LOG(INFO) << "Route #" << ++i << "/" << routes.size(); 51 | LOG(INFO) << "Acyclic: " 52 | << (r.routeType == RouteType::Acyclic ? "True" : "False"); 53 | LOG(INFO) << "Convergence: " << static_cast(r.convergencePoint); 54 | for (auto &n : r.route) { 55 | LOG(INFO) << "Address:" 56 | << flashroute::parseIpv4FromIntToString(n.address) 57 | << " Destination:" 58 | << flashroute::parseIpv4FromIntToString(n.destination) 59 | << " Distance:" << static_cast(n.distance); 60 | } 61 | std::cin >> buf; 62 | if (buf == "j") { 63 | break; 64 | } 65 | } 66 | 67 | std::this_thread::sleep_for(std::chrono::milliseconds(500)); 68 | } 69 | } -------------------------------------------------------------------------------- /parsers/utils/route_similarity_analysis.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "absl/flags/flag.h" 7 | #include "absl/flags/parse.h" 8 | #include "absl/flags/usage.h" 9 | #include "absl/numeric/int128.h" 10 | #include "absl/strings/str_cat.h" 11 | #include "glog/logging.h" 12 | 13 | #include "flashroute/address.h" 14 | #include "flashroute/dump_result.h" 15 | #include "flashroute/utils.h" 16 | #include "parsers/utils/utils.h" 17 | 18 | ABSL_FLAG(std::string, directory, "", "Path to the directory of output files"); 19 | ABSL_FLAG(std::string, label, "", "Label of the data set"); 20 | ABSL_FLAG(int, start, 0, "Starting index of the outputs"); 21 | ABSL_FLAG(int, end, 0, "Ending index of the outputs"); 22 | ABSL_FLAG(int, step, 1, "Step to read outputs"); 23 | ABSL_FLAG(int, offset, 0, "Comparing offset"); 24 | ABSL_FLAG(int, level, 0, "Comparing level 0 weak 1 medium 2 strong"); 25 | ABSL_FLAG(bool, formatted, false, "Output machine-readable format."); 26 | ABSL_FLAG(std::string, output, "", "Directory of output"); 27 | 28 | using flashroute::IpAddress; 29 | using flashroute::IpAddressEquality; 30 | using flashroute::IpAddressHash; 31 | using flashroute::Ipv4Address; 32 | 33 | using GenericEdgeMap = std::unordered_map; 34 | using GenericInterfaceMap = std::unordered_map; 35 | 36 | enum class ComparisonLevel { STRONG, MEDIUM, WEAK }; 37 | 38 | int getLength( 39 | const std::shared_ptr> &m1) { 40 | for (int i = 32; i >= 0; i--) { 41 | if (m1->find(i) != m1->end()) 42 | return i; 43 | } 44 | return 0; 45 | } 46 | 47 | bool triNodeComparison( 48 | const std::shared_ptr> &m1, 49 | const std::shared_ptr> &m2, 50 | int8_t position, ComparisonLevel comp) { 51 | 52 | auto mn1 = m1->find(position); 53 | auto mn2 = m1->find(position + 1); 54 | auto mn3 = m1->find(position + 2); 55 | 56 | auto mm1 = m2->find(position); 57 | auto mm2 = m2->find(position + 1); 58 | auto mm3 = m2->find(position + 2); 59 | 60 | if (mn1 == m1->end()) 61 | return false; 62 | // if (mn1 == m1->end() || mn3 == m1->end()) 63 | // return false; 64 | // if (mm1 == m1->end() || mm3 == m1->end()) 65 | // return false; 66 | // if (mm1->second->getIpv4Address() != mn1->second->getIpv4Address() || 67 | // mm3->second->getIpv4Address() != mn3->second->getIpv4Address()) 68 | // return false; 69 | 70 | // if (comp == ComparisonLevel::WEAK) { 71 | // if (mm2 == m2->end() || mn2 == m1->end()) { 72 | // return true; 73 | // } 74 | 75 | // } else if (comp == ComparisonLevel::MEDIUM) { 76 | // if ((mm2 == m2->end() && mn2 == m1->end()) || 77 | // ((mm2 != m2->end() && mn2 != m1->end()) && 78 | // *(mm2->second) == *(mn2->second))) { 79 | // return true; 80 | // } 81 | // } else { 82 | // if (((mm2 != m2->end() && mn2 != m1->end()) && 83 | // *(mm2->second) == *(mn2->second))) { 84 | // return true; 85 | // } 86 | // } 87 | return true; 88 | } 89 | 90 | int main(int argc, char *argv[]) { 91 | LOG(INFO) << "Program starts."; 92 | FLAGS_alsologtostderr = 1; 93 | absl::SetProgramUsageMessage("This program does nothing."); 94 | absl::ParseCommandLine(argc, argv); 95 | 96 | std::string logOutput = 97 | absl::GetFlag(FLAGS_output) + absl::GetFlag(FLAGS_label) + 98 | std::to_string(absl::GetFlag(FLAGS_start)) + "_" + 99 | std::to_string(absl::GetFlag(FLAGS_end)) + "_frequency_analysis_log"; 100 | 101 | google::InitGoogleLogging(argv[0]); 102 | if (!absl::GetFlag(FLAGS_output).empty()) { 103 | google::SetLogDestination(0, logOutput.c_str()); 104 | } 105 | 106 | std::vector> targetFiles; 107 | 108 | std::string prefix = 109 | absl::GetFlag(FLAGS_directory) + absl::GetFlag(FLAGS_label) + "_"; 110 | int start = absl::GetFlag(FLAGS_start); 111 | int end = 112 | absl::GetFlag(FLAGS_end) == 0 ? start + 1 : absl::GetFlag(FLAGS_end); 113 | 114 | int step = absl::GetFlag(FLAGS_step); 115 | int offset = absl::GetFlag(FLAGS_offset); 116 | for (int i = start; i < end; i += step) { 117 | targetFiles.push_back( 118 | {prefix + std::to_string(i), prefix + std::to_string(i + offset)}); 119 | } 120 | 121 | ComparisonLevel level; 122 | switch (absl::GetFlag(FLAGS_level)) { 123 | case 0: 124 | level = ComparisonLevel::WEAK; 125 | break; 126 | case 1: 127 | level = ComparisonLevel::MEDIUM; 128 | case 2: 129 | level = ComparisonLevel::STRONG; 130 | }; 131 | 132 | for (auto combo : targetFiles) { 133 | 134 | LOG(INFO) << combo.first; 135 | LOG(INFO) << combo.second; 136 | std::string set1 = combo.first; 137 | std::string set2 = combo.second; 138 | 139 | RouteFullMap routeFullMap1; 140 | RouteFullMap routeFullMap2; 141 | 142 | std::unordered_map> routeMap1; 143 | readDataset(set1, routeFullMap1, routeMap1); 144 | LOG(INFO) << "Finished"; 145 | 146 | // readDataset(set2, routeFullMap2); 147 | int similarRoute = 0; 148 | std::string buf; 149 | for (const auto &p : routeMap1) { 150 | uint32_t dest = p.first; 151 | uint32_t addr = p.second->address; 152 | uint32_t dist = p.second->distances[dest]; 153 | 154 | std::vector routes; 155 | std::vector route; 156 | std::unordered_set visited; 157 | 158 | findRouteBack(addr, dest, route, routes, visited, routeFullMap1, 0); 159 | LOG(INFO) << "Destination: " << flashroute::parseIpv4FromIntToString(dest) 160 | << " Distance: " << static_cast(dist); 161 | LOG(INFO) << "Find routes:" << routes.size(); 162 | int i = 0; 163 | for (auto& r: routes) { 164 | LOG(INFO) << "Route #" << ++i << "/" << routes.size(); 165 | LOG(INFO) << "Acyclic: " 166 | << (r.routeType == RouteType::Acyclic ? "True" : "False"); 167 | LOG(INFO) << "Convergence: " 168 | << static_cast(r.convergencePoint); 169 | for(auto& n : r.route) { 170 | LOG(INFO) << "Address:" 171 | << flashroute::parseIpv4FromIntToString(n.address) 172 | << " Destination:" 173 | << flashroute::parseIpv4FromIntToString(n.destination) 174 | << " Distance:" << static_cast(n.distance); 175 | } 176 | std::cin >> buf; 177 | if (buf == "j") { 178 | break; 179 | } 180 | } 181 | } 182 | 183 | LOG(INFO) << "Route map size: " << routeFullMap1.size(); 184 | // LOG(INFO) << "Similar/All: " << similarRoute << "/" 185 | // << std::max(edgeMap2.size(), edgeMap1.size()); 186 | std::this_thread::sleep_for(std::chrono::milliseconds(500)); 187 | } 188 | } -------------------------------------------------------------------------------- /parsers/utils/unique_interface_counter.cc: -------------------------------------------------------------------------------- 1 | #include // for std::size_t -> is a typedef on an unsinged int 2 | #include // for std::strlen 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "glog/logging.h" 9 | #include "absl/flags/usage.h" 10 | #include "absl/flags/flag.h" 11 | #include "absl/flags/parse.h" 12 | #include "absl/strings/str_cat.h" 13 | #include "absl/numeric/int128.h" 14 | 15 | #include "flashroute/address.h" 16 | #include "flashroute/dump_result.h" 17 | #include "parsers/utils/utils.h" 18 | 19 | using flashroute::IpAddress; 20 | using flashroute::Ipv4Address; 21 | using flashroute::IpAddressHash; 22 | using flashroute::IpAddressEquality; 23 | 24 | ABSL_FLAG(std::vector, targets, std::vector{}, 25 | "Outputs of flashroute. If there are multiple files, split by comma."); 26 | 27 | // Example: 28 | // bazel run parsers/utils/unique_interface_counter -- --directory 29 | // /data/directory/ --label 7_25_fast_scan --start 1 --end 100 30 | // --step 5 --formatted true --output ~/prefix_ 31 | 32 | ABSL_FLAG(std::string, directory, "", "Path to the directory of output files"); 33 | ABSL_FLAG(std::string, label, "", "Label of the data set"); 34 | ABSL_FLAG(int, start, 0, "Starting index of the outputs"); 35 | ABSL_FLAG(int, end, 0, "Ending index of the outputs"); 36 | ABSL_FLAG(int, step, 1, "Step to read outputs"); 37 | ABSL_FLAG(bool, formatted, false, "Output machine-readable format."); 38 | ABSL_FLAG(std::string, output, "", "Directory of output"); 39 | 40 | using EdgeMap = std::unordered_map< 41 | IpAddress *, std::shared_ptr>, 42 | IpAddressHash, IpAddressEquality>; 43 | void cleanEdgeMap(EdgeMap& map) { 44 | while (!map.empty()) { 45 | auto element = map.begin(); 46 | auto keyAddress = element->first; 47 | auto routeMap = element->second; 48 | while (!routeMap->empty()) { 49 | auto pair = routeMap->begin(); 50 | delete pair->second; 51 | routeMap->erase(pair->first); 52 | } 53 | map.erase(keyAddress); 54 | delete keyAddress; 55 | } 56 | } 57 | 58 | int main(int argc, char* argv[]) { 59 | FLAGS_alsologtostderr = 1; 60 | absl::SetProgramUsageMessage("This program does nothing."); 61 | absl::ParseCommandLine(argc, argv); 62 | 63 | std::string logOutput = absl::GetFlag(FLAGS_output) + 64 | absl::GetFlag(FLAGS_label) + 65 | std::to_string(absl::GetFlag(FLAGS_start)) + "_" + 66 | std::to_string(absl::GetFlag(FLAGS_end)) + "_log"; 67 | 68 | google::InitGoogleLogging(argv[0]); 69 | if (!absl::GetFlag(FLAGS_output).empty()) { 70 | google::SetLogDestination(0, logOutput.c_str()); 71 | } 72 | 73 | std::unordered_set observedInterface; 74 | 75 | EdgeMap observedEdges; 76 | std::unordered_set edges; 77 | 78 | std::ifstream inFile; 79 | std::vector targetFiles; 80 | if (absl::GetFlag(FLAGS_targets).size() != 0) { 81 | targetFiles = absl::GetFlag(FLAGS_targets); 82 | } else if (!absl::GetFlag(FLAGS_label).empty() && 83 | !absl::GetFlag(FLAGS_directory).empty()) { 84 | std::string prefix = 85 | absl::GetFlag(FLAGS_directory) + absl::GetFlag(FLAGS_label) + "_"; 86 | int start = absl::GetFlag(FLAGS_start); 87 | int end = 88 | absl::GetFlag(FLAGS_end) == 0 ? start + 1 : absl::GetFlag(FLAGS_end); 89 | for (int i = start; i < end; i += absl::GetFlag(FLAGS_step)) { 90 | targetFiles.push_back(prefix + std::to_string(i)); 91 | } 92 | } else { 93 | LOG(ERROR) << "No valid input."; 94 | } 95 | uint64_t records = 0; 96 | uint64_t interface = 0; 97 | uint64_t previousInterface = 0; 98 | uint64_t previousEdge = 0; 99 | 100 | for (auto file : targetFiles) { 101 | if (!absl::GetFlag(FLAGS_formatted)) { 102 | LOG(INFO) << "Start to read data from: " << file; 103 | } 104 | auto logFilename = getLogFileName(absl::GetFlag(FLAGS_directory), file); 105 | 106 | auto createdTime = getStartingTime(logFilename); 107 | inFile.open(file, std::ios::in | std::ios::binary); 108 | DataElement buffer; 109 | std::unordered_map< 110 | IpAddress *, std::shared_ptr>, 111 | IpAddressHash, IpAddressEquality> 112 | observedEdges; 113 | while (inFile.peek() != EOF) { 114 | inFile.read(reinterpret_cast(&buffer), 39); 115 | records++; 116 | if (buffer.ipv4 == 1) { 117 | // IPv4 address handling. 118 | auto addr = new Ipv4Address(buffer.responder[0]); 119 | if (buffer.fromDestination == true) { 120 | // Do nothing 121 | } else if (observedInterface.find(addr) == observedInterface.end()) { 122 | observedInterface.insert(addr); 123 | if (buffer.fromDestination == 0) 124 | interface += 1; 125 | 126 | } else { 127 | delete addr; 128 | } 129 | auto dest = new Ipv4Address(buffer.destination[0]); 130 | if (observedEdges.find(dest) == observedEdges.end()) { 131 | auto tmp = std::make_shared>(); 132 | observedEdges.insert({dest, tmp}); 133 | } 134 | auto tmp = observedEdges.find(dest)->second; 135 | if (tmp->find(buffer.distance) == tmp->end()) { 136 | tmp->insert({buffer.distance, new Ipv4Address(buffer.responder[0])}); 137 | } 138 | } else { 139 | // IPv6 address handling 140 | // TODO: we need to add the code logic handle IPv6 Address. 141 | } 142 | } 143 | inFile.clear(); 144 | inFile.seekg(0); 145 | inFile.close(); 146 | for (const auto &key : observedEdges) { 147 | auto route = key.second; 148 | uint64_t edge = 0; 149 | for (const auto &node : *route) { 150 | if (route->find(node.first - 1) != route->end()) { 151 | uint64_t current = node.second->getIpv4Address(); 152 | uint64_t previous = 153 | route->find(node.first - 1)->second->getIpv4Address(); 154 | edge = previous | current >> 32; 155 | edges.insert(edge); 156 | } 157 | } 158 | } 159 | cleanEdgeMap(observedEdges); 160 | if (!absl::GetFlag(FLAGS_formatted)) { 161 | LOG(INFO) << "Created " << createdTime 162 | << " Unique interface: " << interface << "(+" 163 | << interface - previousInterface 164 | << ") Unique edges: " << edges.size() << "(+" 165 | << edges.size() - previousEdge << ")"; 166 | } else { 167 | LOG(INFO) << createdTime 168 | << " " << interface << " " 169 | << interface - previousInterface 170 | << " " << edges.size() << " " 171 | << edges.size() - previousEdge; 172 | } 173 | previousInterface = interface; 174 | previousEdge = edges.size(); 175 | } 176 | 177 | LOG(INFO) << "Processed " << records << " records."; 178 | LOG(INFO) << "There are " << interface << " unique interfaces."; 179 | LOG(INFO) << "There are " << edges.size() << " unique edges."; 180 | 181 | } 182 | -------------------------------------------------------------------------------- /parsers/utils/utils.cc: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | #include 4 | 5 | #include "glog/logging.h" 6 | #include 7 | #include 8 | 9 | std::string getLogFileName(const std::string &directory, 10 | const std::string &prefix) { 11 | for (const auto &entry : boost::make_iterator_range( 12 | boost::filesystem::directory_iterator(directory), {})) { 13 | std::string file = entry.path().string(); 14 | if (prefix != file && file.find(prefix + "_log") != std::string::npos) { 15 | return file; 16 | } 17 | } 18 | return ""; 19 | } 20 | 21 | std::string getStartingTime(const std::string &logFile) { 22 | 23 | std::ifstream inFile; 24 | inFile.open(logFile, std::ios::in); 25 | std::string line; 26 | std::getline(inFile, line); 27 | inFile.clear(); 28 | inFile.seekg(0); 29 | inFile.close(); 30 | return line.substr(21); 31 | } 32 | 33 | static void connectRouteNodev4(uint32_t dest, std::shared_ptr x, 34 | std::shared_ptr y) { 35 | 36 | x->next.insert({dest, y}); 37 | y->previous.insert({dest, x}); 38 | } 39 | 40 | void readDataset( 41 | std::string file, RouteFullMap &addressMap, 42 | std::unordered_map>& routeMap) { 43 | 44 | std::ifstream inFile; 45 | inFile.open(file, std::ios::in | std::ios::binary); 46 | DataElement buffer; 47 | 48 | uint32_t records = 0; 49 | 50 | std::unordered_map>> 52 | routeRawMap; 53 | // > 54 | 55 | while (inFile.peek() != EOF) { 56 | inFile.read(reinterpret_cast(&buffer), 39); 57 | records++; 58 | if (buffer.ipv4 == 1) { 59 | // IPv4 address handling. 60 | auto addr = buffer.responder[0]; 61 | auto dest = buffer.destination[0]; 62 | auto distance = buffer.distance; 63 | auto destFound = routeRawMap.find(dest); 64 | if (destFound == routeRawMap.end()) { 65 | auto tmp = std::make_shared>(); 66 | destFound = routeRawMap.insert({dest, tmp}).first; 67 | } 68 | if (destFound->second->find(distance) == destFound->second->end()) 69 | destFound->second->insert({distance, addr}); 70 | } else { 71 | // IPv6 address handling 72 | // TODO: we need to add the code logic handle IPv6 Address. 73 | } 74 | } 75 | inFile.close(); 76 | 77 | LOG(INFO) << "Preprocessing finished."; 78 | uint32_t count = 0; 79 | std::shared_ptr lastNode = nullptr; 80 | for(const auto& elem : routeRawMap) { 81 | auto dest = elem.first; 82 | auto& route = elem.second; 83 | lastNode = nullptr; 84 | 85 | std::shared_ptr previousNode = nullptr; 86 | for (const auto& node : *route) { 87 | auto distance = node.first; 88 | auto addr = node.second; 89 | auto nodeFound = addressMap.find(addr); 90 | if (nodeFound == addressMap.end()) { 91 | auto tmp = std::make_shared(); 92 | tmp->address = addr; 93 | nodeFound = addressMap.insert({addr, std::move(tmp)}).first; 94 | } 95 | auto currentNode = nodeFound->second; 96 | if (currentNode->distances.find(dest) == currentNode->distances.end()) 97 | currentNode->distances.insert({dest, distance}); 98 | 99 | if (previousNode) { 100 | connectRouteNodev4(dest, previousNode, currentNode); 101 | } 102 | previousNode = currentNode; 103 | lastNode = currentNode; 104 | } 105 | assert(lastNode); 106 | routeMap.insert({dest, lastNode}); 107 | 108 | LOG_EVERY_N(INFO, 100000) << static_cast(count) / routeRawMap.size() * 100 << "% finished."; 109 | count++; 110 | } 111 | LOG(INFO) << "Processing finished."; 112 | } 113 | 114 | bool findRouteBack(uint32_t address, uint32_t dest, 115 | std::vector &route, 116 | std::vector &routes, 117 | std::unordered_set &visited, 118 | RouteFullMap &addressMap, uint8_t convergencePoint) { 119 | static int depth = 0; 120 | if (visited.find(address) != visited.end()) { 121 | // Cycle detected. 122 | return false; 123 | } 124 | auto node = addressMap.find(address)->second; 125 | auto distance = node->distances[dest]; 126 | route.push_back({address, dest, distance}); 127 | visited.insert(address); 128 | 129 | if ((node->distances.find(dest) != node->distances.end() && 130 | node->distances[dest] <= 2) || 131 | (node->previous.size() == 0)) { 132 | routes.push_back({route, RouteType::Regular, convergencePoint}); 133 | route.pop_back(); 134 | visited.erase(address); 135 | return true; 136 | } 137 | // If we can find the same destionation predecessor. 138 | bool success = false; 139 | if (node->previous.find(dest) != node->previous.end()) { 140 | depth++; 141 | success = 142 | findRouteBack(node->previous.find(dest)->second->address, dest, route, 143 | routes, visited, addressMap, convergencePoint); 144 | depth--; 145 | } else { 146 | std::unordered_set visitedPredecessor; 147 | for (auto &tmp : node->previous) { 148 | auto predecessorAddress = tmp.second->address; 149 | auto predecessorDestination = tmp.first; 150 | 151 | if (visitedPredecessor.find(predecessorAddress) != 152 | visitedPredecessor.end()) 153 | continue; 154 | else 155 | visitedPredecessor.insert(predecessorAddress); 156 | 157 | depth++; 158 | success = 159 | findRouteBack(predecessorAddress, predecessorDestination, route, 160 | routes, visited, addressMap, convergencePoint + 1) || 161 | success; 162 | depth--; 163 | } 164 | } 165 | if (!success) { 166 | // If all attemps fail, this is the end. 167 | routes.push_back({route, RouteType::Acyclic, convergencePoint}); 168 | } 169 | route.pop_back(); 170 | visited.erase(address); 171 | return true; 172 | } 173 | 174 | void readDataset(std::string file, RouteMap &edgeMap, 175 | InterfaceSet &interfaceSet) { 176 | 177 | std::ifstream inFile; 178 | inFile.open(file, std::ios::in | std::ios::binary); 179 | DataElement buffer; 180 | 181 | uint32_t records = 0; 182 | 183 | while (inFile.peek() != EOF) { 184 | inFile.read(reinterpret_cast(&buffer), 39); 185 | records++; 186 | if (buffer.ipv4 == 1) { 187 | // IPv4 address handling. 188 | auto addr = new Ipv4Address(buffer.responder[0]); 189 | if (buffer.fromDestination == true) { 190 | // Do nothing 191 | } else if (interfaceSet.find(addr) == interfaceSet.end()) { 192 | if (buffer.fromDestination == 0) { 193 | interfaceSet.insert(addr); 194 | } 195 | } else { 196 | delete addr; 197 | } 198 | auto dest = new Ipv4Address(buffer.destination[0]); 199 | if (edgeMap.find(dest) == edgeMap.end()) { 200 | auto tmp = 201 | std::make_shared>(); 202 | edgeMap.insert({dest, tmp}); 203 | } 204 | auto tmp = edgeMap.find(dest)->second; 205 | if (tmp->find(buffer.distance) == tmp->end()) { 206 | tmp->insert({buffer.distance, new Ipv4Address(buffer.responder[0])}); 207 | } 208 | } else { 209 | // IPv6 address handling 210 | // TODO: we need to add the code logic handle IPv6 Address. 211 | } 212 | } 213 | inFile.close(); 214 | } 215 | 216 | GenericInterfaceSet 217 | interfaceSetToGenericInterfaceSet(InterfaceSet &interfaceSet) { 218 | GenericInterfaceSet genericItSet; 219 | for (const auto &element : interfaceSet) { 220 | genericItSet.insert(element->getIpv4Address()); 221 | } 222 | return genericItSet; 223 | } 224 | 225 | GenericEdgeSet edgeMapToGenericEdgeSet(RouteMap &edgeMap) { 226 | GenericEdgeSet edgeSet; 227 | for (const auto &key : edgeMap) { 228 | auto route = key.second; 229 | uint64_t edge = 0; 230 | for (const auto &node : *route) { 231 | if (route->find(node.first - 1) != route->end()) { 232 | uint64_t current = node.second->getIpv4Address(); 233 | uint64_t previous = 234 | route->find(node.first - 1)->second->getIpv4Address(); 235 | edge = previous | current >> 32; 236 | edgeSet.insert(edge); 237 | } 238 | } 239 | } 240 | return edgeSet; 241 | } 242 | 243 | void cleanInterfaceSet(InterfaceSet &interfaceSet) { 244 | while (!interfaceSet.empty()) { 245 | auto element = interfaceSet.begin(); 246 | interfaceSet.erase(element); 247 | } 248 | } 249 | 250 | void cleanEdgeMap(RouteMap &edgeMap) { 251 | while (!edgeMap.empty()) { 252 | auto element = edgeMap.begin(); 253 | auto keyAddress = element->first; 254 | auto routeMap = element->second; 255 | while (!routeMap->empty()) { 256 | auto pair = routeMap->begin(); 257 | delete pair->second; 258 | routeMap->erase(pair->first); 259 | } 260 | edgeMap.erase(keyAddress); 261 | delete keyAddress; 262 | } 263 | } -------------------------------------------------------------------------------- /parsers/utils/utils.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "flashroute/address.h" 7 | 8 | using flashroute::IpAddress; 9 | using flashroute::Ipv4Address; 10 | using flashroute::IpAddressHash; 11 | using flashroute::IpAddressEquality; 12 | 13 | struct RouteNodev4 { 14 | uint32_t address; 15 | 16 | /* */ 17 | std::unordered_map> next; 18 | /* */ 19 | std::unordered_map> previous; 20 | /* */ 21 | std::unordered_map distances; 22 | }; 23 | 24 | enum RouteType { 25 | Acyclic, 26 | Regular 27 | }; 28 | 29 | struct RouteConstructNodev4 { 30 | uint32_t address; 31 | uint32_t destination; 32 | uint8_t distance; 33 | }; 34 | 35 | struct Routev4 { 36 | std::vector route; 37 | RouteType routeType; 38 | uint8_t convergencePoint; 39 | }; 40 | 41 | // 42 | using RouteFullMap = std::unordered_map>; 43 | 44 | struct DataElement { 45 | uint32_t destination[4]; 46 | uint32_t responder[4]; 47 | uint32_t rtt; 48 | uint8_t distance; 49 | uint8_t fromDestination; 50 | uint8_t ipv4; 51 | } __attribute__((packed));; 52 | 53 | using RouteMap = 54 | std::unordered_map> /* */, 57 | IpAddressHash, IpAddressEquality>; 58 | 59 | // Ipv4 Generic edge and interface set. 60 | using GenericEdgeSet = std::unordered_set; 61 | using GenericInterfaceSet = std::unordered_set; 62 | 63 | using InterfaceSet = std::unordered_set; 65 | 66 | std::string getLogFileName(const std::string &directory, 67 | const std::string &prefix); 68 | 69 | std::string getStartingTime(const std::string &logFile); 70 | 71 | // Read dataset to a graph map 72 | void readDataset( 73 | std::string file, RouteFullMap &addressMap, 74 | std::unordered_map> &routeMap); 75 | 76 | // Find route from a given point backward to the vantage point 77 | bool findRouteBack(uint32_t address, uint32_t dest, 78 | std::vector &route, 79 | std::vector &routes, 80 | std::unordered_set &visited, 81 | RouteFullMap &addressMap, uint8_t convergencePoint); 82 | 83 | void readDataset(std::string file, RouteMap &edgeMap, 84 | InterfaceSet &interfaceSet); 85 | 86 | GenericEdgeSet edgeMapToGenericEdgeSet(RouteMap &edgeMap); 87 | 88 | GenericInterfaceSet 89 | interfaceSetToGenericInterfaceSet(InterfaceSet &interfaceSet); 90 | 91 | void cleanInterfaceSet(InterfaceSet &interfaceSet); 92 | 93 | void cleanEdgeMap(RouteMap &edgeMap); -------------------------------------------------------------------------------- /tools/BUILD: -------------------------------------------------------------------------------- 1 | load("@parsers_deps//:requirements.bzl", "requirement") 2 | 3 | py_binary( 4 | name = "continuous_runner", 5 | srcs = ["continuous_runner.py"], 6 | python_version = "PY3", 7 | deps = [ 8 | requirement("glog") 9 | ], 10 | ) 11 | 12 | py_binary( 13 | name = "discovery_optimize_mode_runner", 14 | srcs = ["discovery_optimize_mode_runner.py"], 15 | python_version = "PY3", 16 | deps = [ 17 | requirement("glog") 18 | ], 19 | ) -------------------------------------------------------------------------------- /tools/continuous_runner.py: -------------------------------------------------------------------------------- 1 | import os 2 | import glog 3 | import argparse 4 | import time 5 | 6 | 7 | def main(): 8 | argument_parser = argparse.ArgumentParser( 9 | description='Parse output of FlashRoute.') 10 | argument_parser.add_argument("-o", type=str, required=True, 11 | help='Directory of output.') 12 | argument_parser.add_argument("-e", type=str, required=True, 13 | help='Path to Flashroute.') 14 | argument_parser.add_argument("-n", type=int, required=False, default=0, 15 | help='Number of executions.') 16 | argument_parser.add_argument("-t", type=int, required=False, 17 | help='Time to run (minutes)') 18 | argument_parser.add_argument("-d", type=int, required=True, 19 | help='Interval in second between two continuous executions.') 20 | argument_parser.add_argument("-l", type=str, required=True, 21 | help='Label of outputs.') 22 | argument_parser.add_argument("-a", type=str, required=True, 23 | help='Arguments for Flashroute.') 24 | argument_parser.add_argument("-nohistory", type=bool, required=False, default=False, 25 | help='Not reuse history.') 26 | argument_parser.add_argument("-ss", type=int, required=False, default=0, 27 | help='Probing initial speed.') 28 | argument_parser.add_argument("-si", type=int, required=False, default=0, 29 | help='Probing speed step.') 30 | argument_parser.add_argument("-ps", type=int, required=False, default=0, 31 | help='Initial prefix length.') 32 | argument_parser.add_argument("-test", type=bool, required=False, default=False, 33 | help='Test mode.') 34 | args = argument_parser.parse_args() 35 | 36 | output_dir = os.path.abspath(args.o) 37 | 38 | if not os.path.isdir(output_dir): 39 | glog.info(f"{output_dir} is not a directory.") 40 | return 41 | 42 | previous_output = "" 43 | read_history_arg = "" 44 | # stair speed probing 45 | start_speed = args.ss 46 | speed_step = args.si 47 | speed_arg = "" 48 | speed_label = "" 49 | 50 | # stair prefix 51 | start_prefix = args.ps 52 | prefix_arg = "" 53 | 54 | i = 0 55 | start = time.time() 56 | while (args.n != 0 and i < args.n) or ((time.time() - start) / 60 <= args.t): 57 | glog.info(f"{i} round") 58 | if args.nohistory == False and previous_output != "": 59 | read_history_arg = f" --history_probing_result {previous_output}" 60 | 61 | if start_speed != 0 and speed_step !=0: 62 | speed_arg = f" --probing_rate {start_speed} " 63 | speed_label = f"probibng_rate_{start_speed}" 64 | output_filename = os.path.join(output_dir, f"{args.l}_{speed_label}") 65 | start_speed += speed_step 66 | elif start_prefix != 0: 67 | prefix_arg = f" --granularity {start_prefix} " 68 | prefix_label = f"granularity_{start_prefix}" 69 | output_filename = os.path.join(output_dir, f"{args.l}_{prefix_label}") 70 | start_prefix += 1 71 | else: 72 | # generate output filename 73 | output_filename = os.path.join(output_dir, f"{args.l}_{i}") 74 | 75 | command = f"{args.e} --output {output_filename} {read_history_arg} {speed_arg} {prefix_arg} {args.a}" 76 | glog.info(command) 77 | if not args.test: 78 | os.system(command) 79 | time.sleep(args.d) 80 | previous_output = output_filename 81 | i += 1 82 | 83 | 84 | if __name__ == "__main__": 85 | main() 86 | -------------------------------------------------------------------------------- /tools/discovery_optimize_mode_runner.py: -------------------------------------------------------------------------------- 1 | import os 2 | import glog 3 | import argparse 4 | import time 5 | 6 | 7 | def main(): 8 | argument_parser = argparse.ArgumentParser( 9 | description='Parse output of FlashRoute.') 10 | argument_parser.add_argument("-o", type=str, required=True, 11 | help='Directory of output.') 12 | argument_parser.add_argument("-e", type=str, required=True, 13 | help='Path to Flashroute.') 14 | argument_parser.add_argument("-r", type=str, required=True, 15 | help='Path to Reprobe Target Generator.') 16 | argument_parser.add_argument("-n", type=int, required=False, default=0, 17 | help='Number of executions.') 18 | argument_parser.add_argument("-t", type=int, required=False, 19 | help='Time to run (minutes)') 20 | argument_parser.add_argument("-d", type=int, required=True, 21 | help='Interval in second between two continuous executions.') 22 | argument_parser.add_argument("-l", type=str, required=True, 23 | help='Label of outputs.') 24 | argument_parser.add_argument("-ma", type=str, required=True, 25 | help='Arguments for the main scan of Flashroute.') 26 | argument_parser.add_argument("-ea", type=str, required=True, 27 | help='Arguments for the extra scans of Flashroute.') 28 | argument_parser.add_argument("-test", type=bool, required=False, default=False, 29 | help='Test mode.') 30 | args = argument_parser.parse_args() 31 | 32 | output_dir = os.path.abspath(args.o) 33 | 34 | if not os.path.isdir(output_dir): 35 | glog.info(f"{output_dir} is not a directory.") 36 | return 37 | 38 | # scan label 39 | scan_label = args.l 40 | 41 | # scan arguments 42 | main_scan_argument = args.ma 43 | extra_scan_argument = args.ea 44 | 45 | reprobe_target_file = "" 46 | reprobe_nonstop_file = "" 47 | reprobe_target_generator_command = "" 48 | 49 | 50 | i = 0 51 | start = time.time() 52 | while (args.n != 0 and i < args.n) or ((time.time() - start) / 60 <= args.t): 53 | glog.info(f"{i} round") 54 | output_filename = os.path.join(output_dir, f"{scan_label}_{i}") 55 | reprobe_target_file_prefix = os.path.join(output_dir, f"{scan_label}_{i}_reprobe_target") 56 | previous_reprobe_target_file_prefix = os.path.join(output_dir, f"{scan_label}_{i-1}_reprobe_target") 57 | 58 | command = "" 59 | if i == 0: 60 | command = f"{args.e} --output {output_filename} {main_scan_argument}" 61 | glog.info(command) 62 | else: 63 | reprobe_target_file = f"{previous_reprobe_target_file_prefix}" 64 | reprobe_nonstop_file = f"{previous_reprobe_target_file_prefix}_nonstop" 65 | command = f"{args.e} --output {output_filename} --noforward_probing --targets {reprobe_target_file} --nonstop_set_file {reprobe_nonstop_file} {extra_scan_argument}" 66 | glog.info(command) 67 | 68 | if not args.test: 69 | os.system(command) 70 | time.sleep(args.d) 71 | 72 | # Run reprobe target generator 73 | reprobe_target_generator_command = f"{args.r} --directory {output_dir}/ --label {scan_label} --start 0 --end {i + 1} --output {reprobe_target_file_prefix}" 74 | glog.info(reprobe_target_generator_command) 75 | if not args.test: 76 | os.system(reprobe_target_generator_command) 77 | time.sleep(args.d) 78 | 79 | i += 1 80 | 81 | 82 | if __name__ == "__main__": 83 | main() 84 | --------------------------------------------------------------------------------