mirror of
https://github.com/nadoo/glider.git
synced 2025-02-23 01:15:41 +08:00
add proxy rule file support.
This commit is contained in:
parent
bf692de636
commit
4dd429b754
1
.gitignore
vendored
1
.gitignore
vendored
@ -16,5 +16,6 @@
|
||||
# custom
|
||||
*.zip
|
||||
*.conf
|
||||
*.rule
|
||||
glider
|
||||
doc/
|
||||
|
15
direct.go
15
direct.go
@ -4,16 +4,19 @@ import "net"
|
||||
|
||||
// direct proxy
|
||||
type direct struct {
|
||||
Proxy
|
||||
}
|
||||
|
||||
// Direct proxy
|
||||
var Direct = &direct{Proxy: &proxy{addr: "127.0.0.1"}}
|
||||
var Direct = &direct{}
|
||||
|
||||
// Direct proxy always enabled
|
||||
func (d *direct) Enabled() bool {
|
||||
return true
|
||||
}
|
||||
func (d *direct) Addr() string { return "127.0.0.1" }
|
||||
func (d *direct) ListenAndServe() { logf("base proxy ListenAndServe") }
|
||||
func (d *direct) Serve(c net.Conn) { logf("base proxy Serve") }
|
||||
func (d *direct) CurrentProxy() Proxy { return d }
|
||||
func (d *direct) GetProxy(dstAddr string) Proxy { return d }
|
||||
func (d *direct) NextProxy() Proxy { return d }
|
||||
func (d *direct) Enabled() bool { return true }
|
||||
func (d *direct) SetEnable(enable bool) {}
|
||||
|
||||
func (d *direct) Dial(network, addr string) (net.Conn, error) {
|
||||
c, err := net.Dial(network, addr)
|
||||
|
@ -94,3 +94,10 @@ checkwebsite=www.apple.com:443
|
||||
|
||||
# check duration(seconds)
|
||||
checkduration=30
|
||||
|
||||
|
||||
# RULE FILES
|
||||
# ----------
|
||||
# Specify additional forward rules
|
||||
#rulefile=office.rule
|
||||
#rulefile=home.rule
|
||||
|
19
main.go
19
main.go
@ -21,6 +21,7 @@ var conf struct {
|
||||
CheckDuration int
|
||||
Listen arrFlags
|
||||
Forward arrFlags
|
||||
RuleFile arrFlags
|
||||
}
|
||||
|
||||
var flag = conflag.New()
|
||||
@ -125,6 +126,7 @@ func main() {
|
||||
flag.IntVar(&conf.CheckDuration, "checkduration", 30, "proxy check duration(seconds)")
|
||||
flag.Var(&conf.Listen, "listen", "listen url, format: SCHEMA://[USER|METHOD:PASSWORD@][HOST]:PORT")
|
||||
flag.Var(&conf.Forward, "forward", "forward url, format: SCHEMA://[USER|METHOD:PASSWORD@][HOST]:PORT[,SCHEMA://[USER|METHOD:PASSWORD@][HOST]:PORT]")
|
||||
flag.Var(&conf.RuleFile, "rulefile", "rule file path")
|
||||
|
||||
flag.Usage = usage
|
||||
err := flag.Parse()
|
||||
@ -139,6 +141,7 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
// global forwarders in xx.conf
|
||||
var forwarders []Proxy
|
||||
for _, chain := range conf.Forward {
|
||||
var forward Proxy
|
||||
@ -152,7 +155,23 @@ func main() {
|
||||
forwarders = append(forwarders, forward)
|
||||
}
|
||||
|
||||
// combine forwarders to a singer strategy forwarder
|
||||
forwarder := newStrategyForwarder(conf.Strategy, forwarders)
|
||||
|
||||
// rule forwarders
|
||||
var ruleForwarders []*ruleForwarder
|
||||
for _, ruleFile := range conf.RuleFile {
|
||||
ruleForwarder, err := newRuleProxyFromFile(ruleFile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
ruleForwarders = append(ruleForwarders, ruleForwarder)
|
||||
}
|
||||
|
||||
// combine ruleforwarders and global strategy forwarder
|
||||
forwarder = newRulesForwarder(ruleForwarders, forwarder)
|
||||
|
||||
for _, listen := range conf.Listen {
|
||||
local, err := ProxyFromURL(listen, forwarder)
|
||||
if err != nil {
|
||||
|
29
office.rule.example
Normal file
29
office.rule.example
Normal file
@ -0,0 +1,29 @@
|
||||
# Glider rule configuration file.
|
||||
#
|
||||
# Format is the same as glider main config file.
|
||||
# EXCEPTION: Listeners are NOT allowed to setup here.
|
||||
|
||||
# FORWARDERS
|
||||
# ----------
|
||||
# Forwarders, we can setup multiple forwarders.
|
||||
forward=socks5://192.168.1.10:1080
|
||||
forward=ss://method:pass@1.1.1.1:443
|
||||
forward=http://192.168.2.1:8080,socks5://192.168.2.2:1080
|
||||
|
||||
strategy=rr
|
||||
|
||||
checkwebsite=www.apple.com:443
|
||||
checkduration=30
|
||||
|
||||
# DESTINATIONS
|
||||
# ------------
|
||||
# ALL destinations matches the following rules will be forward using forwarders specified above
|
||||
|
||||
# matches abc.com and *.abc.com
|
||||
domain=abc.com
|
||||
|
||||
# matches 1.1.1.1
|
||||
ip=1.1.1.1
|
||||
|
||||
# matches 192.168.100.0/24
|
||||
cidr=192.168.100.0/24
|
8
proxy.go
8
proxy.go
@ -11,15 +11,15 @@ import (
|
||||
|
||||
// A Proxy means to establish a connection and relay it.
|
||||
type Proxy interface {
|
||||
// Get address
|
||||
Addr() string
|
||||
|
||||
// ListenAndServe as proxy server, use only in server mode.
|
||||
ListenAndServe()
|
||||
|
||||
// Serve as proxy server, use only in server mode.
|
||||
Serve(c net.Conn)
|
||||
|
||||
// Get address
|
||||
Addr() string
|
||||
|
||||
// Get current proxy
|
||||
CurrentProxy() Proxy
|
||||
|
||||
@ -55,6 +55,7 @@ func newProxy(addr string, forward Proxy) *proxy {
|
||||
return &proxy{addr: addr, forward: forward, enabled: true}
|
||||
}
|
||||
|
||||
func (p *proxy) Addr() string { return p.addr }
|
||||
func (p *proxy) ListenAndServe() { logf("base proxy ListenAndServe") }
|
||||
func (p *proxy) Serve(c net.Conn) { logf("base proxy Serve") }
|
||||
func (p *proxy) CurrentProxy() Proxy { return p.forward }
|
||||
@ -62,7 +63,6 @@ func (p *proxy) GetProxy(dstAddr string) Proxy { return p.forward }
|
||||
func (p *proxy) NextProxy() Proxy { return p.forward }
|
||||
func (p *proxy) Enabled() bool { return p.enabled }
|
||||
func (p *proxy) SetEnable(enable bool) { p.enabled = enable }
|
||||
func (p *proxy) Addr() string { return p.addr }
|
||||
|
||||
func (p *proxy) Dial(network, addr string) (net.Conn, error) {
|
||||
return p.forward.Dial(network, addr)
|
||||
|
91
rule.go
Normal file
91
rule.go
Normal file
@ -0,0 +1,91 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/nadoo/conflag"
|
||||
)
|
||||
|
||||
// ruleForwarder, every ruleForwarder points to a rule file
|
||||
type ruleForwarder struct {
|
||||
Forward arrFlags
|
||||
Strategy string
|
||||
CheckWebSite string
|
||||
CheckDuration int
|
||||
|
||||
Domain arrFlags
|
||||
IP arrFlags
|
||||
CIDR arrFlags
|
||||
|
||||
name string
|
||||
sForwarder Proxy
|
||||
}
|
||||
|
||||
// newRuleProxyFromFile .
|
||||
func newRuleProxyFromFile(ruleFile string) (*ruleForwarder, error) {
|
||||
p := &ruleForwarder{name: ruleFile}
|
||||
|
||||
f := conflag.NewFromFile("rule", ruleFile)
|
||||
f.Var(&p.Forward, "forward", "forward url, format: SCHEMA://[USER|METHOD:PASSWORD@][HOST]:PORT[,SCHEMA://[USER|METHOD:PASSWORD@][HOST]:PORT]")
|
||||
f.StringVar(&p.Strategy, "strategy", "rr", "forward strategy, default: rr")
|
||||
f.StringVar(&p.CheckWebSite, "checkwebsite", "www.apple.com:443", "proxy check website address")
|
||||
f.IntVar(&p.CheckDuration, "checkduration", 30, "proxy check duration(seconds)")
|
||||
|
||||
f.Var(&p.Domain, "domain", "domain")
|
||||
f.Var(&p.IP, "ip", "ip")
|
||||
f.Var(&p.CIDR, "cidr", "cidr")
|
||||
|
||||
err := f.Parse()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "ERROR: %s\n", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var forwarders []Proxy
|
||||
for _, chain := range p.Forward {
|
||||
var forward Proxy
|
||||
var err error
|
||||
for _, url := range strings.Split(chain, ",") {
|
||||
forward, err = ProxyFromURL(url, forward)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
forwarders = append(forwarders, forward)
|
||||
}
|
||||
|
||||
forwarder := newStrategyForwarder(p.Strategy, forwarders)
|
||||
|
||||
for _, forward := range forwarders {
|
||||
go check(forward, p.CheckWebSite, p.CheckDuration)
|
||||
}
|
||||
|
||||
p.sForwarder = forwarder
|
||||
|
||||
return p, err
|
||||
}
|
||||
|
||||
func (p *ruleForwarder) Addr() string { return "rule forwarder" }
|
||||
func (p *ruleForwarder) ListenAndServe() {}
|
||||
func (p *ruleForwarder) Serve(c net.Conn) {}
|
||||
func (p *ruleForwarder) CurrentProxy() Proxy { return p.sForwarder.CurrentProxy() }
|
||||
|
||||
func (p *ruleForwarder) GetProxy(dstAddr string) Proxy {
|
||||
|
||||
return p.sForwarder.NextProxy()
|
||||
}
|
||||
|
||||
func (p *ruleForwarder) NextProxy() Proxy {
|
||||
return p.sForwarder.NextProxy()
|
||||
}
|
||||
|
||||
func (p *ruleForwarder) Enabled() bool { return true }
|
||||
func (p *ruleForwarder) SetEnable(enable bool) {}
|
||||
|
||||
func (p *ruleForwarder) Dial(network, addr string) (net.Conn, error) {
|
||||
return p.NextProxy().Dial(network, addr)
|
||||
}
|
89
rules.go
Normal file
89
rules.go
Normal file
@ -0,0 +1,89 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type rulesForwarder struct {
|
||||
globalForwarder Proxy
|
||||
|
||||
domainMap map[string]Proxy
|
||||
ipMap map[string]Proxy
|
||||
cidrMap map[string]Proxy
|
||||
}
|
||||
|
||||
// newRulesForwarder .
|
||||
func newRulesForwarder(ruleForwarders []*ruleForwarder, globalForwarder Proxy) Proxy {
|
||||
p := &rulesForwarder{globalForwarder: globalForwarder}
|
||||
|
||||
for _, f := range ruleForwarders {
|
||||
p.domainMap = make(map[string]Proxy)
|
||||
for _, domain := range f.Domain {
|
||||
p.domainMap[domain] = f.sForwarder
|
||||
}
|
||||
|
||||
p.ipMap = make(map[string]Proxy)
|
||||
for _, ip := range f.IP {
|
||||
p.ipMap[ip] = f.sForwarder
|
||||
}
|
||||
|
||||
p.cidrMap = make(map[string]Proxy)
|
||||
for _, cidr := range f.CIDR {
|
||||
p.cidrMap[cidr] = f.sForwarder
|
||||
}
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *rulesForwarder) Addr() string { return "rule forwarder" }
|
||||
func (p *rulesForwarder) ListenAndServe() {}
|
||||
func (p *rulesForwarder) Serve(c net.Conn) {}
|
||||
func (p *rulesForwarder) CurrentProxy() Proxy { return p.globalForwarder.CurrentProxy() }
|
||||
|
||||
func (p *rulesForwarder) GetProxy(dstAddr string) Proxy {
|
||||
|
||||
logf("dstAddr: %s", dstAddr)
|
||||
|
||||
host, _, err := net.SplitHostPort(dstAddr)
|
||||
if err != nil {
|
||||
// TODO: check here
|
||||
logf("%s", err)
|
||||
return p.globalForwarder.GetProxy(dstAddr)
|
||||
}
|
||||
|
||||
// find ip
|
||||
if ip := net.ParseIP(host); ip != nil {
|
||||
// check cidr
|
||||
|
||||
// check ip
|
||||
if p, ok := p.ipMap[ip.String()]; ok {
|
||||
return p
|
||||
}
|
||||
}
|
||||
|
||||
domainParts := strings.Split(host, ".")
|
||||
length := len(domainParts)
|
||||
for i := length - 2; i >= 0; i-- {
|
||||
domain := strings.Join(domainParts[i:length], ".")
|
||||
|
||||
// find in domainMap
|
||||
if p, ok := p.domainMap[domain]; ok {
|
||||
return p
|
||||
}
|
||||
}
|
||||
|
||||
return p.globalForwarder.GetProxy(dstAddr)
|
||||
}
|
||||
|
||||
func (p *rulesForwarder) NextProxy() Proxy {
|
||||
return p.globalForwarder.NextProxy()
|
||||
}
|
||||
|
||||
func (p *rulesForwarder) Enabled() bool { return true }
|
||||
func (p *rulesForwarder) SetEnable(enable bool) {}
|
||||
|
||||
func (p *rulesForwarder) Dial(network, addr string) (net.Conn, error) {
|
||||
return p.GetProxy(addr).Dial(network, addr)
|
||||
}
|
13
strategy.go
13
strategy.go
@ -1,9 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
import "net"
|
||||
|
||||
// newStrategyForwarder .
|
||||
func newStrategyForwarder(strategy string, forwarders []Proxy) Proxy {
|
||||
@ -46,6 +43,7 @@ func newRRProxy(addr string, forwarders []Proxy) Proxy {
|
||||
return &rrProxy{forwarders: forwarders}
|
||||
}
|
||||
|
||||
func (p *rrProxy) Addr() string { return "strategy forwarder" }
|
||||
func (p *rrProxy) ListenAndServe() {}
|
||||
func (p *rrProxy) Serve(c net.Conn) {}
|
||||
func (p *rrProxy) CurrentProxy() Proxy { return p.forwarders[p.idx] }
|
||||
@ -73,10 +71,9 @@ func (p *rrProxy) NextProxy() Proxy {
|
||||
return p.forwarders[p.idx]
|
||||
}
|
||||
|
||||
func (p *rrProxy) Enabled() bool { return true }
|
||||
func (p *rrProxy) SetEnable(enable bool) {}
|
||||
func (p *rrProxy) Check(proxy Proxy, target string, duration time.Duration) {}
|
||||
func (p *rrProxy) Addr() string { return "" }
|
||||
func (p *rrProxy) Enabled() bool { return true }
|
||||
func (p *rrProxy) SetEnable(enable bool) {}
|
||||
|
||||
func (p *rrProxy) Dial(network, addr string) (net.Conn, error) {
|
||||
return p.NextProxy().Dial(network, addr)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user