libipt_ACCOUNT: (tomj) fix long standing "Invalid handle for ipt_acc_handle_free...
[libipt_ACCOUNT] / src / ipt_ACCOUNT_cl.c
CommitLineData
a61040d6
TJ
1/***************************************************************************
2 * Copyright (C) 2004 by Intra2net AG *
3 * opensource@intra2net.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU Lesser General Public License *
7 * version 2.1 as published by the Free Software Foundation; *
8 * *
9 ***************************************************************************/
10
322f2b5b
TJ
11#include <sys/types.h>
12#include <sys/socket.h>
322f2b5b 13
49ba8949
TJ
14#include <netinet/in.h>
15#include <linux/if.h>
16#include <linux/netfilter_ipv4/ip_tables.h>
322f2b5b
TJ
17#include <ipt_ACCOUNT_cl.h>
18
19int ipt_ACCOUNT_init(struct ipt_ACCOUNT_context *ctx)
20{
21 memset (ctx, 0, sizeof(struct ipt_ACCOUNT_context));
a92b7b94 22 ctx->handle.handle_nr = -1;
322f2b5b
TJ
23
24 ctx->sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
e3ccc02f 25 if (ctx->sockfd < 0) {
322f2b5b 26 ctx->sockfd = -1;
e3ccc02f
TJ
27 ctx->error_str = "Can't open socket to kernel. "
28 "Permission denied or ipt_ACCOUNT module not loaded";
322f2b5b
TJ
29 return -1;
30 }
31
32 // 4096 bytes default buffer should save us from reallocations
33 // as it fits 200 concurrent active clients
e3ccc02f 34 if((ctx->data = (void *)malloc(IPT_ACCOUNT_MIN_BUFSIZE)) == NULL) {
322f2b5b
TJ
35 close (ctx->sockfd);
36 ctx->sockfd = -1;
37 ctx->error_str = "Out of memory for data buffer";
38 return -1;
39 }
40 ctx->data_size = IPT_ACCOUNT_MIN_BUFSIZE;
41
42 return 0;
43}
44
45void ipt_ACCOUNT_free_entries(struct ipt_ACCOUNT_context *ctx)
46{
e3ccc02f
TJ
47 if (ctx->handle.handle_nr != -1) {
48 setsockopt(ctx->sockfd, IPPROTO_IP, IPT_SO_SET_ACCOUNT_HANDLE_FREE,
49 &ctx->handle, sizeof (struct ipt_acc_handle_sockopt));
322f2b5b
TJ
50 ctx->handle.handle_nr = -1;
51 }
52
53 ctx->handle.itemcount = 0;
54 ctx->pos = 0;
55}
56
57void ipt_ACCOUNT_deinit(struct ipt_ACCOUNT_context *ctx)
58{
59 free(ctx->data);
60 ctx->data = NULL;
61
62 ipt_ACCOUNT_free_entries(ctx);
63
64 close(ctx->sockfd);
65 ctx->sockfd =-1;
66}
67
e3ccc02f
TJ
68int ipt_ACCOUNT_read_entries(struct ipt_ACCOUNT_context *ctx,
69 const char *table, char dont_flush)
322f2b5b 70{
8721821e 71 unsigned int s = sizeof (struct ipt_acc_handle_sockopt);
322f2b5b
TJ
72 int rtn;
73
74 strncpy(ctx->handle.name, table, ACCOUNT_TABLE_NAME_LEN-1);
75
76 // Get table information
77 if (!dont_flush)
e3ccc02f
TJ
78 rtn = getsockopt(ctx->sockfd, IPPROTO_IP,
79 IPT_SO_GET_ACCOUNT_PREPARE_READ_FLUSH, &ctx->handle, &s);
322f2b5b 80 else
e3ccc02f
TJ
81 rtn = getsockopt(ctx->sockfd, IPPROTO_IP, IPT_SO_GET_ACCOUNT_PREPARE_READ,
82 &ctx->handle, &s);
322f2b5b 83
e3ccc02f
TJ
84 if (rtn < 0) {
85 ctx->error_str = "Can't get table information from kernel. "
86 "Is the table existing?";
322f2b5b
TJ
87 return -1;
88 }
89
90 // Check data buffer size
91 ctx->pos = 0;
e3ccc02f
TJ
92 unsigned int new_size;
93 new_size = ctx->handle.itemcount * sizeof(struct ipt_acc_handle_ip);
322f2b5b
TJ
94 // We want to prevent reallocations all the time
95 if (new_size < IPT_ACCOUNT_MIN_BUFSIZE)
96 new_size = IPT_ACCOUNT_MIN_BUFSIZE;
97
98 // Reallocate if it's too small or twice as big
e3ccc02f 99 if (ctx->data_size < new_size || ctx->data_size > new_size*2) {
322f2b5b
TJ
100 // Free old buffer
101 free (ctx->data);
102 ctx->data_size = 0;
103
e3ccc02f 104 if ((ctx->data = (void*)malloc(new_size)) == NULL) {
322f2b5b
TJ
105 ctx->error_str = "Out of memory for data buffer";
106 ipt_ACCOUNT_free_entries(ctx);
107 return -1;
108 }
109
110 ctx->data_size = new_size;
111 }
112
113 // Copy data from kernel
8721821e 114 memcpy(ctx->data, &ctx->handle, sizeof(struct ipt_acc_handle_sockopt));
e3ccc02f
TJ
115 rtn = getsockopt(ctx->sockfd, IPPROTO_IP, IPT_SO_GET_ACCOUNT_GET_DATA,
116 ctx->data, &ctx->data_size);
117 if (rtn < 0) {
118 ctx->error_str = "Can't get data from kernel. "
119 "Check /var/log/messages for details.";
322f2b5b
TJ
120 ipt_ACCOUNT_free_entries(ctx);
121 return -1;
122 }
123
124 // Free kernel handle but don't reset pos/itemcount
e3ccc02f
TJ
125 setsockopt(ctx->sockfd, IPPROTO_IP, IPT_SO_SET_ACCOUNT_HANDLE_FREE,
126 &ctx->handle, sizeof (struct ipt_acc_handle_sockopt));
322f2b5b
TJ
127 ctx->handle.handle_nr = -1;
128
129 return 0;
130}
131
8721821e 132struct ipt_acc_handle_ip *ipt_ACCOUNT_get_next_entry(struct ipt_ACCOUNT_context *ctx)
322f2b5b 133{
8721821e 134 struct ipt_acc_handle_ip *rtn;
322f2b5b
TJ
135
136 // Empty or no more items left to return?
137 if (!ctx->handle.itemcount || ctx->pos >= ctx->handle.itemcount)
138 return NULL;
139
140 // Get next entry
e3ccc02f
TJ
141 rtn = (struct ipt_acc_handle_ip *)(ctx->data + ctx->pos
142 * sizeof(struct ipt_acc_handle_ip));
322f2b5b
TJ
143 ctx->pos++;
144
145 return rtn;
146}
d7e0bb9c
TJ
147
148int ipt_ACCOUNT_get_handle_usage(struct ipt_ACCOUNT_context *ctx)
149{
8721821e 150 unsigned int s = sizeof (struct ipt_acc_handle_sockopt);
e3ccc02f
TJ
151 if (getsockopt(ctx->sockfd, IPPROTO_IP,
152 IPT_SO_GET_ACCOUNT_GET_HANDLE_USAGE, &ctx->handle, &s) < 0) {
d7e0bb9c
TJ
153 ctx->error_str = "Can't get handle usage information from kernel";
154 return -1;
155 }
a92b7b94 156 ctx->handle.handle_nr = -1;
d7e0bb9c
TJ
157
158 return ctx->handle.itemcount;
159 }
160
161int ipt_ACCOUNT_free_all_handles(struct ipt_ACCOUNT_context *ctx)
162{
e3ccc02f
TJ
163 if (setsockopt(ctx->sockfd, IPPROTO_IP,
164 IPT_SO_SET_ACCOUNT_HANDLE_FREE_ALL, NULL, 0) < 0) {
d7e0bb9c
TJ
165 ctx->error_str = "Can't free all kernel handles";
166 return -1;
167 }
168
169 return 0;
170}
171
172int ipt_ACCOUNT_get_table_names(struct ipt_ACCOUNT_context *ctx)
173{
e3ccc02f
TJ
174 int rtn = getsockopt(ctx->sockfd, IPPROTO_IP,
175 IPT_SO_GET_ACCOUNT_GET_TABLE_NAMES,
176 ctx->data, &ctx->data_size);
177 if (rtn < 0) {
178 ctx->error_str = "Can't get table names from kernel. Out of memory, "
179 "MINBUFISZE too small?";
d7e0bb9c
TJ
180 return -1;
181 }
182 ctx->pos = 0;
183 return 0;
184}
185
42b9e9f8 186const char *ipt_ACCOUNT_get_next_name(struct ipt_ACCOUNT_context *ctx)
d7e0bb9c 187{
8721821e
TJ
188 if (((char *)ctx->data)[ctx->pos] == 0)
189 return 0;
d7e0bb9c 190
8721821e 191 const char *rtn = ctx->data + ctx->pos;
d7e0bb9c
TJ
192 ctx->pos += strlen(ctx->data+ctx->pos) + 1;
193
194 return rtn;
195}