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