Exemple #1
0
func (p *ProxyClient) GetRemoteConn(addr string, port int64) (c *conn.Conn, err error) {
	defer func() {
		if err != nil {
			c.Close()
		}
	}()

	c, err = conn.ConnectServer(addr, port)
	if err != nil {
		log.Error("ProxyName [%s], connect to server [%s:%d] error, %v", p.Name, addr, port, err)
		return
	}

	nowTime := time.Now().Unix()
	authKey := pcrypto.GetAuthKey(p.Name + p.AuthToken + fmt.Sprintf("%d", nowTime))
	req := &msg.ControlReq{
		Type:      consts.NewWorkConn,
		ProxyName: p.Name,
		AuthKey:   authKey,
		Timestamp: nowTime,
	}

	buf, _ := json.Marshal(req)
	err = c.Write(string(buf) + "\n")
	if err != nil {
		log.Error("ProxyName [%s], write to server error, %v", p.Name, err)
		return
	}

	err = nil
	return
}
Exemple #2
0
// recvive msg from reader, then encrypt msg into write
func PipeEncrypt(r net.Conn, w net.Conn, key string) error {
	laes := new(pcrypto.Pcrypto)
	if err := laes.Init([]byte(key)); err != nil {
		log.Error("Pcrypto Init error: %v", err)
		return fmt.Errorf("Pcrypto Init error: %v", err)
	}

	nreader := bufio.NewReader(r)
	buf := make([]byte, 10*1024)

	for {
		n, err := nreader.Read(buf)
		if err != nil {
			return err
		}
		res, err := laes.Encrypt(buf[:n])
		if err != nil {
			log.Error("Encrypt error: %v", err)
			return fmt.Errorf("Encrypt error: %v", err)
		}

		res = append(res, '\n')
		_, err = w.Write(res)
		if err != nil {
			return err
		}
	}
	return nil
}
Exemple #3
0
// decrypt msg from reader, then write into writer
func PipeDecrypt(r net.Conn, w net.Conn, key string) error {
	laes := new(pcrypto.Pcrypto)
	if err := laes.Init([]byte(key)); err != nil {
		log.Error("Pcrypto Init error: %v", err)
		return fmt.Errorf("Pcrypto Init error: %v", err)
	}

	nreader := bufio.NewReader(r)
	for {
		buf, err := nreader.ReadBytes('\n')
		if err != nil {
			return err
		}

		res, err := laes.Decrypt(buf)
		if err != nil {
			log.Error("Decrypt [%s] error, %v", string(buf), err)
			return fmt.Errorf("Decrypt [%s] error: %v", string(buf), err)
		}

		_, err = w.Write(res)
		if err != nil {
			return err
		}
	}
	return nil
}
Exemple #4
0
func loginToServer(cli *client.ProxyClient) (c *conn.Conn, err error) {
	c, err = conn.ConnectServer(client.ServerAddr, client.ServerPort)
	if err != nil {
		log.Error("ProxyName [%s], connect to server [%s:%d] error, %v", cli.Name, client.ServerAddr, client.ServerPort, err)
		return
	}

	nowTime := time.Now().Unix()
	req := &msg.ControlReq{
		Type:          consts.NewCtlConn,
		ProxyName:     cli.Name,
		UseEncryption: cli.UseEncryption,
		UseGzip:       cli.UseGzip,
		PrivilegeMode: cli.PrivilegeMode,
		ProxyType:     cli.Type,
		Timestamp:     nowTime,
	}
	if cli.PrivilegeMode {
		privilegeKey := pcrypto.GetAuthKey(cli.Name + client.PrivilegeToken + fmt.Sprintf("%d", nowTime))
		req.RemotePort = cli.RemotePort
		req.CustomDomains = cli.CustomDomains
		req.PrivilegeKey = privilegeKey
	} else {
		authKey := pcrypto.GetAuthKey(cli.Name + cli.AuthToken + fmt.Sprintf("%d", nowTime))
		req.AuthKey = authKey
	}

	buf, _ := json.Marshal(req)
	err = c.Write(string(buf) + "\n")
	if err != nil {
		log.Error("ProxyName [%s], write to server error, %v", cli.Name, err)
		return
	}

	res, err := c.ReadLine()
	if err != nil {
		log.Error("ProxyName [%s], read from server error, %v", cli.Name, err)
		return
	}
	log.Debug("ProxyName [%s], read [%s]", cli.Name, res)

	ctlRes := &msg.ControlRes{}
	if err = json.Unmarshal([]byte(res), &ctlRes); err != nil {
		log.Error("ProxyName [%s], format server response error, %v", cli.Name, err)
		return
	}

	if ctlRes.Code != 0 {
		log.Error("ProxyName [%s], start proxy error, %s", cli.Name, ctlRes.Msg)
		return c, fmt.Errorf("%s", ctlRes.Msg)
	}

	log.Debug("ProxyName [%s], connect to server [%s:%d] success!", cli.Name, client.ServerAddr, client.ServerPort)
	return
}
Exemple #5
0
// loop for reading messages from frpc after control connection is established
func msgReader(cli *client.ProxyClient, c *conn.Conn, msgSendChan chan interface{}) error {
	// for heartbeat
	var heartbeatTimeout bool = false
	timer := time.AfterFunc(time.Duration(client.HeartBeatTimeout)*time.Second, func() {
		heartbeatTimeout = true
		c.Close()
		log.Error("ProxyName [%s], heartbeatRes from frps timeout", cli.Name)
	})
	defer timer.Stop()

	for {
		buf, err := c.ReadLine()
		if err == io.EOF || c == nil || c.IsClosed() {
			c.Close()
			log.Warn("ProxyName [%s], frps close this control conn!", cli.Name)
			var delayTime time.Duration = 1

			// loop until reconnect to frps
			for {
				log.Info("ProxyName [%s], try to reconnect to frps [%s:%d]...", cli.Name, client.ServerAddr, client.ServerPort)
				c, err = loginToServer(cli)
				if err == nil {
					close(msgSendChan)
					msgSendChan = make(chan interface{}, 1024)
					go heartbeatSender(c, msgSendChan)
					go msgSender(cli, c, msgSendChan)
					break
				}

				if delayTime < 60 {
					delayTime = delayTime * 2
				}
				time.Sleep(delayTime * time.Second)
			}
			continue
		} else if err != nil {
			log.Warn("ProxyName [%s], read from frps error: %v", cli.Name, err)
			continue
		}

		ctlRes := &msg.ControlRes{}
		if err := json.Unmarshal([]byte(buf), &ctlRes); err != nil {
			log.Warn("ProxyName [%s], parse msg from frps error: %v : %s", cli.Name, err, buf)
			continue
		}

		switch ctlRes.Type {
		case consts.HeartbeatRes:
			log.Debug("ProxyName [%s], receive heartbeat response", cli.Name)
			timer.Reset(time.Duration(client.HeartBeatTimeout) * time.Second)
		case consts.NoticeUserConn:
			log.Debug("ProxyName [%s], new user connection", cli.Name)
			// join local and remote connections, async
			go cli.StartTunnel(client.ServerAddr, client.ServerPort)
		default:
			log.Warn("ProxyName [%s}, unsupport msgType [%d]", cli.Name, ctlRes.Type)
		}
	}
	return nil
}
Exemple #6
0
func (p *ProxyClient) GetLocalConn() (c *conn.Conn, err error) {
	c, err = conn.ConnectServer(p.LocalIp, p.LocalPort)
	if err != nil {
		log.Error("ProxyName [%s], connect to local port error, %v", p.Name, err)
	}
	return
}
Exemple #7
0
func apiReload(c *gin.Context) {
	res := &GeneralResponse{}
	defer func() {
		buf, _ := json.Marshal(res)
		log.Info("Http response [/api/reload]: %s", string(buf))
	}()

	log.Info("Http request: [/api/reload]")
	err := ReloadConf(ConfigFile)
	if err != nil {
		res.Code = 2
		res.Msg = fmt.Sprintf("%v", err)
		log.Error("frps reload error: %v", err)
	}
	c.JSON(200, res)
}
Exemple #8
0
// loop for reading messages from frpc after control connection is established
func msgReader(s *server.ProxyServer, c *conn.Conn, msgSendChan chan interface{}) error {
	// for heartbeat
	var heartbeatTimeout bool = false
	timer := time.AfterFunc(time.Duration(server.HeartBeatTimeout)*time.Second, func() {
		heartbeatTimeout = true
		s.Close()
		log.Error("ProxyName [%s], client heartbeat timeout", s.Name)
	})
	defer timer.Stop()

	for {
		buf, err := c.ReadLine()
		if err != nil {
			if err == io.EOF {
				log.Warn("ProxyName [%s], client is dead!", s.Name)
				return err
			} else if c == nil || c.IsClosed() {
				log.Warn("ProxyName [%s], client connection is closed", s.Name)
				return err
			}
			log.Warn("ProxyName [%s], read error: %v", s.Name, err)
			continue
		}

		cliReq := &msg.ControlReq{}
		if err := json.Unmarshal([]byte(buf), &cliReq); err != nil {
			log.Warn("ProxyName [%s], parse msg from frpc error: %v : %s", s.Name, err, buf)
			continue
		}

		switch cliReq.Type {
		case consts.HeartbeatReq:
			log.Debug("ProxyName [%s], get heartbeat", s.Name)
			timer.Reset(time.Duration(server.HeartBeatTimeout) * time.Second)
			heartbeatRes := &msg.ControlRes{
				Type: consts.HeartbeatRes,
			}
			msgSendChan <- heartbeatRes
		default:
			log.Warn("ProxyName [%s}, unsupport msgType [%d]", s.Name, cliReq.Type)
		}
	}
	return nil
}
Exemple #9
0
func ControlProcess(cli *client.ProxyClient, wait *sync.WaitGroup) {
	defer wait.Done()

	msgSendChan := make(chan interface{}, 1024)

	c, err := loginToServer(cli)
	if err != nil {
		log.Error("ProxyName [%s], connect to server failed!", cli.Name)
		return
	}
	defer c.Close()

	go heartbeatSender(c, msgSendChan)

	go msgSender(cli, c, msgSendChan)
	msgReader(cli, c, msgSendChan)

	close(msgSendChan)
}
Exemple #10
0
func main() {
	// the configures parsed from file will be replaced by those from command line if exist
	args, err := docopt.Parse(usage, nil, true, version.Full(), false)

	if args["-c"] != nil {
		server.ConfigFile = args["-c"].(string)
	}
	err = server.LoadConf(server.ConfigFile)
	if err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}

	// reload check
	if args["--reload"] != nil {
		if args["--reload"].(bool) {
			resp, err := http.Get("http://" + server.BindAddr + ":" + fmt.Sprintf("%d", server.DashboardPort) + "/api/reload")
			if err != nil {
				fmt.Printf("frps reload error: %v\n", err)
				os.Exit(1)
			} else {
				defer resp.Body.Close()
				body, err := ioutil.ReadAll(resp.Body)
				if err != nil {
					fmt.Printf("frps reload error: %v\n", err)
					os.Exit(1)
				}
				res := &server.GeneralResponse{}
				err = json.Unmarshal(body, &res)
				if err != nil {
					fmt.Printf("http response error: %v\n", err)
					os.Exit(1)
				} else if res.Code != 0 {
					fmt.Printf("reload error: %s\n", res.Msg)
					os.Exit(1)
				}
				fmt.Printf("reload success\n")
				os.Exit(0)
			}
		}
	}

	if args["-L"] != nil {
		if args["-L"].(string) == "console" {
			server.LogWay = "console"
		} else {
			server.LogWay = "file"
			server.LogFile = args["-L"].(string)
		}
	}

	if args["--log-level"] != nil {
		server.LogLevel = args["--log-level"].(string)
	}

	if args["--addr"] != nil {
		addr := strings.Split(args["--addr"].(string), ":")
		if len(addr) != 2 {
			fmt.Println("--addr format error: example 0.0.0.0:7000")
			os.Exit(1)
		}
		bindPort, err := strconv.ParseInt(addr[1], 10, 64)
		if err != nil {
			fmt.Println("--addr format error, example 0.0.0.0:7000")
			os.Exit(1)
		}
		server.BindAddr = addr[0]
		server.BindPort = bindPort
	}

	if args["-v"] != nil {
		if args["-v"].(bool) {
			fmt.Println(version.Full())
			os.Exit(0)
		}
	}

	log.InitLog(server.LogWay, server.LogFile, server.LogLevel, server.LogMaxDays)

	l, err := conn.Listen(server.BindAddr, server.BindPort)
	if err != nil {
		log.Error("Create server listener error, %v", err)
		os.Exit(1)
	}

	// create vhost if VhostHttpPort != 0
	if server.VhostHttpPort != 0 {
		vhostListener, err := conn.Listen(server.BindAddr, server.VhostHttpPort)
		if err != nil {
			log.Error("Create vhost http listener error, %v", err)
			os.Exit(1)
		}
		server.VhostMuxer, err = vhost.NewHttpMuxer(vhostListener, 30*time.Second)
		if err != nil {
			log.Error("Create vhost httpMuxer error, %v", err)
		}
	}

	// create dashboard web server if DashboardPort is set, so it won't be 0
	if server.DashboardPort != 0 {
		err := server.RunDashboardServer(server.BindAddr, server.DashboardPort)
		if err != nil {
			log.Error("Create dashboard web server error, %v", err)
			os.Exit(1)
		}
	}

	log.Info("Start frps success")
	ProcessControlConn(l)
}