static void nat_decode_session(struct sk_buff *skb, struct flowi *fl)
{
	struct ip_conntrack *ct;
	struct ip_conntrack_tuple *t;
	enum ip_conntrack_info ctinfo;
	enum ip_conntrack_dir dir;
	unsigned long statusbit;

	ct = ip_conntrack_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) {
		fl->fl4_dst = t->dst.ip;
		if (t->dst.protonum == IPPROTO_TCP ||
		    t->dst.protonum == IPPROTO_UDP)
			fl->fl_ip_dport = t->dst.u.tcp.port;
	}

	statusbit ^= IPS_NAT_MASK;

	if (ct->status & statusbit) {
		fl->fl4_src = t->src.ip;
		if (t->dst.protonum == IPPROTO_TCP ||
		    t->dst.protonum == IPPROTO_UDP)
			fl->fl_ip_sport = t->src.u.tcp.port;
	}
}
Exemple #2
0
static unsigned int ipt_dnat_target(struct sk_buff **pskb,
				    const struct net_device *in,
				    const struct net_device *out,
				    unsigned int hooknum,
				    const void *targinfo,
				    void *userinfo)
{
	struct ip_conntrack *ct;
	enum ip_conntrack_info ctinfo;
	const struct ip_nat_multi_range_compat *mr = targinfo;

	IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
		     || hooknum == NF_IP_LOCAL_OUT);

	ct = ip_conntrack_get(*pskb, &ctinfo);

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

	if (hooknum == NF_IP_LOCAL_OUT
	    && mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)
		warn_if_extra_mangle((*pskb)->nh.iph->daddr,
				     mr->range[0].min_ip);

	return ip_nat_setup_info(ct, &mr->range[0], hooknum);
}
static unsigned int
ip_nat_local_fn(unsigned int hooknum,
		struct sk_buff **pskb,
		const struct net_device *in,
		const struct net_device *out,
		int (*okfn)(struct sk_buff *))
{
	struct ip_conntrack *ct;
	enum ip_conntrack_info ctinfo;
	unsigned int ret;

	/* root is playing with raw sockets. */
	if ((*pskb)->len < sizeof(struct iphdr)
	    || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
		return NF_ACCEPT;

	ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
	if (ret != NF_DROP && ret != NF_STOLEN
	    && (ct = ip_conntrack_get(*pskb, &ctinfo)) != NULL) {
		enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);

		if (ct->tuplehash[dir].tuple.dst.ip !=
		    ct->tuplehash[!dir].tuple.src.ip
#ifdef CONFIG_XFRM
		    || ct->tuplehash[dir].tuple.dst.u.all !=
		       ct->tuplehash[!dir].tuple.src.u.all
#endif
		    )
			if (ip_route_me_harder(pskb, RTN_UNSPEC))
				ret = NF_DROP;
	}
	return ret;
}
Exemple #4
0
static u_int32_t
get_led(struct sk_buff **pskb, const struct ipt_led_info *ledinfo)
{
#ifdef CONFIG_IP_NF_CONNTRACK
	enum ip_conntrack_info ctinfo;
	struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo);
