Skip to content

Commit 07949f5

Browse files
committed
Added sticky mode
1 parent 369aaf4 commit 07949f5

File tree

6 files changed

+73
-2
lines changed

6 files changed

+73
-2
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ DNS server parses requested name to extract the requested mode, IP or CNAME by t
99
<proxy-name>.p.<zone> -> resolve proxy name and returns it
1010
<ip1>.<ip2>.r.<zone> -> pick random <ip1> or <ip2>
1111
<ip1>.<ip2>.l.<zone> -> loop over <ip1> and <ip2>
12+
<ip1>.<ip2>.s.<zone> -> "sticky" - <ip1> for first request, then <ip2> in sticky TTL (30 sec by default)
1213
<cname>.c.<zone> -> return CNAME record with <cname>
1314
<any-name>.<zone> -> returns default address
1415
[(<IPv4>.4|<IPv6>.6)...(<IPv4>.4|<IPv6>.6)].m.<zone> -> returns multiple address according to order and type
@@ -55,6 +56,9 @@ When requesting it, we should get the following responses:
5556
# Loop
5657
8ba299a7.8ba299a8.l.example.com -> loop over 139.162.153.167 and 139.162.153.168
5758
59+
# Sticky
60+
8ba299a7.8ba299a8.s.example.com -> 139.162.153.167 then 139.162.153.168, then 139.162.153.168 and so on
61+
5862
# Cname
5963
ya.ru.c.example.com -> canonical name ya.ru
6064
google.com.c.example.com -> canonical name google.com

commands/ns.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package commands
33
import (
44
"errors"
55
"net"
6+
"time"
67

78
"github.com/spf13/cobra"
89
"github.com/spf13/viper"
@@ -29,6 +30,8 @@ func init() {
2930
"default ipv4 address")
3031
flags.Uint32("ttl", cfg.TTL,
3132
"DNS records TTL")
33+
flags.Uint32("sticky-ttl", 30,
34+
"sticky record TTL in seconds")
3235
flags.String("ipv6", "::1",
3336
"default ipv6 address")
3437
flags.String("upstream", "77.88.8.8:53",
@@ -61,5 +64,6 @@ func parseServerConfig(cmd *cobra.Command, args []string) error {
6164
cfg.UseDefault = viper.GetBool("UseDefault")
6265
cfg.Upstream = viper.GetString("Upstream")
6366
cfg.TTL = uint32(viper.GetInt("Ttl"))
67+
cfg.StickyTTL = time.Duration(viper.GetInt("StickyTtl")) * time.Second
6468
return nil
6569
}

pkg/cfg/cfg.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package cfg
22

3-
import "net"
3+
import (
4+
"net"
5+
"time"
6+
)
47

58
const (
69
// RIP version
@@ -21,5 +24,6 @@ var (
2124
// Enable "strict" mode
2225
UseDefault bool
2326
AllowProxy bool
24-
TTL uint32 = 0
27+
TTL uint32 = 0
28+
StickyTTL time.Duration = 30
2529
)

pkg/handlers/handler.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ var handlers = map[string]Handler{
1515
"c": CnameHandler,
1616
"p": ProxyHandler,
1717
"l": LoopHandler,
18+
"s": StickyHandler,
1819
"r": RandomHandler,
1920
"4": Ipv4Handler,
2021
"6": Ipv6Handler,

pkg/handlers/sticky.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package handlers
2+
3+
import (
4+
"strings"
5+
6+
"github.com/buglloc/simplelog"
7+
"github.com/miekg/dns"
8+
9+
"github.com/buglloc/rip/pkg/ip_stick"
10+
)
11+
12+
func StickyHandler(question dns.Question, name string, l log.Logger) (rrs []dns.RR) {
13+
ips := strings.Split(name, ".")
14+
if len(ips) < 2 {
15+
log.Error("failed to parse loop annotation")
16+
return
17+
}
18+
19+
var key string
20+
if question.Qtype == dns.TypeA {
21+
key = name + "A"
22+
} else {
23+
key = name + "AAAA"
24+
}
25+
26+
ips = ips[len(ips)-2:]
27+
targetIp := ip_stick.GetCurrent(key, ips)
28+
ip := parseIp(question.Qtype, targetIp)
29+
if ip == nil {
30+
return
31+
}
32+
33+
rrs = createIpsRR(question, ip)
34+
l.Info("cooking response", "mode", "sticky", "ip", ip.String())
35+
return
36+
}

pkg/ip_stick/ip_stick.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package ip_stick
2+
3+
import (
4+
"github.com/karlseguin/ccache"
5+
6+
"github.com/buglloc/rip/pkg/cfg"
7+
)
8+
9+
var lruCache *ccache.Cache
10+
11+
func init() {
12+
lruCache = ccache.New(ccache.Configure().MaxSize(1000))
13+
}
14+
15+
func GetCurrent(key string, ips []string) string {
16+
if item := lruCache.Get(key); item != nil && !item.Expired() && item.Value() != nil {
17+
return ips[1]
18+
}
19+
20+
lruCache.Set(key, true, cfg.StickyTTL)
21+
return ips[0]
22+
}

0 commit comments

Comments
 (0)