blob: 9f6af1cfbfe9824b92dfa4dfcdf1eaee52b1ff49 [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* 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
11static 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
20static 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
27static void
28parse_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
46static int
47connbytes_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))
56 optind++;
57
58 parse_range(argv[optind-1], 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
98static 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
105static void print_mode(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
123static void print_direction(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
141static void
142connbytes_print(const void *ip, const struct xt_entry_match *match, int numeric)
143{
144 struct xt_connbytes_info *sinfo = (struct xt_connbytes_info *)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
162static void connbytes_save(const void *ip, const struct xt_entry_match *match)
163{
164 struct xt_connbytes_info *sinfo = (struct xt_connbytes_info *)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
182static struct xtables_match connbytes_match = {
183 .family = NFPROTO_IPV4,
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
196static struct xtables_match connbytes_match6 = {
197 .family = NFPROTO_IPV6,
198 .name = "connbytes",
199 .version = XTABLES_VERSION,
200 .size = XT_ALIGN(sizeof(struct xt_connbytes_info)),
201 .userspacesize = XT_ALIGN(sizeof(struct xt_connbytes_info)),
202 .help = connbytes_help,
203 .parse = connbytes_parse,
204 .final_check = connbytes_check,
205 .print = connbytes_print,
206 .save = connbytes_save,
207 .extra_opts = connbytes_opts,
208};
209
210void _init(void)
211{
212 xtables_register_match(&connbytes_match);
213 xtables_register_match(&connbytes_match6);
214}