int process_map_request_record( uint8_t **cur_ptr, lisp_addr_t *local_rloc, lisp_addr_t *remote_rloc, uint16_t dst_port, uint8_t rloc_probe, uint64_t nonce) { lispd_pkt_map_request_eid_prefix_record_t *record = NULL; lispd_mapping_elt *requested_mapping = NULL; lispd_mapping_elt *mapping = NULL; map_reply_opts opts; lisp_addr_t aux_eid_prefix; int aux_eid_prefix_length = 0; int aux_iid = -1; /* Get the requested EID prefix */ record = (lispd_pkt_map_request_eid_prefix_record_t *)*cur_ptr; /* Auxiliar lispd_mapping_elt created to be filled with pkt_process_eid_afi */ requested_mapping = new_local_mapping(aux_eid_prefix, aux_eid_prefix_length, aux_iid); if (requested_mapping == NULL){ return (BAD); } *cur_ptr = (uint8_t *)&(record->eid_prefix_afi); if ((err=pkt_process_eid_afi(cur_ptr, requested_mapping))!=GOOD){ lispd_log_msg(LISP_LOG_DEBUG_2,"process_map_request_record: Requested EID could not be processed"); free_mapping_elt (requested_mapping, TRUE); return (err); } requested_mapping->eid_prefix_length = record->eid_prefix_length; /* Check the existence of the requested EID */ /* We don't use prefix mask and use by default 32 or 128*/ mapping = lookup_eid_in_db(requested_mapping->eid_prefix); if (!mapping){ lispd_log_msg(LISP_LOG_DEBUG_1,"The requested EID doesn't belong to this node: %s/%d", get_char_from_lisp_addr_t(requested_mapping->eid_prefix), requested_mapping->eid_prefix_length); free_mapping_elt (requested_mapping, TRUE); return (BAD); } free_mapping_elt (requested_mapping, TRUE); /* Set flags for Map-Reply */ opts.send_rec = 1; opts.echo_nonce = 0; opts.rloc_probe = rloc_probe; err = build_and_send_map_reply_msg(mapping, local_rloc, remote_rloc, dst_port, nonce, opts); return (err); }
/* * send_map_reply() * * Send a map-reply to a querier. */ void send_map_reply(lispd_pkt_map_request_t *pkt, struct sockaddr_in *source) { lispd_pkt_map_request_eid_prefix_record_t *rec; lispd_pkt_map_request_itr_rloc_t *itr_rloc; lispd_locator_chain_t *loc_chain; lispd_pkt_map_reply_t *reply_pkt; struct ip *iphdr; struct udphdr *udphdr; lisp_addr_t eid_prefix; struct sockaddr_in dst; lispd_if_t *oif = get_primary_interface(); char addr_buf[128]; char *ptr; int offset, i, s, len, nbytes, udp_len; if (!oif) { log_msg(INFO, "No interfaces are available to source reply"); return; } /* * Figure out what they are asking for, need to advance past * all the ITR-RLOCs in the packet. Sigh. */ offset = sizeof(lispd_pkt_map_request_t); if (pkt->source_eid_afi != 0) { if (lisp2inetafi(ntohs(pkt->source_eid_afi)) == AF_INET) { offset += sizeof(struct in_addr); } else { offset += sizeof(struct in6_addr); } } itr_rloc = (lispd_pkt_map_request_itr_rloc_t *)CO(pkt, offset); for (i = 0; i < pkt->additional_itr_rloc_count + 1; i++) { offset += sizeof(lispd_pkt_map_request_itr_rloc_t); if (lisp2inetafi(ntohs(itr_rloc->afi)) == AF_INET) { offset += sizeof(struct in_addr); } else { offset += sizeof(struct in6_addr); } itr_rloc = (lispd_pkt_map_request_itr_rloc_t *)CO(pkt, offset); } rec = (lispd_pkt_map_request_eid_prefix_record_t *)CO(pkt, offset); ptr = CO(rec, sizeof(lispd_pkt_map_request_eid_prefix_record_t)); memcpy(&eid_prefix.address.ip, ptr, sizeof(struct in_addr)); if (lisp2inetafi(ntohs(rec->eid_prefix_afi)) != AF_INET) { log_msg(INFO, " AF: %d unsupported currently.", lisp2inetafi(ntohs(rec->eid_prefix_afi))); return; } log_msg(INFO, " Request for EID: %s/%d", inet_ntop(AF_INET, &eid_prefix.address.ip.s_addr, addr_buf, 128), rec->eid_prefix_mask_length); /* * Lookup in our local database */ if (!lookup_eid_in_db(lisp2inetafi(ntohs(rec->eid_prefix_afi)), eid_prefix.address.ip.s_addr, &loc_chain)) { log_msg(INFO, " Unable to find entry in local database."); return; } else { log_msg(INFO, " Found entry, building reply."); } reply_pkt = build_map_reply(source->sin_addr.s_addr, pkt->rloc_probe, loc_chain, (char *)&pkt->nonce, &len); if (!reply_pkt) { log_msg(INFO, "Failed to build map reply"); return; } /* * Build the outer IP header ourselves, this doesn't * go using LISP, so we don't want the EID used as the source. */ iphdr = (struct ip *)malloc(len + sizeof(struct ip) + sizeof(struct udphdr)); udphdr = (struct udphdr *)CO(iphdr, sizeof(struct ip)); ptr = CO(udphdr, sizeof(struct udphdr)); memcpy(ptr, (char *)reply_pkt, len); free(reply_pkt); udp_len = len + sizeof(struct udphdr); /* * AF_INET for now XXX */ iphdr->ip_hl = 5; iphdr->ip_v = IPVERSION; iphdr->ip_tos = 0; iphdr->ip_len = htons(udp_len + sizeof(struct ip)); iphdr->ip_id = htons(54321); iphdr->ip_off = 0; iphdr->ip_ttl = 255; iphdr->ip_p = IPPROTO_UDP; iphdr->ip_sum = 0; // Raw socket handler does this for us. iphdr->ip_src.s_addr = oif->address.address.ip.s_addr; /// XXX Huh? iphdr->ip_dst.s_addr = source->sin_addr.s_addr; udphdr->source = htons(LISP_CONTROL_PORT); udphdr->dest = source->sin_port; udphdr->len = htons(udp_len); udphdr->check = 0; udphdr->check = udp_checksum(udphdr, udp_len, iphdr, AF_INET); /* XXX: assumes v4 transport */ if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) { log_msg(INFO, "socket (send_map_request): %s", strerror(errno)); return; } memset((char *) &dst, 0, sizeof(dst)); dst.sin_family = AF_INET; /* XXX: assume v4 transport */ dst.sin_addr.s_addr = source->sin_addr.s_addr; if ((nbytes = sendto(s, (const void *)iphdr, len + sizeof(struct ip) + sizeof(struct udphdr), 0, (struct sockaddr *)&dst, sizeof(struct sockaddr))) < 0) { log_msg(INFO, "sendto (send_map_request): %s", strerror(errno)); return; } if (nbytes != (int)(len + sizeof(struct udphdr) + sizeof(struct ip))) { log_msg(INFO, "send_map_request: nbytes (%d) != packet_len (%d)\n", nbytes, len); return; } close(s); free(iphdr); return; }
uint8_t *build_map_request_pkt( lispd_mapping_elt *requested_mapping, lisp_addr_t *src_eid, uint8_t encap, uint8_t probe, uint8_t solicit_map_request,/* boolean really */ uint8_t smr_invoked, int *len, /* return length here */ uint64_t *nonce) /* return nonce here */ { uint8_t *packet = NULL; uint8_t *mr_packet = NULL; lispd_pkt_map_request_t *mrp = NULL; lispd_pkt_mapping_record_t *rec = NULL; lispd_pkt_map_request_itr_rloc_t *itr_rloc = NULL; lispd_pkt_map_request_eid_prefix_record_t *request_eid_record = NULL; uint8_t *cur_ptr = NULL; int map_request_msg_len = 0; int ctr = 0; int cpy_len = 0; int locators_ctr = 0; lispd_mapping_elt *src_mapping = NULL; lispd_locators_list *locators_list[2] = {NULL,NULL}; lispd_locator_elt *locator = NULL; lisp_addr_t *ih_src_ip = NULL; /* * Lookup the local EID prefix from where we generate the message. * src_eid is null for RLOC probing and refreshing map_cache -> Source-EID AFI = 0 */ if (src_eid != NULL){ src_mapping = lookup_eid_in_db(*src_eid); if (!src_mapping){ lispd_log_msg(LISP_LOG_DEBUG_2,"build_map_request_pkt: Source EID address not found in local data base - %s -", get_char_from_lisp_addr_t(*src_eid)); return (NULL); } } /* Calculate the packet size and reserve memory */ map_request_msg_len = get_map_request_length(requested_mapping,src_mapping); *len = map_request_msg_len; if ((packet = malloc(map_request_msg_len)) == NULL){ lispd_log_msg(LISP_LOG_WARNING,"build_map_request_pkt: Unable to allocate memory for Map Request (packet_len): %s", strerror(errno)); return (NULL); } memset(packet, 0, map_request_msg_len); cur_ptr = packet; mrp = (lispd_pkt_map_request_t *)cur_ptr; mrp->type = LISP_MAP_REQUEST; mrp->authoritative = 0; if (src_eid != NULL) mrp->map_data_present = 1; else mrp->map_data_present = 0; if (probe) mrp->rloc_probe = 1; else mrp->rloc_probe = 0; if (solicit_map_request) mrp->solicit_map_request = 1; else mrp->solicit_map_request = 0; if (smr_invoked) mrp->smr_invoked = 1; else mrp->smr_invoked = 0; mrp->additional_itr_rloc_count = 0; /* To be filled later */ mrp->record_count = 1; /* XXX: assume 1 record */ mrp->nonce = build_nonce((unsigned int) time(NULL)); *nonce = mrp->nonce; if (src_eid != NULL){ cur_ptr = pkt_fill_eid(&(mrp->source_eid_afi),src_mapping); /* Add itr-rlocs */ locators_list[0] = src_mapping->head_v4_locators_list; locators_list[1] = src_mapping->head_v6_locators_list; for (ctr=0 ; ctr < 2 ; ctr++){ while (locators_list[ctr]){ locator = locators_list[ctr]->locator; if (*(locator->state)==DOWN){ locators_list[ctr] = locators_list[ctr]->next; continue; } /* Remove ITR locators behind NAT: No control message (4342) can be received in these interfaces */ if (((lcl_locator_extended_info *)locator->extended_info)->rtr_locators_list != NULL){ locators_list[ctr] = locators_list[ctr]->next; continue; } itr_rloc = (lispd_pkt_map_request_itr_rloc_t *)cur_ptr; itr_rloc->afi = htons(get_lisp_afi(locator->locator_addr->afi,NULL)); /* Add rloc address */ cur_ptr = CO(itr_rloc,sizeof(lispd_pkt_map_request_itr_rloc_t)); cpy_len = copy_addr((void *) cur_ptr ,locator->locator_addr, 0); cur_ptr = CO(cur_ptr, cpy_len); locators_ctr ++; locators_list[ctr] = locators_list[ctr]->next; } } }else { // XXX If no source EID is used, then we only use one ITR-RLOC for IPv4 and one for IPv6-> Default control RLOC mrp->source_eid_afi = 0; cur_ptr = CO(mrp, sizeof(lispd_pkt_map_request_t)); if (default_ctrl_iface_v4 != NULL){ itr_rloc = (lispd_pkt_map_request_itr_rloc_t *)cur_ptr; itr_rloc->afi = htons((uint16_t)LISP_AFI_IP); cur_ptr = CO(itr_rloc,sizeof(lispd_pkt_map_request_itr_rloc_t)); cpy_len = copy_addr((void *) cur_ptr ,default_ctrl_iface_v4->ipv4_address, 0); cur_ptr = CO(cur_ptr, cpy_len); locators_ctr ++; } if (default_ctrl_iface_v6 != NULL){ itr_rloc = (lispd_pkt_map_request_itr_rloc_t *)cur_ptr; itr_rloc->afi = htons(get_lisp_afi(AF_INET6,NULL)); cur_ptr = CO(itr_rloc,sizeof(lispd_pkt_map_request_itr_rloc_t)); cpy_len = copy_addr((void *) cur_ptr ,default_ctrl_iface_v6->ipv6_address, 0); cur_ptr = CO(cur_ptr, cpy_len); locators_ctr ++; } } mrp->additional_itr_rloc_count = locators_ctr - 1; /* IRC = 0 --> 1 ITR-RLOC */ if (locators_ctr == 0){ lispd_log_msg(LISP_LOG_DEBUG_2,"build_map_request_pkt: No ITR RLOCs."); free(packet); return (NULL); } /* Requested EID record */ request_eid_record = (lispd_pkt_map_request_eid_prefix_record_t *)cur_ptr; request_eid_record->eid_prefix_length = requested_mapping->eid_prefix_length; cur_ptr = pkt_fill_eid(&(request_eid_record->eid_prefix_afi),requested_mapping); if (mrp->map_data_present == 1){ /* Map-Reply Record */ rec = (lispd_pkt_mapping_record_t *)cur_ptr; if ((pkt_fill_mapping_record(rec, src_mapping, NULL))== NULL) { lispd_log_msg(LISP_LOG_DEBUG_2,"build_map_request_pkt: Couldn't buil map reply record for map request. " "Map Request will not be send"); free(packet); return(NULL); } } /* Add Encapsulated (Inner) control header*/ if (encap){ /* * If no source EID is included (Source-EID-AFI = 0), The default RLOC address is used for * the source address in the inner IP header */ if (src_eid != NULL){ ih_src_ip = &(src_mapping->eid_prefix);; }else{ if (requested_mapping->eid_prefix.afi == AF_INET){ ih_src_ip = get_main_eid (AF_INET); }else{ ih_src_ip = get_main_eid (AF_INET6); } } mr_packet = packet; packet = build_control_encap_pkt(mr_packet, map_request_msg_len, ih_src_ip, &(requested_mapping->eid_prefix), LISP_CONTROL_PORT, LISP_CONTROL_PORT, len); if (packet == NULL){ lispd_log_msg(LISP_LOG_DEBUG_1,"build_map_request_pkt: Couldn't encapsulate the map request"); free (mr_packet); return (NULL); } } return (packet); }