OpenVPN
socket_util.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-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#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#include "syshead.h"
28
29#include "socket_util.h"
30#include "crypto.h"
31#include "manage.h"
32
33/*
34 * Format IP addresses in ascii
35 */
36
37const char *
38print_sockaddr_ex(const struct sockaddr *sa, const char *separator, const unsigned int flags,
39 struct gc_arena *gc)
40{
41 struct buffer out = alloc_buf_gc(128, gc);
42 bool addr_is_defined = false;
43 char hostaddr[NI_MAXHOST] = "";
44 char servname[NI_MAXSERV] = "";
45 int status;
46
47 socklen_t salen = 0;
48 switch (sa->sa_family)
49 {
50 case AF_INET:
51 if (!(flags & PS_DONT_SHOW_FAMILY))
52 {
53 buf_puts(&out, "[AF_INET]");
54 }
55 salen = sizeof(struct sockaddr_in);
56 addr_is_defined = ((struct sockaddr_in *)sa)->sin_addr.s_addr != 0;
57 break;
58
59 case AF_INET6:
60 if (!(flags & PS_DONT_SHOW_FAMILY))
61 {
62 buf_puts(&out, "[AF_INET6]");
63 }
64 salen = sizeof(struct sockaddr_in6);
65 addr_is_defined = !IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)sa)->sin6_addr);
66 break;
67
68 case AF_UNSPEC:
69 if (!(flags & PS_DONT_SHOW_FAMILY))
70 {
71 return "[AF_UNSPEC]";
72 }
73 else
74 {
75 return "";
76 }
77
78 default:
79 ASSERT(0);
80 }
81
82 status = getnameinfo(sa, salen, hostaddr, sizeof(hostaddr), servname, sizeof(servname),
83 NI_NUMERICHOST | NI_NUMERICSERV);
84
85 if (status != 0)
86 {
87 buf_printf(&out, "[nameinfo() err: %s]", gai_strerror(status));
88 return BSTR(&out);
89 }
90
91 if (!(flags & PS_DONT_SHOW_ADDR))
92 {
93 if (addr_is_defined)
94 {
95 buf_puts(&out, hostaddr);
96 }
97 else
98 {
99 buf_puts(&out, "[undef]");
100 }
101 }
102
103 if ((flags & PS_SHOW_PORT) || (flags & PS_SHOW_PORT_IF_DEFINED))
104 {
105 if (separator)
106 {
107 buf_puts(&out, separator);
108 }
109
110 buf_puts(&out, servname);
111 }
112
113 return BSTR(&out);
114}
115
116const char *
121
122#ifndef IF_NAMESIZE
123#define IF_NAMESIZE 16
124#endif
125
126const char *
127print_link_socket_actual_ex(const struct link_socket_actual *act, const char *separator,
128 const unsigned int flags, struct gc_arena *gc)
129{
130 if (act)
131 {
132 struct buffer out = alloc_buf_gc(128, gc);
133 buf_printf(&out, "%s", print_sockaddr_ex(&act->dest.addr.sa, separator, flags, gc));
134#if ENABLE_IP_PKTINFO
135 char ifname[IF_NAMESIZE] = "[undef]";
136
137 if ((flags & PS_SHOW_PKTINFO) && addr_defined_ipi(act))
138 {
139 switch (act->dest.addr.sa.sa_family)
140 {
141 case AF_INET:
142 {
143 struct openvpn_sockaddr sa;
144 CLEAR(sa);
145 sa.addr.in4.sin_family = AF_INET;
146#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
147 sa.addr.in4.sin_addr = act->pi.in4.ipi_spec_dst;
148 if_indextoname(act->pi.in4.ipi_ifindex, ifname);
149#elif defined(IP_RECVDSTADDR)
150 sa.addr.in4.sin_addr = act->pi.in4;
151 ifname[0] = 0;
152#else /* if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) */
153#error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
154#endif
155 buf_printf(&out, " (via %s%%%s)",
156 print_sockaddr_ex(&sa.addr.sa, separator, 0, gc), ifname);
157 }
158 break;
159
160 case AF_INET6:
161 {
162 struct sockaddr_in6 sin6;
163 char buf[INET6_ADDRSTRLEN] = "[undef]";
164 CLEAR(sin6);
165 sin6.sin6_family = AF_INET6;
166 sin6.sin6_addr = act->pi.in6.ipi6_addr;
167 if_indextoname(act->pi.in6.ipi6_ifindex, ifname);
168 if (getnameinfo((struct sockaddr *)&sin6, sizeof(struct sockaddr_in6), buf,
169 sizeof(buf), NULL, 0, NI_NUMERICHOST)
170 == 0)
171 {
172 buf_printf(&out, " (via %s%%%s)", buf, ifname);
173 }
174 else
175 {
176 buf_printf(&out, " (via [getnameinfo() err]%%%s)", ifname);
177 }
178 }
179 break;
180 }
181 }
182#endif /* if ENABLE_IP_PKTINFO */
183 return BSTR(&out);
184 }
185 else
186 {
187 return "[NULL]";
188 }
189}
190
191/*
192 * Convert an in_addr_t in host byte order
193 * to an ascii dotted quad.
194 */
195const char *
196print_in_addr_t(in_addr_t addr, unsigned int flags, struct gc_arena *gc)
197{
198 struct in_addr ia;
199 char *out = gc_malloc(INET_ADDRSTRLEN, true, gc);
200
201 if (addr || !(flags & IA_EMPTY_IF_UNDEF))
202 {
203 CLEAR(ia);
204 ia.s_addr = (flags & IA_NET_ORDER) ? addr : htonl(addr);
205
206 inet_ntop(AF_INET, &ia, out, INET_ADDRSTRLEN);
207 }
208 return out;
209}
210
211/*
212 * Convert an in6_addr in host byte order
213 * to an ascii representation of an IPv6 address
214 */
215const char *
216print_in6_addr(struct in6_addr a6, unsigned int flags, struct gc_arena *gc)
217{
218 char *out = gc_malloc(INET6_ADDRSTRLEN, true, gc);
219
220 if (memcmp(&a6, &in6addr_any, sizeof(a6)) != 0 || !(flags & IA_EMPTY_IF_UNDEF))
221 {
222 inet_ntop(AF_INET6, &a6, out, INET6_ADDRSTRLEN);
223 }
224 return out;
225}
226
227/*
228 * Convert an in_port_t in host byte order to a string
229 */
230const char *
232{
233 struct buffer buffer = alloc_buf_gc(8, gc);
234 buf_printf(&buffer, "%hu", port);
235 return BSTR(&buffer);
236}
237
238/* add some offset to an ipv6 address
239 * (add in steps of 8 bits, taking overflow into next round)
240 */
241struct in6_addr
242add_in6_addr(struct in6_addr base, uint32_t add)
243{
244 for (int i = 15; i >= 0 && add > 0; i--)
245 {
246 register uint32_t carry;
247 register uint32_t h;
248
249 h = base.s6_addr[i];
250 base.s6_addr[i] = (h + add) & UINT8_MAX;
251
252 /* using explicit carry for the 8-bit additions will catch
253 * 8-bit and(!) 32-bit overruns nicely
254 */
255 carry = ((h & 0xff) + (add & 0xff)) >> 8;
256 add = (add >> 8) + carry;
257 }
258 return base;
259}
260
261/* set environmental variables for ip/port in *addr */
262void
263setenv_sockaddr(struct env_set *es, const char *name_prefix, const struct openvpn_sockaddr *addr,
264 const unsigned int flags)
265{
266 char name_buf[256];
267
268 char buf[INET6_ADDRSTRLEN];
269 switch (addr->addr.sa.sa_family)
270 {
271 case AF_INET:
272 if (flags & SA_IP_PORT)
273 {
274 snprintf(name_buf, sizeof(name_buf), "%s_ip", name_prefix);
275 }
276 else
277 {
278 snprintf(name_buf, sizeof(name_buf), "%s", name_prefix);
279 }
280
281 inet_ntop(AF_INET, &addr->addr.in4.sin_addr, buf, sizeof(buf));
282 setenv_str(es, name_buf, buf);
283
284 if ((flags & SA_IP_PORT) && addr->addr.in4.sin_port)
285 {
286 snprintf(name_buf, sizeof(name_buf), "%s_port", name_prefix);
287 setenv_int(es, name_buf, ntohs(addr->addr.in4.sin_port));
288 }
289 break;
290
291 case AF_INET6:
292 if (IN6_IS_ADDR_V4MAPPED(&addr->addr.in6.sin6_addr))
293 {
294 struct in_addr ia;
295 memcpy(&ia.s_addr, &addr->addr.in6.sin6_addr.s6_addr[12], sizeof(ia.s_addr));
296 snprintf(name_buf, sizeof(name_buf), "%s_ip", name_prefix);
297 inet_ntop(AF_INET, &ia, buf, sizeof(buf));
298 }
299 else
300 {
301 snprintf(name_buf, sizeof(name_buf), "%s_ip6", name_prefix);
302 inet_ntop(AF_INET6, &addr->addr.in6.sin6_addr, buf, sizeof(buf));
303 }
304 setenv_str(es, name_buf, buf);
305
306 if ((flags & SA_IP_PORT) && addr->addr.in6.sin6_port)
307 {
308 snprintf(name_buf, sizeof(name_buf), "%s_port", name_prefix);
309 setenv_int(es, name_buf, ntohs(addr->addr.in6.sin6_port));
310 }
311 break;
312 }
313}
314
315void
316setenv_in_addr_t(struct env_set *es, const char *name_prefix, in_addr_t addr,
317 const unsigned int flags)
318{
319 if (addr || !(flags & SA_SET_IF_NONZERO))
320 {
321 struct openvpn_sockaddr si;
322 CLEAR(si);
323 si.addr.in4.sin_family = AF_INET;
324 si.addr.in4.sin_addr.s_addr = htonl(addr);
325 setenv_sockaddr(es, name_prefix, &si, flags);
326 }
327}
328
329void
330setenv_in6_addr(struct env_set *es, const char *name_prefix, const struct in6_addr *addr,
331 const unsigned int flags)
332{
333 if (!IN6_IS_ADDR_UNSPECIFIED(addr) || !(flags & SA_SET_IF_NONZERO))
334 {
335 struct openvpn_sockaddr si;
336 CLEAR(si);
337 si.addr.in6.sin6_family = AF_INET6;
338 si.addr.in6.sin6_addr = *addr;
339 setenv_sockaddr(es, name_prefix, &si, flags);
340 }
341}
342
343void
344setenv_link_socket_actual(struct env_set *es, const char *name_prefix,
345 const struct link_socket_actual *act, const unsigned int flags)
346{
347 setenv_sockaddr(es, name_prefix, &act->dest, flags);
348}
349
350/*
351 * Convert protocol names between index and ascii form.
352 */
353
355{
356 const char *short_form;
357 const char *display_form;
359 uint8_t proto;
360};
361
362/* Indexed by PROTO_x */
363static const struct proto_names proto_names[] = {
364 { "proto-uninitialized", "proto-NONE", AF_UNSPEC, PROTO_NONE },
365 /* try IPv4 and IPv6 (client), bind dual-stack (server) */
366 { "udp", "UDP", AF_UNSPEC, PROTO_UDP },
367 { "tcp-server", "TCP_SERVER", AF_UNSPEC, PROTO_TCP_SERVER },
368 { "tcp-client", "TCP_CLIENT", AF_UNSPEC, PROTO_TCP_CLIENT },
369 { "tcp", "TCP", AF_UNSPEC, PROTO_TCP },
370 /* force IPv4 */
371 { "udp4", "UDPv4", AF_INET, PROTO_UDP },
372 { "tcp4-server", "TCPv4_SERVER", AF_INET, PROTO_TCP_SERVER },
373 { "tcp4-client", "TCPv4_CLIENT", AF_INET, PROTO_TCP_CLIENT },
374 { "tcp4", "TCPv4", AF_INET, PROTO_TCP },
375 /* force IPv6 */
376 { "udp6", "UDPv6", AF_INET6, PROTO_UDP },
377 { "tcp6-server", "TCPv6_SERVER", AF_INET6, PROTO_TCP_SERVER },
378 { "tcp6-client", "TCPv6_CLIENT", AF_INET6, PROTO_TCP_CLIENT },
379 { "tcp6", "TCPv6", AF_INET6, PROTO_TCP },
380};
381
382int
383ascii2proto(const char *proto_name)
384{
385 for (size_t i = 0; i < SIZE(proto_names); ++i)
386 {
387 if (!strcmp(proto_name, proto_names[i].short_form))
388 {
389 return proto_names[i].proto;
390 }
391 }
392 return -1;
393}
394
396ascii2af(const char *proto_name)
397{
398 for (size_t i = 0; i < SIZE(proto_names); ++i)
399 {
400 if (!strcmp(proto_name, proto_names[i].short_form))
401 {
402 return proto_names[i].proto_af;
403 }
404 }
405 return 0;
406}
407
408const char *
410{
411 for (size_t i = 0; i < SIZE(proto_names); ++i)
412 {
413 if (proto_names[i].proto_af == af && proto_names[i].proto == proto)
414 {
415 if (display_form)
416 {
417 return proto_names[i].display_form;
418 }
419 else
420 {
421 return proto_names[i].short_form;
422 }
423 }
424 }
425
426 return "[unknown protocol]";
427}
428
429const char *
431{
432 struct buffer out = alloc_buf_gc(256, gc);
433
434 for (size_t i = 0; i < SIZE(proto_names); ++i)
435 {
436 if (i)
437 {
438 buf_printf(&out, " ");
439 }
440 buf_printf(&out, "[%s]", proto_names[i].short_form);
441 }
442 return BSTR(&out);
443}
444
445const char *
447{
448 switch (af)
449 {
450 case AF_INET:
451 return "AF_INET";
452
453 case AF_INET6:
454 return "AF_INET6";
455 }
456 return "AF_UNSPEC";
457}
458
459/*
460 * Given a local proto, return local proto
461 * if !remote, or compatible remote proto
462 * if remote.
463 *
464 * This is used for options compatibility
465 * checking.
466 *
467 * IPv6 and IPv4 protocols are comptabile but OpenVPN
468 * has always sent UDPv4, TCPv4 over the wire. Keep these
469 * strings for backward compatibility
470 */
471const char *
472proto_remote(int proto, bool remote)
473{
474 ASSERT(proto >= 0 && proto < PROTO_N);
475 if (proto == PROTO_UDP)
476 {
477 return "UDPv4";
478 }
479
480 if ((remote && proto == PROTO_TCP_CLIENT) || (!remote && proto == PROTO_TCP_SERVER))
481 {
482 return "TCPv4_SERVER";
483 }
484 if ((remote && proto == PROTO_TCP_SERVER) || (!remote && proto == PROTO_TCP_CLIENT))
485 {
486 return "TCPv4_CLIENT";
487 }
488
489 ASSERT(0);
490 return ""; /* Make the compiler happy */
491}
492
493/*
494 * We do our own inet_aton because the glibc function
495 * isn't very good about error checking.
496 */
497int
498openvpn_inet_aton(const char *dotted_quad, struct in_addr *addr)
499{
500 unsigned int a, b, c, d;
501
502 CLEAR(*addr);
503 if (sscanf(dotted_quad, "%u.%u.%u.%u", &a, &b, &c, &d) == 4)
504 {
505 if (a < 256 && b < 256 && c < 256 && d < 256)
506 {
507 addr->s_addr = htonl(a << 24 | b << 16 | c << 8 | d);
508 return OIA_IP; /* good dotted quad */
509 }
510 }
511 if (string_class(dotted_quad, CC_DIGIT | CC_DOT, 0))
512 {
513 return OIA_ERROR; /* probably a badly formatted dotted quad */
514 }
515 else
516 {
517 return OIA_HOSTNAME; /* probably a hostname */
518 }
519}
520
521bool
522ip_addr_dotted_quad_safe(const char *dotted_quad)
523{
524 /* verify non-NULL */
525 if (!dotted_quad)
526 {
527 return false;
528 }
529
530 /* verify length is within limits */
531 if (strlen(dotted_quad) > 15)
532 {
533 return false;
534 }
535
536 /* verify that all chars are either numeric or '.' and that no numeric
537 * substring is greater than 3 chars */
538 {
539 int nnum = 0;
540 const char *p = dotted_quad;
541 int c;
542
543 while ((c = *p++))
544 {
545 if (c >= '0' && c <= '9')
546 {
547 ++nnum;
548 if (nnum > 3)
549 {
550 return false;
551 }
552 }
553 else if (c == '.')
554 {
555 nnum = 0;
556 }
557 else
558 {
559 return false;
560 }
561 }
562 }
563
564 /* verify that string will convert to IP address */
565 {
566 struct in_addr a;
567 return openvpn_inet_aton(dotted_quad, &a) == OIA_IP;
568 }
569}
570
571bool
572ipv6_addr_safe(const char *ipv6_text_addr)
573{
574 /* verify non-NULL */
575 if (!ipv6_text_addr)
576 {
577 return false;
578 }
579
580 /* verify length is within limits */
581 if (strlen(ipv6_text_addr) > INET6_ADDRSTRLEN)
582 {
583 return false;
584 }
585
586 /* verify that string will convert to IPv6 address */
587 {
588 struct in6_addr a6;
589 return inet_pton(AF_INET6, ipv6_text_addr, &a6) == 1;
590 }
591}
592
593static bool
594dns_addr_safe(const char *addr)
595{
596 if (addr)
597 {
598 const size_t len = strlen(addr);
599 return len > 0 && len <= 255 && string_class(addr, CC_ALNUM | CC_DASH | CC_DOT, 0);
600 }
601 else
602 {
603 return false;
604 }
605}
606
607bool
608ip_or_dns_addr_safe(const char *addr, const bool allow_fqdn)
609{
610 if (ip_addr_dotted_quad_safe(addr))
611 {
612 return true;
613 }
614 else if (allow_fqdn)
615 {
616 return dns_addr_safe(addr);
617 }
618 else
619 {
620 return false;
621 }
622}
623
624bool
625mac_addr_safe(const char *mac_addr)
626{
627 /* verify non-NULL */
628 if (!mac_addr)
629 {
630 return false;
631 }
632
633 /* verify length is within limits */
634 if (strlen(mac_addr) > 17)
635 {
636 return false;
637 }
638
639 /* verify that all chars are either alphanumeric or ':' and that no
640 * alphanumeric substring is greater than 2 chars */
641 {
642 int nnum = 0;
643 const char *p = mac_addr;
644 int c;
645
646 while ((c = *p++))
647 {
648 if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
649 {
650 ++nnum;
651 if (nnum > 2)
652 {
653 return false;
654 }
655 }
656 else if (c == ':')
657 {
658 nnum = 0;
659 }
660 else
661 {
662 return false;
663 }
664 }
665 }
666
667 /* error-checking is left to script invoked in lladdr.c */
668 return true;
669}
bool buf_printf(struct buffer *buf, const char *format,...)
printf-style append to a buffer with overflow check.
Definition buffer.c:226
bool string_class(const char *str, const unsigned int inclusive, const unsigned int exclusive)
Test whether all characters in a string satisfy a character class filter.
Definition buffer.c:971
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
Allocate memory and, optionally, zero it.
Definition buffer.c:313
void buf_puts(struct buffer *buf, const char *str)
Append a string to a buffer with overflow check.
Definition buffer.c:252
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Allocate a buffer of the given size under garbage collection.
Definition buffer.c:77
#define CC_DASH
dash
Definition buffer.h:1696
#define BSTR(buf)
Return the buffer content pointer cast to char *.
Definition buffer.h:157
#define CC_DIGIT
digit isdigit()
Definition buffer.h:1684
#define CC_DOT
dot
Definition buffer.h:1697
#define CC_ALNUM
alphanumeric isalnum()
Definition buffer.h:1680
Data Channel Cryptography Module.
void setenv_int(struct env_set *es, const char *name, int value)
Definition env_set.c:289
void setenv_str(struct env_set *es, const char *name, const char *value)
Definition env_set.c:305
static SERVICE_STATUS status
Definition interactive.c:52
#define CLEAR(x)
Definition basic.h:32
#define SIZE(x)
Definition basic.h:29
#define ASSERT(x)
Definition error.h:221
static bool dns_addr_safe(const char *addr)
const char * proto2ascii(int proto, sa_family_t af, bool display_form)
bool mac_addr_safe(const char *mac_addr)
void setenv_in_addr_t(struct env_set *es, const char *name_prefix, in_addr_t addr, const unsigned int flags)
const char * print_sockaddr_ex(const struct sockaddr *sa, const char *separator, const unsigned int flags, struct gc_arena *gc)
Definition socket_util.c:38
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)
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)
struct in6_addr add_in6_addr(struct in6_addr base, uint32_t add)
sa_family_t ascii2af(const char *proto_name)
int openvpn_inet_aton(const char *dotted_quad, struct in_addr *addr)
const char * proto_remote(int proto, bool remote)
bool ipv6_addr_safe(const char *ipv6_text_addr)
const char * print_in6_addr(struct in6_addr a6, unsigned int flags, struct gc_arena *gc)
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)
#define IF_NAMESIZE
const char * addr_family_name(int af)
bool ip_addr_dotted_quad_safe(const char *dotted_quad)
#define IA_EMPTY_IF_UNDEF
Definition socket_util.h:89
#define OIA_HOSTNAME
#define SA_IP_PORT
Definition socket_util.h:99
#define PS_SHOW_PORT
Definition socket_util.h:31
@ PROTO_NONE
@ PROTO_UDP
@ PROTO_TCP
@ PROTO_TCP_CLIENT
@ PROTO_N
@ PROTO_TCP_SERVER
#define PS_DONT_SHOW_ADDR
Definition socket_util.h:33
#define OIA_ERROR
#define PS_SHOW_PORT_IF_DEFINED
Definition socket_util.h:30
#define OIA_IP
#define PS_DONT_SHOW_FAMILY
Definition socket_util.h:34
#define IA_NET_ORDER
Definition socket_util.h:90
#define SA_SET_IF_NONZERO
#define PS_SHOW_PKTINFO
Definition socket_util.h:32
Wrapper structure for dynamically allocated memory.
Definition buffer.h:71
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
const char * short_form
uint8_t proto
const char * display_form
sa_family_t proto_af
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