View | Details | Raw Unified
Collapse All | Expand All

(-) a/include/linux/netfilter_ipv4/ip_conntrack.h (-2 / +1 lines)
 Lines 249-258    Link Here 
/* Call me when a conntrack is destroyed. */
/* Call me when a conntrack is destroyed. */
extern void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack);
extern void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack);
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);
/* Delete all conntracks which match. */
/* Delete all conntracks which match. */
extern void
extern void
(-) a/include/net/ip.h (-3 / +13 lines)
 Lines 227-235    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_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 (-19 / +13 lines)
 Lines 72-77    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 242-254    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 273-283    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 324-330    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 351-357    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 363-368    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 385-391    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 399-405    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 407-413    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 641-647    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 656-662    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 686-694    Link Here 
	ipfrag_secret_timer.function = ipfrag_secret_rebuild;
	ipfrag_secret_timer.function = ipfrag_secret_rebuild;
	ipfrag_secret_timer.expires = jiffies + sysctl_ipfrag_secret_interval;
	ipfrag_secret_timer.expires = jiffies + sysctl_ipfrag_secret_interval;
	add_timer(&ipfrag_secret_timer);
	add_timer(&ipfrag_secret_timer);
}
void ipfrag_flush(void)
{
	__ip_evictor(0);
}
}
(-) a/net/ipv4/ip_input.c (-2 / +2 lines)
 Lines 170-176    Link Here 
		    && ((sk->bound_dev_if == 0) 
		    && ((sk->bound_dev_if == 0) 
			|| (sk->bound_dev_if == skb->dev->ifindex))) {
			|| (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 291-297    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 (-3 / +3 lines)
 Lines 506-512    Link Here 
	/* reassemble IP fragments, but will it happen in ICMP packets?? */
	/* reassemble IP fragments, but will it happen in ICMP packets?? */
	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_defrag(skb);
		skb = ip_defrag(skb, IP_DEFRAG_VS_OUT);
		if (!skb)
		if (!skb)
			return NF_STOLEN;
			return NF_STOLEN;
		*skb_p = skb;
		*skb_p = skb;
 Lines 658-664    Link Here 
	/* reassemble IP fragments */
	/* reassemble IP fragments */
	if (iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {
	if (iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {
		skb = ip_defrag(skb);
		skb = ip_defrag(skb, IP_DEFRAG_VS_OUT);
		if (!skb)
		if (!skb)
			return NF_STOLEN;
			return NF_STOLEN;
		iph = skb->nh.iph;
		iph = skb->nh.iph;
 Lines 1164-1170    Link Here 
		return NF_ACCEPT;
		return NF_ACCEPT;
	if (iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {
	if (iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {
		skb = ip_defrag(skb);
		skb = ip_defrag(skb, IP_DEFRAG_VS_FWD);
		if (!skb)
		if (!skb)
			return NF_STOLEN;
			return NF_STOLEN;
		*skb_p = skb;
		*skb_p = skb;
(-) a/net/ipv4/netfilter/ip_conntrack_core.c (-10 / +6 lines)
 Lines 834-840    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 1183-1211    Link Here 
	WRITE_UNLOCK(&ip_conntrack_lock);
	WRITE_UNLOCK(&ip_conntrack_lock);
}
}
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 lines)
 Lines 393-405    Link Here 
 cleanup_inandlocalops:
 cleanup_inandlocalops:
	nf_unregister_hook(&ip_conntrack_local_out_ops);
	nf_unregister_hook(&ip_conntrack_local_out_ops);
 cleanup_inops:
 cleanup_inops:
	/* Frag queues may hold fragments with skb->dst == NULL */
	ip_ct_no_defrag = 1;
	local_bh_disable();
	br_write_lock(BR_NETPROTO_LOCK);
	br_write_unlock(BR_NETPROTO_LOCK);
	ipfrag_flush();
	local_bh_enable();
	nf_unregister_hook(&ip_conntrack_in_ops);
	nf_unregister_hook(&ip_conntrack_in_ops);
 cleanup_proc:
 cleanup_proc:
	proc_net_remove("ip_conntrack");
	proc_net_remove("ip_conntrack");
(-) a/net/ipv4/netfilter/ip_nat_standalone.c (-1 / +1 lines)
 Lines 201-207    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/netsyms.c (-1 lines)
 Lines 287-293    Link Here 
EXPORT_SYMBOL(inetdev_by_index);
EXPORT_SYMBOL(inetdev_by_index);
EXPORT_SYMBOL(in_dev_finish_destroy);
EXPORT_SYMBOL(in_dev_finish_destroy);
EXPORT_SYMBOL(ip_defrag);
EXPORT_SYMBOL(ip_defrag);
EXPORT_SYMBOL(ipfrag_flush);
/* Route manipulation */
/* Route manipulation */
EXPORT_SYMBOL(ip_rt_ioctl);
EXPORT_SYMBOL(ip_rt_ioctl);