- GtkWidget *cap_w, *main_vb, *stop_bt, *counts_tb;
- pcap_t *pch;
- int pcap_encap;
- int file_snaplen;
- gchar open_err_str[PCAP_ERRBUF_SIZE];
- gchar lookup_net_err_str[PCAP_ERRBUF_SIZE];
- gchar label_str[64];
- bpf_u_int32 netnum, netmask;
- struct bpf_program fcode;
- time_t upd_time, cur_time;
- int err, inpkts;
- condition *cnd_stop_capturesize = NULL;
- condition *cnd_stop_timeout = NULL;
- unsigned int i;
- static const char capstart_msg = SP_CAPSTART;
- char errmsg[4096+1];
- gboolean dump_ok;
-#ifndef _WIN32
- static const char ppamsg[] = "can't find PPA for ";
- char *libpcap_warn;
-#endif
- fd_set set1;
- struct timeval timeout;
-#ifdef MUST_DO_SELECT
- int pcap_fd = 0;
-#endif
-#ifdef _WIN32
- WORD wVersionRequested;
- WSADATA wsaData;
-#endif
-#ifndef _WIN32
- int pipe_fd = -1;
- struct pcap_hdr hdr;
-#endif
- struct {
- const gchar *title;
- gint *value_ptr;
- GtkWidget *label, *value, *percent;
- } counts[] = {
- { "Total", &ld.counts.total, NULL, NULL, NULL },
- { "SCTP", &ld.counts.sctp, NULL, NULL, NULL },
- { "TCP", &ld.counts.tcp, NULL, NULL, NULL },
- { "UDP", &ld.counts.udp, NULL, NULL, NULL },
- { "ICMP", &ld.counts.icmp, NULL, NULL, NULL },
- { "OSPF", &ld.counts.ospf, NULL, NULL, NULL },
- { "GRE", &ld.counts.gre, NULL, NULL, NULL },
- { "NetBIOS", &ld.counts.netbios, NULL, NULL, NULL },
- { "IPX", &ld.counts.ipx, NULL, NULL, NULL },
- { "VINES", &ld.counts.vines, NULL, NULL, NULL },
- { "Other", &ld.counts.other, NULL, NULL, NULL }
- };
-
-#define N_COUNTS (sizeof counts / sizeof counts[0])
-
- /* Initialize Windows Socket if we are in a WIN32 OS
- This needs to be done before querying the interface for network/netmask */
-#ifdef _WIN32
- wVersionRequested = MAKEWORD( 1, 1 );
- err = WSAStartup( wVersionRequested, &wsaData );
- if (err!=0) {
- snprintf(errmsg, sizeof errmsg,
- "Couldn't initialize Windows Sockets.");
- pch=NULL;
- goto error;
- }
-#endif
-
- ld.go = TRUE;
- ld.counts.total = 0;
- if (capture_opts.has_autostop_count)
- ld.max = capture_opts.autostop_count;
- else
- ld.max = 0; /* no limit */
- ld.err = 0; /* no error seen yet */
- ld.linktype = WTAP_ENCAP_UNKNOWN;
- ld.pcap_err = FALSE;
- ld.from_pipe = FALSE;
- ld.sync_packets = 0;
- ld.counts.sctp = 0;
- ld.counts.tcp = 0;
- ld.counts.udp = 0;
- ld.counts.icmp = 0;
- ld.counts.ospf = 0;
- ld.counts.gre = 0;
- ld.counts.ipx = 0;
- ld.counts.netbios = 0;
- ld.counts.vines = 0;
- ld.counts.other = 0;
- ld.pdh = NULL;
-
- /* We haven't yet gotten the capture statistics. */
- *stats_known = FALSE;
-
- /* Open the network interface to capture from it.
- Some versions of libpcap may put warnings into the error buffer
- if they succeed; to tell if that's happened, we have to clear
- the error buffer, and check if it's still a null string. */
- open_err_str[0] = '\0';
- pch = pcap_open_live(cfile.iface,
- capture_opts.has_snaplen ? capture_opts.snaplen :
- WTAP_MAX_PACKET_SIZE,
- capture_opts.promisc_mode, CAP_READ_TIMEOUT,
- open_err_str);
-
- if (pch == NULL) {
-#ifdef _WIN32
- /* Well, we couldn't start the capture.
- If this is a child process that does the capturing in sync
- mode or fork mode, it shouldn't do any UI stuff until we pop up the
- capture-progress window, and, since we couldn't start the
- capture, we haven't popped it up. */
- if (!capture_child) {
- while (gtk_events_pending()) gtk_main_iteration();
- }
-
- /* On Win32 OSes, the capture devices are probably available to all
- users; don't warn about permissions problems.
-
- Do, however, warn that WAN devices aren't supported. */
- snprintf(errmsg, sizeof errmsg,
- "The capture session could not be initiated (%s).\n"
- "Please check that you have the proper interface specified.\n"
- "\n"
- "Note that the driver Ethereal uses for packet capture on Windows\n"
- "doesn't support capturing on PPP/WAN interfaces in Windows NT/2000.\n",
- open_err_str);
- goto error;
-#else
- /* try to open cfile.iface as a pipe */
- pipe_fd = pipe_open_live(cfile.iface, &hdr, &ld, open_err_str);
-
- if (pipe_fd == -1) {
- /* Well, we couldn't start the capture.
- If this is a child process that does the capturing in sync
- mode or fork mode, it shouldn't do any UI stuff until we pop up the
- capture-progress window, and, since we couldn't start the
- capture, we haven't popped it up. */
- if (!capture_child) {
- while (gtk_events_pending()) gtk_main_iteration();
- }
-
- /* If we got a "can't find PPA for XXX" message, warn the user (who
- is running Ethereal on HP-UX) that they don't have a version
- of libpcap that properly handles HP-UX (libpcap 0.6.x and later
- versions, which properly handle HP-UX, say "can't find /dev/dlpi
- PPA for XXX" rather than "can't find PPA for XXX"). */
- if (strncmp(open_err_str, ppamsg, sizeof ppamsg - 1) == 0)
- libpcap_warn =
- "\n\n"
- "You are running Ethereal with a version of the libpcap library\n"
- "that doesn't handle HP-UX network devices well; this means that\n"
- "Ethereal may not be able to capture packets.\n"
- "\n"
- "To fix this, you should install libpcap 0.6.2, or a later version\n"
- "of libpcap, rather than libpcap 0.4 or 0.5.x. It is available in\n"
- "packaged binary form from the Software Porting And Archive Centre\n"
- "for HP-UX; the Centre is at http://hpux.connect.org.uk/ - the page\n"
- "at the URL lists a number of mirror sites.";
- else
- libpcap_warn = "";
- snprintf(errmsg, sizeof errmsg,
- "The capture session could not be initiated (%s).\n"
- "Please check to make sure you have sufficient permissions, and that\n"
- "you have the proper interface or pipe specified.%s", open_err_str,
- libpcap_warn);
- goto error;
- }
-#endif
- }
-
- /* capture filters only work on real interfaces */
- if (cfile.cfilter && !ld.from_pipe) {
- /* A capture filter was specified; set it up. */
- if (pcap_lookupnet(cfile.iface, &netnum, &netmask, lookup_net_err_str) < 0) {
- /*
- * Well, we can't get the netmask for this interface; it's used
- * only for filters that check for broadcast IP addresses, so
- * we just punt and use 0. It might be nice to warn the user,
- * but that's a pain in a GUI application, as it'd involve popping
- * up a message box, and it's not clear how often this would make
- * a difference (only filters that check for IP broadcast addresses
- * use the netmask).
- */
- netmask = 0;
- }
- if (pcap_compile(pch, &fcode, cfile.cfilter, 1, netmask) < 0) {
- snprintf(errmsg, sizeof errmsg, "Unable to parse filter string (%s).",
- pcap_geterr(pch));
- goto error;
- }
- if (pcap_setfilter(pch, &fcode) < 0) {
- snprintf(errmsg, sizeof errmsg, "Can't install filter (%s).",
- pcap_geterr(pch));
- goto error;
- }
- }
-
- /* Set up to write to the capture file. */
-#ifndef _WIN32
- if (ld.from_pipe) {
- pcap_encap = hdr.network;
- file_snaplen = hdr.snaplen;
- } else
-#endif
- {
- pcap_encap = get_pcap_linktype(pch, cfile.iface);
- file_snaplen = pcap_snapshot(pch);
- }
- ld.linktype = wtap_pcap_encap_to_wtap_encap(pcap_encap);
- if (ld.linktype == WTAP_ENCAP_UNKNOWN) {
- snprintf(errmsg, sizeof errmsg,
- "The network you're capturing from is of a type"
- " that Ethereal doesn't support (data link type %d).", pcap_encap);
- goto error;
- }
- if (capture_opts.ringbuffer_on) {
- ld.pdh = ringbuf_init_wtap_dump_fdopen(WTAP_FILE_PCAP, ld.linktype,
- file_snaplen, &err);
- } else {
- ld.pdh = wtap_dump_fdopen(cfile.save_file_fd, WTAP_FILE_PCAP,
- ld.linktype, file_snaplen, &err);
- }
-
- if (ld.pdh == NULL) {
- /* We couldn't set up to write to the capture file. */
- switch (err) {
-
- case WTAP_ERR_CANT_OPEN:
- strcpy(errmsg, "The file to which the capture would be saved"
- " couldn't be created for some unknown reason.");
- break;
-
- case WTAP_ERR_SHORT_WRITE:
- strcpy(errmsg, "A full header couldn't be written to the file"
- " to which the capture would be saved.");
- break;
-
- default:
- if (err < 0) {
- snprintf(errmsg, sizeof(errmsg),
- "The file to which the capture would be"
- " saved (\"%s\") could not be opened: Error %d.",
- cfile.save_file, err);
- } else {
- snprintf(errmsg, sizeof(errmsg),
- "The file to which the capture would be"
- " saved (\"%s\") could not be opened: %s.",
- cfile.save_file, strerror(err));
- }
- break;
- }
- goto error;
- }
-
- /* Does "open_err_str" contain a non-empty string? If so, "pcap_open_live()"
- returned a warning; print it, but keep capturing. */
- if (open_err_str[0] != '\0')
- g_warning("%s.", open_err_str);
-
- /* XXX - capture SIGTERM and close the capture, in case we're on a
- Linux 2.0[.x] system and you have to explicitly close the capture
- stream in order to turn promiscuous mode off? We need to do that
- in other places as well - and I don't think that works all the
- time in any case, due to libpcap bugs. */
-
- if (capture_child) {
- /* Well, we should be able to start capturing.
-
- This is the child process for a sync mode capture, so sync out
- the capture file, so the header makes it to the file system,
- and send a "capture started successfully and capture file created"
- message to our parent so that they'll open the capture file and
- update its windows to indicate that we have a live capture in
- progress. */
- fflush(wtap_dump_file(ld.pdh));
- write(1, &capstart_msg, 1);
- }
-
- cap_w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_title(GTK_WINDOW(cap_w), "Ethereal: Capture");
- gtk_window_set_modal(GTK_WINDOW(cap_w), TRUE);
-
- /* Container for capture display widgets */
- main_vb = gtk_vbox_new(FALSE, 1);
- gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
- gtk_container_add(GTK_CONTAINER(cap_w), main_vb);
- gtk_widget_show(main_vb);
-
- /* Individual statistic elements */
- counts_tb = gtk_table_new(N_COUNTS, 3, TRUE);
- gtk_box_pack_start(GTK_BOX(main_vb), counts_tb, TRUE, TRUE, 3);
- gtk_widget_show(counts_tb);
-
- for (i = 0; i < N_COUNTS; i++) {
- counts[i].label = gtk_label_new(counts[i].title);
- gtk_misc_set_alignment(GTK_MISC(counts[i].label), 0.0f, 0.0f);
-
- counts[i].value = gtk_label_new("0");
- gtk_misc_set_alignment(GTK_MISC(counts[i].value), 0.0f, 0.0f);
-
- counts[i].percent = gtk_label_new("0.0%");
- gtk_misc_set_alignment(GTK_MISC(counts[i].percent), 0.0f, 0.0f);
-
- gtk_table_attach_defaults(GTK_TABLE(counts_tb),
- counts[i].label, 0, 1, i, i + 1);
-
- gtk_table_attach(GTK_TABLE(counts_tb),
- counts[i].value,
- 1, 2, i, i + 1, 0, 0, 5, 0);
-
- gtk_table_attach_defaults(GTK_TABLE(counts_tb),
- counts[i].percent, 2, 3, i, i + 1);
-
- gtk_widget_show(counts[i].label);
- gtk_widget_show(counts[i].value);
- gtk_widget_show(counts[i].percent);
- }
-
- /* allow user to either click a stop button, or the close button on
- the window to stop a capture in progress. */
- stop_bt = gtk_button_new_with_label ("Stop");
- gtk_signal_connect(GTK_OBJECT(stop_bt), "clicked",
- GTK_SIGNAL_FUNC(capture_stop_cb), (gpointer) &ld);
- gtk_signal_connect(GTK_OBJECT(cap_w), "delete_event",
- GTK_SIGNAL_FUNC(capture_delete_cb), (gpointer) &ld);
- gtk_box_pack_end(GTK_BOX(main_vb), stop_bt, FALSE, FALSE, 3);
- GTK_WIDGET_SET_FLAGS(stop_bt, GTK_CAN_DEFAULT);
- gtk_widget_grab_default(stop_bt);
- GTK_WIDGET_SET_FLAGS(stop_bt, GTK_CAN_DEFAULT);
- gtk_widget_grab_default(stop_bt);
- gtk_widget_show(stop_bt);
-
- gtk_widget_show(cap_w);
-
- upd_time = time(NULL);
-#ifdef MUST_DO_SELECT
- if (!ld.from_pipe) pcap_fd = pcap_fileno(pch);
-#endif
-