Wireshark-dev: [Wireshark-dev] Possible bug in udpdump TLVs header parsing

Date Prev · Date Next · Thread Prev · Thread Next
From: Jeff Walter <jeff@xxxxxxxxxx>
Date: Thu, 7 Mar 2024 19:19:29 -0600
Hello,

I’m running the g3-proxy from bytedance and am streaming their udpdump to Wireshark for debugging. In Wireshark, both the exported_pdu src and dest ips are being reported as 127.0.0.1. I wrote a little script to decode the exported_pdu data and am seeing the real ips in my code.


I’m pretty convinced this is a bug in the Wireshark exported_pdu dissector code, but I’m not setup to really debug it: https://github.com/wireshark/wireshark/blob/master/epan/dissectors/packet-exported_pdu.c


Please let me know if/how I can make the issue clearer for you guys.

Thanks,




P.S. Here are some screenshots to illustrate what I’m seeing:

Here’s a Wireshark screenshot:
PastedGraphic-1.png


Here’s a screenshot of my script:
PastedGraphic-2.png


Here’s my hacky code (in Go) that produced the above output:

package main

import (
"encoding/binary"
"fmt"
"log"
"net"
"strings"

"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
)

const (
EXP_PDU_TAG_END_OF_OPT = 0
EXP_PDU_TAG_DISSECTOR_NAME = 12
EXP_PDU_TAG_DISSECTOR_TABLE_NAME = 14
EXP_PDU_TAG_IPV4_SRC = 20
EXP_PDU_TAG_IPV4_DST = 21
EXP_PDU_TAG_PORT_TYPE = 24
EXP_PDU_TAG_SRC_PORT = 25
EXP_PDU_TAG_DST_PORT = 26
EXP_PDU_TAG_DISSECTOR_TABLE_NAME_NUM_VAL = 32
EXP_PDU_TAG_TCP_INFO_DATA = 34
EXP_PDU_TAG_USER_DATA_PDU = 37
)

// TCPInfo represents the structure of the TCP info data as described.
type TCPInfo struct {
Version uint16
Seq uint32
Nxtseq uint32
Lastackseq uint32
IsReassembled uint8
Flags uint16
UrgentPointer uint16
}

// decodeTCPInfoData takes a byte slice and attempts to decode it into a TCPInfo struct.
func decodeTCPInfoData(data []byte) (*TCPInfo, error) {
// Ensure the data slice contains enough bytes to decode the complete structure.
if len(data) < 17 { // 2 + 4 + 4 + 4 + 1 + 2 + 2 = 17 bytes
return nil, fmt.Errorf("data slice is too short to contain TCP info data")
}

tcpInfo := &TCPInfo{
Version: binary.BigEndian.Uint16(data[:2]),
Seq: binary.BigEndian.Uint32(data[2:6]),
Nxtseq: binary.BigEndian.Uint32(data[6:10]),
Lastackseq: binary.BigEndian.Uint32(data[10:14]),
IsReassembled: data[14],
Flags: binary.BigEndian.Uint16(data[15:17]),
UrgentPointer: binary.BigEndian.Uint16(data[17:19]),
}

return tcpInfo, nil
}

func hexToASCII(data []byte) string {
var ascii strings.Builder
for _, b := range data {
if b >= 32 && b <= 126 { // printable ASCII range
ascii.WriteByte(b)
} else if b == 0 {
continue // skip null bytes
} else {
ascii.WriteString(fmt.Sprintf("\\x%02x", b))
}
}
return ascii.String()
}

func toIP(data []byte) string {
if len(data) == 4 {
return net.IP(data).String()
}
return ""
}

// portTypeToString maps the integer port type value to its corresponding string representation.
func portTypeToString(portType int) string {
switch portType {
case 0:
return "None"
case 1:
return "SCTP"
case 2:
return "TCP"
case 3:
return "UDP"
case 4:
return "DCCP"
case 5:
return "IPX"
case 6:
return "NCP"
case 7:
return "EXCHG"
case 8:
return "DDP"
case 9:
return "SBCCS"
case 10:
return "IDP"
case 11:
return "TIPC"
case 12:
return "USB"
case 13:
return "I2C"
case 14:
return "IBQP"
case 15:
return "BLUETOOTH"
case 16:
return "TDMOP"
case 17:
return "IWARP_MPA"
case 18:
return "MCTP"
default:
return "Unknown"
}
}

