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");
457 struct sockaddr_storage *host_to_addr(const char *name, sa_family_t family)
459 static struct sockaddr_storage buf;
461 struct addrinfo hints;
462 struct addrinfo *res;
465 memset(&hints, 0, sizeof(hints));
467 hints.ai_family = family;
469 hints.ai_family = AF_INET;
471 hints.ai_socktype = SOCK_RAW;
473 if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0)
477 if (res->ai_family != family)
480 if (family == AF_INET6) {
481 if (res->ai_addrlen != sizeof(struct sockaddr_in6))
483 memcpy(&buf, res->ai_addr, sizeof(struct sockaddr_in6));
488 if (res->ai_addrlen != sizeof(struct sockaddr_in))
490 memcpy(&buf, res->ai_addr, sizeof(struct sockaddr_in));
498 int host_addrtypes(const char *name
, int af
)
500 struct addrinfo hints
;
501 struct addrinfo
*res
;
506 memset(&hints
, 0, sizeof hints
);
508 switch (af
& (IPT_V4
| IPT_V6
)) {
510 hints
.ai_family
= AF_INET
;
513 hints
.ai_family
= AF_INET6
;
515 //case (IPT_V4 | IPT_V6):
518 hints
.ai_family
= AF_UNSPEC
;
521 hints
.ai_family
= AF_INET
;
523 hints
.ai_socktype
= SOCK_RAW
;
525 if ((err
= getaddrinfo(name
, NULL
, &hints
, &res
)) != 0) {
529 for(p
= res
; p
!= NULL
; p
= p
->ai_next
) {
530 switch(p
->ai_family
) {
541 return (addrtypes
& af
);
545 void inc_mac(char *mac
, int plus
)
550 for (i
= 0; i
< 6; i
++)
551 m
[i
] = (unsigned char) strtol(mac
+ (3 * i
), (char **)NULL
, 16);
553 for (i
= 5; i
>= 3; --i
) {
554 m
[i
] += (plus
< 0) ? -1 : 1;
555 if (m
[i
] != 0) break; // continue if rolled over
557 plus
+= (plus
< 0) ? 1 : -1;
559 sprintf(mac
, "%02X:%02X:%02X:%02X:%02X:%02X",
560 m
[0], m
[1], m
[2], m
[3], m
[4], m
[5]);
563 void set_mac(const char *ifname
, const char *nvname
, int plus
)
570 if ((sfd
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
)) < 0) {
571 _dprintf("%s: %s %d\n", ifname
, __FUNCTION__
, __LINE__
);
575 strcpy(ifr
.ifr_name
, ifname
);
578 if (ioctl(sfd
, SIOCGIFFLAGS
, &ifr
) == 0) {
579 if ((up
= ifr
.ifr_flags
& IFF_UP
) != 0) {
580 ifr
.ifr_flags
&= ~IFF_UP
;
581 if (ioctl(sfd
, SIOCSIFFLAGS
, &ifr
) != 0) {
582 _dprintf("%s: %s %d\n", ifname
, __FUNCTION__
, __LINE__
);
587 _dprintf("%s: %s %d\n", ifname
, __FUNCTION__
, __LINE__
);
590 if (!ether_atoe(nvram_safe_get(nvname
), (unsigned char *)&ifr
.ifr_hwaddr
.sa_data
)) {
591 if (!ether_atoe(nvram_safe_get("et0macaddr"), (unsigned char *)&ifr
.ifr_hwaddr
.sa_data
)) {
593 // goofy et0macaddr, make something up
594 nvram_set("et0macaddr", "00:01:23:45:67:89");
595 ifr
.ifr_hwaddr
.sa_data
[0] = 0;
596 ifr
.ifr_hwaddr
.sa_data
[1] = 0x01;
597 ifr
.ifr_hwaddr
.sa_data
[2] = 0x23;
598 ifr
.ifr_hwaddr
.sa_data
[3] = 0x45;
599 ifr
.ifr_hwaddr
.sa_data
[4] = 0x67;
600 ifr
.ifr_hwaddr
.sa_data
[5] = 0x89;
604 for (j
= 5; j
>= 3; --j
) {
605 ifr
.ifr_hwaddr
.sa_data
[j
]++;
606 if (ifr
.ifr_hwaddr
.sa_data
[j
] != 0) break; // continue if rolled over
611 ifr
.ifr_hwaddr
.sa_family
= ARPHRD_ETHER
;
612 if (ioctl(sfd
, SIOCSIFHWADDR
, &ifr
) == -1) {
613 _dprintf("Error setting %s address\n", ifname
);
617 if (ioctl(sfd
, SIOCGIFFLAGS
, &ifr
) == 0) {
618 ifr
.ifr_flags
|= IFF_UP
|IFF_RUNNING
;
619 if (ioctl(sfd
, SIOCSIFFLAGS
, &ifr
) == -1) {
620 _dprintf("%s: %s %d\n", ifname
, __FUNCTION__
, __LINE__
);
624 _dprintf("%s: %s %d\n", ifname
, __FUNCTION__
, __LINE__
);
632 const char *default_wanif(void)
634 return ((strtoul(nvram_safe_get("boardflags"), NULL, 0) & BFL_ENETVLAN) ||
635 (check_hw_type() == HW_BCM4712)) ? "vlan1" : "eth1";
640 const char *default_wlif(void)
642 switch (check_hw_type()) {
644 case HW_BCM4704_BCM5325F:
645 case HW_BCM4704_BCM5325F_EWC:
653 int _vstrsep(char *buf
, const char *sep
, ...)
661 while ((p
= va_arg(ap
, char **)) != NULL
) {
662 if ((*p
= strsep(&buf
, sep
)) == NULL
) break;
669 void simple_unlock(const char *name
)
673 snprintf(fn
, sizeof(fn
), "/var/lock/%s.lock", name
);
674 f_write(fn
, NULL
, 0, 0, 0600);
677 void simple_lock(const char *name
)
682 n
= 5 + (getpid() % 10);
683 snprintf(fn
, sizeof(fn
), "/var/lock/%s.lock", name
);
684 while (unlink(fn
) != 0) {
686 syslog(LOG_DEBUG
, "Breaking %s", fn
);
693 void killall_tk(const char *name
)
697 if (killall(name
, SIGTERM
) == 0) {
699 while ((killall(name
, 0) == 0) && (n
-- > 0)) {
700 _dprintf("%s: waiting name=%s n=%d\n", __FUNCTION__
, name
, n
);
705 while ((killall(name
, SIGKILL
) == 0) && (n
-- > 0)) {
706 _dprintf("%s: SIGKILL name=%s n=%d\n", __FUNCTION__
, name
, n
);
714 * Return non-zero if we created the directory,
715 * and zero if it already existed.
717 int mkdir_if_none(const char *path
)
721 if (!(dp
= opendir(path
))) {
722 eval("mkdir", "-m", "0777", "-p", (char *)path
);
729 long fappend(FILE *out
, const char *fname
)
736 if ((in
= fopen(fname
, "r")) == NULL
) return -1;
738 while ((n
= fread(buf
, 1, sizeof(buf
), in
)) > 0) {
739 if (fwrite(buf
, 1, n
, out
) != n
) {
751 long fappend_file(const char *path
, const char *fname
)
756 if (f_exists(fname
) && (f
= fopen(path
, "a")) != NULL
) {
757 r
= fappend(f
, fname
);