Browse Source

auto update script executed

Toby Chui 1 year ago
parent
commit
1edc9b73eb

+ 5 - 3
accesslist.go

@@ -4,7 +4,7 @@ import (
 	"encoding/json"
 	"net/http"
 
-	strip "github.com/grokify/html-strip-tags-go"
+	"github.com/microcosm-cc/bluemonday"
 	"imuslab.com/zoraxy/mod/geodb"
 	"imuslab.com/zoraxy/mod/utils"
 )
@@ -137,7 +137,8 @@ func handleCountryWhitelistAdd(w http.ResponseWriter, r *http.Request) {
 	}
 
 	comment, _ := utils.PostPara(r, "comment")
-	comment = strip.StripTags(comment)
+	p := bluemonday.StrictPolicy()
+	comment = p.Sanitize(comment)
 
 	geodbStore.AddCountryCodeToWhitelist(countryCode, comment)
 
@@ -164,7 +165,8 @@ func handleIpWhitelistAdd(w http.ResponseWriter, r *http.Request) {
 	}
 
 	comment, _ := utils.PostPara(r, "comment")
-	comment = strip.StripTags(comment)
+	p := bluemonday.StrictPolicy()
+	comment = p.Sanitize(comment)
 
 	geodbStore.AddIPToWhiteList(ipAddr, comment)
 }

+ 3 - 4
go.mod

@@ -10,11 +10,10 @@ require (
 	github.com/gorilla/sessions v1.2.1
 	github.com/gorilla/websocket v1.5.0
 	github.com/grandcat/zeroconf v1.0.0
-	github.com/grokify/html-strip-tags-go v0.1.0
 	github.com/likexian/whois v1.15.1
 	github.com/microcosm-cc/bluemonday v1.0.25
-	golang.org/x/net v0.14.0
-	golang.org/x/sys v0.11.0
-	golang.org/x/text v0.12.0
+	golang.org/x/net v0.20.0
+	golang.org/x/sys v0.16.0
+	golang.org/x/text v0.14.0
 	golang.org/x/tools v0.12.0 // indirect
 )

File diff suppressed because it is too large
+ 330 - 2
go.sum


+ 25 - 0
mod/forwardproxy/cproxy/LICENSE.md

@@ -0,0 +1,25 @@
+MIT License
+
+Copyright (c) 2022 Smarty
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+NOTE: Various optional and subordinate components carry their own licensing
+requirements and restrictions.  Use of those components is subject to the terms
+and conditions outlined the respective license of each component.

+ 109 - 0
mod/forwardproxy/cproxy/config.go

@@ -0,0 +1,109 @@
+package cproxy
+
+import (
+	"net/http"
+	"time"
+)
+
+func New(options ...option) http.Handler {
+	var this configuration
+	Options.apply(options...)(&this)
+	return newHandler(this.Filter, this.ClientConnector, this.ServerConnector, this.Monitor)
+}
+
+var Options singleton
+
+type singleton struct{}
+type option func(*configuration)
+
+type configuration struct {
+	DialTimeout     time.Duration
+	Filter          Filter
+	DialAddress     string
+	Dialer          Dialer
+	LogConnections  bool
+	ProxyProtocol   bool
+	Initializer     initializer
+	ClientConnector clientConnector
+	ServerConnector serverConnector
+	Monitor         monitor
+	Logger          logger
+}
+
+func (singleton) DialTimeout(value time.Duration) option {
+	return func(this *configuration) { this.DialTimeout = value }
+}
+func (singleton) Filter(value Filter) option {
+	return func(this *configuration) { this.Filter = value }
+}
+func (singleton) ClientConnector(value clientConnector) option {
+	return func(this *configuration) { this.ClientConnector = value }
+}
+func (singleton) DialAddress(value string) option {
+	return func(this *configuration) { this.DialAddress = value }
+}
+func (singleton) Dialer(value Dialer) option {
+	return func(this *configuration) { this.Dialer = value }
+}
+func (singleton) LogConnections(value bool) option {
+	return func(this *configuration) { this.LogConnections = value }
+}
+func (singleton) ProxyProtocol(value bool) option {
+	return func(this *configuration) { this.ProxyProtocol = value }
+}
+func (singleton) Initializer(value initializer) option {
+	return func(this *configuration) { this.Initializer = value }
+}
+func (singleton) ServerConnector(value serverConnector) option {
+	return func(this *configuration) { this.ServerConnector = value }
+}
+func (singleton) Monitor(value monitor) option {
+	return func(this *configuration) { this.Monitor = value }
+}
+func (singleton) Logger(value logger) option {
+	return func(this *configuration) { this.Logger = value }
+}
+
+func (singleton) apply(options ...option) option {
+	return func(this *configuration) {
+		for _, item := range Options.defaults(options...) {
+			item(this)
+		}
+
+		if this.Dialer == nil {
+			this.Dialer = newDialer(this)
+		}
+
+		this.Dialer = newRoutingDialer(this)
+
+		if this.ProxyProtocol {
+			this.Initializer = newProxyProtocolInitializer()
+		}
+
+		if this.Initializer == nil {
+			this.Initializer = nop{}
+		}
+
+		this.Initializer = newLoggingInitializer(this)
+
+		if this.ServerConnector == nil {
+			this.ServerConnector = newServerConnector(this.Dialer, this.Initializer)
+		}
+	}
+}
+func (singleton) defaults(options ...option) []option {
+	return append([]option{
+		Options.DialTimeout(time.Second * 10),
+		Options.Filter(newFilter()),
+		Options.ClientConnector(newClientConnector()),
+		Options.Initializer(nop{}),
+		Options.Monitor(nop{}),
+		Options.Logger(nop{}),
+	}, options...)
+}
+
+type nop struct{}
+
+func (nop) Measure(int)                    {}
+func (nop) Printf(string, ...interface{})  {}
+func (nop) Initialize(Socket, Socket) bool { return true }

