Beispiel #1
0
int lispd_get_iface_address(
    char                *ifacename,
    lisp_addr_t         *addr,
    int                 afi)
{
    struct ifaddrs      *ifaddr;
    struct ifaddrs      *ifa;
    struct sockaddr_in  *s4;
    struct sockaddr_in6 *s6;
    lisp_addr_t         ip;
    char addr_str[MAX_INET_ADDRSTRLEN];


    if (default_rloc_afi != -1){ /* If forced a exact RLOC type (Just IPv4 of just IPv6) */
        if(afi != default_rloc_afi){
            lispd_log_msg(LISP_LOG_INFO,"Default RLOC afi defined: Skipped %s address in iface %s",
                          (afi == AF_INET) ? "IPv4" : "IPv6",ifacename);
            return (BAD);
        }
    }

    /* 
     * make sure this is clean
     */

    memset(addr, 0, sizeof(lisp_addr_t));

    /*
     *  go search for the interface
     */

    if (getifaddrs(&ifaddr) !=0) {
        lispd_log_msg(LISP_LOG_DEBUG_2,
               "lispd_get_iface_address: getifaddrs error: %s", strerror(errno));
        return(BAD);
    }

    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
        if ((ifa->ifa_addr == NULL) || ((ifa->ifa_flags & IFF_UP) == 0) || (ifa->ifa_addr->sa_family != afi))
            continue;

        switch (ifa->ifa_addr->sa_family) {
        case AF_INET:
            s4 = (struct sockaddr_in *)(ifa->ifa_addr);
            if (strcmp(ifa->ifa_name, ifacename) == 0) {
                memcpy((void *) &(ip.address),
                       (void *)&(s4->sin_addr), sizeof(struct in_addr));
                ip.afi = AF_INET;
                if (is_link_local_addr(ip) != TRUE){
                    copy_lisp_addr(addr,&ip);
                }else{
                    lispd_log_msg(LISP_LOG_DEBUG_2, "lispd_get_iface_address: interface address from %s discarded (%s)",
                            ifacename, get_char_from_lisp_addr_t(ip));
                    continue;
                }
                lispd_log_msg(LISP_LOG_DEBUG_2, "lispd_get_iface_address: IPv4 RLOC from interface (%s): %s \n",
                        ifacename,
                        inet_ntop(AF_INET, &(s4->sin_addr),
                            addr_str, MAX_INET_ADDRSTRLEN));
                freeifaddrs(ifaddr);
                return(GOOD);
            } else {
                continue;
            }
        case AF_INET6:
            s6 = (struct sockaddr_in6 *)(ifa->ifa_addr);
            // XXX sin6_scope_id is an ID depending on the scope of the address.  Linux only supports it for link-
            // local addresses, in that case sin6_scope_id contains the interface index. --> If sin6_scope_id is
            // not zero, is a link-local address
            if (s6->sin6_scope_id != 0){
                lispd_log_msg(LISP_LOG_DEBUG_2, "lispd_get_iface_address: interface address from %s discarded (%s)",
                        ifacename, inet_ntop(AF_INET6, &(s6->sin6_addr), addr_str, MAX_INET_ADDRSTRLEN));
                continue;
            }
            if (!strcmp(ifa->ifa_name, ifacename)) {
                memcpy((void *) &(addr->address),
                       (void *)&(s6->sin6_addr),
                       sizeof(struct in6_addr));
                addr->afi = AF_INET6;
                lispd_log_msg(LISP_LOG_DEBUG_2, "lispd_get_iface_address: IPv6 RLOC from interface (%s): %s\n",
                        ifacename, 
                        inet_ntop(AF_INET6, &(s6->sin6_addr), 
                            addr_str, MAX_INET_ADDRSTRLEN));
                freeifaddrs(ifaddr);
                return(GOOD);
            } else {
                continue;
            }
        default:
            continue;                   /* XXX */
        }
    }
    freeifaddrs(ifaddr);
    lispd_log_msg(LISP_LOG_DEBUG_3, "lispd_get_iface_address: No %s RLOC configured for interface %s\n",
            (afi == AF_INET) ? "IPv4" : "IPv6",
            ifacename);
    return(BAD);
}
void process_address_change (
    lispd_iface_elt     *iface,
    lisp_addr_t         new_addr)
{
    lisp_addr_t                 *iface_addr         = NULL;
    lispd_iface_mappings_list   *mapping_list       = NULL;
    int                         aux_afi             = 0;

    // XXX To be modified when full NAT implemented --> When Nat Aware active no IPv6 RLOCs supported
    if (nat_aware == TRUE && new_addr.afi == AF_INET6) {
        return;
    }

    /* Check if the addres is a global address*/
    if (is_link_local_addr(new_addr) == TRUE) {
        lispd_log_msg(LISP_LOG_DEBUG_2,"precess_address_change: the extractet address from the netlink "
                      "messages is a local link address: %s discarded", get_char_from_lisp_addr_t(new_addr));
        return;
    }
    /* If default RLOC afi defined (-a 4 or 6), only accept addresses of the specified afi */
    if (default_rloc_afi != AF_UNSPEC && default_rloc_afi != new_addr.afi) {
        lispd_log_msg(LISP_LOG_DEBUG_2,"precess_address_change: Default RLOC afi defined (-a #): Skipped %s address in iface %s",
                      (new_addr.afi == AF_INET) ? "IPv4" : "IPv6",iface->iface_name);
        return;
    }
    /*
     * Actions to be done due to a change of address: SMR
     */

    switch (new_addr.afi) {
    case AF_INET:
        iface_addr = iface->ipv4_address;
        break;
    case AF_INET6:
        iface_addr = iface->ipv6_address;
        break;
    }

    // Same address that we already have
    if (compare_lisp_addr_t(iface_addr,&new_addr)==0) {
        lispd_log_msg(LISP_LOG_DEBUG_2,"precess_address_change: The detected change of address for interface %s "
                      "doesn't affect",iface->iface_name);
        /* We must rebind the socket just in case the address is from a virtual interface who has changed its interafce number */
        switch (new_addr.afi) {
        case AF_INET:
            bind_socket_src_address(iface->out_socket_v4,&new_addr);
            break;
        case AF_INET6:
            bind_socket_src_address(iface->out_socket_v6,&new_addr);
            break;
        }

        return;
    }

    /*
     * Change source routing rules for this interface and binding
     */

    if (iface_addr->afi != AF_UNSPEC) {
        del_rule(iface_addr->afi,
                 0,
                 iface->iface_index,
                 iface->iface_index,
                 RTN_UNICAST,
                 iface_addr,
                 (iface_addr->afi == AF_INET) ? 32 : 128,
                 NULL,0,0);
    }
    add_rule(new_addr.afi,
             0,
             iface->iface_index,
             iface->iface_index,
             RTN_UNICAST,
             &new_addr,
             (new_addr.afi == AF_INET) ? 32 : 128,
             NULL,0,0);

    switch (new_addr.afi) {
    case AF_INET:
        bind_socket_src_address(iface->out_socket_v4,&new_addr);
        break;
    case AF_INET6:
        bind_socket_src_address(iface->out_socket_v6,&new_addr);
        break;
    }


    aux_afi = iface_addr->afi;
    // Update the new address
    copy_lisp_addr(iface_addr, &new_addr);


    /* The interface was down during initial configuratiopn process and now it is up. Activate address */
    if (aux_afi == AF_UNSPEC) {
        lispd_log_msg(LISP_LOG_DEBUG_1,"process_address_change: Activating the locator address %s"
                      , get_char_from_lisp_addr_t(new_addr));
        activate_interface_address(iface, new_addr);
        if (iface->status == UP) {
            iface_balancing_vectors_calc(iface);

            /*
             * If no default control and data interface, recalculate it
             */

            if ((default_ctrl_iface_v4 == NULL && new_addr.afi == AF_INET) ||
                    (default_ctrl_iface_v6 == NULL && new_addr.afi == AF_INET6)) {
                lispd_log_msg(LISP_LOG_DEBUG_2,"No default control interface. Recalculate new control interface");
                set_default_ctrl_ifaces();
            }

            if ((default_out_iface_v4 == NULL && new_addr.afi == AF_INET) ||
                    (default_out_iface_v6 == NULL && new_addr.afi == AF_INET6)) {
                lispd_log_msg(LISP_LOG_DEBUG_2,"No default output interface. Recalculate new output interface");
                set_default_output_ifaces();
            }
        }
    }

    lispd_log_msg(LISP_LOG_DEBUG_1,"precess_address_change: New address detected for interface %s -> %s",
                  iface->iface_name, get_char_from_lisp_addr_t(new_addr));

    mapping_list = iface->head_mappings_list;
    /* Sort again the locators list of the affected mappings*/
    while (mapping_list != NULL) {
        if (aux_afi != AF_UNSPEC && // When the locator is activated, it is automatically sorted
                ((new_addr.afi == AF_INET && mapping_list->use_ipv4_address == TRUE) ||
                 (new_addr.afi == AF_INET6 && mapping_list->use_ipv6_address == TRUE))) {
            sort_locators_list_elt (mapping_list->mapping, iface_addr);
        }
        mapping_list = mapping_list->next;
    }

    /* Indicate change of address in the interface */

    switch (new_addr.afi) {
    case AF_INET:
        iface->ipv4_changed = TRUE;
        break;
    case AF_INET6:
        iface->ipv6_changed = TRUE;
        break;
    }


    /* If it is compiled in router mode, then recompile default routes changing the indicated src address*/

    if (router_mode == TRUE) {
        switch (new_addr.afi) {
        case AF_INET:
            if (iface == default_out_iface_v4) {
                set_tun_default_route_v4();
            }
            break;
        case AF_INET6:
            if (iface == default_out_iface_v6) {
                del_tun_default_route_v6();
                set_tun_default_route_v6();
            }
            break;
        }
    }

    /* Check if the new address is behind NAT */

    if(nat_aware==TRUE) {
        // TODO : To be modified when implementing NAT per multiple interfaces
        nat_status = UNKNOWN;
        clear_rtr_from_locators (iface);

        if (iface->status == UP) {
            initial_info_request_process();
        } else {
            nat_aware_iface_address_change = TRUE;
        }
    }

    /* Reprograming SMR timer*/
    if (smr_timer == NULL) {
        smr_timer = create_timer (SMR_TIMER);
    }

    start_timer(smr_timer, LISPD_SMR_TIMEOUT,(timer_callback)init_smr, NULL);
}
void process_nl_new_route (struct nlmsghdr *nlh)
{
    struct rtmsg             *rtm                       = NULL;
    struct rtattr            *rt_attr                   = NULL;
    int                      rt_length                  = 0;
    lispd_iface_elt          *iface                     = NULL;
    int                      iface_index                = 0;
    char                     iface_name[IF_NAMESIZE];
    lisp_addr_t              gateway                    = {.afi=AF_UNSPEC};
    lisp_addr_t              dst                        = {.afi=AF_UNSPEC};;


    rtm = (struct rtmsg *) NLMSG_DATA (nlh);

    if ((rtm->rtm_family != AF_INET) && (rtm->rtm_family != AF_INET6)) {
        lispd_log_msg(LISP_LOG_DEBUG_2,"process_nl_new_route: Unknown adddress family");
        return;
    }

    if (rtm->rtm_table != RT_TABLE_MAIN) {
        /* Not interested in routes/gateways affecting tables other the main routing table */
        return;
    }

    rt_attr = (struct rtattr *)RTM_RTA(rtm);
    rt_length = RTM_PAYLOAD(nlh);

    for (; RTA_OK(rt_attr, rt_length); rt_attr = RTA_NEXT(rt_attr, rt_length)) {
        switch (rt_attr->rta_type) {
        case RTA_OIF:
            iface_index = *(int *)RTA_DATA(rt_attr);
            iface = get_interface_from_index(iface_index);
            if_indextoname(iface_index, iface_name);
            if (iface == NULL) {
                lispd_log_msg(LISP_LOG_DEBUG_2, "process_nl_new_route: the netlink message is not for any interface associated with RLOCs (%s)",
                              iface_name);
                return;
            }
            break;
        case RTA_GATEWAY:
            gateway.afi = rtm->rtm_family;
            switch (gateway.afi) {
            case AF_INET:
                memcpy(&(gateway.address),(struct in_addr *)RTA_DATA(rt_attr), sizeof(struct in_addr));
                break;
            case AF_INET6:
                memcpy(&(gateway.address),(struct in6_addr *)RTA_DATA(rt_attr), sizeof(struct in6_addr));
                break;
            default:
                break;
            }
            break;
        case RTA_DST: // We check if the new route message contains a destintaion. If it is, then the gateway address is not a default route. Discard it
            dst.afi = rtm->rtm_family;
            switch (dst.afi) {
            case AF_INET:
                memcpy(&(dst.address),(struct in_addr *)RTA_DATA(rt_attr), sizeof(struct in_addr));
                break;
            case AF_INET6:
                memcpy(&(dst.address),(struct in6_addr *)RTA_DATA(rt_attr), sizeof(struct in6_addr));
                break;
            default:
                break;
            }
            break;
        default:
            break;
        }
    }
    if (gateway.afi != AF_UNSPEC && iface_index != 0 && dst.afi == AF_UNSPEC) {
        /* Check default afi*/
        if (default_rloc_afi != AF_UNSPEC && default_rloc_afi != gateway.afi) {
            lispd_log_msg(LISP_LOG_DEBUG_1,  "process_nl_new_route: Default RLOC afi defined (-a #): Skipped %s gateway in iface %s",
                          (gateway.afi == AF_INET) ? "IPv4" : "IPv6",iface->iface_name);
            return;
        }

        /* Check if the addres is a global address*/
        if (is_link_local_addr(gateway) == TRUE) {
            lispd_log_msg(LISP_LOG_DEBUG_2,"process_nl_new_route: the extractet address from the netlink "
                          "messages is a local link address: %s discarded", get_char_from_lisp_addr_t(gateway));
            return;
        }

        /* Process the new gateway */
        lispd_log_msg(LISP_LOG_DEBUG_1,  "process_nl_new_route: Process new gateway associated to the interface %s:  %s",
                      iface_name, get_char_from_lisp_addr_t(gateway));
        process_new_gateway(gateway,iface);
    }
}
Beispiel #4
0
int read_address_nl(
		int 		ifa_index,
		lisp_addr_t *address)
{
    int                 len             = 0;
    char                buffer[4096];
    struct iovec        iov;
    struct sockaddr_nl  dst_addr;
    struct msghdr       msgh;
    struct nlmsghdr     *nlh    		= NULL;
    struct ifaddrmsg    *ifa            = NULL;
    struct rtattr       *rth            = NULL;
    int                 rt_length       = 0;


    nlh = (struct nlmsghdr *)buffer;

    memset(&iov, 0, sizeof(iov));
    iov.iov_base = (void *)nlh;
    iov.iov_len = sizeof(nlh);

    memset(&msgh, 0, sizeof(msgh));
    msgh.msg_name = (void *)&(dst_addr);
    msgh.msg_namelen = sizeof(dst_addr);
    msgh.msg_iov = &iov;
    msgh.msg_iovlen = 1;

    while ((len = recv (netlink_fd,nlh,4096,MSG_DONTWAIT)) > 0){
        for (;(NLMSG_OK (nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE); nlh = NLMSG_NEXT(nlh, len)){
            switch(nlh->nlmsg_type){
            case RTM_NEWADDR:
                lispd_log_msg(LISP_LOG_DEBUG_2, "=>process_netlink_msg: Received  new address message");
                ifa = (struct ifaddrmsg *) NLMSG_DATA (nlh);
                /* Netlink returns addresses from all ifaces even when we specify the iface index in the request msg */
                if (ifa_index != ifa->ifa_index){
                	continue;
                }
                rth = IFA_RTA (ifa);
                rt_length = IFA_PAYLOAD (nlh);
                for (;rt_length && RTA_OK (rth, rt_length); rth = RTA_NEXT (rth,rt_length))
                {
                	if (rth->rta_type == IFA_ADDRESS){
                		if (ifa->ifa_family == AF_INET){
                			memcpy (&(address->address),(struct in_addr *)RTA_DATA(rth),sizeof(struct in_addr));
                			address->afi = AF_INET;
                		}else if (ifa->ifa_family == AF_INET6){
                			memcpy (&(address->address),(struct in6_addr *)RTA_DATA(rth),sizeof(struct in6_addr));
                			address->afi = AF_INET6;
                		}
                		 if (is_link_local_addr(*address) == FALSE){
                			 return (GOOD);
                		 }
                	}
                }
                break;
            default:
                break;
            }
        }
        nlh = (struct nlmsghdr *)buffer;
        memset(nlh,0,4096);
    }
    lispd_log_msg(LISP_LOG_DEBUG_2, "Finish pocessing netlink message");
    return (BAD);
}