Merge commit 'origin/tomato-RT' into tomato-shibby
[tomato.git] / release / src / router / rc / ddns.c
blob45aa732d14caaa8ba592bdb30611ac7298ed5c74
1 /*
3 Tomato Firmware
4 Copyright (C) 2006-2009 Jonathan Zarate
6 */
8 #include "rc.h"
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <time.h>
13 #include <arpa/inet.h>
16 // #define DLOG(args...) syslog(LOG_DEBUG, args)
17 #define DLOG(fmt, args...) _dprintf(fmt"\n", args)
19 static void update(int num, int *dirty, int force)
21 char config[2048];
22 char *p;
23 char *serv, *user, *pass, *host, *wild, *mx, *bmx, *cust;
24 time_t t;
25 struct tm *tm;
26 int n;
27 char ddnsx[16];
28 char ddnsx_path[32];
29 char s[128];
30 char v[128];
31 char cache_fn[32];
32 char conf_fn[32];
33 char cache_nv[32];
34 char msg_fn[32];
35 char ip[32];
36 int exitcode;
37 int errors;
38 FILE *f;
40 DLOG("%s", __FUNCTION__);
42 sprintf(s, "ddns%d", num);
43 eval("cru", "d", s);
44 DLOG("%s: cru d %s", __FUNCTION__, s);
46 sprintf(s, "ddnsf%d", num);
47 eval("cru", "d", s);
48 DLOG("%s: cru d %s", __FUNCTION__, s);
50 sprintf(ddnsx, "ddnsx%d", num);
51 sprintf(ddnsx_path, "/var/lib/mdu/%s", ddnsx);
52 strlcpy(config, nvram_safe_get(ddnsx), sizeof(config));
54 mkdir("/var/lib/mdu", 0700);
55 sprintf(msg_fn, "%s.msg", ddnsx_path);
57 if ((vstrsep(config, "<", &serv, &user, &host, &wild, &mx, &bmx, &cust) != 7) || (*serv == 0)) {
58 DLOG("%s: msg=''\n", __FUNCTION__);
59 f_write(msg_fn, NULL, 0, 0, 0);
60 return;
63 if ((pass = strchr(user, ':')) != NULL) *pass++ = 0;
64 else pass = "";
66 for (n = 120; (n > 0) && (time(0) < Y2K); --n) {
67 sleep(1);
69 if (n <= 0) {
70 syslog(LOG_INFO, "Time not yet set.");
73 if (!wait_action_idle(10)) {
74 DLOG("%s: !wait_action_idle", __FUNCTION__);
75 return;
78 sprintf(cache_nv, "%s_cache", ddnsx);
79 if (force) {
80 DLOG("%s: force=1", __FUNCTION__);
81 nvram_set(cache_nv, "");
84 simple_lock("ddns");
86 strlcpy(ip, nvram_safe_get("ddnsx_ip"), sizeof(ip));
88 if (!check_wanup()) {
89 if ((get_wan_proto() != WP_DISABLED) || (ip[0] == 0)) {
90 DLOG("%s: !check_wanup", __FUNCTION__);
91 goto CLEANUP;
95 if (ip[0] == '@') {
96 if ((strcmp(serv, "zoneedit") == 0) || (strcmp(serv, "tzo") == 0) || (strcmp(serv, "noip") == 0) || (strcmp(serv, "dnsomatic") == 0)) {
97 strcpy(ip + 1, serv);
99 else {
100 strcpy(ip + 1, "dyndns");
103 else if (inet_addr(ip) == -1) {
104 strcpy(ip, get_wanip());
107 sprintf(cache_fn, "%s.cache", ddnsx_path);
108 f_write_string(cache_fn, nvram_safe_get(cache_nv), 0, 0);
110 if (!f_exists(msg_fn)) {
111 DLOG("%s: !f_exist(%s)", __FUNCTION__, msg_fn);
112 f_write(msg_fn, NULL, 0, 0, 0);
116 sprintf(conf_fn, "%s.conf", ddnsx_path);
117 if ((f = fopen(conf_fn, "w")) == NULL) goto CLEANUP;
118 // note: options not needed for the service are ignored by mdu
119 fprintf(f,
120 "user %s\n"
121 "pass %s\n"
122 "host %s\n"
123 "addr %s\n"
124 "mx %s\n"
125 "backmx %s\n"
126 "wildcard %s\n"
127 "url %s\n"
128 "ahash %s\n"
129 "msg %s\n"
130 "cookie %s\n"
131 "addrcache extip\n"
133 user,
134 pass,
135 host,
138 bmx,
139 wild,
140 cust,
141 cust,
142 msg_fn,
143 cache_fn);
145 if (nvram_get_int("debug_ddns")) {
146 fprintf(f, "dump /tmp/mdu-%s.txt\n", serv);
149 fclose(f);
151 exitcode = eval("mdu", "--service", serv, "--conf", conf_fn);
152 DLOG("%s: mdu exitcode=%d", __FUNCTION__, exitcode);
154 sprintf(s, "%s_errors", ddnsx);
155 if ((exitcode == 1) || (exitcode == 2)) {
156 if (nvram_match("ddnsx_retry", "0")) goto CLEANUP;
158 if (force) {
159 errors = 0;
161 else {
162 errors = nvram_get_int(s) + 1;
163 if (errors < 1) errors = 1;
164 if (errors >= 3) {
165 nvram_unset(s);
166 goto CLEANUP;
169 sprintf(v, "%d", errors);
170 nvram_set(s, v);
171 goto SCHED;
173 else {
174 nvram_unset(s);
175 errors = 0;
178 f_read_string(cache_fn, s, sizeof(s));
179 if ((p = strchr(s, '\n')) != NULL) *p = 0;
180 t = strtoul(s, &p, 10);
181 if (*p != ',') goto CLEANUP;
183 if (!nvram_match(cache_nv, s)) {
184 nvram_set(cache_nv, s);
185 if (nvram_get_int("ddnsx_save")) {
186 if (strstr(serv, "dyndns") == 0) *dirty = 1;
190 n = 28;
191 if (((p = nvram_get("ddnsx_refresh")) != NULL) && (*p != 0)) {
192 n = atoi(p);
194 if (n) {
195 if ((n < 0) || (n > 90)) n = 28;
196 t += (n * 86400); // refresh every n days
198 //!!TB - fix: if time is in the past, make it current
199 time_t now = time(0) + (60 * 5);
200 if (t < now) t = now;
202 tm = localtime(&t);
203 sprintf(s, "ddnsf%d", num);
204 sprintf(v, "%d %d %d %d * ddns-update %d force",
205 tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon + 1, num);
206 DLOG("%s: cru a %s %s", __FUNCTION__, s, v);
207 eval("cru", "a", s, v);
210 if (ip[0] == '@') {
211 SCHED:
212 DLOG("%s: SCHED", __FUNCTION__);
213 #if 0
214 t = time(0);
215 tm = localtime(&t);
216 DLOG("%s: now: %d:%d errors=%d", __FUNCTION__, tm->tm_hour, tm->tm_min, errors);
217 #endif
219 // need at least 10m spacing for checkip
220 // +1m to not trip over mdu's ip caching
221 // +5m for every error
222 n = (11 + (errors * 5));
223 if ((exitcode == 1) || (exitcode == 2)) {
224 if (exitcode == 2) n = 30;
225 sprintf(s, "\n#RETRY %d %d\n", n, errors); // should be localized in basic-ddns.asp
226 f_write_string(msg_fn, s, FW_APPEND, 0);
227 DLOG("%s: msg='retry n=%d errors=%d'", __FUNCTION__, n, errors);
230 t = time(0) + (n * 60);
231 tm = localtime(&t);
232 DLOG("%s: sch: %d:%d\n", __FUNCTION__, tm->tm_hour, tm->tm_min);
234 sprintf(s, "ddns%d", num);
235 sprintf(v, "%d * * * * ddns-update %d", tm->tm_min, num);
236 DLOG("%s: cru a %s %s", __FUNCTION__, s, v);
237 eval("cru", "a", s, v);
239 // sprintf(s, "cru a ddns%d \"*/10 * * * * ddns-update %d\"", num);
240 // system(s);
243 CLEANUP:
244 DLOG("%s: CLEANUP", __FUNCTION__);
245 simple_unlock("ddns");
248 int ddns_update_main(int argc, char **argv)
250 int num;
251 int dirty;
253 DLOG("%s: %s %s", __FUNCTION__, (argc >= 2) ? argv[1] : "", (argc >= 3) ? argv[2] : "");
255 dirty = 0;
256 umask(077);
258 if (argc == 1) {
259 update(0, &dirty, 0);
260 update(1, &dirty, 0);
262 else if ((argc == 2) || (argc == 3)) {
263 num = atoi(argv[1]);
264 if ((num == 0) || (num == 1)) {
265 update(num, &dirty, (argc == 3) && (strcmp(argv[2], "force") == 0));
268 if (dirty) nvram_commit_x();
269 return 0;
272 void start_ddns(void)
274 DLOG("%s", __FUNCTION__);
276 stop_ddns();
278 // cleanup
279 simple_unlock("ddns");
280 nvram_unset("ddnsx0_errors");
281 nvram_unset("ddnsx1_errors");
283 xstart("ddns-update");
286 void stop_ddns(void)
288 DLOG("%s", __FUNCTION__);
290 eval("cru", "d", "ddns0");
291 eval("cru", "d", "ddns1");
292 eval("cru", "d", "ddnsf0");
293 eval("cru", "d", "ddnsf1");
294 killall("ddns-update", SIGKILL);
295 killall("mdu", SIGKILL);