func main() {
device := "lo0"
snapshotLen := int32(1024)
promiscuous := true
timeout := pcap.BlockForever

handle, err := pcap.OpenLive(device, snapshotLen, promiscuous, timeout)
if err != nil {
log.Fatal(err)
}
defer handle.Close()

if err := handle.SetBPFFilter("udp and port 5555"); err != nil {
log.Fatal(err)
}

packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
for {
endOfOptions := false
Loop:
for packet := range packetSource.Packets() {
udpLayer := packet.Layer(layers.LayerTypeUDP)
if udpLayer != nil {
udp, _ := udpLayer.(*layers.UDP)
payload := udp.Payload

cursor := 0
for cursor < len(payload) {
if cursor+4 > len(payload) {
fmt.Println("Malformed packet or insufficient data for TLV length")
break Loop
}

tlvType := binary.BigEndian.Uint16(payload[cursor : cursor+2])
tlvLength := binary.BigEndian.Uint16(payload[cursor+2 : cursor+4])
cursor += 4

if cursor+int(tlvLength) > len(payload) {
fmt.Println("Malformed packet or insufficient data for TLV length")
break Loop
}

tlvValue := payload[cursor : cursor+int(tlvLength)]
cursor += int(tlvLength)

if endOfOptions {
// fmt.Printf("Data: %s\n", payload[cursor:])
continue
}
switch tlvType {
case EXP_PDU_TAG_END_OF_OPT:
fmt.Println("***** End of options *****")
endOfOptions = true // Exit loop at the end of options TLV
case EXP_PDU_TAG_DISSECTOR_NAME:
fmt.Printf("Protocol: %s\n", tlvValue)
case EXP_PDU_TAG_DISSECTOR_TABLE_NAME:
fmt.Printf("Dissector Table Name: %s\n", tlvValue)
case EXP_PDU_TAG_IPV4_SRC:
fmt.Printf("Source IP Address: %s\n", toIP(tlvValue))
case EXP_PDU_TAG_IPV4_DST:
fmt.Printf("Destination IP Address: %s\n", toIP(tlvValue))
case EXP_PDU_TAG_PORT_TYPE:
portType := int(binary.BigEndian.Uint32(tlvValue))
fmt.Printf("Port Type: %s\n", portTypeToString(portType))
case EXP_PDU_TAG_SRC_PORT:
fmt.Printf("Source Port: %d\n", binary.BigEndian.Uint32(tlvValue))
case EXP_PDU_TAG_DST_PORT:
fmt.Printf("Destination Port: %d\n", binary.BigEndian.Uint32(tlvValue))
case EXP_PDU_TAG_DISSECTOR_TABLE_NAME_NUM_VAL:
fmt.Printf("Dissector Table Name Num Val: %s\n", hexToASCII(tlvValue))
case EXP_PDU_TAG_TCP_INFO_DATA:
tcpInfo, err := decodeTCPInfoData(tlvValue)
if err != nil {
fmt.Println("Error decoding TCP info data:", err)
break Loop
}
fmt.Println("TCP Info Data:")
fmt.Printf("Version: %d\n", tcpInfo.Version)
fmt.Printf("Seq: %d\n", tcpInfo.Seq)
fmt.Printf("Nxtseq: %d\n", tcpInfo.Nxtseq)
fmt.Printf("Lastackseq: %d\n", tcpInfo.Lastackseq)
fmt.Printf("IsReassembled: %d\n", tcpInfo.IsReassembled)
fmt.Printf("Flags: %d\n", tcpInfo.Flags)
fmt.Printf("UrgentPointer: %d\n", tcpInfo.UrgentPointer)
case EXP_PDU_TAG_USER_DATA_PDU:
fmt.Printf("Data: %s\n", hexToASCII(tlvValue))
default:
fmt.Printf("Unknown TLV Type %d, ASCII Value: %s\n", tlvType, hexToASCII(tlvValue))
}
}
}
}
}
}