3 Copyright (C) 2000,2001 Ivo Timmermans <itimmermans@bigfoot.com>,
4 2000,2001 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.14 2001/06/21 16:16:32 guus Exp $
26 #include <sys/param.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
31 #include <netinet/if.h>
32 #define ETHER_ADDR_LEN 6
34 #include <net/ethernet.h>
36 #include <netinet/if_ether.h>
44 #include "connection.h"
51 int routing_mode = RMODE_ROUTER;
54 void learn_mac(mac_t *address)
60 subnet = lookup_subnet_mac(address);
62 /* If we don't know this MAC address yet, store it */
64 if(!subnet || subnet->owner!=myself)
66 if(debug_lvl >= DEBUG_TRAFFIC)
67 syslog(LOG_INFO, _("Learned new MAC address %hhx:%hhx:%hhx:%hhx:%hhx:%hhx"),
68 address->x[0], address->x[1], address->x[2], address->x[3], address->x[4], address->x[5]);
70 subnet = new_subnet();
71 subnet->type = SUBNET_MAC;
72 memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
73 subnet_add(myself, subnet);
75 /* And tell all other tinc daemons it's our MAC */
77 for(node = connection_tree->head; node; node = node->next)
79 p = (connection_t *)node->data;
80 if(p->status.meta && p->status.active && p!= myself)
81 send_add_subnet(p, subnet);
86 connection_t *route_mac(vpn_packet_t *packet)
90 /* Learn source address */
92 learn_mac((mac_t *)(&packet->data[6]));
94 /* Lookup destination address */
96 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
104 connection_t *route_ipv4(vpn_packet_t *packet)
109 dest = ntohl(*((unsigned long*)(&packet->data[30])));
111 subnet = lookup_subnet_ipv4(&dest);
115 if(debug_lvl >= DEBUG_TRAFFIC)
117 syslog(LOG_WARNING, _("Cannot route packet: unknown destination address %d.%d.%d.%d"),
118 packet->data[30], packet->data[31], packet->data[32], packet->data[33]);
124 return subnet->owner;
127 connection_t *route_ipv6(vpn_packet_t *packet)
130 if(debug_lvl > DEBUG_NOTHING)
132 syslog(LOG_WARNING, _("Cannot route packet: IPv6 routing not yet implemented"));
138 void route_arp(vpn_packet_t *packet)
140 struct ether_arp *arp;
142 unsigned char ipbuf[4];
145 /* First, snatch the source address from the ARP packet */
147 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
149 /* This routine generates replies to ARP requests.
150 You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
151 Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
154 arp = (struct ether_arp *)(packet->data + 14);
156 /* Check if this is a valid ARP request */
158 if(ntohs(arp->arp_hrd) != ARPHRD_ETHER ||
159 ntohs(arp->arp_pro) != ETHERTYPE_IP ||
160 (int) (arp->arp_hln) != ETHER_ADDR_LEN ||
161 (int) (arp->arp_pln) != 4 ||
162 ntohs(arp->arp_op) != ARPOP_REQUEST )
164 if(debug_lvl > DEBUG_TRAFFIC)
166 syslog(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
171 /* Check if the IP address exists on the VPN */
173 dest = ntohl(*((unsigned long*)(arp->arp_tpa)));
174 subnet = lookup_subnet_ipv4(&dest);
178 if(debug_lvl >= DEBUG_TRAFFIC)
180 syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
181 arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2], arp->arp_tpa[3]);
187 /* Check if it is for our own subnet */
189 if(subnet->owner == myself)
190 return; /* silently ignore */
192 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
193 packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
195 memcpy(ipbuf, arp->arp_tpa, 4); /* save protocol addr */
196 memcpy(arp->arp_tpa, arp->arp_spa, 4); /* swap destination and source protocol address */
197 memcpy(arp->arp_spa, ipbuf, 4); /* ... */
199 memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
200 memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* add fake source hard addr */
201 arp->arp_op = htons(ARPOP_REPLY);
203 accept_packet(packet);
207 void route_outgoing(vpn_packet_t *packet)
209 unsigned short int type;
212 /* FIXME: multicast? */
217 type = ntohs(*((unsigned short*)(&packet->data[12])));
221 cl = route_ipv4(packet);
224 cl = route_ipv6(packet);
230 if(debug_lvl >= DEBUG_TRAFFIC)
232 syslog(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
237 send_packet(cl, packet);
241 cl = route_mac(packet);
243 send_packet(cl, packet);
245 broadcast_packet(myself, packet);
249 broadcast_packet(myself, packet);
254 void route_incoming(connection_t *source, vpn_packet_t *packet)
259 memcpy(packet->data, mymac.net.mac.address.x, 6); /* Override destination address to make the kernel accept it */
260 accept_packet(packet);
266 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
270 if(subnet->owner == myself)
271 accept_packet(packet);
273 send_packet(subnet->owner, packet);
277 broadcast_packet(source, packet);
278 accept_packet(packet);
283 broadcast_packet(source,packet); /* Spread it on */
284 accept_packet(packet);