upnp.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. package main
  2. import (
  3. "encoding/json"
  4. "log"
  5. "net/http"
  6. "net/url"
  7. "regexp"
  8. "strconv"
  9. "time"
  10. "imuslab.com/zoraxy/mod/upnp"
  11. "imuslab.com/zoraxy/mod/utils"
  12. )
  13. var upnpEnabled = false
  14. var preforwardMap map[int]string
  15. func initUpnp() error {
  16. go func() {
  17. //Let UPnP discovery run in background
  18. var err error
  19. upnpClient, err = upnp.NewUPNPClient()
  20. if err != nil {
  21. log.Println("UPnP router discover error: ", err.Error())
  22. return
  23. }
  24. if upnpEnabled {
  25. //Forward all the ports
  26. for port, policyName := range preforwardMap {
  27. upnpClient.ForwardPort(port, policyName)
  28. log.Println("Upnp forwarding ", port, " for "+policyName)
  29. time.Sleep(300 * time.Millisecond)
  30. }
  31. }
  32. }()
  33. //Check if the upnp was enabled
  34. sysdb.NewTable("upnp")
  35. sysdb.Read("upnp", "enabled", &upnpEnabled)
  36. //Load all the ports from database
  37. portsMap := map[int]string{}
  38. sysdb.Read("upnp", "portmap", &portsMap)
  39. preforwardMap = portsMap
  40. return nil
  41. }
  42. func handleUpnpDiscover(w http.ResponseWriter, r *http.Request) {
  43. restart, err := utils.PostPara(r, "restart")
  44. if err != nil {
  45. type UpnpInfo struct {
  46. ExternalIp string
  47. RouterIp string
  48. }
  49. if upnpClient == nil {
  50. utils.SendErrorResponse(w, "No UPnP router discovered")
  51. return
  52. }
  53. parsedUrl, _ := url.Parse(upnpClient.Connection.Location())
  54. ipWithPort := parsedUrl.Host
  55. result := UpnpInfo{
  56. ExternalIp: upnpClient.ExternalIP,
  57. RouterIp: ipWithPort,
  58. }
  59. //Show if there is a upnpclient
  60. js, _ := json.Marshal(result)
  61. utils.SendJSONResponse(w, string(js))
  62. } else {
  63. if restart == "true" {
  64. //Close the upnp client if exists
  65. if upnpClient != nil {
  66. saveForwardingPortsToDatabase()
  67. upnpClient.Close()
  68. }
  69. //Restart a new one
  70. initUpnp()
  71. utils.SendOK(w)
  72. }
  73. }
  74. }
  75. func handleToggleUPnP(w http.ResponseWriter, r *http.Request) {
  76. newMode, err := utils.PostPara(r, "mode")
  77. if err != nil {
  78. //Send the current mode to client side
  79. js, _ := json.Marshal(upnpEnabled)
  80. utils.SendJSONResponse(w, string(js))
  81. } else {
  82. if newMode == "true" {
  83. upnpEnabled = true
  84. sysdb.Read("upnp", "enabled", true)
  85. log.Println("UPnP Enabled. Forwarding all required ports")
  86. //Mount all Upnp requests from preforward Map
  87. for port, policyName := range preforwardMap {
  88. upnpClient.ForwardPort(port, policyName)
  89. log.Println("Upnp forwarding ", port, " for "+policyName)
  90. time.Sleep(300 * time.Millisecond)
  91. }
  92. utils.SendOK(w)
  93. return
  94. } else if newMode == "false" {
  95. upnpEnabled = false
  96. sysdb.Read("upnp", "enabled", false)
  97. log.Println("UPnP disabled. Closing all forwarded ports")
  98. //Save the current forwarded ports
  99. saveForwardingPortsToDatabase()
  100. //Unmount all Upnp request
  101. for _, port := range upnpClient.RequiredPorts {
  102. upnpClient.ClosePort(port)
  103. log.Println("UPnP port closed: ", port)
  104. time.Sleep(300 * time.Millisecond)
  105. }
  106. //done
  107. utils.SendOK(w)
  108. return
  109. }
  110. }
  111. }
  112. func filterRFC2141(input string) string {
  113. rfc2141 := regexp.MustCompile(`^[\w\-.!~*'()]*(\%[\da-fA-F]{2}[\w\-.!~*'()]*)*$`)
  114. var result []rune
  115. for _, char := range input {
  116. if char <= 127 && rfc2141.MatchString(string(char)) {
  117. result = append(result, char)
  118. }
  119. }
  120. return string(result)
  121. }
  122. func handleAddUpnpPort(w http.ResponseWriter, r *http.Request) {
  123. portString, err := utils.PostPara(r, "port")
  124. if err != nil {
  125. utils.SendErrorResponse(w, "invalid port given")
  126. return
  127. }
  128. portNumber, err := strconv.Atoi(portString)
  129. if err != nil {
  130. utils.SendErrorResponse(w, "invalid port given")
  131. return
  132. }
  133. policyName, err := utils.PostPara(r, "name")
  134. if err != nil {
  135. utils.SendErrorResponse(w, "invalid policy name")
  136. return
  137. }
  138. policyName = filterRFC2141(policyName)
  139. err = upnpClient.ForwardPort(portNumber, policyName)
  140. if err != nil {
  141. utils.SendErrorResponse(w, err.Error())
  142. return
  143. }
  144. saveForwardingPortsToDatabase()
  145. utils.SendOK(w)
  146. }
  147. func handleRemoveUpnpPort(w http.ResponseWriter, r *http.Request) {
  148. portString, err := utils.PostPara(r, "port")
  149. if err != nil {
  150. utils.SendErrorResponse(w, "invalid port given")
  151. return
  152. }
  153. portNumber, err := strconv.Atoi(portString)
  154. if err != nil {
  155. utils.SendErrorResponse(w, "invalid port given")
  156. return
  157. }
  158. saveForwardingPortsToDatabase()
  159. upnpClient.ClosePort(portNumber)
  160. }
  161. func saveForwardingPortsToDatabase() {
  162. //Move the sync map to map[int]string
  163. m := make(map[int]string)
  164. upnpClient.PolicyNames.Range(func(key, value interface{}) bool {
  165. if k, ok := key.(int); ok {
  166. if v, ok := value.(string); ok {
  167. m[k] = v
  168. }
  169. }
  170. return true
  171. })
  172. preforwardMap = m
  173. sysdb.Write("upnp", "portmap", &preforwardMap)
  174. }