diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index a24f198..ac9e66d 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -23,9 +23,6 @@ jobs: with: go-version: 'stable' - - name: Install pcap - run: sudo apt install -y libpcap-dev - - run: go vet ./... - name: staticcheck @@ -47,7 +44,4 @@ jobs: with: go-version: 'stable' - - name: Install pcap - run: sudo apt install -y libpcap-dev - - run: go test ./... diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 43c9377..ba0565c 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -24,9 +24,6 @@ jobs: with: go-version: "1.22" - - name: Install pcap - run: sudo apt install -y libpcap-dev - - name: Build env: GOOS: ${{ matrix.goos }} diff --git a/cmd/root.go b/cmd/root.go index 1ccf025..288e3d7 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -43,7 +43,6 @@ var logger *zap.Logger // Flags var ( cfgFile string - pcapFile string logLevel string logFormat string ) @@ -119,7 +118,6 @@ func init() { func initFlags() { rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file") - rootCmd.PersistentFlags().StringVarP(&pcapFile, "pcap", "p", "", "pcap file (optional)") rootCmd.PersistentFlags().StringVarP(&logLevel, "log-level", "l", envOrDefaultString(appLogLevelEnv, "info"), "log level") rootCmd.PersistentFlags().StringVarP(&logFormat, "log-format", "f", envOrDefaultString(appLogFormatEnv, "console"), "log format") } @@ -169,7 +167,6 @@ type cliConfig struct { IO cliConfigIO `mapstructure:"io"` Workers cliConfigWorkers `mapstructure:"workers"` Ruleset cliConfigRuleset `mapstructure:"ruleset"` - Replay cliConfigReplay `mapstructure:"replay"` } type cliConfigIO struct { @@ -180,10 +177,6 @@ type cliConfigIO struct { RST bool `mapstructure:"rst"` } -type cliConfigReplay struct { - Realtime bool `mapstructure:"realtime"` -} - type cliConfigWorkers struct { Count int `mapstructure:"count"` QueueSize int `mapstructure:"queueSize"` @@ -204,30 +197,17 @@ func (c *cliConfig) fillLogger(config *engine.Config) error { } func (c *cliConfig) fillIO(config *engine.Config) error { - var ioImpl io.PacketIO - var err error - if pcapFile != "" { - // Setup IO for pcap file replay - logger.Info("replaying from pcap file", zap.String("pcap file", pcapFile)) - ioImpl, err = io.NewPcapPacketIO(io.PcapPacketIOConfig{ - PcapFile: pcapFile, - Realtime: c.Replay.Realtime, - }) - } else { - // Setup IO for nfqueue - ioImpl, err = io.NewNFQueuePacketIO(io.NFQueuePacketIOConfig{ - QueueSize: c.IO.QueueSize, - ReadBuffer: c.IO.ReadBuffer, - WriteBuffer: c.IO.WriteBuffer, - Local: c.IO.Local, - RST: c.IO.RST, - }) - } - + nfio, err := io.NewNFQueuePacketIO(io.NFQueuePacketIOConfig{ + QueueSize: c.IO.QueueSize, + ReadBuffer: c.IO.ReadBuffer, + WriteBuffer: c.IO.WriteBuffer, + Local: c.IO.Local, + RST: c.IO.RST, + }) if err != nil { return configError{Field: "io", Err: err} } - config.IO = ioImpl + config.IO = nfio return nil } diff --git a/engine/engine.go b/engine/engine.go index 1270efb..56f5ed3 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -58,17 +58,12 @@ func (e *engine) UpdateRuleset(r ruleset.Ruleset) error { } func (e *engine) Run(ctx context.Context) error { - workerCtx, workerCancel := context.WithCancel(ctx) - defer workerCancel() // Stop workers - - // Register IO shutdown ioCtx, ioCancel := context.WithCancel(ctx) - e.io.SetCancelFunc(ioCancel) - defer ioCancel() // Stop IO + defer ioCancel() // Stop workers & IO // Start workers for _, w := range e.workers { - go w.Run(workerCtx) + go w.Run(ioCtx) } // Register IO callback @@ -90,8 +85,6 @@ func (e *engine) Run(ctx context.Context) error { return err case <-ctx.Done(): return nil - case <-ioCtx.Done(): - return nil } } diff --git a/io/interface.go b/io/interface.go index f996789..af7e1e7 100644 --- a/io/interface.go +++ b/io/interface.go @@ -48,9 +48,6 @@ type PacketIO interface { ProtectedDialContext(ctx context.Context, network, address string) (net.Conn, error) // Close closes the packet IO. Close() error - // SetCancelFunc gives packet IO access to context cancel function, enabling it to - // trigger a shutdown - SetCancelFunc(cancelFunc context.CancelFunc) error } type ErrInvalidPacket struct { diff --git a/io/nfqueue.go b/io/nfqueue.go index f1a64df..e84a0bb 100644 --- a/io/nfqueue.go +++ b/io/nfqueue.go @@ -281,11 +281,6 @@ func (n *nfqueuePacketIO) Close() error { return n.n.Close() } -// nfqueue IO does not issue shutdown -func (n *nfqueuePacketIO) SetCancelFunc(cancelFunc context.CancelFunc) error { - return nil -} - func (n *nfqueuePacketIO) setupNft(local, rst, remove bool) error { rules, err := generateNftRules(local, rst) if err != nil { diff --git a/io/pcap.go b/io/pcap.go deleted file mode 100644 index 520da17..0000000 --- a/io/pcap.go +++ /dev/null @@ -1,130 +0,0 @@ -package io - -import ( - "context" - "hash/crc32" - "net" - "sort" - "strings" - "time" - - "github.com/google/gopacket" - "github.com/google/gopacket/pcap" -) - -var _ PacketIO = (*pcapPacketIO)(nil) - -type pcapPacketIO struct { - pcap *pcap.Handle - lastTime *time.Time - ioCancel context.CancelFunc - config PcapPacketIOConfig - - dialer *net.Dialer -} - -type PcapPacketIOConfig struct { - PcapFile string - Realtime bool -} - -func NewPcapPacketIO(config PcapPacketIOConfig) (PacketIO, error) { - handle, err := pcap.OpenOffline(config.PcapFile) - if err != nil { - return nil, err - } - - return &pcapPacketIO{ - pcap: handle, - lastTime: nil, - ioCancel: nil, - config: config, - dialer: &net.Dialer{}, - }, nil -} - -func (p *pcapPacketIO) Register(ctx context.Context, cb PacketCallback) error { - go func() { - packetSource := gopacket.NewPacketSource(p.pcap, p.pcap.LinkType()) - for packet := range packetSource.Packets() { - p.wait(packet) - - networkLayer := packet.NetworkLayer() - if networkLayer != nil { - src, dst := networkLayer.NetworkFlow().Endpoints() - endpoints := []string{src.String(), dst.String()} - sort.Strings(endpoints) - id := crc32.Checksum([]byte(strings.Join(endpoints, ",")), crc32.IEEETable) - - cb(&pcapPacket{ - streamID: id, - timestamp: packet.Metadata().Timestamp, - data: packet.LinkLayer().LayerPayload(), - }, nil) - } - } - // Give the workers a chance to finish everything - time.Sleep(time.Second) - // Stop the engine when all packets are finished - p.ioCancel() - }() - - return nil -} - -// A normal dialer is sufficient as pcap IO does not mess up with the networking -func (p *pcapPacketIO) ProtectedDialContext(ctx context.Context, network, address string) (net.Conn, error) { - return p.dialer.DialContext(ctx, network, address) -} - -func (p *pcapPacketIO) SetVerdict(pkt Packet, v Verdict, newPacket []byte) error { - return nil -} - -func (p *pcapPacketIO) SetCancelFunc(cancelFunc context.CancelFunc) error { - p.ioCancel = cancelFunc - return nil -} - -func (p *pcapPacketIO) Close() error { - p.pcap.Close() - return nil -} - -// Intentionally slow down the replay -// In realtime mode, this is to match the timestamps in the capture -func (p *pcapPacketIO) wait(packet gopacket.Packet) error { - if !p.config.Realtime { - return nil - } - - if p.lastTime == nil { - p.lastTime = &packet.Metadata().Timestamp - } else { - t := packet.Metadata().Timestamp.Sub(*p.lastTime) - time.Sleep(t) - p.lastTime = &packet.Metadata().Timestamp - } - - return nil -} - -var _ Packet = (*pcapPacket)(nil) - -type pcapPacket struct { - streamID uint32 - timestamp time.Time - data []byte -} - -func (p *pcapPacket) StreamID() uint32 { - return p.streamID -} - -func (p *pcapPacket) Timestamp() time.Time { - return p.timestamp -} - -func (p *pcapPacket) Data() []byte { - return p.data -}