2 * Routines for packet capture windows
4 * $Id: capture.c,v 1.74 1999/09/30 06:49:53 guy Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@zing.org>
8 * Copyright 1998 Gerald Combs
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.
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.
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.
33 #ifdef HAVE_SYS_TYPES_H
34 # include <sys/types.h>
37 #ifdef HAVE_SYS_STAT_H
38 # include <sys/stat.h>
53 #ifdef HAVE_SYS_SOCKET_H
54 #include <sys/socket.h>
57 #ifdef HAVE_SYS_IOCTL_H
58 #include <sys/ioctl.h>
68 #ifdef NEED_SNPRINTF_H
74 # include "snprintf.h"
86 static void capture_stop_cb(GtkWidget *, gpointer);
87 static void capture_pcap_cb(u_char *, const struct pcap_pkthdr *,
89 static float pct(gint, gint);
91 typedef struct _loop_data {
100 /* Create a temporary file and start a capture to it. */
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));
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. */
118 unlink(cf.save_file); /* silently ignore error */
119 g_free(cf.save_file);
121 cf.save_file = g_strdup(tmpname);
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. */
138 if (sync_mode || fork_mode) { /* use fork() for capture */
141 char scount[24]; /* need a constant for len of numbers */
142 char save_file_fd[24];
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);
151 if ((fork_child = fork()) == 0) {
152 /* args: -k -- capture
153 * -i interface specification
155 * -W file descriptor to write
156 * -c count to capture
157 * -Q quit after capture (forces -k)
161 * -f "filter expression"
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,
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,
186 cf.filename = cf.save_file;
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. */
197 i = read(sync_pipe[0], &c, 1);
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");
207 /* Child process handed us crap. */
208 simple_dialog(ESD_TYPE_WARN, NULL,
209 "Capture child process sent us a bad message");
212 byte_count = byte_count*10 + c - '0';
214 if (byte_count == 0) {
216 err = tail_cap_file(cf.save_file, &cf);
218 simple_dialog(ESD_TYPE_WARN, NULL,
219 file_open_error_message(err, FALSE), cf.save_file);
223 msg = g_malloc(byte_count + 1);
225 simple_dialog(ESD_TYPE_WARN, NULL,
226 "Capture child process failed, but its error message was too big.");
228 i = read(sync_pipe[0], msg, byte_count);
230 simple_dialog(ESD_TYPE_WARN, NULL,
231 "Capture child process failed: Error %s reading its error message.",
234 simple_dialog(ESD_TYPE_WARN, NULL,
235 "Capture child process failed: EOF reading its error message.");
237 simple_dialog(ESD_TYPE_WARN, NULL, msg);
248 /* Do the low-level work of a capture. */
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;
255 gchar err_str[PCAP_ERRBUF_SIZE], label_str[32];
257 bpf_u_int32 netnum, netmask;
258 time_t upd_time, cur_time;
265 ld.linktype = WTAP_ENCAP_UNKNOWN;
272 ld.counts.netbios = 0;
276 /* Open the network interface to capture from it. */
277 pch = pcap_open_live(cf.iface, cf.snap, 1, 250, err_str);
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();
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);
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);
302 if (pcap_compile(pch, &cf.fcode, cf.cfilter, 1, netmask) < 0) {
303 snprintf(errmsg, sizeof errmsg, "Unable to parse filter string (%s).",
307 if (pcap_setfilter(pch, &cf.fcode) < 0) {
308 snprintf(errmsg, sizeof errmsg, "Can't install filter (%s).",
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.");
321 ld.pdh = wtap_dump_fdopen(cf.save_file_fd, WTAP_FILE_PCAP,
322 ld.linktype, pcap_snapshot(pch), &err);
324 if (ld.pdh == NULL) {
325 /* We couldn't set up to write to the capture file. */
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.");
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.");
340 sprintf(errmsg, "The file to which the capture would be"
341 " saved (\"%s\") could not be opened: Error %d.",
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));
353 if (capture_child && sync_mode) {
354 /* Well, we should be able to start capturing.
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
362 fflush(wtap_dump_file(ld.pdh));
366 cap_w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
367 gtk_window_set_title(GTK_WINDOW(cap_w), "Ethereal: Capture / Playback");
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
417 gtk_widget_show(cap_w);
420 upd_time = time(NULL);
422 while (gtk_events_pending()) gtk_main_iteration();
423 inpkts = pcap_dispatch(pch, 1, capture_pcap_cb, (u_char *) &ld);
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) {
431 sprintf(label_str, "Count: %d", ld.counts.total);
432 gtk_label_set(GTK_LABEL(count_lb), label_str);
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);
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);
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);
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);
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);
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);
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);
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. */
469 sprintf(tmp, "%d*", ld.sync_packets);
470 write(1, tmp, strlen(tmp));
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.
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. */
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.");
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.");
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.",
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));
514 gtk_grab_remove(GTK_WIDGET(cap_w));
515 gtk_widget_destroy(GTK_WIDGET(cap_w));
517 if (quit_after_cap) {
518 /* DON'T unlink the save file. Presumably someone wants it. */
522 if ((err = open_cap_file(cf.save_file, &cf)) == 0) {
523 /* Set the read filter to NULL. */
525 err = read_cap_file(&cf);
526 set_menu_sensitivity("/File/Save", TRUE);
527 set_menu_sensitivity("/File/Save As...", FALSE);
532 /* We couldn't even start the capture, so get rid of the capture
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);
541 sprintf(lenbuf, "%u;", msglen);
542 write(1, lenbuf, strlen(lenbuf));
543 write(1, errmsg, msglen);
545 /* Display the dialog box ourselves; there's no parent. */
546 simple_dialog(ESD_TYPE_WARN, NULL, errmsg);
556 pct(gint num, gint denom) {
558 return (float) num * 100.0 / (float) denom;
565 capture_stop_cb(GtkWidget *w, gpointer data) {
566 loop_data *ld = (loop_data *) data;
572 capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr,
574 struct wtap_pkthdr whdr;
575 loop_data *ld = (loop_data *) user;
578 if ((++ld->counts.total >= ld->max) && (ld->max > 0))
584 whdr.caplen = phdr->caplen;
585 whdr.len = phdr->len;
586 whdr.pkt_encap = ld->linktype;
588 /* XXX - do something if this fails */
589 wtap_dump(ld->pdh, &whdr, pd, &err);
592 switch (ld->linktype) {
593 case WTAP_ENCAP_ETHERNET:
594 capture_eth(pd, phdr->caplen, &ld->counts);
596 case WTAP_ENCAP_FDDI:
597 case WTAP_ENCAP_FDDI_BITSWAPPED:
598 capture_fddi(pd, phdr->caplen, &ld->counts);
601 capture_tr(pd, phdr->caplen, &ld->counts);
603 case WTAP_ENCAP_NULL:
604 capture_null(pd, phdr->caplen, &ld->counts);
607 capture_ppp(pd, phdr->caplen, &ld->counts);
609 case WTAP_ENCAP_RAW_IP:
610 capture_raw(pd, phdr->caplen, &ld->counts);
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
618 #endif /* HAVE_LIBPCAP */