upnp.go 4.8 KB

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