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-2026 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 (1u << 0)
118#define GETADDR_FATAL (1u << 1)
119#define GETADDR_HOST_ORDER (1u << 2)
120#define GETADDR_MENTION_RESOLVE_RETRY (1u << 3)
121#define GETADDR_FATAL_ON_SIGNAL (1u << 4)
122#define GETADDR_WARN_ON_SIGNAL (1u << 5)
123#define GETADDR_MSG_VIRT_OUT (1u << 6)
124#define GETADDR_TRY_ONCE (1u << 7)
125#define GETADDR_UPDATE_MANAGEMENT_STATE (1u << 8)
126#define GETADDR_RANDOMIZE (1u << 9)
127#define GETADDR_PASSIVE (1u << 10)
128#define GETADDR_DATAGRAM (1u << 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 msglvl_t 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
253#ifdef TARGET_ANDROID
254static inline bool
255addr_local(const struct sockaddr *addr)
256{
257 if (!addr)
258 {
259 return false;
260 }
261 switch (addr->sa_family)
262 {
263 case AF_INET:
264 return ((const struct sockaddr_in *)addr)->sin_addr.s_addr == htonl(INADDR_LOOPBACK);
265
266 case AF_INET6:
267 return IN6_IS_ADDR_LOOPBACK(&((const struct sockaddr_in6 *)addr)->sin6_addr);
268
269 default:
270 return false;
271 }
272}
273#endif
274
275#if ENABLE_IP_PKTINFO
276static inline bool
277addr_defined_ipi(const struct link_socket_actual *lsa)
278{
279 if (!lsa)
280 {
281 return 0;
282 }
283 switch (lsa->dest.addr.sa.sa_family)
284 {
285#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
286 case AF_INET:
287 return lsa->pi.in4.ipi_spec_dst.s_addr != 0;
288
289#elif defined(IP_RECVDSTADDR)
290 case AF_INET:
291 return lsa->pi.in4.s_addr != 0;
292
293#endif
294 case AF_INET6:
295 return !IN6_IS_ADDR_UNSPECIFIED(&lsa->pi.in6.ipi6_addr);
296
297 default:
298 return 0;
299 }
300 return false;
301}
302#endif
303
304/*
305 * Overhead added to packets by various protocols.
306 */
307static inline int
309{
310 int overhead = 0;
311 overhead += (proto == PROTO_UDP) ? 8 : 20;
312 overhead += (af == AF_INET) ? 20 : 40;
313 return overhead;
314}
315
316/*
317 * Misc inline functions
318 */
319
320static inline bool
322{
323 return !proto_is_dgram(proto);
324}
325
326static inline bool
328{
329 return act && addr_defined(&act->dest);
330}
331
332static inline bool
333addr_match(const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2)
334{
335 switch (a1->addr.sa.sa_family)
336 {
337 case AF_INET:
338 return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr;
339
340 case AF_INET6:
341 return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr);
342 }
343 ASSERT(0);
344 return false;
345}
346
347static inline bool
348addrlist_match(const struct openvpn_sockaddr *a1, const struct addrinfo *addrlist)
349{
350 const struct addrinfo *curele;
351 for (curele = addrlist; curele; curele = curele->ai_next)
352 {
353 switch (a1->addr.sa.sa_family)
354 {
355 case AF_INET:
356 if (a1->addr.in4.sin_addr.s_addr
357 == ((struct sockaddr_in *)curele->ai_addr)->sin_addr.s_addr)
358 {
359 return true;
360 }
361 break;
362
363 case AF_INET6:
364 if (IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr,
365 &((struct sockaddr_in6 *)curele->ai_addr)->sin6_addr))
366 {
367 return true;
368 }
369 break;
370
371 default:
372 ASSERT(0);
373 }
374 }
375 return false;
376}
377
378static inline bool
379addrlist_port_match(const struct openvpn_sockaddr *a1, const struct addrinfo *a2)
380{
381 const struct addrinfo *curele;
382 for (curele = a2; curele; curele = curele->ai_next)
383 {
384 switch (a1->addr.sa.sa_family)
385 {
386 case AF_INET:
387 if (curele->ai_family == AF_INET
388 && a1->addr.in4.sin_addr.s_addr
389 == ((struct sockaddr_in *)curele->ai_addr)->sin_addr.s_addr
390 && a1->addr.in4.sin_port == ((struct sockaddr_in *)curele->ai_addr)->sin_port)
391 {
392 return true;
393 }
394 break;
395
396 case AF_INET6:
397 if (curele->ai_family == AF_INET6
398 && IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr,
399 &((struct sockaddr_in6 *)curele->ai_addr)->sin6_addr)
400 && a1->addr.in6.sin6_port
401 == ((struct sockaddr_in6 *)curele->ai_addr)->sin6_port)
402 {
403 return true;
404 }
405 break;
406
407 default:
408 ASSERT(0);
409 }
410 }
411 return false;
412}
413
414
415static inline bool
416addr_port_match(const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2)
417{
418 switch (a1->addr.sa.sa_family)
419 {
420 case AF_INET:
421 return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr
422 && a1->addr.in4.sin_port == a2->addr.in4.sin_port;
423
424 case AF_INET6:
425 return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr)
426 && a1->addr.in6.sin6_port == a2->addr.in6.sin6_port;
427 }
428 ASSERT(0);
429 return false;
430}
431
432static inline bool
433addr_match_proto(const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2,
434 const int proto)
435{
437 : addr_port_match(a1, a2);
438}
439
440
441static inline bool
442addrlist_match_proto(const struct openvpn_sockaddr *a1, struct addrinfo *addr_list, const int proto)
443{
444 return link_socket_proto_connection_oriented(proto) ? addrlist_match(a1, addr_list)
445 : addrlist_port_match(a1, addr_list);
446}
447
448static inline void
450{
451 switch (addr->addr.sa.sa_family)
452 {
453 case AF_INET:
454 addr->addr.in4.sin_addr.s_addr = 0;
455 break;
456
457 case AF_INET6:
458 memset(&addr->addr.in6.sin6_addr, 0, sizeof(struct in6_addr));
459 break;
460 }
461}
462
463static inline int
465{
466 switch (af)
467 {
468 case AF_INET:
469 return sizeof(struct sockaddr_in);
470
471 case AF_INET6:
472 return sizeof(struct sockaddr_in6);
473
474 default:
475#if 0
476 /* could be called from socket_do_accept() with empty addr */
477 msg(M_ERR, "Bad address family: %d", af);
478 ASSERT(0);
479#endif
480 return 0;
481 }
482}
483
484static inline bool
486{
487 return addr_port_match(&a1->dest, &a2->dest);
488}
489
490#endif
Buffer management functions and garbage collection.
#define M_ERR
Definition error.h:106
#define msg(flags,...)
Definition error.h:152
unsigned int msglvl_t
Definition error.h:77
#define ASSERT(x)
Definition error.h:219
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)
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)
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)
bool get_ipv6_addr(const char *hostname, struct in6_addr *network, unsigned int *netbits, msglvl_t msglevel)
Translate an IPv6 addr or hostname from string form to in6_addr.
Definition socket.c:222
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:195
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:127
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:409
uint16_t in_port_t
Definition syshead.h:53
uint32_t in_addr_t
Definition syshead.h:52
struct env_set * es
struct gc_arena gc
Definition test_ssl.c:122
#define IN6_ARE_ADDR_EQUAL(a, b)
Definition win32.h:52