~ubuntu-branches/ubuntu/quantal/xtables-addons/quantal

« back to all changes in this revision

Viewing changes to extensions/libxt_DNETMAP.c

  • Committer: Bazaar Package Importer
  • Author(s): Pierre Chifflier
  • Date: 2011-03-28 22:34:22 UTC
  • mfrom: (1.3.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20110328223422-xveu262l46h3mote
Tags: 1.33-1
ImportedĀ UpstreamĀ versionĀ 1.33

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Shared library add-on to iptables to add DNETMAP support.
 
2
 * (C) 2010 Marek Kierdelewicz <marek@koba.pl>
 
3
 *
 
4
 * uses some code from libipt_NETMAP by:
 
5
 * Svenning Soerensen <svenning@post5.tele.dk>
 
6
 */
 
7
 
 
8
#include <stdio.h>
 
9
#include <netdb.h>
 
10
#include <string.h>
 
11
#include <stdlib.h>
 
12
#include <getopt.h>
 
13
#include <xtables.h>
 
14
#include <net/netfilter/nf_nat.h>
 
15
#include "xt_DNETMAP.h"
 
16
 
 
17
#define MODULENAME "DNETMAP"
 
18
 
 
19
static const struct option DNETMAP_opts[] = {
 
20
        {"prefix", 1, NULL, 'p'},
 
21
        {"reuse", 0, NULL, 'r'},
 
22
        {"ttl", 1, NULL, 't'},
 
23
        {.name = NULL}
 
24
};
 
25
 
 
26
static void DNETMAP_help(void)
 
27
{
 
28
        printf(MODULENAME " target options:\n"
 
29
               "  --%s address[/mask]\n"
 
30
               "    Network subnet to map to. If not specified, all existing prefixes are used.\n"
 
31
               "  --%s\n"
 
32
               "    Reuse entry for given prenat-ip from any prefix despite bindings ttl < 0.\n"
 
33
               "  --%s seconds\n"
 
34
               "    Regenerate bindings ttl value to seconds. If negative value is specified,\n"
 
35
               "    bindings ttl is kept unchanged. If not specified then default ttl value (600s)\n"
 
36
               "    is used.\n\n",
 
37
               DNETMAP_opts[0].name, DNETMAP_opts[1].name,
 
38
               DNETMAP_opts[2].name);
 
39
}
 
40
 
 
41
static u_int32_t bits2netmask(int bits)
 
42
{
 
43
        u_int32_t netmask, bm;
 
44
 
 
45
        if (bits >= 32 || bits < 0)
 
46
                return ~0;
 
47
        for (netmask = 0, bm = 0x80000000; bits; bits--, bm >>= 1)
 
48
                netmask |= bm;
 
49
        return htonl(netmask);
 
50
}
 
51
 
 
52
static int netmask2bits(u_int32_t netmask)
 
53
{
 
54
        u_int32_t bm;
 
55
        int bits;
 
56
 
 
57
        netmask = ntohl(netmask);
 
58
        for (bits = 0, bm = 0x80000000; netmask & bm; netmask <<= 1)
 
59
                bits++;
 
60
        if (netmask)
 
61
                return -1;      /* holes in netmask */
 
62
        return bits;
 
63
}
 
64
 
 
65
static void DNETMAP_init(struct xt_entry_target *t)
 
66
{
 
67
        struct xt_DNETMAP_tginfo *tginfo = (void *)&t->data;
 
68
        struct nf_nat_multi_range *mr = &tginfo->prefix;
 
69
 
 
70
        /* Actually, it's 0, but it's ignored at the moment. */
 
71
        mr->rangesize = 1;
 
72
        tginfo->ttl = 0;
 
73
        tginfo->flags = 0;
 
74
}
 
75
 
 
76
/* Parses network address */
 
77
static void parse_prefix(char *arg, struct nf_nat_range *range)
 
78
{
 
79
        char *slash;
 
80
        const struct in_addr *ip;
 
81
        u_int32_t netmask;
 
82
        unsigned int bits;
 
83
 
 
84
        range->flags |= IP_NAT_RANGE_MAP_IPS;
 
85
        slash = strchr(arg, '/');
 
86
        if (slash)
 
87
                *slash = '\0';
 
88
 
 
89
        ip = xtables_numeric_to_ipaddr(arg);
 
90
        if (ip == NULL)
 
91
                xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
 
92
                              arg);
 
93
        range->min_ip = ip->s_addr;
 
94
        if (slash) {
 
95
                if (strchr(slash + 1, '.')) {
 
96
                        ip = xtables_numeric_to_ipmask(slash + 1);
 
97
                        if (ip == NULL)
 
98
                                xtables_error(PARAMETER_PROBLEM,
 
99
                                              "Bad netmask \"%s\"\n",
 
100
                                              slash + 1);
 
101
                        netmask = ip->s_addr;
 
102
                } else {
 
103
                        if (!xtables_strtoui(slash + 1, NULL, &bits, 0, 32))
 
104
                                xtables_error(PARAMETER_PROBLEM,
 
105
                                              "Bad netmask \"%s\"\n",
 
106
                                              slash + 1);
 
107
                        netmask = bits2netmask(bits);
 
108
                }
 
109
                /* Don't allow /0 (/1 is probably insane, too) */
 
110
                if (netmask == 0)
 
111
                        xtables_error(PARAMETER_PROBLEM, "Netmask needed\n");
 
112
                /* Mask should be <= then /16 */
 
113
                if (bits < 16)
 
114
                        xtables_error(PARAMETER_PROBLEM,
 
115
                                      "Max netmask size is /16\n");
 
116
        } else
 
117
                netmask = ~0;
 
118
 
 
119
        if (range->min_ip & ~netmask) {
 
120
                if (slash)
 
121
                        *slash = '/';
 
122
                xtables_error(PARAMETER_PROBLEM, "Bad network address \"%s\"\n",
 
123
                              arg);
 
124
        }
 
125
        range->max_ip = range->min_ip | ~netmask;
 
126
}
 