#endif

	switch (ledinfo->mode) {
	case IPT_LED_SAVE:
#ifdef CONFIG_IP_NF_CONNTRACK
		if (ct)
			ct->led = ledinfo->led;
#endif
		/* fallthrough */
	case IPT_LED_SET:
		return ledinfo->led;
	case IPT_LED_RESTORE:
#ifdef CONFIG_IP_NF_CONNTRACK
		if (ct)
			return ct->led;
#endif
		/* fallthrough */
	default:
		return LEDMAN_MAX;
	}
}
Exemple #5
0
static int match(const struct sk_buff *skb,	const struct net_device *in, const struct net_device *out,
				 const void *matchinfo, int offset, const void *hdr, u_int16_t datalen, int *hotdrop)
{
	const struct ipt_bcount_match *info = matchinfo;
	struct ip_conntrack *ct;
	enum ip_conntrack_info ctinfo;

	ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
	if (!ct) return !info->invert;
	return ((ct->bcount >= info->min) && (ct->bcount <= info->max)) ^ info->invert;
}
static int set_addr(struct sk_buff **pskb,
		    unsigned char **data, int dataoff,
		    unsigned int addroff, __be32 ip, u_int16_t port)
{
	enum ip_conntrack_info ctinfo;
	struct ip_conntrack *ct = ip_conntrack_get(*pskb, &ctinfo);
	struct {
		__be32 ip;
		__be16 port;
	} __attribute__ ((__packed__)) buf;
	struct tcphdr _tcph, *th;

	buf.ip = ip;
	buf.port = htons(port);
	addroff += dataoff;

	if ((*pskb)->nh.iph->protocol == IPPROTO_TCP) {
		if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
					      addroff, sizeof(buf),
					      (char *) &buf, sizeof(buf))) {
			if (net_ratelimit())
				printk("ip_nat_h323: ip_nat_mangle_tcp_packet"
				       " error\n");
			return -1;
		}

		/* Relocate data pointer */
		th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4,
					sizeof(_tcph), &_tcph);
		if (th == NULL)
			return -1;
		*data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 +
		    th->doff * 4 + dataoff;
	} else {
		if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo,
					      addroff, sizeof(buf),
					      (char *) &buf, sizeof(buf))) {
			if (net_ratelimit())
				printk("ip_nat_h323: ip_nat_mangle_udp_packet"
				       " error\n");
			return -1;
		}
		/* ip_nat_mangle_udp_packet uses skb_make_writable() to copy
		 * or pull everything in a linear buffer, so we can safely
		 * use the skb pointers now */
		*data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 +
		    sizeof(struct udphdr);
	}

	return 0;
}
static int
match(const struct sk_buff *skb,
      const struct net_device *in,
      const struct net_device *out,
      const void *matchinfo,
      int offset,
      int *hotdrop)
{
	const struct ipt_helper_info *info = matchinfo;
	struct ip_conntrack_expect *exp;
	struct ip_conntrack *ct;
	enum ip_conntrack_info ctinfo;
	int ret = info->invert;
	
	ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
	if (!ct) {
		DEBUGP("ipt_helper: Eek! invalid conntrack?\n");
		return ret;
	}

	if (!ct->master) {
		DEBUGP("ipt_helper: conntrack %p has no master\n", ct);
		return ret;
	}

	exp = ct->master;
	READ_LOCK(&ip_conntrack_lock);
	if (!exp->expectant) {
		DEBUGP("ipt_helper: expectation %p without expectant !?!\n", 
			exp);
		goto out_unlock;
	}

	if (!exp->expectant->helper) {
		DEBUGP("ipt_helper: master ct %p has no helper\n", 
			exp->expectant);
		goto out_unlock;
	}

	DEBUGP("master's name = %s , info->name = %s\n", 
		exp->expectant->helper->name, info->name);

	if (info->name[0] == '\0')
		ret ^= 1;
	else
		ret ^= !strncmp(exp->expectant->helper->name, info->name, 
		                strlen(exp->expectant->helper->name));
out_unlock:
	READ_UNLOCK(&ip_conntrack_lock);
	return ret;
}
static unsigned int
target(struct sk_buff **pskb,
       unsigned int hooknum,
       const struct net_device *in,
       const struct net_device *out,
       const void *targinfo,
       void *userinfo)
{
	enum ip_conntrack_info ctinfo;
	struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo);

	if (ct)
		set_bit(IPS_LOG_BIT, &ct->status);

	return IPT_CONTINUE;
}
Exemple #9
0
static int
match(const struct sk_buff *skb,
      const struct net_device *in,
      const struct net_device *out,
      const void *matchinfo,
      int offset,
      const void *hdr,
      u_int16_t datalen,
      int *hotdrop)
{
	const struct ipt_connmark_info *info = matchinfo;
	enum ip_conntrack_info ctinfo;
	struct ip_conntrack *ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
	if (!ct)
	    return 0;

	return ((ct->mark & info->mask) == info->mark) ^ info->invert;
}
static unsigned int
ip_nat_adjust(unsigned int hooknum,
	      struct sk_buff **pskb,
	      const struct net_device *in,
	      const struct net_device *out,
	      int (*okfn)(struct sk_buff *))
{
	struct ip_conntrack *ct;
	enum ip_conntrack_info ctinfo;

	ct = ip_conntrack_get(*pskb, &ctinfo);
	if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) {
	        DEBUGP("ip_nat_standalone: adjusting sequence number\n");
	        if (!ip_nat_seq_adjust(pskb, ct, ctinfo))
	                return NF_DROP;
	}
	return NF_ACCEPT;
}
Exemple #11
0
static int
match(const struct sk_buff *skb,
      const struct net_device *in,
      const struct net_device *out,
      const void *matchinfo,
      int offset,
      int *hotdrop)
{
	const struct ipt_state_info *sinfo = matchinfo;
	enum ip_conntrack_info ctinfo;
	unsigned int statebit;

	if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo))
		statebit = IPT_STATE_INVALID;
	else
		statebit = IPT_STATE_BIT(ctinfo);

	return (sinfo->statemask & statebit);
}
static unsigned int ip_confirm(unsigned int hooknum,
			       struct sk_buff **pskb,
			       const struct net_device *in,
			       const struct net_device *out,
			       int (*okfn)(struct sk_buff *))
{
	struct ip_conntrack *ct;
	enum ip_conntrack_info ctinfo;

	/* This is where we call the helper: as the packet goes out. */
	ct = ip_conntrack_get(*pskb, &ctinfo);
	if (ct && ct->helper) {
		unsigned int ret;
		ret = ct->helper->help(pskb, ct, ctinfo);
		if (ret != NF_ACCEPT)
			return ret;
	}

	/* We've seen it coming out the other side: confirm it */
	return ip_conntrack_confirm(pskb);
}
Exemple #13
0
static unsigned int
target(struct sk_buff **pskb,
       unsigned int hooknum,
       const struct net_device *in,
       const struct net_device *out,
       const void *targinfo,
       void *userinfo)
{
	const struct ipt_connmark_target_info *markinfo = targinfo;
	unsigned long diff;
	unsigned long nfmark;
	unsigned long newmark;

	enum ip_conntrack_info ctinfo;
	struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo);
	if (ct) {
	    switch(markinfo->mode) {
	    case IPT_CONNMARK_SET:
		newmark = (ct->mark & ~markinfo->mask) | markinfo->mark;
		if (newmark != ct->mark)
		    ct->mark = newmark;
		break;
	    case IPT_CONNMARK_SAVE:
		newmark = (ct->mark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask);
		if (ct->mark != newmark)
		    ct->mark = newmark;
		break;
	    case IPT_CONNMARK_RESTORE:
		nfmark = (*pskb)->nfmark;
		diff = (ct->mark ^ nfmark & markinfo->mask);
		if (diff != 0) {
		    (*pskb)->nfmark = nfmark ^ diff;
		    (*pskb)->nfcache |= NFC_ALTERED;
		}
		break;
	    }
	}

	return IPT_CONTINUE;
}
Exemple #14
0
/* Source NAT */
static unsigned int ipt_snat_target(struct sk_buff **pskb,
				    const struct net_device *in,
				    const struct net_device *out,
				    unsigned int hooknum,
				    const void *targinfo,
				    void *userinfo)
{
	struct ip_conntrack *ct;
	enum ip_conntrack_info ctinfo;
	const struct ip_nat_multi_range_compat *mr = targinfo;

	IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING);

	ct = ip_conntrack_get(*pskb, &ctinfo);

	/* Connection must be valid and new. */
	IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED
	                    || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY));
	IP_NF_ASSERT(out);

	return ip_nat_setup_info(ct, &mr->range[0], hooknum);
}
static unsigned int
ip_nat_fn(unsigned int hooknum,
	  struct sk_buff **pskb,
	  const struct net_device *in,
	  const struct net_device *out,
	  int (*okfn)(struct sk_buff *))
{
	struct ip_conntrack *ct;
	enum ip_conntrack_info ctinfo;
	struct ip_nat_info *info;
	/* maniptype == SRC for postrouting. */
	enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum);

	/* We never see fragments: conntrack defrags on pre-routing
	   and local-out, and ip_nat_out protects post-routing. */
	IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
		       & htons(IP_MF|IP_OFFSET)));

	(*pskb)->nfcache |= NFC_UNKNOWN;

	/* If we had a hardware checksum before, it's now invalid */
	if ((*pskb)->ip_summed == CHECKSUM_HW)
		if (skb_checksum_help(*pskb, (out == NULL)))
			return NF_DROP;

	ct = ip_conntrack_get(*pskb, &ctinfo);
	/* Can't track?  It's not due to stress, or conntrack would
	   have dropped it.  Hence it's the user's responsibilty to
	   packet filter it out, or implement conntrack/NAT for that
	   protocol. 8) --RR */
	if (!ct) {
		/* Exception: ICMP redirect to new connection (not in
                   hash table yet).  We must not let this through, in
                   case we're doing NAT to the same network. */
		if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
			struct icmphdr _hdr, *hp;

			hp = skb_header_pointer(*pskb,
						(*pskb)->nh.iph->ihl*4,
						sizeof(_hdr), &_hdr);
			if (hp != NULL &&
			    hp->type == ICMP_REDIRECT)
				return NF_DROP;
		}
		return NF_ACCEPT;
	}

	switch (ctinfo) {
	case IP_CT_RELATED:
	case IP_CT_RELATED+IP_CT_IS_REPLY:
		if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
			if (!icmp_reply_translation(pskb, ct, maniptype,
						    CTINFO2DIR(ctinfo)))
				return NF_DROP;
			else
				return NF_ACCEPT;
		}
		/* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
	case IP_CT_NEW:
		info = &ct->nat.info;

		/* Seen it before?  This can happen for loopback, retrans,
		   or local packets.. */
		if (!ip_nat_initialized(ct, maniptype)) {
			unsigned int ret;

			/* LOCAL_IN hook doesn't have a chain!  */
			if (hooknum == NF_IP_LOCAL_IN)
				ret = alloc_null_binding(ct, info, hooknum);
			else
				ret = ip_nat_rule_find(pskb, hooknum,
						       in, out, ct,
						       info);

			if (ret != NF_ACCEPT) {
				return ret;
			}
		} else
			DEBUGP("Already setup manip %s for ct %p\n",
			       maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST",
			       ct);
		break;

	default:
		/* ESTABLISHED */
		IP_NF_ASSERT(ctinfo == IP_CT_ESTABLISHED
			     || ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY));
		info = &ct->nat.info;
	}

	IP_NF_ASSERT(info);
	return nat_packet(ct, ctinfo, hooknum, pskb);
}
static unsigned int
ip_nat_fn(unsigned int hooknum,
	  struct sk_buff **pskb,
	  const struct net_device *in,
	  const struct net_device *out,
	  int (*okfn)(struct sk_buff *))
{
	struct ip_conntrack *ct;
	enum ip_conntrack_info ctinfo;
	struct ip_nat_info *info;
	/* maniptype == SRC for postrouting. */
	enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum);

	/* We never see fragments: conntrack defrags on pre-routing
	   and local-out, and ip_nat_out protects post-routing. */
	IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
		       & htons(IP_MF|IP_OFFSET)));

	(*pskb)->nfcache |= NFC_UNKNOWN;

	/* If we had a hardware checksum before, it's now invalid */
	if ((*pskb)->ip_summed == CHECKSUM_HW)
		(*pskb)->ip_summed = CHECKSUM_NONE;

	ct = ip_conntrack_get(*pskb, &ctinfo);
	/* Can't track?  It's not due to stress, or conntrack would
	   have dropped it.  Hence it's the user's responsibilty to
	   packet filter it out, or implement conntrack/NAT for that
	   protocol. 8) --RR */
	if (!ct) {
		/* Exception: ICMP redirect to new connection (not in
                   hash table yet).  We must not let this through, in
                   case we're doing NAT to the same network. */
		struct iphdr *iph = (*pskb)->nh.iph;
		struct icmphdr *hdr = (struct icmphdr *)
			((u_int32_t *)iph + iph->ihl);
		if (iph->protocol == IPPROTO_ICMP
		    && hdr->type == ICMP_REDIRECT)
			return NF_DROP;
		return NF_ACCEPT;
	}

	switch (ctinfo) {
	case IP_CT_RELATED:
	case IP_CT_RELATED+IP_CT_IS_REPLY:
		if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
			return icmp_reply_translation(*pskb, ct, hooknum,
						      CTINFO2DIR(ctinfo));
		}
		/* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
	case IP_CT_NEW:
#ifdef CONFIG_IP_NF_NAT_LOCAL
		/* LOCAL_IN hook doesn't have a chain and thus doesn't care
		 * about new packets -HW */
		if (hooknum == NF_IP_LOCAL_IN)
			return NF_ACCEPT;
