1/* 2 * accounting match helper (libipt_account.c) 3 * (C) 2003,2004 by Piotr Gasid�o (quaker@barbara.eu.org) 4 * 5 * Version: 0.1.6 6 * 7 * This software is distributed under the terms of GNU GPL 8 */ 9 10#include <stdio.h> 11#include <stdlib.h> 12#include <iptables.h> 13#include <string.h> 14#include <getopt.h> 15 16#include <linux/netfilter_ipv4/ipt_account.h> 17 18#ifndef HIPQUAD 19#define HIPQUAD(addr) \ 20 ((unsigned char *)&addr)[3], \ 21 ((unsigned char *)&addr)[2], \ 22 ((unsigned char *)&addr)[1], \ 23 ((unsigned char *)&addr)[0] 24#endif 25 26static void help(void) { 27 printf( 28 "account v%s options:\n" 29 "--aaddr network/netmask\n" 30 " defines network/netmask for which make statistics.\n" 31 "--aname name\n" 32 " defines name of list where statistics will be kept. If no is\n" 33 " specified DEFAULT will be used.\n" 34 "--ashort\n" 35 " table will colect only short statistics (only total counters\n" 36 " without splitting it into protocols.\n" 37 , 38 IPTABLES_VERSION); 39}; 40 41static struct option opts[] = { 42 { .name = "aaddr", .has_arg = 1, .flag = NULL, .val = 201 }, 43 { .name = "aname", .has_arg = 1, .flag = NULL, .val = 202 }, 44 { .name = "ashort", .has_arg = 0, .flag = NULL, .val = 203 }, 45 { .name = 0, .has_arg = 0, .flag = 0, .val = 0 } 46}; 47 48/* Helper functions for parse_network */ 49int parseip(const char *parameter, u_int32_t *ip) { 50 51 char buffer[16], *bufferptr, *dot; 52 unsigned int i, shift, part; 53 54 if (strlen(parameter) > 15) 55 return 0; 56 57 strncpy(buffer, parameter, 15); 58 buffer[15] = 0; 59 60 bufferptr = buffer; 61 62 for (i = 0, shift = 24, *ip = 0; i < 3; i++, shift -= 8) { 63 /* no dot */ 64 if ((dot = strchr(bufferptr, '.')) == NULL) 65 return 0; 66 /* not a number */ 67 if ((part = strtol(bufferptr, (char**)NULL, 10)) < 0) 68 return 0; 69 /* to big number */ 70 if (part > 255) 71 return 0; 72 *ip |= part << shift; 73 bufferptr = dot + 1; 74 } 75 /* not a number */ 76 if ((part = strtol(bufferptr, (char**)NULL, 10)) < 0) 77 return 0; 78 /* to big number */ 79 if (part > 255) 80 return 0; 81 *ip |= part; 82 return 1; 83} 84 85static void parsenetwork(const char *parameter, u_int32_t *network) { 86 if (!parseip(parameter, network)) 87 exit_error(PARAMETER_PROBLEM, "account: wrong ip in network"); 88} 89 90static void parsenetmaskasbits(const char *parameter, u_int32_t *netmask) { 91 92 u_int32_t bits; 93 94 if ((bits = strtol(parameter, (char **)NULL, 10)) < 0 || bits > 32) 95 exit_error(PARAMETER_PROBLEM, "account: wrong netmask"); 96 97 *netmask = 0xffffffff << (32 - bits); 98} 99 100static void parsenetmaskasip(const char *parameter, u_int32_t *netmask) { 101 if (!parseip(parameter, netmask)) 102 exit_error(PARAMETER_PROBLEM, "account: wrong ip in netmask"); 103} 104 105static void parsenetmask(const char *parameter, u_int32_t *netmask) 106{ 107 if (strchr(parameter, '.') != NULL) 108 parsenetmaskasip(parameter, netmask); 109 else 110 parsenetmaskasbits(parameter, netmask); 111} 112 113static void parsenetworkandnetmask(const char *parameter, u_int32_t *network, u_int32_t *netmask) 114{ 115 116 char buffer[32], *slash; 117 118 if (strlen(parameter) > 31) 119 /* text is to long, even for 255.255.255.255/255.255.255.255 */ 120 exit_error(PARAMETER_PROBLEM, "account: wrong network/netmask"); 121 122 strncpy(buffer, parameter, 31); 123 buffer[31] = 0; 124 125 /* check whether netmask is given */ 126 if ((slash = strchr(buffer, '/')) != NULL) { 127 parsenetmask(slash + 1, netmask); 128 *slash = 0; 129 } else 130 *netmask = 0xffffffff; 131 parsenetwork(buffer, network); 132 133 if ((*network & *netmask) != *network) 134 exit_error(PARAMETER_PROBLEM, "account: wrong network/netmask"); 135} 136 137 138/* Function gets network & netmask from argument after --aaddr */ 139static void parse_network(const char *parameter, struct t_ipt_account_info *info) { 140 141 parsenetworkandnetmask(parameter, &info->network, &info->netmask); 142 143} 144 145/* validate netmask */ 146inline int valid_netmask(u_int32_t netmask) { 147 while (netmask & 0x80000000) 148 netmask <<= 1; 149 if (netmask != 0) 150 return 0; 151 return 1; 152} 153 154/* validate network/netmask pair */ 155inline int valid_network_and_netmask(struct t_ipt_account_info *info) { 156 if (!valid_netmask(info->netmask)) 157 return 0; 158 if ((info->network & info->netmask) != info->network) 159 return 0; 160 return 1; 161} 162 163 164 165/* Function initializes match */ 166static void init(struct ipt_entry_match *match, 167 unsigned int *nfcache) { 168 169 struct t_ipt_account_info *info = (struct t_ipt_account_info *)(match)->data; 170 171 172 /* set default table name to DEFAULT */ 173 strncpy(info->name, "DEFAULT", IPT_ACCOUNT_NAME_LEN); 174 info->shortlisting = 0; 175 176} 177 178/* Function parses match's arguments */ 179static int parse(int c, char **argv, 180 int invert, 181 unsigned int *flags, 182 const struct ipt_entry *entry, 183 unsigned int *nfcache, 184 struct ipt_entry_match **match) { 185 186 struct t_ipt_account_info *info = (struct t_ipt_account_info *)(*match)->data; 187 188 switch (c) { 189 190 /* --aaddr */ 191 case 201: 192 parse_network(optarg, info); 193 if (!valid_network_and_netmask(info)) 194 exit_error(PARAMETER_PROBLEM, "account: wrong network/netmask"); 195 *flags = 1; 196 break; 197 198 /* --aname */ 199 case 202: 200 if (strlen(optarg) < IPT_ACCOUNT_NAME_LEN) 201 strncpy(info->name, optarg, IPT_ACCOUNT_NAME_LEN); 202 else 203 exit_error(PARAMETER_PROBLEM, "account: Too long table name"); 204 break; 205 /* --ashort */ 206 case 203: 207 info->shortlisting = 1; 208 break; 209 default: 210 return 0; 211 } 212 return 1; 213} 214 215/* Final check whether network/netmask was specified */ 216static void final_check(unsigned int flags) { 217 if (!flags) 218 exit_error(PARAMETER_PROBLEM, "account: You need specify '--aaddr' parameter"); 219} 220 221/* Function used for printing rule with account match for iptables -L */ 222static void print(const struct ipt_ip *ip, 223 const struct ipt_entry_match *match, 224 int numeric) { 225 226 struct t_ipt_account_info *info = (struct t_ipt_account_info *)match->data; 227 228 printf("account: "); 229 printf("network/netmask: "); 230 printf("%u.%u.%u.%u/%u.%u.%u.%u ", 231 HIPQUAD(info->network), 232 HIPQUAD(info->netmask) 233 ); 234 235 printf("name: %s ", info->name); 236 if (info->shortlisting) 237 printf("short-listing "); 238} 239 240/* Function used for saving rule containing account match */ 241static void save(const struct ipt_ip *ip, 242 const struct ipt_entry_match *match) { 243 244 struct t_ipt_account_info *info = (struct t_ipt_account_info *)match->data; 245 246 printf("--aaddr "); 247 printf("%u.%u.%u.%u/%u.%u.%u.%u ", 248 HIPQUAD(info->network), 249 HIPQUAD(info->netmask) 250 ); 251 252 printf("--aname %s ", info->name); 253 if (info->shortlisting) 254 printf("--ashort "); 255} 256 257static struct iptables_match account = { 258 .next = NULL, 259 .name = "account", 260 .version = IPTABLES_VERSION, 261 .size = IPT_ALIGN(sizeof(struct t_ipt_account_info)), 262 .userspacesize = IPT_ALIGN(sizeof(struct t_ipt_account_info)), 263 .help = &help, 264 .init = &init, 265 .parse = &parse, 266 .final_check = &final_check, 267 .print = &print, 268 .save = &save, 269 .extra_opts = opts 270}; 271 272/* Function which registers match */ 273void _init(void) 274{ 275 register_match(&account); 276} 277 278