1 /* (C) 1999-2001 Paul `Rusty' Russell 2 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 */ 8 9 #include <linux/types.h> 10 #include <linux/export.h> 11 #include <linux/init.h> 12 #include <linux/udp.h> 13 #include <linux/tcp.h> 14 #include <linux/icmp.h> 15 #include <linux/icmpv6.h> 16 17 #include <linux/dccp.h> 18 #include <linux/sctp.h> 19 #include <net/sctp/checksum.h> 20 21 #include <linux/netfilter.h> 22 #include <net/netfilter/nf_nat.h> 23 #include <net/netfilter/nf_nat_core.h> 24 #include <net/netfilter/nf_nat_l3proto.h> 25 #include <net/netfilter/nf_nat_l4proto.h> 26 27 static void 28 __udp_manip_pkt(struct sk_buff *skb, 29 const struct nf_nat_l3proto *l3proto, 30 unsigned int iphdroff, struct udphdr *hdr, 31 const struct nf_conntrack_tuple *tuple, 32 enum nf_nat_manip_type maniptype, bool do_csum) 33 { 34 __be16 *portptr, newport; 35 36 if (maniptype == NF_NAT_MANIP_SRC) { 37 /* Get rid of src port */ 38 newport = tuple->src.u.udp.port; 39 portptr = &hdr->source; 40 } else { 41 /* Get rid of dst port */ 42 newport = tuple->dst.u.udp.port; 43 portptr = &hdr->dest; 44 } 45 if (do_csum) { 46 l3proto->csum_update(skb, iphdroff, &hdr->check, 47 tuple, maniptype); 48 inet_proto_csum_replace2(&hdr->check, skb, *portptr, newport, 49 false); 50 if (!hdr->check) 51 hdr->check = CSUM_MANGLED_0; 52 } 53 *portptr = newport; 54 } 55 56 static bool udp_manip_pkt(struct sk_buff *skb, 57 const struct nf_nat_l3proto *l3proto, 58 unsigned int iphdroff, unsigned int hdroff, 59 const struct nf_conntrack_tuple *tuple, 60 enum nf_nat_manip_type maniptype) 61 { 62 struct udphdr *hdr; 63 bool do_csum; 64 65 if (!skb_make_writable(skb, hdroff + sizeof(*hdr))) 66 return false; 67 68 hdr = (struct udphdr *)(skb->data + hdroff); 69 do_csum = hdr->check || skb->ip_summed == CHECKSUM_PARTIAL; 70 71 __udp_manip_pkt(skb, l3proto, iphdroff, hdr, tuple, maniptype, do_csum); 72 return true; 73 } 74 75 static bool udplite_manip_pkt(struct sk_buff *skb, 76 const struct nf_nat_l3proto *l3proto, 77 unsigned int iphdroff, unsigned int hdroff, 78 const struct nf_conntrack_tuple *tuple, 79 enum nf_nat_manip_type maniptype) 80 { 81 #ifdef CONFIG_NF_CT_PROTO_UDPLITE 82 struct udphdr *hdr; 83 84 if (!skb_make_writable(skb, hdroff + sizeof(*hdr))) 85 return false; 86 87 hdr = (struct udphdr *)(skb->data + hdroff); 88 __udp_manip_pkt(skb, l3proto, iphdroff, hdr, tuple, maniptype, true); 89 #endif 90 return true; 91 } 92 93 static bool 94 sctp_manip_pkt(struct sk_buff *skb, 95 const struct nf_nat_l3proto *l3proto, 96 unsigned int iphdroff, unsigned int hdroff, 97 const struct nf_conntrack_tuple *tuple, 98 enum nf_nat_manip_type maniptype) 99 { 100 #ifdef CONFIG_NF_CT_PROTO_SCTP 101 struct sctphdr *hdr; 102 int hdrsize = 8; 103 104 /* This could be an inner header returned in imcp packet; in such 105 * cases we cannot update the checksum field since it is outside 106 * of the 8 bytes of transport layer headers we are guaranteed. 107 */ 108 if (skb->len >= hdroff + sizeof(*hdr)) 109 hdrsize = sizeof(*hdr); 110 111 if (!skb_make_writable(skb, hdroff + hdrsize)) 112 return false; 113 114 hdr = (struct sctphdr *)(skb->data + hdroff); 115 116 if (maniptype == NF_NAT_MANIP_SRC) { 117 /* Get rid of src port */ 118 hdr->source = tuple->src.u.sctp.port; 119 } else { 120 /* Get rid of dst port */ 121 hdr->dest = tuple->dst.u.sctp.port; 122 } 123 124 if (hdrsize < sizeof(*hdr)) 125 return true; 126 127 if (skb->ip_summed != CHECKSUM_PARTIAL) { 128 hdr->checksum = sctp_compute_cksum(skb, hdroff); 129 skb->ip_summed = CHECKSUM_NONE; 130 } 131 132 #endif 133 return true; 134 } 135 136 static bool 137 tcp_manip_pkt(struct sk_buff *skb, 138 const struct nf_nat_l3proto *l3proto, 139 unsigned int iphdroff, unsigned int hdroff, 140 const struct nf_conntrack_tuple *tuple, 141 enum nf_nat_manip_type maniptype) 142 { 143 struct tcphdr *hdr; 144 __be16 *portptr, newport, oldport; 145 int hdrsize = 8; /* TCP connection tracking guarantees this much */ 146 147 /* this could be a inner header returned in icmp packet; in such 148 cases we cannot update the checksum field since it is outside of 149 the 8 bytes of transport layer headers we are guaranteed */ 150 if (skb->len >= hdroff + sizeof(struct tcphdr)) 151 hdrsize = sizeof(struct tcphdr); 152 153 if (!skb_make_writable(skb, hdroff + hdrsize)) 154 return false; 155 156 hdr = (struct tcphdr *)(skb->data + hdroff); 157 158 if (maniptype == NF_NAT_MANIP_SRC) { 159 /* Get rid of src port */ 160 newport = tuple->src.u.tcp.port; 161 portptr = &hdr->source; 162 } else { 163 /* Get rid of dst port */ 164 newport = tuple->dst.u.tcp.port; 165 portptr = &hdr->dest; 166 } 167 168 oldport = *portptr; 169 *portptr = newport; 170 171 if (hdrsize < sizeof(*hdr)) 172 return true; 173 174 l3proto->csum_update(skb, iphdroff, &hdr->check, tuple, maniptype); 175 inet_proto_csum_replace2(&hdr->check, skb, oldport, newport, false); 176 return true; 177 } 178 179 static bool 180 dccp_manip_pkt(struct sk_buff *skb, 181 const struct nf_nat_l3proto *l3proto, 182 unsigned int iphdroff, unsigned int hdroff, 183 const struct nf_conntrack_tuple *tuple, 184 enum nf_nat_manip_type maniptype) 185 { 186 #ifdef CONFIG_NF_CT_PROTO_DCCP 187 struct dccp_hdr *hdr; 188 __be16 *portptr, oldport, newport; 189 int hdrsize = 8; /* DCCP connection tracking guarantees this much */ 190 191 if (skb->len >= hdroff + sizeof(struct dccp_hdr)) 192 hdrsize = sizeof(struct dccp_hdr); 193 194 if (!skb_make_writable(skb, hdroff + hdrsize)) 195 return false; 196 197 hdr = (struct dccp_hdr *)(skb->data + hdroff); 198 199 if (maniptype == NF_NAT_MANIP_SRC) { 200 newport = tuple->src.u.dccp.port; 201 portptr = &hdr->dccph_sport; 202 } else { 203 newport = tuple->dst.u.dccp.port; 204 portptr = &hdr->dccph_dport; 205 } 206 207 oldport = *portptr; 208 *portptr = newport; 209 210 if (hdrsize < sizeof(*hdr)) 211 return true; 212 213 l3proto->csum_update(skb, iphdroff, &hdr->dccph_checksum, 214 tuple, maniptype); 215 inet_proto_csum_replace2(&hdr->dccph_checksum, skb, oldport, newport, 216 false); 217 #endif 218 return true; 219 } 220 221 static bool 222 icmp_manip_pkt(struct sk_buff *skb, 223 const struct nf_nat_l3proto *l3proto, 224 unsigned int iphdroff, unsigned int hdroff, 225 const struct nf_conntrack_tuple *tuple, 226 enum nf_nat_manip_type maniptype) 227 { 228 struct icmphdr *hdr; 229 230 if (!skb_make_writable(skb, hdroff + sizeof(*hdr))) 231 return false; 232 233 hdr = (struct icmphdr *)(skb->data + hdroff); 234 inet_proto_csum_replace2(&hdr->checksum, skb, 235 hdr->un.echo.id, tuple->src.u.icmp.id, false); 236 hdr->un.echo.id = tuple->src.u.icmp.id; 237 return true; 238 } 239 240 static bool 241 icmpv6_manip_pkt(struct sk_buff *skb, 242 const struct nf_nat_l3proto *l3proto, 243 unsigned int iphdroff, unsigned int hdroff, 244 const struct nf_conntrack_tuple *tuple, 245 enum nf_nat_manip_type maniptype) 246 { 247 struct icmp6hdr *hdr; 248 249 if (!skb_make_writable(skb, hdroff + sizeof(*hdr))) 250 return false; 251 252 hdr = (struct icmp6hdr *)(skb->data + hdroff); 253 l3proto->csum_update(skb, iphdroff, &hdr->icmp6_cksum, 254 tuple, maniptype); 255 if (hdr->icmp6_type == ICMPV6_ECHO_REQUEST || 256 hdr->icmp6_type == ICMPV6_ECHO_REPLY) { 257 inet_proto_csum_replace2(&hdr->icmp6_cksum, skb, 258 hdr->icmp6_identifier, 259 tuple->src.u.icmp.id, false); 260 hdr->icmp6_identifier = tuple->src.u.icmp.id; 261 } 262 return true; 263 } 264 265 /* manipulate a GRE packet according to maniptype */ 266 static bool 267 gre_manip_pkt(struct sk_buff *skb, 268 const struct nf_nat_l3proto *l3proto, 269 unsigned int iphdroff, unsigned int hdroff, 270 const struct nf_conntrack_tuple *tuple, 271 enum nf_nat_manip_type maniptype) 272 { 273 #if IS_ENABLED(CONFIG_NF_CT_PROTO_GRE) 274 const struct gre_base_hdr *greh; 275 struct pptp_gre_header *pgreh; 276 277 /* pgreh includes two optional 32bit fields which are not required 278 * to be there. That's where the magic '8' comes from */ 279 if (!skb_make_writable(skb, hdroff + sizeof(*pgreh) - 8)) 280 return false; 281 282 greh = (void *)skb->data + hdroff; 283 pgreh = (struct pptp_gre_header *)greh; 284 285 /* we only have destination manip of a packet, since 'source key' 286 * is not present in the packet itself */ 287 if (maniptype != NF_NAT_MANIP_DST) 288 return true; 289 290 switch (greh->flags & GRE_VERSION) { 291 case GRE_VERSION_0: 292 /* We do not currently NAT any GREv0 packets. 293 * Try to behave like "nf_nat_proto_unknown" */ 294 break; 295 case GRE_VERSION_1: 296 pr_debug("call_id -> 0x%04x\n", ntohs(tuple->dst.u.gre.key)); 297 pgreh->call_id = tuple->dst.u.gre.key; 298 break; 299 default: 300 pr_debug("can't nat unknown GRE version\n"); 301 return false; 302 } 303 #endif 304 return true; 305 } 306 307 bool nf_nat_l4proto_manip_pkt(struct sk_buff *skb, 308 const struct nf_nat_l3proto *l3proto, 309 unsigned int iphdroff, unsigned int hdroff, 310 const struct nf_conntrack_tuple *tuple, 311 enum nf_nat_manip_type maniptype) 312 { 313 switch (tuple->dst.protonum) { 314 case IPPROTO_TCP: 315 return tcp_manip_pkt(skb, l3proto, iphdroff, hdroff, 316 tuple, maniptype); 317 case IPPROTO_UDP: 318 return udp_manip_pkt(skb, l3proto, iphdroff, hdroff, 319 tuple, maniptype); 320 case IPPROTO_UDPLITE: 321 return udplite_manip_pkt(skb, l3proto, iphdroff, hdroff, 322 tuple, maniptype); 323 case IPPROTO_SCTP: 324 return sctp_manip_pkt(skb, l3proto, iphdroff, hdroff, 325 tuple, maniptype); 326 case IPPROTO_ICMP: 327 return icmp_manip_pkt(skb, l3proto, iphdroff, hdroff, 328 tuple, maniptype); 329 case IPPROTO_ICMPV6: 330 return icmpv6_manip_pkt(skb, l3proto, iphdroff, hdroff, 331 tuple, maniptype); 332 case IPPROTO_DCCP: 333 return dccp_manip_pkt(skb, l3proto, iphdroff, hdroff, 334 tuple, maniptype); 335 case IPPROTO_GRE: 336 return gre_manip_pkt(skb, l3proto, iphdroff, hdroff, 337 tuple, maniptype); 338 } 339 340 /* If we don't know protocol -- no error, pass it unmodified. */ 341 return true; 342 } 343 EXPORT_SYMBOL_GPL(nf_nat_l4proto_manip_pkt); 344