Skip to content

Commit

Permalink
change to use spf13/cobra
Browse files Browse the repository at this point in the history
  • Loading branch information
mozillazg committed Apr 23, 2024
1 parent 98a1f87 commit 43a7026
Show file tree
Hide file tree
Showing 13 changed files with 388 additions and 273 deletions.
38 changes: 38 additions & 0 deletions cmd/ebpf.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package cmd

import (
"github.com/cilium/ebpf/rlimit"
"github.com/mozillazg/ptcpdump/bpf"
"github.com/mozillazg/ptcpdump/internal/dev"
)

func attachHooks(opts Options) (map[int]dev.Device, *bpf.BPF, error) {
devices, err := dev.GetDevices(opts.iface)
if err != nil {
return nil, nil, err
}
if err := rlimit.RemoveMemlock(); err != nil {
return devices, nil, err
}
bf, err := bpf.NewBPF()
if err != nil {
return devices, nil, err
}
if err := bf.Load(bpf.NewOptions(opts.pid, opts.comm, opts.followForks, opts.pcapFilter)); err != nil {
return devices, nil, err
}

if err := bf.AttachKprobes(); err != nil {
return devices, bf, err
}
if err := bf.AttachTracepoints(); err != nil {
return devices, bf, err
}
for _, iface := range devices {
if err := bf.AttachTcHooks(iface.Ifindex); err != nil {
return devices, bf, err
}
}

return devices, bf, nil
}
22 changes: 22 additions & 0 deletions cmd/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package cmd

import (
"fmt"
"github.com/mozillazg/ptcpdump/internal/dev"
"sort"
"strings"
)

func listInterfaces() error {
devices, err := dev.GetDevices("any")
if err != nil {
return err
}
outputs := []string{}
for _, d := range devices {
outputs = append(outputs, fmt.Sprintf("%d.%s", d.Ifindex, d.Name))
}
sort.Strings(outputs)
fmt.Printf("%s\n", strings.Join(outputs, "\n"))
return nil
}
17 changes: 17 additions & 0 deletions cmd/log.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package cmd

import (
"errors"
"github.com/cilium/ebpf"
"log"
)

func logErr(err error) {
var ve *ebpf.VerifierError
if errors.As(err, &ve) {
// Using %+v will print the whole verifier error, not just the last
// few lines.
log.Printf("Verifier error: %+v", ve)
}
log.Printf("%+v", err)
}
18 changes: 18 additions & 0 deletions cmd/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package cmd

type Options struct {
iface string
pid uint
comm string
followForks bool
writeFilePath string
pcapFilter string
listInterfaces bool
}

func (o Options) WritePath() string {
if o.writeFilePath == "" || o.writeFilePath == "-" {
return ""
}
return o.writeFilePath
}
87 changes: 87 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package cmd

import (
"context"
"github.com/mozillazg/ptcpdump/internal/consumer"
"github.com/mozillazg/ptcpdump/internal/metadata"
"github.com/spf13/cobra"
"log"
"os/signal"
"syscall"
)

var opts = Options{}

var rootCmd = &cobra.Command{
Use: "ptcpdump",
Short: "XXX",
Long: `XXX.`,
Run: func(cmd *cobra.Command, args []string) {
err := run(cmd, args)
if err != nil {
logErr(err)
}
},
}

func init() {
rootCmd.Flags().StringVarP(&opts.writeFilePath, "write-file", "w", "",
"Write the raw packets to file rather than parsing and printing them out. e.g. ptcpdump.pcapng")
rootCmd.Flags().StringVarP(&opts.iface, "interface", "i", "lo", "")
rootCmd.Flags().UintVar(&opts.pid, "pid", 0, "")
rootCmd.Flags().StringVar(&opts.comm, "pname", "", "")
rootCmd.Flags().BoolVarP(&opts.followForks, "follow-forks", "f", false,
"Include child processes when filter by process")
rootCmd.Flags().BoolVar(&opts.listInterfaces, "list-interfaces", false,
"Print the list of the network interfaces available on the system")
}

func Execute() error {
return rootCmd.Execute()
}

func run(cmd *cobra.Command, args []string) error {
if opts.listInterfaces {
return listInterfaces()
}

pcache := metadata.NewProcessCache()
writers, err := getWriters(opts, pcache)
if err != nil {
return err
}
go pcache.Start()

devices, bf, err := attachHooks(opts)
if err != nil {
return err
}
defer bf.Close()

packetEventReader, err := bf.NewPacketEventReader()
if err != nil {
return err
}
defer packetEventReader.Close()
execEventReader, err := bf.NewExecEventReader()
if err != nil {
return err
}
defer execEventReader.Close()

ctx, stop := signal.NotifyContext(
context.Background(), syscall.SIGINT, syscall.SIGTERM,
)
defer stop()

execConsumer := consumer.NewExecEventConsumer(pcache)
go execConsumer.Start(ctx, execEventReader)
packetConsumer := consumer.NewPacketEventConsumer(writers, devices)
go packetConsumer.Start(ctx, packetEventReader)

log.Println("tracing...")
<-ctx.Done()
log.Println("bye bye")

return nil
}
68 changes: 68 additions & 0 deletions cmd/writer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package cmd

