diff options
author | Ron Yorston <rmy@pobox.com> | 2012-03-23 11:13:23 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2012-03-23 11:13:23 +0000 |
commit | 40514a0309939f2446f0d4ed9600cad5de396e7f (patch) | |
tree | 0f5f4a57d4bb7893418b5bb11d482858eb17ba8b /networking | |
parent | 9db164d6e39050d09f38288c6045cd2a2cbf6d63 (diff) | |
parent | c0cae52662ccced9df19f19ec94238d1b1e3bd71 (diff) | |
download | busybox-w32-40514a0309939f2446f0d4ed9600cad5de396e7f.tar.gz busybox-w32-40514a0309939f2446f0d4ed9600cad5de396e7f.tar.bz2 busybox-w32-40514a0309939f2446f0d4ed9600cad5de396e7f.zip |
Merge commit 'c0cae52662ccced9df19f19ec94238d1b1e3bd71' into merge
Conflicts:
Makefile.flags
scripts/basic/fixdep.c
Diffstat (limited to 'networking')
-rw-r--r-- | networking/httpd.c | 76 | ||||
-rw-r--r-- | networking/ifupdown.c | 40 | ||||
-rw-r--r-- | networking/inetd.c | 68 | ||||
-rw-r--r-- | networking/nc_bloaty.c | 3 | ||||
-rw-r--r-- | networking/ping.c | 37 | ||||
-rw-r--r-- | networking/tftp.c | 3 | ||||
-rw-r--r-- | networking/traceroute.c | 35 | ||||
-rw-r--r-- | networking/udhcp/common.c | 6 | ||||
-rw-r--r-- | networking/udhcp/common.h | 7 | ||||
-rw-r--r-- | networking/udhcp/dhcpc.c | 220 | ||||
-rw-r--r-- | networking/udhcp/dhcpd.c | 4 | ||||
-rw-r--r-- | networking/udhcp/packet.c | 34 | ||||
-rw-r--r-- | networking/wget.c | 13 | ||||
-rw-r--r-- | networking/zcip.c | 2 |
14 files changed, 277 insertions, 271 deletions
diff --git a/networking/httpd.c b/networking/httpd.c index ba5eebad5..24482fe52 100644 --- a/networking/httpd.c +++ b/networking/httpd.c | |||
@@ -820,78 +820,6 @@ static char *encodeString(const char *string) | |||
820 | } | 820 | } |
821 | #endif | 821 | #endif |
822 | 822 | ||
823 | /* | ||
824 | * Given a URL encoded string, convert it to plain ascii. | ||
825 | * Since decoding always makes strings smaller, the decode is done in-place. | ||
826 | * Thus, callers should xstrdup() the argument if they do not want the | ||
827 | * argument modified. The return is the original pointer, allowing this | ||
828 | * function to be easily used as arguments to other functions. | ||
829 | * | ||
830 | * string The first string to decode. | ||
831 | * option_d 1 if called for httpd -d | ||
832 | * | ||
833 | * Returns a pointer to the decoded string (same as input). | ||
834 | */ | ||
835 | static unsigned hex_to_bin(unsigned char c) | ||
836 | { | ||
837 | unsigned v; | ||
838 | |||
839 | v = c - '0'; | ||
840 | if (v <= 9) | ||
841 | return v; | ||
842 | /* c | 0x20: letters to lower case, non-letters | ||
843 | * to (potentially different) non-letters */ | ||
844 | v = (unsigned)(c | 0x20) - 'a'; | ||
845 | if (v <= 5) | ||
846 | return v + 10; | ||
847 | return ~0; | ||
848 | /* For testing: | ||
849 | void t(char c) { printf("'%c'(%u) %u\n", c, c, hex_to_bin(c)); } | ||
850 | int main() { t(0x10); t(0x20); t('0'); t('9'); t('A'); t('F'); t('a'); t('f'); | ||
851 | t('0'-1); t('9'+1); t('A'-1); t('F'+1); t('a'-1); t('f'+1); return 0; } | ||
852 | */ | ||
853 | } | ||
854 | static char *decodeString(char *orig, int option_d) | ||
855 | { | ||
856 | /* note that decoded string is always shorter than original */ | ||
857 | char *string = orig; | ||
858 | char *ptr = string; | ||
859 | char c; | ||
860 | |||
861 | while ((c = *ptr++) != '\0') { | ||
862 | unsigned v; | ||
863 | |||
864 | if (option_d && c == '+') { | ||
865 | *string++ = ' '; | ||
866 | continue; | ||
867 | } | ||
868 | if (c != '%') { | ||
869 | *string++ = c; | ||
870 | continue; | ||
871 | } | ||
872 | v = hex_to_bin(ptr[0]); | ||
873 | if (v > 15) { | ||
874 | bad_hex: | ||
875 | if (!option_d) | ||
876 | return NULL; | ||
877 | *string++ = '%'; | ||
878 | continue; | ||
879 | } | ||
880 | v = (v * 16) | hex_to_bin(ptr[1]); | ||
881 | if (v > 255) | ||
882 | goto bad_hex; | ||
883 | if (!option_d && (v == '/' || v == '\0')) { | ||
884 | /* caller takes it as indication of invalid | ||
885 | * (dangerous wrt exploits) chars */ | ||
886 | return orig + 1; | ||
887 | } | ||
888 | *string++ = v; | ||
889 | ptr += 2; | ||
890 | } | ||
891 | *string = '\0'; | ||
892 | return orig; | ||
893 | } | ||
894 | |||
895 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH | 823 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH |
896 | /* | 824 | /* |
897 | * Decode a base64 data stream as per rfc1521. | 825 | * Decode a base64 data stream as per rfc1521. |
@@ -1949,7 +1877,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) | |||
1949 | } | 1877 | } |
1950 | 1878 | ||
1951 | /* Decode URL escape sequences */ | 1879 | /* Decode URL escape sequences */ |
1952 | tptr = decodeString(urlcopy, 0); | 1880 | tptr = percent_decode_in_place(urlcopy, /*strict:*/ 1); |
1953 | if (tptr == NULL) | 1881 | if (tptr == NULL) |
1954 | send_headers_and_exit(HTTP_BAD_REQUEST); | 1882 | send_headers_and_exit(HTTP_BAD_REQUEST); |
1955 | if (tptr == urlcopy + 1) { | 1883 | if (tptr == urlcopy + 1) { |
@@ -2408,7 +2336,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) | |||
2408 | , &verbose | 2336 | , &verbose |
2409 | ); | 2337 | ); |
2410 | if (opt & OPT_DECODE_URL) { | 2338 | if (opt & OPT_DECODE_URL) { |
2411 | fputs(decodeString(url_for_decode, 1), stdout); | 2339 | fputs(percent_decode_in_place(url_for_decode, /*strict:*/ 0), stdout); |
2412 | return 0; | 2340 | return 0; |
2413 | } | 2341 | } |
2414 | #if ENABLE_FEATURE_HTTPD_ENCODE_URL_STR | 2342 | #if ENABLE_FEATURE_HTTPD_ENCODE_URL_STR |
diff --git a/networking/ifupdown.c b/networking/ifupdown.c index 382033038..5946323d0 100644 --- a/networking/ifupdown.c +++ b/networking/ifupdown.c | |||
@@ -87,7 +87,6 @@ struct mapping_defn_t { | |||
87 | 87 | ||
88 | char *script; | 88 | char *script; |
89 | 89 | ||
90 | int max_mappings; | ||
91 | int n_mappings; | 90 | int n_mappings; |
92 | char **mapping; | 91 | char **mapping; |
93 | }; | 92 | }; |
@@ -102,7 +101,6 @@ struct interface_defn_t { | |||
102 | const struct method_t *method; | 101 | const struct method_t *method; |
103 | 102 | ||
104 | char *iface; | 103 | char *iface; |
105 | int max_options; | ||
106 | int n_options; | 104 | int n_options; |
107 | struct variable_t *option; | 105 | struct variable_t *option; |
108 | }; | 106 | }; |
@@ -138,6 +136,16 @@ struct globals { | |||
138 | #define INIT_G() do { } while (0) | 136 | #define INIT_G() do { } while (0) |
139 | 137 | ||
140 | 138 | ||
139 | static const char keywords_up_down[] ALIGN1 = | ||
140 | "up\0" | ||
141 | "down\0" | ||
142 | "pre-up\0" | ||
143 | "pre-down\0" | ||
144 | "post-up\0" | ||
145 | "post-down\0" | ||
146 | ; | ||
147 | |||
148 | |||
141 | #if ENABLE_FEATURE_IFUPDOWN_IPV4 || ENABLE_FEATURE_IFUPDOWN_IPV6 | 149 | #if ENABLE_FEATURE_IFUPDOWN_IPV4 || ENABLE_FEATURE_IFUPDOWN_IPV6 |
142 | 150 | ||
143 | static void addstr(char **bufp, const char *str, size_t str_length) | 151 | static void addstr(char **bufp, const char *str, size_t str_length) |
@@ -803,7 +811,6 @@ static struct interfaces_file_t *read_interfaces(const char *filename) | |||
803 | currmap->match = xrealloc_vector(currmap->match, 4, currmap->n_matches); | 811 | currmap->match = xrealloc_vector(currmap->match, 4, currmap->n_matches); |
804 | currmap->match[currmap->n_matches++] = xstrdup(first_word); | 812 | currmap->match[currmap->n_matches++] = xstrdup(first_word); |
805 | } | 813 | } |
806 | /*currmap->max_mappings = 0; - done by xzalloc */ | ||
807 | /*currmap->n_mappings = 0;*/ | 814 | /*currmap->n_mappings = 0;*/ |
808 | /*currmap->mapping = NULL;*/ | 815 | /*currmap->mapping = NULL;*/ |
809 | /*currmap->script = NULL;*/ | 816 | /*currmap->script = NULL;*/ |
@@ -888,23 +895,16 @@ static struct interfaces_file_t *read_interfaces(const char *filename) | |||
888 | if (rest_of_line[0] == '\0') | 895 | if (rest_of_line[0] == '\0') |
889 | bb_error_msg_and_die("option with empty value \"%s\"", buf); | 896 | bb_error_msg_and_die("option with empty value \"%s\"", buf); |
890 | 897 | ||
891 | if (strcmp(first_word, "up") != 0 | 898 | /* If not one of "up", "down",... words... */ |
892 | && strcmp(first_word, "down") != 0 | 899 | if (index_in_strings(keywords_up_down, first_word) < 0) { |
893 | && strcmp(first_word, "pre-up") != 0 | ||
894 | && strcmp(first_word, "post-down") != 0 | ||
895 | ) { | ||
896 | int i; | 900 | int i; |
897 | for (i = 0; i < currif->n_options; i++) { | 901 | for (i = 0; i < currif->n_options; i++) { |
898 | if (strcmp(currif->option[i].name, first_word) == 0) | 902 | if (strcmp(currif->option[i].name, first_word) == 0) |
899 | bb_error_msg_and_die("duplicate option \"%s\"", buf); | 903 | bb_error_msg_and_die("duplicate option \"%s\"", buf); |
900 | } | 904 | } |
901 | } | 905 | } |
902 | if (currif->n_options >= currif->max_options) { | ||
903 | currif->max_options += 10; | ||
904 | currif->option = xrealloc(currif->option, | ||
905 | sizeof(*currif->option) * currif->max_options); | ||
906 | } | ||
907 | debug_noise("\t%s=%s\n", first_word, rest_of_line); | 906 | debug_noise("\t%s=%s\n", first_word, rest_of_line); |
907 | currif->option = xrealloc_vector(currif->option, 4, currif->n_options); | ||
908 | currif->option[currif->n_options].name = xstrdup(first_word); | 908 | currif->option[currif->n_options].name = xstrdup(first_word); |
909 | currif->option[currif->n_options].value = xstrdup(rest_of_line); | 909 | currif->option[currif->n_options].value = xstrdup(rest_of_line); |
910 | currif->n_options++; | 910 | currif->n_options++; |
@@ -916,11 +916,7 @@ static struct interfaces_file_t *read_interfaces(const char *filename) | |||
916 | bb_error_msg_and_die("duplicate script in mapping \"%s\"", buf); | 916 | bb_error_msg_and_die("duplicate script in mapping \"%s\"", buf); |
917 | currmap->script = xstrdup(next_word(&rest_of_line)); | 917 | currmap->script = xstrdup(next_word(&rest_of_line)); |
918 | } else if (strcmp(first_word, "map") == 0) { | 918 | } else if (strcmp(first_word, "map") == 0) { |
919 | if (currmap->n_mappings >= currmap->max_mappings) { | 919 | currmap->mapping = xrealloc_vector(currmap->mapping, 2, currmap->n_mappings); |
920 | currmap->max_mappings = currmap->max_mappings * 2 + 1; | ||
921 | currmap->mapping = xrealloc(currmap->mapping, | ||
922 | sizeof(char *) * currmap->max_mappings); | ||
923 | } | ||
924 | currmap->mapping[currmap->n_mappings] = xstrdup(next_word(&rest_of_line)); | 920 | currmap->mapping[currmap->n_mappings] = xstrdup(next_word(&rest_of_line)); |
925 | currmap->n_mappings++; | 921 | currmap->n_mappings++; |
926 | } else { | 922 | } else { |
@@ -984,11 +980,7 @@ static void set_environ(struct interface_defn_t *iface, const char *mode) | |||
984 | pp = G.my_environ; | 980 | pp = G.my_environ; |
985 | 981 | ||
986 | for (i = 0; i < iface->n_options; i++) { | 982 | for (i = 0; i < iface->n_options; i++) { |
987 | if (strcmp(iface->option[i].name, "up") == 0 | 983 | if (index_in_strings(keywords_up_down, iface->option[i].name) >= 0) { |
988 | || strcmp(iface->option[i].name, "down") == 0 | ||
989 | || strcmp(iface->option[i].name, "pre-up") == 0 | ||
990 | || strcmp(iface->option[i].name, "post-down") == 0 | ||
991 | ) { | ||
992 | continue; | 984 | continue; |
993 | } | 985 | } |
994 | *pp++ = setlocalenv("IF_%s=%s", iface->option[i].name, iface->option[i].value); | 986 | *pp++ = setlocalenv("IF_%s=%s", iface->option[i].name, iface->option[i].value); |
@@ -1056,6 +1048,7 @@ static int iface_up(struct interface_defn_t *iface) | |||
1056 | if (!execute_all(iface, "pre-up")) return 0; | 1048 | if (!execute_all(iface, "pre-up")) return 0; |
1057 | if (!iface->method->up(iface, doit)) return 0; | 1049 | if (!iface->method->up(iface, doit)) return 0; |
1058 | if (!execute_all(iface, "up")) return 0; | 1050 | if (!execute_all(iface, "up")) return 0; |
1051 | if (!execute_all(iface, "post-up")) return 0; | ||
1059 | return 1; | 1052 | return 1; |
1060 | } | 1053 | } |
1061 | 1054 | ||
@@ -1063,6 +1056,7 @@ static int iface_down(struct interface_defn_t *iface) | |||
1063 | { | 1056 | { |
1064 | if (!iface->method->down(iface,check)) return -1; | 1057 | if (!iface->method->down(iface,check)) return -1; |
1065 | set_environ(iface, "stop"); | 1058 | set_environ(iface, "stop"); |
1059 | if (!execute_all(iface, "pre-down")) return 0; | ||
1066 | if (!execute_all(iface, "down")) return 0; | 1060 | if (!execute_all(iface, "down")) return 0; |
1067 | if (!iface->method->down(iface, doit)) return 0; | 1061 | if (!iface->method->down(iface, doit)) return 0; |
1068 | if (!execute_all(iface, "post-down")) return 0; | 1062 | if (!execute_all(iface, "post-down")) return 0; |
diff --git a/networking/inetd.c b/networking/inetd.c index 873fd9528..26b66992d 100644 --- a/networking/inetd.c +++ b/networking/inetd.c | |||
@@ -357,10 +357,26 @@ struct BUG_G_too_big { | |||
357 | config_filename = "/etc/inetd.conf"; \ | 357 | config_filename = "/etc/inetd.conf"; \ |
358 | } while (0) | 358 | } while (0) |
359 | 359 | ||
360 | #if 1 | ||
361 | # define dbg(...) ((void)0) | ||
362 | #else | ||
363 | # define dbg(...) \ | ||
364 | do { \ | ||
365 | int dbg_fd = open("inetd_debug.log", O_WRONLY | O_CREAT | O_APPEND, 0666); \ | ||
366 | if (dbg_fd >= 0) { \ | ||
367 | fdprintf(dbg_fd, "%d: ", getpid()); \ | ||
368 | fdprintf(dbg_fd, __VA_ARGS__); \ | ||
369 | close(dbg_fd); \ | ||
370 | } \ | ||
371 | } while (0) | ||
372 | #endif | ||
373 | |||
360 | static void maybe_close(int fd) | 374 | static void maybe_close(int fd) |
361 | { | 375 | { |
362 | if (fd >= 0) | 376 | if (fd >= 0) { |
363 | close(fd); | 377 | close(fd); |
378 | dbg("closed fd:%d\n", fd); | ||
379 | } | ||
364 | } | 380 | } |
365 | 381 | ||
366 | // TODO: move to libbb? | 382 | // TODO: move to libbb? |
@@ -464,7 +480,9 @@ static void remove_fd_from_set(int fd) | |||
464 | { | 480 | { |
465 | if (fd >= 0) { | 481 | if (fd >= 0) { |
466 | FD_CLR(fd, &allsock); | 482 | FD_CLR(fd, &allsock); |
483 | dbg("stopped listening on fd:%d\n", fd); | ||
467 | maxsock = -1; | 484 | maxsock = -1; |
485 | dbg("maxsock:%d\n", maxsock); | ||
468 | } | 486 | } |
469 | } | 487 | } |
470 | 488 | ||
@@ -472,8 +490,10 @@ static void add_fd_to_set(int fd) | |||
472 | { | 490 | { |
473 | if (fd >= 0) { | 491 | if (fd >= 0) { |
474 | FD_SET(fd, &allsock); | 492 | FD_SET(fd, &allsock); |
493 | dbg("started listening on fd:%d\n", fd); | ||
475 | if (maxsock >= 0 && fd > maxsock) { | 494 | if (maxsock >= 0 && fd > maxsock) { |
476 | prev_maxsock = maxsock = fd; | 495 | prev_maxsock = maxsock = fd; |
496 | dbg("maxsock:%d\n", maxsock); | ||
477 | if ((rlim_t)fd > rlim_ofile_cur - FD_MARGIN) | 497 | if ((rlim_t)fd > rlim_ofile_cur - FD_MARGIN) |
478 | bump_nofile(); | 498 | bump_nofile(); |
479 | } | 499 | } |
@@ -492,6 +512,7 @@ static void recalculate_maxsock(void) | |||
492 | maxsock = fd; | 512 | maxsock = fd; |
493 | fd++; | 513 | fd++; |
494 | } | 514 | } |
515 | dbg("recalculated maxsock:%d\n", maxsock); | ||
495 | prev_maxsock = maxsock; | 516 | prev_maxsock = maxsock; |
496 | if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN) | 517 | if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN) |
497 | bump_nofile(); | 518 | bump_nofile(); |
@@ -549,8 +570,13 @@ static void prepare_socket_fd(servtab_t *sep) | |||
549 | rearm_alarm(); | 570 | rearm_alarm(); |
550 | return; | 571 | return; |
551 | } | 572 | } |
552 | if (sep->se_socktype == SOCK_STREAM) | 573 | |
574 | if (sep->se_socktype == SOCK_STREAM) { | ||
553 | listen(fd, global_queuelen); | 575 | listen(fd, global_queuelen); |
576 | dbg("new sep->se_fd:%d (stream)\n", fd); | ||
577 | } else { | ||
578 | dbg("new sep->se_fd:%d (!stream)\n", fd); | ||
579 | } | ||
554 | 580 | ||
555 | add_fd_to_set(fd); | 581 | add_fd_to_set(fd); |
556 | sep->se_fd = fd; | 582 | sep->se_fd = fd; |
@@ -1012,7 +1038,7 @@ static void reread_config_file(int sig UNUSED_PARAM) | |||
1012 | * new config file doesnt have them. */ | 1038 | * new config file doesnt have them. */ |
1013 | block_CHLD_HUP_ALRM(&omask); | 1039 | block_CHLD_HUP_ALRM(&omask); |
1014 | sepp = &serv_list; | 1040 | sepp = &serv_list; |
1015 | while ((sep = *sepp)) { | 1041 | while ((sep = *sepp) != NULL) { |
1016 | if (sep->se_checked) { | 1042 | if (sep->se_checked) { |
1017 | sepp = &sep->se_next; | 1043 | sepp = &sep->se_next; |
1018 | continue; | 1044 | continue; |
@@ -1206,11 +1232,13 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) | |||
1206 | } | 1232 | } |
1207 | continue; | 1233 | continue; |
1208 | } | 1234 | } |
1235 | dbg("ready_fd_cnt:%d\n", ready_fd_cnt); | ||
1209 | 1236 | ||
1210 | for (sep = serv_list; ready_fd_cnt && sep; sep = sep->se_next) { | 1237 | for (sep = serv_list; ready_fd_cnt && sep; sep = sep->se_next) { |
1211 | if (sep->se_fd == -1 || !FD_ISSET(sep->se_fd, &readable)) | 1238 | if (sep->se_fd == -1 || !FD_ISSET(sep->se_fd, &readable)) |
1212 | continue; | 1239 | continue; |
1213 | 1240 | ||
1241 | dbg("ready fd:%d\n", sep->se_fd); | ||
1214 | ready_fd_cnt--; | 1242 | ready_fd_cnt--; |
1215 | ctrl = sep->se_fd; | 1243 | ctrl = sep->se_fd; |
1216 | accepted_fd = -1; | 1244 | accepted_fd = -1; |
@@ -1218,6 +1246,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) | |||
1218 | if (!sep->se_wait) { | 1246 | if (!sep->se_wait) { |
1219 | if (sep->se_socktype == SOCK_STREAM) { | 1247 | if (sep->se_socktype == SOCK_STREAM) { |
1220 | ctrl = accepted_fd = accept(sep->se_fd, NULL, NULL); | 1248 | ctrl = accepted_fd = accept(sep->se_fd, NULL, NULL); |
1249 | dbg("accepted_fd:%d\n", accepted_fd); | ||
1221 | if (ctrl < 0) { | 1250 | if (ctrl < 0) { |
1222 | if (errno != EINTR) | 1251 | if (errno != EINTR) |
1223 | bb_perror_msg("accept (for %s)", sep->se_service); | 1252 | bb_perror_msg("accept (for %s)", sep->se_service); |
@@ -1238,19 +1267,22 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) | |||
1238 | * (can create many copies of same child, etc). | 1267 | * (can create many copies of same child, etc). |
1239 | * Parent must create and use new socket instead. */ | 1268 | * Parent must create and use new socket instead. */ |
1240 | new_udp_fd = socket(sep->se_family, SOCK_DGRAM, 0); | 1269 | new_udp_fd = socket(sep->se_family, SOCK_DGRAM, 0); |
1270 | dbg("new_udp_fd:%d\n", new_udp_fd); | ||
1241 | if (new_udp_fd < 0) { /* error: eat packet, forget about it */ | 1271 | if (new_udp_fd < 0) { /* error: eat packet, forget about it */ |
1242 | udp_err: | 1272 | udp_err: |
1243 | recv(sep->se_fd, line, LINE_SIZE, MSG_DONTWAIT); | 1273 | recv(sep->se_fd, line, LINE_SIZE, MSG_DONTWAIT); |
1244 | continue; | 1274 | continue; |
1245 | } | 1275 | } |
1246 | setsockopt_reuseaddr(new_udp_fd); | 1276 | setsockopt_reuseaddr(new_udp_fd); |
1247 | /* TODO: better do bind after vfork in parent, | 1277 | /* TODO: better do bind after fork in parent, |
1248 | * so that we don't have two wildcard bound sockets | 1278 | * so that we don't have two wildcard bound sockets |
1249 | * even for a brief moment? */ | 1279 | * even for a brief moment? */ |
1250 | if (bind(new_udp_fd, &sep->se_lsa->u.sa, sep->se_lsa->len) < 0) { | 1280 | if (bind(new_udp_fd, &sep->se_lsa->u.sa, sep->se_lsa->len) < 0) { |
1281 | dbg("bind(new_udp_fd) failed\n"); | ||
1251 | close(new_udp_fd); | 1282 | close(new_udp_fd); |
1252 | goto udp_err; | 1283 | goto udp_err; |
1253 | } | 1284 | } |
1285 | dbg("bind(new_udp_fd) succeeded\n"); | ||
1254 | } | 1286 | } |
1255 | } | 1287 | } |
1256 | 1288 | ||
@@ -1278,6 +1310,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) | |||
1278 | sep->se_count = 0; | 1310 | sep->se_count = 0; |
1279 | rearm_alarm(); /* will revive it in RETRYTIME sec */ | 1311 | rearm_alarm(); /* will revive it in RETRYTIME sec */ |
1280 | restore_sigmask(&omask); | 1312 | restore_sigmask(&omask); |
1313 | maybe_close(new_udp_fd); | ||
1281 | maybe_close(accepted_fd); | 1314 | maybe_close(accepted_fd); |
1282 | continue; /* -> check next fd in fd set */ | 1315 | continue; /* -> check next fd in fd set */ |
1283 | } | 1316 | } |
@@ -1298,17 +1331,18 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) | |||
1298 | bb_perror_msg("vfork"+1); | 1331 | bb_perror_msg("vfork"+1); |
1299 | sleep(1); | 1332 | sleep(1); |
1300 | restore_sigmask(&omask); | 1333 | restore_sigmask(&omask); |
1334 | maybe_close(new_udp_fd); | ||
1301 | maybe_close(accepted_fd); | 1335 | maybe_close(accepted_fd); |
1302 | continue; /* -> check next fd in fd set */ | 1336 | continue; /* -> check next fd in fd set */ |
1303 | } | 1337 | } |
1304 | if (pid == 0) | 1338 | if (pid == 0) |
1305 | pid--; /* -1: "we did fork and we are child" */ | 1339 | pid--; /* -1: "we did fork and we are child" */ |
1306 | } | 1340 | } |
1307 | /* if pid == 0 here, we never forked */ | 1341 | /* if pid == 0 here, we didn't fork */ |
1308 | 1342 | ||
1309 | if (pid > 0) { /* parent */ | 1343 | if (pid > 0) { /* parent */ |
1310 | if (sep->se_wait) { | 1344 | if (sep->se_wait) { |
1311 | /* tcp wait: we passed listening socket to child, | 1345 | /* wait: we passed socket to child, |
1312 | * will wait for child to terminate */ | 1346 | * will wait for child to terminate */ |
1313 | sep->se_wait = pid; | 1347 | sep->se_wait = pid; |
1314 | remove_fd_from_set(sep->se_fd); | 1348 | remove_fd_from_set(sep->se_fd); |
@@ -1317,17 +1351,19 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) | |||
1317 | /* udp nowait: child connected the socket, | 1351 | /* udp nowait: child connected the socket, |
1318 | * we created and will use new, unconnected one */ | 1352 | * we created and will use new, unconnected one */ |
1319 | xmove_fd(new_udp_fd, sep->se_fd); | 1353 | xmove_fd(new_udp_fd, sep->se_fd); |
1354 | dbg("moved new_udp_fd:%d to sep->se_fd:%d\n", new_udp_fd, sep->se_fd); | ||
1320 | } | 1355 | } |
1321 | restore_sigmask(&omask); | 1356 | restore_sigmask(&omask); |
1322 | maybe_close(accepted_fd); | 1357 | maybe_close(accepted_fd); |
1323 | continue; /* -> check next fd in fd set */ | 1358 | continue; /* -> check next fd in fd set */ |
1324 | } | 1359 | } |
1325 | 1360 | ||
1326 | /* we are either child or didn't vfork at all */ | 1361 | /* we are either child or didn't fork at all */ |
1327 | #ifdef INETD_BUILTINS_ENABLED | 1362 | #ifdef INETD_BUILTINS_ENABLED |
1328 | if (sep->se_builtin) { | 1363 | if (sep->se_builtin) { |
1329 | if (pid) { /* "pid" is -1: we did vfork */ | 1364 | if (pid) { /* "pid" is -1: we did fork */ |
1330 | close(sep->se_fd); /* listening socket */ | 1365 | close(sep->se_fd); /* listening socket */ |
1366 | dbg("closed sep->se_fd:%d\n", sep->se_fd); | ||
1331 | logmode = LOGMODE_NONE; /* make xwrite etc silent */ | 1367 | logmode = LOGMODE_NONE; /* make xwrite etc silent */ |
1332 | } | 1368 | } |
1333 | restore_sigmask(&omask); | 1369 | restore_sigmask(&omask); |
@@ -1335,7 +1371,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) | |||
1335 | sep->se_builtin->bi_stream_fn(ctrl, sep); | 1371 | sep->se_builtin->bi_stream_fn(ctrl, sep); |
1336 | else | 1372 | else |
1337 | sep->se_builtin->bi_dgram_fn(ctrl, sep); | 1373 | sep->se_builtin->bi_dgram_fn(ctrl, sep); |
1338 | if (pid) /* we did vfork */ | 1374 | if (pid) /* we did fork */ |
1339 | _exit(EXIT_FAILURE); | 1375 | _exit(EXIT_FAILURE); |
1340 | maybe_close(accepted_fd); | 1376 | maybe_close(accepted_fd); |
1341 | continue; /* -> check next fd in fd set */ | 1377 | continue; /* -> check next fd in fd set */ |
@@ -1345,9 +1381,14 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) | |||
1345 | setsid(); | 1381 | setsid(); |
1346 | /* "nowait" udp */ | 1382 | /* "nowait" udp */ |
1347 | if (new_udp_fd >= 0) { | 1383 | if (new_udp_fd >= 0) { |
1348 | len_and_sockaddr *lsa = xzalloc_lsa(sep->se_family); | 1384 | len_and_sockaddr *lsa; |
1385 | int r; | ||
1386 | |||
1387 | close(new_udp_fd); | ||
1388 | dbg("closed new_udp_fd:%d\n", new_udp_fd); | ||
1389 | lsa = xzalloc_lsa(sep->se_family); | ||
1349 | /* peek at the packet and remember peer addr */ | 1390 | /* peek at the packet and remember peer addr */ |
1350 | int r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT, | 1391 | r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT, |
1351 | &lsa->u.sa, &lsa->len); | 1392 | &lsa->u.sa, &lsa->len); |
1352 | if (r < 0) | 1393 | if (r < 0) |
1353 | goto do_exit1; | 1394 | goto do_exit1; |
@@ -1355,6 +1396,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) | |||
1355 | * only packets from this peer will be recv'ed, | 1396 | * only packets from this peer will be recv'ed, |
1356 | * and bare write()/send() will work on it */ | 1397 | * and bare write()/send() will work on it */ |
1357 | connect(ctrl, &lsa->u.sa, lsa->len); | 1398 | connect(ctrl, &lsa->u.sa, lsa->len); |
1399 | dbg("connected ctrl:%d to remote peer\n", ctrl); | ||
1358 | free(lsa); | 1400 | free(lsa); |
1359 | } | 1401 | } |
1360 | /* prepare env and exec program */ | 1402 | /* prepare env and exec program */ |
@@ -1372,7 +1414,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) | |||
1372 | bb_error_msg("non-root must run services as himself"); | 1414 | bb_error_msg("non-root must run services as himself"); |
1373 | goto do_exit1; | 1415 | goto do_exit1; |
1374 | } | 1416 | } |
1375 | if (pwd->pw_uid) { | 1417 | if (pwd->pw_uid != 0) { |
1376 | if (sep->se_group) | 1418 | if (sep->se_group) |
1377 | pwd->pw_gid = grp->gr_gid; | 1419 | pwd->pw_gid = grp->gr_gid; |
1378 | /* initgroups, setgid, setuid: */ | 1420 | /* initgroups, setgid, setuid: */ |
@@ -1391,6 +1433,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) | |||
1391 | */ | 1433 | */ |
1392 | xmove_fd(ctrl, STDIN_FILENO); | 1434 | xmove_fd(ctrl, STDIN_FILENO); |
1393 | xdup2(STDIN_FILENO, STDOUT_FILENO); | 1435 | xdup2(STDIN_FILENO, STDOUT_FILENO); |
1436 | dbg("moved ctrl:%d to fd 0,1[,2]\n", ctrl); | ||
1394 | /* manpages of inetd I managed to find either say | 1437 | /* manpages of inetd I managed to find either say |
1395 | * that stderr is also redirected to the network, | 1438 | * that stderr is also redirected to the network, |
1396 | * or do not talk about redirection at all (!) */ | 1439 | * or do not talk about redirection at all (!) */ |
@@ -1403,6 +1446,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) | |||
1403 | maybe_close(sep2->se_fd); | 1446 | maybe_close(sep2->se_fd); |
1404 | sigaction_set(SIGPIPE, &saved_pipe_handler); | 1447 | sigaction_set(SIGPIPE, &saved_pipe_handler); |
1405 | restore_sigmask(&omask); | 1448 | restore_sigmask(&omask); |
1449 | dbg("execing:'%s'\n", sep->se_program); | ||
1406 | BB_EXECVP(sep->se_program, sep->se_argv); | 1450 | BB_EXECVP(sep->se_program, sep->se_argv); |
1407 | bb_perror_msg("can't execute '%s'", sep->se_program); | 1451 | bb_perror_msg("can't execute '%s'", sep->se_program); |
1408 | do_exit1: | 1452 | do_exit1: |
diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c index 1daad1358..d184f689b 100644 --- a/networking/nc_bloaty.c +++ b/networking/nc_bloaty.c | |||
@@ -428,8 +428,7 @@ create new one, and bind() it. TODO */ | |||
428 | 428 | ||
429 | rr = getsockopt(netfd, IPPROTO_IP, IP_OPTIONS, optbuf, &x); | 429 | rr = getsockopt(netfd, IPPROTO_IP, IP_OPTIONS, optbuf, &x); |
430 | if (rr >= 0 && x) { /* we've got options, lessee em... */ | 430 | if (rr >= 0 && x) { /* we've got options, lessee em... */ |
431 | bin2hex(bigbuf_net, optbuf, x); | 431 | *bin2hex(bigbuf_net, optbuf, x) = '\0'; |
432 | bigbuf_net[2*x] = '\0'; | ||
433 | fprintf(stderr, "IP options: %s\n", bigbuf_net); | 432 | fprintf(stderr, "IP options: %s\n", bigbuf_net); |
434 | } | 433 | } |
435 | #endif | 434 | #endif |
diff --git a/networking/ping.c b/networking/ping.c index efd4f210b..b8a438ba8 100644 --- a/networking/ping.c +++ b/networking/ping.c | |||
@@ -149,31 +149,6 @@ enum { | |||
149 | PINGINTERVAL = 1, /* 1 second */ | 149 | PINGINTERVAL = 1, /* 1 second */ |
150 | }; | 150 | }; |
151 | 151 | ||
152 | /* Common routines */ | ||
153 | |||
154 | static int in_cksum(unsigned short *buf, int sz) | ||
155 | { | ||
156 | int nleft = sz; | ||
157 | int sum = 0; | ||
158 | unsigned short *w = buf; | ||
159 | unsigned short ans = 0; | ||
160 | |||
161 | while (nleft > 1) { | ||
162 | sum += *w++; | ||
163 | nleft -= 2; | ||
164 | } | ||
165 | |||
166 | if (nleft == 1) { | ||
167 | *(unsigned char *) (&ans) = *(unsigned char *) w; | ||
168 | sum += ans; | ||
169 | } | ||
170 | |||
171 | sum = (sum >> 16) + (sum & 0xFFFF); | ||
172 | sum += (sum >> 16); | ||
173 | ans = ~sum; | ||
174 | return ans; | ||
175 | } | ||
176 | |||
177 | #if !ENABLE_FEATURE_FANCY_PING | 152 | #if !ENABLE_FEATURE_FANCY_PING |
178 | 153 | ||
179 | /* Simple version */ | 154 | /* Simple version */ |
@@ -201,7 +176,7 @@ static void ping4(len_and_sockaddr *lsa) | |||
201 | pkt = (struct icmp *) G.packet; | 176 | pkt = (struct icmp *) G.packet; |
202 | memset(pkt, 0, sizeof(G.packet)); | 177 | memset(pkt, 0, sizeof(G.packet)); |
203 | pkt->icmp_type = ICMP_ECHO; | 178 | pkt->icmp_type = ICMP_ECHO; |
204 | pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(G.packet)); | 179 | pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, sizeof(G.packet)); |
205 | 180 | ||
206 | xsendto(pingsock, G.packet, DEFDATALEN + ICMP_MINLEN, &lsa->u.sa, lsa->len); | 181 | xsendto(pingsock, G.packet, DEFDATALEN + ICMP_MINLEN, &lsa->u.sa, lsa->len); |
207 | 182 | ||
@@ -493,7 +468,7 @@ static void sendping4(int junk UNUSED_PARAM) | |||
493 | /* No hton: we'll read it back on the same machine */ | 468 | /* No hton: we'll read it back on the same machine */ |
494 | *(uint32_t*)&pkt->icmp_dun = monotonic_us(); | 469 | *(uint32_t*)&pkt->icmp_dun = monotonic_us(); |
495 | 470 | ||
496 | pkt->icmp_cksum = in_cksum((unsigned short *) pkt, datalen + ICMP_MINLEN); | 471 | pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, datalen + ICMP_MINLEN); |
497 | 472 | ||
498 | sendping_tail(sendping4, ICMP_MINLEN); | 473 | sendping_tail(sendping4, ICMP_MINLEN); |
499 | } | 474 | } |
@@ -512,7 +487,7 @@ static void sendping6(int junk UNUSED_PARAM) | |||
512 | /*if (datalen >= 4)*/ | 487 | /*if (datalen >= 4)*/ |
513 | *(uint32_t*)(&pkt->icmp6_data8[4]) = monotonic_us(); | 488 | *(uint32_t*)(&pkt->icmp6_data8[4]) = monotonic_us(); |
514 | 489 | ||
515 | //TODO? pkt->icmp_cksum = in_cksum(...); | 490 | //TODO? pkt->icmp_cksum = inet_cksum(...); |
516 | 491 | ||
517 | sendping_tail(sendping6, sizeof(struct icmp6_hdr)); | 492 | sendping_tail(sendping6, sizeof(struct icmp6_hdr)); |
518 | } | 493 | } |
@@ -638,7 +613,7 @@ static void unpack4(char *buf, int sz, struct sockaddr_in *from) | |||
638 | } | 613 | } |
639 | } | 614 | } |
640 | #if ENABLE_PING6 | 615 | #if ENABLE_PING6 |
641 | static void unpack6(char *packet, int sz, /*struct sockaddr_in6 *from,*/ int hoplimit) | 616 | static void unpack6(char *packet, int sz, struct sockaddr_in6 *from, int hoplimit) |
642 | { | 617 | { |
643 | struct icmp6_hdr *icmppkt; | 618 | struct icmp6_hdr *icmppkt; |
644 | char buf[INET6_ADDRSTRLEN]; | 619 | char buf[INET6_ADDRSTRLEN]; |
@@ -658,7 +633,7 @@ static void unpack6(char *packet, int sz, /*struct sockaddr_in6 *from,*/ int hop | |||
658 | if (sz >= sizeof(struct icmp6_hdr) + sizeof(uint32_t)) | 633 | if (sz >= sizeof(struct icmp6_hdr) + sizeof(uint32_t)) |
659 | tp = (uint32_t *) &icmppkt->icmp6_data8[4]; | 634 | tp = (uint32_t *) &icmppkt->icmp6_data8[4]; |
660 | unpack_tail(sz, tp, | 635 | unpack_tail(sz, tp, |
661 | inet_ntop(AF_INET6, &pingaddr.sin6.sin6_addr, | 636 | inet_ntop(AF_INET6, &from->sin6_addr, |
662 | buf, sizeof(buf)), | 637 | buf, sizeof(buf)), |
663 | recv_seq, hoplimit); | 638 | recv_seq, hoplimit); |
664 | } else if (icmppkt->icmp6_type != ICMP6_ECHO_REQUEST) { | 639 | } else if (icmppkt->icmp6_type != ICMP6_ECHO_REQUEST) { |
@@ -808,7 +783,7 @@ static void ping6(len_and_sockaddr *lsa) | |||
808 | move_from_unaligned_int(hoplimit, CMSG_DATA(mp)); | 783 | move_from_unaligned_int(hoplimit, CMSG_DATA(mp)); |
809 | } | 784 | } |
810 | } | 785 | } |
811 | unpack6(G.rcv_packet, c, /*&from,*/ hoplimit); | 786 | unpack6(G.rcv_packet, c, &from, hoplimit); |
812 | if (pingcount && nreceived >= pingcount) | 787 | if (pingcount && nreceived >= pingcount) |
813 | break; | 788 | break; |
814 | } | 789 | } |
diff --git a/networking/tftp.c b/networking/tftp.c index 17485a527..043b879af 100644 --- a/networking/tftp.c +++ b/networking/tftp.c | |||
@@ -813,7 +813,8 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv) | |||
813 | goto err; | 813 | goto err; |
814 | } | 814 | } |
815 | mode = local_file + strlen(local_file) + 1; | 815 | mode = local_file + strlen(local_file) + 1; |
816 | if (mode >= block_buf + result || strcmp(mode, "octet") != 0) { | 816 | /* RFC 1350 says mode string is case independent */ |
817 | if (mode >= block_buf + result || strcasecmp(mode, "octet") != 0) { | ||
817 | goto err; | 818 | goto err; |
818 | } | 819 | } |
819 | # if ENABLE_FEATURE_TFTP_BLOCKSIZE | 820 | # if ENABLE_FEATURE_TFTP_BLOCKSIZE |
diff --git a/networking/traceroute.c b/networking/traceroute.c index c32103519..d197e5410 100644 --- a/networking/traceroute.c +++ b/networking/traceroute.c | |||
@@ -418,39 +418,6 @@ wait_for_reply(len_and_sockaddr *from_lsa, struct sockaddr *to, unsigned *timest | |||
418 | return read_len; | 418 | return read_len; |
419 | } | 419 | } |
420 | 420 | ||
421 | /* | ||
422 | * Checksum routine for Internet Protocol family headers (C Version) | ||
423 | */ | ||
424 | static uint16_t | ||
425 | in_cksum(uint16_t *addr, int len) | ||
426 | { | ||
427 | int nleft = len; | ||
428 | uint16_t *w = addr; | ||
429 | uint16_t answer; | ||
430 | int sum = 0; | ||
431 | |||
432 | /* | ||
433 | * Our algorithm is simple, using a 32 bit accumulator (sum), | ||
434 | * we add sequential 16 bit words to it, and at the end, fold | ||
435 | * back all the carry bits from the top 16 bits into the lower | ||
436 | * 16 bits. | ||
437 | */ | ||
438 | while (nleft > 1) { | ||
439 | sum += *w++; | ||
440 | nleft -= 2; | ||
441 | } | ||
442 | |||
443 | /* mop up an odd byte, if necessary */ | ||
444 | if (nleft == 1) | ||
445 | sum += *(unsigned char *)w; | ||
446 | |||
447 | /* add back carry outs from top 16 bits to low 16 bits */ | ||
448 | sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ | ||
449 | sum += (sum >> 16); /* add carry */ | ||
450 | answer = ~sum; /* truncate to 16 bits */ | ||
451 | return answer; | ||
452 | } | ||
453 | |||
454 | static void | 421 | static void |
455 | send_probe(int seq, int ttl) | 422 | send_probe(int seq, int ttl) |
456 | { | 423 | { |
@@ -477,7 +444,7 @@ send_probe(int seq, int ttl) | |||
477 | 444 | ||
478 | /* Always calculate checksum for icmp packets */ | 445 | /* Always calculate checksum for icmp packets */ |
479 | outicmp->icmp_cksum = 0; | 446 | outicmp->icmp_cksum = 0; |
480 | outicmp->icmp_cksum = in_cksum((uint16_t *)outicmp, | 447 | outicmp->icmp_cksum = inet_cksum((uint16_t *)outicmp, |
481 | packlen - (sizeof(*outip) + optlen)); | 448 | packlen - (sizeof(*outip) + optlen)); |
482 | if (outicmp->icmp_cksum == 0) | 449 | if (outicmp->icmp_cksum == 0) |
483 | outicmp->icmp_cksum = 0xffff; | 450 | outicmp->icmp_cksum = 0xffff; |
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c index 70e34614c..2e6113627 100644 --- a/networking/udhcp/common.c +++ b/networking/udhcp/common.c | |||
@@ -36,6 +36,9 @@ const struct dhcp_optflag dhcp_optflags[] = { | |||
36 | { OPTION_STRING , 0x11 }, /* DHCP_ROOT_PATH */ | 36 | { OPTION_STRING , 0x11 }, /* DHCP_ROOT_PATH */ |
37 | { OPTION_U8 , 0x17 }, /* DHCP_IP_TTL */ | 37 | { OPTION_U8 , 0x17 }, /* DHCP_IP_TTL */ |
38 | { OPTION_U16 , 0x1a }, /* DHCP_MTU */ | 38 | { OPTION_U16 , 0x1a }, /* DHCP_MTU */ |
39 | //TODO: why do we request DHCP_BROADCAST? Can't we assume that | ||
40 | //in the unlikely case it is different from typical N.N.255.255, | ||
41 | //server would let us know anyway? | ||
39 | { OPTION_IP | OPTION_REQ, 0x1c }, /* DHCP_BROADCAST */ | 42 | { OPTION_IP | OPTION_REQ, 0x1c }, /* DHCP_BROADCAST */ |
40 | { OPTION_IP_PAIR | OPTION_LIST , 0x21 }, /* DHCP_ROUTES */ | 43 | { OPTION_IP_PAIR | OPTION_LIST , 0x21 }, /* DHCP_ROUTES */ |
41 | { OPTION_STRING , 0x28 }, /* DHCP_NIS_DOMAIN */ | 44 | { OPTION_STRING , 0x28 }, /* DHCP_NIS_DOMAIN */ |
@@ -59,6 +62,7 @@ const struct dhcp_optflag dhcp_optflags[] = { | |||
59 | { OPTION_U16 , 0x84 }, /* DHCP_VLAN_ID */ | 62 | { OPTION_U16 , 0x84 }, /* DHCP_VLAN_ID */ |
60 | { OPTION_U8 , 0x85 }, /* DHCP_VLAN_PRIORITY */ | 63 | { OPTION_U8 , 0x85 }, /* DHCP_VLAN_PRIORITY */ |
61 | #endif | 64 | #endif |
65 | { OPTION_6RD , 0xd4 }, /* DHCP_6RD */ | ||
62 | { OPTION_STATIC_ROUTES , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */ | 66 | { OPTION_STATIC_ROUTES , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */ |
63 | { OPTION_STRING , 0xfc }, /* DHCP_WPAD */ | 67 | { OPTION_STRING , 0xfc }, /* DHCP_WPAD */ |
64 | 68 | ||
@@ -126,6 +130,7 @@ const char dhcp_option_strings[] ALIGN1 = | |||
126 | "vlanid" "\0" /* DHCP_VLAN_ID */ | 130 | "vlanid" "\0" /* DHCP_VLAN_ID */ |
127 | "vlanpriority" "\0"/* DHCP_VLAN_PRIORITY */ | 131 | "vlanpriority" "\0"/* DHCP_VLAN_PRIORITY */ |
128 | #endif | 132 | #endif |
133 | "ip6rd" "\0" /* DHCP_6RD */ | ||
129 | "msstaticroutes""\0"/* DHCP_MS_STATIC_ROUTES */ | 134 | "msstaticroutes""\0"/* DHCP_MS_STATIC_ROUTES */ |
130 | "wpad" "\0" /* DHCP_WPAD */ | 135 | "wpad" "\0" /* DHCP_WPAD */ |
131 | ; | 136 | ; |
@@ -154,6 +159,7 @@ const uint8_t dhcp_option_lengths[] ALIGN1 = { | |||
154 | [OPTION_S32] = 4, | 159 | [OPTION_S32] = 4, |
155 | /* Just like OPTION_STRING, we use minimum length here */ | 160 | /* Just like OPTION_STRING, we use minimum length here */ |
156 | [OPTION_STATIC_ROUTES] = 5, | 161 | [OPTION_STATIC_ROUTES] = 5, |
162 | [OPTION_6RD] = 22, /* ignored by udhcp_str2optset */ | ||
157 | }; | 163 | }; |
158 | 164 | ||
159 | 165 | ||
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h index ad6991c94..a7f9395b8 100644 --- a/networking/udhcp/common.h +++ b/networking/udhcp/common.h | |||
@@ -88,6 +88,7 @@ enum { | |||
88 | OPTION_S32, | 88 | OPTION_S32, |
89 | OPTION_BIN, | 89 | OPTION_BIN, |
90 | OPTION_STATIC_ROUTES, | 90 | OPTION_STATIC_ROUTES, |
91 | OPTION_6RD, | ||
91 | #if ENABLE_FEATURE_UDHCP_RFC3397 | 92 | #if ENABLE_FEATURE_UDHCP_RFC3397 |
92 | OPTION_DNS_STRING, /* RFC1035 compressed domain name list */ | 93 | OPTION_DNS_STRING, /* RFC1035 compressed domain name list */ |
93 | OPTION_SIP_SERVERS, | 94 | OPTION_SIP_SERVERS, |
@@ -103,7 +104,7 @@ enum { | |||
103 | /* DHCP option codes (partial list). See RFC 2132 and | 104 | /* DHCP option codes (partial list). See RFC 2132 and |
104 | * http://www.iana.org/assignments/bootp-dhcp-parameters/ | 105 | * http://www.iana.org/assignments/bootp-dhcp-parameters/ |
105 | * Commented out options are handled by common option machinery, | 106 | * Commented out options are handled by common option machinery, |
106 | * uncommented ones have spacial cases (grep for them to see). | 107 | * uncommented ones have special cases (grep for them to see). |
107 | */ | 108 | */ |
108 | #define DHCP_PADDING 0x00 | 109 | #define DHCP_PADDING 0x00 |
109 | #define DHCP_SUBNET 0x01 | 110 | #define DHCP_SUBNET 0x01 |
@@ -248,6 +249,7 @@ struct option_set *udhcp_find_option(struct option_set *opt_list, uint8_t code) | |||
248 | /*** Logging ***/ | 249 | /*** Logging ***/ |
249 | 250 | ||
250 | #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 | 251 | #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 |
252 | # define IF_UDHCP_VERBOSE(...) __VA_ARGS__ | ||
251 | extern unsigned dhcp_verbose; | 253 | extern unsigned dhcp_verbose; |
252 | # define log1(...) do { if (dhcp_verbose >= 1) bb_info_msg(__VA_ARGS__); } while (0) | 254 | # define log1(...) do { if (dhcp_verbose >= 1) bb_info_msg(__VA_ARGS__); } while (0) |
253 | # if CONFIG_UDHCP_DEBUG >= 2 | 255 | # if CONFIG_UDHCP_DEBUG >= 2 |
@@ -263,6 +265,7 @@ void udhcp_dump_packet(struct dhcp_packet *packet) FAST_FUNC; | |||
263 | # define log3(...) ((void)0) | 265 | # define log3(...) ((void)0) |
264 | # endif | 266 | # endif |
265 | #else | 267 | #else |
268 | # define IF_UDHCP_VERBOSE(...) | ||
266 | # define udhcp_dump_packet(...) ((void)0) | 269 | # define udhcp_dump_packet(...) ((void)0) |
267 | # define log1(...) ((void)0) | 270 | # define log1(...) ((void)0) |
268 | # define log2(...) ((void)0) | 271 | # define log2(...) ((void)0) |
@@ -277,8 +280,6 @@ int FAST_FUNC udhcp_str2nip(const char *str, void *arg); | |||
277 | /* 2nd param is "struct option_set**" */ | 280 | /* 2nd param is "struct option_set**" */ |
278 | int FAST_FUNC udhcp_str2optset(const char *str, void *arg); | 281 | int FAST_FUNC udhcp_str2optset(const char *str, void *arg); |
279 | 282 | ||
280 | uint16_t udhcp_checksum(void *addr, int count) FAST_FUNC; | ||
281 | |||
282 | void udhcp_init_header(struct dhcp_packet *packet, char type) FAST_FUNC; | 283 | void udhcp_init_header(struct dhcp_packet *packet, char type) FAST_FUNC; |
283 | 284 | ||
284 | int udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) FAST_FUNC; | 285 | int udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) FAST_FUNC; |
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 4d755e6b8..3d4c397ff 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c | |||
@@ -100,6 +100,7 @@ static const uint8_t len_of_option_as_string[] = { | |||
100 | [OPTION_IP ] = sizeof("255.255.255.255 "), | 100 | [OPTION_IP ] = sizeof("255.255.255.255 "), |
101 | [OPTION_IP_PAIR ] = sizeof("255.255.255.255 ") * 2, | 101 | [OPTION_IP_PAIR ] = sizeof("255.255.255.255 ") * 2, |
102 | [OPTION_STATIC_ROUTES ] = sizeof("255.255.255.255/32 255.255.255.255 "), | 102 | [OPTION_STATIC_ROUTES ] = sizeof("255.255.255.255/32 255.255.255.255 "), |
103 | [OPTION_6RD ] = sizeof("32 128 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 255.255.255.255 "), | ||
103 | [OPTION_STRING ] = 1, | 104 | [OPTION_STRING ] = 1, |
104 | #if ENABLE_FEATURE_UDHCP_RFC3397 | 105 | #if ENABLE_FEATURE_UDHCP_RFC3397 |
105 | [OPTION_DNS_STRING ] = 1, /* unused */ | 106 | [OPTION_DNS_STRING ] = 1, /* unused */ |
@@ -123,6 +124,24 @@ static int sprint_nip(char *dest, const char *pre, const uint8_t *ip) | |||
123 | return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]); | 124 | return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]); |
124 | } | 125 | } |
125 | 126 | ||
127 | static int sprint_nip6(char *dest, /*const char *pre,*/ const uint8_t *ip) | ||
128 | { | ||
129 | char hexstrbuf[16 * 2]; | ||
130 | bin2hex(hexstrbuf, (void*)ip, 16); | ||
131 | return sprintf(dest, /* "%s" */ | ||
132 | "%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s", | ||
133 | /* pre, */ | ||
134 | hexstrbuf + 0 * 4, | ||
135 | hexstrbuf + 1 * 4, | ||
136 | hexstrbuf + 2 * 4, | ||
137 | hexstrbuf + 3 * 4, | ||
138 | hexstrbuf + 4 * 4, | ||
139 | hexstrbuf + 5 * 4, | ||
140 | hexstrbuf + 6 * 4, | ||
141 | hexstrbuf + 7 * 4 | ||
142 | ); | ||
143 | } | ||
144 | |||
126 | /* really simple implementation, just count the bits */ | 145 | /* really simple implementation, just count the bits */ |
127 | static int mton(uint32_t mask) | 146 | static int mton(uint32_t mask) |
128 | { | 147 | { |
@@ -142,27 +161,25 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ | |||
142 | int len, type, optlen; | 161 | int len, type, optlen; |
143 | char *dest, *ret; | 162 | char *dest, *ret; |
144 | 163 | ||
145 | /* option points to OPT_DATA, need to go back and get OPT_LEN */ | 164 | /* option points to OPT_DATA, need to go back to get OPT_LEN */ |
146 | len = option[OPT_LEN - OPT_DATA]; | 165 | len = option[-OPT_DATA + OPT_LEN]; |
147 | 166 | ||
148 | type = optflag->flags & OPTION_TYPE_MASK; | 167 | type = optflag->flags & OPTION_TYPE_MASK; |
149 | optlen = dhcp_option_lengths[type]; | 168 | optlen = dhcp_option_lengths[type]; |
150 | upper_length = len_of_option_as_string[type] * ((unsigned)len / (unsigned)optlen); | 169 | upper_length = len_of_option_as_string[type] |
170 | * ((unsigned)(len + optlen - 1) / (unsigned)optlen); | ||
151 | 171 | ||
152 | dest = ret = xmalloc(upper_length + strlen(opt_name) + 2); | 172 | dest = ret = xmalloc(upper_length + strlen(opt_name) + 2); |
153 | dest += sprintf(ret, "%s=", opt_name); | 173 | dest += sprintf(ret, "%s=", opt_name); |
154 | 174 | ||
155 | while (len >= optlen) { | 175 | while (len >= optlen) { |
156 | unsigned ip_ofs = 0; | ||
157 | |||
158 | switch (type) { | 176 | switch (type) { |
177 | case OPTION_IP: | ||
159 | case OPTION_IP_PAIR: | 178 | case OPTION_IP_PAIR: |
160 | dest += sprint_nip(dest, "", option); | 179 | dest += sprint_nip(dest, "", option); |
161 | *dest++ = '/'; | 180 | if (type == OPTION_IP) |
162 | ip_ofs = 4; | 181 | break; |
163 | /* fall through */ | 182 | dest += sprint_nip(dest, "/", option + 4); |
164 | case OPTION_IP: | ||
165 | dest += sprint_nip(dest, "", option + ip_ofs); | ||
166 | break; | 183 | break; |
167 | // case OPTION_BOOLEAN: | 184 | // case OPTION_BOOLEAN: |
168 | // dest += sprintf(dest, *option ? "yes" : "no"); | 185 | // dest += sprintf(dest, *option ? "yes" : "no"); |
@@ -184,10 +201,14 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ | |||
184 | dest += sprintf(dest, type == OPTION_U32 ? "%lu" : "%ld", (unsigned long) ntohl(val_u32)); | 201 | dest += sprintf(dest, type == OPTION_U32 ? "%lu" : "%ld", (unsigned long) ntohl(val_u32)); |
185 | break; | 202 | break; |
186 | } | 203 | } |
204 | /* Note: options which use 'return' instead of 'break' | ||
205 | * (for example, OPTION_STRING) skip the code which handles | ||
206 | * the case of list of options. | ||
207 | */ | ||
187 | case OPTION_STRING: | 208 | case OPTION_STRING: |
188 | memcpy(dest, option, len); | 209 | memcpy(dest, option, len); |
189 | dest[len] = '\0'; | 210 | dest[len] = '\0'; |
190 | return ret; /* Short circuit this case */ | 211 | return ret; |
191 | case OPTION_STATIC_ROUTES: { | 212 | case OPTION_STATIC_ROUTES: { |
192 | /* Option binary format: | 213 | /* Option binary format: |
193 | * mask [one byte, 0..32] | 214 | * mask [one byte, 0..32] |
@@ -232,6 +253,53 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ | |||
232 | 253 | ||
233 | return ret; | 254 | return ret; |
234 | } | 255 | } |
256 | case OPTION_6RD: | ||
257 | /* Option binary format (see RFC 5969): | ||
258 | * 0 1 2 3 | ||
259 | * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | ||
260 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
261 | * | OPTION_6RD | option-length | IPv4MaskLen | 6rdPrefixLen | | ||
262 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
263 | * | 6rdPrefix | | ||
264 | * ... (16 octets) ... | ||
265 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
266 | * ... 6rdBRIPv4Address(es) ... | ||
267 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
268 | * We convert it to a string | ||
269 | * "IPv4MaskLen 6rdPrefixLen 6rdPrefix 6rdBRIPv4Address..." | ||
270 | * | ||
271 | * Sanity check: ensure that our length is at least 22 bytes, that | ||
272 | * IPv4MaskLen <= 32, | ||
273 | * 6rdPrefixLen <= 128, | ||
274 | * 6rdPrefixLen + (32 - IPv4MaskLen) <= 128 | ||
275 | * (2nd condition need no check - it follows from 1st and 3rd). | ||
276 | * Else, return envvar with empty value ("optname=") | ||
277 | */ | ||
278 | if (len >= (1 + 1 + 16 + 4) | ||
279 | && option[0] <= 32 | ||
280 | && (option[1] + 32 - option[0]) <= 128 | ||
281 | ) { | ||
282 | /* IPv4MaskLen */ | ||
283 | dest += sprintf(dest, "%u ", *option++); | ||
284 | /* 6rdPrefixLen */ | ||
285 | dest += sprintf(dest, "%u ", *option++); | ||
286 | /* 6rdPrefix */ | ||
287 | dest += sprint_nip6(dest, /* "", */ option); | ||
288 | option += 16; | ||
289 | len -= 1 + 1 + 16 + 4; | ||
290 | /* "+ 4" above corresponds to the length of IPv4 addr | ||
291 | * we consume in the loop below */ | ||
292 | while (1) { | ||
293 | /* 6rdBRIPv4Address(es) */ | ||
294 | dest += sprint_nip(dest, " ", option); | ||
295 | option += 4; | ||
296 | len -= 4; /* do we have yet another 4+ bytes? */ | ||
297 | if (len < 0) | ||
298 | break; /* no */ | ||
299 | } | ||
300 | } | ||
301 | |||
302 | return ret; | ||
235 | #if ENABLE_FEATURE_UDHCP_RFC3397 | 303 | #if ENABLE_FEATURE_UDHCP_RFC3397 |
236 | case OPTION_DNS_STRING: | 304 | case OPTION_DNS_STRING: |
237 | /* unpack option into dest; use ret for prefix (i.e., "optname=") */ | 305 | /* unpack option into dest; use ret for prefix (i.e., "optname=") */ |
@@ -271,16 +339,21 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ | |||
271 | return ret; | 339 | return ret; |
272 | #endif | 340 | #endif |
273 | } /* switch */ | 341 | } /* switch */ |
342 | |||
343 | /* If we are here, try to format any remaining data | ||
344 | * in the option as another, similarly-formatted option | ||
345 | */ | ||
274 | option += optlen; | 346 | option += optlen; |
275 | len -= optlen; | 347 | len -= optlen; |
276 | // TODO: it can be a list only if (optflag->flags & OPTION_LIST). | 348 | // TODO: it can be a list only if (optflag->flags & OPTION_LIST). |
277 | // Should we bail out/warn if we see multi-ip option which is | 349 | // Should we bail out/warn if we see multi-ip option which is |
278 | // not allowed to be such (for example, DHCP_BROADCAST)? - | 350 | // not allowed to be such (for example, DHCP_BROADCAST)? - |
279 | if (len <= 0 /* || !(optflag->flags & OPTION_LIST) */) | 351 | if (len < optlen /* || !(optflag->flags & OPTION_LIST) */) |
280 | break; | 352 | break; |
281 | *dest++ = ' '; | 353 | *dest++ = ' '; |
282 | *dest = '\0'; | 354 | *dest = '\0'; |
283 | } | 355 | } /* while */ |
356 | |||
284 | return ret; | 357 | return ret; |
285 | } | 358 | } |
286 | 359 | ||
@@ -320,7 +393,7 @@ static char **fill_envp(struct dhcp_packet *packet) | |||
320 | if (i == DHCP_OPTION_OVERLOAD) | 393 | if (i == DHCP_OPTION_OVERLOAD) |
321 | overload = *temp; | 394 | overload = *temp; |
322 | else if (i == DHCP_SUBNET) | 395 | else if (i == DHCP_SUBNET) |
323 | envc++; /* for mton */ | 396 | envc++; /* for $mask */ |
324 | envc++; | 397 | envc++; |
325 | /*if (i != DHCP_MESSAGE_TYPE)*/ | 398 | /*if (i != DHCP_MESSAGE_TYPE)*/ |
326 | FOUND_OPTS(i) |= BMASK(i); | 399 | FOUND_OPTS(i) |= BMASK(i); |
@@ -335,10 +408,42 @@ static char **fill_envp(struct dhcp_packet *packet) | |||
335 | if (!packet) | 408 | if (!packet) |
336 | return envp; | 409 | return envp; |
337 | 410 | ||
411 | /* Export BOOTP fields. Fields we don't (yet?) export: | ||
412 | * uint8_t op; // always BOOTREPLY | ||
413 | * uint8_t htype; // hardware address type. 1 = 10mb ethernet | ||
414 | * uint8_t hlen; // hardware address length | ||
415 | * uint8_t hops; // used by relay agents only | ||
416 | * uint32_t xid; | ||
417 | * uint16_t secs; // elapsed since client began acquisition/renewal | ||
418 | * uint16_t flags; // only one flag so far: bcast. Never set by server | ||
419 | * uint32_t ciaddr; // client IP (usually == yiaddr. can it be different | ||
420 | * // if during renew server wants to give us differn IP?) | ||
421 | * uint32_t gateway_nip; // relay agent IP address | ||
422 | * uint8_t chaddr[16]; // link-layer client hardware address (MAC) | ||
423 | * TODO: export gateway_nip as $giaddr? | ||
424 | */ | ||
425 | /* Most important one: yiaddr as $ip */ | ||
338 | *curr = xmalloc(sizeof("ip=255.255.255.255")); | 426 | *curr = xmalloc(sizeof("ip=255.255.255.255")); |
339 | sprint_nip(*curr, "ip=", (uint8_t *) &packet->yiaddr); | 427 | sprint_nip(*curr, "ip=", (uint8_t *) &packet->yiaddr); |
340 | putenv(*curr++); | 428 | putenv(*curr++); |
429 | if (packet->siaddr_nip) { | ||
430 | /* IP address of next server to use in bootstrap */ | ||
431 | *curr = xmalloc(sizeof("siaddr=255.255.255.255")); | ||
432 | sprint_nip(*curr, "siaddr=", (uint8_t *) &packet->siaddr_nip); | ||
433 | putenv(*curr++); | ||
434 | } | ||
435 | if (!(overload & FILE_FIELD) && packet->file[0]) { | ||
436 | /* watch out for invalid packets */ | ||
437 | *curr = xasprintf("boot_file=%."DHCP_PKT_FILE_LEN_STR"s", packet->file); | ||
438 | putenv(*curr++); | ||
439 | } | ||
440 | if (!(overload & SNAME_FIELD) && packet->sname[0]) { | ||
441 | /* watch out for invalid packets */ | ||
442 | *curr = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname); | ||
443 | putenv(*curr++); | ||
444 | } | ||
341 | 445 | ||
446 | /* Export known DHCP options */ | ||
342 | opt_name = dhcp_option_strings; | 447 | opt_name = dhcp_option_strings; |
343 | i = 0; | 448 | i = 0; |
344 | while (*opt_name) { | 449 | while (*opt_name) { |
@@ -355,29 +460,14 @@ static char **fill_envp(struct dhcp_packet *packet) | |||
355 | /* Subnet option: make things like "$ip/$mask" possible */ | 460 | /* Subnet option: make things like "$ip/$mask" possible */ |
356 | uint32_t subnet; | 461 | uint32_t subnet; |
357 | move_from_unaligned32(subnet, temp); | 462 | move_from_unaligned32(subnet, temp); |
358 | *curr = xasprintf("mask=%d", mton(subnet)); | 463 | *curr = xasprintf("mask=%u", mton(subnet)); |
359 | putenv(*curr++); | 464 | putenv(*curr++); |
360 | } | 465 | } |
361 | next: | 466 | next: |
362 | opt_name += strlen(opt_name) + 1; | 467 | opt_name += strlen(opt_name) + 1; |
363 | i++; | 468 | i++; |
364 | } | 469 | } |
365 | if (packet->siaddr_nip) { | 470 | /* Export unknown options */ |
366 | *curr = xmalloc(sizeof("siaddr=255.255.255.255")); | ||
367 | sprint_nip(*curr, "siaddr=", (uint8_t *) &packet->siaddr_nip); | ||
368 | putenv(*curr++); | ||
369 | } | ||
370 | if (!(overload & FILE_FIELD) && packet->file[0]) { | ||
371 | /* watch out for invalid packets */ | ||
372 | *curr = xasprintf("boot_file=%."DHCP_PKT_FILE_LEN_STR"s", packet->file); | ||
373 | putenv(*curr++); | ||
374 | } | ||
375 | if (!(overload & SNAME_FIELD) && packet->sname[0]) { | ||
376 | /* watch out for invalid packets */ | ||
377 | *curr = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname); | ||
378 | putenv(*curr++); | ||
379 | } | ||
380 | /* Handle unknown options */ | ||
381 | for (i = 0; i < 256;) { | 471 | for (i = 0; i < 256;) { |
382 | BITMAP bitmap = FOUND_OPTS(i); | 472 | BITMAP bitmap = FOUND_OPTS(i); |
383 | if (!bitmap) { | 473 | if (!bitmap) { |
@@ -394,11 +484,12 @@ static char **fill_envp(struct dhcp_packet *packet) | |||
394 | len = temp[-OPT_DATA + OPT_LEN]; | 484 | len = temp[-OPT_DATA + OPT_LEN]; |
395 | *curr = xmalloc(sizeof("optNNN=") + 1 + len*2); | 485 | *curr = xmalloc(sizeof("optNNN=") + 1 + len*2); |
396 | ofs = sprintf(*curr, "opt%u=", i); | 486 | ofs = sprintf(*curr, "opt%u=", i); |
397 | bin2hex(*curr + ofs, (void*) temp, len)[0] = '\0'; | 487 | *bin2hex(*curr + ofs, (void*) temp, len) = '\0'; |
398 | putenv(*curr++); | 488 | putenv(*curr++); |
399 | } | 489 | } |
400 | i++; | 490 | i++; |
401 | } | 491 | } |
492 | |||
402 | return envp; | 493 | return envp; |
403 | } | 494 | } |
404 | 495 | ||
@@ -726,7 +817,8 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) | |||
726 | bytes = ntohs(packet.ip.tot_len); | 817 | bytes = ntohs(packet.ip.tot_len); |
727 | 818 | ||
728 | /* make sure its the right packet for us, and that it passes sanity checks */ | 819 | /* make sure its the right packet for us, and that it passes sanity checks */ |
729 | if (packet.ip.protocol != IPPROTO_UDP || packet.ip.version != IPVERSION | 820 | if (packet.ip.protocol != IPPROTO_UDP |
821 | || packet.ip.version != IPVERSION | ||
730 | || packet.ip.ihl != (sizeof(packet.ip) >> 2) | 822 | || packet.ip.ihl != (sizeof(packet.ip) >> 2) |
731 | || packet.udp.dest != htons(CLIENT_PORT) | 823 | || packet.udp.dest != htons(CLIENT_PORT) |
732 | /* || bytes > (int) sizeof(packet) - can't happen */ | 824 | /* || bytes > (int) sizeof(packet) - can't happen */ |
@@ -739,7 +831,7 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) | |||
739 | /* verify IP checksum */ | 831 | /* verify IP checksum */ |
740 | check = packet.ip.check; | 832 | check = packet.ip.check; |
741 | packet.ip.check = 0; | 833 | packet.ip.check = 0; |
742 | if (check != udhcp_checksum(&packet.ip, sizeof(packet.ip))) { | 834 | if (check != inet_cksum((uint16_t *)&packet.ip, sizeof(packet.ip))) { |
743 | log1("Bad IP header checksum, ignoring"); | 835 | log1("Bad IP header checksum, ignoring"); |
744 | return -2; | 836 | return -2; |
745 | } | 837 | } |
@@ -750,20 +842,22 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) | |||
750 | packet.ip.tot_len = packet.udp.len; /* yes, this is needed */ | 842 | packet.ip.tot_len = packet.udp.len; /* yes, this is needed */ |
751 | check = packet.udp.check; | 843 | check = packet.udp.check; |
752 | packet.udp.check = 0; | 844 | packet.udp.check = 0; |
753 | if (check && check != udhcp_checksum(&packet, bytes)) { | 845 | if (check && check != inet_cksum((uint16_t *)&packet, bytes)) { |
754 | log1("Packet with bad UDP checksum received, ignoring"); | 846 | log1("Packet with bad UDP checksum received, ignoring"); |
755 | return -2; | 847 | return -2; |
756 | } | 848 | } |
757 | 849 | ||
758 | memcpy(dhcp_pkt, &packet.data, bytes - (sizeof(packet.ip) + sizeof(packet.udp))); | 850 | if (packet.data.cookie != htonl(DHCP_MAGIC)) { |
759 | |||
760 | if (dhcp_pkt->cookie != htonl(DHCP_MAGIC)) { | ||
761 | bb_info_msg("Packet with bad magic, ignoring"); | 851 | bb_info_msg("Packet with bad magic, ignoring"); |
762 | return -2; | 852 | return -2; |
763 | } | 853 | } |
854 | |||
764 | log1("Got valid DHCP packet"); | 855 | log1("Got valid DHCP packet"); |
765 | udhcp_dump_packet(dhcp_pkt); | 856 | udhcp_dump_packet(&packet.data); |
766 | return bytes - (sizeof(packet.ip) + sizeof(packet.udp)); | 857 | |
858 | bytes -= sizeof(packet.ip) + sizeof(packet.udp); | ||
859 | memcpy(dhcp_pkt, &packet.data, bytes); | ||
860 | return bytes; | ||
767 | } | 861 | } |
768 | 862 | ||
769 | 863 | ||
@@ -1077,11 +1171,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1077 | 1171 | ||
1078 | /* Parse command line */ | 1172 | /* Parse command line */ |
1079 | /* O,x: list; -T,-t,-A take numeric param */ | 1173 | /* O,x: list; -T,-t,-A take numeric param */ |
1080 | opt_complementary = "O::x::T+:t+:A+" | 1174 | opt_complementary = "O::x::T+:t+:A+" IF_UDHCP_VERBOSE(":vv") ; |
1081 | #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 | ||
1082 | ":vv" | ||
1083 | #endif | ||
1084 | ; | ||
1085 | IF_LONG_OPTS(applet_long_options = udhcpc_longopts;) | 1175 | IF_LONG_OPTS(applet_long_options = udhcpc_longopts;) |
1086 | opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:fB" | 1176 | opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:fB" |
1087 | USE_FOR_MMU("b") | 1177 | USE_FOR_MMU("b") |
@@ -1095,9 +1185,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1095 | , &list_O | 1185 | , &list_O |
1096 | , &list_x | 1186 | , &list_x |
1097 | IF_FEATURE_UDHCP_PORT(, &str_P) | 1187 | IF_FEATURE_UDHCP_PORT(, &str_P) |
1098 | #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 | 1188 | IF_UDHCP_VERBOSE(, &dhcp_verbose) |
1099 | , &dhcp_verbose | ||
1100 | #endif | ||
1101 | ); | 1189 | ); |
1102 | if (opt & (OPT_h|OPT_H)) | 1190 | if (opt & (OPT_h|OPT_H)) |
1103 | client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0); | 1191 | client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0); |
@@ -1361,9 +1449,23 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1361 | switch (udhcp_sp_read(&rfds)) { | 1449 | switch (udhcp_sp_read(&rfds)) { |
1362 | case SIGUSR1: | 1450 | case SIGUSR1: |
1363 | client_config.first_secs = 0; /* make secs field count from 0 */ | 1451 | client_config.first_secs = 0; /* make secs field count from 0 */ |
1452 | already_waited_sec = 0; | ||
1364 | perform_renew(); | 1453 | perform_renew(); |
1365 | if (state == RENEW_REQUESTED) | 1454 | if (state == RENEW_REQUESTED) { |
1455 | /* We might be either on the same network | ||
1456 | * (in which case renew might work), | ||
1457 | * or we might be on a completely different one | ||
1458 | * (in which case renew won't ever succeed). | ||
1459 | * For the second case, must make sure timeout | ||
1460 | * is not too big, or else we can send | ||
1461 | * futile renew requests for hours. | ||
1462 | * (Ab)use -A TIMEOUT value (usually 20 sec) | ||
1463 | * as a cap on the timeout. | ||
1464 | */ | ||
1465 | if (timeout > tryagain_timeout) | ||
1466 | timeout = tryagain_timeout; | ||
1366 | goto case_RENEW_REQUESTED; | 1467 | goto case_RENEW_REQUESTED; |
1468 | } | ||
1367 | /* Start things over */ | 1469 | /* Start things over */ |
1368 | packet_num = 0; | 1470 | packet_num = 0; |
1369 | /* Kill any timeouts, user wants this to hurry along */ | 1471 | /* Kill any timeouts, user wants this to hurry along */ |
@@ -1431,7 +1533,25 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1431 | case INIT_SELECTING: | 1533 | case INIT_SELECTING: |
1432 | /* Must be a DHCPOFFER to one of our xid's */ | 1534 | /* Must be a DHCPOFFER to one of our xid's */ |
1433 | if (*message == DHCPOFFER) { | 1535 | if (*message == DHCPOFFER) { |
1434 | /* TODO: why we don't just fetch server's IP from IP header? */ | 1536 | /* What exactly is server's IP? There are several values. |
1537 | * Example DHCP offer captured with tchdump: | ||
1538 | * | ||
1539 | * 10.34.25.254:67 > 10.34.25.202:68 // IP header's src | ||
1540 | * BOOTP fields: | ||
1541 | * Your-IP 10.34.25.202 | ||
1542 | * Server-IP 10.34.32.125 // "next server" IP | ||
1543 | * Gateway-IP 10.34.25.254 // relay's address (if DHCP relays are in use) | ||
1544 | * DHCP options: | ||
1545 | * DHCP-Message Option 53, length 1: Offer | ||
1546 | * Server-ID Option 54, length 4: 10.34.255.7 // "server ID" | ||
1547 | * Default-Gateway Option 3, length 4: 10.34.25.254 // router | ||
1548 | * | ||
1549 | * We think that real server IP (one to use in renew/release) | ||
1550 | * is one in Server-ID option. But I am not 100% sure. | ||
1551 | * IP header's src and Gateway-IP (same in this example) | ||
1552 | * might work too. | ||
1553 | * "Next server" and router are definitely wrong ones to use, though... | ||
1554 | */ | ||
1435 | temp = udhcp_get_option(&packet, DHCP_SERVER_ID); | 1555 | temp = udhcp_get_option(&packet, DHCP_SERVER_ID); |
1436 | if (!temp) { | 1556 | if (!temp) { |
1437 | bb_error_msg("no server ID, ignoring packet"); | 1557 | bb_error_msg("no server ID, ignoring packet"); |
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index 747472d0c..dd55e70f4 100644 --- a/networking/udhcp/dhcpd.c +++ b/networking/udhcp/dhcpd.c | |||
@@ -314,9 +314,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) | |||
314 | #endif | 314 | #endif |
315 | opt = getopt32(argv, "fSv" | 315 | opt = getopt32(argv, "fSv" |
316 | IF_FEATURE_UDHCP_PORT("P:", &str_P) | 316 | IF_FEATURE_UDHCP_PORT("P:", &str_P) |
317 | #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 | 317 | IF_UDHCP_VERBOSE(, &dhcp_verbose) |
318 | , &dhcp_verbose | ||
319 | #endif | ||
320 | ); | 318 | ); |
321 | if (!(opt & 1)) { /* no -f */ | 319 | if (!(opt & 1)) { /* no -f */ |
322 | bb_daemonize_or_rexec(0, argv); | 320 | bb_daemonize_or_rexec(0, argv); |
diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c index 66b42c5e1..4d5ff0676 100644 --- a/networking/udhcp/packet.c +++ b/networking/udhcp/packet.c | |||
@@ -129,35 +129,6 @@ int FAST_FUNC udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) | |||
129 | return bytes; | 129 | return bytes; |
130 | } | 130 | } |
131 | 131 | ||
132 | uint16_t FAST_FUNC udhcp_checksum(void *addr, int count) | ||
133 | { | ||
134 | /* Compute Internet Checksum for "count" bytes | ||
135 | * beginning at location "addr". | ||
136 | */ | ||
137 | int32_t sum = 0; | ||
138 | uint16_t *source = (uint16_t *) addr; | ||
139 | |||
140 | while (count > 1) { | ||
141 | /* This is the inner loop */ | ||
142 | sum += *source++; | ||
143 | count -= 2; | ||
144 | } | ||
145 | |||
146 | /* Add left-over byte, if any */ | ||
147 | if (count > 0) { | ||
148 | /* Make sure that the left-over byte is added correctly both | ||
149 | * with little and big endian hosts */ | ||
150 | uint16_t tmp = 0; | ||
151 | *(uint8_t*)&tmp = *(uint8_t*)source; | ||
152 | sum += tmp; | ||
153 | } | ||
154 | /* Fold 32-bit sum to 16 bits */ | ||
155 | while (sum >> 16) | ||
156 | sum = (sum & 0xffff) + (sum >> 16); | ||
157 | |||
158 | return ~sum; | ||
159 | } | ||
160 | |||
161 | /* Construct a ip/udp header for a packet, send packet */ | 132 | /* Construct a ip/udp header for a packet, send packet */ |
162 | int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, | 133 | int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, |
163 | uint32_t source_nip, int source_port, | 134 | uint32_t source_nip, int source_port, |
@@ -212,13 +183,14 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, | |||
212 | packet.udp.len = htons(UDP_DHCP_SIZE - padding); | 183 | packet.udp.len = htons(UDP_DHCP_SIZE - padding); |
213 | /* for UDP checksumming, ip.len is set to UDP packet len */ | 184 | /* for UDP checksumming, ip.len is set to UDP packet len */ |
214 | packet.ip.tot_len = packet.udp.len; | 185 | packet.ip.tot_len = packet.udp.len; |
215 | packet.udp.check = udhcp_checksum(&packet, IP_UDP_DHCP_SIZE - padding); | 186 | packet.udp.check = inet_cksum((uint16_t *)&packet, |
187 | IP_UDP_DHCP_SIZE - padding); | ||
216 | /* but for sending, it is set to IP packet len */ | 188 | /* but for sending, it is set to IP packet len */ |
217 | packet.ip.tot_len = htons(IP_UDP_DHCP_SIZE - padding); | 189 | packet.ip.tot_len = htons(IP_UDP_DHCP_SIZE - padding); |
218 | packet.ip.ihl = sizeof(packet.ip) >> 2; | 190 | packet.ip.ihl = sizeof(packet.ip) >> 2; |
219 | packet.ip.version = IPVERSION; | 191 | packet.ip.version = IPVERSION; |
220 | packet.ip.ttl = IPDEFTTL; | 192 | packet.ip.ttl = IPDEFTTL; |
221 | packet.ip.check = udhcp_checksum(&packet.ip, sizeof(packet.ip)); | 193 | packet.ip.check = inet_cksum((uint16_t *)&packet.ip, sizeof(packet.ip)); |
222 | 194 | ||
223 | udhcp_dump_packet(dhcp_pkt); | 195 | udhcp_dump_packet(dhcp_pkt); |
224 | result = sendto(fd, &packet, IP_UDP_DHCP_SIZE - padding, /*flags:*/ 0, | 196 | result = sendto(fd, &packet, IP_UDP_DHCP_SIZE - padding, /*flags:*/ 0, |
diff --git a/networking/wget.c b/networking/wget.c index eca673a86..4dd42de9d 100644 --- a/networking/wget.c +++ b/networking/wget.c | |||
@@ -298,8 +298,13 @@ static void parse_url(const char *src_url, struct host_info *h) | |||
298 | 298 | ||
299 | sp = strrchr(h->host, '@'); | 299 | sp = strrchr(h->host, '@'); |
300 | if (sp != NULL) { | 300 | if (sp != NULL) { |
301 | h->user = h->host; | 301 | // URL-decode "user:password" string before base64-encoding: |
302 | // wget http://test:my%20pass@example.com should send | ||
303 | // Authorization: Basic dGVzdDpteSBwYXNz | ||
304 | // which decodes to "test:my pass". | ||
305 | // Standard wget and curl do this too. | ||
302 | *sp = '\0'; | 306 | *sp = '\0'; |
307 | h->user = percent_decode_in_place(h->host, /*strict:*/ 0); | ||
303 | h->host = sp + 1; | 308 | h->host = sp + 1; |
304 | } | 309 | } |
305 | 310 | ||
@@ -660,12 +665,6 @@ static void download_one_url(const char *url) | |||
660 | 665 | ||
661 | #if ENABLE_FEATURE_WGET_AUTHENTICATION | 666 | #if ENABLE_FEATURE_WGET_AUTHENTICATION |
662 | if (target.user) { | 667 | if (target.user) { |
663 | //TODO: URL-decode "user:password" string before base64-encoding: | ||
664 | //wget http://test:my%20pass@example.com should send | ||
665 | // Authorization: Basic dGVzdDpteSBwYXNz | ||
666 | //which decodes to "test:my pass", instead of what we send now: | ||
667 | // Authorization: Basic dGVzdDpteSUyMHBhc3M= | ||
668 | //Can reuse decodeString() from httpd.c | ||
669 | fprintf(sfp, "Proxy-Authorization: Basic %s\r\n"+6, | 668 | fprintf(sfp, "Proxy-Authorization: Basic %s\r\n"+6, |
670 | base64enc(target.user)); | 669 | base64enc(target.user)); |
671 | } | 670 | } |
diff --git a/networking/zcip.c b/networking/zcip.c index 8a35eca5d..7314ff8db 100644 --- a/networking/zcip.c +++ b/networking/zcip.c | |||
@@ -91,6 +91,7 @@ struct globals { | |||
91 | #define G (*(struct globals*)&bb_common_bufsiz1) | 91 | #define G (*(struct globals*)&bb_common_bufsiz1) |
92 | #define saddr (G.saddr ) | 92 | #define saddr (G.saddr ) |
93 | #define eth_addr (G.eth_addr) | 93 | #define eth_addr (G.eth_addr) |
94 | #define INIT_G() do { } while (0) | ||
94 | 95 | ||
95 | 96 | ||
96 | /** | 97 | /** |
@@ -223,6 +224,7 @@ int zcip_main(int argc UNUSED_PARAM, char **argv) | |||
223 | #define verbose (L.verbose ) | 224 | #define verbose (L.verbose ) |
224 | 225 | ||
225 | memset(&L, 0, sizeof(L)); | 226 | memset(&L, 0, sizeof(L)); |
227 | INIT_G(); | ||
226 | 228 | ||
227 | #define FOREGROUND (opts & 1) | 229 | #define FOREGROUND (opts & 1) |
228 | #define QUIT (opts & 2) | 230 | #define QUIT (opts & 2) |