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