+ 19 - 0
mod/forwardproxy/cproxy/default_client_connector.go

@@ -0,0 +1,19 @@
+package cproxy
+
+import "net/http"
+
+type defaultClientConnector struct{}
+
+func newClientConnector() *defaultClientConnector {
+	return &defaultClientConnector{}
+}
+
+func (this *defaultClientConnector) Connect(response http.ResponseWriter) Socket {
+	if hijacker, ok := response.(http.Hijacker); !ok {
+		return nil
+	} else if socket, _, _ := hijacker.Hijack(); socket == nil {
+		return nil // this 'else if' exists to avoid the pointer nil != interface nil issue
+	} else {
+		return socket
+	}
+}

+ 25 - 0
mod/forwardproxy/cproxy/default_dialer.go

@@ -0,0 +1,25 @@
+package cproxy
+
+import (
+	"net"
+	"time"
+)
+
+type defaultDialer struct {
+	timeout time.Duration
+	logger  logger
+}
+
+func newDialer(config *configuration) *defaultDialer {
+	return &defaultDialer{timeout: config.DialTimeout, logger: config.Logger}
+}
+
+func (this *defaultDialer) Dial(address string) Socket {
+	if socket, err := net.DialTimeout("tcp", address, this.timeout); err == nil {
+		return socket
+	} else {
+		this.logger.Printf("[INFO] Unable to establish connection to [%s]: %s", address, err)
+	}
+
+	return nil
+}

+ 9 - 0
mod/forwardproxy/cproxy/default_filter.go

@@ -0,0 +1,9 @@
+package cproxy
+
+import "net/http"
+
+type defaultFilter struct{}
+
+func newFilter() *defaultFilter { return &defaultFilter{} }
+
+func (this *defaultFilter) IsAuthorized(http.ResponseWriter, *http.Request) bool { return true }

+ 56 - 0
mod/forwardproxy/cproxy/default_handler.go

