libipt_MASQUERADE.c revision 7278461dfad72e2008585dd0bac0e889e5bba99e
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/* Shared library add-on to iptables to add masquerade support. */ 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com#include <stdio.h> 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com#include <netdb.h> 4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com#include <string.h> 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com#include <stdlib.h> 6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com#include <getopt.h> 7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com#include <xtables.h> 870149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com#include <limits.h> /* INT_MAX in ip_tables.h */ 970149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com#include <linux/netfilter_ipv4/ip_tables.h> 10bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com#include <net/netfilter/nf_nat.h> 11bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com 12bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.comstatic void MASQUERADE_help(void) 13bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com{ 14bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com printf( 15bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com"MASQUERADE target options:\n" 16bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com" --to-ports <port>[-<port>]\n" 17bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com" Port (range) to map to.\n" 18bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com" --random\n" 19bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com" Randomize source port.\n"); 20bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com} 21bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com 22bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.comstatic const struct option MASQUERADE_opts[] = { 23bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com { "to-ports", 1, NULL, '1' }, 24bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com { "random", 0, NULL, '2' }, 2570149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com { .name = NULL } 2670149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com}; 2770149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com 2870149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.comstatic void MASQUERADE_init(struct xt_entry_target *t) 2970149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com{ 3070149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com struct nf_nat_multi_range *mr = (struct nf_nat_multi_range *)t->data; 31160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com 32160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com /* Actually, it's 0, but it's ignored at the moment. */ 33160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com mr->rangesize = 1; 34160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com 35160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com} 36160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com 37160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com/* Parses ports */ 38fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.comstatic void 39bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.comparse_ports(const char *arg, struct nf_nat_multi_range *mr) 40bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com{ 41bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com char *end; 42bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com unsigned int port, maxport; 4370149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com 4470149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com mr->range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; 4570149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com 4670149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX)) 4770149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg); 4870149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com 4970149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com switch (*end) { 5070149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com case '\0': 5170149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com mr->range[0].min.tcp.port 52160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com = mr->range[0].max.tcp.port 53160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com = htons(port); 54160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com return; 55160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com case '-': 56160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX)) 57160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com break; 58160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com 59160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com if (maxport < port) 6070149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com break; 6170149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com 6270149060a74bb212e67eb140be7cbf97a7cd36a8reed@android.com mr->range[0].min.tcp.port = htons(port); 63e28ff55d980d2992618b6b721c848aba96cf759areed@android.com mr->range[0].max.tcp.port = htons(maxport); 64e28ff55d980d2992618b6b721c848aba96cf759areed@android.com return; 65a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com default: 66a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com break; 67a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com } 68a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg); 69a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com} 70a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com 71a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.comstatic int MASQUERADE_parse(int c, char **argv, int invert, unsigned int *flags, 72a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com const void *e, struct xt_entry_target **target) 73a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com{ 74a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com const struct ipt_entry *entry = e; 75a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com int portok; 76a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com struct nf_nat_multi_range *mr 77e28ff55d980d2992618b6b721c848aba96cf759areed@android.com = (struct nf_nat_multi_range *)(*target)->data; 78e28ff55d980d2992618b6b721c848aba96cf759areed@android.com 79e28ff55d980d2992618b6b721c848aba96cf759areed@android.com if (entry->ip.proto == IPPROTO_TCP 80fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com || entry->ip.proto == IPPROTO_UDP 81e28ff55d980d2992618b6b721c848aba96cf759areed@android.com || entry->ip.proto == IPPROTO_SCTP 82a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com || entry->ip.proto == IPPROTO_DCCP 83e28ff55d980d2992618b6b721c848aba96cf759areed@android.com || entry->ip.proto == IPPROTO_ICMP) 84e28ff55d980d2992618b6b721c848aba96cf759areed@android.com portok = 1; 85e28ff55d980d2992618b6b721c848aba96cf759areed@android.com else 86e28ff55d980d2992618b6b721c848aba96cf759areed@android.com portok = 0; 87e28ff55d980d2992618b6b721c848aba96cf759areed@android.com 88a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com switch (c) { 89a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com case '1': 90a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com if (!portok) 91a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com xtables_error(PARAMETER_PROBLEM, 92a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com "Need TCP, UDP, SCTP or DCCP with port specification"); 93a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com 94a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) 95a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com xtables_error(PARAMETER_PROBLEM, 96e28ff55d980d2992618b6b721c848aba96cf759areed@android.com "Unexpected `!' after --to-ports"); 97e28ff55d980d2992618b6b721c848aba96cf759areed@android.com 98fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com parse_ports(optarg, mr); 99e28ff55d980d2992618b6b721c848aba96cf759areed@android.com return 1; 100e28ff55d980d2992618b6b721c848aba96cf759areed@android.com 101e28ff55d980d2992618b6b721c848aba96cf759areed@android.com case '2': 102e28ff55d980d2992618b6b721c848aba96cf759areed@android.com mr->range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM; 103e28ff55d980d2992618b6b721c848aba96cf759areed@android.com return 1; 104e28ff55d980d2992618b6b721c848aba96cf759areed@android.com 105e28ff55d980d2992618b6b721c848aba96cf759areed@android.com default: 106e28ff55d980d2992618b6b721c848aba96cf759areed@android.com return 0; 107e28ff55d980d2992618b6b721c848aba96cf759areed@android.com } 108e28ff55d980d2992618b6b721c848aba96cf759areed@android.com} 109e28ff55d980d2992618b6b721c848aba96cf759areed@android.com 110e28ff55d980d2992618b6b721c848aba96cf759areed@android.comstatic void 111e28ff55d980d2992618b6b721c848aba96cf759areed@android.comMASQUERADE_print(const void *ip, const struct xt_entry_target *target, 112e28ff55d980d2992618b6b721c848aba96cf759areed@android.com int numeric) 113e28ff55d980d2992618b6b721c848aba96cf759areed@android.com{ 114e28ff55d980d2992618b6b721c848aba96cf759areed@android.com const struct nf_nat_multi_range *mr = (const void *)target->data; 115e28ff55d980d2992618b6b721c848aba96cf759areed@android.com const struct nf_nat_range *r = &mr->range[0]; 116e28ff55d980d2992618b6b721c848aba96cf759areed@android.com 117fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { 118e28ff55d980d2992618b6b721c848aba96cf759areed@android.com printf("masq ports: "); 119e28ff55d980d2992618b6b721c848aba96cf759areed@android.com printf("%hu", ntohs(r->min.tcp.port)); 120e28ff55d980d2992618b6b721c848aba96cf759areed@android.com if (r->max.tcp.port != r->min.tcp.port) 121e28ff55d980d2992618b6b721c848aba96cf759areed@android.com printf("-%hu", ntohs(r->max.tcp.port)); 122e28ff55d980d2992618b6b721c848aba96cf759areed@android.com printf(" "); 123e28ff55d980d2992618b6b721c848aba96cf759areed@android.com } 124e28ff55d980d2992618b6b721c848aba96cf759areed@android.com 125e28ff55d980d2992618b6b721c848aba96cf759areed@android.com if (r->flags & IP_NAT_RANGE_PROTO_RANDOM) 126e28ff55d980d2992618b6b721c848aba96cf759areed@android.com printf("random "); 127a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com} 128a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com 129a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.comstatic void 130e28ff55d980d2992618b6b721c848aba96cf759areed@android.comMASQUERADE_save(const void *ip, const struct xt_entry_target *target) 131e28ff55d980d2992618b6b721c848aba96cf759areed@android.com{ 132e28ff55d980d2992618b6b721c848aba96cf759areed@android.com const struct nf_nat_multi_range *mr = (const void *)target->data; 133e28ff55d980d2992618b6b721c848aba96cf759areed@android.com const struct nf_nat_range *r = &mr->range[0]; 134e28ff55d980d2992618b6b721c848aba96cf759areed@android.com 135e28ff55d980d2992618b6b721c848aba96cf759areed@android.com if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { 136e28ff55d980d2992618b6b721c848aba96cf759areed@android.com printf("--to-ports %hu", ntohs(r->min.tcp.port)); 137e28ff55d980d2992618b6b721c848aba96cf759areed@android.com if (r->max.tcp.port != r->min.tcp.port) 138e28ff55d980d2992618b6b721c848aba96cf759areed@android.com printf("-%hu", ntohs(r->max.tcp.port)); 139a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com printf(" "); 140a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com } 141a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com 142a3d901099d7d295cd7d9df4114e874d9ccfff447reed@android.com if (r->flags & IP_NAT_RANGE_PROTO_RANDOM) 143e28ff55d980d2992618b6b721c848aba96cf759areed@android.com printf("--random "); 144e28ff55d980d2992618b6b721c848aba96cf759areed@android.com} 145e28ff55d980d2992618b6b721c848aba96cf759areed@android.com 146e28ff55d980d2992618b6b721c848aba96cf759areed@android.comstatic struct xtables_target masquerade_tg_reg = { 147160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com .name = "MASQUERADE", 148160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com .version = XTABLES_VERSION, 149160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com .family = NFPROTO_IPV4, 150160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com .size = XT_ALIGN(sizeof(struct nf_nat_multi_range)), 151160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com .userspacesize = XT_ALIGN(sizeof(struct nf_nat_multi_range)), 152160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com .help = MASQUERADE_help, 153160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com .init = MASQUERADE_init, 154160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com .parse = MASQUERADE_parse, 155160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com .print = MASQUERADE_print, 156160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com .save = MASQUERADE_save, 157160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com .extra_opts = MASQUERADE_opts, 158160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com}; 159160f2c0e1724003767dbbea05bc8046ac5dd78d4reed@google.com 1600e51577a14f903ffeafa117a75954baeb173ffb9humper@google.comvoid _init(void) 161bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com{ 162bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com xtables_register_target(&masquerade_tg_reg); 163bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com} 164bddbc45b0b7e279a3e6f151638dfbf3c4e4ad3c1reed@google.com