dns_inwx.sh 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. #!/usr/bin/env sh
  2. #
  3. #INWX_User="username"
  4. #
  5. #INWX_Password="password"
  6. #
  7. # Dependencies:
  8. # -------------
  9. # - oathtool (When using 2 Factor Authentication)
  10. INWX_Api="https://api.domrobot.com/xmlrpc/"
  11. ######## Public functions #####################
  12. #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
  13. dns_inwx_add() {
  14. fulldomain=$1
  15. txtvalue=$2
  16. INWX_User="${INWX_User:-$(_readaccountconf_mutable INWX_User)}"
  17. INWX_Password="${INWX_Password:-$(_readaccountconf_mutable INWX_Password)}"
  18. INWX_Shared_Secret="${INWX_Shared_Secret:-$(_readaccountconf_mutable INWX_Shared_Secret)}"
  19. if [ -z "$INWX_User" ] || [ -z "$INWX_Password" ]; then
  20. INWX_User=""
  21. INWX_Password=""
  22. _err "You don't specify inwx user and password yet."
  23. _err "Please create you key and try again."
  24. return 1
  25. fi
  26. #save the api key and email to the account conf file.
  27. _saveaccountconf_mutable INWX_User "$INWX_User"
  28. _saveaccountconf_mutable INWX_Password "$INWX_Password"
  29. _saveaccountconf_mutable INWX_Shared_Secret "$INWX_Shared_Secret"
  30. _debug "First detect the root zone"
  31. if ! _get_root "$fulldomain"; then
  32. _err "invalid domain"
  33. return 1
  34. fi
  35. _debug _sub_domain "$_sub_domain"
  36. _debug _domain "$_domain"
  37. _info "Adding record"
  38. _inwx_add_record "$_domain" "$_sub_domain" "$txtvalue"
  39. }
  40. #fulldomain txtvalue
  41. dns_inwx_rm() {
  42. fulldomain=$1
  43. txtvalue=$2
  44. INWX_User="${INWX_User:-$(_readaccountconf_mutable INWX_User)}"
  45. INWX_Password="${INWX_Password:-$(_readaccountconf_mutable INWX_Password)}"
  46. if [ -z "$INWX_User" ] || [ -z "$INWX_Password" ]; then
  47. INWX_User=""
  48. INWX_Password=""
  49. _err "You don't specify inwx user and password yet."
  50. _err "Please create you key and try again."
  51. return 1
  52. fi
  53. #save the api key and email to the account conf file.
  54. _saveaccountconf_mutable INWX_User "$INWX_User"
  55. _saveaccountconf_mutable INWX_Password "$INWX_Password"
  56. _debug "First detect the root zone"
  57. if ! _get_root "$fulldomain"; then
  58. _err "invalid domain"
  59. return 1
  60. fi
  61. _debug _sub_domain "$_sub_domain"
  62. _debug _domain "$_domain"
  63. _debug "Getting txt records"
  64. xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
  65. <methodCall>
  66. <methodName>nameserver.info</methodName>
  67. <params>
  68. <param>
  69. <value>
  70. <struct>
  71. <member>
  72. <name>domain</name>
  73. <value>
  74. <string>%s</string>
  75. </value>
  76. </member>
  77. <member>
  78. <name>type</name>
  79. <value>
  80. <string>TXT</string>
  81. </value>
  82. </member>
  83. <member>
  84. <name>name</name>
  85. <value>
  86. <string>%s</string>
  87. </value>
  88. </member>
  89. </struct>
  90. </value>
  91. </param>
  92. </params>
  93. </methodCall>' "$_domain" "$_sub_domain")
  94. response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
  95. if ! _contains "$response" "Command completed successfully"; then
  96. _err "Error could not get txt records"
  97. return 1
  98. fi
  99. if ! printf "%s" "$response" | grep "count" >/dev/null; then
  100. _info "Do not need to delete record"
  101. else
  102. _record_id=$(printf '%s' "$response" | _egrep_o '.*(<member><name>record){1}(.*)([0-9]+){1}' | _egrep_o '<name>id<\/name><value><int>[0-9]+' | _egrep_o '[0-9]+')
  103. _info "Deleting record"
  104. _inwx_delete_record "$_record_id"
  105. fi
  106. }
  107. #################### Private functions below ##################################
  108. _inwx_login() {
  109. xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
  110. <methodCall>
  111. <methodName>account.login</methodName>
  112. <params>
  113. <param>
  114. <value>
  115. <struct>
  116. <member>
  117. <name>user</name>
  118. <value>
  119. <string>%s</string>
  120. </value>
  121. </member>
  122. <member>
  123. <name>pass</name>
  124. <value>
  125. <string>%s</string>
  126. </value>
  127. </member>
  128. </struct>
  129. </value>
  130. </param>
  131. </params>
  132. </methodCall>' $INWX_User $INWX_Password)
  133. response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
  134. _H1=$(printf "Cookie: %s" "$(grep "domrobot=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')")
  135. export _H1
  136. #https://github.com/inwx/php-client/blob/master/INWX/Domrobot.php#L71
  137. if _contains "$response" "<member><name>code</name><value><int>1000</int></value></member>" \
  138. && _contains "$response" "<member><name>tfa</name><value><string>GOOGLE-AUTH</string></value></member>"; then
  139. if [ -z "$INWX_Shared_Secret" ]; then
  140. _err "Mobile TAN detected."
  141. _err "Please define a shared secret."
  142. return 1
  143. fi
  144. if ! _exists oathtool; then
  145. _err "Please install oathtool to use 2 Factor Authentication."
  146. _err ""
  147. return 1
  148. fi
  149. tan="$(oathtool --base32 --totp "${INWX_Shared_Secret}" 2>/dev/null)"
  150. xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
  151. <methodCall>
  152. <methodName>account.unlock</methodName>
  153. <params>
  154. <param>
  155. <value>
  156. <struct>
  157. <member>
  158. <name>tan</name>
  159. <value>
  160. <string>%s</string>
  161. </value>
  162. </member>
  163. </struct>
  164. </value>
  165. </param>
  166. </params>
  167. </methodCall>' "$tan")
  168. response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
  169. fi
  170. }
  171. _get_root() {
  172. domain=$1
  173. _debug "get root"
  174. domain=$1
  175. i=2
  176. p=1
  177. _inwx_login
  178. xml_content='<?xml version="1.0" encoding="UTF-8"?>
  179. <methodCall>
  180. <methodName>nameserver.list</methodName>
  181. </methodCall>'
  182. response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
  183. while true; do
  184. h=$(printf "%s" "$domain" | cut -d . -f $i-100)
  185. _debug h "$h"
  186. if [ -z "$h" ]; then
  187. #not valid
  188. return 1
  189. fi
  190. if _contains "$response" "$h"; then
  191. _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
  192. _domain="$h"
  193. return 0
  194. fi
  195. p=$i
  196. i=$(_math "$i" + 1)
  197. done
  198. return 1
  199. }
  200. _inwx_delete_record() {
  201. record_id=$1
  202. xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
  203. <methodCall>
  204. <methodName>nameserver.deleteRecord</methodName>
  205. <params>
  206. <param>
  207. <value>
  208. <struct>
  209. <member>
  210. <name>id</name>
  211. <value>
  212. <int>%s</int>
  213. </value>
  214. </member>
  215. </struct>
  216. </value>
  217. </param>
  218. </params>
  219. </methodCall>' "$record_id")
  220. response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
  221. if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then
  222. _err "Error"
  223. return 1
  224. fi
  225. return 0
  226. }
  227. _inwx_update_record() {
  228. record_id=$1
  229. txtval=$2
  230. xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
  231. <methodCall>
  232. <methodName>nameserver.updateRecord</methodName>
  233. <params>
  234. <param>
  235. <value>
  236. <struct>
  237. <member>
  238. <name>content</name>
  239. <value>
  240. <string>%s</string>
  241. </value>
  242. </member>
  243. <member>
  244. <name>id</name>
  245. <value>
  246. <int>%s</int>
  247. </value>
  248. </member>
  249. </struct>
  250. </value>
  251. </param>
  252. </params>
  253. </methodCall>' "$txtval" "$record_id")
  254. response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
  255. if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then
  256. _err "Error"
  257. return 1
  258. fi
  259. return 0
  260. }
  261. _inwx_add_record() {
  262. domain=$1
  263. sub_domain=$2
  264. txtval=$3
  265. xml_content=$(printf '<?xml version="1.0" encoding="UTF-8"?>
  266. <methodCall>
  267. <methodName>nameserver.createRecord</methodName>
  268. <params>
  269. <param>
  270. <value>
  271. <struct>
  272. <member>
  273. <name>domain</name>
  274. <value>
  275. <string>%s</string>
  276. </value>
  277. </member>
  278. <member>
  279. <name>type</name>
  280. <value>
  281. <string>TXT</string>
  282. </value>
  283. </member>
  284. <member>
  285. <name>content</name>
  286. <value>
  287. <string>%s</string>
  288. </value>
  289. </member>
  290. <member>
  291. <name>name</name>
  292. <value>
  293. <string>%s</string>
  294. </value>
  295. </member>
  296. </struct>
  297. </value>
  298. </param>
  299. </params>
  300. </methodCall>' "$domain" "$txtval" "$sub_domain")
  301. response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
  302. if ! printf "%s" "$response" | grep "Command completed successfully" >/dev/null; then
  303. _err "Error"
  304. return 1
  305. fi
  306. return 0
  307. }