Exemplo n.º 1
0
static int talk_help_response(const struct iphdr *iph, size_t len,
		              struct ip_conntrack *ct,
		              enum ip_conntrack_info ctinfo,
		              int talk_port,
		              u_char mode,
		              u_char type,
		              u_char answer,
		              struct talk_addr *addr)
{
	int dir = CTINFO2DIR(ctinfo);
	struct ip_conntrack_expect expect, *exp = &expect;
	struct ip_ct_talk_expect *exp_talk_info = &exp->help.exp_talk_info;

	DEBUGP("ip_ct_talk_help_response: %u.%u.%u.%u:%u, type %d answer %d\n",
		NIPQUAD(addr->ta_addr), ntohs(addr->ta_port),
		type, answer);

	if (!(answer == SUCCESS && type == mode))
		return NF_ACCEPT;
	
	memset(&expect, 0, sizeof(expect));
	
	if (type == ANNOUNCE) {

		DEBUGP("ip_ct_talk_help_response: ANNOUNCE\n");

		/* update the talk info */
		LOCK_BH(&ip_talk_lock);
		exp_talk_info->port = htons(talk_port);

		/* expect callee client -> caller server message */
		exp->tuple = ((struct ip_conntrack_tuple)
			{ { ct->tuplehash[dir].tuple.src.ip,
			    { 0 } },
			  { ct->tuplehash[dir].tuple.dst.ip,
Exemplo n.º 2
0
static unsigned int
pptp_nat_expected(struct sk_buff **pskb,
		  unsigned int hooknum,
		  struct ip_conntrack *ct,
		  struct ip_nat_info *info)
{
	struct ip_conntrack *master = master_ct(ct);
	struct ip_nat_multi_range mr;
	struct ip_ct_pptp_master *ct_pptp_info;
	struct ip_nat_pptp *nat_pptp_info;
	u_int32_t newsrcip, newdstip, newcid;
	int ret;

	IP_NF_ASSERT(info);
	IP_NF_ASSERT(master);
	IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));

	DEBUGP("we have a connection!\n");

	LOCK_BH(&ip_pptp_lock);
	ct_pptp_info = &master->help.ct_pptp_info;
	nat_pptp_info = &master->nat.help.nat_pptp_info;

	/* need to alter GRE tuple because conntrack expectfn() used 'wrong'
	 * (unmanipulated) values */
	if (hooknum == NF_IP_PRE_ROUTING) {
		DEBUGP("completing tuples with NAT info \n");
		/* we can do this, since we're unconfirmed */
		if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key ==
			htonl(ct_pptp_info->pac_call_id)) {	
			/* assume PNS->PAC */
			ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
				htonl(nat_pptp_info->pns_call_id);
//			ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.gre.key =
//				htonl(nat_pptp_info->pac_call_id);
			ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
				htonl(nat_pptp_info->pns_call_id);
		} else {
			/* assume PAC->PNS */
			DEBUGP("WRONG DIRECTION\n");
			ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
				htonl(nat_pptp_info->pac_call_id);
			ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
				htonl(nat_pptp_info->pns_call_id);
		}
	}

	if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
		//OsborneModify Start on August 3, 2006.
		//newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
		newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
		//OsborneModify End.
		newcid = htonl(master->nat.help.nat_pptp_info.pac_call_id);

		mr.rangesize = 1;
		mr.range[0].flags = IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED;
		mr.range[0].min_ip = mr.range[0].max_ip = newdstip;
		mr.range[0].min = mr.range[0].max = 
			((union ip_conntrack_manip_proto ) { newcid }); 
Exemplo n.º 3
0
static unsigned int help(struct ip_conntrack *ct,
			 struct ip_conntrack_expect *exp,
			 struct ip_nat_info *info,
			 enum ip_conntrack_info ctinfo,
			 unsigned int hooknum, 
			 struct sk_buff **pskb)
{
	struct iphdr *iph = (*pskb)->nh.iph;
	struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
	unsigned int datalen;
	int dir;
	struct ip_ct_irc_expect *ct_irc_info;

	if (!exp)
		DEBUGP("ip_nat_irc: no exp!!");
		
	ct_irc_info = &exp->help.exp_irc_info;

	/* Only mangle things once: original direction in POST_ROUTING
	   and reply direction on PRE_ROUTING. */
	dir = CTINFO2DIR(ctinfo);
	if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
	      || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) {
		DEBUGP("nat_irc: Not touching dir %s at hook %s\n",
		       dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
		       hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
		       : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
		       : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
		return NF_ACCEPT;
	}
	DEBUGP("got beyond not touching\n");

	datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
	LOCK_BH(&ip_irc_lock);
	/* Check wether the whole IP/address pattern is carried in the payload */
	if (between(exp->seq + ct_irc_info->len,
		    ntohl(tcph->seq),
		    ntohl(tcph->seq) + datalen)) {
		if (!irc_data_fixup(ct_irc_info, ct, pskb, ctinfo, exp)) {
			UNLOCK_BH(&ip_irc_lock);
			return NF_DROP;
		}
	} else { 
		/* Half a match?  This means a partial retransmisison.
		   It's a cracker being funky. */
		if (net_ratelimit()) {
			printk
			    ("IRC_NAT: partial packet %u/%u in %u/%u\n",
			     exp->seq, ct_irc_info->len,
			     ntohl(tcph->seq),
			     ntohl(tcph->seq) + datalen);
		}
		UNLOCK_BH(&ip_irc_lock);
		return NF_DROP;
	}
	UNLOCK_BH(&ip_irc_lock);

	return NF_ACCEPT;
}
Exemplo n.º 4
0
static int talk_help_response(struct ip_conntrack *ct,
			      struct ip_conntrack_expect *exp,
			      struct sk_buff **pskb,
		              u_char type,
		              u_char answer,
		              struct talk_addr *addr)
{
	u_int32_t newip;
	u_int16_t port;
	struct ip_conntrack_tuple t;
	struct ip_ct_talk_expect *ct_talk_info;

	DEBUGP("ip_nat_talk_help_response: addr: %u.%u.%u.%u:%u, type %d answer %d\n",
		NIPQUAD(addr->ta_addr), ntohs(addr->ta_port),
		type, answer);
	
	LOCK_BH(&ip_talk_lock);
	ct_talk_info = &exp->help.exp_talk_info;

	if (!(answer == SUCCESS 
	      && (type == LOOK_UP || type == ANNOUNCE)
	      && exp != NULL)) {
		UNLOCK_BH(&ip_talk_lock);
		return NF_ACCEPT;
	}
		
	DEBUGP("ip_nat_talk_help_response: talkinfo port %u (%s)\n", 
		ntohs(ct_talk_info->port), 
		type == LOOK_UP ? "LOOK_UP" : "ANNOUNCE");

	/* Change address inside packet to match way we're mapping
	   this connection. */
	newip = ct->tuplehash[type == LOOK_UP ? IP_CT_DIR_ORIGINAL : 
						IP_CT_DIR_REPLY].tuple.dst.ip;
	/* We can read expect here without conntrack lock, since it's
	   only set in ip_conntrack_talk , with ip_talk_lock held
	   writable */ 
	t = exp->tuple;
	t.dst.ip = newip;

	/* Try to get same port: if not, try to change it. */
	for (port = ntohs(ct_talk_info->port); port != 0; port++) {
		if (type == LOOK_UP)
			t.dst.u.tcp.port = htons(port);
		else
			t.dst.u.udp.port = htons(port);

		if (ip_conntrack_change_expect(exp, &t) == 0) {
			DEBUGP("ip_nat_talk_help_response: using %u.%u.%u.%u:%u\n", NIPQUAD(newip), port);
			break;
		}
	}
	UNLOCK_BH(&ip_talk_lock);

	if (port == 0 || !mangle_packet(pskb, ct, newip, htons(port), addr, NULL))
		return NF_DROP;
	
	return NF_ACCEPT;
}
Exemplo n.º 5
0
 static unsigned int
  ftp_nat_expected(struct sk_buff **pskb,
                 unsigned int hooknum,
                 struct ip_conntrack *ct,
                 struct ip_nat_info *info)
  {
        struct ip_nat_multi_range mr;
        u_int32_t newdstip, newsrcip, newip;
        struct ip_ct_ftp_expect *exp_ftp_info;

        struct ip_conntrack *master = master_ct(ct);

        IP_NF_ASSERT(info);
        IP_NF_ASSERT(master);

        IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum))));

        DEBUGP("nat_expected: We have a connection!\n");
        exp_ftp_info = &ct->master->help.exp_ftp_info;

        LOCK_BH(&ip_ftp_lock);

        if (exp_ftp_info->ftptype == IP_CT_FTP_PORT
            || exp_ftp_info->ftptype == IP_CT_FTP_EPRT) {

		/* PORT command: make connection go to the client. */
		newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
		newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
		DEBUGP("nat_expected: PORT cmd. %u.%u.%u.%u->%u.%u.%u.%u\n",
		       NIPQUAD(newsrcip), NIPQUAD(newdstip));
	} else {
		/* PASV command: make the connection go to the server */
		newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
		newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
		DEBUGP("nat_expected: PASV cmd. %u.%u.%u.%u->%u.%u.%u.%u\n",
		       NIPQUAD(newsrcip), NIPQUAD(newdstip));
	}
	UNLOCK_BH(&ip_ftp_lock);

	if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
		newip = newsrcip;
	else
		newip = newdstip;

	DEBUGP("nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip));

	mr.rangesize = 1;
	/* We don't want to manip the per-protocol, just the IPs... */
	mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
	mr.range[0].min_ip = mr.range[0].max_ip = newip;

	/* ... unless we're doing a MANIP_DST, in which case, make
	   sure we map to the correct port */
	if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
		mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
		mr.range[0].min = mr.range[0].max
			= ((union ip_conntrack_manip_proto)
				{ htons(exp_ftp_info->port) });
Exemplo n.º 6
0
/* timer function to flush queue in ULOG_FLUSH_INTERVAL time */
static void ulog_timer(unsigned long data)
{
	DEBUGP("ipt_ULOG: timer function called, calling ulog_send\n");

	/* lock to protect against somebody modifying our structure
	 * from ipt_ulog_target at the same time */
	LOCK_BH(&ulog_lock);
	ulog_send(data);
	UNLOCK_BH(&ulog_lock);
}
Exemplo n.º 7
0
static unsigned int
autofw_nat_expected(struct sk_buff **pskb,
		 unsigned int hooknum,
		 struct ip_conntrack *ct,
		 struct ip_nat_info *info)
{
	struct ip_nat_multi_range mr;
	u_int32_t newdstip, newsrcip, newip;
	u_int16_t port;
	struct ip_conntrack *master = master_ct(ct);

	IP_NF_ASSERT(info);
	IP_NF_ASSERT(master);

	IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum))));

	DEBUGP("autofw_nat_expected: got ");
	DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);

	LOCK_BH(&ip_autofw_lock);

	port = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.all);
	newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
