Ejemplo n.º 1
0
static int tftp_help(struct sk_buff **pskb,
		     struct ip_conntrack *ct,
		     enum ip_conntrack_info ctinfo)
{
	struct tftphdr _tftph, *tfh;
	struct ip_conntrack_expect *exp;
	unsigned int ret = NF_ACCEPT;

	tfh = skb_header_pointer(*pskb,
				 (*pskb)->nh.iph->ihl*4+sizeof(struct udphdr),
				 sizeof(_tftph), &_tftph);
	if (tfh == NULL)
		return NF_ACCEPT;

	switch (ntohs(tfh->opcode)) {
	/* RRQ and WRQ works the same way */
	case TFTP_OPCODE_READ:
	case TFTP_OPCODE_WRITE:
		DEBUGP("");
		DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
		DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);

		exp = ip_conntrack_expect_alloc(ct);
		if (exp == NULL)
			return NF_DROP;

		exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
		exp->mask.src.ip = 0xffffffff;
		exp->mask.src.u.udp.port = 0;
		exp->mask.dst.ip = 0xffffffff;
		exp->mask.dst.u.udp.port = 0xffff;
		exp->mask.dst.protonum = 0xff;
		exp->expectfn = NULL;
		exp->flags = 0;

		DEBUGP("expect: ");
		DUMP_TUPLE(&exp->tuple);
		DUMP_TUPLE(&exp->mask);
		if (ip_nat_tftp_hook)
			ret = ip_nat_tftp_hook(pskb, ctinfo, exp);
		else if (ip_conntrack_expect_related(exp) != 0)
			ret = NF_DROP;
		ip_conntrack_expect_put(exp);
		break;
	case TFTP_OPCODE_DATA:
	case TFTP_OPCODE_ACK:
		DEBUGP("Data/ACK opcode\n");
		break;
	case TFTP_OPCODE_ERROR:
		DEBUGP("Error opcode\n");
		break;
	default:
		DEBUGP("Unknown opcode\n");
	}
	return NF_ACCEPT;
}
/*
 * Handle an incoming packet.
 */
static int
ipsec_help(struct sk_buff *skb,
        struct ip_conntrack *ct,
        enum ip_conntrack_info ctinfo)
{
    struct ip_conntrack_expect *exp;

#if IPSEC_CONNTRACK_DEBUG
    IPSEC_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
    IPSEC_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
    printk (KERN_DEBUG "Received packet Direction %s\n",
            ( ctinfo >= IP_CT_IS_REPLY ) ? "REPLY" : "ORIG");
#endif
    /*
     * We got to trust the netfilter to call this routine only on
     * receiving the first packet without an expectation.
     * There will be at least one more packet for this tuple
     * so set our expectation for it here.
     */
     /* Allocate expectation which will be inserted */
     exp = ip_conntrack_expect_alloc(ct);
     if (exp == NULL) {
             goto out;
     }
     memset(exp, 0, sizeof(exp));

     exp->tuple                       = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
     exp->mask.src.ip                 = 0xFFFFFFFF;
     exp->mask.dst.ip                 = 0xFFFFFFFF;
     exp->mask.dst.u.udp.port         = ntohs(IPSEC_UDP_PORT);
     exp->mask.dst.protonum           = 0xFFFF;
     exp->expectfn                    = NULL;
#if IPSEC_CONNTRACK_DEBUG
     printk( KERN_DEBUG "%s:%s expect: 0x%x 0x%x"
             " %u.%u.%u.%u:%u\n <--> %u.%u.%u.%u:%u\n", __FILE__, __FUNCTION__,
             ntohl(isakmph->initcookie[0]), ntohl(isakmph->initcookie[1]),
             NIPQUAD(iph->saddr), udph->source, NIPQUAD(iph->daddr), udph->dest);
#endif
     
     if( ip_nat_ipsec_hook )
     			ip_nat_ipsec_hook(ct , exp , ct->nat.info , ctinfo , hooknum , &skb);
     else			
     		  ip_conntrack_expect_related(exp);
out:
    return NF_ACCEPT;
}
Ejemplo n.º 3
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.º 4
0
/* So, this packet has hit the connection tracking matching code.
   Mangle it, and change the expectation to match the new version. */
