Exemplo n.º 1
0
static void ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
        _cleanup_route_free_ Route *route = NULL;
        struct in6_addr gateway;
        uint16_t lifetime;
        unsigned preference;
        usec_t time_now;
        int r;

        assert(link);
        assert(rt);

        r = sd_ndisc_router_get_lifetime(rt, &lifetime);
        if (r < 0) {
                log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
                return;
        }
        if (lifetime == 0) /* not a default router */
                return;

        r = sd_ndisc_router_get_address(rt, &gateway);
        if (r < 0) {
                log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
                return;
        }

        r = sd_ndisc_router_get_preference(rt, &preference);
        if (r < 0) {
                log_link_warning_errno(link, r, "Failed to get default router preference from RA: %m");
                return;
        }

        r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
        if (r < 0) {
                log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
                return;
        }

        r = route_new(&route);
        if (r < 0) {
                log_link_error_errno(link, r, "Could not allocate route: %m");
                return;
        }

        route->family = AF_INET6;
        route->table = RT_TABLE_MAIN;
        route->protocol = RTPROT_RA;
        route->pref = preference;
        route->gw.in6 = gateway;
        route->lifetime = time_now + lifetime * USEC_PER_SEC;

        r = route_configure(route, link, ndisc_netlink_handler);
        if (r < 0) {
                log_link_warning_errno(link, r, "Could not set default route: %m");
                link_enter_failed(link);
                return;
        }

        link->ndisc_messages++;
}
Exemplo n.º 2
0
static void ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
        _cleanup_route_free_ Route *route = NULL;
        usec_t time_now;
        uint32_t lifetime;
        unsigned prefixlen;
        int r;

        assert(link);
        assert(rt);

        r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
        if (r < 0) {
                log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
                return;
        }

        r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
        if (r < 0) {
                log_link_error_errno(link, r, "Failed to get prefix length: %m");
                return;
        }

        r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime);
        if (r < 0) {
                log_link_error_errno(link, r, "Failed to get prefix lifetime: %m");
                return;
        }

        r = route_new(&route);
        if (r < 0) {
                log_link_error_errno(link, r, "Could not allocate route: %m");
                return;
        }

        route->family = AF_INET6;
        route->table = RT_TABLE_MAIN;
        route->protocol = RTPROT_RA;
        route->flags = RTM_F_PREFIX;
        route->dst_prefixlen = prefixlen;
        route->lifetime = time_now + lifetime * USEC_PER_SEC;

        r = sd_ndisc_router_prefix_get_address(rt, &route->dst.in6);
        if (r < 0) {
                log_link_error_errno(link, r, "Failed to get prefix address: %m");
                return;
        }

        r = route_configure(route, link, ndisc_netlink_handler);
        if (r < 0) {
                log_link_warning_errno(link, r, "Could not set prefix route: %m");
                link_enter_failed(link);
                return;
        }

        link->ndisc_messages++;
}
int link_routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
        _cleanup_link_unref_ Link *link = userdata;
        int r;

        assert(rtnl);
        assert(m);
        assert(link);
        assert(link->ifname);
        assert(link->routing_policy_rule_messages > 0);

        link->routing_policy_rule_messages--;

        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                return 1;

        r = sd_netlink_message_get_errno(m);
        if (r < 0 && r != -EEXIST)
                log_link_warning_errno(link, r, "Could not add routing policy rule: %m");

        if (link->routing_policy_rule_messages == 0) {
                log_link_debug(link, "Routing policy rule configured");
                link->routing_policy_rules_configured = true;
                link_check_ready(link);
        }

        return 1;
}
Exemplo n.º 4
0
static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) {
        int r;
        sd_dhcp6_lease *lease;
        struct in6_addr ip6_addr;
        uint32_t lifetime_preferred, lifetime_valid;
        uint8_t prefixlen;

        r = sd_dhcp6_client_get_lease(client, &lease);
        if (r < 0)
                return r;

        sd_dhcp6_lease_reset_address_iter(lease);

        while (sd_dhcp6_lease_get_address(lease, &ip6_addr,
                                                &lifetime_preferred,
                                                &lifetime_valid) >= 0) {

                r = sd_icmp6_ra_get_prefixlen(link->icmp6_router_discovery,
                                        &ip6_addr, &prefixlen);
                if (r < 0 && r != -EADDRNOTAVAIL) {
                        log_link_warning_errno(link, r, "Could not get prefix information: %m");
                        return r;
                }

                if (r == -EADDRNOTAVAIL)
                        prefixlen = 128;

                r = dhcp6_address_change(link, &ip6_addr, prefixlen,
                                        lifetime_preferred, lifetime_valid);
                if (r < 0)
                        return r;
        }

        return 0;
}
Exemplo n.º 5
0
static void ndisc_router_handler(sd_ndisc *nd, int event, void *userdata) {
        Link *link = userdata;

        assert(link);
        assert(link->network);
        assert(link->manager);

        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                return;

        switch(event) {
        case SD_NDISC_EVENT_ROUTER_ADVERTISMENT_NONE:
                return;

        case SD_NDISC_EVENT_ROUTER_ADVERTISMENT_OTHER:
                dhcp6_configure(link, true);

                break;
        case SD_NDISC_EVENT_ROUTER_ADVERTISMENT_TIMEOUT:
        case SD_NDISC_EVENT_ROUTER_ADVERTISMENT_MANAGED:
                dhcp6_configure(link, false);

                break;

        default:
                if (event < 0)
                        log_link_warning_errno(link, event, "IPv6 Neighbor Discover error: %m");
                else
                        log_link_warning(link, "IPv6 Neighbor Discovery unknown event: %d", event);

                break;
        }
}
Exemplo n.º 6
0
static int dhcp6_address_change(Link *link, struct in6_addr *ip6_addr,
                                uint8_t prefixlen, uint32_t lifetime_preferred,
                                uint32_t lifetime_valid) {
        int r;
        _cleanup_address_free_ Address *addr = NULL;

        r = address_new(&addr);
        if (r < 0)
                return r;

        addr->family = AF_INET6;
        memcpy(&addr->in_addr.in6, ip6_addr, sizeof(*ip6_addr));

        addr->flags = IFA_F_NOPREFIXROUTE;
        addr->prefixlen = prefixlen;

        addr->cinfo.ifa_prefered = lifetime_preferred;
        addr->cinfo.ifa_valid = lifetime_valid;

        log_link_info(link,
                      "DHCPv6 address "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d timeout preferred %d valid %d",
                      SD_ICMP6_ND_ADDRESS_FORMAT_VAL(addr->in_addr.in6),
                      addr->prefixlen, lifetime_preferred, lifetime_valid);

        r = address_configure(addr, link, dhcp6_address_handler, true);
        if (r < 0)
                log_link_warning_errno(link, r, "Could not assign DHCPv6 address: %m");

        return r;
}
int address_establish(Address *address, Link *link) {
        bool masq;
        int r;

        assert(address);
        assert(link);

        masq = link->network &&
                link->network->ip_masquerade &&
                address->family == AF_INET &&
                address->scope < RT_SCOPE_LINK;

        /* Add firewall entry if this is requested */
        if (address->ip_masquerade_done != masq) {
                union in_addr_union masked = address->in_addr;
                in_addr_mask(address->family, &masked, address->prefixlen);

                r = fw_add_masquerade(masq, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
                if (r < 0)
                        log_link_warning_errno(link, r, "Could not enable IP masquerading: %m");

                address->ip_masquerade_done = masq;
        }

        return 0;
}
Exemplo n.º 8
0
static int dhcp4_set_hostname(Link *link) {
        _cleanup_free_ char *hostname = NULL;
        const char *hn;
        int r;

        assert(link);

        if (!link->network->dhcp_send_hostname)
                hn = NULL;
        else if (link->network->dhcp_hostname)
                hn = link->network->dhcp_hostname;
        else {
                r = gethostname_strict(&hostname);
                if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */
                        return r;

                hn = hostname;
        }

        r = sd_dhcp_client_set_hostname(link->dhcp_client, hn);
        if (r == -EINVAL && hostname)
                /* Ignore error when the machine's hostname is not suitable to send in DHCP packet. */
                log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
        else if (r < 0)
                return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set hostname: %m");

        return 0;
}
Exemplo n.º 9
0
static int dhcp6_address_change(
                Link *link,
                struct in6_addr *ip6_addr,
                uint32_t lifetime_preferred,
                uint32_t lifetime_valid) {

        _cleanup_address_free_ Address *addr = NULL;
        char buffer[INET6_ADDRSTRLEN];
        int r;

        r = address_new(&addr);
        if (r < 0)
                return r;

        addr->family = AF_INET6;
        memcpy(&addr->in_addr.in6, ip6_addr, sizeof(*ip6_addr));

        addr->flags = IFA_F_NOPREFIXROUTE;
        addr->prefixlen = 128;

        addr->cinfo.ifa_prefered = lifetime_preferred;
        addr->cinfo.ifa_valid = lifetime_valid;

        log_link_info(link,
                      "DHCPv6 address %s/%d timeout preferred %d valid %d",
                      inet_ntop(AF_INET6, &addr->in_addr.in6, buffer, sizeof(buffer)),
                      addr->prefixlen, lifetime_preferred, lifetime_valid);

        r = address_configure(addr, link, dhcp6_address_handler, true);
        if (r < 0)
                log_link_warning_errno(link, r, "Could not assign DHCPv6 address: %m");

        return r;
}
Exemplo n.º 10
0
static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
        sd_dhcp_lease *lease;
        struct in_addr address;
        struct in_addr netmask;
        uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
        int r;

        assert(link);
        assert(client);
        assert(link->network);

        r = sd_dhcp_client_get_lease(client, &lease);
        if (r < 0)
                return log_link_warning_errno(link, r, "DHCP error: no lease: %m");

        sd_dhcp_lease_unref(link->dhcp_lease);
        link->dhcp4_configured = false;
        link->dhcp_lease = sd_dhcp_lease_ref(lease);
        link_dirty(link);

        r = sd_dhcp_lease_get_address(lease, &address);
        if (r < 0)
                return log_link_warning_errno(link, r, "DHCP error: no address: %m");

        r = sd_dhcp_lease_get_netmask(lease, &netmask);
        if (r < 0)
                return log_link_warning_errno(link, r, "DHCP error: no netmask: %m");

        if (!link->network->dhcp_critical) {
                r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime);
                if (r < 0)
                        return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
        }

        r = dhcp4_update_address(link, &address, &netmask, lifetime);
        if (r < 0) {
                log_link_warning_errno(link, r, "Could not update IP address: %m");
                link_enter_failed(link);
                return r;
        }

        return 0;
}
Exemplo n.º 11
0
static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
        int r;
        Link *link = userdata;

        assert(link);
        assert(link->network);
        assert(link->manager);

        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                return;

        switch(event) {
        case SD_DHCP6_CLIENT_EVENT_STOP:
        case SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE:
        case SD_DHCP6_CLIENT_EVENT_RETRANS_MAX:
                if (sd_dhcp6_client_get_lease(client, NULL) >= 0)
                        log_link_warning(link, "DHCPv6 lease lost");

                link->dhcp6_configured = false;
                break;

        case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE:
                r = dhcp6_lease_address_acquired(client, link);
                if (r < 0) {
                        link_enter_failed(link);
                        return;
                }

                /* fall through */
        case SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST:
                r = dhcp6_lease_information_acquired(client, link);
                if (r < 0) {
                        link_enter_failed(link);
                        return;
                }

                link->dhcp6_configured = true;
                break;

        default:
                if (event < 0)
                        log_link_warning_errno(link, event, "DHCPv6 error: %m");
                else
                        log_link_warning(link, "DHCPv6 unknown event: %d", event);
                return;
        }

        link_check_ready(link);
}
Exemplo n.º 12
0
static int route_expire_callback(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
        Link *link = userdata;
        int r;

        assert(rtnl);
        assert(m);
        assert(link);
        assert(link->ifname);

        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                return 1;

        r = sd_netlink_message_get_errno(m);
        if (r < 0 && r != -EEXIST)
                log_link_warning_errno(link, r, "could not remove route: %m");

        return 1;
}
static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
        _cleanup_link_unref_ Link *link = userdata;
        int r;

        assert(m);
        assert(link);
        assert(link->ifname);

        link->routing_policy_rule_remove_messages--;

        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                return 1;

        r = sd_netlink_message_get_errno(m);
        if (r < 0)
                log_link_warning_errno(link, r, "Could not drop routing policy rule: %m");

        return 1;
}
int address_release(Address *address, Link *link) {
        int r;

        assert(address);
        assert(link);

        /* Remove masquerading firewall entry if it was added */
        if (address->ip_masquerade_done) {
                union in_addr_union masked = address->in_addr;
                in_addr_mask(address->family, &masked, address->prefixlen);

                r = fw_add_masquerade(false, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
                if (r < 0)
                        log_link_warning_errno(link, r, "Failed to disable IP masquerading: %m");

                address->ip_masquerade_done = false;
        }

        return 0;
}
Exemplo n.º 15
0
static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) {
        Link *link = userdata;

        assert(link);
        assert(link->network);
        assert(link->manager);

        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                return;

        switch(event) {
        case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE:
                return;

        case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT:
        case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER:
        case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED:
                dhcp6_configure(link, event);

                break;

        case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED:
                if (!link->rtnl_extended_attrs)
                        dhcp6_prefix_expired(link);

                break;

        default:
                if (event < 0)
                        log_link_warning_errno(link, event, "ICMPv6 error: %m");
                else
                        log_link_warning(link, "ICMPv6 unknown event: %d", event);

                break;
        }

}
Exemplo n.º 16
0
/* dhcp4_set_promote_secondaries will ensure this interface has
 * the "promote_secondaries" option in the kernel set. If this sysctl
 * is not set DHCP will work only as long as the IP address does not
 * changes between leases. The kernel will remove all secondary IP
 * addresses of an interface otherwise. The way systemd-network works
 * is that the new IP of a lease is added as a secondary IP and when
 * the primary one expires it relies on the kernel to promote the
 * secondary IP. See also https://github.com/systemd/systemd/issues/7163
 */
