go - 在 Mac 上的 golang 中使用 AF_ROUTE 添加路由
问题描述
我正在尝试使用 golang 中的 AF_ROUTE 套接字在我的 Mac 机器中添加路由。我用 C 语言编写了一个程序并尝试将其转换为 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")
}
当我运行这个程序时,它说缓冲区不可用。任何人都可以帮助这里可能出现的问题。可能是我的结构不正确,或者可能缺少一些基本的东西。
解决方案
您提到“可能是您的结构不正确吗?”,是的.. 导出字段的名称并在这些字段上使用结构标签,也是为了rt_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
. 您可以查看no buffer space available
此链接:https ://docs.netgate.com/pfsense/en/latest/routing/no-buffer-space-available.html 。编译您的代码可能会在其他操作系统上出现一些问题,因为它使用syscall
. 可能不支持某些标志。
推荐阅读
- python - 文件数据库关系,sqlalchemy,flask
- python - 无法将抓取的数据转换为 csv 文件
- xamarin.forms - Xamarin.Forms SecureStorage 插件不起作用
- c# - 为什么移动这条线会导致死锁?
- html - 如何在 delphi intraweb 中与 html 文件进行交互?
- authentication - 执行多个故障排除步骤后无法登录到 Tomcat 8 管理器
- blockchain - Ropsten 以太坊不显示交易信息
- java - Spring Boot - 仅允许经过身份验证的用户访问资源
- windows - 在 Windows 上构建 Docker 映像:入口点脚本“没有这样的文件或目录”
- vim - ncurses 库在 vim 构建期间不可用