1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
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
33
34/*
35 * Common network command support routines.
36 */
37#include <sys/param.h>
38#include <sys/queue.h>
39#include <sys/socket.h>
40#include <sys/socketvar.h>
41#include <sys/protosw.h>
42
43#include <net/route.h>
44#include <netinet/in.h>
45#include <netinet/in_systm.h>
46#include <netinet/ip.h>
47#include <netinet/in_pcb.h>
48#include <arpa/inet.h>
49
50#include <ctype.h>
51#include <netdb.h>
52#include <stdlib.h>
53#include <string.h>
54
55#include "systat.h"
56#include "extern.h"
57
58#define	streq(a,b)	(strcmp(a,b)==0)
59
60static	struct hitem {
61	struct	in_addr addr;
62	int	onoff;
63} *hosts;
64
65int nports, nhosts, protos;
66
67static void changeitems(const char *, int);
68static int selectproto(const char *);
69static void showprotos(void);
70static int selectport(long, int);
71static void showports(void);
72static int selecthost(struct in_addr *, int);
73static void showhosts(void);
74
75int
76netcmd(const char *cmd, const char *args)
77{
78
79	if (prefix(cmd, "proto")) {
80		if (*args == '\0') {
81			move(CMDLINE, 0);
82			clrtoeol();
83			addstr("which proto?");
84		} else if (!selectproto(args)) {
85			error("%s: Unknown protocol.", args);
86		}
87		return (1);
88	}
89	if (prefix(cmd, "ignore") || prefix(cmd, "display")) {
90		changeitems(args, prefix(cmd, "display"));
91		return (1);
92	}
93	if (prefix(cmd, "reset")) {
94		selectproto(0);
95		selecthost(0, 0);
96		selectport(-1, 0);
97		return (1);
98	}
99	if (prefix(cmd, "show")) {
100		move(CMDLINE, 0); clrtoeol();
101		if (*args == '\0') {
102			showprotos();
103			showhosts();
104			showports();
105			return (1);
106		}
107		if (prefix(args, "protos"))
108			showprotos();
109		else if (prefix(args, "hosts"))
110			showhosts();
111		else if (prefix(args, "ports"))
112			showports();
113		else
114			addstr("show what?");
115		return (1);
116	}
117	return (0);
118}
119
120static void
121changeitems(const char *args, int onoff)
122{
123	char *cp, *tmpstr, *tmpstr1;
124	struct servent *sp;
125	struct hostent *hp;
126	struct in_addr in;
127
128	tmpstr = tmpstr1 = strdup(args);
129	cp = strchr(tmpstr1, '\n');
130	if (cp)
131		*cp = '\0';
132	for (;;tmpstr1 = cp) {
133		for (cp = tmpstr1; *cp && isspace(*cp); cp++)
134			;
135		tmpstr1 = cp;
136		for (; *cp && !isspace(*cp); cp++)
137			;
138		if (*cp)
139			*cp++ = '\0';
140		if (cp - tmpstr1 == 0)
141			break;
142		sp = getservbyname(tmpstr1,
143		    protos == TCP ? "tcp" : protos == UDP ? "udp" : 0);
144		if (sp) {
145			selectport(sp->s_port, onoff);
146			continue;
147		}
148		hp = gethostbyname(tmpstr1);
149		if (hp == NULL) {
150			in.s_addr = inet_addr(tmpstr1);
151			if (in.s_addr == INADDR_NONE) {
152				error("%s: unknown host or port", tmpstr1);
153				continue;
154			}
155		} else
156			in = *(struct in_addr *)hp->h_addr;
157		selecthost(&in, onoff);
158	}
159	free(tmpstr);
160}
161
162static int
163selectproto(const char *proto)
164{
165
166	if (proto == NULL || streq(proto, "all"))
167		protos = TCP | UDP;
168	else if (streq(proto, "tcp"))
169		protos = TCP;
170	else if (streq(proto, "udp"))
171		protos = UDP;
172	else
173		return (0);
174
175	return (protos);
176}
177
178static void
179showprotos(void)
180{
181
182	if ((protos&TCP) == 0)
183		addch('!');
184	addstr("tcp ");
185	if ((protos&UDP) == 0)
186		addch('!');
187	addstr("udp ");
188}
189
190static	struct pitem {
191	long	port;
192	int	onoff;
193} *ports;
194
195static int
196selectport(long port, int onoff)
197{
198	struct pitem *p;
199
200	if (port == -1) {
201		if (ports == NULL)
202			return (0);
203		free((char *)ports), ports = 0;
204		nports = 0;
205		return (1);
206	}
207	for (p = ports; p < ports + nports; p++)
208		if (p->port == port) {
209			p->onoff = onoff;
210			return (0);
211		}
212	if (nports == 0)
213		ports = (struct pitem *)malloc(sizeof (*p));
214	else
215		ports = (struct pitem *)realloc(ports, (nports+1)*sizeof (*p));
216	p = &ports[nports++];
217	p->port = port;
218	p->onoff = onoff;
219	return (1);
220}
221
222int
223checkport(struct in_conninfo *inc)
224{
225	struct pitem *p;
226
227	if (ports)
228	for (p = ports; p < ports+nports; p++)
229		if (p->port == inc->inc_lport || p->port == inc->inc_fport)
230			return (p->onoff);
231	return (1);
232}
233
234static void
235showports(void)
236{
237	struct pitem *p;
238	struct servent *sp;
239
240	for (p = ports; p < ports+nports; p++) {
241		sp = getservbyport(p->port,
242		    protos == (TCP|UDP) ? 0 : protos == TCP ? "tcp" : "udp");
243		if (!p->onoff)
244			addch('!');
245		if (sp)
246			printw("%s ", sp->s_name);
247		else
248			printw("%d ", p->port);
249	}
250}
251
252static int
253selecthost(struct in_addr *in, int onoff)
254{
255	struct hitem *p;
256
257	if (in == NULL) {
258		if (hosts == NULL)
259			return (0);
260		free((char *)hosts), hosts = 0;
261		nhosts = 0;
262		return (1);
263	}
264	for (p = hosts; p < hosts+nhosts; p++)
265		if (p->addr.s_addr == in->s_addr) {
266			p->onoff = onoff;
267			return (0);
268		}
269	if (nhosts == 0)
270		hosts = (struct hitem *)malloc(sizeof (*p));
271	else
272		hosts = (struct hitem *)realloc(hosts, (nhosts+1)*sizeof (*p));
273	p = &hosts[nhosts++];
274	p->addr = *in;
275	p->onoff = onoff;
276	return (1);
277}
278
279int
280checkhost(struct in_conninfo *inc)
281{
282	struct hitem *p;
283
284	if (hosts)
285	for (p = hosts; p < hosts+nhosts; p++)
286		if (p->addr.s_addr == inc->inc_laddr.s_addr ||
287		    p->addr.s_addr == inc->inc_faddr.s_addr)
288			return (p->onoff);
289	return (1);
290}
291
292static void
293showhosts(void)
294{
295	struct hitem *p;
296	struct hostent *hp;
297
298	for (p = hosts; p < hosts+nhosts; p++) {
299		hp = gethostbyaddr((char *)&p->addr, sizeof (p->addr), AF_INET);
300		if (!p->onoff)
301			addch('!');
302		printw("%s ", hp ? hp->h_name : (char *)inet_ntoa(p->addr));
303	}
304}
305