Repository: microsoft/retina
File: pkg/capture/provider/network_capture_unix.go (Go)

Code before:
	captureConstants "github.com/microsoft/retina/pkg/capture/constants"
	captureUtils "github.com/microsoft/retina/pkg/capture/utils"
	"github.com/microsoft/retina/pkg/log"
)

type NetworkCaptureProvider struct {
	NetworkCaptureProviderCommon
	TmpCaptureDir  string
	CaptureName    string
	NodeHostName   string
	StartTimestamp time.Time

	l *log.ZapLogger
}

var _ NetworkCaptureProviderInterface = &NetworkCaptureProvider{}

func NewNetworkCaptureProvider(logger *log.ZapLogger) NetworkCaptureProviderInterface {
	return &NetworkCaptureProvider{
		NetworkCaptureProviderCommon: NetworkCaptureProviderCommon{l: logger},
		l:                            logger,
	}
}

func (ncp *NetworkCaptureProvider) Setup(captureName, nodeHostname string, startTimestamp time.Time) (string, error) {
	captureFolderDir, err := ncp.NetworkCaptureProviderCommon.Setup(captureName, nodeHostname, startTimestamp)
	if err != nil {
		return "", err
	}
	ncp.l.Info("Created temporary folder for network capture", zap.String("capture temporary folder", captureFolderDir))

	ncp.TmpCaptureDir = captureFolderDir
	ncp.CaptureName = captureName
	ncp.NodeHostName = nodeHostname
	return ncp.TmpCaptureDir, nil
}

func (ncp *NetworkCaptureProvider) CaptureNetworkPacket(filter string, duration, maxSizeMB int, sigChan <-chan os.Signal) error {
	captureFileName := captureUtils.GenerateCaptureFileName(ncp.CaptureName, ncp.NodeHostName, ncp.StartTimestamp)
	captureFileName = fmt.Sprintf("%s.pcap", captureFileName)
	captureFilePath := filepath.Join(ncp.TmpCaptureDir, captureFileName)

	// Remove the folder in case it already exists to mislead the file size check.
	os.Remove(captureFilePath) //nolint:errcheck

	// NOTE(mainred): The tcpdump release of debian:bullseye image, which is for preparing clang and tools, runs as
	// tcpdump user by default for savefiles for output, but when the binary and library are copied to the distroless
	// base image, we lost tcpdump user, and the following error will be raised when running tcpdump in our capture pod.
	// tcpdump: Couldn't find user 'tcpdump'
	// To disable this behavior, we use `--relinquish-privileges=root` same as `-Z root`.
	// ref: https://manpages.debian.org/bullseye/tcpdump/tcpdump.8.en.html#Z

Review comment (suggestion):
Following from the comment on the prev file: Instead of passing timestamp down the `Setup` call chain, we can use ncp.StartTimestamp, and similarly for other objects implementing this interface? I am assuming it is going to be constant for the lifecycle of capture

Code after:
	captureConstants "github.com/microsoft/retina/pkg/capture/constants"
	"github.com/microsoft/retina/pkg/capture/file"
	"github.com/microsoft/retina/pkg/log"
)

type NetworkCaptureProvider struct {
	NetworkCaptureProviderCommon
	TmpCaptureDir  string
	CaptureName    string
	NodeHostName   string
	StartTimestamp *file.Timestamp

	l *log.ZapLogger
}

var _ NetworkCaptureProviderInterface = &NetworkCaptureProvider{}

func NewNetworkCaptureProvider(logger *log.ZapLogger) NetworkCaptureProviderInterface {
	return &NetworkCaptureProvider{
		NetworkCaptureProviderCommon: NetworkCaptureProviderCommon{l: logger},
		l:                            logger,
	}
}

func (ncp *NetworkCaptureProvider) Setup(filename file.CaptureFilename) (string, error) {
	captureFolderDir, err := ncp.NetworkCaptureProviderCommon.Setup(filename)
	if err != nil {
		return "", err
	}
	ncp.l.Info("Created temporary folder for network capture", zap.String("capture temporary folder", captureFolderDir))

	ncp.TmpCaptureDir = captureFolderDir
	ncp.CaptureName = filename.CaptureName
	ncp.NodeHostName = filename.NodeHostname
	ncp.StartTimestamp = filename.StartTimestamp
	return ncp.TmpCaptureDir, nil
}

func (ncp *NetworkCaptureProvider) CaptureNetworkPacket(filter string, duration, maxSizeMB int, sigChan <-chan os.Signal) error {
	filename := file.CaptureFilename{CaptureName: ncp.CaptureName, NodeHostname: ncp.NodeHostName, StartTimestamp: ncp.StartTimestamp}
	captureFileName := fmt.Sprintf("%s.pcap", filename)
	captureFilePath := filepath.Join(ncp.TmpCaptureDir, captureFileName)

	// Remove the folder in case it already exists to mislead the file size check.
	os.Remove(captureFilePath) //nolint:errcheck

	// NOTE(mainred): The tcpdump release of debian:bullseye image, which is for preparing clang and tools, runs as
	// tcpdump user by default for savefiles for output, but when the binary and library are copied to the distroless
	// base image, we lost tcpdump user, and the following error will be raised when running tcpdump in our capture pod.
	// tcpdump: Couldn't find user 'tcpdump'
	// To disable this behavior, we use `--relinquish-privileges=root` same as `-Z root`.