libxt_connbytes.c revision 32b8e61e4e5bd405d9ad07bf9468498dfbb19f9e
1/* Shared library add-on to iptables to add byte tracking support. */ 2#include <stdbool.h> 3#include <stdio.h> 4#include <netdb.h> 5#include <string.h> 6#include <stdlib.h> 7#include <getopt.h> 8#include <xtables.h> 9#include <linux/netfilter/nf_conntrack_common.h> 10#include <linux/netfilter/xt_connbytes.h> 11 12static void connbytes_help(void) 13{ 14 printf( 15"connbytes match options:\n" 16" [!] --connbytes from:[to]\n" 17" --connbytes-dir [original, reply, both]\n" 18" --connbytes-mode [packets, bytes, avgpkt]\n"); 19} 20 21static const struct option connbytes_opts[] = { 22 {.name = "connbytes", .has_arg = true, .val = '1'}, 23 {.name = "connbytes-dir", .has_arg = true, .val = '2'}, 24 {.name = "connbytes-mode", .has_arg = true, .val = '3'}, 25 XT_GETOPT_TABLEEND, 26}; 27 28static void 29parse_range(const char *arg, struct xt_connbytes_info *si) 30{ 31 char *colon,*p; 32 33 si->count.from = strtoul(arg,&colon,10); 34 if (*colon != ':') 35 xtables_error(PARAMETER_PROBLEM, "Bad range \"%s\"", arg); 36 si->count.to = strtoul(colon+1,&p,10); 37 if (p == colon+1) { 38 /* second number omited */ 39 si->count.to = 0xffffffff; 40 } 41 if (si->count.from > si->count.to) 42 xtables_error(PARAMETER_PROBLEM, "%llu should be less than %llu", 43 (unsigned long long)si->count.from, 44 (unsigned long long)si->count.to); 45} 46 47static int 48connbytes_parse(int c, char **argv, int invert, unsigned int *flags, 49 const void *entry, struct xt_entry_match **match) 50{ 51 struct xt_connbytes_info *sinfo = (struct xt_connbytes_info *)(*match)->data; 52 unsigned long i; 53 54 switch (c) { 55 case '1': 56 if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) 57 optind++; 58 59 parse_range(optarg, sinfo); 60 if (invert) { 61 i = sinfo->count.from; 62 sinfo->count.from = sinfo->count.to; 63 sinfo->count.to = i; 64 } 65 *flags |= 1; 66 break; 67 case '2': 68 if (!strcmp(optarg, "original")) 69 sinfo->direction = XT_CONNBYTES_DIR_ORIGINAL; 70 else if (!strcmp(optarg, "reply")) 71 sinfo->direction = XT_CONNBYTES_DIR_REPLY; 72 else if (!strcmp(optarg, "both")) 73 sinfo->direction = XT_CONNBYTES_DIR_BOTH; 74 else 75 xtables_error(PARAMETER_PROBLEM, 76 "Unknown --connbytes-dir `%s'", optarg); 77 78 *flags |= 2; 79 break; 80 case '3': 81 if (!strcmp(optarg, "packets")) 82 sinfo->what = XT_CONNBYTES_PKTS; 83 else if (!strcmp(optarg, "bytes")) 84 sinfo->what = XT_CONNBYTES_BYTES; 85 else if (!strcmp(optarg, "avgpkt")) 86 sinfo->what = XT_CONNBYTES_AVGPKT; 87 else 88 xtables_error(PARAMETER_PROBLEM, 89 "Unknown --connbytes-mode `%s'", optarg); 90 *flags |= 4; 91 break; 92 default: 93 return 0; 94 } 95 96 return 1; 97} 98 99static void connbytes_check(unsigned int flags) 100{ 101 if (flags != 7) 102 xtables_error(PARAMETER_PROBLEM, "You must specify `--connbytes'" 103 "`--connbytes-dir' and `--connbytes-mode'"); 104} 105 106static void print_mode(const struct xt_connbytes_info *sinfo) 107{ 108 switch (sinfo->what) { 109 case XT_CONNBYTES_PKTS: 110 fputs("packets ", stdout); 111 break; 112 case XT_CONNBYTES_BYTES: 113 fputs("bytes ", stdout); 114 break; 115 case XT_CONNBYTES_AVGPKT: 116 fputs("avgpkt ", stdout); 117 break; 118 default: 119 fputs("unknown ", stdout); 120 break; 121 } 122} 123 124static void print_direction(const struct xt_connbytes_info *sinfo) 125{ 126 switch (sinfo->direction) { 127 case XT_CONNBYTES_DIR_ORIGINAL: 128 fputs("original ", stdout); 129 break; 130 case XT_CONNBYTES_DIR_REPLY: 131 fputs("reply ", stdout); 132 break; 133 case XT_CONNBYTES_DIR_BOTH: 134 fputs("both ", stdout); 135 break; 136 default: 137 fputs("unknown ", stdout); 138 break; 139 } 140} 141 142static void 143connbytes_print(const void *ip, const struct xt_entry_match *match, int numeric) 144{ 145 const struct xt_connbytes_info *sinfo = (const void *)match->data; 146 147 if (sinfo->count.from > sinfo->count.to) 148 printf("connbytes ! %llu:%llu ", 149 (unsigned long long)sinfo->count.to, 150 (unsigned long long)sinfo->count.from); 151 else 152 printf("connbytes %llu:%llu ", 153 (unsigned long long)sinfo->count.from, 154 (unsigned long long)sinfo->count.to); 155 156 fputs("connbytes mode ", stdout); 157 print_mode(sinfo); 158 159 fputs("connbytes direction ", stdout); 160 print_direction(sinfo); 161} 162 163static void connbytes_save(const void *ip, const struct xt_entry_match *match) 164{ 165 const struct xt_connbytes_info *sinfo = (const void *)match->data; 166 167 if (sinfo->count.from > sinfo->count.to) 168 printf("! --connbytes %llu:%llu ", 169 (unsigned long long)sinfo->count.to, 170 (unsigned long long)sinfo->count.from); 171 else 172 printf("--connbytes %llu:%llu ", 173 (unsigned long long)sinfo->count.from, 174 (unsigned long long)sinfo->count.to); 175 176 fputs("--connbytes-mode ", stdout); 177 print_mode(sinfo); 178 179 fputs("--connbytes-dir ", stdout); 180 print_direction(sinfo); 181} 182 183static struct xtables_match connbytes_match = { 184 .family = NFPROTO_UNSPEC, 185 .name = "connbytes", 186 .version = XTABLES_VERSION, 187 .size = XT_ALIGN(sizeof(struct xt_connbytes_info)), 188 .userspacesize = XT_ALIGN(sizeof(struct xt_connbytes_info)), 189 .help = connbytes_help, 190 .parse = connbytes_parse, 191 .final_check = connbytes_check, 192 .print = connbytes_print, 193 .save = connbytes_save, 194 .extra_opts = connbytes_opts, 195}; 196 197void _init(void) 198{ 199 xtables_register_match(&connbytes_match); 200} 201