diff --git a/client/admin_api.go b/client/admin_api.go index fae1737e..3c64b917 100644 --- a/client/admin_api.go +++ b/client/admin_api.go @@ -124,22 +124,24 @@ func NewProxyStatusResp(status *ProxyStatus) ProxyStatusResp { psr.LocalAddr = fmt.Sprintf("%s:%d", cfg.LocalIp, cfg.LocalPort) } psr.Plugin = cfg.Plugin - psr.RemoteAddr = fmt.Sprintf(":%d", cfg.RemotePort) + psr.RemoteAddr = config.ClientCommonCfg.ServerAddr + status.RemoteAddr case *config.UdpProxyConf: if cfg.LocalPort != 0 { psr.LocalAddr = fmt.Sprintf("%s:%d", cfg.LocalIp, cfg.LocalPort) } - psr.RemoteAddr = fmt.Sprintf(":%d", cfg.RemotePort) + psr.RemoteAddr = config.ClientCommonCfg.ServerAddr + status.RemoteAddr case *config.HttpProxyConf: if cfg.LocalPort != 0 { psr.LocalAddr = fmt.Sprintf("%s:%d", cfg.LocalIp, cfg.LocalPort) } psr.Plugin = cfg.Plugin + psr.RemoteAddr = status.RemoteAddr case *config.HttpsProxyConf: if cfg.LocalPort != 0 { psr.LocalAddr = fmt.Sprintf("%s:%d", cfg.LocalIp, cfg.LocalPort) } psr.Plugin = cfg.Plugin + psr.RemoteAddr = status.RemoteAddr case *config.StcpProxyConf: if cfg.LocalPort != 0 { psr.LocalAddr = fmt.Sprintf("%s:%d", cfg.LocalIp, cfg.LocalPort) diff --git a/client/control.go b/client/control.go index 65bec393..a4bb9e09 100644 --- a/client/control.go +++ b/client/control.go @@ -158,7 +158,7 @@ func (ctl *Control) HandleReqWorkConn(inMsg *msg.ReqWorkConn) { func (ctl *Control) HandleNewProxyResp(inMsg *msg.NewProxyResp) { // Server will return NewProxyResp message to each NewProxy message. // Start a new proxy handler if no error got - err := ctl.pm.StartProxy(inMsg.ProxyName, inMsg.Error) + err := ctl.pm.StartProxy(inMsg.ProxyName, inMsg.RemoteAddr, inMsg.Error) if err != nil { ctl.Warn("[%s] start error: %v", inMsg.ProxyName, err) } else { diff --git a/client/proxy_manager.go b/client/proxy_manager.go index d756b5ba..77823986 100644 --- a/client/proxy_manager.go +++ b/client/proxy_manager.go @@ -41,6 +41,8 @@ type ProxyWrapper struct { Err string Cfg config.ProxyConf + RemoteAddr string + pxy Proxy mu sync.RWMutex @@ -52,6 +54,9 @@ type ProxyStatus struct { Status string `json:"status"` Err string `json:"err"` Cfg config.ProxyConf `json:"cfg"` + + // Got from server. + RemoteAddr string `json:"remote_addr"` } func NewProxyWrapper(cfg config.ProxyConf) *ProxyWrapper { @@ -78,16 +83,17 @@ func (pw *ProxyWrapper) GetStatus() *ProxyStatus { pw.mu.RLock() defer pw.mu.RUnlock() ps := &ProxyStatus{ - Name: pw.Name, - Type: pw.Type, - Status: pw.Status, - Err: pw.Err, - Cfg: pw.Cfg, + Name: pw.Name, + Type: pw.Type, + Status: pw.Status, + Err: pw.Err, + Cfg: pw.Cfg, + RemoteAddr: pw.RemoteAddr, } return ps } -func (pw *ProxyWrapper) Start(serverRespErr string) error { +func (pw *ProxyWrapper) Start(remoteAddr string, serverRespErr string) error { if pw.pxy != nil { pw.pxy.Close() pw.pxy = nil @@ -96,6 +102,7 @@ func (pw *ProxyWrapper) Start(serverRespErr string) error { if serverRespErr != "" { pw.mu.Lock() pw.Status = ProxyStatusStartErr + pw.RemoteAddr = remoteAddr pw.Err = serverRespErr pw.mu.Unlock() return fmt.Errorf(serverRespErr) @@ -104,6 +111,7 @@ func (pw *ProxyWrapper) Start(serverRespErr string) error { pxy := NewProxy(pw.Cfg) pw.mu.Lock() defer pw.mu.Unlock() + pw.RemoteAddr = remoteAddr if err := pxy.Run(); err != nil { pw.Status = ProxyStatusStartErr pw.Err = err.Error() @@ -139,6 +147,7 @@ func (pw *ProxyWrapper) Close() { func NewProxyManager(ctl *Control, msgSendCh chan (msg.Message), logPrefix string) *ProxyManager { return &ProxyManager{ + ctl: ctl, proxies: make(map[string]*ProxyWrapper), visitorCfgs: make(map[string]config.ProxyConf), visitors: make(map[string]Visitor), @@ -168,7 +177,7 @@ func (pm *ProxyManager) sendMsg(m msg.Message) error { return err } -func (pm *ProxyManager) StartProxy(name string, serverRespErr string) error { +func (pm *ProxyManager) StartProxy(name string, remoteAddr string, serverRespErr string) error { pm.mu.Lock() defer pm.mu.Unlock() if pm.closed { @@ -180,7 +189,7 @@ func (pm *ProxyManager) StartProxy(name string, serverRespErr string) error { return fmt.Errorf("no proxy found") } - if err := pxy.Start(serverRespErr); err != nil { + if err := pxy.Start(remoteAddr, serverRespErr); err != nil { errRet := err err = pm.sendMsg(&msg.CloseProxy{ ProxyName: name, diff --git a/models/msg/msg.go b/models/msg/msg.go index aac0ce70..dd0dde71 100644 --- a/models/msg/msg.go +++ b/models/msg/msg.go @@ -119,8 +119,9 @@ type NewProxy struct { } type NewProxyResp struct { - ProxyName string `json:"proxy_name"` - Error string `json:"error"` + ProxyName string `json:"proxy_name"` + RemoteAddr string `json:"remote_addr"` + Error string `json:"error"` } type CloseProxy struct { diff --git a/server/control.go b/server/control.go index 5e8fe95e..7492ce4b 100644 --- a/server/control.go +++ b/server/control.go @@ -308,7 +308,7 @@ func (ctl *Control) manager() { switch m := rawMsg.(type) { case *msg.NewProxy: // register proxy in this control - err := ctl.RegisterProxy(m) + remoteAddr, err := ctl.RegisterProxy(m) resp := &msg.NewProxyResp{ ProxyName: m.ProxyName, } @@ -316,6 +316,7 @@ func (ctl *Control) manager() { resp.Error = err.Error() ctl.conn.Warn("new proxy [%s] error: %v", m.ProxyName, err) } else { + resp.RemoteAddr = remoteAddr ctl.conn.Info("new proxy [%s] success", m.ProxyName) StatsNewProxy(m.ProxyName, m.ProxyType) } @@ -332,24 +333,24 @@ func (ctl *Control) manager() { } } -func (ctl *Control) RegisterProxy(pxyMsg *msg.NewProxy) (err error) { +func (ctl *Control) RegisterProxy(pxyMsg *msg.NewProxy) (remoteAddr string, err error) { var pxyConf config.ProxyConf // Load configures from NewProxy message and check. pxyConf, err = config.NewProxyConf(pxyMsg) if err != nil { - return err + return } // NewProxy will return a interface Proxy. // In fact it create different proxies by different proxy type, we just call run() here. pxy, err := NewProxy(ctl, pxyConf) if err != nil { - return err + return remoteAddr, err } - err = pxy.Run() + remoteAddr, err = pxy.Run() if err != nil { - return err + return } defer func() { if err != nil { @@ -359,13 +360,13 @@ func (ctl *Control) RegisterProxy(pxyMsg *msg.NewProxy) (err error) { err = ctl.svr.RegisterProxy(pxyMsg.ProxyName, pxy) if err != nil { - return err + return } ctl.mu.Lock() ctl.proxies[pxy.GetName()] = pxy ctl.mu.Unlock() - return nil + return } func (ctl *Control) CloseProxy(closeMsg *msg.CloseProxy) (err error) { diff --git a/server/proxy.go b/server/proxy.go index 8ce1e2b4..f744b8ba 100644 --- a/server/proxy.go +++ b/server/proxy.go @@ -19,6 +19,7 @@ import ( "fmt" "io" "net" + "strings" "sync" "time" @@ -29,11 +30,12 @@ import ( frpIo "github.com/fatedier/frp/utils/io" "github.com/fatedier/frp/utils/log" frpNet "github.com/fatedier/frp/utils/net" + "github.com/fatedier/frp/utils/util" "github.com/fatedier/frp/utils/vhost" ) type Proxy interface { - Run() error + Run() (remoteAddr string, err error) GetControl() *Control GetName() string GetConf() config.ProxyConf @@ -165,17 +167,19 @@ type TcpProxy struct { cfg *config.TcpProxyConf } -func (pxy *TcpProxy) Run() error { - listener, err := frpNet.ListenTcp(config.ServerCommonCfg.ProxyBindAddr, pxy.cfg.RemotePort) - if err != nil { - return err +func (pxy *TcpProxy) Run() (remoteAddr string, err error) { + remoteAddr = fmt.Sprintf(":%d", pxy.cfg.RemotePort) + listener, errRet := frpNet.ListenTcp(config.ServerCommonCfg.ProxyBindAddr, pxy.cfg.RemotePort) + if errRet != nil { + err = errRet + return } listener.AddLogPrefix(pxy.name) pxy.listeners = append(pxy.listeners, listener) pxy.Info("tcp proxy listen port [%d]", pxy.cfg.RemotePort) pxy.startListenHandler(pxy, HandleUserTcpConnection) - return nil + return } func (pxy *TcpProxy) GetConf() config.ProxyConf { @@ -193,7 +197,7 @@ type HttpProxy struct { closeFuncs []func() } -func (pxy *HttpProxy) Run() (err error) { +func (pxy *HttpProxy) Run() (remoteAddr string, err error) { routeConfig := vhost.VhostRouteConfig{ RewriteHost: pxy.cfg.HostHeaderRewrite, Username: pxy.cfg.HttpUser, @@ -205,16 +209,19 @@ func (pxy *HttpProxy) Run() (err error) { if len(locations) == 0 { locations = []string{""} } + + addrs := make([]string, 0) for _, domain := range pxy.cfg.CustomDomains { routeConfig.Domain = domain for _, location := range locations { routeConfig.Location = location - err := pxy.ctl.svr.httpReverseProxy.Register(routeConfig) + err = pxy.ctl.svr.httpReverseProxy.Register(routeConfig) if err != nil { - return err + return } tmpDomain := routeConfig.Domain tmpLocation := routeConfig.Location + addrs = append(addrs, util.CanonicalAddr(tmpDomain, int(config.ServerCommonCfg.VhostHttpPort))) pxy.closeFuncs = append(pxy.closeFuncs, func() { pxy.ctl.svr.httpReverseProxy.UnRegister(tmpDomain, tmpLocation) }) @@ -226,18 +233,20 @@ func (pxy *HttpProxy) Run() (err error) { routeConfig.Domain = pxy.cfg.SubDomain + "." + config.ServerCommonCfg.SubDomainHost for _, location := range locations { routeConfig.Location = location - err := pxy.ctl.svr.httpReverseProxy.Register(routeConfig) + err = pxy.ctl.svr.httpReverseProxy.Register(routeConfig) if err != nil { - return err + return } tmpDomain := routeConfig.Domain tmpLocation := routeConfig.Location + addrs = append(addrs, util.CanonicalAddr(tmpDomain, int(config.ServerCommonCfg.VhostHttpPort))) pxy.closeFuncs = append(pxy.closeFuncs, func() { pxy.ctl.svr.httpReverseProxy.UnRegister(tmpDomain, tmpLocation) }) pxy.Info("http proxy listen for host [%s] location [%s]", routeConfig.Domain, routeConfig.Location) } } + remoteAddr = strings.Join(addrs, ",") return } @@ -279,32 +288,38 @@ type HttpsProxy struct { cfg *config.HttpsProxyConf } -func (pxy *HttpsProxy) Run() (err error) { +func (pxy *HttpsProxy) Run() (remoteAddr string, err error) { routeConfig := &vhost.VhostRouteConfig{} + addrs := make([]string, 0) for _, domain := range pxy.cfg.CustomDomains { routeConfig.Domain = domain - l, err := pxy.ctl.svr.VhostHttpsMuxer.Listen(routeConfig) - if err != nil { - return err + l, errRet := pxy.ctl.svr.VhostHttpsMuxer.Listen(routeConfig) + if errRet != nil { + err = errRet + return } l.AddLogPrefix(pxy.name) pxy.Info("https proxy listen for host [%s]", routeConfig.Domain) pxy.listeners = append(pxy.listeners, l) + addrs = append(addrs, util.CanonicalAddr(routeConfig.Domain, int(config.ServerCommonCfg.VhostHttpsPort))) } if pxy.cfg.SubDomain != "" { routeConfig.Domain = pxy.cfg.SubDomain + "." + config.ServerCommonCfg.SubDomainHost - l, err := pxy.ctl.svr.VhostHttpsMuxer.Listen(routeConfig) - if err != nil { - return err + l, errRet := pxy.ctl.svr.VhostHttpsMuxer.Listen(routeConfig) + if errRet != nil { + err = errRet + return } l.AddLogPrefix(pxy.name) pxy.Info("https proxy listen for host [%s]", routeConfig.Domain) pxy.listeners = append(pxy.listeners, l) + addrs = append(addrs, util.CanonicalAddr(routeConfig.Domain, int(config.ServerCommonCfg.VhostHttpsPort))) } pxy.startListenHandler(pxy, HandleUserTcpConnection) + remoteAddr = strings.Join(addrs, ",") return } @@ -321,17 +336,18 @@ type StcpProxy struct { cfg *config.StcpProxyConf } -func (pxy *StcpProxy) Run() error { - listener, err := pxy.ctl.svr.visitorManager.Listen(pxy.GetName(), pxy.cfg.Sk) - if err != nil { - return err +func (pxy *StcpProxy) Run() (remoteAddr string, err error) { + listener, errRet := pxy.ctl.svr.visitorManager.Listen(pxy.GetName(), pxy.cfg.Sk) + if errRet != nil { + err = errRet + return } listener.AddLogPrefix(pxy.name) pxy.listeners = append(pxy.listeners, listener) pxy.Info("stcp proxy custom listen success") pxy.startListenHandler(pxy, HandleUserTcpConnection) - return nil + return } func (pxy *StcpProxy) GetConf() config.ProxyConf { @@ -350,10 +366,11 @@ type XtcpProxy struct { closeCh chan struct{} } -func (pxy *XtcpProxy) Run() error { +func (pxy *XtcpProxy) Run() (remoteAddr string, err error) { if pxy.ctl.svr.natHoleController == nil { pxy.Error("udp port for xtcp is not specified.") - return fmt.Errorf("xtcp is not supported in frps") + err = fmt.Errorf("xtcp is not supported in frps") + return } sidCh := pxy.ctl.svr.natHoleController.ListenClient(pxy.GetName(), pxy.cfg.Sk) go func() { @@ -362,21 +379,21 @@ func (pxy *XtcpProxy) Run() error { case <-pxy.closeCh: break case sid := <-sidCh: - workConn, err := pxy.GetWorkConnFromPool() - if err != nil { + workConn, errRet := pxy.GetWorkConnFromPool() + if errRet != nil { continue } m := &msg.NatHoleSid{ Sid: sid, } - err = msg.WriteMsg(workConn, m) - if err != nil { - pxy.Warn("write nat hole sid package error, %v", err) + errRet = msg.WriteMsg(workConn, m) + if errRet != nil { + pxy.Warn("write nat hole sid package error, %v", errRet) } } } }() - return nil + return } func (pxy *XtcpProxy) GetConf() config.ProxyConf { @@ -414,15 +431,18 @@ type UdpProxy struct { isClosed bool } -func (pxy *UdpProxy) Run() (err error) { - addr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", config.ServerCommonCfg.ProxyBindAddr, pxy.cfg.RemotePort)) - if err != nil { - return err +func (pxy *UdpProxy) Run() (remoteAddr string, err error) { + remoteAddr = fmt.Sprintf(":%d", pxy.cfg.RemotePort) + addr, errRet := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", config.ServerCommonCfg.ProxyBindAddr, pxy.cfg.RemotePort)) + if errRet != nil { + err = errRet + return } - udpConn, err := net.ListenUDP("udp", addr) - if err != nil { + udpConn, errRet := net.ListenUDP("udp", addr) + if errRet != nil { + err = errRet pxy.Warn("listen udp port error: %v", err) - return err + return } pxy.Info("udp proxy listen port [%d]", pxy.cfg.RemotePort) @@ -537,7 +557,7 @@ func (pxy *UdpProxy) Run() (err error) { udp.ForwardUserConn(udpConn, pxy.readCh, pxy.sendCh) pxy.Close() }() - return nil + return remoteAddr, nil } func (pxy *UdpProxy) GetConf() config.ProxyConf { diff --git a/utils/util/util.go b/utils/util/util.go index 87a6907a..88180e35 100644 --- a/utils/util/util.go +++ b/utils/util/util.go @@ -110,3 +110,12 @@ func PortRangesCut(portRanges [][2]int64, port int64) [][2]int64 { } return tmpRanges } + +func CanonicalAddr(host string, port int) (addr string) { + if port == 80 || port == 443 { + addr = host + } else { + addr = fmt.Sprintf("%s:%d", host, port) + } + return +}