mirror of
https://gitee.com/konyshe/goodlink.git
synced 2025-09-26 12:41:14 +08:00
调整策略
This commit is contained in:
@@ -4,5 +4,5 @@ Website = "https://goodlink.kony.vip"
|
||||
Icon = "theme/favicon.png"
|
||||
Name = "goodlink-windows-amd64-ui"
|
||||
ID = "goodlink.kony.vip"
|
||||
Version = "1.14.25"
|
||||
Version = "1.14.26"
|
||||
Build = 0
|
||||
|
@@ -38,8 +38,8 @@ func Help() {
|
||||
flag.IntVar(&Arg_p2p_timeout, "time_out", 30, "最大连接超时, 单位: 秒")
|
||||
flag.IntVar(&Arg_conn_type, "conn", 0, "若超过10分钟无法连接, 可尝试更换连接方式: 0: 主动; 1: 被动")
|
||||
|
||||
flag.IntVar(&Arg_conn_n0, "n0", 64, "dev n0")
|
||||
flag.IntVar(&Arg_conn_n1, "n1", 16, "dev n1")
|
||||
flag.IntVar(&Arg_conn_n0, "n0", 256, "dev n0")
|
||||
flag.IntVar(&Arg_conn_n1, "n1", 1, "dev n1")
|
||||
|
||||
/* 没有用到的参数 */
|
||||
flag.Bool("fork", false, "子进程")
|
||||
|
14
pro/comm.go
14
pro/comm.go
@@ -41,13 +41,13 @@ func Init(m_cli_redis_addr, m_cli_redis_pass string, m_cli_redis_id int) error {
|
||||
}
|
||||
|
||||
m_redis_db = redis.NewClient(&redis.Options{
|
||||
Addr: m_cli_redis_addr,
|
||||
Password: m_cli_redis_pass,
|
||||
DB: m_cli_redis_id,
|
||||
MaxRetries: 99,
|
||||
DialTimeout: 15 * time.Second,
|
||||
ReadTimeout: 15 * time.Second,
|
||||
WriteTimeout: 15 * time.Second,
|
||||
Addr: m_cli_redis_addr,
|
||||
Password: m_cli_redis_pass,
|
||||
DB: m_cli_redis_id,
|
||||
//MaxRetries: 99,
|
||||
DialTimeout: 5 * time.Second,
|
||||
ReadTimeout: 5 * time.Second,
|
||||
WriteTimeout: 5 * time.Second,
|
||||
})
|
||||
if m_redis_db == nil {
|
||||
return errors.New("Redis失败, 请重启程序")
|
||||
|
@@ -80,12 +80,13 @@ func GetLocalQuicConn(conn_type int, count int) (quic.Connection, quic.Stream, e
|
||||
}
|
||||
|
||||
m_tun_passive = tun.CteateTunPassive(conn, redisJson.ServerIP, redisJson.ServerPort1, redisJson.ServerPort2, redisJson.SendPortCount)
|
||||
m_tun_passive.Start()
|
||||
|
||||
redisJson.State = 2
|
||||
gogo.Log().DebugF("%d: 发送本端地址: %v", redisJson.State, redisJson)
|
||||
RedisSet(redisJson.RedisTimeOut, &redisJson)
|
||||
|
||||
m_tun_passive.Start()
|
||||
|
||||
default:
|
||||
if m_tun_active != nil {
|
||||
m_tun_active.Release()
|
||||
|
@@ -99,13 +99,15 @@ func GetRemoteQuicConn(time_out time.Duration) (quic.Connection, quic.Stream) {
|
||||
m_tun_active = nil
|
||||
|
||||
m_tun_passive = tun.CteateTunPassive(conn, redisJson.ClientIP, redisJson.ClientPort1, redisJson.ClientPort2, 0x100)
|
||||
m_tun_passive.Start()
|
||||
|
||||
tun_passive_chain = m_tun_passive.GetChain()
|
||||
|
||||
redisJson.State = 1
|
||||
gogo.Log().DebugF("%d: 发送本端地址: %v", redisJson.State, redisJson)
|
||||
RedisSet(redisJson.RedisTimeOut, &redisJson)
|
||||
|
||||
m_tun_passive.Start()
|
||||
|
||||
}
|
||||
|
||||
case 2:
|
||||
|
72
upnp/AddPortMapping.go
Normal file
72
upnp/AddPortMapping.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package upnp
|
||||
|
||||
import (
|
||||
// "log"
|
||||
// "fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type AddPortMapping struct {
|
||||
upnp *Upnp
|
||||
}
|
||||
|
||||
func (this *AddPortMapping) Send(localPort, remotePort int, protocol string) bool {
|
||||
request := this.buildRequest(localPort, remotePort, protocol)
|
||||
response, _ := http.DefaultClient.Do(request)
|
||||
resultBody, _ := ioutil.ReadAll(response.Body)
|
||||
if response.StatusCode == 200 {
|
||||
this.resolve(string(resultBody))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func (this *AddPortMapping) buildRequest(localPort, remotePort int, protocol string) *http.Request {
|
||||
//请求头
|
||||
header := http.Header{}
|
||||
header.Set("Accept", "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2")
|
||||
header.Set("SOAPAction", `"urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping"`)
|
||||
header.Set("Content-Type", "text/xml")
|
||||
header.Set("Connection", "Close")
|
||||
header.Set("Content-Length", "")
|
||||
//请求体
|
||||
body := Node{Name: "SOAP-ENV:Envelope",
|
||||
Attr: map[string]string{"xmlns:SOAP-ENV": `"http://schemas.xmlsoap.org/soap/envelope/"`,
|
||||
"SOAP-ENV:encodingStyle": `"http://schemas.xmlsoap.org/soap/encoding/"`}}
|
||||
childOne := Node{Name: `SOAP-ENV:Body`}
|
||||
childTwo := Node{Name: `m:AddPortMapping`,
|
||||
Attr: map[string]string{"xmlns:m": `"urn:schemas-upnp-org:service:WANIPConnection:1"`}}
|
||||
|
||||
childList1 := Node{Name: "NewExternalPort", Content: strconv.Itoa(remotePort)}
|
||||
childList2 := Node{Name: "NewInternalPort", Content: strconv.Itoa(localPort)}
|
||||
childList3 := Node{Name: "NewProtocol", Content: protocol}
|
||||
childList4 := Node{Name: "NewEnabled", Content: "1"}
|
||||
childList5 := Node{Name: "NewInternalClient", Content: this.upnp.LocalHost}
|
||||
childList6 := Node{Name: "NewLeaseDuration", Content: "0"}
|
||||
childList7 := Node{Name: "NewPortMappingDescription", Content: "mandela"}
|
||||
childList8 := Node{Name: "NewRemoteHost"}
|
||||
childTwo.AddChild(childList1)
|
||||
childTwo.AddChild(childList2)
|
||||
childTwo.AddChild(childList3)
|
||||
childTwo.AddChild(childList4)
|
||||
childTwo.AddChild(childList5)
|
||||
childTwo.AddChild(childList6)
|
||||
childTwo.AddChild(childList7)
|
||||
childTwo.AddChild(childList8)
|
||||
|
||||
childOne.AddChild(childTwo)
|
||||
body.AddChild(childOne)
|
||||
bodyStr := body.BuildXML()
|
||||
|
||||
//请求
|
||||
request, _ := http.NewRequest("POST", "http://"+this.upnp.Gateway.Host+this.upnp.CtrlUrl,
|
||||
strings.NewReader(bodyStr))
|
||||
request.Header = header
|
||||
request.Header.Set("Content-Length", strconv.Itoa(len([]byte(bodyStr))))
|
||||
return request
|
||||
}
|
||||
|
||||
func (this *AddPortMapping) resolve(resultStr string) {
|
||||
}
|
61
upnp/DelPortMapping.go
Normal file
61
upnp/DelPortMapping.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package upnp
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
// "log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type DelPortMapping struct {
|
||||
upnp *Upnp
|
||||
}
|
||||
|
||||
func (this *DelPortMapping) Send(remotePort int, protocol string) bool {
|
||||
request := this.buildRequest(remotePort, protocol)
|
||||
response, _ := http.DefaultClient.Do(request)
|
||||
resultBody, _ := ioutil.ReadAll(response.Body)
|
||||
if response.StatusCode == 200 {
|
||||
// log.Println(string(resultBody))
|
||||
this.resolve(string(resultBody))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func (this *DelPortMapping) buildRequest(remotePort int, protocol string) *http.Request {
|
||||
//请求头
|
||||
header := http.Header{}
|
||||
header.Set("Accept", "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2")
|
||||
header.Set("SOAPAction", `"urn:schemas-upnp-org:service:WANIPConnection:1#DeletePortMapping"`)
|
||||
header.Set("Content-Type", "text/xml")
|
||||
header.Set("Connection", "Close")
|
||||
header.Set("Content-Length", "")
|
||||
|
||||
//请求体
|
||||
body := Node{Name: "SOAP-ENV:Envelope",
|
||||
Attr: map[string]string{"xmlns:SOAP-ENV": `"http://schemas.xmlsoap.org/soap/envelope/"`,
|
||||
"SOAP-ENV:encodingStyle": `"http://schemas.xmlsoap.org/soap/encoding/"`}}
|
||||
childOne := Node{Name: `SOAP-ENV:Body`}
|
||||
childTwo := Node{Name: `m:DeletePortMapping`,
|
||||
Attr: map[string]string{"xmlns:m": `"urn:schemas-upnp-org:service:WANIPConnection:1"`}}
|
||||
childList1 := Node{Name: "NewExternalPort", Content: strconv.Itoa(remotePort)}
|
||||
childList2 := Node{Name: "NewProtocol", Content: protocol}
|
||||
childList3 := Node{Name: "NewRemoteHost"}
|
||||
childTwo.AddChild(childList1)
|
||||
childTwo.AddChild(childList2)
|
||||
childTwo.AddChild(childList3)
|
||||
childOne.AddChild(childTwo)
|
||||
body.AddChild(childOne)
|
||||
bodyStr := body.BuildXML()
|
||||
|
||||
//请求
|
||||
request, _ := http.NewRequest("POST", "http://"+this.upnp.Gateway.Host+this.upnp.CtrlUrl,
|
||||
strings.NewReader(bodyStr))
|
||||
request.Header = header
|
||||
request.Header.Set("Content-Length", strconv.Itoa(len([]byte(bodyStr))))
|
||||
return request
|
||||
}
|
||||
|
||||
func (this *DelPortMapping) resolve(resultStr string) {
|
||||
}
|
97
upnp/DeviceDesc.go
Normal file
97
upnp/DeviceDesc.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package upnp
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type DeviceDesc struct {
|
||||
upnp *Upnp
|
||||
}
|
||||
|
||||
func (this *DeviceDesc) Send() bool {
|
||||
request := this.BuildRequest()
|
||||
response, _ := http.DefaultClient.Do(request)
|
||||
resultBody, _ := ioutil.ReadAll(response.Body)
|
||||
if response.StatusCode == 200 {
|
||||
this.resolve(string(resultBody))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func (this *DeviceDesc) BuildRequest() *http.Request {
|
||||
//请求头
|
||||
header := http.Header{}
|
||||
header.Set("Accept", "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2")
|
||||
header.Set("User-Agent", "preston")
|
||||
header.Set("Host", this.upnp.Gateway.Host)
|
||||
header.Set("Connection", "keep-alive")
|
||||
|
||||
//请求
|
||||
request, _ := http.NewRequest("GET", "http://"+this.upnp.Gateway.Host+this.upnp.Gateway.DeviceDescUrl, nil)
|
||||
request.Header = header
|
||||
// request := http.Request{Method: "GET", Proto: "HTTP/1.1",
|
||||
// Host: this.upnp.Gateway.Host, Url: this.upnp.Gateway.DeviceDescUrl, Header: header}
|
||||
return request
|
||||
}
|
||||
|
||||
func (this *DeviceDesc) resolve(resultStr string) {
|
||||
inputReader := strings.NewReader(resultStr)
|
||||
|
||||
// 从文件读取,如可以如下:
|
||||
// content, err := ioutil.ReadFile("studygolang.xml")
|
||||
// decoder := xml.NewDecoder(bytes.NewBuffer(content))
|
||||
|
||||
lastLabel := ""
|
||||
|
||||
ISUpnpServer := false
|
||||
|
||||
IScontrolURL := false
|
||||
var controlURL string //`controlURL`
|
||||
// var eventSubURL string //`eventSubURL`
|
||||
// var SCPDURL string //`SCPDURL`
|
||||
|
||||
decoder := xml.NewDecoder(inputReader)
|
||||
for t, err := decoder.Token(); err == nil && !IScontrolURL; t, err = decoder.Token() {
|
||||
switch token := t.(type) {
|
||||
// 处理元素开始(标签)
|
||||
case xml.StartElement:
|
||||
if ISUpnpServer {
|
||||
name := token.Name.Local
|
||||
lastLabel = name
|
||||
}
|
||||
|
||||
// 处理元素结束(标签)
|
||||
case xml.EndElement:
|
||||
// log.Println("结束标记:", token.Name.Local)
|
||||
// 处理字符数据(这里就是元素的文本)
|
||||
case xml.CharData:
|
||||
//得到url后其他标记就不处理了
|
||||
content := string([]byte(token))
|
||||
|
||||
//找到提供端口映射的服务
|
||||
if content == this.upnp.Gateway.ServiceType {
|
||||
ISUpnpServer = true
|
||||
continue
|
||||
}
|
||||
//urn:upnp-org:serviceId:WANIPConnection
|
||||
if ISUpnpServer {
|
||||
switch lastLabel {
|
||||
case "controlURL":
|
||||
|
||||
controlURL = content
|
||||
IScontrolURL = true
|
||||
case "eventSubURL":
|
||||
// eventSubURL = content
|
||||
case "SCPDURL":
|
||||
// SCPDURL = content
|
||||
}
|
||||
}
|
||||
default:
|
||||
// ...
|
||||
}
|
||||
}
|
||||
this.upnp.CtrlUrl = controlURL
|
||||
}
|
45
upnp/DeviceStatusInfo.go
Normal file
45
upnp/DeviceStatusInfo.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package upnp
|
||||
|
||||
import (
|
||||
// "log"
|
||||
// "io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type SearchGatewayReq struct {
|
||||
host string
|
||||
resultBody string
|
||||
ctrlUrl string
|
||||
upnp *Upnp
|
||||
}
|
||||
|
||||
func (this SearchGatewayReq) Send() {
|
||||
// request := this.BuildRequest()
|
||||
}
|
||||
func (this SearchGatewayReq) BuildRequest() *http.Request {
|
||||
//请求头
|
||||
header := http.Header{}
|
||||
header.Set("Accept", "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2")
|
||||
header.Set("SOAPAction", `"urn:schemas-upnp-org:service:WANIPConnection:1#GetStatusInfo"`)
|
||||
header.Set("Content-Type", "text/xml")
|
||||
header.Set("Connection", "Close")
|
||||
header.Set("Content-Length", "")
|
||||
//请求体
|
||||
body := Node{Name: "SOAP-ENV:Envelope",
|
||||
Attr: map[string]string{"xmlns:SOAP-ENV": `"http://schemas.xmlsoap.org/soap/envelope/"`,
|
||||
"SOAP-ENV:encodingStyle": `"http://schemas.xmlsoap.org/soap/encoding/"`}}
|
||||
childOne := Node{Name: `SOAP-ENV:Body`}
|
||||
childTwo := Node{Name: `m:GetStatusInfo`,
|
||||
Attr: map[string]string{"xmlns:m": `"urn:schemas-upnp-org:service:WANIPConnection:1"`}}
|
||||
childOne.AddChild(childTwo)
|
||||
body.AddChild(childOne)
|
||||
bodyStr := body.BuildXML()
|
||||
//请求
|
||||
request, _ := http.NewRequest("POST", "http://"+this.upnp.Gateway.Host+this.upnp.CtrlUrl,
|
||||
strings.NewReader(bodyStr))
|
||||
request.Header = header
|
||||
request.Header.Set("Content-Length", strconv.Itoa(len([]byte(bodyStr))))
|
||||
return request
|
||||
}
|
78
upnp/ExternalIPAddress.go
Normal file
78
upnp/ExternalIPAddress.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package upnp
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"io/ioutil"
|
||||
// "log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ExternalIPAddress struct {
|
||||
upnp *Upnp
|
||||
}
|
||||
|
||||
func (this *ExternalIPAddress) Send() bool {
|
||||
request := this.BuildRequest()
|
||||
response, _ := http.DefaultClient.Do(request)
|
||||
resultBody, _ := ioutil.ReadAll(response.Body)
|
||||
if response.StatusCode == 200 {
|
||||
this.resolve(string(resultBody))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func (this *ExternalIPAddress) BuildRequest() *http.Request {
|
||||
//请求头
|
||||
header := http.Header{}
|
||||
header.Set("Accept", "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2")
|
||||
header.Set("SOAPAction", `"urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress"`)
|
||||
header.Set("Content-Type", "text/xml")
|
||||
header.Set("Connection", "Close")
|
||||
header.Set("Content-Length", "")
|
||||
//请求体
|
||||
body := Node{Name: "SOAP-ENV:Envelope",
|
||||
Attr: map[string]string{"xmlns:SOAP-ENV": `"http://schemas.xmlsoap.org/soap/envelope/"`,
|
||||
"SOAP-ENV:encodingStyle": `"http://schemas.xmlsoap.org/soap/encoding/"`}}
|
||||
childOne := Node{Name: `SOAP-ENV:Body`}
|
||||
childTwo := Node{Name: `m:GetExternalIPAddress`,
|
||||
Attr: map[string]string{"xmlns:m": `"urn:schemas-upnp-org:service:WANIPConnection:1"`}}
|
||||
childOne.AddChild(childTwo)
|
||||
body.AddChild(childOne)
|
||||
|
||||
bodyStr := body.BuildXML()
|
||||
//请求
|
||||
request, _ := http.NewRequest("POST", "http://"+this.upnp.Gateway.Host+this.upnp.CtrlUrl,
|
||||
strings.NewReader(bodyStr))
|
||||
request.Header = header
|
||||
request.Header.Set("Content-Length", strconv.Itoa(len([]byte(body.BuildXML()))))
|
||||
return request
|
||||
}
|
||||
|
||||
//NewExternalIPAddress
|
||||
func (this *ExternalIPAddress) resolve(resultStr string) {
|
||||
inputReader := strings.NewReader(resultStr)
|
||||
decoder := xml.NewDecoder(inputReader)
|
||||
ISexternalIP := false
|
||||
for t, err := decoder.Token(); err == nil; t, err = decoder.Token() {
|
||||
switch token := t.(type) {
|
||||
// 处理元素开始(标签)
|
||||
case xml.StartElement:
|
||||
name := token.Name.Local
|
||||
if name == "NewExternalIPAddress" {
|
||||
ISexternalIP = true
|
||||
}
|
||||
// 处理元素结束(标签)
|
||||
case xml.EndElement:
|
||||
// 处理字符数据(这里就是元素的文本)
|
||||
case xml.CharData:
|
||||
if ISexternalIP == true {
|
||||
this.upnp.GatewayOutsideIP = string([]byte(token))
|
||||
return
|
||||
}
|
||||
default:
|
||||
// ...
|
||||
}
|
||||
}
|
||||
}
|
121
upnp/SearchGatewayMsg.go
Normal file
121
upnp/SearchGatewayMsg.go
Normal file
@@ -0,0 +1,121 @@
|
||||
package upnp
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
// "net/http"
|
||||
)
|
||||
|
||||
type Gateway struct {
|
||||
GatewayName string //网关名称
|
||||
Host string //网关ip和端口
|
||||
DeviceDescUrl string //网关设备描述路径
|
||||
Cache string //cache
|
||||
ST string
|
||||
USN string
|
||||
deviceType string //设备的urn "urn:schemas-upnp-org:service:WANIPConnection:1"
|
||||
ControlURL string //设备端口映射请求路径
|
||||
ServiceType string //提供upnp服务的服务类型
|
||||
}
|
||||
|
||||
type SearchGateway struct {
|
||||
searchMessage string
|
||||
upnp *Upnp
|
||||
}
|
||||
|
||||
func (this *SearchGateway) Send() bool {
|
||||
this.buildRequest()
|
||||
c := make(chan string)
|
||||
go this.send(c)
|
||||
result := <-c
|
||||
if result == "" {
|
||||
//超时了
|
||||
this.upnp.Active = false
|
||||
return false
|
||||
}
|
||||
this.resolve(result)
|
||||
|
||||
this.upnp.Gateway.ServiceType = "urn:schemas-upnp-org:service:WANIPConnection:1"
|
||||
this.upnp.Active = true
|
||||
return true
|
||||
}
|
||||
func (this *SearchGateway) send(c chan string) {
|
||||
//发送组播消息,要带上端口,格式如:"239.255.255.250:1900"
|
||||
var conn *net.UDPConn
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
//超时了
|
||||
}
|
||||
}()
|
||||
go func(conn *net.UDPConn) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
//没超时
|
||||
}
|
||||
}()
|
||||
//超时时间为3秒
|
||||
time.Sleep(time.Second * 3)
|
||||
c <- ""
|
||||
conn.Close()
|
||||
}(conn)
|
||||
remotAddr, err := net.ResolveUDPAddr("udp", "239.255.255.250:1900")
|
||||
if err != nil {
|
||||
log.Println("组播地址格式不正确")
|
||||
}
|
||||
locaAddr, err := net.ResolveUDPAddr("udp", this.upnp.LocalHost+":")
|
||||
|
||||
if err != nil {
|
||||
log.Println("本地ip地址格式不正确")
|
||||
}
|
||||
conn, err = net.ListenUDP("udp", locaAddr)
|
||||
defer conn.Close()
|
||||
if err != nil {
|
||||
log.Println("监听udp出错")
|
||||
}
|
||||
_, err = conn.WriteToUDP([]byte(this.searchMessage), remotAddr)
|
||||
if err != nil {
|
||||
log.Println("发送msg到组播地址出错")
|
||||
}
|
||||
buf := make([]byte, 1024)
|
||||
n, _, err := conn.ReadFromUDP(buf)
|
||||
if err != nil {
|
||||
log.Println("从组播地址接搜消息出错")
|
||||
}
|
||||
|
||||
result := string(buf[:n])
|
||||
c <- result
|
||||
}
|
||||
func (this *SearchGateway) buildRequest() {
|
||||
this.searchMessage = "M-SEARCH * HTTP/1.1\r\n" +
|
||||
"HOST: 239.255.255.250:1900\r\n" +
|
||||
"ST: urn:schemas-upnp-org:service:WANIPConnection:1\r\n" +
|
||||
"MAN: \"ssdp:discover\"\r\n" + "MX: 3\r\n\r\n"
|
||||
}
|
||||
|
||||
func (this *SearchGateway) resolve(result string) {
|
||||
this.upnp.Gateway = &Gateway{}
|
||||
|
||||
lines := strings.Split(result, "\r\n")
|
||||
for _, line := range lines {
|
||||
//按照第一个冒号分为两个字符串
|
||||
nameValues := strings.SplitAfterN(line, ":", 2)
|
||||
if len(nameValues) < 2 {
|
||||
continue
|
||||
}
|
||||
switch strings.ToUpper(strings.Trim(strings.Split(nameValues[0], ":")[0], " ")) {
|
||||
case "ST":
|
||||
this.upnp.Gateway.ST = nameValues[1]
|
||||
case "CACHE-CONTROL":
|
||||
this.upnp.Gateway.Cache = nameValues[1]
|
||||
case "LOCATION":
|
||||
urls := strings.Split(strings.Split(nameValues[1], "//")[1], "/")
|
||||
this.upnp.Gateway.Host = urls[0]
|
||||
this.upnp.Gateway.DeviceDescUrl = "/" + urls[1]
|
||||
case "SERVER":
|
||||
this.upnp.Gateway.GatewayName = nameValues[1]
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
51
upnp/common.go
Normal file
51
upnp/common.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package upnp
|
||||
|
||||
import (
|
||||
// "log"
|
||||
"errors"
|
||||
"log"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 获取本机能联网的ip地址
|
||||
func GetLocalIntenetIp() string {
|
||||
/*
|
||||
获得所有本机地址
|
||||
判断能联网的ip地址
|
||||
*/
|
||||
|
||||
conn, err := net.Dial("udp4", "124.223.50.150:13478")
|
||||
if err != nil {
|
||||
panic(errors.New("不能连接网络"))
|
||||
}
|
||||
defer conn.Close()
|
||||
log.Println(conn.LocalAddr().String())
|
||||
log.Println(strings.Split(conn.LocalAddr().String(), ":")[0])
|
||||
return strings.Split(conn.LocalAddr().String(), ":")[0]
|
||||
}
|
||||
|
||||
// This returns the list of local ip addresses which other hosts can connect
|
||||
// to (NOTE: Loopback ip is ignored).
|
||||
func GetLocalIPs() ([]*net.IP, error) {
|
||||
addrs, err := net.InterfaceAddrs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ips := make([]*net.IP, 0)
|
||||
for _, addr := range addrs {
|
||||
ipnet, ok := addr.(*net.IPNet)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if ipnet.IP.IsLoopback() {
|
||||
continue
|
||||
}
|
||||
|
||||
ips = append(ips, &ipnet.IP)
|
||||
}
|
||||
|
||||
return ips, nil
|
||||
}
|
31
upnp/message.go
Normal file
31
upnp/message.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package upnp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type Node struct {
|
||||
Name string
|
||||
Content string
|
||||
Attr map[string]string
|
||||
Child []Node
|
||||
}
|
||||
|
||||
func (n *Node) AddChild(node Node) {
|
||||
n.Child = append(n.Child, node)
|
||||
}
|
||||
func (n *Node) BuildXML() string {
|
||||
buf := bytes.NewBufferString("<")
|
||||
buf.WriteString(n.Name)
|
||||
for key, value := range n.Attr {
|
||||
buf.WriteString(" ")
|
||||
buf.WriteString(key + "=" + value)
|
||||
}
|
||||
buf.WriteString(">" + n.Content)
|
||||
|
||||
for _, node := range n.Child {
|
||||
buf.WriteString(node.BuildXML())
|
||||
}
|
||||
buf.WriteString("</" + n.Name + ">")
|
||||
return buf.String()
|
||||
}
|
195
upnp/upnp.go
Normal file
195
upnp/upnp.go
Normal file
@@ -0,0 +1,195 @@
|
||||
package upnp
|
||||
|
||||
import (
|
||||
// "fmt"
|
||||
"errors"
|
||||
"log"
|
||||
"sync"
|
||||
)
|
||||
|
||||
/*
|
||||
* 得到网关
|
||||
*/
|
||||
|
||||
//对所有的端口进行管理
|
||||
type MappingPortStruct struct {
|
||||
lock *sync.Mutex
|
||||
mappingPorts map[string][][]int
|
||||
}
|
||||
|
||||
//添加一个端口映射记录
|
||||
//只对映射进行管理
|
||||
func (this *MappingPortStruct) addMapping(localPort, remotePort int, protocol string) {
|
||||
|
||||
this.lock.Lock()
|
||||
defer this.lock.Unlock()
|
||||
if this.mappingPorts == nil {
|
||||
one := make([]int, 0)
|
||||
one = append(one, localPort)
|
||||
two := make([]int, 0)
|
||||
two = append(two, remotePort)
|
||||
portMapping := [][]int{one, two}
|
||||
this.mappingPorts = map[string][][]int{protocol: portMapping}
|
||||
return
|
||||
}
|
||||
portMapping := this.mappingPorts[protocol]
|
||||
if portMapping == nil {
|
||||
one := make([]int, 0)
|
||||
one = append(one, localPort)
|
||||
two := make([]int, 0)
|
||||
two = append(two, remotePort)
|
||||
this.mappingPorts[protocol] = [][]int{one, two}
|
||||
return
|
||||
}
|
||||
one := portMapping[0]
|
||||
two := portMapping[1]
|
||||
one = append(one, localPort)
|
||||
two = append(two, remotePort)
|
||||
this.mappingPorts[protocol] = [][]int{one, two}
|
||||
}
|
||||
|
||||
//删除一个映射记录
|
||||
//只对映射进行管理
|
||||
func (this *MappingPortStruct) delMapping(remotePort int, protocol string) {
|
||||
this.lock.Lock()
|
||||
defer this.lock.Unlock()
|
||||
if this.mappingPorts == nil {
|
||||
return
|
||||
}
|
||||
tmp := MappingPortStruct{lock: new(sync.Mutex)}
|
||||
mappings := this.mappingPorts[protocol]
|
||||
for i := 0; i < len(mappings[0]); i++ {
|
||||
if mappings[1][i] == remotePort {
|
||||
//要删除的映射
|
||||
break
|
||||
}
|
||||
tmp.addMapping(mappings[0][i], mappings[1][i], protocol)
|
||||
}
|
||||
this.mappingPorts = tmp.mappingPorts
|
||||
}
|
||||
func (this *MappingPortStruct) GetAllMapping() map[string][][]int {
|
||||
return this.mappingPorts
|
||||
}
|
||||
|
||||
type Upnp struct {
|
||||
Active bool //这个upnp协议是否可用
|
||||
LocalHost string //本机ip地址
|
||||
GatewayInsideIP string //局域网网关ip
|
||||
GatewayOutsideIP string //网关公网ip
|
||||
OutsideMappingPort map[string]int //映射外部端口
|
||||
InsideMappingPort map[string]int //映射本机端口
|
||||
Gateway *Gateway //网关信息
|
||||
CtrlUrl string //控制请求url
|
||||
MappingPort MappingPortStruct //已经添加了的映射 {"TCP":[1990],"UDP":[1991]}
|
||||
}
|
||||
|
||||
//得到本地联网的ip地址
|
||||
//得到局域网网关ip
|
||||
func (this *Upnp) SearchGateway() (err error) {
|
||||
defer func(err error) {
|
||||
if errTemp := recover(); errTemp != nil {
|
||||
log.Println("upnp模块报错了", errTemp)
|
||||
err = errTemp.(error)
|
||||
}
|
||||
}(err)
|
||||
|
||||
if this.LocalHost == "" {
|
||||
this.MappingPort = MappingPortStruct{
|
||||
lock: new(sync.Mutex),
|
||||
// mappingPorts: map[string][][]int{},
|
||||
}
|
||||
this.LocalHost = GetLocalIntenetIp()
|
||||
}
|
||||
searchGateway := SearchGateway{upnp: this}
|
||||
if searchGateway.Send() {
|
||||
return nil
|
||||
}
|
||||
return errors.New("未发现网关设备")
|
||||
}
|
||||
|
||||
func (this *Upnp) deviceStatus() {
|
||||
|
||||
}
|
||||
|
||||
//查看设备描述,得到控制请求url
|
||||
func (this *Upnp) deviceDesc() (err error) {
|
||||
if this.GatewayInsideIP == "" {
|
||||
if err := this.SearchGateway(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
device := DeviceDesc{upnp: this}
|
||||
device.Send()
|
||||
this.Active = true
|
||||
// log.Println("获得控制请求url:", this.CtrlUrl)
|
||||
return
|
||||
}
|
||||
|
||||
//查看公网ip地址
|
||||
func (this *Upnp) ExternalIPAddr() (err error) {
|
||||
if this.CtrlUrl == "" {
|
||||
if err := this.deviceDesc(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
eia := ExternalIPAddress{upnp: this}
|
||||
eia.Send()
|
||||
return nil
|
||||
// log.Println("获得公网ip地址为:", this.GatewayOutsideIP)
|
||||
}
|
||||
|
||||
//添加一个端口映射
|
||||
func (this *Upnp) AddPortMapping(localPort, remotePort int, protocol string) (err error) {
|
||||
defer func(err error) {
|
||||
if errTemp := recover(); errTemp != nil {
|
||||
log.Println("upnp模块报错了", errTemp)
|
||||
err = errTemp.(error)
|
||||
}
|
||||
}(err)
|
||||
if this.GatewayOutsideIP == "" {
|
||||
if err := this.ExternalIPAddr(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
addPort := AddPortMapping{upnp: this}
|
||||
if issuccess := addPort.Send(localPort, remotePort, protocol); issuccess {
|
||||
this.MappingPort.addMapping(localPort, remotePort, protocol)
|
||||
// log.Println("添加一个端口映射:protocol:", protocol, "local:", localPort, "remote:", remotePort)
|
||||
return nil
|
||||
} else {
|
||||
this.Active = false
|
||||
// log.Println("添加一个端口映射失败")
|
||||
return errors.New("添加一个端口映射失败")
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Upnp) DelPortMapping(remotePort int, protocol string) bool {
|
||||
delMapping := DelPortMapping{upnp: this}
|
||||
issuccess := delMapping.Send(remotePort, protocol)
|
||||
if issuccess {
|
||||
this.MappingPort.delMapping(remotePort, protocol)
|
||||
log.Println("删除了一个端口映射: remote:", remotePort)
|
||||
}
|
||||
return issuccess
|
||||
}
|
||||
|
||||
//回收端口
|
||||
func (this *Upnp) Reclaim() {
|
||||
mappings := this.MappingPort.GetAllMapping()
|
||||
tcpMapping, ok := mappings["TCP"]
|
||||
if ok {
|
||||
for i := 0; i < len(tcpMapping[0]); i++ {
|
||||
this.DelPortMapping(tcpMapping[1][i], "TCP")
|
||||
}
|
||||
}
|
||||
udpMapping, ok := mappings["UDP"]
|
||||
if ok {
|
||||
for i := 0; i < len(udpMapping[0]); i++ {
|
||||
this.DelPortMapping(udpMapping[0][i], "UDP")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Upnp) GetAllMapping() map[string][][]int {
|
||||
return this.MappingPort.GetAllMapping()
|
||||
}
|
Reference in New Issue
Block a user