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;
234 ipset_data_reset(ipset_session_data(session));
236 session->errmsg = NULL;
237 session->warnmsg = session->report;
243 * ipset_session_reset - reset the report buffer
244 * @session: session structure
246 * Reset the report buffer, the error and warning pointers.
249 ipset_session_report_reset(struct ipset_session *session)
252 session->report[0] = '\0';
253 session->errmsg = session->warnmsg = NULL;
257 * ipset_session_error - return the report buffer as error
258 * @session: session structure
260 * Return the pointer to the report buffer as an error report.
261 * If there is no error message in the buffer, NULL returned.
264 ipset_session_error(const struct ipset_session *session)
268 return session->errmsg;
272 * ipset_session_warning - return the report buffer as warning
273 * @session: session structure
275 * Return the pointer to the report buffer as a warning report.
276 * If there is no warning message in the buffer, NULL returned.
279 ipset_session_warning(const struct ipset_session *session)
283 return session->warnmsg;
287 * Receive data from the kernel
290 struct ipset_attr_policy {
296 /* Attribute policies and mapping to options */
297 static const struct ipset_attr_policy cmd_attrs[] = {
298 [IPSET_ATTR_PROTOCOL] = {
301 [IPSET_ATTR_SETNAME] = {
302 .type = MNL_TYPE_NUL_STRING,
303 .opt = IPSET_SETNAME,
304 .len = IPSET_MAXNAMELEN,
306 [IPSET_ATTR_TYPENAME] = {
307 .type = MNL_TYPE_NUL_STRING,
308 .opt = IPSET_OPT_TYPENAME,
309 .len = IPSET_MAXNAMELEN,
311 /* IPSET_ATTR_SETNAME2 is an alias for IPSET_ATTR_TYPENAME */
312 [IPSET_ATTR_REVISION] = {
314 .opt = IPSET_OPT_REVISION,
316 [IPSET_ATTR_FAMILY] = {
318 .opt = IPSET_OPT_FAMILY,
320 [IPSET_ATTR_FLAGS] = {
321 .type = MNL_TYPE_U32,
322 .opt = IPSET_OPT_FLAGS,
324 [IPSET_ATTR_DATA] = {
325 .type = MNL_TYPE_NESTED,
328 .type = MNL_TYPE_NESTED,
330 [IPSET_ATTR_REVISION_MIN] = {
332 .opt = IPSET_OPT_REVISION_MIN,
334 /* IPSET_ATTR_PROTOCOL_MIN is an alias for IPSET_ATTR_REVISION_MIN */
335 [IPSET_ATTR_LINENO] = {
336 .type = MNL_TYPE_U32,
337 .opt = IPSET_OPT_LINENO,
341 static const struct ipset_attr_policy create_attrs[] = {
343 .type = MNL_TYPE_NESTED,
346 [IPSET_ATTR_IP_TO] = {
347 .type = MNL_TYPE_NESTED,
348 .opt = IPSET_OPT_IP_TO,
350 [IPSET_ATTR_CIDR] = {
352 .opt = IPSET_OPT_CIDR,
354 [IPSET_ATTR_PORT] = {
355 .type = MNL_TYPE_U16,
356 .opt = IPSET_OPT_PORT,
358 [IPSET_ATTR_PORT_TO] = {
359 .type = MNL_TYPE_U16,
360 .opt = IPSET_OPT_PORT_TO,
362 [IPSET_ATTR_TIMEOUT] = {
363 .type = MNL_TYPE_U32,
364 .opt = IPSET_OPT_TIMEOUT,
366 [IPSET_ATTR_PROTO] = {
368 .opt = IPSET_OPT_PROTO,
370 [IPSET_ATTR_CADT_FLAGS] = {
371 .type = MNL_TYPE_U32,
372 .opt = IPSET_OPT_CADT_FLAGS,
375 .type = MNL_TYPE_U32,
378 [IPSET_ATTR_HASHSIZE] = {
379 .type = MNL_TYPE_U32,
380 .opt = IPSET_OPT_HASHSIZE,
382 [IPSET_ATTR_MAXELEM] = {
383 .type = MNL_TYPE_U32,
384 .opt = IPSET_OPT_MAXELEM,
386 [IPSET_ATTR_MARKMASK] = {
387 .type = MNL_TYPE_U32,
388 .opt = IPSET_OPT_MARKMASK,
390 [IPSET_ATTR_NETMASK] = {
392 .opt = IPSET_OPT_NETMASK,
394 [IPSET_ATTR_PROBES] = {
396 .opt = IPSET_OPT_PROBES,
398 [IPSET_ATTR_RESIZE] = {
400 .opt = IPSET_OPT_RESIZE,
402 [IPSET_ATTR_SIZE] = {
403 .type = MNL_TYPE_U32,
404 .opt = IPSET_OPT_SIZE,
406 [IPSET_ATTR_ELEMENTS] = {
407 .type = MNL_TYPE_U32,
408 .opt = IPSET_OPT_ELEMENTS,
410 [IPSET_ATTR_REFERENCES] = {
411 .type = MNL_TYPE_U32,
412 .opt = IPSET_OPT_REFERENCES,
414 [IPSET_ATTR_MEMSIZE] = {
415 .type = MNL_TYPE_U32,
416 .opt = IPSET_OPT_MEMSIZE,
420 static const struct ipset_attr_policy adt_attrs[] = {
422 .type = MNL_TYPE_NESTED,
425 [IPSET_ATTR_IP_TO] = {
426 .type = MNL_TYPE_NESTED,
427 .opt = IPSET_OPT_IP_TO,
429 [IPSET_ATTR_CIDR] = {
431 .opt = IPSET_OPT_CIDR,
433 [IPSET_ATTR_MARK] = {
434 .type = MNL_TYPE_U32,
435 .opt = IPSET_OPT_MARK,
437 [IPSET_ATTR_PORT] = {
438 .type = MNL_TYPE_U16,
439 .opt = IPSET_OPT_PORT,
441 [IPSET_ATTR_PORT_TO] = {
442 .type = MNL_TYPE_U16,
443 .opt = IPSET_OPT_PORT_TO,
445 [IPSET_ATTR_PROTO] = {
447 .opt = IPSET_OPT_PROTO,
449 [IPSET_ATTR_TIMEOUT] = {
450 .type = MNL_TYPE_U32,
451 .opt = IPSET_OPT_TIMEOUT,
453 [IPSET_ATTR_CADT_FLAGS] = {
454 .type = MNL_TYPE_U32,
455 .opt = IPSET_OPT_CADT_FLAGS,
457 [IPSET_ATTR_LINENO] = {
458 .type = MNL_TYPE_U32,
459 .opt = IPSET_OPT_LINENO,
461 [IPSET_ATTR_ETHER] = {
462 .type = MNL_TYPE_BINARY,
463 .opt = IPSET_OPT_ETHER,
466 [IPSET_ATTR_NAME] = {
467 .type = MNL_TYPE_NUL_STRING,
468 .opt = IPSET_OPT_NAME,
469 .len = IPSET_MAXNAMELEN,
471 [IPSET_ATTR_NAMEREF] = {
472 .type = MNL_TYPE_NUL_STRING,
473 .opt = IPSET_OPT_NAMEREF,
474 .len = IPSET_MAXNAMELEN,
477 .type = MNL_TYPE_NESTED,
478 .opt = IPSET_OPT_IP2,
480 [IPSET_ATTR_CIDR2] = {
482 .opt = IPSET_OPT_CIDR2,
484 [IPSET_ATTR_IP2_TO] = {
485 .type = MNL_TYPE_NESTED,
486 .opt = IPSET_OPT_IP2_TO,
488 [IPSET_ATTR_IFACE] = {
489 .type = MNL_TYPE_NUL_STRING,
490 .opt = IPSET_OPT_IFACE,
493 [IPSET_ATTR_PACKETS] = {
494 .type = MNL_TYPE_U64,
495 .opt = IPSET_OPT_PACKETS,
497 [IPSET_ATTR_BYTES] = {
498 .type = MNL_TYPE_U64,
499 .opt = IPSET_OPT_BYTES,
501 [IPSET_ATTR_COMMENT] = {
502 .type = MNL_TYPE_NUL_STRING,
503 .opt = IPSET_OPT_ADT_COMMENT,
504 .len = IPSET_MAX_COMMENT_SIZE + 1,
506 [IPSET_ATTR_SKBMARK] = {
507 .type = MNL_TYPE_U64,
508 .opt = IPSET_OPT_SKBMARK,
510 [IPSET_ATTR_SKBPRIO] = {
511 .type = MNL_TYPE_U32,
512 .opt = IPSET_OPT_SKBPRIO,
514 [IPSET_ATTR_SKBQUEUE] = {
515 .type = MNL_TYPE_U16,
516 .opt = IPSET_OPT_SKBQUEUE,
519 .type = MNL_TYPE_UNSPEC,
524 static const struct ipset_attr_policy ipaddr_attrs[] = {
525 [IPSET_ATTR_IPADDR_IPV4] = {
526 .type = MNL_TYPE_U32,
528 [IPSET_ATTR_IPADDR_IPV6] = {
529 .type = MNL_TYPE_BINARY,
530 .len = sizeof(union nf_inet_addr),
535 static int debug = 1;
539 generic_data_attr_cb(const struct nlattr *attr, void *data,
540 int attr_max, const struct ipset_attr_policy *policy)
542 const struct nlattr **tb = data;
543 int type = mnl_attr_get_type(attr);
545 IF_D(debug, "attr type: %u, len %u", type, attr->nla_len);
546 if (mnl_attr_type_valid(attr, attr_max) < 0) {
547 IF_D(debug, "attr type: %u INVALID", type);
550 if (mnl_attr_validate(attr, policy[type].type) < 0) {
551 IF_D(debug, "attr type: %u POLICY, attrlen %u", type,
552 mnl_attr_get_payload_len(attr));
555 if (policy[type].type == MNL_TYPE_NUL_STRING &&
556 mnl_attr_get_payload_len(attr) > policy[type].len)
563 create_attr_cb(const struct nlattr *attr, void *data)
565 return generic_data_attr_cb(attr, data,
566 IPSET_ATTR_CREATE_MAX, create_attrs);
570 adt_attr_cb(const struct nlattr *attr, void *data)
572 return generic_data_attr_cb(attr, data,
573 IPSET_ATTR_ADT_MAX, adt_attrs);
577 ipaddr_attr_cb(const struct nlattr *attr, void *data)
579 return generic_data_attr_cb(attr, data,
580 IPSET_ATTR_IPADDR_MAX, ipaddr_attrs);
583 #define FAILURE(format, args...) \
584 { ipset_err(session, format , ## args); return MNL_CB_ERROR; }
587 attr2data(struct ipset_session *session, struct nlattr *nla[],
588 int type, const struct ipset_attr_policy attrs[])
590 struct ipset_data *data = session->data;
591 const struct ipset_attr_policy *attr;
599 d = mnl_attr_get_payload(nla[type]);
601 if (attr->type == MNL_TYPE_UNSPEC)
603 if (attr->type == MNL_TYPE_NESTED && attr->opt) {
605 struct nlattr *ipattr[IPSET_ATTR_IPADDR_MAX+1] = {};
606 uint8_t family = ipset_data_family(data);
608 D("IP attr type %u", type);
609 if (mnl_attr_parse_nested(nla[type],
610 ipaddr_attr_cb, ipattr) < 0)
611 FAILURE("Broken kernel message, cannot validate "
612 "IP address attribute!");
614 /* Validate by hand */
617 atype = IPSET_ATTR_IPADDR_IPV4;
619 FAILURE("Broken kernel message: IPv4 address "
620 "expected but not received!");
621 if (ipattr[atype]->nla_len < sizeof(uint32_t))
622 FAILURE("Broken kernel message: "
623 "cannot validate IPv4 "
624 "address attribute!");
627 atype = IPSET_ATTR_IPADDR_IPV6;
629 FAILURE("Broken kernel message: IPv6 address "
630 "expected but not received!");
631 if (ipattr[atype]->nla_len < sizeof(struct in6_addr))
632 FAILURE("Broken kernel message: "
633 "cannot validate IPv6 "
634 "address attribute!");
637 FAILURE("Broken kernel message: "
638 "IP address attribute but "
639 "family is unspecified!");
641 d = mnl_attr_get_payload(ipattr[atype]);
642 } else if (nla[type]->nla_type & NLA_F_NET_BYTEORDER) {
643 D("netorder attr type %u", type);
644 switch (attr->type) {
647 /* Ensure data alignment */
648 memcpy(&tmp, d, sizeof(tmp));
654 v32 = ntohl(*(const uint32_t *)d);
659 v16 = ntohs(*(const uint16_t *)d);
669 D("hostorder attr type %u", type);
670 if (type == IPSET_ATTR_TYPENAME)
671 D("nla typename %s", (const char *) d);
673 ret = ipset_data_set(data, attr->opt, d);
675 if (type == IPSET_ATTR_TYPENAME)
677 (const char *) ipset_data_get(data, IPSET_OPT_TYPENAME));
682 #define ATTR2DATA(session, nla, type, attrs) \
683 if (attr2data(session, nla, type, attrs) < 0) \
686 static const char cmd2name[][9] = {
687 [IPSET_CMD_NONE] = "NONE",
688 [IPSET_CMD_CREATE] = "CREATE",
689 [IPSET_CMD_DESTROY] = "DESTROY",
690 [IPSET_CMD_FLUSH] = "FLUSH",
691 [IPSET_CMD_RENAME] = "RENAME",
692 [IPSET_CMD_SWAP] = "SWAP",
693 [IPSET_CMD_LIST] = "LIST",
694 [IPSET_CMD_SAVE] = "SAVE",
695 [IPSET_CMD_ADD] = "ADD",
696 [IPSET_CMD_DEL] = "DEL",
697 [IPSET_CMD_TEST] = "TEST",
698 [IPSET_CMD_HEADER] = "HEADER",
699 [IPSET_CMD_TYPE] = "TYPE",
700 [IPSET_CMD_PROTOCOL] = "PROTOCOL",
704 call_outfn(struct ipset_session *session)
706 int ret = session->outfn("%s", session->outbuf);
708 session->outbuf[0] = '\0';
710 return ret < 0 ? ret : 0;
713 /* Handle printing failures */
714 static jmp_buf printf_failure;
717 handle_snprintf_error(struct ipset_session *session,
718 int len, int ret, int loop)
720 if (ret < 0 || ret >= IPSET_OUTBUFLEN - len) {
721 /* Buffer was too small, push it out and retry */
722 D("print buffer and try again: len: %u, ret: %d", len, ret);
725 "Internal error at printing, loop detected!");
726 longjmp(printf_failure, 1);
729 session->outbuf[len] = '\0';
730 if (call_outfn(session)) {
732 "Internal error, could not print output buffer!");
733 longjmp(printf_failure, 1);
740 static int __attribute__((format(printf, 2, 3)))
741 safe_snprintf(struct ipset_session *session, const char *fmt, ...)
744 int len, ret, loop = 0;
747 len = strlen(session->outbuf);
748 D("len: %u, retry %u", len, loop);
750 ret = vsnprintf(session->outbuf + len,
751 IPSET_OUTBUFLEN - len,
754 loop = handle_snprintf_error(session, len, ret, loop);
761 safe_dprintf(struct ipset_session *session, ipset_printfn fn,
764 int len, ret, loop = 0;
767 len = strlen(session->outbuf);
768 D("len: %u, retry %u", len, loop);
769 ret = fn(session->outbuf + len, IPSET_OUTBUFLEN - len,
770 session->data, opt, session->envopts);
771 loop = handle_snprintf_error(session, len, ret, loop);
778 list_adt(struct ipset_session *session, struct nlattr *nla[])
780 const struct ipset_data *data = session->data;
781 const struct ipset_type *type;
782 const struct ipset_arg *arg;
786 /* Check and load type, family */
787 if (!ipset_data_test(data, IPSET_OPT_TYPE))
788 type = ipset_type_get(session, IPSET_CMD_ADD);
790 type = ipset_data_get(data, IPSET_OPT_TYPE);
795 for (i = IPSET_ATTR_UNSPEC + 1; i <= IPSET_ATTR_ADT_MAX; i++)
798 ATTR2DATA(session, nla, i, adt_attrs);
800 D("attr found %u", found);
804 switch (session->mode) {
805 case IPSET_LIST_SAVE:
806 safe_snprintf(session, "add %s ", ipset_data_setname(data));
809 safe_snprintf(session, "<member><elem>");
811 case IPSET_LIST_PLAIN:
816 safe_dprintf(session, ipset_print_elem, IPSET_OPT_ELEM);
817 if (session->mode == IPSET_LIST_XML)
818 safe_snprintf(session, "</elem>");
820 for (i = 0; type->cmd[IPSET_ADD].args[i] != IPSET_ARG_NONE; i++) {
821 arg = ipset_keyword(type->cmd[IPSET_ADD].args[i]);
822 D("print arg opt %u (%s) %s", arg->opt, arg->name[0],
823 ipset_data_test(data, arg->opt) ? "(yes)" : "(missing)");
824 if (!(arg->print && ipset_data_test(data, arg->opt)))
826 switch (session->mode) {
827 case IPSET_LIST_SAVE:
828 case IPSET_LIST_PLAIN:
829 if (arg->has_arg == IPSET_NO_ARG) {
830 safe_snprintf(session, " %s", arg->name[0]);
833 safe_snprintf(session, " %s ", arg->name[0]);
834 safe_dprintf(session, arg->print, arg->opt);
837 if (arg->has_arg == IPSET_NO_ARG) {
838 safe_snprintf(session,
839 "<%s/>", arg->name[0]);
842 safe_snprintf(session, "<%s>", arg->name[0]);
843 safe_dprintf(session, arg->print, arg->opt);
844 safe_snprintf(session, "</%s>", arg->name[0]);
851 if (session->mode == IPSET_LIST_XML)
852 safe_snprintf(session, "</member>\n");
854 safe_snprintf(session, "\n");
859 #define FAMILY_TO_STR(f) \
860 ((f) == NFPROTO_IPV4 ? "inet" : \
861 (f) == NFPROTO_IPV6 ? "inet6" : "any")
864 list_create(struct ipset_session *session, struct nlattr *nla[])
866 const struct ipset_data *data = session->data;
867 const struct ipset_type *type;
868 const struct ipset_arg *arg;
872 for (i = IPSET_ATTR_UNSPEC + 1; i <= IPSET_ATTR_CREATE_MAX; i++)
874 D("add attr %u, opt %u", i, create_attrs[i].opt);
875 ATTR2DATA(session, nla, i, create_attrs);
878 type = ipset_type_check(session);
881 family = ipset_data_family(data);
883 switch (session->mode) {
884 case IPSET_LIST_SAVE:
885 safe_snprintf(session, "create %s %s",
886 ipset_data_setname(data),
889 case IPSET_LIST_PLAIN:
890 safe_snprintf(session, "%sName: %s\n"
891 "Type: %s\nRevision: %u\nHeader:",
892 session->printed_set ? "\n" : "",
893 ipset_data_setname(data),
894 type->name, type->revision);
897 safe_snprintf(session,
898 "<ipset name=\"%s\">\n"
900 "<revision>%u</revision>\n"
902 ipset_data_setname(data),
903 type->name, type->revision);
909 D("type %s, rev %u", type->name, type->revision);
910 for (i = 0; type->cmd[IPSET_CREATE].args[i] != IPSET_ARG_NONE; i++) {
911 arg = ipset_keyword(type->cmd[IPSET_CREATE].args[i]);
912 D("create print arg opt %u (%s) %s", arg->opt,
913 arg->name[0] ? arg->name[0] : "",
914 ipset_data_test(data, arg->opt) ? "(yes)" : "(missing)");
916 !ipset_data_test(data, arg->opt) ||
917 (arg->opt == IPSET_OPT_FAMILY &&
918 family == type->family))
920 switch (session->mode) {
921 case IPSET_LIST_SAVE:
922 case IPSET_LIST_PLAIN:
923 if (arg->has_arg == IPSET_NO_ARG) {
924 safe_snprintf(session, " %s", arg->name[0]);
927 safe_snprintf(session, " %s ", arg->name[0]);
928 safe_dprintf(session, arg->print, arg->opt);
931 if (arg->has_arg == IPSET_NO_ARG) {
932 safe_snprintf(session,
933 "<%s/>", arg->name[0]);
936 safe_snprintf(session, "<%s>", arg->name[0]);
937 safe_dprintf(session, arg->print, arg->opt);
938 safe_snprintf(session, "</%s>", arg->name[0]);
944 switch (session->mode) {
945 case IPSET_LIST_SAVE:
946 safe_snprintf(session, "\n");
948 case IPSET_LIST_PLAIN:
949 safe_snprintf(session, "\nSize in memory: ");
950 safe_dprintf(session, ipset_print_number, IPSET_OPT_MEMSIZE);
951 safe_snprintf(session, "\nReferences: ");
952 safe_dprintf(session, ipset_print_number, IPSET_OPT_REFERENCES);
953 if (ipset_data_test(data, IPSET_OPT_ELEMENTS)) {
954 safe_snprintf(session, "\nNumber of entries: ");
955 safe_dprintf(session, ipset_print_number, IPSET_OPT_ELEMENTS);
957 safe_snprintf(session,
958 session->envopts & IPSET_ENV_LIST_HEADER ?
959 "\n" : "\nMembers:\n");
962 safe_snprintf(session, "\n<memsize>");
963 safe_dprintf(session, ipset_print_number, IPSET_OPT_MEMSIZE);
964 safe_snprintf(session, "</memsize>\n<references>");
965 safe_dprintf(session, ipset_print_number, IPSET_OPT_REFERENCES);
966 safe_snprintf(session, "</references>\n");
967 if (ipset_data_test(data, IPSET_OPT_ELEMENTS)) {
968 safe_snprintf(session, "<numentries>");
969 safe_dprintf(session, ipset_print_number, IPSET_OPT_ELEMENTS);
970 safe_snprintf(session, "</numentries>\n");
972 safe_snprintf(session,
973 session->envopts & IPSET_ENV_LIST_HEADER ?
975 "</header>\n<members>\n");
980 session->printed_set++;
986 print_set_done(struct ipset_session *session, bool callback_done)
988 D("called for %s", session->saved_setname[0] == '\0'
989 ? "NONE" : session->saved_setname);
990 switch (session->mode) {
992 if (session->envopts & IPSET_ENV_LIST_SETNAME)
994 if (session->envopts & IPSET_ENV_LIST_HEADER) {
995 if (session->saved_setname[0] != '\0')
996 safe_snprintf(session, "</ipset>\n");
999 if (session->saved_setname[0] != '\0')
1000 safe_snprintf(session, "</members>\n</ipset>\n");
1005 if (callback_done && session->mode == IPSET_LIST_XML)
1006 safe_snprintf(session, "</ipsets>\n");
1007 return call_outfn(session) ? MNL_CB_ERROR : MNL_CB_STOP;
1011 callback_list(struct ipset_session *session, struct nlattr *nla[],
1014 struct ipset_data *data = session->data;
1016 if (setjmp(printf_failure)) {
1017 session->saved_setname[0] = '\0';
1018 session->printed_set = 0;
1019 return MNL_CB_ERROR;
1022 if (!nla[IPSET_ATTR_SETNAME])
1023 FAILURE("Broken %s kernel message: missing setname!",
1026 ATTR2DATA(session, nla, IPSET_ATTR_SETNAME, cmd_attrs);
1027 D("setname %s", ipset_data_setname(data));
1028 if (session->envopts & IPSET_ENV_LIST_SETNAME &&
1029 session->mode != IPSET_LIST_SAVE) {
1030 if (session->mode == IPSET_LIST_XML)
1031 safe_snprintf(session, "<ipset name=\"%s\"/>\n",
1032 ipset_data_setname(data));
1034 safe_snprintf(session, "%s\n",
1035 ipset_data_setname(data));
1036 return call_outfn(session) ? MNL_CB_ERROR : MNL_CB_OK;
1039 if (STREQ(ipset_data_setname(data), session->saved_setname)) {
1040 /* Header part already seen */
1041 if (ipset_data_test(data, IPSET_OPT_TYPE) &&
1042 nla[IPSET_ATTR_DATA] != NULL)
1043 FAILURE("Broken %s kernel message: "
1044 "extra DATA received!", cmd2name[cmd]);
1046 if (nla[IPSET_ATTR_DATA] == NULL)
1047 FAILURE("Broken %s kernel message: "
1048 "missing DATA part!", cmd2name[cmd]);
1050 /* Close previous set printing */
1051 if (session->saved_setname[0] != '\0')
1052 print_set_done(session, false);
1055 if (nla[IPSET_ATTR_DATA] != NULL) {
1056 struct nlattr *cattr[IPSET_ATTR_CREATE_MAX+1] = {};
1058 if (!(nla[IPSET_ATTR_TYPENAME] &&
1059 nla[IPSET_ATTR_FAMILY] &&
1060 nla[IPSET_ATTR_REVISION]))
1061 FAILURE("Broken %s kernel message: missing %s!",
1063 !nla[IPSET_ATTR_TYPENAME] ? "typename" :
1064 !nla[IPSET_ATTR_FAMILY] ? "family" :
1067 /* Reset CREATE specific flags */
1068 ipset_data_flags_unset(data, IPSET_CREATE_FLAGS);
1069 D("nla typename %s",
1070 (char *) mnl_attr_get_payload(nla[IPSET_ATTR_TYPENAME]));
1072 ATTR2DATA(session, nla, IPSET_ATTR_FAMILY, cmd_attrs);
1073 ATTR2DATA(session, nla, IPSET_ATTR_TYPENAME, cmd_attrs);
1074 ATTR2DATA(session, nla, IPSET_ATTR_REVISION, cmd_attrs);
1075 D("head: family %u, typename %s",
1076 ipset_data_family(data),
1077 (const char *) ipset_data_get(data, IPSET_OPT_TYPENAME));
1078 if (mnl_attr_parse_nested(nla[IPSET_ATTR_DATA],
1079 create_attr_cb, cattr) < 0)
1080 FAILURE("Broken %s kernel message: "
1081 "cannot validate DATA attributes!",
1083 if (list_create(session, cattr) != MNL_CB_OK)
1084 return MNL_CB_ERROR;
1085 strcpy(session->saved_setname, ipset_data_setname(data));
1088 if (nla[IPSET_ATTR_ADT] != NULL) {
1089 struct nlattr *tb, *adt[IPSET_ATTR_ADT_MAX+1];
1091 mnl_attr_for_each_nested(tb, nla[IPSET_ATTR_ADT]) {
1092 D("ADT attributes for %s", ipset_data_setname(data));
1093 memset(adt, 0, sizeof(adt));
1094 /* Reset ADT specific flags */
1095 ipset_data_flags_unset(data, IPSET_ADT_FLAGS);
1096 if (mnl_attr_parse_nested(tb, adt_attr_cb, adt) < 0)
1097 FAILURE("Broken %s kernel message: "
1098 "cannot validate ADT attributes!",
1100 if (list_adt(session, adt) != MNL_CB_OK)
1101 return MNL_CB_ERROR;
1104 return call_outfn(session) ? MNL_CB_ERROR : MNL_CB_OK;
1107 #ifndef IPSET_PROTOCOL_MIN
1108 #define IPSET_PROTOCOL_MIN IPSET_PROTOCOL
1111 #ifndef IPSET_PROTOCOL_MAX
1112 #define IPSET_PROTOCOL_MAX IPSET_PROTOCOL
1116 callback_version(struct ipset_session *session, struct nlattr *nla[])
1120 min = max = mnl_attr_get_u8(nla[IPSET_ATTR_PROTOCOL]);
1122 if (nla[IPSET_ATTR_PROTOCOL_MIN]) {
1123 min = mnl_attr_get_u8(nla[IPSET_ATTR_PROTOCOL_MIN]);
1127 if (min > IPSET_PROTOCOL_MAX || max < IPSET_PROTOCOL_MIN)
1128 FAILURE("Cannot communicate with kernel: "
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 if (!(session->envopts & IPSET_ENV_QUIET) &&
1134 max != IPSET_PROTOCOL_MAX)
1136 "Kernel support protocol versions %u-%u "
1137 "while userspace supports protocol versions %u-%u",
1138 min, max, IPSET_PROTOCOL_MIN, IPSET_PROTOCOL_MAX);
1140 session->version_checked = true;
1146 callback_header(struct ipset_session *session, struct nlattr *nla[])
1148 const char *setname;
1149 const struct ipset_data *data = session->data;
1151 if (!nla[IPSET_ATTR_SETNAME])
1152 FAILURE("Broken HEADER kernel message: missing setname!");
1154 setname = mnl_attr_get_str(nla[IPSET_ATTR_SETNAME]);
1155 if (!STREQ(setname, ipset_data_setname(data)))
1156 FAILURE("Broken HEADER kernel message: sent setname `%s' "
1157 "does not match with received one `%s'!",
1158 ipset_data_setname(data), setname);
1160 if (!(nla[IPSET_ATTR_TYPENAME] &&
1161 nla[IPSET_ATTR_REVISION] &&
1162 nla[IPSET_ATTR_FAMILY]))
1163 FAILURE("Broken HEADER kernel message: "
1164 "missing attribute '%s'!",
1165 !nla[IPSET_ATTR_TYPENAME] ? "typename" :
1166 !nla[IPSET_ATTR_REVISION] ? "revision" :
1169 ATTR2DATA(session, nla, IPSET_ATTR_TYPENAME, cmd_attrs);
1170 ATTR2DATA(session, nla, IPSET_ATTR_REVISION, cmd_attrs);
1171 ATTR2DATA(session, nla, IPSET_ATTR_FAMILY, cmd_attrs);
1172 D("got family: %u", ipset_data_family(session->data));
1178 callback_type(struct ipset_session *session, struct nlattr *nla[])
1180 const struct ipset_data *data = session->data;
1181 const char *typename, *orig;
1183 if (!(nla[IPSET_ATTR_TYPENAME] &&
1184 nla[IPSET_ATTR_REVISION] &&
1185 nla[IPSET_ATTR_FAMILY]))
1186 FAILURE("Broken TYPE kernel message: "
1187 "missing attribute '%s'!",
1188 !nla[IPSET_ATTR_TYPENAME] ? "typename" :
1189 !nla[IPSET_ATTR_REVISION] ? "revision" :
1192 typename = mnl_attr_get_str(nla[IPSET_ATTR_TYPENAME]);
1193 orig = ipset_data_get(data, IPSET_OPT_TYPENAME);
1194 if (!STREQ(typename, orig))
1195 FAILURE("Broken TYPE kernel message: sent typename `%s' "
1196 "does not match with received one `%s'!",
1199 ATTR2DATA(session, nla, IPSET_ATTR_TYPENAME, cmd_attrs);
1200 ATTR2DATA(session, nla, IPSET_ATTR_REVISION, cmd_attrs);
1201 ATTR2DATA(session, nla, IPSET_ATTR_FAMILY, cmd_attrs);
1202 if (nla[IPSET_ATTR_REVISION_MIN])
1203 ATTR2DATA(session, nla, IPSET_ATTR_REVISION_MIN, cmd_attrs);
1209 cmd_attr_cb(const struct nlattr *attr, void *data)
1211 return generic_data_attr_cb(attr, data, IPSET_ATTR_CMD_MAX, cmd_attrs);
1216 mnl_attr_parse_dbg(const struct nlmsghdr *nlh, int offset,
1217 mnl_attr_cb_t cb, void *data)
1219 int ret = MNL_CB_OK;
1220 struct nlattr *attr = mnl_nlmsg_get_payload_offset(nlh, offset);
1221 int len = nlh->nlmsg_len - MNL_NLMSG_HDRLEN - MNL_ALIGN(offset);
1223 while (mnl_attr_ok(attr, len)) {
1224 D("attr: type %u, attrlen %u, len %u",
1225 mnl_attr_get_type(attr), attr->nla_len, len);
1226 if (cb && (ret = cb(attr, data)) <= MNL_CB_STOP)
1228 attr = mnl_attr_next(attr, &len);
1235 callback_data(const struct nlmsghdr *nlh, void *data)
1237 struct ipset_session *session = data;
1238 struct nlattr *nla[IPSET_ATTR_CMD_MAX+1] = {};
1240 int ret = MNL_CB_OK, nfmsglen = MNL_ALIGN(sizeof(struct nfgenmsg));
1242 D("called, nlmsg_len %u", nlh->nlmsg_len);
1243 cmd = ipset_get_nlmsg_type(nlh);
1244 if (cmd == IPSET_CMD_LIST && session->cmd == IPSET_CMD_SAVE)
1245 /* Kernel always send IPSET_CMD_LIST */
1246 cmd = IPSET_CMD_SAVE;
1248 if (cmd != session->cmd)
1249 FAILURE("Protocol error, we sent command %s "
1250 "and received %s[%u]",
1251 cmd2name[session->cmd],
1252 cmd < IPSET_MSG_MAX ? cmd2name[cmd] : "unknown", cmd);
1254 if (mnl_attr_parse(nlh, nfmsglen, cmd_attr_cb, nla) < MNL_CB_STOP)
1255 FAILURE("Broken %s kernel message: "
1256 "cannot validate and parse attributes",
1259 if (!nla[IPSET_ATTR_PROTOCOL])
1260 FAILURE("Sad, sad day: kernel message %s "
1261 "does not carry the protocol version.",
1264 proto = mnl_attr_get_u8(nla[IPSET_ATTR_PROTOCOL]);
1266 /* Check protocol */
1267 if (cmd != IPSET_CMD_PROTOCOL && proto != IPSET_PROTOCOL)
1268 FAILURE("Giving up: kernel protocol version %u "
1269 "does not match our protocol version %u",
1270 proto, IPSET_PROTOCOL);
1272 D("Message: %s", cmd2name[cmd]);
1274 case IPSET_CMD_LIST:
1275 case IPSET_CMD_SAVE:
1276 ret = callback_list(session, nla, cmd);
1277 D("flag multi: %u", nlh->nlmsg_flags & NLM_F_MULTI);
1278 if (ret >= MNL_CB_STOP && !(nlh->nlmsg_flags & NLM_F_MULTI))
1279 ret = print_set_done(session, false);
1281 case IPSET_CMD_PROTOCOL:
1282 if (!session->version_checked)
1283 ret = callback_version(session, nla);
1285 case IPSET_CMD_HEADER:
1286 ret = callback_header(session, nla);
1288 case IPSET_CMD_TYPE:
1289 ret = callback_type(session, nla);
1292 FAILURE("Data message received when not expected at %s",
1293 cmd2name[session->cmd]);
1295 D("return code: %s", ret == MNL_CB_STOP ? "stop" :
1296 ret == MNL_CB_OK ? "ok" : "error");
1301 callback_done(const struct nlmsghdr *nlh UNUSED, void *data)
1303 struct ipset_session *session = data;
1306 if (session->cmd == IPSET_CMD_LIST || session->cmd == IPSET_CMD_SAVE)
1307 return print_set_done(session, true);
1309 FAILURE("Invalid message received in non LIST or SAVE state.");
1313 decode_errmsg(struct ipset_session *session, const struct nlmsghdr *nlh)
1315 const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
1316 const struct nlmsghdr *msg = &err->msg;
1317 struct nlattr *nla[IPSET_ATTR_CMD_MAX+1] = {};
1319 int nfmsglen = MNL_ALIGN(sizeof(struct nfgenmsg));
1321 if (nlh->nlmsg_len < (uint32_t) MNL_ALIGN(sizeof(struct nlmsgerr)) ||
1322 nlh->nlmsg_len < MNL_ALIGN(sizeof(struct nlmsgerr))
1324 FAILURE("Broken error report message received.");
1326 cmd = ipset_get_nlmsg_type(msg);
1327 D("nlsmg_len: %u", msg->nlmsg_len);
1328 if (cmd != session->cmd)
1329 FAILURE("Protocol error, we sent command %s "
1330 "and received error report for %s[%u]",
1331 cmd2name[session->cmd],
1332 cmd < IPSET_MSG_MAX ? cmd2name[cmd] : "unknown", cmd);
1334 if (mnl_attr_parse(msg, nfmsglen, cmd_attr_cb, nla) < MNL_CB_STOP)
1335 FAILURE("Broken %s error report message: "
1336 "cannot validate attributes",
1339 if (!nla[IPSET_ATTR_PROTOCOL])
1340 FAILURE("Broken %s error report message: "
1341 "missing protocol attribute",
1344 if (nla[IPSET_ATTR_LINENO]) {
1345 session->lineno = mnl_attr_get_u32(nla[IPSET_ATTR_LINENO]);
1346 if (nla[IPSET_ATTR_LINENO]->nla_type & NLA_F_NET_BYTEORDER)
1347 session->lineno = ntohl(session->lineno);
1350 return ipset_errcode(session, cmd, -err->error);
1354 callback_error(const struct nlmsghdr *nlh, void *cbdata)
1356 struct ipset_session *session = cbdata;
1357 struct ipset_data *data = session->data;
1358 const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
1359 int ret = MNL_CB_ERROR;
1361 D(" called, cmd %s", cmd2name[session->cmd]);
1362 if (nlh->nlmsg_len < mnl_nlmsg_size(sizeof(struct nlmsgerr)))
1363 FAILURE("Broken error message received.");
1365 if (err->error == 0) {
1369 switch (session->cmd) {
1370 case IPSET_CMD_CREATE:
1371 /* Add successfully created set to the cache */
1372 ipset_cache_add(ipset_data_setname(data),
1373 ipset_data_get(data, IPSET_OPT_TYPE),
1374 ipset_data_family(data));
1376 case IPSET_CMD_DESTROY:
1377 /* Delete destroyed sets from the cache */
1378 ipset_cache_del(ipset_data_setname(data));
1380 case IPSET_CMD_FLUSH:
1382 case IPSET_CMD_RENAME:
1383 ipset_cache_rename(ipset_data_setname(data),
1384 ipset_data_get(data,
1385 IPSET_OPT_SETNAME2));
1387 case IPSET_CMD_SWAP:
1388 ipset_cache_swap(ipset_data_setname(data),
1389 ipset_data_get(data,
1390 IPSET_OPT_SETNAME2));
1392 case IPSET_CMD_TEST:
1393 if (!(session->envopts & IPSET_ENV_QUIET)) {
1394 ipset_print_elem(session->report,
1398 ipset_warn(session, " is in set %s.",
1399 ipset_data_setname(data));
1405 case IPSET_CMD_LIST:
1406 case IPSET_CMD_SAVE:
1407 /* No set in kernel */
1408 print_set_done(session, true);
1411 FAILURE("ACK message received to command %s[%u], "
1412 "which is not expected",
1413 session->cmd < IPSET_MSG_MAX
1414 ? cmd2name[session->cmd] : "unknown",
1419 D("nlmsgerr error: %u", -err->error);
1421 /* Error messages */
1423 /* Special case for IPSET_CMD_TEST */
1424 if (session->cmd == IPSET_CMD_TEST &&
1425 err->error == -IPSET_ERR_EXIST) {
1426 if (!(session->envopts & IPSET_ENV_QUIET)) {
1427 ipset_print_elem(session->report, IPSET_ERRORBUFLEN,
1428 session->data, IPSET_OPT_NONE, 0);
1429 ipset_warn(session, " is NOT in set %s.",
1430 ipset_data_setname(data));
1435 decode_errmsg(session, nlh);
1441 callback_noop(const struct nlmsghdr *nlh UNUSED, void *data UNUSED)
1446 * Build and send messages
1450 open_nested(struct ipset_session *session, struct nlmsghdr *nlh, int attr)
1452 if (nlh->nlmsg_len + MNL_ATTR_HDRLEN > session->bufsize)
1454 session->nested[session->nestid++] = mnl_attr_nest_start(nlh, attr);
1459 close_nested(struct ipset_session *session, struct nlmsghdr *nlh)
1461 mnl_attr_nest_end(nlh, session->nested[session->nestid-1]);
1462 session->nested[--session->nestid] = NULL;
1466 attr_len(const struct ipset_attr_policy *attr, uint8_t family, uint16_t *flags)
1468 switch (attr->type) {
1469 case MNL_TYPE_NESTED:
1473 *flags = NLA_F_NET_BYTEORDER;
1474 return family == NFPROTO_IPV4 ? sizeof(uint32_t)
1475 : sizeof(struct in6_addr);
1477 *flags = NLA_F_NET_BYTEORDER;
1478 return sizeof(uint64_t);
1480 *flags = NLA_F_NET_BYTEORDER;
1481 return sizeof(uint32_t);
1483 *flags = NLA_F_NET_BYTEORDER;
1484 return sizeof(uint16_t);
1486 return sizeof(uint8_t);
1492 #define BUFFER_FULL(bufsize, nlmsg_len, nestlen, attrlen) \
1493 (nlmsg_len + nestlen + MNL_ATTR_HDRLEN + MNL_ALIGN(alen) + \
1494 MNL_ALIGN(sizeof(struct nlmsgerr)) > bufsize)
1497 rawdata2attr(struct ipset_session *session, struct nlmsghdr *nlh,
1498 const void *d, int type, uint8_t family,
1499 const struct ipset_attr_policy attrs[])
1501 const struct ipset_attr_policy *attr;
1506 attr = &attrs[type];
1507 if (attr->type == MNL_TYPE_NESTED) {
1509 struct nlattr *nested;
1510 int atype = family == NFPROTO_IPV4 ? IPSET_ATTR_IPADDR_IPV4
1511 : IPSET_ATTR_IPADDR_IPV6;
1513 alen = attr_len(attr, family, &flags);
1514 if (BUFFER_FULL(session->bufsize, nlh->nlmsg_len,
1515 MNL_ATTR_HDRLEN, alen))
1517 nested = mnl_attr_nest_start(nlh, type);
1518 D("family: %s", family == NFPROTO_IPV4 ? "INET" :
1519 family == NFPROTO_IPV6 ? "INET6" : "UNSPEC");
1520 mnl_attr_put(nlh, atype | flags, alen, d);
1521 mnl_attr_nest_end(nlh, nested);
1526 alen = attr_len(attr, family, &flags);
1527 if (BUFFER_FULL(session->bufsize, nlh->nlmsg_len, 0, alen))
1530 switch (attr->type) {
1531 case MNL_TYPE_U64: {
1532 uint64_t value = htobe64(*(const uint64_t *)d);
1534 mnl_attr_put(nlh, type | flags, alen, &value);
1537 case MNL_TYPE_U32: {
1538 uint32_t value = htonl(*(const uint32_t *)d);
1540 mnl_attr_put(nlh, type | flags, alen, &value);
1543 case MNL_TYPE_U16: {
1544 uint16_t value = htons(*(const uint16_t *)d);
1546 mnl_attr_put(nlh, type | flags, alen, &value);
1549 case MNL_TYPE_NUL_STRING:
1550 alen = strlen((const char *)d) + 1;
1556 mnl_attr_put(nlh, type | flags, alen, d);
1562 data2attr(struct ipset_session *session, struct nlmsghdr *nlh,
1563 struct ipset_data *data, int type, uint8_t family,
1564 const struct ipset_attr_policy attrs[])
1566 const struct ipset_attr_policy *attr = &attrs[type];
1568 return rawdata2attr(session, nlh, ipset_data_get(data, attr->opt),
1569 type, family, attrs);
1572 #define ADDATTR_PROTOCOL(nlh) \
1573 mnl_attr_put_u8(nlh, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL)
1575 #define ADDATTR(session, nlh, data, type, family, attrs) \
1576 data2attr(session, nlh, data, type, family, attrs)
1578 #define ADDATTR_SETNAME(session, nlh, data) \
1579 data2attr(session, nlh, data, IPSET_ATTR_SETNAME, NFPROTO_IPV4, \
1582 #define ADDATTR_IF(session, nlh, data, type, family, attrs) \
1583 ipset_data_test(data, attrs[type].opt) ? \
1584 data2attr(session, nlh, data, type, family, attrs) : 0
1586 #define ADDATTR_RAW(session, nlh, data, type, attrs) \
1587 rawdata2attr(session, nlh, data, type, NFPROTO_IPV4, attrs)
1590 addattr_create(struct ipset_session *session,
1591 struct nlmsghdr *nlh, struct ipset_data *data, uint8_t family)
1595 for (i = IPSET_ATTR_UNSPEC + 1; i <= IPSET_ATTR_CREATE_MAX; i++)
1596 ADDATTR_IF(session, nlh, data, i, family, create_attrs);
1600 addattr_adt(struct ipset_session *session,
1601 struct nlmsghdr *nlh, struct ipset_data *data, uint8_t family)
1605 for (i = IPSET_ATTR_UNSPEC + 1; i <= IPSET_ATTR_ADT_MAX; i++)
1606 if (ADDATTR_IF(session, nlh, data, i, family, adt_attrs))
1611 #define PRIVATE_MSG_BUFLEN 256
1614 build_send_private_msg(struct ipset_session *session, enum ipset_cmd cmd)
1616 char buffer[PRIVATE_MSG_BUFLEN] __attribute__ ((aligned)) = {};
1617 struct nlmsghdr *nlh = (void *)buffer;
1618 struct ipset_data *data = session->data;
1619 int len = PRIVATE_MSG_BUFLEN, ret;
1620 enum ipset_cmd saved = session->cmd;
1622 /* Initialize header */
1623 session->transport->fill_hdr(session->handle, cmd, buffer, len, 0);
1625 ADDATTR_PROTOCOL(nlh);
1628 case IPSET_CMD_PROTOCOL:
1630 case IPSET_CMD_HEADER:
1631 if (!ipset_data_test(data, IPSET_SETNAME))
1632 return ipset_err(session,
1633 "Invalid internal HEADER command: "
1635 ADDATTR_SETNAME(session, nlh, data);
1637 case IPSET_CMD_TYPE:
1638 if (!ipset_data_test(data, IPSET_OPT_TYPENAME))
1639 return ipset_err(session,
1640 "Invalid internal TYPE command: "
1642 ADDATTR(session, nlh, data, IPSET_ATTR_TYPENAME,
1643 NFPROTO_IPV4, cmd_attrs);
1644 if (ipset_data_test(data, IPSET_OPT_FAMILY))
1645 ADDATTR(session, nlh, data, IPSET_ATTR_FAMILY,
1646 NFPROTO_IPV4, cmd_attrs);
1648 /* bitmap:port and list:set types */
1649 mnl_attr_put_u8(nlh, IPSET_ATTR_FAMILY, NFPROTO_UNSPEC);
1652 return ipset_err(session, "Internal error: "
1653 "unknown private command %u", cmd);
1656 /* Backup, then restore real command */
1658 ret = session->transport->query(session->handle, buffer, len);
1659 session->cmd = saved;
1665 may_aggregate_ad(struct ipset_session *session, enum ipset_cmd cmd)
1667 return session->lineno != 0 &&
1668 (cmd == IPSET_CMD_ADD || cmd == IPSET_CMD_DEL) &&
1669 cmd == session->cmd &&
1670 STREQ(ipset_data_setname(session->data), session->saved_setname);
1674 build_msg(struct ipset_session *session, bool aggregate)
1676 struct nlmsghdr *nlh = session->buffer;
1677 struct ipset_data *data = session->data;
1679 /* Public commands */
1680 D("cmd %s, nlmsg_len: %u", cmd2name[session->cmd], nlh->nlmsg_len);
1681 if (nlh->nlmsg_len == 0) {
1682 /* Initialize header */
1684 session->transport->fill_hdr(session->handle,
1689 ADDATTR_PROTOCOL(nlh);
1691 D("Protocol added, aggregate %s", aggregate ? "yes" : "no");
1692 switch (session->cmd) {
1693 case IPSET_CMD_CREATE: {
1694 const struct ipset_type *type;
1696 /* Sanity checkings */
1697 if (!ipset_data_test(data, IPSET_SETNAME))
1698 return ipset_err(session,
1699 "Invalid create command: missing setname");
1700 if (!ipset_data_test(data, IPSET_OPT_TYPE))
1701 return ipset_err(session,
1702 "Invalid create command: missing settype");
1704 type = ipset_data_get(data, IPSET_OPT_TYPE);
1706 * setname, typename, revision, family, flags (optional) */
1707 ADDATTR_SETNAME(session, nlh, data);
1708 ADDATTR(session, nlh, data, IPSET_ATTR_TYPENAME,
1709 NFPROTO_IPV4, cmd_attrs);
1710 ADDATTR_RAW(session, nlh, &type->revision,
1711 IPSET_ATTR_REVISION, cmd_attrs);
1712 D("family: %u, type family %u",
1713 ipset_data_family(data), type->family);
1714 if (ipset_data_test(data, IPSET_OPT_FAMILY))
1715 ADDATTR(session, nlh, data, IPSET_ATTR_FAMILY,
1716 NFPROTO_IPV4, cmd_attrs);
1718 /* bitmap:port and list:set types */
1719 mnl_attr_put_u8(nlh, IPSET_ATTR_FAMILY, NFPROTO_UNSPEC);
1721 /* Type-specific create attributes */
1722 D("call open_nested");
1723 open_nested(session, nlh, IPSET_ATTR_DATA);
1724 addattr_create(session, nlh, data, type->family);
1725 D("call close_nested");
1726 close_nested(session, nlh);
1729 case IPSET_CMD_DESTROY:
1730 case IPSET_CMD_FLUSH:
1731 case IPSET_CMD_SAVE:
1732 if (ipset_data_test(data, IPSET_SETNAME))
1733 ADDATTR_SETNAME(session, nlh, data);
1735 case IPSET_CMD_LIST: {
1738 if (session->envopts & IPSET_ENV_LIST_SETNAME)
1739 flags |= IPSET_FLAG_LIST_SETNAME;
1740 if (session->envopts & IPSET_ENV_LIST_HEADER)
1741 flags |= IPSET_FLAG_LIST_HEADER;
1742 if (ipset_data_test(data, IPSET_SETNAME))
1743 ADDATTR_SETNAME(session, nlh, data);
1744 if (flags && session->mode != IPSET_LIST_SAVE) {
1745 ipset_data_set(data, IPSET_OPT_FLAGS, &flags);
1746 ADDATTR(session, nlh, data, IPSET_ATTR_FLAGS,
1747 NFPROTO_IPV4, cmd_attrs);
1751 case IPSET_CMD_RENAME:
1752 case IPSET_CMD_SWAP:
1753 if (!ipset_data_test(data, IPSET_SETNAME))
1754 return ipset_err(session,
1755 "Invalid %s command: missing from-setname",
1756 session->cmd == IPSET_CMD_SWAP ? "swap" :
1758 if (!ipset_data_test(data, IPSET_OPT_SETNAME2))
1759 return ipset_err(session,
1760 "Invalid %s command: missing to-setname",
1761 session->cmd == IPSET_CMD_SWAP ? "swap" :
1763 ADDATTR_SETNAME(session, nlh, data);
1764 ADDATTR_RAW(session, nlh,
1765 ipset_data_get(data, IPSET_OPT_SETNAME2),
1766 IPSET_ATTR_SETNAME2, cmd_attrs);
1769 case IPSET_CMD_DEL: {
1770 const struct ipset_type *type;
1773 /* Setname, type not checked/added yet */
1774 if (!ipset_data_test(data, IPSET_SETNAME))
1775 return ipset_err(session,
1776 "Invalid %s command: missing setname",
1777 session->cmd == IPSET_CMD_ADD ? "add" :
1780 if (!ipset_data_test(data, IPSET_OPT_TYPE))
1781 return ipset_err(session,
1782 "Invalid %s command: missing settype",
1783 session->cmd == IPSET_CMD_ADD ? "add" :
1786 /* Core options: setname */
1787 ADDATTR_SETNAME(session, nlh, data);
1788 if (session->lineno != 0) {
1790 ADDATTR_RAW(session, nlh, &session->lineno,
1791 IPSET_ATTR_LINENO, cmd_attrs);
1792 open_nested(session, nlh, IPSET_ATTR_ADT);
1795 type = ipset_data_get(data, IPSET_OPT_TYPE);
1796 D("family: %u, type family %u",
1797 ipset_data_family(data), type->family);
1798 if (open_nested(session, nlh, IPSET_ATTR_DATA)) {
1799 D("open_nested failed");
1802 if (addattr_adt(session, nlh, data, ipset_data_family(data)) ||
1803 ADDATTR_RAW(session, nlh, &session->lineno,
1804 IPSET_ATTR_LINENO, cmd_attrs)) {
1805 /* Cancel last, unfinished nested attribute */
1806 mnl_attr_nest_cancel(nlh,
1807 session->nested[session->nestid-1]);
1808 session->nested[--session->nestid] = NULL;
1811 close_nested(session, nlh);
1814 case IPSET_CMD_TEST: {
1815 const struct ipset_type *type;
1816 /* Return codes are not aggregated, so tests cannot be either */
1818 /* Setname, type not checked/added yet */
1820 if (!ipset_data_test(data, IPSET_SETNAME))
1821 return ipset_err(session,
1822 "Invalid test command: missing setname");
1824 if (!ipset_data_test(data, IPSET_OPT_TYPE))
1825 return ipset_err(session,
1826 "Invalid test command: missing settype");
1828 type = ipset_data_get(data, IPSET_OPT_TYPE);
1829 D("family: %u, type family %u",
1830 ipset_data_family(data), type->family);
1831 ADDATTR_SETNAME(session, nlh, data);
1832 open_nested(session, nlh, IPSET_ATTR_DATA);
1833 addattr_adt(session, nlh, data, ipset_data_family(data));
1834 close_nested(session, nlh);
1838 return ipset_err(session, "Internal error: unknown command %u",
1845 * ipset_commit - commit buffered commands
1846 * @session: session structure
1848 * Commit buffered commands, if there are any.
1850 * Returns 0 on success or a negative error code.
1853 ipset_commit(struct ipset_session *session)
1855 struct nlmsghdr *nlh;
1860 nlh = session->buffer;
1861 D("send buffer: len %u, cmd %s",
1862 nlh->nlmsg_len, cmd2name[session->cmd]);
1863 if (nlh->nlmsg_len == 0)
1867 /* Close nested data blocks */
1868 for (i = session->nestid - 1; i >= 0; i--)
1869 close_nested(session, nlh);
1872 ret = session->transport->query(session->handle,
1876 /* Reset saved data and nested state */
1877 session->saved_setname[0] = '\0';
1878 session->printed_set = 0;
1879 for (i = session->nestid - 1; i >= 0; i--)
1880 session->nested[i] = NULL;
1881 session->nestid = 0;
1887 if (session->report[0] != '\0')
1890 return ipset_err(session,
1891 "Internal protocol error");
1896 static mnl_cb_t cb_ctl[] = {
1897 [NLMSG_NOOP] = callback_noop,
1898 [NLMSG_ERROR] = callback_error,
1899 [NLMSG_DONE] = callback_done,
1900 [NLMSG_OVERRUN] = callback_noop,
1901 [NLMSG_MIN_TYPE] = callback_data,
1904 static inline struct ipset_handle *
1905 init_transport(struct ipset_session *session)
1907 session->handle = session->transport->init(cb_ctl, session);
1909 return session->handle;
1913 * ipset_cmd - execute a command
1914 * @session: session structure
1915 * @cmd: command to execute
1916 * @lineno: command line number in restore mode
1918 * Execute - or prepare/buffer in restore mode - a command.
1919 * It is the caller responsibility that the data field be filled out
1920 * with all required parameters for a successful execution.
1921 * The data field is cleared after this function call for the public
1924 * Returns 0 on success or a negative error code.
1927 ipset_cmd(struct ipset_session *session, enum ipset_cmd cmd, uint32_t lineno)
1929 struct ipset_data *data;
1930 bool aggregate = false;
1935 if (cmd <= IPSET_CMD_NONE || cmd >= IPSET_MSG_MAX)
1938 /* Initialize transport method if not done yet */
1939 if (session->handle == NULL && init_transport(session) == NULL)
1940 return ipset_err(session,
1941 "Cannot open session to kernel.");
1943 data = session->data;
1945 /* Check protocol version once */
1946 if (!session->version_checked) {
1947 if (build_send_private_msg(session, IPSET_CMD_PROTOCOL) < 0)
1951 /* Private commands */
1952 if (cmd == IPSET_CMD_TYPE || cmd == IPSET_CMD_HEADER)
1953 return build_send_private_msg(session, cmd);
1955 /* Check aggregatable commands */
1956 aggregate = may_aggregate_ad(session, cmd);
1958 /* Flush possible aggregated commands */
1959 ret = ipset_commit(session);
1964 /* Real command: update lineno too */
1966 session->lineno = lineno;
1968 /* Set default output mode */
1969 if (cmd == IPSET_CMD_LIST) {
1970 if (session->mode == IPSET_LIST_NONE)
1971 session->mode = IPSET_LIST_PLAIN;
1972 } else if (cmd == IPSET_CMD_SAVE) {
1973 if (session->mode == IPSET_LIST_NONE)
1974 session->mode = IPSET_LIST_SAVE;
1976 /* Start the root element in XML mode */
1977 if ((cmd == IPSET_CMD_LIST || cmd == IPSET_CMD_SAVE) &&
1978 session->mode == IPSET_LIST_XML)
1979 safe_snprintf(session, "<ipsets>\n");
1981 D("next: build_msg");
1982 /* Build new message or append buffered commands */
1983 ret = build_msg(session, aggregate);
1984 D("build_msg returned %u", ret);
1986 /* Buffer is full, send buffered commands */
1987 ret = ipset_commit(session);
1990 ret = build_msg(session, false);
1991 D("build_msg 2 returned %u", ret);
1995 D("past: build_msg");
1997 /* We have to save the type for error handling */
1998 session->saved_type = ipset_data_get(data, IPSET_OPT_TYPE);
1999 if (session->lineno != 0 &&
2000 (cmd == IPSET_CMD_ADD || cmd == IPSET_CMD_DEL)) {
2001 /* Save setname for the next possible aggregated restore line */
2002 strcpy(session->saved_setname, ipset_data_setname(data));
2003 ipset_data_reset(data);
2004 /* Don't commit: we may aggregate next command */
2010 ret = ipset_commit(session);
2014 ipset_data_reset(data);
2019 * ipset_session_outfn - set session output printing function
2021 * Set the session printing function.
2025 ipset_session_outfn(struct ipset_session *session, ipset_outfn outfn)
2027 session->outfn = outfn ? outfn : printf;
2032 * ipset_session_init - initialize an ipset session
2034 * Initialize an ipset session by allocating a session structure
2035 * and filling out with the initialization data.
2037 * Returns the created session sctructure on success or NULL.
2039 struct ipset_session *
2040 ipset_session_init(ipset_outfn outfn)
2042 struct ipset_session *session;
2043 size_t bufsize = getpagesize();
2045 /* Create session object */
2046 session = calloc(1, sizeof(struct ipset_session) + bufsize);
2047 if (session == NULL)
2049 session->bufsize = bufsize;
2050 session->buffer = session + 1;
2052 /* The single transport method yet */
2053 session->transport = &ipset_mnl_transport;
2055 /* Output function */
2056 session->outfn = outfn;
2058 /* Initialize data structures */
2059 session->data = ipset_data_init();
2060 if (session->data == NULL)
2072 * ipset_session_fini - destroy an ipset session
2073 * @session: session structure
2075 * Destroy an ipset session: release the created structures.
2077 * Returns 0 on success or a negative error code.
2080 ipset_session_fini(struct ipset_session *session)
2084 if (session->handle)
2085 session->transport->fini(session->handle);
2087 ipset_data_fini(session->data);