static dbus_bool_t ni_objectmodel_ppp_config_get_ipv6(const ni_dbus_object_t *object, const ni_dbus_property_t *property, ni_dbus_variant_t *result, DBusError *error) { const ni_ppp_config_t *conf; ni_dbus_variant_t *ipcp; if (!(conf = ni_objectmodel_get_ppp_config(object, FALSE, error))) return FALSE; ni_dbus_dict_add_bool(result, "enabled", conf->ipv6.enabled); if (!conf->ipv6.enabled) return TRUE; if (ni_sockaddr_is_specified(&conf->ipv6.local_ip)) { if (!__ni_objectmodel_dict_add_sockaddr(result, "local-ip", &conf->ipv6.local_ip)) return FALSE; } if (ni_sockaddr_is_specified(&conf->ipv6.remote_ip)) { if (!__ni_objectmodel_dict_add_sockaddr(result, "remote-ip", &conf->ipv6.remote_ip)) return FALSE; } if (!(ipcp = ni_dbus_dict_add(result, "ipcp"))) return FALSE; ni_dbus_variant_init_dict(ipcp); ni_dbus_dict_add_bool(ipcp, "accept-local", conf->ipv6.ipcp.accept_local); return TRUE; }
int ni_addrconf_lease_routes_data_to_xml(const ni_addrconf_lease_t *lease, xml_node_t *node) { ni_route_table_t *tab; ni_route_nexthop_t *nh; xml_node_t *route, *hop; ni_route_t *rp; unsigned int count = 0; unsigned int i; /* A very limitted view */ for (tab = lease->routes; tab; tab = tab->next) { if (tab->tid != 254) /* RT_TABLE_MAIN for now */ continue; for (i = 0; i < tab->routes.count; ++i) { if (!(rp = tab->routes.data[i])) continue; route = xml_node_new("route", NULL); if (ni_sockaddr_is_specified(&rp->destination)) { xml_node_new_element("destination", route, ni_sockaddr_prefix_print(&rp->destination, rp->prefixlen)); } for (nh = &rp->nh; nh; nh = nh->next) { if (!ni_sockaddr_is_specified(&nh->gateway)) continue; hop = xml_node_new("nexthop", route); xml_node_new_element("gateway", hop, ni_sockaddr_print(&nh->gateway)); } if (route->children) { xml_node_add_child(node, route); count++; } else { xml_node_free(route); } } } return count ? 0 : 1; }
static dbus_bool_t ni_objectmodel_ppp_config_get_dns(const ni_dbus_object_t *object, const ni_dbus_property_t *property, ni_dbus_variant_t *result, DBusError *error) { const ni_ppp_config_t *conf; if (!(conf = ni_objectmodel_get_ppp_config(object, FALSE, error))) return FALSE; ni_dbus_dict_add_bool(result, "usepeerdns", conf->dns.usepeerdns); if (ni_sockaddr_is_specified(&conf->dns.dns1)) { if (!__ni_objectmodel_dict_add_sockaddr(result, "dns1", &conf->dns.dns1)) return FALSE; } if (ni_sockaddr_is_specified(&conf->dns.dns2)) { if (!__ni_objectmodel_dict_add_sockaddr(result, "dns2", &conf->dns.dns2)) return FALSE; } return TRUE; }
int ni_addrconf_lease_addrs_data_to_xml(const ni_addrconf_lease_t *lease, xml_node_t *node) { unsigned int count = 0; xml_node_t *anode; ni_address_t *ap; for (ap = lease->addrs; ap; ap = ap->next) { if (lease->family != ap->local_addr.ss_family || !ni_sockaddr_is_specified(&ap->local_addr)) continue; count++; anode = xml_node_new("address", node); xml_node_new_element("local", anode, ni_sockaddr_prefix_print (&ap->local_addr, ap->prefixlen)); if (ap->peer_addr.ss_family == ap->family) { xml_node_new_element("peer", anode, ni_sockaddr_print (&ap->peer_addr)); } if (ap->anycast_addr.ss_family == ap->family) { xml_node_new_element("anycast", anode, ni_sockaddr_print (&ap->anycast_addr)); } if (ap->bcast_addr.ss_family == ap->family) { xml_node_new_element("broadcast", anode, ni_sockaddr_print (&ap->bcast_addr)); } if (ap->family == AF_INET && ap->label) xml_node_new_element("label", anode, ap->label); if (ap->ipv6_cache_info.preferred_lft || ap->ipv6_cache_info.valid_lft) { xml_node_t *cnode = xml_node_new("cache-info", anode); xml_node_new_element_uint("preferred-lifetime", cnode, ap->ipv6_cache_info.preferred_lft); xml_node_new_element_uint("valid-lifetime", cnode, ap->ipv6_cache_info.valid_lft); } } return count ? 0 : 1; }
/* * Given a route, look up the lease owning it */ ni_addrconf_lease_t * __ni_netdev_route_to_lease(ni_netdev_t *dev, const ni_route_t *rp, unsigned int minprio) { ni_addrconf_lease_t *lease; ni_addrconf_lease_t *found = NULL; ni_address_t *ap; unsigned int prio; if (!dev || !rp) return NULL; for (lease = dev->leases; lease; lease = lease->next) { if (rp->family != lease->family) continue; if ((prio = ni_addrconf_lease_get_priority(lease)) < minprio) continue; /* First, check if this is an interface route */ for (ap = lease->addrs; ap; ap = ap->next) { if (ni_sockaddr_is_specified(&rp->nh.gateway)) continue; if (rp->prefixlen != ap->prefixlen) continue; if (!ni_sockaddr_prefix_match(ap->prefixlen, &rp->destination, &ap->local_addr)) continue; if (!found || prio > ni_addrconf_lease_get_priority(found)) found = lease; } if (__ni_lease_owns_route(lease, rp)) { if (!found || prio > ni_addrconf_lease_get_priority(found)) found = lease; } } return found; }
/* * Callback from addrconf supplicant whenever it acquired, released or lost a lease. * * FIXME SECURITY: * Is it good enough to check for the sender interface to avoid that someone is sending * us spoofed lease messages?! */ void ni_objectmodel_addrconf_signal_handler(ni_dbus_connection_t *conn, ni_dbus_message_t *msg, void *user_data) { ni_dbus_addrconf_forwarder_t *forwarder = user_data; const char *signal_name = dbus_message_get_member(msg); ni_netdev_t *ifp; ni_addrconf_lease_t *lease = NULL; ni_dbus_variant_t argv[16]; ni_uuid_t uuid = NI_UUID_INIT; ni_event_t ifevent; int argc, optind = 0; memset(argv, 0, sizeof(argv)); argc = ni_dbus_message_get_args_variants(msg, argv, 16); if (argc < 0) { ni_error("%s: cannot parse arguments for signal %s", __func__, signal_name); goto done; } ifp = ni_objectmodel_addrconf_path_to_device(dbus_message_get_path(msg)); if (ifp == NULL) { ni_debug_dbus("%s: received signal %s for unknown interface %s", __func__, signal_name, dbus_message_get_path(msg)); goto done; } lease = ni_addrconf_lease_new(forwarder->addrconf, forwarder->addrfamily); if (argc != 1 && argc != 2) { ni_warn("%s: ignoring %s event from %s: bad number of arguments (%u)", __func__, signal_name, dbus_message_get_path(msg), argc); goto done; } if (argc == 2 && !ni_dbus_variant_get_uuid(&argv[optind++], &uuid)) { ni_debug_dbus("%s: unable to parse uuid argument", __func__); goto done; } if (!ni_objectmodel_set_addrconf_lease(lease, &argv[optind++])) { ni_error("%s: unable to parse lease argument received from %s", __func__, dbus_message_get_sender(msg)); goto done; } ni_debug_dbus("received signal %s for interface %s (ifindex %d), lease %s:%s, uuid=%s, update=0x%x, flags=0x%x", signal_name, ifp->name, ifp->link.ifindex, ni_addrfamily_type_to_name(lease->family), ni_addrconf_type_to_name(lease->type), ni_uuid_print(&uuid), lease->update, lease->flags); if (!strcmp(signal_name, NI_OBJECTMODEL_LEASE_ACQUIRED_SIGNAL)) { if (lease->state != NI_ADDRCONF_STATE_GRANTED) { ni_error("%s: unexpected lease state in signal %s", __func__, signal_name); goto done; } ifevent = NI_EVENT_ADDRESS_ACQUIRED; if (!__ni_addrconf_should_update(lease->update, NI_ADDRCONF_UPDATE_DEFAULT_ROUTE)) { ni_route_table_t *tab; ni_route_t *rp; unsigned int i; for (tab = lease->routes; tab; tab = tab->next) { for (i = 0; i < tab->routes.count; ++i) { if (!(rp = tab->routes.data[i])) continue; if (ni_sockaddr_is_specified(&rp->destination)) continue; if (ni_route_array_delete(&tab->routes, i)) i--; } } } } else if (!strcmp(signal_name, NI_OBJECTMODEL_LEASE_RELEASED_SIGNAL)) { lease->state = NI_ADDRCONF_STATE_RELEASED; ifevent = NI_EVENT_ADDRESS_RELEASED; } else if (!strcmp(signal_name, NI_OBJECTMODEL_LEASE_LOST_SIGNAL)) { lease->state = NI_ADDRCONF_STATE_FAILED; ifevent = NI_EVENT_ADDRESS_LOST; } else { /* Ignore unknown signal */ goto done; } /* * The following call updates the system with the information given in * the lease. This includes setting all addresses, as well as updating * resolver and hostname, if provided. * When a lease is dropped, we either fall back to the config information * from the next best lease, or if there is none, we restore the original * system settings. * * Note, lease may be NULL after this, as the interface object * takes ownership of it. */ __ni_system_interface_update_lease(ifp, &lease); /* Potentially, there's a client somewhere waiting for that event. * We use the UUID that's passed back and forth to make sure we * really match the event we were expecting to match. */ { ni_dbus_object_t *object; object = ni_objectmodel_get_netif_object(__ni_objectmodel_server, ifp); if (object) ni_objectmodel_send_netif_event(__ni_objectmodel_server, object, ifevent, ni_uuid_is_null(&uuid)? NULL : &uuid); } done: while (argc--) ni_dbus_variant_destroy(&argv[argc]); if (lease) ni_addrconf_lease_free(lease); }
/* * Install information from a lease, and remember that we did */ static ni_bool_t ni_system_updater_install(ni_updater_t *updater, const ni_addrconf_lease_t *lease, const char *ifname) { ni_string_array_t arguments = NI_STRING_ARRAY_INIT; const char *statedir = NULL; char *file = NULL; ni_bool_t result = FALSE; int rv = 0; ni_debug_ifconfig("Updating system %s settings from %s/%s lease", ni_updater_name(updater->kind), ni_addrconf_type_to_name(lease->type), ni_addrfamily_type_to_name(lease->family)); if (!updater->proc_install) return TRUE; if (!ifname || (!updater->have_backup && !ni_system_updater_backup(updater, ifname))) return FALSE; ni_string_array_append(&arguments, "-i"); ni_string_array_append(&arguments, ifname); ni_string_array_append(&arguments, "-t"); ni_string_array_append(&arguments, ni_addrconf_type_to_name(lease->type)); ni_string_array_append(&arguments, "-f"); ni_string_array_append(&arguments, ni_addrfamily_type_to_name(lease->family)); switch (updater->kind) { case NI_ADDRCONF_UPDATER_GENERIC: switch (updater->format) { case NI_ADDRCONF_UPDATER_FORMAT_INFO: ni_leaseinfo_dump(NULL, lease, ifname, NULL); if (!(file = ni_leaseinfo_path(ifname, lease->type, lease->family))) { ni_error("Unable to determine leaseinfo file path."); goto done; } ni_string_array_append(&arguments, file); break; default: ni_error("Unsupported %s updater data format.", ni_updater_name(updater->kind)); goto done; } ni_string_array_append(&arguments, ni_updater_format_name(updater->format)); break; case NI_ADDRCONF_UPDATER_RESOLVER: statedir = ni_extension_statedir(ni_updater_name(updater->kind)); if (!statedir) { ni_error("failed to get %s statedir", ni_updater_name(updater->kind)); goto done; } ni_string_printf(&file, "%s/resolv.conf.%s.%s.%s", statedir, ifname, ni_addrconf_type_to_name(lease->type), ni_addrfamily_type_to_name(lease->family)); ni_string_array_append(&arguments, file); if ((rv = ni_resolver_write_resolv_conf(file, lease->resolver, NULL)) < 0) { ni_error("failed to write resolver info to file: %s", ni_strerror(rv)); goto done; } break; case NI_ADDRCONF_UPDATER_HOSTNAME: if (!ni_string_empty(lease->hostname)) { ni_string_array_append(&arguments, lease->hostname); } else { const ni_address_t *ap; char *name = NULL; unsigned int count; /* bnc#861476 workaround */ if (!can_try_reverse_lookup(lease)) goto done; for (count = 0, ap = lease->addrs; ap; ap = ap->next) { if (!ni_sockaddr_is_specified(&ap->local_addr)) continue; if (!ni_resolve_reverse_timed(&ap->local_addr, &name, NI_UPDATER_REVERSE_TIMEOUT)) break; ni_info("Unable to resolve %s to hostname", ni_sockaddr_print(&ap->local_addr)); if (++count >= NI_UPDATER_REVERSE_MAX_CNT) break; } if (ni_string_empty(name)) { ni_note("Skipping hostname update, none available"); goto done; } ni_string_array_append(&arguments, name); ni_string_free(&name); } break; default: ni_error("cannot install new %s settings - file format not understood", ni_updater_name(updater->kind)); goto done; } if (!ni_system_updater_run(updater->proc_install, &arguments)) { ni_error("failed to install %s settings", ni_updater_name(updater->kind)); goto done; } result = TRUE; switch (updater->kind) { case NI_ADDRCONF_UPDATER_RESOLVER: if (ni_global.other_event) ni_global.other_event(NI_EVENT_RESOLVER_UPDATED); break; case NI_ADDRCONF_UPDATER_HOSTNAME: if (ni_global.other_event) ni_global.other_event(NI_EVENT_HOSTNAME_UPDATED); break; case NI_ADDRCONF_UPDATER_GENERIC: if (ni_global.other_event) ni_global.other_event(NI_EVENT_GENERIC_UPDATED); break; default: break; } done: if (file) free(file); ni_string_array_destroy(&arguments); return result; }
void __ni_compat_generate_static_route(xml_node_t *aconf, const ni_route_t *rp, const char *ifname) { xml_node_t *rnode, *mnode, *knode; char *tmp = NULL; const char *ptr; rnode = xml_node_new("route", aconf); if (rp->destination.ss_family != AF_UNSPEC && rp->prefixlen != 0) { xml_node_new_element("destination", rnode, ni_sockaddr_prefix_print(&rp->destination, rp->prefixlen)); } __ni_compat_generate_static_route_hops(rnode, &rp->nh, ifname); knode = NULL; if (rp->table != RT_TABLE_UNSPEC && rp->table != RT_TABLE_MAIN) { if (!(ptr = ni_route_table_type_to_name(rp->table))) ptr = ni_sprint_uint(rp->table); if (knode == NULL) knode = xml_node_new("kern", rnode); xml_node_new_element("table", knode, ptr); } if (rp->type != RTN_UNSPEC && rp->type != RTN_UNICAST) { if (!(ptr = ni_route_type_type_to_name(rp->type))) ptr = ni_sprint_uint(rp->type); if (knode == NULL) knode = xml_node_new("kern", rnode); xml_node_new_element("type", knode, ptr); } if (rp->scope != RT_SCOPE_UNIVERSE) { if (!(ptr = ni_route_scope_type_to_name(rp->scope))) ptr = ni_sprint_uint(rp->scope); if (knode == NULL) knode = xml_node_new("kern", rnode); xml_node_new_element("scope", knode, ptr); } if (rp->protocol != RTPROT_UNSPEC && rp->protocol != RTPROT_BOOT) { if (!(ptr = ni_route_protocol_type_to_name(rp->protocol))) ptr = ni_sprint_uint(rp->protocol); if (knode == NULL) knode = xml_node_new("kern", rnode); xml_node_new_element("protocol", knode, ptr); } if (rp->priority > 0) { xml_node_new_element("priority", rnode, ni_sprint_uint(rp->priority)); } if (ni_sockaddr_is_specified(&rp->pref_src)) { xml_node_new_element("source", rnode, ni_sockaddr_print(&rp->pref_src)); } if (rp->realm > 0) { /* Hmm */ xml_node_new_element("realm", rnode, ni_sprint_uint(rp->realm)); } if (rp->mark > 0 && ni_string_printf(&tmp, "0x%02x", rp->mark)) { xml_node_new_element("mark", rnode, tmp); ni_string_free(&tmp); } if (rp->flags > 0) { ni_string_array_t names = NI_STRING_ARRAY_INIT; xml_node_t *fnode = NULL; unsigned int i; ni_route_flags_get_names(rp->flags, &names); for (i = 0; i < names.count; ++i) { if (fnode == NULL) fnode = xml_node_new("flags", rnode); xml_node_new(names.data[i], fnode); } } if (rp->tos > 0 && ni_string_printf(&tmp, "0x%02x", rp->tos)) { xml_node_new_element("tos", rnode, tmp); ni_string_free(&tmp); } mnode = xml_node_new("metrics", NULL); __ni_compat_generate_static_route_metrics(mnode, rp); if (mnode->children || mnode->attrs.count || mnode->cdata) xml_node_add_child(rnode, mnode); else xml_node_free(mnode); }