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); } }
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); }