libipt_DNAT.c revision 73866357e4a7a0fdc1b293bf8863fee2bd56da9e
1e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Shared library add-on to iptables to add destination-NAT support. */ 232b8e61e4e5bd405d9ad07bf9468498dfbb19f9eJan Engelhardt#include <stdbool.h> 3e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <stdio.h> 4e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <netdb.h> 5e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <string.h> 6e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <stdlib.h> 7e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <getopt.h> 85d9678ad3eabc34ac40dfe055d7f6a8e44445a5aJan Engelhardt#include <xtables.h> 9afe6b357db60c7d70379a27360c10a352bf55203Jan Engelhardt#include <iptables.h> /* get_kernel_version */ 104e41854423b529d3107c23b85434d50a75d08057Jan Engelhardt#include <limits.h> /* INT_MAX in ip_tables.h */ 11e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <linux/netfilter_ipv4/ip_tables.h> 12978e27e8f8c2e49d0528c6c4ae3a56627fbe8492Jan Engelhardt#include <net/netfilter/nf_nat.h> 13e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 14ef399a3033aa860ea1653b9c4306c0e78777e981Patrick McHardy#define IPT_DNAT_OPT_DEST 0x1 15ef399a3033aa860ea1653b9c4306c0e78777e981Patrick McHardy#define IPT_DNAT_OPT_RANDOM 0x2 16ef399a3033aa860ea1653b9c4306c0e78777e981Patrick McHardy 17e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Dest NAT data consists of a multi-range, indicating where to map 18e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher to. */ 19e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstruct ipt_natinfo 20e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 21193df8ee3507f0c02762c88a16916c4ea950bd99Yasuyuki KOZAKAI struct xt_entry_target t; 22978e27e8f8c2e49d0528c6c4ae3a56627fbe8492Jan Engelhardt struct nf_nat_multi_range mr; 23e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}; 24e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 251d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void DNAT_help(void) 26e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 27e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf( 288b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt"DNAT target options:\n" 29e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher" --to-destination <ipaddr>[-<ipaddr>][:port-port]\n" 30e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher" Address to map destination to.\n" 31467fa9fe70f08342a50b859ddd431c848a956679Patrick McHardy"[--random] [--persistent]\n"); 32e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 33e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 341d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic const struct option DNAT_opts[] = { 3532b8e61e4e5bd405d9ad07bf9468498dfbb19f9eJan Engelhardt {.name = "to-destination", .has_arg = true, .val = '1'}, 3632b8e61e4e5bd405d9ad07bf9468498dfbb19f9eJan Engelhardt {.name = "random", .has_arg = false, .val = '2'}, 3732b8e61e4e5bd405d9ad07bf9468498dfbb19f9eJan Engelhardt {.name = "persistent", .has_arg = false, .val = '3'}, 3832b8e61e4e5bd405d9ad07bf9468498dfbb19f9eJan Engelhardt XT_GETOPT_TABLEEND, 39e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}; 40e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 41e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic struct ipt_natinfo * 42978e27e8f8c2e49d0528c6c4ae3a56627fbe8492Jan Engelhardtappend_range(struct ipt_natinfo *info, const struct nf_nat_range *range) 43e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 44e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int size; 45e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 46e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* One rangesize already in struct ipt_natinfo */ 478b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt size = XT_ALIGN(sizeof(*info) + info->mr.rangesize * sizeof(*range)); 48e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 49e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher info = realloc(info, size); 50e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (!info) 511829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(OTHER_PROBLEM, "Out of memory\n"); 52e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 53228e98dd6303af11925235af4cf3c3ec450f3f41Rusty Russell info->t.u.target_size = size; 54e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher info->mr.range[info->mr.rangesize] = *range; 55e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher info->mr.rangesize++; 56e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 57e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return info; 58e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 59e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 60e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher/* Ranges expected in network order. */ 61193df8ee3507f0c02762c88a16916c4ea950bd99Yasuyuki KOZAKAIstatic struct xt_entry_target * 62e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherparse_to(char *arg, int portok, struct ipt_natinfo *info) 63e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 64978e27e8f8c2e49d0528c6c4ae3a56627fbe8492Jan Engelhardt struct nf_nat_range range; 653fb61f3d4a194ba989fe8470f16064f20e59e3bcPhil Oester char *colon, *dash, *error; 66bd9438420d92c41a5cf20a53b7a18d3ddea4216dJan Engelhardt const struct in_addr *ip; 67e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 68e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher memset(&range, 0, sizeof(range)); 69e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher colon = strchr(arg, ':'); 70e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 71e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (colon) { 72e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher int port; 73e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 74e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (!portok) 751829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(PARAMETER_PROBLEM, 765a942f9501f7ce287e1c37c553eb02a1e269e081Patrick McHardy "Need TCP, UDP, SCTP or DCCP with port specification"); 77e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 78e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED; 79e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 80e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher port = atoi(colon+1); 81a3a9c0d3e3d9df70c5ea2e64ef792e194dbfbde7Yasuyuki KOZAKAI if (port <= 0 || port > 65535) 821829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(PARAMETER_PROBLEM, 83e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher "Port `%s' not valid\n", colon+1); 84e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 853fb61f3d4a194ba989fe8470f16064f20e59e3bcPhil Oester error = strchr(colon+1, ':'); 863fb61f3d4a194ba989fe8470f16064f20e59e3bcPhil Oester if (error) 871829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(PARAMETER_PROBLEM, 883fb61f3d4a194ba989fe8470f16064f20e59e3bcPhil Oester "Invalid port:port syntax - use dash\n"); 893fb61f3d4a194ba989fe8470f16064f20e59e3bcPhil Oester 90e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher dash = strchr(colon, '-'); 91e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (!dash) { 92e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher range.min.tcp.port 93e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher = range.max.tcp.port 94e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher = htons(port); 95e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } else { 96e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher int maxport; 97e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 98e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher maxport = atoi(dash + 1); 99a3a9c0d3e3d9df70c5ea2e64ef792e194dbfbde7Yasuyuki KOZAKAI if (maxport <= 0 || maxport > 65535) 1001829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(PARAMETER_PROBLEM, 101e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher "Port `%s' not valid\n", dash+1); 102e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (maxport < port) 103e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* People are stupid. */ 1041829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(PARAMETER_PROBLEM, 105e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher "Port range `%s' funky\n", colon+1); 106e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher range.min.tcp.port = htons(port); 107e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher range.max.tcp.port = htons(maxport); 108e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 109e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher /* Starts with a colon? No IP info...*/ 110e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (colon == arg) 111e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return &(append_range(info, &range)->t); 112e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *colon = '\0'; 113e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 114e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 115e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher range.flags |= IP_NAT_RANGE_MAP_IPS; 116e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher dash = strchr(arg, '-'); 117e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (colon && dash && dash > colon) 118e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher dash = NULL; 119e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 120e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (dash) 121e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *dash = '\0'; 122e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1231e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt ip = xtables_numeric_to_ipaddr(arg); 124e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (!ip) 1251829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", 126e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher arg); 127e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher range.min_ip = ip->s_addr; 128e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (dash) { 1291e01b0b82f70b0b11dcfbced485dbe7aeac4fb8cJan Engelhardt ip = xtables_numeric_to_ipaddr(dash+1); 130e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (!ip) 1311829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", 132e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher dash+1); 133e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher range.max_ip = ip->s_addr; 134e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } else 135e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher range.max_ip = range.min_ip; 136e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 137e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return &(append_range(info, &range)->t); 138e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 139e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1401d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic int DNAT_parse(int c, char **argv, int invert, unsigned int *flags, 1411d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt const void *e, struct xt_entry_target **target) 142e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 143ac8b2718daf8a79a59b181f6e62495f307ae86b9Yasuyuki KOZAKAI const struct ipt_entry *entry = e; 144e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct ipt_natinfo *info = (void *)*target; 145e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher int portok; 146e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 147e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (entry->ip.proto == IPPROTO_TCP 14836d870c76621b94d51816d09eb8fd05e0fb0a0abPatrick McHardy || entry->ip.proto == IPPROTO_UDP 1495a942f9501f7ce287e1c37c553eb02a1e269e081Patrick McHardy || entry->ip.proto == IPPROTO_SCTP 1505a942f9501f7ce287e1c37c553eb02a1e269e081Patrick McHardy || entry->ip.proto == IPPROTO_DCCP 15136d870c76621b94d51816d09eb8fd05e0fb0a0abPatrick McHardy || entry->ip.proto == IPPROTO_ICMP) 152e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher portok = 1; 153e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher else 154e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher portok = 0; 155e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 156e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher switch (c) { 157e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher case '1': 158bf97128c7262f17a02fec41cdae75b472ba77f88Jan Engelhardt if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) 1591829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(PARAMETER_PROBLEM, 160e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher "Unexpected `!' after --to-destination"); 161e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 162596c69007acb569843391e4c98dc21d6f2336e7bPatrick McHardy if (*flags & IPT_DNAT_OPT_DEST) { 1638cf65913bb6353bf0e92eab0669d1c4c53b43623Phil Oester if (!kernel_version) 1648cf65913bb6353bf0e92eab0669d1c4c53b43623Phil Oester get_kernel_version(); 1658cf65913bb6353bf0e92eab0669d1c4c53b43623Phil Oester if (kernel_version > LINUX_VERSION(2, 6, 10)) 1661829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(PARAMETER_PROBLEM, 1678cf65913bb6353bf0e92eab0669d1c4c53b43623Phil Oester "Multiple --to-destination not supported"); 1688cf65913bb6353bf0e92eab0669d1c4c53b43623Phil Oester } 169e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher *target = parse_to(optarg, portok, info); 170ef399a3033aa860ea1653b9c4306c0e78777e981Patrick McHardy /* WTF do we need this for?? */ 171ef399a3033aa860ea1653b9c4306c0e78777e981Patrick McHardy if (*flags & IPT_DNAT_OPT_RANDOM) 172ef399a3033aa860ea1653b9c4306c0e78777e981Patrick McHardy info->mr.range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM; 173ef399a3033aa860ea1653b9c4306c0e78777e981Patrick McHardy *flags |= IPT_DNAT_OPT_DEST; 174e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher return 1; 175e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 176ef399a3033aa860ea1653b9c4306c0e78777e981Patrick McHardy case '2': 177ef399a3033aa860ea1653b9c4306c0e78777e981Patrick McHardy if (*flags & IPT_DNAT_OPT_DEST) { 178ef399a3033aa860ea1653b9c4306c0e78777e981Patrick McHardy info->mr.range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM; 179ef399a3033aa860ea1653b9c4306c0e78777e981Patrick McHardy *flags |= IPT_DNAT_OPT_RANDOM; 180ef399a3033aa860ea1653b9c4306c0e78777e981Patrick McHardy } else 181ef399a3033aa860ea1653b9c4306c0e78777e981Patrick McHardy *flags |= IPT_DNAT_OPT_RANDOM; 18275b4b2081522ab2f680ca0edf2242bc6f28a0ef7Tom Eastep return 1; 183467fa9fe70f08342a50b859ddd431c848a956679Patrick McHardy 184467fa9fe70f08342a50b859ddd431c848a956679Patrick McHardy case '3': 185467fa9fe70f08342a50b859ddd431c848a956679Patrick McHardy info->mr.range[0].flags |= IP_NAT_RANGE_PERSISTENT; 186467fa9fe70f08342a50b859ddd431c848a956679Patrick McHardy return 1; 187e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 188d09b6d591ca7d7d7575cb6aa20384c9830f777abJan Engelhardt return 0; 189e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 190e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 1911d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void DNAT_check(unsigned int flags) 192e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 193e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (!flags) 1941829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt xtables_error(PARAMETER_PROBLEM, 195e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher "You must specify --to-destination"); 196e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 197e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 198978e27e8f8c2e49d0528c6c4ae3a56627fbe8492Jan Engelhardtstatic void print_range(const struct nf_nat_range *r) 199e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 200e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (r->flags & IP_NAT_RANGE_MAP_IPS) { 201e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher struct in_addr a; 202e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 203e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher a.s_addr = r->min_ip; 204e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt printf("%s", xtables_ipaddr_to_numeric(&a)); 205e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (r->max_ip != r->min_ip) { 206e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher a.s_addr = r->max_ip; 207e44ea7faa17c10c68f14f5338a7cc6e3291a0ce7Jan Engelhardt printf("-%s", xtables_ipaddr_to_numeric(&a)); 208e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 209e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 210e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { 211e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf(":"); 212e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf("%hu", ntohs(r->min.tcp.port)); 213e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher if (r->max.tcp.port != r->min.tcp.port) 214e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher printf("-%hu", ntohs(r->max.tcp.port)); 215e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 216e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 217e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 2181d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void DNAT_print(const void *ip, const struct xt_entry_target *target, 2191d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt int numeric) 220e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 22169f564e3890976461de0016cd81171ff8bfa8353Jan Engelhardt const struct ipt_natinfo *info = (const void *)target; 222e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int i = 0; 223e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 22473866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt printf(" to:"); 225e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher for (i = 0; i < info->mr.rangesize; i++) { 226e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher print_range(&info->mr.range[i]); 227ef399a3033aa860ea1653b9c4306c0e78777e981Patrick McHardy if (info->mr.range[i].flags & IP_NAT_RANGE_PROTO_RANDOM) 22873866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt printf(" random"); 229467fa9fe70f08342a50b859ddd431c848a956679Patrick McHardy if (info->mr.range[i].flags & IP_NAT_RANGE_PERSISTENT) 23073866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt printf(" persistent"); 231e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 232e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 233e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 2341d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void DNAT_save(const void *ip, const struct xt_entry_target *target) 235e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 23669f564e3890976461de0016cd81171ff8bfa8353Jan Engelhardt const struct ipt_natinfo *info = (const void *)target; 237e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher unsigned int i = 0; 238e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 239e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher for (i = 0; i < info->mr.rangesize; i++) { 24073866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt printf(" --to-destination "); 241e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher print_range(&info->mr.range[i]); 242ef399a3033aa860ea1653b9c4306c0e78777e981Patrick McHardy if (info->mr.range[i].flags & IP_NAT_RANGE_PROTO_RANDOM) 24373866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt printf(" --random"); 244467fa9fe70f08342a50b859ddd431c848a956679Patrick McHardy if (info->mr.range[i].flags & IP_NAT_RANGE_PERSISTENT) 24573866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt printf(" --persistent"); 246e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher } 247e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 248e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 2498b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardtstatic struct xtables_target dnat_tg_reg = { 2508caee8b9e34fed4562fcff553197c161fc9d9979Pablo Neira .name = "DNAT", 2518b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt .version = XTABLES_VERSION, 25203d99486d8283552705b58dc55b6085dffc38792Jan Engelhardt .family = NFPROTO_IPV4, 253978e27e8f8c2e49d0528c6c4ae3a56627fbe8492Jan Engelhardt .size = XT_ALIGN(sizeof(struct nf_nat_multi_range)), 254978e27e8f8c2e49d0528c6c4ae3a56627fbe8492Jan Engelhardt .userspacesize = XT_ALIGN(sizeof(struct nf_nat_multi_range)), 2551d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .help = DNAT_help, 2561d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .parse = DNAT_parse, 2571d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .final_check = DNAT_check, 2581d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .print = DNAT_print, 2591d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .save = DNAT_save, 2601d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt .extra_opts = DNAT_opts, 261e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}; 262e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher 263e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchervoid _init(void) 264e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{ 2658b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt xtables_register_target(&dnat_tg_reg); 266e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher} 267