示例#1
0
/* Returns verdict for packet, or -1 for invalid. */
static int gre_packet(struct ip_conntrack *conntrack,
		      struct iphdr *iph, size_t len,
		      enum ip_conntrack_info ctinfo)
{
#ifdef CONFIG_IP_NF_PPTP_DEBUG
	struct pptp_gre_hdr *greh = (struct pptp_gre_hdr *)((u_int32_t *)iph + iph->ihl);
#endif

	/* 
	 *	If we've seen traffic both ways, this is a connected GRE stream.
	 * 	Extend timeout. 
	 */
	if (conntrack->status & IPS_SEEN_REPLY) {
		ip_ct_refresh(conntrack, GRE_CONNECTED_TIMEOUT);
		/* Also, more likely to be important, and not a probe */
		set_bit(IPS_ASSURED_BIT, &conntrack->status);
	} else
		ip_ct_refresh(conntrack, GRE_TIMEOUT);

	DEBUGP("CT=%lx, Master=%lx, DIR=%s ", (unsigned long) conntrack, 
		(unsigned long) conntrack->help.ct_pptp_info.master,
		(ctinfo >= IP_CT_IS_REPLY ? "reply   " : "original"));
	PRINTK_GRE_HDR("", iph, greh);
	return NF_ACCEPT;
}
示例#2
0
static void delete_connection(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
{
	clear_gre_tuples(ct);

	ip_ct_refresh(ct, 5*HZ);
	//nf_conntrack_put(&ct->master);

#if 0
	/* 	expire the GRE connection
	 */
	l = &ct->help.ct_pptp_info.list;
	for (e=l->next; e!=l; e=e->next) {
		ct_gre = list_entry(e, struct ip_conntrack, help.ct_pptp_info.list);
		if(!ct_gre)
		{
			DEBUGP("What - NULL ct_gre!\n");
			continue;
		}
		list_del(&ct_gre->help.ct_pptp_info.list);

		ip_ct_refresh(ct_gre, 5*HZ);
		if (del_timer(&ct_gre->timeout))
	        	ct_gre->timeout.function((unsigned long)ct_gre);
		else
			DEBUGP("Couldn't delete GRE timer!\n");
	}
#endif	
}
/* Returns verdict for packet, and may modify conntracktype */
static int esp_packet(struct ip_conntrack *conntrack,
		      const struct sk_buff *skb,
		      enum ip_conntrack_info conntrackinfo)
{
	const struct iphdr *iph = skb->nh.iph;
	const struct esphdr *esph = (void *)iph + iph->ihl*4;
	struct _esp_table *esp_entry;

        //printk ( KERN_DEBUG "%s:%s (0x%x) %u.%u.%u.%u <-> %u.%u.%u.%u %s\n",
        //         __FILE__, __FUNCTION__, ntohl(esph->spi), 
        //         NIPQUAD(iph->saddr), NIPQUAD(iph->daddr),
        //         (conntrackinfo == IP_CT_NEW ) ? "CT_NEW" : "SEEN_REPLY" );
	/*
	 * This should not happen. We get into this routine only if there is
	 * an existing stream.
	 */
	if (conntrackinfo == IP_CT_NEW ) {
		//printk ( KERN_DEBUG "%s:%s IP_CT_NEW (0x%x) %u.%u.%u.%u <-> %u.%u.%u.%u\n",
                //         __FILE__, __FUNCTION__, esph->spi, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
		if ( (esp_entry = search_esp_entry_by_spi ( esph, 
					iph->daddr ) ) == NULL ) {
			esp_entry = alloc_esp_entry ();
                        if ( esp_entry == NULL ) {
                               	/* All entries are currently in use */
				//printk ( KERN_DEBUG "%s:%s All connections in use\n",
                                //         __FILE__, __FUNCTION__);
                               	return NF_DROP;
                        }
                        esp_entry->l_spi = ntohl(esph->spi);
                        esp_entry->l_ip  = ntohl(iph->saddr);
                        esp_entry->r_spi = 0;
		}
	}
	/* If we've seen traffic both ways, this is some kind of UDP
	   stream.  Extend timeout. */
	if (conntrack->status & IPS_SEEN_REPLY) {
		ip_ct_refresh(conntrack, ESP_STREAM_TIMEOUT);
		/* Also, more likely to be important, and not a probe */
		set_bit(IPS_ASSURED_BIT, &conntrack->status);
	} else {
		ip_ct_refresh(conntrack, ESP_TIMEOUT);
    	}
	//esp_entry = search_esp_entry_by_spi ( esph, iph->daddr );
	if ( esp_entry != NULL ) {
		//printk ( KERN_DEBUG "%s:%s can modify this %u.%u.%u.%u"
		//	   " with %u.%u.%u.%u\n",
		//	   __FILE__, __FUNCTION__,
		// 	   NIPQUAD(conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip),
		//	   NIPQUAD(esp_entry->l_ip) );
	}

	return NF_ACCEPT;
}
/* Returns verdict for packet, and may modify conntracktype */
static int esp_packet(struct ip_conntrack *conntrack,
		      struct iphdr *iph, size_t len,
		      enum ip_conntrack_info conntrackinfo)
{
	/* If we've seen traffic both ways, this is some kind of UDP
	   stream.  Extend timeout. */
	if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
		ip_ct_refresh(conntrack, ip_ct_esp_timeout_stream);
		/* Also, more likely to be important, and not a probe */
		set_bit(IPS_ASSURED_BIT, &conntrack->status);
	} else
		ip_ct_refresh(conntrack, ip_ct_esp_timeout);

	return NF_ACCEPT;
}
/* Returns verdict for packet, or -1 for invalid. */
static int tcp_packet(struct ip_conntrack *conntrack,
		      struct iphdr *iph, size_t len,
		      enum ip_conntrack_info ctinfo)
{
	enum tcp_conntrack newconntrack, oldtcpstate;
	struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl);

	/* We're guaranteed to have the base header, but maybe not the
           options. */
	if (len < (iph->ihl + tcph->doff) * 4) {
		DEBUGP("ip_conntrack_tcp: Truncated packet.\n");
		return -1;
	}

	WRITE_LOCK(&tcp_lock);
	oldtcpstate = conntrack->proto.tcp.state;
	newconntrack
		= tcp_conntracks
		[CTINFO2DIR(ctinfo)]
		[get_conntrack_index(tcph)][oldtcpstate];

	/* Invalid */
	if (newconntrack == TCP_CONNTRACK_MAX) {
		DEBUGP("ip_conntrack_tcp: Invalid dir=%i index=%u conntrack=%u\n",
		       CTINFO2DIR(ctinfo), get_conntrack_index(tcph),
		       conntrack->proto.tcp.state);
		WRITE_UNLOCK(&tcp_lock);
		return -1;
	}

	conntrack->proto.tcp.state = newconntrack;

	/* Poor man's window tracking: record SYN/ACK for handshake check */
	if (oldtcpstate == TCP_CONNTRACK_SYN_SENT
	    && CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY
	    && tcph->syn && tcph->ack)
		conntrack->proto.tcp.handshake_ack
			= htonl(ntohl(tcph->seq) + 1);
	WRITE_UNLOCK(&tcp_lock);

	/* If only reply is a RST, we can consider ourselves not to
	   have an established connection: this is a fairly common
	   problem case, so we can delete the conntrack
	   immediately.  --RR */
	if (!(conntrack->status & IPS_SEEN_REPLY) && tcph->rst) {
		if (del_timer(&conntrack->timeout))
			conntrack->timeout.function((unsigned long)conntrack);
	} else {
		/* Set ASSURED if we see see valid ack in ESTABLISHED after SYN_RECV */
		if (oldtcpstate == TCP_CONNTRACK_SYN_RECV
		    && CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL
		    && tcph->ack && !tcph->syn
		    && tcph->ack_seq == conntrack->proto.tcp.handshake_ack)
			set_bit(IPS_ASSURED_BIT, &conntrack->status);

		ip_ct_refresh(conntrack, tcp_timeouts[newconntrack]);
	}

	return NF_ACCEPT;
}
示例#6
0
/* timeout GRE data connections */
static int pptp_timeout_related(struct ip_conntrack *ct)
{
	struct list_head *cur_item, *next;
	struct ip_conntrack_expect *exp;

	/* FIXME: do we have to lock something ? */
	for (cur_item = ct->sibling_list.next;
	    cur_item != &ct->sibling_list; cur_item = next) {
		next = cur_item->next;
		exp = list_entry(cur_item, struct ip_conntrack_expect,
				 expected_list);

		ip_ct_gre_keymap_destroy(exp);
		if (!exp->sibling) {
			ip_conntrack_unexpect_related(exp);
			continue;
		}

		DEBUGP("setting timeout of conntrack %p to 0\n",
			exp->sibling);
		exp->sibling->proto.gre.timeout = 0;
		exp->sibling->proto.gre.stream_timeout = 0;
		ip_ct_refresh(exp->sibling, 0);
	}

	return 0;
}
/* Returns verdict for packet, or -1 for invalid. */
static int established(struct ip_conntrack *conntrack,
		       struct iphdr *iph, size_t len,
		       enum ip_conntrack_info conntrackinfo)
{
	ip_ct_refresh(conntrack, ip_ct_generic_timeout);
	return NF_ACCEPT;
}
/* Returns verdict for packet, and may modify conntracktype */
static int udp_packet(struct ip_conntrack *conntrack,
		      const struct sk_buff *skb,
		      enum ip_conntrack_info conntrackinfo)
{
	/* If we've seen traffic both ways, this is some kind of UDP
	   stream.  Extend timeout. */
	if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
		ip_ct_refresh(conntrack, ip_ct_udp_timeout_stream);
		/* Also, more likely to be important, and not a probe */
		set_bit(IPS_ASSURED_BIT, &conntrack->status);
	} else
