module_csv.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. /*
  2. * ZMap Copyright 2013 Regents of the University of Michigan
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy
  6. * of the License at http://www.apache.org/licenses/LICENSE-2.0
  7. */
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <sys/socket.h>
  12. #include <netinet/in.h>
  13. #include <arpa/inet.h>
  14. #include <assert.h>
  15. #include <inttypes.h>
  16. #include "../../lib/logger.h"
  17. #include "../fieldset.h"
  18. #include "output_modules.h"
  19. static FILE *file = NULL;
  20. int csv_init(struct state_conf *conf, char **fields, int fieldlens)
  21. {
  22. assert(conf);
  23. if (conf->output_filename) {
  24. if (!strcmp(conf->output_filename, "-")) {
  25. file = stdout;
  26. } else {
  27. if (!(file = fopen(conf->output_filename, "w"))) {
  28. log_fatal("csv", "could not open CSV output file %s",
  29. conf->output_filename);
  30. }
  31. }
  32. } else {
  33. file = stdout;
  34. log_info("csv", "no output file selected, will use stdout");
  35. }
  36. if (fieldlens > 1 && file) {
  37. log_debug("csv", "more than one field, will add headers");
  38. for (int i=0; i < fieldlens; i++) {
  39. if (i) {
  40. fprintf(file, ",");
  41. }
  42. fprintf(file, "%s", fields[i]);
  43. }
  44. fprintf(file, "\n");
  45. }
  46. check_and_log_file_error(file, "csv");
  47. return EXIT_SUCCESS;
  48. }
  49. int csv_close(__attribute__((unused)) struct state_conf* c,
  50. __attribute__((unused)) struct state_send* s,
  51. __attribute__((unused)) struct state_recv* r)
  52. {
  53. if (file) {
  54. fflush(file);
  55. fclose(file);
  56. }
  57. return EXIT_SUCCESS;
  58. }
  59. static void hex_encode(FILE *f, unsigned char* readbuf, size_t len)
  60. {
  61. for(size_t i=0; i < len; i++) {
  62. fprintf(f, "%02x", readbuf[i]);
  63. }
  64. check_and_log_file_error(f, "csv");
  65. }
  66. int csv_process(fieldset_t *fs)
  67. {
  68. if (!file) {
  69. return EXIT_SUCCESS;
  70. }
  71. for (int i=0; i < fs->len; i++) {
  72. field_t *f = &(fs->fields[i]);
  73. if (i) {
  74. fprintf(file, ",");
  75. }
  76. if (f->type == FS_STRING) {
  77. if (strchr((char*) f->value.ptr, ',')) {
  78. fprintf(file, "\"%s\"", (char*) f->value.ptr);
  79. } else {
  80. fprintf(file, "%s", (char*) f->value.ptr);
  81. }
  82. } else if (f->type == FS_UINT64) {
  83. fprintf(file, "%" PRIu64, (uint64_t) f->value.num);
  84. } else if (f->type == FS_BINARY) {
  85. hex_encode(file, (unsigned char*) f->value.ptr, f->len);
  86. } else if (f->type == FS_NULL) {
  87. // do nothing
  88. } else {
  89. log_fatal("csv", "received unknown output type");
  90. }
  91. }
  92. fprintf(file, "\n");
  93. fflush(file);
  94. check_and_log_file_error(file, "csv");
  95. return EXIT_SUCCESS;
  96. }
  97. output_module_t module_csv_file = {
  98. .name = "csv",
  99. .filter_duplicates = 0, // framework should not filter out duplicates
  100. .filter_unsuccessful = 0, // framework should not filter out unsuccessful
  101. .init = &csv_init,
  102. .start = NULL,
  103. .update = NULL,
  104. .update_interval = 0,
  105. .close = &csv_close,
  106. .process_ip = &csv_process,
  107. .helptext = "Outputs one or more output fields as a comma-delimited file. By default, the "
  108. "probe module does not filter out duplicates or limit to successful fields, "
  109. "but rather includes all received packets. Fields can be controlled by "
  110. "setting --output-fields. Filtering out failures and duplicate packets can "
  111. "be achieved by setting an --output-filter."
  112. };