blob: 3972a3bb120023d5ddfee75709d5ce56aa078b69 [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
17help(void)
18{
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
Jan Engelhardt661f1122007-07-30 14:46:51 +000026static const struct option opts[] = {
Marc Bouchere6869a82000-03-20 06:03:29 +000027 { "state", 1, 0, '1' },
28 {0}
29};
30
Marc Bouchere6869a82000-03-20 06:03:29 +000031static int
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +000032parse_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
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +000050parse_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) {
55 if (comma == arg || !parse_state(arg, comma-arg, sinfo))
56 exit_error(PARAMETER_PROBLEM, "Bad state `%s'", arg);
57 arg = comma+1;
58 }
59
60 if (strlen(arg) == 0 || !parse_state(arg, strlen(arg), sinfo))
61 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
67parse(int c, char **argv, int invert, unsigned int *flags,
Yasuyuki KOZAKAIc0a9ab92007-07-24 06:02:05 +000068 const void *entry,
Marc Bouchere6869a82000-03-20 06:03:29 +000069 unsigned int *nfcache,
Yasuyuki KOZAKAI193df8e2007-07-24 05:57:28 +000070 struct xt_entry_match **match)
Marc Bouchere6869a82000-03-20 06:03:29 +000071{
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +000072 struct xt_state_info *sinfo = (struct xt_state_info *)(*match)->data;
Marc Bouchere6869a82000-03-20 06:03:29 +000073
74 switch (c) {
75 case '1':
Harald Welteb77f1da2002-03-14 11:35:58 +000076 check_inverse(optarg, &invert, &optind, 0);
Marc Bouchere6869a82000-03-20 06:03:29 +000077
78 parse_states(argv[optind-1], sinfo);
79 if (invert)
80 sinfo->statemask = ~sinfo->statemask;
81 *flags = 1;
82 break;
83
84 default:
85 return 0;
86 }
87
88 return 1;
89}
90
91/* Final check; must have specified --state. */
92static void final_check(unsigned int flags)
93{
94 if (!flags)
95 exit_error(PARAMETER_PROBLEM, "You must specify `--state'");
96}
97
98static void print_state(unsigned int statemask)
99{
100 const char *sep = "";
101
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +0000102 if (statemask & XT_STATE_INVALID) {
Marc Bouchere6869a82000-03-20 06:03:29 +0000103 printf("%sINVALID", sep);
104 sep = ",";
105 }
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +0000106 if (statemask & XT_STATE_BIT(IP_CT_NEW)) {
Marc Bouchere6869a82000-03-20 06:03:29 +0000107 printf("%sNEW", sep);
108 sep = ",";
109 }
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +0000110 if (statemask & XT_STATE_BIT(IP_CT_RELATED)) {
Marc Bouchere6869a82000-03-20 06:03:29 +0000111 printf("%sRELATED", sep);
112 sep = ",";
113 }
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +0000114 if (statemask & XT_STATE_BIT(IP_CT_ESTABLISHED)) {
Marc Bouchere6869a82000-03-20 06:03:29 +0000115 printf("%sESTABLISHED", sep);
116 sep = ",";
117 }
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +0000118 if (statemask & XT_STATE_UNTRACKED) {
Harald Welte4dc734c2003-10-07 18:55:13 +0000119 printf("%sUNTRACKED", sep);
120 sep = ",";
121 }
Marc Bouchere6869a82000-03-20 06:03:29 +0000122 printf(" ");
123}
124
125/* Prints out the matchinfo. */
126static void
Yasuyuki KOZAKAIc0a9ab92007-07-24 06:02:05 +0000127print(const void *ip,
Yasuyuki KOZAKAI193df8e2007-07-24 05:57:28 +0000128 const struct xt_entry_match *match,
Marc Bouchere6869a82000-03-20 06:03:29 +0000129 int numeric)
130{
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +0000131 struct xt_state_info *sinfo = (struct xt_state_info *)match->data;
Marc Bouchere6869a82000-03-20 06:03:29 +0000132
133 printf("state ");
134 print_state(sinfo->statemask);
135}
136
137/* Saves the matchinfo in parsable form to stdout. */
Yasuyuki KOZAKAIc0a9ab92007-07-24 06:02:05 +0000138static void save(const void *ip, const struct xt_entry_match *match)
Marc Bouchere6869a82000-03-20 06:03:29 +0000139{
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +0000140 struct xt_state_info *sinfo = (struct xt_state_info *)match->data;
Marc Bouchere6869a82000-03-20 06:03:29 +0000141
142 printf("--state ");
143 print_state(sinfo->statemask);
144}
145
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +0000146static struct xtables_match state = {
147 .family = AF_INET,
Pablo Neira8caee8b2004-12-28 13:11:59 +0000148 .name = "state",
149 .version = IPTABLES_VERSION,
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +0000150 .size = XT_ALIGN(sizeof(struct xt_state_info)),
151 .userspacesize = XT_ALIGN(sizeof(struct xt_state_info)),
Pablo Neira8caee8b2004-12-28 13:11:59 +0000152 .help = &help,
Pablo Neira8caee8b2004-12-28 13:11:59 +0000153 .parse = &parse,
154 .final_check = &final_check,
155 .print = &print,
156 .save = &save,
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +0000157 .extra_opts = opts,
158};
159
160static struct xtables_match state6 = {
161 .family = AF_INET6,
162 .name = "state",
163 .version = IPTABLES_VERSION,
164 .size = XT_ALIGN(sizeof(struct xt_state_info)),
165 .userspacesize = XT_ALIGN(sizeof(struct xt_state_info)),
166 .help = &help,
167 .parse = &parse,
168 .final_check = &final_check,
169 .print = &print,
170 .save = &save,
171 .extra_opts = opts,
Marc Bouchere6869a82000-03-20 06:03:29 +0000172};
173
174void _init(void)
175{
Yasuyuki KOZAKAI1ff0b8d2007-08-04 08:09:51 +0000176 xtables_register_match(&state);
177 xtables_register_match(&state6);
Marc Bouchere6869a82000-03-20 06:03:29 +0000178}