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