#ifdef NEW_PORT_TRIG
	newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
#else
	newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
#endif

	if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
		newip = newsrcip;
	else {
		if (port < ntohs(ct->master->help.exp_autofw_info.dport[0]) ||
		    port > ntohs(ct->master->help.exp_autofw_info.dport[1])) {
			UNLOCK_BH(&ip_autofw_lock);
			return NF_DROP;
		}
		newip = newdstip;
	}

	mr.rangesize = 1;
	/* We don't want to manip the per-protocol, just the IPs... */
	mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
	mr.range[0].min_ip = mr.range[0].max_ip = newip;

	/* ... unless we're doing a MANIP_DST, in which case, make
	   sure we map to the correct port */
	port -= ntohs(ct->master->help.exp_autofw_info.dport[0]);
	port += ntohs(ct->master->help.exp_autofw_info.to[0]);
	if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
		mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
		mr.range[0].min = mr.range[0].max
			= ((union ip_conntrack_manip_proto)
				{ htons(port) });
Exemplo n.º 8
0
/* FIXME: This should be in userspace.  Later. */
static int help(struct sk_buff *skb,
		struct ip_conntrack *ct,
		enum ip_conntrack_info ctinfo)
{
	int dir = CTINFO2DIR(ctinfo);
	struct tcphdr tcph;
        struct ip_conntrack_expect exp;
	int i;

	/*
	** We only do this for the new packet 
        */
//	printk("wm_help: Conntrackinfo = %u dir=%d\n", ctinfo,dir);
	if ( ctinfo != IP_CT_NEW)
		return NF_ACCEPT;
	if ( dir != 0)
		return NF_ACCEPT;
        //DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
        //DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
	
	if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) != 0)
		return NF_ACCEPT;	

	LOCK_BH(&ip_wm_lock);
	//for(i = WMMIN; i <= WMMIN; i++) {
	for(i = WMMIN; i <= WMMAX; i++) {
            memset(&exp, 0, sizeof(exp));
            exp.tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
            exp.tuple.dst.u.udp.port = htons(i);
 	    exp.tuple.dst.protonum = IPPROTO_UDP;
            exp.mask.src.ip = 0xffffffff;
            exp.mask.dst.ip = 0xffffffff;
            exp.mask.dst.u.udp.port = 0xffff;
            exp.mask.dst.protonum = 0xffff;
            exp.expectfn = NULL;
            exp.seq = ntohl(tcph.seq);

            DEBUGP("wm_help: expect: ");
            DUMP_TUPLE(&exp.tuple);
            DUMP_TUPLE(&exp.mask);
            ip_conntrack_expect_related(&exp, ct);
	}
	UNLOCK_BH(&ip_wm_lock);
        return NF_ACCEPT;
}
Exemplo n.º 9
0
static unsigned int
talk_nat_expected(struct sk_buff **pskb,
		  unsigned int hooknum,
		  struct ip_conntrack *ct,
		  struct ip_nat_info *info)
{
	struct ip_nat_multi_range mr;
	u_int32_t newdstip, newsrcip, newip;
	u_int16_t port;
	unsigned int ret;
	
	struct ip_conntrack *master = master_ct(ct);

	IP_NF_ASSERT(info);
	IP_NF_ASSERT(master);

	IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum))));

	DEBUGP("ip_nat_talk_expected: We have a connection!\n");

	LOCK_BH(&ip_talk_lock);
	port = ct->master->help.exp_talk_info.port;
	UNLOCK_BH(&ip_talk_lock);

	DEBUGP("ip_nat_talk_expected: dir %s at hook %s, ct %p, master %p\n",
	       CTINFO2DIR((*pskb)->nfct - ct->infos) == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
	       hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
	       : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
	       : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???",
	       ct, master);

	if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == IPPROTO_UDP) {
		/* Callee client -> caller server */
#ifdef IP_NAT_TALK_DEBUG
		struct iphdr *iph = (*pskb)->nh.iph;
		struct udphdr *udph = (void *)iph + iph->ihl * 4;

		DEBUGP("ip_nat_talk_expected: UDP %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
		       NIPQUAD(iph->saddr), ntohs(udph->source),
		       NIPQUAD(iph->daddr), ntohs(udph->dest));
#endif
		newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
		newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
		DEBUGP("ip_nat_talk_expected: callee client -> caller server, newsrc: %u.%u.%u.%u, newdst: %u.%u.%u.%u\n",
		       NIPQUAD(newsrcip), NIPQUAD(newdstip));
	} else {
		/* Callee client -> caller client */
#ifdef IP_NAT_TALK_DEBUG
		struct iphdr *iph = (*pskb)->nh.iph;
		struct tcphdr *tcph = (void *)iph + iph->ihl * 4;

		DEBUGP("ip_nat_talk_expected: TCP %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
		       NIPQUAD(iph->saddr), ntohs(tcph->source),
		       NIPQUAD(iph->daddr), ntohs(tcph->dest));
#endif
		newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
		newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
		DEBUGP("ip_nat_talk_expected: callee client -> caller client, newsrc: %u.%u.%u.%u, newdst: %u.%u.%u.%u\n",
		       NIPQUAD(newsrcip), NIPQUAD(newdstip));
	}
	if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
		newip = newsrcip;
	else
		newip = newdstip;

	DEBUGP("ip_nat_talk_expected: IP to %u.%u.%u.%u, port %u\n", NIPQUAD(newip), ntohs(port));

	mr.rangesize = 1;
	/* We don't want to manip the per-protocol, just the IPs... */
	mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
	mr.range[0].min_ip = mr.range[0].max_ip = newip;
	
	/* ... unless we're doing a MANIP_DST, in which case, make
	   sure we map to the correct port */
	if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
		mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
		mr.range[0].min = mr.range[0].max
			= ((union ip_conntrack_manip_proto)
				{ .udp = { port } });
