在Mac上的golang中使用AF_路由添加路由

在Mac上的golang中使用AF_路由添加路由,go,routes,system-calls,raw-sockets,Go,Routes,System Calls,Raw Sockets,我正在尝试使用golang中的AF_route套接字在我的Mac机器中添加路由。我用C语言写了一个pragram,并试图把它转换成golang。以下是我的golang计划: package main import ( "bytes" "encoding/json" "fmt" "syscall" "unsafe" ) /* Copied and Converted from https://unix.superglobalmegacorp.com/Ne

我正在尝试使用golang中的AF_route套接字在我的Mac机器中添加路由。我用C语言写了一个pragram,并试图把它转换成golang。以下是我的golang计划:

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "syscall"
    "unsafe"
)

/* Copied and Converted from
https://unix.superglobalmegacorp.com/Net2/newsrc/net/route.h.html
*/

type rt_metrics struct {
    rmx_locks    uint64    /* Kernel must leave these values alone */
    rmx_mtu      uint64    /* MTU for this path */
    rmx_hopcount uint64    /* max hops expected */
    rmx_expire   uint64    /* lifetime for route, e.g. redirect */
    rmx_recvpipe uint64    /* inbound delay-bandwith product */
    rmx_sendpipe uint64    /* outbound delay-bandwith product */
    rmx_ssthresh uint64    /* outbound gateway buffer limit */
    rmx_rtt      uint64    /* estimated round trip time */
    rmx_rttvar   uint64    /* estimated rtt variance */
    rmx_pksent   uint32    /* packets sent using this route */
    rmx_state    uint32    /* route state */
    rmx_filler   [3]uint32 /* will be used for T/TCP later */
}

/* Copied and Converted from
https://unix.superglobalmegacorp.com/Net2/newsrc/net/route.h.html
*/

type rt_msghdr struct {
    rtm_msglen  uint16     /* to skip over non-understood messages */
    rtm_version uint8      /* future binary compatability */
    rtm_type    uint8      /* message type */
    rtm_index   uint16     /* index for associated ifp */
    rtm_pid     uint32     /* identify sender */
    rtm_addrs   int        /* bitmask identifying sockaddrs in msg */
    rtm_seq     int        /* for sender to identify action */
    rtm_errno   int        /* why failed */
    rtm_flags   int        /* flags, incl. kern & message, e.g. DONE */
    rtm_use     int        /* from rtentry */
    rtm_inits   uint64     /* which metrics we are initializing */
    rtm_rmx     rt_metrics /* metrics themselves */
}

type rt_msg struct {
    hdr   rt_msghdr
    addr1 syscall.RawSockaddrInet4
    addr2 syscall.RawSockaddrInet4
}

//Init initialize ROUTE Socket
func main() {
    address1 := [4]byte{12, 13, 14, 15}
    address2 := [4]byte{16, 17, 18, 19}
    zero1 := [8]int8{0, 0, 0, 0, 0, 0, 0, 0}
    addr1 := syscall.RawSockaddrInet4{
        0,
        syscall.AF_INET,
        0,
        address1,
        zero1,
    }
    addr2 := syscall.RawSockaddrInet4{
        0,
        syscall.AF_INET,
        0,
        address2,
        zero1,
    }
    var dummy rt_msghdr
    a := unsafe.Sizeof(dummy)
    b := unsafe.Sizeof(addr1) + unsafe.Sizeof(addr1)
    c := a + b
    //  fmt.Print(" a  ", a)
    //  fmt.Print(" b  ", b)
    //  fmt.Print(" c  ", c)
    msgheader := rt_msghdr{
        uint16(c),
        syscall.RTM_VERSION,
        syscall.RTM_ADD,
        (syscall.RTA_DST | syscall.RTA_GATEWAY),
        uint32(syscall.Getpid()),
        syscall.RTA_DST | syscall.RTA_GATEWAY,
        1,
        0,
        0,
        0,
        0,
        rt_metrics{},
    }

    msg := rt_msg{msgheader, addr1, addr2}

    fd, err := syscall.Socket(syscall.AF_ROUTE, syscall.SOCK_RAW, syscall.AF_UNSPEC)
    if err != nil {
        fmt.Printf("Could not create Raw Socket")
    }
    defer func() {
        recover()
    }()
    msgtosend := new(bytes.Buffer)
    json.NewEncoder(msgtosend).Encode(msg)
    fmt.Print(" lenght of data ", len(msgtosend.Bytes()))
    d, e := syscall.Write(fd, msgtosend.Bytes())
    fmt.Print(" written ", d, " error is ", e, "\n\n")
}
在这个例子中,当我运行这个程序时,它说缓冲区不可用。有人能帮帮忙吗?这里有什么问题吗。 可能是我的结构不正确,或者缺少一些基本信息。

您提到“可能是您的结构不正确吗?”,是的。。 导出字段的名称,并在这些字段上使用struct标记,也用于
rt\u msghdr
,使编码器知道正确的名称

type rt_msg struct {
    Hdr   rt_msghdr                   `json:"hdr"`
    Addr1 syscall.RawSockaddrInet4    `json:"addr1"`
    Addr2 syscall.RawSockaddrInet4    `json:"addr2"`
}

type rt_msghdr struct {
    Rtm_msglen  uint16 `json:"rtm_msglen"`    /* to skip over non-understood messages */
    // ... and so on
    Rtm_rmx     rt_metrics `json:"rtm_rmx"` /* metrics themselves */
}

type rt_metrics struct {
    Rmx_locks    uint64    `json:"rmx_locks"` /* Kernel must leave these values alone */
    // ... and so on
}

上面的代码修复了发送到fd的空字节问题。对于
没有可用的缓冲区空间
,您可以检查此链接:。编译代码可能会在其他操作系统上遇到一些问题,因为它使用
syscall
。某些标志可能不受支持。

这并不是那么简单:如果接收端的JSON解码器在涉及文档中对象的字段名称时区分大小写,那么您的方法也不会起作用,因为“Hdr”与接收者可能期望的“Hdr”不一样。因此,完整的答案是“导出字段的名称,但在这些字段上使用struct标记使编码器知道正确的名称”。还应注意,
rt_msghdr
的字段也必须以相同的方式处理。一个指向Go处理入门级HOWTO中某些JSON的指针将是一个胜利。请改进您的答案。@kostix非常感谢您的更正,我完全忘记了要包含这些标签。