diff options
Diffstat (limited to 'networking')
-rw-r--r-- | networking/hostname.c | 4 | ||||
-rw-r--r-- | networking/httpd.c | 2 | ||||
-rw-r--r-- | networking/libiproute/iproute.c | 16 | ||||
-rw-r--r-- | networking/ntpd.c | 6 | ||||
-rw-r--r-- | networking/telnetd.c | 4 | ||||
-rw-r--r-- | networking/tftp.c | 2 | ||||
-rw-r--r-- | networking/tls.c | 200 | ||||
-rw-r--r-- | networking/tls.h | 5 | ||||
-rw-r--r-- | networking/tls_aesgcm.c | 5 | ||||
-rw-r--r-- | networking/udhcp/d6_dhcpc.c | 193 | ||||
-rw-r--r-- | networking/udhcp/d6_packet.c | 16 | ||||
-rw-r--r-- | networking/udhcp/dhcpd.c | 58 |
12 files changed, 236 insertions, 275 deletions
diff --git a/networking/hostname.c b/networking/hostname.c index 36cb70866..101b89e77 100644 --- a/networking/hostname.c +++ b/networking/hostname.c | |||
@@ -25,8 +25,8 @@ | |||
25 | //applet:IF_DNSDOMAINNAME(APPLET_NOEXEC(dnsdomainname, hostname, BB_DIR_BIN, BB_SUID_DROP, dnsdomainname)) | 25 | //applet:IF_DNSDOMAINNAME(APPLET_NOEXEC(dnsdomainname, hostname, BB_DIR_BIN, BB_SUID_DROP, dnsdomainname)) |
26 | //applet:IF_HOSTNAME( APPLET_NOEXEC(hostname, hostname, BB_DIR_BIN, BB_SUID_DROP, hostname )) | 26 | //applet:IF_HOSTNAME( APPLET_NOEXEC(hostname, hostname, BB_DIR_BIN, BB_SUID_DROP, hostname )) |
27 | 27 | ||
28 | //kbuild: lib-$(CONFIG_HOSTNAME) += hostname.o | 28 | //kbuild:lib-$(CONFIG_HOSTNAME) += hostname.o |
29 | //kbuild: lib-$(CONFIG_DNSDOMAINNAME) += hostname.o | 29 | //kbuild:lib-$(CONFIG_DNSDOMAINNAME) += hostname.o |
30 | 30 | ||
31 | //usage:#define hostname_trivial_usage | 31 | //usage:#define hostname_trivial_usage |
32 | //usage: "[-sidf] [HOSTNAME | -F FILE]" | 32 | //usage: "[-sidf] [HOSTNAME | -F FILE]" |
diff --git a/networking/httpd.c b/networking/httpd.c index ddcb03bca..e1a447fa1 100644 --- a/networking/httpd.c +++ b/networking/httpd.c | |||
@@ -2826,7 +2826,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) | |||
2826 | salt[0] = '$'; | 2826 | salt[0] = '$'; |
2827 | salt[1] = '1'; | 2827 | salt[1] = '1'; |
2828 | salt[2] = '$'; | 2828 | salt[2] = '$'; |
2829 | crypt_make_salt(salt + 3, 4); | 2829 | crypt_make_rand64encoded(salt + 3, 8 / 2); /* 8 chars */ |
2830 | puts(pw_encrypt(pass, salt, /*cleanup:*/ 0)); | 2830 | puts(pw_encrypt(pass, salt, /*cleanup:*/ 0)); |
2831 | return 0; | 2831 | return 0; |
2832 | } | 2832 | } |
diff --git a/networking/libiproute/iproute.c b/networking/libiproute/iproute.c index cd77f642f..a30f070eb 100644 --- a/networking/libiproute/iproute.c +++ b/networking/libiproute/iproute.c | |||
@@ -302,24 +302,22 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, | |||
302 | printf("notify "); | 302 | printf("notify "); |
303 | } | 303 | } |
304 | 304 | ||
305 | if (r->rtm_family == AF_INET6) { | 305 | if (r->rtm_family == AF_INET || r->rtm_family == AF_INET6) { |
306 | struct rta_cacheinfo *ci = NULL; | 306 | if (r->rtm_family == AF_INET) { |
307 | if (tb[RTA_CACHEINFO]) { | ||
308 | ci = RTA_DATA(tb[RTA_CACHEINFO]); | ||
309 | } | ||
310 | if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) { | ||
311 | if (r->rtm_flags & RTM_F_CLONED) { | 307 | if (r->rtm_flags & RTM_F_CLONED) { |
312 | printf("%c cache ", _SL_); | 308 | printf("%c cache ", _SL_); |
309 | /* upstream: print_cache_flags() prints more here */ | ||
313 | } | 310 | } |
311 | } | ||
312 | if (tb[RTA_CACHEINFO]) { | ||
313 | struct rta_cacheinfo *ci = RTA_DATA(tb[RTA_CACHEINFO]); | ||
314 | if (ci->rta_expires) { | 314 | if (ci->rta_expires) { |
315 | printf(" expires %dsec", ci->rta_expires / get_hz()); | 315 | printf(" expires %dsec", ci->rta_expires / get_hz()); |
316 | } | 316 | } |
317 | if (ci->rta_error != 0) { | 317 | if (ci->rta_error != 0) { |
318 | printf(" error %d", ci->rta_error); | 318 | printf(" error %d", ci->rta_error); |
319 | } | 319 | } |
320 | } else if (ci) { | 320 | /* upstream: print_rta_cacheinfo() prints more here */ |
321 | if (ci->rta_error != 0) | ||
322 | printf(" error %d", ci->rta_error); | ||
323 | } | 321 | } |
324 | } | 322 | } |
325 | if (tb[RTA_IIF] && G_filter.iif == 0) { | 323 | if (tb[RTA_IIF] && G_filter.iif == 0) { |
diff --git a/networking/ntpd.c b/networking/ntpd.c index dcbdb8e60..dd0a9c91f 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c | |||
@@ -205,7 +205,7 @@ | |||
205 | #define MINDISP 0.01 /* minimum dispersion (sec) */ | 205 | #define MINDISP 0.01 /* minimum dispersion (sec) */ |
206 | #define MAXDISP 16 /* maximum dispersion (sec) */ | 206 | #define MAXDISP 16 /* maximum dispersion (sec) */ |
207 | #define MAXSTRAT 16 /* maximum stratum (infinity metric) */ | 207 | #define MAXSTRAT 16 /* maximum stratum (infinity metric) */ |
208 | #define MAXDIST 1 /* distance threshold (sec) */ | 208 | #define MAXDIST 3 /* distance threshold (sec): do not use peers who are farther away */ |
209 | #define MIN_SELECTED 1 /* minimum intersection survivors */ | 209 | #define MIN_SELECTED 1 /* minimum intersection survivors */ |
210 | #define MIN_CLUSTERED 3 /* minimum cluster survivors */ | 210 | #define MIN_CLUSTERED 3 /* minimum cluster survivors */ |
211 | 211 | ||
@@ -1057,7 +1057,7 @@ step_time(double offset) | |||
1057 | } | 1057 | } |
1058 | tval = tvn.tv_sec; | 1058 | tval = tvn.tv_sec; |
1059 | strftime_YYYYMMDDHHMMSS(buf, sizeof(buf), &tval); | 1059 | strftime_YYYYMMDDHHMMSS(buf, sizeof(buf), &tval); |
1060 | bb_info_msg("setting time to %s.%06u (offset %+fs)", buf, (unsigned)tvn.tv_usec, offset); | 1060 | bb_error_msg("setting time to %s.%06u (offset %+fs)", buf, (unsigned)tvn.tv_usec, offset); |
1061 | //maybe? G.FREQHOLD_cnt = 0; | 1061 | //maybe? G.FREQHOLD_cnt = 0; |
1062 | 1062 | ||
1063 | /* Correct various fields which contain time-relative values: */ | 1063 | /* Correct various fields which contain time-relative values: */ |
@@ -1976,7 +1976,7 @@ recv_and_process_peer_pkt(peer_t *p) | |||
1976 | 1976 | ||
1977 | p->reachable_bits |= 1; | 1977 | p->reachable_bits |= 1; |
1978 | if ((MAX_VERBOSE && G.verbose) || (option_mask32 & OPT_w)) { | 1978 | if ((MAX_VERBOSE && G.verbose) || (option_mask32 & OPT_w)) { |
1979 | bb_info_msg("reply from %s: offset:%+f delay:%f status:0x%02x strat:%d refid:0x%08x rootdelay:%f reach:0x%02x", | 1979 | bb_error_msg("reply from %s: offset:%+f delay:%f status:0x%02x strat:%d refid:0x%08x rootdelay:%f reach:0x%02x", |
1980 | p->p_dotted, | 1980 | p->p_dotted, |
1981 | offset, | 1981 | offset, |
1982 | p->p_raw_delay, | 1982 | p->p_raw_delay, |
diff --git a/networking/telnetd.c b/networking/telnetd.c index bfeea1400..a5a783047 100644 --- a/networking/telnetd.c +++ b/networking/telnetd.c | |||
@@ -104,8 +104,8 @@ | |||
104 | //usage:#define telnetd_full_usage "\n\n" | 104 | //usage:#define telnetd_full_usage "\n\n" |
105 | //usage: "Handle incoming telnet connections" | 105 | //usage: "Handle incoming telnet connections" |
106 | //usage: IF_NOT_FEATURE_TELNETD_STANDALONE(" via inetd") "\n" | 106 | //usage: IF_NOT_FEATURE_TELNETD_STANDALONE(" via inetd") "\n" |
107 | //usage: "\n -l LOGIN Exec LOGIN on connect" | 107 | //usage: "\n -l LOGIN Exec LOGIN on connect (default /bin/login)" |
108 | //usage: "\n -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue" | 108 | //usage: "\n -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue.net" |
109 | //usage: "\n -K Close connection as soon as login exits" | 109 | //usage: "\n -K Close connection as soon as login exits" |
110 | //usage: "\n (normally wait until all programs close slave pty)" | 110 | //usage: "\n (normally wait until all programs close slave pty)" |
111 | //usage: IF_FEATURE_TELNETD_STANDALONE( | 111 | //usage: IF_FEATURE_TELNETD_STANDALONE( |
diff --git a/networking/tftp.c b/networking/tftp.c index f5b4367ca..b698a9288 100644 --- a/networking/tftp.c +++ b/networking/tftp.c | |||
@@ -250,7 +250,7 @@ static int tftp_blksize_check(const char *blksize_str, int maxsize) | |||
250 | return -1; | 250 | return -1; |
251 | } | 251 | } |
252 | # if ENABLE_TFTP_DEBUG | 252 | # if ENABLE_TFTP_DEBUG |
253 | bb_info_msg("using blksize %u", blksize); | 253 | bb_error_msg("using blksize %u", blksize); |
254 | # endif | 254 | # endif |
255 | return blksize; | 255 | return blksize; |
256 | } | 256 | } |
diff --git a/networking/tls.c b/networking/tls.c index 8d074c058..ac6f0767f 100644 --- a/networking/tls.c +++ b/networking/tls.c | |||
@@ -188,8 +188,6 @@ | |||
188 | #define TLS_MAX_OUTBUF (1 << 14) | 188 | #define TLS_MAX_OUTBUF (1 << 14) |
189 | 189 | ||
190 | enum { | 190 | enum { |
191 | SHA_INSIZE = 64, | ||
192 | |||
193 | AES128_KEYSIZE = 16, | 191 | AES128_KEYSIZE = 16, |
194 | AES256_KEYSIZE = 32, | 192 | AES256_KEYSIZE = 32, |
195 | 193 | ||
@@ -335,34 +333,6 @@ void FAST_FUNC tls_get_random(void *buf, unsigned len) | |||
335 | xfunc_die(); | 333 | xfunc_die(); |
336 | } | 334 | } |
337 | 335 | ||
338 | static void xorbuf3(void *dst, const void *src1, const void *src2, unsigned count) | ||
339 | { | ||
340 | uint8_t *d = dst; | ||
341 | const uint8_t *s1 = src1; | ||
342 | const uint8_t* s2 = src2; | ||
343 | while (count--) | ||
344 | *d++ = *s1++ ^ *s2++; | ||
345 | } | ||
346 | |||
347 | void FAST_FUNC xorbuf(void *dst, const void *src, unsigned count) | ||
348 | { | ||
349 | xorbuf3(dst, dst, src, count); | ||
350 | } | ||
351 | |||
352 | void FAST_FUNC xorbuf_aligned_AES_BLOCK_SIZE(void *dst, const void *src) | ||
353 | { | ||
354 | unsigned long *d = dst; | ||
355 | const unsigned long *s = src; | ||
356 | d[0] ^= s[0]; | ||
357 | #if ULONG_MAX <= 0xffffffffffffffff | ||
358 | d[1] ^= s[1]; | ||
359 | #if ULONG_MAX == 0xffffffff | ||
360 | d[2] ^= s[2]; | ||
361 | d[3] ^= s[3]; | ||
362 | #endif | ||
363 | #endif | ||
364 | } | ||
365 | |||
366 | #if !TLS_DEBUG_HASH | 336 | #if !TLS_DEBUG_HASH |
367 | # define hash_handshake(tls, fmt, buffer, len) \ | 337 | # define hash_handshake(tls, fmt, buffer, len) \ |
368 | hash_handshake(tls, buffer, len) | 338 | hash_handshake(tls, buffer, len) |
@@ -393,128 +363,6 @@ static void hash_handshake(tls_state_t *tls, const char *fmt, const void *buffer | |||
393 | # define TLS_MAC_SIZE(tls) (tls)->MAC_size | 363 | # define TLS_MAC_SIZE(tls) (tls)->MAC_size |
394 | #endif | 364 | #endif |
395 | 365 | ||
396 | // RFC 2104: | ||
397 | // HMAC(key, text) based on a hash H (say, sha256) is: | ||
398 | // ipad = [0x36 x INSIZE] | ||
399 | // opad = [0x5c x INSIZE] | ||
400 | // HMAC(key, text) = H((key XOR opad) + H((key XOR ipad) + text)) | ||
401 | // | ||
402 | // H(key XOR opad) and H(key XOR ipad) can be precomputed | ||
403 | // if we often need HMAC hmac with the same key. | ||
404 | // | ||
405 | // text is often given in disjoint pieces. | ||
406 | typedef struct hmac_precomputed { | ||
407 | md5sha_ctx_t hashed_key_xor_ipad; | ||
408 | md5sha_ctx_t hashed_key_xor_opad; | ||
409 | } hmac_precomputed_t; | ||
410 | |||
411 | typedef void md5sha_begin_func(md5sha_ctx_t *ctx) FAST_FUNC; | ||
412 | #if !ENABLE_FEATURE_TLS_SHA1 | ||
413 | #define hmac_begin(pre,key,key_size,begin) \ | ||
414 | hmac_begin(pre,key,key_size) | ||
415 | #define begin sha256_begin | ||
416 | #endif | ||
417 | static void hmac_begin(hmac_precomputed_t *pre, uint8_t *key, unsigned key_size, md5sha_begin_func *begin) | ||
418 | { | ||
419 | uint8_t key_xor_ipad[SHA_INSIZE]; | ||
420 | uint8_t key_xor_opad[SHA_INSIZE]; | ||
421 | // uint8_t tempkey[SHA1_OUTSIZE < SHA256_OUTSIZE ? SHA256_OUTSIZE : SHA1_OUTSIZE]; | ||
422 | unsigned i; | ||
423 | |||
424 | // "The authentication key can be of any length up to INSIZE, the | ||
425 | // block length of the hash function. Applications that use keys longer | ||
426 | // than INSIZE bytes will first hash the key using H and then use the | ||
427 | // resultant OUTSIZE byte string as the actual key to HMAC." | ||
428 | if (key_size > SHA_INSIZE) { | ||
429 | bb_simple_error_msg_and_die("HMAC key>64"); //does not happen (yet?) | ||
430 | // md5sha_ctx_t ctx; | ||
431 | // begin(&ctx); | ||
432 | // md5sha_hash(&ctx, key, key_size); | ||
433 | // key_size = sha_end(&ctx, tempkey); | ||
434 | // //key = tempkey; - right? RIGHT? why does it work without this? | ||
435 | // // because SHA_INSIZE is 64, but hmac() is always called with | ||
436 | // // key_size = tls->MAC_size = SHA1/256_OUTSIZE (20 or 32), | ||
437 | // // and prf_hmac_sha256() -> hmac_sha256() key sizes are: | ||
438 | // // - RSA_PREMASTER_SIZE is 48 | ||
439 | // // - CURVE25519_KEYSIZE is 32 | ||
440 | // // - master_secret[] is 48 | ||
441 | } | ||
442 | |||
443 | for (i = 0; i < key_size; i++) { | ||
444 | key_xor_ipad[i] = key[i] ^ 0x36; | ||
445 | key_xor_opad[i] = key[i] ^ 0x5c; | ||
446 | } | ||
447 | for (; i < SHA_INSIZE; i++) { | ||
448 | key_xor_ipad[i] = 0x36; | ||
449 | key_xor_opad[i] = 0x5c; | ||
450 | } | ||
451 | |||
452 | begin(&pre->hashed_key_xor_ipad); | ||
453 | begin(&pre->hashed_key_xor_opad); | ||
454 | md5sha_hash(&pre->hashed_key_xor_ipad, key_xor_ipad, SHA_INSIZE); | ||
455 | md5sha_hash(&pre->hashed_key_xor_opad, key_xor_opad, SHA_INSIZE); | ||
456 | } | ||
457 | #undef begin | ||
458 | |||
459 | static unsigned hmac_sha_precomputed_v( | ||
460 | hmac_precomputed_t *pre, | ||
461 | uint8_t *out, | ||
462 | va_list va) | ||
463 | { | ||
464 | uint8_t *text; | ||
465 | unsigned len; | ||
466 | |||
467 | /* pre->hashed_key_xor_ipad contains unclosed "H((key XOR ipad) +" state */ | ||
468 | /* pre->hashed_key_xor_opad contains unclosed "H((key XOR opad) +" state */ | ||
469 | |||
470 | /* calculate out = H((key XOR ipad) + text) */ | ||
471 | while ((text = va_arg(va, uint8_t*)) != NULL) { | ||
472 | unsigned text_size = va_arg(va, unsigned); | ||
473 | md5sha_hash(&pre->hashed_key_xor_ipad, text, text_size); | ||
474 | } | ||
475 | len = sha_end(&pre->hashed_key_xor_ipad, out); | ||
476 | |||
477 | /* out = H((key XOR opad) + out) */ | ||
478 | md5sha_hash(&pre->hashed_key_xor_opad, out, len); | ||
479 | return sha_end(&pre->hashed_key_xor_opad, out); | ||
480 | } | ||
481 | |||
482 | static unsigned hmac_sha_precomputed(hmac_precomputed_t *pre_init, uint8_t *out, ...) | ||
483 | { | ||
484 | hmac_precomputed_t pre; | ||
485 | va_list va; | ||
486 | unsigned len; | ||
487 | |||
488 | va_start(va, out); | ||
489 | pre = *pre_init; /* struct copy */ | ||
490 | len = hmac_sha_precomputed_v(&pre, out, va); | ||
491 | va_end(va); | ||
492 | return len; | ||
493 | } | ||
494 | |||
495 | #if !ENABLE_FEATURE_TLS_SHA1 | ||
496 | #define hmac(tls,out,key,key_size,...) \ | ||
497 | hmac(out,key,key_size, __VA_ARGS__) | ||
498 | #endif | ||
499 | static unsigned hmac(tls_state_t *tls, uint8_t *out, uint8_t *key, unsigned key_size, ...) | ||
500 | { | ||
501 | hmac_precomputed_t pre; | ||
502 | va_list va; | ||
503 | unsigned len; | ||
504 | |||
505 | va_start(va, key_size); | ||
506 | |||
507 | hmac_begin(&pre, key, key_size, | ||
508 | (ENABLE_FEATURE_TLS_SHA1 && tls->MAC_size == SHA1_OUTSIZE) | ||
509 | ? sha1_begin | ||
510 | : sha256_begin | ||
511 | ); | ||
512 | len = hmac_sha_precomputed_v(&pre, out, va); | ||
513 | |||
514 | va_end(va); | ||
515 | return len; | ||
516 | } | ||
517 | |||
518 | // RFC 5246: | 366 | // RFC 5246: |
519 | // 5. HMAC and the Pseudorandom Function | 367 | // 5. HMAC and the Pseudorandom Function |
520 | //... | 368 | //... |
@@ -559,7 +407,7 @@ static void prf_hmac_sha256(/*tls_state_t *tls,*/ | |||
559 | const char *label, | 407 | const char *label, |
560 | uint8_t *seed, unsigned seed_size) | 408 | uint8_t *seed, unsigned seed_size) |
561 | { | 409 | { |
562 | hmac_precomputed_t pre; | 410 | hmac_ctx_t ctx; |
563 | uint8_t a[TLS_MAX_MAC_SIZE]; | 411 | uint8_t a[TLS_MAX_MAC_SIZE]; |
564 | uint8_t *out_p = outbuf; | 412 | uint8_t *out_p = outbuf; |
565 | unsigned label_size = strlen(label); | 413 | unsigned label_size = strlen(label); |
@@ -569,26 +417,26 @@ static void prf_hmac_sha256(/*tls_state_t *tls,*/ | |||
569 | #define SEED label, label_size, seed, seed_size | 417 | #define SEED label, label_size, seed, seed_size |
570 | #define A a, MAC_size | 418 | #define A a, MAC_size |
571 | 419 | ||
572 | hmac_begin(&pre, secret, secret_size, sha256_begin); | 420 | hmac_begin(&ctx, secret, secret_size, sha256_begin); |
573 | 421 | ||
574 | /* A(1) = HMAC_hash(secret, seed) */ | 422 | /* A(1) = HMAC_hash(secret, seed) */ |
575 | hmac_sha_precomputed(&pre, a, SEED, NULL); | 423 | hmac_peek_hash(&ctx, a, SEED, NULL); |
576 | 424 | ||
577 | for (;;) { | 425 | for (;;) { |
578 | /* HMAC_hash(secret, A(1) + seed) */ | 426 | /* HMAC_hash(secret, A(1) + seed) */ |
579 | if (outbuf_size <= MAC_size) { | 427 | if (outbuf_size <= MAC_size) { |
580 | /* Last, possibly incomplete, block */ | 428 | /* Last, possibly incomplete, block */ |
581 | /* (use a[] as temp buffer) */ | 429 | /* (use a[] as temp buffer) */ |
582 | hmac_sha_precomputed(&pre, a, A, SEED, NULL); | 430 | hmac_peek_hash(&ctx, a, A, SEED, NULL); |
583 | memcpy(out_p, a, outbuf_size); | 431 | memcpy(out_p, a, outbuf_size); |
584 | return; | 432 | return; |
585 | } | 433 | } |
586 | /* Not last block. Store directly to result buffer */ | 434 | /* Not last block. Store directly to result buffer */ |
587 | hmac_sha_precomputed(&pre, out_p, A, SEED, NULL); | 435 | hmac_peek_hash(&ctx, out_p, A, SEED, NULL); |
588 | out_p += MAC_size; | 436 | out_p += MAC_size; |
589 | outbuf_size -= MAC_size; | 437 | outbuf_size -= MAC_size; |
590 | /* A(2) = HMAC_hash(secret, A(1)) */ | 438 | /* A(2) = HMAC_hash(secret, A(1)) */ |
591 | hmac_sha_precomputed(&pre, a, A, NULL); | 439 | hmac_peek_hash(&ctx, a, A, NULL); |
592 | } | 440 | } |
593 | #undef A | 441 | #undef A |
594 | #undef SECRET | 442 | #undef SECRET |
@@ -655,6 +503,29 @@ static void *tls_get_zeroed_outbuf(tls_state_t *tls, int len) | |||
655 | return record; | 503 | return record; |
656 | } | 504 | } |
657 | 505 | ||
506 | /* Calculate the HMAC over the list of blocks */ | ||
507 | #if !ENABLE_FEATURE_TLS_SHA1 | ||
508 | #define hmac_blocks(tls,out,key,key_size,...) \ | ||
509 | hmac_blocks(out,key,key_size, __VA_ARGS__) | ||
510 | #endif | ||
511 | static unsigned hmac_blocks(tls_state_t *tls, uint8_t *out, uint8_t *key, unsigned key_size, ...) | ||
512 | { | ||
513 | hmac_ctx_t ctx; | ||
514 | va_list va; | ||
515 | |||
516 | hmac_begin(&ctx, key, key_size, | ||
517 | (ENABLE_FEATURE_TLS_SHA1 && tls->MAC_size == SHA1_OUTSIZE) | ||
518 | ? sha1_begin | ||
519 | : sha256_begin | ||
520 | ); | ||
521 | |||
522 | va_start(va, key_size); | ||
523 | hmac_hash_v(&ctx, va); | ||
524 | va_end(va); | ||
525 | |||
526 | return hmac_end(&ctx, out); | ||
527 | } | ||
528 | |||
658 | static void xwrite_encrypted_and_hmac_signed(tls_state_t *tls, unsigned size, unsigned type) | 529 | static void xwrite_encrypted_and_hmac_signed(tls_state_t *tls, unsigned size, unsigned type) |
659 | { | 530 | { |
660 | uint8_t *buf = tls->outbuf + OUTBUF_PFX; | 531 | uint8_t *buf = tls->outbuf + OUTBUF_PFX; |
@@ -676,7 +547,7 @@ static void xwrite_encrypted_and_hmac_signed(tls_state_t *tls, unsigned size, un | |||
676 | xhdr->len16_lo = size & 0xff; | 547 | xhdr->len16_lo = size & 0xff; |
677 | 548 | ||
678 | /* Calculate MAC signature */ | 549 | /* Calculate MAC signature */ |
679 | hmac(tls, buf + size, /* result */ | 550 | hmac_blocks(tls, buf + size, /* result */ |
680 | tls->client_write_MAC_key, TLS_MAC_SIZE(tls), | 551 | tls->client_write_MAC_key, TLS_MAC_SIZE(tls), |
681 | &tls->write_seq64_be, sizeof(tls->write_seq64_be), | 552 | &tls->write_seq64_be, sizeof(tls->write_seq64_be), |
682 | xhdr, RECHDR_LEN, | 553 | xhdr, RECHDR_LEN, |
@@ -865,8 +736,13 @@ static void xwrite_encrypted_aesgcm(tls_state_t *tls, unsigned size, unsigned ty | |||
865 | cnt++; | 736 | cnt++; |
866 | COUNTER(nonce) = htonl(cnt); /* yes, first cnt here is 2 (!) */ | 737 | COUNTER(nonce) = htonl(cnt); /* yes, first cnt here is 2 (!) */ |
867 | aes_encrypt_one_block(&tls->aes_encrypt, nonce, scratch); | 738 | aes_encrypt_one_block(&tls->aes_encrypt, nonce, scratch); |
868 | n = remaining > AES_BLOCK_SIZE ? AES_BLOCK_SIZE : remaining; | 739 | if (remaining >= AES_BLOCK_SIZE) { |
869 | xorbuf(buf, scratch, n); | 740 | n = AES_BLOCK_SIZE; |
741 | xorbuf_AES_BLOCK_SIZE(buf, scratch); | ||
742 | } else { | ||
743 | n = remaining; | ||
744 | xorbuf(buf, scratch, n); | ||
745 | } | ||
870 | buf += n; | 746 | buf += n; |
871 | remaining -= n; | 747 | remaining -= n; |
872 | } | 748 | } |
@@ -1024,7 +900,7 @@ static void tls_aesgcm_decrypt(tls_state_t *tls, uint8_t *buf, int size) | |||
1024 | COUNTER(nonce) = htonl(cnt); /* yes, first cnt here is 2 (!) */ | 900 | COUNTER(nonce) = htonl(cnt); /* yes, first cnt here is 2 (!) */ |
1025 | aes_encrypt_one_block(&tls->aes_decrypt, nonce, scratch); | 901 | aes_encrypt_one_block(&tls->aes_decrypt, nonce, scratch); |
1026 | n = remaining > AES_BLOCK_SIZE ? AES_BLOCK_SIZE : remaining; | 902 | n = remaining > AES_BLOCK_SIZE ? AES_BLOCK_SIZE : remaining; |
1027 | xorbuf3(buf, scratch, buf + 8, n); | 903 | xorbuf_3(buf, scratch, buf + 8, n); |
1028 | buf += n; | 904 | buf += n; |
1029 | remaining -= n; | 905 | remaining -= n; |
1030 | } | 906 | } |
diff --git a/networking/tls.h b/networking/tls.h index 0173b87b2..9751d30ff 100644 --- a/networking/tls.h +++ b/networking/tls.h | |||
@@ -82,10 +82,9 @@ typedef int16_t int16; | |||
82 | 82 | ||
83 | void tls_get_random(void *buf, unsigned len) FAST_FUNC; | 83 | void tls_get_random(void *buf, unsigned len) FAST_FUNC; |
84 | 84 | ||
85 | void xorbuf(void* buf, const void* mask, unsigned count) FAST_FUNC; | ||
86 | |||
87 | #define ALIGNED_long ALIGNED(sizeof(long)) | 85 | #define ALIGNED_long ALIGNED(sizeof(long)) |
88 | void xorbuf_aligned_AES_BLOCK_SIZE(void* buf, const void* mask) FAST_FUNC; | 86 | #define xorbuf_aligned_AES_BLOCK_SIZE(dst,src) xorbuf16_aligned_long(dst,src) |
87 | #define xorbuf_AES_BLOCK_SIZE(dst,src) xorbuf16(dst,src) | ||
89 | 88 | ||
90 | #define matrixCryptoGetPrngData(buf, len, userPtr) (tls_get_random(buf, len), PS_SUCCESS) | 89 | #define matrixCryptoGetPrngData(buf, len, userPtr) (tls_get_random(buf, len), PS_SUCCESS) |
91 | 90 | ||
diff --git a/networking/tls_aesgcm.c b/networking/tls_aesgcm.c index 5ddcdd2ad..9c2381a57 100644 --- a/networking/tls_aesgcm.c +++ b/networking/tls_aesgcm.c | |||
@@ -167,10 +167,7 @@ void FAST_FUNC aesgcm_GHASH(byte* h, | |||
167 | blocks = cSz / AES_BLOCK_SIZE; | 167 | blocks = cSz / AES_BLOCK_SIZE; |
168 | partial = cSz % AES_BLOCK_SIZE; | 168 | partial = cSz % AES_BLOCK_SIZE; |
169 | while (blocks--) { | 169 | while (blocks--) { |
170 | if (BB_UNALIGNED_MEMACCESS_OK) // c is not guaranteed to be aligned | 170 | xorbuf_AES_BLOCK_SIZE(x, c); |
171 | xorbuf_aligned_AES_BLOCK_SIZE(x, c); | ||
172 | else | ||
173 | xorbuf(x, c, AES_BLOCK_SIZE); | ||
174 | GMULT(x, h); | 171 | GMULT(x, h); |
175 | c += AES_BLOCK_SIZE; | 172 | c += AES_BLOCK_SIZE; |
176 | } | 173 | } |
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c index 79cef1999..19c961d5c 100644 --- a/networking/udhcp/d6_dhcpc.c +++ b/networking/udhcp/d6_dhcpc.c | |||
@@ -148,10 +148,11 @@ enum { | |||
148 | OPT_o = 1 << 12, | 148 | OPT_o = 1 << 12, |
149 | OPT_x = 1 << 13, | 149 | OPT_x = 1 << 13, |
150 | OPT_f = 1 << 14, | 150 | OPT_f = 1 << 14, |
151 | OPT_l = 1 << 15, | 151 | OPT_m = 1 << 15, |
152 | OPT_d = 1 << 16, | 152 | OPT_l = 1 << 16, |
153 | OPT_d = 1 << 17, | ||
153 | /* The rest has variable bit positions, need to be clever */ | 154 | /* The rest has variable bit positions, need to be clever */ |
154 | OPTBIT_d = 16, | 155 | OPTBIT_d = 17, |
155 | USE_FOR_MMU( OPTBIT_b,) | 156 | USE_FOR_MMU( OPTBIT_b,) |
156 | ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) | 157 | ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) |
157 | IF_FEATURE_UDHCP_PORT( OPTBIT_P,) | 158 | IF_FEATURE_UDHCP_PORT( OPTBIT_P,) |
@@ -268,6 +269,23 @@ static void option_to_env(const uint8_t *option, const uint8_t *option_end) | |||
268 | //case D6_OPT_SERVERID: | 269 | //case D6_OPT_SERVERID: |
269 | case D6_OPT_IA_NA: | 270 | case D6_OPT_IA_NA: |
270 | case D6_OPT_IA_PD: | 271 | case D6_OPT_IA_PD: |
272 | /* 0 1 2 3 | ||
273 | * 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 | ||
274 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
275 | * | OPTION_IA_PD | option-length | | ||
276 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
277 | * | IAID (4 octets) | | ||
278 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
279 | * | T1 | | ||
280 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
281 | * | T2 | | ||
282 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
283 | * . . | ||
284 | * . IA_PD-options . | ||
285 | * . . | ||
286 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
287 | */ | ||
288 | /* recurse to handle "IA_PD-options" field */ | ||
271 | option_to_env(option + 16, option + 4 + option[3]); | 289 | option_to_env(option + 16, option + 4 + option[3]); |
272 | break; | 290 | break; |
273 | //case D6_OPT_IA_TA: | 291 | //case D6_OPT_IA_TA: |
@@ -604,6 +622,31 @@ static NOINLINE int send_d6_info_request(void) | |||
604 | return d6_mcast_from_client_data_ifindex(&packet, opt_ptr); | 622 | return d6_mcast_from_client_data_ifindex(&packet, opt_ptr); |
605 | } | 623 | } |
606 | 624 | ||
625 | /* | ||
626 | * RFC 3315 10. Identity Association | ||
627 | * | ||
628 | * An "identity-association" (IA) is a construct through which a server | ||
629 | * and a client can identify, group, and manage a set of related IPv6 | ||
630 | * addresses. Each IA consists of an IAID and associated configuration | ||
631 | * information. | ||
632 | * | ||
633 | * A client must associate at least one distinct IA with each of its | ||
634 | * network interfaces for which it is to request the assignment of IPv6 | ||
635 | * addresses from a DHCP server. The client uses the IAs assigned to an | ||
636 | * interface to obtain configuration information from a server for that | ||
637 | * interface. Each IA must be associated with exactly one interface. | ||
638 | * | ||
639 | * The IAID uniquely identifies the IA and must be chosen to be unique | ||
640 | * among the IAIDs on the client. The IAID is chosen by the client. | ||
641 | * For any given use of an IA by the client, the IAID for that IA MUST | ||
642 | * be consistent across restarts of the DHCP client... | ||
643 | */ | ||
644 | /* Generate IAID. We base it on our MAC address' last 4 bytes */ | ||
645 | static void generate_iaid(uint8_t *iaid) | ||
646 | { | ||
647 | memcpy(iaid, &client_data.client_mac[2], 4); | ||
648 | } | ||
649 | |||
607 | /* Multicast a DHCPv6 Solicit packet to the network, with an optionally requested IP. | 650 | /* Multicast a DHCPv6 Solicit packet to the network, with an optionally requested IP. |
608 | * | 651 | * |
609 | * RFC 3315 17.1.1. Creation of Solicit Messages | 652 | * RFC 3315 17.1.1. Creation of Solicit Messages |
@@ -703,7 +746,7 @@ static NOINLINE int send_d6_discover(struct in6_addr *requested_ipv6) | |||
703 | client6_data.ia_na = xzalloc(len); | 746 | client6_data.ia_na = xzalloc(len); |
704 | client6_data.ia_na->code = D6_OPT_IA_NA; | 747 | client6_data.ia_na->code = D6_OPT_IA_NA; |
705 | client6_data.ia_na->len = len - 4; | 748 | client6_data.ia_na->len = len - 4; |
706 | *(bb__aliased_uint32_t*)client6_data.ia_na->data = rand(); /* IAID */ | 749 | generate_iaid(client6_data.ia_na->data); /* IAID */ |
707 | if (requested_ipv6) { | 750 | if (requested_ipv6) { |
708 | struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4); | 751 | struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4); |
709 | iaaddr->code = D6_OPT_IAADDR; | 752 | iaaddr->code = D6_OPT_IAADDR; |
@@ -721,7 +764,7 @@ static NOINLINE int send_d6_discover(struct in6_addr *requested_ipv6) | |||
721 | client6_data.ia_pd = xzalloc(len); | 764 | client6_data.ia_pd = xzalloc(len); |
722 | client6_data.ia_pd->code = D6_OPT_IA_PD; | 765 | client6_data.ia_pd->code = D6_OPT_IA_PD; |
723 | client6_data.ia_pd->len = len - 4; | 766 | client6_data.ia_pd->len = len - 4; |
724 | *(bb__aliased_uint32_t*)client6_data.ia_pd->data = rand(); /* IAID */ | 767 | generate_iaid(client6_data.ia_pd->data); /* IAID */ |
725 | opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, len); | 768 | opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, len); |
726 | } | 769 | } |
727 | 770 | ||
@@ -1131,12 +1174,11 @@ static void client_background(void) | |||
1131 | //usage:#endif | 1174 | //usage:#endif |
1132 | //usage:#define udhcpc6_trivial_usage | 1175 | //usage:#define udhcpc6_trivial_usage |
1133 | //usage: "[-fbq"IF_UDHCP_VERBOSE("v")"R] [-t N] [-T SEC] [-A SEC|-n] [-i IFACE] [-s PROG]\n" | 1176 | //usage: "[-fbq"IF_UDHCP_VERBOSE("v")"R] [-t N] [-T SEC] [-A SEC|-n] [-i IFACE] [-s PROG]\n" |
1134 | //usage: " [-p PIDFILE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-ldo] [-r IPv6] [-x OPT:VAL]... [-O OPT]..." | 1177 | //usage: " [-p PIDFILE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-mldo] [-r IPv6] [-x OPT:VAL]... [-O OPT]..." |
1135 | //usage:#define udhcpc6_full_usage "\n" | 1178 | //usage:#define udhcpc6_full_usage "\n" |
1136 | //usage: "\n -i IFACE Interface to use (default "CONFIG_UDHCPC_DEFAULT_INTERFACE")" | 1179 | //usage: "\n -i IFACE Interface to use (default "CONFIG_UDHCPC_DEFAULT_INTERFACE")" |
1137 | //usage: "\n -p FILE Create pidfile" | 1180 | //usage: "\n -p FILE Create pidfile" |
1138 | //usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC6_DEFAULT_SCRIPT")" | 1181 | //usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC6_DEFAULT_SCRIPT")" |
1139 | //usage: "\n -B Request broadcast replies" | ||
1140 | //usage: "\n -t N Send up to N discover packets" | 1182 | //usage: "\n -t N Send up to N discover packets" |
1141 | //usage: "\n -T SEC Pause between packets (default 3)" | 1183 | //usage: "\n -T SEC Pause between packets (default 3)" |
1142 | //usage: "\n -A SEC Wait if lease is not obtained (default 20)" | 1184 | //usage: "\n -A SEC Wait if lease is not obtained (default 20)" |
@@ -1154,6 +1196,7 @@ static void client_background(void) | |||
1154 | ////usage: IF_FEATURE_UDHCPC_ARPING( | 1196 | ////usage: IF_FEATURE_UDHCPC_ARPING( |
1155 | ////usage: "\n -a Use arping to validate offered address" | 1197 | ////usage: "\n -a Use arping to validate offered address" |
1156 | ////usage: ) | 1198 | ////usage: ) |
1199 | //usage: "\n -m Send multicast renew requests rather than unicast ones" | ||
1157 | //usage: "\n -l Send 'information request' instead of 'solicit'" | 1200 | //usage: "\n -l Send 'information request' instead of 'solicit'" |
1158 | //usage: "\n (used for servers which do not assign IPv6 addresses)" | 1201 | //usage: "\n (used for servers which do not assign IPv6 addresses)" |
1159 | //usage: "\n -r IPv6 Request this address ('no' to not request any IP)" | 1202 | //usage: "\n -r IPv6 Request this address ('no' to not request any IP)" |
@@ -1211,7 +1254,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1211 | /* Parse command line */ | 1254 | /* Parse command line */ |
1212 | opt = getopt32long(argv, "^" | 1255 | opt = getopt32long(argv, "^" |
1213 | /* O,x: list; -T,-t,-A take numeric param */ | 1256 | /* O,x: list; -T,-t,-A take numeric param */ |
1214 | "i:np:qRr:s:T:+t:+SA:+O:*ox:*fld" | 1257 | "i:np:qRr:s:T:+t:+SA:+O:*ox:*fmld" |
1215 | USE_FOR_MMU("b") | 1258 | USE_FOR_MMU("b") |
1216 | ///IF_FEATURE_UDHCPC_ARPING("a") | 1259 | ///IF_FEATURE_UDHCPC_ARPING("a") |
1217 | IF_FEATURE_UDHCP_PORT("P:") | 1260 | IF_FEATURE_UDHCP_PORT("P:") |
@@ -1464,7 +1507,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1464 | if (opt & OPT_l) | 1507 | if (opt & OPT_l) |
1465 | send_d6_info_request(); | 1508 | send_d6_info_request(); |
1466 | else | 1509 | else |
1467 | send_d6_renew(&srv6_buf, requested_ipv6); | 1510 | send_d6_renew(OPT_m ? NULL : &srv6_buf, requested_ipv6); |
1468 | timeout = discover_timeout; | 1511 | timeout = discover_timeout; |
1469 | packet_num++; | 1512 | packet_num++; |
1470 | continue; | 1513 | continue; |
@@ -1606,62 +1649,6 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1606 | case RENEW_REQUESTED: | 1649 | case RENEW_REQUESTED: |
1607 | case REBINDING: | 1650 | case REBINDING: |
1608 | if (packet.d6_msg_type == D6_MSG_REPLY) { | 1651 | if (packet.d6_msg_type == D6_MSG_REPLY) { |
1609 | unsigned start; | ||
1610 | uint32_t lease_seconds; | ||
1611 | struct d6_option *option; | ||
1612 | unsigned address_timeout; | ||
1613 | unsigned prefix_timeout; | ||
1614 | type_is_ok: | ||
1615 | change_listen_mode(LISTEN_NONE); | ||
1616 | |||
1617 | address_timeout = 0; | ||
1618 | prefix_timeout = 0; | ||
1619 | option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE); | ||
1620 | if (option && (option->data[0] | option->data[1]) != 0) { | ||
1621 | ///FIXME: | ||
1622 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1623 | // | OPTION_STATUS_CODE | option-len | | ||
1624 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1625 | // | status-code | | | ||
1626 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | ||
1627 | // . status-message . | ||
1628 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1629 | // so why do we think it's NAK if data[0] is zero but data[1] is not? That's wrong... | ||
1630 | // we should also check that option->len is ok (i.e. not 0), right? | ||
1631 | /* return to init state */ | ||
1632 | bb_info_msg("received DHCP NAK (%u)", option->data[4]); | ||
1633 | d6_run_script(packet.d6_options, | ||
1634 | packet_end, "nak"); | ||
1635 | if (client_data.state != REQUESTING) | ||
1636 | d6_run_script_no_option("deconfig"); | ||
1637 | sleep(3); /* avoid excessive network traffic */ | ||
1638 | client_data.state = INIT_SELECTING; | ||
1639 | client_data.first_secs = 0; /* make secs field count from 0 */ | ||
1640 | requested_ipv6 = NULL; | ||
1641 | timeout = 0; | ||
1642 | packet_num = 0; | ||
1643 | continue; | ||
1644 | } | ||
1645 | option = d6_copy_option(packet.d6_options, packet_end, D6_OPT_SERVERID); | ||
1646 | if (!option) { | ||
1647 | bb_simple_info_msg("no server ID, ignoring packet"); | ||
1648 | continue; | ||
1649 | /* still selecting - this server looks bad */ | ||
1650 | } | ||
1651 | //Note: we do not bother comparing server IDs in Advertise and Reply msgs. | ||
1652 | //server_id variable is used solely for creation of proper server_id option | ||
1653 | //in outgoing packets. (why DHCPv6 even introduced it is a mystery). | ||
1654 | free(client6_data.server_id); | ||
1655 | client6_data.server_id = option; | ||
1656 | if (packet.d6_msg_type == D6_MSG_ADVERTISE) { | ||
1657 | /* enter requesting state */ | ||
1658 | change_listen_mode(LISTEN_RAW); | ||
1659 | client_data.state = REQUESTING; | ||
1660 | timeout = 0; | ||
1661 | packet_num = 0; | ||
1662 | continue; | ||
1663 | } | ||
1664 | /* It's a D6_MSG_REPLY */ | ||
1665 | /* | 1652 | /* |
1666 | * RFC 3315 18.1.8. Receipt of Reply Messages | 1653 | * RFC 3315 18.1.8. Receipt of Reply Messages |
1667 | * | 1654 | * |
@@ -1747,6 +1734,67 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1747 | * . . | 1734 | * . . |
1748 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 1735 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
1749 | */ | 1736 | */ |
1737 | unsigned start; | ||
1738 | uint32_t lease_seconds; | ||
1739 | struct d6_option *option; | ||
1740 | unsigned address_timeout; | ||
1741 | unsigned prefix_timeout; | ||
1742 | type_is_ok: | ||
1743 | change_listen_mode(LISTEN_NONE); | ||
1744 | |||
1745 | address_timeout = 0; | ||
1746 | prefix_timeout = 0; | ||
1747 | option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE); | ||
1748 | if (option) { | ||
1749 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1750 | // | OPTION_STATUS_CODE | option-len | | ||
1751 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1752 | // | status-code | | | ||
1753 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | ||
1754 | // . status-message . | ||
1755 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1756 | unsigned len, status; | ||
1757 | len = ((unsigned)option->len_hi << 8) + option->len; | ||
1758 | if (len < 2) { | ||
1759 | bb_simple_error_msg("invalid OPTION_STATUS_CODE, ignoring packet"); | ||
1760 | continue; | ||
1761 | } | ||
1762 | status = ((unsigned)option->data[0] << 8) + option->data[1]; | ||
1763 | if (status != 0) { | ||
1764 | //TODO: handle status == 5 (UseMulticast)? | ||
1765 | /* return to init state */ | ||
1766 | bb_info_msg("received DHCP NAK: %u '%.*s'", status, len - 2, option->data + 2); | ||
1767 | d6_run_script(packet.d6_options, packet_end, "nak"); | ||
1768 | if (client_data.state != REQUESTING) | ||
1769 | d6_run_script_no_option("deconfig"); | ||
1770 | sleep(3); /* avoid excessive network traffic */ | ||
1771 | client_data.state = INIT_SELECTING; | ||
1772 | client_data.first_secs = 0; /* make secs field count from 0 */ | ||
1773 | requested_ipv6 = NULL; | ||
1774 | timeout = 0; | ||
1775 | packet_num = 0; | ||
1776 | continue; | ||
1777 | } | ||
1778 | } | ||
1779 | option = d6_copy_option(packet.d6_options, packet_end, D6_OPT_SERVERID); | ||
1780 | if (!option) { | ||
1781 | bb_simple_info_msg("no server ID, ignoring packet"); | ||
1782 | continue; | ||
1783 | /* still selecting - this server looks bad */ | ||
1784 | } | ||
1785 | //Note: we do not bother comparing server IDs in Advertise and Reply msgs. | ||
1786 | //server_id variable is used solely for creation of proper server_id option | ||
1787 | //in outgoing packets. (why DHCPv6 even introduced it is a mystery). | ||
1788 | free(client6_data.server_id); | ||
1789 | client6_data.server_id = option; | ||
1790 | if (packet.d6_msg_type == D6_MSG_ADVERTISE) { | ||
1791 | /* enter requesting state */ | ||
1792 | change_listen_mode(LISTEN_RAW); | ||
1793 | client_data.state = REQUESTING; | ||
1794 | timeout = 0; | ||
1795 | packet_num = 0; | ||
1796 | continue; | ||
1797 | } | ||
1750 | if (option_mask32 & OPT_r) { | 1798 | if (option_mask32 & OPT_r) { |
1751 | struct d6_option *iaaddr; | 1799 | struct d6_option *iaaddr; |
1752 | 1800 | ||
@@ -1790,6 +1838,21 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1790 | 1838 | ||
1791 | free(client6_data.ia_pd); | 1839 | free(client6_data.ia_pd); |
1792 | client6_data.ia_pd = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_PD); | 1840 | client6_data.ia_pd = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_PD); |
1841 | // 0 1 2 3 | ||
1842 | // 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 | ||
1843 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1844 | // | OPTION_IA_PD | option-length | | ||
1845 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1846 | // | IAID (4 octets) | | ||
1847 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1848 | // | T1 | | ||
1849 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1850 | // | T2 | | ||
1851 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1852 | // . . | ||
1853 | // . IA_PD-options . | ||
1854 | // . . | ||
1855 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
1793 | if (!client6_data.ia_pd) { | 1856 | if (!client6_data.ia_pd) { |
1794 | bb_info_msg("no %s option%s", "IA_PD", ", ignoring packet"); | 1857 | bb_info_msg("no %s option%s", "IA_PD", ", ignoring packet"); |
1795 | continue; | 1858 | continue; |
diff --git a/networking/udhcp/d6_packet.c b/networking/udhcp/d6_packet.c index 142de9b43..1d7541948 100644 --- a/networking/udhcp/d6_packet.c +++ b/networking/udhcp/d6_packet.c | |||
@@ -153,13 +153,15 @@ int FAST_FUNC d6_send_kernel_packet_from_client_data_ifindex( | |||
153 | } | 153 | } |
154 | setsockopt_reuseaddr(fd); | 154 | setsockopt_reuseaddr(fd); |
155 | 155 | ||
156 | memset(&sa, 0, sizeof(sa)); | 156 | if (src_ipv6) { |
157 | sa.sin6_family = AF_INET6; | 157 | memset(&sa, 0, sizeof(sa)); |
158 | sa.sin6_port = htons(source_port); | 158 | sa.sin6_family = AF_INET6; |
159 | sa.sin6_addr = *src_ipv6; /* struct copy */ | 159 | sa.sin6_port = htons(source_port); |
160 | if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { | 160 | sa.sin6_addr = *src_ipv6; /* struct copy */ |
161 | msg = "bind(%s)"; | 161 | if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { |
162 | goto ret_close; | 162 | msg = "bind(%s)"; |
163 | goto ret_close; | ||
164 | } | ||
163 | } | 165 | } |
164 | 166 | ||
165 | memset(&sa, 0, sizeof(sa)); | 167 | memset(&sa, 0, sizeof(sa)); |
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index 2904119e5..b9cbd6464 100644 --- a/networking/udhcp/dhcpd.c +++ b/networking/udhcp/dhcpd.c | |||
@@ -575,29 +575,51 @@ static void send_packet_to_client(struct dhcp_packet *dhcp_pkt, int force_broadc | |||
575 | const uint8_t *chaddr; | 575 | const uint8_t *chaddr; |
576 | uint32_t ciaddr; | 576 | uint32_t ciaddr; |
577 | 577 | ||
578 | // Was: | 578 | // Logic: |
579 | //if (force_broadcast) { /* broadcast */ } | 579 | //if (force_broadcast) { /* broadcast */ } |
580 | //else if (dhcp_pkt->ciaddr) { /* unicast to dhcp_pkt->ciaddr */ } | 580 | //else if (dhcp_pkt->ciaddr) { /* unicast to dhcp_pkt->ciaddr */ } |
581 | // ^^^ dhcp_pkt->ciaddr comes from client's request packet. | ||
582 | // We expect such clients to have an UDP socket listening on that IP. | ||
581 | //else if (dhcp_pkt->flags & htons(BROADCAST_FLAG)) { /* broadcast */ } | 583 | //else if (dhcp_pkt->flags & htons(BROADCAST_FLAG)) { /* broadcast */ } |
582 | //else { /* unicast to dhcp_pkt->yiaddr */ } | 584 | //else { /* unicast to dhcp_pkt->yiaddr */ } |
583 | // But this is wrong: yiaddr is _our_ idea what client's IP is | 585 | // ^^^ The last case is confusing, but *should* work. |
584 | // (for example, from lease file). Client may not know that, | 586 | // It's a case where client have sent a DISCOVER |
585 | // and may not have UDP socket listening on that IP! | 587 | // and does not have a kernel UDP socket listening on the IP |
586 | // We should never unicast to dhcp_pkt->yiaddr! | 588 | // we are offering in yiaddr (it does not know the IP yet)! |
587 | // dhcp_pkt->ciaddr, OTOH, comes from client's request packet, | 589 | // This *should* work because client *should* listen on a raw socket |
588 | // and can be used. | 590 | // instead at this time (IOW: it should examine ALL IPv4 packets |
589 | 591 | // "by hand", not relying on kernel's UDP stack.) | |
590 | if (force_broadcast | 592 | |
591 | || (dhcp_pkt->flags & htons(BROADCAST_FLAG)) | 593 | chaddr = dhcp_pkt->chaddr; |
592 | || dhcp_pkt->ciaddr == 0 | 594 | |
595 | if (dhcp_pkt->ciaddr == 0 | ||
596 | || force_broadcast /* sending DHCPNAK pkt? */ | ||
593 | ) { | 597 | ) { |
594 | log1s("broadcasting packet to client"); | 598 | if (dhcp_pkt->flags & htons(BROADCAST_FLAG) |
595 | ciaddr = INADDR_BROADCAST; | 599 | || force_broadcast /* sending DHCPNAK pkt? */ |
596 | chaddr = MAC_BCAST_ADDR; | 600 | ) { |
601 | // RFC 2131: | ||
602 | // If 'giaddr' is zero and 'ciaddr' is zero, and the broadcast bit is | ||
603 | // set, then the server broadcasts DHCPOFFER and DHCPACK messages to | ||
604 | // 0xffffffff. ... | ||
605 | // In all cases, when 'giaddr' is zero, the server broadcasts any DHCPNAK | ||
606 | // messages to 0xffffffff. | ||
607 | ciaddr = INADDR_BROADCAST; | ||
608 | chaddr = MAC_BCAST_ADDR; | ||
609 | log1s("broadcasting packet to client"); | ||
610 | } else { | ||
611 | // If the broadcast bit is not set and 'giaddr' is zero and | ||
612 | // 'ciaddr' is zero, then the server unicasts DHCPOFFER and DHCPACK | ||
613 | // messages to the client's hardware address and 'yiaddr' address. | ||
614 | ciaddr = dhcp_pkt->yiaddr; | ||
615 | log1("unicasting packet to client %ciaddr", 'y'); | ||
616 | } | ||
597 | } else { | 617 | } else { |
598 | log1s("unicasting packet to client ciaddr"); | 618 | // If the 'giaddr' |
619 | // field is zero and the 'ciaddr' field is nonzero, then the server | ||
620 | // unicasts DHCPOFFER and DHCPACK messages to the address in 'ciaddr'. | ||
599 | ciaddr = dhcp_pkt->ciaddr; | 621 | ciaddr = dhcp_pkt->ciaddr; |
600 | chaddr = dhcp_pkt->chaddr; | 622 | log1("unicasting packet to client %ciaddr", 'c'); |
601 | } | 623 | } |
602 | 624 | ||
603 | udhcp_send_raw_packet(dhcp_pkt, | 625 | udhcp_send_raw_packet(dhcp_pkt, |
@@ -624,6 +646,10 @@ static void send_packet_to_relay(struct dhcp_packet *dhcp_pkt) | |||
624 | static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast) | 646 | static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast) |
625 | { | 647 | { |
626 | if (dhcp_pkt->gateway_nip) | 648 | if (dhcp_pkt->gateway_nip) |
649 | // RFC 2131: | ||
650 | // If the 'giaddr' field in a DHCP message from a client is non-zero, | ||
651 | // the server sends any return messages to the 'DHCP server' port on the | ||
652 | // BOOTP relay agent whose address appears in 'giaddr'. | ||
627 | send_packet_to_relay(dhcp_pkt); | 653 | send_packet_to_relay(dhcp_pkt); |
628 | else | 654 | else |
629 | send_packet_to_client(dhcp_pkt, force_broadcast); | 655 | send_packet_to_client(dhcp_pkt, force_broadcast); |