xref: /freebsd/usr.bin/systat/netcmds.c (revision 4b9d6057)
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 
60 static	struct hitem {
61 	struct	in_addr addr;
62 	int	onoff;
63 } *hosts;
64 
65 int nports, nhosts, protos;
66 
67 static void changeitems(const char *, int);
68 static int selectproto(const char *);
69 static void showprotos(void);
70 static int selectport(long, int);
71 static void showports(void);
72 static int selecthost(struct in_addr *, int);
73 static void showhosts(void);
74 
75 int
76 netcmd(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 
120 static void
121 changeitems(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 
162 static int
163 selectproto(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 
178 static void
179 showprotos(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 
190 static	struct pitem {
191 	long	port;
192 	int	onoff;
193 } *ports;
194 
195 static int
196 selectport(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 
222 int
223 checkport(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 
234 static void
235 showports(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 
252 static int
253 selecthost(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 
279 int
280 checkhost(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 
292 static void
293 showhosts(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