Example #1
0
static unsigned int
mark_tg(struct sk_buff *skb, const struct xt_action_param *par)
{
	const struct xt_mark_tginfo2 *info = par->targinfo;

	skb->mark = (skb->mark & ~info->mask) ^ info->mark;

#ifdef  HNDCTF
	{
		enum ip_conntrack_info ctinfo;
		struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
		if(ct) ct->ctf_flags |= CTF_FLAGS_EXCLUDED;
	}
#endif  /* HNDCTF */

	return XT_CONTINUE;
}
Example #2
0
/* function to be called by hook */
static unsigned int 
hook_func(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in,
          const struct net_device *out, int (*okfn)(struct sk_buff *))
{
    struct nf_conn *ct;
	enum ip_conntrack_info ctinfo;
    struct nf_conn_counter *acct;

    if (!skb) {
        return NF_ACCEPT;
    }

    if (in == NULL) {
        return NF_ACCEPT;
    } else if (in->name == NULL) {
        return NF_ACCEPT;
    }
    
    if (memcmp(devname, "all", 3) != 0) {
        if (memcmp(devname, in->name, 4) != 0) {
            return NF_ACCEPT;
        }
    }

    /* conntrack check */
    if (skb->nfct == NULL) {
        /* if (net_ratelimit())
         *     pr_info("skb->nfct == NULL!\n"); */
        return NF_ACCEPT;
    }
    ct = nf_ct_get(skb, &ctinfo);

    acct = nf_conn_acct_find(ct);
    if (!acct) {
        if (net_ratelimit())
            pr_info("acct is NULL\n");
        return NF_ACCEPT;
    }

	if (ct->proto.tcp.state == TCP_CONNTRACK_CLOSE_WAIT) {
        pr_info("%pI4 --> %pI4: %llu bytes CLOSE_WAIT\n", &iph->saddr, &iph->daddr, 
            acct[IP_CT_DIR_ORIGINAL].bytes + acct[IP_CT_DIR_REPLY].bytes);
    }

    return NF_ACCEPT;
}
Example #3
0
static int mangle_sdp_packet(struct sk_buff *skb, unsigned int dataoff,
			     const char **dptr, unsigned int *datalen,
			     unsigned int sdpoff,
			     enum sdp_header_types type,
			     enum sdp_header_types term,
			     char *buffer, int buflen)
{
	enum ip_conntrack_info ctinfo;
	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
	unsigned int matchlen, matchoff;

	if (ct_sip_get_sdp_header(ct, *dptr, sdpoff, *datalen, type, term,
				  &matchoff, &matchlen) <= 0)
		return -ENOENT;
	return mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen,
			     buffer, buflen) ? 0 : -EINVAL;
}
Example #4
0
static unsigned int
connmark_tg(struct sk_buff *skb, const struct xt_action_param *par)
{
	const struct xt_connmark_tginfo1 *info = par->targinfo;
	enum ip_conntrack_info ctinfo;
	struct nf_conn *ct;
	u_int32_t newmark;

	ct = nf_ct_get(skb, &ctinfo);
	if (ct == NULL)
		return XT_CONTINUE;

	switch (info->mode) {
	case XT_CONNMARK_SET:
		newmark = (ct->mark & ~info->ctmask) ^ info->ctmark;
		if (ct->mark != newmark) {
			ct->mark = newmark;
			nf_conntrack_event_cache(IPCT_MARK, ct);
		}
		break;
	case XT_CONNMARK_SAVE:
		newmark = (ct->mark & ~info->ctmask) ^
		          (skb->mark & info->nfmask);
		if (ct->mark != newmark) {
			ct->mark = newmark;
			nf_conntrack_event_cache(IPCT_MARK, ct);
		}
        
// ------------- START of KNOX_VPN -----------------//        
        knoxvpn_uidpid(skb,newmark);
// ------------- END of KNOX_VPN -------------------//

		break;
	case XT_CONNMARK_RESTORE:
		newmark = (skb->mark & ~info->nfmask) ^
		          (ct->mark & info->ctmask);
		skb->mark = newmark;

// ------------- START of KNOX_VPN -----------------//		
        knoxvpn_uidpid(skb,newmark);
// ------------- END of KNOX_VPN -------------------//

		break;
	}
	return XT_CONTINUE;
}
static unsigned int
ipt_dnat_target(struct sk_buff *skb, const struct xt_action_param *par)
{
	struct nf_conn *ct;
	enum ip_conntrack_info ctinfo;
	const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;

	NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING ||
		     par->hooknum == NF_INET_LOCAL_OUT);

	ct = nf_ct_get(skb, &ctinfo);

	/* Connection must be valid and new. */
	NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED));

	return nf_nat_setup_info(ct, &mr->range[0], NF_NAT_MANIP_DST);
}
Example #6
0
/* 'skb' should already be pulled to nh_ofs. */
static int ovs_ct_helper(struct sk_buff *skb, u16 proto)
{
	const struct nf_conntrack_helper *helper;
	const struct nf_conn_help *help;
	enum ip_conntrack_info ctinfo;
	unsigned int protoff;
	struct nf_conn *ct;

	ct = nf_ct_get(skb, &ctinfo);
	if (!ct || ctinfo == IP_CT_RELATED_REPLY)
		return NF_ACCEPT;

	help = nfct_help(ct);
	if (!help)
		return NF_ACCEPT;

	helper = rcu_dereference(help->helper);
	if (!helper)
		return NF_ACCEPT;

	switch (proto) {
	case NFPROTO_IPV4:
		protoff = ip_hdrlen(skb);
		break;
	case NFPROTO_IPV6: {
		u8 nexthdr = ipv6_hdr(skb)->nexthdr;
		__be16 frag_off;
		int ofs;

		ofs = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr,
				       &frag_off);
		if (ofs < 0 || (frag_off & htons(~0x7)) != 0) {
			pr_debug("proto header not found\n");
			return NF_ACCEPT;
		}
		protoff = ofs;
		break;
	}
	default:
		WARN_ONCE(1, "helper invoked on non-IP family!");
		return NF_DROP;
	}

	return helper->help(skb, protoff, ct, ctinfo);
}
Example #7
0
/*
 * vlantag_match_pre()
 *	One of the iptables hooks has a packet for us to analyze, do so.
 */
