您好,登錄后才能下訂單哦!
這篇文章主要介紹“Bytom怎么實現P2P網絡upnp端口映射”,在日常操作中,相信很多人在Bytom怎么實現P2P網絡upnp端口映射問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Bytom怎么實現P2P網絡upnp端口映射”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
UPNP(Universal Plug and Play)通用即插即用。UPNP端口映射將一個外部端口映射到一個內網ip:port。從而實現p2p網絡從外網能夠穿透網關訪問到內網的bytomd節點。
SSDP(Simple Service Discovery Protocol 簡單服務發現協議) GENA(Generic Event Notification Architecture 通用事件通知結構) SOAP(Simple Object Access Protocol 簡單對象訪問協議) XML(Extensible Markup Language 可擴張標記語言)
** p2p/upnp/upnp.go **
從網絡中發現支持UPNP功能的設備,并得到該設備的location和url等相關信息
type upnpNAT struct { serviceURL string // 設備的描述文件URL,用于得到該設備的描述信息 ourIP string // 節點本地ip地址 urnDomain string // 設備類型 } func Discover() (nat NAT, err error) { ssdp, err := net.ResolveUDPAddr("udp4", "239.255.255.250:1900") if err != nil { return } conn, err := net.ListenPacket("udp4", ":0") if err != nil { return } socket := conn.(*net.UDPConn) defer socket.Close() err = socket.SetDeadline(time.Now().Add(3 * time.Second)) if err != nil { return } st := "InternetGatewayDevice:1" // 多播請求:M-SEARCH SSDP協議定義的發現請求。 buf := bytes.NewBufferString( "M-SEARCH * HTTP/1.1\r\n" + "HOST: 239.255.255.250:1900\r\n" + "ST: ssdp:all\r\n" + "MAN: \"ssdp:discover\"\r\n" + "MX: 2\r\n\r\n") message := buf.Bytes() answerBytes := make([]byte, 1024) for i := 0; i < 3; i++ { // 向239.255.255.250:1900發送一條多播請求 _, err = socket.WriteToUDP(message, ssdp) if err != nil { return } // 如果從網絡中發現UPNP設備則會從239.255.255.250:1900收到響應消息 var n int n, _, err = socket.ReadFromUDP(answerBytes) for { n, _, err = socket.ReadFromUDP(answerBytes) if err != nil { break } answer := string(answerBytes[0:n]) if strings.Index(answer, st) < 0 { continue } // HTTP header field names are case-insensitive. // http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 // 獲得設備location locString := "\r\nlocation:" answer = strings.ToLower(answer) locIndex := strings.Index(answer, locString) if locIndex < 0 { continue } loc := answer[locIndex+len(locString):] endIndex := strings.Index(loc, "\r\n") if endIndex < 0 { continue } // 獲得設備的描述url和設備類型 locURL := strings.TrimSpace(loc[0:endIndex]) var serviceURL, urnDomain string serviceURL, urnDomain, err = getServiceURL(locURL) if err != nil { return } var ourIP net.IP ourIP, err = localIPv4() if err != nil { return } nat = &upnpNAT{serviceURL: serviceURL, ourIP: ourIP.String(), urnDomain: urnDomain} return } } err = errors.New("UPnP port discovery failed.") return }
向upnp設備發送一條http post請求,將內部網絡ip:port和外部網絡ip:port做映射
func (n *upnpNAT) AddPortMapping(protocol string, externalPort, internalPort int, description string, timeout int) (mappedExternalPort int, err error) { // A single concatenation would break ARM compilation. message := "<u:AddPortMapping xmlns:u=\"urn:" + n.urnDomain + ":service:WANIPConnection:1\">\r\n" + "<NewRemoteHost></NewRemoteHost><NewExternalPort>" + strconv.Itoa(externalPort) message += "</NewExternalPort><NewProtocol>" + protocol + "</NewProtocol>" message += "<NewInternalPort>" + strconv.Itoa(internalPort) + "</NewInternalPort>" + "<NewInternalClient>" + n.ourIP + "</NewInternalClient>" + "<NewEnabled>1</NewEnabled><NewPortMappingDescription>" message += description + "</NewPortMappingDescription><NewLeaseDuration>" + strconv.Itoa(timeout) + "</NewLeaseDuration></u:AddPortMapping>" var response *http.Response response, err = soapRequest(n.serviceURL, "AddPortMapping", message, n.urnDomain) if response != nil { defer response.Body.Close() } if err != nil { return } // TODO: check response to see if the port was forwarded // log.Println(message, response) // JAE: // body, err := ioutil.ReadAll(response.Body) // fmt.Println(string(body), err) mappedExternalPort = externalPort _ = response return }
向upnp設備發送一條http post請求,將內部網絡ip:port和外部網絡ip:port刪除映射關系
func (n *upnpNAT) DeletePortMapping(protocol string, externalPort, internalPort int) (err error) { message := "<u:DeletePortMapping xmlns:u=\"urn:" + n.urnDomain + ":service:WANIPConnection:1\">\r\n" + "<NewRemoteHost></NewRemoteHost><NewExternalPort>" + strconv.Itoa(externalPort) + "</NewExternalPort><NewProtocol>" + protocol + "</NewProtocol>" + "</u:DeletePortMapping>" var response *http.Response response, err = soapRequest(n.serviceURL, "DeletePortMapping", message, n.urnDomain) if response != nil { defer response.Body.Close() } if err != nil { return } // TODO: check response to see if the port was deleted // log.Println(message, response) _ = response return }
func (n *upnpNAT) GetExternalAddress() (addr net.IP, err error) { info, err := n.getExternalIPAddress() if err != nil { return } addr = net.ParseIP(info.externalIpAddress) return } func (n *upnpNAT) getExternalIPAddress() (info statusInfo, err error) { message := "<u:GetExternalIPAddress xmlns:u=\"urn:" + n.urnDomain + ":service:WANIPConnection:1\">\r\n" + "</u:GetExternalIPAddress>" var response *http.Response response, err = soapRequest(n.serviceURL, "GetExternalIPAddress", message, n.urnDomain) if response != nil { defer response.Body.Close() } if err != nil { return } var envelope Envelope data, err := ioutil.ReadAll(response.Body) reader := bytes.NewReader(data) xml.NewDecoder(reader).Decode(&envelope) info = statusInfo{envelope.Soap.ExternalIP.IPAddress} if err != nil { return } return }
到此,關于“Bytom怎么實現P2P網絡upnp端口映射”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。