blob: 33f48c93798a86f31b31418f7c634d9e2600cbcd [file] [log] [blame]
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +00001/* Shared library add-on to iptables to add static NAT support.
2 Author: Svenning Soerensen <svenning@post5.tele.dk>
3*/
4
5#include <stdio.h>
6#include <netdb.h>
7#include <string.h>
8#include <stdlib.h>
9#include <getopt.h>
Jan Engelhardt5d9678a2008-11-20 10:15:35 +010010#include <xtables.h>
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +000011#include <linux/netfilter_ipv4/ip_tables.h>
Patrick McHardy40d54752007-04-18 07:00:36 +000012#include <linux/netfilter/nf_nat.h>
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +000013
14#define MODULENAME "NETMAP"
15
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +000016static const struct option NETMAP_opts[] = {
Patrick McHardy500f4832007-09-08 15:59:04 +000017 { "to", 1, NULL, '1' },
Max Kellermann9ee386a2008-01-29 13:48:05 +000018 { .name = NULL }
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +000019};
20
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +000021static void NETMAP_help(void)
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +000022{
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020023 printf(MODULENAME" target options:\n"
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +000024 " --%s address[/mask]\n"
25 " Network address to map to.\n\n",
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020026 NETMAP_opts[0].name);
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +000027}
28
29static u_int32_t
30bits2netmask(int bits)
31{
32 u_int32_t netmask, bm;
33
34 if (bits >= 32 || bits < 0)
35 return(~0);
36 for (netmask = 0, bm = 0x80000000; bits; bits--, bm >>= 1)
37 netmask |= bm;
38 return htonl(netmask);
39}
40
41static int
42netmask2bits(u_int32_t netmask)
43{
44 u_int32_t bm;
45 int bits;
46
47 netmask = ntohl(netmask);
48 for (bits = 0, bm = 0x80000000; netmask & bm; netmask <<= 1)
49 bits++;
50 if (netmask)
51 return -1; /* holes in netmask */
52 return bits;
53}
54
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +000055static void NETMAP_init(struct xt_entry_target *t)
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +000056{
57 struct ip_nat_multi_range *mr = (struct ip_nat_multi_range *)t->data;
58
59 /* Actually, it's 0, but it's ignored at the moment. */
60 mr->rangesize = 1;
61
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +000062}
63
64/* Parses network address */
65static void
66parse_to(char *arg, struct ip_nat_range *range)
67{
68 char *slash;
Jan Engelhardtbd943842008-01-20 13:38:08 +000069 const struct in_addr *ip;
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +000070 u_int32_t netmask;
Harald Welteb4719762001-07-23 02:14:22 +000071 unsigned int bits;
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +000072
73 range->flags |= IP_NAT_RANGE_MAP_IPS;
74 slash = strchr(arg, '/');
75 if (slash)
76 *slash = '\0';
77
Jan Engelhardtbd943842008-01-20 13:38:08 +000078 ip = numeric_to_ipaddr(arg);
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +000079 if (!ip)
80 exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
81 arg);
82 range->min_ip = ip->s_addr;
83 if (slash) {
84 if (strchr(slash+1, '.')) {
Jan Engelhardtbd943842008-01-20 13:38:08 +000085 ip = numeric_to_ipmask(slash+1);
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +000086 if (!ip)
87 exit_error(PARAMETER_PROBLEM, "Bad netmask `%s'\n",
88 slash+1);
89 netmask = ip->s_addr;
90 }
91 else {
Jan Engelhardt5f2922c2009-01-27 18:43:01 +010092 if (!xtables_strtoui(slash+1, NULL, &bits, 0, 32))
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +000093 exit_error(PARAMETER_PROBLEM, "Bad netmask `%s'\n",
94 slash+1);
95 netmask = bits2netmask(bits);
96 }
97 /* Don't allow /0 (/1 is probably insane, too) */
98 if (netmask == 0)
99 exit_error(PARAMETER_PROBLEM, "Netmask needed\n");
100 }
101 else
102 netmask = ~0;
103
104 if (range->min_ip & ~netmask) {
105 if (slash)
106 *slash = '/';
107 exit_error(PARAMETER_PROBLEM, "Bad network address `%s'\n",
108 arg);
109 }
110 range->max_ip = range->min_ip | ~netmask;
111}
112
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000113static int NETMAP_parse(int c, char **argv, int invert, unsigned int *flags,
114 const void *entry, struct xt_entry_target **target)
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +0000115{
116 struct ip_nat_multi_range *mr
117 = (struct ip_nat_multi_range *)(*target)->data;
118
119 switch (c) {
120 case '1':
Harald Welteb77f1da2002-03-14 11:35:58 +0000121 if (check_inverse(optarg, &invert, NULL, 0))
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +0000122 exit_error(PARAMETER_PROBLEM,
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000123 "Unexpected `!' after --%s", NETMAP_opts[0].name);
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +0000124
125 parse_to(optarg, &mr->range[0]);
126 *flags = 1;
127 return 1;
128
129 default:
130 return 0;
131 }
132}
133
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000134static void NETMAP_check(unsigned int flags)
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +0000135{
136 if (!flags)
137 exit_error(PARAMETER_PROBLEM,
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000138 MODULENAME" needs --%s", NETMAP_opts[0].name);
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +0000139}
140
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000141static void NETMAP_print(const void *ip, const struct xt_entry_target *target,
142 int numeric)
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +0000143{
144 struct ip_nat_multi_range *mr
145 = (struct ip_nat_multi_range *)target->data;
146 struct ip_nat_range *r = &mr->range[0];
147 struct in_addr a;
148 int bits;
149
150 a.s_addr = r->min_ip;
Jan Engelhardte44ea7f2009-01-30 03:55:09 +0100151 printf("%s", xtables_ipaddr_to_numeric(&a));
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +0000152 a.s_addr = ~(r->min_ip ^ r->max_ip);
153 bits = netmask2bits(a.s_addr);
154 if (bits < 0)
Jan Engelhardte44ea7f2009-01-30 03:55:09 +0100155 printf("/%s", xtables_ipaddr_to_numeric(&a));
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +0000156 else
157 printf("/%d", bits);
158}
159
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000160static void NETMAP_save(const void *ip, const struct xt_entry_target *target)
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +0000161{
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000162 printf("--%s ", NETMAP_opts[0].name);
163 NETMAP_print(ip, target, 0);
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +0000164}
165
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200166static struct xtables_target netmap_tg_reg = {
Pablo Neira8caee8b2004-12-28 13:11:59 +0000167 .name = MODULENAME,
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200168 .version = XTABLES_VERSION,
Jan Engelhardt03d99482008-11-18 12:27:54 +0100169 .family = NFPROTO_IPV4,
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200170 .size = XT_ALIGN(sizeof(struct ip_nat_multi_range)),
171 .userspacesize = XT_ALIGN(sizeof(struct ip_nat_multi_range)),
Jan Engelhardt1d5b63d2007-10-04 16:29:00 +0000172 .help = NETMAP_help,
173 .init = NETMAP_init,
174 .parse = NETMAP_parse,
175 .final_check = NETMAP_check,
176 .print = NETMAP_print,
177 .save = NETMAP_save,
178 .extra_opts = NETMAP_opts,
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +0000179};
180
181void _init(void)
182{
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200183 xtables_register_target(&netmap_tg_reg);
Svenning Soerensenb2f9cb72001-05-03 01:15:09 +0000184}