1/* Shared library add-on to iptables to add connection rate tracking
2 * support.
3 *
4 * Copyright (c) 2004 Nuutti Kotivuori <naked@iki.fi>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 **/
10#include <stdio.h>
11#include <netdb.h>
12#include <string.h>
13#include <stdlib.h>
14#include <getopt.h>
15#include <iptables.h>
16#include <linux/netfilter/nf_conntrack_common.h>
17#include <linux/netfilter_ipv4/ipt_connrate.h>
18
19/* Function which prints out usage message. */
20static void
21help(void)
22{
23	printf(
24"connrate v%s options:\n"
25" --connrate [!] [from]:[to]\n"
26"				Match connection transfer rate in bytes\n"
27"				per second. `inf' can be used for maximum\n"
28"				expressible value.\n"
29"\n", IPTABLES_VERSION);
30}
31
32static struct option opts[] = {
33	{ "connrate", 1, 0, '1' },
34	{0}
35};
36
37static u_int32_t
38parse_value(const char *arg, u_int32_t def)
39{
40	char *end;
41	size_t len;
42	u_int32_t value;
43
44	len = strlen(arg);
45	if(len == 0)
46		return def;
47	if(strcmp(arg, "inf") == 0)
48		return 0xFFFFFFFF;
49	value = strtoul(arg, &end, 0);
50	if(*end != '\0')
51		exit_error(PARAMETER_PROBLEM,
52			   "Bad value in range `%s'", arg);
53	return value;
54}
55
56static void
57parse_range(const char *arg, struct ipt_connrate_info *si)
58{
59	char *buffer;
60	char *colon;
61
62	buffer = strdup(arg);
63	if ((colon = strchr(buffer, ':')) == NULL)
64		exit_error(PARAMETER_PROBLEM, "Bad range `%s'", arg);
65	*colon = '\0';
66	si->from = parse_value(buffer, 0);
67	si->to = parse_value(colon+1, 0xFFFFFFFF);
68	if (si->from > si->to)
69		exit_error(PARAMETER_PROBLEM, "%u should be less than %u", si->from,si->to);
70	free(buffer);
71}
72
73#define CONNRATE_OPT 0x01
74
75/* Function which parses command options; returns true if it
76   ate an option */
77static int
78parse(int c, char **argv, int invert, unsigned int *flags,
79      const struct ipt_entry *entry,
80      unsigned int *nfcache,
81      struct ipt_entry_match **match)
82{
83	struct ipt_connrate_info *sinfo = (struct ipt_connrate_info *)(*match)->data;
84	u_int32_t tmp;
85
86	switch (c) {
87	case '1':
88		if (*flags & CONNRATE_OPT)
89			exit_error(PARAMETER_PROBLEM,
90				   "Only one `--connrate' allowed");
91		check_inverse(optarg, &invert, &optind, 0);
92		parse_range(argv[optind-1], sinfo);
93		if (invert) {
94			tmp = sinfo->from;
95			sinfo->from = sinfo->to;
96			sinfo->to = tmp;
97		}
98		*flags |= CONNRATE_OPT;
99		break;
100
101	default:
102		return 0;
103	}
104
105	return 1;
106}
107
108static void final_check(unsigned int flags)
109{
110	if (!(flags & CONNRATE_OPT))
111		exit_error(PARAMETER_PROBLEM,
112			   "connrate match: You must specify `--connrate'");
113}
114
115static void
116print_value(u_int32_t value)
117{
118	if(value == 0xFFFFFFFF)
119		printf("inf");
120	else
121		printf("%u", value);
122}
123
124static void
125print_range(struct ipt_connrate_info *sinfo)
126{
127	if (sinfo->from > sinfo->to) {
128		printf("! ");
129		print_value(sinfo->to);
130		printf(":");
131		print_value(sinfo->from);
132	} else {
133		print_value(sinfo->from);
134		printf(":");
135		print_value(sinfo->to);
136	}
137}
138
139/* Prints out the matchinfo. */
140static void
141print(const struct ipt_ip *ip,
142      const struct ipt_entry_match *match,
143      int numeric)
144{
145	struct ipt_connrate_info *sinfo = (struct ipt_connrate_info *)match->data;
146
147	printf("connrate ");
148	print_range(sinfo);
149	printf(" ");
150}
151
152/* Saves the matchinfo in parsable form to stdout. */
153static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
154{
155	struct ipt_connrate_info *sinfo = (struct ipt_connrate_info *)match->data;
156
157	printf("--connrate ");
158	print_range(sinfo);
159	printf(" ");
160}
161
162static struct iptables_match state = {
163	.next 		= NULL,
164	.name		= "connrate",
165	.version	= IPTABLES_VERSION,
166	.size		= IPT_ALIGN(sizeof(struct ipt_connrate_info)),
167	.userspacesize	= IPT_ALIGN(sizeof(struct ipt_connrate_info)),
168	.help 		= &help,
169	.parse		= &parse,
170	.final_check	= &final_check,
171	.print		= &print,
172	.save		= &save,
173	.extra_opts	= opts
174};
175
176void _init(void)
177{
178	register_match(&state);
179}
180