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  }