Giter Site home page Giter Site logo

dns-groot / groot Goto Github PK

View Code? Open in Web Editor NEW
75.0 3.0 9.0 1.49 MB

Static verification tool for DNS zone files

License: MIT License

C++ 95.91% CMake 1.52% Dockerfile 0.23% Shell 0.56% Python 1.79%
dns zone-files verification static-analyzer dns-zone-files

groot's Introduction

GRoot

License: MIT       codecov

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.


Installation     |     Property Verification  ·  Available Properties     |     Citing GRoot  ·  License (MIT)


📃 SIGCOMM 2020 -- GRoot: Proactive Verification of DNS Configurations

🏆 Best Student Paper Award

🖥️ Slides and Talk

Note

We have updated the paper to handle empty non-terminals as per the RFCs properly. The updated paper is available here. For more details, please check the GitHub issue #11.

Installation

Using docker (recommended)

Note: The docker image may consume ~ 1.2 GB of disk space.

We recommend running GRoot within a docker container, since they have negligible performance overhead. (See this report)

  1. Get docker for your OS.
  2. Pull our docker image#: docker pull dnsgt/groot.
  3. Run a container over the image: docker run -it dnsgt/groot.
    This would give you a bash shell within groot directory.

# Alternatively, you could also build the Docker image locally:

docker build -t dnsgt/groot github.com/dns-groot/groot

Docker containers are isolated from the host system. Therefore, to run GRoot on zones files residing on the host system, you must first bind mount them while running the container:

docker run -v ~/data:/home/groot/groot/shared -it dnsgt/groot

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/.

Manual Installation

CLICK to reveal instructions

Installation for Windows

  1. Install vcpkg package manager to install dependecies.
  2. Install the C++ libraries (64 bit versions) using:
    • .\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
    • .\vcpkg.exe integrate install
  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.
  4. Configure the project properties to use ISO C++17 Standard (std:c++17) for C++ language standard.
  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\.

Installation for Ubuntu 18.04 or later

  1. Follow the instructions mentioned in the DockerFile to natively install in Ubuntu 18.04 or later.
  2. The executable would be located at ~/groot/build/bin/.

Property Verification

Check for any violations of the input properties by invoking GRoot as:

For docker (Ubuntu):

~/groot$ ./build/bin/groot test/TestFiles/cc.il.us/zone_files --jobs=test/TestFiles/cc.il.us/jobs.json --output=output.json

For Windows:

~\groot> .\x64\Release\groot.exe test\TestFiles\cc.il.us\zone_files --jobs=test\TestFiles\cc.il.us\jobs.json --output=output.json

GRoot outputs any violations to the output.json file.

Flags

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.

Packaging zone files data

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.

CLICK to reveal an examplemetadata.json
{  
  "TopNameServers" : ["us.illinois.net."],  //List of top name servers as strings
  "ZoneFiles" : [
      {
         "FileName": "cc.il.us..txt", //cc.il.us. zone file from us.illinois.net. name server
         "NameServer": "us.illinois.net."
      },
      {
         "FileName": "richland.cc.il.us..txt", //richland.cc.il.us. zone file from ns1.richland.cc.il.us. name server
         "NameServer": "ns1.richland.cc.il.us.",
         "Origin": "richland.cc.il.us." // optional field to indicate the origin of the input zone file.
      },
      {
         "FileName": "child.richland.cc.il.us..txt", //child.richland.cc.il.us. zone file from ns1.child.richland.cc.il.us. name server
         "NameServer": "ns1.child.richland.cc.il.us."
      },
      {
         "FileName": "child.richland.cc.il.us.-2.txt", //child.richland.cc.il.us. zone file from ns2.child.richland.cc.il.us. name server 
         "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
      }
  ]
}

Inputting Jobs

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.

CLICK to reveal an example job
[
   {
      "Domain": "cc.il.us." // Name of the domain to check
      "SubDomain": true, //Whether to check the properties on all the subdomains also
      "Properties":[ 
         {
            "PropertyName": "QueryRewrite",
            "Value": ["illinois.net." , "cc.il.us."]
         },
         {
            "PropertyName": "Rewrites",
            "Value": 1
         },
         {
            "PropertyName": "RewriteBlackholing"
         }
      ]
   }
]

Available Properties

Delegation Consistency

The parent and child zone files should have the same set of NS and glue A records for delegation. Input json format:

      {
         "PropertyName": "DelegationConsistency"
      }
Finding all aliases Lists all the input query names (aliases) that are eventually rewritten to one of the canonical names.

Input json format:

      {
         "PropertyName": "AllAliases",
         "Value": ["gw1.richland.cc.il.us."] //List of canonical names
      }
Lame Delegation

A name server that is authoritative for a zone should provide authoritative answers, otherwise it is a lame delegation. Input json format:

      {
         "PropertyName": "LameDelegation"
      }
