ni_bool_t ni_config_parse_addrconf_dhcp4(struct ni_config_dhcp4 *dhcp4, xml_node_t *node) { xml_node_t *child; for (child = node->children; child; child = child->next) { const char *attrval; if (!strcmp(child->name, "vendor-class")) ni_string_dup(&dhcp4->vendor_class, child->cdata); if (!strcmp(child->name, "lease-time") && child->cdata) dhcp4->lease_time = strtoul(child->cdata, NULL, 0); if (!strcmp(child->name, "ignore-server") && (attrval = xml_node_get_attr(child, "ip")) != NULL) ni_string_array_append(&dhcp4->ignore_servers, attrval); if (!strcmp(child->name, "prefer-server") && (attrval = xml_node_get_attr(child, "ip")) != NULL) { ni_server_preference_t *pref; if (dhcp4->num_preferred_servers >= NI_DHCP_SERVER_PREFERENCES_MAX) { ni_warn("config: too many <prefer-server> elements"); continue; } pref = &dhcp4->preferred_server[dhcp4->num_preferred_servers++]; if (ni_sockaddr_parse(&pref->address, attrval, AF_INET) < 0) { ni_error("config: unable to parse <prefer-server ip=\"%s\"", attrval); return FALSE; } pref->weight = 100; if ((attrval = xml_node_get_attr(child, "weight")) != NULL) { if (!strcmp(attrval, "always")) { pref->weight = 100; } else if (!strcmp(attrval, "never")) { pref->weight = -1; } else { pref->weight = strtol(attrval, NULL, 0); if (pref->weight > 100) { pref->weight = 100; ni_warn("preferred dhcp server weight exceeds max, " "clamping to %d", pref->weight); } } } } if (!strcmp(child->name, "allow-update")) ni_config_parse_update_targets(&dhcp4->allow_update, child); } return TRUE; }
static int __ni_dhcp6_lease_ia_addr_from_xml(ni_dhcp6_ia_addr_t *iadr, unsigned int type, const xml_node_t *node) { const xml_node_t *child; const char *name; ni_sockaddr_t addr; unsigned int value; name = (type == NI_DHCP6_OPTION_IA_PD) ? "prefix" : "address"; for (child = node->children; child; child = child->next) { if (ni_string_eq(child->name, name) && child->cdata) { if (type == NI_DHCP6_OPTION_IA_PD) { if (!ni_sockaddr_prefix_parse(child->cdata, &addr, &value) || value == 0 || value > 128 || addr.ss_family != AF_INET6) return -1; iadr->addr = addr.six.sin6_addr; iadr->plen = value; } else { if (ni_sockaddr_parse(&addr, child->cdata, AF_INET6) != 0) return -1; iadr->addr = addr.six.sin6_addr; iadr->plen = 0; } } else if (ni_string_eq(child->name, "preferred-lft") && child->cdata) { if (ni_parse_uint(child->cdata, &value, 10) != 0) return -1; iadr->preferred_lft = value; } else if (ni_string_eq(child->name, "valid-lft") && child->cdata) { if (ni_parse_uint(child->cdata, &value, 10) != 0) return -1; iadr->valid_lft = value; } else if (ni_string_eq(child->name, "status")) { if (__ni_dhcp6_lease_status_from_xml(&iadr->status, child) < 0) return -1; } } ni_sockaddr_set_ipv6(&addr, iadr->addr, 0); if (ni_sockaddr_is_ipv6_specified(&addr)) return 0; else return 1; }
static int __ni_addrconf_lease_route_nh_from_xml(ni_route_t *rp, const xml_node_t *node) { const xml_node_t *child; ni_route_nexthop_t *nh = NULL; ni_sockaddr_t addr; for (child = node->children; child; child = child->next) { if (ni_string_eq(child->name, "gateway") && child->cdata) { if (ni_sockaddr_parse(&addr, child->cdata, AF_UNSPEC) != 0) return -1; if (rp->family != addr.ss_family) return -1; if (nh == NULL) { nh = ni_route_nexthop_new(); ni_route_nexthop_list_append(&rp->nh.next, nh); } nh->gateway = addr; nh = NULL; } } return 0; }
int ni_dhcp6_lease_data_from_xml(ni_addrconf_lease_t *lease, const xml_node_t *node, const char *ifname) { const char *ia_na_name = ni_dhcp6_option_name(NI_DHCP6_OPTION_IA_NA); const char *ia_ta_name = ni_dhcp6_option_name(NI_DHCP6_OPTION_IA_TA); const char *ia_pd_name = ni_dhcp6_option_name(NI_DHCP6_OPTION_IA_PD); unsigned int value; ni_sockaddr_t addr; xml_node_t *child; if (!lease || !node) return -1; lease->dhcp6.rapid_commit = FALSE; for (child = node->children; child; child = child->next) { if (ni_string_eq(child->name, "client-id") && child->cdata) { if (!ni_duid_parse_hex(&lease->dhcp6.client_id, child->cdata)) return -1; } else if (ni_string_eq(child->name, "server-id") && child->cdata) { if (!ni_duid_parse_hex(&lease->dhcp6.server_id, child->cdata)) return -1; } else if (ni_string_eq(child->name, "server-address") && child->cdata) { if (ni_sockaddr_parse(&addr, child->cdata, AF_INET6) < 0) return -1; lease->dhcp6.server_addr = addr.six.sin6_addr; } else if (ni_string_eq(child->name, "server-preference") && child->cdata) { if (ni_parse_uint(child->cdata, &value, 10) != 0 || value > 255) return -1; lease->dhcp6.server_pref = value; } else if (ni_string_eq(child->name, "rapid-commit")) { lease->dhcp6.rapid_commit = TRUE; } else if (ni_string_eq(child->name, "hostname") && child->cdata) { ni_string_dup(&lease->hostname, child->cdata); } if (ni_string_eq(child->name, ia_na_name)) { if (__ni_dhcp6_lease_ia_type_from_xml(&lease->dhcp6.ia_list, NI_DHCP6_OPTION_IA_NA, child) < 0) return -1; } else if (ni_string_eq(child->name, ia_ta_name)) { if (__ni_dhcp6_lease_ia_type_from_xml(&lease->dhcp6.ia_list, NI_DHCP6_OPTION_IA_TA, child) < 0) return -1; } else if (ni_string_eq(child->name, ia_pd_name)) { if (__ni_dhcp6_lease_ia_type_from_xml(&lease->dhcp6.ia_list, NI_DHCP6_OPTION_IA_PD, child) < 0) return -1; } else if (ni_string_eq(child->name, "boot")) { if (__ni_dhcp6_lease_boot_from_xml(lease, child) < 0) return -1; } else if (ni_string_eq(child->name, NI_ADDRCONF_LEASE_XML_DNS_DATA_NODE)) { if (ni_addrconf_lease_dns_data_from_xml(lease, child, ifname) < 0) return -1; } else if (ni_string_eq(child->name, NI_ADDRCONF_LEASE_XML_NTP_DATA_NODE)) { if (ni_addrconf_lease_ntp_data_from_xml(lease, child, ifname) < 0) return -1; } else if (ni_string_eq(child->name, NI_ADDRCONF_LEASE_XML_SIP_DATA_NODE)) { if (ni_addrconf_lease_sip_data_from_xml(lease, child, ifname) < 0) return -1; } else if (ni_string_eq(child->name, NI_ADDRCONF_LEASE_XML_PTZ_DATA_NODE)) { if (ni_addrconf_lease_ptz_data_from_xml(lease, child, ifname) < 0) return -1; } else if (ni_string_eq(child->name, NI_ADDRCONF_LEASE_XML_OPTS_DATA_NODE)) { if (ni_addrconf_lease_opts_data_from_xml(lease, child, ifname) < 0) return -1; } } return 0; }
int ni_do_arp(int argc, char **argv) { static struct option options[] = { { "help", no_argument, NULL, OPT_HELP }, { "quiet", no_argument, NULL, OPT_QUIET }, { "verbose", no_argument, NULL, OPT_VERBOSE }, { "verify", required_argument, NULL, OPT_VERIFY }, { "notify", required_argument, NULL, OPT_NOTIFY }, { "interval", required_argument, NULL, OPT_TIMEOUT }, { NULL, no_argument, NULL, 0 } }; int c, status = NI_WICKED_RC_USAGE; unsigned int opt_verbose = OPT_VERBOSE; unsigned int opt_nprobes; unsigned int opt_nclaims; struct arp_handle handle; memset(&handle, 0, sizeof(handle)); handle.nprobes = opt_nprobes = 3; handle.nclaims = opt_nclaims = 0; handle.timeout = 200; optind = 1; while ((c = getopt_long(argc, argv, "", options, NULL)) != EOF) { switch (c) { case OPT_HELP: status = NI_WICKED_RC_SUCCESS; default: usage: fprintf(stderr, "wicked %s [options ...] <ifname> <IP address>\n" "\n" "Supported options:\n" " --help\n" " Show this help text.\n" " --quiet\n" " Return exit status only\n" " --verbose\n" " Show a result info (default)\n" "\n" " --verify <count>\n" " Verify IP for duplicates on the network (DAD);\n" " Returns 4, when duplicate IP address exists.\n" " --notify <count>\n" " Notify about IP address use (gratuitous ARP)\n" " --interval <msec>\n" " Packet sending interval in msec\n" , argv[0] ); goto cleanup; case OPT_QUIET: case OPT_VERBOSE: opt_verbose = c; break; case OPT_VERIFY: if (ni_parse_uint(optarg, &opt_nprobes, 10)) { ni_error("%s: Cannot parse verify count '%s'", argv[0], optarg); goto cleanup; } handle.nprobes = opt_nprobes; break; case OPT_NOTIFY: if (ni_parse_uint(optarg, &opt_nclaims, 10)) { ni_error("%s: Cannot parse notify count '%s'", argv[0], optarg); goto cleanup; } handle.nclaims = opt_nclaims; break; case OPT_TIMEOUT: if (ni_parse_uint(optarg, &handle.timeout, 10)) { ni_error("%s %s: Cannot parse interval '%s'", argv[0], argv[1], optarg); goto cleanup; } break; } } if (optind + 2 != argc) goto usage; if (!handle.nprobes && !handle.nclaims) { ni_error("%s: nothing to send", argv[0]); goto cleanup; } handle.ifname = argv[optind++]; if (ni_string_empty(handle.ifname)) goto cleanup; if (ni_sockaddr_parse(&handle.ipaddr, argv[optind], AF_INET) != 0) { ni_error("%s: cannot parse '%s' as IPv4 address", argv[0], argv[optind]); goto cleanup; } status = __do_arp_validate(&handle); if (opt_verbose) { if (handle.hwaddr.len) { printf("%s: IP address %s is in use by %s\n", handle.ifname, ni_sockaddr_print(&handle.ipaddr), ni_link_address_print(&handle.hwaddr)); } else { if (opt_nprobes) { printf("%s: No duplicates for IP address %s detected\n", handle.ifname, ni_sockaddr_print(&handle.ipaddr)); } if (opt_nclaims) { printf("%s: Notified neighbours about IP address %s\n", handle.ifname, ni_sockaddr_print(&handle.ipaddr)); } } } cleanup: return status; }
static int __ni_addrconf_lease_addr_from_xml(ni_address_t **ap_list, unsigned int family, const xml_node_t *node) { const xml_node_t *child; ni_sockaddr_t addr; unsigned int plen; ni_address_t *ap; if (!(child = xml_node_get_child(node, "local"))) return 1; if (ni_sockaddr_prefix_parse(child->cdata, &addr, &plen)) return -1; if (family != addr.ss_family || (family == AF_INET && plen > 32) || (family == AF_INET6 && plen > 128)) return -1; if (!(ap = ni_address_new(family, plen, &addr, NULL))) return -1; if ((child = xml_node_get_child(node, "peer"))) { if (ni_sockaddr_parse(&ap->peer_addr, child->cdata, family) != 0) goto failure; } if ((child = xml_node_get_child(node, "anycast"))) { if (ni_sockaddr_parse(&ap->anycast_addr, child->cdata, family) != 0) goto failure; } if ((child = xml_node_get_child(node, "broadcast"))) { if (ni_sockaddr_parse(&ap->bcast_addr, child->cdata, family) != 0) goto failure; } if (family == AF_INET && (child = xml_node_get_child(node, "label"))) { ni_string_dup(&ap->label, child->cdata); } if ((child = xml_node_get_child(node, "cache-info"))) { xml_node_t *cnode; unsigned int lft; if ((cnode = xml_node_get_child(child, "preferred-lifetime"))) { if (ni_parse_uint(child->cdata, &lft, 10) != 0) goto failure; ap->ipv6_cache_info.preferred_lft = lft; } if ((cnode = xml_node_get_child(child, "valid-lifetime"))) { if (ni_parse_uint(child->cdata, &lft, 10) != 0) goto failure; ap->ipv6_cache_info.valid_lft = lft; } } ni_address_list_append(ap_list, ap); return 0; failure: ni_address_free(ap); return -1; }
ni_bool_t ni_config_parse_addrconf_dhcp6(struct ni_config_dhcp6 *dhcp6, xml_node_t *node) { xml_node_t *child; for (child = node->children; child; child = child->next) { const char *attrval; if (!strcmp(child->name, "default-duid") && !ni_string_empty(child->cdata)) { ni_string_dup(&dhcp6->default_duid, child->cdata); } else if (!strcmp(child->name, "user-class")) { ni_string_array_destroy(&dhcp6->user_class_data); if (__ni_config_parse_dhcp6_class_data_nodes(child, &dhcp6->user_class_data) < 0) { ni_string_array_destroy(&dhcp6->user_class_data); return FALSE; } if (dhcp6->user_class_data.count == 0) { ni_warn("config: discarding <user-class> without any <class-data>"); } } else if (!strcmp(child->name, "vendor-class") && (attrval = xml_node_get_attr(child, "enterprise-number")) != NULL) { char * err; long num; num = strtol(attrval, &err, 0); if (*err != '\0' || num < 0 || num >= 0xffffffff) { ni_error("config: unable to parse <vendor-class enterprise-number=\"%s\"", attrval); return FALSE; } ni_string_array_destroy(&dhcp6->vendor_class_data); if (__ni_config_parse_dhcp6_class_data_nodes(child, &dhcp6->vendor_class_data) < 0) { ni_string_array_destroy(&dhcp6->vendor_class_data); return FALSE; } if (dhcp6->vendor_class_data.count == 0) { ni_warn("config: discarding <vendor-class> without any <class-data>"); } else { dhcp6->vendor_class_en = num; } } else if (!strcmp(child->name, "vendor-opts") && (attrval = xml_node_get_attr(child, "enterprise-number")) != NULL) { char * err; long num; num = strtol(attrval, &err, 0); if (*err != '\0' || num < 0 || num >= 0xffffffff) { ni_error("config: unable to parse <vendor-class enterprise-number=\"%s\"", attrval); return FALSE; } ni_var_array_destroy(&dhcp6->vendor_opts_data); if (__ni_config_parse_dhcp6_vendor_opts_nodes(child, &dhcp6->vendor_opts_data) < 0) { ni_var_array_destroy(&dhcp6->vendor_opts_data); } if (dhcp6->vendor_opts_data.count == 0) { ni_warn("config: discarding <vendor-opts> without any <option>"); } else { dhcp6->vendor_opts_en = num; } } else if (!strcmp(child->name, "lease-time") && child->cdata) { dhcp6->lease_time = strtoul(child->cdata, NULL, 0); } else if (!strcmp(child->name, "ignore-server") && (attrval = xml_node_get_attr(child, "ip")) != NULL) { ni_string_array_append(&dhcp6->ignore_servers, attrval); } else if (!strcmp(child->name, "prefer-server")) { ni_server_preference_t *pref; const char *id, *ip; ip = xml_node_get_attr(child, "ip"); id = xml_node_get_attr(child, "id"); if (ip == NULL && id == NULL) continue; if (dhcp6->num_preferred_servers >= NI_DHCP_SERVER_PREFERENCES_MAX) { ni_warn("config: too many <prefer-server> elements"); continue; } pref = &dhcp6->preferred_server[dhcp6->num_preferred_servers++]; if (ip && ni_sockaddr_parse(&pref->address, ip, AF_INET6) < 0) { ni_error("config: unable to parse <prefer-server ip=\"%s\"", ip); return FALSE; } if (id) { int len; /* DUID is "opaque", but has 2 bytes type + up to 128 bytes */ if ((len = sizeof(pref->serverid.data)) > 130) len = 130; /* DUID-LL has 2+2 fixed bytes + variable length hwaddress * and seems to be the shortest one I'm aware of ... */ if ((len = ni_parse_hex(id, pref->serverid.data, len)) <= 4) { ni_error("config: unable to parse <prefer-server id=\"%s\"", id); return FALSE; } pref->serverid.len = (size_t)len; } pref->weight = 255; if ((attrval = xml_node_get_attr(child, "weight")) != NULL) { if (!strcmp(attrval, "always")) { pref->weight = 255; } else if (!strcmp(attrval, "never")) { pref->weight = -1; } else { pref->weight = strtol(attrval, NULL, 0); if (pref->weight > 255) { pref->weight = 255; ni_warn("preferred dhcp server weight exceeds max, " "clamping to %d", pref->weight); } } } } else if (!strcmp(child->name, "allow-update")) { ni_config_parse_update_targets(&dhcp6->allow_update, child); } } return TRUE; }