minidlna support now Samsung TV C550/C650 (thx amir909)
[tomato.git] / release / src / router / openvpn / mroute.c
blob9d8fa664feff6e0fb49603517b7c7272a938a938
1 /*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single TCP/UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
8 * Copyright (C) 2002-2009 OpenVPN Technologies, Inc. <sales@openvpn.net>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program (see the file COPYING included with this
21 * distribution); if not, write to the Free Software Foundation, Inc.,
22 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "syshead.h"
27 #if P2MP_SERVER
29 #include "mroute.h"
30 #include "proto.h"
31 #include "error.h"
32 #include "socket.h"
34 #include "memdbg.h"
36 void
37 mroute_addr_init (struct mroute_addr *addr)
39 CLEAR (*addr);
43 * Ethernet multicast addresses.
46 static inline bool
47 is_mac_mcast_addr (const uint8_t *mac)
49 return (bool) mac[0] & 1;
52 static inline bool
53 is_mac_mcast_maddr (const struct mroute_addr *addr)
55 return (addr->type & MR_ADDR_MASK) == MR_ADDR_ETHER && is_mac_mcast_addr (addr->addr);
59 * Don't learn certain addresses.
61 bool
62 mroute_learnable_address (const struct mroute_addr *addr)
64 int i;
65 bool not_all_zeros = false;
66 bool not_all_ones = false;
68 for (i = 0; i < addr->len; ++i)
70 int b = addr->addr[i];
71 if (b != 0x00)
72 not_all_zeros = true;
73 if (b != 0xFF)
74 not_all_ones = true;
76 return not_all_zeros && not_all_ones && !is_mac_mcast_maddr (addr);
79 static inline void
80 mroute_get_in_addr_t (struct mroute_addr *ma, const in_addr_t src, unsigned int mask)
82 if (ma)
84 ma->type = MR_ADDR_IPV4 | mask;
85 ma->netbits = 0;
86 ma->len = 4;
87 *(in_addr_t*)ma->addr = src;
91 static inline bool
92 mroute_is_mcast (const in_addr_t addr)
94 return ((addr & htonl(IP_MCAST_SUBNET_MASK)) == htonl(IP_MCAST_NETWORK));
97 #ifdef ENABLE_PF
99 static unsigned int
100 mroute_extract_addr_arp (struct mroute_addr *src,
101 struct mroute_addr *dest,
102 const struct buffer *buf)
104 unsigned int ret = 0;
105 if (BLEN (buf) >= (int) sizeof (struct openvpn_arp))
107 const struct openvpn_arp *arp = (const struct openvpn_arp *) BPTR (buf);
108 if (arp->mac_addr_type == htons(0x0001)
109 && arp->proto_addr_type == htons(0x0800)
110 && arp->mac_addr_size == 0x06
111 && arp->proto_addr_size == 0x04)
113 mroute_get_in_addr_t (src, arp->ip_src, MR_ARP);
114 mroute_get_in_addr_t (dest, arp->ip_dest, MR_ARP);
116 /* multicast packet? */
117 if (mroute_is_mcast (arp->ip_dest))
118 ret |= MROUTE_EXTRACT_MCAST;
120 ret |= MROUTE_EXTRACT_SUCCEEDED;
123 return ret;
126 #endif
128 unsigned int
129 mroute_extract_addr_ipv4 (struct mroute_addr *src,
130 struct mroute_addr *dest,
131 const struct buffer *buf)
133 unsigned int ret = 0;
134 if (BLEN (buf) >= 1)
136 switch (OPENVPN_IPH_GET_VER (*BPTR(buf)))
138 case 4:
139 if (BLEN (buf) >= (int) sizeof (struct openvpn_iphdr))
141 const struct openvpn_iphdr *ip = (const struct openvpn_iphdr *) BPTR (buf);
143 mroute_get_in_addr_t (src, ip->saddr, 0);
144 mroute_get_in_addr_t (dest, ip->daddr, 0);
146 /* multicast packet? */
147 if (mroute_is_mcast (ip->daddr))
148 ret |= MROUTE_EXTRACT_MCAST;
150 /* IGMP message? */
151 if (ip->protocol == OPENVPN_IPPROTO_IGMP)
152 ret |= MROUTE_EXTRACT_IGMP;
154 ret |= MROUTE_EXTRACT_SUCCEEDED;
156 break;
157 case 6:
159 msg (M_WARN, "Need IPv6 code in mroute_extract_addr_from_packet");
160 break;
164 return ret;
167 unsigned int
168 mroute_extract_addr_ether (struct mroute_addr *src,
169 struct mroute_addr *dest,
170 struct mroute_addr *esrc,
171 struct mroute_addr *edest,
172 const struct buffer *buf)
174 unsigned int ret = 0;
175 if (BLEN (buf) >= (int) sizeof (struct openvpn_ethhdr))
177 const struct openvpn_ethhdr *eth = (const struct openvpn_ethhdr *) BPTR (buf);
178 if (src)
180 src->type = MR_ADDR_ETHER;
181 src->netbits = 0;
182 src->len = 6;
183 memcpy (src->addr, eth->source, 6);
185 if (dest)
187 dest->type = MR_ADDR_ETHER;
188 dest->netbits = 0;
189 dest->len = 6;
190 memcpy (dest->addr, eth->dest, 6);
192 /* ethernet broadcast/multicast packet? */
193 if (is_mac_mcast_addr (eth->dest))
194 ret |= MROUTE_EXTRACT_BCAST;
197 ret |= MROUTE_EXTRACT_SUCCEEDED;
199 #ifdef ENABLE_PF
200 if (esrc || edest)
202 struct buffer b = *buf;
203 if (buf_advance (&b, sizeof (struct openvpn_ethhdr)))
205 switch (ntohs (eth->proto))
207 case OPENVPN_ETH_P_IPV4:
208 ret |= (mroute_extract_addr_ipv4 (esrc, edest, &b) << MROUTE_SEC_SHIFT);
209 break;
210 case OPENVPN_ETH_P_ARP:
211 ret |= (mroute_extract_addr_arp (esrc, edest, &b) << MROUTE_SEC_SHIFT);
212 break;
216 #endif
218 return ret;
222 * Translate a struct openvpn_sockaddr (osaddr)
223 * to a struct mroute_addr (addr).
225 bool mroute_extract_openvpn_sockaddr (struct mroute_addr *addr,
226 const struct openvpn_sockaddr *osaddr,
227 bool use_port)
229 if (osaddr->sa.sin_family == AF_INET)
231 if (use_port)
233 addr->type = MR_ADDR_IPV4 | MR_WITH_PORT;
234 addr->netbits = 0;
235 addr->len = 6;
236 memcpy (addr->addr, &osaddr->sa.sin_addr.s_addr, 4);
237 memcpy (addr->addr + 4, &osaddr->sa.sin_port, 2);
239 else
241 addr->type = MR_ADDR_IPV4;
242 addr->netbits = 0;
243 addr->len = 4;
244 memcpy (addr->addr, &osaddr->sa.sin_addr.s_addr, 4);
246 return true;
248 return false;
252 * Zero off the host bits in an address, leaving
253 * only the network bits, using the netbits member of
254 * struct mroute_addr as the controlling parameter.
256 void
257 mroute_addr_mask_host_bits (struct mroute_addr *ma)
259 in_addr_t addr = ntohl(*(in_addr_t*)ma->addr);
260 ASSERT ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV4);
261 addr &= netbits_to_netmask (ma->netbits);
262 *(in_addr_t*)ma->addr = htonl (addr);
266 * The mroute_addr hash function takes into account the
267 * address type, number of bits in the network address,
268 * and the actual address.
270 uint32_t
271 mroute_addr_hash_function (const void *key, uint32_t iv)
273 return hash_func (mroute_addr_hash_ptr ((const struct mroute_addr *) key),
274 mroute_addr_hash_len ((const struct mroute_addr *) key),
275 iv);
278 bool
279 mroute_addr_compare_function (const void *key1, const void *key2)
281 return mroute_addr_equal ((const struct mroute_addr *) key1,
282 (const struct mroute_addr *) key2);
285 const char *
286 mroute_addr_print (const struct mroute_addr *ma,
287 struct gc_arena *gc)
289 return mroute_addr_print_ex (ma, MAPF_IA_EMPTY_IF_UNDEF, gc);
292 const char *
293 mroute_addr_print_ex (const struct mroute_addr *ma,
294 const unsigned int flags,
295 struct gc_arena *gc)
297 struct buffer out = alloc_buf_gc (64, gc);
298 if (ma)
300 struct mroute_addr maddr = *ma;
302 switch (maddr.type & MR_ADDR_MASK)
304 case MR_ADDR_ETHER:
305 buf_printf (&out, "%s", format_hex_ex (ma->addr, 6, 0, 1, ":", gc));
306 break;
307 case MR_ADDR_IPV4:
309 struct buffer buf;
310 in_addr_t addr;
311 int port;
312 bool status;
313 buf_set_read (&buf, maddr.addr, maddr.len);
314 addr = buf_read_u32 (&buf, &status);
315 if (status)
317 if ((flags & MAPF_SHOW_ARP) && (maddr.type & MR_ARP))
318 buf_printf (&out, "ARP/");
319 buf_printf (&out, "%s", print_in_addr_t (addr, (flags & MAPF_IA_EMPTY_IF_UNDEF) ? IA_EMPTY_IF_UNDEF : 0, gc));
320 if (maddr.type & MR_WITH_NETBITS)
322 if (flags & MAPF_SUBNET)
324 const in_addr_t netmask = netbits_to_netmask (maddr.netbits);
325 buf_printf (&out, "/%s", print_in_addr_t (netmask, 0, gc));
327 else
328 buf_printf (&out, "/%d", maddr.netbits);
331 if (maddr.type & MR_WITH_PORT)
333 port = buf_read_u16 (&buf);
334 if (port >= 0)
335 buf_printf (&out, ":%d", port);
338 break;
339 case MR_ADDR_IPV6:
340 buf_printf (&out, "IPV6");
341 break;
342 default:
343 buf_printf (&out, "UNKNOWN");
344 break;
346 return BSTR (&out);
348 else
349 return "[NULL]";
353 * mroute_helper's main job is keeping track of
354 * currently used CIDR netlengths, so we don't
355 * have to cycle through all 33.
358 struct mroute_helper *
359 mroute_helper_init (int ageable_ttl_secs)
361 struct mroute_helper *mh;
362 ALLOC_OBJ_CLEAR (mh, struct mroute_helper);
363 /*mutex_init (&mh->mutex);*/
364 mh->ageable_ttl_secs = ageable_ttl_secs;
365 return mh;
368 static void
369 mroute_helper_regenerate (struct mroute_helper *mh)
371 int i, j = 0;
372 for (i = MR_HELPER_NET_LEN - 1; i >= 0; --i)
374 if (mh->net_len_refcount[i] > 0)
375 mh->net_len[j++] = (uint8_t) i;
377 mh->n_net_len = j;
379 #ifdef ENABLE_DEBUG
380 if (check_debug_level (D_MULTI_DEBUG))
382 struct gc_arena gc = gc_new ();
383 struct buffer out = alloc_buf_gc (256, &gc);
384 buf_printf (&out, "MROUTE CIDR netlen:");
385 for (i = 0; i < mh->n_net_len; ++i)
387 buf_printf (&out, " /%d", mh->net_len[i]);
389 dmsg (D_MULTI_DEBUG, "%s", BSTR (&out));
390 gc_free (&gc);
392 #endif
395 void
396 mroute_helper_add_iroute (struct mroute_helper *mh, const struct iroute *ir)
398 if (ir->netbits >= 0)
400 ASSERT (ir->netbits < MR_HELPER_NET_LEN);
401 mroute_helper_lock (mh);
402 ++mh->cache_generation;
403 ++mh->net_len_refcount[ir->netbits];
404 if (mh->net_len_refcount[ir->netbits] == 1)
405 mroute_helper_regenerate (mh);
406 mroute_helper_unlock (mh);
410 void
411 mroute_helper_del_iroute (struct mroute_helper *mh, const struct iroute *ir)
413 if (ir->netbits >= 0)
415 ASSERT (ir->netbits < MR_HELPER_NET_LEN);
416 mroute_helper_lock (mh);
417 ++mh->cache_generation;
418 --mh->net_len_refcount[ir->netbits];
419 ASSERT (mh->net_len_refcount[ir->netbits] >= 0);
420 if (!mh->net_len_refcount[ir->netbits])
421 mroute_helper_regenerate (mh);
422 mroute_helper_unlock (mh);
426 void
427 mroute_helper_free (struct mroute_helper *mh)
429 /*mutex_destroy (&mh->mutex);*/
430 free (mh);
433 #else
434 static void dummy(void) {}
435 #endif /* P2MP_SERVER */