|
| 1 | +#include <stdio.h> |
| 2 | +#include <stdlib.h> |
| 3 | +#include <unistd.h> |
| 4 | +#include <getopt.h> |
| 5 | +#include <sys/types.h> |
| 6 | +#include <dirent.h> |
| 7 | +#include<string.h> |
| 8 | +#include <arpa/inet.h> |
| 9 | +#include <string> |
| 10 | +#include <unordered_map> |
| 11 | +#include <regex> |
| 12 | + |
| 13 | +#include "utils.h" |
| 14 | + |
| 15 | +void create_inode_table (std::unordered_map<std::string, std::string> &Hash_inode_table) { |
| 16 | + DIR *DIR_layer1, *DIR_layer2; |
| 17 | + struct dirent *dirent_layer1, *dirent_layer2; |
| 18 | + const char *path_proc = "/proc"; |
| 19 | + |
| 20 | + DIR_layer1 = opendir(path_proc); |
| 21 | + if (DIR_layer1 == NULL) { |
| 22 | + fprintf(stderr,"Ls: can not open %s", path_proc); |
| 23 | + } else { |
| 24 | + while ((dirent_layer1 = readdir(DIR_layer1)) != NULL) { |
| 25 | + if (is_valid_directory(dirent_layer1)) { |
| 26 | + char *file_path = (char*)malloc(100); |
| 27 | + sprintf(file_path, "%s/%s/fd", path_proc, dirent_layer1->d_name); |
| 28 | + DIR_layer2 = opendir(file_path); |
| 29 | + while ((dirent_layer2 = readdir(DIR_layer2)) != NULL) { |
| 30 | + if (dirent_layer2->d_type == DT_LNK) { |
| 31 | + char* link_path = (char*)malloc(100); |
| 32 | + char* symlink = (char*)malloc(100); |
| 33 | + sprintf(link_path, "%s/%s", file_path, dirent_layer2->d_name); |
| 34 | + int result = readlink(link_path, symlink, 100); |
| 35 | + if (result == -1) |
| 36 | + printf("cannot read link %s\n", link_path); |
| 37 | + else { |
| 38 | + symlink[result] = '\0'; |
| 39 | + // printf("symlink: %s\n", symlink); |
| 40 | + // printf("process: %s\n", dirent_layer1->d_name); |
| 41 | + // printf("inode: %s\n", inode); |
| 42 | + std::string inode = find_inode_by_symlink(symlink); |
| 43 | + Hash_inode_table[inode] = dirent_layer1->d_name; |
| 44 | + } |
| 45 | + } |
| 46 | + } |
| 47 | + } |
| 48 | + } |
| 49 | + } |
| 50 | + closedir(DIR_layer1); |
| 51 | + closedir(DIR_layer2); |
| 52 | +} |
| 53 | + |
| 54 | +void show_tcp_status (const char* path, std::unordered_map<std::string, std::string> &Hash_inode_table, std::vector <std::regex> &filter) { |
| 55 | + FILE *fp; |
| 56 | + char *buf; |
| 57 | + size_t ret; |
| 58 | + const char *delim = "\t\r\n "; |
| 59 | + int ROW_COUNT = 17; |
| 60 | + fp = fopen(path, "rb"); |
| 61 | + buf = (char*)malloc(BUFFER_SIZE); |
| 62 | + ret = fread(buf, 1, BUFFER_SIZE, fp); |
| 63 | + // printf("%s\n", buf); // print "/proc/net/tcp" data |
| 64 | + fclose(fp); |
| 65 | + |
| 66 | + char* local_ip = (char*)malloc(10); |
| 67 | + char* local_port = (char*)malloc(10); |
| 68 | + char* rem_ip = (char*)malloc(10); |
| 69 | + char* rem_port = (char*)malloc(10); |
| 70 | + std::string inode; |
| 71 | + std::string pid; |
| 72 | + char* proc_name = (char*)malloc(50); |
| 73 | + int mode; |
| 74 | + |
| 75 | + if (strcmp(path, "/proc/net/tcp") == 0) |
| 76 | + mode = AF_INET; |
| 77 | + else |
| 78 | + mode = AF_INET6; |
| 79 | + |
| 80 | + char *token = strtok(buf, delim); |
| 81 | + for (int i = 1; token != NULL; i++) { |
| 82 | + if (i > 12) { |
| 83 | + int index = normalize_tcp_index(i); |
| 84 | + // local_address |
| 85 | + if (index % ROW_COUNT == 2) { |
| 86 | + local_ip = parse_address(token, mode); |
| 87 | + local_port = parse_port(token, mode); |
| 88 | + } |
| 89 | + // rem_address |
| 90 | + if (index % ROW_COUNT == 3) { |
| 91 | + rem_ip = parse_address(token, mode); |
| 92 | + rem_port = parse_port(token, mode); |
| 93 | + } |
| 94 | + // inode |
| 95 | + if (index % ROW_COUNT == 10) { |
| 96 | + inode = token; |
| 97 | + auto result = Hash_inode_table.find(inode); |
| 98 | + if (result != Hash_inode_table.end()) { |
| 99 | + pid = result->second.c_str(); |
| 100 | + proc_name = find_proc_name(pid); |
| 101 | + if (is_filter_cmd(filter, std::string(proc_name))) { |
| 102 | + char* local_addr = (char*)malloc(20); |
| 103 | + char* rem_addr = (char*)malloc(20); |
| 104 | + char* pid_pname = (char*)malloc(50); |
| 105 | + sprintf(local_addr, "%s:%s", local_ip, local_port); |
| 106 | + sprintf(rem_addr, "%s:%s", rem_ip, rem_port); |
| 107 | + sprintf(pid_pname, "%s/%s", pid.c_str(), proc_name); |
| 108 | + if (mode == AF_INET) |
| 109 | + printf("%-8s%-20s%-20s%-30s\n", "tcp", local_addr, rem_addr, pid_pname); |
| 110 | + else |
| 111 | + printf("%-8s%-20s%-20s%-30s\n", "tcp6", local_addr, rem_addr, pid_pname); |
| 112 | + } |
| 113 | + } else { |
| 114 | + printf("Not found tcp\n"); |
| 115 | + } |
| 116 | + } |
| 117 | + } |
| 118 | + token = strtok(NULL, delim); |
| 119 | + } |
| 120 | +} |
| 121 | + |
| 122 | +void show_udp_status (const char* path, std::unordered_map<std::string, std::string> &Hash_inode_table, std::vector <std::regex> &filter) { |
| 123 | + FILE *fp; |
| 124 | + char *buf; |
| 125 | + size_t ret; |
| 126 | + const char *delim = " \t\r\n "; |
| 127 | + int ROW_COUNT = 13; |
| 128 | + fp = fopen(path, "rb"); |
| 129 | + buf = (char*)malloc(BUFFER_SIZE); |
| 130 | + ret = fread(buf, 1, BUFFER_SIZE, fp); |
| 131 | + // printf("%s\n", buf); // print "/proc/net/udp" data |
| 132 | + fclose(fp); |
| 133 | + |
| 134 | + char* local_ip = (char*)malloc(10); |
| 135 | + char* local_port = (char*)malloc(10); |
| 136 | + char* rem_ip = (char*)malloc(10); |
| 137 | + char* rem_port = (char*)malloc(10); |
| 138 | + std::string inode; |
| 139 | + std::string pid; |
| 140 | + char* proc_name = (char*)malloc(50); |
| 141 | + int mode; |
| 142 | + |
| 143 | + if (strcmp(path, "/proc/net/udp") == 0) |
| 144 | + mode = AF_INET; |
| 145 | + else |
| 146 | + mode = AF_INET6; |
| 147 | + |
| 148 | + char *token = strtok(buf, delim); |
| 149 | + for (int i = 1; token != NULL; i++) { |
| 150 | + if (i > 15) { |
| 151 | + int index = normalize_udp_index(i); |
| 152 | + // local_address |
| 153 | + if (index % ROW_COUNT == 2) { |
| 154 | + local_ip = parse_address(token, mode); |
| 155 | + local_port = parse_port(token, mode); |
| 156 | + } |
| 157 | + // rem_address |
| 158 | + if (index % ROW_COUNT == 3) { |
| 159 | + rem_ip = parse_address(token, mode); |
| 160 | + rem_port = parse_port(token, mode); |
| 161 | + } |
| 162 | + // inode |
| 163 | + if (index % ROW_COUNT == 10) { |
| 164 | + inode = std::string(token); |
| 165 | + auto result = Hash_inode_table.find(inode); |
| 166 | + if (result != Hash_inode_table.end()) { |
| 167 | + pid = result->second.c_str(); |
| 168 | + proc_name = find_proc_name(pid); |
| 169 | + if (is_filter_cmd(filter, std::string(proc_name))) { |
| 170 | + char* local_addr = (char*)malloc(20); |
| 171 | + char* rem_addr = (char*)malloc(20); |
| 172 | + char* pid_pname = (char*)malloc(50); |
| 173 | + sprintf(local_addr, "%s:%s", local_ip, local_port); |
| 174 | + sprintf(rem_addr, "%s:%s", rem_ip, rem_port); |
| 175 | + sprintf(pid_pname, "%s/%s", pid.c_str(), proc_name); |
| 176 | + if (mode == AF_INET) |
| 177 | + printf("%-8s%-20s%-20s%-30s\n", "udp", local_addr, rem_addr, pid_pname); |
| 178 | + else |
| 179 | + printf("%-8s%-20s%-20s%-30s\n", "udp6", local_addr, rem_addr, pid_pname); |
| 180 | + } |
| 181 | + } else { |
| 182 | + printf("Not found udp\n"); |
| 183 | + } |
| 184 | + } |
| 185 | + } |
| 186 | + token = strtok(NULL, delim); |
| 187 | + } |
| 188 | +} |
| 189 | + |
| 190 | +bool is_filter_cmd(std::vector <std::regex> &filter, std::string proc_name) { |
| 191 | + if (filter.size() == 0) |
| 192 | + return true; |
| 193 | + for (auto ®_filter_cmd: filter) |
| 194 | + if (std::regex_match(proc_name.begin(), proc_name.end(), reg_filter_cmd)) |
| 195 | + return true; |
| 196 | + return false; |
| 197 | +} |
| 198 | + |
| 199 | +char* find_proc_name (std::string pid) { |
| 200 | + FILE *fp; |
| 201 | + char *file_path = (char*)malloc(100); |
| 202 | + char *proc_name; |
| 203 | + size_t ret; |
| 204 | + sprintf(file_path, "/proc/%s/comm", pid.c_str()); |
| 205 | + fp = fopen(file_path, "rb"); |
| 206 | + proc_name = (char*)malloc(100); |
| 207 | + ret = fread(proc_name, 1, 100, fp); |
| 208 | + |
| 209 | + // remove new line character |
| 210 | + int length = 0; |
| 211 | + while(proc_name[length] != '\0') { |
| 212 | + if (proc_name[length] == '\n') { |
| 213 | + proc_name[length] = '\0'; |
| 214 | + break; |
| 215 | + } |
| 216 | + length++; |
| 217 | + } |
| 218 | + return proc_name; |
| 219 | +} |
| 220 | + |
| 221 | +std::string find_inode_by_symlink (char* symlink) { |
| 222 | + std::string inode; |
| 223 | + std::string s = std::string(symlink); |
| 224 | + unsigned int inode_tmp; |
| 225 | + std::regex reg("socket:\[[0-9]*]"); // ex: socket:[123] |
| 226 | + |
| 227 | + if (std::regex_match(s.begin(), s.end(), reg)) |
| 228 | + sscanf(s.substr(8, s.length()-9).c_str(), "%u", &inode_tmp); |
| 229 | + inode = std::to_string(inode_tmp); |
| 230 | + return inode; |
| 231 | +} |
| 232 | + |
| 233 | +char* parse_port (char* token, int mode) { |
| 234 | + char* port = (char*)malloc(10); |
| 235 | + unsigned port_x; |
| 236 | + unsigned addr[4]; |
| 237 | + if (mode == AF_INET) |
| 238 | + sscanf(token, "%x:%x", &addr[0], &port_x); |
| 239 | + else |
| 240 | + sscanf(token, "%8x%8x%8x%8x:%x", &addr[0], &addr[1], &addr[2], &addr[3], &port_x); |
| 241 | + if(port_x == 0) |
| 242 | + sprintf(port, "*"); |
| 243 | + else |
| 244 | + sprintf(port, "%d", port_x); |
| 245 | + |
| 246 | + return port; |
| 247 | +} |
| 248 | + |
| 249 | +char* parse_address (char* token, int mode) { |
| 250 | + unsigned addr[4]; |
| 251 | + char* addr_tmp = (char*)malloc(50); |
| 252 | + int mode_max_len; |
| 253 | + |
| 254 | + if (mode == AF_INET) { |
| 255 | + mode_max_len = INET_ADDRSTRLEN; |
| 256 | + sscanf(token, "%x:", &addr[0]); |
| 257 | + } else { |
| 258 | + mode_max_len = INET6_ADDRSTRLEN; |
| 259 | + sscanf(token, "%8x%8x%8x%8x:", &addr[0], &addr[1], &addr[2], &addr[3]); |
| 260 | + } |
| 261 | + inet_ntop(mode, &addr[0], addr_tmp, mode_max_len); |
| 262 | + |
| 263 | + return addr_tmp; |
| 264 | +} |
| 265 | + |
| 266 | +bool is_valid_directory (struct dirent *ptr) { |
| 267 | + if (ptr->d_type == DT_DIR |
| 268 | + && strcmp(ptr->d_name, ".") != 0 |
| 269 | + && strcmp(ptr->d_name, "..") != 0 |
| 270 | + && ptr->d_name[0] > 47 |
| 271 | + && ptr->d_name[0] < 58) { |
| 272 | + return true; |
| 273 | + } |
| 274 | + return false; |
| 275 | +} |
| 276 | + |
| 277 | +int normalize_udp_index (int index) { |
| 278 | + return index - 15 - (((index - 15) / 13) * 13); |
| 279 | +} |
| 280 | + |
| 281 | +int normalize_tcp_index (int index) { |
| 282 | + return index - 12 - (((index - 12) / 17) * 17); |
| 283 | +} |
| 284 | + |
| 285 | +void parse_cmdline(int argc, char *argv[], int *flag_tcp, int *flag_udp, std::vector <std::regex> &filter) { |
| 286 | + int result; |
| 287 | + int longindex = 0; // null |
| 288 | + const char *optstring = "tu"; |
| 289 | + |
| 290 | + static struct option long_options[] = { |
| 291 | + {"tcp", no_argument, NULL, 't'}, |
| 292 | + {"udp", no_argument, NULL, 'u'}, |
| 293 | + }; |
| 294 | + |
| 295 | + // parse filter cmd |
| 296 | + for(int i = 1; i < argc; i++) { |
| 297 | + if(argv[i][0]!='-') { |
| 298 | + std::string reg_filter_cmd; |
| 299 | + reg_filter_cmd = ".*"; |
| 300 | + reg_filter_cmd = reg_filter_cmd + argv[i] + ".*"; |
| 301 | + filter.push_back(std::regex(reg_filter_cmd.c_str())); |
| 302 | + } |
| 303 | + } |
| 304 | + |
| 305 | + while ((result = getopt_long(argc, argv, optstring, long_options, &longindex)) != -1) { |
| 306 | + switch (result) { |
| 307 | + case 't': |
| 308 | + *flag_tcp = 1; |
| 309 | + break; |
| 310 | + case 'u': |
| 311 | + *flag_udp = 1; |
| 312 | + break; |
| 313 | + default: |
| 314 | + break; |
| 315 | + } |
| 316 | + } |
| 317 | +} |
| 318 | + |
0 commit comments