static unsigned int ip_nat_ftp(struct sk_buff **pskb,
			       enum ip_conntrack_info ctinfo,
			       enum ip_ct_ftp_type type,
			       unsigned int matchoff,
			       unsigned int matchlen,
			       struct ip_conntrack_expect *exp,
			       u32 *seq)
{
	u_int32_t newip;
	u_int16_t port;
	int dir = CTINFO2DIR(ctinfo);
	struct ip_conntrack *ct = exp->master;

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

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

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

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

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

	if (!mangle[type](pskb, newip, port, matchoff, matchlen, ct, ctinfo,
			  seq)) {
		ip_conntrack_unexpect_related(exp);
		return NF_DROP;
	}
	return NF_ACCEPT;
}
Ejemplo n.º 5
0
static int tftp_help(const struct iphdr *iph, size_t len,
	struct ip_conntrack *ct,
	enum ip_conntrack_info ctinfo)
{
	struct udphdr *udph = (void *)iph + iph->ihl * 4;
	struct tftphdr *tftph = (void *)udph + 8;
	struct ip_conntrack_expect exp;
	
	switch (ntohs(tftph->opcode)) {
	/* RRQ and WRQ works the same way */
	case TFTP_OPCODE_READ:
	case TFTP_OPCODE_WRITE:
		DEBUGP("");
		DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
		DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
		memset(&exp, 0, sizeof(exp));

		exp.tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
		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;

		DEBUGP("expect: ");
		DUMP_TUPLE(&exp.tuple);
		DUMP_TUPLE(&exp.mask);
		ip_conntrack_expect_related(ct, &exp);
		break;
	case TFTP_OPCODE_DATA:
	case TFTP_OPCODE_ACK:
		DEBUGP("Data/ACK opcode\n");
		break;
	case TFTP_OPCODE_ERROR:
		DEBUGP("Error opcode\n");
		break;
	default:
		DEBUGP("Unknown opcode\n");
	}
	return NF_ACCEPT;
}
static int nat_t120(struct sk_buff **pskb, struct ip_conntrack *ct,
		    enum ip_conntrack_info ctinfo,
		    unsigned char **data, int dataoff,
		    H245_TransportAddress * addr, u_int16_t port,
		    struct ip_conntrack_expect *exp)
{
	int dir = CTINFO2DIR(ctinfo);
	u_int16_t nated_port = port;

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

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

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

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

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

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

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

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

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

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

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

	if (port == 0)
		return NF_DROP;

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

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

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

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

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

	sprintf(buffer, "%u", port);
	ret = ip_nat_mangle_udp_packet(pskb, exp->master, ctinfo,
				       matchoff, matchlen,
				       buffer, strlen(buffer));
	if (ret != NF_ACCEPT)
		ip_conntrack_unexpect_related(exp);
	return ret;
}
Ejemplo n.º 9
0
static int tftp_help(struct sk_buff *skb,
		     struct ip_conntrack *ct,
		     enum ip_conntrack_info ctinfo)
{
	struct tftphdr tftph;
	struct ip_conntrack_expect exp;

	if (skb_copy_bits(skb, skb->nh.iph->ihl * 4 + sizeof(struct udphdr),
			  &tftph, sizeof(tftph)) != 0)
		return NF_ACCEPT;

