{"id":2450,"date":"2021-07-12T14:47:35","date_gmt":"2021-07-12T22:47:35","guid":{"rendered":"http:\/\/wonghoi.humgar.com\/blog\/?p=2450"},"modified":"2021-07-12T16:52:55","modified_gmt":"2021-07-13T00:52:55","slug":"namecheap-dynamic-dns-setup-in-dd-wrt","status":"publish","type":"post","link":"https:\/\/wonghoi.humgar.com\/blog\/2021\/07\/12\/namecheap-dynamic-dns-setup-in-dd-wrt\/","title":{"rendered":"Namecheap Dynamic DNS setup in dd-wrt"},"content":{"rendered":"\n<p>Namecheap <a href=\"https:\/\/www.namecheap.com\/support\/knowledgebase\/article.aspx\/9356\/11\/how-to-configure-a-ddwrt-router\/\" data-type=\"URL\" data-id=\"https:\/\/www.namecheap.com\/support\/knowledgebase\/article.aspx\/9356\/11\/how-to-configure-a-ddwrt-router\/\" target=\"_blank\" rel=\"noreferrer noopener\">support page<\/a> explained the process of configuring your dd-wrt router firmware to use Namecheap&#8217;s REST (HTTP URL) update interface to dynamically update the IP of your (sub-)domain. The instruction works, but there are few items which doesn&#8217;t quite make sense to me as a programmer, and I did a few experiments to figured that it&#8217;s bogus and developed a few insights about what&#8217;s necessary and why they do it.<\/p>\n\n\n\n<p>Their instructions looks like this:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/namecheap.simplekb.com\/SiteContents\/2-7C22D5236A4543EB827F3BD8936E153E\/media\/ddwrt3.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>and specific verbal instructions are:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>DDNS Service<\/strong>: Custom<\/li><li><strong>DYNDNS Server<\/strong>: dynamicdns.park-your-domain.com &#8211; the name of the server&nbsp;should not&nbsp;be changed<\/li><li><s><strong>Username<\/strong>: yourdomain.com &#8211; replace it with your domain name<\/s><\/li><li><s><strong>Password<\/strong>: Dynamic DNS password for your domain (<strong>Domain List<\/strong>&nbsp;&gt;&gt; click on the&nbsp;<strong>Manage&nbsp;<\/strong>button next to the domain &gt;&gt; the&nbsp;<strong>Advanced DNS<\/strong>&nbsp;tab &gt;&gt;&nbsp;<strong>Dynamic DNS<\/strong>)<\/s><\/li><li><strong>Hostname<\/strong>: Your subdomain (<strong>@<\/strong>&nbsp;for&nbsp;<em>yourdomain.com<\/em>,&nbsp;<strong>www&nbsp;<\/strong>for&nbsp;<em>www.yourdomain.com<\/em>, etc.)<\/li><li><strong>URL<\/strong>:&nbsp;<em>\/update?domain=yourdomain.com&amp;password=DynamicDNSPassword&amp;host=<\/em><\/li><\/ul>\n\n\n\n<p class=\"has-text-align-center\">I stroke out <em><strong>Username<\/strong><\/em> and <em><strong>Password<\/strong><\/em> fields because they are not used! <\/p>\n\n\n\n<p>If you look at the URL, namecheap&#8217;s instructions are asking you to re-enter the <strong><em>domain<\/em><\/strong> and the <strong><em>password<\/em><\/strong> key-value pair AGAIN, which means <em><strong>Username<\/strong><\/em> and <em><strong>Password<\/strong><\/em> fields are not used. <\/p>\n\n\n\n<p>My programmer instinct immediate screams the updater is assuming certain REST API syntax that are not properly substituted so they need to be entered manually, exposing the password without the benefit of the masks (forget about keeping the password top secret, router firmware guys aren&#8217;t top security engineers. Just re-generate one in Namecheap&#8217;s admin interface if it gets compromised).<\/p>\n\n\n\n<p>I checked by entering bogus <em><strong>Username<\/strong><\/em> and <em><strong>Password<\/strong><\/em> fields (the web&#8217;s GUI\/forms checks if they are blank, so you can&#8217;t get away with not entering). It worked as expected. This means the two fields are dummies with Namecheap&#8217;s instructions.<\/p>\n\n\n\n<p>Based on the fact that Namecheap&#8217;s instructions being unable to substitute <em><strong>Username<\/strong><\/em> and <em><strong>Password<\/strong><\/em> fields and the <em><strong>host<\/strong><\/em> key must be put at the end for <strong><em>Hostname<\/em><\/strong> field to substitute correctly, I can safely speculate that the one who wrote this couldn&#8217;t find out what the syntax for the variables are, and exploit that the last parameter <em><strong>hostname<\/strong><\/em> gets attached at the end in the absence of substitution variables in the URL syntax.<\/p>\n\n\n\n<p>Apparent people are doing something stupid like this because nobody in the chain remember to document the substitution variable names! It&#8217;s not in dd-wrt&#8217;s user interface (should have that printed the &#8216;usage&#8217; info next to the URL box) and neither it&#8217;s in INADYN&#8217;s github readmes! <\/p>\n\n\n\n<p>I decided to dig deeper and go after the dynamic DNS updater package in question. dd-wrt is using <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/troglobit\/inadyn\" data-type=\"URL\" data-id=\"https:\/\/github.com\/troglobit\/inadyn\" target=\"_blank\">inadyn<\/a> package to do the dynamic DNS update, as &#8220;INADYN&#8221; is shown in &#8220;DDNS status&#8221; box gives it away (confirmed by dd-wrt&#8217;s <a rel=\"noreferrer noopener\" href=\"https:\/\/wiki.dd-wrt.com\/wiki\/index.php\/DDNS_-_How_to_manage_multiple_DDNS_accounts_using_embedded_inadyn_-_HOWTO\" target=\"_blank\">docs<\/a>):<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1025\" height=\"99\" src=\"https:\/\/wonghoi.humgar.com\/blog\/wp-content\/uploads\/2021\/04\/image-4.png\" alt=\"\" class=\"wp-image-2451\" srcset=\"https:\/\/wonghoi.humgar.com\/blog\/wp-content\/uploads\/2021\/04\/image-4.png 1025w, https:\/\/wonghoi.humgar.com\/blog\/wp-content\/uploads\/2021\/04\/image-4-300x29.png 300w, https:\/\/wonghoi.humgar.com\/blog\/wp-content\/uploads\/2021\/04\/image-4-768x74.png 768w\" sizes=\"auto, (max-width: 1025px) 100vw, 1025px\" \/><\/figure>\n\n\n\n<p>The service itself is called <code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">ddns<\/code> though.<\/p>\n\n\n\n<p>I ended up reading the \/examples folder on the repository and found <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/troglobit\/inadyn\/blob\/master\/examples\/custom.conf\" target=\"_blank\">this<\/a>:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"732\" src=\"https:\/\/wonghoi.humgar.com\/blog\/wp-content\/uploads\/2021\/04\/image-5-1024x732.png\" alt=\"\" class=\"wp-image-2452\" srcset=\"https:\/\/wonghoi.humgar.com\/blog\/wp-content\/uploads\/2021\/04\/image-5-1024x732.png 1024w, https:\/\/wonghoi.humgar.com\/blog\/wp-content\/uploads\/2021\/04\/image-5-300x214.png 300w, https:\/\/wonghoi.humgar.com\/blog\/wp-content\/uploads\/2021\/04\/image-5-768x549.png 768w, https:\/\/wonghoi.humgar.com\/blog\/wp-content\/uploads\/2021\/04\/image-5-1536x1097.png 1536w, https:\/\/wonghoi.humgar.com\/blog\/wp-content\/uploads\/2021\/04\/image-5.png 1772w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Bingo! Here it is:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td class=\"has-text-align-center\" data-align=\"center\">URL substitution string<\/td><td class=\"has-text-align-center\" data-align=\"center\">dd-wrt fields<\/td><td class=\"has-text-align-center\" data-align=\"center\">Namecheap REST key<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\"><code>%u<\/code><\/td><td class=\"has-text-align-center\" data-align=\"center\"><code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">Username<\/code><\/td><td class=\"has-text-align-center\" data-align=\"center\"><code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">domain<\/code><\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\"><code>%p<\/code><\/td><td class=\"has-text-align-center\" data-align=\"center\"><code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">Password<\/code><\/td><td class=\"has-text-align-center\" data-align=\"center\"><code>password<\/code><\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\"><code>%h<\/code><\/td><td class=\"has-text-align-center\" data-align=\"center\"><code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">Hostname<\/code><\/td><td class=\"has-text-align-center\" data-align=\"center\"><code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">host<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><code data-enlighter-language=\"generic\" class=\"EnlighterJSRAW\">generic.c<\/code> is a plugin also shows the above table as well<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"583\" src=\"https:\/\/wonghoi.humgar.com\/blog\/wp-content\/uploads\/2021\/04\/image-6-1024x583.png\" alt=\"\" class=\"wp-image-2453\" srcset=\"https:\/\/wonghoi.humgar.com\/blog\/wp-content\/uploads\/2021\/04\/image-6-1024x583.png 1024w, https:\/\/wonghoi.humgar.com\/blog\/wp-content\/uploads\/2021\/04\/image-6-300x171.png 300w, https:\/\/wonghoi.humgar.com\/blog\/wp-content\/uploads\/2021\/04\/image-6-768x437.png 768w, https:\/\/wonghoi.humgar.com\/blog\/wp-content\/uploads\/2021\/04\/image-6-1536x875.png 1536w, https:\/\/wonghoi.humgar.com\/blog\/wp-content\/uploads\/2021\/04\/image-6.png 1651w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>Since namecheap&#8217;s dynamic DNS service do not mandate how frequently you can update nor they charge per update, it&#8217;s easiest and most reliable to just blindly update the IP every N minutes instead of checking against a local cache to see if the external IP has really changed before updating at each poll interval<\/p>\n\n\n\n<p>This user interface does not have the option to set the updater to run every 1 minute, so why bother since it&#8217;s just a simple program that creates a simple URL and do a curl\/wget? At the end of the day, I decided to just do a cron job:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>PATH=\/sbin:\/usr\/sbin:\/bin:\/usr\/bin\n* * * * * root curl \"https:\/\/dynamicdns.park-your-domain.com\/update?host={subdomain or @}&amp;domain={domain name bought}&amp;password={generated by namecheap's account management page}\"<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"235\" src=\"https:\/\/wonghoi.humgar.com\/blog\/wp-content\/uploads\/2021\/07\/image-1-1024x235.png\" alt=\"\" class=\"wp-image-2626\" srcset=\"https:\/\/wonghoi.humgar.com\/blog\/wp-content\/uploads\/2021\/07\/image-1-1024x235.png 1024w, https:\/\/wonghoi.humgar.com\/blog\/wp-content\/uploads\/2021\/07\/image-1-300x69.png 300w, https:\/\/wonghoi.humgar.com\/blog\/wp-content\/uploads\/2021\/07\/image-1-768x176.png 768w, https:\/\/wonghoi.humgar.com\/blog\/wp-content\/uploads\/2021\/07\/image-1.png 1088w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>There are 3 things that you will need to know:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Paths is from a clean slate. Need to define it first<\/li><li><code>* * * * *<\/code> means every minute. Specify numbers\/range for each time unit (minute, hour, day of month, month, day of week) if desired. Asterisk means ON EVERY.<\/li><li>Need to specify the user after the time syntax and before the actual command<\/li><\/ul>\n<div class=\"pvc_clear\"><\/div><p id=\"pvc_stats_2450\" class=\"pvc_stats all  \" data-element-id=\"2450\" style=\"\"><i class=\"pvc-stats-icon medium\" aria-hidden=\"true\"><svg aria-hidden=\"true\" focusable=\"false\" data-prefix=\"far\" data-icon=\"chart-bar\" role=\"img\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\" class=\"svg-inline--fa fa-chart-bar fa-w-16 fa-2x\"><path fill=\"currentColor\" d=\"M396.8 352h22.4c6.4 0 12.8-6.4 12.8-12.8V108.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v230.4c0 6.4 6.4 12.8 12.8 12.8zm-192 0h22.4c6.4 0 12.8-6.4 12.8-12.8V140.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v198.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h22.4c6.4 0 12.8-6.4 12.8-12.8V204.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v134.4c0 6.4 6.4 12.8 12.8 12.8zM496 400H48V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16zm-387.2-48h22.4c6.4 0 12.8-6.4 12.8-12.8v-70.4c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v70.4c0 6.4 6.4 12.8 12.8 12.8z\" class=\"\"><\/path><\/svg><\/i> <img loading=\"lazy\" decoding=\"async\" width=\"16\" height=\"16\" alt=\"Loading\" src=\"https:\/\/wonghoi.humgar.com\/blog\/wp-content\/plugins\/page-views-count\/ajax-loader-2x.gif\" border=0 \/><\/p><div class=\"pvc_clear\"><\/div>","protected":false},"excerpt":{"rendered":"<p>Namecheap support page explained the process of configuring your dd-wrt router firmware to use Namecheap&#8217;s REST (HTTP URL) update interface to dynamically update the IP of your (sub-)domain. The instruction works, but there are few items which doesn&#8217;t quite make &hellip; <a href=\"https:\/\/wonghoi.humgar.com\/blog\/2021\/07\/12\/namecheap-dynamic-dns-setup-in-dd-wrt\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n<div class=\"pvc_clear\"><\/div>\n<p id=\"pvc_stats_2450\" class=\"pvc_stats all  \" data-element-id=\"2450\" style=\"\"><i class=\"pvc-stats-icon medium\" aria-hidden=\"true\"><svg aria-hidden=\"true\" focusable=\"false\" data-prefix=\"far\" data-icon=\"chart-bar\" role=\"img\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\" class=\"svg-inline--fa fa-chart-bar fa-w-16 fa-2x\"><path fill=\"currentColor\" d=\"M396.8 352h22.4c6.4 0 12.8-6.4 12.8-12.8V108.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v230.4c0 6.4 6.4 12.8 12.8 12.8zm-192 0h22.4c6.4 0 12.8-6.4 12.8-12.8V140.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v198.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h22.4c6.4 0 12.8-6.4 12.8-12.8V204.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v134.4c0 6.4 6.4 12.8 12.8 12.8zM496 400H48V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16zm-387.2-48h22.4c6.4 0 12.8-6.4 12.8-12.8v-70.4c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v70.4c0 6.4 6.4 12.8 12.8 12.8z\" class=\"\"><\/path><\/svg><\/i> <img loading=\"lazy\" decoding=\"async\" width=\"16\" height=\"16\" alt=\"Loading\" src=\"https:\/\/wonghoi.humgar.com\/blog\/wp-content\/plugins\/page-views-count\/ajax-loader-2x.gif\" border=0 \/><\/p>\n<div class=\"pvc_clear\"><\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[44,39],"tags":[],"class_list":["post-2450","post","type-post","status-publish","format-standard","hentry","category-hardware","category-linux"],"_links":{"self":[{"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/posts\/2450","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/comments?post=2450"}],"version-history":[{"count":8,"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/posts\/2450\/revisions"}],"predecessor-version":[{"id":2634,"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/posts\/2450\/revisions\/2634"}],"wp:attachment":[{"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/media?parent=2450"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/categories?post=2450"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/tags?post=2450"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}