Exemplo n.º 10
0
/* FIXME: This should be in userspace.  Later. */
static int help(const struct iphdr *iph, size_t len,
		struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
{
	/* tcplen not negative guarenteed by ip_conntrack_tcp.c */
	struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
	const char *data = (const char *) tcph + tcph->doff * 4;
	const char *_data = data;
	char *data_limit;
	u_int32_t tcplen = len - iph->ihl * 4;
	u_int32_t datalen = tcplen - tcph->doff * 4;
	int dir = CTINFO2DIR(ctinfo);
	struct ip_conntrack_expect expect, *exp = &expect;
	struct ip_ct_irc_expect *exp_irc_info = &exp->help.exp_irc_info;

	u_int32_t dcc_ip;
	u_int16_t dcc_port;
	int i;
	char *addr_beg_p, *addr_end_p;

	DEBUGP("entered\n");

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

	/* Until there's been traffic both ways, don't look in packets. */
	if (ctinfo != IP_CT_ESTABLISHED
	    && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
		DEBUGP("Conntrackinfo = %u\n", ctinfo);
		return NF_ACCEPT;
	}

	/* Not whole TCP header? */
	if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
		DEBUGP("tcplen = %u\n", (unsigned) tcplen);
		return NF_ACCEPT;
	}

	/* Checksum invalid?  Ignore. */
	/* FIXME: Source route IP option packets --RR */
	if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
			 csum_partial((char *) tcph, tcplen, 0))) {
		DEBUGP("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
		     tcph, tcplen, NIPQUAD(iph->saddr),
		     NIPQUAD(iph->daddr));
		return NF_ACCEPT;
	}

	data_limit = (char *) data + datalen;

	/* strlen("\1DCC SEND t AAAAAAAA P\1\n")=24
	 *         5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */
	while (data < (data_limit - (19 + MINMATCHLEN))) {
		if (memcmp(data, "\1DCC ", 5)) {
			data++;
			continue;
		}

		data += 5;
		/* we have at least (19+MINMATCHLEN)-5 bytes valid data left */

		DEBUGP("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u...\n",
			NIPQUAD(iph->saddr), ntohs(tcph->source),
			NIPQUAD(iph->daddr), ntohs(tcph->dest));

		for (i = 0; i < NUM_DCCPROTO; i++) {
			if (memcmp(data, dccprotos[i].match,
				   dccprotos[i].matchlen)) {
				/* no match */
				continue;
			}

			DEBUGP("DCC %s detected\n", dccprotos[i].match);
			data += dccprotos[i].matchlen;
			/* we have at least
			 * (19+MINMATCHLEN)-5-dccprotos[i].matchlen bytes valid
			 * data left (== 14/13 bytes) */
			if (parse_dcc((char *) data, data_limit, &dcc_ip,
				       &dcc_port, &addr_beg_p, &addr_end_p)) {
				/* unable to parse */
				DEBUGP("unable to parse dcc command\n");
				continue;
			}
			DEBUGP("DCC bound ip/port: %u.%u.%u.%u:%u\n",
				HIPQUAD(dcc_ip), dcc_port);

			if (ct->tuplehash[dir].tuple.src.ip != htonl(dcc_ip)) {
				if (net_ratelimit())
					printk(KERN_WARNING
						"Forged DCC command from "
						"%u.%u.%u.%u: %u.%u.%u.%u:%u\n",
				NIPQUAD(ct->tuplehash[dir].tuple.src.ip),
						HIPQUAD(dcc_ip), dcc_port);

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

			LOCK_BH(&ip_irc_lock);

			/* save position of address in dcc string,
			 * neccessary for NAT */
			DEBUGP("tcph->seq = %u\n", tcph->seq);
			exp->seq = ntohl(tcph->seq) + (addr_beg_p - _data);
			exp_irc_info->len = (addr_end_p - addr_beg_p);
			exp_irc_info->port = dcc_port;
			DEBUGP("wrote info seq=%u (ofs=%u), len=%d\n",
				exp->seq, (addr_end_p - _data), exp_irc_info->len);

			exp->tuple = ((struct ip_conntrack_tuple)
				{ { 0, { 0 } },
				  { htonl(dcc_ip), { .tcp = { htons(dcc_port) } },
				    IPPROTO_TCP }});
Exemplo n.º 11
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;
}
Exemplo n.º 12
0
static void ipt_ulog_packet(unsigned int hooknum,
			    const struct sk_buff *skb,
			    const struct net_device *in,
			    const struct net_device *out,
			    const struct ipt_ulog_info *loginfo,
			    const char *prefix)
{
	ulog_buff_t *ub;
	ulog_packet_msg_t *pm;
	size_t size, copy_len;
	struct nlmsghdr *nlh;

	/* ffs == find first bit set, necessary because userspace
	 * is already shifting groupnumber, but we need unshifted.
	 * ffs() returns [1..32], we need [0..31] */
	unsigned int groupnum = ffs(loginfo->nl_group) - 1;

	/* calculate the size of the skb needed */
	if ((loginfo->copy_range == 0) ||
	    (loginfo->copy_range > skb->len)) {
		copy_len = skb->len;
	} else {
		copy_len = loginfo->copy_range;
	}

	size = NLMSG_SPACE(sizeof(*pm) + copy_len);

	ub = &ulog_buffers[groupnum];
	
	LOCK_BH(&ulog_lock);

	if (!ub->skb) {
		if (!(ub->skb = ulog_alloc_skb(size)))
			goto alloc_failure;
	} else if (ub->qlen >= loginfo->qthreshold ||
		   size > skb_tailroom(ub->skb)) {
		/* either the queue len is too high or we don't have 
		 * enough room in nlskb left. send it to userspace. */

		ulog_send(groupnum);

		if (!(ub->skb = ulog_alloc_skb(size)))
			goto alloc_failure;
	}

	DEBUGP("ipt_ULOG: qlen %d, qthreshold %d\n", ub->qlen, 
		loginfo->qthreshold);

	/* NLMSG_PUT contains a hidden goto nlmsg_failure !!! */
	nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, ULOG_NL_EVENT, 
			sizeof(*pm)+copy_len);
	ub->qlen++;

	pm = NLMSG_DATA(nlh);

	/* We might not have a timestamp, get one */
	if (skb->stamp.tv_sec == 0)
		do_gettimeofday((struct timeval *)&skb->stamp);

	/* copy hook, prefix, timestamp, payload, etc. */
	pm->data_len = copy_len;
	pm->timestamp_sec = skb->stamp.tv_sec;
	pm->timestamp_usec = skb->stamp.tv_usec;
	pm->mark = skb->nfmark;
	pm->hook = hooknum;
	if (prefix != NULL)
		strncpy(pm->prefix, prefix, sizeof(pm->prefix));
	else if (loginfo->prefix[0] != '\0')
		strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix));
	else
		*(pm->prefix) = '\0';

	if (in && in->hard_header_len > 0
	    && skb->mac.raw != (void *) skb->nh.iph
	    && in->hard_header_len <= ULOG_MAC_LEN) {
		memcpy(pm->mac, skb->mac.raw, in->hard_header_len);
		pm->mac_len = in->hard_header_len;
	} else
		pm->mac_len = 0;

	if (in)
		strncpy(pm->indev_name, in->name, sizeof(pm->indev_name));
	else
		pm->indev_name[0] = '\0';

	if (out)
		strncpy(pm->outdev_name, out->name, sizeof(pm->outdev_name));
	else
		pm->outdev_name[0] = '\0';

	/* copy_len <= skb->len, so can't fail. */
	if (skb_copy_bits(skb, 0, pm->payload, copy_len) < 0)
		BUG();
	
	/* check if we are building multi-part messages */
	if (ub->qlen > 1) {
		ub->lastnlh->nlmsg_flags |= NLM_F_MULTI;
	}

	ub->lastnlh = nlh;

	/* if timer isn't already running, start it */
	if (!timer_pending(&ub->timer)) {
		ub->timer.expires = jiffies + flushtimeout * HZ / 100;
		add_timer(&ub->timer);
	}

	/* if threshold is reached, send message to userspace */
	if (ub->qlen >= loginfo->qthreshold) {
		if (loginfo->qthreshold > 1)
			nlh->nlmsg_type = NLMSG_DONE;
		ulog_send(groupnum);
	}

	UNLOCK_BH(&ulog_lock);

	return;