static bool vlantag_match_pre(const struct sk_buff *skb, const struct xt_action_param *par)
{
	const struct xt_vlantag_match_info *info = par->targinfo;
	struct nf_conn *ct;
	enum ip_conntrack_info ctinfo;
	struct nf_ct_vlantag_ext *ncve;
	unsigned short int prio;

	if (!is_vlan_dev(skb->dev)) {
		DEBUGP("pre dev %s is not vlan\n", skb->dev->name);
		return false;
	}

	ct = nf_ct_get(skb, &ctinfo);
	if (!ct) {
		DEBUGP("pre xt_VLANTAG: No conntrack connection\n");
		return false;
	}

	ncve = nf_ct_vlantag_ext_find(ct);
	if (!ncve) {
		DEBUGP("pre xt_VLANTAG: No conntrack extension\n");
		return false;
	}

	if ((skb->priority < XT_VLANTAG_SKB_PRIO_MIN) || (skb->priority > XT_VLANTAG_SKB_PRIO_MAX)) {
		DEBUGP("pre dev: %s skb prioriy %d is out of range (%d - %d)",
				skb->dev->name, skb->priority,
				XT_VLANTAG_SKB_PRIO_MIN, XT_VLANTAG_SKB_PRIO_MAX);
		return false;
	}

	prio = skb->priority - XT_VLANTAG_SKB_PRIO_MIN;
	if ((prio & info->imask) == info->itag) {
		ncve->prio = prio;
	} else {
		ncve->prio = XT_VLANTAG_EXT_PRIO_NOT_VALID;
	}

	ncve->imask = info->imask;
	ncve->itag =info->itag;

	DEBUGP("xt_VLANTAG: pre match continue\n");
	return true;
}
Example #8
0
static bool
lscan_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
	const struct xt_lscan_mtinfo *info = par->matchinfo;
	enum ip_conntrack_info ctstate;
	const struct tcphdr *tcph;
	struct nf_conn *ctdata;
	struct tcphdr tcph_buf;

	tcph = skb_header_pointer(skb, par->thoff, sizeof(tcph_buf), &tcph_buf);
	if (tcph == NULL)
		return false;

	/* Check for invalid packets: -m conntrack --ctstate INVALID */
	if ((ctdata = nf_ct_get(skb, &ctstate)) == NULL) {
		if (info->match_stealth)
			return lscan_mt_stealth(tcph);
		/*
		 * If @ctdata is NULL, we cannot match the other scan
		 * types, return.
		 */
		return false;
	}

	/*
	 * If -m lscan was previously applied to this packet, the rules we
	 * simulate must not be run through again. And for speedup, do not call
	 * it either when the connection is already VALID.
	 */
	if ((ctdata->mark & connmark_mask) == mark_valid ||
	     (skb_nfmark(skb) & packet_mask) != mark_seen) {
		unsigned int n;

		n = lscan_mt_full(ctdata->mark & connmark_mask, ctstate,
		    par->state->in == init_net.loopback_dev, tcph,
		    skb->len - par->thoff - 4 * tcph->doff);

		ctdata->mark = (ctdata->mark & ~connmark_mask) | n;
		skb_nfmark(skb) = (skb_nfmark(skb) & ~packet_mask) ^ mark_seen;
	}

	return (info->match_syn && ctdata->mark == mark_synscan) ||
	       (info->match_cn && ctdata->mark == mark_cnscan) ||
	       (info->match_gr && ctdata->mark == mark_grscan);
}
Example #9
0
/* Source NAT */
static unsigned int
ipt_snat_target(struct sk_buff *skb, const struct xt_action_param *par)
{
	struct nf_conn *ct;
	enum ip_conntrack_info ctinfo;
	const struct nf_nat_multi_range_compat *mr = par->targinfo;

	NF_CT_ASSERT(par->hooknum == NF_INET_POST_ROUTING);

	ct = nf_ct_get(skb, &ctinfo);

	/* Connection must be valid and new. */
	NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
			    ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY));
	NF_CT_ASSERT(par->out != NULL);

	return nf_nat_setup_info(ct, &mr->range[0], IP_NAT_MANIP_SRC);
}
Example #10
0
static unsigned int
nf_nat_adjust(unsigned int hooknum,
	      struct sk_buff *skb,
	      const struct net_device *in,
	      const struct net_device *out,
	      int (*okfn)(struct sk_buff *))
{
	struct nf_conn *ct;
	enum ip_conntrack_info ctinfo;

	ct = nf_ct_get(skb, &ctinfo);
	if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) {
		DEBUGP("nf_nat_standalone: adjusting sequence number\n");
		if (!nf_nat_seq_adjust(skb, ct, ctinfo))
			return NF_DROP;
	}
	return NF_ACCEPT;
}
Example #11
0
static bool
state_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
	const struct xt_state_info *sinfo = par->matchinfo;
	enum ip_conntrack_info ctinfo;
	unsigned int statebit;
	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);

	if (!ct)
		statebit = XT_STATE_INVALID;
	else {
		if (nf_ct_is_untracked(ct))
			statebit = XT_STATE_UNTRACKED;
		else
			statebit = XT_STATE_BIT(ctinfo);
	}
	return (sinfo->statemask & statebit);
}
static unsigned int ipv4_confirm(unsigned int hooknum,
				 struct sk_buff *skb,
				 const struct net_device *in,
				 const struct net_device *out,
				 int (*okfn)(struct sk_buff *))
{
	struct nf_conn *ct;
	enum ip_conntrack_info ctinfo;
	const struct nf_conn_help *help;
	const struct nf_conntrack_helper *helper;
	unsigned int ret;

	/* This is where we call the helper: as the packet goes out. */
	ct = nf_ct_get(skb, &ctinfo);
	if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)
		goto out;

	help = nfct_help(ct);
	if (!help)
		goto out;

	/* rcu_read_lock()ed by nf_hook_slow */
	helper = rcu_dereference(help->helper);
	if (!helper)
		goto out;

	ret = helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb),
			   ct, ctinfo);
	if (ret != NF_ACCEPT)
		return ret;

	if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) {
		typeof(nf_nat_seq_adjust_hook) seq_adjust;

		seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook);
		if (!seq_adjust || !seq_adjust(skb, ct, ctinfo)) {
			NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop);
			return NF_DROP;
		}
	}
