CSCI 780: Spring 2025
Distributed System Security
Project 2: sodoh

Due: Fri, Mar 28, 11:59pm


In this project, you will implement a simplified version of Oblivious DNS over HTTPS (ODoH), which Cloudflare proposed in a PETS '21 paper, and which is currently an experimental RFC.

The motivation for ODoH is that, while DNS-over-HTTPS (DoH) ensures the confidentiality of a DNS request from an eavesdropper, the DNS resolver still learns that a given client IP address is looking up a specific domainname. Although this is a normal expectation, it becomes a privacy concern in a world where clients increasingly rely on a small number of open resolvers; such resolvers are in a position to track the activities of a huge number of Internet users.

In order to ensure that a DNS server does not learn both a client's IP address and the client's query, ODoH relies on two servers: a proxy and a target. Clients end-to-end encrypt their DNS communication with the target, who in turn resolves the query. However, the client sends this query to the proxy, who then forwards it to the target. In this way, the proxy learns the IP address, the target learns the DNS request, but neither learns both.

For this project, you will implement three executables:

Protocol

The communication between the client and proxy is over HTTPS. Likewise, the communication between the proxy and target is over HTTPS. The client issues its DNS request to a URL of the form:


https://PROXY/dns-query?targethost=TARGET&targetpath=/dns-query
        

For instance, if the PROXY is at 127.0.0.1:8053 and the TARGET is at 127.0.0.1:8054, the URL would be:


https://127.0.0.1:8053/dns-query?targethost=127.0.0.1:8054&targetpath=/dns-query
        

In turn, the proxy forwards the query to the URL:


https://TARGET/dns-query
        

For example:


https://127.0.0.1:8054/dns-query
        

In our SODoH protocol, the only DNS request that we will support is a combined A/AAAA query -- that is, a query to resolve a domainname to a list of IPv4 and IPv6 addresses. Additionally, we will use JSON as the data exchange format for all queries and replies.

A DNS query has the JSON form:


{
  qname: <string>
}
        

A successful DNS reply has the JSON form:


{
  rcode: <int>,
  answers: [
    <string>
    ...
  ]
}
        

A DNS error reply has the JSON form:


{
  rcode: <int>
}
        

The client hybrid encrypts the DNS query using a randomly generated 256-bit AES key and the target's public RSA key. Specifically, the client sends to the proxy (and the proxy forwards to the target), the following JSON blob:


{
  wrappedKey: <The Base64 encoding of the RSA-OAEP encryption of the random AES-256 key>
  ciphertext: <The Base64 encoding of the AES256-GCM encryption of the JSON DNS query>
}
        

In turn, the target uses its RSA private key to unwrap the AES-256 key, and uses this AES key to decrypt the DNS query. The target performs the DNS resolution, forms the DNS reply, and encrypts the DNS reply with the same AES-256 key. Specifically, the target returns the following JSON reply to the proxy, which then forwards it to the client:


{
  ciphertext: <The Base64 encoding of the AES256-GCM encryption of the JSON DNS reply>
}
        

Error Codes

DNS RCode

If the target receives a well-formed query, the DNS reply can have one of the following rcodes:

0 - NOERROR
The target resolved the domainname to one or more IPv4 addresses
1 - NXDOMAIN
The domainname does not exist and thus can't be resolved.
2 - SERVFAIL
This is catchall error we'll use for any other DNS failure.

HTTP Status Codes

The proxy and target return the following HTTP status codes. Note that if the proxy successfully makes an HTTPS request to the target, then the proxy copies the status code of the target's response for its own response to the client.

200 - OK
Target: Successfully unmarshals and decrypts the JSON query and makes a DNS query. The target returns a 200 status code regardless of whether the query resolves the domainname.
400 - Bad Request
Proxy: The client specifies the /dns-query URL with an incorrect URL query component.
Target: Can't unmarshal or decrypt the JSON query.
404 - Not Found
Both: The HTTPS request is for a URL other than /dns-query.
502 - Bad Gateway
Proxy: Fails to make an HTTPS request to the target.
500 - Internal Server Error
Both: A catchall for any internal error.

client


Name

client - send a simplified Oblivious DNS (ODoH) request.

Synopsis

client [options] QNAME

Positional Arguments

QNAME

The query name (domainname) to resolve.

Options

-ca-cert CA_CERT

The certificate file for the CA that signed the TLS certificate for the proxy.

Default: ca.crt

-target-cert TARGET_CERT

The certificate file for the target. The client uses the certificate's public key to hybrid encrypt the DNS request.

Default: target.crt

-proxy PROXY_HOST

The proxy host. This has the form host[:port], where host can be either a domainname or an IP address.

Default: 127.0.0.1:8053

-target TARGET_HOST

The target host. This has the form host[:port], where host can be either a domainname or an IP address.

Default: 127.0.0.1:8054

-help

Display this usage statement and exit.

Exit Status

If the DNS request is resolved to one or more IP addresses, the client should exit with a status of zero; otherwise, it should exit with a non-zero status.

Example


        ./client -ca-cert assets/ca.crt -target-cert assets/target.crt www.cs.wm.edu
        

proxy


Name

proxy - proxy server for Oblivious DNS (ODoH)

Synopsis

proxy [options] [HOST]:PORT

Positional Arguments

[HOST]:PORT

A "host:port" address that the proxy listens on for HTTPS requests.

Options

-cert TLS_CERT

The TLS certificate file for the proxy.

