예제 #1
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;
}
static void pptp_expectfn(struct ip_conntrack *ct,
			 struct ip_conntrack_expect *exp)
{
	DEBUGP("increasing timeouts\n");

	/* increase timeout of GRE data channel conntrack entry */
	ct->proto.gre.timeout = PPTP_GRE_TIMEOUT;
	ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT;

	/* Can you see how rusty this code is, compared with the pre-2.6.11
	 * one? That's what happened to my shiny newnat of 2002 ;( -HW */

	if (!ip_nat_pptp_hook_expectfn) {
		struct ip_conntrack_tuple inv_t;
		struct ip_conntrack_expect *exp_other;

		/* obviously this tuple inversion only works until you do NAT */
		invert_tuplepr(&inv_t, &exp->tuple);
		DEBUGP("trying to unexpect other dir: ");
		DUMP_TUPLE(&inv_t);
	
		exp_other = __ip_conntrack_exp_find(&inv_t);
		if (exp_other) {
			/* delete other expectation.  */
			DEBUGP("found\n");
			ip_conntrack_unexpect_related(exp_other);
		} else {
			DEBUGP("not found\n");
		}
	} else {
		/* we need more than simple inversion */
		ip_nat_pptp_hook_expectfn(ct, exp);
	}
}
static int timeout_ct_or_exp(const struct ip_conntrack_tuple *t)
{
	struct ip_conntrack_tuple_hash *h;
	struct ip_conntrack_expect *exp;

	DEBUGP("trying to timeout ct or exp for tuple ");
	DUMP_TUPLE(t);

	h = __ip_conntrack_find(t, NULL);
	if (h)  {
		struct ip_conntrack *sibling = tuplehash_to_ctrack(h);
		DEBUGP("setting timeout of conntrack %p to 0\n", sibling);
		sibling->proto.gre.timeout = 0;
		sibling->proto.gre.stream_timeout = 0;
		/* refresh_acct will not modify counters if skb == NULL */
		ip_ct_refresh_acct(sibling, 0, NULL, 0);
		return 1;
	} else {
		exp = __ip_conntrack_exp_find(t);
		if (exp) {
			DEBUGP("unexpect_related of expect %p\n", exp);
			ip_conntrack_unexpect_related(exp);
			return 1;
		}
	}

	return 0;
}
static int destroy_sibling_or_exp(const struct ip_conntrack_tuple *t)
{
	struct ip_conntrack_tuple_hash *h;
	struct ip_conntrack_expect *exp;

	DEBUGP("trying to timeout ct or exp for tuple ");
	DUMP_TUPLE(t);

	h = ip_conntrack_find_get(t, NULL);
	if (h)  {
		struct ip_conntrack *sibling = tuplehash_to_ctrack(h);
		DEBUGP("setting timeout of conntrack %p to 0\n", sibling);
		sibling->proto.gre.timeout = 0;
		sibling->proto.gre.stream_timeout = 0;
		if (del_timer(&sibling->timeout))
			sibling->timeout.function((unsigned long)sibling);
		ip_conntrack_put(sibling);
		return 1;
	} else {
		exp = ip_conntrack_expect_find(t);
		if (exp) {
			DEBUGP("unexpect_related of expect %p\n", exp);
			ip_conntrack_unexpect_related(exp);
			ip_conntrack_expect_put(exp);
			return 1;
		}
	}

	return 0;
}
예제 #5
0
/* So, this packet has hit the connection tracking matching code.
   Mangle it, and change the expectation to match the new version. */
