mirror of
https://github.com/nadoo/glider.git
synced 2025-02-23 17:35:40 +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
|
# custom
|
||||||
*.zip
|
*.zip
|
||||||
*.conf
|
*.conf
|
||||||
|
*.rule
|
||||||
glider
|
glider
|
||||||
doc/
|
doc/
|
||||||
|
15
direct.go
15
direct.go
@ -4,16 +4,19 @@ import "net"
|
|||||||
|
|
||||||
// direct proxy
|
// direct proxy
|
||||||
type direct struct {
|
type direct struct {
|
||||||
Proxy
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Direct proxy
|
// Direct proxy
|
||||||
var Direct = &direct{Proxy: &proxy{addr: "127.0.0.1"}}
|
var Direct = &direct{}
|
||||||
|
|
||||||
// Direct proxy always enabled
|
func (d *direct) Addr() string { return "127.0.0.1" }
|
||||||
func (d *direct) Enabled() bool {
|
func (d *direct) ListenAndServe() { logf("base proxy ListenAndServe") }
|
||||||
return true
|
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) {
|
func (d *direct) Dial(network, addr string) (net.Conn, error) {
|
||||||
c, err := net.Dial(network, addr)
|
c, err := net.Dial(network, addr)
|
||||||
|
@ -94,3 +94,10 @@ checkwebsite=www.apple.com:443
|
|||||||
|
|
||||||
# check duration(seconds)
|
# check duration(seconds)
|
||||||
checkduration=30
|
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
|
CheckDuration int
|
||||||
Listen arrFlags
|
Listen arrFlags
|
||||||
Forward arrFlags
|
Forward arrFlags
|
||||||
|
RuleFile arrFlags
|
||||||
}
|
}
|
||||||
|
|
||||||
var flag = conflag.New()
|
var flag = conflag.New()
|
||||||
@ -125,6 +126,7 @@ func main() {
|
|||||||
flag.IntVar(&conf.CheckDuration, "checkduration", 30, "proxy check duration(seconds)")
|
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.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.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
|
flag.Usage = usage
|
||||||
err := flag.Parse()
|
err := flag.Parse()
|
||||||
@ -139,6 +141,7 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// global forwarders in xx.conf
|
||||||
var forwarders []Proxy
|
var forwarders []Proxy
|
||||||
for _, chain := range conf.Forward {
|
for _, chain := range conf.Forward {
|
||||||
var forward Proxy
|
var forward Proxy
|
||||||
@ -152,7 +155,23 @@ func main() {
|
|||||||
forwarders = append(forwarders, forward)
|
forwarders = append(forwarders, forward)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// combine forwarders to a singer strategy forwarder
|
||||||
forwarder := newStrategyForwarder(conf.Strategy, forwarders)
|
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 {
|
for _, listen := range conf.Listen {
|
||||||
local, err := ProxyFromURL(listen, forwarder)
|
local, err := ProxyFromURL(listen, forwarder)
|
||||||
if err != nil {
|
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.
|
// A Proxy means to establish a connection and relay it.
|
||||||
type Proxy interface {
|
type Proxy interface {
|
||||||
|
// Get address
|
||||||
|
Addr() string
|
||||||
|
|
||||||
// ListenAndServe as proxy server, use only in server mode.
|
// ListenAndServe as proxy server, use only in server mode.
|
||||||
ListenAndServe()
|
ListenAndServe()
|
||||||
|
|
||||||
// Serve as proxy server, use only in server mode.
|
// Serve as proxy server, use only in server mode.
|
||||||
Serve(c net.Conn)
|
Serve(c net.Conn)
|
||||||
|
|
||||||
// Get address
|
|
||||||
Addr() string
|
|
||||||
|
|
||||||
// Get current proxy
|
// Get current proxy
|
||||||
CurrentProxy() Proxy
|
CurrentProxy() Proxy
|
||||||
|
|
||||||
@ -55,6 +55,7 @@ func newProxy(addr string, forward Proxy) *proxy {
|
|||||||
return &proxy{addr: addr, forward: forward, enabled: true}
|
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) ListenAndServe() { logf("base proxy ListenAndServe") }
|
||||||
func (p *proxy) Serve(c net.Conn) { logf("base proxy Serve") }
|
func (p *proxy) Serve(c net.Conn) { logf("base proxy Serve") }
|
||||||
func (p *proxy) CurrentProxy() Proxy { return p.forward }
|
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) NextProxy() Proxy { return p.forward }
|
||||||
func (p *proxy) Enabled() bool { return p.enabled }
|
func (p *proxy) Enabled() bool { return p.enabled }
|
||||||
func (p *proxy) SetEnable(enable bool) { p.enabled = enable }
|
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) {
|
func (p *proxy) Dial(network, addr string) (net.Conn, error) {
|
||||||
return p.forward.Dial(network, addr)
|
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
|
package main
|
||||||
|
|
||||||
import (
|
import "net"
|
||||||
"net"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// newStrategyForwarder .
|
// newStrategyForwarder .
|
||||||
func newStrategyForwarder(strategy string, forwarders []Proxy) Proxy {
|
func newStrategyForwarder(strategy string, forwarders []Proxy) Proxy {
|
||||||
@ -46,6 +43,7 @@ func newRRProxy(addr string, forwarders []Proxy) Proxy {
|
|||||||
return &rrProxy{forwarders: forwarders}
|
return &rrProxy{forwarders: forwarders}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *rrProxy) Addr() string { return "strategy forwarder" }
|
||||||
func (p *rrProxy) ListenAndServe() {}
|
func (p *rrProxy) ListenAndServe() {}
|
||||||
func (p *rrProxy) Serve(c net.Conn) {}
|
func (p *rrProxy) Serve(c net.Conn) {}
|
||||||
func (p *rrProxy) CurrentProxy() Proxy { return p.forwarders[p.idx] }
|
func (p *rrProxy) CurrentProxy() Proxy { return p.forwarders[p.idx] }
|
||||||
@ -73,10 +71,9 @@ func (p *rrProxy) NextProxy() Proxy {
|
|||||||
return p.forwarders[p.idx]
|
return p.forwarders[p.idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *rrProxy) Enabled() bool { return true }
|
func (p *rrProxy) Enabled() bool { return true }
|
||||||
func (p *rrProxy) SetEnable(enable bool) {}
|
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) Dial(network, addr string) (net.Conn, error) {
|
func (p *rrProxy) Dial(network, addr string) (net.Conn, error) {
|
||||||
return p.NextProxy().Dial(network, addr)
|
return p.NextProxy().Dial(network, addr)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user