aboutsummaryrefslogtreecommitdiff
path: root/networking
diff options
context:
space:
mode:
Diffstat (limited to 'networking')
-rw-r--r--networking/arp.c1
-rw-r--r--networking/arping.c1
-rw-r--r--networking/brctl.c1
-rw-r--r--networking/ether-wake.c1
-rw-r--r--networking/httpd.c192
-rw-r--r--networking/httpd_indexcgi.c80
-rw-r--r--networking/ifconfig.c1
-rw-r--r--networking/ifenslave.c1
-rw-r--r--networking/ifplugd.c1
-rw-r--r--networking/ip.c11
-rw-r--r--networking/libiproute/ip_common.h4
-rw-r--r--networking/libiproute/ipaddress.c104
-rw-r--r--networking/nameif.c1
-rw-r--r--networking/netstat.c1
-rw-r--r--networking/ntpd.c38
-rw-r--r--networking/parse_pasv_epsv.c2
-rw-r--r--networking/ping.c1
-rw-r--r--networking/route.c1
-rw-r--r--networking/slattach.c1
-rw-r--r--networking/tls.c2
-rw-r--r--networking/traceroute.c1
-rw-r--r--networking/tunctl.c1
-rw-r--r--networking/udhcp/Config.src2
-rw-r--r--networking/udhcp/dhcpc.c138
-rw-r--r--networking/udhcp/dhcpc.h1
-rw-r--r--networking/udhcp/domain_codec.c157
-rw-r--r--networking/vconfig.c1
-rw-r--r--networking/zcip.c1
28 files changed, 498 insertions, 249 deletions
diff --git a/networking/arp.c b/networking/arp.c
index 6519f8156..16783ab95 100644
--- a/networking/arp.c
+++ b/networking/arp.c
@@ -15,7 +15,6 @@
15//config:config ARP 15//config:config ARP
16//config: bool "arp (10 kb)" 16//config: bool "arp (10 kb)"
17//config: default y 17//config: default y
18//config: select PLATFORM_LINUX
19//config: help 18//config: help
20//config: Manipulate the system ARP cache. 19//config: Manipulate the system ARP cache.
21 20
diff --git a/networking/arping.c b/networking/arping.c
index 2a256aaa0..d44d7d697 100644
--- a/networking/arping.c
+++ b/networking/arping.c
@@ -8,7 +8,6 @@
8//config:config ARPING 8//config:config ARPING
9//config: bool "arping (9 kb)" 9//config: bool "arping (9 kb)"
10//config: default y 10//config: default y
11//config: select PLATFORM_LINUX
12//config: help 11//config: help
13//config: Ping hosts by ARP packets. 12//config: Ping hosts by ARP packets.
14 13
diff --git a/networking/brctl.c b/networking/brctl.c
index 2f4ac4a87..f057f9b60 100644
--- a/networking/brctl.c
+++ b/networking/brctl.c
@@ -12,7 +12,6 @@
12//config:config BRCTL 12//config:config BRCTL
13//config: bool "brctl (4.7 kb)" 13//config: bool "brctl (4.7 kb)"
14//config: default y 14//config: default y
15//config: select PLATFORM_LINUX
16//config: help 15//config: help
17//config: Manage ethernet bridges. 16//config: Manage ethernet bridges.
18//config: Supports addbr/delbr and addif/delif. 17//config: Supports addbr/delbr and addif/delif.
diff --git a/networking/ether-wake.c b/networking/ether-wake.c
index f45d43609..36e90acfb 100644
--- a/networking/ether-wake.c
+++ b/networking/ether-wake.c
@@ -66,7 +66,6 @@
66//config:config ETHER_WAKE 66//config:config ETHER_WAKE
67//config: bool "ether-wake (4.9 kb)" 67//config: bool "ether-wake (4.9 kb)"
68//config: default y 68//config: default y
69//config: select PLATFORM_LINUX
70//config: help 69//config: help
71//config: Send a magic packet to wake up sleeping machines. 70//config: Send a magic packet to wake up sleeping machines.
72 71
diff --git a/networking/httpd.c b/networking/httpd.c
index 5d2d2681c..19cc08fcb 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -214,6 +214,44 @@
214//config: help 214//config: help
215//config: Makes httpd send files using GZIP content encoding if the 215//config: Makes httpd send files using GZIP content encoding if the
216//config: client supports it and a pre-compressed <file>.gz exists. 216//config: client supports it and a pre-compressed <file>.gz exists.
217//config:
218//config:config FEATURE_HTTPD_ETAG
219//config: bool "Support caching via ETag header"
220//config: default y
221//config: depends on HTTPD
222//config: help
223//config: If server responds with ETag then next time client (browser)
224//config: resend it via If-None-Match header.
225//config: Then httpd will check if file wasn't modified and if not,
226//config: return 304 Not Modified status code.
227//config: The ETag value is constructed from last modification date
228//config: in unix epoch, and size: "hex(last_mod)-hex(file_size)".
229//config: It's not completely reliable as hash functions but fair enough.
230//config:
231//config:config FEATURE_HTTPD_LAST_MODIFIED
232//config: bool "Add Last-Modified header to response"
233//config: default y
234//config: depends on HTTPD
235//config: help
236//config: The Last-Modified header is used for cache validation.
237//config: The client sends last seen mtime to server in If-Modified-Since.
238//config: Both headers MUST be an RFC 1123 formatted, which is hard to parse.
239//config: Use ETag header instead.
240//config:
241//config:config FEATURE_HTTPD_DATE
242//config: bool "Add Date header to response"
243//config: default y
244//config: depends on HTTPD
245//config: help
246//config: RFC2616 says that server MUST add Date header to response.
247//config: But it is almost useless and can be omitted.
248//config:
249//config:config FEATURE_HTTPD_ACL_IP
250//config: bool "ACL IP"
251//config: default y
252//config: depends on HTTPD
253//config: help
254//config: Support IP deny/allow rules
217 255
218//applet:IF_HTTPD(APPLET(httpd, BB_DIR_USR_SBIN, BB_SUID_DROP)) 256//applet:IF_HTTPD(APPLET(httpd, BB_DIR_USR_SBIN, BB_SUID_DROP))
219 257
@@ -278,7 +316,7 @@ static void send_REQUEST_TIMEOUT_and_exit(int sig) NORETURN;
278 316
279static const char DEFAULT_PATH_HTTPD_CONF[] ALIGN1 = "/etc"; 317static const char DEFAULT_PATH_HTTPD_CONF[] ALIGN1 = "/etc";
280static const char HTTPD_CONF[] ALIGN1 = "httpd.conf"; 318static const char HTTPD_CONF[] ALIGN1 = "httpd.conf";
281static const char HTTP_200[] ALIGN1 = "HTTP/1.0 200 OK\r\n"; 319static const char HTTP_200[] ALIGN1 = "HTTP/1.1 200 OK\r\n";
282static const char index_html[] ALIGN1 = "index.html"; 320static const char index_html[] ALIGN1 = "index.html";
283 321
284typedef struct has_next_ptr { 322typedef struct has_next_ptr {
@@ -292,6 +330,7 @@ typedef struct Htaccess {
292 char before_colon[1]; /* really bigger, must be last */ 330 char before_colon[1]; /* really bigger, must be last */
293} Htaccess; 331} Htaccess;
294 332
333#if ENABLE_FEATURE_HTTPD_ACL_IP
295/* Must have "next" as a first member */ 334/* Must have "next" as a first member */
296typedef struct Htaccess_IP { 335typedef struct Htaccess_IP {
297 struct Htaccess_IP *next; 336 struct Htaccess_IP *next;
@@ -299,6 +338,7 @@ typedef struct Htaccess_IP {
299 unsigned mask; 338 unsigned mask;
300 int allow_deny; 339 int allow_deny;
301} Htaccess_IP; 340} Htaccess_IP;
341#endif
302 342
303/* Must have "next" as a first member */ 343/* Must have "next" as a first member */
304typedef struct Htaccess_Proxy { 344typedef struct Htaccess_Proxy {
@@ -319,6 +359,7 @@ enum {
319 HTTP_OK = 200, 359 HTTP_OK = 200,
320 HTTP_PARTIAL_CONTENT = 206, 360 HTTP_PARTIAL_CONTENT = 206,
321 HTTP_MOVED_TEMPORARILY = 302, 361 HTTP_MOVED_TEMPORARILY = 302,
362 HTTP_NOT_MODIFIED = 304,
322 HTTP_BAD_REQUEST = 400, /* malformed syntax */ 363 HTTP_BAD_REQUEST = 400, /* malformed syntax */
323 HTTP_UNAUTHORIZED = 401, /* authentication needed, respond with auth hdr */ 364 HTTP_UNAUTHORIZED = 401, /* authentication needed, respond with auth hdr */
324 HTTP_NOT_FOUND = 404, 365 HTTP_NOT_FOUND = 404,
@@ -336,7 +377,6 @@ enum {
336 HTTP_NO_CONTENT = 204, 377 HTTP_NO_CONTENT = 204,
337 HTTP_MULTIPLE_CHOICES = 300, 378 HTTP_MULTIPLE_CHOICES = 300,
338 HTTP_MOVED_PERMANENTLY = 301, 379 HTTP_MOVED_PERMANENTLY = 301,
339 HTTP_NOT_MODIFIED = 304,
340 HTTP_PAYMENT_REQUIRED = 402, 380 HTTP_PAYMENT_REQUIRED = 402,
341 HTTP_BAD_GATEWAY = 502, 381 HTTP_BAD_GATEWAY = 502,
342 HTTP_SERVICE_UNAVAILABLE = 503, /* overload, maintenance */ 382 HTTP_SERVICE_UNAVAILABLE = 503, /* overload, maintenance */
@@ -349,6 +389,9 @@ static const uint16_t http_response_type[] ALIGN2 = {
349 HTTP_PARTIAL_CONTENT, 389 HTTP_PARTIAL_CONTENT,
350#endif 390#endif
351 HTTP_MOVED_TEMPORARILY, 391 HTTP_MOVED_TEMPORARILY,
392#if ENABLE_FEATURE_HTTPD_ETAG
393 HTTP_NOT_MODIFIED,
394#endif
352 HTTP_REQUEST_TIMEOUT, 395 HTTP_REQUEST_TIMEOUT,
353 HTTP_NOT_IMPLEMENTED, 396 HTTP_NOT_IMPLEMENTED,
354#if ENABLE_FEATURE_HTTPD_BASIC_AUTH 397#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
@@ -365,7 +408,6 @@ static const uint16_t http_response_type[] ALIGN2 = {
365 HTTP_NO_CONTENT, 408 HTTP_NO_CONTENT,
366 HTTP_MULTIPLE_CHOICES, 409 HTTP_MULTIPLE_CHOICES,
367 HTTP_MOVED_PERMANENTLY, 410 HTTP_MOVED_PERMANENTLY,
368 HTTP_NOT_MODIFIED,
369 HTTP_BAD_GATEWAY, 411 HTTP_BAD_GATEWAY,
370 HTTP_SERVICE_UNAVAILABLE, 412 HTTP_SERVICE_UNAVAILABLE,
371#endif 413#endif
@@ -380,6 +422,9 @@ static const struct {
380 { "Partial Content", NULL }, 422 { "Partial Content", NULL },
381#endif 423#endif
382 { "Found", NULL }, 424 { "Found", NULL },
425#if ENABLE_FEATURE_HTTPD_ETAG
426 { "Not Modified" },
427#endif
383 { "Request Timeout", "No request appeared within 60 seconds" }, 428 { "Request Timeout", "No request appeared within 60 seconds" },
384 { "Not Implemented", "The requested method is not recognized" }, 429 { "Not Implemented", "The requested method is not recognized" },
385#if ENABLE_FEATURE_HTTPD_BASIC_AUTH 430#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
@@ -396,7 +441,6 @@ static const struct {
396 { "No Content" }, 441 { "No Content" },
397 { "Multiple Choices" }, 442 { "Multiple Choices" },
398 { "Moved Permanently" }, 443 { "Moved Permanently" },
399 { "Not Modified" },
400 { "Bad Gateway", "" }, 444 { "Bad Gateway", "" },
401 { "Service Unavailable", "" }, 445 { "Service Unavailable", "" },
402#endif 446#endif
@@ -410,6 +454,9 @@ struct globals {
410 smallint content_gzip; 454 smallint content_gzip;
411#endif 455#endif
412 time_t last_mod; 456 time_t last_mod;
457#if ENABLE_FEATURE_HTTPD_ETAG
458 char *if_none_match;
459#endif
413 char *rmt_ip_str; /* for $REMOTE_ADDR and $REMOTE_PORT */ 460 char *rmt_ip_str; /* for $REMOTE_ADDR and $REMOTE_PORT */
414 const char *bind_addr_or_port; 461 const char *bind_addr_or_port;
415 462
@@ -420,7 +467,9 @@ struct globals {
420 467
421 const char *found_mime_type; 468 const char *found_mime_type;
422 const char *found_moved_temporarily; 469 const char *found_moved_temporarily;
470#if ENABLE_FEATURE_HTTPD_ACL_IP
423 Htaccess_IP *ip_a_d; /* config allow/deny lines */ 471 Htaccess_IP *ip_a_d; /* config allow/deny lines */
472#endif
424 473
425 IF_FEATURE_HTTPD_BASIC_AUTH(const char *g_realm;) 474 IF_FEATURE_HTTPD_BASIC_AUTH(const char *g_realm;)
426 IF_FEATURE_HTTPD_BASIC_AUTH(char *remoteuser;) 475 IF_FEATURE_HTTPD_BASIC_AUTH(char *remoteuser;)
@@ -444,6 +493,9 @@ struct globals {
444#define sizeof_hdr_buf COMMON_BUFSIZE 493#define sizeof_hdr_buf COMMON_BUFSIZE
445 char *hdr_ptr; 494 char *hdr_ptr;
446 int hdr_cnt; 495 int hdr_cnt;
496#if ENABLE_FEATURE_HTTPD_ETAG
497 char etag[sizeof("'%llx-%llx'") + 2 * sizeof(long long)*3];
498#endif
447#if ENABLE_FEATURE_HTTPD_ERROR_PAGES 499#if ENABLE_FEATURE_HTTPD_ERROR_PAGES
448 const char *http_error_page[ARRAY_SIZE(http_response_type)]; 500 const char *http_error_page[ARRAY_SIZE(http_response_type)];
449#endif 501#endif
@@ -467,7 +519,6 @@ struct globals {
467#define found_mime_type (G.found_mime_type ) 519#define found_mime_type (G.found_mime_type )
468#define found_moved_temporarily (G.found_moved_temporarily) 520#define found_moved_temporarily (G.found_moved_temporarily)
469#define last_mod (G.last_mod ) 521#define last_mod (G.last_mod )
470#define ip_a_d (G.ip_a_d )
471#define g_realm (G.g_realm ) 522#define g_realm (G.g_realm )
472#define remoteuser (G.remoteuser ) 523#define remoteuser (G.remoteuser )
473#define file_size (G.file_size ) 524#define file_size (G.file_size )
@@ -528,11 +579,14 @@ static ALWAYS_INLINE void free_Htaccess_list(Htaccess **pptr)
528 free_llist((has_next_ptr**)pptr); 579 free_llist((has_next_ptr**)pptr);
529} 580}
530 581
582#if ENABLE_FEATURE_HTTPD_ACL_IP
531static ALWAYS_INLINE void free_Htaccess_IP_list(Htaccess_IP **pptr) 583static ALWAYS_INLINE void free_Htaccess_IP_list(Htaccess_IP **pptr)
532{ 584{
533 free_llist((has_next_ptr**)pptr); 585 free_llist((has_next_ptr**)pptr);
534} 586}
587#endif
535 588
589#if ENABLE_FEATURE_HTTPD_ACL_IP
536/* Returns presumed mask width in bits or < 0 on error. 590/* Returns presumed mask width in bits or < 0 on error.
537 * Updates strp, stores IP at provided pointer */ 591 * Updates strp, stores IP at provided pointer */
538static int scan_ip(const char **strp, unsigned *ipp, unsigned char endc) 592static int scan_ip(const char **strp, unsigned *ipp, unsigned char endc)
@@ -617,6 +671,7 @@ static int scan_ip_mask(const char *str, unsigned *ipp, unsigned *maskp)
617 *maskp = (uint32_t)(~mask); 671 *maskp = (uint32_t)(~mask);
618 return 0; 672 return 0;
619} 673}
674#endif
620 675
621/* 676/*
622 * Parse configuration file into in-memory linked list. 677 * Parse configuration file into in-memory linked list.
@@ -646,7 +701,9 @@ static void parse_conf(const char *path, int flag)
646 char buf[160]; 701 char buf[160];
647 702
648 /* discard old rules */ 703 /* discard old rules */
649 free_Htaccess_IP_list(&ip_a_d); 704#if ENABLE_FEATURE_HTTPD_ACL_IP
705 free_Htaccess_IP_list(&G.ip_a_d);
706#endif
650 flg_deny_all = 0; 707 flg_deny_all = 0;
651 /* retain previous auth and mime config only for subdir parse */ 708 /* retain previous auth and mime config only for subdir parse */
652 if (flag != SUBDIR_PARSE) { 709 if (flag != SUBDIR_PARSE) {
@@ -763,6 +820,7 @@ static void parse_conf(const char *path, int flag)
763 continue; 820 continue;
764 } 821 }
765 822
823#if ENABLE_FEATURE_HTTPD_ACL_IP
766 if (ch == 'A' || ch == 'D') { 824 if (ch == 'A' || ch == 'D') {
767 Htaccess_IP *pip; 825 Htaccess_IP *pip;
768 826
@@ -784,13 +842,13 @@ static void parse_conf(const char *path, int flag)
784 pip->allow_deny = ch; 842 pip->allow_deny = ch;
785 if (ch == 'D') { 843 if (ch == 'D') {
786 /* Deny:from_IP - prepend */ 844 /* Deny:from_IP - prepend */
787 pip->next = ip_a_d; 845 pip->next = G.ip_a_d;
788 ip_a_d = pip; 846 G.ip_a_d = pip;
789 } else { 847 } else {
790 /* A:from_IP - append (thus all D's precedes A's) */ 848 /* A:from_IP - append (thus all D's precedes A's) */
791 Htaccess_IP *prev_IP = ip_a_d; 849 Htaccess_IP *prev_IP = G.ip_a_d;
792 if (prev_IP == NULL) { 850 if (prev_IP == NULL) {
793 ip_a_d = pip; 851 G.ip_a_d = pip;
794 } else { 852 } else {
795 while (prev_IP->next) 853 while (prev_IP->next)
796 prev_IP = prev_IP->next; 854 prev_IP = prev_IP->next;
@@ -799,6 +857,7 @@ static void parse_conf(const char *path, int flag)
799 } 857 }
800 continue; 858 continue;
801 } 859 }
860#endif
802 861
803#if ENABLE_FEATURE_HTTPD_ERROR_PAGES 862#if ENABLE_FEATURE_HTTPD_ERROR_PAGES
804 if (flag == FIRST_PARSE && ch == 'E') { 863 if (flag == FIRST_PARSE && ch == 'E') {
@@ -1059,11 +1118,12 @@ static void log_and_exit(void)
1059 */ 1118 */
1060static void send_headers(unsigned responseNum) 1119static void send_headers(unsigned responseNum)
1061{ 1120{
1121#if ENABLE_FEATURE_HTTPD_DATE || ENABLE_FEATURE_HTTPD_LAST_MODIFIED
1062 static const char RFC1123FMT[] ALIGN1 = "%a, %d %b %Y %H:%M:%S GMT"; 1122 static const char RFC1123FMT[] ALIGN1 = "%a, %d %b %Y %H:%M:%S GMT";
1063 /* Fixed size 29-byte string. Example: Sun, 06 Nov 1994 08:49:37 GMT */ 1123 /* Fixed size 29-byte string. Example: Sun, 06 Nov 1994 08:49:37 GMT */
1064 char date_str[40]; /* using a bit larger buffer to paranoia reasons */ 1124 char date_str[40]; /* using a bit larger buffer to paranoia reasons */
1065
1066 struct tm tm; 1125 struct tm tm;
1126#endif
1067 const char *responseString = ""; 1127 const char *responseString = "";
1068 const char *infoString = NULL; 1128 const char *infoString = NULL;
1069#if ENABLE_FEATURE_HTTPD_ERROR_PAGES 1129#if ENABLE_FEATURE_HTTPD_ERROR_PAGES
@@ -1071,7 +1131,6 @@ static void send_headers(unsigned responseNum)
1071#endif 1131#endif
1072 unsigned len; 1132 unsigned len;
1073 unsigned i; 1133 unsigned i;
1074 time_t timer = time(NULL);
1075 1134
1076 for (i = 0; i < ARRAY_SIZE(http_response_type); i++) { 1135 for (i = 0; i < ARRAY_SIZE(http_response_type); i++) {
1077 if (http_response_type[i] == responseNum) { 1136 if (http_response_type[i] == responseNum) {
@@ -1092,15 +1151,24 @@ static void send_headers(unsigned responseNum)
1092 * always fit into those kbytes. 1151 * always fit into those kbytes.
1093 */ 1152 */
1094 1153
1095 strftime(date_str, sizeof(date_str), RFC1123FMT, gmtime_r(&timer, &tm)); 1154 {
1096 /* ^^^ using gmtime_r() instead of gmtime() to not use static data */ 1155#if ENABLE_FEATURE_HTTPD_DATE
1097 len = sprintf(iobuf, 1156 time_t timer = time(NULL);
1098 "HTTP/1.0 %u %s\r\n" 1157 strftime(date_str, sizeof(date_str), RFC1123FMT, gmtime_r(&timer, &tm));
1158 /* ^^^ using gmtime_r() instead of gmtime() to not use static data */
1159#endif
1160 len = sprintf(iobuf,
1161 "HTTP/1.1 %u %s\r\n"
1162#if ENABLE_FEATURE_HTTPD_DATE
1099 "Date: %s\r\n" 1163 "Date: %s\r\n"
1164#endif
1100 "Connection: close\r\n", 1165 "Connection: close\r\n",
1101 responseNum, responseString, 1166 responseNum, responseString
1102 date_str 1167#if ENABLE_FEATURE_HTTPD_DATE
1103 ); 1168 ,date_str
1169#endif
1170 );
1171 }
1104 1172
1105 if (responseNum != HTTP_OK || found_mime_type) { 1173 if (responseNum != HTTP_OK || found_mime_type) {
1106 len += sprintf(iobuf + len, 1174 len += sprintf(iobuf + len,
@@ -1120,7 +1188,7 @@ static void send_headers(unsigned responseNum)
1120#endif 1188#endif
1121 if (responseNum == HTTP_MOVED_TEMPORARILY) { 1189 if (responseNum == HTTP_MOVED_TEMPORARILY) {
1122 /* Responding to "GET /dir" with 1190 /* Responding to "GET /dir" with
1123 * "HTTP/1.0 302 Found" "Location: /dir/" 1191 * "HTTP/1.1 302 Found" "Location: /dir/"
1124 * - IOW, asking them to repeat with a slash. 1192 * - IOW, asking them to repeat with a slash.
1125 * Here, overflow IS possible, can't use sprintf: 1193 * Here, overflow IS possible, can't use sprintf:
1126 * mkdir test 1194 * mkdir test
@@ -1152,7 +1220,9 @@ static void send_headers(unsigned responseNum)
1152#endif 1220#endif
1153 1221
1154 if (file_size != -1) { /* file */ 1222 if (file_size != -1) { /* file */
1223#if ENABLE_FEATURE_HTTPD_LAST_MODIFIED
1155 strftime(date_str, sizeof(date_str), RFC1123FMT, gmtime_r(&last_mod, &tm)); 1224 strftime(date_str, sizeof(date_str), RFC1123FMT, gmtime_r(&last_mod, &tm));
1225#endif
1156#if ENABLE_FEATURE_HTTPD_RANGES 1226#if ENABLE_FEATURE_HTTPD_RANGES
1157 if (responseNum == HTTP_PARTIAL_CONTENT) { 1227 if (responseNum == HTTP_PARTIAL_CONTENT) {
1158 len += sprintf(iobuf + len, 1228 len += sprintf(iobuf + len,
@@ -1197,7 +1267,13 @@ static void send_headers(unsigned responseNum)
1197#if ENABLE_FEATURE_HTTPD_RANGES 1267#if ENABLE_FEATURE_HTTPD_RANGES
1198 "Accept-Ranges: bytes\r\n" 1268 "Accept-Ranges: bytes\r\n"
1199#endif 1269#endif
1270#if ENABLE_FEATURE_HTTPD_LAST_MODIFIED
1200 "Last-Modified: %s\r\n" 1271 "Last-Modified: %s\r\n"
1272#endif
1273#if ENABLE_FEATURE_HTTPD_ETAG
1274 "ETag: %s\r\n"
1275#endif
1276
1201 /* Because of 4.4 (5), we can forgo sending of "Content-Length" 1277 /* Because of 4.4 (5), we can forgo sending of "Content-Length"
1202 * since we close connection afterwards, but it helps clients 1278 * since we close connection afterwards, but it helps clients
1203 * to e.g. estimate download times, show progress bars etc. 1279 * to e.g. estimate download times, show progress bars etc.
@@ -1205,7 +1281,12 @@ static void send_headers(unsigned responseNum)
1205 * but de-facto standard is to send it (see comment below). 1281 * but de-facto standard is to send it (see comment below).
1206 */ 1282 */
1207 "Content-Length: %"OFF_FMT"u\r\n", 1283 "Content-Length: %"OFF_FMT"u\r\n",
1284#if ENABLE_FEATURE_HTTPD_LAST_MODIFIED
1208 date_str, 1285 date_str,
1286#endif
1287#if ENABLE_FEATURE_HTTPD_ETAG
1288 G.etag,
1289#endif
1209 file_size 1290 file_size
1210 ); 1291 );
1211 } 1292 }
@@ -1444,7 +1525,7 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post
1444 count = safe_read(fromCgi_rd, rbuf + out_cnt, IOBUF_SIZE - 8); 1525 count = safe_read(fromCgi_rd, rbuf + out_cnt, IOBUF_SIZE - 8);
1445 if (count <= 0) { 1526 if (count <= 0) {
1446 /* eof (or error) and there was no "HTTP", 1527 /* eof (or error) and there was no "HTTP",
1447 * send "HTTP/1.0 200 OK\r\n", then send received data */ 1528 * send "HTTP/1.1 200 OK\r\n", then send received data */
1448 if (out_cnt) { 1529 if (out_cnt) {
1449 full_write(STDOUT_FILENO, HTTP_200, sizeof(HTTP_200)-1); 1530 full_write(STDOUT_FILENO, HTTP_200, sizeof(HTTP_200)-1);
1450 full_write(STDOUT_FILENO, rbuf, out_cnt); 1531 full_write(STDOUT_FILENO, rbuf, out_cnt);
@@ -1455,10 +1536,10 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post
1455 count = 0; 1536 count = 0;
1456 /* "Status" header format is: "Status: 302 Redirected\r\n" */ 1537 /* "Status" header format is: "Status: 302 Redirected\r\n" */
1457 if (out_cnt >= 8 && memcmp(rbuf, "Status: ", 8) == 0) { 1538 if (out_cnt >= 8 && memcmp(rbuf, "Status: ", 8) == 0) {
1458 /* send "HTTP/1.0 " */ 1539 /* send "HTTP/1.1 " */
1459 if (full_write(STDOUT_FILENO, HTTP_200, 9) != 9) 1540 if (full_write(STDOUT_FILENO, HTTP_200, 9) != 9)
1460 break; 1541 break;
1461 /* skip "Status: " (including space, sending "HTTP/1.0 NNN" is wrong) */ 1542 /* skip "Status: " (including space, sending "HTTP/1.1 NNN" is wrong) */
1462 rbuf += 8; 1543 rbuf += 8;
1463 count = out_cnt - 8; 1544 count = out_cnt - 8;
1464 out_cnt = -1; /* buffering off */ 1545 out_cnt = -1; /* buffering off */
@@ -1474,7 +1555,7 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post
1474 full_write(s, "Content-type: text/plain\r\n\r\n", 28); 1555 full_write(s, "Content-type: text/plain\r\n\r\n", 28);
1475 } 1556 }
1476 * Counter-example of valid CGI without Content-type: 1557 * Counter-example of valid CGI without Content-type:
1477 * echo -en "HTTP/1.0 302 Found\r\n" 1558 * echo -en "HTTP/1.1 302 Found\r\n"
1478 * echo -en "Location: http://www.busybox.net\r\n" 1559 * echo -en "Location: http://www.busybox.net\r\n"
1479 * echo -en "\r\n" 1560 * echo -en "\r\n"
1480 */ 1561 */
@@ -1581,7 +1662,7 @@ static void send_cgi_and_exit(
1581 /* (Older versions of bbox seem to do some decoding) */ 1662 /* (Older versions of bbox seem to do some decoding) */
1582 setenv1("QUERY_STRING", g_query); 1663 setenv1("QUERY_STRING", g_query);
1583 putenv((char*)"SERVER_SOFTWARE=busybox httpd/"BB_VER); 1664 putenv((char*)"SERVER_SOFTWARE=busybox httpd/"BB_VER);
1584 putenv((char*)"SERVER_PROTOCOL=HTTP/1.0"); 1665 putenv((char*)"SERVER_PROTOCOL=HTTP/1.1");
1585 putenv((char*)"GATEWAY_INTERFACE=CGI/1.1"); 1666 putenv((char*)"GATEWAY_INTERFACE=CGI/1.1");
1586 /* Having _separate_ variables for IP and port defeats 1667 /* Having _separate_ variables for IP and port defeats
1587 * the purpose of having socket abstraction. Which "port" 1668 * the purpose of having socket abstraction. Which "port"
@@ -1732,6 +1813,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what)
1732 } 1813 }
1733 } else { 1814 } else {
1734 fd = open(url, O_RDONLY); 1815 fd = open(url, O_RDONLY);
1816 /* file_size and last_mod are already populated */
1735 } 1817 }
1736 if (fd < 0) { 1818 if (fd < 0) {
1737 if (DEBUG) 1819 if (DEBUG)
@@ -1743,6 +1825,19 @@ static NOINLINE void send_file_and_exit(const char *url, int what)
1743 send_headers_and_exit(HTTP_NOT_FOUND); 1825 send_headers_and_exit(HTTP_NOT_FOUND);
1744 log_and_exit(); 1826 log_and_exit();
1745 } 1827 }
1828#if ENABLE_FEATURE_HTTPD_ETAG
1829 /* ETag is "hex(last_mod)-hex(file_size)" e.g. "5e132e20-417" */
1830 sprintf(G.etag, "\"%llx-%llx\"", (unsigned long long)last_mod, (unsigned long long)file_size);
1831
1832 if (G.if_none_match) {
1833 if (DEBUG)
1834 bb_perror_msg("If-None-Match and file's ETag are: '%s' '%s'\n", G.if_none_match, G.etag);
1835 /* Weak ETag comparision.
1836 * If-None-Match may have many ETags but they are quoted so we can use simple substring search */
1837 if (strstr(G.if_none_match, G.etag))
1838 send_headers_and_exit(HTTP_NOT_MODIFIED);
1839 }
1840#endif
1746 /* If you want to know about EPIPE below 1841 /* If you want to know about EPIPE below
1747 * (happens if you abort downloads from local httpd): */ 1842 * (happens if you abort downloads from local httpd): */
1748 signal(SIGPIPE, SIG_IGN); 1843 signal(SIGPIPE, SIG_IGN);
@@ -1878,11 +1973,12 @@ static NOINLINE void send_file_and_exit(const char *url, int what)
1878 log_and_exit(); 1973 log_and_exit();
1879} 1974}
1880 1975
1976#if ENABLE_FEATURE_HTTPD_ACL_IP
1881static void if_ip_denied_send_HTTP_FORBIDDEN_and_exit(unsigned remote_ip) 1977static void if_ip_denied_send_HTTP_FORBIDDEN_and_exit(unsigned remote_ip)
1882{ 1978{
1883 Htaccess_IP *cur; 1979 Htaccess_IP *cur;
1884 1980
1885 for (cur = ip_a_d; cur; cur = cur->next) { 1981 for (cur = G.ip_a_d; cur; cur = cur->next) {
1886#if DEBUG 1982#if DEBUG
1887 fprintf(stderr, 1983 fprintf(stderr,
1888 "checkPermIP: '%s' ? '%u.%u.%u.%u/%u.%u.%u.%u'\n", 1984 "checkPermIP: '%s' ? '%u.%u.%u.%u/%u.%u.%u.%u'\n",
@@ -1907,6 +2003,9 @@ static void if_ip_denied_send_HTTP_FORBIDDEN_and_exit(unsigned remote_ip)
1907 if (flg_deny_all) /* depends on whether we saw "D:*" */ 2003 if (flg_deny_all) /* depends on whether we saw "D:*" */
1908 send_headers_and_exit(HTTP_FORBIDDEN); 2004 send_headers_and_exit(HTTP_FORBIDDEN);
1909} 2005}
2006#else
2007# define if_ip_denied_send_HTTP_FORBIDDEN_and_exit(arg) ((void)0)
2008#endif
1910 2009
1911#if ENABLE_FEATURE_HTTPD_BASIC_AUTH 2010#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
1912 2011
@@ -2160,7 +2259,9 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2160 char *urlcopy; 2259 char *urlcopy;
2161 char *urlp; 2260 char *urlp;
2162 char *tptr; 2261 char *tptr;
2262#if ENABLE_FEATURE_HTTPD_ACL_IP
2163 unsigned remote_ip; 2263 unsigned remote_ip;
2264#endif
2164#if ENABLE_FEATURE_HTTPD_CGI 2265#if ENABLE_FEATURE_HTTPD_CGI
2165 unsigned total_headers_len; 2266 unsigned total_headers_len;
2166#endif 2267#endif
@@ -2182,18 +2283,30 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2182 * (IOW, server process doesn't need to waste 8k) */ 2283 * (IOW, server process doesn't need to waste 8k) */
2183 iobuf = xmalloc(IOBUF_SIZE); 2284 iobuf = xmalloc(IOBUF_SIZE);
2184 2285
2286 if (ENABLE_FEATURE_HTTPD_CGI || DEBUG || verbose) {
2287 /* NB: can be NULL (user runs httpd -i by hand?) */
2288 rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr->u.sa);
2289 }
2290 if (verbose) {
2291 /* this trick makes -v logging much simpler */
2292 if (rmt_ip_str)
2293 applet_name = rmt_ip_str;
2294 if (verbose > 2)
2295 bb_simple_error_msg("connected");
2296 }
2297#if ENABLE_FEATURE_HTTPD_ACL_IP
2185 remote_ip = 0; 2298 remote_ip = 0;
2186 if (fromAddr->u.sa.sa_family == AF_INET) { 2299 if (fromAddr->u.sa.sa_family == AF_INET) {
2187 remote_ip = ntohl(fromAddr->u.sin.sin_addr.s_addr); 2300 remote_ip = ntohl(fromAddr->u.sin.sin_addr.s_addr);
2188 } 2301 }
2189#if ENABLE_FEATURE_IPV6 2302# if ENABLE_FEATURE_IPV6
2190# if !ENABLE_PLATFORM_MINGW32 2303# if !ENABLE_PLATFORM_MINGW32
2191 if (fromAddr->u.sa.sa_family == AF_INET6 2304 if (fromAddr->u.sa.sa_family == AF_INET6
2192 && fromAddr->u.sin6.sin6_addr.s6_addr32[0] == 0 2305 && fromAddr->u.sin6.sin6_addr.s6_addr32[0] == 0
2193 && fromAddr->u.sin6.sin6_addr.s6_addr32[1] == 0 2306 && fromAddr->u.sin6.sin6_addr.s6_addr32[1] == 0
2194 && ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[2]) == 0xffff) 2307 && ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[2]) == 0xffff)
2195 remote_ip = ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[3]); 2308 remote_ip = ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[3]);
2196# else 2309# else
2197 if (fromAddr->u.sa.sa_family == AF_INET6 2310 if (fromAddr->u.sa.sa_family == AF_INET6
2198 && fromAddr->u.sin6.sin6_addr.s6_words[0] == 0 2311 && fromAddr->u.sin6.sin6_addr.s6_words[0] == 0
2199 && fromAddr->u.sin6.sin6_addr.s6_words[1] == 0 2312 && fromAddr->u.sin6.sin6_addr.s6_words[1] == 0
@@ -2201,20 +2314,10 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2201 && fromAddr->u.sin6.sin6_addr.s6_words[3] == 0 2314 && fromAddr->u.sin6.sin6_addr.s6_words[3] == 0
2202 && ntohl(*(uint32_t *)(fromAddr->u.sin6.sin6_addr.s6_words+4)) == 0xffff) 2315 && ntohl(*(uint32_t *)(fromAddr->u.sin6.sin6_addr.s6_words+4)) == 0xffff)
2203 remote_ip = ntohl(*(uint32_t *)(fromAddr->u.sin6.sin6_addr.s6_words+6)); 2316 remote_ip = ntohl(*(uint32_t *)(fromAddr->u.sin6.sin6_addr.s6_words+6));
2317# endif
2204# endif 2318# endif
2205#endif
2206 if (ENABLE_FEATURE_HTTPD_CGI || DEBUG || verbose) {
2207 /* NB: can be NULL (user runs httpd -i by hand?) */
2208 rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr->u.sa);
2209 }
2210 if (verbose) {
2211 /* this trick makes -v logging much simpler */
2212 if (rmt_ip_str)
2213 applet_name = rmt_ip_str;
2214 if (verbose > 2)
2215 bb_simple_error_msg("connected");
2216 }
2217 if_ip_denied_send_HTTP_FORBIDDEN_and_exit(remote_ip); 2319 if_ip_denied_send_HTTP_FORBIDDEN_and_exit(remote_ip);
2320#endif
2218 2321
2219#ifdef SIGALRM 2322#ifdef SIGALRM
2220 /* Install timeout handler. get_line() needs it. */ 2323 /* Install timeout handler. get_line() needs it. */
@@ -2512,6 +2615,13 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2512 continue; 2615 continue;
2513 } 2616 }
2514#endif 2617#endif
2618#if ENABLE_FEATURE_HTTPD_ETAG
2619 if (STRNCASECMP(iobuf, "If-None-Match:") == 0) {
2620 free(G.if_none_match);
2621 G.if_none_match = xstrdup(skip_whitespace(iobuf + sizeof("If-None-Match:") - 1));
2622 continue;
2623 }
2624#endif
2515#if ENABLE_FEATURE_HTTPD_CGI 2625#if ENABLE_FEATURE_HTTPD_CGI
2516 if (cgi_type != CGI_NONE) { 2626 if (cgi_type != CGI_NONE) {
2517 bool ct = (STRNCASECMP(iobuf, "Content-Type:") == 0); 2627 bool ct = (STRNCASECMP(iobuf, "Content-Type:") == 0);
diff --git a/networking/httpd_indexcgi.c b/networking/httpd_indexcgi.c
index 562cd7fbe..47b1159f4 100644
--- a/networking/httpd_indexcgi.c
+++ b/networking/httpd_indexcgi.c
@@ -52,43 +52,42 @@ httpd_indexcgi.c -o index.cgi
52 * to elements. Edit stylesheet to your liking and recompile. */ 52 * to elements. Edit stylesheet to your liking and recompile. */
53 53
54#define STYLE_STR \ 54#define STYLE_STR \
55"<style>" "\n"\ 55"<style>" \
56"table {" "\n"\ 56"table {" \
57 "width:100%;" "\n"\ 57 "width:100%;" \
58 "background-color:#fff5ee;" "\n"\ 58 "background-color:#fff5ee;" \
59 "border-width:1px;" /* 1px 1px 1px 1px; */ "\n"\ 59 "border-width:1px;" /* 1px 1px 1px 1px; */ \
60 "border-spacing:2px;" "\n"\ 60 "border-spacing:2px;" \
61 "border-style:solid;" /* solid solid solid solid; */ "\n"\ 61 "border-style:solid;" /* solid solid solid solid; */ \
62 "border-color:black;" /* black black black black; */ "\n"\ 62 "border-color:black;" /* black black black black; */ \
63 "border-collapse:collapse;" "\n"\ 63 "border-collapse:collapse" \
64"}" "\n"\ 64"}" \
65"th {" "\n"\ 65"th {" \
66 "border-width:1px;" /* 1px 1px 1px 1px; */ "\n"\ 66 "border-width:1px;" /* 1px 1px 1px 1px; */ \
67 "padding:1px;" /* 1px 1px 1px 1px; */ "\n"\ 67 "padding:1px;" /* 1px 1px 1px 1px; */ \
68 "border-style:solid;" /* solid solid solid solid; */ "\n"\ 68 "border-style:solid;" /* solid solid solid solid; */ \
69 "border-color:black;" /* black black black black; */ "\n"\ 69 "border-color:black" /* black black black black; */ \
70"}" "\n"\ 70"}" \
71"td {" "\n"\ 71"td {" \
72 /* top right bottom left */ \ 72 /* top right bottom left */ \
73 "border-width:0px 1px 0px 1px;" "\n"\ 73 "border-width:0 1px 0 1px;" \
74 "padding:1px;" /* 1px 1px 1px 1px; */ "\n"\ 74 "padding:1px;" /* 1px 1px 1px 1px; */ \
75 "border-style:solid;" /* solid solid solid solid; */ "\n"\ 75 "border-style:solid;" /* solid solid solid solid; */ \
76 "border-color:black;" /* black black black black; */ "\n"\ 76 "border-color:black;" /* black black black black; */ \
77 "white-space:nowrap;" "\n"\ 77 "white-space:nowrap" \
78"}" "\n"\ 78"}" \
79"tr.hdr { background-color:#eee5de; }" "\n"\ 79"tr:nth-child(odd) { background-color:#ffffff }" \
80"tr.o { background-color:#ffffff; }" "\n"\ 80"tr.hdr { background-color:#eee5de }" \
81/* tr.e { ... } - for even rows (currently none) */ \ 81"tr.foot { background-color:#eee5de }" \
82"tr.foot { background-color:#eee5de; }" "\n"\ 82"th.cnt { text-align:left }" \
83"th.cnt { text-align:left; }" "\n"\ 83"th.sz { text-align:right }" \
84"th.sz { text-align:right; }" "\n"\ 84"th.dt { text-align:right }" \
85"th.dt { text-align:right; }" "\n"\ 85"td.sz { text-align:right }" \
86"td.sz { text-align:right; }" "\n"\ 86"td.dt { text-align:right }" \
87"td.dt { text-align:right; }" "\n"\ 87"col.nm { width:98% }" \
88"col.nm { width:98%; }" "\n"\ 88"col.sz { width:1% }" \
89"col.sz { width:1%; }" "\n"\ 89"col.dt { width:1% }" \
90"col.dt { width:1%; }" "\n"\ 90"</style>" \
91"</style>" "\n"\
92 91
93typedef struct dir_list_t { 92typedef struct dir_list_t {
94 char *dl_name; 93 char *dl_name;
@@ -220,7 +219,6 @@ int main(int argc, char *argv[])
220 unsigned count_dirs; 219 unsigned count_dirs;
221 unsigned count_files; 220 unsigned count_files;
222 unsigned long long size_total; 221 unsigned long long size_total;
223 int odd;
224 DIR *dirp; 222 DIR *dirp;
225 char *location; 223 char *location;
226 224
@@ -291,7 +289,6 @@ int main(int argc, char *argv[])
291 "<col class=nm><col class=sz><col class=dt>" "\n" 289 "<col class=nm><col class=sz><col class=dt>" "\n"
292 "<tr class=hdr><th class=cnt>Name<th class=sz>Size<th class=dt>Last modified" "\n"); 290 "<tr class=hdr><th class=cnt>Name<th class=sz>Size<th class=dt>Last modified" "\n");
293 291
294 odd = 0;
295 count_dirs = 0; 292 count_dirs = 0;
296 count_files = 0; 293 count_files = 0;
297 size_total = 0; 294 size_total = 0;
@@ -307,9 +304,7 @@ int main(int argc, char *argv[])
307 } else 304 } else
308 goto next; 305 goto next;
309 306
310 fmt_str("<tr class="); 307 fmt_str("<tr><td class=nm><a href='");
311 *dst++ = (odd ? 'o' : 'e');
312 fmt_str("><td class=nm><a href='");
313 fmt_url(cdir->dl_name); /* %20 etc */ 308 fmt_url(cdir->dl_name); /* %20 etc */
314 if (S_ISDIR(cdir->dl_mode)) 309 if (S_ISDIR(cdir->dl_mode))
315 *dst++ = '/'; 310 *dst++ = '/';
@@ -330,7 +325,6 @@ int main(int argc, char *argv[])
330 fmt_02u(ptm->tm_sec); 325 fmt_02u(ptm->tm_sec);
331 *dst++ = '\n'; 326 *dst++ = '\n';
332 327
333 odd = 1 - odd;
334 next: 328 next:
335 cdir++; 329 cdir++;
336 } 330 }
diff --git a/networking/ifconfig.c b/networking/ifconfig.c
index b566d91a9..3c9a2dfb3 100644
--- a/networking/ifconfig.c
+++ b/networking/ifconfig.c
@@ -27,7 +27,6 @@
27//config:config IFCONFIG 27//config:config IFCONFIG
28//config: bool "ifconfig (12 kb)" 28//config: bool "ifconfig (12 kb)"
29//config: default y 29//config: default y
30//config: select PLATFORM_LINUX
31//config: help 30//config: help
32//config: Ifconfig is used to configure the kernel-resident network interfaces. 31//config: Ifconfig is used to configure the kernel-resident network interfaces.
33//config: 32//config:
diff --git a/networking/ifenslave.c b/networking/ifenslave.c
index 5e769b61d..bdb9894be 100644
--- a/networking/ifenslave.c
+++ b/networking/ifenslave.c
@@ -100,7 +100,6 @@
100//config:config IFENSLAVE 100//config:config IFENSLAVE
101//config: bool "ifenslave (13 kb)" 101//config: bool "ifenslave (13 kb)"
102//config: default y 102//config: default y
103//config: select PLATFORM_LINUX
104//config: help 103//config: help
105//config: Userspace application to bind several interfaces 104//config: Userspace application to bind several interfaces
106//config: to a logical interface (use with kernel bonding driver). 105//config: to a logical interface (use with kernel bonding driver).
diff --git a/networking/ifplugd.c b/networking/ifplugd.c
index fa18edd57..0d17b7d8c 100644
--- a/networking/ifplugd.c
+++ b/networking/ifplugd.c
@@ -9,7 +9,6 @@
9//config:config IFPLUGD 9//config:config IFPLUGD
10//config: bool "ifplugd (10 kb)" 10//config: bool "ifplugd (10 kb)"
11//config: default y 11//config: default y
12//config: select PLATFORM_LINUX
13//config: help 12//config: help
14//config: Network interface plug detection daemon. 13//config: Network interface plug detection daemon.
15 14
diff --git a/networking/ip.c b/networking/ip.c
index 034ee4fc8..7d3faf7f8 100644
--- a/networking/ip.c
+++ b/networking/ip.c
@@ -11,7 +11,6 @@
11//config:config IP 11//config:config IP
12//config: bool "ip (35 kb)" 12//config: bool "ip (35 kb)"
13//config: default y 13//config: default y
14//config: select PLATFORM_LINUX
15//config: help 14//config: help
16//config: The "ip" applet is a TCP/IP interface configuration and routing 15//config: The "ip" applet is a TCP/IP interface configuration and routing
17//config: utility. 16//config: utility.
@@ -23,7 +22,6 @@
23//config: bool "ipaddr (14 kb)" 22//config: bool "ipaddr (14 kb)"
24//config: default y 23//config: default y
25//config: select FEATURE_IP_ADDRESS 24//config: select FEATURE_IP_ADDRESS
26//config: select PLATFORM_LINUX
27//config: help 25//config: help
28//config: Short form of "ip addr" 26//config: Short form of "ip addr"
29//config: 27//config:
@@ -31,7 +29,6 @@
31//config: bool "iplink (17 kb)" 29//config: bool "iplink (17 kb)"
32//config: default y 30//config: default y
33//config: select FEATURE_IP_LINK 31//config: select FEATURE_IP_LINK
34//config: select PLATFORM_LINUX
35//config: help 32//config: help
36//config: Short form of "ip link" 33//config: Short form of "ip link"
37//config: 34//config:
@@ -39,7 +36,6 @@
39//config: bool "iproute (15 kb)" 36//config: bool "iproute (15 kb)"
40//config: default y 37//config: default y
41//config: select FEATURE_IP_ROUTE 38//config: select FEATURE_IP_ROUTE
42//config: select PLATFORM_LINUX
43//config: help 39//config: help
44//config: Short form of "ip route" 40//config: Short form of "ip route"
45//config: 41//config:
@@ -47,7 +43,6 @@
47//config: bool "iptunnel (9.6 kb)" 43//config: bool "iptunnel (9.6 kb)"
48//config: default y 44//config: default y
49//config: select FEATURE_IP_TUNNEL 45//config: select FEATURE_IP_TUNNEL
50//config: select PLATFORM_LINUX
51//config: help 46//config: help
52//config: Short form of "ip tunnel" 47//config: Short form of "ip tunnel"
53//config: 48//config:
@@ -55,7 +50,6 @@
55//config: bool "iprule (10 kb)" 50//config: bool "iprule (10 kb)"
56//config: default y 51//config: default y
57//config: select FEATURE_IP_RULE 52//config: select FEATURE_IP_RULE
58//config: select PLATFORM_LINUX
59//config: help 53//config: help
60//config: Short form of "ip rule" 54//config: Short form of "ip rule"
61//config: 55//config:
@@ -63,7 +57,6 @@
63//config: bool "ipneigh (8.3 kb)" 57//config: bool "ipneigh (8.3 kb)"
64//config: default y 58//config: default y
65//config: select FEATURE_IP_NEIGH 59//config: select FEATURE_IP_NEIGH
66//config: select PLATFORM_LINUX
67//config: help 60//config: help
68//config: Short form of "ip neigh" 61//config: Short form of "ip neigh"
69//config: 62//config:
@@ -146,11 +139,13 @@
146//usage:#define ipaddr_trivial_usage 139//usage:#define ipaddr_trivial_usage
147//usage: "add|del IFADDR dev IFACE | show|flush [dev IFACE] [to PREFIX]" 140//usage: "add|del IFADDR dev IFACE | show|flush [dev IFACE] [to PREFIX]"
148//usage:#define ipaddr_full_usage "\n\n" 141//usage:#define ipaddr_full_usage "\n\n"
149//usage: "ipaddr add|change|replace|delete dev IFACE IFADDR\n" 142//usage: "ipaddr add|change|replace|delete dev IFACE [CONFFLAG-LIST] IFADDR\n"
150//usage: " IFADDR := PREFIX | ADDR peer PREFIX [broadcast ADDR|+|-]\n" 143//usage: " IFADDR := PREFIX | ADDR peer PREFIX [broadcast ADDR|+|-]\n"
151//usage: " [anycast ADDR] [label STRING] [scope SCOPE]\n" 144//usage: " [anycast ADDR] [label STRING] [scope SCOPE]\n"
152//usage: " PREFIX := ADDR[/MASK]\n" 145//usage: " PREFIX := ADDR[/MASK]\n"
153//usage: " SCOPE := [host|link|global|NUMBER]\n" 146//usage: " SCOPE := [host|link|global|NUMBER]\n"
147//usage: " CONFFLAG-LIST := [CONFFLAG-LIST] CONFFLAG\n"
148//usage: " CONFFLAG := [noprefixroute]\n"
154//usage: "ipaddr show|flush [dev IFACE] [scope SCOPE] [to PREFIX] [label PATTERN]" 149//usage: "ipaddr show|flush [dev IFACE] [scope SCOPE] [to PREFIX] [label PATTERN]"
155//usage: 150//usage:
156//--------------123456789.123456789.123456789.123456789.123456789.123456789.123456789.123....79 151//--------------123456789.123456789.123456789.123456789.123456789.123456789.123456789.123....79
diff --git a/networking/libiproute/ip_common.h b/networking/libiproute/ip_common.h
index 40171bed9..894e380f8 100644
--- a/networking/libiproute/ip_common.h
+++ b/networking/libiproute/ip_common.h
@@ -33,4 +33,8 @@ int FAST_FUNC do_iplink(char **argv);
33 33
34POP_SAVED_FUNCTION_VISIBILITY 34POP_SAVED_FUNCTION_VISIBILITY
35 35
36#ifndef INFINITY_LIFE_TIME
37#define INFINITY_LIFE_TIME 0xFFFFFFFFU
38#endif
39
36#endif 40#endif
diff --git a/networking/libiproute/ipaddress.c b/networking/libiproute/ipaddress.c
index 86cf3beea..71e8fb6a7 100644
--- a/networking/libiproute/ipaddress.c
+++ b/networking/libiproute/ipaddress.c
@@ -217,6 +217,7 @@ static int FAST_FUNC print_addrinfo(const struct sockaddr_nl *who UNUSED_PARAM,
217{ 217{
218 struct ifaddrmsg *ifa = NLMSG_DATA(n); 218 struct ifaddrmsg *ifa = NLMSG_DATA(n);
219 int len = n->nlmsg_len; 219 int len = n->nlmsg_len;
220 unsigned int ifa_flags;
220 struct rtattr *rta_tb[IFA_MAX+1]; 221 struct rtattr *rta_tb[IFA_MAX+1];
221 222
222 if (n->nlmsg_type != RTM_NEWADDR && n->nlmsg_type != RTM_DELADDR) 223 if (n->nlmsg_type != RTM_NEWADDR && n->nlmsg_type != RTM_DELADDR)
@@ -233,6 +234,8 @@ static int FAST_FUNC print_addrinfo(const struct sockaddr_nl *who UNUSED_PARAM,
233 //memset(rta_tb, 0, sizeof(rta_tb)); - parse_rtattr does this 234 //memset(rta_tb, 0, sizeof(rta_tb)); - parse_rtattr does this
234 parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa))); 235 parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
235 236
237 ifa_flags = rta_tb[IFA_FLAGS] ? *(__u32*)RTA_DATA(rta_tb[IFA_FLAGS]) : ifa->ifa_flags;
238
236 if (!rta_tb[IFA_LOCAL]) 239 if (!rta_tb[IFA_LOCAL])
237 rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS]; 240 rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
238 if (!rta_tb[IFA_ADDRESS]) 241 if (!rta_tb[IFA_ADDRESS])
@@ -242,7 +245,7 @@ static int FAST_FUNC print_addrinfo(const struct sockaddr_nl *who UNUSED_PARAM,
242 return 0; 245 return 0;
243 if ((G_filter.scope ^ ifa->ifa_scope) & G_filter.scopemask) 246 if ((G_filter.scope ^ ifa->ifa_scope) & G_filter.scopemask)
244 return 0; 247 return 0;
245 if ((G_filter.flags ^ ifa->ifa_flags) & G_filter.flagmask) 248 if ((G_filter.flags ^ ifa_flags) & G_filter.flagmask)
246 return 0; 249 return 0;
247 if (G_filter.label) { 250 if (G_filter.label) {
248 const char *label; 251 const char *label;
@@ -322,28 +325,32 @@ static int FAST_FUNC print_addrinfo(const struct sockaddr_nl *who UNUSED_PARAM,
322 ); 325 );
323 } 326 }
324 printf("scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope)); 327 printf("scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope));
325 if (ifa->ifa_flags & IFA_F_SECONDARY) { 328 if (ifa_flags & IFA_F_SECONDARY) {
326 ifa->ifa_flags &= ~IFA_F_SECONDARY; 329 ifa_flags &= ~IFA_F_SECONDARY;
327 printf("secondary "); 330 printf("secondary ");
328 } 331 }
329 if (ifa->ifa_flags & IFA_F_TENTATIVE) { 332 if (ifa_flags & IFA_F_TENTATIVE) {
330 ifa->ifa_flags &= ~IFA_F_TENTATIVE; 333 ifa_flags &= ~IFA_F_TENTATIVE;
331 printf("tentative "); 334 printf("tentative ");
332 } 335 }
333 if (ifa->ifa_flags & IFA_F_DADFAILED) { 336 if (ifa_flags & IFA_F_DADFAILED) {
334 ifa->ifa_flags &= ~IFA_F_DADFAILED; 337 ifa_flags &= ~IFA_F_DADFAILED;
335 printf("dadfailed "); 338 printf("dadfailed ");
336 } 339 }
337 if (ifa->ifa_flags & IFA_F_DEPRECATED) { 340 if (ifa_flags & IFA_F_DEPRECATED) {
338 ifa->ifa_flags &= ~IFA_F_DEPRECATED; 341 ifa_flags &= ~IFA_F_DEPRECATED;
339 printf("deprecated "); 342 printf("deprecated ");
340 } 343 }
341 if (!(ifa->ifa_flags & IFA_F_PERMANENT)) { 344 if (!(ifa_flags & IFA_F_PERMANENT)) {
342 printf("dynamic "); 345 printf("dynamic ");
343 } else 346 } else
344 ifa->ifa_flags &= ~IFA_F_PERMANENT; 347 ifa_flags &= ~IFA_F_PERMANENT;
345 if (ifa->ifa_flags) 348 if (ifa_flags & IFA_F_NOPREFIXROUTE) {
346 printf("flags %02x ", ifa->ifa_flags); 349 ifa_flags &= ~IFA_F_NOPREFIXROUTE;
350 printf("noprefixroute ");
351 }
352 if (ifa_flags)
353 printf("flags %02x ", ifa_flags);
347 if (rta_tb[IFA_LABEL]) 354 if (rta_tb[IFA_LABEL])
348 fputs((char*)RTA_DATA(rta_tb[IFA_LABEL]), stdout); 355 fputs((char*)RTA_DATA(rta_tb[IFA_LABEL]), stdout);
349 if (rta_tb[IFA_CACHEINFO]) { 356 if (rta_tb[IFA_CACHEINFO]) {
@@ -585,6 +592,14 @@ int FAST_FUNC ipaddr_list_or_flush(char **argv, int flush)
585 return 0; 592 return 0;
586} 593}
587 594
595static void set_lifetime(unsigned int *lifetime, char *argv, const char *errmsg)
596{
597 if (strcmp(argv, "forever") == 0)
598 *lifetime = INFINITY_LIFE_TIME;
599 else
600 *lifetime = get_u32(argv, errmsg);
601}
602
588static int default_scope(inet_prefix *lcl) 603static int default_scope(inet_prefix *lcl)
589{ 604{
590 if (lcl->family == AF_INET) { 605 if (lcl->family == AF_INET) {
@@ -600,10 +615,13 @@ static int ipaddr_modify(int cmd, int flags, char **argv)
600 /* If you add stuff here, update ipaddr_full_usage */ 615 /* If you add stuff here, update ipaddr_full_usage */
601 static const char option[] ALIGN1 = 616 static const char option[] ALIGN1 =
602 "peer\0""remote\0""broadcast\0""brd\0" 617 "peer\0""remote\0""broadcast\0""brd\0"
603 "anycast\0""scope\0""dev\0""label\0""local\0"; 618 "anycast\0""valid_lft\0""preferred_lft\0"
619 "scope\0""dev\0""label\0""noprefixroute\0""local\0";
604#define option_peer option 620#define option_peer option
605#define option_broadcast (option + sizeof("peer") + sizeof("remote")) 621#define option_broadcast (option + sizeof("peer") + sizeof("remote"))
606#define option_anycast (option_broadcast + sizeof("broadcast") + sizeof("brd")) 622#define option_anycast (option_broadcast + sizeof("broadcast") + sizeof("brd"))
623#define option_valid_lft (option_anycast + sizeof("anycast"))
624#define option_pref_lft (option_valid_lft + sizeof("valid_lft"))
607 struct rtnl_handle rth; 625 struct rtnl_handle rth;
608 struct { 626 struct {
609 struct nlmsghdr n; 627 struct nlmsghdr n;
@@ -612,6 +630,8 @@ static int ipaddr_modify(int cmd, int flags, char **argv)
612 } req; 630 } req;
613 char *d = NULL; 631 char *d = NULL;
614 char *l = NULL; 632 char *l = NULL;
633 char *valid_lftp = NULL;
634 char *preferred_lftp = NULL;
615 inet_prefix lcl; 635 inet_prefix lcl;
616 inet_prefix peer; 636 inet_prefix peer;
617 int local_len = 0; 637 int local_len = 0;
@@ -619,6 +639,9 @@ static int ipaddr_modify(int cmd, int flags, char **argv)
619 int brd_len = 0; 639 int brd_len = 0;
620 int any_len = 0; 640 int any_len = 0;
621 bool scoped = 0; 641 bool scoped = 0;
642 __u32 valid_lft = INFINITY_LIFE_TIME;
643 __u32 preferred_lft = INFINITY_LIFE_TIME;
644 unsigned int ifa_flags = 0;
622 645
623 memset(&req, 0, sizeof(req)); 646 memset(&req, 0, sizeof(req));
624 647
@@ -630,10 +653,9 @@ static int ipaddr_modify(int cmd, int flags, char **argv)
630 while (*argv) { 653 while (*argv) {
631 unsigned arg = index_in_strings(option, *argv); 654 unsigned arg = index_in_strings(option, *argv);
632 /* if search fails, "local" is assumed */ 655 /* if search fails, "local" is assumed */
633 if ((int)arg >= 0)
634 NEXT_ARG();
635 656
636 if (arg <= 1) { /* peer, remote */ 657 if (arg <= 1) { /* peer, remote */
658 NEXT_ARG();
637 if (peer_len) { 659 if (peer_len) {
638 duparg(option_peer, *argv); 660 duparg(option_peer, *argv);
639 } 661 }
@@ -646,6 +668,7 @@ static int ipaddr_modify(int cmd, int flags, char **argv)
646 req.ifa.ifa_prefixlen = peer.bitlen; 668 req.ifa.ifa_prefixlen = peer.bitlen;
647 } else if (arg <= 3) { /* broadcast, brd */ 669 } else if (arg <= 3) { /* broadcast, brd */
648 inet_prefix addr; 670 inet_prefix addr;
671 NEXT_ARG();
649 if (brd_len) { 672 if (brd_len) {
650 duparg(option_broadcast, *argv); 673 duparg(option_broadcast, *argv);
651 } 674 }
@@ -662,6 +685,7 @@ static int ipaddr_modify(int cmd, int flags, char **argv)
662 } 685 }
663 } else if (arg == 4) { /* anycast */ 686 } else if (arg == 4) { /* anycast */
664 inet_prefix addr; 687 inet_prefix addr;
688 NEXT_ARG();
665 if (any_len) { 689 if (any_len) {
666 duparg(option_anycast, *argv); 690 duparg(option_anycast, *argv);
667 } 691 }
@@ -671,20 +695,39 @@ static int ipaddr_modify(int cmd, int flags, char **argv)
671 } 695 }
672 addattr_l(&req.n, sizeof(req), IFA_ANYCAST, &addr.data, addr.bytelen); 696 addattr_l(&req.n, sizeof(req), IFA_ANYCAST, &addr.data, addr.bytelen);
673 any_len = addr.bytelen; 697 any_len = addr.bytelen;
674 } else if (arg == 5) { /* scope */ 698 } else if (arg == 5) { /* valid_lft */
699 if (valid_lftp)
700 duparg(option_valid_lft, *argv);
701 NEXT_ARG();
702 valid_lftp = *argv;
703 set_lifetime(&valid_lft, *argv, option_valid_lft);
704 } else if (arg == 6) { /* preferred_lft */
705 if (preferred_lftp)
706 duparg(option_pref_lft, *argv);
707 NEXT_ARG();
708 preferred_lftp = *argv;
709 set_lifetime(&preferred_lft, *argv, option_pref_lft);
710 } else if (arg == 7) { /* scope */
675 uint32_t scope = 0; 711 uint32_t scope = 0;
712 NEXT_ARG();
676 if (rtnl_rtscope_a2n(&scope, *argv)) { 713 if (rtnl_rtscope_a2n(&scope, *argv)) {
677 invarg_1_to_2(*argv, "scope"); 714 invarg_1_to_2(*argv, "scope");
678 } 715 }
679 req.ifa.ifa_scope = scope; 716 req.ifa.ifa_scope = scope;
680 scoped = 1; 717 scoped = 1;
681 } else if (arg == 6) { /* dev */ 718 } else if (arg == 8) { /* dev */
719 NEXT_ARG();
682 d = *argv; 720 d = *argv;
683 } else if (arg == 7) { /* label */ 721 } else if (arg == 9) { /* label */
722 NEXT_ARG();
684 l = *argv; 723 l = *argv;
685 addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l) + 1); 724 addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l) + 1);
725 } else if (arg == 10) { /* noprefixroute */
726 ifa_flags |= IFA_F_NOPREFIXROUTE;
686 } else { 727 } else {
687 /* local (specified or assumed) */ 728 /* local (specified or assumed) */
729 if ((int)arg >= 0)
730 NEXT_ARG();
688 if (local_len) { 731 if (local_len) {
689 duparg2("local", *argv); 732 duparg2("local", *argv);
690 } 733 }
@@ -698,6 +741,11 @@ static int ipaddr_modify(int cmd, int flags, char **argv)
698 argv++; 741 argv++;
699 } 742 }
700 743
744 if (ifa_flags <= 0xff)
745 req.ifa.ifa_flags = ifa_flags;
746 else
747 addattr32(&req.n, sizeof(req), IFA_FLAGS, ifa_flags);
748
701 if (!d) { 749 if (!d) {
702 /* There was no "dev IFACE", but we need that */ 750 /* There was no "dev IFACE", but we need that */
703 bb_simple_error_msg_and_die("need \"dev IFACE\""); 751 bb_simple_error_msg_and_die("need \"dev IFACE\"");
@@ -740,6 +788,24 @@ static int ipaddr_modify(int cmd, int flags, char **argv)
740 788
741 req.ifa.ifa_index = xll_name_to_index(d); 789 req.ifa.ifa_index = xll_name_to_index(d);
742 790
791 if (valid_lftp || preferred_lftp) {
792 struct ifa_cacheinfo cinfo = {};
793
794 if (!valid_lft) {
795 fprintf(stderr, "valid_lft is zero\n");
796 return 1;
797 }
798 if (valid_lft < preferred_lft) {
799 fprintf(stderr, "preferred_lft is greater than valid_lft\n");
800 return 1;
801 }
802
803 cinfo.ifa_prefered = preferred_lft;
804 cinfo.ifa_valid = valid_lft;
805 addattr_l(&req.n, sizeof(req), IFA_CACHEINFO, &cinfo,
806 sizeof(cinfo));
807 }
808
743 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) 809 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
744 return 2; 810 return 2;
745 811
diff --git a/networking/nameif.c b/networking/nameif.c
index 91d50536a..854594c83 100644
--- a/networking/nameif.c
+++ b/networking/nameif.c
@@ -12,7 +12,6 @@
12//config:config NAMEIF 12//config:config NAMEIF
13//config: bool "nameif (6.6 kb)" 13//config: bool "nameif (6.6 kb)"
14//config: default y 14//config: default y
15//config: select PLATFORM_LINUX
16//config: select FEATURE_SYSLOG 15//config: select FEATURE_SYSLOG
17//config: help 16//config: help
18//config: nameif is used to rename network interface by its MAC address. 17//config: nameif is used to rename network interface by its MAC address.
diff --git a/networking/netstat.c b/networking/netstat.c
index c7934423b..936610f89 100644
--- a/networking/netstat.c
+++ b/networking/netstat.c
@@ -16,7 +16,6 @@
16//config:config NETSTAT 16//config:config NETSTAT
17//config: bool "netstat (10 kb)" 17//config: bool "netstat (10 kb)"
18//config: default y 18//config: default y
19//config: select PLATFORM_LINUX
20//config: help 19//config: help
21//config: netstat prints information about the Linux networking subsystem. 20//config: netstat prints information about the Linux networking subsystem.
22//config: 21//config:
diff --git a/networking/ntpd.c b/networking/ntpd.c
index 0f12409f9..d721fe80c 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -43,7 +43,6 @@
43//config:config NTPD 43//config:config NTPD
44//config: bool "ntpd (22 kb)" 44//config: bool "ntpd (22 kb)"
45//config: default y 45//config: default y
46//config: select PLATFORM_LINUX
47//config: help 46//config: help
48//config: The NTP client/server daemon. 47//config: The NTP client/server daemon.
49//config: 48//config:
@@ -337,6 +336,9 @@ typedef struct {
337#endif 336#endif
338 int p_fd; 337 int p_fd;
339 int datapoint_idx; 338 int datapoint_idx;
339#if ENABLE_FEATURE_NTPD_SERVER
340 uint32_t p_refid;
341#endif
340 uint32_t lastpkt_refid; 342 uint32_t lastpkt_refid;
341 uint8_t lastpkt_status; 343 uint8_t lastpkt_status;
342 uint8_t lastpkt_stratum; 344 uint8_t lastpkt_stratum;
@@ -413,7 +415,9 @@ struct globals {
413 * in stratum 2+ packets, it's IPv4 address or 4 first bytes 415 * in stratum 2+ packets, it's IPv4 address or 4 first bytes
414 * of MD5 hash of IPv6 416 * of MD5 hash of IPv6
415 */ 417 */
418#if ENABLE_FEATURE_NTPD_SERVER
416 uint32_t refid; 419 uint32_t refid;
420#endif
417 uint8_t ntp_status; 421 uint8_t ntp_status;
418 /* precision is defined as the larger of the resolution and time to 422 /* precision is defined as the larger of the resolution and time to
419 * read the clock, in log2 units. For instance, the precision of a 423 * read the clock, in log2 units. For instance, the precision of a
@@ -836,6 +840,24 @@ reset_peer_stats(peer_t *p, double offset)
836 VERB6 bb_error_msg("%s->lastpkt_recv_time=%f", p->p_dotted, p->lastpkt_recv_time); 840 VERB6 bb_error_msg("%s->lastpkt_recv_time=%f", p->p_dotted, p->lastpkt_recv_time);
837} 841}
838 842
843#if ENABLE_FEATURE_NTPD_SERVER
844static uint32_t calculate_refid(len_and_sockaddr *lsa)
845{
846# if ENABLE_FEATURE_IPV6
847 if (lsa->u.sa.sa_family == AF_INET6) {
848 md5_ctx_t md5;
849 uint32_t res[MD5_OUTSIZE / 4];
850
851 md5_begin(&md5);
852 md5_hash(&md5, &lsa->u.sin6.sin6_addr, sizeof(lsa->u.sin6.sin6_addr));
853 md5_end(&md5, res);
854 return res[0];
855 }
856# endif
857 return lsa->u.sin.sin_addr.s_addr;
858}
859#endif
860
839static len_and_sockaddr* 861static len_and_sockaddr*
840resolve_peer_hostname(peer_t *p) 862resolve_peer_hostname(peer_t *p)
841{ 863{
@@ -847,6 +869,9 @@ resolve_peer_hostname(peer_t *p)
847 p->p_dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa); 869 p->p_dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
848 VERB1 if (strcmp(p->p_hostname, p->p_dotted) != 0) 870 VERB1 if (strcmp(p->p_hostname, p->p_dotted) != 0)
849 bb_error_msg("'%s' is %s", p->p_hostname, p->p_dotted); 871 bb_error_msg("'%s' is %s", p->p_hostname, p->p_dotted);
872#if ENABLE_FEATURE_NTPD_SERVER
873 p->p_refid = calculate_refid(p->p_lsa);
874#endif
850 p->dns_errors = 0; 875 p->dns_errors = 0;
851 return lsa; 876 return lsa;
852 } 877 }
@@ -1764,7 +1789,10 @@ update_local_clock(peer_t *p)
1764 1789
1765 G.reftime = G.cur_time; 1790 G.reftime = G.cur_time;
1766 G.ntp_status = p->lastpkt_status; 1791 G.ntp_status = p->lastpkt_status;
1767 G.refid = p->lastpkt_refid; 1792#if ENABLE_FEATURE_NTPD_SERVER
1793 /* Our current refid is the IPv4 (or md5-hashed IPv6) address of the peer we took time from: */
1794 G.refid = p->p_refid;
1795#endif
1768 G.rootdelay = p->lastpkt_rootdelay + p->lastpkt_delay; 1796 G.rootdelay = p->lastpkt_rootdelay + p->lastpkt_delay;
1769 dtemp = p->filter_jitter; // SQRT(SQUARE(p->filter_jitter) + SQUARE(G.cluster_jitter)); 1797 dtemp = p->filter_jitter; // SQRT(SQUARE(p->filter_jitter) + SQUARE(G.cluster_jitter));
1770 dtemp += MAXD(p->filter_dispersion + FREQ_TOLERANCE * (G.cur_time - p->lastpkt_recv_time) + abs_offset, MINDISP); 1798 dtemp += MAXD(p->filter_dispersion + FREQ_TOLERANCE * (G.cur_time - p->lastpkt_recv_time) + abs_offset, MINDISP);
@@ -2249,11 +2277,11 @@ recv_and_process_client_pkt(void /*int fd*/)
2249 * We don't support this. 2277 * We don't support this.
2250 */ 2278 */
2251 2279
2252#if ENABLE_FEATURE_NTP_AUTH 2280# if ENABLE_FEATURE_NTP_AUTH
2253 if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE_MD5_AUTH && size != NTP_MSGSIZE_SHA1_AUTH) 2281 if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE_MD5_AUTH && size != NTP_MSGSIZE_SHA1_AUTH)
2254#else 2282# else
2255 if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE_MD5_AUTH) 2283 if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE_MD5_AUTH)
2256#endif 2284# endif
2257 { 2285 {
2258 char *addr; 2286 char *addr;
2259 if (size < 0) { 2287 if (size < 0) {
diff --git a/networking/parse_pasv_epsv.c b/networking/parse_pasv_epsv.c
index 14f4d4258..314237be6 100644
--- a/networking/parse_pasv_epsv.c
+++ b/networking/parse_pasv_epsv.c
@@ -38,6 +38,8 @@ int FAST_FUNC parse_pasv_epsv(char *buf)
38 * Server's IP is N1.N2.N3.N4 (we ignore it) 38 * Server's IP is N1.N2.N3.N4 (we ignore it)
39 * Server's port for data connection is P1*256+P2 */ 39 * Server's port for data connection is P1*256+P2 */
40 ptr = strrchr(buf, ')'); 40 ptr = strrchr(buf, ')');
41 if (!ptr) ptr = strrchr(buf, '\r'); /* for PASV responses not ending with ')' */
42 if (!ptr) ptr = strrchr(buf, '\n'); /* for PASV responses not ending with ')' */
41 if (ptr) *ptr = '\0'; 43 if (ptr) *ptr = '\0';
42 44
43 ptr = strrchr(buf, ','); 45 ptr = strrchr(buf, ',');
diff --git a/networking/ping.c b/networking/ping.c
index a47342fee..47b6ab1b2 100644
--- a/networking/ping.c
+++ b/networking/ping.c
@@ -27,7 +27,6 @@
27//config:config PING 27//config:config PING
28//config: bool "ping (10 kb)" 28//config: bool "ping (10 kb)"
29//config: default y 29//config: default y
30//config: select PLATFORM_LINUX
31//config: help 30//config: help
32//config: ping uses the ICMP protocol's mandatory ECHO_REQUEST datagram to 31//config: ping uses the ICMP protocol's mandatory ECHO_REQUEST datagram to
33//config: elicit an ICMP ECHO_RESPONSE from a host or gateway. 32//config: elicit an ICMP ECHO_RESPONSE from a host or gateway.
diff --git a/networking/route.c b/networking/route.c
index e785b1da6..4d9aad6cc 100644
--- a/networking/route.c
+++ b/networking/route.c
@@ -27,7 +27,6 @@
27//config:config ROUTE 27//config:config ROUTE
28//config: bool "route (8.7 kb)" 28//config: bool "route (8.7 kb)"
29//config: default y 29//config: default y
30//config: select PLATFORM_LINUX
31//config: help 30//config: help
32//config: Route displays or manipulates the kernel's IP routing tables. 31//config: Route displays or manipulates the kernel's IP routing tables.
33 32
diff --git a/networking/slattach.c b/networking/slattach.c
index 659822a91..51fbc1f49 100644
--- a/networking/slattach.c
+++ b/networking/slattach.c
@@ -15,7 +15,6 @@
15//config:config SLATTACH 15//config:config SLATTACH
16//config: bool "slattach (6.2 kb)" 16//config: bool "slattach (6.2 kb)"
17//config: default y 17//config: default y
18//config: select PLATFORM_LINUX
19//config: help 18//config: help
20//config: slattach configures serial line as SLIP network interface. 19//config: slattach configures serial line as SLIP network interface.
21 20
diff --git a/networking/tls.c b/networking/tls.c
index 9e81afbad..c00ef5db0 100644
--- a/networking/tls.c
+++ b/networking/tls.c
@@ -212,8 +212,6 @@
212 212
213enum { 213enum {
214 SHA_INSIZE = 64, 214 SHA_INSIZE = 64,
215 SHA1_OUTSIZE = 20,
216 SHA256_OUTSIZE = 32,
217 215
218 AES128_KEYSIZE = 16, 216 AES128_KEYSIZE = 16,
219 AES256_KEYSIZE = 32, 217 AES256_KEYSIZE = 32,
diff --git a/networking/traceroute.c b/networking/traceroute.c
index 06d3f19da..5068f654b 100644
--- a/networking/traceroute.c
+++ b/networking/traceroute.c
@@ -212,7 +212,6 @@
212//config:config TRACEROUTE 212//config:config TRACEROUTE
213//config: bool "traceroute (11 kb)" 213//config: bool "traceroute (11 kb)"
214//config: default y 214//config: default y
215//config: select PLATFORM_LINUX
216//config: help 215//config: help
217//config: Utility to trace the route of IP packets. 216//config: Utility to trace the route of IP packets.
218//config: 217//config:
diff --git a/networking/tunctl.c b/networking/tunctl.c
index a0e3926e9..0f010e196 100644
--- a/networking/tunctl.c
+++ b/networking/tunctl.c
@@ -12,7 +12,6 @@
12//config:config TUNCTL 12//config:config TUNCTL
13//config: bool "tunctl (6.2 kb)" 13//config: bool "tunctl (6.2 kb)"
14//config: default y 14//config: default y
15//config: select PLATFORM_LINUX
16//config: help 15//config: help
17//config: tunctl creates or deletes tun devices. 16//config: tunctl creates or deletes tun devices.
18//config: 17//config:
diff --git a/networking/udhcp/Config.src b/networking/udhcp/Config.src
index 8ef24748e..7d04bb246 100644
--- a/networking/udhcp/Config.src
+++ b/networking/udhcp/Config.src
@@ -6,7 +6,6 @@
6config UDHCPD 6config UDHCPD
7 bool "udhcpd (21 kb)" 7 bool "udhcpd (21 kb)"
8 default y 8 default y
9 select PLATFORM_LINUX
10 help 9 help
11 udhcpd is a DHCP server geared primarily toward embedded systems, 10 udhcpd is a DHCP server geared primarily toward embedded systems,
12 while striving to be fully functional and RFC compliant. 11 while striving to be fully functional and RFC compliant.
@@ -62,7 +61,6 @@ config DHCPRELAY
62config UDHCPC 61config UDHCPC
63 bool "udhcpc (24 kb)" 62 bool "udhcpc (24 kb)"
64 default y 63 default y
65 select PLATFORM_LINUX
66 help 64 help
67 udhcpc is a DHCP client geared primarily toward embedded systems, 65 udhcpc is a DHCP client geared primarily toward embedded systems,
68 while striving to be fully functional and RFC compliant. 66 while striving to be fully functional and RFC compliant.
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 50dfead63..e13eb3f9f 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -115,6 +115,13 @@ enum {
115 115
116 116
117/*** Script execution code ***/ 117/*** Script execution code ***/
118struct dhcp_optitem {
119 unsigned len;
120 uint8_t code;
121 uint8_t malloced;
122 uint8_t *data;
123 char *env;
124};
118 125
119/* get a rough idea of how long an option will be (rounding up...) */ 126/* get a rough idea of how long an option will be (rounding up...) */
120static const uint8_t len_of_option_as_string[] ALIGN1 = { 127static const uint8_t len_of_option_as_string[] ALIGN1 = {
@@ -186,15 +193,15 @@ static int good_hostname(const char *name)
186#endif 193#endif
187 194
188/* Create "opt_name=opt_value" string */ 195/* Create "opt_name=opt_value" string */
189static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_optflag *optflag, const char *opt_name) 196static NOINLINE char *xmalloc_optname_optval(const struct dhcp_optitem *opt_item, const struct dhcp_optflag *optflag, const char *opt_name)
190{ 197{
191 unsigned upper_length; 198 unsigned upper_length;
192 int len, type, optlen; 199 int len, type, optlen;
193 char *dest, *ret; 200 char *dest, *ret;
201 uint8_t *option;
194 202
195 /* option points to OPT_DATA, need to go back to get OPT_LEN */ 203 option = opt_item->data;
196 len = option[-OPT_DATA + OPT_LEN]; 204 len = opt_item->len;
197
198 type = optflag->flags & OPTION_TYPE_MASK; 205 type = optflag->flags & OPTION_TYPE_MASK;
199 optlen = dhcp_option_lengths[type]; 206 optlen = dhcp_option_lengths[type];
200 upper_length = len_of_option_as_string[type] 207 upper_length = len_of_option_as_string[type]
@@ -386,11 +393,70 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_
386 return ret; 393 return ret;
387} 394}
388 395
389static void putenvp(llist_t **envp, char *new_opt) 396static void optitem_unset_env_and_free(void *item)
390{ 397{
391 putenv(new_opt); 398 struct dhcp_optitem *opt_item = item;
399 bb_unsetenv_and_free(opt_item->env);
400 if (opt_item->malloced)
401 free(opt_item->data);
402 free(opt_item);
403}
404
405/* Used by static options (interface, siaddr, etc) */
406static void putenvp(char *new_opt)
407{
408 struct dhcp_optitem *opt_item;
409
410 opt_item = xzalloc(sizeof(*opt_item));
411 /* opt_item->code = 0, so it won't appear in concat_option's lookup */
412 /* opt_item->malloced = 0 */
413 /* opt_item->data = NULL */
414 opt_item->env = new_opt;
415 llist_add_to(&client_data.envp, opt_item);
392 log2(" %s", new_opt); 416 log2(" %s", new_opt);
393 llist_add_to(envp, new_opt); 417 putenv(new_opt);
418}
419
420/* Support RFC3396 Long Encoded Options */
421static struct dhcp_optitem *concat_option(uint8_t *data, uint8_t len, uint8_t code)
422{
423 llist_t *item;
424 struct dhcp_optitem *opt_item;
425
426 /* Check if an option with the code already exists.
427 * A possible optimization is to create a bitmap of all existing options in the packet,
428 * and iterate over the option list only if they exist.
429 * This will result in bigger code, and because dhcp packets don't have too many options it
430 * shouldn't have a big impact on performance.
431 */
432 for (item = client_data.envp; item != NULL; item = item->link) {
433 opt_item = (struct dhcp_optitem *)item->data;
434 if (opt_item->code == code) {
435 /* This option was seen already, concatenate */
436 uint8_t *new_data;
437
438 new_data = xmalloc(len + opt_item->len);
439 memcpy(
440 mempcpy(new_data, opt_item->data, opt_item->len),
441 data, len
442 );
443 opt_item->len += len;
444 if (opt_item->malloced)
445 free(opt_item->data);
446 opt_item->malloced = 1;
447 opt_item->data = new_data;
448 return opt_item;
449 }
450 }
451
452 /* This is a new option, add a new dhcp_optitem to the list */
453 opt_item = xzalloc(sizeof(*opt_item));
454 opt_item->code = code;
455 /* opt_item->malloced = 0 */
456 opt_item->data = data;
457 opt_item->len = len;
458 llist_add_to(&client_data.envp, opt_item);
459 return opt_item;
394} 460}
395 461
396static const char* get_optname(uint8_t code, const struct dhcp_optflag **dh) 462static const char* get_optname(uint8_t code, const struct dhcp_optflag **dh)
@@ -403,7 +469,7 @@ static const char* get_optname(uint8_t code, const struct dhcp_optflag **dh)
403 * and they'll count as unknown options. 469 * and they'll count as unknown options.
404 */ 470 */
405 for (*dh = dhcp_optflags; (*dh)->code && (*dh)->code < code; (*dh)++) 471 for (*dh = dhcp_optflags; (*dh)->code && (*dh)->code < code; (*dh)++)
406 continue; 472 continue;
407 473
408 if ((*dh)->code == code) 474 if ((*dh)->code == code)
409 return nth_string(dhcp_option_strings, (*dh - dhcp_optflags)); 475 return nth_string(dhcp_option_strings, (*dh - dhcp_optflags));
@@ -412,50 +478,54 @@ static const char* get_optname(uint8_t code, const struct dhcp_optflag **dh)
412} 478}
413 479
414/* put all the parameters into the environment */ 480/* put all the parameters into the environment */
415static llist_t *fill_envp(struct dhcp_packet *packet) 481static void fill_envp(struct dhcp_packet *packet)
416{ 482{
417 uint8_t *optptr; 483 uint8_t *optptr;
418 struct dhcp_scan_state scan_state; 484 struct dhcp_scan_state scan_state;
419 char *new_opt; 485 char *new_opt;
420 llist_t *envp = NULL;
421 486
422 putenvp(&envp, xasprintf("interface=%s", client_data.interface)); 487 putenvp(xasprintf("interface=%s", client_data.interface));
423 488
424 if (!packet) 489 if (!packet)
425 return envp; 490 return;
426 491
427 init_scan_state(packet, &scan_state); 492 init_scan_state(packet, &scan_state);
428 493
429 /* Iterate over the packet options. 494 /* Iterate over the packet options.
430 * Handle each option based on whether it's an unknown / known option. 495 * Handle each option based on whether it's an unknown / known option.
431 * There may be (although unlikely) duplicate options. For now, only the last 496 * Long options are supported in compliance with RFC 3396.
432 * appearing option will be stored in the environment, and all duplicates
433 * are freed properly.
434 * Long options may be implemented in the future (see RFC 3396) if needed.
435 */ 497 */
436 while ((optptr = udhcp_scan_options(packet, &scan_state)) != NULL) { 498 while ((optptr = udhcp_scan_options(packet, &scan_state)) != NULL) {
437 const struct dhcp_optflag *dh; 499 const struct dhcp_optflag *dh;
438 const char *opt_name; 500 const char *opt_name;
501 struct dhcp_optitem *opt_item;
439 uint8_t code = optptr[OPT_CODE]; 502 uint8_t code = optptr[OPT_CODE];
440 uint8_t len = optptr[OPT_LEN]; 503 uint8_t len = optptr[OPT_LEN];
441 uint8_t *data = optptr + OPT_DATA; 504 uint8_t *data = optptr + OPT_DATA;
442 505
506 opt_item = concat_option(data, len, code);
443 opt_name = get_optname(code, &dh); 507 opt_name = get_optname(code, &dh);
444 if (opt_name) { 508 if (opt_name) {
445 new_opt = xmalloc_optname_optval(data, dh, opt_name); 509 new_opt = xmalloc_optname_optval(opt_item, dh, opt_name);
446 if (code == DHCP_SUBNET && len == 4) { 510 if (opt_item->code == DHCP_SUBNET && opt_item->len == 4) {
511 /* Generate extra envvar for DHCP_SUBNET, $mask */
447 uint32_t subnet; 512 uint32_t subnet;
448 putenvp(&envp, new_opt); 513 move_from_unaligned32(subnet, opt_item->data);
449 move_from_unaligned32(subnet, data); 514 putenvp(xasprintf("mask=%u", mton(subnet)));
450 new_opt = xasprintf("mask=%u", mton(subnet));
451 } 515 }
452 } else { 516 } else {
453 unsigned ofs; 517 unsigned ofs;
454 new_opt = xmalloc(sizeof("optNNN=") + 1 + len*2); 518 new_opt = xmalloc(sizeof("optNNN=") + 1 + opt_item->len*2);
455 ofs = sprintf(new_opt, "opt%u=", code); 519 ofs = sprintf(new_opt, "opt%u=", opt_item->code);
456 bin2hex(new_opt + ofs, (char *)data, len)[0] = '\0'; 520 bin2hex(new_opt + ofs, (char *)opt_item->data, opt_item->len)[0] = '\0';
457 } 521 }
458 putenvp(&envp, new_opt); 522 log2(" %s", new_opt);
523 putenv(new_opt);
524 /* putenv will replace the existing environment variable in case of a duplicate.
525 * Free the previous occurrence (NULL if it's the first one).
526 */
527 free(opt_item->env);
528 opt_item->env = new_opt;
459 } 529 }
460 530
461 /* Export BOOTP fields. Fields we don't (yet?) export: 531 /* Export BOOTP fields. Fields we don't (yet?) export:
@@ -473,41 +543,38 @@ static llist_t *fill_envp(struct dhcp_packet *packet)
473 /* Most important one: yiaddr as $ip */ 543 /* Most important one: yiaddr as $ip */
474 new_opt = xmalloc(sizeof("ip=255.255.255.255")); 544 new_opt = xmalloc(sizeof("ip=255.255.255.255"));
475 sprint_nip(new_opt, "ip=", (uint8_t *) &packet->yiaddr); 545 sprint_nip(new_opt, "ip=", (uint8_t *) &packet->yiaddr);
476 putenvp(&envp, new_opt); 546 putenvp(new_opt);
477 547
478 if (packet->siaddr_nip) { 548 if (packet->siaddr_nip) {
479 /* IP address of next server to use in bootstrap */ 549 /* IP address of next server to use in bootstrap */
480 new_opt = xmalloc(sizeof("siaddr=255.255.255.255")); 550 new_opt = xmalloc(sizeof("siaddr=255.255.255.255"));
481 sprint_nip(new_opt, "siaddr=", (uint8_t *) &packet->siaddr_nip); 551 sprint_nip(new_opt, "siaddr=", (uint8_t *) &packet->siaddr_nip);
482 putenvp(&envp, new_opt); 552 putenvp(new_opt);
483 } 553 }
484 if (packet->gateway_nip) { 554 if (packet->gateway_nip) {
485 /* IP address of DHCP relay agent */ 555 /* IP address of DHCP relay agent */
486 new_opt = xmalloc(sizeof("giaddr=255.255.255.255")); 556 new_opt = xmalloc(sizeof("giaddr=255.255.255.255"));
487 sprint_nip(new_opt, "giaddr=", (uint8_t *) &packet->gateway_nip); 557 sprint_nip(new_opt, "giaddr=", (uint8_t *) &packet->gateway_nip);
488 putenvp(&envp, new_opt); 558 putenvp(new_opt);
489 } 559 }
490 if (!(scan_state.overload & FILE_FIELD) && packet->file[0]) { 560 if (!(scan_state.overload & FILE_FIELD) && packet->file[0]) {
491 /* watch out for invalid packets */ 561 /* watch out for invalid packets */
492 new_opt = xasprintf("boot_file=%."DHCP_PKT_FILE_LEN_STR"s", packet->file); 562 new_opt = xasprintf("boot_file=%."DHCP_PKT_FILE_LEN_STR"s", packet->file);
493 putenvp(&envp, new_opt); 563 putenvp(new_opt);
494 } 564 }
495 if (!(scan_state.overload & SNAME_FIELD) && packet->sname[0]) { 565 if (!(scan_state.overload & SNAME_FIELD) && packet->sname[0]) {
496 /* watch out for invalid packets */ 566 /* watch out for invalid packets */
497 new_opt = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname); 567 new_opt = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname);
498 putenvp(&envp, new_opt); 568 putenvp(new_opt);
499 } 569 }
500
501 return envp;
502} 570}
503 571
504/* Call a script with a par file and env vars */ 572/* Call a script with a par file and env vars */
505static void udhcp_run_script(struct dhcp_packet *packet, const char *name) 573static void udhcp_run_script(struct dhcp_packet *packet, const char *name)
506{ 574{
507 llist_t *envp;
508 char *argv[3]; 575 char *argv[3];
509 576
510 envp = fill_envp(packet); 577 fill_envp(packet);
511 578
512 /* call script */ 579 /* call script */
513 log1("executing %s %s", client_data.script, name); 580 log1("executing %s %s", client_data.script, name);
@@ -517,7 +584,8 @@ static void udhcp_run_script(struct dhcp_packet *packet, const char *name)
517 spawn_and_wait(argv); 584 spawn_and_wait(argv);
518 585
519 /* Free all allocated environment variables */ 586 /* Free all allocated environment variables */
520 llist_free(envp, (void (*)(void *))bb_unsetenv_and_free); 587 llist_free(client_data.envp, optitem_unset_env_and_free);
588 client_data.envp = NULL;
521} 589}
522 590
523 591
diff --git a/networking/udhcp/dhcpc.h b/networking/udhcp/dhcpc.h
index b407a6cdb..7ad01ea8f 100644
--- a/networking/udhcp/dhcpc.h
+++ b/networking/udhcp/dhcpc.h
@@ -21,6 +21,7 @@ struct client_data_t {
21 uint8_t *vendorclass; /* Optional vendor class-id to use */ 21 uint8_t *vendorclass; /* Optional vendor class-id to use */
22 uint8_t *hostname; /* Optional hostname to use */ 22 uint8_t *hostname; /* Optional hostname to use */
23 uint8_t *fqdn; /* Optional fully qualified domain name to use */ 23 uint8_t *fqdn; /* Optional fully qualified domain name to use */
24 llist_t *envp; /* list of DHCP options used for env vars */
24 25
25 unsigned first_secs; 26 unsigned first_secs;
26 unsigned last_secs; 27 unsigned last_secs;
diff --git a/networking/udhcp/domain_codec.c b/networking/udhcp/domain_codec.c
index 752c0a863..eab4da68b 100644
--- a/networking/udhcp/domain_codec.c
+++ b/networking/udhcp/domain_codec.c
@@ -10,10 +10,14 @@
10# define _GNU_SOURCE 10# define _GNU_SOURCE
11# define FAST_FUNC /* nothing */ 11# define FAST_FUNC /* nothing */
12# define xmalloc malloc 12# define xmalloc malloc
13# define xzalloc(s) calloc(s, 1)
14# define xstrdup strdup
15# define xrealloc realloc
13# include <stdlib.h> 16# include <stdlib.h>
14# include <stdint.h> 17# include <stdint.h>
15# include <string.h> 18# include <string.h>
16# include <stdio.h> 19# include <stdio.h>
20# include <ctype.h>
17#else 21#else
18# include "common.h" 22# include "common.h"
19#endif 23#endif
@@ -26,86 +30,77 @@
26 30
27 31
28/* Expand a RFC1035-compressed list of domain names "cstr", of length "clen"; 32/* Expand a RFC1035-compressed list of domain names "cstr", of length "clen";
29 * returns a newly allocated string containing the space-separated domains, 33 * return a newly allocated string containing the space-separated domains,
30 * prefixed with the contents of string pre, or NULL if an error occurs. 34 * prefixed with the contents of string pre, or NULL if an error occurs.
31 */ 35 */
32char* FAST_FUNC dname_dec(const uint8_t *cstr, int clen, const char *pre) 36char* FAST_FUNC dname_dec(const uint8_t *cstr, int clen, const char *pre)
33{ 37{
34 char *ret = ret; /* for compiler */ 38 char *ret, *end;
35 char *dst = NULL; 39 unsigned len, crtpos, retpos, depth;
36 40
37 /* We make two passes over the cstr string. First, we compute 41 crtpos = retpos = depth = 0;
38 * how long the resulting string would be. Then we allocate a 42 len = strlen(pre);
39 * new buffer of the required length, and fill it in with the 43 end = ret = xstrdup(pre);
40 * expanded content. The advantage of this approach is not 44
41 * having to deal with requiring callers to supply their own 45 /* Scan the string once, allocating new memory as needed */
42 * buffer, then having to check if it's sufficiently large, etc. 46 while (crtpos < clen) {
43 */
44 while (1) {
45 /* note: "return NULL" below are leak-safe since
46 * dst isn't allocated yet */
47 const uint8_t *c; 47 const uint8_t *c;
48 unsigned crtpos, retpos, depth, len; 48 c = cstr + crtpos;
49 49
50 crtpos = retpos = depth = len = 0; 50 if ((*c & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
51 while (crtpos < clen) { 51 /* pointer */
52 c = cstr + crtpos; 52 if (crtpos + 2 > clen) /* no offset to jump to? abort */
53 goto error;
54 if (retpos == 0) /* toplevel? save return spot */
55 retpos = crtpos + 2;
56 depth++;
57 crtpos = ((c[0] << 8) | c[1]) & 0x3fff; /* jump */
58 } else if (*c) {
59 unsigned label_len;
60 /* label */
61 if (crtpos + *c + 1 > clen) /* label too long? abort */
62 goto error;
63 ret = xrealloc(ret, len + *c + 1);
64 /* \3com ---> "com." */
65 end = (char *)mempcpy(ret + len, c + 1, *c);
66 *end = '.';
53 67
54 if ((*c & NS_CMPRSFLGS) == NS_CMPRSFLGS) { 68 label_len = *c + 1;
55 /* pointer */ 69 len += label_len;
56 if (crtpos + 2 > clen) /* no offset to jump to? abort */ 70 crtpos += label_len;
57 return NULL; 71 } else {
58 if (retpos == 0) /* toplevel? save return spot */ 72 /* NUL: end of current domain name */
59 retpos = crtpos + 2; 73 if (retpos == 0) {
60 depth++; 74 /* toplevel? keep going */
61 crtpos = ((c[0] & 0x3f) << 8) | c[1]; /* jump */ 75 crtpos++;
62 } else if (*c) {
63 /* label */
64 if (crtpos + *c + 1 > clen) /* label too long? abort */
65 return NULL;
66 if (dst)
67 /* \3com ---> "com." */
68 ((char*)mempcpy(dst + len, c + 1, *c))[0] = '.';
69 len += *c + 1;
70 crtpos += *c + 1;
71 } else { 76 } else {
72 /* NUL: end of current domain name */ 77 /* return to toplevel saved spot */
73 if (retpos == 0) { 78 crtpos = retpos;
74 /* toplevel? keep going */ 79 retpos = depth = 0;
75 crtpos++;
76 } else {
77 /* return to toplevel saved spot */
78 crtpos = retpos;
79 retpos = depth = 0;
80 }
81 if (dst && len != 0)
82 /* \4host\3com\0\4host and we are at \0:
83 * \3com was converted to "com.", change dot to space.
84 */
85 dst[len - 1] = ' ';
86 } 80 }
87 81
88 if (depth > NS_MAXDNSRCH /* too many jumps? abort, it's a loop */ 82 if (len != 0) {
89 || len > NS_MAXDNAME * NS_MAXDNSRCH /* result too long? abort */ 83 /* \4host\3com\0\4host and we are at \0:
90 ) { 84 * \3com was converted to "com.", change dot to space.
91 return NULL; 85 */
86 ret[len - 1] = ' ';
92 } 87 }
93 } 88 }
94 89
95 if (!len) /* expanded string has 0 length? abort */ 90 if (depth > NS_MAXDNSRCH /* too many jumps? abort, it's a loop */
96 return NULL; 91 || len > NS_MAXDNAME * NS_MAXDNSRCH /* result too long? abort */
97 92 ) {
98 if (!dst) { /* first pass? */ 93 goto error;
99 /* allocate dst buffer and copy pre */
100 unsigned plen = strlen(pre);
101 ret = xmalloc(plen + len);
102 dst = stpcpy(ret, pre);
103 } else {
104 dst[len - 1] = '\0';
105 break;
106 } 94 }
107 } 95 }
108 96
97 if (ret == end) { /* expanded string is empty? abort */
98 error:
99 free(ret);
100 return NULL;
101 }
102
103 *end = '\0';
109 return ret; 104 return ret;
110} 105}
111 106
@@ -115,42 +110,40 @@ char* FAST_FUNC dname_dec(const uint8_t *cstr, int clen, const char *pre)
115 */ 110 */
116static uint8_t *convert_dname(const char *src, int *retlen) 111static uint8_t *convert_dname(const char *src, int *retlen)
117{ 112{
118 uint8_t c, *res, *lenptr, *dst; 113 uint8_t *res, *lenptr, *dst;
119 int len;
120 114
121 res = xmalloc(strlen(src) + 2); 115 res = xzalloc(strlen(src) + 2);
122 dst = lenptr = res; 116 dst = lenptr = res;
123 dst++; 117 dst++;
124 118
125 for (;;) { 119 for (;;) {
120 uint8_t c;
121 int len;
122
126 c = (uint8_t)*src++; 123 c = (uint8_t)*src++;
127 if (c == '.' || c == '\0') { /* end of label */ 124 if (c == '.' || c == '\0') { /* end of label */
128 len = dst - lenptr - 1; 125 len = dst - lenptr - 1;
129 /* label too long, too short, or two '.'s in a row? abort */ 126 /* label too long, too short, or two '.'s in a row (len will be 0) */
130 if (len > NS_MAXLABEL || len == 0 || (c == '.' && *src == '.')) { 127 if (len > NS_MAXLABEL || len == 0)
131 free(res); 128 goto error;
132 *retlen = 0; 129
133 return NULL;
134 }
135 *lenptr = len; 130 *lenptr = len;
136 if (c == '\0' || *src == '\0') /* "" or ".": end of src */ 131 if (c == '\0' || *src == '\0') /* "" or ".": end of src */
137 break; 132 break;
138 lenptr = dst++; 133 lenptr = dst++;
139 continue; 134 continue;
140 } 135 }
141 if (c >= 'A' && c <= 'Z') /* uppercase? convert to lower */ 136 *dst++ = tolower(c);
142 c += ('a' - 'A');
143 *dst++ = c;
144 } 137 }
145 138
146 if (dst - res >= NS_MAXCDNAME) { /* dname too long? abort */ 139 *retlen = dst + 1 - res;
140 if (*retlen > NS_MAXCDNAME) { /* dname too long? abort */
141 error:
147 free(res); 142 free(res);
148 *retlen = 0; 143 *retlen = 0;
149 return NULL; 144 return NULL;
150 } 145 }
151 146
152 *dst++ = 0;
153 *retlen = dst - res;
154 return res; 147 return res;
155} 148}
156 149
@@ -245,6 +238,7 @@ int main(int argc, char **argv)
245 printf("test4:'%s'\n", DNAME_DEC("\4host\3com\0\xC0\5", "")); 238 printf("test4:'%s'\n", DNAME_DEC("\4host\3com\0\xC0\5", ""));
246 printf("test5:'%s'\n", DNAME_DEC("\4host\3com\0\xC0\5\1z\xC0\xA", "")); 239 printf("test5:'%s'\n", DNAME_DEC("\4host\3com\0\xC0\5\1z\xC0\xA", ""));
247 240
241#if 0
248#define DNAME_ENC(cache,source,lenp) dname_enc((uint8_t*)(cache), sizeof(cache), (source), (lenp)) 242#define DNAME_ENC(cache,source,lenp) dname_enc((uint8_t*)(cache), sizeof(cache), (source), (lenp))
249 encoded = dname_enc(NULL, 0, "test.net", &len); 243 encoded = dname_enc(NULL, 0, "test.net", &len);
250 printf("test6:'%s' len:%d\n", dname_dec(encoded, len, ""), len); 244 printf("test6:'%s' len:%d\n", dname_dec(encoded, len, ""), len);
@@ -252,6 +246,13 @@ int main(int argc, char **argv)
252 printf("test7:'%s' len:%d\n", dname_dec(encoded, len, ""), len); 246 printf("test7:'%s' len:%d\n", dname_dec(encoded, len, ""), len);
253 encoded = DNAME_ENC("\4test\3net\0", "test.net", &len); 247 encoded = DNAME_ENC("\4test\3net\0", "test.net", &len);
254 printf("test8:'%s' len:%d\n", dname_dec(encoded, len, ""), len); 248 printf("test8:'%s' len:%d\n", dname_dec(encoded, len, ""), len);
249#endif
250
251 encoded = dname_enc("test.net", &len);
252 printf("test6:'%s' len:%d\n", dname_dec(encoded, len, ""), len);
253 encoded = dname_enc("test.host.com", &len);
254 printf("test7:'%s' len:%d\n", dname_dec(encoded, len, ""), len);
255
255 return 0; 256 return 0;
256} 257}
257#endif 258#endif
diff --git a/networking/vconfig.c b/networking/vconfig.c
index 3cc5f2460..4f1fbe280 100644
--- a/networking/vconfig.c
+++ b/networking/vconfig.c
@@ -9,7 +9,6 @@
9//config:config VCONFIG 9//config:config VCONFIG
10//config: bool "vconfig (2.3 kb)" 10//config: bool "vconfig (2.3 kb)"
11//config: default y 11//config: default y
12//config: select PLATFORM_LINUX
13//config: help 12//config: help
14//config: Creates, removes, and configures VLAN interfaces 13//config: Creates, removes, and configures VLAN interfaces
15 14
diff --git a/networking/zcip.c b/networking/zcip.c
index 134dfb2df..311dfbe4c 100644
--- a/networking/zcip.c
+++ b/networking/zcip.c
@@ -16,7 +16,6 @@
16//config:config ZCIP 16//config:config ZCIP
17//config: bool "zcip (8.4 kb)" 17//config: bool "zcip (8.4 kb)"
18//config: default y 18//config: default y
19//config: select PLATFORM_LINUX
20//config: select FEATURE_SYSLOG 19//config: select FEATURE_SYSLOG
21//config: help 20//config: help
22//config: ZCIP provides ZeroConf IPv4 address selection, according to RFC 3927. 21//config: ZCIP provides ZeroConf IPv4 address selection, according to RFC 3927.