root.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. // Copyright 2018 fatedier, fatedier@gmail.com
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package sub
  15. import (
  16. "context"
  17. "fmt"
  18. "io/ioutil"
  19. "net"
  20. "os"
  21. "os/signal"
  22. "strconv"
  23. "strings"
  24. "syscall"
  25. "time"
  26. "github.com/spf13/cobra"
  27. ini "github.com/vaughan0/go-ini"
  28. "github.com/fatedier/frp/client"
  29. "github.com/fatedier/frp/g"
  30. "github.com/fatedier/frp/models/config"
  31. "github.com/fatedier/frp/utils/log"
  32. "github.com/fatedier/frp/utils/version"
  33. )
  34. const (
  35. CfgFileTypeIni = iota
  36. CfgFileTypeCmd
  37. )
  38. var (
  39. cfgFile string
  40. showVersion bool
  41. serverAddr string
  42. user string
  43. protocol string
  44. token string
  45. logLevel string
  46. logFile string
  47. logMaxDays int
  48. proxyName string
  49. localIp string
  50. localPort int
  51. remotePort int
  52. useEncryption bool
  53. useCompression bool
  54. customDomains string
  55. subDomain string
  56. httpUser string
  57. httpPwd string
  58. locations string
  59. hostHeaderRewrite string
  60. role string
  61. sk string
  62. serverName string
  63. bindAddr string
  64. bindPort int
  65. )
  66. func init() {
  67. rootCmd.PersistentFlags().StringVarP(&cfgFile, "", "c", "./frpc.ini", "config file of frpc")
  68. rootCmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, "version of frpc")
  69. }
  70. var rootCmd = &cobra.Command{
  71. Use: "frpc",
  72. Short: "frpc is the client of frp (https://github.com/fatedier/frp)",
  73. RunE: func(cmd *cobra.Command, args []string) error {
  74. if showVersion {
  75. fmt.Println(version.Full())
  76. return nil
  77. }
  78. // Do not show command usage here.
  79. err := runClient(cfgFile)
  80. if err != nil {
  81. fmt.Println(err)
  82. os.Exit(1)
  83. }
  84. return nil
  85. },
  86. }
  87. func Execute() {
  88. if err := rootCmd.Execute(); err != nil {
  89. os.Exit(1)
  90. }
  91. }
  92. func handleSignal(svr *client.Service) {
  93. ch := make(chan os.Signal)
  94. signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
  95. <-ch
  96. svr.Close()
  97. time.Sleep(250 * time.Millisecond)
  98. os.Exit(0)
  99. }
  100. func parseClientCommonCfg(fileType int, filePath string) (err error) {
  101. if fileType == CfgFileTypeIni {
  102. err = parseClientCommonCfgFromIni(filePath)
  103. } else if fileType == CfgFileTypeCmd {
  104. err = parseClientCommonCfgFromCmd()
  105. }
  106. if err != nil {
  107. return
  108. }
  109. g.GlbClientCfg.CfgFile = cfgFile
  110. err = g.GlbClientCfg.ClientCommonConf.Check()
  111. if err != nil {
  112. return
  113. }
  114. return
  115. }
  116. func parseClientCommonCfgFromIni(filePath string) (err error) {
  117. b, err := ioutil.ReadFile(filePath)
  118. if err != nil {
  119. return err
  120. }
  121. content := string(b)
  122. cfg, err := config.UnmarshalClientConfFromIni(&g.GlbClientCfg.ClientCommonConf, content)
  123. if err != nil {
  124. return err
  125. }
  126. g.GlbClientCfg.ClientCommonConf = *cfg
  127. return
  128. }
  129. func parseClientCommonCfgFromCmd() (err error) {
  130. strs := strings.Split(serverAddr, ":")
  131. if len(strs) < 2 {
  132. err = fmt.Errorf("invalid server_addr")
  133. return
  134. }
  135. if strs[0] != "" {
  136. g.GlbClientCfg.ServerAddr = strs[0]
  137. }
  138. g.GlbClientCfg.ServerPort, err = strconv.Atoi(strs[1])
  139. if err != nil {
  140. err = fmt.Errorf("invalid server_addr")
  141. return
  142. }
  143. g.GlbClientCfg.User = user
  144. g.GlbClientCfg.Protocol = protocol
  145. g.GlbClientCfg.Token = token
  146. g.GlbClientCfg.LogLevel = logLevel
  147. g.GlbClientCfg.LogFile = logFile
  148. g.GlbClientCfg.LogMaxDays = int64(logMaxDays)
  149. return nil
  150. }
  151. func runClient(cfgFilePath string) (err error) {
  152. err = parseClientCommonCfg(CfgFileTypeIni, cfgFilePath)
  153. if err != nil {
  154. return
  155. }
  156. conf, err := ini.LoadFile(cfgFilePath)
  157. if err != nil {
  158. return err
  159. }
  160. pxyCfgs, visitorCfgs, err := config.LoadAllConfFromIni(g.GlbClientCfg.User, conf, g.GlbClientCfg.Start)
  161. if err != nil {
  162. return err
  163. }
  164. err = startService(pxyCfgs, visitorCfgs)
  165. return
  166. }
  167. func startService(pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf) (err error) {
  168. log.InitLog(g.GlbClientCfg.LogWay, g.GlbClientCfg.LogFile, g.GlbClientCfg.LogLevel, g.GlbClientCfg.LogMaxDays)
  169. if g.GlbClientCfg.DnsServer != "" {
  170. s := g.GlbClientCfg.DnsServer
  171. if !strings.Contains(s, ":") {
  172. s += ":53"
  173. }
  174. // Change default dns server for frpc
  175. net.DefaultResolver = &net.Resolver{
  176. PreferGo: true,
  177. Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
  178. return net.Dial("udp", s)
  179. },
  180. }
  181. }
  182. svr := client.NewService(pxyCfgs, visitorCfgs)
  183. // Capture the exit signal if we use kcp.
  184. if g.GlbClientCfg.Protocol == "kcp" {
  185. go handleSignal(svr)
  186. }
  187. err = svr.Run()
  188. return
  189. }