	switch (ntohs(tftph.opcode)) {
	/* RRQ and WRQ works the same way */
	case TFTP_OPCODE_READ:
	case TFTP_OPCODE_WRITE:
		DEBUGP("");
		DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
		DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
		memset(&exp, 0, sizeof(exp));

		exp.tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
		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;

		DEBUGP("expect: ");
		DUMP_TUPLE(&exp.tuple);
		DUMP_TUPLE(&exp.mask);
		ip_conntrack_expect_related(ct, &exp);
		break;
	default:
		DEBUGP("Unknown opcode\n");
	}
	return NF_ACCEPT;
}
Ejemplo 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)
{
	//int dir = CTINFO2DIR(ctinfo);
	//struct udphdr *udph = (void *)iph + iph->ihl * 4;
        struct ip_conntrack_expect exp;
	int i;
	u_int16_t port;
	u_int16_t outproto;
	u_int16_t outport;

	//DEBUGP("pt_help: Conntrackinfo = %u dir=%d\n", ctinfo,dir);
        DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
        DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
/*
** We need to search the pt_record[] to see what inports need to be triggered
** based on the tuple's destination protonum and port number 
** we know from the ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple the protonum and port number
** ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum
** ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.all
*/
	//dump_pt_record();
 outproto = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum;
 outport = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.all;
 //printk("ip_conntrack_pt: outproto=%d outport=%hu\n",outproto,ntohs(outport));
	/*convert proto */
	if (outproto == IPPROTO_TCP)
		outproto=1;
	else if (outproto == IPPROTO_UDP)
		outproto=2;
	else
		outproto=0;

        memset(&exp, 0, sizeof(exp));
        exp.tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
	//dump_pt_record();
	for(i = 0; i < entries; i++) {
	  /* we only call expect_related for entries match our outgoing port(outport) */
	  if ((outproto == pt_record[i].outproto || pt_record[i].outproto== 0) && (ntohs(outport) >= pt_record[i].outport[0] && ntohs(outport) <= pt_record[i].outport[1])) { 
	    for (port = pt_record[i].inport[0]; port <= pt_record[i].inport[1];port++) { 
		//printk("******** ip_conntrack_pt: help port=%d \n",port);
		if ( pt_record[i].inproto == 1 ) {
		   //printk("******** ip_conntrack_pt: help TCP port=%d \n",port);
            	   exp.tuple.dst.protonum = IPPROTO_TCP;
            	   exp.tuple.dst.u.tcp.port = htons(port);
            	   //exp.mask.src.ip = 0xffffffff;
            	   exp.mask.src.ip = 0;
            	   exp.mask.src.u.all = 0;
            	   exp.mask.dst.ip = 0xffffffff;
            	   exp.mask.dst.u.tcp.port = 0xffff;
            	   exp.mask.dst.protonum = 0xffff;
		}
		else if ( pt_record[i].inproto == 2 ) {
		   //printk("******** ip_conntrack_pt: help UDP port=%d \n",port);
            	   exp.tuple.dst.u.udp.port = htons(port);
            	   exp.tuple.dst.protonum = IPPROTO_UDP;
            	   //exp.mask.src.ip = 0xffffffff;
            	   exp.mask.src.ip = 0;
            	   exp.mask.src.u.all = 0;
            	   exp.mask.dst.ip = 0xffffffff;
            	   exp.mask.dst.u.udp.port = 0xffff;
            	   exp.mask.dst.protonum = 0xffff;
		}
		else {
		   //printk("******** ip_conntrack_pt: help BOTH port=%x \n",port);
            	   exp.tuple.dst.u.all = htons(port);
            	   //exp.mask.src.ip = 0xffffffff;
            	   exp.mask.src.ip = 0;
            	   exp.mask.src.u.all = 0;
            	   exp.mask.dst.ip = 0xffffffff;
            	   exp.mask.dst.u.all = 0xffff;
            	   exp.mask.dst.protonum = 0;
		}
                exp.expectfn = NULL;

                //DEBUGP("expect: ");
                //DUMP_TUPLE(&exp.tuple);
                //DUMP_TUPLE(&exp.mask);
                ip_conntrack_expect_related(ct, &exp);
	    } /* end of for */
	  } /* end of if */
	}
        return NF_ACCEPT;
}
Ejemplo n.º 11
0
static unsigned int mms_data_fixup(struct sk_buff **pskb,
                                   enum ip_conntrack_info ctinfo,
                                   const struct ip_ct_mms_expect *ct_mms_info,
                                   struct ip_conntrack_expect *expect)
{
    u_int32_t newip;
    struct ip_conntrack *ct = expect->master;
    struct iphdr *iph = (*pskb)->nh.iph;
    struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
    char *data = (char *)tcph + tcph->doff * 4;
    int i, j, k, port;
    u_int16_t mms_proto;

    u_int32_t *mms_chunkLenLV    = (u_int32_t *)(data + MMS_SRV_CHUNKLENLV_OFFSET);
    u_int32_t *mms_chunkLenLM    = (u_int32_t *)(data + MMS_SRV_CHUNKLENLM_OFFSET);
    u_int32_t *mms_messageLength = (u_int32_t *)(data + MMS_SRV_MESSAGELENGTH_OFFSET);

    int zero_padding;

    char buffer[28];         /* "\\255.255.255.255\UDP\65635" * 2
				    (for unicode) */
    char unicode_buffer[75]; /* 27*2 (unicode) + 20 + 1 */
    char proto_string[6];

    /* what was the protocol again ? */
    mms_proto = expect->tuple.dst.protonum;
    sprintf(proto_string, "%u", mms_proto);

    DEBUGP("ip_nat_mms: mms_data_fixup: info (seq %u + %u) "
           "in %u, proto %s\n",
           expect->seq, ct_mms_info->len, ntohl(tcph->seq),
           mms_proto == IPPROTO_UDP ? "UDP"
           : mms_proto == IPPROTO_TCP ? "TCP":proto_string);

    newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
    expect->saved_proto.tcp.port = expect->tuple.dst.u.tcp.port;
    expect->expectfn = ip_nat_follow_master;

    /* Alter conntrack's expectations. */
    for (port = ct_mms_info->port; port != 0; port++) {
        expect->tuple.dst.u.tcp.port = htons(port);
        if (ip_conntrack_expect_related(expect) == 0) {
            DEBUGP("ip_nat_mms: mms_data_fixup: using port %d\n",
                   port);
            break;
        }
    }

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

    sprintf(buffer, "\\\\%u.%u.%u.%u\\%s\\%u",
            NIPQUAD(newip),
            expect->tuple.dst.protonum == IPPROTO_UDP ? "UDP"
            : expect->tuple.dst.protonum == IPPROTO_TCP ? "TCP":proto_string,
            port);
    DEBUGP("ip_nat_mms: new unicode string=%s\n", buffer);

    memset(unicode_buffer, 0, sizeof(char)*75);

    for (i=0; i<strlen(buffer); ++i)
        *(unicode_buffer+i*2)=*(buffer+i);

    DEBUGP("ip_nat_mms: mms_data_fixup: padding: %u len: %u\n",
           ct_mms_info->padding, ct_mms_info->len);
    DEBUGP("ip_nat_mms: mms_data_fixup: offset: %u\n",
           MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len);
    DUMP_BYTES(data+MMS_SRV_UNICODE_STRING_OFFSET, 60);

    /* add end of packet to it */
    for (j=0; j<ct_mms_info->padding; ++j) {
        DEBUGP("ip_nat_mms: mms_data_fixup: i=%u j=%u byte=%u\n",
               i, j, (u8)*(data+MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len+j));
        *(unicode_buffer+i*2+j) = *(data+MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len+j);
    }

    /* pad with zeroes at the end ? see explanation of weird math below */
    zero_padding = (8-(strlen(buffer)*2 + ct_mms_info->padding + 4)%8)%8;
    for (k=0; k<zero_padding; ++k)
        *(unicode_buffer+i*2+j+k)= (char)0;

    DEBUGP("ip_nat_mms: mms_data_fixup: zero_padding = %u\n", zero_padding);
    DEBUGP("ip_nat_mms: original=> chunkLenLV=%u chunkLenLM=%u "
           "messageLength=%u\n", *mms_chunkLenLV, *mms_chunkLenLM,
           *mms_messageLength);

    /* explanation, before I forget what I did:
       strlen(buffer)*2 + ct_mms_info->padding + 4 must be divisable by 8;
       divide by 8 and add 3 to compute the mms_chunkLenLM field,
       but note that things may have to be padded with zeroes to align by 8
       bytes, hence we add 7 and divide by 8 to get the correct length */
    *mms_chunkLenLM    = (u_int32_t) (3+(strlen(buffer)*2+ct_mms_info->padding+11)/8);
    *mms_chunkLenLV    = *mms_chunkLenLM+2;
    *mms_messageLength = *mms_chunkLenLV*8;

