Skip to content

Commit

Permalink
MOD: Add multi-upstream plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
oif committed Nov 6, 2017
1 parent 9ffa2e2 commit a694adf
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 5 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ build :
clean :
rm *.coverprofile

.PHONY: test build clean
.PHONY: build clean
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
# ΛPΞX [WIP]
ΛPΞX is a DNS server written in Go, help you connect to the real Internet.

[![Build Status](https://travis-ci.org/oif/apex.svg?branch=master)](https://travis-ci.org/oif/apex)
[![Coverage Status](https://coveralls.io/repos/github/oif/apex/badge.svg?branch=master)](https://coveralls.io/github/oif/apex?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/oif/apex)](https://goreportcard.com/report/github.com/oif/apex)

ΛPΞX is a DNS server written in Go, help you connect to the real Internet.

# Feature
* edns-client-subnet
* Multiple DNS upstream
* DNS Over TLS
* UDP/TCP DNS
* Hosts
* DNSSEC
* Cache

# Official Plugins

# Package Management
Apex uses the Go community [dep](https://github.com/golang/dep) project for package management, but it's young so maybe will cause some unexcepted issue occurred during building. For more information about dep project status, check [dep - Current status](https://github.com/golang/dep#current-status)

Expand Down
7 changes: 6 additions & 1 deletion cmd/apexd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
engine "github.com/oif/apex/pkg/engine/v1"
"github.com/oif/apex/plugin/cache"
"github.com/oif/apex/plugin/gdns"
"github.com/oif/apex/plugin/mupstream"
"github.com/oif/apex/plugin/statistics"

log "github.com/Sirupsen/logrus"
Expand All @@ -21,7 +22,11 @@ func main() {
}())
s.RegisterPlugins(func() *cache.Plugin {
plugin := new(cache.Plugin)
plugin.CacheSize = 512
plugin.CacheSize = 1024
return plugin
}())
s.RegisterPlugins(func() *mupstream.Plugin {
plugin := new(mupstream.Plugin)
return plugin
}())
s.RegisterPlugins(func() *gdns.Plugin {
Expand Down
64 changes: 64 additions & 0 deletions plugin/mupstream/plugin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package mupstream

import (
"github.com/Sirupsen/logrus"
plugin "github.com/oif/apex/pkg/plugin/v1"
)

// PluginName for plugin
const PluginName = "Multi-upstream Plugin"

// Plugin implements pkg/plugin/v1
type Plugin struct {
upstreams []*upstream
}

// Name return the name of this plugin
func (p *Plugin) Name() string {
return PluginName
}

// Initialize Google DNS Plugin
func (p *Plugin) Initialize() error {
p.upstreams = append(p.upstreams, newUpstream("119.29.29.29:53"))
p.upstreams = append(p.upstreams, newUpstream("223.5.5.5:53"))
p.upstreams = append(p.upstreams, newUpstream("114.114.114.114:53"))
return nil
}

func (p *Plugin) Warmup(c *plugin.Context) {}
func (p *Plugin) AfterResponse(c *plugin.Context, err error) {}

func (p *Plugin) Patch(c *plugin.Context) {
up := p.bestUpstream()
resp, rtt, err := up.forward(c.Msg)
if err != nil {
c.Error(err)
return
}
resp.CopyTo(c.Msg)
c.Logger().WithFields(logrus.Fields{
"rtt": rtt,
"upstream": up,
}).Debug("Exchange message")

c.Abort() // stop other patch steps
}

func (p *Plugin) bestUpstream() *upstream {
best := 0
for i := 0; i < len(p.upstreams); i++ {
if p.upstreams[i].srtt < p.upstreams[0].srtt {
best = i
}
}
go func(selected int) { // lost decay
for i := 0; i < len(p.upstreams); i++ {
if i != selected {
p.upstreams[i].srttAttenuation()
}
}
}(best)

return p.upstreams[best]
}
55 changes: 55 additions & 0 deletions plugin/mupstream/upstream.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package mupstream

import (
"net"
"time"

"github.com/miekg/dns"
)

var checkClient = &dns.Client{
Net: "tcp",
ReadTimeout: 2 * time.Second,
WriteTimeout: 2 * time.Second,
}

type upstream struct {
addr string
srtt float32
fails uint32
client *dns.Client
}

func newUpstream(addr string) *upstream {
return &upstream{
addr: addr,
client: &dns.Client{
Net: "udp",
Dialer: &net.Dialer{
KeepAlive: time.Minute,
},
Timeout: time.Second,
},
}
}

func (u *upstream) String() string {
return u.addr
}

func (u *upstream) srttAttenuation() {
u.srtt *= 0.98
}

func (u *upstream) forward(m *dns.Msg) (*dns.Msg, time.Duration, error) {
resp, rtt, err := u.client.Exchange(m, u.addr)
if err != nil { //
u.srtt = u.srtt + 200
} else { // success
if rtt > 300 {
rtt = 300
}
u.srtt = u.srtt*0.7 + float32(rtt)*0.3
}
return resp, rtt, err
}

0 comments on commit a694adf

Please sign in to comment.