factor network handling into package

This commit is contained in:
Johannes Kimmel 2021-12-14 10:17:05 +01:00
parent 3f5370882f
commit 931e2ca8a9
3 changed files with 101 additions and 55 deletions

68
main.go
View File

@ -3,92 +3,52 @@ package main
import ( import (
"fmt" "fmt"
"log" "log"
"net"
"git.freifunk-franken.de/jkimmel/abbel/packet"
"git.freifunk-franken.de/jkimmel/abbel/tlv" "git.freifunk-franken.de/jkimmel/abbel/tlv"
"golang.org/x/net/ipv6"
"inet.af/netaddr"
) )
type options struct { type options struct {
Group net.IP Group string
Port uint16 Port uint16
Ifs []net.Interface Ifs []string
} }
func parseOpts() (options, error) { func parseOpts() (options, error) {
var opt options var opt options
var err error var err error
opt.Group = net.ParseIP("ff02::1:6") opt = options{
opt.Port = 6696 Group: "ff02:0:0:0:0:0:1:6",
ifi, err := net.InterfaceByName("babel") Port: 6696,
if err != nil { Ifs: []string{"babel"},
return opt, err
} }
opt.Ifs = []net.Interface{*ifi}
return opt, err return opt, err
} }
func readBabelPacket(up *ipv6.PacketConn, b []byte) ([]byte, netaddr.IP, error) {
n, rcm, src, err := up.ReadFrom(b)
if err != nil {
return nil, netaddr.IP{}, err
}
_ = rcm
b = b[:n]
if len(b) < 4 {
fmt.Println("packet too short:", len(b))
}
magic := b[0]
version := b[1]
length := uint16(b[2])<<8 + uint16(b[3])
b = b[4:]
if magic != 42 {
return nil, netaddr.IP{}, fmt.Errorf("Invalid magic number %d", magic)
}
if int(length) > len(b) {
fmt.Println("invalid length:", length)
}
fmt.Println(src, rcm, magic, version, length, n)
srcipport, err := netaddr.ParseIPPort(src.String())
return b, srcipport.IP(), err
}
func run(opt options) error { func run(opt options) error {
var err error conn, err := packet.ListenPort(opt.Port)
uc, err := net.ListenUDP("udp6", &net.UDPAddr{Port: int(opt.Port)})
if err != nil { if err != nil {
return err return err
} }
defer uc.Close() defer conn.Close()
up := ipv6.NewPacketConn(uc) for _, iface := range opt.Ifs {
if err = conn.JoinGroup(iface, opt.Group); err != nil {
if err := up.SetControlMessage(ipv6.FlagDst, true); err != nil {
return err
}
for ifi := range opt.Ifs {
if err := up.JoinGroup(&opt.Ifs[ifi], &net.UDPAddr{IP: opt.Group}); err != nil {
return err return err
} }
} }
buf := [4096]byte{} buf := [4096]byte{}
var s tlv.PacketDecoder
for { for {
b, src, err := readBabelPacket(up, buf[:]) b, src, ifindex, err := conn.ReadFrom(buf[:])
if err != nil { if err != nil {
fmt.Println("Skipping packet:", err) fmt.Println("Skipping packet:", err)
continue continue
} }
var s tlv.PacketDecoder s.Reset(b, src, ifindex)
s.Reset(b, src)
for s.Scan() { for s.Scan() {
switch t := s.TLV().(type) { switch t := s.TLV().(type) {
case tlv.NextHop: case tlv.NextHop:

86
packet/packet.go Normal file
View File

@ -0,0 +1,86 @@
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
}

View File

@ -183,7 +183,7 @@ type PacketDecoder struct {
} }
// Reset clears the parser state and sets a new byte slice to work on. // Reset clears the parser state and sets a new byte slice to work on.
func (s *PacketDecoder) Reset(b []byte, nexthop netaddr.IP) { func (s *PacketDecoder) Reset(b []byte, nexthop netaddr.IP, ifindex int) {
*s = PacketDecoder{} *s = PacketDecoder{}
s.tlvscanner.Reset(b) s.tlvscanner.Reset(b)
switch { switch {