+/* RFC 792 */
+
+static void route_ipv4_unreachable(vpn_packet_t *packet, uint8_t code)
+{
+ struct ip ip;
+ struct icmp icmp;
+
+ struct in_addr ip_src;
+ struct in_addr ip_dst;
+ uint32_t oldlen;
+
+ if(ratelimit(3))
+ return;
+
+ cp();
+
+ /* Copy headers from packet into properly aligned structs on the stack */
+
+ memcpy(&ip, packet->data + ether_size, ip_size);
+ memcpy(&icmp, packet->data + ether_size + ip_size, icmp_size);
+
+ /* Remember original source and destination */
+
+ memcpy(&ip_src, &ip.ip_src, sizeof(ip_src));
+ memcpy(&ip_dst, &ip.ip_dst, sizeof(ip_dst));
+
+ oldlen = packet->len - ether_size;
+
+ if(oldlen >= IP_MSS - ip_size - icmp_size)
+ oldlen = IP_MSS - ip_size - icmp_size;
+
+ /* Copy first part of original contents to ICMP message */
+
+ memmove(packet->data + ether_size + ip_size + icmp_size, packet->data + ether_size, oldlen);
+
+ /* Fill in IPv4 header */
+
+ ip.ip_v = 4;
+ ip.ip_hl = ip_size / 4;
+ ip.ip_tos = 0;
+ ip.ip_len = htons(ip_size + icmp_size + oldlen);
+ ip.ip_id = 0;
+ ip.ip_off = 0;
+ ip.ip_ttl = 255;
+ ip.ip_p = IPPROTO_ICMP;
+ ip.ip_sum = 0;
+ memcpy(&ip.ip_src, &ip_dst, sizeof(ip_src));
+ memcpy(&ip.ip_dst, &ip_src, sizeof(ip_dst));
+
+ ip.ip_sum = inet_checksum(&ip, ip_size, ~0);
+
+ /* Fill in ICMP header */
+
+ icmp.icmp_type = ICMP_DEST_UNREACH;
+ icmp.icmp_code = code;
+ icmp.icmp_cksum = 0;
+
+ icmp.icmp_cksum = inet_checksum(&icmp, icmp_size, ~0);
+ icmp.icmp_cksum = inet_checksum(packet->data + ether_size + ip_size + icmp_size, oldlen, icmp.icmp_cksum);
+
+ /* Copy structs on stack back to packet */
+
+ memcpy(packet->data + ether_size, &ip, ip_size);
+ memcpy(packet->data + ether_size + ip_size, &icmp, icmp_size);
+
+ packet->len = ether_size + ip_size + icmp_size + oldlen;
+
+ write_packet(packet);
+}
+
+static node_t *route_ipv4(vpn_packet_t *packet)