Пример #1
0
static void masq_expire(unsigned long data)
{
	struct ip_masq *ms = (struct ip_masq *)data, *ms_data;
	unsigned long flags;

	if (ms->flags & IP_MASQ_F_CONTROL) {
		/* a control channel is about to expire */
		int idx = 0, reprieve = 0;
#ifdef DEBUG_CONFIG_IP_MASQUERADE
		printk("Masquerade control %s %lX:%X about to expire\n",
				masq_proto_name(ms->protocol),
				ntohl(ms->saddr),ntohs(ms->sport));
#endif
		save_flags(flags);
		cli();

		/*
		 * If any other masquerade entry claims that the expiring entry
		 * is its control channel then keep the control entry alive.
		 * Useful for long running data channels with inactive control
		 * links which we don't want to lose, e.g. ftp.
		 * Assumption: loops such as a->b->a or a->a will never occur.
		 */
		for (idx = 0; idx < IP_MASQ_TAB_SIZE && !reprieve; idx++) {
			for (ms_data = ip_masq_m_tab[idx]; ms_data ; ms_data = ms_data->m_link) {
				if (ms_data->control == ms) {
					reprieve = 1;	/* this control connection can live a bit longer */
					ip_masq_set_expire(ms, ip_masq_expire->tcp_timeout);
#ifdef DEBUG_CONFIG_IP_MASQUERADE
					printk("Masquerade control %s %lX:%X expiry reprieved\n",
							masq_proto_name(ms->protocol),
							ntohl(ms->saddr),ntohs(ms->sport));
#endif
					break;
				}
			}
		}
		restore_flags(flags);
		if (reprieve)
			return;
	}

#ifdef DEBUG_CONFIG_IP_MASQUERADE
	printk("Masqueraded %s %lX:%X expired\n",masq_proto_name(ms->protocol),ntohl(ms->saddr),ntohs(ms->sport));
#endif
	
	save_flags(flags);
	cli();

        if (ip_masq_unhash(ms)) {
                ip_masq_free_ports[masq_proto_num(ms->protocol)]++;
                if (ms->protocol != IPPROTO_ICMP)
                             ip_masq_unbind_app(ms);
                kfree_s(ms,sizeof(*ms));
        }

	restore_flags(flags);
}
Пример #2
0
/*
 *	Create new entry (from uspace)
 */
static int ip_masq_user_new(struct ip_masq_user *ums)
{
	struct ip_masq *ms = NULL;
	unsigned mflags = 0;
	int ret;

	if (masq_proto_num (ums->protocol) == -1) {
		return EPROTONOSUPPORT;
	}

	if (ums->dport == 0) {
		ums->flags |= IP_MASQ_USER_F_LISTEN;
	}

	if (ums->flags | IP_MASQ_USER_F_LISTEN) {
		if ((ums->saddr == 0) || (ums->sport == 0)) {
			return EINVAL;
		}
		mflags |= (IP_MASQ_F_NO_DPORT|IP_MASQ_F_NO_DADDR);

	}

	if ((ret = ip_masq_user_maddr(ums)) < 0) {
		return -ret;
	}

	mflags |= IP_MASQ_F_USER;
	ms = ip_masq_new(ums->protocol, 
			ums->maddr, ums->mport, 
			ums->saddr, ums->sport,
			ums->daddr, ums->dport,
			mflags);
	
	if (ms == NULL) {
		/*
		 *	FIXME: ip_masq_new() should return errno
		 */
		return EBUSY;
	}

	/*
	 *	Setup timeouts for this new entry
	 */

	if (ums->timeout) {
		ms->timeout = ums->timeout;
	} else if (ums->flags | IP_MASQ_USER_F_LISTEN) {
		ip_masq_listen(ms);
	}

	masq_user_k2u(ms, ums);
	ip_masq_put(ms);
	return 0;
}
Пример #3
0
/* 
 *	Delete existing entry
 */