out:
	/* We've seen it coming out the other side: confirm it */
	return nf_conntrack_confirm(skb);
}
Example #13
0
/*
 * vlantag_target_post()
 *	One of the iptables hooks has a packet for us to analyze, do so.
 */
static bool vlantag_target_post(struct sk_buff *skb, const struct xt_action_param *par)
{
	const struct xt_vlantag_target_info *info = par->targinfo;
	struct nf_conn *ct;
	enum ip_conntrack_info ctinfo;
	struct nf_ct_vlantag_ext *ncve;
	unsigned int vlan_prio;

	if (!is_vlan_dev(skb->dev)) {
		DEBUGP("post dev %s is not vlan\n", skb->dev->name);
		return true;
	}

	ct = nf_ct_get(skb, &ctinfo);
	if (!ct) {
		DEBUGP("post xt_VLANTAG: No conntrack connection\n");
		return true;
	}

	ncve = nf_ct_vlantag_ext_find(ct);
	if (!ncve) {
		DEBUGP("post No vlan tag extension\n");
		return true;
	}

	if (ncve->prio == XT_VLANTAG_EXT_PRIO_NOT_VALID) {
		DEBUGP("post vlan tag ext prio is not set\n");
		if ((skb->priority >= XT_VLANTAG_SKB_PRIO_MIN) && (skb->priority <= XT_VLANTAG_SKB_PRIO_MAX)) {
			DEBUGP("but skb prio %d is in the range of our iptables rule, drop the packet\n", skb->priority);
			return false;
		}
		return true;
	}

	vlan_prio = (ncve->prio & info->omask) | info->oval;
	skb->priority = vlan_prio + XT_VLANTAG_SKB_PRIO_MIN;

	ncve->magic = true;
	ncve->omask = info->omask;
	ncve->oval = info->oval;

	DEBUGP("post xt_VLANTAG: post target continue\n");
	return true;
}
Example #14
0
unsigned int tse6_adjust(unsigned int hooknum,
	      struct sk_buff **pskb,
	      const struct net_device *in,
	      const struct net_device *out,
	      int (*okfn)(struct sk_buff *))
{
	struct nf_conn *ct;
	enum ip_conntrack_info ctinfo;

	ct = nf_ct_get(*pskb, &ctinfo);
	if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status))
    {
		if (!tse6_seq_adjust(pskb, ct, ctinfo))
        {
            return NF_DROP;
		}
	}
	return NF_ACCEPT;
}
Example #15
0
/* Update 'key' based on skb->nfct. If 'post_ct' is true, then OVS has
 * previously sent the packet to conntrack via the ct action.
 */