int dhcp4_set_promote_secondaries(Link *link) {
        int r;

        assert(link);
        assert(link->network);
        assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);

        /* check if the kernel has promote_secondaries enabled for our
         * interface. If it is not globally enabled or enabled for the
         * specific interface we must either enable it.
         */
        if (!(promote_secondaries_enabled("all") || promote_secondaries_enabled(link->ifname))) {
                char *promote_secondaries_path = NULL;

                log_link_debug(link, "promote_secondaries is unset, setting it");
                promote_secondaries_path = strjoina("net/ipv4/conf/", link->ifname, "/promote_secondaries");
                r = sysctl_write(promote_secondaries_path, "1");
                if (r < 0)
                        log_link_warning_errno(link, r, "cannot set sysctl %s to 1", promote_secondaries_path);
                return r > 0;
        }

        return 0;
}
Exemplo n.º 17
0
static int dhcp6_configure(Link *link, int event) {
        int r;
        bool information_request;

        assert_return(link, -EINVAL);
        assert_return(IN_SET(event, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT,
                             SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER,
                             SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED), -EINVAL);

        link->dhcp6_configured = false;

        if (link->dhcp6_client) {
                r = sd_dhcp6_client_get_information_request(link->dhcp6_client,
                                                        &information_request);
                if (r < 0) {
                        log_link_warning_errno(link, r, "Could not get DHCPv6 Information request setting: %m");
                        goto error;
                }

                if (information_request && event != SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER) {
                        r = sd_dhcp6_client_stop(link->dhcp6_client);
                        if (r < 0) {
                                log_link_warning_errno(link, r, "Could not stop DHCPv6 while setting Managed mode: %m");
                                goto error;
                        }

                        r = sd_dhcp6_client_set_information_request(link->dhcp6_client,
                                                                    false);
                        if (r < 0) {
                                log_link_warning_errno(link, r, "Could not unset DHCPv6 Information request: %m");
                                goto error;
                        }

                }

                r = sd_dhcp6_client_start(link->dhcp6_client);
                if (r < 0 && r != -EALREADY) {
                        log_link_warning_errno(link, r, "Could not restart DHCPv6: %m");
                        goto error;
                }

                if (r == -EALREADY)
                        link->dhcp6_configured = true;

                return r;
        }

        r = sd_dhcp6_client_new(&link->dhcp6_client);
        if (r < 0)
                goto error;

        r = sd_dhcp6_client_attach_event(link->dhcp6_client, NULL, 0);
        if (r < 0)
                goto error;

        r = sd_dhcp6_client_set_mac(link->dhcp6_client,
                                    (const uint8_t *) &link->mac,
                                    sizeof (link->mac), ARPHRD_ETHER);
        if (r < 0)
                goto error;

        r = sd_dhcp6_client_set_index(link->dhcp6_client, link->ifindex);
        if (r < 0)
                goto error;

        r = sd_dhcp6_client_set_callback(link->dhcp6_client, dhcp6_handler,
                                         link);
        if (r < 0)
                goto error;

        if (event == SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER) {
                r = sd_dhcp6_client_set_information_request(link->dhcp6_client,
                                                        true);
                if (r < 0)
                        goto error;
        }

        r = sd_dhcp6_client_start(link->dhcp6_client);
        if (r < 0)
                goto error;

        return r;

 error:
        link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
        return r;
}
Exemplo n.º 18
0
static int link_set_dhcp_routes(Link *link) {
    struct in_addr gateway;
    struct sd_dhcp_route *static_routes;
    int r, n, i;

    assert(link);
    assert(link->dhcp_lease);

    r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
    if (r < 0 && r != -ENODATA)
        return log_link_warning_errno(link, r, "DHCP error: could not get gateway: %m");

    if (r >= 0) {
        struct in_addr address;
        _cleanup_route_free_ Route *route = NULL;
        _cleanup_route_free_ Route *route_gw = NULL;

        r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
        if (r < 0)
            return log_link_warning_errno(link, r, "DHCP error: could not get address: %m");

        r = route_new_dynamic(&route, RTPROT_DHCP);
        if (r < 0)
            return log_link_error_errno(link, r, "Could not allocate route: %m");

        r = route_new_dynamic(&route_gw, RTPROT_DHCP);
        if (r < 0)
            return log_link_error_errno(link, r,  "Could not allocate route: %m");

        /* The dhcp netmask may mask out the gateway. Add an explicit
         * route for the gw host so that we can route no matter the
         * netmask or existing kernel route tables. */
        route_gw->family = AF_INET;
        route_gw->dst_addr.in = gateway;
        route_gw->dst_prefixlen = 32;
        route_gw->prefsrc_addr.in = address;
        route_gw->scope = RT_SCOPE_LINK;
        route_gw->metrics = link->network->dhcp_route_metric;

        r = route_configure(route_gw, link, &dhcp4_route_handler);
        if (r < 0)
            return log_link_warning_errno(link, r, "Could not set host route: %m");

        link->dhcp4_messages ++;

        route->family = AF_INET;
        route->in_addr.in = gateway;
        route->prefsrc_addr.in = address;
        route->metrics = link->network->dhcp_route_metric;

        r = route_configure(route, link, &dhcp4_route_handler);
        if (r < 0) {
            log_link_warning_errno(link, r, "Could not set routes: %m");
            link_enter_failed(link);
            return r;
        }

        link->dhcp4_messages ++;
    }

    n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes);
    if (n == -ENODATA)
        return 0;
    if (n < 0)
        return log_link_warning_errno(link, n, "DHCP error: could not get routes: %m");

    for (i = 0; i < n; i++) {
        _cleanup_route_free_ Route *route = NULL;

        r = route_new_dynamic(&route, RTPROT_DHCP);
        if (r < 0)
            return log_link_error_errno(link, r, "Could not allocate route: %m");

        route->family = AF_INET;
        route->in_addr.in = static_routes[i].gw_addr;
        route->dst_addr.in = static_routes[i].dst_addr;
        route->dst_prefixlen = static_routes[i].dst_prefixlen;
        route->metrics = link->network->dhcp_route_metric;

        r = route_configure(route, link, &dhcp4_route_handler);
        if (r < 0)
            return log_link_warning_errno(link, r, "Could not set host route: %m");

        link->dhcp4_messages ++;
    }

    return 0;
}
Exemplo n.º 19
0
static int link_set_dhcp_routes(Link *link) {
        struct in_addr gateway, address;
        _cleanup_free_ sd_dhcp_route **static_routes = NULL;
        int r, n, i;

        assert(link);
        assert(link->dhcp_lease);
        assert(link->network);

        if (!link->network->dhcp_use_routes)
                return 0;

        r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
        if (r < 0)
                return log_link_warning_errno(link, r, "DHCP error: could not get address: %m");

        r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
        if (r < 0 && r != -ENODATA)
                return log_link_warning_errno(link, r, "DHCP error: could not get gateway: %m");

        if (r >= 0) {
                _cleanup_route_free_ Route *route = NULL;
                _cleanup_route_free_ Route *route_gw = NULL;

                r = route_new(&route);
                if (r < 0)
                        return log_link_error_errno(link, r, "Could not allocate route: %m");

                route->protocol = RTPROT_DHCP;

                r = route_new(&route_gw);
                if (r < 0)
                        return log_link_error_errno(link, r,  "Could not allocate route: %m");

                /* The dhcp netmask may mask out the gateway. Add an explicit
                 * route for the gw host so that we can route no matter the
                 * netmask or existing kernel route tables. */
                route_gw->family = AF_INET;
                route_gw->dst.in = gateway;
                route_gw->dst_prefixlen = 32;
                route_gw->prefsrc.in = address;
                route_gw->scope = RT_SCOPE_LINK;
                route_gw->protocol = RTPROT_DHCP;
                route_gw->priority = link->network->dhcp_route_metric;
                route_gw->table = link->network->dhcp_route_table;

                r = route_configure(route_gw, link, dhcp4_route_handler);
                if (r < 0)
                        return log_link_warning_errno(link, r, "Could not set host route: %m");

                link->dhcp4_messages++;

                route->family = AF_INET;
                route->gw.in = gateway;
                route->prefsrc.in = address;
                route->priority = link->network->dhcp_route_metric;
                route->table = link->network->dhcp_route_table;

                r = route_configure(route, link, dhcp4_route_handler);
                if (r < 0) {
                        log_link_warning_errno(link, r, "Could not set routes: %m");
                        link_enter_failed(link);
                        return r;
                }

                link->dhcp4_messages++;
        }

        n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes);
        if (n == -ENODATA)
                return 0;
        if (n < 0)
                return log_link_warning_errno(link, n, "DHCP error: could not get routes: %m");

        for (i = 0; i < n; i++) {
                _cleanup_route_free_ Route *route = NULL;

                r = route_new(&route);
                if (r < 0)
                        return log_link_error_errno(link, r, "Could not allocate route: %m");

                route->family = AF_INET;
                route->protocol = RTPROT_DHCP;
                assert_se(sd_dhcp_route_get_gateway(static_routes[i], &route->gw.in) >= 0);
                assert_se(sd_dhcp_route_get_destination(static_routes[i], &route->dst.in) >= 0);
                assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes[i], &route->dst_prefixlen) >= 0);
                route->priority = link->network->dhcp_route_metric;
                route->table = link->network->dhcp_route_table;
                route->scope = route_scope_from_address(route, &address);

                r = route_configure(route, link, dhcp4_route_handler);
                if (r < 0)
                        return log_link_warning_errno(link, r, "Could not set host route: %m");

                link->dhcp4_messages++;
        }

        return 0;
}
Exemplo n.º 20
0
static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
        Link *link = userdata;
        int r = 0;

        assert(link);
        assert(link->network);
        assert(link->manager);

        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                return;

        switch (event) {
                case SD_DHCP_CLIENT_EVENT_EXPIRED:
                case SD_DHCP_CLIENT_EVENT_STOP:
                case SD_DHCP_CLIENT_EVENT_IP_CHANGE:
                        if (link->network->dhcp_critical) {
                                log_link_error(link, "DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
                                return;
                        }

                        if (link->dhcp_lease) {
                                r = dhcp_lease_lost(link);
                                if (r < 0) {
                                        link_enter_failed(link);
                                        return;
                                }
                        }

                        if (event == SD_DHCP_CLIENT_EVENT_IP_CHANGE) {
                                r = dhcp_lease_acquired(client, link);
                                if (r < 0) {
                                        link_enter_failed(link);
                                        return;
                                }
                        }

                        break;
                case SD_DHCP_CLIENT_EVENT_RENEW:
                        r = dhcp_lease_renew(client, link);
                        if (r < 0) {
                                link_enter_failed(link);
                                return;
                        }
                        break;
                case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE:
                        r = dhcp_lease_acquired(client, link);
                        if (r < 0) {
                                link_enter_failed(link);
                                return;
                        }
                        break;
                default:
                        if (event < 0)
                                log_link_warning_errno(link, event, "DHCP error: Client failed: %m");
                        else
                                log_link_warning(link, "DHCP unknown event: %i", event);
                        break;
        }

        return;
}
Exemplo n.º 21
0
static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
        sd_dhcp_lease *lease;
        struct in_addr address;
        struct in_addr netmask;
        struct in_addr gateway;
        unsigned prefixlen;
        uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
        int r;

        assert(client);
        assert(link);

        r = sd_dhcp_client_get_lease(client, &lease);
        if (r < 0)
                return log_link_error_errno(link, r, "DHCP error: No lease: %m");

        r = sd_dhcp_lease_get_address(lease, &address);
        if (r < 0)
                return log_link_error_errno(link, r, "DHCP error: No address: %m");

        r = sd_dhcp_lease_get_netmask(lease, &netmask);
        if (r < 0)
                return log_link_error_errno(link, r, "DHCP error: No netmask: %m");

        prefixlen = in_addr_netmask_to_prefixlen(&netmask);

        r = sd_dhcp_lease_get_router(lease, &gateway);
        if (r < 0 && r != -ENODATA)
                return log_link_error_errno(link, r, "DHCP error: Could not get gateway: %m");

        if (r >= 0)
                log_struct(LOG_INFO,
                           LOG_LINK_INTERFACE(link),
                           LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
                                            ADDRESS_FMT_VAL(address),
                                            prefixlen,
                                            ADDRESS_FMT_VAL(gateway)),
                           "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
                           "PREFIXLEN=%u", prefixlen,
                           "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(gateway),
                           NULL);
        else
                log_struct(LOG_INFO,
                           LOG_LINK_INTERFACE(link),
                           LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u",
                                            ADDRESS_FMT_VAL(address),
                                            prefixlen),
                           "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
                           "PREFIXLEN=%u", prefixlen,
                           NULL);

        link->dhcp_lease = sd_dhcp_lease_ref(lease);
        link_dirty(link);

        if (link->network->dhcp_use_mtu) {
                uint16_t mtu;

                r = sd_dhcp_lease_get_mtu(lease, &mtu);
                if (r >= 0) {
                        r = link_set_mtu(link, mtu);
                        if (r < 0)
                                log_link_error_errno(link, r, "Failed to set MTU to %" PRIu16 ": %m", mtu);
                }
        }

        if (link->network->dhcp_use_hostname) {
                const char *hostname = NULL;

                if (link->network->dhcp_hostname)
                        hostname = link->network->dhcp_hostname;
                else
                        (void) sd_dhcp_lease_get_hostname(lease, &hostname);

                if (hostname) {
                        r = manager_set_hostname(link->manager, hostname);
                        if (r < 0)
                                log_link_error_errno(link, r, "Failed to set transient hostname to '%s': %m", hostname);
                }
        }

        if (link->network->dhcp_use_timezone) {
                const char *tz = NULL;

                (void) sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz);

                if (tz) {
                        r = manager_set_timezone(link->manager, tz);
                        if (r < 0)
                                log_link_error_errno(link, r, "Failed to set timezone to '%s': %m", tz);
                }
        }

        if (!link->network->dhcp_critical) {
                r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime);
                if (r < 0) {
                        log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
                        return r;
                }
        }

        r = dhcp4_update_address(link, &address, &netmask, lifetime);
        if (r < 0) {
                log_link_warning_errno(link, r, "Could not update IP address: %m");
                link_enter_failed(link);
                return r;
        }

        return 0;
}
Exemplo n.º 22
0
static int dhcp_lease_lost(Link *link) {
        _cleanup_address_free_ Address *address = NULL;
        struct in_addr addr;
        struct in_addr netmask;
        struct in_addr gateway;
        unsigned prefixlen = 0;
        int r;

        assert(link);
        assert(link->dhcp_lease);

        log_link_warning(link, "DHCP lease lost");

        if (link->network->dhcp_use_routes) {
                _cleanup_free_ sd_dhcp_route **routes = NULL;
                int n, i;

                n = sd_dhcp_lease_get_routes(link->dhcp_lease, &routes);
                if (n >= 0) {
                        for (i = 0; i < n; i++) {
                                _cleanup_route_free_ Route *route = NULL;

                                r = route_new(&route);
                                if (r >= 0) {
                                        route->family = AF_INET;
                                        assert_se(sd_dhcp_route_get_gateway(routes[i], &route->gw.in) >= 0);
                                        assert_se(sd_dhcp_route_get_destination(routes[i], &route->dst.in) >= 0);
                                        assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &route->dst_prefixlen) >= 0);

                                        route_remove(route, link,
                                                     link_route_remove_handler);
                                }
                        }
                }
        }

        r = address_new(&address);
        if (r >= 0) {
                r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
                if (r >= 0) {
                        _cleanup_route_free_ Route *route_gw = NULL;
                        _cleanup_route_free_ Route *route = NULL;

                        r = route_new(&route_gw);
                        if (r >= 0) {
                                route_gw->family = AF_INET;
                                route_gw->dst.in = gateway;
                                route_gw->dst_prefixlen = 32;
                                route_gw->scope = RT_SCOPE_LINK;

                                route_remove(route_gw, link,
                                             link_route_remove_handler);
                        }

                        r = route_new(&route);
                        if (r >= 0) {
                                route->family = AF_INET;
                                route->gw.in = gateway;

                                route_remove(route, link,
                                             link_route_remove_handler);
                        }
                }

                r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
                if (r >= 0) {
                        r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
                        if (r >= 0)
                                prefixlen = in_addr_netmask_to_prefixlen(&netmask);

                        address->family = AF_INET;
                        address->in_addr.in = addr;
                        address->prefixlen = prefixlen;

                        address_remove(address, link, link_address_remove_handler);
                }
        }

        if (link->network->dhcp_use_mtu) {
                uint16_t mtu;

                r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
                if (r >= 0 && link->original_mtu != mtu) {
                        r = link_set_mtu(link, link->original_mtu);
                        if (r < 0) {
                                log_link_warning(link,
                                                 "DHCP error: could not reset MTU");
                                link_enter_failed(link);
                                return r;
                        }
                }
        }

        if (link->network->dhcp_use_hostname) {
                const char *hostname = NULL;

                if (link->network->dhcp_hostname)
                        hostname = link->network->dhcp_hostname;
                else
                        (void) sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);

                if (hostname) {
                        /* If a hostname was set due to the lease, then unset it now. */
                        r = manager_set_hostname(link->manager, NULL);
                        if (r < 0)
                                log_link_warning_errno(link, r, "Failed to reset transient hostname: %m");
                }
        }

        link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
        link_dirty(link);
        link->dhcp4_configured = false;

        return 0;
}
Exemplo n.º 23
0
static void ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
        uint32_t lifetime;
        const struct in6_addr *a;
        usec_t time_now;
        int i, n, r;

        assert(link);
        assert(rt);

        r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
        if (r < 0) {
                log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
                return;
        }

        r = sd_ndisc_router_rdnss_get_lifetime(rt, &lifetime);
        if (r < 0) {
                log_link_warning_errno(link, r, "Failed to get RDNSS lifetime: %m");
                return;
        }

        n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
        if (n < 0) {
                log_link_warning_errno(link, n, "Failed to get RDNSS addresses: %m");
                return;
        }

        for (i = 0; i < n; i++) {
                NDiscRDNSS d = {
                        .address = a[i]
                }, *x;

                if (lifetime == 0) {
                        (void) set_remove(link->ndisc_rdnss, &d);
                        link_dirty(link);
                        continue;
                }

                x = set_get(link->ndisc_rdnss, &d);
                if (x) {
                        x->valid_until = time_now + lifetime * USEC_PER_SEC;
                        continue;
                }

                ndisc_vacuum(link);

                if (set_size(link->ndisc_rdnss) >= NDISC_RDNSS_MAX) {
                        log_link_warning(link, "Too many RDNSS records per link, ignoring.");
                        continue;
                }

                r = set_ensure_allocated(&link->ndisc_rdnss, &ndisc_rdnss_hash_ops);
                if (r < 0) {
                        log_oom();
                        return;
                }

                x = new0(NDiscRDNSS, 1);
                if (!x) {
                        log_oom();
                        return;
                }

                x->address = a[i];
                x->valid_until = time_now + lifetime * USEC_PER_SEC;

                r = set_put(link->ndisc_rdnss, x);
                if (r < 0) {
                        free(x);
                        log_oom();
                        return;
                }

                assert(r > 0);
                link_dirty(link);
        }
