1#include <stdio.h> 2#include <netdb.h> 3#include <string.h> 4#include <stdlib.h> 5#include <getopt.h> 6#include <xtables.h> 7#include <limits.h> /* INT_MAX in ip_tables.h */ 8#include <linux/netfilter_ipv4/ip_tables.h> 9#include <net/netfilter/nf_nat.h> 10 11enum { 12 O_TO_PORTS = 0, 13 O_RANDOM, 14}; 15 16static void MASQUERADE_help(void) 17{ 18 printf( 19"MASQUERADE target options:\n" 20" --to-ports <port>[-<port>]\n" 21" Port (range) to map to.\n" 22" --random\n" 23" Randomize source port.\n"); 24} 25 26static const struct xt_option_entry MASQUERADE_opts[] = { 27 {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, 28 {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, 29 XTOPT_TABLEEND, 30}; 31 32static void MASQUERADE_init(struct xt_entry_target *t) 33{ 34 struct nf_nat_multi_range *mr = (struct nf_nat_multi_range *)t->data; 35 36 /* Actually, it's 0, but it's ignored at the moment. */ 37 mr->rangesize = 1; 38} 39 40/* Parses ports */ 41static void 42parse_ports(const char *arg, struct nf_nat_multi_range *mr) 43{ 44 char *end; 45 unsigned int port, maxport; 46 47 mr->range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; 48 49 if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX)) 50 xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg); 51 52 switch (*end) { 53 case '\0': 54 mr->range[0].min.tcp.port 55 = mr->range[0].max.tcp.port 56 = htons(port); 57 return; 58 case '-': 59 if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX)) 60 break; 61 62 if (maxport < port) 63 break; 64 65 mr->range[0].min.tcp.port = htons(port); 66 mr->range[0].max.tcp.port = htons(maxport); 67 return; 68 default: 69 break; 70 } 71 xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg); 72} 73 74static void MASQUERADE_parse(struct xt_option_call *cb) 75{ 76 const struct ipt_entry *entry = cb->xt_entry; 77 int portok; 78 struct nf_nat_multi_range *mr = cb->data; 79 80 if (entry->ip.proto == IPPROTO_TCP 81 || entry->ip.proto == IPPROTO_UDP 82 || entry->ip.proto == IPPROTO_SCTP 83 || entry->ip.proto == IPPROTO_DCCP 84 || entry->ip.proto == IPPROTO_ICMP) 85 portok = 1; 86 else 87 portok = 0; 88 89 xtables_option_parse(cb); 90 switch (cb->entry->id) { 91 case O_TO_PORTS: 92 if (!portok) 93 xtables_error(PARAMETER_PROBLEM, 94 "Need TCP, UDP, SCTP or DCCP with port specification"); 95 parse_ports(cb->arg, mr); 96 break; 97 case O_RANDOM: 98 mr->range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM; 99 break; 100 } 101} 102 103static void 104MASQUERADE_print(const void *ip, const struct xt_entry_target *target, 105 int numeric) 106{ 107 const struct nf_nat_multi_range *mr = (const void *)target->data; 108 const struct nf_nat_range *r = &mr->range[0]; 109 110 if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { 111 printf(" masq ports: "); 112 printf("%hu", ntohs(r->min.tcp.port)); 113 if (r->max.tcp.port != r->min.tcp.port) 114 printf("-%hu", ntohs(r->max.tcp.port)); 115 } 116 117 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM) 118 printf(" random"); 119} 120 121static void 122MASQUERADE_save(const void *ip, const struct xt_entry_target *target) 123{ 124 const struct nf_nat_multi_range *mr = (const void *)target->data; 125 const struct nf_nat_range *r = &mr->range[0]; 126 127 if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { 128 printf(" --to-ports %hu", ntohs(r->min.tcp.port)); 129 if (r->max.tcp.port != r->min.tcp.port) 130 printf("-%hu", ntohs(r->max.tcp.port)); 131 } 132 133 if (r->flags & IP_NAT_RANGE_PROTO_RANDOM) 134 printf(" --random"); 135} 136 137static struct xtables_target masquerade_tg_reg = { 138 .name = "MASQUERADE", 139 .version = XTABLES_VERSION, 140 .family = NFPROTO_IPV4, 141 .size = XT_ALIGN(sizeof(struct nf_nat_multi_range)), 142 .userspacesize = XT_ALIGN(sizeof(struct nf_nat_multi_range)), 143 .help = MASQUERADE_help, 144 .init = MASQUERADE_init, 145 .x6_parse = MASQUERADE_parse, 146 .print = MASQUERADE_print, 147 .save = MASQUERADE_save, 148 .x6_options = MASQUERADE_opts, 149}; 150 151void _init(void) 152{ 153 xtables_register_target(&masquerade_tg_reg); 154} 155