resolvconf_unix_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  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. f, err := Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"search1"}, []string{"opt1"})
  262. if err != nil {
  263. t.Fatal(err)
  264. }
  265. const expected = "search search1\nnameserver ns1\nnameserver ns2\nnameserver ns3\noptions opt1\n"
  266. if !bytes.Equal(f.Content, []byte(expected)) {
  267. t.Errorf("Expected to find '%s' got '%s'", expected, f.Content)
  268. }
  269. content, err := os.ReadFile(file.Name())
  270. if err != nil {
  271. t.Fatal(err)
  272. }
  273. if !bytes.Equal(content, []byte(expected)) {
  274. t.Errorf("Expected to find '%s' got '%s'", expected, content)
  275. }
  276. }
  277. func TestBuildWithZeroLengthDomainSearch(t *testing.T) {
  278. tmpDir := t.TempDir()
  279. file, err := os.CreateTemp(tmpDir, "")
  280. if err != nil {
  281. t.Fatal(err)
  282. }
  283. f, err := Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"."}, []string{"opt1"})
  284. if err != nil {
  285. t.Fatal(err)
  286. }
  287. const expected = "nameserver ns1\nnameserver ns2\nnameserver ns3\noptions opt1\n"
  288. if !bytes.Equal(f.Content, []byte(expected)) {
  289. t.Errorf("Expected to find '%s' got '%s'", expected, f.Content)
  290. }
  291. content, err := os.ReadFile(file.Name())
  292. if err != nil {
  293. t.Fatal(err)
  294. }
  295. if !bytes.Equal(content, []byte(expected)) {
  296. t.Errorf("Expected to find '%s' got '%s'", expected, content)
  297. }
  298. }
  299. func TestBuildWithNoOptions(t *testing.T) {
  300. tmpDir := t.TempDir()
  301. file, err := os.CreateTemp(tmpDir, "")
  302. if err != nil {
  303. t.Fatal(err)
  304. }
  305. f, err := Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"search1"}, []string{})
  306. if err != nil {
  307. t.Fatal(err)
  308. }
  309. const expected = "search search1\nnameserver ns1\nnameserver ns2\nnameserver ns3\n"
  310. if !bytes.Equal(f.Content, []byte(expected)) {
  311. t.Errorf("Expected to find '%s' got '%s'", expected, f.Content)
  312. }
  313. content, err := os.ReadFile(file.Name())
  314. if err != nil {
  315. t.Fatal(err)
  316. }
  317. if !bytes.Equal(content, []byte(expected)) {
  318. t.Errorf("Expected to find '%s' got '%s'", expected, content)
  319. }
  320. }
  321. func TestFilterResolvDNS(t *testing.T) {
  322. ns0 := "nameserver 10.16.60.14\nnameserver 10.16.60.21\n"
  323. if result, _ := FilterResolvDNS([]byte(ns0), false); result != nil {
  324. if ns0 != string(result.Content) {
  325. t.Errorf("Failed No Localhost: expected \n<%s> got \n<%s>", ns0, string(result.Content))
  326. }
  327. }
  328. ns1 := "nameserver 10.16.60.14\nnameserver 10.16.60.21\nnameserver 127.0.0.1\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 10.16.60.14\nnameserver 127.0.0.1\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 127.0.1.1\nnameserver 10.16.60.14\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 ::1\nnameserver 10.16.60.14\nnameserver 127.0.2.1\nnameserver 10.16.60.21\n"
  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. ns1 = "nameserver 10.16.60.14\nnameserver ::1\nnameserver 10.16.60.21\nnameserver ::1"
  353. if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil {
  354. if ns0 != string(result.Content) {
  355. t.Errorf("Failed Localhost: expected \n<%s> got \n<%s>", ns0, string(result.Content))
  356. }
  357. }
  358. // with IPv6 disabled (false param), the IPv6 nameserver should be removed
  359. ns1 = "nameserver 10.16.60.14\nnameserver 2002:dead:beef::1\nnameserver 10.16.60.21\nnameserver ::1"
  360. if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil {
  361. if ns0 != string(result.Content) {
  362. t.Errorf("Failed Localhost+IPv6 off: expected \n<%s> got \n<%s>", ns0, string(result.Content))
  363. }
  364. }
  365. // with IPv6 disabled (false param), the IPv6 link-local nameserver with zone ID should be removed
  366. ns1 = "nameserver 10.16.60.14\nnameserver FE80::BB1%1\nnameserver FE80::BB1%eth0\nnameserver 10.16.60.21\n"
  367. if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil {
  368. if ns0 != string(result.Content) {
  369. t.Errorf("Failed Localhost+IPv6 off: expected \n<%s> got \n<%s>", ns0, string(result.Content))
  370. }
  371. }
  372. // with IPv6 enabled, the IPv6 nameserver should be preserved
  373. ns0 = "nameserver 10.16.60.14\nnameserver 2002:dead:beef::1\nnameserver 10.16.60.21\n"
  374. ns1 = "nameserver 10.16.60.14\nnameserver 2002:dead:beef::1\nnameserver 10.16.60.21\nnameserver ::1"
  375. if result, _ := FilterResolvDNS([]byte(ns1), true); result != nil {
  376. if ns0 != string(result.Content) {
  377. t.Errorf("Failed Localhost+IPv6 on: expected \n<%s> got \n<%s>", ns0, string(result.Content))
  378. }
  379. }
  380. // with IPv6 enabled, and no non-localhost servers, Google defaults (both IPv4+IPv6) should be added
  381. ns0 = "\nnameserver 8.8.8.8\nnameserver 8.8.4.4\nnameserver 2001:4860:4860::8888\nnameserver 2001:4860:4860::8844"
  382. ns1 = "nameserver 127.0.0.1\nnameserver ::1\nnameserver 127.0.2.1"
  383. if result, _ := FilterResolvDNS([]byte(ns1), true); result != nil {
  384. if ns0 != string(result.Content) {
  385. t.Errorf("Failed no Localhost+IPv6 enabled: expected \n<%s> got \n<%s>", ns0, string(result.Content))
  386. }
  387. }
  388. // with IPv6 disabled, and no non-localhost servers, Google defaults (only IPv4) should be added
  389. ns0 = "\nnameserver 8.8.8.8\nnameserver 8.8.4.4"
  390. ns1 = "nameserver 127.0.0.1\nnameserver ::1\nnameserver 127.0.2.1"
  391. if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil {
  392. if ns0 != string(result.Content) {
  393. t.Errorf("Failed no Localhost+IPv6 enabled: expected \n<%s> got \n<%s>", ns0, string(result.Content))
  394. }
  395. }
  396. }