diff --git a/main.go b/main.go index a2fb6d8..723f4b4 100644 --- a/main.go +++ b/main.go @@ -8,19 +8,22 @@ import ( "io" "io/ioutil" "local1/logger" + "net" "net/http" "net/http/httputil" "net/url" "os" "strings" + "time" ) type Server struct { transport *http.Transport whitelist []string + bypass []string } -func NewServer(addr, clientcrt, clientkey, servercrt string, whitelist []string) (*Server, error) { +func NewServer(addr, clientcrt, clientkey, servercrt string, whitelist []string, bypass []string) (*Server, error) { caCert, err := ioutil.ReadFile(servercrt) if err != nil { return nil, err @@ -36,7 +39,7 @@ func NewServer(addr, clientcrt, clientkey, servercrt string, whitelist []string) } return &Server{ transport: &http.Transport{ - Proxy: func(*http.Request) (*url.URL, error) { + Proxy: func(r *http.Request) (*url.URL, error) { return url.Parse(addr) }, TLSClientConfig: &tls.Config{ @@ -45,6 +48,7 @@ func NewServer(addr, clientcrt, clientkey, servercrt string, whitelist []string) }, }, whitelist: whitelist, + bypass: bypass, }, nil } @@ -60,11 +64,48 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { denyAccess(w) return } - // proxy via stuncaddsies + if toWhitelist(s.bypass, r.URL.Host) { + logger.Log("Bypassing", r.URL.String()) + s.passthrough(w, r) + return + } logger.Log("Proxying", r.URL.String()) + // proxy via stuncaddsies s.handleHTTP(w, r) } +func (s *Server) passthrough(w http.ResponseWriter, r *http.Request) { + if r.URL.Scheme == "http" { + proxy := httputil.NewSingleHostReverseProxy(pathlessURL(r.URL)) + proxy.ServeHTTP(w, r) + return + } + dest_conn, err := net.DialTimeout("tcp", r.Host, 10*time.Second) + if err != nil { + http.Error(w, err.Error(), http.StatusServiceUnavailable) + return + } + w.WriteHeader(http.StatusOK) + hijacker, ok := w.(http.Hijacker) + if !ok { + http.Error(w, "Hijacking not supported", http.StatusInternalServerError) + return + } + client_conn, _, err := hijacker.Hijack() + if err != nil { + http.Error(w, err.Error(), http.StatusServiceUnavailable) + } + + transfer := func(destination io.WriteCloser, source io.ReadCloser) { + defer destination.Close() + defer source.Close() + io.Copy(destination, source) + } + + go transfer(dest_conn, client_conn) + go transfer(client_conn, dest_conn) +} + func (s *Server) handleHTTP(w http.ResponseWriter, r *http.Request) { proxy := httputil.NewSingleHostReverseProxy(pathlessURL(r.URL)) proxy.Transport = s.transport @@ -154,12 +195,15 @@ func main() { "servercrt": "/Volumes/bldisk/server.crt", "port": "8888", "whitelist": "192.168.0.86,,bel.house,,minio.gcp.blapointe.com", + "bypass": "plex.tv", }) if !strings.HasPrefix(conf["port"], ":") { conf["port"] = ":" + conf["port"] } + whitelist := strings.Split(conf["whitelist"], ",,") + bypass := strings.Split(conf["bypass"], ",,") logger.Log(conf) - server, err := NewServer(conf["stunaddr"], conf["clientcrt"], conf["clientkey"], conf["servercrt"], strings.Split(conf["whitelist"], ",,")) + server, err := NewServer(conf["stunaddr"], conf["clientcrt"], conf["clientkey"], conf["servercrt"], append(whitelist, bypass...), bypass) if err != nil { logger.Fatal(err) }