3 Copyright (C) 2000-2003 Ivo Timmermans <ivo@o2w.nl>,
4 2000-2003 Guus Sliepen <guus@sliepen.eu.org>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 $Id: route.c,v 1.1.2.62 2003/07/22 20:55:20 guus Exp $
25 #ifdef HAVE_NET_ETHERNET_H
26 #include <net/ethernet.h>
28 #ifdef HAVE_NET_IF_ARP_H
29 #include <net/if_arp.h>
31 #ifdef HAVE_NETINET_IP_ICMP_H
32 #include <netinet/ip_icmp.h>
34 #ifdef HAVE_NETINET_IP6_H
35 #include <netinet/ip6.h>
37 #ifdef HAVE_NETINET_ICMP6_H
38 #include <netinet/icmp6.h>
40 #ifdef HAVE_NETINET_IF_ETHER_H
41 #include <netinet/if_ether.h>
45 #include "connection.h"
57 rmode_t routing_mode = RMODE_ROUTER;
58 bool priorityinheritance = false;
60 bool overwrite_mac = false;
61 mac_t mymac = {{0xFE, 0xFD, 0, 0, 0, 0}};
65 static uint16_t inet_checksum(void *data, int len, uint16_t prevsum)
68 uint32_t checksum = prevsum ^ 0xFFFF;
76 checksum += *(unsigned char *)p;
79 checksum = (checksum & 0xFFFF) + (checksum >> 16);
84 static bool ratelimit(void) {
85 static time_t lasttime = 0;
94 static void learn_mac(mac_t *address)
102 subnet = lookup_subnet_mac(address);
104 /* If we don't know this MAC address yet, store it */
106 if(!subnet || subnet->owner != myself) {
107 ifdebug(TRAFFIC) logger(LOG_INFO, _("Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx"),
108 address->x[0], address->x[1], address->x[2], address->x[3],
109 address->x[4], address->x[5]);
111 subnet = new_subnet();
112 subnet->type = SUBNET_MAC;
113 memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
114 subnet_add(myself, subnet);
116 /* And tell all other tinc daemons it's our MAC */
118 for(node = connection_tree->head; node; node = node->next) {
119 c = (connection_t *) node->data;
121 send_add_subnet(c, subnet);
125 subnet->net.mac.lastseen = now;
132 avl_node_t *node, *next, *node2;
136 for(node = myself->subnet_tree->head; node; node = next) {
138 s = (subnet_t *) node->data;
139 if(s->type == SUBNET_MAC && s->net.mac.lastseen && s->net.mac.lastseen + macexpire < now) {
140 ifdebug(TRAFFIC) logger(LOG_INFO, _("MAC address %hx:%hx:%hx:%hx:%hx:%hx expired"),
141 s->net.mac.address.x[0], s->net.mac.address.x[1],
142 s->net.mac.address.x[2], s->net.mac.address.x[3],
143 s->net.mac.address.x[4], s->net.mac.address.x[5]);
145 for(node2 = connection_tree->head; node2; node2 = node2->next) {
146 c = (connection_t *) node2->data;
148 send_del_subnet(c, s);
151 subnet_del(myself, s);
156 static node_t *route_mac(vpn_packet_t *packet)
162 /* Learn source address */
164 learn_mac((mac_t *)(&packet->data[6]));
166 /* Lookup destination address */
168 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
171 return subnet->owner;
178 static void route_ipv4_unreachable(vpn_packet_t *packet, uint8_t code)
183 struct in_addr ip_src;
184 struct in_addr ip_dst;
192 hdr = (struct ip *)(packet->data + 14);
193 icmp = (struct icmp *)(packet->data + 14 + 20);
195 /* Remember original source and destination */
197 memcpy(&ip_src, &hdr->ip_src, 4);
198 memcpy(&ip_dst, &hdr->ip_dst, 4);
199 oldlen = packet->len - 14;
201 if(oldlen >= IP_MSS - sizeof(*hdr) - sizeof(*icmp))
202 oldlen = IP_MSS - sizeof(*hdr) - sizeof(*icmp);
204 /* Copy first part of original contents to ICMP message */
206 memmove(&icmp->icmp_ip, hdr, oldlen);
208 /* Fill in IPv4 header */
211 hdr->ip_hl = sizeof(*hdr) / 4;
213 hdr->ip_len = htons(20 + 8 + oldlen);
217 hdr->ip_p = IPPROTO_ICMP;
219 memcpy(&hdr->ip_src, &ip_dst, 4);
220 memcpy(&hdr->ip_dst, &ip_src, 4);
222 hdr->ip_sum = inet_checksum(hdr, 20, ~0);
224 /* Fill in ICMP header */
226 icmp->icmp_type = ICMP_DEST_UNREACH;
227 icmp->icmp_code = code;
228 icmp->icmp_cksum = 0;
230 icmp->icmp_cksum = inet_checksum(icmp, 8 + oldlen, ~0);
232 packet->len = 14 + 20 + 8 + oldlen;
234 write_packet(packet);
237 static node_t *route_ipv4(vpn_packet_t *packet)
243 if(priorityinheritance)
244 packet->priority = packet->data[15];
246 subnet = lookup_subnet_ipv4((ipv4_t *) & packet->data[30]);
249 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: unknown IPv4 destination address %d.%d.%d.%d"),
250 packet->data[30], packet->data[31], packet->data[32],
253 route_ipv4_unreachable(packet, ICMP_NET_UNKNOWN);
257 if(!subnet->owner->status.reachable)
258 route_ipv4_unreachable(packet, ICMP_NET_UNREACH);
260 return subnet->owner;
265 static void route_ipv6_unreachable(vpn_packet_t *packet, uint8_t code)
268 struct icmp6_hdr *icmp;
272 struct in6_addr ip6_src; /* source address */
273 struct in6_addr ip6_dst; /* destination address */
283 hdr = (struct ip6_hdr *)(packet->data + 14);
284 icmp = (struct icmp6_hdr *)(packet->data + 14 + sizeof(*hdr));
286 /* Remember original source and destination */
288 memcpy(&pseudo.ip6_src, &hdr->ip6_dst, 16);
289 memcpy(&pseudo.ip6_dst, &hdr->ip6_src, 16);
290 pseudo.length = ntohs(hdr->ip6_plen) + sizeof(*hdr);
292 if(pseudo.length >= IP_MSS - sizeof(*hdr) - sizeof(*icmp))
293 pseudo.length = IP_MSS - sizeof(*hdr) - sizeof(*icmp);
295 /* Copy first part of original contents to ICMP message */
297 memmove(((char *)icmp) + sizeof(*icmp), hdr, pseudo.length);
299 /* Fill in IPv6 header */
301 hdr->ip6_flow = htonl(0x60000000UL);
302 hdr->ip6_plen = htons(sizeof(*icmp) + pseudo.length);
303 hdr->ip6_nxt = IPPROTO_ICMPV6;
305 memcpy(&hdr->ip6_dst, &pseudo.ip6_dst, 16);
306 memcpy(&hdr->ip6_src, &pseudo.ip6_src, 16);
308 /* Fill in ICMP header */
310 icmp->icmp6_type = ICMP6_DST_UNREACH;
311 icmp->icmp6_code = code;
312 icmp->icmp6_cksum = 0;
314 /* Create pseudo header */
316 pseudo.length = htonl(sizeof(*icmp) + pseudo.length);
317 pseudo.next = htonl(IPPROTO_ICMPV6);
319 /* Generate checksum */
321 checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
322 checksum = inet_checksum(icmp, ntohl(pseudo.length), checksum);
324 icmp->icmp6_cksum = checksum;
326 packet->len = 14 + sizeof(*hdr) + ntohl(pseudo.length);
328 write_packet(packet);
331 static node_t *route_ipv6(vpn_packet_t *packet)
337 subnet = lookup_subnet_ipv6((ipv6_t *) & packet->data[38]);
340 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
341 ntohs(*(uint16_t *) & packet->data[38]),
342 ntohs(*(uint16_t *) & packet->data[40]),
343 ntohs(*(uint16_t *) & packet->data[42]),
344 ntohs(*(uint16_t *) & packet->data[44]),
345 ntohs(*(uint16_t *) & packet->data[46]),
346 ntohs(*(uint16_t *) & packet->data[48]),
347 ntohs(*(uint16_t *) & packet->data[50]),
348 ntohs(*(uint16_t *) & packet->data[52]));
349 route_ipv6_unreachable(packet, ICMP6_DST_UNREACH_ADDR);
354 if(!subnet->owner->status.reachable)
355 route_ipv6_unreachable(packet, ICMP6_DST_UNREACH_NOROUTE);
357 return subnet->owner;
362 static void route_neighborsol(vpn_packet_t *packet)
365 struct nd_neighbor_solicit *ns;
366 struct nd_opt_hdr *opt;
371 struct in6_addr ip6_src; /* source address */
372 struct in6_addr ip6_dst; /* destination address */
379 hdr = (struct ip6_hdr *)(packet->data + 14);
380 ns = (struct nd_neighbor_solicit *)(packet->data + 14 + sizeof(*hdr));
381 opt = (struct nd_opt_hdr *)(packet->data + 14 + sizeof(*hdr) + sizeof(*ns));
383 /* First, snatch the source address from the neighbor solicitation packet */
386 memcpy(mymac.x, packet->data + 6, 6);
388 /* Check if this is a valid neighbor solicitation request */
390 if(ns->nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT ||
391 opt->nd_opt_type != ND_OPT_SOURCE_LINKADDR) {
392 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: received unknown type neighbor solicitation request"));
396 /* Create pseudo header */
398 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
399 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
400 pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
401 pseudo.next = htonl(IPPROTO_ICMPV6);
403 /* Generate checksum */
405 checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
406 checksum = inet_checksum(ns, sizeof(*ns) + 8, checksum);
409 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: checksum error for neighbor solicitation request"));
413 /* Check if the IPv6 address exists on the VPN */
415 subnet = lookup_subnet_ipv6((ipv6_t *) & ns->nd_ns_target);
418 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
419 ntohs(((uint16_t *) & ns->nd_ns_target)[0]),
420 ntohs(((uint16_t *) & ns->nd_ns_target)[1]),
421 ntohs(((uint16_t *) & ns->nd_ns_target)[2]),
422 ntohs(((uint16_t *) & ns->nd_ns_target)[3]),
423 ntohs(((uint16_t *) & ns->nd_ns_target)[4]),
424 ntohs(((uint16_t *) & ns->nd_ns_target)[5]),
425 ntohs(((uint16_t *) & ns->nd_ns_target)[6]),
426 ntohs(((uint16_t *) & ns->nd_ns_target)[7]));
431 /* Check if it is for our own subnet */
433 if(subnet->owner == myself)
434 return; /* silently ignore */
436 /* Create neighbor advertation reply */
438 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
439 packet->data[ETHER_ADDR_LEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
441 memcpy(&hdr->ip6_dst, &hdr->ip6_src, 16); /* swap destination and source protocol address */
442 memcpy(&hdr->ip6_src, &ns->nd_ns_target, 16); /* ... */
444 memcpy((char *) opt + sizeof(*opt), packet->data + ETHER_ADDR_LEN, 6); /* add fake source hard addr */
446 ns->nd_ns_hdr.icmp6_cksum = 0;
447 ns->nd_ns_hdr.icmp6_type = ND_NEIGHBOR_ADVERT;
448 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[0] = 0x40; /* Set solicited flag */
449 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[1] =
450 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[2] =
451 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[3] = 0;
452 opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
454 /* Create pseudo header */
456 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
457 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
458 pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
459 pseudo.next = htonl(IPPROTO_ICMPV6);
461 /* Generate checksum */
463 checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
464 checksum = inet_checksum(ns, sizeof(*ns) + 8, checksum);
466 ns->nd_ns_hdr.icmp6_cksum = checksum;
468 write_packet(packet);
473 static void route_arp(vpn_packet_t *packet)
475 struct ether_arp *arp;
481 /* First, snatch the source address from the ARP packet */
484 memcpy(mymac.x, packet->data + 6, 6);
486 /* This routine generates replies to ARP requests.
487 You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
488 Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
491 arp = (struct ether_arp *)(packet->data + 14);
493 /* Check if this is a valid ARP request */
495 if(ntohs(arp->arp_hrd) != ARPHRD_ETHER || ntohs(arp->arp_pro) != ETHERTYPE_IP ||
496 arp->arp_hln != ETHER_ADDR_LEN || arp->arp_pln != 4 || ntohs(arp->arp_op) != ARPOP_REQUEST) {
497 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
501 /* Check if the IPv4 address exists on the VPN */
503 subnet = lookup_subnet_ipv4((ipv4_t *) arp->arp_tpa);
506 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
507 arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2],
512 /* Check if it is for our own subnet */
514 if(subnet->owner == myself)
515 return; /* silently ignore */
517 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
518 packet->data[ETHER_ADDR_LEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
520 memcpy(ipbuf, arp->arp_tpa, 4); /* save protocol addr */
521 memcpy(arp->arp_tpa, arp->arp_spa, 4); /* swap destination and source protocol address */
522 memcpy(arp->arp_spa, ipbuf, 4); /* ... */
524 memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
525 memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* add fake source hard addr */
526 arp->arp_op = htons(ARPOP_REPLY);
528 write_packet(packet);
531 void route_outgoing(vpn_packet_t *packet)
538 /* FIXME: multicast? */
540 switch (routing_mode) {
542 type = ntohs(*((uint16_t *)(&packet->data[12])));
545 n = route_ipv4(packet);
549 if(packet->data[20] == IPPROTO_ICMPV6 && packet->data[54] == ND_NEIGHBOR_SOLICIT) {
550 route_neighborsol(packet);
553 n = route_ipv6(packet);
561 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
565 send_packet(n, packet);
569 n = route_mac(packet);
571 send_packet(n, packet);
573 broadcast_packet(myself, packet);
577 broadcast_packet(myself, packet);
582 void route_incoming(node_t *source, vpn_packet_t *packet)
584 switch (routing_mode) {
590 type = ntohs(*((uint16_t *)(&packet->data[12])));
593 n = route_ipv4(packet);
597 n = route_ipv6(packet);
608 memcpy(packet->data, mymac.x, 6);
609 write_packet(packet);
611 send_packet(n, packet);
620 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
623 if(subnet->owner == myself)
624 write_packet(packet);
626 send_packet(subnet->owner, packet);
628 broadcast_packet(source, packet);
629 write_packet(packet);
635 broadcast_packet(source, packet); /* Spread it on */
636 write_packet(packet);