static void ovs_ct_update_key(const struct sk_buff *skb,
                              struct sw_flow_key *key, bool post_ct)
{
    const struct nf_conntrack_zone *zone = &nf_ct_zone_dflt;
    enum ip_conntrack_info ctinfo;
    struct nf_conn *ct;
    u8 state = 0;

    ct = nf_ct_get(skb, &ctinfo);
    if (ct) {
        state = ovs_ct_get_state(ctinfo);
        if (ct->master)
            state |= OVS_CS_F_RELATED;
        zone = nf_ct_zone(ct);
    } else if (post_ct) {
        state = OVS_CS_F_TRACKED | OVS_CS_F_INVALID;
    }
    __ovs_ct_update_key(key, state, zone, ct);
}
static bool
state_mt(const struct sk_buff *skb, const struct net_device *in,
         const struct net_device *out, const struct xt_match *match,
         const void *matchinfo, int offset, unsigned int protoff,
         bool *hotdrop)
{
	const struct xt_state_info *sinfo = matchinfo;
	enum ip_conntrack_info ctinfo;
	unsigned int statebit;

	if (nf_ct_is_untracked(skb))
		statebit = XT_STATE_UNTRACKED;
	else if (!nf_ct_get(skb, &ctinfo))
		statebit = XT_STATE_INVALID;
	else
		statebit = XT_STATE_BIT(ctinfo);

	return (sinfo->statemask & statebit);
}
Example #17
0
static bool
xt_cluster_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
	struct sk_buff *pskb = (struct sk_buff *)skb;
	const struct xt_cluster_match_info *info = par->matchinfo;
	const struct nf_conn *ct;
	enum ip_conntrack_info ctinfo;
	unsigned long hash;

	/* This match assumes that all nodes see the same packets. This can be
	 * achieved if the switch that connects the cluster nodes support some
	 * sort of 'port mirroring'. However, if your switch does not support
	 * this, your cluster nodes can reply ARP request using a multicast MAC
	 * address. Thus, your switch will flood the same packets to the
	 * cluster nodes with the same multicast MAC address. Using a multicast
	 * link address is a RFC 1812 (section 3.3.2) violation, but this works
	 * fine in practise.
	 *
	 * Unfortunately, if you use the multicast MAC address, the link layer
	 * sets skbuff's pkt_type to PACKET_MULTICAST, which is not accepted
	 * by TCP and others for packets coming to this node. For that reason,
	 * this match mangles skbuff's pkt_type if it detects a packet
	 * addressed to a unicast address but using PACKET_MULTICAST. Yes, I
	 * know, matches should not alter packets, but we are doing this here
	 * because we would need to add a PKTTYPE target for this sole purpose.
	 */
	if (!xt_cluster_is_multicast_addr(skb, xt_family(par)) &&
	    skb->pkt_type == PACKET_MULTICAST) {
	    	pskb->pkt_type = PACKET_HOST;
	}

	ct = nf_ct_get(skb, &ctinfo);
	if (ct == NULL)
		return false;

	if (ct->master)
		hash = xt_cluster_hash(ct->master, info);
	else
		hash = xt_cluster_hash(ct, info);

	return !!((1 << hash) & info->node_mask) ^
	       !!(info->flags & XT_CLUSTER_F_INV);
}
Example #18
0
static unsigned int
target(struct sk_buff **pskb,
       const struct net_device *in,
       const struct net_device *out,
       unsigned int hooknum,
       const struct xt_target *target,
       const void *targinfo)
{
	const struct xt_connmark_target_info *markinfo = targinfo;
	struct nf_conn *ct;
	enum ip_conntrack_info ctinfo;
	u_int32_t diff;
	u_int32_t mark;
	u_int32_t newmark;

	ct = nf_ct_get(*pskb, &ctinfo);
	if (ct) {
		switch(markinfo->mode) {
		case XT_CONNMARK_SET:
			newmark = (ct->mark & ~markinfo->mask) | markinfo->mark;
			if (newmark != ct->mark) {
				ct->mark = newmark;
				nf_conntrack_event_cache(IPCT_MARK, *pskb);
			}
			break;
		case XT_CONNMARK_SAVE:
			newmark = (ct->mark & ~markinfo->mask) |
				  ((*pskb)->mark & markinfo->mask);
			if (ct->mark != newmark) {
				ct->mark = newmark;
				nf_conntrack_event_cache(IPCT_MARK, *pskb);
			}
			break;
		case XT_CONNMARK_RESTORE:
			mark = (*pskb)->mark;
			diff = (ct->mark ^ mark) & markinfo->mask;
			(*pskb)->mark = mark ^ diff;
			break;
		}
	}

	return XT_CONTINUE;
}
Example #19
0
unsigned int
nf_nat_ipv4_local_fn(const struct nf_hook_ops *ops, struct sk_buff *skb,
		     const struct net_device *in, const struct net_device *out,
		     unsigned int (*do_chain)(const struct nf_hook_ops *ops,
					       struct sk_buff *skb,
					       const struct net_device *in,
					       const struct net_device *out,
					       struct nf_conn *ct))
{
	const struct nf_conn *ct;
	enum ip_conntrack_info ctinfo;
	unsigned int ret;
	int err;

