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 11 enum { 12 O_TO_PORTS = 0, 13 O_RANDOM, 14 }; 15 16 static 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 26 static 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 32 static 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 */ 41 static void 42 parse_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 74 static 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 103 static void 104 MASQUERADE_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 121 static void 122 MASQUERADE_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 137 static 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 151 void _init(void) 152 { 153 xtables_register_target(&masquerade_tg_reg); 154 } 155