Skip to content

Commit

Permalink
Merge pull request #203 from Luzilla/system-resolver
Browse files Browse the repository at this point in the history
system resolver
  • Loading branch information
till authored Mar 28, 2024
2 parents f2233cc + ac61f63 commit 8c6250a
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 64 deletions.
101 changes: 50 additions & 51 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
@@ -1,68 +1,67 @@
---
name: integration

on:
pull_request:

jobs:
e2e:
snapshot:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: false
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v5
with:
version: latest
args: release --config ./.goreleaser.ci.yml --clean --snapshot
- name: Copy .ini files
run: cp targets.ini rbls.ini ./dist/dnsbl_exporter_linux_amd64_v1
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: dnsbl_exporter
path: dist/dnsbl_exporter_linux_amd64_v1
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: false
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v5
with:
version: latest
args: release --config ./.goreleaser.ci.yml --clean --snapshot
- name: Copy .ini files
run: cp targets.ini rbls.ini ./dist/dnsbl_exporter_linux_amd64_v1
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: dnsbl_exporter
path: dist/dnsbl_exporter_linux_amd64_v1

integration:
runs-on: ubuntu-latest
needs:
- snapshot
- snapshot
services:
unbound:
image: klutchell/unbound:latest
ports:
- 5053:5053/tcp
- 5053:5053/udp
- 5053:5053/tcp
- 5053:5053/udp
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: false
- uses: goreleaser/goreleaser-action@v5
with:
version: latest
args: release --config ./.goreleaser.ci.yml --clean --snapshot
- run: cp targets.ini rbls.ini ./dist/dnsbl_exporter_linux_amd64_v1
- uses: JarvusInnovations/background-action@v1
with:
run: |
ls -lah && ./dnsbl-exporter --log.debug --config.dns-resolver=localhost:5053 &
wait-on: |
http-get://localhost:9211/
http-get://localhost:9211/metrics
http-get://localhost:9211/prober?target=github.com
tail: true # true = stderr,stdout
log-output-resume: stderr
wait-for: 1m
log-output: stderr,stdout
working-directory: ./dist/dnsbl_exporter_linux_amd64_v1
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: false
- uses: goreleaser/goreleaser-action@v5
with:
version: latest
args: release --config ./.goreleaser.ci.yml --clean --snapshot
- run: cp targets.ini rbls.ini ./dist/dnsbl_exporter_linux_amd64_v1
- uses: JarvusInnovations/background-action@v1
with:
run: |
ls -lah && ./dnsbl-exporter --log.debug --config.dns-resolver=localhost:5053 &
wait-on: |
http-get://localhost:9211/
http-get://localhost:9211/metrics
http-get://localhost:9211/prober?target=github.com
tail: true # true = stderr,stdout
log-output-resume: stderr
wait-for: 1m
log-output: stderr,stdout
working-directory: ./dist/dnsbl_exporter_linux_amd64_v1
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,15 @@ $ sudo unbound -d -vvvv
192.42.118.104
```

### Use /etc/resolv.conf

Use `system` as a value and the exporter will pick the **first** resolver from `/etc/resolv.conf`.

Adequate permissions need to be set by yourself so the exporter can read the file.

- `--config.dns-resolver=system`
- `DNSBL_EXP_RESOLVER=system`

## License / Author

This code is Apache 2.0 licensed.
Expand Down
63 changes: 50 additions & 13 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/Luzilla/dnsbl_exporter/internal/index"
"github.com/Luzilla/dnsbl_exporter/internal/metrics"
"github.com/Luzilla/dnsbl_exporter/internal/prober"
"github.com/Luzilla/dnsbl_exporter/internal/resolvconf"
"github.com/Luzilla/dnsbl_exporter/internal/setup"
"github.com/Luzilla/dnsbl_exporter/pkg/dns"
"github.com/prometheus/client_golang/prometheus/collectors"
Expand All @@ -30,6 +31,8 @@ var (
resolver string
)

const resolvConfFile = "/etc/resolv.conf"

// NewApp ...
func NewApp(name string, version string) DNSBLApp {
appName = name
Expand All @@ -42,7 +45,7 @@ func NewApp(name string, version string) DNSBLApp {
&cli.StringFlag{
Name: "config.dns-resolver",
Value: "127.0.0.1:53",
Usage: "IP address[:port] of the resolver to use.",
Usage: "IP address[:port] of the resolver to use, use `system` to use a resolve from " + resolvConfFile,
EnvVars: []string{"DNSBL_EXP_RESOLVER"},
Destination: &resolver,
},
Expand Down Expand Up @@ -102,6 +105,17 @@ func NewApp(name string, version string) DNSBLApp {
return nil
},
},
&cli.StringFlag{
Name: "log.format",
Value: "text",
Usage: "format, text is logfmt or use json",
Action: func(cCtx *cli.Context, v string) error {
if v != "text" && v != "json" {
return cli.Exit("We currently support only text and json: --log.format", 2)
}
return nil
},
},
}

return DNSBLApp{
Expand All @@ -110,29 +124,36 @@ func NewApp(name string, version string) DNSBLApp {
}

func (a *DNSBLApp) Bootstrap() {
a.App.Action = func(ctx *cli.Context) error {
a.App.Action = func(cCtx *cli.Context) error {
// setup logging
handler := &slog.HandlerOptions{}
var writer io.Writer

if ctx.Bool("log.debug") {
if cCtx.Bool("log.debug") {
handler.Level = slog.LevelDebug
}

switch ctx.String("log.output") {
switch cCtx.String("log.output") {
case "stdout":
writer = os.Stdout
case "stderr":
writer = os.Stderr
}

log := slog.New(handler.NewTextHandler(writer))
var logHandler slog.Handler
if cCtx.String("log.format") == "text" {
logHandler = handler.NewTextHandler(writer)
} else {
logHandler = handler.NewJSONHandler(writer)
}

log := slog.New(logHandler)

c := config.Config{
Logger: log.With("area", "config"),
}

cfgRbls, err := c.LoadFile(ctx.String("config.rbls"))
cfgRbls, err := c.LoadFile(cCtx.String("config.rbls"))
if err != nil {
return err
}
Expand All @@ -142,7 +163,7 @@ func (a *DNSBLApp) Bootstrap() {
return fmt.Errorf("unable to load the rbls from the config: %w", err)
}

cfgTargets, err := c.LoadFile(ctx.String("config.targets"))
cfgTargets, err := c.LoadFile(cCtx.String("config.targets"))
if err != nil {
return err
}
Expand All @@ -155,6 +176,22 @@ func (a *DNSBLApp) Bootstrap() {
log.Info("starting exporter without targets — check the /prober endpoint or correct the .ini file")
}

// use the system's resolver
if resolver == "system" {
log.Info("fetching resolver from " + resolvConfFile)
servers, err := resolvconf.GetServers(resolvConfFile)
if err != nil {
return err
}
if len(servers) == 0 {
return fmt.Errorf("unable to return a server from %s", resolvConfFile)
}

// pick the first
resolver = servers[0]
log.Info("using resolver: " + resolver)
}

iHandler := index.IndexHandler{
Name: appName,
Version: appVersion,
Expand All @@ -174,12 +211,12 @@ func (a *DNSBLApp) Bootstrap() {
return err
}

rblCollector := setup.CreateCollector(rbls, targets, ctx.Bool("config.domain-based"), dnsUtil, log.With("area", "metrics"))
rblCollector := setup.CreateCollector(rbls, targets, cCtx.Bool("config.domain-based"), dnsUtil, log.With("area", "metrics"))
registry.MustRegister(rblCollector)

registryExporter := setup.CreateRegistry()

if ctx.Bool("web.include-exporter-metrics") {
if cCtx.Bool("web.include-exporter-metrics") {
log.Info("Exposing exporter metrics")

registryExporter.MustRegister(
Expand All @@ -193,21 +230,21 @@ func (a *DNSBLApp) Bootstrap() {
RegistryExporter: registryExporter,
}

http.Handle(ctx.String("web.telemetry-path"), mHandler.Handler())
http.Handle(cCtx.String("web.telemetry-path"), mHandler.Handler())

pHandler := prober.ProberHandler{
DNS: dnsUtil,
Rbls: rbls,
DomainBased: ctx.Bool("config.domain-based"),
DomainBased: cCtx.Bool("config.domain-based"),
Logger: log.With("area", "prober"),
}
http.Handle("/prober", pHandler)

log.Info("starting exporter",
slog.String("web.listen-address", ctx.String("web.listen-address")),
slog.String("web.listen-address", cCtx.String("web.listen-address")),
slog.String("resolver", resolver),
)
err = http.ListenAndServe(ctx.String("web.listen-address"), nil)
err = http.ListenAndServe(cCtx.String("web.listen-address"), nil)
if err != nil {
return err
}
Expand Down
1 change: 1 addition & 0 deletions internal/resolvconf/fixtures/no-server.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
search anything.local
3 changes: 3 additions & 0 deletions internal/resolvconf/fixtures/two-servers.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# two servers
nameserver 1.1.1.1
nameserver 8.8.8.8
33 changes: 33 additions & 0 deletions internal/resolvconf/resolvconf.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package resolvconf

import (
"bufio"
"os"
"strings"
)

func GetServers(path string) (servers []string, err error) {
file, err := os.Open(path)
if err != nil {
return
}
defer file.Close()

scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
if !strings.HasPrefix(line, "nameserver ") {
continue
}

server, ok := strings.CutPrefix(line, "nameserver ")
if !ok {
continue
}

servers = append(servers, server)
}

err = scanner.Err()
return
}
31 changes: 31 additions & 0 deletions internal/resolvconf/resolvconf_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package resolvconf_test

import (
"path/filepath"
"testing"

"github.com/Luzilla/dnsbl_exporter/internal/resolvconf"
"github.com/stretchr/testify/assert"
)

func TestGetServers(t *testing.T) {
testCases := []struct {
path string
expected []string
}{
{
path: "no-server.conf",
expected: []string(nil),
},
{
path: "two-servers.conf",
expected: []string{"1.1.1.1", "8.8.8.8"},
},
}

for _, tc := range testCases {
servers, err := resolvconf.GetServers(filepath.Join("fixtures", tc.path))
assert.NoError(t, err)
assert.Equal(t, tc.expected, servers)
}
}

0 comments on commit 8c6250a

Please sign in to comment.