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