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
106static inline void
107mroute_get_in_addr_t(struct mroute_addr *ma, const in_addr_t src, unsigned int mask)
108{
109 if (ma)
110 {
111 ma->type = MR_ADDR_IPV4 | mask;
112 ma->netbits = 0;
113 ma->len = 4;
114 ma->v4.addr = src;
115 }
116}
117
118static inline void
119mroute_get_in6_addr(struct mroute_addr *ma, const struct in6_addr src, unsigned int mask)
120{
121 if (ma)
122 {
123 ma->type = MR_ADDR_IPV6 | mask;
124 ma->netbits = 0;
125 ma->len = 16;
126 ma->v6.addr = src;
127 }
128}
129
130static inline bool
131mroute_is_mcast(const in_addr_t addr)
132{
133 return ((addr & htonl(IP_MCAST_SUBNET_MASK)) == htonl(IP_MCAST_NETWORK));
134}
135
136/* RFC 4291, 2.7, "binary 11111111 at the start of an address identifies
137 * the address as being a multicast address"
138 */
139static inline bool
140mroute_is_mcast_ipv6(const struct in6_addr addr)
141{
142 return (addr.s6_addr[0] == 0xff);
143}
144
145
146unsigned int
147mroute_extract_addr_ip(struct mroute_addr *src, struct mroute_addr *dest, const struct buffer *buf)
148{
149 unsigned int ret = 0;
150 if (BLEN(buf) >= 1)
151 {
152 switch (OPENVPN_IPH_GET_VER(*BPTR(buf)))
153 {
154 case 4:
155 if (BLEN(buf) >= (int)sizeof(struct openvpn_iphdr))
156 {
157 const struct openvpn_iphdr *ip = (const struct openvpn_iphdr *)BPTR(buf);
158
159 mroute_get_in_addr_t(src, ip->saddr, 0);
160 mroute_get_in_addr_t(dest, ip->daddr, 0);
161
162 /* multicast packet? */
163 if (mroute_is_mcast(ip->daddr))
164 {
166 }
167
168 /* IGMP message? */
170 {
171 ret |= MROUTE_EXTRACT_IGMP;
172 }
173
175 }
176 break;
177
178 case 6:
179 if (BLEN(buf) >= (int)sizeof(struct openvpn_ipv6hdr))
180 {
181 const struct openvpn_ipv6hdr *ipv6 = (const struct openvpn_ipv6hdr *)BPTR(buf);
182#if 0 /* very basic debug */
183 struct gc_arena gc = gc_new();
184 msg( M_INFO, "IPv6 packet! src=%s, dst=%s",
185 print_in6_addr( ipv6->saddr, 0, &gc ),
186 print_in6_addr( ipv6->daddr, 0, &gc ));
187 gc_free(&gc);
188#endif
189
190 mroute_get_in6_addr(src, ipv6->saddr, 0);
191 mroute_get_in6_addr(dest, ipv6->daddr, 0);
192
193 if (mroute_is_mcast_ipv6(ipv6->daddr))
194 {
196 }
197
199 }
200 break;
201
202 default:
203 msg(M_WARN, "IP packet with unknown IP version=%d seen",
205 }
206 }
207 return ret;
208}
209
210static void
211mroute_copy_ether_to_addr(struct mroute_addr *maddr, const uint8_t *ether_addr, uint16_t vid)
212{
213 maddr->type = MR_ADDR_ETHER;
214 maddr->netbits = 0;
215 maddr->len = OPENVPN_ETH_ALEN;
216 memcpy(maddr->ether.addr, ether_addr, OPENVPN_ETH_ALEN);
217 maddr->len += sizeof(vid);
218 maddr->ether.vid = vid;
219}
220
221unsigned int
222mroute_extract_addr_ether(struct mroute_addr *src, struct mroute_addr *dest, uint16_t vid,
223 const struct buffer *buf)
224{
225 unsigned int ret = 0;
226 if (BLEN(buf) >= (int)sizeof(struct openvpn_ethhdr))
227 {
228 const struct openvpn_ethhdr *eth = (const struct openvpn_ethhdr *)BPTR(buf);
229 if (src)
230 {
231 mroute_copy_ether_to_addr(src, eth->source, vid);
232 }
233 if (dest)
234 {
236
237 /* ethernet broadcast/multicast packet? */
238 if (is_mac_mcast_addr(eth->dest))
239 {
241 }
242 }
243
245 }
246 return ret;
247}
248
249/*
250 * Translate a struct openvpn_sockaddr (osaddr)
251 * to a struct mroute_addr (addr).
252 */
253bool
255 bool use_port)
256{
257 switch (osaddr->addr.sa.sa_family)
258 {
259 case AF_INET:
260 {
261 if (use_port)
262 {
264 addr->netbits = 0;
265 addr->len = 6;
266 addr->v4.addr = osaddr->addr.in4.sin_addr.s_addr;
267 addr->v4.port = osaddr->addr.in4.sin_port;
268 if (addr->proto != PROTO_NONE)
269 {
270 addr->type |= MR_WITH_PROTO;
271 }
272 }
273 else
274 {
275 addr->type = MR_ADDR_IPV4;
276 addr->netbits = 0;
277 addr->len = 4;
278 addr->v4.addr = osaddr->addr.in4.sin_addr.s_addr;
279 }
280 return true;
281 }
282
283 case AF_INET6:
284 if (use_port)
285 {
287 addr->netbits = 0;
288 addr->len = 18;
289 addr->v6.addr = osaddr->addr.in6.sin6_addr;
290 addr->v6.port = osaddr->addr.in6.sin6_port;
291 if (addr->proto != PROTO_NONE)
292 {
293 addr->type |= MR_WITH_PROTO;
294 }
295 }
296 else
297 {
298 addr->type = MR_ADDR_IPV6;
299 addr->netbits = 0;
300 addr->len = 16;
301 addr->v6.addr = osaddr->addr.in6.sin6_addr;
302 }
303 return true;
304 }
305 return false;
306}
307
308/*
309 * Zero off the host bits in an address, leaving
310 * only the network bits, using the netbits member of
311 * struct mroute_addr as the controlling parameter.
312 *
313 * TODO: this is called for route-lookup for every yet-unhashed
314 * destination address, so for lots of active net-iroutes, this
315 * might benefit from some "zeroize 32 bit at a time" improvements
316 */
317void
319{
320 if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV4)
321 {
322 in_addr_t addr = ntohl(ma->v4.addr);
323 addr &= netbits_to_netmask(ma->netbits);
324 ma->v4.addr = htonl(addr);
325 }
326 else if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV6)
327 {
328 int byte = sizeof(ma->v6.addr) - 1; /* rightmost byte in address */
329 int bits_to_clear = 128 - ma->netbits;
330
331 while (byte >= 0 && bits_to_clear > 0)
332 {
333 if (bits_to_clear >= 8)
334 {
335 ma->v6.addr.s6_addr[byte--] = 0;
336 bits_to_clear -= 8;
337 }
338 else
339 {
340 ma->v6.addr.s6_addr[byte--] &= (IPV4_NETMASK_HOST << bits_to_clear);
341 bits_to_clear = 0;
342 }
343 }
344 ASSERT(bits_to_clear == 0);
345 }
346 else
347 {
348 ASSERT(0);
349 }
350}
351
352/*
353 * The mroute_addr hash function takes into account the
354 * address type, number of bits in the network address,
355 * and the actual address.
356 */
357uint32_t
358mroute_addr_hash_function(const void *key, uint32_t iv)
359{
360 return hash_func(mroute_addr_hash_ptr((const struct mroute_addr *)key),
361 mroute_addr_hash_len((const struct mroute_addr *)key), iv);
362}
363
364bool
365mroute_addr_compare_function(const void *key1, const void *key2)
366{
367 return mroute_addr_equal((const struct mroute_addr *)key1, (const struct mroute_addr *)key2);
368}
369
370const char *
371mroute_addr_print(const struct mroute_addr *ma, struct gc_arena *gc)
372{
374}
375
376const char *
377mroute_addr_print_ex(const struct mroute_addr *ma, const unsigned int flags, struct gc_arena *gc)
378{
379 struct buffer out = alloc_buf_gc(64, gc);
380 if (ma)
381 {
382 struct mroute_addr maddr = *ma;
383
384 switch (maddr.type & MR_ADDR_MASK)
385 {
386 case MR_ADDR_ETHER:
387 buf_printf(&out, "%s",
388 format_hex_ex(ma->ether.addr, sizeof(ma->ether.addr), 0, 1, ":", gc));
389 buf_printf(&out, "@%hu", ma->ether.vid);
390 break;
391
392 case MR_ADDR_IPV4:
393 {
394 if ((flags & MAPF_SHOW_ARP) && (maddr.type & MR_ARP))
395 {
396 buf_printf(&out, "ARP/");
397 }
398 if (maddr.type & MR_WITH_PROTO)
399 {
400 buf_printf(&out, "%s:", proto2ascii(maddr.proto, AF_INET, false));
401 }
402 if (flags & MAPF_SHOW_FAMILY)
403 {
404 buf_printf(&out, "[AF_INET]");
405 }
406 buf_printf(&out, "%s",
407 print_in_addr_t(ntohl(maddr.v4.addr),
409 gc));
410 if (maddr.type & MR_WITH_NETBITS)
411 {
412 if (flags & MAPF_SUBNET)
413 {
414 const in_addr_t netmask = netbits_to_netmask(maddr.netbits);
415 buf_printf(&out, "/%s", print_in_addr_t(netmask, 0, gc));
416 }
417 else
418 {
419 buf_printf(&out, "/%d", maddr.netbits);
420 }
421 }
422 if (maddr.type & MR_WITH_PORT)
423 {
424 buf_printf(&out, ":%d", ntohs(maddr.v4.port));
425 }
426 }
427 break;
428
429 case MR_ADDR_IPV6:
430 {
431 if (maddr.type & MR_WITH_PROTO)
432 {
433 buf_printf(&out, "%s:", proto2ascii(maddr.proto, AF_INET6, false));
434 }
435 if (flags & MAPF_SHOW_FAMILY)
436 {
437 buf_printf(&out, "[AF_INET6]");
438 }
439 if (IN6_IS_ADDR_V4MAPPED(&maddr.v6.addr))
440 {
441 buf_printf(&out, "%s",
442 print_in_addr_t(maddr.v4mappedv6.addr, IA_NET_ORDER, gc));
443 }
444 else if (maddr.type & MR_WITH_PORT)
445 {
446 buf_printf(&out, "[%s]", print_in6_addr(maddr.v6.addr, 0, gc));
447 }
448 else
449 {
450 buf_printf(&out, "%s", print_in6_addr(maddr.v6.addr, 0, gc));
451 }
452 if (maddr.type & MR_WITH_PORT)
453 {
454 buf_printf(&out, ":%d", ntohs(maddr.v6.port));
455 }
456 if (maddr.type & MR_WITH_NETBITS)
457 {
458 buf_printf(&out, "/%d", maddr.netbits);
459 }
460 }
461 break;
462
463 default:
464 buf_printf(&out, "UNKNOWN");
465 break;
466 }
467 return BSTR(&out);
468 }
469 else
470 {
471 return "[NULL]";
472 }
473}
474
475/*
476 * mroute_helper's main job is keeping track of
477 * currently used CIDR netlengths, so we don't
478 * have to cycle through all 33.
479 */
480
481struct mroute_helper *
483{
484 struct mroute_helper *mh;
485 ALLOC_OBJ_CLEAR(mh, struct mroute_helper);
487 return mh;
488}
489
490static void
492{
493 int i, j = 0;
494 for (i = MR_HELPER_NET_LEN - 1; i >= 0; --i)
495 {
496 if (mh->net_len_refcount[i] > 0)
497 {
498 mh->net_len[j++] = (uint8_t)i;
499 }
500 }
501 mh->n_net_len = j;
502
503#ifdef ENABLE_DEBUG
505 {
506 struct gc_arena gc = gc_new();
507 struct buffer out = alloc_buf_gc(256, &gc);
508 buf_printf(&out, "MROUTE CIDR netlen:");
509 for (i = 0; i < mh->n_net_len; ++i)
510 {
511 buf_printf(&out, " /%d", mh->net_len[i]);
512 }
513 dmsg(D_MULTI_DEBUG, "%s", BSTR(&out));
514 gc_free(&gc);
515 }
516#endif
517}
518
519void
521{
522 if (netbits >= 0)
523 {
524 ASSERT(netbits < MR_HELPER_NET_LEN);
525 ++mh->cache_generation;
526 ++mh->net_len_refcount[netbits];
527 if (mh->net_len_refcount[netbits] == 1)
528 {
530 }
531 }
532}
533
534void
536{
537 if (netbits >= 0)
538 {
539 ASSERT(netbits < MR_HELPER_NET_LEN);
540 ++mh->cache_generation;
541 --mh->net_len_refcount[netbits];
542 ASSERT(mh->net_len_refcount[netbits] >= 0);
543 if (!mh->net_len_refcount[netbits])
544 {
546 }
547 }
548}
549
550void
552{
553 free(mh);
554}
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:415
void mroute_addr_mask_host_bits(struct mroute_addr *ma)
Definition mroute.c:318
void mroute_helper_add_iroute46(struct mroute_helper *mh, int netbits)
Definition mroute.c:520
unsigned int mroute_extract_addr_ip(struct mroute_addr *src, struct mroute_addr *dest, const struct buffer *buf)
Definition mroute.c:147
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:211
const char * mroute_addr_print_ex(const struct mroute_addr *ma, const unsigned int flags, struct gc_arena *gc)
Definition mroute.c:377
bool mroute_extract_openvpn_sockaddr(struct mroute_addr *addr, const struct openvpn_sockaddr *osaddr, bool use_port)
Definition mroute.c:254
const char * mroute_addr_print(const struct mroute_addr *ma, struct gc_arena *gc)
Definition mroute.c:371
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:358
void mroute_helper_del_iroute46(struct mroute_helper *mh, int netbits)
Definition mroute.c:535
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:131
bool mroute_addr_compare_function(const void *key1, const void *key2)
Definition mroute.c:365
static bool mroute_is_mcast_ipv6(const struct in6_addr addr)
Definition mroute.c:140
unsigned int mroute_extract_addr_ether(struct mroute_addr *src, struct mroute_addr *dest, uint16_t vid, const struct buffer *buf)
Definition mroute.c:222
struct mroute_helper * mroute_helper_init(int ageable_ttl_secs)
Definition mroute.c:482
void mroute_addr_init(struct mroute_addr *addr)
Definition mroute.c:38
static void mroute_helper_regenerate(struct mroute_helper *mh)
Definition mroute.c:491
static void mroute_get_in_addr_t(struct mroute_addr *ma, const in_addr_t src, unsigned int mask)
Definition mroute.c:107
static void mroute_get_in6_addr(struct mroute_addr *ma, const struct in6_addr src, unsigned int mask)
Definition mroute.c:119
void mroute_helper_free(struct mroute_helper *mh)
Definition mroute.c:551
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(unsigned int level)
Definition error.h:257
#define dmsg(flags,...)
Definition error.h:170
#define msg(flags,...)
Definition error.h:150
#define ASSERT(x)
Definition error.h:217
#define M_WARN
Definition error.h:90
#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:154