static unsigned int ip_nat_ftp(struct sk_buff **pskb,
			       enum ip_conntrack_info ctinfo,
			       enum ip_ct_ftp_type type,
			       unsigned int matchoff,
			       unsigned int matchlen,
			       struct ip_conntrack_expect *exp,
			       u32 *seq)
{
	u_int32_t newip;
	u_int16_t port;
	int dir = CTINFO2DIR(ctinfo);
	struct ip_conntrack *ct = exp->master;

	DEBUGP("FTP_NAT: type %i, off %u len %u\n", type, matchoff, matchlen);

	/* Connection will come from wherever this packet goes, hence !dir */
	newip = ct->tuplehash[!dir].tuple.dst.ip;
	exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
	exp->dir = !dir;

	/* When you see the packet, we need to NAT it the same as the
	 * this one. */
	exp->expectfn = ip_nat_follow_master;

	/* Try to get same port: if not, try to change it. */
	for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
		exp->tuple.dst.u.tcp.port = htons(port);
		if (ip_conntrack_expect_related(exp) == 0)
			break;
	}

	if (port == 0) {
		ip_conntrack_expect_free(exp);
		return NF_DROP;
	}

	if (!mangle[type](pskb, newip, port, matchoff, matchlen, ct, ctinfo,
			  seq)) {
		ip_conntrack_unexpect_related(exp);
		return NF_DROP;
	}
	return NF_ACCEPT;
}
static int nat_t120(struct sk_buff **pskb, struct ip_conntrack *ct,
		    enum ip_conntrack_info ctinfo,
		    unsigned char **data, int dataoff,
		    H245_TransportAddress * addr, u_int16_t port,
		    struct ip_conntrack_expect *exp)
{
	int dir = CTINFO2DIR(ctinfo);
	u_int16_t nated_port = port;

	/* Set expectations for NAT */
	exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
	exp->expectfn = ip_nat_follow_master;
	exp->dir = !dir;

	/* Try to get same port: if not, try to change it. */
	for (; nated_port != 0; nated_port++) {
		exp->tuple.dst.u.tcp.port = htons(nated_port);
		if (ip_conntrack_expect_related(exp) == 0)
			break;
	}

	if (nated_port == 0) {	/* No port available */
		if (net_ratelimit())
			printk("ip_nat_h323: out of TCP ports\n");
		return 0;
	}

	/* Modify signal */
	if (set_h245_addr(pskb, data, dataoff, addr,
			  ct->tuplehash[!dir].tuple.dst.ip, nated_port) < 0) {
		ip_conntrack_unexpect_related(exp);
		return -1;
	}

	DEBUGP("ip_nat_h323: expect T.120 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
	       NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
	       NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));

	return 0;
}
예제 #7
0
/* So, this packet has hit the connection tracking matching code.
   Mangle it, and change the expectation to match the new version. */
static unsigned int ip_nat_sdp(struct sk_buff **pskb,
			       enum ip_conntrack_info ctinfo,
			       struct ip_conntrack_expect *exp,
			       const char *dptr)
{
	struct ip_conntrack *ct = exp->master;
	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
	u_int32_t newip;
	u_int16_t port;

	DEBUGP("ip_nat_sdp():\n");

	/* Connection will come from reply */
	newip = ct->tuplehash[!dir].tuple.dst.ip;

	exp->tuple.dst.ip = newip;
	exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
	exp->dir = !dir;

	/* When you see the packet, we need to NAT it the same as the
	   this one. */
	exp->expectfn = ip_nat_follow_master;

	/* Try to get same port: if not, try to change it. */
	for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) {
		exp->tuple.dst.u.udp.port = htons(port);
		if (ip_conntrack_expect_related(exp) == 0)
			break;
	}

	if (port == 0)
		return NF_DROP;

	if (!mangle_sdp(pskb, ctinfo, ct, newip, port, dptr)) {
		ip_conntrack_unexpect_related(exp);
		return NF_DROP;
	}
	return NF_ACCEPT;
}
예제 #8
0
static unsigned int help(struct sk_buff **pskb,
			 enum ip_conntrack_info ctinfo,
			 unsigned int matchoff,
			 unsigned int matchlen,
			 struct ip_conntrack_expect *exp)
{
	char buffer[sizeof("65535")];
	u_int16_t port;
	unsigned int ret;

	/* Connection comes from client. */
	exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
	exp->dir = IP_CT_DIR_ORIGINAL;

	/* When you see the packet, we need to NAT it the same as the
	 * this one (ie. same IP: it will be TCP and master is UDP). */
	exp->expectfn = ip_nat_follow_master;