	/* root is playing with raw sockets. */
	if (skb->len < sizeof(struct iphdr) ||
	    ip_hdrlen(skb) < sizeof(struct iphdr))
		return NF_ACCEPT;

	ret = nf_nat_ipv4_fn(ops, skb, in, out, do_chain);
	if (ret != NF_DROP && ret != NF_STOLEN &&
	    (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
		enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);

		if (ct->tuplehash[dir].tuple.dst.u3.ip !=
		    ct->tuplehash[!dir].tuple.src.u3.ip) {
			err = ip_route_me_harder(skb, RTN_UNSPEC);
			if (err < 0)
				ret = NF_DROP_ERR(err);
		}
#ifdef CONFIG_XFRM
		else if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
			 ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP &&
			 ct->tuplehash[dir].tuple.dst.u.all !=
			 ct->tuplehash[!dir].tuple.src.u.all) {
			err = nf_xfrm_me_harder(skb, AF_INET);
			if (err < 0)
				ret = NF_DROP_ERR(err);
		}
#endif
	}
	return ret;
}
static unsigned int ipv6_confirm(unsigned int hooknum,
				 struct sk_buff **pskb,
				 const struct net_device *in,
				 const struct net_device *out,
				 int (*okfn)(struct sk_buff *))
{
	struct nf_conn *ct;
	struct nf_conn_help *help;
	struct nf_conntrack_helper *helper;
	enum ip_conntrack_info ctinfo;
	unsigned int ret, protoff;
	unsigned int extoff = (u8 *)(ipv6_hdr(*pskb) + 1) - (*pskb)->data;
	unsigned char pnum = ipv6_hdr(*pskb)->nexthdr;


	/* This is where we call the helper: as the packet goes out. */
	ct = nf_ct_get(*pskb, &ctinfo);
	if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)
		goto out;

	help = nfct_help(ct);
	if (!help)
		goto out;
	/* rcu_read_lock()ed by nf_hook_slow */
	helper = rcu_dereference(help->helper);
	if (!helper)
		goto out;

	protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum,
					 (*pskb)->len - extoff);
	if (protoff > (*pskb)->len || pnum == NEXTHDR_FRAGMENT) {
		DEBUGP("proto header not found\n");
		return NF_ACCEPT;
	}

	ret = helper->help(pskb, protoff, ct, ctinfo);
	if (ret != NF_ACCEPT)
		return ret;
