Index: vl.c =================================================================== RCS file: /sources/qemu/qemu/vl.c,v retrieving revision 1.377 diff -u -r1.377 vl.c --- vl.c 6 Dec 2007 22:11:20 -0000 1.377 +++ vl.c 10 Dec 2007 10:28:35 -0000 @@ -237,6 +237,17 @@ static CPUState *next_cpu; static int event_pending; +/* File header which needs to be written at the start of each PCAP file*/ +static const PCAPHeader pcap_file_header = { + 0xa1b2c3d4, + 2, + 4, + 0, + 0, + MAX_CAPTURED_PACKET_SIZE, + 1 /* Ethernet */ +}; + #define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR) /***********************************************************/ @@ -3588,6 +3599,8 @@ return NULL; vlan->id = id; vlan->next = NULL; + vlan->pcap_fh = -1; + vlan->last_packet_time = 0; pvlan = &first_vlan; while (*pvlan != NULL) pvlan = &(*pvlan)->next; @@ -3635,6 +3648,22 @@ { VLANState *vlan = vc1->vlan; VLANClientState *vc; + + if (vlan->pcap_fh >= 0) { + vlan->packet_header.timestamp_sec = time(NULL); + if (vlan->packet_header.timestamp_sec == vlan->last_packet_time) { + if (vlan->packet_header.timestamp_usec < 1000000) + ++vlan->packet_header.timestamp_usec; + } else { + vlan->packet_header.timestamp_usec = 0; + vlan->last_packet_time = vlan->packet_header.timestamp_sec; + } + + vlan->packet_header.orig_len = size; + vlan->packet_header.saved_len = (size > MAX_CAPTURED_PACKET_SIZE) ? MAX_CAPTURED_PACKET_SIZE : size; + write(vlan->pcap_fh, &vlan->packet_header, sizeof(PCAPPacketHeader)); + write(vlan->pcap_fh, buf, vlan->packet_header.saved_len); + } #if 0 printf("vlan %d send:\n", vlan->id); @@ -4641,7 +4670,8 @@ char device[64]; char buf[1024]; int vlan_id, ret; - VLANState *vlan; + VLANState *vlan; + const char *capture_file_name; p = str; q = device; @@ -4761,6 +4791,27 @@ } vlan->nb_host_devs++; } else + if (!strcmp(device, "capture")) { + if (vlan->pcap_fh >= 0) { + fprintf(stderr, "vlan %d has already a capture file defined! " + "Can't have multiple capture files for the same vlan\n", vlan->id); + return -1; + } + + capture_file_name = DEFAULT_CAPTURE_FILENAME; + if (get_param_value(buf, sizeof(buf), "file", p)) + capture_file_name = buf; + + vlan->pcap_fh = open(capture_file_name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); + if (vlan->pcap_fh < 0) { + fprintf(stderr, "Failed to open capture file \"%s\": %d\n", capture_file_name, errno); + return -1; + } + + write(vlan->pcap_fh, &pcap_file_header, sizeof(pcap_file_header)); + + ret = 0; + } else { fprintf(stderr, "Unknown network device: %s\n", device); return -1; @@ -4784,6 +4835,59 @@ } } +void do_net_capture (const char *path, + int has_vlan, int vlan_id) +{ + VLANState *vlan; + + vlan_id = (has_vlan) ? vlan_id : 0; + vlan = qemu_find_vlan(vlan_id); + if (!vlan) { + term_printf("Failed to find vlan %d\n", vlan_id); + return; + } + + if (vlan->pcap_fh >= 0) { + term_printf("Vlan %d is already capturing!\n", vlan_id); + return; + } + + vlan->pcap_fh = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); + if (vlan->pcap_fh < 0) { + term_printf("Failed to open capture file \"%s\": %d\n", path, errno); + return; + } + + vlan->last_packet_time = 0; + write(vlan->pcap_fh, &pcap_file_header, sizeof(pcap_file_header)); +} + +void do_stop_net_capture(int has_vlan, int vlan_id) +{ + VLANState *vlan; + + if (has_vlan) { + vlan = qemu_find_vlan(vlan_id); + if (!vlan) { + term_printf("Failed to find vlan %d\n", vlan_id); + return; + } + + if (vlan->pcap_fh < 0) { + term_printf("Vlan %d is not capturing!\n", vlan_id); + return; + } + + close(vlan->pcap_fh); + vlan->pcap_fh = -1; + vlan->last_packet_time = 0; + } else { + for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) + if (vlan->pcap_fh >= 0) + close(vlan->pcap_fh); + } +} + #define HD_ALIAS "file=\"%s\",index=%d,media=disk" #ifdef TARGET_PPC #define CDROM_ALIAS "index=1,media=cdrom" @@ -7511,6 +7615,10 @@ " connect the vlan 'n' to another VLAN using a socket connection\n" "-net socket[,vlan=n][,fd=h][,mcast=maddr:port]\n" " connect the vlan 'n' to multicast maddr and port\n" + "-net capture[,vlan=n][,file=filename]\n" + " captures the traffic flowing through VLAN 'n' to the file\n" + " 'filename' in tcpdump format. In case filename is not specified,\n" + " the capture will be saved to " DEFAULT_CAPTURE_FILENAME "\n" "-net none use it alone to have zero network devices; if no -net option\n" " is provided, the default is '-net nic -net user'\n" "\n" @@ -8939,5 +9047,11 @@ } } #endif + + /* close capture files associated with any vlan */ + for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) + if (vlan->pcap_fh >= 0) + close(vlan->pcap_fh); + return 0; } Index: net.h =================================================================== RCS file: /sources/qemu/qemu/net.h,v retrieving revision 1.1 diff -u -r1.1 net.h --- net.h 17 Nov 2007 17:14:38 -0000 1.1 +++ net.h 10 Dec 2007 10:28:35 -0000 @@ -1,6 +1,28 @@ #ifndef QEMU_NET_H #define QEMU_NET_H +/* PCAP support */ +/* source: http://wiki.wireshark.org/Development/LibpcapFileFormat */ +typedef struct { + uint32_t magic_number; + uint16_t version_major; + uint16_t version_minor; + int32_t thiszone; + uint32_t sigfigs; + uint32_t snaplen; + uint32_t network; +} PCAPHeader; + +#define MAX_CAPTURED_PACKET_SIZE 0xFFFF +#define DEFAULT_CAPTURE_FILENAME "qemu.pcap" + +typedef struct { + uint32_t timestamp_sec; + uint32_t timestamp_usec; + uint32_t saved_len; + uint32_t orig_len; +} PCAPPacketHeader; + /* VLANs support */ typedef struct VLANClientState VLANClientState; @@ -21,6 +43,10 @@ VLANClientState *first_client; struct VLANState *next; unsigned int nb_guest_devs, nb_host_devs; + /* Filehandle for the capture file */ + int pcap_fh; + time_t last_packet_time; + PCAPPacketHeader packet_header; }; VLANState *qemu_find_vlan(int id); @@ -34,6 +60,11 @@ void do_info_network(void); +void do_net_capture (const char *path, + int has_vlan, int vlan_id); + +void do_stop_net_capture(int has_vlan, int vlan_id); + /* NIC info */ #define MAX_NICS 8 Index: monitor.c =================================================================== RCS file: /sources/qemu/qemu/monitor.c,v retrieving revision 1.91 diff -u -r1.91 monitor.c --- monitor.c 3 Dec 2007 17:05:38 -0000 1.91 +++ monitor.c 10 Dec 2007 10:28:42 -0000 @@ -1326,6 +1326,10 @@ "capture index", "stop capture" }, { "memsave", "lis", do_memory_save, "addr size file", "save to disk virtual memory dump starting at 'addr' of size 'size'", }, + { "netcapture", "si?", do_net_capture, + "path [vlan]", "saves the traffic flowing through the given vlan to the file" }, + { "stopnetcapture", "i?", do_stop_net_capture, + "[vlan]", "stops the capture of the specified vlan. if no vlan specified, stops all the capture" }, { NULL, NULL, }, };