urlv4_test.go 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. // Copyright 2018 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. package enode
  17. import (
  18. "crypto/ecdsa"
  19. "errors"
  20. "net"
  21. "reflect"
  22. "strings"
  23. "testing"
  24. "github.com/ethereum/go-ethereum/crypto"
  25. "github.com/ethereum/go-ethereum/p2p/enr"
  26. )
  27. func init() {
  28. lookupIPFunc = func(name string) ([]net.IP, error) {
  29. if name == "node.example.org" {
  30. return []net.IP{{33, 44, 55, 66}}, nil
  31. }
  32. return nil, errors.New("no such host")
  33. }
  34. }
  35. var parseNodeTests = []struct {
  36. input string
  37. wantError string
  38. wantResult *Node
  39. }{
  40. // Records
  41. {
  42. input: "enr:-IS4QGrdq0ugARp5T2BZ41TrZOqLc_oKvZoPuZP5--anqWE_J-Tucc1xgkOL7qXl0puJgT7qc2KSvcupc4NCb0nr4tdjgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQM6UUF2Rm-oFe1IH_rQkRCi00T2ybeMHRSvw1HDpRvjPYN1ZHCCdl8",
  43. wantResult: func() *Node {
  44. testKey, _ := crypto.HexToECDSA("45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8")
  45. var r enr.Record
  46. r.Set(enr.IP{127, 0, 0, 1})
  47. r.Set(enr.UDP(30303))
  48. r.SetSeq(99)
  49. SignV4(&r, testKey)
  50. n, _ := New(ValidSchemes, &r)
  51. return n
  52. }(),
  53. },
  54. // Invalid Records
  55. {
  56. input: "enr:",
  57. wantError: "EOF", // could be nicer
  58. },
  59. {
  60. input: "enr:x",
  61. wantError: "illegal base64 data at input byte 0",
  62. },
  63. {
  64. input: "enr:-EmGZm9vYmFyY4JpZIJ2NIJpcIR_AAABiXNlY3AyNTZrMaEDOlFBdkZvqBXtSB_60JEQotNE9sm3jB0Ur8NRw6Ub4z2DdWRwgnZf",
  65. wantError: enr.ErrInvalidSig.Error(),
  66. },
  67. // Complete node URLs with IP address and ports
  68. {
  69. input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@invalid.:3",
  70. wantError: `no such host`,
  71. },
  72. {
  73. input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:foo",
  74. wantError: `invalid port`,
  75. },
  76. {
  77. input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:3?discport=foo",
  78. wantError: `invalid discport in query`,
  79. },
  80. {
  81. input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150",
  82. wantResult: NewV4(
  83. hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
  84. net.IP{127, 0, 0, 1},
  85. 52150,
  86. 52150,
  87. ),
  88. },
  89. {
  90. input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[::]:52150",
  91. wantResult: NewV4(
  92. hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
  93. net.ParseIP("::"),
  94. 52150,
  95. 52150,
  96. ),
  97. },
  98. {
  99. input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[2001:db8:3c4d:15::abcd:ef12]:52150",
  100. wantResult: NewV4(
  101. hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
  102. net.ParseIP("2001:db8:3c4d:15::abcd:ef12"),
  103. 52150,
  104. 52150,
  105. ),
  106. },
  107. {
  108. input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150?discport=22334",
  109. wantResult: NewV4(
  110. hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
  111. net.IP{0x7f, 0x0, 0x0, 0x1},
  112. 52150,
  113. 22334,
  114. ),
  115. },
  116. // Incomplete node URLs with no address
  117. {
  118. input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439",
  119. wantResult: NewV4(
  120. hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
  121. nil, 0, 0,
  122. ),
  123. },
  124. // Invalid URLs
  125. {
  126. input: "",
  127. wantError: errMissingPrefix.Error(),
  128. },
  129. {
  130. input: "1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439",
  131. wantError: errMissingPrefix.Error(),
  132. },
  133. {
  134. input: "01010101",
  135. wantError: errMissingPrefix.Error(),
  136. },
  137. {
  138. input: "enode://01010101@123.124.125.126:3",
  139. wantError: `invalid public key (wrong length, want 128 hex chars)`,
  140. },
  141. {
  142. input: "enode://01010101",
  143. wantError: `invalid public key (wrong length, want 128 hex chars)`,
  144. },
  145. {
  146. input: "http://foobar",
  147. wantError: errMissingPrefix.Error(),
  148. },
  149. {
  150. input: "://foo",
  151. wantError: errMissingPrefix.Error(),
  152. },
  153. {
  154. // Quorum: raft url with invalid hostname (no error, hostname will be saved)
  155. input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@hostname:3?raftport=50401",
  156. wantResult: NewV4Hostname(hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), "hostname", 3, 3, 50401),
  157. },
  158. {
  159. // Quorum: raft url with valid hostname
  160. input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@localhost:3?raftport=50401",
  161. wantResult: NewV4Hostname(hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), "localhost", 3, 3, 50401),
  162. },
  163. {
  164. // Quorum: raft url with no hostname
  165. input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@:3?raftport=50401",
  166. wantError: `empty hostname in raft url`,
  167. },
  168. }
  169. func hexPubkey(h string) *ecdsa.PublicKey {
  170. k, err := parsePubkey(h)
  171. if err != nil {
  172. panic(err)
  173. }
  174. return k
  175. }
  176. func TestParseNode(t *testing.T) {
  177. for _, test := range parseNodeTests {
  178. n, err := Parse(ValidSchemes, test.input)
  179. if test.wantError != "" {
  180. if err == nil {
  181. t.Errorf("test %q:\n got nil error, expected %#q", test.input, test.wantError)
  182. continue
  183. } else if !strings.Contains(err.Error(), test.wantError) {
  184. t.Errorf("test %q:\n got error %#q, expected %#q", test.input, err.Error(), test.wantError)
  185. continue
  186. }
  187. } else {
  188. if err != nil {
  189. t.Errorf("test %q:\n unexpected error: %v", test.input, err)
  190. continue
  191. }
  192. if !reflect.DeepEqual(n, test.wantResult) {
  193. t.Errorf("test %q:\n result mismatch:\ngot: %#v\nwant: %#v", test.input, n, test.wantResult)
  194. }
  195. }
  196. }
  197. }
  198. func TestNodeString(t *testing.T) {
  199. for i, test := range parseNodeTests {
  200. if test.wantError == "" && strings.HasPrefix(test.input, "enode://") {
  201. str := test.wantResult.String()
  202. if str != test.input {
  203. t.Errorf("test %d: Node.String() mismatch:\ngot: %s\nwant: %s", i, str, test.input)
  204. }
  205. }
  206. }
  207. }