Skip to content

Commit

Permalink
Merge pull request #3 from LolHens/master
Browse files Browse the repository at this point in the history
Updated for new dependency versions
  • Loading branch information
DSpeichert committed Apr 5, 2020
2 parents 26987a5 + 98c719f commit 034d779
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 36 deletions.
10 changes: 10 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM golang AS builder
COPY . src/godnsagent/
WORKDIR src/godnsagent/
RUN go get
RUN CGO_ENABLED=0 go build -ldflags "-X 'main.BuildTime=$(date)' -X 'main.BuildVersion=$(git log --pretty=format:'%h' -n 1)'"

FROM alpine
COPY --from=0 /go/src/godnsagent/godnsagent .
RUN chmod +x godnsagent
CMD /godnsagent
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,28 @@ go build -ldflags "-X main.buildtime '`date`' -X main.buildver '`git log --prett

How to run
============
* Parameter ```-z``` defines address of DNS zones. Defaults to http://localhost/zones.json
* Parameter ```-z``` defines address of DNS zones. Defaults to empty.
* Parameter ```-l``` defines the local IP (interface) to listen on. Defaults to all.
* Parameter ```-r``` enable recursive querying of specified servers for answers godnsagent can't provide itself.
* Parameter ```-k``` sets the API key (passed as GET or form value "key" to http notification handlers)
* Parameter ```-lf``` sets the logger flags (integer): https://golang.org/pkg/log/#pkg-constants
* Parameter ```--https``` configures the http server to use https. Defaults to true.
* Parameter ```--zones-reload-interval``` defines the interval in seconds to reload the DNS zones or disables auto reload if set to 0. Defaults to 0.

```
./godnsagent -z https://example.org/path/to/zones.json -l 127.0.0.1 -r 8.8.8.8:53 -k secretkeyhere
```

How it works
============
* Once you start the program, it will try to download the zones JSON document.
* Once you start the program, it will try to download the zones JSON document if the url is not empty.
* If the download fails, the program will fail (exit with error code).
* It binds to ports 53 on TCP and UDP and serves queries.
* The longest matching zone is chosen.
* Answers are marked as authoritative.
* All NS records on the zone are returned with an answer as "Authoritative" section.
* If possible, resolutions for NS records are added as "Extra" section.
* An HTTP GET request to :5380/notify invokes a reload of zones (the reload fails gracefully)
* An HTTP GET request to :5380/notify invokes a reload of zones if the url is not empty (the reload fails gracefully)
* HTTP requests require valid key passed as a GET parameter if such a key is defined
* An HTTP POST request to :5380/notify/zones processes JSON body of request as zones (zones are merged with cache but contents are replaced)
* If recursive querying is enabled, the question will be forwarded to the specified server
Expand Down
16 changes: 11 additions & 5 deletions http.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"net/http"

"github.com/codegangsta/cli"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)

// POST||GET /notify
Expand All @@ -18,7 +18,9 @@ func HTTPNotifyHandler(w http.ResponseWriter, r *http.Request) {
return
}
log.Println("Got HTTP prefetch notification, reloading zones...")
prefetch(zones, false)
if zoneUrl != "" {
prefetch(zones, false)
}
fmt.Fprintln(w, "ok")
}

Expand Down Expand Up @@ -108,7 +110,7 @@ func HTTPMetricsHandler(w http.ResponseWriter, r *http.Request) {
}
*/

prometheus.Handler().ServeHTTP(w, r)
promhttp.Handler().ServeHTTP(w, r)
}