    DEBUGP("ip_nat_mms: modified=> chunkLenLV=%u chunkLenLM=%u"
           " messageLength=%u\n", *mms_chunkLenLV, *mms_chunkLenLM,
           *mms_messageLength);

    ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
                             ct_mms_info->offset,
                             ct_mms_info->len + ct_mms_info->padding,
                             unicode_buffer, strlen(buffer)*2 +
                             ct_mms_info->padding + zero_padding);
    DUMP_BYTES(unicode_buffer, 60);

    return NF_ACCEPT;
}
Ejemplo n.º 12
0
/* expect GRE connections (PNS->PAC and PAC->PNS direction) */
static inline int
exp_gre(struct ip_conntrack *master,
	u_int32_t seq,
	u_int16_t callid,
	u_int16_t peer_callid)
{
	struct ip_conntrack_expect exp;
	struct ip_conntrack_tuple inv_tuple;

	memset(&exp, 0, sizeof(exp));
	/* tuple in original direction, PNS->PAC */
	exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
	exp.tuple.src.u.gre.key = htonl(ntohs(peer_callid));
	exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
	exp.tuple.dst.u.gre.key = htonl(ntohs(callid));
	exp.tuple.dst.u.gre.protocol = __constant_htons(GRE_PROTOCOL_PPTP);
	exp.tuple.dst.u.gre.version = GRE_VERSION_PPTP;
	exp.tuple.dst.protonum = IPPROTO_GRE;

	exp.mask.src.ip = 0xffffffff;
	exp.mask.src.u.all = 0;
	exp.mask.dst.u.all = 0;
	exp.mask.dst.u.gre.key = 0xffffffff;
	exp.mask.dst.u.gre.version = 0xff;
	exp.mask.dst.u.gre.protocol = 0xffff;
	exp.mask.dst.ip = 0xffffffff;
	exp.mask.dst.protonum = 0xffff;
			
	exp.seq = seq;
	exp.expectfn = pptp_expectfn;

	exp.help.exp_pptp_info.pac_call_id = ntohs(callid);
	exp.help.exp_pptp_info.pns_call_id = ntohs(peer_callid);

	DEBUGP("calling expect_related ");
	DUMP_TUPLE_RAW(&exp.tuple);
	
	/* Add GRE keymap entries */
	if (ip_ct_gre_keymap_add(&exp, &exp.tuple, 0) != 0)
		return 1;

	invert_tuplepr(&inv_tuple, &exp.tuple);
	if (ip_ct_gre_keymap_add(&exp, &inv_tuple, 1) != 0) {
		ip_ct_gre_keymap_destroy(&exp);
		return 1;
	}
	
	if (ip_conntrack_expect_related(master, &exp) != 0) {
		ip_ct_gre_keymap_destroy(&exp);
		DEBUGP("cannot expect_related()\n");
		return 1;
	}

	/* tuple in reply direction, PAC->PNS */
	exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
	exp.tuple.src.u.gre.key = htonl(ntohs(callid));
	exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
	exp.tuple.dst.u.gre.key = htonl(ntohs(peer_callid));

	DEBUGP("calling expect_related ");
	DUMP_TUPLE_RAW(&exp.tuple);
	
	/* Add GRE keymap entries */
	ip_ct_gre_keymap_add(&exp, &exp.tuple, 0);
	invert_tuplepr(&inv_tuple, &exp.tuple);
	ip_ct_gre_keymap_add(&exp, &inv_tuple, 1);
	/* FIXME: cannot handle error correctly, since we need to free
	 * the above keymap :( */
	
	if (ip_conntrack_expect_related(master, &exp) != 0) {
		/* free the second pair of keypmaps */
		ip_ct_gre_keymap_destroy(&exp);
		DEBUGP("cannot expect_related():\n");
		return 1;
	}

	return 0;
}
Ejemplo n.º 13
0
/* expect GRE connection in PNS->PAC direction */
static inline int
exp_gre(struct ip_conntrack *master,
	u_int32_t seq,
	u_int16_t callid,
	u_int16_t peer_callid)
{
	struct ip_conntrack_expect exp;
	struct ip_conntrack_tuple inv_tuple;

	memset(&exp, 0, sizeof(exp));
	/* tuple in original direction, PNS->PAC */
	exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
	exp.tuple.src.u.gre.key = htonl(ntohs(peer_callid));
	exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
	exp.tuple.dst.u.gre.key = htonl(ntohs(callid));
	exp.tuple.dst.u.gre.protocol = __constant_htons(GRE_PROTOCOL_PPTP);
	exp.tuple.dst.u.gre.version = GRE_VERSION_PPTP;
	exp.tuple.dst.protonum = IPPROTO_GRE;

	exp.mask.src.ip = 0xffffffff;
	exp.mask.src.u.all = 0;
	exp.mask.dst.u.all = 0;
	exp.mask.dst.u.gre.key = 0xffffffff;
	exp.mask.dst.u.gre.version = 0xff;
	exp.mask.dst.u.gre.protocol = 0xffff;
	exp.mask.dst.ip = 0xffffffff;
	exp.mask.dst.protonum = 0xffff;
			
	exp.seq = seq;
	exp.expectfn = pptp_expectfn;

	exp.help.exp_pptp_info.pac_call_id = ntohs(callid);
	exp.help.exp_pptp_info.pns_call_id = ntohs(peer_callid);

	DEBUGP("calling expect_related ");
	DUMP_TUPLE_RAW(&exp.tuple);
	
	/* Add GRE keymap entries */
	ip_ct_gre_keymap_add(&exp, &exp.tuple, 0);
	invert_tuplepr(&inv_tuple, &exp.tuple);
	ip_ct_gre_keymap_add(&exp, &inv_tuple, 1);
	
	ip_conntrack_expect_related(master, &exp);

	/* tuple in reply direction, PAC->PNS */
	exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
	exp.tuple.src.u.gre.key = htonl(ntohs(callid));
	exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
	exp.tuple.dst.u.gre.key = htonl(ntohs(peer_callid));

	DEBUGP("calling expect_related ");
	DUMP_TUPLE_RAW(&exp.tuple);
	
	/* Add GRE keymap entries */
	ip_ct_gre_keymap_add(&exp, &exp.tuple, 0);
	invert_tuplepr(&inv_tuple, &exp.tuple);
	ip_ct_gre_keymap_add(&exp, &inv_tuple, 1);
	
	ip_conntrack_expect_related(master, &exp);

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

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

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

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

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

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

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

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

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

	return 0;
}
/* outbound packet: client->server */
static inline int
help_out(struct sk_buff **pskb, unsigned char *rb_ptr, unsigned int datalen,
                struct ip_conntrack* ct, enum ip_conntrack_info ctinfo)
{
    struct ip_ct_rtsp_expect expinfo;
    int dir = CTINFO2DIR(ctinfo);   /* = IP_CT_DIR_ORIGINAL */
    //struct  tcphdr* tcph = (void*)iph + iph->ihl * 4;
    //uint    tcplen = pktlen - iph->ihl * 4;
    char*   pdata = rb_ptr;
    //uint    datalen = tcplen - tcph->doff * 4;
    uint    dataoff = 0;
    int ret = NF_ACCEPT;

