• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/iptables/extensions/
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
26static 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
41static 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 */
49int 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
85static 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
90static 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
100static 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
105static 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
113static 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 */
139static 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 */
146inline 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 */
155inline 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 */
166static 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 */
179static 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 */
216static 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 */
222static 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 */
241static 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
257static 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 */
273void _init(void)
274{
275	register_match(&account);
276}
277
278