cool hit counter Derek decodes Bytom source code - P2P network upnp port mapping_Intefrankly

Derek decodes Bytom source code - P2P network upnp port mapping


By Derek

brief introduction

Github address.https://github.com/Bytom/bytom

Gitee address.https://gitee.com/BytomBlockchain/bytom

This chapter introduces upnp port mapping in bytom code P2P networks

The author uses the MacOS operating system, and other platforms are much the same

Golang Version: 1.8

Introduction to UPNP

UPNP (Universal Plug and Play) Universal Plug and Play. UPNP port mapping maps an external port to an intranet ip:port. Thus, the p2p network is able to penetrate the gateway from the outside network to access the bytomd node on the inside network.

UPNP protocol

SSDP (Simple Service Discovery Protocol)

GENA (Generic Event Notification Architecture)

SOAP (Simple Object Access Protocol)

XML (Extensible Markup Language expandable markup language (XML))

UPNP Code

p2p/upnp/upnp.go

Discovering UPNP-enabled devices in the network

Discover the UPNP-enabled device from the network and get the relevant information such as location and url of the device

type upnpNAT struct {
	serviceURL string //  Description file of the deviceURL, Used to get the description information of the device
	ourIP      string //  Node Localip address
	urnDomain  string //  Equipment Type
}

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"

	//  Multicast requests:M-SEARCH SSDP Protocol-defined discovery requests。
	buf := bytes.NewBufferString(
		"M-SEARCH * HTTP/1.1
" +
			"HOST: 239.255.255.250:1900
" +
			"ST: ssdp:all
" +
			"MAN: "ssdp:discover"
" +
			"MX: 2

")
	message := buf.Bytes()
	answerBytes := make([]byte, 1024)
	for i := 0; i < 3; i++ {
		//  toward239.255.255.250:1900 Send a multicast request
		_, err = socket.WriteToUDP(message, ssdp)
		if err != nil {
			return
		}
		//  If one finds from the webUPNP The device, in turn, will start with239.255.255.250:1900 Response message received
		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
			//  Access to equipmentlocation
			locString := "
location:"
			answer = strings.ToLower(answer)
			locIndex := strings.Index(answer, locString)
			if locIndex < 0 {
				continue
			}
			loc := answer[locIndex+len(locString):]
			endIndex := strings.Index(loc, "
")
			if endIndex < 0 {
				continue
			}
			//  Get a description of the deviceurl and type of equipment
			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
}

Adding Port Mapping

Send an http post request to the upnp device, mapping the internal network ip:port to the external network 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">
" +
		"<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
}

Remove port mapping

Send an http post request to the upnp device to remove the mapping between the internal network ip:port and the external network ip:port

func (n *upnpNAT) DeletePortMapping(protocol string, externalPort, internalPort int) (err error) {

	message := "<u:DeletePortMapping xmlns:u="urn:" + n.urnDomain + ":service:WANIPConnection:1">
" +
		"<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
}

Get the mapped public address

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">
" +
		"</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
}

Recommended>>
1、Nearly 2000 students participate in citys highest level of competition in informatics
2、Dong Mingzhu talks AI and trade war at Boao Forum for Asia subforum No need to feel panic but pride
3、What has changed in BP Applicant Q A a month ago
4、TensorFlow implementation of StarGAN code all open source trained in 1 day
5、New vulnerability affects CPU processors worldwide for 20 years

    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号