127
 
 
128
static int DNETMAP_parse(int c, char **argv, int invert, unsigned int *flags,
 
129
                         const void *entry, struct xt_entry_target **target)
 
130
{
 
131
        struct xt_DNETMAP_tginfo *tginfo = (void *)(*target)->data;
 
132
        struct nf_nat_multi_range *mr = &tginfo->prefix;
 
133
        char *end;
 
134
 
 
135
        switch (c) {
 
136
        case 'p':
 
137
                xtables_param_act(XTF_ONLY_ONCE, MODULENAME, "--prefix",
 
138
                                  *flags & XT_DNETMAP_PREFIX);
 
139
                xtables_param_act(XTF_NO_INVERT, MODULENAME, "--prefix",
 
140
                                  invert);
 
141
 
 
142
                /* TO-DO use xtables_ipparse_any instead? */
 
143
                parse_prefix(optarg, &mr->range[0]);
 
144
                *flags |= XT_DNETMAP_PREFIX;
 
145
                tginfo->flags |= XT_DNETMAP_PREFIX;
 
146
                return 1;
 
147
        case 'r':
 
148
                xtables_param_act(XTF_ONLY_ONCE, MODULENAME, "--reuse",
 
149
                                  *flags & XT_DNETMAP_REUSE);
 
150
                xtables_param_act(XTF_NO_INVERT, MODULENAME, "--reuse", invert);
 
151
                *flags |= XT_DNETMAP_REUSE;
 
152
                tginfo->flags |= XT_DNETMAP_REUSE;
 
153
                return 1;
 
154
        case 't':
 
155
                xtables_param_act(XTF_ONLY_ONCE, MODULENAME, "--ttl",
 
156
                                  *flags & XT_DNETMAP_TTL);
 
157
                xtables_param_act(XTF_NO_INVERT, MODULENAME, "--ttl", invert);
 
158
                *flags |= XT_DNETMAP_TTL;
 
159
                tginfo->flags |= XT_DNETMAP_TTL;
 
160
                tginfo->ttl = strtol(optarg, &end, 10);
 
161
                if (*end != '\0')
 
162
                        return 0;
 
163
                return 1;
 
164
        default:
 
165
                return 0;
 
166
        }
 
167
}
 
