github.com/cilium/cilium@v1.16.2/pkg/hubble/filters/patterns.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Hubble 3 4 package filters 5 6 import ( 7 "errors" 8 "fmt" 9 "regexp" 10 "strings" 11 ) 12 13 var ( 14 // fqdnRegexpStr matches an FQDN, inluding underscores. 15 // FIXME this should not match components that begin or end with hyphens, e.g. -foo- 16 fqdnRegexpStr = `(?:[-0-9_a-z]+(?:\.[-0-9_a-z]+)*)` 17 _ = regexp.MustCompile(fqdnRegexpStr) // compile regexp to ensure that it is valid 18 19 errEmptyPattern = errors.New("empty pattern") 20 errMultipleTrailingDotsInPattern = errors.New("multiple trailing dots in pattern") 21 errTooManySlashesInPattern = errors.New("too many slashes in pattern") 22 ) 23 24 // canonicalizeFQDNPattern canonicalizes fqdnPattern by trimming space, trimming 25 // up to one trailing dot, and converting it to lowercase. 26 func canonicalizeFQDNPattern(fqdnPattern string) string { 27 fqdnPattern = strings.TrimSpace(fqdnPattern) 28 fqdnPattern = strings.TrimSuffix(fqdnPattern, ".") 29 fqdnPattern = strings.ToLower(fqdnPattern) 30 return fqdnPattern 31 } 32 33 // appendFQDNPatternRegexp appends the regular expression equivalent to 34 // fqdnPattern to sb. 35 func appendFQDNPatternRegexp(sb *strings.Builder, fqdnPattern string) error { 36 fqdnPattern = canonicalizeFQDNPattern(fqdnPattern) 37 switch { 38 case fqdnPattern == "": 39 return errEmptyPattern 40 case strings.HasSuffix(fqdnPattern, "."): 41 return errMultipleTrailingDotsInPattern 42 } 43 for _, r := range fqdnPattern { 44 switch { 45 case r == '.': 46 sb.WriteString(`\.`) 47 case r == '*': 48 sb.WriteString(`[-.0-9a-z]*`) 49 case r == '-': 50 fallthrough 51 case '0' <= r && r <= '9': 52 fallthrough 53 case r == '_': 54 fallthrough 55 case 'a' <= r && r <= 'z': 56 sb.WriteRune(r) 57 default: 58 return fmt.Errorf("%q: invalid rune in pattern", r) 59 } 60 } 61 return nil 62 } 63 64 // appendNodeNamePatternRegexp appends the regular expression equivalent to 65 // nodeNamePattern to sb. The returned regular expression matches node names 66 // that include a cluster name. 67 // 68 // Node name patterns consist of a cluster pattern element and a node pattern 69 // element separated by a forward slash. Each element is an FQDN pattern, with 70 // an empty pattern matching everything. If there is no forward slash then the 71 // pattern is treated as a node pattern and matches all clusters. 72 func appendNodeNamePatternRegexp(sb *strings.Builder, nodeNamePattern string) error { 73 if nodeNamePattern == "" { 74 return errEmptyPattern 75 } 76 clusterPattern := "" 77 nodePattern := "" 78 elems := strings.Split(nodeNamePattern, "/") 79 switch len(elems) { 80 case 1: 81 nodePattern = elems[0] 82 case 2: 83 clusterPattern = elems[0] 84 nodePattern = elems[1] 85 default: 86 return errTooManySlashesInPattern 87 } 88 89 if clusterPattern == "" { 90 sb.WriteString(fqdnRegexpStr) 91 } else if err := appendFQDNPatternRegexp(sb, clusterPattern); err != nil { 92 return err 93 } 94 sb.WriteByte('/') 95 if nodePattern == "" { 96 sb.WriteString(fqdnRegexpStr) 97 } else if err := appendFQDNPatternRegexp(sb, nodePattern); err != nil { 98 return err 99 } 100 return nil 101 } 102 103 // compileFQDNPattern returns a regular expression equivalent to the FQDN 104 // patterns in fqdnPatterns. 105 func compileFQDNPattern(fqdnPatterns []string) (*regexp.Regexp, error) { 106 var sb strings.Builder 107 sb.WriteString(`\A(?:`) 108 for i, fqdnPattern := range fqdnPatterns { 109 if i > 0 { 110 sb.WriteByte('|') 111 } 112 if err := appendFQDNPatternRegexp(&sb, fqdnPattern); err != nil { 113 return nil, err 114 } 115 } 116 sb.WriteString(`)\z`) 117 return regexp.Compile(sb.String()) 118 } 119 120 // compileNodeNamePattern returns a regular expression equivalent to the node 121 // name patterns in nodeNamePatterns. 122 func compileNodeNamePattern(nodeNamePatterns []string) (*regexp.Regexp, error) { 123 sb := strings.Builder{} 124 sb.WriteString(`\A(?:`) 125 for i, nodeNamePattern := range nodeNamePatterns { 126 if i > 0 { 127 sb.WriteByte('|') 128 } 129 if err := appendNodeNamePatternRegexp(&sb, nodeNamePattern); err != nil { 130 return nil, err 131 } 132 } 133 sb.WriteString(`)\z`) 134 return regexp.Compile(sb.String()) 135 }