1#include <stdio.h> 2#include <string.h> 3#include <xtables.h> 4#include <linux/netfilter/nf_conntrack_common.h> 5#include <linux/netfilter/xt_state.h> 6 7#ifndef XT_STATE_UNTRACKED 8#define XT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1)) 9#endif 10 11enum { 12 O_STATE = 0, 13}; 14 15static void 16state_help(void) 17{ 18 printf( 19"state match options:\n" 20" [!] --state [INVALID|ESTABLISHED|NEW|RELATED|UNTRACKED][,...]\n" 21" State(s) to match\n"); 22} 23 24static const struct xt_option_entry state_opts[] = { 25 {.name = "state", .id = O_STATE, .type = XTTYPE_STRING, 26 .flags = XTOPT_MAND | XTOPT_INVERT}, 27 XTOPT_TABLEEND, 28}; 29 30static int 31state_parse_state(const char *state, size_t len, struct xt_state_info *sinfo) 32{ 33 if (strncasecmp(state, "INVALID", len) == 0) 34 sinfo->statemask |= XT_STATE_INVALID; 35 else if (strncasecmp(state, "NEW", len) == 0) 36 sinfo->statemask |= XT_STATE_BIT(IP_CT_NEW); 37 else if (strncasecmp(state, "ESTABLISHED", len) == 0) 38 sinfo->statemask |= XT_STATE_BIT(IP_CT_ESTABLISHED); 39 else if (strncasecmp(state, "RELATED", len) == 0) 40 sinfo->statemask |= XT_STATE_BIT(IP_CT_RELATED); 41 else if (strncasecmp(state, "UNTRACKED", len) == 0) 42 sinfo->statemask |= XT_STATE_UNTRACKED; 43 else 44 return 0; 45 return 1; 46} 47 48static void 49state_parse_states(const char *arg, struct xt_state_info *sinfo) 50{ 51 const char *comma; 52 53 while ((comma = strchr(arg, ',')) != NULL) { 54 if (comma == arg || !state_parse_state(arg, comma-arg, sinfo)) 55 xtables_error(PARAMETER_PROBLEM, "Bad state \"%s\"", arg); 56 arg = comma+1; 57 } 58 if (!*arg) 59 xtables_error(PARAMETER_PROBLEM, "\"--state\" requires a list of " 60 "states with no spaces, e.g. " 61 "ESTABLISHED,RELATED"); 62 if (strlen(arg) == 0 || !state_parse_state(arg, strlen(arg), sinfo)) 63 xtables_error(PARAMETER_PROBLEM, "Bad state \"%s\"", arg); 64} 65 66static void state_parse(struct xt_option_call *cb) 67{ 68 struct xt_state_info *sinfo = cb->data; 69 70 xtables_option_parse(cb); 71 state_parse_states(cb->arg, sinfo); 72 if (cb->invert) 73 sinfo->statemask = ~sinfo->statemask; 74} 75 76static void state_print_state(unsigned int statemask) 77{ 78 const char *sep = ""; 79 80 if (statemask & XT_STATE_INVALID) { 81 printf("%sINVALID", sep); 82 sep = ","; 83 } 84 if (statemask & XT_STATE_BIT(IP_CT_NEW)) { 85 printf("%sNEW", sep); 86 sep = ","; 87 } 88 if (statemask & XT_STATE_BIT(IP_CT_RELATED)) { 89 printf("%sRELATED", sep); 90 sep = ","; 91 } 92 if (statemask & XT_STATE_BIT(IP_CT_ESTABLISHED)) { 93 printf("%sESTABLISHED", sep); 94 sep = ","; 95 } 96 if (statemask & XT_STATE_UNTRACKED) { 97 printf("%sUNTRACKED", sep); 98 sep = ","; 99 } 100} 101 102static void 103state_print(const void *ip, 104 const struct xt_entry_match *match, 105 int numeric) 106{ 107 const struct xt_state_info *sinfo = (const void *)match->data; 108 109 printf(" state "); 110 state_print_state(sinfo->statemask); 111} 112 113static void state_save(const void *ip, const struct xt_entry_match *match) 114{ 115 const struct xt_state_info *sinfo = (const void *)match->data; 116 117 printf(" --state "); 118 state_print_state(sinfo->statemask); 119} 120 121static struct xtables_match state_match = { 122 .family = NFPROTO_UNSPEC, 123 .name = "state", 124 .version = XTABLES_VERSION, 125 .size = XT_ALIGN(sizeof(struct xt_state_info)), 126 .userspacesize = XT_ALIGN(sizeof(struct xt_state_info)), 127 .help = state_help, 128 .print = state_print, 129 .save = state_save, 130 .x6_parse = state_parse, 131 .x6_options = state_opts, 132}; 133 134void _init(void) 135{ 136 xtables_register_match(&state_match); 137} 138