123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- package main
- import (
- "encoding/json"
- "log"
- "net/http"
- "net/url"
- "regexp"
- "strconv"
- "time"
- "imuslab.com/zoraxy/mod/upnp"
- "imuslab.com/zoraxy/mod/utils"
- )
- var upnpEnabled = false
- var preforwardMap map[int]string
- func initUpnp() error {
- go func() {
- //Let UPnP discovery run in background
- var err error
- upnpClient, err = upnp.NewUPNPClient()
- if err != nil {
- log.Println("UPnP router discover error: ", err.Error())
- return
- }
- 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)
- }
- }
- }()
- //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
- 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)
- }
|