mirror of
https://github.com/tobychui/zoraxy.git
synced 2025-06-03 06:07:20 +02:00
211 lines
4.5 KiB
Go
211 lines
4.5 KiB
Go
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)
|
|
|
|
}
|