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.

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