1/* 2 * ip_nat_proto_gre.c - Version 1.11 3 * 4 * NAT protocol helper module for GRE. 5 * 6 * GRE is a generic encapsulation protocol, which is generally not very 7 * suited for NAT, as it has no protocol-specific part as port numbers. 8 * 9 * It has an optional key field, which may help us distinguishing two 10 * connections between the same two hosts. 11 * 12 * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 13 * 14 * PPTP is built on top of a modified version of GRE, and has a mandatory 15 * field called "CallID", which serves us for the same purpose as the key 16 * field in plain GRE. 17 * 18 * Documentation about PPTP can be found in RFC 2637 19 * 20 * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org> 21 * 22 * Development of this code funded by Astaro AG (http://www.astaro.com/) 23 * 24 */ 25 26#include <linux/config.h> 27#include <linux/module.h> 28#include <linux/ip.h> 29#include <linux/netfilter_ipv4/ip_nat.h> 30#include <linux/netfilter_ipv4/ip_nat_rule.h> 31#include <linux/netfilter_ipv4/ip_nat_protocol.h> 32#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> 33 34MODULE_LICENSE("GPL"); 35MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); 36MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE"); 37 38#define DEBUGP(x, args...) 39 40/* is key in given range between min and max */ 41static int 42gre_in_range(const struct ip_conntrack_tuple *tuple, 43 enum ip_nat_manip_type maniptype, 44 const union ip_conntrack_manip_proto *min, 45 const union ip_conntrack_manip_proto *max) 46{ 47 return ntohl(tuple->src.u.gre.key) >= ntohl(min->gre.key) 48 && ntohl(tuple->src.u.gre.key) <= ntohl(max->gre.key); 49} 50 51/* generate unique tuple ... */ 52static int 53gre_unique_tuple(struct ip_conntrack_tuple *tuple, 54 const struct ip_nat_range *range, 55 enum ip_nat_manip_type maniptype, 56 const struct ip_conntrack *conntrack) 57{ 58 u_int32_t min, i, range_size; 59 u_int32_t key = 0, *keyptr; 60 61 if (maniptype == IP_NAT_MANIP_SRC) 62 keyptr = &tuple->src.u.gre.key; 63 else 64 keyptr = &tuple->dst.u.gre.key; 65 66 if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { 67 68 switch (tuple->dst.u.gre.version) { 69 case 0: 70 DEBUGP("NATing GRE version 0 (ct=%p)\n", 71 conntrack); 72 min = 1; 73 range_size = 0xffffffff; 74 break; 75 case GRE_VERSION_PPTP: 76 DEBUGP("%p: NATing GRE PPTP\n", 77 conntrack); 78 min = 1; 79 range_size = 0xffff; 80 break; 81 default: 82 printk(KERN_WARNING "nat_gre: unknown GRE version\n"); 83 return 0; 84 break; 85 } 86 87 } else { 88 min = ntohl(range->min.gre.key); 89 range_size = ntohl(range->max.gre.key) - min + 1; 90 } 91 92 DEBUGP("min = %u, range_size = %u\n", min, range_size); 93 94 for (i = 0; i < range_size; i++, key++) { 95 *keyptr = htonl(min + key % range_size); 96 if (!ip_nat_used_tuple(tuple, conntrack)) 97 return 1; 98 } 99 100 DEBUGP("%p: no NAT mapping\n", conntrack); 101 102 return 0; 103} 104 105/* manipulate a GRE packet according to maniptype */ 106static void 107gre_manip_pkt(struct iphdr *iph, size_t len, 108 const struct ip_conntrack_manip *manip, 109 enum ip_nat_manip_type maniptype) 110{ 111 struct gre_hdr *greh = (struct gre_hdr *)((u_int32_t *)iph+iph->ihl); 112 struct gre_hdr_pptp *pgreh = (struct gre_hdr_pptp *) greh; 113 114 /* we only have destination manip of a packet, since 'source key' 115 * is not present in the packet itself */ 116 if (maniptype == IP_NAT_MANIP_DST) { 117 /* key manipulation is always dest */ 118 switch (greh->version) { 119 case 0: 120 if (!greh->key) { 121 DEBUGP("can't nat GRE w/o key\n"); 122 break; 123 } 124 if (greh->csum) { 125 *(gre_csum(greh)) = 126 ip_nat_cheat_check(~*(gre_key(greh)), 127 manip->u.gre.key, 128 *(gre_csum(greh))); 129 } 130 *(gre_key(greh)) = manip->u.gre.key; 131 break; 132 case GRE_VERSION_PPTP: 133 DEBUGP("call_id -> 0x%04x\n", 134 ntohl(manip->u.gre.key)); 135 pgreh->call_id = htons(ntohl(manip->u.gre.key)); 136 break; 137 default: 138 DEBUGP("can't nat unknown GRE version\n"); 139 break; 140 } 141 } 142} 143 144/* print out a nat tuple */ 145static unsigned int 146gre_print(char *buffer, 147 const struct ip_conntrack_tuple *match, 148 const struct ip_conntrack_tuple *mask) 149{ 150 unsigned int len = 0; 151 152 if (mask->dst.u.gre.version) 153 len += sprintf(buffer + len, "version=%d ", 154 ntohs(match->dst.u.gre.version)); 155 156 if (mask->dst.u.gre.protocol) 157 len += sprintf(buffer + len, "protocol=0x%x ", 158 ntohs(match->dst.u.gre.protocol)); 159 160 if (mask->src.u.gre.key) 161 len += sprintf(buffer + len, "srckey=0x%x ", 162 ntohl(match->src.u.gre.key)); 163 164 if (mask->dst.u.gre.key) 165 len += sprintf(buffer + len, "dstkey=0x%x ", 166 ntohl(match->src.u.gre.key)); 167 168 return len; 169} 170 171/* print a range of keys */ 172static unsigned int 173gre_print_range(char *buffer, const struct ip_nat_range *range) 174{ 175 if (range->min.gre.key != 0 176 || range->max.gre.key != 0xFFFF) { 177 if (range->min.gre.key == range->max.gre.key) 178 return sprintf(buffer, "key 0x%x ", 179 ntohl(range->min.gre.key)); 180 else 181 return sprintf(buffer, "keys 0x%u-0x%u ", 182 ntohl(range->min.gre.key), 183 ntohl(range->max.gre.key)); 184 } else 185 return 0; 186} 187 188/* nat helper struct */ 189static struct ip_nat_protocol gre = 190 { { NULL, NULL }, "GRE", IPPROTO_GRE, 191 gre_manip_pkt, 192 gre_in_range, 193 gre_unique_tuple, 194 gre_print, 195 gre_print_range 196 }; 197 198static int __init init(void) 199{ 200 if (ip_nat_protocol_register(&gre)) 201 return -EIO; 202 203 return 0; 204} 205 206static void __exit fini(void) 207{ 208 ip_nat_protocol_unregister(&gre); 209} 210 211module_init(init); 212module_exit(fini); 213