github.com/fafucoder/cilium@v1.6.11/proxylib/testparsers/headerparser.go (about) 1 // Copyright 2018 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // 16 // Accompanying file `headerparser.policy` contains an example policy 17 // for this protocol. Install it with: 18 // $ cilium policy import proxylib/testparsers/headerparser.policy 19 // 20 21 package testparsers 22 23 import ( 24 "bytes" 25 "fmt" 26 27 . "github.com/cilium/cilium/proxylib/proxylib" 28 29 "github.com/cilium/proxy/go/cilium/api" 30 log "github.com/sirupsen/logrus" 31 ) 32 33 // 34 // Header parser used for testing 35 // 36 37 type HeaderRule struct { 38 hasPrefix []byte 39 contains []byte 40 hasSuffix []byte 41 } 42 43 // Matches returns true if the HeaderRule matches 44 func (rule *HeaderRule) Matches(data interface{}) bool { 45 log.Debugf("headerparser checking rule %v", *rule) 46 47 // Trim whitespace from both ends 48 bs := bytes.TrimSpace(data.([]byte)) 49 50 if len(rule.hasPrefix) > 0 && !bytes.HasPrefix(bs, rule.hasPrefix) { 51 log.Debugf("headerparser HasPrefix %s does not match %s", bs, rule.hasPrefix) 52 return false 53 } 54 55 if len(rule.contains) > 0 && !bytes.Contains(bs, rule.contains) { 56 log.Debugf("headerparser Contains %s does not match %s", bs, rule.contains) 57 return false 58 } 59 60 if len(rule.hasSuffix) > 0 && !bytes.HasSuffix(bs, rule.hasSuffix) { 61 log.Debugf("headerparser HasSuffix %s does not match %s", bs, rule.hasSuffix) 62 return false 63 } 64 log.Debug("headerparser rule matched!") 65 66 return true 67 } 68 69 // L7HeaderRuleParser parses protobuf L7 rules to and array of HeaderRules 70 func L7HeaderRuleParser(rule *cilium.PortNetworkPolicyRule) []L7NetworkPolicyRule { 71 var rules []L7NetworkPolicyRule 72 l7Rules := rule.GetL7Rules() 73 if l7Rules == nil { 74 return rules 75 } 76 for _, l7Rule := range l7Rules.GetL7Rules() { 77 var hr HeaderRule 78 for k, v := range l7Rule.Rule { 79 switch k { 80 case "prefix": 81 hr.hasPrefix = []byte(v) 82 case "contains": 83 hr.contains = []byte(v) 84 case "suffix": 85 hr.hasSuffix = []byte(v) 86 default: 87 ParseError(fmt.Sprintf("Unsupported key: %s", k), rule) 88 } 89 } 90 log.Debugf("Parsed HeaderRule pair: %v", hr) 91 rules = append(rules, &hr) 92 } 93 return rules 94 } 95 96 type HeaderParserFactory struct{} 97 98 var headerParserFactory *HeaderParserFactory 99 100 const ( 101 parserName = "test.headerparser" 102 ) 103 104 func init() { 105 log.Debug("init(): Registering headerParserFactory") 106 RegisterParserFactory(parserName, headerParserFactory) 107 RegisterL7RuleParser(parserName, L7HeaderRuleParser) 108 } 109 110 type HeaderParser struct { 111 connection *Connection 112 } 113 114 func (p *HeaderParserFactory) Create(connection *Connection) Parser { 115 log.Debugf("HeaderParserFactory: Create: %v", connection) 116 return &HeaderParser{connection: connection} 117 } 118 119 // 120 // Parses individual lines and verifies them against the policy 121 // 122 func (p *HeaderParser) OnData(reply, endStream bool, data [][]byte) (OpType, int) { 123 line, ok := getLine(data) 124 line_len := len(line) 125 126 if !reply { 127 log.Debugf("HeaderParser: Request: %s", line) 128 } else { 129 log.Debugf("HeaderParser: Response: %s", line) 130 } 131 132 if !ok { 133 if line_len > 0 { 134 // Partial line received, but no newline, ask for more 135 return MORE, 1 136 } else { 137 // Nothing received, don't know if more will be coming; do nothing 138 return NOP, 0 139 } 140 } 141 142 // Replies pass unconditionally 143 if reply || p.connection.Matches(line) { 144 p.connection.Log(cilium.EntryType_Request, 145 &cilium.LogEntry_GenericL7{ 146 GenericL7: &cilium.L7LogEntry{ 147 Proto: parserName, 148 Fields: map[string]string{ 149 "status": "PASS", 150 }, 151 }, 152 }) 153 return PASS, line_len 154 } 155 156 // Inject Error response to the reverse direction 157 p.connection.Inject(!reply, []byte(fmt.Sprintf("Line dropped: %s", line))) 158 // Drop the line in the current direction 159 p.connection.Log(cilium.EntryType_Denied, 160 &cilium.LogEntry_GenericL7{ 161 GenericL7: &cilium.L7LogEntry{ 162 Proto: parserName, 163 Fields: map[string]string{ 164 "status": "DROP", 165 }, 166 }, 167 }) 168 169 return DROP, line_len 170 }