summaryrefslogtreecommitdiffstats
path: root/libiptc/libiptc.c
diff options
context:
space:
mode:
authorDerrik Pates <demon@devrandom.net>2005-02-01 13:28:14 +0000
committerHarald Welte <laforge@gnumonks.org>2005-02-01 13:28:14 +0000
commit664c0a30b7963040da2e7a7e86dc56a0f1a829b5 (patch)
tree58b1a92640aab2603b235908f6b65f25ee64b3de /libiptc/libiptc.c
parent3fb61f3d4a194ba989fe8470f16064f20e59e3bc (diff)
- Sets the 'iptc_fn' global variable to the pointer to the current functions in all major TC_* functions. This is necessary because in certain cases, an error return from a function that doesn't set 'iptc_fn' will conflict with a function-specific error return from one that does, causing TC_STRERROR() to return the wrong error string. This ensures that the right one will be returned.
- Implements a simple reference counter for the netlink socket global variable 'sockfd'; this is necessary for IPTables::IPv4, where multiple tables (filter, nat, mangle, untracked) may be opened at one time. The way libiptc does it in the official version causes previously-opened tables to break such that attempts to commit changes will fail. - Adds a couple of memset() invocations in TC_COMMIT, based on past analysis with valgrind. It claimed that allocated structure were not being fully initialized, and adding the memset()s corrected this warning. (Derrik Pates <demon@devrandom.net>)
Diffstat (limited to 'libiptc/libiptc.c')
-rw-r--r--libiptc/libiptc.c49
1 files changed, 36 insertions, 13 deletions
diff --git a/libiptc/libiptc.c b/libiptc/libiptc.c
index ad0b57c4..3557f57a 100644
--- a/libiptc/libiptc.c
+++ b/libiptc/libiptc.c
@@ -45,6 +45,7 @@
#endif
static int sockfd = -1;
+static int sockfd_use = 0;
static void *iptc_fn = NULL;
static const char *hooknames[]
@@ -788,33 +789,38 @@ TC_INIT(const char *tablename)
iptc_fn = TC_INIT;
- if (sockfd != -1) {
- close(sockfd);
- sockfd = -1;
- }
-
if (strlen(tablename) >= TABLE_MAXNAMELEN) {
errno = EINVAL;
return NULL;
}
- sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);
- if (sockfd < 0)
- return NULL;
+ if (sockfd_use == 0) {
+ sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);
+ if (sockfd < 0)
+ return NULL;
+ }
+ sockfd_use++;
s = sizeof(info);
strcpy(info.name, tablename);
- if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0)
+ if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0) {
+ if (--sockfd_use == 0) {
+ close(sockfd);
+ sockfd = -1;
+ }
return NULL;
+ }
DEBUGP("valid_hooks=0x%08x, num_entries=%u, size=%u\n",
info.valid_hooks, info.num_entries, info.size);
if ((h = alloc_handle(info.name, info.size, info.num_entries))
== NULL) {
- close(sockfd);
- sockfd = -1;
+ if (--sockfd_use == 0) {
+ close(sockfd);
+ sockfd = -1;
+ }
return NULL;
}
@@ -846,6 +852,10 @@ TC_INIT(const char *tablename)
CHECK(h);
return h;
error:
+ if (--sockfd_use == 0) {
+ close(sockfd);
+ sockfd = -1;
+ }
TC_FREE(&h);
return NULL;
}
@@ -855,8 +865,11 @@ TC_FREE(TC_HANDLE_T *h)
{
struct chain_head *c, *tmp;
- close(sockfd);
- sockfd = -1;
+ iptc_fn = TC_FREE;
+ if (--sockfd_use == 0) {
+ close(sockfd);
+ sockfd = -1;
+ }
list_for_each_entry_safe(c, tmp, &(*h)->chains, list) {
struct rule_head *r, *rtmp;
@@ -886,6 +899,7 @@ static int dump_entry(STRUCT_ENTRY *e, const TC_HANDLE_T handle);
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",
@@ -912,6 +926,7 @@ 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;
}
@@ -1003,6 +1018,7 @@ TC_NEXT_RULE(const STRUCT_ENTRY *prev, TC_HANDLE_T *handle)
{
struct rule_head *r;
+ iptc_fn = TC_NEXT_RULE;
DEBUGP("rule_iterator_cur=%p...", (*handle)->rule_iterator_cur);
if (!(*handle)->rule_iterator_cur) {
@@ -1576,6 +1592,7 @@ TC_CHECK_PACKET(const IPT_CHAINLABEL chain,
STRUCT_ENTRY *entry,
TC_HANDLE_T *handle)
{
+ iptc_fn = TC_CHECK_PACKET;
errno = ENOSYS;
return NULL;
}
@@ -1611,6 +1628,7 @@ TC_ZERO_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
struct chain_head *c;
struct rule_head *r;
+ iptc_fn = TC_ZERO_ENTRIES;
if (!(c = iptcc_find_label(chain, *handle))) {
errno = ENOENT;
return 0;
@@ -1763,6 +1781,7 @@ TC_GET_REFERENCES(unsigned int *ref, const IPT_CHAINLABEL chain,
{
struct chain_head *c;
+ iptc_fn = TC_GET_REFERENCES;
if (!(c = iptcc_find_label(chain, *handle))) {
errno = ENOENT;
return 0;
@@ -1991,6 +2010,7 @@ 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. */
@@ -2016,6 +2036,7 @@ TC_COMMIT(TC_HANDLE_T *handle)
counterlen = sizeof(STRUCT_COUNTERS_INFO)
+ sizeof(STRUCT_COUNTERS) * new_number;
+ memset(repl, 0, sizeof(*repl) + (*handle)->entries->size);
/* These are the old counters we will get from kernel */
repl->counters = malloc(sizeof(STRUCT_COUNTERS)
@@ -2025,6 +2046,8 @@ TC_COMMIT(TC_HANDLE_T *handle)
errno = ENOMEM;
return 0;
}
+ memset(repl->counters, 0, sizeof(STRUCT_COUNTERS)
+ * (*handle)->info.num_entries);
/* These are the counters we're going to put back, later. */
newcounters = malloc(counterlen);
if (!newcounters) {