View | Details | Raw Unified
Collapse All | Expand All

(-) a/include/linux/netfilter_ipv4/ip_conntrack.h (-2 / +1 lines)
 Lines 262-271    Link Here 
/* Fake conntrack entry for untracked connections */
/* Fake conntrack entry for untracked connections */
extern struct ip_conntrack ip_conntrack_untracked;
extern struct ip_conntrack ip_conntrack_untracked;
extern int ip_ct_no_defrag;
/* Returns new sk_buff, or NULL */
/* Returns new sk_buff, or NULL */
struct sk_buff *
struct sk_buff *
ip_ct_gather_frags(struct sk_buff *skb);
ip_ct_gather_frags(struct sk_buff *skb, u_int32_t user);
/* Iterate over all conntracks: if iter returns true, it's deleted. */
/* Iterate over all conntracks: if iter returns true, it's deleted. */
extern void
extern void
(-) a/include/net/ip.h (-3 / +14 lines)
 Lines 286-294    Link Here 
/*
/*
 *	Functions provided by ip_fragment.o
 *	Functions provided by ip_fragment.o
 */
 */
 
struct sk_buff *ip_defrag(struct sk_buff *skb);
enum ip_defrag_users
extern void ipfrag_flush(void);
{
	IP_DEFRAG_LOCAL_DELIVER,
	IP_DEFRAG_CALL_RA_CHAIN,
	IP_DEFRAG_CONNTRACK_IN,
	IP_DEFRAG_CONNTRACK_OUT,
	IP_DEFRAG_NAT_OUT,
	IP_DEFRAG_VS_IN,
	IP_DEFRAG_VS_OUT,
	IP_DEFRAG_VS_FWD
};
struct sk_buff *ip_defrag(struct sk_buff *skb, u32 user);
extern int ip_frag_nqueues;
extern int ip_frag_nqueues;
extern atomic_t ip_frag_mem;
extern atomic_t ip_frag_mem;
(-) a/net/ipv4/ip_fragment.c (-20 / +13 lines)
 Lines 73-78    Link Here 
