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.

556 lines
18 KiB

2 years ago
  1. /*
  2. * (C) 2008-2010 by Pablo Neira Ayuso <pablo@netfilter.org>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU Lesser General Public License as published
  6. * by the Free Software Foundation; either version 2.1 of the License, or
  7. * (at your option) any later version.
  8. */
  9. #include <stdbool.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <ctype.h>
  13. #include <errno.h>
  14. #include <string.h>
  15. #include "libmnl.h"
  16. /**
  17. * \defgroup nlmsg Netlink message helpers
  18. *
  19. * Netlink message:
  20. * \verbatim
  21. |<----------------- 4 bytes ------------------->|
  22. |<----- 2 bytes ------>|<------- 2 bytes ------>|
  23. |-----------------------------------------------|
  24. | Message length (including header) |
  25. |-----------------------------------------------|
  26. | Message type | Message flags |
  27. |-----------------------------------------------|
  28. | Message sequence number |
  29. |-----------------------------------------------|
  30. | Netlink PortID |
  31. |-----------------------------------------------|
  32. | |
  33. . Payload .
  34. |_______________________________________________|
  35. \endverbatim
  36. *
  37. * There is usually an extra header after the the Netlink header (at the
  38. * beginning of the payload). This extra header is specific of the Netlink
  39. * subsystem. After this extra header, it comes the sequence of attributes
  40. * that are expressed in Type-Length-Value (TLV) format.
  41. *
  42. * @{
  43. */
  44. /**
  45. * mnl_nlmsg_size - calculate the size of Netlink message (without alignment)
  46. * \param len length of the Netlink payload
  47. *
  48. * This function returns the size of a netlink message (header plus payload)
  49. * without alignment.
  50. */
  51. size_t mnl_nlmsg_size(size_t len)
  52. {
  53. return len + MNL_NLMSG_HDRLEN;
  54. }
  55. /**
  56. * mnl_nlmsg_get_payload_len - get the length of the Netlink payload
  57. * \param nlh pointer to the header of the Netlink message
  58. *
  59. * This function returns the Length of the netlink payload, ie. the length
  60. * of the full message minus the size of the Netlink header.
  61. */
  62. size_t mnl_nlmsg_get_payload_len(const struct nlmsghdr *nlh)
  63. {
  64. return nlh->nlmsg_len - MNL_NLMSG_HDRLEN;
  65. }
  66. /**
  67. * mnl_nlmsg_put_header - reserve and prepare room for Netlink header
  68. * \param buf memory already allocated to store the Netlink header
  69. *
  70. * This function sets to zero the room that is required to put the Netlink
  71. * header in the memory buffer passed as parameter. This function also
  72. * initializes the nlmsg_len field to the size of the Netlink header. This
  73. * function returns a pointer to the Netlink header structure.
  74. */
  75. struct nlmsghdr *mnl_nlmsg_put_header(void *buf)
  76. {
  77. int len = MNL_ALIGN(sizeof(struct nlmsghdr));
  78. struct nlmsghdr *nlh = buf;
  79. memset(buf, 0, len);
  80. nlh->nlmsg_len = len;
  81. return nlh;
  82. }
  83. /**
  84. * mnl_nlmsg_put_extra_header - reserve and prepare room for an extra header
  85. * \param nlh pointer to Netlink header
  86. * \param size size of the extra header that we want to put
  87. *
  88. * This function sets to zero the room that is required to put the extra
  89. * header after the initial Netlink header. This function also increases
  90. * the nlmsg_len field. You have to invoke mnl_nlmsg_put_header() before
  91. * you call this function. This function returns a pointer to the extra
  92. * header.
  93. */
  94. void *mnl_nlmsg_put_extra_header(struct nlmsghdr *nlh,
  95. size_t size)
  96. {
  97. char *ptr = (char *)nlh + nlh->nlmsg_len;
  98. size_t len = MNL_ALIGN(size);
  99. nlh->nlmsg_len += len;
  100. memset(ptr, 0, len);
  101. return ptr;
  102. }
  103. /**
  104. * mnl_nlmsg_get_payload - get a pointer to the payload of the netlink message
  105. * \param nlh pointer to a netlink header
  106. *
  107. * This function returns a pointer to the payload of the netlink message.
  108. */
  109. void *mnl_nlmsg_get_payload(const struct nlmsghdr *nlh)
  110. {
  111. return (void *)nlh + MNL_NLMSG_HDRLEN;
  112. }
  113. /**
  114. * mnl_nlmsg_get_payload_offset - get a pointer to the payload of the message
  115. * \param nlh pointer to a netlink header
  116. * \param offset offset to the payload of the attributes TLV set
  117. *
  118. * This function returns a pointer to the payload of the netlink message plus
  119. * a given offset.
  120. */
  121. void *mnl_nlmsg_get_payload_offset(const struct nlmsghdr *nlh,
  122. size_t offset)
  123. {
  124. return (void *)nlh + MNL_NLMSG_HDRLEN + MNL_ALIGN(offset);
  125. }
  126. /**
  127. * mnl_nlmsg_ok - check a there is room for netlink message
  128. * \param nlh netlink message that we want to check
  129. * \param len remaining bytes in a buffer that contains the netlink message
  130. *
  131. * This function is used to check that a buffer that contains a netlink
  132. * message has enough room for the netlink message that it stores, ie. this
  133. * function can be used to verify that a netlink message is not malformed nor
  134. * truncated.
  135. *
  136. * This function does not set errno in case of error since it is intended
  137. * for iterations. Thus, it returns true on success and false on error.
  138. *
  139. * The len parameter may become negative in malformed messages during message
  140. * iteration, that is why we use a signed integer.
  141. */
  142. bool mnl_nlmsg_ok(const struct nlmsghdr *nlh, int len)
  143. {
  144. return len >= (int)sizeof(struct nlmsghdr) &&
  145. nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
  146. (int)nlh->nlmsg_len <= len;
  147. }
  148. /**
  149. * mnl_nlmsg_next - get the next netlink message in a multipart message
  150. * \param nlh current netlink message that we are handling
  151. * \param len length of the remaining bytes in the buffer (passed by reference).
  152. *
  153. * This function returns a pointer to the next netlink message that is part
  154. * of a multi-part netlink message. Netlink can batch several messages into
  155. * one buffer so that the receiver has to iterate over the whole set of
  156. * Netlink messages.
  157. *
  158. * You have to use mnl_nlmsg_ok() to check if the next Netlink message is
  159. * valid.
  160. */
  161. struct nlmsghdr *mnl_nlmsg_next(const struct nlmsghdr *nlh,
  162. int *len)
  163. {
  164. *len -= MNL_ALIGN(nlh->nlmsg_len);
  165. return (struct nlmsghdr *)((void *)nlh + MNL_ALIGN(nlh->nlmsg_len));
  166. }
  167. /**
  168. * mnl_nlmsg_get_payload_tail - get the ending of the netlink message
  169. * \param nlh pointer to netlink message
  170. *
  171. * This function returns a pointer to the netlink message tail. This is useful
  172. * to build a message since we continue adding attributes at the end of the
  173. * message.
  174. */
  175. void *mnl_nlmsg_get_payload_tail(const struct nlmsghdr *nlh)
  176. {
  177. return (void *)nlh + MNL_ALIGN(nlh->nlmsg_len);
  178. }
  179. /**
  180. * mnl_nlmsg_seq_ok - perform sequence tracking
  181. * \param nlh current netlink message that we are handling
  182. * \param seq last sequence number used to send a message
  183. *
  184. * This functions returns true if the sequence tracking is fulfilled, otherwise
  185. * false is returned. We skip the tracking for netlink messages whose sequence
  186. * number is zero since it is usually reserved for event-based kernel
  187. * notifications. On the other hand, if seq is set but the message sequence
  188. * number is not set (i.e. this is an event message coming from kernel-space),
  189. * then we also skip the tracking. This approach is good if we use the same
  190. * socket to send commands to kernel-space (that we want to track) and to
  191. * listen to events (that we do not track).
  192. */
  193. bool mnl_nlmsg_seq_ok(const struct nlmsghdr *nlh,
  194. unsigned int seq)
  195. {
  196. return nlh->nlmsg_seq && seq ? nlh->nlmsg_seq == seq : true;
  197. }
  198. /**
  199. * mnl_nlmsg_portid_ok - perform portID origin check
  200. * \param nlh current netlink message that we are handling
  201. * \param portid netlink portid that we want to check
  202. *
  203. * This functions returns true if the origin is fulfilled, otherwise
  204. * false is returned. We skip the tracking for netlink message whose portID
  205. * is zero since it is reserved for event-based kernel notifications. On the
  206. * other hand, if portid is set but the message PortID is not (i.e. this
  207. * is an event message coming from kernel-space), then we also skip the
  208. * tracking. This approach is good if we use the same socket to send commands
  209. * to kernel-space (that we want to track) and to listen to events (that we
  210. * do not track).
  211. */
  212. bool mnl_nlmsg_portid_ok(const struct nlmsghdr *nlh,
  213. unsigned int portid)
  214. {
  215. return nlh->nlmsg_pid && portid ? nlh->nlmsg_pid == portid : true;
  216. }
  217. static void mnl_nlmsg_fprintf_header(FILE *fd, const struct nlmsghdr *nlh)
  218. {
  219. fprintf(fd, "----------------\t------------------\n");
  220. fprintf(fd, "| %.010u |\t| message length |\n", nlh->nlmsg_len);
  221. fprintf(fd, "| %.05u | %c%c%c%c |\t| type | flags |\n",
  222. nlh->nlmsg_type,
  223. nlh->nlmsg_flags & NLM_F_REQUEST ? 'R' : '-',
  224. nlh->nlmsg_flags & NLM_F_MULTI ? 'M' : '-',
  225. nlh->nlmsg_flags & NLM_F_ACK ? 'A' : '-',
  226. nlh->nlmsg_flags & NLM_F_ECHO ? 'E' : '-');
  227. fprintf(fd, "| %.010u |\t| sequence number|\n", nlh->nlmsg_seq);
  228. fprintf(fd, "| %.010u |\t| port ID |\n", nlh->nlmsg_pid);
  229. fprintf(fd, "----------------\t------------------\n");
  230. }
  231. static void mnl_nlmsg_fprintf_payload(FILE *fd, const struct nlmsghdr *nlh,
  232. size_t extra_header_size)
  233. {
  234. int rem = 0;
  235. unsigned int i;
  236. for (i=sizeof(struct nlmsghdr); i<nlh->nlmsg_len; i+=4) {
  237. char *b = (char *) nlh;
  238. struct nlattr *attr = (struct nlattr *) (b+i);
  239. /* netlink control message. */
  240. if (nlh->nlmsg_type < NLMSG_MIN_TYPE) {
  241. fprintf(fd, "| %.2x %.2x %.2x %.2x |\t",
  242. 0xff & b[i], 0xff & b[i+1],
  243. 0xff & b[i+2], 0xff & b[i+3]);
  244. fprintf(fd, "| |\n");
  245. /* special handling for the extra header. */
  246. } else if (extra_header_size > 0) {
  247. extra_header_size -= 4;
  248. fprintf(fd, "| %.2x %.2x %.2x %.2x |\t",
  249. 0xff & b[i], 0xff & b[i+1],
  250. 0xff & b[i+2], 0xff & b[i+3]);
  251. fprintf(fd, "| extra header |\n");
  252. /* this seems like an attribute header. */
  253. } else if (rem == 0 && (attr->nla_type & NLA_TYPE_MASK) != 0) {
  254. fprintf(fd, "|%c[%d;%dm"
  255. "%.5u"
  256. "%c[%dm"
  257. "|"
  258. "%c[%d;%dm"
  259. "%c%c"
  260. "%c[%dm"
  261. "|"
  262. "%c[%d;%dm"
  263. "%.5u"
  264. "%c[%dm|\t",
  265. 27, 1, 31,
  266. attr->nla_len,
  267. 27, 0,
  268. 27, 1, 32,
  269. attr->nla_type & NLA_F_NESTED ? 'N' : '-',
  270. attr->nla_type &
  271. NLA_F_NET_BYTEORDER ? 'B' : '-',
  272. 27, 0,
  273. 27, 1, 34,
  274. attr->nla_type & NLA_TYPE_MASK,
  275. 27, 0);
  276. fprintf(fd, "|len |flags| type|\n");
  277. if (!(attr->nla_type & NLA_F_NESTED)) {
  278. rem = NLA_ALIGN(attr->nla_len) -
  279. sizeof(struct nlattr);
  280. }
  281. /* this is the attribute payload. */
  282. } else if (rem > 0) {
  283. rem -= 4;
  284. fprintf(fd, "| %.2x %.2x %.2x %.2x |\t",
  285. 0xff & b[i], 0xff & b[i+1],
  286. 0xff & b[i+2], 0xff & b[i+3]);
  287. fprintf(fd, "| data |");
  288. fprintf(fd, "\t %c %c %c %c\n",
  289. isprint(b[i]) ? b[i] : ' ',
  290. isprint(b[i+1]) ? b[i+1] : ' ',
  291. isprint(b[i+2]) ? b[i+2] : ' ',
  292. isprint(b[i+3]) ? b[i+3] : ' ');
  293. }
  294. }
  295. fprintf(fd, "----------------\t------------------\n");
  296. }
  297. /**
  298. * mnl_nlmsg_fprintf - print netlink message to file
  299. * \param fd pointer to file type
  300. * \param data pointer to the buffer that contains messages to be printed
  301. * \param datalen length of data stored in the buffer
  302. * \param extra_header_size size of the extra header (if any)
  303. *
  304. * This function prints the netlink header to a file handle.
  305. * It may be useful for debugging purposes. One example of the output
  306. * is the following:
  307. *
  308. *\verbatim
  309. ---------------- ------------------
  310. | 0000000040 | | message length |
  311. | 00016 | R-A- | | type | flags |
  312. | 1289148991 | | sequence number|
  313. | 0000000000 | | port ID |
  314. ---------------- ------------------
  315. | 00 00 00 00 | | extra header |
  316. | 00 00 00 00 | | extra header |
  317. | 01 00 00 00 | | extra header |
  318. | 01 00 00 00 | | extra header |
  319. |00008|--|00003| |len |flags| type|
  320. | 65 74 68 30 | | data | e t h 0
  321. ---------------- ------------------
  322. \endverbatim
  323. *
  324. * This example above shows the netlink message that is send to kernel-space
  325. * to set up the link interface eth0. The netlink and attribute header data
  326. * are displayed in base 10 whereas the extra header and the attribute payload
  327. * are expressed in base 16. The possible flags in the netlink header are:
  328. *
  329. * - R, that indicates that NLM_F_REQUEST is set.
  330. * - M, that indicates that NLM_F_MULTI is set.
  331. * - A, that indicates that NLM_F_ACK is set.
  332. * - E, that indicates that NLM_F_ECHO is set.
  333. *
  334. * The lack of one flag is displayed with '-'. On the other hand, the possible
  335. * attribute flags available are:
  336. *
  337. * - N, that indicates that NLA_F_NESTED is set.
  338. * - B, that indicates that NLA_F_NET_BYTEORDER is set.
  339. */
  340. void mnl_nlmsg_fprintf(FILE *fd, const void *data, size_t datalen,
  341. size_t extra_header_size)
  342. {
  343. const struct nlmsghdr *nlh = data;
  344. int len = datalen;
  345. while (mnl_nlmsg_ok(nlh, len)) {
  346. mnl_nlmsg_fprintf_header(fd, nlh);
  347. mnl_nlmsg_fprintf_payload(fd, nlh, extra_header_size);
  348. nlh = mnl_nlmsg_next(nlh, &len);
  349. }
  350. }
  351. /**
  352. * @}
  353. */
  354. /**
  355. * \defgroup batch Netlink message batch helpers
  356. *
  357. * This library provides helpers to batch several messages into one single
  358. * datagram. These helpers do not perform strict memory boundary checkings.
  359. *
  360. * The following figure represents a Netlink message batch:
  361. *
  362. * |<-------------- MNL_SOCKET_BUFFER_SIZE ------------->|
  363. * |<-------------------- batch ------------------>| |
  364. * |-----------|-----------|-----------|-----------|-----------|
  365. * |<- nlmsg ->|<- nlmsg ->|<- nlmsg ->|<- nlmsg ->|<- nlmsg ->|
  366. * |-----------|-----------|-----------|-----------|-----------|
  367. * ^ ^
  368. * | |
  369. * message N message N+1
  370. *
  371. * To start the batch, you have to call mnl_nlmsg_batch_start() and you can
  372. * use mnl_nlmsg_batch_stop() to release it.
  373. *
  374. * You have to invoke mnl_nlmsg_batch_next() to get room for a new message
  375. * in the batch. If this function returns NULL, it means that the last
  376. * message that was added (message N+1 in the figure above) does not fit the
  377. * batch. Thus, you have to send the batch (which includes until message N)
  378. * and, then, you have to call mnl_nlmsg_batch_reset() to re-initialize
  379. * the batch (this moves message N+1 to the head of the buffer). For that
  380. * reason, the buffer that you have to use to store the batch must be double
  381. * of MNL_SOCKET_BUFFER_SIZE to ensure that the last message (message N+1)
  382. * that did not fit into the batch is written inside valid memory boundaries.
  383. *
  384. * @{
  385. */
  386. struct mnl_nlmsg_batch {
  387. /* the buffer that is used to store the batch. */
  388. void *buf;
  389. size_t limit;
  390. size_t buflen;
  391. /* the current netlink message in the batch. */
  392. void *cur;
  393. bool overflow;
  394. };
  395. /**
  396. * mnl_nlmsg_batch_start - initialize a batch
  397. * \param buf pointer to the buffer that will store this batch
  398. * \param limit maximum size of the batch (should be MNL_SOCKET_BUFFER_SIZE).
  399. *
  400. * The buffer that you pass must be double of MNL_SOCKET_BUFFER_SIZE. The
  401. * limit must be half of the buffer size, otherwise expect funny memory
  402. * corruptions 8-).
  403. *
  404. * You can allocate the buffer that you use to store the batch in the stack or
  405. * the heap, no restrictions in this regard. This function returns NULL on
  406. * error.
  407. */
  408. struct mnl_nlmsg_batch *mnl_nlmsg_batch_start(void *buf,
  409. size_t limit)
  410. {
  411. struct mnl_nlmsg_batch *b;
  412. b = malloc(sizeof(struct mnl_nlmsg_batch));
  413. if (b == NULL)
  414. return NULL;
  415. b->buf = buf;
  416. b->limit = limit;
  417. b->buflen = 0;
  418. b->cur = buf;
  419. b->overflow = false;
  420. return b;
  421. }
  422. /**
  423. * mnl_nlmsg_batch_stop - release a batch
  424. * \param b pointer to batch
  425. *
  426. * This function releases the batch allocated by mnl_nlmsg_batch_start().
  427. */
  428. void mnl_nlmsg_batch_stop(struct mnl_nlmsg_batch *b)
  429. {
  430. free(b);
  431. }
  432. /**
  433. * mnl_nlmsg_batch_next - get room for the next message in the batch
  434. * \param b pointer to batch
  435. *
  436. * This function returns false if the last message did not fit into the
  437. * batch. Otherwise, it prepares the batch to provide room for the new
  438. * Netlink message in the batch and returns true.
  439. *
  440. * You have to put at least one message in the batch before calling this
  441. * function, otherwise your application is likely to crash.
  442. */
  443. bool mnl_nlmsg_batch_next(struct mnl_nlmsg_batch *b)
  444. {
  445. struct nlmsghdr *nlh = b->cur;
  446. if (b->buflen + nlh->nlmsg_len > b->limit) {
  447. b->overflow = true;
  448. return false;
  449. }
  450. b->cur = b->buf + b->buflen + nlh->nlmsg_len;
  451. b->buflen += nlh->nlmsg_len;
  452. return true;
  453. }
  454. /**
  455. * mnl_nlmsg_batch_reset - reset the batch
  456. * \param b pointer to batch
  457. *
  458. * This function allows to reset a batch, so you can reuse it to create a
  459. * new one. This function moves the last message which does not fit the
  460. * batch to the head of the buffer, if any.
  461. */
  462. void mnl_nlmsg_batch_reset(struct mnl_nlmsg_batch *b)
  463. {
  464. if (b->overflow) {
  465. struct nlmsghdr *nlh = b->cur;
  466. memcpy(b->buf, b->cur, nlh->nlmsg_len);
  467. b->buflen = nlh->nlmsg_len;
  468. b->cur = b->buf + b->buflen;
  469. b->overflow = false;
  470. } else {
  471. b->buflen = 0;
  472. b->cur = b->buf;
  473. }
  474. }
  475. /**
  476. * mnl_nlmsg_batch_size - get current size of the batch
  477. * \param b pointer to batch
  478. *
  479. * This function returns the current size of the batch.
  480. */
  481. size_t mnl_nlmsg_batch_size(struct mnl_nlmsg_batch *b)
  482. {
  483. return b->buflen;
  484. }
  485. /**
  486. * mnl_nlmsg_batch_head - get head of this batch
  487. * \param b pointer to batch
  488. *
  489. * This function returns a pointer to the head of the batch, which is the
  490. * beginning of the buffer that is used.
  491. */
  492. void *mnl_nlmsg_batch_head(struct mnl_nlmsg_batch *b)
  493. {
  494. return b->buf;
  495. }
  496. /**
  497. * mnl_nlmsg_batch_current - returns current position in the batch
  498. * \param b pointer to batch
  499. *
  500. * This function returns a pointer to the current position in the buffer
  501. * that is used to store the batch.
  502. */
  503. void *mnl_nlmsg_batch_current(struct mnl_nlmsg_batch *b)
  504. {
  505. return b->cur;
  506. }
  507. /**
  508. * mnl_nlmsg_batch_is_empty - check if there is any message in the batch
  509. * \param b pointer to batch
  510. *
  511. * This function returns true if the batch is empty.
  512. */
  513. bool mnl_nlmsg_batch_is_empty(struct mnl_nlmsg_batch *b)
  514. {
  515. return b->buflen == 0;
  516. }
  517. /**
  518. * @}
  519. */