github.com/iDigitalFlame/xmt@v0.5.4/com/wc2/rule.go (about) 1 // Copyright (C) 2020 - 2023 iDigitalFlame 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU General Public License as published by 5 // the Free Software Foundation, either version 3 of the License, or 6 // any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU General Public License for more details. 12 // 13 // You should have received a copy of the GNU General Public License 14 // along with this program. If not, see <https://www.gnu.org/licenses/>. 15 // 16 17 package wc2 18 19 import ( 20 "net/http" 21 22 "github.com/iDigitalFlame/xmt/util/text" 23 ) 24 25 // RuleAny is a Rule that can be used to match any Request that comes in. 26 // 27 // Useful for debugging. 28 var RuleAny = Rule{URL: text.MatchAny, Host: text.MatchAny, Agent: text.MatchAny} 29 30 // Rule is a struct that represents a rule set used by the Web server to determine 31 // the difference between normal and C2 traffic. 32 type Rule struct { 33 URL, Host, Agent Matcher 34 Headers map[string]Matcher 35 } 36 37 // Matcher is a utility interface that takes a single 'MatchString(string) bool' 38 // function and reports true if the string matches. 39 type Matcher interface { 40 MatchString(string) bool 41 } 42 43 func (r Rule) match(c *http.Request) bool { 44 if r.Host == nil && r.URL == nil && r.Agent == nil { 45 return true 46 } 47 if r.Host != nil && !r.Host.MatchString(c.Host) { 48 return false 49 } 50 if r.URL != nil && !r.URL.MatchString(c.URL.EscapedPath()) { 51 return false 52 } 53 if r.Agent != nil && !r.Agent.MatchString(c.UserAgent()) { 54 return false 55 } 56 if r.Headers != nil && len(r.Headers) > 0 { 57 if len(c.Header) == 0 { 58 return false 59 } 60 for k, v := range r.Headers { 61 if h, ok := c.Header[k]; !ok || len(h) == 0 || !v.MatchString(h[0]) { 62 return false 63 } 64 } 65 } 66 return true 67 } 68 69 // Header adds the matcher to the Rule's header set. 70 // 71 // This function will create the headers map if it's nil. 72 func (r *Rule) Header(k string, v Matcher) { 73 if r.Headers == nil { 74 r.Headers = make(map[string]Matcher) 75 } 76 r.Headers[k] = v 77 } 78 func matchAll(r *http.Request, s []Rule) bool { 79 if len(s) == 0 { 80 return true 81 } 82 for i := range s { 83 if s[i].match(r) { 84 return true 85 } 86 } 87 return false 88 }