#endif
		info = &ct->nat.info;

		WRITE_LOCK(&ip_nat_lock);
		/* Seen it before?  This can happen for loopback, retrans,
		   or local packets.. */
		if (!(info->initialized & (1 << maniptype))) {
			int in_hashes = info->initialized;
			unsigned int ret;

			if (ct->master
			    && master_ct(ct)->nat.info.helper
			    && master_ct(ct)->nat.info.helper->expect) {
				ret = call_expect(master_ct(ct), pskb, 
						  hooknum, ct, info);
			} else {
				ret = ip_nat_rule_find(pskb, hooknum, in, out,
						       ct, info);
			}

			if (ret != NF_ACCEPT) {
				WRITE_UNLOCK(&ip_nat_lock);
				return ret;
			}

			if (in_hashes) {
				IP_NF_ASSERT(info->bysource.conntrack);
				replace_in_hashes(ct, info);
			} else {
				place_in_hashes(ct, info);
			}
		} else
			DEBUGP("Already setup manip %s for ct %p\n",
			       maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST",
			       ct);
		WRITE_UNLOCK(&ip_nat_lock);
		break;

	default:
		/* ESTABLISHED */
		IP_NF_ASSERT(ctinfo == IP_CT_ESTABLISHED
			     || ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY));
		info = &ct->nat.info;
	}

	IP_NF_ASSERT(info);
	return do_bindings(ct, ctinfo, info, hooknum, pskb);
}
static int
match(const struct sk_buff *skb,
      const struct net_device *in,
      const struct net_device *out,
      const void *matchinfo,
      int offset,
      unsigned int protoff,
      int *hotdrop)
{
	const struct xt_conntrack_info *sinfo = matchinfo;
	struct ip_conntrack *ct;
	enum ip_conntrack_info ctinfo;
	unsigned int statebit;

	ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);

