Skip to content

Commit

Permalink
Merge branch 'master' into minimal
Browse files Browse the repository at this point in the history
  • Loading branch information
Jan Broer committed Feb 12, 2016
2 parents f1878f1 + ad37396 commit 6ec6280
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 130 deletions.
120 changes: 59 additions & 61 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,73 +1,71 @@
# go-dnsmasq
*Version 0.9.8*

go-dnsmasq is a light weight (1.2 MB) DNS caching server/forwarder with minimal filesystem and runtime overhead. It is designed to serve global DNS records by forwarding queries to upstream nameservers as well as local hostname records from a hostsfile.
go-dnsmasq is a light weight (1.2 MB) DNS caching server/forwarder with minimal filesystem and runtime overhead.

### Application examples:

- as local DNS cache for Docker containers
- as nameserver providing local and global DNS records to clients in a private networks
- as DNS proxy providing `search` domain path capability to `musl-libc` based clients (e.g. Alpine Linux)
- Caching DNS server/forwarder in a local network
- Container/Host DNS cache
- DNS proxy providing DNS `search` capabilities to `musl-libc` based clients, particularly Alpine Linux

### Features

* Parses upstream nameservers from resolv.conf
* Configures itself as local DNS cache in resolv.conf
* Serves static hostname records from a hostsfile
* Caching of answers
* Replicates the `search` domain suffixing not supported by `musl-libc` based Linux distributions.
* Stubzones (use a different nameserver for specific domains)
* Round-robin of address records
* Sending stats to Graphite server
* Configuration through CLI and environment variables

### Resolver logic

DNS queries are processed according to the logic used by the GNU C resolver library:
* The first nameserver (as listed in resolv.conf or configured by `--nameservers`) is considered the primary server. Additional servers are queried only when the primary server times out or returns an error code.
* Multiple `search` paths are tried in the order they are configured.
* Single-label queries (e.g.: "redis-service") will always be qualified with `search` list elements
* For multi-label queries (ndots >= 1) the name will be tried first as an absolute name before any `search` list elements are appended to it.

### Commandline options

```sh
NAME:
go-dnsmasq - Lightweight caching DNS proxy for Docker containers

USAGE:
go-dnsmasq [global options] command [command options] [arguments...]

VERSION:
0.9.8

COMMANDS:
help, h Shows a list of commands or help for one command

GLOBAL OPTIONS:
--listen, -l "127.0.0.1:53" listen address: ‘host[:port]‘ [$DNSMASQ_LISTEN]
--default-resolver, -d make go-dnsmasq the local primary nameserver (updates /etc/resolv.conf) [$DNSMASQ_DEFAULT]
--nameservers, -n comma-separated list of name servers: ‘host[:port]‘ [$DNSMASQ_SERVERS]
--stubzones, -z domains to resolve using a specific nameserver: ‘fqdn[,fqdn]/host[:port]‘ [$DNSMASQ_STUB]
--hostsfile, -f full path to hostsfile (e.g. ‘/etc/hosts‘) [$DNSMASQ_HOSTSFILE]
--hostsfile-poll, -p "0" how frequently to poll hostsfile (in seconds, ‘0‘ to disable) [$DNSMASQ_POLL]
--search-domains, -s specify SEARCH domains taking precedence over /etc/resolv.conf: ‘fqdn[,fqdn]‘ [$DNSMASQ_SEARCH]
--append-search-domains, -a enable suffixing single-label queries with SEARCH domains [$DNSMASQ_APPEND]
--rcache, -r "0" capacity of the response cache (‘0‘ to disable caching) [$DNSMASQ_RCACHE]
--rcache-ttl "60" TTL of entries in the response cache [$DNSMASQ_RCACHE_TTL]
--no-rec disable recursion [$DNSMASQ_NOREC]
--round-robin enable round robin of A/AAAA replies [$DNSMASQ_RR]
--systemd bind to socket(s) activated by systemd (ignores --listen) [$DNSMASQ_SYSTEMD]
--verbose enable verbose logging [$DNSMASQ_VERBOSE]
--syslog enable syslog logging [$DNSMASQ_SYSLOG]
--multithreading enable multithreading (num physical CPU cores) [$DNSMASQ_MULTITHREADING]
--help, -h show help
--version, -v print the version
```

