Correct PPTP server firewall rules chain.
[tomato/davidwu.git] / release / src / router / mdu / mdu.c
blobd9cb0ed955c975500225fbf6c493821fb14ed64a
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);
481 else if (strcmp(c, "pairnic") == 0) {
482 if (wget(0, 1, "myip.pairnic.com", "/", NULL, 0, &body) != 200) {
483 // Current IP Address: 1.2.3.4
484 error(M_ERROR_GET_IP);
487 else if (strcmp(c, "ovh") == 0) {
488 if (wget(0, 1, "www.ovh.com", "/", NULL, 0, &body) != 200) {
489 // Current IP Address: 1.2.3.4
490 error(M_ERROR_GET_IP);
493 else if (strcmp(c, "changeip") == 0) {
494 if (wget(0, 1, "nic.changeip.com", "/", NULL, 0, &body) != 200) {
495 // Current IP Address: 1.2.3.4
496 error(M_ERROR_GET_IP);
500 if ((p = strstr(body, "Address:")) != NULL) {
501 // dyndns, zoneedit, tzo, pairnic, ovh, changeip
502 p += 8; // note: tzo doesn't have a space
504 else {
505 // noip, dnsomatic
506 p = body;
509 while (*p == ' ') ++p;
511 q = p;
512 while (((*q >= '0') && (*q <= '9')) || (*q == '.')) ++q;
513 *q = 0;
515 if ((ia.s_addr = inet_addr(p)) != -1) {
516 q = inet_ntoa(ia);
517 sprintf(s, "%ld,%s", ut + (10 * 60), p);
518 f_write_string(cache_name, s, 0, 0);
520 _dprintf("%s: saved '%s'\n", __FUNCTION__, s);
521 return p;
524 error(M_ERROR_GET_IP);
526 return c;
529 return required ? get_option_required("addr") : NULL;
532 static void append_addr_option(char *buffer, const char *format)
534 const char *c;
536 if ((c = get_address(0)) != NULL) {
537 sprintf(buffer + strlen(buffer), format, c);
541 // -----------------------------------------------------------------------------
546 DNS Update API
547 http://www.dyndns.com/developers/specs/
551 DynDNS:
552 http: 80, 8245
553 https: 443
555 http://test:test@members.dyndns.org/nic/update?system=dyndns&hostname=test.shacknet.nu
557 GET /nic/update?
558 system=statdns&
559 hostname=yourhost.ourdomain.ext,yourhost2.dyndns.org&
560 myip=ipaddress&
561 wildcard=OFF&
562 mx=mail.exchanger.ext&
563 backmx=NO&
564 offline=NO
565 HTTP/1.0
566 Host: members.dyndns.org
567 Authorization: Basic username:pass
568 User-Agent: Company - Device - Version Number
571 static void update_dua(const char *type, int ssl, const char *server, const char *path, int reqhost)
573 const char *p;
574 char query[2048];
575 int r;
576 char *body;
578 // +opt
579 sprintf(query, "%s?", path ? path : get_option_required("path"));
581 // +opt
582 if (type) sprintf(query + strlen(query), "system=%s&", type);
584 // +opt
585 p = reqhost ? get_option_required("host") : get_option("host");
586 if (p) sprintf(query + strlen(query), "hostname=%s&", p);
588 // +opt
589 if (((p = get_option("mx")) != NULL) && (*p)) {
590 sprintf(query + strlen(query),
591 "mx=%s&"
592 "backmx=%s&",
594 (get_option_onoff("backmx", 0)) ? "YES" : "NO");
597 // +opt
598 append_addr_option(query, "myip=%s&");
600 if (get_option_onoff("wildcard", 0)) {
601 strcat(query, "wildcard=ON");
604 trimamp(query);
606 r = wget(ssl, 0, server ? server : get_option_required("server"), query, NULL, 1, &body);
607 switch (r) {
608 case 200:
609 if ((strstr(body, "dnserr")) || (strstr(body, "911"))) {
610 error_exitcode = 2;
611 error(M_DOWN);
614 if ((strstr(body, "badsys")) || (strstr(body, "numhost")) || (strstr(body, "ILLEGAL"))) {
615 error(M_INVALID_PARAM__D, -1);
617 if (strstr(body, "badagent")) {
618 error(M_INVALID_PARAM__D, -2);
620 if ((strstr(body, "badauth")) || (strstr(body, "NOACCESS")) || (strstr(body, "!donator"))) {
621 error(M_INVALID_AUTH);
623 if ((strstr(body, "notfqdn")) || (strstr(body, "!yours")) || strstr(body, "nohost") ||
624 (strstr(body, "abuse")) || strstr(body, "NOSERVICE")) {
625 error(M_INVALID_HOST);
627 if (strstr(body, "TOOSOON")) {
628 error(M_TOOSOON);
631 if (strstr(body, "nochg")) {
632 if ((strcmp(get_option("service"), "noip") == 0) && (refresh)) {
633 update_noip_refresh();
635 success();
636 return;
639 if ((strstr(body, "good")) || (strstr(body, "NOERROR"))) {
640 success();
641 return;
644 error(M_UNKNOWN_RESPONSE__D, -1);
645 break;
646 case 401:
647 error(M_INVALID_AUTH);
648 break;
650 error(M_UNKNOWN_ERROR__D, r);
656 namecheap.com
657 http://namecheap.simplekb.com/kb.aspx?show=article&articleid=27&categoryid=22
661 http://dynamicdns.park-your-domain.com/update?host=host_name&domain=domain.com&password=domain_password[&ip=your_ip]
663 ok response:
665 "HTTP/1.1 200 OK
668 <?xml version="1.0"?>
669 <interface-response>
670 <IP>12.123.123.12</IP>
671 <Command>SETDNSHOST</Command>
672 <Language>eng</Language>
673 <ErrCount>0</ErrCount>
674 <ResponseCount>0</ResponseCount>
675 <MinPeriod>1</MinPeriod>
676 <MaxPeriod>10</MaxPeriod>
677 <Server>Reseller9</Server>
678 <Site>Namecheap</Site>
679 <IsLockable>True</IsLockable>
680 <IsRealTimeTLD>True</IsRealTimeTLD>
681 <TimeDifference>+03.00</TimeDifference>
682 <ExecTime>0.0625</ExecTime>
683 <Done>true</Done>
684 <debug><![CDATA[]]></debug>
685 </interface-response>"
688 error response:
690 "HTTP/1.1 200 OK
693 <?xml version="1.0"?>
694 <interface-response>
695 <Command>SETDNSHOST</Command>
696 <Language>eng</Language>
697 <ErrCount>1</ErrCount>
698 <errors>
699 <Err1>Passwords do not match</Err1>
700 </errors>
701 <ResponseCount>1</ResponseCount>
702 <responses>
703 <response>
704 <ResponseNumber>304156</ResponseNumber>
705 <ResponseString>Validation error; invalid ; password</ResponseString>
706 </response>
707 </responses>
708 <MinPeriod>1</MinPeriod>
709 <MaxPeriod>10</MaxPeriod>
710 <Server>Reseller1</Server>
711 <Site></Site>
712 <IsLockable>True</IsLockable>
713 <IsRealTimeTLD>True</IsRealTimeTLD>
714 <TimeDifference>+03.00</TimeDifference>
715 8<ExecTime>0.0625</ExecTime>
716 <Done>true</Done>
717 <debug><![CDATA[]]></debug>
718 </interface-response>"
721 static void update_namecheap(void)
723 int r;
724 char *p;
725 char *q;
726 char *body;
727 char query[2048];
729 // +opt +opt +opt
730 sprintf(query, "/update?host=%s&domain=%s&password=%s",
731 get_option_required("host"), get_option("user") ? : get_option_required("domain"), get_option_required("pass"));
733 // +opt
734 append_addr_option(query, "&ip=%s");
736 r = wget(0, 0, "dynamicdns.park-your-domain.com", query, NULL, 0, &body);
737 if (r == 200) {
738 if (strstr(body, "<ErrCount>0<") != NULL) {
739 success();
741 if ((p = strstr(body, "<Err1>")) != NULL) {
742 p += 6;
743 if ((q = strstr(p, "</")) != NULL) {
744 *q = 0;
745 if ((q - p) >= 64) p[64] = 0;
746 error("%s", p);
749 error(M_UNKNOWN_RESPONSE__D, -1);
752 error(M_UNKNOWN_ERROR__D, r);
758 eNom
759 http://www.enom.com/help/faq_dynamicdns.asp
763 good:
764 ;URL Interface<br>
765 ;Machine is Reseller5<br>
766 IP=127.0.0.1
767 Command=SETDNSHOST
768 Language=eng
770 ErrCount=0
771 ResponseCount=0
772 MinPeriod=1
773 MaxPeriod=10
774 Server=Reseller5
775 Site=eNom
776 IsLockable=True
777 IsRealTimeTLD=True
778 TimeDifference=+08.00
779 ExecTime=0.500
781 bad:
782 ;URL Interface<br>
783 ;Machine is Reseller4<br>
784 -Command=SETDNSHOST
785 Language=eng
786 ErrCount=1
787 Err1=Passwords do not match
788 ResponseCount=1
789 ResponseNumber1=304156
790 ResponseString1=Validation error; invalid ; password
791 MinPeriod=1
792 MaxPeriod=10
793 Server=Reseller4
794 Site=
795 IsLockable=True
796 IsRealTimeTLD=True
797 TimeDifference=+08.00
798 ExecTime=0.235
799 Done=true
802 static void update_enom(void)
804 int r;
805 char *p;
806 char *q;
807 char *body;
808 char query[2048];
810 // http://dynamic.name-services.com/interface.asp?Command=SetDNSHost&HostName=test&Zone=test.com&Address=1.2.3.4&DomainPassword=password
812 // +opt +opt +opt
813 sprintf(query, "/interface.asp?Command=SetDNSHost&HostName=%s&Zone=%s&DomainPassword=%s",
814 get_option_required("host"), get_option("user") ? : get_option_required("domain"), get_option_required("pass"));
816 // +opt
817 append_addr_option(query, "&Address=%s");
819 r = wget(0, 0, "dynamic.name-services.com", query, NULL, 0, &body);
820 if (r == 200) {
821 if (strstr(body, "ErrCount=0") != NULL) {
822 success();
824 if ((p = strstr(body, "Err1=")) != NULL) {
825 p += 5;
826 if ((q = strchr(p, '\n')) != NULL) {
827 *q = 0;
828 if ((q - p) >= 64) p[64] = 0;
829 if ((q = strchr(p, '\r')) != NULL) *q = 0;
830 error("%s", p);
833 error(M_UNKNOWN_RESPONSE__D, -1);
836 error(M_UNKNOWN_ERROR__D, r);
845 dnsExit
846 http://www.dnsexit.com/Direct.sv?cmd=ipClients
850 "HTTP/1.1 200 OK
853 HTTP/1.1 200 OK
854 0=Success"
856 " HTTP/1.1 200 OK
857 11=fail to find foo.bar.com"
859 " HTTP/1.1 200 OK
860 4=Update too often. Please wait at least 8 minutes since the last update"
862 " HTTP/1.1 200 OK" <-- extra in body?
865 static void update_dnsexit(void)
867 int r;
868 char *body;
869 char query[2048];
871 // +opt +opt +opt
872 sprintf(query, "/RemoteUpdate.sv?action=edit&login=%s&password=%s&host=%s",
873 get_option_required("user"), get_option_required("pass"), get_option_required("host"));
875 // +opt
876 append_addr_option(query, "&myip=%s");
878 r = wget(0, 0, "www.dnsexit.com", query, NULL, 0, &body);
879 if (r == 200) {
880 // (\d+)=.+
882 if ((strstr(body, "0=Success") != NULL) || (strstr(body, "1=IP") != NULL)) {
883 success();
885 if ((strstr(body, "2=Invalid") != NULL) || (strstr(body, "3=User") != NULL)) {
886 error(M_INVALID_AUTH);
888 if ((strstr(body, "10=Host") != NULL) || (strstr(body, "11=fail") != NULL)) {
889 error(M_INVALID_HOST);
891 if (strstr(body, "4=Update") != NULL) {
892 error(M_TOOSOON);
895 error(M_UNKNOWN_RESPONSE__D, -1);
898 error(M_UNKNOWN_ERROR__D, r);
904 no-ip.com
908 Example response:
910 mytest.testdomain.com:4
914 static void update_noip(void)
916 int r;
917 const char *c;
918 char *body;
919 char query[2048];
921 // +opt +opt
922 sprintf(query, "/dns?username=%s&password=%s&",
923 get_option_required("user"), get_option_required("pass"));
925 // +opt
926 if (((c = get_option("group")) != NULL) && (*c)) {
927 sprintf(query + strlen(query), "group=%s", c);
929 else {
930 sprintf(query + strlen(query), "hostname=%s", get_option_required("host"));
933 // +opt
934 append_addr_option(query, "&ip=%s");
936 r = wget(0, 0, "dynupdate.no-ip.com", query, NULL, 0, &body);
937 if (r == 200) {
938 if ((c = strchr(body, ':')) != NULL) {
939 ++c;
940 r = atoi(c);
941 switch(r) {
942 case 0: // host same addr
943 while (*c == ' ') ++c;
944 if (*c != '0') {
945 error(M_UNKNOWN_RESPONSE__D, -1);
946 break;
948 // drop
949 case 12: // group same addr
950 case 1: // host updated
951 case 11: // group updated
952 success();
953 break;
954 case 2: // invalid hostname
955 case 10: // invalid group
956 case 6: // account disabled
957 case 8: // disabled hostname
958 error(M_INVALID_HOST);
959 break;
960 case 3: // invalid password
961 case 4: // invalid username
962 error(M_INVALID_AUTH);
963 break;
964 case 5:
965 error(M_TOOSOON);
966 break;
967 case 7: // invalid IP supplied
968 case 99: // client banned
969 case 100: // invalid parameter
970 case 9: // redirect type
971 case 13: //
972 error(M_INVALID_PARAM__D, r);
973 break;
974 default:
975 error(M_UNKNOWN_RESPONSE__D, r);
976 break;
979 else {
980 r = -200;
984 error(M_UNKNOWN_ERROR__D, r);
991 No-IP.com -- refresh
993 http://www.no-ip.com/hostactive.php?host=<host>&domain=<dom>
996 static void update_noip_refresh(void)
998 char query[2048];
999 char host[256];
1000 char *domain;
1002 strlcpy(host, get_option_required("host"), sizeof(host));
1003 if ((domain = strchr(host, '.')) != NULL) {
1004 *domain++ = 0;
1007 sprintf(query, "/hostactive.php?host=%s", host);
1008 if (domain) sprintf(query + strlen(query), "&domain=%s", domain);
1010 wget(0, 1, "www.no-ip.com", query, NULL, 0, NULL);
1011 // return ignored
1018 ieserver.net
1019 http://www.ieserver.net/tools.html
1023 http://ieserver.net/cgi-bin/dip.cgi?username=XXX&domain=XXX&password=XXX&updatehost=1
1025 username = hostname
1026 domain = dip.jp, fam.cx, etc.
1030 static void update_ieserver(void)
1032 int r;
1033 char *body;
1034 char query[2048];
1035 char *p;
1037 // +opt +opt
1038 sprintf(query, "/cgi-bin/dip.cgi?username=%s&domain=%s&password=%s&updatehost=1",
1039 get_option_required("user"), get_option_required("host"), get_option_required("pass"));
1041 r = wget(0, 0, "ieserver.net", query, NULL, 0, &body);
1042 if (r == 200) {
1043 if (strstr(body, "<title>Error") != NULL) {
1045 // <p>yuuzaa na mata pasuwoodo (EUC-JP)
1046 if ((p = strstr(body, "<p>\xA5\xE6\xA1\xBC\xA5\xB6\xA1\xBC")) != NULL) { // <p>user
1047 error(M_INVALID_AUTH);
1050 error(M_UNKNOWN_RESPONSE__D, -1);
1053 success();
1056 error(M_UNKNOWN_ERROR__D, r);
1063 dyns.cx
1064 http://www.dyns.cx/documentation/technical/protocol/v1.1.php
1068 "HTTP/1.1 200 OK
1071 401 testuser not authenticated"
1075 static void update_dyns(void)
1077 int r;
1078 char *body;
1079 char query[2048];
1082 // +opt +opt +opt
1083 sprintf(query, "/postscript011.php?username=%s&password=%s&host=%s",
1084 get_option_required("user"), get_option_required("pass"), get_option_required("host"));
1086 // +opt
1087 append_addr_option(query, "&ip=%s");
1089 #if 0
1090 sprintf(query + strlen(query), "&devel=1");
1091 #endif
1093 r = wget(0, 0, "www.dyns.net", query, NULL, 0, &body);
1094 if (r == 200) {
1095 while ((*body == ' ') || (*body == '\r') || (*body == '\n')) {
1096 ++body;
1098 switch (r = atoi(body)) {
1099 case 200:
1100 success();
1101 break;
1102 case 400:
1103 error(M_INVALID_PARAM__D, r);
1104 break;
1105 case 401:
1106 error(M_INVALID_AUTH);
1107 break;
1108 case 402:
1109 error(M_TOOSOON);
1110 break;
1111 case 405:
1112 error(M_INVALID_HOST);
1113 break;
1116 error(M_UNKNOWN_RESPONSE__D, r);
1119 error(M_UNKNOWN_ERROR__D, r);
1127 http://www.tzo.com/
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>TZO Name: foobartest.tzo.com<br>
1141 IP Address: 1.2.3.4<br>
1142 Expiration: 2007-01-01 1:01:01</p>
1143 </font> <br>
1145 ..."
1148 Invalid hostname or password:
1149 "HTTP/1.1 200 OK
1152 <td valign="top"><font size="4">Congratulations!
1153 You've successfully signed on with TZO.<br>
1154 </font><h1 align="center"><font size="2"
1155 face="Verdana">Here's information about your
1156 account:</font><br>
1157 </h1>
1158 <h3 align="center"><font face="Verdana"><p>Error=bad authentication
1159 </p>
1160 ..."
1163 Update too soon:
1164 "...
1165 face="Verdana">Here's information about your
1166 account:</font><br>
1167 </h1>
1168 <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
1169 </p>
1170 </font> <br>
1171 ..."
1174 static void update_tzo(void)
1176 int r;
1177 char *body;
1178 char query[2048];
1179 char *p;
1181 // +opt +opt +opt
1182 sprintf(query, "/webclient/signedon.html?TZOName=%s&Email=%s&TZOKey=%s",
1183 get_option_required("host"), get_option_required("user"), get_option_required("pass"));
1185 // +opt
1186 append_addr_option(query, "&IPAddress=%s");
1188 r = wget(0, 0, "cgi.tzo.com", query, NULL, 0, &body);
1189 if (r == 200) {
1190 if ((p = strstr(body, "Error=")) != NULL) {
1191 p += 6;
1192 if (strncmp(p, "bad auth", 8) == 0) {
1193 error(M_INVALID_AUTH);
1195 if (strncmp(p, "Try again", 9) == 0) {
1196 error(M_TOOSOON);
1198 error(M_UNKNOWN_ERROR__D, -1);
1200 success();
1203 error(M_UNKNOWN_ERROR__D, r);
1211 ZoneEdit
1212 http://www.zoneedit.com/doc/dynamic.html
1216 "HTTP/1.1 200 OK
1218 <SUCCESS CODE="200" TEXT="Update succeeded." ZONE="test123.com" HOST="www.test123.com" IP="1.2.3.4">"
1220 "<ERROR CODE="707" TEXT="Duplicate updates for the same host/ip, adjust client settings" ZONE="testexamplesite4321.com" HOST="test.testexamplesite4321.com">"
1222 "HTTP/1.1 401 Authorization Required
1224 <title>Authentication Failed </title>"
1226 ERROR CODE="[701-799]" TEXT="Description of the error" ZONE="Zone that Failed"
1227 ERROR CODE="702" TEXT="Update failed." ZONE="%zone%"
1228 ERROR CODE="703" TEXT="one of either parameters 'zones' or 'host' are required."
1229 ERROR CODE="705" TEXT="Zone cannot be empty" ZONE="%zone%"
1230 ERROR CODE="707" TEXT="Duplicate updates for the same host/ip, adjust client settings" ZONE="%zone%"
1231 ERROR CODE="707" TEXT="Too frequent updates for the same host, adjust client settings" ZONE="%zone%"
1232 ERROR CODE="704" TEXT="Zone must be a valid 'dotted' internet name." ZONE="%zone%"
1233 ERROR CODE="701" TEXT="Zone is not set up in this account." ZONE="%zone%"
1234 ERROR CODE="708" TEXT="Login/authorization error"
1235 SUCCESS CODE="[200-201]" TEXT="Description of the success" ZONE="Zone that Succeeded"
1236 SUCCESS CODE="200" TEXT="Update succeeded." ZONE="%zone%" IP="%dnsto%"
1237 SUCCESS CODE="201" TEXT="No records need updating." ZONE="%zone%"
1240 static void update_zoneedit(int ssl)
1242 int r;
1243 char *body;
1244 char *c;
1245 char query[2048];
1247 // +opt
1248 sprintf(query, "/auth/dynamic.html?host=%s", get_option_required("host"));
1250 // +opt
1251 append_addr_option(query, "&dnsto=%s");
1253 r = wget(ssl, 0, "dynamic.zoneedit.com", query, NULL, 1, &body);
1254 switch (r) {
1255 case 200:
1256 if (strstr(body, "<SUCCESS CODE")) {
1257 success();
1259 if ((c = strstr(body, "<ERROR CODE=\"")) != NULL) {
1260 r = atoi(c + 13);
1261 switch (r) {
1262 case 701: // invalid "zone"
1263 error(M_INVALID_HOST);
1264 break;
1265 case 707: // update is the same ip address? / too frequent updates
1266 if (strstr(c, "Duplicate") != NULL) success();
1267 else error(M_TOOSOON);
1268 break;
1269 case 708: // authorization error
1270 error(M_INVALID_AUTH);
1271 break;
1273 error(M_UNKNOWN_RESPONSE__D, r);
1275 error(M_UNKNOWN_RESPONSE__D, -1);
1276 break;
1277 case 401:
1278 error(M_INVALID_AUTH);
1279 break;
1282 error(M_UNKNOWN_ERROR__D, r);
1288 FreeDNS.afraid.org
1293 http://freedns.afraid.org/dynamic/update.php?XXXXXXXXXXYYYYYYYYYYYZZZZZZZ1111222
1295 "HTTP/1.0 200 OK
1298 ERROR: Address 1.2.3.4 has not changed."
1300 "Updated 1 host(s) foobar.mooo.com to 1.2.3.4 in 1.234 seconds"
1302 "ERROR: Missing S/key and DataID, check your update URL."
1304 "fail, make sure you own this record, and the address does not already equal 1.2.3.4"
1309 static void update_afraid(void)
1311 int r;
1312 char *body;
1313 char query[2048];
1315 // +opt
1316 sprintf(query, "/dynamic/update.php?%s", get_option_required("ahash"));
1318 r = wget(0, 0, "freedns.afraid.org", query, NULL, 0, &body);
1319 if (r == 200) {
1320 if ((strstr(body, "ERROR") != NULL) || (strstr(body, "fail") != NULL)) {
1321 if (strstr(body, "has not changed") != NULL) {
1322 success();
1324 error(M_INVALID_AUTH);
1326 else if ((strstr(body, "Updated") != NULL) && (strstr(body, "host") != NULL)) {
1327 success();
1329 else {
1330 error(M_UNKNOWN_RESPONSE__D, -1);
1334 error(M_UNKNOWN_ERROR__D, r);
1339 everydns.net
1341 HTTP/1.1 200 OK
1342 Server: Apache
1343 X-Powered-By: PHP/5.0.1-dev
1344 Connection: close
1345 Content-Type: text/html; charset=utf-8
1347 Authentication given
1348 Authentication failed: Bad Username/password
1349 Exit code: 2
1352 static void update_everydns(void)
1354 int r;
1355 char *body;
1356 char query[2048];
1357 const char *p;
1359 strcpy(query, "/index.php?ver=0.1");
1360 append_addr_option(query, "&ip=%s");
1362 p = get_option("host");
1363 if (p) sprintf(query + strlen(query), "&domain=%s", p);
1365 r = wget(0, 0, "dyn.everydns.net", query, NULL, 1, &body);
1366 if (r == 200) {
1367 if ((p = strstr(body, "Exit code:")) != NULL) {
1368 r = atoi(p + 10);
1369 switch (r) {
1370 case 0:
1371 success();
1372 break;
1373 case 2:
1374 error(M_INVALID_AUTH);
1375 break;
1376 default:
1377 error(M_UNKNOWN_RESPONSE__D, r);
1378 break;
1381 error(M_UNKNOWN_RESPONSE__D, -1);
1384 error(M_UNKNOWN_ERROR__D, r);
1390 miniDNS.net
1391 http://www.minidns.net/areg.php?opcode=ADD&host=bar.minidns.net&username=foo&password=topsecret&ip=1.2.3.4
1395 "okay. BAR.MINIDNS.NET mapped to 1.2.3.4."
1396 "auth_fail. Incorrect username/password/hostname."
1397 "auth_fail. Host name format error."
1400 static void update_minidns(void)
1402 int r;
1403 char *body;
1404 char query[2048];
1406 // +opt +opt +opt
1407 sprintf(query, "/areg.php?opcode=ADD&host=%s&username=%s&password=%s",
1408 get_option_required("host"),
1409 get_option_required("user"),
1410 get_option_required("pass"));
1412 // +opt
1413 append_addr_option(query, "&ip=%s");
1415 r = wget(0, 0, "www.minidns.net", query, NULL, 1, &body);
1416 if (r == 200) {
1417 if (strstr(body, "okay.") != NULL) {
1418 success();
1420 else if (strstr(body, "Host name format error") != NULL) {
1421 error(M_INVALID_HOST);
1423 else if (strstr(body, "auth_fail") != NULL) {
1424 error(M_INVALID_AUTH);
1426 else {
1427 error(M_UNKNOWN_RESPONSE__D, -1);
1431 error(M_UNKNOWN_ERROR__D, r);
1437 editdns.net
1438 http://www.editdns.net/
1440 source: Keith M.
1444 http://DynDNS.EditDNS.net/api/dynLinux.php?p=XXX&r=XXX
1446 p = password
1447 r = hostname
1450 static void update_editdns(void)
1452 int r;
1453 char *body;
1454 char query[2048];
1456 // +opt +opt
1457 sprintf(query, "/api/dynLinux.php?p=%s&r=%s",
1458 get_option_required("pass"), get_option_required("host"));
1460 r = wget(0, 1, "DynDNS.EditDNS.net", query, NULL, 0, &body);
1461 if (r == 200) {
1462 if (strstr(body, "Record has been updated") != NULL) {
1463 success();
1465 if (strstr(body, "Record already exists") != NULL) {
1466 error(M_SAME_IP);
1468 else if (strstr(body, "Invalid Username") != NULL) {
1469 error(M_INVALID_AUTH);
1471 else if (strstr(body, "Invalid DynRecord") != NULL) {
1472 error(M_INVALID_HOST);
1474 else {
1475 error(body);
1479 error(M_UNKNOWN_ERROR__D, r);
1486 HE.net IPv6 TunnelBroker
1487 https://ipv4.tunnelbroker.net/ipv4_end.php?ip=$IPV4ADDR&pass=$MD5PASS&apikey=$USERID&tid=$TUNNELID
1491 "HTTP/1.1 200 OK
1494 Good responses:
1495 +OK: Tunnel endpoint updated to: XXX.XXX.XXX.XXX
1496 -ERROR: This tunnel is already associated with this IP address. Please try and limit your updates to IP changes.
1497 Bad responses:
1498 -ERROR: Tunnel not found
1499 -ERROR: Invalid API key or password
1500 -ERROR: IP is not in a valid format
1501 -ERROR: Missing parameter(s).
1502 -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.
1503 -ERROR: IP is blocked. (RFC1918 Private Address Space)
1506 static void update_heipv6tb(void)
1508 int r;
1509 char *body, *p;
1510 const char *serr = "-ERROR: ";
1511 char query[2048];
1513 // +opt +opt +opt
1514 sprintf(query, "/ipv4_end.php?pass=%s&apikey=%s&tid=%s",
1515 md5_string(get_option_required("pass")),
1516 get_option_required("user"),
1517 get_option_required("host"));
1519 // +opt
1520 append_addr_option(query, "&ip=%s");
1522 r = wget(1, 0, "ipv4.tunnelbroker.net", query, NULL, 0, &body);
1523 if (r == 200) {
1524 if ((strstr(body, "endpoint updated to") != NULL) || (strstr(body, "is already associated") != NULL)) {
1525 success();
1527 if (strstr(body, "Invalid API key or password") != NULL) {
1528 error(M_INVALID_AUTH);
1530 if (strstr(body, "Tunnel not found") != NULL) {
1531 error(M_INVALID_PARAM__S, "Tunnel ID");
1533 if (strstr(body, "IP is not in a valid format") != NULL) {
1534 error(M_INVALID_PARAM__S, "IPv4 endpoint");
1537 error(M_UNKNOWN_RESPONSE__D, -1);
1540 error(M_UNKNOWN_ERROR__D, r);
1547 wget/custom
1550 static void update_wget(void)
1552 int r;
1553 char *c;
1554 char url[256];
1555 char s[256];
1556 char he[256];
1557 char *header;
1558 int https;
1559 char *host;
1560 char path[256];
1561 char *p;
1562 char *body;
1564 // http://user:pass@domain:port/path?query
1565 // https://user:pass@domain:port/path?query
1567 strcpy(url, get_option_required("url"));
1568 https = 0;
1569 host = url + 7;
1570 if (strncasecmp(url, "https://", 8) == 0) {
1571 https = 1;
1572 ++host;
1574 else if (strncasecmp(url, "http://", 7) != 0) {
1575 error(M_INVALID_PARAM__S, "url");
1578 if ((p = strchr(host, '/')) == NULL) {
1579 error(M_INVALID_PARAM__S, "url");
1581 strcpy(path, p);
1582 *p = 0;
1584 if ((c = strstr(path, "@IP")) != NULL) {
1585 strcpy(s, c + 3);
1586 strcpy(c, get_address(1));
1587 strcat(c, s);
1590 if ((c = strrchr(host, '@')) != NULL) {
1591 *c = 0;
1592 s[base64_encode(host, s, c - host)] = 0;
1593 sprintf(he, "Authorization: Basic %s\r\n", s);
1594 header = he;
1595 host = c + 1;
1597 else {
1598 header = NULL;
1601 r = wget(https, 1, host, path, header, 0, &body);
1602 switch (r) {
1603 case 200:
1604 case 302: // redirect -- assume ok
1605 if (body && *body) success_msg((char *)body);
1606 else success();
1607 break;
1608 case 401:
1609 error(M_INVALID_AUTH);
1610 break;
1613 error(M_UNKNOWN_ERROR__D, r);
1616 // -----------------------------------------------------------------------------
1620 static void check_cookie(void)
1622 const char *c;
1623 char addr[16];
1624 long tm;
1626 if (((c = get_option("cookie")) == NULL) || (!read_tmaddr(c, &tm, addr))) {
1627 _dprintf("%s: no cookie\n", __FUNCTION__);
1628 refresh = 1;
1629 return;
1632 if ((c = get_address(0)) == NULL) {
1633 _dprintf("%s: no address specified\n", __FUNCTION__);
1634 return;
1636 if (strcmp(c, addr) != 0) {
1637 _dprintf("%s: address is different (%s != %s)\n", __FUNCTION__, c, addr);
1638 return;
1641 #if 0
1642 long now;
1643 long u;
1645 now = time(NULL);
1646 if ((now < Y2K) || (now < tm)) {
1647 _dprintf("%s: time rolled back (now=%ld, tm=%ld)\n", __FUNCTION__, now, tm);
1648 return;
1650 tm = now - tm;
1652 _dprintf("%s: addr=%s tm=%ld (relative)\n", __FUNCTION__, addr, tm);
1654 if ((c = get_option("maxtime")) != NULL) {
1655 u = strtol(c, NULL, 0);
1656 if (u > 0) {
1657 if (tm > u) {
1658 _dprintf("%s: %s expired (%ld > %ld)\n", __FUNCTION__, addr, tm, u);
1659 return;
1661 _dprintf("%s: maxtime=%ld tm=%ld\n", __FUNCTION__, u, tm);
1663 puts(M_TOOSOON);
1664 exit(3);
1668 if ((c = get_option("mintime")) != NULL) {
1669 u = strtol(c, NULL, 0);
1670 if ((u > 0) && (tm < u)) {
1671 _dprintf("%s: %s recently updated (%ld < %ld)\n", __FUNCTION__, addr, tm, u);
1673 puts(M_TOOSOON);
1674 exit(3);
1678 #endif
1680 puts(M_SAME_IP);
1681 exit(3);
1684 static void save_cookie(void)
1686 const char *cookie;
1687 const char *c;
1688 long now;
1689 char s[256];
1691 now = time(NULL);
1692 if (now < Y2K) {
1693 _dprintf("%s: no time", __FUNCTION__);
1694 return;
1697 if ((cookie = get_option("cookie")) == NULL) {
1698 _dprintf("%s: no cookie\n", __FUNCTION__);
1699 return;
1702 if ((c = get_address(0)) == NULL) {
1703 _dprintf("%s: no address specified\n", __FUNCTION__);
1704 return;
1707 sprintf(s, "%ld,%s", now, c);
1708 f_write_string(cookie, s, FW_NEWLINE, 0);
1710 _dprintf("%s: cookie=%s\n", __FUNCTION__, s);
1713 int main(int argc, char *argv[])
1715 const char *p;
1717 g_argc = argc;
1718 g_argv = argv;
1720 printf("MDU\nCopyright (C) 2007-2009 Jonathan Zarate\n\n");
1721 _dprintf("DEBUG\n");
1723 if ((blob = malloc(BLOB_SIZE)) == NULL) {
1724 return 1;
1727 mkdir("/var/lib/mdu", 0700);
1728 chdir("/var/lib/mdu");
1730 if ((p = get_dump_name()) != NULL) {
1731 unlink(p);
1734 check_cookie();
1736 p = get_option_required("service");
1737 if (strcmp(p, "dua") == 0) {
1738 update_dua("dyndns", 0, NULL, NULL, 1);
1740 else if (strcmp(p, "duas") == 0) {
1741 update_dua("dyndns", 1, NULL, NULL, 1);
1743 else if (strcmp(p, "dyndns") == 0) {
1744 // test ok 9/14 -- zzz
1745 update_dua("dyndns", 0, "members.dyndns.org", "/nic/update", 1);
1747 else if (strcmp(p, "dyndns-static") == 0) {
1748 // test ok 9/14 -- zzz
1749 update_dua("statdns", 0, "members.dyndns.org", "/nic/update", 1);
1751 else if (strcmp(p, "dyndns-custom") == 0) {
1752 // test ok 9/14 -- zzz
1753 update_dua("custom", 0, "members.dyndns.org", "/nic/update", 1);
1755 else if (strcmp(p, "sdyndns") == 0) {
1756 update_dua("dyndns", 1, "members.dyndns.org", "/nic/update", 1);
1758 else if (strcmp(p, "sdyndns-static") == 0) {
1759 update_dua("statdns", 1, "members.dyndns.org", "/nic/update", 1);
1761 else if (strcmp(p, "sdyndns-custom") == 0) {
1762 update_dua("custom", 1, "members.dyndns.org", "/nic/update", 1);
1764 else if (strcmp(p, "easydns") == 0) {
1765 // no account, test output ok, test 401 error parse ok 9/15 -- zzz
1766 update_dua(NULL, 0, "members.easydns.com", "/dyn/dyndns.php", 1);
1768 else if (strcmp(p, "seasydns") == 0) {
1769 update_dua(NULL, 1, "members.easydns.com", "/dyn/dyndns.php", 1);
1771 else if (strcmp(p, "3322") == 0) {
1772 // no account, test output ok, test 401 error parse ok 9/16 -- zzz
1773 update_dua(NULL, 0, "members.3322.org", "/dyndns/update", 1);
1775 else if (strcmp(p, "3322-static") == 0) {
1776 // no account, test output ok, test 401 error parse ok 9/16 -- zzz
1777 update_dua("statdns", 0, "members.3322.org", "/dyndns/update", 1);
1779 else if (strcmp(p, "opendns") == 0) {
1780 // test ok 9/15 -- zzz
1781 update_dua(NULL, 1, "updates.opendns.com", "/nic/update", 0);
1783 else if (strcmp(p, "dnsomatic") == 0) {
1784 // test ok 12/02 -- zzz
1785 update_dua(NULL, 1, "updates.dnsomatic.com", "/nic/update", 0);
1787 else if (strcmp(p, "noip") == 0) {
1788 update_dua(NULL, 0, "dynupdate.no-ip.com", "/nic/update", 1);
1789 // update_noip();
1791 else if (strcmp(p, "namecheap") == 0) {
1792 // test ok 9/14 -- zzz
1793 update_namecheap();
1795 else if (strcmp(p, "enom") == 0) {
1796 // no account, test output ok, 12/03 -- zzz
1797 update_enom();
1799 else if (strcmp(p, "dnsexit") == 0) {
1800 // test ok 9/14 -- zzz
1801 update_dnsexit();
1803 else if (strcmp(p, "ieserver") == 0) {
1804 // test ok 9/14 -- zzz
1805 update_ieserver();
1807 else if (strcmp(p, "dyns") == 0) {
1808 // no account, test output ok, test 401 error parse ok 9/15 -- zzz
1809 update_dyns();
1811 else if (strcmp(p, "tzo") == 0) {
1812 // test ok 9/15 -- zzz
1813 update_tzo();
1815 else if (strcmp(p, "zoneedit") == 0) {
1816 // test ok 9/16 -- zzz
1817 update_zoneedit(0);
1819 else if (strcmp(p, "szoneedit") == 0) {
1820 update_zoneedit(1);
1822 else if (strcmp(p, "afraid") == 0) {
1823 // test ok 9/16 -- zzz
1824 update_afraid();
1826 else if (strcmp(p, "everydns") == 0) {
1827 // 07/2008 -- zzz
1828 update_everydns();
1830 else if (strcmp(p, "editdns") == 0) {
1831 update_editdns();
1833 else if (strcmp(p, "minidns") == 0) {
1834 update_minidns();
1836 else if (strcmp(p, "heipv6tb") == 0) {
1837 update_heipv6tb();
1839 else if (strcmp(p, "pairnic") == 0) {
1840 // pairNIC uses the same API as DynDNS
1841 update_dua("pairnic", 0, "dynamic.pairnic.com", "/nic/update", 1);
1843 else if (strcmp(p, "spairnic") == 0) {
1844 // pairNIC uses the same API as DynDNS
1845 update_dua("pairnic", 1, "dynamic.pairnic.com", "/nic/update", 1);
1847 else if (strcmp(p, "ovh") == 0) {
1848 // OVH uses the same API as DynDNS
1849 update_dua("dyndns", 0, "www.ovh.com", "/nic/update", 1);
1851 else if (strcmp(p, "sovh") == 0) {
1852 // OVH uses the same API as DynDNS
1853 update_dua("dyndns", 1, "www.ovh.com", "/nic/update", 1);
1855 else if (strcmp(p, "schangeip") == 0) {
1856 // ChangeIP uses the same API as DynDNS
1857 update_dua("dyndns", 1, "nic.changeip.com", "/nic/update", 1);
1859 else if ((strcmp(p, "wget") == 0) || (strcmp(p, "custom") == 0)) {
1860 // test ok 9/15 -- zzz
1861 update_wget();
1863 else {
1864 error("Unknown service");
1867 // free(blob);
1868 return 1;