    struct ip_conntrack_expect *exp;

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

    while (dataoff < datalen)
    {
        uint    cmdoff = dataoff;
        uint    hdrsoff = 0;
        uint    hdrslen = 0;
        uint    cseqoff = 0;
        uint    cseqlen = 0;
        uint    lineoff = 0;
        uint    linelen = 0;
        uint    off;

        if (!rtsp_parse_message(pdata, datalen, &dataoff,
                                &hdrsoff, &hdrslen,
                                &cseqoff, &cseqlen))
        {
            break;      /* not a valid message */
        }

        if (strncmp(pdata+cmdoff, "SETUP ", 6) != 0)
        {
            continue;   /* not a SETUP message */
        }
        DEBUGP("found a setup message\n");

        off = 0;
        while (nf_mime_nextline(pdata+hdrsoff, hdrslen, &off,
                                &lineoff, &linelen))
        {
            if (linelen == 0)
            {
                break;
            }
            if (off > hdrsoff+hdrslen)
            {
                INFOP("!! overrun !!");
                break;
            }

            if (nf_strncasecmp(pdata+hdrsoff+lineoff, "Transport:", 10) == 0)
            {
                rtsp_parse_transport(pdata+hdrsoff+lineoff, linelen, &expinfo);
            }
        }

        if (expinfo.loport == 0)
        {
            DEBUGP("no udp transports found\n");
            continue;   /* no udp transports found */
        }

        DEBUGP("udp transport found, ports=(%d,%hu,%hu)\n",
              (int)expinfo.pbtype,
              expinfo.loport,
              expinfo.hiport);

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

        //exp->seq = ntohl(tcph->seq) + hdrsoff; /* mark all the headers */
	exp->master = ct;
        //exp.help.exp_rtsp_info.len = hdrslen;

        exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
        exp->mask.src.ip  = 0xffffffff;
        exp->tuple.dst.ip = ct->tuplehash[dir].tuple.src.ip;
        exp->mask.dst.ip  = 0xffffffff;
        exp->tuple.dst.u.udp.port = expinfo.loport;
        exp->mask.dst.u.udp.port  = 
		(expinfo.pbtype == pb_range) ? 0xfffe : 0xffff;
        exp->tuple.dst.protonum = IPPROTO_UDP;
        exp->mask.dst.protonum  = 0xff;

        DEBUGP("expect_related %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));

	if (ip_nat_rtsp_hook)
        	/* pass the request off to the nat helper */
		ret = ip_nat_rtsp_hook(pskb, ctinfo, &expinfo, exp);
	else if (ip_conntrack_expect_related(exp) != 0) {
  		INFOP("ip_conntrack_expect_related failed\n");
		ip_conntrack_expect_put(exp);
		ret  = NF_DROP;
	}
	goto out;
    }
out:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

out:
	spin_unlock_bh(&amanda_buffer_lock);
	return ret;
}
Ejemplo n.º 18
0
static int
pptp_exp_gre(struct ip_conntrack_expect *expect_orig,
	     struct ip_conntrack_expect *expect_reply)
{
	struct ip_ct_pptp_master *ct_pptp_info = 
				&expect_orig->master->help.ct_pptp_info;
	struct ip_nat_pptp *nat_pptp_info = 
				&expect_orig->master->nat.help.nat_pptp_info;