nlmsg_failure:
	PRINTR("ipt_ULOG: error during NLMSG_PUT\n");

alloc_failure:
	PRINTR("ipt_ULOG: Error building netlink message\n");

	UNLOCK_BH(&ulog_lock);
}
Exemplo n.º 13
0
/* FIXME: This should be in userspace.  Later. */
static int help(struct sk_buff **pskb,
		struct ip_conntrack *ct,
		enum ip_conntrack_info ctinfo)
{
	int ret = NF_DROP;
	struct tcphdr _tcph, *th;
	char *data, *mb_ptr;
	unsigned int datalen, dataoff;


	//struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
	//unsigned int tcplen = len - iph->ihl * 4;
	//unsigned int datalen = tcplen - tcph->doff * 4;
	int dir = CTINFO2DIR(ctinfo);
	struct ip_conntrack_expect *exp;
	struct ip_ct_mms_expect _emmi, *exp_mms_info = &_emmi;
	
	u_int32_t mms_ip;
	u_int16_t mms_proto;
	char mms_proto_string[8];
	u_int16_t mms_port;
	char *mms_string_b, *mms_string_e, *mms_padding_e;
	     
	/* Until there's been traffic both ways, don't look in packets. */
	if (ctinfo != IP_CT_ESTABLISHED
	    && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
		DEBUGP("ip_conntrack_mms: Conntrackinfo = %u\n", ctinfo);
		return NF_ACCEPT;
	}

	/* Not whole TCP header? */
	th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4,
				sizeof(_tcph), &_tcph);
	if (!th)
		return NF_ACCEPT;

	/* No data ? */
	dataoff = (*pskb)->nh.iph->ihl*4 + th->doff*4;
	datalen = (*pskb)->len - dataoff;
	if (dataoff >= (*pskb)->len)
		return NF_ACCEPT;

	LOCK_BH(&mms_buffer_lock);
	mb_ptr = skb_header_pointer(*pskb, dataoff,
				    (*pskb)->len - dataoff, mms_buffer);
	BUG_ON(mb_ptr == NULL);

	data = mb_ptr;

#if 0
	/* Checksum invalid?  Ignore. */
	/* FIXME: Source route IP option packets --RR */
	if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
	    csum_partial((char *)tcph, tcplen, 0))) {
		DEBUGP("mms_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
		       tcph, tcplen, NIPQUAD(iph->saddr),
		       NIPQUAD(iph->daddr));
		return NF_ACCEPT;
	}
