1/*	$NetBSD: netcmds.c,v 1.24 2022/10/28 05:27:17 ozaki-r Exp $	*/
2
3/*-
4 * Copyright (c) 1980, 1992, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33#ifndef lint
34#if 0
35static char sccsid[] = "@(#)netcmds.c	8.1 (Berkeley) 6/6/93";
36#endif
37__RCSID("$NetBSD: netcmds.c,v 1.24 2022/10/28 05:27:17 ozaki-r Exp $");
38#endif /* not lint */
39
40/*
41 * Common network command support routines.
42 */
43#include <sys/param.h>
44#include <sys/mbuf.h>
45#include <sys/protosw.h>
46
47#include <net/route.h>
48#include <netinet/in.h>
49#include <netinet/in_systm.h>
50#include <netinet/ip.h>
51#include <netinet/in_pcb.h>
52#ifdef INET6
53#include <netinet/ip6.h>
54#include <netinet6/in6_pcb.h>
55#endif
56
57#include <arpa/inet.h>
58
59#include <ctype.h>
60#include <netdb.h>
61#include <stdlib.h>
62#include <string.h>
63
64#include "systat.h"
65#include "extern.h"
66
67#define	streq(a,b)	(strcmp(a,b)==0)
68
69static	struct hitem {
70	struct	sockaddr_storage addr;
71	int	onoff;
72} *hosts = NULL;
73
74int nports, nhosts, protos;
75
76static void changeitems(char *, int);
77static void selectproto(const char *);
78static void showprotos(void);
79static int selectport(long, int);
80static void showports(void);
81static int addrcmp(struct sockaddr *, struct sockaddr *);
82static int selecthost(struct sockaddr *, int);
83static void showhosts(void);
84
85/* please note: there are also some netstat commands in netstat.c */
86
87void
88netstat_display(char *args)
89{
90	changeitems(args, 1);
91}
92
93void
94netstat_ignore(char *args)
95{
96	changeitems(args, 0);
97}
98
99void
100netstat_reset(char *args)
101{
102	selectproto(0);
103	selecthost(0, 0);
104	selectport(-1, 0);
105}
106
107void
108netstat_show(char *args)
109{
110	move(CMDLINE, 0); clrtoeol();
111	if (!args || *args == '\0') {
112		showprotos();
113		showhosts();
114		showports();
115		return;
116	}
117	if (strstr(args, "protos") == args)
118		showprotos();
119	else if (strstr(args, "hosts") == args)
120		showhosts();
121	else if (strstr(args, "ports") == args)
122		showports();
123	else
124		addstr("show what?");
125}
126
127void
128netstat_tcp(char *args)
129{
130	selectproto("tcp");
131}
132
133void
134netstat_udp(char *args)
135{
136	selectproto("udp");
137}
138
139static void
140changeitems(char *args, int onoff)
141{
142	char *cp;
143	struct servent *sp;
144	struct addrinfo hints, *res, *res0;
145
146	cp = strchr(args, '\n');
147	if (cp)
148		*cp = '\0';
149	for (;;args = cp) {
150		for (cp = args; *cp && isspace((unsigned char)*cp); cp++)
151			;
152		args = cp;
153		for (; *cp && !isspace((unsigned char)*cp); cp++)
154			;
155		if (*cp)
156			*cp++ = '\0';
157		if (cp - args == 0)
158			break;
159		sp = getservbyname(args,
160		    protos == TCP ? "tcp" : protos == UDP ? "udp" : 0);
161		if (sp) {
162			selectport(sp->s_port, onoff);
163			continue;
164		}
165
166		memset(&hints, 0, sizeof(hints));
167		hints.ai_family = PF_UNSPEC;
168		hints.ai_socktype = SOCK_DGRAM;
169		if (getaddrinfo(args, "0", &hints, &res0) != 0) {
170			error("%s: unknown host or port", args);
171			continue;
172		}
173		for (res = res0; res; res = res->ai_next)
174			selecthost(res->ai_addr, onoff);
175		freeaddrinfo(res0);
176	}
177}
178
179static void
180selectproto(const char *proto)
181{
182
183	if (proto == 0 || streq(proto, "all"))
184		protos = TCP|UDP;
185	else if (streq(proto, "tcp"))
186		protos = TCP;
187	else if (streq(proto, "udp"))
188		protos = UDP;
189}
190
191static void
192showprotos(void)
193{
194
195	if ((protos & TCP) == 0)
196		addch('!');
197	addstr("tcp ");
198	if ((protos & UDP) == 0)
199		addch('!');
200	addstr("udp ");
201}
202
203static	struct pitem {
204	long	port;
205	int	onoff;
206} *ports = NULL;
207
208static int
209selectport(long port, int onoff)
210{
211	struct pitem *p;
212
213	if (port == -1) {
214		if (ports == NULL)
215			return (0);
216		free(ports);
217		ports = NULL;
218		nports = 0;
219		return (1);
220	}
221	for (p = ports; p < ports+nports; p++)
222		if (p->port == port) {
223			p->onoff = onoff;
224			return (0);
225		}
226	if (reallocarr(&ports, nports + 1, sizeof(*p)) != 0) {
227		error("malloc failed");
228		die(0);
229	}
230	p = &ports[nports++];
231	p->port = port;
232	p->onoff = onoff;
233	return (1);
234}
235
236int
237checkport(struct inpcb *inp)
238{
239	struct pitem *p;
240
241	if (ports)
242	for (p = ports; p < ports+nports; p++)
243		if (p->port == inp->inp_lport || p->port == inp->inp_fport)
244			return (p->onoff);
245	return (1);
246}
247
248static void
249showports(void)
250{
251	struct pitem *p;
252	struct servent *sp;
253
254	for (p = ports; p < ports+nports; p++) {
255		sp = getservbyport(p->port,
256		    protos == (TCP|UDP) ? 0 : protos == TCP ? "tcp" : "udp");
257		if (!p->onoff)
258			addch('!');
259		if (sp)
260			printw("%s ", sp->s_name);
261		else
262			printw("%ld ", p->port);
263	}
264}
265
266static int
267addrcmp(struct sockaddr *sa1, struct sockaddr *sa2)
268{
269	if (sa1->sa_family != sa2->sa_family)
270		return 0;
271	if (sa1->sa_len != sa2->sa_len)
272		return 0;
273	switch (sa1->sa_family) {
274	case AF_INET:
275		if (((struct sockaddr_in *)sa1)->sin_addr.s_addr ==
276				((struct sockaddr_in *)sa2)->sin_addr.s_addr)
277			return 1;
278		break;
279#ifdef INET6
280	case AF_INET6:
281		if (IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)sa1)->sin6_addr,
282				&((struct sockaddr_in6 *)sa2)->sin6_addr))
283			return 1;
284		break;
285#endif
286	default:
287		if (memcmp(sa1, sa2, sa1->sa_len) == 0)
288			return 1;
289		break;
290	}
291	return 0;
292}
293
294static int
295selecthost(struct sockaddr *sa, int onoff)
296{
297	struct hitem *p;
298
299	if (sa == 0) {
300		if (hosts == 0)
301			return (0);
302		free((char *)hosts), hosts = 0;
303		nhosts = 0;
304		return (1);
305	}
306	for (p = hosts; p < hosts+nhosts; p++)
307		if (addrcmp((struct sockaddr *)&p->addr, sa)) {
308			p->onoff = onoff;
309			return (0);
310		}
311	if (sa->sa_len > sizeof(struct sockaddr_storage))
312		return (-1);	/*XXX*/
313	if (reallocarr(&hosts, nhosts + 1, sizeof(*p)) != 0) {
314		error("malloc failed");
315		die(0);
316	}
317	p = &hosts[nhosts++];
318	memcpy(&p->addr, sa, sa->sa_len);
319	p->onoff = onoff;
320	return (1);
321}
322
323int
324checkhost(struct inpcb *inp)
325{
326	struct hitem *p;
327	struct sockaddr_in *s_in;
328
329	if (hosts)
330		for (p = hosts; p < hosts+nhosts; p++) {
331			if (((struct sockaddr *)&p->addr)->sa_family != AF_INET)
332				continue;
333			s_in = (struct sockaddr_in *)&p->addr;
334			if (s_in->sin_addr.s_addr == in4p_laddr(inp).s_addr ||
335			    s_in->sin_addr.s_addr == in4p_faddr(inp).s_addr)
336				return (p->onoff);
337		}
338	return (1);
339}
340
341#ifdef INET6
342int
343checkhost6(struct inpcb *inp)
344{
345	struct hitem *p;
346	struct sockaddr_in6 *sin6;
347
348	if (hosts)
349		for (p = hosts; p < hosts+nhosts; p++) {
350			if (((struct sockaddr *)&p->addr)->sa_family != AF_INET6)
351				continue;
352			sin6 = (struct sockaddr_in6 *)&p->addr;
353			if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &in6p_laddr(inp)) ||
354			    IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &in6p_faddr(inp)))
355				return (p->onoff);
356		}
357	return (1);
358}
359#endif
360
361static void
362showhosts(void)
363{
364	struct hitem *p;
365	char hbuf[NI_MAXHOST];
366	struct sockaddr *sa;
367	int flags;
368
369#if 0
370	flags = nflag ? NI_NUMERICHOST : 0;
371#else
372	flags = 0;
373#endif
374	for (p = hosts; p < hosts+nhosts; p++) {
375		sa = (struct sockaddr *)&p->addr;
376		if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0,
377				flags) != 0)
378			strlcpy(hbuf, "(invalid)", sizeof(hbuf));
379		if (!p->onoff)
380			addch('!');
381		printw("%s ", hbuf);
382	}
383}
384