├── .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 | [](https://opensource.org/licenses/MIT)
8 |
9 | [](https://github.com/dns-groot/groot/actions?query=workflow%3A%22Codecov+and+Docker+Image+CI%22)
10 |
11 |
12 |
13 | [](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