upnp.go 4.5 KB

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