├── .clang-format ├── .gitattributes ├── .github └── workflows │ ├── buildandtest.yml │ └── dockerimage.yml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── Dockerfile ├── LICENSE ├── README.md ├── benchmark ├── properties.json └── zone_files │ ├── metadata.json │ └── root.txt ├── bin ├── CMakeLists.txt ├── groot.cpp ├── groot.vcxproj ├── groot.vcxproj.filters └── groot_old.cpp ├── groot.sln ├── setup.sh ├── src ├── CMakeLists.txt ├── context.h ├── driver.cpp ├── driver.h ├── ec-task.cpp ├── ec-task.h ├── equivalence-class.cpp ├── equivalence-class.h ├── interpretation-graph.cpp ├── interpretation-properties.h ├── job.h ├── label-graph.cpp ├── label-graph.h ├── libgroot.vcxproj ├── my-logger.h ├── node-label.cpp ├── node-label.h ├── properties.cpp ├── resource-record.cpp ├── resource-record.h ├── structural-task.cpp ├── structural-task.h ├── task.h ├── utils.cpp ├── utils.h ├── zone-file-parser.cpp ├── zone-graph.cpp └── zone-graph.h └── test ├── CMakeLists.txt ├── TestFiles ├── bankcardExample │ ├── jobs.json │ └── zone_files │ │ ├── a.gtld-servers.net.txt │ │ ├── metadata.json │ │ ├── ns1.fnni.com.1.txt │ │ ├── ns1.fnni.com.2.txt │ │ ├── ns2.fnni.net.1.txt │ │ └── ns2.fnni.net.2.txt ├── cc.il.us │ ├── ig_expected.dot │ ├── jobs.json │ ├── label_graph_expected.dot │ └── zone_files │ │ ├── cc.il.us..txt │ │ ├── child.richland.cc.il.us.-2.txt │ │ ├── child.richland.cc.il.us..txt │ │ ├── metadata.json │ │ └── richland.cc.il.us..txt ├── choice │ ├── jobs.json │ └── zone_files │ │ ├── NS1.com.txt │ │ ├── NS2.com.txt │ │ ├── metadata.json │ │ └── start.com.txt ├── infinite │ ├── jobs.json │ └── zone_files │ │ ├── inf.net.txt │ │ └── metadata.json ├── integration_tests │ └── simple_test │ │ ├── jobs.json │ │ ├── output_expected.json │ │ └── zone_files │ │ ├── foo.com.txt │ │ └── metadata.json ├── parser_tests │ └── test_parser.txt └── short │ ├── jobs.json │ └── zone_files │ ├── inf.net.txt │ └── metadata.json ├── bankcardTest.cpp ├── driver-test.h ├── ec-test.cpp ├── integration-test.cpp ├── label-graph-test.cpp ├── main-example-test.cpp ├── script.py ├── test.vcxproj ├── tester.cpp ├── tests.filters ├── util-test.cpp └── zone-graph-test.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Microsoft 2 | IndentWidth: 4 3 | BreakBeforeBraces: Linux 4 | AlignAfterOpenBracket: AlwaysBreak 5 | AllowAllParametersOfDeclarationOnNextLine: false 6 | BinPackParameters: false 7 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.github/workflows/buildandtest.yml: -------------------------------------------------------------------------------- 1 | name: Build and Test 2 | 3 | on: 4 | push: 5 | paths-ignore: 6 | - 'README.md' 7 | branches: 8 | - '*' 9 | - '!master' 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | steps: 15 | 16 | - name: Checks out the repo 17 | uses: actions/checkout@v2 18 | with: 19 | submodules: true 20 | 21 | - name: Setup the environment 22 | run: |- 23 | bash setup.sh 24 | - name: Build and test groot 25 | run: |- 26 | mkdir build 27 | cd build 28 | cmake -DCODE_COVERAGE=ON -DBUILD_TESTING=ON -DCMAKE_BUILD_TYPE=Debug .. 29 | cmake --build . --config Debug 30 | cp -r ../test/TestFiles/ test/ 31 | ctest --output-on-failure --extra-verbose 32 | -------------------------------------------------------------------------------- /.github/workflows/dockerimage.yml: -------------------------------------------------------------------------------- 1 | name: Codecov and Docker Image CI 2 | 3 | on: 4 | push: 5 | paths-ignore: 6 | - 'README.md' 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | 14 | - name: Checks out the repo 15 | uses: actions/checkout@v2 16 | with: 17 | submodules: true 18 | 19 | - name: Setup the environment 20 | run: |- 21 | bash setup.sh 22 | 23 | - name: Initialize CodeQL 24 | uses: github/codeql-action/init@v1 25 | with: 26 | languages: cpp, python 27 | 28 | - name: Build and test groot 29 | run: |- 30 | mkdir build 31 | cd build 32 | cmake -DCODE_COVERAGE=ON -DBUILD_TESTING=ON -DCMAKE_BUILD_TYPE=Debug .. 33 | cmake --build . --config Debug 34 | cp -r ../test/TestFiles/ test/ 35 | ctest --output-on-failure --extra-verbose 36 | 37 | - name: Perform CodeQL Analysis 38 | uses: github/codeql-action/analyze@v1 39 | 40 | - name: Generate coverage file 41 | run: |- 42 | cd build 43 | lcov --capture --directory . --output-file coverage.info 44 | lcov --remove coverage.info '/usr/*' --output-file coverage.info 45 | lcov --list coverage.info 46 | # curl -s https://codecov.io/bash | bash -s - -f coverage.info -t ${{ secrets.CODECOV_TOKEN }} 47 | 48 | - name: Upload coverage to Codecov 49 | uses: codecov/codecov-action@v1 50 | with: 51 | token: ${{ secrets.CODECOV_TOKEN }} 52 | file: build/coverage.info 53 | fail_ci_if_error: true 54 | 55 | - name: Free up space to allow docker build 56 | run: |- 57 | df -h 58 | sudo apt-get purge -y gcc g++ build-essential 59 | sudo apt-get autoremove -y --purge 60 | df -h 61 | 62 | - name: Docker build and push 63 | uses: docker/build-push-action@v1 64 | with: 65 | username: ${{ secrets.DOCKERHUB_USERNAME }} 66 | password: ${{ secrets.DOCKERHUB_PASSWORD }} 67 | repository: dnsgt/groot 68 | tags: latest 69 | 70 | # Requires password and not the personal access token 71 | # - name: Docker Hub Description 72 | # uses: peter-evans/dockerhub-description@v2 73 | # env: 74 | # DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} 75 | # DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} 76 | # DOCKERHUB_REPOSITORY: dnsgt/groot 77 | 78 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | [Aa][Rr][Mm]/ 24 | [Aa][Rr][Mm]64/ 25 | bld/ 26 | [Bb]in/ 27 | [Oo]bj/ 28 | [Ll]og/ 29 | 30 | # Visual Studio 2015/2017 cache/options directory 31 | .vs/ 32 | # Uncomment if you have tasks that create the project's static files in wwwroot 33 | #wwwroot/ 34 | 35 | # Visual Studio 2017 auto generated files 36 | Generated\ Files/ 37 | 38 | # MSTest test Results 39 | [Tt]est[Rr]esult*/ 40 | [Bb]uild[Ll]og.* 41 | 42 | # NUNIT 43 | *.VisualState.xml 44 | TestResult.xml 45 | 46 | # Build Results of an ATL Project 47 | [Dd]ebugPS/ 48 | [Rr]eleasePS/ 49 | dlldata.c 50 | 51 | # Benchmark Results 52 | BenchmarkDotNet.Artifacts/ 53 | 54 | # .NET Core 55 | project.lock.json 56 | project.fragment.lock.json 57 | artifacts/ 58 | 59 | # StyleCop 60 | StyleCopReport.xml 61 | 62 | # Files built by Visual Studio 63 | *_i.c 64 | *_p.c 65 | *_h.h 66 | *.ilk 67 | *.meta 68 | *.obj 69 | *.iobj 70 | *.pch 71 | *.pdb 72 | *.ipdb 73 | *.pgc 74 | *.pgd 75 | *.rsp 76 | *.sbr 77 | *.tlb 78 | *.tli 79 | *.tlh 80 | *.tmp 81 | *.tmp_proj 82 | *_wpftmp.csproj 83 | *.log 84 | *.vspscc 85 | *.vssscc 86 | .builds 87 | *.pidb 88 | *.svclog 89 | *.scc 90 | 91 | # Chutzpah Test files 92 | _Chutzpah* 93 | 94 | # Visual C++ cache files 95 | ipch/ 96 | *.aps 97 | *.ncb 98 | *.opendb 99 | *.opensdf 100 | *.sdf 101 | *.cachefile 102 | *.VC.db 103 | *.VC.VC.opendb 104 | 105 | # Visual Studio profiler 106 | *.psess 107 | *.vsp 108 | *.vspx 109 | *.sap 110 | 111 | # Visual Studio Trace Files 112 | *.e2e 113 | 114 | # TFS 2012 Local Workspace 115 | $tf/ 116 | 117 | # Guidance Automation Toolkit 118 | *.gpState 119 | 120 | # ReSharper is a .NET coding add-in 121 | _ReSharper*/ 122 | *.[Rr]e[Ss]harper 123 | *.DotSettings.user 124 | 125 | # JustCode is a .NET coding add-in 126 | .JustCode 127 | 128 | # TeamCity is a build add-in 129 | _TeamCity* 130 | 131 | # DotCover is a Code Coverage Tool 132 | *.dotCover 133 | 134 | # AxoCover is a Code Coverage Tool 135 | .axoCover/* 136 | !.axoCover/settings.json 137 | 138 | # Visual Studio code coverage results 139 | *.coverage 140 | *.coveragexml 141 | 142 | # NCrunch 143 | _NCrunch_* 144 | .*crunch*.local.xml 145 | nCrunchTemp_* 146 | 147 | # MightyMoose 148 | *.mm.* 149 | AutoTest.Net/ 150 | 151 | # Web workbench (sass) 152 | .sass-cache/ 153 | 154 | # Installshield output folder 155 | [Ee]xpress/ 156 | 157 | # DocProject is a documentation generator add-in 158 | DocProject/buildhelp/ 159 | DocProject/Help/*.HxT 160 | DocProject/Help/*.HxC 161 | DocProject/Help/*.hhc 162 | DocProject/Help/*.hhk 163 | DocProject/Help/*.hhp 164 | DocProject/Help/Html2 165 | DocProject/Help/html 166 | 167 | # Click-Once directory 168 | publish/ 169 | 170 | # Publish Web Output 171 | *.[Pp]ublish.xml 172 | *.azurePubxml 173 | # Note: Comment the next line if you want to checkin your web deploy settings, 174 | # but database connection strings (with potential passwords) will be unencrypted 175 | *.pubxml 176 | *.publishproj 177 | 178 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 179 | # checkin your Azure Web App publish settings, but sensitive information contained 180 | # in these scripts will be unencrypted 181 | PublishScripts/ 182 | 183 | # NuGet Packages 184 | *.nupkg 185 | # The packages folder can be ignored because of Package Restore 186 | **/[Pp]ackages/* 187 | # except build/, which is used as an MSBuild target. 188 | !**/[Pp]ackages/build/ 189 | # Uncomment if necessary however generally it will be regenerated when needed 190 | #!**/[Pp]ackages/repositories.config 191 | # NuGet v3's project.json files produces more ignorable files 192 | *.nuget.props 193 | *.nuget.targets 194 | 195 | # Microsoft Azure Build Output 196 | csx/ 197 | *.build.csdef 198 | 199 | # Microsoft Azure Emulator 200 | ecf/ 201 | rcf/ 202 | 203 | # Windows Store app package directories and files 204 | AppPackages/ 205 | BundleArtifacts/ 206 | Package.StoreAssociation.xml 207 | _pkginfo.txt 208 | *.appx 209 | 210 | # Visual Studio cache files 211 | # files ending in .cache can be ignored 212 | *.[Cc]ache 213 | # but keep track of directories ending in .cache 214 | !?*.[Cc]ache/ 215 | 216 | # Others 217 | ClientBin/ 218 | ~$* 219 | *~ 220 | *.dbmdl 221 | *.dbproj.schemaview 222 | *.jfm 223 | *.pfx 224 | *.publishsettings 225 | orleans.codegen.cs 226 | 227 | # Including strong name files can present a security risk 228 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 229 | #*.snk 230 | 231 | # Since there are multiple workflows, uncomment next line to ignore bower_components 232 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 233 | #bower_components/ 234 | 235 | # RIA/Silverlight projects 236 | Generated_Code/ 237 | 238 | # Backup & report files from converting an old project file 239 | # to a newer Visual Studio version. Backup files are not needed, 240 | # because we have git ;-) 241 | _UpgradeReport_Files/ 242 | Backup*/ 243 | UpgradeLog*.XML 244 | UpgradeLog*.htm 245 | ServiceFabricBackup/ 246 | *.rptproj.bak 247 | 248 | # SQL Server files 249 | *.mdf 250 | *.ldf 251 | *.ndf 252 | 253 | # Business Intelligence projects 254 | *.rdl.data 255 | *.bim.layout 256 | *.bim_*.settings 257 | *.rptproj.rsuser 258 | *- Backup*.rdl 259 | 260 | # Microsoft Fakes 261 | FakesAssemblies/ 262 | 263 | # GhostDoc plugin setting file 264 | *.GhostDoc.xml 265 | 266 | # Node.js Tools for Visual Studio 267 | .ntvs_analysis.dat 268 | node_modules/ 269 | 270 | # Visual Studio 6 build log 271 | *.plg 272 | 273 | # Visual Studio 6 workspace options file 274 | *.opt 275 | 276 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 277 | *.vbw 278 | 279 | # Visual Studio LightSwitch build output 280 | **/*.HTMLClient/GeneratedArtifacts 281 | **/*.DesktopClient/GeneratedArtifacts 282 | **/*.DesktopClient/ModelManifest.xml 283 | **/*.Server/GeneratedArtifacts 284 | **/*.Server/ModelManifest.xml 285 | _Pvt_Extensions 286 | 287 | # Paket dependency manager 288 | .paket/paket.exe 289 | paket-files/ 290 | 291 | # FAKE - F# Make 292 | .fake/ 293 | 294 | # JetBrains Rider 295 | .idea/ 296 | *.sln.iml 297 | 298 | # CodeRush personal settings 299 | .cr/personal 300 | 301 | # Python Tools for Visual Studio (PTVS) 302 | __pycache__/ 303 | *.pyc 304 | 305 | # Cake - Uncomment if you are using it 306 | # tools/** 307 | # !tools/packages.config 308 | 309 | # Tabs Studio 310 | *.tss 311 | 312 | # Telerik's JustMock configuration file 313 | *.jmconfig 314 | 315 | # BizTalk build output 316 | *.btp.cs 317 | *.btm.cs 318 | *.odx.cs 319 | *.xsd.cs 320 | 321 | # OpenCover UI analysis results 322 | OpenCover/ 323 | 324 | # Azure Stream Analytics local run output 325 | ASALocalRun/ 326 | 327 | # MSBuild Binary and Structured Log 328 | *.binlog 329 | 330 | # NVidia Nsight GPU debugger configuration file 331 | *.nvuser 332 | 333 | # MFractors (Xamarin productivity tool) working folder 334 | .mfractor/ 335 | 336 | # Local History for Visual Studio 337 | .localhistory/ 338 | 339 | # BeatPulse healthcheck temp database 340 | healthchecksdb 341 | *.diagsession 342 | *.dot 343 | *.png 344 | 345 | 346 | Data 347 | build 348 | !/bin 349 | /bin/log.txt 350 | output.json 351 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "concurrentqueue"] 2 | path = concurrentqueue 3 | url = https://github.com/cameron314/concurrentqueue 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10.2) 2 | 3 | # Refuse to build outside `build` 4 | if (NOT ("${CMAKE_CURRENT_BINARY_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}/build")) 5 | message(FATAL_ERROR "Please run `mkdir ${CMAKE_CURRENT_SOURCE_DIR}/build` and run `cmake ..` within it.") 6 | endif() 7 | 8 | set(CMAKE_TOOLCHAIN_FILE "$ENV{HOME}/vcpkg/scripts/buildsystems/vcpkg.cmake") 9 | 10 | project(groot CXX) 11 | 12 | # Code Coverage Configuration 13 | add_library(coverage_config INTERFACE) 14 | 15 | option(CODE_COVERAGE "Enable coverage reporting" OFF) 16 | if(CODE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") 17 | # Add required flags (GCC & LLVM/Clang) 18 | target_compile_options(coverage_config INTERFACE 19 | -O0 # no optimization 20 | -g # generate debug info 21 | --coverage # sets all required flags 22 | ) 23 | target_link_libraries(coverage_config INTERFACE gcov) 24 | message(STATUS "Flags added for coverage") 25 | if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13) 26 | target_link_options(coverage_config INTERFACE --coverage) 27 | else() 28 | target_link_libraries(coverage_config INTERFACE --coverage) 29 | endif() 30 | endif() 31 | 32 | add_subdirectory(src) 33 | 34 | option (BUILD_TESTING "Build the testing tree." OFF) 35 | if (BUILD_TESTING) 36 | enable_testing() 37 | add_subdirectory(test) 38 | else() 39 | add_subdirectory(bin) 40 | endif() -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | 3 | LABEL maintainer="sivakesava@cs.ucla.edu" 4 | 5 | ENV DEBIAN_FRONTEND=noninteractive 6 | 7 | RUN apt-get update && \ 8 | apt-get install sudo dos2unix 9 | 10 | ENV HOME /home/groot 11 | ENV INSIDE_DOCKER="yes" 12 | 13 | RUN adduser --disabled-password --home $HOME --shell /bin/bash --gecos '' groot && \ 14 | echo 'groot ALL=(ALL) NOPASSWD:ALL' >>/etc/sudoers && \ 15 | su groot 16 | 17 | USER groot 18 | WORKDIR $HOME 19 | 20 | COPY setup.sh setup.sh 21 | RUN sudo dos2unix setup.sh 22 | RUN bash setup.sh 23 | 24 | WORKDIR $HOME/groot 25 | 26 | RUN mkdir build &&\ 27 | cd build && \ 28 | cmake .. && \ 29 | cmake --build . 30 | 31 | CMD [ "bash" ] 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | 4 | Copyright (c) 2020 dns-groot 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | GRoot 2 | ========== 3 | 7 | [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?style=popout)](https://opensource.org/licenses/MIT) 8 |   9 | [![](https://img.shields.io/github/actions/workflow/status/dns-groot/groot/dockerimage.yml?logo=docker&style=popout&label=docker+image)](https://github.com/dns-groot/groot/actions?query=workflow%3A%22Codecov+and+Docker+Image+CI%22) 10 |   11 | 12 |   13 | [![codecov](https://codecov.io/gh/dns-groot/groot/branch/master/graph/badge.svg?style=popout)](https://codecov.io/gh/dns-groot/groot) 14 | 15 | 16 | GRoot is a static verification tool for DNS. GRoot consumes a collection of zone files along with a collection of user-defined properties and systematically checks if any input to DNS can lead to violation of the properties. 17 | 18 | --- 19 | 20 | [**Installation**](#installation) 21 |     |     22 | [Property Verification](#property-verification) 23 |  ·  24 | [Available Properties](#available-properties) 25 |     |     26 | [Citing GRoot](#citing-groot) 27 |  ·  28 | [License (MIT)](LICENSE) 29 | 30 | --- 31 | 32 | :page_with_curl: [SIGCOMM 2020](https://conferences.sigcomm.org/sigcomm/2020/) -- [GRoot: Proactive Verification of DNS Configurations](https://doi.org/10.1145/3387514.3405871) 33 | 34 | :trophy: [Best Student Paper Award](http://www.sigcomm.org/awards/student-award-recipients) 35 | 36 | :desktop_computer: [Slides and Talk](https://www.sivak.dev/projects/5-groot) 37 | 38 | 39 | ### Note 40 | We have updated the paper to handle empty non-terminals as per the RFCs properly. **[The updated paper is available here](https://sivakesava1.github.io/assets/pdf/sigcomm20_groot.pdf).** For more details, please check the GitHub issue [#11](https://github.com/dns-groot/groot/issues/11). 41 | 42 | ## Installation 43 | 44 | ### Using `docker` (recommended) 45 | 46 | _**Note:** The docker image may consume ~ 1.2 GB of disk space._ 47 | 48 | We recommend running GRoot within a docker container, 49 | since they have negligible performance overhead. 50 | (See [this report](http://domino.research.ibm.com/library/cyberdig.nsf/papers/0929052195DD819C85257D2300681E7B/$File/rc25482.pdf)) 51 | 52 | 0. [Get `docker` for your OS](https://docs.docker.com/install). 53 | 1. Pull our docker image[#](#note_1): `docker pull dnsgt/groot`. 54 | 2. Run a container over the image: `docker run -it dnsgt/groot`.
55 | This would give you a `bash` shell within groot directory. 56 | 57 | # Alternatively, you could also build the Docker image locally: 58 | 59 | ```bash 60 | docker build -t dnsgt/groot github.com/dns-groot/groot 61 | ``` 62 | Docker containers are isolated from the host system. 63 | Therefore, to run GRoot on zones files residing on the host system, 64 | you must first [bind mount] them while running the container: 65 | 66 | ```bash 67 | docker run -v ~/data:/home/groot/groot/shared -it dnsgt/groot 68 | ``` 69 | 70 | The `~/data` on the host system would then be accessible within the container at `~/groot/shared` (with read+write permissions). The executable would be located at `~/groot/build/bin/`. 71 | 72 | ### Manual Installation 73 | 74 |
75 | 76 | CLICK to reveal instructions 77 | 78 | #### Installation for Windows 79 | 1. Install [`vcpkg`](https://docs.microsoft.com/en-us/cpp/build/vcpkg?view=vs-2019) package manager to install dependecies. 80 | 2. Install the C++ libraries (64 bit versions) using: 81 | - .\vcpkg.exe install boost-serialization:x64-windows boost-flyweight:x64-windows boost-dynamic-bitset:x64-windows boost-graph:x64-windows boost-accumulators:x64-windows docopt:x64-windows nlohmann-json:x64-windows spdlog:x64-windows 82 | - .\vcpkg.exe integrate install 83 | 3. Clone the repository (with `--recurse-submodules`) and open the solution (groot.sln) using Visual studio. Set the platform to x64 and mode to Release. 84 | 4. Configure the project properties to use ISO C++17 Standard (std:c++17) for C++ language standard. 85 | 5. Set `groot` as `Set as Startup Project` using the solution explorer in the Visual Studio. Build the project using visual studio to generate the executable. The executable would be located at `~\groot\x64\Release\`. 86 | 87 | #### Installation for Ubuntu 18.04 or later 88 | 1. Follow the instructions mentioned in the `DockerFile` to natively install in Ubuntu 18.04 or later. 89 | 2. The executable would be located at `~/groot/build/bin/`. 90 | 91 |
92 | 93 | ## Property Verification 94 | Check for any violations of the input properties by invoking GRoot as: 95 | 96 | For docker (Ubuntu): 97 | ```bash 98 | ~/groot$ ./build/bin/groot test/TestFiles/cc.il.us/zone_files --jobs=test/TestFiles/cc.il.us/jobs.json --output=output.json 99 | ``` 100 | For Windows: 101 | ```bash 102 | ~\groot> .\x64\Release\groot.exe test\TestFiles\cc.il.us\zone_files --jobs=test\TestFiles\cc.il.us\jobs.json --output=output.json 103 | ``` 104 | GRoot outputs any violations to the `output.json` file. 105 | 106 | ### Flags 107 | User can log debugging messages to `log.txt` using `-l` and use `-v` flag to log more detailed information. Use `-s` flag to display the statistics of the zone files parsed and the execution time. To log zone file issues (missing glue records, multiple CNAME/DNAME records, duplicate records) separately in `lint.json`, use the `--lint` flag. 108 | 109 | ### Packaging zone files data 110 | GRoot expects all the required zone files to be available in the input directory along with a special file `metadata.json`. The `metadata.json` file has to be created by the user and has to list the file name and the name server from which that zone file was obtained. If the zone files for a domain are obtained from multiple name servers, make sure to give the files a distinct name and fill the metadata accordingly. The user also has to provide the root (top) name servers for his domain in the `metadata.json`. 111 | 112 |
113 | 114 | CLICK to reveal an examplemetadata.json 115 | 116 | ```json5 117 | { 118 | "TopNameServers" : ["us.illinois.net."], //List of top name servers as strings 119 | "ZoneFiles" : [ 120 | { 121 | "FileName": "cc.il.us..txt", //cc.il.us. zone file from us.illinois.net. name server 122 | "NameServer": "us.illinois.net." 123 | }, 124 | { 125 | "FileName": "richland.cc.il.us..txt", //richland.cc.il.us. zone file from ns1.richland.cc.il.us. name server 126 | "NameServer": "ns1.richland.cc.il.us.", 127 | "Origin": "richland.cc.il.us." // optional field to indicate the origin of the input zone file. 128 | }, 129 | { 130 | "FileName": "child.richland.cc.il.us..txt", //child.richland.cc.il.us. zone file from ns1.child.richland.cc.il.us. name server 131 | "NameServer": "ns1.child.richland.cc.il.us." 132 | }, 133 | { 134 | "FileName": "child.richland.cc.il.us.-2.txt", //child.richland.cc.il.us. zone file from ns2.child.richland.cc.il.us. name server 135 | "NameServer": "ns2.child.richland.cc.il.us." //for same domain (child.richland.cc.il.us.) as the last one but from a different name server 136 | } 137 | ] 138 | } 139 | ``` 140 |
141 | 142 | ### Inputting Jobs 143 | GRoot can currently verify properties shown below on the zone files and expects the input list in a `json` file format. A **job** verifies properties on a domain and optionally on all its subdomains. The input `json` file can have a list of jobs. GRoot verifies a default set of properties if no input file is provided. 144 | 145 |
146 | CLICK to reveal an example job 147 | 148 | ```json5 149 | [ 150 | { 151 | "Domain": "cc.il.us." // Name of the domain to check 152 | "SubDomain": true, //Whether to check the properties on all the subdomains also 153 | "Properties":[ 154 | { 155 | "PropertyName": "QueryRewrite", 156 | "Value": ["illinois.net." , "cc.il.us."] 157 | }, 158 | { 159 | "PropertyName": "Rewrites", 160 | "Value": 1 161 | }, 162 | { 163 | "PropertyName": "RewriteBlackholing" 164 | } 165 | ] 166 | } 167 | ] 168 | ``` 169 |
170 | 171 | #### Available Properties 172 |
173 | Delegation Consistency 174 | 175 | The parent and child zone files should have the same set of _NS_ and glue _A_ records for delegation. 176 | Input `json` format: 177 | ```json5 178 | { 179 | "PropertyName": "DelegationConsistency" 180 | } 181 | ``` 182 |
183 | 184 |
185 | Finding all aliases 186 | Lists all the input query names (aliases) that are eventually rewritten to one of the canonical names. 187 | 188 | Input `json` format: 189 | ```json5 190 | { 191 | "PropertyName": "AllAliases", 192 | "Value": ["gw1.richland.cc.il.us."] //List of canonical names 193 | } 194 | ``` 195 |
196 | 197 |
198 | Lame Delegation 199 | 200 | A name server that is authoritative for a zone should provide authoritative answers, otherwise it is a lame delegation. 201 | Input `json` format: 202 | ```json5 203 | { 204 | "PropertyName": "LameDelegation" 205 | } 206 | ``` 207 |
208 | 209 |
210 | Nameserver Contact 211 | 212 | The query should not contact any name server that is not a subdomain of the allowed set of domains for any execution in the DNS. 213 | Input `json` format: 214 | ```json5 215 | { 216 | "PropertyName": "NameserverContact", 217 | "Value": ["edu.", "net.", "cc.il.us."] //List of allowed domain suffixes 218 | } 219 | ``` 220 |
221 | 222 |
223 | Number of Hops 224 | 225 | The query should not go through more than _X_ number of hops for any execution in the DNS. 226 | Input `json` format: 227 | ```json5 228 | { 229 | "PropertyName": "Hops", 230 | "Value": 2 231 | } 232 | ``` 233 |
234 | 235 |
236 | Number of Rewrites 237 | 238 | The query should not be rewritten more than _X_ number of time for any execution in the DNS. 239 | Input `json` format: 240 | ```json5 241 | { 242 | "PropertyName": "Rewrites", 243 | "Value": 3 244 | } 245 | ``` 246 |
247 | 248 |
249 | Query Rewritting 250 | 251 | The query should not be rewritten to any domain that is not a subdomain of the allowed set of domains for any execution in the DNS. 252 | Input `json` format: 253 | ```json5 254 | { 255 | "PropertyName": "QueryRewrite", 256 | "Value": ["illinois.net." , "cc.il.us."] //List of allowed domain suffixes 257 | } 258 | ``` 259 |
260 | 261 |
262 | Response Consistency 263 | Different executions in DNS that might happen due to multiple name servers should result in the same answers. 264 | 265 | Input `json` format: 266 | ```json5 267 | { 268 | "PropertyName": "ResponseConsistency", 269 | "Types": ["A", "MX"] //Checks the consistency for only these types 270 | } 271 | ``` 272 |
273 | 274 |
275 | Response Returned 276 | Different executions in DNS that might happen due to multiple name servers should result in some non-empty response. 277 | 278 | Input `json` format: 279 | ```json5 280 | { 281 | "PropertyName": "ResponseReturned", 282 | "Types": ["CNAME", "A"] //Checks that some non-empty response is returned for these types 283 | } 284 | ``` 285 |
286 | 287 |
288 | Response Value 289 | Every execution in DNS should return an answer that matches the user input answer. 290 | 291 | Input `json` format: 292 | ```json5 293 | { 294 | "PropertyName": "ResponseValue", 295 | "Types": ["A"], 296 | "Value": ["64.107.104.4"] //The expected response 297 | 298 | } 299 | ``` 300 |
301 | 302 |
303 | Rewrite Blackholing 304 | 305 | If the query is rewritten for any execution in the DNS, then the new query's domain name should have at least one resource record. 306 | 307 | Input `json` format: 308 | ```json5 309 | { 310 | "PropertyName": "RewriteBlackholing" 311 | } 312 | ``` 313 |
314 | 315 |
316 | Structural Delegation Consistency 317 | 318 | The parent and child zone files should have the same set of _NS_ and glue _A_ records for delegation irrespective of whether the name server hosting the child zone is reachable from the top name servers. 319 | 320 | Input `json` format: 321 | ```json5 322 | { 323 | "PropertyName": "StructuralDelegationConsistency" 324 | } 325 | ``` 326 |
327 | 328 |
329 | Zero Time To Live 330 | 331 | The query should not return a resource record with zero TTL for the given types. 332 | Input `json` format: 333 | ```json5 334 | { 335 | "PropertyName": "ZeroTTL", 336 | "Types": ["A"] 337 | } 338 | ``` 339 |
340 | 341 |
342 | DNAME Substitution Check 343 | 344 | The query should not overflow the legal size for a domain name after DNAME rewrite. Records with CNAME target domain overflowing the legal size are ignored by the tool and are reported as issues during parsing itself. 345 | Input `json` format: 346 | ```json5 347 | { 348 | "PropertyName": "DNAMESubstitutionCheck" 349 | } 350 | ``` 351 |
352 | 353 | GRoot, by default, checks for cyclic zone dependency and other loops while verifying any of the above properties. 354 | 355 | ## Citing GRoot 356 | 357 | ``` 358 | @inproceedings{10.1145/3387514.3405871, 359 | author = {Kakarla, Siva Kesava Reddy and Beckett, Ryan and Arzani, Behnaz and Millstein, Todd and Varghese, George}, 360 | title = {GRoot: Proactive Verification of DNS Configurations}, 361 | year = {2020}, 362 | isbn = {9781450379557}, 363 | publisher = {Association for Computing Machinery}, 364 | address = {New York, NY, USA}, 365 | url = {https://doi.org/10.1145/3387514.3405871}, 366 | doi = {10.1145/3387514.3405871}, 367 | booktitle = {Proceedings of the Annual Conference of the ACM Special Interest Group on Data Communication on the 368 | Applications, Technologies, Architectures, and Protocols for Computer Communication}, 369 | pages = {310–328}, 370 | numpages = {19}, 371 | keywords = {Static Analysis, Verification, DNS, Formal Methods}, 372 | location = {Virtual Event, USA}, 373 | series = {SIGCOMM ’20} 374 | } 375 | ``` 376 | 377 | [docker-hub]: https://hub.docker.com/r/sivakesava/groot 378 | [bind mount]: https://docs.docker.com/storage/bind-mounts 379 | -------------------------------------------------------------------------------- /benchmark/properties.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Domain": ".", 4 | "SubDomain": false, 5 | "Properties":[ 6 | { 7 | "PropertyName": "DelegationConsistency" 8 | } 9 | ] 10 | } 11 | ] 12 | -------------------------------------------------------------------------------- /benchmark/zone_files/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "TopNameServers":[ 3 | "a.root-servers.net." 4 | ], 5 | "ZoneFiles":[ 6 | { 7 | "FileName": "root.txt", 8 | "NameServer": "a.root-servers.net." 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /benchmark/zone_files/root.txt: -------------------------------------------------------------------------------- 1 | . 86400 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2019092700 1800 900 604800 86400 2 | . 86400 IN RRSIG SOA 8 0 86400 20191010050000 20190927040000 59944 . jWBgKGyFbfky9qOOjSMdFTN3jcktyPwrsKUq0oZ6DnWZdvrU9xRTTKEOY11Roo/UX/KKWcpbYnBDizAUu6bpVsi7f3mK28bAoKwYNgxrtlQx6OzZnx9jedHZiEx6D4eM9IwSA4iaNudl0oRQ6wXCUDWvzo85PIAyX7xgRSB7qqptIe5JnGeHWuf91Lr/lZnyPmlHdKYS7Kr9f5l1SXUlq+C1HOL62mldHfsIYV/M9RSPSyO5NY1euMx9DCqFzgflK8+C8l42gsIVf2C6IO+fKcsucAepP97zQrnGFPRsBDhbqj/KPqZLwOfb4V41eJ7fSIcVTAuBO/QgxfB4lA5beA== 3 | . 518400 IN NS a.root-servers.net. 4 | . 518400 IN NS b.root-servers.net. 5 | . 518400 IN NS c.root-servers.net. 6 | . 518400 IN NS d.root-servers.net. 7 | . 518400 IN NS e.root-servers.net. 8 | . 518400 IN NS f.root-servers.net. 9 | . 518400 IN NS g.root-servers.net. 10 | . 518400 IN NS h.root-servers.net. 11 | . 518400 IN NS i.root-servers.net. 12 | . 518400 IN NS j.root-servers.net. 13 | . 518400 IN NS k.root-servers.net. 14 | . 518400 IN NS l.root-servers.net. 15 | . 518400 IN NS m.root-servers.net. 16 | . 518400 IN RRSIG NS 8 0 518400 20191010050000 20190927040000 59944 . jwYow4QyelYzgqHg1Rc7z8LNIjhyKq6/5VlKgYG5YrtB4HgLYTmfV7r4Cd2/HZXz2NXjyLymoGNi2QvKM5yDFN7WYURVyQidyI1zFgBPFFkdPKEoZPYuO8HSoyyXHvZ6kYHeVfzxqZHGEGAc4pht2PVJolF2KaWZ2h+vCJd2cu5cMhaeKPvXyvZ5kbi2IhEQFCk4UNGL+UhT1yYv4aQ0KhSincYsmUuwr47LDmfd5jOTMYLTqsobHhTwO8XT+xsinKPgZ65nmQ/aXcgxHzfUEyill5wol8O/hpy8xf6gVjEo5fnfqmQK1M/yObtWLgxgm/woHp/8wCl3Fq7JOEm66Q== 17 | . 86400 IN NSEC aaa. NS SOA RRSIG NSEC DNSKEY 18 | . 86400 IN RRSIG NSEC 8 0 86400 20191010050000 20190927040000 59944 . QfKAF7TIlNJIuMLy8b16qVMT45sfF5wrRd6C2G5GVptnTrimcdOMBE5KZpm5NITqrK2Ha8T3VE13DUvB9yHmyK5JrVt3vXe3FQfOtGHox3/mo/VhYAomZgvChaoZc8MseqcGCjf/iQAR9PljhUH/xI+Z3VrqUhe6Lv5vIKGA+Fn51Yi9E+xULAI3tlujFd4dl3CQ0YLtR6SEGZL3cPEQDTJ5g66vVdUuI2fZKO86w1U8ddtMQbEBYh8AmdllW4dEKAjdDYrTS9FSZ2WXkrsj5/ZIP/MRN0iMlHzl8kSVh0wK+AP2TEy3W0coQmCTRT9g65fEVIJj+rAtsbX4gcriaA== 19 | . 172800 IN DNSKEY 256 3 8 AwEAAbPwrxwtOMENWvblQbUFwBllR7ZtXsu9rg/LdyklKs9gU2GQTeOc59XjhuAPZ4WrT09z6YPL+vzIIJqnG3Hiru7hFUQ4pH0qsLNxrsuZrZYmXAKoVa9SXL1Ap0LygwrIugEk1G4v7Rk/Alt1jLUIE+ZymGtSEhIuGQdXrEmj3ffzXY13H42X4Ja3vJTn/WIQOXY7vwHXGDypSh9j0Tt0hknF1yVJCrIpfkhFWihMKNdMzMprD4bV+PDLRA5YSn3OPIeUnRn9qBUCN11LXQKb+W3Jg+m/5xQRQJzJ/qXgDh1+aN+Mc9AstP29Y/ZLFmF6cKtL2zoUMN5I5QymeSkJJzc= 20 | . 172800 IN DNSKEY 256 3 8 AwEAAcTQyaIe6nt3xSPOG2L/YfwBkOVTJN6mlnZ249O5Rtt3ZSRQHxQSW61AODYw6bvgxrrGq8eeOuenFjcSYgNAMcBYoEYYmKDW6e9EryW4ZaT/MCq+8Am06oR40xAA3fClOM6QjRcT85tP41Go946AicBGP8XOP/Aj1aI/oPRGzRnboUPUok/AzTNnW5npBU69+BuiIwYE7mQOiNBFePyvjQBdoiuYbmuD3Py0IyjlBxzZUXbqLsRL9gYFkCqeTY29Ik7usuzMTa+JRSLz6KGS5RSJ7CTSMjZg8aNaUbN2dvGhakJPh92HnLvMA3TefFgbKJphFNPA3BWSKLZ02cRWXqM= 21 | . 172800 IN DNSKEY 257 3 8 AwEAAaz/tAm8yTn4Mfeh5eyI96WSVexTBAvkMgJzkKTOiW1vkIbzxeF3+/4RgWOq7HrxRixHlFlExOLAJr5emLvN7SWXgnLh4+B5xQlNVz8Og8kvArMtNROxVQuCaSnIDdD5LKyWbRd2n9WGe2R8PzgCmr3EgVLrjyBxWezF0jLHwVN8efS3rCj/EWgvIWgb9tarpVUDK/b58Da+sqqls3eNbuv7pr+eoZG+SrDK6nWeL3c6H5Apxz7LjVc1uTIdsIXxuOLYA4/ilBmSVIzuDWfdRUfhHdY6+cn8HFRm+2hM8AnXGXws9555KrUB5qihylGa8subX2Nn6UwNR1AkUTV74bU= 22 | . 172800 IN RRSIG DNSKEY 8 0 172800 20191010000000 20190919000000 20326 . OcVKz5iMycVJP8n4f3IAAYG3AZFS3nh4t6nxMC2Jxg5uk2MyAlFUvAdvclTs15S2D9FP7aL+uQ9JaPSAaMv7opp8tOo5X5qEJjpaHTwXWjSgFeUMGhp2rtdCR1aTeIKlLd6g3JthDpEWV0ip6VQKqLNOYx7gnaQc3j4SzK1q1YyjX/caO7m5We14vJNx0bmp4K/+U6SyKYuIu38IsHPUMbBO624MpRqW0etqcT3WiYCgGgFUTfYbr6aD4YSQPDAjII4N0yPJrBdDvbo2a3Nzvn2edq2zxRinnwWcqAqoymhZzr+hg7CTaLftqq2vTEXAtHSFk8JhLSlmciNm1S1xiA== 23 | aaa. 172800 IN NS ns1.dns.nic.aaa. 24 | aaa. 172800 IN NS ns2.dns.nic.aaa. 25 | aaa. 172800 IN NS ns3.dns.nic.aaa. 26 | aaa. 172800 IN NS ns4.dns.nic.aaa. 27 | aaa. 172800 IN NS ns5.dns.nic.aaa. 28 | aaa. 172800 IN NS ns6.dns.nic.aaa. 29 | aaa. 86400 IN DS 21707 8 1 6D92DD0D0DB0E392FA9D5F08EA15BBD297B8CBE2 30 | aaa. 86400 IN DS 21707 8 2 4F74856F31B73F3BFCDF430985329F55AA655BC9E53C4BF9DC6B14CCE6780600 31 | aaa. 86400 IN DS 28192 8 1 563200F63B8B1797B4D88D14BD6A672EA4D0CC0C 32 | aaa. 86400 IN DS 28192 8 2 DCB5AA6EC2B73D3E8C82D481770151160B38BCF2DBF3B9CD587AAD388D3572D7 33 | aaa. 86400 IN RRSIG DS 8 1 86400 20191010050000 20190927040000 59944 . OIPRwWfQzgp7nO115JZe97AUa17paARlwpyYIiX8LSDeBwDoUbUFEHzjvKLuaC0Kabc4VR7MC4X9dg2NylzNevBTfE/pESGpkkweRqSXiY8N3lSBSEtNRAIang0j3u/sCZf3A85XessdOEyuwe+p16XfEVHGkbpWg+ZRaw9xrySNp5+6JI2a9rhA+/im8pSdDk0oc/nPGqfKWiHh6yus5R9/5FOhPlEtmxSKEQ0uYtbt8gdmY7OWoWG1uN4lKqULluoMCP1DjQ9ZczwA7O8OqozncOG78hmyULXsv3/S083OXmuhFqR7XBRWAFBsGIvgG4ia0mBSAaanQf+iL3Ci9w== 34 | aaa. 86400 IN NSEC aarp. NS DS RRSIG NSEC 35 | aaa. 86400 IN RRSIG NSEC 8 1 86400 20191010050000 20190927040000 59944 . oAwUIQxU1EGDROXfDtsVKwPnfgSbk4Rz78+D0JdAMfTqCZG5RaRsWdnzACUcYc3z072RmBPfF6/Hg4bsUfiNWYt4wXWrmss9DvNZB7ZSBn+dLWisYVZ4BvToHyv22rNDUOgZnwn1CvH0TG9t7LYiDFmUhLmG1QxZBg39A8HOfjG+96yewinGY2032FmaEhRiAF5IkC+8LDWu+CRqJ/IwbY17pkiq8grSkuYbC26fTgjg1rkkRhubIEa9OzOZ6tnjioPRTB71njQ+m9QIfp5QxuhavQ59ylN/DGrjHK2jraEFeBleCO8QxMVB181tQlR9Sx+CJWzSZe2pptry9QZsCQ== 36 | ns1.dns.nic.aaa. 172800 IN A 156.154.144.2 37 | ns1.dns.nic.aaa. 172800 IN AAAA 2610:a1:1071:0:0:0:0:2 38 | ns2.dns.nic.aaa. 172800 IN A 156.154.145.2 39 | ns2.dns.nic.aaa. 172800 IN AAAA 2610:a1:1072:0:0:0:0:2 40 | ns3.dns.nic.aaa. 172800 IN A 156.154.159.2 41 | ns3.dns.nic.aaa. 172800 IN AAAA 2610:a1:1073:0:0:0:0:2 42 | ns4.dns.nic.aaa. 172800 IN A 156.154.156.2 43 | ns4.dns.nic.aaa. 172800 IN AAAA 2610:a1:1074:0:0:0:0:2 44 | ns5.dns.nic.aaa. 172800 IN A 156.154.157.2 45 | ns5.dns.nic.aaa. 172800 IN AAAA 2610:a1:1075:0:0:0:0:2 46 | ns6.dns.nic.aaa. 172800 IN A 156.154.158.2 47 | ns6.dns.nic.aaa. 172800 IN AAAA 2610:a1:1076:0:0:0:0:2 48 | aarp. 172800 IN NS ac1.nstld.com. 49 | aarp. 172800 IN NS ac2.nstld.com. 50 | aarp. 172800 IN NS ac3.nstld.com. 51 | aarp. 172800 IN NS ac4.nstld.com. 52 | aarp. 86400 IN DS 5751 8 2 7E8A14AB8F85009B9F19859815FA695954233FD9DAA6AB359044D12621A77E9F 53 | aarp. 86400 IN RRSIG DS 8 1 86400 20191010050000 20190927040000 59944 . lynI0TF1hj+Mg5CB1MN32al6yHTM0cBS6UnDOv6noz0gSlm5Qk4UeBkV3uEtFnYEBEBvtJ7AbB9RZFf3+bvn8PRB2kurcaPLdM5bE1Za7bXrnT1WW2KHXic8zrhycqPcEi/0cNtDtCp0r42EH0v2GT8MPKY9Y+GlnTrjj3mwzAZ1mWs63p8SkS4V9x2j2a7TWfUBdA6GpItU8jB4RiUwIB1h5fNucC7I8ByCdxn1AlcWLCY55aCiOe88pudjr+SLFcL/rtuVvFNE+fra2TOuF9k7rZRKrFa6MmggHGUUimUbJK/ysQbV4yn0vLx8/c94HKSW/4PL+H321W2VFdwZ8Q== 54 | aarp. 86400 IN NSEC abarth. NS DS RRSIG NSEC 55 | aarp. 86400 IN RRSIG NSEC 8 1 86400 20191010050000 20190927040000 59944 . SBl7u63udaJKwiwNsb31MzBaRQLLMLvDGO/B4anKpMZqt0WzeJeIHmacWMy+P/tf78KAz7B0SHCMRkZ9IxllY0719X01oIspFGyKXQYvot93hz0z8bl9pKzGhmGlWaY5ZBan9HXHwKRlZpvOLWLLrJ/zvyhL1vQ1QW5ygqVpXG+Ss59lqaW4QrGa7Eyer7Y4Fzaro39OSFnFSw3hODBmICtpM5SwBMzbEIkrPaf9f0zCGMJ/1mJH4zx/+mA3wFS1yqQ1RaQ8nx8d3fpGYBHoodRrFGdQiRjs5qUrdNe/GRnVSPicE9/fjKo8X3+37u7RoC5kOhsNBULcVTxNA1TSgQ== 56 | abarth. 172800 IN NS a0.nic.abarth. 57 | abarth. 172800 IN NS a2.nic.abarth. 58 | abarth. 172800 IN NS b0.nic.abarth. 59 | abarth. 172800 IN NS c0.nic.abarth. 60 | abarth. 86400 IN DS 3648 7 1 BBE522E3F7151A144522BF4E5BFC2D4E503727E3 61 | abarth. 86400 IN DS 3648 7 2 AC305C0759443E2E43A06FC9AF1004EA466D21879B19FBBC35F6D752F792FA35 62 | abarth. 86400 IN RRSIG DS 8 1 86400 20191010050000 20190927040000 59944 . ejGi3scHEVegZtOZwcwGCxhA/+tEIpER9evNJsSzI68hm35TNUMJtWUuXDiRfZxJFyXp5ZDdMnTAMAXKcDLLStLOd9KMOS4xuifeksXiURtYDFCtlfcO+ESs07wJ8DmOuSNGZ5MlEClxq48v/b7w0Jhdj+u7Z9s7k1GpKVIQJfrGh01VlEXskg9lMT06z3Ep0kJ3j/EY9Bl8zekhlrOYY2xNTXeP1/2SL/6teoe1FD1JFgPGXyMiQDQEVaFP+cEZuWiTMoL0oR+LFX1bSq/6qYtyNvSltrukkdVHpLDlafsVqbtTwOgNboCV7b/goJzFJktBjM2fzYp80efVik/beA== 63 | abarth. 86400 IN NSEC abb. NS DS RRSIG NSEC 64 | abarth. 86400 IN RRSIG NSEC 8 1 86400 20191010050000 20190927040000 59944 . MEyiseMqlV4hX1LZ5IKzkFpjGytMfml0RKhcJdSjYtPX94CfGQMxx7XOQwVIytxITfSTeMG5YPotzFvbdtnfD8DFV01PKN8eUjOAnuY2/Kw1Srt3kVbw8rZtTPRC+7FYFGUEiDhCS/xMBzyiz/b6v77vXioD3GKVTI3o3mJ865iTnzQZ9Jc2qKY3OcrBLv7701lsrjHATGJ4jiJjvXvG6QX+lwJtaX9XZoyHJYCjJJzbOSl2e31Ojy38DrvejPuzO1qMK1vN5+gcn1mqwsBh4duS2ks5+9pwKmDMu2eF7ZWjVqClt90JxIzKTbbzIVS7rliK3KC/4XsWOux7MwIreQ== 65 | a0.nic.abarth. 172800 IN A 65.22.24.17 66 | a0.nic.abarth. 172800 IN AAAA 2a01:8840:1a:0:0:0:0:17 67 | a2.nic.abarth. 172800 IN A 65.22.27.17 68 | a2.nic.abarth. 172800 IN AAAA 2a01:8840:1d:0:0:0:0:17 69 | b0.nic.abarth. 172800 IN A 65.22.25.17 70 | b0.nic.abarth. 172800 IN AAAA 2a01:8840:1b:0:0:0:0:17 71 | c0.nic.abarth. 172800 IN A 65.22.26.17 72 | c0.nic.abarth. 172800 IN AAAA 2a01:8840:1c:0:0:0:0:17 73 | abb. 172800 IN NS ac1.nstld.com. 74 | abb. 172800 IN NS ac2.nstld.com. 75 | abb. 172800 IN NS ac3.nstld.com. 76 | abb. 172800 IN NS ac4.nstld.com. -------------------------------------------------------------------------------- /bin/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10.2) 2 | 3 | if(NOT TARGET libgroot) 4 | message(FATAL_ERROR "Please run CMake at the repository root and then try `make groot`") 5 | endif() 6 | 7 | set(CMAKE_TOOLCHAIN_FILE "$ENV{HOME}/vcpkg/scripts/buildsystems/vcpkg.cmake") 8 | 9 | project(groot_bin CXX) 10 | 11 | find_package(Boost COMPONENTS regex filesystem REQUIRED) 12 | find_package(docopt CONFIG REQUIRED) 13 | find_package(nlohmann_json CONFIG REQUIRED) 14 | find_package(spdlog CONFIG REQUIRED) 15 | 16 | # specify the C++ standard 17 | set(CMAKE_CXX_STANDARD 17) 18 | set(CMAKE_CXX_STANDARD_REQUIRED True) 19 | 20 | #set ( PROJECT_LINK_LIBS libgroot.a ) 21 | #link_directories("${CMAKE_CURRENT_SOURCE_DIR}/../build/") 22 | 23 | include_directories(${Boost_INCLUDE_DIRS}) 24 | add_executable(groot groot.cpp) 25 | 26 | target_link_libraries(groot PRIVATE ${Boost_LIBRARIES} 27 | docopt_s nlohmann_json spdlog::spdlog 28 | libgroot) 29 | -------------------------------------------------------------------------------- /bin/groot.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "../src/driver.h" 10 | 11 | using namespace std::chrono; 12 | 13 | void Main(string directory, string jobs_file, string output_file, bool lint) 14 | { 15 | 16 | Logger->debug("groot.cpp - Main function called"); 17 | Driver driver; 18 | 19 | high_resolution_clock::time_point t1 = high_resolution_clock::now(); 20 | 21 | std::ifstream metadataFile( 22 | (boost::filesystem::path{directory} / boost::filesystem::path{"metadata.json"}).string()); 23 | json metadata; 24 | metadataFile >> metadata; 25 | Logger->debug("groot.cpp (Main) - Successfully read metadata.json file"); 26 | 27 | driver.SetContext(metadata, directory, lint); 28 | 29 | high_resolution_clock::time_point t2 = high_resolution_clock::now(); 30 | duration time_span = duration_cast>(t2 - t1); 31 | Logger->debug("groot.cpp (Main) - Label graph and Zone graphs built"); 32 | Logger->info(fmt::format("Time to build label graph and zone graphs: {}s", time_span.count())); 33 | 34 | long total_ecs = 0; 35 | 36 | if (jobs_file.length()) { 37 | std::ifstream i(jobs_file); 38 | json jobs; 39 | i >> jobs; 40 | 41 | Logger->debug("groot.cpp (Main) - Successfully read jobs.json file"); 42 | 43 | for (auto &user_job : jobs) { 44 | driver.SetJob(user_job); 45 | Logger->info(fmt::format( 46 | "groot.cpp (Main) - Started property checking for the job- {}", string(user_job["Domain"]))); 47 | driver.GenerateECsAndCheckProperties(); 48 | total_ecs += driver.GetECCountForCurrentJob(); 49 | driver.WriteStatsForAJob(); 50 | Logger->info(fmt::format( 51 | "groot.cpp (Main) - Finished property checking for the job- {}", string(user_job["Domain"]))); 52 | } 53 | } else { 54 | string x = "."; 55 | driver.SetJob(x); 56 | Logger->info(fmt::format("groot.cpp (Main) - Started default property checking for the job")); 57 | driver.GenerateECsAndCheckProperties(); 58 | total_ecs += driver.GetECCountForCurrentJob(); 59 | driver.WriteStatsForAJob(); 60 | Logger->info(fmt::format("groot.cpp (Main) - Finished default property checking for the job")); 61 | } 62 | t2 = high_resolution_clock::now(); 63 | time_span = duration_cast>(t2 - t1); 64 | Logger->info(fmt::format("Time to check all user jobs: {}s", time_span.count())); 65 | Logger->info(fmt::format("Total number of ECs across all jobs: {}", total_ecs)); 66 | driver.WriteViolationsToFile(output_file); 67 | } 68 | 69 | static const char USAGE[] = 70 | R"(groot 1.0 71 | 72 | Groot is a static verification tool for DNS. Groot consumes 73 | a collection of zone files along with a collection of user- 74 | defined properties and systematically checks if any input to 75 | DNS can lead to a property violation for the properties. 76 | 77 | Usage: groot [--jobs=] [-hlsv] [--lint] [--output=] 78 | 79 | Options: 80 | -h --help Show this help screen. 81 | -l --log Generate the log file - "log.txt". 82 | -s --stats Print statistics about the current run. 83 | -v --verbose Print more information to the log file. 84 | --lint Log zone file sanity check warnings separately in "lint.txt". 85 | --version Show groot version. 86 | )"; 87 | 88 | int main(int argc, const char **argv) 89 | { 90 | try { 91 | auto args = docopt::docopt(USAGE, {argv + 1, argv + argc}, true, "groot 1.0"); 92 | 93 | /* for (auto const& arg : args) { 94 | std::cout << arg.first << arg.second << std::endl; 95 | }*/ 96 | spdlog::init_thread_pool(8192, 1); 97 | 98 | auto stdout_sink = std::make_shared(); 99 | if (args.find("--stats")->second.asBool()) { 100 | stdout_sink->set_level(spdlog::level::info); 101 | } else { 102 | stdout_sink->set_level(spdlog::level::warn); 103 | } 104 | stdout_sink->set_pattern("[%x %H:%M:%S.%e] [thread %t] [%^%=7l%$] %v"); 105 | 106 | std::vector sinks{stdout_sink}; 107 | 108 | if (args.find("--log")->second.asBool()) { 109 | auto file_sink = std::make_shared("log.txt", true); 110 | file_sink->set_level(spdlog::level::trace); 111 | file_sink->set_pattern("[%x %H:%M:%S.%e] [thread %t] [%^%=7l%$] %v"); 112 | sinks.push_back(file_sink); 113 | } 114 | 115 | auto logger = std::make_shared( 116 | "my_custom_logger", sinks.begin(), sinks.end(), spdlog::thread_pool(), 117 | spdlog::async_overflow_policy::block); 118 | // auto logger = std::make_shared("my_custom_logger", sinks.begin(), sinks.end()); 119 | logger->flush_on(spdlog::level::trace); 120 | 121 | bool verbose = args.find("--verbose")->second.asBool(); 122 | if (verbose) { 123 | logger->set_level(spdlog::level::trace); 124 | } else { 125 | logger->set_level(spdlog::level::debug); 126 | } 127 | spdlog::register_logger(logger); 128 | 129 | Logger->bind(spdlog::get("my_custom_logger")); 130 | 131 | string zone_directory; 132 | string jobs_file; 133 | auto z = args.find(""); 134 | if (!z->second) { 135 | Logger->critical(fmt::format("groot.cpp (main) - missing parameter ")); 136 | cout << USAGE[0]; 137 | exit(EXIT_FAILURE); 138 | } else { 139 | zone_directory = z->second.asString(); 140 | } 141 | 142 | auto p = args.find("--jobs"); 143 | if (p->second) { 144 | jobs_file = p->second.asString(); 145 | } 146 | 147 | p = args.find("--output"); 148 | string output_file = "output.json"; 149 | if (p->second) { 150 | output_file = p->second.asString(); 151 | } 152 | 153 | p = args.find("--lint"); 154 | if (p->second.asBool()) { 155 | fstream fs; 156 | fs.open("lint.json", ios::out); 157 | fs << "[\n"; 158 | fs.close(); 159 | } 160 | 161 | // TODO: validate that the directory and property files exist 162 | Main(zone_directory, jobs_file, output_file, p->second.asBool()); 163 | Logger->debug("groot.cpp (main) - Finished checking all jobs"); 164 | spdlog::shutdown(); 165 | 166 | if (p->second.asBool()) { 167 | fstream fs; 168 | fs.open("lint.json", ios::app); 169 | fs << "\n]"; 170 | fs.close(); 171 | } 172 | return 0; 173 | } catch (exception &e) { 174 | cout << "Exception:- " << e.what() << endl; 175 | spdlog::shutdown(); 176 | } 177 | } -------------------------------------------------------------------------------- /bin/groot.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {87121386-9CBC-4701-9985-C3353B67FFA9} 24 | Win32Proj 25 | groot 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | true 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | 85 | 86 | 87 | 88 | 89 | Level3 90 | Disabled 91 | true 92 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 93 | true 94 | stdcpp17 95 | 4996 96 | 97 | 98 | Console 99 | true 100 | 101 | 102 | 103 | 104 | 105 | 106 | Level3 107 | Disabled 108 | true 109 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 110 | true 111 | 112 | 113 | Console 114 | true 115 | 116 | 117 | 118 | 119 | 120 | 121 | Level3 122 | MaxSpeed 123 | true 124 | true 125 | true 126 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 127 | true 128 | 129 | 130 | Console 131 | true 132 | true 133 | true 134 | 135 | 136 | 137 | 138 | 139 | 140 | Level3 141 | MaxSpeed 142 | true 143 | true 144 | true 145 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 146 | true 147 | stdcpp17 148 | 149 | 150 | Console 151 | true 152 | true 153 | true 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | {d2a89e18-94e6-474f-b0eb-f0881a5478b1} 162 | 163 | 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /bin/groot.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /groot.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29102.190 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libgroot", "src\libgroot.vcxproj", "{D2A89E18-94E6-474F-B0EB-F0881A5478B1}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test\test.vcxproj", "{BD35F99A-458A-4D58-8F11-3A0222979FFF}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "groot", "bin\groot.vcxproj", "{87121386-9CBC-4701-9985-C3353B67FFA9}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|x64 = Debug|x64 15 | Debug|x86 = Debug|x86 16 | Release|x64 = Release|x64 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {D2A89E18-94E6-474F-B0EB-F0881A5478B1}.Debug|x64.ActiveCfg = Debug|x64 21 | {D2A89E18-94E6-474F-B0EB-F0881A5478B1}.Debug|x64.Build.0 = Debug|x64 22 | {D2A89E18-94E6-474F-B0EB-F0881A5478B1}.Debug|x86.ActiveCfg = Debug|Win32 23 | {D2A89E18-94E6-474F-B0EB-F0881A5478B1}.Debug|x86.Build.0 = Debug|Win32 24 | {D2A89E18-94E6-474F-B0EB-F0881A5478B1}.Release|x64.ActiveCfg = Release|x64 25 | {D2A89E18-94E6-474F-B0EB-F0881A5478B1}.Release|x64.Build.0 = Release|x64 26 | {D2A89E18-94E6-474F-B0EB-F0881A5478B1}.Release|x86.ActiveCfg = Release|Win32 27 | {D2A89E18-94E6-474F-B0EB-F0881A5478B1}.Release|x86.Build.0 = Release|Win32 28 | {BD35F99A-458A-4D58-8F11-3A0222979FFF}.Debug|x64.ActiveCfg = Debug|x64 29 | {BD35F99A-458A-4D58-8F11-3A0222979FFF}.Debug|x64.Build.0 = Debug|x64 30 | {BD35F99A-458A-4D58-8F11-3A0222979FFF}.Debug|x86.ActiveCfg = Debug|Win32 31 | {BD35F99A-458A-4D58-8F11-3A0222979FFF}.Debug|x86.Build.0 = Debug|Win32 32 | {BD35F99A-458A-4D58-8F11-3A0222979FFF}.Release|x64.ActiveCfg = Release|x64 33 | {BD35F99A-458A-4D58-8F11-3A0222979FFF}.Release|x64.Build.0 = Release|x64 34 | {BD35F99A-458A-4D58-8F11-3A0222979FFF}.Release|x86.ActiveCfg = Release|Win32 35 | {BD35F99A-458A-4D58-8F11-3A0222979FFF}.Release|x86.Build.0 = Release|Win32 36 | {87121386-9CBC-4701-9985-C3353B67FFA9}.Debug|x64.ActiveCfg = Debug|x64 37 | {87121386-9CBC-4701-9985-C3353B67FFA9}.Debug|x64.Build.0 = Debug|x64 38 | {87121386-9CBC-4701-9985-C3353B67FFA9}.Debug|x86.ActiveCfg = Debug|Win32 39 | {87121386-9CBC-4701-9985-C3353B67FFA9}.Debug|x86.Build.0 = Debug|Win32 40 | {87121386-9CBC-4701-9985-C3353B67FFA9}.Release|x64.ActiveCfg = Release|x64 41 | {87121386-9CBC-4701-9985-C3353B67FFA9}.Release|x64.Build.0 = Release|x64 42 | {87121386-9CBC-4701-9985-C3353B67FFA9}.Release|x86.ActiveCfg = Release|Win32 43 | {87121386-9CBC-4701-9985-C3353B67FFA9}.Release|x86.Build.0 = Release|Win32 44 | EndGlobalSection 45 | GlobalSection(SolutionProperties) = preSolution 46 | HideSolutionNode = FALSE 47 | EndGlobalSection 48 | GlobalSection(ExtensibilityGlobals) = postSolution 49 | SolutionGuid = {464397B9-1AC8-4C80-8A00-D0585C5C038E} 50 | EndGlobalSection 51 | EndGlobal 52 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | export DEBIAN_FRONTEND=noninteractive 2 | 3 | sudo apt-get update 4 | [[ "$INSIDE_DOCKER" == "yes" ]] && sudo apt-get upgrade -yq 5 | sudo DEBIAN_FRONTEND="noninteractive" apt-get install -yq apt-utils\ 6 | binutils \ 7 | cmake curl \ 8 | g++ git \ 9 | libboost-all-dev \ 10 | patch \ 11 | pkg-config \ 12 | tar time \ 13 | unzip \ 14 | zip 15 | 16 | sudo apt-get autoremove -y --purge 17 | 18 | OLD_PWD="`pwd`" 19 | 20 | # install lcov and its dependecies if it is not for docker 21 | if [ "$INSIDE_DOCKER" != "yes" ]; then 22 | df -h 23 | sudo apt-get install build-essential libz-dev 24 | sudo cpan PerlIO::gzip 25 | sudo cpan JSON 26 | cd $HOME 27 | git clone https://github.com/linux-test-project/lcov.git 28 | cd lcov 29 | sudo make install 30 | df -h 31 | fi 32 | 33 | cd $HOME 34 | 35 | git clone https://github.com/Microsoft/vcpkg.git 36 | 37 | cd vcpkg 38 | 39 | ./bootstrap-vcpkg.sh 40 | ./vcpkg integrate install 41 | ./vcpkg install nlohmann-json docopt spdlog 42 | # ./vcpkg install boost-serialization boost-flyweight boost-dynamic-bitset boost-graph 43 | 44 | echo "Environment: 45 | 46 | cmake: `cmake --version` 47 | 48 | g++: `g++ --version` 49 | 50 | gcc: `gcc --version` 51 | 52 | gcov: `gcov --version` 53 | 54 | vcpkg: `./vcpkg list` 55 | " 56 | 57 | if [ "$INSIDE_DOCKER" == "yes" ]; then 58 | cd $HOME 59 | git clone --recurse-submodules https://github.com/dns-groot/groot.git 60 | cd groot 61 | else 62 | cd $OLD_PWD 63 | fi -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10.2) 2 | set(CMAKE_TOOLCHAIN_FILE "$ENV{HOME}/vcpkg/scripts/buildsystems/vcpkg.cmake") 3 | 4 | project(libgroot CXX) 5 | 6 | find_package(Boost REQUIRED) 7 | find_package(nlohmann_json CONFIG REQUIRED) 8 | find_package(spdlog CONFIG REQUIRED) 9 | 10 | set(CMAKE_BUILD_TYPE Release) 11 | 12 | # specify the C++ standard 13 | set(CMAKE_CXX_STANDARD 17) 14 | set(CMAKE_CXX_STANDARD_REQUIRED True) 15 | 16 | file(GLOB SOURCES "*.cpp") 17 | include_directories(${Boost_INCLUDE_DIRS}) 18 | 19 | add_library(libgroot STATIC ${SOURCES}) 20 | 21 | target_link_libraries(libgroot PRIVATE ${Boost_LIBRARIES} nlohmann_json spdlog::spdlog coverage_config) 22 | 23 | set_target_properties(libgroot PROPERTIES PREFIX "") 24 | -------------------------------------------------------------------------------- /src/context.h: -------------------------------------------------------------------------------- 1 | #ifndef CONTEXT_H 2 | #define CONTEXT_H 3 | 4 | #include "zone-graph.h" 5 | 6 | struct Context { 7 | boost::unordered_map> nameserver_zoneIds_map; 8 | boost::unordered_map zoneId_nameserver_map; 9 | std::vector top_nameservers; 10 | boost::unordered_map zoneId_to_zone; 11 | boost::unordered_map type_to_rr_count; 12 | int zoneId_counter_ = 0; 13 | }; 14 | 15 | #endif -------------------------------------------------------------------------------- /src/driver.h: -------------------------------------------------------------------------------- 1 | #ifndef DRIVER_H_ 2 | #define DRIVER_H_ 3 | 4 | #include 5 | 6 | #include "../concurrentqueue/concurrentqueue.h" 7 | 8 | #include "context.h" 9 | #include "equivalence-class.h" 10 | #include "interpretation-properties.h" 11 | #include "job.h" 12 | #include "label-graph.h" 13 | #include "zone-graph.h" 14 | 15 | using json = nlohmann::json; 16 | 17 | const int kECConsumerCount = 8; 18 | 19 | class Driver 20 | { 21 | 22 | private: 23 | label::Graph label_graph_; 24 | Context context_; 25 | Job current_job_; 26 | std::set property_violations_; 27 | int ParseZoneFileAndExtendGraphs(string, string, string, bool); 28 | // void DumpNameServerZoneMap() const; 29 | 30 | public: 31 | friend class DriverTest; 32 | void GenerateECsAndCheckProperties(); 33 | long GetECCountForCurrentJob() const; 34 | long SetContext(const json &, string, bool); 35 | void SetJob(const json &); 36 | void SetJob(string &); 37 | void WriteStatsForAJob(); 38 | void WriteViolationsToFile(string) const; 39 | }; 40 | 41 | #endif -------------------------------------------------------------------------------- /src/ec-task.cpp: -------------------------------------------------------------------------------- 1 | #include "ec-task.h" 2 | #include "job.h" 3 | 4 | string ECTask::PrintTaskType() 5 | { 6 | return "EC Task"; 7 | } 8 | 9 | void ECTask::Process(const Context &context, vector &variadic_arguments) 10 | { 11 | Job *current_job = boost::any_cast(variadic_arguments[0]); 12 | interpretation::Graph interpretation_graph_for_ec(ec_, context); 13 | interpretation_graph_for_ec.CheckForLoops(current_job->json_queue); 14 | // interpretation_graph_for_ec.GenerateDotFile("InterpretationGraph.dot"); 15 | current_job->attributes_queue.enqueue( 16 | {static_cast(num_vertices(interpretation_graph_for_ec)), 17 | static_cast(num_edges(interpretation_graph_for_ec))}); 18 | current_job->stats.ec_count++; 19 | interpretation_graph_for_ec.CheckPropertiesOnEC( 20 | current_job->path_functions, current_job->node_functions, current_job->json_queue); 21 | } 22 | -------------------------------------------------------------------------------- /src/ec-task.h: -------------------------------------------------------------------------------- 1 | #ifndef EC_TASK_CLASS_H 2 | #define EC_TASK_CLASS_H 3 | 4 | #include "task.h" 5 | 6 | class ECTask : public Task 7 | { 8 | 9 | public: 10 | EC ec_; 11 | string domain_name_; 12 | virtual string PrintTaskType(); 13 | virtual void Process(const Context &, vector &); 14 | }; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/equivalence-class.cpp: -------------------------------------------------------------------------------- 1 | #include "equivalence-class.h" 2 | #include "utils.h" 3 | 4 | string EC::ToString() const 5 | { 6 | string q = ""; 7 | if (excluded) { 8 | q += "~{ }."; 9 | } else { 10 | q += ""; 11 | } 12 | q += LabelUtils::LabelsToString(name); 13 | return q; 14 | } 15 | 16 | bool EC::operator==(const EC &q) const 17 | { 18 | if (name != q.name) { 19 | return false; 20 | } 21 | if (rrTypes != q.rrTypes) { 22 | return false; 23 | } 24 | if (excluded && !q.excluded) { 25 | return false; 26 | } 27 | if (!excluded && q.excluded) { 28 | return false; 29 | } 30 | return true; 31 | } 32 | -------------------------------------------------------------------------------- /src/equivalence-class.h: -------------------------------------------------------------------------------- 1 | #ifndef EQUIVALENCE_CLASS_H 2 | #define EQUIVALENCE_CLASS_H 3 | 4 | #include "resource-record.h" 5 | 6 | class EC 7 | { 8 | 9 | private: 10 | friend class boost::serialization::access; 11 | template void serialize(Archive &ar, const unsigned int version) 12 | { 13 | ar &name; 14 | ar &rrTypes; 15 | ar &excluded; 16 | } 17 | 18 | public: 19 | boost::optional> excluded; 20 | vector name; 21 | std::bitset rrTypes; 22 | bool nonExistent = false; 23 | 24 | string ToString() const; 25 | bool operator==(const EC &) const; 26 | }; 27 | 28 | #endif -------------------------------------------------------------------------------- /src/interpretation-properties.h: -------------------------------------------------------------------------------- 1 | #ifndef INTERPRETATION_PROPERTIES_H 2 | #define INTERPRETATION_PROPERTIES_H 3 | 4 | #include 5 | 6 | #include "../concurrentqueue/concurrentqueue.h" 7 | #include "context.h" 8 | #include "equivalence-class.h" 9 | #include "utils.h" 10 | #include "zone-graph.h" 11 | 12 | using json = nlohmann::json; 13 | 14 | namespace interpretation 15 | { 16 | 17 | struct Vertex { 18 | std::string ns; 19 | EC query; 20 | boost::optional> answer; 21 | 22 | private: 23 | friend class boost::serialization::access; 24 | template void serialize(Archive &ar, const unsigned int version) 25 | { 26 | ar &ns; 27 | ar &query; 28 | ar &answer; 29 | } 30 | }; 31 | 32 | struct Edge { 33 | boost::optional intermediate_query; 34 | 35 | private: 36 | friend class boost::serialization::access; 37 | template void serialize(Archive &ar, const unsigned int version) 38 | { 39 | ar &intermediate_query; 40 | } 41 | }; 42 | 43 | class Graph : public boost::adjacency_list 44 | { 45 | public: 46 | using VertexDescriptor = boost::graph_traits::vertex_descriptor; 47 | using EdgeDescriptor = boost::graph_traits::edge_descriptor; 48 | using Path = vector; 49 | using NodeFunction = 50 | std::function &, moodycamel::ConcurrentQueue &)>; 51 | using PathFunction = std::function &)>; 52 | using Attributes = std::tuple; 53 | 54 | private: 55 | template class VertexWriter 56 | { 57 | public: 58 | VertexWriter(NSMap ns, QueryMap q, AnswerMap a) : nsm(ns), qm(q), am(a) 59 | { 60 | } 61 | template void operator()(ostream &out, const Vertex &v) const; 62 | 63 | private: 64 | NSMap nsm; 65 | QueryMap qm; 66 | AnswerMap am; 67 | }; 68 | 69 | template 70 | inline VertexWriter MakeVertexWriter(NSMap ns, QueryMap q, AnswerMap a) const 71 | { 72 | return VertexWriter(ns, q, a); 73 | } 74 | 75 | template class EdgeWriter 76 | { 77 | public: 78 | EdgeWriter(EdgeMap w) : wm(w) 79 | { 80 | } 81 | template void operator()(ostream &out, const Edge &e) const; 82 | 83 | private: 84 | EdgeMap wm; 85 | }; 86 | 87 | template inline EdgeWriter MakeEdgeWriter(EdgeMap w) const 88 | { 89 | return EdgeWriter(w); 90 | } 91 | 92 | Graph(); 93 | VertexDescriptor root_ = 0; 94 | boost::unordered_map> nameserver_to_vertices_map_; 95 | 96 | void CheckCnameDnameAtSameNameserver(VertexDescriptor &, const EC, const Context &); 97 | bool CheckForLoops(VertexDescriptor, Path, moodycamel::ConcurrentQueue &) const; 98 | void EnumeratePathsAndReturnEndNodes( 99 | VertexDescriptor, 100 | vector &, 101 | Path, 102 | const vector &, 103 | moodycamel::ConcurrentQueue &) const; 104 | boost::optional InsertNode(string, EC, VertexDescriptor, boost::optional); 105 | boost::optional GetRelevantZone(string, const EC, const Context &) const; 106 | vector>> MatchNsGlueRecords(vector records) const; 107 | void NsSubRoutine(const VertexDescriptor &, const string &, boost::optional, const Context &); 108 | void PrettyPrintLoop(const VertexDescriptor &, Path, moodycamel::ConcurrentQueue &) const; 109 | EC ProcessCname(const ResourceRecord &, const EC) const; 110 | EC ProcessDname(const ResourceRecord &, const EC) const; 111 | void QueryResolver(const zone::Graph &, VertexDescriptor &, const Context &); 112 | VertexDescriptor SideQuery(const EC, const Context &); 113 | void StartFromTopNameservers(VertexDescriptor, const EC, const Context &); 114 | 115 | public: 116 | class Properties 117 | { 118 | 119 | private: 120 | static tuple, vector> GetNSGlueRecords(const vector &); 121 | static void PrettyPrintResponseValue( 122 | set, 123 | set &, 124 | const interpretation::Graph &, 125 | const VertexDescriptor &, 126 | json &); 127 | 128 | public: 129 | // End-node properties 130 | static void CheckResponseReturned( 131 | const interpretation::Graph &, 132 | const vector &, 133 | moodycamel::ConcurrentQueue &, 134 | std::bitset); 135 | static void CheckResponseValue( 136 | const interpretation::Graph &, 137 | const vector &, 138 | moodycamel::ConcurrentQueue &, 139 | std::bitset, 140 | set); 141 | static void CheckSameResponseReturned( 142 | const interpretation::Graph &, 143 | const vector &, 144 | moodycamel::ConcurrentQueue &, 145 | std::bitset); 146 | static void ZeroTTL( 147 | const interpretation::Graph &, 148 | const vector &, 149 | moodycamel::ConcurrentQueue &, 150 | std::bitset); 151 | 152 | // Path properties 153 | static void AllAliases( 154 | const interpretation::Graph &, 155 | const Path &, 156 | moodycamel::ConcurrentQueue &, 157 | vector>); 158 | static void CheckDelegationConsistency( 159 | const interpretation::Graph &, 160 | const Path &, 161 | moodycamel::ConcurrentQueue &); 162 | static void InfiniteDName( 163 | const interpretation::Graph &, 164 | const Path &, 165 | moodycamel::ConcurrentQueue &); 166 | static void CheckLameDelegation( 167 | const interpretation::Graph &, 168 | const Path &, 169 | moodycamel::ConcurrentQueue &); 170 | static void DNAMESubstitutionExceedesLength( 171 | const interpretation::Graph &, 172 | const Path &, 173 | moodycamel::ConcurrentQueue &); 174 | static void NameServerContact( 175 | const interpretation::Graph &, 176 | const Path &, 177 | moodycamel::ConcurrentQueue &, 178 | vector>); 179 | static void NumberOfHops(const interpretation::Graph &, const Path &, moodycamel::ConcurrentQueue &, int); 180 | static void NumberOfRewrites( 181 | const interpretation::Graph &, 182 | const Path &, 183 | moodycamel::ConcurrentQueue &, 184 | int); 185 | static void QueryRewrite( 186 | const interpretation::Graph &, 187 | const Path &, 188 | moodycamel::ConcurrentQueue &, 189 | vector>); 190 | static void RewriteBlackholing( 191 | const interpretation::Graph &, 192 | const Path &, 193 | moodycamel::ConcurrentQueue &); 194 | }; 195 | 196 | void CheckForLoops(moodycamel::ConcurrentQueue &) const; 197 | void CheckPropertiesOnEC( 198 | const vector &, 199 | const vector &, 200 | moodycamel::ConcurrentQueue &) const; 201 | void GenerateDotFile(const string) const; 202 | Graph(const EC, const Context &); 203 | }; 204 | } // namespace interpretation 205 | 206 | #endif -------------------------------------------------------------------------------- /src/job.h: -------------------------------------------------------------------------------- 1 | #ifndef JOB_H_ 2 | #define JOB_H_ 3 | 4 | #include "task.h" 5 | 6 | struct Stats { 7 | std::vector interpretation_vertices; 8 | std::vector interpretation_edges; 9 | std::atomic ec_count = 0; 10 | }; 11 | 12 | struct Job { 13 | moodycamel::ConcurrentQueue attributes_queue; 14 | bool check_subdomains = false; 15 | bool check_structural_delegations = false; 16 | moodycamel::ConcurrentQueue> ec_queue; 17 | std::atomic finished_ec_generation = false; 18 | moodycamel::ConcurrentQueue json_queue; 19 | vector node_functions; 20 | vector path_functions; 21 | Stats stats; 22 | std::bitset types_req; 23 | string user_input_domain; 24 | }; 25 | 26 | #endif -------------------------------------------------------------------------------- /src/label-graph.h: -------------------------------------------------------------------------------- 1 | #ifndef LABEL_GRAPH_H_ 2 | #define LABEL_GRAPH_H_ 3 | 4 | //#define BOOST_GRAPH_NO_BUNDLED_PROPERTIES 1 5 | 6 | #include "job.h" 7 | #include "my-logger.h" 8 | 9 | namespace label 10 | { 11 | 12 | struct Vertex { 13 | NodeLabel name; 14 | int16_t len = -1; 15 | std::bitset rrtypes_available; 16 | std::vector> zoneId_vertexId; 17 | 18 | private: 19 | friend class boost::serialization::access; 20 | template void serialize(Archive &ar, const unsigned int version) 21 | { 22 | ar &name; 23 | ar &len; 24 | ar &rrtypes_available; 25 | ar &zoneId_vertexId; 26 | } 27 | }; 28 | 29 | enum EdgeType { normal = 1, dname = 2 }; 30 | 31 | struct Edge { 32 | EdgeType type; 33 | 34 | private: 35 | friend class boost::serialization::access; 36 | template void serialize(Archive &ar, const unsigned int version) 37 | { 38 | ar &type; 39 | } 40 | }; 41 | 42 | class Graph : public boost::adjacency_list 43 | { 44 | public: 45 | using VertexDescriptor = boost::graph_traits::vertex_descriptor; 46 | using ClosestNode = std::pair; 47 | 48 | private: 49 | using EdgeDescriptor = boost::graph_traits::edge_descriptor; 50 | using VertexIterator = boost::graph_traits::vertex_iterator; 51 | using EdgeIterator = boost::graph_traits::edge_iterator; 52 | using LabelToVertex = boost::unordered_map; 53 | using ZoneIdGlueNSRecords = tuple>, vector>; 54 | 55 | template class VertexWriter 56 | { 57 | public: 58 | VertexWriter(VertexMap w) : wm(w) 59 | { 60 | } 61 | template void operator()(ostream &out, const Vertex &v) const 62 | { 63 | auto type = get(wm, v); 64 | out << "[label=\"" << type.get() << "\"]"; 65 | } 66 | 67 | private: 68 | VertexMap wm; 69 | }; 70 | 71 | template inline VertexWriter MakeVertexWriter(VertexMap w) 72 | { 73 | return VertexWriter(w); 74 | } 75 | 76 | template class EdgeWriter 77 | { 78 | public: 79 | EdgeWriter(EdgeMap w) : wm(w) 80 | { 81 | } 82 | template void operator()(ostream &out, const Edge &e) const 83 | { 84 | auto type = get(wm, e); 85 | if (type == normal) { 86 | out << "[color=black]"; 87 | } else { 88 | out << "[color=red]"; 89 | } 90 | } 91 | 92 | private: 93 | EdgeMap wm; 94 | }; 95 | 96 | template inline EdgeWriter MakeEdgeWriter(EdgeMap w) 97 | { 98 | return EdgeWriter(w); 99 | } 100 | 101 | boost::unordered_map vertex_to_child_map_; 102 | VertexDescriptor root_ = 0; 103 | 104 | VertexDescriptor AddNodes(VertexDescriptor, const vector &, int &); 105 | void CompareParentChildDelegationRecords( 106 | const std::vector &, 107 | const std::vector &, 108 | string, 109 | const Context &, 110 | Job &) const; 111 | void ConstructChildLabelsToVertexDescriptorMap(VertexDescriptor); 112 | void ConstructOutputNS( 113 | json &, 114 | const CommonSymDiff &, 115 | boost::optional, 116 | string, 117 | string, 118 | string, 119 | string) const; 120 | VertexDescriptor GetAncestor(VertexDescriptor, const vector &, vector &, int &index) 121 | const; 122 | // string GetHostingNameServer(int, const Context &) const; 123 | void NodeEC(const vector &name, Job &) const; 124 | vector SearchNode(VertexDescriptor, const vector &, int); 125 | void SubDomainECGeneration(VertexDescriptor, vector, bool, Job &, const Context &, bool); 126 | void WildcardChildEC(std::vector &, const vector &, int, Job &) const; 127 | 128 | public: 129 | void AddResourceRecord(const ResourceRecord &, const int &, zone::Graph::VertexDescriptor); 130 | void CheckStructuralDelegationConsistency(string, label::Graph::VertexDescriptor, const Context &, Job &); 131 | vector ClosestEnclosers(const vector &); 132 | vector ClosestEnclosers(const string &); 133 | void GenerateDotFile(string); 134 | void GenerateECs(Job &, const Context &); 135 | Graph(); 136 | }; 137 | } // namespace label 138 | 139 | #endif -------------------------------------------------------------------------------- /src/libgroot.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {D2A89E18-94E6-474F-B0EB-F0881A5478B1} 24 | Win32Proj 25 | libgroot 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | StaticLibrary 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | StaticLibrary 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | true 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | 85 | 86 | 87 | 88 | 89 | Level3 90 | Disabled 91 | true 92 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 93 | true 94 | 95 | 96 | Console 97 | true 98 | 99 | 100 | 101 | 102 | 103 | 104 | Level3 105 | Disabled 106 | true 107 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 108 | true 109 | stdcpp17 110 | 4996 111 | 112 | 113 | Console 114 | true 115 | 116 | 117 | 118 | 119 | 120 | 121 | Level3 122 | MaxSpeed 123 | true 124 | true 125 | true 126 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 127 | true 128 | 129 | 130 | Console 131 | true 132 | true 133 | true 134 | 135 | 136 | 137 | 138 | 139 | 140 | Level3 141 | MaxSpeed 142 | true 143 | true 144 | true 145 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 146 | true 147 | stdcpp17 148 | 149 | 150 | Console 151 | true 152 | true 153 | true 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | -------------------------------------------------------------------------------- /src/my-logger.h: -------------------------------------------------------------------------------- 1 | #ifndef MY_LOGGER_H_ 2 | #define MY_LOGGER_H_ 3 | 4 | #include 5 | 6 | #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE 7 | #include "spdlog/async.h" 8 | #include "spdlog/sinks/basic_file_sink.h" 9 | #include "spdlog/sinks/stdout_color_sinks.h" 10 | #include "spdlog/spdlog.h" 11 | 12 | using namespace std; 13 | 14 | class MyLogger 15 | { 16 | 17 | std::shared_ptr _logger; 18 | MyLogger() 19 | { 20 | } 21 | 22 | public: 23 | void bind(std::shared_ptr logger) 24 | { 25 | if (logger == nullptr) { 26 | throw nullptr; 27 | } 28 | getInstance()->_logger = logger; 29 | } 30 | static MyLogger *getInstance() 31 | { 32 | static MyLogger instance; 33 | return &instance; 34 | } 35 | void trace(std::string s) 36 | { 37 | if (_logger) { 38 | _logger->trace(s); 39 | } 40 | } 41 | void debug(std::string s) 42 | { 43 | if (_logger) { 44 | _logger->debug(s); 45 | } 46 | } 47 | void info(std::string s) 48 | { 49 | if (_logger != nullptr) { 50 | _logger->info(s); 51 | } 52 | } 53 | void warn(std::string s) 54 | { 55 | if (_logger) { 56 | _logger->warn(s); 57 | } 58 | } 59 | void error(std::string s) 60 | { 61 | if (_logger) { 62 | _logger->error(s); 63 | } 64 | } 65 | void critical(std::string s) 66 | { 67 | if (_logger) { 68 | _logger->critical(s); 69 | } 70 | } 71 | }; 72 | 73 | inline class MyLogger *Logger = MyLogger::getInstance(); 74 | 75 | //#define Logger MyLogger::getInstance() 76 | 77 | #endif -------------------------------------------------------------------------------- /src/node-label.cpp: -------------------------------------------------------------------------------- 1 | #include "node-label.h" 2 | 3 | std::string NodeLabel::get() const 4 | { 5 | return n.get(); 6 | } 7 | 8 | void NodeLabel::set(const std::string s) 9 | { 10 | n = s; 11 | } 12 | 13 | bool NodeLabel::operator==(const NodeLabel &nl) const 14 | { 15 | return nl.n == n; 16 | } 17 | 18 | std::size_t hash_value(const NodeLabel &nl) 19 | { 20 | boost::hash, boost::flyweights::no_tracking>> hasher; 21 | return hasher(nl.n); 22 | } 23 | -------------------------------------------------------------------------------- /src/node-label.h: -------------------------------------------------------------------------------- 1 | #ifndef NODE_LABEL_H_ 2 | #define NODE_LABEL_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "../concurrentqueue/concurrentqueue.h" 24 | #include "my-logger.h" 25 | 26 | using namespace std; 27 | using json = nlohmann::json; 28 | 29 | #define kHashMapThreshold 500 30 | #define kMaxLabelLength 63 31 | #define kMaxDomainLength 253 32 | 33 | struct Empty { 34 | }; 35 | 36 | struct NodeLabel { 37 | boost::flyweight, boost::flyweights::no_tracking> n; 38 | NodeLabel(const std::string s) : n{s} {}; 39 | NodeLabel() : n{""} {}; 40 | std::string get() const; 41 | void set(const std::string); 42 | bool operator==(const NodeLabel &) const; 43 | 44 | private: 45 | friend class boost::serialization::access; 46 | template void serialize(Archive &ar, const unsigned int version) 47 | { 48 | ar &n; 49 | } 50 | }; 51 | 52 | std::size_t hash_value(const NodeLabel &); 53 | 54 | #endif -------------------------------------------------------------------------------- /src/resource-record.cpp: -------------------------------------------------------------------------------- 1 | #include "resource-record.h" 2 | #include "utils.h" 3 | 4 | ResourceRecord::ResourceRecord(string name, string type, uint16_t class_, uint32_t ttl, string rdata) 5 | : name_(LabelUtils::StringToLabels(name)), type_(TypeUtils::StringToType(type)), class_(class_), ttl_(ttl), 6 | rdata_(rdata) 7 | { 8 | } 9 | 10 | bool ResourceRecord::operator==(const ResourceRecord &l1) const 11 | { 12 | if (name_ == l1.get_name() && rdata_ == l1.get_rdata() && type_ == l1.get_type()) { 13 | // ignoring ttl_ == l1.get_ttl() 14 | return true; 15 | } 16 | return false; 17 | } 18 | 19 | ostream &operator<<(ostream &os, const ResourceRecord &rr) 20 | { 21 | os << LabelUtils::LabelsToString(rr.name_) << '\t' << rr.type_ << '\t' << rr.rdata_ << endl; 22 | return os; 23 | } 24 | 25 | string ResourceRecord::toString() 26 | { 27 | std::bitset rrTypes; 28 | rrTypes.set(type_); 29 | return LabelUtils::LabelsToString(name_) + " " + TypeUtils::TypesToString(rrTypes) + " " + rdata_.get(); 30 | } 31 | 32 | vector ResourceRecord::get_name() const 33 | { 34 | return name_; 35 | } 36 | 37 | RRType ResourceRecord::get_type() const 38 | { 39 | return type_; 40 | } 41 | 42 | uint16_t ResourceRecord::get_class() const 43 | { 44 | return class_; 45 | } 46 | 47 | uint32_t ResourceRecord::get_ttl() const 48 | { 49 | return ttl_; 50 | } 51 | 52 | string ResourceRecord::get_rdata() const 53 | { 54 | return rdata_; 55 | } 56 | 57 | void ResourceRecord::set_name(string name) 58 | { 59 | name_ = LabelUtils::StringToLabels(name); 60 | } 61 | 62 | void ResourceRecord::set_type(string type) 63 | { 64 | type_ = TypeUtils::StringToType(type); 65 | } 66 | 67 | void ResourceRecord::set_class(uint16_t class_) 68 | { 69 | class_ = class_; 70 | } 71 | 72 | void ResourceRecord::set_ttl(uint32_t ttl) 73 | { 74 | ttl_ = ttl; 75 | } 76 | -------------------------------------------------------------------------------- /src/resource-record.h: -------------------------------------------------------------------------------- 1 | #ifndef RESOURCE_RECORD_H_ 2 | #define RESOURCE_RECORD_H_ 3 | 4 | #include "node-label.h" 5 | 6 | enum RRClass { CLASS_IN = 1, CLASS_CH = 3 }; 7 | 8 | enum RRType { A, NS, CNAME, DNAME, SOA, PTR, MX, TXT, AAAA, SRV, RRSIG, NSEC, SPF, N }; 9 | 10 | class ResourceRecord 11 | { 12 | public: 13 | ResourceRecord(string name, string type, uint16_t class_, uint32_t ttl, string rdata); 14 | bool operator==(const ResourceRecord &l1) const; 15 | vector get_name() const; 16 | RRType get_type() const; 17 | uint16_t get_class() const; 18 | uint32_t get_ttl() const; 19 | string get_rdata() const; 20 | void set_name(string); 21 | void set_type(string); 22 | void set_class(uint16_t); 23 | void set_ttl(uint32_t); 24 | string toString(); 25 | friend ostream &operator<<(ostream &os, const ResourceRecord &rr); 26 | 27 | private: 28 | vector name_; 29 | RRType type_; 30 | uint16_t class_; 31 | uint32_t ttl_; 32 | boost::flyweight, boost::flyweights::no_tracking> rdata_; 33 | friend class boost::serialization::access; 34 | template void serialize(Archive &ar, const unsigned int version) 35 | { 36 | ar &name_; 37 | ar &type_; 38 | ar &class_; 39 | ar &ttl_; 40 | ar &rdata_; 41 | } 42 | }; 43 | 44 | class rrHash 45 | { 46 | public: 47 | size_t operator()(const ResourceRecord &l1) const 48 | { 49 | vector labels = l1.get_name(); 50 | int hash = 0; 51 | int err = 1; 52 | for (NodeLabel n : labels) { 53 | hash = hash + n.get().size() * err; 54 | err++; 55 | } 56 | return hash % 32; 57 | } 58 | }; 59 | 60 | #endif -------------------------------------------------------------------------------- /src/structural-task.cpp: -------------------------------------------------------------------------------- 1 | #include "structural-task.h" 2 | 3 | StructuralTask::StructuralTask(label::Graph::VertexDescriptor node, string domain) : node_(node), domain_name_(domain) 4 | { 5 | } 6 | 7 | string StructuralTask::PrintTaskType() 8 | { 9 | return "Task: Structural"; 10 | } 11 | 12 | void StructuralTask::Process(const Context &context, vector &variadic_arguments) 13 | { 14 | Job *current_job = boost::any_cast(variadic_arguments[0]); 15 | label::Graph *label_graph = boost::any_cast(variadic_arguments[1]); 16 | label_graph->CheckStructuralDelegationConsistency(domain_name_, node_, context, *current_job); 17 | } -------------------------------------------------------------------------------- /src/structural-task.h: -------------------------------------------------------------------------------- 1 | #ifndef STRUCTURAL_TASK_CLASS_H 2 | #define STRUCTURAL_TASK_CLASS_H 3 | 4 | #include "label-graph.h" 5 | #include "task.h" 6 | 7 | class StructuralTask : public Task 8 | { 9 | public: 10 | label::Graph::VertexDescriptor node_; 11 | string domain_name_; 12 | StructuralTask(label::Graph::VertexDescriptor, string); 13 | virtual string PrintTaskType(); 14 | virtual void Process(const Context &, vector &); 15 | }; 16 | 17 | #endif -------------------------------------------------------------------------------- /src/task.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef TASK_H 3 | #define TASK_H 4 | 5 | #include "interpretation-properties.h" 6 | 7 | class Task 8 | { 9 | public: 10 | virtual string PrintTaskType() = 0; 11 | virtual void Process(const Context &, vector &) = 0; 12 | }; 13 | 14 | #endif -------------------------------------------------------------------------------- /src/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | string LabelUtils::LabelsToString(vector domain_name) 4 | { 5 | string domain = ""; 6 | if (domain_name.size() == 0) { 7 | return "."; 8 | } else { 9 | for (auto &l : domain_name) { 10 | domain = l.get() + "." + domain; 11 | } 12 | } 13 | return domain; 14 | } 15 | 16 | string LabelUtils::LabelsToString(vector> domains) 17 | { 18 | string result = "["; 19 | for (auto &d : domains) { 20 | result += LabelsToString(d) + ", "; 21 | } 22 | result.pop_back(); 23 | result.pop_back(); 24 | return result + "]"; 25 | } 26 | 27 | tuple LabelUtils::LengthCheck(vector domain_labels, int level) 28 | { 29 | int length = 0; 30 | for (NodeLabel &l : domain_labels) { 31 | if (l.get().length() > kMaxLabelLength) { 32 | if (level == 2) { 33 | Logger->warn(fmt::format( 34 | "label-graph.cpp (GenerateECs) - Userinput, {}, has a label, {}, exceedeing the valid label length", 35 | LabelUtils::LabelsToString(domain_labels), l.get())); 36 | } 37 | return {false, l.get()}; 38 | } 39 | length += l.get().length() + 1; 40 | } 41 | if (length > kMaxDomainLength) { 42 | if (level == 2) { 43 | Logger->warn(fmt::format( 44 | "label-graph.cpp (GenerateECs) - Userinput, {}, exceedes the valid domain length", 45 | LabelUtils::LabelsToString(domain_labels))); 46 | } 47 | return {false, ""}; 48 | } 49 | return {true, ""}; 50 | } 51 | 52 | vector LabelUtils::StringToLabels(string domain_name) 53 | { 54 | vector tokens; 55 | if (domain_name.length() == 0) { 56 | return tokens; 57 | } 58 | if (domain_name[domain_name.length() - 1] != '.') { 59 | domain_name += "."; 60 | } 61 | // boost::algorithm::split(labels, name, boost::is_any_of(".")); // Avoiding this for the case where . is written 62 | // with \. and root zone. 63 | string previous = ""; 64 | for (auto it = domain_name.begin(); it < domain_name.end(); ++it) { 65 | if (*it == '.' && previous.length() > 0) { 66 | if (previous.back() == '\\') { 67 | previous += *it; 68 | } else { 69 | tokens.push_back(std::move(previous)); 70 | previous = ""; 71 | } 72 | } else { 73 | previous += *it; 74 | } 75 | } 76 | std::reverse(tokens.begin(), tokens.end()); 77 | return tokens; 78 | } 79 | 80 | bool LabelUtils::SubDomainCheck(const vector &domain, const vector &subdomain) 81 | { 82 | if (domain.size() > subdomain.size()) { 83 | return false; 84 | } 85 | for (int i = 0; i < domain.size(); i++) { 86 | if (!(domain[i] == subdomain[i])) { 87 | return false; 88 | } 89 | } 90 | return true; 91 | } 92 | 93 | bool LabelUtils::SubDomainCheck(const vector> &allowed_domains, const vector &subdomain) 94 | { 95 | bool any_subdomain = false; 96 | for (auto &d : allowed_domains) { 97 | any_subdomain |= SubDomainCheck(d, subdomain); 98 | } 99 | return any_subdomain; 100 | } 101 | 102 | RRType TypeUtils::StringToType(const string &type) 103 | { 104 | if (type == "A") { 105 | return A; 106 | } else if (type == "NS") { 107 | return NS; 108 | } else if (type == "CNAME") { 109 | return CNAME; 110 | } else if (type == "DNAME") { 111 | return DNAME; 112 | } else if (type == "SOA") { 113 | return SOA; 114 | } else if (type == "PTR") { 115 | return PTR; 116 | } else if (type == "MX") { 117 | return MX; 118 | } else if (type == "TXT") { 119 | return TXT; 120 | } else if (type == "AAAA") { 121 | return AAAA; 122 | } else if (type == "SRV") { 123 | return SRV; 124 | } else if (type == "RRSIG") { 125 | return RRSIG; 126 | } else if (type == "NSEC") { 127 | return NSEC; 128 | } else if (type == "SPF") { 129 | return SPF; 130 | } 131 | return N; 132 | } 133 | 134 | string type_to_string[] = {"A", "NS", "CNAME", "DNAME", "SOA", "PTR", "MX", 135 | "TXT", "AAAA", "SRV", "RRSIG", "NSEC", "SPF"}; 136 | 137 | string TypeUtils::TypeToString(RRType type) 138 | { 139 | return type_to_string[type]; 140 | } 141 | 142 | string TypeUtils::TypesToString(std::bitset rrTypes) 143 | { 144 | std::set types; 145 | 146 | for (int i = 0; i < RRType::N; i++) { 147 | if (rrTypes[i] == 1) { 148 | types.insert(type_to_string[i]); 149 | } 150 | } 151 | string stypes = ""; 152 | for (auto r : types) { 153 | if (stypes.size() > 0) { 154 | stypes += " "; 155 | } 156 | stypes += r; 157 | } 158 | return stypes; 159 | } 160 | 161 | CommonSymDiff RRUtils::CompareRRs(vector res_a, vector res_b) 162 | { 163 | // For the given pair of collection of resource records, return the common RR's, RR's present only in A and RR's 164 | // present only in B. 165 | // Assumption: resA and resB has unique records (no two records in either vector are exactly the same) 166 | vector common; 167 | auto it = res_a.begin(); 168 | while (it != res_a.end()) { 169 | auto itb = res_b.begin(); 170 | bool erased = false; 171 | while (itb != res_b.end()) { 172 | if (*it == *itb) { 173 | common.push_back(*it); 174 | it = res_a.erase(it); 175 | res_b.erase(itb); 176 | erased = true; 177 | break; 178 | } else { 179 | itb++; 180 | } 181 | } 182 | if (!erased) 183 | it++; 184 | } 185 | return std::make_tuple(common, res_a, res_b); 186 | } 187 | 188 | void LintUtils::WriteIssueToFile(json &log_line, bool lint) 189 | { 190 | int i = 0; 191 | if (lint) { 192 | std::fstream in("lint.json", ios::in); 193 | if (in.is_open()) { 194 | string tp; 195 | 196 | while (getline(in, tp)) { 197 | i++; 198 | if (i > 3) 199 | break; 200 | } 201 | in.close(); 202 | } else { 203 | Logger->error("Linting enabled but unable to open the lint.txt file for reading"); 204 | } 205 | std::ofstream out("lint.json", ios::app); 206 | if (i > 3) 207 | out << ",\n"; 208 | out << log_line.dump(4); 209 | out.close(); 210 | } 211 | } 212 | 213 | void LintUtils::WriteRRIssueToFile( 214 | bool lint, 215 | string file_name, 216 | size_t line, 217 | string current_rr, 218 | string violation, 219 | string previous_rr) 220 | { 221 | if (lint) { 222 | json tmp; 223 | tmp["File Name"] = file_name; 224 | tmp["Line Number"] = line; 225 | tmp["Current Record"] = current_rr; 226 | tmp["Violation"] = violation; 227 | if (previous_rr.length()) { 228 | tmp["Previous Record"] = previous_rr; 229 | } 230 | WriteIssueToFile(tmp, lint); 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H_ 2 | #define UTILS_H_ 3 | 4 | #include 5 | 6 | #include "resource-record.h" 7 | 8 | class LabelUtils 9 | { 10 | public: 11 | static string LabelsToString(vector); 12 | static string LabelsToString(vector>); 13 | static tuple LengthCheck(vector, int); 14 | static vector StringToLabels(string); 15 | static bool SubDomainCheck(const vector &, const vector &); 16 | static bool SubDomainCheck(const vector> &, const vector &); 17 | }; 18 | 19 | class TypeUtils 20 | { 21 | public: 22 | static RRType StringToType(const string &); 23 | static string TypeToString(RRType type); 24 | static string TypesToString(std::bitset); 25 | }; 26 | 27 | using CommonSymDiff = tuple, vector, vector>; 28 | 29 | class RRUtils 30 | { 31 | public: 32 | static CommonSymDiff CompareRRs(vector, vector); 33 | }; 34 | 35 | class LintUtils 36 | { 37 | public: 38 | static void WriteIssueToFile(json &, bool); 39 | static void WriteRRIssueToFile(bool, string, size_t, string, string, string); 40 | }; 41 | #endif 42 | -------------------------------------------------------------------------------- /src/zone-graph.cpp: -------------------------------------------------------------------------------- 1 | #include "zone-graph.h" 2 | #include "utils.h" 3 | 4 | zone::Graph::Graph(int zoneId) 5 | { 6 | root_ = boost::add_vertex(*this); 7 | (*this)[root_].name.set("."); 8 | id_ = zoneId; 9 | } 10 | 11 | const int &zone::Graph::get_id() 12 | { 13 | return id_; 14 | } 15 | 16 | const vector &zone::Graph::get_origin() const 17 | { 18 | return origin_; 19 | } 20 | 21 | void zone::Graph::AddGlueRecords(vector &ns_records) const 22 | { 23 | vector merged_records; 24 | for (auto &record : ns_records) { 25 | vector ns_name = LabelUtils::StringToLabels(record.get_rdata()); 26 | int index = 0; 27 | merged_records.push_back(std::move(record)); 28 | VertexDescriptor closest_encloser = GetAncestor(root_, ns_name, index); 29 | if (ns_name.size() == index) { 30 | // found the node 31 | for (auto &noderecords : (*this)[closest_encloser].rrs) { 32 | if (noderecords.get_type() == RRType::A || noderecords.get_type() == RRType::AAAA) { 33 | merged_records.push_back(noderecords); 34 | } 35 | } 36 | } 37 | } 38 | ns_records = std::move(merged_records); 39 | } 40 | 41 | zone::Graph::VertexDescriptor zone::Graph::AddNodes( 42 | zone::Graph::VertexDescriptor closest_encloser, 43 | const vector &labels, 44 | const int &index) 45 | { 46 | for (int i = index; i < labels.size(); i++) { 47 | VertexDescriptor u = boost::add_vertex(*this); 48 | (*this)[u].name = labels[i]; 49 | EdgeDescriptor e; 50 | bool b; 51 | boost::tie(e, b) = boost::add_edge(closest_encloser, u, *this); 52 | if (!b) { 53 | Logger->critical(fmt::format("zone-graph.cpp (AddNodes) - Unable to add edge to the graph")); 54 | exit(EXIT_FAILURE); 55 | } 56 | // Only the first closestEncloser might have a map. For other cases closestEncloser will take care. 57 | if (vertex_to_child_map_.find(closest_encloser) != vertex_to_child_map_.end()) { 58 | LabelToVertex &m = vertex_to_child_map_.find(closest_encloser)->second; 59 | m[labels[i]] = u; 60 | } 61 | closest_encloser = u; 62 | } 63 | return closest_encloser; 64 | } 65 | 66 | void zone::Graph::CheckGlueRecordsPresence(zone::Graph::VertexDescriptor start, const Nameserver &ns) 67 | { 68 | for (auto &rr : (*this)[start].rrs) { 69 | if (rr.get_type() == RRType::NS) { 70 | vector tmp = {rr}; 71 | if (RequireGlueRecords(tmp)) { 72 | AddGlueRecords(tmp); 73 | if (tmp.size() == 1) { 74 | // missing the necessary glue record. 75 | json j; 76 | j["Server"] = ns.get(); 77 | j["Zone"] = LabelUtils::LabelsToString(origin_); 78 | j["Violation"] = "Missing Glue Record"; 79 | j["Resource Record"] = rr.toString(); 80 | LintUtils::WriteIssueToFile(j, true); 81 | } 82 | } 83 | } 84 | } 85 | for (VertexDescriptor v : boost::make_iterator_range(adjacent_vertices(start, *this))) { 86 | CheckGlueRecordsPresence(v, ns); 87 | } 88 | } 89 | 90 | tuple> zone::Graph::AddResourceRecord( 91 | const ResourceRecord &record) 92 | { 93 | /* 94 | Return codes 95 | 0 - No errors 96 | 1 - Duplicate 97 | 2 - CNAME multiple 98 | 3 - DNAME multiple 99 | 4 - CNAME other records 100 | NO RRs should exist under a DNAME node but its harder to enforce at the time of addition as they may be added in 101 | any order. Such RRs are ignored during QueryLookUpAtZone. 102 | */ 103 | vector labels = record.get_name(); 104 | int index = 0; 105 | vector vertices_to_create_maps{}; 106 | VertexDescriptor closest_encloser = GetAncestor(root_, labels, vertices_to_create_maps, index); 107 | for (auto &v : vertices_to_create_maps) { 108 | ConstructChildLabelsToVertexDescriptorMap(v); 109 | } 110 | VertexDescriptor node = AddNodes(closest_encloser, labels, index); 111 | 112 | for (auto &rr : (*this)[node].rrs) { 113 | if (rr.get_type() == record.get_type()) { 114 | if (rr.get_ttl() == record.get_ttl() && rr.get_rdata() == record.get_rdata()) { 115 | return {RRAddCode::DUPLICATE, {}}; 116 | } 117 | if (record.get_type() == RRType::CNAME) { 118 | return {RRAddCode::CNAME_MULTIPLE, node}; 119 | } 120 | if (record.get_type() == RRType::DNAME) { 121 | return {RRAddCode::DNAME_MULTIPLE, node}; 122 | } 123 | } else if (rr.get_type() == RRType::CNAME || record.get_type() == RRType::CNAME) { 124 | return {RRAddCode::CNAME_OTHER, node}; 125 | } 126 | } 127 | (*this)[node].rrs.push_back(record); 128 | if (record.get_type() == RRType::SOA) { 129 | origin_ = record.get_name(); 130 | } 131 | return {RRAddCode::SUCCESS, node}; 132 | } 133 | 134 | void zone::Graph::CheckGlueRecordsPresence(const Nameserver &ns) 135 | { 136 | CheckGlueRecordsPresence(root_, ns); 137 | } 138 | 139 | bool zone::Graph::CheckZoneMembership(const ResourceRecord &record, const string &filename) 140 | { 141 | if (record.get_type() == RRType::SOA && origin_.size() == 0) { 142 | return true; 143 | } else if (origin_.size() == 0) { 144 | Logger->critical(fmt::format( 145 | "zone-graph.cpp (CheckZoneMembership) - Non SOA record is written before a SOA record in the zone file {}", 146 | filename)); 147 | exit(EXIT_FAILURE); 148 | } 149 | return LabelUtils::SubDomainCheck(origin_, record.get_name()); 150 | } 151 | 152 | vector zone::Graph::LookUpGlueRecords(const vector &ns_records) const 153 | { 154 | vector ip_records; 155 | for (auto &record : ns_records) { 156 | vector ns_name = LabelUtils::StringToLabels(record.get_rdata()); 157 | int index = 0; 158 | VertexDescriptor closest_encloser = GetAncestor(root_, ns_name, index); 159 | if (ns_name.size() == index) { 160 | // found the node 161 | for (auto &noderecords : (*this)[closest_encloser].rrs) { 162 | if (noderecords.get_type() == RRType::A || noderecords.get_type() == RRType::AAAA) { 163 | ip_records.push_back(noderecords); 164 | } 165 | } 166 | } 167 | } 168 | return ip_records; 169 | } 170 | 171 | void zone::Graph::ConstructChildLabelsToVertexDescriptorMap(const zone::Graph::VertexDescriptor node) 172 | { 173 | zone::Graph::LabelToVertex m; 174 | for (EdgeDescriptor edge : boost::make_iterator_range(out_edges(node, *this))) { 175 | m[(*this)[edge.m_target].name] = edge.m_target; 176 | } 177 | // vertex_to_child_map_[node] = std::move(m); 178 | vertex_to_child_map_.insert({node, std::move(m)}); 179 | } 180 | 181 | zone::Graph::VertexDescriptor zone::Graph::GetAncestor( 182 | zone::Graph::VertexDescriptor closest_encloser, 183 | const vector &labels, 184 | int &index) const 185 | { 186 | vector vertices_to_create_maps{}; 187 | return GetAncestor(closest_encloser, labels, vertices_to_create_maps, index); 188 | } 189 | 190 | zone::Graph::VertexDescriptor zone::Graph::GetAncestor( 191 | zone::Graph::VertexDescriptor closest_encloser, 192 | const vector &labels, 193 | vector &vertices_to_create_maps, 194 | int &index) const 195 | { 196 | /*Given a domain this function returns its closest ancestor in the existing Zone Graph. This function is used for 197 | * building the Zone Graph. */ 198 | if (labels.size() == index) { 199 | return closest_encloser; 200 | } 201 | if (vertex_to_child_map_.find(closest_encloser) != vertex_to_child_map_.end()) { 202 | const LabelToVertex &m = vertex_to_child_map_.find(closest_encloser)->second; 203 | auto it = m.find(labels[index]); 204 | if (it != m.end()) { 205 | closest_encloser = it->second; 206 | index++; 207 | return GetAncestor(closest_encloser, labels, vertices_to_create_maps, index); 208 | } 209 | } else { 210 | if (out_degree(closest_encloser, *this) > kHashMapThreshold) { 211 | vertices_to_create_maps.push_back(closest_encloser); 212 | } 213 | for (VertexDescriptor v : boost::make_iterator_range(adjacent_vertices(closest_encloser, *this))) { 214 | if ((*this)[v].name == labels[index]) { 215 | closest_encloser = v; 216 | index++; 217 | return GetAncestor(closest_encloser, labels, vertices_to_create_maps, index); 218 | } 219 | } 220 | } 221 | return closest_encloser; 222 | } 223 | 224 | zone::Graph::VertexDescriptor zone::Graph::GetClosestEncloser( 225 | zone::Graph::VertexDescriptor closest_encloser, 226 | const vector &labels, 227 | int &index) const 228 | { 229 | 230 | if (labels.size() == index) { 231 | return closest_encloser; 232 | } 233 | if (vertex_to_child_map_.find(closest_encloser) != vertex_to_child_map_.end()) { 234 | const LabelToVertex &m = vertex_to_child_map_.find(closest_encloser)->second; 235 | auto it = m.find(labels[index]); 236 | if (it != m.end()) { 237 | closest_encloser = it->second; 238 | index++; 239 | std::bitset nodeRRtypes = GetNodeRRTypes((*this)[closest_encloser].rrs); 240 | // If at any node, we encoutner NS records and they are not part of authoritative data then the search stops 241 | // here as they mark cuts along the bottom of a zone. 242 | // If not NS but we encounter a node with DNAME then that takes precedence. 243 | if (nodeRRtypes[RRType::NS] == 1 and nodeRRtypes[RRType::SOA] != 1) { 244 | return closest_encloser; 245 | } else if (nodeRRtypes[RRType::DNAME] == 1 && labels.size() != index) { 246 | // It should not be the last label and the current node has a DNAME RR 247 | return closest_encloser; 248 | } 249 | return GetClosestEncloser(closest_encloser, labels, index); 250 | } 251 | } else { 252 | for (VertexDescriptor v : boost::make_iterator_range(adjacent_vertices(closest_encloser, *this))) { 253 | if ((*this)[v].name == labels[index]) { 254 | std::bitset nodeRRtypes = GetNodeRRTypes((*this)[v].rrs); 255 | index++; 256 | if (nodeRRtypes[RRType::NS] == 1 and nodeRRtypes[RRType::SOA] != 1) { 257 | return v; 258 | } else if (nodeRRtypes[RRType::DNAME] == 1 && labels.size() != index) { 259 | // It should not be the last label and the current node has a DNAME RR 260 | return v; 261 | } 262 | closest_encloser = v; 263 | return GetClosestEncloser(closest_encloser, labels, index); 264 | } 265 | } 266 | } 267 | return closest_encloser; 268 | } 269 | 270 | std::bitset zone::Graph::GetNodeRRTypes(const vector &rrs) const 271 | { 272 | std::bitset rrTypes; 273 | for (auto &record : rrs) { 274 | rrTypes[record.get_type()] = 1; 275 | } 276 | return rrTypes; 277 | } 278 | 279 | bool zone::Graph::WildcardMatch( 280 | VertexDescriptor closest_encloser, 281 | std::bitset &node_rr_types, 282 | vector &answers, 283 | const EC &query) const 284 | { 285 | NodeLabel wildcard{"*"}; 286 | for (VertexDescriptor v : boost::make_iterator_range(adjacent_vertices(closest_encloser, *this))) { 287 | if ((*this)[v].name == wildcard) { 288 | vector matchingRRs; 289 | std::bitset queryTypesFound; 290 | for (auto &record : (*this)[v].rrs) { 291 | if (record.get_type() == RRType::CNAME) { 292 | answers.clear(); 293 | matchingRRs.clear(); 294 | matchingRRs.push_back(record); 295 | // Return type is Ans if only CNAME is requested 296 | if (query.rrTypes[RRType::CNAME] && query.rrTypes.count() == 1) { 297 | answers.push_back(std::make_tuple(ReturnTag::ANS, node_rr_types, matchingRRs)); 298 | } else { 299 | answers.push_back(std::make_tuple(ReturnTag::REWRITE, node_rr_types, matchingRRs)); 300 | } 301 | return true; // If CNAME then other records would be ignored. 302 | } 303 | if (query.rrTypes[record.get_type()] == 1) { 304 | matchingRRs.push_back(record); 305 | queryTypesFound.set(record.get_type()); 306 | } 307 | // NS records at a wildcard node are forbidden. 308 | } 309 | if (queryTypesFound.count()) 310 | answers.push_back(std::make_tuple(ReturnTag::ANS, queryTypesFound, matchingRRs)); 311 | if ((queryTypesFound ^ query.rrTypes).count()) { 312 | answers.push_back( 313 | std::make_tuple(ReturnTag::ANS, queryTypesFound ^ query.rrTypes, vector{})); 314 | } 315 | return true; 316 | } 317 | } 318 | return false; 319 | } 320 | 321 | boost::optional> zone::Graph::QueryLookUpAtZone(const EC &query, bool &complete_match) const 322 | { 323 | // Query lookup at the zone is peformed only if it is relevant 324 | 325 | /*int index = 0; 326 | for (Label l : z.origin) { 327 | if (index >= query.name.size() || l.n != query.name[index].n) { 328 | return {}; 329 | } 330 | index++; 331 | }*/ 332 | // Logger->debug(fmt::format("zone-graph (QueryLookUpAtZone) Query: {} look up at zone with origin: {}", 333 | // query.ToString(), LabelUtils::LabelsToString(origin_))); 334 | int index = 0; 335 | VertexDescriptor closest_encloser = GetClosestEncloser(root_, query.name, index); 336 | vector answers; 337 | NodeLabel wildcard{"*"}; 338 | 339 | if (query.name.size() != index || (query.excluded && query.name.size() == index)) { 340 | /* 341 | Assuming that zone file may not be perfect. If its correct then NS and DNAME can not exist unless the node 342 | has SOA. If SOA record is there then the order is (1) DNAME (2) Wildcard (3) NX 343 | else (1) NS- Referral (2) DNAME (3) wildcard (4) NX 344 | */ 345 | std::bitset node_rr_types = GetNodeRRTypes((*this)[closest_encloser].rrs); 346 | complete_match = false; 347 | if (node_rr_types[RRType::SOA]) { 348 | if (node_rr_types[RRType::DNAME]) { 349 | for (auto &record : (*this)[closest_encloser].rrs) { 350 | if (record.get_type() == RRType::DNAME) { 351 | // dr < dq ∧ DNAME ∈ T, DNAME is a singleton type, there can be no other records of DNAME type 352 | // at this node. 353 | vector dname; 354 | dname.push_back(record); 355 | answers.push_back(std::make_tuple(ReturnTag::REWRITE, node_rr_types, dname)); 356 | } 357 | } 358 | } else { 359 | if (WildcardMatch(closest_encloser, node_rr_types, answers, query)) { 360 | complete_match = true; 361 | } else { 362 | answers.push_back(std::make_tuple(ReturnTag::NX, query.rrTypes, vector{})); 363 | } 364 | } 365 | } else { 366 | if (node_rr_types[RRType::NS]) { 367 | vector ns_records; 368 | for (auto &record : (*this)[closest_encloser].rrs) { 369 | if (record.get_type() == RRType::NS) { 370 | ns_records.push_back(record); 371 | } 372 | } 373 | if (ns_records.size()) { 374 | AddGlueRecords(ns_records); 375 | answers.push_back(std::make_tuple(ReturnTag::REF, node_rr_types, ns_records)); 376 | } 377 | } else if (node_rr_types[RRType::DNAME]) { 378 | for (auto &record : (*this)[closest_encloser].rrs) { 379 | if (record.get_type() == RRType::DNAME) { 380 | vector dname; 381 | dname.push_back(record); 382 | answers.push_back(std::make_tuple(ReturnTag::REWRITE, node_rr_types, dname)); 383 | } 384 | } 385 | } else if (WildcardMatch(closest_encloser, node_rr_types, answers, query)) { 386 | complete_match = true; 387 | } else { 388 | answers.push_back(std::make_tuple(ReturnTag::NX, query.rrTypes, vector{})); 389 | } 390 | } 391 | return boost::make_optional(answers); 392 | 393 | } else { 394 | // Exact Query Match d_r = d_q 395 | complete_match = true; 396 | std::bitset node_rr_types = GetNodeRRTypes((*this)[closest_encloser].rrs); 397 | vector matching_rrs; // All the RRs requested by query types except NS 398 | vector ns_records; 399 | std::bitset query_types_found; 400 | for (auto &record : (*this)[closest_encloser].rrs) { 401 | if (record.get_type() == RRType::NS) { 402 | ns_records.push_back(record); 403 | } else if (query.rrTypes[record.get_type()] == 1) { 404 | query_types_found.set(record.get_type()); 405 | matching_rrs.push_back(record); 406 | } 407 | if (record.get_type() == RRType::CNAME) { 408 | // CNAME Case 409 | answers.clear(); 410 | matching_rrs.clear(); 411 | matching_rrs.push_back(record); 412 | // Return type is Ans if only CNAME is requested 413 | if (query.rrTypes[RRType::CNAME] && query.rrTypes.count() == 1) { 414 | answers.push_back(std::make_tuple(ReturnTag::ANS, node_rr_types, matching_rrs)); 415 | } else { 416 | answers.push_back(std::make_tuple(ReturnTag::REWRITE, node_rr_types, matching_rrs)); 417 | } 418 | return boost::make_optional(answers); // If CNAME then other records would be ignored. 419 | } 420 | } 421 | // If there are NS records, then get their glue records too. 422 | if (node_rr_types[RRType::NS]) { 423 | AddGlueRecords(ns_records); 424 | } 425 | // Referral case 426 | if (node_rr_types[RRType::NS] && !node_rr_types[RRType::SOA]) { 427 | answers.push_back(std::make_tuple(ReturnTag::REF, node_rr_types, ns_records)); 428 | return boost::make_optional(answers); 429 | } 430 | // Add the NS and glue records if the user requested them. 431 | if (query.rrTypes[RRType::NS] && ns_records.size()) { 432 | matching_rrs.insert(matching_rrs.end(), ns_records.begin(), ns_records.end()); 433 | query_types_found.set(RRType::NS); 434 | } 435 | // Exact Type match 436 | if (query_types_found.count()) 437 | answers.push_back(std::make_tuple(ReturnTag::ANS, query_types_found, matching_rrs)); 438 | if ((query_types_found ^ query.rrTypes).count()) { 439 | answers.push_back( 440 | std::make_tuple(ReturnTag::ANS, query_types_found ^ query.rrTypes, vector{})); 441 | } 442 | return boost::make_optional(answers); 443 | } 444 | } 445 | 446 | bool zone::Graph::RequireGlueRecords(const vector &ns_records) const 447 | { 448 | for (auto &record : ns_records) { 449 | vector ns_name = LabelUtils::StringToLabels(record.get_rdata()); 450 | if (ns_name.size() < origin_.size()) 451 | continue; 452 | int i = 0; 453 | for (; i < origin_.size(); i++) { 454 | if (origin_[i].get() != ns_name[i].get()) { 455 | break; 456 | } 457 | } 458 | if (i == origin_.size()) 459 | return true; 460 | } 461 | return false; 462 | } 463 | -------------------------------------------------------------------------------- /src/zone-graph.h: -------------------------------------------------------------------------------- 1 | #ifndef ZONE_GRAPH_H_ 2 | #define ZONE_GRAPH_H_ 3 | 4 | #include 5 | 6 | #include "equivalence-class.h" 7 | #include "node-label.h" 8 | 9 | using namespace std; 10 | using json = nlohmann::json; 11 | 12 | enum class ReturnTag { ANS, REWRITE, REF, NX, REFUSED, NSNOTFOUND, YX }; 13 | 14 | struct NSdummy { 15 | }; 16 | 17 | using Nameserver = boost::flyweight, boost::flyweights::no_tracking>; 18 | 19 | namespace zone 20 | { 21 | 22 | enum class RRAddCode { SUCCESS, DUPLICATE, CNAME_MULTIPLE, DNAME_MULTIPLE, CNAME_OTHER }; 23 | 24 | struct Vertex { 25 | NodeLabel name; 26 | vector rrs; 27 | 28 | private: 29 | friend class boost::serialization::access; 30 | template void serialize(Archive &ar, const unsigned int version) 31 | { 32 | ar &name; 33 | ar &rrs; 34 | } 35 | }; 36 | 37 | using LookUpAnswer = tuple, vector>; 38 | 39 | class Graph : public boost::adjacency_list 40 | { 41 | public: 42 | using VertexDescriptor = boost::graph_traits::vertex_descriptor; 43 | 44 | private: 45 | using EdgeDescriptor = boost::graph_traits::edge_descriptor; 46 | using LabelToVertex = boost::unordered_map; 47 | 48 | int id_; 49 | vector origin_; 50 | zone::Graph::VertexDescriptor root_ = 0; 51 | std::unordered_map vertex_to_child_map_; 52 | 53 | Graph(); 54 | 55 | void AddGlueRecords(vector &) const; 56 | VertexDescriptor AddNodes(VertexDescriptor, const vector &, const int &); 57 | void CheckGlueRecordsPresence(VertexDescriptor, const Nameserver &); 58 | void ConstructChildLabelsToVertexDescriptorMap(const zone::Graph::VertexDescriptor); 59 | zone::Graph::VertexDescriptor GetAncestor(zone::Graph::VertexDescriptor, const vector &, int &) const; 60 | zone::Graph::VertexDescriptor GetAncestor( 61 | zone::Graph::VertexDescriptor, 62 | const vector &, 63 | vector &, 64 | int &) const; 65 | zone::Graph::VertexDescriptor GetClosestEncloser(zone::Graph::VertexDescriptor, const vector &, int &) 66 | const; 67 | std::bitset GetNodeRRTypes(const vector &rrs) const; 68 | bool WildcardMatch(VertexDescriptor, std::bitset &, vector &, const EC &) const; 69 | 70 | public: 71 | Graph(int); 72 | const int &get_id(); 73 | const vector &get_origin() const; 74 | 75 | tuple> AddResourceRecord(const ResourceRecord &); 76 | void CheckGlueRecordsPresence(const Nameserver &); 77 | bool CheckZoneMembership(const ResourceRecord &, const string &); 78 | vector LookUpGlueRecords(const vector &) const; 79 | boost::optional> QueryLookUpAtZone(const EC &, bool &) const; 80 | bool RequireGlueRecords(const vector &NSRecords) const; 81 | }; 82 | } // namespace zone 83 | 84 | #endif -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10.2) 2 | 3 | if(NOT TARGET libgroot) 4 | message(FATAL_ERROR "Please run CMake at the repository root and then try `make groot`") 5 | endif() 6 | 7 | set(CMAKE_TOOLCHAIN_FILE "$ENV{HOME}/vcpkg/scripts/buildsystems/vcpkg.cmake") 8 | 9 | project(groot_test CXX) 10 | 11 | find_package(Boost COMPONENTS regex filesystem unit_test_framework REQUIRED) 12 | find_package(docopt CONFIG REQUIRED) 13 | find_package(nlohmann_json CONFIG REQUIRED) 14 | find_package(spdlog CONFIG REQUIRED) 15 | 16 | # specify the C++ standard 17 | set(CMAKE_CXX_STANDARD 17) 18 | set(CMAKE_CXX_STANDARD_REQUIRED True) 19 | 20 | #set ( PROJECT_LINK_LIBS libgroot.a ) 21 | #link_directories("${CMAKE_CURRENT_SOURCE_DIR}/../build/") 22 | 23 | 24 | include_directories(${Boost_INCLUDE_DIRS}) 25 | 26 | # Required for native installation of boost libraries 27 | ADD_DEFINITIONS(-DBOOST_TEST_DYN_LINK) 28 | 29 | file(GLOB SRCS "*.cpp") 30 | add_executable(tester ${SRCS}) 31 | 32 | target_link_libraries(tester PRIVATE libgroot ${Boost_LIBRARIES} 33 | docopt_s nlohmann_json spdlog::spdlog) 34 | 35 | add_test(NAME tests COMMAND tester --log_level=test_suite) 36 | 37 | -------------------------------------------------------------------------------- /test/TestFiles/bankcardExample/jobs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Domain": "support.mybankcard.com", 4 | "SubDomain": false, 5 | "Properties":[ 6 | { 7 | "PropertyName": "ResponseConsistency", 8 | "Types": ["A"] 9 | }, 10 | { 11 | "PropertyName": "ResponseValue", 12 | "Types": ["A"], 13 | "Value": ["204.58.233.244"] 14 | } 15 | ] 16 | } 17 | ] -------------------------------------------------------------------------------- /test/TestFiles/bankcardExample/zone_files/a.gtld-servers.net.txt: -------------------------------------------------------------------------------- 1 | $ORIGIN com. 2 | com. 14400 IN SOA a.gtld-servers.net. 3 | mybankcard.com. 14400 IN NS ns1.fnni.com. 4 | mybankcard.com. 14400 IN NS ns2.fnni.net. 5 | ns1.fnni.com. 14400 IN A 216.205.207.204 6 | -------------------------------------------------------------------------------- /test/TestFiles/bankcardExample/zone_files/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "TopNameServers":[ 3 | "a.gtld-servers.net." 4 | ], 5 | "ZoneFiles":[ 6 | { 7 | "FileName": "a.gtld-servers.net.txt", 8 | "NameServer": "a.gtld-servers.net.", 9 | "Origin": "com." 10 | }, 11 | { 12 | "FileName": "ns1.fnni.com.1.txt", 13 | "NameServer": "ns1.fnni.com.", 14 | "Origin": "mybankcard.com." 15 | }, 16 | { 17 | "FileName": "ns1.fnni.com.2.txt", 18 | "NameServer": "ns1.fnni.com.", 19 | "Origin": "bankcard.com." 20 | }, 21 | { 22 | "FileName": "ns2.fnni.net.1.txt", 23 | "NameServer": "ns2.fnni.net.", 24 | "Origin": "mybankcard.com." 25 | }, 26 | { 27 | "FileName": "ns2.fnni.net.2.txt", 28 | "NameServer": "ns2.fnni.net.", 29 | "Origin": "bankcard.com." 30 | } 31 | ] 32 | } -------------------------------------------------------------------------------- /test/TestFiles/bankcardExample/zone_files/ns1.fnni.com.1.txt: -------------------------------------------------------------------------------- 1 | $ORIGIN mybankcard.com. 2 | 3 | mybankcard.com. 14400 IN SOA ns1.fnni.com. 4 | mybankcard.com. 14400 IN NS ns1.fnni.com. 5 | mybankcard.com. 14400 IN NS ns2.fnni.net. 6 | mybankcard.com. 14400 IN DNAME bankcard.com. 7 | -------------------------------------------------------------------------------- /test/TestFiles/bankcardExample/zone_files/ns1.fnni.com.2.txt: -------------------------------------------------------------------------------- 1 | $ORIGIN bankcard.com. 2 | 3 | bankcard.com. 14400 IN SOA ns1.fnni.com. 4 | www.bankcard.com. 14400 IN AAAA 74d7::b94d:d07 5 | www.bankcard.com. 14400 IN A 204.58.233.75 6 | email.bankcard.com. 14400 IN A 66.161.21.26 7 | *.bankcard.com. 14400 IN A 204.58.233.244 8 | -------------------------------------------------------------------------------- /test/TestFiles/bankcardExample/zone_files/ns2.fnni.net.1.txt: -------------------------------------------------------------------------------- 1 | $ORIGIN mybankcard.com. 2 | 3 | mybankcard.com. 14400 IN SOA ns2.fnni.net. 4 | mybankcard.com. 14400 IN NS ns1.fnni.com. 5 | mybankcard.com. 14400 IN NS ns2.fnni.net. 6 | mybankcard.com. 14400 IN DNAME bankcard.com. 7 | -------------------------------------------------------------------------------- /test/TestFiles/bankcardExample/zone_files/ns2.fnni.net.2.txt: -------------------------------------------------------------------------------- 1 | $ORIGIN bankcard.com. 2 | 3 | bankcard.com. 14400 IN SOA ns2.fnni.net. 4 | www.bankcard.com. 14400 IN AAAA 74d7::b94d:d07 5 | www.bankcard.com. 14400 IN A 204.58.233.75 6 | email.bankcard.com. 14400 IN A 66.161.21.26 7 | *.bankcard.com. 14400 IN CNAME www.bankcard.com. 8 | -------------------------------------------------------------------------------- /test/TestFiles/cc.il.us/ig_expected.dot: -------------------------------------------------------------------------------- 1 | digraph G { 2 | 0[label="NS: \n Q:ds3.trial.cc.il.us. T:A \n A:"] [shape=diamond]; 3 | 1[label="NS: us.illinois.net.\n Q:ds3.trial.cc.il.us. T:A \n A:REWRITE"]; 4 | 2[label="NS: us.illinois.net.\n Q:ds3.richland.cc.il.us. T:A \n A:REF"]; 5 | 3[label="NS: \n Q:ns1.illinois.net. T:A AAAA \n A:"] [shape=diamond]; 6 | 4[label="NS: us.illinois.net.\n Q:ns1.illinois.net. T:A AAAA \n A:REFUSED"]; 7 | 5[label="NS: ns1.illinois.net.\n Q:ds3.richland.cc.il.us. T:A \n A:NS Not Found"]; 8 | 6[label="NS: ns1.richland.cc.il.us.\n Q:ds3.richland.cc.il.us. T:A \n A:REWRITE"]; 9 | 7[label="NS: ns1.richland.cc.il.us.\n Q:gw1.richland.cc.il.us. T:A \n A:ANS"]; 10 | 8[label="NS: \n Q:ns1.richland.edu. T:A AAAA \n A:"] [shape=diamond]; 11 | 9[label="NS: us.illinois.net.\n Q:ns1.richland.edu. T:A AAAA \n A:REFUSED"]; 12 | 10[label="NS: ns1.richland.edu.\n Q:ds3.richland.cc.il.us. T:A \n A:NS Not Found"]; 13 | 11[label="NS: \n Q:ns2.illinois.net. T:A AAAA \n A:"] [shape=diamond]; 14 | 12[label="NS: us.illinois.net.\n Q:ns2.illinois.net. T:A AAAA \n A:REFUSED"]; 15 | 13[label="NS: ns2.illinois.net.\n Q:ds3.richland.cc.il.us. T:A \n A:NS Not Found"]; 16 | 14[label="NS: \n Q:ns2.richland.edu. T:A AAAA \n A:"] [shape=diamond]; 17 | 15[label="NS: us.illinois.net.\n Q:ns2.richland.edu. T:A AAAA \n A:REFUSED"]; 18 | 16[label="NS: ns2.richland.edu.\n Q:ds3.richland.cc.il.us. T:A \n A:NS Not Found"]; 19 | 0->1 [color=black]; 20 | 1->2 [color=black]; 21 | 3->4 [color=black]; 22 | 2->5 [color=red]; 23 | 2->6 [color=black]; 24 | 6->7 [color=black]; 25 | 8->9 [color=black]; 26 | 2->10 [color=red]; 27 | 11->12 [color=black]; 28 | 2->13 [color=red]; 29 | 14->15 [color=black]; 30 | 2->16 [color=red]; 31 | } 32 | -------------------------------------------------------------------------------- /test/TestFiles/cc.il.us/jobs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Domain": "child.richland.cc.il.us.", 4 | "SubDomain": false, 5 | "Properties":[ 6 | { 7 | "PropertyName": "DelegationConsistency" 8 | } 9 | ] 10 | }, 11 | { 12 | "Domain": "gw1.richland.cc.il.us.", 13 | "SubDomain": false, 14 | "Properties":[ 15 | { 16 | "PropertyName": "ResponseConsistency", 17 | "Types": ["A"] 18 | }, 19 | { 20 | "PropertyName": "ResponseValue", 21 | "Types": ["A"], 22 | "Value": ["64.107.104.4"] 23 | } 24 | ] 25 | }, 26 | { 27 | "Domain": "child.richland.cc.il.us.", 28 | "SubDomain": true, 29 | "Properties":[ 30 | { 31 | "PropertyName": "ResponseConsistency", 32 | "Types": ["A","MX"] 33 | }, 34 | { 35 | "PropertyName": "RewriteBlackholing" 36 | } 37 | ] 38 | }, 39 | { 40 | "Domain": "ds3.richland.cc.il.us.", 41 | "SubDomain": false, 42 | "Properties":[ 43 | { 44 | "PropertyName": "ResponseReturned", 45 | "Types": ["CNAME","A"] 46 | } 47 | ] 48 | }, 49 | { 50 | "Domain": "cc.il.us.", 51 | "SubDomain": true, 52 | "Properties":[ 53 | { 54 | "PropertyName": "QueryRewrite", 55 | "Value": ["illinois.net." , "cc.il.us."] 56 | }, 57 | { 58 | "PropertyName": "Rewrites", 59 | "Value": 1 60 | }, 61 | { 62 | "PropertyName": "AllAliases", 63 | "Value":["gw1.richland.cc.il.us."] 64 | }, 65 | { 66 | "PropertyName": "NameserverContact", 67 | "Value": ["edu.", "net.", "cc.il.us."] 68 | }, 69 | { 70 | "PropertyName": "LameDelegation" 71 | }, 72 | { 73 | "PropertyName": "StructuralDelegationConsistency" 74 | }, 75 | { 76 | "PropertyName": "ZeroTTL" 77 | }, 78 | { 79 | "PropertyName": "DNAMESubstitutionCheck" 80 | } 81 | ] 82 | } 83 | ] 84 | -------------------------------------------------------------------------------- /test/TestFiles/cc.il.us/label_graph_expected.dot: -------------------------------------------------------------------------------- 1 | digraph G { 2 | 0[label="."]; 3 | 1[label="us"]; 4 | 2[label="il"]; 5 | 3[label="cc"]; 6 | 4[label="*"]; 7 | 5[label="clc"]; 8 | 6[label="dns-t"]; 9 | 7[label="csc"]; 10 | 8[label="dacc"]; 11 | 9[label="jaguar"]; 12 | 10[label="harper"]; 13 | 11[label="ifirewall"]; 14 | 12[label="hcc"]; 15 | 13[label="ns1"]; 16 | 14[label="ns2"]; 17 | 15[label="highland"]; 18 | 16[label="icc"]; 19 | 17[label="epprddns02"]; 20 | 18[label="ns"]; 21 | 19[label="iecc"]; 22 | 20[label="jal"]; 23 | 21[label="dns"]; 24 | 22[label="jjc"]; 25 | 23[label="kc"]; 26 | 24[label="kccn"]; 27 | 25[label="kcc"]; 28 | 26[label="lakeland"]; 29 | 27[label="ns1"]; 30 | 28[label="ns2"]; 31 | 29[label="lc"]; 32 | 30[label="dns1"]; 33 | 31[label="dns2"]; 34 | 32[label="llcc"]; 35 | 33[label="mchenry"]; 36 | 34[label="dns1"]; 37 | 35[label="moraine"]; 38 | 36[label="morton"]; 39 | 37[label="mv"]; 40 | 38[label="parkland"]; 41 | 39[label="prairie"]; 42 | 40[label="ns1"]; 43 | 41[label="ns2"]; 44 | 42[label="richland"]; 45 | 43[label="ns1"]; 46 | 44[label="rlc"]; 47 | 45[label="rvc"]; 48 | 46[label="rwhois"]; 49 | 47[label="shawnee"]; 50 | 48[label="shawneedns"]; 51 | 49[label="sic"]; 52 | 50[label="southwestern"]; 53 | 51[label="src"]; 54 | 52[label="ns"]; 55 | 53[label="ssc"]; 56 | 54[label="elgin"]; 57 | 55[label="hunley"]; 58 | 56[label="trial"]; 59 | 57[label="whois"]; 60 | 58[label="child"]; 61 | 59[label="ns1"]; 62 | 60[label="ns2"]; 63 | 61[label="ds3"]; 64 | 62[label="gw1"]; 65 | 63[label="gw2"]; 66 | 64[label="gw3"]; 67 | 65[label="gw4"]; 68 | 66[label="ns2"]; 69 | 67[label="chicago"]; 70 | 68[label="darwin"]; 71 | 69[label="uranus"]; 72 | 0->1 [color=black]; 73 | 1->2 [color=black]; 74 | 2->3 [color=black]; 75 | 3->4 [color=black]; 76 | 3->5 [color=black]; 77 | 3->7 [color=black]; 78 | 3->8 [color=black]; 79 | 3->10 [color=black]; 80 | 3->12 [color=black]; 81 | 3->15 [color=black]; 82 | 3->16 [color=black]; 83 | 3->19 [color=black]; 84 | 3->20 [color=black]; 85 | 3->22 [color=black]; 86 | 3->23 [color=black]; 87 | 3->25 [color=black]; 88 | 3->26 [color=black]; 89 | 3->29 [color=black]; 90 | 3->32 [color=black]; 91 | 3->33 [color=black]; 92 | 3->35 [color=black]; 93 | 3->36 [color=black]; 94 | 3->37 [color=black]; 95 | 3->38 [color=black]; 96 | 3->39 [color=black]; 97 | 3->42 [color=black]; 98 | 3->44 [color=black]; 99 | 3->45 [color=black]; 100 | 3->46 [color=black]; 101 | 3->47 [color=black]; 102 | 3->49 [color=black]; 103 | 3->50 [color=black]; 104 | 3->51 [color=black]; 105 | 3->53 [color=black]; 106 | 3->56 [color=black]; 107 | 3->57 [color=black]; 108 | 5->6 [color=black]; 109 | 8->9 [color=black]; 110 | 10->11 [color=black]; 111 | 12->13 [color=black]; 112 | 12->14 [color=black]; 113 | 16->17 [color=black]; 114 | 16->18 [color=black]; 115 | 20->21 [color=black]; 116 | 23->24 [color=black]; 117 | 26->27 [color=black]; 118 | 26->28 [color=black]; 119 | 29->30 [color=black]; 120 | 29->31 [color=black]; 121 | 33->34 [color=black]; 122 | 39->40 [color=black]; 123 | 39->41 [color=black]; 124 | 42->43 [color=black]; 125 | 42->58 [color=black]; 126 | 42->61 [color=black]; 127 | 42->62 [color=black]; 128 | 42->63 [color=black]; 129 | 42->64 [color=black]; 130 | 42->65 [color=black]; 131 | 42->66 [color=black]; 132 | 47->48 [color=black]; 133 | 51->52 [color=black]; 134 | 53->54 [color=black]; 135 | 53->55 [color=black]; 136 | 56->42 [color=red]; 137 | 58->59 [color=black]; 138 | 58->60 [color=black]; 139 | 58->67 [color=black]; 140 | 58->68 [color=black]; 141 | 58->69 [color=black]; 142 | } 143 | -------------------------------------------------------------------------------- /test/TestFiles/cc.il.us/zone_files/cc.il.us..txt: -------------------------------------------------------------------------------- 1 | ; <<>> DiG 9.11.3-1ubuntu1.11-Ubuntu <<>> AXFR cc.il.us. @66.99.142.110 2 | ;; global options: +cmd 3 | 4 | cc.il.us. 14400 IN SOA us.illinois.net. us-domain.illinois.net. 2018083000 14400 3600 2419200 14400 5 | cc.il.us. 14400 IN NS us1.illinois.net. 6 | cc.il.us. 14400 IN NS us2.illinois.net. 7 | *.cc.il.us. 86400 IN A 91.144.20.76 8 | clc.cc.il.us. 14400 IN NS ns1.illinois.nt. 9 | clc.cc.il.us. 14400 IN NS ns2.illinois.net. 10 | clc.cc.il.us. 14400 IN NS dns-t.clc.cc.il.us. 11 | dns-t.clc.cc.il.us. 14400 IN A 216.125.48.50 12 | csc.cc.il.us. 14400 IN NS cscns1.sandburg.edu. 13 | csc.cc.il.us. 14400 IN NS cscns2.sandburg.edu. 14 | dacc.cc.il.us. 14400 IN NS ns1.illinois.net. 15 | dacc.cc.il.us. 14400 IN NS ns2.illinois.net. 16 | dacc.cc.il.us. 14400 IN NS jaguar.dacc.cc.il.us. 17 | jaguar.dacc.cc.il.us. 14400 IN A 64.107.112.2 18 | harper.cc.il.us. 14400 IN NS ns1.illinois.net. 19 | harper.cc.il.us. 14400 IN NS auth01.ns.uu.net. 20 | harper.cc.il.us. 14400 IN NS ifirewall.harper.cc.il.us. 21 | ifirewall.harper.cc.il.us. 14400 IN A 157.178.1.101 22 | hcc.cc.il.us. 14400 IN NS ns1.hcc.cc.il.us. 23 | hcc.cc.il.us. 14400 IN NS ns2.hcc.cc.il.us. 24 | ns1.hcc.cc.il.us. 14400 IN A 216.125.243.6 25 | ns2.hcc.cc.il.us. 14400 IN A 4.17.210.2 26 | highland.cc.il.us. 14400 IN NS ns1.illinois.net. 27 | highland.cc.il.us. 14400 IN NS ns2.illinois.net. 28 | icc.cc.il.us. 14400 IN NS ns.icc.cc.il.us. 29 | icc.cc.il.us. 14400 IN NS epprddns02.icc.cc.il.us. 30 | epprddns02.icc.cc.il.us. 14400 IN A 216.124.224.245 31 | ns.icc.cc.il.us. 14400 IN A 216.124.224.253 32 | iecc.cc.il.us. 14400 IN NS ns1.illinois.net. 33 | iecc.cc.il.us. 14400 IN NS ns2.illinois.net. 34 | iecc.cc.il.us. 14400 IN NS dns1.iecc.edu. 35 | jal.cc.il.us. 14400 IN NS dns.jal.cc.il.us. 36 | jal.cc.il.us. 14400 IN NS ns1.illinois.net. 37 | jal.cc.il.us. 14400 IN NS ns2.illinois.net. 38 | dns.jal.cc.il.us. 14400 IN A 66.99.148.241 39 | jjc.cc.il.us. 14400 IN NS ns1.illinois.net. 40 | jjc.cc.il.us. 14400 IN NS ns2.illinois.net. 41 | kc.cc.il.us. 14400 IN NS kccn.kc.cc.il.us. 42 | kccn.kc.cc.il.us. 14400 IN A 64.107.246.5 43 | kcc.cc.il.us. 14400 IN NS ns1.illinois.net. 44 | kcc.cc.il.us. 14400 IN NS ns2.illinois.net. 45 | lakeland.cc.il.us. 14400 IN NS ns1.illinois.net. 46 | lakeland.cc.il.us. 14400 IN NS ns1.lakeland.cc.il.us. 47 | lakeland.cc.il.us. 14400 IN NS ns2.illinois.net. 48 | lakeland.cc.il.us. 14400 IN NS ns2.lakeland.cc.il.us. 49 | ns1.lakeland.cc.il.us. 14400 IN A 207.63.74.136 50 | ns2.lakeland.cc.il.us. 14400 IN A 207.63.74.137 51 | lc.cc.il.us. 14400 IN NS dns1.lc.cc.il.us. 52 | lc.cc.il.us. 14400 IN NS dns2.lc.cc.il.us. 53 | dns1.lc.cc.il.us. 14400 IN A 216.125.196.10 54 | dns2.lc.cc.il.us. 14400 IN A 216.125.196.11 55 | llcc.cc.il.us. 14400 IN NS ns.llcc.edu. 56 | llcc.cc.il.us. 14400 IN NS ns1.illinois.net. 57 | llcc.cc.il.us. 14400 IN NS ns2.illinois.net. 58 | mchenry.cc.il.us. 14400 IN NS ns1.illinois.net. 59 | mchenry.cc.il.us. 14400 IN NS ns2.illinois.net. 60 | mchenry.cc.il.us. 14400 IN NS dns1.mchenry.cc.il.us. 61 | dns1.mchenry.cc.il.us. 14400 IN A 64.107.54.42 62 | moraine.cc.il.us. 14400 IN NS mvccns1.morainevalley.edu. 63 | moraine.cc.il.us. 14400 IN NS mvccns2.morainevalley.edu. 64 | morton.cc.il.us. 14400 IN NS b.ns.verio.net. 65 | morton.cc.il.us. 14400 IN NS t.ns.verio.net. 66 | mv.cc.il.us. 14400 IN NS mvccns1.morainevalley.edu. 67 | mv.cc.il.us. 14400 IN NS mvccns2.morainevalley.edu. 68 | parkland.cc.il.us. 14400 IN NS ns1.illinois.net. 69 | parkland.cc.il.us. 14400 IN NS ns1.parkland.edu. 70 | parkland.cc.il.us. 14400 IN NS ns2.illinois.net. 71 | prairie.cc.il.us. 14400 IN NS ns1.prairie.cc.il.us. 72 | prairie.cc.il.us. 14400 IN NS ns2.prairie.cc.il.us. 73 | ns1.prairie.cc.il.us. 14400 IN A 66.158.49.3 74 | ns2.prairie.cc.il.us. 14400 IN A 66.158.49.4 75 | richland.cc.il.us. 14400 IN NS ns1.illinois.net. 76 | richland.cc.il.us. 14400 IN NS ns1.richland.cc.il.us. 77 | richland.cc.il.us. 14400 IN NS ns1.richland.edu. 78 | richland.cc.il.us. 14400 IN NS ns2.illinois.net. 79 | richland.cc.il.us. 14400 IN NS ns2.richland.edu. 80 | ns1.richland.cc.il.us. 14400 IN A 64.107.104.28 81 | rlc.cc.il.us. 14400 IN NS ns1.illinois.net. 82 | rlc.cc.il.us. 14400 IN NS ns2.illinois.net. 83 | rvc.cc.il.us. 14400 IN NS ns1.illinois.net. 84 | rvc.cc.il.us. 14400 IN NS ns2.illinois.net. 85 | rwhois.cc.il.us. 14400 IN CNAME us.illlinois.net. 86 | shawnee.cc.il.us. 14400 IN NS ns1.illinois.net. 87 | shawnee.cc.il.us. 14400 IN NS ns2.illinois.net. 88 | shawnee.cc.il.us. 14400 IN NS shawneedns.shawnee.cc.il.us. 89 | shawneedns.shawnee.cc.il.us. 14400 IN A 216.124.211.20 90 | sic.cc.il.us. 14400 IN NS ns1.illinois.net. 91 | sic.cc.il.us. 14400 IN NS ns2.illinois.net. 92 | southwestern.cc.il.us. 14400 IN NS ns1.illinois.net. 93 | southwestern.cc.il.us. 14400 IN NS ns2.illinois.net. 94 | src.cc.il.us. 14400 IN NS ns.src.cc.il.us. 95 | src.cc.il.us. 14400 IN NS ns1.illinois.net. 96 | src.cc.il.us. 14400 IN NS ns2.illinois.net. 97 | ns.src.cc.il.us. 14400 IN A 216.124.232.131 98 | ssc.cc.il.us. 14400 IN NS ns1.illinois.net. 99 | ssc.cc.il.us. 14400 IN NS ns2.illinois.net. 100 | ssc.cc.il.us. 14400 IN NS elgin.ssc.cc.il.us. 101 | ssc.cc.il.us. 14400 IN NS hunley.ssc.cc.il.us. 102 | elgin.ssc.cc.il.us. 14400 IN A 64.107.45.5 103 | hunley.ssc.cc.il.us. 14400 IN A 64.107.44.10 104 | trial.cc.il.us. 14400 IN DNAME richland.cc.il.us. 105 | whois.cc.il.us. 14400 IN CNAME us.illinois.net. 106 | 107 | ;; https://tldrproject.s3.amazonaws.com/index.html?prefix=cc.il.us./ 108 | ;; Query time: 80 msec 109 | ;; SERVER: 66.99.142.110#53(66.99.142.110) 110 | ;; WHEN: Thu May 14 15:06:48 PDT 2020 111 | ;; XFR size: 108 records (messages 1, bytes 2134) 112 | 113 | -------------------------------------------------------------------------------- /test/TestFiles/cc.il.us/zone_files/child.richland.cc.il.us.-2.txt: -------------------------------------------------------------------------------- 1 | child.richland.cc.il.us. 3600 IN SOA ns1.child.richland.cc.il.us. james.richland.edu. 19122302 10800 3600 3600000 86400 2 | child.richland.cc.il.us. IN NS ns1.child.richland.cc.il.us. 3 | child.richland.cc.il.us. IN NS ns2.child.richland.cc.il.us. 4 | ns1.child.richland.cc.il.us. IN A 4.4.4.4 5 | ns2.child.richland.cc.il.us. IN A 5.5.5.5 6 | child.richland.cc.il.us. IN A 6.6.6.6 7 | chicago.child.richland.cc.il.us. IN A 7.7.7.7 8 | darwin.child.richland.cc.il.us. 1800 IN CNAME uranus.child.richland.cc.il.us. 9 | uranus.child.richland.cc.il.us. 1800 IN CNAME fusion.child.richland.cc.il.us. 10 | 11 | -------------------------------------------------------------------------------- /test/TestFiles/cc.il.us/zone_files/child.richland.cc.il.us..txt: -------------------------------------------------------------------------------- 1 | child.richland.cc.il.us. 3600 IN SOA ns1.child.richland.cc.il.us. james.richland.edu. 19122302 10800 3600 3600000 86400 2 | child.richland.cc.il.us. IN NS ns1.child.richland.cc.il.us. 3 | ns1.child.richland.cc.il.us. IN A 4.4.4.4 4 | ns2.child.richland.cc.il.us. IN A 5.5.5.5 5 | child.richland.cc.il.us. IN A 6.6.6.6 6 | chicago.child.richland.cc.il.us. IN A 7.7.7.8 7 | -------------------------------------------------------------------------------- /test/TestFiles/cc.il.us/zone_files/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "TopNameServers":[ 3 | "us.illinois.net." 4 | ], 5 | "ZoneFiles":[ 6 | { 7 | "FileName": "cc.il.us..txt", 8 | "NameServer": "us.illinois.net." 9 | }, 10 | { 11 | "FileName": "richland.cc.il.us..txt", 12 | "NameServer": "ns1.richland.cc.il.us.", 13 | "Origin": "richland.cc.il.us." 14 | }, 15 | { 16 | "FileName": "child.richland.cc.il.us..txt", 17 | "NameServer": "ns1.child.richland.cc.il.us." 18 | }, 19 | { 20 | "FileName": "child.richland.cc.il.us.-2.txt", 21 | "NameServer": "ns2.child.richland.cc.il.us." 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /test/TestFiles/cc.il.us/zone_files/richland.cc.il.us..txt: -------------------------------------------------------------------------------- 1 | ; <<>> DiG 9.11.3-1ubuntu1.11-Ubuntu <<>> AXFR richland.cc.il.us. @ns2.richland.edu. 2 | ;; global options: +cmd 3 | 4 | @ 43200 IN SOA ns1.richland.edu. james.richland.edu. 19122302 10800 3600 3600000 86400 5 | richland.cc.il.us. 43200 IN NS ns1.illinois.net. 6 | richland.cc.il.us. 43200 IN NS ns1.richland.cc.il.us. 7 | richland.cc.il.us. 43200 IN NS ns1.richland.edu. 8 | richland.cc.il.us. 43200 IN NS ns2.illinois.net. 9 | richland.cc.il.us. 43200 IN NS ns2.richland.cc.il.us. 10 | richland.cc.il.us. 43200 IN NS ns2.richland.edu. 11 | richland.cc.il.us. 43200 IN A 64.107.104.27 12 | richland.cc.il.us. 43200 IN MX 10 smtp.richland.edu. 13 | richland.cc.il.us. 43200 IN TXT "v=spf1 a mx ~all" 14 | child.richland.cc.il.us. 4500 IN NS ns1.child.richland.cc.il.us. 15 | child.richland.cc.il.us. 4500 IN NS ns2.child.richland.cc.il.us. 16 | ns1.child.richland.cc.il.us. 4500 IN A 4.4.4.4 17 | ns2.child.richland.cc.il.us. 4500 IN A 5.5.5.5 18 | ds3.richland.cc.il.us. 43200 IN CNAME gw1.richland.cc.il.us. 19 | foo.cc.il.us. 4500 IN A 10.10.10.10 20 | gw1.richland.cc.il.us. 43200 IN A 64.107.104.3 21 | gw2.richland.cc.il.us. 43200 IN A 64.107.104.4 22 | gw3.richland.cc.il.us. 43200 IN A 64.107.104.5 23 | gw4.richland.cc.il.us. 43200 IN A 64.107.104.59 24 | ns1.richland.cc.il.us. 43200 IN A 64.107.104.28 25 | ns1.richland.cc.il.us. 43200 IN A 64.107.104.29 26 | ns2.richland.cc.il.us. 43200 IN A 64.107.104.12 27 | 28 | ;; Query time: 64 msec 29 | ;; SERVER: 64.107.104.12#53(64.107.104.12) 30 | ;; WHEN: Thu May 14 15:13:43 PDT 2020 31 | ;; XFR size: 16 records (messages 1, bytes 415) 32 | -------------------------------------------------------------------------------- /test/TestFiles/choice/jobs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Domain": "a.very.bad.choice.com.", 4 | "SubDomain": false, 5 | "Properties": [ 6 | { 7 | "PropertyName": "InfiniteDNameRec" 8 | } 9 | ] 10 | }, 11 | { 12 | "Domain": "a.very.good.choice.com.", 13 | "SubDomain": false, 14 | "Properties": [ 15 | { 16 | "PropertyName": "InfiniteDNameRec" 17 | } 18 | ] 19 | }, 20 | { 21 | "Domain": "a.kinda.bad.choice.com.", 22 | "SubDomain": false, 23 | "Properties": [ 24 | { 25 | "PropertyName": "InfiniteDNameRec" 26 | } 27 | ] 28 | } 29 | ] -------------------------------------------------------------------------------- /test/TestFiles/choice/zone_files/NS1.com.txt: -------------------------------------------------------------------------------- 1 | bad.choice.com. 14400 IN SOA dasd.sda.net 2 | some.bad.choice.com. 14400 IN A 12.23.4.2 3 | very.bad.choice.com. 14400 IN DNAME very.very.bad.choice.com. 4 | kinda.bad.choice.com. 14400 IN DNAME not.good.choice.com. 5 | -------------------------------------------------------------------------------- /test/TestFiles/choice/zone_files/NS2.com.txt: -------------------------------------------------------------------------------- 1 | good.choice.com. 14400 IN SOA sda.edu 2 | a.good.choice.com. 14400 IN A 1.1.1.1 3 | very.good.choice.com. 14400 IN DNAME good.choice.com. 4 | not.good.choice.com. 14400 IN DNAME really.kinda.bad.choice.com. 5 | -------------------------------------------------------------------------------- /test/TestFiles/choice/zone_files/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "TopNameServers":[ 3 | "start.com." 4 | ], 5 | "ZoneFiles":[ 6 | { 7 | "FileName": "start.com.txt", 8 | "NameServer": "start.com." 9 | }, 10 | { 11 | "FileName": "NS1.com.txt", 12 | "NameServer": "NS1.com." 13 | }, 14 | { 15 | "FileName": "NS2.com.txt", 16 | "NameServer": "NS2.com." 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /test/TestFiles/choice/zone_files/start.com.txt: -------------------------------------------------------------------------------- 1 | com. 14400 IN SOA yes.yes 2 | bad.choice.com. 14400 IN NS NS1.com. 3 | good.choice.com. 14400 IN NS NS2.com. 4 | NS1.com. 14400 IN A 1.1.1.2 5 | NS2.com. 14400 IN A 1.1.1.3 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /test/TestFiles/infinite/jobs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Domain": "d.c.b.a.com.", 4 | "SubDomain": false, 5 | "Properties":[ 6 | { 7 | "PropertyName": "InfiniteDNameRec" 8 | } 9 | ] 10 | } 11 | ] -------------------------------------------------------------------------------- /test/TestFiles/infinite/zone_files/inf.net.txt: -------------------------------------------------------------------------------- 1 | com. 14400 IN SOA yes.yes 2 | a.com. 14400 IN A 1.2.3.4 3 | b.a.com. 14400 IN DNAME c.b.a.com. 4 | 5 | 6 | -------------------------------------------------------------------------------- /test/TestFiles/infinite/zone_files/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "TopNameServers":[ 3 | "inf.net." 4 | ], 5 | "ZoneFiles":[ 6 | { 7 | "FileName": "inf.net.txt", 8 | "NameServer": "inf.net." 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /test/TestFiles/integration_tests/simple_test/jobs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Domain": "foo.com.", 4 | "SubDomain": true, 5 | "Properties":[ 6 | { 7 | "PropertyName": "Rewrites", 8 | "Value": 4 9 | } 10 | ] 11 | }, 12 | { 13 | "Domain": "x.a.foo.com.", 14 | "SubDomain": false, 15 | "Properties":[ 16 | { 17 | "PropertyName": "ResponseValue", 18 | "Types": ["A"], 19 | "Value": ["1.2.3.4"] 20 | } 21 | ] 22 | } 23 | ] 24 | -------------------------------------------------------------------------------- /test/TestFiles/integration_tests/simple_test/output_expected.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Property": "Rewrites", 4 | "Query": "*.a.foo.com.", 5 | "Violation": { 6 | "ActualRewrites": 5, 7 | "MaxAllowedRewrites": 4 8 | } 9 | }, 10 | { 11 | "Property": "Rewrites", 12 | "Query": "~{ }.a.foo.com.", 13 | "Violation": { 14 | "ActualRewrites": 5, 15 | "MaxAllowedRewrites": 4 16 | } 17 | } 18 | ] -------------------------------------------------------------------------------- /test/TestFiles/integration_tests/simple_test/zone_files/foo.com.txt: -------------------------------------------------------------------------------- 1 | foo.com. 14400 IN SOA us.illinois.net. us-domain.illinois.net. 2018083000 14400 3600 2419200 14400 2 | 3 | foo.com. 14400 IN NS ns1.foo.com. 4 | foo.com. 14400 IN NS ns2.foo.com. 5 | foo.com. 14400 IN NS ns3.foo.com. 6 | ns1.foo.com. 14400 IN A 66.158.49.3 7 | ns2.foo.com. 14400 IN A 66.158.49.4 8 | a.foo.com. 14400 IN DNAME b.foo.com. 9 | b.foo.com. 14400 IN DNAME c.foo.com. 10 | c.foo.com. 14400 IN DNAME d.foo.com. 11 | d.foo.com. 14400 IN DNAME e.foo.com. 12 | *.e.foo.com. 14400 IN CNAME finally.foo.com. 13 | finally.foo.com. 14400 IN A 1.2.3.4 14 | finally.foo.com. 14400 IN CNAME finally1.foo.com. ;ignored 15 | -------------------------------------------------------------------------------- /test/TestFiles/integration_tests/simple_test/zone_files/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "TopNameServers":[ 3 | "us.illinois.net." 4 | ], 5 | "ZoneFiles":[ 6 | { 7 | "FileName": "foo.com.txt", 8 | "NameServer": "us.illinois.net." 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /test/TestFiles/parser_tests/test_parser.txt: -------------------------------------------------------------------------------- 1 | 0-24.net. 86400 IN SOA ns0.0-24.net. ho\(stmaster.0-24.net. 2020032302 43200 7200 1209600 86400 2 | 0-24.net. 86400 in ds 33276 10 2 (ea6157493f31285336187856a092c7a6041c0103ea4a61762c47fd161374bcdd ) 3 | 0-24.net. 86400 IN rrsig ds 8 2 86400 20190804054429 20190728043429 59540 net. Q7NqAuuAGQvYkMmoD4BcE9oYw2i9oSutcC4Omb7l5T9t+Fhi3qkwaQSHtu5qdZBHzZ2VMwMOdfHRZO41AJgUm4X9E1O/Z2yE0E6DUUkMTgRRE5ZNb3hubnM+3fEk6ZAZY21Z+VklqsGLYsMvh/U6yRq267Xe/65EXazdM653/N/7picDZE2qPnZd4pZ3azRJ9kz7K47t3Ga/oOV7h3Abhg== 4 | 0-24.net. 172800 in TXT "serving your domain :)" 5 | mybank IN DNAME bank 6 | foo A 1.1.1.1 7 | bar IN 300 A 2.2.2.2 8 | A 3.3.3.3 9 | -------------------------------------------------------------------------------- /test/TestFiles/short/jobs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Domain": "d.c.b.a.com.", 4 | "SubDomain": false, 5 | "Properties":[ 6 | { 7 | "PropertyName": "InfiniteDNameRec" 8 | } 9 | ] 10 | } 11 | ] -------------------------------------------------------------------------------- /test/TestFiles/short/zone_files/inf.net.txt: -------------------------------------------------------------------------------- 1 | $ORIGIN com. 2 | com. 14400 IN SOA yes.yes 3 | a.com. 14400 IN A 1.2.3.4 4 | b.a.com. 14400 IN DNAME a.com. 5 | 6 | 7 | -------------------------------------------------------------------------------- /test/TestFiles/short/zone_files/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "TopNameServers":[ 3 | "inf.net." 4 | ], 5 | "ZoneFiles":[ 6 | { 7 | "FileName": "inf.net.txt", 8 | "NameServer": "inf.net.", 9 | "Origin": "com." 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /test/bankcardTest.cpp: -------------------------------------------------------------------------------- 1 | #include "driver-test.h" 2 | #include 3 | 4 | BOOST_AUTO_TEST_SUITE(BankcardTestSuite) 5 | 6 | BOOST_AUTO_TEST_CASE(bankcard_test) 7 | { 8 | Driver driver; 9 | DriverTest dt; 10 | boost::filesystem::path directory("TestFiles"); 11 | std::ifstream metadataFile((directory / "bankcardExample" / "zone_files" / "metadata.json").string()); 12 | json metadata; 13 | metadataFile >> metadata; 14 | 15 | std::ifstream i((directory / "bankcardExample" / "jobs.json").string()); 16 | json j; 17 | i >> j; 18 | 19 | long total_rrs_parsed = driver.SetContext(metadata, (directory / "bankcardExample" / "zone_files").string(), false); 20 | BOOST_TEST(22 == total_rrs_parsed); 21 | auto types_to_count = dt.GetTypeToCountMap(driver); 22 | BOOST_TEST(2 == types_to_count["DNAME"]); 23 | BOOST_TEST(1 == types_to_count["CNAME"]); 24 | BOOST_TEST(6 == types_to_count["A"]); 25 | BOOST_TEST(6 == types_to_count["NS"]); 26 | BOOST_TEST(5 == types_to_count["SOA"]); 27 | BOOST_TEST(2 == types_to_count["AAAA"]); 28 | 29 | for (auto &user_job : j) { 30 | driver.SetJob(user_job); 31 | driver.GenerateECsAndCheckProperties(); 32 | } 33 | 34 | // We check for two properties: 1. Response Consistency 35 | // 2. whether support.mybankcard.com will always get the ip address 204.58.233.244 36 | // Both of them should be violated 37 | BOOST_TEST(2 == dt.GetNumberofViolations(driver)); 38 | 39 | } 40 | 41 | BOOST_AUTO_TEST_SUITE_END() -------------------------------------------------------------------------------- /test/driver-test.h: -------------------------------------------------------------------------------- 1 | #ifndef DRIVER_TEST_H_ 2 | #define DRIVER_TEST_H_ 3 | #include "../src/driver.h" 4 | #include 5 | #include 6 | 7 | class DriverTest 8 | { 9 | 10 | public: 11 | int GetNumberofLabelGraphVertices(Driver &d) 12 | { 13 | return static_cast(num_vertices(d.label_graph_)); 14 | } 15 | 16 | int GetNumberofLabelGraphEdges(Driver &d) 17 | { 18 | return static_cast(num_edges(d.label_graph_)); 19 | } 20 | 21 | int GetNumberofResourceRecordsParsed(Driver &d, string file, string nameserver) 22 | { 23 | return d.ParseZoneFileAndExtendGraphs(file, nameserver, "", false); 24 | } 25 | 26 | int GetNumberofViolations(Driver &d) 27 | { 28 | return static_cast(d.property_violations_.size()); 29 | } 30 | 31 | boost::unordered_map GetTypeToCountMap(Driver &d) 32 | { 33 | return d.context_.type_to_rr_count; 34 | } 35 | 36 | const zone::Graph &GetLatestZone(Driver &d) 37 | { 38 | return d.context_.zoneId_to_zone.at(d.context_.zoneId_counter_); 39 | } 40 | 41 | interpretation::Graph CreateAnInterpretationGraph(Driver &d, const EC ec) 42 | { 43 | return interpretation::Graph(ec, d.context_); 44 | } 45 | 46 | void GenerateLabelGraphDotFile(Driver &d, string filepath) 47 | { 48 | d.label_graph_.GenerateDotFile(filepath); 49 | } 50 | }; 51 | 52 | #endif -------------------------------------------------------------------------------- /test/ec-test.cpp: -------------------------------------------------------------------------------- 1 | #include "../src/equivalence-class.h" 2 | #include "../src/utils.h" 3 | #include 4 | 5 | BOOST_AUTO_TEST_SUITE(EcTestSuite) 6 | 7 | BOOST_AUTO_TEST_CASE(ec_equality1) 8 | { 9 | std::bitset bs; 10 | bs.set(RRType::A); 11 | bs.set(RRType::TXT); 12 | 13 | EC ec1; 14 | ec1.name = LabelUtils::StringToLabels("a.b.c."); 15 | ec1.excluded = {}; 16 | ec1.nonExistent = false; 17 | ec1.rrTypes = bs; 18 | 19 | EC ec2; 20 | ec2.name = LabelUtils::StringToLabels("a.b.c."); 21 | ec2.excluded = {}; 22 | ec2.nonExistent = false; 23 | ec2.rrTypes = bs; 24 | 25 | BOOST_CHECK(ec1 == ec2); 26 | } 27 | 28 | BOOST_AUTO_TEST_CASE(ec_inequality1) 29 | { 30 | EC ec1; 31 | ec1.name = LabelUtils::StringToLabels("a.b.c."); 32 | ec1.excluded = {}; 33 | ec1.nonExistent = false; 34 | 35 | EC ec2; 36 | ec2.name = LabelUtils::StringToLabels("b.c."); 37 | ec2.excluded = {}; 38 | ec2.nonExistent = false; 39 | 40 | BOOST_CHECK(!(ec1 == ec2)); 41 | } 42 | 43 | BOOST_AUTO_TEST_CASE(ec_inequality2) 44 | { 45 | std::bitset bs1; 46 | bs1.set(RRType::A); 47 | 48 | std::bitset bs2; 49 | bs2.set(RRType::A); 50 | bs2.set(RRType::TXT); 51 | 52 | EC ec1; 53 | ec1.name = LabelUtils::StringToLabels("a.b.c."); 54 | ec1.excluded = {}; 55 | ec1.nonExistent = false; 56 | ec1.rrTypes = bs1; 57 | 58 | EC ec2; 59 | ec2.name = LabelUtils::StringToLabels("a.b.c."); 60 | ec2.excluded = {}; 61 | ec2.nonExistent = false; 62 | ec2.rrTypes = bs2; 63 | 64 | BOOST_CHECK(!(ec1 == ec2)); 65 | } 66 | 67 | BOOST_AUTO_TEST_CASE(ec_inequality3) 68 | { 69 | std::bitset bs1; 70 | bs1.set(RRType::A); 71 | bs1.set(RRType::TXT); 72 | 73 | std::bitset bs2; 74 | bs2.set(RRType::A); 75 | 76 | EC ec1; 77 | ec1.name = LabelUtils::StringToLabels("a.b.c."); 78 | ec1.excluded = {}; 79 | ec1.nonExistent = false; 80 | ec1.rrTypes = bs1; 81 | 82 | EC ec2; 83 | ec2.name = LabelUtils::StringToLabels("a.b.c."); 84 | ec2.excluded = {}; 85 | ec2.nonExistent = false; 86 | ec2.rrTypes = bs2; 87 | 88 | BOOST_CHECK(!(ec1 == ec2)); 89 | } 90 | 91 | BOOST_AUTO_TEST_SUITE_END() -------------------------------------------------------------------------------- /test/integration-test.cpp: -------------------------------------------------------------------------------- 1 | #include "driver-test.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace fs = boost::filesystem; 9 | 10 | BOOST_AUTO_TEST_SUITE(IntegrationTestSuite) 11 | 12 | BOOST_AUTO_TEST_CASE(integration_test) 13 | { 14 | Driver driver; 15 | // DriverTest dt; 16 | fs::path directory("TestFiles"); 17 | auto test_directory = directory / "integration_tests"; 18 | 19 | fs::directory_iterator it{test_directory}; 20 | while (it != fs::directory_iterator{}) { 21 | auto entry = *it++; 22 | if (fs::is_directory(entry)) { 23 | auto test_directory = entry.path(); 24 | auto zone_path = test_directory / "zone_files"; 25 | auto metadata_path = zone_path / "metadata.json"; 26 | auto output_path = test_directory / "output.json"; 27 | auto expected_path = test_directory / "output_expected.json"; 28 | auto jobs_path = test_directory / "jobs.json"; 29 | auto lint_expected_path = test_directory / "lint_expected.json"; 30 | 31 | // read in the metadata file 32 | std::ifstream metadataFile(metadata_path.string()); 33 | json metadata; 34 | metadataFile >> metadata; 35 | 36 | // read in the jobs file 37 | std::ifstream i(jobs_path.string()); 38 | json j; 39 | i >> j; 40 | 41 | fstream fs; 42 | fs.open("lint.json", ios::out); 43 | fs << "[\n"; 44 | fs.close(); 45 | 46 | driver.SetContext(metadata, zone_path.string(), true); 47 | 48 | fs.open("lint.json", ios::app); 49 | fs << "\n]"; 50 | fs.close(); 51 | 52 | for (auto &user_job : j) { 53 | driver.SetJob(user_job); 54 | driver.GenerateECsAndCheckProperties(); 55 | } 56 | 57 | driver.WriteViolationsToFile(output_path.string()); 58 | 59 | // compare the actual output with the expected output 60 | std::ifstream actual(output_path.string()); 61 | std::string s1((std::istreambuf_iterator(actual)), std::istreambuf_iterator()); 62 | 63 | std::ifstream expected(expected_path.string()); 64 | std::string s2((std::istreambuf_iterator(expected)), std::istreambuf_iterator()); 65 | 66 | BOOST_CHECK_EQUAL(s1, s2); 67 | 68 | std::ifstream actual_lint("lint.json"); 69 | json lint; 70 | actual_lint >> lint; 71 | 72 | BOOST_CHECK_EQUAL(lint[0]["Violation"], "CNAME AND OTHER TYPES"); 73 | BOOST_CHECK_EQUAL(lint[1]["Violation"], "Missing Glue Record"); 74 | BOOST_CHECK_EQUAL(lint.size(), 2); 75 | 76 | actual_lint.close(); 77 | fs::remove("lint.json"); 78 | } 79 | } 80 | } 81 | 82 | BOOST_AUTO_TEST_CASE(label_graph_dot) 83 | { 84 | Driver driver; 85 | DriverTest dt; 86 | boost::filesystem::path directory("TestFiles"); 87 | std::ifstream metadataFile((directory / "cc.il.us" / "zone_files" / "metadata.json").string()); 88 | json metadata; 89 | metadataFile >> metadata; 90 | 91 | long total_rrs_parsed = driver.SetContext(metadata, (directory / "cc.il.us" / "zone_files").string(), false); 92 | 93 | auto expected_path = directory / "cc.il.us" / "label_graph_expected.dot"; 94 | auto actual_path = directory / "cc.il.us" / "label_graph_actual.dot"; 95 | 96 | dt.GenerateLabelGraphDotFile(driver, actual_path.string()); 97 | 98 | std::ifstream actual(actual_path.string()); 99 | std::string s1((std::istreambuf_iterator(actual)), std::istreambuf_iterator()); 100 | 101 | std::ifstream expected(expected_path.string()); 102 | std::string s2((std::istreambuf_iterator(expected)), std::istreambuf_iterator()); 103 | 104 | BOOST_CHECK_EQUAL(s1, s2); 105 | actual.close(); 106 | boost::filesystem::remove(actual_path); 107 | } 108 | 109 | 110 | BOOST_AUTO_TEST_SUITE_END() -------------------------------------------------------------------------------- /test/label-graph-test.cpp: -------------------------------------------------------------------------------- 1 | #include "driver-test.h" 2 | #include 3 | 4 | BOOST_AUTO_TEST_SUITE(ParsingTestSuite) 5 | 6 | void CheckClosestEncloser(string d1, string d2, string d3, string query, string expectedLabel) 7 | { 8 | label::Graph labelGraph; 9 | zone::Graph zoneGraph(0); 10 | 11 | for (int i = 0; i < RRType::N; i++) { 12 | string type = TypeUtils::TypeToString(static_cast(i)); 13 | if (type != "CNAME") { 14 | ResourceRecord r1(d1, type, 1, 10, ""); 15 | auto [code1, id1] = zoneGraph.AddResourceRecord(r1); 16 | if (code1 == zone::RRAddCode::SUCCESS) 17 | labelGraph.AddResourceRecord(r1, 0, id1.get()); 18 | 19 | ResourceRecord r2(d2, type, 1, 10, ""); 20 | auto [code2, id2] = zoneGraph.AddResourceRecord(r2); 21 | if (code2 == zone::RRAddCode::SUCCESS) 22 | labelGraph.AddResourceRecord(r2, 0, id2.get()); 23 | 24 | ResourceRecord r3(d3, type, 1, 10, ""); 25 | auto [code3, id3] = zoneGraph.AddResourceRecord(r3); 26 | if (code3 == zone::RRAddCode::SUCCESS) 27 | labelGraph.AddResourceRecord(r3, 0, id3.get()); 28 | 29 | auto enclosers = labelGraph.ClosestEnclosers(query); 30 | auto x = labelGraph[enclosers[0].first]; 31 | BOOST_CHECK_EQUAL(expectedLabel, x.name.get()); 32 | } 33 | 34 | } 35 | } 36 | 37 | BOOST_AUTO_TEST_CASE(label_graph_building) 38 | { 39 | Driver d; 40 | DriverTest dt; 41 | boost::filesystem::path directory("TestFiles"); 42 | std::string test_file = (directory / "parser_tests" / "test_parser.txt").string(); 43 | BOOST_CHECK_EQUAL(8, dt.GetNumberofResourceRecordsParsed(d, test_file, "ns1.test.")); 44 | BOOST_CHECK_EQUAL(7, dt.GetNumberofLabelGraphVertices(d)); 45 | BOOST_CHECK_EQUAL(7, dt.GetNumberofLabelGraphEdges(d)); 46 | } 47 | 48 | BOOST_AUTO_TEST_CASE(label_graph_search) 49 | { 50 | label::Graph labelGraph; 51 | zone::Graph zoneGraph(0); 52 | 53 | ResourceRecord r1("foo.com.", "A", 1, 10, "1.2.3.4"); 54 | auto [code1, id1] = zoneGraph.AddResourceRecord(r1); 55 | labelGraph.AddResourceRecord(r1, 0, id1.get()); 56 | 57 | auto enclosers = labelGraph.ClosestEnclosers("foo.com."); 58 | auto node = labelGraph[enclosers[0].first]; 59 | BOOST_CHECK_EQUAL(1, node.rrtypes_available.count()); 60 | 61 | ResourceRecord r2("foo.com", "NS", 1, 10, "ns1.foo.com"); 62 | auto [code2, id2] = zoneGraph.AddResourceRecord(r2); 63 | labelGraph.AddResourceRecord(r2, 0, id2.get()); 64 | 65 | enclosers = labelGraph.ClosestEnclosers("foo.com"); 66 | node = labelGraph[enclosers[0].first]; 67 | BOOST_CHECK_EQUAL(2, node.rrtypes_available.count()); 68 | } 69 | 70 | BOOST_AUTO_TEST_CASE(label_graph_dnames) 71 | { 72 | label::Graph labelGraph; 73 | zone::Graph zoneGraph(0); 74 | 75 | ResourceRecord r1("foo.com", "A", 1, 10, "1.2.3.4"); 76 | auto [code1, id1] = zoneGraph.AddResourceRecord(r1); 77 | labelGraph.AddResourceRecord(r1, 0, id1.get()); 78 | 79 | ResourceRecord r2("bar.com", "DNAME", 1, 10, "foo.com"); 80 | auto [code2, id2] = zoneGraph.AddResourceRecord(r2); 81 | labelGraph.AddResourceRecord(r2, 0, id2.get()); 82 | 83 | ResourceRecord r3("foo.com", "DNAME", 1, 10, "bar.com"); 84 | auto [code3, id3] = zoneGraph.AddResourceRecord(r3); 85 | labelGraph.AddResourceRecord(r3, 0, id3.get()); 86 | 87 | auto enclosers = labelGraph.ClosestEnclosers("a.foo.com"); 88 | BOOST_CHECK_EQUAL(2, enclosers.size()); 89 | auto x = labelGraph[enclosers[0].first]; 90 | BOOST_CHECK_EQUAL("foo", x.name.get()); 91 | BOOST_CHECK_EQUAL(2, x.rrtypes_available.count()); 92 | BOOST_CHECK_EQUAL("bar", labelGraph[enclosers[1].first].name.get()); 93 | } 94 | 95 | BOOST_AUTO_TEST_CASE(label_graph_duplicate_dnames) 96 | { 97 | label::Graph labelGraph; 98 | zone::Graph zoneGraphA(0); 99 | zone::Graph zoneGraphB(1); 100 | 101 | ResourceRecord r1("foo.com", "A", 1, 10, "1.2.3.4"); 102 | auto [code1, id1] = zoneGraphA.AddResourceRecord(r1); 103 | labelGraph.AddResourceRecord(r1, 0, id1.get()); 104 | 105 | ResourceRecord r2("bar.foo.com", "TXT", 1, 10, "Test Duplicate DNAME Records"); 106 | auto [code2, id2] = zoneGraphA.AddResourceRecord(r2); 107 | labelGraph.AddResourceRecord(r2, 0, id2.get()); 108 | 109 | ResourceRecord r3("bar.foo.com", "DNAME", 1, 10, "foo.com"); 110 | auto [code3, id3] = zoneGraphA.AddResourceRecord(r3); 111 | labelGraph.AddResourceRecord(r3, 0, id3.get()); 112 | 113 | ResourceRecord r4("bar.foo.com", "DNAME", 1, 10, "foo.com"); 114 | auto [code4, id4] = zoneGraphB.AddResourceRecord(r4); 115 | labelGraph.AddResourceRecord(r4, 0, id4.get()); 116 | 117 | BOOST_CHECK_EQUAL(4, num_edges(labelGraph)); 118 | 119 | ResourceRecord r5("baz.foo.com", "TXT", 1, 10, "Test Child DNAME Record"); 120 | auto [code5, id5] = zoneGraphA.AddResourceRecord(r5); 121 | labelGraph.AddResourceRecord(r5, 0, id5.get()); 122 | 123 | // There is already an edge from foo to baz (parent-child) because of above TXT record. 124 | // The following DNAME edge should not be skipped. Only duplicate DNAME edges should not be added. 125 | ResourceRecord r6("foo.com", "DNAME", 1, 10, "baz.foo.com"); 126 | auto [code6, id6] = zoneGraphA.AddResourceRecord(r6); 127 | labelGraph.AddResourceRecord(r6, 0, id6.get()); 128 | 129 | ResourceRecord r7("foo.com", "DNAME", 1, 10, "baz.foo.com"); 130 | auto [code7, id7] = zoneGraphB.AddResourceRecord(r7); 131 | labelGraph.AddResourceRecord(r7, 0, id7.get()); 132 | 133 | BOOST_CHECK_EQUAL(6, num_edges(labelGraph)); 134 | } 135 | 136 | BOOST_AUTO_TEST_CASE(label_graph_examples) 137 | { 138 | CheckClosestEncloser("com", "a.com", "b.a.com", "c.b.a.com", "b"); 139 | CheckClosestEncloser("org", "com", "net", "a.b.c.org", "org"); 140 | CheckClosestEncloser("a.org", "aa.org", "aaa.org", "aaa.org", "aaa"); 141 | CheckClosestEncloser("a.org", "aa.org", "aaa.org", "aaaa.org", "org"); 142 | CheckClosestEncloser("com", "com", "com", "com", "com"); 143 | } 144 | 145 | BOOST_AUTO_TEST_CASE(label_graph_many_children) 146 | { 147 | label::Graph labelGraph; 148 | zone::Graph zoneGraph(0); 149 | 150 | int max = kHashMapThreshold + 50; 151 | 152 | // exceed the hashmap threshold for the TLD 153 | for (int i = 0; i <= max; i++) { 154 | string domain = "d" + std::to_string(i); 155 | ResourceRecord r(domain, "TXT", 1, 10, domain); 156 | auto [code, id] = zoneGraph.AddResourceRecord(r); 157 | labelGraph.AddResourceRecord(r, 0, id.get()); 158 | } 159 | 160 | // exceed the threshold for a second level domain 161 | for (int i = 0; i <= max; i++) { 162 | string domain = "d" + std::to_string(i) + ".d0"; 163 | ResourceRecord r(domain, "TXT", 1, 10, domain); 164 | auto [code, id] = zoneGraph.AddResourceRecord(r); 165 | labelGraph.AddResourceRecord(r, 0, id.get()); 166 | } 167 | 168 | for (int i = 0; i <= max; i++) { 169 | string domain = "d" + std::to_string(i); 170 | auto enclosers = labelGraph.ClosestEnclosers(domain); 171 | auto x = labelGraph[enclosers[0].first]; 172 | BOOST_CHECK_EQUAL(domain, x.name.get()); 173 | BOOST_CHECK_EQUAL(1, x.rrtypes_available.count()); 174 | } 175 | 176 | for (int i = 0; i <= max; i++) { 177 | string domain = "d" + std::to_string(i) + ".d0"; 178 | auto enclosers = labelGraph.ClosestEnclosers(domain); 179 | auto x = labelGraph[enclosers[0].first]; 180 | BOOST_CHECK_EQUAL("d" + std::to_string(i), x.name.get()); 181 | BOOST_CHECK_EQUAL(1, x.rrtypes_available.count()); 182 | } 183 | } 184 | 185 | BOOST_AUTO_TEST_SUITE_END() -------------------------------------------------------------------------------- /test/main-example-test.cpp: -------------------------------------------------------------------------------- 1 | #include "driver-test.h" 2 | #include 3 | 4 | BOOST_AUTO_TEST_SUITE(MainExampleTestSuite) 5 | 6 | BOOST_AUTO_TEST_CASE(example_test_jobs) 7 | { 8 | Driver driver; 9 | DriverTest dt; 10 | boost::filesystem::path directory("TestFiles"); 11 | std::ifstream metadataFile((directory / "cc.il.us" / "zone_files" / "metadata.json").string()); 12 | json metadata; 13 | metadataFile >> metadata; 14 | 15 | std::ifstream i((directory / "cc.il.us" / "jobs.json").string()); 16 | json j; 17 | i >> j; 18 | 19 | long total_rrs_parsed = driver.SetContext(metadata, (directory / "cc.il.us" / "zone_files").string(), false); 20 | 21 | BOOST_TEST(140 == total_rrs_parsed); 22 | BOOST_TEST(70 == dt.GetNumberofLabelGraphVertices(driver)); 23 | BOOST_TEST(70 == dt.GetNumberofLabelGraphEdges(driver)); 24 | 25 | boost::unordered_map types_to_count = dt.GetTypeToCountMap(driver); 26 | 27 | BOOST_TEST(1 == types_to_count["Wildcard"]); 28 | BOOST_TEST(1 == types_to_count["DNAME"]); 29 | BOOST_TEST(5 == types_to_count["CNAME"]); 30 | 31 | long total_ecs = 0; 32 | 33 | for (auto &user_job : j) { 34 | driver.SetJob(user_job); 35 | driver.GenerateECsAndCheckProperties(); 36 | total_ecs += driver.GetECCountForCurrentJob(); 37 | } 38 | BOOST_TEST(176 == total_ecs); 39 | BOOST_TEST(19 == dt.GetNumberofViolations(driver)); 40 | 41 | EC test_ec; 42 | test_ec.name = LabelUtils::StringToLabels("ds3.trial.cc.il.us."); 43 | test_ec.rrTypes.set(RRType::A); 44 | interpretation::Graph ig = dt.CreateAnInterpretationGraph(driver, test_ec); 45 | ig.GenerateDotFile("ig.dot"); 46 | 47 | auto expected_path = directory / "cc.il.us" / "ig_expected.dot"; 48 | std::ifstream actual("ig.dot"); 49 | std::string s1((std::istreambuf_iterator(actual)), std::istreambuf_iterator()); 50 | 51 | std::ifstream expected(expected_path.string()); 52 | std::string s2((std::istreambuf_iterator(expected)), std::istreambuf_iterator()); 53 | 54 | BOOST_CHECK_EQUAL(s1, s2); 55 | actual.close(); 56 | boost::filesystem::remove("ig.dot"); 57 | } 58 | 59 | BOOST_AUTO_TEST_CASE(example_test_default_jobs) 60 | { 61 | Driver driver; 62 | DriverTest dt; 63 | boost::filesystem::path directory("TestFiles"); 64 | std::ifstream metadataFile((directory / "cc.il.us" / "zone_files" / "metadata.json").string()); 65 | json metadata; 66 | metadataFile >> metadata; 67 | 68 | long total_rrs_parsed = driver.SetContext(metadata, (directory / "cc.il.us" / "zone_files").string(), false); 69 | 70 | BOOST_TEST(140 == total_rrs_parsed); 71 | BOOST_TEST(70 == dt.GetNumberofLabelGraphVertices(driver)); 72 | BOOST_TEST(70 == dt.GetNumberofLabelGraphEdges(driver)); 73 | 74 | boost::unordered_map types_to_count = dt.GetTypeToCountMap(driver); 75 | 76 | BOOST_TEST(1 == types_to_count["Wildcard"]); 77 | BOOST_TEST(1 == types_to_count["DNAME"]); 78 | BOOST_TEST(5 == types_to_count["CNAME"]); 79 | 80 | string x = "."; 81 | driver.SetJob(x); 82 | driver.GenerateECsAndCheckProperties(); 83 | BOOST_TEST(167 == driver.GetECCountForCurrentJob()); 84 | BOOST_TEST(58 == dt.GetNumberofViolations(driver)); 85 | } 86 | 87 | BOOST_AUTO_TEST_SUITE_END() -------------------------------------------------------------------------------- /test/script.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import logging 3 | import json 4 | import sys 5 | import argparse 6 | 7 | # Setting up a logger 8 | level = logging.INFO 9 | logger = logging.getLogger('logger') 10 | logger.setLevel(level) 11 | ch = logging.StreamHandler() 12 | ch.setLevel(level) 13 | formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 14 | ch.setFormatter(formatter) 15 | logger.addHandler(ch) 16 | 17 | # Some global variables 18 | query_name = '' 19 | save_dir = '.' 20 | visited_ns = [] 21 | visited_domain = [] 22 | 23 | def parse(zonefile): 24 | records = [] 25 | lines = zonefile.rstrip().split("\n") 26 | for line in lines: 27 | if line.rstrip() != "" and line[0]!=';': 28 | rr = line.split() 29 | records.append(rr) 30 | return records 31 | 32 | def dump(name, zonefile, ns, metadata): 33 | filename = name+'.txt' 34 | abs_filename = os.path.join(save_dir, filename) 35 | with open(abs_filename, mode='w') as f: 36 | f.write(zonefile) 37 | logger.debug("dump(): dumped to file "+name+'.txt') 38 | metadata['ZoneFiles'].append({'FileName':name+'.txt', 'NameServer':ns}) 39 | 40 | def zone_transfer(domain, ns, metadata, c, top): 41 | 42 | if ns not in visited_ns: 43 | visited_ns.append(ns) 44 | else: 45 | return 46 | 47 | logger.info('dig axfr '+domain+' @'+ns) 48 | process = subprocess.Popen(['dig', 'axfr', domain, '@'+ns], 49 | stdout = subprocess.PIPE, 50 | stderr = subprocess.PIPE, 51 | universal_newlines=True) 52 | stdout, stderr = process.communicate() 53 | if stderr != "": 54 | logger.error("Encountered an error while running dig: " + stderr) 55 | return False 56 | 57 | name = domain + '-' + str(c) 58 | c += 1 59 | records = parse(stdout) 60 | soa_mname = '' 61 | 62 | if records != []: 63 | for record in records: 64 | if record[3] == 'SOA': 65 | if top == True: 66 | soa_mname = record[4] 67 | if soa_mname not in metadata['TopNameServers']: 68 | metadata['TopNameServers'].append(soa_mname) 69 | if soa_mname in visited_domain: 70 | return 71 | else: 72 | visited_ns.append(soa_mname) 73 | 74 | if records != []: 75 | if soa_mname != '': 76 | dump(name, stdout, soa_mname, metadata) 77 | else: 78 | dump(name, stdout, ns, metadata) 79 | for record in records: 80 | if record[3] == 'NS': 81 | zone_transfer(domain, record[4], metadata, c, False) 82 | if record[3] == 'CNAME': 83 | download(record[4], metadata, False) 84 | return True 85 | else: 86 | return False 87 | 88 | def download(domain, metadata, top): 89 | 90 | if domain in visited_domain: 91 | return 92 | else: 93 | visited_domain.append(domain) 94 | 95 | logger.info('dig +short ns '+domain) 96 | process = subprocess.Popen(['dig', '+short', 'ns', domain], 97 | stdout = subprocess.PIPE, 98 | stderr = subprocess.PIPE, 99 | universal_newlines = True) 100 | 101 | stdout, stderr = process.communicate() 102 | 103 | if stderr != "": 104 | logger.error("Encountered an error while running dig: " + stderr) 105 | return 106 | 107 | nameservers = stdout.rstrip().split("\n") 108 | for ns in nameservers: 109 | if ns.rstrip() == '': 110 | continue 111 | logger.info('trying to transfer from '+ns) 112 | if top == True: 113 | success = zone_transfer(domain, ns, metadata, 0, True) 114 | else: 115 | success = zone_transfer(domain, ns, metadata, 0, False) 116 | if success == True: 117 | logger.info('zone transfer successful: '+ns) 118 | return 119 | logger.info('zone transfer failed: '+ns) 120 | 121 | def main(): 122 | parser = argparse.ArgumentParser(description='Download a set of zone files') 123 | parser.add_argument('domain_name', metavar='NAME', type=str, 124 | help='The domain name you are querying') 125 | parser.add_argument('save_directory', metavar='DIR', type=str, 126 | help='Where you want to save your zone files') 127 | args = parser.parse_args() 128 | query_name = args.domain_name 129 | save_dir = args.save_directory 130 | 131 | # Testing ############# 132 | # d1 = "ucla.edu" 133 | # d2 = "zonetransfer.me" 134 | # query_name = d2 135 | # save_dir = '.' 136 | ####################### 137 | 138 | metadata = {'TopNameServers':[], 'ZoneFiles':[]} 139 | download(query_name, metadata, True) 140 | with open(save_dir+'/'+'metadata.json', mode='w') as metafile: 141 | metafile.write(json.dumps(metadata, indent=4)) 142 | 143 | if __name__ == "__main__": 144 | main() 145 | -------------------------------------------------------------------------------- /test/test.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {BD35F99A-458A-4D58-8F11-3A0222979FFF} 24 | Win32Proj 25 | test 26 | 10.0 27 | test 28 | 29 | 30 | 31 | Application 32 | true 33 | v143 34 | Unicode 35 | 36 | 37 | Application 38 | false 39 | v143 40 | true 41 | Unicode 42 | 43 | 44 | Application 45 | true 46 | v143 47 | Unicode 48 | 49 | 50 | Application 51 | false 52 | v143 53 | true 54 | Unicode 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | true 76 | 77 | 78 | true 79 | 80 | 81 | false 82 | 83 | 84 | false 85 | 86 | 87 | 88 | 89 | 90 | Level3 91 | Disabled 92 | true 93 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 94 | true 95 | stdcpp17 96 | 4996 97 | 98 | 99 | Console 100 | true 101 | 102 | 103 | 104 | 105 | 106 | 107 | Level3 108 | Disabled 109 | true 110 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 111 | true 112 | 113 | 114 | Console 115 | true 116 | 117 | 118 | 119 | 120 | 121 | 122 | Level3 123 | MaxSpeed 124 | true 125 | true 126 | true 127 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 128 | true 129 | 130 | 131 | Console 132 | true 133 | true 134 | true 135 | 136 | 137 | 138 | 139 | 140 | 141 | Level3 142 | MaxSpeed 143 | true 144 | true 145 | true 146 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 147 | true 148 | stdcpp17 149 | 150 | 151 | Console 152 | true 153 | true 154 | true 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | {d2a89e18-94e6-474f-b0eb-f0881a5478b1} 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | Always 181 | 182 | 183 | -------------------------------------------------------------------------------- /test/tester.cpp: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_MODULE TESTER 2 | #include -------------------------------------------------------------------------------- /test/tests.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /test/util-test.cpp: -------------------------------------------------------------------------------- 1 | #include "../src/resource-record.h" 2 | #include "../src/utils.h" 3 | #include 4 | 5 | BOOST_AUTO_TEST_SUITE(UtilTestSuite) 6 | 7 | bool CheckSubdomain(string domain, string subdomain) 8 | { 9 | auto d = LabelUtils::StringToLabels(domain); 10 | auto sd = LabelUtils::StringToLabels(subdomain); 11 | return LabelUtils::SubDomainCheck(d, sd); 12 | } 13 | 14 | BOOST_AUTO_TEST_CASE(type_conversions) 15 | { 16 | for (int i = 0; i < RRType::N; i++) { 17 | std::bitset b; 18 | b[i] = true; 19 | BOOST_CHECK_EQUAL(i, static_cast(TypeUtils::StringToType(TypeUtils::TypesToString(b)))); 20 | } 21 | } 22 | 23 | BOOST_AUTO_TEST_CASE(label_conversions_empty) 24 | { 25 | auto empty = LabelUtils::StringToLabels(""); 26 | BOOST_CHECK_EQUAL(empty.size(), 0); 27 | } 28 | 29 | BOOST_AUTO_TEST_CASE(label_conversions_root) 30 | { 31 | auto empty = LabelUtils::StringToLabels("."); 32 | BOOST_CHECK_EQUAL(empty.size(), 0); 33 | } 34 | 35 | BOOST_AUTO_TEST_CASE(label_conversions) 36 | { 37 | NodeLabel l1("uk"); 38 | NodeLabel l2("co"); 39 | vector domain_name{l1, l2}; 40 | 41 | auto dn = LabelUtils::LabelsToString(domain_name); 42 | BOOST_CHECK_EQUAL("co.uk.", dn); 43 | 44 | auto labels = LabelUtils::StringToLabels(dn); 45 | BOOST_CHECK_EQUAL(labels[0].get(), "uk"); 46 | BOOST_CHECK_EQUAL(labels[1].get(), "co"); 47 | } 48 | 49 | BOOST_AUTO_TEST_CASE(subdomain_check) 50 | { 51 | BOOST_TEST(CheckSubdomain(".", "com.")); 52 | BOOST_TEST(CheckSubdomain(".", "org.")); 53 | BOOST_TEST(CheckSubdomain("", "google.com.")); 54 | BOOST_TEST(CheckSubdomain("bing.com", "search.bing.com")); 55 | BOOST_TEST(!CheckSubdomain("google.com", "com.")); 56 | BOOST_TEST(!CheckSubdomain("google.com", "microsoft.com.")); 57 | BOOST_TEST(!CheckSubdomain("google.com", ".")); 58 | BOOST_TEST(!CheckSubdomain("google.com", "org")); 59 | BOOST_TEST(!CheckSubdomain("a.b.c", "a.c.c")); 60 | } 61 | 62 | BOOST_AUTO_TEST_CASE(flyweight_test) 63 | { 64 | string s = "test"; 65 | 66 | NodeLabel nl; 67 | nl.set(s); 68 | BOOST_CHECK_EQUAL(nl.get(), s); 69 | 70 | NodeLabel nl1(s); 71 | BOOST_ASSERT(nl == nl1); 72 | } 73 | 74 | BOOST_AUTO_TEST_SUITE_END() -------------------------------------------------------------------------------- /test/zone-graph-test.cpp: -------------------------------------------------------------------------------- 1 | #include "driver-test.h" 2 | #include 3 | 4 | BOOST_AUTO_TEST_SUITE(ZoneGraphTestSuite) 5 | 6 | BOOST_AUTO_TEST_CASE(zone_graph_building) 7 | { 8 | Driver d; 9 | DriverTest dt; 10 | boost::filesystem::path directory("TestFiles"); 11 | std::string test_file = (directory / "parser_tests" / "test_parser.txt").string(); 12 | cout << test_file << endl; 13 | BOOST_TEST(8 == dt.GetNumberofResourceRecordsParsed(d, test_file, "ns1.test.")); 14 | const zone::Graph &g = dt.GetLatestZone(d); 15 | BOOST_TEST(6 == num_vertices(g)); 16 | BOOST_TEST(5 == num_edges(g)); 17 | } 18 | 19 | BOOST_AUTO_TEST_CASE(multiple_CNAME) 20 | { 21 | zone::Graph zoneGraph(0); 22 | ResourceRecord r1("foo.com", "CNAME", 1, 10, "bar.com"); 23 | auto [code1, id1] = zoneGraph.AddResourceRecord(r1); 24 | BOOST_CHECK(code1 == zone::RRAddCode::SUCCESS); 25 | 26 | auto [code2, id2] = zoneGraph.AddResourceRecord(r1); 27 | BOOST_CHECK(code2 == zone::RRAddCode::DUPLICATE); // Duplicate record 28 | 29 | ResourceRecord r3("foo.com", "CNAME", 1, 10, "aaa.com"); 30 | auto [code3, id3] = zoneGraph.AddResourceRecord(r3); 31 | BOOST_CHECK(code3 == zone::RRAddCode::CNAME_MULTIPLE); // Multiple CNAME records 32 | 33 | ResourceRecord r4("foo.com", "A", 1, 10, "1.2.3.4"); 34 | auto [code4, id4] = zoneGraph.AddResourceRecord(r4); 35 | BOOST_CHECK(code4 == zone::RRAddCode::CNAME_OTHER); // Other records at CNAME node should not return SUCCESS 36 | } 37 | 38 | BOOST_AUTO_TEST_CASE(multiple_DNAME) 39 | { 40 | zone::Graph zoneGraph(0); 41 | ResourceRecord r1("foo.com", "DNAME", 1, 10, "bar.com"); 42 | auto [code1, id1] = zoneGraph.AddResourceRecord(r1); 43 | BOOST_CHECK(code1 == zone::RRAddCode::SUCCESS); 44 | 45 | auto [code2, id2] = zoneGraph.AddResourceRecord(r1); 46 | BOOST_CHECK(code2 == zone::RRAddCode::DUPLICATE); // Duplicate record 47 | 48 | ResourceRecord r3("foo.com", "DNAME", 1, 10, "aaa.com"); 49 | auto [code3, id3] = zoneGraph.AddResourceRecord(r3); 50 | BOOST_CHECK(code3 == zone::RRAddCode::DNAME_MULTIPLE); // Multiple DNAME records 51 | 52 | ResourceRecord r4("foo.com", "A", 1, 10, "1.2.3.4"); 53 | auto [code4, id4] = zoneGraph.AddResourceRecord(r4); 54 | BOOST_CHECK(code4 == zone::RRAddCode::SUCCESS); // Other records at DNAME node should return success 55 | } 56 | 57 | BOOST_AUTO_TEST_CASE(DNAME_SOA_NS) 58 | { 59 | zone::Graph zoneGraph(0); 60 | ResourceRecord r1( 61 | "foo.com", "SOA", 1, 10, "us.illinois.net. us-domain.illinois.net. 2018083000 14400 3600 2419200 14400"); 62 | auto [code1, id1] = zoneGraph.AddResourceRecord(r1); 63 | BOOST_CHECK(code1 == zone::RRAddCode::SUCCESS); 64 | 65 | ResourceRecord r2("foo.com", "NS", 1, 10, "ns1.bar.com"); 66 | auto [code2, id2] = zoneGraph.AddResourceRecord(r2); 67 | BOOST_CHECK(code2 == zone::RRAddCode::SUCCESS); 68 | 69 | EC longer; 70 | longer.name = LabelUtils::StringToLabels("alpha.foo.com"); 71 | longer.rrTypes.set(RRType::A); 72 | 73 | EC exact; 74 | exact.name = LabelUtils::StringToLabels("foo.com"); 75 | exact.rrTypes.set(RRType::A); 76 | 77 | EC negation; 78 | negation.name = LabelUtils::StringToLabels("foo.com"); 79 | negation.rrTypes.set(RRType::A); 80 | negation.excluded = boost::make_optional(std::vector{}); 81 | 82 | bool complete = false; 83 | 84 | auto longer_answer = zoneGraph.QueryLookUpAtZone(longer, complete); 85 | BOOST_ASSERT(longer_answer.is_initialized()); 86 | BOOST_CHECK(std::get<0>(longer_answer.get()[0]) == ReturnTag::NX); 87 | 88 | auto exact_answer = zoneGraph.QueryLookUpAtZone(exact, complete); 89 | BOOST_ASSERT(exact_answer.is_initialized()); 90 | BOOST_CHECK(std::get<0>(exact_answer.get()[0]) == ReturnTag::ANS); 91 | 92 | auto negation_answer = zoneGraph.QueryLookUpAtZone(negation, complete); 93 | BOOST_ASSERT(negation_answer.is_initialized()); 94 | BOOST_CHECK(std::get<0>(negation_answer.get()[0]) == ReturnTag::NX); 95 | 96 | ResourceRecord r3("foo.com", "DNAME", 1, 10, "bar.com"); // DNAME is allowed to stay with NS as there is SOA 97 | auto [code3, id3] = zoneGraph.AddResourceRecord(r3); 98 | BOOST_CHECK(code3 == zone::RRAddCode::SUCCESS); 99 | 100 | longer_answer = zoneGraph.QueryLookUpAtZone(longer, complete); 101 | BOOST_ASSERT(longer_answer.is_initialized()); 102 | BOOST_CHECK(std::get<0>(longer_answer.get()[0]) == ReturnTag::REWRITE); 103 | 104 | exact_answer = zoneGraph.QueryLookUpAtZone(exact, complete); 105 | BOOST_ASSERT(exact_answer.is_initialized()); 106 | BOOST_CHECK(std::get<0>(exact_answer.get()[0]) == ReturnTag::ANS); 107 | 108 | negation_answer = zoneGraph.QueryLookUpAtZone(negation, complete); 109 | BOOST_ASSERT(negation_answer.is_initialized()); 110 | BOOST_CHECK(std::get<0>(negation_answer.get()[0]) == ReturnTag::REWRITE); 111 | 112 | ResourceRecord r4("alpha.foo.com", "A", 1, 10, "1.1.1.1"); 113 | auto [code4, id4] = zoneGraph.AddResourceRecord(r4); 114 | BOOST_CHECK(code4 == zone::RRAddCode::SUCCESS); 115 | 116 | // Even though there is an exact match that should be ignored because of DNAME 117 | longer_answer = zoneGraph.QueryLookUpAtZone(longer, complete); 118 | BOOST_ASSERT(longer_answer.is_initialized()); 119 | BOOST_CHECK(std::get<0>(longer_answer.get()[0]) == ReturnTag::REWRITE); 120 | 121 | ResourceRecord r5("*.foo.com", "A", 1, 10, "2.2.2.2"); 122 | auto [code5, id5] = zoneGraph.AddResourceRecord(r5); 123 | BOOST_CHECK(code5 == zone::RRAddCode::SUCCESS); 124 | 125 | // Even though there is a wildcard match that should be ignored because of DNAME 126 | negation_answer = zoneGraph.QueryLookUpAtZone(negation, complete); 127 | BOOST_ASSERT(negation_answer.is_initialized()); 128 | BOOST_CHECK(std::get<0>(negation_answer.get()[0]) == ReturnTag::REWRITE); 129 | } 130 | 131 | BOOST_AUTO_TEST_CASE(DNAME_NS) 132 | { 133 | zone::Graph zoneGraph(0); 134 | ResourceRecord r1( 135 | "foo.com", "SOA", 1, 10, "us.illinois.net. us-domain.illinois.net. 2018083000 14400 3600 2419200 14400"); 136 | auto [code1, id1] = zoneGraph.AddResourceRecord(r1); 137 | BOOST_CHECK(code1 == zone::RRAddCode::SUCCESS); 138 | 139 | ResourceRecord r2("alpha.foo.com", "NS", 1, 10, "ns1.bar.com"); 140 | auto [code2, id2] = zoneGraph.AddResourceRecord(r2); 141 | BOOST_CHECK(code2 == zone::RRAddCode::SUCCESS); 142 | 143 | EC longer; 144 | longer.name = LabelUtils::StringToLabels("beta.alpha.foo.com"); 145 | longer.rrTypes.set(RRType::A); 146 | 147 | EC exact; 148 | exact.name = LabelUtils::StringToLabels("alpha.foo.com"); 149 | exact.rrTypes.set(RRType::A); 150 | 151 | EC negation; 152 | negation.name = LabelUtils::StringToLabels("alpha.foo.com"); 153 | negation.rrTypes.set(RRType::A); 154 | negation.excluded = boost::make_optional(std::vector{}); 155 | 156 | bool complete = false; 157 | 158 | auto longer_answer = zoneGraph.QueryLookUpAtZone(longer, complete); 159 | BOOST_ASSERT(longer_answer.is_initialized()); 160 | BOOST_CHECK(std::get<0>(longer_answer.get()[0]) == ReturnTag::REF); 161 | 162 | auto exact_answer = zoneGraph.QueryLookUpAtZone(exact, complete); 163 | BOOST_ASSERT(exact_answer.is_initialized()); 164 | BOOST_CHECK(std::get<0>(exact_answer.get()[0]) == ReturnTag::REF); 165 | 166 | auto negation_answer = zoneGraph.QueryLookUpAtZone(negation, complete); 167 | BOOST_ASSERT(negation_answer.is_initialized()); 168 | BOOST_CHECK(std::get<0>(negation_answer.get()[0]) == ReturnTag::REF); 169 | 170 | ResourceRecord r3("alpha.foo.com", "DNAME", 1, 10, "bar.com"); // By RFC6672 DNAME and NS can not stay together. 171 | auto [code3, id3] = zoneGraph.AddResourceRecord(r3); 172 | BOOST_CHECK(code3 == zone::RRAddCode::SUCCESS); 173 | 174 | // DNAME should be ignored by all the ECs as there is no SOA and NS takes priority (zone-cut) 175 | longer_answer = zoneGraph.QueryLookUpAtZone(longer, complete); 176 | BOOST_ASSERT(longer_answer.is_initialized()); 177 | BOOST_CHECK(std::get<0>(longer_answer.get()[0]) == ReturnTag::REF); 178 | 179 | exact_answer = zoneGraph.QueryLookUpAtZone(exact, complete); 180 | BOOST_ASSERT(exact_answer.is_initialized()); 181 | BOOST_CHECK(std::get<0>(exact_answer.get()[0]) == ReturnTag::REF); 182 | 183 | negation_answer = zoneGraph.QueryLookUpAtZone(negation, complete); 184 | BOOST_ASSERT(negation_answer.is_initialized()); 185 | BOOST_CHECK(std::get<0>(negation_answer.get()[0]) == ReturnTag::REF); 186 | 187 | ResourceRecord r5("*.alpha.foo.com", "A", 1, 10, "2.2.2.2"); 188 | auto [code5, id5] = zoneGraph.AddResourceRecord(r5); 189 | BOOST_CHECK(code5 == zone::RRAddCode::SUCCESS); 190 | 191 | // Even though there is a wildcard match that should be ignored because of zone-cut 192 | negation_answer = zoneGraph.QueryLookUpAtZone(negation, complete); 193 | BOOST_ASSERT(negation_answer.is_initialized()); 194 | BOOST_CHECK(std::get<0>(negation_answer.get()[0]) == ReturnTag::REF); 195 | } 196 | 197 | BOOST_AUTO_TEST_CASE(Wildcard) 198 | { 199 | zone::Graph zoneGraph(0); 200 | ResourceRecord r1( 201 | "foo.com", "SOA", 1, 10, "us.illinois.net. us-domain.illinois.net. 2018083000 14400 3600 2419200 14400"); 202 | auto [code1, id1] = zoneGraph.AddResourceRecord(r1); 203 | BOOST_CHECK(code1 == zone::RRAddCode::SUCCESS); 204 | 205 | ResourceRecord r2("*.foo.com", "A", 1, 10, "1.1.1.1"); 206 | auto [code2, id2] = zoneGraph.AddResourceRecord(r2); 207 | BOOST_CHECK(code2 == zone::RRAddCode::SUCCESS); 208 | 209 | EC longer; 210 | longer.name = LabelUtils::StringToLabels("beta.alpha.foo.com"); 211 | longer.rrTypes.set(RRType::A); 212 | longer.rrTypes.set(RRType::MX); 213 | 214 | EC negation; 215 | negation.name = LabelUtils::StringToLabels("foo.com"); 216 | negation.rrTypes.set(RRType::A); 217 | negation.rrTypes.set(RRType::MX); 218 | negation.excluded = boost::make_optional(std::vector{}); 219 | 220 | bool complete = false; 221 | 222 | auto longer_answer = zoneGraph.QueryLookUpAtZone(longer, complete); 223 | BOOST_ASSERT(longer_answer.is_initialized()); 224 | BOOST_CHECK(std::get<0>(longer_answer.get()[0]) == ReturnTag::ANS); // for A 225 | BOOST_CHECK(std::get<0>(longer_answer.get()[1]) == ReturnTag::ANS); // for MX 226 | 227 | auto negation_answer = zoneGraph.QueryLookUpAtZone(negation, complete); 228 | BOOST_ASSERT(negation_answer.is_initialized()); 229 | BOOST_CHECK(std::get<0>(negation_answer.get()[0]) == ReturnTag::ANS); 230 | BOOST_CHECK(std::get<0>(negation_answer.get()[1]) == ReturnTag::ANS); 231 | 232 | ResourceRecord r3("*.*.foo.com", "CNAME", 1, 10, "aaa.com"); // wildcard under a wildcard 233 | auto [code3, id3] = zoneGraph.AddResourceRecord(r3); 234 | BOOST_CHECK(code3 == zone::RRAddCode::SUCCESS); 235 | 236 | EC star; 237 | star.name = LabelUtils::StringToLabels("alpha.*.foo.com"); 238 | star.rrTypes.set(RRType::A); 239 | star.rrTypes.set(RRType::MX); 240 | 241 | auto star_answer = zoneGraph.QueryLookUpAtZone(star, complete); 242 | BOOST_ASSERT(star_answer.is_initialized()); 243 | BOOST_CHECK(std::get<0>(star_answer.get()[0]) == ReturnTag::REWRITE); 244 | 245 | star.rrTypes.reset(RRType::A); 246 | star.rrTypes.reset(RRType::MX); 247 | star.rrTypes.set(RRType::CNAME); 248 | 249 | star_answer = zoneGraph.QueryLookUpAtZone(star, complete); 250 | BOOST_ASSERT(star_answer.is_initialized()); 251 | BOOST_CHECK(std::get<0>(star_answer.get()[0]) == ReturnTag::ANS); // If CNAME is the only type requested. 252 | 253 | EC double_start; 254 | double_start.name = LabelUtils::StringToLabels("alpha.*.*.foo.com"); 255 | double_start.rrTypes.set(RRType::A); 256 | 257 | auto double_star_answer = zoneGraph.QueryLookUpAtZone(double_start, complete); 258 | BOOST_ASSERT(double_star_answer.is_initialized()); 259 | BOOST_CHECK(std::get<0>(double_star_answer.get()[0]) == ReturnTag::NX); 260 | } 261 | 262 | BOOST_AUTO_TEST_SUITE_END() --------------------------------------------------------------------------------