Created
December 2, 2024 09:32
-
-
Save roopeshsn/541d455f2adcb65170d0c4b0c377b32f to your computer and use it in GitHub Desktop.
Crafting an UDP Packet in Go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"context" | |
"fmt" | |
"log" | |
"net" | |
"syscall" | |
"github.com/google/gopacket" | |
"github.com/google/gopacket/layers" | |
) | |
type PacketConfig struct { | |
SrcMAC net.HardwareAddr | |
DstMAC net.HardwareAddr | |
SrcIP net.IP | |
DstIP net.IP | |
SrcPort layers.UDPPort | |
DstPort layers.UDPPort | |
PayloadSize int | |
} | |
func send(ctx context.Context, s *PacketConfig) error { | |
fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW) | |
if err != nil { | |
log.Fatalf("Failed to create raw socket: %v", err) | |
} | |
defer syscall.Close(fd) | |
// To manually include the IP header enable IP_HDRINCL | |
if err := syscall.SetsockoptInt(fd, syscall.IPPROTO_IP, syscall.IP_HDRINCL, 1); err != nil { | |
log.Fatalf("Failed to set IP_HDRINCL: %v", err) | |
} | |
ipv4DstIP := s.DstIP.To4() | |
if ipv4DstIP == nil { | |
log.Fatalf("Destination IP address is not an IPv4 address: %s", s.DstIP) | |
} | |
dstAddr := &syscall.SockaddrInet4{ | |
Port: int(s.DstPort), | |
Addr: [4]byte{ipv4DstIP[0], ipv4DstIP[1], ipv4DstIP[2], ipv4DstIP[3]}, | |
} | |
packet, err := buildPacket(s) | |
fmt.Println(packet) | |
if err != nil { | |
return fmt.Errorf("failed to build packet: %w", err) | |
} | |
fmt.Println("Packet is created!") | |
select { | |
case <-ctx.Done(): | |
return nil | |
default: | |
if err := syscall.Sendto(fd, packet, 0, dstAddr); err != nil { | |
return fmt.Errorf("failed to send packet: %v", err) | |
} | |
fmt.Println("Packet sent!") | |
} | |
return nil | |
} | |
func buildPacket(c *PacketConfig) ([]byte, error) { | |
buf := gopacket.NewSerializeBuffer() | |
var layersToSerialize []gopacket.SerializableLayer | |
ethLayer := &layers.Ethernet{ | |
SrcMAC: c.SrcMAC, | |
DstMAC: c.DstMAC, | |
EthernetType: layers.EthernetTypeIPv4, | |
} | |
layersToSerialize = append(layersToSerialize, ethLayer) | |
ipLayer := &layers.IPv4{ | |
Version: 4, | |
TTL: 64, | |
SrcIP: c.SrcIP, | |
DstIP: c.DstIP, | |
Protocol: layers.IPProtocolUDP, | |
} | |
layersToSerialize = append(layersToSerialize, ipLayer) | |
udpLayer := &layers.UDP{ | |
SrcPort: c.SrcPort, | |
DstPort: c.DstPort, | |
} | |
udpLayer.SetNetworkLayerForChecksum(ipLayer) | |
layersToSerialize = append(layersToSerialize, udpLayer) | |
payload := make([]byte, c.PayloadSize) | |
layersToSerialize = append(layersToSerialize, gopacket.Payload(payload)) | |
if err := gopacket.SerializeLayers(buf, gopacket.SerializeOptions{ComputeChecksums: true, FixLengths: true}, layersToSerialize...); err != nil { | |
return nil, fmt.Errorf("error serializing packet: %w", err) | |
} | |
return buf.Bytes(), nil | |
} | |
func main() { | |
fmt.Println("netctl v0.0.1. Born 7:04 pm Friday, 29 November 2024 Indian Standard Time (IST)") | |
ctx, cancel := context.WithCancel(context.Background()) | |
defer cancel() | |
srcMAC, err := net.ParseMAC("de:ad:be:ef:ca:fe") | |
if err != nil { | |
fmt.Println("Error parsing MAC address:", err) | |
return | |
} | |
dstMAC, err := net.ParseMAC("de:ad:be:ef:ca:ff") | |
if err != nil { | |
fmt.Println("Error parsing MAC address:", err) | |
return | |
} | |
// now create a packet configuration | |
config := PacketConfig{ | |
SrcMAC: srcMAC, | |
DstMAC: dstMAC, | |
SrcIP: net.ParseIP("191.191.191.191"), | |
DstIP: net.ParseIP("192.192.192.192"), | |
SrcPort: 12345, | |
DstPort: 12346, | |
PayloadSize: 100, | |
} | |
err = send(ctx, &config) | |
if err != nil { | |
fmt.Println(err) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment