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 }