GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/systat/netstat.c Lines: 0 170 0.0 %
Date: 2017-11-07 Branches: 0 132 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: netstat.c,v 1.45 2015/03/12 01:03:00 claudio Exp $	*/
2
/*	$NetBSD: netstat.c,v 1.3 1995/06/18 23:53:07 cgd Exp $	*/
3
4
/*-
5
 * Copyright (c) 1980, 1992, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
/*
34
 * netstat
35
 */
36
37
#include <kvm.h>
38
#include <sys/types.h>
39
#include <sys/sysctl.h>
40
#include <sys/socket.h>
41
#define _KERNEL
42
#include <sys/file.h>
43
#undef _KERNEL
44
45
#include <netinet/in.h>
46
#include <netinet/tcp.h>
47
#include <netinet/tcp_seq.h>
48
#define TCPSTATES
49
#include <netinet/tcp_fsm.h>
50
#include <arpa/inet.h>
51
52
#include <netdb.h>
53
#include <signal.h>
54
#include <stdlib.h>
55
#include <string.h>
56
#include <err.h>
57
#include <nlist.h>
58
#include <paths.h>
59
#include "systat.h"
60
#include "engine.h"
61
62
#define	TCP	0x1
63
#define	UDP	0x2
64
#define	OTHER	0x4
65
66
struct netinfo {
67
	union {
68
		struct	in_addr nif_laddr;	/* local address */
69
		struct	in6_addr nif_laddr6;	/* local address */
70
	} l;
71
	union {
72
		struct	in_addr	nif_faddr;	/* foreign address */
73
		struct	in6_addr nif_faddr6;	/* foreign address */
74
	} f;
75
	long	nif_rcvcc;		/* rcv buffer character count */
76
	long	nif_sndcc;		/* snd buffer character count */
77
	short	nif_lport;		/* local port */
78
	short	nif_fport;		/* foreign port */
79
	short	nif_state;		/* tcp state */
80
	short	nif_family;
81
	short	nif_proto;		/* protocol */
82
	short	nif_ipproto;
83
};
84
85
#define nif_laddr  l.nif_laddr
86
#define nif_laddr6 l.nif_laddr6
87
#define nif_faddr  f.nif_faddr
88
#define nif_faddr6 f.nif_faddr6
89
90
static void enter(struct kinfo_file *);
91
static int kf_comp(const void *, const void *);
92
static void inetprint(struct in_addr *, int, char *, field_def *);
93
static void inet6print(struct in6_addr *, int, char *, field_def *);
94
static void shownetstat(struct netinfo *p);
95
96
void print_ns(void);
97
int read_ns(void);
98
int select_ns(void);
99
int ns_keyboard_callback(int);
100
101
#define	streq(a,b)	(strcmp(a,b)==0)
102
103
static	int aflag = 0;
104
105
#define ADD_ALLOC  1000
106
107
int protos;
108
109
struct netinfo *netinfos = NULL;
110
size_t num_ns = 0;
111
static size_t num_alloc = 0;
112
113
114
field_def fields_ns[] = {
115
	{"LOCAL ADDRESS", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
116
	{"FOREIGN ADDRESS", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
117
	{"PROTO", 4, 9, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
118
	{"RECV-Q", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
119
	{"SEND-Q", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
120
	{"STATE", 5, 11, 6, FLD_ALIGN_LEFT, -1, 0, 0, 0},
121
};
122
123
#define FLD_NS_LOCAL	FIELD_ADDR(fields_ns,0)
124
#define FLD_NS_FOREIGN	FIELD_ADDR(fields_ns,1)
125
#define FLD_NS_PROTO	FIELD_ADDR(fields_ns,2)
126
#define FLD_NS_RECV_Q	FIELD_ADDR(fields_ns,3)
127
#define FLD_NS_SEND_Q	FIELD_ADDR(fields_ns,4)
128
#define FLD_NS_STATE	FIELD_ADDR(fields_ns,5)
129
130
/* Define views */
131
field_def *view_ns_0[] = {
132
	FLD_NS_LOCAL, FLD_NS_FOREIGN, FLD_NS_PROTO,
133
	FLD_NS_RECV_Q, FLD_NS_SEND_Q, FLD_NS_STATE, NULL
134
};
135
136
/* Define view managers */
137
struct view_manager netstat_mgr = {
138
	"Netstat", select_ns, read_ns, NULL, print_header,
139
	print_ns, ns_keyboard_callback, NULL, NULL
140
};
141
142
field_view views_ns[] = {
143
	{view_ns_0, "netstat", '0', &netstat_mgr},
144
	{NULL, NULL, 0, NULL}
145
};
146
147
148
149
150
struct netinfo *
151
next_ns(void)
152
{
153
	if (num_alloc <= num_ns) {
154
		struct netinfo *ni;
155
		size_t a = num_alloc + ADD_ALLOC;
156
		if (a < num_alloc)
157
			return NULL;
158
		ni = reallocarray(netinfos, a, sizeof(*ni));
159
		if (ni == NULL)
160
			return NULL;
161
		netinfos = ni;
162
		num_alloc = a;
163
	}
164
165
	return &netinfos[num_ns++];
166
}
167
168
static void
169
enter(struct kinfo_file *kf)
170
{
171
#define s6_addr32 __u6_addr.__u6_addr32
172
	struct netinfo *p;
173
174
	/* first filter out unwanted sockets */
175
	if (kf->so_family != AF_INET && kf->so_family != AF_INET6)
176
		return;
177
178
	switch (kf->so_protocol) {
179
	case IPPROTO_TCP:
180
		if ((protos & TCP) == 0)
181
			return;
182
		break;
183
	case IPPROTO_UDP:
184
		if ((protos & UDP) == 0)
185
			return;
186
		break;
187
	default:
188
		if ((protos & OTHER) == 0)
189
			return;
190
		break;
191
	}
192
193
	if (!aflag) {
194
		struct in6_addr faddr6;
195
196
		switch (kf->so_family) {
197
		case AF_INET:
198
			if (kf->inp_faddru[0] == INADDR_ANY)
199
				return;
200
			break;
201
		case AF_INET6:
202
			faddr6.s6_addr32[0] = kf->inp_faddru[0];
203
			faddr6.s6_addr32[1] = kf->inp_faddru[1];
204
			faddr6.s6_addr32[2] = kf->inp_faddru[2];
205
			faddr6.s6_addr32[3] = kf->inp_faddru[3];
206
			if (IN6_IS_ADDR_UNSPECIFIED(&faddr6))
207
				return;
208
			break;
209
		}
210
	}
211
212
	/* finally enter the socket to the table */
213
	p = next_ns();
214
	if (p == NULL) {
215
		error("Out of Memory!");
216
		return;
217
	}
218
219
	p->nif_lport = kf->inp_lport;
220
	p->nif_fport = kf->inp_fport;
221
	p->nif_proto = kf->so_protocol;
222
	p->nif_ipproto = kf->inp_proto;
223
224
	switch (kf->so_family) {
225
	case AF_INET:
226
		p->nif_family = AF_INET;
227
		p->nif_laddr.s_addr = kf->inp_laddru[0];
228
		p->nif_faddr.s_addr = kf->inp_faddru[0];
229
		break;
230
	case AF_INET6:
231
		p->nif_family = AF_INET6;
232
		p->nif_laddr6.s6_addr32[0] = kf->inp_laddru[0];
233
		p->nif_laddr6.s6_addr32[1] = kf->inp_laddru[1];
234
		p->nif_laddr6.s6_addr32[2] = kf->inp_laddru[2];
235
		p->nif_laddr6.s6_addr32[3] = kf->inp_laddru[3];
236
		p->nif_faddr6.s6_addr32[0] = kf->inp_faddru[0];
237
		p->nif_faddr6.s6_addr32[1] = kf->inp_faddru[1];
238
		p->nif_faddr6.s6_addr32[2] = kf->inp_faddru[2];
239
		p->nif_faddr6.s6_addr32[3] = kf->inp_faddru[3];
240
		break;
241
	}
242
243
	p->nif_rcvcc = kf->so_rcv_cc;
244
	p->nif_sndcc = kf->so_snd_cc;
245
	p->nif_state = kf->t_state;
246
#undef s6_addr32
247
}
248
249
250
/* netstat callback functions */
251
252
int
253
select_ns(void)
254
{
255
	num_disp = num_ns;
256
	return (0);
257
}
258
259
static int type_map[] = { -1, 2, 3, 1, 4, 5 };
260
261
static int
262
kf_comp(const void *a, const void *b)
263
{
264
	const struct kinfo_file *ka = a, *kb = b;
265
266
	if (ka->so_family != kb->so_family) {
267
		/* AF_INET < AF_INET6 < AF_LOCAL */
268
		if (ka->so_family == AF_INET)
269
			return (-1);
270
		if (ka->so_family == AF_LOCAL)
271
			return (1);
272
		if (kb->so_family == AF_LOCAL)
273
			return (-1);
274
		return (1);
275
	}
276
	if (ka->so_family == AF_LOCAL) {
277
		if (type_map[ka->so_type] < type_map[kb->so_type])
278
			return (-1);
279
		if (type_map[ka->so_type] > type_map[kb->so_type])
280
			return (1);
281
	} else if (ka->so_family == AF_INET || ka->so_family == AF_INET6) {
282
		if (ka->so_protocol < kb->so_protocol)
283
			return (-1);
284
		if (ka->so_protocol > kb->so_protocol)
285
			return (1);
286
		if (ka->so_type == SOCK_DGRAM || ka->so_type == SOCK_STREAM) {
287
			/* order sockets by remote port desc */
288
			if (ka->inp_fport > kb->inp_fport)
289
				return (-1);
290
			if (ka->inp_fport < kb->inp_fport)
291
				return (1);
292
		} else if (ka->so_type == SOCK_RAW) {
293
			if (ka->inp_proto > kb->inp_proto)
294
				return (-1);
295
			if (ka->inp_proto < kb->inp_proto)
296
				return (1);
297
		}
298
	}
299
	return (0);
300
}
301
302
303
int
304
read_ns(void)
305
{
306
	struct kinfo_file *kf;
307
	int i, fcnt;
308
309
	if (kd == NULL) {
310
		error("Failed to initialize KVM!");
311
		return (0);
312
	}
313
	kf = kvm_getfiles(kd, KERN_FILE_BYFILE, DTYPE_SOCKET,
314
	    sizeof(*kf), &fcnt);
315
	if (kf == NULL) {
316
		error("Out of Memory!");
317
		return (0);
318
	}
319
320
	/* sort sockets by AF, proto and type */
321
	qsort(kf, fcnt, sizeof(*kf), kf_comp);
322
323
	num_ns = 0;
324
325
	for (i = 0; i < fcnt; i++)
326
		enter(&kf[i]);
327
328
	num_disp = num_ns;
329
	return 0;
330
}
331
332
void
333
print_ns(void)
334
{
335
	int n, count = 0;
336
337
	for (n = dispstart; n < num_disp; n++) {
338
		shownetstat(netinfos + n);
339
		count++;
340
		if (maxprint > 0 && count >= maxprint)
341
			break;
342
	}
343
}
344
345
346
int
347
initnetstat(void)
348
{
349
	field_view *v;
350
351
	protos = TCP|UDP|OTHER;
352
	for (v = views_ns; v->name != NULL; v++)
353
		add_view(v);
354
355
	return(1);
356
}
357
358
static void
359
shownetstat(struct netinfo *p)
360
{
361
	char *proto = NULL;
362
363
	switch (p->nif_proto) {
364
	case IPPROTO_TCP:
365
		proto = "tcp";
366
		break;
367
	case IPPROTO_UDP:
368
		proto = "udp";
369
		break;
370
	}
371
372
	switch (p->nif_family) {
373
	case AF_INET:
374
		inetprint(&p->nif_laddr, p->nif_lport,
375
			  proto, FLD_NS_LOCAL);
376
		inetprint(&p->nif_faddr, p->nif_fport,
377
			  proto, FLD_NS_FOREIGN);
378
		break;
379
	case AF_INET6:
380
		inet6print(&p->nif_laddr6, p->nif_lport,
381
			   proto, FLD_NS_LOCAL);
382
		inet6print(&p->nif_faddr6, p->nif_fport,
383
			   proto, FLD_NS_FOREIGN);
384
		break;
385
	}
386
387
	tb_start();
388
	switch (p->nif_proto) {
389
	case IPPROTO_TCP:
390
	case IPPROTO_UDP:
391
		tbprintf(proto);
392
		if (p->nif_family == AF_INET6)
393
			tbprintf("6");
394
		break;
395
	case IPPROTO_DIVERT:
396
		tbprintf("divert");
397
		if (p->nif_family == AF_INET6)
398
			tbprintf("6");
399
		break;
400
	default:
401
		tbprintf("%d", p->nif_ipproto);
402
		break;
403
	}
404
405
	print_fld_tb(FLD_NS_PROTO);
406
407
	print_fld_size(FLD_NS_RECV_Q, p->nif_rcvcc);
408
	print_fld_size(FLD_NS_SEND_Q, p->nif_sndcc);
409
410
	if (p->nif_proto == IPPROTO_TCP) {
411
		if (p->nif_state < 0 || p->nif_state >= TCP_NSTATES)
412
			print_fld_uint(FLD_NS_STATE, p->nif_state);
413
		else
414
			print_fld_str(FLD_NS_STATE, tcpstates[p->nif_state]);
415
	}
416
	end_line();
417
}
418
419
/*
420
 * Pretty print an Internet address (net address + port).
421
 * If the nflag was specified, use numbers instead of names.
422
 */
423
static void
424
inetprint(struct in_addr *in, int port, char *proto, field_def *fld)
425
{
426
	struct servent *sp = 0;
427
428
	tb_start();
429
	tbprintf("%s", inetname(*in));
430
431
	if (!nflag && port)
432
		sp = getservbyport(port, proto);
433
	if (sp || port == 0)
434
		tbprintf(":%s", sp ? sp->s_name : "*");
435
	else
436
		tbprintf(":%d", ntohs((u_short)port));
437
438
	print_fld_tb(fld);
439
}
440
441
static void
442
inet6print(struct in6_addr *in6, int port, char *proto, field_def *fld)
443
{
444
	struct servent *sp = 0;
445
446
	tb_start();
447
448
	tbprintf("%s", inet6name(in6));
449
	if (!nflag && port)
450
		sp = getservbyport(port, proto);
451
	if (sp || port == 0)
452
		tbprintf(":%s", sp ? sp->s_name : "*");
453
	else
454
		tbprintf(":%d", ntohs((u_short)port));
455
456
	print_fld_tb(fld);
457
}
458
459
int
460
ns_keyboard_callback(int ch)
461
{
462
	switch (ch) {
463
	case 'a':
464
		aflag = !aflag;
465
		gotsig_alarm = 1;
466
		break;
467
	case 'n':
468
		nflag = !nflag;
469
		gotsig_alarm = 1;
470
		break;
471
	case 'o':
472
		protos ^= OTHER;
473
		gotsig_alarm = 1;
474
		break;
475
	case 'r':
476
		aflag = 0;
477
		nflag = 1;
478
		protos = TCP|UDP;
479
		gotsig_alarm = 1;
480
		break;
481
	case 't':
482
		protos ^= TCP;
483
		gotsig_alarm = 1;
484
		break;
485
	case 'u':
486
		protos ^= UDP;
487
		gotsig_alarm = 1;
488
		break;
489
	default:
490
		return keyboard_callback(ch);
491
	};
492
493
	return 1;
494
}
495