#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))

	if (ct == &ip_conntrack_untracked)
		statebit = XT_CONNTRACK_STATE_UNTRACKED;
	else if (ct)
 		statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
 	else
 		statebit = XT_CONNTRACK_STATE_INVALID;
 
	if(sinfo->flags & XT_CONNTRACK_STATE) {
		if (ct) {
			if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip !=
			    ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip)
				statebit |= XT_CONNTRACK_STATE_SNAT;

			if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip !=
			    ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip)
				statebit |= XT_CONNTRACK_STATE_DNAT;
		}

		if (FWINV((statebit & sinfo->statemask) == 0, XT_CONNTRACK_STATE))
			return 0;
	}

	if(sinfo->flags & XT_CONNTRACK_PROTO) {
		if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, XT_CONNTRACK_PROTO))
                	return 0;
	}

	if(sinfo->flags & XT_CONNTRACK_ORIGSRC) {
		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, XT_CONNTRACK_ORIGSRC))
			return 0;
	}

	if(sinfo->flags & XT_CONNTRACK_ORIGDST) {
		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, XT_CONNTRACK_ORIGDST))
			return 0;
	}

	if(sinfo->flags & XT_CONNTRACK_REPLSRC) {
		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, XT_CONNTRACK_REPLSRC))
			return 0;
	}

	if(sinfo->flags & XT_CONNTRACK_REPLDST) {
		if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, XT_CONNTRACK_REPLDST))
			return 0;
	}

	if(sinfo->flags & XT_CONNTRACK_STATUS) {
		if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, XT_CONNTRACK_STATUS))
			return 0;
	}

	if(sinfo->flags & XT_CONNTRACK_EXPIRES) {
		unsigned long expires;

		if(!ct)
			return 0;

		expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0;

		if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), XT_CONNTRACK_EXPIRES))
			return 0;
	}

	return 1;
}
Exemple #18
0
static unsigned int
napt_handle(unsigned int hooknum,
            struct sk_buff **pskb,
            const struct net_device *in,
            const struct net_device *out, int (*okfn) (struct sk_buff *))
{
    struct ip_conntrack *ct;
    enum ip_conntrack_info ctinfo;
    uint8_t *saddr, *daddr, *ssaddr, *sdaddr, *tsaddr, *tdaddr;
    uint32_t usaddr, udaddr, usport, udport, tusaddr, tusport;
    struct iphdr *iph = (*pskb)->nh.iph;
    struct udphdr *uh = ((struct udphdr *) (*pskb)->h.uh + 20);

    struct tftphdr *tftph = ((struct tftphdr *) (*pskb)->h.uh + 28);
    fal_napt_entry_t napt_entry;

    saddr = (uint8_t *) & iph->saddr;
    daddr = (uint8_t *) & iph->daddr;

    if (daddr[0] == 255)
        return NF_ACCEPT;
    ct = ip_conntrack_get(*pskb, &ctinfo);
    if (!ct)
        return NF_ACCEPT;
    if (((ct->status & IPS_NAT_MASK) != IPS_SRC_NAT)
            &&((ct->status & IPS_NAT_MASK) != IPS_DST_NAT))
        return NF_ACCEPT;

    ssaddr = (uint8_t *) (&ct->tuplehash[0].tuple.src.ip);
    tsaddr = (uint8_t *) (&ct->tuplehash[0].tuple.dst.ip);
    sdaddr = (uint8_t *) (&ct->tuplehash[1].tuple.src.ip);
    tdaddr = (uint8_t *) (&ct->tuplehash[1].tuple.dst.ip);
    if ((ct->status & IPS_NAT_MASK) == IPS_SRC_NAT) {   //snat
        usaddr = ct->tuplehash[0].tuple.src.ip;
        usport = ct->tuplehash[0].tuple.src.u.all;
        udaddr = ct->tuplehash[0].tuple.dst.ip;
        udport = ct->tuplehash[0].tuple.dst.u.all;
        tusaddr = ct->tuplehash[1].tuple.dst.ip;
        tusport = ct->tuplehash[1].tuple.dst.u.all;
    } else {                    //dnat
        usaddr = ct->tuplehash[1].tuple.src.ip;
        usport = ct->tuplehash[1].tuple.src.u.all;
        udaddr = ct->tuplehash[1].tuple.dst.ip;
        udport = ct->tuplehash[1].tuple.dst.u.all;
        tusaddr = ct->tuplehash[0].tuple.dst.ip;
        tusport = ct->tuplehash[0].tuple.dst.u.all;
    }

    if (iph->protocol == P_TCP) {
        //IPS_SRC_NAT IPS_DST_NAT
        if ((ct->proto.tcp.state == TCP_CONNTRACK_SYN_RECV)
                || (ct->proto.tcp.state == TCP_CONNTRACK_CLOSE)) {
            memset((void *) &napt_entry, 0, sizeof (fal_napt_entry_t));

            napt_entry.counter_en = 1;
            napt_entry.counter_id = debug_counter;
            if(++debug_counter == 8) debug_counter = 0;

            napt_entry.flags = FAL_NAT_ENTRY_PROTOCOL_TCP | FAL_NAT_ENTRY_TRANS_IPADDR_INDEX;
            napt_entry.src_addr = usaddr;
            napt_entry.src_port = usport;
            napt_entry.dst_addr = udaddr;
            napt_entry.dst_port = udport;
            napt_entry.trans_addr = public_ip_add(tusaddr);
            napt_entry.trans_port = tusport;
            napt_entry.status = NAPT_AGE;
        }
        if (!ct->helper) {
            if (ct->proto.tcp.state == TCP_CONNTRACK_SYN_RECV) {
                printk("isis_napt_add####(pub:%x)####\n", napt_entry.trans_addr);
                isis_napt_add(0, &napt_entry);
                napt_death(ct, &napt_entry);
            } else if (ct->proto.tcp.state == TCP_CONNTRACK_CLOSE) {

                printk("isis_napt_del########\n");
                /*if hw nat work, we recv the close any more*/
                isis_napt_del(0, FAL_NAT_ENTRY_ID_EN, &napt_entry);
            }
        } else if (ct->proto.tcp.state == TCP_CONNTRACK_ESTABLISHED) {
            /*need kernel support ip_conntrack_pptp.ko and ip_nat_pptp.ko*/
            if (!strcmp(ct->helper->name, "pptp")) {
                printk
                ("PPTP Session state %d, Call state %d, PAC Call ID %d to %d, PNS Call ID %d to %d\n",
                 ct->help.ct_pptp_info.sstate,
                 ct->help.ct_pptp_info.cstate,
                 ntohs(ct->help.ct_pptp_info.pac_call_id),
                 ntohs(ct->nat.help.nat_pptp_info.pac_call_id),
                 ntohs(ct->help.ct_pptp_info.pns_call_id),
                 ntohs(ct->nat.help.nat_pptp_info.pns_call_id));
                if (((ct->help.ct_pptp_info.sstate == PPTP_SESSION_CONFIRMED)
                        && (ct->help.ct_pptp_info.cstate == PPTP_CALL_OUT_REQ))
                        || (ct->help.ct_pptp_info.sstate == PPTP_SESSION_STOPREQ)) {
                    memset((void *) &napt_entry, 0, sizeof (fal_napt_entry_t));

                    napt_entry.counter_en = 1;
                    napt_entry.counter_id = debug_counter;
                    if(++debug_counter == 8) debug_counter = 0;

                    napt_entry.flags =
                        FAL_NAT_ENTRY_PROTOCOL_PPTP |
                        FAL_NAT_ENTRY_TRANS_IPADDR_INDEX;
                    napt_entry.src_addr = usaddr;
                    napt_entry.src_port = ct->help.ct_pptp_info.pns_call_id;
                    napt_entry.dst_addr = udaddr;
                    napt_entry.dst_port = 0;
                    napt_entry.trans_addr = 15;
                    napt_entry.trans_port =
                        ct->nat.help.nat_pptp_info.pns_call_id;
                    napt_entry.status = NAPT_AGE;
                }
                if ((ct->help.ct_pptp_info.sstate == PPTP_SESSION_CONFIRMED)
                        && (ct->help.ct_pptp_info.cstate == PPTP_CALL_OUT_REQ)) {
                    printk("pptp_isis_napt_add########\n");
                    isis_napt_add(0, &napt_entry);
                    napt_death(ct, &napt_entry);
                } else if (ct->help.ct_pptp_info.sstate == PPTP_SESSION_STOPREQ) {
                    printk("pptp_isis_napt_del########\n");
                    /*if hw nat work, we recv the close any more*/
                    isis_napt_del(0, FAL_NAT_ENTRY_ID_EN, &napt_entry);
                }
            }

        }
    }
    else if (iph->protocol == P_UDP) {
        /*need kernel support ip_conntrack_tftp.ko and ip_nat_tftp.ko*/
        if (ct->master && ct->master->helper
                && !strcmp(ct->master->helper->name, "tftp")) {
            if ((ct->status == 0x191 || ct->status == 0x1a1) ||
                    ((ntohs(uh->len) - 12 < 512) && (ntohs(tftph->opcode) == TFTP_OPCODE_DATA))) {
                memset((void *) &napt_entry, 0, sizeof (fal_napt_entry_t));

                napt_entry.counter_en = 1;
                napt_entry.counter_id = debug_counter;
                if(++debug_counter == 8) debug_counter = 0;

                napt_entry.flags =
                    FAL_NAT_ENTRY_PROTOCOL_UDP |
                    FAL_NAT_ENTRY_TRANS_IPADDR_INDEX;
                napt_entry.src_addr = usaddr;
                napt_entry.src_port = usport;
                napt_entry.dst_addr = udaddr;
                napt_entry.dst_port = udport;
                napt_entry.trans_addr = 15;
                napt_entry.trans_port = tusport;
                napt_entry.status = NAPT_AGE;
            }
            if (ct->status == 0x191 || ct->status == 0x1a1) {  //add
                printk("tftp_isis_napt_add########\n");
                isis_napt_add(0, &napt_entry);
                napt_death(ct, &napt_entry);

            } else if ((ntohs(uh->len) - 12 < 512) && (ntohs(tftph->opcode) == TFTP_OPCODE_DATA)) {    //del
                printk("tftp_isis_napt_del########\n");
                /*if hw nat work, we recv the close any more*/
                isis_napt_del(0, FAL_NAT_ENTRY_ID_EN, &napt_entry);
            }
        }
    }
    return NF_ACCEPT;
}
static unsigned int
ip_nat_fn(unsigned int hooknum,
	  struct sk_buff **pskb,
	  const struct net_device *in,
	  const struct net_device *out,
	  int (*okfn)(struct sk_buff *))
{
	struct ip_conntrack *ct;
	enum ip_conntrack_info ctinfo;
	struct ip_nat_info *info;
	/* maniptype == SRC for postrouting. */
	enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum);
