Skip to content

Commit a73fe91

Browse files
authored
Merge pull request #59 from mageddo/feature/58
Domains Wildcard - Feature/58
2 parents cdefde7 + ff848b5 commit a73fe91

File tree

8 files changed

+256
-116
lines changed

8 files changed

+256
-116
lines changed

RELEASE-NOTES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
### 2.3.3
2+
* Domains wildcard support
3+
If you register a hostname with `.` at start, then all subdomains will solve to that container/local storage entry
4+
15
### 2.2.3
26
* Some times container hostname don't get registered at machine startup
37

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.2.3
1+
2.3.3

dns.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ func handleQuestion(respWriter dns.ResponseWriter, reqMsg *dns.Msg) {
4747
questionsQtd, firstQuestion.Name, utils.DnsQTypeCodeToName(firstQuestion.Qtype))
4848

4949
// loading the solvers and try to solve the hostname in that order
50-
solvers := []proxy.DnsSolver{&proxy.DockerDnsSolver{}, proxy.NewLocalDNSSolver(store.GetInstance()), proxy.NewRemoteDnsSolver()}
50+
solvers := []proxy.DnsSolver{
51+
proxy.NewDockerSolver(docker.GetCache()), proxy.NewLocalDNSSolver(store.GetInstance()), proxy.NewRemoteDnsSolver(),
52+
}
53+
5154
for _, solver := range solvers {
5255

5356
solverID := reflect.TypeOf(solver).String()
Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,19 @@ import (
1010
"golang.org/x/net/context"
1111
log "github.com/mageddo/go-logging"
1212
"github.com/docker/engine-api/types"
13+
"github.com/mageddo/dns-proxy-server/cache/lru"
14+
"github.com/mageddo/dns-proxy-server/cache"
1315
"strings"
1416
"errors"
1517
)
1618

17-
var cache = make(map[string]string)
19+
var c = lru.New(43690);
1820

1921
func HandleDockerEvents(){
2022
defaultLogger := log.NewContext()
2123
logger := log.NewLog(defaultLogger)
2224

23-
// adaptar a api do docker aqui
25+
// connecting to docker api
2426
cli, err := client.NewClient("unix:///var/run/docker.sock", "v1.21", nil, nil)
2527
if err != nil {
2628
logger.Errorf("status=error-to-connect-at-host, solver=docker, err=%v", err)
@@ -97,7 +99,7 @@ func HandleDockerEvents(){
9799

98100
case "stop", "die":
99101
for _, host := range hostnames {
100-
remove(host)
102+
c.Remove(host)
101103
}
102104
break
103105

@@ -106,26 +108,8 @@ func HandleDockerEvents(){
106108

107109
}
108110

109-
func ContainsKey(key string) bool {
110-
_, ok := cache[key]
111-
if ok {
112-
return true
113-
}
114-
return false
115-
}
116-
117-
func Get(key string) string {
118-
return cache[key]
119-
}
120-
121-
func GetCache() map[string]string {
122-
return cache
123-
}
124-
125-
func remove(key string){
126-
if ContainsKey(key) {
127-
delete(cache, key)
128-
}
111+
func GetCache() cache.Cache {
112+
return c
129113
}
130114

131115
func getHostnames(inspect types.ContainerJSON) []string {
@@ -169,7 +153,7 @@ func putHostnames(ctx context.Context, hostnames []string, inspect types.Contain
169153
}
170154
}
171155
logger.Debugf("host=%s, ip=%s", host, ip)
172-
cache[host] = ip
156+
c.Put(host, ip)
173157
}
174158
return nil
175159
}

proxy/docker.go

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,54 @@
11
package proxy
22

33
import (
4-
"github.com/miekg/dns"
5-
"github.com/mageddo/dns-proxy-server/events/docker"
4+
"errors"
5+
"github.com/mageddo/dns-proxy-server/cache"
66
log "github.com/mageddo/go-logging"
7+
"github.com/miekg/dns"
8+
"golang.org/x/net/context"
79
"net"
8-
"strings"
910
"strconv"
10-
"errors"
11-
"golang.org/x/net/context"
11+
"strings"
1212
)
1313

1414
type DockerDnsSolver struct {
15-
15+
c cache.Cache
1616
}
1717

18-
func (DockerDnsSolver) Solve(ctx context.Context, question dns.Question) (*dns.Msg, error) {
18+
func (s DockerDnsSolver) Solve(ctx context.Context, question dns.Question) (*dns.Msg, error) {
1919

2020
logger := log.NewLog(ctx)
2121
key := question.Name[:len(question.Name)-1]
22-
if docker.ContainsKey(key) {
23-
logger.Debugf("solver=docker, status=solved-key, solver=docker, hostname=%s, ip=%s", key, docker.Get(key))
24-
ip := docker.Get(key)
25-
ipArr := strings.Split(ip, ".")
26-
i1, _ := strconv.Atoi(ipArr[0])
27-
i2, _ := strconv.Atoi(ipArr[1])
28-
i3, _ := strconv.Atoi(ipArr[2])
29-
i4, _ := strconv.Atoi(ipArr[3])
30-
31-
rr := &dns.A{
32-
Hdr: dns.RR_Header{Name: question.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0},
33-
A: net.IPv4(byte(i1), byte(i2), byte(i3), byte(i4)),
34-
}
35-
36-
m := new(dns.Msg)
37-
m.Answer = append(m.Answer, rr)
38-
return m, nil
22+
if s.c.ContainsKey(key) {
23+
logger.Debugf("solver=docker, status=solved-key, solver=docker, hostname=%s, ip=%+v", key, s.c.Get(key))
24+
return s.getMsg(key, question), nil
25+
}
26+
i := strings.Index(key, ".")
27+
if i > 0 && s.c.ContainsKey(key[i:]) {
28+
logger.Debugf("solver=docker, status=solved-key-wildcard, solver=docker, hostname=%s, ip=%+v", key, s.c.Get(key[i:]))
29+
return s.getMsg(key[i:], question), nil
3930
}
4031
return nil, errors.New("hostname not found " + key)
4132
}
33+
34+
func NewDockerSolver(c cache.Cache) DockerDnsSolver {
35+
return DockerDnsSolver{c}
36+
}
37+
38+
func (s DockerDnsSolver) getMsg(key string, question dns.Question) *dns.Msg {
39+
ip := s.c.Get(key).(string)
40+
ipArr := strings.Split(ip, ".")
41+
i1, _ := strconv.Atoi(ipArr[0])
42+
i2, _ := strconv.Atoi(ipArr[1])
43+
i3, _ := strconv.Atoi(ipArr[2])
44+
i4, _ := strconv.Atoi(ipArr[3])
45+
46+
rr := &dns.A{
47+
Hdr: dns.RR_Header{Name: question.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0},
48+
A: net.IPv4(byte(i1), byte(i2), byte(i3), byte(i4)),
49+
}
50+
51+
m := new(dns.Msg)
52+
m.Answer = append(m.Answer, rr)
53+
return m
54+
}

proxy/docker_test.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package proxy
2+
3+
import (
4+
"testing"
5+
"github.com/miekg/dns"
6+
"github.com/stretchr/testify/mock"
7+
"github.com/stretchr/testify/assert"
8+
"github.com/mageddo/go-logging"
9+
"github.com/mageddo/dns-proxy-server/cache/lru"
10+
"github.com/mageddo/dns-proxy-server/cache"
11+
glru "github.com/hashicorp/golang-lru"
12+
)
13+
14+
var ctx = logging.NewContext()
15+
var logger = logging.NewLog(ctx)
16+
17+
func TestDockerSolve_HostFound(t *testing.T){
18+
c := newCacheMock()
19+
solver := NewDockerSolver(c)
20+
c.Put("host1.com", "127.0.0.1");
21+
22+
q := dns.Question{Name: "host1.com."}
23+
24+
msg, err := solver.Solve(ctx, q)
25+
assert.Nil(t, err)
26+
assert.NotNil(t, msg)
27+
28+
}
29+
30+
func TestDockerSolve_HostNotFound(t *testing.T){
31+
c := newCacheMock()
32+
33+
solver := NewDockerSolver(c)
34+
35+
q := dns.Question{Name: "host1.com."}
36+
msg, err := solver.Solve(ctx, q)
37+
assert.Nil(t, msg)
38+
assert.NotNil(t, err)
39+
40+
}
41+
42+
func TestDockerSolve_WildcardDomain(t *testing.T){
43+
c := newCacheMock()
44+
c.Put(".host1.com", "127.0.0.1");
45+
46+
solver := NewDockerSolver(c)
47+
48+
q := dns.Question{Name: "sub1.host1.com."}
49+
msg, err := solver.Solve(ctx, q)
50+
assert.Nil(t, err)
51+
assert.NotNil(t, msg)
52+
53+
}
54+
55+
type CacheMock struct {
56+
mock.Mock
57+
lru.LRUCache
58+
}
59+
60+
func newCacheMock() cache.Cache {
61+
var err error;
62+
m := CacheMock{}
63+
m.Cache, err = glru.New(10)
64+
if err != nil {
65+
panic(err);
66+
}
67+
return &m
68+
}

proxy/local.go

Lines changed: 53 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
package proxy
22

33
import (
4-
. "github.com/mageddo/dns-proxy-server/log"
54
"errors"
6-
"github.com/miekg/dns"
7-
"net"
5+
"github.com/mageddo/dns-proxy-server/cache"
6+
"github.com/mageddo/dns-proxy-server/cache/timed"
87
"github.com/mageddo/dns-proxy-server/events/local"
8+
. "github.com/mageddo/dns-proxy-server/log"
9+
"github.com/miekg/dns"
910
"golang.org/x/net/context"
10-
"github.com/mageddo/dns-proxy-server/cache"
11+
"net"
12+
"strings"
1113
"time"
12-
"github.com/mageddo/dns-proxy-server/cache/timed"
1314
)
1415

1516
type localDnsSolver struct {
@@ -19,40 +20,13 @@ type localDnsSolver struct {
1920
func (s localDnsSolver) Solve(ctx context.Context, question dns.Question) (*dns.Msg, error) {
2021

2122
key := question.Name[:len(question.Name)-1]
22-
var hostname *local.HostnameVo
23-
if value, found := s.ContainsKey(key); found {
24-
LOGGER.Debugf("solver=local, status=from-cache, hostname=%s, value=%v", key, value)
25-
if value != nil {
26-
hostname = value.(*local.HostnameVo)
27-
}
28-
} else {
29-
LOGGER.Debugf("solver=local, status=hot-load, hostname=%s", key)
30-
conf, err := local.LoadConfiguration(ctx)
31-
if err != nil {
32-
LOGGER.Errorf("status=could-not-load-conf, err=%v", err)
33-
return nil, err
34-
}
35-
activeEnv,_ := conf.GetActiveEnv()
36-
if activeEnv == nil {
37-
return nil, errors.New("original env")
38-
}
39-
var ttl int64 = 86400 // 24 hours
40-
hostname,_ = activeEnv.GetHostname(key)
41-
if hostname != nil { ttl = int64(hostname.Ttl) }
42-
val := s.Cache.PutIfAbsent(key, timed.NewTimedValue(hostname, time.Now(), time.Duration(ttl) * time.Second));
43-
LOGGER.Debugf("status=put, key=%s, value=%v, ttl=%d", key, val, ttl)
23+
if msg, err := s.solveHostname(ctx, question, key); err == nil {
24+
return msg, err
4425
}
4526

46-
if hostname != nil {
47-
rr := &dns.A{
48-
Hdr: dns.RR_Header{Name: question.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0},
49-
A: net.IPv4(hostname.Ip[0], hostname.Ip[1], hostname.Ip[2], hostname.Ip[3]),
50-
}
51-
52-
m := new(dns.Msg)
53-
m.Answer = append(m.Answer, rr)
54-
LOGGER.Debugf("status=success, solver=local, key=%s", key)
55-
return m, nil
27+
i := strings.Index(key, ".")
28+
if i > 0 {
29+
return s.solveHostname(ctx, question, key[i:])
5630
}
5731
return nil, errors.New("hostname not found " + key)
5832
}
@@ -72,6 +46,47 @@ func (s localDnsSolver) ContainsKey(key interface{}) (interface{}, bool) {
7246
}
7347
LOGGER.Debugf("status=expired, key=%v", key)
7448
s.Cache.Remove(key)
75-
return nil, false;
49+
return nil, false
7650
}
7751

52+
func (*localDnsSolver) getMsg(question dns.Question, hostname *local.HostnameVo) *dns.Msg {
53+
rr := &dns.A{
54+
Hdr: dns.RR_Header{Name: question.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0},
55+
A: net.IPv4(hostname.Ip[0], hostname.Ip[1], hostname.Ip[2], hostname.Ip[3]),
56+
}
57+
m := new(dns.Msg)
58+
m.Answer = append(m.Answer, rr)
59+
return m
60+
}
61+
62+
func (s localDnsSolver) solveHostname(ctx context.Context, question dns.Question, key string) (*dns.Msg, error) {
63+
if value, found := s.ContainsKey(key); found {
64+
LOGGER.Debugf("solver=local, status=from-cache, hostname=%s, value=%v", key, value)
65+
hostname := value.(*local.HostnameVo)
66+
if hostname != nil {
67+
return s.getMsg(question, hostname), nil
68+
}
69+
}
70+
71+
LOGGER.Debugf("solver=local, status=hot-load, hostname=%s", key)
72+
conf, err := local.LoadConfiguration(ctx)
73+
if err != nil {
74+
LOGGER.Errorf("status=could-not-load-conf, err=%v", err)
75+
return nil, err
76+
}
77+
activeEnv, _ := conf.GetActiveEnv()
78+
if activeEnv == nil {
79+
return nil, errors.New("original env")
80+
}
81+
var ttl int64 = 86400 // 24 hours
82+
hostname, _ := activeEnv.GetHostname(key)
83+
if hostname != nil {
84+
ttl = int64(hostname.Ttl)
85+
}
86+
val := s.Cache.PutIfAbsent(key, timed.NewTimedValue(hostname, time.Now(), time.Duration(ttl)*time.Second))
87+
LOGGER.Debugf("status=put, key=%s, value=%v, ttl=%d", key, val, ttl)
88+
if hostname != nil {
89+
return s.getMsg(question, hostname), nil
90+
}
91+
return nil, errors.New("hostname not found " + key)
92+
}

0 commit comments

Comments
 (0)