|
@@ -0,0 +1,207 @@
|
|
|
+package main
|
|
|
+
|
|
|
+import (
|
|
|
+ "encoding/json"
|
|
|
+ "log"
|
|
|
+ "net/http"
|
|
|
+ "net/url"
|
|
|
+ "regexp"
|
|
|
+ "strconv"
|
|
|
+ "time"
|
|
|
+
|
|
|
+ "imuslab.com/Zoarxy/mod/upnp"
|
|
|
+ "imuslab.com/Zoarxy/mod/utils"
|
|
|
+)
|
|
|
+
|
|
|
+var upnpEnabled = false
|
|
|
+var preforwardMap map[int]string
|
|
|
+
|
|
|
+func initUpnp() error {
|
|
|
+ var err error
|
|
|
+ upnpClient, err = upnp.NewUPNPClient()
|
|
|
+ if err != nil {
|
|
|
+ log.Println("UPnP router discover error: ", err.Error())
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ //Check if the upnp was enabled
|
|
|
+ sysdb.NewTable("upnp")
|
|
|
+ sysdb.Read("upnp", "enabled", &upnpEnabled)
|
|
|
+
|
|
|
+ //Load all the ports from database
|
|
|
+ portsMap := map[int]string{}
|
|
|
+ sysdb.Read("upnp", "portmap", &portsMap)
|
|
|
+ preforwardMap = portsMap
|
|
|
+
|
|
|
+ if upnpEnabled {
|
|
|
+ //Forward all the ports
|
|
|
+ for port, policyName := range preforwardMap {
|
|
|
+ upnpClient.ForwardPort(port, policyName)
|
|
|
+ log.Println("Upnp forwarding ", port, " for "+policyName)
|
|
|
+ time.Sleep(300 * time.Millisecond)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func handleUpnpDiscover(w http.ResponseWriter, r *http.Request) {
|
|
|
+ restart, err := utils.PostPara(r, "restart")
|
|
|
+ if err != nil {
|
|
|
+ type UpnpInfo struct {
|
|
|
+ ExternalIp string
|
|
|
+ RouterIp string
|
|
|
+ }
|
|
|
+
|
|
|
+ if upnpClient == nil {
|
|
|
+ utils.SendErrorResponse(w, "No UPnP router discovered")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ parsedUrl, _ := url.Parse(upnpClient.Connection.Location())
|
|
|
+ ipWithPort := parsedUrl.Host
|
|
|
+
|
|
|
+ result := UpnpInfo{
|
|
|
+ ExternalIp: upnpClient.ExternalIP,
|
|
|
+ RouterIp: ipWithPort,
|
|
|
+ }
|
|
|
+
|
|
|
+ //Show if there is a upnpclient
|
|
|
+ js, _ := json.Marshal(result)
|
|
|
+ utils.SendJSONResponse(w, string(js))
|
|
|
+ } else {
|
|
|
+ if restart == "true" {
|
|
|
+ //Close the upnp client if exists
|
|
|
+ if upnpClient != nil {
|
|
|
+ saveForwardingPortsToDatabase()
|
|
|
+ upnpClient.Close()
|
|
|
+ }
|
|
|
+
|
|
|
+ //Restart a new one
|
|
|
+ initUpnp()
|
|
|
+
|
|
|
+ utils.SendOK(w)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func handleToggleUPnP(w http.ResponseWriter, r *http.Request) {
|
|
|
+ newMode, err := utils.PostPara(r, "mode")
|
|
|
+ if err != nil {
|
|
|
+ //Send the current mode to client side
|
|
|
+ js, _ := json.Marshal(upnpEnabled)
|
|
|
+ utils.SendJSONResponse(w, string(js))
|
|
|
+ } else {
|
|
|
+ if newMode == "true" {
|
|
|
+ upnpEnabled = true
|
|
|
+ sysdb.Read("upnp", "enabled", true)
|
|
|
+
|
|
|
+ log.Println("UPnP Enabled. Forwarding all required ports")
|
|
|
+ //Mount all Upnp requests from preforward Map
|
|
|
+ for port, policyName := range preforwardMap {
|
|
|
+ upnpClient.ForwardPort(port, policyName)
|
|
|
+ log.Println("Upnp forwarding ", port, " for "+policyName)
|
|
|
+ time.Sleep(300 * time.Millisecond)
|
|
|
+ }
|
|
|
+
|
|
|
+ utils.SendOK(w)
|
|
|
+ return
|
|
|
+
|
|
|
+ } else if newMode == "false" {
|
|
|
+ upnpEnabled = false
|
|
|
+ sysdb.Read("upnp", "enabled", false)
|
|
|
+ log.Println("UPnP disabled. Closing all forwarded ports")
|
|
|
+ //Save the current forwarded ports
|
|
|
+ saveForwardingPortsToDatabase()
|
|
|
+
|
|
|
+ //Unmount all Upnp request
|
|
|
+ for _, port := range upnpClient.RequiredPorts {
|
|
|
+ upnpClient.ClosePort(port)
|
|
|
+ log.Println("UPnP port closed: ", port)
|
|
|
+ time.Sleep(300 * time.Millisecond)
|
|
|
+ }
|
|
|
+
|
|
|
+ //done
|
|
|
+ utils.SendOK(w)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func filterRFC2141(input string) string {
|
|
|
+ rfc2141 := regexp.MustCompile(`^[\w\-.!~*'()]*(\%[\da-fA-F]{2}[\w\-.!~*'()]*)*$`)
|
|
|
+ var result []rune
|
|
|
+ for _, char := range input {
|
|
|
+ if char <= 127 && rfc2141.MatchString(string(char)) {
|
|
|
+ result = append(result, char)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return string(result)
|
|
|
+}
|
|
|
+
|
|
|
+func handleAddUpnpPort(w http.ResponseWriter, r *http.Request) {
|
|
|
+ portString, err := utils.PostPara(r, "port")
|
|
|
+ if err != nil {
|
|
|
+ utils.SendErrorResponse(w, "invalid port given")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ portNumber, err := strconv.Atoi(portString)
|
|
|
+ if err != nil {
|
|
|
+ utils.SendErrorResponse(w, "invalid port given")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ policyName, err := utils.PostPara(r, "name")
|
|
|
+ if err != nil {
|
|
|
+ utils.SendErrorResponse(w, "invalid policy name")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ policyName = filterRFC2141(policyName)
|
|
|
+
|
|
|
+ err = upnpClient.ForwardPort(portNumber, policyName)
|
|
|
+ if err != nil {
|
|
|
+ utils.SendErrorResponse(w, err.Error())
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ saveForwardingPortsToDatabase()
|
|
|
+
|
|
|
+ utils.SendOK(w)
|
|
|
+}
|
|
|
+
|
|
|
+func handleRemoveUpnpPort(w http.ResponseWriter, r *http.Request) {
|
|
|
+ portString, err := utils.PostPara(r, "port")
|
|
|
+ if err != nil {
|
|
|
+ utils.SendErrorResponse(w, "invalid port given")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ portNumber, err := strconv.Atoi(portString)
|
|
|
+ if err != nil {
|
|
|
+ utils.SendErrorResponse(w, "invalid port given")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ saveForwardingPortsToDatabase()
|
|
|
+
|
|
|
+ upnpClient.ClosePort(portNumber)
|
|
|
+}
|
|
|
+
|
|
|
+func saveForwardingPortsToDatabase() {
|
|
|
+ //Move the sync map to map[int]string
|
|
|
+ m := make(map[int]string)
|
|
|
+ upnpClient.PolicyNames.Range(func(key, value interface{}) bool {
|
|
|
+ if k, ok := key.(int); ok {
|
|
|
+ if v, ok := value.(string); ok {
|
|
|
+ m[k] = v
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true
|
|
|
+ })
|
|
|
+
|
|
|
+ preforwardMap = m
|
|
|
+ sysdb.Write("upnp", "portmap", &preforwardMap)
|
|
|
+
|
|
|
+}
|