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.

318 lines
8.4 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 crosses over to the dnsmasq UCI file "dhcp" and parses it for fields
  18. # that will allow Unbound to request local host DNS of dnsmasq. We need to look
  19. # at the interfaces in "dhcp" and get their subnets. The Unbound conf syntax
  20. # makes this a little difficult. First in "server:" we need to create private
  21. # zones for the domain and PTR records. Then we need to create numerous
  22. # "forward:" clauses to forward those zones to dnsmasq.
  23. #
  24. ##############################################################################
  25. # while useful (sh)ellcheck is pedantic and noisy
  26. # shellcheck disable=1091,2002,2004,2034,2039,2086,2094,2140,2154,2155
  27. DM_D_WAN_FQDN=0
  28. DM_LIST_KNOWN_ZONES="invalid"
  29. DM_LIST_TRN_ZONES=""
  30. DM_LIST_LOCAL_DATA=""
  31. DM_LIST_LOCAL_PTR=""
  32. DM_LIST_FWD_PORTS=""
  33. DM_LIST_FWD_ZONES=""
  34. ##############################################################################
  35. create_local_zone() {
  36. local target="$1"
  37. local partial domain found
  38. case $DM_LIST_TRN_ZONES in
  39. *"${target}"*)
  40. found=1
  41. ;;
  42. *)
  43. case $target in
  44. [A-Za-z0-9]*.[A-Za-z0-9]*)
  45. found=0
  46. ;;
  47. *) # no dots
  48. found=1
  49. ;;
  50. esac
  51. esac
  52. if [ $found -eq 0 ] ; then
  53. # New Zone! Bundle local-zones: by first two name tiers "abcd.tld."
  54. partial=$( echo "$target" | awk -F. '{ j=NF ; i=j-1; print $i"."$j }' )
  55. DM_LIST_TRN_ZONES="$DM_LIST_TRN_ZONES $partial"
  56. DM_LIST_KNOWN_ZONES="$DM_LIST_KNOWN_ZONES $partial"
  57. fi
  58. }
  59. ##############################################################################
  60. create_host_record() {
  61. local cfg="$1"
  62. local ip name debug_ip
  63. # basefiles dhcp "domain" clause which means host A, AAAA, and PRT record
  64. config_get ip "$cfg" ip
  65. config_get name "$cfg" name
  66. if [ -n "$name" ] && [ -n "$ip" ] ; then
  67. create_local_zone "$name"
  68. case $ip in
  69. fe[89ab][0-9a-f]:*|169.254.*)
  70. debug_ip="$ip@$name"
  71. ;;
  72. [1-9a-f]*:*[0-9a-f])
  73. DM_LIST_LOCAL_DATA="$DM_LIST_LOCAL_DATA $name.@@300@@IN@@AAAA@@$ip"
  74. DM_LIST_LOCAL_PTR="$DM_LIST_LOCAL_PTR $ip@@300@@$name"
  75. ;;
  76. [1-9]*.*[0-9])
  77. DM_LIST_LOCAL_DATA="$DM_LIST_LOCAL_DATA $name.@@300@@IN@@A@@$ip"
  78. DM_LIST_LOCAL_PTR="$DM_LIST_LOCAL_PTR $ip@@300@@$name"
  79. ;;
  80. esac
  81. fi
  82. }
  83. ##############################################################################
  84. create_mx_record() {
  85. local cfg="$1"
  86. local domain relay pref record
  87. # Insert a static MX record
  88. config_get domain "$cfg" domain
  89. config_get relay "$cfg" relay
  90. config_get pref "$cfg" pref 10
  91. if [ -n "$domain" ] && [ -n "$relay" ] ; then
  92. create_local_zone "$domain"
  93. record="$domain.@@300@@IN@@MX@@$pref@@$relay."
  94. DM_LIST_LOCAL_DATA="$DM_LIST_LOCAL_DATA $record"
  95. fi
  96. }
  97. ##############################################################################
  98. create_srv_record() {
  99. local cfg="$1"
  100. local srv target port class weight record
  101. # Insert a static SRV record such as SIP server
  102. config_get srv "$cfg" srv
  103. config_get target "$cfg" target
  104. config_get port "$cfg" port
  105. config_get class "$cfg" class 10
  106. config_get weight "$cfg" weight 10
  107. if [ -n "$srv" ] && [ -n "$target" ] && [ -n "$port" ] ; then
  108. create_local_zone "$srv"
  109. record="$srv.@@300@@IN@@SRV@@$class@@$weight@@$port@@$target."
  110. DM_LIST_LOCAL_DATA="$DM_LIST_LOCAL_DATA $record"
  111. fi
  112. }
  113. ##############################################################################
  114. create_cname_record() {
  115. local cfg="$1"
  116. local cname target record
  117. # Insert static CNAME record
  118. config_get cname "$cfg" cname
  119. config_get target "$cfg" target
  120. if [ -n "$cname" ] && [ -n "$target" ] ; then
  121. create_local_zone "$cname"
  122. record="$cname.@@300@@IN@@CNAME@@$target."
  123. DM_LIST_LOCAL_DATA="$DM_LIST_LOCAL_DATA $record"
  124. fi
  125. }
  126. ##############################################################################
  127. dnsmasq_local_zone() {
  128. local cfg="$1"
  129. local fwd_port fwd_domain wan_fqdn
  130. # dnsmasq domain and interface assignment settings will control config
  131. config_get fwd_domain "$cfg" domain
  132. config_get fwd_port "$cfg" port
  133. config_get wan_fqdn "$cfg" add_wan_fqdn
  134. if [ -n "$wan_fqdn" ] ; then
  135. DM_D_WAN_FQDN=$wan_fqdn
  136. fi
  137. if [ -n "$fwd_domain" ] && [ -n "$fwd_port" ] \
  138. && [ ! ${fwd_port:-53} -eq 53 ] ; then
  139. # dnsmasq localhost listening ports (possible multiple instances)
  140. DM_LIST_FWD_PORTS="$DM_LIST_FWD_PORTS $fwd_port"
  141. DM_LIST_FWD_ZONES="$DM_LIST_FWD_ZONES $fwd_domain"
  142. fi
  143. }
  144. ##############################################################################
  145. dnsmasq_local_arpa() {
  146. local ifarpa ifsubnet
  147. if [ -n "$UB_LIST_NETW_LAN" ] ; then
  148. for ifsubnet in $UB_LIST_NETW_LAN ; do
  149. ifarpa=$( domain_ptr_any "${ifsubnet#*@}" )
  150. DM_LIST_FWD_ZONES="$DM_LIST_FWD_ZONES $ifarpa"
  151. done
  152. fi
  153. if [ -n "$UB_LIST_NETW_WAN" ] && [ $DM_D_WAN_FQDN -gt 0 ] ; then
  154. for ifsubnet in $UB_LIST_NETW_WAN ; do
  155. ifarpa=$( domain_ptr_any "${ifsubnet#*@}" )
  156. DM_LIST_FWD_ZONES="$DM_LIST_FWD_ZONES $ifarpa"
  157. done
  158. fi
  159. }
  160. ##############################################################################
  161. dnsmasq_inactive() {
  162. local record
  163. if [ $UB_D_EXTRA_DNS -gt 0 ] ; then
  164. # Parasite from the uci.dhcp.domain clauses
  165. DM_LIST_KNOWN_ZONES="$DM_LIST_KNOWN_ZONES $UB_TXT_DOMAIN"
  166. config_load dhcp
  167. config_foreach create_host_record domain
  168. if [ $UB_D_EXTRA_DNS -gt 1 ] ; then
  169. config_foreach create_srv_record srvhost
  170. config_foreach create_mx_record mxhost
  171. fi
  172. if [ $UB_D_EXTRA_DNS -gt 2 ] ; then
  173. config_foreach create_cname_record cname
  174. fi
  175. {
  176. echo "# $UB_SRVMASQ_CONF generated by UCI $( date -Is )"
  177. if [ -n "$DM_LIST_TRN_ZONES" ] ; then
  178. for record in $DM_LIST_TRN_ZONES ; do
  179. echo " local-zone: $record transparent"
  180. done
  181. echo
  182. fi
  183. if [ -n "$DM_LIST_LOCAL_DATA" ] ; then
  184. for record in $DM_LIST_LOCAL_DATA ; do
  185. echo " local-data: \"${record//@@/ }\""
  186. done
  187. echo
  188. fi
  189. if [ -n "$DM_LIST_LOCAL_PTR" ] ; then
  190. for record in $DM_LIST_LOCAL_PTR ; do
  191. echo " local-data-ptr: \"${record//@@/ }\""
  192. done
  193. echo
  194. fi
  195. } > $UB_SRVMASQ_CONF
  196. fi
  197. }
  198. ##############################################################################
  199. dnsmasq_active() {
  200. # Look at dnsmasq settings
  201. config_load dhcp
  202. # Zone for DHCP / SLAAC-PING DOMAIN
  203. config_foreach dnsmasq_local_zone dnsmasq
  204. # Zone for DHCP / SLAAC-PING ARPA
  205. dnsmasq_local_arpa
  206. if [ -n "$DM_LIST_FWD_PORTS" ] && [ -n "$DM_LIST_FWD_ZONES" ] ; then
  207. if [ $UB_B_DNS_ASSIST -lt 1 ] ; then
  208. {
  209. # Forward to dnsmasq on same host for DHCP lease hosts
  210. echo "# $UB_SRVMASQ_CONF generated by UCI $( date -Is )"
  211. echo " do-not-query-localhost: no"
  212. echo
  213. } > $UB_SRVMASQ_CONF
  214. else
  215. echo > $UB_SRVMASQ_CONF
  216. fi
  217. echo "# $UB_EXTMASQ_CONF generated by UCI $( date -Is )" > $UB_EXTMASQ_CONF
  218. for fwd_domain in $DM_LIST_FWD_ZONES ; do
  219. {
  220. # This creates a domain with local privledges
  221. echo " domain-insecure: $fwd_domain"
  222. echo " private-domain: $fwd_domain"
  223. echo " local-zone: $fwd_domain transparent"
  224. echo
  225. } >> $UB_SRVMASQ_CONF
  226. {
  227. # This is derived from dnsmasq local domain and dhcp service subnets
  228. echo "forward-zone:"
  229. echo " name: $fwd_domain"
  230. echo " forward-first: no"
  231. for port in $DM_LIST_FWD_PORTS ; do
  232. echo " forward-addr: 127.0.0.1@$port"
  233. done
  234. echo
  235. } >> $UB_EXTMASQ_CONF
  236. done
  237. fi
  238. }
  239. ##############################################################################
  240. dnsmasq_link() {
  241. if [ "$UB_D_DHCP_LINK" = "dnsmasq" ] ; then
  242. dnsmasq_active
  243. else
  244. dnsmasq_inactive
  245. fi
  246. }
  247. ##############################################################################