1 /* source: sysutils.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* translate socket addresses into human readable form */
10 #include "sysincludes.h"
12 #include "compat.h" /* socklen_t */
23 /* Substitute for Write():
24 Try to write all bytes before returning; this handles EINTR,
25 EAGAIN/EWOULDBLOCK, and partial write situations. The drawback is that this
26 function might block even with O_NONBLOCK option.
27 Returns <0 on unhandled error, errno valid
28 Will only return <0 or bytes
30 ssize_t
writefull(int fd
, const void *buff
, size_t bytes
) {
34 chk
= Write(fd
, (const char *)buff
+ writt
, bytes
- writt
);
39 #if EAGAIN != EWOULDBLOCK
42 Warn4("write(%d, %p, "F_Zu
"): %s", fd
, (const char *)buff
+writt
, bytes
-writt
, strerror(errno
));
46 } else if (writt
+chk
< bytes
) {
47 Warn4("write(%d, %p, "F_Zu
"): only wrote "F_Zu
" bytes, trying to continue (rev.direction is blocked)",
48 fd
, (const char *)buff
+writt
, bytes
-writt
, chk
);
55 Notice3("write(%d, %p, "F_Zu
") completed", fd
, (const char *)buff
, bytes
);
60 void socket_un_init(struct sockaddr_un
*sa
) {
61 #if HAVE_STRUCT_SOCKADDR_SALEN
62 sa
->sun_len
= sizeof(struct sockaddr_un
);
64 sa
->sun_family
= AF_UNIX
;
65 memset(sa
->sun_path
, '\0', sizeof(sa
->sun_path
));
67 #endif /* WITH_UNIX */
70 void socket_in_init(struct sockaddr_in
*sa
) {
71 #if HAVE_STRUCT_SOCKADDR_SALEN
72 sa
->sin_len
= sizeof(struct sockaddr_in
);
74 sa
->sin_family
= AF_INET
;
76 sa
->sin_addr
.s_addr
= 0;
89 void socket_in6_init(struct sockaddr_in6
*sa
) {
90 #if HAVE_STRUCT_SOCKADDR_SALEN
91 sa
->sin6_len
= sizeof(struct sockaddr_in6
);
93 sa
->sin6_family
= AF_INET6
;
95 sa
->sin6_flowinfo
= 0;
96 #if HAVE_IP6_SOCKADDR==0
97 sa
->sin6_addr
.s6_addr
[0] = 0;
98 sa
->sin6_addr
.s6_addr
[1] = 0;
99 sa
->sin6_addr
.s6_addr
[2] = 0;
100 sa
->sin6_addr
.s6_addr
[3] = 0;
101 sa
->sin6_addr
.s6_addr
[4] = 0;
102 sa
->sin6_addr
.s6_addr
[5] = 0;
103 sa
->sin6_addr
.s6_addr
[6] = 0;
104 sa
->sin6_addr
.s6_addr
[7] = 0;
105 sa
->sin6_addr
.s6_addr
[8] = 0;
106 sa
->sin6_addr
.s6_addr
[9] = 0;
107 sa
->sin6_addr
.s6_addr
[10] = 0;
108 sa
->sin6_addr
.s6_addr
[11] = 0;
109 sa
->sin6_addr
.s6_addr
[12] = 0;
110 sa
->sin6_addr
.s6_addr
[13] = 0;
111 sa
->sin6_addr
.s6_addr
[14] = 0;
112 sa
->sin6_addr
.s6_addr
[15] = 0;
113 #elif HAVE_IP6_SOCKADDR==1
114 sa
->sin6_addr
.u6_addr
.u6_addr32
[0] = 0;
115 sa
->sin6_addr
.u6_addr
.u6_addr32
[1] = 0;
116 sa
->sin6_addr
.u6_addr
.u6_addr32
[2] = 0;
117 sa
->sin6_addr
.u6_addr
.u6_addr32
[3] = 0;
118 #elif HAVE_IP6_SOCKADDR==2
119 sa
->sin6_addr
.u6_addr32
[0] = 0;
120 sa
->sin6_addr
.u6_addr32
[1] = 0;
121 sa
->sin6_addr
.u6_addr32
[2] = 0;
122 sa
->sin6_addr
.u6_addr32
[3] = 0;
123 #elif HAVE_IP6_SOCKADDR==3
124 sa
->sin6_addr
.in6_u
.u6_addr32
[0] = 0;
125 sa
->sin6_addr
.in6_u
.u6_addr32
[1] = 0;
126 sa
->sin6_addr
.in6_u
.u6_addr32
[2] = 0;
127 sa
->sin6_addr
.in6_u
.u6_addr32
[3] = 0;
128 #elif HAVE_IP6_SOCKADDR==4
129 sa
->sin6_addr
._S6_un
._S6_u32
[0] = 0;
130 sa
->sin6_addr
._S6_un
._S6_u32
[1] = 0;
131 sa
->sin6_addr
._S6_un
._S6_u32
[2] = 0;
132 sa
->sin6_addr
._S6_un
._S6_u32
[3] = 0;
133 #elif HAVE_IP6_SOCKADDR==5
134 sa
->sin6_addr
.__u6_addr
.__u6_addr32
[0] = 0;
135 sa
->sin6_addr
.__u6_addr
.__u6_addr32
[1] = 0;
136 sa
->sin6_addr
.__u6_addr
.__u6_addr32
[2] = 0;
137 sa
->sin6_addr
.__u6_addr
.__u6_addr32
[3] = 0;
140 #endif /* WITH_IP6 */
144 /* initializes the socket address of the specified address family. Returns the
145 length of the specific socket address, or 0 on error. */
146 socklen_t
socket_init(int af
, union sockaddr_union
*sa
) {
148 case AF_UNSPEC
: memset(sa
, 0, sizeof(*sa
)); return sizeof(*sa
);
150 case AF_UNIX
: socket_un_init(&sa
->un
); return sizeof(sa
->un
);
153 case AF_INET
: socket_in_init(&sa
->ip4
); return sizeof(sa
->ip4
);
156 case AF_INET6
: socket_in6_init(&sa
->ip6
); return sizeof(sa
->ip6
);
158 default: Info1("socket_init(): unknown address family %d", af
);
159 memset(sa
, 0, sizeof(union sockaddr_union
));
160 sa
->soa
.sa_family
= af
;
164 #endif /* _WITH_SOCKET */
167 #define XIOUNIXSOCKOVERHEAD (sizeof(struct sockaddr_un)-sizeof(((struct sockaddr_un*)0)->sun_path))
171 /* writes a textual human readable representation of the sockaddr contents to buff and returns a pointer to buff
172 writes at most blen bytes to buff including the terminating \0 byte
174 char *sockaddr_info(const struct sockaddr
*sa
, socklen_t salen
, char *buff
, size_t blen
) {
175 union sockaddr_union
*sau
= (union sockaddr_union
*)sa
;
180 #if HAVE_STRUCT_SOCKADDR_SALEN
181 n
= xio_snprintf(cp
, blen
, "LEN=%d ", sau
->soa
.sa_len
);
182 if (n
< 0 || n
>= blen
) {
183 Warn1("sockaddr_info(): buffer too short ("F_Zu
")", blen
);
189 n
= xio_snprintf(cp
, blen
, "AF=%d ", sau
->soa
.sa_family
);
190 if (n
< 0 || n
>= blen
) {
191 Warn1("sockaddr_info(): buffer too short ("F_Zu
")", blen
);
197 switch (sau
->soa
.sa_family
) {
202 sockaddr_unix_info(&sau
->un
, salen
, cp
, blen
-1);
204 cp
= strchr(cp
, '\0');
211 case AF_INET
: sockaddr_inet4_info(&sau
->ip4
, cp
, blen
);
215 case AF_INET6
: sockaddr_inet6_info(&sau
->ip6
, cp
, blen
);
219 case AF_VSOCK
: sockaddr_vm_info(&sau
->vm
, cp
, blen
);
223 n
= xio_snprintf(cp
, blen
, "AF=%d ", sa
->sa_family
);
224 if (n
< 0 || n
>= blen
) {
225 Warn1("sockaddr_info(): buffer too short ("F_Zu
")", blen
);
230 n
= xio_snprintf(cp
, blen
,
231 "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
232 ((unsigned char *)sau
->soa
.sa_data
)[0],
233 ((unsigned char *)sau
->soa
.sa_data
)[1],
234 ((unsigned char *)sau
->soa
.sa_data
)[2],
235 ((unsigned char *)sau
->soa
.sa_data
)[3],
236 ((unsigned char *)sau
->soa
.sa_data
)[4],
237 ((unsigned char *)sau
->soa
.sa_data
)[5],
238 ((unsigned char *)sau
->soa
.sa_data
)[6],
239 ((unsigned char *)sau
->soa
.sa_data
)[7],
240 ((unsigned char *)sau
->soa
.sa_data
)[8],
241 ((unsigned char *)sau
->soa
.sa_data
)[9],
242 ((unsigned char *)sau
->soa
.sa_data
)[10],
243 ((unsigned char *)sau
->soa
.sa_data
)[11],
244 ((unsigned char *)sau
->soa
.sa_data
)[12],
245 ((unsigned char *)sau
->soa
.sa_data
)[13]);
246 if (n
< 0 || n
>= blen
) {
247 Warn("sockaddr_info(): buffer too short");
254 #endif /* _WITH_SOCKET */
258 char *sockaddr_unix_info(const struct sockaddr_un
*sa
, socklen_t salen
, char *buff
, size_t blen
) {
259 char ubuff
[5*UNIX_PATH_MAX
+3];
262 #if WITH_ABSTRACT_UNIXSOCKET
263 if (salen
> XIOUNIXSOCKOVERHEAD
&&
264 sa
->sun_path
[0] == '\0') {
266 sanitize_string(sa
->sun_path
, salen
-XIOUNIXSOCKOVERHEAD
,
267 ubuff
, XIOSAN_DEFAULT_BACKSLASH_OCT_3
);
269 #endif /* WITH_ABSTRACT_UNIXSOCKET */
271 if (salen
<= XIOUNIXSOCKOVERHEAD
) {
272 nextc
= sanitize_string ("<anon>", MIN(UNIX_PATH_MAX
, strlen("<anon>")),
273 ubuff
, XIOSAN_DEFAULT_BACKSLASH_OCT_3
);
275 nextc
= sanitize_string(sa
->sun_path
,
276 MIN(UNIX_PATH_MAX
, strlen(sa
->sun_path
)),
277 ubuff
, XIOSAN_DEFAULT_BACKSLASH_OCT_3
);
281 buff
[0] = '\0'; strncat(buff
, ubuff
, blen
-1);
284 #endif /* WITH_UNIX */
287 /* addr in host byte order! */
288 char *inet4addr_info(uint32_t addr
, char *buff
, size_t blen
) {
289 if (xio_snprintf(buff
, blen
, "%u.%u.%u.%u",
290 (unsigned int)(addr
>> 24), (unsigned int)((addr
>> 16) & 0xff),
291 (unsigned int)((addr
>> 8) & 0xff), (unsigned int)(addr
& 0xff)) >= blen
) {
292 Warn("inet4addr_info(): buffer too short");
297 #endif /* WITH_IP4 */
300 char *sockaddr_inet4_info(const struct sockaddr_in
*sa
, char *buff
, size_t blen
) {
301 if (xio_snprintf(buff
, blen
, "%u.%u.%u.%u:%hu",
302 ((unsigned char *)&sa
->sin_addr
.s_addr
)[0],
303 ((unsigned char *)&sa
->sin_addr
.s_addr
)[1],
304 ((unsigned char *)&sa
->sin_addr
.s_addr
)[2],
305 ((unsigned char *)&sa
->sin_addr
.s_addr
)[3],
306 htons(sa
->sin_port
)) >= blen
) {
307 Warn("sockaddr_inet4_info(): buffer too short");
312 #endif /* WITH_IP4 */
315 char *sockaddr_vm_info(const struct sockaddr_vm
*sa
, char *buff
, size_t blen
) {
316 if (xio_snprintf(buff
, blen
, "cid:%u port:%u", sa
->svm_cid
, sa
->svm_port
) >= blen
) {
317 Warn("sockaddr_vm_info(): buffer too short");
323 int sockaddr_vm_parse(struct sockaddr_vm
*sa
, const char *cid_str
,
324 const char *port_str
)
326 char *garbage
= NULL
;
328 sa
->svm_cid
= VMADDR_CID_ANY
;
330 sa
->svm_cid
= strtoul(cid_str
, &garbage
, 0);
331 if (*garbage
!= '\0') {
332 Error1("sockaddr_vm - garbage in cid: \"%s\"", garbage
);
338 sa
->svm_port
= VMADDR_PORT_ANY
;
340 sa
->svm_port
= strtoul(port_str
, &garbage
, 0);
341 if (*garbage
!= '\0') {
342 Error1("sockaddr_vm - garbage in port: \"%s\"", garbage
);
349 #endif /* WITH_VSOCK */
352 /* http://www.opengroup.org/onlinepubs/000095399/functions/inet_ntop.html */
353 const char *inet_ntop(int pf
, const void *binaddr
,
354 char *addrtext
, socklen_t textlen
) {
359 xio_snprintf(addrtext
, textlen
, "%u.%u.%u.%u",
360 ((unsigned char *)binaddr
)[0],
361 ((unsigned char *)binaddr
)[1],
362 ((unsigned char *)binaddr
)[2],
363 ((unsigned char *)binaddr
)[3]))
365 errno
= ENOSPC
; return NULL
;
371 xio_snprintf(addrtext
, textlen
, "%x:%x:%x:%x:%x:%x:%x:%x",
372 ntohs(((uint16_t *)binaddr
)[0]),
373 ntohs(((uint16_t *)binaddr
)[1]),
374 ntohs(((uint16_t *)binaddr
)[2]),
375 ntohs(((uint16_t *)binaddr
)[3]),
376 ntohs(((uint16_t *)binaddr
)[4]),
377 ntohs(((uint16_t *)binaddr
)[5]),
378 ntohs(((uint16_t *)binaddr
)[6]),
379 ntohs(((uint16_t *)binaddr
)[7])
382 errno
= ENOSPC
; return NULL
;
385 #endif /* WITH_IP6 */
387 errno
= EAFNOSUPPORT
;
390 addrtext
[retlen
] = '\0';
393 #endif /* !HAVE_INET_NTOP */
396 /* convert the IP6 socket address to human readable form. buff should be at
397 least 50 chars long. output includes the port number */
398 char *sockaddr_inet6_info(const struct sockaddr_in6
*sa
, char *buff
, size_t blen
) {
399 if (xio_snprintf(buff
, blen
, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:%hu",
400 #if HAVE_IP6_SOCKADDR==0
401 (sa
->sin6_addr
.s6_addr
[0]<<8)+
402 sa
->sin6_addr
.s6_addr
[1],
403 (sa
->sin6_addr
.s6_addr
[2]<<8)+
404 sa
->sin6_addr
.s6_addr
[3],
405 (sa
->sin6_addr
.s6_addr
[4]<<8)+
406 sa
->sin6_addr
.s6_addr
[5],
407 (sa
->sin6_addr
.s6_addr
[6]<<8)+
408 sa
->sin6_addr
.s6_addr
[7],
409 (sa
->sin6_addr
.s6_addr
[8]<<8)+
410 sa
->sin6_addr
.s6_addr
[9],
411 (sa
->sin6_addr
.s6_addr
[10]<<8)+
412 sa
->sin6_addr
.s6_addr
[11],
413 (sa
->sin6_addr
.s6_addr
[12]<<8)+
414 sa
->sin6_addr
.s6_addr
[13],
415 (sa
->sin6_addr
.s6_addr
[14]<<8)+
416 sa
->sin6_addr
.s6_addr
[15],
417 #elif HAVE_IP6_SOCKADDR==1
418 ntohs(((unsigned short *)&sa
->sin6_addr
.u6_addr
.u6_addr16
)[0]),
419 ntohs(((unsigned short *)&sa
->sin6_addr
.u6_addr
.u6_addr16
)[1]),
420 ntohs(((unsigned short *)&sa
->sin6_addr
.u6_addr
.u6_addr16
)[2]),
421 ntohs(((unsigned short *)&sa
->sin6_addr
.u6_addr
.u6_addr16
)[3]),
422 ntohs(((unsigned short *)&sa
->sin6_addr
.u6_addr
.u6_addr16
)[4]),
423 ntohs(((unsigned short *)&sa
->sin6_addr
.u6_addr
.u6_addr16
)[5]),
424 ntohs(((unsigned short *)&sa
->sin6_addr
.u6_addr
.u6_addr16
)[6]),
425 ntohs(((unsigned short *)&sa
->sin6_addr
.u6_addr
.u6_addr16
)[7]),
426 #elif HAVE_IP6_SOCKADDR==2
427 ntohs(((unsigned short *)&sa
->sin6_addr
.u6_addr16
)[0]),
428 ntohs(((unsigned short *)&sa
->sin6_addr
.u6_addr16
)[1]),
429 ntohs(((unsigned short *)&sa
->sin6_addr
.u6_addr16
)[2]),
430 ntohs(((unsigned short *)&sa
->sin6_addr
.u6_addr16
)[3]),
431 ntohs(((unsigned short *)&sa
->sin6_addr
.u6_addr16
)[4]),
432 ntohs(((unsigned short *)&sa
->sin6_addr
.u6_addr16
)[5]),
433 ntohs(((unsigned short *)&sa
->sin6_addr
.u6_addr16
)[6]),
434 ntohs(((unsigned short *)&sa
->sin6_addr
.u6_addr16
)[7]),
435 #elif HAVE_IP6_SOCKADDR==3
436 ntohs(((unsigned short *)&sa
->sin6_addr
.in6_u
.u6_addr16
)[0]),
437 ntohs(((unsigned short *)&sa
->sin6_addr
.in6_u
.u6_addr16
)[1]),
438 ntohs(((unsigned short *)&sa
->sin6_addr
.in6_u
.u6_addr16
)[2]),
439 ntohs(((unsigned short *)&sa
->sin6_addr
.in6_u
.u6_addr16
)[3]),
440 ntohs(((unsigned short *)&sa
->sin6_addr
.in6_u
.u6_addr16
)[4]),
441 ntohs(((unsigned short *)&sa
->sin6_addr
.in6_u
.u6_addr16
)[5]),
442 ntohs(((unsigned short *)&sa
->sin6_addr
.in6_u
.u6_addr16
)[6]),
443 ntohs(((unsigned short *)&sa
->sin6_addr
.in6_u
.u6_addr16
)[7]),
444 #elif HAVE_IP6_SOCKADDR==4
445 (sa
->sin6_addr
._S6_un
._S6_u8
[0]<<8)|(sa
->sin6_addr
._S6_un
._S6_u8
[1]&0xff),
446 (sa
->sin6_addr
._S6_un
._S6_u8
[2]<<8)|(sa
->sin6_addr
._S6_un
._S6_u8
[3]&0xff),
447 (sa
->sin6_addr
._S6_un
._S6_u8
[4]<<8)|(sa
->sin6_addr
._S6_un
._S6_u8
[5]&0xff),
448 (sa
->sin6_addr
._S6_un
._S6_u8
[6]<<8)|(sa
->sin6_addr
._S6_un
._S6_u8
[7]&0xff),
449 (sa
->sin6_addr
._S6_un
._S6_u8
[8]<<8)|(sa
->sin6_addr
._S6_un
._S6_u8
[9]&0xff),
450 (sa
->sin6_addr
._S6_un
._S6_u8
[10]<<8)|(sa
->sin6_addr
._S6_un
._S6_u8
[11]&0xff),
451 (sa
->sin6_addr
._S6_un
._S6_u8
[12]<<8)|(sa
->sin6_addr
._S6_un
._S6_u8
[13]&0xff),
452 (sa
->sin6_addr
._S6_un
._S6_u8
[14]<<8)|(sa
->sin6_addr
._S6_un
._S6_u8
[15]&0xff),
453 #elif HAVE_IP6_SOCKADDR==5
454 ntohs(((unsigned short *)&sa
->sin6_addr
.__u6_addr
.__u6_addr16
)[0]),
455 ntohs(((unsigned short *)&sa
->sin6_addr
.__u6_addr
.__u6_addr16
)[1]),
456 ntohs(((unsigned short *)&sa
->sin6_addr
.__u6_addr
.__u6_addr16
)[2]),
457 ntohs(((unsigned short *)&sa
->sin6_addr
.__u6_addr
.__u6_addr16
)[3]),
458 ntohs(((unsigned short *)&sa
->sin6_addr
.__u6_addr
.__u6_addr16
)[4]),
459 ntohs(((unsigned short *)&sa
->sin6_addr
.__u6_addr
.__u6_addr16
)[5]),
460 ntohs(((unsigned short *)&sa
->sin6_addr
.__u6_addr
.__u6_addr16
)[6]),
461 ntohs(((unsigned short *)&sa
->sin6_addr
.__u6_addr
.__u6_addr16
)[7]),
463 ntohs(sa
->sin6_port
)) >= blen
) {
464 Warn("sockaddr_inet6_info(): buffer too short");
468 #endif /* WITH_IP6 */
472 /* Checks if the given string is an IPv4 address.
473 Returns 0 when it is an address.
474 Returns 1 when it is not an address.
475 Returns -1 when an error occurred (bad regex - internal) */
481 if (regcomp(&preg
, "^(25[0-5]|(2[0-4]|1[0-9]|[1-9]?)[0-9])\\.(25[0-5]|(2[0-4]|1[0-9]|[1-9]?)[0-9])\\.(25[0-5]|(2[0-4]|1[0-9]|[1-9]?)[0-9])\\.(25[0-5]|(2[0-4]|1[0-9]|[1-9]?)[0-9])$", REG_EXTENDED
|REG_NOSUB
)
483 return -1; /* do not handle, just state that no match */
485 if (regexec(&preg
, address
, 0, NULL
, 0) == 0) {
488 #endif /* HAVE_REGEX_H */
489 /* Fallback when no regexec() compiled in */
492 #endif /* WITH_IP4 */
495 /* Checks if the given string is an IPv6 address.
496 Currently a hack, just checks a few criteria.
497 Returns 0 when it is an address.
498 Returns 1 when it is not an address.
499 Returns -1 when an error occurred (bad regex - internal) */
505 if (regcomp(&preg
, "^\\[[0-9a-fA-F:]*\\]$", REG_EXTENDED
|REG_NOSUB
)
507 return -1; /* do not handle, just state that no match */
509 if (regexec(&preg
, address
, 0, NULL
, 0) == 0) {
512 #endif /* HAVE_REGEX_H */
513 /* Fallback when no regexec() compiled in */
516 #endif /* WITH_IP6 */
518 /* Checks if the given string is an IPv6 address.
519 Currently a hack, just checks a few criteria.
520 Returns 0 when it is an address.
521 Returns 1 when it is not an address or on error. */
527 if ((res4
= check_ip4addr(address
)) == 0) {
532 if ((res6
= check_ip6addr(address
)) == 0) {
540 #if HAVE_GETGROUPLIST || (defined(HAVE_SETGRENT) && defined(HAVE_GETGRENT) && defined(HAVE_ENDGRENT))
541 /* fills the list with the supplementary group ids of user.
542 caller passes size of list in ngroups, function returns number of groups in
544 function returns 0 if 0 or more groups were found, or 1 if the list is too
546 int getusergroups(const char *user
, gid_t
*list
, int *ngroups
) {
547 #if HAVE_GETGROUPLIST
548 /* we prefer getgrouplist because it may be much faster with many groups, but it is not standard */
549 gid_t grp
, twogrps
[2];
551 /* getgrouplist requires to pass an extra group id, typically the users primary group, that is then added to the supplementary group list. We don't want such an additional group in the result, but there is not "unspecified" gid value available. Thus we try to find an abitrary supplementary group id that we then pass in a second call to getgrouplist. */
553 Getgrouplist(user
, grp
, twogrps
, &two
);
555 /* either user has just this supp group, or none; we try another id */
557 Getgrouplist(user
, grp
, twogrps
, &two
);
559 /* user has no supp group */
563 /* user has just the first tried group */
564 *ngroups
= 1; list
[0] = grp
;
567 /* find the first supp group that is not our grp, and use its id */
568 if (twogrps
[0] == grp
) {
573 if (Getgrouplist(user
, grp
, list
, ngroups
) < 0) {
578 #elif defined(HAVE_SETGRENT) && defined(HAVE_GETGRENT) && defined(HAVE_ENDGRENT)
579 /* this is standard (POSIX) but may be slow */
585 while (grp
= getgrent()) {
586 char **gusr
= grp
->gr_mem
;
588 if (!strcmp(*gusr
, user
)) {
591 list
[i
++] = grp
->gr_gid
;
600 #endif /* HAVE_SETGRENT... */
605 const char *hstrerror(int err
) {
606 static const char *h_messages
[] = {
608 "authoritative answer not found",
609 "non-authoritative, host not found, or serverfail",
610 "Host name lookup failure", /* "non recoverable error" */
611 "valid name, no data record of requested type" };
613 assert(HOST_NOT_FOUND
==1);
614 assert(TRY_AGAIN
==2);
615 assert(NO_RECOVERY
==3);
617 if ((err
< 0) || err
> sizeof(h_messages
)/sizeof(const char *)) {
620 return h_messages
[err
];
622 #endif /* !HAVE_HSTRERROR */
625 /* this function behaves like poll(). It tries to do so even when the poll()
626 system call is not available. */
627 /* note: glibc 5.4 does not know nfds_t */
628 int xiopoll(struct pollfd fds
[], unsigned long nfds
, struct timeval
*timeout
) {
632 while (true) { /* should be if (), but we want to break */
637 FD_ZERO(&readfds
); FD_ZERO(&writefds
); FD_ZERO(&exceptfds
);
638 for (i
= 0; i
< nfds
; ++i
) {
640 if (fds
[i
].fd
< 0) { continue; }
641 if (fds
[i
].fd
> FD_SETSIZE
) { break; /* use poll */ }
642 if (fds
[i
].events
& POLLIN
) {
643 FD_SET(fds
[i
].fd
, &readfds
); n
= MAX(n
, fds
[i
].fd
); }
644 if (fds
[i
].events
& POLLOUT
) {
645 FD_SET(fds
[i
].fd
, &writefds
); n
= MAX(n
, fds
[i
].fd
); }
647 if (i
< nfds
) { break; /* use poll */ }
649 result
= Select(n
+1, &readfds
, &writefds
, &exceptfds
, timeout
);
650 if (result
< 0) { return result
; }
651 for (i
= 0; i
< nfds
; ++i
) {
652 if (fds
[i
].fd
< 0) { continue; }
653 if ((fds
[i
].events
& POLLIN
) && FD_ISSET(fds
[i
].fd
, &readfds
)) {
654 fds
[i
].revents
|= POLLIN
; ++result
;
656 if ((fds
[i
].events
& POLLOUT
) && FD_ISSET(fds
[i
].fd
, &writefds
)) {
657 fds
[i
].revents
|= POLLOUT
; ++result
;
665 if (timeout
== NULL
) {
668 ms
= 1000*timeout
->tv_sec
+ timeout
->tv_usec
/1000;
671 return Poll(fds
, nfds
, ms
);
672 #else /* HAVE_POLL */
673 Error("poll() not available");
675 #endif /* !HAVE_POLL */
680 #if WITH_TCP || WITH_UDP
681 /* returns port in network byte order;
682 ipproto==IPPROTO_UDP resolves as UDP service, every other value resolves as
684 int parseport(const char *portname
, int ipproto
) {
689 if (isdigit(portname
[0]&0xff)) {
690 result
= htons(strtoul(portname
, &extra
, 0));
691 if (*extra
!= '\0') {
692 Error3("parseport(\"%s\", %d): extra trailing data \"%s\"",
693 portname
, ipproto
, extra
);
698 if ((se
= getservbyname(portname
, ipproto
==IPPROTO_UDP
?"udp":"tcp")) == NULL
) {
699 Error2("cannot resolve service \"%s/%d\"", portname
, ipproto
);
705 #endif /* WITH_TCP || WITH_UDP */
708 #if WITH_IP4 || WITH_IP6 || WITH_INTERFACE
709 /* check the systems interfaces for ifname and return its index
710 or -1 if no interface with this name was found
711 The system calls require an arbitrary socket; the calling program may
712 provide one in anysock to avoid creation of a dummy socket. anysock must be
713 <0 if it does not specify a socket fd.
715 int ifindexbyname(const char *ifname
, int anysock
) {
716 /* Linux: man 7 netdevice */
717 /* FreeBSD: man 4 networking */
718 /* Solaris: man 7 if_tcp */
720 #if defined(HAVE_STRUCT_IFREQ) && defined(SIOCGIFCONF) && defined(SIOCGIFINDEX)
721 /* currently we support Linux, FreeBSD; not Solaris */
723 #define IFBUFSIZ 32*sizeof(struct ifreq) /*1024*/
727 if (ifname
[0] == '\0') {
732 } else if ((s
= Socket(PF_INET
, SOCK_DGRAM
, IPPROTO_IP
)) < 0) {
733 Error1("socket(PF_INET, SOCK_DGRAM, IPPROTO_IP): %s", strerror(errno
));
737 strncpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
); /* ok */
738 if (Ioctl(s
, SIOCGIFINDEX
, &ifr
) < 0) {
739 Info3("ioctl(%d, SIOCGIFINDEX, {\"%s\"}): %s",
740 s
, ifr
.ifr_name
, strerror(errno
));
745 #if HAVE_STRUCT_IFREQ_IFR_INDEX
746 Info3("ioctl(%d, SIOCGIFINDEX, {\"%s\"}) -> { %d }",
747 s
, ifname
, ifr
.ifr_index
);
748 return ifr
.ifr_index
;
749 #elif HAVE_STRUCT_IFREQ_IFR_IFINDEX
750 Info3("ioctl(%d, SIOCGIFINDEX, {\"%s\"}) -> { %d }",
751 s
, ifname
, ifr
.ifr_ifindex
);
752 return ifr
.ifr_ifindex
;
753 #endif /* HAVE_STRUCT_IFREQ_IFR_IFINDEX */
755 #else /* !defined(HAVE_ STRUCT_IFREQ) && defined(SIOCGIFCONF) && defined(SIOCGIFINDEX) */
757 #endif /* !defined(HAVE_ STRUCT_IFREQ) && defined(SIOCGIFCONF) && defined(SIOCGIFINDEX) */
759 #endif /* WITH_IP4 || WITH_IP6 || WITH_INTERFACE */
762 #if WITH_IP4 || WITH_IP6 || WITH_INTERFACE
763 /* like ifindexbyname(), but also allows the index number as input - in this
764 case it does not lookup the index.
765 writes the resulting index to *ifindex and returns 0,
766 or returns -1 on error */
767 int ifindex(const char *ifname
, unsigned int *ifindex
, int anysock
) {
771 if (ifname
[0] == '\0') {
774 val
= strtol(ifname
, &endptr
, 0);
775 if (endptr
[0] == '\0') {
780 if ((val
= ifindexbyname(ifname
, anysock
)) < 0) {
786 #endif /* WITH_IP4 || WITH_IP6 || WITH_INTERFACE */
789 int _xiosetenv(const char *envname
, const char *value
, int overwrite
, const char *sep
) {
792 if (overwrite
>= 2 && (oldval
= getenv(envname
)) != NULL
) {
793 size_t newlen
= strlen(oldval
)+strlen(sep
)+strlen(value
)+1;
794 if ((newval
= Malloc(newlen
+1)) == NULL
) {
797 snprintf(newval
, newlen
+1, "%s%s%s", oldval
, sep
, value
);
799 newval
= (char *)value
;
801 if (Setenv(envname
, newval
, overwrite
) < 0) {
802 Warn3("setenv(\"%s\", \"%s\", 1): %s",
803 envname
, value
, strerror(errno
));
805 Unsetenv(envname
); /* dont want to have a wrong value */
812 /* constructs an environment variable whose name is built from socats uppercase
813 program name, and underscore and varname;
814 if the variable of this name already exists arg overwrite determines:
816 1: overwrite with new value
817 2: append to old value, separated by *sep
818 returns 0 on success or <0 if an error occurred. */
819 int xiosetenv(const char *varname
, const char *value
, int overwrite
, const char *sep
) {
820 # define XIO_ENVNAMELEN 256
821 const char *progname
;
822 char envname
[XIO_ENVNAMELEN
];
825 progname
= diag_get_string('p');
826 envname
[0] = '\0'; strncat(envname
, progname
, XIO_ENVNAMELEN
-1);
828 for (i
= 0; i
< l
; ++i
) envname
[i
] = toupper((unsigned char)envname
[i
]);
829 strncat(envname
+l
, "_", XIO_ENVNAMELEN
-l
-1);
831 strncat(envname
+l
, varname
, XIO_ENVNAMELEN
-l
-1);
832 return _xiosetenv(envname
, value
, overwrite
, sep
);
833 # undef XIO_ENVNAMELEN
836 int xiosetenv2(const char *varname
, const char *varname2
, const char *value
,
837 int overwrite
, const char *sep
) {
838 # define XIO_ENVNAMELEN 256
839 const char *progname
;
840 char envname
[XIO_ENVNAMELEN
];
843 progname
= diag_get_string('p');
844 envname
[0] = '\0'; strncat(envname
, progname
, XIO_ENVNAMELEN
-1);
845 l
= strlen(progname
);
846 strncat(envname
+l
, "_", XIO_ENVNAMELEN
-l
-1);
848 strncat(envname
+l
, varname
, XIO_ENVNAMELEN
-l
-1);
849 l
+= strlen(envname
+l
);
850 strncat(envname
+l
, "_", XIO_ENVNAMELEN
-l
-1);
852 strncat(envname
+l
, varname2
, XIO_ENVNAMELEN
-l
-1);
853 l
+= strlen(envname
+l
);
854 for (i
= 0; i
< l
; ++i
) envname
[i
] = toupper((unsigned char)envname
[i
]);
855 return _xiosetenv(envname
, value
, overwrite
, sep
);
856 # undef XIO_ENVNAMELEN
859 int xiosetenv3(const char *varname
, const char *varname2
, const char *varname3
,
861 int overwrite
, const char *sep
) {
862 # define XIO_ENVNAMELEN 256
863 const char *progname
;
864 char envname
[XIO_ENVNAMELEN
];
867 progname
= diag_get_string('p');
868 envname
[0] = '\0'; strncat(envname
, progname
, XIO_ENVNAMELEN
-1);
869 l
= strlen(progname
);
870 strncat(envname
+l
, "_", XIO_ENVNAMELEN
-l
-1);
872 strncat(envname
+l
, varname
, XIO_ENVNAMELEN
-l
-1);
873 l
+= strlen(envname
+l
);
874 strncat(envname
+l
, "_", XIO_ENVNAMELEN
-l
-1);
876 strncat(envname
+l
, varname2
, XIO_ENVNAMELEN
-l
-1);
877 l
+= strlen(envname
+l
);
878 strncat(envname
+l
, "_", XIO_ENVNAMELEN
-l
-1);
880 strncat(envname
+l
, varname3
, XIO_ENVNAMELEN
-l
-1);
881 l
+= strlen(envname
+l
);
882 for (i
= 0; i
< l
; ++i
) envname
[i
] = toupper((unsigned char)envname
[i
]);
883 return _xiosetenv(envname
, value
, overwrite
, sep
);
884 # undef XIO_ENVNAMELEN
888 /* like xiosetenv(), but uses an unsigned long value */
889 int xiosetenvulong(const char *varname
, unsigned long value
, int overwrite
) {
890 # define XIO_LONGLEN 21 /* should suffice for 64bit longs with \0 */
891 char envbuff
[XIO_LONGLEN
];
893 snprintf(envbuff
, XIO_LONGLEN
, "%lu", value
);
894 return xiosetenv(varname
, envbuff
, overwrite
, NULL
);
898 /* like xiosetenv(), but uses an unsigned short value */
899 int xiosetenvushort(const char *varname
, unsigned short value
, int overwrite
) {
900 # define XIO_SHORTLEN 11 /* should suffice for 32bit shorts with \0 */
901 char envbuff
[XIO_SHORTLEN
];
903 snprintf(envbuff
, XIO_SHORTLEN
, "%hu", value
);
904 return xiosetenv(varname
, envbuff
, overwrite
, NULL
);
909 unsigned long int Strtoul(const char *nptr
, char **endptr
, int base
, const char *txt
) {
912 res
= strtoul(nptr
, endptr
, base
);
913 if (nptr
== *endptr
) {
914 Error1("parseopts(): missing numerical value of option \"%s\"", txt
);
916 if (**endptr
!= '\0') {
917 Error1("parseopts(): trailing garbage in numerical arg of option \"%s\"", txt
);
923 long long int Strtoll(const char *nptr
, char **endptr
, int base
, const char *txt
) {
926 res
= strtoul(nptr
, endptr
, base
);
927 if (nptr
== *endptr
) {
928 Error1("parseopts(): missing numerical value of option \"%s\"", txt
);
930 if (**endptr
!= '\0') {
931 Error1("parseopts(): trailing garbage in numerical arg of option \"%s\"", txt
);
935 #endif /* HAVE_STRTOLL */
937 double Strtod(const char *nptr
, char **endptr
, const char *txt
) {
940 res
= strtod(nptr
, endptr
);
941 if (nptr
== *endptr
) {
942 Error1("parseopts(): missing numerical value of option \"%s\"", txt
);
944 if (**endptr
!= '\0') {
945 Error1("parseopts(): trailing garbage in numerical arg of option \"%s\"", txt
);
951 /* This function gets a string with possible references to environment
952 variables and expands them. Variables must be prefixed with '$' and their
953 names consist only of A-Z, a-z, 0-9, and '_'.
954 The name may be enclosed with { }.
955 To pass a literal "$" us "\$".
956 There are special variables supported whose values do not comr from
958 $$ expands to the process's pid
959 $PROGNAME expands to the executables basename or the value of option -lp
960 $TIMESTAMP expands to the actual time in format %Y%m%dT%H%M%S
961 $MICROS expands to the actual microseconds (decimal)
962 The dst output is a copy of src but with the variables expanded.
963 Returns 0 on success;
964 returns -1 when the output buffer was too short (overflow);
965 returns 1 on syntax error.
968 char *dst
, /* prealloc'd output buff, will be \0 termd */
969 const char *src
, /* input string to generate expansion from */
970 size_t n
, /* length of dst */
971 struct timeval
*tv
) /* in/out timestamp for sync */
973 char c
; /* char currently being lex'd/parsed */
974 bool esc
= false; /* just got '\' */
975 bool bra
= false; /* within ${ } */
976 char *nam
= NULL
; /* points to temp.allocated rw copy of src */
977 const char *e
; /* pointer to isolated var name in tmp[] */
978 size_t s
=0, d
=0; /* counters in src, dst */
979 size_t v
; /* variable name begin */
980 bool ofl
= false; /* dst overflow, output truncated */
981 char tmp
[18]; /* buffer for timestamp, micros */
983 while (c
= src
[s
++]) {
986 if (d
+2 > n
) { ofl
= true; break; }
992 if (d
+3 > n
) { ofl
= true; break; }
995 if (d
+2 > n
) { ofl
= true; break; }
1010 if (d
+2 > n
) { ofl
= true; break; }
1015 /* c == '$': Expecting env var to expand */
1018 if (d
+2 > n
) { ofl
= true; break; }
1025 /* Special case: pid */
1027 wr
= snprintf(&dst
[d
], n
-d
, F_pid
, getpid());
1028 if (wr
>= n
-d
|| wr
< 0) { ofl
= true; break; }
1036 if (!isalpha(c
) && c
!= '_') {
1037 /* Special case no var name, just keep '$' */
1038 if (d
+3 > n
) { ofl
= true; break; }
1044 v
= 0; /* seems we found valid variable name */
1046 nam
= strdup(src
+s
);
1052 while (c
= src
[s
]) {
1053 if (!isalnum(c
) && c
!= '_') {
1059 if (bra
&& c
!= '}') {
1064 /* Var name is complete */
1065 /* Check hardcoded var names */
1066 if (strcmp(nam
, "PROGNAME") == 0) {
1067 e
= diag_get_string('p');
1068 } else if (strcmp(nam
, "TIMESTAMP") == 0) {
1069 if (tv
->tv_sec
== 0) {
1070 gettimeofday(tv
, NULL
);
1073 localtime_r(&tv
->tv_sec
, &tm
);
1074 strftime(tmp
, sizeof(tmp
), "%Y%m%dT%H%M%S", &tm
);
1076 } else if (strcmp(nam
, "MICROS") == 0) {
1077 if (tv
->tv_sec
== 0) {
1078 gettimeofday(tv
, NULL
);
1080 sprintf(tmp
, F_tv_usec
, tv
->tv_usec
);
1086 /* Var not found, skip it */
1089 /* Var found, copy it to output buffer */
1090 if (d
+strlen(e
)+1 > n
) { ofl
= true; break; }
1092 d
+= strlen(&dst
[d
]);
1105 if (src
[s
-1] != '\0') {
1112 int xio_opensnifffile(
1116 char path
[PATH_MAX
];
1121 rc
= expandenv(path
, a
, sizeof(path
), tv
);
1123 Error2("expandenv(source=\"%s\", n="F_Zu
"): Out of memory", a
, sizeof(path
));
1126 } else if (rc
> 0) {
1127 Error1("expandenv(source=\"%s\"): Syntax error", a
);
1131 flags
= O_CREAT
|O_WRONLY
|O_APPEND
|
1139 if ((fd
= Open(path
, flags
, 0664)) < 0) {
1140 if (errno
== ENXIO
) {
1141 /* try to open pipe rdwr */
1142 if ((fd
= Open(path
, flags
, 0664)) < 0) {
1148 if (Fcntl_l(fd
, F_SETFD
, FD_CLOEXEC
) < 0) {
1149 Warn2("fcntl(%d, F_SETFD, FD_CLOEXEC): %s", fd
, strerror(errno
));