github.com/cilium/cilium@v1.16.2/pkg/hubble/filters/fqdn.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Hubble
     3  
     4  package filters
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"regexp"
    10  
    11  	flowpb "github.com/cilium/cilium/api/v1/flow"
    12  	v1 "github.com/cilium/cilium/pkg/hubble/api/v1"
    13  )
    14  
    15  func sourceFQDN(ev *v1.Event) []string {
    16  	return ev.GetFlow().GetSourceNames()
    17  }
    18  
    19  func destinationFQDN(ev *v1.Event) []string {
    20  	return ev.GetFlow().GetDestinationNames()
    21  }
    22  
    23  func filterByFQDNs(fqdnPatterns []string, getFQDNs func(*v1.Event) []string) (FilterFunc, error) {
    24  	fqdnRegexp, err := compileFQDNPattern(fqdnPatterns)
    25  	if err != nil {
    26  		return nil, err
    27  	}
    28  
    29  	return func(ev *v1.Event) bool {
    30  		names := getFQDNs(ev)
    31  		if len(names) == 0 {
    32  			return false
    33  		}
    34  
    35  		for _, name := range names {
    36  			if fqdnRegexp.MatchString(name) {
    37  				return true
    38  			}
    39  		}
    40  
    41  		return false
    42  	}, nil
    43  }
    44  
    45  // filterByDNSQueries returns a FilterFunc that filters a flow by L7.DNS.query field.
    46  // The filter function returns true if and only if the DNS query field matches any of
    47  // the regular expressions.
    48  func filterByDNSQueries(queryPatterns []string) (FilterFunc, error) {
    49  	queries := make([]*regexp.Regexp, 0, len(queryPatterns))
    50  	for _, pattern := range queryPatterns {
    51  		query, err := regexp.Compile(pattern)
    52  		if err != nil {
    53  			return nil, fmt.Errorf("failed to compile regexp: %w", err)
    54  		}
    55  		queries = append(queries, query)
    56  	}
    57  	return func(ev *v1.Event) bool {
    58  		dns := ev.GetFlow().GetL7().GetDns()
    59  		if dns == nil {
    60  			return false
    61  		}
    62  		for _, query := range queries {
    63  			if query.MatchString(dns.Query) {
    64  				return true
    65  			}
    66  		}
    67  		return false
    68  	}, nil
    69  }
    70  
    71  // FQDNFilter implements filtering based on FQDN information
    72  type FQDNFilter struct{}
    73  
    74  // OnBuildFilter builds a FQDN filter
    75  func (f *FQDNFilter) OnBuildFilter(ctx context.Context, ff *flowpb.FlowFilter) ([]FilterFunc, error) {
    76  	var fs []FilterFunc
    77  
    78  	if ff.GetSourceFqdn() != nil {
    79  		ff, err := filterByFQDNs(ff.GetSourceFqdn(), sourceFQDN)
    80  		if err != nil {
    81  			return nil, err
    82  		}
    83  		fs = append(fs, ff)
    84  	}
    85  
    86  	if ff.GetDestinationFqdn() != nil {
    87  		ff, err := filterByFQDNs(ff.GetDestinationFqdn(), destinationFQDN)
    88  		if err != nil {
    89  			return nil, err
    90  		}
    91  		fs = append(fs, ff)
    92  	}
    93  
    94  	if ff.GetDnsQuery() != nil {
    95  		dnsFilters, err := filterByDNSQueries(ff.GetDnsQuery())
    96  		if err != nil {
    97  			return nil, fmt.Errorf("invalid DNS query filter: %w", err)
    98  		}
    99  		fs = append(fs, dnsFilters)
   100  	}
   101  
   102  	return fs, nil
   103  }