func StartHTTP(c *cli.Context) {
Expand All @@ -120,6 +122,10 @@ func StartHTTP(c *cli.Context) {
handlers.HandleFunc("/metrics", HTTPMetricsHandler)

log.Println("Starting HTTP notification listener on", c.String("http-listen"))
log.Fatal(http.ListenAndServeTLS(c.String("http-listen"),
c.String("ssl-cert"), c.String("ssl-key"), handlers))
if c.Bool("https") {
log.Fatal(http.ListenAndServeTLS(c.String("http-listen"),
c.String("ssl-cert"), c.String("ssl-key"), handlers))
} else {
log.Fatal(http.ListenAndServe(c.String("http-listen"), handlers))
}
}
77 changes: 49 additions & 28 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ import (

"golang.org/x/net/idna"

"github.com/boltdb/bolt"
"github.com/codegangsta/cli"
"github.com/miekg/dns"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
bolt "go.etcd.io/bbolt"
)

var (
Expand Down Expand Up @@ -161,38 +162,52 @@ func dbWriteZones(zones map[string][]Record, flush bool) (err error) {
return
}

func startAutoReload(reloadInterval int64) {
for range time.Tick(time.Duration(reloadInterval) * time.Second) {
prefetch(zones, false)
}
}

func main() {
app := cli.NewApp()
app.Name = "godnsagent"
app.Usage = "Spigu Web Cloud: DNS Server Agent"
app.Version = buildver + " built " + buildtime
app.Author = "Daniel Speichert"
app.Email = "[email protected]"
app.Authors = []*cli.Author{
{
Name: "Daniel Speichert",
Email: "[email protected]",
},
}
app.Flags = []cli.Flag{
cli.StringFlag{Name: "zones, z", Value: "http://localhost/zones.json",
Usage: "The URL of zones in JSON format", EnvVar: "ZONES_URL"},
cli.StringFlag{Name: "listen, l", Value: "0.0.0.0:53",
Usage: "The IP:PORT to listen on", EnvVar: "LISTEN"},
cli.StringFlag{Name: "recurse, r", Value: "",
Usage: "Pass-through requests that we can't answer to other DNS server (address:port or empty=disabled)",
EnvVar: "RECURSE_TO"},
cli.StringFlag{Name: "http-listen", Value: "0.0.0.0:5380",
Usage: "IP:PORT to listen on for HTTP interface", EnvVar: "HTTP_LISTEN"},
cli.StringFlag{Name: "key, k", Value: "",
Usage: "API key for HTTP notifications",
EnvVar: "KEY"},
cli.StringFlag{Name: "ssl-cert", Value: "/etc/nginx/ssl/server.pem",
Usage: "path to SSL certificate", EnvVar: "SSL_CERT"},
cli.StringFlag{Name: "ssl-key", Value: "/etc/nginx/ssl/server.key",
Usage: "path to SSL key", EnvVar: "SSL_KEY"},
cli.IntFlag{Name: "flags, f", Value: log.LstdFlags,
Usage: "Logger flags (see https://golang.org/pkg/log/#pkg-constants)",
EnvVar: "LOGGER_FLAGS"},
cli.StringFlag{Name: "cache-db", Value: "/var/cache/godnsagent.db",
Usage: "path to cache DB file", EnvVar: "CACHE_DB"},
&cli.StringFlag{Name: "zones, z", Value: "",
Usage: "The URL of zones in JSON format", EnvVars: []string{"ZONES_URL"}},
&cli.Int64Flag{Name: "zones-reload-interval", Value: 0,
Usage: "The reload interval of the zones URL in seconds (0=disabled)", EnvVars: []string{"ZONES_RELOAD_INTERVAL"}},
&cli.StringFlag{Name: "listen, l", Value: "0.0.0.0:53",
Usage: "The IP:PORT to listen on", EnvVars: []string{"LISTEN"}},
&cli.StringFlag{Name: "recurse, r", Value: "",
Usage: "Pass-through requests that we can't answer to other DNS server (address:port or empty=disabled)",
EnvVars: []string{"RECURSE_TO"}},
&cli.StringFlag{Name: "http-listen", Value: "0.0.0.0:5380",
Usage: "IP:PORT to listen on for HTTP interface", EnvVars: []string{"HTTP_LISTEN"}},
&cli.StringFlag{Name: "key, k", Value: "",
Usage: "API key for HTTP notifications",
EnvVars: []string{"KEY"}},
&cli.BoolFlag{Name: "https", Value: true,
Usage: "Use HTTPS instead of HTTP", EnvVars: []string{"HTTPS"}},
&cli.StringFlag{Name: "ssl-cert", Value: "/etc/nginx/ssl/server.pem",
Usage: "path to SSL certificate", EnvVars: []string{"SSL_CERT"}},
&cli.StringFlag{Name: "ssl-key", Value: "/etc/nginx/ssl/server.key",
Usage: "path to SSL key", EnvVars: []string{"SSL_KEY"}},
&cli.IntFlag{Name: "flags, f", Value: log.LstdFlags,
Usage: "Logger flags (see https://golang.org/pkg/log/#pkg-constants)",
EnvVars: []string{"LOGGER_FLAGS"}},
&cli.StringFlag{Name: "cache-db", Value: "/var/cache/godnsagent.db",
Usage: "path to cache DB file", EnvVars: []string{"CACHE_DB"}},
}

app.Action = func(c *cli.Context) {
app.Action = func(c *cli.Context) error {
log.SetFlags(c.Int("flags"))
zoneUrl = c.String("zones")
recurseTo = c.String("recurse")
Expand Down Expand Up @@ -224,14 +239,13 @@ func main() {
}

// create prometheus counters
dnsReqs = prometheus.NewCounterVec(
dnsReqs = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "dns_requests_total",
Help: "How many DNS requests processed, partitioned by domain zone name and status code.",
},
[]string{"domain", "status"},
)
prometheus.MustRegister(dnsReqs)

// launch DNS server
server := &Server{
Expand All @@ -246,7 +260,14 @@ func main() {
go StartHTTP(c)

// request full DNS zone dump
prefetch(zones, false)
if zoneUrl != "" {
prefetch(zones, false)

reloadInterval := c.Int64("zones-reload-interval")
if reloadInterval > 0 {
go startAutoReload(reloadInterval)
}
}

sig := make(chan os.Signal)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
Expand Down

0 comments on commit 034d779

Please sign in to comment.