1 /* 2 * Copyright 2006-2019, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 * James Woodcock 8 */ 9 10 11 #include <arpa/inet.h> 12 #include <errno.h> 13 #include <getopt.h> 14 #include <net/if.h> 15 #include <netdb.h> 16 #include <netinet/in.h> 17 #include <stdio.h> 18 #include <stdlib.h> 19 #include <string.h> 20 #include <unistd.h> 21 22 #include <SupportDefs.h> 23 24 #include <net_stat.h> 25 #include <syscalls.h> 26 27 28 extern const char* __progname; 29 const char* kProgramName = __progname; 30 31 static int sResolveNames = 1; 32 33 struct address_family { 34 int family; 35 const char* name; 36 const char* identifiers[4]; 37 void (*print_address)(sockaddr* address); 38 }; 39 40 enum filter_flags { 41 FILTER_FAMILY_MASK = 0x0000ff, 42 FILTER_PROTOCOL_MASK = 0x00ff00, 43 FILTER_STATE_MASK = 0xff0000, 44 45 // Families 46 FILTER_AF_INET = 0x000001, 47 FILTER_AF_INET6 = 0x000002, 48 FILTER_AF_UNIX = 0x000004, 49 50 // Protocols 51 FILTER_IPPROTO_TCP = 0x000100, 52 FILTER_IPPROTO_UDP = 0x000200, 53 54 // States 55 FILTER_STATE_LISTEN = 0x010000, 56 }; 57 58 // AF_INET family 59 static void inet_print_address(sockaddr* address); 60 61 static const address_family kFamilies[] = { 62 { 63 AF_INET, 64 "inet", 65 {"AF_INET", "inet", "ipv4", NULL}, 66 inet_print_address 67 }, 68 { -1, NULL, {NULL}, NULL } 69 }; 70 71 72 static void 73 inet_print_address(sockaddr* _address) 74 { 75 sockaddr_in& address = *(sockaddr_in *)_address; 76 77 if (address.sin_family != AF_INET || address.sin_len == 0) { 78 printf("%-22s", "-"); 79 return; 80 } 81 82 hostent* host = NULL; 83 servent* service = NULL; 84 if (sResolveNames) { 85 host = gethostbyaddr((const char*)&address.sin_addr, sizeof(in_addr), 86 AF_INET); 87 service = getservbyport(address.sin_port, NULL); 88 } 89 90 const char *hostName; 91 if (host != NULL) 92 hostName = host->h_name; 93 else if (address.sin_addr.s_addr == INADDR_ANY) 94 hostName = "*"; 95 else 96 hostName = inet_ntoa(address.sin_addr); 97 98 char buffer[128]; 99 int length = strlcpy(buffer, hostName, sizeof(buffer)); 100 101 char port[64]; 102 if (service != NULL) 103 strlcpy(port, service->s_name, sizeof(port)); 104 else if (address.sin_port == 0) 105 strcpy(port, "*"); 106 else 107 snprintf(port, sizeof(port), "%u", ntohs(address.sin_port)); 108 109 snprintf(buffer + length, sizeof(buffer) - length, ":%s", port); 110 111 printf("%-22s", buffer); 112 } 113 114 115 // #pragma mark - 116 117 118 void 119 usage(int status) 120 { 121 printf("Usage: %s [-nh]\n", kProgramName); 122 printf("Options:\n"); 123 printf(" -n don't resolve names\n"); 124 printf(" -h this help\n"); 125 printf("Filter options:\n"); 126 printf(" -4 IPv4\n"); 127 printf(" -6 IPv6\n"); 128 printf(" -x Unix\n"); 129 printf(" -t TCP\n"); 130 printf(" -u UDP\n"); 131 printf(" -l listen state\n"); 132 133 exit(status); 134 } 135 136 137 bool 138 get_address_family(const char* argument, int32& familyIndex) 139 { 140 for (int32 i = 0; kFamilies[i].family >= 0; i++) { 141 for (int32 j = 0; kFamilies[i].identifiers[j]; j++) { 142 if (!strcmp(argument, kFamilies[i].identifiers[j])) { 143 // found a match 144 familyIndex = i; 145 return true; 146 } 147 } 148 } 149 150 // defaults to AF_INET 151 familyIndex = 0; 152 return false; 153 } 154 155 156 // #pragma mark - 157 158 159 int 160 main(int argc, char** argv) 161 { 162 int optionIndex = 0; 163 int opt; 164 int filter = 0; 165 166 const static struct option kLongOptions[] = { 167 {"help", no_argument, 0, 'h'}, 168 {"numeric", no_argument, 0, 'n'}, 169 170 {"inet", no_argument, 0, '4'}, 171 {"inet6", no_argument, 0, '6'}, 172 {"unix", no_argument, 0, 'x'}, 173 174 {"tcp", no_argument, 0, 't'}, 175 {"udp", no_argument, 0, 'u'}, 176 177 {"listen", no_argument, 0, 'l'}, 178 179 {0, 0, 0, 0} 180 }; 181 182 do { 183 opt = getopt_long(argc, argv, "hn46xtul", kLongOptions, 184 &optionIndex); 185 switch (opt) { 186 case -1: 187 // end of arguments, do nothing 188 break; 189 190 case 'n': 191 sResolveNames = 0; 192 break; 193 194 // Family filter 195 case '4': 196 filter |= FILTER_AF_INET; 197 break; 198 case '6': 199 filter |= FILTER_AF_INET6; 200 break; 201 case 'x': 202 filter |= FILTER_AF_UNIX; 203 break; 204 // Protocol filter 205 case 't': 206 filter |= FILTER_IPPROTO_TCP; 207 break; 208 case 'u': 209 filter |= FILTER_IPPROTO_UDP; 210 break; 211 // State filter 212 case 'l': 213 filter |= FILTER_STATE_LISTEN; 214 break; 215 216 case 'h': 217 default: 218 usage(0); 219 break; 220 } 221 } while (opt != -1); 222 223 bool printProgram = true; 224 // TODO: add some more program options... :-) 225 226 printf("Proto Recv-Q Send-Q Local Address Foreign Address " 227 "State Program\n"); 228 229 uint32 cookie = 0; 230 int family = -1; 231 net_stat stat; 232 while (_kern_get_next_socket_stat(family, &cookie, &stat) == B_OK) { 233 // Filter families 234 if ((filter & FILTER_FAMILY_MASK) != 0) { 235 if (((filter & FILTER_AF_INET) == 0 || family != AF_INET) 236 && ((filter & FILTER_AF_INET6) == 0 || family != AF_INET6) 237 && ((filter & FILTER_AF_UNIX) == 0 || family != AF_UNIX)) 238 continue; 239 } 240 // Filter protocols 241 if ((filter & FILTER_PROTOCOL_MASK) != 0) { 242 if (((filter & FILTER_IPPROTO_TCP) == 0 243 || stat.protocol != IPPROTO_TCP) 244 && ((filter & FILTER_IPPROTO_UDP) == 0 245 || stat.protocol != IPPROTO_UDP)) 246 continue; 247 } 248 if ((filter & FILTER_STATE_MASK) != 0) { 249 if ((filter & FILTER_STATE_LISTEN) == 0 250 || strcmp(stat.state, "listen") != 0) 251 continue; 252 } 253 254 protoent* proto = getprotobynumber(stat.protocol); 255 if (proto != NULL) 256 printf("%-6s ", proto->p_name); 257 else 258 printf("%-6d ", stat.protocol); 259 260 printf("%6lu ", stat.receive_queue_size); 261 printf("%6lu ", stat.send_queue_size); 262 263 inet_print_address((sockaddr*)&stat.address); 264 inet_print_address((sockaddr*)&stat.peer); 265 printf("%-12s ", stat.state); 266 267 team_info info; 268 if (printProgram && get_team_info(stat.owner, &info) == B_OK) { 269 // remove arguments 270 char* name = strchr(info.args, ' '); 271 if (name != NULL) 272 name[0] = '\0'; 273 274 // remove path name 275 name = strrchr(info.args, '/'); 276 if (name != NULL) 277 name++; 278 else 279 name = info.args; 280 281 printf("%" B_PRId32 "/%s\n", stat.owner, name); 282 } else 283 printf("%" B_PRId32 "\n", stat.owner); 284 } 285 286 return 0; 287 } 288 289