Default: proxy.crt

-key TLS_PRIVATE_KEY

The TLS private key for the proxy.

Default: proxy.key

-ca-cert CA_CERT

The certificate file for the CA that signed the TLS certificate for the target.

Default: ca.crt

-help

Display this usage statement and exit.

Example


        ./proxy -ca-cert assets/ca.crt -cert assets/proxy.crt -key assets/proxy.key 127.0.0.1:8053
        

target


Name

target - target server for Oblivious DNS (ODoH)

Synopsis

target [options] [HOST]:PORT

Positional Arguments

[HOST]:PORT

A "host:port" address that the target listens on for HTTPS requests.

Options

-cert TLS_CERT

The TLS certificate file for the target.

Default: target.crt

-key TLS_PRIVATE_KEY

The TLS private key for the target.

Default: target.key

-help

Display this usage statement and exit.

Example


        ./target -cert assets/target.crt -key assets/target.key 127.0.0.1:8054
        

Skeleton Code

To help get started, please use the following sodoh.zip skeleton module.

Submitting

Submit your project as a zip file via gradescope. Your project must include a Makefile that builds three executables: client, proxy, and target. Please refer to the instructions for submitting an assignment for details on how to login to gradescope and properly zip your project.

Rubric

Client


1.1 client looks up www.cs.wm.edu (15 pts)


        ./instructor/target -cert assets/target.crt -key assets/target.key 127.0.0.1:8054
        

        ./instructor/proxy -ca-cert assets/ca.crt -cert assets/proxy.crt -key assets/proxy.key 127.0.0.1:8053
        

        ./client -ca-cert assets/ca.crt -target-cert assets/target.crt www.cs.wm.edu
        (out)128.239.2.143
        echo $?
        (out)0
        

1.2 send error message (15 pts)


        ./instructor/target -cert assets/target.crt -key assets/target.key 127.0.0.1:8054
        

        ./instructor/proxy -ca-cert assets/ca.crt -cert assets/proxy.crt -key assets/proxy.key 127.0.0.1:8053
        

        ./client -ca-cert assets/ca.crt -target-cert assets/target.crt zzz.cs.wm.edu
        (out)Non-Existent Domain
        echo $?
        (out)1
        

The client needs to output to stdout a single line that contains either Non-Existent Domain or NXDOMAIN. The error message may contain other text, if you'd like. The character case does not matter. The client should also exit with a non-zero exit status.

Proxy


2.1 proxy forwards a request and returns target's response (14 pts)


        ./instructor/target -cert assets/target.crt -key assets/target.key 127.0.0.1:8054
        

        ./proxy -ca-cert assets/ca.crt -cert assets/proxy.crt -key assets/proxy.key 127.0.0.1:8053
        

        ./instructor/client -ca-cert assets/ca.crt -target-cert assets/target.crt www.wm.edu
        (out)108.138.64.11
        (out)108.138.64.88
        (out)108.138.64.78
        (out)108.138.64.106
        echo $?
        (out)0
        

Note: It's OK if the list of IP addresses is slightly different (e.g., includes IPv6 addresses).

2.2 proxy forwards a request to a non-default target address (13 pts)


        ./instructor/target -cert assets/target.crt -key assets/target.key 127.0.0.1:8064
        

        ./proxy -ca-cert assets/ca.crt -cert assets/proxy.crt -key assets/proxy.key 127.0.0.1:8063
        

        ./instructor/client -ca-cert assets/ca.crt -target-cert assets/target.crt -proxy 127.0.0.1:8063 -target 127.0.0.1:8064 www.wm.edu
        (out)108.138.64.11
        (out)108.138.64.88
        (out)108.138.64.78
        (out)108.138.64.106
        echo $?
        (out)0
        

Note: It's OK if the list of IP addresses is slightly different (e.g., includes IPv6 addresses).

2.3 proxy returns an HTTP status error of 502 when it cannot connect to the target (13 pts)


        ./instructor/target -cert assets/target.crt -key assets/target.key 127.0.0.1:8054
        

        ./proxy -ca-cert assets/ca.crt -cert assets/proxy.crt -key assets/proxy.key 127.0.0.1:8053
        

        ./instructor/client -ca-cert assets/ca.crt -target-cert assets/target.crt -target 127.0.0.1:8067 www.wm.edu
        (out)HTTP status error: 502
        

Target


3.1 target returns a list of IP addresses for www.wm.edu (15 pts)


        ./target -cert assets/target.crt -key assets/target.key 127.0.0.1:8054
        

        ./instructor/proxy -ca-cert assets/ca.crt -cert assets/proxy.crt -key assets/proxy.key 127.0.0.1:8053
        

        ./instructor/client -ca-cert assets/ca.crt -target-cert assets/target.crt www.wm.edu
        (out)108.138.64.11
        (out)108.138.64.88
        (out)108.138.64.78
        (out)108.138.64.106
        echo $?
        (out)0
        

3.2 target returns an NXDOMAIN for www.wm.edux (15 pts)


        ./target -cert assets/target.crt -key assets/target.key 127.0.0.1:8054
        

        ./instructor/proxy -ca-cert assets/ca.crt -cert assets/proxy.crt -key assets/proxy.key 127.0.0.1:8053
        

        ./instructor/client -ca-cert assets/ca.crt -target-cert assets/target.crt www.wm.edux
        (out)DNS returned rcode 1 (Non-Existent Domain)
        echo $?
        (out)1