### Environment Variables

See above (the names inside the brackets).
* Automatically set upstream `nameservers` and `search` domains from resolv.conf
* Insert itself into the host's /etc/resolv.conf on start
* Serve static A/AAAA records from a hostsfile
* Provide DNS response caching
* Replicate the `search` domain treatment not supported by `musl-libc` based Linux distributions
* Supports virtually unlimited number of `search` paths and `nameservers` ([related Kubernetes article](https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/dns#known-issues))
* Configure stubzones (different nameserver for specific domains)
* Round-robin of DNS records
* Send server metrics to Graphite and StatHat
* Configuration through both command line flags and environment variables

### Resolve logic

DNS queries are resolved in the style of the GNU libc resolver:
* The first nameserver (as listed in resolv.conf or configured by `--nameservers`) is always queried first, additional servers are considered fallbacks
* Multiple `search` domains are tried in the order they are configured.
* Single-label queries (e.g.: "redis-service") are always qualified with the `search` domains
* Multi-label queries (ndots >= 1) are first tried as absolute names before qualifying them with the `search` domains

### Command-line options / environment variables

| Flag | Description | Default | Environment vars |
| ------------------------------ | ----------------------------------------------------------------------------- | ------------- | -------------------- |
| --listen, -l | Address to listen on `host[:port]` | 127.0.0.1:53 | $DNSMASQ_LISTEN |
| --default-resolver, -d | Update resolv.conf and make go-dnsmasq the host's primary nameserver | False | $DNSMASQ_DEFAULT |
| --nameservers, -n | Comma-separated list of nameservers `host[:port]` | - | $DNSMASQ_SERVERS |
| --stubzones, -z | Use different nameservers for specific domains `fqdn[,fqdn]/host[:port]` | - | $DNSMASQ_STUB |
| --hostsfile, -f | Full path to a hostsfile | - | $DNSMASQ_HOSTSFILE |
| --hostsfile-poll, -p | How frequently to check hostsfile for changes (seconds, ‘0‘ to disable) | 0 | $DNSMASQ_POLL |
| --search-domains, -s | Specify SEARCH domains (takes precedence over /etc/resolv.conf) `fqdn[,fqdn]` | - | $DNSMASQ_SEARCH |
| --append-search-domains, -a | Qualify queries with SEARCH domains | False | $DNSMASQ_APPEND |
| --rcache, -r | Capacity of the response cache (‘0‘ to disable cache) | 0 | $DNSMASQ_RCACHE |
| --rcache-ttl | TTL for entries in the response cache | 60 | $DNSMASQ_RCACHE_TTL |
| --no-rec | Disable recursion | False | $DNSMASQ_NOREC |
| --round-robin | enable round robin of A/AAAA records | False | $DNSMASQ_RR |
| --systemd | Bind to socket(s) activated by Systemd (ignores --listen) | False | $DNSMASQ_SYSTEMD |
| --verbose | Enable verbose logging | False | $DNSMASQ_VERBOSE |
| --syslog | Log to syslog | False | $DNSMASQ_SYSLOG |
| --multithreading | Enable multithreading | False | |
| --help, -h | Show help | | |
| --version, -v | Print the version | | |

#### Enable Graphite/StatHat metrics

EnvVar: **GRAPHITE_SERVER**
Default: ` `
Set to the `host:port` of the Graphite server

EnvVar: **GRAPHITE_PREFIX**
Default: `go-dnsmasq`
Set a custom prefix for Graphite metrics

EnvVar: **STATHAT_USER**
Default: ` `
Set to your StatHat account email address

### Usage

Expand Down
6 changes: 3 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (
)

// var Version string
const Version = "0.9.8"
const Version = "0.9.9"

var (
nameservers = []string{}
Expand Down Expand Up @@ -173,7 +173,7 @@ func main() {
if sd := c.String("search-domains"); sd != "" {
for _, domain := range strings.Split(sd, ",") {

if dns.CountLabel(domain) < 2 {
if dns.CountLabel(domain) < 1 {
log.Fatalf("This search domain is not a FQDN: %s", domain)
}
domain = dns.Fqdn(strings.ToLower(domain))
Expand Down Expand Up @@ -231,7 +231,7 @@ func main() {
}

for _, sdomain := range strings.Split(segments[0], ",") {
if dns.CountLabel(sdomain) < 2 {
if dns.CountLabel(sdomain) < 1 {
log.Fatalf("This stubzones domain is not a FQDN: %s", sdomain)
}
sdomain = dns.Fqdn(sdomain)
Expand Down
23 changes: 18 additions & 5 deletions server/forwarding.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ func (s *server) ServeDNSForward(w dns.ResponseWriter, req *dns.Msg) *dns.Msg {
var (
r *dns.Msg
err error
nsList []string
nsIndex int // nameserver list index
sdIndex int // search list index
sdName string // QNAME with search path
Expand Down Expand Up @@ -80,11 +81,23 @@ Redo:
req.Question[0] = dns.Question{sdName, req.Question[0].Qtype, req.Question[0].Qclass}
}

nsList = s.config.Nameservers

// Check whether the name matches a stub zone
for zone, nss := range *s.config.Stub {
if strings.HasSuffix(req.Question[0].Name, zone) {
nsList = nss
break
}
}

log.Debugf("Querying nameserver %s question %s", nsList[nsIndex], req.Question[0].Name)

switch tcp {
case false:
r, _, err = s.dnsUDPclient.Exchange(req, s.config.Nameservers[nsIndex])
r, _, err = s.dnsUDPclient.Exchange(req, nsList[nsIndex])
case true:
r, _, err = s.dnsTCPclient.Exchange(req, s.config.Nameservers[nsIndex])
r, _, err = s.dnsTCPclient.Exchange(req, nsList[nsIndex])
}
if err == nil {
if canSearch {
Expand All @@ -111,7 +124,7 @@ Redo:

if r.Rcode == dns.RcodeServerFailure || r.Rcode == dns.RcodeRefused {
// continue with next available nameserver
if (nsIndex + 1) < len(s.config.Nameservers) {
if (nsIndex + 1) < len(nsList) {
nsIndex++
doingSearch = false
goto Redo
Expand All @@ -138,10 +151,10 @@ Redo:
w.WriteMsg(r)
return r
} else {
log.Debugf("Error querying nameserver %s: %q", s.config.Nameservers[nsIndex], err)
log.Debugf("Error querying nameserver %s: %q", nsList[nsIndex], err)
// Got an error, this usually means the server did not respond
// Continue with next available nameserver
if (nsIndex + 1) < len(s.config.Nameservers) {
if (nsIndex + 1) < len(nsList) {
nsIndex++
doingSearch = false
goto Redo
Expand Down
9 changes: 0 additions & 9 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,15 +202,6 @@ func (s *server) ServeDNS(w dns.ResponseWriter, req *dns.Msg) {
return
}

// Forward queries matching stub zones
for zone, ns := range *s.config.Stub {
if strings.HasSuffix(name, zone) {
local = false
s.ServeDNSStubForward(w, req, ns)
return
}
}

// Forward all other queries
local = false
s.ServeDNSForward(w, req)
Expand Down
52 changes: 0 additions & 52 deletions server/stub.go

This file was deleted.

0 comments on commit 6ec6280

Please sign in to comment.