OpenVPN
socket_util.h
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#ifndef SOCKET_UTIL_H
24#define SOCKET_UTIL_H
25
26#include "buffer.h"
27#include "env_set.h"
28#include "sig.h"
29
30#define PS_SHOW_PORT_IF_DEFINED (1 << 0)
31#define PS_SHOW_PORT (1 << 1)
32#define PS_SHOW_PKTINFO (1 << 2)
33#define PS_DONT_SHOW_ADDR (1 << 3)
34#define PS_DONT_SHOW_FAMILY (1 << 4)
35
36/* OpenVPN sockaddr struct */
38{
39 /*int dummy;*/ /* add offset to force a bug if sa not explicitly dereferenced */
40 union
41 {
42 struct sockaddr sa;
43 struct sockaddr_in in4;
44 struct sockaddr_in6 in6;
46};
47
48/* actual address of remote, based on source address of received packets */
50{
51 /*int dummy;*/ /* add offset to force a bug if dest not explicitly dereferenced */
52
54#if ENABLE_IP_PKTINFO
55 union
56 {
57#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
58 struct in_pktinfo in4;
59#elif defined(IP_RECVDSTADDR)
60 struct in_addr in4;
61#endif
62 struct in6_pktinfo in6;
63 } pi;
64#endif
65};
66
67const char *print_sockaddr_ex(const struct sockaddr *addr, const char *separator,
68 const unsigned int flags, struct gc_arena *gc);
69
70static inline const char *
72{
73 return print_sockaddr_ex(&addr->addr.sa, ":", PS_SHOW_PORT, gc);
74}
75
76static inline const char *
77print_sockaddr(const struct sockaddr *addr, struct gc_arena *gc)
78{
79 return print_sockaddr_ex(addr, ":", PS_SHOW_PORT, gc);
80}
81
82
83const char *print_link_socket_actual_ex(const struct link_socket_actual *act, const char *separator,
84 const unsigned int flags, struct gc_arena *gc);
85
86const char *print_link_socket_actual(const struct link_socket_actual *act, struct gc_arena *gc);
87
88
89#define IA_EMPTY_IF_UNDEF (1 << 0)
90#define IA_NET_ORDER (1 << 1)
91const char *print_in_addr_t(in_addr_t addr, unsigned int flags, struct gc_arena *gc);
92
93const char *print_in6_addr(struct in6_addr addr6, unsigned int flags, struct gc_arena *gc);
94
95const char *print_in_port_t(in_port_t port, struct gc_arena *gc);
96
97struct in6_addr add_in6_addr(struct in6_addr base, uint32_t add);
98
99#define SA_IP_PORT (1 << 0)
100#define SA_SET_IF_NONZERO (1 << 1)
101void setenv_sockaddr(struct env_set *es, const char *name_prefix,
102 const struct openvpn_sockaddr *addr, const unsigned int flags);
103
104void setenv_in_addr_t(struct env_set *es, const char *name_prefix, in_addr_t addr,
105 const unsigned int flags);
106
107void setenv_in6_addr(struct env_set *es, const char *name_prefix, const struct in6_addr *addr,
108 const unsigned int flags);
109
110void setenv_link_socket_actual(struct env_set *es, const char *name_prefix,
111 const struct link_socket_actual *act, const unsigned int flags);
112
113/*
114 * DNS resolution
115 */
116
117#define GETADDR_RESOLVE (1 << 0)
118#define GETADDR_FATAL (1 << 1)
119#define GETADDR_HOST_ORDER (1 << 2)
120#define GETADDR_MENTION_RESOLVE_RETRY (1 << 3)
121#define GETADDR_FATAL_ON_SIGNAL (1 << 4)
122#define GETADDR_WARN_ON_SIGNAL (1 << 5)
123#define GETADDR_MSG_VIRT_OUT (1 << 6)
124#define GETADDR_TRY_ONCE (1 << 7)
125#define GETADDR_UPDATE_MANAGEMENT_STATE (1 << 8)
126#define GETADDR_RANDOMIZE (1 << 9)
127#define GETADDR_PASSIVE (1 << 10)
128#define GETADDR_DATAGRAM (1 << 11)
129
130#define GETADDR_CACHE_MASK (GETADDR_DATAGRAM | GETADDR_PASSIVE)
131
138in_addr_t getaddr(unsigned int flags, const char *hostname, int resolve_retry_seconds,
139 bool *succeeded, struct signal_info *sig_info);
140
144bool get_ipv6_addr(const char *hostname, struct in6_addr *network, unsigned int *netbits,
145 int msglevel);
146
147int openvpn_getaddrinfo(unsigned int flags, const char *hostname, const char *servname,
148 int resolve_retry_seconds, struct signal_info *sig_info, int ai_family,
149 struct addrinfo **res);
150
151/* return values of openvpn_inet_aton */
152#define OIA_HOSTNAME 0
153#define OIA_IP 1
154#define OIA_ERROR -1
155int openvpn_inet_aton(const char *dotted_quad, struct in_addr *addr);
156
157/* integrity validation on pulled options */
158bool ip_addr_dotted_quad_safe(const char *dotted_quad);
159
160bool ip_or_dns_addr_safe(const char *addr, const bool allow_fqdn);
161
162bool mac_addr_safe(const char *mac_addr);
163
164bool ipv6_addr_safe(const char *ipv6_text_addr);
165
166/*
167 * Transport protocol naming and other details.
168 */
169
170/*
171 * Use enum's instead of #define to allow for easier
172 * optional proto support
173 */
183
184static inline bool
185proto_is_net(int proto)
186{
187 ASSERT(proto >= 0 && proto < PROTO_N);
188 return proto != PROTO_NONE;
189}
190
194static inline bool
195proto_is_udp(int proto)
196{
197 ASSERT(proto >= 0 && proto < PROTO_N);
198 return proto == PROTO_UDP;
199}
200
205static inline bool
207{
208 return proto_is_udp(proto);
209}
210
214static inline bool
215proto_is_tcp(int proto)
216{
217 ASSERT(proto >= 0 && proto < PROTO_N);
218 return proto == PROTO_TCP_CLIENT || proto == PROTO_TCP_SERVER;
219}
220
221int ascii2proto(const char *proto_name);
222
223sa_family_t ascii2af(const char *proto_name);
224
225const char *proto2ascii(int proto, sa_family_t af, bool display_form);
226
227const char *proto2ascii_all(struct gc_arena *gc);
228
229const char *proto_remote(int proto, bool remote);
230
231const char *addr_family_name(int af);
232
233static inline bool
235{
236 if (!addr)
237 {
238 return 0;
239 }
240 switch (addr->addr.sa.sa_family)
241 {
242 case AF_INET:
243 return addr->addr.in4.sin_addr.s_addr != 0;
244
245 case AF_INET6:
246 return !IN6_IS_ADDR_UNSPECIFIED(&addr->addr.in6.sin6_addr);
247
248 default:
249 return 0;
250 }
251}
252
253static inline bool
254addr_local(const struct sockaddr *addr)
255{
256 if (!addr)
257 {
258 return false;
259 }
260 switch (addr->sa_family)
261 {
262 case AF_INET:
263 return ((const struct sockaddr_in *)addr)->sin_addr.s_addr == htonl(INADDR_LOOPBACK);
264
265 case AF_INET6:
266 return IN6_IS_ADDR_LOOPBACK(&((const struct sockaddr_in6 *)addr)->sin6_addr);
267
268 default:
269 return false;
270 }
271}
272
273
274static inline bool
276{
277#if ENABLE_IP_PKTINFO
278 if (!lsa)
279 {
280 return 0;
281 }
282 switch (lsa->dest.addr.sa.sa_family)
283 {
284#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
285 case AF_INET:
286 return lsa->pi.in4.ipi_spec_dst.s_addr != 0;
287
288#elif defined(IP_RECVDSTADDR)
289 case AF_INET:
290 return lsa->pi.in4.s_addr != 0;
291
292#endif
293 case AF_INET6:
294 return !IN6_IS_ADDR_UNSPECIFIED(&lsa->pi.in6.ipi6_addr);
295
296 default:
297 return 0;
298 }
299#else /* if ENABLE_IP_PKTINFO */
300 ASSERT(0);
301#endif
302 return false;
303}
304
305/*
306 * Overhead added to packets by various protocols.
307 */
308static inline int
310{
311 int overhead = 0;
312 overhead += (proto == PROTO_UDP) ? 8 : 20;
313 overhead += (af == AF_INET) ? 20 : 40;
314 return overhead;
315}
316
317/*
318 * Misc inline functions
319 */
320
321static inline bool
323{
324 return !proto_is_dgram(proto);
325}
326
327static inline bool
329{
330 return act && addr_defined(&act->dest);
331}
332
333static inline bool
334addr_match(const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2)
335{
336 switch (a1->addr.sa.sa_family)
337 {
338 case AF_INET:
339 return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr;
340
341 case AF_INET6:
342 return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr);
343 }
344 ASSERT(0);
345 return false;
346}
347
348static inline bool
349addrlist_match(const struct openvpn_sockaddr *a1, const struct addrinfo *addrlist)
350{
351 const struct addrinfo *curele;
352 for (curele = addrlist; curele; curele = curele->ai_next)
353 {
354 switch (a1->addr.sa.sa_family)
355 {
356 case AF_INET:
357 if (a1->addr.in4.sin_addr.s_addr
358 == ((struct sockaddr_in *)curele->ai_addr)->sin_addr.s_addr)
359 {
360 return true;
361 }
362 break;
363
364 case AF_INET6:
365 if (IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr,
366 &((struct sockaddr_in6 *)curele->ai_addr)->sin6_addr))
367 {
368 return true;
369 }
370 break;
371
372 default:
373 ASSERT(0);
374 }
375 }
376 return false;
377}
378
379static inline bool
380addrlist_port_match(const struct openvpn_sockaddr *a1, const struct addrinfo *a2)
381{
382 const struct addrinfo *curele;
383 for (curele = a2; curele; curele = curele->ai_next)
384 {
385 switch (a1->addr.sa.sa_family)
386 {
387 case AF_INET:
388 if (curele->ai_family == AF_INET
389 && a1->addr.in4.sin_addr.s_addr
390 == ((struct sockaddr_in *)curele->ai_addr)->sin_addr.s_addr
391 && a1->addr.in4.sin_port == ((struct sockaddr_in *)curele->ai_addr)->sin_port)
392 {
393 return true;
394 }
395 break;
396
397 case AF_INET6:
398 if (curele->ai_family == AF_INET6
399 && IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr,
400 &((struct sockaddr_in6 *)curele->ai_addr)->sin6_addr)
401 && a1->addr.in6.sin6_port
402 == ((struct sockaddr_in6 *)curele->ai_addr)->sin6_port)
403 {
404 return true;
405 }
406 break;
407
408 default:
409 ASSERT(0);
410 }
411 }
412 return false;
413}
414
415
416static inline bool
417addr_port_match(const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2)
418{
419 switch (a1->addr.sa.sa_family)
420 {
421 case AF_INET:
422 return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr
423 && a1->addr.in4.sin_port == a2->addr.in4.sin_port;
424
425 case AF_INET6:
426 return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr)
427 && a1->addr.in6.sin6_port == a2->addr.in6.sin6_port;
428 }
429 ASSERT(0);
430 return false;
431}
432
433static inline bool
434addr_match_proto(const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2,
435 const int proto)
436{
438 : addr_port_match(a1, a2);
439}
440
441
442static inline bool
443addrlist_match_proto(const struct openvpn_sockaddr *a1, struct addrinfo *addr_list, const int proto)
444{
445 return link_socket_proto_connection_oriented(proto) ? addrlist_match(a1, addr_list)
446 : addrlist_port_match(a1, addr_list);
447}
448
449static inline void
451{
452 switch (addr->addr.sa.sa_family)
453 {
454 case AF_INET:
455 addr->addr.in4.sin_addr.s_addr = 0;
456 break;
457
458 case AF_INET6:
459 memset(&addr->addr.in6.sin6_addr, 0, sizeof(struct in6_addr));
460 break;
461 }
462}
463
464static inline int
466{
467 switch (af)
468 {
469 case AF_INET:
470 return sizeof(struct sockaddr_in);
471
472 case AF_INET6:
473 return sizeof(struct sockaddr_in6);
474
475 default:
476#if 0
477 /* could be called from socket_do_accept() with empty addr */
478 msg(M_ERR, "Bad address family: %d", af);
479 ASSERT(0);
480#endif
481 return 0;
482 }
483}
484
485static inline bool
487{
488 return addr_port_match(&a1->dest, &a2->dest);
489}
490
491#endif
#define M_ERR
Definition error.h:104
#define msg(flags,...)
Definition error.h:150
#define ASSERT(x)
Definition error.h:217
static bool addr_port_match(const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2)
static const char * print_sockaddr(const struct sockaddr *addr, struct gc_arena *gc)
Definition socket_util.h:77
static bool link_socket_actual_defined(const struct link_socket_actual *act)
static bool addr_match_proto(const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2, const int proto)
const char * proto2ascii(int proto, sa_family_t af, bool display_form)
bool get_ipv6_addr(const char *hostname, struct in6_addr *network, unsigned int *netbits, int msglevel)
Translate an IPv6 addr or hostname from string form to in6_addr.
Definition socket.c:214
static const char * print_openvpn_sockaddr(const struct openvpn_sockaddr *addr, struct gc_arena *gc)
Definition socket_util.h:71
static int datagram_overhead(sa_family_t af, int proto)
static bool proto_is_net(int proto)
int openvpn_getaddrinfo(unsigned int flags, const char *hostname, const char *servname, int resolve_retry_seconds, struct signal_info *sig_info, int ai_family, struct addrinfo **res)
static bool proto_is_udp(int proto)
Returns if the protocol being used is UDP.
static bool link_socket_actual_match(const struct link_socket_actual *a1, const struct link_socket_actual *a2)
static bool addr_local(const struct sockaddr *addr)
bool mac_addr_safe(const char *mac_addr)
#define PS_SHOW_PORT
Definition socket_util.h:31
void setenv_in_addr_t(struct env_set *es, const char *name_prefix, in_addr_t addr, const unsigned int flags)
proto_num
@ PROTO_NONE
@ PROTO_UDP
@ PROTO_TCP
@ PROTO_TCP_CLIENT
@ PROTO_N
@ PROTO_TCP_SERVER
const char * print_in_port_t(in_port_t port, struct gc_arena *gc)
const char * proto2ascii_all(struct gc_arena *gc)
void setenv_link_socket_actual(struct env_set *es, const char *name_prefix, const struct link_socket_actual *act, const unsigned int flags)
void setenv_in6_addr(struct env_set *es, const char *name_prefix, const struct in6_addr *addr, const unsigned int flags)
const char * print_link_socket_actual(const struct link_socket_actual *act, struct gc_arena *gc)
static bool proto_is_tcp(int proto)
returns if the proto is a TCP variant (tcp-server, tcp-client or tcp)
static void addr_zero_host(struct openvpn_sockaddr *addr)
void setenv_sockaddr(struct env_set *es, const char *name_prefix, const struct openvpn_sockaddr *addr, const unsigned int flags)
static bool addr_defined_ipi(const struct link_socket_actual *lsa)
const char * print_link_socket_actual_ex(const struct link_socket_actual *act, const char *separator, const unsigned int flags, struct gc_arena *gc)
struct in6_addr add_in6_addr(struct in6_addr base, uint32_t add)
static bool proto_is_dgram(int proto)
Return if the protocol is datagram (UDP)
sa_family_t ascii2af(const char *proto_name)
static int af_addr_size(sa_family_t af)
int openvpn_inet_aton(const char *dotted_quad, struct in_addr *addr)
static bool addr_defined(const struct openvpn_sockaddr *addr)
const char * proto_remote(int proto, bool remote)
bool ipv6_addr_safe(const char *ipv6_text_addr)
bool ip_or_dns_addr_safe(const char *addr, const bool allow_fqdn)
int ascii2proto(const char *proto_name)
const char * print_in_addr_t(in_addr_t addr, unsigned int flags, struct gc_arena *gc)
static bool addrlist_port_match(const struct openvpn_sockaddr *a1, const struct addrinfo *a2)
const char * print_sockaddr_ex(const struct sockaddr *addr, const char *separator, const unsigned int flags, struct gc_arena *gc)
Definition socket_util.c:38
in_addr_t getaddr(unsigned int flags, const char *hostname, int resolve_retry_seconds, bool *succeeded, struct signal_info *sig_info)
Translate an IPv4 addr or hostname from string form to in_addr_t.
Definition socket.c:187
static bool addr_match(const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2)
const char * addr_family_name(int af)
const char * print_in6_addr(struct in6_addr addr6, unsigned int flags, struct gc_arena *gc)
static bool addrlist_match(const struct openvpn_sockaddr *a1, const struct addrinfo *addrlist)
bool ip_addr_dotted_quad_safe(const char *dotted_quad)
static bool link_socket_proto_connection_oriented(int proto)
static bool addrlist_match_proto(const struct openvpn_sockaddr *a1, struct addrinfo *addr_list, const int proto)
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:116
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
unsigned short sa_family_t
Definition syshead.h:396
struct env_set * es
char ** res
struct gc_arena gc
Definition test_ssl.c:154
#define IN6_ARE_ADDR_EQUAL(a, b)
Definition win32.h:52