	struct ip_conntrack *ct = expect_orig->master;

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

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

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

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

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

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

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

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

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

	return 0;
}
Ejemplo n.º 19
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;
}
/* FIXME: This should be in userspace.  Later. */
static int help(struct sk_buff **pskb,
		struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
{
	struct tcphdr _tcph, *th;
	char *data, *rb_ptr;
	int ret = NF_ACCEPT;
	int dir = CTINFO2DIR(ctinfo);
        struct ip_conntrack_expect *exp;
	unsigned int dataoff, datalen;
	u_int16_t port;
	int maxoctet = 4;

	/*  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 a full tcp header? */
	th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4,
				sizeof(_tcph), &_tcph);
	if (!th) {
		DEBUGP("rsh: skb_header_pointer null\n");
		return NF_ACCEPT;
	}

	/* No data? */
	dataoff = (*pskb)->nh.iph->ihl*4 + th->doff*4;
	if (dataoff >= (*pskb)->len) {
		return NF_ACCEPT;
	}
	datalen = (*pskb)->len - dataoff;
	spin_lock_bh(&rsh_buffer_lock);
	rb_ptr = skb_header_pointer(*pskb, dataoff, datalen, rsh_buffer);
	BUG_ON(rb_ptr == NULL);
	data = rb_ptr;

	DEBUGP("rsh: find rsh stderr port datalen %u\n",datalen);

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

	/* dont relate sessions that try to expose the client */
	if (port == 0) {
           DEBUGP("skipping, port is 0!\n");
	   ret = NF_ACCEPT;goto out;
	}

	DEBUGP("found port %u\n", port);
	if (port > range) {
		DEBUGP("skipping, expected port size is greater than range!\n");
		return NF_ACCEPT;
	}

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

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

	/* 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(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 = 0xff;

	exp->expectfn = NULL;
	exp->master = ct;

	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));

	if (ip_nat_rsh_hook)
		ret = ip_nat_rsh_hook(pskb, ctinfo, rb_ptr - data, exp);
	else if (ip_conntrack_expect_related(exp) != 0) {
		ret = NF_DROP;
	}

	ip_conntrack_expect_put(exp);

out:
	spin_unlock_bh(&rsh_buffer_lock);
	return ret;
}
Ejemplo n.º 21
0
static unsigned int help(struct sk_buff **pskb,
                         enum ip_conntrack_info ctinfo,
                         unsigned int matchoff,
                         unsigned int matchlen,
                         struct ip_conntrack_expect *exp)
{
    u_int16_t port;
    unsigned int ret;

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

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

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

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

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

    if (port == 0)
        return NF_DROP;

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

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

    ret = ip_nat_mangle_tcp_packet(pskb, exp->master, ctinfo,
                                   matchoff, matchlen, buffer,
                                   strlen(buffer));
    if (ret != NF_ACCEPT)
        ip_conntrack_unexpect_related(exp);
    return ret;
}
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;

	spin_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(ct);
			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_put(exp);
				ret = NF_DROP;
			}
			goto out;
		}
	}
	
out:
	spin_unlock_bh(&quake3_buffer_lock);

	return ret;
}
Ejemplo n.º 23
0
static int check_rpc_packet(const u_int32_t *data,
			int dir, struct ip_conntrack *ct,
			struct list_head request_p_list)
{
        int ret = NF_ACCEPT;
	u_int32_t xid;
	struct request_p *req_p;
	struct ip_conntrack_expect *exp;

	/* Translstion's buffer for XDR */
	u_int16_t port_buf;


	/* Get XID */
	xid = *data;

 	/* This does sanity checking on RPC payloads,
	 * and permits only the RPC "get port" (3)
	 * in authorised procedures in client
	 * communications with the portmapper.
	 */

	/* perform direction dependant RPC work */
	if (dir == IP_CT_DIR_ORIGINAL) {

		data += 5;

		/* Get RPC requestor */
		if (IXDR_GET_INT32(data) != 3) {
			DEBUGP("RPC packet contains an invalid (non \"get\") requestor. [skip]\n");
			return NF_ACCEPT;
		}
		DEBUGP("RPC packet contains a \"get\" requestor. [cont]\n");

		data++;

		/* Jump Credentials and Verfifier */
		data = data + IXDR_GET_INT32(data) + 2;
		data = data + IXDR_GET_INT32(data) + 2;

		/* Get RPC procedure */
		DEBUGP("RPC packet contains procedure request [%u]. [cont]\n",
			(unsigned int)IXDR_GET_INT32(data));

		/* Get RPC protocol and store against client parameters */
		data = data + 2;
		alloc_request_p(xid, IXDR_GET_INT32(data), ct->tuplehash[dir].tuple.src.ip,
				ct->tuplehash[dir].tuple.src.u.all);

		DEBUGP("allocated RPC req_p for xid=%u proto=%u %u.%u.%u.%u:%u\n",
			xid, IXDR_GET_INT32(data),
			NIPQUAD(ct->tuplehash[dir].tuple.src.ip),
			ntohs(ct->tuplehash[dir].tuple.src.u.all));

		DEBUGP("allocated RPC request for protocol %u. [done]\n",
			(unsigned int)IXDR_GET_INT32(data));

	} else {

		/* Check for returning packet's stored counterpart */
		req_p = LIST_FIND(&request_p_list_udp, request_p_cmp,
				  struct request_p *, xid,
				  ct->tuplehash[!dir].tuple.src.ip,
				  ct->tuplehash[!dir].tuple.src.u.all);

		/* Drop unexpected packets */
		if (!req_p) {
			DEBUGP("packet is not expected. [skip]\n");
			return NF_ACCEPT;
		}

		/* Verifies if packet is really an RPC reply packet */
		data++;
		if (IXDR_GET_INT32(data) != 1) {
			DEBUGP("packet is not a valid RPC reply. [skip]\n");
			return NF_ACCEPT;
		}

		/* Is status accept? */
		data++;
		if (IXDR_GET_INT32(data)) {
			DEBUGP("packet is not an RPC accept. [skip]\n");
			return NF_ACCEPT;
		}

		/* Get Verifier length. Jump verifier */
		data++;
		data = data + IXDR_GET_INT32(data) + 2;

		/* Is accpet status "success"? */
		if (IXDR_GET_INT32(data)) {
			DEBUGP("packet is not an RPC accept status of success. [skip]\n");
			return NF_ACCEPT;
		}

		/* Get server port number */	  
		data++;
		port_buf = (u_int16_t) IXDR_GET_INT32(data);

		/* If a packet has made it this far then it deserves an
		 * expectation ...  if port == 0, then this service is 
		 * not going to be registered.
		 */
		if (port_buf) {
			DEBUGP("port found: %u\n", port_buf);

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

			/* 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->mask.src.ip = 0xffffffff;
			exp->mask.dst.ip = 0xffffffff;

			switch (req_p->proto) {
				case IPPROTO_UDP:
					exp->tuple.src.u.udp.port = 0;
					exp->tuple.dst.u.udp.port = htons(port_buf);
					exp->tuple.dst.protonum = IPPROTO_UDP;
					exp->mask.src.u.udp.port = 0;
					exp->mask.dst.u.udp.port = htons(0xffff);
					exp->mask.dst.protonum = 0xff;
					break;

				case IPPROTO_TCP:
					exp->tuple.src.u.tcp.port = 0;
					exp->tuple.dst.u.tcp.port = htons(port_buf);
					exp->tuple.dst.protonum = IPPROTO_TCP;
					exp->mask.src.u.tcp.port = 0;
					exp->mask.dst.u.tcp.port = htons(0xffff);
					exp->mask.dst.protonum = 0xff;
					break;
			}
			exp->expectfn = NULL;
			exp->master = ct;

			DEBUGP("expect related ip   %u.%u.%u.%u:0-%u.%u.%u.%u:%u proto=%u\n",
				NIPQUAD(exp->tuple.src.ip),
				NIPQUAD(exp->tuple.dst.ip),
				port_buf, req_p->proto);

			DEBUGP("expect related mask %u.%u.%u.%u:0-%u.%u.%u.%u:65535 proto=%u\n",
				NIPQUAD(exp->mask.src.ip),
				NIPQUAD(exp->mask.dst.ip),
				exp->mask.dst.protonum);

			if (ip_conntrack_expect_related(exp) != 0) {
		                ip_conntrack_expect_free(exp);
        		        ret = NF_DROP;
        		}
		}

out:
		req_cl(req_p);

		DEBUGP("packet evaluated. [expect]\n");
	}

	return ret;
}