3 Copyright (C) 2000-2002 Ivo Timmermans <itimmermans@bigfoot.com>,
4 2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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.39 2002/06/05 00:25:55 guus Exp $
25 #if defined(HAVE_FREEBSD) || defined(HAVE_OPENBSD) || defined(HAVE_NETBSD)
26 #include <sys/param.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #if defined(HAVE_SOLARIS) || defined(HAVE_OPENBSD) || defined(HAVE_NETBSD)
32 #define ETHER_ADDR_LEN 6
34 #include <net/ethernet.h>
36 #include <netinet/ip6.h>
37 #include <netinet/icmp6.h>
38 #include <netinet/if_ether.h>
50 #include "connection.h"
58 int routing_mode = RMODE_ROUTER;
59 int priorityinheritance = 0;
63 void learn_mac(mac_t *address)
69 subnet = lookup_subnet_mac(address);
71 /* If we don't know this MAC address yet, store it */
73 if(!subnet || subnet->owner!=myself)
75 if(debug_lvl >= DEBUG_TRAFFIC)
76 syslog(LOG_INFO, _("Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx"),
77 address->x[0], address->x[1], address->x[2], address->x[3], address->x[4], address->x[5]);
79 subnet = new_subnet();
80 subnet->type = SUBNET_MAC;
81 memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
82 subnet_add(myself, subnet);
84 /* And tell all other tinc daemons it's our MAC */
86 for(node = connection_tree->head; node; node = node->next)
88 c = (connection_t *)node->data;
90 send_add_subnet(c, subnet);
94 subnet->net.mac.lastseen = now;
101 avl_node_t *node, *next, *node2;
103 for(node = myself->subnet_tree->head; node; node = next)
106 s = (subnet_t *)node->data;
107 if(s->type == SUBNET_MAC && s->net.mac.lastseen && s->net.mac.lastseen + macexpire < now)
109 if(debug_lvl >= DEBUG_TRAFFIC)
110 syslog(LOG_INFO, _("MAC address %hx:%hx:%hx:%hx:%hx:%hx expired"),
111 s->net.mac.address.x[0], s->net.mac.address.x[1], s->net.mac.address.x[2], s->net.mac.address.x[3], s->net.mac.address.x[4], s->net.mac.address.x[5]);
112 for(node2 = connection_tree->head; node2; node2 = node2->next)
114 c = (connection_t *)node2->data;
116 send_del_subnet(c, s);
118 subnet_del(myself, s);
124 node_t *route_mac(vpn_packet_t *packet)
128 /* Learn source address */
130 learn_mac((mac_t *)(&packet->data[6]));
132 /* Lookup destination address */
134 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
137 return subnet->owner;
142 node_t *route_ipv4(vpn_packet_t *packet)
146 if(priorityinheritance)
147 packet->priority = packet->data[15];
149 subnet = lookup_subnet_ipv4((ipv4_t *)&packet->data[30]);
153 if(debug_lvl >= DEBUG_TRAFFIC)
155 syslog(LOG_WARNING, _("Cannot route packet: unknown IPv4 destination address %d.%d.%d.%d"),
156 packet->data[30], packet->data[31], packet->data[32], packet->data[33]);
162 return subnet->owner;
165 node_t *route_ipv6(vpn_packet_t *packet)
169 subnet = lookup_subnet_ipv6((ipv6_t *)&packet->data[38]);
173 if(debug_lvl >= DEBUG_TRAFFIC)
175 syslog(LOG_WARNING, _("Cannot route packet: unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
176 ntohs(*(short unsigned int *)&packet->data[38]),
177 ntohs(*(short unsigned int *)&packet->data[40]),
178 ntohs(*(short unsigned int *)&packet->data[42]),
179 ntohs(*(short unsigned int *)&packet->data[44]),
180 ntohs(*(short unsigned int *)&packet->data[46]),
181 ntohs(*(short unsigned int *)&packet->data[48]),
182 ntohs(*(short unsigned int *)&packet->data[50]),
183 ntohs(*(short unsigned int *)&packet->data[52]));
189 return subnet->owner;
192 unsigned short int inet_checksum(unsigned short int *data, int len, unsigned short int prevsum)
194 unsigned long int checksum = prevsum ^ 0xFFFF;
197 checksum += ntohs(*data++);
199 while(checksum >> 16)
200 checksum = (checksum & 0xFFFF) + (checksum >> 16);
202 return checksum ^ 0xFFFF;
205 void route_neighborsol(vpn_packet_t *packet)
208 struct nd_neighbor_solicit *ns;
209 struct nd_opt_hdr *opt;
211 short unsigned int checksum;
214 struct in6_addr ip6_src; /* source address */
215 struct in6_addr ip6_dst; /* destination address */
221 hdr = (struct ip6_hdr *)(packet->data + 14);
222 ns = (struct nd_neighbor_solicit *)(packet->data + 14 + sizeof(*hdr));
223 opt = (struct nd_opt_hdr *)(packet->data + 14 + sizeof(*hdr) + sizeof(*ns));
225 /* First, snatch the source address from the neighbor solicitation packet */
227 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
229 /* Check if this is a valid neighbor solicitation request */
231 if(ns->nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT ||
232 opt->nd_opt_type != ND_OPT_SOURCE_LINKADDR)
234 if(debug_lvl > DEBUG_TRAFFIC)
236 syslog(LOG_WARNING, _("Cannot route packet: received unknown type neighbor solicitation request"));
241 /* Create pseudo header */
243 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
244 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
245 pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
246 pseudo.junk[0] = pseudo.junk[1] = pseudo.junk[2] = 0;
247 pseudo.junk[3] = IPPROTO_ICMPV6;
249 /* Generate checksum */
251 checksum = inet_checksum((unsigned short int *)&pseudo, sizeof(pseudo)/2, ~0);
252 checksum = inet_checksum((unsigned short int *)ns, sizeof(*ns)/2 + 4, checksum);
256 if(debug_lvl >= DEBUG_TRAFFIC)
257 syslog(LOG_WARNING, _("Cannot route packet: checksum error for neighbor solicitation request"));
261 /* Check if the IPv6 address exists on the VPN */
263 subnet = lookup_subnet_ipv6((ipv6_t *)&ns->nd_ns_target);
267 if(debug_lvl >= DEBUG_TRAFFIC)
269 syslog(LOG_WARNING, _("Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
270 ntohs(((uint16_t *)&ns->nd_ns_target)[0]), ntohs(((uint16_t *)&ns->nd_ns_target)[1]), ntohs(((uint16_t *)&ns->nd_ns_target)[2]), ntohs(((uint16_t *)&ns->nd_ns_target)[3]),
271 ntohs(((uint16_t *)&ns->nd_ns_target)[4]), ntohs(((uint16_t *)&ns->nd_ns_target)[5]), ntohs(((uint16_t *)&ns->nd_ns_target)[6]), ntohs(((uint16_t *)&ns->nd_ns_target)[7]));
277 /* Check if it is for our own subnet */
279 if(subnet->owner == myself)
280 return; /* silently ignore */
282 /* Create neighbor advertation reply */
284 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
285 packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
287 memcpy(&hdr->ip6_dst, &hdr->ip6_src, 16); /* swap destination and source protocol address */
288 memcpy(&hdr->ip6_src, &ns->nd_ns_target, 16); /* ... */
290 memcpy((char *)opt + sizeof(*opt), packet->data + ETHER_ADDR_LEN, 6); /* add fake source hard addr */
292 ns->nd_ns_hdr.icmp6_cksum = 0;
293 ns->nd_ns_hdr.icmp6_type = ND_NEIGHBOR_ADVERT;
294 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[0] = 0x40; /* Set solicited flag */
295 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[1] = ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[2] = ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[3] = 0;
296 opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
298 /* Create pseudo header */
300 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
301 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
302 pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
303 pseudo.junk[0] = pseudo.junk[1] = pseudo.junk[2] = 0;
304 pseudo.junk[3] = IPPROTO_ICMPV6;
306 /* Generate checksum */
308 checksum = inet_checksum((unsigned short int *)&pseudo, sizeof(pseudo)/2, ~0);
309 checksum = inet_checksum((unsigned short int *)ns, sizeof(*ns)/2 + 4, checksum);
311 ns->nd_ns_hdr.icmp6_cksum = htons(checksum);
313 write_packet(packet);
317 void route_arp(vpn_packet_t *packet)
319 struct ether_arp *arp;
321 unsigned char ipbuf[4];
323 /* First, snatch the source address from the ARP packet */
325 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
327 /* This routine generates replies to ARP requests.
328 You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
329 Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
332 arp = (struct ether_arp *)(packet->data + 14);
334 /* Check if this is a valid ARP request */
336 if(ntohs(arp->arp_hrd) != ARPHRD_ETHER ||
337 ntohs(arp->arp_pro) != ETHERTYPE_IP ||
338 (int) (arp->arp_hln) != ETHER_ADDR_LEN ||
339 (int) (arp->arp_pln) != 4 ||
340 ntohs(arp->arp_op) != ARPOP_REQUEST )
342 if(debug_lvl > DEBUG_TRAFFIC)
344 syslog(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
349 /* Check if the IPv4 address exists on the VPN */
351 subnet = lookup_subnet_ipv4((ipv4_t *)arp->arp_tpa);
355 if(debug_lvl >= DEBUG_TRAFFIC)
357 syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
358 arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2], arp->arp_tpa[3]);
364 /* Check if it is for our own subnet */
366 if(subnet->owner == myself)
367 return; /* silently ignore */
369 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
370 packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
372 memcpy(ipbuf, arp->arp_tpa, 4); /* save protocol addr */
373 memcpy(arp->arp_tpa, arp->arp_spa, 4); /* swap destination and source protocol address */
374 memcpy(arp->arp_spa, ipbuf, 4); /* ... */
376 memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
377 memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* add fake source hard addr */
378 arp->arp_op = htons(ARPOP_REPLY);
380 write_packet(packet);
384 void route_outgoing(vpn_packet_t *packet)
386 unsigned short int type;
389 /* FIXME: multicast? */
394 type = ntohs(*((unsigned short*)(&packet->data[12])));
398 n = route_ipv4(packet);
401 if(packet->data[20] == IPPROTO_ICMPV6 && packet->data[54] == ND_NEIGHBOR_SOLICIT)
403 route_neighborsol(packet);
406 n = route_ipv6(packet);
412 if(debug_lvl >= DEBUG_TRAFFIC)
414 syslog(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
419 send_packet(n, packet);
423 n = route_mac(packet);
425 send_packet(n, packet);
427 broadcast_packet(myself, packet);
431 broadcast_packet(myself, packet);
436 void route_incoming(node_t *source, vpn_packet_t *packet)
443 unsigned short int type;
445 type = ntohs(*((unsigned short*)(&packet->data[12])));
449 n = route_ipv4(packet);
452 n = route_ipv6(packet);
463 memcpy(packet->data, mymac.net.mac.address.x, 6);
464 write_packet(packet);
467 send_packet(n, packet);
475 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
479 if(subnet->owner == myself)
480 write_packet(packet);
482 send_packet(subnet->owner, packet);
486 broadcast_packet(source, packet);
487 write_packet(packet);
492 broadcast_packet(source, packet); /* Spread it on */
493 write_packet(packet);