# 使用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,但是裡面什麼都沒有。

執行client後,key的資訊才會被寫進來,像這樣:

之後就可以使用Wireshark抓包了
開啟Wireshark
Edit->Preferences->Protocols
選擇QUIC,並設定使用的port

現在Wireshark已經能偵測到QUIC封包,只是點開那些封包後會發現payload的資訊無法顯示,這是因為quic的封包都有用tls進行加密過,如果wireshark沒有鑰匙資訊,那也解不開這些封包。


把之前設定的keylog傳給wireshark:
Edit->Preferences->Protocols
尋找TLS,設定(Pre)-Master-Secret log filename

選擇我們的keylog檔案

這樣就能解開payload了
再來用client隨便傳一些資訊

然後在wireshark上過濾出quic.frame_type == 31的封包,這類型的封包是,QUIC datagram 封包。

點開封包,可以發現剛剛傳送的資訊確實被解析出來了

reference:
https://github.com/quic-go/quic-go