]> granicus.if.org Git - ipset/blob - lib/session.c
Handle padding attribute properly in userspace.
[ipset] / lib / session.c
1 /* Copyright 2007-2010 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
2  *
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.
6  */
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 */
18
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 */
30
31 #define IPSET_NEST_MAX  4
32
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 */
38         /* Command state */
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 */
47         /* Output buffer */
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 */
53         char *errmsg;
54         char *warnmsg;
55         uint8_t envopts;                        /* Session env opts */
56         /* Kernel message buffer */
57         size_t bufsize;
58         void *buffer;
59 };
60
61 /*
62  * Glue functions
63  */
64
65 /**
66  * ipset_session_data - return pointer to the data
67  * @session: session structure
68  *
69  * Returns the pointer to the data structure of the session.
70  */
71 struct ipset_data *
72 ipset_session_data(const struct ipset_session *session)
73 {
74         assert(session);
75         return session->data;
76 }
77
78 /**
79  * ipset_session_handle - return pointer to the handle
80  * @session: session structure
81  *
82  * Returns the pointer to the transport handle structure of the session.
83  */
84 struct ipset_handle *
85 ipset_session_handle(const struct ipset_session *session)
86 {
87         assert(session);
88         return session->handle;
89 }
90
91 /**
92  * ipset_saved_type - return pointer to the saved type
93  * @session: session structure
94  *
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.
97  */
98 const struct ipset_type *
99 ipset_saved_type(const struct ipset_session *session)
100 {
101         assert(session);
102         return session->saved_type;
103 }
104
105 /**
106  * ipset_session_lineno - set session lineno
107  * @session: session structure
108  *
109  * Set session lineno to report parser errors correctly.
110  */
111 void
112 ipset_session_lineno(struct ipset_session *session, uint32_t lineno)
113 {
114         assert(session);
115         session->lineno = lineno;
116 }
117
118 /*
119  * Environment options
120  */
121
122 /**
123  * ipset_envopt_parse - parse/set environment option
124  * @session: session structure
125  * @opt: environment option
126  * @arg: option argument (unused)
127  *
128  * Parse and set an environment option.
129  *
130  * Returns 0 on success or a negative error code.
131  */
132 int
133 ipset_envopt_parse(struct ipset_session *session, int opt,
134                    const char *arg UNUSED)
135 {
136         assert(session);
137
138         switch (opt) {
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;
146                 return 0;
147         default:
148                 break;
149         }
150         return -1;
151 }
152
153 /**
154  * ipset_envopt_test - test environment option
155  * @session: session structure
156  * @opt: environment option
157  *
158  * Test whether the environment option is set in the session.
159  *
160  * Returns true or false.
161  */
162 bool
163 ipset_envopt_test(struct ipset_session *session, enum ipset_envopt opt)
164 {
165         assert(session);
166         return session->envopts & opt;
167 }
168
169 /**
170  * ipset_session_output - set the session output mode
171  * @session: session structure
172  * @mode: output mode
173  *
174  * Set the output mode for the session.
175  *
176  * Returns 0 on success or a negative error code.
177  */
178 int
179 ipset_session_output(struct ipset_session *session,
180                      enum ipset_output_mode mode)
181 {
182         assert(session);
183         session->mode = mode;
184         return 0;
185 }
186
187 /*
188  * Error and warning reporting
189  */
190
191 /**
192  * ipset_session_report - fill the report buffer
193  * @session: session structure
194  * @type: report type
195  * @fmt: message format
196  *
197  * Fill the report buffer with an error or warning message.
198  * Depending on the report type, set the error or warning
199  * message pointer.
200  *
201  * Returns -1.
202  */
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, ...)
207 {
208         int len, offset = 0;
209         va_list args;
210
211         assert(session);
212         assert(fmt);
213
214         if (session->lineno != 0 && type == IPSET_ERROR) {
215                 sprintf(session->report, "Error in line %u: ",
216                         session->lineno);
217         }
218         offset = strlen(session->report);
219
220         va_start(args, fmt);
221         len = vsnprintf(session->report + offset,
222                         IPSET_ERRORBUFLEN - 1 - offset,
223                         fmt, args);
224         va_end(args);
225
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");
230
231         if (type == IPSET_ERROR) {
232                 session->errmsg = session->report;
233                 session->warnmsg = NULL;
234         } else {
235                 session->errmsg = NULL;
236                 session->warnmsg = session->report;
237         }
238         return -1;
239 }
240
241 /**
242  * ipset_session_reset - reset the report buffer
243  * @session: session structure
244  *
245  * Reset the report buffer, the error and warning pointers.
246  */
247 void
248 ipset_session_report_reset(struct ipset_session *session)
249 {
250         assert(session);
251         session->report[0] = '\0';
252         session->errmsg = session->warnmsg = NULL;
253 }
254
255 /**
256  * ipset_session_error - return the report buffer as error
257  * @session: session structure
258  *
259  * Return the pointer to the report buffer as an error report.
260  * If there is no error message in the buffer, NULL returned.
261  */
262 const char *
263 ipset_session_error(const struct ipset_session *session)
264 {
265         assert(session);
266
267         return session->errmsg;
268 }
269
270 /**
271  * ipset_session_warning - return the report buffer as warning
272  * @session: session structure
273  *
274  * Return the pointer to the report buffer as a warning report.
275  * If there is no warning message in the buffer, NULL returned.
276  */
277 const char *
278 ipset_session_warning(const struct ipset_session *session)
279 {
280         assert(session);
281
282         return session->warnmsg;
283 }
284
285 /*
286  * Receive data from the kernel
287  */
288
289 struct ipset_attr_policy {
290         uint16_t type;
291         uint16_t len;
292         enum ipset_opt opt;
293 };
294
295 /* Attribute policies and mapping to options */
296 static const struct ipset_attr_policy cmd_attrs[] = {
297         [IPSET_ATTR_PROTOCOL] = {
298                 .type = MNL_TYPE_U8,
299         },
300         [IPSET_ATTR_SETNAME] = {
301                 .type = MNL_TYPE_NUL_STRING,
302                 .opt  = IPSET_SETNAME,
303                 .len  = IPSET_MAXNAMELEN,
304         },
305         [IPSET_ATTR_TYPENAME] = {
306                 .type = MNL_TYPE_NUL_STRING,
307                 .opt = IPSET_OPT_TYPENAME,
308                 .len  = IPSET_MAXNAMELEN,
309         },
310         /* IPSET_ATTR_SETNAME2 is an alias for IPSET_ATTR_TYPENAME */
311         [IPSET_ATTR_REVISION] = {
312                 .type = MNL_TYPE_U8,
313                 .opt = IPSET_OPT_REVISION,
314         },
315         [IPSET_ATTR_FAMILY] = {
316                 .type = MNL_TYPE_U8,
317                 .opt = IPSET_OPT_FAMILY,
318         },
319         [IPSET_ATTR_FLAGS] = {
320                 .type = MNL_TYPE_U32,
321                 .opt = IPSET_OPT_FLAGS,
322         },
323         [IPSET_ATTR_DATA] = {
324                 .type = MNL_TYPE_NESTED,
325         },
326         [IPSET_ATTR_ADT] = {
327                 .type = MNL_TYPE_NESTED,
328         },
329         [IPSET_ATTR_REVISION_MIN] = {
330                 .type = MNL_TYPE_U8,
331                 .opt = IPSET_OPT_REVISION_MIN,
332         },
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,
337         },
338 };
339
340 static const struct ipset_attr_policy create_attrs[] = {
341         [IPSET_ATTR_IP] = {
342                 .type = MNL_TYPE_NESTED,
343                 .opt = IPSET_OPT_IP,
344         },
345         [IPSET_ATTR_IP_TO] = {
346                 .type = MNL_TYPE_NESTED,
347                 .opt = IPSET_OPT_IP_TO,
348         },
349         [IPSET_ATTR_CIDR] = {
350                 .type = MNL_TYPE_U8,
351                 .opt = IPSET_OPT_CIDR,
352         },
353         [IPSET_ATTR_PORT] = {
354                 .type = MNL_TYPE_U16,
355                 .opt = IPSET_OPT_PORT,
356         },
357         [IPSET_ATTR_PORT_TO] = {
358                 .type = MNL_TYPE_U16,
359                 .opt = IPSET_OPT_PORT_TO,
360         },
361         [IPSET_ATTR_TIMEOUT] = {
362                 .type = MNL_TYPE_U32,
363                 .opt = IPSET_OPT_TIMEOUT,
364         },
365         [IPSET_ATTR_PROTO] = {
366                 .type = MNL_TYPE_U8,
367                 .opt = IPSET_OPT_PROTO,
368         },
369         [IPSET_ATTR_CADT_FLAGS] = {
370                 .type = MNL_TYPE_U32,
371                 .opt = IPSET_OPT_CADT_FLAGS,
372         },
373         [IPSET_ATTR_GC] = {
374                 .type = MNL_TYPE_U32,
375                 .opt = IPSET_OPT_GC,
376         },
377         [IPSET_ATTR_HASHSIZE] = {
378                 .type = MNL_TYPE_U32,
379                 .opt = IPSET_OPT_HASHSIZE,
380         },
381         [IPSET_ATTR_MAXELEM] = {
382                 .type = MNL_TYPE_U32,
383                 .opt = IPSET_OPT_MAXELEM,
384         },
385         [IPSET_ATTR_MARKMASK] = {
386                 .type = MNL_TYPE_U32,
387                 .opt = IPSET_OPT_MARKMASK,
388         },
389         [IPSET_ATTR_NETMASK] = {
390                 .type = MNL_TYPE_U8,
391                 .opt = IPSET_OPT_NETMASK,
392         },
393         [IPSET_ATTR_PROBES] = {
394                 .type = MNL_TYPE_U8,
395                 .opt = IPSET_OPT_PROBES,
396         },
397         [IPSET_ATTR_RESIZE] = {
398                 .type = MNL_TYPE_U8,
399                 .opt = IPSET_OPT_RESIZE,
400         },
401         [IPSET_ATTR_SIZE] = {
402                 .type = MNL_TYPE_U32,
403                 .opt = IPSET_OPT_SIZE,
404         },
405         [IPSET_ATTR_ELEMENTS] = {
406                 .type = MNL_TYPE_U32,
407                 .opt = IPSET_OPT_ELEMENTS,
408         },
409         [IPSET_ATTR_REFERENCES] = {
410                 .type = MNL_TYPE_U32,
411                 .opt = IPSET_OPT_REFERENCES,
412         },
413         [IPSET_ATTR_MEMSIZE] = {
414                 .type = MNL_TYPE_U32,
415                 .opt = IPSET_OPT_MEMSIZE,
416         },
417 };
418
419 static const struct ipset_attr_policy adt_attrs[] = {
420         [IPSET_ATTR_IP] = {
421                 .type = MNL_TYPE_NESTED,
422                 .opt = IPSET_OPT_IP,
423         },
424         [IPSET_ATTR_IP_TO] = {
425                 .type = MNL_TYPE_NESTED,
426                 .opt = IPSET_OPT_IP_TO,
427         },
428         [IPSET_ATTR_CIDR] = {
429                 .type = MNL_TYPE_U8,
430                 .opt = IPSET_OPT_CIDR,
431         },
432         [IPSET_ATTR_MARK] = {
433                 .type = MNL_TYPE_U32,
434                 .opt = IPSET_OPT_MARK,
435         },
436         [IPSET_ATTR_PORT] = {
437                 .type = MNL_TYPE_U16,
438                 .opt = IPSET_OPT_PORT,
439         },
440         [IPSET_ATTR_PORT_TO] = {
441                 .type = MNL_TYPE_U16,
442                 .opt = IPSET_OPT_PORT_TO,
443         },
444         [IPSET_ATTR_PROTO] = {
445                 .type = MNL_TYPE_U8,
446                 .opt = IPSET_OPT_PROTO,
447         },
448         [IPSET_ATTR_TIMEOUT] = {
449                 .type = MNL_TYPE_U32,
450                 .opt = IPSET_OPT_TIMEOUT,
451         },
452         [IPSET_ATTR_CADT_FLAGS] = {
453                 .type = MNL_TYPE_U32,
454                 .opt = IPSET_OPT_CADT_FLAGS,
455         },
456         [IPSET_ATTR_LINENO] = {
457                 .type = MNL_TYPE_U32,
458                 .opt = IPSET_OPT_LINENO,
459         },
460         [IPSET_ATTR_ETHER] = {
461                 .type = MNL_TYPE_BINARY,
462                 .opt = IPSET_OPT_ETHER,
463                 .len  = ETH_ALEN,
464         },
465         [IPSET_ATTR_NAME] = {
466                 .type = MNL_TYPE_NUL_STRING,
467                 .opt = IPSET_OPT_NAME,
468                 .len  = IPSET_MAXNAMELEN,
469         },
470         [IPSET_ATTR_NAMEREF] = {
471                 .type = MNL_TYPE_NUL_STRING,
472                 .opt = IPSET_OPT_NAMEREF,
473                 .len  = IPSET_MAXNAMELEN,
474         },
475         [IPSET_ATTR_IP2] = {
476                 .type = MNL_TYPE_NESTED,
477                 .opt = IPSET_OPT_IP2,
478         },
479         [IPSET_ATTR_CIDR2] = {
480                 .type = MNL_TYPE_U8,
481                 .opt = IPSET_OPT_CIDR2,
482         },
483         [IPSET_ATTR_IP2_TO] = {
484                 .type = MNL_TYPE_NESTED,
485                 .opt = IPSET_OPT_IP2_TO,
486         },
487         [IPSET_ATTR_IFACE] = {
488                 .type = MNL_TYPE_NUL_STRING,
489                 .opt = IPSET_OPT_IFACE,
490                 .len  = IFNAMSIZ,
491         },
492         [IPSET_ATTR_PACKETS] = {
493                 .type = MNL_TYPE_U64,
494                 .opt = IPSET_OPT_PACKETS,
495         },
496         [IPSET_ATTR_BYTES] = {
497                 .type = MNL_TYPE_U64,
498                 .opt = IPSET_OPT_BYTES,
499         },
500         [IPSET_ATTR_COMMENT] = {
501                 .type = MNL_TYPE_NUL_STRING,
502                 .opt = IPSET_OPT_ADT_COMMENT,
503                 .len  = IPSET_MAX_COMMENT_SIZE + 1,
504         },
505         [IPSET_ATTR_SKBMARK] = {
506                 .type = MNL_TYPE_U64,
507                 .opt = IPSET_OPT_SKBMARK,
508         },
509         [IPSET_ATTR_SKBPRIO] = {
510                 .type = MNL_TYPE_U32,
511                 .opt = IPSET_OPT_SKBPRIO,
512         },
513         [IPSET_ATTR_SKBQUEUE] = {
514                 .type = MNL_TYPE_U16,
515                 .opt = IPSET_OPT_SKBQUEUE,
516         },
517         [IPSET_ATTR_PAD] = {
518                 .type = MNL_TYPE_UNSPEC,
519                 .len = 0,
520         },
521 };
522
523 static const struct ipset_attr_policy ipaddr_attrs[] = {
524         [IPSET_ATTR_IPADDR_IPV4] = {
525                 .type = MNL_TYPE_U32,
526         },
527         [IPSET_ATTR_IPADDR_IPV6] = {
528                 .type = MNL_TYPE_BINARY,
529                 .len = sizeof(union nf_inet_addr),
530         },
531 };
532
533 #ifdef IPSET_DEBUG
534 static int debug = 1;
535 #endif
536
537 static int
538 generic_data_attr_cb(const struct nlattr *attr, void *data,
539                      int attr_max, const struct ipset_attr_policy *policy)
540 {
541         const struct nlattr **tb = data;
542         int type = mnl_attr_get_type(attr);
543
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);
547                 return MNL_CB_ERROR;
548         }
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));
552                 return MNL_CB_ERROR;
553         }
554         if (policy[type].type == MNL_TYPE_NUL_STRING &&
555             mnl_attr_get_payload_len(attr) > policy[type].len)
556                 return MNL_CB_ERROR;
557         tb[type] = attr;
558         return MNL_CB_OK;
559 }
560
561 static int
562 create_attr_cb(const struct nlattr *attr, void *data)
563 {
564         return generic_data_attr_cb(attr, data,
565                                     IPSET_ATTR_CREATE_MAX, create_attrs);
566 }
567
568 static int
569 adt_attr_cb(const struct nlattr *attr, void *data)
570 {
571         return generic_data_attr_cb(attr, data,
572                                     IPSET_ATTR_ADT_MAX, adt_attrs);
573 }
574
575 static int
576 ipaddr_attr_cb(const struct nlattr *attr, void *data)
577 {
578         return generic_data_attr_cb(attr, data,
579                                     IPSET_ATTR_IPADDR_MAX, ipaddr_attrs);
580 }
581
582 #define FAILURE(format, args...) \
583         { ipset_err(session, format  , ## args); return MNL_CB_ERROR; }
584
585 static int
586 attr2data(struct ipset_session *session, struct nlattr *nla[],
587           int type, const struct ipset_attr_policy attrs[])
588 {
589         struct ipset_data *data = session->data;
590         const struct ipset_attr_policy *attr;
591         const void *d;
592         uint64_t v64;
593         uint32_t v32;
594         uint16_t v16;
595         int ret;
596
597         attr = &attrs[type];
598         d = mnl_attr_get_payload(nla[type]);
599
600         if (attr->type == MNL_TYPE_UNSPEC)
601                 return 0;
602         if (attr->type == MNL_TYPE_NESTED && attr->opt) {
603                 /* IP addresses */
604                 struct nlattr *ipattr[IPSET_ATTR_IPADDR_MAX+1] = {};
605                 uint8_t family = ipset_data_family(data);
606                 int atype;
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!");
612
613                 /* Validate by hand */
614                 switch (family) {
615                 case NFPROTO_IPV4:
616                         atype = IPSET_ATTR_IPADDR_IPV4;
617                         if (!ipattr[atype])
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!");
624                         break;
625                 case NFPROTO_IPV6:
626                         atype = IPSET_ATTR_IPADDR_IPV6;
627                         if (!ipattr[atype])
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!");
634                         break;
635                 default:
636                         FAILURE("Broken kernel message: "
637                                 "IP address attribute but "
638                                 "family is unspecified!");
639                 }
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) {
644                 case MNL_TYPE_U64: {
645                         uint64_t tmp;
646                         /* Ensure data alignment */
647                         memcpy(&tmp, d, sizeof(tmp));
648                         v64  = be64toh(tmp);
649                         d = &v64;
650                         break;
651                 }
652                 case MNL_TYPE_U32: {
653                         v32  = ntohl(*(const uint32_t *)d);
654                         d = &v32;
655                         break;
656                 }
657                 case MNL_TYPE_U16: {
658                         v16 = ntohs(*(const uint16_t *)d);
659                         d = &v16;
660                         break;
661                 }
662                 default:
663                         break;
664                 }
665         }
666 #ifdef IPSET_DEBUG
667          else
668                 D("hostorder attr type %u", type);
669         if (type == IPSET_ATTR_TYPENAME)
670                 D("nla typename %s", (const char *) d);
671 #endif
672         ret = ipset_data_set(data, attr->opt, d);
673 #ifdef IPSET_DEBUG
674         if (type == IPSET_ATTR_TYPENAME)
675                 D("nla typename %s",
676                   (const char *) ipset_data_get(data, IPSET_OPT_TYPENAME));
677 #endif
678         return ret;
679 }
680
681 #define ATTR2DATA(session, nla, type, attrs)            \
682         if (attr2data(session, nla, type, attrs) < 0)   \
683                 return MNL_CB_ERROR
684
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",
700 };
701
702 static inline int
703 call_outfn(struct ipset_session *session)
704 {
705         int ret = session->outfn("%s", session->outbuf);
706
707         session->outbuf[0] = '\0';
708
709         return ret < 0 ? ret : 0;
710 }
711
712 /* Handle printing failures */
713 static jmp_buf printf_failure;
714
715 static int
716 handle_snprintf_error(struct ipset_session *session,
717                       int len, int ret, int loop)
718 {
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);
722                 if (loop) {
723                         ipset_err(session,
724                                 "Internal error at printing, loop detected!");
725                         longjmp(printf_failure, 1);
726                 }
727
728                 session->outbuf[len] = '\0';
729                 if (call_outfn(session)) {
730                         ipset_err(session,
731                                 "Internal error, could not print output buffer!");
732                         longjmp(printf_failure, 1);
733                 }
734                 return 1;
735         }
736         return 0;
737 }
738
739 static int __attribute__((format(printf, 2, 3)))
740 safe_snprintf(struct ipset_session *session, const char *fmt, ...)
741 {
742         va_list args;
743         int len, ret, loop = 0;
744
745         do {
746                 len = strlen(session->outbuf);
747                 D("len: %u, retry %u", len, loop);
748                 va_start(args, fmt);
749                 ret = vsnprintf(session->outbuf + len,
750                                 IPSET_OUTBUFLEN - len,
751                                 fmt, args);
752                 va_end(args);
753                 loop = handle_snprintf_error(session, len, ret, loop);
754         } while (loop);
755
756         return ret;
757 }
758
759 static int
760 safe_dprintf(struct ipset_session *session, ipset_printfn fn,
761              enum ipset_opt opt)
762 {
763         int len, ret, loop = 0;
764
765         do {
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);
771         } while (loop);
772
773         return ret;
774 }
775
776 static int
777 list_adt(struct ipset_session *session, struct nlattr *nla[])
778 {
779         const struct ipset_data *data = session->data;
780         const struct ipset_type *type;
781         const struct ipset_arg *arg;
782         int i, found = 0;
783
784         D("enter");
785         /* Check and load type, family */
786         if (!ipset_data_test(data, IPSET_OPT_TYPE))
787                 type = ipset_type_get(session, IPSET_CMD_ADD);
788         else
789                 type = ipset_data_get(data, IPSET_OPT_TYPE);
790
791         if (type == NULL)
792                 return MNL_CB_ERROR;
793
794         for (i = IPSET_ATTR_UNSPEC + 1; i <= IPSET_ATTR_ADT_MAX; i++)
795                 if (nla[i]) {
796                         found++;
797                         ATTR2DATA(session, nla, i, adt_attrs);
798         }
799         D("attr found %u", found);
800         if (!found)
801                 return MNL_CB_OK;
802
803         switch (session->mode) {
804         case IPSET_LIST_SAVE:
805                 safe_snprintf(session, "add %s ", ipset_data_setname(data));
806                 break;
807         case IPSET_LIST_XML:
808                 safe_snprintf(session, "<member><elem>");
809                 break;
810         case IPSET_LIST_PLAIN:
811         default:
812                 break;
813         }
814
815         safe_dprintf(session, ipset_print_elem, IPSET_OPT_ELEM);
816         if (session->mode == IPSET_LIST_XML)
817                 safe_snprintf(session, "</elem>");
818
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)))
823                         continue;
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]);
829                                 break;
830                         }
831                         safe_snprintf(session, " %s ", arg->name[0]);
832                         safe_dprintf(session, arg->print, arg->opt);
833                         break;
834                 case IPSET_LIST_XML:
835                         if (arg->has_arg == IPSET_NO_ARG) {
836                                 safe_snprintf(session,
837                                               "<%s/>", arg->name[0]);
838                                 break;
839                         }
840                         safe_snprintf(session, "<%s>", arg->name[0]);
841                         safe_dprintf(session, arg->print, arg->opt);
842                         safe_snprintf(session, "</%s>", arg->name[0]);
843                         break;
844                 default:
845                         break;
846                 }
847         }
848
849         if (session->mode == IPSET_LIST_XML)
850                 safe_snprintf(session, "</member>\n");
851         else
852                 safe_snprintf(session, "\n");
853
854         return MNL_CB_OK;
855 }
856
857 #define FAMILY_TO_STR(f)                \
858         ((f) == NFPROTO_IPV4 ? "inet" : \
859          (f) == NFPROTO_IPV6 ? "inet6" : "any")
860
861 static int
862 list_create(struct ipset_session *session, struct nlattr *nla[])
863 {
864         const struct ipset_data *data = session->data;
865         const struct ipset_type *type;
866         const struct ipset_arg *arg;
867         uint8_t family;
868         int i;
869
870         for (i = IPSET_ATTR_UNSPEC + 1; i <= IPSET_ATTR_CREATE_MAX; i++)
871                 if (nla[i]) {
872                         D("add attr %u, opt %u", i, create_attrs[i].opt);
873                         ATTR2DATA(session, nla, i, create_attrs);
874                 }
875
876         type = ipset_type_check(session);
877         if (type == NULL)
878                 return MNL_CB_ERROR;
879         family = ipset_data_family(data);
880
881         switch (session->mode) {
882         case IPSET_LIST_SAVE:
883                 safe_snprintf(session, "create %s %s",
884                               ipset_data_setname(data),
885                               type->name);
886                 break;
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);
893                 break;
894         case IPSET_LIST_XML:
895                 safe_snprintf(session,
896                               "<ipset name=\"%s\">\n"
897                               "<type>%s</type>\n"
898                               "<revision>%u</revision>\n"
899                               "<header>",
900                               ipset_data_setname(data),
901                               type->name, type->revision);
902                 break;
903         default:
904                 break;
905         }
906
907         for (arg = type->args[IPSET_CREATE]; arg != NULL && arg->opt; arg++) {
908                 if (!arg->print ||
909                     !ipset_data_test(data, arg->opt) ||
910                     (arg->opt == IPSET_OPT_FAMILY &&
911                      family == type->family))
912                         continue;
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]);
918                                 break;
919                         }
920                         safe_snprintf(session, " %s ", arg->name[0]);
921                         safe_dprintf(session, arg->print, arg->opt);
922                         break;
923                 case IPSET_LIST_XML:
924                         if (arg->has_arg == IPSET_NO_ARG) {
925                                 safe_snprintf(session,
926                                               "<%s/>", arg->name[0]);
927                                 break;
928                         }
929                         safe_snprintf(session, "<%s>", arg->name[0]);
930                         safe_dprintf(session, arg->print, arg->opt);
931                         safe_snprintf(session, "</%s>", arg->name[0]);
932                         break;
933                 default:
934                         break;
935                 }
936         }
937         switch (session->mode) {
938         case IPSET_LIST_SAVE:
939                 safe_snprintf(session, "\n");
940                 break;
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);
949                 }
950                 safe_snprintf(session,
951                         session->envopts & IPSET_ENV_LIST_HEADER ?
952                         "\n" : "\nMembers:\n");
953                 break;
954         case IPSET_LIST_XML:
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");
964                 }
965                 safe_snprintf(session,
966                         session->envopts & IPSET_ENV_LIST_HEADER ?
967                         "</header>\n" :
968                         "</header>\n<members>\n");
969                 break;
970         default:
971                 break;
972         }
973         session->printed_set++;
974
975         return MNL_CB_OK;
976 }
977
978 static int
979 print_set_done(struct ipset_session *session, bool callback_done)
980 {
981         D("called for %s", session->saved_setname[0] == '\0'
982                 ? "NONE" : session->saved_setname);
983         switch (session->mode) {
984         case IPSET_LIST_XML:
985                 if (session->envopts & IPSET_ENV_LIST_SETNAME)
986                         break;
987                 if (session->envopts & IPSET_ENV_LIST_HEADER) {
988                         if (session->saved_setname[0] != '\0')
989                                 safe_snprintf(session, "</ipset>\n");
990                         break;
991                 }
992                 if (session->saved_setname[0] != '\0')
993                         safe_snprintf(session, "</members>\n</ipset>\n");
994                 break;
995         default:
996                 break;
997         }
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;
1001 }
1002
1003 static int
1004 callback_list(struct ipset_session *session, struct nlattr *nla[],
1005               enum ipset_cmd cmd)
1006 {
1007         struct ipset_data *data = session->data;
1008
1009         if (setjmp(printf_failure)) {
1010                 session->saved_setname[0] = '\0';
1011                 session->printed_set = 0;
1012                 return MNL_CB_ERROR;
1013         }
1014
1015         if (!nla[IPSET_ATTR_SETNAME])
1016                 FAILURE("Broken %s kernel message: missing setname!",
1017                         cmd2name[cmd]);
1018
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));
1026                 else
1027                         safe_snprintf(session, "%s\n",
1028                                       ipset_data_setname(data));
1029                 return call_outfn(session) ? MNL_CB_ERROR : MNL_CB_OK;
1030         }
1031
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]);
1038         } else {
1039                 if (nla[IPSET_ATTR_DATA] == NULL)
1040                         FAILURE("Broken %s kernel message: "
1041                                 "missing DATA part!", cmd2name[cmd]);
1042
1043                 /* Close previous set printing */
1044                 if (session->saved_setname[0] != '\0')
1045                         print_set_done(session, false);
1046         }
1047
1048         if (nla[IPSET_ATTR_DATA] != NULL) {
1049                 struct nlattr *cattr[IPSET_ATTR_CREATE_MAX+1] = {};
1050
1051                 if (!(nla[IPSET_ATTR_TYPENAME] &&
1052                       nla[IPSET_ATTR_FAMILY] &&
1053                       nla[IPSET_ATTR_REVISION]))
1054                         FAILURE("Broken %s kernel message: missing %s!",
1055                                 cmd2name[cmd],
1056                                 !nla[IPSET_ATTR_TYPENAME] ? "typename" :
1057                                 !nla[IPSET_ATTR_FAMILY] ? "family" :
1058                                 "revision");
1059
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]));
1064
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!",
1075                                 cmd2name[cmd]);
1076                 if (list_create(session, cattr) != MNL_CB_OK)
1077                         return MNL_CB_ERROR;
1078                 strcpy(session->saved_setname, ipset_data_setname(data));
1079         }
1080
1081         if (nla[IPSET_ATTR_ADT] != NULL) {
1082                 struct nlattr *tb, *adt[IPSET_ATTR_ADT_MAX+1];
1083
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!",
1092                                         cmd2name[cmd]);
1093                         if (list_adt(session, adt) != MNL_CB_OK)
1094                                 return MNL_CB_ERROR;
1095                 }
1096         }
1097         return call_outfn(session) ? MNL_CB_ERROR : MNL_CB_OK;
1098 }
1099
1100 #ifndef IPSET_PROTOCOL_MIN
1101 #define IPSET_PROTOCOL_MIN      IPSET_PROTOCOL
1102 #endif
1103
1104 #ifndef IPSET_PROTOCOL_MAX
1105 #define IPSET_PROTOCOL_MAX      IPSET_PROTOCOL
1106 #endif
1107
1108 static int
1109 callback_version(struct ipset_session *session, struct nlattr *nla[])
1110 {
1111         uint8_t min, max;
1112
1113         min = max = mnl_attr_get_u8(nla[IPSET_ATTR_PROTOCOL]);
1114
1115         if (nla[IPSET_ATTR_PROTOCOL_MIN]) {
1116                 min = mnl_attr_get_u8(nla[IPSET_ATTR_PROTOCOL_MIN]);
1117                 D("min: %u", min);
1118         }
1119
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);
1125
1126         if (!(session->envopts & IPSET_ENV_QUIET) &&
1127             max != IPSET_PROTOCOL_MAX)
1128                 ipset_warn(session,
1129                            "Kernel support protocol versions %u-%u "
1130                            "while userspace supports protocol versions %u-%u",
1131                            min, max, IPSET_PROTOCOL_MIN, IPSET_PROTOCOL_MAX);
1132
1133         session->version_checked = true;
1134
1135         return MNL_CB_STOP;
1136 }
1137
1138 static int
1139 callback_header(struct ipset_session *session, struct nlattr *nla[])
1140 {
1141         const char *setname;
1142         const struct ipset_data *data = session->data;
1143
1144         if (!nla[IPSET_ATTR_SETNAME])
1145                 FAILURE("Broken HEADER kernel message: missing setname!");
1146
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);
1152
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" :
1160                         "family");
1161
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));
1166
1167         return MNL_CB_STOP;
1168 }
1169
1170 static int
1171 callback_type(struct ipset_session *session, struct nlattr *nla[])
1172 {
1173         const struct ipset_data *data = session->data;
1174         const char *typename, *orig;
1175
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" :
1183                         "family");
1184
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'!",
1190                         orig, typename);
1191
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);
1197
1198         return MNL_CB_STOP;
1199 }
1200
1201 static int
1202 cmd_attr_cb(const struct nlattr *attr, void *data)
1203 {
1204         return generic_data_attr_cb(attr, data, IPSET_ATTR_CMD_MAX, cmd_attrs);
1205 }
1206
1207 #if 0
1208 static int
1209 mnl_attr_parse_dbg(const struct nlmsghdr *nlh, int offset,
1210                    mnl_attr_cb_t cb, void *data)
1211 {
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);
1215
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)
1220                         return ret;
1221                 attr = mnl_attr_next(attr, &len);
1222         }
1223         return ret;
1224 }
1225 #endif
1226
1227 static int
1228 callback_data(const struct nlmsghdr *nlh, void *data)
1229 {
1230         struct ipset_session *session = data;
1231         struct nlattr *nla[IPSET_ATTR_CMD_MAX+1] = {};
1232         uint8_t proto, cmd;
1233         int ret = MNL_CB_OK, nfmsglen = MNL_ALIGN(sizeof(struct nfgenmsg));
1234
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;
1240
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);
1246
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",
1250                         cmd2name[cmd]);
1251
1252         if (!nla[IPSET_ATTR_PROTOCOL])
1253                 FAILURE("Sad, sad day: kernel message %s "
1254                         "does not carry the protocol version.",
1255                         cmd2name[cmd]);
1256
1257         proto = mnl_attr_get_u8(nla[IPSET_ATTR_PROTOCOL]);
1258
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);
1264
1265         D("Message: %s", cmd2name[cmd]);
1266         switch (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);
1273                 break;
1274         case IPSET_CMD_PROTOCOL:
1275                 if (!session->version_checked)
1276                         ret = callback_version(session, nla);
1277                 break;
1278         case IPSET_CMD_HEADER:
1279                 ret = callback_header(session, nla);
1280                 break;
1281         case IPSET_CMD_TYPE:
1282                 ret = callback_type(session, nla);
1283                 break;
1284         default:
1285                 FAILURE("Data message received when not expected at %s",
1286                         cmd2name[session->cmd]);
1287         }
1288         D("return code: %s", ret == MNL_CB_STOP ? "stop" :
1289                              ret == MNL_CB_OK ? "ok" : "error");
1290         return ret;
1291 }
1292
1293 static int
1294 callback_done(const struct nlmsghdr *nlh UNUSED, void *data)
1295 {
1296         struct ipset_session *session = data;
1297
1298         D(" called");
1299         if (session->cmd == IPSET_CMD_LIST || session->cmd == IPSET_CMD_SAVE)
1300                 return print_set_done(session, true);
1301
1302         FAILURE("Invalid message received in non LIST or SAVE state.");
1303 }
1304
1305 static int
1306 decode_errmsg(struct ipset_session *session, const struct nlmsghdr *nlh)
1307 {
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] = {};
1311         enum ipset_cmd cmd;
1312         int nfmsglen = MNL_ALIGN(sizeof(struct nfgenmsg));
1313
1314         if (nlh->nlmsg_len < (uint32_t) MNL_ALIGN(sizeof(struct nlmsgerr)) ||
1315             nlh->nlmsg_len < MNL_ALIGN(sizeof(struct nlmsgerr))
1316                              + msg->nlmsg_len)
1317                 FAILURE("Broken error report message received.");
1318
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);
1326
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",
1330                         cmd2name[cmd]);
1331
1332         if (!nla[IPSET_ATTR_PROTOCOL])
1333                 FAILURE("Broken %s error report message: "
1334                         "missing protocol attribute",
1335                         cmd2name[cmd]);
1336
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);
1341         }
1342
1343         return ipset_errcode(session, cmd, -err->error);
1344 }
1345
1346 static int
1347 callback_error(const struct nlmsghdr *nlh, void *cbdata)
1348 {
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;
1353
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.");
1357
1358         if (err->error == 0) {
1359                 /* ACK */
1360                 ret = MNL_CB_STOP;
1361
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));
1368                         break;
1369                 case IPSET_CMD_DESTROY:
1370                         /* Delete destroyed sets from the cache */
1371                         ipset_cache_del(ipset_data_setname(data));
1372                         /* Fall through */
1373                 case IPSET_CMD_FLUSH:
1374                         break;
1375                 case IPSET_CMD_RENAME:
1376                         ipset_cache_rename(ipset_data_setname(data),
1377                                            ipset_data_get(data,
1378                                                           IPSET_OPT_SETNAME2));
1379                         break;
1380                 case IPSET_CMD_SWAP:
1381                         ipset_cache_swap(ipset_data_setname(data),
1382                                          ipset_data_get(data,
1383                                                         IPSET_OPT_SETNAME2));
1384                         break;
1385                 case IPSET_CMD_TEST:
1386                         if (!(session->envopts & IPSET_ENV_QUIET)) {
1387                                 ipset_print_elem(session->report,
1388                                                  IPSET_ERRORBUFLEN,
1389                                                  session->data,
1390                                                  IPSET_OPT_NONE, 0);
1391                                 ipset_warn(session, " is in set %s.",
1392                                            ipset_data_setname(data));
1393                         }
1394                         /* Fall through */
1395                 case IPSET_CMD_ADD:
1396                 case IPSET_CMD_DEL:
1397                         break;
1398                 case IPSET_CMD_LIST:
1399                 case IPSET_CMD_SAVE:
1400                         /* No set in kernel */
1401                         print_set_done(session, true);
1402                         break;
1403                 default:
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",
1408                                 session->cmd);
1409                 }
1410                 return ret;
1411         }
1412         D("nlmsgerr error: %u", -err->error);
1413
1414         /* Error messages */
1415
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));
1424                 }
1425                 return ret;
1426         }
1427
1428         decode_errmsg(session, nlh);
1429
1430         return ret;
1431 }
1432
1433 static int
1434 callback_noop(const struct nlmsghdr *nlh UNUSED, void *data UNUSED)
1435 {
1436         return MNL_CB_OK;
1437 }
1438 /*
1439  * Build and send messages
1440  */
1441
1442 static inline int
1443 open_nested(struct ipset_session *session, struct nlmsghdr *nlh, int attr)
1444 {
1445         if (nlh->nlmsg_len + MNL_ATTR_HDRLEN > session->bufsize)
1446                 return 1;
1447         session->nested[session->nestid++] = mnl_attr_nest_start(nlh, attr);
1448         return 0;
1449 }
1450
1451 static inline void
1452 close_nested(struct ipset_session *session, struct nlmsghdr *nlh)
1453 {
1454         mnl_attr_nest_end(nlh, session->nested[session->nestid-1]);
1455         session->nested[--session->nestid] = NULL;
1456 }
1457
1458 static size_t
1459 attr_len(const struct ipset_attr_policy *attr, uint8_t family, uint16_t *flags)
1460 {
1461         switch (attr->type) {
1462         case MNL_TYPE_NESTED:
1463                 if (attr->len)
1464                         return attr->len;
1465
1466                 *flags = NLA_F_NET_BYTEORDER;
1467                 return family == NFPROTO_IPV4 ? sizeof(uint32_t)
1468                                          : sizeof(struct in6_addr);
1469         case MNL_TYPE_U64:
1470                 *flags = NLA_F_NET_BYTEORDER;
1471                 return sizeof(uint64_t);
1472         case MNL_TYPE_U32:
1473                 *flags = NLA_F_NET_BYTEORDER;
1474                 return sizeof(uint32_t);
1475         case MNL_TYPE_U16:
1476                 *flags = NLA_F_NET_BYTEORDER;
1477                 return sizeof(uint16_t);
1478         case MNL_TYPE_U8:
1479                 return sizeof(uint8_t);
1480         default:
1481                 return attr->len;
1482         }
1483 }
1484
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)
1488
1489 static int
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[])
1493 {
1494         const struct ipset_attr_policy *attr;
1495         int alen;
1496         uint16_t flags = 0;
1497
1498
1499         attr = &attrs[type];
1500         if (attr->type == MNL_TYPE_NESTED) {
1501                 /* IP addresses */
1502                 struct nlattr *nested;
1503                 int atype = family == NFPROTO_IPV4 ? IPSET_ATTR_IPADDR_IPV4
1504                                               : IPSET_ATTR_IPADDR_IPV6;
1505
1506                 alen = attr_len(attr, family, &flags);
1507                 if (BUFFER_FULL(session->bufsize, nlh->nlmsg_len,
1508                                 MNL_ATTR_HDRLEN, alen))
1509                         return 1;
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);
1515
1516                 return 0;
1517         }
1518
1519         alen = attr_len(attr, family, &flags);
1520         if (BUFFER_FULL(session->bufsize, nlh->nlmsg_len, 0, alen))
1521                 return 1;
1522
1523         switch (attr->type) {
1524         case MNL_TYPE_U64: {
1525                 uint64_t value = htobe64(*(const uint64_t *)d);
1526
1527                 mnl_attr_put(nlh, type | flags, alen, &value);
1528                 return 0;
1529         }
1530         case MNL_TYPE_U32: {
1531                 uint32_t value = htonl(*(const uint32_t *)d);
1532
1533                 mnl_attr_put(nlh, type | flags, alen, &value);
1534                 return 0;
1535         }
1536         case MNL_TYPE_U16: {
1537                 uint16_t value = htons(*(const uint16_t *)d);
1538
1539                 mnl_attr_put(nlh, type | flags, alen, &value);
1540                 return 0;
1541         }
1542         case MNL_TYPE_NUL_STRING:
1543                 alen = strlen((const char *)d) + 1;
1544                 break;
1545         default:
1546                 break;
1547         }
1548
1549         mnl_attr_put(nlh, type | flags, alen, d);
1550
1551         return 0;
1552 }
1553
1554 static int
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[])
1558 {
1559         const struct ipset_attr_policy *attr = &attrs[type];
1560
1561         return rawdata2attr(session, nlh, ipset_data_get(data, attr->opt),
1562                             type, family, attrs);
1563 }
1564
1565 #define ADDATTR_PROTOCOL(nlh)                                           \
1566         mnl_attr_put_u8(nlh, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL)
1567
1568 #define ADDATTR(session, nlh, data, type, family, attrs)                \
1569         data2attr(session, nlh, data, type, family, attrs)
1570
1571 #define ADDATTR_SETNAME(session, nlh, data)                             \
1572         data2attr(session, nlh, data, IPSET_ATTR_SETNAME, NFPROTO_IPV4, \
1573                   cmd_attrs)
1574
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
1578
1579 #define ADDATTR_RAW(session, nlh, data, type, attrs)                    \
1580         rawdata2attr(session, nlh, data, type, NFPROTO_IPV4, attrs)
1581
1582 static void
1583 addattr_create(struct ipset_session *session,
1584                struct nlmsghdr *nlh, struct ipset_data *data, uint8_t family)
1585 {
1586         int i;
1587
1588         for (i = IPSET_ATTR_UNSPEC + 1; i <= IPSET_ATTR_CREATE_MAX; i++)
1589                 ADDATTR_IF(session, nlh, data, i, family, create_attrs);
1590 }
1591
1592 static int
1593 addattr_adt(struct ipset_session *session,
1594             struct nlmsghdr *nlh, struct ipset_data *data, uint8_t family)
1595 {
1596         int i;
1597
1598         for (i = IPSET_ATTR_UNSPEC + 1; i <= IPSET_ATTR_ADT_MAX; i++)
1599                 if (ADDATTR_IF(session, nlh, data, i, family, adt_attrs))
1600                         return 1;
1601         return 0;
1602 }
1603
1604 #define PRIVATE_MSG_BUFLEN      256
1605
1606 static int
1607 build_send_private_msg(struct ipset_session *session, enum ipset_cmd cmd)
1608 {
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;
1614
1615         /* Initialize header */
1616         session->transport->fill_hdr(session->handle, cmd, buffer, len, 0);
1617
1618         ADDATTR_PROTOCOL(nlh);
1619
1620         switch (cmd) {
1621         case IPSET_CMD_PROTOCOL:
1622                 break;
1623         case IPSET_CMD_HEADER:
1624                 if (!ipset_data_test(data, IPSET_SETNAME))
1625                         return ipset_err(session,
1626                                 "Invalid internal HEADER command: "
1627                                 "missing setname");
1628                 ADDATTR_SETNAME(session, nlh, data);
1629                 break;
1630         case IPSET_CMD_TYPE:
1631                 if (!ipset_data_test(data, IPSET_OPT_TYPENAME))
1632                         return ipset_err(session,
1633                                 "Invalid internal TYPE command: "
1634                                 "missing settype");
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);
1640                 else
1641                         /* bitmap:port and list:set types */
1642                         mnl_attr_put_u8(nlh, IPSET_ATTR_FAMILY, NFPROTO_UNSPEC);
1643                 break;
1644         default:
1645                 return ipset_err(session, "Internal error: "
1646                                  "unknown private command %u", cmd);
1647         }
1648
1649         /* Backup, then restore real command */
1650         session->cmd = cmd;
1651         ret = session->transport->query(session->handle, buffer, len);
1652         session->cmd = saved;
1653
1654         return ret;
1655 }
1656
1657 static inline bool
1658 may_aggregate_ad(struct ipset_session *session, enum ipset_cmd cmd)
1659 {
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);
1664 }
1665
1666 static int
1667 build_msg(struct ipset_session *session, bool aggregate)
1668 {
1669         struct nlmsghdr *nlh = session->buffer;
1670         struct ipset_data *data = session->data;
1671
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 */
1676                 aggregate = false;
1677                 session->transport->fill_hdr(session->handle,
1678                                              session->cmd,
1679                                              session->buffer,
1680                                              session->bufsize,
1681                                              session->envopts);
1682                 ADDATTR_PROTOCOL(nlh);
1683         }
1684         D("Protocol added, aggregate %s", aggregate ? "yes" : "no");
1685         switch (session->cmd) {
1686         case IPSET_CMD_CREATE: {
1687                 const struct ipset_type *type;
1688
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");
1696
1697                 type = ipset_data_get(data, IPSET_OPT_TYPE);
1698                 /* Core attributes:
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);
1710                 else
1711                         /* bitmap:port and list:set types */
1712                         mnl_attr_put_u8(nlh, IPSET_ATTR_FAMILY, NFPROTO_UNSPEC);
1713
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);
1720                 break;
1721         }
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);
1727                 break;
1728         case IPSET_CMD_LIST: {
1729                 uint32_t flags = 0;
1730
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);
1741                 }
1742                 break;
1743         }
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" :
1750                                 "rename");
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" :
1755                                 "rename");
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);
1760                 break;
1761         case IPSET_CMD_ADD:
1762         case IPSET_CMD_DEL: {
1763                 const struct ipset_type *type;
1764
1765                 if (!aggregate) {
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" :
1771                                         "del");
1772
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" :
1777                                         "del");
1778
1779                         /* Core options: setname */
1780                         ADDATTR_SETNAME(session, nlh, data);
1781                         if (session->lineno != 0) {
1782                                 /* Restore mode */
1783                                 ADDATTR_RAW(session, nlh, &session->lineno,
1784                                             IPSET_ATTR_LINENO, cmd_attrs);
1785                                 open_nested(session, nlh, IPSET_ATTR_ADT);
1786                         }
1787                 }
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");
1793                         return 1;
1794                 }
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;
1802                         return 1;
1803                 }
1804                 close_nested(session, nlh);
1805                 break;
1806         }
1807         case IPSET_CMD_TEST: {
1808                 const struct ipset_type *type;
1809                 /* Return codes are not aggregated, so tests cannot be either */
1810
1811                 /* Setname, type not checked/added yet */
1812
1813                 if (!ipset_data_test(data, IPSET_SETNAME))
1814                         return ipset_err(session,
1815                                 "Invalid test command: missing setname");
1816
1817                 if (!ipset_data_test(data, IPSET_OPT_TYPE))
1818                         return ipset_err(session,
1819                                 "Invalid test command: missing settype");
1820
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);
1828                 break;
1829         }
1830         default:
1831                 return ipset_err(session, "Internal error: unknown command %u",
1832                                  session->cmd);
1833         }
1834         return 0;
1835 }
1836
1837 /**
1838  * ipset_commit - commit buffered commands
1839  * @session: session structure
1840  *
1841  * Commit buffered commands, if there are any.
1842  *
1843  * Returns 0 on success or a negative error code.
1844  */
1845 int
1846 ipset_commit(struct ipset_session *session)
1847 {
1848         struct nlmsghdr *nlh;
1849         int ret = 0, i;
1850
1851         assert(session);
1852
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)
1857                 /* Nothing to do */
1858                 return 0;
1859
1860         /* Close nested data blocks */
1861         for (i = session->nestid - 1; i >= 0; i--)
1862                 close_nested(session, nlh);
1863
1864         /* Send buffer */
1865         ret = session->transport->query(session->handle,
1866                                         session->buffer,
1867                                         session->bufsize);
1868
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;
1875         nlh->nlmsg_len = 0;
1876
1877         D("ret: %d", ret);
1878
1879         if (ret < 0) {
1880                 if (session->report[0] != '\0')
1881                         return -1;
1882                 else
1883                         return ipset_err(session,
1884                                          "Internal protocol error");
1885         }
1886         return 0;
1887 }
1888
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,
1895 };
1896
1897 static inline struct ipset_handle *
1898 init_transport(struct ipset_session *session)
1899 {
1900         session->handle = session->transport->init(cb_ctl, session);
1901
1902         return session->handle;
1903 }
1904
1905 /**
1906  * ipset_cmd - execute a command
1907  * @session: session structure
1908  * @cmd: command to execute
1909  * @lineno: command line number in restore mode
1910  *
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
1915  * commands.
1916  *
1917  * Returns 0 on success or a negative error code.
1918  */
1919 int
1920 ipset_cmd(struct ipset_session *session, enum ipset_cmd cmd, uint32_t lineno)
1921 {
1922         struct ipset_data *data;
1923         bool aggregate = false;
1924         int ret = -1;
1925
1926         assert(session);
1927
1928         if (cmd <= IPSET_CMD_NONE || cmd >= IPSET_MSG_MAX)
1929                 return 0;
1930
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.");
1935
1936         data = session->data;
1937
1938         /* Check protocol version once */
1939         if (!session->version_checked) {
1940                 if (build_send_private_msg(session, IPSET_CMD_PROTOCOL) < 0)
1941                         return -1;
1942         }
1943
1944         /* Private commands */
1945         if (cmd == IPSET_CMD_TYPE || cmd == IPSET_CMD_HEADER)
1946                 return build_send_private_msg(session, cmd);
1947
1948         /* Check aggregatable commands */
1949         aggregate = may_aggregate_ad(session, cmd);
1950         if (!aggregate) {
1951                 /* Flush possible aggregated commands */
1952                 ret = ipset_commit(session);
1953                 if (ret < 0)
1954                         return ret;
1955         }
1956
1957         /* Real command: update lineno too */
1958         session->cmd = cmd;
1959         session->lineno = lineno;
1960
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;
1968         }
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");
1973
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);
1978         if (ret > 0) {
1979                 /* Buffer is full, send buffered commands */
1980                 ret = ipset_commit(session);
1981                 if (ret < 0)
1982                         goto cleanup;
1983                 ret = build_msg(session, false);
1984                 D("build_msg 2 returned %u", ret);
1985         }
1986         if (ret < 0)
1987                 goto cleanup;
1988         D("past: build_msg");
1989
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 */
1998                 ret = 0;
1999                 goto cleanup;
2000         }
2001
2002         D("call commit");
2003         ret = ipset_commit(session);
2004
2005 cleanup:
2006         D("reset data");
2007         ipset_data_reset(data);
2008         return ret;
2009 }
2010
2011 /**
2012  * ipset_session_outfn - set session output printing function
2013  *
2014  * Set the session printing function.
2015  *
2016  */
2017 int
2018 ipset_session_outfn(struct ipset_session *session, ipset_outfn outfn)
2019 {
2020         session->outfn = outfn ? outfn : printf;
2021         return 0;
2022 }
2023
2024 /**
2025  * ipset_session_init - initialize an ipset session
2026  *
2027  * Initialize an ipset session by allocating a session structure
2028  * and filling out with the initialization data.
2029  *
2030  * Returns the created session sctructure on success or NULL.
2031  */
2032 struct ipset_session *
2033 ipset_session_init(ipset_outfn outfn)
2034 {
2035         struct ipset_session *session;
2036         size_t bufsize = getpagesize();
2037
2038         /* Create session object */
2039         session = calloc(1, sizeof(struct ipset_session) + bufsize);
2040         if (session == NULL)
2041                 return NULL;
2042         session->bufsize = bufsize;
2043         session->buffer = session + 1;
2044
2045         /* The single transport method yet */
2046         session->transport = &ipset_mnl_transport;
2047
2048         /* Output function */
2049         session->outfn = outfn;
2050
2051         /* Initialize data structures */
2052         session->data = ipset_data_init();
2053         if (session->data == NULL)
2054                 goto free_session;
2055
2056         ipset_cache_init();
2057         return session;
2058
2059 free_session:
2060         free(session);
2061         return NULL;
2062 }
2063
2064 /**
2065  * ipset_session_fini - destroy an ipset session
2066  * @session: session structure
2067  *
2068  * Destroy an ipset session: release the created structures.
2069  *
2070  * Returns 0 on success or a negative error code.
2071  */
2072 int
2073 ipset_session_fini(struct ipset_session *session)
2074 {
2075         assert(session);
2076
2077         if (session->handle)
2078                 session->transport->fini(session->handle);
2079         if (session->data)
2080                 ipset_data_fini(session->data);
2081
2082         ipset_cache_fini();
2083         free(session);
2084         return 0;
2085 }
2086
2087 #ifdef IPSET_DEBUG
2088 #include "debug.c"
2089 #endif