github.com/DxChainNetwork/dxc@v0.8.1-0.20220824085222-1162e304b6e7/p2p/nat/natupnp_test.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package nat
    18  
    19  import (
    20  	"fmt"
    21  	"io"
    22  	"net"
    23  	"net/http"
    24  	"os"
    25  	"runtime"
    26  	"strings"
    27  	"testing"
    28  
    29  	"github.com/huin/goupnp/httpu"
    30  )
    31  
    32  func TestUPNP_DDWRT(t *testing.T) {
    33  	if runtime.GOOS == "windows" {
    34  		t.Skipf("disabled to avoid firewall prompt")
    35  	}
    36  
    37  	dev := &fakeIGD{
    38  		t: t,
    39  		ssdpResp: "HTTP/1.1 200 OK\r\n" +
    40  			"Cache-Control: max-age=300\r\n" +
    41  			"Date: Sun, 10 May 2015 10:05:33 GMT\r\n" +
    42  			"Ext: \r\n" +
    43  			"Location: http://{{listenAddr}}/InternetGatewayDevice.xml\r\n" +
    44  			"Server: POSIX UPnP/1.0 DD-WRT Linux/V24\r\n" +
    45  			"ST: urn:schemas-upnp-org:device:WANConnectionDevice:1\r\n" +
    46  			"USN: uuid:CB2471CC-CF2E-9795-8D9C-E87B34C16800::urn:schemas-upnp-org:device:WANConnectionDevice:1\r\n" +
    47  			"\r\n",
    48  		httpResps: map[string]string{
    49  			"GET /InternetGatewayDevice.xml": `
    50  				 <?xml version="1.0"?>
    51  				 <root xmlns="urn:schemas-upnp-org:device-1-0">
    52  					 <specVersion>
    53  						 <major>1</major>
    54  						 <minor>0</minor>
    55  					 </specVersion>
    56  					 <device>
    57  						 <deviceType>urn:schemas-upnp-org:device:InternetGatewayDevice:1</deviceType>
    58  						 <manufacturer>DD-WRT</manufacturer>
    59  						 <manufacturerURL>http://www.dd-wrt.com</manufacturerURL>
    60  						 <modelDescription>Gateway</modelDescription>
    61  						 <friendlyName>Asus RT-N16:DD-WRT</friendlyName>
    62  						 <modelName>Asus RT-N16</modelName>
    63  						 <modelNumber>V24</modelNumber>
    64  						 <serialNumber>0000001</serialNumber>
    65  						 <modelURL>http://www.dd-wrt.com</modelURL>
    66  						 <UDN>uuid:A13AB4C3-3A14-E386-DE6A-EFEA923A06FE</UDN>
    67  						 <serviceList>
    68  							 <service>
    69  								 <serviceType>urn:schemas-upnp-org:service:Layer3Forwarding:1</serviceType>
    70  								 <serviceId>urn:upnp-org:serviceId:L3Forwarding1</serviceId>
    71  								 <SCPDURL>/x_layer3forwarding.xml</SCPDURL>
    72  								 <controlURL>/control?Layer3Forwarding</controlURL>
    73  								 <eventSubURL>/event?Layer3Forwarding</eventSubURL>
    74  							 </service>
    75  						 </serviceList>
    76  						 <deviceList>
    77  							 <device>
    78  								 <deviceType>urn:schemas-upnp-org:device:WANDevice:1</deviceType>
    79  								 <friendlyName>WANDevice</friendlyName>
    80  								 <manufacturer>DD-WRT</manufacturer>
    81  								 <manufacturerURL>http://www.dd-wrt.com</manufacturerURL>
    82  								 <modelDescription>Gateway</modelDescription>
    83  								 <modelName>router</modelName>
    84  								 <modelURL>http://www.dd-wrt.com</modelURL>
    85  								 <UDN>uuid:48FD569B-F9A9-96AE-4EE6-EB403D3DB91A</UDN>
    86  								 <serviceList>
    87  									 <service>
    88  										 <serviceType>urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1</serviceType>
    89  										 <serviceId>urn:upnp-org:serviceId:WANCommonIFC1</serviceId>
    90  										 <SCPDURL>/x_wancommoninterfaceconfig.xml</SCPDURL>
    91  										 <controlURL>/control?WANCommonInterfaceConfig</controlURL>
    92  										 <eventSubURL>/event?WANCommonInterfaceConfig</eventSubURL>
    93  									 </service>
    94  								 </serviceList>
    95  								 <deviceList>
    96  									 <device>
    97  										 <deviceType>urn:schemas-upnp-org:device:WANConnectionDevice:1</deviceType>
    98  										 <friendlyName>WAN Connection Device</friendlyName>
    99  										 <manufacturer>DD-WRT</manufacturer>
   100  										 <manufacturerURL>http://www.dd-wrt.com</manufacturerURL>
   101  										 <modelDescription>Gateway</modelDescription>
   102  										 <modelName>router</modelName>
   103  										 <modelURL>http://www.dd-wrt.com</modelURL>
   104  										 <UDN>uuid:CB2471CC-CF2E-9795-8D9C-E87B34C16800</UDN>
   105  										 <serviceList>
   106  											 <service>
   107  												 <serviceType>urn:schemas-upnp-org:service:WANIPConnection:1</serviceType>
   108  												 <serviceId>urn:upnp-org:serviceId:WANIPConn1</serviceId>
   109  												 <SCPDURL>/x_wanipconnection.xml</SCPDURL>
   110  												 <controlURL>/control?WANIPConnection</controlURL>
   111  												 <eventSubURL>/event?WANIPConnection</eventSubURL>
   112  											 </service>
   113  										 </serviceList>
   114  									 </device>
   115  								 </deviceList>
   116  							 </device>
   117  							 <device>
   118  								 <deviceType>urn:schemas-upnp-org:device:LANDevice:1</deviceType>
   119  								 <friendlyName>LANDevice</friendlyName>
   120  								 <manufacturer>DD-WRT</manufacturer>
   121  								 <manufacturerURL>http://www.dd-wrt.com</manufacturerURL>
   122  								 <modelDescription>Gateway</modelDescription>
   123  								 <modelName>router</modelName>
   124  								 <modelURL>http://www.dd-wrt.com</modelURL>
   125  								 <UDN>uuid:04021998-3B35-2BDB-7B3C-99DA4435DA09</UDN>
   126  								 <serviceList>
   127  									 <service>
   128  										 <serviceType>urn:schemas-upnp-org:service:LANHostConfigManagement:1</serviceType>
   129  										 <serviceId>urn:upnp-org:serviceId:LANHostCfg1</serviceId>
   130  										 <SCPDURL>/x_lanhostconfigmanagement.xml</SCPDURL>
   131  										 <controlURL>/control?LANHostConfigManagement</controlURL>
   132  										 <eventSubURL>/event?LANHostConfigManagement</eventSubURL>
   133  									 </service>
   134  								 </serviceList>
   135  							 </device>
   136  						 </deviceList>
   137  						 <presentationURL>http://{{listenAddr}}</presentationURL>
   138  					 </device>
   139  				 </root>
   140  			`,
   141  			// The response to our GetNATRSIPStatus call. This
   142  			// particular implementation has a bug where the elements
   143  			// inside u:GetNATRSIPStatusResponse are not properly
   144  			// namespaced.
   145  			"POST /control?WANIPConnection": `
   146  				 <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
   147  				 <s:Body>
   148  				 <u:GetNATRSIPStatusResponse xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1">
   149  				 <NewRSIPAvailable>0</NewRSIPAvailable>
   150  				 <NewNATEnabled>1</NewNATEnabled>
   151  				 </u:GetNATRSIPStatusResponse>
   152  				 </s:Body>
   153  				 </s:Envelope>
   154  			`,
   155  		},
   156  	}
   157  	if err := dev.listen(); err != nil {
   158  		t.Skipf("cannot listen: %v", err)
   159  	}
   160  	dev.serve()
   161  	defer dev.close()
   162  
   163  	// Attempt to discover the fake device.
   164  	discovered := discoverUPnP()
   165  	if discovered == nil {
   166  		if os.Getenv("CI") != "" {
   167  			t.Fatalf("not discovered")
   168  		} else {
   169  			t.Skipf("UPnP not discovered (known issue, see https://github.com/DxChainNetwork/dxc/issues/21476)")
   170  		}
   171  	}
   172  	upnp, _ := discovered.(*upnp)
   173  	if upnp.service != "IGDv1-IP1" {
   174  		t.Errorf("upnp.service mismatch: got %q, want %q", upnp.service, "IGDv1-IP1")
   175  	}
   176  	wantURL := "http://" + dev.listener.Addr().String() + "/InternetGatewayDevice.xml"
   177  	if upnp.dev.URLBaseStr != wantURL {
   178  		t.Errorf("upnp.dev.URLBaseStr mismatch: got %q, want %q", upnp.dev.URLBaseStr, wantURL)
   179  	}
   180  }
   181  
   182  // fakeIGD presents itself as a discoverable UPnP device which sends
   183  // canned responses to HTTPU and HTTP requests.
   184  type fakeIGD struct {
   185  	t *testing.T // for logging
   186  
   187  	listener      net.Listener
   188  	mcastListener *net.UDPConn
   189  
   190  	// This should be a complete HTTP response (including headers).
   191  	// It is sent as the response to any sspd packet. Any occurrence
   192  	// of "{{listenAddr}}" is replaced with the actual TCP listen
   193  	// address of the HTTP server.
   194  	ssdpResp string
   195  	// This one should contain XML payloads for all requests
   196  	// performed. The keys contain method and path, e.g. "GET /foo/bar".
   197  	// As with ssdpResp, "{{listenAddr}}" is replaced with the TCP
   198  	// listen address.
   199  	httpResps map[string]string
   200  }
   201  
   202  // httpu.Handler
   203  func (dev *fakeIGD) ServeMessage(r *http.Request) {
   204  	dev.t.Logf(`HTTPU request %s %s`, r.Method, r.RequestURI)
   205  	conn, err := net.Dial("udp4", r.RemoteAddr)
   206  	if err != nil {
   207  		fmt.Printf("reply Dial error: %v", err)
   208  		return
   209  	}
   210  	defer conn.Close()
   211  	io.WriteString(conn, dev.replaceListenAddr(dev.ssdpResp))
   212  }
   213  
   214  // http.Handler
   215  func (dev *fakeIGD) ServeHTTP(w http.ResponseWriter, r *http.Request) {
   216  	if resp, ok := dev.httpResps[r.Method+" "+r.RequestURI]; ok {
   217  		dev.t.Logf(`HTTP request "%s %s" --> %d`, r.Method, r.RequestURI, 200)
   218  		io.WriteString(w, dev.replaceListenAddr(resp))
   219  	} else {
   220  		dev.t.Logf(`HTTP request "%s %s" --> %d`, r.Method, r.RequestURI, 404)
   221  		w.WriteHeader(http.StatusNotFound)
   222  	}
   223  }
   224  
   225  func (dev *fakeIGD) replaceListenAddr(resp string) string {
   226  	return strings.Replace(resp, "{{listenAddr}}", dev.listener.Addr().String(), -1)
   227  }
   228  
   229  func (dev *fakeIGD) listen() (err error) {
   230  	if dev.listener, err = net.Listen("tcp", "127.0.0.1:0"); err != nil {
   231  		return err
   232  	}
   233  	laddr := &net.UDPAddr{IP: net.ParseIP("239.255.255.250"), Port: 1900}
   234  	if dev.mcastListener, err = net.ListenMulticastUDP("udp", nil, laddr); err != nil {
   235  		dev.listener.Close()
   236  		return err
   237  	}
   238  	return nil
   239  }
   240  
   241  func (dev *fakeIGD) serve() {
   242  	go httpu.Serve(dev.mcastListener, dev)
   243  	go http.Serve(dev.listener, dev)
   244  }
   245  
   246  func (dev *fakeIGD) close() {
   247  	dev.mcastListener.Close()
   248  	dev.listener.Close()
   249  }