summaryrefslogtreecommitdiffhomepage
path: root/tunnel/tools/libwg-go/http-proxy.go
diff options
context:
space:
mode:
Diffstat (limited to 'tunnel/tools/libwg-go/http-proxy.go')
-rw-r--r--tunnel/tools/libwg-go/http-proxy.go165
1 files changed, 165 insertions, 0 deletions
diff --git a/tunnel/tools/libwg-go/http-proxy.go b/tunnel/tools/libwg-go/http-proxy.go
new file mode 100644
index 00000000..4af97314
--- /dev/null
+++ b/tunnel/tools/libwg-go/http-proxy.go
@@ -0,0 +1,165 @@
+package main
+
+import (
+ "net"
+ "net/http"
+ "net/url"
+
+ "github.com/elazarl/goproxy"
+
+ "golang.zx2c4.com/go118/netip"
+ "golang.zx2c4.com/wireguard/device"
+)
+
+type HttpProxy struct {
+ listener net.Listener
+ logger *device.Logger
+ addrPort netip.AddrPort
+ uidRequest chan netip.AddrPort
+ uidResponse chan string
+}
+
+func NewHttpProxy(uidRequest chan netip.AddrPort, uidResponse chan string, logger *device.Logger) *HttpProxy {
+ logger.Verbosef("NewHttpProxy")
+ return &HttpProxy{
+ listener: nil,
+ logger: logger,
+ uidRequest: uidRequest,
+ uidResponse: uidResponse,
+ }
+}
+
+func (p *HttpProxy) GetAddrPort() netip.AddrPort {
+ return p.addrPort
+}
+
+func newGoProxy(proxyUrl string) *goproxy.ProxyHttpServer {
+ proxy := goproxy.NewProxyHttpServer()
+ proxy.Verbose = true
+ proxy.Tr.Proxy = func(req *http.Request) (*url.URL, error) {
+ return url.Parse(proxyUrl)
+ }
+ proxy.ConnectDial = proxy.NewConnectDialToProxy(proxyUrl)
+
+ return proxy
+}
+
+func (p *HttpProxy) Start() (listen_port uint16, err error) {
+ p.logger.Verbosef("HttpProxy.Start()")
+ listen_port = 0
+
+ proxyMap := make(map[string]*goproxy.ProxyHttpServer)
+ proxyMap["bbc.iplayer.android"] = newGoProxy("http://10.49.124.111:8888")
+ proxyMap["no.nrk.tv"] = newGoProxy("http://10.49.124.115:8888")
+
+ defaultProxy := goproxy.NewProxyHttpServer()
+ defaultProxy.Verbose = true
+
+ listener, err := net.Listen("tcp", "localhost:")
+ if err != nil {
+ return
+ }
+
+ p.addrPort, err = netip.ParseAddrPort(listener.Addr().String())
+ if err != nil {
+ return
+ }
+
+ listen_port = p.addrPort.Port()
+
+ handler := NewHttpHandler(proxyMap, defaultProxy, p.logger)
+
+ go http.Serve(NewUidListener(listener, handler, p.uidRequest, p.uidResponse, p.logger), handler)
+
+ return
+}
+
+func (p *HttpProxy) Stop() {
+ if p.listener != nil {
+ p.logger.Verbosef("Close: %v", p.listener)
+ p.listener.Close()
+ p.listener = nil
+ }
+}
+
+type HttpHandler struct {
+ proxyMap map[string]*goproxy.ProxyHttpServer
+ defaultProxy *goproxy.ProxyHttpServer
+ logger *device.Logger
+ remoteAddrPkgMap map[string]string
+}
+
+func NewHttpHandler(proxyMap map[string]*goproxy.ProxyHttpServer, defaultProxy *goproxy.ProxyHttpServer, logger *device.Logger) *HttpHandler{
+ return &HttpHandler{
+ proxyMap: proxyMap,
+ defaultProxy: defaultProxy,
+ logger: logger,
+ remoteAddrPkgMap: make(map[string]string),
+ }
+}
+
+func (h *HttpHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
+ pkg, ok := h.remoteAddrPkgMap[req.RemoteAddr]
+ if ok {
+ h.logger.Verbosef("ServeHTTP remote:%s package:%s", req.RemoteAddr, pkg)
+ delete(h.remoteAddrPkgMap, req.RemoteAddr)
+
+ proxy, ok := h.proxyMap[pkg]
+ if ok {
+ proxy.ServeHTTP(rw, req)
+ } else {
+ h.defaultProxy.ServeHTTP(rw, req)
+ }
+ } else {
+ h.defaultProxy.ServeHTTP(rw, req)
+ }
+}
+
+// UidListener
+type UidListener struct {
+ l net.Listener
+ handler *HttpHandler
+ logger *device.Logger
+ uidRequest chan netip.AddrPort
+ uidResponse chan string
+}
+
+func NewUidListener(listener net.Listener, handler *HttpHandler, uidRequest chan netip.AddrPort, uidResponse chan string, logger *device.Logger) *UidListener{
+ return &UidListener{
+ l: listener,
+ handler: handler,
+ logger: logger,
+ uidRequest: uidRequest,
+ uidResponse: uidResponse,
+ }
+}
+
+func (l *UidListener) Accept() (net.Conn, error) {
+ c, err := l.l.Accept()
+ if err != nil {
+ return c, err
+ }
+
+ l.logger.Verbosef("Accept: %v", c.RemoteAddr().String())
+ addr_port, err := netip.ParseAddrPort(c.RemoteAddr().String())
+ if err == nil {
+ l.logger.Verbosef("uidRequest")
+ l.uidRequest <- addr_port
+
+ // TODO add timeout?
+ select {
+ case pkg := <-l.uidResponse:
+ l.logger.Verbosef("uidResponse: %v", pkg)
+ l.handler.remoteAddrPkgMap[c.RemoteAddr().String()] = pkg
+ }
+ }
+ return c, nil
+}
+
+func (l *UidListener) Close() error {
+ return l.l.Close()
+}
+
+func (l *UidListener) Addr() net.Addr {
+ return l.l.Addr()
+}