Nameserver Contact

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. Input json format:

      {
         "PropertyName": "NameserverContact",
         "Value": ["edu.", "net.", "cc.il.us."] //List of allowed domain suffixes
      }
Number of Hops

The query should not go through more than X number of hops for any execution in the DNS. Input json format:

      {
         "PropertyName": "Hops",
         "Value": 2
      }
Number of Rewrites

The query should not be rewritten more than X number of time for any execution in the DNS. Input json format:

      {
         "PropertyName": "Rewrites",
         "Value": 3
      }
Query Rewritting

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. Input json format:

      {
         "PropertyName": "QueryRewrite",
         "Value": ["illinois.net." , "cc.il.us."] //List of allowed domain suffixes
      }
Response Consistency Different executions in DNS that might happen due to multiple name servers should result in the same answers.

Input json format:

      {
         "PropertyName": "ResponseConsistency",
         "Types": ["A", "MX"] //Checks the consistency for only these types
      }
Response Returned Different executions in DNS that might happen due to multiple name servers should result in some non-empty response.

Input json format:

      {
         "PropertyName": "ResponseReturned",
         "Types": ["CNAME", "A"] //Checks that some non-empty response is returned for these types
      }
Response Value Every execution in DNS should return an answer that matches the user input answer.

Input json format:

      {
         "PropertyName": "ResponseValue",
         "Types": ["A"],
         "Value": ["64.107.104.4"] //The expected response
         
      }
Rewrite Blackholing

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.

Input json format:

      {
         "PropertyName": "RewriteBlackholing"
      }
Structural Delegation Consistency

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.

Input json format:

      {
         "PropertyName": "StructuralDelegationConsistency"
      }
Zero Time To Live

The query should not return a resource record with zero TTL for the given types.
Input json format:

      {
         "PropertyName": "ZeroTTL",
         "Types": ["A"]
      }
DNAME Substitution Check

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.
Input json format:

      {
         "PropertyName": "DNAMESubstitutionCheck"
      }

GRoot, by default, checks for cyclic zone dependency and other loops while verifying any of the above properties.

Citing GRoot

