123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449 |
- package ncutils
- import (
- "crypto/tls"
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "log"
- "math/rand"
- "net"
- "net/http"
- "os"
- "os/exec"
- "regexp"
- "runtime"
- "strconv"
- "strings"
- "time"
- "golang.zx2c4.com/wireguard/wgctrl"
- "golang.zx2c4.com/wireguard/wgctrl/wgtypes"
- "google.golang.org/grpc"
- "google.golang.org/grpc/credentials"
- )
- // NO_DB_RECORD - error message result
- const NO_DB_RECORD = "no result found"
- // NO_DB_RECORDS - error record result
- const NO_DB_RECORDS = "could not find any records"
- // LINUX_APP_DATA_PATH - linux path
- const LINUX_APP_DATA_PATH = "/etc/netclient"
- // WINDOWS_APP_DATA_PATH - windows path
- const WINDOWS_APP_DATA_PATH = "C:\\ProgramData\\Netclient"
- // WINDOWS_APP_DATA_PATH - windows path
- const WINDOWS_WG_DATA_PATH = "C:\\Program Files\\WireGuard\\Data\\Configurations"
- // WINDOWS_SVC_NAME - service name
- const WINDOWS_SVC_NAME = "netclient"
- // NETCLIENT_DEFAULT_PORT - default port
- const NETCLIENT_DEFAULT_PORT = 51821
- // DEFAULT_GC_PERCENT - garbage collection percent
- const DEFAULT_GC_PERCENT = 10
- // Log - logs a message
- func Log(message string) {
- log.SetFlags(log.Flags() &^ (log.Llongfile | log.Lshortfile))
- log.Println("[netclient]", message)
- }
- // IsWindows - checks if is windows
- func IsWindows() bool {
- return runtime.GOOS == "windows"
- }
- // IsMac - checks if is a mac
- func IsMac() bool {
- return runtime.GOOS == "darwin"
- }
- // IsLinux - checks if is linux
- func IsLinux() bool {
- return runtime.GOOS == "linux"
- }
- // IsLinux - checks if is linux
- func IsFreeBSD() bool {
- return runtime.GOOS == "freebsd"
- }
- // GetWireGuard - checks if wg is installed
- func GetWireGuard() string {
- userspace := os.Getenv("WG_QUICK_USERSPACE_IMPLEMENTATION")
- if userspace != "" && (userspace == "boringtun" || userspace == "wireguard-go") {
- return userspace
- }
- return "wg"
- }
- // IsKernel - checks if running kernel WireGuard
- func IsKernel() bool {
- //TODO
- //Replace && true with some config file value
- //This value should be something like kernelmode, which should be 'on' by default.
- return IsLinux() && os.Getenv("WG_QUICK_USERSPACE_IMPLEMENTATION") == ""
- }
- // IsEmptyRecord - repeat from database
- func IsEmptyRecord(err error) bool {
- if err == nil {
- return false
- }
- return strings.Contains(err.Error(), NO_DB_RECORD) || strings.Contains(err.Error(), NO_DB_RECORDS)
- }
- //generate an access key value
- // GenPass - generates a pass
- func GenPass() string {
- var seededRand *rand.Rand = rand.New(
- rand.NewSource(time.Now().UnixNano()))
- length := 16
- charset := "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
- b := make([]byte, length)
- for i := range b {
- b[i] = charset[seededRand.Intn(len(charset))]
- }
- return string(b)
- }
- // GetPublicIP - gets public ip
- func GetPublicIP() (string, error) {
- iplist := []string{"https://ip.client.gravitl.com", "https://ifconfig.me", "https://api.ipify.org", "https://ipinfo.io/ip"}
- endpoint := ""
- var err error
- for _, ipserver := range iplist {
- resp, err := http.Get(ipserver)
- if err != nil {
- continue
- }
- defer resp.Body.Close()
- if resp.StatusCode == http.StatusOK {
- bodyBytes, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- continue
- }
- endpoint = string(bodyBytes)
- break
- }
- }
- if err == nil && endpoint == "" {
- err = errors.New("public address not found")
- }
- return endpoint, err
- }
- // GetMacAddr - get's mac address
- func GetMacAddr() ([]string, error) {
- ifas, err := net.Interfaces()
- if err != nil {
- return nil, err
- }
- var as []string
- for _, ifa := range ifas {
- a := ifa.HardwareAddr.String()
- if a != "" {
- as = append(as, a)
- }
- }
- return as, nil
- }
- func parsePeers(keepalive int32, peers []wgtypes.PeerConfig) (string, error) {
- peersString := ""
- if keepalive <= 0 {
- keepalive = 20
- }
- for _, peer := range peers {
- endpointString := ""
- if peer.Endpoint != nil && peer.Endpoint.String() != "" {
- endpointString += "Endpoint = " + peer.Endpoint.String()
- }
- newAllowedIps := []string{}
- for _, allowedIP := range peer.AllowedIPs {
- newAllowedIps = append(newAllowedIps, allowedIP.String())
- }
- peersString += fmt.Sprintf(`[Peer]
- PublicKey = %s
- AllowedIps = %s
- PersistentKeepAlive = %s
- %s
- `,
- peer.PublicKey.String(),
- strings.Join(newAllowedIps, ","),
- strconv.Itoa(int(keepalive)),
- endpointString,
- )
- }
- return peersString, nil
- }
- // GetLocalIP - gets local ip of machine
- func GetLocalIP(localrange string) (string, error) {
- _, localRange, err := net.ParseCIDR(localrange)
- if err != nil {
- return "", err
- }
- ifaces, err := net.Interfaces()
- if err != nil {
- return "", err
- }
- var local string
- found := false
- for _, i := range ifaces {
- if i.Flags&net.FlagUp == 0 {
- continue // interface down
- }
- if i.Flags&net.FlagLoopback != 0 {
- continue // loopback interface
- }
- addrs, err := i.Addrs()
- if err != nil {
- return "", err
- }
- for _, addr := range addrs {
- var ip net.IP
- switch v := addr.(type) {
- case *net.IPNet:
- if !found {
- ip = v.IP
- local = ip.String()
- found = localRange.Contains(ip)
- }
- case *net.IPAddr:
- if !found {
- ip = v.IP
- local = ip.String()
- found = localRange.Contains(ip)
- }
- }
- }
- }
- if !found || local == "" {
- return "", errors.New("Failed to find local IP in range " + localrange)
- }
- return local, nil
- }
- func GetNetworkIPMask(networkstring string) (string, string, error) {
- ip, ipnet, err := net.ParseCIDR(networkstring)
- if err != nil {
- return "", "", err
- }
- ipstring := ip.String()
- mask := ipnet.Mask
- maskstring := fmt.Sprintf("%d.%d.%d.%d", mask[0], mask[1], mask[2], mask[3])
- //maskstring := ipnet.Mask.String()
- return ipstring, maskstring, err
- }
- // GetFreePort - gets free port of machine
- func GetFreePort(rangestart int32) (int32, error) {
- if rangestart == 0 {
- rangestart = NETCLIENT_DEFAULT_PORT
- }
- wgclient, err := wgctrl.New()
- if err != nil {
- return 0, err
- }
- devices, err := wgclient.Devices()
- if err != nil {
- return 0, err
- }
- for x := rangestart; x <= 65535; x++ {
- conflict := false
- for _, i := range devices {
- if int32(i.ListenPort) == x {
- conflict = true
- break
- }
- }
- if conflict {
- continue
- }
- return int32(x), nil
- }
- return rangestart, err
- }
- // == OS PATH FUNCTIONS ==
- // GetHomeDirWindows - gets home directory in windows
- func GetHomeDirWindows() string {
- if IsWindows() {
- home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
- if home == "" {
- home = os.Getenv("USERPROFILE")
- }
- return home
- }
- return os.Getenv("HOME")
- }
- // GetNetclientPath - gets netclient path locally
- func GetNetclientPath() string {
- if IsWindows() {
- return WINDOWS_APP_DATA_PATH
- } else if IsMac() {
- return "/etc/netclient/"
- } else {
- return LINUX_APP_DATA_PATH
- }
- }
- // GetNetclientPathSpecific - gets specific netclient config path
- func GetNetclientPathSpecific() string {
- if IsWindows() {
- return WINDOWS_APP_DATA_PATH + "\\"
- } else if IsMac() {
- return "/etc/netclient/config/"
- } else {
- return LINUX_APP_DATA_PATH + "/config/"
- }
- }
- // GetNetclientPathSpecific - gets specific netclient config path
- func GetWGPathSpecific() string {
- if IsWindows() {
- return WINDOWS_WG_DATA_PATH + "\\"
- } else {
- return "/etc/wireguard/"
- }
- }
- // GRPCRequestOpts - gets grps request opts
- func GRPCRequestOpts(isSecure string) grpc.DialOption {
- var requestOpts grpc.DialOption
- requestOpts = grpc.WithInsecure()
- if isSecure == "on" {
- h2creds := credentials.NewTLS(&tls.Config{NextProtos: []string{"h2"}})
- requestOpts = grpc.WithTransportCredentials(h2creds)
- }
- return requestOpts
- }
- // Copy - copies a src file to dest
- func Copy(src, dst string) error {
- sourceFileStat, err := os.Stat(src)
- if err != nil {
- return err
- }
- if !sourceFileStat.Mode().IsRegular() {
- return errors.New(src + " is not a regular file")
- }
- source, err := os.Open(src)
- if err != nil {
- return err
- }
- defer source.Close()
- destination, err := os.Create(dst)
- if err != nil {
- return err
- }
- defer destination.Close()
- _, err = io.Copy(destination, source)
- if err != nil {
- return err
- }
- err = os.Chmod(dst, 0755)
- return err
- }
- // RunsCmds - runs cmds
- func RunCmds(commands []string, printerr bool) error {
- var err error
- for _, command := range commands {
- args := strings.Fields(command)
- out, err := exec.Command(args[0], args[1:]...).CombinedOutput()
- if err != nil && printerr {
- log.Println("error running command:", command)
- log.Println(strings.TrimSuffix(string(out), "\n"))
- }
- }
- return err
- }
- // FileExists - checks if file exists locally
- func FileExists(f string) bool {
- info, err := os.Stat(f)
- if os.IsNotExist(err) {
- return false
- }
- if err != nil && strings.Contains(err.Error(), "not a directory") {
- return false
- }
- if err != nil {
- Log("error reading file: " + f + ", " + err.Error())
- }
- return !info.IsDir()
- }
- // PrintLog - prints log
- func PrintLog(message string, loglevel int) {
- log.SetFlags(log.Flags() &^ (log.Llongfile | log.Lshortfile))
- if loglevel < 2 {
- log.Println("[netclient]", message)
- }
- }
- // GetSystemNetworks - get networks locally
- func GetSystemNetworks() ([]string, error) {
- var networks []string
- files, err := ioutil.ReadDir(GetNetclientPathSpecific())
- if err != nil {
- return networks, err
- }
- for _, f := range files {
- if strings.Contains(f.Name(), "netconfig-") {
- networkname := stringAfter(f.Name(), "netconfig-")
- networks = append(networks, networkname)
- }
- }
- return networks, err
- }
- func stringAfter(original string, substring string) string {
- position := strings.LastIndex(original, substring)
- if position == -1 {
- return ""
- }
- adjustedPosition := position + len(substring)
- if adjustedPosition >= len(original) {
- return ""
- }
- return original[adjustedPosition:]
- }
- func ShortenString(input string, length int) string {
- output := input
- if len(input) > length {
- output = input[0:length]
- }
- return output
- }
- func DNSFormatString(input string) string {
- reg, err := regexp.Compile("[^a-zA-Z0-9-]+")
- if err != nil {
- Log("error with regex: " + err.Error())
- return ""
- }
- return reg.ReplaceAllString(input, "")
- }
|