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 11 enum { 12 O_STATE = 0, 13 }; 14 15 static void 16 state_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 24 static const struct xt_option_entry state_opts[] = { 25 {.name = "state", .id = O_STATE, .type = XTTYPE_STRING, 26 .flags = XTOPT_MAND}, 27 XTOPT_TABLEEND, 28 }; 29 30 static int 31 state_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 48 static void 49 state_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 66 static 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 76 static 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 102 static void 103 state_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 113 static 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 121 static 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 134 void _init(void) 135 { 136 xtables_register_match(&state_match); 137 } 138