out:
	/* We've seen it coming out the other side: confirm it */
	return nf_conntrack_confirm(pskb);
}
Example #21
0
static void nat_decode_session(struct sk_buff *skb, struct flowi *fl)
{
    struct flowi4 *fl4 = &fl->u.ip4;
    const struct nf_conn *ct;
    const struct nf_conntrack_tuple *t;
    enum ip_conntrack_info ctinfo;
    enum ip_conntrack_dir dir;
    unsigned long statusbit;

    ct = nf_ct_get(skb, &ctinfo);
    if (ct == NULL)
        return;
    dir = CTINFO2DIR(ctinfo);
    t = &ct->tuplehash[dir].tuple;

    if (dir == IP_CT_DIR_ORIGINAL)
        statusbit = IPS_DST_NAT;
    else
        statusbit = IPS_SRC_NAT;

    if (ct->status & statusbit) {
        fl4->daddr = t->dst.u3.ip;
        if (t->dst.protonum == IPPROTO_TCP ||
                t->dst.protonum == IPPROTO_UDP ||
                t->dst.protonum == IPPROTO_UDPLITE ||
                t->dst.protonum == IPPROTO_DCCP ||
                t->dst.protonum == IPPROTO_SCTP)
            fl4->fl4_dport = t->dst.u.tcp.port;
    }

    statusbit ^= IPS_NAT_MASK;

    if (ct->status & statusbit) {
        fl4->saddr = t->src.u3.ip;
        if (t->dst.protonum == IPPROTO_TCP ||
                t->dst.protonum == IPPROTO_UDP ||
                t->dst.protonum == IPPROTO_UDPLITE ||
                t->dst.protonum == IPPROTO_DCCP ||
                t->dst.protonum == IPPROTO_SCTP)
            fl4->fl4_sport = t->src.u.tcp.port;
    }
}
Example #22
0
static unsigned int nf_nat_sdp_addr(struct sk_buff *skb, unsigned int protoff,
				    unsigned int dataoff,
				    const char **dptr, unsigned int *datalen,
				    unsigned int sdpoff,
				    enum sdp_header_types type,
				    enum sdp_header_types term,
				    const union nf_inet_addr *addr)
{
	enum ip_conntrack_info ctinfo;
	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
	char buffer[INET6_ADDRSTRLEN];
	unsigned int buflen;

	buflen = sip_sprintf_addr(ct, buffer, addr, false);
	if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen,
			      sdpoff, type, term, buffer, buflen))
		return 0;

	return mangle_content_len(skb, protoff, dataoff, dptr, datalen);
}
Example #23
0
static int
match(const struct sk_buff *skb,
      const struct net_device *in,
      const struct net_device *out,
      const struct xt_match *match,
      const void *matchinfo,
      int offset,
      unsigned int protoff,
      int *hotdrop)
{
	const struct xt_connmark_info *info = matchinfo;
	struct nf_conn *ct;
	enum ip_conntrack_info ctinfo;

	ct = nf_ct_get(skb, &ctinfo);
	if (!ct)
		return 0;

	return (((ct->mark) & info->mask) == info->mark) ^ info->invert;
}
Example #24
0
static enum ip_defrag_users nf_ct_defrag_user(unsigned int hooknum,
					      struct sk_buff *skb)
{
	u16 zone_id = NF_CT_DEFAULT_ZONE_ID;
#if IS_ENABLED(CONFIG_NF_CONNTRACK)
	if (skb->nfct) {
		enum ip_conntrack_info ctinfo;
		const struct nf_conn *ct = nf_ct_get(skb, &ctinfo);

		zone_id = nf_ct_zone_id(nf_ct_zone(ct), CTINFO2DIR(ctinfo));
	}
#endif
	if (nf_bridge_in_prerouting(skb))
		return IP_DEFRAG_CONNTRACK_BRIDGE_IN + zone_id;

