resolvconf_unix_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. //go:build !windows
  2. // +build !windows
  3. package resolvconf
  4. import (
  5. "bytes"
  6. "os"
  7. "testing"
  8. )
  9. func TestGet(t *testing.T) {
  10. actual, err := Get()
  11. if err != nil {
  12. t.Fatal(err)
  13. }
  14. expected, err := os.ReadFile(Path())
  15. if err != nil {
  16. t.Fatal(err)
  17. }
  18. if !bytes.Equal(actual.Content, expected) {
  19. t.Errorf("%s and GetResolvConf have different content.", Path())
  20. }
  21. if !bytes.Equal(actual.Hash, hashData(expected)) {
  22. t.Errorf("%s and GetResolvConf have different hashes.", Path())
  23. }
  24. }
  25. func TestGetNameservers(t *testing.T) {
  26. for _, tc := range []struct {
  27. input string
  28. result []string
  29. }{
  30. {
  31. input: ``,
  32. },
  33. {
  34. input: `search example.com`,
  35. },
  36. {
  37. input: ` nameserver 1.2.3.4 `,
  38. result: []string{"1.2.3.4"},
  39. },
  40. {
  41. input: `
  42. nameserver 1.2.3.4
  43. nameserver 40.3.200.10
  44. search example.com`,
  45. result: []string{"1.2.3.4", "40.3.200.10"},
  46. },
  47. {
  48. input: `nameserver 1.2.3.4
  49. search example.com
  50. nameserver 4.30.20.100`,
  51. result: []string{"1.2.3.4", "4.30.20.100"},
  52. },
  53. {
  54. input: `search example.com
  55. nameserver 1.2.3.4
  56. #nameserver 4.3.2.1`,
  57. result: []string{"1.2.3.4"},
  58. },
  59. {
  60. input: `search example.com
  61. nameserver 1.2.3.4 # not 4.3.2.1`,
  62. result: []string{"1.2.3.4"},
  63. },
  64. } {
  65. test := GetNameservers([]byte(tc.input), IP)
  66. if !strSlicesEqual(test, tc.result) {
  67. t.Errorf("Wrong nameserver string {%s} should be %v. Input: %s", test, tc.result, tc.input)
  68. }
  69. }
  70. }
  71. func TestGetNameserversAsCIDR(t *testing.T) {
  72. for _, tc := range []struct {
  73. input string
  74. result []string
  75. }{
  76. {
  77. input: ``,
  78. },
  79. {
  80. input: `search example.com`,
  81. },
  82. {
  83. input: ` nameserver 1.2.3.4 `,
  84. result: []string{"1.2.3.4/32"},
  85. },
  86. {
  87. input: `
  88. nameserver 1.2.3.4
  89. nameserver 40.3.200.10
  90. search example.com`,
  91. result: []string{"1.2.3.4/32", "40.3.200.10/32"},
  92. },
  93. {
  94. input: `nameserver 1.2.3.4
  95. search example.com
  96. nameserver 4.30.20.100`,
  97. result: []string{"1.2.3.4/32", "4.30.20.100/32"},
  98. },
  99. {
  100. input: `search example.com
  101. nameserver 1.2.3.4
  102. #nameserver 4.3.2.1`,
  103. result: []string{"1.2.3.4/32"},
  104. },
  105. {
  106. input: `search example.com
  107. nameserver 1.2.3.4 # not 4.3.2.1`,
  108. result: []string{"1.2.3.4/32"},
  109. },
  110. } {
  111. test := GetNameserversAsCIDR([]byte(tc.input))
  112. if !strSlicesEqual(test, tc.result) {
  113. t.Errorf("Wrong nameserver string {%s} should be %v. Input: %s", test, tc.result, tc.input)
  114. }
  115. }
  116. }
  117. func TestGetSearchDomains(t *testing.T) {
  118. for _, tc := range []struct {
  119. input string
  120. result []string
  121. }{
  122. {
  123. input: ``,
  124. },
  125. {
  126. input: `# ignored`,
  127. },
  128. {
  129. input: `search example.com`,
  130. result: []string{"example.com"},
  131. },
  132. {
  133. input: `search example.com # ignored`,
  134. result: []string{"example.com"},
  135. },
  136. {
  137. input: ` search example.com `,
  138. result: []string{"example.com"},
  139. },
  140. {
  141. input: ` search example.com # ignored`,
  142. result: []string{"example.com"},
  143. },
  144. {
  145. input: `search foo.example.com example.com`,
  146. result: []string{"foo.example.com", "example.com"},
  147. },
  148. {
  149. input: ` search foo.example.com example.com `,
  150. result: []string{"foo.example.com", "example.com"},
  151. },
  152. {
  153. input: ` search foo.example.com example.com # ignored`,
  154. result: []string{"foo.example.com", "example.com"},
  155. },
  156. {
  157. input: `nameserver 1.2.3.4
  158. search foo.example.com example.com`,
  159. result: []string{"foo.example.com", "example.com"},
  160. },
  161. {
  162. input: `nameserver 1.2.3.4
  163. search dup1.example.com dup2.example.com
  164. search foo.example.com example.com`,
  165. result: []string{"foo.example.com", "example.com"},
  166. },
  167. {
  168. input: `nameserver 1.2.3.4
  169. search foo.example.com example.com
  170. nameserver 4.30.20.100`,
  171. result: []string{"foo.example.com", "example.com"},
  172. },
  173. } {
  174. test := GetSearchDomains([]byte(tc.input))
  175. if !strSlicesEqual(test, tc.result) {
  176. t.Errorf("Wrong search domain string {%s} should be %v. Input: %s", test, tc.result, tc.input)
  177. }
  178. }
  179. }
  180. func TestGetOptions(t *testing.T) {
  181. for _, tc := range []struct {
  182. input string
  183. result []string
  184. }{
  185. {
  186. input: ``,
  187. },
  188. {
  189. input: `# ignored`,
  190. },
  191. {
  192. input: `nameserver 1.2.3.4`,
  193. },
  194. {
  195. input: `options opt1`,
  196. result: []string{"opt1"},
  197. },
  198. {
  199. input: `options opt1 # ignored`,
  200. result: []string{"opt1"},
  201. },
  202. {
  203. input: ` options opt1 `,
  204. result: []string{"opt1"},
  205. },
  206. {
  207. input: ` options opt1 # ignored`,
  208. result: []string{"opt1"},
  209. },
  210. {
  211. input: `options opt1 opt2 opt3`,
  212. result: []string{"opt1", "opt2", "opt3"},
  213. },
  214. {
  215. input: `options opt1 opt2 opt3 # ignored`,
  216. result: []string{"opt1", "opt2", "opt3"},
  217. },
  218. {
  219. input: ` options opt1 opt2 opt3 `,
  220. result: []string{"opt1", "opt2", "opt3"},
  221. },
  222. {
  223. input: ` options opt1 opt2 opt3 # ignored`,
  224. result: []string{"opt1", "opt2", "opt3"},
  225. },
  226. {
  227. input: `nameserver 1.2.3.4
  228. options opt1 opt2 opt3`,
  229. result: []string{"opt1", "opt2", "opt3"},
  230. },
  231. {
  232. input: `nameserver 1.2.3.4
  233. options opt1 opt2
  234. options opt3 opt4`,
  235. result: []string{"opt3", "opt4"},
  236. },
  237. } {
  238. test := GetOptions([]byte(tc.input))
  239. if !strSlicesEqual(test, tc.result) {
  240. t.Errorf("Wrong options string {%s} should be %v. Input: %s", test, tc.result, tc.input)
  241. }
  242. }
  243. }
  244. func strSlicesEqual(a, b []string) bool {
  245. if len(a) != len(b) {
  246. return false
  247. }
  248. for i, v := range a {
  249. if v != b[i] {
  250. return false
  251. }
  252. }
  253. return true
  254. }
  255. func TestBuild(t *testing.T) {
  256. tmpDir := t.TempDir()
  257. file, err := os.CreateTemp(tmpDir, "")
  258. if err != nil {
  259. t.Fatal(err)
  260. }
  261. _, err = Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"search1"}, []string{"opt1"})
  262. if err != nil {
  263. t.Fatal(err)
  264. }
  265. content, err := os.ReadFile(file.Name())
  266. if err != nil {
  267. t.Fatal(err)
  268. }
  269. if expected := "search search1\nnameserver ns1\nnameserver ns2\nnameserver ns3\noptions opt1\n"; !bytes.Contains(content, []byte(expected)) {
  270. t.Errorf("Expected to find '%s' got '%s'", expected, content)
  271. }
  272. }
  273. func TestBuildWithZeroLengthDomainSearch(t *testing.T) {
  274. tmpDir := t.TempDir()
  275. file, err := os.CreateTemp(tmpDir, "")
  276. if err != nil {
  277. t.Fatal(err)
  278. }
  279. _, err = Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"."}, []string{"opt1"})
  280. if err != nil {
  281. t.Fatal(err)
  282. }
  283. content, err := os.ReadFile(file.Name())
  284. if err != nil {
  285. t.Fatal(err)
  286. }
  287. if expected := "nameserver ns1\nnameserver ns2\nnameserver ns3\noptions opt1\n"; !bytes.Contains(content, []byte(expected)) {
  288. t.Errorf("Expected to find '%s' got '%s'", expected, content)
  289. }
  290. if notExpected := "search ."; bytes.Contains(content, []byte(notExpected)) {
  291. t.Errorf("Expected to not find '%s' got '%s'", notExpected, content)
  292. }
  293. }
  294. func TestBuildWithNoOptions(t *testing.T) {
  295. tmpDir := t.TempDir()
  296. file, err := os.CreateTemp(tmpDir, "")
  297. if err != nil {
  298. t.Fatal(err)
  299. }
  300. _, err = Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"search1"}, []string{})
  301. if err != nil {
  302. t.Fatal(err)
  303. }
  304. content, err := os.ReadFile(file.Name())
  305. if err != nil {
  306. t.Fatal(err)
  307. }
  308. if expected := "search search1\nnameserver ns1\nnameserver ns2\nnameserver ns3\n"; !bytes.Contains(content, []byte(expected)) {
  309. t.Errorf("Expected to find '%s' got '%s'", expected, content)
  310. }
  311. if notExpected := "search ."; bytes.Contains(content, []byte(notExpected)) {
  312. t.Errorf("Expected to not find '%s' got '%s'", notExpected, content)
  313. }
  314. }
  315. func TestFilterResolvDNS(t *testing.T) {
  316. ns0 := "nameserver 10.16.60.14\nnameserver 10.16.60.21\n"
  317. if result, _ := FilterResolvDNS([]byte(ns0), false); result != nil {
  318. if ns0 != string(result.Content) {
  319. t.Errorf("Failed No Localhost: expected \n<%s> got \n<%s>", ns0, string(result.Content))
  320. }
  321. }
  322. ns1 := "nameserver 10.16.60.14\nnameserver 10.16.60.21\nnameserver 127.0.0.1\n"
  323. if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil {
  324. if ns0 != string(result.Content) {
  325. t.Errorf("Failed Localhost: expected \n<%s> got \n<%s>", ns0, string(result.Content))
  326. }
  327. }
  328. ns1 = "nameserver 10.16.60.14\nnameserver 127.0.0.1\nnameserver 10.16.60.21\n"
  329. if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil {
  330. if ns0 != string(result.Content) {
  331. t.Errorf("Failed Localhost: expected \n<%s> got \n<%s>", ns0, string(result.Content))
  332. }
  333. }
  334. ns1 = "nameserver 127.0.1.1\nnameserver 10.16.60.14\nnameserver 10.16.60.21\n"
  335. if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil {
  336. if ns0 != string(result.Content) {
  337. t.Errorf("Failed Localhost: expected \n<%s> got \n<%s>", ns0, string(result.Content))
  338. }
  339. }
  340. ns1 = "nameserver ::1\nnameserver 10.16.60.14\nnameserver 127.0.2.1\nnameserver 10.16.60.21\n"
  341. if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil {
  342. if ns0 != string(result.Content) {
  343. t.Errorf("Failed Localhost: expected \n<%s> got \n<%s>", ns0, string(result.Content))
  344. }
  345. }
  346. ns1 = "nameserver 10.16.60.14\nnameserver ::1\nnameserver 10.16.60.21\nnameserver ::1"
  347. if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil {
  348. if ns0 != string(result.Content) {
  349. t.Errorf("Failed Localhost: expected \n<%s> got \n<%s>", ns0, string(result.Content))
  350. }
  351. }
  352. // with IPv6 disabled (false param), the IPv6 nameserver should be removed
  353. ns1 = "nameserver 10.16.60.14\nnameserver 2002:dead:beef::1\nnameserver 10.16.60.21\nnameserver ::1"
  354. if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil {
  355. if ns0 != string(result.Content) {
  356. t.Errorf("Failed Localhost+IPv6 off: expected \n<%s> got \n<%s>", ns0, string(result.Content))
  357. }
  358. }
  359. // with IPv6 disabled (false param), the IPv6 link-local nameserver with zone ID should be removed
  360. ns1 = "nameserver 10.16.60.14\nnameserver FE80::BB1%1\nnameserver FE80::BB1%eth0\nnameserver 10.16.60.21\n"
  361. if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil {
  362. if ns0 != string(result.Content) {
  363. t.Errorf("Failed Localhost+IPv6 off: expected \n<%s> got \n<%s>", ns0, string(result.Content))
  364. }
  365. }
  366. // with IPv6 enabled, the IPv6 nameserver should be preserved
  367. ns0 = "nameserver 10.16.60.14\nnameserver 2002:dead:beef::1\nnameserver 10.16.60.21\n"
  368. ns1 = "nameserver 10.16.60.14\nnameserver 2002:dead:beef::1\nnameserver 10.16.60.21\nnameserver ::1"
  369. if result, _ := FilterResolvDNS([]byte(ns1), true); result != nil {
  370. if ns0 != string(result.Content) {
  371. t.Errorf("Failed Localhost+IPv6 on: expected \n<%s> got \n<%s>", ns0, string(result.Content))
  372. }
  373. }
  374. // with IPv6 enabled, and no non-localhost servers, Google defaults (both IPv4+IPv6) should be added
  375. ns0 = "\nnameserver 8.8.8.8\nnameserver 8.8.4.4\nnameserver 2001:4860:4860::8888\nnameserver 2001:4860:4860::8844"
  376. ns1 = "nameserver 127.0.0.1\nnameserver ::1\nnameserver 127.0.2.1"
  377. if result, _ := FilterResolvDNS([]byte(ns1), true); result != nil {
  378. if ns0 != string(result.Content) {
  379. t.Errorf("Failed no Localhost+IPv6 enabled: expected \n<%s> got \n<%s>", ns0, string(result.Content))
  380. }
  381. }
  382. // with IPv6 disabled, and no non-localhost servers, Google defaults (only IPv4) should be added
  383. ns0 = "\nnameserver 8.8.8.8\nnameserver 8.8.4.4"
  384. ns1 = "nameserver 127.0.0.1\nnameserver ::1\nnameserver 127.0.2.1"
  385. if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil {
  386. if ns0 != string(result.Content) {
  387. t.Errorf("Failed no Localhost+IPv6 enabled: expected \n<%s> got \n<%s>", ns0, string(result.Content))
  388. }
  389. }
  390. }