mirror of
https://github.com/kubeshark/kubeshark.git
synced 2025-08-19 00:49:35 +00:00
Fetch source and destination addresses with bpf from tcp kprobes, similar to how it is done for openssl lib. Chunk contains both source address and destination address. FD is no longer used to obtain addresses.
254 lines
6.3 KiB
Go
254 lines
6.3 KiB
Go
package tlstapper
|
|
|
|
import (
|
|
"strconv"
|
|
"sync"
|
|
|
|
"github.com/cilium/ebpf/rlimit"
|
|
"github.com/go-errors/errors"
|
|
"github.com/moby/moby/pkg/parsers/kernel"
|
|
"github.com/up9inc/mizu/logger"
|
|
"github.com/up9inc/mizu/tap/api"
|
|
)
|
|
|
|
const GlobalTapPid = 0
|
|
|
|
// TODO: cilium/ebpf does not support .kconfig Therefore; for now, we build object files per kernel version.
|
|
|
|
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go@v0.9.0 -target $BPF_TARGET -cflags $BPF_CFLAGS -type tls_chunk -type goid_offsets tlsTapper bpf/tls_tapper.c
|
|
|
|
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go@v0.9.0 -target $BPF_TARGET -cflags "${BPF_CFLAGS} -DKERNEL_BEFORE_4_6" -type tls_chunk -type goid_offsets tlsTapper46 bpf/tls_tapper.c
|
|
|
|
type TlsTapper struct {
|
|
bpfObjects tlsTapperObjects
|
|
syscallHooks syscallHooks
|
|
tcpKprobeHooks tcpKprobeHooks
|
|
sslHooksStructs []sslHooks
|
|
goHooksStructs []goHooks
|
|
poller *tlsPoller
|
|
bpfLogger *bpfLogger
|
|
registeredPids sync.Map
|
|
}
|
|
|
|
func (t *TlsTapper) Init(chunksBufferSize int, logBufferSize int, procfs string, extension *api.Extension) error {
|
|
logger.Log.Infof("Initializing tls tapper (chunksSize: %d) (logSize: %d)", chunksBufferSize, logBufferSize)
|
|
|
|
var err error
|
|
err = setupRLimit()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var kernelVersion *kernel.VersionInfo
|
|
kernelVersion, err = kernel.GetKernelVersion()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
logger.Log.Infof("Detected Linux kernel version: %s", kernelVersion)
|
|
|
|
t.bpfObjects = tlsTapperObjects{}
|
|
// TODO: cilium/ebpf does not support .kconfig Therefore; for now, we load object files according to kernel version.
|
|
if kernel.CompareKernelVersion(*kernelVersion, kernel.VersionInfo{Kernel: 4, Major: 6, Minor: 0}) < 1 {
|
|
if err := loadTlsTapper46Objects(&t.bpfObjects, nil); err != nil {
|
|
return errors.Wrap(err, 0)
|
|
}
|
|
} else {
|
|
if err := loadTlsTapperObjects(&t.bpfObjects, nil); err != nil {
|
|
return errors.Wrap(err, 0)
|
|
}
|
|
}
|
|
|
|
t.syscallHooks = syscallHooks{}
|
|
if err := t.syscallHooks.installSyscallHooks(&t.bpfObjects); err != nil {
|
|
return err
|
|
}
|
|
|
|
t.tcpKprobeHooks = tcpKprobeHooks{}
|
|
if err := t.tcpKprobeHooks.installTcpKprobeHooks(&t.bpfObjects); err != nil {
|
|
return err
|
|
}
|
|
|
|
t.sslHooksStructs = make([]sslHooks, 0)
|
|
|
|
t.bpfLogger = newBpfLogger()
|
|
if err := t.bpfLogger.init(&t.bpfObjects, logBufferSize); err != nil {
|
|
return err
|
|
}
|
|
|
|
t.poller, err = newTlsPoller(t, extension, procfs)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return t.poller.init(&t.bpfObjects, chunksBufferSize)
|
|
}
|
|
|
|
func (t *TlsTapper) Poll(emitter api.Emitter, options *api.TrafficFilteringOptions, streamsMap api.TcpStreamMap) {
|
|
t.poller.poll(emitter, options, streamsMap)
|
|
}
|
|
|
|
func (t *TlsTapper) PollForLogging() {
|
|
t.bpfLogger.poll()
|
|
}
|
|
|
|
func (t *TlsTapper) GlobalSSLLibTap(sslLibrary string) error {
|
|
return t.tapSSLLibPid(GlobalTapPid, sslLibrary, api.UnknownNamespace)
|
|
}
|
|
|
|
func (t *TlsTapper) GlobalGoTap(procfs string, pid string) error {
|
|
_pid, err := strconv.Atoi(pid)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return t.tapGoPid(procfs, uint32(_pid), api.UnknownNamespace)
|
|
}
|
|
|
|
func (t *TlsTapper) AddSSLLibPid(procfs string, pid uint32, namespace string) error {
|
|
sslLibrary, err := findSsllib(procfs, pid)
|
|
|
|
if err != nil {
|
|
logger.Log.Infof("PID skipped no libssl.so found (pid: %d) %v", pid, err)
|
|
return nil // hide the error on purpose, it's OK for a process to not use libssl.so
|
|
}
|
|
|
|
return t.tapSSLLibPid(pid, sslLibrary, namespace)
|
|
}
|
|
|
|
func (t *TlsTapper) AddGoPid(procfs string, pid uint32, namespace string) error {
|
|
return t.tapGoPid(procfs, pid, namespace)
|
|
}
|
|
|
|
func (t *TlsTapper) RemovePid(pid uint32) error {
|
|
logger.Log.Infof("Removing PID (pid: %v)", pid)
|
|
|
|
pids := t.bpfObjects.tlsTapperMaps.PidsMap
|
|
|
|
if err := pids.Delete(pid); err != nil {
|
|
return errors.Wrap(err, 0)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (t *TlsTapper) ClearPids() {
|
|
t.poller.clearPids()
|
|
t.registeredPids.Range(func(key, v interface{}) bool {
|
|
pid := key.(uint32)
|
|
if pid == GlobalTapPid {
|
|
return true
|
|
}
|
|
|
|
if err := t.RemovePid(pid); err != nil {
|
|
LogError(err)
|
|
}
|
|
t.registeredPids.Delete(key)
|
|
return true
|
|
})
|
|
}
|
|
|
|
func (t *TlsTapper) Close() []error {
|
|
returnValue := make([]error, 0)
|
|
|
|
if err := t.bpfObjects.Close(); err != nil {
|
|
returnValue = append(returnValue, err)
|
|
}
|
|
|
|
returnValue = append(returnValue, t.syscallHooks.close()...)
|
|
|
|
returnValue = append(returnValue, t.tcpKprobeHooks.close()...)
|
|
|
|
for _, sslHooks := range t.sslHooksStructs {
|
|
returnValue = append(returnValue, sslHooks.close()...)
|
|
}
|
|
|
|
for _, goHooks := range t.goHooksStructs {
|
|
returnValue = append(returnValue, goHooks.close()...)
|
|
}
|
|
|
|
if err := t.bpfLogger.close(); err != nil {
|
|
returnValue = append(returnValue, err)
|
|
}
|
|
|
|
if err := t.poller.close(); err != nil {
|
|
returnValue = append(returnValue, err)
|
|
}
|
|
|
|
return returnValue
|
|
}
|
|
|
|
func setupRLimit() error {
|
|
err := rlimit.RemoveMemlock()
|
|
|
|
if err != nil {
|
|
return errors.Wrap(err, 0)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (t *TlsTapper) tapSSLLibPid(pid uint32, sslLibrary string, namespace string) error {
|
|
newSsl := sslHooks{}
|
|
|
|
if err := newSsl.installUprobes(&t.bpfObjects, sslLibrary); err != nil {
|
|
return err
|
|
}
|
|
|
|
logger.Log.Infof("Tapping TLS (pid: %v) (sslLibrary: %v)", pid, sslLibrary)
|
|
|
|
t.sslHooksStructs = append(t.sslHooksStructs, newSsl)
|
|
|
|
t.poller.addPid(pid, namespace)
|
|
|
|
pids := t.bpfObjects.tlsTapperMaps.PidsMap
|
|
|
|
if err := pids.Put(pid, uint32(1)); err != nil {
|
|
return errors.Wrap(err, 0)
|
|
}
|
|
|
|
t.registeredPids.Store(pid, true)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (t *TlsTapper) tapGoPid(procfs string, pid uint32, namespace string) error {
|
|
exePath, err := findLibraryByPid(procfs, pid, "")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
hooks := goHooks{}
|
|
|
|
if err := hooks.installUprobes(&t.bpfObjects, exePath); err != nil {
|
|
logger.Log.Infof("PID skipped not a Go binary or symbol table is stripped (pid: %v) %v", pid, exePath)
|
|
return nil // hide the error on purpose, its OK for a process to be not a Go binary or stripped Go binary
|
|
}
|
|
|
|
logger.Log.Infof("Tapping TLS (pid: %v) (Go: %v)", pid, exePath)
|
|
|
|
t.goHooksStructs = append(t.goHooksStructs, hooks)
|
|
|
|
t.poller.addPid(pid, namespace)
|
|
|
|
pids := t.bpfObjects.tlsTapperMaps.PidsMap
|
|
|
|
if err := pids.Put(pid, uint32(1)); err != nil {
|
|
return errors.Wrap(err, 0)
|
|
}
|
|
|
|
t.registeredPids.Store(pid, true)
|
|
|
|
return nil
|
|
}
|
|
|
|
func LogError(err error) {
|
|
var e *errors.Error
|
|
if errors.As(err, &e) {
|
|
logger.Log.Errorf("Error: %v", e.ErrorStack())
|
|
} else {
|
|
logger.Log.Errorf("Error: %v", err)
|
|
}
|
|
}
|