168
 
 
169
static void DNETMAP_print_addr(const void *ip,
 
170
                               const struct xt_entry_target *target,
 
171
                               int numeric)
 
172
{
 
173
        struct xt_DNETMAP_tginfo *tginfo = (void *)&target->data;
 
174
        const struct nf_nat_multi_range *mr = &tginfo->prefix;
 
175
        const struct nf_nat_range *r = &mr->range[0];
 
176
        struct in_addr a;
 
177
        int bits;
 
178
 
 
179
        a.s_addr = r->min_ip;
 
180
        printf("%s", xtables_ipaddr_to_numeric(&a));
 
181
        a.s_addr = ~(r->min_ip ^ r->max_ip);
 
182
        bits = netmask2bits(a.s_addr);
 
183
        if (bits < 0)
 
184
                printf("/%s", xtables_ipaddr_to_numeric(&a));
 
185
        else
 
186
                printf("/%d", bits);
 
187
}
 
188
 
 
189
static void DNETMAP_print(const void *ip, const struct xt_entry_target *target,
 
190
                          int numeric)
 
191
{
 
192
        struct xt_DNETMAP_tginfo *tginfo = (void *)&target->data;
 
193
        const __u8 *flags = &tginfo->flags;
 
194
 
 
195
        printf(" prefix ");
 
196
        if (*flags & XT_DNETMAP_PREFIX)
 
197
                DNETMAP_print_addr(ip, target, numeric);
 
198
        else
 
199
                printf("any");
 
200
 
 
201
        printf(" reuse %i", (*flags & XT_DNETMAP_REUSE) > 0);
 
202
        if (*flags & XT_DNETMAP_TTL)
 
203
                printf(" ttl %i", tginfo->ttl);
 
204
        else
 
205
                printf(" ttl default");
 
206
}
 
207
 
 
208
static void DNETMAP_save(const void *ip, const struct xt_entry_target *target)
 
209
{
 
210
        struct xt_DNETMAP_tginfo *tginfo = (void *)&target->data;
 
211
        const __u8 *flags = &tginfo->flags;
 
212
 
 
213
        if (*flags & XT_DNETMAP_PREFIX) {
 
214
                printf(" --%s ", DNETMAP_opts[0].name);
 
215
                DNETMAP_print_addr(ip, target, 0);
 
216
        }
 
217
        printf(" --reuse %i ", *flags & XT_DNETMAP_REUSE);
 
218
 
 
219
        /* ommited because default value can change as kernel mod param */
 
220
        if (*flags & XT_DNETMAP_TTL)
 
221
                printf(" --ttl %i ", tginfo->ttl);
 
222
}
 
223
 
 
224
static struct xtables_target dnetmap_tg_reg = {
 
225
        .name          = MODULENAME,
 
226
        .version       = XTABLES_VERSION,
 
227
        .family        = NFPROTO_IPV4,
 
228
        .size          = XT_ALIGN(sizeof(struct xt_DNETMAP_tginfo)),
 
229
        .userspacesize = XT_ALIGN(sizeof(struct xt_DNETMAP_tginfo)),
 
230
        .help          = DNETMAP_help,
 
231
        .init          = DNETMAP_init,
 
232
        .parse         = DNETMAP_parse,
 
233
        .print         = DNETMAP_print,
 
234
        .save          = DNETMAP_save,
 
235
        .extra_opts    = DNETMAP_opts,
 
236
};
 
237
 
 
238
static void _init(void)
 
239
{
 
240
        xtables_register_target(&dnetmap_tg_reg);
 
241
}