Merge to iptables-1.3.5
[iptables.git] / extensions / libipt_connbytes.c
1 /* Shared library add-on to iptables to add byte tracking support. */
2 #include <stdio.h>
3 #include <netdb.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <getopt.h>
7 #include <iptables.h>
8 #include <linux/netfilter_ipv4/ip_conntrack.h>
9 #include <linux/netfilter_ipv4/ipt_connbytes.h>
10
11 /* Function which prints out usage message. */
12 static void
13 help(void)
14 {
15         printf(
16 "connbytes v%s options:\n"
17 " [!] --connbytes from:[to]\n"
18 "     --connbytes-dir [original, reply, both]\n"
19 "     --connbytes-mode [packets, bytes, avgpkt]\n"
20 "\n", IPTABLES_VERSION);
21 }
22
23 static struct option opts[] = {
24         { "connbytes", 1, 0, '1' },
25         { "connbytes-dir", 1, 0, '2' },
26         { "connbytes-mode", 1, 0, '3' },
27         {0}
28 };
29
30 static void
31 parse_range(const char *arg, struct ipt_connbytes_info *si)
32 {
33         char *colon,*p;
34
35         si->count.from = strtoul(arg,&colon,10);
36         if (*colon != ':') 
37                 exit_error(PARAMETER_PROBLEM, "Bad range `%s'", arg);
38         si->count.to = strtoul(colon+1,&p,10);
39         if (p == colon+1) {
40                 /* second number omited */
41                 si->count.to = 0xffffffff;
42         }
43         if (si->count.from > si->count.to)
44                 exit_error(PARAMETER_PROBLEM, "%llu should be less than %llu",
45                            si->count.from, si->count.to);
46 }
47
48 /* Function which parses command options; returns true if it
49    ate an option */
50 static int
51 parse(int c, char **argv, int invert, unsigned int *flags,
52       const struct ipt_entry *entry,
53       unsigned int *nfcache,
54       struct ipt_entry_match **match)
55 {
56         struct ipt_connbytes_info *sinfo = (struct ipt_connbytes_info *)(*match)->data;
57         unsigned long i;
58
59         switch (c) {
60         case '1':
61                 if (check_inverse(optarg, &invert, &optind, 0))
62                         optind++;
63
64                 parse_range(argv[optind-1], sinfo);
65                 if (invert) {
66                         i = sinfo->count.from;
67                         sinfo->count.from = sinfo->count.to;
68                         sinfo->count.to = i;
69                 }
70                 *flags |= 1;
71                 break;
72         case '2':
73                 if (!strcmp(optarg, "original"))
74                         sinfo->direction = IPT_CONNBYTES_DIR_ORIGINAL;
75                 else if (!strcmp(optarg, "reply"))
76                         sinfo->direction = IPT_CONNBYTES_DIR_REPLY;
77                 else if (!strcmp(optarg, "both"))
78                         sinfo->direction = IPT_CONNBYTES_DIR_BOTH;
79                 else
80                         exit_error(PARAMETER_PROBLEM,
81                                    "Unknown --connbytes-dir `%s'", optarg);
82
83                 *flags |= 2;
84                 break;
85         case '3':
86                 if (!strcmp(optarg, "packets"))
87                         sinfo->what = IPT_CONNBYTES_PKTS;
88                 else if (!strcmp(optarg, "bytes"))
89                         sinfo->what = IPT_CONNBYTES_BYTES;
90                 else if (!strcmp(optarg, "avgpkt"))
91                         sinfo->what = IPT_CONNBYTES_AVGPKT;
92                 else
93                         exit_error(PARAMETER_PROBLEM,
94                                    "Unknown --connbytes-mode `%s'", optarg);
95                 *flags |= 4;
96                 break;
97         default:
98                 return 0;
99         }
100
101         return 1;
102 }
103
104 static void final_check(unsigned int flags)
105 {
106         if (flags != 7)
107                 exit_error(PARAMETER_PROBLEM, "You must specify `--connbytes'"
108                            "`--connbytes-dir' and `--connbytes-mode'");
109 }
110
111 static void print_mode(struct ipt_connbytes_info *sinfo)
112 {
113         switch (sinfo->what) {
114                 case IPT_CONNBYTES_PKTS:
115                         fputs("packets ", stdout);
116                         break;
117                 case IPT_CONNBYTES_BYTES:
118                         fputs("bytes ", stdout);
119                         break;
120                 case IPT_CONNBYTES_AVGPKT:
121                         fputs("avgpkt ", stdout);
122                         break;
123                 default:
124                         fputs("unknown ", stdout);
125                         break;
126         }
127 }
128
129 static void print_direction(struct ipt_connbytes_info *sinfo)
130 {
131         switch (sinfo->direction) {
132                 case IPT_CONNBYTES_DIR_ORIGINAL:
133                         fputs("original ", stdout);
134                         break;
135                 case IPT_CONNBYTES_DIR_REPLY:
136                         fputs("reply ", stdout);
137                         break;
138                 case IPT_CONNBYTES_DIR_BOTH:
139                         fputs("both ", stdout);
140                         break;
141                 default:
142                         fputs("unknown ", stdout);
143                         break;
144         }
145 }
146
147 /* Prints out the matchinfo. */
148 static void
149 print(const struct ipt_ip *ip,
150       const struct ipt_entry_match *match,
151       int numeric)
152 {
153         struct ipt_connbytes_info *sinfo = (struct ipt_connbytes_info *)match->data;
154
155         if (sinfo->count.from > sinfo->count.to) 
156                 printf("connbytes ! %llu:%llu ", sinfo->count.to,
157                         sinfo->count.from);
158         else
159                 printf("connbytes %llu:%llu ",sinfo->count.from,
160                         sinfo->count.to);
161
162         fputs("connbytes mode ", stdout);
163         print_mode(sinfo);
164
165         fputs("connbytes direction ", stdout);
166         print_direction(sinfo);
167 }
168
169 /* Saves the matchinfo in parsable form to stdout. */
170 static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
171 {
172         struct ipt_connbytes_info *sinfo = (struct ipt_connbytes_info *)match->data;
173
174         if (sinfo->count.from > sinfo->count.to) 
175                 printf("! --connbytes %llu:%llu ", sinfo->count.to,
176                         sinfo->count.from);
177         else
178                 printf("--connbytes %llu:%llu ", sinfo->count.from,
179                         sinfo->count.to);
180
181         fputs("--connbytes-mode ", stdout);
182         print_mode(sinfo);
183
184         fputs("--connbytes-dir ", stdout);
185         print_direction(sinfo);
186 }
187
188 static struct iptables_match state = {
189         .next           = NULL,
190         .name           = "connbytes",
191         .version        = IPTABLES_VERSION,
192         .size           = IPT_ALIGN(sizeof(struct ipt_connbytes_info)),
193         .userspacesize  = IPT_ALIGN(sizeof(struct ipt_connbytes_info)),
194         .help           = &help,
195         .parse          = &parse,
196         .final_check    = &final_check,
197         .print          = &print,
198         .save           = &save,
199         .extra_opts     = opts
200 };
201
202 void _init(void)
203 {
204         register_match(&state);
205 }