/* source: fdname.c */ /* Copyright Gerhard Rieger and contributors (see file CHANGES) */ /* Published under the GNU General Public License V.2, see file COPYING */ /* the subroutine sockname prints the basic info about the address of a socket NOTE: it works on UNIX (kernel) file descriptors, not on libc files! */ #include "config.h" #include "xioconfig.h" /* what features are enabled */ #include "sysincludes.h" #include "mytypes.h" #include "compat.h" #include "error.h" #include "sycls.h" #include "sysutils.h" #include "filan.h" struct sockopt { int so; char *name; }; int statname(const char *file, int fd, int filetype, FILE *outfile, char style); int cdevname(int fd, FILE *outfile); int sockname(int fd, FILE *outfile, char style); int unixame(int fd, FILE *outfile); int tcpname(int fd, FILE *outfile); int fdname(const char *file, int fd, FILE *outfile, const char *numform, char style) { struct stat buf = {0}; int filetype; Debug1("checking file descriptor %u", fd); if (fd >= 0) { if (Fstat(fd, &buf) < 0) { if (errno == EBADF) { Debug2("fstat(%d): %s", fd, strerror(errno)); return -1; } else { Error2("fstat(%d): %s", fd, strerror(errno)); } } filetype = (buf.st_mode&S_IFMT)>>12; if (numform != NULL) { fprintf(outfile, numform, fd); } return statname(file, fd, filetype, outfile, style); } else { if (Stat(file, &buf) < 0) { Error2("stat(\"%s\"): %s", file, strerror(errno)); } filetype = (buf.st_mode&S_IFMT)>>12; return statname(file, -1, filetype, outfile, style); } } #if HAVE_PROC_DIR_FD || HAVE_PROC_DIR_PATH static int procgetfdname(int fd, char *filepath, size_t pathsize) { static pid_t pid = -1; char procpath[PATH_MAX]; int len; /* even if configure has shown that we have /proc, we must check if it exists at runtime, because we might be in a chroot environment */ #if HAVE_STAT64 { struct stat64 buf; if (Stat64("/proc", &buf) < 0) { return -1; } if (!S_ISDIR(buf.st_mode)) { return -1; } } #else /* !HAVE_STAT64 */ { struct stat buf; if (Stat("/proc", &buf) < 0) { return -1; } if (!S_ISDIR(buf.st_mode)) { return -1; } } #endif /* !HAVE_STAT64 */ if (pid < 0) pid = Getpid(); snprintf(procpath, sizeof(procpath), "/proc/"F_pid"/" #if HAVE_PROC_DIR_PATH "path" #else "fd" #endif "/%d", pid, fd); if ((len = Readlink(procpath, filepath, pathsize-1)) < 0) { Notice4("readlink(\"%s\", %p, "F_Zu"): %s", procpath, filepath, pathsize, strerror(errno)); len = 0; } filepath[len] = '\0'; return 0; } #endif /* HAVE_PROC_DIR_FD || HAVE_PROC_DIR_PATH */ int statname(const char *file, int fd, int filetype, FILE *outfile, char style) { char filepath[PATH_MAX]; filepath[0] = '\0'; #if HAVE_PROC_DIR_FD || HAVE_PROC_DIR_PATH if (fd >= 0) { procgetfdname(fd, filepath, sizeof(filepath)); if (filepath[0] == '/') { file = filepath; } } #endif /* HAVE_PROC_DIR_FD || HAVE_PROC_DIR_PATH */ /* now see for type specific infos */ switch (filetype) { case (S_IFIFO>>12): /* 1, FIFO */ fputs("pipe", outfile); if (file) fprintf(outfile, " %s", file); break; case (S_IFCHR>>12): /* 2, character device */ if (cdevname(fd, outfile) == 0) { if (file) fprintf(outfile, " %s", file); } break; case (S_IFDIR>>12): /* 4, directory */ fputs("dir", outfile); if (file) fprintf(outfile, " %s", file); break; case (S_IFBLK>>12): /* 6, block device */ fputs("blkdev", outfile); if (file) fprintf(outfile, " %s", file); break; case (S_IFREG>>12): /* 8, regular file */ fputs("file", outfile); if (file) fprintf(outfile, " %s", file); break; case (S_IFLNK>>12): /* 10, symbolic link */ fputs("link", outfile); if (file) fprintf(outfile, " %s", file); break; case (S_IFSOCK>>12): /* 12, socket */ #if _WITH_SOCKET if (fd >= 0) { sockname(fd, outfile, style); } else if (file) { fprintf(outfile, "socket %s", file); } else { fputs("socket", outfile); } #else Error("SOCKET support not compiled in"); return -1; #endif /* !_WITH_SOCKET */ break; #ifdef S_IFDOOR case (S_IFDOOR>>12): /* 13, door (Solaris) */ fputs("door", outfile); if (file) fprintf(outfile, " %s", file); break; #endif /* HAVE_MACRO_S_IFDOOR */ #ifdef S_IFPORT case (S_IFPORT>>12): /* 14, event port (Solaris) */ fputs("event_port", outfile); if (file) fprintf(outfile, " %s", file); break; #endif /* HAVE_MACRO_S_IFPORT */ } /* ioctl() */ fputc('\n', outfile); return 0; } /* character device analysis */ /* return -1 on error, 0 if no name was found, or 1 if it printed ttyname */ int cdevname(int fd, FILE *outfile) { int ret; if ((ret = Isatty(fd)) < 0) { Error2("isatty(%d): %s", fd, strerror(errno)); return -1; } if (ret > 0) { char *name; fputs("tty", outfile); if ((name = Ttyname(fd)) != NULL) { fputc(' ', outfile); fputs(name, outfile); return 1; } } else { fputs("chrdev", outfile); } return 0; } int sockettype(int socktype, char *typename, size_t typenamemax) { switch (socktype) { case SOCK_STREAM: strncpy(typename, "stream", typenamemax); break; case SOCK_DGRAM: strncpy(typename, "dgram", typenamemax); break; case SOCK_SEQPACKET: strncpy(typename, "seqpacket", typenamemax); break; case SOCK_RAW: strncpy(typename, "raw", typenamemax); break; case SOCK_RDM: strncpy(typename, "rdm", typenamemax); break; #ifdef SOCK_PACKET case SOCK_PACKET: strncpy(typename, "packet", typenamemax); break; #endif default: snprintf(typename, typenamemax, "socktype%u", socktype); break; } return 0; } #if _WITH_SOCKET int sockname(int fd, FILE *outfile, char style) { #define FDNAME_OPTLEN 256 #define FDNAME_NAMELEN 256 socklen_t optlen; #if HAVE_GETPROTOBYNUMBER || HAVE_GETPROTOBYNUMBER_R struct protoent protoent, *protoentp; #endif #define PROTONAMEMAX 1024 char protoname[PROTONAMEMAX] = ""; #if defined(SO_PROTOCOL) || defined(SO_PROTOTYPE) int proto = 0; #endif int opttype; #ifdef SO_ACCEPTCONN int optacceptconn = 0; /* OpenBSD does not give value on unix dgram */ #endif int result /*0, i*/; char socknamebuff[FDNAME_NAMELEN]; char peernamebuff[FDNAME_NAMELEN]; /* in Linux these optcodes are 'enum', but on AIX they are bits! */ union sockaddr_union sockname, peername; /* the longest I know of */ socklen_t socknamelen, peernamelen; # define TYPENAMEMAX 16 char typename[TYPENAMEMAX]; #if 0 && defined(SIOCGIFNAME) /*Linux struct ifreq ifc = {{{ 0 }}};*/ struct ifreq ifc = {{ 0 }}; #endif int rc; #if defined(SO_PROTOCOL) || defined(SO_PROTOTYPE) optlen = sizeof(proto); #ifdef SO_PROTOCOL rc = Getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &proto, &optlen); #elif defined(SO_PROTOTYPE) rc = Getsockopt(fd, SOL_SOCKET, SO_PROTOTYPE, &proto, &optlen); #endif if (rc < 0) { Notice5("getsocktop(%d, SOL_SOCKET, " #ifdef SO_PROTOCOL "SO_PROTOCOL" #else "SO_PROTOTYPE" #endif ", &%p, {"F_socklen"}): errno=%d (%s)", fd, &proto, optlen, errno, strerror(errno)); } #endif /* defined(SO_PROTOCOL) || defined(SO_PROTOTYPE) */ optlen = sizeof(opttype); Getsockopt(fd, SOL_SOCKET, SO_TYPE, &opttype, &optlen); sockettype(opttype, typename, sizeof(typename)); optlen = sizeof(optacceptconn); #ifdef SO_ACCEPTCONN Getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &optacceptconn, &optlen); #endif #if defined(SO_PROTOCOL) || defined(SO_PROTOTYPE) #if HAVE_GETPROTOBYNUMBER_R==1 /* Linux */ rc = getprotobynumber_r(proto, &protoent, protoname, sizeof(protoname), &protoentp); if (protoentp == NULL) { Warn2("sockname(): getprotobynumber_r(proto=%d, ...): %s", proto, strerror(rc)); } strncpy(protoname, protoentp->p_name, sizeof(protoname)); #elif HAVE_GETPROTOBYNUMBER_R==2 /* Solaris */ { # define FILAN_GETPROTOBYNUMBER_R_BUFLEN 1024 char buffer[FILAN_GETPROTOBYNUMBER_R_BUFLEN]; protoentp = getprotobynumber_r(proto, &protoent, buffer, FILAN_GETPROTOBYNUMBER_R_BUFLEN); strncpy(protoname, protoentp->p_name, sizeof(protoname)); } #elif HAVE_GETPROTOBYNUMBER_R==3 /* AIX, OpenBSD */ { struct protoent_data proto_data = { 0 }; /* OpenBSD might SIGSEGV */ rc = getprotobynumber_r(proto, &protoent, &proto_data); if (rc == 0) { strncpy(protoname, protoent.p_name, sizeof(protoname)); endprotoent_r(&proto_data); } } #else switch (proto) { case IPPROTO_TCP: strcpy(protoname, "tcp"); break; case IPPROTO_UDP: strcpy(protoname, "udp"); break; case IPPROTO_SCTP: strcpy(protoname, "sctp"); break; default: sprintf(protoname, "proto%d", proto); break; } #endif #else /* ! (defined(SO_PROTOCOL) || defined(SO_PROTOTYPE)) */ if (opttype == SOCK_STREAM) { strcpy(protoname, "(stream)"); } else if (opttype == SOCK_DGRAM) { strcpy(protoname, "(dgram)"); #ifdef SOCK_RAW } else if (opttype == SOCK_RAW) { strcpy(protoname, "(raw)"); #endif #ifdef SOCK_RDM } else if (opttype == SOCK_RDM) { strcpy(protoname, "(rdm)"); #endif #ifdef SOCK_SEQPACKET } else if (opttype == SOCK_SEQPACKET) { strcpy(protoname, "(seqpacket)"); #endif #ifdef SOCK_DCCP } else if (opttype == SOCK_DCCP) { strcpy(protoname, "(dccp)"); #endif #ifdef SOCK_PACKET } else if (opttype == SOCK_PACKET) { strcpy(protoname, "(packet)"); #endif } else { strcpy(protoname, "socket"); } #endif /* ! (defined(SO_PROTOCOL) || defined(SO_PROTOTYPE)) */ socknamelen = sizeof(sockname); result = Getsockname(fd, &sockname.soa, &socknamelen); if (result < 0) { Error2("getsockname(%d): %s", fd, strerror(errno)); return -1; } peernamelen = sizeof(peername); result = Getpeername(fd, (struct sockaddr *)&peername, &peernamelen); if (result < 0) { Warn2("getpeername(%d): %s", fd, strerror(errno)); } switch (sockname.soa.sa_family) { #if WITH_UNIX case AF_UNIX: switch (style) { case 's': fprintf(outfile, "unix%s%s %s", opttype==SOCK_DGRAM?"datagram":"", #ifdef SO_ACCEPTCONN optacceptconn?"(listening)": #endif "", sockaddr_unix_info(&sockname.un, socknamelen, socknamebuff, sizeof(socknamebuff))); break; case 'S': /* sockettype(opttype, typename, TYPENAMEMAX); */ fprintf(outfile, "unix %s-%s %s %s", sockaddr_unix_info(&sockname.un, socknamelen, socknamebuff, sizeof(socknamebuff)), sockaddr_unix_info(&peername.un, peernamelen, peernamebuff, sizeof(peernamebuff)), typename, #ifdef SO_ACCEPTCONN optacceptconn?"(listening)": #endif ""); break; } break; #endif /* WITH_UNIX */ #if WITH_IP4 case AF_INET: switch (style) { case 's': switch (opttype) { #if WITH_TCP case SOCK_STREAM: fprintf(outfile, "%s%s %s %s", protoname, #ifdef SO_ACCEPTCONN optacceptconn?"(listening)": #endif "", sockaddr_inet4_info(&sockname.ip4, socknamebuff, sizeof(socknamebuff)), sockaddr_inet4_info(&peername.ip4, peernamebuff, sizeof(peernamebuff))); break; #endif #if WITH_UDP case SOCK_DGRAM: fprintf(outfile, "%s%s %s %s", protoname, #ifdef SO_ACCEPTCONN optacceptconn?"(listening)": #endif "", sockaddr_inet4_info(&sockname.ip4, socknamebuff, sizeof(socknamebuff)), sockaddr_inet4_info(&peername.ip4, peernamebuff, sizeof(peernamebuff))); break; #endif default: fprintf(outfile, "ip %s", sockaddr_inet4_info(&sockname.ip4, socknamebuff, sizeof(socknamebuff))); break; } break; case 'S': fprintf(outfile, "%s %s-%s (%s) %s", protoname, sockaddr_inet4_info(&sockname.ip4, socknamebuff, sizeof(socknamebuff)), sockaddr_inet4_info(&peername.ip4, peernamebuff, sizeof(peernamebuff)), typename, #ifdef SO_ACCEPTCONN optacceptconn?"(listening)": #endif ""); break; } break; #endif /* WITH_IP4 */ #if WITH_IP6 case AF_INET6: switch (style) { case 's': switch (opttype) { #if WITH_TCP case SOCK_STREAM: fprintf(outfile, "%s6%s %s %s", protoname, #ifdef SO_ACCEPTCONN optacceptconn?"(listening)": #endif "", sockaddr_inet6_info(&sockname.ip6, socknamebuff, sizeof(socknamebuff)), sockaddr_inet6_info(&peername.ip6, peernamebuff, sizeof(peernamebuff))); break; #endif #if WITH_UDP case SOCK_DGRAM: fprintf(outfile, "%s6%s %s %s", protoname, #ifdef SO_ACCEPTCONN optacceptconn?"(listening)": #endif "", sockaddr_inet6_info(&sockname.ip6, socknamebuff, sizeof(socknamebuff)), sockaddr_inet6_info(&peername.ip6, peernamebuff, sizeof(peernamebuff))); break; #endif default: fprintf(outfile, "ip6 %s", sockaddr_inet6_info(&sockname.ip6, socknamebuff, sizeof(socknamebuff))); break; } break; case 'S': fprintf(outfile, "%s6 %s-%s (%s) %s", protoname, sockaddr_inet6_info(&sockname.ip6, socknamebuff, sizeof(socknamebuff)), sockaddr_inet6_info(&peername.ip6, peernamebuff, sizeof(peernamebuff)), typename, #ifdef SO_ACCEPTCONN optacceptconn?"(listening)": #endif ""); break; } break; #endif /* WITH_IP6 */ default: fprintf(outfile, "socket(family/domain=%d)", sockname.soa.sa_family); } #if HAVE_GETPROTOENT if (ipproto >= 0) { endprotoent(); } #endif return result; #undef FDNAME_OPTLEN #undef FDNAME_NAMELEN } #endif /* _WITH_SOCKET */