From: Martin Josefsson <gandalf@wlug.westbo.se>
To: netfilter-devel@lists.netfilter.org
Subject: [PATCH RFT] Improve iptables error reporting
Date: Sun, 12 Aug 2007 01:21:04 +0200 (CEST) [thread overview]
Message-ID: <Pine.LNX.4.62.0708120038080.28796@wlug.westbo.se> (raw)
[-- Attachment #1: Type: TEXT/PLAIN, Size: 2284 bytes --]
Hi
Here's a small patch that reworks the iptables/ip6tables error reporting a
bit. The purpose of this patch is to try to provide more resonable error
messages.
Currently a lot of functions in libiptc sets a pointer called iptc_fn to
point to the current function, and then they set errno to an error
code.
This has at least one major shortcoming:
int some_other_function(void) {
iptc_fn = some_other_function;
...
return 1;
}
void some_function(void) {
iptc_fn = some_function;
if (some_other_function())
errno = ENOENT;
}
Now we have iptc_fn == some_other_function but errno was meant for
some_function, a mismatch has occured, which will cause the wrong error
message to be printed.
What this patch does is to add TC_ERROR (iptc_error/ip6tc_error) which
sets both iptc_errfn and iptc_errno at the same time, and it's only called
when an error is detected. Thus we don't have any mismatches anymore.
Example of error messages:
loop:
old:
# iptables -I INPUT -j tuut
iptables: Too many levels of symbolic links
new:
# iptables -I INPUT -j tuut
iptables: Loop found in table
chain not found:
old:
# iptables -I foo -j ACCEPT
iptables: No chain/target/match by that name
new:
# iptables -I foo -j ACCEPT
iptables: No chain by that name
jump to predefined chain:
old:
# iptables -I tuut -j INPUT
iptables: Invalid argument
new:
# iptables -I tuut -j INPUT
iptables: Can't jump to a built-in target
removal of not empty chain:
old:
# iptables -X tuut
iptables: Directory not empty
new:
# iptables -X tuut
iptables: Chain is not empty
removal of chain with references:
old:
# iptables -X tuut
iptables: Too many links
new:
# iptables -X tuut
iptables: Can't delete chain with references left
Unknown errors will now be displayed like:
(this is made up)
"Unknown error, iptc_commit: 30 (foo not in phase with the moon)"
function, error code and strerror() (might give a clue).
(line number can be added if needed)
And if something signals an error (return value) but doesn't call
iptc_error()/ip6tc_error() it looks like this:
"Something forgot to set the error reason"
Please test and report success or failure. I'm likely to have missed
some/many errors.
/Martin
[-- Attachment #2: Type: TEXT/PLAIN, Size: 33701 bytes --]
diff -X /home/gandalf/dontdiff.ny -x '*.d' -x '*.man' -x '*.8' -urNp iptables-1.3.8-20070810.orig/include/libiptc/libip6tc.h iptables-1.3.8-20070810/include/libiptc/libip6tc.h
--- iptables-1.3.8-20070810.orig/include/libiptc/libip6tc.h 2003-05-05 21:33:40.000000000 +0200
+++ iptables-1.3.8-20070810/include/libiptc/libip6tc.h 2007-08-12 00:06:23.000000000 +0200
@@ -17,6 +17,10 @@ typedef char ip6t_chainlabel[32];
#define IP6TC_LABEL_QUEUE "QUEUE"
#define IP6TC_LABEL_RETURN "RETURN"
+#ifndef TC_LIBNAME
+#define TC_LIBNAME "libip6tc"
+#endif
+
/* Transparent handle type. */
typedef struct ip6tc_handle *ip6tc_handle_t;
@@ -145,8 +149,11 @@ int ip6tc_commit(ip6tc_handle_t *handle)
/* Get raw socket. */
int ip6tc_get_raw_socket();
+/* Report errors */
+void ip6tc_error(const char *, int);
+
/* Translates errno numbers into more human-readable form than strerror. */
-const char *ip6tc_strerror(int err);
+const char *ip6tc_strerror();
/* Return prefix length, or -1 if not contiguous */
int ipv6_prefix_length(const struct in6_addr *a);
diff -X /home/gandalf/dontdiff.ny -x '*.d' -x '*.man' -x '*.8' -urNp iptables-1.3.8-20070810.orig/include/libiptc/libiptc.h iptables-1.3.8-20070810/include/libiptc/libiptc.h
--- iptables-1.3.8-20070810.orig/include/libiptc/libiptc.h 2003-05-02 17:30:11.000000000 +0200
+++ iptables-1.3.8-20070810/include/libiptc/libiptc.h 2007-08-12 00:06:31.000000000 +0200
@@ -25,6 +25,10 @@ typedef char ipt_chainlabel[32];
#define IPTC_LABEL_QUEUE "QUEUE"
#define IPTC_LABEL_RETURN "RETURN"
+#ifndef TC_LIBNAME
+#define TC_LIBNAME "libip4tc"
+#endif
+
/* Transparent handle type. */
typedef struct iptc_handle *iptc_handle_t;
@@ -155,8 +159,11 @@ int iptc_commit(iptc_handle_t *handle);
/* Get raw socket. */
int iptc_get_raw_socket();
+/* Report errors */
+void iptc_error(const char *, int);
+
/* Translates errno numbers into more human-readable form than strerror. */
-const char *iptc_strerror(int err);
+const char *iptc_strerror();
#ifdef __cplusplus
}
Binary files iptables-1.3.8-20070810.orig/ip6tables and iptables-1.3.8-20070810/ip6tables differ
diff -X /home/gandalf/dontdiff.ny -x '*.d' -x '*.man' -x '*.8' -urNp iptables-1.3.8-20070810.orig/ip6tables-restore.c iptables-1.3.8-20070810/ip6tables-restore.c
--- iptables-1.3.8-20070810.orig/ip6tables-restore.c 2007-07-24 07:52:07.000000000 +0200
+++ iptables-1.3.8-20070810/ip6tables-restore.c 2007-08-11 23:39:27.000000000 +0200
@@ -240,14 +240,14 @@ int main(int argc, char *argv[])
exit_error(PARAMETER_PROBLEM,
"error flushing chain "
"'%s':%s\n", chain,
- strerror(errno));
+ ip6tc_strerror());
} else {
DEBUGP("Creating new chain '%s'\n", chain);
if (!ip6tc_create_chain(chain, &handle))
exit_error(PARAMETER_PROBLEM,
"error creating chain "
"'%s':%s\n", chain,
- strerror(errno));
+ ip6tc_strerror());
}
}
@@ -286,7 +286,7 @@ int main(int argc, char *argv[])
"Can't set policy `%s'"
" on `%s' line %u: %s\n",
chain, policy, line,
- ip6tc_strerror(errno));
+ ip6tc_strerror());
}
ret = 1;
diff -X /home/gandalf/dontdiff.ny -x '*.d' -x '*.man' -x '*.8' -urNp iptables-1.3.8-20070810.orig/ip6tables-save.c iptables-1.3.8-20070810/ip6tables-save.c
--- iptables-1.3.8-20070810.orig/ip6tables-save.c 2007-05-10 17:00:39.000000000 +0200
+++ iptables-1.3.8-20070810/ip6tables-save.c 2007-08-11 19:12:51.000000000 +0200
@@ -257,7 +257,7 @@ static int do_output(const char *tablena
h = ip6tc_init(tablename);
if (!h)
exit_error(OTHER_PROBLEM, "Can't initialize: %s\n",
- ip6tc_strerror(errno));
+ ip6tc_strerror());
if (!binary) {
time_t now = time(NULL);
diff -X /home/gandalf/dontdiff.ny -x '*.d' -x '*.man' -x '*.8' -urNp iptables-1.3.8-20070810.orig/ip6tables-standalone.c iptables-1.3.8-20070810/ip6tables-standalone.c
--- iptables-1.3.8-20070810.orig/ip6tables-standalone.c 2004-12-27 20:49:28.000000000 +0100
+++ iptables-1.3.8-20070810/ip6tables-standalone.c 2007-08-11 19:12:51.000000000 +0200
@@ -60,7 +60,7 @@ main(int argc, char *argv[])
if (!ret)
fprintf(stderr, "ip6tables: %s\n",
- ip6tc_strerror(errno));
+ ip6tc_strerror());
exit(!ret);
}
diff -X /home/gandalf/dontdiff.ny -x '*.d' -x '*.man' -x '*.8' -urNp iptables-1.3.8-20070810.orig/ip6tables.c iptables-1.3.8-20070810/ip6tables.c
--- iptables-1.3.8-20070810.orig/ip6tables.c 2007-08-01 17:19:15.000000000 +0200
+++ iptables-1.3.8-20070810/ip6tables.c 2007-08-12 00:08:32.000000000 +0200
@@ -1330,7 +1330,9 @@ list_entries(const ip6t_chainlabel chain
found = 1;
}
- errno = ENOENT;
+ if (!found)
+ ip6tc_error(__FUNCTION__, ENOENT);
+
return found;
}
@@ -1896,7 +1898,7 @@ int do_command6(int argc, char *argv[],
if (!*handle)
exit_error(VERSION_PROBLEM,
"can't initialize ip6tables table `%s': %s",
- *table, ip6tc_strerror(errno));
+ *table, ip6tc_strerror());
if (command == CMD_APPEND
|| command == CMD_DELETE
Binary files iptables-1.3.8-20070810.orig/iptables and iptables-1.3.8-20070810/iptables differ
Binary files iptables-1.3.8-20070810.orig/iptables-restore and iptables-1.3.8-20070810/iptables-restore differ
diff -X /home/gandalf/dontdiff.ny -x '*.d' -x '*.man' -x '*.8' -urNp iptables-1.3.8-20070810.orig/iptables-restore.c iptables-1.3.8-20070810/iptables-restore.c
--- iptables-1.3.8-20070810.orig/iptables-restore.c 2007-07-24 07:52:07.000000000 +0200
+++ iptables-1.3.8-20070810/iptables-restore.c 2007-08-11 23:38:31.000000000 +0200
@@ -243,14 +243,14 @@ main(int argc, char *argv[])
exit_error(PARAMETER_PROBLEM,
"error flushing chain "
"'%s':%s\n", chain,
- strerror(errno));
+ iptc_strerror());
} else {
DEBUGP("Creating new chain '%s'\n", chain);
if (!iptc_create_chain(chain, &handle))
exit_error(PARAMETER_PROBLEM,
"error creating chain "
"'%s':%s\n", chain,
- strerror(errno));
+ iptc_strerror());
}
}
@@ -289,7 +289,7 @@ main(int argc, char *argv[])
"Can't set policy `%s'"
" on `%s' line %u: %s\n",
chain, policy, line,
- iptc_strerror(errno));
+ iptc_strerror());
}
ret = 1;
Binary files iptables-1.3.8-20070810.orig/iptables-save and iptables-1.3.8-20070810/iptables-save differ
diff -X /home/gandalf/dontdiff.ny -x '*.d' -x '*.man' -x '*.8' -urNp iptables-1.3.8-20070810.orig/iptables-save.c iptables-1.3.8-20070810/iptables-save.c
--- iptables-1.3.8-20070810.orig/iptables-save.c 2007-05-10 17:00:39.000000000 +0200
+++ iptables-1.3.8-20070810/iptables-save.c 2007-08-11 19:12:51.000000000 +0200
@@ -268,7 +268,7 @@ static int do_output(const char *tablena
h = iptc_init(tablename);
if (!h)
exit_error(OTHER_PROBLEM, "Can't initialize: %s\n",
- iptc_strerror(errno));
+ iptc_strerror());
if (!binary) {
time_t now = time(NULL);
diff -X /home/gandalf/dontdiff.ny -x '*.d' -x '*.man' -x '*.8' -urNp iptables-1.3.8-20070810.orig/iptables-standalone.c iptables-1.3.8-20070810/iptables-standalone.c
--- iptables-1.3.8-20070810.orig/iptables-standalone.c 2006-06-19 18:53:03.000000000 +0200
+++ iptables-1.3.8-20070810/iptables-standalone.c 2007-08-11 19:12:51.000000000 +0200
@@ -66,7 +66,7 @@ main(int argc, char *argv[])
if (!ret) {
fprintf(stderr, "iptables: %s\n",
- iptc_strerror(errno));
+ iptc_strerror());
if (errno == EAGAIN) {
exit(RESOURCE_PROBLEM);
}
Binary files iptables-1.3.8-20070810.orig/iptables-xml and iptables-1.3.8-20070810/iptables-xml differ
diff -X /home/gandalf/dontdiff.ny -x '*.d' -x '*.man' -x '*.8' -urNp iptables-1.3.8-20070810.orig/iptables.c iptables-1.3.8-20070810/iptables.c
--- iptables-1.3.8-20070810.orig/iptables.c 2007-08-01 17:19:15.000000000 +0200
+++ iptables-1.3.8-20070810/iptables.c 2007-08-12 00:08:15.000000000 +0200
@@ -1371,7 +1371,9 @@ list_entries(const ipt_chainlabel chain,
found = 1;
}
- errno = ENOENT;
+ if (!found)
+ iptc_error(__FUNCTION__, ENOENT);
+
return found;
}
@@ -1961,7 +1963,7 @@ int do_command(int argc, char *argv[], c
if (!*handle)
exit_error(VERSION_PROBLEM,
"can't initialize iptables table `%s': %s",
- *table, iptc_strerror(errno));
+ *table, iptc_strerror());
if (command == CMD_APPEND
|| command == CMD_DELETE
diff -X /home/gandalf/dontdiff.ny -x '*.d' -x '*.man' -x '*.8' -urNp iptables-1.3.8-20070810.orig/libiptc/libip4tc.c iptables-1.3.8-20070810/libiptc/libip4tc.c
--- iptables-1.3.8-20070810.orig/libiptc/libip4tc.c 2006-07-05 11:31:45.000000000 +0200
+++ iptables-1.3.8-20070810/libiptc/libip4tc.c 2007-08-12 00:11:55.000000000 +0200
@@ -93,6 +93,7 @@ typedef unsigned int socklen_t;
#define TC_INIT iptc_init
#define TC_FREE iptc_free
#define TC_COMMIT iptc_commit
+#define TC_ERROR iptc_error
#define TC_STRERROR iptc_strerror
#define TC_NUM_RULES iptc_num_rules
#define TC_GET_RULE iptc_get_rule
@@ -115,6 +116,8 @@ typedef unsigned int socklen_t;
#define ALIGN IPT_ALIGN
#define RETURN IPT_RETURN
+#define TC_ERR(x) TC_ERROR(__FUNCTION__, (x))
+
#include "libiptc.c"
#define IP_PARTS_NATIVE(n) \
diff -X /home/gandalf/dontdiff.ny -x '*.d' -x '*.man' -x '*.8' -urNp iptables-1.3.8-20070810.orig/libiptc/libip6tc.c iptables-1.3.8-20070810/libiptc/libip6tc.c
--- iptables-1.3.8-20070810.orig/libiptc/libip6tc.c 2006-07-05 11:31:45.000000000 +0200
+++ iptables-1.3.8-20070810/libiptc/libip6tc.c 2007-08-12 00:12:33.000000000 +0200
@@ -88,6 +88,7 @@ typedef unsigned int socklen_t;
#define TC_INIT ip6tc_init
#define TC_FREE ip6tc_free
#define TC_COMMIT ip6tc_commit
+#define TC_ERROR ip6tc_error
#define TC_STRERROR ip6tc_strerror
#define TC_NUM_RULES ip6tc_num_rules
#define TC_GET_RULE ip6tc_get_rule
@@ -110,6 +111,8 @@ typedef unsigned int socklen_t;
#define ALIGN IP6T_ALIGN
#define RETURN IP6T_RETURN
+#define TC_ERR(x) TC_ERROR(__FUNCTION__, (x))
+
#include "libiptc.c"
#define BIT6(a, l) \
diff -X /home/gandalf/dontdiff.ny -x '*.d' -x '*.man' -x '*.8' -urNp iptables-1.3.8-20070810.orig/libiptc/libiptc.c iptables-1.3.8-20070810/libiptc/libiptc.c
--- iptables-1.3.8-20070810.orig/libiptc/libiptc.c 2007-06-30 12:47:57.000000000 +0200
+++ iptables-1.3.8-20070810/libiptc/libiptc.c 2007-08-12 00:13:40.000000000 +0200
@@ -46,7 +46,13 @@
static int sockfd = -1;
static int sockfd_use = 0;
-static void *iptc_fn = NULL;
+
+/* Silly games to get cpp to perform recursive macro expansion when quoting */
+#define QUOTE(x) #x
+#define QF(x) QUOTE(x)
+
+static int iptc_errno = 0;
+static char iptc_errfn[64];
static const char *hooknames[]
= { [HOOK_PRE_ROUTING] "PREROUTING",
@@ -456,7 +462,7 @@ static int cache_add_entry(STRUCT_ENTRY
DEBUGP_C("%u:%u:new userdefined chain %s: %p\n", *num, offset,
(char *)c->name, c);
if (!c) {
- errno = -ENOMEM;
+ TC_ERR(ENOMEM);
return -1;
}
@@ -469,7 +475,7 @@ static int cache_add_entry(STRUCT_ENTRY
DEBUGP_C("%u:%u new builtin chain: %p (rules=%p)\n",
*num, offset, c, &c->rules);
if (!c) {
- errno = -ENOMEM;
+ TC_ERR(ENOMEM);
return -1;
}
@@ -486,9 +492,10 @@ new_rule:
if (!(r = iptcc_alloc_rule(h->chain_iterator_cur,
e->next_offset))) {
- errno = ENOMEM;
+ TC_ERR(ENOMEM);
return -1;
}
+
DEBUGP_C("%u:%u normal rule: %p: ", *num, offset, r);
r->index = *num;
@@ -504,7 +511,7 @@ new_rule:
t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
if (t->target.u.target_size
!= ALIGN(sizeof(STRUCT_STANDARD_TARGET))) {
- errno = EINVAL;
+ TC_ERR(EINVAL);
return -1;
}
@@ -770,7 +777,7 @@ alloc_handle(const char *tablename, unsi
h = malloc(sizeof(STRUCT_TC_HANDLE));
if (!h) {
- errno = ENOMEM;
+ TC_ERR(ENOMEM);
return NULL;
}
memset(h, 0, sizeof(*h));
@@ -778,8 +785,10 @@ alloc_handle(const char *tablename, unsi
strcpy(h->info.name, tablename);
h->entries = malloc(sizeof(STRUCT_GET_ENTRIES) + size);
- if (!h->entries)
+ if (!h->entries) {
+ TC_ERR(ENOMEM);
goto out_free_handle;
+ }
strcpy(h->entries->name, tablename);
h->entries->size = size;
@@ -801,17 +810,21 @@ TC_INIT(const char *tablename)
unsigned int tmp;
socklen_t s;
- iptc_fn = TC_INIT;
+ /* ugly hack to avoid warnings if called multiple times */
+ memset(iptc_errfn, 0, 64);
+ iptc_errno = 0;
if (strlen(tablename) >= TABLE_MAXNAMELEN) {
- errno = EINVAL;
+ TC_ERR(E2BIG);
return NULL;
}
if (sockfd_use == 0) {
sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);
- if (sockfd < 0)
+ if (sockfd < 0) {
+ TC_ERR(errno);
return NULL;
+ }
}
sockfd_use++;
@@ -823,6 +836,7 @@ TC_INIT(const char *tablename)
close(sockfd);
sockfd = -1;
}
+ TC_ERR(errno);
return NULL;
}
@@ -835,6 +849,7 @@ TC_INIT(const char *tablename)
close(sockfd);
sockfd = -1;
}
+ TC_ERR(ENOMEM);
return NULL;
}
@@ -846,8 +861,10 @@ TC_INIT(const char *tablename)
tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size;
if (getsockopt(sockfd, TC_IPPROTO, SO_GET_ENTRIES, h->entries,
- &tmp) < 0)
+ &tmp) < 0) {
+ TC_ERR(errno);
goto error;
+ }
#ifdef IPTC_DEBUG2
{
@@ -879,7 +896,6 @@ TC_FREE(TC_HANDLE_T *h)
{
struct chain_head *c, *tmp;
- iptc_fn = TC_FREE;
if (--sockfd_use == 0) {
close(sockfd);
sockfd = -1;
@@ -913,7 +929,6 @@ static int dump_entry(STRUCT_ENTRY *e, c
void
TC_DUMP_ENTRIES(const TC_HANDLE_T handle)
{
- iptc_fn = TC_DUMP_ENTRIES;
CHECK(handle);
#if 0
printf("libiptc v%s. %u bytes.\n",
@@ -940,7 +955,6 @@ TC_DUMP_ENTRIES(const TC_HANDLE_T handle
/* Does this chain exist? */
int TC_IS_CHAIN(const char *chain, const TC_HANDLE_T handle)
{
- iptc_fn = TC_IS_CHAIN;
return iptcc_find_label(chain, handle) != NULL;
}
@@ -962,11 +976,9 @@ TC_FIRST_CHAIN(TC_HANDLE_T *handle)
struct chain_head *c = list_entry((*handle)->chains.next,
struct chain_head, list);
- iptc_fn = TC_FIRST_CHAIN;
-
-
if (list_empty(&(*handle)->chains)) {
DEBUGP(": no chains\n");
+ TC_ERR(ENOENT);
return NULL;
}
@@ -983,8 +995,6 @@ TC_NEXT_CHAIN(TC_HANDLE_T *handle)
{
struct chain_head *c = (*handle)->chain_iterator_cur;
- iptc_fn = TC_NEXT_CHAIN;
-
if (!c) {
DEBUGP(": no more chains\n");
return NULL;
@@ -1003,13 +1013,11 @@ TC_FIRST_RULE(const char *chain, TC_HAND
struct chain_head *c;
struct rule_head *r;
- iptc_fn = TC_FIRST_RULE;
-
DEBUGP("first rule(%s): ", chain);
c = iptcc_find_label(chain, *handle);
if (!c) {
- errno = ENOENT;
+ TC_ERR(ENOENT);
return NULL;
}
@@ -1032,7 +1040,6 @@ TC_NEXT_RULE(const STRUCT_ENTRY *prev, T
{
struct rule_head *r;
- iptc_fn = TC_NEXT_RULE;
DEBUGP("rule_iterator_cur=%p...", (*handle)->rule_iterator_cur);
if (!(*handle)->rule_iterator_cur) {
@@ -1043,8 +1050,6 @@ TC_NEXT_RULE(const STRUCT_ENTRY *prev, T
r = list_entry((*handle)->rule_iterator_cur->list.next,
struct rule_head, list);
- iptc_fn = TC_NEXT_RULE;
-
DEBUGP_C("next=%p, head=%p...", &r->list,
&(*handle)->rule_iterator_cur->chain->rules);
@@ -1066,12 +1071,11 @@ unsigned int
TC_NUM_RULES(const char *chain, TC_HANDLE_T *handle)
{
struct chain_head *c;
- iptc_fn = TC_NUM_RULES;
CHECK(*handle);
c = iptcc_find_label(chain, *handle);
if (!c) {
- errno = ENOENT;
+ TC_ERR(ENOENT);
return (unsigned int)-1;
}
@@ -1085,13 +1089,11 @@ const STRUCT_ENTRY *TC_GET_RULE(const ch
struct chain_head *c;
struct rule_head *r;
- iptc_fn = TC_GET_RULE;
-
CHECK(*handle);
c = iptcc_find_label(chain, *handle);
if (!c) {
- errno = ENOENT;
+ TC_ERR(ENOENT);
return NULL;
}
@@ -1134,8 +1136,6 @@ const char *TC_GET_TARGET(const STRUCT_E
STRUCT_ENTRY *e = (STRUCT_ENTRY *)ce;
struct rule_head *r = container_of(e, struct rule_head, entry[0]);
- iptc_fn = TC_GET_TARGET;
-
switch(r->type) {
int spos;
case IPTCC_R_FALLTHROUGH:
@@ -1162,13 +1162,9 @@ TC_BUILTIN(const char *chain, const TC_H
{
struct chain_head *c;
- iptc_fn = TC_BUILTIN;
-
c = iptcc_find_label(chain, handle);
- if (!c) {
- errno = ENOENT;
+ if (!c)
return 0;
- }
return iptcc_is_builtin(c);
}
@@ -1181,13 +1177,11 @@ TC_GET_POLICY(const char *chain,
{
struct chain_head *c;
- iptc_fn = TC_GET_POLICY;
-
DEBUGP("called for chain %s\n", chain);
c = iptcc_find_label(chain, *handle);
if (!c) {
- errno = ENOENT;
+ TC_ERR(ENOENT);
return NULL;
}
@@ -1209,7 +1203,7 @@ iptcc_standard_map(struct rule_head *r,
if (t->target.u.target_size
!= ALIGN(sizeof(STRUCT_STANDARD_TARGET))) {
- errno = EINVAL;
+ TC_ERR(EINVAL);
return 0;
}
/* memset for memcmp convenience on delete/replace */
@@ -1245,7 +1239,7 @@ iptcc_map_target(const TC_HANDLE_T handl
return iptcc_standard_map(r, RETURN);
else if (TC_BUILTIN(t->u.user.name, handle)) {
/* Can't jump to builtins. */
- errno = EINVAL;
+ TC_ERR(EINVAL);
return 0;
} else {
/* Maybe it's an existing chain name. */
@@ -1284,17 +1278,15 @@ TC_INSERT_ENTRY(const IPT_CHAINLABEL cha
struct rule_head *r;
struct list_head *prev;
- iptc_fn = TC_INSERT_ENTRY;
-
if (!(c = iptcc_find_label(chain, *handle))) {
- errno = ENOENT;
+ TC_ERR(ENOENT);
return 0;
}
/* first rulenum index = 0
first c->num_rules index = 1 */
if (rulenum > c->num_rules) {
- errno = E2BIG;
+ TC_ERR(E2BIG);
return 0;
}
@@ -1312,7 +1304,7 @@ TC_INSERT_ENTRY(const IPT_CHAINLABEL cha
}
if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
- errno = ENOMEM;
+ TC_ERR(ENOMEM);
return 0;
}
@@ -1342,15 +1334,13 @@ TC_REPLACE_ENTRY(const IPT_CHAINLABEL ch
struct chain_head *c;
struct rule_head *r, *old;
- iptc_fn = TC_REPLACE_ENTRY;
-
if (!(c = iptcc_find_label(chain, *handle))) {
- errno = ENOENT;
+ TC_ERR(ENOENT);
return 0;
}
if (rulenum >= c->num_rules) {
- errno = E2BIG;
+ TC_ERR(E2BIG);
return 0;
}
@@ -1362,7 +1352,7 @@ TC_REPLACE_ENTRY(const IPT_CHAINLABEL ch
}
if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
- errno = ENOMEM;
+ TC_ERR(ENOMEM);
return 0;
}
@@ -1392,16 +1382,15 @@ TC_APPEND_ENTRY(const IPT_CHAINLABEL cha
struct chain_head *c;
struct rule_head *r;
- iptc_fn = TC_APPEND_ENTRY;
if (!(c = iptcc_find_label(chain, *handle))) {
DEBUGP("unable to find chain `%s'\n", chain);
- errno = ENOENT;
+ TC_ERR(ENOENT);
return 0;
}
if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
DEBUGP("unable to allocate rule for chain `%s'\n", chain);
- errno = ENOMEM;
+ TC_ERR(ENOMEM);
return 0;
}
@@ -1500,16 +1489,15 @@ TC_DELETE_ENTRY(const IPT_CHAINLABEL cha
struct chain_head *c;
struct rule_head *r, *i;
- iptc_fn = TC_DELETE_ENTRY;
if (!(c = iptcc_find_label(chain, *handle))) {
- errno = ENOENT;
+ TC_ERR(ENOENT);
return 0;
}
/* Create a rule_head from origfw. */
r = iptcc_alloc_rule(c, origfw->next_offset);
if (!r) {
- errno = ENOMEM;
+ TC_ERR(ENOMEM);
return 0;
}
@@ -1557,7 +1545,7 @@ TC_DELETE_ENTRY(const IPT_CHAINLABEL cha
}
free(r);
- errno = ENOENT;
+ TC_ERR(EINVAL);
return 0;
}
@@ -1571,15 +1559,13 @@ TC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL
struct chain_head *c;
struct rule_head *r;
- iptc_fn = TC_DELETE_NUM_ENTRY;
-
if (!(c = iptcc_find_label(chain, *handle))) {
- errno = ENOENT;
+ TC_ERR(ENOENT);
return 0;
}
if (rulenum >= c->num_rules) {
- errno = E2BIG;
+ TC_ERR(E2BIG);
return 0;
}
@@ -1614,8 +1600,7 @@ TC_CHECK_PACKET(const IPT_CHAINLABEL cha
STRUCT_ENTRY *entry,
TC_HANDLE_T *handle)
{
- iptc_fn = TC_CHECK_PACKET;
- errno = ENOSYS;
+ TC_ERR(ENOSYS);
return NULL;
}
@@ -1626,9 +1611,8 @@ TC_FLUSH_ENTRIES(const IPT_CHAINLABEL ch
struct chain_head *c;
struct rule_head *r, *tmp;
- iptc_fn = TC_FLUSH_ENTRIES;
if (!(c = iptcc_find_label(chain, *handle))) {
- errno = ENOENT;
+ TC_ERR(ENOENT);
return 0;
}
@@ -1650,9 +1634,8 @@ TC_ZERO_ENTRIES(const IPT_CHAINLABEL cha
struct chain_head *c;
struct rule_head *r;
- iptc_fn = TC_ZERO_ENTRIES;
if (!(c = iptcc_find_label(chain, *handle))) {
- errno = ENOENT;
+ TC_ERR(ENOENT);
return 0;
}
@@ -1677,16 +1660,15 @@ TC_READ_COUNTER(const IPT_CHAINLABEL cha
struct chain_head *c;
struct rule_head *r;
- iptc_fn = TC_READ_COUNTER;
CHECK(*handle);
if (!(c = iptcc_find_label(chain, *handle))) {
- errno = ENOENT;
+ TC_ERR(ENOENT);
return NULL;
}
if (!(r = iptcc_get_rule_num(c, rulenum))) {
- errno = E2BIG;
+ TC_ERR(E2BIG);
return NULL;
}
@@ -1701,16 +1683,15 @@ TC_ZERO_COUNTER(const IPT_CHAINLABEL cha
struct chain_head *c;
struct rule_head *r;
- iptc_fn = TC_ZERO_COUNTER;
CHECK(*handle);
if (!(c = iptcc_find_label(chain, *handle))) {
- errno = ENOENT;
+ TC_ERR(ENOENT);
return 0;
}
if (!(r = iptcc_get_rule_num(c, rulenum))) {
- errno = E2BIG;
+ TC_ERR(E2BIG);
return 0;
}
@@ -1732,16 +1713,15 @@ TC_SET_COUNTER(const IPT_CHAINLABEL chai
struct rule_head *r;
STRUCT_ENTRY *e;
- iptc_fn = TC_SET_COUNTER;
CHECK(*handle);
if (!(c = iptcc_find_label(chain, *handle))) {
- errno = ENOENT;
+ TC_ERR(ENOENT);
return 0;
}
if (!(r = iptcc_get_rule_num(c, rulenum))) {
- errno = E2BIG;
+ TC_ERR(E2BIG);
return 0;
}
@@ -1763,8 +1743,6 @@ TC_CREATE_CHAIN(const IPT_CHAINLABEL cha
{
static struct chain_head *c;
- iptc_fn = TC_CREATE_CHAIN;
-
/* find_label doesn't cover built-in targets: DROP, ACCEPT,
QUEUE, RETURN. */
if (iptcc_find_label(chain, *handle)
@@ -1773,20 +1751,20 @@ TC_CREATE_CHAIN(const IPT_CHAINLABEL cha
|| strcmp(chain, LABEL_QUEUE) == 0
|| strcmp(chain, LABEL_RETURN) == 0) {
DEBUGP("Chain `%s' already exists\n", chain);
- errno = EEXIST;
+ TC_ERR(EEXIST);
return 0;
}
if (strlen(chain)+1 > sizeof(IPT_CHAINLABEL)) {
DEBUGP("Chain name `%s' too long\n", chain);
- errno = EINVAL;
+ TC_ERR(E2BIG);
return 0;
}
c = iptcc_alloc_chain_head(chain, 0);
if (!c) {
DEBUGP("Cannot allocate memory for chain `%s'\n", chain);
- errno = ENOMEM;
+ TC_ERR(ENOMEM);
return 0;
}
@@ -1806,9 +1784,8 @@ TC_GET_REFERENCES(unsigned int *ref, con
{
struct chain_head *c;
- iptc_fn = TC_GET_REFERENCES;
if (!(c = iptcc_find_label(chain, *handle))) {
- errno = ENOENT;
+ TC_ERR(ENOENT);
return 0;
}
@@ -1824,34 +1801,33 @@ TC_DELETE_CHAIN(const IPT_CHAINLABEL cha
unsigned int references;
struct chain_head *c;
- iptc_fn = TC_DELETE_CHAIN;
-
if (!(c = iptcc_find_label(chain, *handle))) {
DEBUGP("cannot find chain `%s'\n", chain);
- errno = ENOENT;
+ TC_ERR(ENOENT);
return 0;
}
if (TC_BUILTIN(chain, *handle)) {
DEBUGP("cannot remove builtin chain `%s'\n", chain);
- errno = EINVAL;
+ TC_ERR(EINVAL);
return 0;
}
if (!TC_GET_REFERENCES(&references, chain, handle)) {
DEBUGP("cannot get references on chain `%s'\n", chain);
+ TC_ERR(ENOSYS);
return 0;
}
if (references > 0) {
DEBUGP("chain `%s' still has references\n", chain);
- errno = EMLINK;
+ TC_ERR(EMLINK);
return 0;
}
if (c->num_rules) {
DEBUGP("chain `%s' is not empty\n", chain);
- errno = ENOTEMPTY;
+ TC_ERR(ENOTEMPTY);
return 0;
}
@@ -1876,7 +1852,17 @@ int TC_RENAME_CHAIN(const IPT_CHAINLABEL
TC_HANDLE_T *handle)
{
struct chain_head *c;
- iptc_fn = TC_RENAME_CHAIN;
+
+ if (!(c = iptcc_find_label(oldname, *handle))
+ || TC_BUILTIN(oldname, *handle)) {
+ TC_ERR(ENOENT);
+ return 0;
+ }
+
+ if (strlen(newname)+1 > sizeof(IPT_CHAINLABEL)) {
+ TC_ERR(E2BIG);
+ return 0;
+ }
/* find_label doesn't cover built-in targets: DROP, ACCEPT,
QUEUE, RETURN. */
@@ -1885,18 +1871,7 @@ int TC_RENAME_CHAIN(const IPT_CHAINLABEL
|| strcmp(newname, LABEL_ACCEPT) == 0
|| strcmp(newname, LABEL_QUEUE) == 0
|| strcmp(newname, LABEL_RETURN) == 0) {
- errno = EEXIST;
- return 0;
- }
-
- if (!(c = iptcc_find_label(oldname, *handle))
- || TC_BUILTIN(oldname, *handle)) {
- errno = ENOENT;
- return 0;
- }
-
- if (strlen(newname)+1 > sizeof(IPT_CHAINLABEL)) {
- errno = EINVAL;
+ TC_ERR(EEXIST);
return 0;
}
@@ -1916,17 +1891,15 @@ TC_SET_POLICY(const IPT_CHAINLABEL chain
{
struct chain_head *c;
- iptc_fn = TC_SET_POLICY;
-
if (!(c = iptcc_find_label(chain, *handle))) {
DEBUGP("cannot find chain `%s'\n", chain);
- errno = ENOENT;
+ TC_ERR(ENOENT);
return 0;
}
if (!iptcc_is_builtin(c)) {
DEBUGP("cannot set policy of userdefinedchain `%s'\n", chain);
- errno = ENOENT;
+ TC_ERR(ENOENT);
return 0;
}
@@ -1935,7 +1908,7 @@ TC_SET_POLICY(const IPT_CHAINLABEL chain
else if (strcmp(policy, LABEL_DROP) == 0)
c->verdict = -NF_DROP - 1;
else {
- errno = EINVAL;
+ TC_ERR(EINVAL);
return 0;
}
@@ -2035,7 +2008,6 @@ TC_COMMIT(TC_HANDLE_T *handle)
int new_number;
unsigned int new_size;
- iptc_fn = TC_COMMIT;
CHECK(*handle);
/* Don't commit if nothing changed. */
@@ -2044,13 +2016,13 @@ TC_COMMIT(TC_HANDLE_T *handle)
new_number = iptcc_compile_table_prep(*handle, &new_size);
if (new_number < 0) {
- errno = ENOMEM;
+ TC_ERR(ENOMEM);
goto out_zero;
}
repl = malloc(sizeof(*repl) + new_size);
if (!repl) {
- errno = ENOMEM;
+ TC_ERR(ENOMEM);
goto out_zero;
}
memset(repl, 0, sizeof(*repl) + new_size);
@@ -2066,13 +2038,13 @@ TC_COMMIT(TC_HANDLE_T *handle)
repl->counters = malloc(sizeof(STRUCT_COUNTERS)
* (*handle)->info.num_entries);
if (!repl->counters) {
- errno = ENOMEM;
+ TC_ERR(ENOMEM);
goto out_free_repl;
}
/* These are the counters we're going to put back, later. */
newcounters = malloc(counterlen);
if (!newcounters) {
- errno = ENOMEM;
+ TC_ERR(ENOMEM);
goto out_free_repl_counters;
}
memset(newcounters, 0, counterlen);
@@ -2089,7 +2061,7 @@ TC_COMMIT(TC_HANDLE_T *handle)
ret = iptcc_compile_table(*handle, repl);
if (ret < 0) {
- errno = ret;
+ TC_ERR(EINVAL);
goto out_free_newcounters;
}
@@ -2107,8 +2079,10 @@ TC_COMMIT(TC_HANDLE_T *handle)
ret = setsockopt(sockfd, TC_IPPROTO, SO_SET_REPLACE, repl,
sizeof(*repl) + repl->size);
- if (ret < 0)
+ if (ret < 0) {
+ TC_ERR(errno);
goto out_free_newcounters;
+ }
/* Put counters back. */
strcpy(newcounters->name, (*handle)->info.name);
@@ -2183,8 +2157,10 @@ TC_COMMIT(TC_HANDLE_T *handle)
ret = setsockopt(sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS,
newcounters, counterlen);
- if (ret < 0)
+ if (ret < 0) {
+ TC_ERR(errno);
goto out_free_newcounters;
+ }
free(repl->counters);
free(repl);
@@ -2211,57 +2187,98 @@ TC_GET_RAW_SOCKET()
return sockfd;
}
+void
+TC_ERROR(const char *function, int error)
+{
+ if (strlen(iptc_errfn))
+ printf("%s: %s\n", TC_LIBNAME, TC_STRERROR());
+ strncpy(iptc_errfn, function, 63);
+ iptc_errno = error;
+}
+
/* Translates errno numbers into more human-readable form than strerror. */
const char *
-TC_STRERROR(int err)
+TC_STRERROR()
{
- unsigned int i;
+ unsigned int i, length;
+ static char strbuf[256];
+
struct table_struct {
- void *fn;
+ const char *fn;
int err;
const char *message;
} table [] =
- { { TC_INIT, EPERM, "Permission denied (you must be root)" },
- { TC_INIT, EINVAL, "Module is wrong version" },
- { TC_INIT, ENOENT,
- "Table does not exist (do you need to insmod?)" },
- { TC_DELETE_CHAIN, ENOTEMPTY, "Chain is not empty" },
- { TC_DELETE_CHAIN, EINVAL, "Can't delete built-in chain" },
- { TC_DELETE_CHAIN, EMLINK,
- "Can't delete chain with references left" },
- { TC_CREATE_CHAIN, EEXIST, "Chain already exists" },
- { TC_INSERT_ENTRY, E2BIG, "Index of insertion too big" },
- { TC_REPLACE_ENTRY, E2BIG, "Index of replacement too big" },
- { TC_DELETE_NUM_ENTRY, E2BIG, "Index of deletion too big" },
- { TC_READ_COUNTER, E2BIG, "Index of counter too big" },
- { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" },
- { TC_INSERT_ENTRY, ELOOP, "Loop found in table" },
- { TC_INSERT_ENTRY, EINVAL, "Target problem" },
- /* EINVAL for CHECK probably means bad interface. */
- { TC_CHECK_PACKET, EINVAL,
- "Bad arguments (does that interface exist?)" },
- { TC_CHECK_PACKET, ENOSYS,
+ { { QF(TC_APPEND_ENTRY), ENOENT, "No chain by that name" },
+ { QF(TC_CHECK_PACKET), ENOSYS,
"Checking will most likely never get implemented" },
- /* ENOENT for DELETE probably means no matching rule */
- { TC_DELETE_ENTRY, ENOENT,
+ { QF(TC_COMMIT), EINVAL, "Table compilation failed" },
+ { QF(TC_COMMIT), ELOOP, "Loop found in table" },
+ { QF(TC_COMMIT), EPERM, "Permission denied (you must be root)" },
+ { QF(TC_CREATE_CHAIN), EEXIST, "Chain already exists" },
+ { QF(TC_CREATE_CHAIN), E2BIG, "Chain name too long" },
+ { QF(TC_DELETE_CHAIN), ENOTEMPTY, "Chain is not empty" },
+ { QF(TC_DELETE_CHAIN), EINVAL, "Can't delete built-in chain" },
+ { QF(TC_DELETE_CHAIN), EMLINK,
+ "Can't delete chain with references left" },
+ { QF(TC_DELETE_CHAIN), ENOENT, "No chain by that name" },
+ { QF(TC_DELETE_CHAIN), ENOSYS, "Couldn't get reference list for chain" },
+ { QF(TC_DELETE_ENTRY), ENOENT, "No chain by that name" },
+ { QF(TC_DELETE_ENTRY), EINVAL,
"Bad rule (does a matching rule exist in that chain?)" },
- { TC_SET_POLICY, ENOENT,
- "Bad built-in chain name" },
- { TC_SET_POLICY, EINVAL,
- "Bad policy name" },
+ { QF(TC_DELETE_NUM_ENTRY), ENOENT, "No chain by that name" },
+ { QF(TC_DELETE_NUM_ENTRY), E2BIG, "Index of deletion too big" },
+ { QF(TC_FIRST_CHAIN), ENOENT, "No chains to be found" },
+ { QF(TC_FIRST_RULE), ENOENT, "No chain by that name" },
+ { QF(TC_FLUSH_ENTRIES), ENOENT, "No chain by that name" },
+ { QF(TC_GET_POLICY), ENOENT, "No chain by that name" },
+ { QF(TC_GET_REFERENCES), ENOENT, "No chain by that name" },
+ { QF(TC_GET_RULE), ENOENT, "No chain by that name" },
+ { QF(TC_INIT), EPERM, "Permission denied (you must be root)" },
+ { QF(TC_INIT), EINVAL, "Module is wrong version" },
+ { QF(TC_INIT), E2BIG, "Table name too long" },
+ { QF(TC_INIT), ENOENT,
+ "Table does not exist (do you need to insmod?)" },
+ { QF(TC_INSERT_ENTRY), E2BIG, "Index of insertion too big" },
+ { QF(TC_INSERT_ENTRY), ENOENT, "No chain by that name" },
+ { QF(TC_NUM_RULES), ENOENT, "No chain by that name" },
+ { QF(TC_READ_COUNTER), E2BIG, "Index of counter read too big" },
+ { QF(TC_READ_COUNTER), ENOENT, "No chain by that name" },
+ { QF(TC_RENAME_CHAIN), E2BIG, "Chain name too long" },
+ { QF(TC_RENAME_CHAIN), ENOENT, "No chain by that name" },
+ { QF(TC_RENAME_CHAIN), EEXIST, "Chain already exists" },
+ { QF(TC_REPLACE_ENTRY), E2BIG, "Index of replacement too big" },
+ { QF(TC_REPLACE_ENTRY), ENOENT, "No chain by that name" },
+ { QF(TC_SET_COUNTER), E2BIG, "Index of counter too big" },
+ { QF(TC_SET_COUNTER), ENOENT, "No chain by that name" },
+ { QF(TC_SET_POLICY), ENOENT, "Bad built-in chain name" },
+ { QF(TC_SET_POLICY), EINVAL, "Bad policy name" },
+ { QF(TC_ZERO_COUNTER), E2BIG, "Index of counter too big" },
+ { QF(TC_ZERO_COUNTER), ENOENT, "No chain by that name" },
+ { QF(TC_ZERO_ENTRIES), ENOENT, "No chain by that name" },
+
+ { QF(cache_add_entry), EINVAL, "Target problem" },
+ { QF(iptcc_map_target), EINVAL, "Can't jump to a built-in target" },
+ { QF(iptcc_standard_map), EINVAL, "Target problem" },
+ { QF(list_entries), ENOENT, "No chain by that name" },
- { NULL, 0, "Incompatible with this kernel" },
{ NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" },
- { NULL, ENOSYS, "Will be implemented real soon. I promise ;)" },
{ NULL, ENOMEM, "Memory allocation problem" },
- { NULL, ENOENT, "No chain/target/match by that name" },
};
+
+ if (!strlen(iptc_errfn))
+ return "Something forgot to set the error reason";
for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) {
- if ((!table[i].fn || table[i].fn == iptc_fn)
- && table[i].err == err)
+ if ((!table[i].fn || !strcmp(table[i].fn, iptc_errfn))
+ && table[i].err == iptc_errno)
return table[i].message;
}
- return strerror(err);
+ length = snprintf(strbuf, 256, "Unknown error, %s: %i", iptc_errfn, iptc_errno);
+
+ /* Avoid printing "(Success)" */
+ if (iptc_errno)
+ snprintf(strbuf + length, 256 - length, " (%s)", strerror(iptc_errno));
+
+ return strbuf;
}
next reply other threads:[~2007-08-11 23:21 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-08-11 23:21 Martin Josefsson [this message]
2007-09-11 8:42 ` [PATCH RFT] Improve iptables error reporting Martin Josefsson
2007-09-19 12:56 ` Patrick McHardy
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Pine.LNX.4.62.0708120038080.28796@wlug.westbo.se \
--to=gandalf@wlug.westbo.se \
--cc=netfilter-devel@lists.netfilter.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).