import (
"github.com/gopacket/gopacket/layers"
"github.com/gopacket/gopacket/pcapgo"
"github.com/mozillazg/ptcpdump/internal/dev"
"github.com/mozillazg/ptcpdump/internal/metadata"
"github.com/mozillazg/ptcpdump/internal/writer"
"golang.org/x/xerrors"
"io"
"math"
"os"
)

func getWriters(opts Options, pcache *metadata.ProcessCache) ([]writer.PacketWriter, error) {
var writers []writer.PacketWriter

if opts.WritePath() != "" {
pcapFile, err := os.Create(opts.WritePath())
if err != nil {
return nil, err
}
pcapWriter, err := newPcapWriter(pcapFile, pcache)
if err != nil {
return nil, err
}
writers = append(writers, pcapWriter)
} else {
stdoutWriter := writer.NewStdoutWriter(os.Stdout, pcache)
writers = append(writers, stdoutWriter)
}

return writers, nil
}

func newPcapWriter(w io.Writer, pcache *metadata.ProcessCache) (*writer.PcapNGWriter, error) {
devices, err := dev.GetDevices("any")
if err != nil {
return nil, err
}

var interfaces []pcapgo.NgInterface
for _, dev := range devices {
interfaces = append(interfaces, pcapgo.NgInterface{
Name: dev.Name,
Comment: "ptcpdump interface name",
LinkType: layers.LinkTypeEthernet,
SnapLength: uint32(math.MaxUint16),
})
}

pcapWriter, err := pcapgo.NewNgWriterInterface(w, interfaces[0], pcapgo.NgWriterOptions{})
if err != nil {
return nil, xerrors.Errorf(": %w", err)
}
for _, ifc := range interfaces[1:] {
_, err := pcapWriter.AddInterface(ifc)
if err != nil {
return nil, xerrors.Errorf(": %w", err)
}
}

if err := pcapWriter.Flush(); err != nil {
return nil, xerrors.Errorf("writing pcap header: %w", err)
}

return writer.NewPcapNGWriter(pcapWriter, pcache), nil
}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/gopacket/gopacket v1.2.0
github.com/jschwinger233/elibpcap v0.0.0-20231010035657-e99300096f5e
github.com/shirou/gopsutil/v3 v3.24.3
github.com/spf13/cobra v1.8.0
github.com/vishvananda/netlink v1.1.0
github.com/x-way/pktdump v0.0.5
golang.org/x/sys v0.19.0
Expand All @@ -18,13 +19,15 @@ require (
github.com/cloudflare/cbpfc v0.0.0-20230809125630-31aa294050ff // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/native v1.1.0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/mdlayher/netlink v1.6.0 // indirect
github.com/mdlayher/socket v0.1.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ github.com/cilium/ebpf v0.14.0 h1:0PsxAjO6EjI1rcT+rkp6WcCnE0ZvfkXBYiMedJtrSUs=
github.com/cilium/ebpf v0.14.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso=
github.com/cloudflare/cbpfc v0.0.0-20230809125630-31aa294050ff h1:SLLG1soGN/PYTXkYWiR1PAxWlP1URBvgZPYymC5+0WI=
github.com/cloudflare/cbpfc v0.0.0-20230809125630-31aa294050ff/go.mod h1:1xLQNNpgw8yNlVjGrtUHBx0KL52fif71sKa1PleulAQ=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
Expand All @@ -28,6 +29,8 @@ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
Expand Down Expand Up @@ -85,12 +88,17 @@ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:Om
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shirou/gopsutil/v3 v3.24.3 h1:eoUGJSmdfLzJ3mxIhmOAhgKEKgQkeOwKpz1NbhVnuPE=
github.com/shirou/gopsutil/v3 v3.24.3/go.mod h1:JpND7O217xa72ewWz9zN2eIIkPWsDN/3pl0H8Qt0uwg=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
Expand Down
55 changes: 55 additions & 0 deletions internal/consumer/exec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package consumer

import (
"context"
"errors"
"github.com/cilium/ebpf/perf"
"github.com/cilium/ebpf/ringbuf"
"github.com/mozillazg/ptcpdump/internal/event"
"github.com/mozillazg/ptcpdump/internal/metadata"
"log"
)

type ExecEventConsumer struct {
pcache *metadata.ProcessCache
}

func NewExecEventConsumer(pcache *metadata.ProcessCache) *ExecEventConsumer {
return &ExecEventConsumer{
pcache: pcache,
}
}

func (c *ExecEventConsumer) Start(ctx context.Context, reader *ringbuf.Reader) {
for {
select {
case <-ctx.Done():
return
default:
}

record, err := reader.Read()
if err != nil {
if errors.Is(err, perf.ErrClosed) {
log.Println("[ExecEventConsumer] Received signal, exiting...")
return
}
log.Printf("[ExecEventConsumer] read event failed: %s", err)
continue
}
c.parseExecEvent(record.RawSample)
}
}

func (c *ExecEventConsumer) parseExecEvent(rawSample []byte) {
e, err := event.ParseProcessExecEvent(rawSample)
if err != nil {
log.Printf("[ExecEventConsumer] parse event failed: %s", err)
return
}
c.pcache.AddItem(*e)
}

func (c *ExecEventConsumer) Stop() {

}
Loading

0 comments on commit 43a7026

Please sign in to comment.