Exemplo n.º 24
0
static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
        const struct in_addr *router;
        sd_dhcp_lease *lease;
        struct in_addr address;
        struct in_addr netmask;
        unsigned prefixlen;
        uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
        int r;

        assert(client);
        assert(link);

        r = sd_dhcp_client_get_lease(client, &lease);
        if (r < 0)
                return log_link_error_errno(link, r, "DHCP error: No lease: %m");

        r = sd_dhcp_lease_get_address(lease, &address);
        if (r < 0)
                return log_link_error_errno(link, r, "DHCP error: No address: %m");

        r = sd_dhcp_lease_get_netmask(lease, &netmask);
        if (r < 0)
                return log_link_error_errno(link, r, "DHCP error: No netmask: %m");

        prefixlen = in4_addr_netmask_to_prefixlen(&netmask);

        r = sd_dhcp_lease_get_router(lease, &router);
        if (r < 0 && r != -ENODATA)
                return log_link_error_errno(link, r, "DHCP error: Could not get gateway: %m");

        if (r > 0 && !in4_addr_is_null(&router[0]))
                log_struct(LOG_INFO,
                           LOG_LINK_INTERFACE(link),
                           LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
                                            ADDRESS_FMT_VAL(address),
                                            prefixlen,
                                            ADDRESS_FMT_VAL(router[0])),
                           "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
                           "PREFIXLEN=%u", prefixlen,
                           "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(router[0]));
        else
                log_struct(LOG_INFO,
                           LOG_LINK_INTERFACE(link),
                           LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u",
                                            ADDRESS_FMT_VAL(address),
                                            prefixlen),
                           "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
                           "PREFIXLEN=%u", prefixlen);

        link->dhcp_lease = sd_dhcp_lease_ref(lease);
        link_dirty(link);

        if (link->network->dhcp_use_mtu) {
                uint16_t mtu;

                r = sd_dhcp_lease_get_mtu(lease, &mtu);
                if (r >= 0) {
                        r = link_set_mtu(link, mtu, true);
                        if (r < 0)
                                log_link_error_errno(link, r, "Failed to set MTU to %" PRIu16 ": %m", mtu);
                }
        }

        if (link->network->dhcp_use_hostname) {
                const char *dhcpname = NULL;
                _cleanup_free_ char *hostname = NULL;

                if (link->network->dhcp_hostname)
                        dhcpname = link->network->dhcp_hostname;
                else
                        (void) sd_dhcp_lease_get_hostname(lease, &dhcpname);

                if (dhcpname) {
                        r = shorten_overlong(dhcpname, &hostname);
                        if (r < 0)
                                log_link_warning_errno(link, r, "Unable to shorten overlong DHCP hostname '%s', ignoring: %m", dhcpname);
                        if (r == 1)
                                log_link_notice(link, "Overlong DHCP hostname received, shortened from '%s' to '%s'", dhcpname, hostname);
                }

                if (hostname) {
                        r = manager_set_hostname(link->manager, hostname);
                        if (r < 0)
                                log_link_error_errno(link, r, "Failed to set transient hostname to '%s': %m", hostname);
                }
        }

        if (link->network->dhcp_use_timezone) {
                const char *tz = NULL;

                (void) sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz);

                if (tz) {
                        r = manager_set_timezone(link->manager, tz);
                        if (r < 0)
                                log_link_error_errno(link, r, "Failed to set timezone to '%s': %m", tz);
                }
        }

        if (!link->network->dhcp_critical) {
                r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime);
                if (r < 0)
                        return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
        }

        r = dhcp4_update_address(link, &address, &netmask, lifetime);
        if (r < 0) {
                log_link_warning_errno(link, r, "Could not update IP address: %m");
                link_enter_failed(link);
                return r;
        }

        return 0;
}
Exemplo n.º 25
0
static int link_set_dhcp_routes(Link *link) {
        _cleanup_free_ sd_dhcp_route **static_routes = NULL;
        bool classless_route = false, static_route = false;
        const struct in_addr *router;
        struct in_addr address;
        int r, n, i;
        uint32_t table;

        assert(link);

        if (!link->dhcp_lease) /* link went down while we configured the IP addresses? */
                return 0;

        if (!link->network) /* link went down while we configured the IP addresses? */
                return 0;

        if (!link->network->dhcp_use_routes)
                return 0;

        table = link_get_dhcp_route_table(link);

        r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
        if (r < 0)
                return log_link_warning_errno(link, r, "DHCP error: could not get address: %m");

        n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes);
        if (n == -ENODATA)
                log_link_debug_errno(link, n, "DHCP: No routes received from DHCP server: %m");
        else if (n < 0)
                log_link_debug_errno(link, n, "DHCP error: could not get routes: %m");

        for (i = 0; i < n; i++) {
                switch (sd_dhcp_route_get_option(static_routes[i])) {
                case SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
                        classless_route = true;
                        break;
                case SD_DHCP_OPTION_STATIC_ROUTE:
                        static_route = true;
                        break;
                }
        }

        for (i = 0; i < n; i++) {
                _cleanup_(route_freep) Route *route = NULL;

                /* if the DHCP server returns both a Classless Static Routes option and a Static Routes option,
                   the DHCP client MUST ignore the Static Routes option. */
                if (classless_route &&
                    sd_dhcp_route_get_option(static_routes[i]) != SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE)
                        continue;

                r = route_new(&route);
                if (r < 0)
                        return log_link_error_errno(link, r, "Could not allocate route: %m");

                route->family = AF_INET;
                route->protocol = RTPROT_DHCP;
                assert_se(sd_dhcp_route_get_gateway(static_routes[i], &route->gw.in) >= 0);
                assert_se(sd_dhcp_route_get_destination(static_routes[i], &route->dst.in) >= 0);
                assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes[i], &route->dst_prefixlen) >= 0);
                route->priority = link->network->dhcp_route_metric;
                route->table = table;
                route->scope = route_scope_from_address(route, &address);

                r = route_configure(route, link, dhcp4_route_handler);
                if (r < 0)
                        return log_link_warning_errno(link, r, "Could not set host route: %m");

                link->dhcp4_messages++;
        }

        r = sd_dhcp_lease_get_router(link->dhcp_lease, &router);
        if (IN_SET(r, 0, -ENODATA))
                log_link_info(link, "DHCP: No gateway received from DHCP server.");
        else if (r < 0)
                log_link_warning_errno(link, r, "DHCP error: could not get gateway: %m");
        else if (in4_addr_is_null(&router[0]))
                log_link_info(link, "DHCP: Received gateway is null.");

        /* According to RFC 3442: If the DHCP server returns both a Classless Static Routes option and
           a Router option, the DHCP client MUST ignore the Router option. */
        if (classless_route && static_route)
                log_link_warning(link, "Classless static routes received from DHCP server: ignoring static-route option and router option");

        if (r > 0 && !classless_route && !in4_addr_is_null(&router[0])) {
                _cleanup_(route_freep) Route *route = NULL, *route_gw = NULL;

                r = route_new(&route_gw);
                if (r < 0)
                        return log_link_error_errno(link, r,  "Could not allocate route: %m");

                /* The dhcp netmask may mask out the gateway. Add an explicit
                 * route for the gw host so that we can route no matter the
                 * netmask or existing kernel route tables. */
                route_gw->family = AF_INET;
                route_gw->dst.in = router[0];
                route_gw->dst_prefixlen = 32;
                route_gw->prefsrc.in = address;
                route_gw->scope = RT_SCOPE_LINK;
                route_gw->protocol = RTPROT_DHCP;
                route_gw->priority = link->network->dhcp_route_metric;
                route_gw->table = table;

                r = route_configure(route_gw, link, dhcp4_route_handler);
                if (r < 0)
                        return log_link_warning_errno(link, r, "Could not set host route: %m");

                link->dhcp4_messages++;

                r = route_new(&route);
                if (r < 0)
                        return log_link_error_errno(link, r, "Could not allocate route: %m");

                route->family = AF_INET;
                route->gw.in = router[0];
                route->prefsrc.in = address;
                route->protocol = RTPROT_DHCP;
                route->priority = link->network->dhcp_route_metric;
                route->table = table;

                r = route_configure(route, link, dhcp4_route_handler);
                if (r < 0) {
                        log_link_warning_errno(link, r, "Could not set routes: %m");
                        link_enter_failed(link);
                        return r;
                }

                link->dhcp4_messages++;
        }

        return 0;
}
Exemplo n.º 26
0
static int link_set_dhcp_routes(Link *link) {
        _cleanup_free_ sd_dhcp_route **static_routes = NULL;
        bool classless_route = false, static_route = false;
        struct in_addr gateway, address;
        int r, n, i;
        uint32_t table;

        assert(link);

        if (!link->dhcp_lease) /* link went down while we configured the IP addresses? */
                return 0;

        if (!link->network) /* link went down while we configured the IP addresses? */
                return 0;

        if (!link->network->dhcp_use_routes)
                return 0;

        /* When the interface is part of an VRF use the VRFs routing table, unless
         * there is a another table specified. */
        table = link->network->dhcp_route_table;
        if (!link->network->dhcp_route_table_set && link->network->vrf != NULL)
                table = VRF(link->network->vrf)->table;

        r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
        if (r < 0)
                return log_link_warning_errno(link, r, "DHCP error: could not get address: %m");

        n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes);
        if (n < 0)
                log_link_debug_errno(link, n, "DHCP error: could not get routes: %m");

        for (i = 0; i < n; i++) {
                if (static_routes[i]->option == SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE)
                        classless_route = true;

                if (static_routes[i]->option == SD_DHCP_OPTION_STATIC_ROUTE)
                        static_route = true;
        }

        for (i = 0; i < n; i++) {
                _cleanup_route_free_ Route *route = NULL;

                /* if the DHCP server returns both a Classless Static Routes option and a Static Routes option,
                   the DHCP client MUST ignore the Static Routes option. */
                if (classless_route && static_routes[i]->option == SD_DHCP_OPTION_STATIC_ROUTE)
                        continue;

                r = route_new(&route);
                if (r < 0)
                        return log_link_error_errno(link, r, "Could not allocate route: %m");

                route->family = AF_INET;
                route->protocol = RTPROT_DHCP;
                assert_se(sd_dhcp_route_get_gateway(static_routes[i], &route->gw.in) >= 0);
                assert_se(sd_dhcp_route_get_destination(static_routes[i], &route->dst.in) >= 0);
                assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes[i], &route->dst_prefixlen) >= 0);
                route->priority = link->network->dhcp_route_metric;
                route->table = table;
                route->scope = route_scope_from_address(route, &address);

                r = route_configure(route, link, dhcp4_route_handler);
                if (r < 0)
                        return log_link_warning_errno(link, r, "Could not set host route: %m");

                link->dhcp4_messages++;
        }

        r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
        if (r == -ENODATA)
                log_link_info_errno(link, r, "DHCP: No routes received from DHCP server: %m");
        else if (r < 0)
                log_link_warning_errno(link, r, "DHCP error: could not get gateway: %m");

        /* According to RFC 3442: If the DHCP server returns both a Classless Static Routes option and
           a Router option, the DHCP client MUST ignore the Router option. */
        if (classless_route && static_route)
                log_link_warning(link, "Classless static routes received from DHCP server: ignoring static-route option and router option");

        if (r >= 0 && !classless_route) {
                _cleanup_route_free_ Route *route = NULL;
                _cleanup_route_free_ Route *route_gw = NULL;

                r = route_new(&route);
                if (r < 0)
                        return log_link_error_errno(link, r, "Could not allocate route: %m");

                route->protocol = RTPROT_DHCP;

                r = route_new(&route_gw);
                if (r < 0)
                        return log_link_error_errno(link, r,  "Could not allocate route: %m");

                /* The dhcp netmask may mask out the gateway. Add an explicit
                 * route for the gw host so that we can route no matter the
                 * netmask or existing kernel route tables. */
                route_gw->family = AF_INET;
                route_gw->dst.in = gateway;
                route_gw->dst_prefixlen = 32;
                route_gw->prefsrc.in = address;
                route_gw->scope = RT_SCOPE_LINK;
                route_gw->protocol = RTPROT_DHCP;
                route_gw->priority = link->network->dhcp_route_metric;
                route_gw->table = table;

                r = route_configure(route_gw, link, dhcp4_route_handler);
                if (r < 0)
                        return log_link_warning_errno(link, r, "Could not set host route: %m");

                link->dhcp4_messages++;

                route->family = AF_INET;
                route->gw.in = gateway;
                route->prefsrc.in = address;
                route->priority = link->network->dhcp_route_metric;
                route->table = table;

                r = route_configure(route, link, dhcp4_route_handler);
                if (r < 0) {
                        log_link_warning_errno(link, r, "Could not set routes: %m");
                        link_enter_failed(link);
                        return r;
                }

                link->dhcp4_messages++;
        }

        return 0;
}
Exemplo n.º 27
0
static void ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) {
        _cleanup_address_free_ Address *address = NULL;
        uint32_t lifetime_valid, lifetime_preferred;
        unsigned prefixlen;
        int r;

        assert(link);
        assert(rt);

        r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
        if (r < 0) {
                log_link_error_errno(link, r, "Failed to get prefix length: %m");
                return;
        }

        r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_valid);
        if (r < 0) {
                log_link_error_errno(link, r, "Failed to get prefix valid lifetime: %m");
                return;
        }

        r = sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred);
        if (r < 0) {
                log_link_error_errno(link, r, "Failed to get prefix preferred lifetime: %m");
                return;
        }

        r = address_new(&address);
        if (r < 0) {
                log_link_error_errno(link, r, "Could not allocate address: %m");
                return;
        }

        address->family = AF_INET6;
        r = sd_ndisc_router_prefix_get_address(rt, &address->in_addr.in6);
        if (r < 0) {
                log_link_error_errno(link, r, "Failed to get prefix address: %m");
                return;
        }

        if (in_addr_is_null(AF_INET6, (const union in_addr_union *) &link->network->ipv6_token) == 0)
                memcpy(((char *)&address->in_addr.in6) + 8, ((char *)&link->network->ipv6_token) + 8, 8);
        else {
                /* see RFC4291 section 2.5.1 */
                address->in_addr.in6.s6_addr[8]  = link->mac.ether_addr_octet[0];
                address->in_addr.in6.s6_addr[8] ^= 1 << 1;
                address->in_addr.in6.s6_addr[9]  = link->mac.ether_addr_octet[1];
                address->in_addr.in6.s6_addr[10] = link->mac.ether_addr_octet[2];
                address->in_addr.in6.s6_addr[11] = 0xff;
                address->in_addr.in6.s6_addr[12] = 0xfe;
                address->in_addr.in6.s6_addr[13] = link->mac.ether_addr_octet[3];
                address->in_addr.in6.s6_addr[14] = link->mac.ether_addr_octet[4];
                address->in_addr.in6.s6_addr[15] = link->mac.ether_addr_octet[5];
        }
        address->prefixlen = prefixlen;
        address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
        address->cinfo.ifa_prefered = lifetime_preferred;
        address->cinfo.ifa_valid = lifetime_valid;

        r = address_configure(address, link, ndisc_netlink_handler, true);
        if (r < 0) {
                log_link_warning_errno(link, r, "Could not set SLAAC address: %m");
                link_enter_failed(link);
                return;
        }

        link->ndisc_messages++;
}