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.13 2001/06/06 19:12:38 guus Exp $
26 #include <sys/param.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <net/ethernet.h>
31 #include <netinet/if_ether.h>
39 #include "net/ethernet.h"
40 #include "netinet/if_ether.h"
41 #include "connection.h"
48 int routing_mode = RMODE_ROUTER;
51 void learn_mac(mac_t *address)
57 subnet = lookup_subnet_mac(address);
59 /* If we don't know this MAC address yet, store it */
61 if(!subnet || subnet->owner!=myself)
63 if(debug_lvl >= DEBUG_TRAFFIC)
64 syslog(LOG_INFO, _("Learned new MAC address %hhx:%hhx:%hhx:%hhx:%hhx:%hhx"),
65 address->x[0], address->x[1], address->x[2], address->x[3], address->x[4], address->x[5]);
67 subnet = new_subnet();
68 subnet->type = SUBNET_MAC;
69 memcpy(&subnet->net.mac.address, address, sizeof(mac_t));
70 subnet_add(myself, subnet);
72 /* And tell all other tinc daemons it's our MAC */
74 for(node = connection_tree->head; node; node = node->next)
76 p = (connection_t *)node->data;
77 if(p->status.meta && p->status.active && p!= myself)
78 send_add_subnet(p, subnet);
83 connection_t *route_mac(vpn_packet_t *packet)
87 /* Learn source address */
89 learn_mac((mac_t *)(&packet->data[6]));
91 /* Lookup destination address */
93 subnet = lookup_subnet_mac((mac_t *)(&packet->data[0]));
101 connection_t *route_ipv4(vpn_packet_t *packet)
106 dest = ntohl(*((unsigned long*)(&packet->data[30])));
108 subnet = lookup_subnet_ipv4(&dest);
112 if(debug_lvl >= DEBUG_TRAFFIC)
114 syslog(LOG_WARNING, _("Cannot route packet: unknown destination address %d.%d.%d.%d"),
115 packet->data[30], packet->data[31], packet->data[32], packet->data[33]);
121 return subnet->owner;
124 connection_t *route_ipv6(vpn_packet_t *packet)
127 if(debug_lvl > DEBUG_NOTHING)
129 syslog(LOG_WARNING, _("Cannot route packet: IPv6 routing not yet implemented"));
135 void route_arp(vpn_packet_t *packet)
137 struct ether_arp *arp;
139 unsigned char ipbuf[4];
142 /* First, snatch the source address from the ARP packet */
144 memcpy(mymac.net.mac.address.x, packet->data + 6, 6);
146 /* This routine generates replies to ARP requests.
147 You don't need to set NOARP flag on the interface anymore (which is broken on FreeBSD).
148 Most of the code here is taken from choparp.c by Takamichi Tateoka (tree@mma.club.uec.ac.jp)
151 arp = (struct ether_arp *)(packet->data + 14);
153 /* Check if this is a valid ARP request */
155 if(ntohs(arp->arp_hrd) != ARPHRD_ETHER ||
156 ntohs(arp->arp_pro) != ETHERTYPE_IP ||
157 (int) (arp->arp_hln) != ETHER_ADDR_LEN ||
158 (int) (arp->arp_pln) != 4 ||
159 ntohs(arp->arp_op) != ARPOP_REQUEST )
161 if(debug_lvl > DEBUG_TRAFFIC)
163 syslog(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
168 /* Check if the IP address exists on the VPN */
170 dest = ntohl(*((unsigned long*)(arp->arp_tpa)));
171 subnet = lookup_subnet_ipv4(&dest);
175 if(debug_lvl >= DEBUG_TRAFFIC)
177 syslog(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
178 arp->arp_tpa[0], arp->arp_tpa[1], arp->arp_tpa[2], arp->arp_tpa[3]);
184 /* Check if it is for our own subnet */
186 if(subnet->owner == myself)
187 return; /* silently ignore */
189 memcpy(packet->data, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* copy destination address */
190 packet->data[ETHER_ADDR_LEN*2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
192 memcpy(ipbuf, arp->arp_tpa, 4); /* save protocol addr */
193 memcpy(arp->arp_tpa, arp->arp_spa, 4); /* swap destination and source protocol address */
194 memcpy(arp->arp_spa, ipbuf, 4); /* ... */
196 memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
197 memcpy(arp->arp_sha, packet->data + ETHER_ADDR_LEN, ETHER_ADDR_LEN); /* add fake source hard addr */
198 arp->arp_op = htons(ARPOP_REPLY);
200 accept_packet(packet);
204 void route_outgoing(vpn_packet_t *packet)
206 unsigned short int type;
209 /* FIXME: multicast? */
214 type = ntohs(*((unsigned short*)(&packet->data[12])));
218 cl = route_ipv4(packet);
221 cl = route_ipv6(packet);
227 if(debug_lvl >= DEBUG_TRAFFIC)
229 syslog(LOG_WARNING, _("Cannot route packet: unknown type %hx"), type);
234 send_packet(cl, packet);
238 cl = route_mac(packet);
240 send_packet(cl, packet);
242 broadcast_packet(myself, packet);
246 broadcast_packet(myself, packet);
251 void route_incoming(connection_t *source, vpn_packet_t *packet)
256 memcpy(packet->data, mymac.net.mac.address.x, 6); /* Override destination address to make the kernel accept it */
259 if(packet->data[0] & 0x01) /* Broadcast? */
260 broadcast_packet(source, packet); /* If yes, spread it on */
263 broadcast_packet(source,packet); /* Spread it on */
267 accept_packet(packet);