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/* return values of openvpn_inet_aton */
114#define OIA_HOSTNAME 0
115#define OIA_IP 1
116#define OIA_ERROR -1
117int openvpn_inet_aton(const char *dotted_quad, struct in_addr *addr);
118
119/* integrity validation on pulled options */
120bool ip_addr_dotted_quad_safe(const char *dotted_quad);
121
122bool ip_or_dns_addr_safe(const char *addr, const bool allow_fqdn);
123
124bool mac_addr_safe(const char *mac_addr);
125
126bool ipv6_addr_safe(const char *ipv6_text_addr);
127
128/*
129 * Transport protocol naming and other details.
130 */
131
132/*
133 * Use enum's instead of #define to allow for easier
134 * optional proto support
135 */
145
146static inline bool
147proto_is_net(int proto)
148{
149 ASSERT(proto >= 0 && proto < PROTO_N);
150 return proto != PROTO_NONE;
151}
152
156static inline bool
157proto_is_udp(int proto)
158{
159 ASSERT(proto >= 0 && proto < PROTO_N);
160 return proto == PROTO_UDP;
161}
162
167static inline bool
169{
170 return proto_is_udp(proto);
171}
172
176static inline bool
177proto_is_tcp(int proto)
178{
179 ASSERT(proto >= 0 && proto < PROTO_N);
180 return proto == PROTO_TCP_CLIENT || proto == PROTO_TCP_SERVER;
181}
182
183int ascii2proto(const char *proto_name);
184
185sa_family_t ascii2af(const char *proto_name);
186
187const char *proto2ascii(int proto, sa_family_t af, bool display_form);
188
189const char *proto2ascii_all(struct gc_arena *gc);
190
191const char *proto_remote(int proto, bool remote);
192
193const char *addr_family_name(int af);
194
195static inline bool
197{
198 if (!addr)
199 {
200 return 0;
201 }
202 switch (addr->addr.sa.sa_family)
203 {
204 case AF_INET:
205 return addr->addr.in4.sin_addr.s_addr != 0;
206
207 case AF_INET6:
208 return !IN6_IS_ADDR_UNSPECIFIED(&addr->addr.in6.sin6_addr);
209
210 default:
211 return 0;
212 }
213}
214
215#ifdef TARGET_ANDROID
216static inline bool
217addr_local(const struct sockaddr *addr)
218{
219 if (!addr)
220 {
221 return false;
222 }
223 switch (addr->sa_family)
224 {
225 case AF_INET:
226 return ((const struct sockaddr_in *)addr)->sin_addr.s_addr == htonl(INADDR_LOOPBACK);
227
228 case AF_INET6:
229 return IN6_IS_ADDR_LOOPBACK(&((const struct sockaddr_in6 *)addr)->sin6_addr);
230
231 default:
232 return false;
233 }
234}
235#endif
236
237#if ENABLE_IP_PKTINFO
238static inline bool
239addr_defined_ipi(const struct link_socket_actual *lsa)
240{
241 if (!lsa)
242 {
243 return 0;
244 }
245 switch (lsa->dest.addr.sa.sa_family)
246 {
247#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
248 case AF_INET:
249 return lsa->pi.in4.ipi_spec_dst.s_addr != 0;
250
251#elif defined(IP_RECVDSTADDR)
252 case AF_INET:
253 return lsa->pi.in4.s_addr != 0;
254
255#endif
256 case AF_INET6:
257 return !IN6_IS_ADDR_UNSPECIFIED(&lsa->pi.in6.ipi6_addr);
258
259 default:
260 return 0;
261 }
262 return false;
263}
264#endif
265
269static inline int
271{
272 int overhead = 0;
273 overhead += (proto == PROTO_UDP) ? 8 : 20;
274 overhead += (af == AF_INET) ? 20 : 40;
275 return overhead;
276}
277
278/*
279 * Misc inline functions
280 */
281
282static inline bool
284{
285 return !proto_is_dgram(proto);
286}
287
288static inline bool
290{
291 return act && addr_defined(&act->dest);
292}
293
294static inline bool
295addr_match(const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2)
296{
297 switch (a1->addr.sa.sa_family)
298 {
299 case AF_INET:
300 return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr;
301
302 case AF_INET6:
303 return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr);
304 }
305 ASSERT(0);
306 return false;
307}
308
309static inline bool
310addrlist_match(const struct openvpn_sockaddr *a1, const struct addrinfo *addrlist)
311{
312 const struct addrinfo *curele;
313 for (curele = addrlist; curele; curele = curele->ai_next)
314 {
315 switch (a1->addr.sa.sa_family)
316 {
317 case AF_INET:
318 if (a1->addr.in4.sin_addr.s_addr
319 == ((struct sockaddr_in *)curele->ai_addr)->sin_addr.s_addr)
320 {
321 return true;
322 }
323 break;
324
325 case AF_INET6:
326 if (IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr,
327 &((struct sockaddr_in6 *)curele->ai_addr)->sin6_addr))
328 {
329 return true;
330 }
331 break;
332
333 default:
334 ASSERT(0);
335 }
336 }
337 return false;
338}
339
340static inline bool
341addrlist_port_match(const struct openvpn_sockaddr *a1, const struct addrinfo *a2)
342{
343 const struct addrinfo *curele;
344 for (curele = a2; curele; curele = curele->ai_next)
345 {
346 switch (a1->addr.sa.sa_family)
347 {
348 case AF_INET:
349 if (curele->ai_family == AF_INET
350 && a1->addr.in4.sin_addr.s_addr
351 == ((struct sockaddr_in *)curele->ai_addr)->sin_addr.s_addr
352 && a1->addr.in4.sin_port == ((struct sockaddr_in *)curele->ai_addr)->sin_port)
353 {
354 return true;
355 }
356 break;
357
358 case AF_INET6:
359 if (curele->ai_family == AF_INET6
360 && IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr,
361 &((struct sockaddr_in6 *)curele->ai_addr)->sin6_addr)
362 && a1->addr.in6.sin6_port
363 == ((struct sockaddr_in6 *)curele->ai_addr)->sin6_port)
364 {
365 return true;
366 }
367 break;
368
369 default:
370 ASSERT(0);
371 }
372 }
373 return false;
374}
375
376
377static inline bool
378addr_port_match(const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2)
379{
380 switch (a1->addr.sa.sa_family)
381 {
382 case AF_INET:
383 return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr
384 && a1->addr.in4.sin_port == a2->addr.in4.sin_port;
385
386 case AF_INET6:
387 return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr)
388 && a1->addr.in6.sin6_port == a2->addr.in6.sin6_port;
389 }
390 ASSERT(0);
391 return false;
392}
393
394static inline bool
395addr_match_proto(const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2,
396 const int proto)
397{
399 : addr_port_match(a1, a2);
400}
401
402
403static inline bool
404addrlist_match_proto(const struct openvpn_sockaddr *a1, const struct addrinfo *addr_list, const int proto)
405{
406 return link_socket_proto_connection_oriented(proto) ? addrlist_match(a1, addr_list)
407 : addrlist_port_match(a1, addr_list);
408}
409
410static inline void
412{
413 switch (addr->addr.sa.sa_family)
414 {
415 case AF_INET:
416 addr->addr.in4.sin_addr.s_addr = 0;
417 break;
418
419 case AF_INET6:
420 memset(&addr->addr.in6.sin6_addr, 0, sizeof(struct in6_addr));
421 break;
422 }
423}
424
425static inline int
427{
428 switch (af)
429 {
430 case AF_INET:
431 return sizeof(struct sockaddr_in);
432
433 case AF_INET6:
434 return sizeof(struct sockaddr_in6);
435
436 default:
437#if 0
438 /* could be called from socket_do_accept() with empty addr */
439 msg(M_ERR, "Bad address family: %d", af);
440 ASSERT(0);
441#endif
442 return 0;
443 }
444}
445
446static inline bool
448{
449 return addr_port_match(&a1->dest, &a2->dest);
450}
451
452#endif
Buffer management functions and garbage collection.
#define M_ERR
Definition error.h:106
#define msg(flags,...)
Definition error.h:152
#define ASSERT(x)
Definition error.h:221
struct in6_addr add_in6_addr(struct in6_addr base, uint32_t add)
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)
Overhead added to packets by various protocols.
static bool proto_is_net(int proto)
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 addrlist_match_proto(const struct openvpn_sockaddr *a1, const struct addrinfo *addr_list, const int proto)
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)
const char * print_link_socket_actual_ex(const struct link_socket_actual *act, const char *separator, const unsigned int flags, struct gc_arena *gc)
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
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)
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:127
union openvpn_sockaddr::@051240265251124304325377241125360350250341115171 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 gc_arena gc
Definition test_ssl.c:122
#define IN6_ARE_ADDR_EQUAL(a, b)
Definition win32.h:52