linux/net/netfilter/nf_nat_proto.c
<<
>>
Prefs
   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
  24#include <linux/ipv6.h>
  25#include <linux/netfilter_ipv6.h>
  26#include <net/checksum.h>
  27#include <net/ip6_checksum.h>
  28#include <net/ip6_route.h>
  29#include <net/xfrm.h>
  30#include <net/ipv6.h>
  31
  32#include <net/netfilter/nf_conntrack_core.h>
  33#include <net/netfilter/nf_conntrack.h>
  34#include <linux/netfilter/nfnetlink_conntrack.h>
  35
  36static void nf_csum_update(struct sk_buff *skb,
  37                           unsigned int iphdroff, __sum16 *check,
  38                           const struct nf_conntrack_tuple *t,
  39                           enum nf_nat_manip_type maniptype);
  40
  41static void
  42__udp_manip_pkt(struct sk_buff *skb,
  43                unsigned int iphdroff, struct udphdr *hdr,
  44                const struct nf_conntrack_tuple *tuple,
  45                enum nf_nat_manip_type maniptype, bool do_csum)
  46{
  47        __be16 *portptr, newport;
  48
  49        if (maniptype == NF_NAT_MANIP_SRC) {
  50                /* Get rid of src port */
  51                newport = tuple->src.u.udp.port;
  52                portptr = &hdr->source;
  53        } else {
  54                /* Get rid of dst port */
  55                newport = tuple->dst.u.udp.port;
  56                portptr = &hdr->dest;
  57        }
  58        if (do_csum) {
  59                nf_csum_update(skb, iphdroff, &hdr->check, tuple, maniptype);
  60                inet_proto_csum_replace2(&hdr->check, skb, *portptr, newport,
  61                                         false);
  62                if (!hdr->check)
  63                        hdr->check = CSUM_MANGLED_0;
  64        }
  65        *portptr = newport;
  66}
  67
  68static bool udp_manip_pkt(struct sk_buff *skb,
  69                          unsigned int iphdroff, unsigned int hdroff,
  70                          const struct nf_conntrack_tuple *tuple,
  71                          enum nf_nat_manip_type maniptype)
  72{
  73        struct udphdr *hdr;
  74
  75        if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
  76                return false;
  77
  78        hdr = (struct udphdr *)(skb->data + hdroff);
  79        __udp_manip_pkt(skb, iphdroff, hdr, tuple, maniptype, !!hdr->check);
  80
  81        return true;
  82}
  83
  84static bool udplite_manip_pkt(struct sk_buff *skb,
  85                              unsigned int iphdroff, unsigned int hdroff,
  86                              const struct nf_conntrack_tuple *tuple,
  87                              enum nf_nat_manip_type maniptype)
  88{
  89#ifdef CONFIG_NF_CT_PROTO_UDPLITE
  90        struct udphdr *hdr;
  91
  92        if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
  93                return false;
  94
  95        hdr = (struct udphdr *)(skb->data + hdroff);
  96        __udp_manip_pkt(skb, iphdroff, hdr, tuple, maniptype, true);
  97#endif
  98        return true;
  99}
 100
 101static bool
 102sctp_manip_pkt(struct sk_buff *skb,
 103               unsigned int iphdroff, unsigned int hdroff,
 104               const struct nf_conntrack_tuple *tuple,
 105               enum nf_nat_manip_type maniptype)
 106{
 107#ifdef CONFIG_NF_CT_PROTO_SCTP
 108        struct sctphdr *hdr;
 109        int hdrsize = 8;
 110
 111        /* This could be an inner header returned in imcp packet; in such
 112         * cases we cannot update the checksum field since it is outside
 113         * of the 8 bytes of transport layer headers we are guaranteed.
 114         */
 115        if (skb->len >= hdroff + sizeof(*hdr))
 116                hdrsize = sizeof(*hdr);
 117
 118        if (!skb_make_writable(skb, hdroff + hdrsize))
 119                return false;
 120
 121        hdr = (struct sctphdr *)(skb->data + hdroff);
 122
 123        if (maniptype == NF_NAT_MANIP_SRC) {
 124                /* Get rid of src port */
 125                hdr->source = tuple->src.u.sctp.port;
 126        } else {
 127                /* Get rid of dst port */
 128                hdr->dest = tuple->dst.u.sctp.port;
 129        }
 130
 131        if (hdrsize < sizeof(*hdr))
 132                return true;
 133
 134        if (skb->ip_summed != CHECKSUM_PARTIAL) {
 135                hdr->checksum = sctp_compute_cksum(skb, hdroff);
 136                skb->ip_summed = CHECKSUM_NONE;
 137        }
 138
 139#endif
 140        return true;
 141}
 142
 143static bool
 144tcp_manip_pkt(struct sk_buff *skb,
 145              unsigned int iphdroff, unsigned int hdroff,
 146              const struct nf_conntrack_tuple *tuple,
 147              enum nf_nat_manip_type maniptype)
 148{
 149        struct tcphdr *hdr;
 150        __be16 *portptr, newport, oldport;
 151        int hdrsize = 8; /* TCP connection tracking guarantees this much */
 152
 153        /* this could be a inner header returned in icmp packet; in such
 154           cases we cannot update the checksum field since it is outside of
 155           the 8 bytes of transport layer headers we are guaranteed */
 156        if (skb->len >= hdroff + sizeof(struct tcphdr))
 157                hdrsize = sizeof(struct tcphdr);
 158
 159        if (!skb_make_writable(skb, hdroff + hdrsize))
 160                return false;
 161
 162        hdr = (struct tcphdr *)(skb->data + hdroff);
 163
 164        if (maniptype == NF_NAT_MANIP_SRC) {
 165                /* Get rid of src port */
 166                newport = tuple->src.u.tcp.port;
 167                portptr = &hdr->source;
 168        } else {
 169                /* Get rid of dst port */
 170                newport = tuple->dst.u.tcp.port;
 171                portptr = &hdr->dest;
 172        }
 173
 174        oldport = *portptr;
 175        *portptr = newport;
 176
 177        if (hdrsize < sizeof(*hdr))
 178                return true;
 179
 180        nf_csum_update(skb, iphdroff, &hdr->check, tuple, maniptype);
 181        inet_proto_csum_replace2(&hdr->check, skb, oldport, newport, false);
 182        return true;
 183}
 184
 185static bool
 186dccp_manip_pkt(struct sk_buff *skb,
 187               unsigned int iphdroff, unsigned int hdroff,
 188               const struct nf_conntrack_tuple *tuple,
 189               enum nf_nat_manip_type maniptype)
 190{
 191#ifdef CONFIG_NF_CT_PROTO_DCCP
 192        struct dccp_hdr *hdr;
 193        __be16 *portptr, oldport, newport;
 194        int hdrsize = 8; /* DCCP connection tracking guarantees this much */
 195
 196        if (skb->len >= hdroff + sizeof(struct dccp_hdr))
 197                hdrsize = sizeof(struct dccp_hdr);
 198
 199        if (!skb_make_writable(skb, hdroff + hdrsize))
 200                return false;
 201
 202        hdr = (struct dccp_hdr *)(skb->data + hdroff);
 203
 204        if (maniptype == NF_NAT_MANIP_SRC) {
 205                newport = tuple->src.u.dccp.port;
 206                portptr = &hdr->dccph_sport;
 207        } else {
 208                newport = tuple->dst.u.dccp.port;
 209                portptr = &hdr->dccph_dport;
 210        }
 211
 212        oldport = *portptr;
 213        *portptr = newport;
 214
 215        if (hdrsize < sizeof(*hdr))
 216                return true;
 217
 218        nf_csum_update(skb, iphdroff, &hdr->dccph_checksum, tuple, maniptype);
 219        inet_proto_csum_replace2(&hdr->dccph_checksum, skb, oldport, newport,
 220                                 false);
 221#endif
 222        return true;
 223}
 224
 225static bool
 226icmp_manip_pkt(struct sk_buff *skb,
 227               unsigned int iphdroff, unsigned int hdroff,
 228               const struct nf_conntrack_tuple *tuple,
 229               enum nf_nat_manip_type maniptype)
 230{
 231        struct icmphdr *hdr;
 232
 233        if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
 234                return false;
 235
 236        hdr = (struct icmphdr *)(skb->data + hdroff);
 237        switch (hdr->type) {
 238        case ICMP_ECHO:
 239        case ICMP_ECHOREPLY:
 240        case ICMP_TIMESTAMP:
 241        case ICMP_TIMESTAMPREPLY:
 242        case ICMP_INFO_REQUEST:
 243        case ICMP_INFO_REPLY:
 244        case ICMP_ADDRESS:
 245        case ICMP_ADDRESSREPLY:
 246                break;
 247        default:
 248                return true;
 249        }
 250        inet_proto_csum_replace2(&hdr->checksum, skb,
 251                                 hdr->un.echo.id, tuple->src.u.icmp.id, false);
 252        hdr->un.echo.id = tuple->src.u.icmp.id;
 253        return true;
 254}
 255
 256static bool
 257icmpv6_manip_pkt(struct sk_buff *skb,
 258                 unsigned int iphdroff, unsigned int hdroff,
 259                 const struct nf_conntrack_tuple *tuple,
 260                 enum nf_nat_manip_type maniptype)
 261{
 262        struct icmp6hdr *hdr;
 263
 264        if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
 265                return false;
 266
 267        hdr = (struct icmp6hdr *)(skb->data + hdroff);
 268        nf_csum_update(skb, iphdroff, &hdr->icmp6_cksum, tuple, maniptype);
 269        if (hdr->icmp6_type == ICMPV6_ECHO_REQUEST ||
 270            hdr->icmp6_type == ICMPV6_ECHO_REPLY) {
 271                inet_proto_csum_replace2(&hdr->icmp6_cksum, skb,
 272                                         hdr->icmp6_identifier,
 273                                         tuple->src.u.icmp.id, false);
 274                hdr->icmp6_identifier = tuple->src.u.icmp.id;
 275        }
 276        return true;
 277}
 278
 279/* manipulate a GRE packet according to maniptype */
 280static bool
 281gre_manip_pkt(struct sk_buff *skb,
 282              unsigned int iphdroff, unsigned int hdroff,
 283              const struct nf_conntrack_tuple *tuple,
 284              enum nf_nat_manip_type maniptype)
 285{
 286#if IS_ENABLED(CONFIG_NF_CT_PROTO_GRE)
 287        const struct gre_base_hdr *greh;
 288        struct pptp_gre_header *pgreh;
 289
 290        /* pgreh includes two optional 32bit fields which are not required
 291         * to be there.  That's where the magic '8' comes from */
 292        if (!skb_make_writable(skb, hdroff + sizeof(*pgreh) - 8))
 293                return false;
 294
 295        greh = (void *)skb->data + hdroff;
 296        pgreh = (struct pptp_gre_header *)greh;
 297
 298        /* we only have destination manip of a packet, since 'source key'
 299         * is not present in the packet itself */
 300        if (maniptype != NF_NAT_MANIP_DST)
 301                return true;
 302
 303        switch (greh->flags & GRE_VERSION) {
 304        case GRE_VERSION_0:
 305                /* We do not currently NAT any GREv0 packets.
 306                 * Try to behave like "nf_nat_proto_unknown" */
 307                break;
 308        case GRE_VERSION_1:
 309                pr_debug("call_id -> 0x%04x\n", ntohs(tuple->dst.u.gre.key));
 310                pgreh->call_id = tuple->dst.u.gre.key;
 311                break;
 312        default:
 313                pr_debug("can't nat unknown GRE version\n");
 314                return false;
 315        }
 316#endif
 317        return true;
 318}
 319
 320static bool l4proto_manip_pkt(struct sk_buff *skb,
 321                              unsigned int iphdroff, unsigned int hdroff,
 322                              const struct nf_conntrack_tuple *tuple,
 323                              enum nf_nat_manip_type maniptype)
 324{
 325        switch (tuple->dst.protonum) {
 326        case IPPROTO_TCP:
 327                return tcp_manip_pkt(skb, iphdroff, hdroff,
 328                                     tuple, maniptype);
 329        case IPPROTO_UDP:
 330                return udp_manip_pkt(skb, iphdroff, hdroff,
 331                                     tuple, maniptype);
 332        case IPPROTO_UDPLITE:
 333                return udplite_manip_pkt(skb, iphdroff, hdroff,
 334                                         tuple, maniptype);
 335        case IPPROTO_SCTP:
 336                return sctp_manip_pkt(skb, iphdroff, hdroff,
 337                                      tuple, maniptype);
 338        case IPPROTO_ICMP:
 339                return icmp_manip_pkt(skb, iphdroff, hdroff,
 340                                      tuple, maniptype);
 341        case IPPROTO_ICMPV6:
 342                return icmpv6_manip_pkt(skb, iphdroff, hdroff,
 343                                        tuple, maniptype);
 344        case IPPROTO_DCCP:
 345                return dccp_manip_pkt(skb, iphdroff, hdroff,
 346                                      tuple, maniptype);
 347        case IPPROTO_GRE:
 348                return gre_manip_pkt(skb, iphdroff, hdroff,
 349                                     tuple, maniptype);
 350        }
 351
 352        /* If we don't know protocol -- no error, pass it unmodified. */
 353        return true;
 354}
 355
 356static bool nf_nat_ipv4_manip_pkt(struct sk_buff *skb,
 357                                  unsigned int iphdroff,
 358                                  const struct nf_conntrack_tuple *target,
 359                                  enum nf_nat_manip_type maniptype)
 360{
 361        struct iphdr *iph;
 362        unsigned int hdroff;
 363
 364        if (!skb_make_writable(skb, iphdroff + sizeof(*iph)))
 365                return false;
 366
 367        iph = (void *)skb->data + iphdroff;
 368        hdroff = iphdroff + iph->ihl * 4;
 369
 370        if (!l4proto_manip_pkt(skb, iphdroff, hdroff, target, maniptype))
 371                return false;
 372        iph = (void *)skb->data + iphdroff;
 373
 374        if (maniptype == NF_NAT_MANIP_SRC) {
 375                csum_replace4(&iph->check, iph->saddr, target->src.u3.ip);
 376                iph->saddr = target->src.u3.ip;
 377        } else {
 378                csum_replace4(&iph->check, iph->daddr, target->dst.u3.ip);
 379                iph->daddr = target->dst.u3.ip;
 380        }
 381        return true;
 382}
 383
 384static bool nf_nat_ipv6_manip_pkt(struct sk_buff *skb,
 385                                  unsigned int iphdroff,
 386                                  const struct nf_conntrack_tuple *target,
 387                                  enum nf_nat_manip_type maniptype)
 388{
 389#if IS_ENABLED(CONFIG_IPV6)
 390        struct ipv6hdr *ipv6h;
 391        __be16 frag_off;
 392        int hdroff;
 393        u8 nexthdr;
 394
 395        if (!skb_make_writable(skb, iphdroff + sizeof(*ipv6h)))
 396                return false;
 397
 398        ipv6h = (void *)skb->data + iphdroff;
 399        nexthdr = ipv6h->nexthdr;
 400        hdroff = ipv6_skip_exthdr(skb, iphdroff + sizeof(*ipv6h),
 401                                  &nexthdr, &frag_off);
 402        if (hdroff < 0)
 403                goto manip_addr;
 404
 405        if ((frag_off & htons(~0x7)) == 0 &&
 406            !l4proto_manip_pkt(skb, iphdroff, hdroff, target, maniptype))
 407                return false;
 408
 409        /* must reload, offset might have changed */
 410        ipv6h = (void *)skb->data + iphdroff;
 411
 412manip_addr:
 413        if (maniptype == NF_NAT_MANIP_SRC)
 414                ipv6h->saddr = target->src.u3.in6;
 415        else
 416                ipv6h->daddr = target->dst.u3.in6;
 417
 418#endif
 419        return true;
 420}
 421
 422unsigned int nf_nat_manip_pkt(struct sk_buff *skb, struct nf_conn *ct,
 423                              enum nf_nat_manip_type mtype,
 424                              enum ip_conntrack_dir dir)
 425{
 426        struct nf_conntrack_tuple target;
 427
 428        /* We are aiming to look like inverse of other direction. */
 429        nf_ct_invert_tuple(&target, &ct->tuplehash[!dir].tuple);
 430
 431        switch (target.src.l3num) {
 432        case NFPROTO_IPV6:
 433                if (nf_nat_ipv6_manip_pkt(skb, 0, &target, mtype))
 434                        return NF_ACCEPT;
 435                break;
 436        case NFPROTO_IPV4:
 437                if (nf_nat_ipv4_manip_pkt(skb, 0, &target, mtype))
 438                        return NF_ACCEPT;
 439                break;
 440        default:
 441                WARN_ON_ONCE(1);
 442                break;
 443        }
 444
 445        return NF_DROP;
 446}
 447
 448static void nf_nat_ipv4_csum_update(struct sk_buff *skb,
 449                                    unsigned int iphdroff, __sum16 *check,
 450                                    const struct nf_conntrack_tuple *t,
 451                                    enum nf_nat_manip_type maniptype)
 452{
 453        struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
 454        __be32 oldip, newip;
 455
 456        if (maniptype == NF_NAT_MANIP_SRC) {
 457                oldip = iph->saddr;
 458                newip = t->src.u3.ip;
 459        } else {
 460                oldip = iph->daddr;
 461                newip = t->dst.u3.ip;
 462        }
 463        inet_proto_csum_replace4(check, skb, oldip, newip, true);
 464}
 465
 466static void nf_nat_ipv6_csum_update(struct sk_buff *skb,
 467                                    unsigned int iphdroff, __sum16 *check,
 468                                    const struct nf_conntrack_tuple *t,
 469                                    enum nf_nat_manip_type maniptype)
 470{
 471#if IS_ENABLED(CONFIG_IPV6)
 472        const struct ipv6hdr *ipv6h = (struct ipv6hdr *)(skb->data + iphdroff);
 473        const struct in6_addr *oldip, *newip;
 474
 475        if (maniptype == NF_NAT_MANIP_SRC) {
 476                oldip = &ipv6h->saddr;
 477                newip = &t->src.u3.in6;
 478        } else {
 479                oldip = &ipv6h->daddr;
 480                newip = &t->dst.u3.in6;
 481        }
 482        inet_proto_csum_replace16(check, skb, oldip->s6_addr32,
 483                                  newip->s6_addr32, true);
 484#endif
 485}
 486
 487static void nf_csum_update(struct sk_buff *skb,
 488                           unsigned int iphdroff, __sum16 *check,
 489                           const struct nf_conntrack_tuple *t,
 490                           enum nf_nat_manip_type maniptype)
 491{
 492        switch (t->src.l3num) {
 493        case NFPROTO_IPV4:
 494                nf_nat_ipv4_csum_update(skb, iphdroff, check, t, maniptype);
 495                return;
 496        case NFPROTO_IPV6:
 497                nf_nat_ipv6_csum_update(skb, iphdroff, check, t, maniptype);
 498                return;
 499        }
 500}
 501
 502static void nf_nat_ipv4_csum_recalc(struct sk_buff *skb,
 503                                    u8 proto, void *data, __sum16 *check,
 504                                    int datalen, int oldlen)
 505{
 506        if (skb->ip_summed != CHECKSUM_PARTIAL) {
 507                const struct iphdr *iph = ip_hdr(skb);
 508
 509                skb->ip_summed = CHECKSUM_PARTIAL;
 510                skb->csum_start = skb_headroom(skb) + skb_network_offset(skb) +
 511                        ip_hdrlen(skb);
 512                skb->csum_offset = (void *)check - data;
 513                *check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, datalen,
 514                                            proto, 0);
 515        } else {
 516                inet_proto_csum_replace2(check, skb,
 517                                         htons(oldlen), htons(datalen), true);
 518        }
 519}
 520
 521#if IS_ENABLED(CONFIG_IPV6)
 522static void nf_nat_ipv6_csum_recalc(struct sk_buff *skb,
 523                                    u8 proto, void *data, __sum16 *check,
 524                                    int datalen, int oldlen)
 525{
 526        if (skb->ip_summed != CHECKSUM_PARTIAL) {
 527                const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
 528
 529                skb->ip_summed = CHECKSUM_PARTIAL;
 530                skb->csum_start = skb_headroom(skb) + skb_network_offset(skb) +
 531                        (data - (void *)skb->data);
 532                skb->csum_offset = (void *)check - data;
 533                *check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr,
 534                                          datalen, proto, 0);
 535        } else {
 536                inet_proto_csum_replace2(check, skb,
 537                                         htons(oldlen), htons(datalen), true);
 538        }
 539}
 540#endif
 541
 542void nf_nat_csum_recalc(struct sk_buff *skb,
 543                        u8 nfproto, u8 proto, void *data, __sum16 *check,
 544                        int datalen, int oldlen)
 545{
 546        switch (nfproto) {
 547        case NFPROTO_IPV4:
 548                nf_nat_ipv4_csum_recalc(skb, proto, data, check,
 549                                        datalen, oldlen);
 550                return;
 551#if IS_ENABLED(CONFIG_IPV6)
 552        case NFPROTO_IPV6:
 553                nf_nat_ipv6_csum_recalc(skb, proto, data, check,
 554                                        datalen, oldlen);
 555                return;
 556#endif
 557        }
 558
 559        WARN_ON_ONCE(1);
 560}
 561
 562int nf_nat_icmp_reply_translation(struct sk_buff *skb,
 563                                  struct nf_conn *ct,
 564                                  enum ip_conntrack_info ctinfo,
 565                                  unsigned int hooknum)
 566{
 567        struct {
 568                struct icmphdr  icmp;
 569                struct iphdr    ip;
 570        } *inside;
 571        enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
 572        enum nf_nat_manip_type manip = HOOK2MANIP(hooknum);
 573        unsigned int hdrlen = ip_hdrlen(skb);
 574        struct nf_conntrack_tuple target;
 575        unsigned long statusbit;
 576
 577        WARN_ON(ctinfo != IP_CT_RELATED && ctinfo != IP_CT_RELATED_REPLY);
 578
 579        if (!skb_make_writable(skb, hdrlen + sizeof(*inside)))
 580                return 0;
 581        if (nf_ip_checksum(skb, hooknum, hdrlen, IPPROTO_ICMP))
 582                return 0;
 583
 584        inside = (void *)skb->data + hdrlen;
 585        if (inside->icmp.type == ICMP_REDIRECT) {
 586                if ((ct->status & IPS_NAT_DONE_MASK) != IPS_NAT_DONE_MASK)
 587                        return 0;
 588                if (ct->status & IPS_NAT_MASK)
 589                        return 0;
 590        }
 591
 592        if (manip == NF_NAT_MANIP_SRC)
 593                statusbit = IPS_SRC_NAT;
 594        else
 595                statusbit = IPS_DST_NAT;
 596
 597        /* Invert if this is reply direction */
 598        if (dir == IP_CT_DIR_REPLY)
 599                statusbit ^= IPS_NAT_MASK;
 600
 601        if (!(ct->status & statusbit))
 602                return 1;
 603
 604        if (!nf_nat_ipv4_manip_pkt(skb, hdrlen + sizeof(inside->icmp),
 605                                   &ct->tuplehash[!dir].tuple, !manip))
 606                return 0;
 607
 608        if (skb->ip_summed != CHECKSUM_PARTIAL) {
 609                /* Reloading "inside" here since manip_pkt may reallocate */
 610                inside = (void *)skb->data + hdrlen;
 611                inside->icmp.checksum = 0;
 612                inside->icmp.checksum =
 613                        csum_fold(skb_checksum(skb, hdrlen,
 614                                               skb->len - hdrlen, 0));
 615        }
 616
 617        /* Change outer to look like the reply to an incoming packet */
 618        nf_ct_invert_tuple(&target, &ct->tuplehash[!dir].tuple);
 619        target.dst.protonum = IPPROTO_ICMP;
 620        if (!nf_nat_ipv4_manip_pkt(skb, 0, &target, manip))
 621                return 0;
 622
 623        return 1;
 624}
 625EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation);
 626
 627static unsigned int
 628nf_nat_ipv4_fn(void *priv, struct sk_buff *skb,
 629               const struct nf_hook_state *state)
 630{
 631        struct nf_conn *ct;
 632        enum ip_conntrack_info ctinfo;
 633
 634        ct = nf_ct_get(skb, &ctinfo);
 635        if (!ct)
 636                return NF_ACCEPT;
 637
 638        if (ctinfo == IP_CT_RELATED || ctinfo == IP_CT_RELATED_REPLY) {
 639                if (ip_hdr(skb)->protocol == IPPROTO_ICMP) {
 640                        if (!nf_nat_icmp_reply_translation(skb, ct, ctinfo,
 641                                                           state->hook))
 642                                return NF_DROP;
 643                        else
 644                                return NF_ACCEPT;
 645                }
 646        }
 647
 648        return nf_nat_inet_fn(priv, skb, state);
 649}
 650
 651static unsigned int
 652nf_nat_ipv4_in(void *priv, struct sk_buff *skb,
 653               const struct nf_hook_state *state)
 654{
 655        unsigned int ret;
 656        __be32 daddr = ip_hdr(skb)->daddr;
 657
 658        ret = nf_nat_ipv4_fn(priv, skb, state);
 659        if (ret == NF_ACCEPT && daddr != ip_hdr(skb)->daddr)
 660                skb_dst_drop(skb);
 661
 662        return ret;
 663}
 664
 665static unsigned int
 666nf_nat_ipv4_out(void *priv, struct sk_buff *skb,
 667                const struct nf_hook_state *state)
 668{
 669#ifdef CONFIG_XFRM
 670        const struct nf_conn *ct;
 671        enum ip_conntrack_info ctinfo;
 672        int err;
 673#endif
 674        unsigned int ret;
 675
 676        ret = nf_nat_ipv4_fn(priv, skb, state);
 677#ifdef CONFIG_XFRM
 678        if (ret != NF_ACCEPT)
 679                return ret;
 680
 681        if (IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED)
 682                return ret;
 683
 684        ct = nf_ct_get(skb, &ctinfo);
 685        if (ct) {
 686                enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
 687
 688                if (ct->tuplehash[dir].tuple.src.u3.ip !=
 689                     ct->tuplehash[!dir].tuple.dst.u3.ip ||
 690                    (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP &&
 691                     ct->tuplehash[dir].tuple.src.u.all !=
 692                     ct->tuplehash[!dir].tuple.dst.u.all)) {
 693                        err = nf_xfrm_me_harder(state->net, skb, AF_INET);
 694                        if (err < 0)
 695                                ret = NF_DROP_ERR(err);
 696                }
 697        }
 698#endif
 699        return ret;
 700}
 701
 702static unsigned int
 703nf_nat_ipv4_local_fn(void *priv, struct sk_buff *skb,
 704                     const struct nf_hook_state *state)
 705{
 706        const struct nf_conn *ct;
 707        enum ip_conntrack_info ctinfo;
 708        unsigned int ret;
 709        int err;
 710
 711        ret = nf_nat_ipv4_fn(priv, skb, state);
 712        if (ret != NF_ACCEPT)
 713                return ret;
 714
 715        ct = nf_ct_get(skb, &ctinfo);
 716        if (ct) {
 717                enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
 718
 719                if (ct->tuplehash[dir].tuple.dst.u3.ip !=
 720                    ct->tuplehash[!dir].tuple.src.u3.ip) {
 721                        err = ip_route_me_harder(state->net, state->sk, skb, RTN_UNSPEC);
 722                        if (err < 0)
 723                                ret = NF_DROP_ERR(err);
 724                }
 725#ifdef CONFIG_XFRM
 726                else if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
 727                         ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP &&
 728                         ct->tuplehash[dir].tuple.dst.u.all !=
 729                         ct->tuplehash[!dir].tuple.src.u.all) {
 730                        err = nf_xfrm_me_harder(state->net, skb, AF_INET);
 731                        if (err < 0)
 732                                ret = NF_DROP_ERR(err);
 733                }
 734#endif
 735        }
 736        return ret;
 737}
 738
 739const struct nf_hook_ops nf_nat_ipv4_ops[] = {
 740        /* Before packet filtering, change destination */
 741        {
 742                .hook           = nf_nat_ipv4_in,
 743                .pf             = NFPROTO_IPV4,
 744                .hooknum        = NF_INET_PRE_ROUTING,
 745                .priority       = NF_IP_PRI_NAT_DST,
 746        },
 747        /* After packet filtering, change source */
 748        {
 749                .hook           = nf_nat_ipv4_out,
 750                .pf             = NFPROTO_IPV4,
 751                .hooknum        = NF_INET_POST_ROUTING,
 752                .priority       = NF_IP_PRI_NAT_SRC,
 753        },
 754        /* Before packet filtering, change destination */
 755        {
 756                .hook           = nf_nat_ipv4_local_fn,
 757                .pf             = NFPROTO_IPV4,
 758                .hooknum        = NF_INET_LOCAL_OUT,
 759                .priority       = NF_IP_PRI_NAT_DST,
 760        },
 761        /* After packet filtering, change source */
 762        {
 763                .hook           = nf_nat_ipv4_fn,
 764                .pf             = NFPROTO_IPV4,
 765                .hooknum        = NF_INET_LOCAL_IN,
 766                .priority       = NF_IP_PRI_NAT_SRC,
 767        },
 768};
 769
 770int nf_nat_ipv4_register_fn(struct net *net, const struct nf_hook_ops *ops)
 771{
 772        return nf_nat_register_fn(net, ops->pf, ops, nf_nat_ipv4_ops,
 773                                  ARRAY_SIZE(nf_nat_ipv4_ops));
 774}
 775EXPORT_SYMBOL_GPL(nf_nat_ipv4_register_fn);
 776
 777void nf_nat_ipv4_unregister_fn(struct net *net, const struct nf_hook_ops *ops)
 778{
 779        nf_nat_unregister_fn(net, ops->pf, ops, ARRAY_SIZE(nf_nat_ipv4_ops));
 780}
 781EXPORT_SYMBOL_GPL(nf_nat_ipv4_unregister_fn);
 782
 783#if IS_ENABLED(CONFIG_IPV6)
 784int nf_nat_icmpv6_reply_translation(struct sk_buff *skb,
 785                                    struct nf_conn *ct,
 786                                    enum ip_conntrack_info ctinfo,
 787                                    unsigned int hooknum,
 788                                    unsigned int hdrlen)
 789{
 790        struct {
 791                struct icmp6hdr icmp6;
 792                struct ipv6hdr  ip6;
 793        } *inside;
 794        enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
 795        enum nf_nat_manip_type manip = HOOK2MANIP(hooknum);
 796        struct nf_conntrack_tuple target;
 797        unsigned long statusbit;
 798
 799        WARN_ON(ctinfo != IP_CT_RELATED && ctinfo != IP_CT_RELATED_REPLY);
 800
 801        if (!skb_make_writable(skb, hdrlen + sizeof(*inside)))
 802                return 0;
 803        if (nf_ip6_checksum(skb, hooknum, hdrlen, IPPROTO_ICMPV6))
 804                return 0;
 805
 806        inside = (void *)skb->data + hdrlen;
 807        if (inside->icmp6.icmp6_type == NDISC_REDIRECT) {
 808                if ((ct->status & IPS_NAT_DONE_MASK) != IPS_NAT_DONE_MASK)
 809                        return 0;
 810                if (ct->status & IPS_NAT_MASK)
 811                        return 0;
 812        }
 813
 814        if (manip == NF_NAT_MANIP_SRC)
 815                statusbit = IPS_SRC_NAT;
 816        else
 817                statusbit = IPS_DST_NAT;
 818
 819        /* Invert if this is reply direction */
 820        if (dir == IP_CT_DIR_REPLY)
 821                statusbit ^= IPS_NAT_MASK;
 822
 823        if (!(ct->status & statusbit))
 824                return 1;
 825
 826        if (!nf_nat_ipv6_manip_pkt(skb, hdrlen + sizeof(inside->icmp6),
 827                                   &ct->tuplehash[!dir].tuple, !manip))
 828                return 0;
 829
 830        if (skb->ip_summed != CHECKSUM_PARTIAL) {
 831                struct ipv6hdr *ipv6h = ipv6_hdr(skb);
 832
 833                inside = (void *)skb->data + hdrlen;
 834                inside->icmp6.icmp6_cksum = 0;
 835                inside->icmp6.icmp6_cksum =
 836                        csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr,
 837                                        skb->len - hdrlen, IPPROTO_ICMPV6,
 838                                        skb_checksum(skb, hdrlen,
 839                                                     skb->len - hdrlen, 0));
 840        }
 841
 842        nf_ct_invert_tuple(&target, &ct->tuplehash[!dir].tuple);
 843        target.dst.protonum = IPPROTO_ICMPV6;
 844        if (!nf_nat_ipv6_manip_pkt(skb, 0, &target, manip))
 845                return 0;
 846
 847        return 1;
 848}
 849EXPORT_SYMBOL_GPL(nf_nat_icmpv6_reply_translation);
 850
 851static unsigned int
 852nf_nat_ipv6_fn(void *priv, struct sk_buff *skb,
 853               const struct nf_hook_state *state)
 854{
 855        struct nf_conn *ct;
 856        enum ip_conntrack_info ctinfo;
 857        __be16 frag_off;
 858        int hdrlen;
 859        u8 nexthdr;
 860
 861        ct = nf_ct_get(skb, &ctinfo);
 862        /* Can't track?  It's not due to stress, or conntrack would
 863         * have dropped it.  Hence it's the user's responsibilty to
 864         * packet filter it out, or implement conntrack/NAT for that
 865         * protocol. 8) --RR
 866         */
 867        if (!ct)
 868                return NF_ACCEPT;
 869
 870        if (ctinfo == IP_CT_RELATED || ctinfo == IP_CT_RELATED_REPLY) {
 871                nexthdr = ipv6_hdr(skb)->nexthdr;
 872                hdrlen = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
 873                                          &nexthdr, &frag_off);
 874
 875                if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) {
 876                        if (!nf_nat_icmpv6_reply_translation(skb, ct, ctinfo,
 877                                                             state->hook,
 878                                                             hdrlen))
 879                                return NF_DROP;
 880                        else
 881                                return NF_ACCEPT;
 882                }
 883        }
 884
 885        return nf_nat_inet_fn(priv, skb, state);
 886}
 887
 888static unsigned int
 889nf_nat_ipv6_in(void *priv, struct sk_buff *skb,
 890               const struct nf_hook_state *state)
 891{
 892        unsigned int ret;
 893        struct in6_addr daddr = ipv6_hdr(skb)->daddr;
 894
 895        ret = nf_nat_ipv6_fn(priv, skb, state);
 896        if (ret != NF_DROP && ret != NF_STOLEN &&
 897            ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr))
 898                skb_dst_drop(skb);
 899
 900        return ret;
 901}
 902
 903static unsigned int
 904nf_nat_ipv6_out(void *priv, struct sk_buff *skb,
 905                const struct nf_hook_state *state)
 906{
 907#ifdef CONFIG_XFRM
 908        const struct nf_conn *ct;
 909        enum ip_conntrack_info ctinfo;
 910        int err;
 911#endif
 912        unsigned int ret;
 913
 914        ret = nf_nat_ipv6_fn(priv, skb, state);
 915#ifdef CONFIG_XFRM
 916        if (ret != NF_ACCEPT)
 917                return ret;
 918
 919        if (IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED)
 920                return ret;
 921        ct = nf_ct_get(skb, &ctinfo);
 922        if (ct) {
 923                enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
 924
 925                if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3,
 926                                      &ct->tuplehash[!dir].tuple.dst.u3) ||
 927                    (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 &&
 928                     ct->tuplehash[dir].tuple.src.u.all !=
 929                     ct->tuplehash[!dir].tuple.dst.u.all)) {
 930                        err = nf_xfrm_me_harder(state->net, skb, AF_INET6);
 931                        if (err < 0)
 932                                ret = NF_DROP_ERR(err);
 933                }
 934        }
 935#endif
 936
 937        return ret;
 938}
 939
 940static unsigned int
 941nf_nat_ipv6_local_fn(void *priv, struct sk_buff *skb,
 942                     const struct nf_hook_state *state)
 943{
 944        const struct nf_conn *ct;
 945        enum ip_conntrack_info ctinfo;
 946        unsigned int ret;
 947        int err;
 948
 949        ret = nf_nat_ipv6_fn(priv, skb, state);
 950        if (ret != NF_ACCEPT)
 951                return ret;
 952
 953        ct = nf_ct_get(skb, &ctinfo);
 954        if (ct) {
 955                enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
 956
 957                if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3,
 958                                      &ct->tuplehash[!dir].tuple.src.u3)) {
 959                        err = nf_ip6_route_me_harder(state->net, state->sk, skb);
 960                        if (err < 0)
 961                                ret = NF_DROP_ERR(err);
 962                }
 963#ifdef CONFIG_XFRM
 964                else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
 965                         ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 &&
 966                         ct->tuplehash[dir].tuple.dst.u.all !=
 967                         ct->tuplehash[!dir].tuple.src.u.all) {
 968                        err = nf_xfrm_me_harder(state->net, skb, AF_INET6);
 969                        if (err < 0)
 970                                ret = NF_DROP_ERR(err);
 971                }
 972#endif
 973        }
 974
 975        return ret;
 976}
 977
 978const struct nf_hook_ops nf_nat_ipv6_ops[] = {
 979        /* Before packet filtering, change destination */
 980        {
 981                .hook           = nf_nat_ipv6_in,
 982                .pf             = NFPROTO_IPV6,
 983                .hooknum        = NF_INET_PRE_ROUTING,
 984                .priority       = NF_IP6_PRI_NAT_DST,
 985        },
 986        /* After packet filtering, change source */
 987        {
 988                .hook           = nf_nat_ipv6_out,
 989                .pf             = NFPROTO_IPV6,
 990                .hooknum        = NF_INET_POST_ROUTING,
 991                .priority       = NF_IP6_PRI_NAT_SRC,
 992        },
 993        /* Before packet filtering, change destination */
 994        {
 995                .hook           = nf_nat_ipv6_local_fn,
 996                .pf             = NFPROTO_IPV6,
 997                .hooknum        = NF_INET_LOCAL_OUT,
 998                .priority       = NF_IP6_PRI_NAT_DST,
 999        },
1000        /* After packet filtering, change source */
1001        {
1002                .hook           = nf_nat_ipv6_fn,
1003                .pf             = NFPROTO_IPV6,
1004                .hooknum        = NF_INET_LOCAL_IN,
1005                .priority       = NF_IP6_PRI_NAT_SRC,
1006        },
1007};
1008
1009int nf_nat_ipv6_register_fn(struct net *net, const struct nf_hook_ops *ops)
1010{
1011        return nf_nat_register_fn(net, ops->pf, ops, nf_nat_ipv6_ops,
1012                                  ARRAY_SIZE(nf_nat_ipv6_ops));
1013}
1014EXPORT_SYMBOL_GPL(nf_nat_ipv6_register_fn);
1015
1016void nf_nat_ipv6_unregister_fn(struct net *net, const struct nf_hook_ops *ops)
1017{
1018        nf_nat_unregister_fn(net, ops->pf, ops, ARRAY_SIZE(nf_nat_ipv6_ops));
1019}
1020EXPORT_SYMBOL_GPL(nf_nat_ipv6_unregister_fn);
1021#endif /* CONFIG_IPV6 */
1022
1023#if defined(CONFIG_NF_TABLES_INET) && IS_ENABLED(CONFIG_NFT_NAT)
1024int nf_nat_inet_register_fn(struct net *net, const struct nf_hook_ops *ops)
1025{
1026        int ret;
1027
1028        if (WARN_ON_ONCE(ops->pf != NFPROTO_INET))
1029                return -EINVAL;
1030
1031        ret = nf_nat_register_fn(net, NFPROTO_IPV6, ops, nf_nat_ipv6_ops,
1032                                 ARRAY_SIZE(nf_nat_ipv6_ops));
1033        if (ret)
1034                return ret;
1035
1036        ret = nf_nat_register_fn(net, NFPROTO_IPV4, ops, nf_nat_ipv4_ops,
1037                                 ARRAY_SIZE(nf_nat_ipv4_ops));
1038        if (ret)
1039                nf_nat_unregister_fn(net, NFPROTO_IPV6, ops,
1040                                        ARRAY_SIZE(nf_nat_ipv6_ops));
1041        return ret;
1042}
1043EXPORT_SYMBOL_GPL(nf_nat_inet_register_fn);
1044
1045void nf_nat_inet_unregister_fn(struct net *net, const struct nf_hook_ops *ops)
1046{
1047        nf_nat_unregister_fn(net, NFPROTO_IPV4, ops, ARRAY_SIZE(nf_nat_ipv4_ops));
1048        nf_nat_unregister_fn(net, NFPROTO_IPV6, ops, ARRAY_SIZE(nf_nat_ipv6_ops));
1049}
1050EXPORT_SYMBOL_GPL(nf_nat_inet_unregister_fn);
1051#endif /* NFT INET NAT */
1052