nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* source: filan.c */ |
2 | /* Copyright Gerhard Rieger */ |
||
3 | /* Published under the GNU General Public License V.2, see file COPYING */ |
||
4 | |||
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! */ |
||
9 | |||
10 | #include "config.h" |
||
11 | #include "xioconfig.h" /* what features are enabled */ |
||
12 | |||
13 | #include "sysincludes.h" |
||
14 | |||
15 | #include "mytypes.h" |
||
16 | #include "compat.h" |
||
17 | #include "error.h" |
||
18 | #include "sycls.h" |
||
19 | #include "sysutils.h" |
||
20 | |||
21 | #include "filan.h" |
||
22 | |||
23 | |||
24 | struct sockopt { |
||
25 | int so; |
||
26 | char *name; |
||
27 | }; |
||
28 | |||
29 | static int filan_streams_analyze(int fd, FILE *outfile); |
||
30 | |||
31 | /* dirty workaround so we dont get an error on AIX when being linked with |
||
32 | libwrap */ |
||
33 | int allow_severity, deny_severity; |
||
34 | |||
35 | /* global variables for configuring filan */ |
||
36 | bool filan_followsymlinks; |
||
37 | bool filan_rawoutput; |
||
38 | |||
39 | |||
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); |
||
43 | |||
44 | static int printtime(FILE *outfile, time_t time); |
||
45 | |||
46 | static int headprinted; |
||
47 | |||
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 */ |
||
57 | |||
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)); |
||
66 | } |
||
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)); |
||
75 | } |
||
76 | } |
||
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)); |
||
92 | } |
||
93 | } |
||
94 | |||
95 | result = filan_stat(&buf, fd, -1, outfile); |
||
96 | fputc('\n', outfile); |
||
97 | return result; |
||
98 | } |
||
99 | |||
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; |
||
108 | |||
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)); |
||
120 | } |
||
121 | return -1; |
||
122 | } |
||
123 | Debug2("fd %d is a %s", fd, getfiletypestring(buf.st_mode)); |
||
124 | |||
125 | result = filan_stat(&buf, fd, fd, outfile); |
||
126 | |||
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 |
||
146 | ; |
||
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); |
||
162 | } |
||
163 | } |
||
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; |
||
176 | |||
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); |
||
199 | } |
||
200 | } |
||
201 | #endif /* _WITH_SOCKET && defined(MSG_DONTWAIT) */ |
||
202 | } |
||
203 | } |
||
204 | } |
||
205 | fputc('\n', outfile); |
||
206 | return 0; |
||
207 | } |
||
208 | |||
209 | |||
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 | |||
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); |
||
255 | |||
256 | } /* endif !rawoutput */ |
||
257 | |||
258 | #if defined(F_GETSIG) |
||
259 | fputs("\tsigio", outfile); |
||
260 | #endif /* defined(F_GETSIG) */ |
||
261 | fputc('\n', outfile); |
||
262 | headprinted = 1; |
||
263 | } |
||
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)); |
||
268 | } |
||
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 |
||
295 | , |
||
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 |
||
311 | ); |
||
312 | |||
313 | printtime(outfile, buf->st_atime); |
||
314 | printtime(outfile, buf->st_mtime); |
||
315 | printtime(outfile, buf->st_ctime); |
||
316 | |||
317 | #if 0 |
||
318 | { |
||
319 | fputc('\t', outfile); |
||
320 | time = asctime(localtime(&buf->st_mtime)); |
||
321 | if (strchr(time, '\n')) *strchr(time, '\n') = '\0'; |
||
322 | fputs(time, outfile); |
||
323 | |||
324 | fputc('\t', outfile); |
||
325 | time = asctime(localtime(&buf->st_ctime)); |
||
326 | if (strchr(time, '\n')) *strchr(time, '\n') = '\0'; |
||
327 | fputs(time, outfile); |
||
328 | } |
||
329 | #endif |
||
330 | |||
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) */ |
||
340 | |||
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); |
||
365 | } |
||
366 | |||
367 | /* ever heard of POSIX streams? here we handle these */ |
||
368 | filan_streams_analyze(statfd, outfile); |
||
369 | |||
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 */ |
||
396 | } |
||
397 | } |
||
398 | /* ioctl() */ |
||
399 | return 0; |
||
400 | } |
||
401 | |||
402 | |||
403 | #if LATER |
||
404 | int fdinfo(int fd) { |
||
405 | int result; |
||
406 | |||
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 |
||
416 | } |
||
417 | |||
418 | |||
419 | int devinfo(int fd) { |
||
420 | ioctl(); |
||
421 | } |
||
422 | #endif |
||
423 | |||
424 | |||
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; |
||
432 | |||
433 | if (!isastream(fd)) { |
||
434 | fprintf(outfile, "\t(no STREAMS modules)"); |
||
435 | return 0; |
||
436 | } |
||
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; |
||
444 | } |
||
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; |
||
449 | } |
||
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; |
||
455 | } |
||
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); |
||
460 | } |
||
461 | free(modnames.sl_modlist); |
||
462 | #endif /* defined(I_LIST) */ |
||
463 | return 0; |
||
464 | } |
||
465 | |||
466 | |||
467 | /* character device analysis */ |
||
468 | int cdevan(int fd, FILE *outfile) { |
||
469 | int ret; |
||
470 | |||
471 | #if _WITH_TERMIOS |
||
472 | if ((ret = Isatty(fd)) < 0) { |
||
473 | Warn2("isatty(%d): %s", fd, strerror(errno)); |
||
474 | return -1; |
||
475 | } |
||
476 | if (ret > 0) { |
||
477 | struct termios termarg; |
||
478 | char *name; |
||
479 | int i; |
||
480 | |||
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); |
||
486 | } |
||
487 | if (Tcgetattr(fd, &termarg) < 0) { |
||
488 | Warn3("tcgetattr(%d, %p): %s", fd, &termarg, strerror(errno)); |
||
489 | return -1; |
||
490 | } |
||
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); |
||
496 | |||
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]); |
||
501 | } |
||
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'; |
||
516 | } |
||
517 | fprintf(outfile, " cc[%d]=%s", i, s); |
||
518 | } |
||
519 | } |
||
520 | } |
||
521 | #endif /* _WITH_TERMIOS */ |
||
522 | return 0; |
||
523 | } |
||
524 | |||
525 | |||
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 |
||
613 | |||
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]); |
||
622 | } |
||
623 | |||
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]); |
||
642 | } |
||
643 | ++optname; |
||
644 | } |
||
645 | |||
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; |
||
652 | } |
||
653 | fputc('\t', outfile); |
||
654 | fputs(sockaddr_info((struct sockaddr *)&sockname, namelen, nambuff, sizeof(nambuff)), |
||
655 | outfile); |
||
656 | |||
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))); |
||
668 | } |
||
669 | |||
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); |
||
675 | } |
||
676 | #endif /* SIOCGIFNAME */ |
||
677 | |||
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; |
||
699 | } |
||
700 | return result; |
||
701 | #undef FILAN_OPTLEN |
||
702 | #undef FILAN_NAMELEN |
||
703 | } |
||
704 | #endif /* _WITH_SOCKET */ |
||
705 | |||
706 | |||
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); |
||
764 | |||
765 | optname = ipopts; while (optname->so) { |
||
766 | sockoptan(fd, optname, SOL_IP, outfile); |
||
767 | ++optname; |
||
768 | } |
||
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 |
||
776 | } |
||
777 | } |
||
778 | return 0; |
||
779 | } |
||
780 | #endif /* WITH_IP */ |
||
781 | |||
782 | |||
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; |
||
792 | |||
793 | optname = ip6opts; while (optname->so) { |
||
794 | sockoptan(fd, optname, SOL_IPV6, outfile); |
||
795 | ++optname; |
||
796 | } |
||
797 | return 0; |
||
798 | } |
||
799 | #endif /* WITH_IP6 */ |
||
800 | |||
801 | |||
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} |
||
881 | } ; |
||
882 | const struct sockopt *optname; |
||
883 | |||
884 | optname = tcpopts; while (optname->so) { |
||
885 | sockoptan(fd, optname, SOL_TCP, outfile); |
||
886 | ++optname; |
||
887 | } |
||
888 | return 0; |
||
889 | } |
||
890 | #endif /* WITH_TCP */ |
||
891 | |||
892 | |||
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 | char i[FILAN_OPTLEN/sizeof(int)]; |
||
899 | } optval; |
||
900 | socklen_t optlen; |
||
901 | int result; |
||
902 | |||
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]); |
||
923 | } |
||
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); |
||
928 | } |
||
929 | return 0; |
||
930 | #undef FILAN_OPTLEN |
||
931 | } |
||
932 | #endif /* _WITH_SOCKET */ |
||
933 | |||
934 | |||
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; |
||
952 | } |
||
953 | /* note: when S_ISSOCK was undefined, it always gives 0 */ |
||
954 | return S_ISSOCK(props.st_mode); |
||
955 | } |
||
956 | #endif /* _WITH_SOCKET */ |
||
957 | |||
958 | |||
959 | const char *getfiletypestring(int st_mode) { |
||
960 | const char *s; |
||
961 | |||
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; |
||
972 | } |
||
973 | return s; |
||
974 | } |
||
975 | |||
976 | static int printtime(FILE *outfile, time_t time) { |
||
977 | const char *s; |
||
978 | |||
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); |
||
986 | } |
||
987 | return 0; |
||
988 | } |