OpenVPN
mroute.c
Go to the documentation of this file.
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.
7 *
8 * Copyright (C) 2002-2024 OpenVPN Inc <sales@openvpn.net>
9 *
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.
13 *
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.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include "syshead.h"
29
30
31#include "mroute.h"
32#include "proto.h"
33#include "error.h"
34#include "socket.h"
35
36#include "memdbg.h"
37
38void
40{
41 CLEAR(*addr);
42}
43
44/*
45 * Ethernet multicast addresses.
46 */
47
48static inline bool
49is_mac_mcast_addr(const uint8_t *mac)
50{
51 return (bool) (mac[0] & 1);
52}
53
54static inline bool
56{
57 return (addr->type & MR_ADDR_MASK) == MR_ADDR_ETHER
59}
60
61/*
62 * Don't learn certain addresses.
63 */
64bool
65mroute_learnable_address(const struct mroute_addr *addr, struct gc_arena *gc)
66{
67 int i;
68 bool all_zeros = true;
69 bool all_ones = true;
70
71 for (i = 0; i < addr->len; ++i)
72 {
73 int b = addr->raw_addr[i];
74 if (b != 0x00)
75 {
76 all_zeros = false;
77 }
78 if (b != 0xFF)
79 {
80 all_ones = false;
81 }
82 }
83
84 /* only networkss shorter than 8 bits are allowed to be all 0s. */
85 if (all_zeros
86 && !((addr->type & MR_WITH_NETBITS) && (addr->netbits < 8)))
87 {
88 msg(D_MULTI_LOW, "Can't learn %s: network is all 0s, but netbits >= 8",
89 mroute_addr_print(addr, gc));
90 return false;
91 }
92
93 if (all_ones)
94 {
95 msg(D_MULTI_LOW, "Can't learn %s: network is all 1s",
96 mroute_addr_print(addr, gc));
97 return false;
98 }
99
100 if (is_mac_mcast_maddr(addr))
101 {
102 msg(D_MULTI_LOW, "Can't learn %s: network is a multicast address",
103 mroute_addr_print(addr, gc));
104 return false;
105 }
106
107 return true;
108}
109
110static inline void
111mroute_get_in_addr_t(struct mroute_addr *ma, const in_addr_t src, unsigned int mask)
112{
113 if (ma)
114 {
115 ma->type = MR_ADDR_IPV4 | mask;
116 ma->netbits = 0;
117 ma->len = 4;
118 ma->v4.addr = src;
119 }
120}
121
122static inline void
123mroute_get_in6_addr(struct mroute_addr *ma, const struct in6_addr src, unsigned int mask)
124{
125 if (ma)
126 {
127 ma->type = MR_ADDR_IPV6 | mask;
128 ma->netbits = 0;
129 ma->len = 16;
130 ma->v6.addr = src;
131 }
132}
133
134static inline bool
135mroute_is_mcast(const in_addr_t addr)
136{
137 return ((addr & htonl(IP_MCAST_SUBNET_MASK)) == htonl(IP_MCAST_NETWORK));
138}
139
140/* RFC 4291, 2.7, "binary 11111111 at the start of an address identifies
141 * the address as being a multicast address"
142 */
143static inline bool
144mroute_is_mcast_ipv6(const struct in6_addr addr)
145{
146 return (addr.s6_addr[0] == 0xff);
147}
148
149
150unsigned int
152 const struct buffer *buf)
153{
154 unsigned int ret = 0;
155 if (BLEN(buf) >= 1)
156 {
157 switch (OPENVPN_IPH_GET_VER(*BPTR(buf)))
158 {
159 case 4:
160 if (BLEN(buf) >= (int) sizeof(struct openvpn_iphdr))
161 {
162 const struct openvpn_iphdr *ip = (const struct openvpn_iphdr *) BPTR(buf);
163
164 mroute_get_in_addr_t(src, ip->saddr, 0);
165 mroute_get_in_addr_t(dest, ip->daddr, 0);
166
167 /* multicast packet? */
168 if (mroute_is_mcast(ip->daddr))
169 {
171 }
172
173 /* IGMP message? */
175 {
176 ret |= MROUTE_EXTRACT_IGMP;
177 }
178
180 }
181 break;
182
183 case 6:
184 if (BLEN(buf) >= (int) sizeof(struct openvpn_ipv6hdr))
185 {
186 const struct openvpn_ipv6hdr *ipv6 = (const struct openvpn_ipv6hdr *) BPTR(buf);
187#if 0 /* very basic debug */
188 struct gc_arena gc = gc_new();
189 msg( M_INFO, "IPv6 packet! src=%s, dst=%s",
190 print_in6_addr( ipv6->saddr, 0, &gc ),
191 print_in6_addr( ipv6->daddr, 0, &gc ));
192 gc_free(&gc);
193#endif
194
195 mroute_get_in6_addr(src, ipv6->saddr, 0);
196 mroute_get_in6_addr(dest, ipv6->daddr, 0);
197
198 if (mroute_is_mcast_ipv6(ipv6->daddr))
199 {
201 }
202
204 }
205 break;
206
207 default:
208 msg(M_WARN, "IP packet with unknown IP version=%d seen",
210 }
211 }
212 return ret;
213}
214
215static void
217 const uint8_t *ether_addr,
218 uint16_t vid)
219{
220 maddr->type = MR_ADDR_ETHER;
221 maddr->netbits = 0;
222 maddr->len = OPENVPN_ETH_ALEN;
223 memcpy(maddr->ether.addr, ether_addr, OPENVPN_ETH_ALEN);
224 maddr->len += sizeof(vid);
225 maddr->ether.vid = vid;
226}
227
228unsigned int
230 struct mroute_addr *dest,
231 uint16_t vid,
232 const struct buffer *buf)
233{
234 unsigned int ret = 0;
235 if (BLEN(buf) >= (int) sizeof(struct openvpn_ethhdr))
236 {
237 const struct openvpn_ethhdr *eth = (const struct openvpn_ethhdr *) BPTR(buf);
238 if (src)
239 {
240 mroute_copy_ether_to_addr(src, eth->source, vid);
241 }
242 if (dest)
243 {
245
246 /* ethernet broadcast/multicast packet? */
247 if (is_mac_mcast_addr(eth->dest))
248 {
250 }
251 }
252
254
255 }
256 return ret;
257}
258
259/*
260 * Translate a struct openvpn_sockaddr (osaddr)
261 * to a struct mroute_addr (addr).
262 */
263bool
265 const struct openvpn_sockaddr *osaddr,
266 bool use_port)
267{
268 switch (osaddr->addr.sa.sa_family)
269 {
270 case AF_INET:
271 {
272 if (use_port)
273 {
275 addr->netbits = 0;
276 addr->len = 6;
277 addr->v4.addr = osaddr->addr.in4.sin_addr.s_addr;
278 addr->v4.port = osaddr->addr.in4.sin_port;
279 if (addr->proto != PROTO_NONE)
280 {
281 addr->type |= MR_WITH_PROTO;
282 }
283 }
284 else
285 {
286 addr->type = MR_ADDR_IPV4;
287 addr->netbits = 0;
288 addr->len = 4;
289 addr->v4.addr = osaddr->addr.in4.sin_addr.s_addr;
290 }
291 return true;
292 }
293
294 case AF_INET6:
295 if (use_port)
296 {
298 addr->netbits = 0;
299 addr->len = 18;
300 addr->v6.addr = osaddr->addr.in6.sin6_addr;
301 addr->v6.port = osaddr->addr.in6.sin6_port;
302 if (addr->proto != PROTO_NONE)
303 {
304 addr->type |= MR_WITH_PROTO;
305 }
306 }
307 else
308 {
309 addr->type = MR_ADDR_IPV6;
310 addr->netbits = 0;
311 addr->len = 16;
312 addr->v6.addr = osaddr->addr.in6.sin6_addr;
313 }
314 return true;
315 }
316 return false;
317}
318
319/*
320 * Zero off the host bits in an address, leaving
321 * only the network bits, using the netbits member of
322 * struct mroute_addr as the controlling parameter.
323 *
324 * TODO: this is called for route-lookup for every yet-unhashed
325 * destination address, so for lots of active net-iroutes, this
326 * might benefit from some "zeroize 32 bit at a time" improvements
327 */
328void
330{
331 if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV4)
332 {
333 in_addr_t addr = ntohl(ma->v4.addr);
334 addr &= netbits_to_netmask(ma->netbits);
335 ma->v4.addr = htonl(addr);
336 }
337 else if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV6)
338 {
339 int byte = sizeof(ma->v6.addr) - 1; /* rightmost byte in address */
340 int bits_to_clear = 128 - ma->netbits;
341
342 while (byte >= 0 && bits_to_clear > 0)
343 {
344 if (bits_to_clear >= 8)
345 {
346 ma->v6.addr.s6_addr[byte--] = 0;
347 bits_to_clear -= 8;
348 }
349 else
350 {
351 ma->v6.addr.s6_addr[byte--] &= (IPV4_NETMASK_HOST << bits_to_clear);
352 bits_to_clear = 0;
353 }
354 }
355 ASSERT( bits_to_clear == 0 );
356 }
357 else
358 {
359 ASSERT(0);
360 }
361}
362
363/*
364 * The mroute_addr hash function takes into account the
365 * address type, number of bits in the network address,
366 * and the actual address.
367 */
368uint32_t
369mroute_addr_hash_function(const void *key, uint32_t iv)
370{
371 return hash_func(mroute_addr_hash_ptr((const struct mroute_addr *) key),
372 mroute_addr_hash_len((const struct mroute_addr *) key),
373 iv);
374}
375
376bool
377mroute_addr_compare_function(const void *key1, const void *key2)
378{
379 return mroute_addr_equal((const struct mroute_addr *) key1,
380 (const struct mroute_addr *) key2);
381}
382
383const char *
385 struct gc_arena *gc)
386{
388}
389
390const char *
392 const unsigned int flags,
393 struct gc_arena *gc)
394{
395 struct buffer out = alloc_buf_gc(64, gc);
396 if (ma)
397 {
398 struct mroute_addr maddr = *ma;
399
400 switch (maddr.type & MR_ADDR_MASK)
401 {
402 case MR_ADDR_ETHER:
403 buf_printf(&out, "%s", format_hex_ex(ma->ether.addr,
404 sizeof(ma->ether.addr), 0, 1, ":", gc));
405 buf_printf(&out, "@%hu", ma->ether.vid);
406 break;
407
408 case MR_ADDR_IPV4:
409 {
410 if ((flags & MAPF_SHOW_ARP) && (maddr.type & MR_ARP))
411 {
412 buf_printf(&out, "ARP/");
413 }
414 if (maddr.type & MR_WITH_PROTO)
415 {
416 buf_printf(&out, "%s:", proto2ascii(maddr.proto, AF_INET, false));
417 }
418 buf_printf(&out, "%s", print_in_addr_t(ntohl(maddr.v4.addr),
420 if (maddr.type & MR_WITH_NETBITS)
421 {
422 if (flags & MAPF_SUBNET)
423 {
424 const in_addr_t netmask = netbits_to_netmask(maddr.netbits);
425 buf_printf(&out, "/%s", print_in_addr_t(netmask, 0, gc));
426 }
427 else
428 {
429 buf_printf(&out, "/%d", maddr.netbits);
430 }
431 }
432 if (maddr.type & MR_WITH_PORT)
433 {
434 buf_printf(&out, ":%d", ntohs(maddr.v4.port));
435 }
436 }
437 break;
438
439 case MR_ADDR_IPV6:
440 {
441 if (maddr.type & MR_WITH_PROTO)
442 {
443 buf_printf(&out, "%s:", proto2ascii(maddr.proto, AF_INET6, false));
444 }
445 if (IN6_IS_ADDR_V4MAPPED( &maddr.v6.addr ) )
446 {
447 buf_printf(&out, "%s", print_in_addr_t(maddr.v4mappedv6.addr,
448 IA_NET_ORDER, gc));
449 }
450 else if (maddr.type & MR_WITH_PORT)
451 {
452 buf_printf(&out, "[%s]", print_in6_addr(maddr.v6.addr, 0, gc));
453 }
454 else
455 {
456 buf_printf(&out, "%s", print_in6_addr(maddr.v6.addr, 0, gc));
457 }
458 if (maddr.type & MR_WITH_PORT)
459 {
460 buf_printf(&out, ":%d", ntohs(maddr.v6.port));
461 }
462 if (maddr.type & MR_WITH_NETBITS)
463 {
464 buf_printf(&out, "/%d", maddr.netbits);
465 }
466 }
467 break;
468
469 default:
470 buf_printf(&out, "UNKNOWN");
471 break;
472 }
473 return BSTR(&out);
474 }
475 else
476 {
477 return "[NULL]";
478 }
479}
480
481/*
482 * mroute_helper's main job is keeping track of
483 * currently used CIDR netlengths, so we don't
484 * have to cycle through all 33.
485 */
486
487struct mroute_helper *
489{
490 struct mroute_helper *mh;
491 ALLOC_OBJ_CLEAR(mh, struct mroute_helper);
493 return mh;
494}
495
496static void
498{
499 int i, j = 0;
500 for (i = MR_HELPER_NET_LEN - 1; i >= 0; --i)
501 {
502 if (mh->net_len_refcount[i] > 0)
503 {
504 mh->net_len[j++] = (uint8_t) i;
505 }
506 }
507 mh->n_net_len = j;
508
509#ifdef ENABLE_DEBUG
511 {
512 struct gc_arena gc = gc_new();
513 struct buffer out = alloc_buf_gc(256, &gc);
514 buf_printf(&out, "MROUTE CIDR netlen:");
515 for (i = 0; i < mh->n_net_len; ++i)
516 {
517 buf_printf(&out, " /%d", mh->net_len[i]);
518 }
519 dmsg(D_MULTI_DEBUG, "%s", BSTR(&out));
520 gc_free(&gc);
521 }
522#endif
523}
524
525void
527{
528 if (netbits >= 0)
529 {
530 ASSERT(netbits < MR_HELPER_NET_LEN);
531 ++mh->cache_generation;
532 ++mh->net_len_refcount[netbits];
533 if (mh->net_len_refcount[netbits] == 1)
534 {
536 }
537 }
538}
539
540void
542{
543 if (netbits >= 0)
544 {
545 ASSERT(netbits < MR_HELPER_NET_LEN);
546 ++mh->cache_generation;
547 --mh->net_len_refcount[netbits];
548 ASSERT(mh->net_len_refcount[netbits] >= 0);
549 if (!mh->net_len_refcount[netbits])
550 {
552 }
553 }
554}
555
556void
558{
559 free(mh);
560}
bool buf_printf(struct buffer *buf, const char *format,...)
Definition buffer.c:240
char * format_hex_ex(const uint8_t *data, int size, int maxoutput, unsigned int space_break_flags, const char *separator, struct gc_arena *gc)
Definition buffer.c:483
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition buffer.c:88
#define BSTR(buf)
Definition buffer.h:129
#define BPTR(buf)
Definition buffer.h:124
#define BLEN(buf)
Definition buffer.h:127
static void gc_free(struct gc_arena *a)
Definition buffer.h:1033
#define ALLOC_OBJ_CLEAR(dptr, type)
Definition buffer.h:1060
static struct gc_arena gc_new(void)
Definition buffer.h:1025
static const char *const key1
Definition cert_data.h:56
#define D_MULTI_DEBUG
Definition errlevel.h:127
#define D_MULTI_LOW
Definition errlevel.h:86
#define M_INFO
Definition errlevel.h:55
uint32_t hash_func(const uint8_t *k, uint32_t length, uint32_t initval)
Definition list.c:408
void mroute_addr_mask_host_bits(struct mroute_addr *ma)
Definition mroute.c:329
void mroute_helper_add_iroute46(struct mroute_helper *mh, int netbits)
Definition mroute.c:526
unsigned int mroute_extract_addr_ip(struct mroute_addr *src, struct mroute_addr *dest, const struct buffer *buf)
Definition mroute.c:151
static bool is_mac_mcast_maddr(const struct mroute_addr *addr)
Definition mroute.c:55
static void mroute_copy_ether_to_addr(struct mroute_addr *maddr, const uint8_t *ether_addr, uint16_t vid)
Definition mroute.c:216
const char * mroute_addr_print_ex(const struct mroute_addr *ma, const unsigned int flags, struct gc_arena *gc)
Definition mroute.c:391
bool mroute_extract_openvpn_sockaddr(struct mroute_addr *addr, const struct openvpn_sockaddr *osaddr, bool use_port)
Definition mroute.c:264
const char * mroute_addr_print(const struct mroute_addr *ma, struct gc_arena *gc)
Definition mroute.c:384
static bool is_mac_mcast_addr(const uint8_t *mac)
Definition mroute.c:49
uint32_t mroute_addr_hash_function(const void *key, uint32_t iv)
Definition mroute.c:369
void mroute_helper_del_iroute46(struct mroute_helper *mh, int netbits)
Definition mroute.c:541
bool mroute_learnable_address(const struct mroute_addr *addr, struct gc_arena *gc)
Definition mroute.c:65
static bool mroute_is_mcast(const in_addr_t addr)
Definition mroute.c:135
bool mroute_addr_compare_function(const void *key1, const void *key2)
Definition mroute.c:377
static bool mroute_is_mcast_ipv6(const struct in6_addr addr)
Definition mroute.c:144
unsigned int mroute_extract_addr_ether(struct mroute_addr *src, struct mroute_addr *dest, uint16_t vid, const struct buffer *buf)
Definition mroute.c:229
struct mroute_helper * mroute_helper_init(int ageable_ttl_secs)
Definition mroute.c:488
void mroute_addr_init(struct mroute_addr *addr)
Definition mroute.c:39
static void mroute_helper_regenerate(struct mroute_helper *mh)
Definition mroute.c:497
static void mroute_get_in_addr_t(struct mroute_addr *ma, const in_addr_t src, unsigned int mask)
Definition mroute.c:111
static void mroute_get_in6_addr(struct mroute_addr *ma, const struct in6_addr src, unsigned int mask)
Definition mroute.c:123
void mroute_helper_free(struct mroute_helper *mh)
Definition mroute.c:557
static uint32_t mroute_addr_hash_len(const struct mroute_addr *a)
Definition mroute.h:239
#define MROUTE_EXTRACT_SUCCEEDED
Definition mroute.h:38
#define MROUTE_EXTRACT_MCAST
Definition mroute.h:40
#define MR_ADDR_ETHER
Definition mroute.h:61
#define IP_MCAST_NETWORK
Definition mroute.h:34
#define MR_WITH_NETBITS
Definition mroute.h:70
#define MR_WITH_PROTO
Definition mroute.h:76
#define IP_MCAST_SUBNET_MASK
Definition mroute.h:33
#define MR_ADDR_IPV4
Definition mroute.h:62
#define MAPF_SHOW_ARP
Definition mroute.h:152
#define MAPF_SUBNET
Definition mroute.h:150
static const uint8_t * mroute_addr_hash_ptr(const struct mroute_addr *a)
Definition mroute.h:232
#define MR_WITH_PORT
Definition mroute.h:67
#define MR_ARP
Definition mroute.h:73
#define MR_HELPER_NET_LEN
Definition mroute.h:119
#define MAPF_IA_EMPTY_IF_UNDEF
Definition mroute.h:151
static bool mroute_addr_equal(const struct mroute_addr *a1, const struct mroute_addr *a2)
Definition mroute.h:210
#define MROUTE_EXTRACT_BCAST
Definition mroute.h:39
#define MROUTE_EXTRACT_IGMP
Definition mroute.h:41
#define MR_ADDR_IPV6
Definition mroute.h:63
#define MR_ADDR_MASK
Definition mroute.h:64
#define IPV4_NETMASK_HOST
Definition basic.h:35
#define CLEAR(x)
Definition basic.h:33
static bool check_debug_level(unsigned int level)
Definition error.h:220
#define dmsg(flags,...)
Definition error.h:148
#define msg(flags,...)
Definition error.h:144
#define ASSERT(x)
Definition error.h:195
#define M_WARN
Definition error.h:91
#define OPENVPN_ETH_ALEN
Definition proto.h:53
#define OPENVPN_IPH_GET_VER(v)
Definition proto.h:93
#define OPENVPN_IPPROTO_IGMP
Definition proto.h:106
static in_addr_t netbits_to_netmask(const int netbits)
Definition route.h:394
const char * proto2ascii(int proto, sa_family_t af, bool display_form)
Definition socket.c:3196
const char * print_in6_addr(struct in6_addr a6, unsigned int flags, struct gc_arena *gc)
Definition socket.c:2994
const char * print_in_addr_t(in_addr_t addr, unsigned int flags, struct gc_arena *gc)
Definition socket.c:2974
#define IA_EMPTY_IF_UNDEF
Definition socket.h:401
@ PROTO_NONE
Definition socket.h:567
#define IA_NET_ORDER
Definition socket.h:402
Wrapper structure for dynamically allocated memory.
Definition buffer.h:61
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:66
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:117
Container for bidirectional cipher and HMAC key material.
Definition crypto.h:239
Container for unidirectional cipher and HMAC key material.
Definition crypto.h:152
uint8_t raw_addr[MR_MAX_ADDR_LEN]
Definition mroute.h:85
uint16_t vid
Definition mroute.h:88
struct mroute_addr::@2::@4 ether
struct mroute_addr::@2::@6 v6
uint8_t addr[OPENVPN_ETH_ALEN]
Definition mroute.h:87
struct mroute_addr::@2::@5 v4
uint8_t proto
Definition mroute.h:80
uint8_t type
Definition mroute.h:81
in_port_t port
Definition mroute.h:92
uint8_t len
Definition mroute.h:79
uint8_t netbits
Definition mroute.h:82
int ageable_ttl_secs
Definition mroute.h:126
int net_len_refcount[MR_HELPER_NET_LEN]
Definition mroute.h:129
uint8_t net_len[MR_HELPER_NET_LEN]
Definition mroute.h:128
int n_net_len
Definition mroute.h:127
uint8_t dest[OPENVPN_ETH_ALEN]
Definition proto.h:56
uint8_t source[OPENVPN_ETH_ALEN]
Definition proto.h:57
uint32_t saddr
Definition proto.h:113
uint32_t daddr
Definition proto.h:114
uint8_t protocol
Definition proto.h:110
struct in6_addr saddr
Definition proto.h:128
struct in6_addr daddr
Definition proto.h:129
union openvpn_sockaddr::@20 addr
struct sockaddr sa
Definition socket.h:69
struct sockaddr_in in4
Definition socket.h:70
struct sockaddr_in6 in6
Definition socket.h:71
struct gc_arena gc
Definition test_ssl.c:155