#include "precomp.h" #ifdef _WIN32 /* * check if there is enough place for another connection entry and allocate some more * memory if necessary */ DWORD check_and_allocate(struct connection_table **table_connection) { DWORD newsize; struct connection_table * tmp_table; if ((*table_connection)->entries >= (*table_connection)->max_entries) { newsize = sizeof(struct connection_table); newsize += ((*table_connection)->entries + 10) * sizeof(struct connection_entry); tmp_table = (struct connection_table *)realloc(*table_connection, newsize); if (tmp_table == NULL) { free(*table_connection); return ERROR_NOT_ENOUGH_MEMORY; } *table_connection = tmp_table; memset(&(*table_connection)->table[(*table_connection)->entries], 0, 10 * sizeof(struct connection_entry)); (*table_connection)->max_entries += 10; } return ERROR_SUCCESS; } typedef HANDLE (WINAPI *ptr_CreateToolhelp32Snapshot)(DWORD dwFlags,DWORD th32ProcessID); typedef BOOL (WINAPI *ptr_Process32First)(HANDLE hSnapshot, LPPROCESSENTRY32 lppe); typedef BOOL (WINAPI *ptr_Process32Next)(HANDLE hSnapshot, LPPROCESSENTRY32 lppe); /* * write pid/process_name in buffer */ DWORD set_process_name(DWORD pid, char * buffer, DWORD buffer_size) { HANDLE hSnapshot; ptr_CreateToolhelp32Snapshot ct32s = NULL; ptr_Process32First p32f = NULL; ptr_Process32Next p32n = NULL; ct32s = (ptr_CreateToolhelp32Snapshot)GetProcAddress(GetModuleHandle("kernel32"), "CreateToolhelp32Snapshot"); p32f = (ptr_Process32First)GetProcAddress(GetModuleHandle("kernel32"), "Process32First"); p32n = (ptr_Process32Next)GetProcAddress(GetModuleHandle("kernel32"), "Process32Next"); if ((!ct32s) || (!p32f) || (!p32n)) return -1; hSnapshot = ct32s(TH32CS_SNAPPROCESS,0); if(hSnapshot) { PROCESSENTRY32 pe32; pe32.dwSize = sizeof(PROCESSENTRY32); if(p32f(hSnapshot,&pe32)) { do { if (pe32.th32ProcessID == pid) { _snprintf_s(buffer, buffer_size-1, _TRUNCATE, "%d/%s",pid, pe32.szExeFile); break; } } while(p32n(hSnapshot,&pe32)); } CloseHandle(hSnapshot); } return ERROR_SUCCESS; } char *tcp_connection_states[] = { "", "CLOSED", "LISTEN", "SYN_SENT", "SYN_RECV", "ESTABLISHED", "FIN_WAIT1", "FIN_WAIT2", "CLOSE_WAIT", "CLOSING", "LAST_ACK", "TIME_WAIT", "DELETE_TCB", "UNKNOWN" }; typedef struct _MIB_TCP6ROW_OWNER_MODULE { UCHAR ucLocalAddr[16]; DWORD dwLocalScopeId; DWORD dwLocalPort; UCHAR ucRemoteAddr[16]; DWORD dwRemoteScopeId; DWORD dwRemotePort; DWORD dwState; DWORD dwOwningPid; LARGE_INTEGER liCreateTimestamp; ULONGLONG OwningModuleInfo[TCPIP_OWNING_MODULE_SIZE]; } MIB_TCP6ROW_OWNER_MODULE, *PMIB_TCP6ROW_OWNER_MODULE; typedef struct _MIB_UDP6ROW_OWNER_MODULE { UCHAR ucLocalAddr[16]; DWORD dwLocalScopeId; DWORD dwLocalPort; DWORD dwOwningPid; LARGE_INTEGER liCreateTimestamp; union { struct { int SpecificPortBind :1; }; int dwFlags; }; ULONGLONG OwningModuleInfo[TCPIP_OWNING_MODULE_SIZE]; } MIB_UDP6ROW_OWNER_MODULE, *PMIB_UDP6ROW_OWNER_MODULE; typedef struct _MIB_TCP6TABLE_OWNER_MODULE { DWORD dwNumEntries; MIB_TCP6ROW_OWNER_MODULE table[ANY_SIZE]; } MIB_TCP6TABLE_OWNER_MODULE, *PMIB_TCP6TABLE_OWNER_MODULE; typedef struct { DWORD dwNumEntries; MIB_UDP6ROW_OWNER_MODULE table[ANY_SIZE]; } MIB_UDP6TABLE_OWNER_MODULE, *PMIB_UDP6TABLE_OWNER_MODULE; typedef DWORD (WINAPI * ptr_GetExtendedTcpTable)(PVOID, PDWORD pdwSize, BOOL bOrder, ULONG ulAf,TCP_TABLE_CLASS TableClass, ULONG Reserved); typedef DWORD (WINAPI * ptr_GetExtendedUdpTable)(PVOID, PDWORD pdwSize, BOOL bOrder, ULONG ulAf,TCP_TABLE_CLASS TableClass, ULONG Reserved); /* * retrieve tcp table for win 2000 and NT4 ? */ DWORD windows_get_tcp_table_win2000_down(struct connection_table **table_connection) { PMIB_TCPTABLE pTcpTable = NULL; struct connection_entry * current_connection; DWORD dwSize = 0; DWORD dwRetVal = 0; DWORD result = ERROR_SUCCESS; DWORD i, state; do { dwRetVal = GetTcpTable(pTcpTable, &dwSize, TRUE); dprintf("[NETSTAT TCP] need %d bytes",dwSize); /* Get the size required by GetTcpTable() */ if (dwRetVal == ERROR_INSUFFICIENT_BUFFER) { pTcpTable = (MIB_TCPTABLE *) malloc (dwSize); } else if (dwRetVal != NO_ERROR) { result = ERROR_NOT_SUPPORTED; break; } if ((dwRetVal = GetTcpTable(pTcpTable, &dwSize, TRUE)) == NO_ERROR) { dprintf("[NETSTAT] found %d tcp connections", pTcpTable->dwNumEntries); for (i = 0 ; i < pTcpTable->dwNumEntries ; i++) { // check available memory and allocate if necessary if (check_and_allocate(table_connection) == ERROR_NOT_ENOUGH_MEMORY) { free(pTcpTable); return ERROR_NOT_ENOUGH_MEMORY; } current_connection = &(*table_connection)->table[(*table_connection)->entries]; current_connection->type = AF_INET; current_connection->local_addr.addr = pTcpTable->table[i].dwLocalAddr; current_connection->remote_addr.addr = pTcpTable->table[i].dwRemoteAddr; current_connection->local_port = ntohs((u_short)(pTcpTable->table[i].dwLocalPort & 0x0000ffff)); // if socket is in LISTEN, remote_port is garbage, force value to 0 if (pTcpTable->table[i].dwState == MIB_TCP_STATE_LISTEN) current_connection->remote_port = 0; else current_connection->remote_port = ntohs((u_short)(pTcpTable->table[i].dwRemotePort & 0x0000ffff)); state = pTcpTable->table[i].dwState; if ((state <= 0) || (state > 12)) state = 13; // points to UNKNOWN in the state array strncpy(current_connection->state, tcp_connection_states[state], sizeof(current_connection->state)); strncpy(current_connection->protocol, "tcp", sizeof(current_connection->protocol)); // force program_name to "-" strncpy(current_connection->program_name, "-", sizeof(current_connection->program_name)); (*table_connection)->entries++; } free(pTcpTable); } else { // GetTcpTable failed result = GetLastError(); break; } } while (0) ; return result; } /* * retrieve tcp table for win xp and up */ DWORD windows_get_tcp_table(struct connection_table **table_connection) { DWORD result = ERROR_SUCCESS; struct connection_entry * current_connection = NULL; MIB_TCPTABLE_OWNER_MODULE * tablev4 = NULL; MIB_TCP6TABLE_OWNER_MODULE * tablev6 = NULL; MIB_TCPROW_OWNER_MODULE * currentv4 = NULL; MIB_TCP6ROW_OWNER_MODULE * currentv6 = NULL; DWORD i, state, dwSize; ptr_GetExtendedTcpTable gett = NULL; gett = (ptr_GetExtendedTcpTable)GetProcAddress(GetModuleHandle("iphlpapi"), "GetExtendedTcpTable"); // systems that don't support GetExtendedTcpTable if (gett == NULL) { return windows_get_tcp_table_win2000_down(table_connection); } do { // IPv4 part dwSize = 0; if (gett(NULL,&dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_MODULE_ALL, 0) == ERROR_INSUFFICIENT_BUFFER) { tablev4 = (MIB_TCPTABLE_OWNER_MODULE *)malloc(dwSize); if (gett(tablev4, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_MODULE_ALL, 0) == NO_ERROR) { for(i=0; i<tablev4->dwNumEntries; i++) { // check available memory and allocate if necessary if (check_and_allocate(table_connection) == ERROR_NOT_ENOUGH_MEMORY) { free(tablev4); return ERROR_NOT_ENOUGH_MEMORY; } currentv4 = &tablev4->table[i]; current_connection = &(*table_connection)->table[(*table_connection)->entries]; current_connection->type = AF_INET; current_connection->local_addr.addr = currentv4->dwLocalAddr; current_connection->remote_addr.addr = currentv4->dwRemoteAddr; current_connection->local_port = ntohs((u_short)(currentv4->dwLocalPort & 0x0000ffff)); // if socket is in LISTEN, remote_port is garbage, force value to 0 if (currentv4->dwState == MIB_TCP_STATE_LISTEN) current_connection->remote_port = 0; else current_connection->remote_port = ntohs((u_short)(currentv4->dwRemotePort & 0x0000ffff)); state = currentv4->dwState; if ((state <= 0) || (state > 12)) state = 13; // points to UNKNOWN in the state array strncpy(current_connection->state, tcp_connection_states[state], sizeof(current_connection->state)); strncpy(current_connection->protocol, "tcp", sizeof(current_connection->protocol)); // force program_name to "-" and try to get real name through GetOwnerModuleFromXXXEntry strncpy(current_connection->program_name, "-", sizeof(current_connection->program_name)); set_process_name(currentv4->dwOwningPid, current_connection->program_name, sizeof(current_connection->program_name)); (*table_connection)->entries++; } } else { // gett failed result = GetLastError(); if (tablev4) free(tablev4); break; } if (tablev4) free(tablev4); } // IPv6 part dwSize = 0; if (gett(NULL,&dwSize, TRUE, AF_INET6, TCP_TABLE_OWNER_MODULE_ALL, 0) == ERROR_INSUFFICIENT_BUFFER) { tablev6 = (MIB_TCP6TABLE_OWNER_MODULE *)malloc(dwSize); if (gett(tablev6, &dwSize, TRUE, AF_INET6, TCP_TABLE_OWNER_MODULE_ALL, 0) == NO_ERROR) { for(i=0; i<tablev6->dwNumEntries; i++) { // check available memory and allocate if necessary if (check_and_allocate(table_connection) == ERROR_NOT_ENOUGH_MEMORY) { free(tablev6); return ERROR_NOT_ENOUGH_MEMORY; } currentv6 = &tablev6->table[i]; current_connection = &(*table_connection)->table[(*table_connection)->entries]; current_connection->type = AF_INET6; memcpy(¤t_connection->local_addr.addr6, currentv6->ucLocalAddr, sizeof(current_connection->local_addr.addr6)); memcpy(¤t_connection->remote_addr.addr6, currentv6->ucRemoteAddr, sizeof(current_connection->remote_addr.addr6)); current_connection->local_port = ntohs((u_short)(currentv6->dwLocalPort & 0x0000ffff)); // if socket is in LISTEN, remote_port is garbage, force value to 0 if (currentv6->dwState == MIB_TCP_STATE_LISTEN) current_connection->remote_port = 0; else current_connection->remote_port = ntohs((u_short)(currentv6->dwRemotePort & 0x0000ffff)); state = currentv6->dwState; if ((state <= 0) || (state > 12)) state = 13; // points to UNKNOWN in the state array strncpy(current_connection->state, tcp_connection_states[state], sizeof(current_connection->state)); strncpy(current_connection->protocol, "tcp6", sizeof(current_connection->protocol)); // force program_name to "-" and try to get real name through GetOwnerModuleFromXXXEntry strncpy(current_connection->program_name, "-", sizeof(current_connection->program_name)); set_process_name(currentv6->dwOwningPid, current_connection->program_name, sizeof(current_connection->program_name)); (*table_connection)->entries++; } } else { // gett failed result = GetLastError(); if (tablev6) free(tablev6); break; } if (tablev6) free(tablev6); } } while (0); return result; } /* * retrieve udp table for win 2000 and NT4 ? */ DWORD windows_get_udp_table_win2000_down(struct connection_table **table_connection) { PMIB_UDPTABLE pUdpTable = NULL; struct connection_entry * current_connection; DWORD dwSize = 0; DWORD dwRetVal = 0; DWORD result = ERROR_SUCCESS; DWORD i; do { dwRetVal = GetUdpTable(pUdpTable, &dwSize, TRUE); dprintf("[NETSTAT UDP] need %d bytes",dwSize); /* Get the size required by GetUdpTable() */ if (dwRetVal == ERROR_INSUFFICIENT_BUFFER) { pUdpTable = (MIB_UDPTABLE *) malloc (dwSize); } else if (dwRetVal != NO_ERROR) { result = ERROR_NOT_SUPPORTED; break; } if ((dwRetVal = GetUdpTable(pUdpTable, &dwSize, TRUE)) == NO_ERROR) { dprintf("[NETSTAT] found %d udp connections", pUdpTable->dwNumEntries); for (i = 0 ; i < pUdpTable->dwNumEntries ; i++) { // check available memory and allocate if necessary if (check_and_allocate(table_connection) == ERROR_NOT_ENOUGH_MEMORY) { free(pUdpTable); return ERROR_NOT_ENOUGH_MEMORY; } // GetUdpTable reports only listening UDP sockets, not "active" ones current_connection = &(*table_connection)->table[(*table_connection)->entries]; current_connection->type = AF_INET; current_connection->local_addr.addr = pUdpTable->table[i].dwLocalAddr; current_connection->remote_addr.addr = 0; current_connection->local_port = ntohs((u_short)(pUdpTable->table[i].dwLocalPort & 0x0000ffff)); current_connection->remote_port = 0; // force state to "" strncpy(current_connection->state, "", sizeof(current_connection->state)); strncpy(current_connection->protocol, "udp", sizeof(current_connection->protocol)); // force program_name to "-" strncpy(current_connection->program_name, "-", sizeof(current_connection->program_name)); (*table_connection)->entries++; } free(pUdpTable); } else { // GetUdpTable failed result = GetLastError(); break; } } while (0) ; return result; } /* * retrieve udp table for win xp and up */ DWORD windows_get_udp_table(struct connection_table **table_connection) { DWORD result = ERROR_SUCCESS; struct connection_entry * current_connection = NULL; MIB_UDPTABLE_OWNER_MODULE * tablev4 = NULL; MIB_UDP6TABLE_OWNER_MODULE * tablev6 = NULL; MIB_UDPROW_OWNER_MODULE * currentv4 = NULL; MIB_UDP6ROW_OWNER_MODULE * currentv6 = NULL; DWORD i, dwSize; ptr_GetExtendedUdpTable geut = NULL; geut = (ptr_GetExtendedTcpTable)GetProcAddress(GetModuleHandle("iphlpapi"), "GetExtendedUdpTable"); // systems that don't support GetExtendedUdpTable if (geut == NULL) { return windows_get_udp_table_win2000_down(table_connection); } do { // IPv4 part dwSize = 0; if (geut(NULL,&dwSize, TRUE, AF_INET, UDP_TABLE_OWNER_MODULE, 0) == ERROR_INSUFFICIENT_BUFFER) { tablev4 = (MIB_UDPTABLE_OWNER_MODULE *)malloc(dwSize); if (geut(tablev4, &dwSize, TRUE, AF_INET, UDP_TABLE_OWNER_MODULE, 0) == NO_ERROR) { for(i=0; i<tablev4->dwNumEntries; i++) { // check available memory and allocate if necessary if (check_and_allocate(table_connection) == ERROR_NOT_ENOUGH_MEMORY) { free(tablev4); return ERROR_NOT_ENOUGH_MEMORY; } // GetExtendedUdpTable reports only listening UDP sockets, not "active" ones currentv4 = &tablev4->table[i]; current_connection = &(*table_connection)->table[(*table_connection)->entries]; current_connection->type = AF_INET; current_connection->local_addr.addr = currentv4->dwLocalAddr; current_connection->remote_addr.addr = 0; current_connection->local_port = ntohs((u_short)(currentv4->dwLocalPort & 0x0000ffff)); current_connection->remote_port = 0; strncpy(current_connection->state, "", sizeof(current_connection->state)); strncpy(current_connection->protocol, "udp", sizeof(current_connection->protocol)); // force program_name to "-" and try to get real name through GetOwnerModuleFromXXXEntry strncpy(current_connection->program_name, "-", sizeof(current_connection->program_name)); set_process_name(currentv4->dwOwningPid, current_connection->program_name, sizeof(current_connection->program_name)); (*table_connection)->entries++; } } else { // geut failed result = GetLastError(); if (tablev4) free(tablev4); break; } if (tablev4) free(tablev4); } // IPv6 part dwSize = 0; if (geut(NULL,&dwSize, TRUE, AF_INET6, UDP_TABLE_OWNER_MODULE, 0) == ERROR_INSUFFICIENT_BUFFER) { tablev6 = (MIB_UDP6TABLE_OWNER_MODULE *)malloc(dwSize); if (geut(tablev6, &dwSize, TRUE, AF_INET6, UDP_TABLE_OWNER_MODULE, 0) == NO_ERROR) { for(i=0; i<tablev6->dwNumEntries; i++) { // check available memory and allocate if necessary if (check_and_allocate(table_connection) == ERROR_NOT_ENOUGH_MEMORY) { free(tablev6); return ERROR_NOT_ENOUGH_MEMORY; } currentv6 = &tablev6->table[i]; current_connection = &(*table_connection)->table[(*table_connection)->entries]; current_connection->type = AF_INET6; memcpy(¤t_connection->local_addr.addr6, currentv6->ucLocalAddr, sizeof(current_connection->local_addr.addr6)); memset(¤t_connection->remote_addr.addr6, 0, sizeof(current_connection->remote_addr.addr6)); current_connection->local_port = ntohs((u_short)(currentv6->dwLocalPort & 0x0000ffff)); current_connection->remote_port = 0; strncpy(current_connection->state, "", sizeof(current_connection->state)); strncpy(current_connection->protocol, "udp6", sizeof(current_connection->protocol)); // force program_name to "-" and try to get real name through GetOwnerModuleFromXXXEntry strncpy(current_connection->program_name, "-", sizeof(current_connection->program_name)); set_process_name(currentv6->dwOwningPid, current_connection->program_name, sizeof(current_connection->program_name)); (*table_connection)->entries++; } } else { // gett failed result = GetLastError(); if (tablev6) free(tablev6); break; } if (tablev6) free(tablev6); } } while (0); return result; } DWORD windows_get_connection_table(Remote *remote, Packet *response) { struct connection_table *table_connection = NULL; struct connection_entry * current_connection; DWORD dwRetVal; int index; DWORD local_port_be, remote_port_be; table_connection = (struct connection_table *)calloc(sizeof(struct connection_table) + 10 * sizeof(struct connection_entry), 1); table_connection->max_entries = 10; dwRetVal = windows_get_tcp_table(&table_connection); if (dwRetVal == ERROR_NOT_ENOUGH_MEMORY) return ERROR_NOT_ENOUGH_MEMORY; dwRetVal = windows_get_udp_table(&table_connection); if (dwRetVal == ERROR_NOT_ENOUGH_MEMORY) return ERROR_NOT_ENOUGH_MEMORY; for(index = 0; index < table_connection->entries; index++) { Tlv connection[7]; current_connection = &table_connection->table[index]; if (current_connection->type == AF_INET) { connection[0].header.type = TLV_TYPE_LOCAL_HOST_RAW; connection[0].header.length = sizeof(__u32); connection[0].buffer = (PUCHAR)¤t_connection->local_addr.addr; connection[1].header.type = TLV_TYPE_PEER_HOST_RAW; connection[1].header.length = sizeof(__u32); connection[1].buffer = (PUCHAR)¤t_connection->remote_addr.addr; } else { connection[0].header.type = TLV_TYPE_LOCAL_HOST_RAW; connection[0].header.length = sizeof(__u128); connection[0].buffer = (PUCHAR)¤t_connection->local_addr.addr6; connection[1].header.type = TLV_TYPE_PEER_HOST_RAW; connection[1].header.length = sizeof(__u128); connection[1].buffer = (PUCHAR)¤t_connection->remote_addr.addr6; } local_port_be = htonl(current_connection->local_port); connection[2].header.type = TLV_TYPE_LOCAL_PORT; connection[2].header.length = sizeof(__u32); connection[2].buffer = (PUCHAR)&local_port_be; remote_port_be = htonl(current_connection->remote_port); connection[3].header.type = TLV_TYPE_PEER_PORT; connection[3].header.length = sizeof(__u32); connection[3].buffer = (PUCHAR)&remote_port_be; connection[4].header.type = TLV_TYPE_MAC_NAME; connection[4].header.length = strlen(current_connection->protocol) + 1; connection[4].buffer = (PUCHAR)(current_connection->protocol); connection[5].header.type = TLV_TYPE_SUBNET_STRING; connection[5].header.length = strlen(current_connection->state) + 1; connection[5].buffer = (PUCHAR)(current_connection->state); connection[6].header.type = TLV_TYPE_PROCESS_NAME; connection[6].header.length = strlen(current_connection->program_name) + 1; connection[6].buffer = (PUCHAR)(current_connection->program_name); packet_add_tlv_group(response, TLV_TYPE_NETSTAT_ENTRY, connection, 7); } dprintf("sent %d connections", table_connection->entries); if (table_connection) free(table_connection); return ERROR_SUCCESS; } #else #include <sys/types.h> #include <dirent.h> char *tcp_connection_states[] = { "", "ESTABLISHED", "SYN_SENT", "SYN_RECV", "FIN_WAIT1", "FIN_WAIT2", "TIME_WAIT", "CLOSED", "CLOSE_WAIT", "LAST_ACK", "LISTEN", "CLOSING", "UNKNOWN" }; char *udp_connection_states[] = { "", "ESTABLISHED", "", "", "", "", "", "", "", "", "", "", "UNKNOWN" }; DWORD linux_parse_proc_net_file(char * filename, struct connection_table ** table_connection, char type, char * protocol, char tableidx ) { struct connection_table * tmp_table; struct connection_entry * current_connection; char ** connection_states; FILE * fd; char buffer[300], buffer_junk[100]; __u32 local_addr, remote_addr; __u128 local_addr6, remote_addr6; __u32 local_port, remote_port; __u32 state, uid, inode; __u32 newsize; fd = fopen(filename, "r"); if (fd == NULL) return -1; if (tableidx == 0) // TCP states connection_states = tcp_connection_states; else // UDP states connection_states = udp_connection_states; /* * read first line that we don't need * sl local_address remote_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode */ while (!feof(fd) && fgetc(fd) != '\n'); while (!feof(fd) && (fgets(buffer, sizeof(buffer), fd) != NULL)) { if ((*table_connection)->entries >= (*table_connection)->max_entries) { newsize = sizeof(struct connection_table); newsize += ((*table_connection)->entries + 10) * sizeof(struct connection_entry); tmp_table = realloc(*table_connection, newsize); *table_connection = tmp_table; memset(&(*table_connection)->table[(*table_connection)->entries], 0, 10 * sizeof(struct connection_entry)); (*table_connection)->max_entries += 10; } current_connection = &(*table_connection)->table[(*table_connection)->entries]; if (type == AF_INET) { if (sscanf(buffer, " %*u: %lX:%x %lX:%x %x %*X:%*X %*x:%*X %*x %u %*u %u %[^\n] ", &local_addr, &local_port, &remote_addr, &remote_port, &state, &uid, &inode, buffer_junk) == 8) { current_connection->local_addr.addr = local_addr; current_connection->remote_addr.addr = remote_addr; } else continue; } else { // AF_INET6 if (sscanf(buffer, " %*u: %08X%08X%08X%08X:%x %08X%08x%08X%08X:%x %x %*X:%*X %*x:%*X %*x %u %*u %u %[^\n] ", &local_addr6.a1, &local_addr6.a2,&local_addr6.a3, &local_addr6.a4, &local_port, &remote_addr6.a1, &remote_addr6.a2, &remote_addr6.a3, &remote_addr6.a4,&remote_port, &state, &uid, &inode, buffer_junk) == 14) { memcpy(¤t_connection->local_addr.addr6, &local_addr6, sizeof(__u128)); memcpy(¤t_connection->remote_addr.addr6, &remote_addr6, sizeof(__u128)); } else continue; } current_connection->type = type; current_connection->local_port = local_port; current_connection->remote_port = remote_port; current_connection->uid = uid; current_connection->inode = inode; // protocol such as tcp/tcp6/udp/udp6 strncpy(current_connection->protocol, protocol, sizeof(current_connection->protocol)); if ((state < 0) && (state > 11)) state = 12; // points to UNKNOWN in the table // state, number to string : 0x0A --> LISTEN strncpy(current_connection->state, connection_states[state], sizeof(current_connection->state)); // initialize every program_name to "-", will be changed if we find the good info in /proc strncpy(current_connection->program_name, "-", sizeof(current_connection->program_name)); (*table_connection)->entries++; } fclose(fd); return 0; } DWORD linux_proc_get_program_name(struct connection_entry * connection, unsigned char * pid) { FILE *fd; char buffer[30], buffer_file[256], name[256]; char * bname; int do_status = 0; do { // try /proc/PID/cmdline first snprintf(buffer, sizeof(buffer)-1, "/proc/%s/cmdline", pid); fd = fopen(buffer, "r"); // will try /proc/PID/status if (fd == NULL) { do_status = 1; break; } if (fgets(buffer_file, sizeof(buffer_file), fd) == NULL) { fclose(fd); do_status = 1; break; } // each entry in cmdline is seperated by '\0' so buffer_file contains first the path of the executable launched if ((bname = basename(buffer_file)) == NULL) { fclose(fd); do_status = 1; break; } // copy basename into name to be consistent at the end strncpy(name, bname, sizeof(name)-1); name[sizeof(name)-1] = '\0'; } while (0); if (fd != NULL) fclose(fd); // /proc/PID/cmdline failed, try /proc/PID/status if (do_status == 1) { snprintf(buffer, sizeof(buffer), "/proc/%s/status", pid); fd = fopen(buffer, "r"); // will try /proc/PID/status if (fd == NULL) return -1; if (fgets(buffer_file, sizeof(buffer_file), fd) == NULL) { fclose(fd); return -1; } if (sscanf(buffer_file, "Name: %200s\n", name) != 1) { fclose(fd); return -1; } fclose(fd); } snprintf(connection->program_name, sizeof(connection->program_name), "%s/%s", pid, name); return 0; } struct connection_entry * find_connection(struct connection_table * table_connection, __u32 inode) { __u32 i; for( i = 0 ; i < table_connection->entries ; i++) { if (table_connection->table[i].inode == inode) return &table_connection->table[i]; } return NULL; } DWORD linux_proc_fill_program_name(struct connection_table * table_connection) { char buffer[60]; struct dirent *procent, *fdent; DIR * procfd, * pidfd; struct stat stat_buf; struct connection_entry * connection; procfd = opendir("/proc"); if (procfd == NULL) return -1; while ((procent = readdir(procfd)) != NULL) { // not a pid directory if (!isdigit(*(procent->d_name))) continue; snprintf(buffer, sizeof(buffer), "/proc/%s/fd/", procent->d_name); if ((pidfd = opendir(buffer)) == NULL) continue; while((fdent = readdir(pidfd)) != NULL) { snprintf(buffer, sizeof(buffer), "/proc/%s/fd/%s", procent->d_name, fdent->d_name); if (stat(buffer, &stat_buf) < 0) continue; if (!S_ISSOCK(stat_buf.st_mode)) continue; // ok, FD is a socket, search if we have it in our list if ((connection = find_connection(table_connection, stat_buf.st_ino)) != NULL) linux_proc_get_program_name(connection, procent->d_name); } closedir(pidfd); } closedir(procfd); return 0; } DWORD linux_proc_get_connection_table(struct connection_table ** table_connection) { *table_connection = calloc(sizeof(struct connection_table) + 10 * sizeof(struct connection_entry), 1); (*table_connection)->max_entries = 10; linux_parse_proc_net_file("/proc/net/tcp" , table_connection, AF_INET , "tcp", 0); linux_parse_proc_net_file("/proc/net/tcp6", table_connection, AF_INET6, "tcp6", 0); linux_parse_proc_net_file("/proc/net/udp" , table_connection, AF_INET , "udp", 1); linux_parse_proc_net_file("/proc/net/udp6", table_connection, AF_INET6, "udp6", 1); // fill the PID/program_name part linux_proc_fill_program_name(*table_connection); return ERROR_SUCCESS; } DWORD linux_get_connection_table(Remote *remote, Packet *response) { struct connection_table *table_connection = NULL; __u32 local_port_be, remote_port_be, uid_be, inode_be; __u32 index; DWORD result; dprintf("getting connection list through /proc/net"); result = linux_proc_get_connection_table(&table_connection); dprintf("result = %d, table_connection = 0x%p , entries : %d", result, table_connection, table_connection->entries); for(index = 0; index < table_connection->entries; index++) { Tlv connection[9]; if (table_connection->table[index].type == AF_INET) { connection[0].header.type = TLV_TYPE_LOCAL_HOST_RAW; connection[0].header.length = sizeof(__u32); connection[0].buffer = (PUCHAR)&table_connection->table[index].local_addr.addr; connection[1].header.type = TLV_TYPE_PEER_HOST_RAW; connection[1].header.length = sizeof(__u32); connection[1].buffer = (PUCHAR)&table_connection->table[index].remote_addr.addr; } else { connection[0].header.type = TLV_TYPE_LOCAL_HOST_RAW; connection[0].header.length = sizeof(__u128); connection[0].buffer = (PUCHAR)&table_connection->table[index].local_addr.addr6; connection[1].header.type = TLV_TYPE_PEER_HOST_RAW; connection[1].header.length = sizeof(__u128); connection[1].buffer = (PUCHAR)&table_connection->table[index].remote_addr.addr6; } local_port_be = htonl(table_connection->table[index].local_port & 0x0000ffff); connection[2].header.type = TLV_TYPE_LOCAL_PORT; connection[2].header.length = sizeof(__u32); connection[2].buffer = (PUCHAR)&local_port_be; remote_port_be = htonl(table_connection->table[index].remote_port & 0x0000ffff); connection[3].header.type = TLV_TYPE_PEER_PORT; connection[3].header.length = sizeof(__u32); connection[3].buffer = (PUCHAR)&remote_port_be; connection[4].header.type = TLV_TYPE_MAC_NAME; connection[4].header.length = strlen(table_connection->table[index].protocol) + 1; connection[4].buffer = (PUCHAR)(table_connection->table[index].protocol); connection[5].header.type = TLV_TYPE_SUBNET_STRING; connection[5].header.length = strlen(table_connection->table[index].state) + 1; connection[5].buffer = (PUCHAR)(table_connection->table[index].state); uid_be = htonl(table_connection->table[index].uid); connection[6].header.type = TLV_TYPE_PID; connection[6].header.length = sizeof(__u32); connection[6].buffer = (PUCHAR)&uid_be; inode_be = htonl(table_connection->table[index].inode); connection[7].header.type = TLV_TYPE_ROUTE_METRIC; connection[7].header.length = sizeof(__u32); connection[7].buffer = (PUCHAR)&inode_be; connection[8].header.type = TLV_TYPE_PROCESS_NAME; connection[8].header.length = strlen(table_connection->table[index].program_name) + 1; connection[8].buffer = (PUCHAR)(table_connection->table[index].program_name); packet_add_tlv_group(response, TLV_TYPE_NETSTAT_ENTRY, connection, 9); } dprintf("sent %d connections", table_connection->entries); if (table_connection) free(table_connection); } #endif /* * Returns zero or more connection entries to the requestor from the connection list */ DWORD request_net_config_get_netstat(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); DWORD result; #ifdef _WIN32 result = windows_get_connection_table(remote, response); #else result = linux_get_connection_table(remote, response); #endif packet_transmit_response(result, remote, response); return ERROR_SUCCESS; }