blob: a87cc51c85b82ebdbc00ffc8732df81203bec30c [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/*
2 * libxt_sockopt
3 * Shared library add-on to iptables for socket field matching support.
4 */
5#include <getopt.h>
6#include <stdio.h>
7#include <string.h>
8#include <xtables.h>
9#include <linux/netfilter.h>
10#include <linux/netfilter/xt_sockopt.h>
11
12static void sockopt_mt_help(void)
13{
14 printf(
15"sockopt match options:\n"
16"[!] --soorigdev devname\n"
17"[!] --soorigsrc address[/mask]\n"
18"[!] --soorigsrc address-address\n"
19"[!] --soorigdst address[/mask]\n"
20"[!] --soorigdst address-address\n"
21);
22}
23
24static const struct option sockopt_mt_opts[] = {
25 {.name = "soorigdev", .has_arg = true, .val = '1'},
26 {.name = "soorigsrc", .has_arg = true, .val = '2'},
27 {.name = "soorigdst", .has_arg = true, .val = '3'},
28 {.name = NULL},
29};
30
31static int parse_addr(struct in_addr *addr, struct in_addr *mask, char *arg)
32{
33 struct in_addr *ip;
34 char *dash;
35
36 dash = strrchr(arg, '-');
37 if (dash != NULL) {
38 *dash = '\0';
39 ip = xtables_numeric_to_ipaddr(arg);
40 if (!ip)
41 xtables_error(PARAMETER_PROBLEM,
42 "sockopt match: Bad IP address \"%s\"\n", arg);
43 *addr = *ip;
44
45 ip = xtables_numeric_to_ipaddr(dash + 1);
46 if (!ip)
47 xtables_error(PARAMETER_PROBLEM,
48 "sockopt match: Bad IP address \"%s\"\n",
49 dash + 1);
50 *mask = *ip;
51
52 return 1;
53 } else {
54 struct in_addr *addrs = NULL;
55 unsigned int naddrs = 0;
56
57 xtables_ipparse_any(arg, &addrs, mask, &naddrs);
58 if (naddrs > 1)
59 xtables_error(PARAMETER_PROBLEM,
60 "multiple IP addresses not allowed");
61 if (naddrs == 1)
62 memcpy(addr, addrs, sizeof(*addrs));
63
64 return 0;
65 }
66}
67
68static int sockopt_mt_parse(int c, char **argv, int invert, unsigned int *flags,
69 const void *entry, struct xt_entry_match **match)
70{
71 struct xt_sockopt_mtinfo *info = (void *)(*match)->data;
72 unsigned int dev;
73 char *end;
74
75 switch (c) {
76 case '1':
77 xtables_param_act(XTF_ONLY_ONCE, "sockopt", "--soorigdev", *flags & XT_SOCKOPT_ORIGDEV);
78 if (!xtables_strtoui(optarg, &end, &dev, 0, UINT32_MAX))
79 xtables_param_act(XTF_BAD_VALUE, "sockopt", "--soorigdev", optarg);
80 if (*end != '\0')
81 xtables_param_act(XTF_BAD_VALUE, "sockopt", "--soorigdev", optarg);
82 info->origdev = dev;
83 if (invert)
84 info->invert |= XT_SOCKOPT_ORIGDEV;
85 info->match |= XT_SOCKOPT_ORIGDEV;
86 *flags |= XT_SOCKOPT_ORIGDEV;
87 return true;
88
89 case '2':
90 xtables_param_act(XTF_ONLY_ONCE, "sockopt", "--soorigsrc", *flags & XT_SOCKOPT_ORIGSRC);
91 if (parse_addr(&info->origsrc_addr.in, &info->origsrc_mask.in,
92 argv[optind-1]))
93 info->match |= XT_SOCKOPT_SRCRANGE;
94 if (invert)
95 info->invert |= XT_SOCKOPT_ORIGSRC;
96 info->match |= XT_SOCKOPT_ORIGSRC;
97 *flags |= XT_SOCKOPT_ORIGSRC;
98 return true;
99
100 case '3':
101 xtables_param_act(XTF_ONLY_ONCE, "sockopt", "--soorigdst", *flags & XT_SOCKOPT_ORIGDST);
102 if (parse_addr(&info->origdst_addr.in, &info->origdst_mask.in,
103 argv[optind-1]))
104 info->match |= XT_SOCKOPT_DSTRANGE;
105 if (invert)
106 info->invert |= XT_SOCKOPT_ORIGDST;
107 info->match |= XT_SOCKOPT_ORIGDST;
108 *flags |= XT_SOCKOPT_ORIGDST;
109 return true;
110
111 default:
112 return false;
113 }
114}
115
116static void sockopt_mt_check(unsigned int flags)
117{
118 if (flags == 0)
119 xtables_error(PARAMETER_PROBLEM, "sockopt: At least one option "
120 "is required");
121}
122
123static void
124sockopt_dump_addr(const union nf_inet_addr *addr,
125 const union nf_inet_addr *mask, int range,
126 unsigned int family, bool numeric)
127{
128 if (family == NFPROTO_IPV4) {
129 if (!numeric && addr->ip == 0) {
130 printf("anywhere ");
131 } else if (range) {
132 printf("%s-%s ", xtables_ipaddr_to_numeric(&addr->in),
133 xtables_ipaddr_to_numeric(&mask->in));
134 } else if (numeric) {
135 printf("%s%s ", xtables_ipaddr_to_numeric(&addr->in),
136 xtables_ipmask_to_numeric(&mask->in));
137 } else {
138 printf("%s%s ", xtables_ipaddr_to_anyname(&addr->in),
139 xtables_ipmask_to_numeric(&mask->in));
140 }
141 } else if (family == NFPROTO_IPV6) {
142 if (!numeric && addr->ip6[0] == 0 && addr->ip6[1] == 0 &&
143 addr->ip6[2] == 0 && addr->ip6[3] == 0) {
144 printf("anywhere ");
145 } else if (range) {
146 printf("%s-%s ", xtables_ip6addr_to_numeric(&addr->in6),
147 xtables_ip6addr_to_numeric(&mask->in6));
148 } else if (numeric) {
149 printf("%s%s ", xtables_ip6addr_to_numeric(&addr->in6),
150 xtables_ip6mask_to_numeric(&mask->in6));
151 } else {
152 printf("%s%s ", xtables_ip6addr_to_anyname(&addr->in6),
153 xtables_ip6mask_to_numeric(&mask->in6));
154 }
155 }
156}
157
158static void
159sockopt_dump(const struct xt_sockopt_mtinfo *info, const char *prefix,
160 unsigned int family, bool numeric)
161{
162 if (info->match & XT_SOCKOPT_ORIGDEV) {
163 if (info->invert & XT_SOCKOPT_ORIGDEV)
164 printf("! ");
165 printf("%ssoorigdev ", prefix);
166 printf("%u ", info->origdev);
167 }
168
169 if (info->match & XT_SOCKOPT_ORIGSRC) {
170 if (info->invert & XT_SOCKOPT_ORIGSRC)
171 printf("! ");
172 printf("%ssoorigsrc ", prefix);
173 sockopt_dump_addr(
174 &info->origsrc_addr,
175 &info->origsrc_mask,
176 info->match & XT_SOCKOPT_SRCRANGE,
177 family, numeric);
178 }
179
180 if (info->match & XT_SOCKOPT_ORIGDST) {
181 if (info->invert & XT_SOCKOPT_ORIGDST)
182 printf("! ");
183 printf("%ssoorigsrc ", prefix);
184 sockopt_dump_addr(
185 &info->origdst_addr,
186 &info->origdst_mask,
187 info->match & XT_SOCKOPT_DSTRANGE,
188 family, numeric);
189 }
190}
191
192static void
193sockopt_mt_print(const void *ip, const struct xt_entry_match *match,
194 int numeric)
195{
196 sockopt_dump((const void *)match->data, "", NFPROTO_IPV4, numeric);
197}
198
199static void sockopt_mt_save(const void *ip,
200 const struct xt_entry_match *match)
201{
202 sockopt_dump((const void *)match->data, "--", NFPROTO_IPV4, true);
203}
204
205static struct xtables_match sockopt_mt_reg = {
206 .version = XTABLES_VERSION,
207 .name = "sockopt",
208 .revision = 0,
209 .family = NFPROTO_IPV4,
210 .size = XT_ALIGN(sizeof(struct xt_sockopt_mtinfo)),
211 .userspacesize = XT_ALIGN(sizeof(struct xt_sockopt_mtinfo)),
212 .help = sockopt_mt_help,
213 .parse = sockopt_mt_parse,
214 .final_check = sockopt_mt_check,
215 .print = sockopt_mt_print,
216 .save = sockopt_mt_save,
217 .extra_opts = sockopt_mt_opts,
218};
219
220void _init(void)
221{
222 xtables_register_match(&sockopt_mt_reg);
223}