abbel/packet/packet.go

87 lines
1.7 KiB
Go

package packet
import (
"fmt"
"net"
"golang.org/x/net/ipv6"
"inet.af/netaddr"
)
const (
BabelMagic = 42
BabelVersion = 2
BabelPacketHeaderSize = 4
)
type Conn struct {
v6pc *ipv6.PacketConn
}
func ListenPort(port uint16) (Conn, error) {
var c Conn
uc, err := net.ListenUDP("udp6", &net.UDPAddr{Port: int(port)})
if err != nil {
return c, err
}
c.v6pc = ipv6.NewPacketConn(uc)
return c, c.v6pc.SetControlMessage(ipv6.FlagDst, true)
}
func (c Conn) Close() error {
return c.v6pc.Close()
}
func (c Conn) JoinGroup(ifname string, addr string) error {
ifi, err := net.InterfaceByName(ifname)
if err != nil {
return err
}
ip, err := netaddr.ParseIP(addr)
if err != nil {
return err
}
return c.v6pc.JoinGroup(ifi, &net.UDPAddr{IP: ip.IPAddr().IP})
}
func (c Conn) ReadFrom(b []byte) (body []byte, src netaddr.IP, ifindex int, err error) {
n, rcm, _, err := c.v6pc.ReadFrom(b)
if err != nil {
return nil, netaddr.IP{}, 0, err
}
b = b[:n]
if len(b) < BabelPacketHeaderSize {
return nil, netaddr.IP{}, 0, fmt.Errorf("Packet too short: %d", len(b))
}
magic := b[0]
version := b[1]
length := uint16(b[2])<<8 + uint16(b[3])
b = b[4:]
if magic != BabelMagic {
return nil, netaddr.IP{}, 0, fmt.Errorf("Invalid magic number %d", magic)
}
if version != BabelVersion {
return nil, netaddr.IP{}, 0, fmt.Errorf("Unsupported version number %d", version)
}
if int(length) > len(b) {
return nil, netaddr.IP{}, 0, fmt.Errorf("Invalid length for packet of size %d: %d", n, length)
}
var ok bool
src, ok = netaddr.FromStdIPRaw(rcm.Src)
if !ok {
return nil, netaddr.IP{}, 0, fmt.Errorf("Invalid src address %q", rcm.Src)
}
return b, src, rcm.IfIndex, err
}