Add a new global flag "capture_child", which is TRUE if we're a child
[obnox/wireshark/wip.git] / capture.c
1 /* capture.c
2  * Routines for packet capture windows
3  *
4  * $Id: capture.c,v 1.74 1999/09/30 06:49:53 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #ifdef HAVE_LIBPCAP
32
33 #ifdef HAVE_SYS_TYPES_H
34 # include <sys/types.h>
35 #endif
36
37 #ifdef HAVE_SYS_STAT_H
38 # include <sys/stat.h>
39 #endif
40
41 #include <gtk/gtk.h>
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <ctype.h>
45 #include <string.h>
46
47 #ifdef HAVE_UNISTD_H
48 #include <unistd.h>
49 #endif
50
51 #include <time.h>
52
53 #ifdef HAVE_SYS_SOCKET_H
54 #include <sys/socket.h>
55 #endif
56
57 #ifdef HAVE_SYS_IOCTL_H
58 #include <sys/ioctl.h>
59 #endif
60
61 #ifdef HAVE_NET_IF_H
62 #include <net/if.h>
63 #endif
64
65 #include <signal.h>
66 #include <errno.h>
67
68 #ifdef NEED_SNPRINTF_H
69 # ifdef HAVE_STDARG_H
70 #  include <stdarg.h>
71 # else
72 #  include <varargs.h>
73 # endif
74 # include "snprintf.h"
75 #endif
76
77 #include "gtk/main.h"
78 #include "packet.h"
79 #include "file.h"
80 #include "gtk/menu.h"
81 #include "capture.h"
82 #include "util.h"
83 #include "prefs.h"
84 #include "globals.h"
85
86 static void capture_stop_cb(GtkWidget *, gpointer);
87 static void capture_pcap_cb(u_char *, const struct pcap_pkthdr *,
88   const u_char *);
89 static float pct(gint, gint);
90
91 typedef struct _loop_data {
92   gint           go;
93   gint           max;
94   gint           linktype;
95   gint           sync_packets;
96   packet_counts  counts;
97   wtap_dumper   *pdh;
98 } loop_data;
99
100 /* Create a temporary file and start a capture to it. */
101 void
102 do_capture(void)
103 {
104   char tmpname[128+1];
105
106   /* Choose a random name for the capture buffer */
107   cf.save_file_fd = create_tempfile(tmpname, sizeof tmpname, "ether");
108   if (cf.save_file_fd == -1) {
109     simple_dialog(ESD_TYPE_WARN, NULL,
110         "The file to which the capture would be saved (\"%s\")"
111         "could not be opened: %s.", tmpname, strerror(errno));
112     return;
113   }
114   close_cap_file(&cf, info_bar, file_ctx);
115   if (cf.save_file != NULL) {
116     /* If the current file is a temporary capture file, remove it. */
117     if (!cf.user_saved)
118       unlink(cf.save_file); /* silently ignore error */
119     g_free(cf.save_file);
120   }
121   cf.save_file = g_strdup(tmpname);
122   cf.user_saved = 0;
123
124   run_capture();
125 }
126
127 /* Start a capture to a file we've opened; "cf.save_file" is the
128    pathname of the file, and "cf.save_file_fd" is the file descriptor
129    we got when we opened it. */
130 void
131 run_capture(void)
132
133   u_char c;
134   int i;
135   guint byte_count;
136   char *msg;
137
138   if (sync_mode || fork_mode) { /*  use fork() for capture */
139     int  fork_child;
140     char ssnap[24];
141     char scount[24];    /* need a constant for len of numbers */
142     char save_file_fd[24];
143     int err;
144
145     sprintf(ssnap,"%d",cf.snap); /* in lieu of itoa */
146     sprintf(scount,"%d",cf.count);
147     sprintf(save_file_fd,"%d",cf.save_file_fd);
148     signal(SIGCHLD, SIG_IGN);
149     if (sync_mode)
150       pipe(sync_pipe);
151     if ((fork_child = fork()) == 0) {
152       /* args: -k -- capture
153        * -i interface specification
154        * -w file to write
155        * -W file descriptor to write
156        * -c count to capture
157        * -Q quit after capture (forces -k)
158        * -s snaplen
159        * -S sync mode
160        * -m / -b fonts
161        * -f "filter expression"
162        */
163        if (sync_mode) {
164          close(1);
165          dup(sync_pipe[1]);
166          close(sync_pipe[0]);
167          execlp(ethereal_path, CHILD_NAME, "-k", "-Q", "-i", cf.iface,
168                 "-w", cf.save_file, "-W", save_file_fd,
169                 "-c", scount, "-s", ssnap, "-S", 
170                 "-m", medium_font, "-b", bold_font,
171                 (cf.cfilter == NULL)? 0 : "-f",
172                 (cf.cfilter == NULL)? 0 : cf.cfilter,
173                 (const char *)NULL);    
174        }
175        else {
176          execlp(ethereal_path, CHILD_NAME, "-k", "-Q", "-i", cf.iface,
177                 "-w", cf.save_file, "-W", save_file_fd,
178                 "-c", scount, "-s", ssnap,
179                 "-m", medium_font, "-b", bold_font,
180                 (cf.cfilter == NULL)? 0 : "-f",
181                 (cf.cfilter == NULL)? 0 : cf.cfilter,
182                 (const char *)NULL);
183        }
184     }
185     else {
186        cf.filename = cf.save_file;
187        if (sync_mode) {
188          close(sync_pipe[1]);
189
190          /* Read a byte count from "sync_pipe[0]", terminated with a
191             colon; if the count is 0, the child process created the
192             capture file and we should start reading from it, otherwise
193             the capture couldn't start and the count is a count of bytes
194             of error message, and we should display the message. */
195          byte_count = 0;
196          for (;;) {
197            i = read(sync_pipe[0], &c, 1);
198            if (i == 0) {
199              /* EOF - the child process died.
200                 XXX - reap it and report the status. */
201              simple_dialog(ESD_TYPE_WARN, NULL, "Capture child process died");
202              return;
203            }
204            if (c == ';')
205              break;
206            if (!isdigit(c)) {
207              /* Child process handed us crap. */
208              simple_dialog(ESD_TYPE_WARN, NULL,
209                 "Capture child process sent us a bad message");
210              return;
211            }
212            byte_count = byte_count*10 + c - '0';
213          }
214          if (byte_count == 0) {
215            /* Success. */
216            err = tail_cap_file(cf.save_file, &cf);
217            if (err != 0) {
218              simple_dialog(ESD_TYPE_WARN, NULL,
219                         file_open_error_message(err, FALSE), cf.save_file);
220            }
221          } else {
222            /* Failure. */
223            msg = g_malloc(byte_count + 1);
224            if (msg == NULL) {
225              simple_dialog(ESD_TYPE_WARN, NULL,
226                 "Capture child process failed, but its error message was too big.");
227            } else {
228              i = read(sync_pipe[0], msg, byte_count);
229              if (i < 0) {
230                 simple_dialog(ESD_TYPE_WARN, NULL,
231                   "Capture child process failed: Error %s reading its error message.",
232                   strerror(errno));
233              } else if (i == 0) {
234                 simple_dialog(ESD_TYPE_WARN, NULL,
235                   "Capture child process failed: EOF reading its error message.");
236              } else
237                 simple_dialog(ESD_TYPE_WARN, NULL, msg);
238              g_free(msg);
239            }
240          }
241        }
242     }
243   }
244   else
245     capture();
246 }
247
248 /* Do the low-level work of a capture. */
249 void
250 capture(void)
251 {
252   GtkWidget  *cap_w, *main_vb, *count_lb, *tcp_lb, *udp_lb, *icmp_lb,
253              *ospf_lb, *gre_lb, *netbios_lb, *other_lb, *stop_bt;
254   pcap_t     *pch;
255   gchar       err_str[PCAP_ERRBUF_SIZE], label_str[32];
256   loop_data   ld;
257   bpf_u_int32 netnum, netmask;
258   time_t      upd_time, cur_time;
259   int         err, inpkts;
260   char        errmsg[1024+1];
261
262   ld.go             = TRUE;
263   ld.counts.total   = 0;
264   ld.max            = cf.count;
265   ld.linktype       = WTAP_ENCAP_UNKNOWN;
266   ld.sync_packets   = 0;
267   ld.counts.tcp     = 0;
268   ld.counts.udp     = 0;
269   ld.counts.icmp    = 0;
270   ld.counts.ospf    = 0;
271   ld.counts.gre     = 0;
272   ld.counts.netbios = 0;
273   ld.counts.other   = 0;
274   ld.pdh            = NULL;
275
276   /* Open the network interface to capture from it. */
277   pch = pcap_open_live(cf.iface, cf.snap, 1, 250, err_str);
278
279   if (pch == NULL) {
280     /* Well, we couldn't start the capture.
281        If this is a child process that does the capturing in sync
282        mode or fork mode, it shouldn't do any UI stuff until we pop up the
283        capture-progress window, and, since we couldn't start the
284        capture, we haven't popped it up. */
285     if (!capture_child) {
286       while (gtk_events_pending()) gtk_main_iteration();
287     }
288     snprintf(errmsg, sizeof errmsg,
289       "The capture session could not be initiated (%s).\n"
290       "Please check to make sure you have sufficient permissions, and that\n"
291       "you have the proper interface specified.", err_str);
292     goto error;
293   }
294
295   if (cf.cfilter) {
296     /* A capture filter was specified; set it up. */
297     if (pcap_lookupnet (cf.iface, &netnum, &netmask, err_str) < 0) {
298       snprintf(errmsg, sizeof errmsg,
299         "Can't use filter:  Couldn't obtain netmask info (%s).", err_str);
300       goto error;
301     }
302     if (pcap_compile(pch, &cf.fcode, cf.cfilter, 1, netmask) < 0) {
303       snprintf(errmsg, sizeof errmsg, "Unable to parse filter string (%s).",
304         pcap_geterr(pch));
305       goto error;
306     }
307     if (pcap_setfilter(pch, &cf.fcode) < 0) {
308       snprintf(errmsg, sizeof errmsg, "Can't install filter (%s).",
309         pcap_geterr(pch));
310       goto error;
311     }
312   }
313
314   /* Set up to write to the capture file. */
315   ld.linktype = wtap_pcap_encap_to_wtap_encap(pcap_datalink(pch));
316   if (ld.linktype == WTAP_ENCAP_UNKNOWN) {
317     strcpy(errmsg, "The network you're capturing from is of a type"
318              " that Ethereal doesn't support.");
319     goto error;
320   }
321   ld.pdh = wtap_dump_fdopen(cf.save_file_fd, WTAP_FILE_PCAP,
322                 ld.linktype, pcap_snapshot(pch), &err);
323
324   if (ld.pdh == NULL) {
325     /* We couldn't set up to write to the capture file. */
326     switch (err) {
327
328     case WTAP_ERR_CANT_OPEN:
329       strcpy(errmsg, "The file to which the capture would be saved"
330                " couldn't be created for some unknown reason.");
331       break;
332
333     case WTAP_ERR_SHORT_WRITE:
334       strcpy(errmsg, "A full header couldn't be written to the file"
335                " to which the capture would be saved.");
336       break;
337
338     default:
339       if (err < 0) {
340         sprintf(errmsg, "The file to which the capture would be"
341                      " saved (\"%s\") could not be opened: Error %d.",
342                         cf.save_file, err);
343       } else {
344         sprintf(errmsg, "The file to which the capture would be"
345                      " saved (\"%s\") could not be opened: %s.",
346                         cf.save_file, strerror(err));
347       }
348       break;
349     }
350     goto error;
351   }
352
353   if (capture_child && sync_mode) {
354     /* Well, we should be able to start capturing.
355
356        This is the child process for a sync mode capture, so sync out
357        the capture file, so the header makes it to the file system,
358        and send a "capture started successfully and capture file created"
359        message to our parent so that they'll open the capture file and
360        update its windows to indicate that we have a live capture in
361        progress. */
362     fflush(wtap_dump_file(ld.pdh));
363     write(1, "0;", 2);
364   }
365
366   cap_w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
367   gtk_window_set_title(GTK_WINDOW(cap_w), "Ethereal: Capture / Playback");
368
369   /* Container for capture display widgets */
370   main_vb = gtk_vbox_new(FALSE, 1);
371   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
372   gtk_container_add(GTK_CONTAINER(cap_w), main_vb);
373   gtk_widget_show(main_vb);
374
375   count_lb = gtk_label_new("Count: 0");
376   gtk_box_pack_start(GTK_BOX(main_vb), count_lb, FALSE, FALSE, 3);
377   gtk_widget_show(count_lb);
378
379   tcp_lb = gtk_label_new("TCP: 0 (0.0%)");
380   gtk_box_pack_start(GTK_BOX(main_vb), tcp_lb, FALSE, FALSE, 3);
381   gtk_widget_show(tcp_lb);
382
383   udp_lb = gtk_label_new("UDP: 0 (0.0%)");
384   gtk_box_pack_start(GTK_BOX(main_vb), udp_lb, FALSE, FALSE, 3);
385   gtk_widget_show(udp_lb);
386
387   icmp_lb = gtk_label_new("ICMP: 0 (0.0%)");
388   gtk_box_pack_start(GTK_BOX(main_vb), icmp_lb, FALSE, FALSE, 3);
389   gtk_widget_show(icmp_lb);
390
391   ospf_lb = gtk_label_new("OSPF: 0 (0.0%)");
392   gtk_box_pack_start(GTK_BOX(main_vb), ospf_lb, FALSE, FALSE, 3);
393   gtk_widget_show(ospf_lb);
394
395   gre_lb = gtk_label_new("GRE: 0 (0.0%)");
396   gtk_box_pack_start(GTK_BOX(main_vb), gre_lb, FALSE, FALSE, 3);
397   gtk_widget_show(gre_lb);
398
399   netbios_lb = gtk_label_new("NetBIOS: 0 (0.0%)");
400   gtk_box_pack_start(GTK_BOX(main_vb), netbios_lb, FALSE, FALSE, 3);
401   gtk_widget_show(netbios_lb);
402
403   other_lb = gtk_label_new("Other: 0 (0.0%)");
404   gtk_box_pack_start(GTK_BOX(main_vb), other_lb, FALSE, FALSE, 3);
405   gtk_widget_show(other_lb);
406
407   stop_bt = gtk_button_new_with_label ("Stop");
408   gtk_signal_connect(GTK_OBJECT(stop_bt), "clicked",
409     GTK_SIGNAL_FUNC(capture_stop_cb), (gpointer) &ld);
410   gtk_box_pack_end(GTK_BOX(main_vb), stop_bt, FALSE, FALSE, 3);
411   GTK_WIDGET_SET_FLAGS(stop_bt, GTK_CAN_DEFAULT);
412   gtk_widget_grab_default(stop_bt);
413   GTK_WIDGET_SET_FLAGS(stop_bt, GTK_CAN_DEFAULT);
414   gtk_widget_grab_default(stop_bt);
415   gtk_widget_show(stop_bt);
416
417   gtk_widget_show(cap_w);
418   gtk_grab_add(cap_w);
419
420   upd_time = time(NULL);
421   while (ld.go) {
422     while (gtk_events_pending()) gtk_main_iteration();
423     inpkts = pcap_dispatch(pch, 1, capture_pcap_cb, (u_char *) &ld);
424     if (inpkts > 0)
425       ld.sync_packets += inpkts;
426     /* Only update once a second so as not to overload slow displays */
427     cur_time = time(NULL);
428     if (cur_time > upd_time) {
429       upd_time = cur_time;
430
431       sprintf(label_str, "Count: %d", ld.counts.total);
432       gtk_label_set(GTK_LABEL(count_lb), label_str);
433
434       sprintf(label_str, "TCP: %d (%.1f%%)", ld.counts.tcp,
435                 pct(ld.counts.tcp, ld.counts.total));
436       gtk_label_set(GTK_LABEL(tcp_lb), label_str);
437
438       sprintf(label_str, "UDP: %d (%.1f%%)", ld.counts.udp,
439                 pct(ld.counts.udp, ld.counts.total));
440       gtk_label_set(GTK_LABEL(udp_lb), label_str);
441
442       sprintf(label_str, "ICMP: %d (%.1f%%)", ld.counts.icmp,
443                 pct(ld.counts.icmp, ld.counts.total));
444       gtk_label_set(GTK_LABEL(icmp_lb), label_str);
445
446       sprintf(label_str, "OSPF: %d (%.1f%%)", ld.counts.ospf,
447                 pct(ld.counts.ospf, ld.counts.total));
448       gtk_label_set(GTK_LABEL(ospf_lb), label_str);
449
450       sprintf(label_str, "GRE: %d (%.1f%%)", ld.counts.gre,
451                 pct(ld.counts.gre, ld.counts.total));
452       gtk_label_set(GTK_LABEL(gre_lb), label_str);
453
454       sprintf(label_str, "NetBIOS: %d (%.1f%%)", ld.counts.netbios,
455                 pct(ld.counts.netbios, ld.counts.total));
456       gtk_label_set(GTK_LABEL(netbios_lb), label_str);
457
458       sprintf(label_str, "Other: %d (%.1f%%)", ld.counts.other,
459                 pct(ld.counts.other, ld.counts.total));
460       gtk_label_set(GTK_LABEL(other_lb), label_str);
461
462       /* do sync here, too */
463       fflush(wtap_dump_file(ld.pdh));
464       if (capture_child && sync_mode && ld.sync_packets) {
465         /* This is the child process for a sync mode capture, so send
466            our parent a message saying we've written out "ld.sync_packets"
467            packets to the capture file. */
468         char tmp[20];
469         sprintf(tmp, "%d*", ld.sync_packets);
470         write(1, tmp, strlen(tmp));
471         ld.sync_packets = 0;
472       }
473     }
474   }
475     
476   if (!wtap_dump_close(ld.pdh, &err)) {
477     /* XXX - in fork mode, this may not pop up, or, if it does,
478        it may disappear as soon as we exit.
479
480        We should have the parent process, while it's reading
481        the packet count update messages, catch error messages
482        and pop up a message box if it sees one. */
483     switch (err) {
484
485     case WTAP_ERR_CANT_CLOSE:
486       simple_dialog(ESD_TYPE_WARN, NULL,
487                 "The file to which the capture was being saved"
488                 " couldn't be closed for some unknown reason.");
489       break;
490
491     case WTAP_ERR_SHORT_WRITE:
492       simple_dialog(ESD_TYPE_WARN, NULL,
493                 "Not all the data could be written to the file"
494                 " to which the capture was being saved.");
495       break;
496
497     default:
498       if (err < 0) {
499         simple_dialog(ESD_TYPE_WARN, NULL,
500                 "The file to which the capture was being"
501                 " saved (\"%s\") could not be closed: Error %d.",
502                 cf.save_file, err);
503       } else {
504         simple_dialog(ESD_TYPE_WARN, NULL,
505                 "The file to which the capture was being"
506                 " saved (\"%s\") could not be closed: %s.",
507                 cf.save_file, strerror(err));
508       }
509       break;
510     }
511   }
512   pcap_close(pch);
513
514   gtk_grab_remove(GTK_WIDGET(cap_w));
515   gtk_widget_destroy(GTK_WIDGET(cap_w));
516
517   if (quit_after_cap) {
518     /* DON'T unlink the save file.  Presumably someone wants it. */
519     gtk_exit(0);
520   }
521
522   if ((err = open_cap_file(cf.save_file, &cf)) == 0) {
523     /* Set the read filter to NULL. */
524     cf.rfcode = NULL;
525     err = read_cap_file(&cf);
526     set_menu_sensitivity("/File/Save", TRUE);
527     set_menu_sensitivity("/File/Save As...", FALSE);
528   }
529   return;
530
531 error:
532   /* We couldn't even start the capture, so get rid of the capture
533      file. */
534   unlink(cf.save_file); /* silently ignore error */
535   if (capture_child && sync_mode) {
536     /* This is the child process for a sync mode capture.
537        Send the error message to our parent, so they can display a
538        dialog box containing it. */
539     int msglen = strlen(errmsg);
540     char lenbuf[10+1+1];
541     sprintf(lenbuf, "%u;", msglen);
542     write(1, lenbuf, strlen(lenbuf));
543     write(1, errmsg, msglen);
544   } else {
545     /* Display the dialog box ourselves; there's no parent. */
546     simple_dialog(ESD_TYPE_WARN, NULL, errmsg);
547   }
548   if (pch != NULL)
549     pcap_close(pch);
550
551   if (quit_after_cap)
552     gtk_exit(0);
553 }
554
555 static float
556 pct(gint num, gint denom) {
557   if (denom) {
558     return (float) num * 100.0 / (float) denom;
559   } else {
560     return 0.0;
561   }
562 }
563
564 static void
565 capture_stop_cb(GtkWidget *w, gpointer data) {
566   loop_data *ld = (loop_data *) data;
567   
568   ld->go = FALSE;
569 }
570
571 static void
572 capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
573   const u_char *pd) {
574   struct wtap_pkthdr whdr;
575   loop_data *ld = (loop_data *) user;
576   int err;
577
578   if ((++ld->counts.total >= ld->max) && (ld->max > 0)) 
579   {
580      ld->go = FALSE;
581   }
582   if (ld->pdh) {
583      whdr.ts = phdr->ts;
584      whdr.caplen = phdr->caplen;
585      whdr.len = phdr->len;
586      whdr.pkt_encap = ld->linktype;
587
588      /* XXX - do something if this fails */
589      wtap_dump(ld->pdh, &whdr, pd, &err);
590   }
591     
592   switch (ld->linktype) {
593     case WTAP_ENCAP_ETHERNET:
594       capture_eth(pd, phdr->caplen, &ld->counts);
595       break;
596     case WTAP_ENCAP_FDDI:
597     case WTAP_ENCAP_FDDI_BITSWAPPED:
598       capture_fddi(pd, phdr->caplen, &ld->counts);
599       break;
600     case WTAP_ENCAP_TR:
601       capture_tr(pd, phdr->caplen, &ld->counts);
602       break;
603     case WTAP_ENCAP_NULL:
604       capture_null(pd, phdr->caplen, &ld->counts);
605       break;
606     case WTAP_ENCAP_PPP:
607       capture_ppp(pd, phdr->caplen, &ld->counts);
608       break;
609     case WTAP_ENCAP_RAW_IP:
610       capture_raw(pd, phdr->caplen, &ld->counts);
611       break;
612     /* XXX - FreeBSD may append 4-byte ATM pseudo-header to DLT_ATM_RFC1483,
613        with LLC header following; we should implement it at some
614        point. */
615   }
616 }
617
618 #endif /* HAVE_LIBPCAP */