Files
virtuallan/pkg/packet/multicast_linux.go
2024-07-12 09:51:43 +08:00

87 lines
2.0 KiB
Go

package packet
import (
"encoding/binary"
"fmt"
"net"
"github.com/lucheng0127/virtuallan/pkg/utils"
log "github.com/sirupsen/logrus"
)
const (
MULTICAST_ADDR = "224.0.0.1"
MULTICAST_PORT = 9999
MAX_DATA_SIZE = 8192
ROUTES_PREFIX = uint16(0x2b00 | 0x01)
)
func MulticastStream(data []byte) error {
udpAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", MULTICAST_ADDR, MULTICAST_PORT))
if err != nil {
return err
}
conn, err := net.DialUDP("udp", nil, udpAddr)
if err != nil {
return err
}
if _, err := conn.Write(data); err != nil {
return err
}
return nil
}
func MonitorRouteMulticast(iface *net.Interface, tapIP string) error {
// Monitor route multicast will run as a goruntine in client so log error but don't exit
udpAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", MULTICAST_ADDR, MULTICAST_PORT))
if err != nil {
return fmt.Errorf("parse multicast addr %s", err.Error())
}
// Listen multicast on tap interface
ln, err := net.ListenMulticastUDP("udp", iface, udpAddr)
if err != nil {
return fmt.Errorf("listen multicast address %s", err.Error())
}
// Read data from udp
for {
buf := make([]byte, MAX_DATA_SIZE)
n, srcAddr, err := ln.ReadFromUDP(buf)
if err != nil {
log.Errorf("read from multicast %s", err.Error())
continue
}
log.Debugf("read multicast from %s", srcAddr.String())
// XXX: Check source addr same cidr with enpoint ip maybe
// Strip route prefix
if n < 2 {
// Not validate stream
continue
}
streamPrefix := binary.BigEndian.Uint16(buf[:2])
if streamPrefix != ROUTES_PREFIX {
// Not route stream
continue
}
// Parse route stream
routes := utils.ParseRoutesStream(buf[2:])
log.Debugf("receive route multicast:\n%+v", routes)
// TODO: Implement in windows
// Sync routes, use flag replace, for unknow ip need delete
if err := utils.SyncRoutesForIface(iface.Name, tapIP, routes); err != nil {
return fmt.Errorf("sync route for %s %s", iface.Name, err.Error())
}
}
}