From ede9674a0806b51e886224be9e1b46d6a9a1c3a6 Mon Sep 17 00:00:00 2001 From: Akilan Date: Thu, 29 Dec 2022 03:17:42 +0000 Subject: [PATCH] base version working for reverse proxy --- config/config.go | 258 +++++++++++++++---------------- p2p/frp/client.go | 174 ++++++++++----------- p2p/ip_table.json | 7 +- p2p/iptable.go | 344 ++++++++++++++++++++++-------------------- p2p/speedtest.go | 144 +++++++++--------- p2p/testingMetrics.go | 30 ++-- server/server.go | 332 ++++++++++++++++++++-------------------- 7 files changed, 655 insertions(+), 634 deletions(-) diff --git a/config/config.go b/config/config.go index 6c648e0..25e154a 100644 --- a/config/config.go +++ b/config/config.go @@ -1,73 +1,74 @@ package config import ( - "github.com/spf13/viper" - "io" - "os" + "github.com/spf13/viper" + "io" + "os" ) var ( - defaultPath string - defaults = map[string]interface{}{} - configName = "config" - configType = "json" - configFile = "config.json" - configPaths []string - defaultEnvName = "P2PRC" + defaultPath string + defaults = map[string]interface{}{} + configName = "config" + configType = "json" + configFile = "config.json" + configPaths []string + defaultEnvName = "P2PRC" ) type Config struct { - IPTable string - DockerContainers string - DefaultDockerFile string - SpeedTestFile string - IPV6Address string - PluginPath string - TrackContainersPath string - ServerPort string - GroupTrackContainersPath string - FRPServerPort string - //NetworkInterface string - //NetworkInterfaceIPV6Index int + IPTable string + DockerContainers string + DefaultDockerFile string + SpeedTestFile string + IPV6Address string + PluginPath string + TrackContainersPath string + ServerPort string + GroupTrackContainersPath string + FRPServerPort string + BehindNAT string + //NetworkInterface string + //NetworkInterfaceIPV6Index int } // Exists reports whether the named file or directory exists. func fileExists(name string) bool { - if _, err := os.Stat(name); err != nil { - if os.IsNotExist(err) { - return false - } - } - return true + if _, err := os.Stat(name); err != nil { + if os.IsNotExist(err) { + return false + } + } + return true } // Copy the src file to dst. Any existing file will be overwritten and will not // copy file attributes. // Source: https://stackoverflow.com/questions/21060945/simple-way-to-copy-a-file func Copy(src, dst string) error { - in, err := os.Open(src) - if err != nil { - return err - } - defer in.Close() + in, err := os.Open(src) + if err != nil { + return err + } + defer in.Close() - out, err := os.Create(dst) - if err != nil { - return err - } - defer out.Close() + out, err := os.Create(dst) + if err != nil { + return err + } + defer out.Close() - _, err = io.Copy(out, in) - if err != nil { - return err - } - return out.Close() + _, err = io.Copy(out, in) + if err != nil { + return err + } + return out.Close() } // GetPathP2PRC Getting P2PRC Directory from environment variable func GetPathP2PRC() (string, error) { - curDir := os.Getenv(defaultEnvName) - return curDir + "/", nil + curDir := os.Getenv(defaultEnvName) + return curDir + "/", nil } // SetEnvName Sets the environment name @@ -75,112 +76,113 @@ func GetPathP2PRC() (string, error) { // your environment variable // This is useful when extending the use case of P2PRC func SetEnvName(EnvName string) error { - defaultEnvName = EnvName - // Handling error to be implemented only if needed - return nil + defaultEnvName = EnvName + // Handling error to be implemented only if needed + return nil } // GetCurrentPath Getting P2PRC Directory from environment variable func GetCurrentPath() (string, error) { - curDir := os.Getenv("PWD") - return curDir + "/", nil + curDir := os.Getenv("PWD") + return curDir + "/", nil } // SetDefaults This function to be called only during a // make install func SetDefaults() error { - //Setting current directory to default path - defaultPath, err := GetPathP2PRC() - if err != nil { - return err - } + //Setting current directory to default path + defaultPath, err := GetPathP2PRC() + if err != nil { + return err + } - //Creates ip_table.json in the json directory - err = Copy("p2p/ip_table.json", "p2p/iptable/ip_table.json") - if err != nil { - return err - } + //Creates ip_table.json in the json directory + err = Copy("p2p/ip_table.json", "p2p/iptable/ip_table.json") + if err != nil { + return err + } - //Creates a copy of trackcontainers.json in the appropriate directory - err = Copy("client/trackcontainers.json", "client/trackcontainers/trackcontainers.json") - if err != nil { - return err - } + //Creates a copy of trackcontainers.json in the appropriate directory + err = Copy("client/trackcontainers.json", "client/trackcontainers/trackcontainers.json") + if err != nil { + return err + } - //Creates a copy of trackcontainers.json in the appropriate directory - err = Copy("client/grouptrackcontainers.json", "client/trackcontainers/grouptrackcontainers.json") - if err != nil { - return err - } + //Creates a copy of trackcontainers.json in the appropriate directory + err = Copy("client/grouptrackcontainers.json", "client/trackcontainers/grouptrackcontainers.json") + if err != nil { + return err + } - //Setting default paths for the config file - defaults["IPTable"] = defaultPath + "p2p/iptable/ip_table.json" - defaults["DefaultDockerFile"] = defaultPath + "server/docker/containers/docker-ubuntu-sshd/" - defaults["DockerContainers"] = defaultPath + "server/docker/containers/" - defaults["SpeedTestFile"] = defaultPath + "p2p/50.bin" - defaults["IPV6Address"] = "" - defaults["PluginPath"] = defaultPath + "plugin/deploy" - defaults["TrackContainersPath"] = defaultPath + "client/trackcontainers/trackcontainers.json" - defaults["GroupTrackContainersPath"] = defaultPath + "client/trackcontainers/grouptrackcontainers.json" - defaults["ServerPort"] = "8088" - defaults["FRPServerPort"] = "0" - //defaults["NetworkInterface"] = "wlp0s20f3" - //defaults["NetworkInterfaceIPV6Index"] = "2" + //Setting default paths for the config file + defaults["IPTable"] = defaultPath + "p2p/iptable/ip_table.json" + defaults["DefaultDockerFile"] = defaultPath + "server/docker/containers/docker-ubuntu-sshd/" + defaults["DockerContainers"] = defaultPath + "server/docker/containers/" + defaults["SpeedTestFile"] = defaultPath + "p2p/50.bin" + defaults["IPV6Address"] = "" + defaults["PluginPath"] = defaultPath + "plugin/deploy" + defaults["TrackContainersPath"] = defaultPath + "client/trackcontainers/trackcontainers.json" + defaults["GroupTrackContainersPath"] = defaultPath + "client/trackcontainers/grouptrackcontainers.json" + defaults["ServerPort"] = "8088" + defaults["FRPServerPort"] = "0" + defaults["BehindNAT"] = "True" + //defaults["NetworkInterface"] = "wlp0s20f3" + //defaults["NetworkInterfaceIPV6Index"] = "2" - //Paths to search for config file - configPaths = append(configPaths, defaultPath) + //Paths to search for config file + configPaths = append(configPaths, defaultPath) - if fileExists(defaultPath + "config.json") { - err := os.Remove(defaultPath + "config.json") - if err != nil { - return err - } - } + if fileExists(defaultPath + "config.json") { + err := os.Remove(defaultPath + "config.json") + if err != nil { + return err + } + } - //Calling configuration file - _, err = ConfigInit() - if err != nil { - return err - } - return nil + //Calling configuration file + _, err = ConfigInit() + if err != nil { + return err + } + return nil } func ConfigInit() (*Config, error) { - //Setting current directory to default path - defaultPath, err := GetPathP2PRC() - if err != nil { - return nil, err - } - //Paths to search for config file - configPaths = append(configPaths, defaultPath) + //Setting current directory to default path + defaultPath, err := GetPathP2PRC() + if err != nil { + return nil, err + } + //Paths to search for config file + configPaths = append(configPaths, defaultPath) - //Add all possible configurations paths - for _, v := range configPaths { - viper.AddConfigPath(v) - } + //Add all possible configurations paths + for _, v := range configPaths { + viper.AddConfigPath(v) + } - //Read config file - if err := viper.ReadInConfig(); err != nil { - // If the error thrown is config file not found - //Sets default configuration to viper - for k, v := range defaults { - viper.SetDefault(k, v) - } - viper.SetConfigName(configName) - viper.SetConfigFile(configFile) - viper.SetConfigType(configType) + //Read config file + if err := viper.ReadInConfig(); err != nil { + // If the error thrown is config file not found + //Sets default configuration to viper + for k, v := range defaults { + viper.SetDefault(k, v) + } + viper.SetConfigName(configName) + viper.SetConfigFile(configFile) + viper.SetConfigType(configType) - if err = viper.WriteConfig(); err != nil { - return nil, err - } - } + if err = viper.WriteConfig(); err != nil { + return nil, err + } + } - // Adds configuration to the struct - var config Config - if err := viper.Unmarshal(&config); err != nil { - return nil, err - } + // Adds configuration to the struct + var config Config + if err := viper.Unmarshal(&config); err != nil { + return nil, err + } - return &config, nil + return &config, nil } diff --git a/p2p/frp/client.go b/p2p/frp/client.go index 3bd51b4..62a9013 100644 --- a/p2p/frp/client.go +++ b/p2p/frp/client.go @@ -1,134 +1,140 @@ package frp import ( - "git.sr.ht/~akilan1999/p2p-rendering-computation/server/docker" - "github.com/fatedier/frp/client" - "github.com/fatedier/frp/pkg/config" - "math/rand" - "strconv" + "git.sr.ht/~akilan1999/p2p-rendering-computation/server/docker" + "github.com/fatedier/frp/client" + "github.com/fatedier/frp/pkg/config" + "math/rand" + "strconv" ) // Client This struct stores // client information with server // proxy connected type Client struct { - Name string - Server *Server - ClientMappings []ClientMapping + Name string + Server *Server + ClientMappings []ClientMapping } // ClientMapping Stores client mapping ports // to proxy server type ClientMapping struct { - LocalIP string - LocalPort int - RemotePort int + LocalIP string + LocalPort int + RemotePort int } // StartFRPClientForServer Starts Server using FRP server // returns back a port -func StartFRPClientForServer(ipaddress string, port string) (string, error) { - // Setup server information - var s Server - s.address = ipaddress - // convert port to int - portInt, err := strconv.Atoi(port) - if err != nil { - return "", err - } - s.port = portInt +func StartFRPClientForServer(ipaddress string, port string, localport string) (string, error) { + // Setup server information + var s Server + s.address = ipaddress + // convert port to int + portInt, err := strconv.Atoi(port) + if err != nil { + return "", err + } + s.port = portInt - // Setup client information - var c Client - c.Name = "ServerPort" - c.Server = &s + // Setup client information + var c Client + c.Name = "ServerPort" + c.Server = &s - //random port - randPort := rangeIn(10000, 99999) - c.ClientMappings = []ClientMapping{ - { - LocalIP: ipaddress, - LocalPort: randPort, - RemotePort: randPort, - }, - } + // converts localport to int + portInt, err = strconv.Atoi(localport) + if err != nil { + return "", err + } - // Start client server - go c.StartFRPClient() + //random port + randPort := rangeIn(10000, 99999) + c.ClientMappings = []ClientMapping{ + { + LocalIP: ipaddress, + LocalPort: portInt, + RemotePort: randPort, + }, + } - return strconv.Itoa(randPort), nil + // Start client server + go c.StartFRPClient() + + return strconv.Itoa(randPort), nil } func StartFRPCDockerContainer(ipaddress string, port string, docker *docker.DockerVM) error { - // Setup server information - var s Server - s.address = ipaddress - // convert port to int - portInt, err := strconv.Atoi(port) - if err != nil { - return err - } - s.port = portInt + // Setup server information + var s Server + s.address = ipaddress + // convert port to int + portInt, err := strconv.Atoi(port) + if err != nil { + return err + } + s.port = portInt - // Setup client information - var c Client - c.Name = "ServerPort" - c.Server = &s + // Setup client information + var c Client + c.Name = "ServerPort" + c.Server = &s - // set client mapping - var clientMappings []ClientMapping - for i, _ := range docker.Ports.PortSet { - // Set client mapping - var clientMapping ClientMapping - portMap := docker.Ports.PortSet[i].ExternalPort - clientMapping.LocalPort = portMap - clientMapping.RemotePort = portMap - // Append to array - clientMappings = append(clientMappings, clientMapping) - } + // set client mapping + var clientMappings []ClientMapping + for i, _ := range docker.Ports.PortSet { + // Set client mapping + var clientMapping ClientMapping + portMap := docker.Ports.PortSet[i].ExternalPort + clientMapping.LocalPort = portMap + clientMapping.RemotePort = portMap + // Append to array + clientMappings = append(clientMappings, clientMapping) + } - // Start client server - go c.StartFRPClient() + // Start client server + go c.StartFRPClient() - return nil + return nil } // StartFRPClient Starts FRP client func (c *Client) StartFRPClient() error { - cfg := config.GetDefaultClientConf() + cfg := config.GetDefaultClientConf() - var proxyConfs map[string]config.ProxyConf - var visitorCfgs map[string]config.VisitorConf + var proxyConfs map[string]config.ProxyConf + var visitorCfgs map[string]config.VisitorConf - proxyConfs = make(map[string]config.ProxyConf) + proxyConfs = make(map[string]config.ProxyConf) - cfg.ServerAddr = c.Server.address - cfg.ServerPort = c.Server.port + cfg.ServerAddr = c.Server.address + cfg.ServerPort = c.Server.port - for i, _ := range c.ClientMappings { - var tcpcnf config.TCPProxyConf - tcpcnf.LocalIP = c.ClientMappings[i].LocalIP - tcpcnf.LocalPort = c.ClientMappings[i].LocalPort - tcpcnf.RemotePort = c.ClientMappings[i].RemotePort + for i, _ := range c.ClientMappings { + var tcpcnf config.TCPProxyConf + tcpcnf.LocalIP = c.ClientMappings[i].LocalIP + tcpcnf.LocalPort = c.ClientMappings[i].LocalPort + tcpcnf.RemotePort = c.ClientMappings[i].RemotePort - proxyConfs[tcpcnf.ProxyName] = &tcpcnf - } + proxyConfs[tcpcnf.ProxyName] = &tcpcnf + } - cli, err := client.NewService(cfg, proxyConfs, visitorCfgs, "") - if err != nil { - return err - } + cli, err := client.NewService(cfg, proxyConfs, visitorCfgs, "") + if err != nil { + return err + } - cli.Run() + cli.Run() - return nil + return nil } // helper function to generate random // number in a certain range func rangeIn(low, hi int) int { - return low + rand.Intn(hi-low) + return low + rand.Intn(hi-low) } diff --git a/p2p/ip_table.json b/p2p/ip_table.json index 6c8ae9f..704faf9 100644 --- a/p2p/ip_table.json +++ b/p2p/ip_table.json @@ -1,12 +1,13 @@ { "ip_address": [ { - "ipv4": "139.162.246.221", + "ipv4": "64.227.168.102", "ipv6": "", "latency": 0, "download": 0, "upload": 0, - "serverport": "8088" + "serverport": "8088", + "proxyport": "7000" } ] -} \ No newline at end of file +} diff --git a/p2p/iptable.go b/p2p/iptable.go index 845babf..c8a8b82 100644 --- a/p2p/iptable.go +++ b/p2p/iptable.go @@ -1,243 +1,255 @@ package p2p import ( - "encoding/json" - "fmt" - "git.sr.ht/~akilan1999/p2p-rendering-computation/config" - "io/ioutil" - "net" - "net/http" - "os" - "time" + "encoding/json" + "fmt" + "git.sr.ht/~akilan1999/p2p-rendering-computation/config" + "io/ioutil" + "net" + "net/http" + "os" + "time" ) // Get IP table Data type IpAddresses struct { - IpAddress []IpAddress `json:"ip_address"` + IpAddress []IpAddress `json:"ip_address"` } type IpAddress struct { - Ipv4 string `json:"ipv4"` - Ipv6 string `json:"ipv6"` - Latency time.Duration `json:"latency"` - Download float64 `json:"download"` - Upload float64 `json:"upload"` - ServerPort string `json:"serverport"` - ProxyPort string `json:"proxyport"` + Ipv4 string `json:"ipv4"` + Ipv6 string `json:"ipv6"` + Latency time.Duration `json:"latency"` + Download float64 `json:"download"` + Upload float64 `json:"upload"` + ServerPort string `json:"serverport"` + ProxyPort string `json:"proxyport"` } type IP struct { - Query string + Query string } // ReadIpTable Read data from Ip tables from json file func ReadIpTable() (*IpAddresses, error) { - // Get Path from config - config, err := config.ConfigInit() - if err != nil { - return nil, err - } - jsonFile, err := os.Open(config.IPTable) - // if we os.Open returns an error then handle it - if err != nil { - return nil, err - } + // Get Path from config + config, err := config.ConfigInit() + if err != nil { + return nil, err + } + jsonFile, err := os.Open(config.IPTable) + // if we os.Open returns an error then handle it + if err != nil { + return nil, err + } - // defer the closing of our jsonFile so that we can parse it later on - defer jsonFile.Close() + // defer the closing of our jsonFile so that we can parse it later on + defer jsonFile.Close() - // read our opened xmlFile as a byte array. - byteValue, _ := ioutil.ReadAll(jsonFile) + // read our opened xmlFile as a byte array. + byteValue, _ := ioutil.ReadAll(jsonFile) - // we initialize our Users array - var ipAddresses IpAddresses + // we initialize our Users array + var ipAddresses IpAddresses - // we unmarshal our byteArray which contains our - // jsonFile's content into 'users' which we defined above - json.Unmarshal(byteValue, &ipAddresses) + // we unmarshal our byteArray which contains our + // jsonFile's content into 'users' which we defined above + json.Unmarshal(byteValue, &ipAddresses) - var PublicIP IpAddress + var PublicIP IpAddress - ipv6, err := GetCurrentIPV6() - if err != nil { - return nil, err - } + ipv6, err := GetCurrentIPV6() + if err != nil { + return nil, err + } - ip, err := CurrentPublicIP() - if err != nil { - return nil, err - } - PublicIP.Ipv4 = ip - PublicIP.Ipv6 = ipv6 - PublicIP.ServerPort = config.ServerPort - if config.FRPServerPort != "0" { - PublicIP.ProxyPort = config.FRPServerPort - } + ip, err := CurrentPublicIP() + if err != nil { + return nil, err + } + PublicIP.Ipv4 = ip + PublicIP.Ipv6 = ipv6 + PublicIP.ServerPort = config.ServerPort + if config.FRPServerPort != "0" { + PublicIP.ProxyPort = config.FRPServerPort + } - // Updates current machine IP address to the IP table - ipAddresses.IpAddress = append(ipAddresses.IpAddress, PublicIP) + // Updates current machine IP address to the IP table + ipAddresses.IpAddress = append(ipAddresses.IpAddress, PublicIP) - //before writing to iptable ensures the duplicates are removed - if err = ipAddresses.RemoveDuplicates(); err != nil { - return nil, err - } + //before writing to iptable ensures the duplicates are removed + if err = ipAddresses.RemoveDuplicates(); err != nil { + return nil, err + } - return &ipAddresses, nil + return &ipAddresses, nil } // WriteIpTable Write to IP table json file func (i *IpAddresses) WriteIpTable() error { - //before writing to iptable ensures the duplicates are removed - if err := i.RemoveDuplicates(); err != nil { - return err - } + //before writing to iptable ensures the duplicates are removed + if err := i.RemoveDuplicates(); err != nil { + return err + } - file, err := json.MarshalIndent(i, "", " ") - if err != nil { - return err - } + file, err := json.MarshalIndent(i, "", " ") + if err != nil { + return err + } - // Get Path from config - config, err := config.ConfigInit() - if err != nil { - return err - } + // Get Path from config + config, err := config.ConfigInit() + if err != nil { + return err + } - err = ioutil.WriteFile(config.IPTable, file, 0644) - if err != nil { - return err - } + err = ioutil.WriteFile(config.IPTable, file, 0644) + if err != nil { + return err + } - return nil + return nil } // PrintIpTable Print Ip table data for Cli func PrintIpTable() error { - table, err := ReadIpTable() + table, err := ReadIpTable() - if err != nil { - return err - } + if err != nil { + return err + } - for i := 0; i < len(table.IpAddress); i++ { - fmt.Printf("\nIP Address: %s\nIPV6: %s\nLatency: %s\nServerPort: %s\n-----------"+ - "-----------------\n", table.IpAddress[i].Ipv4, table.IpAddress[i].Ipv6, - table.IpAddress[i].Latency, table.IpAddress[i].ServerPort) - } + //for i := 0; i < len(table.IpAddress); i++ { + // fmt.Printf("\nIP Address: %s\nIPV6: %s\nLatency: %s\nServerPort: %s\n-----------"+ + // "-----------------\n", table.IpAddress[i].Ipv4, table.IpAddress[i].Ipv6, + // table.IpAddress[i].Latency, table.IpAddress[i].ServerPort) + //} + PrettyPrint(table) - return nil + return nil } // RemoveDuplicates This is a temporary fix current functions failing to remove // Duplicate IP addresses from local IP table func (table *IpAddresses) RemoveDuplicates() error { - var NoDuplicates IpAddresses - for i, _ := range table.IpAddress { - Exists := false - for k := range NoDuplicates.IpAddress { - if (NoDuplicates.IpAddress[k].Ipv4 != "" && NoDuplicates.IpAddress[k].Ipv4 == table.IpAddress[i].Ipv4) || (NoDuplicates.IpAddress[k].Ipv6 != "" && NoDuplicates.IpAddress[k].Ipv6 == table.IpAddress[i].Ipv6) { - if NoDuplicates.IpAddress[k].ProxyPort == "0" { - Exists = true - break - } - } - } - if Exists { - continue - } - NoDuplicates.IpAddress = append(NoDuplicates.IpAddress, table.IpAddress[i]) - } + var NoDuplicates IpAddresses + for i, _ := range table.IpAddress { + Exists := false + for k := range NoDuplicates.IpAddress { + if (NoDuplicates.IpAddress[k].Ipv4 != "" && NoDuplicates.IpAddress[k].Ipv4 == table.IpAddress[i].Ipv4) || (NoDuplicates.IpAddress[k].Ipv6 != "" && NoDuplicates.IpAddress[k].Ipv6 == table.IpAddress[i].Ipv6) { + if NoDuplicates.IpAddress[k].ProxyPort == "0" { + Exists = true + break + } + } + } + if Exists { + continue + } + NoDuplicates.IpAddress = append(NoDuplicates.IpAddress, table.IpAddress[i]) + } - table.IpAddress = NoDuplicates.IpAddress + table.IpAddress = NoDuplicates.IpAddress - return nil + return nil } // CurrentPublicIP Get Current Public IP address func CurrentPublicIP() (string, error) { - req, err := http.Get("http://ip-api.com/json/") - if err != nil { - return "", err - } - defer req.Body.Close() + req, err := http.Get("http://ip-api.com/json/") + if err != nil { + return "", err + } + defer req.Body.Close() - body, err := ioutil.ReadAll(req.Body) - if err != nil { - return "", err - } + body, err := ioutil.ReadAll(req.Body) + if err != nil { + return "", err + } - var ip IP - json.Unmarshal(body, &ip) + var ip IP + json.Unmarshal(body, &ip) - return ip.Query, nil + return ip.Query, nil } // GetCurrentIPV6 gets the current IPV6 address based on the interface // specified in the config file func GetCurrentIPV6() (string, error) { - Config, err := config.ConfigInit() - if err != nil { - return "", err - } + Config, err := config.ConfigInit() + if err != nil { + return "", err + } - // Fix in future release - //byNameInterface, err := net.InterfaceByName(Config.NetworkInterface) - //if err != nil { - // return "",err - //} - //addresses, err := byNameInterface.Addrs() - //if err != nil { - // return "",err - //} - //if addresses[1].String() == "" { - // return "",errors.New("IPV6 address not detected") - //} - //IP,_,err := net.ParseCIDR(addresses[Config.NetworkInterfaceIPV6Index].String()) - //if err != nil { - // return "",err - //} + // Fix in future release + //byNameInterface, err := net.InterfaceByName(Config.NetworkInterface) + //if err != nil { + // return "",err + //} + //addresses, err := byNameInterface.Addrs() + //if err != nil { + // return "",err + //} + //if addresses[1].String() == "" { + // return "",errors.New("IPV6 address not detected") + //} + //IP,_,err := net.ParseCIDR(addresses[Config.NetworkInterfaceIPV6Index].String()) + //if err != nil { + // return "",err + //} - return Config.IPV6Address, nil + return Config.IPV6Address, nil } // ViewNetworkInterface This function is created to view the network interfaces available func ViewNetworkInterface() error { - ifaces, err := net.Interfaces() - if err != nil { - return err - } - for _, i := range ifaces { - addrs, err := i.Addrs() - if err != nil { - return err - } - for index, a := range addrs { - switch v := a.(type) { - case *net.IPAddr: - fmt.Printf("(%v) %v : %s (%s)\n", index, i.Name, v, v.IP.DefaultMask()) + ifaces, err := net.Interfaces() + if err != nil { + return err + } + for _, i := range ifaces { + addrs, err := i.Addrs() + if err != nil { + return err + } + for index, a := range addrs { + switch v := a.(type) { + case *net.IPAddr: + fmt.Printf("(%v) %v : %s (%s)\n", index, i.Name, v, v.IP.DefaultMask()) - case *net.IPNet: - fmt.Printf("(%v) %v : %s \n", index, i.Name, v) - } + case *net.IPNet: + fmt.Printf("(%v) %v : %s \n", index, i.Name, v) + } - } - } - return nil + } + } + return nil } // Ip4or6 Helper function to check if the IP address is IPV4 or -//IPV6 (https://socketloop.com/tutorials/golang-check-if-ip-address-is-version-4-or-6) +// IPV6 (https://socketloop.com/tutorials/golang-check-if-ip-address-is-version-4-or-6) func Ip4or6(s string) string { - for i := 0; i < len(s); i++ { - switch s[i] { - case '.': - return "version 4" - case ':': - return "version 6" - } - } - return "version 6" + for i := 0; i < len(s); i++ { + switch s[i] { + case '.': + return "version 4" + case ':': + return "version 6" + } + } + return "version 6" } + +func PrettyPrint(data interface{}) { + var p []byte + // var err := error + p, err := json.MarshalIndent(data, "", "\t") + if err != nil { + fmt.Println(err) + return + } + fmt.Printf("%s \n", p) +} diff --git a/p2p/speedtest.go b/p2p/speedtest.go index 0eca01b..ac26beb 100644 --- a/p2p/speedtest.go +++ b/p2p/speedtest.go @@ -3,106 +3,106 @@ package p2p // SpeedTest Runs a speed test and does updates IP tables accordingly func (ip *IpAddresses) SpeedTest() error { - //temp variable to store elements IP addresses and other information - // of IP addresses that are pingable - var ActiveIP IpAddresses + //temp variable to store elements IP addresses and other information + // of IP addresses that are pingable + var ActiveIP IpAddresses - // Index to remove from struct - for _, value := range ip.IpAddress { + // Index to remove from struct + for _, value := range ip.IpAddress { - var err error - //if len(ip.IpAddress) == 1 { - // i = 0 - //} + var err error + //if len(ip.IpAddress) == 1 { + // i = 0 + //} - // Ping Test - err = value.PingTest() + // Ping Test + err = value.PingTest() - if err != nil { - continue - } + if err != nil { + continue + } - //Upload Speed Test - //err = value.UploadSpeed() - //if err != nil { - // return err - //} - // - //err = value.DownloadSpeed() - //if err != nil { - // return err - //} + //Upload Speed Test + //err = value.UploadSpeed() + //if err != nil { + // return err + //} + // + //err = value.DownloadSpeed() + //if err != nil { + // return err + //} - //Set value to the list + //Set value to the list - ActiveIP.IpAddress = append(ActiveIP.IpAddress, value) + ActiveIP.IpAddress = append(ActiveIP.IpAddress, value) - } + } - ip.IpAddress = ActiveIP.IpAddress + ip.IpAddress = ActiveIP.IpAddress - err := ip.WriteIpTable() - if err != nil { - return err - } + err := ip.WriteIpTable() + if err != nil { + return err + } - return nil + return nil } // SpeedTestUpdatedIPTable Called when ip tables from httpclient/server is also passed on func (ip *IpAddresses) SpeedTestUpdatedIPTable() error { - targets, err := ReadIpTable() - if err != nil { - return err - } + targets, err := ReadIpTable() + if err != nil { + return err + } - // To ensure struct has no duplicates IP addresses - //DoNotRead := targets + // To ensure struct has no duplicates IP addresses + //DoNotRead := targets - // Appends all IP addresses - for i, _ := range targets.IpAddress { + // Appends all IP addresses + for i, _ := range targets.IpAddress { - // To ensure that there are no duplicate IP addresses - //Exists := false - //for k := range ip.IpAddress { - // // Checks if both the IPV4 addresses are the same or the IPV6 address is not - // // an empty string and IPV6 address are the same - // if ip.IpAddress[k].Ipv4 == targets.IpAddress[i].Ipv4 || (targets.IpAddress[i].Ipv6 != "" && ip.IpAddress[k].Ipv6 == targets.IpAddress[i].Ipv6) { - // Exists = true - // break - // } - //} - // - //// If the struct exists then continues - //if Exists { - // continue - //} + //To ensure that there are no duplicate IP addresses + Exists := false + for k := range ip.IpAddress { + // Checks if both the IPV4 addresses are the same or the IPV6 address is not + // an empty string and IPV6 address are the same + if (ip.IpAddress[k].Ipv4 == targets.IpAddress[i].Ipv4 && targets.IpAddress[i].ProxyPort == "0") || (targets.IpAddress[i].Ipv6 != "" && ip.IpAddress[k].Ipv6 == targets.IpAddress[i].Ipv6 && targets.IpAddress[i].ProxyPort == "0") { + Exists = true + break + } + } - ip.IpAddress = append(ip.IpAddress, targets.IpAddress[i]) - } + // If the struct exists then continues + if Exists { + continue + } - err = ip.SpeedTest() + ip.IpAddress = append(ip.IpAddress, targets.IpAddress[i]) + } - if err != nil { - return err - } + err = ip.SpeedTest() - return nil + if err != nil { + return err + } + + return nil } // LocalSpeedTestIpTable Runs speed test in iptables locally only func LocalSpeedTestIpTable() error { - targets, err := ReadIpTable() - if err != nil { - return err - } + targets, err := ReadIpTable() + if err != nil { + return err + } - err = targets.SpeedTest() - if err != nil { - return err - } + err = targets.SpeedTest() + if err != nil { + return err + } - return nil + return nil } // Helper function to remove element from an array of a struct diff --git a/p2p/testingMetrics.go b/p2p/testingMetrics.go index bb1a296..2423459 100644 --- a/p2p/testingMetrics.go +++ b/p2p/testingMetrics.go @@ -2,6 +2,7 @@ package p2p import ( "bytes" + "errors" "git.sr.ht/~akilan1999/p2p-rendering-computation/config" "io" "io/ioutil" @@ -12,8 +13,8 @@ import ( "time" ) -//var dlSizes = [...]int{350, 500, 750, 1000, 1500, 2000, 2500, 3000, 3500, 4000} -//var ulSizes = [...]int{100, 300, 500, 800, 1000, 1500, 2500, 3000, 3500, 4000} //kB +// var dlSizes = [...]int{350, 500, 750, 1000, 1500, 2000, 2500, 3000, 3500, 4000} +// var ulSizes = [...]int{100, 300, 500, 800, 1000, 1500, 2500, 3000, 3500, 4000} //kB var httpclient = http.Client{} // DownloadTest executes the test to measure download speed @@ -78,7 +79,7 @@ var httpclient = http.Client{} //} // Download Speed -func (s *IpAddress)DownloadSpeed() error { +func (s *IpAddress) DownloadSpeed() error { start := time.Now() resp, err := httpclient.Get("http://" + s.Ipv4 + ":8088/50") if err != nil { @@ -89,11 +90,11 @@ func (s *IpAddress)DownloadSpeed() error { t := time.Since(start) //fmt.Println(s.Seconds()) // size * time (seconds) - s.Download = (50/t.Seconds())*8 - return nil + s.Download = (50 / t.Seconds()) * 8 + return nil } -func (s *IpAddress)UploadSpeed() error { +func (s *IpAddress) UploadSpeed() error { start := time.Now() // Get upload file path from config file @@ -103,9 +104,9 @@ func (s *IpAddress)UploadSpeed() error { return err } - b, w := createMultipartFormData("file",config.SpeedTestFile) + b, w := createMultipartFormData("file", config.SpeedTestFile) - req, err := http.NewRequest("GET", "http://" + s.Ipv4 + ":" + s.ServerPort + "/upload", &b) + req, err := http.NewRequest("GET", "http://"+s.Ipv4+":"+s.ServerPort+"/upload", &b) if err != nil { return err } @@ -116,12 +117,12 @@ func (s *IpAddress)UploadSpeed() error { t := time.Since(start) //fmt.Println(s.Seconds()) // size * time (seconds) - s.Upload = (50/t.Seconds())*8 + s.Upload = (50 / t.Seconds()) * 8 return nil } -//Upload helper function for uploading -//(https://stackoverflow.com/questions/20205796/post-data-using-the-content-type-multipart-form-data +// Upload helper function for uploading +// (https://stackoverflow.com/questions/20205796/post-data-using-the-content-type-multipart-form-data func createMultipartFormData(fieldName, fileName string) (bytes.Buffer, *multipart.Writer) { var b bytes.Buffer var err error @@ -142,7 +143,7 @@ func createMultipartFormData(fieldName, fileName string) (bytes.Buffer, *multipa func mustOpen(f string) *os.File { r, err := os.Open(f) if err != nil { - log.Fatalf("Error with mustOpen: %v",err) + log.Fatalf("Error with mustOpen: %v", err) } return r } @@ -163,8 +164,8 @@ func (s *IpAddress) PingTest() error { sTime := time.Now() resp, err := http.Get(pingURL) fTime := time.Now() - if err != nil { - return err + if err != nil || resp.StatusCode != 200 { + return errors.New("Node not found") } if fTime.Sub(sTime) < l { l = fTime.Sub(sTime) @@ -176,4 +177,3 @@ func (s *IpAddress) PingTest() error { return nil } - diff --git a/server/server.go b/server/server.go index fe58c5b..4c7cc98 100644 --- a/server/server.go +++ b/server/server.go @@ -1,208 +1,208 @@ package server import ( - "encoding/json" - "fmt" - "git.sr.ht/~akilan1999/p2p-rendering-computation/config" - "git.sr.ht/~akilan1999/p2p-rendering-computation/p2p" - "git.sr.ht/~akilan1999/p2p-rendering-computation/p2p/frp" - "git.sr.ht/~akilan1999/p2p-rendering-computation/server/docker" - "github.com/gin-gonic/gin" - "io/ioutil" - "net/http" + "encoding/json" + "fmt" + "git.sr.ht/~akilan1999/p2p-rendering-computation/config" + "git.sr.ht/~akilan1999/p2p-rendering-computation/p2p" + "git.sr.ht/~akilan1999/p2p-rendering-computation/p2p/frp" + "git.sr.ht/~akilan1999/p2p-rendering-computation/server/docker" + "github.com/gin-gonic/gin" + "io/ioutil" + "net/http" ) func Server() error { - r := gin.Default() + r := gin.Default() - // update IPTable with new port and ip address and update ip table - var ProxyIpAddr p2p.IpAddress + // update IPTable with new port and ip address and update ip table + var ProxyIpAddr p2p.IpAddress - // Gets default information of the server - r.GET("/server_info", func(c *gin.Context) { - c.JSON(http.StatusOK, ServerInfo()) - }) + // Gets default information of the server + r.GET("/server_info", func(c *gin.Context) { + c.JSON(http.StatusOK, ServerInfo()) + }) - // Speed test with 50 mbps - r.GET("/50", func(c *gin.Context) { - // Get Path from config - config, err := config.ConfigInit() - if err != nil { - c.String(http.StatusOK, fmt.Sprint(err)) - } - c.File(config.SpeedTestFile) - }) + // Speed test with 50 mbps + r.GET("/50", func(c *gin.Context) { + // Get Path from config + config, err := config.ConfigInit() + if err != nil { + c.String(http.StatusOK, fmt.Sprint(err)) + } + c.File(config.SpeedTestFile) + }) - // Route build to do a speed test - r.GET("/upload", func(c *gin.Context) { - file, _ := c.FormFile("file") + // Route build to do a speed test + r.GET("/upload", func(c *gin.Context) { + file, _ := c.FormFile("file") - // Upload the file to specific dst. - // c.SaveUploadedFile(file, dst) + // Upload the file to specific dst. + // c.SaveUploadedFile(file, dst) - c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename)) - }) + c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename)) + }) - //Gets Ip Table from server node - r.POST("/IpTable", func(c *gin.Context) { - // Getting IPV4 address of client - var ClientHost p2p.IpAddress + //Gets Ip Table from server node + r.POST("/IpTable", func(c *gin.Context) { + // Getting IPV4 address of client + var ClientHost p2p.IpAddress - if p2p.Ip4or6(c.ClientIP()) == "version 6" { - ClientHost.Ipv6 = c.ClientIP() - } else { - ClientHost.Ipv4 = c.ClientIP() - } + if p2p.Ip4or6(c.ClientIP()) == "version 6" { + ClientHost.Ipv6 = c.ClientIP() + } else { + ClientHost.Ipv4 = c.ClientIP() + } - // Variable to store IP table information - var IPTable p2p.IpAddresses + // Variable to store IP table information + var IPTable p2p.IpAddresses - // Receive file from POST request - body, err := c.FormFile("json") - if err != nil { - c.String(http.StatusOK, fmt.Sprint(err)) - } + // Receive file from POST request + body, err := c.FormFile("json") + if err != nil { + c.String(http.StatusOK, fmt.Sprint(err)) + } - // Open file - open, err := body.Open() - if err != nil { - c.String(http.StatusOK, fmt.Sprint(err)) - } + // Open file + open, err := body.Open() + if err != nil { + c.String(http.StatusOK, fmt.Sprint(err)) + } - // Open received file - file, err := ioutil.ReadAll(open) - if err != nil { - c.String(http.StatusOK, fmt.Sprint(err)) - } + // Open received file + file, err := ioutil.ReadAll(open) + if err != nil { + c.String(http.StatusOK, fmt.Sprint(err)) + } - json.Unmarshal(file, &IPTable) + json.Unmarshal(file, &IPTable) - //Add Client IP address to IPTable struct - IPTable.IpAddress = append(IPTable.IpAddress, ClientHost) + //Add Client IP address to IPTable struct + IPTable.IpAddress = append(IPTable.IpAddress, ClientHost) - // Runs speed test to return only servers in the IP table pingable - err = IPTable.SpeedTestUpdatedIPTable() - if err != nil { - c.String(http.StatusOK, fmt.Sprint(err)) - } + // Runs speed test to return only servers in the IP table pingable + err = IPTable.SpeedTestUpdatedIPTable() + if err != nil { + c.String(http.StatusOK, fmt.Sprint(err)) + } - // Reads IP addresses from ip table - IpAddresses, err := p2p.ReadIpTable() - if err != nil { - c.String(http.StatusOK, fmt.Sprint(err)) - } + // Reads IP addresses from ip table + IpAddresses, err := p2p.ReadIpTable() + if err != nil { + c.String(http.StatusOK, fmt.Sprint(err)) + } - c.JSON(http.StatusOK, IpAddresses) - }) + c.JSON(http.StatusOK, IpAddresses) + }) - // Starts docker container in server - r.GET("/startcontainer", func(c *gin.Context) { - // Get Number of ports to open and whether to use GPU or not - Ports := c.DefaultQuery("ports", "0") - GPU := c.DefaultQuery("GPU", "false") - ContainerName := c.DefaultQuery("ContainerName", "") - var PortsInt int + // Starts docker container in server + r.GET("/startcontainer", func(c *gin.Context) { + // Get Number of ports to open and whether to use GPU or not + Ports := c.DefaultQuery("ports", "0") + GPU := c.DefaultQuery("GPU", "false") + ContainerName := c.DefaultQuery("ContainerName", "") + var PortsInt int - // Convert Get Request value to int - fmt.Sscanf(Ports, "%d", &PortsInt) + // Convert Get Request value to int + fmt.Sscanf(Ports, "%d", &PortsInt) - // Creates container and returns-back result to - // access container - resp, err := docker.BuildRunContainer(PortsInt, GPU, ContainerName) + // Creates container and returns-back result to + // access container + resp, err := docker.BuildRunContainer(PortsInt, GPU, ContainerName) - if ProxyIpAddr.Ipv4 != "" { - err := frp.StartFRPCDockerContainer(ProxyIpAddr.Ipv4, ProxyIpAddr.ProxyPort, resp) - if err != nil { - c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err)) - } - } + if ProxyIpAddr.Ipv4 != "" { + err := frp.StartFRPCDockerContainer(ProxyIpAddr.Ipv4, ProxyIpAddr.ProxyPort, resp) + if err != nil { + c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err)) + } + } - if err != nil { - c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err)) - } + if err != nil { + c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err)) + } - c.JSON(http.StatusOK, resp) - }) + c.JSON(http.StatusOK, resp) + }) - //Remove container - r.GET("/RemoveContainer", func(c *gin.Context) { - ID := c.DefaultQuery("id", "0") - if err := docker.StopAndRemoveContainer(ID); err != nil { - c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err)) - } - c.String(http.StatusOK, "success") - }) + //Remove container + r.GET("/RemoveContainer", func(c *gin.Context) { + ID := c.DefaultQuery("id", "0") + if err := docker.StopAndRemoveContainer(ID); err != nil { + c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err)) + } + c.String(http.StatusOK, "success") + }) - //Show images available - r.GET("/ShowImages", func(c *gin.Context) { - resp, err := docker.ViewAllContainers() - if err != nil { - c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err)) - } - c.JSON(http.StatusOK, resp) - }) + //Show images available + r.GET("/ShowImages", func(c *gin.Context) { + resp, err := docker.ViewAllContainers() + if err != nil { + c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err)) + } + c.JSON(http.StatusOK, resp) + }) - //Get Server port based on the config file - config, err := config.ConfigInit() - if err != nil { - return err - } + //Get Server port based on the config file + config, err := config.ConfigInit() + if err != nil { + return err + } - // If there is a proxy port specified - // then starts the FRP server - if config.FRPServerPort != "0" { - go frp.StartFRPProxyFromConfig() - } + // If there is a proxy port specified + // then starts the FRP server + if config.FRPServerPort != "0" { + go frp.StartFRPProxyFromConfig() + } - // TODO check if IPV6 or Proxy port is specified - // if not update current entry as proxy address - // with appropriate port on IP Table - if config.IPV6Address == "" || config.FRPServerPort == "0" { - table, err := p2p.ReadIpTable() - if err != nil { - return err - } + // TODO check if IPV6 or Proxy port is specified + // if not update current entry as proxy address + // with appropriate port on IP Table + if config.BehindNAT == "True" { + table, err := p2p.ReadIpTable() + if err != nil { + return err + } - var lowestLatency int64 - // random large number - lowestLatency = 10000000 - var lowestLatencyIpAddress p2p.IpAddress - for i, _ := range table.IpAddress { - // Checks if the ping is the lowest and if the following node is acting as a proxy - if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && table.IpAddress[i].ProxyPort != "" { - lowestLatency = table.IpAddress[i].Latency.Milliseconds() - lowestLatencyIpAddress = table.IpAddress[i] - } - } + var lowestLatency int64 + // random large number + lowestLatency = 10000000 + var lowestLatencyIpAddress p2p.IpAddress + for i, _ := range table.IpAddress { + // Checks if the ping is the lowest and if the following node is acting as a proxy + if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && table.IpAddress[i].ProxyPort != "" { + lowestLatency = table.IpAddress[i].Latency.Milliseconds() + lowestLatencyIpAddress = table.IpAddress[i] + } + } - // If there is an identified node - if lowestLatency != 10000000 { - // Starts FRP as a client with - proxyPort, err := frp.StartFRPClientForServer(lowestLatencyIpAddress.Ipv4, lowestLatencyIpAddress.ProxyPort) - if err != nil { - return err - } + // If there is an identified node + if lowestLatency != 10000000 { + // Starts FRP as a client with + proxyPort, err := frp.StartFRPClientForServer(lowestLatencyIpAddress.Ipv4, lowestLatencyIpAddress.ProxyPort, config.ServerPort) + if err != nil { + return err + } - // updating with the current proxy address - ProxyIpAddr.Ipv4 = lowestLatencyIpAddress.Ipv4 - ProxyIpAddr.ServerPort = proxyPort - ProxyIpAddr.ProxyPort = lowestLatencyIpAddress.ProxyPort + // updating with the current proxy address + ProxyIpAddr.Ipv4 = lowestLatencyIpAddress.Ipv4 + ProxyIpAddr.ServerPort = proxyPort + ProxyIpAddr.ProxyPort = lowestLatencyIpAddress.ProxyPort - // append the following to the ip table - table.IpAddress = append(table.IpAddress, ProxyIpAddr) - // write information back to the IP Table - table.WriteIpTable() - // update ip table - go table.SpeedTestUpdatedIPTable() - } + // append the following to the ip table + table.IpAddress = append(table.IpAddress, ProxyIpAddr) + // write information back to the IP Table + table.WriteIpTable() + // update ip table + go table.SpeedTest() + } - } + } - // Run gin server on the specified port - err = r.Run(":" + config.ServerPort) - if err != nil { - return err - } + // Run gin server on the specified port + err = r.Run(":" + config.ServerPort) + if err != nil { + return err + } - return nil + return nil }