#endif
	
	/* Only look at packets with 0x00030002/196610 on bytes 36->39 of TCP
	 * payload */

	/* FIXME: There is an issue with only looking at this packet: before
	 * this packet, the client has already sent a packet to the server with
	 * the server's hostname according to the client (think of it as the
	 * "Host: " header in HTTP/1.1). The server will break the connection
	 * if this doesn't correspond to its own host header. The client can
	 * also connect to an IP address; if it's the server's IP address, it
	 * will not break the connection. When doing DNAT on a connection where
	 * the client uses a server's IP address, the nat module should detect
	 * this and change this string accordingly to the DNATed address. This
	 * should probably be done by checking for an IP address, then storing
	 * it as a member of struct ip_ct_mms_expect and checking for it in
	 * ip_nat_mms...
	 */
	if ((MMS_SRV_MSG_OFFSET < datalen) && 
	    ((*(u32 *)(data+MMS_SRV_MSG_OFFSET)) == MMS_SRV_MSG_ID)) {
		DEBUGP("ip_conntrack_mms: offset 37: %u %u %u %u, datalen:%u\n", 
		       (u8)*(data+36), (u8)*(data+37), 
		       (u8)*(data+38), (u8)*(data+39),
		       datalen);
		if (parse_mms(data, datalen, &mms_ip, &mms_proto, &mms_port,
		             &mms_string_b, &mms_string_e, &mms_padding_e))
			if (net_ratelimit())
				/* FIXME: more verbose debugging ? */
				printk(KERN_WARNING
				       "ip_conntrack_mms: Unable to parse "
				       "data payload\n");

		sprintf(mms_proto_string, "(%u)", mms_proto);
		DEBUGP("ip_conntrack_mms: adding %s expectation "
		       "%u.%u.%u.%u -> %u.%u.%u.%u:%u\n",
		       mms_proto == IPPROTO_TCP ? "TCP"
		       : mms_proto == IPPROTO_UDP ? "UDP":mms_proto_string,
		       NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
		       NIPQUAD(mms_ip),
		       mms_port);
		
		/* it's possible that the client will just ask the server to
		 * tunnel the stream over the same TCP session (from port
		 * 1755): there's shouldn't be a need to add an expectation in
		 * that case, but it makes NAT packet mangling so much easier
		 * */

		DEBUGP("ip_conntrack_mms: tcph->seq = %u\n", tcph->seq);

		exp = ip_conntrack_expect_alloc();
		if (!exp) {
			ret = NF_DROP;
			goto out;
		}
		
		exp_mms_info->offset  = (mms_string_b - data);
		exp_mms_info->len     = (mms_string_e  - mms_string_b);
		exp_mms_info->padding = (mms_padding_e - mms_string_e);
		exp_mms_info->port    = mms_port;
		
		DEBUGP("ip_conntrack_mms: wrote info seq=%u (ofs=%u), "
		       "len=%d, padding=%u\n", exp->seq, (mms_string_e - data),
		       exp_mms_info->len, exp_mms_info->padding);
		
		exp->tuple = ((struct ip_conntrack_tuple)
		              { { ct->tuplehash[!dir].tuple.src.ip, { 0 } },
		              { mms_ip,
Exemplo n.º 14
0
static unsigned int help(struct ip_conntrack *ct,
         		 struct ip_conntrack_expect *exp,
			 struct ip_nat_info *info,
			 enum ip_conntrack_info ctinfo,
			 unsigned int hooknum,
			 struct sk_buff **pskb)
{
	struct iphdr *iph = (*pskb)->nh.iph;
	struct tcphdr *tcph = (void *)iph + iph->ihl*4;
	unsigned int datalen;
	int dir;
	int score;
	struct ip_ct_sc_expect *exp_sc_info = &exp->help.exp_sc_info;

	/* Only mangle things once: original direction in POST_ROUTING
	   and reply direction on PRE_ROUTING. */
	dir = CTINFO2DIR(ctinfo);
	DEBUGP("nat_sc: help()\n");
	
#if 0
	if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_REPLY)
	      || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_ORIGINAL))) {
#if 1
		DEBUGP("nat_sc: Not touching dir %s at hook %s\n",
		       dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
		       hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
		       : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
		       : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
#endif
		return NF_ACCEPT;
	}
#endif

	datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
	score = 0;
	LOCK_BH(&ip_sc_lock);
	
	if (exp_sc_info->len) {
		/* If it's in the right range... */
		score += between(exp_sc_info->seq, ntohl(tcph->seq),
				 ntohl(tcph->seq) + datalen);
		score += between(exp_sc_info->seq + exp_sc_info->len,
				 ntohl(tcph->seq),
				 ntohl(tcph->seq) + datalen);
		if (score == 1) {
			/* Half a match?  This means a partial retransmisison.
			   It's a cracker being funky. */
			if (net_ratelimit()) {
				printk("SC_NAT: partial packet %u/%u in %u/%u\n",
				       exp_sc_info->seq, exp_sc_info->len,
				       ntohl(tcph->seq),
				       ntohl(tcph->seq) + datalen);
			}
			UNLOCK_BH(&ip_sc_lock);
			return NF_DROP;
		} else if (score == 2) {
			if (!sc_data_fixup(exp_sc_info, ct, datalen, pskb, ctinfo)) {
				UNLOCK_BH(&ip_sc_lock);
				return NF_DROP;
			}
			/* skb may have been reallocated */
			iph = (*pskb)->nh.iph;
			tcph = (void *)iph + iph->ihl*4;
		}
	}

	UNLOCK_BH(&ip_sc_lock);
	
	DEBUGP("nat_sc: ip_nat_seq_adjust()\n");
	ip_nat_seq_adjust(*pskb, ct, ctinfo);

	return NF_ACCEPT;
}
Exemplo n.º 15
0
/* FIXME: This should be in userspace.  Later. */
static int h245_help(const struct iphdr *iph, size_t len,
		     struct ip_conntrack *ct,
		     enum ip_conntrack_info ctinfo)
{
	struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
	unsigned char *data = (unsigned char *) tcph + tcph->doff * 4;
	unsigned char *data_limit;
	u_int32_t tcplen = len - iph->ihl * 4;
	u_int32_t datalen = tcplen - tcph->doff * 4;
	int dir = CTINFO2DIR(ctinfo);
	struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
	struct ip_conntrack_expect expect, *exp = &expect;
	struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info;
	u_int16_t data_port;
	u_int32_t data_ip;
	unsigned int i;

	DEBUGP("ct_h245_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
		NIPQUAD(iph->saddr), ntohs(tcph->source),
		NIPQUAD(iph->daddr), ntohs(tcph->dest));

#ifdef CONFIG_IFX_ALG_QOS //Suresh
        ct->ifx_alg_qos_mark = IFX_ALG_APP_H323;
        DEBUGP ("\nH323_ALG h245_help marked ct->ifx_alg_qos_mark to : %x ***\n",
                                ct->ifx_alg_qos_mark );
#endif

	/* Can't track connections formed before we registered */
	if (!info)
		return NF_ACCEPT;
		
	/* Until there's been traffic both ways, don't look in packets. */
	if (ctinfo != IP_CT_ESTABLISHED
	    && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
		DEBUGP("ct_h245_help: Conntrackinfo = %u\n", ctinfo);
		return NF_ACCEPT;
	}

	/* Not whole TCP header or too short packet? */
	if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) {
		DEBUGP("ct_h245_help: tcplen = %u\n", (unsigned)tcplen);
		return NF_ACCEPT;
	}

	/* Checksum invalid?  Ignore. */
	/* FIXME: Source route IP option packets --RR */
	if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
			      csum_partial((char *)tcph, tcplen, 0))) {
		DEBUGP("ct_h245_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
		       tcph, tcplen, NIPQUAD(iph->saddr),
		       NIPQUAD(iph->daddr));
		return NF_ACCEPT;
	}

	data_limit = (unsigned char *) data + datalen;
	/* bytes: 0123   45
	          ipadrr port */
	for (i = 0; data < (data_limit - 5); data++, i++) {
		data_ip = *((u_int32_t *)data);
		if (data_ip == iph->saddr) {
			data_port = *((u_int16_t *)(data + 4));
			memset(&expect, 0, sizeof(expect));
			/* update the H.225 info */
			DEBUGP("ct_h245_help: new RTCP/RTP requested %u.%u.%u.%u:->%u.%u.%u.%u:%u\n",
				NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
				NIPQUAD(iph->saddr), ntohs(data_port));
			LOCK_BH(&ip_h323_lock);
			info->is_h225 = H225_PORT + 1;
			exp_info->port = data_port;
			exp_info->dir = dir;
			exp_info->offset = i;

			exp->seq = ntohl(tcph->seq) + i;
		    
			exp->tuple = ((struct ip_conntrack_tuple)
				{ { ct->tuplehash[!dir].tuple.src.ip,
				    { 0 } },
				  { data_ip,
				    { .udp = { .port = data_port } },
				    IPPROTO_UDP }});
Exemplo n.º 16
0
/* FIXME: This should be in userspace.  Later. */
static int help(const struct iphdr *iph, size_t len,
                struct ip_conntrack *ct,
                enum ip_conntrack_info ctinfo)
{
    /* tcplen not negative guaranteed by ip_conntrack_tcp.c */
    struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
    const char *data = (const char *)tcph + tcph->doff * 4;
    unsigned int tcplen = len - iph->ihl * 4;
    unsigned int datalen = tcplen - tcph->doff * 4;
    int dir = CTINFO2DIR(ctinfo);
    struct ip_conntrack_expect expect, *exp = &expect;
    struct ip_ct_mms_expect *exp_mms_info = &exp->help.exp_mms_info;

    u_int32_t mms_ip;
    u_int16_t mms_proto;
    char mms_proto_string[8];
    u_int16_t mms_port;
    char *mms_string_b, *mms_string_e, *mms_padding_e;

    /* Until there's been traffic both ways, don't look in packets. */
    if (ctinfo != IP_CT_ESTABLISHED
            && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
        DEBUGP("ip_conntrack_mms: Conntrackinfo = %u\n", ctinfo);
        return NF_ACCEPT;
    }

    /* Not whole TCP header? */
    if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff*4) {
        DEBUGP("ip_conntrack_mms: tcplen = %u\n", (unsigned)tcplen);
        return NF_ACCEPT;
    }

    /* Checksum invalid?  Ignore. */
    /* FIXME: Source route IP option packets --RR */
    if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
                     csum_partial((char *)tcph, tcplen, 0))) {
        DEBUGP("mms_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
               tcph, tcplen, NIPQUAD(iph->saddr),
               NIPQUAD(iph->daddr));
        return NF_ACCEPT;
    }

    /* Only look at packets with 0x00030002/196610 on bytes 36->39 of TCP payload */
    /* FIXME: There is an issue with only looking at this packet: before this packet,
       the client has already sent a packet to the server with the server's hostname
       according to the client (think of it as the "Host: " header in HTTP/1.1). The
       server will break the connection if this doesn't correspond to its own host
       header. The client can also connect to an IP address; if it's the server's IP
       address, it will not break the connection. When doing DNAT on a connection
       where the client uses a server's IP address, the nat module should detect
       this and change this string accordingly to the DNATed address. This should
       probably be done by checking for an IP address, then storing it as a member
       of struct ip_ct_mms_expect and checking for it in ip_nat_mms...
       */
    if( (MMS_SRV_MSG_OFFSET < datalen) &&
            ((*(u32 *)(data+MMS_SRV_MSG_OFFSET)) == MMS_SRV_MSG_ID)) {
        DEBUGP("ip_conntrack_mms: offset 37: %u %u %u %u, datalen:%u\n",
               (u8)*(data+36), (u8)*(data+37),
               (u8)*(data+38), (u8)*(data+39),
               datalen);
        if(parse_mms(data, datalen, &mms_ip, &mms_proto, &mms_port,
                     &mms_string_b, &mms_string_e, &mms_padding_e))
            if(net_ratelimit())
                /* FIXME: more verbose debugging ? */
                printk(KERN_WARNING
                       "ip_conntrack_mms: Unable to parse data payload\n");

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

        sprintf(mms_proto_string, "(%u)", mms_proto);
        DEBUGP("ip_conntrack_mms: adding %s expectation %u.%u.%u.%u -> %u.%u.%u.%u:%u\n",
               mms_proto == IPPROTO_TCP ? "TCP"
               : mms_proto == IPPROTO_UDP ? "UDP":mms_proto_string,
               NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
               NIPQUAD(mms_ip),
               mms_port);

        /* it's possible that the client will just ask the server to tunnel
           the stream over the same TCP session (from port 1755): there's
           shouldn't be a need to add an expectation in that case, but it
           makes NAT packet mangling so much easier */
        LOCK_BH(&ip_mms_lock);

        DEBUGP("ip_conntrack_mms: tcph->seq = %u\n", tcph->seq);

        exp->seq = ntohl(tcph->seq) + (mms_string_b - data);
        exp_mms_info->len     = (mms_string_e  - mms_string_b);
        exp_mms_info->padding = (mms_padding_e - mms_string_e);
        exp_mms_info->port    = mms_port;

        DEBUGP("ip_conntrack_mms: wrote info seq=%u (ofs=%u), len=%d, padding=%u\n",
               exp->seq, (mms_string_e - data), exp_mms_info->len, exp_mms_info->padding);

        exp->tuple = ((struct ip_conntrack_tuple)
        { {
                ct->tuplehash[!dir].tuple.src.ip, { 0 }
            },
            {   mms_ip,
static int help(struct sk_buff *skb,
                struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
{
	struct ip_conntrack_expect *exp;
	struct ip_ct_amanda_expect *exp_amanda_info;
	char *data, *data_limit, *tmp;
	unsigned int dataoff, i;
	u_int16_t port, len;

	/* 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, master_timeout * HZ);

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

	LOCK_BH(&amanda_buffer_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;
	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();
		if (exp == NULL)
			goto out;

		exp->tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
		exp->tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
		exp->tuple.dst.protonum = IPPROTO_TCP;
		exp->mask.src.ip = 0xFFFFFFFF;
		exp->mask.dst.ip = 0xFFFFFFFF;
		exp->mask.dst.protonum = 0xFFFF;
		exp->mask.dst.u.tcp.port = 0xFFFF;

		exp_amanda_info = &exp->help.exp_amanda_info;
		exp_amanda_info->offset = data - amanda_buffer;
		exp_amanda_info->port   = port;
		exp_amanda_info->len    = len;

		exp->tuple.dst.u.tcp.port = htons(port);

		ip_conntrack_expect_related(exp, ct);
	}

out:
	UNLOCK_BH(&amanda_buffer_lock);
	return NF_ACCEPT;
}
Exemplo n.º 18
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 }});
Exemplo n.º 19
0
/* track caller id inside control connection, call expect_related */
static int 
conntrack_pptp_help(const struct iphdr *iph, size_t len,
		    struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)

{
	struct pptp_pkt_hdr *pptph;
	
	struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
	u_int32_t tcplen = len - iph->ihl * 4;
	u_int32_t datalen = tcplen - tcph->doff * 4;
	void *datalimit;
	int dir = CTINFO2DIR(ctinfo);
	struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;

	int oldsstate, oldcstate;
	int ret;

	#ifdef CONFIG_IFX_ALG_QOS  //  chandrav
		/*
		 * Mark the connection tracket with PPTP ALG Family type
		 * ( IFX_ALG_APP_PPTP) for PPTP traffic.
		 */
		ct->ifx_alg_qos_mark = IFX_ALG_APP_PPTP;
		IFX_ALG_QOS_DBG("\nPPTP_ALG helper marked ct->ifx_alg_qos_mark to : %x ***\n",ct->ifx_alg_qos_mark );
	#endif  /* CONFIG_IFX_ALG_QOS */

	/* don't do any tracking before tcp handshake complete */
	if (ctinfo != IP_CT_ESTABLISHED 
	    && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
		DEBUGP("ctinfo = %u, skipping\n", ctinfo);
		return NF_ACCEPT;
	}
	
	/* not a complete TCP header? */
	if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
		DEBUGP("tcplen = %u\n", tcplen);
		return NF_ACCEPT;
	}

	/* checksum invalid? */
	if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
			csum_partial((char *) tcph, tcplen, 0))) {
	DEBUGP("TC Test0\n");
		printk(KERN_NOTICE __FILE__ ": bad csum\n");
		/* W2K PPTP server sends TCP packets with wrong checksum :(( */
		//return NF_ACCEPT;
	}

	DEBUGP("TC Test1\n");
	if (tcph->fin || tcph->rst) {
		DEBUGP("RST/FIN received, timeouting GRE\n");
		/* can't do this after real newnat */
		info->cstate = PPTP_CALL_NONE;

		/* untrack this call id, unexpect GRE packets */
		pptp_timeout_related(ct);
	}


	DEBUGP("TC Test2\n");
	pptph = (struct pptp_pkt_hdr *) ((void *) tcph + tcph->doff * 4);
	datalimit = (void *) pptph + datalen;

	/* not a full pptp packet header? */
	if ((void *) pptph+sizeof(*pptph) >= datalimit) {
		DEBUGP("no full PPTP header, can't track\n");
		return NF_ACCEPT;
	}
	
	/* if it's not a control message we can't do anything with it */
        if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
	    ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
		DEBUGP("not a control packet\n");
		return NF_ACCEPT;
	}

	DEBUGP("TC Test3\n");
	oldsstate = info->sstate;
	oldcstate = info->cstate;

	LOCK_BH(&ip_pptp_lock);

	/* FIXME: We just blindly assume that the control connection is always
	 * established from PNS->PAC.  However, RFC makes no guarantee */
	if (dir == IP_CT_DIR_ORIGINAL)
		/* client -> server (PNS -> PAC) */
		ret = pptp_outbound_pkt(tcph, pptph, datalen, ct, ctinfo);
	else
		/* server -> client (PAC -> PNS) */
		ret = pptp_inbound_pkt(tcph, pptph, datalen, ct, ctinfo);
	DEBUGP("sstate: %d->%d, cstate: %d->%d\n",
		oldsstate, info->sstate, oldcstate, info->cstate);
	UNLOCK_BH(&ip_pptp_lock);

	return ret;
}
Exemplo n.º 20
0
static int help(struct sk_buff *skb,
		struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
{
	unsigned int dataoff;
	struct tcphdr tcph;
	char *data, *data_limit;
	int dir = CTINFO2DIR(ctinfo);
	struct ip_conntrack_expect *exp;
	struct ip_ct_irc_expect *exp_irc_info = NULL;

	u_int32_t dcc_ip;
	u_int16_t dcc_port;
	int i;
	char *addr_beg_p, *addr_end_p;

	DEBUGP("entered\n");

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

	/* Until there's been traffic both ways, don't look in packets. */
	if (ctinfo != IP_CT_ESTABLISHED
	    && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
		DEBUGP("Conntrackinfo = %u\n", ctinfo);
		return NF_ACCEPT;
	}

	/* Not a full tcp header? */
	if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) != 0)
		return NF_ACCEPT;

	/* No data? */
	dataoff = skb->nh.iph->ihl*4 + tcph.doff*4;
	if (dataoff >= skb->len)
		return NF_ACCEPT;

	LOCK_BH(&ip_irc_lock);
	skb_copy_bits(skb, dataoff, irc_buffer, skb->len - dataoff);

	data = irc_buffer;
	data_limit = irc_buffer + skb->len - dataoff;

	/* strlen("\1DCC SENT t AAAAAAAA P\1\n")=24
	 * 5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */
	while (data < (data_limit - (19 + MINMATCHLEN))) {
		if (memcmp(data, "\1DCC ", 5)) {
			data++;
			continue;
		}

		data += 5;
		/* we have at least (19+MINMATCHLEN)-5 bytes valid data left */

		DEBUGP("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u...\n",
			NIPQUAD(iph->saddr), ntohs(tcph.source),
			NIPQUAD(iph->daddr), ntohs(tcph.dest));

		for (i = 0; i < ARRAY_SIZE(dccprotos); i++) {
			if (memcmp(data, dccprotos[i], strlen(dccprotos[i]))) {
				/* no match */
				continue;
			}

			DEBUGP("DCC %s detected\n", dccprotos[i]);
			data += strlen(dccprotos[i]);
			/* we have at least 
			 * (19+MINMATCHLEN)-5-dccprotos[i].matchlen bytes valid
			 * data left (== 14/13 bytes) */
			if (parse_dcc((char *)data, data_limit, &dcc_ip,
				       &dcc_port, &addr_beg_p, &addr_end_p)) {
				/* unable to parse */
				DEBUGP("unable to parse dcc command\n");
				continue;
			}
			DEBUGP("DCC bound ip/port: %u.%u.%u.%u:%u\n",
				HIPQUAD(dcc_ip), dcc_port);

			/* dcc_ip can be the internal OR external (NAT'ed) IP
			 * Tiago Sousa <*****@*****.**> */
			if (ct->tuplehash[dir].tuple.src.ip != htonl(dcc_ip)
			    && ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip != htonl(dcc_ip)) {
				if (net_ratelimit())
					printk(KERN_WARNING
						"Forged DCC command from "
						"%u.%u.%u.%u: %u.%u.%u.%u:%u\n",
				NIPQUAD(ct->tuplehash[dir].tuple.src.ip),
						HIPQUAD(dcc_ip), dcc_port);

				continue;
			}

			exp = ip_conntrack_expect_alloc();
			if (exp == NULL)
				goto out;

			exp_irc_info = &exp->help.exp_irc_info;

			/* save position of address in dcc string,
			 * necessary for NAT */
			DEBUGP("tcph->seq = %u\n", tcph.seq);
			exp->seq = ntohl(tcph.seq) + (addr_beg_p - irc_buffer);
			exp_irc_info->len = (addr_end_p - addr_beg_p);
			exp_irc_info->port = dcc_port;
			DEBUGP("wrote info seq=%u (ofs=%u), len=%d\n",
				exp->seq, (addr_end_p - _data), exp_irc_info->len);

			exp->tuple = ((struct ip_conntrack_tuple)
				{ { 0, { 0 } },
				  { ct->tuplehash[dir].tuple.src.ip, { .tcp = { htons(dcc_port) } },
				    IPPROTO_TCP }});
Exemplo n.º 21
0
static unsigned int ipt_ulog_target(struct sk_buff **pskb,
				    unsigned int hooknum,
				    const struct net_device *in,
				    const struct net_device *out,
				    const void *targinfo, void *userinfo)
{
	ulog_buff_t *ub;
	ulog_packet_msg_t *pm;
	size_t size, copy_len;
	struct nlmsghdr *nlh;
	struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;

	/* calculate the size of the skb needed */
	if ((loginfo->copy_range == 0) ||
	    (loginfo->copy_range > (*pskb)->len)) {
		copy_len = (*pskb)->len;
	} else {
		copy_len = loginfo->copy_range;
	}

	size = NLMSG_SPACE(sizeof(*pm) + copy_len);

	ub = &ulog_buffers[loginfo->nl_group];
	
	LOCK_BH(&ulog_lock);

	if (!ub->skb) {
		if (!(ub->skb = ulog_alloc_skb(size)))
			goto alloc_failure;
	} else if (ub->qlen >= loginfo->qthreshold ||
		   size > skb_tailroom(ub->skb)) {
		/* either the queue len is too high or we don't have 
		 * enough room in nlskb left. send it to userspace. */

		ulog_send(loginfo->nl_group);

		if (!(ub->skb = ulog_alloc_skb(size)))
			goto alloc_failure;
	}

	DEBUGP("ipt_ULOG: qlen %d, qthreshold %d\n", ub->qlen, 
		loginfo->qthreshold);

	/* NLMSG_PUT contains a hidden goto nlmsg_failure !!! */
	nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, ULOG_NL_EVENT, 
			size - sizeof(*nlh));
	ub->qlen++;

	pm = NLMSG_DATA(nlh);

	/* copy hook, prefix, timestamp, payload, etc. */
	pm->data_len = copy_len;
	pm->timestamp_sec = (*pskb)->stamp.tv_sec;
	pm->timestamp_usec = (*pskb)->stamp.tv_usec;
	pm->mark = (*pskb)->nfmark;
	pm->hook = hooknum;
	if (loginfo->prefix[0] != '\0')
		strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix));
	else
		*(pm->prefix) = '\0';

	if (in && in->hard_header_len > 0
	    && (*pskb)->mac.raw != (void *) (*pskb)->nh.iph
	    && in->hard_header_len <= ULOG_MAC_LEN) {
		memcpy(pm->mac, (*pskb)->mac.raw, in->hard_header_len);
		pm->mac_len = in->hard_header_len;
	}

	if (in)
		strncpy(pm->indev_name, in->name, sizeof(pm->indev_name));
	else
		pm->indev_name[0] = '\0';

	if (out)
		strncpy(pm->outdev_name, out->name, sizeof(pm->outdev_name));
	else
		pm->outdev_name[0] = '\0';

	if (copy_len)
		memcpy(pm->payload, (*pskb)->data, copy_len);
	
	/* check if we are building multi-part messages */
	if (ub->qlen > 1) {
		ub->lastnlh->nlmsg_flags |= NLM_F_MULTI;
	}

	/* if threshold is reached, send message to userspace */
	if (qlen >= loginfo->qthreshold) {
		if (loginfo->qthreshold > 1)
			nlh->nlmsg_type = NLMSG_DONE;
	}

	ub->lastnlh = nlh;

	/* if timer isn't already running, start it */
	if (!timer_pending(&ub->timer)) {
		ub->timer.expires = jiffies + flushtimeout;
		add_timer(&ub->timer);
	}

	UNLOCK_BH(&ulog_lock);

	return IPT_CONTINUE;


nlmsg_failure:
	PRINTR("ipt_ULOG: error during NLMSG_PUT\n");

alloc_failure:
	PRINTR("ipt_ULOG: Error building netlink message\n");

	UNLOCK_BH(&ulog_lock);

	return IPT_CONTINUE;
}
Exemplo n.º 22
0
static unsigned int
h225_nat_expected(struct sk_buff **pskb,
		  unsigned int hooknum,
		  struct ip_conntrack *ct,
		  struct ip_nat_info *info)
{
	struct ip_nat_multi_range mr;
	u_int32_t newdstip, newsrcip, newip;
	u_int16_t port;
	struct ip_ct_h225_expect *exp_info;
	struct ip_ct_h225_master *master_info;
	struct ip_conntrack *master = master_ct(ct);
	unsigned int is_h225, ret;
	
	IP_NF_ASSERT(info);
	IP_NF_ASSERT(master);

	IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum))));

	DEBUGP("h225_nat_expected: We have a connection!\n");
	master_info = &ct->master->expectant->help.ct_h225_info;
	exp_info = &ct->master->help.exp_h225_info;

	LOCK_BH(&ip_h323_lock);

	DEBUGP("master: ");
	DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
	DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_REPLY].tuple);
	DEBUGP("conntrack: ");
	DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
	if (exp_info->dir == IP_CT_DIR_ORIGINAL) {
		/* Make connection go to the client. */
		newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
		newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
		DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to client)\n",
		       NIPQUAD(newsrcip), NIPQUAD(newdstip));
	} else {
		/* Make the connection go to the server */
		newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
		newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
		DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to server)\n",
		       NIPQUAD(newsrcip), NIPQUAD(newdstip));
	}
	port = exp_info->port;
	is_h225 = master_info->is_h225 == H225_PORT;
	UNLOCK_BH(&ip_h323_lock);
	
	if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
		newip = newsrcip;
	else
		newip = newdstip;

	DEBUGP("h225_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip));

	mr.rangesize = 1;
	/* We don't want to manip the per-protocol, just the IPs... */
	mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
	mr.range[0].min_ip = mr.range[0].max_ip = newip;

	/* ... unless we're doing a MANIP_DST, in which case, make
	   sure we map to the correct port */
	if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
		mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
		mr.range[0].min = mr.range[0].max
			= ((union ip_conntrack_manip_proto)
				{ .tcp = { port } });
Exemplo n.º 23
0
static int quake3_help(struct sk_buff **pskb,
	struct ip_conntrack *ct,
	enum ip_conntrack_info ctinfo)
{
	struct udphdr _udph, *uh;
	struct ip_conntrack_expect *exp;
	void *data, *qb_ptr;
	int dir = CTINFO2DIR(ctinfo);
	int i, dataoff;
	int ret = NF_ACCEPT;

	
	/* Until there's been traffic both ways, don't look in packets. note:
	 * it's UDP ! */
	if (ctinfo != IP_CT_ESTABLISHED
	    && ctinfo != IP_CT_IS_REPLY) {
	        DEBUGP("ip_conntrack_quake3: not ok ! Conntrackinfo = %u\n",
			ctinfo);
	        return NF_ACCEPT;
	} else { 
		DEBUGP("ip_conntrack_quake3: it's ok ! Conntrackinfo = %u\n",
			ctinfo);
	}

	/* Valid UDP header? */
	uh = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4,
				sizeof(_udph), &_udph);
	if (!uh)
		return NF_ACCEPT;

	/* Any data? */
	dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
	if (dataoff >= (*pskb)->len)
		return NF_ACCEPT;

	LOCK_BH(&quake3_buffer_lock);
	qb_ptr = skb_header_pointer(*pskb, dataoff,
				    (*pskb)->len - dataoff, quake3_buffer);
	BUG_ON(qb_ptr == NULL);
	data = qb_ptr;

	
	if (strnicmp(data + 4, quake3s_conntrack.pattern, 
		     quake3s_conntrack.plen) == 0) {
		for(i=23;    /* 4 bytes filler, 18 bytes "getserversResponse", 
				1 byte "\" */
		    i+6 < ntohs(uh->len);
		    i+=7) {
			u_int32_t *ip = data+i;
			u_int16_t *port = data+i+4;
#if 0
			DEBUGP("ip_conntrack_quake3: adding server at offset "
			       "%u/%u %u.%u.%u.%u:%u\n", i, ntohs(uh->len),
			       NIPQUAD(*ip), ntohs(*port));
#endif

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

			memset(exp, 0, sizeof(*exp));

			exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
			exp->tuple.dst.ip = *ip;
			exp->tuple.dst.u.udp.port = *port;
			exp->tuple.dst.protonum = IPPROTO_UDP;

			exp->mask.src.ip = 0xffffffff;
			exp->mask.dst.ip = 0xffffffff;
			exp->mask.dst.u.udp.port = 0xffff;
			exp->mask.dst.protonum = 0xff;

			if (ip_nat_quake3_hook) 
				ret = ip_nat_quake3_hook(exp);
			else if (ip_conntrack_expect_related(exp) != 0) {
				ip_conntrack_expect_free(exp);
				ret = NF_DROP;
			}
			goto out;
		}
	}
	
out:
	return ret;
}
Exemplo n.º 24
0
/* FIXME: This should be in userspace.  Later. */
static int help(const struct iphdr *iph, size_t len,
		struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
{
	/* tcplen not negative guarenteed by ip_conntrack_tcp.c */
	struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
	const char *data = (const char *) tcph + tcph->doff * 4;
	u_int32_t tcplen = len - iph->ihl * 4;
	int dir = CTINFO2DIR(ctinfo);
        struct ip_conntrack_expect expect, *exp = &expect;
        struct ip_ct_rsh_expect *exp_rsh_info = &exp->help.exp_rsh_info;
	u_int16_t port;
	int maxoctet;

	/*  note that "maxoctet" is used to maintain sanity (8 was the
 	 *  original array size used in rshd/glibc) -- is there a
	 *  vulnerability in rshd.c in the looped port *= 10?
 	 */


	DEBUGP("entered\n");

	/* bail if packet is not from RSH client */
	if (dir == IP_CT_DIR_REPLY)
		return NF_ACCEPT;

	/* Until there's been traffic both ways, don't look in packets. */
	if (ctinfo != IP_CT_ESTABLISHED
	    && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
		DEBUGP("Conntrackinfo = %u\n", ctinfo);
		return NF_ACCEPT;
	}

	/* Not whole TCP header? */
	if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
		DEBUGP("tcplen = %u\n", (unsigned) tcplen);
		return NF_ACCEPT;
	}

	/* Checksum invalid?  Ignore. */
	/* FIXME: Source route IP option packets --RR */
	if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
			 csum_partial((char *) tcph, tcplen, 0))) {
		DEBUGP("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
		     tcph, tcplen, NIPQUAD(iph->saddr),
		     NIPQUAD(iph->daddr));
		return NF_ACCEPT;
	}

	/* find the rsh stderr port */
	maxoctet = 4;
	port = 0;
	for ( ; *data != 0 && maxoctet != 0; data++, maxoctet--) {
		if (*data < 0)
			return(1);
		if (*data == 0)
			break;
		if (*data < 48 || *data > 57) {
			DEBUGP("these aren't the packets you're looking for ..\n");
			return NF_ACCEPT;
		}
		port = port * 10 + ( *data - 48 );
	}

	/* dont relate sessions that try to expose the client */
	DEBUGP("found port %u\n", port);
	if (port > range) {
		DEBUGP("skipping, expected port size is greater than range!\n");
		return NF_ACCEPT;
	}


	LOCK_BH(&ip_rsh_lock);

	/*  new(,related) connection is;
	 *          reply + dst (uint)port + src port (0:1023)
	 */
	memset(&expect, 0, sizeof(expect));

	/*  save some discovered data, in case someone ever wants to write
	 *  a NAT module for this bastard ..
	 */
	exp_rsh_info->port = port;

	DEBUGP("wrote info port=%u\n", exp_rsh_info->port);


	/* Watch out, Radioactive-Man! */
	exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
	exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
	exp->tuple.src.u.tcp.port = 0;
	exp->tuple.dst.u.tcp.port = htons(exp_rsh_info->port);
	exp->tuple.dst.protonum = IPPROTO_TCP;

	exp->mask.src.ip = 0xffffffff;
	exp->mask.dst.ip = 0xffffffff;

	exp->mask.src.u.tcp.port = htons(rangemask);
	exp->mask.dst.u.tcp.port = htons(0xffff);
	exp->mask.dst.protonum = 0xffff;

	exp->expectfn = NULL;

	ip_conntrack_expect_related(ct, &expect);

	DEBUGP("expect related ip   %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\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));

	DEBUGP("expect related mask %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n",
		NIPQUAD(exp->mask.src.ip),
		ntohs(exp->mask.src.u.tcp.port),
		NIPQUAD(exp->mask.dst.ip),
		ntohs(exp->mask.dst.u.tcp.port));
	UNLOCK_BH(&ip_rsh_lock);

	return NF_ACCEPT;
}