diff --git a/.gitignore b/.gitignore index 8f34978..9903888 100644 --- a/.gitignore +++ b/.gitignore @@ -33,7 +33,7 @@ server/docker/containers/ export/ # Any testing file -test* +*test # Ignore public and private keys p2prc.publicKey diff --git a/cert.pem b/cert.pem deleted file mode 100644 index f9a2028..0000000 --- a/cert.pem +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC9DCCAdygAwIBAgIQXOymZW4XLjqscy843BeeBzANBgkqhkiG9w0BAQsFADAS -MRAwDgYDVQQKEwdBY21lIENvMB4XDTI0MTAyMDIxMjc1NloXDTI1MTAyMDIxMjc1 -NlowEjEQMA4GA1UEChMHQWNtZSBDbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBAMFErOjO5LYkiMev4Xma6DX7rmjcyQRau84IyOflajE7LFyUnEDxZJkE -JU57mm06uOLr6XUytkFOFrgeCsWAbraiGhKDH5srBvvNAgah/8RgkIFXASDslEy5 -bI9RZZLe8jJP0cVGvgnZi6aZsDYZm9wlYSgY+9f9QddCb1NQ+/0mu9cluq6v/n3G -q5PhXHt9CnHoYs8hJ+fbJATAogugvfh3zYbkrBUPY73hQ2/dwHy7mdfAieo6i3GR -NP2/YQTHBwBqm6teOlBZ8VfQOyzU8czz1mhbD8GVh5CF/ZWE6tHxxjWG+B53VW/e -yH0LlQQFttNn2bB58W9Bgfov5CBj/30CAwEAAaNGMEQwDgYDVR0PAQH/BAQDAgWg -MBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDwYDVR0RBAgwBocE -TWH5GDANBgkqhkiG9w0BAQsFAAOCAQEAEs4zLQt9n1BLibCmoKwzYDSUK/KQQdcA -8LREoTH6bD+TryzWSQ1zF+WZHbru9pGNO9gkEbmcYwziTVoPmFwblvoc/YoXFp2B -fQiIAZ5+TMtEfdj6agW8+fz00eMKvo1HkbO3RhDj+KYxlED7DL4Tn/ESx7wKtPsX -lSUBK4Chqmj3hB8OCIeDUoMwnCaA1plLfBgcFixtWyYEGv8gXgwrpVqXLfdnGCOI -biFWeLMSXiqZOykJl6fJbOGjkmTsLSDHcyhV2x1+FHviDJYF4WckrkhSmBw+Pspz -OT41o6uP/MFimbFAhCfcPRwHj1vMzfunKvb7UGPJPCWE5oWA7sWsQw== ------END CERTIFICATE----- diff --git a/client/clientIPTable/AddCustomInformationToIPTable.go b/client/clientIPTable/AddCustomInformationToIPTable.go index 56763b3..a6b8c4e 100644 --- a/client/clientIPTable/AddCustomInformationToIPTable.go +++ b/client/clientIPTable/AddCustomInformationToIPTable.go @@ -31,7 +31,7 @@ func AddCustomInformationToIPTable(text string) error { if found { table.WriteIpTable() // update IPTable after modified entry - UpdateIpTableListClient() + go UpdateIpTableListClient() } else { return errors.New("start server with p2prc -s as the server is currently not running") } diff --git a/client/clientIPTable/Iptable.go b/client/clientIPTable/Iptable.go index d6da7e0..204bbf0 100644 --- a/client/clientIPTable/Iptable.go +++ b/client/clientIPTable/Iptable.go @@ -64,10 +64,11 @@ func UpdateIpTable(IpAddress string, serverPort string, wg *sync.WaitGroup) erro } } - err = ipStruct.WriteIpTable() - if err != nil { - return err - } + // Not required to update IP table as speed test updates the IP Table + //err = ipStruct.WriteIpTable() + //if err != nil { + // return err + //} wg.Done() diff --git a/config/config.go b/config/config.go index 163a597..883638b 100644 --- a/config/config.go +++ b/config/config.go @@ -36,7 +36,8 @@ type Config struct { PrivateKeyFile string PemFile string KeyFile string - BareMetal string + BareMetal bool + UnsafeMode bool CustomConfig interface{} //NetworkInterface string //NetworkInterfaceIPV6Index int diff --git a/config/generate/generate.go b/config/generate/generate.go index cdccc37..b926457 100644 --- a/config/generate/generate.go +++ b/config/generate/generate.go @@ -91,9 +91,10 @@ func SetDefaults(envName string, forceDefault bool, CustomConfig interface{}, No } // Generate Public and private keys and set path - Defaults.PublicKeyFile = defaultPath + "p2prc.PublicKeyBareMetal" + Defaults.PublicKeyFile = defaultPath + "p2prc.publicKey" Defaults.PrivateKeyFile = defaultPath + "p2prc.privateKey" - Defaults.BareMetal = "False" + Defaults.BareMetal = false + Defaults.UnsafeMode = false // Generate certificate files for SSL err = GenerateCertificate() diff --git a/key.pem b/key.pem deleted file mode 100644 index 170c493..0000000 --- a/key.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDBRKzozuS2JIjH -r+F5mug1+65o3MkEWrvOCMjn5WoxOyxclJxA8WSZBCVOe5ptOrji6+l1MrZBTha4 -HgrFgG62ohoSgx+bKwb7zQIGof/EYJCBVwEg7JRMuWyPUWWS3vIyT9HFRr4J2Yum -mbA2GZvcJWEoGPvX/UHXQm9TUPv9JrvXJbqur/59xquT4Vx7fQpx6GLPISfn2yQE -wKILoL34d82G5KwVD2O94UNv3cB8u5nXwInqOotxkTT9v2EExwcAapurXjpQWfFX -0Dss1PHM89ZoWw/BlYeQhf2VhOrR8cY1hvged1Vv3sh9C5UEBbbTZ9mwefFvQYH6 -L+QgY/99AgMBAAECggEAag7BxFAk+j86QDqoRQ9Y9qbSowDl3tnbzcjMV1Vx3OpY -AcYbqRfO2JmJz3PM3rwm0YAccRAPK+8qUIdL6e3804RJQndqVMBb6LorrnAf5ygG -pLOWDvdEuoXWqR9F2j82MZ3Tw6p6hvU2yYn1RPrwqPJqSpLLQU/dXb87UEFUxyoQ -7bNBNzsulZNd70JJtvmieXU1tf88EdiIxv/Ua9ZRepkkLDJlt3BwsGK+JdVhOhN2 -zUjhlQ4HrErdY6C0rEX7gKznSaThaZb6RYZOLqBfe5nG/uQjw+OfltLEz4nR5xn2 -2F07T0a5hP4WvCgNQRBzsXGYNumJEuSkcadEw8hEkQKBgQD2RAnUlnQ99xqvz3QK -STptQcJOF07DQmEs6A8E7BHue/Z4+gYNtbyQ7NefDYBuGWOzUOXOJs6k//CCgcDe -ZzmtRPs3Sro8AfK0FS09r/OpXL+LPJjhSJ+YEjoVzERSDCvVNshuIO92zlDPITg8 -J9ZsPzXrm+Yh1f5gvSgvmgJodwKBgQDI6FsH7mdjW3bp1tGnF/SzqOBMutyZp7/9 -b7dtJhZNwdi4765JVtLAXDei5kht7NzVlH7GJGcrIen5emKBRS6JjDlhFcFw669V -biOiBrL/3Gu9irjLh2abSBE5r7GClelDLgmJ/JrpkRJRcBtfoPLsYIHtViNXz2CE -w2yf3D+IqwKBgDV7l0r1Fe+zL7eI7WGif67kvicphrB/RQ10pHZkMozBnUiuvAvU -MUykMzvWudKvbuitpAr+gJhzAS/GsDVc47jOp2RdtU58+dHEW5vvD5LzkqHRmj4r -AIYNR1Iel6PeAtL+X88TFg6ORhyF0Wm3GSlPHQ27QOKOT/2Ady7HWsiHAoGAAZ2U -tdCd9jeTEjhPAUf5CMTP4O4TvgySR6hxUihfP4rSglIzFZXkJfXX4LB3XqLr96+1 -AUTjq34fUolAZ4e14xdEktpI7u6GP2qeULw7DkGogCKwb7qMAa2nrc4S4FjyQj8J -hpmIaV5oRk1fevphWbNA+DacHCWnwgmMQxDTVfcCgYAxbQQFyRJ1B+WJtvE66cqA -T/DvgzevwqE4na+NNc6hApZt+kNoLODLUi6ikYimNzdtGnr4AIitvGR3J9qzFC+I -+d2F1ioSV4fpVD7idYDVkncME+pXzzGweg91k8ucHqcdU1k70lYTokGgm3DyClcP -76O6IS1URnFFXco9DGuDcA== ------END PRIVATE KEY----- diff --git a/main.go b/main.go index 3607d92..fb85b0f 100644 --- a/main.go +++ b/main.go @@ -1,11 +1,13 @@ package main import ( - "log" - "os" + "log" + "os" + "os/signal" + "syscall" - "github.com/Akilan1999/p2p-rendering-computation/cmd" - "github.com/urfave/cli/v2" + "github.com/Akilan1999/p2p-rendering-computation/cmd" + "github.com/urfave/cli/v2" ) // VERSION specifies the version of the platform @@ -16,16 +18,36 @@ var mode string var OS, Pull_location, Run_script string var List_servers, Ip_table bool +// To be implemented later on +func getFireSignalsChannel() chan os.Signal { + + c := make(chan os.Signal, 1) + signal.Notify(c, + // https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html + syscall.SIGTERM, // "the normal way to politely ask a program to terminate" + syscall.SIGINT, // Ctrl+C + syscall.SIGQUIT, // Ctrl-\ + syscall.SIGKILL, // "always fatal", "SIGKILL and SIGSTOP may not be caught by a program" + syscall.SIGHUP, // "terminal is disconnected" + ) + return c + +} + +func exit() { + syscall.Kill(syscall.Getpid(), syscall.SIGTERM) +} + func main() { - app := cli.NewApp() - app.Name = "p2p-rendering-computation" - app.Usage = "p2p cli application to create and access VMs in other servers" - app.Version = VERSION - app.Flags = cmd.AppConfigFlags - app.Action = cmd.CliAction - - err := app.Run(os.Args) - if err != nil { - log.Fatal(err) - } + app := cli.NewApp() + app.Name = "p2p-rendering-computation" + app.Usage = "p2p cli application to create and access VMs in other servers" + app.Version = VERSION + app.Flags = cmd.AppConfigFlags + app.Action = cmd.CliAction + + err := app.Run(os.Args) + if err != nil { + log.Fatal(err) + } } diff --git a/p2p/iptable.go b/p2p/iptable.go index 372d88d..9cdf891 100644 --- a/p2p/iptable.go +++ b/p2p/iptable.go @@ -21,6 +21,7 @@ type IpAddresses struct { type IpAddress struct { Name string `json:"Name"` + MachineUsername string `json:"MachineUsername"` Ipv4 string `json:"IPV4"` Ipv6 string `json:"IPV6"` Latency time.Duration `json:"Latency"` @@ -31,6 +32,8 @@ type IpAddress struct { NAT string `json:"NAT"` EscapeImplementation string `json:"EscapeImplementation"` ProxyServer string `json:"ProxyServer"` + UnSafeMode bool `json:"UnSafeMode"` + PublicKey string `json:"PublicKey"` CustomInformation string `json:"CustomInformation"` //CustomInformationKey []byte `json:"CustomInformationKey"` } diff --git a/p2p/speedtest.go b/p2p/speedtest.go index 4957181..0468b07 100644 --- a/p2p/speedtest.go +++ b/p2p/speedtest.go @@ -1,5 +1,9 @@ package p2p +import ( + "github.com/Akilan1999/p2p-rendering-computation/config" +) + // SpeedTest Runs a speed test and does updates IP tables accordingly func (ip *IpAddresses) SpeedTest() error { @@ -50,11 +54,26 @@ func (ip *IpAddresses) SpeedTest() error { // SpeedTestUpdatedIPTable Called when ip tables from httpclient/server is also passed on func (ip *IpAddresses) SpeedTestUpdatedIPTable() error { + + Config, err := config.ConfigInit(nil, nil) + if err != nil { + return err + } + targets, err := ReadIpTable() if err != nil { return err } + // Checks if baremetal mode and unsafe mode + // is enabled. If it is enabled it adds the + // the propagated public key to the list. + + AddPublicKey := false + if Config.BareMetal && Config.UnsafeMode { + AddPublicKey = true + } + // To ensure struct has no duplicates IP addresses //DoNotRead := targets @@ -64,6 +83,16 @@ func (ip *IpAddresses) SpeedTestUpdatedIPTable() error { //To ensure that there are no duplicate IP addresses Exists := false for k := range ip.IpAddress { + if AddPublicKey && ip.IpAddress[k].PublicKey != "" { + // This function call (AddAuthorisationKey) is inefficient but to be optimised later on. + // This is because when if the user is running on as unsafe mode the authorization file + // is opened from the SSH directory and then iterates through every single SSH entry + // to find out if the SSH entry exists or not. This will incur multiple CPU cycles + // for no reason. A better approach would be to have been to store the states on memory and only + // add when needed based on the memory location. This is something is to be discussed + // and look upon later on. + AddAuthorisationKey(ip.IpAddress[k].PublicKey) + } // 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].NAT == "True") || (targets.IpAddress[i].Ipv6 != "" && ip.IpAddress[k].Ipv6 == targets.IpAddress[i].Ipv6) { diff --git a/p2p/ssh_autorisation.go b/p2p/ssh_autorisation.go new file mode 100644 index 0000000..89b4a86 --- /dev/null +++ b/p2p/ssh_autorisation.go @@ -0,0 +1,123 @@ +// NOTE: Most of the code snippet was generated using ChatGPT +// Prompt used: "generate go program to read and populate ssh authorization file" + +package p2p + +import ( + "bufio" + "errors" + "fmt" + "os" + "path/filepath" + "strings" +) + +// GetAuthorizedKeysPath returns the path to the authorized_keys file +func GetAuthorizedKeysPath() (string, error) { + homeDir, err := os.UserHomeDir() + if err != nil { + return "", fmt.Errorf("could not find home directory: %v", err) + } + return filepath.Join(homeDir, ".ssh", "authorized_keys"), nil +} + +// ReadAuthorizedKeys reads and returns the current contents of the authorized_keys file as a map +func ReadAuthorizedKeys(path string) (map[string]bool, error) { + file, err := os.Open(path) + if err != nil { + return nil, fmt.Errorf("could not open authorized_keys file: %v", err) + } + defer file.Close() + + keys := make(map[string]bool) + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + // Skip empty lines and comments + if line != "" && !strings.HasPrefix(line, "#") { + keys[line] = true + } + } + if err := scanner.Err(); err != nil { + return nil, fmt.Errorf("error reading authorized_keys file: %v", err) + } + return keys, nil +} + +// AddKeyToAuthorizedKeys adds a new key to the authorized_keys file if it doesn’t already exist +func AddKeyToAuthorizedKeys(path, newKey string) error { + keys, err := ReadAuthorizedKeys(path) + if err != nil { + return err + } + + // Check if the key already exists in the map + if keys[newKey] { + return errors.New("key already exists in authorized_keys") + } + + // Append the new key + file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) + if err != nil { + return fmt.Errorf("could not open authorized_keys file for writing: %v", err) + } + defer file.Close() + + if _, err := file.WriteString(newKey + "\n"); err != nil { + return fmt.Errorf("could not write to authorized_keys file: %v", err) + } + return nil +} + +func RemoveKeyFromAuthorizedKeys(path, keyToRemove string) error { + keys, err := ReadAuthorizedKeys(path) + if err != nil { + return err + } + + // Check if the key exists in the map + if !keys[keyToRemove] { + return errors.New("key not found in authorized_keys") + } + + // Delete the key from the map + delete(keys, keyToRemove) + + // Write updated keys back to the authorized_keys file + file, err := os.OpenFile(path, os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0600) + if err != nil { + return fmt.Errorf("could not open authorized_keys file for writing: %v", err) + } + defer file.Close() + + for key := range keys { + if _, err := file.WriteString(key + "\n"); err != nil { + return fmt.Errorf("could not write to authorized_keys file: %v", err) + } + } + + return nil +} + +// AddAuthorisationKey Adds public key provided to the +// authorization file so that nodes can SSH into +// the +func AddAuthorisationKey(PublicKey string) error { + path, err := GetAuthorizedKeysPath() + if err != nil { + return err + } + + // Display existing keys + _, err = ReadAuthorizedKeys(path) + if err != nil { + return err + } + + err = AddKeyToAuthorizedKeys(path, PublicKey) + if err != nil { + return err + } + + return nil +} diff --git a/server/server.go b/server/server.go index 8140e48..0e56ed1 100644 --- a/server/server.go +++ b/server/server.go @@ -13,6 +13,7 @@ import ( "github.com/gin-gonic/gin" "io/ioutil" "net/http" + "os/user" "strconv" "time" ) @@ -69,13 +70,13 @@ func Server() (*gin.Engine, error) { //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() - } + //var ClientHost p2p.IpAddress + // + //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 @@ -101,7 +102,7 @@ func Server() (*gin.Engine, error) { json.Unmarshal(file, &IPTable) //Add Client IP address to IPTable struct - IPTable.IpAddress = append(IPTable.IpAddress, ClientHost) + //IPTable.IpAddress = append(IPTable.IpAddress, ClientHost) // Runs speed test to return only servers in the IP table pingable err = IPTable.SpeedTestUpdatedIPTable() @@ -294,7 +295,7 @@ func Server() (*gin.Engine, error) { ProxyIpAddr.ProxyServer = "False" ProxyIpAddr.EscapeImplementation = "FRP" - if config.BareMetal == "True" { + if config.BareMetal { _, SSHPort, err := MapPort("22", "") if err != nil { return nil, err @@ -303,9 +304,6 @@ func Server() (*gin.Engine, error) { } //ProxyIpAddr.CustomInformationKey = p2p.GenerateHashSHA256(config.IPTableKey) - - // append the following to the ip table - table.IpAddress = append(table.IpAddress, ProxyIpAddr) // write information back to the IP Table } @@ -321,13 +319,33 @@ func Server() (*gin.Engine, error) { ProxyIpAddr.ProxyServer = "True" } ProxyIpAddr.EscapeImplementation = "" - if config.BareMetal == "True" { + if config.BareMetal { ProxyIpAddr.BareMetalSSHPort = "22" } - table.IpAddress = append(table.IpAddress, ProxyIpAddr) + } + // Get machine username + currentUser, err := user.Current() + if err != nil { + return nil, err } + // Add username p2prc binary is being run under + ProxyIpAddr.MachineUsername = currentUser.Username + ProxyIpAddr.UnSafeMode = config.UnsafeMode + // Adds the public key information to the IPTable + // improving transmission of IPTables without the + // entire public key is future work to be improved + // in the P2PRC protocol level (Improving by adding + // UDP with TCP reliability layer). + ProxyIpAddr.PublicKey, err = config.GetPublicKey() + + if err != nil { + return nil, err + } + + // append the following to the ip table + table.IpAddress = append(table.IpAddress, ProxyIpAddr) // Writing results to the IPTable err = table.WriteIpTable() @@ -406,11 +424,8 @@ func MapPort(port string, domainName string) (string, string, error) { return "", "", err } - fmt.Println(domainName) - // Doing the proxy mapping for the domain name if domainName != "" { - fmt.Println("called --------------------------------") fmt.Println("http://" + lowestLatencyIpAddress.Ipv4 + ":" + lowestLatencyIpAddress.ServerPort + "/AddProxy?port=" + proxyPort + "&domain_name=" + domainName + "&ip_address=" + lowestLatencyIpAddress.Ipv4) URL := "http://" + lowestLatencyIpAddress.Ipv4 + ":" + lowestLatencyIpAddress.ServerPort + "/AddProxy?port=" + proxyPort + "&domain_name=" + domainName + "&ip_address=" + lowestLatencyIpAddress.Ipv4 //} else { @@ -426,6 +441,7 @@ func MapPort(port string, domainName string) (string, string, error) { ProxyIpAddr.Name = config.MachineName ProxyIpAddr.NAT = "False" ProxyIpAddr.EscapeImplementation = "FRP" + //ProxyIpAddr.CustomInformationKey = p2p.GenerateHashSHA256(config.IPTableKey) } else { return "", "", errors.New("proxy IP not found")