Diff comments:
> diff --git a/src/maasagent/cmd/netmon/main.go
> b/src/maasagent/cmd/netmon/main.go
> index e83655f..7b60e83 100644
> --- a/src/maasagent/cmd/netmon/main.go
> +++ b/src/maasagent/cmd/netmon/main.go
> @@ -1,9 +1,83 @@
> package main
>
> +/*
> + Copyright 2023 Canonical Ltd. This software is licensed under the
> + GNU Affero General Public License version 3 (see the file LICENSE).
> +*/
> +
> import (
> + "context"
> + "encoding/json"
> + "os"
> + "os/signal"
> + "syscall"
> +
> + "github.com/rs/zerolog"
> + "github.com/rs/zerolog/log"
> + "golang.org/x/sync/errgroup"
> +
> "launchpad.net/maas/maas/src/maasagent/internal/netmon"
> )
>
> +func Run() int {
> + zerolog.SetGlobalLevel(zerolog.InfoLevel)
> + log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
> +
> + if envLogLevel, ok := os.LookupEnv("LOG_LEVEL"); ok {
> + if logLevel, err := zerolog.ParseLevel(envLogLevel); err != nil
> {
> + log.Warn().Str("LOG_LEVEL", envLogLevel).Msg("Unknown
> log level, defaulting to INFO")
> + } else {
> + zerolog.SetGlobalLevel(logLevel)
> + }
> + }
> +
> + if len(os.Args) < 2 {
> + log.Error().Msg("Please provide an interface to monitor")
> + return 2
> + }
> + iface := os.Args[1]
> +
> + ctx, cancel := context.WithCancel(context.Background())
> +
+1
> + sigC := make(chan os.Signal, 2)
> + signal.Notify(sigC, syscall.SIGTERM, syscall.SIGINT)
> +
> + resultC := make(chan netmon.Result)
> +
> + g, ctx := errgroup.WithContext(ctx)
> + g.SetLimit(2)
> +
> + svc := netmon.NewService(iface)
> + g.Go(func() error {
> + return svc.Start(ctx, resultC)
> + })
> + g.Go(func() error {
> + encoder := json.NewEncoder(os.Stdout)
> + for {
> + select {
> + case <-sigC:
> + cancel()
> + return nil
> + case res, ok := <-resultC:
> + if !ok {
> + log.Debug().Msg("result channel has
> been closed")
> + return nil
> + }
> + err := encoder.Encode(res)
> + if err != nil {
> + return err
> + }
> + }
> + }
> + })
> + log.Info().Msg("Service netmon started")
> + if err := g.Wait(); err != nil {
> + log.Error().Err(err).Send()
> + return 1
> + }
> + return 0
> +}
> +
> func main() {
> - netmon.NewService()
> + os.Exit(Run())
> }
> diff --git a/src/maasagent/internal/ethernet/arp.go
> b/src/maasagent/internal/ethernet/arp.go
> new file mode 100644
> index 0000000..a3ee694
> --- /dev/null
> +++ b/src/maasagent/internal/ethernet/arp.go
> @@ -0,0 +1,168 @@
> +package ethernet
> +
> +/*
> + Copyright 2023 Canonical Ltd. This software is licensed under the
> + GNU Affero General Public License version 3 (see the file LICENSE).
> +*/
> +
> +import (
> + "encoding/binary"
> + "errors"
> + "fmt"
> + "io"
> + "net"
> + "net/netip"
> +)
> +
> +const (
> + // HardwareTypeReserved is a special value for hardware type
> + HardwareTypeReserved uint16 = 0 // see RFC5494
> + // HardwareTypeEthernet is the hardware type value for Ethernet
> + // we only care about ethernet, but additional types are defined for
> + // testing and possible future use
> + HardwareTypeEthernet uint16 = 1
> + // HardwareTypeExpEth is the hardware type for experimental ethernet
> + HardwareTypeExpEth uint16 = 2
> + // HardwareTypeAX25 is the hardware type for Radio AX.25
> + HardwareTypeAX25 uint16 = 3
> + // HardwareTypeChaos is a chaos value for hardware type
> + HardwareTypeChaos uint16 = 4
> + // HardwareTypeIEEE802 is for IEEE 802 networks
> + HardwareTypeIEEE802 uint16 = 5
> +
> + // skipping propriatary networks
> +
> + // HardwareTypeFiberChannel is the hardware type for fiber channel
> + HardwareTypeFiberChannel uint16 = 18
> + // HardwareTypeSerialLine is the hardware type for serial line
> + HardwareTypeSerialLine uint16 = 19
> + // HardwareTypeHIPARP is the hardware type for HIPARP
> + HardwareTypeHIPARP uint16 = 28
> + // HardwareTypeIPARPISO7163 is the hardware type for IP and ARP over
> ISO 7816-3
> + HardwareTypeIPARPISO7163 uint16 = 29
> + // HardwareTypeARPSec is the hardware type for ARPSec
> + HardwareTypeARPSec uint16 = 30
> + // HardwareTypeIPSec is the hardware type for IPSec tunnel
> + HardwareTypeIPSec uint16 = 31
> + // HardwareTypeInfiniBand is the hardware type for InfiniBand
> + HardwareTypeInfiniBand uint16 = 32
> +)
> +
> +const (
> + // ProtocolTypeIPv4 is the value for IPv4 ARP packets
> + ProtocolTypeIPv4 uint16 = 0x0800
> + // ProtocolTypeIPv6 is the value for IPv6 ARP packets,
> + // which shouldn't be used, this is defined for testing purposes
> + ProtocolTypeIPv6 uint16 = 0x86dd
> + // ProtocolTypeARP is the value for ARP packets with a protocol
> + // value of ARP itself
> + ProtocolTypeARP uint16 = 0x0806
> +)
> +
> +const (
> + // OpReserved is a special reserved OpCode
> + OpReserved uint16 = iota // see RFC5494
> + // OpRequest is the OpCode for ARP requests
> + OpRequest
> + // OpReply is the OpCode for ARP replies
> + OpReply
> +)
> +
> +var (
> + // ErrMalformedPacket is an error returned when parsing a malformed ARP
> packet
> + ErrMalformedARPPacket = errors.New("malformed ARP packet")
> +)
> +
> +// Packet is a struct containing the data of an ARP packet
> +type ARPPacket struct {
> + HardwareType uint16
> + ProtocolType uint16
> + HardwareAddrLen uint8
> + ProtocolAddrLen uint8
> + OpCode uint16
> + SendHwdAddr net.HardwareAddr
> + SendIPAddr netip.Addr
> + TgtHwdAddr net.HardwareAddr
> + TgtIPAddr netip.Addr
> +}
> +
> +func checkPacketLen(buf []byte, bytesRead, length int) error {
> + if len(buf) == 0 {
> + return io.ErrUnexpectedEOF
> + }
+1
> + if len(buf[bytesRead:]) < length {
> + return ErrMalformedARPPacket
> + }
> + return nil
> +}
> +
> +// UnmarsahalBinary takes the ARP packet bytes and parses it into a Packet
> +func (pkt *ARPPacket) UnmarshalBinary(buf []byte) error {
> + var (
> + bytesRead int
> + )
> +
> + err := checkPacketLen(buf, bytesRead, 8)
> + if err != nil {
> + return fmt.Errorf("%w: packet missing initial ARP fields", err)
> + }
> +
> + pkt.HardwareType = binary.BigEndian.Uint16(buf[0:2])
> + pkt.ProtocolType = binary.BigEndian.Uint16(buf[2:4])
> + pkt.HardwareAddrLen = buf[4]
> + pkt.ProtocolAddrLen = buf[5]
> + pkt.OpCode = binary.BigEndian.Uint16(buf[6:8])
> +
> + bytesRead = 8
> + hwdAddrLen := int(pkt.HardwareAddrLen)
> + ipAddrLen := int(pkt.ProtocolAddrLen)
> +
> + err = checkPacketLen(buf, bytesRead, hwdAddrLen)
> + if err != nil {
> + return fmt.Errorf("%w: packet too short for sender hardware
> address", err)
> + }
> +
> + sendHwdAddrBuf := make([]byte, hwdAddrLen)
> + copy(sendHwdAddrBuf[:], buf[bytesRead:bytesRead+hwdAddrLen])
> + pkt.SendHwdAddr = sendHwdAddrBuf
> + bytesRead += hwdAddrLen
> +
> + err = checkPacketLen(buf, bytesRead, ipAddrLen)
> + if err != nil {
> + return fmt.Errorf("%w: packet too short for sender IP address",
> err)
> + }
> +
> + var ok bool
> +
> + sendIPAddrBuf := make([]byte, ipAddrLen)
> + copy(sendIPAddrBuf[:], buf[bytesRead:bytesRead+ipAddrLen])
> + pkt.SendIPAddr, ok = netip.AddrFromSlice(sendIPAddrBuf)
> + if !ok {
> + return fmt.Errorf("%w: invalid sender IP address",
> ErrMalformedARPPacket)
> + }
> + bytesRead += ipAddrLen
> +
> + err = checkPacketLen(buf, bytesRead, hwdAddrLen)
> + if err != nil {
> + return fmt.Errorf("%w: packet too short for target hardware
> address", err)
> + }
> +
> + tgtHwdAddrBuf := make([]byte, hwdAddrLen)
> + copy(tgtHwdAddrBuf[:], buf[bytesRead:bytesRead+hwdAddrLen])
> + pkt.TgtHwdAddr = tgtHwdAddrBuf
> + bytesRead += hwdAddrLen
> +
> + err = checkPacketLen(buf, bytesRead, ipAddrLen)
> + if err != nil {
> + return fmt.Errorf("%w: packet too short for target IP address",
> err)
> + }
> +
> + tgtIPAddrBuf := make([]byte, ipAddrLen)
> + copy(tgtIPAddrBuf[:], buf[bytesRead:bytesRead+ipAddrLen])
> + pkt.TgtIPAddr, ok = netip.AddrFromSlice(tgtIPAddrBuf)
> + if !ok {
> + return fmt.Errorf("%w: invalid target IP address",
> ErrMalformedARPPacket)
> + }
> +
> + return nil
> +}
--
https://code.launchpad.net/~cgrabowski/maas/+git/maas/+merge/441702
Your team MAAS Committers is subscribed to branch maas:master.
--
Mailing list: https://launchpad.net/~sts-sponsors
Post to : sts-sponsors@lists.launchpad.net
Unsubscribe : https://launchpad.net/~sts-sponsors
More help : https://help.launchpad.net/ListHelp