Last active
December 7, 2024 06:03
-
-
Save roopeshsn/0704a45f7356387a8b27c2aa2b3a65a7 to your computer and use it in GitHub Desktop.
Crafting an UDP packet using x/sys and gopacket packages
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" | |
"github.com/google/gopacket" | |
"github.com/google/gopacket/layers" | |
"golang.org/x/sys/unix" | |
) | |
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 := unix.Socket(unix.AF_INET, unix.SOCK_RAW, unix.IPPROTO_RAW) | |
if err != nil { | |
log.Fatalf("Error creating socket: %v", err) | |
} | |
defer unix.Close(fd) | |
// To manually include the IP header enable IP_HDRINCL | |
if err := unix.SetsockoptInt(fd, unix.IPPROTO_IP, unix.IP_HDRINCL, 1); err != nil { | |
log.Fatalf("Failed to set IP_HDRINCL: %v", err) | |
} | |
fmt.Printf("Raw socket created successfully with FD: %d\n", fd) | |
ipv4DstIP := s.DstIP.To4() | |
if ipv4DstIP == nil { | |
log.Fatalf("Destination IP address is not an IPv4 address: %s", s.DstIP) | |
} | |
dstAddr := &unix.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 := unix.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 | |
} | |
// 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