	/* Try to get same port: if not, try to change it. */
	for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
		exp->tuple.dst.u.tcp.port = htons(port);
		if (ip_conntrack_expect_related(exp) == 0)
			break;
	}

	if (port == 0) {
		ip_conntrack_expect_free(exp);
		return NF_DROP;
	}

	sprintf(buffer, "%u", port);
	ret = ip_nat_mangle_udp_packet(pskb, exp->master, ctinfo,
				       matchoff, matchlen,
				       buffer, strlen(buffer));
	if (ret != NF_ACCEPT)
		ip_conntrack_unexpect_related(exp);
	return ret;
}
예제 #9
0
static int pptp_expectfn(struct ip_conntrack *ct)
{
	struct ip_conntrack *master;
	struct ip_conntrack_expect *exp;

	#ifdef CONFIG_IFX_ALG_QOS  // chandrav
	IFX_ALG_QOS_DBG("\nPPTP_ALG: Master conntracker ifx_alg_qos_mark is : %x \n",ct->ifx_alg_qos_mark );
	/*
	 * Mark the connection tracker with PPTP ALG Application Family type 
	 * (IFX_ALG_PROTO_DATA) and PPTP ALG Protocol Family type 
	 * (IFX_ALG_PROTO_DATA)	
	 */
	ct->ifx_alg_qos_mark = IFX_ALG_APP_PPTP | IFX_ALG_PROTO_DATA;
	IFX_ALG_QOS_DBG("\nPPTP ALG:Marked the Child conntracker with:%x \n",
					ct->ifx_alg_qos_mark );	
	#endif /* CONFIG_IFX_ALG_QOS */

	DEBUGP("increasing timeouts\n");
	/* increase timeout of GRE data channel conntrack entry */
	ct->proto.gre.timeout = PPTP_GRE_TIMEOUT;
	ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT;

	master = master_ct(ct);
	if (!master) {
		DEBUGP(" no master!!!\n");
		return 0;
	}

	exp = ct->master;
	if (!exp) {
		DEBUGP("no expectation!!\n");
		return 0;
	}

	DEBUGP("completing tuples with ct info\n");
	/* we can do this, since we're unconfirmed */
	if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == 
		htonl(master->help.ct_pptp_info.pac_call_id)) {	
		/* assume PNS->PAC */
		ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = 
			htonl(master->help.ct_pptp_info.pns_call_id);
		ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
			htonl(master->help.ct_pptp_info.pns_call_id);
	} else {
		/* assume PAC->PNS */
		ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
			htonl(master->help.ct_pptp_info.pac_call_id);
		ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
			htonl(master->help.ct_pptp_info.pac_call_id);
	}
	
	/* delete other expectation */
	if (exp->expected_list.next != &exp->expected_list) {
		struct ip_conntrack_expect *other_exp;
		struct list_head *cur_item, *next;

		for (cur_item = master->sibling_list.next;
		     cur_item != &master->sibling_list; cur_item = next) {
			next = cur_item->next;
			other_exp = list_entry(cur_item,
					       struct ip_conntrack_expect,
					       expected_list);
			/* remove only if occurred at same sequence number */
			if (other_exp != exp && other_exp->seq == exp->seq) {
				DEBUGP("unexpecting other direction\n");
				ip_ct_gre_keymap_destroy(other_exp);
				ip_conntrack_unexpect_related(other_exp);
			}
		}
	}

	return 0;
}
static int nat_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct,
			enum ip_conntrack_info ctinfo,
			unsigned char **data, int dataoff,
			H245_TransportAddress * addr,
			u_int16_t port, u_int16_t rtp_port,
			struct ip_conntrack_expect *rtp_exp,
			struct ip_conntrack_expect *rtcp_exp)
{
	struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
	int dir = CTINFO2DIR(ctinfo);
	int i;
	u_int16_t nated_port;

	/* Set expectations for NAT */
	rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
	rtp_exp->expectfn = ip_nat_follow_master;
	rtp_exp->dir = !dir;
	rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
	rtcp_exp->expectfn = ip_nat_follow_master;
	rtcp_exp->dir = !dir;

	/* Lookup existing expects */
	for (i = 0; i < H323_RTP_CHANNEL_MAX; i++) {
		if (info->rtp_port[i][dir] == rtp_port) {
			/* Expected */

			/* Use allocated ports first. This will refresh
			 * the expects */
			rtp_exp->tuple.dst.u.udp.port =
			    htons(info->rtp_port[i][dir]);
			rtcp_exp->tuple.dst.u.udp.port =
			    htons(info->rtp_port[i][dir] + 1);
			break;
		} else if (info->rtp_port[i][dir] == 0) {
			/* Not expected */
			break;
		}
	}

