You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

404 lines
10 KiB

9 years ago
9 years ago
return an error if we fail to parse external IP ``` I[06-08|11:51:57.234] Getting UPNP external address module=p2p I[06-08|11:51:58.867] Got UPNP external address module=p2p address= ``` Fixes #1717 ``` I[06-08|11:51:56.952] Starting multiAppConn module=proxy impl=multiAppConn I[06-08|11:51:56.952] Starting localClient module=abci-client connection=query impl=localClient I[06-08|11:51:56.952] Starting localClient module=abci-client connection=mempool impl=localClient I[06-08|11:51:56.952] Starting localClient module=abci-client connection=consensus impl=localClient I[06-08|11:51:56.952] ABCI Handshake module=consensus appHeight=0 appHash= I[06-08|11:51:56.952] ABCI Replay Blocks module=consensus appHeight=0 storeHeight=0 stateHeight=0 I[06-08|11:51:57.053] Completed ABCI Handshake - Tendermint and App are synced module=consensus appHeight=0 appHash= I[06-08|11:51:57.053] This node is a validator module=consensus addr=6816B5D9BAC32A3CDF07884D9D3D2650694C371D pubKey=PubKeyEd25519{27A40CD032DD2467342D0CF27C5EC92052D966FEC714B6CF2F3BF3146AFD0D51} I[06-08|11:51:57.234] Starting Node module=main impl=Node I[06-08|11:51:57.234] Starting EventBus module=events impl=EventBus I[06-08|11:51:57.234] Local listener module=p2p ip=:: port=46656 I[06-08|11:51:57.234] Getting UPNP external address module=p2p I[06-08|11:51:58.867] Got UPNP external address module=p2p address= I[06-08|11:51:58.867] Starting DefaultListener module=p2p impl=Listener(@<nil>:46656) I[06-08|11:51:58.867] P2P Node ID module=main ID=3629b516392e494ae717ac4c6a1ea7eb0fe421c3 file=/home/tpb/.tendermint/config/node_key.json I[06-08|11:51:58.868] Add our address to book module=p2p book=/home/tpb/.tendermint/config/addrbook.json addr=null panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x38 pc=0x89fb86] goroutine 1 [running]: github.com/tendermint/tendermint/p2p.(*NetAddress).String(0x0, 0xc96e24, 0x17) /home/tpb/code/go/src/github.com/tendermint/tendermint/p2p/netaddress.go:171 +0x26 github.com/tendermint/tendermint/p2p/pex.(*addrBook).AddOurAddress(0xc420190620, 0x0) /home/tpb/code/go/src/github.com/tendermint/tendermint/p2p/pex/addrbook.go:160 +0x116 github.com/tendermint/tendermint/node.(*Node).OnStart(0xc420286d00, 0xc4201b8010, 0xd) /home/tpb/code/go/src/github.com/tendermint/tendermint/node/node.go:402 +0x547 github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common.(*BaseService).Start(0xc420286d00, 0xe51c40, 0xc42000bd40) /home/tpb/code/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common/service.go:130 +0x3bd github.com/tendermint/tendermint/cmd/tendermint/commands.NewRunNodeCmd.func1(0xc42022e000, 0xc4200acdc0, 0x0, 0x1, 0x0, 0x0) /home/tpb/code/go/src/github.com/tendermint/tendermint/cmd/tendermint/commands/run_node.go:58 +0xfe github.com/tendermint/tendermint/vendor/github.com/spf13/cobra.(*Command).execute(0xc42022e000, 0xc4200acda0, 0x1, 0x1, 0xc42022e000, 0xc4200acda0) /home/tpb/code/go/src/github.com/tendermint/tendermint/vendor/github.com/spf13/cobra/command.go:762 +0x468 github.com/tendermint/tendermint/vendor/github.com/spf13/cobra.(*Command).ExecuteC(0x1289280, 0xbbdda0, 0xc420015e01, 0xc4201bc640) /home/tpb/code/go/src/github.com/tendermint/tendermint/vendor/github.com/spf13/cobra/command.go:852 +0x30a github.com/tendermint/tendermint/vendor/github.com/spf13/cobra.(*Command).Execute(0x1289280, 0xc4201bc640, 0xc420015e98) /home/tpb/code/go/src/github.com/tendermint/tendermint/vendor/github.com/spf13/cobra/command.go:800 +0x2b github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/cli.Executor.Execute(0x1289280, 0xde5798, 0x2, 0xc4200332c0) /home/tpb/code/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/cli/setup.go:89 +0x4e main.main() /home/tpb/code/go/src/github.com/tendermint/tendermint/cmd/tendermint/main.go:45 +0x24d ```
7 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
return an error if we fail to parse external IP ``` I[06-08|11:51:57.234] Getting UPNP external address module=p2p I[06-08|11:51:58.867] Got UPNP external address module=p2p address= ``` Fixes #1717 ``` I[06-08|11:51:56.952] Starting multiAppConn module=proxy impl=multiAppConn I[06-08|11:51:56.952] Starting localClient module=abci-client connection=query impl=localClient I[06-08|11:51:56.952] Starting localClient module=abci-client connection=mempool impl=localClient I[06-08|11:51:56.952] Starting localClient module=abci-client connection=consensus impl=localClient I[06-08|11:51:56.952] ABCI Handshake module=consensus appHeight=0 appHash= I[06-08|11:51:56.952] ABCI Replay Blocks module=consensus appHeight=0 storeHeight=0 stateHeight=0 I[06-08|11:51:57.053] Completed ABCI Handshake - Tendermint and App are synced module=consensus appHeight=0 appHash= I[06-08|11:51:57.053] This node is a validator module=consensus addr=6816B5D9BAC32A3CDF07884D9D3D2650694C371D pubKey=PubKeyEd25519{27A40CD032DD2467342D0CF27C5EC92052D966FEC714B6CF2F3BF3146AFD0D51} I[06-08|11:51:57.234] Starting Node module=main impl=Node I[06-08|11:51:57.234] Starting EventBus module=events impl=EventBus I[06-08|11:51:57.234] Local listener module=p2p ip=:: port=46656 I[06-08|11:51:57.234] Getting UPNP external address module=p2p I[06-08|11:51:58.867] Got UPNP external address module=p2p address= I[06-08|11:51:58.867] Starting DefaultListener module=p2p impl=Listener(@<nil>:46656) I[06-08|11:51:58.867] P2P Node ID module=main ID=3629b516392e494ae717ac4c6a1ea7eb0fe421c3 file=/home/tpb/.tendermint/config/node_key.json I[06-08|11:51:58.868] Add our address to book module=p2p book=/home/tpb/.tendermint/config/addrbook.json addr=null panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x38 pc=0x89fb86] goroutine 1 [running]: github.com/tendermint/tendermint/p2p.(*NetAddress).String(0x0, 0xc96e24, 0x17) /home/tpb/code/go/src/github.com/tendermint/tendermint/p2p/netaddress.go:171 +0x26 github.com/tendermint/tendermint/p2p/pex.(*addrBook).AddOurAddress(0xc420190620, 0x0) /home/tpb/code/go/src/github.com/tendermint/tendermint/p2p/pex/addrbook.go:160 +0x116 github.com/tendermint/tendermint/node.(*Node).OnStart(0xc420286d00, 0xc4201b8010, 0xd) /home/tpb/code/go/src/github.com/tendermint/tendermint/node/node.go:402 +0x547 github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common.(*BaseService).Start(0xc420286d00, 0xe51c40, 0xc42000bd40) /home/tpb/code/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common/service.go:130 +0x3bd github.com/tendermint/tendermint/cmd/tendermint/commands.NewRunNodeCmd.func1(0xc42022e000, 0xc4200acdc0, 0x0, 0x1, 0x0, 0x0) /home/tpb/code/go/src/github.com/tendermint/tendermint/cmd/tendermint/commands/run_node.go:58 +0xfe github.com/tendermint/tendermint/vendor/github.com/spf13/cobra.(*Command).execute(0xc42022e000, 0xc4200acda0, 0x1, 0x1, 0xc42022e000, 0xc4200acda0) /home/tpb/code/go/src/github.com/tendermint/tendermint/vendor/github.com/spf13/cobra/command.go:762 +0x468 github.com/tendermint/tendermint/vendor/github.com/spf13/cobra.(*Command).ExecuteC(0x1289280, 0xbbdda0, 0xc420015e01, 0xc4201bc640) /home/tpb/code/go/src/github.com/tendermint/tendermint/vendor/github.com/spf13/cobra/command.go:852 +0x30a github.com/tendermint/tendermint/vendor/github.com/spf13/cobra.(*Command).Execute(0x1289280, 0xc4201bc640, 0xc420015e98) /home/tpb/code/go/src/github.com/tendermint/tendermint/vendor/github.com/spf13/cobra/command.go:800 +0x2b github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/cli.Executor.Execute(0x1289280, 0xde5798, 0x2, 0xc4200332c0) /home/tpb/code/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/cli/setup.go:89 +0x4e main.main() /home/tpb/code/go/src/github.com/tendermint/tendermint/cmd/tendermint/main.go:45 +0x24d ```
7 years ago
9 years ago
return an error if we fail to parse external IP ``` I[06-08|11:51:57.234] Getting UPNP external address module=p2p I[06-08|11:51:58.867] Got UPNP external address module=p2p address= ``` Fixes #1717 ``` I[06-08|11:51:56.952] Starting multiAppConn module=proxy impl=multiAppConn I[06-08|11:51:56.952] Starting localClient module=abci-client connection=query impl=localClient I[06-08|11:51:56.952] Starting localClient module=abci-client connection=mempool impl=localClient I[06-08|11:51:56.952] Starting localClient module=abci-client connection=consensus impl=localClient I[06-08|11:51:56.952] ABCI Handshake module=consensus appHeight=0 appHash= I[06-08|11:51:56.952] ABCI Replay Blocks module=consensus appHeight=0 storeHeight=0 stateHeight=0 I[06-08|11:51:57.053] Completed ABCI Handshake - Tendermint and App are synced module=consensus appHeight=0 appHash= I[06-08|11:51:57.053] This node is a validator module=consensus addr=6816B5D9BAC32A3CDF07884D9D3D2650694C371D pubKey=PubKeyEd25519{27A40CD032DD2467342D0CF27C5EC92052D966FEC714B6CF2F3BF3146AFD0D51} I[06-08|11:51:57.234] Starting Node module=main impl=Node I[06-08|11:51:57.234] Starting EventBus module=events impl=EventBus I[06-08|11:51:57.234] Local listener module=p2p ip=:: port=46656 I[06-08|11:51:57.234] Getting UPNP external address module=p2p I[06-08|11:51:58.867] Got UPNP external address module=p2p address= I[06-08|11:51:58.867] Starting DefaultListener module=p2p impl=Listener(@<nil>:46656) I[06-08|11:51:58.867] P2P Node ID module=main ID=3629b516392e494ae717ac4c6a1ea7eb0fe421c3 file=/home/tpb/.tendermint/config/node_key.json I[06-08|11:51:58.868] Add our address to book module=p2p book=/home/tpb/.tendermint/config/addrbook.json addr=null panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x38 pc=0x89fb86] goroutine 1 [running]: github.com/tendermint/tendermint/p2p.(*NetAddress).String(0x0, 0xc96e24, 0x17) /home/tpb/code/go/src/github.com/tendermint/tendermint/p2p/netaddress.go:171 +0x26 github.com/tendermint/tendermint/p2p/pex.(*addrBook).AddOurAddress(0xc420190620, 0x0) /home/tpb/code/go/src/github.com/tendermint/tendermint/p2p/pex/addrbook.go:160 +0x116 github.com/tendermint/tendermint/node.(*Node).OnStart(0xc420286d00, 0xc4201b8010, 0xd) /home/tpb/code/go/src/github.com/tendermint/tendermint/node/node.go:402 +0x547 github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common.(*BaseService).Start(0xc420286d00, 0xe51c40, 0xc42000bd40) /home/tpb/code/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common/service.go:130 +0x3bd github.com/tendermint/tendermint/cmd/tendermint/commands.NewRunNodeCmd.func1(0xc42022e000, 0xc4200acdc0, 0x0, 0x1, 0x0, 0x0) /home/tpb/code/go/src/github.com/tendermint/tendermint/cmd/tendermint/commands/run_node.go:58 +0xfe github.com/tendermint/tendermint/vendor/github.com/spf13/cobra.(*Command).execute(0xc42022e000, 0xc4200acda0, 0x1, 0x1, 0xc42022e000, 0xc4200acda0) /home/tpb/code/go/src/github.com/tendermint/tendermint/vendor/github.com/spf13/cobra/command.go:762 +0x468 github.com/tendermint/tendermint/vendor/github.com/spf13/cobra.(*Command).ExecuteC(0x1289280, 0xbbdda0, 0xc420015e01, 0xc4201bc640) /home/tpb/code/go/src/github.com/tendermint/tendermint/vendor/github.com/spf13/cobra/command.go:852 +0x30a github.com/tendermint/tendermint/vendor/github.com/spf13/cobra.(*Command).Execute(0x1289280, 0xc4201bc640, 0xc420015e98) /home/tpb/code/go/src/github.com/tendermint/tendermint/vendor/github.com/spf13/cobra/command.go:800 +0x2b github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/cli.Executor.Execute(0x1289280, 0xde5798, 0x2, 0xc4200332c0) /home/tpb/code/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/cli/setup.go:89 +0x4e main.main() /home/tpb/code/go/src/github.com/tendermint/tendermint/cmd/tendermint/main.go:45 +0x24d ```
7 years ago
return an error if we fail to parse external IP ``` I[06-08|11:51:57.234] Getting UPNP external address module=p2p I[06-08|11:51:58.867] Got UPNP external address module=p2p address= ``` Fixes #1717 ``` I[06-08|11:51:56.952] Starting multiAppConn module=proxy impl=multiAppConn I[06-08|11:51:56.952] Starting localClient module=abci-client connection=query impl=localClient I[06-08|11:51:56.952] Starting localClient module=abci-client connection=mempool impl=localClient I[06-08|11:51:56.952] Starting localClient module=abci-client connection=consensus impl=localClient I[06-08|11:51:56.952] ABCI Handshake module=consensus appHeight=0 appHash= I[06-08|11:51:56.952] ABCI Replay Blocks module=consensus appHeight=0 storeHeight=0 stateHeight=0 I[06-08|11:51:57.053] Completed ABCI Handshake - Tendermint and App are synced module=consensus appHeight=0 appHash= I[06-08|11:51:57.053] This node is a validator module=consensus addr=6816B5D9BAC32A3CDF07884D9D3D2650694C371D pubKey=PubKeyEd25519{27A40CD032DD2467342D0CF27C5EC92052D966FEC714B6CF2F3BF3146AFD0D51} I[06-08|11:51:57.234] Starting Node module=main impl=Node I[06-08|11:51:57.234] Starting EventBus module=events impl=EventBus I[06-08|11:51:57.234] Local listener module=p2p ip=:: port=46656 I[06-08|11:51:57.234] Getting UPNP external address module=p2p I[06-08|11:51:58.867] Got UPNP external address module=p2p address= I[06-08|11:51:58.867] Starting DefaultListener module=p2p impl=Listener(@<nil>:46656) I[06-08|11:51:58.867] P2P Node ID module=main ID=3629b516392e494ae717ac4c6a1ea7eb0fe421c3 file=/home/tpb/.tendermint/config/node_key.json I[06-08|11:51:58.868] Add our address to book module=p2p book=/home/tpb/.tendermint/config/addrbook.json addr=null panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x38 pc=0x89fb86] goroutine 1 [running]: github.com/tendermint/tendermint/p2p.(*NetAddress).String(0x0, 0xc96e24, 0x17) /home/tpb/code/go/src/github.com/tendermint/tendermint/p2p/netaddress.go:171 +0x26 github.com/tendermint/tendermint/p2p/pex.(*addrBook).AddOurAddress(0xc420190620, 0x0) /home/tpb/code/go/src/github.com/tendermint/tendermint/p2p/pex/addrbook.go:160 +0x116 github.com/tendermint/tendermint/node.(*Node).OnStart(0xc420286d00, 0xc4201b8010, 0xd) /home/tpb/code/go/src/github.com/tendermint/tendermint/node/node.go:402 +0x547 github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common.(*BaseService).Start(0xc420286d00, 0xe51c40, 0xc42000bd40) /home/tpb/code/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/common/service.go:130 +0x3bd github.com/tendermint/tendermint/cmd/tendermint/commands.NewRunNodeCmd.func1(0xc42022e000, 0xc4200acdc0, 0x0, 0x1, 0x0, 0x0) /home/tpb/code/go/src/github.com/tendermint/tendermint/cmd/tendermint/commands/run_node.go:58 +0xfe github.com/tendermint/tendermint/vendor/github.com/spf13/cobra.(*Command).execute(0xc42022e000, 0xc4200acda0, 0x1, 0x1, 0xc42022e000, 0xc4200acda0) /home/tpb/code/go/src/github.com/tendermint/tendermint/vendor/github.com/spf13/cobra/command.go:762 +0x468 github.com/tendermint/tendermint/vendor/github.com/spf13/cobra.(*Command).ExecuteC(0x1289280, 0xbbdda0, 0xc420015e01, 0xc4201bc640) /home/tpb/code/go/src/github.com/tendermint/tendermint/vendor/github.com/spf13/cobra/command.go:852 +0x30a github.com/tendermint/tendermint/vendor/github.com/spf13/cobra.(*Command).Execute(0x1289280, 0xc4201bc640, 0xc420015e98) /home/tpb/code/go/src/github.com/tendermint/tendermint/vendor/github.com/spf13/cobra/command.go:800 +0x2b github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/cli.Executor.Execute(0x1289280, 0xde5798, 0x2, 0xc4200332c0) /home/tpb/code/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/tmlibs/cli/setup.go:89 +0x4e main.main() /home/tpb/code/go/src/github.com/tendermint/tendermint/cmd/tendermint/main.go:45 +0x24d ```
7 years ago
9 years ago
9 years ago
9 years ago
9 years ago
  1. // Taken from taipei-torrent.
  2. // Just enough UPnP to be able to forward ports
  3. // For more information, see: http://www.upnp-hacks.org/upnp.html
  4. package upnp
  5. // TODO: use syscalls to get actual ourIP, see issue #712
  6. import (
  7. "bytes"
  8. "encoding/xml"
  9. "errors"
  10. "fmt"
  11. "io/ioutil"
  12. "net"
  13. "net/http"
  14. "strconv"
  15. "strings"
  16. "time"
  17. )
  18. type upnpNAT struct {
  19. serviceURL string
  20. ourIP string
  21. urnDomain string
  22. }
  23. // protocol is either "udp" or "tcp"
  24. type NAT interface {
  25. GetExternalAddress() (addr net.IP, err error)
  26. AddPortMapping(
  27. protocol string,
  28. externalPort,
  29. internalPort int,
  30. description string,
  31. timeout int) (mappedExternalPort int, err error)
  32. DeletePortMapping(protocol string, externalPort, internalPort int) (err error)
  33. }
  34. func Discover() (nat NAT, err error) {
  35. ssdp, err := net.ResolveUDPAddr("udp4", "239.255.255.250:1900")
  36. if err != nil {
  37. return
  38. }
  39. conn, err := net.ListenPacket("udp4", ":0")
  40. if err != nil {
  41. return
  42. }
  43. socket := conn.(*net.UDPConn)
  44. defer socket.Close() // nolint: errcheck
  45. if err := socket.SetDeadline(time.Now().Add(3 * time.Second)); err != nil {
  46. return nil, err
  47. }
  48. st := "InternetGatewayDevice:1"
  49. buf := bytes.NewBufferString(
  50. "M-SEARCH * HTTP/1.1\r\n" +
  51. "HOST: 239.255.255.250:1900\r\n" +
  52. "ST: ssdp:all\r\n" +
  53. "MAN: \"ssdp:discover\"\r\n" +
  54. "MX: 2\r\n\r\n")
  55. message := buf.Bytes()
  56. answerBytes := make([]byte, 1024)
  57. for i := 0; i < 3; i++ {
  58. _, err = socket.WriteToUDP(message, ssdp)
  59. if err != nil {
  60. return
  61. }
  62. var n int
  63. _, _, err = socket.ReadFromUDP(answerBytes)
  64. if err != nil {
  65. return
  66. }
  67. for {
  68. n, _, err = socket.ReadFromUDP(answerBytes)
  69. if err != nil {
  70. break
  71. }
  72. answer := string(answerBytes[0:n])
  73. if !strings.Contains(answer, st) {
  74. continue
  75. }
  76. // HTTP header field names are case-insensitive.
  77. // http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
  78. locString := "\r\nlocation:"
  79. answer = strings.ToLower(answer)
  80. locIndex := strings.Index(answer, locString)
  81. if locIndex < 0 {
  82. continue
  83. }
  84. loc := answer[locIndex+len(locString):]
  85. endIndex := strings.Index(loc, "\r\n")
  86. if endIndex < 0 {
  87. continue
  88. }
  89. locURL := strings.TrimSpace(loc[0:endIndex])
  90. var serviceURL, urnDomain string
  91. serviceURL, urnDomain, err = getServiceURL(locURL)
  92. if err != nil {
  93. return
  94. }
  95. var ourIP net.IP
  96. ourIP, err = localIPv4()
  97. if err != nil {
  98. return
  99. }
  100. nat = &upnpNAT{serviceURL: serviceURL, ourIP: ourIP.String(), urnDomain: urnDomain}
  101. return
  102. }
  103. }
  104. err = errors.New("upnp port discovery failed")
  105. return nat, err
  106. }
  107. type Envelope struct {
  108. XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Envelope"`
  109. Soap *SoapBody
  110. }
  111. type SoapBody struct {
  112. XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"`
  113. ExternalIP *ExternalIPAddressResponse
  114. }
  115. type ExternalIPAddressResponse struct {
  116. XMLName xml.Name `xml:"GetExternalIPAddressResponse"`
  117. IPAddress string `xml:"NewExternalIPAddress"`
  118. }
  119. type ExternalIPAddress struct {
  120. XMLName xml.Name `xml:"NewExternalIPAddress"`
  121. IP string
  122. }
  123. type UPNPService struct {
  124. ServiceType string `xml:"serviceType"`
  125. ControlURL string `xml:"controlURL"`
  126. }
  127. type DeviceList struct {
  128. Device []Device `xml:"device"`
  129. }
  130. type ServiceList struct {
  131. Service []UPNPService `xml:"service"`
  132. }
  133. type Device struct {
  134. XMLName xml.Name `xml:"device"`
  135. DeviceType string `xml:"deviceType"`
  136. DeviceList DeviceList `xml:"deviceList"`
  137. ServiceList ServiceList `xml:"serviceList"`
  138. }
  139. type Root struct {
  140. Device Device
  141. }
  142. func getChildDevice(d *Device, deviceType string) *Device {
  143. dl := d.DeviceList.Device
  144. for i := 0; i < len(dl); i++ {
  145. if strings.Contains(dl[i].DeviceType, deviceType) {
  146. return &dl[i]
  147. }
  148. }
  149. return nil
  150. }
  151. func getChildService(d *Device, serviceType string) *UPNPService {
  152. sl := d.ServiceList.Service
  153. for i := 0; i < len(sl); i++ {
  154. if strings.Contains(sl[i].ServiceType, serviceType) {
  155. return &sl[i]
  156. }
  157. }
  158. return nil
  159. }
  160. func localIPv4() (net.IP, error) {
  161. tt, err := net.Interfaces()
  162. if err != nil {
  163. return nil, err
  164. }
  165. for _, t := range tt {
  166. aa, err := t.Addrs()
  167. if err != nil {
  168. return nil, err
  169. }
  170. for _, a := range aa {
  171. ipnet, ok := a.(*net.IPNet)
  172. if !ok {
  173. continue
  174. }
  175. v4 := ipnet.IP.To4()
  176. if v4 == nil || v4[0] == 127 { // loopback address
  177. continue
  178. }
  179. return v4, nil
  180. }
  181. }
  182. return nil, errors.New("cannot find local IP address")
  183. }
  184. func getServiceURL(rootURL string) (url, urnDomain string, err error) {
  185. r, err := http.Get(rootURL) // nolint: gosec
  186. if err != nil {
  187. return
  188. }
  189. defer r.Body.Close() // nolint: errcheck
  190. if r.StatusCode >= 400 {
  191. err = errors.New(string(r.StatusCode))
  192. return
  193. }
  194. var root Root
  195. err = xml.NewDecoder(r.Body).Decode(&root)
  196. if err != nil {
  197. return
  198. }
  199. a := &root.Device
  200. if !strings.Contains(a.DeviceType, "InternetGatewayDevice:1") {
  201. err = errors.New("no InternetGatewayDevice")
  202. return
  203. }
  204. b := getChildDevice(a, "WANDevice:1")
  205. if b == nil {
  206. err = errors.New("no WANDevice")
  207. return
  208. }
  209. c := getChildDevice(b, "WANConnectionDevice:1")
  210. if c == nil {
  211. err = errors.New("no WANConnectionDevice")
  212. return
  213. }
  214. d := getChildService(c, "WANIPConnection:1")
  215. if d == nil {
  216. // Some routers don't follow the UPnP spec, and put WanIPConnection under WanDevice,
  217. // instead of under WanConnectionDevice
  218. d = getChildService(b, "WANIPConnection:1")
  219. if d == nil {
  220. err = errors.New("no WANIPConnection")
  221. return
  222. }
  223. }
  224. // Extract the domain name, which isn't always 'schemas-upnp-org'
  225. urnDomain = strings.Split(d.ServiceType, ":")[1]
  226. url = combineURL(rootURL, d.ControlURL)
  227. return url, urnDomain, err
  228. }
  229. func combineURL(rootURL, subURL string) string {
  230. protocolEnd := "://"
  231. protoEndIndex := strings.Index(rootURL, protocolEnd)
  232. a := rootURL[protoEndIndex+len(protocolEnd):]
  233. rootIndex := strings.Index(a, "/")
  234. return rootURL[0:protoEndIndex+len(protocolEnd)+rootIndex] + subURL
  235. }
  236. func soapRequest(url, function, message, domain string) (r *http.Response, err error) {
  237. fullMessage := "<?xml version=\"1.0\" ?>" +
  238. "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" " +
  239. "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n" +
  240. "<s:Body>" + message + "</s:Body></s:Envelope>"
  241. req, err := http.NewRequest("POST", url, strings.NewReader(fullMessage))
  242. if err != nil {
  243. return nil, err
  244. }
  245. req.Header.Set("Content-Type", "text/xml ; charset=\"utf-8\"")
  246. req.Header.Set("User-Agent", "Darwin/10.0.0, UPnP/1.0, MiniUPnPc/1.3")
  247. //req.Header.Set("Transfer-Encoding", "chunked")
  248. req.Header.Set("SOAPAction", "\"urn:"+domain+":service:WANIPConnection:1#"+function+"\"")
  249. req.Header.Set("Connection", "Close")
  250. req.Header.Set("Cache-Control", "no-cache")
  251. req.Header.Set("Pragma", "no-cache")
  252. // log.Stderr("soapRequest ", req)
  253. r, err = http.DefaultClient.Do(req)
  254. if err != nil {
  255. return nil, err
  256. }
  257. /*if r.Body != nil {
  258. defer r.Body.Close()
  259. }*/
  260. if r.StatusCode >= 400 {
  261. // log.Stderr(function, r.StatusCode)
  262. err = errors.New("error " + strconv.Itoa(r.StatusCode) + " for " + function)
  263. r = nil
  264. return
  265. }
  266. return r, err
  267. }
  268. type statusInfo struct {
  269. externalIPAddress string
  270. }
  271. func (n *upnpNAT) getExternalIPAddress() (info statusInfo, err error) {
  272. message := "<u:GetExternalIPAddress xmlns:u=\"urn:" + n.urnDomain + ":service:WANIPConnection:1\">\r\n" +
  273. "</u:GetExternalIPAddress>"
  274. var response *http.Response
  275. response, err = soapRequest(n.serviceURL, "GetExternalIPAddress", message, n.urnDomain)
  276. if response != nil {
  277. defer response.Body.Close() // nolint: errcheck
  278. }
  279. if err != nil {
  280. return
  281. }
  282. var envelope Envelope
  283. data, err := ioutil.ReadAll(response.Body)
  284. if err != nil {
  285. return
  286. }
  287. reader := bytes.NewReader(data)
  288. err = xml.NewDecoder(reader).Decode(&envelope)
  289. if err != nil {
  290. return
  291. }
  292. info = statusInfo{envelope.Soap.ExternalIP.IPAddress}
  293. if err != nil {
  294. return
  295. }
  296. return info, err
  297. }
  298. // GetExternalAddress returns an external IP. If GetExternalIPAddress action
  299. // fails or IP returned is invalid, GetExternalAddress returns an error.
  300. func (n *upnpNAT) GetExternalAddress() (addr net.IP, err error) {
  301. info, err := n.getExternalIPAddress()
  302. if err != nil {
  303. return
  304. }
  305. addr = net.ParseIP(info.externalIPAddress)
  306. if addr == nil {
  307. err = fmt.Errorf("failed to parse IP: %v", info.externalIPAddress)
  308. }
  309. return
  310. }
  311. func (n *upnpNAT) AddPortMapping(
  312. protocol string,
  313. externalPort,
  314. internalPort int,
  315. description string,
  316. timeout int) (mappedExternalPort int, err error) {
  317. // A single concatenation would break ARM compilation.
  318. message := "<u:AddPortMapping xmlns:u=\"urn:" + n.urnDomain + ":service:WANIPConnection:1\">\r\n" +
  319. "<NewRemoteHost></NewRemoteHost><NewExternalPort>" + strconv.Itoa(externalPort)
  320. message += "</NewExternalPort><NewProtocol>" + protocol + "</NewProtocol>"
  321. message += "<NewInternalPort>" + strconv.Itoa(internalPort) + "</NewInternalPort>" +
  322. "<NewInternalClient>" + n.ourIP + "</NewInternalClient>" +
  323. "<NewEnabled>1</NewEnabled><NewPortMappingDescription>"
  324. message += description +
  325. "</NewPortMappingDescription><NewLeaseDuration>" + strconv.Itoa(timeout) +
  326. "</NewLeaseDuration></u:AddPortMapping>"
  327. var response *http.Response
  328. response, err = soapRequest(n.serviceURL, "AddPortMapping", message, n.urnDomain)
  329. if response != nil {
  330. defer response.Body.Close() // nolint: errcheck
  331. }
  332. if err != nil {
  333. return
  334. }
  335. // TODO: check response to see if the port was forwarded
  336. // log.Println(message, response)
  337. // JAE:
  338. // body, err := ioutil.ReadAll(response.Body)
  339. // fmt.Println(string(body), err)
  340. mappedExternalPort = externalPort
  341. _ = response
  342. return
  343. }
  344. func (n *upnpNAT) DeletePortMapping(protocol string, externalPort, internalPort int) (err error) {
  345. message := "<u:DeletePortMapping xmlns:u=\"urn:" + n.urnDomain + ":service:WANIPConnection:1\">\r\n" +
  346. "<NewRemoteHost></NewRemoteHost><NewExternalPort>" + strconv.Itoa(externalPort) +
  347. "</NewExternalPort><NewProtocol>" + protocol + "</NewProtocol>" +
  348. "</u:DeletePortMapping>"
  349. var response *http.Response
  350. response, err = soapRequest(n.serviceURL, "DeletePortMapping", message, n.urnDomain)
  351. if response != nil {
  352. defer response.Body.Close() // nolint: errcheck
  353. }
  354. if err != nil {
  355. return
  356. }
  357. // TODO: check response to see if the port was deleted
  358. // log.Println(message, response)
  359. _ = response
  360. return
  361. }