/* jimmy added 20080324 */
	struct sip_rtp_binding *sip_rtp_binding_tmp = NULL;
/* --------------------------------- */

	/* We never see fragments: conntrack defrags on pre-routing
	   and local-out, and ip_nat_out protects post-routing. */
	IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
		       & htons(IP_MF|IP_OFFSET)));

	/* If we had a hardware checksum before, it's now invalid */
	if ((*pskb)->ip_summed == CHECKSUM_HW)
		if (skb_checksum_help(*pskb, (out == NULL)))
			return NF_DROP;

	ct = ip_conntrack_get(*pskb, &ctinfo);
	/* Can't track?  It's not due to stress, or conntrack would
	   have dropped it.  Hence it's the user's responsibilty to
	   packet filter it out, or implement conntrack/NAT for that
	   protocol. 8) --RR */
	if (!ct) {
		/* Exception: ICMP redirect to new connection (not in
                   hash table yet).  We must not let this through, in
                   case we're doing NAT to the same network. */
		if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
			struct icmphdr _hdr, *hp;

			hp = skb_header_pointer(*pskb,
						(*pskb)->nh.iph->ihl*4,
						sizeof(_hdr), &_hdr);
			if (hp != NULL &&
			    hp->type == ICMP_REDIRECT)
				return NF_DROP;
		}
		return NF_ACCEPT;
	}

	/* Don't try to NAT if this packet is not conntracked */
	if (ct == &ip_conntrack_untracked)
		return NF_ACCEPT;

	switch (ctinfo) {
	case IP_CT_RELATED:
	case IP_CT_RELATED+IP_CT_IS_REPLY:
		if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
			if (!ip_nat_icmp_reply_translation(pskb, ct, maniptype,
							   CTINFO2DIR(ctinfo)))
				return NF_DROP;
			else
				return NF_ACCEPT;
		}
		/* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
	case IP_CT_NEW:
		info = &ct->nat.info;

		/* Seen it before?  This can happen for loopback, retrans,
		   or local packets.. */
		if (!ip_nat_initialized(ct, maniptype)) {
			unsigned int ret;

			if (unlikely(is_confirmed(ct)))
				/* NAT module was loaded late */
				ret = alloc_null_binding_confirmed(ct, info,
				                                   hooknum);
			else if (hooknum == NF_IP_LOCAL_IN)
				/* LOCAL_IN hook doesn't have a chain!  */
				ret = alloc_null_binding(ct, info, hooknum);
			else{
				ret = ip_nat_rule_find(pskb, hooknum,
						       in, out, ct,
						       info);
/* jimmy added 20080324 */
				if((hooknum == NF_IP_POST_ROUTING) && ((*pskb)->nh.iph->protocol == IPPROTO_UDP)){
					sip_rtp_binding_tmp = sip_rtp_binding_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip,
										ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip);
					if(sip_rtp_binding_tmp){
					/* jimmy added 20080328, for avoid sip pattern 100 run through in */
						if( sip_rtp_binding_tmp->wan_uac_port && 
							(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all == sip_rtp_binding_tmp->wan_uac_port)){
					/* ----------------------------------------------- */
						if(sip_rtp_binding_tmp->router_port && sip_rtp_binding_tmp->router_ip &&
							(sip_rtp_binding_tmp->router_ip == ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip) &&
							(sip_rtp_binding_tmp->router_port != ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all)){
							write_lock_bh(&ip_conntrack_lock);
							ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all = sip_rtp_binding_tmp->router_port;
							write_unlock_bh(&ip_conntrack_lock);

							DEBUGP("After modified conntrack for sip incoming conntrack hash, this ct are\n");
							DEBUGP("[IP_CT_DIR_REPLY] : %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n",
								ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum,
								NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip), ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all),
								NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip), ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all));
							DEBUGP("[IP_CT_DIR_ORIGINAL] : %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n",
								ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum,
								NIPQUAD(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip), ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all),
								NIPQUAD(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip), ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.all));
						}
					/* jimmy added 20080328, for avoid sip pattern 100 */
						}
					/* ----------------------------------------------- */
					}
				}
