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