@@ -0,0 +1,56 @@
+package cproxy
+
+import "net/http"
+
+type defaultHandler struct {
+	filter          Filter
+	clientConnector clientConnector
+	serverConnector serverConnector
+	meter           monitor
+}
+
+func newHandler(filter Filter, clientConnector clientConnector, serverConnector serverConnector, meter monitor) *defaultHandler {
+	return &defaultHandler{
+		filter:          filter,
+		clientConnector: clientConnector,
+		serverConnector: serverConnector,
+		meter:           meter,
+	}
+}
+
+func (this *defaultHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {
+	this.meter.Measure(MeasurementHTTPRequest)
+
+	if request.Method != "CONNECT" {
+		this.meter.Measure(MeasurementBadMethod)
+		writeResponseStatus(response, http.StatusMethodNotAllowed)
+
+	} else if !this.filter.IsAuthorized(response, request) {
+		this.meter.Measure(MeasurementUnauthorizedRequest)
+		writeResponseStatus(response, http.StatusUnauthorized)
+
+	} else if client := this.clientConnector.Connect(response); client == nil {
+		this.meter.Measure(MeasurementClientConnectionFailed)
+		writeResponseStatus(response, http.StatusNotImplemented)
+
+	} else if connection := this.serverConnector.Connect(client, request.URL.Host); connection == nil {
+		this.meter.Measure(MeasurementServerConnectionFailed)
+		_, _ = client.Write(statusBadGateway)
+		_ = client.Close()
+
+	} else {
+		this.meter.Measure(MeasurementProxyReady)
+		_, _ = client.Write(statusReady)
+		connection.Proxy()
+		this.meter.Measure(MeasurementProxyComplete)
+	}
+}
+
+func writeResponseStatus(response http.ResponseWriter, statusCode int) {
+	http.Error(response, http.StatusText(statusCode), statusCode)
+}
+
+var (
+	statusBadGateway = []byte("HTTP/1.1 502 Bad Gateway\r\n\r\n")
+	statusReady      = []byte("HTTP/1.1 200 OK\r\n\r\n")
+)

+ 54 - 0
mod/forwardproxy/cproxy/default_proxy.go

@@ -0,0 +1,54 @@
+package cproxy
+
+import (
+	"io"
+	"sync"
+)
+
+type defaultProxy struct {
+	client Socket
+	server Socket
+	waiter *sync.WaitGroup
+}
+
+func newProxy(client, server Socket) *defaultProxy {
+	waiter := &sync.WaitGroup{}
+	waiter.Add(2) // wait on both client->server and server->client streams
+
+	return &defaultProxy{
+		waiter: waiter,
+		client: client,
+		server: server,
+	}
+}
+
+func (this *defaultProxy) Proxy() {
+	go this.streamAndClose(this.client, this.server)
+	go this.streamAndClose(this.server, this.client)
+	this.closeSockets()
+}
+
+func (this *defaultProxy) streamAndClose(reader, writer Socket) {
+	_, _ = io.Copy(writer, reader)
+
+	tryCloseRead(reader)
+	tryCloseWrite(writer)
+
+	this.waiter.Done()
+}
+func tryCloseRead(socket Socket) {
+	if tcp, ok := socket.(tcpSocket); ok {
+		_ = tcp.CloseRead()
+	}
+}
+func tryCloseWrite(socket Socket) {
+	if tcp, ok := socket.(tcpSocket); ok {
+		_ = tcp.CloseWrite()
+	}
+}
+
+func (this *defaultProxy) closeSockets() {
+	this.waiter.Wait()
+	_ = this.client.Close()
+	_ = this.server.Close()
+}

+ 24 - 0
mod/forwardproxy/cproxy/default_server_connector.go

@@ -0,0 +1,24 @@
+package cproxy
+
+type defaultServerConnector struct {
+	dialer      Dialer
+	initializer initializer
+}
+
+func newServerConnector(dialer Dialer, initializer initializer) *defaultServerConnector {
+	return &defaultServerConnector{dialer: dialer, initializer: initializer}
+}
+
+func (this *defaultServerConnector) Connect(client Socket, serverAddress string) proxy {
+	server := this.dialer.Dial(serverAddress)
+	if server == nil {
+		return nil
+	}
+
+	if !this.initializer.Initialize(client, server) {
+		_ = server.Close()
+		return nil
+	}
+
+	return newProxy(client, server)
+}

+ 32 - 0
mod/forwardproxy/cproxy/hostname_filter.go

@@ -0,0 +1,32 @@
+package cproxy
+
+import "net/http"
+
+type hostnameFilter struct {
+	authorized []string
+}
+
+func NewHostnameFilter(authorized []string) Filter {
+	return &hostnameFilter{authorized: authorized}
+}
+
+func (this hostnameFilter) IsAuthorized(_ http.ResponseWriter, request *http.Request) bool {
+	if len(this.authorized) == 0 {
+		return true
+	}
+
+	host := request.URL.Host
+	hostLength := len(host)
+	for _, authorized := range this.authorized {
+		if authorized[:2] == "*." {
+			have, want := hostLength, len(authorized)-1
+			if have > want && authorized[1:] == host[hostLength-want:] {
+				return true
+			}
+		} else if authorized == host {
+			return true
+		}
+	}
+
+	return false
+}

+ 26 - 0
mod/forwardproxy/cproxy/hostname_suffix_filter.go

@@ -0,0 +1,26 @@
+package cproxy
+
+import (
+	"net/http"
+	"strings"
+)
+
+type hostnameSuffixFilter struct {
+	authorized []string
+}
+
+func NewHostnameSuffixFilter(authorized []string) Filter {
+	return &hostnameSuffixFilter{authorized: authorized}
+}
+
+func (this hostnameSuffixFilter) IsAuthorized(_ http.ResponseWriter, request *http.Request) bool {
+	host := request.URL.Host
+
+	for _, authorized := range this.authorized {
+		if strings.HasSuffix(host, authorized) {
+			return true
+		}
+	}
+
+	return false
+}

+ 67 - 0
mod/forwardproxy/cproxy/interfaces.go

@@ -0,0 +1,67 @@
+package cproxy
+
+import (
+	"io"
+	"net"
+	"net/http"
+)
+
+type (
+	Filter interface {
+		IsAuthorized(http.ResponseWriter, *http.Request) bool
+	}
+
+	clientConnector interface {
+		Connect(http.ResponseWriter) Socket
+	}
+)
+
+type (
+	Dialer interface {
+		Dial(string) Socket
+	}
+
+	serverConnector interface {
+		Connect(Socket, string) proxy
+	}
+
+	initializer interface {
+		Initialize(Socket, Socket) bool
+	}
+
+	proxy interface {
+		Proxy()
+	}
+)
+
+type (
+	Socket interface {
+		io.ReadWriteCloser
+		RemoteAddr() net.Addr
+	}
+
+	tcpSocket interface {
+		Socket
+		CloseRead() error
+		CloseWrite() error
+	}
+)
+
+type (
+	monitor interface {
+		Measure(int)
+	}
+	logger interface {
+		Printf(string, ...interface{})
+	}
+)
+
+const (
+	MeasurementHTTPRequest int = iota
+	MeasurementBadMethod
+	MeasurementUnauthorizedRequest
+	MeasurementClientConnectionFailed
+	MeasurementServerConnectionFailed
+	MeasurementProxyReady
+	MeasurementProxyComplete
+)

+ 24 - 0
mod/forwardproxy/cproxy/logging_initializer.go

@@ -0,0 +1,24 @@
+package cproxy
+
+type loggingInitializer struct {
+	logger logger
+	inner  initializer
+}
+
+func newLoggingInitializer(config *configuration) initializer {
+	if !config.LogConnections {
+		return config.Initializer
+	}
+
+	return &loggingInitializer{inner: config.Initializer, logger: config.Logger}
+}
+
+func (this *loggingInitializer) Initialize(client, server Socket) bool {
+	result := this.inner.Initialize(client, server)
+
+	if !result {
+		this.logger.Printf("[INFO] Connection failed [%s] -> [%s]", client.RemoteAddr(), server.RemoteAddr())
+	}
+
+	return result
+}

+ 36 - 0
mod/forwardproxy/cproxy/proxy_protocol_initializer.go

@@ -0,0 +1,36 @@
+package cproxy
+
+import (
+	"fmt"
+	"io"
+	"net"
+	"strings"
+)
+
+type proxyProtocolInitializer struct{}
+
+func newProxyProtocolInitializer() *proxyProtocolInitializer {
+	return &proxyProtocolInitializer{}
+}
+
+func (this *proxyProtocolInitializer) Initialize(client, server Socket) bool {
+	header := formatHeader(client.RemoteAddr(), server.RemoteAddr())
+	_, err := io.WriteString(server, header)
+	return err == nil
+}
+func formatHeader(client, server net.Addr) string {
+	clientAddress, clientPort := parseAddress(client.String())
+	serverAddress, serverPort := parseAddress(server.String())
+	if strings.Contains(clientAddress, ":") {
+		return fmt.Sprintf(proxyProtocolIPv6Preamble, clientAddress, serverAddress, clientPort, serverPort)
+	}
+
+	return fmt.Sprintf(proxyProtocolIPv4Preamble, clientAddress, serverAddress, clientPort, serverPort)
+}
+func parseAddress(address string) (string, string) {
+	address, port, _ := net.SplitHostPort(address)
+	return address, port
+}
+
+const proxyProtocolIPv4Preamble = "PROXY TCP4 %s %s %s %s\r\n"
+const proxyProtocolIPv6Preamble = "PROXY TCP6 %s %s %s %s\r\n"

+ 18 - 0
mod/forwardproxy/cproxy/routing_dialer.go

@@ -0,0 +1,18 @@
+package cproxy
+
+type routingDialer struct {
+	inner         Dialer
+	targetAddress string
+}
+
+func newRoutingDialer(config *configuration) Dialer {
+	if len(config.DialAddress) == 0 {
+		return config.Dialer
+	}
+
+	return &routingDialer{inner: config.Dialer, targetAddress: config.DialAddress}
+}
+
+func (this *routingDialer) Dial(string) Socket {
+	return this.inner.Dial(this.targetAddress)
+}

+ 6 - 0
start.go

@@ -1,6 +1,7 @@
 package main
 
 import (
+	"fmt"
 	"log"
 	"net/http"
 	"os"
@@ -12,6 +13,7 @@ import (
 	"imuslab.com/zoraxy/mod/auth"
 	"imuslab.com/zoraxy/mod/database"
 	"imuslab.com/zoraxy/mod/dynamicproxy/redirection"
+	"imuslab.com/zoraxy/mod/forwardproxy/cproxy"
 	"imuslab.com/zoraxy/mod/ganserv"
 	"imuslab.com/zoraxy/mod/geodb"
 	"imuslab.com/zoraxy/mod/info/logger"
@@ -241,4 +243,8 @@ func finalSequence() {
 
 	//Inject routing rules
 	registerBuildInRoutingRules()
+
+	fmt.Println("Running debug forward web proxy")
+	handler := cproxy.New()
+	http.ListenAndServe(":8088", handler)
 }

Some files were not shown because too many files changed in this diff