static int ip_masq_user_del(struct ip_masq_user *ums)
{
	struct ip_masq *ms=NULL;

	if (masq_proto_num (ums->protocol) == -1) {
		return EPROTONOSUPPORT;
	}
	start_bh_atomic();
	if (ums->mport && ums->maddr) {
		ms = ip_masq_in_get(ums->protocol, 
				ums->daddr, ums->dport, 
				ums->maddr, ums->mport);
		end_bh_atomic();
	} else if (ums->sport && ums->saddr) {
		ms = ip_masq_out_get(ums->protocol,
				ums->saddr, ums->sport,
				ums->daddr, ums->dport);
		end_bh_atomic();
	} else
		return EINVAL;	
	
	if (ms == NULL) {
		return ESRCH;
	}

	/*
	 *	got (locked) entry, setup almost tiny timeout :) and  
	 *	give away
	 *
	 *	FIXME: should use something better than S_CLOSE
	 */
	ms->timeout = IP_MASQ_S_CLOSE;

	masq_user_k2u(ms, ums);
	ip_masq_put(ms);
	return 0;
}
Пример #4
0
static struct ip_masq * ip_masq_user_locked_get (struct ip_masq_user *ums, int *err)
{
	struct ip_masq *ms=NULL;
	if (masq_proto_num (ums->protocol) == -1) {
		*err = EPROTONOSUPPORT;
	}

	start_bh_atomic();
	if (ums->mport && ums->maddr) {
		ms = ip_masq_in_get(ums->protocol, 
				ums->daddr, ums->dport, 
				ums->maddr, ums->mport);
		end_bh_atomic();
	} else if (ums->sport && ums->saddr) {
		ms = ip_masq_out_get(ums->protocol,
				ums->saddr, ums->sport,
				ums->daddr, ums->dport);
		end_bh_atomic();
	} else
		*err = EINVAL;	
	
	if (ms == NULL) *err = ESRCH;
	return ms;
}
Пример #5
0
static __inline__ const char *masq_proto_name(unsigned proto)
{
        return strProt[masq_proto_num(proto)];
}
Пример #6
0
int ip_fw_masquerade(struct sk_buff **skb_ptr, struct device *dev)
{
	struct sk_buff  *skb=*skb_ptr;
	struct iphdr	*iph = skb->h.iph;
	__u16	*portptr;
	struct ip_masq	*ms;
	int		size;
        unsigned long 	timeout;

	/*
	 * We can only masquerade protocols with ports...
	 * [TODO]
	 * We may need to consider masq-ing some ICMP related to masq-ed protocols
	 */

        if (iph->protocol==IPPROTO_ICMP) 
            return (ip_fw_masq_icmp(skb_ptr,dev));
	if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP)
		return -1;

	/*
	 *	Now hunt the list to see if we have an old entry
	 */

	portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
#ifdef DEBUG_CONFIG_IP_MASQUERADE
	printk("Outgoing %s %lX:%X -> %lX:%X\n",
		masq_proto_name(iph->protocol),
		ntohl(iph->saddr), ntohs(portptr[0]),
		ntohl(iph->daddr), ntohs(portptr[1]));
#endif

        ms = ip_masq_out_get(iph);
	if (ms!=NULL) {
                ip_masq_set_expire(ms,0);
                
                /*
                 *	If sysctl !=0 and no pkt has been received yet
                 *	in this tunnel and routing iface address has changed...
                 *	 "You are welcome, diald".
                 */
                if ( sysctl_ip_dynaddr && ms->flags & IP_MASQ_F_NO_REPLY && dev->pa_addr != ms->maddr) {
                        unsigned long flags;
                        if (sysctl_ip_dynaddr > 1) {
                                printk(KERN_INFO "ip_fw_masquerade(): change maddr from %s",
                                       in_ntoa(ms->maddr));
                                printk(" to %s\n", in_ntoa(dev->pa_addr));
                        }
                        save_flags(flags);
                        cli();
                        ip_masq_unhash(ms);
                        ms->maddr = dev->pa_addr;
                        ip_masq_hash(ms);
                        restore_flags(flags);
                }
                
		/*
		 *      Set sport if not defined yet (e.g. ftp PASV).  Because
		 *	masq entries are hashed on sport, unhash with old value
		 *	and hash with new.
		 */

		if ( ms->flags & IP_MASQ_F_NO_SPORT && ms->protocol == IPPROTO_TCP ) {
			unsigned long flags;
			ms->flags &= ~IP_MASQ_F_NO_SPORT;
			save_flags(flags);
			cli();
			ip_masq_unhash(ms);
			ms->sport = portptr[0];
			ip_masq_hash(ms);	/* hash on new sport */
			restore_flags(flags);
#ifdef DEBUG_CONFIG_IP_MASQUERADE
			printk("ip_fw_masquerade(): filled sport=%d\n",
			       ntohs(ms->sport));
#endif
		}
	}

