-
Notifications
You must be signed in to change notification settings - Fork 11
/
rules.go
155 lines (122 loc) · 2.46 KB
/
rules.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package freki
import (
"fmt"
"io"
"net"
"net/url"
"os"
"strconv"
"github.com/google/gopacket/pcap"
yaml "gopkg.in/yaml.v2"
"golang.org/x/net/bpf"
)
type RuleType int
const (
Rewrite RuleType = iota
ProxyTCP
LogTCP
LogHTTP
UserConnHandler
Drop
PassThrough
)
type Config struct {
Version int `yaml:"version"`
Rules []*Rule `yaml:"rules"`
}
type Rule struct {
Match string `yaml:"match"`
Type string `yaml:"type"`
Target string `yaml:"target,omitempty"`
Name string `yaml:"name,omitempty"`
isInit bool
ruleType RuleType
index int
matcher *bpf.VM
targetURL *url.URL
host string
port int
}
func (r *Rule) String() string {
return fmt.Sprintf("Rule: %s", r.Match)
}
func ReadRulesFromFile(file *os.File) ([]*Rule, error) {
data, err := io.ReadAll(file)
if err != nil {
return nil, err
}
return ParseRuleSpec(data)
}
func ParseRuleSpec(spec []byte) ([]*Rule, error) {
config := &Config{}
err := yaml.Unmarshal(spec, config)
if err != nil {
return nil, err
}
if config.Version == 0 {
// TODO: log warning
config.Version = 1
}
if config.Version != 1 {
return nil, fmt.Errorf("unsupported rules version: %v", config.Version)
}
return config.Rules, err
}
func initRule(idx int, rule *Rule, iface *pcap.Handle) error {
if rule.isInit {
return nil
}
switch rule.Type {
case "rewrite":
rule.ruleType = Rewrite
case "proxy":
rule.ruleType = ProxyTCP
case "log_tcp":
rule.ruleType = LogTCP
case "log_http":
rule.ruleType = LogHTTP
case "conn_handler":
rule.ruleType = UserConnHandler
case "drop":
rule.ruleType = Drop
case "passthrough":
rule.ruleType = PassThrough
default:
return fmt.Errorf("unknown rule type: %s", rule.Type)
}
if len(rule.Match) > 0 {
instuctions, err := iface.CompileBPFFilter(rule.Match)
if err != nil {
return err
}
rule.matcher = pcapBPFToXNetBPF(instuctions)
}
if rule.Target != "" {
var err error
if rule.ruleType == ProxyTCP {
rule.targetURL, err = url.Parse(rule.Target)
if err != nil {
return err
}
var sport string
rule.host, sport, err = net.SplitHostPort(rule.targetURL.Host)
if err != nil {
return err
}
rule.port, err = strconv.Atoi(sport)
if err != nil {
return err
}
// TODO: handle scheme specific validation/parsing
}
if rule.ruleType == Rewrite {
rule.port, err = strconv.Atoi(rule.Target)
if err != nil {
return err
}
}
}
rule.index = idx
rule.isInit = true
return nil
}