2
0

dump.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  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 "sysemu/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. struct iovec dumpiov[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. int offset = qemu_get_using_vnet_hdr(nf->netdev) ?
  134. qemu_get_vnet_hdr_len(nf->netdev) : 0;
  135. dump_receive_iov(&nfds->ds, iov, iovcnt, offset);
  136. return 0;
  137. }
  138. static void filter_dump_cleanup(NetFilterState *nf)
  139. {
  140. NetFilterDumpState *nfds = FILTER_DUMP(nf);
  141. dump_cleanup(&nfds->ds);
  142. }
  143. static void filter_dump_setup(NetFilterState *nf, Error **errp)
  144. {
  145. NetFilterDumpState *nfds = FILTER_DUMP(nf);
  146. if (!nfds->filename) {
  147. error_setg(errp, "dump filter needs 'file' property set!");
  148. return;
  149. }
  150. net_dump_state_init(&nfds->ds, nfds->filename, nfds->maxlen, errp);
  151. }
  152. static void filter_dump_get_maxlen(Object *obj, Visitor *v, const char *name,
  153. void *opaque, Error **errp)
  154. {
  155. NetFilterDumpState *nfds = FILTER_DUMP(obj);
  156. uint32_t value = nfds->maxlen;
  157. visit_type_uint32(v, name, &value, errp);
  158. }
  159. static void filter_dump_set_maxlen(Object *obj, Visitor *v, const char *name,
  160. void *opaque, Error **errp)
  161. {
  162. NetFilterDumpState *nfds = FILTER_DUMP(obj);
  163. uint32_t value;
  164. if (!visit_type_uint32(v, name, &value, errp)) {
  165. return;
  166. }
  167. if (value == 0) {
  168. error_setg(errp, "Property '%s.%s' doesn't take value '%u'",
  169. object_get_typename(obj), name, value);
  170. return;
  171. }
  172. nfds->maxlen = value;
  173. }
  174. static char *file_dump_get_filename(Object *obj, Error **errp)
  175. {
  176. NetFilterDumpState *nfds = FILTER_DUMP(obj);
  177. return g_strdup(nfds->filename);
  178. }
  179. static void file_dump_set_filename(Object *obj, const char *value, Error **errp)
  180. {
  181. NetFilterDumpState *nfds = FILTER_DUMP(obj);
  182. g_free(nfds->filename);
  183. nfds->filename = g_strdup(value);
  184. }
  185. static void filter_dump_instance_init(Object *obj)
  186. {
  187. NetFilterDumpState *nfds = FILTER_DUMP(obj);
  188. nfds->maxlen = 65536;
  189. }
  190. static void filter_dump_instance_finalize(Object *obj)
  191. {
  192. NetFilterDumpState *nfds = FILTER_DUMP(obj);
  193. g_free(nfds->filename);
  194. }
  195. static void filter_dump_class_init(ObjectClass *oc, void *data)
  196. {
  197. NetFilterClass *nfc = NETFILTER_CLASS(oc);
  198. object_class_property_add(oc, "maxlen", "uint32", filter_dump_get_maxlen,
  199. filter_dump_set_maxlen, NULL, NULL);
  200. object_class_property_add_str(oc, "file", file_dump_get_filename,
  201. file_dump_set_filename);
  202. nfc->setup = filter_dump_setup;
  203. nfc->cleanup = filter_dump_cleanup;
  204. nfc->receive_iov = filter_dump_receive_iov;
  205. }
  206. static const TypeInfo filter_dump_info = {
  207. .name = TYPE_FILTER_DUMP,
  208. .parent = TYPE_NETFILTER,
  209. .class_init = filter_dump_class_init,
  210. .instance_init = filter_dump_instance_init,
  211. .instance_finalize = filter_dump_instance_finalize,
  212. .instance_size = sizeof(NetFilterDumpState),
  213. };
  214. static void filter_dump_register_types(void)
  215. {
  216. type_register_static(&filter_dump_info);
  217. }
  218. type_init(filter_dump_register_types);