	/* Run out of expectations */
	if (i >= H323_RTP_CHANNEL_MAX) {
		if (net_ratelimit())
			printk("ip_nat_h323: out of expectations\n");
		return 0;
	}

	/* Try to get a pair of ports. */
	for (nated_port = ntohs(rtp_exp->tuple.dst.u.udp.port);
	     nated_port != 0; nated_port += 2) {
		rtp_exp->tuple.dst.u.udp.port = htons(nated_port);
		if (ip_conntrack_expect_related(rtp_exp) == 0) {
			rtcp_exp->tuple.dst.u.udp.port =
			    htons(nated_port + 1);
			if (ip_conntrack_expect_related(rtcp_exp) == 0)
				break;
			ip_conntrack_unexpect_related(rtp_exp);
		}
	}

	if (nated_port == 0) {	/* No port available */
		if (net_ratelimit())
			printk("ip_nat_h323: out of RTP ports\n");
		return 0;
	}

	/* Modify signal */
	if (set_h245_addr(pskb, data, dataoff, addr,
			  ct->tuplehash[!dir].tuple.dst.ip,
			  (port & 1) ? nated_port + 1 : nated_port) == 0) {
		/* Save ports */
		info->rtp_port[i][dir] = rtp_port;
		info->rtp_port[i][!dir] = nated_port;
	} else {
		ip_conntrack_unexpect_related(rtp_exp);
		ip_conntrack_unexpect_related(rtcp_exp);
		return -1;
	}

	/* Success */
	DEBUGP("ip_nat_h323: expect RTP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
	       NIPQUAD(rtp_exp->tuple.src.ip),
	       ntohs(rtp_exp->tuple.src.u.udp.port),
	       NIPQUAD(rtp_exp->tuple.dst.ip),
	       ntohs(rtp_exp->tuple.dst.u.udp.port));
	DEBUGP("ip_nat_h323: expect RTCP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
	       NIPQUAD(rtcp_exp->tuple.src.ip),
	       ntohs(rtcp_exp->tuple.src.u.udp.port),
	       NIPQUAD(rtcp_exp->tuple.dst.ip),
	       ntohs(rtcp_exp->tuple.dst.u.udp.port));

	return 0;
}
예제 #11
0
static void pptp_nat_expected(struct ip_conntrack *ct,
			      struct ip_conntrack_expect *exp)
{
	struct ip_conntrack *master = ct->master;
	struct ip_conntrack_expect *other_exp;
	struct ip_conntrack_tuple t;
	struct ip_ct_pptp_master *ct_pptp_info;
	struct ip_nat_pptp *nat_pptp_info;
	struct ip_nat_range range;

	ct_pptp_info = &master->help.ct_pptp_info;
	nat_pptp_info = &master->nat.help.nat_pptp_info;

	/* And here goes the grand finale of corrosion... */

	if (exp->dir == IP_CT_DIR_ORIGINAL) {
		DEBUGP("we are PNS->PAC\n");
		/* therefore, build tuple for PAC->PNS */
		t.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
		t.src.u.gre.key = htons(master->help.ct_pptp_info.pac_call_id);
		t.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
		t.dst.u.gre.key = htons(master->help.ct_pptp_info.pns_call_id);
		t.dst.protonum = IPPROTO_GRE;
	} else {
		DEBUGP("we are PAC->PNS\n");
		/* build tuple for PNS->PAC */
		t.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
		t.src.u.gre.key = 
			htons(master->nat.help.nat_pptp_info.pns_call_id);
		t.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
		t.dst.u.gre.key = 
			htons(master->nat.help.nat_pptp_info.pac_call_id);
		t.dst.protonum = IPPROTO_GRE;
	}

	DEBUGP("trying to unexpect other dir: \n");
	DUMP_TUPLE(&t);
	other_exp = __ip_conntrack_exp_find(&t);
	if (other_exp) {
		ip_conntrack_unexpect_related(other_exp);
		DEBUGP("success\n");
	} else {
		DEBUGP("not found!\n");
	}

	/* This must be a fresh one. */
	BUG_ON(ct->status & IPS_NAT_DONE_MASK);

