Add intelligent rule suggestions @release

This commit is contained in:
wweir
2019-01-22 20:12:47 +08:00
parent e02da26936
commit 756a8c8d17
12 changed files with 210 additions and 174 deletions
+4 -3
View File
@@ -5,7 +5,7 @@
[![GitHub star](https://img.shields.io/github/stars/wweir/sower.svg?style=popout)](https://github.com/wweir/sower/stargazers)
[![GitHub license](https://img.shields.io/github/license/wweir/sower.svg?style=popout)](LICENSE)
The sower is a cross-platform transparent proxy tool base on DNS solution.
The sower is a cross-platform intelligent transparent proxy tool base on DNS solution.
If you wanna enjoy the sower, you need to deploy sower on both server and client side.
On client side, sower listening UDP `53` and TCP `80`/`443` ports, so that you need run it with privileged.
@@ -58,7 +58,8 @@ Auto deploy script support Linux server side and masOS/Linux client side.
$ bash -c "$(curl -s https://raw.githubusercontent.com/wweir/sower/master/deploy/install)"
```
Then modify the configuration file as needed and set `127.0.0.1` as your first domain name server. In most situation, you just need to modify `/etc/resolv.conf`.
Then modify the configuration file as needed and set `127.0.0.1` as your first domain name server.
In most situation, you just need to modify `/etc/resolv.conf`.
If you wanna uninstall sower, change `install` into `uninstall` and rerun the command.
@@ -83,4 +84,4 @@ But the client is more troublesome and needs some understanding of the working m
- [x] CI/CD
- [ ] relay optimization
- [ ] deploy script for all normal platform
- [ ] dns rule dynamic configuration
- [x] dns rule intelligent suggestions
+45 -10
View File
@@ -3,11 +3,11 @@ package conf
import (
"context"
"flag"
"net"
"os"
"os/exec"
"path/filepath"
"strconv"
"sync"
"time"
"github.com/golang/glog"
@@ -27,24 +27,32 @@ var Conf = struct {
DNSServer string `toml:"dns_server"`
ClientIP string `toml:"client_ip"`
ClientIPNet net.IP `toml:"-"`
ClearDNSCache string `toml:"clear_dns_cache"`
BlockList []string `toml:"blocklist"`
WhiteList []string `toml:"whitelist"`
Suggestions []string `toml:"suggestions"`
Verbose int `toml:"verbose"`
tree *toml.Tree // for suggestions
}{}
var mu = &sync.Mutex{}
var OnRefreash = []func() error{
func() (err error) {
if Conf.tree, err = toml.LoadFile(Conf.ConfigFile); err != nil {
return err
} else if err = Conf.tree.Unmarshal(&Conf); err != nil {
mu.Lock()
defer mu.Unlock()
f, err := os.OpenFile(Conf.ConfigFile, os.O_RDONLY, 0644)
if err != nil {
return err
}
defer f.Close()
file := Conf.ConfigFile
if err = toml.NewDecoder(f).Decode(&Conf); err != nil {
return err
}
Conf.ConfigFile = file
Conf.ClientIPNet = net.ParseIP(Conf.ClientIP)
return flag.Set("v", strconv.Itoa(Conf.Verbose))
},
func() error {
@@ -75,10 +83,13 @@ func init() {
}
if _, err := os.Stat(Conf.ConfigFile); os.IsNotExist(err) {
glog.Warningln("no config file has been load:", Conf.ConfigFile)
return
}
if err := OnRefreash[0](); err != nil {
panic(err)
for i := range OnRefreash {
if err := OnRefreash[i](); err != nil {
glog.Fatalln(err)
}
}
watchConfigFile()
}
@@ -114,3 +125,27 @@ func watchConfigFile() {
}
}()
}
func AddSuggest(domain string) {
mu.Lock()
defer mu.Unlock()
Conf.Suggestions = append(Conf.Suggestions, domain)
// safe write
f, err := os.OpenFile(Conf.ConfigFile+"~", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
glog.Errorln(err)
return
}
defer f.Close()
if err := toml.NewEncoder(f).ArraysWithOneElementPerLine(true).Encode(Conf); err != nil {
glog.Errorln(err)
return
}
if err = os.Rename(Conf.ConfigFile+"~", Conf.ConfigFile); err != nil {
glog.Errorln(err)
}
}
-60
View File
@@ -9,82 +9,22 @@ client_ip="127.0.0.1"
# clear_dns_cache="killall -HUP mDNSResponder"
blocklist=[
"*.google.com", # google
"*.google.com.hk",
"*.google.ca",
"*.google.jp",
"*.google.tw",
"ocsp.pki.goog",
"g.co",
"*.goo.gl",
"*.googleusercontent.com",
"*.googleapis.com",
"gmail.com",
"*.youtube.com", # youtube
"*.ytimg.com",
"*.ggpht.com",
"*.googlevideo.com",
"*.vimeo.com",
"*.facebook.com", # facebook
"*.xx.fbcdn.net",
"connect.facebook.net",
"*.twitter.com", # twitter
"t.co",
"*.twimg.com",
"www.linkedin.com",
"www.reddit.com", # reddit
"www.redditmedia.com",
"*.blogspot.com", # blogspot
"www.blogger.com",
"www.feedburner.com",
"img1.blogblog.com",
"*.aws.amazon.com", # amazon
"m.media-amazon.com",
"*.awsstatic.com",
"*.s3.amazonaws.com",
"*.cloudfront.net", # atlassian
"synchrony-cdn.atlassian.com",
"avatar-cdn.atlassian.com",
"*.medium.com",
"*.prod.public.atl-paas.net",
"accounts-static.cdn.mozilla.net", # firefox
"*.services.mozilla.com",
"pocket-image-cache.com", # pocket
"*.golang.org", # golang
"*.googlesource.com",
"godoc.org",
"gist.github.com", # github
"*.github.io",
"*.k8s.io", # k8s
"k8s.gcr.io",
"*.wikipedia.org", # wikipeida
"*.wikimedia.org",
"*.wikisource.org",
"lookup-api.apple.com",
"lookup-api.apple.com.edgekey.net",
"e16991.b.akamaiedge.net",
"*.web.telegram.org", # telegram
"core.telegram.org",
"telegram.me",
"t.me",
"*.slack.com", #slack
"*.slack-edge.com",
"js.driftt.com",
"cloud.feedly.com", # feedly
"static.grammarly.com", # grammarly
"denali-static.grammarly.com",
"apkpure.com", # apkpure
"download.apkpure.com",
"*.nytimes.com", # New York times
"*.nyt.com",
"*.akadns.net", # suggestions
"*.haxx.se",
"shadowsocks.org",
"t66y.com",
"ocsp.godaddy.com",
"*.qualtrics.com",
"*.starfieldtech.com",
"*.typekit.net",
"*.v2ray.com",
"homebrew.bintray.com",
]
verbose=0
+60 -58
View File
@@ -1,18 +1,24 @@
package dns
import (
"io"
"net"
"strings"
"time"
"github.com/golang/glog"
"github.com/miekg/dns"
mem "github.com/wweir/mem-go"
"github.com/wweir/sower/conf"
)
const colon = byte(':')
func StartDNS(dnsServer, listenIP string, ipNet net.IP) {
func StartDNS(dnsServer, listenIP string) {
ip := net.ParseIP(listenIP)
suggest := &intelliSuggest{listenIP, 2 * time.Second}
mem.DefaultCache = mem.New(time.Hour)
dns.HandleFunc(".", func(w dns.ResponseWriter, r *dns.Msg) {
// *Msg r has an TSIG record and it was validated
if r.IsTsig() != nil && w.TsigStatus() == nil {
@@ -29,84 +35,80 @@ func StartDNS(dnsServer, listenIP string, ipNet net.IP) {
domain = domain[:idx]
}
if len(conf.Conf.BlockList) == 0 {
bestTry(w, r, domain, dnsServer, ipNet)
} else {
manual(w, r, domain, dnsServer, ipNet)
}
matchAndServe(w, r, domain, listenIP, dnsServer, ip, suggest)
})
server := &dns.Server{Addr: listenIP + ":53", Net: "udp"}
glog.Fatalln(server.ListenAndServe())
}
func bestTry(w dns.ResponseWriter, r *dns.Msg, domain, dnsServer string, ipNet net.IP) {
msg, _ := dns.Exchange(r, dnsServer+":53")
if msg == nil {
return
}
if len(msg.Answer) == 0 { // expose any response
w.WriteMsg(msg)
return
}
func matchAndServe(w dns.ResponseWriter, r *dns.Msg, domain, listenIP, dnsServer string, ipNet net.IP, suggest *intelliSuggest) {
inWriteList := whiteList.Match(domain)
var ip string
switch msg.Answer[0].(type) {
case *dns.A:
ip = msg.Answer[0].(*dns.A).A.String()
case *dns.AAAA:
ip = "[" + msg.Answer[0].(*dns.AAAA).AAAA.String() + "]"
default:
w.WriteMsg(msg)
return
}
if _, err := net.DialTimeout("tcp", ip+":http", time.Second); err != nil {
glog.V(2).Infoln(ip+":80", err)
w.WriteMsg(localA(r, domain, ipNet))
return
}
w.WriteMsg(msg)
}
func manual(w dns.ResponseWriter, r *dns.Msg, domain, dnsServer string, ipNet net.IP) {
if !writeList.Match(domain) &&
(blockList.Match(domain) || suggestList.Match(domain)) {
if !inWriteList && (blockList.Match(domain) || suggestList.Match(domain)) {
glog.V(2).Infof("match %s suss", domain)
w.WriteMsg(localA(r, domain, ipNet))
return
}
if !inWriteList {
go mem.Remember(suggest, domain)
}
msg, err := dns.Exchange(r, dnsServer+":53")
if msg == nil { // expose any response except nil
glog.V(1).Infof("get dns of %s fail: %s", domain, err)
return
}
w.WriteMsg(msg)
}
if conf.Conf.Verbose != 0 && len(msg.Answer) != 0 {
go func() {
_, err := net.DialTimeout("tcp", domain+":http", 2*time.Second)
if err == nil || !strings.Contains(err.Error(), "timeout") {
return
}
type intelliSuggest struct {
listenIP string
timeout time.Duration
}
_, err = net.DialTimeout("tcp", domain+":https", 3*time.Second)
if err == nil || !strings.Contains(err.Error(), "timeout") {
return
}
func (i *intelliSuggest) GetOne(domain interface{}) (interface{}, error) {
addr := strings.TrimSuffix(domain.(string), ".")
glog.V(1).Infof("SUGGEST check (%s) http(s) service: %s", domain, err)
}()
{ // First: test direct connect
conn, err := net.DialTimeout("tcp", addr+":http", i.timeout)
if err == nil {
conn.Close()
return false, nil
}
glog.V(2).Infoln("first dial fail:", addr)
}
}
{ // Second: test remote connect
conn, err := net.DialTimeout("tcp", i.listenIP+":http", i.timeout/100)
if err != nil {
glog.V(1).Infoln("dial self service fail:", err)
return false, err
}
defer conn.Close()
func localA(r *dns.Msg, domain string, localIP net.IP) *dns.Msg {
m := new(dns.Msg)
m.SetReply(r)
m.Answer = []dns.RR{&dns.A{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 20},
A: localIP,
}}
return m
conn.SetReadDeadline(time.Now().Add(2 * time.Second))
if _, err = conn.Write([]byte("TRACE / HTTP/1.1\r\nHost: " + addr + "\r\n\r\n")); err != nil {
glog.V(1).Infoln("dial self service fail:", err)
return false, err
}
if _, err = conn.Read(make([]byte, 1)); err != nil && err != io.EOF {
return false, nil
}
glog.V(2).Infoln("remote dial succ:", addr)
}
{ // Third: retest direct connect
conn, err := net.DialTimeout("tcp", addr+":http", i.timeout)
if err == nil {
whiteList.Add(addr)
conn.Close()
return false, nil
}
glog.V(2).Infoln("retry dial fail:", addr)
}
// After three round test, most probably the addr is blocked
conf.AddSuggest(addr)
glog.Infof("added suggest domain: %s", addr)
return true, nil
}
+27 -18
View File
@@ -2,29 +2,36 @@ package dns
import (
"strings"
"sync"
)
type Node struct {
sep string
Node map[string]*Node
node
sep string
*sync.RWMutex
}
type node struct {
node map[string]*node
}
func NewNode(sep string) *Node {
return &Node{sep: sep, Node: map[string]*Node{}}
return &Node{node{node: map[string]*node{}}, sep, &sync.RWMutex{}}
}
func NewNodeFromRules(sep string, rules ...string) *Node {
node := NewNode(sep)
n := NewNode(sep)
for i := range rules {
node.Add(rules[i])
n.Add(rules[i])
}
return node
return n
}
func (n *Node) String() string {
n.RLock()
defer n.RUnlock()
return n.string("")
}
func (n *Node) string(prefix string) (out string) {
for key, val := range n.Node {
func (n *node) string(prefix string) (out string) {
for key, val := range n.node {
out += prefix + key + "\n" + val.string(prefix+" ")
}
return
@@ -34,20 +41,22 @@ func (n *Node) trim(item string) string {
}
func (n *Node) Add(item string) {
n.Lock()
defer n.Unlock()
n.add(strings.Split(n.trim(item), n.sep))
}
func (n *Node) add(secs []string) {
func (n *node) add(secs []string) {
length := len(secs)
switch length {
case 0:
return
case 1:
n.Node[secs[length-1]] = NewNode(n.sep)
n.node[secs[length-1]] = &node{node: map[string]*node{}}
default:
subNode, ok := n.Node[secs[length-1]]
subNode, ok := n.node[secs[length-1]]
if !ok {
subNode = NewNode(n.sep)
n.Node[secs[length-1]] = subNode
subNode = &node{node: map[string]*node{}}
n.node[secs[length-1]] = subNode
}
subNode.add(secs[:length-1])
}
@@ -57,24 +66,24 @@ func (n *Node) Match(item string) bool {
return n.matchSecs(strings.Split(n.trim(item), n.sep))
}
func (n *Node) matchSecs(secs []string) bool {
func (n *node) matchSecs(secs []string) bool {
length := len(secs)
if length == 0 {
switch len(n.Node) {
switch len(n.node) {
case 0:
return true
case 1:
_, ok := n.Node["*"]
_, ok := n.node["*"]
return ok
default:
return false
}
}
if n, ok := n.Node[secs[length-1]]; ok {
if n, ok := n.node[secs[length-1]]; ok {
return n.matchSecs(secs[:length-1])
}
_, ok := n.Node["*"]
_, ok := n.node["*"]
return ok
}
+16 -1
View File
@@ -1,23 +1,28 @@
package dns
import (
"net"
"github.com/golang/glog"
"github.com/miekg/dns"
"github.com/wweir/sower/conf"
)
var (
blockList *Node
whiteList *Node
suggestList *Node
writeList = NewNode(".")
)
func init() {
//first init
blockList = loadRules("block", conf.Conf.BlockList)
whiteList = loadRules("white", conf.Conf.WhiteList)
suggestList = loadRules("suggest", conf.Conf.BlockList)
conf.OnRefreash = append(conf.OnRefreash, func() error {
blockList = loadRules("block", conf.Conf.BlockList)
whiteList = loadRules("white", conf.Conf.WhiteList)
suggestList = loadRules("suggest", conf.Conf.Suggestions)
return nil
})
@@ -28,3 +33,13 @@ func loadRules(name string, list []string) *Node {
glog.V(2).Infof("load %s rule:\n%s", name, rule)
return rule
}
func localA(r *dns.Msg, domain string, localIP net.IP) *dns.Msg {
m := new(dns.Msg)
m.SetReply(r)
m.Answer = []dns.RR{&dns.A{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 20},
A: localIP,
}}
return m
}
+11 -4
View File
@@ -7,24 +7,31 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/golang/mock v1.2.0 // indirect
github.com/guregu/null v3.4.0+incompatible // indirect
github.com/hashicorp/golang-lru v0.5.0 // indirect
github.com/klauspost/cpuid v1.2.0 // indirect
github.com/klauspost/reedsolomon v1.8.0 // indirect
github.com/lib/pq v1.0.0 // indirect
github.com/lucas-clemente/aes12 v0.0.0-20171027163421-cd47fb39b79f // indirect
github.com/lucas-clemente/quic-go v0.10.0
github.com/lucas-clemente/quic-go v0.10.1
github.com/lucas-clemente/quic-go-certificates v0.0.0-20160823095156-d2f86524cced // indirect
github.com/miekg/dns v1.1.3
github.com/onsi/ginkgo v1.7.0 // indirect
github.com/onsi/gomega v1.4.3 // indirect
github.com/pelletier/go-toml v1.2.0
github.com/pkg/errors v0.8.1
github.com/satori/go.uuid v1.2.0 // indirect
github.com/stretchr/testify v1.3.0 // indirect
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect
github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b // indirect
github.com/tjfoc/gmsm v1.0.1 // indirect
github.com/ulule/deepcopier v0.0.0-20171107155558-ca99b135e50f // indirect
github.com/wweir/fsnotify v1.4.8
github.com/wweir/mem-go v0.0.0-20190109100331-8673ab596296
github.com/xtaci/kcp-go v5.0.7+incompatible
golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc
golang.org/x/net v0.0.0-20190110200230-915654e7eabc // indirect
golang.org/x/crypto v0.0.0-20190122013713-64072686203f
golang.org/x/net v0.0.0-20190119204137-ed066c81e75e // indirect
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect
golang.org/x/sys v0.0.0-20190114130336-2be517255631 // indirect
golang.org/x/sys v0.0.0-20190122071731-054c452bb702 // indirect
gopkg.in/yaml.v2 v2.2.2 // indirect
)
+26 -9
View File
@@ -4,6 +4,7 @@ github.com/bifurcation/mint v0.0.0-20181105071958-a14404e9a861 h1:x17NvoJaphEzay
github.com/bifurcation/mint v0.0.0-20181105071958-a14404e9a861/go.mod h1:zVt7zX3K/aDCk9Tj+VM7YymsX66ERvzCJzw8rFCX2JU=
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
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/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
@@ -14,6 +15,8 @@ github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/guregu/null v3.4.0+incompatible h1:a4mw37gBO7ypcBlTJeZGuMpSxxFTV9qFfFKgWxQSGaM=
github.com/guregu/null v3.4.0+incompatible/go.mod h1:ePGpQaN9cw0tj45IR5E5ehMvsFlLlQZAkkOXZurJ3NM=
github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
@@ -22,10 +25,12 @@ github.com/klauspost/cpuid v1.2.0 h1:NMpwD2G9JSFOE1/TJjGSo5zG7Yb2bTe7eq1jH+irmeE
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/reedsolomon v1.8.0 h1:lvvOkvk64cE1EGbBIgFk7WSOOsI1GexpuLiT7zjab6g=
github.com/klauspost/reedsolomon v1.8.0/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4=
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lucas-clemente/aes12 v0.0.0-20171027163421-cd47fb39b79f h1:sSeNEkJrs+0F9TUau0CgWTTNEwF23HST3Eq0A+QIx+A=
github.com/lucas-clemente/aes12 v0.0.0-20171027163421-cd47fb39b79f/go.mod h1:JpH9J1c9oX6otFSgdUHwUBUizmKlrMjxWnIAjff4m04=
github.com/lucas-clemente/quic-go v0.10.0 h1:xEF+pSHYAOcu+U10Meunf+DTtc8vhQDRqlA0BJ6hufc=
github.com/lucas-clemente/quic-go v0.10.0/go.mod h1:wuD+2XqEx8G9jtwx5ou2BEYBsE+whgQmlj0Vz/77PrY=
github.com/lucas-clemente/quic-go v0.10.1 h1:ipcMmYP9RT+b1YytOKGUY1qndxPGOczVEQkAVz3CZrs=
github.com/lucas-clemente/quic-go v0.10.1/go.mod h1:wuD+2XqEx8G9jtwx5ou2BEYBsE+whgQmlj0Vz/77PrY=
github.com/lucas-clemente/quic-go-certificates v0.0.0-20160823095156-d2f86524cced h1:zqEC1GJZFbGZA0tRyNZqRjep92K5fujFtFsu5ZW7Aug=
github.com/lucas-clemente/quic-go-certificates v0.0.0-20160823095156-d2f86524cced/go.mod h1:NCcRLrOTZbzhZvixZLlERbJtDtYsmMw8Jc4vS8Z0g58=
github.com/miekg/dns v1.1.3 h1:1g0r1IvskvgL8rR+AcHzUA+oFmGcQlaIm4IqakufeMM=
@@ -39,27 +44,38 @@ github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.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/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 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU=
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b h1:mnG1fcsIB1d/3vbkBak2MM0u+vhGhlQwpeimUi7QncM=
github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4=
github.com/tjfoc/gmsm v1.0.1 h1:R11HlqhXkDospckjZEihx9SW/2VW0RgdwrykyWMFOQU=
github.com/tjfoc/gmsm v1.0.1/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/wc=
github.com/ulule/deepcopier v0.0.0-20171107155558-ca99b135e50f h1:QatZ4lsJBY3x1+Imst9g95+vUl7m52dqM9Pi4aSMW8w=
github.com/ulule/deepcopier v0.0.0-20171107155558-ca99b135e50f/go.mod h1:BNLmYJ8oMJPIPpNx5968jCyUhwEU1XT3YsuOqtbo5qo=
github.com/wweir/fsnotify v1.4.8 h1:zxOoqwE5p91F3rmcYLQheoSeTlIVqwi2b5T7UlpElWE=
github.com/wweir/fsnotify v1.4.8/go.mod h1:4GuxIc23DXfJI1/LhBXG5eE/wJ4CzL+kk5M7woxVprc=
github.com/wweir/mem-go v0.0.0-20190109100331-8673ab596296 h1:/HkUfg+ZMx/tNdnyJdVlhyv+xO3A7ZlpfL9nFLWLYcc=
github.com/wweir/mem-go v0.0.0-20190109100331-8673ab596296/go.mod h1:k7rjBGWoJ+JKwvfe8juAX0zgybjo/Yo3JGkca5f/06s=
github.com/xtaci/kcp-go v5.0.7+incompatible h1:zs9tc8XRID0m+aetu3qPWZFyRt2UIMqbXIBgw+vcnlE=
github.com/xtaci/kcp-go v5.0.7+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc h1:F5tKCVGp+MUAHhKp5MZtGqAlGX3+oCsiL1Q629FL90M=
golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190122013713-64072686203f h1:u1CmMhe3a44hy8VIgpInORnI01UVaUYheqR7x9BxT3c=
golang.org/x/crypto v0.0.0-20190122013713-64072686203f/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190110200230-915654e7eabc h1:Yx9JGxI1SBhVLFjpAkWMaO1TF+xyqtHLjZpvQboJGiM=
golang.org/x/net v0.0.0-20190110200230-915654e7eabc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190119204137-ed066c81e75e h1:MDa3fSUp6MdYHouVmCCNz/zaH2a6CRcxY3VhT/K3C5Q=
golang.org/x/net v0.0.0-20190119204137-ed066c81e75e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190114130336-2be517255631 h1:g/5trXm6f9Tm+ochb21RlFNnF63lt+elB9hVBqtPu5Y=
golang.org/x/sys v0.0.0-20190114130336-2be517255631/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190122071731-054c452bb702 h1:Lk4tbZFnlyPgV+sLgTw5yGfzrlOn9kx4vSombi2FFlY=
golang.org/x/sys v0.0.0-20190122071731-054c452bb702/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
@@ -68,5 +84,6 @@ gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+1 -1
View File
@@ -22,7 +22,7 @@ func main() {
conf.Cipher, conf.Password, conf.HTTPProxy)
}
go dns.StartDNS(conf.DNSServer, conf.ClientIP, conf.ClientIPNet)
go dns.StartDNS(conf.DNSServer, conf.ClientIP)
proxy.StartClient(conf.NetType, conf.ServerAddr, conf.Cipher, conf.Password, conf.ClientIP)
}
}
+8 -5
View File
@@ -2,6 +2,7 @@ package proxy
import (
"net"
"strings"
"github.com/golang/glog"
"github.com/wweir/sower/proxy/kcp"
@@ -31,18 +32,20 @@ func NewClient(netType string) Client {
func StartClient(netType, server, cipher, password, listenIP string) {
connCh := listenLocal(listenIP, []string{":80", ":443"})
client := NewClient(netType)
ips, err := net.LookupIP(server)
if err != nil || len(ips) == 0 {
glog.Fatalln(ips, err)
if idx := strings.Index(server, ":"); idx > 0 {
ips, err := net.LookupIP(server[:idx])
if err != nil || len(ips) == 0 {
glog.Fatalln(err, ips)
}
server = ips[0].String() + server[idx:]
}
serverAddr := ips[0].String()
glog.Infoln("Client started.")
for {
conn := <-connCh
glog.V(1).Infof("new conn from (%s) to (%s)", conn.RemoteAddr(), server)
rc, err := client.Dial(serverAddr)
rc, err := client.Dial(server)
if err != nil {
conn.Close()
glog.Errorln(err)
+9 -3
View File
@@ -1,16 +1,22 @@
package tcp
import "net"
import (
"net"
"time"
)
type client struct {
DialTimeout time.Duration
}
func NewClient() *client {
return &client{}
return &client{
DialTimeout: 5 * time.Second,
}
}
func (c *client) Dial(server string) (net.Conn, error) {
conn, err := net.Dial("tcp", server)
conn, err := net.DialTimeout("tcp", server, c.DialTimeout)
if err != nil {
return nil, err
}
+3 -2
View File
@@ -34,9 +34,10 @@ func redirect(dst, src net.Conn, wg *sync.WaitGroup, exitFlag *int32) {
}
if atomic.CompareAndSwapInt32(exitFlag, 0, 1) {
// wakeup blocked goroutine
now := time.Now()
src.SetReadDeadline(now)
dst.SetWriteDeadline(now)
src.SetDeadline(now)
dst.SetDeadline(now)
} else {
src.Close()
dst.Close()