forked from go-freebsd/pf
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rule_parse.go
135 lines (121 loc) · 3.24 KB
/
rule_parse.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
package pf
import (
"fmt"
"strconv"
"strings"
"text/scanner"
)
// #include <net/if.h>
// #include <net/pfvar.h>
import "C"
// ParseSource sets the source ip (inet and inet6) based on the
// passed strings, if parsing failes err is returned
func (r *Rule) ParseSource(src, port string, neg bool) error {
err := parsePort(&r.wrap.rule.src, port)
if err != nil {
return err
}
err = parseAddress(&r.wrap.rule.src, src, neg)
if err != nil {
return err
}
// determine if it is IPv6 or IPv4
if strings.ContainsRune(src, ':') {
r.SetAddressFamily(AddressFamilyInet6)
} else {
r.SetAddressFamily(AddressFamilyInet)
}
return nil
}
// ParseDestination sets the destination (inet and inet6) based on
// the passed strings, if parsing failes err returned
func (r *Rule) ParseDestination(dst, port string, neg bool) error {
err := parsePort(&r.wrap.rule.dst, port)
if err != nil {
return err
}
return parseAddress(&r.wrap.rule.dst, dst, neg)
}
// parseAddress parses the passed string into the addr structure
func parseAddress(addr *C.struct_pf_rule_addr, address string, negative bool) error {
if negative {
addr.neg = 1
}
a := Address{wrap: &addr.addr}
return a.ParseCIDR(address)
}
// parsePort parses the passed port into the address structure port section
func parsePort(addr *C.struct_pf_rule_addr, port string) error {
s := scanner.Scanner{}
s.Init(strings.NewReader(port))
addr.port_op = C.PF_OP_NONE
var tok rune
curPort := 0
for tok != scanner.EOF {
tok = s.Scan()
switch tok {
case -3:
if curPort >= 2 {
return fmt.Errorf("Unexpected 3rd number in port range: %s",
s.TokenText())
}
val, err := strconv.ParseUint(s.TokenText(), 10, 16)
if err != nil {
return fmt.Errorf("Number not allowed in port range: %s",
s.TokenText())
}
if val < 0 {
return fmt.Errorf("Port number can't be negative: %d", val)
}
addr.port[curPort] = C.u_int16_t(C.htons(C.uint16_t(val)))
curPort++
// if it is the first number and after there is nothing, set none
case ':':
addr.port_op = C.PF_OP_RRG
case '!':
if curPort != 0 {
return fmt.Errorf("Unexpected number before '!'")
}
if s.Peek() == '=' {
s.Next() // consume
addr.port_op = C.PF_OP_NE
} else {
return fmt.Errorf("Expected '=' after '!'")
}
case '<':
if s.Peek() == '>' {
s.Next() // consume
addr.port_op = C.PF_OP_XRG
} else if s.Peek() == '=' {
s.Next() // consume
addr.port_op = C.PF_OP_LE
} else if s.Peek() >= '0' && s.Peek() <= '9' { // int
// next is port number continue
addr.port_op = C.PF_OP_LT
} else {
return fmt.Errorf("Expected port number not '%c'", s.Peek())
}
case '>':
if s.Peek() == '<' {
s.Next() // consume
addr.port_op = C.PF_OP_IRG
} else if s.Peek() == '=' {
s.Next() // consume
addr.port_op = C.PF_OP_GE
} else if s.Peek() >= '0' && s.Peek() <= '9' { // int
// next is port number continue
addr.port_op = C.PF_OP_GT
} else {
return fmt.Errorf("Expected port number not '%c'", s.Peek())
}
case -1:
// if no operation was set
if curPort == 1 && addr.port_op == C.PF_OP_NONE { // one port
addr.port_op = C.PF_OP_EQ
}
default:
return fmt.Errorf("Unexpected char '%c'", s.Peek())
}
}
return nil
}