	/* Change src to where master sends to */
	range.flags = IP_NAT_RANGE_MAP_IPS;
	range.min_ip = range.max_ip
		= ct->master->tuplehash[!exp->dir].tuple.dst.ip;
	if (exp->dir == IP_CT_DIR_ORIGINAL) {
		range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
		range.min = range.max = exp->saved_proto;
	}
	/* hook doesn't matter, but it has to do source manip */
	ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING);

	/* For DST manip, map port here to where it's expected. */
	range.flags = IP_NAT_RANGE_MAP_IPS;
	range.min_ip = range.max_ip
		= ct->master->tuplehash[!exp->dir].tuple.src.ip;
//sam add +++ 2008.10.03 for pptp passthrough can not work.
	ct->tuplehash[!exp->dir].tuple.dst.u.gre.key = t.dst.u.gre.key;
//sam add ---	
	if (exp->dir == IP_CT_DIR_REPLY) {
		range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
		range.min = range.max = exp->saved_proto;
	}
	/* hook doesn't matter, but it has to do destination manip */
	ip_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING);
}
예제 #12
0
static int
pptp_exp_gre(struct ip_conntrack_expect *expect_orig,
	     struct ip_conntrack_expect *expect_reply)
{
	struct ip_ct_pptp_master *ct_pptp_info = 
				&expect_orig->master->help.ct_pptp_info;
	struct ip_nat_pptp *nat_pptp_info = 
				&expect_orig->master->nat.help.nat_pptp_info;

	struct ip_conntrack *ct = expect_orig->master;

	struct ip_conntrack_tuple inv_t;
	struct ip_conntrack_tuple *orig_t, *reply_t;

	/* save original PAC call ID in nat_info */
	nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id;

	/* alter expectation */
	orig_t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
	reply_t = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;

	/* alter expectation for PNS->PAC direction */
	invert_tuplepr(&inv_t, &expect_orig->tuple);
	expect_orig->saved_proto.gre.key = htons(ct_pptp_info->pns_call_id);
	expect_orig->tuple.src.u.gre.key = htons(nat_pptp_info->pns_call_id);
	expect_orig->tuple.dst.u.gre.key = htons(ct_pptp_info->pac_call_id);
	inv_t.src.ip = reply_t->src.ip;
	inv_t.dst.ip = reply_t->dst.ip;
	inv_t.src.u.gre.key = htons(nat_pptp_info->pac_call_id);
	inv_t.dst.u.gre.key = htons(ct_pptp_info->pns_call_id);

	if (!ip_conntrack_expect_related(expect_orig)) {
		DEBUGP("successfully registered expect\n");
	} else {
		DEBUGP("can't expect_related(expect_orig)\n");
		ip_conntrack_expect_free(expect_orig);
		return 1;
	}

	/* alter expectation for PAC->PNS direction */
	invert_tuplepr(&inv_t, &expect_reply->tuple);
	expect_reply->saved_proto.gre.key = htons(nat_pptp_info->pns_call_id);
	expect_reply->tuple.src.u.gre.key = htons(nat_pptp_info->pac_call_id);
	expect_reply->tuple.dst.u.gre.key = htons(ct_pptp_info->pns_call_id);
	inv_t.src.ip = orig_t->src.ip;
	inv_t.dst.ip = orig_t->dst.ip;
	inv_t.src.u.gre.key = htons(nat_pptp_info->pns_call_id);
	inv_t.dst.u.gre.key = htons(ct_pptp_info->pac_call_id);

	if (!ip_conntrack_expect_related(expect_reply)) {
		DEBUGP("successfully registered expect\n");
	} else {
		DEBUGP("can't expect_related(expect_reply)\n");
		ip_conntrack_unexpect_related(expect_orig);
		ip_conntrack_expect_free(expect_reply);
		return 1;
	}

	if (ip_ct_gre_keymap_add(ct, &expect_reply->tuple, 0) < 0) {
		DEBUGP("can't register original keymap\n");
		ip_conntrack_unexpect_related(expect_orig);
		ip_conntrack_unexpect_related(expect_reply);
		return 1;
	}

	if (ip_ct_gre_keymap_add(ct, &inv_t, 1) < 0) {
		DEBUGP("can't register reply keymap\n");
		ip_conntrack_unexpect_related(expect_orig);
		ip_conntrack_unexpect_related(expect_reply);
		ip_ct_gre_keymap_destroy(ct);
		return 1;
	}

