netclientutils.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. package netclientutils
  2. import (
  3. "errors"
  4. "fmt"
  5. "io/ioutil"
  6. "log"
  7. "math/rand"
  8. "net"
  9. "net/http"
  10. "os"
  11. "runtime"
  12. "strconv"
  13. "strings"
  14. "time"
  15. "crypto/tls"
  16. "google.golang.org/grpc"
  17. "google.golang.org/grpc/credentials"
  18. "golang.zx2c4.com/wireguard/wgctrl"
  19. "golang.zx2c4.com/wireguard/wgctrl/wgtypes"
  20. )
  21. const NO_DB_RECORD = "no result found"
  22. const NO_DB_RECORDS = "could not find any records"
  23. const LINUX_APP_DATA_PATH = "/etc/netclient"
  24. const WINDOWS_APP_DATA_PATH = "C:\\ProgramData\\Netclient"
  25. const WINDOWS_SVC_NAME = "netclient"
  26. const NETCLIENT_DEFAULT_PORT = 51821
  27. const DEFAULT_GC_PERCENT = 10
  28. func Log(message string) {
  29. log.SetFlags(log.Flags() &^ (log.Llongfile | log.Lshortfile))
  30. log.Println("[netclient]", message)
  31. }
  32. func IsWindows() bool {
  33. return runtime.GOOS == "windows"
  34. }
  35. // == database returned nothing error ==
  36. func IsEmptyRecord(err error) bool {
  37. if err == nil {
  38. return false
  39. }
  40. return strings.Contains(err.Error(), NO_DB_RECORD) || strings.Contains(err.Error(), NO_DB_RECORDS)
  41. }
  42. //generate an access key value
  43. func GenPass() string {
  44. var seededRand *rand.Rand = rand.New(
  45. rand.NewSource(time.Now().UnixNano()))
  46. length := 16
  47. charset := "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
  48. b := make([]byte, length)
  49. for i := range b {
  50. b[i] = charset[seededRand.Intn(len(charset))]
  51. }
  52. return string(b)
  53. }
  54. func GetPublicIP() (string, error) {
  55. iplist := []string{"http://ip.client.gravitl.com", "https://ifconfig.me", "http://api.ipify.org", "http://ipinfo.io/ip"}
  56. endpoint := ""
  57. var err error
  58. for _, ipserver := range iplist {
  59. resp, err := http.Get(ipserver)
  60. if err != nil {
  61. continue
  62. }
  63. defer resp.Body.Close()
  64. if resp.StatusCode == http.StatusOK {
  65. bodyBytes, err := ioutil.ReadAll(resp.Body)
  66. if err != nil {
  67. continue
  68. }
  69. endpoint = string(bodyBytes)
  70. break
  71. }
  72. }
  73. if err == nil && endpoint == "" {
  74. err = errors.New("public address not found")
  75. }
  76. return endpoint, err
  77. }
  78. func GetMacAddr() ([]string, error) {
  79. ifas, err := net.Interfaces()
  80. if err != nil {
  81. return nil, err
  82. }
  83. var as []string
  84. for _, ifa := range ifas {
  85. a := ifa.HardwareAddr.String()
  86. if a != "" {
  87. as = append(as, a)
  88. }
  89. }
  90. return as, nil
  91. }
  92. func parsePeers(keepalive int32, peers []wgtypes.PeerConfig) (string, error) {
  93. peersString := ""
  94. if keepalive <= 0 {
  95. keepalive = 20
  96. }
  97. for _, peer := range peers {
  98. newAllowedIps := []string{}
  99. for _, allowedIP := range peer.AllowedIPs {
  100. newAllowedIps = append(newAllowedIps, allowedIP.String())
  101. }
  102. peersString += fmt.Sprintf(`[Peer]
  103. PublicKey = %s
  104. AllowedIps = %s
  105. Endpoint = %s
  106. PersistentKeepAlive = %s
  107. `,
  108. peer.PublicKey.String(),
  109. strings.Join(newAllowedIps, ","),
  110. peer.Endpoint.String(),
  111. strconv.Itoa(int(keepalive)),
  112. )
  113. }
  114. return peersString, nil
  115. }
  116. func CreateUserSpaceConf(address string, privatekey string, listenPort string, mtu int32, perskeepalive int32, peers []wgtypes.PeerConfig) (string, error) {
  117. peersString, err := parsePeers(perskeepalive, peers)
  118. listenPortString := ""
  119. if mtu <= 0 {
  120. mtu = 1280
  121. }
  122. if listenPort != "" {
  123. listenPortString += "ListenPort = " + listenPort
  124. }
  125. if err != nil {
  126. return "", err
  127. }
  128. config := fmt.Sprintf(`[Interface]
  129. Address = %s
  130. PrivateKey = %s
  131. MTU = %s
  132. %s
  133. %s
  134. `,
  135. address+"/32",
  136. privatekey,
  137. strconv.Itoa(int(mtu)),
  138. listenPortString,
  139. peersString)
  140. return config, nil
  141. }
  142. func GetLocalIP(localrange string) (string, error) {
  143. _, localRange, err := net.ParseCIDR(localrange)
  144. if err != nil {
  145. return "", err
  146. }
  147. ifaces, err := net.Interfaces()
  148. if err != nil {
  149. return "", err
  150. }
  151. var local string
  152. found := false
  153. for _, i := range ifaces {
  154. if i.Flags&net.FlagUp == 0 {
  155. continue // interface down
  156. }
  157. if i.Flags&net.FlagLoopback != 0 {
  158. continue // loopback interface
  159. }
  160. addrs, err := i.Addrs()
  161. if err != nil {
  162. return "", err
  163. }
  164. for _, addr := range addrs {
  165. var ip net.IP
  166. switch v := addr.(type) {
  167. case *net.IPNet:
  168. if !found {
  169. ip = v.IP
  170. local = ip.String()
  171. found = localRange.Contains(ip)
  172. }
  173. case *net.IPAddr:
  174. if !found {
  175. ip = v.IP
  176. local = ip.String()
  177. found = localRange.Contains(ip)
  178. }
  179. }
  180. }
  181. }
  182. if !found || local == "" {
  183. return "", errors.New("Failed to find local IP in range " + localrange)
  184. }
  185. return local, nil
  186. }
  187. func GetFreePort(rangestart int32) (int32, error) {
  188. if rangestart == 0 {
  189. rangestart = NETCLIENT_DEFAULT_PORT
  190. }
  191. wgclient, err := wgctrl.New()
  192. if err != nil {
  193. return 0, err
  194. }
  195. devices, err := wgclient.Devices()
  196. if err != nil {
  197. return 0, err
  198. }
  199. for x := rangestart; x <= 65535; x++ {
  200. conflict := false
  201. for _, i := range devices {
  202. if int32(i.ListenPort) == x {
  203. conflict = true
  204. break
  205. }
  206. }
  207. if conflict {
  208. continue
  209. }
  210. return int32(x), nil
  211. }
  212. return rangestart, err
  213. }
  214. // == OS PATH FUNCTIONS ==
  215. func GetHomeDirWindows() string {
  216. if IsWindows() {
  217. home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
  218. if home == "" {
  219. home = os.Getenv("USERPROFILE")
  220. }
  221. return home
  222. }
  223. return os.Getenv("HOME")
  224. }
  225. func GetNetclientPath() string {
  226. if IsWindows() {
  227. return WINDOWS_APP_DATA_PATH
  228. } else {
  229. return LINUX_APP_DATA_PATH
  230. }
  231. }
  232. func GetNetclientPathSpecific() string {
  233. if IsWindows() {
  234. return WINDOWS_APP_DATA_PATH + "\\"
  235. } else {
  236. return LINUX_APP_DATA_PATH + "/"
  237. }
  238. }
  239. func GRPCRequestOpts(isSecure string) grpc.DialOption {
  240. var requestOpts grpc.DialOption
  241. requestOpts = grpc.WithInsecure()
  242. if isSecure == "on" {
  243. h2creds := credentials.NewTLS(&tls.Config{NextProtos: []string{"h2"}})
  244. requestOpts = grpc.WithTransportCredentials(h2creds)
  245. }
  246. return requestOpts
  247. }