blob: 68f52808a50b5236317c8f016a4191c5a943e87f [file] [log] [blame]
Marc Bouchere6869a82000-03-20 06:03:29 +00001/* Shared library add-on to iptables to add state tracking support. */
2#include <stdio.h>
3#include <netdb.h>
4#include <string.h>
5#include <stdlib.h>
6#include <getopt.h>
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +00007#include <xtables.h>
Patrick McHardy40d54752007-04-18 07:00:36 +00008#include <linux/netfilter/nf_conntrack_common.h>
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +00009#include <linux/netfilter/xt_state.h>
Marc Bouchere6869a82000-03-20 06:03:29 +000010
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +000011#ifndef XT_STATE_UNTRACKED
12#define XT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1))
Harald Welte4dc734c2003-10-07 18:55:13 +000013#endif
14
Marc Bouchere6869a82000-03-20 06:03:29 +000015/* Function which prints out usage message. */
16static void
László Attila Tóth72118882007-10-08 05:12:42 +000017state_help(void)
Marc Bouchere6869a82000-03-20 06:03:29 +000018{
19 printf(
20"state v%s options:\n"
Harald Welte4dc734c2003-10-07 18:55:13 +000021" [!] --state [INVALID|ESTABLISHED|NEW|RELATED|UNTRACKED][,...]\n"
Marc Bouchere6869a82000-03-20 06:03:29 +000022" State(s) to match\n"
Harald Welte80fe35d2002-05-29 13:08:15 +000023"\n", IPTABLES_VERSION);
Marc Bouchere6869a82000-03-20 06:03:29 +000024}
25
László Attila Tóth72118882007-10-08 05:12:42 +000026static const struct option state_opts[] = {
Patrick McHardy500f4832007-09-08 15:59:04 +000027 { "state", 1, NULL, '1' },
Max Kellermann9ee386a2008-01-29 13:48:05 +000028 { .name = NULL }
Marc Bouchere6869a82000-03-20 06:03:29 +000029};
30
Marc Bouchere6869a82000-03-20 06:03:29 +000031static int
László Attila Tóth72118882007-10-08 05:12:42 +000032state_parse_state(const char *state, size_t strlen, struct xt_state_info *sinfo)
Marc Bouchere6869a82000-03-20 06:03:29 +000033{
34 if (strncasecmp(state, "INVALID", strlen) == 0)
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +000035 sinfo->statemask |= XT_STATE_INVALID;
Marc Bouchere6869a82000-03-20 06:03:29 +000036 else if (strncasecmp(state, "NEW", strlen) == 0)
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +000037 sinfo->statemask |= XT_STATE_BIT(IP_CT_NEW);
Marc Bouchere6869a82000-03-20 06:03:29 +000038 else if (strncasecmp(state, "ESTABLISHED", strlen) == 0)
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +000039 sinfo->statemask |= XT_STATE_BIT(IP_CT_ESTABLISHED);
Marc Bouchere6869a82000-03-20 06:03:29 +000040 else if (strncasecmp(state, "RELATED", strlen) == 0)
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +000041 sinfo->statemask |= XT_STATE_BIT(IP_CT_RELATED);
Harald Welte4dc734c2003-10-07 18:55:13 +000042 else if (strncasecmp(state, "UNTRACKED", strlen) == 0)
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +000043 sinfo->statemask |= XT_STATE_UNTRACKED;
Marc Bouchere6869a82000-03-20 06:03:29 +000044 else
45 return 0;
46 return 1;
47}
48
49static void
László Attila Tóth72118882007-10-08 05:12:42 +000050state_parse_states(const char *arg, struct xt_state_info *sinfo)
Marc Bouchere6869a82000-03-20 06:03:29 +000051{
52 const char *comma;
53
54 while ((comma = strchr(arg, ',')) != NULL) {
László Attila Tóth72118882007-10-08 05:12:42 +000055 if (comma == arg || !state_parse_state(arg, comma-arg, sinfo))
Marc Bouchere6869a82000-03-20 06:03:29 +000056 exit_error(PARAMETER_PROBLEM, "Bad state `%s'", arg);
57 arg = comma+1;
58 }
59
László Attila Tóth72118882007-10-08 05:12:42 +000060 if (strlen(arg) == 0 || !state_parse_state(arg, strlen(arg), sinfo))
Marc Bouchere6869a82000-03-20 06:03:29 +000061 exit_error(PARAMETER_PROBLEM, "Bad state `%s'", arg);
62}
63
64/* Function which parses command options; returns true if it
65 ate an option */
66static int
László Attila Tóth72118882007-10-08 05:12:42 +000067state_parse(int c, char **argv, int invert, unsigned int *flags,
Yasuyuki KOZAKAIc0a9ab92007-07-24 06:02:05 +000068 const void *entry,
Yasuyuki KOZAKAI193df8e2007-07-24 05:57:28 +000069 struct xt_entry_match **match)
Marc Bouchere6869a82000-03-20 06:03:29 +000070{
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +000071 struct xt_state_info *sinfo = (struct xt_state_info *)(*match)->data;
Marc Bouchere6869a82000-03-20 06:03:29 +000072
73 switch (c) {
74 case '1':
Harald Welteb77f1da2002-03-14 11:35:58 +000075 check_inverse(optarg, &invert, &optind, 0);
Marc Bouchere6869a82000-03-20 06:03:29 +000076
László Attila Tóth72118882007-10-08 05:12:42 +000077 state_parse_states(argv[optind-1], sinfo);
Marc Bouchere6869a82000-03-20 06:03:29 +000078 if (invert)
79 sinfo->statemask = ~sinfo->statemask;
80 *flags = 1;
81 break;
82
83 default:
84 return 0;
85 }
86
87 return 1;
88}
89
90/* Final check; must have specified --state. */
László Attila Tóth72118882007-10-08 05:12:42 +000091static void state_final_check(unsigned int flags)
Marc Bouchere6869a82000-03-20 06:03:29 +000092{
93 if (!flags)
94 exit_error(PARAMETER_PROBLEM, "You must specify `--state'");
95}
96
László Attila Tóth72118882007-10-08 05:12:42 +000097static void state_print_state(unsigned int statemask)
Marc Bouchere6869a82000-03-20 06:03:29 +000098{
99 const char *sep = "";
100
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +0000101 if (statemask & XT_STATE_INVALID) {
Marc Bouchere6869a82000-03-20 06:03:29 +0000102 printf("%sINVALID", sep);
103 sep = ",";
104 }
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +0000105 if (statemask & XT_STATE_BIT(IP_CT_NEW)) {
Marc Bouchere6869a82000-03-20 06:03:29 +0000106 printf("%sNEW", sep);
107 sep = ",";
108 }
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +0000109 if (statemask & XT_STATE_BIT(IP_CT_RELATED)) {
Marc Bouchere6869a82000-03-20 06:03:29 +0000110 printf("%sRELATED", sep);
111 sep = ",";
112 }
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +0000113 if (statemask & XT_STATE_BIT(IP_CT_ESTABLISHED)) {
Marc Bouchere6869a82000-03-20 06:03:29 +0000114 printf("%sESTABLISHED", sep);
115 sep = ",";
116 }
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +0000117 if (statemask & XT_STATE_UNTRACKED) {
Harald Welte4dc734c2003-10-07 18:55:13 +0000118 printf("%sUNTRACKED", sep);
119 sep = ",";
120 }
Marc Bouchere6869a82000-03-20 06:03:29 +0000121 printf(" ");
122}
123
124/* Prints out the matchinfo. */
125static void
László Attila Tóth72118882007-10-08 05:12:42 +0000126state_print(const void *ip,
Yasuyuki KOZAKAI193df8e2007-07-24 05:57:28 +0000127 const struct xt_entry_match *match,
Marc Bouchere6869a82000-03-20 06:03:29 +0000128 int numeric)
129{
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +0000130 struct xt_state_info *sinfo = (struct xt_state_info *)match->data;
Marc Bouchere6869a82000-03-20 06:03:29 +0000131
132 printf("state ");
László Attila Tóth72118882007-10-08 05:12:42 +0000133 state_print_state(sinfo->statemask);
Marc Bouchere6869a82000-03-20 06:03:29 +0000134}
135
136/* Saves the matchinfo in parsable form to stdout. */
László Attila Tóth72118882007-10-08 05:12:42 +0000137static void state_save(const void *ip, const struct xt_entry_match *match)
Marc Bouchere6869a82000-03-20 06:03:29 +0000138{
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +0000139 struct xt_state_info *sinfo = (struct xt_state_info *)match->data;
Marc Bouchere6869a82000-03-20 06:03:29 +0000140
141 printf("--state ");
László Attila Tóth72118882007-10-08 05:12:42 +0000142 state_print_state(sinfo->statemask);
Marc Bouchere6869a82000-03-20 06:03:29 +0000143}
144
László Attila Tóth72118882007-10-08 05:12:42 +0000145static struct xtables_match state_match = {
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +0000146 .family = AF_INET,
Pablo Neira8caee8b2004-12-28 13:11:59 +0000147 .name = "state",
148 .version = IPTABLES_VERSION,
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +0000149 .size = XT_ALIGN(sizeof(struct xt_state_info)),
150 .userspacesize = XT_ALIGN(sizeof(struct xt_state_info)),
László Attila Tóth72118882007-10-08 05:12:42 +0000151 .help = state_help,
152 .parse = state_parse,
153 .final_check = state_final_check,
154 .print = state_print,
155 .save = state_save,
156 .extra_opts = state_opts,
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +0000157};
158
László Attila Tóth72118882007-10-08 05:12:42 +0000159static struct xtables_match state_match6 = {
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +0000160 .family = AF_INET6,
161 .name = "state",
162 .version = IPTABLES_VERSION,
163 .size = XT_ALIGN(sizeof(struct xt_state_info)),
164 .userspacesize = XT_ALIGN(sizeof(struct xt_state_info)),
László Attila Tóth72118882007-10-08 05:12:42 +0000165 .help = state_help,
166 .parse = state_parse,
167 .final_check = state_final_check,
168 .print = state_print,
169 .save = state_save,
170 .extra_opts = state_opts,
Marc Bouchere6869a82000-03-20 06:03:29 +0000171};
172
173void _init(void)
174{
László Attila Tóth72118882007-10-08 05:12:42 +0000175 xtables_register_match(&state_match);
176 xtables_register_match(&state_match6);
Marc Bouchere6869a82000-03-20 06:03:29 +0000177}