Skip to content

Commit

Permalink
Merge pull request #3 from james-stevens/dev
Browse files Browse the repository at this point in the history
minor changes
  • Loading branch information
james-stevens committed Jul 22, 2020
2 parents 641e064 + 04977dd commit bff630d
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 110 deletions.
124 changes: 18 additions & 106 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,6 @@ Google also supports sending binary DNS query packets to their service. This doe
It allows you to issue JSON DNS queries and get JSON responses, with the DNS done using an
underlying UDP client socket. It really should be ASGI, but its currently WSGI.

I've used ...

* Python - v3.6.9
* dnspython - v1.16.0 (`pip install dnspython`)
* Flask - v1.1.1 (`pip install Flask`)

Installing `nginx` or `Python` needs to be done using your O/S level install procedure.

But it doesn't do anything tricky, so any reasonably recent version will probably work.

If you feel like it, leave a comment in the [first issue](https://github.com/james-stevens/dnsflsk/issues/1) called `Just for chatting`


# Status

The code works, but I'll probably keep updating it, if I can think of anything else, or in response to feedback / bugs.


# Additional Options
Expand All @@ -33,10 +17,11 @@ In addition to the [Google Supported Parameters](https://developers.google.com/s
Each server can be specified as either a name or IPv4 address. Names will be resolved using your server's default resolution mechanism
(i.e. the same as the command line).

If you do not specify a `servers` option, it will default to `8.8.8.8,8.8.4.4` (Google).
If you do not specify a `servers` option, it will default to `8.8.8.8,8.8.4.4` (Google). If you
set the environment variable `DOH_SERVERS` as a comma separated list of IP Addresses, this will be used instead.

When more than one server is specified, your query will be sent to all the `servers`, and the
response you get will be the first one received (as specified in the `Responder` property.
response you get will be the first one received, as specified in the `Responder` property.


# Additional Properties
Expand Down Expand Up @@ -82,100 +67,27 @@ optional arguments:

# Running at Production Quality

I've also supplied all the extra files you'd need to run this at production quality. I used `gunicorn` and `nginx`.

* `pip install gunicorn` (if you don't already have it)
* Copy (or symlink) `nginx.conf` into the `${NGINX_BASE_DIR}/conf/dnsflsk.conf`
* Run `nginx -t -c conf/dnsflsk.conf` to check its OK
* Start Nginx with `nginx -c conf/dnsflsk.conf`
* Start WSGI/gunicorn with `./start_wsgi`

For `start_wsgi` to work, you may need to ensure `gunicorn` is in your run-path, or edit the script.

Then, from another ssh, you should be able to run something like

```
$ curl 'http://127.0.0.1:800/dns/api/v1.0/resolv?name=www.google.com'
```
If you fail to start the WSGI agent, you will get an HTTP `502 Bad Gateway` message

If it works, you'll see something like this
```
$ curl 'http://127.0.0.1:800/dns/api/v1.0/resolv?name=www.google.com' 2>/dev/null | jq
{
"QR": true,
"AA": false,
"TC": false,
"RD": true,
"CD": false,
"AD": false,
"RA": true,
"Flags": [
"QR",
"RD",
"RA"
],
"Status": 0,
"Question": [
{
"name": "www.google.com.",
"type": 1
}
],
"Answer": [
{
"name": "www.google.com.",
"data": "216.58.210.36",
"type": 1
}
],
"Authority": [],
"Responder": "8.8.4.4"
}
```
For production use, I strongly recommend you simply use the container `jamesstevens / doh`, or build the container yourself by running
`./dkmk`.

By default, the container will send its queries to the Google rsolvers `8.8.8.8` & `8.4.4.8`. By default
it will also run 5 `python/gunicorn` threads and load-balance then using `nginx`.

# Runnning in a Production Docker Container
The number of sessions and the destination DNS servers cna be changed using the environment variables
`DOH_SESSIONS` and `DOH_SERVERS`, which can be specified at the command line (using `docker run -e`) or in a file
using `docket run --env-file=`.

I've created a base container image called [`jamesstevens/mini-slack142-py38-nginx`](https://hub.docker.com/repository/docker/jamesstevens/mini-slack142-py38-nginx)
that has `nginx` and `Python` in it, and then created an application container to run `dnsflsk` in that.
`DOH_SERVERS` is a comma separated list of IP Addresses.

I also have a base container [using CentOS v8](https://hub.docker.com/repository/docker/jamesstevens/mini-centos8-py38-nginx) which you can use instead.
`DOH_SESSIONS` is simply a positive integer.

All you need to do is
`nginx` will also do the SSL using the key & certificate in the file `certkey.pem`, which has been created using a private
certificate authority. The public key for this private CA is in the file `myCA.pem`.

* Have a current `docker` platform :)
* Run `docker pull jamesstevens/mini-slack142-py38-nginx:vX.X` (where X.X is the latest version) to get the base container (optional)
* Run `./dkmk` to build the application container (must be run in a directory containing a clone of this project)
* Run `./dkrun init` to run it, you can also use `./dkrun sh` to shell into the container.
The server name for the key is `doh.jrcs.net` which should resolve to `127.0.0.1`, so if you start the container with `./dkrun`, then run

This will run `dnsflsk` (under `gunicorn`) and `nginx` under the very basic, but still very good, supervisor program `sysvinit`
curl --cacert myCA.pem https://doh.jrcs.net:800/dns/api/v1.0/resolv?name=www.google.com

You should get some commentary like this...
```
INIT: version 2.89 booting
INIT: Entering runlevel: 3
[2020-01-17 16:27:34 +0000] [8] [INFO] Starting gunicorn 20.0.4
[2020-01-17 16:27:34 +0000] [8] [INFO] Listening at: unix:/var/run/dnsflsk.sock (8)
[2020-01-17 16:27:34 +0000] [8] [INFO] Using worker: sync
[2020-01-17 16:27:34 +0000] [13] [INFO] Booting worker with pid: 13
```
then it whould work fine, but for production use I would recommend you replace the certificate with a publicly verifiable one.

Then, once again, a command like this should test it works
```
$ curl 'http://127.0.0.1:800/dns/api/v1.0/resolv?name=www.google.com'
```

You can also test the container by running `/bin/sh` instead, then running `/app/cmdresolv.py -n www.google.com` from the container's shell.
You can, of course, also (instead) invoke `cmdresolv.py` directly from a `docker run` command.

I've provided the one-line shell scripts `dkmk` to build the app container and `dkrun <cmd>` to run the container, where `<cmd>` will
probably be either `sh` to get a shell in the container or `init` to run `sysvinit` to start the application.

If you want to run `nginx` in the container as an `HTTPS` instead of an `HTTP` server, then all you need to do is copy a file called `cert.pem` into this
directory **before** you build the container. The file will then be copied into the `nginx/conf` directory and used by the `start_nginx` script.

The `cert.pem` file must contain **both** the private key and the certificate. For example ...
```
cat /opt/daemon/keys/letsencrypt/cert.pem /opt/daemon/keys/letsencrypt/privkey.pem > cert.pem
```
NOTE: the container is designed to run `read-only` so we would recommend you use this.
2 changes: 1 addition & 1 deletion dkmk
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#! /bin/bash

docker image build -t dnsflsk .
docker image build -t doh .
2 changes: 1 addition & 1 deletion dkrun
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#! /bin/sh

docker run --read-only -it -p 800:800 dnsflsk
docker run --read-only -it -p 800:800 doh
23 changes: 23 additions & 0 deletions myCA.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIID2zCCAsOgAwIBAgIJANSqK7ZFrRljMA0GCSqGSIb3DQEBCwUAMIGDMQswCQYD
VQQGEwJHQjEOMAwGA1UECAwFQmVya3MxEDAOBgNVBAcMB1dpbmRzb3IxDTALBgNV
BAoMBEpSQ1MxDDAKBgNVBAsMA0RldjEWMBQGA1UEAwwNamFtZXMuc3RldmVuczEd
MBsGCSqGSIb3DQEJARYOYWRtaW5AanJjcy5uZXQwHhcNMjAwNjExMTUyNjQ0WhcN
MjUwNjEwMTUyNjQ0WjCBgzELMAkGA1UEBhMCR0IxDjAMBgNVBAgMBUJlcmtzMRAw
DgYDVQQHDAdXaW5kc29yMQ0wCwYDVQQKDARKUkNTMQwwCgYDVQQLDANEZXYxFjAU
BgNVBAMMDWphbWVzLnN0ZXZlbnMxHTAbBgkqhkiG9w0BCQEWDmFkbWluQGpyY3Mu
bmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnIzDJ6crPQRWnNyg
ZLKHvjwCIrvqut4ExMf3O9diJueSo73omx9zl2ntJSZAhNAar+xro7meA8rnnZ3y
L4iMN0m9lZQS1tI93kfmDX0tla432mIlQl/Dl5lsUxUgLzDDoPHwS0yyk8d3sCeD
g4b4BXGogCe/kGq6XTyn1m53L5tyXQN3avoRkNi5cb8RTJUQ8g2O1ZQQpQUyDlZB
ufnZIRoUZCnxGj0SudcJmJH/+d5YYZNC+0I+rDB+4+sRovJ4UHjGbM22LsOzJBjb
ykIILe6tPhGyfLAxSVThSNnr4mOuucotztBkIycFdBrj1kR0kkzt2AvoDi8NZ4wy
tjvtFwIDAQABo1AwTjAdBgNVHQ4EFgQU2D8qsB6Jteqwjj6lR2GwnXkd4d8wHwYD
VR0jBBgwFoAU2D8qsB6Jteqwjj6lR2GwnXkd4d8wDAYDVR0TBAUwAwEB/zANBgkq
hkiG9w0BAQsFAAOCAQEAApqYNxfLeM/11N27/2PkS9lJov/DOV7gVwT4xBnpIkre
NY2pbU4YGkU8MEsQv16bPm3oayT3XnHsMGg95iZCeO6pW6ViigUm6t2rz8hsyiag
EXXV6XNd8U10tT7PeQVscAp3G3XZEXoZCsbMtDthrrXk8kcDqH4UTgyRfXzMylTG
W+uqX1ucdczXEoVt4NC6AWKGJ5nobiI2sRpLwiF/6WOJMv1uzBphptqKU9qQP7D3
8pSeBfhl8q525o7Tj6j61MDEmStm12twPEFhy10MYkWgMQUN9BQVmbP6Q9Povpqa
1KppticlnGGqBciYT3P6h6HEv9zmolsDGsTrsoutCQ==
-----END CERTIFICATE-----
4 changes: 2 additions & 2 deletions start_nginx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ http {
sendfile on;
keepalive_timeout 65;
upstream epp_servers {
upstream dns_servers {
"
sessions=5
if test "${DOH_SESSIONS}"; then sessions="${DOH_SESSIONS}"; fi
Expand Down Expand Up @@ -51,7 +51,7 @@ echo "
location / {
proxy_pass http://epp_servers;
proxy_pass http://dns_servers;
}
}
}"
Expand Down

0 comments on commit bff630d

Please sign in to comment.