1/* Shared library add-on to iptables to add byte 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/nf_conntrack_common.h> 9#include <linux/netfilter_ipv4/ipt_connbytes.h> 10 11/* Function which prints out usage message. */ 12static void 13help(void) 14{ 15 printf( 16"connbytes v%s options:\n" 17" [!] --connbytes from:[to]\n" 18" --connbytes-dir [original, reply, both]\n" 19" --connbytes-mode [packets, bytes, avgpkt]\n" 20"\n", IPTABLES_VERSION); 21} 22 23static struct option opts[] = { 24 { "connbytes", 1, 0, '1' }, 25 { "connbytes-dir", 1, 0, '2' }, 26 { "connbytes-mode", 1, 0, '3' }, 27 {0} 28}; 29 30static void 31parse_range(const char *arg, struct ipt_connbytes_info *si) 32{ 33 char *colon,*p; 34 35 si->count.from = strtoul(arg,&colon,10); 36 if (*colon != ':') 37 exit_error(PARAMETER_PROBLEM, "Bad range `%s'", arg); 38 si->count.to = strtoul(colon+1,&p,10); 39 if (p == colon+1) { 40 /* second number omited */ 41 si->count.to = 0xffffffff; 42 } 43 if (si->count.from > si->count.to) 44 exit_error(PARAMETER_PROBLEM, "%llu should be less than %llu", 45 si->count.from, si->count.to); 46} 47 48/* Function which parses command options; returns true if it 49 ate an option */ 50static int 51parse(int c, char **argv, int invert, unsigned int *flags, 52 const struct ipt_entry *entry, 53 unsigned int *nfcache, 54 struct ipt_entry_match **match) 55{ 56 struct ipt_connbytes_info *sinfo = (struct ipt_connbytes_info *)(*match)->data; 57 unsigned long i; 58 59 switch (c) { 60 case '1': 61 if (check_inverse(optarg, &invert, &optind, 0)) 62 optind++; 63 64 parse_range(argv[optind-1], sinfo); 65 if (invert) { 66 i = sinfo->count.from; 67 sinfo->count.from = sinfo->count.to; 68 sinfo->count.to = i; 69 } 70 *flags |= 1; 71 break; 72 case '2': 73 if (!strcmp(optarg, "original")) 74 sinfo->direction = IPT_CONNBYTES_DIR_ORIGINAL; 75 else if (!strcmp(optarg, "reply")) 76 sinfo->direction = IPT_CONNBYTES_DIR_REPLY; 77 else if (!strcmp(optarg, "both")) 78 sinfo->direction = IPT_CONNBYTES_DIR_BOTH; 79 else 80 exit_error(PARAMETER_PROBLEM, 81 "Unknown --connbytes-dir `%s'", optarg); 82 83 *flags |= 2; 84 break; 85 case '3': 86 if (!strcmp(optarg, "packets")) 87 sinfo->what = IPT_CONNBYTES_PKTS; 88 else if (!strcmp(optarg, "bytes")) 89 sinfo->what = IPT_CONNBYTES_BYTES; 90 else if (!strcmp(optarg, "avgpkt")) 91 sinfo->what = IPT_CONNBYTES_AVGPKT; 92 else 93 exit_error(PARAMETER_PROBLEM, 94 "Unknown --connbytes-mode `%s'", optarg); 95 *flags |= 4; 96 break; 97 default: 98 return 0; 99 } 100 101 return 1; 102} 103 104static void final_check(unsigned int flags) 105{ 106 if (flags != 7) 107 exit_error(PARAMETER_PROBLEM, "You must specify `--connbytes'" 108 "`--connbytes-dir' and `--connbytes-mode'"); 109} 110 111static void print_mode(struct ipt_connbytes_info *sinfo) 112{ 113 switch (sinfo->what) { 114 case IPT_CONNBYTES_PKTS: 115 fputs("packets ", stdout); 116 break; 117 case IPT_CONNBYTES_BYTES: 118 fputs("bytes ", stdout); 119 break; 120 case IPT_CONNBYTES_AVGPKT: 121 fputs("avgpkt ", stdout); 122 break; 123 default: 124 fputs("unknown ", stdout); 125 break; 126 } 127} 128 129static void print_direction(struct ipt_connbytes_info *sinfo) 130{ 131 switch (sinfo->direction) { 132 case IPT_CONNBYTES_DIR_ORIGINAL: 133 fputs("original ", stdout); 134 break; 135 case IPT_CONNBYTES_DIR_REPLY: 136 fputs("reply ", stdout); 137 break; 138 case IPT_CONNBYTES_DIR_BOTH: 139 fputs("both ", stdout); 140 break; 141 default: 142 fputs("unknown ", stdout); 143 break; 144 } 145} 146 147/* Prints out the matchinfo. */ 148static void 149print(const struct ipt_ip *ip, 150 const struct ipt_entry_match *match, 151 int numeric) 152{ 153 struct ipt_connbytes_info *sinfo = (struct ipt_connbytes_info *)match->data; 154 155 if (sinfo->count.from > sinfo->count.to) 156 printf("connbytes ! %llu:%llu ", sinfo->count.to, 157 sinfo->count.from); 158 else 159 printf("connbytes %llu:%llu ",sinfo->count.from, 160 sinfo->count.to); 161 162 fputs("connbytes mode ", stdout); 163 print_mode(sinfo); 164 165 fputs("connbytes direction ", stdout); 166 print_direction(sinfo); 167} 168 169/* Saves the matchinfo in parsable form to stdout. */ 170static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match) 171{ 172 struct ipt_connbytes_info *sinfo = (struct ipt_connbytes_info *)match->data; 173 174 if (sinfo->count.from > sinfo->count.to) 175 printf("! --connbytes %llu:%llu ", sinfo->count.to, 176 sinfo->count.from); 177 else 178 printf("--connbytes %llu:%llu ", sinfo->count.from, 179 sinfo->count.to); 180 181 fputs("--connbytes-mode ", stdout); 182 print_mode(sinfo); 183 184 fputs("--connbytes-dir ", stdout); 185 print_direction(sinfo); 186} 187 188static struct iptables_match state = { 189 .next = NULL, 190 .name = "connbytes", 191 .version = IPTABLES_VERSION, 192 .size = IPT_ALIGN(sizeof(struct ipt_connbytes_info)), 193 .userspacesize = IPT_ALIGN(sizeof(struct ipt_connbytes_info)), 194 .help = &help, 195 .parse = &parse, 196 .final_check = &final_check, 197 .print = &print, 198 .save = &save, 199 .extra_opts = opts 200}; 201 202void _init(void) 203{ 204 register_match(&state); 205} 206