You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

432 lines
13 KiB

  1. From cc919f7013d2d76c8bef0b9c562c1faf98a095a3 Mon Sep 17 00:00:00 2001
  2. From: Ander Juaristi <a@juaristi.eus>
  3. Date: Fri, 26 Apr 2019 09:58:07 +0200
  4. Subject: IPFIX: Introduce template record support
  5. This commit adds the ability to send template records
  6. to the remote collector.
  7. In addition, it also introduces a new
  8. configuration parameter 'send_template', which tells when template
  9. records should be sent. It accepts the following string values:
  10. - "once": Send the template record only the first time (might be coalesced
  11. with data records).
  12. - "always": Send the template record always, with every data record that is sent
  13. to the collector (multiple data records might be sent together).
  14. - "never": Assume the collector knows the schema already. Do not send template records.
  15. If omitted, the default value for 'send_template' is "once".
  16. Signed-off-by: Ander Juaristi <a@juaristi.eus>
  17. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
  18. ---
  19. include/ulogd/ipfix_protocol.h | 1 +
  20. output/ipfix/ipfix.c | 97 +++++++++++++++++++++++++++++++++++++--
  21. output/ipfix/ipfix.h | 22 ++++-----
  22. output/ipfix/ulogd_output_IPFIX.c | 56 ++++++++++++----------
  23. 4 files changed, 139 insertions(+), 37 deletions(-)
  24. diff --git a/include/ulogd/ipfix_protocol.h b/include/ulogd/ipfix_protocol.h
  25. index aef47f0..01dd96a 100644
  26. --- a/include/ulogd/ipfix_protocol.h
  27. +++ b/include/ulogd/ipfix_protocol.h
  28. @@ -129,6 +129,7 @@ enum {
  29. /* reserved */
  30. IPFIX_fragmentOffsetIPv4 = 88,
  31. /* reserved */
  32. + IPFIX_applicationId = 95,
  33. IPFIX_bgpNextAdjacentAsNumber = 128,
  34. IPFIX_bgpPrevAdjacentAsNumber = 129,
  35. IPFIX_exporterIPv4Address = 130,
  36. diff --git a/output/ipfix/ipfix.c b/output/ipfix/ipfix.c
  37. index 60a4c7f..4bb432a 100644
  38. --- a/output/ipfix/ipfix.c
  39. +++ b/output/ipfix/ipfix.c
  40. @@ -2,6 +2,7 @@
  41. * ipfix.c
  42. *
  43. * Holger Eitzenberger, 2009.
  44. + * Ander Juaristi, 2019
  45. */
  46. /* These forward declarations are needed since ulogd.h doesn't like to be the first */
  47. @@ -13,25 +14,107 @@
  48. #include <ulogd/ulogd.h>
  49. #include <ulogd/common.h>
  50. +#include <ulogd/ipfix_protocol.h>
  51. +
  52. +struct ipfix_templ_elem {
  53. + uint16_t id;
  54. + uint16_t len;
  55. +};
  56. +
  57. +struct ipfix_templ {
  58. + unsigned int num_templ_elements;
  59. + struct ipfix_templ_elem templ_elements[];
  60. +};
  61. +
  62. +/* Template fields modeled after vy_ipfix_data */
  63. +static const struct ipfix_templ template = {
  64. + .num_templ_elements = 10,
  65. + .templ_elements = {
  66. + {
  67. + .id = IPFIX_sourceIPv4Address,
  68. + .len = sizeof(uint32_t)
  69. + },
  70. + {
  71. + .id = IPFIX_destinationIPv4Address,
  72. + .len = sizeof(uint32_t)
  73. + },
  74. + {
  75. + .id = IPFIX_packetTotalCount,
  76. + .len = sizeof(uint32_t)
  77. + },
  78. + {
  79. + .id = IPFIX_octetTotalCount,
  80. + .len = sizeof(uint32_t)
  81. + },
  82. + {
  83. + .id = IPFIX_flowStartSeconds,
  84. + .len = sizeof(uint32_t)
  85. + },
  86. + {
  87. + .id = IPFIX_flowEndSeconds,
  88. + .len = sizeof(uint32_t)
  89. + },
  90. + {
  91. + .id = IPFIX_sourceTransportPort,
  92. + .len = sizeof(uint16_t)
  93. + },
  94. + {
  95. + .id = IPFIX_destinationTransportPort,
  96. + .len = sizeof(uint16_t)
  97. + },
  98. + {
  99. + .id = IPFIX_protocolIdentifier,
  100. + .len = sizeof(uint8_t)
  101. + },
  102. + {
  103. + .id = IPFIX_applicationId,
  104. + .len = sizeof(uint32_t)
  105. + }
  106. + }
  107. +};
  108. -struct ipfix_msg *ipfix_msg_alloc(size_t len, uint32_t oid)
  109. +struct ipfix_msg *ipfix_msg_alloc(size_t len, uint32_t oid, int tid)
  110. {
  111. struct ipfix_msg *msg;
  112. struct ipfix_hdr *hdr;
  113. + struct ipfix_templ_hdr *templ_hdr;
  114. + struct ipfix_templ_elem *elem;
  115. + unsigned int i = 0;
  116. - if (len < IPFIX_HDRLEN + IPFIX_SET_HDRLEN)
  117. + if ((tid > 0 && len < IPFIX_HDRLEN + IPFIX_TEMPL_HDRLEN(template.num_templ_elements) + IPFIX_SET_HDRLEN) ||
  118. + (len < IPFIX_HDRLEN + IPFIX_SET_HDRLEN))
  119. return NULL;
  120. msg = malloc(sizeof(struct ipfix_msg) + len);
  121. memset(msg, 0, sizeof(struct ipfix_msg));
  122. - msg->tail = msg->data + IPFIX_HDRLEN;
  123. + msg->tid = tid;
  124. msg->end = msg->data + len;
  125. + msg->tail = msg->data + IPFIX_HDRLEN;
  126. + if (tid > 0)
  127. + msg->tail += IPFIX_TEMPL_HDRLEN(template.num_templ_elements);
  128. + /* Initialize message header */
  129. hdr = ipfix_msg_hdr(msg);
  130. memset(hdr, 0, IPFIX_HDRLEN);
  131. hdr->version = htons(IPFIX_VERSION);
  132. hdr->oid = htonl(oid);
  133. + if (tid > 0) {
  134. + /* Initialize template record header */
  135. + templ_hdr = ipfix_msg_templ_hdr(msg);
  136. + templ_hdr->sid = htons(2);
  137. + templ_hdr->tid = htons(tid);
  138. + templ_hdr->len = htons(IPFIX_TEMPL_HDRLEN(template.num_templ_elements));
  139. + templ_hdr->cnt = htons(template.num_templ_elements);
  140. +
  141. + while (i < template.num_templ_elements) {
  142. + elem = (struct ipfix_templ_elem *) &templ_hdr->data[i * 4];
  143. + elem->id = htons(template.templ_elements[i].id);
  144. + elem->len = htons(template.templ_elements[i].len);
  145. + i++;
  146. + }
  147. + }
  148. +
  149. return msg;
  150. }
  151. @@ -47,6 +130,14 @@ void ipfix_msg_free(struct ipfix_msg *msg)
  152. free(msg);
  153. }
  154. +struct ipfix_templ_hdr *ipfix_msg_templ_hdr(const struct ipfix_msg *msg)
  155. +{
  156. + if (msg->tid > 0)
  157. + return (struct ipfix_templ_hdr *) (msg->data + IPFIX_HDRLEN);
  158. +
  159. + return NULL;
  160. +}
  161. +
  162. struct ipfix_hdr *ipfix_msg_hdr(const struct ipfix_msg *msg)
  163. {
  164. return (struct ipfix_hdr *)msg->data;
  165. diff --git a/output/ipfix/ipfix.h b/output/ipfix/ipfix.h
  166. index cdb5a6f..93945fb 100644
  167. --- a/output/ipfix/ipfix.h
  168. +++ b/output/ipfix/ipfix.h
  169. @@ -2,6 +2,7 @@
  170. * ipfix.h
  171. *
  172. * Holger Eitzenberger <holger@eitzenberger.org>, 2009.
  173. + * Ander Juaristi <a@juaristi.eus>, 2019
  174. */
  175. #ifndef IPFIX_H
  176. #define IPFIX_H
  177. @@ -20,17 +21,21 @@ struct ipfix_hdr {
  178. uint8_t data[];
  179. } __packed;
  180. -#define IPFIX_HDRLEN sizeof(struct ipfix_hdr)
  181. +#define IPFIX_HDRLEN sizeof(struct ipfix_hdr)
  182. /*
  183. * IDs 0-255 are reserved for Template Sets. IDs of Data Sets are > 255.
  184. */
  185. struct ipfix_templ_hdr {
  186. - uint16_t id;
  187. + uint16_t sid;
  188. + uint16_t len;
  189. + uint16_t tid;
  190. uint16_t cnt;
  191. uint8_t data[];
  192. } __packed;
  193. +#define IPFIX_TEMPL_HDRLEN(nfields) sizeof(struct ipfix_templ_hdr) + (sizeof(uint16_t) * 2 * nfields)
  194. +
  195. struct ipfix_set_hdr {
  196. #define IPFIX_SET_TEMPL 2
  197. #define IPFIX_SET_OPT_TEMPL 3
  198. @@ -46,6 +51,7 @@ struct ipfix_msg {
  199. uint8_t *tail;
  200. uint8_t *end;
  201. unsigned nrecs;
  202. + int tid;
  203. struct ipfix_set_hdr *last_set;
  204. uint8_t data[];
  205. };
  206. @@ -53,18 +59,14 @@ struct ipfix_msg {
  207. struct vy_ipfix_data {
  208. struct in_addr saddr;
  209. struct in_addr daddr;
  210. - uint16_t ifi_in;
  211. - uint16_t ifi_out;
  212. uint32_t packets;
  213. uint32_t bytes;
  214. uint32_t start; /* Unix time */
  215. uint32_t end; /* Unix time */
  216. uint16_t sport;
  217. uint16_t dport;
  218. - uint32_t aid; /* Application ID */
  219. uint8_t l4_proto;
  220. - uint8_t dscp;
  221. - uint16_t __padding;
  222. + uint32_t aid; /* Application ID */
  223. } __packed;
  224. #define VY_IPFIX_SID 256
  225. @@ -73,13 +75,11 @@ struct vy_ipfix_data {
  226. #define VY_IPFIX_PKT_LEN (IPFIX_HDRLEN + IPFIX_SET_HDRLEN \
  227. + VY_IPFIX_FLOWS * sizeof(struct vy_ipfix_data))
  228. -/* template management */
  229. -size_t ipfix_rec_len(uint16_t);
  230. -
  231. /* message handling */
  232. -struct ipfix_msg *ipfix_msg_alloc(size_t, uint32_t);
  233. +struct ipfix_msg *ipfix_msg_alloc(size_t, uint32_t, int);
  234. void ipfix_msg_free(struct ipfix_msg *);
  235. struct ipfix_hdr *ipfix_msg_hdr(const struct ipfix_msg *);
  236. +struct ipfix_templ_hdr *ipfix_msg_templ_hdr(const struct ipfix_msg *);
  237. size_t ipfix_msg_len(const struct ipfix_msg *);
  238. void *ipfix_msg_data(struct ipfix_msg *);
  239. struct ipfix_set_hdr *ipfix_msg_add_set(struct ipfix_msg *, uint16_t);
  240. diff --git a/output/ipfix/ulogd_output_IPFIX.c b/output/ipfix/ulogd_output_IPFIX.c
  241. index ec143b1..5b59003 100644
  242. --- a/output/ipfix/ulogd_output_IPFIX.c
  243. +++ b/output/ipfix/ulogd_output_IPFIX.c
  244. @@ -3,6 +3,9 @@
  245. *
  246. * ulogd IPFIX Exporter plugin.
  247. *
  248. + * (C) 2009 by Holger Eitzenberger <holger@eitzenberger.org>, Astaro AG
  249. + * (C) 2019 by Ander Juaristi <a@juaristi.eus>
  250. + *
  251. * This program is distributed in the hope that it will be useful,
  252. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  253. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  254. @@ -11,8 +14,6 @@
  255. * You should have received a copy of the GNU General Public License
  256. * along with this program; if not, write to the Free Software
  257. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  258. - *
  259. - * Holger Eitzenberger <holger@eitzenberger.org> Astaro AG 2009
  260. */
  261. #include <unistd.h>
  262. #include <time.h>
  263. @@ -28,6 +29,7 @@
  264. #define DEFAULT_MTU 512 /* RFC 5101, 10.3.3 */
  265. #define DEFAULT_PORT 4739 /* RFC 5101, 10.3.4 */
  266. #define DEFAULT_SPORT 4740
  267. +#define DEFAULT_SEND_TEMPLATE "once"
  268. enum {
  269. OID_CE = 0,
  270. @@ -35,16 +37,18 @@ enum {
  271. PORT_CE,
  272. PROTO_CE,
  273. MTU_CE,
  274. + SEND_TEMPLATE_CE
  275. };
  276. -#define oid_ce(x) (x->ces[OID_CE])
  277. -#define host_ce(x) (x->ces[HOST_CE])
  278. -#define port_ce(x) (x->ces[PORT_CE])
  279. -#define proto_ce(x) (x->ces[PROTO_CE])
  280. -#define mtu_ce(x) (x->ces[MTU_CE])
  281. +#define oid_ce(x) (x->ces[OID_CE])
  282. +#define host_ce(x) (x->ces[HOST_CE])
  283. +#define port_ce(x) (x->ces[PORT_CE])
  284. +#define proto_ce(x) (x->ces[PROTO_CE])
  285. +#define mtu_ce(x) (x->ces[MTU_CE])
  286. +#define send_template_ce(x) (x->ces[SEND_TEMPLATE_CE])
  287. static const struct config_keyset ipfix_kset = {
  288. - .num_ces = 5,
  289. + .num_ces = 6,
  290. .ces = {
  291. {
  292. .key = "oid",
  293. @@ -70,20 +74,21 @@ static const struct config_keyset ipfix_kset = {
  294. .key = "mtu",
  295. .type = CONFIG_TYPE_INT,
  296. .u.value = DEFAULT_MTU
  297. + },
  298. + {
  299. + .key = "send_template",
  300. + .type = CONFIG_TYPE_STRING,
  301. + .u.string = DEFAULT_SEND_TEMPLATE
  302. }
  303. }
  304. };
  305. -struct ipfix_templ {
  306. - struct ipfix_templ *next;
  307. -};
  308. -
  309. struct ipfix_priv {
  310. struct ulogd_fd ufd;
  311. uint32_t seqno;
  312. struct ipfix_msg *msg; /* current message */
  313. struct llist_head list;
  314. - struct ipfix_templ *templates;
  315. + int tid;
  316. int proto;
  317. struct ulogd_timer timer;
  318. struct sockaddr_in sa;
  319. @@ -258,8 +263,8 @@ static void ipfix_timer_cb(struct ulogd_timer *t, void *data)
  320. static int ipfix_configure(struct ulogd_pluginstance *pi, struct ulogd_pluginstance_stack *stack)
  321. {
  322. struct ipfix_priv *priv = (struct ipfix_priv *) &pi->private;
  323. + char *host, *proto, *send_template;
  324. int oid, port, mtu, ret;
  325. - char *host, *proto;
  326. char addr[16];
  327. ret = config_parse_file(pi->id, pi->config_kset);
  328. @@ -271,6 +276,7 @@ static int ipfix_configure(struct ulogd_pluginstance *pi, struct ulogd_pluginsta
  329. port = port_ce(pi->config_kset).u.value;
  330. proto = proto_ce(pi->config_kset).u.string;
  331. mtu = mtu_ce(pi->config_kset).u.value;
  332. + send_template = send_template_ce(pi->config_kset).u.string;
  333. if (!oid) {
  334. ulogd_log(ULOGD_FATAL, "invalid Observation ID\n");
  335. @@ -303,6 +309,8 @@ static int ipfix_configure(struct ulogd_pluginstance *pi, struct ulogd_pluginsta
  336. ulogd_init_timer(&priv->timer, pi, ipfix_timer_cb);
  337. + priv->tid = (strcmp(send_template, "never") ? VY_IPFIX_SID : -1);
  338. +
  339. ulogd_log(ULOGD_INFO, "using IPFIX Collector at %s:%d (MTU %d)\n",
  340. inet_ntop(AF_INET, &priv->sa.sin_addr, addr, sizeof(addr)),
  341. port, mtu);
  342. @@ -410,25 +418,30 @@ static int ipfix_stop(struct ulogd_pluginstance *pi)
  343. static int ipfix_interp(struct ulogd_pluginstance *pi)
  344. {
  345. struct ipfix_priv *priv = (struct ipfix_priv *) &pi->private;
  346. + char saddr[16], daddr[16], *send_template;
  347. struct vy_ipfix_data *data;
  348. int oid, mtu, ret;
  349. - char addr[16];
  350. if (!(GET_FLAGS(pi->input.keys, InIpSaddr) & ULOGD_RETF_VALID))
  351. return ULOGD_IRET_OK;
  352. oid = oid_ce(pi->config_kset).u.value;
  353. mtu = mtu_ce(pi->config_kset).u.value;
  354. + send_template = send_template_ce(pi->config_kset).u.string;
  355. again:
  356. if (!priv->msg) {
  357. - priv->msg = ipfix_msg_alloc(mtu, oid);
  358. + priv->msg = ipfix_msg_alloc(mtu, oid, priv->tid);
  359. if (!priv->msg) {
  360. /* just drop this flow */
  361. ulogd_log(ULOGD_ERROR, "out of memory, dropping flow\n");
  362. return ULOGD_IRET_OK;
  363. }
  364. ipfix_msg_add_set(priv->msg, VY_IPFIX_SID);
  365. +
  366. + /* template sent - do not send it again the next time */
  367. + if (priv->tid == VY_IPFIX_SID && strcmp(send_template, "once") == 0)
  368. + priv->tid = -1;
  369. }
  370. data = ipfix_msg_add_data(priv->msg, sizeof(struct vy_ipfix_data));
  371. @@ -439,8 +452,6 @@ again:
  372. goto again;
  373. }
  374. - data->ifi_in = data->ifi_out = 0;
  375. -
  376. data->saddr.s_addr = ikey_get_u32(&pi->input.keys[InIpSaddr]);
  377. data->daddr.s_addr = ikey_get_u32(&pi->input.keys[InIpDaddr]);
  378. @@ -462,13 +473,12 @@ again:
  379. data->aid = htonl(ikey_get_u32(&pi->input.keys[InCtMark]));
  380. data->l4_proto = ikey_get_u8(&pi->input.keys[InIpProto]);
  381. - data->__padding = 0;
  382. ulogd_log(ULOGD_DEBUG, "Got new packet (packets = %u, bytes = %u, flow = (%u, %u), saddr = %s, daddr = %s, sport = %u, dport = %u)\n",
  383. - ntohl(data->packets), ntohl(data->bytes), ntohl(data->start), ntohl(data->end),
  384. - inet_ntop(AF_INET, &data->saddr.s_addr, addr, sizeof(addr)),
  385. - inet_ntop(AF_INET, &data->daddr.s_addr, addr, sizeof(addr)),
  386. - ntohs(data->sport), ntohs(data->dport));
  387. + ntohl(data->packets), ntohl(data->bytes), ntohl(data->start), ntohl(data->end),
  388. + inet_ntop(AF_INET, &data->saddr.s_addr, saddr, sizeof(saddr)),
  389. + inet_ntop(AF_INET, &data->daddr.s_addr, daddr, sizeof(daddr)),
  390. + ntohs(data->sport), ntohs(data->dport));
  391. if ((ret = send_msgs(pi)) < 0)
  392. return ret;
  393. --
  394. cgit v1.2.1