@inproceedings{10.1145/3387514.3405871,
    author = {Kakarla, Siva Kesava Reddy and Beckett, Ryan and Arzani, Behnaz and Millstein, Todd and Varghese, George},
    title = {GRoot: Proactive Verification of DNS Configurations},
    year = {2020},
    isbn = {9781450379557},
    publisher = {Association for Computing Machinery},
    address = {New York, NY, USA},
    url = {https://doi.org/10.1145/3387514.3405871},
    doi = {10.1145/3387514.3405871},
    booktitle = {Proceedings of the Annual Conference of the ACM Special Interest Group on Data Communication on the 
                 Applications, Technologies, Architectures, and Protocols for Computer Communication},
    pages = {310–328},
    numpages = {19},
    keywords = {Static Analysis, Verification, DNS, Formal Methods},
    location = {Virtual Event, USA},
    series = {SIGCOMM ’20}
}

groot's People

Contributors

ajis01 avatar rabeckett avatar sivakesava1 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

groot's Issues

json boilerplate

There appears to be a lot of repetitive json boilerplate (e.g., in properties.cpp), where the json is being constructed manually. This manual conversion is also what caused the bug in the structural delegation property.

Could we create specific classes for the result of each property check and then a superclass for "violation" that contains the common data (property name, etc.)? Then we could use the json library's simple method for converting classes to json:

https://github.com/nlohmann/json#basic-usage

README Example not working?

I run the latest docker image () on my computer and copied the example from the README:

docker run -it dnsgt/groot

# First try with literally what I copied from GitHub
groot@177a7eb9e05c:~/groot$ .~/groot/build/bin/groot ~/groot/test/TestFiles/cc.il.us/zone_files --jobs=~/groot/test/TestFiles/cc.il.us/jobs.json --output=output.json
bash: .~/groot/build/bin/groot: No such file or directory

# First attempt at fixing
groot@177a7eb9e05c:~/groot$ . ~/groot/build/bin/groot ~/groot/test/TestFiles/cc.il.us/zone_files --jobs=~/groot/test/TestFiles/cc.il.us/jobs.json --output=output.json
bash: .: /home/groot/groot/build/bin/groot: cannot execute binary file

# Second attempt at fixing
groot@177a7eb9e05c:~/groot$ ~/groot/build/bin/groot ~/groot/test/TestFiles/cc.il.us/zone_files --jobs=~/groot/test/TestFiles/cc.il.us/jobs.json --output=output.json
Exception:- [json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal

Sorry if I'm overlooking something obvious!

Groot itself seems to be working:

groot@177a7eb9e05c:~/groot$ ./build/bin/groot 
Arguments did not match expected patterns
groot 1.0
[...]

Also, the JSON seems to check out:

groot@177a7eb9e05c:~/groot$ python3
Python 3.8.10 (default, Sep 28 2021, 16:10:42) 
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import json
>>> json.load(open("/home/groot/groot/test/TestFiles/cc.il.us/jobs.json"))
[{'Domain': 'child.richland.cc.il.us.', [...]

WIN10+VS2022 can not complie groot

I followed the Installation for Windows section in README.md. However, there is a problem compiling the libgroot project with the following error message:

1>------ Build started: Project: libgroot, Configuration: Debug x64 ------
1>driver.cpp
1>C:\Users\DELL\Desktop\dns\groot\src\resource-record.h(53,25): warning C4267: '=': conversion from 'size_t' to 'int', possible loss of data
1>C:\Users\DELL\Desktop\dns\groot\concurrentqueue\concurrentqueue.h(431,2): warning C4554: '<<': check operator precedence for possible error; use parentheses to clarify precedence
1>C:\Users\DELL\Desktop\dns\groot\concurrentqueue\concurrentqueue.h(1682,20): message : see reference to function template instantiation 'bool moodycamel::details::circular_less_than<unsigned __int64>(T,T)' being compiled
1>        with
1>        [
1>            T=unsigned __int64
1>        ]
1>C:\Users\DELL\Desktop\dns\groot\concurrentqueue\concurrentqueue.h(1678,17): message : while compiling class template member function 'unsigned __int64 moodycamel::ConcurrentQueue<std::unique_ptr<Task,std::default_delete<Task>>,moodycamel::ConcurrentQueueDefaultTraits>::ProducerBase::size_approx(void) const'
1>C:\Users\DELL\Desktop\dns\groot\concurrentqueue\concurrentqueue.h(1269,9): message : see the first reference to 'moodycamel::ConcurrentQueue<std::unique_ptr<Task,std::default_delete<Task>>,moodycamel::ConcurrentQueueDefaultTraits>::ProducerBase::size_approx' in 'moodycamel::ConcurrentQueue<std::unique_ptr<Task,std::default_delete<Task>>,moodycamel::ConcurrentQueueDefaultTraits>::size_approx'
1>C:\Users\DELL\Desktop\dns\groot\src\driver.cpp(13,5): message : see the first reference to 'moodycamel::ConcurrentQueue<std::unique_ptr<Task,std::default_delete<Task>>,moodycamel::ConcurrentQueueDefaultTraits>::size_approx' in 'Driver::GenerateECsAndCheckProperties'
1>C:\Users\DELL\Desktop\dns\groot\concurrentqueue\concurrentqueue.h(1268,85): message : see reference to class template instantiation 'moodycamel::ConcurrentQueue<std::unique_ptr<Task,std::default_delete<Task>>,moodycamel::ConcurrentQueueDefaultTraits>::ProducerBase' being compiled
1>C:\Users\DELL\Desktop\dns\groot\concurrentqueue\concurrentqueue.h(1265,9): message : while compiling class template member function 'unsigned __int64 moodycamel::ConcurrentQueue<std::unique_ptr<Task,std::default_delete<Task>>,moodycamel::ConcurrentQueueDefaultTraits>::size_approx(void) const'
1>C:\Users\DELL\Desktop\dns\groot\src\driver.cpp(13,5): message : see the first reference to 'moodycamel::ConcurrentQueue<std::unique_ptr<Task,std::default_delete<Task>>,moodycamel::ConcurrentQueueDefaultTraits>::size_approx' in 'Driver::GenerateECsAndCheckProperties'
1>C:\Users\DELL\Desktop\dns\groot\src\job.h(16,51): message : see reference to class template instantiation 'moodycamel::ConcurrentQueue<std::unique_ptr<Task,std::default_delete<Task>>,moodycamel::ConcurrentQueueDefaultTraits>' being compiled
1>C:\Program Files\vcpkg\installed\x64-windows\include\fmt\core.h(1580,7): error C2338: static_assert failed: 'Cannot format an argument. To make type T formattable provide a formatter<T> specialization: https://fmt.dev/latest/api.html#udt'
1>C:\Program Files\vcpkg\installed\x64-windows\include\fmt\core.h(1808,23): message : see reference to function template instantiation 'fmt::v10::detail::value<Context> fmt::v10::detail::make_arg<true,Context,std::atomic<long>,0>(T &)' being compiled
1>        with
1>        [
1>            Context=fmt::v10::format_context,
1>            T=std::atomic<long>
1>        ]
1>C:\Program Files\vcpkg\installed\x64-windows\include\fmt\core.h(1826,11): message : see reference to function template instantiation 'fmt::v10::format_arg_store<fmt::v10::format_context,std::atomic<long>>::format_arg_store<std::atomic<long>>(std::atomic<long> &)' being compiled
1>C:\Program Files\vcpkg\installed\x64-windows\include\fmt\core.h(2788,28): message : see reference to function template instantiation 'fmt::v10::format_arg_store<fmt::v10::format_context,std::atomic<long>> fmt::v10::make_format_args<fmt::v10::format_context,std::atomic<long>>(std::atomic<long> &)' being compiled
1>C:\Users\DELL\Desktop\dns\groot\src\driver.cpp(432,23): message : see reference to function template instantiation 'std::string fmt::v10::format<std::atomic<long>&>(fmt::v10::basic_format_string<char,std::atomic<long> &>,std::atomic<long> &)' being compiled
1>C:\Program Files\vcpkg\installed\x64-windows\include\fmt\core.h(1576,63): error C2079: '_' uses undefined struct 'fmt::v10::detail::type_is_unformattable_for<std::atomic<long>,char>'
1>zone-graph.cpp
1>C:\Users\DELL\Desktop\dns\groot\src\resource-record.h(53,25): warning C4267: '=': conversion from 'size_t' to 'int', possible loss of data
1>Generating Code...
1>Done building project "libgroot.vcxproj" -- FAILED.
2>------ Build started: Project: groot, Configuration: Debug x64 ------

Could you tell me how to fix it?

Clarification regarding empty non-terminals (RFC 8020)

Hi,

I was reading your paper "GRooT: Proactive Verification of DNS Configurations" and have a question how the presented RRLookup would react to encountering empty non-terminals (ENTs) (see RFC7719 and RFC 8020).
If this is not a suitable place to discuss this I am happy to discuss this over e-mail too. I searched in the paper and in the repository and couldn't find an answer so far.

Here is in short why I think the paper does not properly model ENTs. I try to expand on each of the points a bit. Aa ENT is a domain name which exists, but has no resource records attached to it. An example might be _tcp.example.com. assuming that _jabber._tcp.example.com. exists and has an SRV record.

  • The RRLookup as given in Figure 3 does not seem to account for ENTs as the ExactMatch rule does not apply, since there is no exact match. The other rules also do not apply, as a zone can have ENTs without having wildcards, DNAMEs or delegations.
  • A resource records cannot model an ENT as a record always needs to have a type assigned so there is no way to model an empty record. From the paper:

    We model a resource record r ∈ record = ⟨d, t, c, τ, a, b⟩ as a tuple with six components: [...] (2) a record type t ∈ type = {A, AAAA, MX, NS, DNAME, CNAME, SOA, . . .} representing the kind of data the record holds (e.g., AAAA for an IPv6 address)

  • A well-formed zone (Appendix A) is allowed to have ENTs. No rule prohibits it.

Longer Explanation

Let's assume we have a simple zone like this. I omitted the TTL as it is not important. The parts abbreviated with ... do not matter, except that they should be a valid record of course.

example.com. IN SOA ...
example.com. IN NS ns1.dns.net.
example.com. IN NS ns2.dns.net.

_jabber._tcp.example.com. IN SRV ...

A query like _tcp.example.com. IN SRV should return NOERROR and no data (i.e., ⟨Ans, ∅⟩).
(Btw. you can test this with google.com, which has a _jabber._tcp and _tcp is also an ENT.)

The zone is well-formed according to Appendix A. Rules (1)-(3) hold for the example. (4)-(9),(11) are not applicable since there is neither a CNAME nor a DNAME record. (10) also holds, as the only NS records also have an SOA record.

A zone is a set of records. It does not cover the fact that some domain names exist but have no records.

It is also not possible to create a record which only exists for the domain name, but without associated types or answer, as would be necessary for an ENT. This is a direct result of the definition of a record = ⟨d, t, c, τ, a, b⟩.

The ZoneLookup function will call RRLookup with a set of records. The records for example.com. have a higher rank than the record for _jabber._tcp.example.com., since 𝓘 (Match(r, q) is true for the former, but not the latter. Thus, the maximum lexicographical ordering will result in the records for example.com..

Now only the fallback rule for RRLookup applies. It is no exact match since _tcp.example.com. != example.com., there are no wildcards which could match, no DNAME rewrite, nor any delegations. Thus, RRLookup will return NXDOMAIN.

The NXDOMAIN is a violation of RFC 8020 "NXDOMAIN: There Really Is Nothing Underneath". NXDOMAIN means that the name and everything underneath does not exist. However, _jabber._tcp.example.com. exists and is underneath _tcp.example.com..


ZoneLookup / RRLookup will find the correct answer when presented with a query for _jabber._tcp.example.com.. That is not how all resolvers work though. RFC 7816: QNAME Minimization describes how resolvers instead can query label by label. Thus, such a QNAME minimization resolver would conclude that the answer to _jabber._tcp.example.com. is NXDOMAIN.


I hope my reasoning is clear from the description above and I didn't make a mistake with the formalism.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.