Skip to content

Commit

Permalink
optional early regulation & adopt random Pk for dnscrypt nodes
Browse files Browse the repository at this point in the history
(cherry picked from commit c7c1b6a)
  • Loading branch information
AZ-X committed Jul 6, 2022
1 parent 023a774 commit 536d09a
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 49 deletions.
89 changes: 60 additions & 29 deletions repique/features/dns/nodes/dnscrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,34 @@ type dnscryptnode struct {
relayaddr *atomic.Value //*EPRing
dailFn common.DialFn
bs_relays []*common.Endpoint
randomSvrPK bool
}

const regulation_cycle = 5 * time.Second
func (n *dnscryptnode) boost(o *node) interface{} {
if o.status&status_outdated == status_outdated || n.GetDefaultExpiration().Before(time.Now()) {
relays := n.bs_relays
if _, err := dnscrypt.RetrieveServicesInfo(false, n.Resolver, n.dailFn, n.Network, n.ipaddr, &relays); err == nil {
n.bs2epring(relays)
expired := n.GetDefaultExpiration()
return &expired
} else {
dlog.Debugf("dnscrypt boost failed, %v", err)
relays := n.bs_relays
if _, err := dnscrypt.RetrieveServicesInfo(false, n.Resolver, n.dailFn, n.Network, n.ipaddr, &relays); err == nil {
n.bs2epring(relays)
if n.randomSvrPK {
if s := n.GetDefaultServices(); len(s) > 1 {
expired := time.Unix(int64(s[0].DtFrom), 0).Add(time.Duration(s[1].Regular) * time.Hour).Add(regulation_cycle)
return &expired
}
}
expired := n.GetDefaultExpiration()
return &expired
} else {
if n.randomSvrPK && time.Now().Before(n.GetDefaultExpiration()) {
if s := n.GetDefaultServices(); len(s) > 1 {
expired := time.Unix(int64(s[0].DtFrom), 0).Add(time.Duration(s[1].Regular) * time.Hour)
if time.Since(expired) > time.Minute {
dlog.Debugf("abort dnscrypt early regulation boost")
return n.GetDefaultExpiration()
}
return time.Now().Add(regulation_cycle)
}
}
dlog.Debugf("dnscrypt boost failed, %v", err)
}
return nil
}
Expand All @@ -51,33 +67,45 @@ func (n *dnscryptnode) material() marshaling {
return n
}

const dnscryptmarshalfmt = "%d %d %d %d %d %x %x" + eol
const dnscryptmarshalfmt = "%d %d %d %d %d %d %x %x" + eol
func (n *dnscryptnode) marshal() *struct{c uint8; v string} {
s := n.GetDefaultService()
ss := n.GetDefaultServices()
var count uint8 = 0
var c strings.Builder
fmt.Fprintf(&c, dnscryptmarshalfmt, s.Version, s.Minor, s.Serial, s.DtFrom, s.DtTo, s.MagicQuery, s.ServerPk)
return &struct{c uint8; v string} {1,c.String()}
for _, s := range ss {
if time.Now().After(time.Unix(int64(s.DtTo), 0)) {
break
}
count++
fmt.Fprintf(&c, dnscryptmarshalfmt, s.Version, s.Minor, s.Serial, s.DtFrom, s.DtTo, s.Regular, s.MagicQuery, s.ServerPk)
}
return &struct{c uint8; v string} {count, c.String()}
}

func (n *dnscryptnode) unmarshal(ss *struct{c uint8; v string}) *time.Time {
s := &dnscrypt.ServiceInfo{Service:&dnscrypt.Service{ServerKey:&dnscrypt.ServerKey{}}}
c := strings.NewReader(ss.v)
var mq, sk []byte
if _, err := fmt.Fscanf(c, dnscryptmarshalfmt,
&s.Version, &s.Minor, &s.Serial, &s.DtFrom, &s.DtTo, &mq, &sk); err != nil {
panic(err)
}
copy(s.MagicQuery[:], mq)
copy(s.ServerPk[:], sk)
s.Name = n.name()
if s.Version == dnscrypt.XSalsa20Poly1305 {
n.V1_Services = append(n.V1_Services, s)
} else {
n.V2_Services = append(n.V2_Services, s)
func (n *dnscryptnode) unmarshal(ss *struct{c uint8; v string}) (to *time.Time) {
for i := ss.c; i > 0; i -- {
s := &dnscrypt.ServiceInfo{Service:&dnscrypt.Service{ServerKey:&dnscrypt.ServerKey{}}}
c := strings.NewReader(ss.v)
var mq, sk []byte
if _, err := fmt.Fscanf(c, dnscryptmarshalfmt,
&s.Version, &s.Minor, &s.Serial, &s.DtFrom, &s.DtTo, &s.Regular, &mq, &sk); err != nil {
panic(err)
}
copy(s.MagicQuery[:], mq)
copy(s.ServerPk[:], sk)
s.Name = n.name()
if s.Version == dnscrypt.XSalsa20Poly1305 {
n.V1_Services = append(n.V1_Services, s)
} else {
n.V2_Services = append(n.V2_Services, s)
}
defer func() {
t := time.Unix(int64(s.DtTo), 0)
to = &t
}()
}
n.bs2epring(n.bs_relays)
to := time.Unix(int64(s.DtTo), 0)
return &to
return
}

func (_ *dnscryptnode) proto() string {
Expand All @@ -95,5 +123,8 @@ func (n *dnscryptnode) exchange(bin *[]byte, _ ...interface{}) (*[]byte, error)
relayAddr = ep.Endpoint
n.relayaddr.Store(ep.Next())
}
if n.randomSvrPK {
return dnscrypt.Query(n.dailFn, n.Network, n.GetRandomService().Service, bin, n.ipaddr, relayAddr)
}
return dnscrypt.Query(n.dailFn, n.Network, n.GetDefaultService().Service, bin, n.ipaddr, relayAddr)
}
18 changes: 10 additions & 8 deletions repique/features/dns/nodes/node_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,15 @@ const (

//Predefined Well-known Tag Name
const (
Well_Known_Tag_NO_PROXY = "NO-PROXY" // intranet
Well_Known_Tag_HTTP_USE_GET = "HTTP-USE-GET"
Well_Known_Tag_DNS_BOOST_GROUP = "DNS-BOOST-GROUP" // shared across all servers
Well_Known_Tag_DNSSEC_PRIME_GROUP = "DNSSEC-PRIME-GROUP" // shared across all servers
Well_Known_Tag_DNSCRPT_OBTAIN_FAST_KEY = "DNSCRPT-OBTAIN-FAST-KEY" // works with cfg:credentialpath when import_credential=false
Well_Known_Tag_TIMEOUT1 = "TIMEOUT1" //1s
Well_Known_Tag_TIMEOUT2 = "TIMEOUT2" //2s
Well_Known_Tag_TIMEOUT3 = "TIMEOUT3" //3s
Well_Known_Tag_NO_PROXY = "NO-PROXY" // intranet
Well_Known_Tag_HTTP_USE_GET = "HTTP-USE-GET"
Well_Known_Tag_DNS_BOOST_GROUP = "DNS-BOOST-GROUP" // shared across all servers
Well_Known_Tag_DNSSEC_PRIME_GROUP = "DNSSEC-PRIME-GROUP" // shared across all servers
Well_Known_Tag_DNSCRPT_OBTAIN_FAST_KEY = "DNSCRPT-OBTAIN-FAST-KEY" // works with cfg:credentialpath when import_credential=false
Well_Known_Tag_DNSCRPT_EARLY_REGULATION = "DNSCRPT-EARLY-REGULATION" // catch up 'key rotation' and use 1o2 random server PK
Well_Known_Tag_TIMEOUT1 = "TIMEOUT1" //1s
Well_Known_Tag_TIMEOUT2 = "TIMEOUT2" //2s
Well_Known_Tag_TIMEOUT3 = "TIMEOUT3" //3s
)

type connectivity interface {
Expand Down Expand Up @@ -387,6 +388,7 @@ func (mgr *NodesMgr) Init(cfg *Config, routes *AnonymizedDNSConfig, sum []byte,
Resolver:r,
ipaddr:ep,
bs_relays:newroutes(name),
randomSvrPK:hasTag(Well_Known_Tag_DNSCRPT_EARLY_REGULATION, svr.Name),
}
node.dailFn = func(network, address string) (net.Conn, error) {
if network == "udp" && !node.Proxies.UDPProxies() {
Expand Down
61 changes: 49 additions & 12 deletions repique/protocols/dnscrypt/dnscrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ type Resolver struct {
type ServiceInfo struct {
*Service
Minor uint16
Regular uint16 //A.K.A period of key rotation in hours if exists
Serial uint32
DtFrom uint32
DtTo uint32
Expand All @@ -102,11 +103,34 @@ type ServerKey struct {
ServerPk [PublicKeySize]byte
}

func (r *Resolver) GetDefaultService() (s *ServiceInfo) {
func (r *Resolver) GetDefaultServices() []*ServiceInfo {
if len(r.V2_Services) != 0 {
s = r.V2_Services[0]
return r.V2_Services
} else if len(r.V1_Services) != 0 {
s = r.V1_Services[0]
return r.V1_Services
}
return nil
}

func (r *Resolver) GetDefaultService() (s *ServiceInfo) {
if s := r.GetDefaultServices(); s != nil {
return s[0]
}
return
}

func (r *Resolver) GetRandomService() (s *ServiceInfo) {
if s := r.GetDefaultServices(); s != nil {
if len(s) > 1 && time.Now().Before(time.Unix(int64(s[1].DtTo), 0)) {
var c chan int
defer close(c)
select {
case c <- 0:
case c <- 1:
}
return s[<-c]
}
return s[0]
}
return
}
Expand Down Expand Up @@ -284,33 +308,46 @@ RowLoop:
}
if len(resolver.V1_Services) != 0 || len(resolver.V2_Services) != 0 || len(resolver.VN_Services) != 0 {
deleted := make(map[ServerKey]interface{})
visitFn := func(sis []*ServiceInfo, sis0 []*ServiceInfo) {
visitFn := func(sis []*ServiceInfo, sis0 *[]*ServiceInfo) {
for _, si := range sis {
if _, found := keys[*si.ServerKey]; !found {
deleted[*si.ServerKey] = nil
sis0 = append(sis0, si)
*sis0 = append(*sis0, si)
} else {
delete(keys, *si.ServerKey)
}
}
}
visitFn(resolver.V1_Services, v1_Services)
visitFn(resolver.V2_Services, v2_Services)
visitFn(resolver.VN_Services, vn_Services)
visitFn(resolver.V1_Services, &v1_Services)
visitFn(resolver.V2_Services, &v2_Services)
visitFn(resolver.VN_Services, &vn_Services)
dlog.Infof("[%s] public key re-engage: added=%d deleted=%d", *resolver.Name, len(keys), len(deleted))
}
sortF := func(sis []*ServiceInfo) {
sort.Slice(sis, func(i, j int) bool {
return sis[i].Serial > sis[j].Serial
return sis[i].Serial > sis[j].Serial || (sis[i].Serial == sis[j].Serial && sis[i].DtTo > sis[j].DtTo )
})
for _, si := range sis {
for idx, si := range sis {
from := time.Unix(int64(si.DtFrom), 0).UTC()
to := time.Unix(int64(si.DtTo), 0).UTC()
dlog.Infof("[%s] public key info: ver=%d.%d serial=%d from=UTC%v-%d-%v+%.2v:%.2v to=UTC%v-%d-%v+%.2v:%.2v len_ext=%d", *resolver.Name,
d := to.Sub(from)
checkdt := func(d time.Duration) {
if d <= 0 || d > 15 * 24 * time.Hour {
panic("stop using it! malformed datetime represented of " + *resolver.Name)
}
}
checkdt(d)
if idx == 0 {
checkdt(time.Until(to))
}
if idx > 0 {
si.Regular = uint16((time.Duration(si.DtTo - sis[idx-1].DtFrom) * time.Second).Truncate(time.Hour).Hours())
}
dlog.Infof("[%s] public key info: ver=%d.%d serial=%d from=UTC%v-%d-%v+%.2v:%.2v to=UTC%v-%d-%v+%.2v:%.2v len_ext=%d R=%dH", *resolver.Name,
si.Version, si.Minor, si.Serial,
from.Year(), from.Month(), from.Day(), from.Hour(), from.Minute(),
to.Year(), to.Month(), to.Day(), to.Hour(), to.Minute(),
len(si.Ext))
len(si.Ext), si.Regular)
}
}
sortF(v1_Services)
Expand Down

0 comments on commit 536d09a

Please sign in to comment.