-
Notifications
You must be signed in to change notification settings - Fork 23
/
config.go
138 lines (121 loc) · 3 KB
/
config.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
package usocksd
import (
"errors"
"net"
"strings"
"github.com/BurntSushi/toml"
"github.com/cybozu-go/well"
)
const (
defaultPort = 1080
defaultMetricsPort = 1081
)
// IncomingConfig is a set of configurations to accept clients.
type IncomingConfig struct {
Port int
MetricsPort int `toml:"metrics_port"`
Addresses []net.IP
AllowFrom []string `toml:"allow_from"`
allowSubnets []*net.IPNet
}
// OutgoingConfig is a set of configurations to connect to destinations.
type OutgoingConfig struct {
AllowSites []string `toml:"allow_sites"`
DenySites []string `toml:"deny_sites"`
DenyPorts []int `toml:"deny_ports"`
IFace string `toml:"iface"`
Addresses []net.IP
DNSBLDomain string `toml:"dnsbl_domain"`
}
// Config is a struct tagged for TOML for usocksd.
type Config struct {
Log well.LogConfig `toml:"log"`
Incoming IncomingConfig `toml:"incoming"`
Outgoing OutgoingConfig `toml:"outgoing"`
}
// NewConfig creates and initializes Config.
func NewConfig() *Config {
c := new(Config)
c.Incoming.Port = defaultPort
c.Incoming.MetricsPort = defaultMetricsPort
return c
}
// Load loads a TOML file from path.
func (c *Config) Load(path string) error {
md, err := toml.DecodeFile(path, c)
if err != nil {
return err
}
if len(md.Undecoded()) > 0 {
return errors.New("Unknown config keys in " + path)
}
if len(c.Incoming.AllowFrom) > 0 {
subnets := make([]*net.IPNet, 0, len(c.Incoming.AllowFrom))
for _, s := range c.Incoming.AllowFrom {
if strings.IndexByte(s, '/') == -1 {
s = s + "/32"
}
_, n, err := net.ParseCIDR(s)
if err != nil {
return errors.New("Invalid network or IP address: " + s)
}
subnets = append(subnets, n)
}
c.Incoming.allowSubnets = subnets
}
c.Outgoing.AllowSites = toLowerStrings(c.Outgoing.AllowSites)
c.Outgoing.DenySites = toLowerStrings(c.Outgoing.DenySites)
return nil
}
func toLowerStrings(l []string) (nl []string) {
for _, s := range l {
nl = append(nl, strings.ToLower(s))
}
return
}
// allowIP tests if ip is allowed to connect to usocksd.
func (c *Config) allowIP(ip net.IP) bool {
if len(c.Incoming.allowSubnets) == 0 {
return true
}
for _, n := range c.Incoming.allowSubnets {
if n.Contains(ip) {
return true
}
}
return false
}
func siteMatch(site, match string) bool {
if len(match) > 0 && match[0] == '.' {
return strings.HasSuffix(site, match)
}
return site == match
}
// allowFQDN tests if FQDN is granted to access or not.
func (c *Config) allowFQDN(fqdn string) bool {
fqdn = strings.ToLower(fqdn)
if len(c.Outgoing.AllowSites) > 0 {
for _, match := range c.Outgoing.AllowSites {
if siteMatch(fqdn, match) {
goto CHECK_DENY
}
}
return false
}
CHECK_DENY:
for _, match := range c.Outgoing.DenySites {
if siteMatch(fqdn, match) {
return false
}
}
return true
}
// allowPort tests if port is legitimate for destination.
func (c *Config) allowPort(port int) bool {
for _, p := range c.Outgoing.DenyPorts {
if p == port {
return false
}
}
return true
}