/* * Send an ICMPv4 packet with the unreach type and the needfrag code * to the node specidied by the remote_addrp parameter. The source * address is the IPv4 address related to the final IPv6 node of the * original packet that caused this ICMPv4 error. */ int icmpsub_send_icmp4_unreach_needfrag(int tun_fd, void *in_pktp, const struct in_addr *local_addrp, const struct in_addr *remote_addrp, int mtu) { assert(in_pktp != NULL); assert(local_addrp != NULL); assert(remote_addrp != NULL); /* Check if we can send this ICMPv4 packet or not. */ if (icmpsub_check_sending_rate()) { warnx("ICMP rate limit over."); return (0); } /* Prepare IPv4 and ICMPv4 headers and fill most of their fields. */ struct ip ip4_hdr; struct icmp icmp4_hdr; if (icmpsub_create_icmp4_unreach_needfrag(&ip4_hdr, &icmp4_hdr, local_addrp, remote_addrp, mtu) == -1) { warnx("ICMP unreach needfrag packet creation failed."); return (-1); } /* Calculate the IPv4 header checksum. */ ip4_hdr.ip_sum = cksum_calc_ip4_header(&ip4_hdr); struct iovec iov[5]; uint32_t af; tun_set_af(&af, AF_INET); iov[0].iov_base = ⁡ iov[0].iov_len = sizeof(uint32_t); iov[1].iov_base = &ip4_hdr; iov[1].iov_len = sizeof(struct ip); iov[2].iov_base = NULL; iov[2].iov_len = 0; iov[3].iov_base = &icmp4_hdr; iov[3].iov_len = ICMP_MINLEN; iov[4].iov_base = in_pktp; iov[4].iov_len = sizeof(struct ip); /* Calculate the ICMPv4 header checksum. */ cksum_calc_ulp(IPPROTO_ICMP, iov); if (writev(tun_fd, iov, 5) == -1) { warn("failed to write ICMP unreach needfrag packet to the tun device."); return (-1); } return (0); }
/* * Send an ICMPv6 packet with the Packet Too Big type to the node * specidied by the remote_addrp parameter. The source address is the * IPv6 address related to the final IPv4 node of the original packet * that caused this ICMPv6 error. */ int icmpsub_send_icmp6_packet_too_big(int tun_fd, void *in_pktp, const struct in6_addr *local_addrp, const struct in6_addr *remote_addrp, int mtu) { assert(in_pktp != NULL); assert(local_addrp != NULL); assert(remote_addrp != NULL); /* Check if we can send this ICMPv6 packet or not. */ if (icmpsub_check_sending_rate()) { warnx("ICMP rate limit over."); return (0); } /* Prepare IPv6 and ICMPv6 headers and fill most of their fields. */ struct ip6_hdr ip6_hdr; struct icmp6_hdr icmp6_hdr; if (icmpsub_create_icmp6_packet_too_big(&ip6_hdr, &icmp6_hdr, local_addrp, remote_addrp, mtu) == -1) { warnx("ICMPv6 packet too big header creation failed."); return (-1); } struct iovec iov[5]; uint32_t af; tun_set_af(&af, AF_INET6); iov[0].iov_base = ⁡ iov[0].iov_len = sizeof(uint32_t); iov[1].iov_base = &ip6_hdr; iov[1].iov_len = sizeof(struct ip6_hdr); iov[2].iov_base = NULL; iov[2].iov_len = 0; iov[3].iov_base = &icmp6_hdr; iov[3].iov_len = sizeof(struct icmp6_hdr); iov[4].iov_base = in_pktp; iov[4].iov_len = sizeof(struct ip6_hdr); /* Calculate the ICMPv6 header checksum. */ cksum_calc_ulp(IPPROTO_ICMPV6, iov); if (writev(tun_fd, iov, 5) == -1) { warn("failed to write ICMPv6 packet too big message to the tun device."); return (-1); } return (0); }
void translate_6to4(struct mapping *st, char *buf, int len){ struct ip6_hdr *ip6 = (struct ip6_hdr *)buf; struct ip ip; struct tun_pi pi; struct iovec iov[3]; memset(&ip, 0, sizeof(struct ip)); ip.ip_v = 4; ip.ip_hl = 5; ip.ip_len = htons(len - sizeof(struct ip6_hdr) + sizeof(struct ip)); ip.ip_id = ip6->ip6_flow; ip.ip_off = htons(IP_DF); ip.ip_ttl = ip6->ip6_hlim; ip.ip_p = ip6->ip6_nxt; ip.ip_src = st->mapped_ipv4_addr; ip.ip_dst = sa46t_extract_6to4_addr(ip6->ip6_dst); if(ip6->ip6_nxt == IPPROTO_FRAGMENT){ /* drop already fragmented packet */ return; } if(ip6->ip6_nxt == IPPROTO_ICMPV6){ ip.ip_p = IPPROTO_ICMP; process_icmpv6_packet(buf + sizeof(struct ip6_hdr), len - sizeof(struct ip6_hdr)); } if(ip6->ip6_nxt == IPPROTO_TCP){ process_tcp_packet(AF_INET, &ip, buf + sizeof(struct ip6_hdr), len - sizeof(struct ip6_hdr)); } if(ip6->ip6_nxt == IPPROTO_UDP){ process_udp_packet(AF_INET, &ip, buf + sizeof(struct ip6_hdr), len - sizeof(struct ip6_hdr)); } ip.ip_sum = 0; ip.ip_sum = ip_checksum((unsigned short *)&ip, sizeof(struct ip)); tun_set_af(&pi, AF_INET); iov[0].iov_base = π iov[0].iov_len = sizeof(pi); iov[1].iov_base = &ip; iov[1].iov_len = sizeof(ip); iov[2].iov_base = buf + sizeof(struct ip6_hdr); iov[2].iov_len = len - sizeof(struct ip6_hdr); send_iovec(iov, 3); }
void translate_4to6(struct mapping *st, char *buf, int len){ struct ip *ip = (struct ip *)buf; struct ip6_hdr ip6; struct tun_pi pi; struct iovec iov[4]; memset(&ip6, 0, sizeof(struct ip6_hdr)); ip6.ip6_vfc = 0x60; ip6.ip6_plen = htons(len - sizeof(struct ip)); ip6.ip6_nxt = ip->ip_p; ip6.ip6_hlim = ip->ip_ttl; ip6.ip6_src = sa46t_map_4to6_addr(sa46t_addr, plane_id, ip->ip_src); ip6.ip6_dst = st->source_ipv6_addr; if((ip->ip_off & htons(IP_MF)) > 0){ /* drop already fragmented packet */ return; } if(sizeof(ip6) + len - sizeof(struct ip) > MTU){ fragment_4to6(&ip6, ip, buf + sizeof(struct ip), len - sizeof(struct ip)); return; } if(ip->ip_p == IPPROTO_ICMP){ ip6.ip6_nxt = IPPROTO_ICMPV6; process_icmp_packet(&ip6, buf + sizeof(struct ip), len - sizeof(struct ip)); } if(ip->ip_p == IPPROTO_TCP){ process_tcp_packet(AF_INET6, &ip6, buf + sizeof(struct ip), len - sizeof(struct ip)); } if(ip->ip_p == IPPROTO_UDP){ process_udp_packet(AF_INET6, &ip6, buf + sizeof(struct ip), len - sizeof(struct ip)); } tun_set_af(&pi, AF_INET6); iov[0].iov_base = π iov[0].iov_len = sizeof(pi); iov[1].iov_base = &ip6; iov[1].iov_len = sizeof(ip6); iov[2].iov_base = buf + sizeof(struct ip); iov[2].iov_len = len - sizeof(struct ip); send_iovec(iov, 3); }