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.30 2002/03/11 13:14:53 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>
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 void route_neighborsol(vpn_packet_t *packet)
192 struct nd_neighbor_solicit *ns;
193 struct nd_opt_hdr *opt;
196 hdr = (struct ip6_hdr *)(packet->data + 14);
197 ns = (struct nd_neighbor_solicit *)(packet->data + 14 + sizeof(struct ip6_hdr));
198 opt = (struct nd_opt_hdr *)(packet->data + 14 + sizeof(struct ip6_hdr) + sizeof(struct nd_neighbor_solicit));
200 /* First, snatch the source address from the neighbor solicitation packet */
202 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
204 /* Check if this is a valid neighbor solicitation request */
206 if(ns->nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT ||
207 opt->nd_opt_type != ND_OPT_SOURCE_LINKADDR)
209 if(debug_lvl > DEBUG_TRAFFIC)
211 syslog(LOG_WARNING, _("Cannot route packet: received unknown type neighbor solicitation request"));
216 /* Check if the IPv6 address exists on the VPN */
218 subnet = lookup_subnet_ipv6((ipv6_t *)&ns->nd_ns_target);
222 if(debug_lvl >= DEBUG_TRAFFIC)
224 syslog(LOG_WARNING, _("Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
225 ntohs(ns->nd_ns_target.s6_addr16[0]), ntohs(ns->nd_ns_target.s6_addr16[1]), ntohs(ns->nd_ns_target.s6_addr16[2]), ntohs(ns->nd_ns_target.s6_addr16[3]),
226 ntohs(ns->nd_ns_target.s6_addr16[4]), ntohs(ns->nd_ns_target.s6_addr16[5]), ntohs(ns->nd_ns_target.s6_addr16[6]), ntohs(ns->nd_ns_target.s6_addr16[7]));
232 /* Check if it is for our own subnet */
234 if(subnet->owner == myself)
235 return; /* silently ignore */
237 /* Create neighbor advertation reply */
239 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
240 packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
242 memcpy(&hdr->ip6_dst, &hdr->ip6_src, 16); /* swap destination and source protocol address */
243 memcpy(&hdr->ip6_src, &ns->nd_ns_target, 16); /* ... */
245 memcpy((char *)opt + sizeof(*opt), packet->data + ETHER_ADDR_LEN, 6); /* add fake source hard addr */
247 ns->nd_ns_hdr.icmp6_type = ND_NEIGHBOR_ADVERT;
248 opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
250 write_packet(packet);
254 void route_arp(vpn_packet_t *packet)
256 struct ether_arp *arp;
258 unsigned char ipbuf[4];
260 /* First, snatch the source address from the ARP packet */
262 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
264 /* This routine generates replies to ARP requests.
265 You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
266 Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
269 arp = (struct ether_arp *)(packet->data + 14);
271 /* Check if this is a valid ARP request */
273 if(ntohs(arp->arp_hrd) != ARPHRD_ETHER ||
274 ntohs(arp->arp_pro) != ETHERTYPE_IP ||
275 (int) (arp->arp_hln) != ETHER_ADDR_LEN ||
276 (int) (arp->arp_pln) != 4 ||
277 ntohs(arp->arp_op) != ARPOP_REQUEST )
279 if(debug_lvl > DEBUG_TRAFFIC)
281 syslog(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
286 /* Check if the IPv4 address exists on the VPN */
288 subnet = lookup_subnet_ipv4((ipv4_t *)arp->arp_tpa);
292 if(debug_lvl >= DEBUG_TRAFFIC)
294 syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
295 arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2], arp->arp_tpa[3]);
301 /* Check if it is for our own subnet */
303 if(subnet->owner == myself)
304 return; /* silently ignore */
306 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
307 packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
309 memcpy(ipbuf, arp->arp_tpa, 4); /* save protocol addr */
310 memcpy(arp->arp_tpa, arp->arp_spa, 4); /* swap destination and source protocol address */
311 memcpy(arp->arp_spa, ipbuf, 4); /* ... */
313 memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
314 memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* add fake source hard addr */
315 arp->arp_op = htons(ARPOP_REPLY);
317 write_packet(packet);
321 void route_outgoing(vpn_packet_t *packet)
323 unsigned short int type;
326 /* FIXME: multicast? */
331 type = ntohs(*((unsigned short*)(&packet->data[12])));
335 n = route_ipv4(packet);
338 n = route_ipv6(packet);
339 if(!n && packet->data[6] == 0x33 && packet->data[7] == 0x33 && packet->data[8] == 0xff)
341 route_neighborsol(packet);
349 if(debug_lvl >= DEBUG_TRAFFIC)
351 syslog(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
356 send_packet(n, packet);
360 n = route_mac(packet);
362 send_packet(n, packet);
364 broadcast_packet(myself, packet);
368 broadcast_packet(myself, packet);
373 void route_incoming(node_t *source, vpn_packet_t *packet)
380 unsigned short int type;
382 type = ntohs(*((unsigned short*)(&packet->data[12])));
386 n = route_ipv4(packet);
389 n = route_ipv6(packet);
400 memcpy(packet->data, mymac.net.mac.address.x, 6);
401 write_packet(packet);
404 send_packet(n, packet);
412 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
416 if(subnet->owner == myself)
417 write_packet(packet);
419 send_packet(subnet->owner, packet);
423 broadcast_packet(source, packet);
424 write_packet(packet);
429 broadcast_packet(source, packet); /* Spread it on */
430 write_packet(packet);