#if defined(CONFIG_MIPS_BRCM) 
	{
		/* Special handling of UNRPLIED DNS query packet: Song Wang
		*  Before NAT and WAN interface are UP, during that time window,
		* if a DNS query is sent out, there will be an UNRPLIED DNS connection track entry
		* in which expected src/dst are private IP addresses in the tuple.
		* After  NAT and WAN interface are UP, the UNRPLIED DNS connection track
		* entry should go away ASAP to enable the establishment  of the tuple with
		* the expected src/dst that are public IP addresses. 
		*/
		struct iphdr *iph = skb->nh.iph;
		struct udphdr *udph = (void *)iph + iph->ihl * 4;
		__u16 dport = ntohs(udph->dest);

		if (dport == 53)
			ip_ct_refresh(conntrack, ip_ct_udp_unreplieddns_timeout);
		else   
			ip_ct_refresh(conntrack, ip_ct_udp_timeout);
	}
#else	
		ip_ct_refresh(conntrack, ip_ct_udp_timeout);
#endif		

	return NF_ACCEPT;
}
示例#9
0
static int ip_outbound_pptp_tcp(const struct iphdr *iph, struct ip_conntrack *ct,
				enum ip_conntrack_info ctinfo)
{
	struct pptp_pkt_hdr		*pptph;
	struct PptpControlHeader	*ctlh;
        union {
                void				*rawreq;
                struct PptpOutCallRequest       *ocreq;
                struct PptpOutCallReply         *ocack;
                struct PptpInCallRequest        *icreq;
                struct PptpInCallReply          *icack;
		struct PptpClearCallRequest	*clrreq;
                struct PptpCallDisconnectNotify *disc;
                struct PptpWanErrorNotify       *wanerr;
                struct PptpSetLinkInfo          *setlink;
        } pptpReq;
	__u16				msg, *cid;