	if (hooknum == NF_INET_PRE_ROUTING)
		return IP_DEFRAG_CONNTRACK_IN + zone_id;
	else
		return IP_DEFRAG_CONNTRACK_OUT + zone_id;
}
Example #25
0
unsigned int
nf_nat_ipv6_local_fn(void *priv, struct sk_buff *skb,
		     const struct nf_hook_state *state,
		     unsigned int (*do_chain)(void *priv,
					      struct sk_buff *skb,
					      const struct nf_hook_state *state,
					      struct nf_conn *ct))
{
	const struct nf_conn *ct;
	enum ip_conntrack_info ctinfo;
	unsigned int ret;
	int err;

	/* root is playing with raw sockets. */
	if (skb->len < sizeof(struct ipv6hdr))
		return NF_ACCEPT;

	ret = nf_nat_ipv6_fn(priv, skb, state, do_chain);
	if (ret != NF_DROP && ret != NF_STOLEN &&
	    (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
		enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);

		if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3,
				      &ct->tuplehash[!dir].tuple.src.u3)) {
			err = ip6_route_me_harder(state->net, skb);
			if (err < 0)
				ret = NF_DROP_ERR(err);
		}
#ifdef CONFIG_XFRM
		else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
			 ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 &&
			 ct->tuplehash[dir].tuple.dst.u.all !=
			 ct->tuplehash[!dir].tuple.src.u.all) {
			err = nf_xfrm_me_harder(state->net, skb, AF_INET6);
			if (err < 0)
				ret = NF_DROP_ERR(err);
		}
#endif
	}
	return ret;
}
Example #26
0
static void nft_nat_eval(const struct nft_expr *expr,
			 struct nft_data data[NFT_REG_MAX + 1],
			 const struct nft_pktinfo *pkt)
{
	const struct nft_nat *priv = nft_expr_priv(expr);
	enum ip_conntrack_info ctinfo;
	struct nf_conn *ct = nf_ct_get(pkt->skb, &ctinfo);
	struct nf_nat_range range;

	memset(&range, 0, sizeof(range));
	if (priv->sreg_addr_min) {
		if (priv->family == AF_INET) {
			range.min_addr.ip = (__force __be32)
					data[priv->sreg_addr_min].data[0];
			range.max_addr.ip = (__force __be32)
					data[priv->sreg_addr_max].data[0];

		} else {
			memcpy(range.min_addr.ip6,
			       data[priv->sreg_addr_min].data,
			       sizeof(struct nft_data));
			memcpy(range.max_addr.ip6,
			       data[priv->sreg_addr_max].data,
			       sizeof(struct nft_data));
		}
		range.flags |= NF_NAT_RANGE_MAP_IPS;
	}

	if (priv->sreg_proto_min) {
		range.min_proto.all =
			*(__be16 *)&data[priv->sreg_proto_min].data[0];
		range.max_proto.all =
			*(__be16 *)&data[priv->sreg_proto_max].data[0];
		range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
	}

	range.flags |= priv->flags;

	data[NFT_REG_VERDICT].verdict =
		nf_nat_setup_info(ct, &range, priv->type);
}
Example #27
0
static unsigned int ipv4_conntrack_local(void *priv,
					 struct sk_buff *skb,
					 const struct nf_hook_state *state)
{
	if (ip_is_fragment(ip_hdr(skb))) { /* IP_NODEFRAG setsockopt set */
		enum ip_conntrack_info ctinfo;
		struct nf_conn *tmpl;

		tmpl = nf_ct_get(skb, &ctinfo);
		if (tmpl && nf_ct_is_template(tmpl)) {
			/* when skipping ct, clear templates to avoid fooling
			 * later targets/matches
			 */
			skb->_nfct = 0;
			nf_ct_put(tmpl);
		}
		return NF_ACCEPT;
	}

	return nf_conntrack_in(state->net, PF_INET, state->hook, skb);
}
/* 获取缓存socket的HOOK函数 */
static unsigned int ipv4_conntrack_restore_sock (unsigned int hooknum,  
                                      struct sk_buff *skb,  
                                      const struct net_device *in,  
                                      const struct net_device *out,  
                                      int (*okfn)(struct sk_buff *))  
{  
	struct nf_conn *ct;  
	enum ip_conntrack_info ctinfo;  
	struct nf_conntrack_ext *exts;
	ct = nf_ct_get(skb, &ctinfo);  
	if (!ct || ct == &nf_conntrack_untracked){
		goto out;
	}
	if ((ip_hdr(skb)->protocol != IPPROTO_UDP) && 
			(ip_hdr(skb)->protocol != IPPROTO_TCP)) {
		goto out;
	}

	exts = nf_conn_exts_find(ct);
	if (exts) {  
		/* 获取缓存的socket */
		if (exts->bits_idx[CONN_SOCK] != -1) {
			struct sock *sk = (struct sock *)nf_ct_exts_get(ct, exts->bits_idx[CONN_SOCK]);
			if (sk) {
				if ((ip_hdr(skb)->protocol == IPPROTO_TCP) && sk->sk_state != TCP_ESTABLISHED) {
					goto out;
				}
				if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) {
					goto out;
				}
				skb_orphan(skb);
				skb->sk = sk;
				/* 曾经在上面atomic inc了引用计数,等到转交给下任owner的时候,一定要put */
				skb->destructor = nf_ext_destructor;
			}
		}
	}
