mirror of
https://github.com/wweir/sower.git
synced 2024-04-21 12:42:15 +00:00
Changes for unit test
This commit is contained in:
@@ -24,15 +24,20 @@ kill:
|
||||
sudo pkill -9 sower || true
|
||||
|
||||
client: build kill
|
||||
sudo $(PWD)/sower
|
||||
sudo $(PWD)/sower -f '' -s 127.0.0.1:5533 -H "127.0.0.1:8080"
|
||||
|
||||
server: build kill
|
||||
$(PWD)/sower -n TCP -v 1
|
||||
server: build
|
||||
$(PWD)/sower -f ''
|
||||
|
||||
run: build kill
|
||||
$(PWD)/sower -n TCP -v 1 &
|
||||
sudo $(PWD)/sower &
|
||||
$(PWD)/sower -f '' &
|
||||
sudo $(PWD)/sower -f '' -s 127.0.0.1:5533 -H "127.0.0.1:8080" &
|
||||
|
||||
@sleep 1
|
||||
curl localhost
|
||||
HTTP_PROXY=http://127.0.0.1:8080 curl http://baidu.com || true
|
||||
@echo
|
||||
HTTPS_PROXY=http://127.0.0.1:8080 curl https://baidu.com || true
|
||||
@echo
|
||||
|
||||
@sleep 1
|
||||
@sudo pkill -9 sower || true
|
||||
|
||||
+2
-2
@@ -23,11 +23,11 @@ func initArgs() {
|
||||
flag.StringVar(&Conf.Cipher, "C", "AES_128_GCM", "cipher type: "+strings.Join(shadow.ListCiphers(), ","))
|
||||
flag.StringVar(&Conf.Password, "p", "12345678", "password")
|
||||
flag.StringVar(&Conf.ServerPort, "P", "5533", "server mode listen port")
|
||||
flag.StringVar(&Conf.ServerAddr, "s", "", "server IP (run in CLIENT MODE if set)")
|
||||
flag.StringVar(&Conf.ServerAddr, "s", "", "server IP (run in CLIENT mode if set)")
|
||||
flag.StringVar(&Conf.HTTPProxy, "H", "", "http proxy listen addr")
|
||||
flag.StringVar(&Conf.DNSServer, "d", "114.114.114.114", "client dns server")
|
||||
flag.StringVar(&Conf.ClientIP, "c", "127.0.0.1", "client dns service redirect IP")
|
||||
flag.StringVar(&Conf.SuggestLevel, "S", "SPEEDUP", "suggest level setting: "+strings.Join(dns.ListSuggestLevels(), ","))
|
||||
flag.StringVar(&Conf.SuggestLevel, "l", "SPEEDUP", "suggest level setting: "+strings.Join(dns.ListSuggestLevels(), ","))
|
||||
flag.BoolVar(&Conf.VersionOnly, "V", false, "print sower version")
|
||||
|
||||
if !flag.Parsed() {
|
||||
|
||||
+11
-2
@@ -1,9 +1,18 @@
|
||||
package dns
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetDefaultDNSServer(t *testing.T) {
|
||||
t.Skip("skip for some enviroment not support dhcp and permission")
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
case "darwin":
|
||||
default:
|
||||
t.Skip("skip for some enviroment not support dhcp and permission set")
|
||||
return
|
||||
}
|
||||
|
||||
if got, err := GetDefaultDNSServer(); err != nil {
|
||||
t.Errorf("GetDefaultDNSServer() return error: %s", err)
|
||||
|
||||
+27
-38
@@ -10,14 +10,15 @@ import (
|
||||
"github.com/golang/glog"
|
||||
"github.com/miekg/dns"
|
||||
mem "github.com/wweir/mem-go"
|
||||
"github.com/wweir/sower/util"
|
||||
)
|
||||
|
||||
const colon = byte(':')
|
||||
|
||||
func StartDNS(dnsServer, listenIP string, suggestCh chan<- string, suggestLevel string) {
|
||||
func StartDNS(dnsServer, listenIP string, suggestCh chan<- string, level string) {
|
||||
ip := net.ParseIP(listenIP)
|
||||
|
||||
suggest := &intelliSuggest{suggestCh, parseSuggestLevel(suggestLevel), listenIP, time.Second}
|
||||
suggest := &intelliSuggest{suggestCh, parseSuggestLevel(level), listenIP, time.Second}
|
||||
mem.DefaultCache = mem.New(time.Hour)
|
||||
|
||||
dhcpCh := make(chan struct{})
|
||||
@@ -93,18 +94,7 @@ func matchAndServe(w dns.ResponseWriter, r *dns.Msg, domain, listenIP, dnsServer
|
||||
return
|
||||
}
|
||||
|
||||
if !inWriteList {
|
||||
go func() {
|
||||
ip, err := net.LookupIP(domain)
|
||||
if err != nil || len(ip) == 0 {
|
||||
glog.V(1).Infoln(ip, err)
|
||||
return
|
||||
}
|
||||
|
||||
mem.Remember(suggest, addr{domain, ip[0].String()})
|
||||
}()
|
||||
}
|
||||
|
||||
go mem.Remember(suggest, domain)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
@@ -127,40 +117,39 @@ func matchAndServe(w dns.ResponseWriter, r *dns.Msg, domain, listenIP, dnsServer
|
||||
}
|
||||
|
||||
type intelliSuggest struct {
|
||||
suggestCh chan<- string
|
||||
suggestLevel suggestLevel
|
||||
listenIP string
|
||||
timeout time.Duration
|
||||
}
|
||||
type addr struct {
|
||||
domain string
|
||||
ip string
|
||||
suggestCh chan<- string
|
||||
level level
|
||||
listenIP string
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
func (i *intelliSuggest) GetOne(key interface{}) (iface interface{}, e error) {
|
||||
iface, e = struct{}{}, nil
|
||||
if i.suggestLevel == DISABLE {
|
||||
if i.level == DISABLE {
|
||||
return
|
||||
}
|
||||
|
||||
domain := key.(addr).domain
|
||||
ip := key.(addr).ip
|
||||
|
||||
// kill deadloop, for ugly wildcard setting dns setting
|
||||
domain = strings.TrimSuffix(domain, ".")
|
||||
domain := strings.TrimSuffix(key.(string), ".")
|
||||
if strings.Count(domain, ".") > 10 {
|
||||
return
|
||||
}
|
||||
|
||||
ip, err := net.LookupIP(domain)
|
||||
if err != nil || len(ip) == 0 {
|
||||
glog.V(1).Infoln(domain, ip, err)
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
pings = [...]struct {
|
||||
viaAddr string
|
||||
port Port
|
||||
port util.Port
|
||||
}{
|
||||
{ip, HTTP},
|
||||
{i.listenIP, HTTP},
|
||||
{ip, HTTPS},
|
||||
{i.listenIP, HTTPS},
|
||||
{ip[0].String(), util.HTTP},
|
||||
{i.listenIP, util.HTTP},
|
||||
{ip[0].String(), util.HTTPS},
|
||||
{i.listenIP, util.HTTPS},
|
||||
}
|
||||
protos = [...]*int32{
|
||||
new(int32), /*HTTP*/
|
||||
@@ -170,19 +159,19 @@ func (i *intelliSuggest) GetOne(key interface{}) (iface interface{}, e error) {
|
||||
)
|
||||
for idx := range pings {
|
||||
go func(idx int) {
|
||||
if err := HTTPPing(pings[idx].viaAddr, domain, pings[idx].port, i.timeout); err != nil {
|
||||
if err := util.HTTPPing(pings[idx].viaAddr, domain, pings[idx].port, i.timeout); err != nil {
|
||||
// local ping fail
|
||||
if pings[idx].viaAddr == ip {
|
||||
atomic.AddInt32(score, 1)
|
||||
glog.V(1).Infof("local ping %s fail", domain)
|
||||
} else {
|
||||
if pings[idx].viaAddr == i.listenIP {
|
||||
atomic.AddInt32(score, -1)
|
||||
glog.V(1).Infof("remote ping %s fail", domain)
|
||||
} else {
|
||||
atomic.AddInt32(score, 1)
|
||||
glog.V(1).Infof("local ping %s fail", domain)
|
||||
}
|
||||
|
||||
// remote ping faster
|
||||
} else if pings[idx].viaAddr == i.listenIP {
|
||||
if atomic.CompareAndSwapInt32(protos[idx/2], 0, 1) && i.suggestLevel == SPEEDUP {
|
||||
if atomic.CompareAndSwapInt32(protos[idx/2], 0, 1) && i.level == SPEEDUP {
|
||||
atomic.AddInt32(score, 1)
|
||||
}
|
||||
glog.V(1).Infof("remote ping %s faster", domain)
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// Code generated by "stringer -type=level util.go"; DO NOT EDIT.
|
||||
|
||||
package dns
|
||||
|
||||
import "strconv"
|
||||
|
||||
const _level_name = "DISABLEBLOCKSPEEDUPlevelEnd"
|
||||
|
||||
var _level_index = [...]uint8{0, 7, 12, 19, 27}
|
||||
|
||||
func (i level) String() string {
|
||||
if i < 0 || i >= level(len(_level_index)-1) {
|
||||
return "level(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _level_name[_level_index[i]:_level_index[i+1]]
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
// Code generated by "stringer -type=suggestLevel util.go"; DO NOT EDIT.
|
||||
|
||||
package dns
|
||||
|
||||
import "strconv"
|
||||
|
||||
const _suggestLevel_name = "DISABLEBLOCKSPEEDUPlevelEnd"
|
||||
|
||||
var _suggestLevel_index = [...]uint8{0, 7, 12, 19, 27}
|
||||
|
||||
func (i suggestLevel) String() string {
|
||||
if i < 0 || i >= suggestLevel(len(_suggestLevel_index)-1) {
|
||||
return "suggestLevel(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _suggestLevel_name[_suggestLevel_index[i]:_suggestLevel_index[i+1]]
|
||||
}
|
||||
+8
-8
@@ -46,11 +46,11 @@ func localA(r *dns.Msg, domain string, localIP net.IP) *dns.Msg {
|
||||
return m
|
||||
}
|
||||
|
||||
//go:generate stringer -type=suggestLevel $GOFILE
|
||||
type suggestLevel int32
|
||||
//go:generate stringer -type=level $GOFILE
|
||||
type level int32
|
||||
|
||||
const (
|
||||
DISABLE suggestLevel = iota
|
||||
DISABLE level = iota
|
||||
BLOCK
|
||||
SPEEDUP
|
||||
levelEnd
|
||||
@@ -58,19 +58,19 @@ const (
|
||||
|
||||
func ListSuggestLevels() []string {
|
||||
list := make([]string, 0, int(levelEnd))
|
||||
for i := suggestLevel(0); i < levelEnd; i++ {
|
||||
for i := level(0); i < levelEnd; i++ {
|
||||
list = append(list, i.String())
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func parseSuggestLevel(level string) suggestLevel {
|
||||
for i := suggestLevel(0); i < levelEnd; i++ {
|
||||
if level == i.String() {
|
||||
func parseSuggestLevel(suggestLevel string) level {
|
||||
for i := level(0); i < levelEnd; i++ {
|
||||
if suggestLevel == i.String() {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
glog.Exitln("invalid suggest level: " + level)
|
||||
glog.Exitln("invalid suggest level: " + suggestLevel)
|
||||
return levelEnd
|
||||
}
|
||||
|
||||
+2
-2
@@ -62,11 +62,11 @@ func StartClient(tran transport.Transport, isSocks5 bool, server, cipher, passwo
|
||||
|
||||
case !isSocks5 && isHttp:
|
||||
rc = shadow.Shadow(rc, cipher, password)
|
||||
rc = parser.NewHttpProtocol(rc)
|
||||
rc = parser.NewHttpConn(rc)
|
||||
|
||||
case !isSocks5 && !isHttp:
|
||||
rc = shadow.Shadow(rc, cipher, password)
|
||||
rc = parser.NewHttpsProtocol(rc, "443")
|
||||
rc = parser.NewHttpsConn(rc, "443")
|
||||
}
|
||||
|
||||
go relay(conn, rc)
|
||||
|
||||
+3
-3
@@ -58,8 +58,8 @@ func httpProxy(w http.ResponseWriter, r *http.Request,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
conn = parser.NewHttpProtocol(conn)
|
||||
return shadow.Shadow(conn, cipher, password), nil
|
||||
conn = shadow.Shadow(conn, cipher, password)
|
||||
return parser.NewHttpConn(conn), nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ func httpsProxy(w http.ResponseWriter, r *http.Request,
|
||||
|
||||
} else {
|
||||
rc = shadow.Shadow(rc, cipher, password)
|
||||
rc = parser.NewHttpsProtocol(rc, port)
|
||||
rc = parser.NewHttpsConn(rc, port)
|
||||
}
|
||||
|
||||
relay(rc, conn)
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/wweir/sower/util"
|
||||
)
|
||||
|
||||
func TestParseAddr1(t *testing.T) {
|
||||
c1, c2 := net.Pipe()
|
||||
|
||||
go func() {
|
||||
c1 = NewHttpConn(c1)
|
||||
req, _ := http.NewRequest("GET", "http://wweir.cc", bytes.NewReader([]byte{1, 2, 3}))
|
||||
req.Write(c1)
|
||||
}()
|
||||
|
||||
c2, host, port, err := ParseAddr(c2)
|
||||
|
||||
if err != nil || host != "wweir.cc" || port != "80" {
|
||||
t.Error(err, host, port)
|
||||
}
|
||||
|
||||
req, err := http.ReadRequest(bufio.NewReader(c2))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil || len(data) != 3 || data[0] != 1 {
|
||||
t.Error(err, data)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseAddr2(t *testing.T) {
|
||||
c1, c2 := net.Pipe()
|
||||
|
||||
go func() {
|
||||
c1 = NewHttpsConn(c1, "443")
|
||||
c1.Write(util.HTTPS.PingMsg("wweir.cc"))
|
||||
}()
|
||||
|
||||
_, host, port, err := ParseAddr(c2)
|
||||
|
||||
if err != nil || host != "wweir.cc" || port != "443" {
|
||||
t.Error(err, host, port)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseAddr3(t *testing.T) {
|
||||
c1, c2 := net.Pipe()
|
||||
|
||||
go func() {
|
||||
c1 = NewOtherConn(c1, "wweir.cc", "1080")
|
||||
c1.Write(util.HTTPS.PingMsg("wweir.cc"))
|
||||
}()
|
||||
|
||||
_, host, port, err := ParseAddr(c2)
|
||||
|
||||
if err != nil || host != "wweir.cc" || port != "1080" {
|
||||
t.Error(err, host, port)
|
||||
}
|
||||
}
|
||||
+4
-6
@@ -14,7 +14,7 @@ func StartServer(tran transport.Transport, port, cipher, password string) {
|
||||
if port == "" {
|
||||
glog.Fatalln("port must set")
|
||||
}
|
||||
if !strings.Contains(port, ":") {
|
||||
if !strings.HasPrefix(port, ":") {
|
||||
port = ":" + port
|
||||
}
|
||||
|
||||
@@ -25,14 +25,12 @@ func StartServer(tran transport.Transport, port, cipher, password string) {
|
||||
|
||||
glog.Infoln("Server started.")
|
||||
for {
|
||||
conn := <-connCh
|
||||
conn = shadow.Shadow(conn, cipher, password)
|
||||
|
||||
go handle(conn)
|
||||
go handle(<-connCh, cipher, password)
|
||||
}
|
||||
}
|
||||
|
||||
func handle(conn net.Conn) {
|
||||
func handle(conn net.Conn, cipher, password string) {
|
||||
conn = shadow.Shadow(conn, cipher, password)
|
||||
conn, host, port, err := parser.ParseAddr(conn)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
|
||||
@@ -8,11 +8,11 @@ import (
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
)
|
||||
|
||||
//go:generate stringer -type=cipherType $GOFILE
|
||||
type cipherType int
|
||||
//go:generate stringer -type=typ $GOFILE
|
||||
type typ int
|
||||
|
||||
const (
|
||||
AES_128_GCM cipherType = iota
|
||||
AES_128_GCM typ = iota
|
||||
AES_192_GCM
|
||||
AES_256_GCM
|
||||
CHACHA20_IETF_POLY1305
|
||||
@@ -22,15 +22,15 @@ const (
|
||||
|
||||
func ListCiphers() []string {
|
||||
list := make([]string, 0, int(cipherEnd))
|
||||
for i := cipherType(0); i < cipherEnd; i++ {
|
||||
for i := typ(0); i < cipherEnd; i++ {
|
||||
list = append(list, i.String())
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func pickCipher(cipherType, password string) (cipher.AEAD, error) {
|
||||
func pickCipher(typ, password string) (cipher.AEAD, error) {
|
||||
var blockSize int
|
||||
switch cipherType {
|
||||
switch typ {
|
||||
case AES_128_GCM.String():
|
||||
blockSize = 16
|
||||
case AES_192_GCM.String():
|
||||
@@ -44,7 +44,7 @@ func pickCipher(cipherType, password string) (cipher.AEAD, error) {
|
||||
return chacha20poly1305.NewX(genKey(password, 256))
|
||||
|
||||
default:
|
||||
return nil, errors.New("do not support cipher type: " + cipherType)
|
||||
return nil, errors.New("do not support cipher type: " + typ)
|
||||
}
|
||||
|
||||
// aes gcm
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
// Code generated by "stringer -type=cipherType cipher.go"; DO NOT EDIT.
|
||||
|
||||
package shadow
|
||||
|
||||
import "strconv"
|
||||
|
||||
const _cipherType_name = "AES_128_GCMAES_192_GCMAES_256_GCMCHACHA20_IETF_POLY1305XCHACHA20_IETF_POLY1305cipherEnd"
|
||||
|
||||
var _cipherType_index = [...]uint8{0, 11, 22, 33, 55, 78, 87}
|
||||
|
||||
func (i cipherType) String() string {
|
||||
if i < 0 || i >= cipherType(len(_cipherType_index)-1) {
|
||||
return "cipherType(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _cipherType_name[_cipherType_index[i]:_cipherType_index[i+1]]
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package shadow
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestShadow(t *testing.T) {
|
||||
c1, c2 := net.Pipe()
|
||||
|
||||
go func() {
|
||||
conn := Shadow(c1, "AES_128_GCM", "12345678")
|
||||
conn.Write([]byte{1, 2})
|
||||
}()
|
||||
|
||||
conn := Shadow(c2, "AES_128_GCM", "12345678")
|
||||
buf := make([]byte, 3)
|
||||
n, _ := conn.Read(buf)
|
||||
if n!=2|| buf[0] != 1 || buf[1] != 2 {
|
||||
t.Error(buf)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// Code generated by "stringer -type=typ cipher.go"; DO NOT EDIT.
|
||||
|
||||
package shadow
|
||||
|
||||
import "strconv"
|
||||
|
||||
const _typ_name = "AES_128_GCMAES_192_GCMAES_256_GCMCHACHA20_IETF_POLY1305XCHACHA20_IETF_POLY1305cipherEnd"
|
||||
|
||||
var _typ_index = [...]uint8{0, 11, 22, 33, 55, 78, 87}
|
||||
|
||||
func (i typ) String() string {
|
||||
if i < 0 || i >= typ(len(_typ_index)-1) {
|
||||
return "typ(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _typ_name[_typ_index[i]:_typ_index[i+1]]
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package dns
|
||||
package util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -18,7 +18,7 @@ func HTTPPing(viaHost, domain string, port Port, timeout time.Duration) (err err
|
||||
defer conn.Close()
|
||||
|
||||
conn.SetDeadline(time.Now().Add(timeout))
|
||||
if _, err = conn.Write(port.pingMsg(domain)); err != nil {
|
||||
if _, err = conn.Write(port.PingMsg(domain)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func (p Port) JoinAddr(addr string) string {
|
||||
}
|
||||
}
|
||||
|
||||
func (p Port) pingMsg(domain string) []byte {
|
||||
func (p Port) PingMsg(domain string) []byte {
|
||||
switch p {
|
||||
case HTTP:
|
||||
return []byte("TRACE / HTTP/1.1\r\nHost: " + domain + "\r\n\r\n")
|
||||
@@ -1,11 +1,18 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPickInterface(t *testing.T) {
|
||||
t.Skip("skip for some enviroment not have net interface")
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
case "darwin":
|
||||
default:
|
||||
t.Skip("skip for some enviroment not have net interface")
|
||||
return
|
||||
}
|
||||
|
||||
got, err := PickInterface()
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user