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.
		
		
		
		
		
			
		
			
				
					
					
						
							276 lines
						
					
					
						
							7.1 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							276 lines
						
					
					
						
							7.1 KiB
						
					
					
				
								#!/usr/bin/env sh
							 | 
						|
								# shellcheck disable=SC2034
							 | 
						|
								dns_opnsense_info='OPNsense Server
							 | 
						|
								Site: docs.opnsense.org/development/api.html
							 | 
						|
								Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_opnsense
							 | 
						|
								Options:
							 | 
						|
								 OPNs_Host Server Hostname. E.g. "opnsense.example.com"
							 | 
						|
								 OPNs_Port Port. Default: "443".
							 | 
						|
								 OPNs_Key API Key
							 | 
						|
								 OPNs_Token API Token
							 | 
						|
								 OPNs_Api_Insecure Insecure TLS. 0: check for cert validity, 1: always accept
							 | 
						|
								Issues: github.com/acmesh-official/acme.sh/issues/2480
							 | 
						|
								'
							 | 
						|
								
							 | 
						|
								########  Public functions #####################
							 | 
						|
								#Usage: add _acme-challenge.www.domain.com "123456789ABCDEF0000000000000000000000000000000000000"
							 | 
						|
								#fulldomain
							 | 
						|
								#txtvalue
							 | 
						|
								OPNs_DefaultPort=443
							 | 
						|
								OPNs_DefaultApi_Insecure=0
							 | 
						|
								
							 | 
						|
								dns_opnsense_add() {
							 | 
						|
								  fulldomain=$1
							 | 
						|
								  txtvalue=$2
							 | 
						|
								
							 | 
						|
								  _opns_check_auth || return 1
							 | 
						|
								
							 | 
						|
								  if ! set_record "$fulldomain" "$txtvalue"; then
							 | 
						|
								    return 1
							 | 
						|
								  fi
							 | 
						|
								
							 | 
						|
								  return 0
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								#fulldomain
							 | 
						|
								dns_opnsense_rm() {
							 | 
						|
								  fulldomain=$1
							 | 
						|
								  txtvalue=$2
							 | 
						|
								
							 | 
						|
								  _opns_check_auth || return 1
							 | 
						|
								
							 | 
						|
								  if ! rm_record "$fulldomain" "$txtvalue"; then
							 | 
						|
								    return 1
							 | 
						|
								  fi
							 | 
						|
								
							 | 
						|
								  return 0
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								set_record() {
							 | 
						|
								  fulldomain=$1
							 | 
						|
								  new_challenge=$2
							 | 
						|
								  _info "Adding record $fulldomain with challenge: $new_challenge"
							 | 
						|
								
							 | 
						|
								  _debug "Detect root zone"
							 | 
						|
								  if ! _get_root "$fulldomain"; then
							 | 
						|
								    _err "invalid domain"
							 | 
						|
								    return 1
							 | 
						|
								  fi
							 | 
						|
								
							 | 
						|
								  _debug _domain "$_domain"
							 | 
						|
								  _debug _host "$_host"
							 | 
						|
								  _debug _domainid "$_domainid"
							 | 
						|
								  _return_str=""
							 | 
						|
								  _record_string=""
							 | 
						|
								  _build_record_string "$_domainid" "$_host" "$new_challenge"
							 | 
						|
								  _uuid=""
							 | 
						|
								  if _existingchallenge "$_domain" "$_host" "$new_challenge"; then
							 | 
						|
								    # Update
							 | 
						|
								    if _opns_rest "POST" "/record/setRecord/${_uuid}" "$_record_string"; then
							 | 
						|
								      _return_str="$response"
							 | 
						|
								    else
							 | 
						|
								      return 1
							 | 
						|
								    fi
							 | 
						|
								
							 | 
						|
								  else
							 | 
						|
								    #create
							 | 
						|
								    if _opns_rest "POST" "/record/addRecord" "$_record_string"; then
							 | 
						|
								      _return_str="$response"
							 | 
						|
								    else
							 | 
						|
								      return 1
							 | 
						|
								    fi
							 | 
						|
								  fi
							 | 
						|
								
							 | 
						|
								  if echo "$_return_str" | _egrep_o "\"result\":\"saved\"" >/dev/null; then
							 | 
						|
								    _opns_rest "POST" "/service/reconfigure" "{}"
							 | 
						|
								    _debug "Record created"
							 | 
						|
								  else
							 | 
						|
								    _err "Error creating record $_record_string"
							 | 
						|
								    return 1
							 | 
						|
								  fi
							 | 
						|
								
							 | 
						|
								  return 0
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								rm_record() {
							 | 
						|
								  fulldomain=$1
							 | 
						|
								  new_challenge="$2"
							 | 
						|
								  _info "Remove record $fulldomain with challenge: $new_challenge"
							 | 
						|
								
							 | 
						|
								  _debug "Detect root zone"
							 | 
						|
								  if ! _get_root "$fulldomain"; then
							 | 
						|
								    _err "invalid domain"
							 | 
						|
								    return 1
							 | 
						|
								  fi
							 | 
						|
								
							 | 
						|
								  _debug _domain "$_domain"
							 | 
						|
								  _debug _host "$_host"
							 | 
						|
								  _debug _domainid "$_domainid"
							 | 
						|
								  _uuid=""
							 | 
						|
								  if _existingchallenge "$_domain" "$_host" "$new_challenge"; then
							 | 
						|
								    # Delete
							 | 
						|
								    if _opns_rest "POST" "/record/delRecord/${_uuid}" "\{\}"; then
							 | 
						|
								      if echo "$response" | _egrep_o "\"result\":\"deleted\"" >/dev/null; then
							 | 
						|
								        _debug "Record deleted"
							 | 
						|
								        _opns_rest "POST" "/service/reconfigure" "{}"
							 | 
						|
								        _debug "Service reconfigured"
							 | 
						|
								      else
							 | 
						|
								        _err "Error deleting record $_host from domain $fulldomain"
							 | 
						|
								        return 1
							 | 
						|
								      fi
							 | 
						|
								    else
							 | 
						|
								      _err "Error requesting deletion of record $_host from domain $fulldomain"
							 | 
						|
								      return 1
							 | 
						|
								    fi
							 | 
						|
								  else
							 | 
						|
								    _info "Record not found, nothing to remove"
							 | 
						|
								  fi
							 | 
						|
								
							 | 
						|
								  return 0
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								####################  Private functions below ##################################
							 | 
						|
								#_acme-challenge.www.domain.com
							 | 
						|
								#returns
							 | 
						|
								# _domainid=domid
							 | 
						|
								#_domain=domain.com
							 | 
						|
								_get_root() {
							 | 
						|
								  domain=$1
							 | 
						|
								  i=2
							 | 
						|
								  p=1
							 | 
						|
								  if _opns_rest "GET" "/domain/searchPrimaryDomain"; then
							 | 
						|
								    _domain_response="$response"
							 | 
						|
								  else
							 | 
						|
								    return 1
							 | 
						|
								  fi
							 | 
						|
								
							 | 
						|
								  while true; do
							 | 
						|
								    h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
							 | 
						|
								    if [ -z "$h" ]; then
							 | 
						|
								      #not valid
							 | 
						|
								      return 1
							 | 
						|
								    fi
							 | 
						|
								    _debug h "$h"
							 | 
						|
								    lines=$(echo "$_domain_response" | sed 's/{/\n/g')
							 | 
						|
								    for line in $lines; do
							 | 
						|
								      id=$(echo "$line" | _egrep_o "\"uuid\":\"[a-z0-9\-]*\",\"enabled\":\"1\",\"type\":\"primary\",.*\"domainname\":\"${h}\"" | cut -d ':' -f 2 | cut -d '"' -f 2)
							 | 
						|
								      if [ -n "$id" ]; then
							 | 
						|
								        _debug id "$id"
							 | 
						|
								        _host=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
							 | 
						|
								        _domain="${h}"
							 | 
						|
								        _domainid="${id}"
							 | 
						|
								        return 0
							 | 
						|
								      fi
							 | 
						|
								    done
							 | 
						|
								    p=$i
							 | 
						|
								    i=$(_math "$i" + 1)
							 | 
						|
								  done
							 | 
						|
								  _debug "$domain not found"
							 | 
						|
								
							 | 
						|
								  return 1
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								_opns_rest() {
							 | 
						|
								  method=$1
							 | 
						|
								  ep=$2
							 | 
						|
								  data=$3
							 | 
						|
								  #Percent encode user and token
							 | 
						|
								  key=$(echo "$OPNs_Key" | tr -d "\n\r" | _url_encode)
							 | 
						|
								  token=$(echo "$OPNs_Token" | tr -d "\n\r" | _url_encode)
							 | 
						|
								
							 | 
						|
								  opnsense_url="https://${key}:${token}@${OPNs_Host}:${OPNs_Port:-$OPNs_DefaultPort}/api/bind${ep}"
							 | 
						|
								  export _H1="Content-Type: application/json"
							 | 
						|
								  _debug2 "Try to call api: https://${OPNs_Host}:${OPNs_Port:-$OPNs_DefaultPort}/api/bind${ep}"
							 | 
						|
								  if [ ! "$method" = "GET" ]; then
							 | 
						|
								    _debug data "$data"
							 | 
						|
								    export _H1="Content-Type: application/json"
							 | 
						|
								    response="$(_post "$data" "$opnsense_url" "" "$method")"
							 | 
						|
								  else
							 | 
						|
								    export _H1=""
							 | 
						|
								    response="$(_get "$opnsense_url")"
							 | 
						|
								  fi
							 | 
						|
								
							 | 
						|
								  if [ "$?" != "0" ]; then
							 | 
						|
								    _err "error $ep"
							 | 
						|
								    return 1
							 | 
						|
								  fi
							 | 
						|
								  _debug2 response "$response"
							 | 
						|
								
							 | 
						|
								  return 0
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								_build_record_string() {
							 | 
						|
								  _record_string="{\"record\":{\"enabled\":\"1\",\"domain\":\"$1\",\"name\":\"$2\",\"type\":\"TXT\",\"value\":\"$3\"}}"
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								_existingchallenge() {
							 | 
						|
								  if _opns_rest "GET" "/record/searchRecord"; then
							 | 
						|
								    _record_response="$response"
							 | 
						|
								  else
							 | 
						|
								    return 1
							 | 
						|
								  fi
							 | 
						|
								  _uuid=""
							 | 
						|
								  _uuid=$(echo "$_record_response" | _egrep_o "\"uuid\":\"[a-z0-9\-]*\",\"enabled\":\"[01]\",\"domain\":\"[a-z0-9\-]*\",\"%domain\":\"$1\",\"name\":\"$2\",\"type\":\"TXT\",\"value\":\"$3\"" | cut -d ':' -f 2 | cut -d '"' -f 2)
							 | 
						|
								
							 | 
						|
								  if [ -n "$_uuid" ]; then
							 | 
						|
								    _debug uuid "$_uuid"
							 | 
						|
								    return 0
							 | 
						|
								  fi
							 | 
						|
								  _debug "${2}.${1} record not found"
							 | 
						|
								
							 | 
						|
								  return 1
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								_opns_check_auth() {
							 | 
						|
								  OPNs_Host="${OPNs_Host:-$(_readaccountconf_mutable OPNs_Host)}"
							 | 
						|
								  OPNs_Port="${OPNs_Port:-$(_readaccountconf_mutable OPNs_Port)}"
							 | 
						|
								  OPNs_Key="${OPNs_Key:-$(_readaccountconf_mutable OPNs_Key)}"
							 | 
						|
								  OPNs_Token="${OPNs_Token:-$(_readaccountconf_mutable OPNs_Token)}"
							 | 
						|
								  OPNs_Api_Insecure="${OPNs_Api_Insecure:-$(_readaccountconf_mutable OPNs_Api_Insecure)}"
							 | 
						|
								
							 | 
						|
								  if [ -z "$OPNs_Host" ]; then
							 | 
						|
								    _err "You don't specify OPNsense address."
							 | 
						|
								    return 1
							 | 
						|
								  else
							 | 
						|
								    _saveaccountconf_mutable OPNs_Host "$OPNs_Host"
							 | 
						|
								  fi
							 | 
						|
								
							 | 
						|
								  if ! printf '%s' "$OPNs_Port" | grep '^[0-9]*$' >/dev/null; then
							 | 
						|
								    _err 'OPNs_Port specified but not numeric value'
							 | 
						|
								    return 1
							 | 
						|
								  elif [ -z "$OPNs_Port" ]; then
							 | 
						|
								    _info "OPNSense port not specified. Defaulting to using port $OPNs_DefaultPort"
							 | 
						|
								  else
							 | 
						|
								    _saveaccountconf_mutable OPNs_Port "$OPNs_Port"
							 | 
						|
								  fi
							 | 
						|
								
							 | 
						|
								  if ! printf '%s' "$OPNs_Api_Insecure" | grep '^[01]$' >/dev/null; then
							 | 
						|
								    _err 'OPNs_Api_Insecure specified but not 0/1 value'
							 | 
						|
								    return 1
							 | 
						|
								  elif [ -n "$OPNs_Api_Insecure" ]; then
							 | 
						|
								    _saveaccountconf_mutable OPNs_Api_Insecure "$OPNs_Api_Insecure"
							 | 
						|
								  fi
							 | 
						|
								  export HTTPS_INSECURE="${OPNs_Api_Insecure:-$OPNs_DefaultApi_Insecure}"
							 | 
						|
								
							 | 
						|
								  if [ -z "$OPNs_Key" ]; then
							 | 
						|
								    _err "you have not specified your OPNsense api key id."
							 | 
						|
								    _err "Please set OPNs_Key and try again."
							 | 
						|
								    return 1
							 | 
						|
								  else
							 | 
						|
								    _saveaccountconf_mutable OPNs_Key "$OPNs_Key"
							 | 
						|
								  fi
							 | 
						|
								
							 | 
						|
								  if [ -z "$OPNs_Token" ]; then
							 | 
						|
								    _err "you have not specified your OPNsense token."
							 | 
						|
								    _err "Please create OPNs_Token and try again."
							 | 
						|
								    return 1
							 | 
						|
								  else
							 | 
						|
								    _saveaccountconf_mutable OPNs_Token "$OPNs_Token"
							 | 
						|
								  fi
							 | 
						|
								
							 | 
						|
								  if ! _opns_rest "GET" "/general/get"; then
							 | 
						|
								    _err "Call to OPNsense API interface failed. Unable to access OPNsense API."
							 | 
						|
								    return 1
							 | 
						|
								  fi
							 | 
						|
								  return 0
							 | 
						|
								}
							 |