1  /*-
2  * Copyright (c) 2001 Hellmuth Michaelis. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  *---------------------------------------------------------------------------
26  *
27  *	nifmon - main
28  *	-------------
29  *
30  *      last edit-date: [Wed May  2 16:32:52 2001]
31  *
32  *---------------------------------------------------------------------------*/
33 
34 #define MAIN
35 #include "nifmon.h"
36 #undef MAIN
37 
38 static pid_t pid;
39 
40 /*---------------------------------------------------------------------------
41  *	Display usage and exit
42  *---------------------------------------------------------------------------*/
43 static void
usage()44 usage()
45 {
46 	fprintf(stderr, "\n");
47 	fprintf(stderr, "nifmon -b -e <expr> -i <if> -r <tty> -t <termtype> (V%d.%d)\n", VERSION, RELEASE);
48 	fprintf(stderr, "       -b        run in background [needs -r and -t]\n");
49 	fprintf(stderr, "       -e <expr> tcpdump expression\n");
50 	fprintf(stderr, "       -i <if>   monitor interface <if>, default lo0\n");
51 	fprintf(stderr, "       -r <tty>  redirect output to device <tty>\n");
52 	fprintf(stderr, "       -t <term> terminal type for device <tty>\n");
53 	exit(1);
54 }
55 
56 /*---------------------------------------------------------------------------
57  *	Parse command line, startup monitor client
58  *---------------------------------------------------------------------------*/
59 int
main(int argc,char ** argv)60 main(int argc, char **argv)
61 {
62 	int i;
63 	char *netif = "lo0";
64 	char *expression = "";
65 
66 	while ((i = getopt(argc, argv, "be:i:r:t:")) != -1)
67 	{
68 		switch (i)
69 		{
70 			case 'b':
71 				background = 1;
72 				break;
73 
74 			case 'e':
75 				expression = optarg;
76 				break;
77 
78 			case 'i':
79 				netif = optarg;
80 				break;
81 
82 			case 'r':
83 				rdev = optarg;
84 				has_rdev = 1;
85 				break;
86 
87 			case 't':
88 				term = optarg;
89 				has_term = 1;
90 				break;
91 			default:
92 				usage();
93 				break;
94 		}
95 	}
96 
97 	if (background)
98 	{
99 		if (has_rdev == 0 || has_term == 0)
100 		{
101 			fprintf(stderr, "-b option needs both -t and -r!\n");
102 			exit(1);
103 		}
104 	}
105 
106 	/* only root is able to open /dev/bpfN */
107 
108 	if (getuid() != 0)
109 	{
110 		fprintf(stderr,
111 			"You must be superuser (root) to run this program\n");
112 		exit(1);
113 	}
114 
115 	sprintf(pidfile, "%s-%s%s", PIDFIL, netif, PIDPID);
116 
117 	if (background)
118 	{
119 		check_pid(pidfile);
120 		daemonize();
121 		write_pid(pidfile);
122 	}
123 
124 	signal(SIGHUP,  do_exit);
125 	signal(SIGINT,  do_exit);
126 	signal(SIGQUIT, do_exit);
127 	signal(SIGTERM, do_exit);
128 	signal(SIGUSR1, do_exit);
129 	signal(SIGUSR2, do_exit);
130 
131 	init_interface(netif);
132 
133 	init_screen(netif);
134 
135 	pfp = mpopen(netif, expression);
136 
137 	if (pfp == NULL)
138 	{
139 		perror("mpopen");
140 		do_exit(1);
141 	}
142 
143 	for (;;)
144 	{
145 		fd_set set;
146 		struct timeval timeout;
147 		int ret;
148 		int high_selfd;
149 
150 		FD_ZERO(&set);
151 
152 		FD_SET(fileno(stdin), &set);
153 		high_selfd = fileno(stdin);
154 
155 		FD_SET(fileno(pfp), &set);
156 		high_selfd = fileno(pfp);
157 
158 		timeout.tv_sec = 1;
159 		timeout.tv_usec = 0;
160 
161 		ret = select(high_selfd + 1, &set, NULL, NULL, &timeout);
162 
163 		if (ret > 0)
164 		{
165 			if (FD_ISSET(fileno(stdin), &set))
166 				kbdrdhdl();
167 
168 			if (FD_ISSET(fileno(pfp), &set))
169 				loghdl(pfp);
170 		}
171 		update_interface(netif);
172 	}
173 }
174 
175 /*---------------------------------------------------------------------------*
176  *	program exit
177  *---------------------------------------------------------------------------*/
178 void
do_exit(int exitval)179 do_exit(int exitval)
180 {
181 	mpclose(pfp);
182 	if (curses_ready)
183 		endwin();
184 	unlink(pidfile);
185 	exit(exitval);
186 }
187 
188 /*---------------------------------------------------------------------------*
189  *	open pipe to tcpdump
190  *---------------------------------------------------------------------------*/
191 FILE *
mpopen(char * interface,char * expression)192 mpopen(char *interface, char *expression)
193 {
194 	FILE *fp;
195 	int pdes[2];
196 	char *argv[5];
197 
198 	if (pipe(pdes) < 0)
199 		return (NULL);
200 
201 	argv[0] = TCPDUMP;
202 	argv[1] = TCPDUMPFLAGS;
203 	argv[2] = interface;
204 	argv[3] = expression;
205 	argv[4] = NULL;
206 
207 	switch (pid = vfork())
208 	{
209 		case -1:	/* Error. */
210 			(void) close(pdes[0]);
211 			(void) close(pdes[1]);
212 			return (NULL);
213 
214 		case 0:	/* Child. */
215 			(void) close(pdes[0]);
216 
217 			if (pdes[1] != STDOUT_FILENO)
218 			{
219 				(void) dup2(pdes[1], STDOUT_FILENO);
220 				(void) close(pdes[1]);
221 			}
222 /*XXX*/			close(STDERR_FILENO);
223 
224 			execv(TCPDUMPPATH, argv);
225 			_exit(127);
226 	}
227 
228 	/* Parent */
229 
230 	fp = fdopen(pdes[0], "r");
231 	(void) close(pdes[1]);
232 
233 	return (fp);
234 }
235 
236 /*---------------------------------------------------------------------------*
237  *	close pipe and terminate tcpdump
238  *---------------------------------------------------------------------------*/
239 int
mpclose(FILE * fp)240 mpclose(FILE * fp)
241 {
242 	int pstat;
243 	pid_t mpid;
244 
245 	(void) fclose(fp);
246 
247 	kill(pid, SIGTERM);
248 
249 	do
250 	{
251 		mpid = wait4(pid, &pstat, 0, (struct rusage *) 0);
252 	}
253 	while (mpid == -1 && errno == EINTR);
254 
255 	return (mpid == -1 ? -1 : pstat);
256 }
257