Compare commits

...

10 Commits

Author SHA1 Message Date
bel
5fccea247e dont close until they close themself 2023-04-15 17:36:06 -06:00
bel
7d82bdcdfe Merge branch 'master' of https://gogs.inhome.blapointe.com/local/mfproxy 2023-04-15 17:11:09 -06:00
bel
e1b45989df blind tcp proxy gogo 2023-04-15 17:10:54 -06:00
bel
43152b1296 rename 2023-04-15 15:25:43 -06:00
bel
45a0dc5b6b nvm nvm 2023-04-15 15:20:47 -06:00
bel
5f25222e64 nvm 2023-04-15 15:20:09 -06:00
bel
cbb7de1453 stub 2023-04-15 15:13:24 -06:00
bel
83e848f262 accept -socks and -proxy 2023-04-15 15:10:38 -06:00
Bel LaPointe
4559e269e0 race 2022-12-27 19:49:34 -05:00
Bel LaPointe
c4a1c9ce98 time limit dns caching, and tcp6 if tcp6 specifically 2022-12-26 14:34:51 -05:00
6 changed files with 130 additions and 25 deletions

View File

@@ -15,6 +15,8 @@ type Config struct {
TLSInsecure bool
Limiter *rate.Limiter
DNS string
TCPProxy string
TCPProxyTLS bool
}
func NewConfig() *Config {
@@ -23,9 +25,11 @@ func NewConfig() *Config {
as.Append(args.INT, "p", "port to listen on", 61113)
as.Append(args.INT, "kbps", "kilobytes per sec limit", -1)
as.Append(args.BOOL, "tls-insecure", "permit tls insecure", false)
as.Append(args.BOOL, "tcp-proxy-tls", "tcp proxy uses tls", true)
as.Append(args.DURATION, "t", "timeout", time.Minute)
as.Append(args.STRING, "dns", "dns ip:port", "1.1.1.1:53")
as.Append(args.STRING, "tcp-proxy", "host:port to tcp proxy to instead", "")
if err := as.Parse(); err != nil {
panic(err)
@@ -43,5 +47,7 @@ func NewConfig() *Config {
TLSInsecure: as.GetBool("tls-insecure"),
Limiter: limiter,
DNS: as.GetString("dns"),
TCPProxy: as.GetString("tcp-proxy"),
TCPProxyTLS: as.GetBool("tcp-proxy-tls"),
}
}

6
go.mod
View File

@@ -7,6 +7,10 @@ require (
local/args v0.0.0-00010101000000-000000000000
)
require gopkg.in/yaml.v2 v2.4.0 // indirect
require (
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 // indirect
golang.org/x/net v0.9.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
replace local/args => ../../local/args

4
go.sum
View File

@@ -1,3 +1,7 @@
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ=
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=

11
main.go
View File

@@ -7,10 +7,17 @@ import (
func main() {
config := NewConfig()
server := NewServer(config)
log.Printf("config: %+v", *config)
if config.TCPProxy != "" {
server := NewTCPServer(config)
if err := server.Listen(); err != nil {
panic(err)
}
} else {
server := NewServer(config)
if err := http.ListenAndServe(config.Listen, server); err != nil {
panic(err)
}
}
}

View File

@@ -10,6 +10,7 @@ import (
"net"
"net/http"
"strings"
"sync"
"time"
"golang.org/x/time/rate"
@@ -20,7 +21,22 @@ type Server struct {
resolver *net.Resolver
limiter *rate.Limiter
Timeout time.Duration
dnsCache map[string]string
dnsCacheLock sync.Mutex
dnsCache map[string]dns
}
type dns struct {
result string
err error
ts time.Time
}
func (dns dns) ok() bool {
dur := time.Minute * 10
if dns.err != nil {
dur = time.Minute * 1
}
return time.Since(dns.ts) < dur
}
func NewServer(c *Config) *Server {
@@ -28,11 +44,11 @@ func NewServer(c *Config) *Server {
PreferGo: true,
Dial: func(ctx context.Context, network, addr string) (net.Conn, error) {
d := net.Dialer{Timeout: c.Timeout}
return d.DialContext(ctx, network, c.DNS)
},
if c.DNS != "" {
addr = c.DNS
}
if c.DNS == "" {
resolver = &net.Resolver{}
return d.DialContext(ctx, network, addr)
},
}
transport := &http.Transport{}
transport.TLSClientConfig = &tls.Config{
@@ -43,7 +59,7 @@ func NewServer(c *Config) *Server {
Transport: transport,
Timeout: c.Timeout,
resolver: resolver,
dnsCache: map[string]string{},
dnsCache: map[string]dns{},
}
transport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
addr, err := s.dig(ctx, addr)
@@ -84,12 +100,18 @@ func (s *Server) Connect(w http.ResponseWriter, r *http.Request) {
return
}
dest, err := net.DialTimeout("tcp", host, s.Timeout)
network := "tcp"
if n := strings.Count(host, ":"); n > 3 {
network = "tcp6"
}
dest, err := net.DialTimeout(network, host, s.Timeout)
if err != nil {
s.Error(r, w, fmt.Errorf("error dialing w timeout %s=>%s: %w", r.Host, host, err))
return
}
w.WriteHeader(http.StatusOK)
client, _, err := hijacker.Hijack()
if err != nil {
s.Error(r, w, err)
@@ -134,8 +156,10 @@ func (s *Server) dig(ctx context.Context, host string) (string, error) {
search := host
search = strings.TrimPrefix(search, "https://")
search = strings.TrimPrefix(search, "http://")
if v, ok := s.dnsCache[host]; ok {
return v, nil
s.dnsCacheLock.Lock()
defer s.dnsCacheLock.Unlock()
if v, ok := s.dnsCache[host]; ok && v.ok() {
return v.result, v.err
}
port := ""
if splithost, splitport, err := net.SplitHostPort(host); err == nil {
@@ -143,14 +167,13 @@ func (s *Server) dig(ctx context.Context, host string) (string, error) {
port = ":" + splitport
}
ip, err := s.resolver.LookupHost(ctx, search)
if err != nil {
result := ""
if len(ip) > 0 {
result = strings.TrimPrefix(ip[0], "//") + port
}
s.dnsCache[host] = dns{result: result, err: err, ts: time.Now()}
if err != nil || result == "" {
return "", fmt.Errorf("failed to dns lookup %s: %v", search, err)
}
if len(ip) == 0 {
return "", errors.New("name does not resolve")
}
result := strings.TrimPrefix(ip[0], "//") + port
s.dnsCache[host] = result
//log.Printf("dug %s => %s => %s", host, search, result)
return result, nil
}

61
tcp.go Normal file
View File

@@ -0,0 +1,61 @@
package main
import (
"crypto/tls"
"io"
"log"
"net"
)
type TCP struct {
config *Config
}
func NewTCPServer(c *Config) TCP {
return TCP{config: c}
}
func (tcp TCP) Listen() error {
ln, err := net.Listen("tcp", tcp.config.Listen)
if err != nil {
return err
}
defer ln.Close()
log.Println("accepting tcp on", tcp.config.Listen)
for {
conn, err := ln.Accept()
if err != nil {
return err
}
go func() {
defer conn.Close()
conn2, err := func() (net.Conn, error) {
if tcp.config.TCPProxyTLS {
return tls.Dial("tcp", tcp.config.TCPProxy, &tls.Config{})
}
return net.Dial("tcp", tcp.config.TCPProxy)
}()
if err != nil {
log.Println(err)
return
}
defer conn2.Close()
errc := make(chan error)
go func() {
_, err := io.Copy(conn, conn2)
errc <- err
}()
go func() {
_, err := io.Copy(conn2, conn)
errc <- err
}()
for i := 0; i < 2; i++ {
<-errc
}
close(errc)
}()
}
}