Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

権威DNSサービスへのDDoSと
ハイパフォーマンスなベンチマーカ / DNS Pseudo ...

kazeburo
March 19, 2023

権威DNSサービスへのDDoSと
ハイパフォーマンスなベンチマーカ / DNS Pseudo random subdomain attack and High performance Benchmarker

権威DNSサービスへのDDoSと
ハイパフォーマンスなベンチマーカ
YAPC::Kyoto 2023 at Kyoto Research Park 2023/03/19

kazeburo

March 19, 2023
Tweet

More Decks by kazeburo

Other Decks in Technology

Transcript

  1. 権威DNSサービスへのDDoSと 
 ハイパフォーマンスなベンチマーカ YAPC::Kyoto 2023 at Kyoto Research Park 2023/03/19

    さくらインターネット株式会社 クラウド事業本部 SRE室 Masahiro Nagano (kazeburo)
  2. Me • ⻑野雅広(ながのまさひろ) • CPAN: KAZEBURO • Twitter/GitHub @kazeburo •

    2006年まで京都リサーチパーク4号館で勤務 • さくらインターネット株式会社 クラウド事業本部 
 SRE室 室⻑ • ISUCON1, 2, 9予選出題。ISUCON3, 4優勝
  3. さくらインターネット SRE室の取り組み • ミッション • クラウドサービスの信頼性を⾼めることにより、お客様や社会のDXをしっかり⽀える • ビジョン • 社内でのSREの実践を広め、お客様への価値提供を⾏う

    • さくらのサービスそのものの信頼性向上、それにより価値向上を⽬指す • さくら社員がEnabling SREとして、お客様・社外のサービスの信頼性向上に携わる
  4. さくらインターネット SRE室の取り組み • SRE as a Service • 社内における Kubernetes

    基盤構築 • ログ/監視基盤の研究開発 • Embedded SRE / Enabling SREとしての取り組み  • クラウドサービスのチーム開発/運⽤体制作り • CI/CDなどDX(Develoer Experience)向上の仕組みの構築 • 既存クラウドサービスの開発運⽤
  5. 「DNS⽔責め攻撃」とは • ランダムサブドメイン攻撃 (Pseudo-Random Subdomain Attack) と呼ばれ ることも • 2014年に初めて観測

    (https://cybersecurity-jp.com/column/34745) • DNSによる名前解決として正しい動作、通信パケットであり防ぐのが難しい • GoogleやCloud fl areのPublic DNSが利⽤されるため、単純なブロックがで きない
  6. 実際の攻撃(tcpdump) 07:25:11.719035 IP 209.216.160.2.50051 > 133.242.64.100.53: 43104 A? meetmodeling.example.com. (50)

    07:25:11.719057 IP 205.171.30.238.44916 > 133.242.64.100.53: 64321% [1au] A? _.modeling.example.com. (71) 07:25:11.719069 IP 172.70.109.31.63292 > 133.242.64.100.53: 40380 [1au] A? osaExpe1-pLatINUM.exAmpLe.cOm. (66) 07:25:11.719071 IP 3.139.136.204.44597 > 133.242.64.100.53: 32383% [1au] A? webdirect.foster.example.com. (65) 07:25:11.719113 IP 18.188.77.103.42513 > 133.242.64.100.53: 14853 [1au] A? note-modeling.example.com. (62) 07:25:11.719132 IP 172.70.33.19.27971 > 133.242.64.100.53: 35379 [1au] A? indian-awarded.example.com. (63) 07:25:11.719147 IP 12.121.89.48.43564 > 133.242.64.100.53: 23891 A? matchfiling.example.com. (49) 07:25:11.719156 IP 74.125.181.130.64517 > 133.242.64.100.53: 25285% [1au] A? xmL.mODeLING.eXaMple.CoM. (61) 07:25:11.719166 IP 165.225.41.202.17203 > 133.242.64.100.53: 53044% [1au] A? qatawarded.example.com. (59) 07:25:11.719176 IP 96.114.53.67.20082 > 133.242.64.100.53: 41999 [1au] A? netherlands.filing.example.com. (67) 07:25:11.719190 IP 172.253.195.196.35276 > 133.242.64.100.53: 45639% [1au] A? tdd-modeling.example.com. (61) 07:25:11.719195 IP 172.253.217.12.40587 > 133.242.64.100.53: 62658% [1au] A? web.modeling.example.com. (61) 07:25:11.719197 IP 172.253.9.4.50295 > 133.242.64.100.53: 37961% [1au] A? co.awarded.example.com. (59) 07:25:11.719224 IP 172.71.29.39.30489 > 133.242.64.100.53: 2496 [1au] A? SfaaSobvioUs.ExamplE.Com. (61) 07:25:11.719235 IP 209.66.107.33.57264 > 133.242.64.100.53: 50511 [1au] A? hap.modeling.example.com. (61) 07:25:11.719275 IP 96.114.53.69.53157 > 133.242.64.100.53: 5679 [1au] A? gitcn-awarded.example.com. (62) 07:25:11.719312 IP 172.70.229.30.59530 > 133.242.64.100.53: 45890 [1au] A? ipafoster.example.com. (58) 07:25:11.719336 IP 172.217.46.78.59507 > 133.242.64.100.53: 60186% [1au] A? testcloud-modeling.example.com. (67) 07:25:11.719351 IP 69.47.193.166.52891 > 133.242.64.100.53: 238 [1au] A? bfmpassing.example.com. (59) 07:25:11.719353 IP 34.218.119.91.26001 > 133.242.64.100.53: 31511% [1au] A? signal-modeling.example.com. (64) 07:25:11.719365 IP 34.218.119.91.13381 > 133.242.64.100.53: 4210% [1au] A? pairfiling.example.com. (59)
  7. 実際の攻撃(tcpdump) 07:25:11.719035 IP 209.216.160.2.50051 > 133.242.64.100.53: 43104 A? meetmodeling.example.com. (50)

    07:25:11.719057 IP 205.171.30.238.44916 > 133.242.64.100.53: 64321% [1au] A? _.modeling.example.com. (71) 07:25:11.719069 IP 172.70.109.31.63292 > 133.242.64.100.53: 40380 [1au] A? osaExpe1-pLatINUM.exAmpLe.cOm. (66) 07:25:11.719071 IP 3.139.136.204.44597 > 133.242.64.100.53: 32383% [1au] A? webdirect.foster.example.com. (65) 07:25:11.719113 IP 18.188.77.103.42513 > 133.242.64.100.53: 14853 [1au] A? note-modeling.example.com. (62) 07:25:11.719132 IP 172.70.33.19.27971 > 133.242.64.100.53: 35379 [1au] A? indian-awarded.example.com. (63) 07:25:11.719147 IP 12.121.89.48.43564 > 133.242.64.100.53: 23891 A? matchfiling.example.com. (49) 07:25:11.719156 IP 74.125.181.130.64517 > 133.242.64.100.53: 25285% [1au] A? xmL.mODeLING.eXaMple.CoM. (61) 07:25:11.719166 IP 165.225.41.202.17203 > 133.242.64.100.53: 53044% [1au] A? qatawarded.example.com. (59) 07:25:11.719176 IP 96.114.53.67.20082 > 133.242.64.100.53: 41999 [1au] A? netherlands.filing.example.com. (67) 07:25:11.719190 IP 172.253.195.196.35276 > 133.242.64.100.53: 45639% [1au] A? tdd-modeling.example.com. (61) 07:25:11.719195 IP 172.253.217.12.40587 > 133.242.64.100.53: 62658% [1au] A? web.modeling.example.com. (61) 07:25:11.719197 IP 172.253.9.4.50295 > 133.242.64.100.53: 37961% [1au] A? co.awarded.example.com. (59) 07:25:11.719224 IP 172.71.29.39.30489 > 133.242.64.100.53: 2496 [1au] A? SfaaSobvioUs.ExamplE.Com. (61) 07:25:11.719235 IP 209.66.107.33.57264 > 133.242.64.100.53: 50511 [1au] A? hap.modeling.example.com. (61) 07:25:11.719275 IP 96.114.53.69.53157 > 133.242.64.100.53: 5679 [1au] A? gitcn-awarded.example.com. (62) 07:25:11.719312 IP 172.70.229.30.59530 > 133.242.64.100.53: 45890 [1au] A? ipafoster.example.com. (58) 07:25:11.719336 IP 172.217.46.78.59507 > 133.242.64.100.53: 60186% [1au] A? testcloud-modeling.example.com. (67) 07:25:11.719351 IP 69.47.193.166.52891 > 133.242.64.100.53: 238 [1au] A? bfmpassing.example.com. (59) 07:25:11.719353 IP 34.218.119.91.26001 > 133.242.64.100.53: 31511% [1au] A? signal-modeling.example.com. (64) 07:25:11.719365 IP 34.218.119.91.13381 > 133.242.64.100.53: 4210% [1au] A? pairfiling.example.com. (59) • ランダムな⽂字列、単語の組み合わせ • ⼤⽂字・⼩⽂字まざり(Google Public DNS仕様) • ラベル数が増えることも
  8. (権威)DNSサーバのベンチマークツール • dnsperf • https://github.com/DNS-OARC/dnsperf • あらかじめ問い合わせするクエリをファイルに記述しベンチマークを⾏う • ⾃作する •

    ランダム⽂字列の⼤⽂字⼩⽂字、⻑さや数を柔軟に変更したい • ベンチマーカから対象まで全体を把握できる。DNSについて学べる
  9. package main import ( "fmt" "math/rand" "net" "time" ) const

    letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" func randString(n int) string { rand.Seed(time.Now().UnixNano()) b := make([]byte, n) for i := range b { b[i] = letterBytes[rand.Intn(len(letterBytes))] } return string(b) } func main() { for i := 0; i < 1000; i++ { randStr := randString(10) // 10จࣈͷϥϯμϜจࣈྻΛੜ੒ addrs, err := net.LookupHost(randStr) if err != nil { fmt.Printf("Failed to resolve %s: %v\n", randStr, err) } else { fmt.Printf("%s resolves to %v\n", randStr, addrs) } } } 3/10に実⾏
  10. package main import ( "fmt" "math/rand" "net" "time" ) const

    letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" func randString(n int) string { rand.Seed(time.Now().UnixNano()) b := make([]byte, n) for i := range b { b[i] = letterBytes[rand.Intn(len(letterBytes))] } return string(b) } func main() { for i := 0; i < 1000; i++ { randStr := randString(10) // 10จࣈͷϥϯμϜจࣈྻΛੜ੒ addrs, err := net.LookupHost(randStr) if err != nil { fmt.Printf("Failed to resolve %s: %v\n", randStr, err) } else { fmt.Printf("%s resolves to %v\n", randStr, addrs) } } } ちゃんと動きそう..?
  11. エラー処理(net.Resolver) func do() { r := &net.Resolver{ PreferGo: true, Dial:

    func(ctx context.Context, network, address string) (net.Conn, error) { d := net.Dialer{ Timeout: timeout, } return d.DialContext(ctx, protocol, net.JoinHostPort(host, port)) }, } sub := randString(10) _, err := r.LookupHost(context.Background(), sub+"."+zone) if err := err.(*net.DNSError); err.IsNotFound { } } エラーは取得できるが、詳しい内容はエラーの⽂⾔を解析しないとわからない (LookupHostはAと同時にAAAAの名前解決を⾏う)
  12. エラー処理(miekg/dnsの) import "github.com/miekg/dns" atype = dns.StringToType["A"] func do() { c

    := &dns.Client{Net: protocol, Timeout: timeout} address := net.JoinHostPort(host, port) m := new(dns.Msg) sub := randString(10) m.SetQuestion(sub+”.”+zone+”.", atype) r, _, err := c.Exchange(m, address) if err != nil { } if r.Rcode == dns.RcodeRefused { } } Pure GoなシンプルなAPIとコード DNSのステータス(RCODE)が取得可能
  13. パフォーマンス💪 • 対象のパフォーマンス > ベンチマーカのパフォーマンスでは正しい計測ができない • 現代において Apache Bench が常に適切なツールとはならない

    • クライアント側にもハイパフォーマンスが求められる • ベンチマークにとって余分な処理の削減(Happy EyeBallsなど) • 並⾏・並列化 • パフォーマンスチューニング
  14. 並⾏・並列化 Use Goroutines ctx, cancel := context.WithTimeout( context.Background(), timeLimit, )

    defer cancel() for w := 0; w < maxWorkers; w++ { go func() { for { do() } }() } <- ctx.Done() import "github.com/miekg/dns" atype = dns.StringToType["A"] func do() { c := &dns.Client{Net: protocol, Timeout: timeout} address := net.JoinHostPort(host, port) m := new(dns.Msg) sub := randString(10) m.SetQuestion(sub+”.”+zone+”.", atype) r, _, err := c.Exchange(m, address) if err != nil { } if r.Rcode == dns.RcodeRefused { } } goroutineを起動し、 名前解決をループで実⾏
  15. メモリーアロケーションを減らす import "github.com/miekg/dns" ctx, cancel := context.WithTimeout( context.Background(), timeLimit, )

    defer cancel() for w := 0; w < maxWorkers; w++ { go func() { c := &dns.Client{Net: protocol, Timeout: timeout} m := new(dns.Msg) address := net.JoinHostPort(host, port) for { do(c, m, address) } }() } <- ctx.Done() var atype = dns.StringToType[“A"] func do(c *dns.Client, m *dns.Msg, address string ) { sub := randString(10) m.SetQuestion(sub+”.”+zone+”.", atype) r, _, err := c.Exchange(m, address) if err != nil { } if r.Rcode == dns.RcodeRefused { } } ループごとに初期化する 必要ない。ループの外へ移動する
  16. ⽂字列連結の⾼速化 バッファの再利⽤ import ( “strings" “github.com/miekg/dns" ) for w :=

    0; w < maxWorkers; w++ { go func() { c := &dns.Client{Net: protocol, Timeout: timeout} m := new(dns.Msg) address := net.JoinHostPort(host, port) bb := new(bytes.Buffer) for { do(c, m, address, bb) } }() } <- ctx.Done() var atype = dns.StringToType[“A"] func do(c *dns.Client, m *dns.Msg, address string bb *bytes.Buffer ) { defer sb.Reset() randString(bb, 10) bb.WriteByte('.') bb.WriteString(opt.Zone) bb.WriteByte('.') b := sb.Byte() z := unsafe.String(&b[0], len(b)) m.SetQuestion(z, atype) r, _, err := c.Exchange(m, address) } ループの外でbufferを作成し ループの中でresetして使い回す
  17. ランダム⽂字列の⽣成 // https://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-go const ( letterBytes = "abcdefghijklmnopqrstuvwxyz0123456789" letterIdxBits =

    6 // 6 bits to represent a letter index letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits ) func randString(bb *bytes.Buffer, n int) { for i, cache, remain := n-1, int63(), letterIdxMax; i >= 0; { if remain == 0 { cache, remain = int63(), letterIdxMax } if idx := int(cache & letterIdxMask); idx < len(letterBytes) { bb.WriteByte(letterBytes[idx]) i-- } cache >>= letterIdxBits remain-- } } 新たな⽂字列を⽣成することなく ランダムな⽂字を追記していく
  18. チューニングの結果の計測 % go test -bench . -benchmem -benchtime 3s goos:

    darwin goarch: amd64 pkg: github.com/kazeburo/bench cpu: Intel(R) Core(TM) i5-1038NG7 CPU @ 2.00GHz BenchmarkDo-8 2798367 1269 ns/op 28 B/op 3 allocs/op BenchmarkDoMoto-8 324367 10319 ns/op 224 B/op 8 allocs/op PASS ok github.com/kazeburo/bench 8.465s 9倍程度⾼速化 (dns.SetQuestionまで) 1回あたりのアロケー ション回数(allocs/ op) 1回あたりのアロ ケーションで確保 した容量(B/op) 実⾏した回数 1回あたりの実⾏に掛か った時間(ns/op)
  19. チューニングの結果の計測 % go test -bench . -benchmem -benchtime 3s goos:

    darwin goarch: amd64 pkg: github.com/kazeburo/bench cpu: Intel(R) Core(TM) i5-1038NG7 CPU @ 2.00GHz BenchmarkDo-8 2798367 1269 ns/op 28 B/op 3 allocs/op BenchmarkDoMoto-8 324367 10319 ns/op 224 B/op 8 allocs/op PASS ok github.com/kazeburo/bench 8.465s 9倍程度⾼速化 (dns.SetQuestionまで) 1回あたりのアロケー ション回数(allocs/ op) 1回あたりのアロ ケーションで確保 した容量(B/op) 実⾏した回数 1回あたりの実⾏に掛か った時間(ns/op)
  20. プロファイリングを⾏う go test -cpuprofile cpu.prof -memprofile mem.prof -benchtime 3s -bench

    'BenchmarkDo$' goos: darwin goarch: amd64 pkg: github.com/kazeburo/bench cpu: Intel(R) Core(TM) i5-1038NG7 CPU @ 2.00GHz BenchmarkDo-8 2401633 1478 ns/op PASS ok github.com/kazeburo/bench 5.362s
  21. プロファイリング % go tool pprof -top mem.prof Type: alloc_space Time:

    Mar 13, 2023 at 4:08pm (JST) Showing nodes accounting for 99.73MB, 100% of 99.73MB total flat flat% sum% cum cum% 87MB 87.24% 87.24% 98MB 98.27% github.com/miekg/dns.(*Msg).SetQuestion 10.50MB 10.53% 97.77% 11MB 11.03% github.com/miekg/dns.id 1.16MB 1.16% 98.93% 1.16MB 1.16% runtime/pprof.StartCPUProfile 0.57MB 0.57% 99.50% 0.57MB 0.57% compress/flate.newDeflateFast (inline) 0.50MB 0.5% 100% 0.50MB 0.5% encoding/binary.Read 0 0% 100% 0.57MB 0.57% compress/flate.(*compressor).init 0 0% 100% 0.57MB 0.57% compress/flate.NewWriter 0 0% 100% 0.57MB 0.57% compress/gzip.(*Writer).Write 0 0% 100% 98MB 98.27% github.com/kazeburo/bench.BenchmarkDo 0 0% 100% 98MB 98.27% github.com/kazeburo/bench.do 0 0% 100% 1.16MB 1.16% main.main 0 0% 100% 1.16MB 1.16% runtime.main … このあたりがアヤシイ
  22. チューニングの確認 % go test -bench . -benchmem -benchtime 3s goos:

    darwin goarch: amd64 pkg: github.com/kazeburo/bench cpu: Intel(R) Core(TM) i5-1038NG7 CPU @ 2.00GHz BenchmarkDo-8 24056054 138.3 ns/op 0 B/op 0 allocs/op BenchmarkDoMoto-8 306056 10851 ns/op 224 B/op 8 allocs/op PASS ok github.com/kazeburo/bench 7.234s アロケーションは0に、当初の80倍程度⾼速化 1回あたりのアロケー ション回数(allocs/ op) 1回あたりのアロ ケーションで確保 した容量(B/op) 実⾏した回数 1回あたりの実⾏に掛か った時間(ns/op)
  23. GOGC • GoでGCを実⾏するヒープサイズの⽬標となるパラメータ • デフォルト 100 で⼤きくすることでGCの頻度を減らしCPUコストを下げる (メモリは増加する) # ./prsd-bench

    -P 53 -H 192.168.10.50 --time-duration 32s --max-workers 300 --max-length 8 --label 1 -- zone x.y 2023-03-11 18:18:56.526777432 +0900 JST m=+20.001327490 resolved: 0.000000 query/sec, refused 157012.900000 query/sec, failed 0.000000 query/sec # GOGC=500 ./prsd-bench -P 53 -H 192.168.10.50 --time-duration 32s --max-workers 300 --max-length 8 -- label 1 --zone x.y 2023-03-11 18:19:40.175067406 +0900 JST m=+20.001772051 resolved: 0.000000 query/sec, refused 178251.500000 query/sec, failed 0.000000 query/sec 最後の⼀押として使う
  24. SAKURA internet ࣾձΛࢧ͑Δ 
 ύϒϦοΫΫϥ΢υΛ 
 Ұॹʹ࡞Γ·ͤΜ͔ʁ Perl, Go, Python

    インフラ基盤から フロントエンドまで 採⽤強化中! さくらインターネットではエン ジ ニア採⽤を強化しています さくらインターネットは新たなアイ デ アの創出に強い熱意と情熱を持って挑戦するお客様を は じ め、私たちとつな が りのあるす べ ての⼈たちのために、未来のある べ き姿を想い描きな が ら ―「やりたいこと」を「 で きる」に変える ― あらゆるア プ ローチを “インターネッ ト”を通 じ て提供します。 詳しくはWebサイトにて、カジュアル⾯談もやってます 👉 www.sakura.ad.jp/lp/22engineer/