From 3d6ee5e376dcdce2a9387b30cae94f3b99f2230d Mon Sep 17 00:00:00 2001 From: wweir Date: Tue, 10 Sep 2024 07:40:08 +0800 Subject: [PATCH] feat: support http(s)_proxy --- cmd/sower/main.go | 30 +++++++++++++++++++---- cmd/sower/proxy.go | 61 ++++++++++++++++++++++++++++++++++++++++++++-- router/util.go | 22 +++++++++++++++++ 3 files changed, 106 insertions(+), 7 deletions(-) create mode 100644 router/util.go diff --git a/cmd/sower/main.go b/cmd/sower/main.go index a9a2266..31ad8d2 100644 --- a/cmd/sower/main.go +++ b/cmd/sower/main.go @@ -34,10 +34,11 @@ var ( } DNS struct { - Disable bool `default:"false" usage:"disable DNS proxy"` - Serve string `default:"127.0.0.1" required:"true" usage:"dns server ip"` - Serve6 string `usage:"dns server ipv6, eg: ::1"` - Fallback string `default:"223.5.5.5" required:"true" usage:"fallback dns server"` + Disable bool `default:"false" usage:"disable DNS proxy"` + Serve string `default:"127.0.0.1" required:"true" usage:"dns server ip"` + Serve6 string `usage:"dns server ipv6, eg: ::1"` + ServeIface string `usage:"use the IP in the net interface, if serve ip not setted. eg: eth0"` + Fallback string `default:"223.5.5.5" required:"true" usage:"fallback dns server"` } Socks5 struct { Disable bool `default:"false" usage:"disable sock5 proxy"` @@ -87,6 +88,25 @@ func init() { Msg("Load config") } + if conf.DNS.ServeIface != "" { + iface, err := net.InterfaceByName(conf.DNS.ServeIface) + log.DebugFatal(err).Str("iface", conf.DNS.ServeIface).Msg("get iface") + addrs, err := iface.Addrs() + log.InfoFatal(err).Str("iface", conf.DNS.ServeIface).Msg("get iface addrs") + for _, addr := range addrs { + ip, _, err := net.ParseCIDR(addr.String()) + log.InfoFatal(err).Str("iface", conf.DNS.ServeIface). + Msg("parse iface addr: " + addr.String()) + + if ip.To4() != nil && conf.DNS.Serve == "" { + conf.DNS.Serve = ip.String() + } + if ip.To16() != nil && conf.DNS.Serve6 == "" { + conf.DNS.Serve = ip.String() + } + } + } + conf.Router.Direct.Rules = append(conf.Router.Direct.Rules, conf.Remote.Addr, "**.in-addr.arpa", "**.ip6.arpa") log.Info(). @@ -106,7 +126,6 @@ func main() { if conf.DNS.Disable { log.Info().Msg("DNS proxy disabled") - } else { ips := make([]string, 0, 2) if strings.TrimSpace(conf.DNS.Serve) != "" { @@ -169,6 +188,7 @@ func loadRule(rule *suffixtree.Node, proxyDial router.ProxyDialFn, file, linePre } rule.GC() } + func fetchRuleFile(proxyDial router.ProxyDialFn, file string) <-chan string { if file == "" { return make(chan string) diff --git a/cmd/sower/proxy.go b/cmd/sower/proxy.go index e078487..f81272b 100644 --- a/cmd/sower/proxy.go +++ b/cmd/sower/proxy.go @@ -150,7 +150,23 @@ func ServeSocks5(ln net.Listener, r *router.Router) { go ServeSocks5(ln, r) defer conn.Close() - addr, err := socks5.New().Unwrap(conn) + teeConn := teeconn.New(conn) + + buf1 := make([]byte, 1) + if _, err := teeConn.Read(buf1); err != nil { + log.Warn().Err(err). + Msg("read socks5 version") + return + } + + if buf1[0] != 5 { + teeConn.Reread() + serveHttpProxy(teeConn, r) + return + } + + teeConn.Stop().Reread() + addr, err := socks5.New().Unwrap(teeConn) if err != nil { log.Warn().Err(err). Msgf("parse socks5 target: %s", addr) @@ -158,5 +174,46 @@ func ServeSocks5(ln net.Listener, r *router.Router) { } host, port := addr.(*socks5.AddrHead).Addr() - r.RouteHandle(conn, host, port) + r.RouteHandle(teeConn, host, port) +} + +func serveHttpProxy(teeConn *teeconn.Conn, r *router.Router) { + req, err := http.ReadRequest(bufio.NewReader(teeConn)) + if err != nil { + log.Warn().Err(err). + Msg("read http request") + return + } + + teeConn.Stop() + switch req.Method { + case "CONNECT": + if _, err := teeConn.Write([]byte(req.Proto + " 200 Connection established\r\n\r\n")); err != nil { + log.Warn().Err(err). + Msg("write https proxy response") + return + } + + host, port, err := router.ParseHostPort(req.Host, 443) + if err != nil { + log.Warn().Err(err). + Msg("parse https_proxy target") + return + } + + rc, err := r.ProxyDial("tcp", host, port) + if err != nil { + log.Warn().Err(err). + Str("host", host). + Msg("dial proxy") + return + } + defer rc.Close() + + relay.Relay(teeConn, rc) + + default: + teeConn.Reread() + r.RouteHandle(teeConn, req.Host, 80) + } } diff --git a/router/util.go b/router/util.go new file mode 100644 index 0000000..790b76b --- /dev/null +++ b/router/util.go @@ -0,0 +1,22 @@ +package router + +import ( + "net" + "strconv" +) + +func ParseHostPort(hostport string, defaultPort uint16) (string, uint16, error) { + host, port, err := net.SplitHostPort(hostport) + if err != nil { + return "", 0, err + } + if port == "" { + return host, defaultPort, nil + } + + portInt, err := strconv.ParseUint(port, 10, 16) + if err != nil { + return "", 0, err + } + return host, uint16(portInt), nil +}