add listen-timeout to function as an accept timeout
[socat/sam.git] / filan.c
blob6461e47e3746e1bf495308384819fb6eb49c0e4e
1 /* source: filan.c */
2 /* Copyright Gerhard Rieger 2001-2008 */
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];
218 int result;
220 /* print header */
221 if (!headprinted) {
222 if (filan_rawoutput) {
223 fputs(" FD type\tdevice\tinode\tmode\tlinks\tuid\tgid"
224 #if HAVE_ST_RDEV
225 "\trdev"
226 #endif
227 "\tsize"
228 #if HAVE_ST_BLKSIZE
229 "\tblksize"
230 #endif
231 #if HAVE_ST_BLOCKS
232 "\tblocks"
233 #endif
234 "\tatime\t\tmtime\t\tctime\t\tcloexec\tflags"
235 #if defined(F_GETOWN)
236 "\tsigown"
237 #endif
238 , outfile);
239 } else /* !rawoutput */ {
240 fputs(" FD type\tdevice\tinode\tmode\tlinks\tuid\tgid"
241 #if HAVE_ST_RDEV
242 "\trdev"
243 #endif
244 "\tsize"
245 #if HAVE_ST_BLKSIZE
246 "\tblksize"
247 #endif
248 #if HAVE_ST_BLOCKS
249 "\tblocks"
250 #endif
251 "\tatime\t\t\t\tmtime\t\t\t\tctime\t\t\t\tcloexec\tflags"
252 #if defined(F_GETOWN)
253 "\tsigown"
254 #endif
255 , outfile);
257 } /* endif !rawoutput */
259 #if defined(F_GETSIG)
260 fputs("\tsigio", outfile);
261 #endif /* defined(F_GETSIG) */
262 fputc('\n', outfile);
263 headprinted = 1;
265 if (filan_rawoutput) {
266 snprintf(stdevstr, 8, F_st_dev, buf->st_dev);
267 } else {
268 snprintf(stdevstr, 8, "%hu,%hu", (unsigned short)buf->st_dev>>8, (unsigned short)buf->st_dev&0xff);
270 fprintf(outfile, "%4d: %s\t%s\t"
271 #if HAVE_STAT64
272 F_st64_ino
273 #else
274 F_st_ino
275 #endif /* HAVE_STAT64 */
276 "\t"F_mode"\t"F_st_nlink"\t"F_uid"\t"F_gid
277 #if HAVE_ST_RDEV
278 "\t%hu,%hu"
279 #endif
280 "\t"
281 #if HAVE_STAT64
282 F_st64_size
283 #else
284 F_st_size
285 #endif /* HAVE_STAT64 */
286 #if HAVE_ST_BLKSIZE
287 "\t"F_st_blksize
288 #endif
289 #if HAVE_ST_BLOCKS
290 #if HAVE_STAT64
291 "\t"F_st64_blocks
292 #else
293 "\t"F_st_blocks
294 #endif /* HAVE_STAT64 */
295 #endif
297 (dynfd>=0?dynfd:statfd), getfiletypestring(buf->st_mode),
298 stdevstr,
299 buf->st_ino,
300 buf->st_mode, buf->st_nlink, buf->st_uid,
301 buf->st_gid,
302 #if HAVE_ST_RDEV
303 (unsigned short)buf->st_rdev>>8, (unsigned short)buf->st_rdev&0xff,
304 #endif
305 buf->st_size
306 #if HAVE_ST_BLKSIZE
307 , buf->st_blksize
308 #endif
309 #if HAVE_ST_BLOCKS
310 , buf->st_blocks /* on Linux, this applies to stat and stat64 */
311 #endif
314 printtime(outfile, buf->st_atime);
315 printtime(outfile, buf->st_mtime);
316 printtime(outfile, buf->st_ctime);
318 #if 0
320 fputc('\t', outfile);
321 time = asctime(localtime(&buf->st_mtime));
322 if (strchr(time, '\n')) *strchr(time, '\n') = '\0';
323 fputs(time, outfile);
325 fputc('\t', outfile);
326 time = asctime(localtime(&buf->st_ctime));
327 if (strchr(time, '\n')) *strchr(time, '\n') = '\0';
328 fputs(time, outfile);
330 #endif
332 /* here comes dynamic info - it is only meaningful with preexisting FDs */
333 if (dynfd >= 0) { /*!indent */
334 int cloexec, flags;
335 #if defined(F_GETOWN)
336 int sigown;
337 #endif
338 #if defined(F_GETSIG)
339 int sigio;
340 #endif /* defined(F_GETSIG) */
342 cloexec = Fcntl(dynfd, F_GETFD);
343 flags = Fcntl(dynfd, F_GETFL);
344 #if defined(F_GETOWN)
345 sigown = Fcntl(dynfd, F_GETOWN);
346 #endif
347 #if defined(F_GETSIG)
348 sigio = Fcntl(dynfd, F_GETSIG);
349 #endif /* defined(F_GETSIG) */
350 fprintf(outfile, "\t%d\tx%06x", cloexec, flags);
351 #if defined(F_GETOWN)
352 fprintf(outfile, "\t%d", sigown);
353 #endif
354 #if defined(F_GETSIG)
355 fprintf(outfile, "\t%d", sigio);
356 #endif /* defined(F_GETSIG) */
357 } else {
358 fputs("\t\t"
359 #if defined(F_GETOWN)
360 "\t"
361 #endif
362 #if defined(F_GETSIG)
363 "\t"
364 #endif /* defined(F_GETSIG) */
365 , outfile);
368 /* ever heard of POSIX streams? here we handle these */
369 filan_streams_analyze(statfd, outfile);
371 /* now see for type specific infos */
372 if (statfd >= 0) { /*!indent */
373 switch (buf->st_mode&S_IFMT) {
374 case (S_IFIFO): /* 1, FIFO */
375 break;
376 case (S_IFCHR): /* 2, character device */
377 result = cdevan(statfd, outfile);
378 break;
379 case (S_IFDIR): /* 4, directory */
380 break;
381 case (S_IFBLK): /* 6, block device */
382 break;
383 case (S_IFREG): /* 8, regular file */
384 break;
385 case (S_IFLNK): /* 10, symbolic link */
386 break;
387 #ifdef S_IFSOCK
388 case (S_IFSOCK): /* 12, socket */
389 #if _WITH_SOCKET
390 result = sockan(statfd, outfile);
391 #else
392 Warn("SOCKET support not compiled in");
393 return -1;
394 #endif /* !_WITH_SOCKET */
395 break;
396 #endif /* S_IFSOCK */
399 /* ioctl() */
400 return 0;
404 #if LATER
405 int fdinfo(int fd) {
406 int result;
408 result = Fcntl(fd, F_GETFD);
409 fcntl(fd, F_GETFL, );
410 fcntl(fd, F_GETLK, );
411 #ifdef F_GETOWN
412 fcntl(fd, F_GETOWN, );
413 #endif
414 #ifdef F_GETSIG
415 fcntl(fd, F_GETSIG, );
416 #endif
420 int devinfo(int fd) {
421 ioctl();
423 #endif
426 /* returns 0 on success (not a stream descriptor, or no module)
427 returns <0 on failure */
428 static int filan_streams_analyze(int fd, FILE *outfile) {
429 #ifdef I_LIST
430 # define SL_NMODS 8 /* max number of module names we can store */
431 struct str_list modnames;
432 int i;
434 if (!isastream(fd)) {
435 fprintf(outfile, "\t(no STREAMS modules)");
436 return 0;
438 #if 0 /* uncomment for debugging */
439 fprintf(outfile, "\tfind=%d", ioctl(fd, I_FIND, "ldterm"));
440 #endif
441 modnames.sl_nmods = ioctl(fd, I_LIST, 0);
442 if (modnames.sl_nmods < 0) {
443 fprintf(stderr, "ioctl(%d, I_LIST, 0): %s\n", fd, strerror(errno));
444 return -1;
446 modnames.sl_modlist = Malloc(modnames.sl_nmods*(sizeof(struct str_mlist)));
447 if (modnames.sl_modlist == NULL) {
448 fprintf(stderr, "out of memory\n");
449 return -1;
451 if (ioctl(fd, I_LIST, &modnames) < 0) {
452 fprintf(stderr, "ioctl(%d, I_LIST, %p): %s\n",
453 fd, &modnames, strerror(errno));
454 free(modnames.sl_modlist);
455 return -1;
457 fprintf(outfile, "\tSTREAMS: ");
458 for (i = 0; i < modnames.sl_nmods; ++i) {
459 fprintf(outfile, "\"%s\"", modnames.sl_modlist[i].l_name);
460 if (i+1 < modnames.sl_nmods) fputc(',', outfile);
462 free(modnames.sl_modlist);
463 #endif /* defined(I_LIST) */
464 return 0;
468 /* character device analysis */
469 int cdevan(int fd, FILE *outfile) {
470 int ret;
472 #if _WITH_TERMIOS
473 if ((ret = Isatty(fd)) < 0) {
474 Warn2("isatty(%d): %s", fd, strerror(errno));
475 return -1;
477 if (ret > 0) {
478 struct termios termarg;
479 char *name;
480 int i;
482 if ((name = Ttyname(fd)) == NULL) {
483 /*Warn2("ttyname(%d): %s", fd, strerror(errno));*/
484 fputs("\tNULL", outfile);
485 } else {
486 fprintf(outfile, "\t%s", name);
488 if (Tcgetattr(fd, &termarg) < 0) {
489 Warn3("tcgetattr(%d, %p): %s", fd, &termarg, strerror(errno));
490 return -1;
492 fprintf(outfile, " \tIFLAGS=%08x OFLAGS=%08x CFLAGS=%08x LFLAGS=%08x",
493 termarg.c_iflag, termarg.c_oflag, termarg.c_cflag, termarg.c_lflag);
495 /* and the control characters */
496 if (filan_rawoutput) {
497 for (i=0; i<NCCS; ++i) {
498 fprintf(outfile, " cc[%d]=%d", i, termarg.c_cc[i]);
500 } else {
501 for (i=0; i<NCCS; ++i) {
502 int ch;
503 unsigned char s[4];
504 ch = termarg.c_cc[i];
505 if (isprint(ch)) {
506 s[0] = ch; s[1]= '\0';
507 } else if (ch < ' ') {
508 s[0] = '^'; s[1] = ch+'@'; s[2] = '\0';
509 } else {
510 s[0] = 'x';
511 s[1] = (ch>>4)>=10?(ch>>4)-10+'A':(ch>>4)+'0';
512 s[2] = (ch&0x0f)>=10?(ch&0x0f)-10+'A':(ch&0x0f)+'0';
513 s[3] = '\0';
515 fprintf(outfile, " cc[%d]=%s", i, s);
519 #endif /* _WITH_TERMIOS */
520 return 0;
524 #if _WITH_SOCKET
525 int sockan(int fd, FILE *outfile) {
526 #define FILAN_OPTLEN 256
527 #define FILAN_NAMELEN 256
528 socklen_t optlen;
529 int result /*0, i*/;
530 static const char *socktypes[] = {
531 "undef", "STREAM", "DGRAM", "RAW", "RDM",
532 "SEQPACKET", "undef", "undef", "undef", "undef",
533 "PACKET", "undef" } ;
534 char nambuff[FILAN_NAMELEN];
535 /* in Linux these optcodes are 'enum', but on AIX they are bits! */
536 static const struct sockopt sockopts[] = {
537 {SO_DEBUG, "DEBUG"},
538 {SO_REUSEADDR, "REUSEADDR"},
539 {SO_TYPE, "TYPE"},
540 {SO_ERROR, "ERROR"},
541 #ifdef SO_PROTOTYPE
542 {SO_PROTOTYPE, "PROTOTYPE"},
543 #endif
544 {SO_DONTROUTE, "DONTROUTE"},
545 {SO_BROADCAST, "BROADCAST"},
546 {SO_SNDBUF, "SNDBUF"},
547 {SO_RCVBUF, "RCVBUF"},
548 {SO_KEEPALIVE, "KEEPALIVE"},
549 {SO_OOBINLINE, "OOBINLINE"},
550 #ifdef SO_NO_CHECK
551 {SO_NO_CHECK, "NO_CHECK"},
552 #endif
553 #ifdef SO_PRIORITY
554 {SO_PRIORITY, "PRIORITY"},
555 #endif
556 {SO_LINGER, "LINGER"},
557 #ifdef SO_BSDCOMPAT
558 {SO_BSDCOMPAT, "BSDCOMPAT"},
559 #endif
560 #ifdef SO_REUSEPORT
561 {SO_REUSEPORT, "REUSEPORT"},
562 #endif /* defined(SO_REUSEPORT) */
563 #ifdef SO_PASSCRED
564 {SO_PASSCRED, "PASSCRED"},
565 #endif
566 #ifdef SO_PEERCRED
567 {SO_PEERCRED, "PEERCRED"},
568 #endif
569 #ifdef SO_RCVLOWAT
570 {SO_RCVLOWAT, "RCVLOWAT"},
571 #endif
572 #ifdef SO_SNDLOWAT
573 {SO_SNDLOWAT, "SNDLOWAT"},
574 #endif
575 #ifdef SO_RCVTIMEO
576 {SO_RCVTIMEO, "RCVTIMEO"},
577 #endif
578 #ifdef SO_SNDTIMEO
579 {SO_SNDTIMEO, "SNDTIMEO"},
580 #endif
581 #ifdef SO_SECURITY_AUTHENTICATION
582 {SO_SECURITY_AUTHENTICATION, "SECURITY_AUTHENTICATION"},
583 #endif
584 #ifdef SO_SECURITY_ENCRYPTION_TRANSPORT
585 {SO_SECURITY_ENCRYPTION_TRANSPORT, "SECURITY_ENCRYPTION_TRANSPORT"},
586 #endif
587 #ifdef SO_SECURITY_ENCRYPTION_NETWORK
588 {SO_SECURITY_ENCRYPTION_NETWORK, "SECURITY_ENCRYPTION_NETWORK"},
589 #endif
590 #ifdef SO_BINDTODEVICE
591 {SO_BINDTODEVICE, "BINDTODEVICE"},
592 #endif
593 #ifdef SO_ATTACH_FILTER
594 {SO_ATTACH_FILTER, "ATTACH_FILTER"},
595 #endif
596 #ifdef SO_DETACH_FILTER
597 {SO_DETACH_FILTER, "DETACH_FILTER"},
598 #endif
599 {0, NULL} } ;
600 char optval[FILAN_OPTLEN];
601 const struct sockopt *optname;
602 union sockaddr_union sockname, peername; /* the longest I know of */
603 socklen_t namelen;
604 #if 0 && defined(SIOCGIFNAME)
605 /*Linux struct ifreq ifc = {{{ 0 }}};*/
606 struct ifreq ifc = {{ 0 }};
607 #endif
609 optlen = FILAN_OPTLEN;
610 result = Getsockopt(fd, SOL_SOCKET, SO_TYPE, optval, &optlen);
611 if (result < 0) {
612 Debug4("getsockopt(%d, SOL_SOCKET, SO_TYPE, %p, {"F_socklen"}): %s",
613 fd, optval, optlen, strerror(errno));
614 } else {
615 Debug3("fd %d: socket of type %d (\"%s\")", fd, *(int *)optval,
616 socktypes[*(int *)optval]);
619 optname = sockopts; while (optname->so) {
620 optlen = FILAN_OPTLEN;
621 result =
622 Getsockopt(fd, SOL_SOCKET, optname->so, (void *)optval, &optlen);
623 if (result < 0) {
624 Debug5("getsockopt(%d, SOL_SOCKET, %d, %p, {"F_socklen"}): %s",
625 fd, optname->so, optval, optlen, strerror(errno));
626 fputc('\t', outfile);
627 } else if (optlen == sizeof(int)) {
628 Debug2("getsockopt(,,, {%d}, %d)",
629 *(int *)optval, optlen);
630 /*Info2("%s: %d", optname->name, *(int *)optval);*/
631 fprintf(outfile, "%s=%d\t", optname->name, *(int *)optval);
632 } else {
633 Debug3("getsockopt(,,, {%d,%d}, %d)",
634 ((int *)optval)[0], ((int *)optval)[1], optlen);
635 fprintf(outfile, "%s={%d,%d}\t", optname->name,
636 ((int *)optval)[0], ((int *)optval)[1]);
638 ++optname;
641 namelen = sizeof(sockname);
642 result = Getsockname(fd, (struct sockaddr *)&sockname, &namelen);
643 if (result < 0) {
644 putc('\n', outfile);
645 Warn2("getsockname(%d): %s", fd, strerror(errno));
646 return -1;
648 fputc('\t', outfile);
649 fputs(sockaddr_info((struct sockaddr *)&sockname, namelen, nambuff, sizeof(nambuff)),
650 outfile);
652 namelen = sizeof(peername);
653 result = Getpeername(fd, (struct sockaddr *)&peername, &namelen);
654 if (result < 0) {
655 putc('\n', outfile);
656 Warn2("getpeername(%d): %s", fd, strerror(errno));
657 } else {
658 /* only valid if getpeername() succeeded */
659 fputs(" <-> ", outfile);
660 fprintf(outfile, "%s\t",
661 sockaddr_info((struct sockaddr *)&peername, namelen,
662 nambuff, sizeof(nambuff)));
665 #if 0 && defined(SIOCGIFNAME)
666 if ((result = Ioctl(fd, SIOCGIFNAME, &ifc)) < 0) {
667 Warn3("ioctl(%d, SIOCGIFNAME, %p): %s", fd, &ifc, strerror(errno));
668 } else {
669 fprintf(outfile, "IFNAME=\"%s\"\t", ifc.ifr_name);
671 #endif /* SIOCGIFNAME */
673 switch (((struct sockaddr *)&sockname)->sa_family) {
674 #if WITH_UNIX
675 case AF_UNIX:
676 /* no options for unix domain sockets known yet -> no unixan() */
677 result = 0;
678 break;
679 #endif
680 #if WITH_IP4
681 case AF_INET:
682 result = ipan(fd, outfile);
683 break;
684 #endif
685 #if WITH_IP6
686 case AF_INET6:
687 result = ipan(fd, outfile);
688 result |= ip6an(fd, outfile);
689 break;
690 #endif
691 default:
692 fputs("**** NO FURTHER ANALYSIS FOR THIS SOCKET TYPE IMPLEMENTED", outfile);
693 result = 0;
695 return result;
696 #undef FILAN_OPTLEN
697 #undef FILAN_NAMELEN
699 #endif /* _WITH_SOCKET */
702 #if WITH_IP4 || WITH_IP6
703 /* prints the option values for the IP protocol and the IP based protocols */
704 /* no distinction between IP4 and IP6 yet */
705 int ipan(int fd, FILE *outfile) {
706 /* in Linux these optcodes are 'enum', but on AIX they are bits! */
707 static const struct sockopt ipopts[] = {
708 {IP_TOS, "IP_TOS"},
709 {IP_TTL, "IP_TTL"},
710 #ifdef IP_HDRINCL
711 {IP_HDRINCL, "IP_HDRINCL"},
712 #endif
713 #ifdef IP_OPTIONS
714 {IP_OPTIONS, "IP_OPTIONS"},
715 #endif
716 #ifdef IP_ROUTER_ALERT
717 {IP_ROUTER_ALERT, "IP_ROUTER_ALERT"},
718 #endif
719 #ifdef IP_RECVOPTS
720 {IP_RECVOPTS, "IP_RECVOPTS"},
721 #endif
722 #ifdef IP_RETOPTS
723 {IP_RETOPTS, "IP_RETOPTS"},
724 #endif
725 #ifdef IP_PKTINFO
726 {IP_PKTINFO, "IP_PKTINFO"},
727 #endif
728 #ifdef IP_PKTOPTIONS
729 {IP_PKTOPTIONS, "IP_PKTOPTIONS"},
730 #endif
731 #ifdef IP_MTU_DISCOVER
732 {IP_MTU_DISCOVER, "IP_MTU_DISCOVER"},
733 #endif
734 #ifdef IP_RECVERR
735 {IP_RECVERR, "IP_RECVERR"},
736 #endif
737 #ifdef IP_RECVTTL
738 {IP_RECVTTL, "IP_RECVTTL"},
739 #endif
740 #ifdef IP_RECVTOS
741 {IP_RECVTOS, "IP_RECVTOS"},
742 #endif
743 #ifdef IP_MTU
744 {IP_MTU, "IP_MTU"},
745 #endif
746 #ifdef IP_FREEBIND
747 {IP_FREEBIND, "IP_FREEBIND"},
748 #endif
749 #ifdef IP_MULTICAST_TTL
750 {IP_MULTICAST_TTL, "IP_MULTICAST_TTL"},
751 #endif
752 #ifdef IP_MULTICAST_LOOP
753 {IP_MULTICAST_LOOP, "IP_MULTICAST_LOOP"},
754 #endif
755 {0, NULL} } ;
756 const struct sockopt *optname;
757 int opttype;
758 socklen_t optlen = sizeof(opttype);
760 optname = ipopts; while (optname->so) {
761 sockoptan(fd, optname, SOL_IP, outfile);
762 ++optname;
764 /* want to pass the fd to the next layer protocol. dont know how to get the
765 protocol number from the fd? use TYPE to identify TCP. */
766 if (Getsockopt(fd, SOL_SOCKET, SO_TYPE, &opttype, &optlen) >= 0) {
767 switch (opttype) {
768 #if WITH_TCP
769 case SOCK_STREAM: tcpan(fd, outfile); break;
770 #endif
773 return 0;
775 #endif /* WITH_IP */
778 #if WITH_IP6
779 /* prints the option values for the IPv6 protocol */
780 int ip6an(int fd, FILE *outfile) {
781 static const struct sockopt ip6opts[] = {
782 #ifdef IPV6_V6ONLY
783 {IPV6_V6ONLY, "IPV6_V6ONLY"},
784 #endif
785 {0, NULL} } ;
786 const struct sockopt *optname;
788 optname = ip6opts; while (optname->so) {
789 sockoptan(fd, optname, SOL_IPV6, outfile);
790 ++optname;
792 return 0;
794 #endif /* WITH_IP6 */
797 #if WITH_TCP
798 int tcpan(int fd, FILE *outfile) {
799 static const struct sockopt tcpopts[] = {
800 #ifdef TCP_NODELAY
801 { TCP_NODELAY, "TCP_NODELAY" },
802 #endif
803 #ifdef TCP_MAXSEG
804 { TCP_MAXSEG, "TCP_MAXSEG" },
805 #endif
806 #ifdef TCP_STDURG
807 { TCP_STDURG, "TCP_STDURG" },
808 #endif
809 #ifdef TCP_RFC1323
810 { TCP_RFC1323, "TCP_RFC1323" },
811 #endif
812 #ifdef TCP_CORK
813 { TCP_CORK, "TCP_CORK" },
814 #endif
815 #ifdef TCP_KEEPIDLE
816 { TCP_KEEPIDLE, "TCP_KEEPIDLE" },
817 #endif
818 #ifdef TCP_KEEPINTVL
819 { TCP_KEEPINTVL, "TCP_KEEPINTVL" },
820 #endif
821 #ifdef TCP_KEEPCNT
822 { TCP_KEEPCNT, "TCP_KEEPCNT" },
823 #endif
824 #ifdef TCP_SYNCNT
825 { TCP_SYNCNT, "TCP_SYNCNT" },
826 #endif
827 #ifdef TCP_LINGER2
828 { TCP_LINGER2, "TCP_LINGER2" },
829 #endif
830 #ifdef TCP_DEFER_ACCEPT
831 { TCP_DEFER_ACCEPT, "TCP_ACCEPT" },
832 #endif
833 #ifdef TCP_WINDOW_CLAMP
834 { TCP_WINDOW_CLAMP, "TCP_WINDOW_CLAMP" },
835 #endif
836 #ifdef TCP_INFO
837 { TCP_INFO, "TCP_INFO" },
838 #endif
839 #ifdef TCP_QUICKACK
840 { TCP_QUICKACK, "TCP_QUICKACK" },
841 #endif
842 #ifdef TCP_MD5SIG
843 { TCP_MD5SIG, "TCP_MD5SIG" },
844 #endif
845 #ifdef TCP_NOOPT
846 { TCP_NOOPT, "TCP_NOOPT" },
847 #endif
848 #ifdef TCP_NOPUSH
849 { TCP_NOPUSH, "TCP_NOPUSH" },
850 #endif
851 #ifdef TCP_SACK_DISABLE
852 { TCP_SACK_DISABLE, "TCP_SACK_DISABLE" },
853 #endif
854 #ifdef TCP_SIGNATURE_ENABLE
855 { TCP_SIGNATURE_ENABLE, "TCP_SIGNATURE_ENABLE" },
856 #endif
857 #ifdef TCP_ABORT_THRESHOLD
858 { TCP_ABORT_THRESHOLD, "TCP_ABORT_THRESHOLD" },
859 #endif
860 #ifdef TCP_CONN_ABORT_THRESHOLD
861 { TCP_CONN_ABORT_THRESHOLD, "TCP_CONN_ABORT_THRESHOLD" },
862 #endif
863 #ifdef TCP_KEEPINIT
864 { TCP_KEEPINIT, "TCP_KEEPINIT" },
865 #endif
866 #ifdef TCP_PAWS
867 { TCP_PAWS, "TCP_PAWS" },
868 #endif
869 #ifdef TCP_SACKENA
870 { TCP_SACKENA, "TCP_SACKENA" },
871 #endif
872 #ifdef TCP_TSOPTENA
873 { TCP_TSOPTENA, "TCP_TSOPTENA" },
874 #endif
875 {0, NULL}
877 const struct sockopt *optname;
879 optname = tcpopts; while (optname->so) {
880 sockoptan(fd, optname, SOL_TCP, outfile);
881 ++optname;
883 return 0;
885 #endif /* WITH_TCP */
888 #if _WITH_SOCKET
889 int sockoptan(int fd, const struct sockopt *optname, int socklay, FILE *outfile) {
890 #define FILAN_OPTLEN 256
891 char optval[FILAN_OPTLEN];
892 socklen_t optlen;
893 int result;
895 optlen = FILAN_OPTLEN;
896 result =
897 Getsockopt(fd, socklay, optname->so, (void *)optval, &optlen);
898 if (result < 0) {
899 Debug6("getsockopt(%d, %d, %d, %p, {"F_socklen"}): %s",
900 fd, socklay, optname->so, optval, optlen, strerror(errno));
901 fputc('\t', outfile);
902 return -1;
903 } else if (optlen == 0) {
904 Debug1("getsockopt(,,, {}, %d)", optlen);
905 fprintf(outfile, "%s=\"\"\t", optname->name);
906 } else if (optlen == sizeof(int)) {
907 Debug2("getsockopt(,,, {%d}, %d)",
908 *(int *)optval, optlen);
909 fprintf(outfile, "%s=%d\t", optname->name, *(int *)optval);
910 } else {
911 char outbuf[FILAN_OPTLEN*9+128], *cp = outbuf;
912 int i;
913 for (i = 0; i < optlen/sizeof(unsigned int); ++i) {
914 cp += sprintf(cp, "%08x ", ((unsigned int *)optval)[i]);
916 *--cp = '\0'; /* delete trailing space */
917 Debug2("getsockopt(,,, {%s}, %d)", outbuf, optlen);
918 fflush(outfile);
919 fprintf(outfile, "%s={%s}\t", optname->name, outbuf);
921 return 0;
922 #undef FILAN_OPTLEN
924 #endif /* _WITH_SOCKET */
927 #if _WITH_SOCKET
928 int isasocket(int fd) {
929 int retval;
930 #if HAVE_STAT64
931 struct stat64 props;
932 #else
933 struct stat props;
934 #endif /* HAVE_STAT64 */
935 retval =
936 #if HAVE_STAT64
937 Fstat64(fd, &props);
938 #else
939 Fstat(fd, &props);
940 #endif
941 if (retval < 0) {
942 Info3("fstat(%d, %p): %s", fd, &props, strerror(errno));
943 return 0;
945 /* note: when S_ISSOCK was undefined, it always gives 0 */
946 return S_ISSOCK(props.st_mode);
948 #endif /* _WITH_SOCKET */
951 const char *getfiletypestring(int st_mode) {
952 const char *s;
954 switch (st_mode&S_IFMT) {
955 case S_IFIFO: s = "pipe"; break;
956 case S_IFCHR: s = "chrdev"; break;
957 case S_IFDIR: s = "dir"; break;
958 case S_IFBLK: s = "blkdev"; break;
959 case S_IFREG: s = "file"; break;
960 case S_IFLNK: s = "symlink"; break;
961 case S_IFSOCK: s = "socket"; break;
962 /*! AIX: MT? */
963 default: s = "undef"; break;
965 return s;
968 static int printtime(FILE *outfile, time_t time) {
969 const char *s;
971 if (filan_rawoutput) {
972 fprintf(outfile, "\t"F_time, time);
973 } else {
974 fputc('\t', outfile);
975 s = asctime(localtime(&time));
976 if (strchr(s, '\n')) *strchr(s, '\n') = '\0';
977 fputs(s, outfile);
979 return 0;