#ifdef CONFIG_IP_MASQUERADE_IPAUTOFW
	/* update any ipautofw entries .. */
	ip_autofw_update_out(iph->saddr, iph->daddr, portptr[1], 
			     iph->protocol);
#endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */

	/*
	 *	Nope, not found, create a new entry for it
	 */
	if (ms==NULL)
	{
#ifdef CONFIG_IP_MASQUERADE_IPAUTOFW
		/* if the source port is supposed to match the masq port, then
		   make it so */
		if (ip_autofw_check_direct(portptr[1],iph->protocol))
	                ms = ip_masq_new_enh(dev, iph->protocol,
        	                         iph->saddr, portptr[0],
                	                 iph->daddr, portptr[1],
                        	         0,
                        	         portptr[0]);
                else
#endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */
	                ms = ip_masq_new_enh(dev, iph->protocol,
        	                         iph->saddr, portptr[0],
                	                 iph->daddr, portptr[1],
                        	         0,
                        	         0);
                if (ms == NULL)
			return -1;
 	}

 	/*
 	 *	Change the fragments origin
 	 */
 	
 	size = skb->len - ((unsigned char *)portptr - skb->h.raw);
        /*
         *	Set iph addr and port from ip_masq obj.
         */
 	iph->saddr = ms->maddr;
 	portptr[0] = ms->mport;

 	/*
 	 *	Attempt ip_masq_app call.
         *	will fix ip_masq and iph seq stuff
 	 */
        if (ip_masq_app_pkt_out(ms, skb_ptr, dev) != 0)
	{
                /*
                 *	skb has possibly changed, update pointers.
                 */
                skb = *skb_ptr;
                iph = skb->h.iph;
                portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
                size = skb->len - ((unsigned char *)portptr-skb->h.raw);
        }

 	/*
 	 *	Adjust packet accordingly to protocol
 	 */
 	
 	if (masq_proto_num(iph->protocol)==0)
 	{
                timeout = ip_masq_expire->udp_timeout;
 		recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size);
 	}
 	else
 	{
 		struct tcphdr *th;
 		th = (struct tcphdr *)portptr;

		/* Set the flags up correctly... */
		if (th->fin)
		{
			ms->flags |= IP_MASQ_F_SAW_FIN_OUT;
		}

		if (th->rst)
		{
			ms->flags |= IP_MASQ_F_SAW_RST;
		}

 		/*
 		 *	Timeout depends if FIN packet has been seen
		 *	Very short timeout if RST packet seen.
 		 */
 		if (ms->flags & IP_MASQ_F_SAW_RST)
		{
                        timeout = 1;
		}
 		else if ((ms->flags & IP_MASQ_F_SAW_FIN) == IP_MASQ_F_SAW_FIN)
		{
                        timeout = ip_masq_expire->tcp_fin_timeout;
		}
 		else timeout = ip_masq_expire->tcp_timeout;

		skb->csum = csum_partial((void *)(th + 1), size - sizeof(*th), 0);
 		tcp_send_check(th,iph->saddr,iph->daddr,size,skb);
 	}
        ip_masq_set_expire(ms, timeout);
 	ip_send_check(iph);

 #ifdef DEBUG_CONFIG_IP_MASQUERADE
 	printk("O-routed from %lX:%X over %s\n",ntohl(ms->maddr),ntohs(ms->mport),dev->name);
 #endif

	return 0;
 }
