3 Copyright (C) 2000-2002 Ivo Timmermans <ivo@o2w.nl>,
4 2000-2002 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.47 2003/03/29 21:51:21 guus Exp $
25 #ifdef HAVE_SYS_PARAM_H
26 #include <sys/param.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
33 #ifdef HAVE_NET_ETHERNET_H
34 #include <net/ethernet.h>
36 #ifdef HAVE_NETINET_IN_SYSTM_H
37 #include <netinet/in_systm.h>
39 #include <netinet/ip.h>
40 #include <netinet/ip_icmp.h>
41 #include <netinet/ip6.h>
42 #include <netinet/icmp6.h>
43 #include <netinet/if_ether.h>
48 #ifdef HAVE_INTTYPES_H
55 #include "connection.h"
63 #ifndef ETHER_ADDR_LEN
64 #define ETHER_ADDR_LEN 6
67 int routing_mode = RMODE_ROUTER;
68 int priorityinheritance = 0;
74 uint16_t inet_checksum(void *data, int len, uint16_t prevsum)
77 uint32_t checksum = prevsum ^ 0xFFFF;
85 checksum = (checksum & 0xFFFF) + (checksum >> 16);
91 static time_t lasttime = 0;
100 void learn_mac(mac_t *address)
108 subnet = lookup_subnet_mac(address);
110 /* If we don't know this MAC address yet, store it */
112 if(!subnet || subnet->owner != myself) {
113 if(debug_lvl >= DEBUG_TRAFFIC)
114 syslog(LOG_INFO, _("Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx"),
115 address->x[0], address->x[1], address->x[2], address->x[3],
116 address->x[4], address->x[5]);
118 subnet = new_subnet();
119 subnet->type = SUBNET_MAC;
120 memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
121 subnet_add(myself, subnet);
123 /* And tell all other tinc daemons it's our MAC */
125 for(node = connection_tree->head; node; node = node->next) {
126 c = (connection_t *) node->data;
128 send_add_subnet(c, subnet);
132 subnet->net.mac.lastseen = now;
139 avl_node_t *node, *next, *node2;
143 for(node = myself->subnet_tree->head; node; node = next) {
145 s = (subnet_t *) node->data;
146 if(s->type == SUBNET_MAC && s->net.mac.lastseen && s->net.mac.lastseen + macexpire < now) {
147 if(debug_lvl >= DEBUG_TRAFFIC)
148 syslog(LOG_INFO, _("MAC address %hx:%hx:%hx:%hx:%hx:%hx expired"),
149 s->net.mac.address.x[0], s->net.mac.address.x[1],
150 s->net.mac.address.x[2], s->net.mac.address.x[3],
151 s->net.mac.address.x[4], s->net.mac.address.x[5]);
153 for(node2 = connection_tree->head; node2; node2 = node2->next) {
154 c = (connection_t *) node2->data;
156 send_del_subnet(c, s);
159 subnet_del(myself, s);
164 node_t *route_mac(vpn_packet_t *packet)
170 /* Learn source address */
172 learn_mac((mac_t *)(&packet->data[6]));
174 /* Lookup destination address */
176 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
179 return subnet->owner;
186 void route_ipv4_unreachable(vpn_packet_t *packet, uint8_t code)
191 struct in_addr ip_src;
192 struct in_addr ip_dst;
200 hdr = (struct ip *)(packet->data + 14);
201 icmp = (struct icmp *)(packet->data + 14 + 20);
203 /* Remember original source and destination */
205 memcpy(&ip_src, &hdr->ip_src, 4);
206 memcpy(&ip_dst, &hdr->ip_dst, 4);
207 oldlen = packet->len - 14;
209 if(oldlen >= IP_MSS - sizeof(*hdr) - sizeof(struct icmphdr))
210 oldlen = IP_MSS - sizeof(*hdr) - sizeof(struct icmphdr);
212 /* Copy first part of original contents to ICMP message */
214 memmove(&icmp->icmp_ip, hdr, oldlen);
216 /* Fill in IPv4 header */
219 hdr->ip_hl = sizeof(*hdr) / 4;
221 hdr->ip_len = htons(20 + 8 + oldlen);
225 hdr->ip_p = IPPROTO_ICMP;
227 memcpy(&hdr->ip_src, &ip_dst, 4);
228 memcpy(&hdr->ip_dst, &ip_src, 4);
230 hdr->ip_sum = inet_checksum(hdr, 20, ~0);
232 /* Fill in ICMP header */
234 icmp->icmp_type = ICMP_DEST_UNREACH;
235 icmp->icmp_code = code;
236 icmp->icmp_cksum = 0;
238 icmp->icmp_cksum = inet_checksum(icmp, 8 + oldlen, ~0);
240 packet->len = 14 + 20 + 8 + oldlen;
242 write_packet(packet);
245 node_t *route_ipv4(vpn_packet_t *packet)
251 if(priorityinheritance)
252 packet->priority = packet->data[15];
254 subnet = lookup_subnet_ipv4((ipv4_t *) & packet->data[30]);
257 if(debug_lvl >= DEBUG_TRAFFIC) {
258 syslog(LOG_WARNING, _("Cannot route packet: unknown IPv4 destination address %d.%d.%d.%d"),
259 packet->data[30], packet->data[31], packet->data[32],
263 route_ipv4_unreachable(packet, ICMP_NET_UNKNOWN);
267 if(!subnet->owner->status.reachable)
268 route_ipv4_unreachable(packet, ICMP_NET_UNREACH);
270 return subnet->owner;
275 void route_ipv6_unreachable(vpn_packet_t *packet, uint8_t code)
278 struct icmp6_hdr *icmp;
282 struct in6_addr ip6_src; /* source address */
283 struct in6_addr ip6_dst; /* destination address */
293 hdr = (struct ip6_hdr *)(packet->data + 14);
294 icmp = (struct icmp6_hdr *)(packet->data + 14 + sizeof(*hdr));
296 /* Remember original source and destination */
298 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
299 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
300 pseudo.length = ntohs(hdr->ip6_plen) + sizeof(*hdr);
302 if(pseudo.length >= IP_MSS - sizeof(*hdr) - sizeof(*icmp))
303 pseudo.length = IP_MSS - sizeof(*hdr) - sizeof(*icmp);
305 /* Copy first part of original contents to ICMP message */
307 memmove(((char *)icmp) + sizeof(*icmp), hdr, pseudo.length);
309 /* Fill in IPv6 header */
311 hdr->ip6_flow = htonl(0x60000000UL);
312 hdr->ip6_plen = htons(sizeof(*icmp) + pseudo.length);
313 hdr->ip6_nxt = IPPROTO_ICMPV6;
315 memcpy(&hdr->ip6_dst, &pseudo.ip6_src, 16);
316 memcpy(&hdr->ip6_src, &pseudo.ip6_dst, 16);
318 /* Fill in ICMP header */
320 icmp->icmp6_type = ICMP6_DST_UNREACH;
321 icmp->icmp6_code = code;
322 icmp->icmp6_cksum = 0;
324 /* Create pseudo header */
326 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
327 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
328 pseudo.length = htonl(sizeof(*icmp) + pseudo.length);
329 pseudo.next = htonl(IPPROTO_ICMPV6);
331 /* Generate checksum */
333 checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
334 checksum = inet_checksum(icmp, ntohl(pseudo.length), checksum);
336 icmp->icmp6_cksum = checksum;
338 packet->len = 14 + sizeof(*hdr) + ntohl(pseudo.length);
340 write_packet(packet);
343 node_t *route_ipv6(vpn_packet_t *packet)
349 subnet = lookup_subnet_ipv6((ipv6_t *) & packet->data[38]);
352 if(debug_lvl >= DEBUG_TRAFFIC) {
353 syslog(LOG_WARNING, _("Cannot route packet: unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
354 ntohs(*(uint16_t *) & packet->data[38]),
355 ntohs(*(uint16_t *) & packet->data[40]),
356 ntohs(*(uint16_t *) & packet->data[42]),
357 ntohs(*(uint16_t *) & packet->data[44]),
358 ntohs(*(uint16_t *) & packet->data[46]),
359 ntohs(*(uint16_t *) & packet->data[48]),
360 ntohs(*(uint16_t *) & packet->data[50]),
361 ntohs(*(uint16_t *) & packet->data[52]));
363 route_ipv6_unreachable(packet, ICMP6_DST_UNREACH_ADDR);
368 if(!subnet->owner->status.reachable)
369 route_ipv6_unreachable(packet, ICMP6_DST_UNREACH_NOROUTE);
371 return subnet->owner;
376 void route_neighborsol(vpn_packet_t *packet)
379 struct nd_neighbor_solicit *ns;
380 struct nd_opt_hdr *opt;
385 struct in6_addr ip6_src; /* source address */
386 struct in6_addr ip6_dst; /* destination address */
393 hdr = (struct ip6_hdr *)(packet->data + 14);
394 ns = (struct nd_neighbor_solicit *)(packet->data + 14 + sizeof(*hdr));
395 opt = (struct nd_opt_hdr *)(packet->data + 14 + sizeof(*hdr) + sizeof(*ns));
397 /* First, snatch the source address from the neighbor solicitation packet */
399 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
401 /* Check if this is a valid neighbor solicitation request */
403 if(ns->nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT ||
404 opt->nd_opt_type != ND_OPT_SOURCE_LINKADDR) {
405 if(debug_lvl > DEBUG_TRAFFIC) {
406 syslog(LOG_WARNING, _("Cannot route packet: received unknown type neighbor solicitation request"));
411 /* Create pseudo header */
413 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
414 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
415 pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
416 pseudo.next = htonl(IPPROTO_ICMPV6);
418 /* Generate checksum */
420 checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
421 checksum = inet_checksum(ns, sizeof(*ns) + 8, checksum);
424 if(debug_lvl >= DEBUG_TRAFFIC)
425 syslog(LOG_WARNING, _("Cannot route packet: checksum error for neighbor solicitation request"));
429 /* Check if the IPv6 address exists on the VPN */
431 subnet = lookup_subnet_ipv6((ipv6_t *) & ns->nd_ns_target);
434 if(debug_lvl >= DEBUG_TRAFFIC) {
435 syslog(LOG_WARNING, _("Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
436 ntohs(((uint16_t *) & ns->nd_ns_target)[0]),
437 ntohs(((uint16_t *) & ns->nd_ns_target)[1]),
438 ntohs(((uint16_t *) & ns->nd_ns_target)[2]),
439 ntohs(((uint16_t *) & ns->nd_ns_target)[3]),
440 ntohs(((uint16_t *) & ns->nd_ns_target)[4]),
441 ntohs(((uint16_t *) & ns->nd_ns_target)[5]),
442 ntohs(((uint16_t *) & ns->nd_ns_target)[6]),
443 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 void route_arp(vpn_packet_t *packet)
493 struct ether_arp *arp;
499 /* First, snatch the source address from the ARP packet */
501 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
503 /* This routine generates replies to ARP requests.
504 You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
505 Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
508 arp = (struct ether_arp *)(packet->data + 14);
510 /* Check if this is a valid ARP request */
512 if(ntohs(arp->arp_hrd) != ARPHRD_ETHER || ntohs(arp->arp_pro) != ETHERTYPE_IP ||
513 arp->arp_hln != ETHER_ADDR_LEN || arp->arp_pln != 4 || ntohs(arp->arp_op) != ARPOP_REQUEST) {
514 if(debug_lvl > DEBUG_TRAFFIC) {
515 syslog(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
520 /* Check if the IPv4 address exists on the VPN */
522 subnet = lookup_subnet_ipv4((ipv4_t *) arp->arp_tpa);
525 if(debug_lvl >= DEBUG_TRAFFIC) {
526 syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
527 arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2],
534 /* Check if it is for our own subnet */
536 if(subnet->owner == myself)
537 return; /* silently ignore */
539 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
540 packet->data[ETHER_ADDR_LEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
542 memcpy(ipbuf, arp->arp_tpa, 4); /* save protocol addr */
543 memcpy(arp->arp_tpa, arp->arp_spa, 4); /* swap destination and source protocol address */
544 memcpy(arp->arp_spa, ipbuf, 4); /* ... */
546 memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
547 memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* add fake source hard addr */
548 arp->arp_op = htons(ARPOP_REPLY);
550 write_packet(packet);
553 void route_outgoing(vpn_packet_t *packet)
560 /* FIXME: multicast? */
562 switch (routing_mode) {
564 type = ntohs(*((uint16_t *)(&packet->data[12])));
567 n = route_ipv4(packet);
571 if(packet->data[20] == IPPROTO_ICMPV6 && packet->data[54] == ND_NEIGHBOR_SOLICIT) {
572 route_neighborsol(packet);
575 n = route_ipv6(packet);
583 if(debug_lvl >= DEBUG_TRAFFIC)
584 syslog(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
588 send_packet(n, packet);
592 n = route_mac(packet);
594 send_packet(n, packet);
596 broadcast_packet(myself, packet);
600 broadcast_packet(myself, packet);
605 void route_incoming(node_t *source, vpn_packet_t *packet)
607 switch (routing_mode) {
613 type = ntohs(*((uint16_t *)(&packet->data[12])));
616 n = route_ipv4(packet);
620 n = route_ipv6(packet);
630 memcpy(packet->data, mymac.net.mac.address.x, 6);
631 write_packet(packet);
633 send_packet(n, packet);
642 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
645 if(subnet->owner == myself)
646 write_packet(packet);
648 send_packet(subnet->owner, packet);
650 broadcast_packet(source, packet);
651 write_packet(packet);
657 broadcast_packet(source, packet); /* Spread it on */
658 write_packet(packet);