Golang原始套接字UDP不起作用

Main Question

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)

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
", buf[:numRead])
    }

}