diff options
Diffstat (limited to 'tunnel/tools/libwg-go/http-proxy.go')
-rw-r--r-- | tunnel/tools/libwg-go/http-proxy.go | 165 |
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() +} |