4 Copyright (C) 2006-2009 Jonathan Zarate
11 #include <sys/ioctl.h>
12 #include <net/if_arp.h>
21 void usage_exit(const char *cmd
, const char *help
)
23 fprintf(stderr
, "Usage: %s %s\n", cmd
, help
);
27 #if 0 // replaced by #define in rc.h
28 int modprobe(const char *mod
)
31 return eval("modprobe", "-s", (char *)mod
);
33 int r
= eval("modprobe", "-s", (char *)mod
);
34 cprintf("modprobe %s = %d\n", mod
, r
);
40 int modprobe_r(const char *mod
)
43 return eval("modprobe", "-r", (char *)mod
);
45 int r
= eval("modprobe", "-r", (char *)mod
);
46 cprintf("modprobe -r %s = %d\n", mod
, r
);
53 #define ct_modprobe(mod, args...) ({ \
54 modprobe("nf_conntrack_"mod, ## args); \
55 modprobe("nf_nat_"mod); \
58 #define ct_modprobe(mod, args...) ({ \
59 modprobe("ip_conntrack_"mod, ## args); \
60 modprobe("ip_nat_"mod, ## args); \
67 #define ct_modprobe_r(mod) ({ \
68 modprobe_r("nf_nat_"mod); \
69 modprobe_r("nf_conntrack_"mod); \
72 #define ct_modprobe_r(mod) ({ \
73 modprobe_r("ip_nat_"mod); \
74 modprobe_r("ip_conntrack_"mod); \
80 * The various child job starting functions:
82 * Start the child. If ppid param is NULL, wait until the child exits.
83 * Otherwise, store the child's pid in ppid and return immediately.
85 * Call _eval with a NULL ppid, to wait for the child to exit.
87 * Call _eval with a garbage ppid (to not wait), then return.
89 * Execute each executable in a directory that has the specified extention.
90 * Call _eval with a ppid (to not wait), then check every second for the child's pid.
91 * After wtime seconds or when the child has exited, return.
92 * If any such filename has an '&' character in it, then do *not* wait at
93 * all for the child to exit, regardless of the wtime.
96 #define MAX_XSTART_ARGC 16
97 int _xstart(const char *cmd
, ...)
100 char *argv
[MAX_XSTART_ARGC
];
104 argv
[0] = (char *)cmd
;
107 while ((argv
[argc
++] = va_arg(ap
, char *)) != NULL
) {
108 if (argc
>= MAX_XSTART_ARGC
) {
109 _dprintf("%s: too many parameters\n", __FUNCTION__
);
115 return _eval(argv
, NULL
, 0, &pid
);
118 static int endswith(const char *str
, char *cmp
)
120 int cmp_len
, str_len
, i
;
122 cmp_len
= strlen(cmp
);
123 str_len
= strlen(str
);
124 if (cmp_len
> str_len
)
126 for (i
= 0; i
< cmp_len
; i
++) {
127 if (str
[(str_len
- 1) - i
] != cmp
[(cmp_len
- 1) - i
])
133 static void execute_with_maxwait(char *const argv
[], int wtime
)
137 if (_eval(argv
, NULL
, 0, &pid
) != 0)
140 while (wtime
-- > 0) {
141 waitpid(pid
, NULL
, WNOHANG
); /* Reap the zombie if it has terminated. */
142 if (kill(pid
, 0) != 0) break;
145 _dprintf("%s killdon: errno: %d pid %d\n", argv
[0], errno
, pid
);
149 /* This is a bit ugly. Why didn't they allow another parameter to filter???? */
150 static char *filter_extension
;
151 static int endswith_filter(const struct dirent
*entry
)
153 return endswith(entry
->d_name
, filter_extension
);
156 /* If the filename has an '&' character in it, don't wait at all. */
157 void run_userfile(char *folder
, char *extension
, const char *arg1
, int wtime
)
159 unsigned char buf
[PATH_MAX
+ 1];
160 char *argv
[] = { buf
, (char *)arg1
, NULL
};
161 struct dirent
**namelist
;
164 /* Do them in sorted order. */
165 filter_extension
= extension
;
166 n
= scandir(folder
, &namelist
, endswith_filter
, alphasort
);
168 for (i
= 0; i
< n
; ++i
) {
169 sprintf(buf
, "%s/%s", folder
, namelist
[i
]->d_name
);
170 execute_with_maxwait(argv
,
171 strchr(namelist
[i
]->d_name
, '&') ? 0 : wtime
);
178 /* Run user-supplied script(s), with 1 argument.
179 * Return when the script(s) have finished,
180 * or after wtime seconds, even if they aren't finished.
182 * Extract NAME from nvram variable named as "script_NAME".
184 * The sole exception to the nvram item naming rule is sesx.
185 * That one is "sesx_script" rather than "script_sesx", due
186 * to historical accident.
188 * The other exception is time-scheduled commands.
189 * These have names that start with "sch_".
190 * No directories are searched for corresponding user scripts.
192 * Execute in this order:
193 * nvram item: nv (run as a /bin/sh script)
194 * (unless nv starts with a dot)
195 * All files with a suffix of ".NAME" in these directories:
203 At this time, the names/events are:
204 (Unless otherwise noted, there are no parameters. Otherwise, one parameter).
205 sesx SES/AOSS Button custom script. Param: ??
206 brau "bridge/auto" button pushed. Param: mode (bridge/auto/etc)
207 fire When firewall service has been started or re-started.
208 shut At system shutdown, just before wan/lan/usb/etc. are stopped.
209 init At system startup, just before wan/lan/usb/etc. are started.
210 The root filesystem and /jffs are mounted, but not any USB devices.
211 usbmount After an auto-mounted USB drive is mounted.
212 usbumount Before an auto-mounted USB drive is unmounted.
213 usbhotplug When any USB device is attached or removed.
214 wanup After WAN has come up.
215 autostop When a USB partition gets un-mounted. Param: the mount-point (directory).
216 If unmounted from the GUI, the directory is still mounted and accessible.
217 If the USB drive was unplugged, it is still mounted but not accessible.
219 User scripts -- no directories are searched. One parameter.
220 autorun When a USB disk partition gets auto-mounted. Param: the mount-point (directory).
221 But not if the partition was already mounted.
222 Only the files in that directory will be run.
224 void run_nvscript(const char *nv
, const char *arg1
, int wtime
)
228 char s
[PATH_MAX
+ 1];
229 char *argv
[] = { s
, (char *)arg1
, NULL
};
236 script
= nvram_get(nv
);
238 if ((script
) && (*script
!= 0)) {
239 sprintf(s
, "/tmp/%s.sh", nv
);
240 if ((f
= fopen(s
, "w")) != NULL
) {
241 fputs("#!/bin/sh\n", f
);
248 _dprintf("Running: '%s %s'\n", argv
[0], argv
[1]? argv
[1]: "");
249 execute_with_maxwait(argv
, wtime
);
254 sprintf(s
, ".%s", nv
);
255 if (strncmp("sch_c", nv
, 5) == 0) {
258 else if (strncmp("sesx_", nv
, 5) == 0) {
261 else if (strncmp("script_", nv
, 7) == 0) {
262 strcpy(&s
[1], &nv
[7]);
266 if (nvram_match("userfiles_disable", "1")) {
267 // backdoor to disable user scripts execution
271 if ((check_dirs
) && strcmp(s
, ".") != 0) {
272 _dprintf("checking for user scripts: '%s'\n", s
);
273 run_userfile("/etc/config", s
, arg1
, wtime
);
274 run_userfile("/jffs/etc/config", s
, arg1
, wtime
);
275 run_userfile("/opt/etc/config", s
, arg1
, wtime
);
276 run_userfile("/mmc/etc/config", s
, arg1
, wtime
);
277 run_userfile("/tmp/config", s
, arg1
, wtime
);
281 static void write_ct_timeout(const char *type
, const char *name
, unsigned int val
)
283 unsigned char buf
[128];
286 sprintf(buf
, "/proc/sys/net/ipv4/netfilter/ip_conntrack_%s_timeout%s%s",
287 type
, (name
&& name
[0]) ? "_" : "", name
? name
: "");
288 sprintf(v
, "%u", val
);
290 f_write_string(buf
, v
, 0, 0);
293 #ifndef write_tcp_timeout
294 #define write_tcp_timeout(name, val) write_ct_timeout("tcp", name, val)
297 #ifndef write_udp_timeout
298 #define write_udp_timeout(name, val) write_ct_timeout("udp", name, val)
301 static unsigned int read_ct_timeout(const char *type
, const char *name
)
303 unsigned char buf
[128];
304 unsigned int val
= 0;
307 sprintf(buf
, "/proc/sys/net/ipv4/netfilter/ip_conntrack_%s_timeout%s%s",
308 type
, (name
&& name
[0]) ? "_" : "", name
? name
: "");
309 if (f_read_string(buf
, v
, sizeof(v
)) > 0)
315 #ifndef read_tcp_timeout
316 #define read_tcp_timeout(name) read_ct_timeout("tcp", name)
319 #ifndef read_udp_timeout
320 #define read_udp_timeout(name) read_ct_timeout("udp", name)
323 void setup_conntrack(void)
330 p
= nvram_safe_get("ct_tcp_timeout");
331 if (sscanf(p
, "%u%u%u%u%u%u%u%u%u%u",
332 &v
[0], &v
[1], &v
[2], &v
[3], &v
[4], &v
[5], &v
[6], &v
[7], &v
[8], &v
[9]) == 10) { // lightly verify
333 write_tcp_timeout("established", v
[1]);
334 write_tcp_timeout("syn_sent", v
[2]);
335 write_tcp_timeout("syn_recv", v
[3]);
336 write_tcp_timeout("fin_wait", v
[4]);
337 write_tcp_timeout("time_wait", v
[5]);
338 write_tcp_timeout("close", v
[6]);
339 write_tcp_timeout("close_wait", v
[7]);
340 write_tcp_timeout("last_ack", v
[8]);
343 v
[1] = read_tcp_timeout("established");
344 v
[2] = read_tcp_timeout("syn_sent");
345 v
[3] = read_tcp_timeout("syn_recv");
346 v
[4] = read_tcp_timeout("fin_wait");
347 v
[5] = read_tcp_timeout("time_wait");
348 v
[6] = read_tcp_timeout("close");
349 v
[7] = read_tcp_timeout("close_wait");
350 v
[8] = read_tcp_timeout("last_ack");
351 sprintf(buf
, "0 %u %u %u %u %u %u %u %u 0",
352 v
[1], v
[2], v
[3], v
[4], v
[5], v
[6], v
[7], v
[8]);
353 nvram_set("ct_tcp_timeout", buf
);
356 p
= nvram_safe_get("ct_udp_timeout");
357 if (sscanf(p
, "%u%u", &v
[0], &v
[1]) == 2) {
358 write_udp_timeout(NULL
, v
[0]);
359 write_udp_timeout("stream", v
[1]);
362 v
[0] = read_udp_timeout(NULL
);
363 v
[1] = read_udp_timeout("stream");
364 sprintf(buf
, "%u %u", v
[0], v
[1]);
365 nvram_set("ct_udp_timeout", buf
);
368 p
= nvram_safe_get("ct_timeout");
369 if (sscanf(p
, "%u%u", &v
[0], &v
[1]) == 2) {
370 write_ct_timeout("generic", NULL
, v
[0]);
371 write_ct_timeout("icmp", NULL
, v
[1]);
374 v
[0] = read_ct_timeout("generic", NULL
);
375 v
[1] = read_ct_timeout("icmp", NULL
);
376 sprintf(buf
, "%u %u", v
[0], v
[1]);
377 nvram_set("ct_timeout", buf
);
381 p
= nvram_safe_get("ct_hashsize");
384 f_write_string("/sys/module/nf_conntrack/parameters/hashsize", p
, 0, 0);
386 else if (f_read_string("/sys/module/nf_conntrack/parameters/hashsize", buf
, sizeof(buf
)) > 0) {
387 if (atoi(buf
) > 0) nvram_set("ct_hashsize", buf
);
391 p
= nvram_safe_get("ct_max");
394 f_write_string("/proc/sys/net/ipv4/netfilter/ip_conntrack_max", p
, 0, 0);
396 else if (f_read_string("/proc/sys/net/ipv4/netfilter/ip_conntrack_max", buf
, sizeof(buf
)) > 0) {
397 if (atoi(buf
) > 0) nvram_set("ct_max", buf
);
400 if (!nvram_match("nf_rtsp", "0")) {
404 ct_modprobe_r("rtsp");
407 if (!nvram_match("nf_h323", "0")) {
411 ct_modprobe_r("h323");
415 if (!nvram_match("nf_sip", "0")) {
419 ct_modprobe_r("sip");
425 i
= nvram_get_int("ftp_port");
426 if (nvram_match("ftp_enable", "1") && (i
> 0) && (i
!= 21))
430 sprintf(ports
, "ports=21,%d", i
);
431 ct_modprobe("ftp", ports
);
435 if (!nvram_match("nf_ftp", "0")
437 || nvram_match("ftp_enable", "1") // !!TB - FTP Server
443 ct_modprobe_r("ftp");
446 if (!nvram_match("nf_pptp", "0")) {
447 ct_modprobe("proto_gre");
451 ct_modprobe_r("pptp");
452 ct_modprobe_r("proto_gre");
456 int host_addr_info(const char *name
, int af
, struct sockaddr_storage
*buf
)
458 struct addrinfo hints
;
459 struct addrinfo
*res
;
464 memset(&hints
, 0, sizeof hints
);
466 switch (af
& (IPT_V4
| IPT_V6
)) {
468 hints
.ai_family
= AF_INET
;
471 hints
.ai_family
= AF_INET6
;
473 //case (IPT_V4 | IPT_V6):
476 hints
.ai_family
= AF_UNSPEC
;
479 hints
.ai_family
= AF_INET
;
481 hints
.ai_socktype
= SOCK_RAW
;
483 if ((err
= getaddrinfo(name
, NULL
, &hints
, &res
)) != 0) {
487 for(p
= res
; p
!= NULL
; p
= p
->ai_next
) {
488 switch(p
->ai_family
) {
496 if (buf
&& (hints
.ai_family
== p
->ai_family
) && res
->ai_addrlen
) {
497 memcpy(buf
, res
->ai_addr
, res
->ai_addrlen
);
502 return (addrtypes
& af
);
505 inline int host_addrtypes(const char *name
, int af
)
507 return host_addr_info(name
, af
, NULL
);
510 void inc_mac(char *mac
, int plus
)
515 for (i
= 0; i
< 6; i
++)
516 m
[i
] = (unsigned char) strtol(mac
+ (3 * i
), (char **)NULL
, 16);
518 for (i
= 5; i
>= 3; --i
) {
519 m
[i
] += (plus
< 0) ? -1 : 1;
520 if (m
[i
] != 0) break; // continue if rolled over
522 plus
+= (plus
< 0) ? 1 : -1;
524 sprintf(mac
, "%02X:%02X:%02X:%02X:%02X:%02X",
525 m
[0], m
[1], m
[2], m
[3], m
[4], m
[5]);
528 void set_mac(const char *ifname
, const char *nvname
, int plus
)
535 if ((sfd
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
)) < 0) {
536 _dprintf("%s: %s %d\n", ifname
, __FUNCTION__
, __LINE__
);
540 strcpy(ifr
.ifr_name
, ifname
);
543 if (ioctl(sfd
, SIOCGIFFLAGS
, &ifr
) == 0) {
544 if ((up
= ifr
.ifr_flags
& IFF_UP
) != 0) {
545 ifr
.ifr_flags
&= ~IFF_UP
;
546 if (ioctl(sfd
, SIOCSIFFLAGS
, &ifr
) != 0) {
547 _dprintf("%s: %s %d\n", ifname
, __FUNCTION__
, __LINE__
);
552 _dprintf("%s: %s %d\n", ifname
, __FUNCTION__
, __LINE__
);
555 if (!ether_atoe(nvram_safe_get(nvname
), (unsigned char *)&ifr
.ifr_hwaddr
.sa_data
)) {
556 if (!ether_atoe(nvram_safe_get("et0macaddr"), (unsigned char *)&ifr
.ifr_hwaddr
.sa_data
)) {
558 // goofy et0macaddr, make something up
559 nvram_set("et0macaddr", "00:01:23:45:67:89");
560 ifr
.ifr_hwaddr
.sa_data
[0] = 0;
561 ifr
.ifr_hwaddr
.sa_data
[1] = 0x01;
562 ifr
.ifr_hwaddr
.sa_data
[2] = 0x23;
563 ifr
.ifr_hwaddr
.sa_data
[3] = 0x45;
564 ifr
.ifr_hwaddr
.sa_data
[4] = 0x67;
565 ifr
.ifr_hwaddr
.sa_data
[5] = 0x89;
569 for (j
= 5; j
>= 3; --j
) {
570 ifr
.ifr_hwaddr
.sa_data
[j
]++;
571 if (ifr
.ifr_hwaddr
.sa_data
[j
] != 0) break; // continue if rolled over
576 ifr
.ifr_hwaddr
.sa_family
= ARPHRD_ETHER
;
577 if (ioctl(sfd
, SIOCSIFHWADDR
, &ifr
) == -1) {
578 _dprintf("Error setting %s address\n", ifname
);
582 if (ioctl(sfd
, SIOCGIFFLAGS
, &ifr
) == 0) {
583 ifr
.ifr_flags
|= IFF_UP
|IFF_RUNNING
;
584 if (ioctl(sfd
, SIOCSIFFLAGS
, &ifr
) == -1) {
585 _dprintf("%s: %s %d\n", ifname
, __FUNCTION__
, __LINE__
);
589 _dprintf("%s: %s %d\n", ifname
, __FUNCTION__
, __LINE__
);
597 const char *default_wanif(void)
599 return ((strtoul(nvram_safe_get("boardflags"), NULL, 0) & BFL_ENETVLAN) ||
600 (check_hw_type() == HW_BCM4712)) ? "vlan1" : "eth1";
605 const char *default_wlif(void)
607 switch (check_hw_type()) {
609 case HW_BCM4704_BCM5325F:
610 case HW_BCM4704_BCM5325F_EWC:
618 int _vstrsep(char *buf
, const char *sep
, ...)
626 while ((p
= va_arg(ap
, char **)) != NULL
) {
627 if ((*p
= strsep(&buf
, sep
)) == NULL
) break;
634 void simple_unlock(const char *name
)
638 snprintf(fn
, sizeof(fn
), "/var/lock/%s.lock", name
);
639 f_write(fn
, NULL
, 0, 0, 0600);
642 void simple_lock(const char *name
)
647 n
= 5 + (getpid() % 10);
648 snprintf(fn
, sizeof(fn
), "/var/lock/%s.lock", name
);
649 while (unlink(fn
) != 0) {
651 syslog(LOG_DEBUG
, "Breaking %s", fn
);
658 void killall_tk(const char *name
)
662 if (killall(name
, SIGTERM
) == 0) {
664 while ((killall(name
, 0) == 0) && (n
-- > 0)) {
665 _dprintf("%s: waiting name=%s n=%d\n", __FUNCTION__
, name
, n
);
670 while ((killall(name
, SIGKILL
) == 0) && (n
-- > 0)) {
671 _dprintf("%s: SIGKILL name=%s n=%d\n", __FUNCTION__
, name
, n
);
679 * Return non-zero if we created the directory,
680 * and zero if it already existed.
682 int mkdir_if_none(const char *path
)
686 if (!(dp
= opendir(path
))) {
687 eval("mkdir", "-m", "0777", "-p", (char *)path
);
694 long fappend(FILE *out
, const char *fname
)
701 if ((in
= fopen(fname
, "r")) == NULL
) return -1;
703 while ((n
= fread(buf
, 1, sizeof(buf
), in
)) > 0) {
704 if (fwrite(buf
, 1, n
, out
) != n
) {
716 long fappend_file(const char *path
, const char *fname
)
721 if (f_exists(fname
) && (f
= fopen(path
, "a")) != NULL
) {
722 r
= fappend(f
, fname
);