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.

608 lines
15 KiB

  1. #!/bin/sh
  2. ##############################################################################
  3. #
  4. # This program is free software; you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License version 2 as
  6. # published by the Free Software Foundation.
  7. #
  8. # This program is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. #
  13. # Copyright (C) 2016 Eric Luehrsen
  14. #
  15. ##############################################################################
  16. #
  17. # This builds the basic UCI components currently supported for Unbound. It is
  18. # intentionally NOT comprehensive and bundles a lot of options. The UCI is to
  19. # be a simpler presentation of the total Unbound conf set.
  20. #
  21. ##############################################################################
  22. UNBOUND_B_CONTROL=0
  23. UNBOUND_B_DNSMASQ=0
  24. UNBOUND_B_DNSSEC=0
  25. UNBOUND_B_DNS64=0
  26. UNBOUND_B_GATE_NAME=0
  27. UNBOUND_B_HIDE_BIND=1
  28. UNBOUND_B_LOCL_BLCK=0
  29. UNBOUND_B_LOCL_NAME=0
  30. UNBOUND_B_LOCL_SERV=1
  31. UNBOUND_B_MAN_CONF=0
  32. UNBOUND_B_NTP_BOOT=1
  33. UNBOUND_B_PRIV_BLCK=1
  34. UNBOUND_B_QUERY_MIN=0
  35. UNBOUND_B_QRY_MINST=0
  36. UNBOUND_IP_DNS64="64:ff9b::/96"
  37. UNBOUND_D_RESOURCE=small
  38. UNBOUND_D_RECURSION=passive
  39. UNBOUND_D_PROTOCOL=mixed
  40. UNBOUND_TXT_FWD_ZONE=""
  41. UNBOUND_TTL_MIN=120
  42. UNBOUND_N_EDNS_SIZE=1280
  43. UNBOUND_N_FWD_PORTS=""
  44. UNBOUND_N_RX_PORT=53
  45. UNBOUND_N_ROOT_AGE=28
  46. ##############################################################################
  47. UNBOUND_ANCHOR=/usr/bin/unbound-anchor
  48. UNBOUND_CONTROL=/usr/bin/unbound-control
  49. UNBOUND_LIBDIR=/usr/lib/unbound
  50. UNBOUND_PIDFILE=/var/run/unbound.pid
  51. UNBOUND_VARDIR=/var/lib/unbound
  52. UNBOUND_CONFFILE=$UNBOUND_VARDIR/unbound.conf
  53. UNBOUND_KEYFILE=$UNBOUND_VARDIR/root.key
  54. UNBOUND_HINTFILE=$UNBOUND_VARDIR/root.hints
  55. UNBOUND_TIMEFILE=$UNBOUND_VARDIR/unbound.time
  56. UNBOUND_CHECKFILE=$UNBOUND_VARDIR/unbound.check
  57. ##############################################################################
  58. . /lib/functions.sh
  59. . /lib/functions/network.sh
  60. . $UNBOUND_LIBDIR/dnsmasq.sh
  61. . $UNBOUND_LIBDIR/iptools.sh
  62. . $UNBOUND_LIBDIR/rootzone.sh
  63. ##############################################################################
  64. create_access_control() {
  65. local cfg="$1"
  66. local subnets subnets4 subnets6
  67. local validip4 validip6
  68. network_get_subnets subnets4 "$cfg"
  69. network_get_subnets6 subnets6 "$cfg"
  70. subnets="$subnets4 $subnets6"
  71. if [ -n "$subnets" ] ; then
  72. for subnet in $subnets ; do
  73. validip4=$( valid_subnet4 $subnet )
  74. validip6=$( valid_subnet6 $subnet )
  75. if [ "$validip4" = "ok" -o "$validip6" = "ok" ] ; then
  76. # For each "network" UCI add "access-control:" white list for queries
  77. echo " access-control: $subnet allow" >> $UNBOUND_CONFFILE
  78. fi
  79. done
  80. fi
  81. }
  82. ##############################################################################
  83. create_domain_insecure() {
  84. echo " domain-insecure: \"$1\"" >> $UNBOUND_CONFFILE
  85. }
  86. ##############################################################################
  87. unbound_mkdir() {
  88. mkdir -p $UNBOUND_VARDIR
  89. touch $UNBOUND_CONFFILE
  90. if [ -f /etc/unbound/root.hints ] ; then
  91. # Your own local copy of root.hints
  92. cp -p /etc/unbound/root.hints $UNBOUND_HINTFILE
  93. elif [ -f /usr/share/dns/root.hints ] ; then
  94. # Debian-like package dns-root-data
  95. cp -p /usr/share/dns/root.hints $UNBOUND_HINTFILE
  96. else
  97. logger -t unbound -s "iterator will use built-in root hints"
  98. fi
  99. if [ -f /etc/unbound/root.key ] ; then
  100. # Your own local copy of a root.key
  101. cp -p /etc/unbound/root.key $UNBOUND_KEYFILE
  102. elif [ -f /usr/share/dns/root.key ] ; then
  103. # Debian-like package dns-root-data
  104. cp -p /usr/share/dns/root.key $UNBOUND_KEYFILE
  105. elif [ -x "$UNBOUND_ANCHOR" ] ; then
  106. $UNBOUND_ANCHOR -a $UNBOUND_KEYFILE
  107. else
  108. logger -t unbound -s "validator will use built-in trust anchor"
  109. fi
  110. }
  111. ##############################################################################
  112. unbound_conf() {
  113. local cfg=$1
  114. local rt_mem rt_conn modulestring
  115. {
  116. # Make fresh conf file
  117. echo "# $UNBOUND_CONFFILE generated by UCI $( date )"
  118. echo
  119. } > $UNBOUND_CONFFILE
  120. if [ "$UNBOUND_B_CONTROL" -gt 0 ] ; then
  121. {
  122. # Enable remote control tool, but only at local host for security
  123. echo "remote-control:"
  124. echo " control-enable: yes"
  125. echo " control-use-cert: no"
  126. echo " control-interface: 127.0.0.1"
  127. echo " control-interface: ::1"
  128. echo
  129. } >> $UNBOUND_CONFFILE
  130. else
  131. {
  132. # "control:" clause is seperate before "server:" so we can append
  133. # dnsmasq "server:" parts and "forward:" cluases towards the end.
  134. echo "remote-control:"
  135. echo " control-enable: no"
  136. echo
  137. } >> $UNBOUND_CONFFILE
  138. fi
  139. {
  140. # No threading
  141. echo "server:"
  142. echo " username: unbound"
  143. echo " num-threads: 1"
  144. echo " msg-cache-slabs: 1"
  145. echo " rrset-cache-slabs: 1"
  146. echo " infra-cache-slabs: 1"
  147. echo " key-cache-slabs: 1"
  148. echo
  149. } >> $UNBOUND_CONFFILE
  150. {
  151. # Logging
  152. echo " verbosity: 1"
  153. echo " statistics-interval: 0"
  154. echo " statistics-cumulative: no"
  155. echo " extended-statistics: no"
  156. echo
  157. } >> $UNBOUND_CONFFILE
  158. {
  159. # Interfaces (access contol "option local_service")
  160. echo " interface: 0.0.0.0"
  161. echo " interface: ::0"
  162. echo " outgoing-interface: 0.0.0.0"
  163. echo " outgoing-interface: ::0"
  164. echo
  165. } >> $UNBOUND_CONFFILE
  166. case "$UNBOUND_D_PROTOCOL" in
  167. ip4_only)
  168. {
  169. echo " do-ip4: yes"
  170. echo " do-ip6: no"
  171. } >> $UNBOUND_CONFFILE
  172. ;;
  173. ip6_only)
  174. {
  175. echo " do-ip4: no"
  176. echo " do-ip6: yes"
  177. } >> $UNBOUND_CONFFILE
  178. ;;
  179. ip6_prefer)
  180. {
  181. echo " do-ip4: yes"
  182. echo " do-ip6: yes"
  183. echo " prefer-ip6: yes"
  184. } >> $UNBOUND_CONFFILE
  185. ;;
  186. *)
  187. {
  188. echo " do-ip4: yes"
  189. echo " do-ip6: yes"
  190. } >> $UNBOUND_CONFFILE
  191. ;;
  192. esac
  193. {
  194. # protocol level tuning
  195. echo " edns-buffer-size: $UNBOUND_N_EDNS_SIZE"
  196. echo " msg-buffer-size: 8192"
  197. echo " port: $UNBOUND_N_RX_PORT"
  198. echo " outgoing-port-permit: 10240-65535"
  199. echo
  200. } >> $UNBOUND_CONFFILE
  201. {
  202. # Other harding and options for an embedded router
  203. echo " harden-short-bufsize: yes"
  204. echo " harden-large-queries: yes"
  205. echo " harden-glue: yes"
  206. echo " harden-below-nxdomain: no"
  207. echo " harden-referral-path: no"
  208. echo " use-caps-for-id: no"
  209. echo
  210. } >> $UNBOUND_CONFFILE
  211. {
  212. # Default Files
  213. echo " use-syslog: yes"
  214. echo " chroot: \"$UNBOUND_VARDIR\""
  215. echo " directory: \"$UNBOUND_VARDIR\""
  216. echo " pidfile: \"$UNBOUND_PIDFILE\""
  217. } >> $UNBOUND_CONFFILE
  218. if [ -f "$UNBOUND_HINTFILE" ] ; then
  219. # Optional hints if found
  220. echo " root-hints: \"$UNBOUND_HINTFILE\"" >> $UNBOUND_CONFFILE
  221. fi
  222. if [ "$UNBOUND_B_DNSSEC" -gt 0 -a -f "$UNBOUND_KEYFILE" ] ; then
  223. {
  224. echo " auto-trust-anchor-file: \"$UNBOUND_KEYFILE\""
  225. echo
  226. } >> $UNBOUND_CONFFILE
  227. else
  228. echo >> $UNBOUND_CONFFILE
  229. fi
  230. case "$UNBOUND_D_RESOURCE" in
  231. # Tiny - Unbound's recommended cheap hardware config
  232. tiny) rt_mem=1 ; rt_conn=1 ;;
  233. # Small - Half RRCACHE and open ports
  234. small) rt_mem=8 ; rt_conn=5 ;;
  235. # Medium - Nearly default but with some added balancintg
  236. medium) rt_mem=16 ; rt_conn=10 ;;
  237. # Large - Double medium
  238. large) rt_mem=32 ; rt_conn=10 ;;
  239. # Whatever unbound does
  240. *) rt_mem=0 ; rt_conn=0 ;;
  241. esac
  242. if [ "$rt_mem" -gt 0 ] ; then
  243. {
  244. # Set memory sizing parameters
  245. echo " outgoing-range: $(($rt_conn*64))"
  246. echo " num-queries-per-thread: $(($rt_conn*32))"
  247. echo " outgoing-num-tcp: $(($rt_conn))"
  248. echo " incoming-num-tcp: $(($rt_conn))"
  249. echo " rrset-cache-size: $(($rt_mem*256))k"
  250. echo " msg-cache-size: $(($rt_mem*128))k"
  251. echo " key-cache-size: $(($rt_mem*128))k"
  252. echo " neg-cache-size: $(($rt_mem*64))k"
  253. echo " infra-cache-numhosts: $(($rt_mem*256))"
  254. echo
  255. } >> $UNBOUND_CONFFILE
  256. else
  257. logger -t unbound -s "default memory resource consumption"
  258. fi
  259. # Assembly of module-config: options is tricky; order matters
  260. modulestring="iterator"
  261. if [ "$UNBOUND_B_DNSSEC" -gt 0 ] ; then
  262. if [ ! -f "$UNBOUND_TIMEFILE" -a "$UNBOUND_B_NTP_BOOT" -gt 0 ] ; then
  263. # DNSSEC chicken and egg with getting NTP time
  264. echo " val-override-date: -1" >> $UNBOUND_CONFFILE
  265. fi
  266. {
  267. echo " harden-dnssec-stripped: yes"
  268. echo " val-clean-additional: yes"
  269. echo " ignore-cd-flag: yes"
  270. } >> $UNBOUND_CONFFILE
  271. modulestring="validator $modulestring"
  272. fi
  273. if [ "$UNBOUND_B_DNS64" -gt 0 ] ; then
  274. echo " dns64-prefix: $UNBOUND_IP_DNS64" >> $UNBOUND_CONFFILE
  275. modulestring="dns64 $modulestring"
  276. fi
  277. {
  278. # Print final module string
  279. echo " module-config: \"$modulestring\""
  280. echo
  281. } >> $UNBOUND_CONFFILE
  282. if [ "$UNBOUND_B_QRY_MINST" -gt 0 -a "$UNBOUND_B_QUERY_MIN" -gt 0 ] ; then
  283. {
  284. # Some query privacy but "strict" will break some name servers
  285. echo " qname-minimisation: yes"
  286. echo " qname-minimisation-strict: yes"
  287. } >> $UNBOUND_CONFFILE
  288. elif [ "$UNBOUND_B_QUERY_MIN" -gt 0 ] ; then
  289. # Minor improvement on query privacy
  290. echo " qname-minimisation: yes" >> $UNBOUND_CONFFILE
  291. else
  292. echo " qname-minimisation: no" >> $UNBOUND_CONFFILE
  293. fi
  294. case "$UNBOUND_D_RECURSION" in
  295. passive)
  296. {
  297. echo " prefetch: no"
  298. echo " prefetch-key: no"
  299. echo " target-fetch-policy: \"0 0 0 0 0\""
  300. echo
  301. } >> $UNBOUND_CONFFILE
  302. ;;
  303. aggressive)
  304. {
  305. echo " prefetch: yes"
  306. echo " prefetch-key: yes"
  307. echo " target-fetch-policy: \"3 2 1 0 0\""
  308. echo
  309. } >> $UNBOUND_CONFFILE
  310. ;;
  311. *)
  312. logger -t unbound -s "default recursion configuration"
  313. ;;
  314. esac
  315. {
  316. # Reload records more than 10 hours old
  317. # DNSSEC 5 minute bogus cool down before retry
  318. # Adaptive infrastructure info kept for 15 minutes
  319. echo " cache-min-ttl: $UNBOUND_TTL_MIN"
  320. echo " cache-max-ttl: 36000"
  321. echo " val-bogus-ttl: 300"
  322. echo " infra-host-ttl: 900"
  323. echo
  324. } >> $UNBOUND_CONFFILE
  325. if [ "$UNBOUND_B_HIDE_BIND" -gt 0 ] ; then
  326. {
  327. # Block server id and version DNS TXT records
  328. echo " hide-identity: yes"
  329. echo " hide-version: yes"
  330. echo
  331. } >> $UNBOUND_CONFFILE
  332. fi
  333. if [ "$UNBOUND_B_PRIV_BLCK" -gt 0 ] ; then
  334. {
  335. # Remove _upstream_ or global reponses with private addresses.
  336. # Unbounds own "local zone" and "forward zone" may still use these.
  337. # RFC1918, RFC3927, RFC4291, RFC6598, RFC6890
  338. echo " private-address: 10.0.0.0/8"
  339. echo " private-address: 100.64.0.0/10"
  340. echo " private-address: 169.254.0.0/16"
  341. echo " private-address: 172.16.0.0/12"
  342. echo " private-address: 192.168.0.0/16"
  343. echo " private-address: fc00::/8"
  344. echo " private-address: fd00::/8"
  345. echo " private-address: fe80::/10"
  346. } >> $UNBOUND_CONFFILE
  347. fi
  348. if [ "$UNBOUND_B_LOCL_BLCK" -gt 0 ] ; then
  349. {
  350. # Remove DNS reponses from upstream with loopback IP
  351. # Black hole DNS method for ad blocking, so consider...
  352. echo " private-address: 127.0.0.0/8"
  353. echo " private-address: ::1/128"
  354. echo
  355. } >> $UNBOUND_CONFFILE
  356. else
  357. echo >> $UNBOUND_CONFFILE
  358. fi
  359. # Domain Exceptions
  360. config_list_foreach "$cfg" "domain_insecure" create_domain_insecure
  361. echo >> $UNBOUND_CONFFILE
  362. ####################
  363. # UCI @ network #
  364. ####################
  365. if [ "$UNBOUND_B_LOCL_SERV" -gt 0 ] ; then
  366. # Only respond to queries from which this device has an interface.
  367. # Prevent DNS amplification attacks by not responding to the universe.
  368. config_load network
  369. config_foreach create_access_control interface
  370. {
  371. echo " access-control: 127.0.0.0/8 allow"
  372. echo " access-control: ::1/128 allow"
  373. echo " access-control: fe80::/10 allow"
  374. echo
  375. } >> $UNBOUND_CONFFILE
  376. else
  377. {
  378. echo " access-control: 0.0.0.0/0 allow"
  379. echo " access-control: ::0/0 allow"
  380. echo
  381. } >> $UNBOUND_CONFFILE
  382. fi
  383. }
  384. ##############################################################################
  385. unbound_uci() {
  386. local cfg=$1
  387. local dnsmasqpath
  388. ####################
  389. # UCI @ unbound #
  390. ####################
  391. config_get_bool UNBOUND_B_DNS64 "$cfg" dns64 0
  392. config_get_bool UNBOUND_B_GATE_NAME "$cfg" dnsmasq_gate_name 0
  393. config_get_bool UNBOUND_B_DNSMASQ "$cfg" dnsmasq_link_dns 0
  394. config_get_bool UNBOUND_B_HIDE_BIND "$cfg" hide_binddata 1
  395. config_get_bool UNBOUND_B_LOCL_NAME "$cfg" dnsmasq_only_local 0
  396. config_get_bool UNBOUND_B_LOCL_SERV "$cfg" localservice 1
  397. config_get_bool UNBOUND_B_MAN_CONF "$cfg" manual_conf 0
  398. config_get_bool UNBOUND_B_QUERY_MIN "$cfg" query_minimize 0
  399. config_get_bool UNBOUND_B_QRY_MINST "$cfg" query_min_strict 0
  400. config_get_bool UNBOUND_B_PRIV_BLCK "$cfg" rebind_protection 1
  401. config_get_bool UNBOUND_B_LOCL_BLCK "$cfg" rebind_localhost 0
  402. config_get_bool UNBOUND_B_CONTROL "$cfg" unbound_control 0
  403. config_get_bool UNBOUND_B_DNSSEC "$cfg" validator 0
  404. config_get_bool UNBOUND_B_NTP_BOOT "$cfg" validator_ntp 1
  405. config_get UNBOUND_IP_DNS64 "$cfg" dns64_prefix "64:ff9b::/96"
  406. config_get UNBOUND_N_EDNS_SIZE "$cfg" edns_size 1280
  407. config_get UNBOUND_N_RX_PORT "$cfg" listen_port 53
  408. config_get UNBOUND_N_ROOT_AGE "$cfg" root_age 7
  409. config_get UNBOUND_D_PROTOCOL "$cfg" protocol mixed
  410. config_get UNBOUND_D_RECURSION "$cfg" recursion passive
  411. config_get UNBOUND_D_RESOURCE "$cfg" resource small
  412. config_get UNBOUND_TTL_MIN "$cfg" ttl_min 120
  413. if [ "$UNBOUND_B_DNSMASQ" -gt 0 ] ; then
  414. dnsmasqpath=$( which dnsmasq )
  415. if [ ! -x "$dnsmasqpath" ] ; then
  416. logger -t unbound -s "cannot forward to dnsmasq"
  417. UNBOUND_B_DNSMASQ=0
  418. fi
  419. fi
  420. if [ "$UNBOUND_N_EDNS_SIZE" -lt 512 \
  421. -o 4096 -lt "$UNBOUND_N_EDNS_SIZE" ] ; then
  422. # exceeds range, back to default
  423. UNBOUND_N_EDNS_SIZE=1280
  424. fi
  425. if [ "$UNBOUND_N_RX_PORT" -lt 1024 \
  426. -o 10240 -lt "$UNBOUND_N_RX_PORT" ] ; then
  427. # special port or in 5 digits, back to default
  428. UNBOUND_N_RX_PORT=53
  429. fi
  430. if [ "$UNBOUND_TTL_MIN" -gt 1800 ] ; then
  431. # that could have had awful side effects
  432. UNBOUND_TTL_MIN=300
  433. fi
  434. if [ "$UNBOUND_B_MAN_CONF" -gt 0 ] ; then
  435. # Don't want this being triggered. Maybe we could, but then the
  436. # base conf you provide would need to be just right.
  437. UNBOUND_B_DNSMASQ=0
  438. else
  439. unbound_conf $cfg
  440. fi
  441. }
  442. ##############################################################################
  443. unbound_own () {
  444. # Debug UCI
  445. {
  446. echo "# $UNBOUND_CHECKFILE generated by UCI $( date )"
  447. echo
  448. set | grep ^UNBOUND_
  449. } > $UNBOUND_CHECKFILE
  450. if [ "$UNBOUND_B_MAN_CONF" -gt 0 ] ; then
  451. # You are doing your own thing, so just copy /etc/ to /var/
  452. cp -p /etc/unbound/* $UNBOUND_VARDIR/
  453. fi
  454. # Ensure access and prepare to jail
  455. chown -R unbound:unbound $UNBOUND_VARDIR
  456. chmod 775 $UNBOUND_VARDIR
  457. chmod 664 $UNBOUND_VARDIR/*
  458. }
  459. ##############################################################################
  460. unbound_prepare() {
  461. # Make a home for Unbound in /var/lib/unbound
  462. unbound_mkdir
  463. # Load up the chunks of UCI
  464. config_load unbound
  465. config_foreach unbound_uci unbound
  466. # Unbound primary DNS, and dnsmasq side service DHCP-DNS (dnsmasq.sh)
  467. dnsmasq_link
  468. # Unbound needs chroot ownership
  469. unbound_own
  470. }
  471. ##############################################################################