# 使用Wireshark抓取quic-go產生的QUIC封包 這邊文章教大家如何使用Wireshark抓取並解析quic-go產生的QUIC封包。 Server code: ``` package main import ( "context" "crypto/rand" "crypto/rsa" "crypto/tls" "crypto/x509" "encoding/pem" "fmt" "math/big" "time" "os" "github.com/quic-go/quic-go" ) func main() { fmt.Println("hello") err := Server() if err != nil { fmt.Println("server err") fmt.Println(err) } } func Server() error { const addr = "127.0.0.1:30000" ctx, cancel := context.WithTimeout(context.Background(), time.Hour) defer cancel() listener, err := quic.ListenAddr(addr, generateTLSConfig(), &quic.Config{ KeepAlivePeriod: time.Minute * 5, EnableDatagrams: true, }) if err != nil { return err } conn, err := listener.Accept(ctx) if err != nil { return err } for { size := 256 buf := make([]byte, size) buf, err = conn.ReceiveMessage() if err != nil { fmt.Println(err) break } fmt.Printf("Got: %s", buf) } return err } // Setup a bare-bones TLS config for the server func generateTLSConfig() *tls.Config { key, err := rsa.GenerateKey(rand.Reader, 1024) if err != nil { panic(err) } template := x509.Certificate{SerialNumber: big.NewInt(1)} certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key) if err != nil { panic(err) } keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}) certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}) kl, err := os.OpenFile("tls_key.log", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) tlsCert, err := tls.X509KeyPair(certPEM, keyPEM) if err != nil { panic(err) } return &tls.Config{ Certificates: []tls.Certificate{tlsCert}, NextProtos: []string{"quic-echo-example"}, KeyLogWriter: kl, } } ``` 主要是參考quic-go的example,然後再加上一些改動,quic.config裡的EnableDatagram我把它設成true使他能夠接受RFC 9221裡定義的datagram封包。 然後在tls.Config的地方,我增加了KeyLogWrite這個field,go本身的描述是 KeyLogWriter optionally specifies a destination for TLS master secrets in NSS key log format that can be used to allow external programs such as Wireshark to decrypt TLS connections. See https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format. Use of KeyLogWriter compromises security and should only be used for debugging. 使用上只要開一個os.File然後給他就行 client code: ``` package main import ( "bufio" "crypto/tls" "fmt" "os" "time" "github.com/quic-go/quic-go" ) const addr = "127.0.0.1:30000" func main() { fmt.Println("hello") err := Client() if err != nil { fmt.Println("client err") fmt.Println(err) } } func Client() error { tlsConf := &tls.Config{ InsecureSkipVerify: true, NextProtos: []string{"quic-echo-example"}, } conn, err := quic.DialAddr(addr, tlsConf, &quic.Config{ KeepAlivePeriod: time.Minute * 5, EnableDatagrams: true, }) if err != nil { fmt.Println("conn err") fmt.Println(err) return err } reader := bufio.NewReader(os.Stdin) for { fmt.Println("What message do you want to send?") fmt.Print("message: ") text, _ := reader.ReadString('\n') sendData := []byte(text) err = conn.SendMessage(sendData) if err != nil { fmt.Println(err) return err } time.Sleep(1 * time.Second) } } ``` 接收使用者打的資訊並用datagram的形式傳給server 在執行server後,你會發現資料夾下多了tls_key.log,但是裡面什麼都沒有。 ![](https://i.imgur.com/OJ1tVWv.png) 執行client後,key的資訊才會被寫進來,像這樣: ![](https://i.imgur.com/50ug2qr.png) 之後就可以使用Wireshark抓包了 開啟Wireshark Edit->Preferences->Protocols 選擇QUIC,並設定使用的port ![](https://i.imgur.com/cL2UFpm.png) 現在Wireshark已經能偵測到QUIC封包,只是點開那些封包後會發現payload的資訊無法顯示,這是因為quic的封包都有用tls進行加密過,如果wireshark沒有鑰匙資訊,那也解不開這些封包。 ![](https://i.imgur.com/Ao3atTr.png) ![](https://i.imgur.com/uGdepq0.png) 把之前設定的keylog傳給wireshark: Edit->Preferences->Protocols 尋找TLS,設定(Pre)-Master-Secret log filename ![](https://i.imgur.com/gZ1SqLF.png) 選擇我們的keylog檔案 ![](https://i.imgur.com/fM06MDD.png) 這樣就能解開payload了 再來用client隨便傳一些資訊 ![](https://i.imgur.com/9nxdgJf.png) 然後在wireshark上過濾出quic.frame_type == 31的封包,這類型的封包是,QUIC datagram 封包。 ![](https://i.imgur.com/yWhlhCT.png) 點開封包,可以發現剛剛傳送的資訊確實被解析出來了 ![](https://i.imgur.com/lYhHFcK.png) reference: https://github.com/quic-go/quic-go