/* ---------------------- */
			}
			if (ret != NF_ACCEPT) {
				return ret;
			}
		} else
			DEBUGP("Already setup manip %s for ct %p\n",
			       maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST",
			       ct);
		break;

	default:
		/* ESTABLISHED */
		IP_NF_ASSERT(ctinfo == IP_CT_ESTABLISHED
			     || ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY));
		info = &ct->nat.info;
	}

	IP_NF_ASSERT(info);
	return ip_nat_packet(ct, ctinfo, hooknum, pskb);
}
Exemple #20
0
static unsigned int
ip_nat_fn(unsigned int hooknum,
	  struct sk_buff **pskb,
	  const struct net_device *in,
	  const struct net_device *out,
	  int (*okfn)(struct sk_buff *))
{
	struct ip_conntrack *ct;
	enum ip_conntrack_info ctinfo;
	struct ip_nat_info *info;
	/* maniptype == SRC for postrouting. */
	enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum);

	/* We never see fragments: conntrack defrags on pre-routing
	   and local-out, and ip_nat_out protects post-routing. */
	IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
		       & __constant_htons(IP_MF|IP_OFFSET)));

	(*pskb)->nfcache |= NFC_UNKNOWN;

	/* If we had a hardware checksum before, it's now invalid */
	if ((*pskb)->pkt_type != PACKET_LOOPBACK)
		(*pskb)->ip_summed = CHECKSUM_NONE;

	ct = ip_conntrack_get(*pskb, &ctinfo);
	/* Can't track?  Maybe out of memory: this would make NAT
           unreliable. */
	if (!ct) {
		if (net_ratelimit())
			printk(KERN_DEBUG "NAT: %u dropping untracked packet %p %u %u.%u.%u.%u -> %u.%u.%u.%u\n",
			       hooknum,
			       *pskb,
			       (*pskb)->nh.iph->protocol,
			       NIPQUAD((*pskb)->nh.iph->saddr),
			       NIPQUAD((*pskb)->nh.iph->daddr));
		return NF_DROP;
	}

	switch (ctinfo) {
	case IP_CT_RELATED:
	case IP_CT_RELATED+IP_CT_IS_REPLY:
		if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
			return icmp_reply_translation(*pskb, ct, hooknum,
						      CTINFO2DIR(ctinfo));
		}
		/* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
	case IP_CT_NEW:
		info = &ct->nat.info;

		WRITE_LOCK(&ip_nat_lock);
		/* Seen it before?  This can happen for loopback, retrans,
		   or local packets.. */
		if (!(info->initialized & (1 << maniptype))) {
			int in_hashes = info->initialized;
			unsigned int ret;

			ret = ip_nat_rule_find(pskb, hooknum, in, out,
					       ct, info);
			if (ret != NF_ACCEPT) {
				WRITE_UNLOCK(&ip_nat_lock);
				return ret;
			}

			if (in_hashes) {
				IP_NF_ASSERT(info->bysource.conntrack);
				replace_in_hashes(ct, info);
			} else {
				place_in_hashes(ct, info);
			}
		} else
			DEBUGP("Already setup manip %s for ct %p\n",
			       maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST",
			       ct);
		WRITE_UNLOCK(&ip_nat_lock);
		break;

	default:
		/* ESTABLISHED */
		IP_NF_ASSERT(ctinfo == IP_CT_ESTABLISHED
			     || ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY));
		info = &ct->nat.info;
	}

	IP_NF_ASSERT(info);
	return do_bindings(ct, ctinfo, info, hooknum, pskb);
}