lin
2025-08-21 57113df3a0e2be01232281fad9a5f2c060567981
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/* Shared library add-on to iptables to add static NAT support.
   Author: Svenning Soerensen <svenning@post5.tele.dk>
*/
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <xtables.h>
#include <linux/netfilter/nf_nat.h>
 
#define MODULENAME "NETMAP"
 
enum {
   O_TO = 0,
};
 
static const struct xt_option_entry NETMAP_opts[] = {
   {.name = "to", .id = O_TO, .type = XTTYPE_HOSTMASK,
    .flags = XTOPT_MAND},
   XTOPT_TABLEEND,
};
 
static void NETMAP_help(void)
{
   printf(MODULENAME" target options:\n"
          "  --%s address[/mask]\n"
          "                Network address to map to.\n\n",
          NETMAP_opts[0].name);
}
 
static int
netmask2bits(uint32_t netmask)
{
   uint32_t bm;
   int bits;
 
   netmask = ntohl(netmask);
   for (bits = 0, bm = 0x80000000; netmask & bm; netmask <<= 1)
       bits++;
   if (netmask)
       return -1; /* holes in netmask */
   return bits;
}
 
static void NETMAP_init(struct xt_entry_target *t)
{
   struct nf_nat_ipv4_multi_range_compat *mr = (struct nf_nat_ipv4_multi_range_compat *)t->data;
 
   /* Actually, it's 0, but it's ignored at the moment. */
   mr->rangesize = 1;
}
 
static void NETMAP_parse(struct xt_option_call *cb)
{
   struct nf_nat_ipv4_multi_range_compat *mr = cb->data;
   struct nf_nat_ipv4_range *range = &mr->range[0];
 
   xtables_option_parse(cb);
   range->flags |= NF_NAT_RANGE_MAP_IPS;
   range->min_ip = cb->val.haddr.ip & cb->val.hmask.ip;
   range->max_ip = range->min_ip | ~cb->val.hmask.ip;
}
 
static void __NETMAP_print(const void *ip, const struct xt_entry_target *target,
              int numeric)
{
   const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data;
   const struct nf_nat_ipv4_range *r = &mr->range[0];
   struct in_addr a;
   int bits;
 
   a.s_addr = r->min_ip;
   printf("%s", xtables_ipaddr_to_numeric(&a));
   a.s_addr = ~(r->min_ip ^ r->max_ip);
   bits = netmask2bits(a.s_addr);
   if (bits < 0)
       printf("/%s", xtables_ipaddr_to_numeric(&a));
   else
       printf("/%d", bits);
}
 
static void NETMAP_print(const void *ip, const struct xt_entry_target *target,
            int numeric)
{
   printf(" to:");
   __NETMAP_print(ip, target, numeric);
}
 
static void NETMAP_save(const void *ip, const struct xt_entry_target *target)
{
   printf(" --%s ", NETMAP_opts[0].name);
   __NETMAP_print(ip, target, 0);
}
 
static struct xtables_target netmap_tg_reg = {
   .name        = MODULENAME,
   .version    = XTABLES_VERSION,
   .family        = NFPROTO_IPV4,
   .size        = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
   .userspacesize    = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)),
   .help        = NETMAP_help,
   .init        = NETMAP_init,
   .x6_parse    = NETMAP_parse,
   .print        = NETMAP_print,
   .save        = NETMAP_save,
   .x6_options    = NETMAP_opts,
};
 
void _init(void)
{
   xtables_register_target(&netmap_tg_reg);
}