Fork for IVI and add .changes file
[profile/ivi/iptables.git] / extensions / libxt_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 <xtables.h>
8 #include <linux/netfilter/nf_conntrack_common.h>
9 #include <linux/netfilter/xt_connbytes.h>
10
11 static void connbytes_help(void)
12 {
13         printf(
14 "connbytes match options:\n"
15 " [!] --connbytes from:[to]\n"
16 "     --connbytes-dir [original, reply, both]\n"
17 "     --connbytes-mode [packets, bytes, avgpkt]\n");
18 }
19
20 static const struct option connbytes_opts[] = {
21         { "connbytes", 1, NULL, '1' },
22         { "connbytes-dir", 1, NULL, '2' },
23         { "connbytes-mode", 1, NULL, '3' },
24         { .name = NULL }
25 };
26
27 static void
28 parse_range(const char *arg, struct xt_connbytes_info *si)
29 {
30         char *colon,*p;
31
32         si->count.from = strtoul(arg,&colon,10);
33         if (*colon != ':') 
34                 xtables_error(PARAMETER_PROBLEM, "Bad range \"%s\"", arg);
35         si->count.to = strtoul(colon+1,&p,10);
36         if (p == colon+1) {
37                 /* second number omited */
38                 si->count.to = 0xffffffff;
39         }
40         if (si->count.from > si->count.to)
41                 xtables_error(PARAMETER_PROBLEM, "%llu should be less than %llu",
42                            (unsigned long long)si->count.from,
43                            (unsigned long long)si->count.to);
44 }
45
46 static int
47 connbytes_parse(int c, char **argv, int invert, unsigned int *flags,
48                 const void *entry, struct xt_entry_match **match)
49 {
50         struct xt_connbytes_info *sinfo = (struct xt_connbytes_info *)(*match)->data;
51         unsigned long i;
52
53         switch (c) {
54         case '1':
55                 if (xtables_check_inverse(optarg, &invert, &optind, 0, argv))
56                         optind++;
57
58                 parse_range(optarg, sinfo);
59                 if (invert) {
60                         i = sinfo->count.from;
61                         sinfo->count.from = sinfo->count.to;
62                         sinfo->count.to = i;
63                 }
64                 *flags |= 1;
65                 break;
66         case '2':
67                 if (!strcmp(optarg, "original"))
68                         sinfo->direction = XT_CONNBYTES_DIR_ORIGINAL;
69                 else if (!strcmp(optarg, "reply"))
70                         sinfo->direction = XT_CONNBYTES_DIR_REPLY;
71                 else if (!strcmp(optarg, "both"))
72                         sinfo->direction = XT_CONNBYTES_DIR_BOTH;
73                 else
74                         xtables_error(PARAMETER_PROBLEM,
75                                    "Unknown --connbytes-dir `%s'", optarg);
76
77                 *flags |= 2;
78                 break;
79         case '3':
80                 if (!strcmp(optarg, "packets"))
81                         sinfo->what = XT_CONNBYTES_PKTS;
82                 else if (!strcmp(optarg, "bytes"))
83                         sinfo->what = XT_CONNBYTES_BYTES;
84                 else if (!strcmp(optarg, "avgpkt"))
85                         sinfo->what = XT_CONNBYTES_AVGPKT;
86                 else
87                         xtables_error(PARAMETER_PROBLEM,
88                                    "Unknown --connbytes-mode `%s'", optarg);
89                 *flags |= 4;
90                 break;
91         default:
92                 return 0;
93         }
94
95         return 1;
96 }
97
98 static void connbytes_check(unsigned int flags)
99 {
100         if (flags != 7)
101                 xtables_error(PARAMETER_PROBLEM, "You must specify `--connbytes'"
102                            "`--connbytes-dir' and `--connbytes-mode'");
103 }
104
105 static void print_mode(const struct xt_connbytes_info *sinfo)
106 {
107         switch (sinfo->what) {
108                 case XT_CONNBYTES_PKTS:
109                         fputs("packets ", stdout);
110                         break;
111                 case XT_CONNBYTES_BYTES:
112                         fputs("bytes ", stdout);
113                         break;
114                 case XT_CONNBYTES_AVGPKT:
115                         fputs("avgpkt ", stdout);
116                         break;
117                 default:
118                         fputs("unknown ", stdout);
119                         break;
120         }
121 }
122
123 static void print_direction(const struct xt_connbytes_info *sinfo)
124 {
125         switch (sinfo->direction) {
126                 case XT_CONNBYTES_DIR_ORIGINAL:
127                         fputs("original ", stdout);
128                         break;
129                 case XT_CONNBYTES_DIR_REPLY:
130                         fputs("reply ", stdout);
131                         break;
132                 case XT_CONNBYTES_DIR_BOTH:
133                         fputs("both ", stdout);
134                         break;
135                 default:
136                         fputs("unknown ", stdout);
137                         break;
138         }
139 }
140
141 static void
142 connbytes_print(const void *ip, const struct xt_entry_match *match, int numeric)
143 {
144         const struct xt_connbytes_info *sinfo = (const void *)match->data;
145
146         if (sinfo->count.from > sinfo->count.to) 
147                 printf("connbytes ! %llu:%llu ",
148                         (unsigned long long)sinfo->count.to,
149                         (unsigned long long)sinfo->count.from);
150         else
151                 printf("connbytes %llu:%llu ",
152                         (unsigned long long)sinfo->count.from,
153                         (unsigned long long)sinfo->count.to);
154
155         fputs("connbytes mode ", stdout);
156         print_mode(sinfo);
157
158         fputs("connbytes direction ", stdout);
159         print_direction(sinfo);
160 }
161
162 static void connbytes_save(const void *ip, const struct xt_entry_match *match)
163 {
164         const struct xt_connbytes_info *sinfo = (const void *)match->data;
165
166         if (sinfo->count.from > sinfo->count.to) 
167                 printf("! --connbytes %llu:%llu ",
168                         (unsigned long long)sinfo->count.to,
169                         (unsigned long long)sinfo->count.from);
170         else
171                 printf("--connbytes %llu:%llu ",
172                         (unsigned long long)sinfo->count.from,
173                         (unsigned long long)sinfo->count.to);
174
175         fputs("--connbytes-mode ", stdout);
176         print_mode(sinfo);
177
178         fputs("--connbytes-dir ", stdout);
179         print_direction(sinfo);
180 }
181
182 static struct xtables_match connbytes_match = {
183         .family         = NFPROTO_UNSPEC,
184         .name           = "connbytes",
185         .version        = XTABLES_VERSION,
186         .size           = XT_ALIGN(sizeof(struct xt_connbytes_info)),
187         .userspacesize  = XT_ALIGN(sizeof(struct xt_connbytes_info)),
188         .help           = connbytes_help,
189         .parse          = connbytes_parse,
190         .final_check    = connbytes_check,
191         .print          = connbytes_print,
192         .save           = connbytes_save,
193         .extra_opts     = connbytes_opts,
194 };
195
196 void _init(void)
197 {
198         xtables_register_match(&connbytes_match);
199 }