github.com/castai/kvisor@v1.7.1-0.20240516114728-b3572a2607b5/pkg/ebpftracer/policy_filters.go (about)

     1  package ebpftracer
     2  
     3  import (
     4  	"errors"
     5  	"log/slog"
     6  	"time"
     7  
     8  	"github.com/castai/kvisor/pkg/ebpftracer/events"
     9  	"github.com/castai/kvisor/pkg/ebpftracer/types"
    10  	"github.com/castai/kvisor/pkg/logging"
    11  	"github.com/cespare/xxhash"
    12  	"github.com/elastic/go-freelru"
    13  	"github.com/samber/lo"
    14  	"golang.org/x/time/rate"
    15  )
    16  
    17  var (
    18  	FilterPass                    error = nil
    19  	FilterErrRateLimit                  = errors.New("rate limit")
    20  	FilterErrEmptyDNSResponse           = errors.New("empty dns response")
    21  	FilterErrDNSDuplicateDetected       = errors.New("dns duplicate detected")
    22  )
    23  
    24  // GlobalPreEventFilterGenerator always returns the given filter on each generator invocation. This is useful,
    25  // if you want some global filtering across cgroups.
    26  func GlobalPreEventFilterGenerator(filter PreEventFilter) PreEventFilterGenerator {
    27  	return func() PreEventFilter {
    28  		return filter
    29  	}
    30  }
    31  
    32  // GlobalEventFilterGenerator always returns the given filter on each generator invocation. This is useful,
    33  // if you want some global filtering across cgroups.
    34  func GlobalEventFilterGenerator(filter EventFilter) EventFilterGenerator {
    35  	return func() EventFilter {
    36  		return filter
    37  	}
    38  }
    39  
    40  func FilterAnd(filtersGenerators ...EventFilterGenerator) EventFilterGenerator {
    41  	return func() EventFilter {
    42  		filters := lo.Map(filtersGenerators, func(generator EventFilterGenerator, index int) EventFilter {
    43  			return generator()
    44  		})
    45  
    46  		return func(event *types.Event) error {
    47  			for _, f := range filters {
    48  				if err := f(event); err != nil {
    49  					return err
    50  				}
    51  			}
    52  
    53  			return FilterPass
    54  		}
    55  	}
    56  }
    57  
    58  // PreRateLimit creates an pre event filter that limits the amount of events that will be
    59  // processed accoring to the specified limits
    60  func PreRateLimit(spec RateLimitPolicy) PreEventFilterGenerator {
    61  	return func() PreEventFilter {
    62  		rateLimiter := newRateLimiter(spec)
    63  
    64  		return func(ctx *types.EventContext) error {
    65  			if rateLimiter.Allow() {
    66  				return FilterPass
    67  			}
    68  
    69  			return FilterErrRateLimit
    70  		}
    71  	}
    72  }
    73  
    74  func RateLimit(spec RateLimitPolicy) EventFilterGenerator {
    75  	return func() EventFilter {
    76  		rateLimiter := newRateLimiter(spec)
    77  
    78  		return func(event *types.Event) error {
    79  			if rateLimiter.Allow() {
    80  				return FilterPass
    81  			}
    82  
    83  			return FilterErrRateLimit
    84  		}
    85  	}
    86  }
    87  
    88  func newRateLimiter(spec RateLimitPolicy) *rate.Limiter {
    89  	var limit rate.Limit
    90  
    91  	if spec.Interval != 0 {
    92  		limit = rate.Every(spec.Interval)
    93  		spec.Burst = 1
    94  	} else {
    95  		limit = rate.Limit(spec.Rate)
    96  		if spec.Burst == 0 {
    97  			spec.Burst = 1
    98  		}
    99  	}
   100  
   101  	rateLimiter := rate.NewLimiter(limit, spec.Burst)
   102  	return rateLimiter
   103  }
   104  
   105  // FilterEmptyDnsAnswers will drop any DNS event, that is missing an answer section
   106  func FilterEmptyDnsAnswers(l *logging.Logger) EventFilterGenerator {
   107  	return func() EventFilter {
   108  		return func(event *types.Event) error {
   109  			if event.Context.EventID != events.NetPacketDNSBase {
   110  				return FilterPass
   111  			}
   112  
   113  			dnsEventArgs, ok := event.Args.(types.NetPacketDNSBaseArgs)
   114  			if !ok {
   115  				return FilterPass
   116  			}
   117  
   118  			if dnsEventArgs.Payload == nil {
   119  				l.Warn("retreived invalid event for event type dns")
   120  				return FilterPass
   121  			}
   122  
   123  			if len(dnsEventArgs.Payload.Answers) == 0 {
   124  				return FilterErrEmptyDNSResponse
   125  			}
   126  
   127  			return FilterPass
   128  		}
   129  	}
   130  }
   131  
   132  // more hash function in https://github.com/elastic/go-freelru/blob/main/bench/hash.go
   133  func hashStringXXHASH(s string) uint32 {
   134  	return uint32(xxhash.Sum64String(s))
   135  }
   136  
   137  // DeduplicateDnsEvents creates a filter that will drop any DNS event with questions already seen in `ttl` time
   138  func DeduplicateDnsEvents(l *logging.Logger, size uint32, ttl time.Duration) EventFilterGenerator {
   139  	type cacheValue struct{}
   140  
   141  	return func() EventFilter {
   142  		cache, err := freelru.New[string, cacheValue](size, hashStringXXHASH)
   143  		// err is only ever returned on configuration issues. There is nothing we can really do here, besides
   144  		// panicing and surfacing the error to the user.
   145  		if err != nil {
   146  			panic(err)
   147  		}
   148  
   149  		cache.SetLifetime(ttl)
   150  
   151  		return func(event *types.Event) error {
   152  			if event.Context.EventID != events.NetPacketDNSBase {
   153  				return FilterPass
   154  			}
   155  
   156  			dnsEventArgs, ok := event.Args.(types.NetPacketDNSBaseArgs)
   157  			if !ok {
   158  				return FilterPass
   159  			}
   160  
   161  			if dnsEventArgs.Payload == nil {
   162  				l.Warn("received invalid event for event type dns")
   163  				return FilterPass
   164  			}
   165  
   166  			cacheKey := dnsEventArgs.Payload.DNSQuestionDomain
   167  			if cache.Contains(cacheKey) {
   168  				if l.IsEnabled(slog.LevelDebug) {
   169  					l.WithField("cachekey", cacheKey).Debug("dropping DNS event")
   170  				}
   171  				return FilterErrDNSDuplicateDetected
   172  			}
   173  
   174  			cache.Add(cacheKey, cacheValue{})
   175  
   176  			return FilterPass
   177  		}
   178  	}
   179  }