	pptph = (struct pptp_pkt_hdr *) ((char *) iph + sizeof(struct iphdr) + sizeof(struct tcphdr));

	DEBUGP("outbound_pptp_tcp(): CT=%lx, ", (unsigned long) ct);
	PRINTK_PPTP_HDR("", iph, pptph);

	ctlh = (struct PptpControlHeader *) ((char *) pptph + sizeof(struct pptp_pkt_hdr));
	pptpReq.rawreq = (void *) ((char*) ctlh + sizeof(struct PptpControlHeader));
	switch (msg = htons(ctlh->messageType)) {
		case PPTP_OUT_CALL_REQUEST:
			/* masq'd client initiating connection to server */
			cid = &pptpReq.ocreq->callID;
			break;		/* create conntrack and get CID */

		case PPTP_IN_CALL_REQUEST:
			/* masq'd client initiating connection to server */
			cid = &pptpReq.icreq->callID;
			break;		/* create conntrack and get CID */

		case PPTP_CALL_CLEAR_REQUEST:
			/* masq'd client sending to server */
			/* no need to alter conntrack */
			return 0;

		case PPTP_CALL_DISCONNECT_NOTIFY:
			/* masq'd client notifying server */
			/* expire this connection */
			ip_ct_refresh(ct, (30*HZ));
			clear_gre_tuples(ct);
			return 0;

		default:
			DEBUGP("UNKNOWN outbound packet: ");
			DEBUGP("%s (TY=%d)\n", (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0], msg);
			/* fall through */

		case PPTP_SET_LINK_INFO:
		case PPTP_START_SESSION_REQUEST:
		case PPTP_START_SESSION_REPLY:
		case PPTP_STOP_SESSION_REQUEST:
		case PPTP_STOP_SESSION_REPLY:
		case PPTP_ECHO_REQUEST:
			/* no need to alter conntrack */
			return 0;
	}


