usbmodeswitch: Updated to v.1.2.6 from shibby's branch.
[tomato.git] / release / src / router / mdu / mdu.c
blobfc3c2b9aa310ca20da3101156cea75f5348b97b1
1 /*
3 MDU -- Mini DDNS Updater
4 Copyright (C) 2007-2009 Jonathan Zarate
6 Licensed under GNU GPL v2 or later versions.
8 */
10 // #define DEBUG
11 #define _GNU_SOURCE
13 #include <unistd.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <netdb.h>
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <netinet/ip.h>
23 #include <arpa/inet.h>
24 #include <stdarg.h>
25 #include <sys/stat.h>
26 #include <time.h>
28 #include <shared.h>
29 #include <shutils.h>
30 #include <tomato_version.h>
32 #include "md5.h"
33 #include "mssl.h"
37 #ifdef DEBUG
38 #define AGENT "MDU - TEST DDNS CLIENT"
39 #else
40 #define AGENT "MDU - Tomato Firmware " TOMATO_MAJOR "." TOMATO_MINOR
41 #endif
43 #define MAX_OPTION_LENGTH 256
44 #define BLOB_SIZE (4 * 1024)
47 #define M_UNKNOWN_ERROR__D "Unknown error (%d)."
48 #define M_UNKNOWN_RESPONSE__D "Unknown response (%d)."
49 #define M_INVALID_HOST "Invalid hostname."
50 #define M_INVALID_AUTH "Invalid authentication."
51 #define M_INVALID_PARAM__D "Invalid parameter (%d)."
52 #define M_INVALID_PARAM__S "Invalid parameter (%s)."
53 #define M_TOOSOON "Update was too soon or too frequent. Please try again later."
54 #define M_ERROR_GET_IP "Error obtaining IP address."
55 #define M_SAME_IP "The IP address is the same."
56 #define M_DOWN "Server temporarily down or under maintenance."
58 char *blob = NULL;
59 int error_exitcode = 1;
61 int g_argc;
62 char **g_argv;
64 char *f_argv[32];
65 int f_argc = -1;
66 int refresh = 0;
68 static void save_cookie(void);
69 static void update_noip_refresh(void);
72 static void trimamp(char *s)
74 int n;
76 n = strlen(s);
77 if ((n > 0) && (s[--n] == '&')) s[n] = 0;
80 static const char *get_option(const char *name)
82 char *p;
83 int i;
84 int n;
85 FILE *f;
86 const char *c;
87 char s[384];
89 if (f_argc < 0) {
90 f_argc = 0;
91 if ((c = get_option("conf")) != NULL) {
92 if ((f = fopen(c, "r")) != NULL) {
93 while (fgets(s, sizeof(s), f)) {
94 p = s;
95 if ((s[0] == '-') && (s[1] == '-')) p += 2;
96 if ((c = strchr(p, ' ')) != NULL) {
97 n = strlen(p);
98 if (p[n - 1] == '\n') p[n - 1] = 0;
100 n = strlen(c + 1);
101 if (n <= 0) continue;
102 if (n >= MAX_OPTION_LENGTH) exit(88);
104 if ((p = strdup(p)) == NULL) exit(99);
105 f_argv[f_argc++] = p;
106 if (f_argc >= (sizeof(f_argv) / sizeof(f_argv[0]))) break;
109 fclose(f);
114 n = strlen(name);
115 for (i = 0; i < f_argc; ++i) {
116 c = f_argv[i];
117 if ((strncmp(c, name, n) == 0) && (c[n] == ' ')) {
118 return c + n + 1;
122 for (i = 0; i < g_argc; ++i) {
123 p = g_argv[i];
124 if ((p[0] == '-') && (p[1] == '-')) {
125 if (strcmp(p + 2, name) == 0) {
126 ++i;
127 if ((i >= g_argc) || (strlen(g_argv[i]) >= MAX_OPTION_LENGTH)) break;
128 return g_argv[i];
132 return NULL;
136 static const char *get_option_safe(const char *name)
138 return get_option(name) ? : "";
142 static const char *get_option_required(const char *name)
144 const char *p;
146 if ((p = get_option(name)) != NULL) return p;
147 fprintf(stderr, "Required option --%s is missing.\n", name);
148 exit(2);
151 static const char *get_option_or(const char *name, const char *alt)
153 return get_option(name) ? : alt;
156 static int get_option_onoff(const char *name, int def)
158 const char *p;
160 if ((p = get_option(name)) == NULL) return def;
161 if ((strcmp(p, "on") == 0) || (strcmp(p, "1") == 0)) return 1;
162 if ((strcmp(p, "off") == 0) || (strcmp(p, "0") == 0)) return 0;
164 fprintf(stderr, "--%s requires the value off/on or 0/1.\n", name);
165 exit(2);
168 static const char *md5_string(const char *value)
170 static char buf[(MD5_DIGEST_BYTES + 1) * 2];
171 unsigned char digestbuf[MD5_DIGEST_BYTES];
172 int i;
174 md5_buffer(value, strlen(value), digestbuf);
175 for (i = 0; i < MD5_DIGEST_BYTES; i++)
176 sprintf(&buf[i * 2], "%02x", digestbuf[i]);
177 return buf;
181 static void save_msg(const char *s)
183 const char *path;
185 if ((path = get_option("msg")) != NULL) {
186 f_write_string(path, s, FW_NEWLINE, 0);
190 static void error(const char *fmt, ...)
192 va_list args;
193 char s[512];
195 va_start(args, fmt);
196 vsnprintf(s, sizeof(s), fmt, args);
197 s[sizeof(s) - 1] = 0;
198 va_end(args);
200 _dprintf("%s: %s\n", __FUNCTION__, s);
202 printf("%s\n", s);
203 save_msg(s);
204 exit(error_exitcode);
207 static void success_msg(const char *msg)
209 save_cookie();
211 _dprintf("%s\n", __FUNCTION__);
213 printf("%s\n", msg);
214 save_msg(msg);
215 exit(0);
218 static void success(void)
220 success_msg("Update successful.");
225 static const char *get_dump_name(void)
227 #ifdef DEBUG
228 return get_option_or("dump", "/tmp/mdu.txt");
229 #else
230 return get_option("dump");
231 #endif
234 static int _wget(int ssl, const char *host, int port, const char *request, char *buffer, int bufsize, char **body)
236 struct hostent *he;
237 struct sockaddr_in sa;
238 int sd;
239 FILE *f;
240 int i;
241 int trys;
242 char *p;
243 const char *c;
244 struct timeval tv;
246 _dprintf("\n*** %s\n", host);
248 sd = -1; // for gcc warning
250 for (trys = 4; trys > 0; --trys) {
251 _dprintf("_wget trys=%d\n", trys);
253 for (i = 4; i > 0; --i) {
254 if ((he = gethostbyname(host)) != NULL) {
255 if ((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
256 return -1;
258 memset(&sa, 0, sizeof(sa));
259 sa.sin_family = AF_INET;
260 sa.sin_port = htons(port);
261 memcpy(&sa.sin_addr, he->h_addr, sizeof(sa.sin_addr));
263 #ifdef DEBUG
264 struct in_addr ia;
265 ia.s_addr = sa.sin_addr.s_addr;
267 _dprintf("[%s][%d]\n", inet_ntoa(ia), port);
268 _dprintf("connecting...\n");
269 #endif
271 if (connect_timeout(sd, (struct sockaddr *)&sa, sizeof(sa), 10) == 0) {
272 _dprintf("connected\n");
273 break;
275 #ifdef DEBUG
276 perror("connect");
277 #endif
278 close(sd);
279 sleep(2);
282 if (i <= 0) return -1;
284 tv.tv_sec = 10;
285 tv.tv_usec = 0;
286 setsockopt(sd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
287 setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
289 if (ssl) {
290 mssl_init(NULL, NULL);
291 f = ssl_client_fopen(sd);
293 else {
294 f = fdopen(sd, "r+");
296 if (f == NULL) {
297 _dprintf("error opening\n");
298 close(sd);
299 continue;
302 i = strlen(request);
303 if (fwrite(request, 1, i, f) != i) {
304 _dprintf("error writing i=%d\n", i);
305 fclose(f);
306 close(sd);
307 continue;
309 _dprintf("sent request\n");
311 i = fread(buffer, 1, bufsize, f);
312 if (i <= 0) {
313 fclose(f);
314 close(sd);
315 _dprintf("error reading i=%d\n", i);
316 continue;
318 buffer[i] = 0;
320 _dprintf("recvd=[%s], i=%d\n", buffer, i);
322 fclose(f);
323 close(sd);
325 if ((c = get_dump_name()) != NULL) {
326 if ((f = fopen(c, "a")) != NULL) {
327 fprintf(f, "\n[%s:%d]\nREQUEST\n", host, port);
328 fputs(request, f);
329 fputs("\nREPLY\n", f);
330 fputs(buffer, f);
331 fputs("\nEND\n", f);
332 fclose(f);
336 if ((sscanf(buffer, "HTTP/1.%*d %d", &i) == 1) && (i >= 100) && (i <= 999)) {
337 _dprintf("HTTP/1.* i=%d\n", i);
338 if ((p = strstr(buffer, "\r\n\r\n")) != NULL) p += 4;
339 else if ((p = strstr(buffer, "\n\n")) != NULL) p += 2;
340 if (p) {
341 if (body) {
342 *body = p;
343 _dprintf("body=[%s]\n", p);
345 return i;
347 else {
348 _dprintf("!p\n");
353 return -1;
356 static int wget(int ssl, int static_host, const char *host, const char *get, const char *header, int auth, char **body)
358 char *p;
359 int port;
360 char a[512];
361 char b[512];
362 int n;
364 if (!static_host) host = get_option_or("server", host);
366 n = strlen(get);
367 if (header) n += strlen(header);
368 if (n > (BLOB_SIZE - 512)) return -1; // just don't go over 512 below...
370 sprintf(blob,
371 "GET %s HTTP/1.0\r\n"
372 "Host: %s\r\n"
373 "User-Agent: " AGENT "\r\n",
374 get, host);
375 if (auth) {
376 sprintf(a, "%s:%s", get_option_required("user"), get_option_required("pass"));
377 n = base64_encode(a, b, strlen(a));
378 b[n] = 0;
379 sprintf(blob + strlen(blob), "Authorization: Basic %s\r\n", b);
381 if ((header) && ((n = strlen(header)) > 0)) {
382 strcat(blob, header);
383 if (header[n - 1] != '\n') strcat(blob, "\r\n");
385 strcat(blob, "\r\n");
388 _dprintf("blob=[%s]\n", blob);
390 port = ssl ? 443 : 80;
391 strlcpy(a, host, sizeof(a));
392 if ((p = strrchr(a, ':')) != NULL) {
393 *p = 0;
394 if ((n = atoi(p + 1)) > 0) port = n;
397 if ((p = strdup(blob)) == NULL) return -1;
398 n = _wget(ssl, a, port, p, blob, BLOB_SIZE, body);
399 free(p);
401 _dprintf("%s: n=%d\n", __FUNCTION__, n);
402 return n;
407 int read_tmaddr(const char *name, long *tm, char *addr)
409 char s[64];
411 if (f_read_string(name, s, sizeof(s)) > 0) {
412 if (sscanf(s, "%ld,%15s", tm, addr) == 2) {
413 _dprintf("%s: s=%s tm=%ld addr=%s\n", __FUNCTION__, s, *tm, addr);
414 if ((tm > 0) && (inet_addr(addr) != -1)) return 1;
416 else {
417 _dprintf("%s: unknown=%s\n", __FUNCTION__, s);
420 return 0;
423 const char *get_address(int required)
425 char *body;
426 struct in_addr ia;
427 const char *c, *d;
428 char *p, *q;
429 char s[64];
430 char cache_name[64];
431 static char addr[16];
432 long ut, et;
434 if ((c = get_option("addr")) != NULL) {
435 if (*c == '@') {
436 ++c;
437 if ((*c != 0) && (strlen(c) < 20)) {
438 ut = get_uptime();
440 if ((d = get_option("addrcache")) != NULL) strlcpy(cache_name, d, sizeof(cache_name));
441 else sprintf(cache_name, "%s.ip", c);
442 if (read_tmaddr(cache_name, &et, addr)) {
443 if ((et > ut) && ((et - ut) <= (10 * 60))) {
444 _dprintf("%s: Using cached address %s from %s. Expires in %ld seconds.\n", __FUNCTION__, addr, cache_name, et - ut);
445 return addr;
449 if (strcmp(c, "dyndns") == 0) {
450 if ((wget(0, 1, "checkip.dyndns.org:8245", "/", NULL, 0, &body) != 200) &&
451 (wget(0, 1, "checkip.dyndns.org", "/", NULL, 0, &body) != 200)) {
452 // Current IP Address: 1.2.3.4
453 error(M_ERROR_GET_IP);
456 else if (strcmp(c, "zoneedit") == 0 || strcmp(c, "szoneedit") == 0) {
457 if (wget(0, 1, "dynamic.zoneedit.com", "/checkip.html", NULL, 0, &body) != 200) {
458 // Current IP Address: 1.2.3.4
459 error(M_ERROR_GET_IP);
462 else if (strcmp(c, "tzo") == 0) {
463 if ((wget(0, 1, "echo.tzo.com:21333", "/ip.shtml", NULL, 0, &body) != 200) &&
464 (wget(0, 1, "echo.tzo.com", "/ip.shtml", NULL, 0, &body) != 200)) {
465 // IPAddress:1.2.3.4
466 error(M_ERROR_GET_IP);
469 else if (strcmp(c, "noip") == 0) {
470 if (wget(0, 1, "ip1.dynupdate.no-ip.com", "/", NULL, 0, &body) != 200) {
471 // 1.2.3.4
472 error(M_ERROR_GET_IP);
475 else if (strcmp(c, "dnsomatic") == 0) {
476 if (wget(0, 1, "myip.dnsomatic.com", "/", NULL, 0, &body) != 200) {
477 // 1.2.3.4
478 error(M_ERROR_GET_IP);
482 if ((p = strstr(body, "Address:")) != NULL) {
483 // dyndns, zoneedit, tzo
484 p += 8; // note: tzo doesn't have a space
486 else {
487 // noip, dnsomatic
488 p = body;
491 while (*p == ' ') ++p;
493 q = p;
494 while (((*q >= '0') && (*q <= '9')) || (*q == '.')) ++q;
495 *q = 0;
497 if ((ia.s_addr = inet_addr(p)) != -1) {
498 q = inet_ntoa(ia);
499 sprintf(s, "%ld,%s", ut + (10 * 60), p);
500 f_write_string(cache_name, s, 0, 0);
502 _dprintf("%s: saved '%s'\n", __FUNCTION__, s);
503 return p;
506 error(M_ERROR_GET_IP);
508 return c;
511 return required ? get_option_required("addr") : NULL;
514 static void append_addr_option(char *buffer, const char *format)
516 const char *c;
518 if ((c = get_address(0)) != NULL) {
519 sprintf(buffer + strlen(buffer), format, c);
523 // -----------------------------------------------------------------------------
528 DNS Update API
529 http://www.dyndns.com/developers/specs/
533 DynDNS:
534 http: 80, 8245
535 https: 443
537 http://test:test@members.dyndns.org/nic/update?system=dyndns&hostname=test.shacknet.nu
539 GET /nic/update?
540 system=statdns&
541 hostname=yourhost.ourdomain.ext,yourhost2.dyndns.org&
542 myip=ipaddress&
543 wildcard=OFF&
544 mx=mail.exchanger.ext&
545 backmx=NO&
546 offline=NO
547 HTTP/1.0
548 Host: members.dyndns.org
549 Authorization: Basic username:pass
550 User-Agent: Company - Device - Version Number
553 static void update_dua(const char *type, int ssl, const char *server, const char *path, int reqhost)
555 const char *p;
556 char query[2048];
557 int r;
558 char *body;
560 // +opt
561 sprintf(query, "%s?", path ? path : get_option_required("path"));
563 // +opt
564 if (type) sprintf(query + strlen(query), "system=%s&", type);
566 // +opt
567 p = reqhost ? get_option_required("host") : get_option("host");
568 if (p) sprintf(query + strlen(query), "hostname=%s&", p);
570 // +opt
571 if (((p = get_option("mx")) != NULL) && (*p)) {
572 sprintf(query + strlen(query),
573 "mx=%s&"
574 "backmx=%s&",
576 (get_option_onoff("backmx", 0)) ? "YES" : "NO");
579 // +opt
580 append_addr_option(query, "myip=%s&");
582 if (get_option_onoff("wildcard", 0)) {
583 strcat(query, "wildcard=ON");
586 trimamp(query);
588 r = wget(ssl, 0, server ? server : get_option_required("server"), query, NULL, 1, &body);
589 switch (r) {
590 case 200:
591 if ((strstr(body, "dnserr")) || (strstr(body, "911"))) {
592 error_exitcode = 2;
593 error(M_DOWN);
596 if ((strstr(body, "badsys")) || (strstr(body, "numhost")) || (strstr(body, "ILLEGAL"))) {
597 error(M_INVALID_PARAM__D, -1);
599 if (strstr(body, "badagent")) {
600 error(M_INVALID_PARAM__D, -2);
602 if ((strstr(body, "badauth")) || (strstr(body, "NOACCESS")) || (strstr(body, "!donator"))) {
603 error(M_INVALID_AUTH);
605 if ((strstr(body, "notfqdn")) || (strstr(body, "!yours")) || strstr(body, "nohost") ||
606 (strstr(body, "abuse")) || strstr(body, "NOSERVICE")) {
607 error(M_INVALID_HOST);
609 if (strstr(body, "TOOSOON")) {
610 error(M_TOOSOON);
613 if (strstr(body, "nochg")) {
614 if ((strcmp(get_option("service"), "noip") == 0) && (refresh)) {
615 update_noip_refresh();
617 success();
618 return;
621 if ((strstr(body, "good")) || (strstr(body, "NOERROR"))) {
622 success();
623 return;
626 error(M_UNKNOWN_RESPONSE__D, -1);
627 break;
628 case 401:
629 error(M_INVALID_AUTH);
630 break;
632 error(M_UNKNOWN_ERROR__D, r);
638 namecheap.com
639 http://namecheap.simplekb.com/kb.aspx?show=article&articleid=27&categoryid=22
643 http://dynamicdns.park-your-domain.com/update?host=host_name&domain=domain.com&password=domain_password[&ip=your_ip]
645 ok response:
647 "HTTP/1.1 200 OK
650 <?xml version="1.0"?>
651 <interface-response>
652 <IP>12.123.123.12</IP>
653 <Command>SETDNSHOST</Command>
654 <Language>eng</Language>
655 <ErrCount>0</ErrCount>
656 <ResponseCount>0</ResponseCount>
657 <MinPeriod>1</MinPeriod>
658 <MaxPeriod>10</MaxPeriod>
659 <Server>Reseller9</Server>
660 <Site>Namecheap</Site>
661 <IsLockable>True</IsLockable>
662 <IsRealTimeTLD>True</IsRealTimeTLD>
663 <TimeDifference>+03.00</TimeDifference>
664 <ExecTime>0.0625</ExecTime>
665 <Done>true</Done>
666 <debug><![CDATA[]]></debug>
667 </interface-response>"
670 error response:
672 "HTTP/1.1 200 OK
675 <?xml version="1.0"?>
676 <interface-response>
677 <Command>SETDNSHOST</Command>
678 <Language>eng</Language>
679 <ErrCount>1</ErrCount>
680 <errors>
681 <Err1>Passwords do not match</Err1>
682 </errors>
683 <ResponseCount>1</ResponseCount>
684 <responses>
685 <response>
686 <ResponseNumber>304156</ResponseNumber>
687 <ResponseString>Validation error; invalid ; password</ResponseString>
688 </response>
689 </responses>
690 <MinPeriod>1</MinPeriod>
691 <MaxPeriod>10</MaxPeriod>
692 <Server>Reseller1</Server>
693 <Site></Site>
694 <IsLockable>True</IsLockable>
695 <IsRealTimeTLD>True</IsRealTimeTLD>
696 <TimeDifference>+03.00</TimeDifference>
697 8<ExecTime>0.0625</ExecTime>
698 <Done>true</Done>
699 <debug><![CDATA[]]></debug>
700 </interface-response>"
703 static void update_namecheap(void)
705 int r;
706 char *p;
707 char *q;
708 char *body;
709 char query[2048];
711 // +opt +opt +opt
712 sprintf(query, "/update?host=%s&domain=%s&password=%s",
713 get_option_required("host"), get_option("user") ? : get_option_required("domain"), get_option_required("pass"));
715 // +opt
716 append_addr_option(query, "&ip=%s");
718 r = wget(0, 0, "dynamicdns.park-your-domain.com", query, NULL, 0, &body);
719 if (r == 200) {
720 if (strstr(body, "<ErrCount>0<") != NULL) {
721 success();
723 if ((p = strstr(body, "<Err1>")) != NULL) {
724 p += 6;
725 if ((q = strstr(p, "</")) != NULL) {
726 *q = 0;
727 if ((q - p) >= 64) p[64] = 0;
728 error("%s", p);
731 error(M_UNKNOWN_RESPONSE__D, -1);
734 error(M_UNKNOWN_ERROR__D, r);
740 eNom
741 http://www.enom.com/help/faq_dynamicdns.asp
745 good:
746 ;URL Interface<br>
747 ;Machine is Reseller5<br>
748 IP=127.0.0.1
749 Command=SETDNSHOST
750 Language=eng
752 ErrCount=0
753 ResponseCount=0
754 MinPeriod=1
755 MaxPeriod=10
756 Server=Reseller5
757 Site=eNom
758 IsLockable=True
759 IsRealTimeTLD=True
760 TimeDifference=+08.00
761 ExecTime=0.500
763 bad:
764 ;URL Interface<br>
765 ;Machine is Reseller4<br>
766 -Command=SETDNSHOST
767 Language=eng
768 ErrCount=1
769 Err1=Passwords do not match
770 ResponseCount=1
771 ResponseNumber1=304156
772 ResponseString1=Validation error; invalid ; password
773 MinPeriod=1
774 MaxPeriod=10
775 Server=Reseller4
776 Site=
777 IsLockable=True
778 IsRealTimeTLD=True
779 TimeDifference=+08.00
780 ExecTime=0.235
781 Done=true
784 static void update_enom(void)
786 int r;
787 char *p;
788 char *q;
789 char *body;
790 char query[2048];
792 // http://dynamic.name-services.com/interface.asp?Command=SetDNSHost&HostName=test&Zone=test.com&Address=1.2.3.4&DomainPassword=password
794 // +opt +opt +opt
795 sprintf(query, "/interface.asp?Command=SetDNSHost&HostName=%s&Zone=%s&DomainPassword=%s",
796 get_option_required("host"), get_option("user") ? : get_option_required("domain"), get_option_required("pass"));
798 // +opt
799 append_addr_option(query, "&Address=%s");
801 r = wget(0, 0, "dynamic.name-services.com", query, NULL, 0, &body);
802 if (r == 200) {
803 if (strstr(body, "ErrCount=0") != NULL) {
804 success();
806 if ((p = strstr(body, "Err1=")) != NULL) {
807 p += 5;
808 if ((q = strchr(p, '\n')) != NULL) {
809 *q = 0;
810 if ((q - p) >= 64) p[64] = 0;
811 if ((q = strchr(p, '\r')) != NULL) *q = 0;
812 error("%s", p);
815 error(M_UNKNOWN_RESPONSE__D, -1);
818 error(M_UNKNOWN_ERROR__D, r);
827 dnsExit
828 http://www.dnsexit.com/Direct.sv?cmd=ipClients
832 "HTTP/1.1 200 OK
835 HTTP/1.1 200 OK
836 0=Success"
838 " HTTP/1.1 200 OK
839 11=fail to find foo.bar.com"
841 " HTTP/1.1 200 OK
842 4=Update too often. Please wait at least 8 minutes since the last update"
844 " HTTP/1.1 200 OK" <-- extra in body?
847 static void update_dnsexit(void)
849 int r;
850 char *body;
851 char query[2048];
853 // +opt +opt +opt
854 sprintf(query, "/RemoteUpdate.sv?action=edit&login=%s&password=%s&host=%s",
855 get_option_required("user"), get_option_required("pass"), get_option_required("host"));
857 // +opt
858 append_addr_option(query, "&myip=%s");
860 r = wget(0, 0, "www.dnsexit.com", query, NULL, 0, &body);
861 if (r == 200) {
862 // (\d+)=.+
864 if ((strstr(body, "0=Success") != NULL) || (strstr(body, "1=IP") != NULL)) {
865 success();
867 if ((strstr(body, "2=Invalid") != NULL) || (strstr(body, "3=User") != NULL)) {
868 error(M_INVALID_AUTH);
870 if ((strstr(body, "10=Host") != NULL) || (strstr(body, "11=fail") != NULL)) {
871 error(M_INVALID_HOST);
873 if (strstr(body, "4=Update") != NULL) {
874 error(M_TOOSOON);
877 error(M_UNKNOWN_RESPONSE__D, -1);
880 error(M_UNKNOWN_ERROR__D, r);
886 no-ip.com
890 Example response:
892 mytest.testdomain.com:4
896 static void update_noip(void)
898 int r;
899 const char *c;
900 char *body;
901 char query[2048];
903 // +opt +opt
904 sprintf(query, "/dns?username=%s&password=%s&",
905 get_option_required("user"), get_option_required("pass"));
907 // +opt
908 if (((c = get_option("group")) != NULL) && (*c)) {
909 sprintf(query + strlen(query), "group=%s", c);
911 else {
912 sprintf(query + strlen(query), "hostname=%s", get_option_required("host"));
915 // +opt
916 append_addr_option(query, "&ip=%s");
918 r = wget(0, 0, "dynupdate.no-ip.com", query, NULL, 0, &body);
919 if (r == 200) {
920 if ((c = strchr(body, ':')) != NULL) {
921 ++c;
922 r = atoi(c);
923 switch(r) {
924 case 0: // host same addr
925 while (*c == ' ') ++c;
926 if (*c != '0') {
927 error(M_UNKNOWN_RESPONSE__D, -1);
928 break;
930 // drop
931 case 12: // group same addr
932 case 1: // host updated
933 case 11: // group updated
934 success();
935 break;
936 case 2: // invalid hostname
937 case 10: // invalid group
938 case 6: // account disabled
939 case 8: // disabled hostname
940 error(M_INVALID_HOST);
941 break;
942 case 3: // invalid password
943 case 4: // invalid username
944 error(M_INVALID_AUTH);
945 break;
946 case 5:
947 error(M_TOOSOON);
948 break;
949 case 7: // invalid IP supplied
950 case 99: // client banned
951 case 100: // invalid parameter
952 case 9: // redirect type
953 case 13: //
954 error(M_INVALID_PARAM__D, r);
955 break;
956 default:
957 error(M_UNKNOWN_RESPONSE__D, r);
958 break;
961 else {
962 r = -200;
966 error(M_UNKNOWN_ERROR__D, r);
973 No-IP.com -- refresh
975 http://www.no-ip.com/hostactive.php?host=<host>&domain=<dom>
978 static void update_noip_refresh(void)
980 char query[2048];
981 char host[256];
982 char *domain;
984 strlcpy(host, get_option_required("host"), sizeof(host));
985 if ((domain = strchr(host, '.')) != NULL) {
986 *domain++ = 0;
989 sprintf(query, "/hostactive.php?host=%s", host);
990 if (domain) sprintf(query + strlen(query), "&domain=%s", domain);
992 wget(0, 1, "www.no-ip.com", query, NULL, 0, NULL);
993 // return ignored
1000 ieserver.net
1001 http://www.ieserver.net/tools.html
1005 http://ieserver.net/cgi-bin/dip.cgi?username=XXX&domain=XXX&password=XXX&updatehost=1
1007 username = hostname
1008 domain = dip.jp, fam.cx, etc.
1012 static void update_ieserver(void)
1014 int r;
1015 char *body;
1016 char query[2048];
1017 char *p;
1019 // +opt +opt
1020 sprintf(query, "/cgi-bin/dip.cgi?username=%s&domain=%s&password=%s&updatehost=1",
1021 get_option_required("user"), get_option_required("host"), get_option_required("pass"));
1023 r = wget(0, 0, "ieserver.net", query, NULL, 0, &body);
1024 if (r == 200) {
1025 if (strstr(body, "<title>Error") != NULL) {
1027 // <p>yuuzaa na mata pasuwoodo (EUC-JP)
1028 if ((p = strstr(body, "<p>\xA5\xE6\xA1\xBC\xA5\xB6\xA1\xBC")) != NULL) { // <p>user
1029 error(M_INVALID_AUTH);
1032 error(M_UNKNOWN_RESPONSE__D, -1);
1035 success();
1038 error(M_UNKNOWN_ERROR__D, r);
1045 dyns.cx
1046 http://www.dyns.cx/documentation/technical/protocol/v1.1.php
1050 "HTTP/1.1 200 OK
1053 401 testuser not authenticated"
1057 static void update_dyns(void)
1059 int r;
1060 char *body;
1061 char query[2048];
1064 // +opt +opt +opt
1065 sprintf(query, "/postscript011.php?username=%s&password=%s&host=%s",
1066 get_option_required("user"), get_option_required("pass"), get_option_required("host"));
1068 // +opt
1069 append_addr_option(query, "&ip=%s");
1071 #if 0
1072 sprintf(query + strlen(query), "&devel=1");
1073 #endif
1075 r = wget(0, 0, "www.dyns.net", query, NULL, 0, &body);
1076 if (r == 200) {
1077 while ((*body == ' ') || (*body == '\r') || (*body == '\n')) {
1078 ++body;
1080 switch (r = atoi(body)) {
1081 case 200:
1082 success();
1083 break;
1084 case 400:
1085 error(M_INVALID_PARAM__D, r);
1086 break;
1087 case 401:
1088 error(M_INVALID_AUTH);
1089 break;
1090 case 402:
1091 error(M_TOOSOON);
1092 break;
1093 case 405:
1094 error(M_INVALID_HOST);
1095 break;
1098 error(M_UNKNOWN_RESPONSE__D, r);
1101 error(M_UNKNOWN_ERROR__D, r);
1109 http://www.tzo.com/
1113 "HTTP/1.1 200 OK
1116 <td valign="top"><font size="4">Congratulations!
1117 You've successfully signed on with TZO.<br>
1118 </font><h1 align="center"><font size="2"
1119 face="Verdana">Here's information about your
1120 account:</font><br>
1121 </h1>
1122 <h3 align="center"><font face="Verdana"><p>TZO Name: foobartest.tzo.com<br>
1123 IP Address: 1.2.3.4<br>
1124 Expiration: 2007-01-01 1:01:01</p>
1125 </font> <br>
1127 ..."
1130 Invalid hostname or password:
1131 "HTTP/1.1 200 OK
1134 <td valign="top"><font size="4">Congratulations!
1135 You've successfully signed on with TZO.<br>
1136 </font><h1 align="center"><font size="2"
1137 face="Verdana">Here's information about your
1138 account:</font><br>
1139 </h1>
1140 <h3 align="center"><font face="Verdana"><p>Error=bad authentication
1141 </p>
1142 ..."
1145 Update too soon:
1146 "...
1147 face="Verdana">Here's information about your
1148 account:</font><br>
1149 </h1>
1150 <h3 align="center"><font face="Verdana"><p>Error=Try again later. Please wait at least 1 minute before any additional requests.1.2.3.4
1151 </p>
1152 </font> <br>
1153 ..."
1156 static void update_tzo(void)
1158 int r;
1159 char *body;
1160 char query[2048];
1161 char *p;
1163 // +opt +opt +opt
1164 sprintf(query, "/webclient/signedon.html?TZOName=%s&Email=%s&TZOKey=%s",
1165 get_option_required("host"), get_option_required("user"), get_option_required("pass"));
1167 // +opt
1168 append_addr_option(query, "&IPAddress=%s");
1170 r = wget(0, 0, "cgi.tzo.com", query, NULL, 0, &body);
1171 if (r == 200) {
1172 if ((p = strstr(body, "Error=")) != NULL) {
1173 p += 6;
1174 if (strncmp(p, "bad auth", 8) == 0) {
1175 error(M_INVALID_AUTH);
1177 if (strncmp(p, "Try again", 9) == 0) {
1178 error(M_TOOSOON);
1180 error(M_UNKNOWN_ERROR__D, -1);
1182 success();
1185 error(M_UNKNOWN_ERROR__D, r);
1193 ZoneEdit
1194 http://www.zoneedit.com/doc/dynamic.html
1198 "HTTP/1.1 200 OK
1200 <SUCCESS CODE="200" TEXT="Update succeeded." ZONE="test123.com" HOST="www.test123.com" IP="1.2.3.4">"
1202 "<ERROR CODE="707" TEXT="Duplicate updates for the same host/ip, adjust client settings" ZONE="testexamplesite4321.com" HOST="test.testexamplesite4321.com">"
1204 "HTTP/1.1 401 Authorization Required
1206 <title>Authentication Failed </title>"
1208 ERROR CODE="[701-799]" TEXT="Description of the error" ZONE="Zone that Failed"
1209 ERROR CODE="702" TEXT="Update failed." ZONE="%zone%"
1210 ERROR CODE="703" TEXT="one of either parameters 'zones' or 'host' are required."
1211 ERROR CODE="705" TEXT="Zone cannot be empty" ZONE="%zone%"
1212 ERROR CODE="707" TEXT="Duplicate updates for the same host/ip, adjust client settings" ZONE="%zone%"
1213 ERROR CODE="707" TEXT="Too frequent updates for the same host, adjust client settings" ZONE="%zone%"
1214 ERROR CODE="704" TEXT="Zone must be a valid 'dotted' internet name." ZONE="%zone%"
1215 ERROR CODE="701" TEXT="Zone is not set up in this account." ZONE="%zone%"
1216 ERROR CODE="708" TEXT="Login/authorization error"
1217 SUCCESS CODE="[200-201]" TEXT="Description of the success" ZONE="Zone that Succeeded"
1218 SUCCESS CODE="200" TEXT="Update succeeded." ZONE="%zone%" IP="%dnsto%"
1219 SUCCESS CODE="201" TEXT="No records need updating." ZONE="%zone%"
1222 static void update_zoneedit(int ssl)
1224 int r;
1225 char *body;
1226 char *c;
1227 char query[2048];
1229 // +opt
1230 sprintf(query, "/auth/dynamic.html?host=%s", get_option_required("host"));
1232 // +opt
1233 append_addr_option(query, "&dnsto=%s");
1235 r = wget(ssl, 0, "dynamic.zoneedit.com", query, NULL, 1, &body);
1236 switch (r) {
1237 case 200:
1238 if (strstr(body, "<SUCCESS CODE")) {
1239 success();
1241 if ((c = strstr(body, "<ERROR CODE=\"")) != NULL) {
1242 r = atoi(c + 13);
1243 switch (r) {
1244 case 701: // invalid "zone"
1245 error(M_INVALID_HOST);
1246 break;
1247 case 707: // update is the same ip address? / too frequent updates
1248 if (strstr(c, "Duplicate") != NULL) success();
1249 else error(M_TOOSOON);
1250 break;
1251 case 708: // authorization error
1252 error(M_INVALID_AUTH);
1253 break;
1255 error(M_UNKNOWN_RESPONSE__D, r);
1257 error(M_UNKNOWN_RESPONSE__D, -1);
1258 break;
1259 case 401:
1260 error(M_INVALID_AUTH);
1261 break;
1264 error(M_UNKNOWN_ERROR__D, r);
1270 FreeDNS.afraid.org
1275 http://freedns.afraid.org/dynamic/update.php?XXXXXXXXXXYYYYYYYYYYYZZZZZZZ1111222
1277 "HTTP/1.0 200 OK
1280 ERROR: Address 1.2.3.4 has not changed."
1282 "Updated 1 host(s) foobar.mooo.com to 1.2.3.4 in 1.234 seconds"
1284 "ERROR: Missing S/key and DataID, check your update URL."
1286 "fail, make sure you own this record, and the address does not already equal 1.2.3.4"
1291 static void update_afraid(void)
1293 int r;
1294 char *body;
1295 char query[2048];
1297 // +opt
1298 sprintf(query, "/dynamic/update.php?%s", get_option_required("ahash"));
1300 r = wget(0, 0, "freedns.afraid.org", query, NULL, 0, &body);
1301 if (r == 200) {
1302 if ((strstr(body, "ERROR") != NULL) || (strstr(body, "fail") != NULL)) {
1303 if (strstr(body, "has not changed") != NULL) {
1304 success();
1306 error(M_INVALID_AUTH);
1308 else if ((strstr(body, "Updated") != NULL) && (strstr(body, "host") != NULL)) {
1309 success();
1311 else {
1312 error(M_UNKNOWN_RESPONSE__D, -1);
1316 error(M_UNKNOWN_ERROR__D, r);
1321 everydns.net
1323 HTTP/1.1 200 OK
1324 Server: Apache
1325 X-Powered-By: PHP/5.0.1-dev
1326 Connection: close
1327 Content-Type: text/html; charset=utf-8
1329 Authentication given
1330 Authentication failed: Bad Username/password
1331 Exit code: 2
1334 static void update_everydns(void)
1336 int r;
1337 char *body;
1338 char query[2048];
1339 const char *p;
1341 strcpy(query, "/index.php?ver=0.1");
1342 append_addr_option(query, "&ip=%s");
1344 p = get_option("host");
1345 if (p) sprintf(query + strlen(query), "&domain=%s", p);
1347 r = wget(0, 0, "dyn.everydns.net", query, NULL, 1, &body);
1348 if (r == 200) {
1349 if ((p = strstr(body, "Exit code:")) != NULL) {
1350 r = atoi(p + 10);
1351 switch (r) {
1352 case 0:
1353 success();
1354 break;
1355 case 2:
1356 error(M_INVALID_AUTH);
1357 break;
1358 default:
1359 error(M_UNKNOWN_RESPONSE__D, r);
1360 break;
1363 error(M_UNKNOWN_RESPONSE__D, -1);
1366 error(M_UNKNOWN_ERROR__D, r);
1372 miniDNS.net
1373 http://www.minidns.net/areg.php?opcode=ADD&host=bar.minidns.net&username=foo&password=topsecret&ip=1.2.3.4
1377 "okay. BAR.MINIDNS.NET mapped to 1.2.3.4."
1378 "auth_fail. Incorrect username/password/hostname."
1379 "auth_fail. Host name format error."
1382 static void update_minidns(void)
1384 int r;
1385 char *body;
1386 char query[2048];
1388 // +opt +opt +opt
1389 sprintf(query, "/areg.php?opcode=ADD&host=%s&username=%s&password=%s",
1390 get_option_required("host"),
1391 get_option_required("user"),
1392 get_option_required("pass"));
1394 // +opt
1395 append_addr_option(query, "&ip=%s");
1397 r = wget(0, 0, "www.minidns.net", query, NULL, 1, &body);
1398 if (r == 200) {
1399 if (strstr(body, "okay.") != NULL) {
1400 success();
1402 else if (strstr(body, "Host name format error") != NULL) {
1403 error(M_INVALID_HOST);
1405 else if (strstr(body, "auth_fail") != NULL) {
1406 error(M_INVALID_AUTH);
1408 else {
1409 error(M_UNKNOWN_RESPONSE__D, -1);
1413 error(M_UNKNOWN_ERROR__D, r);
1419 editdns.net
1420 http://www.editdns.net/
1422 source: Keith M.
1426 http://DynDNS.EditDNS.net/api/dynLinux.php?p=XXX&r=XXX
1428 p = password
1429 r = hostname
1432 static void update_editdns(void)
1434 int r;
1435 char *body;
1436 char query[2048];
1438 // +opt +opt
1439 sprintf(query, "/api/dynLinux.php?p=%s&r=%s",
1440 get_option_required("pass"), get_option_required("host"));
1442 r = wget(0, 1, "DynDNS.EditDNS.net", query, NULL, 0, &body);
1443 if (r == 200) {
1444 if (strstr(body, "Record has been updated") != NULL) {
1445 success();
1447 if (strstr(body, "Record already exists") != NULL) {
1448 error(M_SAME_IP);
1450 else if (strstr(body, "Invalid Username") != NULL) {
1451 error(M_INVALID_AUTH);
1453 else if (strstr(body, "Invalid DynRecord") != NULL) {
1454 error(M_INVALID_HOST);
1456 else {
1457 error(body);
1461 error(M_UNKNOWN_ERROR__D, r);
1468 HE.net IPv6 TunnelBroker
1469 https://ipv4.tunnelbroker.net/ipv4_end.php?ip=$IPV4ADDR&pass=$MD5PASS&apikey=$USERID&tid=$TUNNELID
1473 "HTTP/1.1 200 OK
1476 Good responses:
1477 +OK: Tunnel endpoint updated to: X.X.X.X
1479 Bad responses:
1480 -ERROR: This tunnel is already associated with this IP address. Please try and limit your updates to IP changes.
1481 -ERROR: Invalid API key or password
1482 -ERROR: Tunnel not found
1483 -ERROR: IP is not in a valid format
1484 -ERROR: IP is blocked. (RFC1918 Private Address Space)
1485 -ERROR: IP is not ICMP pingable. Please make sure ICMP is not blocked. If you are blocking ICMP, please allow 66.220.2.74 through your firewall.
1486 -ERROR: Missing parameter(s).
1488 static void update_heipv6tb(void)
1490 int r;
1491 char *body, *p;
1492 const char *serr = "-ERROR: ";
1493 char query[2048];
1495 // +opt +opt +opt
1496 sprintf(query, "/ipv4_end.php?pass=%s&apikey=%s&tid=%s",
1497 md5_string(get_option_required("pass")),
1498 get_option_required("user"),
1499 get_option_required("host"));
1501 // +opt
1502 append_addr_option(query, "&ip=%s");
1504 r = wget(1, 0, "ipv4.tunnelbroker.net", query, NULL, 0, &body);
1505 if (r == 200) {
1506 if (strstr(body, "+OK:") != NULL) {
1507 success();
1510 p = strstr(body, serr);
1511 if (p != NULL) {
1512 p += strlen(serr);
1513 if (p != NULL) {
1514 if (strstr(p, "already associated with this IP") != NULL)
1515 success_msg(p);
1516 else
1517 error(p);
1521 error(M_UNKNOWN_RESPONSE__D, -1);
1524 error(M_UNKNOWN_ERROR__D, r);
1531 wget/custom
1534 static void update_wget(void)
1536 int r;
1537 char *c;
1538 char url[256];
1539 char s[256];
1540 char he[256];
1541 char *header;
1542 int https;
1543 char *host;
1544 char path[256];
1545 char *p;
1546 char *body;
1548 // http://user:pass@domain:port/path?query
1549 // https://user:pass@domain:port/path?query
1551 strcpy(url, get_option_required("url"));
1552 https = 0;
1553 host = url + 7;
1554 if (strncasecmp(url, "https://", 8) == 0) {
1555 https = 1;
1556 ++host;
1558 else if (strncasecmp(url, "http://", 7) != 0) {
1559 error(M_INVALID_PARAM__S, "url");
1562 if ((p = strchr(host, '/')) == NULL) {
1563 error(M_INVALID_PARAM__S, "url");
1565 strcpy(path, p);
1566 *p = 0;
1568 if ((c = strstr(path, "@IP")) != NULL) {
1569 strcpy(s, c + 3);
1570 strcpy(c, get_address(1));
1571 strcat(c, s);
1574 if ((c = strrchr(host, '@')) != NULL) {
1575 *c = 0;
1576 s[base64_encode(host, s, c - host)] = 0;
1577 sprintf(he, "Authorization: Basic %s\r\n", s);
1578 header = he;
1579 host = c + 1;
1581 else {
1582 header = NULL;
1585 r = wget(https, 1, host, path, header, 0, &body);
1586 switch (r) {
1587 case 200:
1588 case 302: // redirect -- assume ok
1589 if (body && *body) success_msg((char *)body);
1590 else success();
1591 break;
1592 case 401:
1593 error(M_INVALID_AUTH);
1594 break;
1597 error(M_UNKNOWN_ERROR__D, r);
1600 // -----------------------------------------------------------------------------
1604 static void check_cookie(void)
1606 const char *c;
1607 char addr[16];
1608 long tm;
1610 if (((c = get_option("cookie")) == NULL) || (!read_tmaddr(c, &tm, addr))) {
1611 _dprintf("%s: no cookie\n", __FUNCTION__);
1612 refresh = 1;
1613 return;
1616 if ((c = get_address(0)) == NULL) {
1617 _dprintf("%s: no address specified\n", __FUNCTION__);
1618 return;
1620 if (strcmp(c, addr) != 0) {
1621 _dprintf("%s: address is different (%s != %s)\n", __FUNCTION__, c, addr);
1622 return;
1625 #if 0
1626 long now;
1627 long u;
1629 now = time(NULL);
1630 if ((now < Y2K) || (now < tm)) {
1631 _dprintf("%s: time rolled back (now=%ld, tm=%ld)\n", __FUNCTION__, now, tm);
1632 return;
1634 tm = now - tm;
1636 _dprintf("%s: addr=%s tm=%ld (relative)\n", __FUNCTION__, addr, tm);
1638 if ((c = get_option("maxtime")) != NULL) {
1639 u = strtol(c, NULL, 0);
1640 if (u > 0) {
1641 if (tm > u) {
1642 _dprintf("%s: %s expired (%ld > %ld)\n", __FUNCTION__, addr, tm, u);
1643 return;
1645 _dprintf("%s: maxtime=%ld tm=%ld\n", __FUNCTION__, u, tm);
1647 puts(M_TOOSOON);
1648 exit(3);
1652 if ((c = get_option("mintime")) != NULL) {
1653 u = strtol(c, NULL, 0);
1654 if ((u > 0) && (tm < u)) {
1655 _dprintf("%s: %s recently updated (%ld < %ld)\n", __FUNCTION__, addr, tm, u);
1657 puts(M_TOOSOON);
1658 exit(3);
1662 #endif
1664 puts(M_SAME_IP);
1665 exit(3);
1668 static void save_cookie(void)
1670 const char *cookie;
1671 const char *c;
1672 long now;
1673 char s[256];
1675 now = time(NULL);
1676 if (now < Y2K) {
1677 _dprintf("%s: no time", __FUNCTION__);
1678 return;
1681 if ((cookie = get_option("cookie")) == NULL) {
1682 _dprintf("%s: no cookie\n", __FUNCTION__);
1683 return;
1686 if ((c = get_address(0)) == NULL) {
1687 _dprintf("%s: no address specified\n", __FUNCTION__);
1688 return;
1691 sprintf(s, "%ld,%s", now, c);
1692 f_write_string(cookie, s, FW_NEWLINE, 0);
1694 _dprintf("%s: cookie=%s\n", __FUNCTION__, s);
1697 int main(int argc, char *argv[])
1699 const char *p;
1701 g_argc = argc;
1702 g_argv = argv;
1704 printf("MDU\nCopyright (C) 2007-2009 Jonathan Zarate\n\n");
1705 _dprintf("DEBUG\n");
1707 if ((blob = malloc(BLOB_SIZE)) == NULL) {
1708 return 1;
1711 mkdir("/var/lib/mdu", 0700);
1712 chdir("/var/lib/mdu");
1714 if ((p = get_dump_name()) != NULL) {
1715 unlink(p);
1718 check_cookie();
1720 p = get_option_required("service");
1721 if (strcmp(p, "dua") == 0) {
1722 update_dua("dyndns", 0, NULL, NULL, 1);
1724 else if (strcmp(p, "duas") == 0) {
1725 update_dua("dyndns", 1, NULL, NULL, 1);
1727 else if (strcmp(p, "dyndns") == 0) {
1728 // test ok 9/14 -- zzz
1729 update_dua("dyndns", 0, "members.dyndns.org", "/nic/update", 1);
1731 else if (strcmp(p, "dyndns-static") == 0) {
1732 // test ok 9/14 -- zzz
1733 update_dua("statdns", 0, "members.dyndns.org", "/nic/update", 1);
1735 else if (strcmp(p, "dyndns-custom") == 0) {
1736 // test ok 9/14 -- zzz
1737 update_dua("custom", 0, "members.dyndns.org", "/nic/update", 1);
1739 else if (strcmp(p, "sdyndns") == 0) {
1740 update_dua("dyndns", 1, "members.dyndns.org", "/nic/update", 1);
1742 else if (strcmp(p, "sdyndns-static") == 0) {
1743 update_dua("statdns", 1, "members.dyndns.org", "/nic/update", 1);
1745 else if (strcmp(p, "sdyndns-custom") == 0) {
1746 update_dua("custom", 1, "members.dyndns.org", "/nic/update", 1);
1748 else if (strcmp(p, "easydns") == 0) {
1749 // no account, test output ok, test 401 error parse ok 9/15 -- zzz
1750 update_dua(NULL, 0, "members.easydns.com", "/dyn/dyndns.php", 1);
1752 else if (strcmp(p, "seasydns") == 0) {
1753 update_dua(NULL, 1, "members.easydns.com", "/dyn/dyndns.php", 1);
1755 else if (strcmp(p, "3322") == 0) {
1756 // no account, test output ok, test 401 error parse ok 9/16 -- zzz
1757 update_dua(NULL, 0, "members.3322.org", "/dyndns/update", 1);
1759 else if (strcmp(p, "3322-static") == 0) {
1760 // no account, test output ok, test 401 error parse ok 9/16 -- zzz
1761 update_dua("statdns", 0, "members.3322.org", "/dyndns/update", 1);
1763 else if (strcmp(p, "opendns") == 0) {
1764 // test ok 9/15 -- zzz
1765 update_dua(NULL, 1, "updates.opendns.com", "/nic/update", 0);
1767 else if (strcmp(p, "dnsomatic") == 0) {
1768 // test ok 12/02 -- zzz
1769 update_dua(NULL, 1, "updates.dnsomatic.com", "/nic/update", 0);
1771 else if (strcmp(p, "noip") == 0) {
1772 update_dua(NULL, 0, "dynupdate.no-ip.com", "/nic/update", 1);
1773 // update_noip();
1775 else if (strcmp(p, "namecheap") == 0) {
1776 // test ok 9/14 -- zzz
1777 update_namecheap();
1779 else if (strcmp(p, "enom") == 0) {
1780 // no account, test output ok, 12/03 -- zzz
1781 update_enom();
1783 else if (strcmp(p, "dnsexit") == 0) {
1784 // test ok 9/14 -- zzz
1785 update_dnsexit();
1787 else if (strcmp(p, "ieserver") == 0) {
1788 // test ok 9/14 -- zzz
1789 update_ieserver();
1791 else if (strcmp(p, "dyns") == 0) {
1792 // no account, test output ok, test 401 error parse ok 9/15 -- zzz
1793 update_dyns();
1795 else if (strcmp(p, "tzo") == 0) {
1796 // test ok 9/15 -- zzz
1797 update_tzo();
1799 else if (strcmp(p, "zoneedit") == 0) {
1800 // test ok 9/16 -- zzz
1801 update_zoneedit(0);
1803 else if (strcmp(p, "szoneedit") == 0) {
1804 update_zoneedit(1);
1806 else if (strcmp(p, "afraid") == 0) {
1807 // test ok 9/16 -- zzz
1808 update_afraid();
1810 else if (strcmp(p, "everydns") == 0) {
1811 // 07/2008 -- zzz
1812 update_everydns();
1814 else if (strcmp(p, "editdns") == 0) {
1815 update_editdns();
1817 else if (strcmp(p, "minidns") == 0) {
1818 update_minidns();
1820 else if (strcmp(p, "heipv6tb") == 0) {
1821 update_heipv6tb();
1823 else if ((strcmp(p, "wget") == 0) || (strcmp(p, "custom") == 0)) {
1824 // test ok 9/15 -- zzz
1825 update_wget();
1827 else {
1828 error("Unknown service");
1831 // free(blob);
1832 return 1;