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/nf_nat.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} 67 68/* Parses network address */ 69static void 70parse_to(char *arg, struct ip_nat_range *range) 71{ 72 char *slash; 73 struct in_addr *ip; 74 u_int32_t netmask; 75 unsigned int bits; 76 77 range->flags |= IP_NAT_RANGE_MAP_IPS; 78 slash = strchr(arg, '/'); 79 if (slash) 80 *slash = '\0'; 81 82 ip = dotted_to_addr(arg); 83 if (!ip) 84 exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n", 85 arg); 86 range->min_ip = ip->s_addr; 87 if (slash) { 88 if (strchr(slash+1, '.')) { 89 ip = dotted_to_mask(slash+1); 90 if (!ip) 91 exit_error(PARAMETER_PROBLEM, "Bad netmask `%s'\n", 92 slash+1); 93 netmask = ip->s_addr; 94 } 95 else { 96 if (string_to_number(slash+1, 0, 32, &bits) == -1) 97 exit_error(PARAMETER_PROBLEM, "Bad netmask `%s'\n", 98 slash+1); 99 netmask = bits2netmask(bits); 100 } 101 /* Don't allow /0 (/1 is probably insane, too) */ 102 if (netmask == 0) 103 exit_error(PARAMETER_PROBLEM, "Netmask needed\n"); 104 } 105 else 106 netmask = ~0; 107 108 if (range->min_ip & ~netmask) { 109 if (slash) 110 *slash = '/'; 111 exit_error(PARAMETER_PROBLEM, "Bad network address `%s'\n", 112 arg); 113 } 114 range->max_ip = range->min_ip | ~netmask; 115} 116 117/* Function which parses command options; returns true if it 118 ate an option */ 119static int 120parse(int c, char **argv, int invert, unsigned int *flags, 121 const struct ipt_entry *entry, 122 struct ipt_entry_target **target) 123{ 124 struct ip_nat_multi_range *mr 125 = (struct ip_nat_multi_range *)(*target)->data; 126 127 switch (c) { 128 case '1': 129 if (check_inverse(optarg, &invert, NULL, 0)) 130 exit_error(PARAMETER_PROBLEM, 131 "Unexpected `!' after --%s", opts[0].name); 132 133 parse_to(optarg, &mr->range[0]); 134 *flags = 1; 135 return 1; 136 137 default: 138 return 0; 139 } 140} 141 142/* Final check; need --to */ 143static void final_check(unsigned int flags) 144{ 145 if (!flags) 146 exit_error(PARAMETER_PROBLEM, 147 MODULENAME" needs --%s", opts[0].name); 148} 149 150/* Prints out the targinfo. */ 151static void 152print(const struct ipt_ip *ip, 153 const struct ipt_entry_target *target, 154 int numeric) 155{ 156 struct ip_nat_multi_range *mr 157 = (struct ip_nat_multi_range *)target->data; 158 struct ip_nat_range *r = &mr->range[0]; 159 struct in_addr a; 160 int bits; 161 162 a.s_addr = r->min_ip; 163 printf("%s", addr_to_dotted(&a)); 164 a.s_addr = ~(r->min_ip ^ r->max_ip); 165 bits = netmask2bits(a.s_addr); 166 if (bits < 0) 167 printf("/%s", addr_to_dotted(&a)); 168 else 169 printf("/%d", bits); 170} 171 172/* Saves the targinfo in parsable form to stdout. */ 173static void 174save(const struct ipt_ip *ip, const struct ipt_entry_target *target) 175{ 176 printf("--%s ", opts[0].name); 177 print(ip, target, 0); 178} 179 180static struct iptables_target target_module = { 181 .next = NULL, 182 .name = MODULENAME, 183 .version = IPTABLES_VERSION, 184 .size = IPT_ALIGN(sizeof(struct ip_nat_multi_range)), 185 .userspacesize = IPT_ALIGN(sizeof(struct ip_nat_multi_range)), 186 .help = &help, 187 .init = &init, 188 .parse = &parse, 189 .final_check = &final_check, 190 .print = &print, 191 .save = &save, 192 .extra_opts = opts 193}; 194 195void _init(void) 196{ 197 register_target(&target_module); 198} 199 200