	/* Info for NAT */
	DEBUGP("ip_outbound_pptp_tcp: original client call id: %d\n", *cid);
	ct->nat.help.pptp_info.call_id = *cid;

	DEBUGP("ip_outbound_pptp_tcp(): ");
	DEBUGP("%s, CT=%lx, CID=%d\n", strMName[msg], (unsigned long) ct,
		(cid ? ntohs(*cid) : 0));

	return NF_ACCEPT;
}
示例#10
0
static int ip_inbound_pptp_tcp(const struct iphdr *iph, struct ip_conntrack *ct,
				enum ip_conntrack_info ctinfo)
{
	struct pptp_pkt_hdr		*pptph;
	struct PptpControlHeader	*ctlh;
        union {
                void				*rawreq;
                struct PptpOutCallRequest       *ocreq;
                struct PptpOutCallReply         *ocack;
                struct PptpInCallRequest        *icreq;
                struct PptpInCallReply          *icack;
		struct PptpClearCallRequest	*clrreq;
                struct PptpCallDisconnectNotify *disc;
                struct PptpWanErrorNotify       *wanerr;
                struct PptpSetLinkInfo          *setlink;
        } pptpReq;
	__u16				msg, *cid, *pcid;
	int dir = CTINFO2DIR(ctinfo);

	pptph = (struct pptp_pkt_hdr *) ((char *) iph + sizeof(struct iphdr) + sizeof(struct tcphdr));

	DEBUGP("inbound_pptp_tcp(): CT=%lx, ", (unsigned long) ct);
	PRINTK_PPTP_HDR("", iph, pptph);

	ctlh = (struct PptpControlHeader *) ((char *) pptph + sizeof(struct pptp_pkt_hdr));
	pptpReq.rawreq = (void *) ((char*) ctlh + sizeof(struct PptpControlHeader));
	switch (msg = htons(ctlh->messageType)) {
		case PPTP_OUT_CALL_REPLY:
			/* server responding to masq'd client */
			cid = &pptpReq.ocack->callID;
			pcid = &pptpReq.ocack->peersCallID;
			break;

		case PPTP_IN_CALL_REPLY:
			/* server responding to masq'd client */
			cid = &pptpReq.icack->callID;
			pcid = &pptpReq.icack->peersCallID;
			break;

		case PPTP_WAN_ERROR_NOTIFY:
			/* server notifying masq'd client */
			/* no need to alter conntrack */
			return 0;

		case PPTP_SET_LINK_INFO:
			/* server notifying masq'd client */
			/* no need to alter conntrack */
			return 0;

		case PPTP_CALL_DISCONNECT_NOTIFY:
			/* server notifying masq'd client */
			/* expire this connection */
			ip_ct_refresh(ct, (30*HZ));
			clear_gre_tuples(ct);
			return 0;

		default:
			DEBUGP("UNKNOWN inbound packet: ");
			DEBUGP("%s (TY=%d)\n", (msg <= PPTP_MSG_MAX)? strMName[msg] : strMName[0], msg);
			/* fall through */

		case PPTP_ECHO_REPLY:
		case PPTP_START_SESSION_REQUEST:
		case PPTP_START_SESSION_REPLY:
		case PPTP_STOP_SESSION_REQUEST:
		case PPTP_STOP_SESSION_REPLY:
		case PPTP_ECHO_REQUEST:
			/* no need to alter conntrack */
			return 0;
	}

	LOCK_BH(&ip_pptp_lock);

	/* info for conntrack/NAT */
        struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;
        struct ip_conntrack_expect expect, *exp = &expect;
        struct ip_ct_pptp_expect *exp_pptp_info = &exp->help.exp_pptp_info;

	exp_pptp_info->pptp_magic = PPTP_TCP_PORT;		/* our magic number */
	exp_pptp_info->orig_call_id = *cid;
	exp_pptp_info->peer_call_id = *pcid;
	INIT_LIST_HEAD(&(ct_pptp_info->list));

