psamp.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /*
  2. * Copyright 2019 Hitoshi Irino <irino@sfc.wide.ad.jp> All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. * 1. Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * 2. Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  14. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  16. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  17. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  18. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  19. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  20. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  21. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  22. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  23. */
  24. #include "common.h"
  25. #include "log.h"
  26. #include "ipfix.h"
  27. #include "psamp.h"
  28. #include <pcap.h>
  29. #define PSAMP_SOFTFLOWD_TEMPLATE_ID 3072
  30. #define PSAMP_SOFTFLOWD_TEMPLATE_NRECORDS 4
  31. #define PSAMP_DATALINKFRAME_SIZE IPFIX_SOFTFLOWD_MAX_PACKET_SIZE - \
  32. sizeof(struct IPFIX_HEADER) - sizeof(struct IPFIX_SET_HEADER) - 8 - 8 -2
  33. const struct IPFIX_FIELD_SPECIFIER field_psamp[] = {
  34. {PSAMP_selectionSequenceId, 8},
  35. {PSAMP_observationTimeMicroseconds, 8},
  36. {PSAMP_sectionExportedOctets, 2},
  37. {PSAMP_dataLinkFrameSection, PSAMP_DATALINKFRAME_SIZE}
  38. };
  39. struct PSAMP_SOFTFLOWD_TEMPLATE {
  40. struct IPFIX_TEMPLATE_SET_HEADER h;
  41. struct IPFIX_FIELD_SPECIFIER r[PSAMP_SOFTFLOWD_TEMPLATE_NRECORDS];
  42. } __packed;
  43. struct PSAMP_SOFTFLOWD_TEMPLATE template;
  44. static int psamp_pkts_until_template = -1;
  45. static void
  46. psamp_init_template (struct PSAMP_SOFTFLOWD_TEMPLATE *template_p) {
  47. u_int index = 0;
  48. bzero (template_p, sizeof (*template_p));
  49. template_p->h.c.set_id = htons (IPFIX_TEMPLATE_SET_ID);
  50. template_p->h.c.length = htons (sizeof (struct PSAMP_SOFTFLOWD_TEMPLATE));
  51. template_p->h.r.template_id = htons (PSAMP_SOFTFLOWD_TEMPLATE_ID);
  52. template_p->h.r.count = htons (PSAMP_SOFTFLOWD_TEMPLATE_NRECORDS);
  53. ipfix_init_fields (template_p->r, &index, field_psamp,
  54. PSAMP_SOFTFLOWD_TEMPLATE_NRECORDS);
  55. }
  56. int
  57. send_psamp (const u_char * pkt, int caplen, struct timeval tv,
  58. struct NETFLOW_TARGET *target, uint64_t total_packets) {
  59. u_char packet[IPFIX_SOFTFLOWD_MAX_PACKET_SIZE];
  60. struct IPFIX_HEADER *ipfix = (struct IPFIX_HEADER *) packet;
  61. struct IPFIX_SET_HEADER *dh;
  62. u_int64_t *sequenceId;
  63. struct ntp_time_t *ntptime;
  64. u_int16_t *exportedOctets;
  65. int offset = sizeof (struct IPFIX_HEADER);
  66. int copysize =
  67. caplen < PSAMP_DATALINKFRAME_SIZE ? caplen : PSAMP_DATALINKFRAME_SIZE;
  68. ipfix->version = htons (NF_VERSION_IPFIX); // PSAMP uses IPFIX
  69. ipfix->export_time = htonl (tv.tv_sec);
  70. ipfix->sequence = htonl ((u_int32_t) (total_packets & 0x00000000ffffffff));
  71. ipfix->od_id = 0;
  72. if (psamp_pkts_until_template == -1) {
  73. psamp_init_template (&template);
  74. psamp_pkts_until_template = 0;
  75. memcpy (&packet[offset], &template, sizeof (template));
  76. ipfix->length = htons (offset + sizeof (template));
  77. if (send_multi_destinations
  78. (target->num_destinations, target->destinations, 0, packet,
  79. offset + sizeof (template)) < 0)
  80. return (-1);
  81. }
  82. dh = (struct IPFIX_SET_HEADER *) &packet[offset];
  83. dh->set_id = htons (PSAMP_SOFTFLOWD_TEMPLATE_ID);
  84. dh->length =
  85. htons (IPFIX_SOFTFLOWD_MAX_PACKET_SIZE - sizeof (struct IPFIX_HEADER));
  86. offset += sizeof (struct IPFIX_SET_HEADER);
  87. sequenceId = (u_int64_t *) & packet[offset];
  88. *sequenceId = htobe64 (total_packets);
  89. offset += sizeof (u_int64_t);
  90. ntptime = (struct ntp_time_t *) &packet[offset];
  91. conv_unix_to_ntp (tv, ntptime);
  92. ntptime->second = htonl (ntptime->second);
  93. ntptime->fraction = htonl (ntptime->fraction);
  94. offset += sizeof (struct ntp_time_t);
  95. exportedOctets = (u_int16_t *) & packet[offset];
  96. *exportedOctets = htons (copysize);
  97. offset += sizeof (u_int16_t);
  98. memset (&packet[offset], 0, IPFIX_SOFTFLOWD_MAX_PACKET_SIZE - offset);
  99. memcpy (&packet[offset], pkt, copysize);
  100. ipfix->length = htons (IPFIX_SOFTFLOWD_MAX_PACKET_SIZE);
  101. if (send_multi_destinations (target->num_destinations, target->destinations,
  102. target->is_loadbalance,
  103. packet, IPFIX_SOFTFLOWD_MAX_PACKET_SIZE) < 0)
  104. return (-1);
  105. return 1;
  106. }
  107. // This function only process softflowd orignate psamp data record.
  108. int
  109. recv_psamp (int rsock, struct CB_CTXT *cb_ctxt) {
  110. char buf[IPFIX_SOFTFLOWD_MAX_PACKET_SIZE];
  111. struct IPFIX_HEADER *ipfix = (struct IPFIX_HEADER *) buf;
  112. struct ntp_time_t ntptime;
  113. struct pcap_pkthdr pkthdr;
  114. int recvsize = 0;
  115. int offset = 0;
  116. memset (buf, 0, sizeof (buf));
  117. recvsize = recv (rsock, buf, sizeof (buf), 0);
  118. if (recvsize < 0) {
  119. perror ("recv");
  120. return -1;
  121. } else if (recvsize <
  122. (sizeof (struct IPFIX_HEADER) +
  123. sizeof (struct IPFIX_SET_HEADER) + sizeof (uint64_t) +
  124. sizeof (struct ntp_time_t) + sizeof (uint16_t))) {
  125. logit (LOG_DEBUG, "recv_psamp: recvsize: %d is shorter than needed size",
  126. recvsize);
  127. return -1;
  128. }
  129. offset = sizeof (struct IPFIX_HEADER);
  130. struct IPFIX_SET_HEADER *sh = (struct IPFIX_SET_HEADER *) &buf[offset];
  131. offset += sizeof (struct IPFIX_SET_HEADER);
  132. if (ntohs (ipfix->version) != NF_VERSION_IPFIX)
  133. return -1;
  134. if (ntohs (sh->set_id) != PSAMP_SOFTFLOWD_TEMPLATE_ID)
  135. return 0; // This function only process softflowd orignate psamp data record.
  136. // disrgard selectionSequenceId
  137. offset += sizeof (uint64_t);
  138. // observationTimeMicroseconds
  139. ntptime = *((struct ntp_time_t *) &buf[offset]);
  140. offset += sizeof (struct ntp_time_t);
  141. ntptime.second = ntohl (ntptime.second);
  142. ntptime.fraction = ntohl (ntptime.fraction);
  143. pkthdr.ts = conv_ntp_to_unix (ntptime);
  144. //sectionExportedOctets
  145. pkthdr.caplen = pkthdr.len = ntohs (*((uint16_t *) & buf[offset]));
  146. offset += sizeof (uint16_t);
  147. pkthdr.caplen =
  148. pkthdr.caplen <
  149. sizeof (buf) - offset ? pkthdr.caplen : sizeof (buf) - offset;
  150. flow_cb ((u_char *) cb_ctxt, &pkthdr, (const u_char *) &buf[offset]);
  151. return 1;
  152. }