github.com/johnathanhowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/modules/gateway/upnp.go (about) 1 package gateway 2 3 import ( 4 "errors" 5 "io" 6 "io/ioutil" 7 "net" 8 "net/http" 9 "strconv" 10 "time" 11 12 "github.com/NebulousLabs/go-upnp" 13 14 "github.com/NebulousLabs/Sia/build" 15 "github.com/NebulousLabs/Sia/modules" 16 ) 17 18 // myExternalIP discovers the gateway's external IP by querying a centralized 19 // service, http://myexternalip.com. 20 func myExternalIP() (string, error) { 21 // timeout after 10 seconds 22 client := http.Client{Timeout: time.Duration(10 * time.Second)} 23 resp, err := client.Get("http://myexternalip.com/raw") 24 if err != nil { 25 return "", err 26 } 27 defer resp.Body.Close() 28 if resp.StatusCode != http.StatusOK { 29 errResp, _ := ioutil.ReadAll(resp.Body) 30 return "", errors.New(string(errResp)) 31 } 32 buf := make([]byte, 64) 33 n, err := resp.Body.Read(buf) 34 if err != nil && err != io.EOF { 35 return "", err 36 } 37 // trim newline 38 return string(buf[:n-1]), nil 39 } 40 41 // learnHostname discovers the external IP of the Gateway. Once the IP has 42 // been discovered, it registers the ShareNodes RPC to be called on new 43 // connections, advertising the IP to other nodes. 44 func (g *Gateway) learnHostname(port string) { 45 if build.Release == "testing" { 46 return 47 } 48 49 var host string 50 51 // try UPnP first, then fallback to myexternalip.com 52 d, err := upnp.Discover() 53 if err == nil { 54 host, err = d.ExternalIP() 55 } 56 if err != nil { 57 host, err = myExternalIP() 58 } 59 if err != nil { 60 g.log.Println("WARN: failed to discover external IP:", err) 61 return 62 } 63 64 addr := modules.NetAddress(net.JoinHostPort(host, port)) 65 if err := addr.IsValid(); err != nil { 66 g.log.Printf("WARN: discovered hostname %q is invalid: %v", addr, err) 67 return 68 } 69 70 id := g.mu.Lock() 71 g.myAddr = addr 72 g.mu.Unlock(id) 73 74 g.log.Println("INFO: our address is", g.myAddr) 75 76 // now that we know our address, we can start advertising it 77 g.RegisterConnectCall("RelayNode", g.sendAddress) 78 } 79 80 // forwardPort adds a port mapping to the router. 81 func (g *Gateway) forwardPort(port string) { 82 if build.Release == "testing" { 83 return 84 } 85 86 d, err := upnp.Discover() 87 if err != nil { 88 g.log.Printf("WARN: could not automatically forward port %s: no UPnP-enabled devices found", port) 89 return 90 } 91 92 portInt, _ := strconv.Atoi(port) 93 err = d.Forward(uint16(portInt), "Sia RPC") 94 if err != nil { 95 g.log.Printf("WARN: could not automatically forward port %s: %v", port, err) 96 return 97 } 98 99 g.log.Println("INFO: successfully forwarded port", port) 100 } 101 102 // clearPort removes a port mapping from the router. 103 func (g *Gateway) clearPort(port string) { 104 if build.Release == "testing" { 105 return 106 } 107 108 //d, err := upnp.Load("http://192.168.1.1:5000/Public_UPNP_gatedesc.xml") 109 d, err := upnp.Discover() 110 if err != nil { 111 return 112 } 113 114 portInt, _ := strconv.Atoi(port) 115 err = d.Clear(uint16(portInt)) 116 if err != nil { 117 g.log.Printf("WARN: could not automatically unforward port %s: %v", port, err) 118 return 119 } 120 121 g.log.Println("INFO: successfully unforwarded port", port) 122 }