mirror of
https://github.com/wweir/sower.git
synced 2024-04-21 12:42:15 +00:00
support config reference
This commit is contained in:
+60
-13
@@ -1,27 +1,36 @@
|
||||
package conf
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
toml "github.com/pelletier/go-toml"
|
||||
"github.com/wweir/sower/util"
|
||||
"github.com/wweir/utils/log"
|
||||
"github.com/wweir/util-go/log"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
Address string `toml:"address"`
|
||||
HTTPProxy string `toml:"http_proxy"`
|
||||
DNSServeIP string `toml:"dns_serve_ip"`
|
||||
DNSUpstream string `toml:"dns_upstream"`
|
||||
Socks5Proxy string `toml:"socks5"`
|
||||
HTTPProxy string `toml:"http_proxy"`
|
||||
PortForward map[string]string `toml:"port_forward"`
|
||||
|
||||
Router struct {
|
||||
DetectLevel int `toml:"detect_level"`
|
||||
ProxyList []string `toml:"proxy_list"`
|
||||
ProxyRefs []string `toml:"proxy_refs"`
|
||||
DirectList []string `toml:"direct_list"`
|
||||
DirectRefs []string `toml:"direct_refs"`
|
||||
BlockList []string `toml:"block_list"`
|
||||
BlockRefs []string `toml:"block_refs"`
|
||||
} `toml:"router"`
|
||||
}
|
||||
type Server struct {
|
||||
@@ -59,7 +68,7 @@ func Init() (*Client, *Server, string) {
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
defer log.Infow("starting", "config", &conf)
|
||||
defer log.Infow("starting", "version", version, "date", date, "config", &conf)
|
||||
if conf.file == "" {
|
||||
return &conf.Client, &conf.Server, conf.Password
|
||||
}
|
||||
@@ -76,16 +85,61 @@ func Init() (*Client, *Server, string) {
|
||||
var loadConfigFns = []struct {
|
||||
step string
|
||||
fn func() error
|
||||
}{{"load_config", func() error {
|
||||
}{{"parse file", func() error {
|
||||
f, err := os.OpenFile(conf.file, os.O_RDONLY, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
return xerrors.New(err.Error())
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
return toml.NewDecoder(f).Decode(&conf)
|
||||
}}, {"load referenced rule", func() error {
|
||||
for _, addr := range conf.Client.Router.BlockRefs {
|
||||
lines, err := getRemoteRuleLines(addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conf.Client.Router.BlockList = append(conf.Client.Router.BlockList, lines...)
|
||||
}
|
||||
for _, addr := range conf.Client.Router.ProxyRefs {
|
||||
lines, err := getRemoteRuleLines(addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conf.Client.Router.ProxyList = append(conf.Client.Router.ProxyList, lines...)
|
||||
}
|
||||
for _, addr := range conf.Client.Router.DirectRefs {
|
||||
lines, err := getRemoteRuleLines(addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conf.Client.Router.DirectList = append(conf.Client.Router.DirectList, lines...)
|
||||
}
|
||||
|
||||
return nil
|
||||
}}}
|
||||
|
||||
func getRemoteRuleLines(addr string) ([]string, error) {
|
||||
resp, err := http.Get(addr)
|
||||
if err != nil {
|
||||
return nil, xerrors.New(err.Error())
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
br := bufio.NewReader(resp.Body)
|
||||
lines := []string{}
|
||||
for {
|
||||
line, _, err := br.ReadLine()
|
||||
if err == io.EOF {
|
||||
return lines, nil
|
||||
} else if err != nil {
|
||||
return nil, xerrors.New(err.Error())
|
||||
}
|
||||
|
||||
lines = append(lines, "**."+strings.TrimSpace(string(line)))
|
||||
}
|
||||
}
|
||||
|
||||
// flushCh to avoid parallel persist
|
||||
var flushCh = make(chan struct{})
|
||||
var flushOnce = sync.Once{}
|
||||
@@ -138,12 +192,5 @@ func flushConfDaemon() {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// reload config
|
||||
for i := range loadConfigFns {
|
||||
if err := loadConfigFns[i].fn(); err != nil {
|
||||
log.Errorw("flush config", "step", loadConfigFns[i].step, "err", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ import (
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/wweir/utils/log"
|
||||
"github.com/wweir/util-go/log"
|
||||
)
|
||||
|
||||
const svcPath = "/Library/LaunchDaemons/sower.plist"
|
||||
|
||||
+1
-8
@@ -12,7 +12,7 @@ import (
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/wweir/utils/log"
|
||||
"github.com/wweir/util-go/log"
|
||||
)
|
||||
|
||||
const svcPath = "/etc/systemd/system/sower.service"
|
||||
@@ -66,13 +66,6 @@ func afterInitFlag() {
|
||||
case uninstallFlag:
|
||||
uninstall()
|
||||
default:
|
||||
if conf.Client.DNSServeIP != "" {
|
||||
log.Infow("setting system DNS", "DNS", conf.Client.DNSServeIP)
|
||||
if err := execute(fmt.Sprintf("grep '%s' || sed -i '1inameserver %s' /etc/resolv.conf",
|
||||
conf.Client.DNSServeIP, conf.Client.DNSServeIP)); err != nil {
|
||||
log.Errorf("set DNS fail, please set DNS to %s manually", conf.Client.DNSServeIP)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
os.Exit(0)
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/wweir/utils/log"
|
||||
"github.com/wweir/util-go/log"
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.org/x/sys/windows/svc"
|
||||
"golang.org/x/sys/windows/svc/eventlog"
|
||||
|
||||
+59
-48
@@ -1,54 +1,65 @@
|
||||
password="" # sower password
|
||||
password = "" # sower password
|
||||
|
||||
[client]
|
||||
address = "" # aa.bb.cc, socks5h://127.0.0.1:1080
|
||||
http_proxy=":8080"
|
||||
dns_serve_ip="" # eg: 127.0.0.1. keep empty to disable DNS solution
|
||||
dns_upstream="" # keep empty to set via dhcp, not effective in any environment
|
||||
address = "" # aa.bb.cc, socks5h://127.0.0.1:1080
|
||||
dns_upstream = "" # keep empty to set via dhcp, not effective in any environment
|
||||
http_proxy = ""
|
||||
socks5 = ""
|
||||
|
||||
[client.port_forward]
|
||||
# eg: ":2222"="aa.bb.cc:22"
|
||||
|
||||
[client.router]
|
||||
detect_level = 0 # [-4, 4], the bigger the harder to add
|
||||
direct_list = [
|
||||
"**.in-addr.arpa",
|
||||
"imap.*.*",
|
||||
"imap.*.*.*",
|
||||
"smtp.*.*",
|
||||
"smtp.*.*.*",
|
||||
"pop.*.*",
|
||||
"pop.*.*.*",
|
||||
"**.cn",
|
||||
]
|
||||
proxy_list = [
|
||||
"**.google.*",
|
||||
"**.goo.gl",
|
||||
"**.googleusercontent.com",
|
||||
"**.googleapis.com",
|
||||
"*.googlesource.com",
|
||||
"**.youtube.com",
|
||||
"**.ytimg.com",
|
||||
"**.ggpht.com",
|
||||
"**.googlevideo.com",
|
||||
"**.facebook.com",
|
||||
"**.fbcdn.net",
|
||||
"**.twitter.com",
|
||||
"**.twimg.com",
|
||||
"**.blogspot.com",
|
||||
"**.appspot.com",
|
||||
"**.wikipedia.org",
|
||||
"*.cloudfront.net",
|
||||
"**.amazon.com",
|
||||
"**.amazonaws.com",
|
||||
"*.githubusercontent.com",
|
||||
"*.githubassets.com",
|
||||
"*.github.*",
|
||||
]
|
||||
[client.port_forward]
|
||||
# eg: ":2222"="aa.bb.cc:22"
|
||||
|
||||
[client.router]
|
||||
block_refs = [
|
||||
"https://cdn.jsdelivr.net/gh/pexcn/daily@gh-pages/adlist/adlist.txt",
|
||||
]
|
||||
detect_level = 0 # [-4, 4], the bigger the harder to add
|
||||
direct_cird_refs = [
|
||||
"https://cdn.jsdelivr.net/gh/pexcn/daily@gh-pages/chnroute/chnroute.txt",
|
||||
]
|
||||
direct_list = [
|
||||
"**.in-addr.arpa",
|
||||
"imap.*.*",
|
||||
"imap.*.*.*",
|
||||
"smtp.*.*",
|
||||
"smtp.*.*.*",
|
||||
"pop.*.*",
|
||||
"pop.*.*.*",
|
||||
"**.cn",
|
||||
]
|
||||
direct_refs = [
|
||||
"https://cdn.jsdelivr.net/gh/pexcn/daily@gh-pages/chinalist/chinalist.txt",
|
||||
]
|
||||
proxy_list = [
|
||||
"**.google.*",
|
||||
"**.goo.gl",
|
||||
"**.googleusercontent.com",
|
||||
"**.googleapis.com",
|
||||
"*.googlesource.com",
|
||||
"**.youtube.com",
|
||||
"**.ytimg.com",
|
||||
"**.ggpht.com",
|
||||
"**.googlevideo.com",
|
||||
"**.facebook.com",
|
||||
"**.fbcdn.net",
|
||||
"**.twitter.com",
|
||||
"**.twimg.com",
|
||||
"**.blogspot.com",
|
||||
"**.appspot.com",
|
||||
"**.wikipedia.org",
|
||||
"*.cloudfront.net",
|
||||
"**.amazon.com",
|
||||
"**.amazonaws.com",
|
||||
"*.githubusercontent.com",
|
||||
"*.githubassets.com",
|
||||
"*.github.*",
|
||||
]
|
||||
proxy_refs = [
|
||||
"https://cdn.jsdelivr.net/gh/pexcn/daily@gh-pages/gfwlist/gfwlist.txt",
|
||||
]
|
||||
|
||||
[server]
|
||||
cert_email = "" # eg: user@aa.bb.cc
|
||||
cert_file = "" # eg: /etc/ssl/server.crt
|
||||
key_file = "" # eg: /etc/ssl/server.key
|
||||
upstream = "" # eg: 127.0.0.1:8080
|
||||
cert_email = "" # eg: user@aa.bb.cc
|
||||
cert_file = "" # eg: /etc/ssl/server.crt
|
||||
key_file = "" # eg: /etc/ssl/server.key
|
||||
upstream = "" # eg: 127.0.0.1:8080
|
||||
|
||||
@@ -4,11 +4,12 @@ go 1.14
|
||||
|
||||
require (
|
||||
github.com/krolaw/dhcp4 v0.0.0-20190909130307-a50d88189771
|
||||
github.com/libp2p/go-reuseport v0.0.1
|
||||
github.com/miekg/dns v1.1.29
|
||||
github.com/pelletier/go-toml v1.7.0
|
||||
github.com/libp2p/go-reuseport v0.0.2
|
||||
github.com/miekg/dns v1.1.30
|
||||
github.com/pelletier/go-toml v1.8.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/wweir/utils v0.0.0-20200401081845-fc35af3737dc
|
||||
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904
|
||||
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4
|
||||
github.com/wweir/util-go/log v0.0.0-20200701032032-3cff7b4a46ea
|
||||
github.com/wweir/util-go/mem v0.0.0-20200701032032-3cff7b4a46ea
|
||||
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543
|
||||
)
|
||||
|
||||
@@ -1,64 +1,47 @@
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/guregu/null v3.4.0+incompatible h1:a4mw37gBO7ypcBlTJeZGuMpSxxFTV9qFfFKgWxQSGaM=
|
||||
github.com/guregu/null v3.4.0+incompatible/go.mod h1:ePGpQaN9cw0tj45IR5E5ehMvsFlLlQZAkkOXZurJ3NM=
|
||||
github.com/influxdata/influxdb v1.7.9/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
|
||||
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/krolaw/dhcp4 v0.0.0-20190909130307-a50d88189771 h1:t2c2B9g1ZVhMYduqmANSEGVD3/1WlsrEYNPtVoFlENk=
|
||||
github.com/krolaw/dhcp4 v0.0.0-20190909130307-a50d88189771/go.mod h1:0AqAH3ZogsCrvrtUpvc6EtVKbc3w6xwZhkvGLuqyi3o=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
|
||||
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/libp2p/go-reuseport v0.0.1 h1:7PhkfH73VXfPJYKQ6JwS5I/eVcoyYi9IMNGc6FWpFLw=
|
||||
github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/miekg/dns v1.1.29 h1:xHBEhR+t5RzcFJjBLJlax2daXOrTYtr9z4WdKEfWFzg=
|
||||
github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI=
|
||||
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
||||
github.com/libp2p/go-reuseport v0.0.2 h1:XSG94b1FJfGA01BUrT82imejHQyTxO4jEWqheyCXYvU=
|
||||
github.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ=
|
||||
github.com/miekg/dns v1.1.30 h1:Qww6FseFn8PRfw07jueqIXqodm0JKiiKuK0DeXSqfyo=
|
||||
github.com/miekg/dns v1.1.30/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/pelletier/go-toml v1.8.0 h1:Keo9qb7iRJs2voHvunFtuuYFsbWeOBh8/P9v/kVMFtw=
|
||||
github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/ulule/deepcopier v0.0.0-20200117111125-792cfb847af8 h1:iCslye9fWwp1ExDu06BcKM8/gjDRAlX9DBL+T8CjuWU=
|
||||
github.com/ulule/deepcopier v0.0.0-20200117111125-792cfb847af8/go.mod h1:wUZg40sMUnY+1FU5F9rZwwCruLb8h1bHF8HzI09kgok=
|
||||
github.com/wweir/utils v0.0.0-20200401081845-fc35af3737dc h1:XvNZju71btZ0/hammNDOu0Jqv7qi0kR0x9KaXYRKOAY=
|
||||
github.com/wweir/utils v0.0.0-20200401081845-fc35af3737dc/go.mod h1:5PfQ9g8nWDRNkzu2gyjtFo/Xo6+s5ZCpulQADjvGz7M=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6 h1:TtyC78WMafNW8QFfv3TeP3yWNDG+uxNkk9vOrnDu6JA=
|
||||
github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6/go.mod h1:h8272+G2omSmi30fBXiZDMkmHuOgonplfKIKjQWzlfs=
|
||||
github.com/wweir/util-go v0.0.0-20200701032032-3cff7b4a46ea h1:V/bIKmS5Bv4zMwQ5qE7ugJiHpcAVFnAxvxRbb7OCwug=
|
||||
github.com/wweir/util-go/log v0.0.0-20200701032032-3cff7b4a46ea h1:IlO7d9R0I/l2syxJkx4/PURW9yVf4hy/Qf2IzdR4y38=
|
||||
github.com/wweir/util-go/log v0.0.0-20200701032032-3cff7b4a46ea/go.mod h1:OObmMboiahxgJ1P3twG+AN8EAZ/wz14vstI4E5kaZzI=
|
||||
github.com/wweir/util-go/mem v0.0.0-20200701032032-3cff7b4a46ea h1:nXgUp7CflDJnuR+zd43DHKxRA/hvuMkFtueSRLY7mEc=
|
||||
github.com/wweir/util-go/mem v0.0.0-20200701032032-3cff7b4a46ea/go.mod h1:gp1gaDO1K4uV/B8NfrTjVim99Xq5xAmm1SHVamRsVW0=
|
||||
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo=
|
||||
go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
||||
go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM=
|
||||
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904 h1:bXoxMPcSLOq08zI3/c5dEBT6lE4eh+jOh886GHrn6V8=
|
||||
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg=
|
||||
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
@@ -67,31 +50,26 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe h1:6fAMxZRR6sl1Uq8U61gxU+kPTs2tR8uOySCbBP7BN/M=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 h1:opSr2sbRXk5X5/givKrrKj9HXxFpW2sdCiP8MJSKLQY=
|
||||
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 h1:VvQyQJN0tSuecqgcIxMWnnfG5kSmgy9KZR9sW3W5QeA=
|
||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
|
||||
@@ -19,13 +19,12 @@ func main() {
|
||||
server.CertFile, server.KeyFile, server.CertEmail)
|
||||
|
||||
case client.Address != "":
|
||||
route := &router.Route{
|
||||
ProxyAddress: client.Address,
|
||||
ProxyPassword: password,
|
||||
DetectLevel: client.Router.DetectLevel,
|
||||
DirectList: client.Router.DirectList,
|
||||
ProxyList: client.Router.ProxyList,
|
||||
PersistFn: conf.PersistRule,
|
||||
route := router.NewRoute(client.Address, password, client.Router.DetectLevel,
|
||||
client.Router.BlockList, client.Router.ProxyList, client.Router.DirectList,
|
||||
conf.PersistRule)
|
||||
|
||||
if client.Socks5Proxy != "" {
|
||||
go proxy.StartSocks5Proxy(client.Socks5Proxy, client.Address, []byte(password))
|
||||
}
|
||||
|
||||
if client.HTTPProxy != "" {
|
||||
@@ -33,15 +32,10 @@ func main() {
|
||||
[]byte(password), route.GenProxyCheck(true))
|
||||
}
|
||||
|
||||
enableDNSSolution := client.DNSServeIP != ""
|
||||
if enableDNSSolution {
|
||||
transport.SetDNS(nil, client.DNSUpstream)
|
||||
go proxy.StartDNS(client.DNSServeIP, client.DNSUpstream,
|
||||
route.GenProxyCheck(false))
|
||||
}
|
||||
transport.SetDNS(nil, client.DNSUpstream)
|
||||
go proxy.StartDNS(client.DNSUpstream, route.GenProxyCheck(false))
|
||||
|
||||
proxy.StartClient(client.Address, password,
|
||||
client.DNSServeIP, enableDNSSolution,
|
||||
client.PortForward, route.GenProxyCheck(true))
|
||||
|
||||
default:
|
||||
|
||||
+10
-10
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
"github.com/miekg/dns"
|
||||
"github.com/wweir/sower/dhcp"
|
||||
"github.com/wweir/utils/log"
|
||||
"github.com/wweir/util-go/log"
|
||||
)
|
||||
|
||||
type msgCache struct {
|
||||
@@ -18,12 +18,7 @@ type msgCache struct {
|
||||
|
||||
var cache sync.Map
|
||||
|
||||
func StartDNS(redirectIP, relayServer string, shouldProxy func(string) bool) {
|
||||
serveIP := net.ParseIP(redirectIP)
|
||||
if redirectIP == "" || serveIP.String() != redirectIP {
|
||||
log.Fatalw("invalid listen ip", "ip", redirectIP)
|
||||
}
|
||||
|
||||
func StartDNS(relayServer string, shouldProxy func(string) (bool, bool)) {
|
||||
var err error
|
||||
if relayServer, err = pickRelayAddr(relayServer); err != nil {
|
||||
log.Fatalw("pick upstream dns server", "err", err)
|
||||
@@ -47,8 +42,13 @@ func StartDNS(redirectIP, relayServer string, shouldProxy func(string) bool) {
|
||||
domain = domain[:idx] // trim port
|
||||
}
|
||||
|
||||
if shouldProxy(domain) {
|
||||
w.WriteMsg(localA(r, domain, serveIP))
|
||||
if isblock, isproxy := shouldProxy(domain); isblock {
|
||||
m := new(dns.Msg)
|
||||
m.SetReply(r)
|
||||
w.WriteMsg(m)
|
||||
} else if isproxy {
|
||||
host, _, _ := net.SplitHostPort(w.LocalAddr().String())
|
||||
w.WriteMsg(localA(r, domain, net.ParseIP(host)))
|
||||
|
||||
} else if val, ok := cache.Load(domain); ok && val.(*msgCache).After(time.Now()) {
|
||||
msg := val.(*msgCache)
|
||||
@@ -82,7 +82,7 @@ func StartDNS(redirectIP, relayServer string, shouldProxy func(string) bool) {
|
||||
}
|
||||
})
|
||||
|
||||
server := &dns.Server{Addr: net.JoinHostPort(redirectIP, "53"), Net: "udp"}
|
||||
server := &dns.Server{Addr: ":53", Net: "udp"}
|
||||
log.Infow("start dns", "addr", server.Addr)
|
||||
log.Fatalw("dns serve fail", "err", server.ListenAndServe())
|
||||
}
|
||||
|
||||
+5
-5
@@ -10,20 +10,20 @@ import (
|
||||
|
||||
"github.com/wweir/sower/transport"
|
||||
"github.com/wweir/sower/util"
|
||||
"github.com/wweir/utils/log"
|
||||
"github.com/wweir/util-go/log"
|
||||
)
|
||||
|
||||
// StartHTTPProxy start http reverse proxy.
|
||||
// The httputil.ReverseProxy do not supply enough support for https request.
|
||||
func StartHTTPProxy(httpProxyAddr, serverAddr string, password []byte,
|
||||
shouldProxy func(string) bool) {
|
||||
shouldProxy func(string) (bool, bool)) {
|
||||
|
||||
proxy := httputil.ReverseProxy{
|
||||
Director: func(r *http.Request) {},
|
||||
Transport: &http.Transport{
|
||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return transport.Dial(serverAddr, func(host string) (string, []byte) {
|
||||
if shouldProxy(host) {
|
||||
if _, ok := shouldProxy(host); ok {
|
||||
return httpProxyAddr, password
|
||||
}
|
||||
return "", nil
|
||||
@@ -51,7 +51,7 @@ func StartHTTPProxy(httpProxyAddr, serverAddr string, password []byte,
|
||||
}
|
||||
|
||||
func httpsProxy(w http.ResponseWriter, r *http.Request,
|
||||
serverAddr string, password []byte, shouldProxy func(string) bool) {
|
||||
serverAddr string, password []byte, shouldProxy func(string) (bool, bool)) {
|
||||
|
||||
conn, _, err := w.(http.Hijacker).Hijack()
|
||||
if err != nil {
|
||||
@@ -68,7 +68,7 @@ func httpsProxy(w http.ResponseWriter, r *http.Request,
|
||||
|
||||
target, _ := util.WithDefaultPort(r.Host, "443")
|
||||
rc, err := transport.Dial(target, func(host string) (string, []byte) {
|
||||
if shouldProxy(host) {
|
||||
if _, ok := shouldProxy(host); ok {
|
||||
return serverAddr, password
|
||||
}
|
||||
return "", nil
|
||||
|
||||
+10
-13
@@ -6,17 +6,17 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/wweir/sower/transport"
|
||||
"github.com/wweir/utils/log"
|
||||
"github.com/wweir/util-go/log"
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
)
|
||||
|
||||
func StartClient(serverAddr, password, serveIP string, enableDNS bool,
|
||||
forwards map[string]string, shouldProxy func(string) bool) {
|
||||
func StartClient(serverAddr, password string,
|
||||
forwards map[string]string, shouldProxy func(string) (bool, bool)) {
|
||||
|
||||
passwordData := []byte(password)
|
||||
relayToRemote := func(lnAddr, target string,
|
||||
parseFn func(net.Conn) (net.Conn, string, error),
|
||||
shouldProxy func(string) bool) {
|
||||
shouldProxy func(string) (bool, bool)) {
|
||||
|
||||
ln, err := net.Listen("tcp", lnAddr)
|
||||
if err != nil {
|
||||
@@ -41,14 +41,13 @@ func StartClient(serverAddr, password, serveIP string, enableDNS bool,
|
||||
}
|
||||
|
||||
rc, err := transport.Dial(target, func(domain string) (string, []byte) {
|
||||
if shouldProxy(domain) {
|
||||
if _, ok := shouldProxy(domain); ok {
|
||||
return serverAddr, passwordData
|
||||
}
|
||||
return "", nil
|
||||
})
|
||||
if err != nil {
|
||||
host, _, _ := net.SplitHostPort(target)
|
||||
log.Warnw("dial", "addr", target, "proxy", shouldProxy(host), "err", err)
|
||||
log.Warnw("dial", "addr", target, "err", err)
|
||||
return
|
||||
}
|
||||
defer rc.Close()
|
||||
@@ -59,15 +58,13 @@ func StartClient(serverAddr, password, serveIP string, enableDNS bool,
|
||||
}
|
||||
|
||||
for from, to := range forwards {
|
||||
go relayToRemote(from, to, nil, func(string) bool { return true })
|
||||
go relayToRemote(from, to, nil, func(string) (bool, bool) { return false, true })
|
||||
}
|
||||
|
||||
if enableDNS {
|
||||
go relayToRemote(net.JoinHostPort(serveIP, "http"), "", ParseHTTP, shouldProxy)
|
||||
go relayToRemote(net.JoinHostPort(serveIP, "https"), "", ParseHTTPS, shouldProxy)
|
||||
}
|
||||
go relayToRemote(":http", "", ParseHTTP, shouldProxy)
|
||||
go relayToRemote(":https", "", ParseHTTPS, shouldProxy)
|
||||
|
||||
log.Infow("start sower client", "dns solution", enableDNS, "forwards", forwards)
|
||||
log.Infow("start sower client", "forwards", forwards)
|
||||
|
||||
select {}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/wweir/sower/transport"
|
||||
"github.com/wweir/util-go/log"
|
||||
)
|
||||
|
||||
func StartSocks5Proxy(listenAddr, serverAddr string, password []byte) {
|
||||
ln, err := net.Listen("tcp", listenAddr)
|
||||
if err != nil {
|
||||
log.Fatalw("socks5 proxy", "addr", listenAddr, "err", err)
|
||||
}
|
||||
|
||||
serveSocks5(ln, serverAddr, password)
|
||||
}
|
||||
|
||||
func serveSocks5(ln net.Listener, serverAddr string, password []byte) {
|
||||
conn, err := ln.Accept()
|
||||
if err != nil {
|
||||
log.Fatalw("socks5 proxy", "err", err)
|
||||
}
|
||||
go serveSocks5(ln, serverAddr, password)
|
||||
|
||||
tgtAddr, err := transport.ParseSocks5(conn)
|
||||
if err != nil {
|
||||
log.Errorw("socks5 proxy", "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
rc, err := transport.Dial(tgtAddr, func(host string) (string, []byte) {
|
||||
return serverAddr, password
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorw("socks5 proxy", "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
relay(conn, rc)
|
||||
conn.Close()
|
||||
rc.Close()
|
||||
}
|
||||
+31
-21
@@ -9,8 +9,8 @@ import (
|
||||
|
||||
"github.com/wweir/sower/transport"
|
||||
"github.com/wweir/sower/util"
|
||||
"github.com/wweir/utils/log"
|
||||
"github.com/wweir/utils/mem"
|
||||
"github.com/wweir/util-go/log"
|
||||
"github.com/wweir/util-go/mem"
|
||||
)
|
||||
|
||||
// Route implement a router for each request
|
||||
@@ -18,27 +18,33 @@ type Route struct {
|
||||
once sync.Once
|
||||
cache *mem.Cache
|
||||
|
||||
ProxyAddress string
|
||||
ProxyPassword string
|
||||
password []byte
|
||||
ProxyAddress string
|
||||
password []byte
|
||||
|
||||
DetectLevel int // dynamic detect proxy level
|
||||
DirectList []string
|
||||
directRule *util.Node
|
||||
ProxyList []string
|
||||
blockRule *util.Node
|
||||
proxyRule *util.Node
|
||||
directRule *util.Node
|
||||
PersistFn func(string)
|
||||
}
|
||||
|
||||
// ShouldProxy check if the domain shoule request though proxy
|
||||
func (r *Route) GenProxyCheck(sync bool) func(string) bool {
|
||||
r.once.Do(func() {
|
||||
r.cache = mem.New(4 * time.Hour)
|
||||
r.password = []byte(r.ProxyPassword)
|
||||
r.directRule = util.NewNodeFromRules(r.DirectList...)
|
||||
r.proxyRule = util.NewNodeFromRules(r.ProxyList...)
|
||||
})
|
||||
func NewRoute(address, password string, detectLevel int,
|
||||
blocklist, proxylist, directlist []string, persist func(string)) *Route {
|
||||
return &Route{
|
||||
cache: mem.New(4 * time.Hour),
|
||||
ProxyAddress: address,
|
||||
password: []byte(password),
|
||||
|
||||
DetectLevel: detectLevel,
|
||||
blockRule: util.NewNodeFromRules(blocklist...),
|
||||
proxyRule: util.NewNodeFromRules(proxylist...),
|
||||
directRule: util.NewNodeFromRules(directlist...),
|
||||
PersistFn: persist,
|
||||
}
|
||||
}
|
||||
|
||||
// ShouldProxy check if the domain shoule request though proxy
|
||||
func (r *Route) GenProxyCheck(sync bool) func(string) (bool, bool) {
|
||||
detect := func(domain string) bool {
|
||||
go r.cache.Remember(r, domain)
|
||||
return true
|
||||
@@ -53,21 +59,25 @@ func (r *Route) GenProxyCheck(sync bool) func(string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
return func(domain string) bool {
|
||||
return func(domain string) (bool, bool) {
|
||||
domain = strings.TrimSuffix(domain, ".")
|
||||
// break deadlook, for wildcard
|
||||
if sepCount := strings.Count(domain, "."); sepCount == 0 || sepCount >= 5 {
|
||||
return false
|
||||
return false, false
|
||||
}
|
||||
|
||||
if r.blockRule.Match(domain) {
|
||||
return true, false
|
||||
}
|
||||
|
||||
if r.proxyRule.Match(domain) {
|
||||
return true
|
||||
return false, true
|
||||
}
|
||||
if r.directRule.Match(domain) {
|
||||
return false
|
||||
return false, false
|
||||
}
|
||||
|
||||
return detect(domain)
|
||||
return false, detect(domain)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func IsSocks5Schema(addr string) (string, bool) {
|
||||
if strings.HasPrefix(addr, "socks5://") {
|
||||
return strings.TrimPrefix(addr, "socks5://"), true
|
||||
}
|
||||
|
||||
if strings.HasPrefix(addr, "socks5h://") {
|
||||
return strings.TrimPrefix(addr, "socks5h://"), true
|
||||
}
|
||||
|
||||
return addr, false
|
||||
}
|
||||
|
||||
func ToSocks5(c net.Conn, host string, port uint16) (net.Conn, error) {
|
||||
return &conn{
|
||||
init: make(chan struct{}),
|
||||
Conn: c,
|
||||
domain: host,
|
||||
port: port,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type conn struct {
|
||||
init chan struct{}
|
||||
domain string
|
||||
port uint16
|
||||
net.Conn
|
||||
}
|
||||
|
||||
func (c *conn) Read(b []byte) (n int, err error) {
|
||||
<-c.init
|
||||
return c.Conn.Read(b)
|
||||
}
|
||||
|
||||
func (c *conn) Write(b []byte) (n int, err error) {
|
||||
select {
|
||||
case <-c.init:
|
||||
return c.Conn.Write(b)
|
||||
default:
|
||||
}
|
||||
|
||||
{
|
||||
req := &authReq{
|
||||
VER: 5,
|
||||
NMETHODS: 1,
|
||||
METHODS: [1]byte{0}, // NO AUTHENTICATION REQUIRED
|
||||
}
|
||||
if err := binary.Write(c.Conn, binary.BigEndian, req); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
{
|
||||
resp := &authResp{}
|
||||
if err := binary.Read(c.Conn, binary.BigEndian, resp); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
{
|
||||
portBuf := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(portBuf, c.port)
|
||||
req := &request{
|
||||
req: req{
|
||||
VER: 5, // socks5
|
||||
CMD: 1, // CONNECT
|
||||
RSV: 0, // RESERVED
|
||||
ATYP: 3, // DOMAINNAME
|
||||
},
|
||||
DST_ADDR: append([]byte{byte(len(c.domain))}, []byte(c.domain)...),
|
||||
DST_PORT: portBuf,
|
||||
}
|
||||
|
||||
if _, err := c.Conn.Write(req.Bytes()); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
{
|
||||
resp := &response{}
|
||||
if err := binary.Read(c.Conn, binary.BigEndian, &(resp.resp)); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
switch resp.REP {
|
||||
case 0x00:
|
||||
default:
|
||||
return 0, fmt.Errorf("socks5 handshake fail, return code: %d", resp.REP)
|
||||
}
|
||||
|
||||
switch resp.ATYP {
|
||||
case 0x01: // IPv4
|
||||
resp.DST_ADDR = make([]byte, net.IPv4len)
|
||||
if _, err := io.ReadFull(c.Conn, resp.DST_ADDR); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
case 0x03: // domain name
|
||||
if _, err := io.ReadFull(c.Conn, resp.DST_ADDR[:1]); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if _, err := io.ReadFull(c.Conn, resp.DST_ADDR[1:1+int(resp.DST_ADDR[0])]); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
case 0x04:
|
||||
resp.DST_ADDR = make([]byte, net.IPv6len)
|
||||
if _, err := io.ReadFull(c.Conn, resp.DST_ADDR); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
resp.DST_PORT = make([]byte, 2)
|
||||
if _, err := io.ReadFull(c.Conn, resp.DST_PORT); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
close(c.init)
|
||||
return c.Conn.Write(b)
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
func IsSocks5Schema(addr string) (string, bool) {
|
||||
if strings.HasPrefix(addr, "socks5://") {
|
||||
return strings.TrimPrefix(addr, "socks5://"), true
|
||||
}
|
||||
|
||||
if strings.HasPrefix(addr, "socks5h://") {
|
||||
return strings.TrimPrefix(addr, "socks5h://"), true
|
||||
}
|
||||
|
||||
return addr, false
|
||||
}
|
||||
|
||||
func ToSocks5(c net.Conn, host string, port uint16) (net.Conn, error) {
|
||||
return &conn{
|
||||
init: make(chan struct{}),
|
||||
Conn: c,
|
||||
domain: host,
|
||||
port: port,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type conn struct {
|
||||
init chan struct{}
|
||||
domain string
|
||||
port uint16
|
||||
net.Conn
|
||||
}
|
||||
|
||||
func (c *conn) Read(b []byte) (n int, err error) {
|
||||
select {
|
||||
case <-c.init:
|
||||
return c.Conn.Read(b)
|
||||
default:
|
||||
return 0, c.clientHandshake()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *conn) Write(b []byte) (n int, err error) {
|
||||
select {
|
||||
case <-c.init:
|
||||
return c.Conn.Write(b)
|
||||
default:
|
||||
return 0, c.clientHandshake()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *conn) clientHandshake() error {
|
||||
{
|
||||
req := &authReq{
|
||||
VER: 5,
|
||||
NMETHODS: 1,
|
||||
METHODS: [1]byte{0}, // NO AUTHENTICATION REQUIRED
|
||||
}
|
||||
if err := binary.Write(c.Conn, binary.BigEndian, req); err != nil {
|
||||
return xerrors.New(err.Error())
|
||||
}
|
||||
}
|
||||
{
|
||||
resp := &authResp{}
|
||||
if err := binary.Read(c.Conn, binary.BigEndian, resp); err != nil {
|
||||
return xerrors.New(err.Error())
|
||||
}
|
||||
}
|
||||
{
|
||||
reqHead := requestHead{
|
||||
VER: 5, // socks5
|
||||
CMD: 1, // CONNECT
|
||||
RSV: 0, // RESERVED
|
||||
ATYP: 3, // DOMAINNAME
|
||||
}
|
||||
|
||||
if err := binary.Write(c.Conn, binary.BigEndian, reqHead); err != nil {
|
||||
return xerrors.New(err.Error())
|
||||
}
|
||||
|
||||
buf := make([]byte, 0, 1 /*LEN*/ +len(c.domain)+2 /*PORT*/)
|
||||
buf = append(buf, byte(len(c.domain)))
|
||||
buf = append(buf, []byte(c.domain)...)
|
||||
buf = append(buf, byte(c.port>>8), byte(c.port))
|
||||
if _, err := c.Conn.Write(buf); err != nil {
|
||||
return xerrors.New(err.Error())
|
||||
}
|
||||
}
|
||||
{
|
||||
head := replyHead{}
|
||||
if err := binary.Read(c.Conn, binary.BigEndian, &head); err != nil {
|
||||
return xerrors.New(err.Error())
|
||||
}
|
||||
|
||||
switch head.REP {
|
||||
case 0x00:
|
||||
default:
|
||||
return xerrors.Errorf("socks5 handshake fail, return code: %d", head.REP)
|
||||
}
|
||||
|
||||
var bindAddr addrType
|
||||
switch head.ATYP {
|
||||
case 0x01: // IPv4
|
||||
bindAddr = addrTypeIPv4{}
|
||||
case 0x03: // domain name
|
||||
bindAddr = addrTypeDomain{}
|
||||
case 0x04: // IPv6
|
||||
bindAddr = addrTypeIPv6{}
|
||||
default:
|
||||
return xerrors.New("invalid connect type")
|
||||
}
|
||||
if err := bindAddr.Fullfill(c.Conn); err != nil {
|
||||
return xerrors.New(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
close(c.init)
|
||||
return nil
|
||||
}
|
||||
+89
-18
@@ -1,44 +1,115 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// https://tools.ietf.org/html/rfc1928
|
||||
|
||||
// 1. client send auth request
|
||||
type authReq struct {
|
||||
VER byte
|
||||
NMETHODS byte
|
||||
METHODS [1]byte // 1 to 255, fix to no authentication
|
||||
}
|
||||
|
||||
// 2. server response auth request
|
||||
type authResp struct {
|
||||
VER byte
|
||||
METHOD byte
|
||||
}
|
||||
|
||||
type request struct {
|
||||
req
|
||||
DST_ADDR []byte // first byte is length
|
||||
DST_PORT []byte // two bytes
|
||||
}
|
||||
type req struct {
|
||||
// 3. client request with target address
|
||||
type requestHead struct {
|
||||
VER byte
|
||||
CMD byte
|
||||
RSV byte
|
||||
ATYP byte
|
||||
}
|
||||
|
||||
func (r *request) Bytes() []byte {
|
||||
out := []byte{r.VER, r.CMD, r.RSV, r.ATYP}
|
||||
out = append(out, r.DST_ADDR...)
|
||||
return append(out, r.DST_PORT...)
|
||||
}
|
||||
|
||||
type response struct {
|
||||
resp
|
||||
DST_ADDR []byte // first byte is length
|
||||
DST_PORT []byte // two bytes
|
||||
}
|
||||
type resp struct {
|
||||
// 4. server response with the address that assigned to connect to target address
|
||||
type replyHead struct {
|
||||
VER byte
|
||||
REP byte
|
||||
RSV byte
|
||||
ATYP byte
|
||||
}
|
||||
|
||||
type addrType interface {
|
||||
Fullfill(r io.Reader) error
|
||||
String() string
|
||||
}
|
||||
|
||||
// ATYP:
|
||||
// 0x01 -> net.IPv4len
|
||||
// 0x03 -> first byte is length
|
||||
// 0x04 -> net.IPv6len
|
||||
type addrTypeIPv4 struct {
|
||||
DST_ADDR [4]byte
|
||||
DST_PORT uint16
|
||||
}
|
||||
|
||||
func (a addrTypeIPv4) Fullfill(r io.Reader) error {
|
||||
return binary.Read(r, binary.BigEndian, &a)
|
||||
}
|
||||
func (a addrTypeIPv4) String() string {
|
||||
return net.JoinHostPort(
|
||||
net.IP(a.DST_ADDR[:]).String(),
|
||||
strconv.FormatUint(uint64(a.DST_PORT), 10),
|
||||
)
|
||||
}
|
||||
|
||||
type addrTypeDomain struct {
|
||||
DST_ADDR_LEN uint8
|
||||
DST_ADDR []byte
|
||||
DST_PORT uint16
|
||||
}
|
||||
|
||||
func (a addrTypeDomain) Fullfill(r io.Reader) error {
|
||||
buf := make([]byte, 256)
|
||||
// domain length
|
||||
if _, err := io.ReadFull(r, buf[:1]); err != nil {
|
||||
return xerrors.New(err.Error())
|
||||
}
|
||||
a.DST_ADDR_LEN = uint8(buf[0])
|
||||
|
||||
// domain
|
||||
if _, err := io.ReadFull(r, buf[:int(buf[0])]); err != nil {
|
||||
return xerrors.New(err.Error())
|
||||
}
|
||||
a.DST_ADDR = buf[:int(buf[0])]
|
||||
|
||||
// port
|
||||
if _, err := io.ReadFull(r, buf[:2]); err != nil {
|
||||
return xerrors.New(err.Error())
|
||||
}
|
||||
a.DST_PORT = binary.BigEndian.Uint16(buf[:2])
|
||||
|
||||
return nil
|
||||
}
|
||||
func (a addrTypeDomain) String() string {
|
||||
return net.JoinHostPort(
|
||||
net.IP(a.DST_ADDR[:]).String(),
|
||||
strconv.FormatUint(uint64(a.DST_PORT), 10),
|
||||
)
|
||||
}
|
||||
|
||||
type addrTypeIPv6 struct {
|
||||
DST_ADDR [16]byte
|
||||
DST_PORT uint16
|
||||
}
|
||||
|
||||
func (a addrTypeIPv6) Fullfill(r io.Reader) error {
|
||||
return binary.Read(r, binary.BigEndian, &a)
|
||||
}
|
||||
func (a addrTypeIPv6) String() string {
|
||||
return net.JoinHostPort(
|
||||
net.IP(a.DST_ADDR[:]).String(),
|
||||
strconv.FormatUint(uint64(a.DST_PORT), 10),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"net"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
func ParseSocks5(conn net.Conn) (tgtaddr string, err error) {
|
||||
{
|
||||
authReq := new(authReq)
|
||||
if err := binary.Read(conn, binary.BigEndian, authReq); err != nil {
|
||||
return "", xerrors.New(err.Error())
|
||||
}
|
||||
|
||||
if authReq.VER != 5 || // socks5
|
||||
authReq.NMETHODS != 1 ||
|
||||
authReq.METHODS[0] != 0 { // NO_AUTH
|
||||
return "", xerrors.New("invalid socks5 auth method")
|
||||
}
|
||||
}
|
||||
{
|
||||
if err := binary.Write(conn, binary.BigEndian, &authResp{
|
||||
VER: 5,
|
||||
METHOD: 1,
|
||||
}); err != nil {
|
||||
return "", xerrors.New(err.Error())
|
||||
}
|
||||
}
|
||||
{
|
||||
head := &requestHead{}
|
||||
if err := binary.Read(conn, binary.BigEndian, head); err != nil {
|
||||
return "", xerrors.New(err.Error())
|
||||
}
|
||||
if head.VER != 5 ||
|
||||
head.CMD != 1 {
|
||||
return "", xerrors.New("invalid socks5 connect request")
|
||||
}
|
||||
|
||||
var addr addrType
|
||||
switch head.ATYP {
|
||||
case 0x01: // IPv4
|
||||
addr = addrTypeIPv4{}
|
||||
case 0x03: // domain name
|
||||
addr = addrTypeDomain{}
|
||||
case 0x04: // IPv6
|
||||
addr = addrTypeIPv6{}
|
||||
default:
|
||||
return "", xerrors.New("invalid connect type")
|
||||
}
|
||||
if err := addr.Fullfill(conn); err != nil {
|
||||
return "", xerrors.New(err.Error())
|
||||
}
|
||||
tgtaddr = addr.String()
|
||||
}
|
||||
{
|
||||
if err := binary.Write(conn, binary.BigEndian, &replyHead{
|
||||
VER: 5,
|
||||
REP: 0,
|
||||
RSV: 0,
|
||||
ATYP: 1,
|
||||
}); err != nil {
|
||||
return "", xerrors.New(err.Error())
|
||||
}
|
||||
|
||||
// FIXME: return the real address
|
||||
if _, err := conn.Write(make([]byte, 6)); err != nil {
|
||||
return "", xerrors.New(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return tgtaddr, nil
|
||||
}
|
||||
+1
-1
@@ -7,7 +7,7 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/wweir/sower/dhcp"
|
||||
"github.com/wweir/utils/log"
|
||||
"github.com/wweir/util-go/log"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ func (n *node) add(secs []string) {
|
||||
case 0:
|
||||
return
|
||||
case 1:
|
||||
n.node[secs[length-1]] = &node{node: map[string]*node{"": &node{}}}
|
||||
n.node[secs[length-1]] = &node{node: map[string]*node{"": {}}}
|
||||
default:
|
||||
sec := secs[length-1]
|
||||
if sec == "**" {
|
||||
|
||||
Reference in New Issue
Block a user