Пример #7
0
struct ip_masq * ip_masq_new_enh(struct device *dev, int proto, __u32 saddr, __u16 sport, __u32 daddr, __u16 dport, unsigned mflags, __u16 matchport)
{
        struct ip_masq *ms, *mst;
        int ports_tried, *free_ports_p;
	unsigned long flags;
        static int n_fails = 0;

        free_ports_p = &ip_masq_free_ports[masq_proto_num(proto)];

        if (*free_ports_p == 0) {
                if (++n_fails < 5)
                        printk("ip_masq_new(proto=%s): no free ports.\n",
                               masq_proto_name(proto));
                return NULL;
        }
        ms = (struct ip_masq *) kmalloc(sizeof(struct ip_masq), GFP_ATOMIC);
        if (ms == NULL) {
                if (++n_fails < 5)
                        printk("ip_masq_new(proto=%s): no memory available.\n",
                               masq_proto_name(proto));
                return NULL;
        }
        memset(ms, 0, sizeof(*ms));
	init_timer(&ms->timer);
	ms->timer.data     = (unsigned long)ms;
	ms->timer.function = masq_expire;
        ms->protocol	   = proto;
        ms->saddr    	   = saddr;
        ms->sport	   = sport;
        ms->daddr	   = daddr;
        ms->dport	   = dport;
        ms->flags	   = mflags;
        ms->app_data	   = NULL;
	ms->control	   = NULL;

        if (proto == IPPROTO_UDP && !matchport)
                ms->flags |= IP_MASQ_F_NO_DADDR;
        
        /* get masq address from rif */
        ms->maddr	   = dev->pa_addr;
        /*
         *	Setup new entry as not replied yet.
         *	This flag will allow masq. addr (ms->maddr)
         *	to follow forwarding interface address.
         */
        ms->flags         |= IP_MASQ_F_NO_REPLY;

        for (ports_tried = 0; 
	     (*free_ports_p && (ports_tried <= (PORT_MASQ_END - PORT_MASQ_BEGIN)));
	     ports_tried++){
                save_flags(flags);
                cli();
                
		/*
                 *	Try the next available port number
                 */
                if (!matchport || ports_tried)
			ms->mport = htons(masq_port++);
		else
			ms->mport = matchport;
			
		if (masq_port==PORT_MASQ_END) masq_port = PORT_MASQ_BEGIN;
                
                restore_flags(flags);
                
                /*
                 *	lookup to find out if this port is used.
                 */
                
                mst = ip_masq_getbym(proto, ms->maddr, ms->mport);
                if (mst == NULL || matchport) {
                        save_flags(flags);
                        cli();
                
                        if (*free_ports_p == 0) {
                                restore_flags(flags);
                                break;
                        }
                        (*free_ports_p)--;
                        ip_masq_hash(ms);
                        
                        restore_flags(flags);
                        
                        if (proto != IPPROTO_ICMP)
                              ip_masq_bind_app(ms);
                        n_fails = 0;
                        return ms;
                }
        }
        
