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.38 2002/04/19 14:06:40 guus Exp $
25 #if defined(HAVE_FREEBSD) || defined(HAVE_OPENBSD)
26 #include <sys/param.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #if defined(HAVE_SOLARIS) || defined(HAVE_OPENBSD)
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>
48 #include "connection.h"
56 int routing_mode = RMODE_ROUTER;
57 int priorityinheritance = 0;
61 void learn_mac(mac_t *address)
67 subnet = lookup_subnet_mac(address);
69 /* If we don't know this MAC address yet, store it */
71 if(!subnet || subnet->owner!=myself)
73 if(debug_lvl >= DEBUG_TRAFFIC)
74 syslog(LOG_INFO, _("Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx"),
75 address->x[0], address->x[1], address->x[2], address->x[3], address->x[4], address->x[5]);
77 subnet = new_subnet();
78 subnet->type = SUBNET_MAC;
79 memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
80 subnet_add(myself, subnet);
82 /* And tell all other tinc daemons it's our MAC */
84 for(node = connection_tree->head; node; node = node->next)
86 c = (connection_t *)node->data;
88 send_add_subnet(c, subnet);
92 subnet->net.mac.lastseen = now;
99 avl_node_t *node, *next, *node2;
101 for(node = myself->subnet_tree->head; node; node = next)
104 s = (subnet_t *)node->data;
105 if(s->type == SUBNET_MAC && s->net.mac.lastseen && s->net.mac.lastseen + macexpire < now)
107 if(debug_lvl >= DEBUG_TRAFFIC)
108 syslog(LOG_INFO, _("MAC address %hx:%hx:%hx:%hx:%hx:%hx expired"),
109 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]);
110 for(node2 = connection_tree->head; node2; node2 = node2->next)
112 c = (connection_t *)node2->data;
114 send_del_subnet(c, s);
116 subnet_del(myself, s);
122 node_t *route_mac(vpn_packet_t *packet)
126 /* Learn source address */
128 learn_mac((mac_t *)(&packet->data[6]));
130 /* Lookup destination address */
132 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
135 return subnet->owner;
140 node_t *route_ipv4(vpn_packet_t *packet)
144 if(priorityinheritance)
145 packet->priority = packet->data[15];
147 subnet = lookup_subnet_ipv4((ipv4_t *)&packet->data[30]);
151 if(debug_lvl >= DEBUG_TRAFFIC)
153 syslog(LOG_WARNING, _("Cannot route packet: unknown IPv4 destination address %d.%d.%d.%d"),
154 packet->data[30], packet->data[31], packet->data[32], packet->data[33]);
160 return subnet->owner;
163 node_t *route_ipv6(vpn_packet_t *packet)
167 subnet = lookup_subnet_ipv6((ipv6_t *)&packet->data[38]);
171 if(debug_lvl >= DEBUG_TRAFFIC)
173 syslog(LOG_WARNING, _("Cannot route packet: unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
174 ntohs(*(short unsigned int *)&packet->data[38]),
175 ntohs(*(short unsigned int *)&packet->data[40]),
176 ntohs(*(short unsigned int *)&packet->data[42]),
177 ntohs(*(short unsigned int *)&packet->data[44]),
178 ntohs(*(short unsigned int *)&packet->data[46]),
179 ntohs(*(short unsigned int *)&packet->data[48]),
180 ntohs(*(short unsigned int *)&packet->data[50]),
181 ntohs(*(short unsigned int *)&packet->data[52]));
187 return subnet->owner;
190 unsigned short int inet_checksum(unsigned short int *data, int len, unsigned short int prevsum)
192 unsigned long int checksum = prevsum ^ 0xFFFF;
195 checksum += ntohs(*data++);
197 while(checksum >> 16)
198 checksum = (checksum & 0xFFFF) + (checksum >> 16);
200 return checksum ^ 0xFFFF;
203 void route_neighborsol(vpn_packet_t *packet)
206 struct nd_neighbor_solicit *ns;
207 struct nd_opt_hdr *opt;
209 short unsigned int checksum;
212 struct in6_addr ip6_src; /* source address */
213 struct in6_addr ip6_dst; /* destination address */
219 hdr = (struct ip6_hdr *)(packet->data + 14);
220 ns = (struct nd_neighbor_solicit *)(packet->data + 14 + sizeof(*hdr));
221 opt = (struct nd_opt_hdr *)(packet->data + 14 + sizeof(*hdr) + sizeof(*ns));
223 /* First, snatch the source address from the neighbor solicitation packet */
225 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
227 /* Check if this is a valid neighbor solicitation request */
229 if(ns->nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT ||
230 opt->nd_opt_type != ND_OPT_SOURCE_LINKADDR)
232 if(debug_lvl > DEBUG_TRAFFIC)
234 syslog(LOG_WARNING, _("Cannot route packet: received unknown type neighbor solicitation request"));
239 /* Create pseudo header */
241 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
242 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
243 pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
244 pseudo.junk[0] = pseudo.junk[1] = pseudo.junk[2] = 0;
245 pseudo.junk[3] = IPPROTO_ICMPV6;
247 /* Generate checksum */
249 checksum = inet_checksum((unsigned short int *)&pseudo, sizeof(pseudo)/2, ~0);
250 checksum = inet_checksum((unsigned short int *)ns, sizeof(*ns)/2 + 4, checksum);
254 if(debug_lvl >= DEBUG_TRAFFIC)
255 syslog(LOG_WARNING, _("Cannot route packet: checksum error for neighbor solicitation request"));
259 /* Check if the IPv6 address exists on the VPN */
261 subnet = lookup_subnet_ipv6((ipv6_t *)&ns->nd_ns_target);
265 if(debug_lvl >= DEBUG_TRAFFIC)
267 syslog(LOG_WARNING, _("Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
268 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]),
269 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]));
275 /* Check if it is for our own subnet */
277 if(subnet->owner == myself)
278 return; /* silently ignore */
280 /* Create neighbor advertation reply */
282 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
283 packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
285 memcpy(&hdr->ip6_dst, &hdr->ip6_src, 16); /* swap destination and source protocol address */
286 memcpy(&hdr->ip6_src, &ns->nd_ns_target, 16); /* ... */
288 memcpy((char *)opt + sizeof(*opt), packet->data + ETHER_ADDR_LEN, 6); /* add fake source hard addr */
290 ns->nd_ns_hdr.icmp6_cksum = 0;
291 ns->nd_ns_hdr.icmp6_type = ND_NEIGHBOR_ADVERT;
292 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[0] = 0x40; /* Set solicited flag */
293 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;
294 opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
296 /* Create pseudo header */
298 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
299 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
300 pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
301 pseudo.junk[0] = pseudo.junk[1] = pseudo.junk[2] = 0;
302 pseudo.junk[3] = IPPROTO_ICMPV6;
304 /* Generate checksum */
306 checksum = inet_checksum((unsigned short int *)&pseudo, sizeof(pseudo)/2, ~0);
307 checksum = inet_checksum((unsigned short int *)ns, sizeof(*ns)/2 + 4, checksum);
309 ns->nd_ns_hdr.icmp6_cksum = htons(checksum);
311 write_packet(packet);
315 void route_arp(vpn_packet_t *packet)
317 struct ether_arp *arp;
319 unsigned char ipbuf[4];
321 /* First, snatch the source address from the ARP packet */
323 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
325 /* This routine generates replies to ARP requests.
326 You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
327 Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
330 arp = (struct ether_arp *)(packet->data + 14);
332 /* Check if this is a valid ARP request */
334 if(ntohs(arp->arp_hrd) != ARPHRD_ETHER ||
335 ntohs(arp->arp_pro) != ETHERTYPE_IP ||
336 (int) (arp->arp_hln) != ETHER_ADDR_LEN ||
337 (int) (arp->arp_pln) != 4 ||
338 ntohs(arp->arp_op) != ARPOP_REQUEST )
340 if(debug_lvl > DEBUG_TRAFFIC)
342 syslog(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
347 /* Check if the IPv4 address exists on the VPN */
349 subnet = lookup_subnet_ipv4((ipv4_t *)arp->arp_tpa);
353 if(debug_lvl >= DEBUG_TRAFFIC)
355 syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
356 arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2], arp->arp_tpa[3]);
362 /* Check if it is for our own subnet */
364 if(subnet->owner == myself)
365 return; /* silently ignore */
367 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
368 packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
370 memcpy(ipbuf, arp->arp_tpa, 4); /* save protocol addr */
371 memcpy(arp->arp_tpa, arp->arp_spa, 4); /* swap destination and source protocol address */
372 memcpy(arp->arp_spa, ipbuf, 4); /* ... */
374 memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
375 memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* add fake source hard addr */
376 arp->arp_op = htons(ARPOP_REPLY);
378 write_packet(packet);
382 void route_outgoing(vpn_packet_t *packet)
384 unsigned short int type;
387 /* FIXME: multicast? */
392 type = ntohs(*((unsigned short*)(&packet->data[12])));
396 n = route_ipv4(packet);
399 if(packet->data[20] == IPPROTO_ICMPV6 && packet->data[54] == ND_NEIGHBOR_SOLICIT)
401 route_neighborsol(packet);
404 n = route_ipv6(packet);
410 if(debug_lvl >= DEBUG_TRAFFIC)
412 syslog(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
417 send_packet(n, packet);
421 n = route_mac(packet);
423 send_packet(n, packet);
425 broadcast_packet(myself, packet);
429 broadcast_packet(myself, packet);
434 void route_incoming(node_t *source, vpn_packet_t *packet)
441 unsigned short int type;
443 type = ntohs(*((unsigned short*)(&packet->data[12])));
447 n = route_ipv4(packet);
450 n = route_ipv6(packet);
461 memcpy(packet->data, mymac.net.mac.address.x, 6);
462 write_packet(packet);
465 send_packet(n, packet);
473 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
477 if(subnet->owner == myself)
478 write_packet(packet);
480 send_packet(subnet->owner, packet);
484 broadcast_packet(source, packet);
485 write_packet(packet);
490 broadcast_packet(source, packet); /* Spread it on */
491 write_packet(packet);