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