Failed to compile on OmniOS due to TCP_INFO
[socat.git] / filan.c
bloba733a0af326cdd2999fedd346f811e4acfb77439
1 /* source: filan.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* the subroutine filan makes a "FILe descriptor ANalysis". It checks the
6 type of file descriptor and tries to retrieve as much info about it as
7 possible without modifying its state.
8 NOTE: it works on UNIX (kernel) file descriptors, not on libc files! */
10 #include "config.h"
11 #include "xioconfig.h" /* what features are enabled */
13 #include "sysincludes.h"
15 #include "mytypes.h"
16 #include "compat.h"
17 #include "error.h"
18 #include "sycls.h"
19 #include "sysutils.h"
21 #include "filan.h"
24 struct sockopt {
25 int so;
26 char *name;
29 static int filan_streams_analyze(int fd, FILE *outfile);
31 /* global variables for configuring filan */
32 bool filan_followsymlinks;
33 bool filan_rawoutput;
36 int sockoptan(int fd, const struct sockopt *optname, int socklay, FILE *outfile);
37 int tcpan(int fd, FILE *outfile);
38 int tcpan2(int fd, FILE *outfile);
39 const char *getfiletypestring(int st_mode);
41 static int printtime(FILE *outfile, time_t time);
43 static int headprinted;
45 /* analyse a file system entry, referred by file name */
46 int filan_file(const char *filename, FILE *outfile) {
47 int fd = -1;
48 int result;
49 #if HAVE_STAT64
50 struct stat64 buf = {0};
51 #else
52 struct stat buf = {0};
53 #endif /* !HAVE_STAT64 */
55 if (filan_followsymlinks) {
56 #if HAVE_STAT64
57 result = Stat64(filename, &buf);
58 #else
59 result = Stat(filename, &buf);
60 #endif /* !HAVE_STAT64 */
61 if (result < 0) {
62 Warn3("stat(\"%s\", %p): %s", filename, &buf, strerror(errno));
64 } else {
65 #if HAVE_STAT64
66 result = Lstat64(filename, &buf);
67 #else
68 result = Lstat(filename, &buf);
69 #endif /* !HAVE_STAT64 */
70 if (result < 0) {
71 Warn3("lstat(\"%s\", %p): %s", filename, &buf, strerror(errno));
74 switch (buf.st_mode&S_IFMT) {
75 #ifdef S_IFSOCK
76 case S_IFSOCK: /* probably, it's useless to make a socket and describe it */
77 break;
78 #endif /* S_IFSOCK */
79 default:
80 if ((fd =
81 Open(filename, O_RDONLY|O_NOCTTY|O_NONBLOCK
82 #ifdef O_LARGEFILE
83 |O_LARGEFILE
84 #endif
85 , 0700))
86 < 0) {
87 Warn2("open(\"%s\", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE, 0700): %s",
88 filename, strerror(errno));
92 result = filan_stat(&buf, fd, -1, outfile);
93 fputc('\n', outfile);
94 return result;
97 /* analyze a file descriptor */
98 int filan_fd(int fd, FILE *outfile) {
99 #if HAVE_STAT64
100 struct stat64 buf = {0};
101 #else
102 struct stat buf = {0};
103 #endif /* !HAVE_STAT64 */
104 int result;
106 Debug1("checking file descriptor %u", fd);
107 #if HAVE_STAT64
108 result = Fstat64(fd, &buf);
109 #else
110 result = Fstat(fd, &buf);
111 #endif /* !HAVE_STAT64 */
112 if (result < 0) {
113 if (errno == EBADF) {
114 Debug2("fstat(%d): %s", fd, strerror(errno));
115 } else {
116 Warn2("fstat(%d): %s", fd, strerror(errno));
118 return -1;
120 Debug2("fd %d is a %s", fd, getfiletypestring(buf.st_mode));
122 result = filan_stat(&buf, fd, fd, outfile);
124 if (result >= 0) {
125 /* even more dynamic info */
126 { /* see if data is available */
127 struct pollfd ufds;
128 ufds.fd = fd;
129 ufds.events = POLLIN|POLLPRI|POLLOUT
130 #ifdef POLLRDNORM
131 |POLLRDNORM
132 #endif
133 #ifdef POLLRDBAND
134 |POLLRDBAND
135 #endif
136 |POLLWRNORM
137 #ifdef POLLWRBAND
138 |POLLWRBAND
139 #endif
140 #ifdef POLLMSG
141 |POLLMSG
142 #endif
144 #if HAVE_POLL
145 if (Poll(&ufds, 1, 0) < 0) {
146 Warn4("poll({%d, %hd, %hd}, 1, 0): %s",
147 ufds.fd, ufds.events, ufds.revents, strerror(errno));
148 } else {
149 fputs("poll: ", outfile);
150 if (ufds.revents & POLLIN) fputs("IN,", outfile);
151 if (ufds.revents & POLLPRI) fputs("PRI,", outfile);
152 if (ufds.revents & POLLOUT) fputs("OUT,", outfile);
153 if (ufds.revents & POLLERR) fputs("ERR,", outfile);
154 if (ufds.revents & POLLNVAL) fputs("NVAL,", outfile);
155 #ifdef FIONREAD
156 if (ufds.revents & POLLIN) {
157 size_t sizet;
158 if ((result = Ioctl(fd, FIONREAD, &sizet) >= 0)) {
159 fprintf (outfile, "; FIONREAD="F_Zu, sizet);
162 #endif /* defined(FIONREAD) */
163 #if _WITH_SOCKET && defined(MSG_DONTWAIT)
164 if ((ufds.revents & POLLIN) && isasocket(fd)) {
165 char _peername[SOCKADDR_MAX];
166 struct sockaddr *pa = (struct sockaddr *)_peername;
167 struct msghdr msgh = {0};
168 char peekbuff[1]; /* [0] fails with some compilers */
169 #if HAVE_STRUCT_IOVEC
170 struct iovec iovec;
171 #endif
172 char ctrlbuff[5120];
173 ssize_t bytes;
175 fputs("; ", outfile);
176 msgh.msg_name = pa;
177 msgh.msg_namelen = sizeof(*pa);
178 #if HAVE_STRUCT_IOVEC
179 iovec.iov_base = peekbuff;
180 iovec.iov_len = sizeof(peekbuff);
181 msgh.msg_iov = &iovec;
182 msgh.msg_iovlen = 1;
183 #endif
184 #if HAVE_STRUCT_MSGHDR_MSGCONTROL
185 msgh.msg_control = ctrlbuff;
186 #endif
187 #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
188 msgh.msg_controllen = sizeof(ctrlbuff);
189 #endif
190 #if HAVE_STRUCT_MSGHDR_MSGFLAGS
191 msgh.msg_flags = 0;
192 #endif
193 if ((bytes = Recvmsg(fd, &msgh, MSG_PEEK|MSG_DONTWAIT)) < 0) {
194 Warn1("recvmsg(): %s", strerror(errno));
195 } else {
196 fprintf(outfile, "recvmsg="F_Zd", ", bytes);
199 #endif /* _WITH_SOCKET && defined(MSG_DONTWAIT) */
201 #endif /* HAVE_POLL */
204 fputc('\n', outfile);
205 return 0;
209 int filan_stat(
210 #if HAVE_STAT64
211 struct stat64 *buf
212 #else
213 struct stat *buf
214 #endif /* !HAVE_STAT64 */
215 , int statfd, int dynfd, FILE *outfile) {
216 char stdevstr[8];
218 /* print header */
219 if (!headprinted) {
220 if (filan_rawoutput) {
221 fputs(" FD type\tdevice\tinode\tmode\tlinks\tuid\tgid"
222 #if HAVE_ST_RDEV
223 "\trdev"
224 #endif
225 "\tsize"
226 #if HAVE_ST_BLKSIZE
227 "\tblksize"
228 #endif
229 #if HAVE_ST_BLOCKS
230 "\tblocks"
231 #endif
232 "\tatime\t\tmtime\t\tctime\t\tcloexec\tflags"
233 #if defined(F_GETOWN)
234 "\tsigown"
235 #endif
236 , outfile);
237 } else /* !rawoutput */ {
238 fputs(" FD type\tdevice\tinode\tmode\tlinks\tuid\tgid"
239 #if HAVE_ST_RDEV
240 "\trdev"
241 #endif
242 "\tsize"
243 #if HAVE_ST_BLKSIZE
244 "\tblksize"
245 #endif
246 #if HAVE_ST_BLOCKS
247 "\tblocks"
248 #endif
249 "\tatime\t\t\t\tmtime\t\t\t\tctime\t\t\t\tcloexec\tflags"
250 #if defined(F_GETOWN)
251 "\tsigown"
252 #endif
253 , outfile);
255 } /* endif !rawoutput */
257 #if defined(F_GETSIG)
258 fputs("\tsigio", outfile);
259 #endif /* defined(F_GETSIG) */
260 fputc('\n', outfile);
261 headprinted = 1;
263 if (filan_rawoutput) {
264 snprintf(stdevstr, 8, F_dev, buf->st_dev);
265 } else {
266 snprintf(stdevstr, 8, "%hu,%hu", (unsigned short)(buf->st_dev>>8), (unsigned short)(buf->st_dev&0xff));
268 fprintf(outfile, "%4d: %s\t%s\t"
269 #if HAVE_STAT64
270 F_st64_ino
271 #else
272 F_st_ino
273 #endif /* HAVE_STAT64 */
274 "\t"F_mode"\t"F_st_nlink"\t"F_uid"\t"F_gid
275 #if HAVE_ST_RDEV
276 "\t%hu,%hu"
277 #endif
278 "\t"
279 #if HAVE_STAT64
280 F_st64_size
281 #else
282 F_st_size
283 #endif /* HAVE_STAT64 */
284 #if HAVE_ST_BLKSIZE
285 "\t"F_st_blksize
286 #endif
287 #if HAVE_ST_BLOCKS
288 #if HAVE_STAT64
289 "\t"F_st64_blocks
290 #else
291 "\t"F_st_blocks
292 #endif /* HAVE_STAT64 */
293 #endif
295 (dynfd>=0?dynfd:statfd), getfiletypestring(buf->st_mode),
296 stdevstr,
297 buf->st_ino,
298 buf->st_mode, buf->st_nlink, buf->st_uid,
299 buf->st_gid,
300 #if HAVE_ST_RDEV
301 (unsigned short)(buf->st_rdev>>8), (unsigned short)(buf->st_rdev&0xff),
302 #endif
303 buf->st_size
304 #if HAVE_ST_BLKSIZE
305 , buf->st_blksize
306 #endif
307 #if HAVE_ST_BLOCKS
308 , buf->st_blocks /* on Linux, this applies to stat and stat64 */
309 #endif
312 printtime(outfile, buf->st_atime);
313 printtime(outfile, buf->st_mtime);
314 printtime(outfile, buf->st_ctime);
316 #if 0
318 fputc('\t', outfile);
319 time = asctime(localtime(&buf->st_mtime));
320 if (strchr(time, '\n')) *strchr(time, '\n') = '\0';
321 fputs(time, outfile);
323 fputc('\t', outfile);
324 time = asctime(localtime(&buf->st_ctime));
325 if (strchr(time, '\n')) *strchr(time, '\n') = '\0';
326 fputs(time, outfile);
328 #endif
330 /* here comes dynamic info - it is only meaningful with preexisting FDs */
331 if (dynfd >= 0) { /*!indent */
332 int cloexec, flags;
333 #if defined(F_GETOWN)
334 int sigown;
335 #endif
336 #if defined(F_GETSIG)
337 int sigio;
338 #endif /* defined(F_GETSIG) */
340 cloexec = Fcntl(dynfd, F_GETFD);
341 flags = Fcntl(dynfd, F_GETFL);
342 #if defined(F_GETOWN)
343 sigown = Fcntl(dynfd, F_GETOWN);
344 #endif
345 #if defined(F_GETSIG)
346 sigio = Fcntl(dynfd, F_GETSIG);
347 #endif /* defined(F_GETSIG) */
348 fprintf(outfile, "\t%d\tx%06x", cloexec, flags);
349 #if defined(F_GETOWN)
350 fprintf(outfile, "\t%d", sigown);
351 #endif
352 #if defined(F_GETSIG)
353 fprintf(outfile, "\t%d", sigio);
354 #endif /* defined(F_GETSIG) */
355 } else {
356 fputs("\t\t"
357 #if defined(F_GETOWN)
358 "\t"
359 #endif
360 #if defined(F_GETSIG)
361 "\t"
362 #endif /* defined(F_GETSIG) */
363 , outfile);
366 /* ever heard of POSIX streams? here we handle these */
367 filan_streams_analyze(statfd, outfile);
369 /* now see for type specific infos */
370 if (statfd >= 0) { /*!indent */
371 switch (buf->st_mode&S_IFMT) {
372 case (S_IFIFO): /* 1, FIFO */
373 break;
374 case (S_IFCHR): /* 2, character device */
375 cdevan(statfd, outfile);
376 break;
377 case (S_IFDIR): /* 4, directory */
378 break;
379 case (S_IFBLK): /* 6, block device */
380 break;
381 case (S_IFREG): /* 8, regular file */
382 break;
383 case (S_IFLNK): /* 10, symbolic link */
384 break;
385 #ifdef S_IFSOCK
386 case (S_IFSOCK): /* 12, socket */
387 #if _WITH_SOCKET
388 sockan(statfd, outfile);
389 #else
390 Warn("SOCKET support not compiled in");
391 return -1;
392 #endif /* !_WITH_SOCKET */
393 break;
394 #endif /* S_IFSOCK */
397 /* ioctl() */
398 return 0;
402 #if LATER
403 int fdinfo(int fd) {
404 int result;
406 result = Fcntl(fd, F_GETFD);
407 fcntl(fd, F_GETFL, );
408 fcntl(fd, F_GETLK, );
409 #ifdef F_GETOWN
410 fcntl(fd, F_GETOWN, );
411 #endif
412 #ifdef F_GETSIG
413 fcntl(fd, F_GETSIG, );
414 #endif
418 int devinfo(int fd) {
419 ioctl();
421 #endif
424 /* returns 0 on success (not a stream descriptor, or no module)
425 returns <0 on failure */
426 static int filan_streams_analyze(int fd, FILE *outfile) {
427 #ifdef I_LIST
428 # define SL_NMODS 8 /* max number of module names we can store */
429 struct str_list modnames;
430 int i;
432 if (!isastream(fd)) {
433 fprintf(outfile, "\t(no STREAMS modules)");
434 return 0;
436 #if 0 /* uncomment for debugging */
437 fprintf(outfile, "\tfind=%d", ioctl(fd, I_FIND, "ldterm"));
438 #endif
439 modnames.sl_nmods = ioctl(fd, I_LIST, 0);
440 if (modnames.sl_nmods < 0) {
441 fprintf(stderr, "ioctl(%d, I_LIST, 0): %s\n", fd, strerror(errno));
442 return -1;
444 modnames.sl_modlist = Malloc(modnames.sl_nmods*(sizeof(struct str_mlist)));
445 if (modnames.sl_modlist == NULL) {
446 fprintf(stderr, "out of memory\n");
447 return -1;
449 if (ioctl(fd, I_LIST, &modnames) < 0) {
450 fprintf(stderr, "ioctl(%d, I_LIST, %p): %s\n",
451 fd, &modnames, strerror(errno));
452 free(modnames.sl_modlist);
453 return -1;
455 fprintf(outfile, "\tSTREAMS: ");
456 for (i = 0; i < modnames.sl_nmods; ++i) {
457 fprintf(outfile, "\"%s\"", modnames.sl_modlist[i].l_name);
458 if (i+1 < modnames.sl_nmods) fputc(',', outfile);
460 free(modnames.sl_modlist);
461 #endif /* defined(I_LIST) */
462 return 0;
466 /* character device analysis */
467 int cdevan(int fd, FILE *outfile) {
468 int ret;
470 #if _WITH_TERMIOS
471 if ((ret = Isatty(fd)) < 0) {
472 Warn2("isatty(%d): %s", fd, strerror(errno));
473 return -1;
475 if (ret > 0) {
476 struct termios termarg;
477 char *name;
478 int i;
480 if ((name = Ttyname(fd)) == NULL) {
481 /*Warn2("ttyname(%d): %s", fd, strerror(errno));*/
482 fputs("\tNULL", outfile);
483 } else {
484 fprintf(outfile, "\t%s", name);
486 if (Tcgetattr(fd, &termarg) < 0) {
487 Warn3("tcgetattr(%d, %p): %s", fd, &termarg, strerror(errno));
488 return -1;
490 fprintf(outfile, " \tIFLAGS=%08x OFLAGS=%08x CFLAGS=%08x LFLAGS=%08x",
491 (unsigned int)termarg.c_iflag,
492 (unsigned int)termarg.c_oflag,
493 (unsigned int)termarg.c_cflag,
494 (unsigned int)termarg.c_lflag);
496 /* and the control characters */
497 if (filan_rawoutput) {
498 for (i=0; i<NCCS; ++i) {
499 fprintf(outfile, " cc[%d]=%d", i, termarg.c_cc[i]);
501 } else {
502 for (i=0; i<NCCS; ++i) {
503 int ch;
504 unsigned char s[4];
505 ch = termarg.c_cc[i];
506 if (isprint(ch)) {
507 s[0] = ch; s[1]= '\0';
508 } else if (ch < ' ') {
509 s[0] = '^'; s[1] = ch+'@'; s[2] = '\0';
510 } else {
511 s[0] = 'x';
512 s[1] = (ch>>4)>=10?(ch>>4)-10+'A':(ch>>4)+'0';
513 s[2] = (ch&0x0f)>=10?(ch&0x0f)-10+'A':(ch&0x0f)+'0';
514 s[3] = '\0';
516 fprintf(outfile, " cc[%d]=%s", i, s);
520 #endif /* _WITH_TERMIOS */
521 return 0;
525 #if _WITH_SOCKET
526 int sockan(int fd, FILE *outfile) {
527 #define FILAN_OPTLEN 256
528 #define FILAN_NAMELEN 256
529 socklen_t optlen;
530 int result /*0, i*/;
531 char nambuff[FILAN_NAMELEN];
532 /* in Linux these optcodes are 'enum', but on AIX they are bits! */
533 static const struct sockopt sockopts[] = {
534 {SO_DEBUG, "DEBUG"},
535 {SO_REUSEADDR, "REUSEADDR"},
536 #ifdef SO_PROTOCOL
537 {SO_PROTOCOL, "PROTOCOL"},
538 #elif defined(SO_PROTOTYPE)
539 {SO_PROTOTYPE, "PROTOTYPE"},
540 #endif
541 {SO_TYPE, "TYPE"},
542 {SO_ERROR, "ERROR"},
543 {SO_DONTROUTE, "DONTROUTE"},
544 {SO_BROADCAST, "BROADCAST"},
545 {SO_SNDBUF, "SNDBUF"},
546 {SO_RCVBUF, "RCVBUF"},
547 {SO_KEEPALIVE, "KEEPALIVE"},
548 {SO_OOBINLINE, "OOBINLINE"},
549 #ifdef SO_NO_CHECK
550 {SO_NO_CHECK, "NO_CHECK"},
551 #endif
552 #ifdef SO_PRIORITY
553 {SO_PRIORITY, "PRIORITY"},
554 #endif
555 {SO_LINGER, "LINGER"},
556 #ifdef SO_BSDCOMPAT
557 {SO_BSDCOMPAT, "BSDCOMPAT"},
558 #endif
559 #ifdef SO_REUSEPORT
560 {SO_REUSEPORT, "REUSEPORT"},
561 #endif /* defined(SO_REUSEPORT) */
562 #ifdef SO_PASSCRED
563 {SO_PASSCRED, "PASSCRED"},
564 #endif
565 #ifdef SO_PEERCRED
566 {SO_PEERCRED, "PEERCRED"},
567 #endif
568 #ifdef SO_RCVLOWAT
569 {SO_RCVLOWAT, "RCVLOWAT"},
570 #endif
571 #ifdef SO_SNDLOWAT
572 {SO_SNDLOWAT, "SNDLOWAT"},
573 #endif
574 #ifdef SO_RCVTIMEO
575 {SO_RCVTIMEO, "RCVTIMEO"},
576 #endif
577 #ifdef SO_SNDTIMEO
578 {SO_SNDTIMEO, "SNDTIMEO"},
579 #endif
580 #ifdef SO_SECURITY_AUTHENTICATION
581 {SO_SECURITY_AUTHENTICATION, "SECURITY_AUTHENTICATION"},
582 #endif
583 #ifdef SO_SECURITY_ENCRYPTION_TRANSPORT
584 {SO_SECURITY_ENCRYPTION_TRANSPORT, "SECURITY_ENCRYPTION_TRANSPORT"},
585 #endif
586 #ifdef SO_SECURITY_ENCRYPTION_NETWORK
587 {SO_SECURITY_ENCRYPTION_NETWORK, "SECURITY_ENCRYPTION_NETWORK"},
588 #endif
589 #ifdef SO_BINDTODEVICE
590 {SO_BINDTODEVICE, "BINDTODEVICE"},
591 #endif
592 #ifdef SO_ATTACH_FILTER
593 {SO_ATTACH_FILTER, "ATTACH_FILTER"},
594 #endif
595 #ifdef SO_DETACH_FILTER
596 {SO_DETACH_FILTER, "DETACH_FILTER"},
597 #endif
598 {0, NULL} } ;
599 union {
600 char c[FILAN_OPTLEN];
601 int i[FILAN_OPTLEN/sizeof(int)];
602 } optval;
603 const struct sockopt *optname;
604 union sockaddr_union sockname, peername; /* the longest I know of */
605 socklen_t namelen;
606 #if 0 && defined(SIOCGIFNAME)
607 /*Linux struct ifreq ifc = {{{ 0 }}};*/
608 struct ifreq ifc = {{ 0 }};
609 #endif
611 optlen = FILAN_OPTLEN;
612 result = Getsockopt(fd, SOL_SOCKET, SO_TYPE, optval.c, &optlen);
613 if (result < 0) {
614 Debug4("getsockopt(%d, SOL_SOCKET, SO_TYPE, %p, {"F_socklen"}): %s",
615 fd, optval.c, optlen, strerror(errno));
616 } else {
617 # define TYPENAMEMAX 16
618 char typename[TYPENAMEMAX];
619 sockettype(*optval.i, typename, sizeof(typename));
621 Debug3("fd %d: socket of type %d (\"%s\")", fd, *optval.i,
622 typename);
625 optname = sockopts; while (optname->so) {
626 optlen = FILAN_OPTLEN;
627 result =
628 Getsockopt(fd, SOL_SOCKET, optname->so, (void *)optval.c, &optlen);
629 if (result < 0) {
630 Debug5("getsockopt(%d, SOL_SOCKET, %d, %p, {"F_socklen"}): %s",
631 fd, optname->so, optval.c, optlen, strerror(errno));
632 fputc('\t', outfile);
633 } else if (optlen == sizeof(int)) {
634 Debug2("getsockopt(,,, {%d}, %d)",
635 *optval.i, optlen);
636 /*Info2("%s: %d", optname->name, optval.i);*/
637 fprintf(outfile, "%s=%d\t", optname->name, *optval.i);
638 } else {
639 Debug3("getsockopt(,,, {%d,%d}, %d)",
640 optval.i[0], optval.i[1], optlen);
641 fprintf(outfile, "%s={%d,%d}\t", optname->name,
642 optval.i[0], optval.i[1]);
644 ++optname;
647 namelen = sizeof(sockname);
648 result = Getsockname(fd, (struct sockaddr *)&sockname, &namelen);
649 if (result < 0) {
650 putc('\n', outfile);
651 Warn2("getsockname(%d): %s", fd, strerror(errno));
652 return -1;
654 fputc('\t', outfile);
655 fputs(sockaddr_info((struct sockaddr *)&sockname, namelen, nambuff, sizeof(nambuff)),
656 outfile);
658 namelen = sizeof(peername);
659 result = Getpeername(fd, (struct sockaddr *)&peername, &namelen);
660 if (result < 0) {
661 putc('\n', outfile);
662 Warn2("getpeername(%d): %s", fd, strerror(errno));
663 } else {
664 /* only valid if getpeername() succeeded */
665 fputs(" <-> ", outfile);
666 fprintf(outfile, "%s\t",
667 sockaddr_info((struct sockaddr *)&peername, namelen,
668 nambuff, sizeof(nambuff)));
671 #if 0 && defined(SIOCGIFNAME)
672 if ((result = Ioctl(fd, SIOCGIFNAME, &ifc)) < 0) {
673 Warn3("ioctl(%d, SIOCGIFNAME, %p): %s", fd, &ifc, strerror(errno));
674 } else {
675 fprintf(outfile, "IFNAME=\"%s\"\t", ifc.ifr_name);
677 #endif /* SIOCGIFNAME */
679 switch (((struct sockaddr *)&sockname)->sa_family) {
680 #if WITH_UNIX
681 case AF_UNIX:
682 /* no options for unix domain sockets known yet -> no unixan() */
683 result = 0;
684 break;
685 #endif
686 #if WITH_IP4
687 case AF_INET:
688 result = ipan(fd, outfile);
689 break;
690 #endif
691 #if WITH_IP6
692 case AF_INET6:
693 result = ipan(fd, outfile);
694 result |= ip6an(fd, outfile);
695 break;
696 #endif
697 default:
698 fputs("**** NO FURTHER ANALYSIS FOR THIS SOCKET TYPE IMPLEMENTED", outfile);
699 result = 0;
701 return result;
702 #undef FILAN_OPTLEN
703 #undef FILAN_NAMELEN
705 #endif /* _WITH_SOCKET */
708 #if WITH_IP4 || WITH_IP6
709 /* prints the option values for the IP protocol and the IP based protocols */
710 /* no distinction between IP4 and IP6 yet */
711 int ipan(int fd, FILE *outfile) {
712 /* in Linux these optcodes are 'enum', but on AIX they are bits! */
713 static const struct sockopt ipopts[] = {
714 {IP_TOS, "IP_TOS"},
715 {IP_TTL, "IP_TTL"},
716 #ifdef IP_HDRINCL
717 {IP_HDRINCL, "IP_HDRINCL"},
718 #endif
719 #ifdef IP_OPTIONS
720 {IP_OPTIONS, "IP_OPTIONS"},
721 #endif
722 #ifdef IP_ROUTER_ALERT
723 {IP_ROUTER_ALERT, "IP_ROUTER_ALERT"},
724 #endif
725 #ifdef IP_RECVOPTS
726 {IP_RECVOPTS, "IP_RECVOPTS"},
727 #endif
728 #ifdef IP_RETOPTS
729 {IP_RETOPTS, "IP_RETOPTS"},
730 #endif
731 #ifdef IP_PKTINFO
732 {IP_PKTINFO, "IP_PKTINFO"},
733 #endif
734 #ifdef IP_PKTOPTIONS
735 {IP_PKTOPTIONS, "IP_PKTOPTIONS"},
736 #endif
737 #ifdef IP_MTU_DISCOVER
738 {IP_MTU_DISCOVER, "IP_MTU_DISCOVER"},
739 #endif
740 #ifdef IP_RECVERR
741 {IP_RECVERR, "IP_RECVERR"},
742 #endif
743 #ifdef IP_RECVTTL
744 {IP_RECVTTL, "IP_RECVTTL"},
745 #endif
746 #ifdef IP_RECVTOS
747 {IP_RECVTOS, "IP_RECVTOS"},
748 #endif
749 #ifdef IP_TRANSPARENT
750 {IP_TRANSPARENT, "IP_TRANSPARENT"},
751 #endif
752 #ifdef IP_MTU
753 {IP_MTU, "IP_MTU"},
754 #endif
755 #ifdef IP_FREEBIND
756 {IP_FREEBIND, "IP_FREEBIND"},
757 #endif
758 #ifdef IP_MULTICAST_TTL
759 {IP_MULTICAST_TTL, "IP_MULTICAST_TTL"},
760 #endif
761 #ifdef IP_MULTICAST_LOOP
762 {IP_MULTICAST_LOOP, "IP_MULTICAST_LOOP"},
763 #endif
764 {0, NULL} } ;
765 const struct sockopt *optname;
766 int optproto;
767 socklen_t optlen = sizeof(optproto);
769 optname = ipopts; while (optname->so) {
770 sockoptan(fd, optname, SOL_IP, outfile);
771 ++optname;
773 /* want to pass the fd to the next layer protocol. */
774 #if defined(SO_PROTOCOL) || defined(SO_PROTOTYPE)
775 if (Getsockopt(fd, SOL_SOCKET,
776 #ifdef SO_PROTOCOL
777 SO_PROTOCOL,
778 #elif defined(SO_PROTOTYPE)
779 SO_PROTOTYPE,
780 #endif
781 &optproto, &optlen) >= 0) {
782 switch (optproto) {
783 #if WITH_TCP
784 case IPPROTO_TCP: tcpan(fd, outfile); break;
785 #endif
788 #endif /* defined(SO_PROTOCOL) || defined(SO_PROTOTYPE) */
789 return 0;
791 #endif /* WITH_IP */
794 #if WITH_IP6
795 /* prints the option values for the IPv6 protocol */
796 int ip6an(int fd, FILE *outfile) {
797 static const struct sockopt ip6opts[] = {
798 #ifdef IPV6_V6ONLY
799 {IPV6_V6ONLY, "IPV6_V6ONLY"},
800 #endif
801 {0, NULL} } ;
802 const struct sockopt *optname;
804 optname = ip6opts; while (optname->so) {
805 sockoptan(fd, optname, SOL_IPV6, outfile);
806 ++optname;
808 return 0;
810 #endif /* WITH_IP6 */
813 #if WITH_TCP
814 int tcpan(int fd, FILE *outfile) {
815 static const struct sockopt tcpopts[] = {
816 #ifdef TCP_NODELAY
817 { TCP_NODELAY, "TCP_NODELAY" },
818 #endif
819 #ifdef TCP_MAXSEG
820 { TCP_MAXSEG, "TCP_MAXSEG" },
821 #endif
822 #ifdef TCP_STDURG
823 { TCP_STDURG, "TCP_STDURG" },
824 #endif
825 #ifdef TCP_RFC1323
826 { TCP_RFC1323, "TCP_RFC1323" },
827 #endif
828 #ifdef TCP_CORK
829 { TCP_CORK, "TCP_CORK" },
830 #endif
831 #ifdef TCP_KEEPIDLE
832 { TCP_KEEPIDLE, "TCP_KEEPIDLE" },
833 #endif
834 #ifdef TCP_KEEPINTVL
835 { TCP_KEEPINTVL, "TCP_KEEPINTVL" },
836 #endif
837 #ifdef TCP_KEEPCNT
838 { TCP_KEEPCNT, "TCP_KEEPCNT" },
839 #endif
840 #ifdef TCP_SYNCNT
841 { TCP_SYNCNT, "TCP_SYNCNT" },
842 #endif
843 #ifdef TCP_LINGER2
844 { TCP_LINGER2, "TCP_LINGER2" },
845 #endif
846 #ifdef TCP_DEFER_ACCEPT
847 { TCP_DEFER_ACCEPT, "TCP_ACCEPT" },
848 #endif
849 #ifdef TCP_WINDOW_CLAMP
850 { TCP_WINDOW_CLAMP, "TCP_WINDOW_CLAMP" },
851 #endif
852 #ifdef TCP_INFO
853 { TCP_INFO, "TCP_INFO" },
854 #endif
855 #ifdef TCP_QUICKACK
856 { TCP_QUICKACK, "TCP_QUICKACK" },
857 #endif
858 #ifdef TCP_MD5SIG
859 { TCP_MD5SIG, "TCP_MD5SIG" },
860 #endif
861 #ifdef TCP_NOOPT
862 { TCP_NOOPT, "TCP_NOOPT" },
863 #endif
864 #ifdef TCP_NOPUSH
865 { TCP_NOPUSH, "TCP_NOPUSH" },
866 #endif
867 #ifdef TCP_SACK_DISABLE
868 { TCP_SACK_DISABLE, "TCP_SACK_DISABLE" },
869 #endif
870 #ifdef TCP_SIGNATURE_ENABLE
871 { TCP_SIGNATURE_ENABLE, "TCP_SIGNATURE_ENABLE" },
872 #endif
873 #ifdef TCP_ABORT_THRESHOLD
874 { TCP_ABORT_THRESHOLD, "TCP_ABORT_THRESHOLD" },
875 #endif
876 #ifdef TCP_CONN_ABORT_THRESHOLD
877 { TCP_CONN_ABORT_THRESHOLD, "TCP_CONN_ABORT_THRESHOLD" },
878 #endif
879 #ifdef TCP_KEEPINIT
880 { TCP_KEEPINIT, "TCP_KEEPINIT" },
881 #endif
882 #ifdef TCP_PAWS
883 { TCP_PAWS, "TCP_PAWS" },
884 #endif
885 #ifdef TCP_SACKENA
886 { TCP_SACKENA, "TCP_SACKENA" },
887 #endif
888 #ifdef TCP_TSOPTENA
889 { TCP_TSOPTENA, "TCP_TSOPTENA" },
890 #endif
891 {0, NULL}
893 const struct sockopt *optname;
895 optname = tcpopts; while (optname->so) {
896 sockoptan(fd, optname, SOL_TCP, outfile);
897 ++optname;
900 #ifdef TCP_INFO
901 tcpan2(fd, outfile);
902 #endif
903 return 0;
905 #endif /* WITH_TCP */
907 #if WITH_TCP && defined(TCP_INFO)
909 int tcpan2(int fd, FILE *outfile) {
910 struct tcp_info tcpinfo;
911 socklen_t tcpinfolen = sizeof(tcpinfo);
912 int result;
914 result = Getsockopt(fd, SOL_TCP, TCP_INFO, &tcpinfo, &tcpinfolen);
915 if (result < 0) {
916 Debug4("getsockopt(%d, SOL_TCP, TCP_INFO, %p, {"F_Zu"}): %s",
917 fd, &tcpinfo, sizeof(tcpinfo), strerror(errno));
918 return -1;
920 fprintf(outfile, "%s={%u}\t", "TCPI_STATE", tcpinfo.tcpi_state);
921 #if 0 /* on BSD these components are prefixed with __ - I get tired... */
922 fprintf(outfile, "%s={%u}\t", "TCPI_CA_STATE", tcpinfo.tcpi_ca_state);
923 fprintf(outfile, "%s={%u}\t", "TCPI_RETRANSMITS", tcpinfo.tcpi_retransmits);
924 fprintf(outfile, "%s={%u}\t", "TCPI_PROBES", tcpinfo.tcpi_probes);
925 fprintf(outfile, "%s={%u}\t", "TCPI_BACKOFF", tcpinfo.tcpi_backoff);
926 #endif
927 fprintf(outfile, "%s={%u}\t", "TCPI_OPTIONS", tcpinfo.tcpi_options);
928 fprintf(outfile, "%s={%u}\t", "TCPI_SND_WSCALE", tcpinfo.tcpi_snd_wscale);
929 fprintf(outfile, "%s={%u}\t", "TCPI_RCV_WSCALE", tcpinfo.tcpi_rcv_wscale);
930 //fprintf(outfile, "%s={%u}\t", "TCPI_DELIVERY_RATE_APP_LIMITED", tcpinfo.tcpi_delivery_rate_app_limited);
931 //fprintf(outfile, "%s={%u}\t", "TCPI_FASTOPEN_CLIENT_FAIL", tcpinfo.tcpi_fastopen_client_fail);
932 // fprintf(outfile, "%s={%u}\t", "TCPI_", tcpinfo.tcpi_);
934 return 0;
937 #endif /* WITH_TCP */
940 #if _WITH_SOCKET
941 int sockoptan(int fd, const struct sockopt *optname, int socklay, FILE *outfile) {
942 #define FILAN_OPTLEN 256
943 union {
944 char c[FILAN_OPTLEN];
945 int i[FILAN_OPTLEN/sizeof(int)];
946 } optval;
947 socklen_t optlen;
948 int result;
950 optlen = FILAN_OPTLEN;
951 result =
952 Getsockopt(fd, socklay, optname->so, (void *)optval.c, &optlen);
953 if (result < 0) {
954 Debug6("getsockopt(%d, %d, %d, %p, {"F_socklen"}): %s",
955 fd, socklay, optname->so, optval.c, optlen, strerror(errno));
956 fputc('\t', outfile);
957 return -1;
958 } else if (optlen == 0) {
959 Debug1("getsockopt(,,, {}, %d)", optlen);
960 fprintf(outfile, "%s=\"\"\t", optname->name);
961 } else if (optlen == sizeof(int)) {
962 Debug2("getsockopt(,,, {%d}, %d)",
963 *optval.i, optlen);
964 fprintf(outfile, "%s=%d\t", optname->name, *optval.i);
965 } else {
966 char outbuf[FILAN_OPTLEN*9+128], *cp = outbuf;
967 int i;
968 for (i = 0; i < optlen/sizeof(unsigned int); ++i) {
969 cp += sprintf(cp, "%08x ", (unsigned int)optval.i[i]);
971 *--cp = '\0'; /* delete trailing space */
972 Debug2("getsockopt(,,, {%s}, %d)", outbuf, optlen);
973 fflush(outfile);
974 fprintf(outfile, "%s={%s}\t", optname->name, outbuf);
976 return 0;
977 #undef FILAN_OPTLEN
979 #endif /* _WITH_SOCKET */
982 #if _WITH_SOCKET
983 int isasocket(int fd) {
984 int retval;
985 #if HAVE_STAT64
986 struct stat64 props;
987 #else
988 struct stat props;
989 #endif /* HAVE_STAT64 */
990 retval =
991 #if HAVE_STAT64
992 Fstat64(fd, &props);
993 #else
994 Fstat(fd, &props);
995 #endif
996 if (retval < 0) {
997 Info3("fstat(%d, %p): %s", fd, &props, strerror(errno));
998 return 0;
1000 /* note: when S_ISSOCK was undefined, it always gives 0 */
1001 return S_ISSOCK(props.st_mode);
1003 #endif /* _WITH_SOCKET */
1006 const char *getfiletypestring(int st_mode) {
1007 const char *s;
1009 switch (st_mode&S_IFMT) {
1010 case S_IFIFO: s = "pipe"; break;
1011 case S_IFCHR: s = "chrdev"; break;
1012 case S_IFDIR: s = "dir"; break;
1013 case S_IFBLK: s = "blkdev"; break;
1014 case S_IFREG: s = "file"; break;
1015 case S_IFLNK: s = "symlink"; break;
1016 case S_IFSOCK: s = "socket"; break;
1017 /*! AIX: MT? */
1018 default: s = "undef"; break;
1020 return s;
1023 static int printtime(FILE *outfile, time_t time) {
1024 const char *s;
1026 if (filan_rawoutput) {
1027 fprintf(outfile, "\t"F_time, time);
1028 } else {
1029 fputc('\t', outfile);
1030 s = asctime(localtime(&time));
1031 if (strchr(s, '\n')) *strchr(s, '\n') = '\0';
1032 fputs(s, outfile);
1034 return 0;