iptables-1.3.2-20050720
[iptables.git] / extensions / libipt_account.c
1 /* 
2  * accounting match helper (libipt_account.c)
3  * (C) 2003,2004 by Piotr Gasid³o (quaker@barbara.eu.org)
4  *
5  * Version: 0.1.6
6  *
7  * This software is distributed under the terms of GNU GPL
8  */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <iptables.h>
13 #include <string.h>
14 #include <getopt.h>
15
16 #include <linux/netfilter_ipv4/ipt_account.h>
17
18 #ifndef HIPQUAD
19 #define HIPQUAD(addr) \
20         ((unsigned char *)&addr)[3], \
21         ((unsigned char *)&addr)[2], \
22         ((unsigned char *)&addr)[1], \
23         ((unsigned char *)&addr)[0]
24 #endif
25                                 
26 static void help(void) {
27         printf(
28                         "account v%s options:\n"
29                         "--aaddr network/netmask\n"
30                         "       defines network/netmask for which make statistics.\n"
31                         "--aname name\n"
32                         "       defines name of list where statistics will be kept. If no is\n"
33                         "       specified DEFAULT will be used.\n"
34                         "--ashort\n"
35                         "       table will colect only short statistics (only total counters\n"
36                         "       without splitting it into protocols.\n"
37         , 
38         IPTABLES_VERSION);
39 };
40
41 static struct option opts[] = {
42         { .name = "aaddr",  .has_arg = 1, .flag = NULL, .val = 201 },
43         { .name = "aname",  .has_arg = 1, .flag = NULL, .val = 202 },
44         { .name = "ashort", .has_arg = 0, .flag = NULL, .val = 203 },
45         { .name = 0, .has_arg = 0, .flag = 0, .val = 0 }
46 };
47
48 /* Helper functions for parse_network */
49 int parseip(const char *parameter, u_int32_t *ip) {
50         
51         char buffer[16], *bufferptr, *dot;
52         unsigned int i, shift, part;
53
54         if (strlen(parameter) > 15)
55                 return 0;
56
57         strncpy(buffer, parameter, 15);
58         buffer[15] = 0;
59
60         bufferptr = buffer;
61
62         for (i = 0, shift = 24, *ip = 0; i < 3; i++, shift -= 8) {
63                 /* no dot */
64                 if ((dot = strchr(bufferptr, '.')) == NULL)
65                         return 0;
66                 /* not a number */
67                 if ((part = strtol(bufferptr, (char**)NULL, 10)) < 0) 
68                         return 0;       
69                 /* to big number */
70                 if (part > 255)
71                         return 0;
72                 *ip |= part << shift;           
73                 bufferptr = dot + 1;
74         }
75         /* not a number */
76         if ((part = strtol(bufferptr, (char**)NULL, 10)) < 0) 
77                 return 0;
78         /* to big number */
79         if (part > 255)
80                 return 0;
81         *ip |= part;
82         return 1;
83 }
84
85 static void parsenetwork(const char *parameter, u_int32_t *network) {
86         if (!parseip(parameter, network))
87                 exit_error(PARAMETER_PROBLEM, "account: wrong ip in network");
88 }
89
90 static void parsenetmaskasbits(const char *parameter, u_int32_t *netmask) {
91         
92         u_int32_t bits;
93         
94         if ((bits = strtol(parameter, (char **)NULL, 10)) < 0 || bits > 32)
95                 exit_error(PARAMETER_PROBLEM, "account: wrong netmask");
96
97         *netmask = 0xffffffff << (32 - bits);
98 }
99
100 static void parsenetmaskasip(const char *parameter, u_int32_t *netmask) {
101         if (!parseip(parameter, netmask))
102                 exit_error(PARAMETER_PROBLEM, "account: wrong ip in netmask");
103 }
104
105 static void parsenetmask(const char *parameter, u_int32_t *netmask) 
106 {
107         if (strchr(parameter, '.') != NULL)
108                 parsenetmaskasip(parameter, netmask);
109         else
110                 parsenetmaskasbits(parameter, netmask);
111 }
112
113 static void parsenetworkandnetmask(const char *parameter, u_int32_t *network, u_int32_t *netmask) 
114 {
115         
116         char buffer[32], *slash;
117
118         if (strlen(parameter) > 31)
119                 /* text is to long, even for 255.255.255.255/255.255.255.255 */
120                 exit_error(PARAMETER_PROBLEM, "account: wrong network/netmask");
121
122         strncpy(buffer, parameter, 31);
123         buffer[31] = 0;
124
125         /* check whether netmask is given */
126         if ((slash = strchr(buffer, '/')) != NULL) {
127                 parsenetmask(slash + 1, netmask);
128                 *slash = 0;
129         } else
130                 *netmask = 0xffffffff;
131         parsenetwork(buffer, network);
132
133         if ((*network & *netmask) != *network)
134                 exit_error(PARAMETER_PROBLEM, "account: wrong network/netmask");
135 }
136
137
138 /* Function gets network & netmask from argument after --aaddr */
139 static void parse_network(const char *parameter, struct t_ipt_account_info *info) {
140
141         parsenetworkandnetmask(parameter, &info->network, &info->netmask);
142         
143 }
144
145 /* validate netmask */
146 inline int valid_netmask(u_int32_t netmask) {
147         while (netmask & 0x80000000)
148                 netmask <<= 1;
149         if (netmask != 0)
150                 return 0;
151         return 1;
152 }
153
154 /* validate network/netmask pair */
155 inline int valid_network_and_netmask(struct t_ipt_account_info *info) {
156         if (!valid_netmask(info->netmask))
157                 return 0;
158         if ((info->network & info->netmask) != info->network)
159                 return 0;
160         return 1;
161 }
162
163
164
165 /* Function initializes match */
166 static void init(struct ipt_entry_match *match, 
167                  unsigned int *nfcache) {
168         
169         struct t_ipt_account_info *info = (struct t_ipt_account_info *)(match)->data;
170
171
172         /* set default table name to DEFAULT */
173         strncpy(info->name, "DEFAULT", IPT_ACCOUNT_NAME_LEN);
174         info->shortlisting = 0;
175         
176 }
177
178 /* Function parses match's arguments */
179 static int parse(int c, char **argv, 
180                   int invert, 
181                   unsigned int *flags,
182                   const struct ipt_entry *entry,
183                   unsigned int *nfcache,
184                   struct ipt_entry_match **match) {
185         
186         struct t_ipt_account_info *info = (struct t_ipt_account_info *)(*match)->data;
187
188         switch (c) {
189                 
190                 /* --aaddr */
191                 case 201:
192                         parse_network(optarg, info);
193                         if (!valid_network_and_netmask(info))
194                                 exit_error(PARAMETER_PROBLEM, "account: wrong network/netmask");
195                         *flags = 1;
196                         break;
197                         
198                 /* --aname */
199                 case 202:
200                         if (strlen(optarg) < IPT_ACCOUNT_NAME_LEN)
201                                 strncpy(info->name, optarg, IPT_ACCOUNT_NAME_LEN);
202                         else
203                                 exit_error(PARAMETER_PROBLEM, "account: Too long table name");                  
204                         break;  
205                 /* --ashort */
206                 case 203:
207                         info->shortlisting = 1;
208                         break;
209                 default:
210                         return 0;                       
211         }
212         return 1;       
213 }
214
215 /* Final check whether network/netmask was specified */
216 static void final_check(unsigned int flags) {
217         if (!flags)
218                 exit_error(PARAMETER_PROBLEM, "account: You need specify '--aaddr' parameter");
219 }
220
221 /* Function used for printing rule with account match for iptables -L */
222 static void print(const struct ipt_ip *ip,
223                   const struct ipt_entry_match *match, 
224                   int numeric) {
225         
226         struct t_ipt_account_info *info = (struct t_ipt_account_info *)match->data;
227         
228         printf("account: ");
229         printf("network/netmask: ");
230         printf("%u.%u.%u.%u/%u.%u.%u.%u ",
231                         HIPQUAD(info->network),
232                         HIPQUAD(info->netmask)
233               );
234         
235         printf("name: %s ", info->name);
236         if (info->shortlisting)
237                 printf("short-listing ");
238 }
239
240 /* Function used for saving rule containing account match */
241 static void save(const struct ipt_ip *ip, 
242                  const struct ipt_entry_match *match) {
243
244         struct t_ipt_account_info *info = (struct t_ipt_account_info *)match->data;
245         
246         printf("--aaddr ");
247         printf("%u.%u.%u.%u/%u.%u.%u.%u ",
248                          HIPQUAD(info->network),
249                          HIPQUAD(info->netmask)
250                );
251         
252         printf("--aname %s ", info->name);
253         if (info->shortlisting)
254                 printf("--ashort ");
255 }
256         
257 static struct iptables_match account = {
258         .next = NULL,
259         .name = "account",
260         .version = IPTABLES_VERSION,
261         .size = IPT_ALIGN(sizeof(struct t_ipt_account_info)),
262         .userspacesize = IPT_ALIGN(sizeof(struct t_ipt_account_info)),
263         .help = &help,
264         .init = &init,
265         .parse = &parse,
266         .final_check = &final_check,
267         .print = &print,
268         .save = &save,
269         .extra_opts = opts
270 };
271
272 /* Function which registers match */
273 void _init(void)
274 {
275         register_match(&account);
276 }
277