Sync with dhcpcd-9.3.2diff -r1.41 -r1.42 src/external/bsd/dhcpcd/dist/src/dhcp.c
(roy)
--- src/external/bsd/dhcpcd/dist/src/dhcp.c 2020/10/12 14:09:03 1.41
+++ src/external/bsd/dhcpcd/dist/src/dhcp.c 2020/11/01 14:24:01 1.42
@@ -524,3661 +524,3714 @@ get_option_string(struct dhcpcd_ctx *ctx | @@ -524,3661 +524,3714 @@ get_option_string(struct dhcpcd_ctx *ctx | |||
524 | { | 524 | { | |
525 | size_t len; | 525 | size_t len; | |
526 | const uint8_t *p; | 526 | const uint8_t *p; | |
527 | char *s; | 527 | char *s; | |
528 | 528 | |||
529 | p = get_option(ctx, bootp, bootp_len, option, &len); | 529 | p = get_option(ctx, bootp, bootp_len, option, &len); | |
530 | if (!p || len == 0 || *p == '\0') | 530 | if (!p || len == 0 || *p == '\0') | |
531 | return NULL; | 531 | return NULL; | |
532 | 532 | |||
533 | s = malloc(sizeof(char) * (len + 1)); | 533 | s = malloc(sizeof(char) * (len + 1)); | |
534 | if (s) { | 534 | if (s) { | |
535 | memcpy(s, p, len); | 535 | memcpy(s, p, len); | |
536 | s[len] = '\0'; | 536 | s[len] = '\0'; | |
537 | } | 537 | } | |
538 | return s; | 538 | return s; | |
539 | } | 539 | } | |
540 | 540 | |||
541 | /* This calculates the netmask that we should use for static routes. | 541 | /* This calculates the netmask that we should use for static routes. | |
542 | * This IS different from the calculation used to calculate the netmask | 542 | * This IS different from the calculation used to calculate the netmask | |
543 | * for an interface address. */ | 543 | * for an interface address. */ | |
544 | static uint32_t | 544 | static uint32_t | |
545 | route_netmask(uint32_t ip_in) | 545 | route_netmask(uint32_t ip_in) | |
546 | { | 546 | { | |
547 | /* used to be unsigned long - check if error */ | 547 | /* used to be unsigned long - check if error */ | |
548 | uint32_t p = ntohl(ip_in); | 548 | uint32_t p = ntohl(ip_in); | |
549 | uint32_t t; | 549 | uint32_t t; | |
550 | 550 | |||
551 | if (IN_CLASSA(p)) | 551 | if (IN_CLASSA(p)) | |
552 | t = ~IN_CLASSA_NET; | 552 | t = ~IN_CLASSA_NET; | |
553 | else { | 553 | else { | |
554 | if (IN_CLASSB(p)) | 554 | if (IN_CLASSB(p)) | |
555 | t = ~IN_CLASSB_NET; | 555 | t = ~IN_CLASSB_NET; | |
556 | else { | 556 | else { | |
557 | if (IN_CLASSC(p)) | 557 | if (IN_CLASSC(p)) | |
558 | t = ~IN_CLASSC_NET; | 558 | t = ~IN_CLASSC_NET; | |
559 | else | 559 | else | |
560 | t = 0; | 560 | t = 0; | |
561 | } | 561 | } | |
562 | } | 562 | } | |
563 | 563 | |||
564 | while (t & p) | 564 | while (t & p) | |
565 | t >>= 1; | 565 | t >>= 1; | |
566 | 566 | |||
567 | return (htonl(~t)); | 567 | return (htonl(~t)); | |
568 | } | 568 | } | |
569 | 569 | |||
570 | /* We need to obey routing options. | 570 | /* We need to obey routing options. | |
571 | * If we have a CSR then we only use that. | 571 | * If we have a CSR then we only use that. | |
572 | * Otherwise we add static routes and then routers. */ | 572 | * Otherwise we add static routes and then routers. */ | |
573 | static int | 573 | static int | |
574 | get_option_routes(rb_tree_t *routes, struct interface *ifp, | 574 | get_option_routes(rb_tree_t *routes, struct interface *ifp, | |
575 | const struct bootp *bootp, size_t bootp_len) | 575 | const struct bootp *bootp, size_t bootp_len) | |
576 | { | 576 | { | |
577 | struct if_options *ifo = ifp->options; | 577 | struct if_options *ifo = ifp->options; | |
578 | const uint8_t *p; | 578 | const uint8_t *p; | |
579 | const uint8_t *e; | 579 | const uint8_t *e; | |
580 | struct rt *rt = NULL; | 580 | struct rt *rt = NULL; | |
581 | struct in_addr dest, netmask, gateway; | 581 | struct in_addr dest, netmask, gateway; | |
582 | size_t len; | 582 | size_t len; | |
583 | const char *csr = ""; | 583 | const char *csr = ""; | |
584 | int n; | 584 | int n; | |
585 | 585 | |||
586 | /* If we have CSR's then we MUST use these only */ | 586 | /* If we have CSR's then we MUST use these only */ | |
587 | if (!has_option_mask(ifo->nomask, DHO_CSR)) | 587 | if (!has_option_mask(ifo->nomask, DHO_CSR)) | |
588 | p = get_option(ifp->ctx, bootp, bootp_len, DHO_CSR, &len); | 588 | p = get_option(ifp->ctx, bootp, bootp_len, DHO_CSR, &len); | |
589 | else | 589 | else | |
590 | p = NULL; | 590 | p = NULL; | |
591 | /* Check for crappy MS option */ | 591 | /* Check for crappy MS option */ | |
592 | if (!p && !has_option_mask(ifo->nomask, DHO_MSCSR)) { | 592 | if (!p && !has_option_mask(ifo->nomask, DHO_MSCSR)) { | |
593 | p = get_option(ifp->ctx, bootp, bootp_len, DHO_MSCSR, &len); | 593 | p = get_option(ifp->ctx, bootp, bootp_len, DHO_MSCSR, &len); | |
594 | if (p) | 594 | if (p) | |
595 | csr = "MS "; | 595 | csr = "MS "; | |
596 | } | 596 | } | |
597 | if (p && (n = decode_rfc3442_rt(routes, ifp, p, len, bootp)) != -1) { | 597 | if (p && (n = decode_rfc3442_rt(routes, ifp, p, len, bootp)) != -1) { | |
598 | const struct dhcp_state *state; | 598 | const struct dhcp_state *state; | |
599 | 599 | |||
600 | state = D_CSTATE(ifp); | 600 | state = D_CSTATE(ifp); | |
601 | if (!(ifo->options & DHCPCD_CSR_WARNED) && | 601 | if (!(ifo->options & DHCPCD_CSR_WARNED) && | |
602 | !(state->added & STATE_FAKE)) | 602 | !(state->added & STATE_FAKE)) | |
603 | { | 603 | { | |
604 | logdebugx("%s: using %sClassless Static Routes", | 604 | logdebugx("%s: using %sClassless Static Routes", | |
605 | ifp->name, csr); | 605 | ifp->name, csr); | |
606 | ifo->options |= DHCPCD_CSR_WARNED; | 606 | ifo->options |= DHCPCD_CSR_WARNED; | |
607 | } | 607 | } | |
608 | return n; | 608 | return n; | |
609 | } | 609 | } | |
610 | 610 | |||
611 | n = 0; | 611 | n = 0; | |
612 | /* OK, get our static routes first. */ | 612 | /* OK, get our static routes first. */ | |
613 | if (!has_option_mask(ifo->nomask, DHO_STATICROUTE)) | 613 | if (!has_option_mask(ifo->nomask, DHO_STATICROUTE)) | |
614 | p = get_option(ifp->ctx, bootp, bootp_len, | 614 | p = get_option(ifp->ctx, bootp, bootp_len, | |
615 | DHO_STATICROUTE, &len); | 615 | DHO_STATICROUTE, &len); | |
616 | else | 616 | else | |
617 | p = NULL; | 617 | p = NULL; | |
618 | /* RFC 2131 Section 5.8 states length MUST be in multiples of 8 */ | 618 | /* RFC 2131 Section 5.8 states length MUST be in multiples of 8 */ | |
619 | if (p && len % 8 == 0) { | 619 | if (p && len % 8 == 0) { | |
620 | e = p + len; | 620 | e = p + len; | |
621 | while (p < e) { | 621 | while (p < e) { | |
622 | memcpy(&dest.s_addr, p, sizeof(dest.s_addr)); | 622 | memcpy(&dest.s_addr, p, sizeof(dest.s_addr)); | |
623 | p += 4; | 623 | p += 4; | |
624 | memcpy(&gateway.s_addr, p, sizeof(gateway.s_addr)); | 624 | memcpy(&gateway.s_addr, p, sizeof(gateway.s_addr)); | |
625 | p += 4; | 625 | p += 4; | |
626 | /* RFC 2131 Section 5.8 states default route is | 626 | /* RFC 2131 Section 5.8 states default route is | |
627 | * illegal */ | 627 | * illegal */ | |
628 | if (gateway.s_addr == INADDR_ANY) | 628 | if (gateway.s_addr == INADDR_ANY) | |
629 | continue; | 629 | continue; | |
630 | if ((rt = rt_new(ifp)) == NULL) | 630 | if ((rt = rt_new(ifp)) == NULL) | |
631 | return -1; | 631 | return -1; | |
632 | 632 | |||
633 | /* A on-link host route is normally set by having the | 633 | /* A on-link host route is normally set by having the | |
634 | * gateway match the destination or assigned address */ | 634 | * gateway match the destination or assigned address */ | |
635 | if (gateway.s_addr == dest.s_addr || | 635 | if (gateway.s_addr == dest.s_addr || | |
636 | (gateway.s_addr == bootp->yiaddr || | 636 | (gateway.s_addr == bootp->yiaddr || | |
637 | gateway.s_addr == bootp->ciaddr)) | 637 | gateway.s_addr == bootp->ciaddr)) | |
638 | { | 638 | { | |
639 | gateway.s_addr = INADDR_ANY; | 639 | gateway.s_addr = INADDR_ANY; | |
640 | netmask.s_addr = INADDR_BROADCAST; | 640 | netmask.s_addr = INADDR_BROADCAST; | |
641 | } else | 641 | } else | |
642 | netmask.s_addr = route_netmask(dest.s_addr); | 642 | netmask.s_addr = route_netmask(dest.s_addr); | |
643 | if (netmask.s_addr == INADDR_BROADCAST) | 643 | if (netmask.s_addr == INADDR_BROADCAST) | |
644 | rt->rt_flags = RTF_HOST; | 644 | rt->rt_flags = RTF_HOST; | |
645 | 645 | |||
646 | sa_in_init(&rt->rt_dest, &dest); | 646 | sa_in_init(&rt->rt_dest, &dest); | |
647 | sa_in_init(&rt->rt_netmask, &netmask); | 647 | sa_in_init(&rt->rt_netmask, &netmask); | |
648 | sa_in_init(&rt->rt_gateway, &gateway); | 648 | sa_in_init(&rt->rt_gateway, &gateway); | |
649 | if (rt_proto_add(routes, rt)) | 649 | if (rt_proto_add(routes, rt)) | |
650 | n++; | 650 | n++; | |
651 | } | 651 | } | |
652 | } | 652 | } | |
653 | 653 | |||
654 | /* Now grab our routers */ | 654 | /* Now grab our routers */ | |
655 | if (!has_option_mask(ifo->nomask, DHO_ROUTER)) | 655 | if (!has_option_mask(ifo->nomask, DHO_ROUTER)) | |
656 | p = get_option(ifp->ctx, bootp, bootp_len, DHO_ROUTER, &len); | 656 | p = get_option(ifp->ctx, bootp, bootp_len, DHO_ROUTER, &len); | |
657 | else | 657 | else | |
658 | p = NULL; | 658 | p = NULL; | |
659 | if (p && len % 4 == 0) { | 659 | if (p && len % 4 == 0) { | |
660 | e = p + len; | 660 | e = p + len; | |
661 | dest.s_addr = INADDR_ANY; | 661 | dest.s_addr = INADDR_ANY; | |
662 | netmask.s_addr = INADDR_ANY; | 662 | netmask.s_addr = INADDR_ANY; | |
663 | while (p < e) { | 663 | while (p < e) { | |
664 | if ((rt = rt_new(ifp)) == NULL) | 664 | if ((rt = rt_new(ifp)) == NULL) | |
665 | return -1; | 665 | return -1; | |
666 | memcpy(&gateway.s_addr, p, sizeof(gateway.s_addr)); | 666 | memcpy(&gateway.s_addr, p, sizeof(gateway.s_addr)); | |
667 | p += 4; | 667 | p += 4; | |
668 | sa_in_init(&rt->rt_dest, &dest); | 668 | sa_in_init(&rt->rt_dest, &dest); | |
669 | sa_in_init(&rt->rt_netmask, &netmask); | 669 | sa_in_init(&rt->rt_netmask, &netmask); | |
670 | sa_in_init(&rt->rt_gateway, &gateway); | 670 | sa_in_init(&rt->rt_gateway, &gateway); | |
671 | if (rt_proto_add(routes, rt)) | 671 | if (rt_proto_add(routes, rt)) | |
672 | n++; | 672 | n++; | |
673 | } | 673 | } | |
674 | } | 674 | } | |
675 | 675 | |||
676 | return n; | 676 | return n; | |
677 | } | 677 | } | |
678 | 678 | |||
679 | uint16_t | 679 | uint16_t | |
680 | dhcp_get_mtu(const struct interface *ifp) | 680 | dhcp_get_mtu(const struct interface *ifp) | |
681 | { | 681 | { | |
682 | const struct dhcp_state *state; | 682 | const struct dhcp_state *state; | |
683 | uint16_t mtu; | 683 | uint16_t mtu; | |
684 | 684 | |||
685 | if (ifp->options->mtu) | 685 | if (ifp->options->mtu) | |
686 | return (uint16_t)ifp->options->mtu; | 686 | return (uint16_t)ifp->options->mtu; | |
687 | mtu = 0; /* bogus gcc warning */ | 687 | mtu = 0; /* bogus gcc warning */ | |
688 | if ((state = D_CSTATE(ifp)) == NULL || | 688 | if ((state = D_CSTATE(ifp)) == NULL || | |
689 | has_option_mask(ifp->options->nomask, DHO_MTU) || | 689 | has_option_mask(ifp->options->nomask, DHO_MTU) || | |
690 | get_option_uint16(ifp->ctx, &mtu, | 690 | get_option_uint16(ifp->ctx, &mtu, | |
691 | state->new, state->new_len, DHO_MTU) == -1) | 691 | state->new, state->new_len, DHO_MTU) == -1) | |
692 | return 0; | 692 | return 0; | |
693 | return mtu; | 693 | return mtu; | |
694 | } | 694 | } | |
695 | 695 | |||
696 | /* Grab our routers from the DHCP message and apply any MTU value | 696 | /* Grab our routers from the DHCP message and apply any MTU value | |
697 | * the message contains */ | 697 | * the message contains */ | |
698 | int | 698 | int | |
699 | dhcp_get_routes(rb_tree_t *routes, struct interface *ifp) | 699 | dhcp_get_routes(rb_tree_t *routes, struct interface *ifp) | |
700 | { | 700 | { | |
701 | const struct dhcp_state *state; | 701 | const struct dhcp_state *state; | |
702 | 702 | |||
703 | if ((state = D_CSTATE(ifp)) == NULL || !(state->added & STATE_ADDED)) | 703 | if ((state = D_CSTATE(ifp)) == NULL || !(state->added & STATE_ADDED)) | |
704 | return 0; | 704 | return 0; | |
705 | return get_option_routes(routes, ifp, state->new, state->new_len); | 705 | return get_option_routes(routes, ifp, state->new, state->new_len); | |
706 | } | 706 | } | |
707 | 707 | |||
708 | /* Assumes DHCP options */ | 708 | /* Assumes DHCP options */ | |
709 | static int | 709 | static int | |
710 | dhcp_message_add_addr(struct bootp *bootp, | 710 | dhcp_message_add_addr(struct bootp *bootp, | |
711 | uint8_t type, struct in_addr addr) | 711 | uint8_t type, struct in_addr addr) | |
712 | { | 712 | { | |
713 | uint8_t *p; | 713 | uint8_t *p; | |
714 | size_t len; | 714 | size_t len; | |
715 | 715 | |||
716 | p = bootp->vend; | 716 | p = bootp->vend; | |
717 | while (*p != DHO_END) { | 717 | while (*p != DHO_END) { | |
718 | p++; | 718 | p++; | |
719 | p += *p + 1; | 719 | p += *p + 1; | |
720 | } | 720 | } | |
721 | 721 | |||
722 | len = (size_t)(p - bootp->vend); | 722 | len = (size_t)(p - bootp->vend); | |
723 | if (len + 6 > sizeof(bootp->vend)) { | 723 | if (len + 6 > sizeof(bootp->vend)) { | |
724 | errno = ENOMEM; | 724 | errno = ENOMEM; | |
725 | return -1; | 725 | return -1; | |
726 | } | 726 | } | |
727 | 727 | |||
728 | *p++ = type; | 728 | *p++ = type; | |
729 | *p++ = 4; | 729 | *p++ = 4; | |
730 | memcpy(p, &addr.s_addr, 4); | 730 | memcpy(p, &addr.s_addr, 4); | |
731 | p += 4; | 731 | p += 4; | |
732 | *p = DHO_END; | 732 | *p = DHO_END; | |
733 | return 0; | 733 | return 0; | |
734 | } | 734 | } | |
735 | 735 | |||
736 | static ssize_t | 736 | static ssize_t | |
737 | make_message(struct bootp **bootpm, const struct interface *ifp, uint8_t type) | 737 | make_message(struct bootp **bootpm, const struct interface *ifp, uint8_t type) | |
738 | { | 738 | { | |
739 | struct bootp *bootp; | 739 | struct bootp *bootp; | |
740 | uint8_t *lp, *p, *e; | 740 | uint8_t *lp, *p, *e; | |
741 | uint8_t *n_params = NULL; | 741 | uint8_t *n_params = NULL; | |
742 | uint32_t ul; | 742 | uint32_t ul; | |
743 | uint16_t sz; | 743 | uint16_t sz; | |
744 | size_t len, i; | 744 | size_t len, i; | |
745 | const struct dhcp_opt *opt; | 745 | const struct dhcp_opt *opt; | |
746 | struct if_options *ifo = ifp->options; | 746 | struct if_options *ifo = ifp->options; | |
747 | const struct dhcp_state *state = D_CSTATE(ifp); | 747 | const struct dhcp_state *state = D_CSTATE(ifp); | |
748 | const struct dhcp_lease *lease = &state->lease; | 748 | const struct dhcp_lease *lease = &state->lease; | |
749 | char hbuf[HOSTNAME_MAX_LEN + 1]; | 749 | char hbuf[HOSTNAME_MAX_LEN + 1]; | |
750 | const char *hostname; | 750 | const char *hostname; | |
751 | const struct vivco *vivco; | 751 | const struct vivco *vivco; | |
752 | int mtu; | 752 | int mtu; | |
753 | #ifdef AUTH | 753 | #ifdef AUTH | |
754 | uint8_t *auth, auth_len; | 754 | uint8_t *auth, auth_len; | |
755 | #endif | 755 | #endif | |
756 | 756 | |||
757 | if ((mtu = if_getmtu(ifp)) == -1) | 757 | if ((mtu = if_getmtu(ifp)) == -1) | |
758 | logerr("%s: if_getmtu", ifp->name); | 758 | logerr("%s: if_getmtu", ifp->name); | |
759 | else if (mtu < MTU_MIN) { | 759 | else if (mtu < MTU_MIN) { | |
760 | if (if_setmtu(ifp, MTU_MIN) == -1) | 760 | if (if_setmtu(ifp, MTU_MIN) == -1) | |
761 | logerr("%s: if_setmtu", ifp->name); | 761 | logerr("%s: if_setmtu", ifp->name); | |
762 | mtu = MTU_MIN; | 762 | mtu = MTU_MIN; | |
763 | } | 763 | } | |
764 | 764 | |||
765 | if (ifo->options & DHCPCD_BOOTP) | 765 | if (ifo->options & DHCPCD_BOOTP) | |
766 | bootp = calloc(1, sizeof (*bootp)); | 766 | bootp = calloc(1, sizeof (*bootp)); | |
767 | else | 767 | else | |
768 | /* Make the maximal message we could send */ | 768 | /* Make the maximal message we could send */ | |
769 | bootp = calloc(1, (size_t)(mtu - IP_UDP_SIZE)); | 769 | bootp = calloc(1, (size_t)(mtu - IP_UDP_SIZE)); | |
770 | 770 | |||
771 | if (bootp == NULL) | 771 | if (bootp == NULL) | |
772 | return -1; | 772 | return -1; | |
773 | *bootpm = bootp; | 773 | *bootpm = bootp; | |
774 | 774 | |||
775 | if (state->addr != NULL && | 775 | if (state->addr != NULL && | |
776 | (type == DHCP_INFORM || type == DHCP_RELEASE || | 776 | (type == DHCP_INFORM || type == DHCP_RELEASE || | |
777 | (type == DHCP_REQUEST && | 777 | (type == DHCP_REQUEST && | |
778 | state->addr->mask.s_addr == lease->mask.s_addr && | 778 | state->addr->mask.s_addr == lease->mask.s_addr && | |
779 | (state->new == NULL || IS_DHCP(state->new)) && | 779 | (state->new == NULL || IS_DHCP(state->new)) && | |
780 | !(state->added & (STATE_FAKE | STATE_EXPIRED))))) | 780 | !(state->added & (STATE_FAKE | STATE_EXPIRED))))) | |
781 | bootp->ciaddr = state->addr->addr.s_addr; | 781 | bootp->ciaddr = state->addr->addr.s_addr; | |
782 | 782 | |||
783 | bootp->op = BOOTREQUEST; | 783 | bootp->op = BOOTREQUEST; | |
784 | bootp->htype = (uint8_t)ifp->hwtype; | 784 | bootp->htype = (uint8_t)ifp->hwtype; | |
785 | if (ifp->hwlen != 0 && ifp->hwlen < sizeof(bootp->chaddr)) { | 785 | if (ifp->hwlen != 0 && ifp->hwlen < sizeof(bootp->chaddr)) { | |
786 | bootp->hlen = (uint8_t)ifp->hwlen; | 786 | bootp->hlen = (uint8_t)ifp->hwlen; | |
787 | memcpy(&bootp->chaddr, &ifp->hwaddr, ifp->hwlen); | 787 | memcpy(&bootp->chaddr, &ifp->hwaddr, ifp->hwlen); | |
788 | } | 788 | } | |
789 | 789 | |||
790 | if (ifo->options & DHCPCD_BROADCAST && | 790 | if (ifo->options & DHCPCD_BROADCAST && | |
791 | bootp->ciaddr == 0 && | 791 | bootp->ciaddr == 0 && | |
792 | type != DHCP_DECLINE && | 792 | type != DHCP_DECLINE && | |
793 | type != DHCP_RELEASE) | 793 | type != DHCP_RELEASE) | |
794 | bootp->flags = htons(BROADCAST_FLAG); | 794 | bootp->flags = htons(BROADCAST_FLAG); | |
795 | 795 | |||
796 | if (type != DHCP_DECLINE && type != DHCP_RELEASE) { | 796 | if (type != DHCP_DECLINE && type != DHCP_RELEASE) { | |
797 | struct timespec tv; | 797 | struct timespec tv; | |
798 | unsigned long long secs; | 798 | unsigned long long secs; | |
799 | 799 | |||
800 | clock_gettime(CLOCK_MONOTONIC, &tv); | 800 | clock_gettime(CLOCK_MONOTONIC, &tv); | |
801 | secs = eloop_timespec_diff(&tv, &state->started, NULL); | 801 | secs = eloop_timespec_diff(&tv, &state->started, NULL); | |
802 | if (secs > UINT16_MAX) | 802 | if (secs > UINT16_MAX) | |
803 | bootp->secs = htons((uint16_t)UINT16_MAX); | 803 | bootp->secs = htons((uint16_t)UINT16_MAX); | |
804 | else | 804 | else | |
805 | bootp->secs = htons((uint16_t)secs); | 805 | bootp->secs = htons((uint16_t)secs); | |
806 | } | 806 | } | |
807 | 807 | |||
808 | bootp->xid = htonl(state->xid); | 808 | bootp->xid = htonl(state->xid); | |
809 | 809 | |||
810 | if (ifo->options & DHCPCD_BOOTP) | 810 | if (ifo->options & DHCPCD_BOOTP) | |
811 | return sizeof(*bootp); | 811 | return sizeof(*bootp); | |
812 | 812 | |||
813 | p = bootp->vend; | 813 | p = bootp->vend; | |
814 | e = (uint8_t *)bootp + (mtu - IP_UDP_SIZE) - 1; /* -1 for DHO_END */ | 814 | e = (uint8_t *)bootp + (mtu - IP_UDP_SIZE) - 1; /* -1 for DHO_END */ | |
815 | 815 | |||
816 | ul = htonl(MAGIC_COOKIE); | 816 | ul = htonl(MAGIC_COOKIE); | |
817 | memcpy(p, &ul, sizeof(ul)); | 817 | memcpy(p, &ul, sizeof(ul)); | |
818 | p += sizeof(ul); | 818 | p += sizeof(ul); | |
819 | 819 | |||
820 | #define AREA_LEFT (size_t)(e - p) | 820 | #define AREA_LEFT (size_t)(e - p) | |
821 | #define AREA_FIT(s) if ((s) > AREA_LEFT) goto toobig | 821 | #define AREA_FIT(s) if ((s) > AREA_LEFT) goto toobig | |
822 | #define AREA_CHECK(s) if ((s) + 2UL > AREA_LEFT) goto toobig | 822 | #define AREA_CHECK(s) if ((s) + 2UL > AREA_LEFT) goto toobig | |
823 | #define PUT_ADDR(o, a) do { \ | 823 | #define PUT_ADDR(o, a) do { \ | |
824 | AREA_CHECK(4); \ | 824 | AREA_CHECK(4); \ | |
825 | *p++ = (o); \ | 825 | *p++ = (o); \ | |
826 | *p++ = 4; \ | 826 | *p++ = 4; \ | |
827 | memcpy(p, &(a)->s_addr, 4); \ | 827 | memcpy(p, &(a)->s_addr, 4); \ | |
828 | p += 4; \ | 828 | p += 4; \ | |
829 | } while (0 /* CONSTCOND */) | 829 | } while (0 /* CONSTCOND */) | |
830 | 830 | |||
831 | /* Options are listed in numerical order as per RFC 7844 Section 3.1 | 831 | /* Options are listed in numerical order as per RFC 7844 Section 3.1 | |
832 | * XXX: They should be randomised. */ | 832 | * XXX: They should be randomised. */ | |
833 | 833 | |||
834 | bool putip = false; | 834 | bool putip = false; | |
835 | if (lease->addr.s_addr && lease->cookie == htonl(MAGIC_COOKIE)) { | 835 | if (lease->addr.s_addr && lease->cookie == htonl(MAGIC_COOKIE)) { | |
836 | if (type == DHCP_DECLINE || | 836 | if (type == DHCP_DECLINE || | |
837 | (type == DHCP_REQUEST && | 837 | (type == DHCP_REQUEST && | |
838 | (state->addr == NULL || | 838 | (state->addr == NULL || | |
839 | state->added & (STATE_FAKE | STATE_EXPIRED) || | 839 | state->added & (STATE_FAKE | STATE_EXPIRED) || | |
840 | lease->addr.s_addr != state->addr->addr.s_addr))) | 840 | lease->addr.s_addr != state->addr->addr.s_addr))) | |
841 | { | 841 | { | |
842 | putip = true; | 842 | putip = true; | |
843 | PUT_ADDR(DHO_IPADDRESS, &lease->addr); | 843 | PUT_ADDR(DHO_IPADDRESS, &lease->addr); | |
844 | } | 844 | } | |
845 | } | 845 | } | |
846 | 846 | |||
847 | AREA_CHECK(3); | 847 | AREA_CHECK(3); | |
848 | *p++ = DHO_MESSAGETYPE; | 848 | *p++ = DHO_MESSAGETYPE; | |
849 | *p++ = 1; | 849 | *p++ = 1; | |
850 | *p++ = type; | 850 | *p++ = type; | |
851 | 851 | |||
852 | if (lease->addr.s_addr && lease->cookie == htonl(MAGIC_COOKIE)) { | 852 | if (lease->addr.s_addr && lease->cookie == htonl(MAGIC_COOKIE)) { | |
853 | if (type == DHCP_RELEASE || putip) { | 853 | if (type == DHCP_RELEASE || putip) { | |
854 | if (lease->server.s_addr) | 854 | if (lease->server.s_addr) | |
855 | PUT_ADDR(DHO_SERVERID, &lease->server); | 855 | PUT_ADDR(DHO_SERVERID, &lease->server); | |
856 | } | 856 | } | |
857 | } | 857 | } | |
858 | 858 | |||
859 | if (type == DHCP_DECLINE) { | 859 | if (type == DHCP_DECLINE) { | |
860 | len = strlen(DAD); | 860 | len = strlen(DAD); | |
861 | if (len > AREA_LEFT) { | 861 | if (len > AREA_LEFT) { | |
862 | *p++ = DHO_MESSAGE; | 862 | *p++ = DHO_MESSAGE; | |
863 | *p++ = (uint8_t)len; | 863 | *p++ = (uint8_t)len; | |
864 | memcpy(p, DAD, len); | 864 | memcpy(p, DAD, len); | |
865 | p += len; | 865 | p += len; | |
866 | } | 866 | } | |
867 | } | 867 | } | |
868 | 868 | |||
869 | #define DHCP_DIR(type) ((type) == DHCP_DISCOVER || (type) == DHCP_INFORM || \ | 869 | #define DHCP_DIR(type) ((type) == DHCP_DISCOVER || (type) == DHCP_INFORM || \ | |
870 | (type) == DHCP_REQUEST) | 870 | (type) == DHCP_REQUEST) | |
871 | 871 | |||
872 | if (DHCP_DIR(type)) { | 872 | if (DHCP_DIR(type)) { | |
873 | /* vendor is already encoded correctly, so just add it */ | 873 | /* vendor is already encoded correctly, so just add it */ | |
874 | if (ifo->vendor[0]) { | 874 | if (ifo->vendor[0]) { | |
875 | AREA_CHECK(ifo->vendor[0]); | 875 | AREA_CHECK(ifo->vendor[0]); | |
876 | *p++ = DHO_VENDOR; | 876 | *p++ = DHO_VENDOR; | |
877 | memcpy(p, ifo->vendor, (size_t)ifo->vendor[0] + 1); | 877 | memcpy(p, ifo->vendor, (size_t)ifo->vendor[0] + 1); | |
878 | p += ifo->vendor[0] + 1; | 878 | p += ifo->vendor[0] + 1; | |
879 | } | 879 | } | |
880 | } | 880 | } | |
881 | 881 | |||
882 | if (type == DHCP_DISCOVER && ifo->options & DHCPCD_REQUEST) | 882 | if (type == DHCP_DISCOVER && ifo->options & DHCPCD_REQUEST) | |
883 | PUT_ADDR(DHO_IPADDRESS, &ifo->req_addr); | 883 | PUT_ADDR(DHO_IPADDRESS, &ifo->req_addr); | |
884 | 884 | |||
885 | if (DHCP_DIR(type)) { | 885 | if (DHCP_DIR(type)) { | |
886 | if (type != DHCP_INFORM) { | 886 | if (type != DHCP_INFORM) { | |
887 | if (ifo->leasetime != 0) { | 887 | if (ifo->leasetime != 0) { | |
888 | AREA_CHECK(4); | 888 | AREA_CHECK(4); | |
889 | *p++ = DHO_LEASETIME; | 889 | *p++ = DHO_LEASETIME; | |
890 | *p++ = 4; | 890 | *p++ = 4; | |
891 | ul = htonl(ifo->leasetime); | 891 | ul = htonl(ifo->leasetime); | |
892 | memcpy(p, &ul, 4); | 892 | memcpy(p, &ul, 4); | |
893 | p += 4; | 893 | p += 4; | |
894 | } | 894 | } | |
895 | } | 895 | } | |
896 | 896 | |||
897 | AREA_CHECK(0); | 897 | AREA_CHECK(0); | |
898 | *p++ = DHO_PARAMETERREQUESTLIST; | 898 | *p++ = DHO_PARAMETERREQUESTLIST; | |
899 | n_params = p; | 899 | n_params = p; | |
900 | *p++ = 0; | 900 | *p++ = 0; | |
901 | for (i = 0, opt = ifp->ctx->dhcp_opts; | 901 | for (i = 0, opt = ifp->ctx->dhcp_opts; | |
902 | i < ifp->ctx->dhcp_opts_len; | 902 | i < ifp->ctx->dhcp_opts_len; | |
903 | i++, opt++) | 903 | i++, opt++) | |
904 | { | 904 | { | |
905 | if (!DHC_REQOPT(opt, ifo->requestmask, ifo->nomask)) | 905 | if (!DHC_REQOPT(opt, ifo->requestmask, ifo->nomask)) | |
906 | continue; | 906 | continue; | |
907 | if (type == DHCP_INFORM && | 907 | if (type == DHCP_INFORM && | |
908 | (opt->option == DHO_RENEWALTIME || | 908 | (opt->option == DHO_RENEWALTIME || | |
909 | opt->option == DHO_REBINDTIME)) | 909 | opt->option == DHO_REBINDTIME)) | |
910 | continue; | 910 | continue; | |
911 | AREA_FIT(1); | 911 | AREA_FIT(1); | |
912 | *p++ = (uint8_t)opt->option; | 912 | *p++ = (uint8_t)opt->option; | |
913 | } | 913 | } | |
914 | for (i = 0, opt = ifo->dhcp_override; | 914 | for (i = 0, opt = ifo->dhcp_override; | |
915 | i < ifo->dhcp_override_len; | 915 | i < ifo->dhcp_override_len; | |
916 | i++, opt++) | 916 | i++, opt++) | |
917 | { | 917 | { | |
918 | /* Check if added above */ | 918 | /* Check if added above */ | |
919 | for (lp = n_params + 1; lp < p; lp++) | 919 | for (lp = n_params + 1; lp < p; lp++) | |
920 | if (*lp == (uint8_t)opt->option) | 920 | if (*lp == (uint8_t)opt->option) | |
921 | break; | 921 | break; | |
922 | if (lp < p) | 922 | if (lp < p) | |
923 | continue; | 923 | continue; | |
924 | if (!DHC_REQOPT(opt, ifo->requestmask, ifo->nomask)) | 924 | if (!DHC_REQOPT(opt, ifo->requestmask, ifo->nomask)) | |
925 | continue; | 925 | continue; | |
926 | if (type == DHCP_INFORM && | 926 | if (type == DHCP_INFORM && | |
927 | (opt->option == DHO_RENEWALTIME || | 927 | (opt->option == DHO_RENEWALTIME || | |
928 | opt->option == DHO_REBINDTIME)) | 928 | opt->option == DHO_REBINDTIME)) | |
929 | continue; | 929 | continue; | |
930 | AREA_FIT(1); | 930 | AREA_FIT(1); | |
931 | *p++ = (uint8_t)opt->option; | 931 | *p++ = (uint8_t)opt->option; | |
932 | } | 932 | } | |
933 | *n_params = (uint8_t)(p - n_params - 1); | 933 | *n_params = (uint8_t)(p - n_params - 1); | |
934 | 934 | |||
935 | if (mtu != -1 && | 935 | if (mtu != -1 && | |
936 | !(has_option_mask(ifo->nomask, DHO_MAXMESSAGESIZE))) | 936 | !(has_option_mask(ifo->nomask, DHO_MAXMESSAGESIZE))) | |
937 | { | 937 | { | |
938 | AREA_CHECK(2); | 938 | AREA_CHECK(2); | |
939 | *p++ = DHO_MAXMESSAGESIZE; | 939 | *p++ = DHO_MAXMESSAGESIZE; | |
940 | *p++ = 2; | 940 | *p++ = 2; | |
941 | sz = htons((uint16_t)(mtu - IP_UDP_SIZE)); | 941 | sz = htons((uint16_t)(mtu - IP_UDP_SIZE)); | |
942 | memcpy(p, &sz, 2); | 942 | memcpy(p, &sz, 2); | |
943 | p += 2; | 943 | p += 2; | |
944 | } | 944 | } | |
945 | 945 | |||
946 | if (ifo->userclass[0] && | 946 | if (ifo->userclass[0] && | |
947 | !has_option_mask(ifo->nomask, DHO_USERCLASS)) | 947 | !has_option_mask(ifo->nomask, DHO_USERCLASS)) | |
948 | { | 948 | { | |
949 | AREA_CHECK(ifo->userclass[0]); | 949 | AREA_CHECK(ifo->userclass[0]); | |
950 | *p++ = DHO_USERCLASS; | 950 | *p++ = DHO_USERCLASS; | |
951 | memcpy(p, ifo->userclass, | 951 | memcpy(p, ifo->userclass, | |
952 | (size_t)ifo->userclass[0] + 1); | 952 | (size_t)ifo->userclass[0] + 1); | |
953 | p += ifo->userclass[0] + 1; | 953 | p += ifo->userclass[0] + 1; | |
954 | } | 954 | } | |
955 | } | 955 | } | |
956 | 956 | |||
957 | if (state->clientid) { | 957 | if (state->clientid) { | |
958 | AREA_CHECK(state->clientid[0]); | 958 | AREA_CHECK(state->clientid[0]); | |
959 | *p++ = DHO_CLIENTID; | 959 | *p++ = DHO_CLIENTID; | |
960 | memcpy(p, state->clientid, (size_t)state->clientid[0] + 1); | 960 | memcpy(p, state->clientid, (size_t)state->clientid[0] + 1); | |
961 | p += state->clientid[0] + 1; | 961 | p += state->clientid[0] + 1; | |
962 | } | 962 | } | |
963 | 963 | |||
964 | if (DHCP_DIR(type) && | 964 | if (DHCP_DIR(type) && | |
965 | !has_option_mask(ifo->nomask, DHO_VENDORCLASSID) && | 965 | !has_option_mask(ifo->nomask, DHO_VENDORCLASSID) && | |
966 | ifo->vendorclassid[0]) | 966 | ifo->vendorclassid[0]) | |
967 | { | 967 | { | |
968 | AREA_CHECK(ifo->vendorclassid[0]); | 968 | AREA_CHECK(ifo->vendorclassid[0]); | |
969 | *p++ = DHO_VENDORCLASSID; | 969 | *p++ = DHO_VENDORCLASSID; | |
970 | memcpy(p, ifo->vendorclassid, (size_t)ifo->vendorclassid[0]+1); | 970 | memcpy(p, ifo->vendorclassid, (size_t)ifo->vendorclassid[0]+1); | |
971 | p += ifo->vendorclassid[0] + 1; | 971 | p += ifo->vendorclassid[0] + 1; | |
972 | } | 972 | } | |
973 | 973 | |||
974 | if (type == DHCP_DISCOVER && | 974 | if (type == DHCP_DISCOVER && | |
975 | !(ifp->ctx->options & DHCPCD_TEST) && | 975 | !(ifp->ctx->options & DHCPCD_TEST) && | |
976 | DHC_REQ(ifo->requestmask, ifo->nomask, DHO_RAPIDCOMMIT)) | 976 | DHC_REQ(ifo->requestmask, ifo->nomask, DHO_RAPIDCOMMIT)) | |
977 | { | 977 | { | |
978 | /* RFC 4039 Section 3 */ | 978 | /* RFC 4039 Section 3 */ | |
979 | AREA_CHECK(0); | 979 | AREA_CHECK(0); | |
980 | *p++ = DHO_RAPIDCOMMIT; | 980 | *p++ = DHO_RAPIDCOMMIT; | |
981 | *p++ = 0; | 981 | *p++ = 0; | |
982 | } | 982 | } | |
983 | 983 | |||
984 | if (DHCP_DIR(type)) { | 984 | if (DHCP_DIR(type)) { | |
985 | hostname = dhcp_get_hostname(hbuf, sizeof(hbuf), ifo); | 985 | hostname = dhcp_get_hostname(hbuf, sizeof(hbuf), ifo); | |
986 | 986 | |||
987 | /* | 987 | /* | |
988 | * RFC4702 3.1 States that if we send the Client FQDN option | 988 | * RFC4702 3.1 States that if we send the Client FQDN option | |
989 | * then we MUST NOT also send the Host Name option. | 989 | * then we MUST NOT also send the Host Name option. | |
990 | * Technically we could, but that is not RFC conformant and | 990 | * Technically we could, but that is not RFC conformant and | |
991 | * also seems to break some DHCP server implemetations such as | 991 | * also seems to break some DHCP server implemetations such as | |
992 | * Windows. On the other hand, ISC dhcpd is just as non RFC | 992 | * Windows. On the other hand, ISC dhcpd is just as non RFC | |
993 | * conformant by not accepting a partially qualified FQDN. | 993 | * conformant by not accepting a partially qualified FQDN. | |
994 | */ | 994 | */ | |
995 | if (ifo->fqdn != FQDN_DISABLE) { | 995 | if (ifo->fqdn != FQDN_DISABLE) { | |
996 | /* IETF DHC-FQDN option (81), RFC4702 */ | 996 | /* IETF DHC-FQDN option (81), RFC4702 */ | |
997 | i = 3; | 997 | i = 3; | |
998 | if (hostname) | 998 | if (hostname) | |
999 | i += encode_rfc1035(hostname, NULL); | 999 | i += encode_rfc1035(hostname, NULL); | |
1000 | AREA_CHECK(i); | 1000 | AREA_CHECK(i); | |
1001 | *p++ = DHO_FQDN; | 1001 | *p++ = DHO_FQDN; | |
1002 | *p++ = (uint8_t)i; | 1002 | *p++ = (uint8_t)i; | |
1003 | /* | 1003 | /* | |
1004 | * Flags: 0000NEOS | 1004 | * Flags: 0000NEOS | |
1005 | * S: 1 => Client requests Server to update | 1005 | * S: 1 => Client requests Server to update | |
1006 | * a RR in DNS as well as PTR | 1006 | * a RR in DNS as well as PTR | |
1007 | * O: 1 => Server indicates to client that | 1007 | * O: 1 => Server indicates to client that | |
1008 | * DNS has been updated | 1008 | * DNS has been updated | |
1009 | * E: 1 => Name data is DNS format | 1009 | * E: 1 => Name data is DNS format | |
1010 | * N: 1 => Client requests Server to not | 1010 | * N: 1 => Client requests Server to not | |
1011 | * update DNS | 1011 | * update DNS | |
1012 | */ | 1012 | */ | |
1013 | if (hostname) | 1013 | if (hostname) | |
1014 | *p++ = (uint8_t)((ifo->fqdn & 0x09) | 0x04); | 1014 | *p++ = (uint8_t)((ifo->fqdn & 0x09) | 0x04); | |
1015 | else | 1015 | else | |
1016 | *p++ = (FQDN_NONE & 0x09) | 0x04; | 1016 | *p++ = (FQDN_NONE & 0x09) | 0x04; | |
1017 | *p++ = 0; /* from server for PTR RR */ | 1017 | *p++ = 0; /* from server for PTR RR */ | |
1018 | *p++ = 0; /* from server for A RR if S=1 */ | 1018 | *p++ = 0; /* from server for A RR if S=1 */ | |
1019 | if (hostname) { | 1019 | if (hostname) { | |
1020 | i = encode_rfc1035(hostname, p); | 1020 | i = encode_rfc1035(hostname, p); | |
1021 | p += i; | 1021 | p += i; | |
1022 | } | 1022 | } | |
1023 | } else if (ifo->options & DHCPCD_HOSTNAME && hostname) { | 1023 | } else if (ifo->options & DHCPCD_HOSTNAME && hostname) { | |
1024 | len = strlen(hostname); | 1024 | len = strlen(hostname); | |
1025 | AREA_CHECK(len); | 1025 | AREA_CHECK(len); | |
1026 | *p++ = DHO_HOSTNAME; | 1026 | *p++ = DHO_HOSTNAME; | |
1027 | *p++ = (uint8_t)len; | 1027 | *p++ = (uint8_t)len; | |
1028 | memcpy(p, hostname, len); | 1028 | memcpy(p, hostname, len); | |
1029 | p += len; | 1029 | p += len; | |
1030 | } | 1030 | } | |
1031 | } | 1031 | } | |
1032 | 1032 | |||
1033 | #ifdef AUTH | 1033 | #ifdef AUTH | |
1034 | auth = NULL; /* appease GCC */ | 1034 | auth = NULL; /* appease GCC */ | |
1035 | auth_len = 0; | 1035 | auth_len = 0; | |
1036 | if (ifo->auth.options & DHCPCD_AUTH_SEND) { | 1036 | if (ifo->auth.options & DHCPCD_AUTH_SEND) { | |
1037 | ssize_t alen = dhcp_auth_encode(ifp->ctx, &ifo->auth, | 1037 | ssize_t alen = dhcp_auth_encode(ifp->ctx, &ifo->auth, | |
1038 | state->auth.token, | 1038 | state->auth.token, | |
1039 | NULL, 0, 4, type, NULL, 0); | 1039 | NULL, 0, 4, type, NULL, 0); | |
1040 | if (alen != -1 && alen > UINT8_MAX) { | 1040 | if (alen != -1 && alen > UINT8_MAX) { | |
1041 | errno = ERANGE; | 1041 | errno = ERANGE; | |
1042 | alen = -1; | 1042 | alen = -1; | |
1043 | } | 1043 | } | |
1044 | if (alen == -1) | 1044 | if (alen == -1) | |
1045 | logerr("%s: dhcp_auth_encode", ifp->name); | 1045 | logerr("%s: dhcp_auth_encode", ifp->name); | |
1046 | else if (alen != 0) { | 1046 | else if (alen != 0) { | |
1047 | auth_len = (uint8_t)alen; | 1047 | auth_len = (uint8_t)alen; | |
1048 | AREA_CHECK(auth_len); | 1048 | AREA_CHECK(auth_len); | |
1049 | *p++ = DHO_AUTHENTICATION; | 1049 | *p++ = DHO_AUTHENTICATION; | |
1050 | *p++ = auth_len; | 1050 | *p++ = auth_len; | |
1051 | auth = p; | 1051 | auth = p; | |
1052 | p += auth_len; | 1052 | p += auth_len; | |
1053 | } | 1053 | } | |
1054 | } | 1054 | } | |
1055 | #endif | 1055 | #endif | |
1056 | 1056 | |||
1057 | /* RFC 2563 Auto Configure */ | 1057 | /* RFC 2563 Auto Configure */ | |
1058 | if (type == DHCP_DISCOVER && ifo->options & DHCPCD_IPV4LL && | 1058 | if (type == DHCP_DISCOVER && ifo->options & DHCPCD_IPV4LL && | |
1059 | !(has_option_mask(ifo->nomask, DHO_AUTOCONFIGURE))) | 1059 | !(has_option_mask(ifo->nomask, DHO_AUTOCONFIGURE))) | |
1060 | { | 1060 | { | |
1061 | AREA_CHECK(1); | 1061 | AREA_CHECK(1); | |
1062 | *p++ = DHO_AUTOCONFIGURE; | 1062 | *p++ = DHO_AUTOCONFIGURE; | |
1063 | *p++ = 1; | 1063 | *p++ = 1; | |
1064 | *p++ = 1; | 1064 | *p++ = 1; | |
1065 | } | 1065 | } | |
1066 | 1066 | |||
1067 | if (DHCP_DIR(type)) { | 1067 | if (DHCP_DIR(type)) { | |
1068 | if (ifo->mudurl[0]) { | 1068 | if (ifo->mudurl[0]) { | |
1069 | AREA_CHECK(ifo->mudurl[0]); | 1069 | AREA_CHECK(ifo->mudurl[0]); | |
1070 | *p++ = DHO_MUDURL; | 1070 | *p++ = DHO_MUDURL; | |
1071 | memcpy(p, ifo->mudurl, (size_t)ifo->mudurl[0] + 1); | 1071 | memcpy(p, ifo->mudurl, (size_t)ifo->mudurl[0] + 1); | |
1072 | p += ifo->mudurl[0] + 1; | 1072 | p += ifo->mudurl[0] + 1; | |
1073 | } | 1073 | } | |
1074 | 1074 | |||
1075 | if (ifo->vivco_len && | 1075 | if (ifo->vivco_len && | |
1076 | !has_option_mask(ifo->nomask, DHO_VIVCO)) | 1076 | !has_option_mask(ifo->nomask, DHO_VIVCO)) | |
1077 | { | 1077 | { | |
1078 | AREA_CHECK(sizeof(ul)); | 1078 | AREA_CHECK(sizeof(ul)); | |
1079 | *p++ = DHO_VIVCO; | 1079 | *p++ = DHO_VIVCO; | |
1080 | lp = p++; | 1080 | lp = p++; | |
1081 | *lp = sizeof(ul); | 1081 | *lp = sizeof(ul); | |
1082 | ul = htonl(ifo->vivco_en); | 1082 | ul = htonl(ifo->vivco_en); | |
1083 | memcpy(p, &ul, sizeof(ul)); | 1083 | memcpy(p, &ul, sizeof(ul)); | |
1084 | p += sizeof(ul); | 1084 | p += sizeof(ul); | |
1085 | for (i = 0, vivco = ifo->vivco; | 1085 | for (i = 0, vivco = ifo->vivco; | |
1086 | i < ifo->vivco_len; | 1086 | i < ifo->vivco_len; | |
1087 | i++, vivco++) | 1087 | i++, vivco++) | |
1088 | { | 1088 | { | |
1089 | AREA_FIT(vivco->len); | 1089 | AREA_FIT(vivco->len); | |
1090 | if (vivco->len + 2 + *lp > 255) { | 1090 | if (vivco->len + 2 + *lp > 255) { | |
1091 | logerrx("%s: VIVCO option too big", | 1091 | logerrx("%s: VIVCO option too big", | |
1092 | ifp->name); | 1092 | ifp->name); | |
1093 | free(bootp); | 1093 | free(bootp); | |
1094 | return -1; | 1094 | return -1; | |
1095 | } | 1095 | } | |
1096 | *p++ = (uint8_t)vivco->len; | 1096 | *p++ = (uint8_t)vivco->len; | |
1097 | memcpy(p, vivco->data, vivco->len); | 1097 | memcpy(p, vivco->data, vivco->len); | |
1098 | p += vivco->len; | 1098 | p += vivco->len; | |
1099 | *lp = (uint8_t)(*lp + vivco->len + 1); | 1099 | *lp = (uint8_t)(*lp + vivco->len + 1); | |
1100 | } | 1100 | } | |
1101 | } | 1101 | } | |
1102 | 1102 | |||
1103 | #ifdef AUTH | 1103 | #ifdef AUTH | |
1104 | if ((ifo->auth.options & DHCPCD_AUTH_SENDREQUIRE) != | 1104 | if ((ifo->auth.options & DHCPCD_AUTH_SENDREQUIRE) != | |
1105 | DHCPCD_AUTH_SENDREQUIRE && | 1105 | DHCPCD_AUTH_SENDREQUIRE && | |
1106 | !has_option_mask(ifo->nomask, DHO_FORCERENEW_NONCE)) | 1106 | !has_option_mask(ifo->nomask, DHO_FORCERENEW_NONCE)) | |
1107 | { | 1107 | { | |
1108 | /* We support HMAC-MD5 */ | 1108 | /* We support HMAC-MD5 */ | |
1109 | AREA_CHECK(1); | 1109 | AREA_CHECK(1); | |
1110 | *p++ = DHO_FORCERENEW_NONCE; | 1110 | *p++ = DHO_FORCERENEW_NONCE; | |
1111 | *p++ = 1; | 1111 | *p++ = 1; | |
1112 | *p++ = AUTH_ALG_HMAC_MD5; | 1112 | *p++ = AUTH_ALG_HMAC_MD5; | |
1113 | } | 1113 | } | |
1114 | #endif | 1114 | #endif | |
1115 | } | 1115 | } | |
1116 | 1116 | |||
1117 | *p++ = DHO_END; | 1117 | *p++ = DHO_END; | |
1118 | len = (size_t)(p - (uint8_t *)bootp); | 1118 | len = (size_t)(p - (uint8_t *)bootp); | |
1119 | 1119 | |||
1120 | /* Pad out to the BOOTP message length. | 1120 | /* Pad out to the BOOTP message length. | |
1121 | * Even if we send a DHCP packet with a variable length vendor area, | 1121 | * Even if we send a DHCP packet with a variable length vendor area, | |
1122 | * some servers / relay agents don't like packets smaller than | 1122 | * some servers / relay agents don't like packets smaller than | |
1123 | * a BOOTP message which is fine because that's stipulated | 1123 | * a BOOTP message which is fine because that's stipulated | |
1124 | * in RFC1542 section 2.1. */ | 1124 | * in RFC1542 section 2.1. */ | |
1125 | while (len < sizeof(*bootp)) { | 1125 | while (len < sizeof(*bootp)) { | |
1126 | *p++ = DHO_PAD; | 1126 | *p++ = DHO_PAD; | |
1127 | len++; | 1127 | len++; | |
1128 | } | 1128 | } | |
1129 | 1129 | |||
1130 | #ifdef AUTH | 1130 | #ifdef AUTH | |
1131 | if (ifo->auth.options & DHCPCD_AUTH_SEND && auth_len != 0) | 1131 | if (ifo->auth.options & DHCPCD_AUTH_SEND && auth_len != 0) | |
1132 | dhcp_auth_encode(ifp->ctx, &ifo->auth, state->auth.token, | 1132 | dhcp_auth_encode(ifp->ctx, &ifo->auth, state->auth.token, | |
1133 | (uint8_t *)bootp, len, 4, type, auth, auth_len); | 1133 | (uint8_t *)bootp, len, 4, type, auth, auth_len); | |
1134 | #endif | 1134 | #endif | |
1135 | 1135 | |||
1136 | return (ssize_t)len; | 1136 | return (ssize_t)len; | |
1137 | 1137 | |||
1138 | toobig: | 1138 | toobig: | |
1139 | logerrx("%s: DHCP message too big", ifp->name); | 1139 | logerrx("%s: DHCP message too big", ifp->name); | |
1140 | free(bootp); | 1140 | free(bootp); | |
1141 | return -1; | 1141 | return -1; | |
1142 | } | 1142 | } | |
1143 | 1143 | |||
1144 | static size_t | 1144 | static size_t | |
1145 | read_lease(struct interface *ifp, struct bootp **bootp) | 1145 | read_lease(struct interface *ifp, struct bootp **bootp) | |
1146 | { | 1146 | { | |
1147 | union { | 1147 | union { | |
1148 | struct bootp bootp; | 1148 | struct bootp bootp; | |
1149 | uint8_t buf[FRAMELEN_MAX]; | 1149 | uint8_t buf[FRAMELEN_MAX]; | |
1150 | } buf; | 1150 | } buf; | |
1151 | struct dhcp_state *state = D_STATE(ifp); | 1151 | struct dhcp_state *state = D_STATE(ifp); | |
1152 | ssize_t sbytes; | 1152 | ssize_t sbytes; | |
1153 | size_t bytes; | 1153 | size_t bytes; | |
1154 | uint8_t type; | 1154 | uint8_t type; | |
1155 | #ifdef AUTH | 1155 | #ifdef AUTH | |
1156 | const uint8_t *auth; | 1156 | const uint8_t *auth; | |
1157 | size_t auth_len; | 1157 | size_t auth_len; | |
1158 | #endif | 1158 | #endif | |
1159 | 1159 | |||
1160 | /* Safety */ | 1160 | /* Safety */ | |
1161 | *bootp = NULL; | 1161 | *bootp = NULL; | |
1162 | 1162 | |||
1163 | if (state->leasefile[0] == '\0') { | 1163 | if (state->leasefile[0] == '\0') { | |
1164 | logdebugx("reading standard input"); | 1164 | logdebugx("reading standard input"); | |
1165 | sbytes = read(fileno(stdin), buf.buf, sizeof(buf.buf)); | 1165 | sbytes = read(fileno(stdin), buf.buf, sizeof(buf.buf)); | |
1166 | } else { | 1166 | } else { | |
1167 | logdebugx("%s: reading lease: %s", | 1167 | logdebugx("%s: reading lease: %s", | |
1168 | ifp->name, state->leasefile); | 1168 | ifp->name, state->leasefile); | |
1169 | sbytes = dhcp_readfile(ifp->ctx, state->leasefile, | 1169 | sbytes = dhcp_readfile(ifp->ctx, state->leasefile, | |
1170 | buf.buf, sizeof(buf.buf)); | 1170 | buf.buf, sizeof(buf.buf)); | |
1171 | } | 1171 | } | |
1172 | if (sbytes == -1) { | 1172 | if (sbytes == -1) { | |
1173 | if (errno != ENOENT) | 1173 | if (errno != ENOENT) | |
1174 | logerr("%s: %s", ifp->name, state->leasefile); | 1174 | logerr("%s: %s", ifp->name, state->leasefile); | |
1175 | return 0; | 1175 | return 0; | |
1176 | } | 1176 | } | |
1177 | bytes = (size_t)sbytes; | 1177 | bytes = (size_t)sbytes; | |
1178 | 1178 | |||
1179 | /* Ensure the packet is at lease BOOTP sized | 1179 | /* Ensure the packet is at lease BOOTP sized | |
1180 | * with a vendor area of 4 octets | 1180 | * with a vendor area of 4 octets | |
1181 | * (it should be more, and our read packet enforces this so this | 1181 | * (it should be more, and our read packet enforces this so this | |
1182 | * code should not be needed, but of course people could | 1182 | * code should not be needed, but of course people could | |
1183 | * scribble whatever in the stored lease file. */ | 1183 | * scribble whatever in the stored lease file. */ | |
1184 | if (bytes < DHCP_MIN_LEN) { | 1184 | if (bytes < DHCP_MIN_LEN) { | |
1185 | logerrx("%s: %s: truncated lease", ifp->name, __func__); | 1185 | logerrx("%s: %s: truncated lease", ifp->name, __func__); | |
1186 | return 0; | 1186 | return 0; | |
1187 | } | 1187 | } | |
1188 | 1188 | |||
1189 | if (ifp->ctx->options & DHCPCD_DUMPLEASE) | 1189 | if (ifp->ctx->options & DHCPCD_DUMPLEASE) | |
1190 | goto out; | 1190 | goto out; | |
1191 | 1191 | |||
1192 | /* We may have found a BOOTP server */ | 1192 | /* We may have found a BOOTP server */ | |
1193 | if (get_option_uint8(ifp->ctx, &type, &buf.bootp, bytes, | 1193 | if (get_option_uint8(ifp->ctx, &type, &buf.bootp, bytes, | |
1194 | DHO_MESSAGETYPE) == -1) | 1194 | DHO_MESSAGETYPE) == -1) | |
1195 | type = 0; | 1195 | type = 0; | |
1196 | 1196 | |||
1197 | #ifdef AUTH | 1197 | #ifdef AUTH | |
1198 | /* Authenticate the message */ | 1198 | /* Authenticate the message */ | |
1199 | auth = get_option(ifp->ctx, &buf.bootp, bytes, | 1199 | auth = get_option(ifp->ctx, &buf.bootp, bytes, | |
1200 | DHO_AUTHENTICATION, &auth_len); | 1200 | DHO_AUTHENTICATION, &auth_len); | |
1201 | if (auth) { | 1201 | if (auth) { | |
1202 | if (dhcp_auth_validate(&state->auth, &ifp->options->auth, | 1202 | if (dhcp_auth_validate(&state->auth, &ifp->options->auth, | |
1203 | &buf.bootp, bytes, 4, type, auth, auth_len) == NULL) | 1203 | &buf.bootp, bytes, 4, type, auth, auth_len) == NULL) | |
1204 | { | 1204 | { | |
1205 | logerr("%s: authentication failed", ifp->name); | 1205 | logerr("%s: authentication failed", ifp->name); | |
1206 | return 0; | 1206 | return 0; | |
1207 | } | 1207 | } | |
1208 | if (state->auth.token) | 1208 | if (state->auth.token) | |
1209 | logdebugx("%s: validated using 0x%08" PRIu32, | 1209 | logdebugx("%s: validated using 0x%08" PRIu32, | |
1210 | ifp->name, state->auth.token->secretid); | 1210 | ifp->name, state->auth.token->secretid); | |
1211 | else | 1211 | else | |
1212 | logdebugx("%s: accepted reconfigure key", ifp->name); | 1212 | logdebugx("%s: accepted reconfigure key", ifp->name); | |
1213 | } else if ((ifp->options->auth.options & DHCPCD_AUTH_SENDREQUIRE) == | 1213 | } else if ((ifp->options->auth.options & DHCPCD_AUTH_SENDREQUIRE) == | |
1214 | DHCPCD_AUTH_SENDREQUIRE) | 1214 | DHCPCD_AUTH_SENDREQUIRE) | |
1215 | { | 1215 | { | |
1216 | logerrx("%s: authentication now required", ifp->name); | 1216 | logerrx("%s: authentication now required", ifp->name); | |
1217 | return 0; | 1217 | return 0; | |
1218 | } | 1218 | } | |
1219 | #endif | 1219 | #endif | |
1220 | 1220 | |||
1221 | out: | 1221 | out: | |
1222 | *bootp = malloc(bytes); | 1222 | *bootp = malloc(bytes); | |
1223 | if (*bootp == NULL) { | 1223 | if (*bootp == NULL) { | |
1224 | logerr(__func__); | 1224 | logerr(__func__); | |
1225 | return 0; | 1225 | return 0; | |
1226 | } | 1226 | } | |
1227 | memcpy(*bootp, buf.buf, bytes); | 1227 | memcpy(*bootp, buf.buf, bytes); | |
1228 | return bytes; | 1228 | return bytes; | |
1229 | } | 1229 | } | |
1230 | 1230 | |||
1231 | static const struct dhcp_opt * | 1231 | static const struct dhcp_opt * | |
1232 | dhcp_getoverride(const struct if_options *ifo, unsigned int o) | 1232 | dhcp_getoverride(const struct if_options *ifo, unsigned int o) | |
1233 | { | 1233 | { | |
1234 | size_t i; | 1234 | size_t i; | |
1235 | const struct dhcp_opt *opt; | 1235 | const struct dhcp_opt *opt; | |
1236 | 1236 | |||
1237 | for (i = 0, opt = ifo->dhcp_override; | 1237 | for (i = 0, opt = ifo->dhcp_override; | |
1238 | i < ifo->dhcp_override_len; | 1238 | i < ifo->dhcp_override_len; | |
1239 | i++, opt++) | 1239 | i++, opt++) | |
1240 | { | 1240 | { | |
1241 | if (opt->option == o) | 1241 | if (opt->option == o) | |
1242 | return opt; | 1242 | return opt; | |
1243 | } | 1243 | } | |
1244 | return NULL; | 1244 | return NULL; | |
1245 | } | 1245 | } | |
1246 | 1246 | |||
1247 | static const uint8_t * | 1247 | static const uint8_t * | |
1248 | dhcp_getoption(struct dhcpcd_ctx *ctx, | 1248 | dhcp_getoption(struct dhcpcd_ctx *ctx, | |
1249 | size_t *os, unsigned int *code, size_t *len, | 1249 | size_t *os, unsigned int *code, size_t *len, | |
1250 | const uint8_t *od, size_t ol, struct dhcp_opt **oopt) | 1250 | const uint8_t *od, size_t ol, struct dhcp_opt **oopt) | |
1251 | { | 1251 | { | |
1252 | size_t i; | 1252 | size_t i; | |
1253 | struct dhcp_opt *opt; | 1253 | struct dhcp_opt *opt; | |
1254 | 1254 | |||
1255 | if (od) { | 1255 | if (od) { | |
1256 | if (ol < 2) { | 1256 | if (ol < 2) { | |
1257 | errno = EINVAL; | 1257 | errno = EINVAL; | |
1258 | return NULL; | 1258 | return NULL; | |
1259 | } | 1259 | } | |
1260 | *os = 2; /* code + len */ | 1260 | *os = 2; /* code + len */ | |
1261 | *code = (unsigned int)*od++; | 1261 | *code = (unsigned int)*od++; | |
1262 | *len = (size_t)*od++; | 1262 | *len = (size_t)*od++; | |
1263 | if (*len > ol - *os) { | 1263 | if (*len > ol - *os) { | |
1264 | errno = ERANGE; | 1264 | errno = ERANGE; | |
1265 | return NULL; | 1265 | return NULL; | |
1266 | } | 1266 | } | |
1267 | } | 1267 | } | |
1268 | 1268 | |||
1269 | *oopt = NULL; | 1269 | *oopt = NULL; | |
1270 | for (i = 0, opt = ctx->dhcp_opts; i < ctx->dhcp_opts_len; i++, opt++) { | 1270 | for (i = 0, opt = ctx->dhcp_opts; i < ctx->dhcp_opts_len; i++, opt++) { | |
1271 | if (opt->option == *code) { | 1271 | if (opt->option == *code) { | |
1272 | *oopt = opt; | 1272 | *oopt = opt; | |
1273 | break; | 1273 | break; | |
1274 | } | 1274 | } | |
1275 | } | 1275 | } | |
1276 | 1276 | |||
1277 | return od; | 1277 | return od; | |
1278 | } | 1278 | } | |
1279 | 1279 | |||
1280 | ssize_t | 1280 | ssize_t | |
1281 | dhcp_env(FILE *fenv, const char *prefix, const struct interface *ifp, | 1281 | dhcp_env(FILE *fenv, const char *prefix, const struct interface *ifp, | |
1282 | const struct bootp *bootp, size_t bootp_len) | 1282 | const struct bootp *bootp, size_t bootp_len) | |
1283 | { | 1283 | { | |
1284 | const struct if_options *ifo; | 1284 | const struct if_options *ifo; | |
1285 | const uint8_t *p; | 1285 | const uint8_t *p; | |
1286 | struct in_addr addr; | 1286 | struct in_addr addr; | |
1287 | struct in_addr net; | 1287 | struct in_addr net; | |
1288 | struct in_addr brd; | 1288 | struct in_addr brd; | |
1289 | struct dhcp_opt *opt, *vo; | 1289 | struct dhcp_opt *opt, *vo; | |
1290 | size_t i, pl; | 1290 | size_t i, pl; | |
1291 | char safe[(BOOTP_FILE_LEN * 4) + 1]; | 1291 | char safe[(BOOTP_FILE_LEN * 4) + 1]; | |
1292 | uint8_t overl = 0; | 1292 | uint8_t overl = 0; | |
1293 | uint32_t en; | 1293 | uint32_t en; | |
1294 | 1294 | |||
1295 | ifo = ifp->options; | 1295 | ifo = ifp->options; | |
1296 | if (get_option_uint8(ifp->ctx, &overl, bootp, bootp_len, | 1296 | if (get_option_uint8(ifp->ctx, &overl, bootp, bootp_len, | |
1297 | DHO_OPTSOVERLOADED) == -1) | 1297 | DHO_OPTSOVERLOADED) == -1) | |
1298 | overl = 0; | 1298 | overl = 0; | |
1299 | 1299 | |||
1300 | if (bootp->yiaddr || bootp->ciaddr) { | 1300 | if (bootp->yiaddr || bootp->ciaddr) { | |
1301 | /* Set some useful variables that we derive from the DHCP | 1301 | /* Set some useful variables that we derive from the DHCP | |
1302 | * message but are not necessarily in the options */ | 1302 | * message but are not necessarily in the options */ | |
1303 | addr.s_addr = bootp->yiaddr ? bootp->yiaddr : bootp->ciaddr; | 1303 | addr.s_addr = bootp->yiaddr ? bootp->yiaddr : bootp->ciaddr; | |
1304 | if (efprintf(fenv, "%s_ip_address=%s", | 1304 | if (efprintf(fenv, "%s_ip_address=%s", | |
1305 | prefix, inet_ntoa(addr)) == -1) | 1305 | prefix, inet_ntoa(addr)) == -1) | |
1306 | return -1; | 1306 | return -1; | |
1307 | if (get_option_addr(ifp->ctx, &net, | 1307 | if (get_option_addr(ifp->ctx, &net, | |
1308 | bootp, bootp_len, DHO_SUBNETMASK) == -1) { | 1308 | bootp, bootp_len, DHO_SUBNETMASK) == -1) { | |
1309 | net.s_addr = ipv4_getnetmask(addr.s_addr); | 1309 | net.s_addr = ipv4_getnetmask(addr.s_addr); | |
1310 | if (efprintf(fenv, "%s_subnet_mask=%s", | 1310 | if (efprintf(fenv, "%s_subnet_mask=%s", | |
1311 | prefix, inet_ntoa(net)) == -1) | 1311 | prefix, inet_ntoa(net)) == -1) | |
1312 | return -1; | 1312 | return -1; | |
1313 | } | 1313 | } | |
1314 | if (efprintf(fenv, "%s_subnet_cidr=%d", | 1314 | if (efprintf(fenv, "%s_subnet_cidr=%d", | |
1315 | prefix, inet_ntocidr(net))== -1) | 1315 | prefix, inet_ntocidr(net))== -1) | |
1316 | return -1; | 1316 | return -1; | |
1317 | if (get_option_addr(ifp->ctx, &brd, | 1317 | if (get_option_addr(ifp->ctx, &brd, | |
1318 | bootp, bootp_len, DHO_BROADCAST) == -1) | 1318 | bootp, bootp_len, DHO_BROADCAST) == -1) | |
1319 | { | 1319 | { | |
1320 | brd.s_addr = addr.s_addr | ~net.s_addr; | 1320 | brd.s_addr = addr.s_addr | ~net.s_addr; | |
1321 | if (efprintf(fenv, "%s_broadcast_address=%s", | 1321 | if (efprintf(fenv, "%s_broadcast_address=%s", | |
1322 | prefix, inet_ntoa(brd)) == -1) | 1322 | prefix, inet_ntoa(brd)) == -1) | |
1323 | return -1; | 1323 | return -1; | |
1324 | } | 1324 | } | |
1325 | addr.s_addr = bootp->yiaddr & net.s_addr; | 1325 | addr.s_addr = bootp->yiaddr & net.s_addr; | |
1326 | if (efprintf(fenv, "%s_network_number=%s", | 1326 | if (efprintf(fenv, "%s_network_number=%s", | |
1327 | prefix, inet_ntoa(addr)) == -1) | 1327 | prefix, inet_ntoa(addr)) == -1) | |
1328 | return -1; | 1328 | return -1; | |
1329 | } | 1329 | } | |
1330 | 1330 | |||
1331 | if (*bootp->file && !(overl & 1)) { | 1331 | if (*bootp->file && !(overl & 1)) { | |
1332 | print_string(safe, sizeof(safe), OT_STRING, | 1332 | print_string(safe, sizeof(safe), OT_STRING, | |
1333 | bootp->file, sizeof(bootp->file)); | 1333 | bootp->file, sizeof(bootp->file)); | |
1334 | if (efprintf(fenv, "%s_filename=%s", prefix, safe) == -1) | 1334 | if (efprintf(fenv, "%s_filename=%s", prefix, safe) == -1) | |
1335 | return -1; | 1335 | return -1; | |
1336 | } | 1336 | } | |
1337 | if (*bootp->sname && !(overl & 2)) { | 1337 | if (*bootp->sname && !(overl & 2)) { | |
1338 | print_string(safe, sizeof(safe), OT_STRING | OT_DOMAIN, | 1338 | print_string(safe, sizeof(safe), OT_STRING | OT_DOMAIN, | |
1339 | bootp->sname, sizeof(bootp->sname)); | 1339 | bootp->sname, sizeof(bootp->sname)); | |
1340 | if (efprintf(fenv, "%s_server_name=%s", prefix, safe) == -1) | 1340 | if (efprintf(fenv, "%s_server_name=%s", prefix, safe) == -1) | |
1341 | return -1; | 1341 | return -1; | |
1342 | } | 1342 | } | |
1343 | 1343 | |||
1344 | /* Zero our indexes */ | 1344 | /* Zero our indexes */ | |
1345 | for (i = 0, opt = ifp->ctx->dhcp_opts; | 1345 | for (i = 0, opt = ifp->ctx->dhcp_opts; | |
1346 | i < ifp->ctx->dhcp_opts_len; | 1346 | i < ifp->ctx->dhcp_opts_len; | |
1347 | i++, opt++) | 1347 | i++, opt++) | |
1348 | dhcp_zero_index(opt); | 1348 | dhcp_zero_index(opt); | |
1349 | for (i = 0, opt = ifp->options->dhcp_override; | 1349 | for (i = 0, opt = ifp->options->dhcp_override; | |
1350 | i < ifp->options->dhcp_override_len; | 1350 | i < ifp->options->dhcp_override_len; | |
1351 | i++, opt++) | 1351 | i++, opt++) | |
1352 | dhcp_zero_index(opt); | 1352 | dhcp_zero_index(opt); | |
1353 | for (i = 0, opt = ifp->ctx->vivso; | 1353 | for (i = 0, opt = ifp->ctx->vivso; | |
1354 | i < ifp->ctx->vivso_len; | 1354 | i < ifp->ctx->vivso_len; | |
1355 | i++, opt++) | 1355 | i++, opt++) | |
1356 | dhcp_zero_index(opt); | 1356 | dhcp_zero_index(opt); | |
1357 | 1357 | |||
1358 | for (i = 0, opt = ifp->ctx->dhcp_opts; | 1358 | for (i = 0, opt = ifp->ctx->dhcp_opts; | |
1359 | i < ifp->ctx->dhcp_opts_len; | 1359 | i < ifp->ctx->dhcp_opts_len; | |
1360 | i++, opt++) | 1360 | i++, opt++) | |
1361 | { | 1361 | { | |
1362 | if (has_option_mask(ifo->nomask, opt->option)) | 1362 | if (has_option_mask(ifo->nomask, opt->option)) | |
1363 | continue; | 1363 | continue; | |
1364 | if (dhcp_getoverride(ifo, opt->option)) | 1364 | if (dhcp_getoverride(ifo, opt->option)) | |
1365 | continue; | 1365 | continue; | |
1366 | p = get_option(ifp->ctx, bootp, bootp_len, opt->option, &pl); | 1366 | p = get_option(ifp->ctx, bootp, bootp_len, opt->option, &pl); | |
1367 | if (p == NULL) | 1367 | if (p == NULL) | |
1368 | continue; | 1368 | continue; | |
1369 | dhcp_envoption(ifp->ctx, fenv, prefix, ifp->name, | 1369 | dhcp_envoption(ifp->ctx, fenv, prefix, ifp->name, | |
1370 | opt, dhcp_getoption, p, pl); | 1370 | opt, dhcp_getoption, p, pl); | |
1371 | 1371 | |||
1372 | if (opt->option != DHO_VIVSO || pl <= (int)sizeof(uint32_t)) | 1372 | if (opt->option != DHO_VIVSO || pl <= (int)sizeof(uint32_t)) | |
1373 | continue; | 1373 | continue; | |
1374 | memcpy(&en, p, sizeof(en)); | 1374 | memcpy(&en, p, sizeof(en)); | |
1375 | en = ntohl(en); | 1375 | en = ntohl(en); | |
1376 | vo = vivso_find(en, ifp); | 1376 | vo = vivso_find(en, ifp); | |
1377 | if (vo == NULL) | 1377 | if (vo == NULL) | |
1378 | continue; | 1378 | continue; | |
1379 | /* Skip over en + total size */ | 1379 | /* Skip over en + total size */ | |
1380 | p += sizeof(en) + 1; | 1380 | p += sizeof(en) + 1; | |
1381 | pl -= sizeof(en) + 1; | 1381 | pl -= sizeof(en) + 1; | |
1382 | dhcp_envoption(ifp->ctx, fenv, prefix, ifp->name, | 1382 | dhcp_envoption(ifp->ctx, fenv, prefix, ifp->name, | |
1383 | vo, dhcp_getoption, p, pl); | 1383 | vo, dhcp_getoption, p, pl); | |
1384 | } | 1384 | } | |
1385 | 1385 | |||
1386 | for (i = 0, opt = ifo->dhcp_override; | 1386 | for (i = 0, opt = ifo->dhcp_override; | |
1387 | i < ifo->dhcp_override_len; | 1387 | i < ifo->dhcp_override_len; | |
1388 | i++, opt++) | 1388 | i++, opt++) | |
1389 | { | 1389 | { | |
1390 | if (has_option_mask(ifo->nomask, opt->option)) | 1390 | if (has_option_mask(ifo->nomask, opt->option)) | |
1391 | continue; | 1391 | continue; | |
1392 | p = get_option(ifp->ctx, bootp, bootp_len, opt->option, &pl); | 1392 | p = get_option(ifp->ctx, bootp, bootp_len, opt->option, &pl); | |
1393 | if (p == NULL) | 1393 | if (p == NULL) | |
1394 | continue; | 1394 | continue; | |
1395 | dhcp_envoption(ifp->ctx, fenv, prefix, ifp->name, | 1395 | dhcp_envoption(ifp->ctx, fenv, prefix, ifp->name, | |
1396 | opt, dhcp_getoption, p, pl); | 1396 | opt, dhcp_getoption, p, pl); | |
1397 | } | 1397 | } | |
1398 | 1398 | |||
1399 | return 1; | 1399 | return 1; | |
1400 | } | 1400 | } | |
1401 | 1401 | |||
1402 | static void | 1402 | static void | |
1403 | get_lease(struct interface *ifp, | 1403 | get_lease(struct interface *ifp, | |
1404 | struct dhcp_lease *lease, const struct bootp *bootp, size_t len) | 1404 | struct dhcp_lease *lease, const struct bootp *bootp, size_t len) | |
1405 | { | 1405 | { | |
1406 | struct dhcpcd_ctx *ctx; | 1406 | struct dhcpcd_ctx *ctx; | |
1407 | 1407 | |||
1408 | assert(bootp != NULL); | 1408 | assert(bootp != NULL); | |
1409 | 1409 | |||
1410 | memcpy(&lease->cookie, bootp->vend, sizeof(lease->cookie)); | 1410 | memcpy(&lease->cookie, bootp->vend, sizeof(lease->cookie)); | |
1411 | /* BOOTP does not set yiaddr for replies when ciaddr is set. */ | 1411 | /* BOOTP does not set yiaddr for replies when ciaddr is set. */ | |
1412 | lease->addr.s_addr = bootp->yiaddr ? bootp->yiaddr : bootp->ciaddr; | 1412 | lease->addr.s_addr = bootp->yiaddr ? bootp->yiaddr : bootp->ciaddr; | |
1413 | ctx = ifp->ctx; | 1413 | ctx = ifp->ctx; | |
1414 | if (ifp->options->options & (DHCPCD_STATIC | DHCPCD_INFORM)) { | 1414 | if (ifp->options->options & (DHCPCD_STATIC | DHCPCD_INFORM)) { | |
1415 | if (ifp->options->req_addr.s_addr != INADDR_ANY) { | 1415 | if (ifp->options->req_addr.s_addr != INADDR_ANY) { | |
1416 | lease->mask = ifp->options->req_mask; | 1416 | lease->mask = ifp->options->req_mask; | |
1417 | if (ifp->options->req_brd.s_addr != INADDR_ANY) | 1417 | if (ifp->options->req_brd.s_addr != INADDR_ANY) | |
1418 | lease->brd = ifp->options->req_brd; | 1418 | lease->brd = ifp->options->req_brd; | |
1419 | else | 1419 | else | |
1420 | lease->brd.s_addr = | 1420 | lease->brd.s_addr = | |
1421 | lease->addr.s_addr | ~lease->mask.s_addr; | 1421 | lease->addr.s_addr | ~lease->mask.s_addr; | |
1422 | } else { | 1422 | } else { | |
1423 | const struct ipv4_addr *ia; | 1423 | const struct ipv4_addr *ia; | |
1424 | 1424 | |||
1425 | ia = ipv4_iffindaddr(ifp, &lease->addr, NULL); | 1425 | ia = ipv4_iffindaddr(ifp, &lease->addr, NULL); | |
1426 | assert(ia != NULL); | 1426 | assert(ia != NULL); | |
1427 | lease->mask = ia->mask; | 1427 | lease->mask = ia->mask; | |
1428 | lease->brd = ia->brd; | 1428 | lease->brd = ia->brd; | |
1429 | } | 1429 | } | |
1430 | } else { | 1430 | } else { | |
1431 | if (get_option_addr(ctx, &lease->mask, bootp, len, | 1431 | if (get_option_addr(ctx, &lease->mask, bootp, len, | |
1432 | DHO_SUBNETMASK) == -1) | 1432 | DHO_SUBNETMASK) == -1) | |
1433 | lease->mask.s_addr = | 1433 | lease->mask.s_addr = | |
1434 | ipv4_getnetmask(lease->addr.s_addr); | 1434 | ipv4_getnetmask(lease->addr.s_addr); | |
1435 | if (get_option_addr(ctx, &lease->brd, bootp, len, | 1435 | if (get_option_addr(ctx, &lease->brd, bootp, len, | |
1436 | DHO_BROADCAST) == -1) | 1436 | DHO_BROADCAST) == -1) | |
1437 | lease->brd.s_addr = | 1437 | lease->brd.s_addr = | |
1438 | lease->addr.s_addr | ~lease->mask.s_addr; | 1438 | lease->addr.s_addr | ~lease->mask.s_addr; | |
1439 | } | 1439 | } | |
1440 | if (get_option_uint32(ctx, &lease->leasetime, | 1440 | if (get_option_uint32(ctx, &lease->leasetime, | |
1441 | bootp, len, DHO_LEASETIME) != 0) | 1441 | bootp, len, DHO_LEASETIME) != 0) | |
1442 | lease->leasetime = DHCP_INFINITE_LIFETIME; | 1442 | lease->leasetime = DHCP_INFINITE_LIFETIME; | |
1443 | if (get_option_uint32(ctx, &lease->renewaltime, | 1443 | if (get_option_uint32(ctx, &lease->renewaltime, | |
1444 | bootp, len, DHO_RENEWALTIME) != 0) | 1444 | bootp, len, DHO_RENEWALTIME) != 0) | |
1445 | lease->renewaltime = 0; | 1445 | lease->renewaltime = 0; | |
1446 | if (get_option_uint32(ctx, &lease->rebindtime, | 1446 | if (get_option_uint32(ctx, &lease->rebindtime, | |
1447 | bootp, len, DHO_REBINDTIME) != 0) | 1447 | bootp, len, DHO_REBINDTIME) != 0) | |
1448 | lease->rebindtime = 0; | 1448 | lease->rebindtime = 0; | |
1449 | if (get_option_addr(ctx, &lease->server, bootp, len, DHO_SERVERID) != 0) | 1449 | if (get_option_addr(ctx, &lease->server, bootp, len, DHO_SERVERID) != 0) | |
1450 | lease->server.s_addr = INADDR_ANY; | 1450 | lease->server.s_addr = INADDR_ANY; | |
1451 | } | 1451 | } | |
1452 | 1452 | |||
1453 | static const char * | 1453 | static const char * | |
1454 | get_dhcp_op(uint8_t type) | 1454 | get_dhcp_op(uint8_t type) | |
1455 | { | 1455 | { | |
1456 | const struct dhcp_op *d; | 1456 | const struct dhcp_op *d; | |
1457 | 1457 | |||
1458 | for (d = dhcp_ops; d->name; d++) | 1458 | for (d = dhcp_ops; d->name; d++) | |
1459 | if (d->value == type) | 1459 | if (d->value == type) | |
1460 | return d->name; | 1460 | return d->name; | |
1461 | return NULL; | 1461 | return NULL; | |
1462 | } | 1462 | } | |
1463 | 1463 | |||
1464 | static void | 1464 | static void | |
1465 | dhcp_fallback(void *arg) | 1465 | dhcp_fallback(void *arg) | |
1466 | { | 1466 | { | |
1467 | struct interface *iface; | 1467 | struct interface *iface; | |
1468 | 1468 | |||
1469 | iface = (struct interface *)arg; | 1469 | iface = (struct interface *)arg; | |
1470 | dhcpcd_selectprofile(iface, iface->options->fallback); | 1470 | dhcpcd_selectprofile(iface, iface->options->fallback); | |
1471 | dhcpcd_startinterface(iface); | 1471 | dhcpcd_startinterface(iface); | |
1472 | } | 1472 | } | |
1473 | 1473 | |||
1474 | static void | 1474 | static void | |
1475 | dhcp_new_xid(struct interface *ifp) | 1475 | dhcp_new_xid(struct interface *ifp) | |
1476 | { | 1476 | { | |
1477 | struct dhcp_state *state; | 1477 | struct dhcp_state *state; | |
1478 | const struct interface *ifp1; | 1478 | const struct interface *ifp1; | |
1479 | const struct dhcp_state *state1; | 1479 | const struct dhcp_state *state1; | |
1480 | 1480 | |||
1481 | state = D_STATE(ifp); | 1481 | state = D_STATE(ifp); | |
1482 | if (ifp->options->options & DHCPCD_XID_HWADDR && | 1482 | if (ifp->options->options & DHCPCD_XID_HWADDR && | |
1483 | ifp->hwlen >= sizeof(state->xid)) | 1483 | ifp->hwlen >= sizeof(state->xid)) | |
1484 | /* The lower bits are probably more unique on the network */ | 1484 | /* The lower bits are probably more unique on the network */ | |
1485 | memcpy(&state->xid, | 1485 | memcpy(&state->xid, | |
1486 | (ifp->hwaddr + ifp->hwlen) - sizeof(state->xid), | 1486 | (ifp->hwaddr + ifp->hwlen) - sizeof(state->xid), | |
1487 | sizeof(state->xid)); | 1487 | sizeof(state->xid)); | |
1488 | else { | 1488 | else { | |
1489 | again: | 1489 | again: | |
1490 | state->xid = arc4random(); | 1490 | state->xid = arc4random(); | |
1491 | } | 1491 | } | |
1492 | 1492 | |||
1493 | /* Ensure it's unique */ | 1493 | /* Ensure it's unique */ | |
1494 | TAILQ_FOREACH(ifp1, ifp->ctx->ifaces, next) { | 1494 | TAILQ_FOREACH(ifp1, ifp->ctx->ifaces, next) { | |
1495 | if (ifp == ifp1) | 1495 | if (ifp == ifp1) | |
1496 | continue; | 1496 | continue; | |
1497 | if ((state1 = D_CSTATE(ifp1)) == NULL) | 1497 | if ((state1 = D_CSTATE(ifp1)) == NULL) | |
1498 | continue; | 1498 | continue; | |
1499 | if (state1->xid == state->xid) | 1499 | if (state1->xid == state->xid) | |
1500 | break; | 1500 | break; | |
1501 | } | 1501 | } | |
1502 | if (ifp1 != NULL) { | 1502 | if (ifp1 != NULL) { | |
1503 | if (ifp->options->options & DHCPCD_XID_HWADDR && | 1503 | if (ifp->options->options & DHCPCD_XID_HWADDR && | |
1504 | ifp->hwlen >= sizeof(state->xid)) | 1504 | ifp->hwlen >= sizeof(state->xid)) | |
1505 | { | 1505 | { | |
1506 | logerrx("%s: duplicate xid on %s", | 1506 | logerrx("%s: duplicate xid on %s", | |
1507 | ifp->name, ifp1->name); | 1507 | ifp->name, ifp1->name); | |
1508 | return; | 1508 | return; | |
1509 | } | 1509 | } | |
1510 | goto again; | 1510 | goto again; | |
1511 | } | 1511 | } | |
1512 | 1512 | |||
1513 | /* We can't do this when sharing leases across interfaes */ | 1513 | /* We can't do this when sharing leases across interfaes */ | |
1514 | #if 0 | 1514 | #if 0 | |
1515 | /* As the XID changes, re-apply the filter. */ | 1515 | /* As the XID changes, re-apply the filter. */ | |
1516 | if (state->bpf_fd != -1) { | 1516 | if (state->bpf_fd != -1) { | |
1517 | if (bpf_bootp(ifp, state->bpf_fd) == -1) | 1517 | if (bpf_bootp(ifp, state->bpf_fd) == -1) | |
1518 | logerr(__func__); /* try to continue */ | 1518 | logerr(__func__); /* try to continue */ | |
1519 | } | 1519 | } | |
1520 | #endif | 1520 | #endif | |
1521 | } | 1521 | } | |
1522 | 1522 | |||
1523 | void | 1523 | static void | |
1524 | dhcp_close(struct interface *ifp) | 1524 | dhcp_closebpf(struct interface *ifp) | |
1525 | { | 1525 | { | |
1526 | struct dhcpcd_ctx *ctx = ifp->ctx; | 1526 | struct dhcpcd_ctx *ctx = ifp->ctx; | |
1527 | struct dhcp_state *state = D_STATE(ifp); | 1527 | struct dhcp_state *state = D_STATE(ifp); | |
1528 | 1528 | |||
1529 | if (state == NULL) | |||
1530 | return; | |||
1531 | ||||
1532 | #ifdef PRIVSEP | 1529 | #ifdef PRIVSEP | |
1533 | if (IN_PRIVSEP_SE(ctx)) { | 1530 | if (IN_PRIVSEP_SE(ctx)) | |
1534 | ps_bpf_closebootp(ifp); | 1531 | ps_bpf_closebootp(ifp); | |
1535 | if (state->addr != NULL) | |||
1536 | ps_inet_closebootp(state->addr); | |||
1537 | } | |||
1538 | #endif | 1532 | #endif | |
1539 | 1533 | |||
1540 | if (state->bpf != NULL) { | 1534 | if (state->bpf != NULL) { | |
1541 | eloop_event_delete(ctx->eloop, state->bpf->bpf_fd); | 1535 | eloop_event_delete(ctx->eloop, state->bpf->bpf_fd); | |
1542 | bpf_close(state->bpf); | 1536 | bpf_close(state->bpf); | |
1543 | state->bpf = NULL; | 1537 | state->bpf = NULL; | |
1544 | } | 1538 | } | |
1539 | } | |||
1540 | ||||
1541 | static void | |||
1542 | dhcp_closeinet(struct interface *ifp) | |||
1543 | { | |||
1544 | struct dhcpcd_ctx *ctx = ifp->ctx; | |||
1545 | struct dhcp_state *state = D_STATE(ifp); | |||
1546 | ||||
1547 | #ifdef PRIVSEP | |||
1548 | if (IN_PRIVSEP_SE(ctx)) { | |||
1549 | if (state->addr != NULL) | |||
1550 | ps_inet_closebootp(state->addr); | |||
1551 | } | |||
1552 | #endif | |||
1553 | ||||
1545 | if (state->udp_rfd != -1) { | 1554 | if (state->udp_rfd != -1) { | |
1546 | eloop_event_delete(ctx->eloop, state->udp_rfd); | 1555 | eloop_event_delete(ctx->eloop, state->udp_rfd); | |
1547 | close(state->udp_rfd); | 1556 | close(state->udp_rfd); | |
1548 | state->udp_rfd = -1; | 1557 | state->udp_rfd = -1; | |
1549 | } | 1558 | } | |
1559 | } | |||
1560 | ||||
1561 | void | |||
1562 | dhcp_close(struct interface *ifp) | |||
1563 | { | |||
1564 | struct dhcp_state *state = D_STATE(ifp); | |||
1565 | ||||
1566 | if (state == NULL) | |||
1567 | return; | |||
1568 | ||||
1569 | dhcp_closebpf(ifp); | |||
1570 | dhcp_closeinet(ifp); | |||
1550 | 1571 | |||
1551 | state->interval = 0; | 1572 | state->interval = 0; | |
1552 | } | 1573 | } | |
1553 | 1574 | |||
1554 | int | 1575 | int | |
1555 | dhcp_openudp(struct in_addr *ia) | 1576 | dhcp_openudp(struct in_addr *ia) | |
1556 | { | 1577 | { | |
1557 | int s; | 1578 | int s; | |
1558 | struct sockaddr_in sin; | 1579 | struct sockaddr_in sin; | |
1559 | int n; | 1580 | int n; | |
1560 | 1581 | |||
1561 | if ((s = xsocket(PF_INET, SOCK_DGRAM | SOCK_CXNB, IPPROTO_UDP)) == -1) | 1582 | if ((s = xsocket(PF_INET, SOCK_DGRAM | SOCK_CXNB, IPPROTO_UDP)) == -1) | |
1562 | return -1; | 1583 | return -1; | |
1563 | 1584 | |||
1564 | n = 1; | 1585 | n = 1; | |
1565 | if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1) | 1586 | if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1) | |
1566 | goto errexit; | 1587 | goto errexit; | |
1567 | #ifdef IP_RECVIF | 1588 | #ifdef IP_RECVIF | |
1568 | if (setsockopt(s, IPPROTO_IP, IP_RECVIF, &n, sizeof(n)) == -1) | 1589 | if (setsockopt(s, IPPROTO_IP, IP_RECVIF, &n, sizeof(n)) == -1) | |
1569 | goto errexit; | 1590 | goto errexit; | |
1570 | #else | 1591 | #else | |
1571 | if (setsockopt(s, IPPROTO_IP, IP_RECVPKTINFO, &n, sizeof(n)) == -1) | 1592 | if (setsockopt(s, IPPROTO_IP, IP_RECVPKTINFO, &n, sizeof(n)) == -1) | |
1572 | goto errexit; | 1593 | goto errexit; | |
1573 | #endif | 1594 | #endif | |
1574 | #ifdef SO_RERROR | 1595 | #ifdef SO_RERROR | |
1575 | if (setsockopt(s, SOL_SOCKET, SO_RERROR, &n, sizeof(n)) == -1) | 1596 | if (setsockopt(s, SOL_SOCKET, SO_RERROR, &n, sizeof(n)) == -1) | |
1576 | goto errexit; | 1597 | goto errexit; | |
1577 | #endif | 1598 | #endif | |
1578 | 1599 | |||
1579 | memset(&sin, 0, sizeof(sin)); | 1600 | memset(&sin, 0, sizeof(sin)); | |
1580 | sin.sin_family = AF_INET; | 1601 | sin.sin_family = AF_INET; | |
1581 | sin.sin_port = htons(BOOTPC); | 1602 | sin.sin_port = htons(BOOTPC); | |
1582 | if (ia != NULL) | 1603 | if (ia != NULL) | |
1583 | sin.sin_addr = *ia; | 1604 | sin.sin_addr = *ia; | |
1584 | if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == -1) | 1605 | if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == -1) | |
1585 | goto errexit; | 1606 | goto errexit; | |
1586 | 1607 | |||
1587 | return s; | 1608 | return s; | |
1588 | 1609 | |||
1589 | errexit: | 1610 | errexit: | |
1590 | close(s); | 1611 | close(s); | |
1591 | return -1; | 1612 | return -1; | |
1592 | } | 1613 | } | |
1593 | 1614 | |||
1594 | static uint16_t | 1615 | static uint16_t | |
1595 | in_cksum(const void *data, size_t len, uint32_t *isum) | 1616 | in_cksum(const void *data, size_t len, uint32_t *isum) | |
1596 | { | 1617 | { | |
1597 | const uint16_t *word = data; | 1618 | const uint16_t *word = data; | |
1598 | uint32_t sum = isum != NULL ? *isum : 0; | 1619 | uint32_t sum = isum != NULL ? *isum : 0; | |
1599 | 1620 | |||
1600 | for (; len > 1; len -= sizeof(*word)) | 1621 | for (; len > 1; len -= sizeof(*word)) | |
1601 | sum += *word++; | 1622 | sum += *word++; | |
1602 | 1623 | |||
1603 | if (len == 1) | 1624 | if (len == 1) | |
1604 | sum += htons((uint16_t)(*(const uint8_t *)word << 8)); | 1625 | sum += htons((uint16_t)(*(const uint8_t *)word << 8)); | |
1605 | 1626 | |||
1606 | if (isum != NULL) | 1627 | if (isum != NULL) | |
1607 | *isum = sum; | 1628 | *isum = sum; | |
1608 | 1629 | |||
1609 | sum = (sum >> 16) + (sum & 0xffff); | 1630 | sum = (sum >> 16) + (sum & 0xffff); | |
1610 | sum += (sum >> 16); | 1631 | sum += (sum >> 16); | |
1611 | 1632 | |||
1612 | return (uint16_t)~sum; | 1633 | return (uint16_t)~sum; | |
1613 | } | 1634 | } | |
1614 | 1635 | |||
1615 | static struct bootp_pkt * | 1636 | static struct bootp_pkt * | |
1616 | dhcp_makeudppacket(size_t *sz, const uint8_t *data, size_t length, | 1637 | dhcp_makeudppacket(size_t *sz, const uint8_t *data, size_t length, | |
1617 | struct in_addr source, struct in_addr dest) | 1638 | struct in_addr source, struct in_addr dest) | |
1618 | { | 1639 | { | |
1619 | struct bootp_pkt *udpp; | 1640 | struct bootp_pkt *udpp; | |
1620 | struct ip *ip; | 1641 | struct ip *ip; | |
1621 | struct udphdr *udp; | 1642 | struct udphdr *udp; | |
1622 | 1643 | |||
1623 | if ((udpp = calloc(1, sizeof(*ip) + sizeof(*udp) + length)) == NULL) | 1644 | if ((udpp = calloc(1, sizeof(*ip) + sizeof(*udp) + length)) == NULL) | |
1624 | return NULL; | 1645 | return NULL; | |
1625 | ip = &udpp->ip; | 1646 | ip = &udpp->ip; | |
1626 | udp = &udpp->udp; | 1647 | udp = &udpp->udp; | |
1627 | 1648 | |||
1628 | /* OK, this is important :) | 1649 | /* OK, this is important :) | |
1629 | * We copy the data to our packet and then create a small part of the | 1650 | * We copy the data to our packet and then create a small part of the | |
1630 | * ip structure and an invalid ip_len (basically udp length). | 1651 | * ip structure and an invalid ip_len (basically udp length). | |
1631 | * We then fill the udp structure and put the checksum | 1652 | * We then fill the udp structure and put the checksum | |
1632 | * of the whole packet into the udp checksum. | 1653 | * of the whole packet into the udp checksum. | |
1633 | * Finally we complete the ip structure and ip checksum. | 1654 | * Finally we complete the ip structure and ip checksum. | |
1634 | * If we don't do the ordering like so then the udp checksum will be | 1655 | * If we don't do the ordering like so then the udp checksum will be | |
1635 | * broken, so find another way of doing it! */ | 1656 | * broken, so find another way of doing it! */ | |
1636 | 1657 | |||
1637 | memcpy(&udpp->bootp, data, length); | 1658 | memcpy(&udpp->bootp, data, length); | |
1638 | 1659 | |||
1639 | ip->ip_p = IPPROTO_UDP; | 1660 | ip->ip_p = IPPROTO_UDP; | |
1640 | ip->ip_src.s_addr = source.s_addr; | 1661 | ip->ip_src.s_addr = source.s_addr; | |
1641 | if (dest.s_addr == 0) | 1662 | if (dest.s_addr == 0) | |
1642 | ip->ip_dst.s_addr = INADDR_BROADCAST; | 1663 | ip->ip_dst.s_addr = INADDR_BROADCAST; | |
1643 | else | 1664 | else | |
1644 | ip->ip_dst.s_addr = dest.s_addr; | 1665 | ip->ip_dst.s_addr = dest.s_addr; | |
1645 | 1666 | |||
1646 | udp->uh_sport = htons(BOOTPC); | 1667 | udp->uh_sport = htons(BOOTPC); | |
1647 | udp->uh_dport = htons(BOOTPS); | 1668 | udp->uh_dport = htons(BOOTPS); | |
1648 | udp->uh_ulen = htons((uint16_t)(sizeof(*udp) + length)); | 1669 | udp->uh_ulen = htons((uint16_t)(sizeof(*udp) + length)); | |
1649 | ip->ip_len = udp->uh_ulen; | 1670 | ip->ip_len = udp->uh_ulen; | |
1650 | udp->uh_sum = in_cksum(udpp, sizeof(*ip) + sizeof(*udp) + length, NULL); | 1671 | udp->uh_sum = in_cksum(udpp, sizeof(*ip) + sizeof(*udp) + length, NULL); | |
1651 | 1672 | |||
1652 | ip->ip_v = IPVERSION; | 1673 | ip->ip_v = IPVERSION; | |
1653 | ip->ip_hl = sizeof(*ip) >> 2; | 1674 | ip->ip_hl = sizeof(*ip) >> 2; | |
1654 | ip->ip_id = (uint16_t)arc4random_uniform(UINT16_MAX); | 1675 | ip->ip_id = (uint16_t)arc4random_uniform(UINT16_MAX); | |
1655 | ip->ip_ttl = IPDEFTTL; | 1676 | ip->ip_ttl = IPDEFTTL; | |
1656 | ip->ip_len = htons((uint16_t)(sizeof(*ip) + sizeof(*udp) + length)); | 1677 | ip->ip_len = htons((uint16_t)(sizeof(*ip) + sizeof(*udp) + length)); | |
1657 | ip->ip_sum = in_cksum(ip, sizeof(*ip), NULL); | 1678 | ip->ip_sum = in_cksum(ip, sizeof(*ip), NULL); | |
1658 | if (ip->ip_sum == 0) | 1679 | if (ip->ip_sum == 0) | |
1659 | ip->ip_sum = 0xffff; /* RFC 768 */ | 1680 | ip->ip_sum = 0xffff; /* RFC 768 */ | |
1660 | 1681 | |||
1661 | *sz = sizeof(*ip) + sizeof(*udp) + length; | 1682 | *sz = sizeof(*ip) + sizeof(*udp) + length; | |
1662 | return udpp; | 1683 | return udpp; | |
1663 | } | 1684 | } | |
1664 | 1685 | |||
1665 | static ssize_t | 1686 | static ssize_t | |
1666 | dhcp_sendudp(struct interface *ifp, struct in_addr *to, void *data, size_t len) | 1687 | dhcp_sendudp(struct interface *ifp, struct in_addr *to, void *data, size_t len) | |
1667 | { | 1688 | { | |
1668 | struct sockaddr_in sin = { | 1689 | struct sockaddr_in sin = { | |
1669 | .sin_family = AF_INET, | 1690 | .sin_family = AF_INET, | |
1670 | .sin_addr = *to, | 1691 | .sin_addr = *to, | |
1671 | .sin_port = htons(BOOTPS), | 1692 | .sin_port = htons(BOOTPS), | |
1672 | #ifdef HAVE_SA_LEN | 1693 | #ifdef HAVE_SA_LEN | |
1673 | .sin_len = sizeof(sin), | 1694 | .sin_len = sizeof(sin), | |
1674 | #endif | 1695 | #endif | |
1675 | }; | 1696 | }; | |
1676 | struct udphdr udp = { | 1697 | struct udphdr udp = { | |
1677 | .uh_sport = htons(BOOTPC), | 1698 | .uh_sport = htons(BOOTPC), | |
1678 | .uh_dport = htons(BOOTPS), | 1699 | .uh_dport = htons(BOOTPS), | |
1679 | .uh_ulen = htons((uint16_t)(sizeof(udp) + len)), | 1700 | .uh_ulen = htons((uint16_t)(sizeof(udp) + len)), | |
1680 | }; | 1701 | }; | |
1681 | struct iovec iov[] = { | 1702 | struct iovec iov[] = { | |
1682 | { .iov_base = &udp, .iov_len = sizeof(udp), }, | 1703 | { .iov_base = &udp, .iov_len = sizeof(udp), }, | |
1683 | { .iov_base = data, .iov_len = len, }, | 1704 | { .iov_base = data, .iov_len = len, }, | |
1684 | }; | 1705 | }; | |
1685 | struct msghdr msg = { | 1706 | struct msghdr msg = { | |
1686 | .msg_name = (void *)&sin, | 1707 | .msg_name = (void *)&sin, | |
1687 | .msg_namelen = sizeof(sin), | 1708 | .msg_namelen = sizeof(sin), | |
1688 | .msg_iov = iov, | 1709 | .msg_iov = iov, | |
1689 | .msg_iovlen = __arraycount(iov), | 1710 | .msg_iovlen = __arraycount(iov), | |
1690 | }; | 1711 | }; | |
1691 | struct dhcpcd_ctx *ctx = ifp->ctx; | 1712 | struct dhcpcd_ctx *ctx = ifp->ctx; | |
1692 | 1713 | |||
1693 | #ifdef PRIVSEP | 1714 | #ifdef PRIVSEP | |
1694 | if (ctx->options & DHCPCD_PRIVSEP) | 1715 | if (ctx->options & DHCPCD_PRIVSEP) | |
1695 | return ps_inet_sendbootp(ifp, &msg); | 1716 | return ps_inet_sendbootp(ifp, &msg); | |
1696 | #endif | 1717 | #endif | |
1697 | return sendmsg(ctx->udp_wfd, &msg, 0); | 1718 | return sendmsg(ctx->udp_wfd, &msg, 0); | |
1698 | } | 1719 | } | |
1699 | 1720 | |||
1700 | static void | 1721 | static void | |
1701 | send_message(struct interface *ifp, uint8_t type, | 1722 | send_message(struct interface *ifp, uint8_t type, | |
1702 | void (*callback)(void *)) | 1723 | void (*callback)(void *)) | |
1703 | { | 1724 | { | |
1704 | struct dhcp_state *state = D_STATE(ifp); | 1725 | struct dhcp_state *state = D_STATE(ifp); | |
1705 | struct if_options *ifo = ifp->options; | 1726 | struct if_options *ifo = ifp->options; | |
1706 | struct bootp *bootp; | 1727 | struct bootp *bootp; | |
1707 | struct bootp_pkt *udp; | 1728 | struct bootp_pkt *udp; | |
1708 | size_t len, ulen; | 1729 | size_t len, ulen; | |
1709 | ssize_t r; | 1730 | ssize_t r; | |
1710 | struct in_addr from, to; | 1731 | struct in_addr from, to; | |
1711 | unsigned int RT; | 1732 | unsigned int RT; | |
1712 | 1733 | |||
1713 | if (callback == NULL) { | 1734 | if (callback == NULL) { | |
1714 | /* No carrier? Don't bother sending the packet. */ | 1735 | /* No carrier? Don't bother sending the packet. */ | |
1715 | if (!if_is_link_up(ifp)) | 1736 | if (!if_is_link_up(ifp)) | |
1716 | return; | 1737 | return; | |
1717 | logdebugx("%s: sending %s with xid 0x%x", | 1738 | logdebugx("%s: sending %s with xid 0x%x", | |
1718 | ifp->name, | 1739 | ifp->name, | |
1719 | ifo->options & DHCPCD_BOOTP ? "BOOTP" : get_dhcp_op(type), | 1740 | ifo->options & DHCPCD_BOOTP ? "BOOTP" : get_dhcp_op(type), | |
1720 | state->xid); | 1741 | state->xid); | |
1721 | RT = 0; /* bogus gcc warning */ | 1742 | RT = 0; /* bogus gcc warning */ | |
1722 | } else { | 1743 | } else { | |
1723 | if (state->interval == 0) | 1744 | if (state->interval == 0) | |
1724 | state->interval = 4; | 1745 | state->interval = 4; | |
1725 | else { | 1746 | else { | |
1726 | state->interval *= 2; | 1747 | state->interval *= 2; | |
1727 | if (state->interval > 64) | 1748 | if (state->interval > 64) | |
1728 | state->interval = 64; | 1749 | state->interval = 64; | |
1729 | } | 1750 | } | |
1730 | RT = (state->interval * MSEC_PER_SEC) + | 1751 | RT = (state->interval * MSEC_PER_SEC) + | |
1731 | (arc4random_uniform(MSEC_PER_SEC * 2) - MSEC_PER_SEC); | 1752 | (arc4random_uniform(MSEC_PER_SEC * 2) - MSEC_PER_SEC); | |
1732 | /* No carrier? Don't bother sending the packet. | 1753 | /* No carrier? Don't bother sending the packet. | |
1733 | * However, we do need to advance the timeout. */ | 1754 | * However, we do need to advance the timeout. */ | |
1734 | if (!if_is_link_up(ifp)) | 1755 | if (!if_is_link_up(ifp)) | |
1735 | goto fail; | 1756 | goto fail; | |
1736 | logdebugx("%s: sending %s (xid 0x%x), next in %0.1f seconds", | 1757 | logdebugx("%s: sending %s (xid 0x%x), next in %0.1f seconds", | |
1737 | ifp->name, | 1758 | ifp->name, | |
1738 | ifo->options & DHCPCD_BOOTP ? "BOOTP" : get_dhcp_op(type), | 1759 | ifo->options & DHCPCD_BOOTP ? "BOOTP" : get_dhcp_op(type), | |
1739 | state->xid, | 1760 | state->xid, | |
1740 | (float)RT / MSEC_PER_SEC); | 1761 | (float)RT / MSEC_PER_SEC); | |
1741 | } | 1762 | } | |
1742 | 1763 | |||
1743 | r = make_message(&bootp, ifp, type); | 1764 | r = make_message(&bootp, ifp, type); | |
1744 | if (r == -1) | 1765 | if (r == -1) | |
1745 | goto fail; | 1766 | goto fail; | |
1746 | len = (size_t)r; | 1767 | len = (size_t)r; | |
1747 | 1768 | |||
1748 | if (!(state->added & (STATE_FAKE | STATE_EXPIRED)) && | 1769 | if (!(state->added & (STATE_FAKE | STATE_EXPIRED)) && | |
1749 | state->addr != NULL && | 1770 | state->addr != NULL && | |
1750 | ipv4_iffindaddr(ifp, &state->lease.addr, NULL) != NULL) | 1771 | ipv4_iffindaddr(ifp, &state->lease.addr, NULL) != NULL) | |
1751 | from.s_addr = state->lease.addr.s_addr; | 1772 | from.s_addr = state->lease.addr.s_addr; | |
1752 | else | 1773 | else | |
1753 | from.s_addr = INADDR_ANY; | 1774 | from.s_addr = INADDR_ANY; | |
1754 | if (from.s_addr != INADDR_ANY && | 1775 | if (from.s_addr != INADDR_ANY && | |
1755 | state->lease.server.s_addr != INADDR_ANY) | 1776 | state->lease.server.s_addr != INADDR_ANY) | |
1756 | to.s_addr = state->lease.server.s_addr; | 1777 | to.s_addr = state->lease.server.s_addr; | |
1757 | else | 1778 | else | |
1758 | to.s_addr = INADDR_BROADCAST; | 1779 | to.s_addr = INADDR_BROADCAST; | |
1759 | 1780 | |||
1760 | /* | 1781 | /* | |
1761 | * If not listening on the unspecified address we can | 1782 | * If not listening on the unspecified address we can | |
1762 | * only receive broadcast messages via BPF. | 1783 | * only receive broadcast messages via BPF. | |
1763 | * Sockets bound to an address cannot receive broadcast messages | 1784 | * Sockets bound to an address cannot receive broadcast messages | |
1764 | * even if they are setup to send them. | 1785 | * even if they are setup to send them. | |
1765 | * Broadcasting from UDP is only an optimisation for rebinding | 1786 | * Broadcasting from UDP is only an optimisation for rebinding | |
1766 | * and on BSD, at least, is reliant on the subnet route being | 1787 | * and on BSD, at least, is reliant on the subnet route being | |
1767 | * correctly configured to receive the unicast reply. | 1788 | * correctly configured to receive the unicast reply. | |
1768 | * As such, we always broadcast and receive the reply to it via BPF. | 1789 | * As such, we always broadcast and receive the reply to it via BPF. | |
1769 | * This also guarantees we have a DHCP server attached to the | 1790 | * This also guarantees we have a DHCP server attached to the | |
1770 | * interface we want to configure because we can't dictate the | 1791 | * interface we want to configure because we can't dictate the | |
1771 | * interface via IP_PKTINFO unlike for IPv6. | 1792 | * interface via IP_PKTINFO unlike for IPv6. | |
1772 | */ | 1793 | */ | |
1773 | if (to.s_addr != INADDR_BROADCAST) { | 1794 | if (to.s_addr != INADDR_BROADCAST) { | |
1774 | if (dhcp_sendudp(ifp, &to, bootp, len) != -1) | 1795 | if (dhcp_sendudp(ifp, &to, bootp, len) != -1) | |
1775 | goto out; | 1796 | goto out; | |
1776 | logerr("%s: dhcp_sendudp", ifp->name); | 1797 | logerr("%s: dhcp_sendudp", ifp->name); | |
1777 | } | 1798 | } | |
1778 | 1799 | |||
1779 | if (dhcp_openbpf(ifp) == -1) | 1800 | if (dhcp_openbpf(ifp) == -1) | |
1780 | goto out; | 1801 | goto out; | |
1781 | 1802 | |||
1782 | udp = dhcp_makeudppacket(&ulen, (uint8_t *)bootp, len, from, to); | 1803 | udp = dhcp_makeudppacket(&ulen, (uint8_t *)bootp, len, from, to); | |
1783 | if (udp == NULL) { | 1804 | if (udp == NULL) { | |
1784 | logerr("%s: dhcp_makeudppacket", ifp->name); | 1805 | logerr("%s: dhcp_makeudppacket", ifp->name); | |
1785 | r = 0; | 1806 | r = 0; | |
1786 | #ifdef PRIVSEP | 1807 | #ifdef PRIVSEP | |
1787 | } else if (ifp->ctx->options & DHCPCD_PRIVSEP) { | 1808 | } else if (ifp->ctx->options & DHCPCD_PRIVSEP) { | |
1788 | r = ps_bpf_sendbootp(ifp, udp, ulen); | 1809 | r = ps_bpf_sendbootp(ifp, udp, ulen); | |
1789 | free(udp); | 1810 | free(udp); | |
1790 | #endif | 1811 | #endif | |
1791 | } else { | 1812 | } else { | |
1792 | r = bpf_send(state->bpf, ETHERTYPE_IP, udp, ulen); | 1813 | r = bpf_send(state->bpf, ETHERTYPE_IP, udp, ulen); | |
1793 | free(udp); | 1814 | free(udp); | |
1794 | } | 1815 | } | |
1795 | /* If we failed to send a raw packet this normally means | 1816 | /* If we failed to send a raw packet this normally means | |
1796 | * we don't have the ability to work beneath the IP layer | 1817 | * we don't have the ability to work beneath the IP layer | |
1797 | * for this interface. | 1818 | * for this interface. | |
1798 | * As such we remove it from consideration without actually | 1819 | * As such we remove it from consideration without actually | |
1799 | * stopping the interface. */ | 1820 | * stopping the interface. */ | |
1800 | if (r == -1) { | 1821 | if (r == -1) { | |
1801 | logerr("%s: bpf_send", ifp->name); | 1822 | logerr("%s: bpf_send", ifp->name); | |
1802 | switch(errno) { | 1823 | switch(errno) { | |
1803 | case ENETDOWN: | 1824 | case ENETDOWN: | |
1804 | case ENETRESET: | 1825 | case ENETRESET: | |
1805 | case ENETUNREACH: | 1826 | case ENETUNREACH: | |
1806 | case ENOBUFS: | 1827 | case ENOBUFS: | |
1807 | break; | 1828 | break; | |
1808 | default: | 1829 | default: | |
1809 | if (!(ifp->ctx->options & DHCPCD_TEST)) | 1830 | if (!(ifp->ctx->options & DHCPCD_TEST)) | |
1810 | dhcp_drop(ifp, "FAIL"); | 1831 | dhcp_drop(ifp, "FAIL"); | |
1811 | eloop_timeout_delete(ifp->ctx->eloop, | 1832 | eloop_timeout_delete(ifp->ctx->eloop, | |
1812 | NULL, ifp); | 1833 | NULL, ifp); | |
1813 | callback = NULL; | 1834 | callback = NULL; | |
1814 | } | 1835 | } | |
1815 | } | 1836 | } | |
1816 | 1837 | |||
1817 | out: | 1838 | out: | |
1818 | free(bootp); | 1839 | free(bootp); | |
1819 | 1840 | |||
1820 | fail: | 1841 | fail: | |
1821 | /* Even if we fail to send a packet we should continue as we are | 1842 | /* Even if we fail to send a packet we should continue as we are | |
1822 | * as our failure timeouts will change out codepath when needed. */ | 1843 | * as our failure timeouts will change out codepath when needed. */ | |
1823 | if (callback != NULL) | 1844 | if (callback != NULL) | |
1824 | eloop_timeout_add_msec(ifp->ctx->eloop, RT, callback, ifp); | 1845 | eloop_timeout_add_msec(ifp->ctx->eloop, RT, callback, ifp); | |
1825 | } | 1846 | } | |
1826 | 1847 | |||
1827 | static void | 1848 | static void | |
1828 | send_inform(void *arg) | 1849 | send_inform(void *arg) | |
1829 | { | 1850 | { | |
1830 | 1851 | |||
1831 | send_message((struct interface *)arg, DHCP_INFORM, send_inform); | 1852 | send_message((struct interface *)arg, DHCP_INFORM, send_inform); | |
1832 | } | 1853 | } | |
1833 | 1854 | |||
1834 | static void | 1855 | static void | |
1835 | send_discover(void *arg) | 1856 | send_discover(void *arg) | |
1836 | { | 1857 | { | |
1837 | 1858 | |||
1838 | send_message((struct interface *)arg, DHCP_DISCOVER, send_discover); | 1859 | send_message((struct interface *)arg, DHCP_DISCOVER, send_discover); | |
1839 | } | 1860 | } | |
1840 | 1861 | |||
1841 | static void | 1862 | static void | |
1842 | send_request(void *arg) | 1863 | send_request(void *arg) | |
1843 | { | 1864 | { | |
1844 | 1865 | |||
1845 | send_message((struct interface *)arg, DHCP_REQUEST, send_request); | 1866 | send_message((struct interface *)arg, DHCP_REQUEST, send_request); | |
1846 | } | 1867 | } | |
1847 | 1868 | |||
1848 | static void | 1869 | static void | |
1849 | send_renew(void *arg) | 1870 | send_renew(void *arg) | |
1850 | { | 1871 | { | |
1851 | 1872 | |||
1852 | send_message((struct interface *)arg, DHCP_REQUEST, send_renew); | 1873 | send_message((struct interface *)arg, DHCP_REQUEST, send_renew); | |
1853 | } | 1874 | } | |
1854 | 1875 | |||
1855 | static void | 1876 | static void | |
1856 | send_rebind(void *arg) | 1877 | send_rebind(void *arg) | |
1857 | { | 1878 | { | |
1858 | 1879 | |||
1859 | send_message((struct interface *)arg, DHCP_REQUEST, send_rebind); | 1880 | send_message((struct interface *)arg, DHCP_REQUEST, send_rebind); | |
1860 | } | 1881 | } | |
1861 | 1882 | |||
1862 | void | 1883 | void | |
1863 | dhcp_discover(void *arg) | 1884 | dhcp_discover(void *arg) | |
1864 | { | 1885 | { | |
1865 | struct interface *ifp = arg; | 1886 | struct interface *ifp = arg; | |
1866 | struct dhcp_state *state = D_STATE(ifp); | 1887 | struct dhcp_state *state = D_STATE(ifp); | |
1867 | struct if_options *ifo = ifp->options; | 1888 | struct if_options *ifo = ifp->options; | |
1868 | 1889 | |||
1869 | state->state = DHS_DISCOVER; | 1890 | state->state = DHS_DISCOVER; | |
1870 | dhcp_new_xid(ifp); | 1891 | dhcp_new_xid(ifp); | |
1871 | eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); | 1892 | eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); | |
1872 | if (!(state->added & STATE_EXPIRED)) { | 1893 | if (!(state->added & STATE_EXPIRED)) { | |
1873 | if (ifo->fallback) | 1894 | if (ifo->fallback) | |
1874 | eloop_timeout_add_sec(ifp->ctx->eloop, | 1895 | eloop_timeout_add_sec(ifp->ctx->eloop, | |
1875 | ifo->reboot, dhcp_fallback, ifp); | 1896 | ifo->reboot, dhcp_fallback, ifp); | |
1876 | #ifdef IPV4LL | 1897 | #ifdef IPV4LL | |
1877 | else if (ifo->options & DHCPCD_IPV4LL) | 1898 | else if (ifo->options & DHCPCD_IPV4LL) | |
1878 | eloop_timeout_add_sec(ifp->ctx->eloop, | 1899 | eloop_timeout_add_sec(ifp->ctx->eloop, | |
1879 | ifo->reboot, ipv4ll_start, ifp); | 1900 | ifo->reboot, ipv4ll_start, ifp); | |
1880 | #endif | 1901 | #endif | |
1881 | } | 1902 | } | |
1882 | if (ifo->options & DHCPCD_REQUEST) | 1903 | if (ifo->options & DHCPCD_REQUEST) | |
1883 | loginfox("%s: soliciting a DHCP lease (requesting %s)", | 1904 | loginfox("%s: soliciting a DHCP lease (requesting %s)", | |
1884 | ifp->name, inet_ntoa(ifo->req_addr)); | 1905 | ifp->name, inet_ntoa(ifo->req_addr)); | |
1885 | else | 1906 | else | |
1886 | loginfox("%s: soliciting a %s lease", | 1907 | loginfox("%s: soliciting a %s lease", | |
1887 | ifp->name, ifo->options & DHCPCD_BOOTP ? "BOOTP" : "DHCP"); | 1908 | ifp->name, ifo->options & DHCPCD_BOOTP ? "BOOTP" : "DHCP"); | |
1888 | send_discover(ifp); | 1909 | send_discover(ifp); | |
1889 | } | 1910 | } | |
1890 | 1911 | |||
1891 | static void | 1912 | static void | |
1892 | dhcp_request(void *arg) | 1913 | dhcp_request(void *arg) | |
1893 | { | 1914 | { | |
1894 | struct interface *ifp = arg; | 1915 | struct interface *ifp = arg; | |
1895 | struct dhcp_state *state = D_STATE(ifp); | 1916 | struct dhcp_state *state = D_STATE(ifp); | |
1896 | 1917 | |||
1897 | state->state = DHS_REQUEST; | 1918 | state->state = DHS_REQUEST; | |
1898 | send_request(ifp); | 1919 | send_request(ifp); | |
1899 | } | 1920 | } | |
1900 | 1921 | |||
1901 | static void | 1922 | static void | |
1902 | dhcp_expire(void *arg) | 1923 | dhcp_expire(void *arg) | |
1903 | { | 1924 | { | |
1904 | struct interface *ifp = arg; | 1925 | struct interface *ifp = arg; | |
1905 | struct dhcp_state *state = D_STATE(ifp); | 1926 | struct dhcp_state *state = D_STATE(ifp); | |
1906 | 1927 | |||
1907 | if (ifp->options->options & DHCPCD_LASTLEASE_EXTEND) { | 1928 | if (ifp->options->options & DHCPCD_LASTLEASE_EXTEND) { | |
1908 | logwarnx("%s: DHCP lease expired, extending lease", ifp->name); | 1929 | logwarnx("%s: DHCP lease expired, extending lease", ifp->name); | |
1909 | state->added |= STATE_EXPIRED; | 1930 | state->added |= STATE_EXPIRED; | |
1910 | } else { | 1931 | } else { | |
1911 | logerrx("%s: DHCP lease expired", ifp->name); | 1932 | logerrx("%s: DHCP lease expired", ifp->name); | |
1912 | dhcp_drop(ifp, "EXPIRE"); | 1933 | dhcp_drop(ifp, "EXPIRE"); | |
1913 | dhcp_unlink(ifp->ctx, state->leasefile); | 1934 | dhcp_unlink(ifp->ctx, state->leasefile); | |
1914 | } | 1935 | } | |
1915 | state->interval = 0; | 1936 | state->interval = 0; | |
1916 | dhcp_discover(ifp); | 1937 | dhcp_discover(ifp); | |
1917 | } | 1938 | } | |
1918 | 1939 | |||
1919 | #if defined(ARP) || defined(IN_IFF_DUPLICATED) | 1940 | #if defined(ARP) || defined(IN_IFF_DUPLICATED) | |
1920 | static void | 1941 | static void | |
1921 | dhcp_decline(struct interface *ifp) | 1942 | dhcp_decline(struct interface *ifp) | |
1922 | { | 1943 | { | |
1923 | 1944 | |||
1924 | send_message(ifp, DHCP_DECLINE, NULL); | 1945 | send_message(ifp, DHCP_DECLINE, NULL); | |
1925 | } | 1946 | } | |
1926 | #endif | 1947 | #endif | |
1927 | 1948 | |||
1928 | static void | 1949 | static void | |
1929 | dhcp_startrenew(void *arg) | 1950 | dhcp_startrenew(void *arg) | |
1930 | { | 1951 | { | |
1931 | struct interface *ifp = arg; | 1952 | struct interface *ifp = arg; | |
1932 | struct dhcp_state *state; | 1953 | struct dhcp_state *state; | |
1933 | struct dhcp_lease *lease; | 1954 | struct dhcp_lease *lease; | |
1934 | 1955 | |||
1935 | if ((state = D_STATE(ifp)) == NULL) | 1956 | if ((state = D_STATE(ifp)) == NULL) | |
1936 | return; | 1957 | return; | |
1937 | 1958 | |||
1938 | /* Only renew in the bound or renew states */ | 1959 | /* Only renew in the bound or renew states */ | |
1939 | if (state->state != DHS_BOUND && | 1960 | if (state->state != DHS_BOUND && | |
1940 | state->state != DHS_RENEW) | 1961 | state->state != DHS_RENEW) | |
1941 | return; | 1962 | return; | |
1942 | 1963 | |||
1943 | /* Remove the timeout as the renew may have been forced. */ | 1964 | /* Remove the timeout as the renew may have been forced. */ | |
1944 | eloop_timeout_delete(ifp->ctx->eloop, dhcp_startrenew, ifp); | 1965 | eloop_timeout_delete(ifp->ctx->eloop, dhcp_startrenew, ifp); | |
1945 | 1966 | |||
1946 | lease = &state->lease; | 1967 | lease = &state->lease; | |
1947 | logdebugx("%s: renewing lease of %s", ifp->name, | 1968 | logdebugx("%s: renewing lease of %s", ifp->name, | |
1948 | inet_ntoa(lease->addr)); | 1969 | inet_ntoa(lease->addr)); | |
1949 | state->state = DHS_RENEW; | 1970 | state->state = DHS_RENEW; | |
1950 | dhcp_new_xid(ifp); | 1971 | dhcp_new_xid(ifp); | |
1951 | state->interval = 0; | 1972 | state->interval = 0; | |
1952 | send_renew(ifp); | 1973 | send_renew(ifp); | |
1953 | } | 1974 | } | |
1954 | 1975 | |||
1955 | void | 1976 | void | |
1956 | dhcp_renew(struct interface *ifp) | 1977 | dhcp_renew(struct interface *ifp) | |
1957 | { | 1978 | { | |
1958 | 1979 | |||
1959 | dhcp_startrenew(ifp); | 1980 | dhcp_startrenew(ifp); | |
1960 | } | 1981 | } | |
1961 | 1982 | |||
1962 | static void | 1983 | static void | |
1963 | dhcp_rebind(void *arg) | 1984 | dhcp_rebind(void *arg) | |
1964 | { | 1985 | { | |
1965 | struct interface *ifp = arg; | 1986 | struct interface *ifp = arg; | |
1966 | struct dhcp_state *state = D_STATE(ifp); | 1987 | struct dhcp_state *state = D_STATE(ifp); | |
1967 | struct dhcp_lease *lease = &state->lease; | 1988 | struct dhcp_lease *lease = &state->lease; | |
1968 | 1989 | |||
1969 | logwarnx("%s: failed to renew DHCP, rebinding", ifp->name); | 1990 | logwarnx("%s: failed to renew DHCP, rebinding", ifp->name); | |
1970 | logdebugx("%s: expire in %"PRIu32" seconds", | 1991 | logdebugx("%s: expire in %"PRIu32" seconds", | |
1971 | ifp->name, lease->leasetime - lease->rebindtime); | 1992 | ifp->name, lease->leasetime - lease->rebindtime); | |
1972 | state->state = DHS_REBIND; | 1993 | state->state = DHS_REBIND; | |
1973 | eloop_timeout_delete(ifp->ctx->eloop, send_renew, ifp); | 1994 | eloop_timeout_delete(ifp->ctx->eloop, send_renew, ifp); | |
1974 | state->lease.server.s_addr = INADDR_ANY; | 1995 | state->lease.server.s_addr = INADDR_ANY; | |
1975 | state->interval = 0; | 1996 | state->interval = 0; | |
1976 | ifp->options->options &= ~(DHCPCD_CSR_WARNED | | 1997 | ifp->options->options &= ~(DHCPCD_CSR_WARNED | | |
1977 | DHCPCD_ROUTER_HOST_ROUTE_WARNED); | 1998 | DHCPCD_ROUTER_HOST_ROUTE_WARNED); | |
1978 | send_rebind(ifp); | 1999 | send_rebind(ifp); | |
1979 | } | 2000 | } | |
1980 | 2001 | |||
1981 | #if defined(ARP) || defined(IN_IFF_DUPLICATED) | 2002 | #if defined(ARP) || defined(IN_IFF_DUPLICATED) | |
1982 | static void | 2003 | static void | |
1983 | dhcp_finish_dad(struct interface *ifp, struct in_addr *ia) | 2004 | dhcp_finish_dad(struct interface *ifp, struct in_addr *ia) | |
1984 | { | 2005 | { | |
1985 | struct dhcp_state *state = D_STATE(ifp); | 2006 | struct dhcp_state *state = D_STATE(ifp); | |
1986 | 2007 | |||
1987 | if (state->state != DHS_PROBE) | 2008 | if (state->state != DHS_PROBE) | |
1988 | return; | 2009 | return; | |
1989 | if (state->offer == NULL || state->offer->yiaddr != ia->s_addr) | 2010 | if (state->offer == NULL || state->offer->yiaddr != ia->s_addr) | |
1990 | return; | 2011 | return; | |
1991 | 2012 | |||
1992 | logdebugx("%s: DAD completed for %s", ifp->name, inet_ntoa(*ia)); | 2013 | logdebugx("%s: DAD completed for %s", ifp->name, inet_ntoa(*ia)); | |
1993 | if (!(ifp->options->options & DHCPCD_INFORM)) | 2014 | if (!(ifp->options->options & DHCPCD_INFORM)) | |
1994 | dhcp_bind(ifp); | 2015 | dhcp_bind(ifp); | |
1995 | #ifndef IN_IFF_DUPLICATED | 2016 | #ifndef IN_IFF_DUPLICATED | |
1996 | else { | 2017 | else { | |
1997 | struct bootp *bootp; | 2018 | struct bootp *bootp; | |
1998 | size_t len; | 2019 | size_t len; | |
1999 | 2020 | |||
2000 | bootp = state->new; | 2021 | bootp = state->new; | |
2001 | len = state->new_len; | 2022 | len = state->new_len; | |
2002 | state->new = state->offer; | 2023 | state->new = state->offer; | |
2003 | state->new_len = state->offer_len; | 2024 | state->new_len = state->offer_len; | |
2004 | get_lease(ifp, &state->lease, state->new, state->new_len); | 2025 | get_lease(ifp, &state->lease, state->new, state->new_len); | |
2005 | ipv4_applyaddr(ifp); | 2026 | ipv4_applyaddr(ifp); | |
2006 | state->new = bootp; | 2027 | state->new = bootp; | |
2007 | state->new_len = len; | 2028 | state->new_len = len; | |
2008 | } | 2029 | } | |
2009 | #endif | 2030 | #endif | |
2010 | 2031 | |||
2011 | #ifdef IPV4LL | 2032 | #ifdef IPV4LL | |
2012 | /* Stop IPv4LL now we have a working DHCP address */ | 2033 | /* Stop IPv4LL now we have a working DHCP address */ | |
2013 | ipv4ll_drop(ifp); | 2034 | ipv4ll_drop(ifp); | |
2014 | #endif | 2035 | #endif | |
2015 | 2036 | |||
2016 | if (ifp->options->options & DHCPCD_INFORM) | 2037 | if (ifp->options->options & DHCPCD_INFORM) | |
2017 | dhcp_inform(ifp); | 2038 | dhcp_inform(ifp); | |
2018 | } | 2039 | } | |
2019 | 2040 | |||
2020 | 2041 | |||
2021 | static bool | 2042 | static bool | |
2022 | dhcp_addr_duplicated(struct interface *ifp, struct in_addr *ia) | 2043 | dhcp_addr_duplicated(struct interface *ifp, struct in_addr *ia) | |
2023 | { | 2044 | { | |
2024 | struct dhcp_state *state = D_STATE(ifp); | 2045 | struct dhcp_state *state = D_STATE(ifp); | |
2025 | unsigned long long opts = ifp->options->options; | 2046 | unsigned long long opts = ifp->options->options; | |
2026 | struct dhcpcd_ctx *ctx = ifp->ctx; | 2047 | struct dhcpcd_ctx *ctx = ifp->ctx; | |
2027 | bool deleted = false; | 2048 | bool deleted = false; | |
2028 | #ifdef IN_IFF_DUPLICATED | 2049 | #ifdef IN_IFF_DUPLICATED | |
2029 | struct ipv4_addr *iap; | 2050 | struct ipv4_addr *iap; | |
2030 | #endif | 2051 | #endif | |
2031 | 2052 | |||
2032 | if ((state->offer == NULL || state->offer->yiaddr != ia->s_addr) && | 2053 | if ((state->offer == NULL || state->offer->yiaddr != ia->s_addr) && | |
2033 | !IN_ARE_ADDR_EQUAL(ia, &state->lease.addr)) | 2054 | !IN_ARE_ADDR_EQUAL(ia, &state->lease.addr)) | |
2034 | return deleted; | 2055 | return deleted; | |
2035 | 2056 | |||
2036 | /* RFC 2131 3.1.5, Client-server interaction */ | 2057 | /* RFC 2131 3.1.5, Client-server interaction */ | |
2037 | logerrx("%s: DAD detected %s", ifp->name, inet_ntoa(*ia)); | 2058 | logerrx("%s: DAD detected %s", ifp->name, inet_ntoa(*ia)); | |
2038 | dhcp_unlink(ifp->ctx, state->leasefile); | 2059 | dhcp_unlink(ifp->ctx, state->leasefile); | |
2039 | if (!(opts & DHCPCD_STATIC) && !state->lease.frominfo) | 2060 | if (!(opts & DHCPCD_STATIC) && !state->lease.frominfo) | |
2040 | dhcp_decline(ifp); | 2061 | dhcp_decline(ifp); | |
2041 | #ifdef IN_IFF_DUPLICATED | 2062 | #ifdef IN_IFF_DUPLICATED | |
2042 | if ((iap = ipv4_iffindaddr(ifp, ia, NULL)) != NULL) { | 2063 | if ((iap = ipv4_iffindaddr(ifp, ia, NULL)) != NULL) { | |
2043 | ipv4_deladdr(iap, 0); | 2064 | ipv4_deladdr(iap, 0); | |
2044 | deleted = true; | 2065 | deleted = true; | |
2045 | } | 2066 | } | |
2046 | #endif | 2067 | #endif | |
2047 | eloop_timeout_delete(ctx->eloop, NULL, ifp); | 2068 | eloop_timeout_delete(ctx->eloop, NULL, ifp); | |
2048 | if (opts & (DHCPCD_STATIC | DHCPCD_INFORM)) { | 2069 | if (opts & (DHCPCD_STATIC | DHCPCD_INFORM)) { | |
2049 | state->reason = "EXPIRE"; | 2070 | state->reason = "EXPIRE"; | |
2050 | script_runreason(ifp, state->reason); | 2071 | script_runreason(ifp, state->reason); | |
2051 | #define NOT_ONLY_SELF (DHCPCD_MASTER | DHCPCD_IPV6RS | DHCPCD_DHCP6) | 2072 | #define NOT_ONLY_SELF (DHCPCD_MASTER | DHCPCD_IPV6RS | DHCPCD_DHCP6) | |
2052 | if (!(ctx->options & NOT_ONLY_SELF)) | 2073 | if (!(ctx->options & NOT_ONLY_SELF)) | |
2053 | eloop_exit(ifp->ctx->eloop, EXIT_FAILURE); | 2074 | eloop_exit(ifp->ctx->eloop, EXIT_FAILURE); | |
2054 | return deleted; | 2075 | return deleted; | |
2055 | } | 2076 | } | |
2056 | eloop_timeout_add_sec(ifp->ctx->eloop, | 2077 | eloop_timeout_add_sec(ifp->ctx->eloop, | |
2057 | DHCP_RAND_MAX, dhcp_discover, ifp); | 2078 | DHCP_RAND_MAX, dhcp_discover, ifp); | |
2058 | return deleted; | 2079 | return deleted; | |
2059 | } | 2080 | } | |
2060 | #endif | 2081 | #endif | |
2061 | 2082 | |||
2062 | #ifdef ARP | 2083 | #ifdef ARP | |
2063 | #ifdef KERNEL_RFC5227 | 2084 | #ifdef KERNEL_RFC5227 | |
2085 | #ifdef ARPING | |||
2064 | static void | 2086 | static void | |
2065 | dhcp_arp_announced(struct arp_state *state) | 2087 | dhcp_arp_announced(struct arp_state *state) | |
2066 | { | 2088 | { | |
2067 | 2089 | |||
2068 | arp_free(state); | 2090 | arp_free(state); | |
2069 | } | 2091 | } | |
2092 | #endif | |||
2070 | #else | 2093 | #else | |
2071 | static void | 2094 | static void | |
2072 | dhcp_arp_defend_failed(struct arp_state *astate) | 2095 | dhcp_arp_defend_failed(struct arp_state *astate) | |
2073 | { | 2096 | { | |
2074 | struct interface *ifp = astate->iface; | 2097 | struct interface *ifp = astate->iface; | |
2075 | 2098 | |||
2076 | dhcp_drop(ifp, "EXPIRED"); | 2099 | dhcp_drop(ifp, "EXPIRED"); | |
2077 | dhcp_start1(ifp); | 2100 | dhcp_start1(ifp); | |
2078 | } | 2101 | } | |
2079 | #endif | 2102 | #endif | |
2080 | 2103 | |||
2081 | #if !defined(KERNEL_RFC5227) || defined(ARPING) | 2104 | #if !defined(KERNEL_RFC5227) || defined(ARPING) | |
2082 | static void dhcp_arp_not_found(struct arp_state *); | 2105 | static void dhcp_arp_not_found(struct arp_state *); | |
2083 | 2106 | |||
2084 | static struct arp_state * | 2107 | static struct arp_state * | |
2085 | dhcp_arp_new(struct interface *ifp, struct in_addr *addr) | 2108 | dhcp_arp_new(struct interface *ifp, struct in_addr *addr) | |
2086 | { | 2109 | { | |
2087 | struct arp_state *astate; | 2110 | struct arp_state *astate; | |
2088 | 2111 | |||
2089 | astate = arp_new(ifp, addr); | 2112 | astate = arp_new(ifp, addr); | |
2090 | if (astate == NULL) | 2113 | if (astate == NULL) | |
2091 | return NULL; | 2114 | return NULL; | |
2092 | 2115 | |||
2093 | astate->found_cb = dhcp_arp_found; | 2116 | astate->found_cb = dhcp_arp_found; | |
2094 | astate->not_found_cb = dhcp_arp_not_found; | 2117 | astate->not_found_cb = dhcp_arp_not_found; | |
2095 | #ifdef KERNEL_RFC5227 | 2118 | #ifdef KERNEL_RFC5227 | |
2096 | astate->announced_cb = dhcp_arp_announced; | 2119 | astate->announced_cb = dhcp_arp_announced; | |
2097 | #else | 2120 | #else | |
2098 | astate->announced_cb = NULL; | 2121 | astate->announced_cb = NULL; | |
2099 | astate->defend_failed_cb = dhcp_arp_defend_failed; | 2122 | astate->defend_failed_cb = dhcp_arp_defend_failed; | |
2100 | #endif | 2123 | #endif | |
2101 | return astate; | 2124 | return astate; | |
2102 | } | 2125 | } | |
2103 | #endif | 2126 | #endif | |
2104 | 2127 | |||
2105 | #ifdef ARPING | 2128 | #ifdef ARPING | |
2106 | static int | 2129 | static int | |
2107 | dhcp_arping(struct interface *ifp) | 2130 | dhcp_arping(struct interface *ifp) | |
2108 | { | 2131 | { | |
2109 | struct dhcp_state *state; | 2132 | struct dhcp_state *state; | |
2110 | struct if_options *ifo; | 2133 | struct if_options *ifo; | |
2111 | struct arp_state *astate; | 2134 | struct arp_state *astate; | |
2112 | struct in_addr addr; | 2135 | struct in_addr addr; | |
2113 | 2136 | |||
2114 | state = D_STATE(ifp); | 2137 | state = D_STATE(ifp); | |
2115 | ifo = ifp->options; | 2138 | ifo = ifp->options; | |
2116 | 2139 | |||
2117 | if (ifo->arping_len == 0 || state->arping_index > ifo->arping_len) | 2140 | if (ifo->arping_len == 0 || state->arping_index > ifo->arping_len) | |
2118 | return 0; | 2141 | return 0; | |
2119 | 2142 | |||
2120 | if (state->arping_index + 1 == ifo->arping_len) { | 2143 | if (state->arping_index + 1 == ifo->arping_len) { | |
2121 | state->arping_index++; | 2144 | state->arping_index++; | |
2122 | dhcpcd_startinterface(ifp); | 2145 | dhcpcd_startinterface(ifp); | |
2123 | return 1; | 2146 | return 1; | |
2124 | } | 2147 | } | |
2125 | 2148 | |||
2126 | addr.s_addr = ifo->arping[++state->arping_index]; | 2149 | addr.s_addr = ifo->arping[++state->arping_index]; | |
2127 | astate = dhcp_arp_new(ifp, &addr); | 2150 | astate = dhcp_arp_new(ifp, &addr); | |
2128 | if (astate == NULL) { | 2151 | if (astate == NULL) { | |
2129 | logerr(__func__); | 2152 | logerr(__func__); | |
2130 | return -1; | 2153 | return -1; | |
2131 | } | 2154 | } | |
2132 | arp_probe(astate); | 2155 | arp_probe(astate); | |
2133 | return 1; | 2156 | return 1; | |
2134 | } | 2157 | } | |
2135 | #endif | 2158 | #endif | |
2136 | 2159 | |||
2137 | #if !defined(KERNEL_RFC5227) || defined(ARPING) | 2160 | #if !defined(KERNEL_RFC5227) || defined(ARPING) | |
2138 | static void | 2161 | static void | |
2139 | dhcp_arp_not_found(struct arp_state *astate) | 2162 | dhcp_arp_not_found(struct arp_state *astate) | |
2140 | { | 2163 | { | |
2141 | struct interface *ifp; | 2164 | struct interface *ifp; | |
2142 | 2165 | |||
2143 | ifp = astate->iface; | 2166 | ifp = astate->iface; | |
2144 | #ifdef ARPING | 2167 | #ifdef ARPING | |
2145 | if (dhcp_arping(ifp) == 1) { | 2168 | if (dhcp_arping(ifp) == 1) { | |
2146 | arp_free(astate); | 2169 | arp_free(astate); | |
2147 | return; | 2170 | return; | |
2148 | } | 2171 | } | |
2149 | #endif | 2172 | #endif | |
2150 | 2173 | |||
2151 | dhcp_finish_dad(ifp, &astate->addr); | 2174 | dhcp_finish_dad(ifp, &astate->addr); | |
2152 | } | 2175 | } | |
2153 | 2176 | |||
2154 | static void | 2177 | static void | |
2155 | dhcp_arp_found(struct arp_state *astate, const struct arp_msg *amsg) | 2178 | dhcp_arp_found(struct arp_state *astate, const struct arp_msg *amsg) | |
2156 | { | 2179 | { | |
2157 | struct in_addr addr; | 2180 | struct in_addr addr; | |
2158 | struct interface *ifp = astate->iface; | 2181 | struct interface *ifp = astate->iface; | |
2159 | #ifdef ARPING | 2182 | #ifdef ARPING | |
2160 | struct dhcp_state *state; | 2183 | struct dhcp_state *state; | |
2161 | struct if_options *ifo; | 2184 | struct if_options *ifo; | |
2162 | 2185 | |||
2163 | state = D_STATE(ifp); | 2186 | state = D_STATE(ifp); | |
2164 | 2187 | |||
2165 | ifo = ifp->options; | 2188 | ifo = ifp->options; | |
2166 | if (state->arping_index != -1 && | 2189 | if (state->arping_index != -1 && | |
2167 | state->arping_index < ifo->arping_len && | 2190 | state->arping_index < ifo->arping_len && | |
2168 | amsg && | 2191 | amsg && | |
2169 | amsg->sip.s_addr == ifo->arping[state->arping_index]) | 2192 | amsg->sip.s_addr == ifo->arping[state->arping_index]) | |
2170 | { | 2193 | { | |
2171 | char buf[HWADDR_LEN * 3]; | 2194 | char buf[HWADDR_LEN * 3]; | |
2172 | 2195 | |||
2173 | hwaddr_ntoa(amsg->sha, ifp->hwlen, buf, sizeof(buf)); | 2196 | hwaddr_ntoa(amsg->sha, ifp->hwlen, buf, sizeof(buf)); | |
2174 | if (dhcpcd_selectprofile(ifp, buf) == -1 && | 2197 | if (dhcpcd_selectprofile(ifp, buf) == -1 && | |
2175 | dhcpcd_selectprofile(ifp, inet_ntoa(amsg->sip)) == -1) | 2198 | dhcpcd_selectprofile(ifp, inet_ntoa(amsg->sip)) == -1) | |
2176 | { | 2199 | { | |
2177 | /* We didn't find a profile for this | 2200 | /* We didn't find a profile for this | |
2178 | * address or hwaddr, so move to the next | 2201 | * address or hwaddr, so move to the next | |
2179 | * arping profile */ | 2202 | * arping profile */ | |
2180 | dhcp_arp_not_found(astate); | 2203 | dhcp_arp_not_found(astate); | |
2181 | return; | 2204 | return; | |
2182 | } | 2205 | } | |
2183 | arp_free(astate); | 2206 | arp_free(astate); | |
2184 | eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); | 2207 | eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); | |
2185 | dhcpcd_startinterface(ifp); | 2208 | dhcpcd_startinterface(ifp); | |
2186 | return; | 2209 | return; | |
2187 | } | 2210 | } | |
2188 | #else | 2211 | #else | |
2189 | UNUSED(amsg); | 2212 | UNUSED(amsg); | |
2190 | #endif | 2213 | #endif | |
2191 | 2214 | |||
2192 | addr = astate->addr; | 2215 | addr = astate->addr; | |
2193 | arp_free(astate); | 2216 | arp_free(astate); | |
2194 | dhcp_addr_duplicated(ifp, &addr); | 2217 | dhcp_addr_duplicated(ifp, &addr); | |
2195 | } | 2218 | } | |
2196 | #endif | 2219 | #endif | |
2197 | 2220 | |||
2198 | #endif /* ARP */ | 2221 | #endif /* ARP */ | |
2199 | 2222 | |||
2200 | void | 2223 | void | |
2201 | dhcp_bind(struct interface *ifp) | 2224 | dhcp_bind(struct interface *ifp) | |
2202 | { | 2225 | { | |
2203 | struct dhcpcd_ctx *ctx = ifp->ctx; | 2226 | struct dhcpcd_ctx *ctx = ifp->ctx; | |
2204 | struct dhcp_state *state = D_STATE(ifp); | 2227 | struct dhcp_state *state = D_STATE(ifp); | |
2205 | struct if_options *ifo = ifp->options; | 2228 | struct if_options *ifo = ifp->options; | |
2206 | struct dhcp_lease *lease = &state->lease; | 2229 | struct dhcp_lease *lease = &state->lease; | |
2207 | uint8_t old_state; | 2230 | uint8_t old_state; | |
2208 | 2231 | |||
2209 | state->reason = NULL; | 2232 | state->reason = NULL; | |
2210 | /* If we don't have an offer, we are re-binding a lease on preference, | 2233 | /* If we don't have an offer, we are re-binding a lease on preference, | |
2211 | * normally when two interfaces have a lease matching IP addresses. */ | 2234 | * normally when two interfaces have a lease matching IP addresses. */ | |
2212 | if (state->offer) { | 2235 | if (state->offer) { | |
2213 | free(state->old); | 2236 | free(state->old); | |
2214 | state->old = state->new; | 2237 | state->old = state->new; | |
2215 | state->old_len = state->new_len; | 2238 | state->old_len = state->new_len; | |
2216 | state->new = state->offer; | 2239 | state->new = state->offer; | |
2217 | state->new_len = state->offer_len; | 2240 | state->new_len = state->offer_len; | |
2218 | state->offer = NULL; | 2241 | state->offer = NULL; | |
2219 | state->offer_len = 0; | 2242 | state->offer_len = 0; | |
2220 | } | 2243 | } | |
2221 | get_lease(ifp, lease, state->new, state->new_len); | 2244 | get_lease(ifp, lease, state->new, state->new_len); | |
2222 | if (ifo->options & DHCPCD_STATIC) { | 2245 | if (ifo->options & DHCPCD_STATIC) { | |
2223 | loginfox("%s: using static address %s/%d", | 2246 | loginfox("%s: using static address %s/%d", | |
2224 | ifp->name, inet_ntoa(lease->addr), | 2247 | ifp->name, inet_ntoa(lease->addr), | |
2225 | inet_ntocidr(lease->mask)); | 2248 | inet_ntocidr(lease->mask)); | |
2226 | lease->leasetime = DHCP_INFINITE_LIFETIME; | 2249 | lease->leasetime = DHCP_INFINITE_LIFETIME; | |
2227 | state->reason = "STATIC"; | 2250 | state->reason = "STATIC"; | |
2228 | } else if (ifo->options & DHCPCD_INFORM) { | 2251 | } else if (ifo->options & DHCPCD_INFORM) { | |
2229 | loginfox("%s: received approval for %s", | 2252 | loginfox("%s: received approval for %s", | |
2230 | ifp->name, inet_ntoa(lease->addr)); | 2253 | ifp->name, inet_ntoa(lease->addr)); | |
2231 | lease->leasetime = DHCP_INFINITE_LIFETIME; | 2254 | lease->leasetime = DHCP_INFINITE_LIFETIME; | |
2232 | state->reason = "INFORM"; | 2255 | state->reason = "INFORM"; | |
2233 | } else { | 2256 | } else { | |
2234 | if (lease->frominfo) | 2257 | if (lease->frominfo) | |
2235 | state->reason = "TIMEOUT"; | 2258 | state->reason = "TIMEOUT"; | |
2236 | if (lease->leasetime == DHCP_INFINITE_LIFETIME) { | 2259 | if (lease->leasetime == DHCP_INFINITE_LIFETIME) { | |
2237 | lease->renewaltime = | 2260 | lease->renewaltime = | |
2238 | lease->rebindtime = | 2261 | lease->rebindtime = | |
2239 | lease->leasetime; | 2262 | lease->leasetime; | |
2240 | loginfox("%s: leased %s for infinity", | 2263 | loginfox("%s: leased %s for infinity", | |
2241 | ifp->name, inet_ntoa(lease->addr)); | 2264 | ifp->name, inet_ntoa(lease->addr)); | |
2242 | } else { | 2265 | } else { | |
2243 | if (lease->leasetime < DHCP_MIN_LEASE) { | 2266 | if (lease->leasetime < DHCP_MIN_LEASE) { | |
2244 | logwarnx("%s: minimum lease is %d seconds", | 2267 | logwarnx("%s: minimum lease is %d seconds", | |
2245 | ifp->name, DHCP_MIN_LEASE); | 2268 | ifp->name, DHCP_MIN_LEASE); | |
2246 | lease->leasetime = DHCP_MIN_LEASE; | 2269 | lease->leasetime = DHCP_MIN_LEASE; | |
2247 | } | 2270 | } | |
2248 | if (lease->rebindtime == 0) | 2271 | if (lease->rebindtime == 0) | |
2249 | lease->rebindtime = | 2272 | lease->rebindtime = | |
2250 | (uint32_t)(lease->leasetime * T2); | 2273 | (uint32_t)(lease->leasetime * T2); | |
2251 | else if (lease->rebindtime >= lease->leasetime) { | 2274 | else if (lease->rebindtime >= lease->leasetime) { | |
2252 | lease->rebindtime = | 2275 | lease->rebindtime = | |
2253 | (uint32_t)(lease->leasetime * T2); | 2276 | (uint32_t)(lease->leasetime * T2); | |
2254 | logwarnx("%s: rebind time greater than lease " | 2277 | logwarnx("%s: rebind time greater than lease " | |
2255 | "time, forcing to %"PRIu32" seconds", | 2278 | "time, forcing to %"PRIu32" seconds", | |
2256 | ifp->name, lease->rebindtime); | 2279 | ifp->name, lease->rebindtime); | |
2257 | } | 2280 | } | |
2258 | if (lease->renewaltime == 0) | 2281 | if (lease->renewaltime == 0) | |
2259 | lease->renewaltime = | 2282 | lease->renewaltime = | |
2260 | (uint32_t)(lease->leasetime * T1); | 2283 | (uint32_t)(lease->leasetime * T1); | |
2261 | else if (lease->renewaltime > lease->rebindtime) { | 2284 | else if (lease->renewaltime > lease->rebindtime) { | |
2262 | lease->renewaltime = | 2285 | lease->renewaltime = | |
2263 | (uint32_t)(lease->leasetime * T1); | 2286 | (uint32_t)(lease->leasetime * T1); | |
2264 | logwarnx("%s: renewal time greater than " | 2287 | logwarnx("%s: renewal time greater than " | |
2265 | "rebind time, forcing to %"PRIu32" seconds", | 2288 | "rebind time, forcing to %"PRIu32" seconds", | |
2266 | ifp->name, lease->renewaltime); | 2289 | ifp->name, lease->renewaltime); | |
2267 | } | 2290 | } | |
2268 | if (state->state == DHS_RENEW && state->addr && | 2291 | if (state->state == DHS_RENEW && state->addr && | |
2269 | lease->addr.s_addr == state->addr->addr.s_addr && | 2292 | lease->addr.s_addr == state->addr->addr.s_addr && | |
2270 | !(state->added & STATE_FAKE)) | 2293 | !(state->added & STATE_FAKE)) | |
2271 | logdebugx("%s: leased %s for %"PRIu32" seconds", | 2294 | logdebugx("%s: leased %s for %"PRIu32" seconds", | |
2272 | ifp->name, inet_ntoa(lease->addr), | 2295 | ifp->name, inet_ntoa(lease->addr), | |
2273 | lease->leasetime); | 2296 | lease->leasetime); | |
2274 | else | 2297 | else | |
2275 | loginfox("%s: leased %s for %"PRIu32" seconds", | 2298 | loginfox("%s: leased %s for %"PRIu32" seconds", | |
2276 | ifp->name, inet_ntoa(lease->addr), | 2299 | ifp->name, inet_ntoa(lease->addr), | |
2277 | lease->leasetime); | 2300 | lease->leasetime); | |
2278 | } | 2301 | } | |
2279 | } | 2302 | } | |
2280 | if (ctx->options & DHCPCD_TEST) { | 2303 | if (ctx->options & DHCPCD_TEST) { | |
2281 | state->reason = "TEST"; | 2304 | state->reason = "TEST"; | |
2282 | script_runreason(ifp, state->reason); | 2305 | script_runreason(ifp, state->reason); | |
2283 | eloop_exit(ctx->eloop, EXIT_SUCCESS); | 2306 | eloop_exit(ctx->eloop, EXIT_SUCCESS); | |
2284 | return; | 2307 | return; | |
2285 | } | 2308 | } | |
2286 | if (state->reason == NULL) { | 2309 | if (state->reason == NULL) { | |
2287 | if (state->old && | 2310 | if (state->old && | |
2288 | !(state->added & (STATE_FAKE | STATE_EXPIRED))) | 2311 | !(state->added & (STATE_FAKE | STATE_EXPIRED))) | |
2289 | { | 2312 | { | |
2290 | if (state->old->yiaddr == state->new->yiaddr && | 2313 | if (state->old->yiaddr == state->new->yiaddr && | |
2291 | lease->server.s_addr && | 2314 | lease->server.s_addr && | |
2292 | state->state != DHS_REBIND) | 2315 | state->state != DHS_REBIND) | |
2293 | state->reason = "RENEW"; | 2316 | state->reason = "RENEW"; | |
2294 | else | 2317 | else | |
2295 | state->reason = "REBIND"; | 2318 | state->reason = "REBIND"; | |
2296 | } else if (state->state == DHS_REBOOT) | 2319 | } else if (state->state == DHS_REBOOT) | |
2297 | state->reason = "REBOOT"; | 2320 | state->reason = "REBOOT"; | |
2298 | else | 2321 | else | |
2299 | state->reason = "BOUND"; | 2322 | state->reason = "BOUND"; | |
2300 | } | 2323 | } | |
2301 | if (lease->leasetime == DHCP_INFINITE_LIFETIME) | 2324 | if (lease->leasetime == DHCP_INFINITE_LIFETIME) | |
2302 | lease->renewaltime = lease->rebindtime = lease->leasetime; | 2325 | lease->renewaltime = lease->rebindtime = lease->leasetime; | |
2303 | else { | 2326 | else { | |
2304 | eloop_timeout_add_sec(ctx->eloop, | 2327 | eloop_timeout_add_sec(ctx->eloop, | |
2305 | lease->renewaltime, dhcp_startrenew, ifp); | 2328 | lease->renewaltime, dhcp_startrenew, ifp); | |
2306 | eloop_timeout_add_sec(ctx->eloop, | 2329 | eloop_timeout_add_sec(ctx->eloop, | |
2307 | lease->rebindtime, dhcp_rebind, ifp); | 2330 | lease->rebindtime, dhcp_rebind, ifp); | |
2308 | eloop_timeout_add_sec(ctx->eloop, | 2331 | eloop_timeout_add_sec(ctx->eloop, | |
2309 | lease->leasetime, dhcp_expire, ifp); | 2332 | lease->leasetime, dhcp_expire, ifp); | |
2310 | logdebugx("%s: renew in %"PRIu32" seconds, rebind in %"PRIu32 | 2333 | logdebugx("%s: renew in %"PRIu32" seconds, rebind in %"PRIu32 | |
2311 | " seconds", | 2334 | " seconds", | |
2312 | ifp->name, lease->renewaltime, lease->rebindtime); | 2335 | ifp->name, lease->renewaltime, lease->rebindtime); | |
2313 | } | 2336 | } | |
2314 | state->state = DHS_BOUND; | 2337 | state->state = DHS_BOUND; | |
2315 | if (!state->lease.frominfo && | 2338 | if (!state->lease.frominfo && | |
2316 | !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))) { | 2339 | !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))) { | |
2317 | logdebugx("%s: writing lease: %s", | 2340 | logdebugx("%s: writing lease: %s", | |
2318 | ifp->name, state->leasefile); | 2341 | ifp->name, state->leasefile); | |
2319 | if (dhcp_writefile(ifp->ctx, state->leasefile, 0640, | 2342 | if (dhcp_writefile(ifp->ctx, state->leasefile, 0640, | |
2320 | state->new, state->new_len) == -1) | 2343 | state->new, state->new_len) == -1) | |
2321 | logerr("dhcp_writefile: %s", state->leasefile); | 2344 | logerr("dhcp_writefile: %s", state->leasefile); | |
2322 | } | 2345 | } | |
2323 | 2346 | |||
2347 | old_state = state->added; | |||
2348 | ||||
2324 | /* Close the BPF filter as we can now receive DHCP messages | 2349 | /* Close the BPF filter as we can now receive DHCP messages | |
2325 | * on a UDP socket. */ | 2350 | * on a UDP socket. */ | |
2326 | old_state = state->added; | 2351 | dhcp_closebpf(ifp); | |
2327 | if (ctx->options & DHCPCD_MASTER || | |||
2328 | state->old == NULL || | |||
2329 | state->old->yiaddr != state->new->yiaddr || old_state & STATE_FAKE) | |||
2330 | dhcp_close(ifp); | |||
2331 | 2352 | |||
2353 | /* Add the address */ | |||
2332 | ipv4_applyaddr(ifp); | 2354 | ipv4_applyaddr(ifp); | |
2333 | 2355 | |||
2334 | /* If not in master mode, open an address specific socket. */ | 2356 | /* If not in master mode, open an address specific socket. */ | |
2335 | if (ctx->options & DHCPCD_MASTER || | 2357 | if (ctx->options & DHCPCD_MASTER || | |
2336 | (state->old != NULL && | 2358 | (state->old != NULL && | |
2337 | state->old->yiaddr == state->new->yiaddr && | 2359 | state->old->yiaddr == state->new->yiaddr && | |
2338 | old_state & STATE_ADDED && !(old_state & STATE_FAKE))) | 2360 | old_state & STATE_ADDED && !(old_state & STATE_FAKE))) | |
2339 | return; | 2361 | return; | |
2340 | 2362 | |||
2363 | dhcp_closeinet(ifp); | |||
2364 | ||||
2341 | #ifdef PRIVSEP | 2365 | #ifdef PRIVSEP | |
2342 | if (IN_PRIVSEP_SE(ctx)) { | 2366 | if (IN_PRIVSEP_SE(ctx)) { | |
2343 | if (ps_inet_openbootp(state->addr) == -1) | 2367 | if (ps_inet_openbootp(state->addr) == -1) | |
2344 | logerr(__func__); | 2368 | logerr(__func__); | |
2345 | return; | 2369 | return; | |
2346 | } | 2370 | } | |
2347 | #endif | 2371 | #endif | |
2348 | 2372 | |||
2349 | state->udp_rfd = dhcp_openudp(&state->addr->addr); | 2373 | state->udp_rfd = dhcp_openudp(&state->addr->addr); | |
2350 | if (state->udp_rfd == -1) { | 2374 | if (state->udp_rfd == -1) { | |
2351 | logerr(__func__); | 2375 | logerr(__func__); | |
2352 | /* Address sharing without master mode is not supported. | 2376 | /* Address sharing without master mode is not supported. | |
2353 | * It's also possible another DHCP client could be running, | 2377 | * It's also possible another DHCP client could be running, | |
2354 | * which is even worse. | 2378 | * which is even worse. | |
2355 | * We still need to work, so re-open BPF. */ | 2379 | * We still need to work, so re-open BPF. */ | |
2356 | dhcp_openbpf(ifp); | 2380 | dhcp_openbpf(ifp); | |
2357 | return; | 2381 | return; | |
2358 | } | 2382 | } | |
2359 | eloop_event_add(ctx->eloop, state->udp_rfd, dhcp_handleifudp, ifp); | 2383 | eloop_event_add(ctx->eloop, state->udp_rfd, dhcp_handleifudp, ifp); | |
2360 | } | 2384 | } | |
2361 | 2385 | |||
2362 | static size_t | 2386 | static size_t | |
2363 | dhcp_message_new(struct bootp **bootp, | 2387 | dhcp_message_new(struct bootp **bootp, | |
2364 | const struct in_addr *addr, const struct in_addr *mask) | 2388 | const struct in_addr *addr, const struct in_addr *mask) | |
2365 | { | 2389 | { | |
2366 | uint8_t *p; | 2390 | uint8_t *p; | |
2367 | uint32_t cookie; | 2391 | uint32_t cookie; | |
2368 | 2392 | |||
2369 | if ((*bootp = calloc(1, sizeof(**bootp))) == NULL) | 2393 | if ((*bootp = calloc(1, sizeof(**bootp))) == NULL) | |
2370 | return 0; | 2394 | return 0; | |
2371 | 2395 | |||
2372 | (*bootp)->yiaddr = addr->s_addr; | 2396 | (*bootp)->yiaddr = addr->s_addr; | |
2373 | p = (*bootp)->vend; | 2397 | p = (*bootp)->vend; | |
2374 | 2398 | |||
2375 | cookie = htonl(MAGIC_COOKIE); | 2399 | cookie = htonl(MAGIC_COOKIE); | |
2376 | memcpy(p, &cookie, sizeof(cookie)); | 2400 | memcpy(p, &cookie, sizeof(cookie)); | |
2377 | p += sizeof(cookie); | 2401 | p += sizeof(cookie); | |
2378 | 2402 | |||
2379 | if (mask->s_addr != INADDR_ANY) { | 2403 | if (mask->s_addr != INADDR_ANY) { | |
2380 | *p++ = DHO_SUBNETMASK; | 2404 | *p++ = DHO_SUBNETMASK; | |
2381 | *p++ = sizeof(mask->s_addr); | 2405 | *p++ = sizeof(mask->s_addr); | |
2382 | memcpy(p, &mask->s_addr, sizeof(mask->s_addr)); | 2406 | memcpy(p, &mask->s_addr, sizeof(mask->s_addr)); | |
2383 | p+= sizeof(mask->s_addr); | 2407 | p+= sizeof(mask->s_addr); | |
2384 | } | 2408 | } | |
2385 | 2409 | |||
2386 | *p = DHO_END; | 2410 | *p = DHO_END; | |
2387 | return sizeof(**bootp); | 2411 | return sizeof(**bootp); | |
2388 | } | 2412 | } | |
2389 | 2413 | |||
2390 | #if defined(ARP) || defined(KERNEL_RFC5227) | 2414 | #if defined(ARP) || defined(KERNEL_RFC5227) | |
2391 | static int | 2415 | static int | |
2392 | dhcp_arp_address(struct interface *ifp) | 2416 | dhcp_arp_address(struct interface *ifp) | |
2393 | { | 2417 | { | |
2394 | struct dhcp_state *state; | 2418 | struct dhcp_state *state; | |
2395 | struct in_addr addr; | 2419 | struct in_addr addr; | |
2396 | struct ipv4_addr *ia; | 2420 | struct ipv4_addr *ia; | |
2397 | 2421 | |||
2398 | eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); | 2422 | eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); | |
2399 | 2423 | |||
2400 | state = D_STATE(ifp); | 2424 | state = D_STATE(ifp); | |
2401 | addr.s_addr = state->offer->yiaddr == INADDR_ANY ? | 2425 | addr.s_addr = state->offer->yiaddr == INADDR_ANY ? | |
2402 | state->offer->ciaddr : state->offer->yiaddr; | 2426 | state->offer->ciaddr : state->offer->yiaddr; | |
2403 | /* If the interface already has the address configured | 2427 | /* If the interface already has the address configured | |
2404 | * then we can't ARP for duplicate detection. */ | 2428 | * then we can't ARP for duplicate detection. */ | |
2405 | ia = ipv4_iffindaddr(ifp, &addr, NULL); | 2429 | ia = ipv4_iffindaddr(ifp, &addr, NULL); | |
2406 | #ifdef IN_IFF_NOTUSEABLE | 2430 | #ifdef IN_IFF_NOTUSEABLE | |
2407 | if (ia == NULL || ia->addr_flags & IN_IFF_NOTUSEABLE) { | 2431 | if (ia == NULL || ia->addr_flags & IN_IFF_NOTUSEABLE) { | |
2408 | state->state = DHS_PROBE; | 2432 | state->state = DHS_PROBE; | |
2409 | if (ia == NULL) { | 2433 | if (ia == NULL) { | |
2410 | struct dhcp_lease l; | 2434 | struct dhcp_lease l; | |
2411 | 2435 | |||
2412 | get_lease(ifp, &l, state->offer, state->offer_len); | 2436 | get_lease(ifp, &l, state->offer, state->offer_len); | |
2413 | /* Add the address now, let the kernel handle DAD. */ | 2437 | /* Add the address now, let the kernel handle DAD. */ | |
2414 | ipv4_addaddr(ifp, &l.addr, &l.mask, &l.brd, | 2438 | ipv4_addaddr(ifp, &l.addr, &l.mask, &l.brd, | |
2415 | l.leasetime, l.rebindtime); | 2439 | l.leasetime, l.rebindtime); | |
2416 | } else if (ia->addr_flags & IN_IFF_DUPLICATED) | 2440 | } else if (ia->addr_flags & IN_IFF_DUPLICATED) | |
2417 | dhcp_addr_duplicated(ifp, &ia->addr); | 2441 | dhcp_addr_duplicated(ifp, &ia->addr); | |
2418 | else | 2442 | else | |
2419 | loginfox("%s: waiting for DAD on %s", | 2443 | loginfox("%s: waiting for DAD on %s", | |
2420 | ifp->name, inet_ntoa(addr)); | 2444 | ifp->name, inet_ntoa(addr)); | |
2421 | return 0; | 2445 | return 0; | |
2422 | } | 2446 | } | |
2423 | #else | 2447 | #else | |
2424 | if (!(ifp->flags & IFF_NOARP) && | 2448 | if (!(ifp->flags & IFF_NOARP) && | |
2425 | ifp->options->options & DHCPCD_ARP) | 2449 | ifp->options->options & DHCPCD_ARP) | |
2426 | { | 2450 | { | |
2427 | struct arp_state *astate; | 2451 | struct arp_state *astate; | |
2428 | struct dhcp_lease l; | 2452 | struct dhcp_lease l; | |
2429 | 2453 | |||
2430 | /* Even if the address exists, we need to defend it. */ | 2454 | /* Even if the address exists, we need to defend it. */ | |
2431 | astate = dhcp_arp_new(ifp, &addr); | 2455 | astate = dhcp_arp_new(ifp, &addr); | |
2432 | if (astate == NULL) | 2456 | if (astate == NULL) | |
2433 | return -1; | 2457 | return -1; | |
2434 | 2458 | |||
2435 | if (ia == NULL) { | 2459 | if (ia == NULL) { | |
2436 | state->state = DHS_PROBE; | 2460 | state->state = DHS_PROBE; | |
2437 | get_lease(ifp, &l, state->offer, state->offer_len); | 2461 | get_lease(ifp, &l, state->offer, state->offer_len); | |
2438 | loginfox("%s: probing address %s/%d", | 2462 | loginfox("%s: probing address %s/%d", | |
2439 | ifp->name, inet_ntoa(l.addr), inet_ntocidr(l.mask)); | 2463 | ifp->name, inet_ntoa(l.addr), inet_ntocidr(l.mask)); | |
2440 | /* We need to handle DAD. */ | 2464 | /* We need to handle DAD. */ | |
2441 | arp_probe(astate); | 2465 | arp_probe(astate); | |
2442 | return 0; | 2466 | return 0; | |
2443 | } | 2467 | } | |
2444 | } | 2468 | } | |
2445 | #endif | 2469 | #endif | |
2446 | 2470 | |||
2447 | return 1; | 2471 | return 1; | |
2448 | } | 2472 | } | |
2449 | 2473 | |||
2450 | static void | 2474 | static void | |
2451 | dhcp_arp_bind(struct interface *ifp) | 2475 | dhcp_arp_bind(struct interface *ifp) | |
2452 | { | 2476 | { | |
2453 | 2477 | |||
2454 | if (ifp->ctx->options & DHCPCD_TEST || | 2478 | if (ifp->ctx->options & DHCPCD_TEST || | |
2455 | dhcp_arp_address(ifp) == 1) | 2479 | dhcp_arp_address(ifp) == 1) | |
2456 | dhcp_bind(ifp); | 2480 | dhcp_bind(ifp); | |
2457 | } | 2481 | } | |
2458 | #endif | 2482 | #endif | |
2459 | 2483 | |||
2460 | static void | 2484 | static void | |
2461 | dhcp_lastlease(void *arg) | 2485 | dhcp_lastlease(void *arg) | |
2462 | { | 2486 | { | |
2463 | struct interface *ifp = arg; | 2487 | struct interface *ifp = arg; | |
2464 | struct dhcp_state *state = D_STATE(ifp); | 2488 | struct dhcp_state *state = D_STATE(ifp); | |
2465 | 2489 | |||
2466 | loginfox("%s: timed out contacting a DHCP server, using last lease", | 2490 | loginfox("%s: timed out contacting a DHCP server, using last lease", | |
2467 | ifp->name); | 2491 | ifp->name); | |
2468 | #if defined(ARP) || defined(KERNEL_RFC5227) | 2492 | #if defined(ARP) || defined(KERNEL_RFC5227) | |
2469 | dhcp_arp_bind(ifp); | 2493 | dhcp_arp_bind(ifp); | |
2470 | #else | 2494 | #else | |
2471 | dhcp_bind(ifp); | 2495 | dhcp_bind(ifp); | |
2472 | #endif | 2496 | #endif | |
2473 | /* Set expired here because dhcp_bind() -> ipv4_addaddr() will reset | 2497 | /* Set expired here because dhcp_bind() -> ipv4_addaddr() will reset | |
2474 | * state */ | 2498 | * state */ | |
2475 | state->added |= STATE_EXPIRED; | 2499 | state->added |= STATE_EXPIRED; | |
2476 | state->interval = 0; | 2500 | state->interval = 0; | |
2477 | dhcp_discover(ifp); | 2501 | dhcp_discover(ifp); | |
2478 | } | 2502 | } | |
2479 | 2503 | |||
2480 | static void | 2504 | static void | |
2481 | dhcp_static(struct interface *ifp) | 2505 | dhcp_static(struct interface *ifp) | |
2482 | { | 2506 | { | |
2483 | struct if_options *ifo; | 2507 | struct if_options *ifo; | |
2484 | struct dhcp_state *state; | 2508 | struct dhcp_state *state; | |
2485 | struct ipv4_addr *ia; | 2509 | struct ipv4_addr *ia; | |
2486 | 2510 | |||
2487 | state = D_STATE(ifp); | 2511 | state = D_STATE(ifp); | |
2488 | ifo = ifp->options; | 2512 | ifo = ifp->options; | |
2489 | 2513 | |||
2490 | ia = NULL; | 2514 | ia = NULL; | |
2491 | if (ifo->req_addr.s_addr == INADDR_ANY && | 2515 | if (ifo->req_addr.s_addr == INADDR_ANY && | |
2492 | (ia = ipv4_iffindaddr(ifp, NULL, NULL)) == NULL) | 2516 | (ia = ipv4_iffindaddr(ifp, NULL, NULL)) == NULL) | |
2493 | { | 2517 | { | |
2494 | loginfox("%s: waiting for 3rd party to " | 2518 | loginfox("%s: waiting for 3rd party to " | |
2495 | "configure IP address", ifp->name); | 2519 | "configure IP address", ifp->name); | |
2496 | state->reason = "3RDPARTY"; | 2520 | state->reason = "3RDPARTY"; | |
2497 | script_runreason(ifp, state->reason); | 2521 | script_runreason(ifp, state->reason); | |
2498 | return; | 2522 | return; | |
2499 | } | 2523 | } | |
2500 | 2524 | |||
2501 | state->offer_len = dhcp_message_new(&state->offer, | 2525 | state->offer_len = dhcp_message_new(&state->offer, | |
2502 | ia ? &ia->addr : &ifo->req_addr, | 2526 | ia ? &ia->addr : &ifo->req_addr, | |
2503 | ia ? &ia->mask : &ifo->req_mask); | 2527 | ia ? &ia->mask : &ifo->req_mask); | |
2504 | if (state->offer_len) | 2528 | if (state->offer_len) | |
2505 | #if defined(ARP) || defined(KERNEL_RFC5227) | 2529 | #if defined(ARP) || defined(KERNEL_RFC5227) | |
2506 | dhcp_arp_bind(ifp); | 2530 | dhcp_arp_bind(ifp); | |
2507 | #else | 2531 | #else | |
2508 | dhcp_bind(ifp); | 2532 | dhcp_bind(ifp); | |
2509 | #endif | 2533 | #endif | |
2510 | } | 2534 | } | |
2511 | 2535 | |||
2512 | void | 2536 | void | |
2513 | dhcp_inform(struct interface *ifp) | 2537 | dhcp_inform(struct interface *ifp) | |
2514 | { | 2538 | { | |
2515 | struct dhcp_state *state; | 2539 | struct dhcp_state *state; | |
2516 | struct if_options *ifo; | 2540 | struct if_options *ifo; | |
2517 | struct ipv4_addr *ia; | 2541 | struct ipv4_addr *ia; | |
2518 | 2542 | |||
2519 | state = D_STATE(ifp); | 2543 | state = D_STATE(ifp); | |
2520 | ifo = ifp->options; | 2544 | ifo = ifp->options; | |
2521 | 2545 | |||
2522 | state->state = DHS_INFORM; | 2546 | state->state = DHS_INFORM; | |
2523 | free(state->offer); | 2547 | free(state->offer); | |
2524 | state->offer = NULL; | 2548 | state->offer = NULL; | |
2525 | state->offer_len = 0; | 2549 | state->offer_len = 0; | |
2526 | 2550 | |||
2527 | if (ifo->req_addr.s_addr == INADDR_ANY) { | 2551 | if (ifo->req_addr.s_addr == INADDR_ANY) { | |
2528 | ia = ipv4_iffindaddr(ifp, NULL, NULL); | 2552 | ia = ipv4_iffindaddr(ifp, NULL, NULL); | |
2529 | if (ia == NULL) { | 2553 | if (ia == NULL) { | |
2530 | loginfox("%s: waiting for 3rd party to " | 2554 | loginfox("%s: waiting for 3rd party to " | |
2531 | "configure IP address", | 2555 | "configure IP address", | |
2532 | ifp->name); | 2556 | ifp->name); | |
2533 | if (!(ifp->ctx->options & DHCPCD_TEST)) { | 2557 | if (!(ifp->ctx->options & DHCPCD_TEST)) { | |
2534 | state->reason = "3RDPARTY"; | 2558 | state->reason = "3RDPARTY"; | |
2535 | script_runreason(ifp, state->reason); | 2559 | script_runreason(ifp, state->reason); | |
2536 | } | 2560 | } | |
2537 | return; | 2561 | return; | |
2538 | } | 2562 | } | |
2539 | } else { | 2563 | } else { | |
2540 | ia = ipv4_iffindaddr(ifp, &ifo->req_addr, &ifo->req_mask); | 2564 | ia = ipv4_iffindaddr(ifp, &ifo->req_addr, &ifo->req_mask); | |
2541 | if (ia == NULL) { | 2565 | if (ia == NULL) { | |
2542 | if (ifp->ctx->options & DHCPCD_TEST) { | 2566 | if (ifp->ctx->options & DHCPCD_TEST) { | |
2543 | logerrx("%s: cannot add IP address in test mode", | 2567 | logerrx("%s: cannot add IP address in test mode", | |
2544 | ifp->name); | 2568 | ifp->name); | |
2545 | return; | 2569 | return; | |
2546 | } | 2570 | } | |
2547 | ia = ipv4_iffindaddr(ifp, &ifo->req_addr, NULL); | 2571 | ia = ipv4_iffindaddr(ifp, &ifo->req_addr, NULL); | |
2548 | if (ia != NULL) | 2572 | if (ia != NULL) | |
2549 | /* Netmask must be different, delete it. */ | 2573 | /* Netmask must be different, delete it. */ | |
2550 | ipv4_deladdr(ia, 1); | 2574 | ipv4_deladdr(ia, 1); | |
2551 | state->offer_len = dhcp_message_new(&state->offer, | 2575 | state->offer_len = dhcp_message_new(&state->offer, | |
2552 | &ifo->req_addr, &ifo->req_mask); | 2576 | &ifo->req_addr, &ifo->req_mask); | |
2553 | #ifdef ARP | 2577 | #ifdef ARP | |
2554 | if (dhcp_arp_address(ifp) != 1) | 2578 | if (dhcp_arp_address(ifp) != 1) | |
2555 | return; | 2579 | return; | |
2556 | #endif | 2580 | #endif | |
2557 | ia = ipv4_iffindaddr(ifp, | 2581 | ia = ipv4_iffindaddr(ifp, | |
2558 | &ifo->req_addr, &ifo->req_mask); | 2582 | &ifo->req_addr, &ifo->req_mask); | |
2559 | assert(ia != NULL); | 2583 | assert(ia != NULL); | |
2560 | } | 2584 | } | |
2561 | } | 2585 | } | |
2562 | 2586 | |||
2563 | state->addr = ia; | 2587 | state->addr = ia; | |
2564 | state->offer_len = dhcp_message_new(&state->offer, | 2588 | state->offer_len = dhcp_message_new(&state->offer, | |
2565 | &ia->addr, &ia->mask); | 2589 | &ia->addr, &ia->mask); | |
2566 | if (state->offer_len) { | 2590 | if (state->offer_len) { | |
2567 | dhcp_new_xid(ifp); | 2591 | dhcp_new_xid(ifp); | |
2568 | get_lease(ifp, &state->lease, state->offer, state->offer_len); | 2592 | get_lease(ifp, &state->lease, state->offer, state->offer_len); | |
2569 | send_inform(ifp); | 2593 | send_inform(ifp); | |
2570 | } | 2594 | } | |
2571 | } | 2595 | } | |
2572 | 2596 | |||
2573 | void | 2597 | void | |
2574 | dhcp_reboot_newopts(struct interface *ifp, unsigned long long oldopts) | 2598 | dhcp_reboot_newopts(struct interface *ifp, unsigned long long oldopts) | |
2575 | { | 2599 | { | |
2576 | struct if_options *ifo; | 2600 | struct if_options *ifo; | |
2577 | struct dhcp_state *state = D_STATE(ifp); | 2601 | struct dhcp_state *state = D_STATE(ifp); | |
2578 | 2602 | |||
2579 | if (state == NULL || state->state == DHS_NONE) | 2603 | if (state == NULL || state->state == DHS_NONE) | |
2580 | return; | 2604 | return; | |
2581 | ifo = ifp->options; | 2605 | ifo = ifp->options; | |
2582 | if ((ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC) && | 2606 | if ((ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC) && | |
2583 | (state->addr == NULL || | 2607 | (state->addr == NULL || | |
2584 | state->addr->addr.s_addr != ifo->req_addr.s_addr)) || | 2608 | state->addr->addr.s_addr != ifo->req_addr.s_addr)) || | |
2585 | (oldopts & (DHCPCD_INFORM | DHCPCD_STATIC) && | 2609 | (oldopts & (DHCPCD_INFORM | DHCPCD_STATIC) && | |
2586 | !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)))) | 2610 | !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)))) | |
2587 | { | 2611 | { | |
2588 | dhcp_drop(ifp, "EXPIRE"); | 2612 | dhcp_drop(ifp, "EXPIRE"); | |
2589 | } | 2613 | } | |
2590 | } | 2614 | } | |
2591 | 2615 | |||
2592 | #ifdef ARP | 2616 | #ifdef ARP | |
2593 | static int | 2617 | static int | |
2594 | dhcp_activeaddr(const struct interface *ifp, const struct in_addr *addr) | 2618 | dhcp_activeaddr(const struct interface *ifp, const struct in_addr *addr) | |
2595 | { | 2619 | { | |
2596 | const struct interface *ifp1; | 2620 | const struct interface *ifp1; | |
2597 | const struct dhcp_state *state; | 2621 | const struct dhcp_state *state; | |
2598 | 2622 | |||
2599 | TAILQ_FOREACH(ifp1, ifp->ctx->ifaces, next) { | 2623 | TAILQ_FOREACH(ifp1, ifp->ctx->ifaces, next) { | |
2600 | if (ifp1 == ifp) | 2624 | if (ifp1 == ifp) | |
2601 | continue; | 2625 | continue; | |
2602 | if ((state = D_CSTATE(ifp1)) == NULL) | 2626 | if ((state = D_CSTATE(ifp1)) == NULL) | |
2603 | continue; | 2627 | continue; | |
2604 | switch(state->state) { | 2628 | switch(state->state) { | |
2605 | case DHS_REBOOT: | 2629 | case DHS_REBOOT: | |
2606 | case DHS_RENEW: | 2630 | case DHS_RENEW: | |
2607 | case DHS_REBIND: | 2631 | case DHS_REBIND: | |
2608 | case DHS_BOUND: | 2632 | case DHS_BOUND: | |
2609 | case DHS_INFORM: | 2633 | case DHS_INFORM: | |
2610 | break; | 2634 | break; | |
2611 | default: | 2635 | default: | |
2612 | continue; | 2636 | continue; | |
2613 | } | 2637 | } | |
2614 | if (state->lease.addr.s_addr == addr->s_addr) | 2638 | if (state->lease.addr.s_addr == addr->s_addr) | |
2615 | return 1; | 2639 | return 1; | |
2616 | } | 2640 | } | |
2617 | return 0; | 2641 | return 0; | |
2618 | } | 2642 | } | |
2619 | #endif | 2643 | #endif | |
2620 | 2644 | |||
2621 | static void | 2645 | static void | |
2622 | dhcp_reboot(struct interface *ifp) | 2646 | dhcp_reboot(struct interface *ifp) | |
2623 | { | 2647 | { | |
2624 | struct if_options *ifo; | 2648 | struct if_options *ifo; | |
2625 | struct dhcp_state *state = D_STATE(ifp); | 2649 | struct dhcp_state *state = D_STATE(ifp); | |
2626 | #ifdef ARP | 2650 | #ifdef ARP | |
2627 | struct ipv4_addr *ia; | 2651 | struct ipv4_addr *ia; | |
2628 | #endif | 2652 | #endif | |
2629 | 2653 | |||
2630 | if (state == NULL || state->state == DHS_NONE) | 2654 | if (state == NULL || state->state == DHS_NONE) | |
2631 | return; | 2655 | return; | |
2632 | ifo = ifp->options; | 2656 | ifo = ifp->options; | |
2633 | state->state = DHS_REBOOT; | 2657 | state->state = DHS_REBOOT; | |
2634 | state->interval = 0; | 2658 | state->interval = 0; | |
2635 | 2659 | |||
2636 | if (ifo->options & DHCPCD_LINK && !if_is_link_up(ifp)) { | 2660 | if (ifo->options & DHCPCD_LINK && !if_is_link_up(ifp)) { | |
2637 | loginfox("%s: waiting for carrier", ifp->name); | 2661 | loginfox("%s: waiting for carrier", ifp->name); | |
2638 | return; | 2662 | return; | |
2639 | } | 2663 | } | |
2640 | if (ifo->options & DHCPCD_STATIC) { | 2664 | if (ifo->options & DHCPCD_STATIC) { | |
2641 | dhcp_static(ifp); | 2665 | dhcp_static(ifp); | |
2642 | return; | 2666 | return; | |
2643 | } | 2667 | } | |
2644 | if (ifo->options & DHCPCD_INFORM) { | 2668 | if (ifo->options & DHCPCD_INFORM) { | |
2645 | loginfox("%s: informing address of %s", | 2669 | loginfox("%s: informing address of %s", | |
2646 | ifp->name, inet_ntoa(state->lease.addr)); | 2670 | ifp->name, inet_ntoa(state->lease.addr)); | |
2647 | dhcp_inform(ifp); | 2671 | dhcp_inform(ifp); | |
2648 | return; | 2672 | return; | |
2649 | } | 2673 | } | |
2650 | if (ifo->reboot == 0 || state->offer == NULL) { | 2674 | if (ifo->reboot == 0 || state->offer == NULL) { | |
2651 | dhcp_discover(ifp); | 2675 | dhcp_discover(ifp); | |
2652 | return; | 2676 | return; | |
2653 | } | 2677 | } | |
2654 | if (!IS_DHCP(state->offer)) | 2678 | if (!IS_DHCP(state->offer)) | |
2655 | return; | 2679 | return; | |
2656 | 2680 | |||
2657 | loginfox("%s: rebinding lease of %s", | 2681 | loginfox("%s: rebinding lease of %s", | |
2658 | ifp->name, inet_ntoa(state->lease.addr)); | 2682 | ifp->name, inet_ntoa(state->lease.addr)); | |
2659 | 2683 | |||
2660 | #ifdef ARP | 2684 | #ifdef ARP | |
2661 | #ifndef KERNEL_RFC5227 | 2685 | #ifndef KERNEL_RFC5227 | |
2662 | /* Create the DHCP ARP state so we can defend it. */ | 2686 | /* Create the DHCP ARP state so we can defend it. */ | |
2663 | (void)dhcp_arp_new(ifp, &state->lease.addr); | 2687 | (void)dhcp_arp_new(ifp, &state->lease.addr); | |
2664 | #endif | 2688 | #endif | |
2665 | 2689 | |||
2666 | /* If the address exists on the interface and no other interface | 2690 | /* If the address exists on the interface and no other interface | |
2667 | * is currently using it then announce it to ensure this | 2691 | * is currently using it then announce it to ensure this | |
2668 | * interface gets the reply. */ | 2692 | * interface gets the reply. */ | |
2669 | ia = ipv4_iffindaddr(ifp, &state->lease.addr, NULL); | 2693 | ia = ipv4_iffindaddr(ifp, &state->lease.addr, NULL); | |
2670 | if (ia != NULL && | 2694 | if (ia != NULL && | |
2671 | !(ifp->ctx->options & DHCPCD_TEST) && | 2695 | !(ifp->ctx->options & DHCPCD_TEST) && | |
2672 | #ifdef IN_IFF_NOTUSEABLE | 2696 | #ifdef IN_IFF_NOTUSEABLE | |
2673 | !(ia->addr_flags & IN_IFF_NOTUSEABLE) && | 2697 | !(ia->addr_flags & IN_IFF_NOTUSEABLE) && | |
2674 | #endif | 2698 | #endif | |
2675 | dhcp_activeaddr(ifp, &state->lease.addr) == 0) | 2699 | dhcp_activeaddr(ifp, &state->lease.addr) == 0) | |
2676 | arp_ifannounceaddr(ifp, &state->lease.addr); | 2700 | arp_ifannounceaddr(ifp, &state->lease.addr); | |
2677 | #endif | 2701 | #endif | |
2678 | 2702 | |||
2679 | dhcp_new_xid(ifp); | 2703 | dhcp_new_xid(ifp); | |
2680 | state->lease.server.s_addr = INADDR_ANY; | 2704 | state->lease.server.s_addr = INADDR_ANY; | |
2681 | eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); | 2705 | eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); | |
2682 | 2706 | |||
2683 | #ifdef IPV4LL | 2707 | #ifdef IPV4LL | |
2684 | /* Need to add this before dhcp_expire and friends. */ | 2708 | /* Need to add this before dhcp_expire and friends. */ | |
2685 | if (!ifo->fallback && ifo->options & DHCPCD_IPV4LL) | 2709 | if (!ifo->fallback && ifo->options & DHCPCD_IPV4LL) | |
2686 | eloop_timeout_add_sec(ifp->ctx->eloop, | 2710 | eloop_timeout_add_sec(ifp->ctx->eloop, | |
2687 | ifo->reboot, ipv4ll_start, ifp); | 2711 | ifo->reboot, ipv4ll_start, ifp); | |
2688 | #endif | 2712 | #endif | |
2689 | 2713 | |||
2690 | if (ifo->options & DHCPCD_LASTLEASE && state->lease.frominfo) | 2714 | if (ifo->options & DHCPCD_LASTLEASE && state->lease.frominfo) | |
2691 | eloop_timeout_add_sec(ifp->ctx->eloop, | 2715 | eloop_timeout_add_sec(ifp->ctx->eloop, | |
2692 | ifo->reboot, dhcp_lastlease, ifp); | 2716 | ifo->reboot, dhcp_lastlease, ifp); | |
2693 | else if (!(ifo->options & DHCPCD_INFORM)) | 2717 | else if (!(ifo->options & DHCPCD_INFORM)) | |
2694 | eloop_timeout_add_sec(ifp->ctx->eloop, | 2718 | eloop_timeout_add_sec(ifp->ctx->eloop, | |
2695 | ifo->reboot, dhcp_expire, ifp); | 2719 | ifo->reboot, dhcp_expire, ifp); | |
2696 | 2720 | |||
2697 | /* Don't bother ARP checking as the server could NAK us first. | 2721 | /* Don't bother ARP checking as the server could NAK us first. | |
2698 | * Don't call dhcp_request as that would change the state */ | 2722 | * Don't call dhcp_request as that would change the state */ | |
2699 | send_request(ifp); | 2723 | send_request(ifp); | |
2700 | } | 2724 | } | |
2701 | 2725 | |||
2702 | void | 2726 | void | |
2703 | dhcp_drop(struct interface *ifp, const char *reason) | 2727 | dhcp_drop(struct interface *ifp, const char *reason) | |
2704 | { | 2728 | { | |
2705 | struct dhcp_state *state; | 2729 | struct dhcp_state *state; | |
2706 | #ifdef RELEASE_SLOW | 2730 | #ifdef RELEASE_SLOW | |
2707 | struct timespec ts; | 2731 | struct timespec ts; | |
2708 | #endif | 2732 | #endif | |
2709 | 2733 | |||
2710 | state = D_STATE(ifp); | 2734 | state = D_STATE(ifp); | |
2711 | /* dhcp_start may just have been called and we don't yet have a state | 2735 | /* dhcp_start may just have been called and we don't yet have a state | |
2712 | * but we do have a timeout, so punt it. */ | 2736 | * but we do have a timeout, so punt it. */ | |
2713 | if (state == NULL || state->state == DHS_NONE) { | 2737 | if (state == NULL || state->state == DHS_NONE) { | |
2714 | eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); | 2738 | eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); | |
2715 | return; | 2739 | return; | |
2716 | } | 2740 | } | |
2717 | 2741 | |||
2718 | #ifdef ARP | 2742 | #ifdef ARP | |
2719 | if (state->addr != NULL) | 2743 | if (state->addr != NULL) | |
2720 | arp_freeaddr(ifp, &state->addr->addr); | 2744 | arp_freeaddr(ifp, &state->addr->addr); | |
2721 | #endif | 2745 | #endif | |
2722 | #ifdef ARPING | 2746 | #ifdef ARPING | |
2723 | state->arping_index = -1; | 2747 | state->arping_index = -1; | |
2724 | #endif | 2748 | #endif | |
2725 | 2749 | |||
2726 | if (ifp->options->options & DHCPCD_RELEASE && | 2750 | if (ifp->options->options & DHCPCD_RELEASE && | |
2727 | !(ifp->options->options & DHCPCD_INFORM)) | 2751 | !(ifp->options->options & DHCPCD_INFORM)) | |
2728 | { | 2752 | { | |
2729 | /* Failure to send the release may cause this function to | 2753 | /* Failure to send the release may cause this function to | |
2730 | * re-enter so guard by setting the state. */ | 2754 | * re-enter so guard by setting the state. */ | |
2731 | if (state->state == DHS_RELEASE) | 2755 | if (state->state == DHS_RELEASE) | |
2732 | return; | 2756 | return; | |
2733 | state->state = DHS_RELEASE; | 2757 | state->state = DHS_RELEASE; | |
2734 | 2758 | |||
2735 | dhcp_unlink(ifp->ctx, state->leasefile); | 2759 | dhcp_unlink(ifp->ctx, state->leasefile); | |
2736 | if (if_is_link_up(ifp) && | 2760 | if (if_is_link_up(ifp) && | |
2737 | state->new != NULL && | 2761 | state->new != NULL && | |
2738 | state->lease.server.s_addr != INADDR_ANY) | 2762 | state->lease.server.s_addr != INADDR_ANY) | |
2739 | { | 2763 | { | |
2740 | loginfox("%s: releasing lease of %s", | 2764 | loginfox("%s: releasing lease of %s", | |
2741 | ifp->name, inet_ntoa(state->lease.addr)); | 2765 | ifp->name, inet_ntoa(state->lease.addr)); | |
2742 | dhcp_new_xid(ifp); | 2766 | dhcp_new_xid(ifp); | |
2743 | send_message(ifp, DHCP_RELEASE, NULL); | 2767 | send_message(ifp, DHCP_RELEASE, NULL); | |
2744 | #ifdef RELEASE_SLOW | 2768 | #ifdef RELEASE_SLOW | |
2745 | /* Give the packet a chance to go */ | 2769 | /* Give the packet a chance to go */ | |
2746 | ts.tv_sec = RELEASE_DELAY_S; | 2770 | ts.tv_sec = RELEASE_DELAY_S; | |
2747 | ts.tv_nsec = RELEASE_DELAY_NS; | 2771 | ts.tv_nsec = RELEASE_DELAY_NS; | |
2748 | nanosleep(&ts, NULL); | 2772 | nanosleep(&ts, NULL); | |
2749 | #endif | 2773 | #endif | |
2750 | } | 2774 | } | |
2751 | } | 2775 | } | |
2752 | #ifdef AUTH | 2776 | #ifdef AUTH | |
2753 | else if (state->auth.reconf != NULL) { | 2777 | else if (state->auth.reconf != NULL) { | |
2754 | /* | 2778 | /* | |
2755 | * Drop the lease as the token may only be present | 2779 | * Drop the lease as the token may only be present | |
2756 | * in the initial reply message and not subsequent | 2780 | * in the initial reply message and not subsequent | |
2757 | * renewals. | 2781 | * renewals. | |
2758 | * If dhcpcd is restarted, the token is lost. | 2782 | * If dhcpcd is restarted, the token is lost. | |
2759 | * XXX persist this in another file? | 2783 | * XXX persist this in another file? | |
2760 | */ | 2784 | */ | |
2761 | dhcp_unlink(ifp->ctx, state->leasefile); | 2785 | dhcp_unlink(ifp->ctx, state->leasefile); | |
2762 | } | 2786 | } | |
2763 | #endif | 2787 | #endif | |
2764 | 2788 | |||
2765 | eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); | 2789 | eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); | |
2766 | #ifdef AUTH | 2790 | #ifdef AUTH | |
2767 | dhcp_auth_reset(&state->auth); | 2791 | dhcp_auth_reset(&state->auth); | |
2768 | #endif | 2792 | #endif | |
2769 | 2793 | |||
2770 | /* Close DHCP ports so a changed interface family is picked | 2794 | /* Close DHCP ports so a changed interface family is picked | |
2771 | * up by a new BPF state. */ | 2795 | * up by a new BPF state. */ | |
2772 | dhcp_close(ifp); | 2796 | dhcp_close(ifp); | |
2773 | 2797 | |||
2774 | state->state = DHS_NONE; | 2798 | state->state = DHS_NONE; | |
2775 | free(state->offer); | 2799 | free(state->offer); | |
2776 | state->offer = NULL; | 2800 | state->offer = NULL; | |
2777 | state->offer_len = 0; | 2801 | state->offer_len = 0; | |
2778 | free(state->old); | 2802 | free(state->old); | |
2779 | state->old = state->new; | 2803 | state->old = state->new; | |
2780 | state->old_len = state->new_len; | 2804 | state->old_len = state->new_len; | |
2781 | state->new = NULL; | 2805 | state->new = NULL; | |
2782 | state->new_len = 0; | 2806 | state->new_len = 0; | |
2783 | state->reason = reason; | 2807 | state->reason = reason; | |
2784 | ipv4_applyaddr(ifp); | 2808 | ipv4_applyaddr(ifp); | |
2785 | free(state->old); | 2809 | free(state->old); | |
2786 | state->old = NULL; | 2810 | state->old = NULL; | |
2787 | state->old_len = 0; | 2811 | state->old_len = 0; | |
2788 | state->lease.addr.s_addr = 0; | 2812 | state->lease.addr.s_addr = 0; | |
2789 | ifp->options->options &= ~(DHCPCD_CSR_WARNED | | 2813 | ifp->options->options &= ~(DHCPCD_CSR_WARNED | | |
2790 | DHCPCD_ROUTER_HOST_ROUTE_WARNED); | 2814 | DHCPCD_ROUTER_HOST_ROUTE_WARNED); | |
2791 | } | 2815 | } | |
2792 | 2816 | |||
2793 | static int | 2817 | static int | |
2794 | blacklisted_ip(const struct if_options *ifo, in_addr_t addr) | 2818 | blacklisted_ip(const struct if_options *ifo, in_addr_t addr) | |
2795 | { | 2819 | { | |
2796 | size_t i; | 2820 | size_t i; | |
2797 | 2821 | |||
2798 | for (i = 0; i < ifo->blacklist_len; i += 2) | 2822 | for (i = 0; i < ifo->blacklist_len; i += 2) | |
2799 | if (ifo->blacklist[i] == (addr & ifo->blacklist[i + 1])) | 2823 | if (ifo->blacklist[i] == (addr & ifo->blacklist[i + 1])) | |
2800 | return 1; | 2824 | return 1; | |
2801 | return 0; | 2825 | return 0; | |
2802 | } | 2826 | } | |
2803 | 2827 | |||
2804 | #define WHTLST_NONE 0 | 2828 | #define WHTLST_NONE 0 | |
2805 | #define WHTLST_MATCH 1 | 2829 | #define WHTLST_MATCH 1 | |
2806 | #define WHTLST_NOMATCH 2 | 2830 | #define WHTLST_NOMATCH 2 | |
2807 | static unsigned int | 2831 | static unsigned int | |
2808 | whitelisted_ip(const struct if_options *ifo, in_addr_t addr) | 2832 | whitelisted_ip(const struct if_options *ifo, in_addr_t addr) | |
2809 | { | 2833 | { | |
2810 | size_t i; | 2834 | size_t i; | |
2811 | 2835 | |||
2812 | if (ifo->whitelist_len == 0) | 2836 | if (ifo->whitelist_len == 0) | |
2813 | return WHTLST_NONE; | 2837 | return WHTLST_NONE; | |
2814 | for (i = 0; i < ifo->whitelist_len; i += 2) | 2838 | for (i = 0; i < ifo->whitelist_len; i += 2) | |
2815 | if (ifo->whitelist[i] == (addr & ifo->whitelist[i + 1])) | 2839 | if (ifo->whitelist[i] == (addr & ifo->whitelist[i + 1])) | |
2816 | return WHTLST_MATCH; | 2840 | return WHTLST_MATCH; | |
2817 | return WHTLST_NOMATCH; | 2841 | return WHTLST_NOMATCH; | |
2818 | } | 2842 | } | |
2819 | 2843 | |||
2820 | static void | 2844 | static void | |
2821 | log_dhcp(int loglevel, const char *msg, | 2845 | log_dhcp(int loglevel, const char *msg, | |
2822 | const struct interface *ifp, const struct bootp *bootp, size_t bootp_len, | 2846 | const struct interface *ifp, const struct bootp *bootp, size_t bootp_len, | |
2823 | const struct in_addr *from, int ad) | 2847 | const struct in_addr *from, int ad) | |
2824 | { | 2848 | { | |
2825 | const char *tfrom; | 2849 | const char *tfrom; | |
2826 | char *a, sname[sizeof(bootp->sname) * 4]; | 2850 | char *a, sname[sizeof(bootp->sname) * 4]; | |
2827 | struct in_addr addr; | 2851 | struct in_addr addr; | |
2828 | int r; | 2852 | int r; | |
2829 | uint8_t overl; | 2853 | uint8_t overl; | |
2830 | 2854 | |||
2831 | if (strcmp(msg, "NAK:") == 0) { | 2855 | if (strcmp(msg, "NAK:") == 0) { | |
2832 | a = get_option_string(ifp->ctx, bootp, bootp_len, DHO_MESSAGE); | 2856 | a = get_option_string(ifp->ctx, bootp, bootp_len, DHO_MESSAGE); | |
2833 | if (a) { | 2857 | if (a) { | |
2834 | char *tmp; | 2858 | char *tmp; | |
2835 | size_t al, tmpl; | 2859 | size_t al, tmpl; | |
2836 | 2860 | |||
2837 | al = strlen(a); | 2861 | al = strlen(a); | |
2838 | tmpl = (al * 4) + 1; | 2862 | tmpl = (al * 4) + 1; | |
2839 | tmp = malloc(tmpl); | 2863 | tmp = malloc(tmpl); | |
2840 | if (tmp == NULL) { | 2864 | if (tmp == NULL) { | |
2841 | logerr(__func__); | 2865 | logerr(__func__); | |
2842 | free(a); | 2866 | free(a); | |
2843 | return; | 2867 | return; | |
2844 | } | 2868 | } | |
2845 | print_string(tmp, tmpl, OT_STRING, (uint8_t *)a, al); | 2869 | print_string(tmp, tmpl, OT_STRING, (uint8_t *)a, al); | |
2846 | free(a); | 2870 | free(a); | |
2847 | a = tmp; | 2871 | a = tmp; | |
2848 | } | 2872 | } | |
2849 | } else if (ad && bootp->yiaddr != 0) { | 2873 | } else if (ad && bootp->yiaddr != 0) { | |
2850 | addr.s_addr = bootp->yiaddr; | 2874 | addr.s_addr = bootp->yiaddr; | |
2851 | a = strdup(inet_ntoa(addr)); | 2875 | a = strdup(inet_ntoa(addr)); | |
2852 | if (a == NULL) { | 2876 | if (a == NULL) { | |
2853 | logerr(__func__); | 2877 | logerr(__func__); | |
2854 | return; | 2878 | return; | |
2855 | } | 2879 | } | |
2856 | } else | 2880 | } else | |
2857 | a = NULL; | 2881 | a = NULL; | |
2858 | 2882 | |||
2859 | tfrom = "from"; | 2883 | tfrom = "from"; | |
2860 | r = get_option_addr(ifp->ctx, &addr, bootp, bootp_len, DHO_SERVERID); | 2884 | r = get_option_addr(ifp->ctx, &addr, bootp, bootp_len, DHO_SERVERID); | |
2861 | if (get_option_uint8(ifp->ctx, &overl, bootp, bootp_len, | 2885 | if (get_option_uint8(ifp->ctx, &overl, bootp, bootp_len, | |
2862 | DHO_OPTSOVERLOADED) == -1) | 2886 | DHO_OPTSOVERLOADED) == -1) | |
2863 | overl = 0; | 2887 | overl = 0; | |
2864 | if (bootp->sname[0] && r == 0 && !(overl & 2)) { | 2888 | if (bootp->sname[0] && r == 0 && !(overl & 2)) { | |
2865 | print_string(sname, sizeof(sname), OT_STRING | OT_DOMAIN, | 2889 | print_string(sname, sizeof(sname), OT_STRING | OT_DOMAIN, | |
2866 | bootp->sname, sizeof(bootp->sname)); | 2890 | bootp->sname, sizeof(bootp->sname)); | |
2867 | if (a == NULL) | 2891 | if (a == NULL) | |
2868 | logmessage(loglevel, "%s: %s %s %s %s", | 2892 | logmessage(loglevel, "%s: %s %s %s %s", | |
2869 | ifp->name, msg, tfrom, inet_ntoa(addr), sname); | 2893 | ifp->name, msg, tfrom, inet_ntoa(addr), sname); | |
2870 | else | 2894 | else | |
2871 | logmessage(loglevel, "%s: %s %s %s %s %s", | 2895 | logmessage(loglevel, "%s: %s %s %s %s %s", | |
2872 | ifp->name, msg, a, tfrom, inet_ntoa(addr), sname); | 2896 | ifp->name, msg, a, tfrom, inet_ntoa(addr), sname); | |
2873 | } else { | 2897 | } else { | |
2874 | if (r != 0) { | 2898 | if (r != 0) { | |
2875 | tfrom = "via"; | 2899 | tfrom = "via"; | |
2876 | addr = *from; | 2900 | addr = *from; | |
2877 | } | 2901 | } | |
2878 | if (a == NULL) | 2902 | if (a == NULL) | |
2879 | logmessage(loglevel, "%s: %s %s %s", | 2903 | logmessage(loglevel, "%s: %s %s %s", | |
2880 | ifp->name, msg, tfrom, inet_ntoa(addr)); | 2904 | ifp->name, msg, tfrom, inet_ntoa(addr)); | |
2881 | else | 2905 | else | |
2882 | logmessage(loglevel, "%s: %s %s %s %s", | 2906 | logmessage(loglevel, "%s: %s %s %s %s", | |
2883 | ifp->name, msg, a, tfrom, inet_ntoa(addr)); | 2907 | ifp->name, msg, a, tfrom, inet_ntoa(addr)); | |
2884 | } | 2908 | } | |
2885 | free(a); | 2909 | free(a); | |
2886 | } | 2910 | } | |
2887 | 2911 | |||
2888 | /* If we're sharing the same IP address with another interface on the | 2912 | /* If we're sharing the same IP address with another interface on the | |
2889 | * same network, we may receive the DHCP reply on the wrong interface. | 2913 | * same network, we may receive the DHCP reply on the wrong interface. | |
2890 | * Try and re-direct it here. */ | 2914 | * Try and re-direct it here. */ | |
2891 | static void | 2915 | static void | |
2892 | dhcp_redirect_dhcp(struct interface *ifp, struct bootp *bootp, size_t bootp_len, | 2916 | dhcp_redirect_dhcp(struct interface *ifp, struct bootp *bootp, size_t bootp_len, | |
2893 | const struct in_addr *from) | 2917 | const struct in_addr *from) | |
2894 | { | 2918 | { | |
2895 | struct interface *ifn; | 2919 | struct interface *ifn; | |
2896 | const struct dhcp_state *state; | 2920 | const struct dhcp_state *state; | |
2897 | uint32_t xid; | 2921 | uint32_t xid; | |
2898 | 2922 | |||
2899 | xid = ntohl(bootp->xid); | 2923 | xid = ntohl(bootp->xid); | |
2900 | TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) { | 2924 | TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) { | |
2901 | if (ifn == ifp) | 2925 | if (ifn == ifp) | |
2902 | continue; | 2926 | continue; | |
2903 | state = D_CSTATE(ifn); | 2927 | state = D_CSTATE(ifn); | |
2904 | if (state == NULL || state->state == DHS_NONE) | 2928 | if (state == NULL || state->state == DHS_NONE) | |
2905 | continue; | 2929 | continue; | |
2906 | if (state->xid != xid) | 2930 | if (state->xid != xid) | |
2907 | continue; | 2931 | continue; | |
2908 | if (ifn->hwlen <= sizeof(bootp->chaddr) && | 2932 | if (ifn->hwlen <= sizeof(bootp->chaddr) && | |
2909 | memcmp(bootp->chaddr, ifn->hwaddr, ifn->hwlen)) | 2933 | memcmp(bootp->chaddr, ifn->hwaddr, ifn->hwlen)) | |
2910 | continue; | 2934 | continue; | |
2911 | logdebugx("%s: redirecting DHCP message to %s", | 2935 | logdebugx("%s: redirecting DHCP message to %s", | |
2912 | ifp->name, ifn->name); | 2936 | ifp->name, ifn->name); | |
2913 | dhcp_handledhcp(ifn, bootp, bootp_len, from); | 2937 | dhcp_handledhcp(ifn, bootp, bootp_len, from); | |
2914 | } | 2938 | } | |
2915 | } | 2939 | } | |
2916 | 2940 | |||
2917 | static void | 2941 | static void | |
2918 | dhcp_handledhcp(struct interface *ifp, struct bootp *bootp, size_t bootp_len, | 2942 | dhcp_handledhcp(struct interface *ifp, struct bootp *bootp, size_t bootp_len, | |
2919 | const struct in_addr *from) | 2943 | const struct in_addr *from) | |
2920 | { | 2944 | { | |
2921 | struct dhcp_state *state = D_STATE(ifp); | 2945 | struct dhcp_state *state = D_STATE(ifp); | |
2922 | struct if_options *ifo = ifp->options; | 2946 | struct if_options *ifo = ifp->options; | |
2923 | struct dhcp_lease *lease = &state->lease; | 2947 | struct dhcp_lease *lease = &state->lease; | |
2924 | uint8_t type, tmp; | 2948 | uint8_t type, tmp; | |
2925 | struct in_addr addr; | 2949 | struct in_addr addr; | |
2926 | unsigned int i; | 2950 | unsigned int i; | |
2927 | char *msg; | 2951 | char *msg; | |
2928 | bool bootp_copied; | 2952 | bool bootp_copied; | |
2953 | uint32_t v6only_time = 0; | |||
2954 | bool use_v6only = false; | |||
2929 | #ifdef AUTH | 2955 | #ifdef AUTH | |
2930 | const uint8_t *auth; | 2956 | const uint8_t *auth; | |
2931 | size_t auth_len; | 2957 | size_t auth_len; | |
2932 | #endif | 2958 | #endif | |
2933 | #ifdef IN_IFF_DUPLICATED | 2959 | #ifdef IN_IFF_DUPLICATED | |
2934 | struct ipv4_addr *ia; | 2960 | struct ipv4_addr *ia; | |
2935 | #endif | 2961 | #endif | |
2936 | 2962 | |||
2937 | #define LOGDHCP0(l, m) \ | 2963 | #define LOGDHCP0(l, m) \ | |
2938 | log_dhcp((l), (m), ifp, bootp, bootp_len, from, 0) | 2964 | log_dhcp((l), (m), ifp, bootp, bootp_len, from, 0) | |
2939 | #define LOGDHCP(l, m) \ | 2965 | #define LOGDHCP(l, m) \ | |
2940 | log_dhcp((l), (m), ifp, bootp, bootp_len, from, 1) | 2966 | log_dhcp((l), (m), ifp, bootp, bootp_len, from, 1) | |
2941 | 2967 | |||
2942 | #define IS_STATE_ACTIVE(s) ((s)-state != DHS_NONE && \ | 2968 | #define IS_STATE_ACTIVE(s) ((s)-state != DHS_NONE && \ | |
2943 | (s)->state != DHS_INIT && (s)->state != DHS_BOUND) | 2969 | (s)->state != DHS_INIT && (s)->state != DHS_BOUND) | |
2944 | 2970 | |||
2945 | if (bootp->op != BOOTREPLY) { | 2971 | if (bootp->op != BOOTREPLY) { | |
2946 | if (IS_STATE_ACTIVE(state)) | 2972 | if (IS_STATE_ACTIVE(state)) | |
2947 | logdebugx("%s: op (%d) is not BOOTREPLY", | 2973 | logdebugx("%s: op (%d) is not BOOTREPLY", | |
2948 | ifp->name, bootp->op); | 2974 | ifp->name, bootp->op); | |
2949 | return; | 2975 | return; | |
2950 | } | 2976 | } | |
2951 | 2977 | |||
2952 | if (state->xid != ntohl(bootp->xid)) { | 2978 | if (state->xid != ntohl(bootp->xid)) { | |
2953 | if (IS_STATE_ACTIVE(state)) | 2979 | if (IS_STATE_ACTIVE(state)) | |
2954 | logdebugx("%s: wrong xid 0x%x (expecting 0x%x) from %s", | 2980 | logdebugx("%s: wrong xid 0x%x (expecting 0x%x) from %s", | |
2955 | ifp->name, ntohl(bootp->xid), state->xid, | 2981 | ifp->name, ntohl(bootp->xid), state->xid, | |
2956 | inet_ntoa(*from)); | 2982 | inet_ntoa(*from)); | |
2957 | dhcp_redirect_dhcp(ifp, bootp, bootp_len, from); | 2983 | dhcp_redirect_dhcp(ifp, bootp, bootp_len, from); | |
2958 | return; | 2984 | return; | |
2959 | } | 2985 | } | |
2960 | 2986 | |||
2961 | if (ifp->hwlen <= sizeof(bootp->chaddr) && | 2987 | if (ifp->hwlen <= sizeof(bootp->chaddr) && | |
2962 | memcmp(bootp->chaddr, ifp->hwaddr, ifp->hwlen)) | 2988 | memcmp(bootp->chaddr, ifp->hwaddr, ifp->hwlen)) | |
2963 | { | 2989 | { | |
2964 | if (IS_STATE_ACTIVE(state)) { | 2990 | if (IS_STATE_ACTIVE(state)) { | |
2965 | char buf[sizeof(bootp->chaddr) * 3]; | 2991 | char buf[sizeof(bootp->chaddr) * 3]; | |
2966 | 2992 | |||
2967 | logdebugx("%s: xid 0x%x is for hwaddr %s", | 2993 | logdebugx("%s: xid 0x%x is for hwaddr %s", | |
2968 | ifp->name, ntohl(bootp->xid), | 2994 | ifp->name, ntohl(bootp->xid), | |
2969 | hwaddr_ntoa(bootp->chaddr, sizeof(bootp->chaddr), | 2995 | hwaddr_ntoa(bootp->chaddr, sizeof(bootp->chaddr), | |
2970 | buf, sizeof(buf))); | 2996 | buf, sizeof(buf))); | |
2971 | } | 2997 | } | |
2972 | dhcp_redirect_dhcp(ifp, bootp, bootp_len, from); | 2998 | dhcp_redirect_dhcp(ifp, bootp, bootp_len, from); | |
2973 | return; | 2999 | return; | |
2974 | } | 3000 | } | |
2975 | 3001 | |||
2976 | if (!ifp->active) | 3002 | if (!ifp->active) | |
2977 | return; | 3003 | return; | |
2978 | 3004 | |||
2979 | i = whitelisted_ip(ifp->options, from->s_addr); | 3005 | i = whitelisted_ip(ifp->options, from->s_addr); | |
2980 | switch (i) { | 3006 | switch (i) { | |
2981 | case WHTLST_NOMATCH: | 3007 | case WHTLST_NOMATCH: | |
2982 | logwarnx("%s: non whitelisted DHCP packet from %s", | 3008 | logwarnx("%s: non whitelisted DHCP packet from %s", | |
2983 | ifp->name, inet_ntoa(*from)); | 3009 | ifp->name, inet_ntoa(*from)); | |
2984 | return; | 3010 | return; | |
2985 | case WHTLST_MATCH: | 3011 | case WHTLST_MATCH: | |
2986 | break; | 3012 | break; | |
2987 | case WHTLST_NONE: | 3013 | case WHTLST_NONE: | |
2988 | if (blacklisted_ip(ifp->options, from->s_addr) == 1) { | 3014 | if (blacklisted_ip(ifp->options, from->s_addr) == 1) { | |
2989 | logwarnx("%s: blacklisted DHCP packet from %s", | 3015 | logwarnx("%s: blacklisted DHCP packet from %s", | |
2990 | ifp->name, inet_ntoa(*from)); | 3016 | ifp->name, inet_ntoa(*from)); | |
2991 | return; | 3017 | return; | |
2992 | } | 3018 | } | |
2993 | } | 3019 | } | |
2994 | 3020 | |||
2995 | /* We may have found a BOOTP server */ | 3021 | /* We may have found a BOOTP server */ | |
2996 | if (get_option_uint8(ifp->ctx, &type, | 3022 | if (get_option_uint8(ifp->ctx, &type, | |
2997 | bootp, bootp_len, DHO_MESSAGETYPE) == -1) | 3023 | bootp, bootp_len, DHO_MESSAGETYPE) == -1) | |
2998 | type = 0; | 3024 | type = 0; | |
2999 | else if (ifo->options & DHCPCD_BOOTP) { | 3025 | else if (ifo->options & DHCPCD_BOOTP) { | |
3000 | logdebugx("%s: ignoring DHCP reply (expecting BOOTP)", | 3026 | logdebugx("%s: ignoring DHCP reply (expecting BOOTP)", | |
3001 | ifp->name); | 3027 | ifp->name); | |
3002 | return; | 3028 | return; | |
3003 | } | 3029 | } | |
3004 | 3030 | |||
3005 | #ifdef AUTH | 3031 | #ifdef AUTH | |
3006 | /* Authenticate the message */ | 3032 | /* Authenticate the message */ | |
3007 | auth = get_option(ifp->ctx, bootp, bootp_len, | 3033 | auth = get_option(ifp->ctx, bootp, bootp_len, | |
3008 | DHO_AUTHENTICATION, &auth_len); | 3034 | DHO_AUTHENTICATION, &auth_len); | |
3009 | if (auth) { | 3035 | if (auth) { | |
3010 | if (dhcp_auth_validate(&state->auth, &ifo->auth, | 3036 | if (dhcp_auth_validate(&state->auth, &ifo->auth, | |
3011 | (uint8_t *)bootp, bootp_len, 4, type, | 3037 | (uint8_t *)bootp, bootp_len, 4, type, | |
3012 | auth, auth_len) == NULL) | 3038 | auth, auth_len) == NULL) | |
3013 | { | 3039 | { | |
3014 | LOGDHCP0(LOG_ERR, "authentication failed"); | 3040 | LOGDHCP0(LOG_ERR, "authentication failed"); | |
3015 | return; | 3041 | return; | |
3016 | } | 3042 | } | |
3017 | if (state->auth.token) | 3043 | if (state->auth.token) | |
3018 | logdebugx("%s: validated using 0x%08" PRIu32, | 3044 | logdebugx("%s: validated using 0x%08" PRIu32, | |
3019 | ifp->name, state->auth.token->secretid); | 3045 | ifp->name, state->auth.token->secretid); | |
3020 | else | 3046 | else | |
3021 | loginfox("%s: accepted reconfigure key", ifp->name); | 3047 | loginfox("%s: accepted reconfigure key", ifp->name); | |
3022 | } else if (ifo->auth.options & DHCPCD_AUTH_SEND) { | 3048 | } else if (ifo->auth.options & DHCPCD_AUTH_SEND) { | |
3023 | if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) { | 3049 | if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) { | |
3024 | LOGDHCP0(LOG_ERR, "no authentication"); | 3050 | LOGDHCP0(LOG_ERR, "no authentication"); | |
3025 | return; | 3051 | return; | |
3026 | } | 3052 | } | |
3027 | LOGDHCP0(LOG_WARNING, "no authentication"); | 3053 | LOGDHCP0(LOG_WARNING, "no authentication"); | |
3028 | } | 3054 | } | |
3029 | #endif | 3055 | #endif | |
3030 | 3056 | |||
3031 | /* RFC 3203 */ | 3057 | /* RFC 3203 */ | |
3032 | if (type == DHCP_FORCERENEW) { | 3058 | if (type == DHCP_FORCERENEW) { | |
3033 | if (from->s_addr == INADDR_ANY || | 3059 | if (from->s_addr == INADDR_ANY || | |
3034 | from->s_addr == INADDR_BROADCAST) | 3060 | from->s_addr == INADDR_BROADCAST) | |
3035 | { | 3061 | { | |
3036 | LOGDHCP(LOG_ERR, "discarding Force Renew"); | 3062 | LOGDHCP(LOG_ERR, "discarding Force Renew"); | |
3037 | return; | 3063 | return; | |
3038 | } | 3064 | } | |
3039 | #ifdef AUTH | 3065 | #ifdef AUTH | |
3040 | if (auth == NULL) { | 3066 | if (auth == NULL) { | |
3041 | LOGDHCP(LOG_ERR, "unauthenticated Force Renew"); | 3067 | LOGDHCP(LOG_ERR, "unauthenticated Force Renew"); | |
3042 | if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) | 3068 | if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) | |
3043 | return; | 3069 | return; | |
3044 | } | 3070 | } | |
3045 | if (state->state != DHS_BOUND && state->state != DHS_INFORM) { | 3071 | if (state->state != DHS_BOUND && state->state != DHS_INFORM) { | |
3046 | LOGDHCP(LOG_DEBUG, "not bound, ignoring Force Renew"); | 3072 | LOGDHCP(LOG_DEBUG, "not bound, ignoring Force Renew"); | |
3047 | return; | 3073 | return; | |
3048 | } | 3074 | } | |
3049 | LOGDHCP(LOG_INFO, "Force Renew from"); | 3075 | LOGDHCP(LOG_INFO, "Force Renew from"); | |
3050 | /* The rebind and expire timings are still the same, we just | 3076 | /* The rebind and expire timings are still the same, we just | |
3051 | * enter the renew state early */ | 3077 | * enter the renew state early */ | |
3052 | if (state->state == DHS_BOUND) | 3078 | if (state->state == DHS_BOUND) | |
3053 | dhcp_renew(ifp); | 3079 | dhcp_renew(ifp); | |
3054 | else { | 3080 | else { | |
3055 | eloop_timeout_delete(ifp->ctx->eloop, | 3081 | eloop_timeout_delete(ifp->ctx->eloop, | |
3056 | send_inform, ifp); | 3082 | send_inform, ifp); | |
3057 | dhcp_inform(ifp); | 3083 | dhcp_inform(ifp); | |
3058 | } | 3084 | } | |
3059 | #else | 3085 | #else | |
3060 | LOGDHCP(LOG_ERR, "unauthenticated Force Renew"); | 3086 | LOGDHCP(LOG_ERR, "unauthenticated Force Renew"); | |
3061 | #endif | 3087 | #endif | |
3062 | return; | 3088 | return; | |
3063 | } | 3089 | } | |
3064 | 3090 | |||
3065 | if (state->state == DHS_BOUND) { | 3091 | if (state->state == DHS_BOUND) { | |
3066 | LOGDHCP(LOG_DEBUG, "bound, ignoring"); | 3092 | LOGDHCP(LOG_DEBUG, "bound, ignoring"); | |
3067 | return; | 3093 | return; | |
3068 | } | 3094 | } | |
3069 | 3095 | |||
3070 | if (state->state == DHS_PROBE) { | 3096 | if (state->state == DHS_PROBE) { | |
3071 | /* Ignore any DHCP messages whilst probing a lease to bind. */ | 3097 | /* Ignore any DHCP messages whilst probing a lease to bind. */ | |
3072 | LOGDHCP(LOG_DEBUG, "probing, ignoring"); | 3098 | LOGDHCP(LOG_DEBUG, "probing, ignoring"); | |
3073 | return; | 3099 | return; | |
3074 | } | 3100 | } | |
3075 | 3101 | |||
3076 | /* reset the message counter */ | 3102 | /* reset the message counter */ | |
3077 | state->interval = 0; | 3103 | state->interval = 0; | |
3078 | 3104 | |||
3079 | /* Ensure that no reject options are present */ | 3105 | /* Ensure that no reject options are present */ | |
3080 | for (i = 1; i < 255; i++) { | 3106 | for (i = 1; i < 255; i++) { | |
3081 | if (has_option_mask(ifo->rejectmask, i) && | 3107 | if (has_option_mask(ifo->rejectmask, i) && | |
3082 | get_option_uint8(ifp->ctx, &tmp, | 3108 | get_option_uint8(ifp->ctx, &tmp, | |
3083 | bootp, bootp_len, (uint8_t)i) == 0) | 3109 | bootp, bootp_len, (uint8_t)i) == 0) | |
3084 | { | 3110 | { | |
3085 | LOGDHCP(LOG_WARNING, "reject DHCP"); | 3111 | LOGDHCP(LOG_WARNING, "reject DHCP"); | |
3086 | return; | 3112 | return; | |
3087 | } | 3113 | } | |
3088 | } | 3114 | } | |
3089 | 3115 | |||
3090 | if (type == DHCP_NAK) { | 3116 | if (type == DHCP_NAK) { | |
3091 | /* For NAK, only check if we require the ServerID */ | 3117 | /* For NAK, only check if we require the ServerID */ | |
3092 | if (has_option_mask(ifo->requiremask, DHO_SERVERID) && | 3118 | if (has_option_mask(ifo->requiremask, DHO_SERVERID) && | |
3093 | get_option_addr(ifp->ctx, &addr, | 3119 | get_option_addr(ifp->ctx, &addr, | |
3094 | bootp, bootp_len, DHO_SERVERID) == -1) | 3120 | bootp, bootp_len, DHO_SERVERID) == -1) | |
3095 | { | 3121 | { | |
3096 | LOGDHCP(LOG_WARNING, "reject NAK"); | 3122 | LOGDHCP(LOG_WARNING, "reject NAK"); | |
3097 | return; | 3123 | return; | |
3098 | } | 3124 | } | |
3099 | 3125 | |||
3100 | /* We should restart on a NAK */ | 3126 | /* We should restart on a NAK */ | |
3101 | LOGDHCP(LOG_WARNING, "NAK:"); | 3127 | LOGDHCP(LOG_WARNING, "NAK:"); | |
3102 | if ((msg = get_option_string(ifp->ctx, | 3128 | if ((msg = get_option_string(ifp->ctx, | |
3103 | bootp, bootp_len, DHO_MESSAGE))) | 3129 | bootp, bootp_len, DHO_MESSAGE))) | |
3104 | { | 3130 | { | |
3105 | logwarnx("%s: message: %s", ifp->name, msg); | 3131 | logwarnx("%s: message: %s", ifp->name, msg); | |
3106 | free(msg); | 3132 | free(msg); | |
3107 | } | 3133 | } | |
3108 | if (state->state == DHS_INFORM) /* INFORM should not be NAKed */ | 3134 | if (state->state == DHS_INFORM) /* INFORM should not be NAKed */ | |
3109 | return; | 3135 | return; | |
3110 | if (!(ifp->ctx->options & DHCPCD_TEST)) { | 3136 | if (!(ifp->ctx->options & DHCPCD_TEST)) { | |
3111 | dhcp_drop(ifp, "NAK"); | 3137 | dhcp_drop(ifp, "NAK"); | |
3112 | dhcp_unlink(ifp->ctx, state->leasefile); | 3138 | dhcp_unlink(ifp->ctx, state->leasefile); | |
3113 | } | 3139 | } | |
3114 | 3140 | |||
3115 | /* If we constantly get NAKS then we should slowly back off */ | 3141 | /* If we constantly get NAKS then we should slowly back off */ | |
3116 | eloop_timeout_add_sec(ifp->ctx->eloop, | 3142 | eloop_timeout_add_sec(ifp->ctx->eloop, | |
3117 | state->nakoff, dhcp_discover, ifp); | 3143 | state->nakoff, dhcp_discover, ifp); | |
3118 | if (state->nakoff == 0) | 3144 | if (state->nakoff == 0) | |
3119 | state->nakoff = 1; | 3145 | state->nakoff = 1; | |
3120 | else { | 3146 | else { | |
3121 | state->nakoff *= 2; | 3147 | state->nakoff *= 2; | |
3122 | if (state->nakoff > NAKOFF_MAX) | 3148 | if (state->nakoff > NAKOFF_MAX) | |
3123 | state->nakoff = NAKOFF_MAX; | 3149 | state->nakoff = NAKOFF_MAX; | |
3124 | } | 3150 | } | |
3125 | return; | 3151 | return; | |
3126 | } | 3152 | } | |
3127 | 3153 | |||
3128 | /* Ensure that all required options are present */ | 3154 | /* Ensure that all required options are present */ | |
3129 | for (i = 1; i < 255; i++) { | 3155 | for (i = 1; i < 255; i++) { | |
3130 | if (has_option_mask(ifo->requiremask, i) && | 3156 | if (has_option_mask(ifo->requiremask, i) && | |
3131 | get_option_uint8(ifp->ctx, &tmp, | 3157 | get_option_uint8(ifp->ctx, &tmp, | |
3132 | bootp, bootp_len, (uint8_t)i) != 0) | 3158 | bootp, bootp_len, (uint8_t)i) != 0) | |
3133 | { | 3159 | { | |
3134 | /* If we are BOOTP, then ignore the need for serverid. | 3160 | /* If we are BOOTP, then ignore the need for serverid. | |
3135 | * To ignore BOOTP, require dhcp_message_type. | 3161 | * To ignore BOOTP, require dhcp_message_type. | |
3136 | * However, nothing really stops BOOTP from providing | 3162 | * However, nothing really stops BOOTP from providing | |
3137 | * DHCP style options as well so the above isn't | 3163 | * DHCP style options as well so the above isn't | |
3138 | * always true. */ | 3164 | * always true. */ | |
3139 | if (type == 0 && i == DHO_SERVERID) | 3165 | if (type == 0 && i == DHO_SERVERID) | |
3140 | continue; | 3166 | continue; | |
3141 | LOGDHCP(LOG_WARNING, "reject DHCP"); | 3167 | LOGDHCP(LOG_WARNING, "reject DHCP"); | |
3142 | return; | 3168 | return; | |
3143 | } | 3169 | } | |
3144 | } | 3170 | } | |
3145 | 3171 | |||
3172 | if (has_option_mask(ifo->requestmask, DHO_IPV6_PREFERRED_ONLY)) { | |||
3173 | if (get_option_uint32(ifp->ctx, &v6only_time, bootp, bootp_len, | |||
3174 | DHO_IPV6_PREFERRED_ONLY) == 0 && | |||
3175 | (state->state == DHS_DISCOVER || state->state == DHS_REBOOT)) | |||
3176 | { | |||
3177 | char v6msg[128]; | |||
3178 | ||||
3179 | use_v6only = true; | |||
3180 | if (v6only_time < MIN_V6ONLY_WAIT) | |||
3181 | v6only_time = MIN_V6ONLY_WAIT; | |||
3182 | snprintf(v6msg, sizeof(v6msg), | |||
3183 | "IPv6-Only Preferred received (%u seconds)", | |||
3184 | v6only_time); | |||
3185 | LOGDHCP(LOG_INFO, v6msg); | |||
3186 | } | |||
3187 | } | |||
3188 | ||||
3146 | /* DHCP Auto-Configure, RFC 2563 */ | 3189 | /* DHCP Auto-Configure, RFC 2563 */ | |
3147 | if (type == DHCP_OFFER && bootp->yiaddr == 0) { | 3190 | if (type == DHCP_OFFER && bootp->yiaddr == 0) { | |
3148 | LOGDHCP(LOG_WARNING, "no address given"); | 3191 | LOGDHCP(LOG_WARNING, "no address given"); | |
3149 | if ((msg = get_option_string(ifp->ctx, | 3192 | if ((msg = get_option_string(ifp->ctx, | |
3150 | bootp, bootp_len, DHO_MESSAGE))) | 3193 | bootp, bootp_len, DHO_MESSAGE))) | |
3151 | { | 3194 | { | |
3152 | logwarnx("%s: message: %s", ifp->name, msg); | 3195 | logwarnx("%s: message: %s", ifp->name, msg); | |
3153 | free(msg); | 3196 | free(msg); | |
3154 | } | 3197 | } | |
3155 | #ifdef IPV4LL | 3198 | #ifdef IPV4LL | |
3156 | if (state->state == DHS_DISCOVER && | 3199 | if (state->state == DHS_DISCOVER && | |
3157 | get_option_uint8(ifp->ctx, &tmp, bootp, bootp_len, | 3200 | get_option_uint8(ifp->ctx, &tmp, bootp, bootp_len, | |
3158 | DHO_AUTOCONFIGURE) == 0) | 3201 | DHO_AUTOCONFIGURE) == 0) | |
3159 | { | 3202 | { | |
3160 | switch (tmp) { | 3203 | switch (tmp) { | |
3161 | case 0: | 3204 | case 0: | |
3162 | LOGDHCP(LOG_WARNING, "IPv4LL disabled from"); | 3205 | LOGDHCP(LOG_WARNING, "IPv4LL disabled from"); | |
3163 | ipv4ll_drop(ifp); | 3206 | ipv4ll_drop(ifp); | |
3164 | #ifdef ARP | 3207 | #ifdef ARP | |
3165 | arp_drop(ifp); | 3208 | arp_drop(ifp); | |
3166 | #endif | 3209 | #endif | |
3167 | break; | 3210 | break; | |
3168 | case 1: | 3211 | case 1: | |
3169 | LOGDHCP(LOG_WARNING, "IPv4LL enabled from"); | 3212 | LOGDHCP(LOG_WARNING, "IPv4LL enabled from"); | |
3170 | ipv4ll_start(ifp); | 3213 | ipv4ll_start(ifp); | |
3171 | break; | 3214 | break; | |
3172 | default: | 3215 | default: | |
3173 | logerrx("%s: unknown auto configuration " | 3216 | logerrx("%s: unknown auto configuration " | |
3174 | "option %d", | 3217 | "option %d", | |
3175 | ifp->name, tmp); | 3218 | ifp->name, tmp); | |
3176 | break; | 3219 | break; | |
3177 | } | 3220 | } | |
3178 | eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); | 3221 | eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); | |
3179 | eloop_timeout_add_sec(ifp->ctx->eloop, | 3222 | eloop_timeout_add_sec(ifp->ctx->eloop, | |
3180 | DHCP_MAX, dhcp_discover, ifp); | 3223 | use_v6only ? v6only_time : DHCP_MAX, | |
3224 | dhcp_discover, ifp); | |||
3181 | } | 3225 | } | |
3182 | #endif | 3226 | #endif | |
3183 | return; | 3227 | return; | |
3184 | } | 3228 | } | |
3185 | 3229 | |||
3230 | if (use_v6only) { | |||
3231 | dhcp_drop(ifp, "EXPIRE"); | |||
3232 | dhcp_unlink(ifp->ctx, state->leasefile); | |||
3233 | eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); | |||
3234 | eloop_timeout_add_sec(ifp->ctx->eloop, v6only_time, | |||
3235 | dhcp_discover, ifp); | |||
3236 | return; | |||
3237 | } | |||
3238 | ||||
3186 | /* Ensure that the address offered is valid */ | 3239 | /* Ensure that the address offered is valid */ | |
3187 | if ((type == 0 || type == DHCP_OFFER || type == DHCP_ACK) && | 3240 | if ((type == 0 || type == DHCP_OFFER || type == DHCP_ACK) && | |
3188 | (bootp->ciaddr == INADDR_ANY || bootp->ciaddr == INADDR_BROADCAST) | 3241 | (bootp->ciaddr == INADDR_ANY || bootp->ciaddr == INADDR_BROADCAST) | |
3189 | && | 3242 | && | |
3190 | (bootp->yiaddr == INADDR_ANY || bootp->yiaddr == INADDR_BROADCAST)) | 3243 | (bootp->yiaddr == INADDR_ANY || bootp->yiaddr == INADDR_BROADCAST)) | |
3191 | { | 3244 | { | |
3192 | LOGDHCP(LOG_WARNING, "reject invalid address"); | 3245 | LOGDHCP(LOG_WARNING, "reject invalid address"); | |
3193 | return; | 3246 | return; | |
3194 | } | 3247 | } | |
3195 | 3248 | |||
3196 | #ifdef IN_IFF_DUPLICATED | 3249 | #ifdef IN_IFF_DUPLICATED | |
3197 | ia = ipv4_iffindaddr(ifp, &lease->addr, NULL); | 3250 | ia = ipv4_iffindaddr(ifp, &lease->addr, NULL); | |
3198 | if (ia && ia->addr_flags & IN_IFF_DUPLICATED) { | 3251 | if (ia && ia->addr_flags & IN_IFF_DUPLICATED) { | |
3199 | LOGDHCP(LOG_WARNING, "declined duplicate address"); | 3252 | LOGDHCP(LOG_WARNING, "declined duplicate address"); | |
3200 | if (type) | 3253 | if (type) | |
3201 | dhcp_decline(ifp); | 3254 | dhcp_decline(ifp); | |
3202 | ipv4_deladdr(ia, 0); | 3255 | ipv4_deladdr(ia, 0); | |
3203 | eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); | 3256 | eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); | |
3204 | eloop_timeout_add_sec(ifp->ctx->eloop, | 3257 | eloop_timeout_add_sec(ifp->ctx->eloop, | |
3205 | DHCP_RAND_MAX, dhcp_discover, ifp); | 3258 | DHCP_RAND_MAX, dhcp_discover, ifp); | |
3206 | return; | 3259 | return; | |
3207 | } | 3260 | } | |
3208 | #endif | 3261 | #endif | |
3209 | 3262 | |||
3210 | bootp_copied = false; | 3263 | bootp_copied = false; | |
3211 | if ((type == 0 || type == DHCP_OFFER) && state->state == DHS_DISCOVER) { | 3264 | if ((type == 0 || type == DHCP_OFFER) && state->state == DHS_DISCOVER) { | |
3212 | lease->frominfo = 0; | 3265 | lease->frominfo = 0; | |
3213 | lease->addr.s_addr = bootp->yiaddr; | 3266 | lease->addr.s_addr = bootp->yiaddr; | |
3214 | memcpy(&lease->cookie, bootp->vend, sizeof(lease->cookie)); | 3267 | memcpy(&lease->cookie, bootp->vend, sizeof(lease->cookie)); | |
3215 | if (type == 0 || | 3268 | if (type == 0 || | |
3216 | get_option_addr(ifp->ctx, | 3269 | get_option_addr(ifp->ctx, | |
3217 | &lease->server, bootp, bootp_len, DHO_SERVERID) != 0) | 3270 | &lease->server, bootp, bootp_len, DHO_SERVERID) != 0) | |
3218 | lease->server.s_addr = INADDR_ANY; | 3271 | lease->server.s_addr = INADDR_ANY; | |
3219 | 3272 | |||
3220 | /* Test for rapid commit in the OFFER */ | 3273 | /* Test for rapid commit in the OFFER */ | |
3221 | if (!(ifp->ctx->options & DHCPCD_TEST) && | 3274 | if (!(ifp->ctx->options & DHCPCD_TEST) && | |
3222 | has_option_mask(ifo->requestmask, DHO_RAPIDCOMMIT) && | 3275 | has_option_mask(ifo->requestmask, DHO_RAPIDCOMMIT) && | |
3223 | get_option(ifp->ctx, bootp, bootp_len, | 3276 | get_option(ifp->ctx, bootp, bootp_len, | |
3224 | DHO_RAPIDCOMMIT, NULL)) | 3277 | DHO_RAPIDCOMMIT, NULL)) | |
3225 | { | 3278 | { | |
3226 | state->state = DHS_REQUEST; | 3279 | state->state = DHS_REQUEST; | |
3227 | goto rapidcommit; | 3280 | goto rapidcommit; | |
3228 | } | 3281 | } | |
3229 | 3282 | |||
3230 | LOGDHCP(LOG_INFO, "offered"); | 3283 | LOGDHCP(LOG_INFO, "offered"); | |
3231 | if (state->offer_len < bootp_len) { | 3284 | if (state->offer_len < bootp_len) { | |
3232 | free(state->offer); | 3285 | free(state->offer); | |
3233 | if ((state->offer = malloc(bootp_len)) == NULL) { | 3286 | if ((state->offer = malloc(bootp_len)) == NULL) { | |
3234 | logerr(__func__); | 3287 | logerr(__func__); | |
3235 | state->offer_len = 0; | 3288 | state->offer_len = 0; | |
3236 | return; | 3289 | return; | |
3237 | } | 3290 | } | |
3238 | } | 3291 | } | |
3239 | state->offer_len = bootp_len; | 3292 | state->offer_len = bootp_len; | |
3240 | memcpy(state->offer, bootp, bootp_len); | 3293 | memcpy(state->offer, bootp, bootp_len); | |
3241 | bootp_copied = true; | 3294 | bootp_copied = true; | |
3242 | if (ifp->ctx->options & DHCPCD_TEST) { | 3295 | if (ifp->ctx->options & DHCPCD_TEST) { | |
3243 | free(state->old); | 3296 | free(state->old); | |
3244 | state->old = state->new; | 3297 | state->old = state->new; | |
3245 | state->old_len = state->new_len; | 3298 | state->old_len = state->new_len; | |
3246 | state->new = state->offer; | 3299 | state->new = state->offer; | |
3247 | state->new_len = state->offer_len; | 3300 | state->new_len = state->offer_len; | |
3248 | state->offer = NULL; | 3301 | state->offer = NULL; | |
3249 | state->offer_len = 0; | 3302 | state->offer_len = 0; | |
3250 | state->reason = "TEST"; | 3303 | state->reason = "TEST"; | |
3251 | script_runreason(ifp, state->reason); | 3304 | script_runreason(ifp, state->reason); | |
3252 | eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS); | 3305 | eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS); | |
3253 | state->bpf->bpf_flags |= BPF_EOF; | 3306 | state->bpf->bpf_flags |= BPF_EOF; | |
3254 | return; | 3307 | return; | |
3255 | } | 3308 | } | |
3256 | eloop_timeout_delete(ifp->ctx->eloop, send_discover, ifp); | 3309 | eloop_timeout_delete(ifp->ctx->eloop, send_discover, ifp); | |
3257 | /* We don't request BOOTP addresses */ | 3310 | /* We don't request BOOTP addresses */ | |
3258 | if (type) { | 3311 | if (type) { | |
3259 | /* We used to ARP check here, but that seems to be in | 3312 | /* We used to ARP check here, but that seems to be in | |
3260 | * violation of RFC2131 where it only describes | 3313 | * violation of RFC2131 where it only describes | |
3261 | * DECLINE after REQUEST. | 3314 | * DECLINE after REQUEST. | |
3262 | * It also seems that some MS DHCP servers actually | 3315 | * It also seems that some MS DHCP servers actually | |
3263 | * ignore DECLINE if no REQUEST, ie we decline a | 3316 | * ignore DECLINE if no REQUEST, ie we decline a | |
3264 | * DISCOVER. */ | 3317 | * DISCOVER. */ | |
3265 | dhcp_request(ifp); | 3318 | dhcp_request(ifp); | |
3266 | return; | 3319 | return; | |
3267 | } | 3320 | } | |
3268 | } | 3321 | } | |
3269 | 3322 | |||
3270 | if (type) { | 3323 | if (type) { | |
3271 | if (type == DHCP_OFFER) { | 3324 | if (type == DHCP_OFFER) { | |
3272 | LOGDHCP(LOG_WARNING, "ignoring offer of"); | 3325 | LOGDHCP(LOG_WARNING, "ignoring offer of"); | |
3273 | return; | 3326 | return; | |
3274 | } | 3327 | } | |
3275 | 3328 | |||
3276 | /* We should only be dealing with acks */ | 3329 | /* We should only be dealing with acks */ | |
3277 | if (type != DHCP_ACK) { | 3330 | if (type != DHCP_ACK) { | |
3278 | LOGDHCP(LOG_ERR, "not ACK or OFFER"); | 3331 | LOGDHCP(LOG_ERR, "not ACK or OFFER"); | |
3279 | return; | 3332 | return; | |
3280 | } | 3333 | } | |
3281 | 3334 | |||
3282 | if (state->state == DHS_DISCOVER) { | 3335 | if (state->state == DHS_DISCOVER) { | |
3283 | /* We only allow ACK of rapid commit DISCOVER. */ | 3336 | /* We only allow ACK of rapid commit DISCOVER. */ | |
3284 | if (has_option_mask(ifo->requestmask, | 3337 | if (has_option_mask(ifo->requestmask, | |
3285 | DHO_RAPIDCOMMIT) && | 3338 | DHO_RAPIDCOMMIT) && | |
3286 | get_option(ifp->ctx, bootp, bootp_len, | 3339 | get_option(ifp->ctx, bootp, bootp_len, | |
3287 | DHO_RAPIDCOMMIT, NULL)) | 3340 | DHO_RAPIDCOMMIT, NULL)) | |
3288 | state->state = DHS_REQUEST; | 3341 | state->state = DHS_REQUEST; | |
3289 | else { | 3342 | else { | |
3290 | LOGDHCP(LOG_DEBUG, "ignoring ack of"); | 3343 | LOGDHCP(LOG_DEBUG, "ignoring ack of"); | |
3291 | return; | 3344 | return; | |
3292 | } | 3345 | } | |
3293 | } | 3346 | } | |
3294 | 3347 | |||
3295 | rapidcommit: | 3348 | rapidcommit: | |
3296 | if (!(ifo->options & DHCPCD_INFORM)) | 3349 | if (!(ifo->options & DHCPCD_INFORM)) | |
3297 | LOGDHCP(LOG_DEBUG, "acknowledged"); | 3350 | LOGDHCP(LOG_DEBUG, "acknowledged"); | |
3298 | else | 3351 | else | |
3299 | ifo->options &= ~DHCPCD_STATIC; | 3352 | ifo->options &= ~DHCPCD_STATIC; | |
3300 | } | 3353 | } | |
3301 | 3354 | |||
3302 | /* No NAK, so reset the backoff | 3355 | /* No NAK, so reset the backoff | |
3303 | * We don't reset on an OFFER message because the server could | 3356 | * We don't reset on an OFFER message because the server could | |
3304 | * potentially NAK the REQUEST. */ | 3357 | * potentially NAK the REQUEST. */ | |
3305 | state->nakoff = 0; | 3358 | state->nakoff = 0; | |
3306 | 3359 | |||
3307 | /* BOOTP could have already assigned this above. */ | 3360 | /* BOOTP could have already assigned this above. */ | |
3308 | if (!bootp_copied) { | 3361 | if (!bootp_copied) { | |
3309 | if (state->offer_len < bootp_len) { | 3362 | if (state->offer_len < bootp_len) { | |
3310 | free(state->offer); | 3363 | free(state->offer); | |
3311 | if ((state->offer = malloc(bootp_len)) == NULL) { | 3364 | if ((state->offer = malloc(bootp_len)) == NULL) { | |
3312 | logerr(__func__); | 3365 | logerr(__func__); | |
3313 | state->offer_len = 0; | 3366 | state->offer_len = 0; | |
3314 | return; | 3367 | return; | |
3315 | } | 3368 | } | |
3316 | } | 3369 | } | |
3317 | state->offer_len = bootp_len; | 3370 | state->offer_len = bootp_len; | |
3318 | memcpy(state->offer, bootp, bootp_len); | 3371 | memcpy(state->offer, bootp, bootp_len); | |
3319 | } | 3372 | } | |
3320 | 3373 | |||
3321 | lease->frominfo = 0; | 3374 | lease->frominfo = 0; | |
3322 | eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); | 3375 | eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); | |
3323 | 3376 | |||
3324 | #if defined(ARP) || defined(KERNEL_RFC5227) | 3377 | #if defined(ARP) || defined(KERNEL_RFC5227) | |
3325 | dhcp_arp_bind(ifp); | 3378 | dhcp_arp_bind(ifp); | |
3326 | #else | 3379 | #else | |
3327 | dhcp_bind(ifp); | 3380 | dhcp_bind(ifp); | |
3328 | #endif | 3381 | #endif | |
3329 | } | 3382 | } | |
3330 | 3383 | |||
3331 | static void * | 3384 | static void * | |
3332 | get_udp_data(void *packet, size_t *len) | 3385 | get_udp_data(void *packet, size_t *len) | |
3333 | { | 3386 | { | |
3334 | const struct ip *ip = packet; | 3387 | const struct ip *ip = packet; | |
3335 | size_t ip_hl = (size_t)ip->ip_hl * 4; | 3388 | size_t ip_hl = (size_t)ip->ip_hl * 4; | |
3336 | char *p = packet; | 3389 | char *p = packet; | |
3337 | 3390 | |||
3338 | p += ip_hl + sizeof(struct udphdr); | 3391 | p += ip_hl + sizeof(struct udphdr); | |
3339 | *len = (size_t)ntohs(ip->ip_len) - sizeof(struct udphdr) - ip_hl; | 3392 | *len = (size_t)ntohs(ip->ip_len) - sizeof(struct udphdr) - ip_hl; | |
3340 | return p; | 3393 | return p; | |
3341 | } | 3394 | } | |
3342 | 3395 | |||
3343 | static bool | 3396 | static bool | |
3344 | is_packet_udp_bootp(void *packet, size_t plen) | 3397 | is_packet_udp_bootp(void *packet, size_t plen) | |
3345 | { | 3398 | { | |
3346 | struct ip *ip = packet; | 3399 | struct ip *ip = packet; | |
3347 | size_t ip_hlen; | 3400 | size_t ip_hlen; | |
3348 | struct udphdr udp; | 3401 | struct udphdr udp; | |
3349 | 3402 | |||
3350 | if (plen < sizeof(*ip)) | 3403 | if (plen < sizeof(*ip)) | |
3351 | return false; | 3404 | return false; | |
3352 | 3405 | |||
3353 | if (ip->ip_v != IPVERSION || ip->ip_p != IPPROTO_UDP) | 3406 | if (ip->ip_v != IPVERSION || ip->ip_p != IPPROTO_UDP) | |
3354 | return false; | 3407 | return false; | |
3355 | 3408 | |||
3356 | /* Sanity. */ | 3409 | /* Sanity. */ | |
3357 | if (ntohs(ip->ip_len) > plen) | 3410 | if (ntohs(ip->ip_len) > plen) | |
3358 | return false; | 3411 | return false; | |
3359 | 3412 | |||
3360 | ip_hlen = (size_t)ip->ip_hl * 4; | 3413 | ip_hlen = (size_t)ip->ip_hl * 4; | |
3361 | if (ip_hlen < sizeof(*ip)) | 3414 | if (ip_hlen < sizeof(*ip)) | |
3362 | return false; | 3415 | return false; | |
3363 | 3416 | |||
3364 | /* Check we have a UDP header and BOOTP. */ | 3417 | /* Check we have a UDP header and BOOTP. */ | |
3365 | if (ip_hlen + sizeof(udp) + offsetof(struct bootp, vend) > plen) | 3418 | if (ip_hlen + sizeof(udp) + offsetof(struct bootp, vend) > plen) | |
3366 | return false; | 3419 | return false; | |
3367 | 3420 | |||
3368 | /* Sanity. */ | 3421 | /* Sanity. */ | |
3369 | memcpy(&udp, (char *)ip + ip_hlen, sizeof(udp)); | 3422 | memcpy(&udp, (char *)ip + ip_hlen, sizeof(udp)); | |
3370 | if (ntohs(udp.uh_ulen) < sizeof(udp)) | 3423 | if (ntohs(udp.uh_ulen) < sizeof(udp)) | |
3371 | return false; | 3424 | return false; | |
3372 | if (ip_hlen + ntohs(udp.uh_ulen) > plen) | 3425 | if (ip_hlen + ntohs(udp.uh_ulen) > plen) | |
3373 | return false; | 3426 | return false; | |
3374 | 3427 | |||
3375 | /* Check it's to and from the right ports. */ | 3428 | /* Check it's to and from the right ports. */ | |
3376 | if (udp.uh_dport != htons(BOOTPC) || udp.uh_sport != htons(BOOTPS)) | 3429 | if (udp.uh_dport != htons(BOOTPC) || udp.uh_sport != htons(BOOTPS)) | |
3377 | return false; | 3430 | return false; | |
3378 | 3431 | |||
3379 | return true; | 3432 | return true; | |
3380 | } | 3433 | } | |
3381 | 3434 | |||
3382 | /* Lengths have already been checked. */ | 3435 | /* Lengths have already been checked. */ | |
3383 | static bool | 3436 | static bool | |
3384 | checksums_valid(void *packet, | 3437 | checksums_valid(void *packet, | |
3385 | struct in_addr *from, unsigned int flags) | 3438 | struct in_addr *from, unsigned int flags) | |
3386 | { | 3439 | { | |
3387 | struct ip *ip = packet; | 3440 | struct ip *ip = packet; | |
3388 | union pip { | 3441 | union pip { | |
3389 | struct ip ip; | 3442 | struct ip ip; | |
3390 | uint16_t w[sizeof(struct ip) / 2]; | 3443 | uint16_t w[sizeof(struct ip) / 2]; | |
3391 | } pip = { | 3444 | } pip = { | |
3392 | .ip = { | 3445 | .ip = { | |
3393 | .ip_p = IPPROTO_UDP, | 3446 | .ip_p = IPPROTO_UDP, | |
3394 | .ip_src = ip->ip_src, | 3447 | .ip_src = ip->ip_src, | |
3395 | .ip_dst = ip->ip_dst, | 3448 | .ip_dst = ip->ip_dst, | |
3396 | } | 3449 | } | |
3397 | }; | 3450 | }; | |
3398 | size_t ip_hlen; | 3451 | size_t ip_hlen; | |
3399 | struct udphdr udp; | 3452 | struct udphdr udp; | |
3400 | char *udpp, *uh_sump; | 3453 | char *udpp, *uh_sump; | |
3401 | uint32_t csum; | 3454 | uint32_t csum; | |
3402 | 3455 | |||
3403 | if (from != NULL) | 3456 | if (from != NULL) | |
3404 | from->s_addr = ip->ip_src.s_addr; | 3457 | from->s_addr = ip->ip_src.s_addr; | |
3405 | 3458 | |||
3406 | ip_hlen = (size_t)ip->ip_hl * 4; | 3459 | ip_hlen = (size_t)ip->ip_hl * 4; | |
3407 | if (in_cksum(ip, ip_hlen, NULL) != 0) | 3460 | if (in_cksum(ip, ip_hlen, NULL) != 0) | |
3408 | return false; | 3461 | return false; | |
3409 | 3462 | |||
3410 | if (flags & BPF_PARTIALCSUM) | 3463 | if (flags & BPF_PARTIALCSUM) | |
3411 | return true; | 3464 | return true; | |
3412 | 3465 | |||
3413 | udpp = (char *)ip + ip_hlen; | 3466 | udpp = (char *)ip + ip_hlen; | |
3414 | memcpy(&udp, udpp, sizeof(udp)); | 3467 | memcpy(&udp, udpp, sizeof(udp)); | |
3415 | if (udp.uh_sum == 0) | 3468 | if (udp.uh_sum == 0) | |
3416 | return true; | 3469 | return true; | |
3417 | 3470 | |||
3418 | /* UDP checksum is based on a pseudo IP header alongside | 3471 | /* UDP checksum is based on a pseudo IP header alongside | |
3419 | * the UDP header and payload. */ | 3472 | * the UDP header and payload. */ | |
3420 | pip.ip.ip_len = udp.uh_ulen; | 3473 | pip.ip.ip_len = udp.uh_ulen; | |
3421 | csum = 0; | 3474 | csum = 0; | |
3422 | 3475 | |||
3423 | /* Need to zero the UDP sum in the packet for the checksum to work. */ | 3476 | /* Need to zero the UDP sum in the packet for the checksum to work. */ | |
3424 | uh_sump = udpp + offsetof(struct udphdr, uh_sum); | 3477 | uh_sump = udpp + offsetof(struct udphdr, uh_sum); | |
3425 | memset(uh_sump, 0, sizeof(udp.uh_sum)); | 3478 | memset(uh_sump, 0, sizeof(udp.uh_sum)); | |
3426 | 3479 | |||
3427 | /* Checksum pseudo header and then UDP + payload. */ | 3480 | /* Checksum pseudo header and then UDP + payload. */ | |
3428 | in_cksum(pip.w, sizeof(pip.w), &csum); | 3481 | in_cksum(pip.w, sizeof(pip.w), &csum); | |
3429 | csum = in_cksum(udpp, ntohs(udp.uh_ulen), &csum); | 3482 | csum = in_cksum(udpp, ntohs(udp.uh_ulen), &csum); | |
3430 | 3483 | |||
3431 | #if 0 /* Not needed, just here for completeness. */ | 3484 | #if 0 /* Not needed, just here for completeness. */ | |
3432 | /* Put the checksum back. */ | 3485 | /* Put the checksum back. */ | |
3433 | memcpy(uh_sump, &udp.uh_sum, sizeof(udp.uh_sum)); | 3486 | memcpy(uh_sump, &udp.uh_sum, sizeof(udp.uh_sum)); | |
3434 | #endif | 3487 | #endif | |
3435 | 3488 | |||
3436 | return csum == udp.uh_sum; | 3489 | return csum == udp.uh_sum; | |
3437 | } | 3490 | } | |
3438 | 3491 | |||
3439 | static void | 3492 | static void | |
3440 | dhcp_handlebootp(struct interface *ifp, struct bootp *bootp, size_t len, | 3493 | dhcp_handlebootp(struct interface *ifp, struct bootp *bootp, size_t len, | |
3441 | struct in_addr *from) | 3494 | struct in_addr *from) | |
3442 | { | 3495 | { | |
3443 | size_t v; | 3496 | size_t v; | |
3444 | 3497 | |||
3445 | if (len < offsetof(struct bootp, vend)) { | 3498 | if (len < offsetof(struct bootp, vend)) { | |
3446 | logerrx("%s: truncated packet (%zu) from %s", | 3499 | logerrx("%s: truncated packet (%zu) from %s", | |
3447 | ifp->name, len, inet_ntoa(*from)); | 3500 | ifp->name, len, inet_ntoa(*from)); | |
3448 | return; | 3501 | return; | |
3449 | } | 3502 | } | |
3450 | 3503 | |||
3451 | /* Unlikely, but appeases sanitizers. */ | 3504 | /* Unlikely, but appeases sanitizers. */ | |
3452 | if (len > FRAMELEN_MAX) { | 3505 | if (len > FRAMELEN_MAX) { | |
3453 | logerrx("%s: packet exceeded frame length (%zu) from %s", | 3506 | logerrx("%s: packet exceeded frame length (%zu) from %s", | |
3454 | ifp->name, len, inet_ntoa(*from)); | 3507 | ifp->name, len, inet_ntoa(*from)); | |
3455 | return; | 3508 | return; | |
3456 | } | 3509 | } | |
3457 | 3510 | |||
3458 | /* To make our IS_DHCP macro easy, ensure the vendor | 3511 | /* To make our IS_DHCP macro easy, ensure the vendor | |
3459 | * area has at least 4 octets. */ | 3512 | * area has at least 4 octets. */ | |
3460 | v = len - offsetof(struct bootp, vend); | 3513 | v = len - offsetof(struct bootp, vend); | |
3461 | while (v < 4) { | 3514 | while (v < 4) { | |
3462 | bootp->vend[v++] = '\0'; | 3515 | bootp->vend[v++] = '\0'; | |
3463 | len++; | 3516 | len++; | |
3464 | } | 3517 | } | |
3465 | 3518 | |||
3466 | dhcp_handledhcp(ifp, bootp, len, from); | 3519 | dhcp_handledhcp(ifp, bootp, len, from); | |
3467 | } | 3520 | } | |
3468 | 3521 | |||
3469 | void | 3522 | void | |
3470 | dhcp_packet(struct interface *ifp, uint8_t *data, size_t len, | 3523 | dhcp_packet(struct interface *ifp, uint8_t *data, size_t len, | |
3471 | unsigned int bpf_flags) | 3524 | unsigned int bpf_flags) | |
3472 | { | 3525 | { | |
3473 | struct bootp *bootp; | 3526 | struct bootp *bootp; | |
3474 | struct in_addr from; | 3527 | struct in_addr from; | |
3475 | size_t udp_len; | 3528 | size_t udp_len; | |
3476 | size_t fl = bpf_frame_header_len(ifp); | 3529 | size_t fl = bpf_frame_header_len(ifp); | |
3477 | #ifdef PRIVSEP | 3530 | #ifdef PRIVSEP | |
3478 | const struct dhcp_state *state = D_CSTATE(ifp); | 3531 | const struct dhcp_state *state = D_CSTATE(ifp); | |
3479 | 3532 | |||
3480 | /* It's possible that an interface departs and arrives in short | 3533 | /* It's possible that an interface departs and arrives in short | |
3481 | * order to receive a BPF frame out of order. | 3534 | * order to receive a BPF frame out of order. | |
3482 | * There is a similar check in ARP, but much lower down the stack. | 3535 | * There is a similar check in ARP, but much lower down the stack. | |
3483 | * It's not needed for other inet protocols because we send the | 3536 | * It's not needed for other inet protocols because we send the | |
3484 | * message as a whole and select the interface off that and then | 3537 | * message as a whole and select the interface off that and then | |
3485 | * check state. BPF on the other hand is very interface | 3538 | * check state. BPF on the other hand is very interface | |
3486 | * specific and we do need this check. */ | 3539 | * specific and we do need this check. */ | |
3487 | if (state == NULL) | 3540 | if (state == NULL) | |
3488 | return; | 3541 | return; | |
3489 | 3542 | |||
3490 | /* Ignore double reads */ | 3543 | /* Ignore double reads */ | |
3491 | if (IN_PRIVSEP(ifp->ctx)) { | 3544 | if (IN_PRIVSEP(ifp->ctx)) { | |
3492 | switch (state->state) { | 3545 | switch (state->state) { | |
3493 | case DHS_BOUND: /* FALLTHROUGH */ | 3546 | case DHS_BOUND: /* FALLTHROUGH */ | |
3494 | case DHS_RENEW: | 3547 | case DHS_RENEW: | |
3495 | return; | 3548 | return; | |
3496 | default: | 3549 | default: | |
3497 | break; | 3550 | break; | |
3498 | } | 3551 | } | |
3499 | } | 3552 | } | |
3500 | #endif | 3553 | #endif | |
3501 | 3554 | |||
3502 | /* Trim frame header */ | 3555 | /* Trim frame header */ | |
3503 | if (fl != 0) { | 3556 | if (fl != 0) { | |
3504 | if (len < fl) { | 3557 | if (len < fl) { | |
3505 | logerrx("%s: %s: short frame header %zu", | 3558 | logerrx("%s: %s: short frame header %zu", | |
3506 | __func__, ifp->name, len); | 3559 | __func__, ifp->name, len); | |
3507 | return; | 3560 | return; | |
3508 | } | 3561 | } | |
3509 | len -= fl; | 3562 | len -= fl; | |
3510 | /* Move the data to avoid alignment errors. */ | 3563 | /* Move the data to avoid alignment errors. */ | |
3511 | memmove(data, data + fl, len); | 3564 | memmove(data, data + fl, len); | |
3512 | } | 3565 | } | |
3513 | 3566 | |||
3514 | /* Validate filter. */ | 3567 | /* Validate filter. */ | |
3515 | if (!is_packet_udp_bootp(data, len)) { | 3568 | if (!is_packet_udp_bootp(data, len)) { | |
3516 | #ifdef BPF_DEBUG | 3569 | #ifdef BPF_DEBUG | |
3517 | logerrx("%s: DHCP BPF validation failure", ifp->name); | 3570 | logerrx("%s: DHCP BPF validation failure", ifp->name); | |
3518 | #endif | 3571 | #endif | |
3519 | return; | 3572 | return; | |
3520 | } | 3573 | } | |
3521 | 3574 | |||
3522 | if (!checksums_valid(data, &from, bpf_flags)) { | 3575 | if (!checksums_valid(data, &from, bpf_flags)) { | |
3523 | logerrx("%s: checksum failure from %s", | 3576 | logerrx("%s: checksum failure from %s", | |
3524 | ifp->name, inet_ntoa(from)); | 3577 | ifp->name, inet_ntoa(from)); | |
3525 | return; | 3578 | return; | |
3526 | } | 3579 | } | |
3527 | 3580 | |||
3528 | /* | 3581 | /* | |
3529 | * DHCP has a variable option area rather than a fixed vendor area. | 3582 | * DHCP has a variable option area rather than a fixed vendor area. | |
3530 | * Because DHCP uses the BOOTP protocol it should still send BOOTP | 3583 | * Because DHCP uses the BOOTP protocol it should still send BOOTP | |
3531 | * sized packets to be RFC compliant. | 3584 | * sized packets to be RFC compliant. | |
3532 | * However some servers send a truncated vendor area. | 3585 | * However some servers send a truncated vendor area. | |
3533 | * dhcpcd can work fine without the vendor area being sent. | 3586 | * dhcpcd can work fine without the vendor area being sent. | |
3534 | */ | 3587 | */ | |
3535 | bootp = get_udp_data(data, &udp_len); | 3588 | bootp = get_udp_data(data, &udp_len); | |
3536 | dhcp_handlebootp(ifp, bootp, udp_len, &from); | 3589 | dhcp_handlebootp(ifp, bootp, udp_len, &from); | |
3537 | } | 3590 | } | |
3538 | 3591 | |||
3539 | static void | 3592 | static void | |
3540 | dhcp_readbpf(void *arg) | 3593 | dhcp_readbpf(void *arg) | |
3541 | { | 3594 | { | |
3542 | struct interface *ifp = arg; | 3595 | struct interface *ifp = arg; | |
3543 | uint8_t buf[FRAMELEN_MAX]; | 3596 | uint8_t buf[FRAMELEN_MAX]; | |
3544 | ssize_t bytes; | 3597 | ssize_t bytes; | |
3545 | struct dhcp_state *state = D_STATE(ifp); | 3598 | struct dhcp_state *state = D_STATE(ifp); | |
3546 | struct bpf *bpf = state->bpf; | 3599 | struct bpf *bpf = state->bpf; | |
3547 | 3600 | |||
3548 | bpf->bpf_flags &= ~BPF_EOF; | 3601 | bpf->bpf_flags &= ~BPF_EOF; | |
3549 | while (!(bpf->bpf_flags & BPF_EOF)) { | 3602 | while (!(bpf->bpf_flags & BPF_EOF)) { | |
3550 | bytes = bpf_read(bpf, buf, sizeof(buf)); | 3603 | bytes = bpf_read(bpf, buf, sizeof(buf)); | |
3551 | if (bytes == -1) { | 3604 | if (bytes == -1) { | |
3552 | if (state->state != DHS_NONE) { | 3605 | if (state->state != DHS_NONE) { | |
3553 | logerr("%s: %s", __func__, ifp->name); | 3606 | logerr("%s: %s", __func__, ifp->name); | |
3554 | dhcp_close(ifp); | 3607 | dhcp_close(ifp); | |
3555 | } | 3608 | } | |
3556 | break; | 3609 | break; | |
3557 | } | 3610 | } | |
3558 | dhcp_packet(ifp, buf, (size_t)bytes, bpf->bpf_flags); | 3611 | dhcp_packet(ifp, buf, (size_t)bytes, bpf->bpf_flags); | |
3559 | /* Check we still have a state after processing. */ | 3612 | /* Check we still have a state after processing. */ | |
3560 | if ((state = D_STATE(ifp)) == NULL) | 3613 | if ((state = D_STATE(ifp)) == NULL) | |
3561 | break; | 3614 | break; | |
3562 | if ((bpf = state->bpf) == NULL) | 3615 | if ((bpf = state->bpf) == NULL) | |
3563 | break; | 3616 | break; | |
3564 | } | 3617 | } | |
3565 | } | 3618 | } | |
3566 | 3619 | |||
3567 | void | 3620 | void | |
3568 | dhcp_recvmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg) | 3621 | dhcp_recvmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg) | |
3569 | { | 3622 | { | |
3570 | struct sockaddr_in *from = (struct sockaddr_in *)msg->msg_name; | 3623 | struct sockaddr_in *from = (struct sockaddr_in *)msg->msg_name; | |
3571 | struct iovec *iov = &msg->msg_iov[0]; | 3624 | struct iovec *iov = &msg->msg_iov[0]; | |
3572 | struct interface *ifp; | 3625 | struct interface *ifp; | |
3573 | const struct dhcp_state *state; | 3626 | const struct dhcp_state *state; | |
3574 | 3627 | |||
3575 | ifp = if_findifpfromcmsg(ctx, msg, NULL); | 3628 | ifp = if_findifpfromcmsg(ctx, msg, NULL); | |
3576 | if (ifp == NULL) { | 3629 | if (ifp == NULL) { | |
3577 | logerr(__func__); | 3630 | logerr(__func__); | |
3578 | return; | 3631 | return; | |
3579 | } | 3632 | } | |
3580 | state = D_CSTATE(ifp); | 3633 | state = D_CSTATE(ifp); | |
3581 | if (state == NULL) { | 3634 | if (state == NULL) { | |
3582 | /* Try re-directing it to another interface. */ | 3635 | /* Try re-directing it to another interface. */ | |
3583 | dhcp_redirect_dhcp(ifp, (struct bootp *)iov->iov_base, | 3636 | dhcp_redirect_dhcp(ifp, (struct bootp *)iov->iov_base, | |
3584 | iov->iov_len, &from->sin_addr); | 3637 | iov->iov_len, &from->sin_addr); | |
3585 | return; | 3638 | return; | |
3586 | } | 3639 | } | |
3587 | 3640 | |||
3588 | if (state->bpf != NULL) { | 3641 | if (state->bpf != NULL) { | |
3589 | /* Avoid a duplicate read if BPF is open for the interface. */ | 3642 | /* Avoid a duplicate read if BPF is open for the interface. */ | |
3590 | return; | 3643 | return; | |
3591 | } | 3644 | } | |
3592 | #ifdef PRIVSEP | 3645 | #ifdef PRIVSEP | |
3593 | if (IN_PRIVSEP(ctx)) { | 3646 | if (IN_PRIVSEP(ctx)) { | |
3594 | switch (state->state) { | 3647 | switch (state->state) { | |
3595 | case DHS_BOUND: /* FALLTHROUGH */ | 3648 | case DHS_BOUND: /* FALLTHROUGH */ | |
3596 | case DHS_RENEW: | 3649 | case DHS_RENEW: | |
3597 | break; | 3650 | break; | |
3598 | default: | 3651 | default: | |
3599 | /* Any other state we ignore it or will receive | 3652 | /* Any other state we ignore it or will receive | |
3600 | * via BPF. */ | 3653 | * via BPF. */ | |
3601 | return; | 3654 | return; | |
3602 | } | 3655 | } | |
3603 | } | 3656 | } | |
3604 | #endif | 3657 | #endif | |
3605 | 3658 | |||
3606 | dhcp_handlebootp(ifp, iov->iov_base, iov->iov_len, | 3659 | dhcp_handlebootp(ifp, iov->iov_base, iov->iov_len, | |
3607 | &from->sin_addr); | 3660 | &from->sin_addr); | |
3608 | } | 3661 | } | |
3609 | 3662 | |||
3610 | static void | 3663 | static void | |
3611 | dhcp_readudp(struct dhcpcd_ctx *ctx, struct interface *ifp) | 3664 | dhcp_readudp(struct dhcpcd_ctx *ctx, struct interface *ifp) | |
3612 | { | 3665 | { | |
3613 | const struct dhcp_state *state; | 3666 | const struct dhcp_state *state; | |
3614 | struct sockaddr_in from; | 3667 | struct sockaddr_in from; | |
3615 | union { | 3668 | union { | |
3616 | struct bootp bootp; | 3669 | struct bootp bootp; | |
3617 | uint8_t buf[10 * 1024]; /* Maximum MTU */ | 3670 | uint8_t buf[10 * 1024]; /* Maximum MTU */ | |
3618 | } iovbuf; | 3671 | } iovbuf; | |
3619 | struct iovec iov = { | 3672 | struct iovec iov = { | |
3620 | .iov_base = iovbuf.buf, | 3673 | .iov_base = iovbuf.buf, | |
3621 | .iov_len = sizeof(iovbuf.buf), | 3674 | .iov_len = sizeof(iovbuf.buf), | |
3622 | }; | 3675 | }; | |
3623 | union { | 3676 | union { | |
3624 | struct cmsghdr hdr; | 3677 | struct cmsghdr hdr; | |
3625 | #ifdef IP_RECVIF | 3678 | #ifdef IP_RECVIF | |
3626 | uint8_t buf[CMSG_SPACE(sizeof(struct sockaddr_dl))]; | 3679 | uint8_t buf[CMSG_SPACE(sizeof(struct sockaddr_dl))]; | |
3627 | #else | 3680 | #else | |
3628 | uint8_t buf[CMSG_SPACE(sizeof(struct in_pktinfo))]; | 3681 | uint8_t buf[CMSG_SPACE(sizeof(struct in_pktinfo))]; | |
3629 | #endif | 3682 | #endif | |
3630 | } cmsgbuf = { .buf = { 0 } }; | 3683 | } cmsgbuf = { .buf = { 0 } }; | |
3631 | struct msghdr msg = { | 3684 | struct msghdr msg = { | |
3632 | .msg_name = &from, .msg_namelen = sizeof(from), | 3685 | .msg_name = &from, .msg_namelen = sizeof(from), | |
3633 | .msg_iov = &iov, .msg_iovlen = 1, | 3686 | .msg_iov = &iov, .msg_iovlen = 1, | |
3634 | .msg_control = cmsgbuf.buf, .msg_controllen = sizeof(cmsgbuf.buf), | 3687 | .msg_control = cmsgbuf.buf, .msg_controllen = sizeof(cmsgbuf.buf), | |
3635 | }; | 3688 | }; | |
3636 | int s; | 3689 | int s; | |
3637 | ssize_t bytes; | 3690 | ssize_t bytes; | |
3638 | 3691 | |||
3639 | if (ifp != NULL) { | 3692 | if (ifp != NULL) { | |
3640 | state = D_CSTATE(ifp); | 3693 | state = D_CSTATE(ifp); | |
3641 | s = state->udp_rfd; | 3694 | s = state->udp_rfd; | |
3642 | } else | 3695 | } else | |
3643 | s = ctx->udp_rfd; | 3696 | s = ctx->udp_rfd; | |
3644 | 3697 | |||
3645 | bytes = recvmsg(s, &msg, 0); | 3698 | bytes = recvmsg(s, &msg, 0); | |
3646 | if (bytes == -1) { | 3699 | if (bytes == -1) { | |
3647 | logerr(__func__); | 3700 | logerr(__func__); | |
3648 | return; | 3701 | return; | |
3649 | } | 3702 | } | |
3650 | 3703 | |||
3651 | iov.iov_len = (size_t)bytes; | 3704 | iov.iov_len = (size_t)bytes; | |
3652 | dhcp_recvmsg(ctx, &msg); | 3705 | dhcp_recvmsg(ctx, &msg); | |
3653 | } | 3706 | } | |
3654 | 3707 | |||
3655 | static void | 3708 | static void | |
3656 | dhcp_handleudp(void *arg) | 3709 | dhcp_handleudp(void *arg) | |
3657 | { | 3710 | { | |
3658 | struct dhcpcd_ctx *ctx = arg; | 3711 | struct dhcpcd_ctx *ctx = arg; | |
3659 | 3712 | |||
3660 | dhcp_readudp(ctx, NULL); | 3713 | dhcp_readudp(ctx, NULL); | |
3661 | } | 3714 | } | |
3662 | 3715 | |||
3663 | static void | 3716 | static void | |
3664 | dhcp_handleifudp(void *arg) | 3717 | dhcp_handleifudp(void *arg) | |
3665 | { | 3718 | { | |
3666 | struct interface *ifp = arg; | 3719 | struct interface *ifp = arg; | |
3667 | 3720 | |||
3668 | dhcp_readudp(ifp->ctx, ifp); | 3721 | dhcp_readudp(ifp->ctx, ifp); | |
3669 | } | 3722 | } | |
3670 | 3723 | |||
3671 | static int | 3724 | static int | |
3672 | dhcp_openbpf(struct interface *ifp) | 3725 | dhcp_openbpf(struct interface *ifp) | |
3673 | { | 3726 | { | |
3674 | struct dhcp_state *state; | 3727 | struct dhcp_state *state; | |
3675 | 3728 | |||
3676 | state = D_STATE(ifp); | 3729 | state = D_STATE(ifp); | |
3677 | 3730 | |||
3678 | #ifdef PRIVSEP | 3731 | #ifdef PRIVSEP | |
3679 | if (IN_PRIVSEP_SE(ifp->ctx)) { | 3732 | if (IN_PRIVSEP_SE(ifp->ctx)) { | |
3680 | if (ps_bpf_openbootp(ifp) == -1) { | 3733 | if (ps_bpf_openbootp(ifp) == -1) { | |
3681 | logerr(__func__); | 3734 | logerr(__func__); | |
3682 | return -1; | 3735 | return -1; | |
3683 | } | 3736 | } | |
3684 | return 0; | 3737 | return 0; | |
3685 | } | 3738 | } | |
3686 | #endif | 3739 | #endif | |
3687 | 3740 | |||
3688 | if (state->bpf != NULL) | 3741 | if (state->bpf != NULL) | |
3689 | return 0; | 3742 | return 0; | |
3690 | 3743 | |||
3691 | state->bpf = bpf_open(ifp, bpf_bootp, NULL); | 3744 | state->bpf = bpf_open(ifp, bpf_bootp, NULL); | |
3692 | if (state->bpf == NULL) { | 3745 | if (state->bpf == NULL) { | |
3693 | if (errno == ENOENT) { | 3746 | if (errno == ENOENT) { | |
3694 | logerrx("%s not found", bpf_name); | 3747 | logerrx("%s not found", bpf_name); | |
3695 | /* May as well disable IPv4 entirely at | 3748 | /* May as well disable IPv4 entirely at | |
3696 | * this point as we really need it. */ | 3749 | * this point as we really need it. */ | |
3697 | ifp->options->options &= ~DHCPCD_IPV4; | 3750 | ifp->options->options &= ~DHCPCD_IPV4; | |
3698 | } else | 3751 | } else | |
3699 | logerr("%s: %s", __func__, ifp->name); | 3752 | logerr("%s: %s", __func__, ifp->name); | |
3700 | return -1; | 3753 | return -1; | |
3701 | } | 3754 | } | |
3702 | 3755 | |||
3703 | eloop_event_add(ifp->ctx->eloop, | 3756 | eloop_event_add(ifp->ctx->eloop, | |
3704 | state->bpf->bpf_fd, dhcp_readbpf, ifp); | 3757 | state->bpf->bpf_fd, dhcp_readbpf, ifp); | |
3705 | return 0; | 3758 | return 0; | |
3706 | } | 3759 | } | |
3707 | 3760 | |||
3708 | void | 3761 | void | |
3709 | dhcp_free(struct interface *ifp) | 3762 | dhcp_free(struct interface *ifp) | |
3710 | { | 3763 | { | |
3711 | struct dhcp_state *state = D_STATE(ifp); | 3764 | struct dhcp_state *state = D_STATE(ifp); | |
3712 | struct dhcpcd_ctx *ctx; | 3765 | struct dhcpcd_ctx *ctx; | |
3713 | 3766 | |||
3714 | dhcp_close(ifp); | 3767 | dhcp_close(ifp); | |
3715 | #ifdef ARP | 3768 | #ifdef ARP | |
3716 | arp_drop(ifp); | 3769 | arp_drop(ifp); | |
3717 | #endif | 3770 | #endif | |
3718 | if (state) { | 3771 | if (state) { | |
3719 | state->state = DHS_NONE; | 3772 | state->state = DHS_NONE; | |
3720 | free(state->old); | 3773 | free(state->old); | |
3721 | free(state->new); | 3774 | free(state->new); | |
3722 | free(state->offer); | 3775 | free(state->offer); | |
3723 | free(state->clientid); | 3776 | free(state->clientid); | |
3724 | free(state); | 3777 | free(state); | |
3725 | } | 3778 | } | |
3726 | 3779 | |||
3727 | ctx = ifp->ctx; | 3780 | ctx = ifp->ctx; | |
3728 | /* If we don't have any more DHCP enabled interfaces, | 3781 | /* If we don't have any more DHCP enabled interfaces, | |
3729 | * close the global socket and release resources */ | 3782 | * close the global socket and release resources */ | |
3730 | if (ctx->ifaces) { | 3783 | if (ctx->ifaces) { | |
3731 | TAILQ_FOREACH(ifp, ctx->ifaces, next) { | 3784 | TAILQ_FOREACH(ifp, ctx->ifaces, next) { | |
3732 | state = D_STATE(ifp); | 3785 | state = D_STATE(ifp); | |
3733 | if (state != NULL && state->state != DHS_NONE) | 3786 | if (state != NULL && state->state != DHS_NONE) | |
3734 | break; | 3787 | break; | |
3735 | } | 3788 | } | |
3736 | } | 3789 | } | |
3737 | if (ifp == NULL) { | 3790 | if (ifp == NULL) { | |
3738 | if (ctx->udp_rfd != -1) { | 3791 | if (ctx->udp_rfd != -1) { | |
3739 | eloop_event_delete(ctx->eloop, ctx->udp_rfd); | 3792 | eloop_event_delete(ctx->eloop, ctx->udp_rfd); | |
3740 | close(ctx->udp_rfd); | 3793 | close(ctx->udp_rfd); | |
3741 | ctx->udp_rfd = -1; | 3794 | ctx->udp_rfd = -1; | |
3742 | } | 3795 | } | |
3743 | if (ctx->udp_wfd != -1) { | 3796 | if (ctx->udp_wfd != -1) { | |
3744 | close(ctx->udp_wfd); | 3797 | close(ctx->udp_wfd); | |
3745 | ctx->udp_wfd = -1; | 3798 | ctx->udp_wfd = -1; | |
3746 | } | 3799 | } | |
3747 | 3800 | |||
3748 | free(ctx->opt_buffer); | 3801 | free(ctx->opt_buffer); | |
3749 | ctx->opt_buffer = NULL; | 3802 | ctx->opt_buffer = NULL; | |
3750 | } | 3803 | } | |
3751 | } | 3804 | } | |
3752 | 3805 | |||
3753 | static int | 3806 | static int | |
3754 | dhcp_initstate(struct interface *ifp) | 3807 | dhcp_initstate(struct interface *ifp) | |
3755 | { | 3808 | { | |
3756 | struct dhcp_state *state; | 3809 | struct dhcp_state *state; | |
3757 | 3810 | |||
3758 | state = D_STATE(ifp); | 3811 | state = D_STATE(ifp); | |
3759 | if (state != NULL) | 3812 | if (state != NULL) | |
3760 | return 0; | 3813 | return 0; | |
3761 | 3814 | |||
3762 | ifp->if_data[IF_DATA_DHCP] = calloc(1, sizeof(*state)); | 3815 | ifp->if_data[IF_DATA_DHCP] = calloc(1, sizeof(*state)); | |
3763 | state = D_STATE(ifp); | 3816 | state = D_STATE(ifp); | |
3764 | if (state == NULL) | 3817 | if (state == NULL) | |
3765 | return -1; | 3818 | return -1; | |
3766 | 3819 | |||
3767 | state->state = DHS_NONE; | 3820 | state->state = DHS_NONE; | |
3768 | /* 0 is a valid fd, so init to -1 */ | 3821 | /* 0 is a valid fd, so init to -1 */ | |
3769 | state->udp_rfd = -1; | 3822 | state->udp_rfd = -1; | |
3770 | #ifdef ARPING | 3823 | #ifdef ARPING | |
3771 | state->arping_index = -1; | 3824 | state->arping_index = -1; | |
3772 | #endif | 3825 | #endif | |
3773 | return 1; | 3826 | return 1; | |
3774 | } | 3827 | } | |
3775 | 3828 | |||
3776 | static int | 3829 | static int | |
3777 | dhcp_init(struct interface *ifp) | 3830 | dhcp_init(struct interface *ifp) | |
3778 | { | 3831 | { | |
3779 | struct dhcp_state *state; | 3832 | struct dhcp_state *state; | |
3780 | struct if_options *ifo; | 3833 | struct if_options *ifo; | |
3781 | uint8_t len; | 3834 | uint8_t len; | |
3782 | char buf[(sizeof(ifo->clientid) - 1) * 3]; | 3835 | char buf[(sizeof(ifo->clientid) - 1) * 3]; | |
3783 | 3836 | |||
3784 | if (dhcp_initstate(ifp) == -1) | 3837 | if (dhcp_initstate(ifp) == -1) | |
3785 | return -1; | 3838 | return -1; | |
3786 | 3839 | |||
3787 | state = D_STATE(ifp); | 3840 | state = D_STATE(ifp); | |
3788 | state->state = DHS_INIT; | 3841 | state->state = DHS_INIT; | |
3789 | state->reason = "PREINIT"; | 3842 | state->reason = "PREINIT"; | |
3790 | state->nakoff = 0; | 3843 | state->nakoff = 0; | |
3791 | dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile), | 3844 | dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile), | |
3792 | AF_INET, ifp); | 3845 | AF_INET, ifp); | |
3793 | 3846 | |||
3794 | ifo = ifp->options; | 3847 | ifo = ifp->options; | |
3795 | /* We need to drop the leasefile so that dhcp_start | 3848 | /* We need to drop the leasefile so that dhcp_start | |
3796 | * doesn't load it. */ | 3849 | * doesn't load it. */ | |
3797 | if (ifo->options & DHCPCD_REQUEST) | 3850 | if (ifo->options & DHCPCD_REQUEST) | |
3798 | dhcp_unlink(ifp->ctx, state->leasefile); | 3851 | dhcp_unlink(ifp->ctx, state->leasefile); | |
3799 | 3852 | |||
3800 | free(state->clientid); | 3853 | free(state->clientid); | |
3801 | state->clientid = NULL; | 3854 | state->clientid = NULL; | |
3802 | 3855 | |||
3803 | if (ifo->options & DHCPCD_ANONYMOUS) { | 3856 | if (ifo->options & DHCPCD_ANONYMOUS) { | |
3804 | uint8_t duid[DUID_LEN]; | 3857 | uint8_t duid[DUID_LEN]; | |
3805 | uint8_t duid_len; | 3858 | uint8_t duid_len; | |
3806 | 3859 | |||
3807 | duid_len = (uint8_t)duid_make(duid, ifp, DUID_LL); | 3860 | duid_len = (uint8_t)duid_make(duid, ifp, DUID_LL); | |
3808 | if (duid_len != 0) { | 3861 | if (duid_len != 0) { | |
3809 | state->clientid = malloc((size_t)duid_len + 6); | 3862 | state->clientid = malloc((size_t)duid_len + 6); | |
3810 | if (state->clientid == NULL) | 3863 | if (state->clientid == NULL) | |
3811 | goto eexit; | 3864 | goto eexit; | |
3812 | state->clientid[0] =(uint8_t)(duid_len + 5); | 3865 | state->clientid[0] =(uint8_t)(duid_len + 5); | |
3813 | state->clientid[1] = 255; /* RFC 4361 */ | 3866 | state->clientid[1] = 255; /* RFC 4361 */ | |
3814 | memcpy(state->clientid + 2, ifo->iaid, 4); | 3867 | memcpy(state->clientid + 2, ifo->iaid, 4); | |
3815 | memset(state->clientid + 2, 0, 4); /* IAID */ | 3868 | memset(state->clientid + 2, 0, 4); /* IAID */ | |
3816 | memcpy(state->clientid + 6, duid, duid_len); | 3869 | memcpy(state->clientid + 6, duid, duid_len); | |
3817 | } | 3870 | } | |
3818 | } else if (*ifo->clientid) { | 3871 | } else if (*ifo->clientid) { | |
3819 | state->clientid = malloc((size_t)(ifo->clientid[0] + 1)); | 3872 | state->clientid = malloc((size_t)(ifo->clientid[0] + 1)); | |
3820 | if (state->clientid == NULL) | 3873 | if (state->clientid == NULL) | |
3821 | goto eexit; | 3874 | goto eexit; | |
3822 | memcpy(state->clientid, ifo->clientid, | 3875 | memcpy(state->clientid, ifo->clientid, | |
3823 | (size_t)(ifo->clientid[0]) + 1); | 3876 | (size_t)(ifo->clientid[0]) + 1); | |
3824 | } else if (ifo->options & DHCPCD_CLIENTID) { | 3877 | } else if (ifo->options & DHCPCD_CLIENTID) { | |
3825 | if (ifo->options & DHCPCD_DUID) { | 3878 | if (ifo->options & DHCPCD_DUID) { | |
3826 | state->clientid = malloc(ifp->ctx->duid_len + 6); | 3879 | state->clientid = malloc(ifp->ctx->duid_len + 6); | |
3827 | if (state->clientid == NULL) | 3880 | if (state->clientid == NULL) | |
3828 | goto eexit; | 3881 | goto eexit; | |
3829 | state->clientid[0] =(uint8_t)(ifp->ctx->duid_len + 5); | 3882 | state->clientid[0] =(uint8_t)(ifp->ctx->duid_len + 5); | |
3830 | state->clientid[1] = 255; /* RFC 4361 */ | 3883 | state->clientid[1] = 255; /* RFC 4361 */ | |
3831 | memcpy(state->clientid + 2, ifo->iaid, 4); | 3884 | memcpy(state->clientid + 2, ifo->iaid, 4); | |
3832 | memcpy(state->clientid + 6, ifp->ctx->duid, | 3885 | memcpy(state->clientid + 6, ifp->ctx->duid, | |
3833 | ifp->ctx->duid_len); | 3886 | ifp->ctx->duid_len); | |
3834 | } else { | 3887 | } else { | |
3835 | len = (uint8_t)(ifp->hwlen + 1); | 3888 | len = (uint8_t)(ifp->hwlen + 1); | |
3836 | state->clientid = malloc((size_t)len + 1); | 3889 | state->clientid = malloc((size_t)len + 1); | |
3837 | if (state->clientid == NULL) | 3890 | if (state->clientid == NULL) | |
3838 | goto eexit; | 3891 | goto eexit; | |
3839 | state->clientid[0] = len; | 3892 | state->clientid[0] = len; | |
3840 | state->clientid[1] = (uint8_t)ifp->hwtype; | 3893 | state->clientid[1] = (uint8_t)ifp->hwtype; | |
3841 | memcpy(state->clientid + 2, ifp->hwaddr, | 3894 | memcpy(state->clientid + 2, ifp->hwaddr, | |
3842 | ifp->hwlen); | 3895 | ifp->hwlen); | |
3843 | } | 3896 | } | |
3844 | } | 3897 | } | |
3845 | 3898 | |||
3846 | if (ifo->options & DHCPCD_DUID) | 3899 | if (ifo->options & DHCPCD_DUID) | |
3847 | /* Don't bother logging as DUID and IAID are reported | 3900 | /* Don't bother logging as DUID and IAID are reported | |
3848 | * at device start. */ | 3901 | * at device start. */ | |
3849 | return 0; | 3902 | return 0; | |
3850 | 3903 | |||
3851 | if (ifo->options & DHCPCD_CLIENTID && state->clientid != NULL) | 3904 | if (ifo->options & DHCPCD_CLIENTID && state->clientid != NULL) | |
3852 | logdebugx("%s: using ClientID %s", ifp->name, | 3905 | logdebugx("%s: using ClientID %s", ifp->name, | |
3853 | hwaddr_ntoa(state->clientid + 1, state->clientid[0], | 3906 | hwaddr_ntoa(state->clientid + 1, state->clientid[0], | |
3854 | buf, sizeof(buf))); | 3907 | buf, sizeof(buf))); | |
3855 | else if (ifp->hwlen) | 3908 | else if (ifp->hwlen) | |
3856 | logdebugx("%s: using hwaddr %s", ifp->name, | 3909 | logdebugx("%s: using hwaddr %s", ifp->name, | |
3857 | hwaddr_ntoa(ifp->hwaddr, ifp->hwlen, buf, sizeof(buf))); | 3910 | hwaddr_ntoa(ifp->hwaddr, ifp->hwlen, buf, sizeof(buf))); | |
3858 | return 0; | 3911 | return 0; | |
3859 | 3912 | |||
3860 | eexit: | 3913 | eexit: | |
3861 | logerr(__func__); | 3914 | logerr(__func__); | |
3862 | return -1; | 3915 | return -1; | |
3863 | } | 3916 | } | |
3864 | 3917 | |||
3865 | static void | 3918 | static void | |
3866 | dhcp_start1(void *arg) | 3919 | dhcp_start1(void *arg) | |
3867 | { | 3920 | { | |
3868 | struct interface *ifp = arg; | 3921 | struct interface *ifp = arg; | |
3869 | struct dhcpcd_ctx *ctx = ifp->ctx; | 3922 | struct dhcpcd_ctx *ctx = ifp->ctx; | |
3870 | struct if_options *ifo = ifp->options; | 3923 | struct if_options *ifo = ifp->options; | |
3871 | struct dhcp_state *state; | 3924 | struct dhcp_state *state; | |
3872 | uint32_t l; | 3925 | uint32_t l; | |
3873 | int nolease; | 3926 | int nolease; | |
3874 | 3927 | |||
3875 | if (!(ifo->options & DHCPCD_IPV4)) | 3928 | if (!(ifo->options & DHCPCD_IPV4)) | |
3876 | return; | 3929 | return; | |
3877 | 3930 | |||
3878 | /* Listen on *.*.*.*:bootpc so that the kernel never sends an | 3931 | /* Listen on *.*.*.*:bootpc so that the kernel never sends an | |
3879 | * ICMP port unreachable message back to the DHCP server. | 3932 | * ICMP port unreachable message back to the DHCP server. | |
3880 | * Only do this in master mode so we don't swallow messages | 3933 | * Only do this in master mode so we don't swallow messages | |
3881 | * for dhcpcd running on another interface. */ | 3934 | * for dhcpcd running on another interface. */ | |
3882 | if ((ctx->options & (DHCPCD_MASTER|DHCPCD_PRIVSEP)) == DHCPCD_MASTER | 3935 | if ((ctx->options & (DHCPCD_MASTER|DHCPCD_PRIVSEP)) == DHCPCD_MASTER | |
3883 | && ctx->udp_rfd == -1) | 3936 | && ctx->udp_rfd == -1) | |
3884 | { | 3937 | { | |
3885 | ctx->udp_rfd = dhcp_openudp(NULL); | 3938 | ctx->udp_rfd = dhcp_openudp(NULL); | |
3886 | if (ctx->udp_rfd == -1) { | 3939 | if (ctx->udp_rfd == -1) { | |
3887 | logerr(__func__); | 3940 | logerr(__func__); | |
3888 | return; | 3941 | return; | |
3889 | } | 3942 | } | |
3890 | eloop_event_add(ctx->eloop, ctx->udp_rfd, dhcp_handleudp, ctx); | 3943 | eloop_event_add(ctx->eloop, ctx->udp_rfd, dhcp_handleudp, ctx); | |
3891 | } | 3944 | } | |
3892 | if (!IN_PRIVSEP(ctx) && ctx->udp_wfd == -1) { | 3945 | if (!IN_PRIVSEP(ctx) && ctx->udp_wfd == -1) { | |
3893 | ctx->udp_wfd = xsocket(PF_INET, SOCK_RAW|SOCK_CXNB,IPPROTO_UDP); | 3946 | ctx->udp_wfd = xsocket(PF_INET, SOCK_RAW|SOCK_CXNB,IPPROTO_UDP); | |
3894 | if (ctx->udp_wfd == -1) { | 3947 | if (ctx->udp_wfd == -1) { | |
3895 | logerr(__func__); | 3948 | logerr(__func__); | |
3896 | return; | 3949 | return; | |
3897 | } | 3950 | } | |
3898 | } | 3951 | } | |
3899 | 3952 | |||
3900 | if (dhcp_init(ifp) == -1) { | 3953 | if (dhcp_init(ifp) == -1) { | |
3901 | logerr("%s: dhcp_init", ifp->name); | 3954 | logerr("%s: dhcp_init", ifp->name); | |
3902 | return; | 3955 | return; | |
3903 | } | 3956 | } | |
3904 | 3957 | |||
3905 | state = D_STATE(ifp); | 3958 | state = D_STATE(ifp); | |
3906 | clock_gettime(CLOCK_MONOTONIC, &state->started); | 3959 | clock_gettime(CLOCK_MONOTONIC, &state->started); | |
3907 | state->interval = 0; | 3960 | state->interval = 0; | |
3908 | free(state->offer); | 3961 | free(state->offer); | |
3909 | state->offer = NULL; | 3962 | state->offer = NULL; | |
3910 | state->offer_len = 0; | 3963 | state->offer_len = 0; | |
3911 | 3964 | |||
3912 | #ifdef ARPING | 3965 | #ifdef ARPING | |
3913 | if (ifo->arping_len && state->arping_index < ifo->arping_len) { | 3966 | if (ifo->arping_len && state->arping_index < ifo->arping_len) { | |
3914 | dhcp_arping(ifp); | 3967 | dhcp_arping(ifp); | |
3915 | return; | 3968 | return; | |
3916 | } | 3969 | } | |
3917 | #endif | 3970 | #endif | |
3918 | 3971 | |||
3919 | if (ifo->options & DHCPCD_STATIC) { | 3972 | if (ifo->options & DHCPCD_STATIC) { | |
3920 | dhcp_static(ifp); | 3973 | dhcp_static(ifp); | |
3921 | return; | 3974 | return; | |
3922 | } | 3975 | } | |
3923 | 3976 | |||
3924 | if (ifo->options & DHCPCD_INFORM) { | 3977 | if (ifo->options & DHCPCD_INFORM) { | |
3925 | dhcp_inform(ifp); | 3978 | dhcp_inform(ifp); | |
3926 | return; | 3979 | return; | |
3927 | } | 3980 | } | |
3928 | 3981 | |||
3929 | /* We don't want to read the old lease if we NAK an old test */ | 3982 | /* We don't want to read the old lease if we NAK an old test */ | |
3930 | nolease = state->offer && ifp->ctx->options & DHCPCD_TEST; | 3983 | nolease = state->offer && ifp->ctx->options & DHCPCD_TEST; | |
3931 | if (!nolease && ifo->options & DHCPCD_DHCP) { | 3984 | if (!nolease && ifo->options & DHCPCD_DHCP) { | |
3932 | state->offer_len = read_lease(ifp, &state->offer); | 3985 | state->offer_len = read_lease(ifp, &state->offer); | |
3933 | /* Check the saved lease matches the type we want */ | 3986 | /* Check the saved lease matches the type we want */ | |
3934 | if (state->offer) { | 3987 | if (state->offer) { | |
3935 | #ifdef IN_IFF_DUPLICATED | 3988 | #ifdef IN_IFF_DUPLICATED | |
3936 | struct in_addr addr; | 3989 | struct in_addr addr; | |
3937 | struct ipv4_addr *ia; | 3990 | struct ipv4_addr *ia; | |
3938 | 3991 | |||
3939 | addr.s_addr = state->offer->yiaddr; | 3992 | addr.s_addr = state->offer->yiaddr; | |
3940 | ia = ipv4_iffindaddr(ifp, &addr, NULL); | 3993 | ia = ipv4_iffindaddr(ifp, &addr, NULL); | |
3941 | #endif | 3994 | #endif | |
3942 | 3995 | |||
3943 | if ((!IS_DHCP(state->offer) && | 3996 | if ((!IS_DHCP(state->offer) && | |
3944 | !(ifo->options & DHCPCD_BOOTP)) || | 3997 | !(ifo->options & DHCPCD_BOOTP)) || | |
3945 | #ifdef IN_IFF_DUPLICATED | 3998 | #ifdef IN_IFF_DUPLICATED | |
3946 | (ia && ia->addr_flags & IN_IFF_DUPLICATED) || | 3999 | (ia && ia->addr_flags & IN_IFF_DUPLICATED) || | |
3947 | #endif | 4000 | #endif | |
3948 | (IS_DHCP(state->offer) && | 4001 | (IS_DHCP(state->offer) && | |
3949 | ifo->options & DHCPCD_BOOTP)) | 4002 | ifo->options & DHCPCD_BOOTP)) | |
3950 | { | 4003 | { | |
3951 | free(state->offer); | 4004 | free(state->offer); | |
3952 | state->offer = NULL; | 4005 | state->offer = NULL; | |
3953 | state->offer_len = 0; | 4006 | state->offer_len = 0; | |
3954 | } | 4007 | } | |
3955 | } | 4008 | } | |
3956 | } | 4009 | } | |
3957 | if (state->offer) { | 4010 | if (state->offer) { | |
3958 | struct ipv4_addr *ia; | 4011 | struct ipv4_addr *ia; | |
3959 | time_t mtime; | 4012 | time_t mtime; | |
3960 | 4013 | |||
3961 | get_lease(ifp, &state->lease, state->offer, state->offer_len); | 4014 | get_lease(ifp, &state->lease, state->offer, state->offer_len); | |
3962 | state->lease.frominfo = 1; | 4015 | state->lease.frominfo = 1; | |
3963 | if (state->new == NULL && | 4016 | if (state->new == NULL && | |
3964 | (ia = ipv4_iffindaddr(ifp, | 4017 | (ia = ipv4_iffindaddr(ifp, | |
3965 | &state->lease.addr, &state->lease.mask)) != NULL) | 4018 | &state->lease.addr, &state->lease.mask)) != NULL) | |
3966 | { | 4019 | { | |
3967 | /* We still have the IP address from the last lease. | 4020 | /* We still have the IP address from the last lease. | |
3968 | * Fake add the address and routes from it so the lease | 4021 | * Fake add the address and routes from it so the lease | |
3969 | * can be cleaned up. */ | 4022 | * can be cleaned up. */ | |
3970 | state->new = malloc(state->offer_len); | 4023 | state->new = malloc(state->offer_len); | |
3971 | if (state->new) { | 4024 | if (state->new) { | |
3972 | memcpy(state->new, | 4025 | memcpy(state->new, | |
3973 | state->offer, state->offer_len); | 4026 | state->offer, state->offer_len); | |
3974 | state->new_len = state->offer_len; | 4027 | state->new_len = state->offer_len; | |
3975 | state->addr = ia; | 4028 | state->addr = ia; | |
3976 | state->added |= STATE_ADDED | STATE_FAKE; | 4029 | state->added |= STATE_ADDED | STATE_FAKE; | |
3977 | rt_build(ifp->ctx, AF_INET); | 4030 | rt_build(ifp->ctx, AF_INET); | |
3978 | } else | 4031 | } else | |
3979 | logerr(__func__); | 4032 | logerr(__func__); | |
3980 | } | 4033 | } | |
3981 | if (!IS_DHCP(state->offer)) { | 4034 | if (!IS_DHCP(state->offer)) { | |
3982 | free(state->offer); | 4035 | free(state->offer); | |
3983 | state->offer = NULL; | 4036 | state->offer = NULL; | |
3984 | state->offer_len = 0; | 4037 | state->offer_len = 0; | |
3985 | } else if (!(ifo->options & DHCPCD_LASTLEASE_EXTEND) && | 4038 | } else if (!(ifo->options & DHCPCD_LASTLEASE_EXTEND) && | |
3986 | state->lease.leasetime != DHCP_INFINITE_LIFETIME && | 4039 | state->lease.leasetime != DHCP_INFINITE_LIFETIME && | |
3987 | dhcp_filemtime(ifp->ctx, state->leasefile, &mtime) == 0) | 4040 | dhcp_filemtime(ifp->ctx, state->leasefile, &mtime) == 0) | |
3988 | { | 4041 | { | |
3989 | time_t now; | 4042 | time_t now; | |
3990 | 4043 | |||
3991 | /* Offset lease times and check expiry */ | 4044 | /* Offset lease times and check expiry */ | |
3992 | now = time(NULL); | 4045 | now = time(NULL); | |
3993 | if (now == -1 || | 4046 | if (now == -1 || | |
3994 | (time_t)state->lease.leasetime < now - mtime) | 4047 | (time_t)state->lease.leasetime < now - mtime) | |
3995 | { | 4048 | { | |
3996 | logdebugx("%s: discarding expired lease", | 4049 | logdebugx("%s: discarding expired lease", | |
3997 | ifp->name); | 4050 | ifp->name); | |
3998 | free(state->offer); | 4051 | free(state->offer); | |
3999 | state->offer = NULL; | 4052 | state->offer = NULL; | |
4000 | state->offer_len = 0; | 4053 | state->offer_len = 0; | |
4001 | state->lease.addr.s_addr = 0; | 4054 | state->lease.addr.s_addr = 0; | |
4002 | /* Technically we should discard the lease | 4055 | /* Technically we should discard the lease | |
4003 | * as it's expired, just as DHCPv6 addresses | 4056 | * as it's expired, just as DHCPv6 addresses | |
4004 | * would be by the kernel. | 4057 | * would be by the kernel. | |
4005 | * However, this may violate POLA so | 4058 | * However, this may violate POLA so | |
4006 | * we currently leave it be. | 4059 | * we currently leave it be. | |
4007 | * If we get a totally different lease from | 4060 | * If we get a totally different lease from | |
4008 | * the DHCP server we'll drop it anyway, as | 4061 | * the DHCP server we'll drop it anyway, as | |
4009 | * we will on any other event which would | 4062 | * we will on any other event which would | |
4010 | * trigger a lease drop. | 4063 | * trigger a lease drop. | |
4011 | * This should only happen if dhcpcd stops | 4064 | * This should only happen if dhcpcd stops | |
4012 | * running and the lease expires before | 4065 | * running and the lease expires before | |
4013 | * dhcpcd starts again. */ | 4066 | * dhcpcd starts again. */ | |
4014 | #if 0 | 4067 | #if 0 | |
4015 | if (state->new) | 4068 | if (state->new) | |
4016 | dhcp_drop(ifp, "EXPIRE"); | 4069 | dhcp_drop(ifp, "EXPIRE"); | |
4017 | #endif | 4070 | #endif | |
4018 | } else { | 4071 | } else { | |
4019 | l = (uint32_t)(now - mtime); | 4072 | l = (uint32_t)(now - mtime); | |
4020 | state->lease.leasetime -= l; | 4073 | state->lease.leasetime -= l; | |
4021 | state->lease.renewaltime -= l; | 4074 | state->lease.renewaltime -= l; | |
4022 | state->lease.rebindtime -= l; | 4075 | state->lease.rebindtime -= l; | |
4023 | } | 4076 | } | |
4024 | } | 4077 | } | |
4025 | } | 4078 | } | |
4026 | 4079 | |||
4027 | #ifdef IPV4LL | 4080 | #ifdef IPV4LL | |
4028 | if (!(ifo->options & DHCPCD_DHCP)) { | 4081 | if (!(ifo->options & DHCPCD_DHCP)) { | |
4029 | if (ifo->options & DHCPCD_IPV4LL) | 4082 | if (ifo->options & DHCPCD_IPV4LL) | |
4030 | ipv4ll_start(ifp); | 4083 | ipv4ll_start(ifp); | |
4031 | return; | 4084 | return; | |
4032 | } | 4085 | } | |
4033 | #endif | 4086 | #endif | |
4034 | 4087 | |||
4035 | if (state->offer == NULL || | 4088 | if (state->offer == NULL || | |
4036 | !IS_DHCP(state->offer) || | 4089 | !IS_DHCP(state->offer) || | |
4037 | ifo->options & DHCPCD_ANONYMOUS) | 4090 | ifo->options & DHCPCD_ANONYMOUS) | |
4038 | dhcp_discover(ifp); | 4091 | dhcp_discover(ifp); | |
4039 | else | 4092 | else | |
4040 | dhcp_reboot(ifp); | 4093 | dhcp_reboot(ifp); | |
4041 | } | 4094 | } | |
4042 | 4095 | |||
4043 | void | 4096 | void | |
4044 | dhcp_start(struct interface *ifp) | 4097 | dhcp_start(struct interface *ifp) | |
4045 | { | 4098 | { | |
4046 | unsigned int delay; | 4099 | unsigned int delay; | |
4047 | #ifdef ARPING | 4100 | #ifdef ARPING | |
4048 | const struct dhcp_state *state; | 4101 | const struct dhcp_state *state; | |
4049 | #endif | 4102 | #endif | |
4050 | 4103 | |||
4051 | if (!(ifp->options->options & DHCPCD_IPV4)) | 4104 | if (!(ifp->options->options & DHCPCD_IPV4)) | |
4052 | return; | 4105 | return; | |
4053 | 4106 | |||
4054 | /* If we haven't been given a netmask for our requested address, | 4107 | /* If we haven't been given a netmask for our requested address, | |
4055 | * set it now. */ | 4108 | * set it now. */ | |
4056 | if (ifp->options->req_addr.s_addr != INADDR_ANY && | 4109 | if (ifp->options->req_addr.s_addr != INADDR_ANY && | |
4057 | ifp->options->req_mask.s_addr == INADDR_ANY) | 4110 | ifp->options->req_mask.s_addr == INADDR_ANY) | |
4058 | ifp->options->req_mask.s_addr = | 4111 | ifp->options->req_mask.s_addr = | |
4059 | ipv4_getnetmask(ifp->options->req_addr.s_addr); | 4112 | ipv4_getnetmask(ifp->options->req_addr.s_addr); | |
4060 | 4113 | |||
4061 | /* If we haven't specified a ClientID and our hardware address | 4114 | /* If we haven't specified a ClientID and our hardware address | |
4062 | * length is greater than BOOTP CHADDR then we enforce a ClientID | 4115 | * length is greater than BOOTP CHADDR then we enforce a ClientID | |
4063 | * of the hardware address type and the hardware address. | 4116 | * of the hardware address type and the hardware address. | |
4064 | * If there is no hardware address and no ClientID set, | 4117 | * If there is no hardware address and no ClientID set, | |
4065 | * force a DUID based ClientID. */ | 4118 | * force a DUID based ClientID. */ | |
4066 | if (ifp->hwlen > 16) | 4119 | if (ifp->hwlen > 16) | |
4067 | ifp->options->options |= DHCPCD_CLIENTID; | 4120 | ifp->options->options |= DHCPCD_CLIENTID; | |
4068 | else if (ifp->hwlen == 0 && !(ifp->options->options & DHCPCD_CLIENTID)) | 4121 | else if (ifp->hwlen == 0 && !(ifp->options->options & DHCPCD_CLIENTID)) | |
4069 | ifp->options->options |= DHCPCD_CLIENTID | DHCPCD_DUID; | 4122 | ifp->options->options |= DHCPCD_CLIENTID | DHCPCD_DUID; | |
4070 | 4123 | |||
4071 | /* Firewire and InfiniBand interfaces require ClientID and | 4124 | /* Firewire and InfiniBand interfaces require ClientID and | |
4072 | * the broadcast option being set. */ | 4125 | * the broadcast option being set. */ | |
4073 | switch (ifp->hwtype) { | 4126 | switch (ifp->hwtype) { | |
4074 | case ARPHRD_IEEE1394: /* FALLTHROUGH */ | 4127 | case ARPHRD_IEEE1394: /* FALLTHROUGH */ | |
4075 | case ARPHRD_INFINIBAND: | 4128 | case ARPHRD_INFINIBAND: | |
4076 | ifp->options->options |= DHCPCD_CLIENTID | DHCPCD_BROADCAST; | 4129 | ifp->options->options |= DHCPCD_CLIENTID | DHCPCD_BROADCAST; | |
4077 | break; | 4130 | break; | |
4078 | } | 4131 | } | |
4079 | 4132 | |||
4080 | /* If we violate RFC2131 section 3.7 then require ARP | 4133 | /* If we violate RFC2131 section 3.7 then require ARP | |
4081 | * to detect if any other client wants our address. */ | 4134 | * to detect if any other client wants our address. */ | |
4082 | if (ifp->options->options & DHCPCD_LASTLEASE_EXTEND) | 4135 | if (ifp->options->options & DHCPCD_LASTLEASE_EXTEND) | |
4083 | ifp->options->options |= DHCPCD_ARP; | 4136 | ifp->options->options |= DHCPCD_ARP; | |
4084 | 4137 | |||
4085 | /* No point in delaying a static configuration */ | 4138 | /* No point in delaying a static configuration */ | |
4086 | if (ifp->options->options & DHCPCD_STATIC || | 4139 | if (ifp->options->options & DHCPCD_STATIC || | |
4087 | !(ifp->options->options & DHCPCD_INITIAL_DELAY)) | 4140 | !(ifp->options->options & DHCPCD_INITIAL_DELAY)) | |
4088 | { | 4141 | { | |
4089 | dhcp_start1(ifp); | 4142 | dhcp_start1(ifp); | |
4090 | return; | 4143 | return; | |
4091 | } | 4144 | } | |
4092 | 4145 | |||
4093 | #ifdef ARPING | 4146 | #ifdef ARPING | |
4094 | /* If we have arpinged then we have already delayed. */ | 4147 | /* If we have arpinged then we have already delayed. */ | |
4095 | state = D_CSTATE(ifp); | 4148 | state = D_CSTATE(ifp); | |
4096 | if (state != NULL && state->arping_index != -1) { | 4149 | if (state != NULL && state->arping_index != -1) { | |
4097 | dhcp_start1(ifp); | 4150 | dhcp_start1(ifp); | |
4098 | return; | 4151 | return; | |
4099 | } | 4152 | } | |
4100 | #endif | 4153 | #endif | |
4101 | delay = MSEC_PER_SEC + | 4154 | delay = MSEC_PER_SEC + | |
4102 | (arc4random_uniform(MSEC_PER_SEC * 2) - MSEC_PER_SEC); | 4155 | (arc4random_uniform(MSEC_PER_SEC * 2) - MSEC_PER_SEC); | |
4103 | logdebugx("%s: delaying IPv4 for %0.1f seconds", | 4156 | logdebugx("%s: delaying IPv4 for %0.1f seconds", | |
4104 | ifp->name, (float)delay / MSEC_PER_SEC); | 4157 | ifp->name, (float)delay / MSEC_PER_SEC); | |
4105 | 4158 | |||
4106 | eloop_timeout_add_msec(ifp->ctx->eloop, delay, dhcp_start1, ifp); | 4159 | eloop_timeout_add_msec(ifp->ctx->eloop, delay, dhcp_start1, ifp); | |
4107 | } | 4160 | } | |
4108 | 4161 | |||
4109 | void | 4162 | void | |
4110 | dhcp_abort(struct interface *ifp) | 4163 | dhcp_abort(struct interface *ifp) | |
4111 | { | 4164 | { | |
4112 | struct dhcp_state *state; | 4165 | struct dhcp_state *state; | |
4113 | 4166 | |||
4114 | state = D_STATE(ifp); | 4167 | state = D_STATE(ifp); | |
4115 | #ifdef ARPING | 4168 | #ifdef ARPING | |
4116 | if (state != NULL) | 4169 | if (state != NULL) | |
4117 | state->arping_index = -1; | 4170 | state->arping_index = -1; | |
4118 | #endif | 4171 | #endif | |
4119 | 4172 | |||
4120 | eloop_timeout_delete(ifp->ctx->eloop, dhcp_start1, ifp); | 4173 | eloop_timeout_delete(ifp->ctx->eloop, dhcp_start1, ifp); | |
4121 | 4174 | |||
4122 | if (state != NULL && state->added) { | 4175 | if (state != NULL && state->added) { | |
4123 | rt_build(ifp->ctx, AF_INET); | 4176 | rt_build(ifp->ctx, AF_INET); | |
4124 | #ifdef ARP | 4177 | #ifdef ARP | |
4125 | if (ifp->options->options & DHCPCD_ARP) | 4178 | if (ifp->options->options & DHCPCD_ARP) | |
4126 | arp_announceaddr(ifp->ctx, &state->addr->addr); | 4179 | arp_announceaddr(ifp->ctx, &state->addr->addr); | |
4127 | #endif | 4180 | #endif | |
4128 | } | 4181 | } | |
4129 | } | 4182 | } | |
4130 | 4183 | |||
4131 | struct ipv4_addr * | 4184 | struct ipv4_addr * | |
4132 | dhcp_handleifa(int cmd, struct ipv4_addr *ia, pid_t pid) | 4185 | dhcp_handleifa(int cmd, struct ipv4_addr *ia, pid_t pid) | |
4133 | { | 4186 | { | |
4134 | struct interface *ifp; | 4187 | struct interface *ifp; | |
4135 | struct dhcp_state *state; | 4188 | struct dhcp_state *state; | |
4136 | struct if_options *ifo; | 4189 | struct if_options *ifo; | |
4137 | uint8_t i; | 4190 | uint8_t i; | |
4138 | 4191 | |||
4139 | ifp = ia->iface; | 4192 | ifp = ia->iface; | |
4140 | state = D_STATE(ifp); | 4193 | state = D_STATE(ifp); | |
4141 | if (state == NULL || state->state == DHS_NONE) | 4194 | if (state == NULL || state->state == DHS_NONE) | |
4142 | return ia; | 4195 | return ia; | |
4143 | 4196 | |||
4144 | if (cmd == RTM_DELADDR) { | 4197 | if (cmd == RTM_DELADDR) { | |
4145 | if (state->addr == ia) { | 4198 | if (state->addr == ia) { | |
4146 | loginfox("%s: pid %d deleted IP address %s", | 4199 | loginfox("%s: pid %d deleted IP address %s", | |
4147 | ifp->name, pid, ia->saddr); | 4200 | ifp->name, pid, ia->saddr); | |
4148 | dhcp_close(ifp); | 4201 | dhcp_close(ifp); | |
4149 | state->addr = NULL; | 4202 | state->addr = NULL; | |
4150 | /* Don't clear the added state as we need | 4203 | /* Don't clear the added state as we need | |
4151 | * to drop the lease. */ | 4204 | * to drop the lease. */ | |
4152 | dhcp_drop(ifp, "EXPIRE"); | 4205 | dhcp_drop(ifp, "EXPIRE"); | |
4153 | dhcp_start1(ifp); | 4206 | dhcp_start1(ifp); | |
4154 | return ia; | 4207 | return ia; | |
4155 | } | 4208 | } | |
4156 | } | 4209 | } | |
4157 | 4210 | |||
4158 | if (cmd != RTM_NEWADDR) | 4211 | if (cmd != RTM_NEWADDR) | |
4159 | return ia; | 4212 | return ia; | |
4160 | 4213 | |||
4161 | #ifdef IN_IFF_NOTUSEABLE | 4214 | #ifdef IN_IFF_NOTUSEABLE | |
4162 | if (!(ia->addr_flags & IN_IFF_NOTUSEABLE)) | 4215 | if (!(ia->addr_flags & IN_IFF_NOTUSEABLE)) | |
4163 | dhcp_finish_dad(ifp, &ia->addr); | 4216 | dhcp_finish_dad(ifp, &ia->addr); | |
4164 | else if (ia->addr_flags & IN_IFF_DUPLICATED) | 4217 | else if (ia->addr_flags & IN_IFF_DUPLICATED) | |
4165 | return dhcp_addr_duplicated(ifp, &ia->addr) ? NULL : ia; | 4218 | return dhcp_addr_duplicated(ifp, &ia->addr) ? NULL : ia; | |
4166 | #endif | 4219 | #endif | |
4167 | 4220 | |||
4168 | ifo = ifp->options; | 4221 | ifo = ifp->options; | |
4169 | if (ifo->options & DHCPCD_INFORM) { | 4222 | if (ifo->options & DHCPCD_INFORM) { | |
4170 | if (state->state != DHS_INFORM) | 4223 | if (state->state != DHS_INFORM) | |
4171 | dhcp_inform(ifp); | 4224 | dhcp_inform(ifp); | |
4172 | return ia; | 4225 | return ia; | |
4173 | } | 4226 | } | |
4174 | 4227 | |||
4175 | if (!(ifo->options & DHCPCD_STATIC)) | 4228 | if (!(ifo->options & DHCPCD_STATIC)) | |
4176 | return ia; | 4229 | return ia; | |
4177 | if (ifo->req_addr.s_addr != INADDR_ANY) | 4230 | if (ifo->req_addr.s_addr != INADDR_ANY) | |
4178 | return ia; | 4231 | return ia; | |
4179 | 4232 | |||
4180 | free(state->old); | 4233 | free(state->old); | |
4181 | state->old = state->new; | 4234 | state->old = state->new; | |
4182 | state->new_len = dhcp_message_new(&state->new, &ia->addr, &ia->mask); | 4235 | state->new_len = dhcp_message_new(&state->new, &ia->addr, &ia->mask); | |
4183 | if (state->new == NULL) | 4236 | if (state->new == NULL) | |
4184 | return ia; | 4237 | return ia; |
--- src/external/bsd/dhcpcd/dist/src/Attic/dhcpcd.8.in 2020/09/06 14:55:34 1.8
+++ src/external/bsd/dhcpcd/dist/src/Attic/dhcpcd.8.in 2020/11/01 14:24:01 1.9
@@ -1,858 +1,850 @@ | @@ -1,858 +1,850 @@ | |||
1 | .\" SPDX-License-Identifier: BSD-2-Clause | 1 | .\" SPDX-License-Identifier: BSD-2-Clause | |
2 | .\" | 2 | .\" | |
3 | .\" Copyright (c) 2006-2020 Roy Marples | 3 | .\" Copyright (c) 2006-2020 Roy Marples | |
4 | .\" All rights reserved | 4 | .\" All rights reserved | |
5 | .\" | 5 | .\" | |
6 | .\" Redistribution and use in source and binary forms, with or without | 6 | .\" Redistribution and use in source and binary forms, with or without | |
7 | .\" modification, are permitted provided that the following conditions | 7 | .\" modification, are permitted provided that the following conditions | |
8 | .\" are met: | 8 | .\" are met: | |
9 | .\" 1. Redistributions of source code must retain the above copyright | 9 | .\" 1. Redistributions of source code must retain the above copyright | |
10 | .\" notice, this list of conditions and the following disclaimer. | 10 | .\" notice, this list of conditions and the following disclaimer. | |
11 | .\" 2. Redistributions in binary form must reproduce the above copyright | 11 | .\" 2. Redistributions in binary form must reproduce the above copyright | |
12 | .\" notice, this list of conditions and the following disclaimer in the | 12 | .\" notice, this list of conditions and the following disclaimer in the | |
13 | .\" documentation and/or other materials provided with the distribution. | 13 | .\" documentation and/or other materials provided with the distribution. | |
14 | .\" | 14 | .\" | |
15 | .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | 15 | .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
16 | .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 16 | .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
17 | .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 17 | .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
18 | .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | 18 | .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
19 | .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 19 | .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
20 | .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 20 | .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
21 | .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 21 | .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
22 | .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 22 | .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
23 | .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 23 | .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
24 | .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 24 | .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
25 | .\" SUCH DAMAGE. | 25 | .\" SUCH DAMAGE. | |
26 | .\" | 26 | .\" | |
27 | .Dd September 2, 2020 | 27 | .Dd October 30, 2020 | |
28 | .Dt DHCPCD 8 | 28 | .Dt DHCPCD 8 | |
29 | .Os | 29 | .Os | |
30 | .Sh NAME | 30 | .Sh NAME | |
31 | .Nm dhcpcd | 31 | .Nm dhcpcd | |
32 | .Nd a DHCP client | 32 | .Nd a DHCP client | |
33 | .Sh SYNOPSIS | 33 | .Sh SYNOPSIS | |
34 | .Nm | 34 | .Nm | |
35 | .Op Fl 146ABbDdEGgHJKLMNPpqTV | 35 | .Op Fl 146ABbDdEGgHJKLMNPpqTV | |
36 | .Op Fl C , Fl Fl nohook Ar hook | 36 | .Op Fl C , Fl Fl nohook Ar hook | |
37 | .Op Fl c , Fl Fl script Ar script | 37 | .Op Fl c , Fl Fl script Ar script | |
38 | .Op Fl e , Fl Fl env Ar value | 38 | .Op Fl e , Fl Fl env Ar value | |
39 | .Op Fl F , Fl Fl fqdn Ar FQDN | 39 | .Op Fl F , Fl Fl fqdn Ar FQDN | |
40 | .Op Fl f , Fl Fl config Ar file | 40 | .Op Fl f , Fl Fl config Ar file | |
41 | .Op Fl h , Fl Fl hostname Ar hostname | 41 | .Op Fl h , Fl Fl hostname Ar hostname | |
42 | .Op Fl I , Fl Fl clientid Ar clientid | 42 | .Op Fl I , Fl Fl clientid Ar clientid | |
43 | .Op Fl i , Fl Fl vendorclassid Ar vendorclassid | 43 | .Op Fl i , Fl Fl vendorclassid Ar vendorclassid | |
44 | .Op Fl j , Fl Fl logfile Ar logfile | 44 | .Op Fl j , Fl Fl logfile Ar logfile | |
45 | .Op Fl l , Fl Fl leasetime Ar seconds | 45 | .Op Fl l , Fl Fl leasetime Ar seconds | |
46 | .Op Fl m , Fl Fl metric Ar metric | 46 | .Op Fl m , Fl Fl metric Ar metric | |
47 | .Op Fl O , Fl Fl nooption Ar option | 47 | .Op Fl O , Fl Fl nooption Ar option | |
48 | .Op Fl o , Fl Fl option Ar option | 48 | .Op Fl o , Fl Fl option Ar option | |
49 | .Op Fl Q , Fl Fl require Ar option | 49 | .Op Fl Q , Fl Fl require Ar option | |
50 | .Op Fl r , Fl Fl request Ar address | 50 | .Op Fl r , Fl Fl request Ar address | |
51 | .Op Fl S , Fl Fl static Ar value | 51 | .Op Fl S , Fl Fl static Ar value | |
52 | .Op Fl s , Fl Fl inform Ar address Ns Op Ar /cidr Ns Op Ar /broadcast_address | 52 | .Op Fl s , Fl Fl inform Ar address Ns Op Ar /cidr Ns Op Ar /broadcast_address | |
53 | .Op Fl Fl inform6 | 53 | .Op Fl Fl inform6 | |
54 | .Op Fl t , Fl Fl timeout Ar seconds | 54 | .Op Fl t , Fl Fl timeout Ar seconds | |
55 | .Op Fl u , Fl Fl userclass Ar class | 55 | .Op Fl u , Fl Fl userclass Ar class | |
56 | .Op Fl v , Fl Fl vendor Ar code , Ar value | 56 | .Op Fl v , Fl Fl vendor Ar code , Ar value | |
57 | .Op Fl W , Fl Fl whitelist Ar address Ns Op Ar /cidr | 57 | .Op Fl W , Fl Fl whitelist Ar address Ns Op Ar /cidr | |
58 | .Op Fl w | 58 | .Op Fl w | |
59 | .Op Fl Fl waitip Ns = Ns Op 4 | 6 | 59 | .Op Fl Fl waitip Ns = Ns Op 4 | 6 | |
60 | .Op Fl y , Fl Fl reboot Ar seconds | 60 | .Op Fl y , Fl Fl reboot Ar seconds | |
61 | .Op Fl X , Fl Fl blacklist Ar address Ns Op Ar /cidr | 61 | .Op Fl X , Fl Fl blacklist Ar address Ns Op Ar /cidr | |
62 | .Op Fl Z , Fl Fl denyinterfaces Ar pattern | 62 | .Op Fl Z , Fl Fl denyinterfaces Ar pattern | |
63 | .Op Fl z , Fl Fl allowinterfaces Ar pattern | 63 | .Op Fl z , Fl Fl allowinterfaces Ar pattern | |
64 | .Op Fl Fl inactive | 64 | .Op Fl Fl inactive | |
65 | .Op interface | 65 | .Op interface | |
66 | .Op ... | 66 | .Op ... | |
67 | .Nm | 67 | .Nm | |
68 | .Fl n , Fl Fl rebind | 68 | .Fl n , Fl Fl rebind | |
69 | .Op interface | 69 | .Op interface | |
70 | .Nm | 70 | .Nm | |
71 | .Fl k , Fl Fl release | 71 | .Fl k , Fl Fl release | |
72 | .Op interface | 72 | .Op interface | |
73 | .Nm | 73 | .Nm | |
74 | .Fl U , Fl Fl dumplease | 74 | .Fl U , Fl Fl dumplease | |
75 | .Op Ar interface | 75 | .Op Ar interface | |
76 | .Nm | 76 | .Nm | |
77 | .Fl Fl version | 77 | .Fl Fl version | |
78 | .Nm | 78 | .Nm | |
79 | .Fl x , Fl Fl exit | 79 | .Fl x , Fl Fl exit | |
80 | .Op interface | 80 | .Op interface | |
81 | .Sh DESCRIPTION | 81 | .Sh DESCRIPTION | |
82 | .Nm | 82 | .Nm | |
83 | is an implementation of the DHCP client specified in | 83 | is an implementation of the DHCP client specified in | |
84 | .Li RFC 2131 . | 84 | .Li RFC 2131 . | |
85 | .Nm | 85 | .Nm | |
86 | gets the host information | 86 | gets the host information | |
87 | .Po | 87 | .Po | |
88 | IP address, routes, etc | 88 | IP address, routes, etc | |
89 | .Pc | 89 | .Pc | |
90 | from a DHCP server and configures the network | 90 | from a DHCP server and configures the network | |
91 | .Ar interface | 91 | .Ar interface | |
92 | of the | 92 | of the | |
93 | machine on which it is running. | 93 | machine on which it is running. | |
94 | .Nm | 94 | .Nm | |
95 | then runs the configuration script which writes DNS information to | 95 | then runs the configuration script which writes DNS information to | |
96 | .Xr resolvconf 8 , | 96 | .Xr resolvconf 8 , | |
97 | if available, otherwise directly to | 97 | if available, otherwise directly to | |
98 | .Pa /etc/resolv.conf . | 98 | .Pa /etc/resolv.conf . | |
99 | If the hostname is currently blank, (null) or localhost, or | 99 | If the hostname is currently blank, (null) or localhost, or | |
100 | .Va force_hostname | 100 | .Va force_hostname | |
101 | is YES or TRUE or 1 then | 101 | is YES or TRUE or 1 then | |
102 | .Nm | 102 | .Nm | |
103 | sets the hostname to the one supplied by the DHCP server. | 103 | sets the hostname to the one supplied by the DHCP server. | |
104 | .Nm | 104 | .Nm | |
105 | then daemonises and waits for the lease renewal time to lapse. | 105 | then daemonises and waits for the lease renewal time to lapse. | |
106 | It will then attempt to renew its lease and reconfigure if the new lease | 106 | It will then attempt to renew its lease and reconfigure if the new lease | |
107 | changes when the lease begins to expire or the DHCP server sends a message | 107 | changes when the lease begins to expire or the DHCP server sends a message | |
108 | to renew early. | 108 | to renew early. | |
109 | .Pp | 109 | .Pp | |
110 | If any interface reports a working carrier then | 110 | If any interface reports a working carrier then | |
111 | .Nm | 111 | .Nm | |
112 | will try to obtain a lease before forking to the background, | 112 | will try to obtain a lease before forking to the background, | |
113 | otherwise it will fork right away. | 113 | otherwise it will fork right away. | |
114 | This behaviour can be modified with the | 114 | This behaviour can be modified with the | |
115 | .Fl b , Fl Fl background | 115 | .Fl b , Fl Fl background | |
116 | and | 116 | and | |
117 | .Fl w , Fl Fl waitip | 117 | .Fl w , Fl Fl waitip | |
118 | options. | 118 | options. | |
119 | .Pp | 119 | .Pp | |
120 | .Nm | 120 | .Nm | |
121 | is also an implementation of the BOOTP client specified in | 121 | is also an implementation of the BOOTP client specified in | |
122 | .Li RFC 951 . | 122 | .Li RFC 951 . | |
123 | .Pp | 123 | .Pp | |
124 | .Nm | 124 | .Nm | |
125 | is also an implementation of the IPv6 Router Solicitor as specified in | 125 | is also an implementation of the IPv6 Router Solicitor as specified in | |
126 | .Li RFC 4861 | 126 | .Li RFC 4861 | |
127 | and | 127 | and | |
128 | .Li RFC 6106 . | 128 | .Li RFC 6106 . | |
129 | .Pp | 129 | .Pp | |
130 | .Nm | 130 | .Nm | |
131 | is also an implementation of the IPv6 Privacy Extensions to AutoConf as | 131 | is also an implementation of the IPv6 Privacy Extensions to AutoConf as | |
132 | specified in | 132 | specified in | |
133 | .Li RFC 4941 . | 133 | .Li RFC 4941 . | |
134 | This feature needs to be enabled in the kernel and | 134 | This feature needs to be enabled in the kernel and | |
135 | .Nm | 135 | .Nm | |
136 | will start using it. | 136 | will start using it. | |
137 | .Pp | 137 | .Pp | |
138 | .Nm | 138 | .Nm | |
139 | is also an implementation of the DHCPv6 client as specified in | 139 | is also an implementation of the DHCPv6 client as specified in | |
140 | .Li RFC 3315 . | 140 | .Li RFC 3315 . | |
141 | By default, | 141 | By default, | |
142 | .Nm | 142 | .Nm | |
143 | only starts DHCPv6 when instructed to do so by an IPV6 Router Advertisement. | 143 | only starts DHCPv6 when instructed to do so by an IPV6 Router Advertisement. | |
144 | If no Identity Association is configured, | 144 | If no Identity Association is configured, | |
145 | then a Non-temporary Address is requested. | 145 | then a Non-temporary Address is requested. | |
146 | .Ss Local Link configuration | 146 | .Ss Local Link configuration | |
147 | If | 147 | If | |
148 | .Nm | 148 | .Nm | |
149 | failed to obtain a lease, it probes for a valid IPv4LL address | 149 | failed to obtain a lease, it probes for a valid IPv4LL address | |
150 | .Po | 150 | .Po | |
151 | aka ZeroConf, aka APIPA | 151 | aka ZeroConf, aka APIPA | |
152 | .Pc . | 152 | .Pc . | |
153 | Once obtained it restarts the process of looking for a DHCP server to get a | 153 | Once obtained it restarts the process of looking for a DHCP server to get a | |
154 | proper address. | 154 | proper address. | |
155 | .Pp | 155 | .Pp | |
156 | When using IPv4LL, | 156 | When using IPv4LL, | |
157 | .Nm | 157 | .Nm | |
158 | nearly always succeeds and returns an exit code of 0. | 158 | nearly always succeeds and returns an exit code of 0. | |
159 | In the rare case it fails, it normally means that there is a reverse ARP proxy | 159 | In the rare case it fails, it normally means that there is a reverse ARP proxy | |
160 | installed which always defeats IPv4LL probing. | 160 | installed which always defeats IPv4LL probing. | |
161 | To disable this behaviour, you can use the | 161 | To disable this behaviour, you can use the | |
162 | .Fl L , Fl Fl noipv4ll | 162 | .Fl L , Fl Fl noipv4ll | |
163 | option. | 163 | option. | |
164 | .Ss Multiple interfaces | 164 | .Ss Multiple interfaces | |
165 | If a list of interfaces are given on the command line, then | 165 | If a list of interfaces are given on the command line, then | |
166 | .Nm | 166 | .Nm | |
167 | only works with those interfaces, otherwise | 167 | only works with those interfaces, otherwise | |
168 | .Nm | 168 | .Nm | |
169 | discovers available Ethernet interfaces that can be configured. | 169 | discovers available Ethernet interfaces that can be configured. | |
170 | When | 170 | When | |
171 | .Nm | 171 | .Nm | |
172 | not limited to one interface on the command line, | 172 | not limited to one interface on the command line, | |
173 | it is running in Master mode. | 173 | it is running in Master mode. | |
174 | The | 174 | The | |
175 | .Nm dhcpcd-ui | 175 | .Nm dhcpcd-ui | |
176 | project expects dhcpcd to be running this way. | 176 | project expects dhcpcd to be running this way. | |
177 | .Pp | 177 | .Pp | |
178 | If a single interface is given then | 178 | If a single interface is given then | |
179 | .Nm | 179 | .Nm | |
180 | only works for that interface and runs as a separate instance to other | 180 | only works for that interface and runs as a separate instance to other | |
181 | .Nm | 181 | .Nm | |
182 | processes. | 182 | processes. | |
183 | .Fl w , Fl Fl waitip | 183 | .Fl w , Fl Fl waitip | |
184 | option is enabled in this instance to maintain compatibility with older | 184 | option is enabled in this instance to maintain compatibility with older | |
185 | versions. | 185 | versions. | |
186 | Using a single interface also affects the | 186 | Using a single interface also affects the | |
187 | .Fl k , | 187 | .Fl k , | |
188 | .Fl N , | 188 | .Fl N , | |
189 | .Fl n | 189 | .Fl n | |
190 | and | 190 | and | |
191 | .Fl x | 191 | .Fl x | |
192 | options, where the same interface will need to be specified, as a lack of an | 192 | options, where the same interface will need to be specified, as a lack of an | |
193 | interface will imply Master mode which this is not. | 193 | interface will imply Master mode which this is not. | |
194 | To force starting in Master mode with only one interface, the | 194 | To force starting in Master mode with only one interface, the | |
195 | .Fl M , Fl Fl master | 195 | .Fl M , Fl Fl master | |
196 | option can be used. | 196 | option can be used. | |
197 | .Pp | 197 | .Pp | |
198 | Interfaces are preferred by carrier, DHCP lease/IPv4LL and then lowest metric. | 198 | Interfaces are preferred by carrier, DHCP lease/IPv4LL and then lowest metric. | |
199 | For systems that support route metrics, each route will be tagged with the | 199 | For systems that support route metrics, each route will be tagged with the | |
200 | metric, otherwise | 200 | metric, otherwise | |
201 | .Nm | 201 | .Nm | |
202 | changes the routes to use the interface with the same route and the lowest | 202 | changes the routes to use the interface with the same route and the lowest | |
203 | metric. | 203 | metric. | |
204 | See options below for controlling which interfaces we allow and deny through | 204 | See options below for controlling which interfaces we allow and deny through | |
205 | the use of patterns. | 205 | the use of patterns. | |
206 | .Pp | 206 | .Pp | |
207 | Non-ethernet interfaces and some virtual ethernet interfaces | 207 | Non-ethernet interfaces and some virtual ethernet interfaces | |
208 | such as TAP and bridge are ignored by default, | 208 | such as TAP and bridge are ignored by default, | |
209 | as is the FireWire interface. | 209 | as is the FireWire interface. | |
210 | To work with these devices they either need to be specified on the command line, | 210 | To work with these devices they either need to be specified on the command line, | |
211 | be listed in | 211 | be listed in | |
212 | .Fl Fl allowinterfaces | 212 | .Fl Fl allowinterfaces | |
213 | or have an interface directive in | 213 | or have an interface directive in | |
214 | .Pa @SYSCONFDIR@/dhcpcd.conf . | 214 | .Pa @SYSCONFDIR@/dhcpcd.conf . | |
215 | .Ss Hooking into events | 215 | .Ss Hooking into events | |
216 | .Nm | 216 | .Nm | |
217 | runs | 217 | runs | |
218 | .Pa @SCRIPT@ , | 218 | .Pa @SCRIPT@ , | |
219 | or the script specified by the | 219 | or the script specified by the | |
220 | .Fl c , Fl Fl script | 220 | .Fl c , Fl Fl script | |
221 | option. | 221 | option. | |
222 | This script runs each script found in | 222 | This script runs each script found in | |
223 | .Pa @HOOKDIR@ | 223 | .Pa @HOOKDIR@ | |
224 | in a lexical order. | 224 | in a lexical order. | |
225 | The default installation supplies the scripts | 225 | The default installation supplies the scripts | |
226 | .Pa 01-test , | 226 | .Pa 01-test , | |
227 | .Pa 02-dump , | 227 | .Pa 02-dump , | |
228 | .Pa 20-resolv.conf | 228 | .Pa 20-resolv.conf | |
229 | and | 229 | and | |
230 | .Pa 30-hostname . | 230 | .Pa 30-hostname . | |
231 | You can disable each script by using the | 231 | You can disable each script by using the | |
232 | .Fl C , Fl Fl nohook | 232 | .Fl C , Fl Fl nohook | |
233 | option. | 233 | option. | |
234 | See | 234 | See | |
235 | .Xr dhcpcd-run-hooks 8 | 235 | .Xr dhcpcd-run-hooks 8 | |
236 | for details on how these scripts work. | 236 | for details on how these scripts work. | |
237 | .Nm | 237 | .Nm | |
238 | currently ignores the exit code of the script. | 238 | currently ignores the exit code of the script. | |
239 | .Pp | 239 | .Pp | |
240 | More scripts are supplied in | 240 | More scripts are supplied in | |
241 | .Pa @DATADIR@/dhcpcd/hooks | 241 | .Pa @DATADIR@/dhcpcd/hooks | |
242 | and need to be copied to | 242 | and need to be copied to | |
243 | .Pa @HOOKDIR@ | 243 | .Pa @HOOKDIR@ | |
244 | if you intend to use them. | 244 | if you intend to use them. | |
245 | For example, you could install | 245 | For example, you could install | |
246 | .Pa 29-lookup-hostname | 246 | .Pa 29-lookup-hostname | |
247 | so that | 247 | so that | |
248 | .Nm | 248 | .Nm | |
249 | can lookup the hostname of the IP address in DNS if no hostname | 249 | can lookup the hostname of the IP address in DNS if no hostname | |
250 | is given by the lease and one is not already set. | 250 | is given by the lease and one is not already set. | |
251 | .Ss Fine tuning | 251 | .Ss Fine tuning | |
252 | You can fine-tune the behaviour of | 252 | You can fine-tune the behaviour of | |
253 | .Nm | 253 | .Nm | |
254 | with the following options: | 254 | with the following options: | |
255 | .Bl -tag -width indent | 255 | .Bl -tag -width indent | |
256 | .It Fl b , Fl Fl background | 256 | .It Fl b , Fl Fl background | |
257 | Background immediately. | 257 | Background immediately. | |
258 | This is useful for startup scripts which don't disable link messages for | 258 | This is useful for startup scripts which don't disable link messages for | |
259 | carrier status. | 259 | carrier status. | |
260 | .It Fl c , Fl Fl script Ar script | 260 | .It Fl c , Fl Fl script Ar script | |
261 | Use this | 261 | Use this | |
262 | .Ar script | 262 | .Ar script | |
263 | instead of the default | 263 | instead of the default | |
264 | .Pa @SCRIPT@ . | 264 | .Pa @SCRIPT@ . | |
265 | .It Fl D , Fl Fl duid | 265 | .It Fl D , Fl Fl duid | |
266 | Use a DHCP Unique Identifier. | 266 | Use a DHCP Unique Identifier. | |
267 | If a system UUID is available, that will be used to create a DUID-UUID, | 267 | If a system UUID is available, that will be used to create a DUID-UUID, | |
268 | otheriwse if persistent storage is available then a DUID-LLT | 268 | otheriwse if persistent storage is available then a DUID-LLT | |
269 | (link local address + time) is generated, | 269 | (link local address + time) is generated, | |
270 | otherwise DUID-LL is generated (link local address). | 270 | otherwise DUID-LL is generated (link local address). | |
271 | This, plus the IAID will be used as the | 271 | This, plus the IAID will be used as the | |
272 | .Fl I , Fl Fl clientid . | 272 | .Fl I , Fl Fl clientid . | |
273 | The DUID generated will be held in | 273 | The DUID generated will be held in | |
274 | .Pa @DBDIR@/duid | 274 | .Pa @DBDIR@/duid | |
275 | and should not be copied to other hosts. | 275 | and should not be copied to other hosts. | |
276 | This file also takes precedence over the above rules. | 276 | This file also takes precedence over the above rules. | |
277 | .It Fl d , Fl Fl debug | 277 | .It Fl d , Fl Fl debug | |
278 | Echo debug messages to the stderr and syslog. | 278 | Echo debug messages to the stderr and syslog. | |
279 | .It Fl E , Fl Fl lastlease | 279 | .It Fl E , Fl Fl lastlease | |
280 | If | 280 | If | |
281 | .Nm | 281 | .Nm | |
282 | cannot obtain a lease, then try to use the last lease acquired for the | 282 | cannot obtain a lease, then try to use the last lease acquired for the | |
283 | interface. | 283 | interface. | |
284 | .It Fl Fl lastleaseextend | 284 | .It Fl Fl lastleaseextend | |
285 | Same as the above, but the lease will be retained even if it expires. | 285 | Same as the above, but the lease will be retained even if it expires. | |
286 | .Nm | 286 | .Nm | |
287 | will give it up if any other host tries to claim it for their own via ARP. | 287 | will give it up if any other host tries to claim it for their own via ARP. | |
288 | This violates RFC 2131, section 3.7, which states the lease should be | 288 | This violates RFC 2131, section 3.7, which states the lease should be | |
289 | dropped once it has expired. | 289 | dropped once it has expired. | |
290 | .It Fl e , Fl Fl env Ar value | 290 | .It Fl e , Fl Fl env Ar value | |
291 | Push | 291 | Push | |
292 | .Ar value | 292 | .Ar value | |
293 | to the environment for use in | 293 | to the environment for use in | |
294 | .Xr dhcpcd-run-hooks 8 . | 294 | .Xr dhcpcd-run-hooks 8 . | |
295 | For example, you can force the hostname hook to always set the hostname with | 295 | For example, you can force the hostname hook to always set the hostname with | |
296 | .Fl e | 296 | .Fl e | |
297 | .Va force_hostname=YES . | 297 | .Va force_hostname=YES . | |
298 | .It Fl g , Fl Fl reconfigure | 298 | .It Fl g , Fl Fl reconfigure | |
299 | .Nm | 299 | .Nm | |
300 | will re-apply IP address, routing and run | 300 | will re-apply IP address, routing and run | |
301 | .Xr dhcpcd-run-hooks 8 | 301 | .Xr dhcpcd-run-hooks 8 | |
302 | for each interface. | 302 | for each interface. | |
303 | This is useful so that a 3rd party such as PPP or VPN can change the routing | 303 | This is useful so that a 3rd party such as PPP or VPN can change the routing | |
304 | table and / or DNS, etc and then instruct | 304 | table and / or DNS, etc and then instruct | |
305 | .Nm | 305 | .Nm | |
306 | to put things back afterwards. | 306 | to put things back afterwards. | |
307 | .Nm | 307 | .Nm | |
308 | does not read a new configuration when this happens - you should rebind if you | 308 | does not read a new configuration when this happens - you should rebind if you | |
309 | need that functionality. | 309 | need that functionality. | |
310 | .It Fl F , Fl Fl fqdn Ar fqdn | 310 | .It Fl F , Fl Fl fqdn Ar fqdn | |
311 | Requests that the DHCP server updates DNS using FQDN instead of just a | 311 | Requests that the DHCP server updates DNS using FQDN instead of just a | |
312 | hostname. | 312 | hostname. | |
313 | Valid values for | 313 | Valid values for | |
314 | .Ar fqdn | 314 | .Ar fqdn | |
315 | are disable, none, ptr and both. | 315 | are disable, none, ptr and both. | |
316 | .Nm | 316 | .Nm | |
317 | itself never does any DNS updates. | 317 | itself never does any DNS updates. | |
318 | .Nm | 318 | .Nm | |
319 | encodes the FQDN hostname as specified in | 319 | encodes the FQDN hostname as specified in | |
320 | .Li RFC 1035 . | 320 | .Li RFC 1035 . | |
321 | .It Fl f , Fl Fl config Ar file | 321 | .It Fl f , Fl Fl config Ar file | |
322 | Specify a config to load instead of | 322 | Specify a config to load instead of | |
323 | .Pa @SYSCONFDIR@/dhcpcd.conf . | 323 | .Pa @SYSCONFDIR@/dhcpcd.conf . | |
324 | .Nm | 324 | .Nm | |
325 | always processes the config file before any command line options. | 325 | always processes the config file before any command line options. | |
326 | .It Fl h , Fl Fl hostname Ar hostname | 326 | .It Fl h , Fl Fl hostname Ar hostname | |
327 | Sends | 327 | Sends | |
328 | .Ar hostname | 328 | .Ar hostname | |
329 | to the DHCP server so it can be registered in DNS. | 329 | to the DHCP server so it can be registered in DNS. | |
330 | If | 330 | If | |
331 | .Ar hostname | 331 | .Ar hostname | |
332 | is an empty string then the current system hostname is sent. | 332 | is an empty string then the current system hostname is sent. | |
333 | If | 333 | If | |
334 | .Ar hostname | 334 | .Ar hostname | |
335 | is a FQDN (i.e., contains a .) then it will be encoded as such. | 335 | is a FQDN (i.e., contains a .) then it will be encoded as such. | |
336 | .It Fl I , Fl Fl clientid Ar clientid | 336 | .It Fl I , Fl Fl clientid Ar clientid | |
337 | Send the | 337 | Send the | |
338 | .Ar clientid . | 338 | .Ar clientid . | |
339 | If the string is of the format 01:02:03 then it is encoded as hex. | 339 | If the string is of the format 01:02:03 then it is encoded as hex. | |
340 | For interfaces whose hardware address is longer than 8 bytes, or if the | 340 | For interfaces whose hardware address is longer than 8 bytes, or if the | |
341 | .Ar clientid | 341 | .Ar clientid | |
342 | is an empty string then | 342 | is an empty string then | |
343 | .Nm | 343 | .Nm | |
344 | sends a default | 344 | sends a default | |
345 | .Ar clientid | 345 | .Ar clientid | |
346 | of the hardware family and the hardware address. | 346 | of the hardware family and the hardware address. | |
347 | .It Fl i , Fl Fl vendorclassid Ar vendorclassid | 347 | .It Fl i , Fl Fl vendorclassid Ar vendorclassid | |
348 | Override the DHCPv4 | 348 | Override the DHCPv4 | |
349 | .Ar vendorclassid | 349 | .Ar vendorclassid | |
350 | field sent. | 350 | field sent. | |
351 | The default is | 351 | The default is | |
352 | dhcpcd-<version>:<os>:<machine>:<platform>. | 352 | dhcpcd-<version>:<os>:<machine>:<platform>. | |
353 | For example | 353 | For example | |
354 | .D1 dhcpcd-5.5.6:NetBSD-6.99.5:i386:i386 | 354 | .D1 dhcpcd-5.5.6:NetBSD-6.99.5:i386:i386 | |
355 | If not set then none is sent. | 355 | If not set then none is sent. | |
356 | Some badly configured DHCP servers reject unknown vendorclassids. | 356 | Some badly configured DHCP servers reject unknown vendorclassids. | |
357 | To work around it, try and impersonate Windows by using the MSFT vendorclassid. | 357 | To work around it, try and impersonate Windows by using the MSFT vendorclassid. | |
358 | .It Fl j , Fl Fl logfile Ar logfile | 358 | .It Fl j , Fl Fl logfile Ar logfile | |
359 | Writes to the specified | 359 | Writes to the specified | |
360 | .Ar logfile . | 360 | .Ar logfile . | |
361 | .Nm | 361 | .Nm | |
362 | still writes to | 362 | still writes to | |
363 | .Xr syslog 3 . | 363 | .Xr syslog 3 . | |
364 | The | 364 | The | |
365 | .Ar logfile | 365 | .Ar logfile | |
366 | is reopened when | 366 | is reopened when | |
367 | .Nm | 367 | .Nm | |
368 | receives the | 368 | receives the | |
369 | .Dv SIGUSR2 | 369 | .Dv SIGUSR2 | |
370 | signal. | 370 | signal. | |
371 | .It Fl k , Fl Fl release Op Ar interface | 371 | .It Fl k , Fl Fl release Op Ar interface | |
372 | This causes an existing | 372 | This causes an existing | |
373 | .Nm | 373 | .Nm | |
374 | process running on the | 374 | process running on the | |
375 | .Ar interface | 375 | .Ar interface | |
376 | to release its lease and de-configure the | 376 | to release its lease and de-configure the | |
377 | .Ar interface | 377 | .Ar interface | |
378 | regardless of the | 378 | regardless of the | |
379 | .Fl p , Fl Fl persistent | 379 | .Fl p , Fl Fl persistent | |
380 | option. | 380 | option. | |
381 | If no | 381 | If no | |
382 | .Ar interface | 382 | .Ar interface | |
383 | is specified then this applies to all interfaces in Master mode. | 383 | is specified then this applies to all interfaces in Master mode. | |
384 | If no interfaces are left running, | 384 | If no interfaces are left running, | |
385 | .Nm | 385 | .Nm | |
386 | will exit. | 386 | will exit. | |
387 | .It Fl l , Fl Fl leasetime Ar seconds | 387 | .It Fl l , Fl Fl leasetime Ar seconds | |
388 | Request a lease time of | 388 | Request a lease time of | |
389 | .Ar seconds . | 389 | .Ar seconds . | |
390 | .Ar -1 | 390 | .Ar -1 | |
391 | represents an infinite lease time. | 391 | represents an infinite lease time. | |
392 | By default | 392 | By default | |
393 | .Nm | 393 | .Nm | |
394 | does not request any lease time and leaves it in the hands of the | 394 | does not request any lease time and leaves it in the hands of the | |
395 | DHCP server. | 395 | DHCP server. | |
396 | .It Fl M , Fl Fl master | 396 | .It Fl M , Fl Fl master | |
397 | Start | 397 | Start | |
398 | .Nm | 398 | .Nm | |
399 | in Master mode even if only one interface specified on the command line. | 399 | in Master mode even if only one interface specified on the command line. | |
400 | See the Multiple Interfaces section above. | 400 | See the Multiple Interfaces section above. | |
401 | .It Fl m , Fl Fl metric Ar metric | 401 | .It Fl m , Fl Fl metric Ar metric | |
402 | Metrics are used to prefer an interface over another one, lowest wins. | 402 | Metrics are used to prefer an interface over another one, lowest wins. | |
403 | .Nm | 403 | .Nm | |
404 | will supply a default metic of 200 + | 404 | will supply a default metic of 200 + | |
405 | .Xr if_nametoindex 3 . | 405 | .Xr if_nametoindex 3 . | |
406 | An extra 100 will be added for wireless interfaces. | 406 | An extra 100 will be added for wireless interfaces. | |
407 | .It Fl n , Fl Fl rebind Op Ar interface | 407 | .It Fl n , Fl Fl rebind Op Ar interface | |
408 | Notifies | 408 | Notifies | |
409 | .Nm | 409 | .Nm | |
410 | to reload its configuration and rebind the specified | 410 | to reload its configuration and rebind the specified | |
411 | .Ar interface . | 411 | .Ar interface . | |
412 | If no | 412 | If no | |
413 | .Ar interface | 413 | .Ar interface | |
414 | is specified then this applies to all interfaces in Master mode. | 414 | is specified then this applies to all interfaces in Master mode. | |
415 | If | 415 | If | |
416 | .Nm | 416 | .Nm | |
417 | is not running, then it starts up as normal. | 417 | is not running, then it starts up as normal. | |
418 | .It Fl N , Fl Fl renew Op Ar interface | 418 | .It Fl N , Fl Fl renew Op Ar interface | |
419 | Notifies | 419 | Notifies | |
420 | .Nm | 420 | .Nm | |
421 | to renew existing addresses on the specified | 421 | to renew existing addresses on the specified | |
422 | .Ar interface . | 422 | .Ar interface . | |
423 | If no | 423 | If no | |
424 | .Ar interface | 424 | .Ar interface | |
425 | is specified then this applies to all interfaces in Master mode. | 425 | is specified then this applies to all interfaces in Master mode. | |
426 | If | 426 | If | |
427 | .Nm | 427 | .Nm | |
428 | is not running, then it starts up as normal. | 428 | is not running, then it starts up as normal. | |
429 | Unlike the | 429 | Unlike the | |
430 | .Fl n , Fl Fl rebind | 430 | .Fl n , Fl Fl rebind | |
431 | option above, the configuration for | 431 | option above, the configuration for | |
432 | .Nm | 432 | .Nm | |
433 | is not reloaded. | 433 | is not reloaded. | |
434 | .It Fl o , Fl Fl option Ar option | 434 | .It Fl o , Fl Fl option Ar option | |
435 | Request the DHCP | 435 | Request the DHCP | |
436 | .Ar option | 436 | .Ar option | |
437 | variable for use in | 437 | variable for use in | |
438 | .Pa @SCRIPT@ . | 438 | .Pa @SCRIPT@ . | |
439 | .It Fl p , Fl Fl persistent | 439 | .It Fl p , Fl Fl persistent | |
440 | .Nm | 440 | .Nm | |
441 | normally de-configures the | 441 | normally de-configures the | |
442 | .Ar interface | 442 | .Ar interface | |
443 | and configuration when it exits. | 443 | and configuration when it exits. | |
444 | Sometimes, this isn't desirable if, for example, you have root mounted over | 444 | Sometimes, this isn't desirable if, for example, you have root mounted over | |
445 | NFS or SSH clients connect to this host and they need to be notified of | 445 | NFS or SSH clients connect to this host and they need to be notified of | |
446 | the host shutting down. | 446 | the host shutting down. | |
447 | You can use this option to stop this from happening. | 447 | You can use this option to stop this from happening. | |
448 | .It Fl r , Fl Fl request Ar address | 448 | .It Fl r , Fl Fl request Ar address | |
449 | Request the | 449 | Request the | |
450 | .Ar address | 450 | .Ar address | |
451 | in the DHCP DISCOVER message. | 451 | in the DHCP DISCOVER message. | |
452 | There is no guarantee this is the address the DHCP server will actually give. | 452 | There is no guarantee this is the address the DHCP server will actually give. | |
453 | If no | 453 | If no | |
454 | .Ar address | 454 | .Ar address | |
455 | is given then the first address currently assigned to the | 455 | is given then the first address currently assigned to the | |
456 | .Ar interface | 456 | .Ar interface | |
457 | is used. | 457 | is used. | |
458 | .It Fl s , Fl Fl inform Ar address Ns Op Ar /cidr Ns Op Ar /broadcast_address | 458 | .It Fl s , Fl Fl inform Ar address Ns Op Ar /cidr Ns Op Ar /broadcast_address | |
459 | Behaves like | 459 | Behaves like | |
460 | .Fl r , Fl Fl request | 460 | .Fl r , Fl Fl request | |
461 | as above, but sends a DHCP INFORM instead of DISCOVER/REQUEST. | 461 | as above, but sends a DHCP INFORM instead of DISCOVER/REQUEST. | |
462 | This does not get a lease as such, just notifies the DHCP server of the | 462 | This does not get a lease as such, just notifies the DHCP server of the | |
463 | .Ar address | 463 | .Ar address | |
464 | in use. | 464 | in use. | |
465 | You should also include the optional | 465 | You should also include the optional | |
466 | .Ar cidr | 466 | .Ar cidr | |
467 | network number in case the address is not already configured on the interface. | 467 | network number in case the address is not already configured on the interface. | |
468 | .Nm | 468 | .Nm | |
469 | remains running and pretends it has an infinite lease. | 469 | remains running and pretends it has an infinite lease. | |
470 | .Nm | 470 | .Nm | |
471 | will not de-configure the interface when it exits. | 471 | will not de-configure the interface when it exits. | |
472 | If | 472 | If | |
473 | .Nm | 473 | .Nm | |
474 | fails to contact a DHCP server then it returns a failure instead of falling | 474 | fails to contact a DHCP server then it returns a failure instead of falling | |
475 | back on IPv4LL. | 475 | back on IPv4LL. | |
476 | .It Fl Fl inform6 | 476 | .It Fl Fl inform6 | |
477 | Performs a DHCPv6 Information Request. | 477 | Performs a DHCPv6 Information Request. | |
478 | No address is requested or specified, but all other DHCPv6 options are allowed. | 478 | No address is requested or specified, but all other DHCPv6 options are allowed. | |
479 | This is normally performed automatically when the IPv6 Router Advertises | 479 | This is normally performed automatically when the IPv6 Router Advertises | |
480 | that the client should perform this operation. | 480 | that the client should perform this operation. | |
481 | This option is only needed when | 481 | This option is only needed when | |
482 | .Nm | 482 | .Nm | |
483 | is not processing IPv6RA messages and the need for DHCPv6 Information Request | 483 | is not processing IPv6RA messages and the need for DHCPv6 Information Request | |
484 | exists. | 484 | exists. | |
485 | .It Fl S , Fl Fl static Ar value | 485 | .It Fl S , Fl Fl static Ar value | |
486 | Configures a static DHCP | 486 | Configures a static DHCP | |
487 | .Ar value . | 487 | .Ar value . | |
488 | If you set | 488 | If you set | |
489 | .Ic ip_address | 489 | .Ic ip_address | |
490 | then | 490 | then | |
491 | .Nm | 491 | .Nm | |
492 | will not attempt to obtain a lease and just use the value for the address with | 492 | will not attempt to obtain a lease and just use the value for the address with | |
493 | an infinite lease time. | 493 | an infinite lease time. | |
494 | .Pp | 494 | .Pp | |
495 | Here is an example which configures a static address, routes and DNS. | 495 | Here is an example which configures a static address, routes and DNS. | |
496 | .D1 dhcpcd -S ip_address=192.168.0.10/24 \e | 496 | .D1 dhcpcd -S ip_address=192.168.0.10/24 \e | |
497 | .D1 -S routers=192.168.0.1 \e | 497 | .D1 -S routers=192.168.0.1 \e | |
498 | .D1 -S domain_name_servers=192.168.0.1 \e | 498 | .D1 -S domain_name_servers=192.168.0.1 \e | |
499 | .D1 eth0 | 499 | .D1 eth0 | |
500 | .Pp | 500 | .Pp | |
501 | You cannot presently set static DHCPv6 values. | 501 | You cannot presently set static DHCPv6 values. | |
502 | Use the | 502 | Use the | |
503 | .Fl e , Fl Fl env | 503 | .Fl e , Fl Fl env | |
504 | option instead. | 504 | option instead. | |
505 | .It Fl t , Fl Fl timeout Ar seconds | 505 | .It Fl t , Fl Fl timeout Ar seconds | |
506 | Timeout after | 506 | Timeout after | |
507 | .Ar seconds , | 507 | .Ar seconds , | |
508 | instead of the default 30. | 508 | instead of the default 30. | |
509 | A setting of 0 | 509 | A setting of 0 | |
510 | .Ar seconds | 510 | .Ar seconds | |
511 | causes | 511 | causes | |
512 | .Nm | 512 | .Nm | |
513 | to wait forever to get a lease. | 513 | to wait forever to get a lease. | |
514 | If | 514 | If | |
515 | .Nm | 515 | .Nm | |
516 | is working on a single interface then | 516 | is working on a single interface then | |
517 | .Nm | 517 | .Nm | |
518 | will exit when a timeout occurs, otherwise | 518 | will exit when a timeout occurs, otherwise | |
519 | .Nm | 519 | .Nm | |
520 | will fork into the background. | 520 | will fork into the background. | |
521 | .It Fl u , Fl Fl userclass Ar class | 521 | .It Fl u , Fl Fl userclass Ar class | |
522 | Tags the DHCPv4 message with the userclass | 522 | Tags the DHCPv4 message with the userclass | |
523 | .Ar class . | 523 | .Ar class . | |
524 | DHCP servers use this to give members of the class DHCP options other than the | 524 | DHCP servers use this to give members of the class DHCP options other than the | |
525 | default, without having to know things like hardware address or hostname. | 525 | default, without having to know things like hardware address or hostname. | |
526 | .It Fl v , Fl Fl vendor Ar code , Ns Ar value | 526 | .It Fl v , Fl Fl vendor Ar code , Ns Ar value | |
527 | Add an encapsulated vendor option. | 527 | Add an encapsulated vendor option. | |
528 | .Ar code | 528 | .Ar code | |
529 | should be between 1 and 254 inclusive. | 529 | should be between 1 and 254 inclusive. | |
530 | To add a raw vendor string, omit | 530 | To add a raw vendor string, omit | |
531 | .Ar code | 531 | .Ar code | |
532 | but keep the comma. | 532 | but keep the comma. | |
533 | Examples. | 533 | Examples. | |
534 | .Pp | 534 | .Pp | |
535 | Set the vendor option 01 with an IP address. | 535 | Set the vendor option 01 with an IP address. | |
536 | .D1 dhcpcd \-v 01,192.168.0.2 eth0 | 536 | .D1 dhcpcd \-v 01,192.168.0.2 eth0 | |
537 | Set the vendor option 02 with a hex code. | 537 | Set the vendor option 02 with a hex code. | |
538 | .D1 dhcpcd \-v 02,01:02:03:04:05 eth0 | 538 | .D1 dhcpcd \-v 02,01:02:03:04:05 eth0 | |
539 | Set the vendor option 03 with an IP address as a string. | 539 | Set the vendor option 03 with an IP address as a string. | |
540 | .D1 dhcpcd \-v 03,\e"192.168.0.2\e" eth0 | 540 | .D1 dhcpcd \-v 03,\e"192.168.0.2\e" eth0 | |
541 | Set un-encapsulated vendor option to hello world. | 541 | Set un-encapsulated vendor option to hello world. | |
542 | .D1 dhcpcd \-v ,"hello world" eth0 | 542 | .D1 dhcpcd \-v ,"hello world" eth0 | |
543 | .It Fl Fl version | 543 | .It Fl Fl version | |
544 | Display both program version and copyright information. | 544 | Display both program version and copyright information. | |
545 | .Nm | 545 | .Nm | |
546 | then exits before doing any configuration. | 546 | then exits before doing any configuration. | |
547 | .It Fl w | 547 | .It Fl w | |
548 | Wait for an address to be assigned before forking to the background. | 548 | Wait for an address to be assigned before forking to the background. | |
549 | Does not take an argument, unlike the below option. | 549 | Does not take an argument, unlike the below option. | |
550 | .It Fl Fl waitip Ns = Ns Op 4 | 6 | 550 | .It Fl Fl waitip Ns = Ns Op 4 | 6 | |
551 | Wait for an address to be assigned before forking to the background. | 551 | Wait for an address to be assigned before forking to the background. | |
552 | 4 means wait for an IPv4 address to be assigned. | 552 | 4 means wait for an IPv4 address to be assigned. | |
553 | 6 means wait for an IPv6 address to be assigned. | 553 | 6 means wait for an IPv6 address to be assigned. | |
554 | If no argument is given, | 554 | If no argument is given, | |
555 | .Nm | 555 | .Nm | |
556 | will wait for any address protocol to be assigned. | 556 | will wait for any address protocol to be assigned. | |
557 | It is possible to wait for more than one address protocol and | 557 | It is possible to wait for more than one address protocol and | |
558 | .Nm | 558 | .Nm | |
559 | will only fork to the background when all waiting conditions are satisfied. | 559 | will only fork to the background when all waiting conditions are satisfied. | |
560 | .It Fl x , Fl Fl exit Op Ar interface | 560 | .It Fl x , Fl Fl exit Op Ar interface | |
561 | This will signal an existing | 561 | This will signal an existing | |
562 | .Nm | 562 | .Nm | |
563 | process running on the | 563 | process running on the | |
564 | .Ar interface | 564 | .Ar interface | |
565 | to exit. | 565 | to exit. | |
566 | If no | 566 | If no | |
567 | .Ar interface | 567 | .Ar interface | |
568 | is specified, then the above is applied to all interfaces in Master mode. | 568 | is specified, then the above is applied to all interfaces in Master mode. | |
569 | See the | 569 | See the | |
570 | .Fl p , Fl Fl persistent | 570 | .Fl p , Fl Fl persistent | |
571 | option to control configuration persistence on exit, | 571 | option to control configuration persistence on exit, | |
572 | which is enabled by default in | 572 | which is enabled by default in | |
573 | .Xr dhcpcd.conf 5 . | 573 | .Xr dhcpcd.conf 5 . | |
574 | .Nm | 574 | .Nm | |
575 | then waits until this process has exited. | 575 | then waits until this process has exited. | |
576 | .It Fl y , Fl Fl reboot Ar seconds | 576 | .It Fl y , Fl Fl reboot Ar seconds | |
577 | Allow | 577 | Allow | |
578 | .Ar reboot | 578 | .Ar reboot | |
579 | seconds before moving to the discover phase if we have an old lease to use. | 579 | seconds before moving to the discover phase if we have an old lease to use. | |
580 | Allow | 580 | Allow | |
581 | .Ar reboot | 581 | .Ar reboot | |
582 | seconds before starting fallback states from the discover phase. | 582 | seconds before starting fallback states from the discover phase. | |
583 | IPv4LL is started when the first | 583 | IPv4LL is started when the first | |
584 | .Ar reboot | 584 | .Ar reboot | |
585 | timeout is reached. | 585 | timeout is reached. | |
586 | The default is 5 seconds. | 586 | The default is 5 seconds. | |
587 | A setting of 0 seconds causes | 587 | A setting of 0 seconds causes | |
588 | .Nm | 588 | .Nm | |
589 | to skip the reboot phase and go straight into discover. | 589 | to skip the reboot phase and go straight into discover. | |
590 | This has no effect on DHCPv6 other than skipping the reboot phase. | 590 | This has no effect on DHCPv6 other than skipping the reboot phase. | |
591 | .El | 591 | .El | |
592 | .Ss Restricting behaviour | 592 | .Ss Restricting behaviour | |
593 | .Nm | 593 | .Nm | |
594 | will try to do as much as it can by default. | 594 | will try to do as much as it can by default. | |
595 | However, there are sometimes situations where you don't want the things to be | 595 | However, there are sometimes situations where you don't want the things to be | |
596 | configured exactly how the DHCP server wants. | 596 | configured exactly how the DHCP server wants. | |
597 | Here are some options that deal with turning these bits off. | 597 | Here are some options that deal with turning these bits off. | |
598 | .Pp | 598 | .Pp | |
599 | Note that when | 599 | Note that when | |
600 | .Nm | 600 | .Nm | |
601 | is restricted to a single interface then the interface also needs to be | 601 | is restricted to a single interface then the interface also needs to be | |
602 | specified when asking | 602 | specified when asking | |
603 | .Nm | 603 | .Nm | |
604 | to exit using the commandline. | 604 | to exit using the commandline. | |
605 | If the protocol is restricted as well then the protocol needs to be included | 605 | If the protocol is restricted as well then the protocol needs to be included | |
606 | with the exit instruction. | 606 | with the exit instruction. | |
607 | .Bl -tag -width indent | 607 | .Bl -tag -width indent | |
608 | .It Fl 1 , Fl Fl oneshot | 608 | .It Fl 1 , Fl Fl oneshot | |
609 | Exit after configuring an interface. | 609 | Exit after configuring an interface. | |
610 | Use the | 610 | Use the | |
611 | .Fl w , Fl Fl waitip | 611 | .Fl w , Fl Fl waitip | |
612 | option to specify which protocol(s) to configure before exiting. | 612 | option to specify which protocol(s) to configure before exiting. | |
613 | .It Fl 4 , Fl Fl ipv4only | 613 | .It Fl 4 , Fl Fl ipv4only | |
614 | Configure IPv4 only. | 614 | Configure IPv4 only. | |
615 | .It Fl 6 , Fl Fl ipv6only | 615 | .It Fl 6 , Fl Fl ipv6only | |
616 | Configure IPv6 only. | 616 | Configure IPv6 only. | |
617 | .It Fl A , Fl Fl noarp | 617 | .It Fl A , Fl Fl noarp | |
618 | Don't request or claim the address by ARP. | 618 | Don't request or claim the address by ARP. | |
619 | This also disables IPv4LL. | 619 | This also disables IPv4LL. | |
620 | .It Fl B , Fl Fl nobackground | 620 | .It Fl B , Fl Fl nobackground | |
621 | Don't run in the background when we acquire a lease. | 621 | Don't run in the background when we acquire a lease. | |
622 | This is mainly useful for running under the control of another process, such | 622 | This is mainly useful for running under the control of another process, such | |
623 | as a debugger or a network manager. | 623 | as a debugger or a network manager. | |
624 | .It Fl C , Fl Fl nohook Ar script | 624 | .It Fl C , Fl Fl nohook Ar script | |
625 | Don't run this hook script. | 625 | Don't run this hook script. | |
626 | Matches full name, or prefixed with 2 numbers optionally ending with | 626 | Matches full name, or prefixed with 2 numbers optionally ending with | |
627 | .Pa .sh . | 627 | .Pa .sh . | |
628 | .Pp | 628 | .Pp | |
629 | So to stop | 629 | So to stop | |
630 | .Nm | 630 | .Nm | |
631 | from touching your DNS settings you would do:- | 631 | from touching your DNS settings you would do:- | |
632 | .D1 dhcpcd -C resolv.conf eth0 | 632 | .D1 dhcpcd -C resolv.conf eth0 | |
633 | .It Fl G , Fl Fl nogateway | 633 | .It Fl G , Fl Fl nogateway | |
634 | Don't set any default routes. | 634 | Don't set any default routes. | |
635 | .It Fl H , Fl Fl xidhwaddr | 635 | .It Fl H , Fl Fl xidhwaddr | |
636 | Use the last four bytes of the hardware address as the DHCP xid instead | 636 | Use the last four bytes of the hardware address as the DHCP xid instead | |
637 | of a randomly generated number. | 637 | of a randomly generated number. | |
638 | .It Fl J , Fl Fl broadcast | 638 | .It Fl J , Fl Fl broadcast | |
639 | Instructs the DHCP server to broadcast replies back to the client. | 639 | Instructs the DHCP server to broadcast replies back to the client. | |
640 | Normally this is only set for non-Ethernet interfaces, | 640 | Normally this is only set for non-Ethernet interfaces, | |
641 | such as FireWire and InfiniBand. | 641 | such as FireWire and InfiniBand. | |
642 | In most instances, | 642 | In most instances, | |
643 | .Nm | 643 | .Nm | |
644 | will set this automatically. | 644 | will set this automatically. | |
645 | .It Fl K , Fl Fl nolink | 645 | .It Fl K , Fl Fl nolink | |
646 | Don't receive link messages for carrier status. | 646 | Don't receive link messages for carrier status. | |
647 | You should only have to use this with buggy device drivers or running | 647 | You should only have to use this with buggy device drivers or running | |
648 | .Nm | 648 | .Nm | |
649 | through a network manager. | 649 | through a network manager. | |
650 | .It Fl L , Fl Fl noipv4ll | 650 | .It Fl L , Fl Fl noipv4ll | |
651 | Don't use IPv4LL (aka APIPA, aka Bonjour, aka ZeroConf). | 651 | Don't use IPv4LL (aka APIPA, aka Bonjour, aka ZeroConf). | |
652 | .It Fl O , Fl Fl nooption Ar option | 652 | .It Fl O , Fl Fl nooption Ar option | |
653 | Removes the | 653 | Removes the | |
654 | .Ar option | 654 | .Ar option | |
655 | from the DHCP message before processing. | 655 | from the DHCP message before processing. | |
656 | .It Fl P , Fl Fl printpidfile | 656 | .It Fl P , Fl Fl printpidfile | |
657 | Print the | 657 | Print the | |
658 | .Pa pidfile | 658 | .Pa pidfile | |
659 | .Nm | 659 | .Nm | |
660 | will use based on commmand-line arguments to stdout. | 660 | will use based on commmand-line arguments to stdout. | |
661 | .It Fl Q , Fl Fl require Ar option | 661 | .It Fl Q , Fl Fl require Ar option | |
662 | Requires the | 662 | Requires the | |
663 | .Ar option | 663 | .Ar option | |
664 | to be present in all DHCP messages, otherwise the message is ignored. | 664 | to be present in all DHCP messages, otherwise the message is ignored. | |
665 | To enforce that | 665 | To enforce that | |
666 | .Nm | 666 | .Nm | |
667 | only responds to DHCP servers and not BOOTP servers, you can | 667 | only responds to DHCP servers and not BOOTP servers, you can | |
668 | .Fl Q | 668 | .Fl Q | |
669 | .Ar dhcp_message_type . | 669 | .Ar dhcp_message_type . | |
670 | .It Fl q , Fl Fl quiet | 670 | .It Fl q , Fl Fl quiet | |
671 | Quiet | 671 | Quiet | |
672 | .Nm | 672 | .Nm | |
673 | on the command line, only warnings and errors will be displayed. | 673 | on the command line, only warnings and errors will be displayed. | |
674 | If this option is used another time then all console output is disabled. | 674 | If this option is used another time then all console output is disabled. | |
675 | These messages are still logged via | 675 | These messages are still logged via | |
676 | .Xr syslog 3 . | 676 | .Xr syslog 3 . | |
677 | .It Fl T , Fl Fl test | 677 | .It Fl T , Fl Fl test | |
678 | On receipt of DHCP messages just call | 678 | On receipt of DHCP messages just call | |
679 | .Pa @SCRIPT@ | 679 | .Pa @SCRIPT@ | |
680 | with the reason of TEST which echos the DHCP variables found in the message | 680 | with the reason of TEST which echos the DHCP variables found in the message | |
681 | to the console. | 681 | to the console. | |
682 | The interface configuration isn't touched and neither are any configuration | 682 | The interface configuration isn't touched and neither are any configuration | |
683 | files. | 683 | files. | |
684 | The | 684 | The | |
685 | .Ar rapid_commit | 685 | .Ar rapid_commit | |
686 | option is not sent in TEST mode so that the server does not lease an address. | 686 | option is not sent in TEST mode so that the server does not lease an address. | |
687 | To test INFORM the interface needs to be configured with the desired address | 687 | To test INFORM the interface needs to be configured with the desired address | |
688 | before starting | 688 | before starting | |
689 | .Nm . | 689 | .Nm . | |
690 | .It Fl U , Fl Fl dumplease Op Ar interface | 690 | .It Fl U , Fl Fl dumplease Op Ar interface | |
691 | Dumps the current lease for the | 691 | Dumps the current lease for the | |
692 | .Ar interface | 692 | .Ar interface | |
693 | to stdout. | 693 | to stdout. | |
694 | If no | 694 | If no | |
695 | .Ar interface | 695 | .Ar interface | |
696 | is given then all interfaces are dumped. | 696 | is given then all interfaces are dumped. | |
697 | Use the | 697 | Use the | |
698 | .Fl 4 | 698 | .Fl 4 | |
699 | or | 699 | or | |
700 | .Fl 6 | 700 | .Fl 6 | |
701 | flags to specify an address family. | 701 | flags to specify an address family. | |
702 | If a lease is piped in via standard input then that is dumped. | 702 | If a lease is piped in via standard input then that is dumped. | |
703 | In this case, specifying an address family is mandatory. | 703 | In this case, specifying an address family is mandatory. | |
704 | .It Fl V , Fl Fl variables | 704 | .It Fl V , Fl Fl variables | |
705 | Display a list of option codes, the associated variable and encoding for use in | 705 | Display a list of option codes, the associated variable and encoding for use in | |
706 | .Xr dhcpcd-run-hooks 8 . | 706 | .Xr dhcpcd-run-hooks 8 . | |
707 | Variables are prefixed with new_ and old_ unless the option number is -. | 707 | Variables are prefixed with new_ and old_ unless the option number is -. | |
708 | Variables without an option are part of the DHCP message and cannot be | 708 | Variables without an option are part of the DHCP message and cannot be | |
709 | directly requested. | 709 | directly requested. | |
710 | .It Fl W , Fl Fl whitelist Ar address Ns Op /cidr | 710 | .It Fl W , Fl Fl whitelist Ar address Ns Op /cidr | |
711 | Only accept packets from | 711 | Only accept packets from | |
712 | .Ar address Ns Op /cidr . | 712 | .Ar address Ns Op /cidr . | |
713 | .Fl X , Fl Fl blacklist | 713 | .Fl X , Fl Fl blacklist | |
714 | is ignored if | 714 | is ignored if | |
715 | .Fl W , Fl Fl whitelist | 715 | .Fl W , Fl Fl whitelist | |
716 | is set. | 716 | is set. | |
717 | .It Fl X , Fl Fl blacklist Ar address Ns Op Ar /cidr | 717 | .It Fl X , Fl Fl blacklist Ar address Ns Op Ar /cidr | |
718 | Ignore all packets from | 718 | Ignore all packets from | |
719 | .Ar address Ns Op Ar /cidr . | 719 | .Ar address Ns Op Ar /cidr . | |
720 | .It Fl Z , Fl Fl denyinterfaces Ar pattern | 720 | .It Fl Z , Fl Fl denyinterfaces Ar pattern | |
721 | When discovering interfaces, the interface name must not match | 721 | When discovering interfaces, the interface name must not match | |
722 | .Ar pattern | 722 | .Ar pattern | |
723 | which is a space or comma separated list of patterns passed to | 723 | which is a space or comma separated list of patterns passed to | |
724 | .Xr fnmatch 3 . | 724 | .Xr fnmatch 3 . | |
725 | .It Fl z , Fl Fl allowinterfaces Ar pattern | 725 | .It Fl z , Fl Fl allowinterfaces Ar pattern | |
726 | When discovering interfaces, the interface name must match | 726 | When discovering interfaces, the interface name must match | |
727 | .Ar pattern | 727 | .Ar pattern | |
728 | which is a space or comma separated list of patterns passed to | 728 | which is a space or comma separated list of patterns passed to | |
729 | .Xr fnmatch 3 . | 729 | .Xr fnmatch 3 . | |
730 | If the same interface is matched in | 730 | If the same interface is matched in | |
731 | .Fl Z , Fl Fl denyinterfaces | 731 | .Fl Z , Fl Fl denyinterfaces | |
732 | then it is still denied. | 732 | then it is still denied. | |
733 | .It Fl Fl inactive | 733 | .It Fl Fl inactive | |
734 | Don't start any interfaces other than those specified on the command line. | 734 | Don't start any interfaces other than those specified on the command line. | |
735 | This allows | 735 | This allows | |
736 | .Nm | 736 | .Nm | |
737 | to be started in Master mode and then wait for subsequent | 737 | to be started in Master mode and then wait for subsequent | |
738 | .Nm | 738 | .Nm | |
739 | commands to start each interface as required. | 739 | commands to start each interface as required. | |
740 | .It Fl Fl nodev | 740 | .It Fl Fl nodev | |
741 | Don't load any | 741 | Don't load any | |
742 | .Pa /dev | 742 | .Pa /dev | |
743 | management modules. | 743 | management modules. | |
744 | .El | 744 | .El | |
745 | .Sh 3RDPARTY LINK MANAGEMENT | 745 | .Sh 3RDPARTY LINK MANAGEMENT | |
746 | Some interfaces require configuration by 3rd parties, such as PPP or VPN. | 746 | Some interfaces require configuration by 3rd parties, such as PPP or VPN. | |
747 | When an interface configuration in | 747 | When an interface configuration in | |
748 | .Nm | 748 | .Nm | |
749 | is marked as STATIC or INFORM without an address then | 749 | is marked as STATIC or INFORM without an address then | |
750 | .Nm | 750 | .Nm | |
751 | will monitor the interface until an address is added or removed from it and | 751 | will monitor the interface until an address is added or removed from it and | |
752 | act accordingly. | 752 | act accordingly. | |
753 | For point to point interfaces (like PPP), a default route to its | 753 | For point to point interfaces (like PPP), a default route to its | |
754 | destination is automatically added to the configuration. | 754 | destination is automatically added to the configuration. | |
755 | If the point to point interface is configured for INFORM, then | 755 | If the point to point interface is configured for INFORM, then | |
756 | .Nm | 756 | .Nm | |
757 | unicasts INFORM to the destination, otherwise it defaults to STATIC. | 757 | unicasts INFORM to the destination, otherwise it defaults to STATIC. | |
758 | .Sh NOTES | 758 | .Sh NOTES | |
759 | .Nm | 759 | .Nm | |
760 | requires a Berkley Packet Filter, or BPF device on BSD based systems and a | 760 | requires a Berkley Packet Filter, or BPF device on BSD based systems and a | |
761 | Linux Socket Filter, or LPF device on Linux based systems for all IPv4 | 761 | Linux Socket Filter, or LPF device on Linux based systems for all IPv4 | |
762 | configuration. | 762 | configuration. | |
763 | .Pp | 763 | .Pp | |
764 | If restricting | 764 | If restricting | |
765 | .Nm | 765 | .Nm | |
766 | to a single interface and optionally address family via the command-line | 766 | to a single interface and optionally address family via the command-line | |
767 | then all further calls to | 767 | then all further calls to | |
768 | .Nm | 768 | .Nm | |
769 | to rebind, reconfigure or exit need to include the same restrictive flags | 769 | to rebind, reconfigure or exit need to include the same restrictive flags | |
770 | so that | 770 | so that | |
771 | .Nm | 771 | .Nm | |
772 | knows which process to signal. | 772 | knows which process to signal. | |
773 | .Pp | 773 | .Pp | |
774 | Some DHCP servers implement ClientID filtering. | 774 | Some DHCP servers implement ClientID filtering. | |
775 | If | 775 | If | |
776 | .Nm | 776 | .Nm | |
777 | is replacing an in-use DHCP client then you might need to adjust the clientid | 777 | is replacing an in-use DHCP client then you might need to adjust the clientid | |
778 | option | 778 | option | |
779 | .Nm | 779 | .Nm | |
780 | sends to match. | 780 | sends to match. | |
781 | If using a DUID in place of the ClientID, edit | 781 | If using a DUID in place of the ClientID, edit | |
782 | .Pa @DBDIR@/duid | 782 | .Pa @DBDIR@/duid | |
783 | accordingly. | 783 | accordingly. | |
784 | .Sh FILES | 784 | .Sh FILES | |
785 | .Bl -ohang | 785 | .Bl -ohang | |
786 | .It Pa @SYSCONFDIR@/dhcpcd.conf | 786 | .It Pa @SYSCONFDIR@/dhcpcd.conf | |
787 | Configuration file for dhcpcd. | 787 | Configuration file for dhcpcd. | |
788 | If you always use the same options, put them here. | 788 | If you always use the same options, put them here. | |
789 | .It Pa @SCRIPT@ | 789 | .It Pa @SCRIPT@ | |
790 | Bourne shell script that is run to configure or de-configure an interface. | 790 | Bourne shell script that is run to configure or de-configure an interface. | |
791 | .It Pa @LIBDIR@/dhcpcd/dev | 791 | .It Pa @LIBDIR@/dhcpcd/dev | |
792 | Linux | 792 | Linux | |
793 | .Pa /dev | 793 | .Pa /dev | |
794 | management modules. | 794 | management modules. | |
795 | .It Pa @HOOKDIR@ | 795 | .It Pa @HOOKDIR@ | |
796 | A directory containing bourne shell scripts that are run by the above script. | 796 | A directory containing bourne shell scripts that are run by the above script. | |
797 | Each script can be disabled by using the | 797 | Each script can be disabled by using the | |
798 | .Fl C , Fl Fl nohook | 798 | .Fl C , Fl Fl nohook | |
799 | option described above. | 799 | option described above. | |
800 | .It Pa @DBDIR@/duid | 800 | .It Pa @DBDIR@/duid | |
801 | Text file that holds the DUID used to identify the host. | 801 | Text file that holds the DUID used to identify the host. | |
802 | .It Pa @DBDIR@/secret | 802 | .It Pa @DBDIR@/secret | |
803 | Text file that holds a secret key known only to the host. | 803 | Text file that holds a secret key known only to the host. | |
804 | .It Pa @DBDIR@/ Ns Ar interface Ns Ar -ssid Ns .lease | 804 | .It Pa @DBDIR@/ Ns Ar interface Ns Ar -ssid Ns .lease | |
805 | The actual DHCP message sent by the server. | 805 | The actual DHCP message sent by the server. | |
806 | We use this when reading the last | 806 | We use this when reading the last | |
807 | lease and use the file's mtime as when it was issued. | 807 | lease and use the file's mtime as when it was issued. | |
808 | .It Pa @DBDIR@/ Ns Ar interface Ns Ar -ssid Ns .lease6 | 808 | .It Pa @DBDIR@/ Ns Ar interface Ns Ar -ssid Ns .lease6 | |
809 | The actual DHCPv6 message sent by the server. | 809 | The actual DHCPv6 message sent by the server. | |
810 | We use this when reading the last | 810 | We use this when reading the last | |
811 | lease and use the file's mtime as when it was issued. | 811 | lease and use the file's mtime as when it was issued. | |
812 | .It Pa @DBDIR@/rdm_monotonic | 812 | .It Pa @DBDIR@/rdm_monotonic | |
813 | Stores the monotonic counter used in the | 813 | Stores the monotonic counter used in the | |
814 | .Ar replay | 814 | .Ar replay | |
815 | field in Authentication Options. | 815 | field in Authentication Options. | |
816 | .It Pa @RUNDIR@/pid | 816 | .It Pa @RUNDIR@/pid | |
817 | Stores the PID of | 817 | Stores the PID of | |
818 | .Nm | 818 | .Nm | |
819 | running on all interfaces. | 819 | running on all interfaces. | |
820 | .It Pa @RUNDIR@/ Ns Ar interface Ns .pid | 820 | .It Pa @RUNDIR@/ Ns Ar interface Ns .pid | |
821 | Stores the PID of | 821 | Stores the PID of | |
822 | .Nm | 822 | .Nm | |
823 | running on the | 823 | running on the | |
824 | .Ar interface . | 824 | .Ar interface . | |
825 | .It Pa @RUNDIR@/sock | 825 | .It Pa @RUNDIR@/sock | |
826 | Control socket to the master daemon. | 826 | Control socket to the master daemon. | |
827 | .It Pa @RUNDIR@/unpriv.sock | 827 | .It Pa @RUNDIR@/unpriv.sock | |
828 | Unprivileged socket to the master daemon, only allows state retrieval. | 828 | Unprivileged socket to the master daemon, only allows state retrieval. | |
829 | .It Pa @RUNDIR@/ Ns Ar interface Ns .sock | 829 | .It Pa @RUNDIR@/ Ns Ar interface Ns .sock | |
830 | Control socket to per interface daemon. | 830 | Control socket to per interface daemon. | |
831 | .El | 831 | .El | |
832 | .Sh SEE ALSO | 832 | .Sh SEE ALSO | |
833 | .Xr fnmatch 3 , | 833 | .Xr fnmatch 3 , | |
834 | .Xr if_nametoindex 3 , | 834 | .Xr if_nametoindex 3 , | |
835 | .Xr dhcpcd.conf 5 , | 835 | .Xr dhcpcd.conf 5 , | |
836 | .Xr resolv.conf 5 , | 836 | .Xr resolv.conf 5 , | |
837 | .Xr dhcpcd-run-hooks 8 , | 837 | .Xr dhcpcd-run-hooks 8 , | |
838 | .Xr resolvconf 8 | 838 | .Xr resolvconf 8 | |
839 | .Sh STANDARDS | 839 | .Sh STANDARDS | |
840 | RFC\ 951, RFC\ 1534, RFC\ 2104, RFC\ 2131, RFC\ 2132, RFC\ 2563, RFC\ 2855, | 840 | RFC\ 951, RFC\ 1534, RFC\ 2104, RFC\ 2131, RFC\ 2132, RFC\ 2563, RFC\ 2855, | |
841 | RFC\ 3004, RFC\ 3118, RFC\ 3203, RFC\ 3315, RFC\ 3361, RFC\ 3633, RFC\ 3396, | 841 | RFC\ 3004, RFC\ 3118, RFC\ 3203, RFC\ 3315, RFC\ 3361, RFC\ 3633, RFC\ 3396, | |
842 | RFC\ 3397, RFC\ 3442, RFC\ 3495, RFC\ 3925, RFC\ 3927, RFC\ 4039, RFC\ 4075, | 842 | RFC\ 3397, RFC\ 3442, RFC\ 3495, RFC\ 3925, RFC\ 3927, RFC\ 4039, RFC\ 4075, | |
843 | RFC\ 4242, RFC\ 4361, RFC\ 4390, RFC\ 4702, RFC\ 4074, RFC\ 4861, RFC\ 4833, | 843 | RFC\ 4242, RFC\ 4361, RFC\ 4390, RFC\ 4702, RFC\ 4074, RFC\ 4861, RFC\ 4833, | |
844 | RFC\ 4941, RFC\ 5227, RFC\ 5942, RFC\ 5969, RFC\ 6106, RFC\ 6334, RFC\ 6355, | 844 | RFC\ 4941, RFC\ 5227, RFC\ 5942, RFC\ 5969, RFC\ 6106, RFC\ 6334, RFC\ 6355, | |
845 | RFC\ 6603, RFC\ 6704, RFC\ 7217, RFC\ 7550, RFC\ 7844. | 845 | RFC\ 6603, RFC\ 6704, RFC\ 7217, RFC\ 7550, RFC\ 7844. | |
846 | .Sh AUTHORS | 846 | .Sh AUTHORS | |
847 | .An Roy Marples Aq Mt roy@marples.name | 847 | .An Roy Marples Aq Mt roy@marples.name | |
848 | .Sh BUGS | 848 | .Sh BUGS | |
849 | If | |||
850 | .Nm | |||
851 | is running in a | |||
852 | .Xr chroot 2 | |||
853 | then re-opening the | |||
854 | .Fl Fl logfile | |||
855 | from SIGUSR2 may not work. | |||
856 | .Pp | |||
857 | Please report them to | 849 | Please report them to | |
858 | .Lk http://roy.marples.name/projects/dhcpcd | 850 | .Lk http://roy.marples.name/projects/dhcpcd |
--- src/external/bsd/dhcpcd/dist/src/dhcpcd.c 2020/10/12 14:09:03 1.44
+++ src/external/bsd/dhcpcd/dist/src/dhcpcd.c 2020/11/01 14:24:01 1.45
@@ -426,2163 +426,2169 @@ stop_interface(struct interface *ifp, co | @@ -426,2163 +426,2169 @@ stop_interface(struct interface *ifp, co | |||
426 | /* De-activate the interface */ | 426 | /* De-activate the interface */ | |
427 | ifp->active = IF_INACTIVE; | 427 | ifp->active = IF_INACTIVE; | |
428 | ifp->options->options &= ~DHCPCD_STOPPING; | 428 | ifp->options->options &= ~DHCPCD_STOPPING; | |
429 | 429 | |||
430 | if (!(ctx->options & (DHCPCD_MASTER | DHCPCD_TEST))) | 430 | if (!(ctx->options & (DHCPCD_MASTER | DHCPCD_TEST))) | |
431 | eloop_exit(ctx->eloop, EXIT_FAILURE); | 431 | eloop_exit(ctx->eloop, EXIT_FAILURE); | |
432 | } | 432 | } | |
433 | 433 | |||
434 | static void | 434 | static void | |
435 | configure_interface1(struct interface *ifp) | 435 | configure_interface1(struct interface *ifp) | |
436 | { | 436 | { | |
437 | struct if_options *ifo = ifp->options; | 437 | struct if_options *ifo = ifp->options; | |
438 | 438 | |||
439 | /* Do any platform specific configuration */ | 439 | /* Do any platform specific configuration */ | |
440 | if_conf(ifp); | 440 | if_conf(ifp); | |
441 | 441 | |||
442 | /* If we want to release a lease, we can't really persist the | 442 | /* If we want to release a lease, we can't really persist the | |
443 | * address either. */ | 443 | * address either. */ | |
444 | if (ifo->options & DHCPCD_RELEASE) | 444 | if (ifo->options & DHCPCD_RELEASE) | |
445 | ifo->options &= ~DHCPCD_PERSISTENT; | 445 | ifo->options &= ~DHCPCD_PERSISTENT; | |
446 | 446 | |||
447 | if (ifp->flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) { | 447 | if (ifp->flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) { | |
448 | ifo->options &= ~DHCPCD_ARP; | 448 | ifo->options &= ~DHCPCD_ARP; | |
449 | if (!(ifp->flags & IFF_MULTICAST)) | 449 | if (!(ifp->flags & IFF_MULTICAST)) | |
450 | ifo->options &= ~DHCPCD_IPV6RS; | 450 | ifo->options &= ~DHCPCD_IPV6RS; | |
451 | if (!(ifo->options & (DHCPCD_INFORM | DHCPCD_WANTDHCP))) | 451 | if (!(ifo->options & (DHCPCD_INFORM | DHCPCD_WANTDHCP))) | |
452 | ifo->options |= DHCPCD_STATIC; | 452 | ifo->options |= DHCPCD_STATIC; | |
453 | } | 453 | } | |
454 | 454 | |||
455 | if (ifo->metric != -1) | 455 | if (ifo->metric != -1) | |
456 | ifp->metric = (unsigned int)ifo->metric; | 456 | ifp->metric = (unsigned int)ifo->metric; | |
457 | 457 | |||
458 | #ifdef INET6 | 458 | #ifdef INET6 | |
459 | /* We want to setup INET6 on the interface as soon as possible. */ | 459 | /* We want to setup INET6 on the interface as soon as possible. */ | |
460 | if (ifp->active == IF_ACTIVE_USER && | 460 | if (ifp->active == IF_ACTIVE_USER && | |
461 | ifo->options & DHCPCD_IPV6 && | 461 | ifo->options & DHCPCD_IPV6 && | |
462 | !(ifp->ctx->options & (DHCPCD_DUMPLEASE | DHCPCD_TEST))) | 462 | !(ifp->ctx->options & (DHCPCD_DUMPLEASE | DHCPCD_TEST))) | |
463 | { | 463 | { | |
464 | /* If not doing any DHCP, disable the RDNSS requirement. */ | 464 | /* If not doing any DHCP, disable the RDNSS requirement. */ | |
465 | if (!(ifo->options & (DHCPCD_DHCP | DHCPCD_DHCP6))) | 465 | if (!(ifo->options & (DHCPCD_DHCP | DHCPCD_DHCP6))) | |
466 | ifo->options &= ~DHCPCD_IPV6RA_REQRDNSS; | 466 | ifo->options &= ~DHCPCD_IPV6RA_REQRDNSS; | |
467 | if_setup_inet6(ifp); | 467 | if_setup_inet6(ifp); | |
468 | } | 468 | } | |
469 | #endif | 469 | #endif | |
470 | 470 | |||
471 | if (!(ifo->options & DHCPCD_IAID)) { | 471 | if (!(ifo->options & DHCPCD_IAID)) { | |
472 | /* | 472 | /* | |
473 | * An IAID is for identifying a unqiue interface within | 473 | * An IAID is for identifying a unqiue interface within | |
474 | * the client. It is 4 bytes long. Working out a default | 474 | * the client. It is 4 bytes long. Working out a default | |
475 | * value is problematic. | 475 | * value is problematic. | |
476 | * | 476 | * | |
477 | * Interface name and number are not stable | 477 | * Interface name and number are not stable | |
478 | * between different OS's. Some OS's also cannot make | 478 | * between different OS's. Some OS's also cannot make | |
479 | * up their mind what the interface should be called | 479 | * up their mind what the interface should be called | |
480 | * (yes, udev, I'm looking at you). | 480 | * (yes, udev, I'm looking at you). | |
481 | * Also, the name could be longer than 4 bytes. | 481 | * Also, the name could be longer than 4 bytes. | |
482 | * Also, with pluggable interfaces the name and index | 482 | * Also, with pluggable interfaces the name and index | |
483 | * could easily get swapped per actual interface. | 483 | * could easily get swapped per actual interface. | |
484 | * | 484 | * | |
485 | * The MAC address is 6 bytes long, the final 3 | 485 | * The MAC address is 6 bytes long, the final 3 | |
486 | * being unique to the manufacturer and the initial 3 | 486 | * being unique to the manufacturer and the initial 3 | |
487 | * being unique to the organisation which makes it. | 487 | * being unique to the organisation which makes it. | |
488 | * We could use the last 4 bytes of the MAC address | 488 | * We could use the last 4 bytes of the MAC address | |
489 | * as the IAID as it's the most stable part given the | 489 | * as the IAID as it's the most stable part given the | |
490 | * above, but equally it's not guaranteed to be | 490 | * above, but equally it's not guaranteed to be | |
491 | * unique. | 491 | * unique. | |
492 | * | 492 | * | |
493 | * Given the above, and our need to reliably work | 493 | * Given the above, and our need to reliably work | |
494 | * between reboots without persitent storage, | 494 | * between reboots without persitent storage, | |
495 | * generating the IAID from the MAC address is the only | 495 | * generating the IAID from the MAC address is the only | |
496 | * logical default. | 496 | * logical default. | |
497 | * Saying that, if a VLANID has been specified then we | 497 | * Saying that, if a VLANID has been specified then we | |
498 | * can use that. It's possible that different interfaces | 498 | * can use that. It's possible that different interfaces | |
499 | * can have the same VLANID, but this is no worse than | 499 | * can have the same VLANID, but this is no worse than | |
500 | * generating the IAID from the duplicate MAC address. | 500 | * generating the IAID from the duplicate MAC address. | |
501 | * | 501 | * | |
502 | * dhclient uses the last 4 bytes of the MAC address. | 502 | * dhclient uses the last 4 bytes of the MAC address. | |
503 | * dibbler uses an increamenting counter. | 503 | * dibbler uses an increamenting counter. | |
504 | * wide-dhcpv6 uses 0 or a configured value. | 504 | * wide-dhcpv6 uses 0 or a configured value. | |
505 | * odhcp6c uses 1. | 505 | * odhcp6c uses 1. | |
506 | * Windows 7 uses the first 3 bytes of the MAC address | 506 | * Windows 7 uses the first 3 bytes of the MAC address | |
507 | * and an unknown byte. | 507 | * and an unknown byte. | |
508 | * dhcpcd-6.1.0 and earlier used the interface name, | 508 | * dhcpcd-6.1.0 and earlier used the interface name, | |
509 | * falling back to interface index if name > 4. | 509 | * falling back to interface index if name > 4. | |
510 | */ | 510 | */ | |
511 | if (ifp->vlanid != 0) { | 511 | if (ifp->vlanid != 0) { | |
512 | uint32_t vlanid; | 512 | uint32_t vlanid; | |
513 | 513 | |||
514 | /* Maximal VLANID is 4095, so prefix with 0xff | 514 | /* Maximal VLANID is 4095, so prefix with 0xff | |
515 | * so we don't conflict with an interface index. */ | 515 | * so we don't conflict with an interface index. */ | |
516 | vlanid = htonl(ifp->vlanid | 0xff000000); | 516 | vlanid = htonl(ifp->vlanid | 0xff000000); | |
517 | memcpy(ifo->iaid, &vlanid, sizeof(vlanid)); | 517 | memcpy(ifo->iaid, &vlanid, sizeof(vlanid)); | |
518 | } else if (ifo->options & DHCPCD_ANONYMOUS) | 518 | } else if (ifo->options & DHCPCD_ANONYMOUS) | |
519 | memset(ifo->iaid, 0, sizeof(ifo->iaid)); | 519 | memset(ifo->iaid, 0, sizeof(ifo->iaid)); | |
520 | else if (ifp->hwlen >= sizeof(ifo->iaid)) { | 520 | else if (ifp->hwlen >= sizeof(ifo->iaid)) { | |
521 | memcpy(ifo->iaid, | 521 | memcpy(ifo->iaid, | |
522 | ifp->hwaddr + ifp->hwlen - sizeof(ifo->iaid), | 522 | ifp->hwaddr + ifp->hwlen - sizeof(ifo->iaid), | |
523 | sizeof(ifo->iaid)); | 523 | sizeof(ifo->iaid)); | |
524 | } else { | 524 | } else { | |
525 | uint32_t len; | 525 | uint32_t len; | |
526 | 526 | |||
527 | len = (uint32_t)strlen(ifp->name); | 527 | len = (uint32_t)strlen(ifp->name); | |
528 | if (len <= sizeof(ifo->iaid)) { | 528 | if (len <= sizeof(ifo->iaid)) { | |
529 | memcpy(ifo->iaid, ifp->name, len); | 529 | memcpy(ifo->iaid, ifp->name, len); | |
530 | if (len < sizeof(ifo->iaid)) | 530 | if (len < sizeof(ifo->iaid)) | |
531 | memset(ifo->iaid + len, 0, | 531 | memset(ifo->iaid + len, 0, | |
532 | sizeof(ifo->iaid) - len); | 532 | sizeof(ifo->iaid) - len); | |
533 | } else { | 533 | } else { | |
534 | /* IAID is the same size as a uint32_t */ | 534 | /* IAID is the same size as a uint32_t */ | |
535 | len = htonl(ifp->index); | 535 | len = htonl(ifp->index); | |
536 | memcpy(ifo->iaid, &len, sizeof(ifo->iaid)); | 536 | memcpy(ifo->iaid, &len, sizeof(ifo->iaid)); | |
537 | } | 537 | } | |
538 | } | 538 | } | |
539 | ifo->options |= DHCPCD_IAID; | 539 | ifo->options |= DHCPCD_IAID; | |
540 | } | 540 | } | |
541 | 541 | |||
542 | #ifdef DHCP6 | 542 | #ifdef DHCP6 | |
543 | if (ifo->ia_len == 0 && ifo->options & DHCPCD_IPV6 && | 543 | if (ifo->ia_len == 0 && ifo->options & DHCPCD_IPV6 && | |
544 | ifp->name[0] != '\0') | 544 | ifp->name[0] != '\0') | |
545 | { | 545 | { | |
546 | ifo->ia = malloc(sizeof(*ifo->ia)); | 546 | ifo->ia = malloc(sizeof(*ifo->ia)); | |
547 | if (ifo->ia == NULL) | 547 | if (ifo->ia == NULL) | |
548 | logerr(__func__); | 548 | logerr(__func__); | |
549 | else { | 549 | else { | |
550 | ifo->ia_len = 1; | 550 | ifo->ia_len = 1; | |
551 | ifo->ia->ia_type = D6_OPTION_IA_NA; | 551 | ifo->ia->ia_type = D6_OPTION_IA_NA; | |
552 | memcpy(ifo->ia->iaid, ifo->iaid, sizeof(ifo->iaid)); | 552 | memcpy(ifo->ia->iaid, ifo->iaid, sizeof(ifo->iaid)); | |
553 | memset(&ifo->ia->addr, 0, sizeof(ifo->ia->addr)); | 553 | memset(&ifo->ia->addr, 0, sizeof(ifo->ia->addr)); | |
554 | #ifndef SMALL | 554 | #ifndef SMALL | |
555 | ifo->ia->sla = NULL; | 555 | ifo->ia->sla = NULL; | |
556 | ifo->ia->sla_len = 0; | 556 | ifo->ia->sla_len = 0; | |
557 | #endif | 557 | #endif | |
558 | } | 558 | } | |
559 | } else { | 559 | } else { | |
560 | size_t i; | 560 | size_t i; | |
561 | 561 | |||
562 | for (i = 0; i < ifo->ia_len; i++) { | 562 | for (i = 0; i < ifo->ia_len; i++) { | |
563 | if (!ifo->ia[i].iaid_set) { | 563 | if (!ifo->ia[i].iaid_set) { | |
564 | memcpy(&ifo->ia[i].iaid, ifo->iaid, | 564 | memcpy(&ifo->ia[i].iaid, ifo->iaid, | |
565 | sizeof(ifo->ia[i].iaid)); | 565 | sizeof(ifo->ia[i].iaid)); | |
566 | ifo->ia[i].iaid_set = 1; | 566 | ifo->ia[i].iaid_set = 1; | |
567 | } | 567 | } | |
568 | } | 568 | } | |
569 | } | 569 | } | |
570 | #endif | 570 | #endif | |
571 | 571 | |||
572 | /* If root is network mounted, we don't want to kill the connection | 572 | /* If root is network mounted, we don't want to kill the connection | |
573 | * if the DHCP server goes the way of the dodo OR dhcpcd is rebooting | 573 | * if the DHCP server goes the way of the dodo OR dhcpcd is rebooting | |
574 | * and the lease file has expired. */ | 574 | * and the lease file has expired. */ | |
575 | if (is_root_local() == 0) | 575 | if (is_root_local() == 0) | |
576 | ifo->options |= DHCPCD_LASTLEASE_EXTEND; | 576 | ifo->options |= DHCPCD_LASTLEASE_EXTEND; | |
577 | } | 577 | } | |
578 | 578 | |||
579 | int | 579 | int | |
580 | dhcpcd_selectprofile(struct interface *ifp, const char *profile) | 580 | dhcpcd_selectprofile(struct interface *ifp, const char *profile) | |
581 | { | 581 | { | |
582 | struct if_options *ifo; | 582 | struct if_options *ifo; | |
583 | char pssid[PROFILE_LEN]; | 583 | char pssid[PROFILE_LEN]; | |
584 | 584 | |||
585 | if (ifp->ssid_len) { | 585 | if (ifp->ssid_len) { | |
586 | ssize_t r; | 586 | ssize_t r; | |
587 | 587 | |||
588 | r = print_string(pssid, sizeof(pssid), OT_ESCSTRING, | 588 | r = print_string(pssid, sizeof(pssid), OT_ESCSTRING, | |
589 | ifp->ssid, ifp->ssid_len); | 589 | ifp->ssid, ifp->ssid_len); | |
590 | if (r == -1) { | 590 | if (r == -1) { | |
591 | logerr(__func__); | 591 | logerr(__func__); | |
592 | pssid[0] = '\0'; | 592 | pssid[0] = '\0'; | |
593 | } | 593 | } | |
594 | } else | 594 | } else | |
595 | pssid[0] = '\0'; | 595 | pssid[0] = '\0'; | |
596 | ifo = read_config(ifp->ctx, ifp->name, pssid, profile); | 596 | ifo = read_config(ifp->ctx, ifp->name, pssid, profile); | |
597 | if (ifo == NULL) { | 597 | if (ifo == NULL) { | |
598 | logdebugx("%s: no profile %s", ifp->name, profile); | 598 | logdebugx("%s: no profile %s", ifp->name, profile); | |
599 | return -1; | 599 | return -1; | |
600 | } | 600 | } | |
601 | if (profile != NULL) { | 601 | if (profile != NULL) { | |
602 | strlcpy(ifp->profile, profile, sizeof(ifp->profile)); | 602 | strlcpy(ifp->profile, profile, sizeof(ifp->profile)); | |
603 | loginfox("%s: selected profile %s", ifp->name, profile); | 603 | loginfox("%s: selected profile %s", ifp->name, profile); | |
604 | } else | 604 | } else | |
605 | *ifp->profile = '\0'; | 605 | *ifp->profile = '\0'; | |
606 | 606 | |||
607 | free_options(ifp->ctx, ifp->options); | 607 | free_options(ifp->ctx, ifp->options); | |
608 | ifp->options = ifo; | 608 | ifp->options = ifo; | |
609 | if (profile) { | 609 | if (profile) { | |
610 | add_options(ifp->ctx, ifp->name, ifp->options, | 610 | add_options(ifp->ctx, ifp->name, ifp->options, | |
611 | ifp->ctx->argc, ifp->ctx->argv); | 611 | ifp->ctx->argc, ifp->ctx->argv); | |
612 | configure_interface1(ifp); | 612 | configure_interface1(ifp); | |
613 | } | 613 | } | |
614 | return 1; | 614 | return 1; | |
615 | } | 615 | } | |
616 | 616 | |||
617 | static void | 617 | static void | |
618 | configure_interface(struct interface *ifp, int argc, char **argv, | 618 | configure_interface(struct interface *ifp, int argc, char **argv, | |
619 | unsigned long long options) | 619 | unsigned long long options) | |
620 | { | 620 | { | |
621 | time_t old; | 621 | time_t old; | |
622 | 622 | |||
623 | old = ifp->options ? ifp->options->mtime : 0; | 623 | old = ifp->options ? ifp->options->mtime : 0; | |
624 | dhcpcd_selectprofile(ifp, NULL); | 624 | dhcpcd_selectprofile(ifp, NULL); | |
625 | if (ifp->options == NULL) { | 625 | if (ifp->options == NULL) { | |
626 | /* dhcpcd cannot continue with this interface. */ | 626 | /* dhcpcd cannot continue with this interface. */ | |
627 | ifp->active = IF_INACTIVE; | 627 | ifp->active = IF_INACTIVE; | |
628 | return; | 628 | return; | |
629 | } | 629 | } | |
630 | add_options(ifp->ctx, ifp->name, ifp->options, argc, argv); | 630 | add_options(ifp->ctx, ifp->name, ifp->options, argc, argv); | |
631 | ifp->options->options |= options; | 631 | ifp->options->options |= options; | |
632 | configure_interface1(ifp); | 632 | configure_interface1(ifp); | |
633 | 633 | |||
634 | /* If the mtime has changed drop any old lease */ | 634 | /* If the mtime has changed drop any old lease */ | |
635 | if (old != 0 && ifp->options->mtime != old) { | 635 | if (old != 0 && ifp->options->mtime != old) { | |
636 | logwarnx("%s: config file changed, expiring leases", | 636 | logwarnx("%s: config file changed, expiring leases", | |
637 | ifp->name); | 637 | ifp->name); | |
638 | dhcpcd_drop(ifp, 0); | 638 | dhcpcd_drop(ifp, 0); | |
639 | } | 639 | } | |
640 | } | 640 | } | |
641 | 641 | |||
642 | static void | 642 | static void | |
643 | dhcpcd_initstate2(struct interface *ifp, unsigned long long options) | 643 | dhcpcd_initstate2(struct interface *ifp, unsigned long long options) | |
644 | { | 644 | { | |
645 | struct if_options *ifo; | 645 | struct if_options *ifo; | |
646 | 646 | |||
647 | if (options) { | 647 | if (options) { | |
648 | if ((ifo = default_config(ifp->ctx)) == NULL) { | 648 | if ((ifo = default_config(ifp->ctx)) == NULL) { | |
649 | logerr(__func__); | 649 | logerr(__func__); | |
650 | return; | 650 | return; | |
651 | } | 651 | } | |
652 | ifo->options |= options; | 652 | ifo->options |= options; | |
653 | free(ifp->options); | 653 | free(ifp->options); | |
654 | ifp->options = ifo; | 654 | ifp->options = ifo; | |
655 | } else | 655 | } else | |
656 | ifo = ifp->options; | 656 | ifo = ifp->options; | |
657 | 657 | |||
658 | #ifdef INET6 | 658 | #ifdef INET6 | |
659 | if (ifo->options & DHCPCD_IPV6 && ipv6_init(ifp->ctx) == -1) { | 659 | if (ifo->options & DHCPCD_IPV6 && ipv6_init(ifp->ctx) == -1) { | |
660 | logerr(__func__); | 660 | logerr(__func__); | |
661 | ifo->options &= ~DHCPCD_IPV6; | 661 | ifo->options &= ~DHCPCD_IPV6; | |
662 | } | 662 | } | |
663 | #endif | 663 | #endif | |
664 | } | 664 | } | |
665 | 665 | |||
666 | static void | 666 | static void | |
667 | dhcpcd_initstate1(struct interface *ifp, int argc, char **argv, | 667 | dhcpcd_initstate1(struct interface *ifp, int argc, char **argv, | |
668 | unsigned long long options) | 668 | unsigned long long options) | |
669 | { | 669 | { | |
670 | 670 | |||
671 | configure_interface(ifp, argc, argv, options); | 671 | configure_interface(ifp, argc, argv, options); | |
672 | if (ifp->active) | 672 | if (ifp->active) | |
673 | dhcpcd_initstate2(ifp, 0); | 673 | dhcpcd_initstate2(ifp, 0); | |
674 | } | 674 | } | |
675 | 675 | |||
676 | static void | 676 | static void | |
677 | dhcpcd_initstate(struct interface *ifp, unsigned long long options) | 677 | dhcpcd_initstate(struct interface *ifp, unsigned long long options) | |
678 | { | 678 | { | |
679 | 679 | |||
680 | dhcpcd_initstate1(ifp, ifp->ctx->argc, ifp->ctx->argv, options); | 680 | dhcpcd_initstate1(ifp, ifp->ctx->argc, ifp->ctx->argv, options); | |
681 | } | 681 | } | |
682 | 682 | |||
683 | static void | 683 | static void | |
684 | dhcpcd_reportssid(struct interface *ifp) | 684 | dhcpcd_reportssid(struct interface *ifp) | |
685 | { | 685 | { | |
686 | char pssid[IF_SSIDLEN * 4]; | 686 | char pssid[IF_SSIDLEN * 4]; | |
687 | 687 | |||
688 | if (print_string(pssid, sizeof(pssid), OT_ESCSTRING, | 688 | if (print_string(pssid, sizeof(pssid), OT_ESCSTRING, | |
689 | ifp->ssid, ifp->ssid_len) == -1) | 689 | ifp->ssid, ifp->ssid_len) == -1) | |
690 | { | 690 | { | |
691 | logerr(__func__); | 691 | logerr(__func__); | |
692 | return; | 692 | return; | |
693 | } | 693 | } | |
694 | 694 | |||
695 | loginfox("%s: connected to Access Point: %s", ifp->name, pssid); | 695 | loginfox("%s: connected to Access Point: %s", ifp->name, pssid); | |
696 | } | 696 | } | |
697 | 697 | |||
698 | void | 698 | void | |
699 | dhcpcd_handlecarrier(struct interface *ifp, int carrier, unsigned int flags) | 699 | dhcpcd_handlecarrier(struct interface *ifp, int carrier, unsigned int flags) | |
700 | { | 700 | { | |
701 | bool was_link_up = if_is_link_up(ifp); | 701 | bool was_link_up = if_is_link_up(ifp); | |
702 | 702 | |||
703 | ifp->carrier = carrier; | 703 | ifp->carrier = carrier; | |
704 | ifp->flags = flags; | 704 | ifp->flags = flags; | |
705 | 705 | |||
706 | if (!if_is_link_up(ifp)) { | 706 | if (!if_is_link_up(ifp)) { | |
707 | if (!was_link_up || !ifp->active) | 707 | if (!was_link_up || !ifp->active) | |
708 | return; | 708 | return; | |
709 | loginfox("%s: carrier lost", ifp->name); | 709 | loginfox("%s: carrier lost", ifp->name); | |
710 | script_runreason(ifp, "NOCARRIER"); | 710 | script_runreason(ifp, "NOCARRIER"); | |
711 | #ifdef NOCARRIER_PRESERVE_IP | 711 | #ifdef NOCARRIER_PRESERVE_IP | |
712 | if (ifp->flags & IFF_UP && | 712 | if (ifp->flags & IFF_UP && | |
713 | !(ifp->options->options & DHCPCD_ANONYMOUS)) | 713 | !(ifp->options->options & DHCPCD_ANONYMOUS)) | |
714 | { | 714 | { | |
715 | #ifdef ARP | 715 | #ifdef ARP | |
716 | arp_drop(ifp); | 716 | arp_drop(ifp); | |
717 | #endif | 717 | #endif | |
718 | #ifdef INET | 718 | #ifdef INET | |
719 | dhcp_abort(ifp); | 719 | dhcp_abort(ifp); | |
720 | #endif | 720 | #endif | |
721 | #ifdef DHCP6 | 721 | #ifdef DHCP6 | |
722 | dhcp6_abort(ifp); | 722 | dhcp6_abort(ifp); | |
723 | #endif | 723 | #endif | |
724 | } else | 724 | } else | |
725 | #endif | 725 | #endif | |
726 | dhcpcd_drop(ifp, 0); | 726 | dhcpcd_drop(ifp, 0); | |
727 | if (ifp->options->options & DHCPCD_ANONYMOUS) { | 727 | if (ifp->options->options & DHCPCD_ANONYMOUS) { | |
728 | bool is_up = ifp->flags & IFF_UP; | 728 | bool is_up = ifp->flags & IFF_UP; | |
729 | 729 | |||
730 | if (is_up) | 730 | if (is_up) | |
731 | if_down(ifp); | 731 | if_down(ifp); | |
732 | if (if_randomisemac(ifp) == -1 && errno != ENXIO) | 732 | if (if_randomisemac(ifp) == -1 && errno != ENXIO) | |
733 | logerr(__func__); | 733 | logerr(__func__); | |
734 | if (is_up) | 734 | if (is_up) | |
735 | if_up(ifp); | 735 | if_up(ifp); | |
736 | } | 736 | } | |
737 | return; | 737 | return; | |
738 | } | 738 | } | |
739 | 739 | |||
740 | /* | 740 | /* | |
741 | * At this point carrier is NOT DOWN and we have IFF_UP. | 741 | * At this point carrier is NOT DOWN and we have IFF_UP. | |
742 | * We should treat LINK_UNKNOWN as up as the driver may not support | 742 | * We should treat LINK_UNKNOWN as up as the driver may not support | |
743 | * link state changes. | 743 | * link state changes. | |
744 | * The consideration of any other information about carrier should | 744 | * The consideration of any other information about carrier should | |
745 | * be handled in the OS specific if_carrier() function. | 745 | * be handled in the OS specific if_carrier() function. | |
746 | */ | 746 | */ | |
747 | if (was_link_up) | 747 | if (was_link_up) | |
748 | return; | 748 | return; | |
749 | 749 | |||
750 | if (ifp->active) { | 750 | if (ifp->active) { | |
751 | if (carrier == LINK_UNKNOWN) | 751 | if (carrier == LINK_UNKNOWN) | |
752 | loginfox("%s: carrier unknown, assuming up", ifp->name); | 752 | loginfox("%s: carrier unknown, assuming up", ifp->name); | |
753 | else | 753 | else | |
754 | loginfox("%s: carrier acquired", ifp->name); | 754 | loginfox("%s: carrier acquired", ifp->name); | |
755 | } | 755 | } | |
756 | 756 | |||
757 | #if !defined(__linux__) && !defined(__NetBSD__) | 757 | #if !defined(__linux__) && !defined(__NetBSD__) | |
758 | /* BSD does not emit RTM_NEWADDR or RTM_CHGADDR when the | 758 | /* BSD does not emit RTM_NEWADDR or RTM_CHGADDR when the | |
759 | * hardware address changes so we have to go | 759 | * hardware address changes so we have to go | |
760 | * through the disovery process to work it out. */ | 760 | * through the disovery process to work it out. */ | |
761 | dhcpcd_handleinterface(ifp->ctx, 0, ifp->name); | 761 | dhcpcd_handleinterface(ifp->ctx, 0, ifp->name); | |
762 | #endif | 762 | #endif | |
763 | 763 | |||
764 | if (ifp->wireless) { | 764 | if (ifp->wireless) { | |
765 | uint8_t ossid[IF_SSIDLEN]; | 765 | uint8_t ossid[IF_SSIDLEN]; | |
766 | size_t olen; | 766 | size_t olen; | |
767 | 767 | |||
768 | olen = ifp->ssid_len; | 768 | olen = ifp->ssid_len; | |
769 | memcpy(ossid, ifp->ssid, ifp->ssid_len); | 769 | memcpy(ossid, ifp->ssid, ifp->ssid_len); | |
770 | if_getssid(ifp); | 770 | if_getssid(ifp); | |
771 | 771 | |||
772 | /* If we changed SSID network, drop leases */ | 772 | /* If we changed SSID network, drop leases */ | |
773 | if ((ifp->ssid_len != olen || | 773 | if ((ifp->ssid_len != olen || | |
774 | memcmp(ifp->ssid, ossid, ifp->ssid_len)) && ifp->active) | 774 | memcmp(ifp->ssid, ossid, ifp->ssid_len)) && ifp->active) | |
775 | { | 775 | { | |
776 | dhcpcd_reportssid(ifp); | 776 | dhcpcd_reportssid(ifp); | |
777 | #ifdef NOCARRIER_PRESERVE_IP | 777 | #ifdef NOCARRIER_PRESERVE_IP | |
778 | dhcpcd_drop(ifp, 0); | 778 | dhcpcd_drop(ifp, 0); | |
779 | #endif | 779 | #endif | |
780 | #ifdef IPV4LL | 780 | #ifdef IPV4LL | |
781 | ipv4ll_reset(ifp); | 781 | ipv4ll_reset(ifp); | |
782 | #endif | 782 | #endif | |
783 | } | 783 | } | |
784 | } | 784 | } | |
785 | 785 | |||
786 | if (!ifp->active) | 786 | if (!ifp->active) | |
787 | return; | 787 | return; | |
788 | 788 | |||
789 | dhcpcd_initstate(ifp, 0); | 789 | dhcpcd_initstate(ifp, 0); | |
790 | script_runreason(ifp, "CARRIER"); | 790 | script_runreason(ifp, "CARRIER"); | |
791 | #ifdef INET6 | 791 | #ifdef INET6 | |
792 | #ifdef NOCARRIER_PRESERVE_IP | 792 | #ifdef NOCARRIER_PRESERVE_IP | |
793 | /* Set any IPv6 Routers we remembered to expire faster than they | 793 | /* Set any IPv6 Routers we remembered to expire faster than they | |
794 | * would normally as we maybe on a new network. */ | 794 | * would normally as we maybe on a new network. */ | |
795 | ipv6nd_startexpire(ifp); | 795 | ipv6nd_startexpire(ifp); | |
796 | #endif | 796 | #endif | |
797 | #ifdef IPV6_MANAGETEMPADDR | 797 | #ifdef IPV6_MANAGETEMPADDR | |
798 | /* RFC4941 Section 3.5 */ | 798 | /* RFC4941 Section 3.5 */ | |
799 | ipv6_regentempaddrs(ifp); | 799 | ipv6_regentempaddrs(ifp); | |
800 | #endif | 800 | #endif | |
801 | #endif | 801 | #endif | |
802 | dhcpcd_startinterface(ifp); | 802 | dhcpcd_startinterface(ifp); | |
803 | } | 803 | } | |
804 | 804 | |||
805 | static void | 805 | static void | |
806 | warn_iaid_conflict(struct interface *ifp, uint16_t ia_type, uint8_t *iaid) | 806 | warn_iaid_conflict(struct interface *ifp, uint16_t ia_type, uint8_t *iaid) | |
807 | { | 807 | { | |
808 | struct interface *ifn; | 808 | struct interface *ifn; | |
809 | #ifdef INET6 | 809 | #ifdef INET6 | |
810 | size_t i; | 810 | size_t i; | |
811 | struct if_ia *ia; | 811 | struct if_ia *ia; | |
812 | #endif | 812 | #endif | |
813 | 813 | |||
814 | TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) { | 814 | TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) { | |
815 | if (ifn == ifp || !ifn->active) | 815 | if (ifn == ifp || !ifn->active) | |
816 | continue; | 816 | continue; | |
817 | if (ifn->options->options & DHCPCD_ANONYMOUS) | 817 | if (ifn->options->options & DHCPCD_ANONYMOUS) | |
818 | continue; | 818 | continue; | |
819 | if (ia_type == 0 && | 819 | if (ia_type == 0 && | |
820 | memcmp(ifn->options->iaid, iaid, | 820 | memcmp(ifn->options->iaid, iaid, | |
821 | sizeof(ifn->options->iaid)) == 0) | 821 | sizeof(ifn->options->iaid)) == 0) | |
822 | break; | 822 | break; | |
823 | #ifdef INET6 | 823 | #ifdef INET6 | |
824 | for (i = 0; i < ifn->options->ia_len; i++) { | 824 | for (i = 0; i < ifn->options->ia_len; i++) { | |
825 | ia = &ifn->options->ia[i]; | 825 | ia = &ifn->options->ia[i]; | |
826 | if (ia->ia_type == ia_type && | 826 | if (ia->ia_type == ia_type && | |
827 | memcmp(ia->iaid, iaid, sizeof(ia->iaid)) == 0) | 827 | memcmp(ia->iaid, iaid, sizeof(ia->iaid)) == 0) | |
828 | break; | 828 | break; | |
829 | } | 829 | } | |
830 | #endif | 830 | #endif | |
831 | } | 831 | } | |
832 | 832 | |||
833 | /* This is only a problem if the interfaces are on the same network. */ | 833 | /* This is only a problem if the interfaces are on the same network. */ | |
834 | if (ifn) | 834 | if (ifn) | |
835 | logerrx("%s: IAID conflicts with one assigned to %s", | 835 | logerrx("%s: IAID conflicts with one assigned to %s", | |
836 | ifp->name, ifn->name); | 836 | ifp->name, ifn->name); | |
837 | } | 837 | } | |
838 | 838 | |||
839 | static void | 839 | static void | |
840 | dhcpcd_initduid(struct dhcpcd_ctx *ctx, struct interface *ifp) | 840 | dhcpcd_initduid(struct dhcpcd_ctx *ctx, struct interface *ifp) | |
841 | { | 841 | { | |
842 | char buf[DUID_LEN * 3]; | 842 | char buf[DUID_LEN * 3]; | |
843 | 843 | |||
844 | if (ctx->duid != NULL) | 844 | if (ctx->duid != NULL) | |
845 | return; | 845 | return; | |
846 | 846 | |||
847 | duid_init(ctx, ifp); | 847 | duid_init(ctx, ifp); | |
848 | if (ctx->duid == NULL) | 848 | if (ctx->duid == NULL) | |
849 | return; | 849 | return; | |
850 | 850 | |||
851 | loginfox("DUID %s", | 851 | loginfox("DUID %s", | |
852 | hwaddr_ntoa(ctx->duid, ctx->duid_len, buf, sizeof(buf))); | 852 | hwaddr_ntoa(ctx->duid, ctx->duid_len, buf, sizeof(buf))); | |
853 | } | 853 | } | |
854 | 854 | |||
855 | void | 855 | void | |
856 | dhcpcd_startinterface(void *arg) | 856 | dhcpcd_startinterface(void *arg) | |
857 | { | 857 | { | |
858 | struct interface *ifp = arg; | 858 | struct interface *ifp = arg; | |
859 | struct if_options *ifo = ifp->options; | 859 | struct if_options *ifo = ifp->options; | |
860 | 860 | |||
861 | if (ifo->options & DHCPCD_LINK && !if_is_link_up(ifp)) { | 861 | if (ifo->options & DHCPCD_LINK && !if_is_link_up(ifp)) { | |
862 | loginfox("%s: waiting for carrier", ifp->name); | 862 | loginfox("%s: waiting for carrier", ifp->name); | |
863 | return; | 863 | return; | |
864 | } | 864 | } | |
865 | 865 | |||
866 | if (ifo->options & (DHCPCD_DUID | DHCPCD_IPV6) && | 866 | if (ifo->options & (DHCPCD_DUID | DHCPCD_IPV6) && | |
867 | !(ifo->options & DHCPCD_ANONYMOUS)) | 867 | !(ifo->options & DHCPCD_ANONYMOUS)) | |
868 | { | 868 | { | |
869 | char buf[sizeof(ifo->iaid) * 3]; | 869 | char buf[sizeof(ifo->iaid) * 3]; | |
870 | #ifdef INET6 | 870 | #ifdef INET6 | |
871 | size_t i; | 871 | size_t i; | |
872 | struct if_ia *ia; | 872 | struct if_ia *ia; | |
873 | #endif | 873 | #endif | |
874 | 874 | |||
875 | /* Try and init DUID from the interface hardware address */ | 875 | /* Try and init DUID from the interface hardware address */ | |
876 | dhcpcd_initduid(ifp->ctx, ifp); | 876 | dhcpcd_initduid(ifp->ctx, ifp); | |
877 | 877 | |||
878 | /* Report IAIDs */ | 878 | /* Report IAIDs */ | |
879 | loginfox("%s: IAID %s", ifp->name, | 879 | loginfox("%s: IAID %s", ifp->name, | |
880 | hwaddr_ntoa(ifo->iaid, sizeof(ifo->iaid), | 880 | hwaddr_ntoa(ifo->iaid, sizeof(ifo->iaid), | |
881 | buf, sizeof(buf))); | 881 | buf, sizeof(buf))); | |
882 | warn_iaid_conflict(ifp, 0, ifo->iaid); | 882 | warn_iaid_conflict(ifp, 0, ifo->iaid); | |
883 | 883 | |||
884 | #ifdef INET6 | 884 | #ifdef INET6 | |
885 | for (i = 0; i < ifo->ia_len; i++) { | 885 | for (i = 0; i < ifo->ia_len; i++) { | |
886 | ia = &ifo->ia[i]; | 886 | ia = &ifo->ia[i]; | |
887 | if (memcmp(ifo->iaid, ia->iaid, sizeof(ifo->iaid))) { | 887 | if (memcmp(ifo->iaid, ia->iaid, sizeof(ifo->iaid))) { | |
888 | loginfox("%s: IA type %u IAID %s", | 888 | loginfox("%s: IA type %u IAID %s", | |
889 | ifp->name, ia->ia_type, | 889 | ifp->name, ia->ia_type, | |
890 | hwaddr_ntoa(ia->iaid, sizeof(ia->iaid), | 890 | hwaddr_ntoa(ia->iaid, sizeof(ia->iaid), | |
891 | buf, sizeof(buf))); | 891 | buf, sizeof(buf))); | |
892 | warn_iaid_conflict(ifp, ia->ia_type, ia->iaid); | 892 | warn_iaid_conflict(ifp, ia->ia_type, ia->iaid); | |
893 | } | 893 | } | |
894 | } | 894 | } | |
895 | #endif | 895 | #endif | |
896 | } | 896 | } | |
897 | 897 | |||
898 | #ifdef INET6 | 898 | #ifdef INET6 | |
899 | if (ifo->options & DHCPCD_IPV6 && ipv6_start(ifp) == -1) { | 899 | if (ifo->options & DHCPCD_IPV6 && ipv6_start(ifp) == -1) { | |
900 | logerr("%s: ipv6_start", ifp->name); | 900 | logerr("%s: ipv6_start", ifp->name); | |
901 | ifo->options &= ~DHCPCD_IPV6; | 901 | ifo->options &= ~DHCPCD_IPV6; | |
902 | } | 902 | } | |
903 | 903 | |||
904 | if (ifo->options & DHCPCD_IPV6) { | 904 | if (ifo->options & DHCPCD_IPV6) { | |
905 | if (ifp->active == IF_ACTIVE_USER) { | 905 | if (ifp->active == IF_ACTIVE_USER) { | |
906 | ipv6_startstatic(ifp); | 906 | ipv6_startstatic(ifp); | |
907 | 907 | |||
908 | if (ifo->options & DHCPCD_IPV6RS) | 908 | if (ifo->options & DHCPCD_IPV6RS) | |
909 | ipv6nd_startrs(ifp); | 909 | ipv6nd_startrs(ifp); | |
910 | } | 910 | } | |
911 | 911 | |||
912 | #ifdef DHCP6 | 912 | #ifdef DHCP6 | |
913 | /* DHCPv6 could be turned off, but the interface | 913 | /* DHCPv6 could be turned off, but the interface | |
914 | * is still delegated to. */ | 914 | * is still delegated to. */ | |
915 | if (ifp->active) | 915 | if (ifp->active) | |
916 | dhcp6_find_delegates(ifp); | 916 | dhcp6_find_delegates(ifp); | |
917 | 917 | |||
918 | if (ifo->options & DHCPCD_DHCP6) { | 918 | if (ifo->options & DHCPCD_DHCP6) { | |
919 | if (ifp->active == IF_ACTIVE_USER) { | 919 | if (ifp->active == IF_ACTIVE_USER) { | |
920 | enum DH6S d6_state; | 920 | enum DH6S d6_state; | |
921 | 921 | |||
922 | if (ifo->options & DHCPCD_IA_FORCED) | 922 | if (ifo->options & DHCPCD_IA_FORCED) | |
923 | d6_state = DH6S_INIT; | 923 | d6_state = DH6S_INIT; | |
924 | else if (ifo->options & DHCPCD_INFORM6) | 924 | else if (ifo->options & DHCPCD_INFORM6) | |
925 | d6_state = DH6S_INFORM; | 925 | d6_state = DH6S_INFORM; | |
926 | else | 926 | else | |
927 | d6_state = DH6S_CONFIRM; | 927 | d6_state = DH6S_CONFIRM; | |
928 | if (dhcp6_start(ifp, d6_state) == -1) | 928 | if (dhcp6_start(ifp, d6_state) == -1) | |
929 | logerr("%s: dhcp6_start", ifp->name); | 929 | logerr("%s: dhcp6_start", ifp->name); | |
930 | } | 930 | } | |
931 | } | 931 | } | |
932 | #endif | 932 | #endif | |
933 | } | 933 | } | |
934 | #endif | 934 | #endif | |
935 | 935 | |||
936 | #ifdef INET | 936 | #ifdef INET | |
937 | if (ifo->options & DHCPCD_IPV4 && ifp->active == IF_ACTIVE_USER) { | 937 | if (ifo->options & DHCPCD_IPV4 && ifp->active == IF_ACTIVE_USER) { | |
938 | /* Ensure we have an IPv4 state before starting DHCP */ | 938 | /* Ensure we have an IPv4 state before starting DHCP */ | |
939 | if (ipv4_getstate(ifp) != NULL) | 939 | if (ipv4_getstate(ifp) != NULL) | |
940 | dhcp_start(ifp); | 940 | dhcp_start(ifp); | |
941 | } | 941 | } | |
942 | #endif | 942 | #endif | |
943 | } | 943 | } | |
944 | 944 | |||
945 | static void | 945 | static void | |
946 | dhcpcd_prestartinterface(void *arg) | 946 | dhcpcd_prestartinterface(void *arg) | |
947 | { | 947 | { | |
948 | struct interface *ifp = arg; | 948 | struct interface *ifp = arg; | |
949 | struct dhcpcd_ctx *ctx = ifp->ctx; | 949 | struct dhcpcd_ctx *ctx = ifp->ctx; | |
950 | bool anondown; | 950 | bool anondown; | |
951 | 951 | |||
952 | if (ifp->carrier <= LINK_DOWN && | 952 | if (ifp->carrier <= LINK_DOWN && | |
953 | ifp->options->options & DHCPCD_ANONYMOUS && | 953 | ifp->options->options & DHCPCD_ANONYMOUS && | |
954 | ifp->flags & IFF_UP) | 954 | ifp->flags & IFF_UP) | |
955 | { | 955 | { | |
956 | if_down(ifp); | 956 | if_down(ifp); | |
957 | anondown = true; | 957 | anondown = true; | |
958 | } else | 958 | } else | |
959 | anondown = false; | 959 | anondown = false; | |
960 | 960 | |||
961 | if ((!(ctx->options & DHCPCD_MASTER) || | 961 | if ((!(ctx->options & DHCPCD_MASTER) || | |
962 | ifp->options->options & DHCPCD_IF_UP || anondown) && | 962 | ifp->options->options & DHCPCD_IF_UP || anondown) && | |
963 | !(ifp->flags & IFF_UP)) | 963 | !(ifp->flags & IFF_UP)) | |
964 | { | 964 | { | |
965 | if (ifp->options->options & DHCPCD_ANONYMOUS && | 965 | if (ifp->options->options & DHCPCD_ANONYMOUS && | |
966 | if_randomisemac(ifp) == -1) | 966 | if_randomisemac(ifp) == -1) | |
967 | logerr(__func__); | 967 | logerr(__func__); | |
968 | if (if_up(ifp) == -1) | 968 | if (if_up(ifp) == -1) | |
969 | logerr(__func__); | 969 | logerr(__func__); | |
970 | } | 970 | } | |
971 | 971 | |||
972 | dhcpcd_startinterface(ifp); | 972 | dhcpcd_startinterface(ifp); | |
973 | } | 973 | } | |
974 | 974 | |||
975 | static void | 975 | static void | |
976 | run_preinit(struct interface *ifp) | 976 | run_preinit(struct interface *ifp) | |
977 | { | 977 | { | |
978 | 978 | |||
979 | if (ifp->ctx->options & DHCPCD_TEST) | 979 | if (ifp->ctx->options & DHCPCD_TEST) | |
980 | return; | 980 | return; | |
981 | 981 | |||
982 | script_runreason(ifp, "PREINIT"); | 982 | script_runreason(ifp, "PREINIT"); | |
983 | if (ifp->wireless && if_is_link_up(ifp)) | 983 | if (ifp->wireless && if_is_link_up(ifp)) | |
984 | dhcpcd_reportssid(ifp); | 984 | dhcpcd_reportssid(ifp); | |
985 | if (ifp->options->options & DHCPCD_LINK && ifp->carrier != LINK_UNKNOWN) | 985 | if (ifp->options->options & DHCPCD_LINK && ifp->carrier != LINK_UNKNOWN) | |
986 | script_runreason(ifp, | 986 | script_runreason(ifp, | |
987 | ifp->carrier == LINK_UP ? "CARRIER" : "NOCARRIER"); | 987 | ifp->carrier == LINK_UP ? "CARRIER" : "NOCARRIER"); | |
988 | } | 988 | } | |
989 | 989 | |||
990 | void | 990 | void | |
991 | dhcpcd_activateinterface(struct interface *ifp, unsigned long long options) | 991 | dhcpcd_activateinterface(struct interface *ifp, unsigned long long options) | |
992 | { | 992 | { | |
993 | 993 | |||
994 | if (!ifp->active) { | 994 | if (!ifp->active) { | |
995 | ifp->active = IF_ACTIVE; | 995 | ifp->active = IF_ACTIVE; | |
996 | dhcpcd_initstate2(ifp, options); | 996 | dhcpcd_initstate2(ifp, options); | |
997 | /* It's possible we might not have been able to load | 997 | /* It's possible we might not have been able to load | |
998 | * a config. */ | 998 | * a config. */ | |
999 | if (ifp->active) { | 999 | if (ifp->active) { | |
1000 | configure_interface1(ifp); | 1000 | configure_interface1(ifp); | |
1001 | run_preinit(ifp); | 1001 | run_preinit(ifp); | |
1002 | dhcpcd_prestartinterface(ifp); | 1002 | dhcpcd_prestartinterface(ifp); | |
1003 | } | 1003 | } | |
1004 | } | 1004 | } | |
1005 | } | 1005 | } | |
1006 | 1006 | |||
1007 | int | 1007 | int | |
1008 | dhcpcd_handleinterface(void *arg, int action, const char *ifname) | 1008 | dhcpcd_handleinterface(void *arg, int action, const char *ifname) | |
1009 | { | 1009 | { | |
1010 | struct dhcpcd_ctx *ctx = arg; | 1010 | struct dhcpcd_ctx *ctx = arg; | |
1011 | struct ifaddrs *ifaddrs; | 1011 | struct ifaddrs *ifaddrs; | |
1012 | struct if_head *ifs; | 1012 | struct if_head *ifs; | |
1013 | struct interface *ifp, *iff; | 1013 | struct interface *ifp, *iff; | |
1014 | const char * const argv[] = { ifname }; | 1014 | const char * const argv[] = { ifname }; | |
1015 | int e; | 1015 | int e; | |
1016 | 1016 | |||
1017 | if (action == -1) { | 1017 | if (action == -1) { | |
1018 | ifp = if_find(ctx->ifaces, ifname); | 1018 | ifp = if_find(ctx->ifaces, ifname); | |
1019 | if (ifp == NULL) { | 1019 | if (ifp == NULL) { | |
1020 | errno = ESRCH; | 1020 | errno = ESRCH; | |
1021 | return -1; | 1021 | return -1; | |
1022 | } | 1022 | } | |
1023 | if (ifp->active) { | 1023 | if (ifp->active) { | |
1024 | logdebugx("%s: interface departed", ifp->name); | 1024 | logdebugx("%s: interface departed", ifp->name); | |
1025 | stop_interface(ifp, "DEPARTED"); | 1025 | stop_interface(ifp, "DEPARTED"); | |
1026 | } | 1026 | } | |
1027 | TAILQ_REMOVE(ctx->ifaces, ifp, next); | 1027 | TAILQ_REMOVE(ctx->ifaces, ifp, next); | |
1028 | if_free(ifp); | 1028 | if_free(ifp); | |
1029 | return 0; | 1029 | return 0; | |
1030 | } | 1030 | } | |
1031 | 1031 | |||
1032 | ifs = if_discover(ctx, &ifaddrs, -1, UNCONST(argv)); | 1032 | ifs = if_discover(ctx, &ifaddrs, -1, UNCONST(argv)); | |
1033 | if (ifs == NULL) { | 1033 | if (ifs == NULL) { | |
1034 | logerr(__func__); | 1034 | logerr(__func__); | |
1035 | return -1; | 1035 | return -1; | |
1036 | } | 1036 | } | |
1037 | 1037 | |||
1038 | ifp = if_find(ifs, ifname); | 1038 | ifp = if_find(ifs, ifname); | |
1039 | if (ifp == NULL) { | 1039 | if (ifp == NULL) { | |
1040 | /* This can happen if an interface is quickly added | 1040 | /* This can happen if an interface is quickly added | |
1041 | * and then removed. */ | 1041 | * and then removed. */ | |
1042 | errno = ENOENT; | 1042 | errno = ENOENT; | |
1043 | e = -1; | 1043 | e = -1; | |
1044 | goto out; | 1044 | goto out; | |
1045 | } | 1045 | } | |
1046 | e = 1; | 1046 | e = 1; | |
1047 | 1047 | |||
1048 | /* Check if we already have the interface */ | 1048 | /* Check if we already have the interface */ | |
1049 | iff = if_find(ctx->ifaces, ifp->name); | 1049 | iff = if_find(ctx->ifaces, ifp->name); | |
1050 | 1050 | |||
1051 | if (iff != NULL) { | 1051 | if (iff != NULL) { | |
1052 | if (iff->active) | 1052 | if (iff->active) | |
1053 | logdebugx("%s: interface updated", iff->name); | 1053 | logdebugx("%s: interface updated", iff->name); | |
1054 | /* The flags and hwaddr could have changed */ | 1054 | /* The flags and hwaddr could have changed */ | |
1055 | iff->flags = ifp->flags; | 1055 | iff->flags = ifp->flags; | |
1056 | iff->hwlen = ifp->hwlen; | 1056 | iff->hwlen = ifp->hwlen; | |
1057 | if (ifp->hwlen != 0) | 1057 | if (ifp->hwlen != 0) | |
1058 | memcpy(iff->hwaddr, ifp->hwaddr, iff->hwlen); | 1058 | memcpy(iff->hwaddr, ifp->hwaddr, iff->hwlen); | |
1059 | } else { | 1059 | } else { | |
1060 | TAILQ_REMOVE(ifs, ifp, next); | 1060 | TAILQ_REMOVE(ifs, ifp, next); | |
1061 | TAILQ_INSERT_TAIL(ctx->ifaces, ifp, next); | 1061 | TAILQ_INSERT_TAIL(ctx->ifaces, ifp, next); | |
1062 | if (ifp->active) { | 1062 | if (ifp->active) { | |
1063 | logdebugx("%s: interface added", ifp->name); | 1063 | logdebugx("%s: interface added", ifp->name); | |
1064 | dhcpcd_initstate(ifp, 0); | 1064 | dhcpcd_initstate(ifp, 0); | |
1065 | run_preinit(ifp); | 1065 | run_preinit(ifp); | |
1066 | } | 1066 | } | |
1067 | iff = ifp; | 1067 | iff = ifp; | |
1068 | } | 1068 | } | |
1069 | 1069 | |||
1070 | if (action > 0) { | 1070 | if (action > 0) { | |
1071 | if_learnaddrs(ctx, ifs, &ifaddrs); | 1071 | if_learnaddrs(ctx, ifs, &ifaddrs); | |
1072 | if (iff->active) | 1072 | if (iff->active) | |
1073 | dhcpcd_prestartinterface(iff); | 1073 | dhcpcd_prestartinterface(iff); | |
1074 | } | 1074 | } | |
1075 | 1075 | |||
1076 | out: | 1076 | out: | |
1077 | /* Free our discovered list */ | 1077 | /* Free our discovered list */ | |
1078 | while ((ifp = TAILQ_FIRST(ifs))) { | 1078 | while ((ifp = TAILQ_FIRST(ifs))) { | |
1079 | TAILQ_REMOVE(ifs, ifp, next); | 1079 | TAILQ_REMOVE(ifs, ifp, next); | |
1080 | if_free(ifp); | 1080 | if_free(ifp); | |
1081 | } | 1081 | } | |
1082 | free(ifs); | 1082 | free(ifs); | |
1083 | 1083 | |||
1084 | return e; | 1084 | return e; | |
1085 | } | 1085 | } | |
1086 | 1086 | |||
1087 | static void | 1087 | static void | |
1088 | dhcpcd_handlelink(void *arg) | 1088 | dhcpcd_handlelink(void *arg) | |
1089 | { | 1089 | { | |
1090 | struct dhcpcd_ctx *ctx = arg; | 1090 | struct dhcpcd_ctx *ctx = arg; | |
1091 | 1091 | |||
1092 | if (if_handlelink(ctx) == -1) { | 1092 | if (if_handlelink(ctx) == -1) { | |
1093 | if (errno == ENOBUFS || errno == ENOMEM) { | 1093 | if (errno == ENOBUFS || errno == ENOMEM) { | |
1094 | dhcpcd_linkoverflow(ctx); | 1094 | dhcpcd_linkoverflow(ctx); | |
1095 | return; | 1095 | return; | |
1096 | } | 1096 | } | |
1097 | if (errno != ENOTSUP) | 1097 | if (errno != ENOTSUP) | |
1098 | logerr(__func__); | 1098 | logerr(__func__); | |
1099 | } | 1099 | } | |
1100 | } | 1100 | } | |
1101 | 1101 | |||
1102 | static void | 1102 | static void | |
1103 | dhcpcd_checkcarrier(void *arg) | 1103 | dhcpcd_checkcarrier(void *arg) | |
1104 | { | 1104 | { | |
1105 | struct interface *ifp0 = arg, *ifp; | 1105 | struct interface *ifp0 = arg, *ifp; | |
1106 | 1106 | |||
1107 | ifp = if_find(ifp0->ctx->ifaces, ifp0->name); | 1107 | ifp = if_find(ifp0->ctx->ifaces, ifp0->name); | |
1108 | if (ifp == NULL || ifp->carrier == ifp0->carrier) | 1108 | if (ifp == NULL || ifp->carrier == ifp0->carrier) | |
1109 | return; | 1109 | return; | |
1110 | 1110 | |||
1111 | dhcpcd_handlecarrier(ifp, ifp0->carrier, ifp0->flags); | 1111 | dhcpcd_handlecarrier(ifp, ifp0->carrier, ifp0->flags); | |
1112 | if_free(ifp0); | 1112 | if_free(ifp0); | |
1113 | } | 1113 | } | |
1114 | 1114 | |||
1115 | #ifndef SMALL | 1115 | #ifndef SMALL | |
1116 | static void | 1116 | static void | |
1117 | dhcpcd_setlinkrcvbuf(struct dhcpcd_ctx *ctx) | 1117 | dhcpcd_setlinkrcvbuf(struct dhcpcd_ctx *ctx) | |
1118 | { | 1118 | { | |
1119 | socklen_t socklen; | 1119 | socklen_t socklen; | |
1120 | 1120 | |||
1121 | if (ctx->link_rcvbuf == 0) | 1121 | if (ctx->link_rcvbuf == 0) | |
1122 | return; | 1122 | return; | |
1123 | 1123 | |||
1124 | logdebugx("setting route socket receive buffer size to %d bytes", | 1124 | logdebugx("setting route socket receive buffer size to %d bytes", | |
1125 | ctx->link_rcvbuf); | 1125 | ctx->link_rcvbuf); | |
1126 | 1126 | |||
1127 | socklen = sizeof(ctx->link_rcvbuf); | 1127 | socklen = sizeof(ctx->link_rcvbuf); | |
1128 | if (setsockopt(ctx->link_fd, SOL_SOCKET, | 1128 | if (setsockopt(ctx->link_fd, SOL_SOCKET, | |
1129 | SO_RCVBUF, &ctx->link_rcvbuf, socklen) == -1) | 1129 | SO_RCVBUF, &ctx->link_rcvbuf, socklen) == -1) | |
1130 | logerr(__func__); | 1130 | logerr(__func__); | |
1131 | } | 1131 | } | |
1132 | #endif | 1132 | #endif | |
1133 | 1133 | |||
1134 | static void | 1134 | static void | |
1135 | dhcpcd_runprestartinterface(void *arg) | 1135 | dhcpcd_runprestartinterface(void *arg) | |
1136 | { | 1136 | { | |
1137 | struct interface *ifp = arg; | 1137 | struct interface *ifp = arg; | |
1138 | 1138 | |||
1139 | run_preinit(ifp); | 1139 | run_preinit(ifp); | |
1140 | dhcpcd_prestartinterface(ifp); | 1140 | dhcpcd_prestartinterface(ifp); | |
1141 | } | 1141 | } | |
1142 | 1142 | |||
1143 | void | 1143 | void | |
1144 | dhcpcd_linkoverflow(struct dhcpcd_ctx *ctx) | 1144 | dhcpcd_linkoverflow(struct dhcpcd_ctx *ctx) | |
1145 | { | 1145 | { | |
1146 | socklen_t socklen; | 1146 | socklen_t socklen; | |
1147 | int rcvbuflen; | 1147 | int rcvbuflen; | |
1148 | char buf[2048]; | 1148 | char buf[2048]; | |
1149 | ssize_t rlen; | 1149 | ssize_t rlen; | |
1150 | size_t rcnt; | 1150 | size_t rcnt; | |
1151 | struct if_head *ifaces; | 1151 | struct if_head *ifaces; | |
1152 | struct ifaddrs *ifaddrs; | 1152 | struct ifaddrs *ifaddrs; | |
1153 | struct interface *ifp, *ifn, *ifp1; | 1153 | struct interface *ifp, *ifn, *ifp1; | |
1154 | 1154 | |||
1155 | socklen = sizeof(rcvbuflen); | 1155 | socklen = sizeof(rcvbuflen); | |
1156 | if (getsockopt(ctx->link_fd, SOL_SOCKET, | 1156 | if (getsockopt(ctx->link_fd, SOL_SOCKET, | |
1157 | SO_RCVBUF, &rcvbuflen, &socklen) == -1) | 1157 | SO_RCVBUF, &rcvbuflen, &socklen) == -1) | |
1158 | rcvbuflen = 0; | 1158 | rcvbuflen = 0; | |
1159 | #ifdef __linux__ | 1159 | #ifdef __linux__ | |
1160 | else | 1160 | else | |
1161 | rcvbuflen /= 2; | 1161 | rcvbuflen /= 2; | |
1162 | #endif | 1162 | #endif | |
1163 | 1163 | |||
1164 | logerrx("route socket overflowed (rcvbuflen %d)" | 1164 | logerrx("route socket overflowed (rcvbuflen %d)" | |
1165 | " - learning interface state", rcvbuflen); | 1165 | " - learning interface state", rcvbuflen); | |
1166 | 1166 | |||
1167 | /* Drain the socket. | 1167 | /* Drain the socket. | |
1168 | * We cannot open a new one due to privsep. */ | 1168 | * We cannot open a new one due to privsep. */ | |
1169 | rcnt = 0; | 1169 | rcnt = 0; | |
1170 | do { | 1170 | do { | |
1171 | rlen = read(ctx->link_fd, buf, sizeof(buf)); | 1171 | rlen = read(ctx->link_fd, buf, sizeof(buf)); | |
1172 | if (++rcnt % 1000 == 0) | 1172 | if (++rcnt % 1000 == 0) | |
1173 | logwarnx("drained %zu messages", rcnt); | 1173 | logwarnx("drained %zu messages", rcnt); | |
1174 | } while (rlen != -1 || errno == ENOBUFS || errno == ENOMEM); | 1174 | } while (rlen != -1 || errno == ENOBUFS || errno == ENOMEM); | |
1175 | if (rcnt % 1000 != 0) | 1175 | if (rcnt % 1000 != 0) | |
1176 | logwarnx("drained %zu messages", rcnt); | 1176 | logwarnx("drained %zu messages", rcnt); | |
1177 | 1177 | |||
1178 | /* Work out the current interfaces. */ | 1178 | /* Work out the current interfaces. */ | |
1179 | ifaces = if_discover(ctx, &ifaddrs, ctx->ifc, ctx->ifv); | 1179 | ifaces = if_discover(ctx, &ifaddrs, ctx->ifc, ctx->ifv); | |
1180 | if (ifaces == NULL) { | 1180 | if (ifaces == NULL) { | |
1181 | logerr(__func__); | 1181 | logerr(__func__); | |
1182 | return; | 1182 | return; | |
1183 | } | 1183 | } | |
1184 | 1184 | |||
1185 | /* Punt departed interfaces */ | 1185 | /* Punt departed interfaces */ | |
1186 | TAILQ_FOREACH_SAFE(ifp, ctx->ifaces, next, ifn) { | 1186 | TAILQ_FOREACH_SAFE(ifp, ctx->ifaces, next, ifn) { | |
1187 | if (if_find(ifaces, ifp->name) != NULL) | 1187 | if (if_find(ifaces, ifp->name) != NULL) | |
1188 | continue; | 1188 | continue; | |
1189 | dhcpcd_handleinterface(ctx, -1, ifp->name); | 1189 | dhcpcd_handleinterface(ctx, -1, ifp->name); | |
1190 | } | 1190 | } | |
1191 | 1191 | |||
1192 | /* Add new interfaces */ | 1192 | /* Add new interfaces */ | |
1193 | while ((ifp = TAILQ_FIRST(ifaces)) != NULL ) { | 1193 | while ((ifp = TAILQ_FIRST(ifaces)) != NULL ) { | |
1194 | TAILQ_REMOVE(ifaces, ifp, next); | 1194 | TAILQ_REMOVE(ifaces, ifp, next); | |
1195 | ifp1 = if_find(ctx->ifaces, ifp->name); | 1195 | ifp1 = if_find(ctx->ifaces, ifp->name); | |
1196 | if (ifp1 != NULL) { | 1196 | if (ifp1 != NULL) { | |
1197 | /* If the interface already exists, | 1197 | /* If the interface already exists, | |
1198 | * check carrier state. | 1198 | * check carrier state. | |
1199 | * dhcpcd_checkcarrier will free ifp. */ | 1199 | * dhcpcd_checkcarrier will free ifp. */ | |
1200 | eloop_timeout_add_sec(ctx->eloop, 0, | 1200 | eloop_timeout_add_sec(ctx->eloop, 0, | |
1201 | dhcpcd_checkcarrier, ifp); | 1201 | dhcpcd_checkcarrier, ifp); | |
1202 | continue; | 1202 | continue; | |
1203 | } | 1203 | } | |
1204 | TAILQ_INSERT_TAIL(ctx->ifaces, ifp, next); | 1204 | TAILQ_INSERT_TAIL(ctx->ifaces, ifp, next); | |
1205 | if (ifp->active) { | 1205 | if (ifp->active) { | |
1206 | dhcpcd_initstate(ifp, 0); | 1206 | dhcpcd_initstate(ifp, 0); | |
1207 | eloop_timeout_add_sec(ctx->eloop, 0, | 1207 | eloop_timeout_add_sec(ctx->eloop, 0, | |
1208 | dhcpcd_runprestartinterface, ifp); | 1208 | dhcpcd_runprestartinterface, ifp); | |
1209 | } | 1209 | } | |
1210 | } | 1210 | } | |
1211 | free(ifaces); | 1211 | free(ifaces); | |
1212 | 1212 | |||
1213 | /* Update address state. */ | 1213 | /* Update address state. */ | |
1214 | if_markaddrsstale(ctx->ifaces); | 1214 | if_markaddrsstale(ctx->ifaces); | |
1215 | if_learnaddrs(ctx, ctx->ifaces, &ifaddrs); | 1215 | if_learnaddrs(ctx, ctx->ifaces, &ifaddrs); | |
1216 | if_deletestaleaddrs(ctx->ifaces); | 1216 | if_deletestaleaddrs(ctx->ifaces); | |
1217 | } | 1217 | } | |
1218 | 1218 | |||
1219 | void | 1219 | void | |
1220 | dhcpcd_handlehwaddr(struct interface *ifp, | 1220 | dhcpcd_handlehwaddr(struct interface *ifp, | |
1221 | uint16_t hwtype, const void *hwaddr, uint8_t hwlen) | 1221 | uint16_t hwtype, const void *hwaddr, uint8_t hwlen) | |
1222 | { | 1222 | { | |
1223 | char buf[sizeof(ifp->hwaddr) * 3]; | 1223 | char buf[sizeof(ifp->hwaddr) * 3]; | |
1224 | 1224 | |||
1225 | if (hwaddr == NULL || !if_valid_hwaddr(hwaddr, hwlen)) | 1225 | if (hwaddr == NULL || !if_valid_hwaddr(hwaddr, hwlen)) | |
1226 | hwlen = 0; | 1226 | hwlen = 0; | |
1227 | 1227 | |||
1228 | if (hwlen > sizeof(ifp->hwaddr)) { | 1228 | if (hwlen > sizeof(ifp->hwaddr)) { | |
1229 | errno = ENOBUFS; | 1229 | errno = ENOBUFS; | |
1230 | logerr("%s: %s", __func__, ifp->name); | 1230 | logerr("%s: %s", __func__, ifp->name); | |
1231 | return; | 1231 | return; | |
1232 | } | 1232 | } | |
1233 | 1233 | |||
1234 | if (ifp->hwtype != hwtype) { | 1234 | if (ifp->hwtype != hwtype) { | |
1235 | loginfox("%s: hardware address type changed from %d to %d", | 1235 | loginfox("%s: hardware address type changed from %d to %d", | |
1236 | ifp->name, ifp->hwtype, hwtype); | 1236 | ifp->name, ifp->hwtype, hwtype); | |
1237 | ifp->hwtype = hwtype; | 1237 | ifp->hwtype = hwtype; | |
1238 | } | 1238 | } | |
1239 | 1239 | |||
1240 | if (ifp->hwlen == hwlen && | 1240 | if (ifp->hwlen == hwlen && | |
1241 | (hwlen == 0 || memcmp(ifp->hwaddr, hwaddr, hwlen) == 0)) | 1241 | (hwlen == 0 || memcmp(ifp->hwaddr, hwaddr, hwlen) == 0)) | |
1242 | return; | 1242 | return; | |
1243 | 1243 | |||
1244 | loginfox("%s: new hardware address: %s", ifp->name, | 1244 | loginfox("%s: new hardware address: %s", ifp->name, | |
1245 | hwaddr_ntoa(hwaddr, hwlen, buf, sizeof(buf))); | 1245 | hwaddr_ntoa(hwaddr, hwlen, buf, sizeof(buf))); | |
1246 | ifp->hwlen = hwlen; | 1246 | ifp->hwlen = hwlen; | |
1247 | if (hwaddr != NULL) | 1247 | if (hwaddr != NULL) | |
1248 | memcpy(ifp->hwaddr, hwaddr, hwlen); | 1248 | memcpy(ifp->hwaddr, hwaddr, hwlen); | |
1249 | } | 1249 | } | |
1250 | 1250 | |||
1251 | static void | 1251 | static void | |
1252 | if_reboot(struct interface *ifp, int argc, char **argv) | 1252 | if_reboot(struct interface *ifp, int argc, char **argv) | |
1253 | { | 1253 | { | |
1254 | #ifdef INET | 1254 | #ifdef INET | |
1255 | unsigned long long oldopts; | 1255 | unsigned long long oldopts; | |
1256 | 1256 | |||
1257 | oldopts = ifp->options->options; | 1257 | oldopts = ifp->options->options; | |
1258 | #endif | 1258 | #endif | |
1259 | script_runreason(ifp, "RECONFIGURE"); | 1259 | script_runreason(ifp, "RECONFIGURE"); | |
1260 | dhcpcd_initstate1(ifp, argc, argv, 0); | 1260 | dhcpcd_initstate1(ifp, argc, argv, 0); | |
1261 | #ifdef INET | 1261 | #ifdef INET | |
1262 | dhcp_reboot_newopts(ifp, oldopts); | 1262 | dhcp_reboot_newopts(ifp, oldopts); | |
1263 | #endif | 1263 | #endif | |
1264 | #ifdef DHCP6 | 1264 | #ifdef DHCP6 | |
1265 | dhcp6_reboot(ifp); | 1265 | dhcp6_reboot(ifp); | |
1266 | #endif | 1266 | #endif | |
1267 | dhcpcd_prestartinterface(ifp); | 1267 | dhcpcd_prestartinterface(ifp); | |
1268 | } | 1268 | } | |
1269 | 1269 | |||
1270 | static void | 1270 | static void | |
1271 | reload_config(struct dhcpcd_ctx *ctx) | 1271 | reload_config(struct dhcpcd_ctx *ctx) | |
1272 | { | 1272 | { | |
1273 | struct if_options *ifo; | 1273 | struct if_options *ifo; | |
1274 | 1274 | |||
1275 | free_globals(ctx); | 1275 | free_globals(ctx); | |
1276 | if ((ifo = read_config(ctx, NULL, NULL, NULL)) == NULL) | 1276 | if ((ifo = read_config(ctx, NULL, NULL, NULL)) == NULL) | |
1277 | return; | 1277 | return; | |
1278 | add_options(ctx, NULL, ifo, ctx->argc, ctx->argv); | 1278 | add_options(ctx, NULL, ifo, ctx->argc, ctx->argv); | |
1279 | /* We need to preserve these options. */ | 1279 | /* We need to preserve these options. */ | |
1280 | if (ctx->options & DHCPCD_STARTED) | 1280 | if (ctx->options & DHCPCD_STARTED) | |
1281 | ifo->options |= DHCPCD_STARTED; | 1281 | ifo->options |= DHCPCD_STARTED; | |
1282 | if (ctx->options & DHCPCD_MASTER) | 1282 | if (ctx->options & DHCPCD_MASTER) | |
1283 | ifo->options |= DHCPCD_MASTER; | 1283 | ifo->options |= DHCPCD_MASTER; | |
1284 | if (ctx->options & DHCPCD_DAEMONISED) | 1284 | if (ctx->options & DHCPCD_DAEMONISED) | |
1285 | ifo->options |= DHCPCD_DAEMONISED; | 1285 | ifo->options |= DHCPCD_DAEMONISED; | |
1286 | if (ctx->options & DHCPCD_PRIVSEP) | 1286 | if (ctx->options & DHCPCD_PRIVSEP) | |
1287 | ifo->options |= DHCPCD_PRIVSEP; | 1287 | ifo->options |= DHCPCD_PRIVSEP; | |
1288 | ctx->options = ifo->options; | 1288 | ctx->options = ifo->options; | |
1289 | free_options(ctx, ifo); | 1289 | free_options(ctx, ifo); | |
1290 | } | 1290 | } | |
1291 | 1291 | |||
1292 | static void | 1292 | static void | |
1293 | reconf_reboot(struct dhcpcd_ctx *ctx, int action, int argc, char **argv, int oi) | 1293 | reconf_reboot(struct dhcpcd_ctx *ctx, int action, int argc, char **argv, int oi) | |
1294 | { | 1294 | { | |
1295 | int i; | 1295 | int i; | |
1296 | struct interface *ifp; | 1296 | struct interface *ifp; | |
1297 | 1297 | |||
1298 | TAILQ_FOREACH(ifp, ctx->ifaces, next) { | 1298 | TAILQ_FOREACH(ifp, ctx->ifaces, next) { | |
1299 | for (i = oi; i < argc; i++) { | 1299 | for (i = oi; i < argc; i++) { | |
1300 | if (strcmp(ifp->name, argv[i]) == 0) | 1300 | if (strcmp(ifp->name, argv[i]) == 0) | |
1301 | break; | 1301 | break; | |
1302 | } | 1302 | } | |
1303 | if (oi != argc && i == argc) | 1303 | if (oi != argc && i == argc) | |
1304 | continue; | 1304 | continue; | |
1305 | if (ifp->active == IF_ACTIVE_USER) { | 1305 | if (ifp->active == IF_ACTIVE_USER) { | |
1306 | if (action) | 1306 | if (action) | |
1307 | if_reboot(ifp, argc, argv); | 1307 | if_reboot(ifp, argc, argv); | |
1308 | #ifdef INET | 1308 | #ifdef INET | |
1309 | else | 1309 | else | |
1310 | ipv4_applyaddr(ifp); | 1310 | ipv4_applyaddr(ifp); | |
1311 | #endif | 1311 | #endif | |
1312 | } else if (i != argc) { | 1312 | } else if (i != argc) { | |
1313 | ifp->active = IF_ACTIVE_USER; | 1313 | ifp->active = IF_ACTIVE_USER; | |
1314 | dhcpcd_initstate1(ifp, argc, argv, 0); | 1314 | dhcpcd_initstate1(ifp, argc, argv, 0); | |
1315 | run_preinit(ifp); | 1315 | run_preinit(ifp); | |
1316 | dhcpcd_prestartinterface(ifp); | 1316 | dhcpcd_prestartinterface(ifp); | |
1317 | } | 1317 | } | |
1318 | } | 1318 | } | |
1319 | } | 1319 | } | |
1320 | 1320 | |||
1321 | static void | 1321 | static void | |
1322 | stop_all_interfaces(struct dhcpcd_ctx *ctx, unsigned long long opts) | 1322 | stop_all_interfaces(struct dhcpcd_ctx *ctx, unsigned long long opts) | |
1323 | { | 1323 | { | |
1324 | struct interface *ifp; | 1324 | struct interface *ifp; | |
1325 | 1325 | |||
1326 | ctx->options |= DHCPCD_EXITING; | 1326 | ctx->options |= DHCPCD_EXITING; | |
1327 | if (ctx->ifaces == NULL) | 1327 | if (ctx->ifaces == NULL) | |
1328 | return; | 1328 | return; | |
1329 | 1329 | |||
1330 | /* Drop the last interface first */ | 1330 | /* Drop the last interface first */ | |
1331 | TAILQ_FOREACH_REVERSE(ifp, ctx->ifaces, if_head, next) { | 1331 | TAILQ_FOREACH_REVERSE(ifp, ctx->ifaces, if_head, next) { | |
1332 | if (!ifp->active) | 1332 | if (!ifp->active) | |
1333 | continue; | 1333 | continue; | |
1334 | ifp->options->options |= opts; | 1334 | ifp->options->options |= opts; | |
1335 | if (ifp->options->options & DHCPCD_RELEASE) | 1335 | if (ifp->options->options & DHCPCD_RELEASE) | |
1336 | ifp->options->options &= ~DHCPCD_PERSISTENT; | 1336 | ifp->options->options &= ~DHCPCD_PERSISTENT; | |
1337 | ifp->options->options |= DHCPCD_EXITING; | 1337 | ifp->options->options |= DHCPCD_EXITING; | |
1338 | stop_interface(ifp, NULL); | 1338 | stop_interface(ifp, NULL); | |
1339 | } | 1339 | } | |
1340 | } | 1340 | } | |
1341 | 1341 | |||
1342 | static void | 1342 | static void | |
1343 | dhcpcd_ifrenew(struct interface *ifp) | 1343 | dhcpcd_ifrenew(struct interface *ifp) | |
1344 | { | 1344 | { | |
1345 | 1345 | |||
1346 | if (!ifp->active) | 1346 | if (!ifp->active) | |
1347 | return; | 1347 | return; | |
1348 | 1348 | |||
1349 | if (ifp->options->options & DHCPCD_LINK && !if_is_link_up(ifp)) | 1349 | if (ifp->options->options & DHCPCD_LINK && !if_is_link_up(ifp)) | |
1350 | return; | 1350 | return; | |
1351 | 1351 | |||
1352 | #ifdef INET | 1352 | #ifdef INET | |
1353 | dhcp_renew(ifp); | 1353 | dhcp_renew(ifp); | |
1354 | #endif | 1354 | #endif | |
1355 | #ifdef INET6 | 1355 | #ifdef INET6 | |
1356 | #define DHCPCD_RARENEW (DHCPCD_IPV6 | DHCPCD_IPV6RS) | 1356 | #define DHCPCD_RARENEW (DHCPCD_IPV6 | DHCPCD_IPV6RS) | |
1357 | if ((ifp->options->options & DHCPCD_RARENEW) == DHCPCD_RARENEW) | 1357 | if ((ifp->options->options & DHCPCD_RARENEW) == DHCPCD_RARENEW) | |
1358 | ipv6nd_startrs(ifp); | 1358 | ipv6nd_startrs(ifp); | |
1359 | #endif | 1359 | #endif | |
1360 | #ifdef DHCP6 | 1360 | #ifdef DHCP6 | |
1361 | dhcp6_renew(ifp); | 1361 | dhcp6_renew(ifp); | |
1362 | #endif | 1362 | #endif | |
1363 | } | 1363 | } | |
1364 | 1364 | |||
1365 | static void | 1365 | static void | |
1366 | dhcpcd_renew(struct dhcpcd_ctx *ctx) | 1366 | dhcpcd_renew(struct dhcpcd_ctx *ctx) | |
1367 | { | 1367 | { | |
1368 | struct interface *ifp; | 1368 | struct interface *ifp; | |
1369 | 1369 | |||
1370 | TAILQ_FOREACH(ifp, ctx->ifaces, next) { | 1370 | TAILQ_FOREACH(ifp, ctx->ifaces, next) { | |
1371 | dhcpcd_ifrenew(ifp); | 1371 | dhcpcd_ifrenew(ifp); | |
1372 | } | 1372 | } | |
1373 | } | 1373 | } | |
1374 | 1374 | |||
1375 | #ifdef USE_SIGNALS | 1375 | #ifdef USE_SIGNALS | |
1376 | #define sigmsg "received %s, %s" | 1376 | #define sigmsg "received %s, %s" | |
1377 | static void | 1377 | static void | |
1378 | dhcpcd_signal_cb(int sig, void *arg) | 1378 | dhcpcd_signal_cb(int sig, void *arg) | |
1379 | { | 1379 | { | |
1380 | struct dhcpcd_ctx *ctx = arg; | 1380 | struct dhcpcd_ctx *ctx = arg; | |
1381 | unsigned long long opts; | 1381 | unsigned long long opts; | |
1382 | int exit_code; | 1382 | int exit_code; | |
1383 | 1383 | |||
1384 | if (ctx->options & DHCPCD_DUMPLEASE) { | 1384 | if (ctx->options & DHCPCD_DUMPLEASE) { | |
1385 | eloop_exit(ctx->eloop, EXIT_FAILURE); | 1385 | eloop_exit(ctx->eloop, EXIT_FAILURE); | |
1386 | return; | 1386 | return; | |
1387 | } | 1387 | } | |
1388 | 1388 | |||
1389 | if (sig != SIGCHLD && ctx->options & DHCPCD_FORKED) { | 1389 | if (sig != SIGCHLD && ctx->options & DHCPCD_FORKED) { | |
1390 | if (sig != SIGHUP && | 1390 | if (sig != SIGHUP && | |
1391 | write(ctx->fork_fd, &sig, sizeof(sig)) == -1) | 1391 | write(ctx->fork_fd, &sig, sizeof(sig)) == -1) | |
1392 | logerr("%s: write", __func__); | 1392 | logerr("%s: write", __func__); | |
1393 | return; | 1393 | return; | |
1394 | } | 1394 | } | |
1395 | 1395 | |||
1396 | opts = 0; | 1396 | opts = 0; | |
1397 | exit_code = EXIT_FAILURE; | 1397 | exit_code = EXIT_FAILURE; | |
1398 | switch (sig) { | 1398 | switch (sig) { | |
1399 | case SIGINT: | 1399 | case SIGINT: | |
1400 | loginfox(sigmsg, "SIGINT", "stopping"); | 1400 | loginfox(sigmsg, "SIGINT", "stopping"); | |
1401 | break; | 1401 | break; | |
1402 | case SIGTERM: | 1402 | case SIGTERM: | |
1403 | loginfox(sigmsg, "SIGTERM", "stopping"); | 1403 | loginfox(sigmsg, "SIGTERM", "stopping"); | |
1404 | exit_code = EXIT_SUCCESS; | 1404 | exit_code = EXIT_SUCCESS; | |
1405 | break; | 1405 | break; | |
1406 | case SIGALRM: | 1406 | case SIGALRM: | |
1407 | loginfox(sigmsg, "SIGALRM", "releasing"); | 1407 | loginfox(sigmsg, "SIGALRM", "releasing"); | |
1408 | opts |= DHCPCD_RELEASE; | 1408 | opts |= DHCPCD_RELEASE; | |
1409 | exit_code = EXIT_SUCCESS; | 1409 | exit_code = EXIT_SUCCESS; | |
1410 | break; | 1410 | break; | |
1411 | case SIGHUP: | 1411 | case SIGHUP: | |
1412 | loginfox(sigmsg, "SIGHUP", "rebinding"); | 1412 | loginfox(sigmsg, "SIGHUP", "rebinding"); | |
1413 | reload_config(ctx); | 1413 | reload_config(ctx); | |
1414 | /* Preserve any options passed on the commandline | 1414 | /* Preserve any options passed on the commandline | |
1415 | * when we were started. */ | 1415 | * when we were started. */ | |
1416 | reconf_reboot(ctx, 1, ctx->argc, ctx->argv, | 1416 | reconf_reboot(ctx, 1, ctx->argc, ctx->argv, | |
1417 | ctx->argc - ctx->ifc); | 1417 | ctx->argc - ctx->ifc); | |
1418 | return; | 1418 | return; | |
1419 | case SIGUSR1: | 1419 | case SIGUSR1: | |
1420 | loginfox(sigmsg, "SIGUSR1", "renewing"); | 1420 | loginfox(sigmsg, "SIGUSR1", "renewing"); | |
1421 | dhcpcd_renew(ctx); | 1421 | dhcpcd_renew(ctx); | |
1422 | return; | 1422 | return; | |
1423 | case SIGUSR2: | 1423 | case SIGUSR2: | |
1424 | loginfox(sigmsg, "SIGUSR2", "reopening log"); | 1424 | loginfox(sigmsg, "SIGUSR2", "reopening log"); | |
1425 | /* XXX This may not work that well in a chroot */ | 1425 | #ifdef PRIVSEP | |
1426 | logclose(); | 1426 | if (IN_PRIVSEP(ctx)) { | |
1427 | if (ps_root_logreopen(ctx) == -1) | |||
1428 | logerr("ps_root_logreopen"); | |||
1429 | return; | |||
1430 | } | |||
1431 | #endif | |||
1427 | if (logopen(ctx->logfile) == -1) | 1432 | if (logopen(ctx->logfile) == -1) | |
1428 | logerr(__func__); | 1433 | logerr("logopen"); | |
1429 | return; | 1434 | return; | |
1430 | case SIGCHLD: | 1435 | case SIGCHLD: | |
1431 | while (waitpid(-1, NULL, WNOHANG) > 0) | 1436 | while (waitpid(-1, NULL, WNOHANG) > 0) | |
1432 | ; | 1437 | ; | |
1433 | return; | 1438 | return; | |
1434 | default: | 1439 | default: | |
1435 | logerrx("received signal %d but don't know what to do with it", | 1440 | logerrx("received signal %d but don't know what to do with it", | |
1436 | sig); | 1441 | sig); | |
1437 | return; | 1442 | return; | |
1438 | } | 1443 | } | |
1439 | 1444 | |||
1440 | if (!(ctx->options & DHCPCD_TEST)) | 1445 | if (!(ctx->options & DHCPCD_TEST)) | |
1441 | stop_all_interfaces(ctx, opts); | 1446 | stop_all_interfaces(ctx, opts); | |
1442 | eloop_exit(ctx->eloop, exit_code); | 1447 | eloop_exit(ctx->eloop, exit_code); | |
1443 | } | 1448 | } | |
1444 | #endif | 1449 | #endif | |
1445 | 1450 | |||
1446 | int | 1451 | int | |
1447 | dhcpcd_handleargs(struct dhcpcd_ctx *ctx, struct fd_list *fd, | 1452 | dhcpcd_handleargs(struct dhcpcd_ctx *ctx, struct fd_list *fd, | |
1448 | int argc, char **argv) | 1453 | int argc, char **argv) | |
1449 | { | 1454 | { | |
1450 | struct interface *ifp; | 1455 | struct interface *ifp; | |
1451 | unsigned long long opts; | 1456 | unsigned long long opts; | |
1452 | int opt, oi, do_reboot, do_renew, af = AF_UNSPEC; | 1457 | int opt, oi, do_reboot, do_renew, af = AF_UNSPEC; | |
1453 | size_t len, l, nifaces; | 1458 | size_t len, l, nifaces; | |
1454 | char *tmp, *p; | 1459 | char *tmp, *p; | |
1455 | 1460 | |||
1456 | /* Special commands for our control socket | 1461 | /* Special commands for our control socket | |
1457 | * as the other end should be blocking until it gets the | 1462 | * as the other end should be blocking until it gets the | |
1458 | * expected reply we should be safely able just to change the | 1463 | * expected reply we should be safely able just to change the | |
1459 | * write callback on the fd */ | 1464 | * write callback on the fd */ | |
1460 | /* Make any change here in privsep-control.c as well. */ | 1465 | /* Make any change here in privsep-control.c as well. */ | |
1461 | if (strcmp(*argv, "--version") == 0) { | 1466 | if (strcmp(*argv, "--version") == 0) { | |
1462 | return control_queue(fd, UNCONST(VERSION), | 1467 | return control_queue(fd, UNCONST(VERSION), | |
1463 | strlen(VERSION) + 1); | 1468 | strlen(VERSION) + 1); | |
1464 | } else if (strcmp(*argv, "--getconfigfile") == 0) { | 1469 | } else if (strcmp(*argv, "--getconfigfile") == 0) { | |
1465 | return control_queue(fd, UNCONST(fd->ctx->cffile), | 1470 | return control_queue(fd, UNCONST(fd->ctx->cffile), | |
1466 | strlen(fd->ctx->cffile) + 1); | 1471 | strlen(fd->ctx->cffile) + 1); | |
1467 | } else if (strcmp(*argv, "--getinterfaces") == 0) { | 1472 | } else if (strcmp(*argv, "--getinterfaces") == 0) { | |
1468 | optind = argc = 0; | 1473 | optind = argc = 0; | |
1469 | goto dumplease; | 1474 | goto dumplease; | |
1470 | } else if (strcmp(*argv, "--listen") == 0) { | 1475 | } else if (strcmp(*argv, "--listen") == 0) { | |
1471 | fd->flags |= FD_LISTEN; | 1476 | fd->flags |= FD_LISTEN; | |
1472 | return 0; | 1477 | return 0; | |
1473 | } | 1478 | } | |
1474 | 1479 | |||
1475 | /* Log the command */ | 1480 | /* Log the command */ | |
1476 | len = 1; | 1481 | len = 1; | |
1477 | for (opt = 0; opt < argc; opt++) | 1482 | for (opt = 0; opt < argc; opt++) | |
1478 | len += strlen(argv[opt]) + 1; | 1483 | len += strlen(argv[opt]) + 1; | |
1479 | tmp = malloc(len); | 1484 | tmp = malloc(len); | |
1480 | if (tmp == NULL) | 1485 | if (tmp == NULL) | |
1481 | return -1; | 1486 | return -1; | |
1482 | p = tmp; | 1487 | p = tmp; | |
1483 | for (opt = 0; opt < argc; opt++) { | 1488 | for (opt = 0; opt < argc; opt++) { | |
1484 | l = strlen(argv[opt]); | 1489 | l = strlen(argv[opt]); | |
1485 | strlcpy(p, argv[opt], len); | 1490 | strlcpy(p, argv[opt], len); | |
1486 | len -= l + 1; | 1491 | len -= l + 1; | |
1487 | p += l; | 1492 | p += l; | |
1488 | *p++ = ' '; | 1493 | *p++ = ' '; | |
1489 | } | 1494 | } | |
1490 | *--p = '\0'; | 1495 | *--p = '\0'; | |
1491 | loginfox("control command: %s", tmp); | 1496 | loginfox("control command: %s", tmp); | |
1492 | free(tmp); | 1497 | free(tmp); | |
1493 | 1498 | |||
1494 | optind = 0; | 1499 | optind = 0; | |
1495 | oi = 0; | 1500 | oi = 0; | |
1496 | opts = 0; | 1501 | opts = 0; | |
1497 | do_reboot = do_renew = 0; | 1502 | do_reboot = do_renew = 0; | |
1498 | while ((opt = getopt_long(argc, argv, IF_OPTS, cf_options, &oi)) != -1) | 1503 | while ((opt = getopt_long(argc, argv, IF_OPTS, cf_options, &oi)) != -1) | |
1499 | { | 1504 | { | |
1500 | switch (opt) { | 1505 | switch (opt) { | |
1501 | case 'g': | 1506 | case 'g': | |
1502 | /* Assumed if below not set */ | 1507 | /* Assumed if below not set */ | |
1503 | break; | 1508 | break; | |
1504 | case 'k': | 1509 | case 'k': | |
1505 | opts |= DHCPCD_RELEASE; | 1510 | opts |= DHCPCD_RELEASE; | |
1506 | break; | 1511 | break; | |
1507 | case 'n': | 1512 | case 'n': | |
1508 | do_reboot = 1; | 1513 | do_reboot = 1; | |
1509 | break; | 1514 | break; | |
1510 | case 'p': | 1515 | case 'p': | |
1511 | opts |= DHCPCD_PERSISTENT; | 1516 | opts |= DHCPCD_PERSISTENT; | |
1512 | break; | 1517 | break; | |
1513 | case 'x': | 1518 | case 'x': | |
1514 | opts |= DHCPCD_EXITING; | 1519 | opts |= DHCPCD_EXITING; | |
1515 | break; | 1520 | break; | |
1516 | case 'N': | 1521 | case 'N': | |
1517 | do_renew = 1; | 1522 | do_renew = 1; | |
1518 | break; | 1523 | break; | |
1519 | case 'U': | 1524 | case 'U': | |
1520 | opts |= DHCPCD_DUMPLEASE; | 1525 | opts |= DHCPCD_DUMPLEASE; | |
1521 | break; | 1526 | break; | |
1522 | case '4': | 1527 | case '4': | |
1523 | af = AF_INET; | 1528 | af = AF_INET; | |
1524 | break; | 1529 | break; | |
1525 | case '6': | 1530 | case '6': | |
1526 | af = AF_INET6; | 1531 | af = AF_INET6; | |
1527 | break; | 1532 | break; | |
1528 | } | 1533 | } | |
1529 | } | 1534 | } | |
1530 | 1535 | |||
1531 | if (opts & DHCPCD_DUMPLEASE) { | 1536 | if (opts & DHCPCD_DUMPLEASE) { | |
1532 | ctx->options |= DHCPCD_DUMPLEASE; | 1537 | ctx->options |= DHCPCD_DUMPLEASE; | |
1533 | dumplease: | 1538 | dumplease: | |
1534 | nifaces = 0; | 1539 | nifaces = 0; | |
1535 | TAILQ_FOREACH(ifp, ctx->ifaces, next) { | 1540 | TAILQ_FOREACH(ifp, ctx->ifaces, next) { | |
1536 | if (!ifp->active) | 1541 | if (!ifp->active) | |
1537 | continue; | 1542 | continue; | |
1538 | for (oi = optind; oi < argc; oi++) { | 1543 | for (oi = optind; oi < argc; oi++) { | |
1539 | if (strcmp(ifp->name, argv[oi]) == 0) | 1544 | if (strcmp(ifp->name, argv[oi]) == 0) | |
1540 | break; | 1545 | break; | |
1541 | } | 1546 | } | |
1542 | if (optind == argc || oi < argc) { | 1547 | if (optind == argc || oi < argc) { | |
1543 | opt = send_interface(NULL, ifp, af); | 1548 | opt = send_interface(NULL, ifp, af); | |
1544 | if (opt == -1) | 1549 | if (opt == -1) | |
1545 | goto dumperr; | 1550 | goto dumperr; | |
1546 | nifaces += (size_t)opt; | 1551 | nifaces += (size_t)opt; | |
1547 | } | 1552 | } | |
1548 | } | 1553 | } | |
1549 | if (write(fd->fd, &nifaces, sizeof(nifaces)) != sizeof(nifaces)) | 1554 | if (write(fd->fd, &nifaces, sizeof(nifaces)) != sizeof(nifaces)) | |
1550 | goto dumperr; | 1555 | goto dumperr; | |
1551 | TAILQ_FOREACH(ifp, ctx->ifaces, next) { | 1556 | TAILQ_FOREACH(ifp, ctx->ifaces, next) { | |
1552 | if (!ifp->active) | 1557 | if (!ifp->active) | |
1553 | continue; | 1558 | continue; | |
1554 | for (oi = optind; oi < argc; oi++) { | 1559 | for (oi = optind; oi < argc; oi++) { | |
1555 | if (strcmp(ifp->name, argv[oi]) == 0) | 1560 | if (strcmp(ifp->name, argv[oi]) == 0) | |
1556 | break; | 1561 | break; | |
1557 | } | 1562 | } | |
1558 | if (optind == argc || oi < argc) { | 1563 | if (optind == argc || oi < argc) { | |
1559 | if (send_interface(fd, ifp, af) == -1) | 1564 | if (send_interface(fd, ifp, af) == -1) | |
1560 | goto dumperr; | 1565 | goto dumperr; | |
1561 | } | 1566 | } | |
1562 | } | 1567 | } | |
1563 | ctx->options &= ~DHCPCD_DUMPLEASE; | 1568 | ctx->options &= ~DHCPCD_DUMPLEASE; | |
1564 | return 0; | 1569 | return 0; | |
1565 | dumperr: | 1570 | dumperr: | |
1566 | ctx->options &= ~DHCPCD_DUMPLEASE; | 1571 | ctx->options &= ~DHCPCD_DUMPLEASE; | |
1567 | return -1; | 1572 | return -1; | |
1568 | } | 1573 | } | |
1569 | 1574 | |||
1570 | /* Only privileged users can control dhcpcd via the socket. */ | 1575 | /* Only privileged users can control dhcpcd via the socket. */ | |
1571 | if (fd->flags & FD_UNPRIV) { | 1576 | if (fd->flags & FD_UNPRIV) { | |
1572 | errno = EPERM; | 1577 | errno = EPERM; | |
1573 | return -1; | 1578 | return -1; | |
1574 | } | 1579 | } | |
1575 | 1580 | |||
1576 | if (opts & (DHCPCD_EXITING | DHCPCD_RELEASE)) { | 1581 | if (opts & (DHCPCD_EXITING | DHCPCD_RELEASE)) { | |
1577 | if (optind == argc) { | 1582 | if (optind == argc) { | |
1578 | stop_all_interfaces(ctx, opts); | 1583 | stop_all_interfaces(ctx, opts); | |
1579 | eloop_exit(ctx->eloop, EXIT_SUCCESS); | 1584 | eloop_exit(ctx->eloop, EXIT_SUCCESS); | |
1580 | return 0; | 1585 | return 0; | |
1581 | } | 1586 | } | |
1582 | for (oi = optind; oi < argc; oi++) { | 1587 | for (oi = optind; oi < argc; oi++) { | |
1583 | if ((ifp = if_find(ctx->ifaces, argv[oi])) == NULL) | 1588 | if ((ifp = if_find(ctx->ifaces, argv[oi])) == NULL) | |
1584 | continue; | 1589 | continue; | |
1585 | if (!ifp->active) | 1590 | if (!ifp->active) | |
1586 | continue; | 1591 | continue; | |
1587 | ifp->options->options |= opts; | 1592 | ifp->options->options |= opts; | |
1588 | if (opts & DHCPCD_RELEASE) | 1593 | if (opts & DHCPCD_RELEASE) | |
1589 | ifp->options->options &= ~DHCPCD_PERSISTENT; | 1594 | ifp->options->options &= ~DHCPCD_PERSISTENT; | |
1590 | stop_interface(ifp, NULL); | 1595 | stop_interface(ifp, NULL); | |
1591 | } | 1596 | } | |
1592 | return 0; | 1597 | return 0; | |
1593 | } | 1598 | } | |
1594 | 1599 | |||
1595 | if (do_renew) { | 1600 | if (do_renew) { | |
1596 | if (optind == argc) { | 1601 | if (optind == argc) { | |
1597 | dhcpcd_renew(ctx); | 1602 | dhcpcd_renew(ctx); | |
1598 | return 0; | 1603 | return 0; | |
1599 | } | 1604 | } | |
1600 | for (oi = optind; oi < argc; oi++) { | 1605 | for (oi = optind; oi < argc; oi++) { | |
1601 | if ((ifp = if_find(ctx->ifaces, argv[oi])) == NULL) | 1606 | if ((ifp = if_find(ctx->ifaces, argv[oi])) == NULL) | |
1602 | continue; | 1607 | continue; | |
1603 | dhcpcd_ifrenew(ifp); | 1608 | dhcpcd_ifrenew(ifp); | |
1604 | } | 1609 | } | |
1605 | return 0; | 1610 | return 0; | |
1606 | } | 1611 | } | |
1607 | 1612 | |||
1608 | reload_config(ctx); | 1613 | reload_config(ctx); | |
1609 | /* XXX: Respect initial commandline options? */ | 1614 | /* XXX: Respect initial commandline options? */ | |
1610 | reconf_reboot(ctx, do_reboot, argc, argv, optind - 1); | 1615 | reconf_reboot(ctx, do_reboot, argc, argv, optind - 1); | |
1611 | return 0; | 1616 | return 0; | |
1612 | } | 1617 | } | |
1613 | 1618 | |||
1614 | static void dhcpcd_readdump1(void *); | 1619 | static void dhcpcd_readdump1(void *); | |
1615 | 1620 | |||
1616 | static void | 1621 | static void | |
1617 | dhcpcd_readdump2(void *arg) | 1622 | dhcpcd_readdump2(void *arg) | |
1618 | { | 1623 | { | |
1619 | struct dhcpcd_ctx *ctx = arg; | 1624 | struct dhcpcd_ctx *ctx = arg; | |
1620 | ssize_t len; | 1625 | ssize_t len; | |
1621 | int exit_code = EXIT_FAILURE; | 1626 | int exit_code = EXIT_FAILURE; | |
1622 | 1627 | |||
1623 | len = read(ctx->control_fd, ctx->ctl_buf + ctx->ctl_bufpos, | 1628 | len = read(ctx->control_fd, ctx->ctl_buf + ctx->ctl_bufpos, | |
1624 | ctx->ctl_buflen - ctx->ctl_bufpos); | 1629 | ctx->ctl_buflen - ctx->ctl_bufpos); | |
1625 | if (len == -1) { | 1630 | if (len == -1) { | |
1626 | logerr(__func__); | 1631 | logerr(__func__); | |
1627 | goto finished; | 1632 | goto finished; | |
1628 | } else if (len == 0) | 1633 | } else if (len == 0) | |
1629 | goto finished; | 1634 | goto finished; | |
1630 | if ((size_t)len + ctx->ctl_bufpos != ctx->ctl_buflen) { | 1635 | if ((size_t)len + ctx->ctl_bufpos != ctx->ctl_buflen) { | |
1631 | ctx->ctl_bufpos += (size_t)len; | 1636 | ctx->ctl_bufpos += (size_t)len; | |
1632 | return; | 1637 | return; | |
1633 | } | 1638 | } | |
1634 | 1639 | |||
1635 | if (ctx->ctl_buf[ctx->ctl_buflen - 1] != '\0') /* unlikely */ | 1640 | if (ctx->ctl_buf[ctx->ctl_buflen - 1] != '\0') /* unlikely */ | |
1636 | ctx->ctl_buf[ctx->ctl_buflen - 1] = '\0'; | 1641 | ctx->ctl_buf[ctx->ctl_buflen - 1] = '\0'; | |
1637 | script_dump(ctx->ctl_buf, ctx->ctl_buflen); | 1642 | script_dump(ctx->ctl_buf, ctx->ctl_buflen); | |
1638 | fflush(stdout); | 1643 | fflush(stdout); | |
1639 | if (--ctx->ctl_extra != 0) { | 1644 | if (--ctx->ctl_extra != 0) { | |
1640 | putchar('\n'); | 1645 | putchar('\n'); | |
1641 | eloop_event_add(ctx->eloop, ctx->control_fd, | 1646 | eloop_event_add(ctx->eloop, ctx->control_fd, | |
1642 | dhcpcd_readdump1, ctx); | 1647 | dhcpcd_readdump1, ctx); | |
1643 | return; | 1648 | return; | |
1644 | } | 1649 | } | |
1645 | exit_code = EXIT_SUCCESS; | 1650 | exit_code = EXIT_SUCCESS; | |
1646 | 1651 | |||
1647 | finished: | 1652 | finished: | |
1648 | shutdown(ctx->control_fd, SHUT_RDWR); | 1653 | shutdown(ctx->control_fd, SHUT_RDWR); | |
1649 | eloop_exit(ctx->eloop, exit_code); | 1654 | eloop_exit(ctx->eloop, exit_code); | |
1650 | } | 1655 | } | |
1651 | 1656 | |||
1652 | static void | 1657 | static void | |
1653 | dhcpcd_readdump1(void *arg) | 1658 | dhcpcd_readdump1(void *arg) | |
1654 | { | 1659 | { | |
1655 | struct dhcpcd_ctx *ctx = arg; | 1660 | struct dhcpcd_ctx *ctx = arg; | |
1656 | ssize_t len; | 1661 | ssize_t len; | |
1657 | 1662 | |||
1658 | len = read(ctx->control_fd, &ctx->ctl_buflen, sizeof(ctx->ctl_buflen)); | 1663 | len = read(ctx->control_fd, &ctx->ctl_buflen, sizeof(ctx->ctl_buflen)); | |
1659 | if (len != sizeof(ctx->ctl_buflen)) { | 1664 | if (len != sizeof(ctx->ctl_buflen)) { | |
1660 | if (len != -1) | 1665 | if (len != -1) | |
1661 | errno = EINVAL; | 1666 | errno = EINVAL; | |
1662 | goto err; | 1667 | goto err; | |
1663 | } | 1668 | } | |
1664 | if (ctx->ctl_buflen > SSIZE_MAX) { | 1669 | if (ctx->ctl_buflen > SSIZE_MAX) { | |
1665 | errno = ENOBUFS; | 1670 | errno = ENOBUFS; | |
1666 | goto err; | 1671 | goto err; | |
1667 | } | 1672 | } | |
1668 | 1673 | |||
1669 | free(ctx->ctl_buf); | 1674 | free(ctx->ctl_buf); | |
1670 | ctx->ctl_buf = malloc(ctx->ctl_buflen); | 1675 | ctx->ctl_buf = malloc(ctx->ctl_buflen); | |
1671 | if (ctx->ctl_buf == NULL) | 1676 | if (ctx->ctl_buf == NULL) | |
1672 | goto err; | 1677 | goto err; | |
1673 | 1678 | |||
1674 | ctx->ctl_bufpos = 0; | 1679 | ctx->ctl_bufpos = 0; | |
1675 | eloop_event_add(ctx->eloop, ctx->control_fd, | 1680 | eloop_event_add(ctx->eloop, ctx->control_fd, | |
1676 | dhcpcd_readdump2, ctx); | 1681 | dhcpcd_readdump2, ctx); | |
1677 | return; | 1682 | return; | |
1678 | 1683 | |||
1679 | err: | 1684 | err: | |
1680 | logerr(__func__); | 1685 | logerr(__func__); | |
1681 | eloop_exit(ctx->eloop, EXIT_FAILURE); | 1686 | eloop_exit(ctx->eloop, EXIT_FAILURE); | |
1682 | } | 1687 | } | |
1683 | 1688 | |||
1684 | static void | 1689 | static void | |
1685 | dhcpcd_readdump0(void *arg) | 1690 | dhcpcd_readdump0(void *arg) | |
1686 | { | 1691 | { | |
1687 | struct dhcpcd_ctx *ctx = arg; | 1692 | struct dhcpcd_ctx *ctx = arg; | |
1688 | ssize_t len; | 1693 | ssize_t len; | |
1689 | 1694 | |||
1690 | len = read(ctx->control_fd, &ctx->ctl_extra, sizeof(ctx->ctl_extra)); | 1695 | len = read(ctx->control_fd, &ctx->ctl_extra, sizeof(ctx->ctl_extra)); | |
1691 | if (len != sizeof(ctx->ctl_extra)) { | 1696 | if (len != sizeof(ctx->ctl_extra)) { | |
1692 | if (len != -1) | 1697 | if (len != -1) | |
1693 | errno = EINVAL; | 1698 | errno = EINVAL; | |
1694 | logerr(__func__); | 1699 | logerr(__func__); | |
1695 | eloop_exit(ctx->eloop, EXIT_FAILURE); | 1700 | eloop_exit(ctx->eloop, EXIT_FAILURE); | |
1696 | return; | 1701 | return; | |
1697 | } | 1702 | } | |
1698 | 1703 | |||
1699 | if (ctx->ctl_extra == 0) { | 1704 | if (ctx->ctl_extra == 0) { | |
1700 | eloop_exit(ctx->eloop, EXIT_SUCCESS); | 1705 | eloop_exit(ctx->eloop, EXIT_SUCCESS); | |
1701 | return; | 1706 | return; | |
1702 | } | 1707 | } | |
1703 | 1708 | |||
1704 | eloop_event_add(ctx->eloop, ctx->control_fd, | 1709 | eloop_event_add(ctx->eloop, ctx->control_fd, | |
1705 | dhcpcd_readdump1, ctx); | 1710 | dhcpcd_readdump1, ctx); | |
1706 | } | 1711 | } | |
1707 | 1712 | |||
1708 | static void | 1713 | static void | |
1709 | dhcpcd_readdumptimeout(void *arg) | 1714 | dhcpcd_readdumptimeout(void *arg) | |
1710 | { | 1715 | { | |
1711 | struct dhcpcd_ctx *ctx = arg; | 1716 | struct dhcpcd_ctx *ctx = arg; | |
1712 | 1717 | |||
1713 | logerrx(__func__); | 1718 | logerrx(__func__); | |
1714 | eloop_exit(ctx->eloop, EXIT_FAILURE); | 1719 | eloop_exit(ctx->eloop, EXIT_FAILURE); | |
1715 | } | 1720 | } | |
1716 | 1721 | |||
1717 | static int | 1722 | static int | |
1718 | dhcpcd_readdump(struct dhcpcd_ctx *ctx) | 1723 | dhcpcd_readdump(struct dhcpcd_ctx *ctx) | |
1719 | { | 1724 | { | |
1720 | 1725 | |||
1721 | ctx->options |= DHCPCD_FORKED; | 1726 | ctx->options |= DHCPCD_FORKED; | |
1722 | if (eloop_timeout_add_sec(ctx->eloop, 5, | 1727 | if (eloop_timeout_add_sec(ctx->eloop, 5, | |
1723 | dhcpcd_readdumptimeout, ctx) == -1) | 1728 | dhcpcd_readdumptimeout, ctx) == -1) | |
1724 | return -1; | 1729 | return -1; | |
1725 | return eloop_event_add(ctx->eloop, ctx->control_fd, | 1730 | return eloop_event_add(ctx->eloop, ctx->control_fd, | |
1726 | dhcpcd_readdump0, ctx); | 1731 | dhcpcd_readdump0, ctx); | |
1727 | } | 1732 | } | |
1728 | 1733 | |||
1729 | static void | 1734 | static void | |
1730 | dhcpcd_fork_cb(void *arg) | 1735 | dhcpcd_fork_cb(void *arg) | |
1731 | { | 1736 | { | |
1732 | struct dhcpcd_ctx *ctx = arg; | 1737 | struct dhcpcd_ctx *ctx = arg; | |
1733 | int exit_code; | 1738 | int exit_code; | |
1734 | ssize_t len; | 1739 | ssize_t len; | |
1735 | 1740 | |||
1736 | len = read(ctx->fork_fd, &exit_code, sizeof(exit_code)); | 1741 | len = read(ctx->fork_fd, &exit_code, sizeof(exit_code)); | |
1737 | if (len == -1) { | 1742 | if (len == -1) { | |
1738 | logerr(__func__); | 1743 | logerr(__func__); | |
1739 | exit_code = EXIT_FAILURE; | 1744 | exit_code = EXIT_FAILURE; | |
1740 | } else if ((size_t)len < sizeof(exit_code)) { | 1745 | } else if ((size_t)len < sizeof(exit_code)) { | |
1741 | logerrx("%s: truncated read %zd (expected %zu)", | 1746 | logerrx("%s: truncated read %zd (expected %zu)", | |
1742 | __func__, len, sizeof(exit_code)); | 1747 | __func__, len, sizeof(exit_code)); | |
1743 | exit_code = EXIT_FAILURE; | 1748 | exit_code = EXIT_FAILURE; | |
1744 | } | 1749 | } | |
1745 | if (ctx->options & DHCPCD_FORKED) | 1750 | if (ctx->options & DHCPCD_FORKED) | |
1746 | eloop_exit(ctx->eloop, exit_code); | 1751 | eloop_exit(ctx->eloop, exit_code); | |
1747 | else | 1752 | else | |
1748 | dhcpcd_signal_cb(exit_code, ctx); | 1753 | dhcpcd_signal_cb(exit_code, ctx); | |
1749 | } | 1754 | } | |
1750 | 1755 | |||
1751 | static void | 1756 | static void | |
1752 | dhcpcd_stderr_cb(void *arg) | 1757 | dhcpcd_stderr_cb(void *arg) | |
1753 | { | 1758 | { | |
1754 | struct dhcpcd_ctx *ctx = arg; | 1759 | struct dhcpcd_ctx *ctx = arg; | |
1755 | char log[BUFSIZ]; | 1760 | char log[BUFSIZ]; | |
1756 | ssize_t len; | 1761 | ssize_t len; | |
1757 | 1762 | |||
1758 | len = read(ctx->stderr_fd, log, sizeof(log)); | 1763 | len = read(ctx->stderr_fd, log, sizeof(log)); | |
1759 | if (len == -1) { | 1764 | if (len == -1) { | |
1760 | if (errno != ECONNRESET) | 1765 | if (errno != ECONNRESET) | |
1761 | logerr(__func__); | 1766 | logerr(__func__); | |
1762 | return; | 1767 | return; | |
1763 | } | 1768 | } | |
1764 | 1769 | |||
1765 | log[len] = '\0'; | 1770 | log[len] = '\0'; | |
1766 | fprintf(stderr, "%s", log); | 1771 | fprintf(stderr, "%s", log); | |
1767 | } | 1772 | } | |
1768 | 1773 | |||
1769 | int | 1774 | int | |
1770 | main(int argc, char **argv, char **envp) | 1775 | main(int argc, char **argv, char **envp) | |
1771 | { | 1776 | { | |
1772 | struct dhcpcd_ctx ctx; | 1777 | struct dhcpcd_ctx ctx; | |
1773 | struct ifaddrs *ifaddrs = NULL; | 1778 | struct ifaddrs *ifaddrs = NULL; | |
1774 | struct if_options *ifo; | 1779 | struct if_options *ifo; | |
1775 | struct interface *ifp; | 1780 | struct interface *ifp; | |
1776 | sa_family_t family = AF_UNSPEC; | 1781 | sa_family_t family = AF_UNSPEC; | |
1777 | int opt, oi = 0, i; | 1782 | int opt, oi = 0, i; | |
1778 | unsigned int logopts, t; | 1783 | unsigned int logopts, t; | |
1779 | ssize_t len; | 1784 | ssize_t len; | |
1780 | #if defined(USE_SIGNALS) || !defined(THERE_IS_NO_FORK) | 1785 | #if defined(USE_SIGNALS) || !defined(THERE_IS_NO_FORK) | |
1781 | pid_t pid; | 1786 | pid_t pid; | |
1782 | int fork_fd[2], stderr_fd[2]; | 1787 | int fork_fd[2], stderr_fd[2]; | |
1783 | #endif | 1788 | #endif | |
1784 | #ifdef USE_SIGNALS | 1789 | #ifdef USE_SIGNALS | |
1785 | int sig = 0; | 1790 | int sig = 0; | |
1786 | const char *siga = NULL; | 1791 | const char *siga = NULL; | |
1787 | size_t si; | 1792 | size_t si; | |
1788 | #endif | 1793 | #endif | |
1789 | 1794 | |||
1790 | #ifdef SETPROCTITLE_H | 1795 | #ifdef SETPROCTITLE_H | |
1791 | setproctitle_init(argc, argv, envp); | 1796 | setproctitle_init(argc, argv, envp); | |
1792 | #else | 1797 | #else | |
1793 | UNUSED(envp); | 1798 | UNUSED(envp); | |
1794 | #endif | 1799 | #endif | |
1795 | 1800 | |||
1796 | /* Test for --help and --version */ | 1801 | /* Test for --help and --version */ | |
1797 | if (argc > 1) { | 1802 | if (argc > 1) { | |
1798 | if (strcmp(argv[1], "--help") == 0) { | 1803 | if (strcmp(argv[1], "--help") == 0) { | |
1799 | usage(); | 1804 | usage(); | |
1800 | return EXIT_SUCCESS; | 1805 | return EXIT_SUCCESS; | |
1801 | } else if (strcmp(argv[1], "--version") == 0) { | 1806 | } else if (strcmp(argv[1], "--version") == 0) { | |
1802 | printf(""PACKAGE" "VERSION"\n%s\n", dhcpcd_copyright); | 1807 | printf(""PACKAGE" "VERSION"\n%s\n", dhcpcd_copyright); | |
1803 | printf("Compiled in features:" | 1808 | printf("Compiled in features:" | |
1804 | #ifdef INET | 1809 | #ifdef INET | |
1805 | " INET" | 1810 | " INET" | |
1806 | #endif | 1811 | #endif | |
1807 | #ifdef ARP | 1812 | #ifdef ARP | |
1808 | " ARP" | 1813 | " ARP" | |
1809 | #endif | 1814 | #endif | |
1810 | #ifdef ARPING | 1815 | #ifdef ARPING | |
1811 | " ARPing" | 1816 | " ARPing" | |
1812 | #endif | 1817 | #endif | |
1813 | #ifdef IPV4LL | 1818 | #ifdef IPV4LL | |
1814 | " IPv4LL" | 1819 | " IPv4LL" | |
1815 | #endif | 1820 | #endif | |
1816 | #ifdef INET6 | 1821 | #ifdef INET6 | |
1817 | " INET6" | 1822 | " INET6" | |
1818 | #endif | 1823 | #endif | |
1819 | #ifdef DHCP6 | 1824 | #ifdef DHCP6 | |
1820 | " DHCPv6" | 1825 | " DHCPv6" | |
1821 | #endif | 1826 | #endif | |
1822 | #ifdef AUTH | 1827 | #ifdef AUTH | |
1823 | " AUTH" | 1828 | " AUTH" | |
1824 | #endif | 1829 | #endif | |
1825 | #ifdef PRIVSEP | 1830 | #ifdef PRIVSEP | |
1826 | " PRIVSEP" | 1831 | " PRIVSEP" | |
1827 | #endif | 1832 | #endif | |
1828 | "\n"); | 1833 | "\n"); | |
1829 | return EXIT_SUCCESS; | 1834 | return EXIT_SUCCESS; | |
1830 | } | 1835 | } | |
1831 | } | 1836 | } | |
1832 | 1837 | |||
1833 | memset(&ctx, 0, sizeof(ctx)); | 1838 | memset(&ctx, 0, sizeof(ctx)); | |
1834 | 1839 | |||
1835 | ifo = NULL; | 1840 | ifo = NULL; | |
1836 | ctx.cffile = CONFIG; | 1841 | ctx.cffile = CONFIG; | |
1837 | ctx.script = UNCONST(dhcpcd_default_script); | 1842 | ctx.script = UNCONST(dhcpcd_default_script); | |
1838 | ctx.control_fd = ctx.control_unpriv_fd = ctx.link_fd = -1; | 1843 | ctx.control_fd = ctx.control_unpriv_fd = ctx.link_fd = -1; | |
1839 | ctx.pf_inet_fd = -1; | 1844 | ctx.pf_inet_fd = -1; | |
1840 | #ifdef PF_LINK | 1845 | #ifdef PF_LINK | |
1841 | ctx.pf_link_fd = -1; | 1846 | ctx.pf_link_fd = -1; | |
1842 | #endif | 1847 | #endif | |
1843 | 1848 | |||
1844 | TAILQ_INIT(&ctx.control_fds); | 1849 | TAILQ_INIT(&ctx.control_fds); | |
1845 | #ifdef USE_SIGNALS | 1850 | #ifdef USE_SIGNALS | |
1846 | ctx.fork_fd = -1; | 1851 | ctx.fork_fd = -1; | |
1847 | #endif | 1852 | #endif | |
1848 | #ifdef PLUGIN_DEV | 1853 | #ifdef PLUGIN_DEV | |
1849 | ctx.dev_fd = -1; | 1854 | ctx.dev_fd = -1; | |
1850 | #endif | 1855 | #endif | |
1851 | #ifdef INET | 1856 | #ifdef INET | |
1852 | ctx.udp_rfd = -1; | 1857 | ctx.udp_rfd = -1; | |
1853 | ctx.udp_wfd = -1; | 1858 | ctx.udp_wfd = -1; | |
1854 | #endif | 1859 | #endif | |
1855 | #if defined(INET6) && !defined(__sun) | 1860 | #if defined(INET6) && !defined(__sun) | |
1856 | ctx.nd_fd = -1; | 1861 | ctx.nd_fd = -1; | |
1857 | #endif | 1862 | #endif | |
1858 | #ifdef DHCP6 | 1863 | #ifdef DHCP6 | |
1859 | ctx.dhcp6_rfd = -1; | 1864 | ctx.dhcp6_rfd = -1; | |
1860 | ctx.dhcp6_wfd = -1; | 1865 | ctx.dhcp6_wfd = -1; | |
1861 | #endif | 1866 | #endif | |
1862 | #ifdef PRIVSEP | 1867 | #ifdef PRIVSEP | |
1863 | ctx.ps_root_fd = ctx.ps_data_fd = -1; | 1868 | ctx.ps_root_fd = ctx.ps_log_fd = ctx.ps_data_fd = -1; | |
1864 | ctx.ps_inet_fd = ctx.ps_control_fd = -1; | 1869 | ctx.ps_inet_fd = ctx.ps_control_fd = -1; | |
1865 | TAILQ_INIT(&ctx.ps_processes); | 1870 | TAILQ_INIT(&ctx.ps_processes); | |
1866 | #endif | 1871 | #endif | |
1867 | 1872 | |||
1868 | /* Check our streams for validity */ | 1873 | /* Check our streams for validity */ | |
1869 | ctx.stdin_valid = fcntl(STDIN_FILENO, F_GETFD) != -1; | 1874 | ctx.stdin_valid = fcntl(STDIN_FILENO, F_GETFD) != -1; | |
1870 | ctx.stdout_valid = fcntl(STDOUT_FILENO, F_GETFD) != -1; | 1875 | ctx.stdout_valid = fcntl(STDOUT_FILENO, F_GETFD) != -1; | |
1871 | ctx.stderr_valid = fcntl(STDERR_FILENO, F_GETFD) != -1; | 1876 | ctx.stderr_valid = fcntl(STDERR_FILENO, F_GETFD) != -1; | |
1872 | 1877 | |||
1873 | logopts = LOGERR_LOG | LOGERR_LOG_DATE | LOGERR_LOG_PID; | 1878 | logopts = LOGERR_LOG | LOGERR_LOG_DATE | LOGERR_LOG_PID; | |
1874 | if (ctx.stderr_valid) | 1879 | if (ctx.stderr_valid) | |
1875 | logopts |= LOGERR_ERR; | 1880 | logopts |= LOGERR_ERR; | |
1876 | 1881 | |||
1877 | i = 0; | 1882 | i = 0; | |
1878 | while ((opt = getopt_long(argc, argv, | 1883 | while ((opt = getopt_long(argc, argv, | |
1879 | ctx.options & DHCPCD_PRINT_PIDFILE ? NOERR_IF_OPTS : IF_OPTS, | 1884 | ctx.options & DHCPCD_PRINT_PIDFILE ? NOERR_IF_OPTS : IF_OPTS, | |
1880 | cf_options, &oi)) != -1) | 1885 | cf_options, &oi)) != -1) | |
1881 | { | 1886 | { | |
1882 | switch (opt) { | 1887 | switch (opt) { | |
1883 | case '4': | 1888 | case '4': | |
1884 | family = AF_INET; | 1889 | family = AF_INET; | |
1885 | break; | 1890 | break; | |
1886 | case '6': | 1891 | case '6': | |
1887 | family = AF_INET6; | 1892 | family = AF_INET6; | |
1888 | break; | 1893 | break; | |
1889 | case 'f': | 1894 | case 'f': | |
1890 | ctx.cffile = optarg; | 1895 | ctx.cffile = optarg; | |
1891 | break; | 1896 | break; | |
1892 | case 'j': | 1897 | case 'j': | |
1893 | free(ctx.logfile); | 1898 | free(ctx.logfile); | |
1894 | ctx.logfile = strdup(optarg); | 1899 | ctx.logfile = strdup(optarg); | |
1895 | break; | 1900 | break; | |
1896 | #ifdef USE_SIGNALS | 1901 | #ifdef USE_SIGNALS | |
1897 | case 'k': | 1902 | case 'k': | |
1898 | sig = SIGALRM; | 1903 | sig = SIGALRM; | |
1899 | siga = "ALRM"; | 1904 | siga = "ALRM"; | |
1900 | break; | 1905 | break; | |
1901 | case 'n': | 1906 | case 'n': | |
1902 | sig = SIGHUP; | 1907 | sig = SIGHUP; | |
1903 | siga = "HUP"; | 1908 | siga = "HUP"; | |
1904 | break; | 1909 | break; | |
1905 | case 'g': | 1910 | case 'g': | |
1906 | case 'p': | 1911 | case 'p': | |
1907 | /* Force going via command socket as we're | 1912 | /* Force going via command socket as we're | |
1908 | * out of user definable signals. */ | 1913 | * out of user definable signals. */ | |
1909 | i = 4; | 1914 | i = 4; | |
1910 | break; | 1915 | break; | |
1911 | case 'q': | 1916 | case 'q': | |
1912 | /* -qq disables console output entirely. | 1917 | /* -qq disables console output entirely. | |
1913 | * This is important for systemd because it logs | 1918 | * This is important for systemd because it logs | |
1914 | * both console AND syslog to the same log | 1919 | * both console AND syslog to the same log | |
1915 | * resulting in untold confusion. */ | 1920 | * resulting in untold confusion. */ | |
1916 | if (logopts & LOGERR_QUIET) | 1921 | if (logopts & LOGERR_QUIET) | |
1917 | logopts &= ~LOGERR_ERR; | 1922 | logopts &= ~LOGERR_ERR; | |
1918 | else | 1923 | else | |
1919 | logopts |= LOGERR_QUIET; | 1924 | logopts |= LOGERR_QUIET; | |
1920 | break; | 1925 | break; | |
1921 | case 'x': | 1926 | case 'x': | |
1922 | sig = SIGTERM; | 1927 | sig = SIGTERM; | |
1923 | siga = "TERM"; | 1928 | siga = "TERM"; | |
1924 | break; | 1929 | break; | |
1925 | case 'N': | 1930 | case 'N': | |
1926 | sig = SIGUSR1; | 1931 | sig = SIGUSR1; | |
1927 | siga = "USR1"; | 1932 | siga = "USR1"; | |
1928 | break; | 1933 | break; | |
1929 | #endif | 1934 | #endif | |
1930 | case 'P': | 1935 | case 'P': | |
1931 | ctx.options |= DHCPCD_PRINT_PIDFILE; | 1936 | ctx.options |= DHCPCD_PRINT_PIDFILE; | |
1932 | logopts &= ~(LOGERR_LOG | LOGERR_ERR); | 1937 | logopts &= ~(LOGERR_LOG | LOGERR_ERR); | |
1933 | break; | 1938 | break; | |
1934 | case 'T': | 1939 | case 'T': | |
1935 | i = 1; | 1940 | i = 1; | |
1936 | logopts &= ~LOGERR_LOG; | 1941 | logopts &= ~LOGERR_LOG; | |
1937 | break; | 1942 | break; | |
1938 | case 'U': | 1943 | case 'U': | |
1939 | i = 3; | 1944 | i = 3; | |
1940 | break; | 1945 | break; | |
1941 | case 'V': | 1946 | case 'V': | |
1942 | i = 2; | 1947 | i = 2; | |
1943 | break; | 1948 | break; | |
1944 | case '?': | 1949 | case '?': | |
1945 | if (ctx.options & DHCPCD_PRINT_PIDFILE) | 1950 | if (ctx.options & DHCPCD_PRINT_PIDFILE) | |
1946 | continue; | 1951 | continue; | |
1947 | usage(); | 1952 | usage(); | |
1948 | goto exit_failure; | 1953 | goto exit_failure; | |
1949 | } | 1954 | } | |
1950 | } | 1955 | } | |
1951 | 1956 | |||
1952 | logsetopts(logopts); | 1957 | logsetopts(logopts); | |
1953 | logopen(ctx.logfile); | 1958 | logopen(ctx.logfile); | |
1954 | 1959 | |||
1955 | ctx.argv = argv; | 1960 | ctx.argv = argv; | |
1956 | ctx.argc = argc; | 1961 | ctx.argc = argc; | |
1957 | ctx.ifc = argc - optind; | 1962 | ctx.ifc = argc - optind; | |
1958 | ctx.ifv = argv + optind; | 1963 | ctx.ifv = argv + optind; | |
1959 | 1964 | |||
1960 | rt_init(&ctx); | 1965 | rt_init(&ctx); | |
1961 | 1966 | |||
1962 | ifo = read_config(&ctx, NULL, NULL, NULL); | 1967 | ifo = read_config(&ctx, NULL, NULL, NULL); | |
1963 | if (ifo == NULL) { | 1968 | if (ifo == NULL) { | |
1964 | if (ctx.options & DHCPCD_PRINT_PIDFILE) | 1969 | if (ctx.options & DHCPCD_PRINT_PIDFILE) | |
1965 | goto printpidfile; | 1970 | goto printpidfile; | |
1966 | goto exit_failure; | 1971 | goto exit_failure; | |
1967 | } | 1972 | } | |
1968 | opt = add_options(&ctx, NULL, ifo, argc, argv); | 1973 | opt = add_options(&ctx, NULL, ifo, argc, argv); | |
1969 | if (opt != 1) { | 1974 | if (opt != 1) { | |
1970 | if (ctx.options & DHCPCD_PRINT_PIDFILE) | 1975 | if (ctx.options & DHCPCD_PRINT_PIDFILE) | |
1971 | goto printpidfile; | 1976 | goto printpidfile; | |
1972 | if (opt == 0) | 1977 | if (opt == 0) | |
1973 | usage(); | 1978 | usage(); | |
1974 | goto exit_failure; | 1979 | goto exit_failure; | |
1975 | } | 1980 | } | |
1976 | if (i == 2) { | 1981 | if (i == 2) { | |
1977 | printf("Interface options:\n"); | 1982 | printf("Interface options:\n"); | |
1978 | if (optind == argc - 1) { | 1983 | if (optind == argc - 1) { | |
1979 | free_options(&ctx, ifo); | 1984 | free_options(&ctx, ifo); | |
1980 | ifo = read_config(&ctx, argv[optind], NULL, NULL); | 1985 | ifo = read_config(&ctx, argv[optind], NULL, NULL); | |
1981 | if (ifo == NULL) | 1986 | if (ifo == NULL) | |
1982 | goto exit_failure; | 1987 | goto exit_failure; | |
1983 | add_options(&ctx, NULL, ifo, argc, argv); | 1988 | add_options(&ctx, NULL, ifo, argc, argv); | |
1984 | } | 1989 | } | |
1985 | if_printoptions(); | 1990 | if_printoptions(); | |
1986 | #ifdef INET | 1991 | #ifdef INET | |
1987 | if (family == 0 || family == AF_INET) { | 1992 | if (family == 0 || family == AF_INET) { | |
1988 | printf("\nDHCPv4 options:\n"); | 1993 | printf("\nDHCPv4 options:\n"); | |
1989 | dhcp_printoptions(&ctx, | 1994 | dhcp_printoptions(&ctx, | |
1990 | ifo->dhcp_override, ifo->dhcp_override_len); | 1995 | ifo->dhcp_override, ifo->dhcp_override_len); | |
1991 | } | 1996 | } | |
1992 | #endif | 1997 | #endif | |
1993 | #ifdef INET6 | 1998 | #ifdef INET6 | |
1994 | if (family == 0 || family == AF_INET6) { | 1999 | if (family == 0 || family == AF_INET6) { | |
1995 | printf("\nND options:\n"); | 2000 | printf("\nND options:\n"); | |
1996 | ipv6nd_printoptions(&ctx, | 2001 | ipv6nd_printoptions(&ctx, | |
1997 | ifo->nd_override, ifo->nd_override_len); | 2002 | ifo->nd_override, ifo->nd_override_len); | |
1998 | #ifdef DHCP6 | 2003 | #ifdef DHCP6 | |
1999 | printf("\nDHCPv6 options:\n"); | 2004 | printf("\nDHCPv6 options:\n"); | |
2000 | dhcp6_printoptions(&ctx, | 2005 | dhcp6_printoptions(&ctx, | |
2001 | ifo->dhcp6_override, ifo->dhcp6_override_len); | 2006 | ifo->dhcp6_override, ifo->dhcp6_override_len); | |
2002 | #endif | 2007 | #endif | |
2003 | } | 2008 | } | |
2004 | #endif | 2009 | #endif | |
2005 | goto exit_success; | 2010 | goto exit_success; | |
2006 | } | 2011 | } | |
2007 | ctx.options |= ifo->options; | 2012 | ctx.options |= ifo->options; | |
2008 | if (i == 1 || i == 3) { | 2013 | if (i == 1 || i == 3) { | |
2009 | if (i == 1) | 2014 | if (i == 1) | |
2010 | ctx.options |= DHCPCD_TEST; | 2015 | ctx.options |= DHCPCD_TEST; | |
2011 | else | 2016 | else | |
2012 | ctx.options |= DHCPCD_DUMPLEASE; | 2017 | ctx.options |= DHCPCD_DUMPLEASE; | |
2013 | ctx.options |= DHCPCD_PERSISTENT; | 2018 | ctx.options |= DHCPCD_PERSISTENT; | |
2014 | ctx.options &= ~DHCPCD_DAEMONISE; | 2019 | ctx.options &= ~DHCPCD_DAEMONISE; | |
2015 | } | 2020 | } | |
2016 | 2021 | |||
2017 | #ifdef THERE_IS_NO_FORK | 2022 | #ifdef THERE_IS_NO_FORK | |
2018 | ctx.options &= ~DHCPCD_DAEMONISE; | 2023 | ctx.options &= ~DHCPCD_DAEMONISE; | |
2019 | #endif | 2024 | #endif | |
2020 | 2025 | |||
2021 | if (ctx.options & DHCPCD_DEBUG) | 2026 | if (ctx.options & DHCPCD_DEBUG) | |
2022 | logsetopts(logopts | LOGERR_DEBUG); | 2027 | logsetopts(logopts | LOGERR_DEBUG); | |
2023 | 2028 | |||
2024 | if (!(ctx.options & (DHCPCD_TEST | DHCPCD_DUMPLEASE))) { | 2029 | if (!(ctx.options & (DHCPCD_TEST | DHCPCD_DUMPLEASE))) { | |
2025 | printpidfile: | 2030 | printpidfile: | |
2026 | /* If we have any other args, we should run as a single dhcpcd | 2031 | /* If we have any other args, we should run as a single dhcpcd | |
2027 | * instance for that interface. */ | 2032 | * instance for that interface. */ | |
2028 | if (optind == argc - 1 && !(ctx.options & DHCPCD_MASTER)) { | 2033 | if (optind == argc - 1 && !(ctx.options & DHCPCD_MASTER)) { | |
2029 | const char *per; | 2034 | const char *per; | |
2030 | const char *ifname; | 2035 | const char *ifname; | |
2031 | 2036 | |||
2032 | ifname = *ctx.ifv; | 2037 | ifname = *ctx.ifv; | |
2033 | if (ifname == NULL || strlen(ifname) > IF_NAMESIZE) { | 2038 | if (ifname == NULL || strlen(ifname) > IF_NAMESIZE) { | |
2034 | errno = ifname == NULL ? EINVAL : E2BIG; | 2039 | errno = ifname == NULL ? EINVAL : E2BIG; | |
2035 | logerr("%s: ", ifname); | 2040 | logerr("%s: ", ifname); | |
2036 | goto exit_failure; | 2041 | goto exit_failure; | |
2037 | } | 2042 | } | |
2038 | /* Allow a dhcpcd interface per address family */ | 2043 | /* Allow a dhcpcd interface per address family */ | |
2039 | switch(family) { | 2044 | switch(family) { | |
2040 | case AF_INET: | 2045 | case AF_INET: | |
2041 | per = "-4"; | 2046 | per = "-4"; | |
2042 | break; | 2047 | break; | |
2043 | case AF_INET6: | 2048 | case AF_INET6: | |
2044 | per = "-6"; | 2049 | per = "-6"; | |
2045 | break; | 2050 | break; | |
2046 | default: | 2051 | default: | |
2047 | per = ""; | 2052 | per = ""; | |
2048 | } | 2053 | } | |
2049 | snprintf(ctx.pidfile, sizeof(ctx.pidfile), | 2054 | snprintf(ctx.pidfile, sizeof(ctx.pidfile), | |
2050 | PIDFILE, ifname, per, "."); | 2055 | PIDFILE, ifname, per, "."); | |
2051 | } else { | 2056 | } else { | |
2052 | snprintf(ctx.pidfile, sizeof(ctx.pidfile), | 2057 | snprintf(ctx.pidfile, sizeof(ctx.pidfile), | |
2053 | PIDFILE, "", "", ""); | 2058 | PIDFILE, "", "", ""); | |
2054 | ctx.options |= DHCPCD_MASTER; | 2059 | ctx.options |= DHCPCD_MASTER; | |
2055 | } | 2060 | } | |
2056 | if (ctx.options & DHCPCD_PRINT_PIDFILE) { | 2061 | if (ctx.options & DHCPCD_PRINT_PIDFILE) { | |
2057 | printf("%s\n", ctx.pidfile); | 2062 | printf("%s\n", ctx.pidfile); | |
2058 | goto exit_success; | 2063 | goto exit_success; | |
2059 | } | 2064 | } | |
2060 | } | 2065 | } | |
2061 | 2066 | |||
2062 | if (chdir("/") == -1) | 2067 | if (chdir("/") == -1) | |
2063 | logerr("%s: chdir: /", __func__); | 2068 | logerr("%s: chdir: /", __func__); | |
2064 | 2069 | |||
2065 | /* Freeing allocated addresses from dumping leases can trigger | 2070 | /* Freeing allocated addresses from dumping leases can trigger | |
2066 | * eloop removals as well, so init here. */ | 2071 | * eloop removals as well, so init here. */ | |
2067 | if ((ctx.eloop = eloop_new()) == NULL) { | 2072 | if ((ctx.eloop = eloop_new()) == NULL) { | |
2068 | logerr("%s: eloop_init", __func__); | 2073 | logerr("%s: eloop_init", __func__); | |
2069 | goto exit_failure; | 2074 | goto exit_failure; | |
2070 | } | 2075 | } | |
2071 | 2076 | |||
2072 | #ifdef USE_SIGNALS | 2077 | #ifdef USE_SIGNALS | |
2073 | for (si = 0; si < dhcpcd_signals_ignore_len; si++) | 2078 | for (si = 0; si < dhcpcd_signals_ignore_len; si++) | |
2074 | signal(dhcpcd_signals_ignore[si], SIG_IGN); | 2079 | signal(dhcpcd_signals_ignore[si], SIG_IGN); | |
2075 | 2080 | |||
2076 | /* Save signal mask, block and redirect signals to our handler */ | 2081 | /* Save signal mask, block and redirect signals to our handler */ | |
2077 | eloop_signal_set_cb(ctx.eloop, | 2082 | eloop_signal_set_cb(ctx.eloop, | |
2078 | dhcpcd_signals, dhcpcd_signals_len, | 2083 | dhcpcd_signals, dhcpcd_signals_len, | |
2079 | dhcpcd_signal_cb, &ctx); | 2084 | dhcpcd_signal_cb, &ctx); | |
2080 | if (eloop_signal_mask(ctx.eloop, &ctx.sigset) == -1) { | 2085 | if (eloop_signal_mask(ctx.eloop, &ctx.sigset) == -1) { | |
2081 | logerr("%s: eloop_signal_mask", __func__); | 2086 | logerr("%s: eloop_signal_mask", __func__); | |
2082 | goto exit_failure; | 2087 | goto exit_failure; | |
2083 | } | 2088 | } | |
2084 | 2089 | |||
2085 | if (sig != 0) { | 2090 | if (sig != 0) { | |
2086 | pid = pidfile_read(ctx.pidfile); | 2091 | pid = pidfile_read(ctx.pidfile); | |
2087 | if (pid != 0 && pid != -1) | 2092 | if (pid != 0 && pid != -1) | |
2088 | loginfox("sending signal %s to pid %d", siga, pid); | 2093 | loginfox("sending signal %s to pid %d", siga, pid); | |
2089 | if (pid == 0 || pid == -1 || kill(pid, sig) != 0) { | 2094 | if (pid == 0 || pid == -1 || kill(pid, sig) != 0) { | |
2090 | if (sig != SIGHUP && sig != SIGUSR1 && errno != EPERM) | 2095 | if (sig != SIGHUP && sig != SIGUSR1 && errno != EPERM) | |
2091 | logerrx(PACKAGE" not running"); | 2096 | logerrx(PACKAGE" not running"); | |
2092 | if (pid != 0 && pid != -1 && errno != ESRCH) { | 2097 | if (pid != 0 && pid != -1 && errno != ESRCH) { | |
2093 | logerr("kill"); | 2098 | logerr("kill"); | |
2094 | goto exit_failure; | 2099 | goto exit_failure; | |
2095 | } | 2100 | } | |
2096 | unlink(ctx.pidfile); | 2101 | unlink(ctx.pidfile); | |
2097 | if (sig != SIGHUP && sig != SIGUSR1) | 2102 | if (sig != SIGHUP && sig != SIGUSR1) | |
2098 | goto exit_failure; | 2103 | goto exit_failure; | |
2099 | } else { | 2104 | } else { | |
2100 | struct timespec ts; | 2105 | struct timespec ts; | |
2101 | 2106 | |||
2102 | if (sig == SIGHUP || sig == SIGUSR1) | 2107 | if (sig == SIGHUP || sig == SIGUSR1) | |
2103 | goto exit_success; | 2108 | goto exit_success; | |
2104 | /* Spin until it exits */ | 2109 | /* Spin until it exits */ | |
2105 | loginfox("waiting for pid %d to exit", pid); | 2110 | loginfox("waiting for pid %d to exit", pid); | |
2106 | ts.tv_sec = 0; | 2111 | ts.tv_sec = 0; | |
2107 | ts.tv_nsec = 100000000; /* 10th of a second */ | 2112 | ts.tv_nsec = 100000000; /* 10th of a second */ | |
2108 | for(i = 0; i < 100; i++) { | 2113 | for(i = 0; i < 100; i++) { | |
2109 | nanosleep(&ts, NULL); | 2114 | nanosleep(&ts, NULL); | |
2110 | if (pidfile_read(ctx.pidfile) == -1) | 2115 | if (pidfile_read(ctx.pidfile) == -1) | |
2111 | goto exit_success; | 2116 | goto exit_success; | |
2112 | } | 2117 | } | |
2113 | logerrx("pid %d failed to exit", pid); | 2118 | logerrx("pid %d failed to exit", pid); | |
2114 | goto exit_failure; | 2119 | goto exit_failure; | |
2115 | } | 2120 | } | |
2116 | } | 2121 | } | |
2117 | #endif | 2122 | #endif | |
2118 | 2123 | |||
2119 | #ifdef PRIVSEP | 2124 | #ifdef PRIVSEP | |
2120 | ps_init(&ctx); | 2125 | ps_init(&ctx); | |
2121 | #endif | 2126 | #endif | |
2122 | 2127 | |||
2123 | #ifndef SMALL | 2128 | #ifndef SMALL | |
2124 | if (ctx.options & DHCPCD_DUMPLEASE && | 2129 | if (ctx.options & DHCPCD_DUMPLEASE && | |
2125 | ioctl(fileno(stdin), FIONREAD, &i, sizeof(i)) == 0 && | 2130 | ioctl(fileno(stdin), FIONREAD, &i, sizeof(i)) == 0 && | |
2126 | i > 0) | 2131 | i > 0) | |
2127 | { | 2132 | { | |
2128 | ctx.options |= DHCPCD_FORKED; /* pretend child process */ | 2133 | ctx.options |= DHCPCD_FORKED; /* pretend child process */ | |
2129 | #ifdef PRIVSEP | 2134 | #ifdef PRIVSEP | |
2130 | if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx, NULL) == -1) | 2135 | if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx, NULL) == -1) | |
2131 | goto exit_failure; | 2136 | goto exit_failure; | |
2132 | #endif | 2137 | #endif | |
2133 | ifp = calloc(1, sizeof(*ifp)); | 2138 | ifp = calloc(1, sizeof(*ifp)); | |
2134 | if (ifp == NULL) { | 2139 | if (ifp == NULL) { | |
2135 | logerr(__func__); | 2140 | logerr(__func__); | |
2136 | goto exit_failure; | 2141 | goto exit_failure; | |
2137 | } | 2142 | } | |
2138 | ifp->ctx = &ctx; | 2143 | ifp->ctx = &ctx; | |
2139 | ifp->options = ifo; | 2144 | ifp->options = ifo; | |
2140 | switch (family) { | 2145 | switch (family) { | |
2141 | case AF_INET: | 2146 | case AF_INET: | |
2142 | #ifdef INET | 2147 | #ifdef INET | |
2143 | if (dhcp_dump(ifp) == -1) | 2148 | if (dhcp_dump(ifp) == -1) | |
2144 | goto exit_failure; | 2149 | goto exit_failure; | |
2145 | break; | 2150 | break; | |
2146 | #else | 2151 | #else | |
2147 | logerrx("No DHCP support"); | 2152 | logerrx("No DHCP support"); | |
2148 | goto exit_failure; | 2153 | goto exit_failure; | |
2149 | #endif | 2154 | #endif | |
2150 | case AF_INET6: | 2155 | case AF_INET6: | |
2151 | #ifdef DHCP6 | 2156 | #ifdef DHCP6 | |
2152 | if (dhcp6_dump(ifp) == -1) | 2157 | if (dhcp6_dump(ifp) == -1) | |
2153 | goto exit_failure; | 2158 | goto exit_failure; | |
2154 | break; | 2159 | break; | |
2155 | #else | 2160 | #else | |
2156 | logerrx("No DHCP6 support"); | 2161 | logerrx("No DHCP6 support"); | |
2157 | goto exit_failure; | 2162 | goto exit_failure; | |
2158 | #endif | 2163 | #endif | |
2159 | default: | 2164 | default: | |
2160 | logerrx("Family not specified. Please use -4 or -6."); | 2165 | logerrx("Family not specified. Please use -4 or -6."); | |
2161 | goto exit_failure; | 2166 | goto exit_failure; | |
2162 | } | 2167 | } | |
2163 | goto exit_success; | 2168 | goto exit_success; | |
2164 | } | 2169 | } | |
2165 | #endif | 2170 | #endif | |
2166 | 2171 | |||
2167 | /* Test against siga instead of sig to avoid gcc | 2172 | /* Test against siga instead of sig to avoid gcc | |
2168 | * warning about a bogus potential signed overflow. | 2173 | * warning about a bogus potential signed overflow. | |
2169 | * The end result will be the same. */ | 2174 | * The end result will be the same. */ | |
2170 | if ((siga == NULL || i == 4 || ctx.ifc != 0) && | 2175 | if ((siga == NULL || i == 4 || ctx.ifc != 0) && | |
2171 | !(ctx.options & DHCPCD_TEST)) | 2176 | !(ctx.options & DHCPCD_TEST)) | |
2172 | { | 2177 | { | |
2173 | ctx.options |= DHCPCD_FORKED; /* avoid socket unlink */ | 2178 | ctx.options |= DHCPCD_FORKED; /* avoid socket unlink */ | |
2174 | if (!(ctx.options & DHCPCD_MASTER)) | 2179 | if (!(ctx.options & DHCPCD_MASTER)) | |
2175 | ctx.control_fd = control_open(argv[optind], family, | 2180 | ctx.control_fd = control_open(argv[optind], family, | |
2176 | ctx.options & DHCPCD_DUMPLEASE); | 2181 | ctx.options & DHCPCD_DUMPLEASE); | |
2177 | if (ctx.control_fd == -1) | 2182 | if (ctx.control_fd == -1) | |
2178 | ctx.control_fd = control_open(NULL, AF_UNSPEC, | 2183 | ctx.control_fd = control_open(NULL, AF_UNSPEC, | |
2179 | ctx.options & DHCPCD_DUMPLEASE); | 2184 | ctx.options & DHCPCD_DUMPLEASE); | |
2180 | if (ctx.control_fd != -1) { | 2185 | if (ctx.control_fd != -1) { | |
2181 | #ifdef PRIVSEP | 2186 | #ifdef PRIVSEP | |
2182 | if (IN_PRIVSEP(&ctx) && | 2187 | if (IN_PRIVSEP(&ctx) && | |
2183 | ps_mastersandbox(&ctx, NULL) == -1) | 2188 | ps_mastersandbox(&ctx, NULL) == -1) | |
2184 | goto exit_failure; | 2189 | goto exit_failure; | |
2185 | #endif | 2190 | #endif | |
2186 | if (!(ctx.options & DHCPCD_DUMPLEASE)) | 2191 | if (!(ctx.options & DHCPCD_DUMPLEASE)) | |
2187 | loginfox("sending commands to dhcpcd process"); | 2192 | loginfox("sending commands to dhcpcd process"); | |
2188 | len = control_send(&ctx, argc, argv); | 2193 | len = control_send(&ctx, argc, argv); | |
2189 | if (len > 0) | 2194 | if (len > 0) | |
2190 | logdebugx("send OK"); | 2195 | logdebugx("send OK"); | |
2191 | else { | 2196 | else { | |
2192 | logerr("%s: control_send", __func__); | 2197 | logerr("%s: control_send", __func__); | |
2193 | goto exit_failure; | 2198 | goto exit_failure; | |
2194 | } | 2199 | } | |
2195 | if (ctx.options & DHCPCD_DUMPLEASE) { | 2200 | if (ctx.options & DHCPCD_DUMPLEASE) { | |
2196 | if (dhcpcd_readdump(&ctx) == -1) { | 2201 | if (dhcpcd_readdump(&ctx) == -1) { | |
2197 | logerr("%s: dhcpcd_readdump", __func__); | 2202 | logerr("%s: dhcpcd_readdump", __func__); | |
2198 | goto exit_failure; | 2203 | goto exit_failure; | |
2199 | } | 2204 | } | |
2200 | goto run_loop; | 2205 | goto run_loop; | |
2201 | } | 2206 | } | |
2202 | goto exit_success; | 2207 | goto exit_success; | |
2203 | } else { | 2208 | } else { | |
2204 | if (errno != ENOENT) | 2209 | if (errno != ENOENT) | |
2205 | logerr("%s: control_open", __func__); | 2210 | logerr("%s: control_open", __func__); | |
2206 | if (ctx.options & DHCPCD_DUMPLEASE) { | 2211 | if (ctx.options & DHCPCD_DUMPLEASE) { | |
2207 | if (errno == ENOENT) | 2212 | if (errno == ENOENT) | |
2208 | logerrx("dhcpcd is not running"); | 2213 | logerrx("dhcpcd is not running"); | |
2209 | goto exit_failure; | 2214 | goto exit_failure; | |
2210 | } | 2215 | } | |
2211 | if (errno == EPERM || errno == EACCES) | 2216 | if (errno == EPERM || errno == EACCES) | |
2212 | goto exit_failure; | 2217 | goto exit_failure; | |
2213 | } | 2218 | } | |
2214 | ctx.options &= ~DHCPCD_FORKED; | 2219 | ctx.options &= ~DHCPCD_FORKED; | |
2215 | } | 2220 | } | |
2216 | 2221 | |||
2217 | if (!(ctx.options & DHCPCD_TEST)) { | 2222 | if (!(ctx.options & DHCPCD_TEST)) { | |
2218 | /* Ensure we have the needed directories */ | 2223 | /* Ensure we have the needed directories */ | |
2219 | if (mkdir(DBDIR, 0750) == -1 && errno != EEXIST) | 2224 | if (mkdir(DBDIR, 0750) == -1 && errno != EEXIST) | |
2220 | logerr("%s: mkdir: %s", __func__, DBDIR); | 2225 | logerr("%s: mkdir: %s", __func__, DBDIR); | |
2221 | if (mkdir(RUNDIR, 0755) == -1 && errno != EEXIST) | 2226 | if (mkdir(RUNDIR, 0755) == -1 && errno != EEXIST) | |
2222 | logerr("%s: mkdir: %s", __func__, RUNDIR); | 2227 | logerr("%s: mkdir: %s", __func__, RUNDIR); | |
2223 | if ((pid = pidfile_lock(ctx.pidfile)) != 0) { | 2228 | if ((pid = pidfile_lock(ctx.pidfile)) != 0) { | |
2224 | if (pid == -1) | 2229 | if (pid == -1) | |
2225 | logerr("%s: pidfile_lock: %s", | 2230 | logerr("%s: pidfile_lock: %s", | |
2226 | __func__, ctx.pidfile); | 2231 | __func__, ctx.pidfile); | |
2227 | else | 2232 | else | |
2228 | logerrx(PACKAGE | 2233 | logerrx(PACKAGE | |
2229 | " already running on pid %d (%s)", | 2234 | " already running on pid %d (%s)", | |
2230 | pid, ctx.pidfile); | 2235 | pid, ctx.pidfile); | |
2231 | goto exit_failure; | 2236 | goto exit_failure; | |
2232 | } | 2237 | } | |
2233 | } | 2238 | } | |
2234 | 2239 | |||
2235 | loginfox(PACKAGE "-" VERSION " starting"); | 2240 | loginfox(PACKAGE "-" VERSION " starting"); | |
2236 | if (ctx.stdin_valid && freopen(_PATH_DEVNULL, "w", stdin) == NULL) | 2241 | if (ctx.stdin_valid && freopen(_PATH_DEVNULL, "w", stdin) == NULL) | |
2237 | logwarn("freopen stdin"); | 2242 | logwarn("freopen stdin"); | |
2238 | 2243 | |||
2239 | #if defined(USE_SIGNALS) && !defined(THERE_IS_NO_FORK) | 2244 | #if defined(USE_SIGNALS) && !defined(THERE_IS_NO_FORK) | |
2240 | if (xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, fork_fd) == -1 || | 2245 | if (xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, fork_fd) == -1 || | |
2241 | (ctx.stderr_valid && | 2246 | (ctx.stderr_valid && | |
2242 | xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, stderr_fd) == -1)) | 2247 | xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, stderr_fd) == -1)) | |
2243 | { | 2248 | { | |
2244 | logerr("socketpair"); | 2249 | logerr("socketpair"); | |
2245 | goto exit_failure; | 2250 | goto exit_failure; | |
2246 | } | 2251 | } | |
2247 | switch (pid = fork()) { | 2252 | switch (pid = fork()) { | |
2248 | case -1: | 2253 | case -1: | |
2249 | logerr("fork"); | 2254 | logerr("fork"); | |
2250 | goto exit_failure; | 2255 | goto exit_failure; | |
2251 | case 0: | 2256 | case 0: | |
2252 | ctx.fork_fd = fork_fd[1]; | 2257 | ctx.fork_fd = fork_fd[1]; | |
2253 | close(fork_fd[0]); | 2258 | close(fork_fd[0]); | |
2254 | #ifdef PRIVSEP_RIGHTS | 2259 | #ifdef PRIVSEP_RIGHTS | |
2255 | if (ps_rights_limit_fd(ctx.fork_fd) == -1) { | 2260 | if (ps_rights_limit_fd(ctx.fork_fd) == -1) { | |
2256 | logerr("ps_rights_limit_fdpair"); | 2261 | logerr("ps_rights_limit_fdpair"); | |
2257 | goto exit_failure; | 2262 | goto exit_failure; | |
2258 | } | 2263 | } | |
2259 | #endif | 2264 | #endif | |
2260 | eloop_event_add(ctx.eloop, ctx.fork_fd, dhcpcd_fork_cb, &ctx); | 2265 | eloop_event_add(ctx.eloop, ctx.fork_fd, dhcpcd_fork_cb, &ctx); | |
2261 | 2266 | |||
2262 | /* | 2267 | /* | |
2263 | * Redirect stderr to the stderr socketpair. | 2268 | * Redirect stderr to the stderr socketpair. | |
2264 | * Redirect stdout as well. | 2269 | * Redirect stdout as well. | |
2265 | * dhcpcd doesn't output via stdout, but something in | 2270 | * dhcpcd doesn't output via stdout, but something in | |
2266 | * a called script might. | 2271 | * a called script might. | |
2267 | */ | 2272 | */ | |
2268 | if (ctx.stderr_valid) { | 2273 | if (ctx.stderr_valid) { | |
2269 | if (dup2(stderr_fd[1], STDERR_FILENO) == -1 || | 2274 | if (dup2(stderr_fd[1], STDERR_FILENO) == -1 || | |
2270 | (ctx.stdout_valid && | 2275 | (ctx.stdout_valid && | |
2271 | dup2(stderr_fd[1], STDOUT_FILENO) == -1)) | 2276 | dup2(stderr_fd[1], STDOUT_FILENO) == -1)) | |
2272 | logerr("dup2"); | 2277 | logerr("dup2"); | |
2273 | close(stderr_fd[0]); | 2278 | close(stderr_fd[0]); | |
2274 | close(stderr_fd[1]); | 2279 | close(stderr_fd[1]); | |
2275 | } else if (ctx.stdout_valid) { | 2280 | } else if (ctx.stdout_valid) { | |
2276 | if (freopen(_PATH_DEVNULL, "w", stdout) == NULL) | 2281 | if (freopen(_PATH_DEVNULL, "w", stdout) == NULL) | |
2277 | logerr("freopen stdout"); | 2282 | logerr("freopen stdout"); | |
2278 | } | 2283 | } | |
2279 | if (setsid() == -1) { | 2284 | if (setsid() == -1) { | |
2280 | logerr("%s: setsid", __func__); | 2285 | logerr("%s: setsid", __func__); | |
2281 | goto exit_failure; | 2286 | goto exit_failure; | |
2282 | } | 2287 | } | |
2283 | /* Ensure we can never get a controlling terminal */ | 2288 | /* Ensure we can never get a controlling terminal */ | |
2284 | switch (pid = fork()) { | 2289 | switch (pid = fork()) { | |
2285 | case -1: | 2290 | case -1: | |
2286 | logerr("fork"); | 2291 | logerr("fork"); | |
2287 | goto exit_failure; | 2292 | goto exit_failure; | |
2288 | case 0: | 2293 | case 0: | |
2289 | break; | 2294 | break; | |
2290 | default: | 2295 | default: | |
2291 | ctx.options |= DHCPCD_FORKED; /* A lie */ | 2296 | ctx.options |= DHCPCD_FORKED; /* A lie */ | |
2292 | i = EXIT_SUCCESS; | 2297 | i = EXIT_SUCCESS; | |
2293 | goto exit1; | 2298 | goto exit1; | |
2294 | } | 2299 | } | |
2295 | break; | 2300 | break; | |
2296 | default: | 2301 | default: | |
2297 | setproctitle("[launcher]"); | 2302 | setproctitle("[launcher]"); | |
2298 | ctx.options |= DHCPCD_FORKED | DHCPCD_LAUNCHER; | 2303 | ctx.options |= DHCPCD_FORKED | DHCPCD_LAUNCHER; | |
2299 | ctx.fork_fd = fork_fd[0]; | 2304 | ctx.fork_fd = fork_fd[0]; | |
2300 | close(fork_fd[1]); | 2305 | close(fork_fd[1]); | |
2301 | #ifdef PRIVSEP_RIGHTS | 2306 | #ifdef PRIVSEP_RIGHTS | |
2302 | if (ps_rights_limit_fd(ctx.fork_fd) == -1) { | 2307 | if (ps_rights_limit_fd(ctx.fork_fd) == -1) { | |
2303 | logerr("ps_rights_limit_fd"); | 2308 | logerr("ps_rights_limit_fd"); | |
2304 | goto exit_failure; | 2309 | goto exit_failure; | |
2305 | } | 2310 | } | |
2306 | #endif | 2311 | #endif | |
2307 | eloop_event_add(ctx.eloop, ctx.fork_fd, dhcpcd_fork_cb, &ctx); | 2312 | eloop_event_add(ctx.eloop, ctx.fork_fd, dhcpcd_fork_cb, &ctx); | |
2308 | 2313 | |||
2309 | if (ctx.stderr_valid) { | 2314 | if (ctx.stderr_valid) { | |
2310 | ctx.stderr_fd = stderr_fd[0]; | 2315 | ctx.stderr_fd = stderr_fd[0]; | |
2311 | close(stderr_fd[1]); | 2316 | close(stderr_fd[1]); | |
2312 | #ifdef PRIVSEP_RIGHTS | 2317 | #ifdef PRIVSEP_RIGHTS | |
2313 | if (ps_rights_limit_fd(ctx.stderr_fd) == 1) { | 2318 | if (ps_rights_limit_fd(ctx.stderr_fd) == 1) { | |
2314 | logerr("ps_rights_limit_fd"); | 2319 | logerr("ps_rights_limit_fd"); | |
2315 | goto exit_failure; | 2320 | goto exit_failure; | |
2316 | } | 2321 | } | |
2317 | #endif | 2322 | #endif | |
2318 | eloop_event_add(ctx.eloop, ctx.stderr_fd, | 2323 | eloop_event_add(ctx.eloop, ctx.stderr_fd, | |
2319 | dhcpcd_stderr_cb, &ctx); | 2324 | dhcpcd_stderr_cb, &ctx); | |
2320 | } | 2325 | } | |
2321 | #ifdef PRIVSEP | 2326 | #ifdef PRIVSEP | |
2322 | if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx, NULL) == -1) | 2327 | if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx, NULL) == -1) | |
2323 | goto exit_failure; | 2328 | goto exit_failure; | |
2324 | #endif | 2329 | #endif | |
2325 | goto run_loop; | 2330 | goto run_loop; | |
2326 | } | 2331 | } | |
2327 | 2332 | |||
2328 | /* We have now forked, setsid, forked once more. | 2333 | /* We have now forked, setsid, forked once more. | |
2329 | * From this point on, we are the controlling daemon. */ | 2334 | * From this point on, we are the controlling daemon. */ | |
2330 | ctx.options |= DHCPCD_STARTED; | 2335 | ctx.options |= DHCPCD_STARTED; | |
2336 | logdebugx("spawned master process on PID %d", getpid()); | |||
2331 | if ((pid = pidfile_lock(ctx.pidfile)) != 0) { | 2337 | if ((pid = pidfile_lock(ctx.pidfile)) != 0) { | |
2332 | logerr("%s: pidfile_lock %d", __func__, pid); | 2338 | logerr("%s: pidfile_lock %d", __func__, pid); | |
2333 | #ifdef PRIVSEP | 2339 | #ifdef PRIVSEP | |
2334 | /* privsep has not started ... */ | 2340 | /* privsep has not started ... */ | |
2335 | ctx.options &= ~DHCPCD_PRIVSEP; | 2341 | ctx.options &= ~DHCPCD_PRIVSEP; | |
2336 | #endif | 2342 | #endif | |
2337 | goto exit_failure; | 2343 | goto exit_failure; | |
2338 | } | 2344 | } | |
2339 | #endif | 2345 | #endif | |
2340 | 2346 | |||
2341 | os_init(); | 2347 | os_init(); | |
2342 | 2348 | |||
2343 | #if defined(BSD) && defined(INET6) | 2349 | #if defined(BSD) && defined(INET6) | |
2344 | /* Disable the kernel RTADV sysctl as early as possible. */ | 2350 | /* Disable the kernel RTADV sysctl as early as possible. */ | |
2345 | if (ctx.options & DHCPCD_IPV6 && ctx.options & DHCPCD_IPV6RS) | 2351 | if (ctx.options & DHCPCD_IPV6 && ctx.options & DHCPCD_IPV6RS) | |
2346 | if_disable_rtadv(); | 2352 | if_disable_rtadv(); | |
2347 | #endif | 2353 | #endif | |
2348 | 2354 | |||
2349 | #ifdef PRIVSEP | 2355 | #ifdef PRIVSEP | |
2350 | if (IN_PRIVSEP(&ctx) && ps_start(&ctx) == -1) { | 2356 | if (IN_PRIVSEP(&ctx) && ps_start(&ctx) == -1) { | |
2351 | logerr("ps_start"); | 2357 | logerr("ps_start"); | |
2352 | goto exit_failure; | 2358 | goto exit_failure; | |
2353 | } | 2359 | } | |
2354 | if (ctx.options & DHCPCD_FORKED) | 2360 | if (ctx.options & DHCPCD_FORKED) | |
2355 | goto run_loop; | 2361 | goto run_loop; | |
2356 | #endif | 2362 | #endif | |
2357 | 2363 | |||
2358 | if (!(ctx.options & DHCPCD_TEST)) { | 2364 | if (!(ctx.options & DHCPCD_TEST)) { | |
2359 | if (control_start(&ctx, | 2365 | if (control_start(&ctx, | |
2360 | ctx.options & DHCPCD_MASTER ? | 2366 | ctx.options & DHCPCD_MASTER ? | |
2361 | NULL : argv[optind], family) == -1) | 2367 | NULL : argv[optind], family) == -1) | |
2362 | { | 2368 | { | |
2363 | logerr("%s: control_start", __func__); | 2369 | logerr("%s: control_start", __func__); | |
2364 | goto exit_failure; | 2370 | goto exit_failure; | |
2365 | } | 2371 | } | |
2366 | } | 2372 | } | |
2367 | 2373 | |||
2368 | #ifdef PLUGIN_DEV | 2374 | #ifdef PLUGIN_DEV | |
2369 | /* Start any dev listening plugin which may want to | 2375 | /* Start any dev listening plugin which may want to | |
2370 | * change the interface name provided by the kernel */ | 2376 | * change the interface name provided by the kernel */ | |
2371 | if (!IN_PRIVSEP(&ctx) && | 2377 | if (!IN_PRIVSEP(&ctx) && | |
2372 | (ctx.options & (DHCPCD_MASTER | DHCPCD_DEV)) == | 2378 | (ctx.options & (DHCPCD_MASTER | DHCPCD_DEV)) == | |
2373 | (DHCPCD_MASTER | DHCPCD_DEV)) | 2379 | (DHCPCD_MASTER | DHCPCD_DEV)) | |
2374 | dev_start(&ctx, dhcpcd_handleinterface); | 2380 | dev_start(&ctx, dhcpcd_handleinterface); | |
2375 | #endif | 2381 | #endif | |
2376 | 2382 | |||
2377 | setproctitle("%s%s%s", | 2383 | setproctitle("%s%s%s", | |
2378 | ctx.options & DHCPCD_MASTER ? "[master]" : argv[optind], | 2384 | ctx.options & DHCPCD_MASTER ? "[master]" : argv[optind], | |
2379 | ctx.options & DHCPCD_IPV4 ? " [ip4]" : "", | 2385 | ctx.options & DHCPCD_IPV4 ? " [ip4]" : "", | |
2380 | ctx.options & DHCPCD_IPV6 ? " [ip6]" : ""); | 2386 | ctx.options & DHCPCD_IPV6 ? " [ip6]" : ""); | |
2381 | 2387 | |||
2382 | if (if_opensockets(&ctx) == -1) { | 2388 | if (if_opensockets(&ctx) == -1) { | |
2383 | logerr("%s: if_opensockets", __func__); | 2389 | logerr("%s: if_opensockets", __func__); | |
2384 | goto exit_failure; | 2390 | goto exit_failure; | |
2385 | } | 2391 | } | |
2386 | #ifndef SMALL | 2392 | #ifndef SMALL | |
2387 | dhcpcd_setlinkrcvbuf(&ctx); | 2393 | dhcpcd_setlinkrcvbuf(&ctx); | |
2388 | #endif | 2394 | #endif | |
2389 | 2395 | |||
2390 | /* Try and create DUID from the machine UUID. */ | 2396 | /* Try and create DUID from the machine UUID. */ | |
2391 | dhcpcd_initduid(&ctx, NULL); | 2397 | dhcpcd_initduid(&ctx, NULL); | |
2392 | 2398 | |||
2393 | /* Cache the default vendor option. */ | 2399 | /* Cache the default vendor option. */ | |
2394 | if (dhcp_vendor(ctx.vendor, sizeof(ctx.vendor)) == -1) | 2400 | if (dhcp_vendor(ctx.vendor, sizeof(ctx.vendor)) == -1) | |
2395 | logerr("dhcp_vendor"); | 2401 | logerr("dhcp_vendor"); | |
2396 | 2402 | |||
2397 | /* Start handling kernel messages for interfaces, addresses and | 2403 | /* Start handling kernel messages for interfaces, addresses and | |
2398 | * routes. */ | 2404 | * routes. */ | |
2399 | eloop_event_add(ctx.eloop, ctx.link_fd, dhcpcd_handlelink, &ctx); | 2405 | eloop_event_add(ctx.eloop, ctx.link_fd, dhcpcd_handlelink, &ctx); | |
2400 | 2406 | |||
2401 | #ifdef PRIVSEP | 2407 | #ifdef PRIVSEP | |
2402 | if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx, "stdio route") == -1) | 2408 | if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx, "stdio route") == -1) | |
2403 | goto exit_failure; | 2409 | goto exit_failure; | |
2404 | #endif | 2410 | #endif | |
2405 | 2411 | |||
2406 | /* When running dhcpcd against a single interface, we need to retain | 2412 | /* When running dhcpcd against a single interface, we need to retain | |
2407 | * the old behaviour of waiting for an IP address */ | 2413 | * the old behaviour of waiting for an IP address */ | |
2408 | if (ctx.ifc == 1 && !(ctx.options & DHCPCD_BACKGROUND)) | 2414 | if (ctx.ifc == 1 && !(ctx.options & DHCPCD_BACKGROUND)) | |
2409 | ctx.options |= DHCPCD_WAITIP; | 2415 | ctx.options |= DHCPCD_WAITIP; | |
2410 | 2416 | |||
2411 | ctx.ifaces = if_discover(&ctx, &ifaddrs, ctx.ifc, ctx.ifv); | 2417 | ctx.ifaces = if_discover(&ctx, &ifaddrs, ctx.ifc, ctx.ifv); | |
2412 | if (ctx.ifaces == NULL) { | 2418 | if (ctx.ifaces == NULL) { | |
2413 | logerr("%s: if_discover", __func__); | 2419 | logerr("%s: if_discover", __func__); | |
2414 | goto exit_failure; | 2420 | goto exit_failure; | |
2415 | } | 2421 | } | |
2416 | for (i = 0; i < ctx.ifc; i++) { | 2422 | for (i = 0; i < ctx.ifc; i++) { | |
2417 | if ((ifp = if_find(ctx.ifaces, ctx.ifv[i])) == NULL) | 2423 | if ((ifp = if_find(ctx.ifaces, ctx.ifv[i])) == NULL) | |
2418 | logerrx("%s: interface not found", | 2424 | logerrx("%s: interface not found", | |
2419 | ctx.ifv[i]); | 2425 | ctx.ifv[i]); | |
2420 | else if (!ifp->active) | 2426 | else if (!ifp->active) | |
2421 | logerrx("%s: interface has an invalid configuration", | 2427 | logerrx("%s: interface has an invalid configuration", | |
2422 | ctx.ifv[i]); | 2428 | ctx.ifv[i]); | |
2423 | } | 2429 | } | |
2424 | TAILQ_FOREACH(ifp, ctx.ifaces, next) { | 2430 | TAILQ_FOREACH(ifp, ctx.ifaces, next) { | |
2425 | if (ifp->active == IF_ACTIVE_USER) | 2431 | if (ifp->active == IF_ACTIVE_USER) | |
2426 | break; | 2432 | break; | |
2427 | } | 2433 | } | |
2428 | if (ifp == NULL) { | 2434 | if (ifp == NULL) { | |
2429 | if (ctx.ifc == 0) { | 2435 | if (ctx.ifc == 0) { | |
2430 | int loglevel; | 2436 | int loglevel; | |
2431 | 2437 | |||
2432 | loglevel = ctx.options & DHCPCD_INACTIVE ? | 2438 | loglevel = ctx.options & DHCPCD_INACTIVE ? | |
2433 | LOG_DEBUG : LOG_ERR; | 2439 | LOG_DEBUG : LOG_ERR; | |
2434 | logmessage(loglevel, "no valid interfaces found"); | 2440 | logmessage(loglevel, "no valid interfaces found"); | |
2435 | dhcpcd_daemonise(&ctx); | 2441 | dhcpcd_daemonise(&ctx); | |
2436 | } else | 2442 | } else | |
2437 | goto exit_failure; | 2443 | goto exit_failure; | |
2438 | if (!(ctx.options & DHCPCD_LINK)) { | 2444 | if (!(ctx.options & DHCPCD_LINK)) { | |
2439 | logerrx("aborting as link detection is disabled"); | 2445 | logerrx("aborting as link detection is disabled"); | |
2440 | goto exit_failure; | 2446 | goto exit_failure; | |
2441 | } | 2447 | } | |
2442 | } | 2448 | } | |
2443 | 2449 | |||
2444 | TAILQ_FOREACH(ifp, ctx.ifaces, next) { | 2450 | TAILQ_FOREACH(ifp, ctx.ifaces, next) { | |
2445 | if (ifp->active) | 2451 | if (ifp->active) | |
2446 | dhcpcd_initstate1(ifp, argc, argv, 0); | 2452 | dhcpcd_initstate1(ifp, argc, argv, 0); | |
2447 | } | 2453 | } | |
2448 | if_learnaddrs(&ctx, ctx.ifaces, &ifaddrs); | 2454 | if_learnaddrs(&ctx, ctx.ifaces, &ifaddrs); | |
2449 | 2455 | |||
2450 | if (ctx.options & DHCPCD_BACKGROUND) | 2456 | if (ctx.options & DHCPCD_BACKGROUND) | |
2451 | dhcpcd_daemonise(&ctx); | 2457 | dhcpcd_daemonise(&ctx); | |
2452 | 2458 | |||
2453 | opt = 0; | 2459 | opt = 0; | |
2454 | TAILQ_FOREACH(ifp, ctx.ifaces, next) { | 2460 | TAILQ_FOREACH(ifp, ctx.ifaces, next) { | |
2455 | if (ifp->active) { | 2461 | if (ifp->active) { | |
2456 | run_preinit(ifp); | 2462 | run_preinit(ifp); | |
2457 | if (if_is_link_up(ifp)) | 2463 | if (if_is_link_up(ifp)) | |
2458 | opt = 1; | 2464 | opt = 1; | |
2459 | } | 2465 | } | |
2460 | } | 2466 | } | |
2461 | 2467 | |||
2462 | if (!(ctx.options & DHCPCD_BACKGROUND)) { | 2468 | if (!(ctx.options & DHCPCD_BACKGROUND)) { | |
2463 | if (ctx.options & DHCPCD_MASTER) | 2469 | if (ctx.options & DHCPCD_MASTER) | |
2464 | t = ifo->timeout; | 2470 | t = ifo->timeout; | |
2465 | else { | 2471 | else { | |
2466 | t = 0; | 2472 | t = 0; | |
2467 | TAILQ_FOREACH(ifp, ctx.ifaces, next) { | 2473 | TAILQ_FOREACH(ifp, ctx.ifaces, next) { | |
2468 | if (ifp->active) { | 2474 | if (ifp->active) { | |
2469 | t = ifp->options->timeout; | 2475 | t = ifp->options->timeout; | |
2470 | break; | 2476 | break; | |
2471 | } | 2477 | } | |
2472 | } | 2478 | } | |
2473 | } | 2479 | } | |
2474 | if (opt == 0 && | 2480 | if (opt == 0 && | |
2475 | ctx.options & DHCPCD_LINK && | 2481 | ctx.options & DHCPCD_LINK && | |
2476 | !(ctx.options & DHCPCD_WAITIP)) | 2482 | !(ctx.options & DHCPCD_WAITIP)) | |
2477 | { | 2483 | { | |
2478 | int loglevel; | 2484 | int loglevel; | |
2479 | 2485 | |||
2480 | loglevel = ctx.options & DHCPCD_INACTIVE ? | 2486 | loglevel = ctx.options & DHCPCD_INACTIVE ? | |
2481 | LOG_DEBUG : LOG_WARNING; | 2487 | LOG_DEBUG : LOG_WARNING; | |
2482 | logmessage(loglevel, "no interfaces have a carrier"); | 2488 | logmessage(loglevel, "no interfaces have a carrier"); | |
2483 | dhcpcd_daemonise(&ctx); | 2489 | dhcpcd_daemonise(&ctx); | |
2484 | } else if (t > 0 && | 2490 | } else if (t > 0 && | |
2485 | /* Test mode removes the daemonise bit, so check for both */ | 2491 | /* Test mode removes the daemonise bit, so check for both */ | |
2486 | ctx.options & (DHCPCD_DAEMONISE | DHCPCD_TEST)) | 2492 | ctx.options & (DHCPCD_DAEMONISE | DHCPCD_TEST)) | |
2487 | { | 2493 | { | |
2488 | eloop_timeout_add_sec(ctx.eloop, t, | 2494 | eloop_timeout_add_sec(ctx.eloop, t, | |
2489 | handle_exit_timeout, &ctx); | 2495 | handle_exit_timeout, &ctx); | |
2490 | } | 2496 | } | |
2491 | } | 2497 | } | |
2492 | free_options(&ctx, ifo); | 2498 | free_options(&ctx, ifo); | |
2493 | ifo = NULL; | 2499 | ifo = NULL; | |
2494 | 2500 | |||
2495 | TAILQ_FOREACH(ifp, ctx.ifaces, next) { | 2501 | TAILQ_FOREACH(ifp, ctx.ifaces, next) { | |
2496 | if (ifp->active) | 2502 | if (ifp->active) | |
2497 | eloop_timeout_add_sec(ctx.eloop, 0, | 2503 | eloop_timeout_add_sec(ctx.eloop, 0, | |
2498 | dhcpcd_prestartinterface, ifp); | 2504 | dhcpcd_prestartinterface, ifp); | |
2499 | } | 2505 | } | |
2500 | 2506 | |||
2501 | run_loop: | 2507 | run_loop: | |
2502 | i = eloop_start(ctx.eloop, &ctx.sigset); | 2508 | i = eloop_start(ctx.eloop, &ctx.sigset); | |
2503 | if (i < 0) { | 2509 | if (i < 0) { | |
2504 | logerr("%s: eloop_start", __func__); | 2510 | logerr("%s: eloop_start", __func__); | |
2505 | goto exit_failure; | 2511 | goto exit_failure; | |
2506 | } | 2512 | } | |
2507 | goto exit1; | 2513 | goto exit1; | |
2508 | 2514 | |||
2509 | exit_success: | 2515 | exit_success: | |
2510 | i = EXIT_SUCCESS; | 2516 | i = EXIT_SUCCESS; | |
2511 | goto exit1; | 2517 | goto exit1; | |
2512 | 2518 | |||
2513 | exit_failure: | 2519 | exit_failure: | |
2514 | i = EXIT_FAILURE; | 2520 | i = EXIT_FAILURE; | |
2515 | 2521 | |||
2516 | exit1: | 2522 | exit1: | |
2517 | if (control_stop(&ctx) == -1) | 2523 | if (control_stop(&ctx) == -1) | |
2518 | logerr("%s: control_stop", __func__); | 2524 | logerr("%s: control_stop", __func__); | |
2519 | if (ifaddrs != NULL) { | 2525 | if (ifaddrs != NULL) { | |
2520 | #ifdef PRIVSEP_GETIFADDRS | 2526 | #ifdef PRIVSEP_GETIFADDRS | |
2521 | if (IN_PRIVSEP(&ctx)) | 2527 | if (IN_PRIVSEP(&ctx)) | |
2522 | free(ifaddrs); | 2528 | free(ifaddrs); | |
2523 | else | 2529 | else | |
2524 | #endif | 2530 | #endif | |
2525 | freeifaddrs(ifaddrs); | 2531 | freeifaddrs(ifaddrs); | |
2526 | } | 2532 | } | |
2527 | /* ps_stop will clear DHCPCD_PRIVSEP but we need to | 2533 | /* ps_stop will clear DHCPCD_PRIVSEP but we need to | |
2528 | * remember it to avoid attemping to remove the pidfile */ | 2534 | * remember it to avoid attemping to remove the pidfile */ | |
2529 | oi = ctx.options & DHCPCD_PRIVSEP ? 1 : 0; | 2535 | oi = ctx.options & DHCPCD_PRIVSEP ? 1 : 0; | |
2530 | #ifdef PRIVSEP | 2536 | #ifdef PRIVSEP | |
2531 | ps_stop(&ctx); | 2537 | ps_stop(&ctx); | |
2532 | #endif | 2538 | #endif | |
2533 | /* Free memory and close fd's */ | 2539 | /* Free memory and close fd's */ | |
2534 | if (ctx.ifaces) { | 2540 | if (ctx.ifaces) { | |
2535 | while ((ifp = TAILQ_FIRST(ctx.ifaces))) { | 2541 | while ((ifp = TAILQ_FIRST(ctx.ifaces))) { | |
2536 | TAILQ_REMOVE(ctx.ifaces, ifp, next); | 2542 | TAILQ_REMOVE(ctx.ifaces, ifp, next); | |
2537 | if_free(ifp); | 2543 | if_free(ifp); | |
2538 | } | 2544 | } | |
2539 | free(ctx.ifaces); | 2545 | free(ctx.ifaces); | |
2540 | ctx.ifaces = NULL; | 2546 | ctx.ifaces = NULL; | |
2541 | } | 2547 | } | |
2542 | free_options(&ctx, ifo); | 2548 | free_options(&ctx, ifo); | |
2543 | #ifdef HAVE_OPEN_MEMSTREAM | 2549 | #ifdef HAVE_OPEN_MEMSTREAM | |
2544 | if (ctx.script_fp) | 2550 | if (ctx.script_fp) | |
2545 | fclose(ctx.script_fp); | 2551 | fclose(ctx.script_fp); | |
2546 | #endif | 2552 | #endif | |
2547 | free(ctx.script_buf); | 2553 | free(ctx.script_buf); | |
2548 | free(ctx.script_env); | 2554 | free(ctx.script_env); | |
2549 | rt_dispose(&ctx); | 2555 | rt_dispose(&ctx); | |
2550 | free(ctx.duid); | 2556 | free(ctx.duid); | |
2551 | if (ctx.link_fd != -1) { | 2557 | if (ctx.link_fd != -1) { | |
2552 | eloop_event_delete(ctx.eloop, ctx.link_fd); | 2558 | eloop_event_delete(ctx.eloop, ctx.link_fd); | |
2553 | close(ctx.link_fd); | 2559 | close(ctx.link_fd); | |
2554 | } | 2560 | } | |
2555 | if_closesockets(&ctx); | 2561 | if_closesockets(&ctx); | |
2556 | free_globals(&ctx); | 2562 | free_globals(&ctx); | |
2557 | #ifdef INET6 | 2563 | #ifdef INET6 | |
2558 | ipv6_ctxfree(&ctx); | 2564 | ipv6_ctxfree(&ctx); | |
2559 | #endif | 2565 | #endif | |
2560 | #ifdef PLUGIN_DEV | 2566 | #ifdef PLUGIN_DEV | |
2561 | dev_stop(&ctx); | 2567 | dev_stop(&ctx); | |
2562 | #endif | 2568 | #endif | |
2563 | #ifdef PRIVSEP | 2569 | #ifdef PRIVSEP | |
2564 | eloop_free(ctx.ps_eloop); | 2570 | eloop_free(ctx.ps_eloop); | |
2565 | #endif | 2571 | #endif | |
2566 | eloop_free(ctx.eloop); | 2572 | eloop_free(ctx.eloop); | |
2567 | if (ctx.script != dhcpcd_default_script) | 2573 | if (ctx.script != dhcpcd_default_script) | |
2568 | free(ctx.script); | 2574 | free(ctx.script); | |
2569 | if (ctx.options & DHCPCD_STARTED && !(ctx.options & DHCPCD_FORKED)) | 2575 | if (ctx.options & DHCPCD_STARTED && !(ctx.options & DHCPCD_FORKED)) | |
2570 | loginfox(PACKAGE " exited"); | 2576 | loginfox(PACKAGE " exited"); | |
2571 | logclose(); | 2577 | logclose(); | |
2572 | free(ctx.logfile); | 2578 | free(ctx.logfile); | |
2573 | free(ctx.ctl_buf); | 2579 | free(ctx.ctl_buf); | |
2574 | #ifdef SETPROCTITLE_H | 2580 | #ifdef SETPROCTITLE_H | |
2575 | setproctitle_fini(); | 2581 | setproctitle_fini(); | |
2576 | #endif | 2582 | #endif | |
2577 | #ifdef USE_SIGNALS | 2583 | #ifdef USE_SIGNALS | |
2578 | if (ctx.options & DHCPCD_STARTED) { | 2584 | if (ctx.options & DHCPCD_STARTED) { | |
2579 | /* Try to detach from the launch process. */ | 2585 | /* Try to detach from the launch process. */ | |
2580 | if (ctx.fork_fd != -1 && | 2586 | if (ctx.fork_fd != -1 && | |
2581 | write(ctx.fork_fd, &i, sizeof(i)) == -1) | 2587 | write(ctx.fork_fd, &i, sizeof(i)) == -1) | |
2582 | logerr("%s: write", __func__); | 2588 | logerr("%s: write", __func__); | |
2583 | } | 2589 | } | |
2584 | if (ctx.options & DHCPCD_FORKED || oi != 0) | 2590 | if (ctx.options & DHCPCD_FORKED || oi != 0) | |
2585 | _exit(i); /* so atexit won't remove our pidfile */ | 2591 | _exit(i); /* so atexit won't remove our pidfile */ | |
2586 | #endif | 2592 | #endif | |
2587 | return i; | 2593 | return i; | |
2588 | } | 2594 | } |
--- src/external/bsd/dhcpcd/dist/src/logerr.c 2020/10/12 14:09:03 1.10
+++ src/external/bsd/dhcpcd/dist/src/logerr.c 2020/11/01 14:24:01 1.11
@@ -1,416 +1,496 @@ | @@ -1,416 +1,496 @@ | |||
1 | /* SPDX-License-Identifier: BSD-2-Clause */ | 1 | /* SPDX-License-Identifier: BSD-2-Clause */ | |
2 | /* | 2 | /* | |
3 | * logerr: errx with logging | 3 | * logerr: errx with logging | |
4 | * Copyright (c) 2006-2020 Roy Marples <roy@marples.name> | 4 | * Copyright (c) 2006-2020 Roy Marples <roy@marples.name> | |
5 | * All rights reserved | 5 | * All rights reserved | |
6 | 6 | |||
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * | 15 | * | |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
26 | * SUCH DAMAGE. | 26 | * SUCH DAMAGE. | |
27 | */ | 27 | */ | |
28 | 28 | |||
29 | #include <sys/time.h> | 29 | #include <sys/time.h> | |
30 | #include <errno.h> | 30 | #include <errno.h> | |
31 | #include <stdbool.h> | 31 | #include <stdbool.h> | |
32 | #include <stdarg.h> | 32 | #include <stdarg.h> | |
33 | #include <stdio.h> | 33 | #include <stdio.h> | |
34 | #include <stdlib.h> | 34 | #include <stdlib.h> | |
35 | #include <string.h> | 35 | #include <string.h> | |
36 | #include <syslog.h> | 36 | #include <syslog.h> | |
37 | #include <time.h> | 37 | #include <time.h> | |
38 | #include <unistd.h> | 38 | #include <unistd.h> | |
39 | 39 | |||
40 | #include "logerr.h" | 40 | #include "logerr.h" | |
41 | 41 | |||
42 | #ifndef LOGERR_SYSLOG_FACILITY | 42 | #ifndef LOGERR_SYSLOG_FACILITY | |
43 | #define LOGERR_SYSLOG_FACILITY LOG_DAEMON | 43 | #define LOGERR_SYSLOG_FACILITY LOG_DAEMON | |
44 | #endif | 44 | #endif | |
45 | 45 | |||
46 | #ifdef SMALL | 46 | #ifdef SMALL | |
47 | #undef LOGERR_TAG | 47 | #undef LOGERR_TAG | |
48 | #endif | 48 | #endif | |
49 | 49 | |||
50 | /* syslog protocol is 1k message max, RFC 3164 section 4.1 */ | |||
51 | #define LOGERR_SYSLOGBUF 1024 + sizeof(int) + sizeof(pid_t) | |||
52 | ||||
50 | #define UNUSED(a) (void)(a) | 53 | #define UNUSED(a) (void)(a) | |
51 | 54 | |||
52 | struct logctx { | 55 | struct logctx { | |
53 | char log_buf[BUFSIZ]; | 56 | char log_buf[BUFSIZ]; | |
54 | unsigned int log_opts; | 57 | unsigned int log_opts; | |
58 | int log_fd; | |||
59 | pid_t log_pid; | |||
55 | #ifndef SMALL | 60 | #ifndef SMALL | |
56 | FILE *log_file; | 61 | FILE *log_file; | |
57 | #ifdef LOGERR_TAG | 62 | #ifdef LOGERR_TAG | |
58 | const char *log_tag; | 63 | const char *log_tag; | |
59 | #endif | 64 | #endif | |
60 | #endif | 65 | #endif | |
61 | }; | 66 | }; | |
62 | 67 | |||
63 | static struct logctx _logctx = { | 68 | static struct logctx _logctx = { | |
64 | /* syslog style, but without the hostname or tag. */ | 69 | /* syslog style, but without the hostname or tag. */ | |
65 | .log_opts = LOGERR_LOG | LOGERR_LOG_DATE | LOGERR_LOG_PID, | 70 | .log_opts = LOGERR_LOG | LOGERR_LOG_DATE | LOGERR_LOG_PID, | |
71 | .log_fd = -1, | |||
72 | .log_pid = 0, | |||
66 | }; | 73 | }; | |
67 | 74 | |||
68 | #if defined(LOGERR_TAG) && defined(__linux__) | 75 | #if defined(__linux__) | |
69 | /* Poor man's getprogname(3). */ | 76 | /* Poor man's getprogname(3). */ | |
70 | static char *_logprog; | 77 | static char *_logprog; | |
71 | static const char * | 78 | static const char * | |
72 | getprogname(void) | 79 | getprogname(void) | |
73 | { | 80 | { | |
74 | const char *p; | 81 | const char *p; | |
75 | 82 | |||
76 | /* Use PATH_MAX + 1 to avoid truncation. */ | 83 | /* Use PATH_MAX + 1 to avoid truncation. */ | |
77 | if (_logprog == NULL) { | 84 | if (_logprog == NULL) { | |
78 | /* readlink(2) does not append a NULL byte, | 85 | /* readlink(2) does not append a NULL byte, | |
79 | * so zero the buffer. */ | 86 | * so zero the buffer. */ | |
80 | if ((_logprog = calloc(1, PATH_MAX + 1)) == NULL) | 87 | if ((_logprog = calloc(1, PATH_MAX + 1)) == NULL) | |
81 | return NULL; | 88 | return NULL; | |
89 | if (readlink("/proc/self/exe", _logprog, PATH_MAX + 1) == -1) { | |||
90 | free(_logprog); | |||
91 | _logprog = NULL; | |||
92 | return NULL; | |||
93 | } | |||
82 | } | 94 | } | |
83 | if (readlink("/proc/self/exe", _logprog, PATH_MAX + 1) == -1) | |||
84 | return NULL; | |||
85 | if (_logprog[0] == '[') | 95 | if (_logprog[0] == '[') | |
86 | return NULL; | 96 | return NULL; | |
87 | p = strrchr(_logprog, '/'); | 97 | p = strrchr(_logprog, '/'); | |
88 | if (p == NULL) | 98 | if (p == NULL) | |
89 | return _logprog; | 99 | return _logprog; | |
90 | return p + 1; | 100 | return p + 1; | |
91 | } | 101 | } | |
92 | #endif | 102 | #endif | |
93 | 103 | |||
94 | #ifndef SMALL | 104 | #ifndef SMALL | |
95 | /* Write the time, syslog style. month day time - */ | 105 | /* Write the time, syslog style. month day time - */ | |
96 | static int | 106 | static int | |
97 | logprintdate(FILE *stream) | 107 | logprintdate(FILE *stream) | |
98 | { | 108 | { | |
99 | struct timeval tv; | 109 | struct timeval tv; | |
100 | time_t now; | 110 | time_t now; | |
101 | struct tm tmnow; | 111 | struct tm tmnow; | |
102 | char buf[32]; | 112 | char buf[32]; | |
103 | 113 | |||
104 | if (gettimeofday(&tv, NULL) == -1) | 114 | if (gettimeofday(&tv, NULL) == -1) | |
105 | return -1; | 115 | return -1; | |
106 | 116 | |||
107 | now = tv.tv_sec; | 117 | now = tv.tv_sec; | |
108 | if (localtime_r(&now, &tmnow) == NULL) | 118 | if (localtime_r(&now, &tmnow) == NULL) | |
109 | return -1; | 119 | return -1; | |
110 | if (strftime(buf, sizeof(buf), "%b %d %T ", &tmnow) == 0) | 120 | if (strftime(buf, sizeof(buf), "%b %d %T ", &tmnow) == 0) | |
111 | return -1; | 121 | return -1; | |
112 | return fprintf(stream, "%s", buf); | 122 | return fprintf(stream, "%s", buf); | |
113 | } | 123 | } | |
114 | #endif | 124 | #endif | |
115 | 125 | |||
116 | __printflike(3, 0) static int | 126 | __printflike(3, 0) static int | |
117 | vlogprintf_r(struct logctx *ctx, FILE *stream, const char *fmt, va_list args) | 127 | vlogprintf_r(struct logctx *ctx, FILE *stream, const char *fmt, va_list args) | |
118 | { | 128 | { | |
119 | int len = 0, e; | 129 | int len = 0, e; | |
120 | va_list a; | 130 | va_list a; | |
121 | #ifndef SMALL | 131 | #ifndef SMALL | |
122 | bool log_pid; | 132 | bool log_pid; | |
123 | #ifdef LOGERR_TAG | 133 | #ifdef LOGERR_TAG | |
124 | bool log_tag; | 134 | bool log_tag; | |
125 | #endif | 135 | #endif | |
126 | 136 | |||
127 | if ((stream == stderr && ctx->log_opts & LOGERR_ERR_DATE) || | 137 | if ((stream == stderr && ctx->log_opts & LOGERR_ERR_DATE) || | |
128 | (stream != stderr && ctx->log_opts & LOGERR_LOG_DATE)) | 138 | (stream != stderr && ctx->log_opts & LOGERR_LOG_DATE)) | |
129 | { | 139 | { | |
130 | if ((e = logprintdate(stream)) == -1) | 140 | if ((e = logprintdate(stream)) == -1) | |
131 | return -1; | 141 | return -1; | |
132 | len += e; | 142 | len += e; | |
133 | } | 143 | } | |
134 | 144 | |||
135 | #ifdef LOGERR_TAG | 145 | #ifdef LOGERR_TAG | |
136 | log_tag = ((stream == stderr && ctx->log_opts & LOGERR_ERR_TAG) || | 146 | log_tag = ((stream == stderr && ctx->log_opts & LOGERR_ERR_TAG) || | |
137 | (stream != stderr && ctx->log_opts & LOGERR_LOG_TAG)); | 147 | (stream != stderr && ctx->log_opts & LOGERR_LOG_TAG)); | |
138 | if (log_tag) { | 148 | if (log_tag) { | |
139 | if (ctx->log_tag == NULL) | 149 | if (ctx->log_tag == NULL) | |
140 | ctx->log_tag = getprogname(); | 150 | ctx->log_tag = getprogname(); | |
141 | if ((e = fprintf(stream, "%s", ctx->log_tag)) == -1) | 151 | if ((e = fprintf(stream, "%s", ctx->log_tag)) == -1) | |
142 | return -1; | 152 | return -1; | |
143 | len += e; | 153 | len += e; | |
144 | } | 154 | } | |
145 | #endif | 155 | #endif | |
146 | 156 | |||
147 | log_pid = ((stream == stderr && ctx->log_opts & LOGERR_ERR_PID) || | 157 | log_pid = ((stream == stderr && ctx->log_opts & LOGERR_ERR_PID) || | |
148 | (stream != stderr && ctx->log_opts & LOGERR_LOG_PID)); | 158 | (stream != stderr && ctx->log_opts & LOGERR_LOG_PID)); | |
149 | if (log_pid) { | 159 | if (log_pid) { | |
150 | if ((e = fprintf(stream, "[%d]", getpid())) == -1) | 160 | pid_t pid; | |
161 | ||||
162 | if (ctx->log_pid == 0) | |||
163 | pid = getpid(); | |||
164 | else | |||
165 | pid = ctx->log_pid; | |||
166 | if ((e = fprintf(stream, "[%d]", pid)) == -1) | |||
151 | return -1; | 167 | return -1; | |
152 | len += e; | 168 | len += e; | |
153 | } | 169 | } | |
154 | 170 | |||
155 | #ifdef LOGERR_TAG | 171 | #ifdef LOGERR_TAG | |
156 | if (log_tag || log_pid) | 172 | if (log_tag || log_pid) | |
157 | #else | 173 | #else | |
158 | if (log_pid) | 174 | if (log_pid) | |
159 | #endif | 175 | #endif | |
160 | { | 176 | { | |
161 | if ((e = fprintf(stream, ": ")) == -1) | 177 | if ((e = fprintf(stream, ": ")) == -1) | |
162 | return -1; | 178 | return -1; | |
163 | len += e; | 179 | len += e; | |
164 | } | 180 | } | |
165 | #else | 181 | #else | |
166 | UNUSED(ctx); | 182 | UNUSED(ctx); | |
167 | #endif | 183 | #endif | |
168 | 184 | |||
169 | va_copy(a, args); | 185 | va_copy(a, args); | |
170 | e = vfprintf(stream, fmt, a); | 186 | e = vfprintf(stream, fmt, a); | |
171 | if (fputc('\n', stream) == EOF) | 187 | if (fputc('\n', stream) == EOF) | |
172 | e = -1; | 188 | e = -1; | |
173 | else if (e != -1) | 189 | else if (e != -1) | |
174 | e++; | 190 | e++; | |
175 | va_end(a); | 191 | va_end(a); | |
176 | 192 | |||
177 | return e == -1 ? -1 : len + e; | 193 | return e == -1 ? -1 : len + e; | |
178 | } | 194 | } | |
179 | 195 | |||
180 | /* | 196 | /* | |
181 | * NetBSD's gcc has been modified to check for the non standard %m in printf | 197 | * NetBSD's gcc has been modified to check for the non standard %m in printf | |
182 | * like functions and warn noisily about it that they should be marked as | 198 | * like functions and warn noisily about it that they should be marked as | |
183 | * syslog like instead. | 199 | * syslog like instead. | |
184 | * This is all well and good, but our logger also goes via vfprintf and | 200 | * This is all well and good, but our logger also goes via vfprintf and | |
185 | * when marked as a sysloglike funcion, gcc will then warn us that the | 201 | * when marked as a sysloglike funcion, gcc will then warn us that the | |
186 | * function should be printflike instead! | 202 | * function should be printflike instead! | |
187 | * This creates an infinte loop of gcc warnings. | 203 | * This creates an infinte loop of gcc warnings. | |
188 | * Until NetBSD solves this issue, we have to disable a gcc diagnostic | 204 | * Until NetBSD solves this issue, we have to disable a gcc diagnostic | |
189 | * for our fully standards compliant code in the logger function. | 205 | * for our fully standards compliant code in the logger function. | |
190 | */ | 206 | */ | |
191 | #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5)) | 207 | #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5)) | |
192 | #pragma GCC diagnostic push | 208 | #pragma GCC diagnostic push | |
193 | #pragma GCC diagnostic ignored "-Wmissing-format-attribute" | 209 | #pragma GCC diagnostic ignored "-Wmissing-format-attribute" | |
194 | #endif | 210 | #endif | |
195 | __printflike(2, 0) static int | 211 | __printflike(2, 0) static int | |
196 | vlogmessage(int pri, const char *fmt, va_list args) | 212 | vlogmessage(int pri, const char *fmt, va_list args) | |
197 | { | 213 | { | |
198 | struct logctx *ctx = &_logctx; | 214 | struct logctx *ctx = &_logctx; | |
199 | int len = 0; | 215 | int len = 0; | |
200 | 216 | |||
217 | if (ctx->log_fd != -1) { | |||
218 | char buf[LOGERR_SYSLOGBUF]; | |||
219 | pid_t pid; | |||
220 | ||||
221 | memcpy(buf, &pri, sizeof(pri)); | |||
222 | pid = getpid(); | |||
223 | memcpy(buf + sizeof(pri), &pid, sizeof(pid)); | |||
224 | len = vsnprintf(buf + sizeof(pri) + sizeof(pid), | |||
225 | sizeof(buf) - sizeof(pri) - sizeof(pid), | |||
226 | fmt, args); | |||
227 | if (len != -1) | |||
228 | len = (int)write(ctx->log_fd, buf, | |||
229 | ((size_t)++len) + sizeof(pri) + sizeof(pid)); | |||
230 | return len; | |||
231 | } | |||
232 | ||||
201 | if (ctx->log_opts & LOGERR_ERR && | 233 | if (ctx->log_opts & LOGERR_ERR && | |
202 | (pri <= LOG_ERR || | 234 | (pri <= LOG_ERR || | |
203 | (!(ctx->log_opts & LOGERR_QUIET) && pri <= LOG_INFO) || | 235 | (!(ctx->log_opts & LOGERR_QUIET) && pri <= LOG_INFO) || | |
204 | (ctx->log_opts & LOGERR_DEBUG && pri <= LOG_DEBUG))) | 236 | (ctx->log_opts & LOGERR_DEBUG && pri <= LOG_DEBUG))) | |
205 | len = vlogprintf_r(ctx, stderr, fmt, args); | 237 | len = vlogprintf_r(ctx, stderr, fmt, args); | |
206 | 238 | |||
207 | if (!(ctx->log_opts & LOGERR_LOG)) | |||
208 | return len; | |||
209 | ||||
210 | #ifndef SMALL | 239 | #ifndef SMALL | |
211 | if (ctx->log_file != NULL && | 240 | if (ctx->log_file != NULL && | |
212 | (pri != LOG_DEBUG || (ctx->log_opts & LOGERR_DEBUG))) | 241 | (pri != LOG_DEBUG || (ctx->log_opts & LOGERR_DEBUG))) | |
213 | len = vlogprintf_r(ctx, ctx->log_file, fmt, args); | 242 | len = vlogprintf_r(ctx, ctx->log_file, fmt, args); | |
214 | #endif | 243 | #endif | |
215 | 244 | |||
216 | vsyslog(pri, fmt, args); | 245 | if (ctx->log_opts & LOGERR_LOG) | |
246 | vsyslog(pri, fmt, args); | |||
247 | ||||
217 | return len; | 248 | return len; | |
218 | } | 249 | } | |
219 | #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5)) | 250 | #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5)) | |
220 | #pragma GCC diagnostic pop | 251 | #pragma GCC diagnostic pop | |
221 | #endif | 252 | #endif | |
222 | 253 | |||
223 | __printflike(2, 3) void | 254 | __printflike(2, 3) void | |
224 | logmessage(int pri, const char *fmt, ...) | 255 | logmessage(int pri, const char *fmt, ...) | |
225 | { | 256 | { | |
226 | va_list args; | 257 | va_list args; | |
227 | 258 | |||
228 | va_start(args, fmt); | 259 | va_start(args, fmt); | |
229 | vlogmessage(pri, fmt, args); | 260 | vlogmessage(pri, fmt, args); | |
230 | va_end(args); | 261 | va_end(args); | |
231 | } | 262 | } | |
232 | 263 | |||
233 | __printflike(2, 0) static void | 264 | __printflike(2, 0) static void | |
234 | vlogerrmessage(int pri, const char *fmt, va_list args) | 265 | vlogerrmessage(int pri, const char *fmt, va_list args) | |
235 | { | 266 | { | |
236 | int _errno = errno; | 267 | int _errno = errno; | |
237 | char buf[1024]; | 268 | char buf[1024]; | |
238 | 269 | |||
239 | vsnprintf(buf, sizeof(buf), fmt, args); | 270 | vsnprintf(buf, sizeof(buf), fmt, args); | |
240 | logmessage(pri, "%s: %s", buf, strerror(_errno)); | 271 | logmessage(pri, "%s: %s", buf, strerror(_errno)); | |
241 | errno = _errno; | 272 | errno = _errno; | |
242 | } | 273 | } | |
243 | 274 | |||
244 | __printflike(2, 3) void | 275 | __printflike(2, 3) void | |
245 | logerrmessage(int pri, const char *fmt, ...) | 276 | logerrmessage(int pri, const char *fmt, ...) | |
246 | { | 277 | { | |
247 | va_list args; | 278 | va_list args; | |
248 | 279 | |||
249 | va_start(args, fmt); | 280 | va_start(args, fmt); | |
250 | vlogerrmessage(pri, fmt, args); | 281 | vlogerrmessage(pri, fmt, args); | |
251 | va_end(args); | 282 | va_end(args); | |
252 | } | 283 | } | |
253 | 284 | |||
254 | void | 285 | void | |
255 | log_debug(const char *fmt, ...) | 286 | log_debug(const char *fmt, ...) | |
256 | { | 287 | { | |
257 | va_list args; | 288 | va_list args; | |
258 | 289 | |||
259 | va_start(args, fmt); | 290 | va_start(args, fmt); | |
260 | vlogerrmessage(LOG_DEBUG, fmt, args); | 291 | vlogerrmessage(LOG_DEBUG, fmt, args); | |
261 | va_end(args); | 292 | va_end(args); | |
262 | } | 293 | } | |
263 | 294 | |||
264 | void | 295 | void | |
265 | log_debugx(const char *fmt, ...) | 296 | log_debugx(const char *fmt, ...) | |
266 | { | 297 | { | |
267 | va_list args; | 298 | va_list args; | |
268 | 299 | |||
269 | va_start(args, fmt); | 300 | va_start(args, fmt); | |
270 | vlogmessage(LOG_DEBUG, fmt, args); | 301 | vlogmessage(LOG_DEBUG, fmt, args); | |
271 | va_end(args); | 302 | va_end(args); | |
272 | } | 303 | } | |
273 | 304 | |||
274 | void | 305 | void | |
275 | log_info(const char *fmt, ...) | 306 | log_info(const char *fmt, ...) | |
276 | { | 307 | { | |
277 | va_list args; | 308 | va_list args; | |
278 | 309 | |||
279 | va_start(args, fmt); | 310 | va_start(args, fmt); | |
280 | vlogerrmessage(LOG_INFO, fmt, args); | 311 | vlogerrmessage(LOG_INFO, fmt, args); | |
281 | va_end(args); | 312 | va_end(args); | |
282 | } | 313 | } | |
283 | 314 | |||
284 | void | 315 | void | |
285 | log_infox(const char *fmt, ...) | 316 | log_infox(const char *fmt, ...) | |
286 | { | 317 | { | |
287 | va_list args; | 318 | va_list args; | |
288 | 319 | |||
289 | va_start(args, fmt); | 320 | va_start(args, fmt); | |
290 | vlogmessage(LOG_INFO, fmt, args); | 321 | vlogmessage(LOG_INFO, fmt, args); | |
291 | va_end(args); | 322 | va_end(args); | |
292 | } | 323 | } | |
293 | 324 | |||
294 | void | 325 | void | |
295 | log_warn(const char *fmt, ...) | 326 | log_warn(const char *fmt, ...) | |
296 | { | 327 | { | |
297 | va_list args; | 328 | va_list args; | |
298 | 329 | |||
299 | va_start(args, fmt); | 330 | va_start(args, fmt); | |
300 | vlogerrmessage(LOG_WARNING, fmt, args); | 331 | vlogerrmessage(LOG_WARNING, fmt, args); | |
301 | va_end(args); | 332 | va_end(args); | |
302 | } | 333 | } | |
303 | 334 | |||
304 | void | 335 | void | |
305 | log_warnx(const char *fmt, ...) | 336 | log_warnx(const char *fmt, ...) | |
306 | { | 337 | { | |
307 | va_list args; | 338 | va_list args; | |
308 | 339 | |||
309 | va_start(args, fmt); | 340 | va_start(args, fmt); | |
310 | vlogmessage(LOG_WARNING, fmt, args); | 341 | vlogmessage(LOG_WARNING, fmt, args); | |
311 | va_end(args); | 342 | va_end(args); | |
312 | } | 343 | } | |
313 | 344 | |||
314 | void | 345 | void | |
315 | log_err(const char *fmt, ...) | 346 | log_err(const char *fmt, ...) | |
316 | { | 347 | { | |
317 | va_list args; | 348 | va_list args; | |
318 | 349 | |||
319 | va_start(args, fmt); | 350 | va_start(args, fmt); | |
320 | vlogerrmessage(LOG_ERR, fmt, args); | 351 | vlogerrmessage(LOG_ERR, fmt, args); | |
321 | va_end(args); | 352 | va_end(args); | |
322 | } | 353 | } | |
323 | 354 | |||
324 | void | 355 | void | |
325 | log_errx(const char *fmt, ...) | 356 | log_errx(const char *fmt, ...) | |
326 | { | 357 | { | |
327 | va_list args; | 358 | va_list args; | |
328 | 359 | |||
329 | va_start(args, fmt); | 360 | va_start(args, fmt); | |
330 | vlogmessage(LOG_ERR, fmt, args); | 361 | vlogmessage(LOG_ERR, fmt, args); | |
331 | va_end(args); | 362 | va_end(args); | |
332 | } | 363 | } | |
333 | 364 | |||
365 | int | |||
366 | loggetfd(void) | |||
367 | { | |||
368 | struct logctx *ctx = &_logctx; | |||
369 | ||||
370 | return ctx->log_fd; | |||
371 | } | |||
372 | ||||
373 | void | |||
374 | logsetfd(int fd) | |||
375 | { | |||
376 | struct logctx *ctx = &_logctx; | |||
377 | ||||
378 | ctx->log_fd = fd; | |||
379 | #ifndef SMALL | |||
380 | if (fd != -1 && ctx->log_file != NULL) { | |||
381 | fclose(ctx->log_file); | |||
382 | ctx->log_file = NULL; | |||
383 | } | |||
384 | #endif | |||
385 | } | |||
386 | ||||
387 | int | |||
388 | logreadfd(int fd) | |||
389 | { | |||
390 | struct logctx *ctx = &_logctx; | |||
391 | char buf[LOGERR_SYSLOGBUF]; | |||
392 | int len, pri; | |||
393 | ||||
394 | len = (int)read(fd, buf, sizeof(buf)); | |||
395 | if (len == -1) | |||
396 | return -1; | |||
397 | ||||
398 | /* Ensure we have pri, pid and a terminator */ | |||
399 | if (len < (int)(sizeof(pri) + sizeof(pid_t) + 1) || | |||
400 | buf[len - 1] != '\0') | |||
401 | { | |||
402 | errno = EINVAL; | |||
403 | return -1; | |||
404 | } | |||
405 | ||||
406 | memcpy(&pri, buf, sizeof(pri)); | |||
407 | memcpy(&ctx->log_pid, buf + sizeof(pri), sizeof(ctx->log_pid)); | |||
408 | logmessage(pri, "%s", buf + sizeof(pri) + sizeof(ctx->log_pid)); | |||
409 | ctx->log_pid = 0; | |||
410 | return len; | |||
411 | } | |||
412 | ||||
334 | unsigned int | 413 | unsigned int | |
335 | loggetopts(void) | 414 | loggetopts(void) | |
336 | { | 415 | { | |
337 | struct logctx *ctx = &_logctx; | 416 | struct logctx *ctx = &_logctx; | |
338 | 417 | |||
339 | return ctx->log_opts; | 418 | return ctx->log_opts; | |
340 | } | 419 | } | |
341 | 420 | |||
342 | void | 421 | void | |
343 | logsetopts(unsigned int opts) | 422 | logsetopts(unsigned int opts) | |
344 | { | 423 | { | |
345 | struct logctx *ctx = &_logctx; | 424 | struct logctx *ctx = &_logctx; | |
346 | 425 | |||
347 | ctx->log_opts = opts; | 426 | ctx->log_opts = opts; | |
348 | setlogmask(LOG_UPTO(opts & LOGERR_DEBUG ? LOG_DEBUG : LOG_INFO)); | 427 | setlogmask(LOG_UPTO(opts & LOGERR_DEBUG ? LOG_DEBUG : LOG_INFO)); | |
349 | } | 428 | } | |
350 | 429 | |||
351 | #ifdef LOGERR_TAG | 430 | #ifdef LOGERR_TAG | |
352 | void | 431 | void | |
353 | logsettag(const char *tag) | 432 | logsettag(const char *tag) | |
354 | { | 433 | { | |
355 | #if !defined(SMALL) | 434 | #if !defined(SMALL) | |
356 | struct logctx *ctx = &_logctx; | 435 | struct logctx *ctx = &_logctx; | |
357 | 436 | |||
358 | ctx->log_tag = tag; | 437 | ctx->log_tag = tag; | |
359 | #else | 438 | #else | |
360 | UNUSED(tag); | 439 | UNUSED(tag); | |
361 | #endif | 440 | #endif | |
362 | } | 441 | } | |
363 | #endif | 442 | #endif | |
364 | 443 | |||
365 | int | 444 | int | |
366 | logopen(const char *path) | 445 | logopen(const char *path) | |
367 | { | 446 | { | |
368 | struct logctx *ctx = &_logctx; | 447 | struct logctx *ctx = &_logctx; | |
369 | int opts = 0; | 448 | int opts = 0; | |
370 | 449 | |||
371 | /* Cache timezone */ | 450 | /* Cache timezone */ | |
372 | tzset(); | 451 | tzset(); | |
373 | 452 | |||
374 | (void)setvbuf(stderr, ctx->log_buf, _IOLBF, sizeof(ctx->log_buf)); | 453 | (void)setvbuf(stderr, ctx->log_buf, _IOLBF, sizeof(ctx->log_buf)); | |
375 | 454 | |||
376 | if (!(ctx->log_opts & LOGERR_LOG)) | 455 | #ifndef SMALL | |
377 | return 1; | 456 | if (ctx->log_file != NULL) { | |
378 | 457 | fclose(ctx->log_file); | ||
379 | #ifdef LOG_NDELAY | 458 | ctx->log_file = NULL; | |
380 | opts |= LOG_NDELAY; | 459 | } | |
381 | #endif | 460 | #endif | |
461 | ||||
382 | if (ctx->log_opts & LOGERR_LOG_PID) | 462 | if (ctx->log_opts & LOGERR_LOG_PID) | |
383 | opts |= LOG_PID; | 463 | opts |= LOG_PID; | |
384 | openlog(NULL, opts, LOGERR_SYSLOG_FACILITY); | 464 | openlog(getprogname(), opts, LOGERR_SYSLOG_FACILITY); | |
385 | if (path == NULL) | 465 | if (path == NULL) | |
386 | return 1; | 466 | return 1; | |
387 | 467 | |||
388 | #ifndef SMALL | 468 | #ifndef SMALL | |
389 | if ((ctx->log_file = fopen(path, "ae")) == NULL) | 469 | if ((ctx->log_file = fopen(path, "ae")) == NULL) | |
390 | return -1; | 470 | return -1; | |
391 | setlinebuf(ctx->log_file); | 471 | setlinebuf(ctx->log_file); | |
392 | return fileno(ctx->log_file); | 472 | return fileno(ctx->log_file); | |
393 | #else | 473 | #else | |
394 | errno = ENOTSUP; | 474 | errno = ENOTSUP; | |
395 | return -1; | 475 | return -1; | |
396 | #endif | 476 | #endif | |
397 | } | 477 | } | |
398 | 478 | |||
399 | void | 479 | void | |
400 | logclose(void) | 480 | logclose(void) | |
401 | { | 481 | { | |
402 | #ifndef SMALL | 482 | #ifndef SMALL | |
403 | struct logctx *ctx = &_logctx; | 483 | struct logctx *ctx = &_logctx; | |
404 | #endif | 484 | #endif | |
405 | 485 | |||
406 | closelog(); | 486 | closelog(); | |
407 | #ifndef SMALL | 487 | #ifndef SMALL | |
408 | if (ctx->log_file == NULL) | 488 | if (ctx->log_file == NULL) | |
409 | return; | 489 | return; | |
410 | fclose(ctx->log_file); | 490 | fclose(ctx->log_file); | |
411 | ctx->log_file = NULL; | 491 | ctx->log_file = NULL; | |
412 | #endif | 492 | #endif | |
413 | #if defined(LOGERR_TAG) && defined(__linux__) | 493 | #if defined(__linux__) | |
414 | free(_logprog); | 494 | free(_logprog); | |
415 | #endif | 495 | #endif | |
416 | } | 496 | } |
--- src/external/bsd/dhcpcd/dist/src/privsep.c 2020/10/12 14:09:03 1.9
+++ src/external/bsd/dhcpcd/dist/src/privsep.c 2020/11/01 14:24:01 1.10
@@ -1,984 +1,997 @@ | @@ -1,984 +1,997 @@ | |||
1 | /* SPDX-License-Identifier: BSD-2-Clause */ | 1 | /* SPDX-License-Identifier: BSD-2-Clause */ | |
2 | /* | 2 | /* | |
3 | * Privilege Separation for dhcpcd | 3 | * Privilege Separation for dhcpcd | |
4 | * Copyright (c) 2006-2020 Roy Marples <roy@marples.name> | 4 | * Copyright (c) 2006-2020 Roy Marples <roy@marples.name> | |
5 | * All rights reserved | 5 | * All rights reserved | |
6 | 6 | |||
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * | 15 | * | |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
26 | * SUCH DAMAGE. | 26 | * SUCH DAMAGE. | |
27 | */ | 27 | */ | |
28 | 28 | |||
29 | /* | 29 | /* | |
30 | * The current design is this: | 30 | * The current design is this: | |
31 | * Spawn a priv process to carry out privileged actions and | 31 | * Spawn a priv process to carry out privileged actions and | |
32 | * spawning unpriv process to initate network connections such as BPF | 32 | * spawning unpriv process to initate network connections such as BPF | |
33 | * or address specific listener. | 33 | * or address specific listener. | |
34 | * Spawn an unpriv process to send/receive common network data. | 34 | * Spawn an unpriv process to send/receive common network data. | |
35 | * Then drop all privs and start running. | 35 | * Then drop all privs and start running. | |
36 | * Every process aside from the privileged actioneer is chrooted. | 36 | * Every process aside from the privileged actioneer is chrooted. | |
37 | * All privsep processes ignore signals - only the master process accepts them. | 37 | * All privsep processes ignore signals - only the master process accepts them. | |
38 | * | 38 | * | |
39 | * dhcpcd will maintain the config file in the chroot, no need to handle | 39 | * dhcpcd will maintain the config file in the chroot, no need to handle | |
40 | * this in a script or something. | 40 | * this in a script or something. | |
41 | */ | 41 | */ | |
42 | 42 | |||
43 | #include <sys/resource.h> | 43 | #include <sys/resource.h> | |
44 | #include <sys/socket.h> | 44 | #include <sys/socket.h> | |
45 | #include <sys/stat.h> | 45 | #include <sys/stat.h> | |
46 | #include <sys/types.h> | 46 | #include <sys/types.h> | |
47 | #include <sys/wait.h> | 47 | #include <sys/wait.h> | |
48 | 48 | |||
49 | #ifdef AF_LINK | 49 | #ifdef AF_LINK | |
50 | #include <net/if_dl.h> | 50 | #include <net/if_dl.h> | |
51 | #endif | 51 | #endif | |
52 | 52 | |||
53 | #include <assert.h> | 53 | #include <assert.h> | |
54 | #include <errno.h> | 54 | #include <errno.h> | |
55 | #include <fcntl.h> | 55 | #include <fcntl.h> | |
56 | #include <grp.h> | 56 | #include <grp.h> | |
57 | #include <paths.h> | 57 | #include <paths.h> | |
58 | #include <pwd.h> | 58 | #include <pwd.h> | |
59 | #include <stddef.h> /* For offsetof, struct padding debug */ | 59 | #include <stddef.h> /* For offsetof, struct padding debug */ | |
60 | #include <signal.h> | 60 | #include <signal.h> | |
61 | #include <stdlib.h> | 61 | #include <stdlib.h> | |
62 | #include <string.h> | 62 | #include <string.h> | |
63 | #include <unistd.h> | 63 | #include <unistd.h> | |
64 | 64 | |||
65 | #include "arp.h" | 65 | #include "arp.h" | |
66 | #include "common.h" | 66 | #include "common.h" | |
67 | #include "control.h" | 67 | #include "control.h" | |
68 | #include "dev.h" | 68 | #include "dev.h" | |
69 | #include "dhcp.h" | 69 | #include "dhcp.h" | |
70 | #include "dhcp6.h" | 70 | #include "dhcp6.h" | |
71 | #include "eloop.h" | 71 | #include "eloop.h" | |
72 | #include "ipv6nd.h" | 72 | #include "ipv6nd.h" | |
73 | #include "logerr.h" | 73 | #include "logerr.h" | |
74 | #include "privsep.h" | 74 | #include "privsep.h" | |
75 | 75 | |||
76 | #ifdef HAVE_CAPSICUM | 76 | #ifdef HAVE_CAPSICUM | |
77 | #include <sys/capsicum.h> | 77 | #include <sys/capsicum.h> | |
78 | #include <capsicum_helpers.h> | 78 | #include <capsicum_helpers.h> | |
79 | #endif | 79 | #endif | |
80 | #ifdef HAVE_UTIL_H | 80 | #ifdef HAVE_UTIL_H | |
81 | #include <util.h> | 81 | #include <util.h> | |
82 | #endif | 82 | #endif | |
83 | 83 | |||
84 | int | 84 | int | |
85 | ps_init(struct dhcpcd_ctx *ctx) | 85 | ps_init(struct dhcpcd_ctx *ctx) | |
86 | { | 86 | { | |
87 | struct passwd *pw; | 87 | struct passwd *pw; | |
88 | struct stat st; | 88 | struct stat st; | |
89 | 89 | |||
90 | errno = 0; | 90 | errno = 0; | |
91 | if ((ctx->ps_user = pw = getpwnam(PRIVSEP_USER)) == NULL) { | 91 | if ((ctx->ps_user = pw = getpwnam(PRIVSEP_USER)) == NULL) { | |
92 | ctx->options &= ~DHCPCD_PRIVSEP; | 92 | ctx->options &= ~DHCPCD_PRIVSEP; | |
93 | if (errno == 0) { | 93 | if (errno == 0) { | |
94 | logerrx("no such user %s", PRIVSEP_USER); | 94 | logerrx("no such user %s", PRIVSEP_USER); | |
95 | /* Just incase logerrx caused an error... */ | 95 | /* Just incase logerrx caused an error... */ | |
96 | errno = 0; | 96 | errno = 0; | |
97 | } else | 97 | } else | |
98 | logerr("getpwnam"); | 98 | logerr("getpwnam"); | |
99 | return -1; | 99 | return -1; | |
100 | } | 100 | } | |
101 | 101 | |||
102 | if (stat(pw->pw_dir, &st) == -1 || !S_ISDIR(st.st_mode)) { | 102 | if (stat(pw->pw_dir, &st) == -1 || !S_ISDIR(st.st_mode)) { | |
103 | ctx->options &= ~DHCPCD_PRIVSEP; | 103 | ctx->options &= ~DHCPCD_PRIVSEP; | |
104 | logerrx("refusing chroot: %s: %s", | 104 | logerrx("refusing chroot: %s: %s", | |
105 | PRIVSEP_USER, pw->pw_dir); | 105 | PRIVSEP_USER, pw->pw_dir); | |
106 | errno = 0; | 106 | errno = 0; | |
107 | return -1; | 107 | return -1; | |
108 | } | 108 | } | |
109 | 109 | |||
110 | ctx->options |= DHCPCD_PRIVSEP; | 110 | ctx->options |= DHCPCD_PRIVSEP; | |
111 | return 0; | 111 | return 0; | |
112 | } | 112 | } | |
113 | 113 | |||
114 | static int | 114 | static int | |
115 | ps_dropprivs(struct dhcpcd_ctx *ctx) | 115 | ps_dropprivs(struct dhcpcd_ctx *ctx) | |
116 | { | 116 | { | |
117 | struct passwd *pw = ctx->ps_user; | 117 | struct passwd *pw = ctx->ps_user; | |
118 | 118 | |||
119 | if (ctx->options & DHCPCD_LAUNCHER) | 119 | if (ctx->options & DHCPCD_LAUNCHER) | |
120 | logdebugx("chrooting as %s to %s", pw->pw_name, pw->pw_dir); | 120 | logdebugx("chrooting as %s to %s", pw->pw_name, pw->pw_dir); | |
121 | if (chroot(pw->pw_dir) == -1 && | 121 | if (chroot(pw->pw_dir) == -1 && | |
122 | (errno != EPERM || ctx->options & DHCPCD_FORKED)) | 122 | (errno != EPERM || ctx->options & DHCPCD_FORKED)) | |
123 | logerr("%s: chroot: %s", __func__, pw->pw_dir); | 123 | logerr("%s: chroot: %s", __func__, pw->pw_dir); | |
124 | if (chdir("/") == -1) | 124 | if (chdir("/") == -1) | |
125 | logerr("%s: chdir: /", __func__); | 125 | logerr("%s: chdir: /", __func__); | |
126 | 126 | |||
127 | if ((setgroups(1, &pw->pw_gid) == -1 || | 127 | if ((setgroups(1, &pw->pw_gid) == -1 || | |
128 | setgid(pw->pw_gid) == -1 || | 128 | setgid(pw->pw_gid) == -1 || | |
129 | setuid(pw->pw_uid) == -1) && | 129 | setuid(pw->pw_uid) == -1) && | |
130 | (errno != EPERM || ctx->options & DHCPCD_FORKED)) | 130 | (errno != EPERM || ctx->options & DHCPCD_FORKED)) | |
131 | { | 131 | { | |
132 | logerr("failed to drop privileges"); | 132 | logerr("failed to drop privileges"); | |
133 | return -1; | 133 | return -1; | |
134 | } | 134 | } | |
135 | 135 | |||
136 | struct rlimit rzero = { .rlim_cur = 0, .rlim_max = 0 }; | 136 | struct rlimit rzero = { .rlim_cur = 0, .rlim_max = 0 }; | |
137 | 137 | |||
138 | if (ctx->ps_control_pid != getpid()) { | 138 | if (ctx->ps_control_pid != getpid()) { | |
139 | /* Prohibit new files, sockets, etc */ | 139 | /* Prohibit new files, sockets, etc */ | |
140 | #if defined(__linux__) || defined(__sun) || defined(__OpenBSD__) | 140 | #if defined(__linux__) || defined(__sun) || defined(__OpenBSD__) | |
141 | /* | 141 | /* | |
142 | * If poll(2) is called with nfds > RLIMIT_NOFILE | 142 | * If poll(2) is called with nfds > RLIMIT_NOFILE | |
143 | * then it returns EINVAL. | 143 | * then it returns EINVAL. | |
144 | * This blows. | 144 | * This blows. | |
145 | * Do the best we can and limit to what we need. | 145 | * Do the best we can and limit to what we need. | |
146 | * An attacker could potentially close a file and | 146 | * An attacker could potentially close a file and | |
147 | * open a new one still, but that cannot be helped. | 147 | * open a new one still, but that cannot be helped. | |
148 | */ | 148 | */ | |
149 | unsigned long maxfd; | 149 | unsigned long maxfd; | |
150 | maxfd = (unsigned long)eloop_event_count(ctx->eloop); | 150 | maxfd = (unsigned long)eloop_event_count(ctx->eloop); | |
151 | if (IN_PRIVSEP_SE(ctx)) | 151 | if (IN_PRIVSEP_SE(ctx)) | |
152 | maxfd++; /* XXX why? */ | 152 | maxfd++; /* XXX why? */ | |
153 | 153 | |||
154 | struct rlimit rmaxfd = { | 154 | struct rlimit rmaxfd = { | |
155 | .rlim_cur = maxfd, | 155 | .rlim_cur = maxfd, | |
156 | .rlim_max = maxfd | 156 | .rlim_max = maxfd | |
157 | }; | 157 | }; | |
158 | if (setrlimit(RLIMIT_NOFILE, &rmaxfd) == -1) | 158 | if (setrlimit(RLIMIT_NOFILE, &rmaxfd) == -1) | |
159 | logerr("setrlimit RLIMIT_NOFILE"); | 159 | logerr("setrlimit RLIMIT_NOFILE"); | |
160 | #else | 160 | #else | |
161 | if (setrlimit(RLIMIT_NOFILE, &rzero) == -1) | 161 | if (setrlimit(RLIMIT_NOFILE, &rzero) == -1) | |
162 | logerr("setrlimit RLIMIT_NOFILE"); | 162 | logerr("setrlimit RLIMIT_NOFILE"); | |
163 | #endif | 163 | #endif | |
164 | } | 164 | } | |
165 | 165 | |||
166 | /* Prohibit writing to files. | 166 | /* Prohibit writing to files. | |
167 | * Obviously this won't work if we are using a logfile | 167 | * Obviously this won't work if we are using a logfile | |
168 | * or redirecting stderr to a file. */ | 168 | * or redirecting stderr to a file. */ | |
169 | if (ctx->logfile == NULL && | 169 | if (ctx->logfile == NULL && | |
170 | (ctx->options & DHCPCD_STARTED || | 170 | (ctx->options & DHCPCD_STARTED || | |
171 | !ctx->stderr_valid || isatty(STDERR_FILENO) == 1)) | 171 | !ctx->stderr_valid || isatty(STDERR_FILENO) == 1)) | |
172 | { | 172 | { | |
173 | if (setrlimit(RLIMIT_FSIZE, &rzero) == -1) | 173 | if (setrlimit(RLIMIT_FSIZE, &rzero) == -1) | |
174 | logerr("setrlimit RLIMIT_FSIZE"); | 174 | logerr("setrlimit RLIMIT_FSIZE"); | |
175 | } | 175 | } | |
176 | 176 | |||
177 | #ifdef RLIMIT_NPROC | 177 | #ifdef RLIMIT_NPROC | |
178 | /* Prohibit forks */ | 178 | /* Prohibit forks */ | |
179 | if (setrlimit(RLIMIT_NPROC, &rzero) == -1) | 179 | if (setrlimit(RLIMIT_NPROC, &rzero) == -1) | |
180 | logerr("setrlimit RLIMIT_NPROC"); | 180 | logerr("setrlimit RLIMIT_NPROC"); | |
181 | #endif | 181 | #endif | |
182 | 182 | |||
183 | return 0; | 183 | return 0; | |
184 | } | 184 | } | |
185 | 185 | |||
186 | static int | 186 | static int | |
187 | ps_setbuf0(int fd, int ctl, int minlen) | 187 | ps_setbuf0(int fd, int ctl, int minlen) | |
188 | { | 188 | { | |
189 | int len; | 189 | int len; | |
190 | socklen_t slen; | 190 | socklen_t slen; | |
191 | 191 | |||
192 | slen = sizeof(len); | 192 | slen = sizeof(len); | |
193 | if (getsockopt(fd, SOL_SOCKET, ctl, &len, &slen) == -1) | 193 | if (getsockopt(fd, SOL_SOCKET, ctl, &len, &slen) == -1) | |
194 | return -1; | 194 | return -1; | |
195 | 195 | |||
196 | #ifdef __linux__ | 196 | #ifdef __linux__ | |
197 | len /= 2; | 197 | len /= 2; | |
198 | #endif | 198 | #endif | |
199 | if (len >= minlen) | 199 | if (len >= minlen) | |
200 | return 0; | 200 | return 0; | |
201 | 201 | |||
202 | return setsockopt(fd, SOL_SOCKET, ctl, &minlen, sizeof(minlen)); | 202 | return setsockopt(fd, SOL_SOCKET, ctl, &minlen, sizeof(minlen)); | |
203 | } | 203 | } | |
204 | 204 | |||
205 | static int | 205 | static int | |
206 | ps_setbuf(int fd) | 206 | ps_setbuf(int fd) | |
207 | { | 207 | { | |
208 | /* Ensure we can receive a fully sized privsep message. | 208 | /* Ensure we can receive a fully sized privsep message. | |
209 | * Double the send buffer. */ | 209 | * Double the send buffer. */ | |
210 | int minlen = (int)sizeof(struct ps_msg); | 210 | int minlen = (int)sizeof(struct ps_msg); | |
211 | 211 | |||
212 | if (ps_setbuf0(fd, SO_RCVBUF, minlen) == -1 || | 212 | if (ps_setbuf0(fd, SO_RCVBUF, minlen) == -1 || | |
213 | ps_setbuf0(fd, SO_SNDBUF, minlen * 2) == -1) | 213 | ps_setbuf0(fd, SO_SNDBUF, minlen * 2) == -1) | |
214 | { | 214 | { | |
215 | logerr(__func__); | 215 | logerr(__func__); | |
216 | return -1; | 216 | return -1; | |
217 | } | 217 | } | |
218 | return 0; | 218 | return 0; | |
219 | } | 219 | } | |
220 | 220 | |||
221 | int | 221 | int | |
222 | ps_setbuf_fdpair(int fd[]) | 222 | ps_setbuf_fdpair(int fd[]) | |
223 | { | 223 | { | |
224 | 224 | |||
225 | if (ps_setbuf(fd[0]) == -1 || ps_setbuf(fd[1]) == -1) | 225 | if (ps_setbuf(fd[0]) == -1 || ps_setbuf(fd[1]) == -1) | |
226 | return -1; | 226 | return -1; | |
227 | return 0; | 227 | return 0; | |
228 | } | 228 | } | |
229 | 229 | |||
230 | #ifdef PRIVSEP_RIGHTS | 230 | #ifdef PRIVSEP_RIGHTS | |
231 | int | 231 | int | |
232 | ps_rights_limit_ioctl(int fd) | 232 | ps_rights_limit_ioctl(int fd) | |
233 | { | 233 | { | |
234 | cap_rights_t rights; | 234 | cap_rights_t rights; | |
235 | 235 | |||
236 | cap_rights_init(&rights, CAP_IOCTL); | 236 | cap_rights_init(&rights, CAP_IOCTL); | |
237 | if (cap_rights_limit(fd, &rights) == -1 && errno != ENOSYS) | 237 | if (cap_rights_limit(fd, &rights) == -1 && errno != ENOSYS) | |
238 | return -1; | 238 | return -1; | |
239 | return 0; | 239 | return 0; | |
240 | } | 240 | } | |
241 | 241 | |||
242 | int | 242 | int | |
243 | ps_rights_limit_fd_fctnl(int fd) | 243 | ps_rights_limit_fd_fctnl(int fd) | |
244 | { | 244 | { | |
245 | cap_rights_t rights; | 245 | cap_rights_t rights; | |
246 | 246 | |||
247 | cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_EVENT, | 247 | cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_EVENT, | |
248 | CAP_ACCEPT, CAP_FCNTL); | 248 | CAP_ACCEPT, CAP_FCNTL); | |
249 | if (cap_rights_limit(fd, &rights) == -1 && errno != ENOSYS) | 249 | if (cap_rights_limit(fd, &rights) == -1 && errno != ENOSYS) | |
250 | return -1; | 250 | return -1; | |
251 | return 0; | 251 | return 0; | |
252 | } | 252 | } | |
253 | 253 | |||
254 | int | 254 | int | |
255 | ps_rights_limit_fd(int fd) | 255 | ps_rights_limit_fd(int fd) | |
256 | { | 256 | { | |
257 | cap_rights_t rights; | 257 | cap_rights_t rights; | |
258 | 258 | |||
259 | cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_EVENT, CAP_SHUTDOWN); | 259 | cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_EVENT, CAP_SHUTDOWN); | |
260 | if (cap_rights_limit(fd, &rights) == -1 && errno != ENOSYS) | 260 | if (cap_rights_limit(fd, &rights) == -1 && errno != ENOSYS) | |
261 | return -1; | 261 | return -1; | |
262 | return 0; | 262 | return 0; | |
263 | } | 263 | } | |
264 | 264 | |||
265 | int | 265 | int | |
266 | ps_rights_limit_fd_sockopt(int fd) | 266 | ps_rights_limit_fd_sockopt(int fd) | |
267 | { | 267 | { | |
268 | cap_rights_t rights; | 268 | cap_rights_t rights; | |
269 | 269 | |||
270 | cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_EVENT, | 270 | cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_EVENT, | |
271 | CAP_GETSOCKOPT, CAP_SETSOCKOPT); | 271 | CAP_GETSOCKOPT, CAP_SETSOCKOPT); | |
272 | if (cap_rights_limit(fd, &rights) == -1 && errno != ENOSYS) | 272 | if (cap_rights_limit(fd, &rights) == -1 && errno != ENOSYS) | |
273 | return -1; | 273 | return -1; | |
274 | return 0; | 274 | return 0; | |
275 | } | 275 | } | |
276 | 276 | |||
277 | int | 277 | int | |
278 | ps_rights_limit_fd_rdonly(int fd) | 278 | ps_rights_limit_fd_rdonly(int fd) | |
279 | { | 279 | { | |
280 | cap_rights_t rights; | 280 | cap_rights_t rights; | |
281 | 281 | |||
282 | cap_rights_init(&rights, CAP_READ, CAP_EVENT); | 282 | cap_rights_init(&rights, CAP_READ, CAP_EVENT); | |
283 | if (cap_rights_limit(fd, &rights) == -1 && errno != ENOSYS) | 283 | if (cap_rights_limit(fd, &rights) == -1 && errno != ENOSYS) | |
284 | return -1; | 284 | return -1; | |
285 | return 0; | 285 | return 0; | |
286 | } | 286 | } | |
287 | 287 | |||
288 | int | 288 | int | |
289 | ps_rights_limit_fdpair(int fd[]) | 289 | ps_rights_limit_fdpair(int fd[]) | |
290 | { | 290 | { | |
291 | 291 | |||
292 | if (ps_rights_limit_fd(fd[0]) == -1 || ps_rights_limit_fd(fd[1]) == -1) | 292 | if (ps_rights_limit_fd(fd[0]) == -1 || ps_rights_limit_fd(fd[1]) == -1) | |
293 | return -1; | 293 | return -1; | |
294 | return 0; | 294 | return 0; | |
295 | } | 295 | } | |
296 | 296 | |||
297 | static int | 297 | static int | |
298 | ps_rights_limit_stdio(struct dhcpcd_ctx *ctx) | 298 | ps_rights_limit_stdio(struct dhcpcd_ctx *ctx) | |
299 | { | 299 | { | |
300 | const int iebadf = CAPH_IGNORE_EBADF; | 300 | const int iebadf = CAPH_IGNORE_EBADF; | |
301 | int error = 0; | 301 | int error = 0; | |
302 | 302 | |||
303 | if (ctx->stdin_valid && | 303 | if (ctx->stdin_valid && | |
304 | caph_limit_stream(STDIN_FILENO, CAPH_READ | iebadf) == -1) | 304 | caph_limit_stream(STDIN_FILENO, CAPH_READ | iebadf) == -1) | |
305 | error = -1; | 305 | error = -1; | |
306 | if (ctx->stdout_valid && | 306 | if (ctx->stdout_valid && | |
307 | caph_limit_stream(STDOUT_FILENO, CAPH_WRITE | iebadf) == -1) | 307 | caph_limit_stream(STDOUT_FILENO, CAPH_WRITE | iebadf) == -1) | |
308 | error = -1; | 308 | error = -1; | |
309 | if (ctx->stderr_valid && | 309 | if (ctx->stderr_valid && | |
310 | caph_limit_stream(STDERR_FILENO, CAPH_WRITE | iebadf) == -1) | 310 | caph_limit_stream(STDERR_FILENO, CAPH_WRITE | iebadf) == -1) | |
311 | error = -1; | 311 | error = -1; | |
312 | 312 | |||
313 | return error; | 313 | return error; | |
314 | } | 314 | } | |
315 | #endif | 315 | #endif | |
316 | 316 | |||
317 | pid_t | 317 | pid_t | |
318 | ps_dostart(struct dhcpcd_ctx *ctx, | 318 | ps_dostart(struct dhcpcd_ctx *ctx, | |
319 | pid_t *priv_pid, int *priv_fd, | 319 | pid_t *priv_pid, int *priv_fd, | |
320 | void (*recv_msg)(void *), void (*recv_unpriv_msg), | 320 | void (*recv_msg)(void *), void (*recv_unpriv_msg), | |
321 | void *recv_ctx, int (*callback)(void *), void (*signal_cb)(int, void *), | 321 | void *recv_ctx, int (*callback)(void *), void (*signal_cb)(int, void *), | |
322 | unsigned int flags) | 322 | unsigned int flags) | |
323 | { | 323 | { | |
324 | int fd[2]; | 324 | int fd[2]; | |
325 | pid_t pid; | 325 | pid_t pid; | |
326 | 326 | |||
327 | if (xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, fd) == -1) { | 327 | if (xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, fd) == -1) { | |
328 | logerr("%s: socketpair", __func__); | 328 | logerr("%s: socketpair", __func__); | |
329 | return -1; | 329 | return -1; | |
330 | } | 330 | } | |
331 | if (ps_setbuf_fdpair(fd) == -1) { | 331 | if (ps_setbuf_fdpair(fd) == -1) { | |
332 | logerr("%s: ps_setbuf_fdpair", __func__); | 332 | logerr("%s: ps_setbuf_fdpair", __func__); | |
333 | return -1; | 333 | return -1; | |
334 | } | 334 | } | |
335 | #ifdef PRIVSEP_RIGHTS | 335 | #ifdef PRIVSEP_RIGHTS | |
336 | if (ps_rights_limit_fdpair(fd) == -1) { | 336 | if (ps_rights_limit_fdpair(fd) == -1) { | |
337 | logerr("%s: ps_rights_limit_fdpair", __func__); | 337 | logerr("%s: ps_rights_limit_fdpair", __func__); | |
338 | return -1; | 338 | return -1; | |
339 | } | 339 | } | |
340 | #endif | 340 | #endif | |
341 | 341 | |||
342 | switch (pid = fork()) { | 342 | switch (pid = fork()) { | |
343 | case -1: | 343 | case -1: | |
344 | logerr("fork"); | 344 | logerr("fork"); | |
345 | return -1; | 345 | return -1; | |
346 | case 0: | 346 | case 0: | |
347 | *priv_fd = fd[1]; | 347 | *priv_fd = fd[1]; | |
348 | close(fd[0]); | 348 | close(fd[0]); | |
349 | break; | 349 | break; | |
350 | default: | 350 | default: | |
351 | *priv_pid = pid; | 351 | *priv_pid = pid; | |
352 | *priv_fd = fd[0]; | 352 | *priv_fd = fd[0]; | |
353 | close(fd[1]); | 353 | close(fd[1]); | |
354 | if (recv_unpriv_msg == NULL) | 354 | if (recv_unpriv_msg == NULL) | |
355 | ; | 355 | ; | |
356 | else if (eloop_event_add(ctx->eloop, *priv_fd, | 356 | else if (eloop_event_add(ctx->eloop, *priv_fd, | |
357 | recv_unpriv_msg, recv_ctx) == -1) | 357 | recv_unpriv_msg, recv_ctx) == -1) | |
358 | { | 358 | { | |
359 | logerr("%s: eloop_event_add", __func__); | 359 | logerr("%s: eloop_event_add", __func__); | |
360 | return -1; | 360 | return -1; | |
361 | } | 361 | } | |
362 | return pid; | 362 | return pid; | |
363 | } | 363 | } | |
364 | 364 | |||
365 | ctx->options |= DHCPCD_UNPRIV | DHCPCD_FORKED; | 365 | ctx->options |= DHCPCD_UNPRIV | DHCPCD_FORKED; | |
366 | if (ctx->fork_fd != -1) { | 366 | if (ctx->fork_fd != -1) { | |
367 | close(ctx->fork_fd); | 367 | close(ctx->fork_fd); | |
368 | ctx->fork_fd = -1; | 368 | ctx->fork_fd = -1; | |
369 | } | 369 | } | |
370 | pidfile_clean(); | 370 | pidfile_clean(); | |
371 | eloop_clear(ctx->eloop); | 371 | eloop_clear(ctx->eloop); | |
372 | 372 | |||
373 | /* We are not root */ | 373 | /* We are not root */ | |
374 | if (priv_fd != &ctx->ps_root_fd) { | 374 | if (priv_fd != &ctx->ps_root_fd) { | |
375 | ps_freeprocesses(ctx, recv_ctx); | 375 | ps_freeprocesses(ctx, recv_ctx); | |
376 | if (ctx->ps_root_fd != -1) { | 376 | if (ctx->ps_root_fd != -1) { | |
377 | close(ctx->ps_root_fd); | 377 | close(ctx->ps_root_fd); | |
378 | ctx->ps_root_fd = -1; | 378 | ctx->ps_root_fd = -1; | |
379 | } | 379 | } | |
380 | 380 | |||
381 | #ifdef PRIVSEP_RIGHTS | 381 | #ifdef PRIVSEP_RIGHTS | |
382 | /* We cannot limit the root process in any way. */ | 382 | /* We cannot limit the root process in any way. */ | |
383 | if (ps_rights_limit_stdio(ctx) == -1) { | 383 | if (ps_rights_limit_stdio(ctx) == -1) { | |
384 | logerr("ps_rights_limit_stdio"); | 384 | logerr("ps_rights_limit_stdio"); | |
385 | goto errexit; | 385 | goto errexit; | |
386 | } | 386 | } | |
387 | #endif | 387 | #endif | |
388 | } | 388 | } | |
389 | 389 | |||
390 | if (priv_fd != &ctx->ps_inet_fd && ctx->ps_inet_fd != -1) { | 390 | if (priv_fd != &ctx->ps_inet_fd && ctx->ps_inet_fd != -1) { | |
391 | close(ctx->ps_inet_fd); | 391 | close(ctx->ps_inet_fd); | |
392 | ctx->ps_inet_fd = -1; | 392 | ctx->ps_inet_fd = -1; | |
393 | } | 393 | } | |
394 | 394 | |||
395 | eloop_signal_set_cb(ctx->eloop, | 395 | eloop_signal_set_cb(ctx->eloop, | |
396 | dhcpcd_signals, dhcpcd_signals_len, signal_cb, ctx); | 396 | dhcpcd_signals, dhcpcd_signals_len, signal_cb, ctx); | |
397 | 397 | |||
398 | /* ctx->sigset aready has the initial sigmask set in main() */ | 398 | /* ctx->sigset aready has the initial sigmask set in main() */ | |
399 | if (eloop_signal_mask(ctx->eloop, NULL) == -1) { | 399 | if (eloop_signal_mask(ctx->eloop, NULL) == -1) { | |
400 | logerr("%s: eloop_signal_mask", __func__); | 400 | logerr("%s: eloop_signal_mask", __func__); | |
401 | goto errexit; | 401 | goto errexit; | |
402 | } | 402 | } | |
403 | 403 | |||
404 | if (eloop_event_add(ctx->eloop, *priv_fd, recv_msg, recv_ctx) == -1) | 404 | if (eloop_event_add(ctx->eloop, *priv_fd, recv_msg, recv_ctx) == -1) | |
405 | { | 405 | { | |
406 | logerr("%s: eloop_event_add", __func__); | 406 | logerr("%s: eloop_event_add", __func__); | |
407 | goto errexit; | 407 | goto errexit; | |
408 | } | 408 | } | |
409 | 409 | |||
410 | if (callback(recv_ctx) == -1) | 410 | if (callback(recv_ctx) == -1) | |
411 | goto errexit; | 411 | goto errexit; | |
412 | 412 | |||
413 | if (flags & PSF_DROPPRIVS) | 413 | if (flags & PSF_DROPPRIVS) | |
414 | ps_dropprivs(ctx); | 414 | ps_dropprivs(ctx); | |
415 | 415 | |||
416 | return 0; | 416 | return 0; | |
417 | 417 | |||
418 | errexit: | 418 | errexit: | |
419 | /* Failure to start root or inet processes is fatal. */ | 419 | /* Failure to start root or inet processes is fatal. */ | |
420 | if (priv_fd == &ctx->ps_root_fd || priv_fd == &ctx->ps_inet_fd) | 420 | if (priv_fd == &ctx->ps_root_fd || priv_fd == &ctx->ps_inet_fd) | |
421 | (void)ps_sendcmd(ctx, *priv_fd, PS_STOP, 0, NULL, 0); | 421 | (void)ps_sendcmd(ctx, *priv_fd, PS_STOP, 0, NULL, 0); | |
422 | shutdown(*priv_fd, SHUT_RDWR); | 422 | shutdown(*priv_fd, SHUT_RDWR); | |
423 | *priv_fd = -1; | 423 | *priv_fd = -1; | |
424 | eloop_exit(ctx->eloop, EXIT_FAILURE); | 424 | eloop_exit(ctx->eloop, EXIT_FAILURE); | |
425 | return -1; | 425 | return -1; | |
426 | } | 426 | } | |
427 | 427 | |||
428 | int | 428 | int | |
429 | ps_dostop(struct dhcpcd_ctx *ctx, pid_t *pid, int *fd) | 429 | ps_dostop(struct dhcpcd_ctx *ctx, pid_t *pid, int *fd) | |
430 | { | 430 | { | |
431 | int err = 0; | 431 | int err = 0; | |
432 | 432 | |||
433 | #ifdef PRIVSEP_DEBUG | 433 | #ifdef PRIVSEP_DEBUG | |
434 | logdebugx("%s: pid=%d fd=%d", __func__, *pid, *fd); | 434 | logdebugx("%s: pid=%d fd=%d", __func__, *pid, *fd); | |
435 | #endif | 435 | #endif | |
436 | 436 | |||
437 | if (*fd != -1) { | 437 | if (*fd != -1) { | |
438 | eloop_event_delete(ctx->eloop, *fd); | 438 | eloop_event_delete(ctx->eloop, *fd); | |
439 | if (ps_sendcmd(ctx, *fd, PS_STOP, 0, NULL, 0) == -1) { | 439 | if (ps_sendcmd(ctx, *fd, PS_STOP, 0, NULL, 0) == -1) { | |
440 | logerr(__func__); | 440 | logerr(__func__); | |
441 | err = -1; | 441 | err = -1; | |
442 | } | 442 | } | |
443 | (void)shutdown(*fd, SHUT_RDWR); | 443 | (void)shutdown(*fd, SHUT_RDWR); | |
444 | close(*fd); | 444 | close(*fd); | |
445 | *fd = -1; | 445 | *fd = -1; | |
446 | } | 446 | } | |
447 | 447 | |||
448 | /* Don't wait for the process as it may not respond to the shutdown | 448 | /* Don't wait for the process as it may not respond to the shutdown | |
449 | * request. We'll reap the process on receipt of SIGCHLD. */ | 449 | * request. We'll reap the process on receipt of SIGCHLD. */ | |
450 | *pid = 0; | 450 | *pid = 0; | |
451 | return err; | 451 | return err; | |
452 | } | 452 | } | |
453 | 453 | |||
454 | int | 454 | int | |
455 | ps_start(struct dhcpcd_ctx *ctx) | 455 | ps_start(struct dhcpcd_ctx *ctx) | |
456 | { | 456 | { | |
457 | pid_t pid; | 457 | pid_t pid; | |
458 | 458 | |||
459 | TAILQ_INIT(&ctx->ps_processes); | 459 | TAILQ_INIT(&ctx->ps_processes); | |
460 | 460 | |||
461 | switch (pid = ps_root_start(ctx)) { | 461 | switch (pid = ps_root_start(ctx)) { | |
462 | case -1: | 462 | case -1: | |
463 | logerr("ps_root_start"); | 463 | logerr("ps_root_start"); | |
464 | return -1; | 464 | return -1; | |
465 | case 0: | 465 | case 0: | |
466 | return 0; | 466 | return 0; | |
467 | default: | 467 | default: | |
468 | logdebugx("spawned privileged actioneer on PID %d", pid); | 468 | logdebugx("spawned privileged actioneer on PID %d", pid); | |
469 | } | 469 | } | |
470 | 470 | |||
471 | /* No point in spawning the generic network listener if we're | 471 | /* No point in spawning the generic network listener if we're | |
472 | * not going to use it. */ | 472 | * not going to use it. */ | |
473 | if (!ps_inet_canstart(ctx)) | 473 | if (!ps_inet_canstart(ctx)) | |
474 | goto started_net; | 474 | goto started_net; | |
475 | 475 | |||
476 | switch (pid = ps_inet_start(ctx)) { | 476 | switch (pid = ps_inet_start(ctx)) { | |
477 | case -1: | 477 | case -1: | |
478 | return -1; | 478 | return -1; | |
479 | case 0: | 479 | case 0: | |
480 | return 0; | 480 | return 0; | |
481 | default: | 481 | default: | |
482 | logdebugx("spawned network proxy on PID %d", pid); | 482 | logdebugx("spawned network proxy on PID %d", pid); | |
483 | } | 483 | } | |
484 | 484 | |||
485 | started_net: | 485 | started_net: | |
486 | if (!(ctx->options & DHCPCD_TEST)) { | 486 | if (!(ctx->options & DHCPCD_TEST)) { | |
487 | switch (pid = ps_ctl_start(ctx)) { | 487 | switch (pid = ps_ctl_start(ctx)) { | |
488 | case -1: | 488 | case -1: | |
489 | return -1; | 489 | return -1; | |
490 | case 0: | 490 | case 0: | |
491 | return 0; | 491 | return 0; | |
492 | default: | 492 | default: | |
493 | logdebugx("spawned controller proxy on PID %d", pid); | 493 | logdebugx("spawned controller proxy on PID %d", pid); | |
494 | } | 494 | } | |
495 | } | 495 | } | |
496 | 496 | |||
497 | #ifdef ARC4RANDOM_H | 497 | #ifdef ARC4RANDOM_H | |
498 | /* Seed the random number generator early incase it needs /dev/urandom | 498 | /* Seed the random number generator early incase it needs /dev/urandom | |
499 | * which won't be available in the chroot. */ | 499 | * which won't be available in the chroot. */ | |
500 | arc4random(); | 500 | arc4random(); | |
501 | #endif | 501 | #endif | |
502 | 502 | |||
503 | return 1; | 503 | return 1; | |
504 | } | 504 | } | |
505 | 505 | |||
506 | int | 506 | int | |
507 | ps_entersandbox(const char *_pledge, const char **sandbox) | 507 | ps_entersandbox(const char *_pledge, const char **sandbox) | |
508 | { | 508 | { | |
509 | 509 | |||
510 | #if !defined(HAVE_PLEDGE) | 510 | #if !defined(HAVE_PLEDGE) | |
511 | UNUSED(_pledge); | 511 | UNUSED(_pledge); | |
512 | #endif | 512 | #endif | |
513 | 513 | |||
514 | #if defined(HAVE_CAPSICUM) | 514 | #if defined(HAVE_CAPSICUM) | |
515 | if (sandbox != NULL) | 515 | if (sandbox != NULL) | |
516 | *sandbox = "capsicum"; | 516 | *sandbox = "capsicum"; | |
517 | return cap_enter(); | 517 | return cap_enter(); | |
518 | #elif defined(HAVE_PLEDGE) | 518 | #elif defined(HAVE_PLEDGE) | |
519 | if (sandbox != NULL) | 519 | if (sandbox != NULL) | |
520 | *sandbox = "pledge"; | 520 | *sandbox = "pledge"; | |
521 | return pledge(_pledge, NULL); | 521 | return pledge(_pledge, NULL); | |
522 | #elif defined(HAVE_SECCOMP) | 522 | #elif defined(HAVE_SECCOMP) | |
523 | if (sandbox != NULL) | 523 | if (sandbox != NULL) | |
524 | *sandbox = "seccomp"; | 524 | *sandbox = "seccomp"; | |
525 | return ps_seccomp_enter(); | 525 | return ps_seccomp_enter(); | |
526 | #else | 526 | #else | |
527 | if (sandbox != NULL) | 527 | if (sandbox != NULL) | |
528 | *sandbox = "posix resource limited"; | 528 | *sandbox = "posix resource limited"; | |
529 | return 0; | 529 | return 0; | |
530 | #endif | 530 | #endif | |
531 | } | 531 | } | |
532 | 532 | |||
533 | int | 533 | int | |
534 | ps_mastersandbox(struct dhcpcd_ctx *ctx, const char *_pledge) | 534 | ps_mastersandbox(struct dhcpcd_ctx *ctx, const char *_pledge) | |
535 | { | 535 | { | |
536 | const char *sandbox = NULL; | 536 | const char *sandbox = NULL; | |
537 | bool forked; | 537 | bool forked; | |
538 | int dropped; | 538 | int dropped; | |
539 | 539 | |||
540 | forked = ctx->options & DHCPCD_FORKED; | 540 | forked = ctx->options & DHCPCD_FORKED; | |
541 | ctx->options &= ~DHCPCD_FORKED; | 541 | ctx->options &= ~DHCPCD_FORKED; | |
542 | dropped = ps_dropprivs(ctx); | 542 | dropped = ps_dropprivs(ctx); | |
543 | if (forked) | 543 | if (forked) | |
544 | ctx->options |= DHCPCD_FORKED; | 544 | ctx->options |= DHCPCD_FORKED; | |
545 | ||||
546 | /* | |||
547 | * If we don't have a root process, we cannot use syslog. | |||
548 | * If it cannot be opened before chrooting then syslog(3) will fail. | |||
549 | * openlog(3) does not return an error which doubly sucks. | |||
550 | */ | |||
551 | if (ctx->ps_root_fd == -1) { | |||
552 | unsigned int logopts = loggetopts(); | |||
553 | ||||
554 | logopts &= ~LOGERR_LOG; | |||
555 | logsetopts(logopts); | |||
556 | } | |||
557 | ||||
545 | if (dropped == -1) { | 558 | if (dropped == -1) { | |
546 | logerr("%s: ps_dropprivs", __func__); | 559 | logerr("%s: ps_dropprivs", __func__); | |
547 | return -1; | 560 | return -1; | |
548 | } | 561 | } | |
549 | 562 | |||
550 | #ifdef PRIVSEP_RIGHTS | 563 | #ifdef PRIVSEP_RIGHTS | |
551 | if ((ctx->pf_inet_fd != -1 && | 564 | if ((ctx->pf_inet_fd != -1 && | |
552 | ps_rights_limit_ioctl(ctx->pf_inet_fd) == -1) || | 565 | ps_rights_limit_ioctl(ctx->pf_inet_fd) == -1) || | |
553 | ps_rights_limit_stdio(ctx) == -1) | 566 | ps_rights_limit_stdio(ctx) == -1) | |
554 | { | 567 | { | |
555 | logerr("%s: cap_rights_limit", __func__); | 568 | logerr("%s: cap_rights_limit", __func__); | |
556 | return -1; | 569 | return -1; | |
557 | } | 570 | } | |
558 | #endif | 571 | #endif | |
559 | 572 | |||
560 | if (_pledge == NULL) | 573 | if (_pledge == NULL) | |
561 | _pledge = "stdio"; | 574 | _pledge = "stdio"; | |
562 | if (ps_entersandbox(_pledge, &sandbox) == -1) { | 575 | if (ps_entersandbox(_pledge, &sandbox) == -1) { | |
563 | if (errno == ENOSYS) { | 576 | if (errno == ENOSYS) { | |
564 | if (sandbox != NULL) | 577 | if (sandbox != NULL) | |
565 | logwarnx("sandbox unavailable: %s", sandbox); | 578 | logwarnx("sandbox unavailable: %s", sandbox); | |
566 | return 0; | 579 | return 0; | |
567 | } | 580 | } | |
568 | logerr("%s: %s", __func__, sandbox); | 581 | logerr("%s: %s", __func__, sandbox); | |
569 | return -1; | 582 | return -1; | |
570 | } else if (ctx->options & DHCPCD_LAUNCHER) | 583 | } else if (ctx->options & DHCPCD_LAUNCHER) | |
571 | logdebugx("sandbox: %s", sandbox); | 584 | logdebugx("sandbox: %s", sandbox); | |
572 | return 0; | 585 | return 0; | |
573 | } | 586 | } | |
574 | 587 | |||
575 | int | 588 | int | |
576 | ps_stop(struct dhcpcd_ctx *ctx) | 589 | ps_stop(struct dhcpcd_ctx *ctx) | |
577 | { | 590 | { | |
578 | int r, ret = 0; | 591 | int r, ret = 0; | |
579 | 592 | |||
580 | if (!(ctx->options & DHCPCD_PRIVSEP) || | 593 | if (!(ctx->options & DHCPCD_PRIVSEP) || | |
581 | ctx->options & DHCPCD_FORKED || | 594 | ctx->options & DHCPCD_FORKED || | |
582 | ctx->eloop == NULL) | 595 | ctx->eloop == NULL) | |
583 | return 0; | 596 | return 0; | |
584 | 597 | |||
585 | r = ps_ctl_stop(ctx); | 598 | r = ps_ctl_stop(ctx); | |
586 | if (r != 0) | 599 | if (r != 0) | |
587 | ret = r; | 600 | ret = r; | |
588 | 601 | |||
589 | r = ps_inet_stop(ctx); | 602 | r = ps_inet_stop(ctx); | |
590 | if (r != 0) | 603 | if (r != 0) | |
591 | ret = r; | 604 | ret = r; | |
592 | 605 | |||
593 | /* We've been chrooted, so we need to tell the | 606 | /* We've been chrooted, so we need to tell the | |
594 | * privileged actioneer to remove the pidfile. */ | 607 | * privileged actioneer to remove the pidfile. */ | |
595 | ps_root_unlink(ctx, ctx->pidfile); | 608 | ps_root_unlink(ctx, ctx->pidfile); | |
596 | 609 | |||
597 | r = ps_root_stop(ctx); | 610 | r = ps_root_stop(ctx); | |
598 | if (r != 0) | 611 | if (r != 0) | |
599 | ret = r; | 612 | ret = r; | |
600 | 613 | |||
601 | ctx->options &= ~DHCPCD_PRIVSEP; | 614 | ctx->options &= ~DHCPCD_PRIVSEP; | |
602 | return ret; | 615 | return ret; | |
603 | } | 616 | } | |
604 | 617 | |||
605 | void | 618 | void | |
606 | ps_freeprocess(struct ps_process *psp) | 619 | ps_freeprocess(struct ps_process *psp) | |
607 | { | 620 | { | |
608 | 621 | |||
609 | TAILQ_REMOVE(&psp->psp_ctx->ps_processes, psp, next); | 622 | TAILQ_REMOVE(&psp->psp_ctx->ps_processes, psp, next); | |
610 | if (psp->psp_fd != -1) { | 623 | if (psp->psp_fd != -1) { | |
611 | eloop_event_delete(psp->psp_ctx->eloop, psp->psp_fd); | 624 | eloop_event_delete(psp->psp_ctx->eloop, psp->psp_fd); | |
612 | close(psp->psp_fd); | 625 | close(psp->psp_fd); | |
613 | } | 626 | } | |
614 | if (psp->psp_work_fd != -1) { | 627 | if (psp->psp_work_fd != -1) { | |
615 | eloop_event_delete(psp->psp_ctx->eloop, psp->psp_work_fd); | 628 | eloop_event_delete(psp->psp_ctx->eloop, psp->psp_work_fd); | |
616 | close(psp->psp_work_fd); | 629 | close(psp->psp_work_fd); | |
617 | } | 630 | } | |
618 | #ifdef INET | 631 | #ifdef INET | |
619 | if (psp->psp_bpf != NULL) | 632 | if (psp->psp_bpf != NULL) | |
620 | bpf_close(psp->psp_bpf); | 633 | bpf_close(psp->psp_bpf); | |
621 | #endif | 634 | #endif | |
622 | free(psp); | 635 | free(psp); | |
623 | } | 636 | } | |
624 | 637 | |||
625 | static void | 638 | static void | |
626 | ps_free(struct dhcpcd_ctx *ctx) | 639 | ps_free(struct dhcpcd_ctx *ctx) | |
627 | { | 640 | { | |
628 | struct ps_process *psp; | 641 | struct ps_process *psp; | |
629 | bool stop = ctx->ps_root_pid == getpid(); | 642 | bool stop = ctx->ps_root_pid == getpid(); | |
630 | 643 | |||
631 | while ((psp = TAILQ_FIRST(&ctx->ps_processes)) != NULL) { | 644 | while ((psp = TAILQ_FIRST(&ctx->ps_processes)) != NULL) { | |
632 | if (stop) | 645 | if (stop) | |
633 | ps_dostop(ctx, &psp->psp_pid, &psp->psp_fd); | 646 | ps_dostop(ctx, &psp->psp_pid, &psp->psp_fd); | |
634 | ps_freeprocess(psp); | 647 | ps_freeprocess(psp); | |
635 | } | 648 | } | |
636 | } | 649 | } | |
637 | 650 | |||
638 | int | 651 | int | |
639 | ps_unrollmsg(struct msghdr *msg, struct ps_msghdr *psm, | 652 | ps_unrollmsg(struct msghdr *msg, struct ps_msghdr *psm, | |
640 | const void *data, size_t len) | 653 | const void *data, size_t len) | |
641 | { | 654 | { | |
642 | uint8_t *datap, *namep, *controlp; | 655 | uint8_t *datap, *namep, *controlp; | |
643 | 656 | |||
644 | namep = UNCONST(data); | 657 | namep = UNCONST(data); | |
645 | controlp = namep + psm->ps_namelen; | 658 | controlp = namep + psm->ps_namelen; | |
646 | datap = controlp + psm->ps_controllen; | 659 | datap = controlp + psm->ps_controllen; | |
647 | 660 | |||
648 | if (psm->ps_namelen != 0) { | 661 | if (psm->ps_namelen != 0) { | |
649 | if (psm->ps_namelen > len) { | 662 | if (psm->ps_namelen > len) { | |
650 | errno = EINVAL; | 663 | errno = EINVAL; | |
651 | return -1; | 664 | return -1; | |
652 | } | 665 | } | |
653 | msg->msg_name = namep; | 666 | msg->msg_name = namep; | |
654 | len -= psm->ps_namelen; | 667 | len -= psm->ps_namelen; | |
655 | } else | 668 | } else | |
656 | msg->msg_name = NULL; | 669 | msg->msg_name = NULL; | |
657 | msg->msg_namelen = psm->ps_namelen; | 670 | msg->msg_namelen = psm->ps_namelen; | |
658 | 671 | |||
659 | if (psm->ps_controllen != 0) { | 672 | if (psm->ps_controllen != 0) { | |
660 | if (psm->ps_controllen > len) { | 673 | if (psm->ps_controllen > len) { | |
661 | errno = EINVAL; | 674 | errno = EINVAL; | |
662 | return -1; | 675 | return -1; | |
663 | } | 676 | } | |
664 | msg->msg_control = controlp; | 677 | msg->msg_control = controlp; | |
665 | len -= psm->ps_controllen; | 678 | len -= psm->ps_controllen; | |
666 | } else | 679 | } else | |
667 | msg->msg_control = NULL; | 680 | msg->msg_control = NULL; | |
668 | msg->msg_controllen = psm->ps_controllen; | 681 | msg->msg_controllen = psm->ps_controllen; | |
669 | 682 | |||
670 | if (len != 0) { | 683 | if (len != 0) { | |
671 | msg->msg_iovlen = 1; | 684 | msg->msg_iovlen = 1; | |
672 | msg->msg_iov[0].iov_base = datap; | 685 | msg->msg_iov[0].iov_base = datap; | |
673 | msg->msg_iov[0].iov_len = len; | 686 | msg->msg_iov[0].iov_len = len; | |
674 | } else { | 687 | } else { | |
675 | msg->msg_iovlen = 0; | 688 | msg->msg_iovlen = 0; | |
676 | msg->msg_iov[0].iov_base = NULL; | 689 | msg->msg_iov[0].iov_base = NULL; | |
677 | msg->msg_iov[0].iov_len = 0; | 690 | msg->msg_iov[0].iov_len = 0; | |
678 | } | 691 | } | |
679 | return 0; | 692 | return 0; | |
680 | } | 693 | } | |
681 | 694 | |||
682 | ssize_t | 695 | ssize_t | |
683 | ps_sendpsmmsg(struct dhcpcd_ctx *ctx, int fd, | 696 | ps_sendpsmmsg(struct dhcpcd_ctx *ctx, int fd, | |
684 | struct ps_msghdr *psm, const struct msghdr *msg) | 697 | struct ps_msghdr *psm, const struct msghdr *msg) | |
685 | { | 698 | { | |
686 | struct iovec iov[] = { | 699 | struct iovec iov[] = { | |
687 | { .iov_base = UNCONST(psm), .iov_len = sizeof(*psm) }, | 700 | { .iov_base = UNCONST(psm), .iov_len = sizeof(*psm) }, | |
688 | { .iov_base = NULL, }, /* name */ | 701 | { .iov_base = NULL, }, /* name */ | |
689 | { .iov_base = NULL, }, /* control */ | 702 | { .iov_base = NULL, }, /* control */ | |
690 | { .iov_base = NULL, }, /* payload 1 */ | 703 | { .iov_base = NULL, }, /* payload 1 */ | |
691 | { .iov_base = NULL, }, /* payload 2 */ | 704 | { .iov_base = NULL, }, /* payload 2 */ | |
692 | { .iov_base = NULL, }, /* payload 3 */ | 705 | { .iov_base = NULL, }, /* payload 3 */ | |
693 | }; | 706 | }; | |
694 | int iovlen; | 707 | int iovlen; | |
695 | ssize_t len; | 708 | ssize_t len; | |
696 | 709 | |||
697 | if (msg != NULL) { | 710 | if (msg != NULL) { | |
698 | struct iovec *iovp = &iov[1]; | 711 | struct iovec *iovp = &iov[1]; | |
699 | int i; | 712 | int i; | |
700 | 713 | |||
701 | psm->ps_namelen = msg->msg_namelen; | 714 | psm->ps_namelen = msg->msg_namelen; | |
702 | psm->ps_controllen = (socklen_t)msg->msg_controllen; | 715 | psm->ps_controllen = (socklen_t)msg->msg_controllen; | |
703 | 716 | |||
704 | iovp->iov_base = msg->msg_name; | 717 | iovp->iov_base = msg->msg_name; | |
705 | iovp->iov_len = msg->msg_namelen; | 718 | iovp->iov_len = msg->msg_namelen; | |
706 | iovp++; | 719 | iovp++; | |
707 | iovp->iov_base = msg->msg_control; | 720 | iovp->iov_base = msg->msg_control; | |
708 | iovp->iov_len = msg->msg_controllen; | 721 | iovp->iov_len = msg->msg_controllen; | |
709 | iovlen = 3; | 722 | iovlen = 3; | |
710 | 723 | |||
711 | for (i = 0; i < (int)msg->msg_iovlen; i++) { | 724 | for (i = 0; i < (int)msg->msg_iovlen; i++) { | |
712 | if ((size_t)(iovlen + i) > __arraycount(iov)) { | 725 | if ((size_t)(iovlen + i) > __arraycount(iov)) { | |
713 | errno = ENOBUFS; | 726 | errno = ENOBUFS; | |
714 | return -1; | 727 | return -1; | |
715 | } | 728 | } | |
716 | iovp++; | 729 | iovp++; | |
717 | iovp->iov_base = msg->msg_iov[i].iov_base; | 730 | iovp->iov_base = msg->msg_iov[i].iov_base; | |
718 | iovp->iov_len = msg->msg_iov[i].iov_len; | 731 | iovp->iov_len = msg->msg_iov[i].iov_len; | |
719 | } | 732 | } | |
720 | iovlen += i; | 733 | iovlen += i; | |
721 | } else | 734 | } else | |
722 | iovlen = 1; | 735 | iovlen = 1; | |
723 | 736 | |||
724 | len = writev(fd, iov, iovlen); | 737 | len = writev(fd, iov, iovlen); | |
725 | if (len == -1) { | 738 | if (len == -1) { | |
726 | logerr(__func__); | 739 | logerr(__func__); | |
727 | if (ctx->options & DHCPCD_FORKED && | 740 | if (ctx->options & DHCPCD_FORKED && | |
728 | !(ctx->options & DHCPCD_PRIVSEPROOT)) | 741 | !(ctx->options & DHCPCD_PRIVSEPROOT)) | |
729 | eloop_exit(ctx->eloop, EXIT_FAILURE); | 742 | eloop_exit(ctx->eloop, EXIT_FAILURE); | |
730 | } | 743 | } | |
731 | return len; | 744 | return len; | |
732 | } | 745 | } | |
733 | 746 | |||
734 | ssize_t | 747 | ssize_t | |
735 | ps_sendpsmdata(struct dhcpcd_ctx *ctx, int fd, | 748 | ps_sendpsmdata(struct dhcpcd_ctx *ctx, int fd, | |
736 | struct ps_msghdr *psm, const void *data, size_t len) | 749 | struct ps_msghdr *psm, const void *data, size_t len) | |
737 | { | 750 | { | |
738 | struct iovec iov[] = { | 751 | struct iovec iov[] = { | |
739 | { .iov_base = UNCONST(data), .iov_len = len }, | 752 | { .iov_base = UNCONST(data), .iov_len = len }, | |
740 | }; | 753 | }; | |
741 | struct msghdr msg = { | 754 | struct msghdr msg = { | |
742 | .msg_iov = iov, .msg_iovlen = 1, | 755 | .msg_iov = iov, .msg_iovlen = 1, | |
743 | }; | 756 | }; | |
744 | 757 | |||
745 | return ps_sendpsmmsg(ctx, fd, psm, &msg); | 758 | return ps_sendpsmmsg(ctx, fd, psm, &msg); | |
746 | } | 759 | } | |
747 | 760 | |||
748 | 761 | |||
749 | ssize_t | 762 | ssize_t | |
750 | ps_sendmsg(struct dhcpcd_ctx *ctx, int fd, uint16_t cmd, unsigned long flags, | 763 | ps_sendmsg(struct dhcpcd_ctx *ctx, int fd, uint16_t cmd, unsigned long flags, | |
751 | const struct msghdr *msg) | 764 | const struct msghdr *msg) | |
752 | { | 765 | { | |
753 | struct ps_msghdr psm = { | 766 | struct ps_msghdr psm = { | |
754 | .ps_cmd = cmd, | 767 | .ps_cmd = cmd, | |
755 | .ps_flags = flags, | 768 | .ps_flags = flags, | |
756 | .ps_namelen = msg->msg_namelen, | 769 | .ps_namelen = msg->msg_namelen, | |
757 | .ps_controllen = (socklen_t)msg->msg_controllen, | 770 | .ps_controllen = (socklen_t)msg->msg_controllen, | |
758 | }; | 771 | }; | |
759 | size_t i; | 772 | size_t i; | |
760 | 773 | |||
761 | for (i = 0; i < (size_t)msg->msg_iovlen; i++) | 774 | for (i = 0; i < (size_t)msg->msg_iovlen; i++) | |
762 | psm.ps_datalen += msg->msg_iov[i].iov_len; | 775 | psm.ps_datalen += msg->msg_iov[i].iov_len; | |
763 | 776 | |||
764 | #if 0 /* For debugging structure padding. */ | 777 | #if 0 /* For debugging structure padding. */ | |
765 | logerrx("psa.family %lu %zu", offsetof(struct ps_addr, psa_family), sizeof(psm.ps_id.psi_addr.psa_family)); | 778 | logerrx("psa.family %lu %zu", offsetof(struct ps_addr, psa_family), sizeof(psm.ps_id.psi_addr.psa_family)); | |
766 | logerrx("psa.pad %lu %zu", offsetof(struct ps_addr, psa_pad), sizeof(psm.ps_id.psi_addr.psa_pad)); | 779 | logerrx("psa.pad %lu %zu", offsetof(struct ps_addr, psa_pad), sizeof(psm.ps_id.psi_addr.psa_pad)); | |
767 | logerrx("psa.psa_u %lu %zu", offsetof(struct ps_addr, psa_u), sizeof(psm.ps_id.psi_addr.psa_u)); | 780 | logerrx("psa.psa_u %lu %zu", offsetof(struct ps_addr, psa_u), sizeof(psm.ps_id.psi_addr.psa_u)); | |
768 | logerrx("psa %zu", sizeof(psm.ps_id.psi_addr)); | 781 | logerrx("psa %zu", sizeof(psm.ps_id.psi_addr)); | |
769 | 782 | |||
770 | logerrx("psi.addr %lu %zu", offsetof(struct ps_id, psi_addr), sizeof(psm.ps_id.psi_addr)); | 783 | logerrx("psi.addr %lu %zu", offsetof(struct ps_id, psi_addr), sizeof(psm.ps_id.psi_addr)); | |
771 | logerrx("psi.index %lu %zu", offsetof(struct ps_id, psi_ifindex), sizeof(psm.ps_id.psi_ifindex)); | 784 | logerrx("psi.index %lu %zu", offsetof(struct ps_id, psi_ifindex), sizeof(psm.ps_id.psi_ifindex)); | |
772 | logerrx("psi.cmd %lu %zu", offsetof(struct ps_id, psi_cmd), sizeof(psm.ps_id.psi_cmd)); | 785 | logerrx("psi.cmd %lu %zu", offsetof(struct ps_id, psi_cmd), sizeof(psm.ps_id.psi_cmd)); | |
773 | logerrx("psi.pad %lu %zu", offsetof(struct ps_id, psi_pad), sizeof(psm.ps_id.psi_pad)); | 786 | logerrx("psi.pad %lu %zu", offsetof(struct ps_id, psi_pad), sizeof(psm.ps_id.psi_pad)); | |
774 | logerrx("psi %zu", sizeof(struct ps_id)); | 787 | logerrx("psi %zu", sizeof(struct ps_id)); | |
775 | 788 | |||
776 | logerrx("ps_cmd %lu", offsetof(struct ps_msghdr, ps_cmd)); | 789 | logerrx("ps_cmd %lu", offsetof(struct ps_msghdr, ps_cmd)); | |
777 | logerrx("ps_pad %lu %zu", offsetof(struct ps_msghdr, ps_pad), sizeof(psm.ps_pad)); | 790 | logerrx("ps_pad %lu %zu", offsetof(struct ps_msghdr, ps_pad), sizeof(psm.ps_pad)); | |
778 | logerrx("ps_flags %lu %zu", offsetof(struct ps_msghdr, ps_flags), sizeof(psm.ps_flags)); | 791 | logerrx("ps_flags %lu %zu", offsetof(struct ps_msghdr, ps_flags), sizeof(psm.ps_flags)); | |
779 | 792 | |||
780 | logerrx("ps_id %lu %zu", offsetof(struct ps_msghdr, ps_id), sizeof(psm.ps_id)); | 793 | logerrx("ps_id %lu %zu", offsetof(struct ps_msghdr, ps_id), sizeof(psm.ps_id)); | |
781 | 794 | |||
782 | logerrx("ps_namelen %lu %zu", offsetof(struct ps_msghdr, ps_namelen), sizeof(psm.ps_namelen)); | 795 | logerrx("ps_namelen %lu %zu", offsetof(struct ps_msghdr, ps_namelen), sizeof(psm.ps_namelen)); | |
783 | logerrx("ps_controllen %lu %zu", offsetof(struct ps_msghdr, ps_controllen), sizeof(psm.ps_controllen)); | 796 | logerrx("ps_controllen %lu %zu", offsetof(struct ps_msghdr, ps_controllen), sizeof(psm.ps_controllen)); | |
784 | logerrx("ps_pad2 %lu %zu", offsetof(struct ps_msghdr, ps_pad2), sizeof(psm.ps_pad2)); | 797 | logerrx("ps_pad2 %lu %zu", offsetof(struct ps_msghdr, ps_pad2), sizeof(psm.ps_pad2)); | |
785 | logerrx("ps_datalen %lu %zu", offsetof(struct ps_msghdr, ps_datalen), sizeof(psm.ps_datalen)); | 798 | logerrx("ps_datalen %lu %zu", offsetof(struct ps_msghdr, ps_datalen), sizeof(psm.ps_datalen)); | |
786 | logerrx("psm %zu", sizeof(psm)); | 799 | logerrx("psm %zu", sizeof(psm)); | |
787 | #endif | 800 | #endif | |
788 | 801 | |||
789 | return ps_sendpsmmsg(ctx, fd, &psm, msg); | 802 | return ps_sendpsmmsg(ctx, fd, &psm, msg); | |
790 | } | 803 | } | |
791 | 804 | |||
792 | ssize_t | 805 | ssize_t | |
793 | ps_sendcmd(struct dhcpcd_ctx *ctx, int fd, uint16_t cmd, unsigned long flags, | 806 | ps_sendcmd(struct dhcpcd_ctx *ctx, int fd, uint16_t cmd, unsigned long flags, | |
794 | const void *data, size_t len) | 807 | const void *data, size_t len) | |
795 | { | 808 | { | |
796 | struct ps_msghdr psm = { | 809 | struct ps_msghdr psm = { | |
797 | .ps_cmd = cmd, | 810 | .ps_cmd = cmd, | |
798 | .ps_flags = flags, | 811 | .ps_flags = flags, | |
799 | }; | 812 | }; | |
800 | struct iovec iov[] = { | 813 | struct iovec iov[] = { | |
801 | { .iov_base = UNCONST(data), .iov_len = len } | 814 | { .iov_base = UNCONST(data), .iov_len = len } | |
802 | }; | 815 | }; | |
803 | struct msghdr msg = { | 816 | struct msghdr msg = { | |
804 | .msg_iov = iov, .msg_iovlen = 1, | 817 | .msg_iov = iov, .msg_iovlen = 1, | |
805 | }; | 818 | }; | |
806 | 819 | |||
807 | return ps_sendpsmmsg(ctx, fd, &psm, &msg); | 820 | return ps_sendpsmmsg(ctx, fd, &psm, &msg); | |
808 | } | 821 | } | |
809 | 822 | |||
810 | static ssize_t | 823 | static ssize_t | |
811 | ps_sendcmdmsg(int fd, uint16_t cmd, const struct msghdr *msg) | 824 | ps_sendcmdmsg(int fd, uint16_t cmd, const struct msghdr *msg) | |
812 | { | 825 | { | |
813 | struct ps_msghdr psm = { .ps_cmd = cmd }; | 826 | struct ps_msghdr psm = { .ps_cmd = cmd }; | |
814 | uint8_t data[PS_BUFLEN], *p = data; | 827 | uint8_t data[PS_BUFLEN], *p = data; | |
815 | struct iovec iov[] = { | 828 | struct iovec iov[] = { | |
816 | { .iov_base = &psm, .iov_len = sizeof(psm) }, | 829 | { .iov_base = &psm, .iov_len = sizeof(psm) }, | |
817 | { .iov_base = data, .iov_len = 0 }, | 830 | { .iov_base = data, .iov_len = 0 }, | |
818 | }; | 831 | }; | |
819 | size_t dl = sizeof(data); | 832 | size_t dl = sizeof(data); | |
820 | 833 | |||
821 | if (msg->msg_namelen != 0) { | 834 | if (msg->msg_namelen != 0) { | |
822 | if (msg->msg_namelen > dl) | 835 | if (msg->msg_namelen > dl) | |
823 | goto nobufs; | 836 | goto nobufs; | |
824 | psm.ps_namelen = msg->msg_namelen; | 837 | psm.ps_namelen = msg->msg_namelen; | |
825 | memcpy(p, msg->msg_name, msg->msg_namelen); | 838 | memcpy(p, msg->msg_name, msg->msg_namelen); | |
826 | p += msg->msg_namelen; | 839 | p += msg->msg_namelen; | |
827 | dl -= msg->msg_namelen; | 840 | dl -= msg->msg_namelen; | |
828 | } | 841 | } | |
829 | 842 | |||
830 | if (msg->msg_controllen != 0) { | 843 | if (msg->msg_controllen != 0) { | |
831 | if (msg->msg_controllen > dl) | 844 | if (msg->msg_controllen > dl) | |
832 | goto nobufs; | 845 | goto nobufs; | |
833 | psm.ps_controllen = (socklen_t)msg->msg_controllen; | 846 | psm.ps_controllen = (socklen_t)msg->msg_controllen; | |
834 | memcpy(p, msg->msg_control, msg->msg_controllen); | 847 | memcpy(p, msg->msg_control, msg->msg_controllen); | |
835 | p += msg->msg_controllen; | 848 | p += msg->msg_controllen; | |
836 | dl -= msg->msg_controllen; | 849 | dl -= msg->msg_controllen; | |
837 | } | 850 | } | |
838 | 851 | |||
839 | psm.ps_datalen = msg->msg_iov[0].iov_len; | 852 | psm.ps_datalen = msg->msg_iov[0].iov_len; | |
840 | if (psm.ps_datalen > dl) | 853 | if (psm.ps_datalen > dl) | |
841 | goto nobufs; | 854 | goto nobufs; | |
842 | 855 | |||
843 | iov[1].iov_len = psm.ps_namelen + psm.ps_controllen + psm.ps_datalen; | 856 | iov[1].iov_len = psm.ps_namelen + psm.ps_controllen + psm.ps_datalen; | |
844 | if (psm.ps_datalen != 0) | 857 | if (psm.ps_datalen != 0) | |
845 | memcpy(p, msg->msg_iov[0].iov_base, psm.ps_datalen); | 858 | memcpy(p, msg->msg_iov[0].iov_base, psm.ps_datalen); | |
846 | return writev(fd, iov, __arraycount(iov)); | 859 | return writev(fd, iov, __arraycount(iov)); | |
847 | 860 | |||
848 | nobufs: | 861 | nobufs: | |
849 | errno = ENOBUFS; | 862 | errno = ENOBUFS; | |
850 | return -1; | 863 | return -1; | |
851 | } | 864 | } | |
852 | 865 | |||
853 | ssize_t | 866 | ssize_t | |
854 | ps_recvmsg(struct dhcpcd_ctx *ctx, int rfd, uint16_t cmd, int wfd) | 867 | ps_recvmsg(struct dhcpcd_ctx *ctx, int rfd, uint16_t cmd, int wfd) | |
855 | { | 868 | { | |
856 | struct sockaddr_storage ss = { .ss_family = AF_UNSPEC }; | 869 | struct sockaddr_storage ss = { .ss_family = AF_UNSPEC }; | |
857 | uint8_t controlbuf[sizeof(struct sockaddr_storage)] = { 0 }; | 870 | uint8_t controlbuf[sizeof(struct sockaddr_storage)] = { 0 }; | |
858 | uint8_t databuf[64 * 1024]; | 871 | uint8_t databuf[64 * 1024]; | |
859 | struct iovec iov[] = { | 872 | struct iovec iov[] = { | |
860 | { .iov_base = databuf, .iov_len = sizeof(databuf) } | 873 | { .iov_base = databuf, .iov_len = sizeof(databuf) } | |
861 | }; | 874 | }; | |
862 | struct msghdr msg = { | 875 | struct msghdr msg = { | |
863 | .msg_name = &ss, .msg_namelen = sizeof(ss), | 876 | .msg_name = &ss, .msg_namelen = sizeof(ss), | |
864 | .msg_control = controlbuf, .msg_controllen = sizeof(controlbuf), | 877 | .msg_control = controlbuf, .msg_controllen = sizeof(controlbuf), | |
865 | .msg_iov = iov, .msg_iovlen = 1, | 878 | .msg_iov = iov, .msg_iovlen = 1, | |
866 | }; | 879 | }; | |
867 | 880 | |||
868 | ssize_t len = recvmsg(rfd, &msg, 0); | 881 | ssize_t len = recvmsg(rfd, &msg, 0); | |
869 | 882 | |||
870 | if (len == -1) | 883 | if (len == -1) | |
871 | logerr("%s: recvmsg", __func__); | 884 | logerr("%s: recvmsg", __func__); | |
872 | if (len == -1 || len == 0) { | 885 | if (len == -1 || len == 0) { | |
873 | if (ctx->options & DHCPCD_FORKED && | 886 | if (ctx->options & DHCPCD_FORKED && | |
874 | !(ctx->options & DHCPCD_PRIVSEPROOT)) | 887 | !(ctx->options & DHCPCD_PRIVSEPROOT)) | |
875 | eloop_exit(ctx->eloop, | 888 | eloop_exit(ctx->eloop, | |
876 | len == 0 ? EXIT_SUCCESS : EXIT_FAILURE); | 889 | len == 0 ? EXIT_SUCCESS : EXIT_FAILURE); | |
877 | return len; | 890 | return len; | |
878 | } | 891 | } | |
879 | 892 | |||
880 | iov[0].iov_len = (size_t)len; | 893 | iov[0].iov_len = (size_t)len; | |
881 | len = ps_sendcmdmsg(wfd, cmd, &msg); | 894 | len = ps_sendcmdmsg(wfd, cmd, &msg); | |
882 | if (len == -1) { | 895 | if (len == -1) { | |
883 | logerr("ps_sendcmdmsg"); | 896 | logerr("ps_sendcmdmsg"); | |
884 | if (ctx->options & DHCPCD_FORKED && | 897 | if (ctx->options & DHCPCD_FORKED && | |
885 | !(ctx->options & DHCPCD_PRIVSEPROOT)) | 898 | !(ctx->options & DHCPCD_PRIVSEPROOT)) | |
886 | eloop_exit(ctx->eloop, EXIT_FAILURE); | 899 | eloop_exit(ctx->eloop, EXIT_FAILURE); | |
887 | } | 900 | } | |
888 | return len; | 901 | return len; | |
889 | } | 902 | } | |
890 | 903 | |||
891 | ssize_t | 904 | ssize_t | |
892 | ps_recvpsmsg(struct dhcpcd_ctx *ctx, int fd, | 905 | ps_recvpsmsg(struct dhcpcd_ctx *ctx, int fd, | |
893 | ssize_t (*callback)(void *, struct ps_msghdr *, struct msghdr *), | 906 | ssize_t (*callback)(void *, struct ps_msghdr *, struct msghdr *), | |
894 | void *cbctx) | 907 | void *cbctx) | |
895 | { | 908 | { | |
896 | struct ps_msg psm; | 909 | struct ps_msg psm; | |
897 | ssize_t len; | 910 | ssize_t len; | |
898 | size_t dlen; | 911 | size_t dlen; | |
899 | struct iovec iov[1]; | 912 | struct iovec iov[1]; | |
900 | struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1 }; | 913 | struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1 }; | |
901 | bool stop = false; | 914 | bool stop = false; | |
902 | 915 | |||
903 | len = read(fd, &psm, sizeof(psm)); | 916 | len = read(fd, &psm, sizeof(psm)); | |
904 | #ifdef PRIVSEP_DEBUG | 917 | #ifdef PRIVSEP_DEBUG | |
905 | logdebugx("%s: %zd", __func__, len); | 918 | logdebugx("%s: %zd", __func__, len); | |
906 | #endif | 919 | #endif | |
907 | 920 | |||
908 | if (len == -1 || len == 0) | 921 | if (len == -1 || len == 0) | |
909 | stop = true; | 922 | stop = true; | |
910 | else { | 923 | else { | |
911 | dlen = (size_t)len; | 924 | dlen = (size_t)len; | |
912 | if (dlen < sizeof(psm.psm_hdr)) { | 925 | if (dlen < sizeof(psm.psm_hdr)) { | |
913 | errno = EINVAL; | 926 | errno = EINVAL; | |
914 | return -1; | 927 | return -1; | |
915 | } | 928 | } | |
916 | 929 | |||
917 | if (psm.psm_hdr.ps_cmd == PS_STOP) { | 930 | if (psm.psm_hdr.ps_cmd == PS_STOP) { | |
918 | stop = true; | 931 | stop = true; | |
919 | len = 0; | 932 | len = 0; | |
920 | } | 933 | } | |
921 | } | 934 | } | |
922 | 935 | |||
923 | if (stop) { | 936 | if (stop) { | |
924 | #ifdef PRIVSEP_DEBUG | 937 | #ifdef PRIVSEP_DEBUG | |
925 | logdebugx("process %d stopping", getpid()); | 938 | logdebugx("process %d stopping", getpid()); | |
926 | #endif | 939 | #endif | |
927 | ps_free(ctx); | 940 | ps_free(ctx); | |
928 | #ifdef PLUGIN_DEV | 941 | #ifdef PLUGIN_DEV | |
929 | dev_stop(ctx); | 942 | dev_stop(ctx); | |
930 | #endif | 943 | #endif | |
931 | eloop_exit(ctx->eloop, len != -1 ? EXIT_SUCCESS : EXIT_FAILURE); | 944 | eloop_exit(ctx->eloop, len != -1 ? EXIT_SUCCESS : EXIT_FAILURE); | |
932 | return len; | 945 | return len; | |
933 | } | 946 | } | |
934 | dlen -= sizeof(psm.psm_hdr); | 947 | dlen -= sizeof(psm.psm_hdr); | |
935 | 948 | |||
936 | if (ps_unrollmsg(&msg, &psm.psm_hdr, psm.psm_data, dlen) == -1) | 949 | if (ps_unrollmsg(&msg, &psm.psm_hdr, psm.psm_data, dlen) == -1) | |
937 | return -1; | 950 | return -1; | |
938 | 951 | |||
939 | if (callback == NULL) | 952 | if (callback == NULL) | |
940 | return 0; | 953 | return 0; | |
941 | 954 | |||
942 | errno = 0; | 955 | errno = 0; | |
943 | return callback(cbctx, &psm.psm_hdr, &msg); | 956 | return callback(cbctx, &psm.psm_hdr, &msg); | |
944 | } | 957 | } | |
945 | 958 | |||
946 | struct ps_process * | 959 | struct ps_process * | |
947 | ps_findprocess(struct dhcpcd_ctx *ctx, struct ps_id *psid) | 960 | ps_findprocess(struct dhcpcd_ctx *ctx, struct ps_id *psid) | |
948 | { | 961 | { | |
949 | struct ps_process *psp; | 962 | struct ps_process *psp; | |
950 | 963 | |||
951 | TAILQ_FOREACH(psp, &ctx->ps_processes, next) { | 964 | TAILQ_FOREACH(psp, &ctx->ps_processes, next) { | |
952 | if (memcmp(&psp->psp_id, psid, sizeof(psp->psp_id)) == 0) | 965 | if (memcmp(&psp->psp_id, psid, sizeof(psp->psp_id)) == 0) | |
953 | return psp; | 966 | return psp; | |
954 | } | 967 | } | |
955 | errno = ESRCH; | 968 | errno = ESRCH; | |
956 | return NULL; | 969 | return NULL; | |
957 | } | 970 | } | |
958 | 971 | |||
959 | struct ps_process * | 972 | struct ps_process * | |
960 | ps_newprocess(struct dhcpcd_ctx *ctx, struct ps_id *psid) | 973 | ps_newprocess(struct dhcpcd_ctx *ctx, struct ps_id *psid) | |
961 | { | 974 | { | |
962 | struct ps_process *psp; | 975 | struct ps_process *psp; | |
963 | 976 | |||
964 | psp = calloc(1, sizeof(*psp)); | 977 | psp = calloc(1, sizeof(*psp)); | |
965 | if (psp == NULL) | 978 | if (psp == NULL) | |
966 | return NULL; | 979 | return NULL; | |
967 | psp->psp_ctx = ctx; | 980 | psp->psp_ctx = ctx; | |
968 | memcpy(&psp->psp_id, psid, sizeof(psp->psp_id)); | 981 | memcpy(&psp->psp_id, psid, sizeof(psp->psp_id)); | |
969 | psp->psp_work_fd = -1; | 982 | psp->psp_work_fd = -1; | |
970 | TAILQ_INSERT_TAIL(&ctx->ps_processes, psp, next); | 983 | TAILQ_INSERT_TAIL(&ctx->ps_processes, psp, next); | |
971 | return psp; | 984 | return psp; | |
972 | } | 985 | } | |
973 | 986 | |||
974 | void | 987 | void | |
975 | ps_freeprocesses(struct dhcpcd_ctx *ctx, struct ps_process *notthis) | 988 | ps_freeprocesses(struct dhcpcd_ctx *ctx, struct ps_process *notthis) | |
976 | { | 989 | { | |
977 | struct ps_process *psp, *psn; | 990 | struct ps_process *psp, *psn; | |
978 | 991 | |||
979 | TAILQ_FOREACH_SAFE(psp, &ctx->ps_processes, next, psn) { | 992 | TAILQ_FOREACH_SAFE(psp, &ctx->ps_processes, next, psn) { | |
980 | if (psp == notthis) | 993 | if (psp == notthis) | |
981 | continue; | 994 | continue; | |
982 | ps_freeprocess(psp); | 995 | ps_freeprocess(psp); | |
983 | } | 996 | } | |
984 | } | 997 | } |