int vpnapi_control_dp_send_msg(oor_ctrl_t *ctrl, lbuf_t *buff, uconn_t *udp_conn) { int ret; int sock; ip_addr_t *src_addr, *dst_addr; vpnapi_ctr_dplane_data_t * data; data = (vpnapi_ctr_dplane_data_t *)ctrl->control_data_plane->control_dp_data; if (lisp_addr_lafi(&udp_conn->ra) != LM_AFI_IP) { OOR_LOG(LDBG_2, "vpnapi_control_dp_send_msg: Destination address %s of UDP connection is not a IP. " "Discarding!", lisp_addr_to_char(&udp_conn->ra)); return(BAD); } src_addr = lisp_addr_ip(&udp_conn->la); dst_addr = lisp_addr_ip(&udp_conn->ra); if (!lisp_addr_is_no_addr(&udp_conn->la) && (ip_addr_afi(src_addr) != ip_addr_afi(dst_addr))) { OOR_LOG(LDBG_2, "vpnapi_control_dp_send_msg: src %s and dst %s of UDP connection have " "different IP AFI. Discarding!", ip_addr_to_char(src_addr), ip_addr_to_char(dst_addr)); return(BAD); } switch (ip_addr_afi(dst_addr)){ case AF_INET: if (udp_conn->lp == LISP_CONTROL_PORT){ sock = data->ipv4_ctrl_socket; }else{ sock = data->ipv4_data_socket; } break; case AF_INET6: sock = data->ipv6_ctrl_socket; break; default: return (BAD); } ret = send_datagram_packet (sock, lbuf_data(buff), lbuf_size(buff), &udp_conn->ra, udp_conn->rp); if (ret != GOOD) { OOR_LOG(LDBG_1, "Failed to send contrl message from RLOC: %s -> %s", lisp_addr_to_char(&udp_conn->la), lisp_addr_to_char(&udp_conn->ra)); return(BAD); } else { OOR_LOG(LDBG_1, "Sent control message IP: %s -> %s UDP: %d -> %d", lisp_addr_to_char(&udp_conn->la), lisp_addr_to_char(&udp_conn->ra), udp_conn->lp, udp_conn->rp); return(GOOD); } }
int sock_recv(int sfd, lbuf_t *b) { int nread; nread = read(sfd, lbuf_data(b), lbuf_tailroom(b)); if (nread == 0) { LMLOG(LWRN, "sock_recv: recvmsg error: %s", strerror(errno)); return (BAD); } lbuf_set_size(b, lbuf_size(b) + nread); return(GOOD); }
static int vpnapi_output_unicast(lbuf_t *b, packet_tuple_t *tuple) { fwd_info_t *fi; fwd_entry_t *fe; fi = ttable_lookup(&ttable, tuple); if (!fi) { fi = ctrl_get_forwarding_info(tuple); if (!fi){ return (BAD); } fe = fi->fwd_info; if (fe && fe->srloc && fe->drloc) { switch (lisp_addr_ip_afi(fe->srloc)){ case AF_INET: fe->out_sock = &(((vpnapi_data_t *)dplane_vpnapi.datap_data)->ipv4_data_socket); break; case AF_INET6: fe->out_sock = &(((vpnapi_data_t *)dplane_vpnapi.datap_data)->ipv6_data_socket); break; default: LMLOG(LDBG_3,"OUTPUT: No output socket for afi %d", lisp_addr_ip_afi(fe->srloc)); return(BAD); } } ttable_insert(&ttable, pkt_tuple_clone(tuple), fi); }else{ fe = fi->fwd_info; } /* Packets with no/negative map cache entry AND no PETR * OR packets with missing src or dst RLOCs * forward them natively */ if (!fe || !fe->srloc || !fe->drloc) { LMLOG(LDBG_3,"OUTPUT: Packet with non lisp destination. No PeTRs compatibles to be used. Discarding packet"); return(BAD); } LMLOG(LDBG_3,"OUTPUT: Sending encapsulated packet: RLOC %s -> %s\n", lisp_addr_to_char(fe->srloc), lisp_addr_to_char(fe->drloc)); /* push lisp data hdr */ lisp_data_push_hdr(b); return(send_datagram_packet (*(fe->out_sock), lbuf_data(b), lbuf_size(b), fe->drloc, LISP_DATA_PORT)); }
int tun_process_input_packet(sock_t *sl) { uint32_t iid; lbuf_use_stack(&pkt_buf, &pkt_recv_buf, MAX_IP_PKT_LEN); if (tun_read_and_decap_pkt(sl->fd, &pkt_buf, &iid) != GOOD) { return (BAD); } /* XXX Destination packet should be checked it belongs to this xTR */ if ((write(tun_receive_fd, lbuf_l3(&pkt_buf), lbuf_size(&pkt_buf))) < 0) { OOR_LOG(LDBG_2, "lisp_input: write error: %s\n ", strerror(errno)); } return (GOOD); }
struct ip6_hdr * pkt_push_ipv6(lbuf_t *b, struct in6_addr *src, struct in6_addr *dst, int proto) { struct ip6_hdr *ip6h; int len; len = lbuf_size(b); ip6h = lbuf_push_uninit(b, sizeof(struct ip6_hdr)); ip6h->ip6_hops = 255; ip6h->ip6_vfc = (IP6VERSION << 4); ip6h->ip6_nxt = proto; ip6h->ip6_plen = htons(len); memcpy(ip6h->ip6_src.s6_addr, src->s6_addr, sizeof(struct in6_addr)); memcpy(ip6h->ip6_dst.s6_addr, dst->s6_addr, sizeof(struct in6_addr)); return(ip6h); }
/* Process a LISP protocol message sitting on * socket s with address family afi */ int vpnapi_control_dp_recv_msg(sock_t *sl) { uconn_t uc; lbuf_t *b; oor_ctrl_t *ctrl; oor_ctrl_dev_t *dev; ctrl = sl->arg; /* Only one device supported for now */ dev = glist_first_data(ctrl->devices); uc.lp = LISP_CONTROL_PORT; b = lisp_msg_create_buf(); if (sock_ctrl_recv(sl->fd, b, &uc) != GOOD) { OOR_LOG(LDBG_1, "Couldn't retrieve socket information" "for control message! Discarding packet!"); lbuf_del(b); return (BAD); } if (lbuf_size(b) < 4){ OOR_LOG(LDBG_3, "Received a non LISP message in the " "control port! Discarding packet!"); return (BAD); } lbuf_reset_lisp(b); OOR_LOG(LDBG_1, "Received %s, IP: %s -> %s, UDP: %d -> %d", lisp_msg_hdr_to_char(b), lisp_addr_to_char(&uc.ra), lisp_addr_to_char(&uc.la), uc.rp, uc.lp); /* direct call of ctrl device * TODO: check type to decide where to send msg*/ ctrl_dev_recv(dev, b, &uc); lbuf_del(b); return (GOOD); }
void * pkt_push_udp(lbuf_t *b, uint16_t sp, uint16_t dp) { struct udphdr *uh; int udp_len; udp_len = sizeof(struct udphdr) + lbuf_size(b); uh = lbuf_push_uninit(b, sizeof(struct udphdr)); #ifdef BSD uh->uh_sport = htons(port_from); uh->uh_dport = htons(port_dest); uh->uh_ulen = htons(udp_payload_len); uh->uh_sum = 0; #else uh->source = htons(sp); uh->dest = htons(dp); uh->len = htons(udp_len); uh->check = 0; /* to be filled in after IP is pushed */ #endif return(uh); }
struct ip * pkt_push_ipv4(lbuf_t *b, struct in_addr *src, struct in_addr *dst, int proto) { struct ip *iph; iph = lbuf_push_uninit(b, sizeof(struct ip)); /* XXX: assume no other headers */ iph->ip_hl = 5; iph->ip_v = IPVERSION; iph->ip_tos = 0; iph->ip_len = htons(lbuf_size(b)); iph->ip_id = htons(get_IP_ID()); /* Do not fragment flag. See 5.4.1 in LISP RFC (6830) * TODO: decide if we allow fragments in case of control */ iph->ip_off = htons(IP_DF); iph->ip_ttl = 255; iph->ip_p = proto; iph->ip_src.s_addr = src->s_addr; iph->ip_dst.s_addr = dst->s_addr; /* FIXME: ip checksum could be offloaded to NIC*/ /* iph->ip_sum = 0; */ iph->ip_sum = ip_checksum((uint16_t *) iph, sizeof(struct ip)); return(iph); }
int sock_data_recv(int sock, lbuf_t *b, int *afi, uint8_t *ttl, uint8_t *tos) { /* Space for TTL and TOS data */ union control_data { struct cmsghdr cmsg; u_char data[CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(int))]; }; union sockunion su; struct msghdr msg; struct iovec iov[1]; union control_data cmsg; struct cmsghdr *cmsgptr = NULL; int nbytes = 0; iov[0].iov_base = lbuf_data(b); iov[0].iov_len = lbuf_tailroom(b); memset(&msg, 0, sizeof msg); msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_control = &cmsg; msg.msg_controllen = sizeof cmsg; msg.msg_name = &su; msg.msg_namelen = sizeof(union sockunion); nbytes = recvmsg(sock, &msg, 0); if (nbytes == -1) { LMLOG(LWRN, "read_packet: recvmsg error: %s", strerror(errno)); return (BAD); } lbuf_set_size(b, lbuf_size(b) + nbytes); if (su.s4.sin_family == AF_INET) { for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_TTL) { *ttl = *((uint8_t *) CMSG_DATA(cmsgptr)); } if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_TOS) { *tos = *((uint8_t *) CMSG_DATA(cmsgptr)); } } *afi = AF_INET; } else { for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { if (cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_HOPLIMIT) { *ttl = *((uint8_t *) CMSG_DATA(cmsgptr)); } if (cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_TCLASS) { *tos = *((uint8_t *) CMSG_DATA(cmsgptr)); } } *afi = AF_INET6; } return (GOOD); }
/* Get a packet from the socket. It also returns the destination addres and * source port of the packet */ int sock_ctrl_recv(int sock, struct lbuf *buf, uconn_t *uc) { union control_data { struct cmsghdr cmsg; u_char data4[CMSG_SPACE(sizeof(struct in_pktinfo))]; u_char data6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; }; union sockunion su; struct msghdr msg; struct iovec iov[1]; union control_data cmsg; struct cmsghdr *cmsgptr = NULL; int nbytes = 0; iov[0].iov_base = lbuf_data(buf); iov[0].iov_len = lbuf_tailroom(buf); memset(&msg, 0, sizeof msg); msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_control = &cmsg; msg.msg_controllen = sizeof cmsg; msg.msg_name = &su; msg.msg_namelen = sizeof(union sockunion); nbytes = recvmsg(sock, &msg, 0); if (nbytes == -1) { LMLOG(LWRN, "sock_recv_ctrl: recvmsg error: %s", strerror(errno)); return (BAD); } lbuf_set_size(buf, lbuf_size(buf) + nbytes); /* read local address, remote port and remote address */ if (su.s4.sin_family == AF_INET) { for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_PKTINFO) { lisp_addr_ip_init(&uc->la, &(((struct in_pktinfo *) (CMSG_DATA(cmsgptr)))->ipi_addr), AF_INET); break; } } lisp_addr_ip_init(&uc->ra, &su.s4.sin_addr, AF_INET); uc->rp = ntohs(su.s4.sin_port); } else { for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { if (cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_PKTINFO) { lisp_addr_ip_init(&uc->la, &(((struct in6_pktinfo *) (CMSG_DATA(cmsgptr)))->ipi6_addr), AF_INET6); break; } } lisp_addr_ip_init(&uc->ra, &su.s6.sin6_addr, AF_INET6); uc->rp = ntohs(su.s6.sin6_port); } return (GOOD); }