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
inet_print_address(sockaddr * _address)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
usage(int status)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
get_address_family(const char * argument,int32 & familyIndex)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
main(int argc,char ** argv)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