18dfd7ea7SAxel Dörfler /*
220a31c45SAxel Dörfler * Copyright 2006-2019, Haiku, Inc. All Rights Reserved.
38dfd7ea7SAxel Dörfler * Distributed under the terms of the MIT License.
48dfd7ea7SAxel Dörfler *
58dfd7ea7SAxel Dörfler * Authors:
68dfd7ea7SAxel Dörfler * Axel Dörfler, axeld@pinc-software.de
7bcdcff76SAxel Dörfler * James Woodcock
88dfd7ea7SAxel Dörfler */
98dfd7ea7SAxel Dörfler
1020a31c45SAxel Dörfler
118dfd7ea7SAxel Dörfler #include <arpa/inet.h>
128dfd7ea7SAxel Dörfler #include <errno.h>
13df50f7a9SIngo Weinhold #include <getopt.h>
14df50f7a9SIngo Weinhold #include <net/if.h>
15df50f7a9SIngo Weinhold #include <netdb.h>
16df50f7a9SIngo Weinhold #include <netinet/in.h>
178dfd7ea7SAxel Dörfler #include <stdio.h>
188dfd7ea7SAxel Dörfler #include <stdlib.h>
198dfd7ea7SAxel Dörfler #include <string.h>
208dfd7ea7SAxel Dörfler #include <unistd.h>
21df50f7a9SIngo Weinhold
22df50f7a9SIngo Weinhold #include <SupportDefs.h>
23df50f7a9SIngo Weinhold
24df50f7a9SIngo Weinhold #include <net_stat.h>
25df50f7a9SIngo Weinhold #include <syscalls.h>
268dfd7ea7SAxel Dörfler
278dfd7ea7SAxel Dörfler
288dfd7ea7SAxel Dörfler extern const char* __progname;
298dfd7ea7SAxel Dörfler const char* kProgramName = __progname;
308dfd7ea7SAxel Dörfler
31bcdcff76SAxel Dörfler static int sResolveNames = 1;
328dfd7ea7SAxel Dörfler
338dfd7ea7SAxel Dörfler struct address_family {
348dfd7ea7SAxel Dörfler int family;
358dfd7ea7SAxel Dörfler const char* name;
368dfd7ea7SAxel Dörfler const char* identifiers[4];
378dfd7ea7SAxel Dörfler void (*print_address)(sockaddr* address);
388dfd7ea7SAxel Dörfler };
398dfd7ea7SAxel Dörfler
4020a31c45SAxel Dörfler enum filter_flags {
4120a31c45SAxel Dörfler FILTER_FAMILY_MASK = 0x0000ff,
4220a31c45SAxel Dörfler FILTER_PROTOCOL_MASK = 0x00ff00,
4320a31c45SAxel Dörfler FILTER_STATE_MASK = 0xff0000,
4420a31c45SAxel Dörfler
4520a31c45SAxel Dörfler // Families
4620a31c45SAxel Dörfler FILTER_AF_INET = 0x000001,
4720a31c45SAxel Dörfler FILTER_AF_INET6 = 0x000002,
4820a31c45SAxel Dörfler FILTER_AF_UNIX = 0x000004,
4920a31c45SAxel Dörfler
5020a31c45SAxel Dörfler // Protocols
5120a31c45SAxel Dörfler FILTER_IPPROTO_TCP = 0x000100,
5220a31c45SAxel Dörfler FILTER_IPPROTO_UDP = 0x000200,
5320a31c45SAxel Dörfler
5420a31c45SAxel Dörfler // States
5520a31c45SAxel Dörfler FILTER_STATE_LISTEN = 0x010000,
5620a31c45SAxel Dörfler };
5720a31c45SAxel Dörfler
588dfd7ea7SAxel Dörfler // AF_INET family
598dfd7ea7SAxel Dörfler static void inet_print_address(sockaddr* address);
608dfd7ea7SAxel Dörfler
618dfd7ea7SAxel Dörfler static const address_family kFamilies[] = {
628dfd7ea7SAxel Dörfler {
638dfd7ea7SAxel Dörfler AF_INET,
648dfd7ea7SAxel Dörfler "inet",
658dfd7ea7SAxel Dörfler {"AF_INET", "inet", "ipv4", NULL},
668dfd7ea7SAxel Dörfler inet_print_address
678dfd7ea7SAxel Dörfler },
688dfd7ea7SAxel Dörfler { -1, NULL, {NULL}, NULL }
698dfd7ea7SAxel Dörfler };
708dfd7ea7SAxel Dörfler
718dfd7ea7SAxel Dörfler
728dfd7ea7SAxel Dörfler static void
inet_print_address(sockaddr * _address)738dfd7ea7SAxel Dörfler inet_print_address(sockaddr* _address)
748dfd7ea7SAxel Dörfler {
758dfd7ea7SAxel Dörfler sockaddr_in& address = *(sockaddr_in *)_address;
768dfd7ea7SAxel Dörfler
778dfd7ea7SAxel Dörfler if (address.sin_family != AF_INET || address.sin_len == 0) {
7866a4a428SHugo Santos printf("%-22s", "-");
798dfd7ea7SAxel Dörfler return;
808dfd7ea7SAxel Dörfler }
818dfd7ea7SAxel Dörfler
82bcdcff76SAxel Dörfler hostent* host = NULL;
83bcdcff76SAxel Dörfler servent* service = NULL;
84bcdcff76SAxel Dörfler if (sResolveNames) {
85bcdcff76SAxel Dörfler host = gethostbyaddr((const char*)&address.sin_addr, sizeof(in_addr),
86bcdcff76SAxel Dörfler AF_INET);
87eab09848SAxel Dörfler service = getservbyport(address.sin_port, NULL);
88bcdcff76SAxel Dörfler }
898dfd7ea7SAxel Dörfler
9079608a2dSAxel Dörfler const char *hostName;
9179608a2dSAxel Dörfler if (host != NULL)
9279608a2dSAxel Dörfler hostName = host->h_name;
9379608a2dSAxel Dörfler else if (address.sin_addr.s_addr == INADDR_ANY)
9479608a2dSAxel Dörfler hostName = "*";
958dfd7ea7SAxel Dörfler else
9679608a2dSAxel Dörfler hostName = inet_ntoa(address.sin_addr);
978dfd7ea7SAxel Dörfler
9879608a2dSAxel Dörfler char buffer[128];
9979608a2dSAxel Dörfler int length = strlcpy(buffer, hostName, sizeof(buffer));
10079608a2dSAxel Dörfler
10179608a2dSAxel Dörfler char port[64];
10279608a2dSAxel Dörfler if (service != NULL)
10379608a2dSAxel Dörfler strlcpy(port, service->s_name, sizeof(port));
10479608a2dSAxel Dörfler else if (address.sin_port == 0)
10579608a2dSAxel Dörfler strcpy(port, "*");
10679608a2dSAxel Dörfler else
10779608a2dSAxel Dörfler snprintf(port, sizeof(port), "%u", ntohs(address.sin_port));
10879608a2dSAxel Dörfler
10979608a2dSAxel Dörfler snprintf(buffer + length, sizeof(buffer) - length, ":%s", port);
11079608a2dSAxel Dörfler
11166a4a428SHugo Santos printf("%-22s", buffer);
1128dfd7ea7SAxel Dörfler }
1138dfd7ea7SAxel Dörfler
1148dfd7ea7SAxel Dörfler
1158dfd7ea7SAxel Dörfler // #pragma mark -
1168dfd7ea7SAxel Dörfler
1178dfd7ea7SAxel Dörfler
1188dfd7ea7SAxel Dörfler void
usage(int status)1198dfd7ea7SAxel Dörfler usage(int status)
1208dfd7ea7SAxel Dörfler {
12120a31c45SAxel Dörfler printf("Usage: %s [-nh]\n", kProgramName);
12220a31c45SAxel Dörfler printf("Options:\n");
123bcdcff76SAxel Dörfler printf(" -n don't resolve names\n");
124bcdcff76SAxel Dörfler printf(" -h this help\n");
12520a31c45SAxel Dörfler printf("Filter options:\n");
12620a31c45SAxel Dörfler printf(" -4 IPv4\n");
12720a31c45SAxel Dörfler printf(" -6 IPv6\n");
12820a31c45SAxel Dörfler printf(" -x Unix\n");
12920a31c45SAxel Dörfler printf(" -t TCP\n");
13020a31c45SAxel Dörfler printf(" -u UDP\n");
13120a31c45SAxel Dörfler printf(" -l listen state\n");
1328dfd7ea7SAxel Dörfler
1338dfd7ea7SAxel Dörfler exit(status);
1348dfd7ea7SAxel Dörfler }
1358dfd7ea7SAxel Dörfler
1368dfd7ea7SAxel Dörfler
1378dfd7ea7SAxel Dörfler bool
get_address_family(const char * argument,int32 & familyIndex)1388dfd7ea7SAxel Dörfler get_address_family(const char* argument, int32& familyIndex)
1398dfd7ea7SAxel Dörfler {
1408dfd7ea7SAxel Dörfler for (int32 i = 0; kFamilies[i].family >= 0; i++) {
1418dfd7ea7SAxel Dörfler for (int32 j = 0; kFamilies[i].identifiers[j]; j++) {
1428dfd7ea7SAxel Dörfler if (!strcmp(argument, kFamilies[i].identifiers[j])) {
1438dfd7ea7SAxel Dörfler // found a match
1448dfd7ea7SAxel Dörfler familyIndex = i;
1458dfd7ea7SAxel Dörfler return true;
1468dfd7ea7SAxel Dörfler }
1478dfd7ea7SAxel Dörfler }
1488dfd7ea7SAxel Dörfler }
1498dfd7ea7SAxel Dörfler
1508dfd7ea7SAxel Dörfler // defaults to AF_INET
1518dfd7ea7SAxel Dörfler familyIndex = 0;
1528dfd7ea7SAxel Dörfler return false;
1538dfd7ea7SAxel Dörfler }
1548dfd7ea7SAxel Dörfler
1558dfd7ea7SAxel Dörfler
1568dfd7ea7SAxel Dörfler // #pragma mark -
1578dfd7ea7SAxel Dörfler
1588dfd7ea7SAxel Dörfler
1598dfd7ea7SAxel Dörfler int
main(int argc,char ** argv)1608dfd7ea7SAxel Dörfler main(int argc, char** argv)
1618dfd7ea7SAxel Dörfler {
162bcdcff76SAxel Dörfler int optionIndex = 0;
163bcdcff76SAxel Dörfler int opt;
16420a31c45SAxel Dörfler int filter = 0;
16520a31c45SAxel Dörfler
16620a31c45SAxel Dörfler const static struct option kLongOptions[] = {
167bcdcff76SAxel Dörfler {"help", no_argument, 0, 'h'},
168bcdcff76SAxel Dörfler {"numeric", no_argument, 0, 'n'},
16920a31c45SAxel Dörfler
17020a31c45SAxel Dörfler {"inet", no_argument, 0, '4'},
17120a31c45SAxel Dörfler {"inet6", no_argument, 0, '6'},
17220a31c45SAxel Dörfler {"unix", no_argument, 0, 'x'},
17320a31c45SAxel Dörfler
17420a31c45SAxel Dörfler {"tcp", no_argument, 0, 't'},
17520a31c45SAxel Dörfler {"udp", no_argument, 0, 'u'},
17620a31c45SAxel Dörfler
17720a31c45SAxel Dörfler {"listen", no_argument, 0, 'l'},
17820a31c45SAxel Dörfler
179bcdcff76SAxel Dörfler {0, 0, 0, 0}
180bcdcff76SAxel Dörfler };
181bcdcff76SAxel Dörfler
182bcdcff76SAxel Dörfler do {
18320a31c45SAxel Dörfler opt = getopt_long(argc, argv, "hn46xtul", kLongOptions,
18420a31c45SAxel Dörfler &optionIndex);
185bcdcff76SAxel Dörfler switch (opt) {
186bcdcff76SAxel Dörfler case -1:
187bcdcff76SAxel Dörfler // end of arguments, do nothing
188bcdcff76SAxel Dörfler break;
189bcdcff76SAxel Dörfler
190bcdcff76SAxel Dörfler case 'n':
191bcdcff76SAxel Dörfler sResolveNames = 0;
192bcdcff76SAxel Dörfler break;
193bcdcff76SAxel Dörfler
19420a31c45SAxel Dörfler // Family filter
19520a31c45SAxel Dörfler case '4':
19620a31c45SAxel Dörfler filter |= FILTER_AF_INET;
19720a31c45SAxel Dörfler break;
19820a31c45SAxel Dörfler case '6':
19920a31c45SAxel Dörfler filter |= FILTER_AF_INET6;
20020a31c45SAxel Dörfler break;
20120a31c45SAxel Dörfler case 'x':
20220a31c45SAxel Dörfler filter |= FILTER_AF_UNIX;
20320a31c45SAxel Dörfler break;
20420a31c45SAxel Dörfler // Protocol filter
20520a31c45SAxel Dörfler case 't':
20620a31c45SAxel Dörfler filter |= FILTER_IPPROTO_TCP;
20720a31c45SAxel Dörfler break;
20820a31c45SAxel Dörfler case 'u':
20920a31c45SAxel Dörfler filter |= FILTER_IPPROTO_UDP;
21020a31c45SAxel Dörfler break;
21120a31c45SAxel Dörfler // State filter
21220a31c45SAxel Dörfler case 'l':
21320a31c45SAxel Dörfler filter |= FILTER_STATE_LISTEN;
21420a31c45SAxel Dörfler break;
21520a31c45SAxel Dörfler
216bcdcff76SAxel Dörfler case 'h':
217bcdcff76SAxel Dörfler default:
2188dfd7ea7SAxel Dörfler usage(0);
219bcdcff76SAxel Dörfler break;
220bcdcff76SAxel Dörfler }
221bcdcff76SAxel Dörfler } while (opt != -1);
2228dfd7ea7SAxel Dörfler
2238dfd7ea7SAxel Dörfler bool printProgram = true;
224bcdcff76SAxel Dörfler // TODO: add some more program options... :-)
2258dfd7ea7SAxel Dörfler
226bcdcff76SAxel Dörfler printf("Proto Recv-Q Send-Q Local Address Foreign Address "
227bcdcff76SAxel Dörfler "State Program\n");
2288dfd7ea7SAxel Dörfler
2298dfd7ea7SAxel Dörfler uint32 cookie = 0;
2308dfd7ea7SAxel Dörfler int family = -1;
2318dfd7ea7SAxel Dörfler net_stat stat;
232df50f7a9SIngo Weinhold while (_kern_get_next_socket_stat(family, &cookie, &stat) == B_OK) {
23320a31c45SAxel Dörfler // Filter families
23420a31c45SAxel Dörfler if ((filter & FILTER_FAMILY_MASK) != 0) {
23520a31c45SAxel Dörfler if (((filter & FILTER_AF_INET) == 0 || family != AF_INET)
23620a31c45SAxel Dörfler && ((filter & FILTER_AF_INET6) == 0 || family != AF_INET6)
23720a31c45SAxel Dörfler && ((filter & FILTER_AF_UNIX) == 0 || family != AF_UNIX))
23820a31c45SAxel Dörfler continue;
23920a31c45SAxel Dörfler }
24020a31c45SAxel Dörfler // Filter protocols
24120a31c45SAxel Dörfler if ((filter & FILTER_PROTOCOL_MASK) != 0) {
24220a31c45SAxel Dörfler if (((filter & FILTER_IPPROTO_TCP) == 0
24320a31c45SAxel Dörfler || stat.protocol != IPPROTO_TCP)
24420a31c45SAxel Dörfler && ((filter & FILTER_IPPROTO_UDP) == 0
24520a31c45SAxel Dörfler || stat.protocol != IPPROTO_UDP))
24620a31c45SAxel Dörfler continue;
24720a31c45SAxel Dörfler }
24820a31c45SAxel Dörfler if ((filter & FILTER_STATE_MASK) != 0) {
24920a31c45SAxel Dörfler if ((filter & FILTER_STATE_LISTEN) == 0
25020a31c45SAxel Dörfler || strcmp(stat.state, "listen") != 0)
25120a31c45SAxel Dörfler continue;
25220a31c45SAxel Dörfler }
25320a31c45SAxel Dörfler
2548dfd7ea7SAxel Dörfler protoent* proto = getprotobynumber(stat.protocol);
2558dfd7ea7SAxel Dörfler if (proto != NULL)
2568dfd7ea7SAxel Dörfler printf("%-6s ", proto->p_name);
2578dfd7ea7SAxel Dörfler else
2588dfd7ea7SAxel Dörfler printf("%-6d ", stat.protocol);
2598dfd7ea7SAxel Dörfler
26066a4a428SHugo Santos printf("%6lu ", stat.receive_queue_size);
26166a4a428SHugo Santos printf("%6lu ", stat.send_queue_size);
26266a4a428SHugo Santos
2638dfd7ea7SAxel Dörfler inet_print_address((sockaddr*)&stat.address);
2648dfd7ea7SAxel Dörfler inet_print_address((sockaddr*)&stat.peer);
2658dfd7ea7SAxel Dörfler printf("%-12s ", stat.state);
2668dfd7ea7SAxel Dörfler
2678dfd7ea7SAxel Dörfler team_info info;
2688dfd7ea7SAxel Dörfler if (printProgram && get_team_info(stat.owner, &info) == B_OK) {
2698dfd7ea7SAxel Dörfler // remove arguments
2708dfd7ea7SAxel Dörfler char* name = strchr(info.args, ' ');
2718dfd7ea7SAxel Dörfler if (name != NULL)
2728dfd7ea7SAxel Dörfler name[0] = '\0';
2738dfd7ea7SAxel Dörfler
2748dfd7ea7SAxel Dörfler // remove path name
2758dfd7ea7SAxel Dörfler name = strrchr(info.args, '/');
2768dfd7ea7SAxel Dörfler if (name != NULL)
2778dfd7ea7SAxel Dörfler name++;
2788dfd7ea7SAxel Dörfler else
2798dfd7ea7SAxel Dörfler name = info.args;
2808dfd7ea7SAxel Dörfler
281*a2efc1d6SMurai Takashi printf("%" B_PRId32 "/%s\n", stat.owner, name);
2828dfd7ea7SAxel Dörfler } else
283*a2efc1d6SMurai Takashi printf("%" B_PRId32 "\n", stat.owner);
2848dfd7ea7SAxel Dörfler }
2858dfd7ea7SAxel Dörfler
2868dfd7ea7SAxel Dörfler return 0;
2878dfd7ea7SAxel Dörfler }
2888dfd7ea7SAxel Dörfler
289