Home | History | Annotate | Download | only in extensions
      1 /* 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>
      7 #include <iptables.h>
      8 #include <linux/netfilter_ipv4/ip_conntrack.h>
      9 #include <linux/netfilter_ipv4/ipt_state.h>
     10 
     11 #ifndef IPT_STATE_UNTRACKED
     12 #define IPT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1))
     13 #endif
     14 
     15 /* Function which prints out usage message. */
     16 static void
     17 help(void)
     18 {
     19 	printf(
     20 "state v%s options:\n"
     21 " [!] --state [INVALID|ESTABLISHED|NEW|RELATED|UNTRACKED][,...]\n"
     22 "				State(s) to match\n"
     23 "\n", IPTABLES_VERSION);
     24 }
     25 
     26 static struct option opts[] = {
     27 	{ "state", 1, 0, '1' },
     28 	{0}
     29 };
     30 
     31 static int
     32 parse_state(const char *state, size_t strlen, struct ipt_state_info *sinfo)
     33 {
     34 	if (strncasecmp(state, "INVALID", strlen) == 0)
     35 		sinfo->statemask |= IPT_STATE_INVALID;
     36 	else if (strncasecmp(state, "NEW", strlen) == 0)
     37 		sinfo->statemask |= IPT_STATE_BIT(IP_CT_NEW);
     38 	else if (strncasecmp(state, "ESTABLISHED", strlen) == 0)
     39 		sinfo->statemask |= IPT_STATE_BIT(IP_CT_ESTABLISHED);
     40 	else if (strncasecmp(state, "RELATED", strlen) == 0)
     41 		sinfo->statemask |= IPT_STATE_BIT(IP_CT_RELATED);
     42 	else if (strncasecmp(state, "UNTRACKED", strlen) == 0)
     43 		sinfo->statemask |= IPT_STATE_UNTRACKED;
     44 	else
     45 		return 0;
     46 	return 1;
     47 }
     48 
     49 static void
     50 parse_states(const char *arg, struct ipt_state_info *sinfo)
     51 {
     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 */
     66 static int
     67 parse(int c, char **argv, int invert, unsigned int *flags,
     68       const struct ipt_entry *entry,
     69       unsigned int *nfcache,
     70       struct ipt_entry_match **match)
     71 {
     72 	struct ipt_state_info *sinfo = (struct ipt_state_info *)(*match)->data;
     73 
     74 	switch (c) {
     75 	case '1':
     76 		check_inverse(optarg, &invert, &optind, 0);
     77 
     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. */
     92 static void final_check(unsigned int flags)
     93 {
     94 	if (!flags)
     95 		exit_error(PARAMETER_PROBLEM, "You must specify `--state'");
     96 }
     97 
     98 static void print_state(unsigned int statemask)
     99 {
    100 	const char *sep = "";
    101 
    102 	if (statemask & IPT_STATE_INVALID) {
    103 		printf("%sINVALID", sep);
    104 		sep = ",";
    105 	}
    106 	if (statemask & IPT_STATE_BIT(IP_CT_NEW)) {
    107 		printf("%sNEW", sep);
    108 		sep = ",";
    109 	}
    110 	if (statemask & IPT_STATE_BIT(IP_CT_RELATED)) {
    111 		printf("%sRELATED", sep);
    112 		sep = ",";
    113 	}
    114 	if (statemask & IPT_STATE_BIT(IP_CT_ESTABLISHED)) {
    115 		printf("%sESTABLISHED", sep);
    116 		sep = ",";
    117 	}
    118 	if (statemask & IPT_STATE_UNTRACKED) {
    119 		printf("%sUNTRACKED", sep);
    120 		sep = ",";
    121 	}
    122 	printf(" ");
    123 }
    124 
    125 /* Prints out the matchinfo. */
    126 static void
    127 print(const struct ipt_ip *ip,
    128       const struct ipt_entry_match *match,
    129       int numeric)
    130 {
    131 	struct ipt_state_info *sinfo = (struct ipt_state_info *)match->data;
    132 
    133 	printf("state ");
    134 	print_state(sinfo->statemask);
    135 }
    136 
    137 /* Saves the matchinfo in parsable form to stdout. */
    138 static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
    139 {
    140 	struct ipt_state_info *sinfo = (struct ipt_state_info *)match->data;
    141 
    142 	printf("--state ");
    143 	print_state(sinfo->statemask);
    144 }
    145 
    146 static struct iptables_match state = {
    147 	.next		= NULL,
    148 	.name		= "state",
    149 	.version	= IPTABLES_VERSION,
    150 	.size		= IPT_ALIGN(sizeof(struct ipt_state_info)),
    151 	.userspacesize	= IPT_ALIGN(sizeof(struct ipt_state_info)),
    152 	.help		= &help,
    153 	.parse		= &parse,
    154 	.final_check	= &final_check,
    155 	.print		= &print,
    156 	.save		= &save,
    157 	.extra_opts	= opts
    158 };
    159 
    160 void ipt_state_init(void)
    161 {
    162 	register_match(&state);
    163 }
    164