From 2177076e01fba52b4b649e7eaa2767ec34fcaa62 Mon Sep 17 00:00:00 2001 From: ICKelin Date: Sat, 5 Jun 2021 16:36:28 +0800 Subject: [PATCH] feature: reply proxy info to client --- etc/opennotr.yaml | 13 +++------- internal/proto/cs.go | 13 +++++++--- opennotr/client.go | 7 +++++ opennotrd/core/server.go | 31 ++++++++++++++--------- opennotrd/plugin/dummy/dummy.go | 4 +-- opennotrd/plugin/plugin.go | 21 ++++++++++----- opennotrd/plugin/restyproxy/restyproxy.go | 11 +++++--- opennotrd/plugin/tcpproxy/tcpproxy.go | 15 ++++++++--- opennotrd/plugin/udpproxy/udpproxy.go | 16 +++++++++--- 9 files changed, 88 insertions(+), 43 deletions(-) diff --git a/etc/opennotr.yaml b/etc/opennotr.yaml index dd01930..b34b56c 100644 --- a/etc/opennotr.yaml +++ b/etc/opennotr.yaml @@ -1,13 +1,13 @@ serverAddr: "demo.notr.tech:10100" -key: "client server exchange key" +key: "http://www.notr.tech" forwards: - protocol: tcp ports: - 2221: 2222 + 0: 2222 - protocol: udp ports: - 531: 53 + 0: 53 - protocol: http ports: @@ -20,9 +20,4 @@ forwards: - protocol: h2c ports: 0: 50052 - - - protocol: dummy - ports: - 0: 0 - rawConfig: - "this is a test config pass to dummy plugin" \ No newline at end of file + \ No newline at end of file diff --git a/internal/proto/cs.go b/internal/proto/cs.go index 56adaa4..915b73b 100644 --- a/internal/proto/cs.go +++ b/internal/proto/cs.go @@ -21,7 +21,7 @@ type C2SHeartbeat struct{} type C2SAuth struct { Key string `json:"key" yaml:"key"` Domain string `json:"domain" yaml:"domain"` - Forward []ForwardItem `json:"forwards" yaml:"forwards"` + Forward []ForwardItem `json:"forwards" yaml:"forwards"` // request forwards, not real, it depends on opennotrd } type ForwardItem struct { @@ -43,8 +43,15 @@ type ForwardItem struct { } type S2CAuth struct { - Domain string `json:"domain"` // 分配域名 - Vip string `json:"vip"` // 分配虚拟ip地址 + Domain string `json:"domain"` // uniq domain for opennotr + Vip string `json:"vip"` // vip for opennotr + ProxyInfos []*ProxyTuple `json:"proxyInfos"` // real proxy table +} + +type ProxyTuple struct { + Protocol string + FromPort string + ToPort string } type ProxyProtocol struct { diff --git a/opennotr/client.go b/opennotr/client.go index cfb937b..fb6f08f 100644 --- a/opennotr/client.go +++ b/opennotr/client.go @@ -75,6 +75,13 @@ func (c *Client) Run() { log.Println("connect success") log.Println("vhost:", auth.Vip) log.Println("domain:", auth.Domain) + for _, item := range auth.ProxyInfos { + fromaddr := fmt.Sprintf("%s:%s", auth.Domain, item.FromPort) + if len(item.FromPort) == 0 { + fromaddr = auth.Domain + } + log.Printf("%s://%s => 127.0.0.1:%s\n", item.Protocol, fromaddr, item.ToPort) + } mux, err := smux.Client(conn, nil) if err != nil { diff --git a/opennotrd/core/server.go b/opennotrd/core/server.go index 9011b97..05290bb 100644 --- a/opennotrd/core/server.go +++ b/opennotrd/core/server.go @@ -98,17 +98,6 @@ func (s *Server) onConn(conn net.Conn) { return } - reply := &proto.S2CAuth{ - Vip: vip, - Domain: auth.Domain, - } - - err = proto.WriteJSON(conn, proto.CmdAuth, reply) - if err != nil { - logs.Error("write json fail: %v", err) - return - } - // dynamic dns, write domain=>ip map to etcd // coredns will read records from etcd and reply to dns client if s.resolver != nil { @@ -128,6 +117,7 @@ func (s *Server) onConn(conn net.Conn) { // 2. for to address, we use $vip:$localPort // the vip is the virtual lan ip address // Domain is only use for restyproxy + proxyInfos := make([]*proto.ProxyTuple, 0) for _, forward := range auth.Forward { for publicPort, localPort := range forward.Ports { item := &plugin.PluginMeta{ @@ -139,15 +129,32 @@ func (s *Server) onConn(conn net.Conn) { Ctx: forward.RawConfig, } - err = s.pluginMgr.AddProxy(item) + p, err := s.pluginMgr.AddProxy(item) if err != nil { logs.Error("add proxy fail: %v", err) return } + proxyInfos = append(proxyInfos, &proto.ProxyTuple{ + Protocol: forward.Protocol, + FromPort: p.FromPort, + ToPort: p.ToPort, + }) defer s.pluginMgr.DelProxy(item) } } + reply := &proto.S2CAuth{ + Vip: vip, + Domain: auth.Domain, + ProxyInfos: proxyInfos, + } + + err = proto.WriteJSON(conn, proto.CmdAuth, reply) + if err != nil { + logs.Error("write json fail: %v", err) + return + } + mux, err := smux.Server(conn, nil) if err != nil { logs.Error("smux server fail:%v", err) diff --git a/opennotrd/plugin/dummy/dummy.go b/opennotrd/plugin/dummy/dummy.go index 5c5d40b..148ba78 100644 --- a/opennotrd/plugin/dummy/dummy.go +++ b/opennotrd/plugin/dummy/dummy.go @@ -17,9 +17,9 @@ func (d *DummyPlugin) Setup(cfg json.RawMessage) error { return nil } -func (d *DummyPlugin) RunProxy(meta *plugin.PluginMeta) error { +func (d *DummyPlugin) RunProxy(meta *plugin.PluginMeta) (*plugin.ProxyTuple, error) { logs.Info("dummy plugin client config: %v", meta.Ctx) - return nil + return &plugin.ProxyTuple{}, nil } func (d *DummyPlugin) StopProxy(meta *plugin.PluginMeta) {} diff --git a/opennotrd/plugin/plugin.go b/opennotrd/plugin/plugin.go index 825d10f..613f45c 100644 --- a/opennotrd/plugin/plugin.go +++ b/opennotrd/plugin/plugin.go @@ -13,6 +13,13 @@ var pluginMgr = &PluginManager{ plugins: make(map[string]IPlugin), } +// ProxyTuple defineds plugins real proxy address +type ProxyTuple struct { + Protocol string + FromPort string + ToPort string +} + // PluginMeta defineds data that the plugins needs // these members are filled by server.go type PluginMeta struct { @@ -58,7 +65,7 @@ type IPlugin interface { StopProxy(item *PluginMeta) // Run a proxy, it may be called by client's connection established - RunProxy(item *PluginMeta) error + RunProxy(item *PluginMeta) (*ProxyTuple, error) } type PluginManager struct { @@ -103,26 +110,26 @@ func Setup(plugins map[string]string) error { return nil } -func (p *PluginManager) AddProxy(item *PluginMeta) error { +func (p *PluginManager) AddProxy(item *PluginMeta) (*ProxyTuple, error) { p.mu.Lock() defer p.mu.Unlock() key := item.identify() if _, ok := p.routes[key]; ok { - return fmt.Errorf("port %s is in used", key) + return nil, fmt.Errorf("port %s is in used", key) } plug, ok := p.plugins[item.Protocol] if !ok { - return fmt.Errorf("proxy %s not register", item.Protocol) + return nil, fmt.Errorf("proxy %s not register", item.Protocol) } - err := plug.RunProxy(item) + tuple, err := plug.RunProxy(item) if err != nil { logs.Error("run proxy fail: %v", err) - return err + return nil, err } p.routes[key] = item - return nil + return tuple, nil } func (p *PluginManager) DelProxy(item *PluginMeta) { diff --git a/opennotrd/plugin/restyproxy/restyproxy.go b/opennotrd/plugin/restyproxy/restyproxy.go index 6572c71..789355c 100644 --- a/opennotrd/plugin/restyproxy/restyproxy.go +++ b/opennotrd/plugin/restyproxy/restyproxy.go @@ -50,10 +50,10 @@ func (p *RestyProxy) StopProxy(item *plugin.PluginMeta) { p.sendDeleteReq(item.Domain, item.Protocol) } -func (p *RestyProxy) RunProxy(item *plugin.PluginMeta) error { +func (p *RestyProxy) RunProxy(item *plugin.PluginMeta) (*plugin.ProxyTuple, error) { vip, port, err := net.SplitHostPort(item.To) if err != nil { - return err + return nil, err } req := &AddUpstreamBody{ @@ -64,7 +64,12 @@ func (p *RestyProxy) RunProxy(item *plugin.PluginMeta) error { } go p.sendPostReq(req) - return nil + + _, toPort, _ := net.SplitHostPort(item.To) + return &plugin.ProxyTuple{ + Protocol: item.Protocol, + ToPort: toPort, + }, nil } func (p *RestyProxy) sendPostReq(body interface{}) { diff --git a/opennotrd/plugin/tcpproxy/tcpproxy.go b/opennotrd/plugin/tcpproxy/tcpproxy.go index f6b07d2..bfc8d5b 100644 --- a/opennotrd/plugin/tcpproxy/tcpproxy.go +++ b/opennotrd/plugin/tcpproxy/tcpproxy.go @@ -26,11 +26,13 @@ func (t *TCPProxy) StopProxy(item *plugin.PluginMeta) { } } -func (t *TCPProxy) RunProxy(item *plugin.PluginMeta) error { +// RunProxy runs a tcp server and proxy to item.To +// RunProxy may change item.From address to the real listenner address +func (t *TCPProxy) RunProxy(item *plugin.PluginMeta) (*plugin.ProxyTuple, error) { from, to := item.From, item.To lis, err := net.Listen("tcp", from) if err != nil { - return err + return nil, err } fin := make(chan struct{}) @@ -73,7 +75,14 @@ func (t *TCPProxy) RunProxy(item *plugin.PluginMeta) error { } }() - return nil + _, fromPort, _ := net.SplitHostPort(lis.Addr().String()) + _, toPort, _ := net.SplitHostPort(item.To) + + return &plugin.ProxyTuple{ + Protocol: item.Protocol, + FromPort: fromPort, + ToPort: toPort, + }, nil } func (t *TCPProxy) doProxy(conn net.Conn, to string) { diff --git a/opennotrd/plugin/udpproxy/udpproxy.go b/opennotrd/plugin/udpproxy/udpproxy.go index 3dd7d7c..fcc8552 100644 --- a/opennotrd/plugin/udpproxy/udpproxy.go +++ b/opennotrd/plugin/udpproxy/udpproxy.go @@ -48,20 +48,28 @@ func (p *UDPProxy) StopProxy(item *plugin.PluginMeta) { } } -func (p *UDPProxy) RunProxy(item *plugin.PluginMeta) error { +func (p *UDPProxy) RunProxy(item *plugin.PluginMeta) (*plugin.ProxyTuple, error) { from := item.From laddr, err := net.ResolveUDPAddr("udp", from) if err != nil { - return err + return nil, err } lis, err := net.ListenUDP("udp", laddr) if err != nil { - return err + return nil, err } go p.doProxy(lis, item) - return nil + + _, fromPort, _ := net.SplitHostPort(lis.LocalAddr().String()) + _, toPort, _ := net.SplitHostPort(item.To) + + return &plugin.ProxyTuple{ + Protocol: item.Protocol, + FromPort: fromPort, + ToPort: toPort, + }, nil } func (p *UDPProxy) doProxy(lis *net.UDPConn, item *plugin.PluginMeta) {