#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cnx_inode.h" #include "inodelist.h" #include "mypcap.h" const int MAX_FDLINK = 10; const int MAX_PID_LENGTH = 20; #define MAX_SIZE 256 static char st_file_prefix[MAX_SIZE]="";//Will be time of day static pcap_t *st_hdl_out_pcap = NULL; const char *cst_cnx_file_details_list[]= { "/proc/net/tcp", //~ "/proc/net/tcp6", "/proc/net/udp", //~ "/proc/net/udp6", NULL, }; bool is_number(const char*s) { char* e = NULL; strtol(s, &e, 0); return e != NULL && *e == (char)0; } void set_file_prefix(const char*file_prefix) { strcpy(st_file_prefix,file_prefix); } void set_pcap_handle(pcap_t *pcap) { st_hdl_out_pcap = pcap; } int _file_exist (const char *filename) { struct stat buffer; return (stat (filename, &buffer) == 0); } /* * parses a /proc/net/tcp-line of the form: * sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt *uid timeout inode * 10: 020310AC:1770 9DD8A9C3:A525 01 00000000:00000000 00:00000000 00000000 *0 0 2119 1 c0f4f0c0 206 40 10 3 -1 * 11: 020310AC:0404 936B2ECF:0747 01 00000000:00000000 00:00000000 00000000 *1000 0 2109 1 c0f4fc00 368 40 20 2 -1 * * and of the form: * 2: 0000000000000000FFFF0000020310AC:0016 *0000000000000000FFFF00009DD8A9C3:A526 01 00000000:00000000 02:000A7214 *00000000 0 0 2525 2 c732eca0 201 40 1 2 -1 * */ void _addtoconninode(char *buffer) { short int sa_family; struct in6_addr result_addr_local = {}; struct in6_addr result_addr_remote = {}; char rem_addr[128], local_addr[128]; int local_port, rem_port; struct in6_addr in6_local; struct in6_addr in6_remote; unsigned long inode; int matches = sscanf(buffer, "%*d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %*X " "%*X:%*X %*X:%*X %*X %*d %*d %ld %*512s\n", local_addr, &local_port, rem_addr, &rem_port, &inode); if (matches != 5) { fprintf(stderr, "Unexpected buffer: '%s'\n", buffer); exit(0); } if (inode == 0) { /* connection is in TIME_WAIT state. We rely on * the old data still in the table. */ return; } //~ printf("inode:%lu\n", inode); if (strlen(local_addr) > 8) { /* this is an IPv6-style row */ /* Demangle what the kernel gives us */ sscanf(local_addr, "%08X%08X%08X%08X", &in6_local.s6_addr32[0], &in6_local.s6_addr32[1], &in6_local.s6_addr32[2], &in6_local.s6_addr32[3]); sscanf(rem_addr, "%08X%08X%08X%08X", &in6_remote.s6_addr32[0], &in6_remote.s6_addr32[1], &in6_remote.s6_addr32[2], &in6_remote.s6_addr32[3]); if ((in6_local.s6_addr32[0] == 0x0) && (in6_local.s6_addr32[1] == 0x0) && (in6_local.s6_addr32[2] == 0xFFFF0000)) { /* IPv4-compatible address */ result_addr_local.s6_addr32[0] = in6_local.s6_addr32[3]; result_addr_remote.s6_addr32[0] = in6_remote.s6_addr32[3]; sa_family = AF_INET; } else { /* real IPv6 address */ // inet_ntop(AF_INET6, &in6_local, addr6, sizeof(addr6)); // INET6_getsock(addr6, (struct sockaddr *) &localaddr); // inet_ntop(AF_INET6, &in6_remote, addr6, sizeof(addr6)); // INET6_getsock(addr6, (struct sockaddr *) &remaddr); // localaddr.sin6_family = AF_INET6; // remaddr.sin6_family = AF_INET6; result_addr_local = in6_local; result_addr_remote = in6_remote; sa_family = AF_INET6; } } else { /* this is an IPv4-style row */ sscanf(local_addr, "%X", (unsigned int *)&result_addr_local); sscanf(rem_addr, "%X", (unsigned int *)&result_addr_remote); sa_family = AF_INET; } char *hashkey = (char *)malloc(HASHKEYSIZE * sizeof(char)); char *hashkey2 = (char *)malloc(HASHKEYSIZE * sizeof(char)); char *local_string = (char *)malloc(50); char *remote_string = (char *)malloc(50); inet_ntop(sa_family, &result_addr_local, local_string, 49); inet_ntop(sa_family, &result_addr_remote, remote_string, 49); snprintf(hashkey, HASHKEYSIZE * sizeof(char), "%s:%d-%s:%d", local_string, local_port, remote_string, rem_port); snprintf(hashkey2, HASHKEYSIZE * sizeof(char), "%s:%d-%s:%d", remote_string, rem_port,local_string, local_port); free(local_string); //~ printf("inode[%lu]:hashkey:[%s]\n",inode,hashkey); inodelist_insert_if_not_with_hashkey(inode,hashkey,hashkey2,strlen(hashkey)); /* workaround: sometimes, when a connection is actually from 172.16.3.1 to * 172.16.3.3, packages arrive from 195.169.216.157 to 172.16.3.3, where * 172.16.3.1 and 195.169.216.157 are the local addresses of different * interfaces */ //~ for (class local_addr *current_local_addr = local_addrs; //~ current_local_addr != NULL; //~ current_local_addr = current_local_addr->next) { //~ /* TODO maybe only add the ones with the same sa_family */ //~ snprintf(hashkey, HASHKEYSIZE * sizeof(char), "%s:%d-%s:%d", //~ current_local_addr->string, local_port, remote_string, rem_port); //~ conninode[hashkey] = inode; //~ } free(hashkey); free(remote_string); } int _addprocinfo(const char *filename) { FILE *procinfo = fopen(filename, "r"); char buffer[8192]; if (procinfo == NULL) return 0; char *ret = fgets(buffer, sizeof(buffer), procinfo); if( NULL == ret ) { return 0; } do { if (fgets(buffer, sizeof(buffer), procinfo)) _addtoconninode(buffer); } while (!feof(procinfo)); fclose(procinfo); return 1; } unsigned long _str2ulong(const char *ptr) { unsigned long retval = 0; while ((*ptr >= '0') && (*ptr <= '9')) { retval *= 10; retval += *ptr - '0'; ptr++; } return retval; } int _str2int(const char *ptr) { int retval = 0; while ((*ptr >= '0') && (*ptr <= '9')) { retval *= 10; retval += *ptr - '0'; ptr++; } return retval; } char *_read_file(int fd, char *content) { char buf[255]; int length = 0; //~ for (length; (length = read(fd, buf, sizeof(buf))) > 0;) { while( (length = read(fd, buf, sizeof(buf))) > 0) { if (length < 0) { fprintf(stderr, "Error reading file: %s\n", strerror(errno)); exit(34); } memcpy(content, buf, length); } return content; } char *_read_file_filename(const char *filepath, char *contents) { int fd = open(filepath, O_RDONLY); if (fd < 0) { fprintf(stderr, "Error opening %s: %s\n", filepath, strerror(errno)); exit(3); return NULL; } _read_file(fd,contents); if (close(fd)) { fprintf(stderr, "Error opening %s: %s\n", filepath, strerror(errno)); exit(34); } return contents; } char *_getcmdline(pid_t pid,char *cmdline) { const int maxfilenamelen = 14 + MAX_PID_LENGTH + 1; char filename[maxfilenamelen]; snprintf(filename, maxfilenamelen, "/proc/%d/cmdline", pid); bool replace_null = false; _read_file_filename(filename, cmdline); //~ // join parameters, keep prgname separate, don't overwrite trailing null size_t idx = 0; for (idx = 0; idx < strlen(cmdline); idx++) { if (cmdline[idx] == 0x00) { if (replace_null) { cmdline[idx] = ' '; } replace_null = true; } } return cmdline; } void _setnode(unsigned long inode, pid_t pid) { char cmdline[9000]=""; _getcmdline(pid,cmdline); inodelist_t *tempNodeList=inodelist_get_inode_from_value(inode); if( NULL != tempNodeList ) { tempNodeList->data.pid = pid; if( 0 == strlen(tempNodeList->data.cmdline)) { strcpy(tempNodeList->data.cmdline, cmdline); //PCAP Dumper if( NULL == tempNodeList->data.mydumper ) { char pcapname[1024]; sprintf(pcapname,"%s--%d--%s.pcap", st_file_prefix, pid, cmdline ); uint32_t i = 0; for( i = 0; i < strlen(pcapname);i++ ) { if( pcapname[i] == '/' ) pcapname[i]='_'; else if( pcapname[i] == ':' ) pcapname[i]='_'; else if( pcapname[i] == '@' ) pcapname[i]='_'; else if( pcapname[i] == ' ' ) pcapname[i]='_'; } tempNodeList->data.mydumper = mypcap_open( pcapname,"ab+" ); } } } } void _get_info_by_linkname(const char *pid, const char *linkname) { if (strncmp(linkname, "socket:[", 8) == 0) { _setnode(_str2ulong(linkname + 8), _str2int(pid)); } } void _get_info_for_pid(const char *pid) { char dirname[10 + MAX_PID_LENGTH]; size_t dirlen = 10 + strlen(pid); snprintf(dirname, dirlen, "/proc/%s/fd", pid); DIR *dir = opendir(dirname); if (!dir) { fprintf(stderr, "Couldn't open dir %s, removing entry\n", dirname); int32_t failed_index = inodelist_get_index_from_pid(_str2int(pid)); if( -1 != failed_index ) { inodelist_remove_at(failed_index); } return; } /* walk through /proc/%s/fd/... */ struct dirent *entry; while ((entry = readdir(dir))) { if (entry->d_type != DT_LNK) continue; size_t fromlen = dirlen + strlen(entry->d_name) + 1; char fromname[10 + MAX_PID_LENGTH + 1 + MAX_FDLINK]; snprintf(fromname, fromlen, "%s/%s", dirname, entry->d_name); int linklen = 80; char linkname[linklen]; int usedlen = readlink(fromname, linkname, linklen - 1); if (usedlen == -1) { continue; } assert(usedlen < linklen); linkname[usedlen] = '\0'; _get_info_by_linkname(pid, linkname); } closedir(dir); } void cnx_inode_refresh() { uint32_t i = 0; while(NULL != cst_cnx_file_details_list[i]) { if (!_addprocinfo(cst_cnx_file_details_list[i])) { fprintf(stderr, "Error: couldn't open %s", cst_cnx_file_details_list[i] ); } i++; } } void reread_mapping() { DIR *proc = opendir("/proc"); if (proc == 0) { fprintf(stderr, "Error reading /proc, needed to get inode-to-pid-maping\n"); exit(1); } struct dirent *entry; while ((entry = readdir(proc))) { if (entry->d_type != DT_DIR) continue; if (!is_number(entry->d_name)) continue; //~ printf("/proc/%s\n", entry->d_name ); _get_info_for_pid(entry->d_name); } closedir(proc); }