From f844a9e16261638dc442f1ab817a0523324b68a9 Mon Sep 17 00:00:00 2001 From: Huang Huang Date: Sun, 16 Jun 2024 21:30:21 +0800 Subject: [PATCH] Add new flag `--docker-address`, `--containerd-address`, `--cri-runtime-address` (#74) --- README.md | 38 ++++++++++++++----------- cmd/container.go | 3 +- cmd/options.go | 35 +++++++++++++++++++++++ cmd/root.go | 10 +++++++ internal/metadata/container.go | 7 +++-- internal/metadata/container/multiple.go | 6 ++-- internal/metadata/k8s/cri.go | 15 ++++++---- 7 files changed, 85 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 7fd901eb..2ceba0cb 100644 --- a/README.md +++ b/README.md @@ -150,23 +150,27 @@ Examples: Expression: see "man 7 pcap-filter" Flags: - --container-id string Filter by container id (only TCP and UDP packets are supported) - --container-name string Filter by container name (only TCP and UDP packets are supported) - -Q, --direction string Choose send/receive direction for which packets should be captured. Possible values are 'in', 'out' and 'inout' (default "inout") - -f, --follow-forks Trace child processes as they are created by currently traced processes when filter by process - -h, --help help for ptcpdump - -i, --interface strings Interfaces to capture (default [lo]) - --list-interfaces Print the list of the network interfaces available on the system - --log-level string Set the logging level ("debug", "info", "warn", "error", "fatal") (default "warn") - --oneline Print parsed packet output in a single line - --pid uint Filter by process ID (only TCP and UDP packets are supported) - --pname string Filter by process name (only TCP and UDP packets are supported) - --print Print parsed packet output, even if the raw packets are being saved to a file with the -w flag - -r, --read-file string Read packets from file (which was created with the -w option). e.g. ptcpdump.pcapng - -c, --receive-count uint Exit after receiving count packets - -v, --verbose count When parsing and printing, produce (slightly more) verbose output - --version Print the ptcpdump and libpcap version strings and exit - -w, --write-file string Write the raw packets to file rather than parsing and printing them out. They can later be printed with the -r option. Standard output is used if file is '-'. e.g. ptcpdump.pcapng + --container-id string Filter by container id (only TCP and UDP packets are supported) + --container-name string Filter by container name (only TCP and UDP packets are supported) + --containerd-address string Address of containerd service (default "/run/containerd/containerd.sock") + --count Print only on stdout the packet count when reading capture file instead of parsing/printing the packets + --cri-runtime-address string Address of CRI container runtime service (default: uses in order the first successful one of [/run/containerd/containerd.sock, /run/crio/crio.sock, /var/run/cri-dockerd.sock, /var/run/dockershim.sock]) + -Q, --direction string Choose send/receive direction for which packets should be captured. Possible values are 'in', 'out' and 'inout' (default "inout") + --docker-address string Address of Docker Engine service (default "/var/run/docker.sock") + -f, --follow-forks Trace child processes as they are created by currently traced processes when filter by process + -h, --help help for ptcpdump + -i, --interface strings Interfaces to capture (default [lo]) + --list-interfaces Print the list of the network interfaces available on the system + --log-level string Set the logging level ("debug", "info", "warn", "error", "fatal") (default "warn") + --oneline Print parsed packet output in a single line + --pid uint Filter by process ID (only TCP and UDP packets are supported) + --pname string Filter by process name (only TCP and UDP packets are supported) + --print Print parsed packet output, even if the raw packets are being saved to a file with the -w flag + -r, --read-file string Read packets from file (which was created with the -w option). e.g. ptcpdump.pcapng + -c, --receive-count uint Exit after receiving count packets + -v, --verbose count When parsing and printing, produce (slightly more) verbose output + --version Print the ptcpdump and libpcap version strings and exit + -w, --write-file string Write the raw packets to file rather than parsing and printing them out. They can later be printed with the -r option. Standard output is used if file is '-'. e.g. ptcpdump.pcapng ```

🔝

diff --git a/cmd/container.go b/cmd/container.go index 617e8f7e..92a543f4 100644 --- a/cmd/container.go +++ b/cmd/container.go @@ -9,7 +9,8 @@ import ( ) func applyContainerFilter(ctx context.Context, opts *Options) (*metadata.ContainerCache, error) { - cc, err := metadata.NewContainerCache(ctx) + cc, err := metadata.NewContainerCache(ctx, opts.dockerEndpoint, + opts.containerdEndpoint, opts.criRuntimeEndpoint) if err != nil { if opts.filterByContainer() { log.Fatalf("find container failed: %s", err) diff --git a/cmd/options.go b/cmd/options.go index 59bace95..746c3d8a 100644 --- a/cmd/options.go +++ b/cmd/options.go @@ -1,8 +1,11 @@ package cmd import ( + "fmt" "strings" "time" + + "github.com/mozillazg/ptcpdump/internal/metadata/k8s" ) const ( @@ -38,6 +41,10 @@ type Options struct { execEventsWorkerNumber uint logLevel string + dockerEndpoint string + containerdEndpoint string + criRuntimeEndpoint string + subProgArgs []string mntns_id uint32 @@ -76,4 +83,32 @@ func prepareOptions(opts *Options, rawArgs []string, args []string) { opts.pcapFilter = strings.TrimSuffix(opts.pcapFilter, strings.Join(subProgArgs, " ")) } opts.pcapFilter = strings.TrimSpace(opts.pcapFilter) + + if opts.dockerEndpoint != "" { + opts.dockerEndpoint = getEndpoint(opts.dockerEndpoint) + } + // if opts.containerdEndpoint != "" { + // opts.containerdEndpoint = getEndpoint(opts.containerdEndpoint) + // } + if opts.criRuntimeEndpoint != "" { + opts.criRuntimeEndpoint = getEndpoint(opts.criRuntimeEndpoint) + } +} + +func getEndpoint(raw string) string { + if strings.HasPrefix(raw, "http") { + return raw + } + if strings.HasPrefix(raw, "unix://") { + return raw + } + return fmt.Sprintf("unix://%s", raw) +} + +func getDefaultCriRuntimeEndpoint() []string { + var rs []string + for _, end := range k8s.DefaultRuntimeEndpoints { + rs = append(rs, strings.TrimPrefix(end, "unix://")) + } + return rs } diff --git a/cmd/root.go b/cmd/root.go index 2b1c6646..f841f421 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -2,8 +2,10 @@ package cmd import ( "context" + "fmt" "os" "os/signal" + "strings" "syscall" "github.com/mozillazg/ptcpdump/internal/utils" @@ -85,6 +87,14 @@ func init() { rootCmd.Flags().StringVar(&opts.containerId, "container-id", "", "Filter by container id (only TCP and UDP packets are supported)") rootCmd.Flags().StringVar(&opts.containerName, "container-name", "", "Filter by container name (only TCP and UDP packets are supported)") rootCmd.Flags().StringVar(&opts.logLevel, "log-level", "warn", `Set the logging level ("debug", "info", "warn", "error", "fatal")`) + rootCmd.Flags().StringVar(&opts.dockerEndpoint, "docker-address", "/var/run/docker.sock", + `Address of Docker Engine service`) + rootCmd.Flags().StringVar(&opts.containerdEndpoint, "containerd-address", "/run/containerd/containerd.sock", + `Address of containerd service`) + rootCmd.Flags().StringVar(&opts.criRuntimeEndpoint, "cri-runtime-address", "", + "Address of CRI container runtime service "+ + fmt.Sprintf("(default: uses in order the first successful one of [%s])", + strings.Join(getDefaultCriRuntimeEndpoint(), ", "))) } diff --git a/internal/metadata/container.go b/internal/metadata/container.go index 63b273a6..60440fc8 100644 --- a/internal/metadata/container.go +++ b/internal/metadata/container.go @@ -14,13 +14,14 @@ type ContainerCache struct { k8s *k8s.MetaData } -func NewContainerCache(ctx context.Context) (*ContainerCache, error) { - d := container.NewMultipleEngineMetaData() +func NewContainerCache(ctx context.Context, + dockerEndpoint, containerdEndpoint, criRuntimeEndpoint string) (*ContainerCache, error) { + d := container.NewMultipleEngineMetaData(dockerEndpoint, containerdEndpoint) if err := d.Start(ctx); err != nil { return nil, err } - k8sd, err := k8s.NewMetaData() + k8sd, err := k8s.NewMetaData(criRuntimeEndpoint) if err != nil { log.Warnf("skip k8s integration: %s", err) } diff --git a/internal/metadata/container/multiple.go b/internal/metadata/container/multiple.go index d198ce2b..20c46fca 100644 --- a/internal/metadata/container/multiple.go +++ b/internal/metadata/container/multiple.go @@ -13,10 +13,10 @@ type MultipleEngineMetaData struct { engines []MetaData } -func NewMultipleEngineMetaData() *MultipleEngineMetaData { +func NewMultipleEngineMetaData(dockerEndpoint, containerdEndpoint string) *MultipleEngineMetaData { var m MultipleEngineMetaData - dr, err := docker.NewMetaData("") + dr, err := docker.NewMetaData(dockerEndpoint) if err != nil { log.Infof(err.Error()) log.Warn("skip Docker Engine integration") @@ -24,7 +24,7 @@ func NewMultipleEngineMetaData() *MultipleEngineMetaData { m.engines = append(m.engines, dr) } - cd, err := containerd.NewMultipleNamespacesMetaData("", "") + cd, err := containerd.NewMultipleNamespacesMetaData(containerdEndpoint, "") if err != nil { log.Infof(err.Error()) log.Warn("skip containerd integration") diff --git a/internal/metadata/k8s/cri.go b/internal/metadata/k8s/cri.go index 28a90a24..b498039c 100644 --- a/internal/metadata/k8s/cri.go +++ b/internal/metadata/k8s/cri.go @@ -13,10 +13,11 @@ import ( "k8s.io/klog/v2" ) -var defaultRuntimeEndpoints = []string{ +var DefaultRuntimeEndpoints = []string{ "unix:///run/containerd/containerd.sock", "unix:///run/crio/crio.sock", "unix:///var/run/cri-dockerd.sock", + "unix:///var/run/dockershim.sock", } const defaultTimeout = 2 * time.Second @@ -25,8 +26,8 @@ type MetaData struct { res cri.RuntimeService } -func NewMetaData() (*MetaData, error) { - res, err := getRuntimeService() +func NewMetaData(criRuntimeEndpoint string) (*MetaData, error) { + res, err := getRuntimeService(criRuntimeEndpoint) if err != nil { log.Warn("skip kubernetes integration") } @@ -79,12 +80,16 @@ func tidyLabels(raw map[string]string) map[string]string { return newLabels } -func getRuntimeService() (res cri.RuntimeService, err error) { +func getRuntimeService(criRuntimeEndpoint string) (res cri.RuntimeService, err error) { logger := klog.Background() t := defaultTimeout + endpoints := DefaultRuntimeEndpoints var tp trace.TracerProvider = noop.NewTracerProvider() + if criRuntimeEndpoint != "" { + endpoints = []string{criRuntimeEndpoint} + } - for _, endPoint := range defaultRuntimeEndpoints { + for _, endPoint := range endpoints { log.Debugf("Connect using endpoint %q with %q timeout", endPoint, t) res, err = remote.NewRemoteRuntimeService(endPoint, t, tp, &logger) if err != nil {