out:
	return NF_ACCEPT;
}
Example #29
0
unsigned int
nf_nat_ipv4_out(void *priv, struct sk_buff *skb,
		const struct nf_hook_state *state,
		unsigned int (*do_chain)(void *priv,
					  struct sk_buff *skb,
					  const struct nf_hook_state *state,
					  struct nf_conn *ct))
{
#ifdef CONFIG_XFRM
	const struct nf_conn *ct;
	enum ip_conntrack_info ctinfo;
	int err;
#endif
	unsigned int ret;

	/* root is playing with raw sockets. */
	if (skb->len < sizeof(struct iphdr) ||
	    ip_hdrlen(skb) < sizeof(struct iphdr))
		return NF_ACCEPT;

	ret = nf_nat_ipv4_fn(priv, skb, state, do_chain);
#ifdef CONFIG_XFRM
	if (ret != NF_DROP && ret != NF_STOLEN &&
	    !(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
	    (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
		enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);

		if ((ct->tuplehash[dir].tuple.src.u3.ip !=
		     ct->tuplehash[!dir].tuple.dst.u3.ip) ||
		    (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP &&
		     ct->tuplehash[dir].tuple.src.u.all !=
		     ct->tuplehash[!dir].tuple.dst.u.all)) {
			err = nf_xfrm_me_harder(state->net, skb, AF_INET);
			if (err < 0)
				ret = NF_DROP_ERR(err);
		}
	}
#endif
	return ret;
}
Example #30
0
unsigned int
nf_nat_ipv6_out(const struct nf_hook_ops *ops, struct sk_buff *skb,
		const struct net_device *in, const struct net_device *out,
		unsigned int (*do_chain)(const struct nf_hook_ops *ops,
					 struct sk_buff *skb,
					 const struct net_device *in,
					 const struct net_device *out,
					 struct nf_conn *ct))
{
#ifdef CONFIG_XFRM
	const struct nf_conn *ct;
	enum ip_conntrack_info ctinfo;
	int err;
#endif
	unsigned int ret;

	/* root is playing with raw sockets. */
	if (skb->len < sizeof(struct ipv6hdr))
		return NF_ACCEPT;

	ret = nf_nat_ipv6_fn(ops, skb, in, out, do_chain);
#ifdef CONFIG_XFRM
	if (ret != NF_DROP && ret != NF_STOLEN &&
	    !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
	    (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
		enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);

		if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3,
				      &ct->tuplehash[!dir].tuple.dst.u3) ||
		    (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 &&
		     ct->tuplehash[dir].tuple.src.u.all !=
		     ct->tuplehash[!dir].tuple.dst.u.all)) {
			err = nf_xfrm_me_harder(skb, AF_INET6);
			if (err < 0)
				ret = NF_DROP_ERR(err);
		}
	}
#endif
	return ret;
}