        if (++n_fails < 5)
                printk("ip_masq_new(proto=%s): could not get free masq entry (free=%d).\n",
                       masq_proto_name(ms->protocol), *free_ports_p);
        kfree_s(ms, sizeof(*ms));
        return NULL;
}
Пример #8
0
int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev)
{
        struct sk_buff 	*skb = *skb_p;
 	struct iphdr	*iph = skb->h.iph;
 	__u16	*portptr;
 	struct ip_masq	*ms;
	unsigned short len;
	unsigned long 	timeout;
#ifdef CONFIG_IP_MASQUERADE_IPAUTOFW 
 	struct ip_autofw *af;
#endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */

	switch (iph->protocol) {
	case IPPROTO_ICMP:
		return(ip_fw_demasq_icmp(skb_p, dev));
	case IPPROTO_TCP:
	case IPPROTO_UDP:
		/* Make sure packet is in the masq range */
		portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
		if ((ntohs(portptr[1]) < PORT_MASQ_BEGIN ||
		     ntohs(portptr[1]) > PORT_MASQ_END)
#ifdef CONFIG_IP_MASQUERADE_IPAUTOFW 
		    && !ip_autofw_check_range(iph->saddr, portptr[1], 
					      iph->protocol, 0)
		    && !ip_autofw_check_direct(portptr[1], iph->protocol)
		    && !ip_autofw_check_port(portptr[1], iph->protocol)
#endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */
			)
			return 0;

		/* Check that the checksum is OK */
		len = ntohs(iph->tot_len) - (iph->ihl * 4);
		if ((iph->protocol == IPPROTO_UDP) && (portptr[3] == 0))
			/* No UDP checksum */
			break;

		switch (skb->ip_summed) 
		{
			case CHECKSUM_NONE:
				skb->csum = csum_partial((char *)portptr, len, 0);
			case CHECKSUM_HW:
				if (csum_tcpudp_magic(iph->saddr, iph->daddr, len,
						      iph->protocol, skb->csum))
				{
					printk(KERN_DEBUG "MASQ: failed TCP/UDP checksum from %s!\n", 
					       in_ntoa(iph->saddr));
					return -1;
				}
			default:
				/* CHECKSUM_UNNECESSARY */
		}
		break;
	default:
		return 0;
	}


#ifdef DEBUG_CONFIG_IP_MASQUERADE
 	printk("Incoming %s %lX:%X -> %lX:%X\n",
 		masq_proto_name(iph->protocol),
 		ntohl(iph->saddr), ntohs(portptr[0]),
 		ntohl(iph->daddr), ntohs(portptr[1]));
#endif
 	/*
 	 * reroute to original host:port if found...
         */

        ms = ip_masq_in_get(iph);

#ifdef CONFIG_IP_MASQUERADE_IPAUTOFW 

        if (ms == NULL && (af=ip_autofw_check_range(iph->saddr, portptr[1], iph->protocol, 0))) 
	{
#ifdef DEBUG_CONFIG_IP_MASQUERADE
		printk("ip_autofw_check_range\n");
#endif
        	ms = ip_masq_new_enh(dev, iph->protocol,
        			     af->where, portptr[1],
        			     iph->saddr, portptr[0],
        			     0,
        			     portptr[1]);
        }
        if ( ms == NULL && (af=ip_autofw_check_port(portptr[1], iph->protocol)) ) 
	{
#ifdef DEBUG_CONFIG_IP_MASQUERADE
		printk("ip_autofw_check_port\n");
#endif
        	ms = ip_masq_new_enh(dev, iph->protocol,
        			     af->where, htons(af->hidden),
        			     iph->saddr, portptr[0],
        			     IP_MASQ_F_AFW_PORT,
        			     htons(af->visible));
        }
#endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */

        if (ms != NULL)
        {
#ifdef CONFIG_IP_MASQUERADE_IPAUTOFW 
        	ip_autofw_update_in(iph->saddr, portptr[1], iph->protocol);
#endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */
        	
		/* Stop the timer ticking.... */
		ip_masq_set_expire(ms,0);

                /*
                 *	got reply, so clear flag
                 */
                ms->flags &= ~IP_MASQ_F_NO_REPLY;
                
                /*
                 *	Set dport if not defined yet.
                 */

                if ( ms->flags & IP_MASQ_F_NO_DPORT && ms->protocol == IPPROTO_TCP ) {
                        ms->flags &= ~IP_MASQ_F_NO_DPORT;
                        ms->dport = portptr[0];
#ifdef DEBUG_CONFIG_IP_MASQUERADE
                        printk("ip_fw_demasquerade(): filled dport=%d\n",
                               ntohs(ms->dport));
#endif
                }
                if (ms->flags & IP_MASQ_F_NO_DADDR && ms->protocol == IPPROTO_TCP)  {
                        ms->flags &= ~IP_MASQ_F_NO_DADDR;
                        ms->daddr = iph->saddr;
#ifdef DEBUG_CONFIG_IP_MASQUERADE
                        printk("ip_fw_demasquerade(): filled daddr=%X\n",
                               ntohs(ms->daddr));
#endif
                }
                iph->daddr = ms->saddr;
                portptr[1] = ms->sport;

                /*
                 *	Attempt ip_masq_app call.
                 *	will fix ip_masq and iph ack_seq stuff
                 */

                if (ip_masq_app_pkt_in(ms, skb_p, dev) != 0)
                {
                        /*
                         *	skb has changed, update pointers.
                         */

                        skb = *skb_p;
                        iph = skb->h.iph;
                        portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
                        len = ntohs(iph->tot_len) - (iph->ihl * 4);
                }

                /*
                 * Yug! adjust UDP/TCP and IP checksums, also update
		 * timeouts.
		 * If a TCP RST is seen collapse the tunnel (by using short timeout)!
                 */
                if (masq_proto_num(iph->protocol)==0)
		{
                        recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,len);
			timeout = ip_masq_expire->udp_timeout;
		}
                else
                {
			struct tcphdr *th;
                        skb->csum = csum_partial((void *)(((struct tcphdr *)portptr) + 1),
                                                 len - sizeof(struct tcphdr), 0);
                        tcp_send_check((struct tcphdr *)portptr,iph->saddr,iph->daddr,len,skb);

			/* Check if TCP FIN or RST */
			th = (struct tcphdr *)portptr;
			if (th->fin)
			{
				ms->flags |= IP_MASQ_F_SAW_FIN_IN;
			}
			if (th->rst)
			{
				ms->flags |= IP_MASQ_F_SAW_RST;
			}
			
			/* Now set the timeouts */
			if (ms->flags & IP_MASQ_F_SAW_RST)
			{
				timeout = 1;
			}
			else if ((ms->flags & IP_MASQ_F_SAW_FIN) == IP_MASQ_F_SAW_FIN)
			{
				timeout = ip_masq_expire->tcp_fin_timeout;
			}
			else timeout = ip_masq_expire->tcp_timeout;
                }
		ip_masq_set_expire(ms, timeout);
                ip_send_check(iph);
#ifdef DEBUG_CONFIG_IP_MASQUERADE
                printk("I-routed to %lX:%X\n",ntohl(iph->daddr),ntohs(portptr[1]));
#endif
                return 1;
 	}

 	/* sorry, all this trouble for a no-hit :) */
 	return 0;
}

