dump.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. /*
  2. * QEMU System Emulator
  3. *
  4. * Copyright (c) 2003-2008 Fabrice Bellard
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. #include "qemu/osdep.h"
  25. #include "clients.h"
  26. #include "qapi/error.h"
  27. #include "qemu/error-report.h"
  28. #include "qemu/iov.h"
  29. #include "qemu/module.h"
  30. #include "qemu/timer.h"
  31. #include "qapi/visitor.h"
  32. #include "net/filter.h"
  33. #include "qom/object.h"
  34. #include "system/rtc.h"
  35. typedef struct DumpState {
  36. int64_t start_ts;
  37. int fd;
  38. int pcap_caplen;
  39. } DumpState;
  40. #define PCAP_MAGIC 0xa1b2c3d4
  41. struct pcap_file_hdr {
  42. uint32_t magic;
  43. uint16_t version_major;
  44. uint16_t version_minor;
  45. int32_t thiszone;
  46. uint32_t sigfigs;
  47. uint32_t snaplen;
  48. uint32_t linktype;
  49. };
  50. struct pcap_sf_pkthdr {
  51. struct {
  52. int32_t tv_sec;
  53. int32_t tv_usec;
  54. } ts;
  55. uint32_t caplen;
  56. uint32_t len;
  57. };
  58. static ssize_t dump_receive_iov(DumpState *s, const struct iovec *iov, int cnt,
  59. int offset)
  60. {
  61. struct pcap_sf_pkthdr hdr;
  62. int64_t ts;
  63. int caplen;
  64. size_t size = iov_size(iov, cnt) - offset;
  65. g_autofree struct iovec *dumpiov = g_new(struct iovec, cnt + 1);
  66. /* Early return in case of previous error. */
  67. if (s->fd < 0) {
  68. return size;
  69. }
  70. ts = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL);
  71. caplen = size > s->pcap_caplen ? s->pcap_caplen : size;
  72. hdr.ts.tv_sec = ts / 1000000 + s->start_ts;
  73. hdr.ts.tv_usec = ts % 1000000;
  74. hdr.caplen = caplen;
  75. hdr.len = size;
  76. dumpiov[0].iov_base = &hdr;
  77. dumpiov[0].iov_len = sizeof(hdr);
  78. cnt = iov_copy(&dumpiov[1], cnt, iov, cnt, offset, caplen);
  79. if (writev(s->fd, dumpiov, cnt + 1) != sizeof(hdr) + caplen) {
  80. error_report("network dump write error - stopping dump");
  81. close(s->fd);
  82. s->fd = -1;
  83. }
  84. return size;
  85. }
  86. static void dump_cleanup(DumpState *s)
  87. {
  88. close(s->fd);
  89. s->fd = -1;
  90. }
  91. static int net_dump_state_init(DumpState *s, const char *filename,
  92. int len, Error **errp)
  93. {
  94. struct pcap_file_hdr hdr;
  95. struct tm tm;
  96. int fd;
  97. fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0644);
  98. if (fd < 0) {
  99. error_setg_errno(errp, errno, "net dump: can't open %s", filename);
  100. return -1;
  101. }
  102. hdr.magic = PCAP_MAGIC;
  103. hdr.version_major = 2;
  104. hdr.version_minor = 4;
  105. hdr.thiszone = 0;
  106. hdr.sigfigs = 0;
  107. hdr.snaplen = len;
  108. hdr.linktype = 1;
  109. if (write(fd, &hdr, sizeof(hdr)) < sizeof(hdr)) {
  110. error_setg_errno(errp, errno, "net dump write error");
  111. close(fd);
  112. return -1;
  113. }
  114. s->fd = fd;
  115. s->pcap_caplen = len;
  116. qemu_get_timedate(&tm, 0);
  117. s->start_ts = mktime(&tm);
  118. return 0;
  119. }
  120. #define TYPE_FILTER_DUMP "filter-dump"
  121. OBJECT_DECLARE_SIMPLE_TYPE(NetFilterDumpState, FILTER_DUMP)
  122. struct NetFilterDumpState {
  123. NetFilterState nfs;
  124. DumpState ds;
  125. char *filename;
  126. uint32_t maxlen;
  127. };
  128. static ssize_t filter_dump_receive_iov(NetFilterState *nf, NetClientState *sndr,
  129. unsigned flags, const struct iovec *iov,
  130. int iovcnt, NetPacketSent *sent_cb)
  131. {
  132. NetFilterDumpState *nfds = FILTER_DUMP(nf);
  133. dump_receive_iov(&nfds->ds, iov, iovcnt, flags & QEMU_NET_PACKET_FLAG_RAW ?
  134. 0 : qemu_get_vnet_hdr_len(nf->netdev));
  135. return 0;
  136. }
  137. static void filter_dump_cleanup(NetFilterState *nf)
  138. {
  139. NetFilterDumpState *nfds = FILTER_DUMP(nf);
  140. dump_cleanup(&nfds->ds);
  141. }
  142. static void filter_dump_setup(NetFilterState *nf, Error **errp)
  143. {
  144. NetFilterDumpState *nfds = FILTER_DUMP(nf);
  145. if (!nfds->filename) {
  146. error_setg(errp, "dump filter needs 'file' property set!");
  147. return;
  148. }
  149. net_dump_state_init(&nfds->ds, nfds->filename, nfds->maxlen, errp);
  150. }
  151. static void filter_dump_get_maxlen(Object *obj, Visitor *v, const char *name,
  152. void *opaque, Error **errp)
  153. {
  154. NetFilterDumpState *nfds = FILTER_DUMP(obj);
  155. uint32_t value = nfds->maxlen;
  156. visit_type_uint32(v, name, &value, errp);
  157. }
  158. static void filter_dump_set_maxlen(Object *obj, Visitor *v, const char *name,
  159. void *opaque, Error **errp)
  160. {
  161. NetFilterDumpState *nfds = FILTER_DUMP(obj);
  162. uint32_t value;
  163. if (!visit_type_uint32(v, name, &value, errp)) {
  164. return;
  165. }
  166. if (value == 0) {
  167. error_setg(errp, "Property '%s.%s' doesn't take value '%u'",
  168. object_get_typename(obj), name, value);
  169. return;
  170. }
  171. nfds->maxlen = value;
  172. }
  173. static char *file_dump_get_filename(Object *obj, Error **errp)
  174. {
  175. NetFilterDumpState *nfds = FILTER_DUMP(obj);
  176. return g_strdup(nfds->filename);
  177. }
  178. static void file_dump_set_filename(Object *obj, const char *value, Error **errp)
  179. {
  180. NetFilterDumpState *nfds = FILTER_DUMP(obj);
  181. g_free(nfds->filename);
  182. nfds->filename = g_strdup(value);
  183. }
  184. static void filter_dump_instance_init(Object *obj)
  185. {
  186. NetFilterDumpState *nfds = FILTER_DUMP(obj);
  187. nfds->maxlen = 65536;
  188. }
  189. static void filter_dump_instance_finalize(Object *obj)
  190. {
  191. NetFilterDumpState *nfds = FILTER_DUMP(obj);
  192. g_free(nfds->filename);
  193. }
  194. static void filter_dump_class_init(ObjectClass *oc, void *data)
  195. {
  196. NetFilterClass *nfc = NETFILTER_CLASS(oc);
  197. object_class_property_add(oc, "maxlen", "uint32", filter_dump_get_maxlen,
  198. filter_dump_set_maxlen, NULL, NULL);
  199. object_class_property_add_str(oc, "file", file_dump_get_filename,
  200. file_dump_set_filename);
  201. nfc->setup = filter_dump_setup;
  202. nfc->cleanup = filter_dump_cleanup;
  203. nfc->receive_iov = filter_dump_receive_iov;
  204. }
  205. static const TypeInfo filter_dump_info = {
  206. .name = TYPE_FILTER_DUMP,
  207. .parent = TYPE_NETFILTER,
  208. .class_init = filter_dump_class_init,
  209. .instance_init = filter_dump_instance_init,
  210. .instance_finalize = filter_dump_instance_finalize,
  211. .instance_size = sizeof(NetFilterDumpState),
  212. };
  213. static void filter_dump_register_types(void)
  214. {
  215. type_register_static(&filter_dump_info);
  216. }
  217. type_init(filter_dump_register_types);