1 /* Shared library add-on to iptables to add TCP support. */
8 #include <linux/netfilter_ipv4/ip_tables.h>
10 /* Function which prints out usage message. */
16 " --tcp-flags [!] mask comp match when TCP flags & mask == comp\n"
17 " (Flags: SYN ACK FIN RST URG PSH ALL NONE)\n"
18 "[!] --syn match when only SYN flag set\n"
19 " (equivalent to --tcp-flags SYN,RST,ACK,FIN SYN)\n"
20 " --source-port [!] port[:port]\n"
22 " match source port(s)\n"
23 " --destination-port [!] port[:port]\n"
25 " match destination port(s)\n"
26 " --tcp-option [!] number match if TCP option set\n\n",
30 static struct option opts
[] = {
31 { "source-port", 1, 0, '1' },
32 { "sport", 1, 0, '1' }, /* synonym */
33 { "destination-port", 1, 0, '2' },
34 { "dport", 1, 0, '2' }, /* synonym */
36 { "tcp-flags", 1, 0, '4' },
37 { "tcp-option", 1, 0, '5' },
42 parse_tcp_ports(const char *portstring
, u_int16_t
*ports
)
47 buffer
= strdup(portstring
);
48 if ((cp
= strchr(buffer
, ':')) == NULL
)
49 ports
[0] = ports
[1] = parse_port(buffer
, "tcp");
54 ports
[0] = buffer
[0] ? parse_port(buffer
, "tcp") : 0;
55 ports
[1] = cp
[0] ? parse_port(cp
, "tcp") : 0xFFFF;
57 if (ports
[0] > ports
[1])
58 exit_error(PARAMETER_PROBLEM
,
59 "invalid portrange (min > max)");
64 struct tcp_flag_names
{
69 static struct tcp_flag_names tcp_flag_names
[]
81 parse_tcp_flag(const char *flags
)
87 buffer
= strdup(flags
);
89 for (ptr
= strtok(buffer
, ","); ptr
; ptr
= strtok(NULL
, ",")) {
92 i
< sizeof(tcp_flag_names
)/sizeof(struct tcp_flag_names
);
94 if (strcasecmp(tcp_flag_names
[i
].name
, ptr
) == 0) {
95 ret
|= tcp_flag_names
[i
].flag
;
99 if (i
== sizeof(tcp_flag_names
)/sizeof(struct tcp_flag_names
))
100 exit_error(PARAMETER_PROBLEM
,
101 "Unknown TCP flag `%s'", ptr
);
109 parse_tcp_flags(struct ipt_tcp
*tcpinfo
,
114 tcpinfo
->flg_mask
= parse_tcp_flag(mask
);
115 tcpinfo
->flg_cmp
= parse_tcp_flag(cmp
);
118 tcpinfo
->invflags
|= IPT_TCP_INV_FLAGS
;
122 parse_tcp_option(const char *option
, u_int8_t
*result
)
126 if (string_to_number(option
, 1, 255, &ret
) == -1)
127 exit_error(PARAMETER_PROBLEM
, "Bad TCP option `%s'", option
);
129 *result
= (u_int8_t
)ret
;
132 /* Initialize the match. */
134 init(struct ipt_entry_match
*m
, unsigned int *nfcache
)
136 struct ipt_tcp
*tcpinfo
= (struct ipt_tcp
*)m
->data
;
138 tcpinfo
->spts
[1] = tcpinfo
->dpts
[1] = 0xFFFF;
141 #define TCP_SRC_PORTS 0x01
142 #define TCP_DST_PORTS 0x02
143 #define TCP_FLAGS 0x04
144 #define TCP_OPTION 0x08
146 /* Function which parses command options; returns true if it
149 parse(int c
, char **argv
, int invert
, unsigned int *flags
,
150 const struct ipt_entry
*entry
,
151 unsigned int *nfcache
,
152 struct ipt_entry_match
**match
)
154 struct ipt_tcp
*tcpinfo
= (struct ipt_tcp
*)(*match
)->data
;
158 if (*flags
& TCP_SRC_PORTS
)
159 exit_error(PARAMETER_PROBLEM
,
160 "Only one `--source-port' allowed");
161 check_inverse(optarg
, &invert
, &optind
, 0);
162 parse_tcp_ports(argv
[optind
-1], tcpinfo
->spts
);
164 tcpinfo
->invflags
|= IPT_TCP_INV_SRCPT
;
165 *flags
|= TCP_SRC_PORTS
;
169 if (*flags
& TCP_DST_PORTS
)
170 exit_error(PARAMETER_PROBLEM
,
171 "Only one `--destination-port' allowed");
172 check_inverse(optarg
, &invert
, &optind
, 0);
173 parse_tcp_ports(argv
[optind
-1], tcpinfo
->dpts
);
175 tcpinfo
->invflags
|= IPT_TCP_INV_DSTPT
;
176 *flags
|= TCP_DST_PORTS
;
180 if (*flags
& TCP_FLAGS
)
181 exit_error(PARAMETER_PROBLEM
,
182 "Only one of `--syn' or `--tcp-flags' "
184 parse_tcp_flags(tcpinfo
, "SYN,RST,ACK,FIN", "SYN", invert
);
189 if (*flags
& TCP_FLAGS
)
190 exit_error(PARAMETER_PROBLEM
,
191 "Only one of `--syn' or `--tcp-flags' "
193 check_inverse(optarg
, &invert
, &optind
, 0);
196 || argv
[optind
][0] == '-' || argv
[optind
][0] == '!')
197 exit_error(PARAMETER_PROBLEM
,
198 "--tcp-flags requires two args.");
200 parse_tcp_flags(tcpinfo
, argv
[optind
-1], argv
[optind
],
207 if (*flags
& TCP_OPTION
)
208 exit_error(PARAMETER_PROBLEM
,
209 "Only one `--tcp-option' allowed");
210 check_inverse(optarg
, &invert
, &optind
, 0);
211 parse_tcp_option(argv
[optind
-1], &tcpinfo
->option
);
213 tcpinfo
->invflags
|= IPT_TCP_INV_OPTION
;
214 *flags
|= TCP_OPTION
;
224 /* Final check; we don't care. */
226 final_check(unsigned int flags
)
231 port_to_service(int port
)
233 struct servent
*service
;
235 if ((service
= getservbyport(htons(port
), "tcp")))
236 return service
->s_name
;
242 print_port(u_int16_t port
, int numeric
)
246 if (numeric
|| (service
= port_to_service(port
)) == NULL
)
249 printf("%s", service
);
253 print_ports(const char *name
, u_int16_t min
, u_int16_t max
,
254 int invert
, int numeric
)
256 const char *inv
= invert
? "!" : "";
258 if (min
!= 0 || max
!= 0xFFFF || invert
) {
262 print_port(min
, numeric
);
265 print_port(min
, numeric
);
267 print_port(max
, numeric
);
274 print_option(u_int8_t option
, int invert
, int numeric
)
276 if (option
|| invert
)
277 printf("option=%s%u ", invert
? "!" : "", option
);
281 print_tcpf(u_int8_t flags
)
288 for (i
= 0; (flags
& tcp_flag_names
[i
].flag
) == 0; i
++);
292 printf("%s", tcp_flag_names
[i
].name
);
295 flags
&= ~tcp_flag_names
[i
].flag
;
303 print_flags(u_int8_t mask
, u_int8_t cmp
, int invert
, int numeric
)
305 if (mask
|| invert
) {
306 printf("flags:%s", invert
? "!" : "");
308 printf("0x%02X/0x%02X ", mask
, cmp
);
318 /* Prints out the union ipt_matchinfo. */
320 print(const struct ipt_ip
*ip
,
321 const struct ipt_entry_match
*match
, int numeric
)
323 const struct ipt_tcp
*tcp
= (struct ipt_tcp
*)match
->data
;
326 print_ports("spt", tcp
->spts
[0], tcp
->spts
[1],
327 tcp
->invflags
& IPT_TCP_INV_SRCPT
,
329 print_ports("dpt", tcp
->dpts
[0], tcp
->dpts
[1],
330 tcp
->invflags
& IPT_TCP_INV_DSTPT
,
332 print_option(tcp
->option
,
333 tcp
->invflags
& IPT_TCP_INV_OPTION
,
335 print_flags(tcp
->flg_mask
, tcp
->flg_cmp
,
336 tcp
->invflags
& IPT_TCP_INV_FLAGS
,
338 if (tcp
->invflags
& ~IPT_TCP_INV_MASK
)
339 printf("Unknown invflags: 0x%X ",
340 tcp
->invflags
& ~IPT_TCP_INV_MASK
);
343 /* Saves the union ipt_matchinfo in parsable form to stdout. */
344 static void save(const struct ipt_ip
*ip
, const struct ipt_entry_match
*match
)
346 const struct ipt_tcp
*tcpinfo
= (struct ipt_tcp
*)match
->data
;
348 if (tcpinfo
->spts
[0] != 0
349 || tcpinfo
->spts
[1] != 0xFFFF) {
350 if (tcpinfo
->invflags
& IPT_TCP_INV_SRCPT
)
354 printf("--sport %u:%u ",
358 printf("--sport %u ",
362 if (tcpinfo
->dpts
[0] != 0
363 || tcpinfo
->dpts
[1] != 0xFFFF) {
364 if (tcpinfo
->invflags
& IPT_TCP_INV_DSTPT
)
368 printf("--dport %u:%u ",
372 printf("--dport %u ",
377 || (tcpinfo
->invflags
& IPT_TCP_INV_OPTION
)) {
378 if (tcpinfo
->invflags
& IPT_TCP_INV_OPTION
)
380 printf("--tcp-option %u ", tcpinfo
->option
);
383 if (tcpinfo
->flg_mask
384 || (tcpinfo
->invflags
& IPT_TCP_INV_FLAGS
)) {
385 if (tcpinfo
->invflags
& IPT_TCP_INV_FLAGS
)
387 printf("--tcp-flags ");
388 if (tcpinfo
->flg_mask
!= 0xFF) {
389 print_tcpf(tcpinfo
->flg_mask
);
392 print_tcpf(tcpinfo
->flg_cmp
);
397 static struct iptables_match tcp
= {
400 .version
= IPTABLES_VERSION
,
401 .size
= IPT_ALIGN(sizeof(struct ipt_tcp
)),
402 .userspacesize
= IPT_ALIGN(sizeof(struct ipt_tcp
)),
406 .final_check
= &final_check
,
415 register_match(&tcp
);