/*
 *	/proc/net entries
 */


#ifdef CONFIG_IP_MASQUERADE_IPAUTOFW

static int ip_autofw_procinfo(char *buffer, char **start, off_t offset,
			      int length, int unused)
{
	off_t pos=0, begin=0;
	struct ip_autofw * af;
	int len=0;
	
	len=sprintf(buffer,"Type Prot Low  High Vis  Hid  Where    Last     CPto CPrt Timer Flags\n"); 
        
        for(af = ip_autofw_hosts; af ; af = af->next)
	{
		len+=sprintf(buffer+len,"%4X %4X %04X-%04X/%04X %04X %08lX %08lX %04X %04X %6lu %4X\n",
					af->type,
					af->protocol,
					af->low,
					af->high,
					af->visible,
					af->hidden,
					ntohl(af->where),
					ntohl(af->lastcontact),
					af->ctlproto,
					af->ctlport,
					(af->timer.expires<jiffies ? 0 : af->timer.expires-jiffies), 
					af->flags);

		pos=begin+len;
		if(pos<offset) 
		{
 			len=0;
			begin=pos;
		}
		if(pos>offset+length)
			break;
        }
	*start=buffer+(offset-begin);
	len-=(offset-begin);
	if(len>length)
		len=length;
	return len;
}