struct ipq {
struct ipq {
	struct ipq	*next;		/* linked list pointers			*/
	struct ipq	*next;		/* linked list pointers			*/
	struct list_head lru_list;	/* lru list member 			*/
	struct list_head lru_list;	/* lru list member 			*/
	u32		user;
	u32		saddr;
	u32		saddr;
	u32		daddr;
	u32		daddr;
	u16		id;
	u16		id;
 Lines 243-255    Link Here 
/* Memory limiting on fragments.  Evictor trashes the oldest 
/* Memory limiting on fragments.  Evictor trashes the oldest 
 * fragment queue until we are back under the threshold.
 * fragment queue until we are back under the threshold.
 */
 */
static void __ip_evictor(int threshold)
static void ip_evictor(void)
{
{
	struct ipq *qp;
	struct ipq *qp;
	struct list_head *tmp;
	struct list_head *tmp;
	int work;
	int work;
	work = atomic_read(&ip_frag_mem) - threshold;
	work = atomic_read(&ip_frag_mem) - sysctl_ipfrag_low_thresh;
	if (work <= 0)
	if (work <= 0)
		return;
		return;
 Lines 274-284    Link Here 
	}
	}
}
}
static inline void ip_evictor(void)
{
	__ip_evictor(sysctl_ipfrag_low_thresh);
}
/*
/*
 * Oops, a fragment queue timed out.  Kill it and send an ICMP reply.
 * Oops, a fragment queue timed out.  Kill it and send an ICMP reply.
 */
 */
 Lines 325-331    Link Here 
		if(qp->id == qp_in->id		&&
		if(qp->id == qp_in->id		&&
		   qp->saddr == qp_in->saddr	&&
		   qp->saddr == qp_in->saddr	&&
		   qp->daddr == qp_in->daddr	&&
		   qp->daddr == qp_in->daddr	&&
		   qp->protocol == qp_in->protocol) {
		   qp->protocol == qp_in->protocol &&
		   qp->user == qp_in->user) {
			atomic_inc(&qp->refcnt);
			atomic_inc(&qp->refcnt);
			write_unlock(&ipfrag_lock);
			write_unlock(&ipfrag_lock);
			qp_in->last_in |= COMPLETE;
			qp_in->last_in |= COMPLETE;
 Lines 352-358    Link Here 
}
}
/* Add an entry to the 'ipq' queue for a newly received IP datagram. */
/* Add an entry to the 'ipq' queue for a newly received IP datagram. */
static struct ipq *ip_frag_create(unsigned hash, struct iphdr *iph)
static struct ipq *ip_frag_create(unsigned hash, struct iphdr *iph, u32 user)
{
{
	struct ipq *qp;
	struct ipq *qp;
 Lines 364-369    Link Here 
	qp->id = iph->id;
	qp->id = iph->id;
	qp->saddr = iph->saddr;
	qp->saddr = iph->saddr;
	qp->daddr = iph->daddr;
	qp->daddr = iph->daddr;
	qp->user = user;
	qp->len = 0;
	qp->len = 0;
	qp->meat = 0;
	qp->meat = 0;
	qp->fragments = NULL;
	qp->fragments = NULL;
 Lines 386-392    Link Here 
/* Find the correct entry in the "incomplete datagrams" queue for
/* Find the correct entry in the "incomplete datagrams" queue for
 * this IP datagram, and create new one, if nothing is found.
 * this IP datagram, and create new one, if nothing is found.
 */
 */
static inline struct ipq *ip_find(struct iphdr *iph)
static inline struct ipq *ip_find(struct iphdr *iph, u32 user)
{
{
	__u16 id = iph->id;
	__u16 id = iph->id;
	__u32 saddr = iph->saddr;
	__u32 saddr = iph->saddr;
 Lines 400-406    Link Here 
		if(qp->id == id		&&
		if(qp->id == id		&&
		   qp->saddr == saddr	&&
		   qp->saddr == saddr	&&
		   qp->daddr == daddr	&&
		   qp->daddr == daddr	&&
		   qp->protocol == protocol) {
		   qp->protocol == protocol &&
		   qp->user == user) {
			atomic_inc(&qp->refcnt);
			atomic_inc(&qp->refcnt);
			read_unlock(&ipfrag_lock);
			read_unlock(&ipfrag_lock);
			return qp;
			return qp;
 Lines 408-414    Link Here 
	}
	}
	read_unlock(&ipfrag_lock);
	read_unlock(&ipfrag_lock);
	return ip_frag_create(hash, iph);
	return ip_frag_create(hash, iph, user);
}
}
/* Add new segment to existing queue. */
/* Add new segment to existing queue. */
 Lines 642-648    Link Here 
}
}
/* Process an incoming IP datagram fragment. */
/* Process an incoming IP datagram fragment. */
struct sk_buff *ip_defrag(struct sk_buff *skb)
struct sk_buff *ip_defrag(struct sk_buff *skb, u32 user)
{
{
	struct iphdr *iph = skb->nh.iph;
	struct iphdr *iph = skb->nh.iph;
	struct ipq *qp;
	struct ipq *qp;
 Lines 657-663    Link Here 
	dev = skb->dev;
	dev = skb->dev;
	/* Lookup (or create) queue header */
	/* Lookup (or create) queue header */
	if ((qp = ip_find(iph)) != NULL) {
	if ((qp = ip_find(iph, user)) != NULL) {
		struct sk_buff *ret = NULL;
		struct sk_buff *ret = NULL;
		spin_lock(&qp->lock);
		spin_lock(&qp->lock);
 Lines 689-698    Link Here 
	add_timer(&ipfrag_secret_timer);
	add_timer(&ipfrag_secret_timer);
}
}
void ipfrag_flush(void)
{
	__ip_evictor(0);
}
EXPORT_SYMBOL(ip_defrag);
EXPORT_SYMBOL(ip_defrag);
EXPORT_SYMBOL(ipfrag_flush);
(-) a/net/ipv4/ip_input.c (-2 / +2 lines)
 Lines 172-178    Link Here 
		    (!sk->sk_bound_dev_if ||
		    (!sk->sk_bound_dev_if ||
		     sk->sk_bound_dev_if == skb->dev->ifindex)) {
		     sk->sk_bound_dev_if == skb->dev->ifindex)) {
			if (skb->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
			if (skb->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
				skb = ip_defrag(skb);
				skb = ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN);
				if (skb == NULL) {
				if (skb == NULL) {
					read_unlock(&ip_ra_lock);
					read_unlock(&ip_ra_lock);
					return 1;
					return 1;
 Lines 273-279    Link Here 
	 */
	 */
	if (skb->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
	if (skb->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
		skb = ip_defrag(skb);
		skb = ip_defrag(skb, IP_DEFRAG_LOCAL_DELIVER);
		if (!skb)
		if (!skb)
			return 0;
			return 0;
	}
	}
(-) a/net/ipv4/ipvs/ip_vs_core.c (-8 / +11 lines)
 Lines 544-552    Link Here 
}
}
static inline struct sk_buff *
static inline struct sk_buff *
ip_vs_gather_frags(struct sk_buff *skb)
ip_vs_gather_frags(struct sk_buff *skb, u_int32_t user)
{
{
	skb = ip_defrag(skb);
	skb = ip_defrag(skb, user);
	if (skb)
	if (skb)
		ip_send_check(skb->nh.iph);
		ip_send_check(skb->nh.iph);
	return skb;
	return skb;
 Lines 620-626    Link Here 
	/* reassemble IP fragments */
	/* reassemble IP fragments */
	if (skb->nh.iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {
	if (skb->nh.iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {
		skb = ip_vs_gather_frags(skb);
		skb = ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT);
		if (!skb)
		if (!skb)
			return NF_STOLEN;
			return NF_STOLEN;
		*pskb = skb;
		*pskb = skb;
 Lines 759-765    Link Here 
	/* reassemble IP fragments */
	/* reassemble IP fragments */
	if (unlikely(iph->frag_off & __constant_htons(IP_MF|IP_OFFSET) &&
	if (unlikely(iph->frag_off & __constant_htons(IP_MF|IP_OFFSET) &&
		     !pp->dont_defrag)) {
		     !pp->dont_defrag)) {
		skb = ip_vs_gather_frags(skb);
		skb = ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT);
		if (!skb)
		if (!skb)
			return NF_STOLEN;
			return NF_STOLEN;
		iph = skb->nh.iph;
		iph = skb->nh.iph;
 Lines 839-845    Link Here 
 *	forward to the right destination host if relevant.
 *	forward to the right destination host if relevant.
 *	Currently handles error types - unreachable, quench, ttl exceeded.
 *	Currently handles error types - unreachable, quench, ttl exceeded.
 */
 */
static int ip_vs_in_icmp(struct sk_buff **pskb, int *related)
static int 
ip_vs_in_icmp(struct sk_buff **pskb, int *related, unsigned int hooknum)
{
{
	struct sk_buff *skb = *pskb;
	struct sk_buff *skb = *pskb;
	struct iphdr *iph;
	struct iphdr *iph;
 Lines 853-859    Link Here 
	/* reassemble IP fragments */
	/* reassemble IP fragments */
	if (skb->nh.iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {
	if (skb->nh.iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {
		skb = ip_vs_gather_frags(skb);
		skb = ip_vs_gather_frags(skb,
		                         hooknum == NF_IP_LOCAL_IN ?
					 IP_DEFRAG_VS_IN : IP_DEFRAG_VS_FWD);
		if (!skb)
		if (!skb)
			return NF_STOLEN;
			return NF_STOLEN;
		*pskb = skb;
		*pskb = skb;
 Lines 962-968    Link Here 
	iph = skb->nh.iph;
	iph = skb->nh.iph;
	if (unlikely(iph->protocol == IPPROTO_ICMP)) {
	if (unlikely(iph->protocol == IPPROTO_ICMP)) {
		int related, verdict = ip_vs_in_icmp(pskb, &related);
		int related, verdict = ip_vs_in_icmp(pskb, &related, hooknum);
		if (related)
		if (related)
			return verdict;
			return verdict;
 Lines 1057-1063    Link Here 
	if ((*pskb)->nh.iph->protocol != IPPROTO_ICMP)
	if ((*pskb)->nh.iph->protocol != IPPROTO_ICMP)
		return NF_ACCEPT;
		return NF_ACCEPT;
	return ip_vs_in_icmp(pskb, &r);
	return ip_vs_in_icmp(pskb, &r, hooknum);
}
}
(-) a/net/ipv4/netfilter/ip_conntrack_core.c (-9 / +2 lines)
 Lines 936-964    Link Here 
	}
	}
}
}
int ip_ct_no_defrag;
/* Returns new sk_buff, or NULL */
/* Returns new sk_buff, or NULL */
struct sk_buff *
struct sk_buff *
ip_ct_gather_frags(struct sk_buff *skb)
ip_ct_gather_frags(struct sk_buff *skb, u_int32_t user)
{
{
	struct sock *sk = skb->sk;
	struct sock *sk = skb->sk;
#ifdef CONFIG_NETFILTER_DEBUG
#ifdef CONFIG_NETFILTER_DEBUG
	unsigned int olddebug = skb->nf_debug;
	unsigned int olddebug = skb->nf_debug;
#endif
#endif
	if (unlikely(ip_ct_no_defrag)) {
		kfree_skb(skb);
		return NULL;
	}
	if (sk) {
	if (sk) {
		sock_hold(sk);
		sock_hold(sk);
		skb_orphan(skb);
		skb_orphan(skb);
	}
	}
	local_bh_disable(); 
	local_bh_disable(); 
	skb = ip_defrag(skb);
	skb = ip_defrag(skb, user);
	local_bh_enable();
	local_bh_enable();
	if (!skb) {
	if (!skb) {
(-) a/net/ipv4/netfilter/ip_conntrack_standalone.c (-7 / +4 lines)
 Lines 391-397    Link Here 
	/* Gather fragments. */
	/* Gather fragments. */
	if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
	if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
		*pskb = ip_ct_gather_frags(*pskb);
		*pskb = ip_ct_gather_frags(*pskb,
		                           hooknum == NF_IP_PRE_ROUTING ? 
					   IP_DEFRAG_CONNTRACK_IN :
					   IP_DEFRAG_CONNTRACK_OUT);
		if (!*pskb)
		if (!*pskb)
			return NF_STOLEN;
			return NF_STOLEN;
	}
	}
 Lines 823-834    Link Here 
 cleanup_defraglocalops:
 cleanup_defraglocalops:
	nf_unregister_hook(&ip_conntrack_defrag_local_out_ops);
	nf_unregister_hook(&ip_conntrack_defrag_local_out_ops);
 cleanup_defragops:
 cleanup_defragops:
	/* Frag queues may hold fragments with skb->dst == NULL */
	ip_ct_no_defrag = 1;
	synchronize_net();
	local_bh_disable();
	ipfrag_flush();
	local_bh_enable();
	nf_unregister_hook(&ip_conntrack_defrag_ops);
	nf_unregister_hook(&ip_conntrack_defrag_ops);
 cleanup_proc_stat:
 cleanup_proc_stat:
#ifdef CONFIG_PROC_FS
#ifdef CONFIG_PROC_FS
(-) a/net/ipv4/netfilter/ip_nat_standalone.c (-1 / +1 lines)
 Lines 195-201    Link Here 
	   I'm starting to have nightmares about fragments.  */
	   I'm starting to have nightmares about fragments.  */
	if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
	if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
		*pskb = ip_ct_gather_frags(*pskb);
		*pskb = ip_ct_gather_frags(*pskb, IP_DEFRAG_NAT_OUT);
		if (!*pskb)
		if (!*pskb)
			return NF_STOLEN;
			return NF_STOLEN;
(-) a/net/ipv4/ip_output.c (+1 lines)
 Lines 504-509    Link Here 
			/* Prepare header of the next frame,
			/* Prepare header of the next frame,
			 * before previous one went down. */
			 * before previous one went down. */
			if (frag) {
			if (frag) {
				frag->ip_summed = CHECKSUM_NONE;
				frag->h.raw = frag->data;
				frag->h.raw = frag->data;
				frag->nh.raw = __skb_push(frag, hlen);
				frag->nh.raw = __skb_push(frag, hlen);
				memcpy(frag->nh.raw, iph, hlen);
				memcpy(frag->nh.raw, iph, hlen);
(-) a/net/ipv6/ip6_output.c (+1 lines)
 Lines 592-597    Link Here 
			/* Prepare header of the next frame,
			/* Prepare header of the next frame,
			 * before previous one went down. */
			 * before previous one went down. */
			if (frag) {
			if (frag) {
				frag->ip_summed = CHECKSUM_NONE;
				frag->h.raw = frag->data;
				frag->h.raw = frag->data;
				fh = (struct frag_hdr*)__skb_push(frag, sizeof(struct frag_hdr));
				fh = (struct frag_hdr*)__skb_push(frag, sizeof(struct frag_hdr));
				frag->nh.raw = __skb_push(frag, hlen);
				frag->nh.raw = __skb_push(frag, hlen);