1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54#include <syslog.h>
55
56#define WANT_PIDFILE 1
57#include "common.h"
58#include "dhcpd.h"
59#include "dhcpc.h"
60#include "d6_common.h"
61
62#include <netinet/if_ether.h>
63#include <netpacket/packet.h>
64#include <linux/filter.h>
65
66
67
68static const struct dhcp_optflag d6_optflags[] = {
69#if ENABLE_FEATURE_UDHCPC6_RFC3646
70 { OPTION_6RD | OPTION_LIST | OPTION_REQ, D6_OPT_DNS_SERVERS },
71 { OPTION_DNS_STRING | OPTION_LIST | OPTION_REQ, D6_OPT_DOMAIN_LIST },
72#endif
73#if ENABLE_FEATURE_UDHCPC6_RFC4704
74 { OPTION_DNS_STRING, D6_OPT_CLIENT_FQDN },
75#endif
76#if ENABLE_FEATURE_UDHCPC6_RFC4833
77 { OPTION_STRING, D6_OPT_TZ_POSIX },
78 { OPTION_STRING, D6_OPT_TZ_NAME },
79#endif
80#if ENABLE_FEATURE_UDHCPC6_RFC5970
81 { OPTION_STRING, D6_OPT_BOOT_URL },
82 { OPTION_STRING, D6_OPT_BOOT_PARAM },
83#endif
84 { OPTION_STRING, 0xd1 },
85 { OPTION_STRING, 0xd2 },
86 { 0, 0 }
87};
88
89static const char d6_option_strings[] ALIGN1 =
90#if ENABLE_FEATURE_UDHCPC6_RFC3646
91 "dns" "\0"
92 "search" "\0"
93#endif
94#if ENABLE_FEATURE_UDHCPC6_RFC4704
95 "fqdn" "\0"
96#endif
97#if ENABLE_FEATURE_UDHCPC6_RFC4833
98 "tz" "\0"
99 "timezone" "\0"
100#endif
101#if ENABLE_FEATURE_UDHCPC6_RFC5970
102 "bootfile_url" "\0"
103 "bootfile_param" "\0"
104#endif
105 "pxeconffile" "\0"
106 "pxepathprefix" "\0"
107 "\0";
108
109#if ENABLE_LONG_OPTS
110static const char udhcpc6_longopts[] ALIGN1 =
111 "interface\0" Required_argument "i"
112 "now\0" No_argument "n"
113 "pidfile\0" Required_argument "p"
114 "quit\0" No_argument "q"
115 "release\0" No_argument "R"
116 "request\0" Required_argument "r"
117 "requestprefix\0" No_argument "d"
118 "script\0" Required_argument "s"
119 "timeout\0" Required_argument "T"
120 "retries\0" Required_argument "t"
121 "tryagain\0" Required_argument "A"
122 "syslog\0" No_argument "S"
123 "request-option\0" Required_argument "O"
124 "no-default-options\0" No_argument "o"
125 "foreground\0" No_argument "f"
126 "stateless\0" No_argument "l"
127 USE_FOR_MMU(
128 "background\0" No_argument "b"
129 )
130
131 IF_FEATURE_UDHCP_PORT("client-port\0" Required_argument "P")
132 ;
133#endif
134
135enum {
136 OPT_i = 1 << 0,
137 OPT_n = 1 << 1,
138 OPT_p = 1 << 2,
139 OPT_q = 1 << 3,
140 OPT_R = 1 << 4,
141 OPT_r = 1 << 5,
142 OPT_s = 1 << 6,
143 OPT_T = 1 << 7,
144 OPT_t = 1 << 8,
145 OPT_S = 1 << 9,
146 OPT_A = 1 << 10,
147 OPT_O = 1 << 11,
148 OPT_o = 1 << 12,
149 OPT_x = 1 << 13,
150 OPT_f = 1 << 14,
151 OPT_l = 1 << 15,
152 OPT_d = 1 << 16,
153
154 OPTBIT_d = 16,
155 USE_FOR_MMU( OPTBIT_b,)
156
157 IF_FEATURE_UDHCP_PORT( OPTBIT_P,)
158 USE_FOR_MMU( OPT_b = 1 << OPTBIT_b,)
159
160 IF_FEATURE_UDHCP_PORT( OPT_P = 1 << OPTBIT_P,)
161};
162
163#if ENABLE_FEATURE_UDHCPC6_RFC4704
164static const char opt_fqdn_req[] = {
165 (D6_OPT_CLIENT_FQDN >> 8), (D6_OPT_CLIENT_FQDN & 0xff),
166 0, 2,
167 0,
168
169
170
171 0
172};
173#endif
174
175
176
177static void *d6_find_option(uint8_t *option, uint8_t *option_end, unsigned code)
178{
179
180 int len_m4 = option_end - option - 4;
181 while (len_m4 >= 0) {
182
183 if (option[3] > len_m4)
184 return NULL;
185
186
187
188
189 if (option[0] != 0 || option[2] != 0)
190 return NULL;
191
192
193 if (option[1] == code)
194 return option;
195 len_m4 -= option[3] + 4;
196 option += option[3] + 4;
197 }
198 return NULL;
199}
200
201static void *d6_copy_option(uint8_t *option, uint8_t *option_end, unsigned code)
202{
203 uint8_t *opt = d6_find_option(option, option_end, code);
204 if (!opt)
205 return opt;
206 return xmemdup(opt, opt[3] + 4);
207}
208
209
210
211static char** new_env(void)
212{
213 client6_data.env_ptr = xrealloc_vector(client6_data.env_ptr, 3, client6_data.env_idx);
214 return &client6_data.env_ptr[client6_data.env_idx++];
215}
216
217static char *string_option_to_env(const uint8_t *option,
218 const uint8_t *option_end)
219{
220 const char *ptr, *name = NULL;
221 unsigned val_len;
222 int i;
223
224 ptr = d6_option_strings;
225 i = 0;
226 while (*ptr) {
227 if (d6_optflags[i].code == option[1]) {
228 name = ptr;
229 goto found;
230 }
231 ptr += strlen(ptr) + 1;
232 i++;
233 }
234 bb_error_msg("can't find option name for 0x%x, skipping", option[1]);
235 return NULL;
236
237 found:
238 val_len = (option[2] << 8) | option[3];
239 if (val_len + &option[D6_OPT_DATA] > option_end) {
240 bb_simple_error_msg("option data exceeds option length");
241 return NULL;
242 }
243 return xasprintf("%s=%.*s", name, val_len, (char*)option + 4);
244}
245
246
247static void option_to_env(const uint8_t *option, const uint8_t *option_end)
248{
249#if ENABLE_FEATURE_UDHCPC6_RFC3646
250 int addrs, option_offset;
251#endif
252
253 int len_m4 = option_end - option - 4;
254
255 while (len_m4 >= 0) {
256 uint32_t v32;
257 char ipv6str[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")];
258
259 if (option[0] != 0 || option[2] != 0)
260 break;
261
262
263 if (option[3] > len_m4)
264 break;
265
266 switch (option[1]) {
267
268
269 case D6_OPT_IA_NA:
270 case D6_OPT_IA_PD:
271 option_to_env(option + 16, option + 4 + option[3]);
272 break;
273
274 case D6_OPT_IAADDR:
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291 if (option[3] < 24)
292 break;
293
294 sprint_nip6(ipv6str, option + 4);
295 *new_env() = xasprintf("ipv6=%s", ipv6str);
296
297 move_from_unaligned32(v32, option + 4 + 16 + 4);
298 *new_env() = xasprintf("lease=%u", (unsigned)v32);
299 break;
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316 case D6_OPT_IAPREFIX:
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334 move_from_unaligned32(v32, option + 4 + 4);
335 *new_env() = xasprintf("ipv6prefix_lease=%u", (unsigned)v32);
336
337 sprint_nip6(ipv6str, option + 4 + 4 + 4 + 1);
338 *new_env() = xasprintf("ipv6prefix=%s/%u", ipv6str, (unsigned)(option[4 + 4 + 4]));
339 break;
340#if ENABLE_FEATURE_UDHCPC6_RFC3646
341 case D6_OPT_DNS_SERVERS: {
342 char *dlist;
343
344
345 if ((option[3] & 0x0f) != 0)
346 break;
347
348
349 addrs = option[3] >> 4;
350
351
352 *new_env() = dlist = xmalloc(4 + addrs * 40 - 1);
353 dlist = stpcpy(dlist, "dns=");
354 option_offset = 0;
355
356 while (addrs--) {
357 sprint_nip6(dlist, option + 4 + option_offset);
358 dlist += 39;
359 option_offset += 16;
360 if (addrs)
361 *dlist++ = ' ';
362 }
363
364 break;
365 }
366 case D6_OPT_DOMAIN_LIST: {
367 char *dlist;
368
369 dlist = dname_dec(option + 4, (option[2] << 8) | option[3], "search=");
370 if (!dlist)
371 break;
372 *new_env() = dlist;
373 break;
374 }
375#endif
376#if ENABLE_FEATURE_UDHCPC6_RFC4704
377 case D6_OPT_CLIENT_FQDN: {
378 char *dlist;
379
380 if (option[3] == 0)
381 break;
382
383
384
385
386
387
388
389 if (option[4] & 0xf8) {
390 *new_env() = xasprintf("fqdn=%.*s", (int)option[3], (char*)option + 4);
391 break;
392 }
393 dlist = dname_dec(option + 5, ( option[3]) - 1, "fqdn=");
394 if (!dlist)
395 break;
396 *new_env() = dlist;
397 break;
398 }
399#endif
400#if ENABLE_FEATURE_UDHCPC6_RFC4833
401
402 case D6_OPT_TZ_POSIX:
403 *new_env() = xasprintf("tz=%.*s", (int)option[3], (char*)option + 4);
404 break;
405 case D6_OPT_TZ_NAME:
406 *new_env() = xasprintf("tz_name=%.*s", (int)option[3], (char*)option + 4);
407 break;
408#endif
409 case D6_OPT_BOOT_URL:
410 case D6_OPT_BOOT_PARAM:
411 case 0xd1:
412 case 0xd2:
413 {
414 char *tmp = string_option_to_env(option, option_end);
415 if (tmp)
416 *new_env() = tmp;
417 break;
418 }
419 }
420 len_m4 -= 4 + option[3];
421 option += 4 + option[3];
422 }
423}
424
425static char **fill_envp(const uint8_t *option, const uint8_t *option_end)
426{
427 char **envp, **curr;
428
429 client6_data.env_ptr = NULL;
430 client6_data.env_idx = 0;
431
432 *new_env() = xasprintf("interface=%s", client_data.interface);
433
434 if (option)
435 option_to_env(option, option_end);
436
437 envp = curr = client6_data.env_ptr;
438 while (*curr)
439 putenv(*curr++);
440
441 return envp;
442}
443
444
445static void d6_run_script(const uint8_t *option, const uint8_t *option_end,
446 const char *name)
447{
448 char **envp, **curr;
449 char *argv[3];
450
451 envp = fill_envp(option, option_end);
452
453
454 log1("executing %s %s", client_data.script, name);
455 argv[0] = (char*) client_data.script;
456 argv[1] = (char*) name;
457 argv[2] = NULL;
458 spawn_and_wait(argv);
459
460 for (curr = envp; *curr; curr++) {
461 log2(" %s", *curr);
462 bb_unsetenv_and_free(*curr);
463 }
464 free(envp);
465}
466
467
468static void d6_run_script_no_option(const char *name)
469{
470 d6_run_script(NULL, NULL, name);
471}
472
473
474
475static ALWAYS_INLINE uint32_t random_xid(void)
476{
477 uint32_t t = rand() & htonl(0x00ffffff);
478 return t;
479}
480
481
482static uint8_t *init_d6_packet(struct d6_packet *packet, char type)
483{
484 uint8_t *ptr;
485 unsigned secs;
486
487 memset(packet, 0, sizeof(*packet));
488
489 packet->d6_xid32 = client_data.xid;
490 packet->d6_msg_type = type;
491
492
493
494
495 ptr = packet->d6_options;
496 *((uint32_t*)ptr) = htonl((D6_OPT_ELAPSED_TIME << 16) + 2);
497 ptr += 4;
498 client_data.last_secs = monotonic_sec();
499 if (client_data.first_secs == 0)
500 client_data.first_secs = client_data.last_secs;
501 secs = client_data.last_secs - client_data.first_secs;
502 *((uint16_t*)ptr) = (secs < 0xffff) ? htons(secs) : 0xffff;
503 ptr += 2;
504
505 return ptr;
506}
507
508static uint8_t *add_d6_client_options(uint8_t *ptr)
509{
510 struct option_set *curr;
511 uint8_t *start = ptr;
512 unsigned option;
513 uint16_t len;
514
515 ptr += 4;
516 for (option = 1; option < 256; option++) {
517 if (client_data.opt_mask[option >> 3] & (1 << (option & 7))) {
518 ptr[0] = (option >> 8);
519 ptr[1] = option;
520 ptr += 2;
521 }
522 }
523
524 if ((ptr - start - 4) != 0) {
525 start[0] = (D6_OPT_ORO >> 8);
526 start[1] = D6_OPT_ORO;
527 start[2] = ((ptr - start - 4) >> 8);
528 start[3] = (ptr - start - 4);
529 } else
530 ptr = start;
531
532#if ENABLE_FEATURE_UDHCPC6_RFC4704
533 ptr = mempcpy(ptr, &opt_fqdn_req, sizeof(opt_fqdn_req));
534#endif
535
536 curr = client_data.options;
537 while (curr) {
538 len = (curr->data[D6_OPT_LEN] << 8) | curr->data[D6_OPT_LEN + 1];
539 ptr = mempcpy(ptr, curr->data, D6_OPT_DATA + len);
540 curr = curr->next;
541 }
542
543 return ptr;
544}
545
546static int d6_mcast_from_client_data_ifindex(struct d6_packet *packet, uint8_t *end)
547{
548
549 static const uint8_t FF02__1_2[16] = {
550 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
551 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02,
552 };
553
554 static const uint8_t MAC_DHCP6MCAST_ADDR[6] ALIGN2 = {
555 0x33, 0x33, 0x00, 0x01, 0x00, 0x02,
556 };
557
558 return d6_send_raw_packet_from_client_data_ifindex(
559 packet, (end - (uint8_t*) packet),
560 &client6_data.ll_ip6, CLIENT_PORT6,
561 (struct in6_addr*)FF02__1_2, SERVER_PORT6, MAC_DHCP6MCAST_ADDR
562 );
563}
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588static NOINLINE int send_d6_info_request(void)
589{
590 struct d6_packet packet;
591 uint8_t *opt_ptr;
592
593
594 opt_ptr = init_d6_packet(&packet, D6_MSG_INFORMATION_REQUEST);
595
596
597
598
599 opt_ptr = add_d6_client_options(opt_ptr);
600
601 bb_error_msg("sending %s", "info request");
602 return d6_mcast_from_client_data_ifindex(&packet, opt_ptr);
603}
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687static NOINLINE int send_d6_discover(struct in6_addr *requested_ipv6)
688{
689 struct d6_packet packet;
690 uint8_t *opt_ptr;
691 unsigned len;
692
693
694 opt_ptr = init_d6_packet(&packet, D6_MSG_SOLICIT);
695
696
697 free(client6_data.ia_na);
698 client6_data.ia_na = NULL;
699 if (option_mask32 & OPT_r) {
700 len = requested_ipv6 ? 2+2+4+4+4 + 2+2+16+4+4 : 2+2+4+4+4;
701 client6_data.ia_na = xzalloc(len);
702 client6_data.ia_na->code = D6_OPT_IA_NA;
703 client6_data.ia_na->len = len - 4;
704 *(bb__aliased_uint32_t*)client6_data.ia_na->data = rand();
705 if (requested_ipv6) {
706 struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4);
707 iaaddr->code = D6_OPT_IAADDR;
708 iaaddr->len = 16+4+4;
709 memcpy(iaaddr->data, requested_ipv6, 16);
710 }
711 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, len);
712 }
713
714
715 free(client6_data.ia_pd);
716 client6_data.ia_pd = NULL;
717 if (option_mask32 & OPT_d) {
718 len = 2+2+4+4+4;
719 client6_data.ia_pd = xzalloc(len);
720 client6_data.ia_pd->code = D6_OPT_IA_PD;
721 client6_data.ia_pd->len = len - 4;
722 *(bb__aliased_uint32_t*)client6_data.ia_pd->data = rand();
723 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, len);
724 }
725
726
727
728
729 opt_ptr = add_d6_client_options(opt_ptr);
730
731 bb_info_msg("sending %s", "discover");
732 return d6_mcast_from_client_data_ifindex(&packet, opt_ptr);
733}
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766static NOINLINE int send_d6_select(void)
767{
768 struct d6_packet packet;
769 uint8_t *opt_ptr;
770
771
772 opt_ptr = init_d6_packet(&packet, D6_MSG_REQUEST);
773
774
775 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
776
777 if (client6_data.ia_na)
778 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
779
780 if (client6_data.ia_pd)
781 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2);
782
783
784
785
786 opt_ptr = add_d6_client_options(opt_ptr);
787
788 bb_info_msg("sending %s", "select");
789 return d6_mcast_from_client_data_ifindex(&packet, opt_ptr);
790}
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839static NOINLINE int send_d6_renew(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6)
840{
841 struct d6_packet packet;
842 uint8_t *opt_ptr;
843
844
845 opt_ptr = init_d6_packet(&packet, DHCPREQUEST);
846
847
848 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
849
850 if (client6_data.ia_na)
851 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
852
853 if (client6_data.ia_pd)
854 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2);
855
856
857
858
859 opt_ptr = add_d6_client_options(opt_ptr);
860
861 bb_info_msg("sending %s", "renew");
862 if (server_ipv6)
863 return d6_send_kernel_packet_from_client_data_ifindex(
864 &packet, (opt_ptr - (uint8_t*) &packet),
865 our_cur_ipv6, CLIENT_PORT6,
866 server_ipv6, SERVER_PORT6
867 );
868 return d6_mcast_from_client_data_ifindex(&packet, opt_ptr);
869}
870
871
872static
873ALWAYS_INLINE
874int send_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6)
875{
876 struct d6_packet packet;
877 uint8_t *opt_ptr;
878 struct option_set *ci;
879
880
881 opt_ptr = init_d6_packet(&packet, D6_MSG_RELEASE);
882
883 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
884
885 if (client6_data.ia_na)
886 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
887
888 if (client6_data.ia_pd)
889 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2);
890
891
892 ci = udhcp_find_option(client_data.options, D6_OPT_CLIENTID, 1);
893 if (ci)
894 opt_ptr = mempcpy(opt_ptr, ci->data, D6_OPT_DATA + 2+2 + 6);
895
896 bb_info_msg("sending %s", "release");
897 return d6_send_kernel_packet_from_client_data_ifindex(
898 &packet, (opt_ptr - (uint8_t*) &packet),
899 our_cur_ipv6, CLIENT_PORT6,
900 server_ipv6, SERVER_PORT6
901 );
902}
903
904
905
906static NOINLINE int d6_recv_raw_packet(struct in6_addr *peer_ipv6, struct d6_packet *d6_pkt, int fd)
907{
908 int bytes;
909 struct ip6_udp_d6_packet packet;
910
911 bytes = safe_read(fd, &packet, sizeof(packet));
912 if (bytes < 0) {
913 log1s("packet read error, ignoring");
914
915 return bytes;
916 }
917
918 if (bytes < (int) (sizeof(packet.ip6) + sizeof(packet.udp))) {
919 log1s("packet is too short, ignoring");
920 return -2;
921 }
922
923 if (bytes < sizeof(packet.ip6) + ntohs(packet.ip6.ip6_plen)) {
924
925 log1s("oversized packet, ignoring");
926 return -2;
927 }
928
929
930 bytes = sizeof(packet.ip6) + ntohs(packet.ip6.ip6_plen);
931
932
933 if (packet.ip6.ip6_nxt != IPPROTO_UDP
934 || (packet.ip6.ip6_vfc >> 4) != 6
935 || packet.udp.dest != htons(CLIENT_PORT6)
936
937 || packet.udp.len != packet.ip6.ip6_plen
938 ) {
939 log1s("unrelated/bogus packet, ignoring");
940 return -2;
941 }
942
943
944
945
946
947
948
949
950
951
952
953
954
955 if (peer_ipv6)
956 *peer_ipv6 = packet.ip6.ip6_src;
957
958 log2("received %s", "a packet");
959
960 d6_dump_packet(&packet.data);
961
962 bytes -= sizeof(packet.ip6) + sizeof(packet.udp);
963 memcpy(d6_pkt, &packet.data, bytes);
964 return bytes;
965}
966
967
968
969
970#define LISTEN_NONE 0
971#define LISTEN_KERNEL 1
972#define LISTEN_RAW 2
973
974
975
976#define INIT_SELECTING 0
977
978#define REQUESTING 1
979
980#define BOUND 2
981
982#define RENEWING 3
983
984#define REBINDING 4
985
986#define RENEW_REQUESTED 5
987
988#define RELEASED 6
989
990static int d6_raw_socket(int ifindex)
991{
992 int fd;
993 struct sockaddr_ll sock;
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016#if 0
1017 static const struct sock_filter filter_instr[] = {
1018
1019 BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
1020
1021 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6),
1022
1023 BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6),
1024
1025 BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0),
1026
1027 BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0),
1028
1029 BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2),
1030
1031 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1),
1032
1033 BPF_STMT(BPF_RET|BPF_K, 0x7fffffff),
1034
1035 BPF_STMT(BPF_RET|BPF_K, 0),
1036 };
1037 static const struct sock_fprog filter_prog = {
1038 .len = sizeof(filter_instr) / sizeof(filter_instr[0]),
1039
1040 .filter = (struct sock_filter *) filter_instr,
1041 };
1042#endif
1043
1044 log2("opening raw socket on ifindex %d", ifindex);
1045
1046 fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6));
1047
1048 memset(&sock, 0, sizeof(sock));
1049 sock.sll_family = AF_PACKET;
1050 sock.sll_protocol = htons(ETH_P_IPV6);
1051 sock.sll_ifindex = ifindex;
1052
1053
1054
1055
1056 xbind(fd, (struct sockaddr *) &sock, sizeof(sock));
1057
1058#if 0
1059 if (CLIENT_PORT6 == 546) {
1060
1061
1062 if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog,
1063 sizeof(filter_prog)) >= 0)
1064 log1("attached filter to raw socket fd %d", fd);
1065 }
1066#endif
1067 return fd;
1068}
1069
1070static void change_listen_mode(int new_mode)
1071{
1072 log1("entering listen mode: %s",
1073 new_mode != LISTEN_NONE
1074 ? (new_mode == LISTEN_KERNEL ? "kernel" : "raw")
1075 : "none"
1076 );
1077
1078 client_data.listen_mode = new_mode;
1079 if (client_data.sockfd >= 0) {
1080 close(client_data.sockfd);
1081 client_data.sockfd = -1;
1082 }
1083 if (new_mode == LISTEN_KERNEL)
1084 client_data.sockfd = udhcp_listen_socket( CLIENT_PORT6, client_data.interface);
1085 else if (new_mode != LISTEN_NONE)
1086 client_data.sockfd = d6_raw_socket(client_data.ifindex);
1087
1088}
1089
1090static void perform_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6)
1091{
1092 change_listen_mode(LISTEN_NONE);
1093
1094
1095 if (client_data.state == BOUND
1096 || client_data.state == RENEWING
1097 || client_data.state == REBINDING
1098 || client_data.state == RENEW_REQUESTED
1099 ) {
1100 bb_simple_info_msg("unicasting a release");
1101 client_data.xid = random_xid();
1102 send_d6_release(server_ipv6, our_cur_ipv6);
1103 }
1104 bb_simple_info_msg("entering released state");
1105
1106
1107
1108
1109
1110
1111 d6_run_script_no_option("deconfig");
1112 client_data.state = RELEASED;
1113}
1114
1115#if BB_MMU
1116static void client_background(void)
1117{
1118 bb_daemonize(0);
1119 logmode &= ~LOGMODE_STDIO;
1120
1121 write_pidfile(client_data.pidfile);
1122}
1123#endif
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174int udhcpc6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1175int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1176{
1177 const char *str_r;
1178 IF_FEATURE_UDHCP_PORT(char *str_P;)
1179 uint8_t *clientid_mac_ptr;
1180 llist_t *list_O = NULL;
1181 llist_t *list_x = NULL;
1182 int tryagain_timeout = 20;
1183 int discover_timeout = 3;
1184 int discover_retries = 3;
1185 struct in6_addr srv6_buf;
1186 struct in6_addr ipv6_buf;
1187 struct in6_addr *requested_ipv6;
1188 int packet_num;
1189 int timeout;
1190 int lease_remaining;
1191 unsigned opt;
1192 int retval;
1193
1194 setup_common_bufsiz();
1195
1196 srand(monotonic_us());
1197
1198
1199 IF_FEATURE_UDHCP_PORT(SERVER_PORT6 = 547;)
1200 IF_FEATURE_UDHCP_PORT(CLIENT_PORT6 = 546;)
1201 client_data.interface = CONFIG_UDHCPC_DEFAULT_INTERFACE;
1202 client_data.script = CONFIG_UDHCPC_DEFAULT_SCRIPT;
1203 client_data.sockfd = -1;
1204
1205
1206
1207 udhcp_sp_setup();
1208
1209
1210 opt = getopt32long(argv, "^"
1211
1212 "i:np:qRr:s:T:+t:+SA:+O:*ox:*fld"
1213 USE_FOR_MMU("b")
1214
1215 IF_FEATURE_UDHCP_PORT("P:")
1216 "v"
1217 "\0" IF_UDHCP_VERBOSE("vv")
1218 , udhcpc6_longopts
1219 , &client_data.interface, &client_data.pidfile, &str_r
1220 , &client_data.script
1221 , &discover_timeout, &discover_retries, &tryagain_timeout
1222 , &list_O
1223 , &list_x
1224 IF_FEATURE_UDHCP_PORT(, &str_P)
1225 IF_UDHCP_VERBOSE(, &dhcp_verbose)
1226 );
1227 requested_ipv6 = NULL;
1228 option_mask32 |= OPT_r;
1229 if (opt & OPT_l) {
1230
1231 option_mask32 &= ~OPT_r;
1232 } else if (opt & OPT_r) {
1233
1234 if (strcmp(str_r, "no") == 0) {
1235 option_mask32 &= ~OPT_r;
1236 } else {
1237 if (inet_pton(AF_INET6, str_r, &ipv6_buf) <= 0)
1238 bb_error_msg_and_die("bad IPv6 address '%s'", str_r);
1239 requested_ipv6 = &ipv6_buf;
1240 }
1241 }
1242
1243#if ENABLE_FEATURE_UDHCP_PORT
1244 if (opt & OPT_P) {
1245 CLIENT_PORT6 = xatou16(str_P);
1246 SERVER_PORT6 = CLIENT_PORT6 + 1;
1247 }
1248#endif
1249 while (list_O) {
1250 char *optstr = llist_pop(&list_O);
1251 unsigned n = bb_strtou(optstr, NULL, 0);
1252 if (errno || n > 254) {
1253 n = udhcp_option_idx(optstr, d6_option_strings);
1254 n = d6_optflags[n].code;
1255 }
1256 client_data.opt_mask[n >> 3] |= 1 << (n & 7);
1257 }
1258 if (!(opt & OPT_o)) {
1259 unsigned i, n;
1260 for (i = 0; (n = d6_optflags[i].code) != 0; i++) {
1261 if (d6_optflags[i].flags & OPTION_REQ) {
1262 client_data.opt_mask[n >> 3] |= 1 << (n & 7);
1263 }
1264 }
1265 }
1266 while (list_x) {
1267 char *optstr = xstrdup(llist_pop(&list_x));
1268 udhcp_str2optset(optstr, &client_data.options,
1269 d6_optflags, d6_option_strings,
1270 1
1271 );
1272 free(optstr);
1273 }
1274
1275 clientid_mac_ptr = NULL;
1276 if (!udhcp_find_option(client_data.options, D6_OPT_CLIENTID, 1)) {
1277
1278 clientid_mac_ptr = udhcp_insert_new_option(
1279 &client_data.options, D6_OPT_CLIENTID,
1280 2+2 + 6, 1);
1281 clientid_mac_ptr += 2+2;
1282 clientid_mac_ptr[1] = 3;
1283 clientid_mac_ptr[3] = 1;
1284 clientid_mac_ptr += 2+2;
1285 }
1286
1287 if (d6_read_interface(client_data.interface,
1288 &client_data.ifindex,
1289 &client6_data.ll_ip6,
1290 client_data.client_mac)
1291 ) {
1292 return 1;
1293 }
1294
1295#if !BB_MMU
1296
1297 if (!(opt & OPT_f)) {
1298 bb_daemonize_or_rexec(0 , argv);
1299 logmode = LOGMODE_NONE;
1300 }
1301#endif
1302 if (opt & OPT_S) {
1303 openlog(applet_name, LOG_PID, LOG_DAEMON);
1304 logmode |= LOGMODE_SYSLOG;
1305 }
1306
1307
1308 write_pidfile(client_data.pidfile);
1309
1310 bb_simple_info_msg("started, v"BB_VER);
1311
1312 client_data.state = INIT_SELECTING;
1313 d6_run_script_no_option("deconfig");
1314 packet_num = 0;
1315 timeout = 0;
1316 lease_remaining = 0;
1317
1318
1319
1320
1321
1322 for (;;) {
1323 struct pollfd pfds[2];
1324 struct d6_packet packet;
1325 uint8_t *packet_end;
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336 udhcp_sp_fd_set(pfds, client_data.sockfd);
1337
1338 retval = 0;
1339
1340 if (timeout > 0) {
1341 unsigned diff;
1342
1343 if (timeout > INT_MAX/1000)
1344 timeout = INT_MAX/1000;
1345 log1("waiting %u seconds", timeout);
1346 diff = (unsigned)monotonic_sec();
1347 retval = poll(pfds, 2, timeout * 1000);
1348 diff = (unsigned)monotonic_sec() - diff;
1349 lease_remaining -= diff;
1350 if (lease_remaining < 0)
1351 lease_remaining = 0;
1352 timeout -= diff;
1353 if (timeout < 0)
1354 timeout = 0;
1355
1356 if (retval < 0) {
1357
1358 if (errno == EINTR) {
1359 continue;
1360 }
1361
1362 bb_simple_perror_msg_and_die("poll");
1363 }
1364 }
1365
1366
1367
1368
1369 if (retval == 0) {
1370
1371
1372
1373
1374
1375 if (d6_read_interface(client_data.interface,
1376 &client_data.ifindex,
1377 &client6_data.ll_ip6,
1378 client_data.client_mac)
1379 ) {
1380 goto ret0;
1381 }
1382
1383 if (clientid_mac_ptr)
1384 memcpy(clientid_mac_ptr, client_data.client_mac, 6);
1385
1386 switch (client_data.state) {
1387 case INIT_SELECTING:
1388 if (!discover_retries || packet_num < discover_retries) {
1389 if (packet_num == 0) {
1390 change_listen_mode(LISTEN_RAW);
1391 client_data.xid = random_xid();
1392 }
1393
1394 if (opt & OPT_l)
1395 send_d6_info_request();
1396 else
1397 send_d6_discover(requested_ipv6);
1398 timeout = discover_timeout;
1399 packet_num++;
1400 continue;
1401 }
1402 leasefail:
1403 change_listen_mode(LISTEN_NONE);
1404 d6_run_script_no_option("leasefail");
1405#if BB_MMU
1406 if (opt & OPT_b) {
1407 bb_simple_info_msg("no lease, forking to background");
1408 client_background();
1409
1410 opt = ((opt & ~(OPT_b|OPT_n)) | OPT_f);
1411
1412
1413
1414
1415
1416
1417 } else
1418#endif
1419 if (opt & OPT_n) {
1420 bb_simple_info_msg("no lease, failing");
1421 retval = 1;
1422 goto ret;
1423 }
1424
1425 timeout = tryagain_timeout;
1426 packet_num = 0;
1427 continue;
1428 case REQUESTING:
1429 if (!discover_retries || packet_num < discover_retries) {
1430
1431 send_d6_select();
1432 timeout = discover_timeout;
1433 packet_num++;
1434 continue;
1435 }
1436
1437
1438
1439
1440 client_data.state = INIT_SELECTING;
1441 goto leasefail;
1442 case BOUND:
1443
1444 client_data.state = RENEWING;
1445 client_data.first_secs = 0;
1446 got_SIGUSR1:
1447 log1s("entering renew state");
1448 change_listen_mode(LISTEN_KERNEL);
1449
1450 case RENEW_REQUESTED:
1451 case RENEWING:
1452 if (packet_num == 0) {
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462 if (opt & OPT_l)
1463 send_d6_info_request();
1464 else
1465 send_d6_renew(&srv6_buf, requested_ipv6);
1466 timeout = discover_timeout;
1467 packet_num++;
1468 continue;
1469 }
1470 log1s("no response to renew");
1471 if (lease_remaining > 30) {
1472
1473 change_listen_mode(LISTEN_NONE);
1474 goto BOUND_for_half_lease;
1475 }
1476
1477 client_data.state = REBINDING;
1478 log1s("entering rebinding state");
1479
1480 change_listen_mode(LISTEN_RAW);
1481 packet_num = 0;
1482
1483 case REBINDING:
1484
1485
1486 if (lease_remaining > 0 && packet_num < 3) {
1487 if (opt & OPT_l)
1488 send_d6_info_request();
1489 else
1490 send_d6_renew( NULL, requested_ipv6);
1491 timeout = discover_timeout;
1492 packet_num++;
1493 continue;
1494 }
1495
1496 change_listen_mode(LISTEN_NONE);
1497 bb_simple_info_msg("lease lost, entering init state");
1498 d6_run_script_no_option("deconfig");
1499 client_data.state = INIT_SELECTING;
1500 client_data.first_secs = 0;
1501 timeout = 0;
1502 packet_num = 0;
1503 continue;
1504
1505 }
1506
1507
1508
1509 timeout = INT_MAX;
1510 continue;
1511 }
1512
1513
1514
1515
1516 switch (udhcp_sp_read()) {
1517 case SIGUSR1:
1518 if (client_data.state <= REQUESTING)
1519
1520 break;
1521 if (client_data.state == REBINDING)
1522
1523 break;
1524
1525 if (lease_remaining > 30)
1526 lease_remaining = 30;
1527 client_data.first_secs = 0;
1528 packet_num = 0;
1529
1530 switch (client_data.state) {
1531 case BOUND:
1532 case RENEWING:
1533
1534 change_listen_mode(LISTEN_KERNEL);
1535 client_data.state = RENEW_REQUESTED;
1536 goto got_SIGUSR1;
1537
1538 case RENEW_REQUESTED:
1539
1540 change_listen_mode(LISTEN_NONE);
1541 d6_run_script_no_option("deconfig");
1542
1543 default:
1544
1545
1546 change_listen_mode(LISTEN_NONE);
1547 }
1548 client_data.state = INIT_SELECTING;
1549
1550 timeout = 0;
1551 continue;
1552 case SIGUSR2:
1553 perform_d6_release(&srv6_buf, requested_ipv6);
1554
1555 timeout = INT_MAX;
1556 continue;
1557 case SIGTERM:
1558 bb_info_msg("received %s", "SIGTERM");
1559 goto ret0;
1560 }
1561
1562
1563 if (!pfds[1].revents)
1564 continue;
1565
1566 {
1567 int len;
1568
1569
1570 if (client_data.listen_mode == LISTEN_KERNEL)
1571 len = d6_recv_kernel_packet(&srv6_buf, &packet, client_data.sockfd);
1572 else
1573 len = d6_recv_raw_packet(&srv6_buf, &packet, client_data.sockfd);
1574 if (len == -1) {
1575
1576 bb_error_msg("read error: "STRERROR_FMT", reopening socket" STRERROR_ERRNO);
1577 sleep(discover_timeout);
1578 change_listen_mode(client_data.listen_mode);
1579 }
1580 if (len < 0)
1581 continue;
1582 packet_end = (uint8_t*)&packet + len;
1583 }
1584
1585 if ((packet.d6_xid32 & htonl(0x00ffffff)) != client_data.xid) {
1586 log1("xid %x (our is %x)%s",
1587 (unsigned)(packet.d6_xid32 & htonl(0x00ffffff)), (unsigned)client_data.xid,
1588 ", ignoring packet"
1589 );
1590 continue;
1591 }
1592
1593 switch (client_data.state) {
1594 case INIT_SELECTING:
1595 if (packet.d6_msg_type == D6_MSG_ADVERTISE)
1596 goto type_is_ok;
1597
1598
1599
1600
1601 case REQUESTING:
1602 case RENEWING:
1603 case RENEW_REQUESTED:
1604 case REBINDING:
1605 if (packet.d6_msg_type == D6_MSG_REPLY) {
1606 unsigned start;
1607 uint32_t lease_seconds;
1608 struct d6_option *option;
1609 unsigned address_timeout;
1610 unsigned prefix_timeout;
1611 type_is_ok:
1612 change_listen_mode(LISTEN_NONE);
1613
1614 address_timeout = 0;
1615 prefix_timeout = 0;
1616 option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE);
1617 if (option && (option->data[0] | option->data[1]) != 0) {
1618
1619 bb_info_msg("received DHCP NAK (%u)", option->data[4]);
1620 d6_run_script(packet.d6_options,
1621 packet_end, "nak");
1622 if (client_data.state != REQUESTING)
1623 d6_run_script_no_option("deconfig");
1624 sleep(3);
1625 client_data.state = INIT_SELECTING;
1626 client_data.first_secs = 0;
1627 requested_ipv6 = NULL;
1628 timeout = 0;
1629 packet_num = 0;
1630 continue;
1631 }
1632 option = d6_copy_option(packet.d6_options, packet_end, D6_OPT_SERVERID);
1633 if (!option) {
1634 bb_simple_info_msg("no server ID, ignoring packet");
1635 continue;
1636
1637 }
1638
1639
1640
1641 free(client6_data.server_id);
1642 client6_data.server_id = option;
1643 if (packet.d6_msg_type == D6_MSG_ADVERTISE) {
1644
1645 change_listen_mode(LISTEN_RAW);
1646 client_data.state = REQUESTING;
1647 timeout = 0;
1648 packet_num = 0;
1649 continue;
1650 }
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737 if (option_mask32 & OPT_r) {
1738 struct d6_option *iaaddr;
1739
1740 free(client6_data.ia_na);
1741 client6_data.ia_na = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_NA);
1742 if (!client6_data.ia_na) {
1743 bb_info_msg("no %s option%s", "IA_NA", ", ignoring packet");
1744 continue;
1745 }
1746 if (client6_data.ia_na->len < (4 + 4 + 4) + (2 + 2 + 16 + 4 + 4)) {
1747 bb_info_msg("%s option is too short:%d bytes",
1748 "IA_NA", client6_data.ia_na->len);
1749 continue;
1750 }
1751 iaaddr = d6_find_option(client6_data.ia_na->data + 4 + 4 + 4,
1752 client6_data.ia_na->data + client6_data.ia_na->len,
1753 D6_OPT_IAADDR
1754 );
1755 if (!iaaddr) {
1756 bb_info_msg("no %s option%s", "IAADDR", ", ignoring packet");
1757 continue;
1758 }
1759 if (iaaddr->len < (16 + 4 + 4)) {
1760 bb_info_msg("%s option is too short:%d bytes",
1761 "IAADDR", iaaddr->len);
1762 continue;
1763 }
1764
1765
1766
1767 requested_ipv6 = (struct in6_addr*) iaaddr->data;
1768 move_from_unaligned32(lease_seconds, iaaddr->data + 16 + 4);
1769 lease_seconds = ntohl(lease_seconds);
1770
1771 bb_info_msg("%s obtained, lease time %u",
1772 "IPv6", (unsigned)lease_seconds);
1773 address_timeout = lease_seconds;
1774 }
1775 if (option_mask32 & OPT_d) {
1776 struct d6_option *iaprefix;
1777
1778 free(client6_data.ia_pd);
1779 client6_data.ia_pd = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_PD);
1780 if (!client6_data.ia_pd) {
1781 bb_info_msg("no %s option%s", "IA_PD", ", ignoring packet");
1782 continue;
1783 }
1784 if (client6_data.ia_pd->len < (4 + 4 + 4) + (2 + 2 + 4 + 4 + 1 + 16)) {
1785 bb_info_msg("%s option is too short:%d bytes",
1786 "IA_PD", client6_data.ia_pd->len);
1787 continue;
1788 }
1789 iaprefix = d6_find_option(client6_data.ia_pd->data + 4 + 4 + 4,
1790 client6_data.ia_pd->data + client6_data.ia_pd->len,
1791 D6_OPT_IAPREFIX
1792 );
1793 if (!iaprefix) {
1794 bb_info_msg("no %s option%s", "IAPREFIX", ", ignoring packet");
1795 continue;
1796 }
1797 if (iaprefix->len < (4 + 4 + 1 + 16)) {
1798 bb_info_msg("%s option is too short:%d bytes",
1799 "IAPREFIX", iaprefix->len);
1800 continue;
1801 }
1802 move_from_unaligned32(lease_seconds, iaprefix->data + 4);
1803 lease_seconds = ntohl(lease_seconds);
1804 bb_info_msg("%s obtained, lease time %u",
1805 "prefix", (unsigned)lease_seconds);
1806 prefix_timeout = lease_seconds;
1807 }
1808 if (!address_timeout)
1809 address_timeout = prefix_timeout;
1810 if (!prefix_timeout)
1811 prefix_timeout = address_timeout;
1812 lease_remaining = (prefix_timeout < address_timeout ? prefix_timeout : address_timeout);
1813 if (lease_remaining < 0)
1814 lease_remaining = INT_MAX;
1815 if (opt & OPT_l) {
1816
1817
1818
1819 lease_remaining = 24 * 60 * 60;
1820 }
1821
1822 if (lease_remaining < 30)
1823 lease_remaining = 30;
1824
1825
1826 start = monotonic_sec();
1827 d6_run_script(packet.d6_options, packet_end,
1828 (client_data.state == REQUESTING ? "bound" : "renew"));
1829 lease_remaining -= (unsigned)monotonic_sec() - start;
1830 if (lease_remaining < 0)
1831 lease_remaining = 0;
1832 if (opt & OPT_q) {
1833 goto ret0;
1834 }
1835
1836 opt &= ~OPT_n;
1837#if BB_MMU
1838 if (!(opt & OPT_f)) {
1839 client_background();
1840
1841 opt = ((opt & ~OPT_b) | OPT_f);
1842 }
1843#endif
1844
1845 BOUND_for_half_lease:
1846 timeout = (unsigned)lease_remaining / 2;
1847 client_data.state = BOUND;
1848 packet_num = 0;
1849 continue;
1850 }
1851 continue;
1852
1853
1854 }
1855
1856 }
1857
1858 ret0:
1859 if (opt & OPT_R)
1860 perform_d6_release(&srv6_buf, requested_ipv6);
1861 retval = 0;
1862 ret:
1863
1864 remove_pidfile(client_data.pidfile);
1865 return retval;
1866}
1867