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