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.

269 lines
6.8 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. #!/usr/bin/env sh
  2. #OPNsense Bind API
  3. #https://docs.opnsense.org/development/api.html
  4. #
  5. #OPNs_Host="opnsense.example.com"
  6. #OPNs_Port="443" (optional, defaults to 443 if unset)
  7. #OPNs_Key="qocfU9RSbt8vTIBcnW8bPqCrpfAHMDvj5OzadE7Str+rbjyCyk7u6yMrSCHtBXabgDDXx/dY0POUp7ZA"
  8. #OPNs_Token="pZEQ+3ce8dDlfBBdg3N8EpqpF5I1MhFqdxX06le6Gl8YzyQvYCfCzNaFX9O9+IOSyAs7X71fwdRiZ+Lv"
  9. #OPNs_Api_Insecure=0 (optional, defaults to 0 if unset) # Set 1 for insecure and 0 for secure -> difference is whether ssl cert is checked for validity (0) or whether it is just accepted (1)
  10. ######## Public functions #####################
  11. #Usage: add _acme-challenge.www.domain.com "123456789ABCDEF0000000000000000000000000000000000000"
  12. #fulldomain
  13. #txtvalue
  14. OPNs_DefaultPort=443
  15. OPNs_DefaultApi_Insecure=0
  16. dns_opnsense_add() {
  17. fulldomain=$1
  18. txtvalue=$2
  19. _opns_check_auth || return 1
  20. if ! set_record "$fulldomain" "$txtvalue"; then
  21. return 1
  22. fi
  23. return 0
  24. }
  25. #fulldomain
  26. dns_opnsense_rm() {
  27. fulldomain=$1
  28. txtvalue=$2
  29. _opns_check_auth || return 1
  30. if ! rm_record "$fulldomain" "$txtvalue"; then
  31. return 1
  32. fi
  33. return 0
  34. }
  35. set_record() {
  36. _info "Adding record"
  37. fulldomain=$1
  38. new_challenge=$2
  39. _debug "Detect root zone"
  40. if ! _get_root "$fulldomain"; then
  41. _err "invalid domain"
  42. return 1
  43. fi
  44. _debug _domain "$_domain"
  45. _debug _host "$_host"
  46. _debug _domainid "$_domainid"
  47. _return_str=""
  48. _record_string=""
  49. _build_record_string "$_domainid" "$_host" "$new_challenge"
  50. _uuid=""
  51. if _existingchallenge "$_domain" "$_host" "$new_challenge"; then
  52. # Update
  53. if _opns_rest "POST" "/record/setRecord/${_uuid}" "$_record_string"; then
  54. _return_str="$response"
  55. else
  56. return 1
  57. fi
  58. else
  59. #create
  60. if _opns_rest "POST" "/record/addRecord" "$_record_string"; then
  61. _return_str="$response"
  62. else
  63. return 1
  64. fi
  65. fi
  66. if echo "$_return_str" | _egrep_o "\"result\":\"saved\"" >/dev/null; then
  67. _opns_rest "POST" "/service/reconfigure" "{}"
  68. _debug "Record created"
  69. else
  70. _err "Error createing record $_record_string"
  71. return 1
  72. fi
  73. return 0
  74. }
  75. rm_record() {
  76. _info "Remove record"
  77. fulldomain=$1
  78. new_challenge="$2"
  79. _debug "Detect root zone"
  80. if ! _get_root "$fulldomain"; then
  81. _err "invalid domain"
  82. return 1
  83. fi
  84. _debug _domain "$_domain"
  85. _debug _host "$_host"
  86. _debug _domainid "$_domainid"
  87. _uuid=""
  88. if _existingchallenge "$_domain" "$_host" "$new_challenge"; then
  89. # Delete
  90. if _opns_rest "POST" "/record/delRecord/${_uuid}" "\{\}"; then
  91. if echo "$_return_str" | _egrep_o "\"result\":\"deleted\"" >/dev/null; then
  92. _opns_rest "POST" "/service/reconfigure" "{}"
  93. _debug "Record deleted"
  94. else
  95. _err "Error delteting record $fulldomain"
  96. return 1
  97. fi
  98. else
  99. _err "Error delteting record $fulldomain"
  100. return 1
  101. fi
  102. else
  103. _info "Record not found, nothing to remove"
  104. fi
  105. return 0
  106. }
  107. #################### Private functions below ##################################
  108. #_acme-challenge.www.domain.com
  109. #returns
  110. # _domainid=domid
  111. #_domain=domain.com
  112. _get_root() {
  113. domain=$1
  114. i=2
  115. p=1
  116. if _opns_rest "GET" "/domain/get"; then
  117. _domain_response="$response"
  118. else
  119. return 1
  120. fi
  121. while true; do
  122. h=$(printf "%s" "$domain" | cut -d . -f $i-100)
  123. if [ -z "$h" ]; then
  124. #not valid
  125. return 1
  126. fi
  127. _debug h "$h"
  128. id=$(echo "$_domain_response" | _egrep_o "\"[^\"]*\":{\"enabled\":\"1\",\"type\":{\"master\":{\"value\":\"master\",\"selected\":1},\"slave\":{\"value\":\"slave\",\"selected\":0}},\"masterip\":\"[^\"]*\",\"domainname\":\"${h}\"" | cut -d ':' -f 1 | cut -d '"' -f 2)
  129. if [ -n "$id" ]; then
  130. _debug id "$id"
  131. _host=$(printf "%s" "$domain" | cut -d . -f 1-$p)
  132. _domain="${h}"
  133. _domainid="${id}"
  134. return 0
  135. fi
  136. p=$i
  137. i=$(_math $i + 1)
  138. done
  139. _debug "$domain not found"
  140. return 1
  141. }
  142. _opns_rest() {
  143. method=$1
  144. ep=$2
  145. data=$3
  146. #Percent encode user and token
  147. key=$(echo "$OPNs_Key" | tr -d "\n\r" | _url_encode)
  148. token=$(echo "$OPNs_Token" | tr -d "\n\r" | _url_encode)
  149. opnsense_url="https://${key}:${token}@${OPNs_Host}:${OPNs_Port:-$OPNs_DefaultPort}/api/bind${ep}"
  150. export _H1="Content-Type: application/json"
  151. if [ ! "$method" = "GET" ]; then
  152. _debug data "$data"
  153. export _H1="Content-Type: application/json"
  154. response="$(_post "$data" "$opnsense_url" "" "$method")"
  155. else
  156. export _H1=""
  157. response="$(_get "$opnsense_url")"
  158. fi
  159. if [ "$?" != "0" ]; then
  160. _err "error $ep"
  161. return 1
  162. fi
  163. _debug2 response "$response"
  164. return 0
  165. }
  166. _build_record_string() {
  167. _record_string="{\"record\":{\"enabled\":\"1\",\"domain\":\"$1\",\"name\":\"$2\",\"type\":\"TXT\",\"value\":\"$3\"}}"
  168. }
  169. _existingchallenge() {
  170. if _opns_rest "GET" "/record/searchRecord"; then
  171. _record_response="$response"
  172. else
  173. return 1
  174. fi
  175. _uuid=""
  176. _uuid=$(echo "$_record_response" | _egrep_o "\"uuid\":\"[^\"]*\",\"enabled\":\"[01]\",\"domain\":\"$1\",\"name\":\"$2\",\"type\":\"TXT\",\"value\":\"$3\"" | cut -d ':' -f 2 | cut -d '"' -f 2)
  177. if [ -n "$_uuid" ]; then
  178. _debug uuid "$_uuid"
  179. return 0
  180. fi
  181. _debug "${2}.$1{1} record not found"
  182. return 1
  183. }
  184. _opns_check_auth() {
  185. OPNs_Host="${OPNs_Host:-$(_readaccountconf_mutable OPNs_Host)}"
  186. OPNs_Port="${OPNs_Port:-$(_readaccountconf_mutable OPNs_Port)}"
  187. OPNs_Key="${OPNs_Key:-$(_readaccountconf_mutable OPNs_Key)}"
  188. OPNs_Token="${OPNs_Token:-$(_readaccountconf_mutable OPNs_Token)}"
  189. OPNs_Api_Insecure="${OPNs_Api_Insecure:-$(_readaccountconf_mutable OPNs_Api_Insecure)}"
  190. if [ -z "$OPNs_Host" ]; then
  191. _err "You don't specify OPNsense address."
  192. return 1
  193. else
  194. _saveaccountconf_mutable OPNs_Host "$OPNs_Host"
  195. fi
  196. if ! printf '%s' "$OPNs_Port" | grep -q '^[0-9]*$'; then
  197. _err 'OPNs_Port specified but not numeric value'
  198. return 1
  199. elif [ -z "$OPNs_Port" ]; then
  200. _info "OPNSense port not specified. Defaulting to using port $OPNs_DefaultPort"
  201. else
  202. _saveaccountconf_mutable OPNs_Port "$OPNs_Port"
  203. fi
  204. if ! printf '%s' "$OPNs_Api_Insecure" | grep -q '^[01]$'; then
  205. _err 'OPNs_Api_Insecure specified but not 0/1 value'
  206. return 1
  207. elif [ -n "$OPNs_Api_Insecure" ]; then
  208. _saveaccountconf_mutable OPNs_Api_Insecure "$OPNs_Api_Insecure"
  209. fi
  210. export HTTPS_INSECURE="${OPNs_Api_Insecure:-$OPNs_DefaultApi_Insecure}"
  211. if [ -z "$OPNs_Key" ]; then
  212. _err "You don't specify OPNsense api key id."
  213. _err "Please set you OPNs_Key and try again."
  214. return 1
  215. else
  216. _saveaccountconf_mutable OPNs_Key "$OPNs_Key"
  217. fi
  218. if [ -z "$OPNs_Token" ]; then
  219. _err "You don't specify OPNsense token."
  220. _err "Please create you OPNs_Token and try again."
  221. return 1
  222. else
  223. _saveaccountconf_mutable OPNs_Token "$OPNs_Token"
  224. fi
  225. if ! _opns_rest "GET" "/general/get"; then
  226. _err "Can't Access OPNsense"
  227. return 1
  228. fi
  229. return 0
  230. }