I am looking for a way of sending packets using the go language which grants me the ability to view and set the TTL and other low level fields of packets(I don't need to modify Ethernet headers just IP & UDP headers). I have attempted to craft and send my own packets in the code below.
When running the below code no messages are received by the receiver. Can anyone either a.) alert me to any errors I have made in this code or b.) suggest another means of sending UDP data using golang while retaining access to the IP & UDP headers?
I have removed the MAC addresses, they would need to be replaced to run this code.
(Sending)
package main
import (
"syscall"
"log"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"fmt"
"encoding/hex"
"encoding/json"
"net"
)
type NameTag struct {
Name string `json:"name"`
}
func main() {
var err error
fd, e := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_UDP)
if e != nil {
fmt.Println("Problem @ location 1")
}
addr := syscall.SockaddrInet4{
Port: 27289,
Addr: [4]byte{127, 0, 0, 1},
}
p := pkt()
err = syscall.Sendto(fd, p, 0, &addr)
if err != nil {
log.Fatal("Sendto:", err)
}
}
func pkt() []byte {
sb := gopacket.NewSerializeBuffer()
nt := NameTag{"Paul"}
b, _ := json.Marshal(nt)
pld := gopacket.Payload(b)
l := uint16(len(pld))
udp := layers.UDP{
SrcPort: 27289,
DstPort: 27288,
Length: l + 8,
Checksum: 0,
}
l = l + 8
ip := layers.IPv4{
Version: 0x4,
IHL: 5,
Length: 20 + l,
TTL: 255,
Flags: 0x40,
FragOffset: 0,
Checksum: 0,
Protocol: syscall.IPPROTO_UDP,
DstIP: net.IPv4(127, 0, 0, 1),
SrcIP: net.IPv4(127, 0, 0, 1),
}
l = l + 20
eth := layers.Ethernet{
EthernetType: layers.EthernetTypeIPv4,
SrcMAC: net.HardwareAddr{
0x--, 0x--, 0x--, 0x--, 0x--, 0x--,
},
DstMAC: net.HardwareAddr{
0x--, 0x--, 0x--, 0x--, 0x--, 0x--,
},
}
fmt.Println(pld.SerializeTo(sb, gopacket.SerializeOptions{}))
fmt.Println(udp.SerializeTo(sb, gopacket.SerializeOptions{}))
fmt.Println(ip.SerializeTo(sb, gopacket.SerializeOptions{}))
fmt.Println(eth.SerializeTo(sb, gopacket.SerializeOptions{}))
//Debug prints here (first line is for dump to packet validator)
fmt.Println(hex.EncodeToString(sb.Bytes()))
fmt.Println(sb.Bytes())
return sb.Bytes()
}
(Receiving)
package main
import (
"syscall"
"os"
"fmt"
)
func main() {
fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_UDP)
if err != nil {
fmt.Println(err)
return
}
sa:= &syscall.SockaddrInet4{
Addr: [4]byte{127,0,0,1},
Port:27288,
}
e := syscall.Bind(fd, sa)
if e != nil {
fmt.Println("problems @ location 1")
}
f := os.NewFile(uintptr(fd), fmt.Sprintf("fd%d", fd))
fmt.Println("Entering main loop")
for {
fmt.Println("In loop")
buf := make([]byte, 1024)
numRead, err := f.Read(buf)
if err != nil {
fmt.Println("problems @ location 2")
}
fmt.Printf("Loop done %v\n", buf[:numRead])
}
}