56796630d11499802fabcac45e678bae0c9d14a7
[ipt_ACCOUNT] / iptables / extensions / libipt_ACCOUNT.c
1 /* Shared library add-on to iptables to add ACCOUNT(ing) support.
2    Author: Intra2net AG <opensource@intra2net.com>
3 */
4
5 #include <stdio.h>
6 #include <netdb.h>
7 #include <string.h>
8 #include <stdlib.h>
9 #include <syslog.h>
10 #include <getopt.h>
11 #include <stddef.h>
12 #include <iptables.h>
13 #include <linux/netfilter_ipv4/ip_tables.h>
14 #include <linux/netfilter_ipv4/ipt_ACCOUNT.h>
15
16 static struct option opts[] = {
17     { .name = "addr",        .has_arg = 1, .flag = 0, .val = 'a' },
18     { .name = "tname",       .has_arg = 1, .flag = 0, .val = 't' },
19     { .name = 0 }
20 };
21
22 /* Compat glue for iptables 1.4.0 */
23 #ifndef XTABLES_VERSION
24 #define XTABLES_VERSION IPTABLES_VERSION
25 #endif
26
27 /* Function which prints out usage message. */
28 static void help(void)
29 {
30     printf(
31 "ACCOUNT v%s options:\n"
32 " --%s ip/netmask\t\tBase network IP and netmask used for this table\n"
33 " --%s name\t\t\tTable name for the userspace library\n",
34 XTABLES_VERSION, opts[0].name, opts[1].name);
35 }
36
37 /* Initialize the target. */
38 static void
39 init(struct xt_entry_target *t)
40 {
41     struct ipt_acc_info *accountinfo = (struct ipt_acc_info *)t->data;
42
43     accountinfo->table_nr = -1;
44 }
45
46 #define IPT_ACCOUNT_OPT_ADDR 0x01
47 #define IPT_ACCOUNT_OPT_TABLE 0x02
48
49 /* Function which parses command options; returns true if it
50    ate an option */
51
52 static int parse(int c, char **argv, int invert, unsigned int *flags,
53                      const void *entry, struct xt_entry_target **target)
54 {
55     struct ipt_acc_info *accountinfo = (struct ipt_acc_info *)(*target)->data;
56     struct in_addr *addrs = NULL, mask;
57     unsigned int naddrs = 0;
58
59     switch (c) {
60     case 'a':
61         if (*flags & IPT_ACCOUNT_OPT_ADDR)
62                 exit_error(PARAMETER_PROBLEM, "Can't specify --%s twice",
63                             opts[0].name);
64
65         if (check_inverse(optarg, &invert, NULL, 0))
66                 exit_error(PARAMETER_PROBLEM, "Unexpected `!' after --%s",
67                             opts[0].name);
68
69 #ifdef XTABLES_VERSION_CODE
70         ipparse_hostnetworkmask(optarg, &addrs, &mask, &naddrs);
71 #else
72         parse_hostnetworkmask(optarg, &addrs, &mask, &naddrs);
73 #endif
74
75         if (naddrs > 1)
76                 exit_error(PARAMETER_PROBLEM, "multiple IP addresses not allowed");
77
78         accountinfo->net_ip = addrs[0].s_addr;
79         accountinfo->net_mask = mask.s_addr;
80
81         *flags |= IPT_ACCOUNT_OPT_ADDR;
82         break;
83
84     case 't':
85             if (*flags & IPT_ACCOUNT_OPT_TABLE)
86                     exit_error(PARAMETER_PROBLEM,
87                                 "Can't specify --%s twice", opts[1].name);
88
89             if (check_inverse(optarg, &invert, NULL, 0))
90                     exit_error(PARAMETER_PROBLEM,
91                                 "Unexpected `!' after --%s", opts[1].name);
92
93             if (strlen(optarg) > ACCOUNT_TABLE_NAME_LEN - 1)
94                     exit_error(PARAMETER_PROBLEM,
95                                 "Maximum table name length %u for --%s",
96                                 ACCOUNT_TABLE_NAME_LEN - 1, opts[1].name);
97
98             strcpy(accountinfo->table_name, optarg);
99             *flags |= IPT_ACCOUNT_OPT_TABLE;
100             break;
101
102     default:
103             return 0;
104     }
105     return 1;
106 }
107
108 /* Final check; nothing. */
109 static void final_check(unsigned int flags)
110 {
111     if (!(flags&IPT_ACCOUNT_OPT_ADDR) || !(flags&IPT_ACCOUNT_OPT_TABLE))
112         exit_error(PARAMETER_PROBLEM, "ACCOUNT: needs --%s and --%s",
113                     opts[0].name, opts[1].name);
114 }
115
116 static const char *print_helper_ip(struct in_addr a)
117 {
118 #ifdef XTABLES_VERSION_CODE
119     return ipaddr_to_numeric(&a);
120 #else
121     return addr_to_dotted(&a);
122 #endif
123 }
124
125 static const char *print_helper_mask(struct in_addr a)
126 {
127 #ifdef XTABLES_VERSION_CODE
128     return ipmask_to_numeric(&a);
129 #else
130     return mask_to_dotted(&a);
131 #endif
132 }
133
134 static void print_it(const void *ip,
135                      const struct xt_entry_target *target, char do_prefix)
136 {
137     const struct ipt_acc_info *accountinfo
138         = (const struct ipt_acc_info *)target->data;
139     struct in_addr a;
140
141     if (!do_prefix)
142         printf("ACCOUNT ");
143
144     // Network information
145     if (do_prefix)
146         printf("--");
147     printf("%s ", opts[0].name);
148
149     a.s_addr = accountinfo->net_ip;     
150     printf("%s", print_helper_ip(a));
151     a.s_addr = accountinfo->net_mask;
152     printf("%s", print_helper_mask(a));
153
154     printf(" ");
155     if (do_prefix)
156         printf("--");
157
158     printf("%s %s", opts[1].name, accountinfo->table_name);
159 }
160
161
162 static void
163 print(const void *ip,
164       const struct xt_entry_target *target,
165       int numeric)
166 {
167     print_it (ip, target, 0);
168 }
169
170 /* Saves the union ipt_targinfo in parsable form to stdout. */
171 static void
172 save(const void *ip, const struct xt_entry_target *target)
173 {
174     print_it(ip, target, 1);
175 }
176
177 static
178 struct xtables_target account
179 = {
180     .next          = NULL,
181     .name          = "ACCOUNT",
182     .version       = XTABLES_VERSION,
183     .size          = IPT_ALIGN(sizeof(struct ipt_acc_info)),
184     .userspacesize = offsetof(struct ipt_acc_info, table_nr),
185     .help          = &help,
186     .init          = &init,
187     .parse         = &parse,
188     .final_check   = &final_check,
189     .print         = &print,
190     .save          = &save,
191     .extra_opts    = opts
192 };
193
194 void _init(void)
195 {
196     xtables_register_target(&account);
197 }