Добавьте маршруты, используя AF_ROUTE в golang на Mac - PullRequest
1 голос
/ 16 марта 2020

Я пытаюсь добавить маршрут на моей машине Ma c, используя сокет AF_ROUTE в golang. Я взял одну прагатуру в 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")
}

в этом, когда я запускаю эту программу, она говорит, что буфер недоступен. Может ли кто-нибудь помочь, в чем может быть проблема здесь. Может быть, мои структуры не верны или что-то не так c.

1 Ответ

1 голос
/ 16 марта 2020

Вы упомянули «Может быть, ваша структура неверна?», Да. Сделайте имена экспортируемых полей и используйте теги struct для этих полей, также для 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. некоторые флаги могут не поддерживаться.

...