libipt_NETMAP.c revision 8caee8b9e34fed4562fcff553197c161fc9d9979
1/* 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> 10#include <iptables.h> 11#include <linux/netfilter_ipv4/ip_tables.h> 12#include <linux/netfilter_ipv4/ip_nat_rule.h> 13 14#define MODULENAME "NETMAP" 15 16static struct option opts[] = { 17 { "to", 1, 0, '1' }, 18 { 0 } 19}; 20 21/* Function which prints out usage message. */ 22static void 23help(void) 24{ 25 printf(MODULENAME" v%s options:\n" 26 " --%s address[/mask]\n" 27 " Network address to map to.\n\n", 28 IPTABLES_VERSION, opts[0].name); 29} 30 31static u_int32_t 32bits2netmask(int bits) 33{ 34 u_int32_t netmask, bm; 35 36 if (bits >= 32 || bits < 0) 37 return(~0); 38 for (netmask = 0, bm = 0x80000000; bits; bits--, bm >>= 1) 39 netmask |= bm; 40 return htonl(netmask); 41} 42 43static int 44netmask2bits(u_int32_t netmask) 45{ 46 u_int32_t bm; 47 int bits; 48 49 netmask = ntohl(netmask); 50 for (bits = 0, bm = 0x80000000; netmask & bm; netmask <<= 1) 51 bits++; 52 if (netmask) 53 return -1; /* holes in netmask */ 54 return bits; 55} 56 57/* Initialize the target. */ 58static void 59init(struct ipt_entry_target *t, unsigned int *nfcache) 60{ 61 struct ip_nat_multi_range *mr = (struct ip_nat_multi_range *)t->data; 62 63 /* Actually, it's 0, but it's ignored at the moment. */ 64 mr->rangesize = 1; 65 66 /* Can't cache this */ 67 *nfcache |= NFC_UNKNOWN; 68} 69 70/* Parses network address */ 71static void 72parse_to(char *arg, struct ip_nat_range *range) 73{ 74 char *slash; 75 struct in_addr *ip; 76 u_int32_t netmask; 77 unsigned int bits; 78 79 range->flags |= IP_NAT_RANGE_MAP_IPS; 80 slash = strchr(arg, '/'); 81 if (slash) 82 *slash = '\0'; 83 84 ip = dotted_to_addr(arg); 85 if (!ip) 86 exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n", 87 arg); 88 range->min_ip = ip->s_addr; 89 if (slash) { 90 if (strchr(slash+1, '.')) { 91 ip = dotted_to_addr(slash+1); 92 if (!ip) 93 exit_error(PARAMETER_PROBLEM, "Bad netmask `%s'\n", 94 slash+1); 95 netmask = ip->s_addr; 96 } 97 else { 98 if (string_to_number(slash+1, 0, 32, &bits) == -1) 99 exit_error(PARAMETER_PROBLEM, "Bad netmask `%s'\n", 100 slash+1); 101 netmask = bits2netmask(bits); 102 } 103 /* Don't allow /0 (/1 is probably insane, too) */ 104 if (netmask == 0) 105 exit_error(PARAMETER_PROBLEM, "Netmask needed\n"); 106 } 107 else 108 netmask = ~0; 109 110 if (range->min_ip & ~netmask) { 111 if (slash) 112 *slash = '/'; 113 exit_error(PARAMETER_PROBLEM, "Bad network address `%s'\n", 114 arg); 115 } 116 range->max_ip = range->min_ip | ~netmask; 117} 118 119/* Function which parses command options; returns true if it 120 ate an option */ 121static int 122parse(int c, char **argv, int invert, unsigned int *flags, 123 const struct ipt_entry *entry, 124 struct ipt_entry_target **target) 125{ 126 struct ip_nat_multi_range *mr 127 = (struct ip_nat_multi_range *)(*target)->data; 128 129 switch (c) { 130 case '1': 131 if (check_inverse(optarg, &invert, NULL, 0)) 132 exit_error(PARAMETER_PROBLEM, 133 "Unexpected `!' after --%s", opts[0].name); 134 135 parse_to(optarg, &mr->range[0]); 136 *flags = 1; 137 return 1; 138 139 default: 140 return 0; 141 } 142} 143 144/* Final check; need --to */ 145static void final_check(unsigned int flags) 146{ 147 if (!flags) 148 exit_error(PARAMETER_PROBLEM, 149 MODULENAME" needs --%s", opts[0].name); 150} 151 152/* Prints out the targinfo. */ 153static void 154print(const struct ipt_ip *ip, 155 const struct ipt_entry_target *target, 156 int numeric) 157{ 158 struct ip_nat_multi_range *mr 159 = (struct ip_nat_multi_range *)target->data; 160 struct ip_nat_range *r = &mr->range[0]; 161 struct in_addr a; 162 int bits; 163 164 a.s_addr = r->min_ip; 165 printf("%s", addr_to_dotted(&a)); 166 a.s_addr = ~(r->min_ip ^ r->max_ip); 167 bits = netmask2bits(a.s_addr); 168 if (bits < 0) 169 printf("/%s", addr_to_dotted(&a)); 170 else 171 printf("/%d", bits); 172} 173 174/* Saves the targinfo in parsable form to stdout. */ 175static void 176save(const struct ipt_ip *ip, const struct ipt_entry_target *target) 177{ 178 printf("--%s ", opts[0].name); 179 print(ip, target, 0); 180} 181 182static struct iptables_target target_module = { 183 .next = NULL, 184 .name = MODULENAME, 185 .version = IPTABLES_VERSION, 186 .size = IPT_ALIGN(sizeof(struct ip_nat_multi_range)), 187 .userspacesize = IPT_ALIGN(sizeof(struct ip_nat_multi_range)), 188 .help = &help, 189 .init = &init, 190 .parse = &parse, 191 .final_check = &final_check, 192 .print = &print, 193 .save = &save, 194 .extra_opts = opts 195}; 196 197void _init(void) 198{ 199 register_target(&target_module); 200} 201 202