1 /* Copyright 2007-2010 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 as
5 * published by the Free Software Foundation.
7 #include <assert.h> /* assert */
8 #include <endian.h> /* htobe64 */
9 #include <errno.h> /* errno */
10 #include <setjmp.h> /* setjmp, longjmp */
11 #include <stdio.h> /* snprintf */
12 #include <stdarg.h> /* va_* */
13 #include <stdlib.h> /* free */
14 #include <string.h> /* str* */
15 #include <unistd.h> /* getpagesize */
16 #include <net/ethernet.h> /* ETH_ALEN */
17 #include <net/if.h> /* IFNAMSIZ */
19 #include <libipset/compat.h> /* be64toh() */
20 #include <libipset/debug.h> /* D() */
21 #include <libipset/data.h> /* IPSET_OPT_* */
22 #include <libipset/errcode.h> /* ipset_errcode */
23 #include <libipset/print.h> /* ipset_print_* */
24 #include <libipset/types.h> /* struct ipset_type */
25 #include <libipset/transport.h> /* transport */
26 #include <libipset/mnl.h> /* default backend */
27 #include <libipset/utils.h> /* STREQ */
28 #include <libipset/ui.h> /* IPSET_ENV_* */
29 #include <libipset/session.h> /* prototypes */
31 #define IPSET_NEST_MAX 4
33 /* The session structure */
34 struct ipset_session {
35 const struct ipset_transport *transport;/* Transport protocol */
36 struct ipset_handle *handle; /* Transport handler */
37 struct ipset_data *data; /* Input/output data */
39 enum ipset_cmd cmd; /* Current command */
40 uint32_t lineno; /* Current lineno in restore mode */
41 uint32_t printed_set; /* Printed sets so far */
42 char saved_setname[IPSET_MAXNAMELEN]; /* Saved setname */
43 const struct ipset_type *saved_type; /* Saved type */
44 struct nlattr *nested[IPSET_NEST_MAX]; /* Pointer to nest levels */
45 uint8_t nestid; /* Current nest level */
46 bool version_checked; /* Version checked */
48 char outbuf[IPSET_OUTBUFLEN]; /* Output buffer */
49 enum ipset_output_mode mode; /* Output mode */
50 ipset_outfn outfn; /* Output function */
51 /* Error/warning reporting */
52 char report[IPSET_ERRORBUFLEN]; /* Error/report buffer */
55 uint8_t envopts; /* Session env opts */
56 /* Kernel message buffer */
66 * ipset_session_data - return pointer to the data
67 * @session: session structure
69 * Returns the pointer to the data structure of the session.
72 ipset_session_data(const struct ipset_session *session)
79 * ipset_session_handle - return pointer to the handle
80 * @session: session structure
82 * Returns the pointer to the transport handle structure of the session.
85 ipset_session_handle(const struct ipset_session *session)
88 return session->handle;
92 * ipset_saved_type - return pointer to the saved type
93 * @session: session structure
95 * Returns the pointer to the saved type from the last ipset_cmd
96 * It is required to decode type-specific error codes in restore mode.
98 const struct ipset_type *
99 ipset_saved_type(const struct ipset_session *session)
102 return session->saved_type;
106 * ipset_session_lineno - set session lineno
107 * @session: session structure
109 * Set session lineno to report parser errors correctly.
112 ipset_session_lineno(struct ipset_session *session, uint32_t lineno)
115 session->lineno = lineno;
119 * Environment options
123 * ipset_envopt_parse - parse/set environment option
124 * @session: session structure
125 * @opt: environment option
126 * @arg: option argument (unused)
128 * Parse and set an environment option.
130 * Returns 0 on success or a negative error code.
133 ipset_envopt_parse(struct ipset_session *session, int opt,
134 const char *arg UNUSED)
139 case IPSET_ENV_SORTED:
140 case IPSET_ENV_QUIET:
141 case IPSET_ENV_RESOLVE:
142 case IPSET_ENV_EXIST:
143 case IPSET_ENV_LIST_SETNAME:
144 case IPSET_ENV_LIST_HEADER:
145 session->envopts |= opt;
154 * ipset_envopt_test - test environment option
155 * @session: session structure
156 * @opt: environment option
158 * Test whether the environment option is set in the session.
160 * Returns true or false.
163 ipset_envopt_test(struct ipset_session *session, enum ipset_envopt opt)
166 return session->envopts & opt;
170 * ipset_session_output - set the session output mode
171 * @session: session structure
174 * Set the output mode for the session.
176 * Returns 0 on success or a negative error code.
179 ipset_session_output(struct ipset_session *session,
180 enum ipset_output_mode mode)
183 session->mode = mode;
188 * Error and warning reporting
192 * ipset_session_report - fill the report buffer
193 * @session: session structure
195 * @fmt: message format
197 * Fill the report buffer with an error or warning message.
198 * Depending on the report type, set the error or warning
203 int __attribute__((format(printf, 3, 4)))
204 ipset_session_report(struct ipset_session *session,
205 enum ipset_err_type type,
206 const char *fmt, ...)
214 if (session->lineno != 0 && type == IPSET_ERROR) {
215 sprintf(session->report, "Error in line %u: ",
218 offset = strlen(session->report);
221 len = vsnprintf(session->report + offset,
222 IPSET_ERRORBUFLEN - 1 - offset,
226 if (len >= IPSET_ERRORBUFLEN - 1 - offset)
227 session->report[IPSET_ERRORBUFLEN - 1] = '\0';
228 if (strlen(session->report) < IPSET_ERRORBUFLEN - 1)
229 strcat(session->report, "\n");
231 if (type == IPSET_ERROR) {
232 session->errmsg = session->report;
233 session->warnmsg = NULL;
235 session->errmsg = NULL;
236 session->warnmsg = session->report;
242 * ipset_session_reset - reset the report buffer
243 * @session: session structure
245 * Reset the report buffer, the error and warning pointers.
248 ipset_session_report_reset(struct ipset_session *session)
251 session->report[0] = '\0';
252 session->errmsg = session->warnmsg = NULL;
256 * ipset_session_error - return the report buffer as error
257 * @session: session structure
259 * Return the pointer to the report buffer as an error report.
260 * If there is no error message in the buffer, NULL returned.
263 ipset_session_error(const struct ipset_session *session)
267 return session->errmsg;
271 * ipset_session_warning - return the report buffer as warning
272 * @session: session structure
274 * Return the pointer to the report buffer as a warning report.
275 * If there is no warning message in the buffer, NULL returned.
278 ipset_session_warning(const struct ipset_session *session)
282 return session->warnmsg;
286 * Receive data from the kernel
289 struct ipset_attr_policy {
295 /* Attribute policies and mapping to options */
296 static const struct ipset_attr_policy cmd_attrs[] = {
297 [IPSET_ATTR_PROTOCOL] = {
300 [IPSET_ATTR_SETNAME] = {
301 .type = MNL_TYPE_NUL_STRING,
302 .opt = IPSET_SETNAME,
303 .len = IPSET_MAXNAMELEN,
305 [IPSET_ATTR_TYPENAME] = {
306 .type = MNL_TYPE_NUL_STRING,
307 .opt = IPSET_OPT_TYPENAME,
308 .len = IPSET_MAXNAMELEN,
310 /* IPSET_ATTR_SETNAME2 is an alias for IPSET_ATTR_TYPENAME */
311 [IPSET_ATTR_REVISION] = {
313 .opt = IPSET_OPT_REVISION,
315 [IPSET_ATTR_FAMILY] = {
317 .opt = IPSET_OPT_FAMILY,
319 [IPSET_ATTR_FLAGS] = {
320 .type = MNL_TYPE_U32,
321 .opt = IPSET_OPT_FLAGS,
323 [IPSET_ATTR_DATA] = {
324 .type = MNL_TYPE_NESTED,
327 .type = MNL_TYPE_NESTED,
329 [IPSET_ATTR_REVISION_MIN] = {
331 .opt = IPSET_OPT_REVISION_MIN,
333 /* IPSET_ATTR_PROTOCOL_MIN is an alias for IPSET_ATTR_REVISION_MIN */
334 [IPSET_ATTR_LINENO] = {
335 .type = MNL_TYPE_U32,
336 .opt = IPSET_OPT_LINENO,
340 static const struct ipset_attr_policy create_attrs[] = {
342 .type = MNL_TYPE_NESTED,
345 [IPSET_ATTR_IP_TO] = {
346 .type = MNL_TYPE_NESTED,
347 .opt = IPSET_OPT_IP_TO,
349 [IPSET_ATTR_CIDR] = {
351 .opt = IPSET_OPT_CIDR,
353 [IPSET_ATTR_PORT] = {
354 .type = MNL_TYPE_U16,
355 .opt = IPSET_OPT_PORT,
357 [IPSET_ATTR_PORT_TO] = {
358 .type = MNL_TYPE_U16,
359 .opt = IPSET_OPT_PORT_TO,
361 [IPSET_ATTR_TIMEOUT] = {
362 .type = MNL_TYPE_U32,
363 .opt = IPSET_OPT_TIMEOUT,
365 [IPSET_ATTR_PROTO] = {
367 .opt = IPSET_OPT_PROTO,
369 [IPSET_ATTR_CADT_FLAGS] = {
370 .type = MNL_TYPE_U32,
371 .opt = IPSET_OPT_CADT_FLAGS,
374 .type = MNL_TYPE_U32,
377 [IPSET_ATTR_HASHSIZE] = {
378 .type = MNL_TYPE_U32,
379 .opt = IPSET_OPT_HASHSIZE,
381 [IPSET_ATTR_MAXELEM] = {
382 .type = MNL_TYPE_U32,
383 .opt = IPSET_OPT_MAXELEM,
385 [IPSET_ATTR_MARKMASK] = {
386 .type = MNL_TYPE_U32,
387 .opt = IPSET_OPT_MARKMASK,
389 [IPSET_ATTR_NETMASK] = {
391 .opt = IPSET_OPT_NETMASK,
393 [IPSET_ATTR_PROBES] = {
395 .opt = IPSET_OPT_PROBES,
397 [IPSET_ATTR_RESIZE] = {
399 .opt = IPSET_OPT_RESIZE,
401 [IPSET_ATTR_SIZE] = {
402 .type = MNL_TYPE_U32,
403 .opt = IPSET_OPT_SIZE,
405 [IPSET_ATTR_ELEMENTS] = {
406 .type = MNL_TYPE_U32,
407 .opt = IPSET_OPT_ELEMENTS,
409 [IPSET_ATTR_REFERENCES] = {
410 .type = MNL_TYPE_U32,
411 .opt = IPSET_OPT_REFERENCES,
413 [IPSET_ATTR_MEMSIZE] = {
414 .type = MNL_TYPE_U32,
415 .opt = IPSET_OPT_MEMSIZE,
419 static const struct ipset_attr_policy adt_attrs[] = {
421 .type = MNL_TYPE_NESTED,
424 [IPSET_ATTR_IP_TO] = {
425 .type = MNL_TYPE_NESTED,
426 .opt = IPSET_OPT_IP_TO,
428 [IPSET_ATTR_CIDR] = {
430 .opt = IPSET_OPT_CIDR,
432 [IPSET_ATTR_MARK] = {
433 .type = MNL_TYPE_U32,
434 .opt = IPSET_OPT_MARK,
436 [IPSET_ATTR_PORT] = {
437 .type = MNL_TYPE_U16,
438 .opt = IPSET_OPT_PORT,
440 [IPSET_ATTR_PORT_TO] = {
441 .type = MNL_TYPE_U16,
442 .opt = IPSET_OPT_PORT_TO,
444 [IPSET_ATTR_PROTO] = {
446 .opt = IPSET_OPT_PROTO,
448 [IPSET_ATTR_TIMEOUT] = {
449 .type = MNL_TYPE_U32,
450 .opt = IPSET_OPT_TIMEOUT,
452 [IPSET_ATTR_CADT_FLAGS] = {
453 .type = MNL_TYPE_U32,
454 .opt = IPSET_OPT_CADT_FLAGS,
456 [IPSET_ATTR_LINENO] = {
457 .type = MNL_TYPE_U32,
458 .opt = IPSET_OPT_LINENO,
460 [IPSET_ATTR_ETHER] = {
461 .type = MNL_TYPE_BINARY,
462 .opt = IPSET_OPT_ETHER,
465 [IPSET_ATTR_NAME] = {
466 .type = MNL_TYPE_NUL_STRING,
467 .opt = IPSET_OPT_NAME,
468 .len = IPSET_MAXNAMELEN,
470 [IPSET_ATTR_NAMEREF] = {
471 .type = MNL_TYPE_NUL_STRING,
472 .opt = IPSET_OPT_NAMEREF,
473 .len = IPSET_MAXNAMELEN,
476 .type = MNL_TYPE_NESTED,
477 .opt = IPSET_OPT_IP2,
479 [IPSET_ATTR_CIDR2] = {
481 .opt = IPSET_OPT_CIDR2,
483 [IPSET_ATTR_IP2_TO] = {
484 .type = MNL_TYPE_NESTED,
485 .opt = IPSET_OPT_IP2_TO,
487 [IPSET_ATTR_IFACE] = {
488 .type = MNL_TYPE_NUL_STRING,
489 .opt = IPSET_OPT_IFACE,
492 [IPSET_ATTR_PACKETS] = {
493 .type = MNL_TYPE_U64,
494 .opt = IPSET_OPT_PACKETS,
496 [IPSET_ATTR_BYTES] = {
497 .type = MNL_TYPE_U64,
498 .opt = IPSET_OPT_BYTES,
500 [IPSET_ATTR_COMMENT] = {
501 .type = MNL_TYPE_NUL_STRING,
502 .opt = IPSET_OPT_ADT_COMMENT,
503 .len = IPSET_MAX_COMMENT_SIZE + 1,
505 [IPSET_ATTR_SKBMARK] = {
506 .type = MNL_TYPE_U64,
507 .opt = IPSET_OPT_SKBMARK,
509 [IPSET_ATTR_SKBPRIO] = {
510 .type = MNL_TYPE_U32,
511 .opt = IPSET_OPT_SKBPRIO,
513 [IPSET_ATTR_SKBQUEUE] = {
514 .type = MNL_TYPE_U16,
515 .opt = IPSET_OPT_SKBQUEUE,
518 .type = MNL_TYPE_UNSPEC,
523 static const struct ipset_attr_policy ipaddr_attrs[] = {
524 [IPSET_ATTR_IPADDR_IPV4] = {
525 .type = MNL_TYPE_U32,
527 [IPSET_ATTR_IPADDR_IPV6] = {
528 .type = MNL_TYPE_BINARY,
529 .len = sizeof(union nf_inet_addr),
534 static int debug = 1;
538 generic_data_attr_cb(const struct nlattr *attr, void *data,
539 int attr_max, const struct ipset_attr_policy *policy)
541 const struct nlattr **tb = data;
542 int type = mnl_attr_get_type(attr);
544 IF_D(debug, "attr type: %u, len %u", type, attr->nla_len);
545 if (mnl_attr_type_valid(attr, attr_max) < 0) {
546 IF_D(debug, "attr type: %u INVALID", type);
549 if (mnl_attr_validate(attr, policy[type].type) < 0) {
550 IF_D(debug, "attr type: %u POLICY, attrlen %u", type,
551 mnl_attr_get_payload_len(attr));
554 if (policy[type].type == MNL_TYPE_NUL_STRING &&
555 mnl_attr_get_payload_len(attr) > policy[type].len)
562 create_attr_cb(const struct nlattr *attr, void *data)
564 return generic_data_attr_cb(attr, data,
565 IPSET_ATTR_CREATE_MAX, create_attrs);
569 adt_attr_cb(const struct nlattr *attr, void *data)
571 return generic_data_attr_cb(attr, data,
572 IPSET_ATTR_ADT_MAX, adt_attrs);
576 ipaddr_attr_cb(const struct nlattr *attr, void *data)
578 return generic_data_attr_cb(attr, data,
579 IPSET_ATTR_IPADDR_MAX, ipaddr_attrs);
582 #define FAILURE(format, args...) \
583 { ipset_err(session, format , ## args); return MNL_CB_ERROR; }
586 attr2data(struct ipset_session *session, struct nlattr *nla[],
587 int type, const struct ipset_attr_policy attrs[])
589 struct ipset_data *data = session->data;
590 const struct ipset_attr_policy *attr;
598 d = mnl_attr_get_payload(nla[type]);
600 if (attr->type == MNL_TYPE_UNSPEC)
602 if (attr->type == MNL_TYPE_NESTED && attr->opt) {
604 struct nlattr *ipattr[IPSET_ATTR_IPADDR_MAX+1] = {};
605 uint8_t family = ipset_data_family(data);
607 D("IP attr type %u", type);
608 if (mnl_attr_parse_nested(nla[type],
609 ipaddr_attr_cb, ipattr) < 0)
610 FAILURE("Broken kernel message, cannot validate "
611 "IP address attribute!");
613 /* Validate by hand */
616 atype = IPSET_ATTR_IPADDR_IPV4;
618 FAILURE("Broken kernel message: IPv4 address "
619 "expected but not received!");
620 if (ipattr[atype]->nla_len < sizeof(uint32_t))
621 FAILURE("Broken kernel message: "
622 "cannot validate IPv4 "
623 "address attribute!");
626 atype = IPSET_ATTR_IPADDR_IPV6;
628 FAILURE("Broken kernel message: IPv6 address "
629 "expected but not received!");
630 if (ipattr[atype]->nla_len < sizeof(struct in6_addr))
631 FAILURE("Broken kernel message: "
632 "cannot validate IPv6 "
633 "address attribute!");
636 FAILURE("Broken kernel message: "
637 "IP address attribute but "
638 "family is unspecified!");
640 d = mnl_attr_get_payload(ipattr[atype]);
641 } else if (nla[type]->nla_type & NLA_F_NET_BYTEORDER) {
642 D("netorder attr type %u", type);
643 switch (attr->type) {
646 /* Ensure data alignment */
647 memcpy(&tmp, d, sizeof(tmp));
653 v32 = ntohl(*(const uint32_t *)d);
658 v16 = ntohs(*(const uint16_t *)d);
668 D("hostorder attr type %u", type);
669 if (type == IPSET_ATTR_TYPENAME)
670 D("nla typename %s", (const char *) d);
672 ret = ipset_data_set(data, attr->opt, d);
674 if (type == IPSET_ATTR_TYPENAME)
676 (const char *) ipset_data_get(data, IPSET_OPT_TYPENAME));
681 #define ATTR2DATA(session, nla, type, attrs) \
682 if (attr2data(session, nla, type, attrs) < 0) \
685 static const char cmd2name[][9] = {
686 [IPSET_CMD_NONE] = "NONE",
687 [IPSET_CMD_CREATE] = "CREATE",
688 [IPSET_CMD_DESTROY] = "DESTROY",
689 [IPSET_CMD_FLUSH] = "FLUSH",
690 [IPSET_CMD_RENAME] = "RENAME",
691 [IPSET_CMD_SWAP] = "SWAP",
692 [IPSET_CMD_LIST] = "LIST",
693 [IPSET_CMD_SAVE] = "SAVE",
694 [IPSET_CMD_ADD] = "ADD",
695 [IPSET_CMD_DEL] = "DEL",
696 [IPSET_CMD_TEST] = "TEST",
697 [IPSET_CMD_HEADER] = "HEADER",
698 [IPSET_CMD_TYPE] = "TYPE",
699 [IPSET_CMD_PROTOCOL] = "PROTOCOL",
703 call_outfn(struct ipset_session *session)
705 int ret = session->outfn("%s", session->outbuf);
707 session->outbuf[0] = '\0';
709 return ret < 0 ? ret : 0;
712 /* Handle printing failures */
713 static jmp_buf printf_failure;
716 handle_snprintf_error(struct ipset_session *session,
717 int len, int ret, int loop)
719 if (ret < 0 || ret >= IPSET_OUTBUFLEN - len) {
720 /* Buffer was too small, push it out and retry */
721 D("print buffer and try again: len: %u, ret: %d", len, ret);
724 "Internal error at printing, loop detected!");
725 longjmp(printf_failure, 1);
728 session->outbuf[len] = '\0';
729 if (call_outfn(session)) {
731 "Internal error, could not print output buffer!");
732 longjmp(printf_failure, 1);
739 static int __attribute__((format(printf, 2, 3)))
740 safe_snprintf(struct ipset_session *session, const char *fmt, ...)
743 int len, ret, loop = 0;
746 len = strlen(session->outbuf);
747 D("len: %u, retry %u", len, loop);
749 ret = vsnprintf(session->outbuf + len,
750 IPSET_OUTBUFLEN - len,
753 loop = handle_snprintf_error(session, len, ret, loop);
760 safe_dprintf(struct ipset_session *session, ipset_printfn fn,
763 int len, ret, loop = 0;
766 len = strlen(session->outbuf);
767 D("len: %u, retry %u", len, loop);
768 ret = fn(session->outbuf + len, IPSET_OUTBUFLEN - len,
769 session->data, opt, session->envopts);
770 loop = handle_snprintf_error(session, len, ret, loop);
777 list_adt(struct ipset_session *session, struct nlattr *nla[])
779 const struct ipset_data *data = session->data;
780 const struct ipset_type *type;
781 const struct ipset_arg *arg;
785 /* Check and load type, family */
786 if (!ipset_data_test(data, IPSET_OPT_TYPE))
787 type = ipset_type_get(session, IPSET_CMD_ADD);
789 type = ipset_data_get(data, IPSET_OPT_TYPE);
794 for (i = IPSET_ATTR_UNSPEC + 1; i <= IPSET_ATTR_ADT_MAX; i++)
797 ATTR2DATA(session, nla, i, adt_attrs);
799 D("attr found %u", found);
803 switch (session->mode) {
804 case IPSET_LIST_SAVE:
805 safe_snprintf(session, "add %s ", ipset_data_setname(data));
808 safe_snprintf(session, "<member><elem>");
810 case IPSET_LIST_PLAIN:
815 safe_dprintf(session, ipset_print_elem, IPSET_OPT_ELEM);
816 if (session->mode == IPSET_LIST_XML)
817 safe_snprintf(session, "</elem>");
819 for (arg = type->args[IPSET_ADD]; arg != NULL && arg->opt; arg++) {
820 D("print arg opt %u %s", arg->opt,
821 ipset_data_test(data, arg->opt) ? "(yes)" : "(missing)");
822 if (!(arg->print && ipset_data_test(data, arg->opt)))
824 switch (session->mode) {
825 case IPSET_LIST_SAVE:
826 case IPSET_LIST_PLAIN:
827 if (arg->has_arg == IPSET_NO_ARG) {
828 safe_snprintf(session, " %s", arg->name[0]);
831 safe_snprintf(session, " %s ", arg->name[0]);
832 safe_dprintf(session, arg->print, arg->opt);
835 if (arg->has_arg == IPSET_NO_ARG) {
836 safe_snprintf(session,
837 "<%s/>", arg->name[0]);
840 safe_snprintf(session, "<%s>", arg->name[0]);
841 safe_dprintf(session, arg->print, arg->opt);
842 safe_snprintf(session, "</%s>", arg->name[0]);
849 if (session->mode == IPSET_LIST_XML)
850 safe_snprintf(session, "</member>\n");
852 safe_snprintf(session, "\n");
857 #define FAMILY_TO_STR(f) \
858 ((f) == NFPROTO_IPV4 ? "inet" : \
859 (f) == NFPROTO_IPV6 ? "inet6" : "any")
862 list_create(struct ipset_session *session, struct nlattr *nla[])
864 const struct ipset_data *data = session->data;
865 const struct ipset_type *type;
866 const struct ipset_arg *arg;
870 for (i = IPSET_ATTR_UNSPEC + 1; i <= IPSET_ATTR_CREATE_MAX; i++)
872 D("add attr %u, opt %u", i, create_attrs[i].opt);
873 ATTR2DATA(session, nla, i, create_attrs);
876 type = ipset_type_check(session);
879 family = ipset_data_family(data);
881 switch (session->mode) {
882 case IPSET_LIST_SAVE:
883 safe_snprintf(session, "create %s %s",
884 ipset_data_setname(data),
887 case IPSET_LIST_PLAIN:
888 safe_snprintf(session, "%sName: %s\n"
889 "Type: %s\nRevision: %u\nHeader:",
890 session->printed_set ? "\n" : "",
891 ipset_data_setname(data),
892 type->name, type->revision);
895 safe_snprintf(session,
896 "<ipset name=\"%s\">\n"
898 "<revision>%u</revision>\n"
900 ipset_data_setname(data),
901 type->name, type->revision);
907 for (arg = type->args[IPSET_CREATE]; arg != NULL && arg->opt; arg++) {
909 !ipset_data_test(data, arg->opt) ||
910 (arg->opt == IPSET_OPT_FAMILY &&
911 family == type->family))
913 switch (session->mode) {
914 case IPSET_LIST_SAVE:
915 case IPSET_LIST_PLAIN:
916 if (arg->has_arg == IPSET_NO_ARG) {
917 safe_snprintf(session, " %s", arg->name[0]);
920 safe_snprintf(session, " %s ", arg->name[0]);
921 safe_dprintf(session, arg->print, arg->opt);
924 if (arg->has_arg == IPSET_NO_ARG) {
925 safe_snprintf(session,
926 "<%s/>", arg->name[0]);
929 safe_snprintf(session, "<%s>", arg->name[0]);
930 safe_dprintf(session, arg->print, arg->opt);
931 safe_snprintf(session, "</%s>", arg->name[0]);
937 switch (session->mode) {
938 case IPSET_LIST_SAVE:
939 safe_snprintf(session, "\n");
941 case IPSET_LIST_PLAIN:
942 safe_snprintf(session, "\nSize in memory: ");
943 safe_dprintf(session, ipset_print_number, IPSET_OPT_MEMSIZE);
944 safe_snprintf(session, "\nReferences: ");
945 safe_dprintf(session, ipset_print_number, IPSET_OPT_REFERENCES);
946 if (ipset_data_test(data, IPSET_OPT_ELEMENTS)) {
947 safe_snprintf(session, "\nNumber of entries: ");
948 safe_dprintf(session, ipset_print_number, IPSET_OPT_ELEMENTS);
950 safe_snprintf(session,
951 session->envopts & IPSET_ENV_LIST_HEADER ?
952 "\n" : "\nMembers:\n");
955 safe_snprintf(session, "\n<memsize>");
956 safe_dprintf(session, ipset_print_number, IPSET_OPT_MEMSIZE);
957 safe_snprintf(session, "</memsize>\n<references>");
958 safe_dprintf(session, ipset_print_number, IPSET_OPT_REFERENCES);
959 safe_snprintf(session, "</references>\n");
960 if (ipset_data_test(data, IPSET_OPT_ELEMENTS)) {
961 safe_snprintf(session, "<numentries>");
962 safe_dprintf(session, ipset_print_number, IPSET_OPT_ELEMENTS);
963 safe_snprintf(session, "</numentries>\n");
965 safe_snprintf(session,
966 session->envopts & IPSET_ENV_LIST_HEADER ?
968 "</header>\n<members>\n");
973 session->printed_set++;
979 print_set_done(struct ipset_session *session, bool callback_done)
981 D("called for %s", session->saved_setname[0] == '\0'
982 ? "NONE" : session->saved_setname);
983 switch (session->mode) {
985 if (session->envopts & IPSET_ENV_LIST_SETNAME)
987 if (session->envopts & IPSET_ENV_LIST_HEADER) {
988 if (session->saved_setname[0] != '\0')
989 safe_snprintf(session, "</ipset>\n");
992 if (session->saved_setname[0] != '\0')
993 safe_snprintf(session, "</members>\n</ipset>\n");
998 if (callback_done && session->mode == IPSET_LIST_XML)
999 safe_snprintf(session, "</ipsets>\n");
1000 return call_outfn(session) ? MNL_CB_ERROR : MNL_CB_STOP;
1004 callback_list(struct ipset_session *session, struct nlattr *nla[],
1007 struct ipset_data *data = session->data;
1009 if (setjmp(printf_failure)) {
1010 session->saved_setname[0] = '\0';
1011 session->printed_set = 0;
1012 return MNL_CB_ERROR;
1015 if (!nla[IPSET_ATTR_SETNAME])
1016 FAILURE("Broken %s kernel message: missing setname!",
1019 ATTR2DATA(session, nla, IPSET_ATTR_SETNAME, cmd_attrs);
1020 D("setname %s", ipset_data_setname(data));
1021 if (session->envopts & IPSET_ENV_LIST_SETNAME &&
1022 session->mode != IPSET_LIST_SAVE) {
1023 if (session->mode == IPSET_LIST_XML)
1024 safe_snprintf(session, "<ipset name=\"%s\"/>\n",
1025 ipset_data_setname(data));
1027 safe_snprintf(session, "%s\n",
1028 ipset_data_setname(data));
1029 return call_outfn(session) ? MNL_CB_ERROR : MNL_CB_OK;
1032 if (STREQ(ipset_data_setname(data), session->saved_setname)) {
1033 /* Header part already seen */
1034 if (ipset_data_test(data, IPSET_OPT_TYPE) &&
1035 nla[IPSET_ATTR_DATA] != NULL)
1036 FAILURE("Broken %s kernel message: "
1037 "extra DATA received!", cmd2name[cmd]);
1039 if (nla[IPSET_ATTR_DATA] == NULL)
1040 FAILURE("Broken %s kernel message: "
1041 "missing DATA part!", cmd2name[cmd]);
1043 /* Close previous set printing */
1044 if (session->saved_setname[0] != '\0')
1045 print_set_done(session, false);
1048 if (nla[IPSET_ATTR_DATA] != NULL) {
1049 struct nlattr *cattr[IPSET_ATTR_CREATE_MAX+1] = {};
1051 if (!(nla[IPSET_ATTR_TYPENAME] &&
1052 nla[IPSET_ATTR_FAMILY] &&
1053 nla[IPSET_ATTR_REVISION]))
1054 FAILURE("Broken %s kernel message: missing %s!",
1056 !nla[IPSET_ATTR_TYPENAME] ? "typename" :
1057 !nla[IPSET_ATTR_FAMILY] ? "family" :
1060 /* Reset CREATE specific flags */
1061 ipset_data_flags_unset(data, IPSET_CREATE_FLAGS);
1062 D("nla typename %s",
1063 (char *) mnl_attr_get_payload(nla[IPSET_ATTR_TYPENAME]));
1065 ATTR2DATA(session, nla, IPSET_ATTR_FAMILY, cmd_attrs);
1066 ATTR2DATA(session, nla, IPSET_ATTR_TYPENAME, cmd_attrs);
1067 ATTR2DATA(session, nla, IPSET_ATTR_REVISION, cmd_attrs);
1068 D("head: family %u, typename %s",
1069 ipset_data_family(data),
1070 (const char *) ipset_data_get(data, IPSET_OPT_TYPENAME));
1071 if (mnl_attr_parse_nested(nla[IPSET_ATTR_DATA],
1072 create_attr_cb, cattr) < 0)
1073 FAILURE("Broken %s kernel message: "
1074 "cannot validate DATA attributes!",
1076 if (list_create(session, cattr) != MNL_CB_OK)
1077 return MNL_CB_ERROR;
1078 strcpy(session->saved_setname, ipset_data_setname(data));
1081 if (nla[IPSET_ATTR_ADT] != NULL) {
1082 struct nlattr *tb, *adt[IPSET_ATTR_ADT_MAX+1];
1084 mnl_attr_for_each_nested(tb, nla[IPSET_ATTR_ADT]) {
1085 D("ADT attributes for %s", ipset_data_setname(data));
1086 memset(adt, 0, sizeof(adt));
1087 /* Reset ADT specific flags */
1088 ipset_data_flags_unset(data, IPSET_ADT_FLAGS);
1089 if (mnl_attr_parse_nested(tb, adt_attr_cb, adt) < 0)
1090 FAILURE("Broken %s kernel message: "
1091 "cannot validate ADT attributes!",
1093 if (list_adt(session, adt) != MNL_CB_OK)
1094 return MNL_CB_ERROR;
1097 return call_outfn(session) ? MNL_CB_ERROR : MNL_CB_OK;
1100 #ifndef IPSET_PROTOCOL_MIN
1101 #define IPSET_PROTOCOL_MIN IPSET_PROTOCOL
1104 #ifndef IPSET_PROTOCOL_MAX
1105 #define IPSET_PROTOCOL_MAX IPSET_PROTOCOL
1109 callback_version(struct ipset_session *session, struct nlattr *nla[])
1113 min = max = mnl_attr_get_u8(nla[IPSET_ATTR_PROTOCOL]);
1115 if (nla[IPSET_ATTR_PROTOCOL_MIN]) {
1116 min = mnl_attr_get_u8(nla[IPSET_ATTR_PROTOCOL_MIN]);
1120 if (min > IPSET_PROTOCOL_MAX || max < IPSET_PROTOCOL_MIN)
1121 FAILURE("Cannot communicate with kernel: "
1122 "Kernel support protocol versions %u-%u "
1123 "while userspace supports protocol versions %u-%u",
1124 min, max, IPSET_PROTOCOL_MIN, IPSET_PROTOCOL_MAX);
1126 if (!(session->envopts & IPSET_ENV_QUIET) &&
1127 max != IPSET_PROTOCOL_MAX)
1129 "Kernel support protocol versions %u-%u "
1130 "while userspace supports protocol versions %u-%u",
1131 min, max, IPSET_PROTOCOL_MIN, IPSET_PROTOCOL_MAX);
1133 session->version_checked = true;
1139 callback_header(struct ipset_session *session, struct nlattr *nla[])
1141 const char *setname;
1142 const struct ipset_data *data = session->data;
1144 if (!nla[IPSET_ATTR_SETNAME])
1145 FAILURE("Broken HEADER kernel message: missing setname!");
1147 setname = mnl_attr_get_str(nla[IPSET_ATTR_SETNAME]);
1148 if (!STREQ(setname, ipset_data_setname(data)))
1149 FAILURE("Broken HEADER kernel message: sent setname `%s' "
1150 "does not match with received one `%s'!",
1151 ipset_data_setname(data), setname);
1153 if (!(nla[IPSET_ATTR_TYPENAME] &&
1154 nla[IPSET_ATTR_REVISION] &&
1155 nla[IPSET_ATTR_FAMILY]))
1156 FAILURE("Broken HEADER kernel message: "
1157 "missing attribute '%s'!",
1158 !nla[IPSET_ATTR_TYPENAME] ? "typename" :
1159 !nla[IPSET_ATTR_REVISION] ? "revision" :
1162 ATTR2DATA(session, nla, IPSET_ATTR_TYPENAME, cmd_attrs);
1163 ATTR2DATA(session, nla, IPSET_ATTR_REVISION, cmd_attrs);
1164 ATTR2DATA(session, nla, IPSET_ATTR_FAMILY, cmd_attrs);
1165 D("got family: %u", ipset_data_family(session->data));
1171 callback_type(struct ipset_session *session, struct nlattr *nla[])
1173 const struct ipset_data *data = session->data;
1174 const char *typename, *orig;
1176 if (!(nla[IPSET_ATTR_TYPENAME] &&
1177 nla[IPSET_ATTR_REVISION] &&
1178 nla[IPSET_ATTR_FAMILY]))
1179 FAILURE("Broken TYPE kernel message: "
1180 "missing attribute '%s'!",
1181 !nla[IPSET_ATTR_TYPENAME] ? "typename" :
1182 !nla[IPSET_ATTR_REVISION] ? "revision" :
1185 typename = mnl_attr_get_str(nla[IPSET_ATTR_TYPENAME]);
1186 orig = ipset_data_get(data, IPSET_OPT_TYPENAME);
1187 if (!STREQ(typename, orig))
1188 FAILURE("Broken TYPE kernel message: sent typename `%s' "
1189 "does not match with received one `%s'!",
1192 ATTR2DATA(session, nla, IPSET_ATTR_TYPENAME, cmd_attrs);
1193 ATTR2DATA(session, nla, IPSET_ATTR_REVISION, cmd_attrs);
1194 ATTR2DATA(session, nla, IPSET_ATTR_FAMILY, cmd_attrs);
1195 if (nla[IPSET_ATTR_REVISION_MIN])
1196 ATTR2DATA(session, nla, IPSET_ATTR_REVISION_MIN, cmd_attrs);
1202 cmd_attr_cb(const struct nlattr *attr, void *data)
1204 return generic_data_attr_cb(attr, data, IPSET_ATTR_CMD_MAX, cmd_attrs);
1209 mnl_attr_parse_dbg(const struct nlmsghdr *nlh, int offset,
1210 mnl_attr_cb_t cb, void *data)
1212 int ret = MNL_CB_OK;
1213 struct nlattr *attr = mnl_nlmsg_get_payload_offset(nlh, offset);
1214 int len = nlh->nlmsg_len - MNL_NLMSG_HDRLEN - MNL_ALIGN(offset);
1216 while (mnl_attr_ok(attr, len)) {
1217 D("attr: type %u, attrlen %u, len %u",
1218 mnl_attr_get_type(attr), attr->nla_len, len);
1219 if (cb && (ret = cb(attr, data)) <= MNL_CB_STOP)
1221 attr = mnl_attr_next(attr, &len);
1228 callback_data(const struct nlmsghdr *nlh, void *data)
1230 struct ipset_session *session = data;
1231 struct nlattr *nla[IPSET_ATTR_CMD_MAX+1] = {};
1233 int ret = MNL_CB_OK, nfmsglen = MNL_ALIGN(sizeof(struct nfgenmsg));
1235 D("called, nlmsg_len %u", nlh->nlmsg_len);
1236 cmd = ipset_get_nlmsg_type(nlh);
1237 if (cmd == IPSET_CMD_LIST && session->cmd == IPSET_CMD_SAVE)
1238 /* Kernel always send IPSET_CMD_LIST */
1239 cmd = IPSET_CMD_SAVE;
1241 if (cmd != session->cmd)
1242 FAILURE("Protocol error, we sent command %s "
1243 "and received %s[%u]",
1244 cmd2name[session->cmd],
1245 cmd < IPSET_MSG_MAX ? cmd2name[cmd] : "unknown", cmd);
1247 if (mnl_attr_parse(nlh, nfmsglen, cmd_attr_cb, nla) < MNL_CB_STOP)
1248 FAILURE("Broken %s kernel message: "
1249 "cannot validate and parse attributes",
1252 if (!nla[IPSET_ATTR_PROTOCOL])
1253 FAILURE("Sad, sad day: kernel message %s "
1254 "does not carry the protocol version.",
1257 proto = mnl_attr_get_u8(nla[IPSET_ATTR_PROTOCOL]);
1259 /* Check protocol */
1260 if (cmd != IPSET_CMD_PROTOCOL && proto != IPSET_PROTOCOL)
1261 FAILURE("Giving up: kernel protocol version %u "
1262 "does not match our protocol version %u",
1263 proto, IPSET_PROTOCOL);
1265 D("Message: %s", cmd2name[cmd]);
1267 case IPSET_CMD_LIST:
1268 case IPSET_CMD_SAVE:
1269 ret = callback_list(session, nla, cmd);
1270 D("flag multi: %u", nlh->nlmsg_flags & NLM_F_MULTI);
1271 if (ret >= MNL_CB_STOP && !(nlh->nlmsg_flags & NLM_F_MULTI))
1272 ret = print_set_done(session, false);
1274 case IPSET_CMD_PROTOCOL:
1275 if (!session->version_checked)
1276 ret = callback_version(session, nla);
1278 case IPSET_CMD_HEADER:
1279 ret = callback_header(session, nla);
1281 case IPSET_CMD_TYPE:
1282 ret = callback_type(session, nla);
1285 FAILURE("Data message received when not expected at %s",
1286 cmd2name[session->cmd]);
1288 D("return code: %s", ret == MNL_CB_STOP ? "stop" :
1289 ret == MNL_CB_OK ? "ok" : "error");
1294 callback_done(const struct nlmsghdr *nlh UNUSED, void *data)
1296 struct ipset_session *session = data;
1299 if (session->cmd == IPSET_CMD_LIST || session->cmd == IPSET_CMD_SAVE)
1300 return print_set_done(session, true);
1302 FAILURE("Invalid message received in non LIST or SAVE state.");
1306 decode_errmsg(struct ipset_session *session, const struct nlmsghdr *nlh)
1308 const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
1309 const struct nlmsghdr *msg = &err->msg;
1310 struct nlattr *nla[IPSET_ATTR_CMD_MAX+1] = {};
1312 int nfmsglen = MNL_ALIGN(sizeof(struct nfgenmsg));
1314 if (nlh->nlmsg_len < (uint32_t) MNL_ALIGN(sizeof(struct nlmsgerr)) ||
1315 nlh->nlmsg_len < MNL_ALIGN(sizeof(struct nlmsgerr))
1317 FAILURE("Broken error report message received.");
1319 cmd = ipset_get_nlmsg_type(msg);
1320 D("nlsmg_len: %u", msg->nlmsg_len);
1321 if (cmd != session->cmd)
1322 FAILURE("Protocol error, we sent command %s "
1323 "and received error report for %s[%u]",
1324 cmd2name[session->cmd],
1325 cmd < IPSET_MSG_MAX ? cmd2name[cmd] : "unknown", cmd);
1327 if (mnl_attr_parse(msg, nfmsglen, cmd_attr_cb, nla) < MNL_CB_STOP)
1328 FAILURE("Broken %s error report message: "
1329 "cannot validate attributes",
1332 if (!nla[IPSET_ATTR_PROTOCOL])
1333 FAILURE("Broken %s error report message: "
1334 "missing protocol attribute",
1337 if (nla[IPSET_ATTR_LINENO]) {
1338 session->lineno = mnl_attr_get_u32(nla[IPSET_ATTR_LINENO]);
1339 if (nla[IPSET_ATTR_LINENO]->nla_type & NLA_F_NET_BYTEORDER)
1340 session->lineno = ntohl(session->lineno);
1343 return ipset_errcode(session, cmd, -err->error);
1347 callback_error(const struct nlmsghdr *nlh, void *cbdata)
1349 struct ipset_session *session = cbdata;
1350 struct ipset_data *data = session->data;
1351 const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
1352 int ret = MNL_CB_ERROR;
1354 D(" called, cmd %s", cmd2name[session->cmd]);
1355 if (nlh->nlmsg_len < mnl_nlmsg_size(sizeof(struct nlmsgerr)))
1356 FAILURE("Broken error message received.");
1358 if (err->error == 0) {
1362 switch (session->cmd) {
1363 case IPSET_CMD_CREATE:
1364 /* Add successfully created set to the cache */
1365 ipset_cache_add(ipset_data_setname(data),
1366 ipset_data_get(data, IPSET_OPT_TYPE),
1367 ipset_data_family(data));
1369 case IPSET_CMD_DESTROY:
1370 /* Delete destroyed sets from the cache */
1371 ipset_cache_del(ipset_data_setname(data));
1373 case IPSET_CMD_FLUSH:
1375 case IPSET_CMD_RENAME:
1376 ipset_cache_rename(ipset_data_setname(data),
1377 ipset_data_get(data,
1378 IPSET_OPT_SETNAME2));
1380 case IPSET_CMD_SWAP:
1381 ipset_cache_swap(ipset_data_setname(data),
1382 ipset_data_get(data,
1383 IPSET_OPT_SETNAME2));
1385 case IPSET_CMD_TEST:
1386 if (!(session->envopts & IPSET_ENV_QUIET)) {
1387 ipset_print_elem(session->report,
1391 ipset_warn(session, " is in set %s.",
1392 ipset_data_setname(data));
1398 case IPSET_CMD_LIST:
1399 case IPSET_CMD_SAVE:
1400 /* No set in kernel */
1401 print_set_done(session, true);
1404 FAILURE("ACK message received to command %s[%u], "
1405 "which is not expected",
1406 session->cmd < IPSET_MSG_MAX
1407 ? cmd2name[session->cmd] : "unknown",
1412 D("nlmsgerr error: %u", -err->error);
1414 /* Error messages */
1416 /* Special case for IPSET_CMD_TEST */
1417 if (session->cmd == IPSET_CMD_TEST &&
1418 err->error == -IPSET_ERR_EXIST) {
1419 if (!(session->envopts & IPSET_ENV_QUIET)) {
1420 ipset_print_elem(session->report, IPSET_ERRORBUFLEN,
1421 session->data, IPSET_OPT_NONE, 0);
1422 ipset_warn(session, " is NOT in set %s.",
1423 ipset_data_setname(data));
1428 decode_errmsg(session, nlh);
1434 callback_noop(const struct nlmsghdr *nlh UNUSED, void *data UNUSED)
1439 * Build and send messages
1443 open_nested(struct ipset_session *session, struct nlmsghdr *nlh, int attr)
1445 if (nlh->nlmsg_len + MNL_ATTR_HDRLEN > session->bufsize)
1447 session->nested[session->nestid++] = mnl_attr_nest_start(nlh, attr);
1452 close_nested(struct ipset_session *session, struct nlmsghdr *nlh)
1454 mnl_attr_nest_end(nlh, session->nested[session->nestid-1]);
1455 session->nested[--session->nestid] = NULL;
1459 attr_len(const struct ipset_attr_policy *attr, uint8_t family, uint16_t *flags)
1461 switch (attr->type) {
1462 case MNL_TYPE_NESTED:
1466 *flags = NLA_F_NET_BYTEORDER;
1467 return family == NFPROTO_IPV4 ? sizeof(uint32_t)
1468 : sizeof(struct in6_addr);
1470 *flags = NLA_F_NET_BYTEORDER;
1471 return sizeof(uint64_t);
1473 *flags = NLA_F_NET_BYTEORDER;
1474 return sizeof(uint32_t);
1476 *flags = NLA_F_NET_BYTEORDER;
1477 return sizeof(uint16_t);
1479 return sizeof(uint8_t);
1485 #define BUFFER_FULL(bufsize, nlmsg_len, nestlen, attrlen) \
1486 (nlmsg_len + nestlen + MNL_ATTR_HDRLEN + MNL_ALIGN(alen) + \
1487 MNL_ALIGN(sizeof(struct nlmsgerr)) > bufsize)
1490 rawdata2attr(struct ipset_session *session, struct nlmsghdr *nlh,
1491 const void *d, int type, uint8_t family,
1492 const struct ipset_attr_policy attrs[])
1494 const struct ipset_attr_policy *attr;
1499 attr = &attrs[type];
1500 if (attr->type == MNL_TYPE_NESTED) {
1502 struct nlattr *nested;
1503 int atype = family == NFPROTO_IPV4 ? IPSET_ATTR_IPADDR_IPV4
1504 : IPSET_ATTR_IPADDR_IPV6;
1506 alen = attr_len(attr, family, &flags);
1507 if (BUFFER_FULL(session->bufsize, nlh->nlmsg_len,
1508 MNL_ATTR_HDRLEN, alen))
1510 nested = mnl_attr_nest_start(nlh, type);
1511 D("family: %s", family == NFPROTO_IPV4 ? "INET" :
1512 family == NFPROTO_IPV6 ? "INET6" : "UNSPEC");
1513 mnl_attr_put(nlh, atype | flags, alen, d);
1514 mnl_attr_nest_end(nlh, nested);
1519 alen = attr_len(attr, family, &flags);
1520 if (BUFFER_FULL(session->bufsize, nlh->nlmsg_len, 0, alen))
1523 switch (attr->type) {
1524 case MNL_TYPE_U64: {
1525 uint64_t value = htobe64(*(const uint64_t *)d);
1527 mnl_attr_put(nlh, type | flags, alen, &value);
1530 case MNL_TYPE_U32: {
1531 uint32_t value = htonl(*(const uint32_t *)d);
1533 mnl_attr_put(nlh, type | flags, alen, &value);
1536 case MNL_TYPE_U16: {
1537 uint16_t value = htons(*(const uint16_t *)d);
1539 mnl_attr_put(nlh, type | flags, alen, &value);
1542 case MNL_TYPE_NUL_STRING:
1543 alen = strlen((const char *)d) + 1;
1549 mnl_attr_put(nlh, type | flags, alen, d);
1555 data2attr(struct ipset_session *session, struct nlmsghdr *nlh,
1556 struct ipset_data *data, int type, uint8_t family,
1557 const struct ipset_attr_policy attrs[])
1559 const struct ipset_attr_policy *attr = &attrs[type];
1561 return rawdata2attr(session, nlh, ipset_data_get(data, attr->opt),
1562 type, family, attrs);
1565 #define ADDATTR_PROTOCOL(nlh) \
1566 mnl_attr_put_u8(nlh, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL)
1568 #define ADDATTR(session, nlh, data, type, family, attrs) \
1569 data2attr(session, nlh, data, type, family, attrs)
1571 #define ADDATTR_SETNAME(session, nlh, data) \
1572 data2attr(session, nlh, data, IPSET_ATTR_SETNAME, NFPROTO_IPV4, \
1575 #define ADDATTR_IF(session, nlh, data, type, family, attrs) \
1576 ipset_data_test(data, attrs[type].opt) ? \
1577 data2attr(session, nlh, data, type, family, attrs) : 0
1579 #define ADDATTR_RAW(session, nlh, data, type, attrs) \
1580 rawdata2attr(session, nlh, data, type, NFPROTO_IPV4, attrs)
1583 addattr_create(struct ipset_session *session,
1584 struct nlmsghdr *nlh, struct ipset_data *data, uint8_t family)
1588 for (i = IPSET_ATTR_UNSPEC + 1; i <= IPSET_ATTR_CREATE_MAX; i++)
1589 ADDATTR_IF(session, nlh, data, i, family, create_attrs);
1593 addattr_adt(struct ipset_session *session,
1594 struct nlmsghdr *nlh, struct ipset_data *data, uint8_t family)
1598 for (i = IPSET_ATTR_UNSPEC + 1; i <= IPSET_ATTR_ADT_MAX; i++)
1599 if (ADDATTR_IF(session, nlh, data, i, family, adt_attrs))
1604 #define PRIVATE_MSG_BUFLEN 256
1607 build_send_private_msg(struct ipset_session *session, enum ipset_cmd cmd)
1609 char buffer[PRIVATE_MSG_BUFLEN] __attribute__ ((aligned)) = {};
1610 struct nlmsghdr *nlh = (void *)buffer;
1611 struct ipset_data *data = session->data;
1612 int len = PRIVATE_MSG_BUFLEN, ret;
1613 enum ipset_cmd saved = session->cmd;
1615 /* Initialize header */
1616 session->transport->fill_hdr(session->handle, cmd, buffer, len, 0);
1618 ADDATTR_PROTOCOL(nlh);
1621 case IPSET_CMD_PROTOCOL:
1623 case IPSET_CMD_HEADER:
1624 if (!ipset_data_test(data, IPSET_SETNAME))
1625 return ipset_err(session,
1626 "Invalid internal HEADER command: "
1628 ADDATTR_SETNAME(session, nlh, data);
1630 case IPSET_CMD_TYPE:
1631 if (!ipset_data_test(data, IPSET_OPT_TYPENAME))
1632 return ipset_err(session,
1633 "Invalid internal TYPE command: "
1635 ADDATTR(session, nlh, data, IPSET_ATTR_TYPENAME,
1636 NFPROTO_IPV4, cmd_attrs);
1637 if (ipset_data_test(data, IPSET_OPT_FAMILY))
1638 ADDATTR(session, nlh, data, IPSET_ATTR_FAMILY,
1639 NFPROTO_IPV4, cmd_attrs);
1641 /* bitmap:port and list:set types */
1642 mnl_attr_put_u8(nlh, IPSET_ATTR_FAMILY, NFPROTO_UNSPEC);
1645 return ipset_err(session, "Internal error: "
1646 "unknown private command %u", cmd);
1649 /* Backup, then restore real command */
1651 ret = session->transport->query(session->handle, buffer, len);
1652 session->cmd = saved;
1658 may_aggregate_ad(struct ipset_session *session, enum ipset_cmd cmd)
1660 return session->lineno != 0 &&
1661 (cmd == IPSET_CMD_ADD || cmd == IPSET_CMD_DEL) &&
1662 cmd == session->cmd &&
1663 STREQ(ipset_data_setname(session->data), session->saved_setname);
1667 build_msg(struct ipset_session *session, bool aggregate)
1669 struct nlmsghdr *nlh = session->buffer;
1670 struct ipset_data *data = session->data;
1672 /* Public commands */
1673 D("cmd %s, nlmsg_len: %u", cmd2name[session->cmd], nlh->nlmsg_len);
1674 if (nlh->nlmsg_len == 0) {
1675 /* Initialize header */
1677 session->transport->fill_hdr(session->handle,
1682 ADDATTR_PROTOCOL(nlh);
1684 D("Protocol added, aggregate %s", aggregate ? "yes" : "no");
1685 switch (session->cmd) {
1686 case IPSET_CMD_CREATE: {
1687 const struct ipset_type *type;
1689 /* Sanity checkings */
1690 if (!ipset_data_test(data, IPSET_SETNAME))
1691 return ipset_err(session,
1692 "Invalid create command: missing setname");
1693 if (!ipset_data_test(data, IPSET_OPT_TYPE))
1694 return ipset_err(session,
1695 "Invalid create command: missing settype");
1697 type = ipset_data_get(data, IPSET_OPT_TYPE);
1699 * setname, typename, revision, family, flags (optional) */
1700 ADDATTR_SETNAME(session, nlh, data);
1701 ADDATTR(session, nlh, data, IPSET_ATTR_TYPENAME,
1702 NFPROTO_IPV4, cmd_attrs);
1703 ADDATTR_RAW(session, nlh, &type->revision,
1704 IPSET_ATTR_REVISION, cmd_attrs);
1705 D("family: %u, type family %u",
1706 ipset_data_family(data), type->family);
1707 if (ipset_data_test(data, IPSET_OPT_FAMILY))
1708 ADDATTR(session, nlh, data, IPSET_ATTR_FAMILY,
1709 NFPROTO_IPV4, cmd_attrs);
1711 /* bitmap:port and list:set types */
1712 mnl_attr_put_u8(nlh, IPSET_ATTR_FAMILY, NFPROTO_UNSPEC);
1714 /* Type-specific create attributes */
1715 D("call open_nested");
1716 open_nested(session, nlh, IPSET_ATTR_DATA);
1717 addattr_create(session, nlh, data, type->family);
1718 D("call close_nested");
1719 close_nested(session, nlh);
1722 case IPSET_CMD_DESTROY:
1723 case IPSET_CMD_FLUSH:
1724 case IPSET_CMD_SAVE:
1725 if (ipset_data_test(data, IPSET_SETNAME))
1726 ADDATTR_SETNAME(session, nlh, data);
1728 case IPSET_CMD_LIST: {
1731 if (session->envopts & IPSET_ENV_LIST_SETNAME)
1732 flags |= IPSET_FLAG_LIST_SETNAME;
1733 if (session->envopts & IPSET_ENV_LIST_HEADER)
1734 flags |= IPSET_FLAG_LIST_HEADER;
1735 if (ipset_data_test(data, IPSET_SETNAME))
1736 ADDATTR_SETNAME(session, nlh, data);
1737 if (flags && session->mode != IPSET_LIST_SAVE) {
1738 ipset_data_set(data, IPSET_OPT_FLAGS, &flags);
1739 ADDATTR(session, nlh, data, IPSET_ATTR_FLAGS,
1740 NFPROTO_IPV4, cmd_attrs);
1744 case IPSET_CMD_RENAME:
1745 case IPSET_CMD_SWAP:
1746 if (!ipset_data_test(data, IPSET_SETNAME))
1747 return ipset_err(session,
1748 "Invalid %s command: missing from-setname",
1749 session->cmd == IPSET_CMD_SWAP ? "swap" :
1751 if (!ipset_data_test(data, IPSET_OPT_SETNAME2))
1752 return ipset_err(session,
1753 "Invalid %s command: missing to-setname",
1754 session->cmd == IPSET_CMD_SWAP ? "swap" :
1756 ADDATTR_SETNAME(session, nlh, data);
1757 ADDATTR_RAW(session, nlh,
1758 ipset_data_get(data, IPSET_OPT_SETNAME2),
1759 IPSET_ATTR_SETNAME2, cmd_attrs);
1762 case IPSET_CMD_DEL: {
1763 const struct ipset_type *type;
1766 /* Setname, type not checked/added yet */
1767 if (!ipset_data_test(data, IPSET_SETNAME))
1768 return ipset_err(session,
1769 "Invalid %s command: missing setname",
1770 session->cmd == IPSET_CMD_ADD ? "add" :
1773 if (!ipset_data_test(data, IPSET_OPT_TYPE))
1774 return ipset_err(session,
1775 "Invalid %s command: missing settype",
1776 session->cmd == IPSET_CMD_ADD ? "add" :
1779 /* Core options: setname */
1780 ADDATTR_SETNAME(session, nlh, data);
1781 if (session->lineno != 0) {
1783 ADDATTR_RAW(session, nlh, &session->lineno,
1784 IPSET_ATTR_LINENO, cmd_attrs);
1785 open_nested(session, nlh, IPSET_ATTR_ADT);
1788 type = ipset_data_get(data, IPSET_OPT_TYPE);
1789 D("family: %u, type family %u",
1790 ipset_data_family(data), type->family);
1791 if (open_nested(session, nlh, IPSET_ATTR_DATA)) {
1792 D("open_nested failed");
1795 if (addattr_adt(session, nlh, data, ipset_data_family(data)) ||
1796 ADDATTR_RAW(session, nlh, &session->lineno,
1797 IPSET_ATTR_LINENO, cmd_attrs)) {
1798 /* Cancel last, unfinished nested attribute */
1799 mnl_attr_nest_cancel(nlh,
1800 session->nested[session->nestid-1]);
1801 session->nested[--session->nestid] = NULL;
1804 close_nested(session, nlh);
1807 case IPSET_CMD_TEST: {
1808 const struct ipset_type *type;
1809 /* Return codes are not aggregated, so tests cannot be either */
1811 /* Setname, type not checked/added yet */
1813 if (!ipset_data_test(data, IPSET_SETNAME))
1814 return ipset_err(session,
1815 "Invalid test command: missing setname");
1817 if (!ipset_data_test(data, IPSET_OPT_TYPE))
1818 return ipset_err(session,
1819 "Invalid test command: missing settype");
1821 type = ipset_data_get(data, IPSET_OPT_TYPE);
1822 D("family: %u, type family %u",
1823 ipset_data_family(data), type->family);
1824 ADDATTR_SETNAME(session, nlh, data);
1825 open_nested(session, nlh, IPSET_ATTR_DATA);
1826 addattr_adt(session, nlh, data, ipset_data_family(data));
1827 close_nested(session, nlh);
1831 return ipset_err(session, "Internal error: unknown command %u",
1838 * ipset_commit - commit buffered commands
1839 * @session: session structure
1841 * Commit buffered commands, if there are any.
1843 * Returns 0 on success or a negative error code.
1846 ipset_commit(struct ipset_session *session)
1848 struct nlmsghdr *nlh;
1853 nlh = session->buffer;
1854 D("send buffer: len %u, cmd %s",
1855 nlh->nlmsg_len, cmd2name[session->cmd]);
1856 if (nlh->nlmsg_len == 0)
1860 /* Close nested data blocks */
1861 for (i = session->nestid - 1; i >= 0; i--)
1862 close_nested(session, nlh);
1865 ret = session->transport->query(session->handle,
1869 /* Reset saved data and nested state */
1870 session->saved_setname[0] = '\0';
1871 session->printed_set = 0;
1872 for (i = session->nestid - 1; i >= 0; i--)
1873 session->nested[i] = NULL;
1874 session->nestid = 0;
1880 if (session->report[0] != '\0')
1883 return ipset_err(session,
1884 "Internal protocol error");
1889 static mnl_cb_t cb_ctl[] = {
1890 [NLMSG_NOOP] = callback_noop,
1891 [NLMSG_ERROR] = callback_error,
1892 [NLMSG_DONE] = callback_done,
1893 [NLMSG_OVERRUN] = callback_noop,
1894 [NLMSG_MIN_TYPE] = callback_data,
1897 static inline struct ipset_handle *
1898 init_transport(struct ipset_session *session)
1900 session->handle = session->transport->init(cb_ctl, session);
1902 return session->handle;
1906 * ipset_cmd - execute a command
1907 * @session: session structure
1908 * @cmd: command to execute
1909 * @lineno: command line number in restore mode
1911 * Execute - or prepare/buffer in restore mode - a command.
1912 * It is the caller responsibility that the data field be filled out
1913 * with all required parameters for a successful execution.
1914 * The data field is cleared after this function call for the public
1917 * Returns 0 on success or a negative error code.
1920 ipset_cmd(struct ipset_session *session, enum ipset_cmd cmd, uint32_t lineno)
1922 struct ipset_data *data;
1923 bool aggregate = false;
1928 if (cmd <= IPSET_CMD_NONE || cmd >= IPSET_MSG_MAX)
1931 /* Initialize transport method if not done yet */
1932 if (session->handle == NULL && init_transport(session) == NULL)
1933 return ipset_err(session,
1934 "Cannot open session to kernel.");
1936 data = session->data;
1938 /* Check protocol version once */
1939 if (!session->version_checked) {
1940 if (build_send_private_msg(session, IPSET_CMD_PROTOCOL) < 0)
1944 /* Private commands */
1945 if (cmd == IPSET_CMD_TYPE || cmd == IPSET_CMD_HEADER)
1946 return build_send_private_msg(session, cmd);
1948 /* Check aggregatable commands */
1949 aggregate = may_aggregate_ad(session, cmd);
1951 /* Flush possible aggregated commands */
1952 ret = ipset_commit(session);
1957 /* Real command: update lineno too */
1959 session->lineno = lineno;
1961 /* Set default output mode */
1962 if (cmd == IPSET_CMD_LIST) {
1963 if (session->mode == IPSET_LIST_NONE)
1964 session->mode = IPSET_LIST_PLAIN;
1965 } else if (cmd == IPSET_CMD_SAVE) {
1966 if (session->mode == IPSET_LIST_NONE)
1967 session->mode = IPSET_LIST_SAVE;
1969 /* Start the root element in XML mode */
1970 if ((cmd == IPSET_CMD_LIST || cmd == IPSET_CMD_SAVE) &&
1971 session->mode == IPSET_LIST_XML)
1972 safe_snprintf(session, "<ipsets>\n");
1974 D("next: build_msg");
1975 /* Build new message or append buffered commands */
1976 ret = build_msg(session, aggregate);
1977 D("build_msg returned %u", ret);
1979 /* Buffer is full, send buffered commands */
1980 ret = ipset_commit(session);
1983 ret = build_msg(session, false);
1984 D("build_msg 2 returned %u", ret);
1988 D("past: build_msg");
1990 /* We have to save the type for error handling */
1991 session->saved_type = ipset_data_get(data, IPSET_OPT_TYPE);
1992 if (session->lineno != 0 &&
1993 (cmd == IPSET_CMD_ADD || cmd == IPSET_CMD_DEL)) {
1994 /* Save setname for the next possible aggregated restore line */
1995 strcpy(session->saved_setname, ipset_data_setname(data));
1996 ipset_data_reset(data);
1997 /* Don't commit: we may aggregate next command */
2003 ret = ipset_commit(session);
2007 ipset_data_reset(data);
2012 * ipset_session_outfn - set session output printing function
2014 * Set the session printing function.
2018 ipset_session_outfn(struct ipset_session *session, ipset_outfn outfn)
2020 session->outfn = outfn ? outfn : printf;
2025 * ipset_session_init - initialize an ipset session
2027 * Initialize an ipset session by allocating a session structure
2028 * and filling out with the initialization data.
2030 * Returns the created session sctructure on success or NULL.
2032 struct ipset_session *
2033 ipset_session_init(ipset_outfn outfn)
2035 struct ipset_session *session;
2036 size_t bufsize = getpagesize();
2038 /* Create session object */
2039 session = calloc(1, sizeof(struct ipset_session) + bufsize);
2040 if (session == NULL)
2042 session->bufsize = bufsize;
2043 session->buffer = session + 1;
2045 /* The single transport method yet */
2046 session->transport = &ipset_mnl_transport;
2048 /* Output function */
2049 session->outfn = outfn;
2051 /* Initialize data structures */
2052 session->data = ipset_data_init();
2053 if (session->data == NULL)
2065 * ipset_session_fini - destroy an ipset session
2066 * @session: session structure
2068 * Destroy an ipset session: release the created structures.
2070 * Returns 0 on success or a negative error code.
2073 ipset_session_fini(struct ipset_session *session)
2077 if (session->handle)
2078 session->transport->fini(session->handle);
2080 ipset_data_fini(session->data);