4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
25 * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
26 */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <stropts.h>
35 #include <sys/sockio.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <sys/socket.h>
39 #include <net/route.h>
40 #include <netinet/in.h>
41 #include <inet/ip.h>
42 #include <arpa/inet.h>
43 #include <libintl.h>
44 #include <libdlpi.h>
511
512 if (iph->iph_dlh == NULL) {
513 assert(iph->iph_zoneid != GLOBAL_ZONEID);
514 return (B_FALSE);
515 }
516 dlstatus = dladm_name2info(iph->iph_dlh, ifname, &linkid, NULL,
517 &class, NULL);
518 if (dlstatus == DLADM_STATUS_OK && class == DATALINK_CLASS_IPTUN) {
519 params.iptun_param_linkid = linkid;
520 dlstatus = dladm_iptun_getparams(iph->iph_dlh, ¶ms,
521 DLADM_OPT_ACTIVE);
522 if (dlstatus == DLADM_STATUS_OK &&
523 params.iptun_param_type == IPTUN_TYPE_6TO4) {
524 return (B_TRUE);
525 }
526 }
527 return (B_FALSE);
528 }
529
530 /*
531 * Returns B_TRUE if `ifname' represents an IPMP underlying interface.
532 */
533 boolean_t
534 i_ipadm_is_under_ipmp(ipadm_handle_t iph, const char *ifname)
535 {
536 struct lifreq lifr;
537
538 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
539 if (ioctl(iph->iph_sock, SIOCGLIFGROUPNAME, (caddr_t)&lifr) < 0) {
540 if (ioctl(iph->iph_sock6, SIOCGLIFGROUPNAME,
541 (caddr_t)&lifr) < 0) {
542 return (B_FALSE);
543 }
544 }
545 return (lifr.lifr_groupname[0] != '\0');
546 }
547
548 /*
549 * Returns B_TRUE if `ifname' represents an IPMP meta-interface.
550 */
551 boolean_t
552 i_ipadm_is_ipmp(ipadm_handle_t iph, const char *ifname)
553 {
554 uint64_t flags;
555
556 if (i_ipadm_get_flags(iph, ifname, AF_INET, &flags) != IPADM_SUCCESS &&
557 i_ipadm_get_flags(iph, ifname, AF_INET6, &flags) != IPADM_SUCCESS)
558 return (B_FALSE);
559
560 return ((flags & IFF_IPMP) != 0);
561 }
562
563 /*
564 * For a given interface name, ipadm_if_enabled() checks if v4
565 * or v6 or both IP interfaces exist in the active configuration.
566 */
567 boolean_t
568 ipadm_if_enabled(ipadm_handle_t iph, const char *ifname, sa_family_t af)
569 {
570 struct lifreq lifr;
571 int s4 = iph->iph_sock;
572 int s6 = iph->iph_sock6;
573
574 bzero(&lifr, sizeof (lifr));
575 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
576 switch (af) {
577 case AF_INET:
578 if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0)
579 return (B_TRUE);
580 break;
581 case AF_INET6:
582 if (ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0)
583 return (B_TRUE);
676 case IPADM_ADDR_NONE:
677 status = ipadm_set_addrprop(iph, name, pval, aobjname,
678 IPADM_OPT_ACTIVE);
679 break;
680 }
681
682 return (status);
683 }
684
685 /*
686 * Instantiate the interface object by retrieving the configuration from
687 * `ifnvl'. The nvlist `ifnvl' contains all the persistent configuration
688 * (interface properties and address objects on that interface) for the
689 * given `ifname'.
690 */
691 ipadm_status_t
692 i_ipadm_init_ifobj(ipadm_handle_t iph, const char *ifname, nvlist_t *ifnvl)
693 {
694 nvlist_t *nvl = NULL;
695 nvpair_t *nvp;
696 char *afstr;
697 ipadm_status_t status;
698 ipadm_status_t ret_status = IPADM_SUCCESS;
699 char newifname[LIFNAMSIZ];
700 char *aobjstr;
701 sa_family_t af = AF_UNSPEC;
702 boolean_t is_ngz = (iph->iph_zoneid != GLOBAL_ZONEID);
703
704 (void) strlcpy(newifname, ifname, sizeof (newifname));
705 /*
706 * First plumb the given interface and then apply all the persistent
707 * interface properties and then instantiate any persistent addresses
708 * objects on that interface.
709 */
710 for (nvp = nvlist_next_nvpair(ifnvl, NULL); nvp != NULL;
711 nvp = nvlist_next_nvpair(ifnvl, nvp)) {
712 if (nvpair_value_nvlist(nvp, &nvl) != 0)
713 continue;
714
715 if (nvlist_lookup_string(nvl, IPADM_NVP_FAMILY, &afstr) == 0) {
716 status = i_ipadm_plumb_if(iph, newifname, atoi(afstr),
717 IPADM_OPT_ACTIVE);
718 /*
719 * If the interface is already plumbed, we should
720 * ignore this error because there might be address
721 * address objects on that interface that needs to
722 * be enabled again.
723 */
724 if (status == IPADM_IF_EXISTS)
725 status = IPADM_SUCCESS;
726
727 if (is_ngz)
728 af = atoi(afstr);
729 } else if (nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME,
730 &aobjstr) == 0) {
731 /*
732 * For addresses, we need to relocate addrprops from the
733 * nvlist `ifnvl'.
734 */
735 if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
736 nvlist_exists(nvl, IPADM_NVP_IPV6ADDR) ||
737 nvlist_exists(nvl, IPADM_NVP_DHCP)) {
738 status = i_ipadm_merge_addrprops_from_nvl(ifnvl,
739 nvl, aobjstr);
740 if (status != IPADM_SUCCESS)
741 continue;
742 }
743 status = i_ipadm_init_addrobj(iph, nvl);
744 /*
745 * If this address is in use on some other interface,
746 * we want to record an error to be returned as
747 * a soft error and continue processing the rest of
748 * the addresses.
749 */
750 if (status == IPADM_ADDR_NOTAVAIL) {
751 ret_status = IPADM_ALL_ADDRS_NOT_ENABLED;
752 status = IPADM_SUCCESS;
753 }
754 } else {
755 assert(nvlist_exists(nvl, IPADM_NVP_PROTONAME));
756 status = i_ipadm_init_ifprop(iph, nvl);
757 }
758 if (status != IPADM_SUCCESS)
759 return (status);
760 }
761
762 if (is_ngz && af != AF_UNSPEC)
763 ret_status = ipadm_init_net_from_gz(iph, newifname, NULL);
764 return (ret_status);
765 }
766
767 /*
768 * Retrieves the persistent configuration for the given interface(s) in `ifs'
769 * by contacting the daemon and dumps the information in `allifs'.
770 */
771 ipadm_status_t
772 i_ipadm_init_ifs(ipadm_handle_t iph, const char *ifs, nvlist_t **allifs)
773 {
774 nvlist_t *nvl = NULL;
775 size_t nvlsize, bufsize;
776 ipmgmt_initif_arg_t *iargp;
777 char *buf = NULL, *nvlbuf = NULL;
778 ipmgmt_get_rval_t *rvalp = NULL;
779 int err;
780 ipadm_status_t status = IPADM_SUCCESS;
781
782 if ((err = ipadm_str2nvlist(ifs, &nvl, IPADM_NORVAL)) != 0)
942 if (err == 0) {
943 void *newp;
944
945 /* allocated memory will be freed by the caller */
946 if ((newp = realloc(*rbufp, darg.rsize)) == NULL) {
947 err = ENOMEM;
948 } else {
949 *rbufp = newp;
950 (void) memcpy(*rbufp, darg.rbuf, darg.rsize);
951 }
952 }
953 /* munmap() the door buffer */
954 (void) munmap(darg.rbuf, darg.rsize);
955 } else {
956 if (darg.rsize != rsize)
957 err = EBADE;
958 }
959 return (err);
960 }
961
962 /*
963 * ipadm_is_nil_hostname() : Determine if the `hostname' is nil: i.e.,
964 * NULL, empty, or a single space (e.g., as returned by
965 * domainname(1M)/sysinfo).
966 *
967 * input: const char *: the hostname to inspect;
968 * output: boolean_t: B_TRUE if `hostname' is not NULL satisfies the
969 * criteria above; otherwise, B_FALSE;
970 */
971
972 boolean_t
973 ipadm_is_nil_hostname(const char *hostname)
974 {
975 return (hostname == NULL || *hostname == '\0' ||
976 (*hostname == ' ' && hostname[1] == '\0'));
977 }
978
979 /*
980 * ipadm_is_valid_hostname(): check whether a string is a valid hostname
981 *
|
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2016 Nexenta Systems, Inc.
25 * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
26 */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <stropts.h>
35 #include <sys/sockio.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <sys/socket.h>
39 #include <net/route.h>
40 #include <netinet/in.h>
41 #include <inet/ip.h>
42 #include <arpa/inet.h>
43 #include <libintl.h>
44 #include <libdlpi.h>
511
512 if (iph->iph_dlh == NULL) {
513 assert(iph->iph_zoneid != GLOBAL_ZONEID);
514 return (B_FALSE);
515 }
516 dlstatus = dladm_name2info(iph->iph_dlh, ifname, &linkid, NULL,
517 &class, NULL);
518 if (dlstatus == DLADM_STATUS_OK && class == DATALINK_CLASS_IPTUN) {
519 params.iptun_param_linkid = linkid;
520 dlstatus = dladm_iptun_getparams(iph->iph_dlh, ¶ms,
521 DLADM_OPT_ACTIVE);
522 if (dlstatus == DLADM_STATUS_OK &&
523 params.iptun_param_type == IPTUN_TYPE_6TO4) {
524 return (B_TRUE);
525 }
526 }
527 return (B_FALSE);
528 }
529
530 /*
531 * For a given interface name, ipadm_if_enabled() checks if v4
532 * or v6 or both IP interfaces exist in the active configuration.
533 */
534 boolean_t
535 ipadm_if_enabled(ipadm_handle_t iph, const char *ifname, sa_family_t af)
536 {
537 struct lifreq lifr;
538 int s4 = iph->iph_sock;
539 int s6 = iph->iph_sock6;
540
541 bzero(&lifr, sizeof (lifr));
542 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
543 switch (af) {
544 case AF_INET:
545 if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0)
546 return (B_TRUE);
547 break;
548 case AF_INET6:
549 if (ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0)
550 return (B_TRUE);
643 case IPADM_ADDR_NONE:
644 status = ipadm_set_addrprop(iph, name, pval, aobjname,
645 IPADM_OPT_ACTIVE);
646 break;
647 }
648
649 return (status);
650 }
651
652 /*
653 * Instantiate the interface object by retrieving the configuration from
654 * `ifnvl'. The nvlist `ifnvl' contains all the persistent configuration
655 * (interface properties and address objects on that interface) for the
656 * given `ifname'.
657 */
658 ipadm_status_t
659 i_ipadm_init_ifobj(ipadm_handle_t iph, const char *ifname, nvlist_t *ifnvl)
660 {
661 nvlist_t *nvl = NULL;
662 nvpair_t *nvp;
663 ipadm_status_t status = IPADM_ENXIO;
664 ipadm_status_t ret_status = IPADM_SUCCESS;
665 char newifname[LIFNAMSIZ];
666 char *aobjstr;
667 uint16_t *afs;
668 char *gifname;
669 uint_t nelem = 0;
670 boolean_t init_from_gz = B_FALSE;
671 boolean_t move_to_group = B_FALSE;
672
673 (void) strlcpy(newifname, ifname, sizeof (newifname));
674
675 /*
676 * First go through the ifnvl nvlist looking for nested nvlist
677 * containing interface class and address families.
678 */
679 for (nvp = nvlist_next_nvpair(ifnvl, NULL); nvp != NULL;
680 nvp = nvlist_next_nvpair(ifnvl, nvp)) {
681 char *icstr;
682 char **mifnames;
683 uint32_t ipadm_flags = IPADM_OPT_ACTIVE;
684
685 if (nvpair_value_nvlist(nvp, &nvl) != 0 ||
686 nvlist_lookup_uint16_array(nvl, IPADM_NVP_FAMILIES,
687 &afs, &nelem) != 0)
688 continue;
689
690 /* Check if this is IPMP group interface */
691 if (nvlist_lookup_string(nvl, IPADM_NVP_IFCLASS,
692 &icstr) == 0 && atoi(icstr) == IPADM_IF_CLASS_IPMP)
693 ipadm_flags |= IPADM_OPT_IPMP;
694
695 /* Create interfaces for address families specified */
696 while (nelem-- > 0) {
697 uint16_t af = afs[nelem];
698
699 assert(af == AF_INET || af == AF_INET6);
700
701 status = i_ipadm_plumb_if(iph, newifname, af,
702 ipadm_flags);
703 if (status == IPADM_IF_EXISTS)
704 status = IPADM_SUCCESS;
705 if (status != IPADM_SUCCESS)
706 return (status);
707 }
708 if (nvlist_lookup_string(nvl, IPADM_NVP_GIFNAME,
709 &gifname) == 0) {
710 /*
711 * IPMP underlying interface. Move to the
712 * specified IPMP group.
713 */
714 move_to_group = B_TRUE;
715 } else if ((ipadm_flags & IPADM_OPT_IPMP) &&
716 nvlist_lookup_string_array(nvl, IPADM_NVP_MIFNAMES,
717 &mifnames, &nelem) == 0) {
718 /* Non-empty IPMP group interface */
719 while (nelem-- > 0) {
720 (void) ipadm_add_ipmp_member(iph, newifname,
721 mifnames[nelem], IPADM_OPT_ACTIVE);
722 }
723 }
724 if (iph->iph_zoneid != GLOBAL_ZONEID)
725 init_from_gz = B_TRUE;
726 }
727
728 if (status != IPADM_SUCCESS)
729 return (status);
730
731 /*
732 * Go through the ifnvl nvlist again, applying persistent configuration.
733 */
734 for (nvp = nvlist_next_nvpair(ifnvl, NULL); nvp != NULL;
735 nvp = nvlist_next_nvpair(ifnvl, nvp)) {
736 if (nvpair_value_nvlist(nvp, &nvl) != 0)
737 continue;
738 if (nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME,
739 &aobjstr) == 0) {
740 /*
741 * For addresses, we need to relocate addrprops from the
742 * nvlist `ifnvl'.
743 */
744 if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
745 nvlist_exists(nvl, IPADM_NVP_IPV6ADDR) ||
746 nvlist_exists(nvl, IPADM_NVP_DHCP)) {
747 status = i_ipadm_merge_addrprops_from_nvl(ifnvl,
748 nvl, aobjstr);
749
750 if (status != IPADM_SUCCESS)
751 continue;
752 }
753 status = i_ipadm_init_addrobj(iph, nvl);
754
755 /*
756 * If this address is in use on some other interface,
757 * we want to record an error to be returned as
758 * a soft error and continue processing the rest of
759 * the addresses.
760 */
761 if (status == IPADM_ADDR_NOTAVAIL) {
762 ret_status = IPADM_ALL_ADDRS_NOT_ENABLED;
763 status = IPADM_SUCCESS;
764 }
765 } else if (nvlist_exists(nvl, IPADM_NVP_PROTONAME) == B_TRUE) {
766 status = i_ipadm_init_ifprop(iph, nvl);
767 }
768 if (status != IPADM_SUCCESS)
769 return (status);
770 }
771 if (move_to_group) {
772 (void) ipadm_add_ipmp_member(iph, gifname, newifname,
773 IPADM_OPT_ACTIVE);
774 }
775 if (init_from_gz)
776 ret_status = ipadm_init_net_from_gz(iph, newifname, NULL);
777 return (ret_status);
778 }
779
780 /*
781 * Retrieves the persistent configuration for the given interface(s) in `ifs'
782 * by contacting the daemon and dumps the information in `allifs'.
783 */
784 ipadm_status_t
785 i_ipadm_init_ifs(ipadm_handle_t iph, const char *ifs, nvlist_t **allifs)
786 {
787 nvlist_t *nvl = NULL;
788 size_t nvlsize, bufsize;
789 ipmgmt_initif_arg_t *iargp;
790 char *buf = NULL, *nvlbuf = NULL;
791 ipmgmt_get_rval_t *rvalp = NULL;
792 int err;
793 ipadm_status_t status = IPADM_SUCCESS;
794
795 if ((err = ipadm_str2nvlist(ifs, &nvl, IPADM_NORVAL)) != 0)
955 if (err == 0) {
956 void *newp;
957
958 /* allocated memory will be freed by the caller */
959 if ((newp = realloc(*rbufp, darg.rsize)) == NULL) {
960 err = ENOMEM;
961 } else {
962 *rbufp = newp;
963 (void) memcpy(*rbufp, darg.rbuf, darg.rsize);
964 }
965 }
966 /* munmap() the door buffer */
967 (void) munmap(darg.rbuf, darg.rsize);
968 } else {
969 if (darg.rsize != rsize)
970 err = EBADE;
971 }
972 return (err);
973 }
974
975 /*
976 * A helper that is used by i_ipadm_get_db_addr and i_ipadm_get_db_if
977 * to do a door_call to ipmgmtd, that should return persistent information
978 * about interfaces or/and addresses from ipadm DB
979 */
980 ipadm_status_t
981 i_ipadm_call_ipmgmtd(ipadm_handle_t iph, void *garg, size_t garg_size,
982 nvlist_t **onvl)
983 {
984 ipmgmt_get_rval_t *rvalp;
985 int err;
986 size_t nvlsize;
987 char *nvlbuf;
988
989 rvalp = malloc(sizeof (ipmgmt_get_rval_t));
990 err = ipadm_door_call(iph, garg, garg_size, (void **)&rvalp,
991 sizeof (*rvalp), B_TRUE);
992 if (err == 0) {
993 nvlsize = rvalp->ir_nvlsize;
994 nvlbuf = (char *)rvalp + sizeof (ipmgmt_get_rval_t);
995 err = nvlist_unpack(nvlbuf, nvlsize, onvl, NV_ENCODE_NATIVE);
996 }
997 free(rvalp);
998
999 return (ipadm_errno2status(err));
1000 }
1001
1002 /*
1003 * ipadm_is_nil_hostname() : Determine if the `hostname' is nil: i.e.,
1004 * NULL, empty, or a single space (e.g., as returned by
1005 * domainname(1M)/sysinfo).
1006 *
1007 * input: const char *: the hostname to inspect;
1008 * output: boolean_t: B_TRUE if `hostname' is not NULL satisfies the
1009 * criteria above; otherwise, B_FALSE;
1010 */
1011
1012 boolean_t
1013 ipadm_is_nil_hostname(const char *hostname)
1014 {
1015 return (hostname == NULL || *hostname == '\0' ||
1016 (*hostname == ' ' && hostname[1] == '\0'));
1017 }
1018
1019 /*
1020 * ipadm_is_valid_hostname(): check whether a string is a valid hostname
1021 *
|