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

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Hubble
     3  
     4  package filters
     5  
     6  import (
     7  	"context"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  
    12  	flowpb "github.com/cilium/cilium/api/v1/flow"
    13  	v1 "github.com/cilium/cilium/pkg/hubble/api/v1"
    14  )
    15  
    16  func TestFQDNFilter(t *testing.T) {
    17  	type args struct {
    18  		f  []*flowpb.FlowFilter
    19  		ev []*v1.Event
    20  	}
    21  	tests := []struct {
    22  		name    string
    23  		args    args
    24  		wantErr bool
    25  		want    []bool
    26  	}{
    27  		{
    28  			name: "source fqdn",
    29  			args: args{
    30  				f: []*flowpb.FlowFilter{
    31  					{SourceFqdn: []string{"cilium.io", "ebpf.io"}},
    32  				},
    33  				ev: []*v1.Event{
    34  					{Event: &flowpb.Flow{SourceNames: []string{"cilium.io"}}},
    35  					{Event: &flowpb.Flow{SourceNames: []string{"ebpf.io"}}},
    36  					{Event: &flowpb.Flow{DestinationNames: []string{"cilium.io"}}},
    37  					{Event: &flowpb.Flow{DestinationNames: []string{"ebpf.io"}}},
    38  				},
    39  			},
    40  			want: []bool{
    41  				true,
    42  				true,
    43  				false,
    44  				false,
    45  			},
    46  		},
    47  		{
    48  			name: "destination fqdn",
    49  			args: args{
    50  				f: []*flowpb.FlowFilter{
    51  					{DestinationFqdn: []string{"cilium.io", "ebpf.io"}},
    52  				},
    53  				ev: []*v1.Event{
    54  					{Event: &flowpb.Flow{SourceNames: []string{"cilium.io"}}},
    55  					{Event: &flowpb.Flow{SourceNames: []string{"ebpf.io"}}},
    56  					{Event: &flowpb.Flow{DestinationNames: []string{"cilium.io"}}},
    57  					{Event: &flowpb.Flow{DestinationNames: []string{"ebpf.io"}}},
    58  				},
    59  			},
    60  			want: []bool{
    61  				false,
    62  				false,
    63  				true,
    64  				true,
    65  			},
    66  		},
    67  		{
    68  			name: "source and destination fqdn",
    69  			args: args{
    70  				f: []*flowpb.FlowFilter{
    71  					{
    72  						SourceFqdn:      []string{"cilium.io", "docs.cilium.io"},
    73  						DestinationFqdn: []string{"ebpf.io"},
    74  					},
    75  				},
    76  				ev: []*v1.Event{
    77  					{Event: &flowpb.Flow{
    78  						SourceNames:      []string{"cilium.io"},
    79  						DestinationNames: []string{"ebpf.io"},
    80  					}},
    81  					{Event: &flowpb.Flow{
    82  						SourceNames:      []string{"ebpf.io"},
    83  						DestinationNames: []string{"cilium.io"},
    84  					}},
    85  					{Event: &flowpb.Flow{
    86  						SourceNames:      []string{"deathstar.empire.svc.cluster.local", "docs.cilium.io"},
    87  						DestinationNames: []string{"ebpf.io"},
    88  					}},
    89  				},
    90  			},
    91  			want: []bool{
    92  				true,
    93  				false,
    94  				true,
    95  			},
    96  		},
    97  		{
    98  			name: "source or destination fqdn",
    99  			args: args{
   100  				f: []*flowpb.FlowFilter{
   101  					{SourceFqdn: []string{"cilium.io", "docs.cilium.io"}},
   102  					{DestinationFqdn: []string{"ebpf.io"}},
   103  				},
   104  				ev: []*v1.Event{
   105  					{Event: &flowpb.Flow{
   106  						SourceNames:      []string{"cilium.io"},
   107  						DestinationNames: []string{"ebpf.io"},
   108  					}},
   109  					{Event: &flowpb.Flow{
   110  						SourceNames:      []string{"ebpf.io"},
   111  						DestinationNames: []string{"cilium.io"},
   112  					}},
   113  					{Event: &flowpb.Flow{
   114  						SourceNames: []string{"deathstar.empire.svc.cluster.local", "docs.cilium.io"},
   115  					}},
   116  					{Event: &flowpb.Flow{
   117  						DestinationNames: []string{"ebpf.io"},
   118  					}},
   119  					{Event: &flowpb.Flow{
   120  						SourceNames:      []string{"deathstar.empire.svc.cluster.local", "docs.cilium.io"},
   121  						DestinationNames: []string{"ebpf.io"},
   122  					}},
   123  				},
   124  			},
   125  			want: []bool{
   126  				true,
   127  				false,
   128  				true,
   129  				true,
   130  				true,
   131  			},
   132  		},
   133  		{
   134  			name: "invalid data",
   135  			args: args{
   136  				f: []*flowpb.FlowFilter{
   137  					{SourceFqdn: []string{"cilium.io."}},
   138  				},
   139  				ev: []*v1.Event{
   140  					nil,
   141  					{},
   142  					{Event: &flowpb.Flow{}},
   143  					{Event: &flowpb.Flow{SourceNames: []string{"cilium.io."}}}, // should not have trailing dot
   144  					{Event: &flowpb.Flow{SourceNames: []string{"www.cilium.io"}}},
   145  					{Event: &flowpb.Flow{SourceNames: []string{""}}},
   146  				},
   147  			},
   148  			want: []bool{
   149  				false,
   150  				false,
   151  				false,
   152  				false,
   153  				false,
   154  				false,
   155  			},
   156  		},
   157  		{
   158  			name: "invalid source fqdn filter",
   159  			args: args{
   160  				f: []*flowpb.FlowFilter{
   161  					{SourceFqdn: []string{""}},
   162  				},
   163  			},
   164  			wantErr: true,
   165  		},
   166  		{
   167  			name: "invalid destination fqdn filter",
   168  			args: args{
   169  				f: []*flowpb.FlowFilter{
   170  					{DestinationFqdn: []string{"."}},
   171  				},
   172  			},
   173  			wantErr: true,
   174  		},
   175  		{
   176  			name: "wildcard filters",
   177  			args: args{
   178  				f: []*flowpb.FlowFilter{
   179  					{SourceFqdn: []string{"*.cilium.io", "*.org."}},
   180  					{DestinationFqdn: []string{"*"}},
   181  				},
   182  				ev: []*v1.Event{
   183  					{Event: &flowpb.Flow{SourceNames: []string{"www.cilium.io"}}},
   184  					{Event: &flowpb.Flow{SourceNames: []string{"multiple.domains.org"}}},
   185  					{Event: &flowpb.Flow{SourceNames: []string{"cilium.io"}}},
   186  					{Event: &flowpb.Flow{SourceNames: []string{"tiefighter", "empire.org"}}},
   187  					{Event: &flowpb.Flow{DestinationNames: []string{}}},
   188  					{Event: &flowpb.Flow{DestinationNames: []string{"anything.really"}}},
   189  					{Event: &flowpb.Flow{DestinationNames: []string{""}}},
   190  				},
   191  			},
   192  			want: []bool{
   193  				true,
   194  				true,
   195  				false,
   196  				true,
   197  				false,
   198  				true,
   199  				true,
   200  			},
   201  		},
   202  	}
   203  	for _, tt := range tests {
   204  		t.Run(tt.name, func(t *testing.T) {
   205  			fl, err := BuildFilterList(context.Background(), tt.args.f, []OnBuildFilter{&FQDNFilter{}})
   206  			if (err != nil) != tt.wantErr {
   207  				t.Errorf("BuildFilterList() with FQDNFilter: error = %v, wantErr %v", err, tt.wantErr)
   208  				return
   209  			}
   210  			for i, ev := range tt.args.ev {
   211  				if filterResult := fl.MatchOne(ev); filterResult != tt.want[i] {
   212  					t.Errorf("\"%s\" filterResult %d = %v, want %v", tt.name, i, filterResult, tt.want[i])
   213  				}
   214  			}
   215  		})
   216  	}
   217  }
   218  
   219  func Test_filterByDNSQuery(t *testing.T) {
   220  	type args struct {
   221  		f  []*flowpb.FlowFilter
   222  		ev *v1.Event
   223  	}
   224  	tests := []struct {
   225  		name    string
   226  		args    args
   227  		wantErr bool
   228  		want    bool
   229  	}{
   230  		{
   231  			name: "not-dns",
   232  			args: args{
   233  				f:  []*flowpb.FlowFilter{{DnsQuery: []string{".*"}}},
   234  				ev: &v1.Event{Event: &flowpb.Flow{}},
   235  			},
   236  			wantErr: false,
   237  			want:    false,
   238  		},
   239  		{
   240  			name: "invalid-regex",
   241  			args: args{
   242  				f: []*flowpb.FlowFilter{{DnsQuery: []string{"*"}}},
   243  			},
   244  			wantErr: true,
   245  		},
   246  		{
   247  			name: "positive",
   248  			args: args{
   249  				f: []*flowpb.FlowFilter{{DnsQuery: []string{".*\\.com$", ".*\\.io"}}},
   250  				ev: &v1.Event{Event: &flowpb.Flow{
   251  					L7: &flowpb.Layer7{
   252  						Record: &flowpb.Layer7_Dns{
   253  							Dns: &flowpb.DNS{
   254  								Query: "cilium.io",
   255  							},
   256  						},
   257  					},
   258  				}},
   259  			},
   260  			want: true,
   261  		},
   262  		{
   263  			name: "positive",
   264  			args: args{
   265  				f: []*flowpb.FlowFilter{{DnsQuery: []string{".*\\.com$", ".*\\.io"}}},
   266  				ev: &v1.Event{Event: &flowpb.Flow{
   267  					L7: &flowpb.Layer7{
   268  						Record: &flowpb.Layer7_Dns{
   269  							Dns: &flowpb.DNS{
   270  								Query: "cilium.io",
   271  							},
   272  						},
   273  					},
   274  				}},
   275  			},
   276  			wantErr: false,
   277  			want:    true,
   278  		},
   279  		{
   280  			name: "negative",
   281  			args: args{
   282  				f: []*flowpb.FlowFilter{{DnsQuery: []string{".*\\.com$", ".*\\.net"}}},
   283  				ev: &v1.Event{Event: &flowpb.Flow{
   284  					L7: &flowpb.Layer7{
   285  						Record: &flowpb.Layer7_Dns{
   286  							Dns: &flowpb.DNS{
   287  								Query: "cilium.io",
   288  							},
   289  						},
   290  					},
   291  				}},
   292  			},
   293  			wantErr: false,
   294  			want:    false,
   295  		},
   296  	}
   297  	for _, tt := range tests {
   298  		t.Run(tt.name, func(t *testing.T) {
   299  			fl, err := BuildFilterList(context.Background(), tt.args.f, []OnBuildFilter{&FQDNFilter{}})
   300  			assert.Equal(t, tt.wantErr, err != nil)
   301  			if err == nil {
   302  				got := fl.MatchOne(tt.args.ev)
   303  				assert.Equal(t, tt.want, got)
   304  			}
   305  		})
   306  	}
   307  }