mirror of
https://github.com/wweir/sower.git
synced 2024-04-21 12:42:15 +00:00
Add intelligent rule suggestions @release
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
[](https://github.com/wweir/sower/stargazers)
|
||||
[](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
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user