Ejemplo n.º 1
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;
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
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) });
Ejemplo n.º 4
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);
}
Ejemplo n.º 5
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) });
Ejemplo n.º 6
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;
}
Ejemplo n.º 7
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;
}
Ejemplo n.º 8
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;
}
Ejemplo n.º 9
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;
}
Ejemplo n.º 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;
}
Ejemplo n.º 11
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);
}
Ejemplo n.º 12
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 } });
Ejemplo n.º 13
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 } });
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;
}
Ejemplo n.º 15
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;
}