utils.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. package sshprox
  2. import (
  3. "errors"
  4. "fmt"
  5. "net"
  6. "net/url"
  7. "regexp"
  8. "runtime"
  9. "strings"
  10. "time"
  11. )
  12. // Rewrite url based on proxy root (default site)
  13. func RewriteURL(rooturl string, requestURL string) (*url.URL, error) {
  14. rewrittenURL := strings.TrimPrefix(requestURL, rooturl)
  15. return url.Parse(rewrittenURL)
  16. }
  17. // Check if the current platform support web.ssh function
  18. func IsWebSSHSupported() bool {
  19. //Check if the binary exists in system/gotty/
  20. binary := "gotty_" + runtime.GOOS + "_" + runtime.GOARCH
  21. if runtime.GOOS == "windows" {
  22. binary = binary + ".exe"
  23. }
  24. //Check if the target gotty terminal exists
  25. f, err := gotty.Open("gotty/" + binary)
  26. if err != nil {
  27. return false
  28. }
  29. f.Close()
  30. return true
  31. }
  32. // Get the next free port in the list
  33. func (m *Manager) GetNextPort() int {
  34. nextPort := m.StartingPort
  35. occupiedPort := make(map[int]bool)
  36. for _, instance := range m.Instances {
  37. occupiedPort[instance.AssignedPort] = true
  38. }
  39. for {
  40. if !occupiedPort[nextPort] {
  41. return nextPort
  42. }
  43. nextPort++
  44. }
  45. }
  46. // Check if a given domain and port is a valid ssh server
  47. func IsSSHConnectable(ipOrDomain string, port int) bool {
  48. timeout := time.Second * 3
  49. conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", ipOrDomain, port), timeout)
  50. if err != nil {
  51. return false
  52. }
  53. defer conn.Close()
  54. // Send an SSH version identification string to the server to check if it's SSH
  55. _, err = conn.Write([]byte("SSH-2.0-Go\r\n"))
  56. if err != nil {
  57. return false
  58. }
  59. // Wait for a response from the server
  60. buf := make([]byte, 1024)
  61. _, err = conn.Read(buf)
  62. if err != nil {
  63. return false
  64. }
  65. // Check if the response starts with "SSH-2.0"
  66. return string(buf[:7]) == "SSH-2.0"
  67. }
  68. // Validate the username and remote address to prevent injection
  69. func ValidateUsernameAndRemoteAddr(username string, remoteIpAddr string) error {
  70. // Validate and sanitize the username to prevent ssh injection
  71. validUsername := regexp.MustCompile(`^[a-zA-Z0-9._-]+$`)
  72. if !validUsername.MatchString(username) {
  73. return errors.New("invalid username, only alphanumeric characters, dots, underscores and dashes are allowed")
  74. }
  75. //Check if the remoteIpAddr is a valid ipv4 or ipv6 address
  76. if net.ParseIP(remoteIpAddr) != nil {
  77. //A valid IP address do not need further validation
  78. return nil
  79. }
  80. // Validate and sanitize the remote domain to prevent injection
  81. validRemoteAddr := regexp.MustCompile(`^[a-zA-Z0-9._-]+$`)
  82. if !validRemoteAddr.MatchString(remoteIpAddr) {
  83. return errors.New("invalid remote address, only alphanumeric characters, dots, underscores and dashes are allowed")
  84. }
  85. return nil
  86. }
  87. // Check if the given ip or domain is a loopback address
  88. // or resolves to a loopback address
  89. func IsLoopbackIPOrDomain(ipOrDomain string) bool {
  90. if strings.EqualFold(strings.TrimSpace(ipOrDomain), "localhost") || strings.TrimSpace(ipOrDomain) == "127.0.0.1" {
  91. return true
  92. }
  93. //Check if the ipOrDomain resolves to a loopback address
  94. ips, err := net.LookupIP(ipOrDomain)
  95. if err != nil {
  96. return false
  97. }
  98. for _, ip := range ips {
  99. if ip.IsLoopback() {
  100. return true
  101. }
  102. }
  103. return false
  104. }