cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

nf_nat_helper.c (5900B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* nf_nat_helper.c - generic support functions for NAT helpers
      3 *
      4 * (C) 2000-2002 Harald Welte <laforge@netfilter.org>
      5 * (C) 2003-2006 Netfilter Core Team <coreteam@netfilter.org>
      6 * (C) 2007-2012 Patrick McHardy <kaber@trash.net>
      7 */
      8#include <linux/module.h>
      9#include <linux/gfp.h>
     10#include <linux/types.h>
     11#include <linux/skbuff.h>
     12#include <linux/tcp.h>
     13#include <linux/udp.h>
     14#include <net/tcp.h>
     15
     16#include <net/netfilter/nf_conntrack.h>
     17#include <net/netfilter/nf_conntrack_helper.h>
     18#include <net/netfilter/nf_conntrack_ecache.h>
     19#include <net/netfilter/nf_conntrack_expect.h>
     20#include <net/netfilter/nf_conntrack_seqadj.h>
     21#include <net/netfilter/nf_nat.h>
     22#include <net/netfilter/nf_nat_helper.h>
     23
     24/* Frobs data inside this packet, which is linear. */
     25static void mangle_contents(struct sk_buff *skb,
     26			    unsigned int dataoff,
     27			    unsigned int match_offset,
     28			    unsigned int match_len,
     29			    const char *rep_buffer,
     30			    unsigned int rep_len)
     31{
     32	unsigned char *data;
     33
     34	SKB_LINEAR_ASSERT(skb);
     35	data = skb_network_header(skb) + dataoff;
     36
     37	/* move post-replacement */
     38	memmove(data + match_offset + rep_len,
     39		data + match_offset + match_len,
     40		skb_tail_pointer(skb) - (skb_network_header(skb) + dataoff +
     41			     match_offset + match_len));
     42
     43	/* insert data from buffer */
     44	memcpy(data + match_offset, rep_buffer, rep_len);
     45
     46	/* update skb info */
     47	if (rep_len > match_len) {
     48		pr_debug("nf_nat_mangle_packet: Extending packet by "
     49			 "%u from %u bytes\n", rep_len - match_len, skb->len);
     50		skb_put(skb, rep_len - match_len);
     51	} else {
     52		pr_debug("nf_nat_mangle_packet: Shrinking packet from "
     53			 "%u from %u bytes\n", match_len - rep_len, skb->len);
     54		__skb_trim(skb, skb->len + rep_len - match_len);
     55	}
     56
     57	if (nf_ct_l3num((struct nf_conn *)skb_nfct(skb)) == NFPROTO_IPV4) {
     58		/* fix IP hdr checksum information */
     59		ip_hdr(skb)->tot_len = htons(skb->len);
     60		ip_send_check(ip_hdr(skb));
     61	} else
     62		ipv6_hdr(skb)->payload_len =
     63			htons(skb->len - sizeof(struct ipv6hdr));
     64}
     65
     66/* Unusual, but possible case. */
     67static bool enlarge_skb(struct sk_buff *skb, unsigned int extra)
     68{
     69	if (skb->len + extra > 65535)
     70		return false;
     71
     72	if (pskb_expand_head(skb, 0, extra - skb_tailroom(skb), GFP_ATOMIC))
     73		return false;
     74
     75	return true;
     76}
     77
     78/* Generic function for mangling variable-length address changes inside
     79 * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX
     80 * command in FTP).
     81 *
     82 * Takes care about all the nasty sequence number changes, checksumming,
     83 * skb enlargement, ...
     84 *
     85 * */
     86bool __nf_nat_mangle_tcp_packet(struct sk_buff *skb,
     87				struct nf_conn *ct,
     88				enum ip_conntrack_info ctinfo,
     89				unsigned int protoff,
     90				unsigned int match_offset,
     91				unsigned int match_len,
     92				const char *rep_buffer,
     93				unsigned int rep_len, bool adjust)
     94{
     95	struct tcphdr *tcph;
     96	int oldlen, datalen;
     97
     98	if (skb_ensure_writable(skb, skb->len))
     99		return false;
    100
    101	if (rep_len > match_len &&
    102	    rep_len - match_len > skb_tailroom(skb) &&
    103	    !enlarge_skb(skb, rep_len - match_len))
    104		return false;
    105
    106	tcph = (void *)skb->data + protoff;
    107
    108	oldlen = skb->len - protoff;
    109	mangle_contents(skb, protoff + tcph->doff*4,
    110			match_offset, match_len, rep_buffer, rep_len);
    111
    112	datalen = skb->len - protoff;
    113
    114	nf_nat_csum_recalc(skb, nf_ct_l3num(ct), IPPROTO_TCP,
    115			   tcph, &tcph->check, datalen, oldlen);
    116
    117	if (adjust && rep_len != match_len)
    118		nf_ct_seqadj_set(ct, ctinfo, tcph->seq,
    119				 (int)rep_len - (int)match_len);
    120
    121	return true;
    122}
    123EXPORT_SYMBOL(__nf_nat_mangle_tcp_packet);
    124
    125/* Generic function for mangling variable-length address changes inside
    126 * NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX
    127 * command in the Amanda protocol)
    128 *
    129 * Takes care about all the nasty sequence number changes, checksumming,
    130 * skb enlargement, ...
    131 *
    132 * XXX - This function could be merged with nf_nat_mangle_tcp_packet which
    133 *       should be fairly easy to do.
    134 */
    135bool
    136nf_nat_mangle_udp_packet(struct sk_buff *skb,
    137			 struct nf_conn *ct,
    138			 enum ip_conntrack_info ctinfo,
    139			 unsigned int protoff,
    140			 unsigned int match_offset,
    141			 unsigned int match_len,
    142			 const char *rep_buffer,
    143			 unsigned int rep_len)
    144{
    145	struct udphdr *udph;
    146	int datalen, oldlen;
    147
    148	if (skb_ensure_writable(skb, skb->len))
    149		return false;
    150
    151	if (rep_len > match_len &&
    152	    rep_len - match_len > skb_tailroom(skb) &&
    153	    !enlarge_skb(skb, rep_len - match_len))
    154		return false;
    155
    156	udph = (void *)skb->data + protoff;
    157
    158	oldlen = skb->len - protoff;
    159	mangle_contents(skb, protoff + sizeof(*udph),
    160			match_offset, match_len, rep_buffer, rep_len);
    161
    162	/* update the length of the UDP packet */
    163	datalen = skb->len - protoff;
    164	udph->len = htons(datalen);
    165
    166	/* fix udp checksum if udp checksum was previously calculated */
    167	if (!udph->check && skb->ip_summed != CHECKSUM_PARTIAL)
    168		return true;
    169
    170	nf_nat_csum_recalc(skb, nf_ct_l3num(ct), IPPROTO_UDP,
    171			   udph, &udph->check, datalen, oldlen);
    172
    173	return true;
    174}
    175EXPORT_SYMBOL(nf_nat_mangle_udp_packet);
    176
    177/* Setup NAT on this expected conntrack so it follows master. */
    178/* If we fail to get a free NAT slot, we'll get dropped on confirm */
    179void nf_nat_follow_master(struct nf_conn *ct,
    180			  struct nf_conntrack_expect *exp)
    181{
    182	struct nf_nat_range2 range;
    183
    184	/* This must be a fresh one. */
    185	BUG_ON(ct->status & IPS_NAT_DONE_MASK);
    186
    187	/* Change src to where master sends to */
    188	range.flags = NF_NAT_RANGE_MAP_IPS;
    189	range.min_addr = range.max_addr
    190		= ct->master->tuplehash[!exp->dir].tuple.dst.u3;
    191	nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC);
    192
    193	/* For DST manip, map port here to where it's expected. */
    194	range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED);
    195	range.min_proto = range.max_proto = exp->saved_proto;
    196	range.min_addr = range.max_addr
    197		= ct->master->tuplehash[!exp->dir].tuple.src.u3;
    198	nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST);
    199}
    200EXPORT_SYMBOL(nf_nat_follow_master);