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.

416 lines
9.7 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. #!/usr/bin/env sh
  2. # shellcheck disable=SC2034
  3. dns_namecheap_info='NameCheap.com
  4. Site: NameCheap.com
  5. Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_namecheap
  6. Options:
  7. NAMECHEAP_API_KEY API Key
  8. NAMECHEAP_USERNAME Username
  9. NAMECHEAP_SOURCEIP Source IP
  10. Issues: github.com/acmesh-official/acme.sh/issues/2107
  11. '
  12. # Namecheap API
  13. # https://www.namecheap.com/support/api/intro.aspx
  14. # Due to Namecheap's API limitation all the records of your domain will be read and re applied, make sure to have a backup of your records you could apply if any issue would arise.
  15. ######## Public functions #####################
  16. NAMECHEAP_API="https://api.namecheap.com/xml.response"
  17. #Usage: dns_namecheap_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
  18. dns_namecheap_add() {
  19. fulldomain=$1
  20. txtvalue=$2
  21. if ! _namecheap_check_config; then
  22. _err "$error"
  23. return 1
  24. fi
  25. if ! _namecheap_set_publicip; then
  26. return 1
  27. fi
  28. _debug "First detect the root zone"
  29. if ! _get_root "$fulldomain"; then
  30. _err "invalid domain"
  31. return 1
  32. fi
  33. _debug fulldomain "$fulldomain"
  34. _debug txtvalue "$txtvalue"
  35. _debug domain "$_domain"
  36. _debug sub_domain "$_sub_domain"
  37. _set_namecheap_TXT "$_domain" "$_sub_domain" "$txtvalue"
  38. }
  39. #Usage: fulldomain txtvalue
  40. #Remove the txt record after validation.
  41. dns_namecheap_rm() {
  42. fulldomain=$1
  43. txtvalue=$2
  44. if ! _namecheap_set_publicip; then
  45. return 1
  46. fi
  47. if ! _namecheap_check_config; then
  48. _err "$error"
  49. return 1
  50. fi
  51. _debug "First detect the root zone"
  52. if ! _get_root "$fulldomain"; then
  53. _err "invalid domain"
  54. return 1
  55. fi
  56. _debug fulldomain "$fulldomain"
  57. _debug txtvalue "$txtvalue"
  58. _debug domain "$_domain"
  59. _debug sub_domain "$_sub_domain"
  60. _del_namecheap_TXT "$_domain" "$_sub_domain" "$txtvalue"
  61. }
  62. #################### Private functions below ##################################
  63. #_acme-challenge.www.domain.com
  64. #returns
  65. # _sub_domain=_acme-challenge.www
  66. # _domain=domain.com
  67. _get_root() {
  68. fulldomain=$1
  69. if ! _get_root_by_getList "$fulldomain"; then
  70. _debug "Failed domain lookup via domains.getList api call. Trying domain lookup via domains.dns.getHosts api."
  71. # The above "getList" api will only return hosts *owned* by the calling user. However, if the calling
  72. # user is not the owner, but still has administrative rights, we must query the getHosts api directly.
  73. # See this comment and the official namecheap response: https://disq.us/p/1q6v9x9
  74. if ! _get_root_by_getHosts "$fulldomain"; then
  75. return 1
  76. fi
  77. fi
  78. return 0
  79. }
  80. _get_root_by_getList() {
  81. domain=$1
  82. if ! _namecheap_post "namecheap.domains.getList"; then
  83. _err "$error"
  84. return 1
  85. fi
  86. i=2
  87. p=1
  88. while true; do
  89. h=$(printf "%s" "$domain" | cut -d . -f $i-100)
  90. _debug h "$h"
  91. if [ -z "$h" ]; then
  92. #not valid
  93. return 1
  94. fi
  95. if ! _contains "$h" "\\."; then
  96. #not valid
  97. return 1
  98. fi
  99. if ! _contains "$response" "$h"; then
  100. _debug "$h not found"
  101. else
  102. _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
  103. _domain="$h"
  104. return 0
  105. fi
  106. p="$i"
  107. i=$(_math "$i" + 1)
  108. done
  109. return 1
  110. }
  111. _get_root_by_getHosts() {
  112. i=100
  113. p=99
  114. while [ $p -ne 0 ]; do
  115. h=$(printf "%s" "$1" | cut -d . -f $i-100)
  116. if [ -n "$h" ]; then
  117. if _contains "$h" "\\."; then
  118. _debug h "$h"
  119. if _namecheap_set_tld_sld "$h"; then
  120. _sub_domain=$(printf "%s" "$1" | cut -d . -f 1-$p)
  121. _domain="$h"
  122. return 0
  123. else
  124. _debug "$h not found"
  125. fi
  126. fi
  127. fi
  128. i="$p"
  129. p=$(_math "$p" - 1)
  130. done
  131. return 1
  132. }
  133. _namecheap_set_publicip() {
  134. if [ -z "$NAMECHEAP_SOURCEIP" ]; then
  135. _err "No Source IP specified for Namecheap API."
  136. _err "Use your public ip address or an url to retrieve it (e.g. https://ifconfig.co/ip) and export it as NAMECHEAP_SOURCEIP"
  137. return 1
  138. else
  139. _saveaccountconf NAMECHEAP_SOURCEIP "$NAMECHEAP_SOURCEIP"
  140. _debug sourceip "$NAMECHEAP_SOURCEIP"
  141. ip=$(echo "$NAMECHEAP_SOURCEIP" | _egrep_o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
  142. addr=$(echo "$NAMECHEAP_SOURCEIP" | _egrep_o '(http|https):\/\/.*')
  143. _debug2 ip "$ip"
  144. _debug2 addr "$addr"
  145. if [ -n "$ip" ]; then
  146. _publicip="$ip"
  147. elif [ -n "$addr" ]; then
  148. _publicip=$(_get "$addr")
  149. else
  150. _err "No Source IP specified for Namecheap API."
  151. _err "Use your public ip address or an url to retrieve it (e.g. https://ifconfig.co/ip) and export it as NAMECHEAP_SOURCEIP"
  152. return 1
  153. fi
  154. fi
  155. _debug publicip "$_publicip"
  156. return 0
  157. }
  158. _namecheap_post() {
  159. command=$1
  160. data="ApiUser=${NAMECHEAP_USERNAME}&ApiKey=${NAMECHEAP_API_KEY}&ClientIp=${_publicip}&UserName=${NAMECHEAP_USERNAME}&Command=${command}"
  161. _debug2 "_namecheap_post data" "$data"
  162. response="$(_post "$data" "$NAMECHEAP_API" "" "POST")"
  163. _debug2 response "$response"
  164. if _contains "$response" "Status=\"ERROR\"" >/dev/null; then
  165. error=$(echo "$response" | _egrep_o ">.*<\\/Error>" | cut -d '<' -f 1 | tr -d '>')
  166. _err "error $error"
  167. return 1
  168. fi
  169. return 0
  170. }
  171. _namecheap_parse_host() {
  172. _host=$1
  173. _debug _host "$_host"
  174. _hostid=$(echo "$_host" | _egrep_o ' HostId="[^"]*' | cut -d '"' -f 2)
  175. _hostname=$(echo "$_host" | _egrep_o ' Name="[^"]*' | cut -d '"' -f 2)
  176. _hosttype=$(echo "$_host" | _egrep_o ' Type="[^"]*' | cut -d '"' -f 2)
  177. _hostaddress=$(echo "$_host" | _egrep_o ' Address="[^"]*' | cut -d '"' -f 2 | _xml_decode)
  178. _hostmxpref=$(echo "$_host" | _egrep_o ' MXPref="[^"]*' | cut -d '"' -f 2)
  179. _hostttl=$(echo "$_host" | _egrep_o ' TTL="[^"]*' | cut -d '"' -f 2)
  180. _debug hostid "$_hostid"
  181. _debug hostname "$_hostname"
  182. _debug hosttype "$_hosttype"
  183. _debug hostaddress "$_hostaddress"
  184. _debug hostmxpref "$_hostmxpref"
  185. _debug hostttl "$_hostttl"
  186. }
  187. _namecheap_check_config() {
  188. if [ -z "$NAMECHEAP_API_KEY" ]; then
  189. _err "No API key specified for Namecheap API."
  190. _err "Create your key and export it as NAMECHEAP_API_KEY"
  191. return 1
  192. fi
  193. if [ -z "$NAMECHEAP_USERNAME" ]; then
  194. _err "No username key specified for Namecheap API."
  195. _err "Create your key and export it as NAMECHEAP_USERNAME"
  196. return 1
  197. fi
  198. _saveaccountconf NAMECHEAP_API_KEY "$NAMECHEAP_API_KEY"
  199. _saveaccountconf NAMECHEAP_USERNAME "$NAMECHEAP_USERNAME"
  200. return 0
  201. }
  202. _set_namecheap_TXT() {
  203. subdomain=$2
  204. txt=$3
  205. if ! _namecheap_set_tld_sld "$1"; then
  206. return 1
  207. fi
  208. request="namecheap.domains.dns.getHosts&SLD=${_sld}&TLD=${_tld}"
  209. if ! _namecheap_post "$request"; then
  210. _err "$error"
  211. return 1
  212. fi
  213. hosts=$(echo "$response" | _egrep_o '<host[^>]*')
  214. _debug hosts "$hosts"
  215. if [ -z "$hosts" ]; then
  216. _err "Hosts not found"
  217. return 1
  218. fi
  219. _namecheap_reset_hostList
  220. while read -r host; do
  221. if _contains "$host" "<host"; then
  222. _namecheap_parse_host "$host"
  223. _debug2 _hostname "_hostname"
  224. _debug2 _hosttype "_hosttype"
  225. _debug2 _hostaddress "_hostaddress"
  226. _debug2 _hostmxpref "_hostmxpref"
  227. _hostaddress="$(printf "%s" "$_hostaddress" | _url_encode)"
  228. _debug2 "encoded _hostaddress" "_hostaddress"
  229. _namecheap_add_host "$_hostname" "$_hosttype" "$_hostaddress" "$_hostmxpref" "$_hostttl"
  230. fi
  231. done <<EOT
  232. echo "$hosts"
  233. EOT
  234. _namecheap_add_host "$subdomain" "TXT" "$txt" 10 120
  235. _debug hostrequestfinal "$_hostrequest"
  236. request="namecheap.domains.dns.setHosts&SLD=${_sld}&TLD=${_tld}${_hostrequest}"
  237. if ! _namecheap_post "$request"; then
  238. _err "$error"
  239. return 1
  240. fi
  241. return 0
  242. }
  243. _del_namecheap_TXT() {
  244. subdomain=$2
  245. txt=$3
  246. if ! _namecheap_set_tld_sld "$1"; then
  247. return 1
  248. fi
  249. request="namecheap.domains.dns.getHosts&SLD=${_sld}&TLD=${_tld}"
  250. if ! _namecheap_post "$request"; then
  251. _err "$error"
  252. return 1
  253. fi
  254. hosts=$(echo "$response" | _egrep_o '<host[^>]*')
  255. _debug hosts "$hosts"
  256. if [ -z "$hosts" ]; then
  257. _err "Hosts not found"
  258. return 1
  259. fi
  260. _namecheap_reset_hostList
  261. found=0
  262. while read -r host; do
  263. if _contains "$host" "<host"; then
  264. _namecheap_parse_host "$host"
  265. if [ "$_hosttype" = "TXT" ] && [ "$_hostname" = "$subdomain" ] && [ "$_hostaddress" = "$txt" ]; then
  266. _debug "TXT entry found"
  267. found=1
  268. else
  269. _hostaddress="$(printf "%s" "$_hostaddress" | _url_encode)"
  270. _namecheap_add_host "$_hostname" "$_hosttype" "$_hostaddress" "$_hostmxpref" "$_hostttl"
  271. fi
  272. fi
  273. done <<EOT
  274. echo "$hosts"
  275. EOT
  276. if [ $found -eq 0 ]; then
  277. _debug "TXT entry not found"
  278. return 0
  279. fi
  280. _debug hostrequestfinal "$_hostrequest"
  281. request="namecheap.domains.dns.setHosts&SLD=${_sld}&TLD=${_tld}${_hostrequest}"
  282. if ! _namecheap_post "$request"; then
  283. _err "$error"
  284. return 1
  285. fi
  286. return 0
  287. }
  288. _namecheap_reset_hostList() {
  289. _hostindex=0
  290. _hostrequest=""
  291. }
  292. #Usage: _namecheap_add_host HostName RecordType Address MxPref TTL
  293. _namecheap_add_host() {
  294. _hostindex=$(_math "$_hostindex" + 1)
  295. _hostrequest=$(printf '%s&HostName%d=%s&RecordType%d=%s&Address%d=%s&MXPref%d=%d&TTL%d=%d' "$_hostrequest" "$_hostindex" "$1" "$_hostindex" "$2" "$_hostindex" "$3" "$_hostindex" "$4" "$_hostindex" "$5")
  296. }
  297. _namecheap_set_tld_sld() {
  298. domain=$1
  299. _tld=""
  300. _sld=""
  301. i=2
  302. while true; do
  303. _tld=$(printf "%s" "$domain" | cut -d . -f $i-100)
  304. _debug tld "$_tld"
  305. if [ -z "$_tld" ]; then
  306. _debug "invalid tld"
  307. return 1
  308. fi
  309. j=$(_math "$i" - 1)
  310. _sld=$(printf "%s" "$domain" | cut -d . -f 1-"$j")
  311. _debug sld "$_sld"
  312. if [ -z "$_sld" ]; then
  313. _debug "invalid sld"
  314. return 1
  315. fi
  316. request="namecheap.domains.dns.getHosts&SLD=$_sld&TLD=$_tld"
  317. if ! _namecheap_post "$request"; then
  318. _debug "sld($_sld)/tld($_tld) not found"
  319. else
  320. _debug "sld($_sld)/tld($_tld) found"
  321. return 0
  322. fi
  323. i=$(_math "$i" + 1)
  324. done
  325. }
  326. _xml_decode() {
  327. sed 's/&quot;/"/g'
  328. }