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.60 2003/07/18 12:16:24 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 /* Missing definitions */
59 #ifndef ETHER_ADDR_LEN
60 #define ETHER_ADDR_LEN 6
63 #ifndef ICMP_DEST_UNREACH
64 #define ICMP_DEST_UNREACH 3
67 #ifndef ICMP_NET_UNKNOWN
68 #define ICMP_NET_UNKNOWN 6
71 #ifndef ICMP_NET_UNREACH
72 #define ICMP_NET_UNREACH 0
75 int routing_mode = RMODE_ROUTER;
76 int priorityinheritance = 0;
78 int overwrite_mac = 0;
79 mac_t mymac = {{0xFE, 0xFD, 0, 0, 0, 0}};
83 static uint16_t inet_checksum(void *data, int len, uint16_t prevsum)
86 uint32_t checksum = prevsum ^ 0xFFFF;
94 checksum += *(unsigned char *)p;
97 checksum = (checksum & 0xFFFF) + (checksum >> 16);
102 static int ratelimit(void) {
103 static time_t lasttime = 0;
112 static void learn_mac(mac_t *address)
120 subnet = lookup_subnet_mac(address);
122 /* If we don't know this MAC address yet, store it */
124 if(!subnet || subnet->owner != myself) {
125 ifdebug(TRAFFIC) logger(LOG_INFO, _("Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx"),
126 address->x[0], address->x[1], address->x[2], address->x[3],
127 address->x[4], address->x[5]);
129 subnet = new_subnet();
130 subnet->type = SUBNET_MAC;
131 memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
132 subnet_add(myself, subnet);
134 /* And tell all other tinc daemons it's our MAC */
136 for(node = connection_tree->head; node; node = node->next) {
137 c = (connection_t *) node->data;
139 send_add_subnet(c, subnet);
143 subnet->net.mac.lastseen = now;
150 avl_node_t *node, *next, *node2;
154 for(node = myself->subnet_tree->head; node; node = next) {
156 s = (subnet_t *) node->data;
157 if(s->type == SUBNET_MAC && s->net.mac.lastseen && s->net.mac.lastseen + macexpire < now) {
158 ifdebug(TRAFFIC) logger(LOG_INFO, _("MAC address %hx:%hx:%hx:%hx:%hx:%hx expired"),
159 s->net.mac.address.x[0], s->net.mac.address.x[1],
160 s->net.mac.address.x[2], s->net.mac.address.x[3],
161 s->net.mac.address.x[4], s->net.mac.address.x[5]);
163 for(node2 = connection_tree->head; node2; node2 = node2->next) {
164 c = (connection_t *) node2->data;
166 send_del_subnet(c, s);
169 subnet_del(myself, s);
174 static node_t *route_mac(vpn_packet_t *packet)
180 /* Learn source address */
182 learn_mac((mac_t *)(&packet->data[6]));
184 /* Lookup destination address */
186 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
189 return subnet->owner;
196 static void route_ipv4_unreachable(vpn_packet_t *packet, uint8_t code)
201 struct in_addr ip_src;
202 struct in_addr ip_dst;
210 hdr = (struct ip *)(packet->data + 14);
211 icmp = (struct icmp *)(packet->data + 14 + 20);
213 /* Remember original source and destination */
215 memcpy(&ip_src, &hdr->ip_src, 4);
216 memcpy(&ip_dst, &hdr->ip_dst, 4);
217 oldlen = packet->len - 14;
219 if(oldlen >= IP_MSS - sizeof(*hdr) - sizeof(*icmp))
220 oldlen = IP_MSS - sizeof(*hdr) - sizeof(*icmp);
222 /* Copy first part of original contents to ICMP message */
224 memmove(&icmp->icmp_ip, hdr, oldlen);
226 /* Fill in IPv4 header */
229 hdr->ip_hl = sizeof(*hdr) / 4;
231 hdr->ip_len = htons(20 + 8 + oldlen);
235 hdr->ip_p = IPPROTO_ICMP;
237 memcpy(&hdr->ip_src, &ip_dst, 4);
238 memcpy(&hdr->ip_dst, &ip_src, 4);
240 hdr->ip_sum = inet_checksum(hdr, 20, ~0);
242 /* Fill in ICMP header */
244 icmp->icmp_type = ICMP_DEST_UNREACH;
245 icmp->icmp_code = code;
246 icmp->icmp_cksum = 0;
248 icmp->icmp_cksum = inet_checksum(icmp, 8 + oldlen, ~0);
250 packet->len = 14 + 20 + 8 + oldlen;
252 write_packet(packet);
255 static node_t *route_ipv4(vpn_packet_t *packet)
261 if(priorityinheritance)
262 packet->priority = packet->data[15];
264 subnet = lookup_subnet_ipv4((ipv4_t *) & packet->data[30]);
267 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: unknown IPv4 destination address %d.%d.%d.%d"),
268 packet->data[30], packet->data[31], packet->data[32],
271 route_ipv4_unreachable(packet, ICMP_NET_UNKNOWN);
275 if(!subnet->owner->status.reachable)
276 route_ipv4_unreachable(packet, ICMP_NET_UNREACH);
278 return subnet->owner;
283 static void route_ipv6_unreachable(vpn_packet_t *packet, uint8_t code)
286 struct icmp6_hdr *icmp;
290 struct in6_addr ip6_src; /* source address */
291 struct in6_addr ip6_dst; /* destination address */
301 hdr = (struct ip6_hdr *)(packet->data + 14);
302 icmp = (struct icmp6_hdr *)(packet->data + 14 + sizeof(*hdr));
304 /* Remember original source and destination */
306 memcpy(&pseudo.ip6_src, &hdr->ip6_dst, 16);
307 memcpy(&pseudo.ip6_dst, &hdr->ip6_src, 16);
308 pseudo.length = ntohs(hdr->ip6_plen) + sizeof(*hdr);
310 if(pseudo.length >= IP_MSS - sizeof(*hdr) - sizeof(*icmp))
311 pseudo.length = IP_MSS - sizeof(*hdr) - sizeof(*icmp);
313 /* Copy first part of original contents to ICMP message */
315 memmove(((char *)icmp) + sizeof(*icmp), hdr, pseudo.length);
317 /* Fill in IPv6 header */
319 hdr->ip6_flow = htonl(0x60000000UL);
320 hdr->ip6_plen = htons(sizeof(*icmp) + pseudo.length);
321 hdr->ip6_nxt = IPPROTO_ICMPV6;
323 memcpy(&hdr->ip6_dst, &pseudo.ip6_dst, 16);
324 memcpy(&hdr->ip6_src, &pseudo.ip6_src, 16);
326 /* Fill in ICMP header */
328 icmp->icmp6_type = ICMP6_DST_UNREACH;
329 icmp->icmp6_code = code;
330 icmp->icmp6_cksum = 0;
332 /* Create pseudo header */
334 pseudo.length = htonl(sizeof(*icmp) + pseudo.length);
335 pseudo.next = htonl(IPPROTO_ICMPV6);
337 /* Generate checksum */
339 checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
340 checksum = inet_checksum(icmp, ntohl(pseudo.length), checksum);
342 icmp->icmp6_cksum = checksum;
344 packet->len = 14 + sizeof(*hdr) + ntohl(pseudo.length);
346 write_packet(packet);
349 static node_t *route_ipv6(vpn_packet_t *packet)
355 subnet = lookup_subnet_ipv6((ipv6_t *) & packet->data[38]);
358 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
359 ntohs(*(uint16_t *) & packet->data[38]),
360 ntohs(*(uint16_t *) & packet->data[40]),
361 ntohs(*(uint16_t *) & packet->data[42]),
362 ntohs(*(uint16_t *) & packet->data[44]),
363 ntohs(*(uint16_t *) & packet->data[46]),
364 ntohs(*(uint16_t *) & packet->data[48]),
365 ntohs(*(uint16_t *) & packet->data[50]),
366 ntohs(*(uint16_t *) & packet->data[52]));
367 route_ipv6_unreachable(packet, ICMP6_DST_UNREACH_ADDR);
372 if(!subnet->owner->status.reachable)
373 route_ipv6_unreachable(packet, ICMP6_DST_UNREACH_NOROUTE);
375 return subnet->owner;
380 static void route_neighborsol(vpn_packet_t *packet)
383 struct nd_neighbor_solicit *ns;
384 struct nd_opt_hdr *opt;
389 struct in6_addr ip6_src; /* source address */
390 struct in6_addr ip6_dst; /* destination address */
397 hdr = (struct ip6_hdr *)(packet->data + 14);
398 ns = (struct nd_neighbor_solicit *)(packet->data + 14 + sizeof(*hdr));
399 opt = (struct nd_opt_hdr *)(packet->data + 14 + sizeof(*hdr) + sizeof(*ns));
401 /* First, snatch the source address from the neighbor solicitation packet */
404 memcpy(mymac.x, packet->data + 6, 6);
406 /* Check if this is a valid neighbor solicitation request */
408 if(ns->nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT ||
409 opt->nd_opt_type != ND_OPT_SOURCE_LINKADDR) {
410 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: received unknown type neighbor solicitation request"));
414 /* Create pseudo header */
416 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
417 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
418 pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
419 pseudo.next = htonl(IPPROTO_ICMPV6);
421 /* Generate checksum */
423 checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
424 checksum = inet_checksum(ns, sizeof(*ns) + 8, checksum);
427 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: checksum error for neighbor solicitation request"));
431 /* Check if the IPv6 address exists on the VPN */
433 subnet = lookup_subnet_ipv6((ipv6_t *) & ns->nd_ns_target);
436 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
437 ntohs(((uint16_t *) & ns->nd_ns_target)[0]),
438 ntohs(((uint16_t *) & ns->nd_ns_target)[1]),
439 ntohs(((uint16_t *) & ns->nd_ns_target)[2]),
440 ntohs(((uint16_t *) & ns->nd_ns_target)[3]),
441 ntohs(((uint16_t *) & ns->nd_ns_target)[4]),
442 ntohs(((uint16_t *) & ns->nd_ns_target)[5]),
443 ntohs(((uint16_t *) & ns->nd_ns_target)[6]),
444 ntohs(((uint16_t *) & ns->nd_ns_target)[7]));
449 /* Check if it is for our own subnet */
451 if(subnet->owner == myself)
452 return; /* silently ignore */
454 /* Create neighbor advertation reply */
456 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
457 packet->data[ETHER_ADDR_LEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
459 memcpy(&hdr->ip6_dst, &hdr->ip6_src, 16); /* swap destination and source protocol address */
460 memcpy(&hdr->ip6_src, &ns->nd_ns_target, 16); /* ... */
462 memcpy((char *) opt + sizeof(*opt), packet->data + ETHER_ADDR_LEN, 6); /* add fake source hard addr */
464 ns->nd_ns_hdr.icmp6_cksum = 0;
465 ns->nd_ns_hdr.icmp6_type = ND_NEIGHBOR_ADVERT;
466 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[0] = 0x40; /* Set solicited flag */
467 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[1] =
468 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[2] =
469 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[3] = 0;
470 opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
472 /* Create pseudo header */
474 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
475 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
476 pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
477 pseudo.next = htonl(IPPROTO_ICMPV6);
479 /* Generate checksum */
481 checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
482 checksum = inet_checksum(ns, sizeof(*ns) + 8, checksum);
484 ns->nd_ns_hdr.icmp6_cksum = checksum;
486 write_packet(packet);
491 static void route_arp(vpn_packet_t *packet)
493 struct ether_arp *arp;
499 /* First, snatch the source address from the ARP packet */
502 memcpy(mymac.x, packet->data + 6, 6);
504 /* This routine generates replies to ARP requests.
505 You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
506 Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
509 arp = (struct ether_arp *)(packet->data + 14);
511 /* Check if this is a valid ARP request */
513 if(ntohs(arp->arp_hrd) != ARPHRD_ETHER || ntohs(arp->arp_pro) != ETHERTYPE_IP ||
514 arp->arp_hln != ETHER_ADDR_LEN || arp->arp_pln != 4 || ntohs(arp->arp_op) != ARPOP_REQUEST) {
515 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
519 /* Check if the IPv4 address exists on the VPN */
521 subnet = lookup_subnet_ipv4((ipv4_t *) arp->arp_tpa);
524 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
525 arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2],
530 /* Check if it is for our own subnet */
532 if(subnet->owner == myself)
533 return; /* silently ignore */
535 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
536 packet->data[ETHER_ADDR_LEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
538 memcpy(ipbuf, arp->arp_tpa, 4); /* save protocol addr */
539 memcpy(arp->arp_tpa, arp->arp_spa, 4); /* swap destination and source protocol address */
540 memcpy(arp->arp_spa, ipbuf, 4); /* ... */
542 memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
543 memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* add fake source hard addr */
544 arp->arp_op = htons(ARPOP_REPLY);
546 write_packet(packet);
549 void route_outgoing(vpn_packet_t *packet)
556 /* FIXME: multicast? */
558 switch (routing_mode) {
560 type = ntohs(*((uint16_t *)(&packet->data[12])));
563 n = route_ipv4(packet);
567 if(packet->data[20] == IPPROTO_ICMPV6 && packet->data[54] == ND_NEIGHBOR_SOLICIT) {
568 route_neighborsol(packet);
571 n = route_ipv6(packet);
579 ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
583 send_packet(n, packet);
587 n = route_mac(packet);
589 send_packet(n, packet);
591 broadcast_packet(myself, packet);
595 broadcast_packet(myself, packet);
600 void route_incoming(node_t *source, vpn_packet_t *packet)
602 switch (routing_mode) {
608 type = ntohs(*((uint16_t *)(&packet->data[12])));
611 n = route_ipv4(packet);
615 n = route_ipv6(packet);
626 memcpy(packet->data, mymac.x, 6);
627 write_packet(packet);
629 send_packet(n, packet);
638 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
641 if(subnet->owner == myself)
642 write_packet(packet);
644 send_packet(subnet->owner, packet);
646 broadcast_packet(source, packet);
647 write_packet(packet);
653 broadcast_packet(source, packet); /* Spread it on */
654 write_packet(packet);