version 1.7.3.0
[socat.git] / filan.c
blobb64ee5cdb5d0215a7fee56f3cd5d42da496cd474
1 /* source: filan.c */
2 /* Copyright Gerhard Rieger */
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 /* dirty workaround so we dont get an error on AIX when being linked with
32 libwrap */
33 int allow_severity, deny_severity;
35 /* global variables for configuring filan */
36 bool filan_followsymlinks;
37 bool filan_rawoutput;
40 int sockoptan(int fd, const struct sockopt *optname, int socklay, FILE *outfile);
41 int tcpan(int fd, FILE *outfile);
42 const char *getfiletypestring(int st_mode);
44 static int printtime(FILE *outfile, time_t time);
46 static int headprinted;
48 /* analyse a file system entry, referred by file name */
49 int filan_file(const char *filename, FILE *outfile) {
50 int fd = -1;
51 int result;
52 #if HAVE_STAT64
53 struct stat64 buf = {0};
54 #else
55 struct stat buf = {0};
56 #endif /* !HAVE_STAT64 */
58 if (filan_followsymlinks) {
59 #if HAVE_STAT64
60 result = Stat64(filename, &buf);
61 #else
62 result = Stat(filename, &buf);
63 #endif /* !HAVE_STAT64 */
64 if (result < 0) {
65 Warn3("stat(\"%s\", %p): %s", filename, &buf, strerror(errno));
67 } else {
68 #if HAVE_STAT64
69 result = Lstat64(filename, &buf);
70 #else
71 result = Lstat(filename, &buf);
72 #endif /* !HAVE_STAT64 */
73 if (result < 0) {
74 Warn3("lstat(\"%s\", %p): %s", filename, &buf, strerror(errno));
77 switch (buf.st_mode&S_IFMT) {
78 #ifdef S_IFSOCK
79 case S_IFSOCK: /* probably, it's useless to make a socket and describe it */
80 break;
81 #endif /* S_IFSOCK */
82 default:
83 if ((fd =
84 Open(filename, O_RDONLY|O_NOCTTY|O_NONBLOCK
85 #ifdef O_LARGEFILE
86 |O_LARGEFILE
87 #endif
88 , 0700))
89 < 0) {
90 Warn2("open(\"%s\", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE, 0700): %s",
91 filename, strerror(errno));
95 result = filan_stat(&buf, fd, -1, outfile);
96 fputc('\n', outfile);
97 return result;
100 /* analyze a file descriptor */
101 int filan_fd(int fd, FILE *outfile) {
102 #if HAVE_STAT64
103 struct stat64 buf = {0};
104 #else
105 struct stat buf = {0};
106 #endif /* !HAVE_STAT64 */
107 int result;
109 Debug1("checking file descriptor %u", fd);
110 #if HAVE_STAT64
111 result = Fstat64(fd, &buf);
112 #else
113 result = Fstat(fd, &buf);
114 #endif /* !HAVE_STAT64 */
115 if (result < 0) {
116 if (errno == EBADF) {
117 Debug2("fstat(%d): %s", fd, strerror(errno));
118 } else {
119 Warn2("fstat(%d): %s", fd, strerror(errno));
121 return -1;
123 Debug2("fd %d is a %s", fd, getfiletypestring(buf.st_mode));
125 result = filan_stat(&buf, fd, fd, outfile);
127 if (result >= 0) {
128 /* even more dynamic info */
129 { /* see if data is available */
130 struct pollfd ufds;
131 ufds.fd = fd;
132 ufds.events = POLLIN|POLLPRI|POLLOUT
133 #ifdef POLLRDNORM
134 |POLLRDNORM
135 #endif
136 #ifdef POLLRDBAND
137 |POLLRDBAND
138 #endif
139 |POLLWRNORM
140 #ifdef POLLWRBAND
141 |POLLWRBAND
142 #endif
143 #ifdef POLLMSG
144 |POLLMSG
145 #endif
147 if (Poll(&ufds, 1, 0) < 0) {
148 Warn4("poll({%d, %hd, %hd}, 1, 0): %s",
149 ufds.fd, ufds.events, ufds.revents, strerror(errno));
150 } else {
151 fputs("poll: ", outfile);
152 if (ufds.revents & POLLIN) fputs("IN,", outfile);
153 if (ufds.revents & POLLPRI) fputs("PRI,", outfile);
154 if (ufds.revents & POLLOUT) fputs("OUT,", outfile);
155 if (ufds.revents & POLLERR) fputs("ERR,", outfile);
156 if (ufds.revents & POLLNVAL) fputs("NVAL,", outfile);
157 #ifdef FIONREAD
158 if (ufds.revents & POLLIN) {
159 size_t sizet;
160 if ((result = Ioctl(fd, FIONREAD, &sizet) >= 0)) {
161 fprintf (outfile, "; FIONREAD="F_Zu, sizet);
164 #endif /* defined(FIONREAD) */
165 #if _WITH_SOCKET && defined(MSG_DONTWAIT)
166 if ((ufds.revents & POLLIN) && isasocket(fd)) {
167 char _peername[SOCKADDR_MAX];
168 struct sockaddr *pa = (struct sockaddr *)_peername;
169 struct msghdr msgh = {0};
170 char peekbuff[1]; /* [0] fails with some compilers */
171 #if HAVE_STRUCT_IOVEC
172 struct iovec iovec;
173 #endif
174 char ctrlbuff[5120];
175 ssize_t bytes;
177 fputs("; ", outfile);
178 msgh.msg_name = pa;
179 msgh.msg_namelen = sizeof(*pa);
180 #if HAVE_STRUCT_IOVEC
181 iovec.iov_base = peekbuff;
182 iovec.iov_len = sizeof(peekbuff);
183 msgh.msg_iov = &iovec;
184 msgh.msg_iovlen = 1;
185 #endif
186 #if HAVE_STRUCT_MSGHDR_MSGCONTROL
187 msgh.msg_control = ctrlbuff;
188 #endif
189 #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
190 msgh.msg_controllen = sizeof(ctrlbuff);
191 #endif
192 #if HAVE_STRUCT_MSGHDR_MSGFLAGS
193 msgh.msg_flags = 0;
194 #endif
195 if ((bytes = Recvmsg(fd, &msgh, MSG_PEEK|MSG_DONTWAIT)) < 0) {
196 Warn1("recvmsg(): %s", strerror(errno));
197 } else {
198 fprintf(outfile, "recvmsg="F_Zd", ", bytes);
201 #endif /* _WITH_SOCKET && defined(MSG_DONTWAIT) */
205 fputc('\n', outfile);
206 return 0;
210 int filan_stat(
211 #if HAVE_STAT64
212 struct stat64 *buf
213 #else
214 struct stat *buf
215 #endif /* !HAVE_STAT64 */
216 , int statfd, int dynfd, FILE *outfile) {
217 char stdevstr[8];
219 /* print header */
220 if (!headprinted) {
221 if (filan_rawoutput) {
222 fputs(" FD type\tdevice\tinode\tmode\tlinks\tuid\tgid"
223 #if HAVE_ST_RDEV
224 "\trdev"
225 #endif
226 "\tsize"
227 #if HAVE_ST_BLKSIZE
228 "\tblksize"
229 #endif
230 #if HAVE_ST_BLOCKS
231 "\tblocks"
232 #endif
233 "\tatime\t\tmtime\t\tctime\t\tcloexec\tflags"
234 #if defined(F_GETOWN)
235 "\tsigown"
236 #endif
237 , outfile);
238 } else /* !rawoutput */ {
239 fputs(" FD type\tdevice\tinode\tmode\tlinks\tuid\tgid"
240 #if HAVE_ST_RDEV
241 "\trdev"
242 #endif
243 "\tsize"
244 #if HAVE_ST_BLKSIZE
245 "\tblksize"
246 #endif
247 #if HAVE_ST_BLOCKS
248 "\tblocks"
249 #endif
250 "\tatime\t\t\t\tmtime\t\t\t\tctime\t\t\t\tcloexec\tflags"
251 #if defined(F_GETOWN)
252 "\tsigown"
253 #endif
254 , outfile);
256 } /* endif !rawoutput */
258 #if defined(F_GETSIG)
259 fputs("\tsigio", outfile);
260 #endif /* defined(F_GETSIG) */
261 fputc('\n', outfile);
262 headprinted = 1;
264 if (filan_rawoutput) {
265 snprintf(stdevstr, 8, F_dev, buf->st_dev);
266 } else {
267 snprintf(stdevstr, 8, "%hu,%hu", (unsigned short)(buf->st_dev>>8), (unsigned short)(buf->st_dev&0xff));
269 fprintf(outfile, "%4d: %s\t%s\t"
270 #if HAVE_STAT64
271 F_st64_ino
272 #else
273 F_st_ino
274 #endif /* HAVE_STAT64 */
275 "\t"F_mode"\t"F_st_nlink"\t"F_uid"\t"F_gid
276 #if HAVE_ST_RDEV
277 "\t%hu,%hu"
278 #endif
279 "\t"
280 #if HAVE_STAT64
281 F_st64_size
282 #else
283 F_st_size
284 #endif /* HAVE_STAT64 */
285 #if HAVE_ST_BLKSIZE
286 "\t"F_st_blksize
287 #endif
288 #if HAVE_ST_BLOCKS
289 #if HAVE_STAT64
290 "\t"F_st64_blocks
291 #else
292 "\t"F_st_blocks
293 #endif /* HAVE_STAT64 */
294 #endif
296 (dynfd>=0?dynfd:statfd), getfiletypestring(buf->st_mode),
297 stdevstr,
298 buf->st_ino,
299 buf->st_mode, buf->st_nlink, buf->st_uid,
300 buf->st_gid,
301 #if HAVE_ST_RDEV
302 (unsigned short)(buf->st_rdev>>8), (unsigned short)(buf->st_rdev&0xff),
303 #endif
304 buf->st_size
305 #if HAVE_ST_BLKSIZE
306 , buf->st_blksize
307 #endif
308 #if HAVE_ST_BLOCKS
309 , buf->st_blocks /* on Linux, this applies to stat and stat64 */
310 #endif
313 printtime(outfile, buf->st_atime);
314 printtime(outfile, buf->st_mtime);
315 printtime(outfile, buf->st_ctime);
317 #if 0
319 fputc('\t', outfile);
320 time = asctime(localtime(&buf->st_mtime));
321 if (strchr(time, '\n')) *strchr(time, '\n') = '\0';
322 fputs(time, outfile);
324 fputc('\t', outfile);
325 time = asctime(localtime(&buf->st_ctime));
326 if (strchr(time, '\n')) *strchr(time, '\n') = '\0';
327 fputs(time, outfile);
329 #endif
331 /* here comes dynamic info - it is only meaningful with preexisting FDs */
332 if (dynfd >= 0) { /*!indent */
333 int cloexec, flags;
334 #if defined(F_GETOWN)
335 int sigown;
336 #endif
337 #if defined(F_GETSIG)
338 int sigio;
339 #endif /* defined(F_GETSIG) */
341 cloexec = Fcntl(dynfd, F_GETFD);
342 flags = Fcntl(dynfd, F_GETFL);
343 #if defined(F_GETOWN)
344 sigown = Fcntl(dynfd, F_GETOWN);
345 #endif
346 #if defined(F_GETSIG)
347 sigio = Fcntl(dynfd, F_GETSIG);
348 #endif /* defined(F_GETSIG) */
349 fprintf(outfile, "\t%d\tx%06x", cloexec, flags);
350 #if defined(F_GETOWN)
351 fprintf(outfile, "\t%d", sigown);
352 #endif
353 #if defined(F_GETSIG)
354 fprintf(outfile, "\t%d", sigio);
355 #endif /* defined(F_GETSIG) */
356 } else {
357 fputs("\t\t"
358 #if defined(F_GETOWN)
359 "\t"
360 #endif
361 #if defined(F_GETSIG)
362 "\t"
363 #endif /* defined(F_GETSIG) */
364 , outfile);
367 /* ever heard of POSIX streams? here we handle these */
368 filan_streams_analyze(statfd, outfile);
370 /* now see for type specific infos */
371 if (statfd >= 0) { /*!indent */
372 switch (buf->st_mode&S_IFMT) {
373 case (S_IFIFO): /* 1, FIFO */
374 break;
375 case (S_IFCHR): /* 2, character device */
376 cdevan(statfd, outfile);
377 break;
378 case (S_IFDIR): /* 4, directory */
379 break;
380 case (S_IFBLK): /* 6, block device */
381 break;
382 case (S_IFREG): /* 8, regular file */
383 break;
384 case (S_IFLNK): /* 10, symbolic link */
385 break;
386 #ifdef S_IFSOCK
387 case (S_IFSOCK): /* 12, socket */
388 #if _WITH_SOCKET
389 sockan(statfd, outfile);
390 #else
391 Warn("SOCKET support not compiled in");
392 return -1;
393 #endif /* !_WITH_SOCKET */
394 break;
395 #endif /* S_IFSOCK */
398 /* ioctl() */
399 return 0;
403 #if LATER
404 int fdinfo(int fd) {
405 int result;
407 result = Fcntl(fd, F_GETFD);
408 fcntl(fd, F_GETFL, );
409 fcntl(fd, F_GETLK, );
410 #ifdef F_GETOWN
411 fcntl(fd, F_GETOWN, );
412 #endif
413 #ifdef F_GETSIG
414 fcntl(fd, F_GETSIG, );
415 #endif
419 int devinfo(int fd) {
420 ioctl();
422 #endif
425 /* returns 0 on success (not a stream descriptor, or no module)
426 returns <0 on failure */
427 static int filan_streams_analyze(int fd, FILE *outfile) {
428 #ifdef I_LIST
429 # define SL_NMODS 8 /* max number of module names we can store */
430 struct str_list modnames;
431 int i;
433 if (!isastream(fd)) {
434 fprintf(outfile, "\t(no STREAMS modules)");
435 return 0;
437 #if 0 /* uncomment for debugging */
438 fprintf(outfile, "\tfind=%d", ioctl(fd, I_FIND, "ldterm"));
439 #endif
440 modnames.sl_nmods = ioctl(fd, I_LIST, 0);
441 if (modnames.sl_nmods < 0) {
442 fprintf(stderr, "ioctl(%d, I_LIST, 0): %s\n", fd, strerror(errno));
443 return -1;
445 modnames.sl_modlist = Malloc(modnames.sl_nmods*(sizeof(struct str_mlist)));
446 if (modnames.sl_modlist == NULL) {
447 fprintf(stderr, "out of memory\n");
448 return -1;
450 if (ioctl(fd, I_LIST, &modnames) < 0) {
451 fprintf(stderr, "ioctl(%d, I_LIST, %p): %s\n",
452 fd, &modnames, strerror(errno));
453 free(modnames.sl_modlist);
454 return -1;
456 fprintf(outfile, "\tSTREAMS: ");
457 for (i = 0; i < modnames.sl_nmods; ++i) {
458 fprintf(outfile, "\"%s\"", modnames.sl_modlist[i].l_name);
459 if (i+1 < modnames.sl_nmods) fputc(',', outfile);
461 free(modnames.sl_modlist);
462 #endif /* defined(I_LIST) */
463 return 0;
467 /* character device analysis */
468 int cdevan(int fd, FILE *outfile) {
469 int ret;
471 #if _WITH_TERMIOS
472 if ((ret = Isatty(fd)) < 0) {
473 Warn2("isatty(%d): %s", fd, strerror(errno));
474 return -1;
476 if (ret > 0) {
477 struct termios termarg;
478 char *name;
479 int i;
481 if ((name = Ttyname(fd)) == NULL) {
482 /*Warn2("ttyname(%d): %s", fd, strerror(errno));*/
483 fputs("\tNULL", outfile);
484 } else {
485 fprintf(outfile, "\t%s", name);
487 if (Tcgetattr(fd, &termarg) < 0) {
488 Warn3("tcgetattr(%d, %p): %s", fd, &termarg, strerror(errno));
489 return -1;
491 fprintf(outfile, " \tIFLAGS=%08x OFLAGS=%08x CFLAGS=%08x LFLAGS=%08x",
492 (unsigned int)termarg.c_iflag,
493 (unsigned int)termarg.c_oflag,
494 (unsigned int)termarg.c_cflag,
495 (unsigned int)termarg.c_lflag);
497 /* and the control characters */
498 if (filan_rawoutput) {
499 for (i=0; i<NCCS; ++i) {
500 fprintf(outfile, " cc[%d]=%d", i, termarg.c_cc[i]);
502 } else {
503 for (i=0; i<NCCS; ++i) {
504 int ch;
505 unsigned char s[4];
506 ch = termarg.c_cc[i];
507 if (isprint(ch)) {
508 s[0] = ch; s[1]= '\0';
509 } else if (ch < ' ') {
510 s[0] = '^'; s[1] = ch+'@'; s[2] = '\0';
511 } else {
512 s[0] = 'x';
513 s[1] = (ch>>4)>=10?(ch>>4)-10+'A':(ch>>4)+'0';
514 s[2] = (ch&0x0f)>=10?(ch&0x0f)-10+'A':(ch&0x0f)+'0';
515 s[3] = '\0';
517 fprintf(outfile, " cc[%d]=%s", i, s);
521 #endif /* _WITH_TERMIOS */
522 return 0;
526 #if _WITH_SOCKET
527 int sockan(int fd, FILE *outfile) {
528 #define FILAN_OPTLEN 256
529 #define FILAN_NAMELEN 256
530 socklen_t optlen;
531 int result /*0, i*/;
532 static const char *socktypes[] = {
533 "undef", "STREAM", "DGRAM", "RAW", "RDM",
534 "SEQPACKET", "undef", "undef", "undef", "undef",
535 "PACKET", "undef" } ;
536 char nambuff[FILAN_NAMELEN];
537 /* in Linux these optcodes are 'enum', but on AIX they are bits! */
538 static const struct sockopt sockopts[] = {
539 {SO_DEBUG, "DEBUG"},
540 {SO_REUSEADDR, "REUSEADDR"},
541 {SO_TYPE, "TYPE"},
542 {SO_ERROR, "ERROR"},
543 #ifdef SO_PROTOTYPE
544 {SO_PROTOTYPE, "PROTOTYPE"},
545 #endif
546 {SO_DONTROUTE, "DONTROUTE"},
547 {SO_BROADCAST, "BROADCAST"},
548 {SO_SNDBUF, "SNDBUF"},
549 {SO_RCVBUF, "RCVBUF"},
550 {SO_KEEPALIVE, "KEEPALIVE"},
551 {SO_OOBINLINE, "OOBINLINE"},
552 #ifdef SO_NO_CHECK
553 {SO_NO_CHECK, "NO_CHECK"},
554 #endif
555 #ifdef SO_PRIORITY
556 {SO_PRIORITY, "PRIORITY"},
557 #endif
558 {SO_LINGER, "LINGER"},
559 #ifdef SO_BSDCOMPAT
560 {SO_BSDCOMPAT, "BSDCOMPAT"},
561 #endif
562 #ifdef SO_REUSEPORT
563 {SO_REUSEPORT, "REUSEPORT"},
564 #endif /* defined(SO_REUSEPORT) */
565 #ifdef SO_PASSCRED
566 {SO_PASSCRED, "PASSCRED"},
567 #endif
568 #ifdef SO_PEERCRED
569 {SO_PEERCRED, "PEERCRED"},
570 #endif
571 #ifdef SO_RCVLOWAT
572 {SO_RCVLOWAT, "RCVLOWAT"},
573 #endif
574 #ifdef SO_SNDLOWAT
575 {SO_SNDLOWAT, "SNDLOWAT"},
576 #endif
577 #ifdef SO_RCVTIMEO
578 {SO_RCVTIMEO, "RCVTIMEO"},
579 #endif
580 #ifdef SO_SNDTIMEO
581 {SO_SNDTIMEO, "SNDTIMEO"},
582 #endif
583 #ifdef SO_SECURITY_AUTHENTICATION
584 {SO_SECURITY_AUTHENTICATION, "SECURITY_AUTHENTICATION"},
585 #endif
586 #ifdef SO_SECURITY_ENCRYPTION_TRANSPORT
587 {SO_SECURITY_ENCRYPTION_TRANSPORT, "SECURITY_ENCRYPTION_TRANSPORT"},
588 #endif
589 #ifdef SO_SECURITY_ENCRYPTION_NETWORK
590 {SO_SECURITY_ENCRYPTION_NETWORK, "SECURITY_ENCRYPTION_NETWORK"},
591 #endif
592 #ifdef SO_BINDTODEVICE
593 {SO_BINDTODEVICE, "BINDTODEVICE"},
594 #endif
595 #ifdef SO_ATTACH_FILTER
596 {SO_ATTACH_FILTER, "ATTACH_FILTER"},
597 #endif
598 #ifdef SO_DETACH_FILTER
599 {SO_DETACH_FILTER, "DETACH_FILTER"},
600 #endif
601 {0, NULL} } ;
602 union {
603 char c[FILAN_OPTLEN];
604 int i[FILAN_OPTLEN/sizeof(int)];
605 } optval;
606 const struct sockopt *optname;
607 union sockaddr_union sockname, peername; /* the longest I know of */
608 socklen_t namelen;
609 #if 0 && defined(SIOCGIFNAME)
610 /*Linux struct ifreq ifc = {{{ 0 }}};*/
611 struct ifreq ifc = {{ 0 }};
612 #endif
614 optlen = FILAN_OPTLEN;
615 result = Getsockopt(fd, SOL_SOCKET, SO_TYPE, optval.c, &optlen);
616 if (result < 0) {
617 Debug4("getsockopt(%d, SOL_SOCKET, SO_TYPE, %p, {"F_socklen"}): %s",
618 fd, optval.c, optlen, strerror(errno));
619 } else {
620 Debug3("fd %d: socket of type %d (\"%s\")", fd, *optval.i,
621 socktypes[*optval.i]);
624 optname = sockopts; while (optname->so) {
625 optlen = FILAN_OPTLEN;
626 result =
627 Getsockopt(fd, SOL_SOCKET, optname->so, (void *)optval.c, &optlen);
628 if (result < 0) {
629 Debug5("getsockopt(%d, SOL_SOCKET, %d, %p, {"F_socklen"}): %s",
630 fd, optname->so, optval.c, optlen, strerror(errno));
631 fputc('\t', outfile);
632 } else if (optlen == sizeof(int)) {
633 Debug2("getsockopt(,,, {%d}, %d)",
634 *optval.i, optlen);
635 /*Info2("%s: %d", optname->name, optval.i);*/
636 fprintf(outfile, "%s=%d\t", optname->name, *optval.i);
637 } else {
638 Debug3("getsockopt(,,, {%d,%d}, %d)",
639 optval.i[0], optval.i[1], optlen);
640 fprintf(outfile, "%s={%d,%d}\t", optname->name,
641 optval.i[0], optval.i[1]);
643 ++optname;
646 namelen = sizeof(sockname);
647 result = Getsockname(fd, (struct sockaddr *)&sockname, &namelen);
648 if (result < 0) {
649 putc('\n', outfile);
650 Warn2("getsockname(%d): %s", fd, strerror(errno));
651 return -1;
653 fputc('\t', outfile);
654 fputs(sockaddr_info((struct sockaddr *)&sockname, namelen, nambuff, sizeof(nambuff)),
655 outfile);
657 namelen = sizeof(peername);
658 result = Getpeername(fd, (struct sockaddr *)&peername, &namelen);
659 if (result < 0) {
660 putc('\n', outfile);
661 Warn2("getpeername(%d): %s", fd, strerror(errno));
662 } else {
663 /* only valid if getpeername() succeeded */
664 fputs(" <-> ", outfile);
665 fprintf(outfile, "%s\t",
666 sockaddr_info((struct sockaddr *)&peername, namelen,
667 nambuff, sizeof(nambuff)));
670 #if 0 && defined(SIOCGIFNAME)
671 if ((result = Ioctl(fd, SIOCGIFNAME, &ifc)) < 0) {
672 Warn3("ioctl(%d, SIOCGIFNAME, %p): %s", fd, &ifc, strerror(errno));
673 } else {
674 fprintf(outfile, "IFNAME=\"%s\"\t", ifc.ifr_name);
676 #endif /* SIOCGIFNAME */
678 switch (((struct sockaddr *)&sockname)->sa_family) {
679 #if WITH_UNIX
680 case AF_UNIX:
681 /* no options for unix domain sockets known yet -> no unixan() */
682 result = 0;
683 break;
684 #endif
685 #if WITH_IP4
686 case AF_INET:
687 result = ipan(fd, outfile);
688 break;
689 #endif
690 #if WITH_IP6
691 case AF_INET6:
692 result = ipan(fd, outfile);
693 result |= ip6an(fd, outfile);
694 break;
695 #endif
696 default:
697 fputs("**** NO FURTHER ANALYSIS FOR THIS SOCKET TYPE IMPLEMENTED", outfile);
698 result = 0;
700 return result;
701 #undef FILAN_OPTLEN
702 #undef FILAN_NAMELEN
704 #endif /* _WITH_SOCKET */
707 #if WITH_IP4 || WITH_IP6
708 /* prints the option values for the IP protocol and the IP based protocols */
709 /* no distinction between IP4 and IP6 yet */
710 int ipan(int fd, FILE *outfile) {
711 /* in Linux these optcodes are 'enum', but on AIX they are bits! */
712 static const struct sockopt ipopts[] = {
713 {IP_TOS, "IP_TOS"},
714 {IP_TTL, "IP_TTL"},
715 #ifdef IP_HDRINCL
716 {IP_HDRINCL, "IP_HDRINCL"},
717 #endif
718 #ifdef IP_OPTIONS
719 {IP_OPTIONS, "IP_OPTIONS"},
720 #endif
721 #ifdef IP_ROUTER_ALERT
722 {IP_ROUTER_ALERT, "IP_ROUTER_ALERT"},
723 #endif
724 #ifdef IP_RECVOPTS
725 {IP_RECVOPTS, "IP_RECVOPTS"},
726 #endif
727 #ifdef IP_RETOPTS
728 {IP_RETOPTS, "IP_RETOPTS"},
729 #endif
730 #ifdef IP_PKTINFO
731 {IP_PKTINFO, "IP_PKTINFO"},
732 #endif
733 #ifdef IP_PKTOPTIONS
734 {IP_PKTOPTIONS, "IP_PKTOPTIONS"},
735 #endif
736 #ifdef IP_MTU_DISCOVER
737 {IP_MTU_DISCOVER, "IP_MTU_DISCOVER"},
738 #endif
739 #ifdef IP_RECVERR
740 {IP_RECVERR, "IP_RECVERR"},
741 #endif
742 #ifdef IP_RECVTTL
743 {IP_RECVTTL, "IP_RECVTTL"},
744 #endif
745 #ifdef IP_RECVTOS
746 {IP_RECVTOS, "IP_RECVTOS"},
747 #endif
748 #ifdef IP_MTU
749 {IP_MTU, "IP_MTU"},
750 #endif
751 #ifdef IP_FREEBIND
752 {IP_FREEBIND, "IP_FREEBIND"},
753 #endif
754 #ifdef IP_MULTICAST_TTL
755 {IP_MULTICAST_TTL, "IP_MULTICAST_TTL"},
756 #endif
757 #ifdef IP_MULTICAST_LOOP
758 {IP_MULTICAST_LOOP, "IP_MULTICAST_LOOP"},
759 #endif
760 {0, NULL} } ;
761 const struct sockopt *optname;
762 int opttype;
763 socklen_t optlen = sizeof(opttype);
765 optname = ipopts; while (optname->so) {
766 sockoptan(fd, optname, SOL_IP, outfile);
767 ++optname;
769 /* want to pass the fd to the next layer protocol. dont know how to get the
770 protocol number from the fd? use TYPE to identify TCP. */
771 if (Getsockopt(fd, SOL_SOCKET, SO_TYPE, &opttype, &optlen) >= 0) {
772 switch (opttype) {
773 #if WITH_TCP
774 case SOCK_STREAM: tcpan(fd, outfile); break;
775 #endif
778 return 0;
780 #endif /* WITH_IP */
783 #if WITH_IP6
784 /* prints the option values for the IPv6 protocol */
785 int ip6an(int fd, FILE *outfile) {
786 static const struct sockopt ip6opts[] = {
787 #ifdef IPV6_V6ONLY
788 {IPV6_V6ONLY, "IPV6_V6ONLY"},
789 #endif
790 {0, NULL} } ;
791 const struct sockopt *optname;
793 optname = ip6opts; while (optname->so) {
794 sockoptan(fd, optname, SOL_IPV6, outfile);
795 ++optname;
797 return 0;
799 #endif /* WITH_IP6 */
802 #if WITH_TCP
803 int tcpan(int fd, FILE *outfile) {
804 static const struct sockopt tcpopts[] = {
805 #ifdef TCP_NODELAY
806 { TCP_NODELAY, "TCP_NODELAY" },
807 #endif
808 #ifdef TCP_MAXSEG
809 { TCP_MAXSEG, "TCP_MAXSEG" },
810 #endif
811 #ifdef TCP_STDURG
812 { TCP_STDURG, "TCP_STDURG" },
813 #endif
814 #ifdef TCP_RFC1323
815 { TCP_RFC1323, "TCP_RFC1323" },
816 #endif
817 #ifdef TCP_CORK
818 { TCP_CORK, "TCP_CORK" },
819 #endif
820 #ifdef TCP_KEEPIDLE
821 { TCP_KEEPIDLE, "TCP_KEEPIDLE" },
822 #endif
823 #ifdef TCP_KEEPINTVL
824 { TCP_KEEPINTVL, "TCP_KEEPINTVL" },
825 #endif
826 #ifdef TCP_KEEPCNT
827 { TCP_KEEPCNT, "TCP_KEEPCNT" },
828 #endif
829 #ifdef TCP_SYNCNT
830 { TCP_SYNCNT, "TCP_SYNCNT" },
831 #endif
832 #ifdef TCP_LINGER2
833 { TCP_LINGER2, "TCP_LINGER2" },
834 #endif
835 #ifdef TCP_DEFER_ACCEPT
836 { TCP_DEFER_ACCEPT, "TCP_ACCEPT" },
837 #endif
838 #ifdef TCP_WINDOW_CLAMP
839 { TCP_WINDOW_CLAMP, "TCP_WINDOW_CLAMP" },
840 #endif
841 #ifdef TCP_INFO
842 { TCP_INFO, "TCP_INFO" },
843 #endif
844 #ifdef TCP_QUICKACK
845 { TCP_QUICKACK, "TCP_QUICKACK" },
846 #endif
847 #ifdef TCP_MD5SIG
848 { TCP_MD5SIG, "TCP_MD5SIG" },
849 #endif
850 #ifdef TCP_NOOPT
851 { TCP_NOOPT, "TCP_NOOPT" },
852 #endif
853 #ifdef TCP_NOPUSH
854 { TCP_NOPUSH, "TCP_NOPUSH" },
855 #endif
856 #ifdef TCP_SACK_DISABLE
857 { TCP_SACK_DISABLE, "TCP_SACK_DISABLE" },
858 #endif
859 #ifdef TCP_SIGNATURE_ENABLE
860 { TCP_SIGNATURE_ENABLE, "TCP_SIGNATURE_ENABLE" },
861 #endif
862 #ifdef TCP_ABORT_THRESHOLD
863 { TCP_ABORT_THRESHOLD, "TCP_ABORT_THRESHOLD" },
864 #endif
865 #ifdef TCP_CONN_ABORT_THRESHOLD
866 { TCP_CONN_ABORT_THRESHOLD, "TCP_CONN_ABORT_THRESHOLD" },
867 #endif
868 #ifdef TCP_KEEPINIT
869 { TCP_KEEPINIT, "TCP_KEEPINIT" },
870 #endif
871 #ifdef TCP_PAWS
872 { TCP_PAWS, "TCP_PAWS" },
873 #endif
874 #ifdef TCP_SACKENA
875 { TCP_SACKENA, "TCP_SACKENA" },
876 #endif
877 #ifdef TCP_TSOPTENA
878 { TCP_TSOPTENA, "TCP_TSOPTENA" },
879 #endif
880 {0, NULL}
882 const struct sockopt *optname;
884 optname = tcpopts; while (optname->so) {
885 sockoptan(fd, optname, SOL_TCP, outfile);
886 ++optname;
888 return 0;
890 #endif /* WITH_TCP */
893 #if _WITH_SOCKET
894 int sockoptan(int fd, const struct sockopt *optname, int socklay, FILE *outfile) {
895 #define FILAN_OPTLEN 256
896 union {
897 char c[FILAN_OPTLEN];
898 int i[FILAN_OPTLEN/sizeof(int)];
899 } optval;
900 socklen_t optlen;
901 int result;
903 optlen = FILAN_OPTLEN;
904 result =
905 Getsockopt(fd, socklay, optname->so, (void *)optval.c, &optlen);
906 if (result < 0) {
907 Debug6("getsockopt(%d, %d, %d, %p, {"F_socklen"}): %s",
908 fd, socklay, optname->so, optval.c, optlen, strerror(errno));
909 fputc('\t', outfile);
910 return -1;
911 } else if (optlen == 0) {
912 Debug1("getsockopt(,,, {}, %d)", optlen);
913 fprintf(outfile, "%s=\"\"\t", optname->name);
914 } else if (optlen == sizeof(int)) {
915 Debug2("getsockopt(,,, {%d}, %d)",
916 *optval.i, optlen);
917 fprintf(outfile, "%s=%d\t", optname->name, *optval.i);
918 } else {
919 char outbuf[FILAN_OPTLEN*9+128], *cp = outbuf;
920 int i;
921 for (i = 0; i < optlen/sizeof(unsigned int); ++i) {
922 cp += sprintf(cp, "%08x ", (unsigned int)optval.i[i]);
924 *--cp = '\0'; /* delete trailing space */
925 Debug2("getsockopt(,,, {%s}, %d)", outbuf, optlen);
926 fflush(outfile);
927 fprintf(outfile, "%s={%s}\t", optname->name, outbuf);
929 return 0;
930 #undef FILAN_OPTLEN
932 #endif /* _WITH_SOCKET */
935 #if _WITH_SOCKET
936 int isasocket(int fd) {
937 int retval;
938 #if HAVE_STAT64
939 struct stat64 props;
940 #else
941 struct stat props;
942 #endif /* HAVE_STAT64 */
943 retval =
944 #if HAVE_STAT64
945 Fstat64(fd, &props);
946 #else
947 Fstat(fd, &props);
948 #endif
949 if (retval < 0) {
950 Info3("fstat(%d, %p): %s", fd, &props, strerror(errno));
951 return 0;
953 /* note: when S_ISSOCK was undefined, it always gives 0 */
954 return S_ISSOCK(props.st_mode);
956 #endif /* _WITH_SOCKET */
959 const char *getfiletypestring(int st_mode) {
960 const char *s;
962 switch (st_mode&S_IFMT) {
963 case S_IFIFO: s = "pipe"; break;
964 case S_IFCHR: s = "chrdev"; break;
965 case S_IFDIR: s = "dir"; break;
966 case S_IFBLK: s = "blkdev"; break;
967 case S_IFREG: s = "file"; break;
968 case S_IFLNK: s = "symlink"; break;
969 case S_IFSOCK: s = "socket"; break;
970 /*! AIX: MT? */
971 default: s = "undef"; break;
973 return s;
976 static int printtime(FILE *outfile, time_t time) {
977 const char *s;
979 if (filan_rawoutput) {
980 fprintf(outfile, "\t"F_time, time);
981 } else {
982 fputc('\t', outfile);
983 s = asctime(localtime(&time));
984 if (strchr(s, '\n')) *strchr(s, '\n') = '\0';
985 fputs(s, outfile);
987 return 0;