mirror of
https://github.com/wweir/sower.git
synced 2024-04-21 12:42:15 +00:00
Add http proxy support
This commit is contained in:
@@ -27,10 +27,10 @@ Yet another cross platform transparent proxy tool
|
||||
| | |
|
||||
| 127.0.0.1 or other |
|
||||
| | |
|
||||
+-------^----------+---^----^---+
|
||||
| | |
|
||||
| | | +----->
|
||||
| +----------+ | |
|
||||
+-^-----^----------+---^----^---+
|
||||
| | | |
|
||||
| | | | +----->
|
||||
http(s) proxy | +----------+ | |
|
||||
2 1 1 2
|
||||
+ + + +
|
||||
blocked request normal request
|
||||
|
||||
+10
-8
@@ -17,16 +17,17 @@ import (
|
||||
var Conf = struct {
|
||||
ConfigFile string
|
||||
NetType string `toml:"net_type"`
|
||||
Cipher string `toml:cipher`
|
||||
Cipher string `toml:"cipher"`
|
||||
Password string `toml:"password"`
|
||||
|
||||
ServerPort string `toml:"server_port"`
|
||||
ServerAddr string `toml:"server_addr"`
|
||||
ServerPort string `toml:"server_port"`
|
||||
ServerAddr string `toml:"server_addr"`
|
||||
HTTPProxyPort string `toml:"http_proxy_port"`
|
||||
|
||||
DnsServer string `toml:"dns_server"`
|
||||
DNSServer string `toml:"dns_server"`
|
||||
ClientIP string `toml:"client_ip"`
|
||||
ClientIPNet net.IP `toml:"-"`
|
||||
ClearDnsCache string `toml:"clear_dns_cache"`
|
||||
ClearDNSCache string `toml:"clear_dns_cache"`
|
||||
|
||||
BlockList []string `toml:"blocklist"`
|
||||
Suggestions []string `toml:"suggestions"`
|
||||
@@ -40,7 +41,8 @@ func init() {
|
||||
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.DnsServer, "d", "114.114.114.114", "client dns server")
|
||||
flag.StringVar(&Conf.HTTPProxyPort, "H", "", "http proxy listen port")
|
||||
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")
|
||||
|
||||
if !flag.Parsed() {
|
||||
@@ -63,9 +65,9 @@ var OnRefreash = []func() error{func() error {
|
||||
Conf.ClientIPNet = net.ParseIP(Conf.ClientIP)
|
||||
|
||||
// clear dns cache
|
||||
if Conf.ClearDnsCache != "" {
|
||||
if Conf.ClearDNSCache != "" {
|
||||
ctx, _ := context.WithTimeout(context.TODO(), 5*time.Second)
|
||||
if err := exec.CommandContext(ctx, "sh", "-c", Conf.ClearDnsCache).Run(); err != nil {
|
||||
if err := exec.CommandContext(ctx, "sh", "-c", Conf.ClearDNSCache).Run(); err != nil {
|
||||
glog.Errorln(err)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -3,6 +3,7 @@ cipher="AES_128_GCM"
|
||||
password="12345678"
|
||||
server_port="5533"
|
||||
server_addr="remote-server:5533" # replce it to remote server
|
||||
http_proxy_port="8080"
|
||||
dns_server="223.5.5.5" # Alibaba public dns
|
||||
client_ip="127.0.0.1"
|
||||
# clear_dns_cache="killall -HUP mDNSResponder"
|
||||
@@ -44,6 +45,7 @@ blocklist=[
|
||||
"synchrony-cdn.atlassian.com",
|
||||
"avatar-cdn.atlassian.com",
|
||||
"*.medium.com",
|
||||
"*.us-east-1.prod.public.atl-paas.net",
|
||||
"accounts-static.cdn.mozilla.net", # firefox
|
||||
"*.services.mozilla.com",
|
||||
"pocket-image-cache.com", # pocket
|
||||
@@ -73,8 +75,6 @@ blocklist=[
|
||||
"download.apkpure.com",
|
||||
"*.nytimes.com", # New York times
|
||||
"*.nyt.com",
|
||||
"bandwagonhost.com", # bandwagonhost
|
||||
"www.bwh1.net",
|
||||
"*.akadns.net", # suggestions
|
||||
"*.haxx.se",
|
||||
"shadowsocks.org",
|
||||
|
||||
@@ -13,8 +13,14 @@ func main() {
|
||||
|
||||
if conf.ServerAddr == "" {
|
||||
proxy.StartServer(conf.NetType, conf.ServerPort, conf.Cipher, conf.Password)
|
||||
|
||||
} else {
|
||||
go dns.StartDNS(conf.DnsServer, conf.ClientIP, conf.ClientIPNet)
|
||||
if conf.HTTPProxyPort != "" {
|
||||
go proxy.StartHttpProxy(conf.NetType, conf.ServerAddr,
|
||||
conf.Cipher, conf.Password, conf.ClientIP, conf.HTTPProxyPort)
|
||||
}
|
||||
|
||||
go dns.StartDNS(conf.DNSServer, conf.ClientIP, conf.ClientIPNet)
|
||||
proxy.StartClient(conf.NetType, conf.ServerAddr, conf.Cipher, conf.Password, conf.ClientIP)
|
||||
}
|
||||
}
|
||||
|
||||
+10
-7
@@ -14,20 +14,23 @@ type Client interface {
|
||||
Dial(server string) (net.Conn, error)
|
||||
}
|
||||
|
||||
func StartClient(netType, server, cipher, password, listenIP string) {
|
||||
var connCh = listenLocal(listenIP, []string{":80", ":443"})
|
||||
|
||||
var client Client
|
||||
func NewClient(netType string) Client {
|
||||
switch netType {
|
||||
case QUIC.String():
|
||||
client = quic.NewClient()
|
||||
return quic.NewClient()
|
||||
case KCP.String():
|
||||
client = kcp.NewClient()
|
||||
return kcp.NewClient()
|
||||
case TCP.String():
|
||||
client = tcp.NewClient()
|
||||
return tcp.NewClient()
|
||||
default:
|
||||
glog.Fatalln("invalid net type: " + netType)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func StartClient(netType, server, cipher, password, listenIP string) {
|
||||
connCh := listenLocal(listenIP, []string{":80", ":443"})
|
||||
client := NewClient(netType)
|
||||
|
||||
glog.Infoln("Client started.")
|
||||
for {
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/wweir/sower/shadow"
|
||||
)
|
||||
|
||||
func StartHttpProxy(netType, server, cipher, password, listenIP, port string) {
|
||||
if port[0] != ':' {
|
||||
port = ":" + port
|
||||
}
|
||||
|
||||
client := NewClient(netType)
|
||||
|
||||
srv := &http.Server{
|
||||
Addr: listenIP + port,
|
||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == http.MethodConnect {
|
||||
httpsProxy(w, r, client, server, cipher, password)
|
||||
} else {
|
||||
httpProxy(w, r, client, server, cipher, password)
|
||||
}
|
||||
}),
|
||||
// Disable HTTP/2.
|
||||
TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),
|
||||
}
|
||||
|
||||
glog.Fatalln(srv.ListenAndServe())
|
||||
}
|
||||
|
||||
func httpsProxy(w http.ResponseWriter, r *http.Request, client Client, server, cipher, password string) {
|
||||
// remote conn
|
||||
rc, err := client.Dial(server)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
rc = shadow.Shadow(rc, cipher, password)
|
||||
|
||||
// local conn
|
||||
w.WriteHeader(http.StatusOK)
|
||||
hijacker, ok := w.(http.Hijacker)
|
||||
if !ok {
|
||||
http.Error(w, "Hijacking not supported", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
conn, _, err := hijacker.Hijack()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusServiceUnavailable)
|
||||
}
|
||||
|
||||
relay(rc, conn)
|
||||
}
|
||||
|
||||
func httpProxy(w http.ResponseWriter, req *http.Request, client Client, server, cipher, password string) {
|
||||
roundTripper := &http.Transport{
|
||||
DialContext: func(context.Context, string, string) (net.Conn, error) {
|
||||
conn, err := client.Dial(server)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return shadow.Shadow(conn, cipher, password), nil
|
||||
},
|
||||
MaxIdleConns: 100,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
}
|
||||
|
||||
resp, err := roundTripper.RoundTrip(req)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
for k, vs := range resp.Header {
|
||||
for _, v := range vs {
|
||||
w.Header().Add(k, v)
|
||||
}
|
||||
}
|
||||
w.WriteHeader(resp.StatusCode)
|
||||
io.Copy(w, resp.Body)
|
||||
}
|
||||
+1
-1
@@ -15,7 +15,7 @@ type server struct {
|
||||
SockBuf int
|
||||
}
|
||||
|
||||
func NewServer(password string) *server {
|
||||
func NewServer() *server {
|
||||
return &server{
|
||||
DataShard: 10,
|
||||
ParityShard: 3,
|
||||
|
||||
+9
-6
@@ -16,26 +16,29 @@ type Server interface {
|
||||
Listen(port string) (<-chan net.Conn, error)
|
||||
}
|
||||
|
||||
func StartServer(netType, port, cipher, password string) {
|
||||
var server Server
|
||||
func NewServer(netType string) Server {
|
||||
switch netType {
|
||||
case QUIC.String():
|
||||
server = quic.NewServer()
|
||||
return quic.NewServer()
|
||||
case KCP.String():
|
||||
server = kcp.NewServer(password)
|
||||
return kcp.NewServer()
|
||||
case TCP.String():
|
||||
server = tcp.NewServer()
|
||||
return tcp.NewServer()
|
||||
default:
|
||||
glog.Fatalln("invalid net type: " + netType)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func StartServer(netType, port, cipher, password string) {
|
||||
if port == "" {
|
||||
glog.Fatalln("port must set")
|
||||
}
|
||||
if !strings.Contains(port, ":") {
|
||||
port = ":" + port
|
||||
}
|
||||
connCh, err := server.Listen(port)
|
||||
|
||||
connCh, err := NewServer(netType).Listen(port)
|
||||
if err != nil {
|
||||
glog.Fatalf("listen %v fail: %s", port, err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user