	/* tuple for GRE packets (from server to masqed client)
	 * Here src = pptp server, dst = ppp addr 
	 * !dir: src = masq client, dst = pptp server 
	 */

	/*	
	 *	masq client <--> pptp serv 
	 *	new connection replaces any old ones.
	 */
	
	/*
	 * 	populate our lists for peer call ID lookup
	 */
	put_gre_tuple(ct->tuplehash[!dir].tuple.src.ip, ct->tuplehash[!dir].tuple.dst.ip, *cid, *pcid, ct);
	put_gre_tuple(ct->tuplehash[!dir].tuple.dst.ip, ct->tuplehash[!dir].tuple.src.ip, *pcid, *cid, ct);
	put_gre_tuple(ct->tuplehash[dir].tuple.src.ip, ct->tuplehash[dir].tuple.dst.ip, *pcid, *cid, ct);
	put_gre_tuple(ct->tuplehash[dir].tuple.dst.ip, ct->tuplehash[dir].tuple.src.ip, *cid, *pcid, ct);

	if(ip_conntrack_protocol_register(&ip_conntrack_protocol_gre) == 0)
		DEBUGP("pptp: registered conntrack protocol GRE!\n");
	else
		DEBUGP("pptp: failed to register conntrack protocol GRE!\n");

	UNLOCK_BH(&ip_pptp_lock);

