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.2 2002/04/09 15:26:01 zarq 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>
47 #include "connection.h"
55 int routing_mode = RMODE_ROUTER;
56 int priorityinheritance = 0;
60 void learn_mac(mac_t *address)
66 subnet = lookup_subnet_mac(address);
68 /* If we don't know this MAC address yet, store it */
70 if(!subnet || subnet->owner!=myself)
72 if(debug_lvl >= DEBUG_TRAFFIC)
73 syslog(LOG_INFO, _("Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx"),
74 address->x[0], address->x[1], address->x[2], address->x[3], address->x[4], address->x[5]);
76 subnet = new_subnet();
77 subnet->type = SUBNET_MAC;
78 memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
79 subnet_add(myself, subnet);
81 /* And tell all other tinc daemons it's our MAC */
83 for(node = connection_tree->head; node; node = node->next)
85 c = (connection_t *)node->data;
87 send_add_subnet(c, subnet);
91 subnet->net.mac.lastseen = now;
98 avl_node_t *node, *next, *node2;
100 for(node = myself->subnet_tree->head; node; node = next)
103 s = (subnet_t *)node->data;
104 if(s->type == SUBNET_MAC && s->net.mac.lastseen && s->net.mac.lastseen + macexpire < now)
106 if(debug_lvl >= DEBUG_TRAFFIC)
107 syslog(LOG_INFO, _("MAC address %hx:%hx:%hx:%hx:%hx:%hx expired"),
108 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]);
109 for(node2 = connection_tree->head; node2; node2 = node2->next)
111 c = (connection_t *)node2->data;
113 send_del_subnet(c, s);
115 subnet_del(myself, s);
121 node_t *route_mac(vpn_packet_t *packet)
125 /* Learn source address */
127 learn_mac((mac_t *)(&packet->data[6]));
129 /* Lookup destination address */
131 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
134 return subnet->owner;
139 node_t *route_ipv4(vpn_packet_t *packet)
143 if(priorityinheritance)
144 packet->priority = packet->data[15];
146 subnet = lookup_subnet_ipv4((ipv4_t *)&packet->data[30]);
150 if(debug_lvl >= DEBUG_TRAFFIC)
152 syslog(LOG_WARNING, _("Cannot route packet: unknown IPv4 destination address %d.%d.%d.%d"),
153 packet->data[30], packet->data[31], packet->data[32], packet->data[33]);
159 return subnet->owner;
162 node_t *route_ipv6(vpn_packet_t *packet)
166 subnet = lookup_subnet_ipv6((ipv6_t *)&packet->data[38]);
170 if(debug_lvl >= DEBUG_TRAFFIC)
172 syslog(LOG_WARNING, _("Cannot route packet: unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
173 ntohs(*(short unsigned int *)&packet->data[38]),
174 ntohs(*(short unsigned int *)&packet->data[40]),
175 ntohs(*(short unsigned int *)&packet->data[42]),
176 ntohs(*(short unsigned int *)&packet->data[44]),
177 ntohs(*(short unsigned int *)&packet->data[46]),
178 ntohs(*(short unsigned int *)&packet->data[48]),
179 ntohs(*(short unsigned int *)&packet->data[50]),
180 ntohs(*(short unsigned int *)&packet->data[52]));
186 return subnet->owner;
189 unsigned short int inet_checksum(unsigned short int *data, int len, unsigned short int prevsum)
191 unsigned long int checksum = prevsum ^ 0xFFFF;
194 checksum += ntohs(*data++);
196 while(checksum >> 16)
197 checksum = (checksum & 0xFFFF) + (checksum >> 16);
199 return checksum ^ 0xFFFF;
202 void route_neighborsol(vpn_packet_t *packet)
205 struct nd_neighbor_solicit *ns;
206 struct nd_opt_hdr *opt;
208 short unsigned int checksum;
211 struct in6_addr ip6_src; /* source address */
212 struct in6_addr ip6_dst; /* destination address */
218 hdr = (struct ip6_hdr *)(packet->data + 14);
219 ns = (struct nd_neighbor_solicit *)(packet->data + 14 + sizeof(*hdr));
220 opt = (struct nd_opt_hdr *)(packet->data + 14 + sizeof(*hdr) + sizeof(*ns));
222 /* First, snatch the source address from the neighbor solicitation packet */
224 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
226 /* Check if this is a valid neighbor solicitation request */
228 if(ns->nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT ||
229 opt->nd_opt_type != ND_OPT_SOURCE_LINKADDR)
231 if(debug_lvl > DEBUG_TRAFFIC)
233 syslog(LOG_WARNING, _("Cannot route packet: received unknown type neighbor solicitation request"));
238 /* Create pseudo header */
240 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
241 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
242 pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
243 pseudo.junk[0] = pseudo.junk[1] = pseudo.junk[2] = 0;
244 pseudo.junk[3] = IPPROTO_ICMPV6;
246 /* Generate checksum */
248 checksum = inet_checksum((unsigned short int *)&pseudo, sizeof(pseudo)/2, ~0);
249 checksum = inet_checksum((unsigned short int *)ns, sizeof(*ns)/2 + 4, checksum);
253 if(debug_lvl >= DEBUG_TRAFFIC)
254 syslog(LOG_WARNING, _("Cannot route packet: checksum error for neighbor solicitation request"));
258 /* Check if the IPv6 address exists on the VPN */
260 subnet = lookup_subnet_ipv6((ipv6_t *)&ns->nd_ns_target);
264 if(debug_lvl >= DEBUG_TRAFFIC)
266 syslog(LOG_WARNING, _("Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
267 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]),
268 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]));
274 /* Check if it is for our own subnet */
276 if(subnet->owner == myself)
277 return; /* silently ignore */
279 /* Create neighbor advertation reply */
281 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
282 packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
284 memcpy(&hdr->ip6_dst, &hdr->ip6_src, 16); /* swap destination and source protocol address */
285 memcpy(&hdr->ip6_src, &ns->nd_ns_target, 16); /* ... */
287 memcpy((char *)opt + sizeof(*opt), packet->data + ETHER_ADDR_LEN, 6); /* add fake source hard addr */
289 ns->nd_ns_hdr.icmp6_cksum = 0;
290 ns->nd_ns_hdr.icmp6_type = ND_NEIGHBOR_ADVERT;
291 ns->nd_ns_hdr.icmp6_dataun.icmp6_un_data8[0] = 0x40; /* Set solicited flag */
292 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;
293 opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
295 /* Create pseudo header */
297 memcpy(&pseudo.ip6_src, &hdr->ip6_src, 16);
298 memcpy(&pseudo.ip6_dst, &hdr->ip6_dst, 16);
299 pseudo.length = htonl(sizeof(*ns) + sizeof(*opt) + 6);
300 pseudo.junk[0] = pseudo.junk[1] = pseudo.junk[2] = 0;
301 pseudo.junk[3] = IPPROTO_ICMPV6;
303 /* Generate checksum */
305 checksum = inet_checksum((unsigned short int *)&pseudo, sizeof(pseudo)/2, ~0);
306 checksum = inet_checksum((unsigned short int *)ns, sizeof(*ns)/2 + 4, checksum);
308 ns->nd_ns_hdr.icmp6_cksum = htons(checksum);
310 write_packet(packet);
314 void route_arp(vpn_packet_t *packet)
316 struct ether_arp *arp;
318 unsigned char ipbuf[4];
320 /* First, snatch the source address from the ARP packet */
322 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
324 /* This routine generates replies to ARP requests.
325 You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
326 Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
329 arp = (struct ether_arp *)(packet->data + 14);
331 /* Check if this is a valid ARP request */
333 if(ntohs(arp->arp_hrd) != ARPHRD_ETHER ||
334 ntohs(arp->arp_pro) != ETHERTYPE_IP ||
335 (int) (arp->arp_hln) != ETHER_ADDR_LEN ||
336 (int) (arp->arp_pln) != 4 ||
337 ntohs(arp->arp_op) != ARPOP_REQUEST )
339 if(debug_lvl > DEBUG_TRAFFIC)
341 syslog(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
346 /* Check if the IPv4 address exists on the VPN */
348 subnet = lookup_subnet_ipv4((ipv4_t *)arp->arp_tpa);
352 if(debug_lvl >= DEBUG_TRAFFIC)
354 syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
355 arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2], arp->arp_tpa[3]);
361 /* Check if it is for our own subnet */
363 if(subnet->owner == myself)
364 return; /* silently ignore */
366 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
367 packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
369 memcpy(ipbuf, arp->arp_tpa, 4); /* save protocol addr */
370 memcpy(arp->arp_tpa, arp->arp_spa, 4); /* swap destination and source protocol address */
371 memcpy(arp->arp_spa, ipbuf, 4); /* ... */
373 memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
374 memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* add fake source hard addr */
375 arp->arp_op = htons(ARPOP_REPLY);
377 write_packet(packet);
381 void route_outgoing(vpn_packet_t *packet)
383 unsigned short int type;
386 /* FIXME: multicast? */
391 type = ntohs(*((unsigned short*)(&packet->data[12])));
395 n = route_ipv4(packet);
398 if(packet->data[20] == IPPROTO_ICMPV6 && packet->data[54] == ND_NEIGHBOR_SOLICIT)
400 route_neighborsol(packet);
403 n = route_ipv6(packet);
409 if(debug_lvl >= DEBUG_TRAFFIC)
411 syslog(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
416 send_packet(n, packet);
420 n = route_mac(packet);
422 send_packet(n, packet);
424 broadcast_packet(myself, packet);
428 broadcast_packet(myself, packet);
433 void route_incoming(node_t *source, vpn_packet_t *packet)
440 unsigned short int type;
442 type = ntohs(*((unsigned short*)(&packet->data[12])));
446 n = route_ipv4(packet);
449 n = route_ipv6(packet);
460 memcpy(packet->data, mymac.net.mac.address.x, 6);
461 write_packet(packet);
464 send_packet(n, packet);
472 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
476 if(subnet->owner == myself)
477 write_packet(packet);
479 send_packet(subnet->owner, packet);
483 broadcast_packet(source, packet);
484 write_packet(packet);
489 broadcast_packet(source, packet); /* Spread it on */
490 write_packet(packet);