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-2017 OpenVPN Technologies, 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 #elif defined(_MSC_VER)
27 #include "config-msvc.h"
28 #endif
29 
30 #include "syshead.h"
31 
32 #if P2MP_SERVER
33 
34 #include "mroute.h"
35 #include "proto.h"
36 #include "error.h"
37 #include "socket.h"
38 
39 #include "memdbg.h"
40 
41 void
43 {
44  CLEAR(*addr);
45 }
46 
47 /*
48  * Ethernet multicast addresses.
49  */
50 
51 static inline bool
53 {
54  return (bool) (mac[0] & 1);
55 }
56 
57 static inline bool
58 is_mac_mcast_maddr(const struct mroute_addr *addr)
59 {
60  return (addr->type & MR_ADDR_MASK) == MR_ADDR_ETHER
61  && is_mac_mcast_addr(addr->eth_addr);
62 }
63 
64 /*
65  * Don't learn certain addresses.
66  */
67 bool
69 {
70  int i;
71  bool not_all_zeros = false;
72  bool not_all_ones = false;
73 
74  for (i = 0; i < addr->len; ++i)
75  {
76  int b = addr->raw_addr[i];
77  if (b != 0x00)
78  {
79  not_all_zeros = true;
80  }
81  if (b != 0xFF)
82  {
83  not_all_ones = true;
84  }
85  }
86  return not_all_zeros && not_all_ones && !is_mac_mcast_maddr(addr);
87 }
88 
89 static inline void
90 mroute_get_in_addr_t(struct mroute_addr *ma, const in_addr_t src, unsigned int mask)
91 {
92  if (ma)
93  {
94  ma->type = MR_ADDR_IPV4 | mask;
95  ma->netbits = 0;
96  ma->len = 4;
97  ma->v4.addr = src;
98  }
99 }
100 
101 static inline void
102 mroute_get_in6_addr(struct mroute_addr *ma, const struct in6_addr src, unsigned int mask)
103 {
104  if (ma)
105  {
106  ma->type = MR_ADDR_IPV6 | mask;
107  ma->netbits = 0;
108  ma->len = 16;
109  ma->v6.addr = src;
110  }
111 }
112 
113 static inline bool
115 {
116  return ((addr & htonl(IP_MCAST_SUBNET_MASK)) == htonl(IP_MCAST_NETWORK));
117 }
118 
119 /* RFC 4291, 2.7, "binary 11111111 at the start of an address identifies
120  * the address as being a multicast address"
121  */
122 static inline bool
123 mroute_is_mcast_ipv6(const struct in6_addr addr)
124 {
125  return (addr.s6_addr[0] == 0xff);
126 }
127 
128 #ifdef ENABLE_PF
129 
130 static unsigned int
131 mroute_extract_addr_arp(struct mroute_addr *src,
132  struct mroute_addr *dest,
133  const struct buffer *buf)
134 {
135  unsigned int ret = 0;
136  if (BLEN(buf) >= (int) sizeof(struct openvpn_arp))
137  {
138  const struct openvpn_arp *arp = (const struct openvpn_arp *) BPTR(buf);
139  if (arp->mac_addr_type == htons(0x0001)
140  && arp->proto_addr_type == htons(0x0800)
141  && arp->mac_addr_size == 0x06
142  && arp->proto_addr_size == 0x04)
143  {
144  mroute_get_in_addr_t(src, arp->ip_src, MR_ARP);
145  mroute_get_in_addr_t(dest, arp->ip_dest, MR_ARP);
146 
147  /* multicast packet? */
148  if (mroute_is_mcast(arp->ip_dest))
149  {
150  ret |= MROUTE_EXTRACT_MCAST;
151  }
152 
154  }
155  }
156  return ret;
157 }
158 
159 #endif /* ifdef ENABLE_PF */
160 
161 unsigned int
163  const struct buffer *buf)
164 {
165  unsigned int ret = 0;
166  if (BLEN(buf) >= 1)
167  {
168  switch (OPENVPN_IPH_GET_VER(*BPTR(buf)))
169  {
170  case 4:
171  if (BLEN(buf) >= (int) sizeof(struct openvpn_iphdr))
172  {
173  const struct openvpn_iphdr *ip = (const struct openvpn_iphdr *) BPTR(buf);
174 
175  mroute_get_in_addr_t(src, ip->saddr, 0);
176  mroute_get_in_addr_t(dest, ip->daddr, 0);
177 
178  /* multicast packet? */
179  if (mroute_is_mcast(ip->daddr))
180  {
181  ret |= MROUTE_EXTRACT_MCAST;
182  }
183 
184  /* IGMP message? */
185  if (ip->protocol == OPENVPN_IPPROTO_IGMP)
186  {
187  ret |= MROUTE_EXTRACT_IGMP;
188  }
189 
191  }
192  break;
193 
194  case 6:
195  if (BLEN(buf) >= (int) sizeof(struct openvpn_ipv6hdr))
196  {
197  const struct openvpn_ipv6hdr *ipv6 = (const struct openvpn_ipv6hdr *) BPTR(buf);
198 #if 0 /* very basic debug */
199  struct gc_arena gc = gc_new();
200  msg( M_INFO, "IPv6 packet! src=%s, dst=%s",
201  print_in6_addr( ipv6->saddr, 0, &gc ),
202  print_in6_addr( ipv6->daddr, 0, &gc ));
203  gc_free(&gc);
204 #endif
205 
206  mroute_get_in6_addr(src, ipv6->saddr, 0);
207  mroute_get_in6_addr(dest, ipv6->daddr, 0);
208 
209  if (mroute_is_mcast_ipv6(ipv6->daddr))
210  {
211  ret |= MROUTE_EXTRACT_MCAST;
212  }
213 
215  }
216  break;
217 
218  default:
219  msg(M_WARN, "IP packet with unknown IP version=%d seen",
220  OPENVPN_IPH_GET_VER(*BPTR(buf)));
221  }
222  }
223  return ret;
224 }
225 
226 unsigned int
228  struct mroute_addr *dest,
229  struct mroute_addr *esrc,
230  struct mroute_addr *edest,
231  const struct buffer *buf)
232 {
233  unsigned int ret = 0;
234  if (BLEN(buf) >= (int) sizeof(struct openvpn_ethhdr))
235  {
236  const struct openvpn_ethhdr *eth = (const struct openvpn_ethhdr *) BPTR(buf);
237  if (src)
238  {
239  src->type = MR_ADDR_ETHER;
240  src->netbits = 0;
241  src->len = 6;
242  memcpy(src->eth_addr, eth->source, sizeof(dest->eth_addr));
243  }
244  if (dest)
245  {
246  dest->type = MR_ADDR_ETHER;
247  dest->netbits = 0;
248  dest->len = 6;
249  memcpy(dest->eth_addr, eth->dest, sizeof(dest->eth_addr));
250 
251  /* ethernet broadcast/multicast packet? */
252  if (is_mac_mcast_addr(eth->dest))
253  {
254  ret |= MROUTE_EXTRACT_BCAST;
255  }
256  }
257 
259 
260 #ifdef ENABLE_PF
261  if (esrc || edest)
262  {
263  struct buffer b = *buf;
264  if (buf_advance(&b, sizeof(struct openvpn_ethhdr)))
265  {
266  switch (ntohs(eth->proto))
267  {
268  case OPENVPN_ETH_P_IPV4:
269  ret |= (mroute_extract_addr_ip(esrc, edest, &b) << MROUTE_SEC_SHIFT);
270  break;
271 
272  case OPENVPN_ETH_P_ARP:
273  ret |= (mroute_extract_addr_arp(esrc, edest, &b) << MROUTE_SEC_SHIFT);
274  break;
275  }
276  }
277  }
278 #endif
279  }
280  return ret;
281 }
282 
283 /*
284  * Translate a struct openvpn_sockaddr (osaddr)
285  * to a struct mroute_addr (addr).
286  */
287 bool
289  const struct openvpn_sockaddr *osaddr,
290  bool use_port)
291 {
292  switch (osaddr->addr.sa.sa_family)
293  {
294  case AF_INET:
295  {
296  if (use_port)
297  {
298  addr->type = MR_ADDR_IPV4 | MR_WITH_PORT;
299  addr->netbits = 0;
300  addr->len = 6;
301  addr->v4.addr = osaddr->addr.in4.sin_addr.s_addr;
302  addr->v4.port = osaddr->addr.in4.sin_port;
303  }
304  else
305  {
306  addr->type = MR_ADDR_IPV4;
307  addr->netbits = 0;
308  addr->len = 4;
309  addr->v4.addr = osaddr->addr.in4.sin_addr.s_addr;
310  }
311  return true;
312  }
313 
314  case AF_INET6:
315  if (use_port)
316  {
317  addr->type = MR_ADDR_IPV6 | MR_WITH_PORT;
318  addr->netbits = 0;
319  addr->len = 18;
320  addr->v6.addr = osaddr->addr.in6.sin6_addr;
321  addr->v6.port = osaddr->addr.in6.sin6_port;
322  }
323  else
324  {
325  addr->type = MR_ADDR_IPV6;
326  addr->netbits = 0;
327  addr->len = 16;
328  addr->v6.addr = osaddr->addr.in6.sin6_addr;
329  }
330  return true;
331  }
332  return false;
333 }
334 
335 /*
336  * Zero off the host bits in an address, leaving
337  * only the network bits, using the netbits member of
338  * struct mroute_addr as the controlling parameter.
339  *
340  * TODO: this is called for route-lookup for every yet-unhashed
341  * destination address, so for lots of active net-iroutes, this
342  * might benefit from some "zeroize 32 bit at a time" improvements
343  */
344 void
346 {
347  if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV4)
348  {
349  in_addr_t addr = ntohl(ma->v4.addr);
350  addr &= netbits_to_netmask(ma->netbits);
351  ma->v4.addr = htonl(addr);
352  }
353  else if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV6)
354  {
355  int byte = sizeof(ma->v6.addr) - 1; /* rightmost byte in address */
356  int bits_to_clear = 128 - ma->netbits;
357 
358  while (byte >= 0 && bits_to_clear > 0)
359  {
360  if (bits_to_clear >= 8)
361  {
362  ma->v6.addr.s6_addr[byte--] = 0;
363  bits_to_clear -= 8;
364  }
365  else
366  {
367  ma->v6.addr.s6_addr[byte--] &= (IPV4_NETMASK_HOST << bits_to_clear);
368  bits_to_clear = 0;
369  }
370  }
371  ASSERT( bits_to_clear == 0 );
372  }
373  else
374  {
375  ASSERT(0);
376  }
377 }
378 
379 /*
380  * The mroute_addr hash function takes into account the
381  * address type, number of bits in the network address,
382  * and the actual address.
383  */
384 uint32_t
386 {
387  return hash_func(mroute_addr_hash_ptr((const struct mroute_addr *) key),
388  mroute_addr_hash_len((const struct mroute_addr *) key),
389  iv);
390 }
391 
392 bool
393 mroute_addr_compare_function(const void *key1, const void *key2)
394 {
395  return mroute_addr_equal((const struct mroute_addr *) key1,
396  (const struct mroute_addr *) key2);
397 }
398 
399 const char *
401  struct gc_arena *gc)
402 {
404 }
405 
406 const char *
408  const unsigned int flags,
409  struct gc_arena *gc)
410 {
411  struct buffer out = alloc_buf_gc(64, gc);
412  if (ma)
413  {
414  struct mroute_addr maddr = *ma;
415 
416  switch (maddr.type & MR_ADDR_MASK)
417  {
418  case MR_ADDR_ETHER:
419  buf_printf(&out, "%s", format_hex_ex(ma->eth_addr,
420  sizeof(ma->eth_addr), 0, 1, ":", gc));
421  break;
422 
423  case MR_ADDR_IPV4:
424  {
425  if ((flags & MAPF_SHOW_ARP) && (maddr.type & MR_ARP))
426  {
427  buf_printf(&out, "ARP/");
428  }
429  buf_printf(&out, "%s", print_in_addr_t(ntohl(maddr.v4.addr),
430  (flags & MAPF_IA_EMPTY_IF_UNDEF) ? IA_EMPTY_IF_UNDEF : 0, gc));
431  if (maddr.type & MR_WITH_NETBITS)
432  {
433  if (flags & MAPF_SUBNET)
434  {
435  const in_addr_t netmask = netbits_to_netmask(maddr.netbits);
436  buf_printf(&out, "/%s", print_in_addr_t(netmask, 0, gc));
437  }
438  else
439  {
440  buf_printf(&out, "/%d", maddr.netbits);
441  }
442  }
443  if (maddr.type & MR_WITH_PORT)
444  {
445  buf_printf(&out, ":%d", ntohs(maddr.v4.port));
446  }
447  }
448  break;
449 
450  case MR_ADDR_IPV6:
451  {
452  if (IN6_IS_ADDR_V4MAPPED( &maddr.v6.addr ) )
453  {
454  buf_printf(&out, "%s", print_in_addr_t(maddr.v4mappedv6.addr,
455  IA_NET_ORDER, gc));
456  }
457  else
458  {
459  buf_printf(&out, "%s", print_in6_addr(maddr.v6.addr, 0, gc));
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 
486 struct mroute_helper *
488 {
489  struct mroute_helper *mh;
490  ALLOC_OBJ_CLEAR(mh, struct mroute_helper);
492  return mh;
493 }
494 
495 static 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 
524 void
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 
539 void
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 void
557 {
558  free(mh);
559 }
560 
561 #else /* if P2MP_SERVER */
562 static void
563 dummy(void)
564 {
565 }
566 #endif /* P2MP_SERVER */
uint8_t type
Definition: mroute.h:80
#define MR_WITH_NETBITS
Definition: mroute.h:72
union openvpn_sockaddr::@6 addr
uint32_t daddr
Definition: proto.h:105
static bool mroute_is_mcast_ipv6(const struct in6_addr addr)
Definition: mroute.c:123
uint8_t protocol
Definition: proto.h:101
void mroute_addr_mask_host_bits(struct mroute_addr *ma)
Definition: mroute.c:345
static bool buf_advance(struct buffer *buf, int size)
Definition: buffer.h:613
#define IPV4_NETMASK_HOST
Definition: basic.h:35
const char * print_in6_addr(struct in6_addr a6, unsigned int flags, struct gc_arena *gc)
Definition: socket.c:2855
#define M_INFO
Definition: errlevel.h:55
#define MR_ADDR_ETHER
Definition: mroute.h:63
static void gc_free(struct gc_arena *a)
Definition: buffer.h:990
static bool check_debug_level(unsigned int level)
Definition: error.h:245
static void mroute_get_in6_addr(struct mroute_addr *ma, const struct in6_addr src, unsigned int mask)
Definition: mroute.c:102
#define MROUTE_EXTRACT_MCAST
Definition: mroute.h:42
bool mroute_addr_compare_function(const void *key1, const void *key2)
Definition: mroute.c:393
#define ASSERT(x)
Definition: error.h:221
static uint32_t mroute_addr_hash_len(const struct mroute_addr *a)
Definition: mroute.h:233
void mroute_helper_del_iroute46(struct mroute_helper *mh, int netbits)
Definition: mroute.c:540
#define MR_ADDR_MASK
Definition: mroute.h:66
static in_addr_t netbits_to_netmask(const int netbits)
Definition: route.h:367
uint32_t mroute_addr_hash_function(const void *key, uint32_t iv)
Definition: mroute.c:385
bool buf_printf(struct buffer *buf, const char *format,...)
Definition: buffer.c:223
#define CLEAR(x)
Definition: basic.h:33
const char * mroute_addr_print_ex(const struct mroute_addr *ma, const unsigned int flags, struct gc_arena *gc)
Definition: mroute.c:407
#define in_addr_t
Definition: config-msvc.h:104
bool mroute_learnable_address(const struct mroute_addr *addr)
Definition: mroute.c:68
#define MR_WITH_PORT
Definition: mroute.h:69
static void dummy(void)
Definition: comp-lz4.c:319
static bool mroute_is_mcast(const in_addr_t addr)
Definition: mroute.c:114
unsigned int cache_generation
Definition: mroute.h:131
struct mroute_addr::@0::@2 v6
uint8_t mac_addr_size
Definition: proto.h:71
#define IA_NET_ORDER
Definition: socket.h:394
#define OPENVPN_IPH_GET_VER(v)
Definition: proto.h:85
uint16_t proto
Definition: proto.h:63
#define IP_MCAST_SUBNET_MASK
Definition: mroute.h:35
struct in6_addr daddr
Definition: proto.h:120
void mroute_addr_init(struct mroute_addr *addr)
Definition: mroute.c:42
#define MROUTE_EXTRACT_IGMP
Definition: mroute.h:43
in_addr_t ip_src
Definition: proto.h:79
struct sockaddr_in6 in6
Definition: socket.h:70
unsigned int mroute_extract_addr_ether(struct mroute_addr *src, struct mroute_addr *dest, struct mroute_addr *esrc, struct mroute_addr *edest, const struct buffer *buf)
Definition: mroute.c:227
#define BPTR(buf)
Definition: buffer.h:124
#define IA_EMPTY_IF_UNDEF
Definition: socket.h:393
int net_len_refcount[MR_HELPER_NET_LEN]
Definition: mroute.h:135
#define MAPF_SHOW_ARP
Definition: mroute.h:157
const char * mroute_addr_print(const struct mroute_addr *ma, struct gc_arena *gc)
Definition: mroute.c:400
#define OPENVPN_ETH_P_IPV4
Definition: proto.h:60
int ageable_ttl_secs
Definition: mroute.h:132
static struct gc_arena gc_new(void)
Definition: buffer.h:982
#define ALLOC_OBJ_CLEAR(dptr, type)
Definition: buffer.h:1017
const char * print_in_addr_t(in_addr_t addr, unsigned int flags, struct gc_arena *gc)
Definition: socket.c:2835
bool mroute_extract_openvpn_sockaddr(struct mroute_addr *addr, const struct openvpn_sockaddr *osaddr, bool use_port)
Definition: mroute.c:288
#define MR_ARP
Definition: mroute.h:75
struct sockaddr_in in4
Definition: socket.h:69
#define D_MULTI_DEBUG
Definition: errlevel.h:123
unsigned __int32 uint32_t
Definition: config-msvc.h:121
uint8_t len
Definition: mroute.h:78
void mroute_helper_free(struct mroute_helper *mh)
Definition: mroute.c:556
struct in6_addr saddr
Definition: proto.h:119
#define MROUTE_EXTRACT_BCAST
Definition: mroute.h:41
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:460
#define IP_MCAST_NETWORK
Definition: mroute.h:36
static bool is_mac_mcast_maddr(const struct mroute_addr *addr)
Definition: mroute.c:58
#define MAPF_IA_EMPTY_IF_UNDEF
Definition: mroute.h:156
#define OPENVPN_ETH_P_ARP
Definition: proto.h:62
uint8_t proto_addr_size
Definition: proto.h:72
static void mroute_get_in_addr_t(struct mroute_addr *ma, const in_addr_t src, unsigned int mask)
Definition: mroute.c:90
#define dmsg
Definition: error.h:174
#define MR_ADDR_IPV4
Definition: mroute.h:64
uint8_t source[OPENVPN_ETH_ALEN]
Definition: proto.h:58
Container for bidirectional cipher and HMAC key material.
Definition: crypto.h:183
uint8_t dest[OPENVPN_ETH_ALEN]
Definition: proto.h:57
#define BLEN(buf)
Definition: buffer.h:127
in_addr_t ip_dest
Definition: proto.h:81
uint8_t raw_addr[MR_MAX_ADDR_LEN]
Definition: mroute.h:84
uint16_t proto_addr_type
Definition: proto.h:70
uint32_t hash_func(const uint8_t *k, uint32_t length, uint32_t initval)
Definition: list.c:602
unsigned __int8 uint8_t
Definition: config-msvc.h:123
uint32_t saddr
Definition: proto.h:104
#define MROUTE_EXTRACT_SUCCEEDED
Definition: mroute.h:40
struct mroute_helper * mroute_helper_init(int ageable_ttl_secs)
Definition: mroute.c:487
static const uint8_t * mroute_addr_hash_ptr(const struct mroute_addr *a)
Definition: mroute.h:226
#define msg
Definition: error.h:173
Wrapper structure for dynamically allocated memory.
Definition: buffer.h:60
void mroute_helper_add_iroute46(struct mroute_helper *mh, int netbits)
Definition: mroute.c:525
uint16_t mac_addr_type
Definition: proto.h:68
#define OPENVPN_IPPROTO_IGMP
Definition: proto.h:98
int n_net_len
Definition: mroute.h:133
#define MR_ADDR_IPV6
Definition: mroute.h:65
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition: buffer.c:88
uint8_t eth_addr[OPENVPN_ETH_ALEN]
Definition: mroute.h:85
static bool is_mac_mcast_addr(const uint8_t *mac)
Definition: mroute.c:52
Garbage collection arena used to keep track of dynamically allocated memory.
Definition: buffer.h:116
static void mroute_helper_regenerate(struct mroute_helper *mh)
Definition: mroute.c:496
static bool mroute_addr_equal(const struct mroute_addr *a1, const struct mroute_addr *a2)
Definition: mroute.h:208
#define MROUTE_SEC_SHIFT
Definition: mroute.h:50
#define BSTR(buf)
Definition: buffer.h:129
unsigned int mroute_extract_addr_ip(struct mroute_addr *src, struct mroute_addr *dest, const struct buffer *buf)
Definition: mroute.c:162
#define MAPF_SUBNET
Definition: mroute.h:155
uint8_t net_len[MR_HELPER_NET_LEN]
Definition: mroute.h:134
uint8_t netbits
Definition: mroute.h:81
char * dest
Definition: compat-lz4.h:431
struct sockaddr sa
Definition: socket.h:68
struct mroute_addr::@0::@3 v4mappedv6
#define M_WARN
Definition: error.h:96
#define MR_HELPER_NET_LEN
Definition: mroute.h:125
struct mroute_addr::@0::@1 v4
Container for unidirectional cipher and HMAC key material.
Definition: crypto.h:153