	return 0;
}
static int help(struct sk_buff **pskb,
                struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
{
	struct ip_conntrack_expect *exp;
	char *data, *data_limit, *tmp;
	unsigned int dataoff, i;
	u_int16_t port, len;
	int ret = NF_ACCEPT;

	/* Only look at packets from the Amanda server */
	if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
		return NF_ACCEPT;

	/* increase the UDP timeout of the master connection as replies from
	 * Amanda clients to the server can be quite delayed */
	ip_ct_refresh(ct, *pskb, master_timeout * HZ);

	/* No data? */
	dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
	if (dataoff >= (*pskb)->len) {
		if (net_ratelimit())
			printk("amanda_help: skblen = %u\n", (*pskb)->len);
		return NF_ACCEPT;
	}

	spin_lock_bh(&amanda_buffer_lock);
	skb_copy_bits(*pskb, dataoff, amanda_buffer, (*pskb)->len - dataoff);
	data = amanda_buffer;
	data_limit = amanda_buffer + (*pskb)->len - dataoff;
	*data_limit = '\0';

	/* Search for the CONNECT string */
	data = strstr(data, "CONNECT ");
	if (!data)
		goto out;
	data += strlen("CONNECT ");

	/* Only search first line. */	
	if ((tmp = strchr(data, '\n')))
		*tmp = '\0';

	for (i = 0; i < ARRAY_SIZE(conns); i++) {
		char *match = strstr(data, conns[i]);
		if (!match)
			continue;
		tmp = data = match + strlen(conns[i]);
		port = simple_strtoul(data, &data, 10);
		len = data - tmp;
		if (port == 0 || len > 5)
			break;

		exp = ip_conntrack_expect_alloc(ct);
		if (exp == NULL) {
			ret = NF_DROP;
			goto out;
		}

		exp->expectfn = NULL;
		exp->flags = 0;

		exp->tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
		exp->tuple.src.u.tcp.port = 0;
		exp->tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
		exp->tuple.dst.protonum = IPPROTO_TCP;
		exp->tuple.dst.u.tcp.port = htons(port);

		exp->mask.src.ip = 0xFFFFFFFF;
		exp->mask.src.u.tcp.port = 0;
		exp->mask.dst.ip = 0xFFFFFFFF;
		exp->mask.dst.protonum = 0xFF;
		exp->mask.dst.u.tcp.port = 0xFFFF;

		if (ip_nat_amanda_hook)
			ret = ip_nat_amanda_hook(pskb, ctinfo,
						 tmp - amanda_buffer,
						 len, exp);
		else if (ip_conntrack_expect_related(exp) != 0)
			ret = NF_DROP;
		ip_conntrack_expect_put(exp);
	}

out:
	spin_unlock_bh(&amanda_buffer_lock);
	return ret;
}
/* Returns verdict for packet, or -1 for invalid. */
static int tcp_packet(struct ip_conntrack *conntrack,
		      const struct sk_buff *skb,
		      enum ip_conntrack_info ctinfo)
{
	enum tcp_conntrack newconntrack, oldtcpstate;
	struct tcphdr tcph;

	if (skb_copy_bits(skb, skb->nh.iph->ihl * 4, &tcph, sizeof(tcph)) != 0)
		return -1;
	if (skb->len < skb->nh.iph->ihl * 4 + tcph.doff * 4)
		return -1;

	/* If only reply is a RST, we can consider ourselves not to
	   have an established connection: this is a fairly common
	   problem case, so we can delete the conntrack
	   immediately.  --RR */
	if (!test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) && tcph.rst) {
		if (del_timer(&conntrack->timeout))
			conntrack->timeout.function((unsigned long)conntrack);
		return NF_ACCEPT;
	}

	WRITE_LOCK(&tcp_lock);
	oldtcpstate = conntrack->proto.tcp.state;
	newconntrack
		= tcp_conntracks
		[CTINFO2DIR(ctinfo)]
		[get_conntrack_index(&tcph)][oldtcpstate];

	/* Invalid */
	if (newconntrack == TCP_CONNTRACK_MAX) {
		DEBUGP("ip_conntrack_tcp: Invalid dir=%i index=%u conntrack=%u\n",
		       CTINFO2DIR(ctinfo), get_conntrack_index(&tcph),
		       conntrack->proto.tcp.state);
		WRITE_UNLOCK(&tcp_lock);
		return -1;
	}

	conntrack->proto.tcp.state = newconntrack;

	/* Poor man's window tracking: record SYN/ACK for handshake check */
	if (oldtcpstate == TCP_CONNTRACK_SYN_SENT
	    && CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY
	    && tcph.syn && tcph.ack) {
		conntrack->proto.tcp.handshake_ack
			= htonl(ntohl(tcph.seq) + 1);
		goto out;
	}

	/* Set ASSURED if we see valid ack in ESTABLISHED after SYN_RECV */
	if (oldtcpstate == TCP_CONNTRACK_SYN_RECV
	    && CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL
	    && tcph.ack && !tcph.syn
	    && tcph.ack_seq == conntrack->proto.tcp.handshake_ack)
		set_bit(IPS_ASSURED_BIT, &conntrack->status);

out:	WRITE_UNLOCK(&tcp_lock);
	ip_ct_refresh(conntrack, *tcp_timeouts[newconntrack]);

	return NF_ACCEPT;
}
示例#13
0
static int help(struct sk_buff **pskb,
                struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
{
	struct ts_state ts;
	struct ip_conntrack_expect *exp;
	unsigned int dataoff, start, stop, off, i;
	char pbuf[sizeof("65535")], *tmp;
	u_int16_t port, len;
	int ret = NF_ACCEPT;

	/* Only look at packets from the Amanda server */
	if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
		return NF_ACCEPT;

	/* increase the UDP timeout of the master connection as replies from
	 * Amanda clients to the server can be quite delayed */
	ip_ct_refresh(ct, *pskb, master_timeout * HZ);

	/* No data? */
	dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
	if (dataoff >= (*pskb)->len) {
		if (net_ratelimit())
			printk("amanda_help: skblen = %u\n", (*pskb)->len);
		return NF_ACCEPT;
	}

	memset(&ts, 0, sizeof(ts));
	start = skb_find_text(*pskb, dataoff, (*pskb)->len,
			      search[SEARCH_CONNECT].ts, &ts);
	if (start == UINT_MAX)
		goto out;
	start += dataoff + search[SEARCH_CONNECT].len;

	memset(&ts, 0, sizeof(ts));
	stop = skb_find_text(*pskb, start, (*pskb)->len,
			     search[SEARCH_NEWLINE].ts, &ts);
	if (stop == UINT_MAX)
		goto out;
	stop += start;

	for (i = SEARCH_DATA; i <= SEARCH_INDEX; i++) {
		memset(&ts, 0, sizeof(ts));
		off = skb_find_text(*pskb, start, stop, search[i].ts, &ts);
		if (off == UINT_MAX)
			continue;
		off += start + search[i].len;

		len = min_t(unsigned int, sizeof(pbuf) - 1, stop - off);
		if (skb_copy_bits(*pskb, off, pbuf, len))
			break;
		pbuf[len] = '\0';

		port = simple_strtoul(pbuf, &tmp, 10);
		len = tmp - pbuf;
		if (port == 0 || len > 5)
			break;

		exp = ip_conntrack_expect_alloc(ct);
		if (exp == NULL) {
			ret = NF_DROP;
			goto out;
		}

		exp->expectfn = NULL;
		exp->flags = 0;

		exp->tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
		exp->tuple.src.u.tcp.port = 0;
		exp->tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
		exp->tuple.dst.protonum = IPPROTO_TCP;
		exp->tuple.dst.u.tcp.port = htons(port);

		exp->mask.src.ip = htonl(0xFFFFFFFF);
		exp->mask.src.u.tcp.port = 0;
		exp->mask.dst.ip = htonl(0xFFFFFFFF);
		exp->mask.dst.protonum = 0xFF;
		exp->mask.dst.u.tcp.port = htons(0xFFFF);

		if (ip_nat_amanda_hook)
			ret = ip_nat_amanda_hook(pskb, ctinfo, off - dataoff,
						 len, exp);
		else if (ip_conntrack_expect_related(exp) != 0)
			ret = NF_DROP;
		ip_conntrack_expect_put(exp);
	}

out:
	return ret;
}
示例#14
0
static int help(struct sk_buff *skb,
		struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
{
	char *data, *data_limit;
	int dir = CTINFO2DIR(ctinfo);
	unsigned int dataoff, i;
	struct ip_ct_amanda *info =
				(struct ip_ct_amanda *)&ct->help.ct_ftp_info;

	/* Can't track connections formed before we registered */
	if (!info)
		return NF_ACCEPT;

	/* increase the UDP timeout of the master connection as replies from
	 * Amanda clients to the server can be quite delayed */
	ip_ct_refresh(ct, master_timeout * HZ);

	/* If packet is coming from Amanda server */
	if (dir == IP_CT_DIR_ORIGINAL)
		return NF_ACCEPT;

	/* No data? */
	dataoff = skb->nh.iph->ihl*4 + sizeof(struct udphdr);
	if (dataoff >= skb->len) {
		if (net_ratelimit())
			printk("ip_conntrack_amanda_help: skblen = %u\n",
			       (unsigned)skb->len);
		return NF_ACCEPT;
	}

	LOCK_BH(&ip_amanda_lock);
	skb_copy_bits(skb, dataoff, amanda_buffer, skb->len - dataoff);
	data = amanda_buffer;
	data_limit = amanda_buffer + skb->len - dataoff;
	*data_limit = '\0';

	/* Search for the CONNECT string */
	data = strstr(data, "CONNECT ");
	if (!data)
		goto out;

	DEBUGP("ip_conntrack_amanda_help: CONNECT found in connection "
		   "%u.%u.%u.%u:%u %u.%u.%u.%u:%u\n",
		   NIPQUAD(iph->saddr), htons(udph->source),
		   NIPQUAD(iph->daddr), htons(udph->dest));
	data += strlen("CONNECT ");

	/* Only search first line. */	
	if (strchr(data, '\n'))
		*strchr(data, '\n') = '\0';

	for (i = 0; i < ARRAY_SIZE(conns); i++) {
		char *match = strstr(data, conns[i]);
		if (match) {
			char *portchr;
			struct ip_conntrack_expect expect;
			struct ip_ct_amanda_expect *exp_amanda_info =
				&expect.help.exp_amanda_info;

			memset(&expect, 0, sizeof(expect));

			data += strlen(conns[i]);
			/* this is not really tcp, but let's steal an
			 * idea from a tcp stream helper :-) */
			// XXX expect.seq = data - amanda_buffer;
			exp_amanda_info->offset = data - amanda_buffer;
// XXX DEBUGP("expect.seq = %p - %p = %d\n", data, amanda_buffer, expect.seq);
DEBUGP("exp_amanda_info->offset = %p - %p = %d\n", data, amanda_buffer, exp_amanda_info->offset);
			portchr = data;
			exp_amanda_info->port = simple_strtoul(data, &data,10);
			exp_amanda_info->len = data - portchr;

			/* eat whitespace */
			while (*data == ' ')
				data++;
			DEBUGP("ip_conntrack_amanda_help: "
			       "CONNECT %s request with port "
			       "%u found\n", conns[i],
			       exp_amanda_info->port);

			expect.tuple = ((struct ip_conntrack_tuple)
				{ { ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip,
				    { 0 } },
				  { ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip,
				    { htons(exp_amanda_info->port) },
				    IPPROTO_TCP }});