	return 0;
}
예제 #13
0
static unsigned int help(struct sk_buff **pskb,
                         enum ip_conntrack_info ctinfo,
                         unsigned int matchoff,
                         unsigned int matchlen,
                         struct ip_conntrack_expect *exp)
{
    u_int16_t port;
    unsigned int ret;

    /* "4294967296 65635 " */
    char buffer[18];

    DEBUGP("IRC_NAT: info (seq %u + %u) in %u\n",
           expect->seq, exp_irc_info->len,
           ntohl(tcph->seq));

    /* Reply comes from server. */
    exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
    exp->dir = IP_CT_DIR_REPLY;

    /* When you see the packet, we need to NAT it the same as the
     * this one. */
    exp->expectfn = ip_nat_follow_master;

    /* Try to get same port: if not, try to change it. */
    for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
        exp->tuple.dst.u.tcp.port = htons(port);
        if (ip_conntrack_expect_related(exp) == 0)
            break;
    }

    if (port == 0)
        return NF_DROP;

    /*      strlen("\1DCC CHAT chat AAAAAAAA P\1\n")=27
     *      strlen("\1DCC SCHAT chat AAAAAAAA P\1\n")=28
     *      strlen("\1DCC SEND F AAAAAAAA P S\1\n")=26
     *      strlen("\1DCC MOVE F AAAAAAAA P S\1\n")=26
     *      strlen("\1DCC TSEND F AAAAAAAA P S\1\n")=27
     *              AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits,
     *                      255.255.255.255==4294967296, 10 digits)
     *              P:         bound port (min 1 d, max 5d (65635))
     *              F:         filename   (min 1 d )
     *              S:         size       (min 1 d )
     *              0x01, \n:  terminators
     */

    /* AAA = "us", ie. where server normally talks to. */
    sprintf(buffer, "%u %u",
            ntohl(exp->master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip),
            port);
    DEBUGP("ip_nat_irc: Inserting '%s' == %u.%u.%u.%u, port %u\n",
           buffer, NIPQUAD(exp->tuple.src.ip), port);

    ret = ip_nat_mangle_tcp_packet(pskb, exp->master, ctinfo,
                                   matchoff, matchlen, buffer,
                                   strlen(buffer));
    if (ret != NF_ACCEPT)
        ip_conntrack_unexpect_related(exp);
    return ret;
}
예제 #14
0
static int pptp_expectfn(struct ip_conntrack *ct)
{
	struct ip_conntrack *master;
	struct ip_conntrack_expect *exp;

	DEBUGP("increasing timeouts\n");
	/* increase timeout of GRE data channel conntrack entry */
	ct->proto.gre.timeout = PPTP_GRE_TIMEOUT;
	ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT;

	master = master_ct(ct);
	if (!master) {
		DEBUGP(" no master!!!\n");
		return 0;
	}

	exp = ct->master;
	if (!exp) {
		DEBUGP("no expectation!!\n");
		return 0;
	}

	DEBUGP("completing tuples with ct info\n");
	/* we can do this, since we're unconfirmed */
	if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == 
		htonl(master->help.ct_pptp_info.pac_call_id)) {	
		/* assume PNS->PAC */
		ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = 
			htonl(master->help.ct_pptp_info.pns_call_id);
		ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
			htonl(master->help.ct_pptp_info.pns_call_id);
	} else {
		/* assume PAC->PNS */
		ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
			htonl(master->help.ct_pptp_info.pac_call_id);
		ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
			htonl(master->help.ct_pptp_info.pac_call_id);
	}
	
	/* delete other expectation */
	if (exp->expected_list.next != &exp->expected_list) {
		struct ip_conntrack_expect *other_exp;
		struct list_head *cur_item, *next;

		for (cur_item = master->sibling_list.next;
		     cur_item != &master->sibling_list; cur_item = next) {
			next = cur_item->next;
			other_exp = list_entry(cur_item,
					       struct ip_conntrack_expect,
					       expected_list);
			/* remove only if occurred at same sequence number */
			if (other_exp != exp && other_exp->seq == exp->seq) {
				DEBUGP("unexpecting other direction\n");
				ip_ct_gre_keymap_destroy(other_exp);
				ip_conntrack_unexpect_related(other_exp);
			}
		}
	}

	return 0;
}