0

I'm trying to send hand-crafted DNS packets with gopacket.

Here is my code:

package main

import (
    "net"

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

func main() {
    handle, err := pcap.OpenLive("lo", 1500, false, pcap.BlockForever)
    if err != nil {
        panic(err)
    }

    // Create ethernet layer
    eth := layers.Ethernet{
        SrcMAC:       net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
        DstMAC:       net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
        EthernetType: layers.EthernetTypeIPv4,
    }

    // Create ip layer
    ip := layers.IPv4{
        Version:  4,
        TTL:      64,
        SrcIP:    net.IP{1, 3, 3, 7},
        DstIP:    net.IP{127, 0, 0, 1},
        Protocol: layers.IPProtocolUDP,
    }

    // Create udp layer
    udp := layers.UDP{
        SrcPort: 62003,
        DstPort: 9000,
    }
    udp.SetNetworkLayerForChecksum(&ip)

    qst := layers.DNSQuestion{
        Name:  []byte{'w', 'w', 'w', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'c', 'o', 'm', '.'},
        Type:  layers.DNSTypeCNAME,
        Class: layers.DNSClassIN,
    }

    dns := layers.DNS{
        BaseLayer:    layers.BaseLayer{},
        ID:           0,
        QR:           true,
        OpCode:       0,
        AA:           false,
        TC:           false,
        RD:           true,
        RA:           true,
        Z:            0,
        ResponseCode: 0,
        QDCount:      1,
        ANCount:      1,
        NSCount:      0,
        ARCount:      0,
        Questions:    []layers.DNSQuestion{qst},
    }

    buffer := gopacket.NewSerializeBuffer()
    options := gopacket.SerializeOptions{
        ComputeChecksums: true,
        FixLengths:       true,
    }

    if err = gopacket.SerializeLayers(buffer, options,
        &eth,
        &ip,
        &udp,
        &dns,
    ); err != nil {
        panic(err)
    }
    outgoingPacket := buffer.Bytes()

    if err = handle.WritePacketData(outgoingPacket); err != nil {
        panic(err)
    }
}

There is no issue and I correctly see the UDP packet going over the wire, however, when I capture it with Wireshark, it is labelled as "UDP" in the "protocol" column, but if I try host www.google.com, the captured packets are labelled as "DNS". So I guess I'm sending malformed packets, but I can't find what I'm missing.

My packet captured with Wireshark has the wrong label in protocol section

I have already checked this question, but it didn't solve my issue.

hacb
  • 175
  • 2
  • 10
  • 1
    "I'm trying to send hand-crafted DNS packets with gopacket." why? What is wrong in using the very good relevant DNS library for Go? For one thing you put "ANcount =1 " but then there is no data for the answer... Also DNS is normally to port 53 if using other ports a dissector may not know about it (your screenshot shows src port = 62003, dst port = 9000). – Patrick Mevzek Feb 15 '21 at 16:51
  • I know there is already a package, but I just want to try and explore other things ! And thank you for the suggestion about the port, it seems that it was the issue with Wireshark ! Feel free to officially answer to the question I'll mark it as the solution. Thanks ! – hacb Feb 15 '21 at 16:53
  • 2
    "but I just want to try and explore other things" That is an honourable goal, but in case of future problems, you can use that tactic: do the packet using an high level library, save the PCAP of what happens on the network, and then try to redo it with your lower level libraries, but that way you have a working point of comparison. – Patrick Mevzek Feb 15 '21 at 18:04
  • That's noted, thanks for the advice – hacb Feb 15 '21 at 20:11

2 Answers2

1

The issue seems to be on Wireshark side, I tried your code and it shows up as DNS if you either:

  1. use a standard port for DNS (53)
 udp := layers.UDP{
        SrcPort: 62003,
        DstPort: 53, // < --- changed here
 }
  1. Right-click on entry and choose Decode As and change UDP port 9000 and set Current as DNS
Uku Loskit
  • 40,868
  • 9
  • 92
  • 93
0

Try to define real MAC addresses (eth.SrcMAC and eth.DstMAC).

Also you should try crafting a question like this:

qst := layers.DNSQuestion{
    Name: []byte("www.google.com") // without the last dot
    Type:  layers.DNSTypeA,
    Class: layers.DNSClassIN,
}

dns := layers.DNS{
    RD:        true, // enable recursion (should be just enough)
    Questions: []layers.DNSQuestion{qst},
}
Coops
  • 3
  • 1
nautim
  • 1