Example #1
0
// 1. Redirect packets from client to the service provider 
static unsigned int hook_func_in(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *))
{
  struct iphdr *iph = NULL;
  struct tcphdr *tcph=NULL;
  int tcplen;

  if (!in) return NF_ACCEPT;

  iph = ip_hdr(skb);
  if (unlikely(iph == NULL)) return NF_ACCEPT;


  /* Packets destinated to the mbox will be redirected to the service provider*/
  if(iph->daddr == middlebox_networkip)
  {
    if(iph->protocol == IPPROTO_TCP)
    {
      // obtains the tcp header
      tcph = (struct tcphdr *)((__u32 *)iph + iph->ihl);

      // irrelevant packets
      // 9877 is the port listened by the service provider
      if (ntohs(tcph->dest) != 9877) return NF_ACCEPT;

      // redirect packet to the service provider
      iph->daddr = redirect_networkip;

      /*
      // Here we can add additional data into the packet to serve as network capabilities
      // 1. Additional data should be appended into the payload. We cannot add these data in front of the skb_buff since that the front space stores the packet headers, which are crutial for TCP/IP
      // 2. We need to check the tailroom before appending new data into the skb_buff.
      // 3. A module at the service provider needs to strip the added data to deliever original data context
      
      // Check whether the skb_buff has at least 40 bytes and make sure the skb_buff has not been paged.
      // The pagement of the skb_buff can be avoided once we disable the TSO offloading
      if (skb_tailroom(skb) >= 40 && skb->data_len == 0) {

	secure = network_capabilities	
    
	// append the capabilities to the data payload
	secure = skb_put(skb, 40);
      }
      */

      // recompute tcp checksum
      // This is very important, otherwise the packet will be dropped due to checksum error
      tcplen = skb->len - ip_hdrlen(skb);
      tcph->check = 0; 
      tcph->check = tcp_v4_check(tcplen, iph->saddr, iph->daddr, csum_partial(tcph, tcplen, 0));

      // recompute the IP checksum
      skb->ip_summed = CHECKSUM_NONE;
      ip_send_check(iph);

      //printk(KERN_INFO "Packet length after PRE_ROUTING: %u\n", ntohs(iph->tot_len));
    }
  }

  return NF_ACCEPT;                                                              
}
static int help(struct sk_buff **pskb, struct ip_conntrack* ct, enum
		ip_conntrack_info ctinfo) 
{
    struct tcphdr _tcph, *th;
    unsigned int dataoff, datalen;
    char *rb_ptr;
    int ret = NF_DROP;

    /* 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? */
    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;

    spin_lock_bh(&rtsp_buffer_lock);
    rb_ptr = skb_header_pointer(*pskb, dataoff,
		    		(*pskb)->len - dataoff, rtsp_buffer);
    BUG_ON(rb_ptr == NULL);

#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("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

    switch (CTINFO2DIR(ctinfo))
    {
    case IP_CT_DIR_ORIGINAL:
        ret = help_out(pskb, rb_ptr, datalen, ct, ctinfo);
        break;
    case IP_CT_DIR_REPLY:
	/* inbound packet: server->client */
        ret = NF_ACCEPT;
        break;
    }

    spin_unlock_bh(&rtsp_buffer_lock);

    return ret;
}
/* Generic function for mangling variable-length address changes inside
 * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX
 * command in FTP).
 *
 * Takes care about all the nasty sequence number changes, checksumming,
 * skb enlargement, ...
 *
 * */
int
nf_nat_mangle_tcp_packet(struct sk_buff **pskb,
			 struct nf_conn *ct,
			 enum ip_conntrack_info ctinfo,
			 unsigned int match_offset,
			 unsigned int match_len,
			 const char *rep_buffer,
			 unsigned int rep_len)
{
	struct iphdr *iph;
	struct tcphdr *tcph;
	int oldlen, datalen;

	if (!skb_make_writable(pskb, (*pskb)->len))
		return 0;

	if (rep_len > match_len &&
	    rep_len - match_len > skb_tailroom(*pskb) &&
	    !enlarge_skb(pskb, rep_len - match_len))
		return 0;

	SKB_LINEAR_ASSERT(*pskb);

	iph = (*pskb)->nh.iph;
	tcph = (void *)iph + iph->ihl*4;

	oldlen = (*pskb)->len - iph->ihl*4;
	mangle_contents(*pskb, iph->ihl*4 + tcph->doff*4,
			match_offset, match_len, rep_buffer, rep_len);

	datalen = (*pskb)->len - iph->ihl*4;
	if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
		tcph->check = 0;
		tcph->check = tcp_v4_check(datalen,
					   iph->saddr, iph->daddr,
					   csum_partial((char *)tcph,
							datalen, 0));
	} else
		nf_proto_csum_replace2(&tcph->check, *pskb,
				       htons(oldlen), htons(datalen), 1);

	if (rep_len != match_len) {
		set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
		adjust_tcp_sequence(ntohl(tcph->seq),
				    (int)rep_len - (int)match_len,
				    ct, ctinfo);
		/* Tell TCP window tracking about seq change */
		nf_conntrack_tcp_update(*pskb, (*pskb)->nh.iph->ihl*4,
					ct, CTINFO2DIR(ctinfo));
	}
	return 1;
}
Example #4
0
static int tcf_csum_ipv4_tcp(struct sk_buff *skb, struct iphdr *iph,
			     unsigned int ihl, unsigned int ipl)
{
	struct tcphdr *tcph;

	tcph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*tcph));
	if (tcph == NULL)
		return 0;

	tcph->check = 0;
	skb->csum = csum_partial(tcph, ipl - ihl, 0);
	tcph->check = tcp_v4_check(ipl - ihl,
				   iph->saddr, iph->daddr, skb->csum);

	skb->ip_summed = CHECKSUM_NONE;

	return 1;
}
void tcp_send_check(struct sk_buff *skb) {
	if (skb_is_nonlinear(skb)) {
		skb_linearize(skb);
	}
	struct iphdr *ip_header = ip_hdr(skb);
	struct tcphdr *tcp_header = tcp_hdr(skb);
	unsigned int tcp_header_length = (skb->len - (ip_header->ihl << 2));
	tcp_header->check = 0;
	tcp_header->check = tcp_v4_check(
		tcp_header_length,
		ip_header->saddr,
		ip_header->daddr,
		csum_partial(
			(char*)tcp_header,
			tcp_header_length,
			0
		)
	);
	skb->ip_summed = CHECKSUM_NONE;
}
Example #6
0
static int tcf_csum_ipv4_tcp(struct sk_buff *skb, unsigned int ihl,
			     unsigned int ipl)
{
	struct tcphdr *tcph;
	const struct iphdr *iph;

	if (skb_is_gso(skb) && skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
		return 1;

	tcph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*tcph));
	if (tcph == NULL)
		return 0;

	iph = ip_hdr(skb);
	tcph->check = 0;
	skb->csum = csum_partial(tcph, ipl - ihl, 0);
	tcph->check = tcp_v4_check(ipl - ihl,
				   iph->saddr, iph->daddr, skb->csum);

	skb->ip_summed = CHECKSUM_NONE;

	return 1;
}
Example #7
0
/* Send reply */
static void tarpit_tcp(struct sk_buff *oskb,struct rtable *ort,int local)
{
	struct sk_buff *nskb;
	struct rtable *nrt;
	struct tcphdr *otcph, *ntcph;
	struct flowi fl = {};
	unsigned int otcplen;
	u_int16_t tmp;

	/* A truncated TCP header isn't going to be useful */
	if (oskb->len < (ip_hdr(oskb)->ihl*4) + sizeof(struct tcphdr))
		return;

	otcph = (struct tcphdr *)((u_int32_t*)ip_hdr(oskb)
				  + ip_hdr(oskb)->ihl);
	otcplen = oskb->len - ip_hdr(oskb)->ihl*4;

	/* No replies for RST or FIN */
	if (otcph->rst || otcph->fin)
		return;

	/* No reply to !SYN,!ACK.  Rate-limit replies to !SYN,ACKs */
	if (!otcph->syn && (!otcph->ack || !xrlim_allow(&ort->u.dst, 1*HZ)))
		return;

	/* Check checksum. */
	if (tcp_v4_check(otcplen, ip_hdr(oskb)->saddr,
			 ip_hdr(oskb)->daddr,
			 csum_partial((char *)otcph, otcplen, 0)) != 0)
		return;

	/* Copy skb (even if skb is about to be dropped, we can't just
           clone it because there may be other things, such as tcpdump,
           interested in it) */
	nskb = skb_copy(oskb, GFP_ATOMIC);
	if (!nskb)
		return;

#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
	/* This packet will not be the same as the other: clear nf fields */
	nf_conntrack_put(nskb->nfct);
	nskb->nfct = NULL;
#endif /* CONFIG_NF_CONNTRACK */

	ntcph = (struct tcphdr *)((u_int32_t*)ip_hdr(nskb) + ip_hdr(nskb)->ihl);

	/* Truncate to length (no data) */
	ntcph->doff = sizeof(struct tcphdr)/4;
	skb_trim(nskb, ip_hdr(nskb)->ihl*4 + sizeof(struct tcphdr));
	ip_hdr(nskb)->tot_len = htons(nskb->len);

	/* Swap source and dest */
	ip_hdr(nskb)->daddr = xchg(&ip_hdr(nskb)->saddr, ip_hdr(nskb)->daddr);
	tmp = ntcph->source;
	ntcph->source = ntcph->dest;
	ntcph->dest = tmp;

	/* Use supplied sequence number or make a new one */
	ntcph->seq = otcph->ack ? otcph->ack_seq
		: htonl(secure_tcp_sequence_number(ip_hdr(nskb)->saddr,
						   ip_hdr(nskb)->daddr,
						   ntcph->source,
						   ntcph->dest));

	/* Our SYN-ACKs must have a >0 window */
	ntcph->window = (otcph->syn && !otcph->ack) ? htons(5) : 0;

	ntcph->urg_ptr = 0;

	/* Reset flags */
	((u_int8_t *)ntcph)[13] = 0;

	if (otcph->syn && otcph->ack) {
		ntcph->rst = 1;
		ntcph->ack_seq = 0;
	} else {
		ntcph->syn = otcph->syn;
		ntcph->ack = 1;
		ntcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn);
	}

	/* Adjust TCP checksum */
	ntcph->check = 0;
	ntcph->check = tcp_v4_check(sizeof(struct tcphdr),
				   ip_hdr(nskb)->saddr,
				   ip_hdr(nskb)->daddr,
				   csum_partial((char *)ntcph,
						sizeof(struct tcphdr), 0));

	fl.nl_u.ip4_u.daddr = ip_hdr(nskb)->daddr;
	fl.nl_u.ip4_u.saddr = local ? ip_hdr(nskb)->saddr : 0;
	fl.nl_u.ip4_u.tos = RT_TOS(ip_hdr(nskb)->tos) | RTO_CONN;
	fl.oif = 0;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
	if (ip_route_output_key(&init_net, &nrt, &fl))
#else
	if (ip_route_output_key(&nrt, &fl))
#endif
		goto free_nskb;

	dst_release(nskb->dst);
	nskb->dst = &nrt->u.dst;

	/* Adjust IP TTL */
	ip_hdr(nskb)->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);

	/* Set DF, id = 0 */
	ip_hdr(nskb)->frag_off = htons(IP_DF);
	ip_hdr(nskb)->id = 0;

	/* Adjust IP checksum */
	ip_hdr(nskb)->check = 0;
	ip_hdr(nskb)->check = ip_fast_csum((unsigned char *)ip_hdr(nskb),
					   ip_hdr(nskb)->ihl);

	/* "Never happens" */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
	if (nskb->len > dst_mtu(nskb->dst))
#else
	if (nskb->len > dst_pmtu(nskb->dst))
#endif
		goto free_nskb;

	ip_direct_send (nskb);

	return;

 free_nskb:
	kfree_skb(nskb);
}
Example #8
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;
}
Example #9
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 }});
Example #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 }});
Example #11
0
	datalen = skb->len - iph->ihl*4;
	if (skb->ip_summed != CHECKSUM_PARTIAL) {
		if (!(rt->rt_flags & RTCF_LOCAL) &&
		    skb->dev->features & NETIF_F_V4_CSUM) {
			skb->ip_summed = CHECKSUM_PARTIAL;
			skb->csum_start = skb_headroom(skb) +
					  skb_network_offset(skb) +
					  iph->ihl * 4;
			skb->csum_offset = offsetof(struct tcphdr, check);
			tcph->check = ~tcp_v4_check(datalen,
						    iph->saddr, iph->daddr, 0);
		} else {
			tcph->check = 0;
			tcph->check = tcp_v4_check(datalen,
						   iph->saddr, iph->daddr,
						   csum_partial(tcph,
								datalen, 0));
		}
	} else
		nf_proto_csum_replace2(&tcph->check, skb,
				       htons(oldlen), htons(datalen), 1);

	if (rep_len != match_len) {
		set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
		adjust_tcp_sequence(ntohl(tcph->seq),
				    (int)rep_len - (int)match_len,
				    ct, ctinfo);
		/* Tell TCP window tracking about seq change */
		nf_conntrack_tcp_update(skb, ip_hdrlen(skb),
					ct, CTINFO2DIR(ctinfo));
	}
Example #12
0
/* Send RST reply */
static void send_reset(struct sk_buff *oldskb, int hook)
{
	struct sk_buff *nskb;
	struct iphdr *iph = oldskb->nh.iph;
	struct tcphdr _otcph, *oth, *tcph;
	__be16 tmp_port;
	__be32 tmp_addr;
	int needs_ack;
	unsigned int addr_type;

	/* IP header checks: fragment. */
	if (oldskb->nh.iph->frag_off & htons(IP_OFFSET))
		return;

	oth = skb_header_pointer(oldskb, oldskb->nh.iph->ihl * 4,
				 sizeof(_otcph), &_otcph);
	if (oth == NULL)
 		return;

	/* No RST for RST. */
	if (oth->rst)
		return;

	/* Check checksum */
	if (nf_ip_checksum(oldskb, hook, iph->ihl * 4, IPPROTO_TCP))
		return;

	/* We need a linear, writeable skb.  We also need to expand
	   headroom in case hh_len of incoming interface < hh_len of
	   outgoing interface */
	nskb = skb_copy_expand(oldskb, LL_MAX_HEADER, skb_tailroom(oldskb),
			       GFP_ATOMIC);
	if (!nskb)
		return;

	/* This packet will not be the same as the other: clear nf fields */
	nf_reset(nskb);
	nskb->nfmark = 0;
	skb_init_secmark(nskb);

	tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);

	/* Swap source and dest */
	tmp_addr = nskb->nh.iph->saddr;
	nskb->nh.iph->saddr = nskb->nh.iph->daddr;
	nskb->nh.iph->daddr = tmp_addr;
	tmp_port = tcph->source;
	tcph->source = tcph->dest;
	tcph->dest = tmp_port;

	/* Truncate to length (no data) */
	tcph->doff = sizeof(struct tcphdr)/4;
	skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr));
	nskb->nh.iph->tot_len = htons(nskb->len);

	if (tcph->ack) {
		needs_ack = 0;
		tcph->seq = oth->ack_seq;
		tcph->ack_seq = 0;
	} else {
		needs_ack = 1;
		tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin
				      + oldskb->len - oldskb->nh.iph->ihl*4
				      - (oth->doff<<2));
		tcph->seq = 0;
	}

	/* Reset flags */
	((u_int8_t *)tcph)[13] = 0;
	tcph->rst = 1;
	tcph->ack = needs_ack;

	tcph->window = 0;
	tcph->urg_ptr = 0;

	/* Adjust TCP checksum */
	tcph->check = 0;
	tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr),
				   nskb->nh.iph->saddr,
				   nskb->nh.iph->daddr,
				   csum_partial((char *)tcph,
						sizeof(struct tcphdr), 0));

	/* Set DF, id = 0 */
	nskb->nh.iph->frag_off = htons(IP_DF);
	nskb->nh.iph->id = 0;

	addr_type = RTN_UNSPEC;
	if (hook != NF_IP_FORWARD
#ifdef CONFIG_BRIDGE_NETFILTER
	    || (nskb->nf_bridge && nskb->nf_bridge->mask & BRNF_BRIDGED)
#endif
	   )
		addr_type = RTN_LOCAL;

	if (ip_route_me_harder(&nskb, addr_type))
		goto free_nskb;

	nskb->ip_summed = CHECKSUM_NONE;

	/* Adjust IP TTL */
	nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);

	/* Adjust IP checksum */
	nskb->nh.iph->check = 0;
	nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph, 
					   nskb->nh.iph->ihl);

	/* "Never happens" */
	if (nskb->len > dst_mtu(nskb->dst))
		goto free_nskb;

	nf_ct_attach(nskb, oldskb);

	NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
		dst_output);
	return;

 free_nskb:
	kfree_skb(nskb);
}
Example #13
0
static void tarpit_tcp4(struct net *net, struct sk_buff *oldskb,
    unsigned int hook, unsigned int mode)
{
	struct tcphdr _otcph, *tcph;
	const struct tcphdr *oth;
	unsigned int addr_type = RTN_UNSPEC;
	struct sk_buff *nskb;
	const struct iphdr *oldhdr;
	struct iphdr *niph;
	uint16_t tmp, payload;

	/* A truncated TCP header is not going to be useful */
	if (oldskb->len < ip_hdrlen(oldskb) + sizeof(struct tcphdr))
		return;

	oth = skb_header_pointer(oldskb, ip_hdrlen(oldskb),
	                         sizeof(_otcph), &_otcph);
	if (oth == NULL)
		return;

	/* Check checksum. */
	if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP))
		return;

	/*
	 * Copy skb (even if skb is about to be dropped, we cannot just
	 * clone it because there may be other things, such as tcpdump,
	 * interested in it)
	 */
	nskb = skb_copy_expand(oldskb, LL_MAX_HEADER,
	                       skb_tailroom(oldskb), GFP_ATOMIC);
	if (nskb == NULL)
		return;

	/* This packet will not be the same as the other: clear nf fields */
	nf_reset(nskb);
	skb_nfmark(nskb) = 0;
	skb_init_secmark(nskb);
	skb_shinfo(nskb)->gso_size = 0;
	skb_shinfo(nskb)->gso_segs = 0;
	skb_shinfo(nskb)->gso_type = 0;
	oldhdr = ip_hdr(oldskb);
	tcph = (struct tcphdr *)(skb_network_header(nskb) + ip_hdrlen(nskb));

	/* Swap source and dest */
	niph         = ip_hdr(nskb);
	niph->daddr  = xchg(&niph->saddr, niph->daddr);
	tmp          = tcph->source;
	tcph->source = tcph->dest;
	tcph->dest   = tmp;

	/* Calculate payload size?? */
	payload = nskb->len - ip_hdrlen(nskb) - sizeof(struct tcphdr);

	/* Truncate to length (no data) */
	tcph->doff    = sizeof(struct tcphdr) / 4;
	skb_trim(nskb, ip_hdrlen(nskb) + sizeof(struct tcphdr));
	niph->tot_len = htons(nskb->len);
	tcph->urg_ptr = 0;
	/* Reset flags */
	((u_int8_t *)tcph)[13] = 0;

	if (!tarpit_generic(tcph, oth, payload, mode))
		goto free_nskb;

	/* Adjust TCP checksum */
	tcph->check = 0;
	tcph->check = tcp_v4_check(sizeof(struct tcphdr), niph->saddr,
	              niph->daddr, csum_partial((char *)tcph,
	              sizeof(struct tcphdr), 0));

	/* Set DF, id = 0 */
	niph->frag_off = htons(IP_DF);
	if (mode == XTTARPIT_TARPIT || mode == XTTARPIT_RESET)
		niph->id = 0;
	else if (mode == XTTARPIT_HONEYPOT)
		niph->id = ~oldhdr->id + 1;

#ifdef CONFIG_BRIDGE_NETFILTER
	if (hook != NF_INET_FORWARD || (nskb->nf_bridge != NULL &&
	    nskb->nf_bridge->physoutdev != NULL))
#else
	if (hook != NF_INET_FORWARD)
#endif
		addr_type = RTN_LOCAL;

	if (ip_route_me_harder(net, nskb, addr_type))
		goto free_nskb;
	else
		niph = ip_hdr(nskb);

	nskb->ip_summed = CHECKSUM_NONE;

	/* Adjust IP TTL */
	if (mode == XTTARPIT_HONEYPOT)
		niph->ttl = 128;
	else
		niph->ttl = ip4_dst_hoplimit(skb_dst(nskb));

	/* Adjust IP checksum */
	niph->check = 0;
	niph->check = ip_fast_csum(skb_network_header(nskb), niph->ihl);

	/* "Never happens" */
	if (nskb->len > dst_mtu(skb_dst(nskb)))
		goto free_nskb;

	nf_ct_attach(nskb, oldskb);
	NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, net, nskb->sk, nskb, NULL,
		skb_dst(nskb)->dev, dst_output);
	return;

 free_nskb:
	kfree_skb(nskb);
}
Example #14
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,
Example #15
0
/* Send RST reply */
static void send_reset(struct sk_buff *oldskb, int hook)
{
	struct sk_buff *nskb;
	struct tcphdr _otcph, *oth, *tcph;
	struct rtable *rt;
	u_int16_t tmp_port;
	u_int32_t tmp_addr;
	int needs_ack;
	int hh_len;

	/* IP header checks: fragment. */
	if (oldskb->nh.iph->frag_off & htons(IP_OFFSET))
		return;

	oth = skb_header_pointer(oldskb, oldskb->nh.iph->ihl * 4,
				 sizeof(_otcph), &_otcph);
	if (oth == NULL)
 		return;

	/* No RST for RST. */
	if (oth->rst)
		return;

	/* FIXME: Check checksum --RR */
	if ((rt = route_reverse(oldskb, oth, hook)) == NULL)
		return;

	hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);

	/* We need a linear, writeable skb.  We also need to expand
	   headroom in case hh_len of incoming interface < hh_len of
	   outgoing interface */
	nskb = skb_copy_expand(oldskb, hh_len, skb_tailroom(oldskb),
			       GFP_ATOMIC);
	if (!nskb) {
		dst_release(&rt->u.dst);
		return;
	}

	dst_release(nskb->dst);
	nskb->dst = &rt->u.dst;

	/* This packet will not be the same as the other: clear nf fields */
	nf_reset(nskb);
	nskb->nfcache = 0;
	nskb->nfmark = 0;
#ifdef CONFIG_BRIDGE_NETFILTER
	nf_bridge_put(nskb->nf_bridge);
	nskb->nf_bridge = NULL;
#endif

	tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);

	/* Swap source and dest */
	tmp_addr = nskb->nh.iph->saddr;
	nskb->nh.iph->saddr = nskb->nh.iph->daddr;
	nskb->nh.iph->daddr = tmp_addr;
	tmp_port = tcph->source;
	tcph->source = tcph->dest;
	tcph->dest = tmp_port;

	/* Truncate to length (no data) */
	tcph->doff = sizeof(struct tcphdr)/4;
	skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr));
	nskb->nh.iph->tot_len = htons(nskb->len);

	if (tcph->ack) {
		needs_ack = 0;
		tcph->seq = oth->ack_seq;
		tcph->ack_seq = 0;
	} else {
		needs_ack = 1;
		tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin
				      + oldskb->len - oldskb->nh.iph->ihl*4
				      - (oth->doff<<2));
		tcph->seq = 0;
	}

	/* Reset flags */
	((u_int8_t *)tcph)[13] = 0;
	tcph->rst = 1;
	tcph->ack = needs_ack;

	tcph->window = 0;
	tcph->urg_ptr = 0;

	/* Adjust TCP checksum */
	tcph->check = 0;
	tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr),
				   nskb->nh.iph->saddr,
				   nskb->nh.iph->daddr,
				   csum_partial((char *)tcph,
						sizeof(struct tcphdr), 0));

	/* Adjust IP TTL, DF */
	nskb->nh.iph->ttl = MAXTTL;
	/* Set DF, id = 0 */
	nskb->nh.iph->frag_off = htons(IP_DF);
	nskb->nh.iph->id = 0;

	/* Adjust IP checksum */
	nskb->nh.iph->check = 0;
	nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph, 
					   nskb->nh.iph->ihl);

	/* "Never happens" */
	if (nskb->len > dst_pmtu(nskb->dst))
		goto free_nskb;

	nf_ct_attach(nskb, oldskb);

	NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
		ip_finish_output);
	return;

 free_nskb:
	kfree_skb(nskb);
}
Example #16
0
inline unsigned int modifyIpHdr(const char *fn, struct sk_buff *skb)
{
	struct iphdr *iph = ip_hdr(skb);
	//struct tcphdr *tcph = tcp_hdr(skb);  // not valid
	//http://www.linuxquestions.org/questions/programming-9/tcp-checksum-calculation-4175416394/
	struct tcphdr *tcph = (void *)(skb_network_header(skb) + iph->ihl * 4); // Gets the TCP header
	int tcplen;
	static int tcpwin_old=0;

	//(1) list the origin content of skb
	//printk(KERN_ALERT "---------------------------------\n");
	//printk(KERN_ALERT "%s, saddr:%pI4:%hu, daddr:%pI4:%hu\n", fn, &iph->saddr, ntohs(tcph->source), &iph->daddr, ntohs(tcph->dest));

	//(2) filter 'ACK' package
	//tcp_header :
	//http://www.cse.scu.edu/~dclark/am_256_graph_theory/linux_2_6_stack/linux_2tcp_8h-source.html
	//printk(KERN_ALERT "ACK:%d\n", tcph->ack);
	//printk(KERN_ALERT "SYN:%d\n", tcph->syn);
	//printk(KERN_ALERT "FIN:%d\n", tcph->fin);
	//printk(KERN_ALERT "PSH:%d\n", tcph->psh);

	//(2a) skip syn+ack or fin+ack
	// ack+psh : TLSv1.2 (SSL) data transfer
	//if (tcph->syn || tcph->fin || tcph->psh )
	if (tcph->syn || tcph->fin )
		return NF_ACCEPT;

	//(2b) ACK packet to request data usually have less than 33 tcp length
	//printk(KERN_ALERT "[tcp_win]:%d\n", ntohs(tcph->window));
	//printk(KERN_ALERT "[tcp_win_old]:%d\n", tcpwin_old);
	tcplen = (skb->len - (iph->ihl << 2));
	//printk(KERN_ALERT "[tcp_len]:%d\n", tcplen);
	//printk(KERN_ALERT "[skb_len]:%d\n", skb->len);
	if( tcplen > 33 || tcph->window == 0 )
		return NF_ACCEPT;

	//(2c) if the win size of request packet is less than previous one, 
	//       skip this modifying !
	//     it means this packet is the final one of a fragmented packet
	//       or flow control make this frangmented packet size lower
	if( tcpwin_old >= ntohs(tcph->window) )
	{
		tcpwin_old= ntohs(tcph->window);
		return NF_ACCEPT;
	}
	tcpwin_old= ntohs(tcph->window);

	//(3) modify package
	// http://stackoverflow.com/questions/8237983/packet-processing-in-netfilter-hooks
	//printk(KERN_ALERT "[advertise win_old]:%hu\n", ntohs(tcph->window));
	//printk(KERN_ALERT "[tcp_win]:edit 0x??ff\n");
	//tcph->window = htons(0xffff);
	// new_win always is the 3/4 of recv_buff
	// http://notes.yuwh.net/linux-protocol-stack-8-tcp_select_window/
	// 2048:upgrade the win size of the initial packet (default slow start)
	tcph->window = tcph->window+ htons((tcph->window>>2)+2048);
	//printk(KERN_ALERT "[advertise win_new]:%hu\n", ntohs(tcph->window));

	//(4) calculate new checksum
	// http://www.spinics.net/lists/newbies/msg49938.html

	// after linearize, obtain new pointer position
	// http://stackoverflow.com/questions/16610989/calculating-tcp-checksum-in-a-netfilter-module
	if( skb_linearize(skb)<0 ){
		//printk("[POLIMI] Not Linearizable \n");
		return NF_DROP;
	}
	tcph = (void *)(skb_network_header(skb) + iph->ihl * 4);
	iph = ip_hdr(skb);	

	/* tcp checksum */
	//printk(KERN_ALERT "[tcp_check_old]:%d\n", tcph->check);
	tcplen = (skb->len - (iph->ihl << 2)); //tcplen is the length of the skb - the ip-header length 
	tcph->check = 0; //This must be zero to be able to calculate it with csum above.
	tcph->check = tcp_v4_check(tcplen,
                                iph->saddr,
                                iph->daddr,
                                csum_partial((char*) tcph, tcplen, 0));
	//printk(KERN_ALERT "[tcp_check_new]:%d\n", tcph->check);
	/* IP Checksum */
	iph->check = htons(0);
	iph->check = ip_fast_csum((unsigned char *) iph,iph->ihl);

	return NF_ACCEPT;
}
Example #17
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,
Example #18
0
/* Send RST reply */
static void send_reset(struct sk_buff *oldskb, int hook)
{
	struct sk_buff *nskb;
	const struct iphdr *oiph;
	struct iphdr *niph;
	const struct tcphdr *oth;
	struct tcphdr _otcph, *tcph;
	unsigned int addr_type;

	/* IP header checks: fragment. */
	if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET))
		return;

	oth = skb_header_pointer(oldskb, ip_hdrlen(oldskb),
				 sizeof(_otcph), &_otcph);
	if (oth == NULL)
		return;

	/* No RST for RST. */
	if (oth->rst)
		return;

	/* Check checksum */
	if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP))
		return;
	oiph = ip_hdr(oldskb);

	nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) +
			 LL_MAX_HEADER, GFP_ATOMIC);
	if (!nskb)
		return;

	skb_reserve(nskb, LL_MAX_HEADER);

	skb_reset_network_header(nskb);
	niph = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr));
	niph->version	= 4;
	niph->ihl	= sizeof(struct iphdr) / 4;
	niph->tos	= 0;
	niph->id	= 0;
	niph->frag_off	= htons(IP_DF);
	niph->protocol	= IPPROTO_TCP;
	niph->check	= 0;
	niph->saddr	= oiph->daddr;
	niph->daddr	= oiph->saddr;

	tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
	memset(tcph, 0, sizeof(*tcph));
	tcph->source	= oth->dest;
	tcph->dest	= oth->source;
	tcph->doff	= sizeof(struct tcphdr) / 4;

	if (oth->ack)
		tcph->seq = oth->ack_seq;
	else {
		tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin +
				      oldskb->len - ip_hdrlen(oldskb) -
				      (oth->doff << 2));
		tcph->ack = 1;
	}

	tcph->rst	= 1;
	tcph->check	= tcp_v4_check(sizeof(struct tcphdr),
				       niph->saddr, niph->daddr,
				       csum_partial(tcph,
						    sizeof(struct tcphdr), 0));

	addr_type = RTN_UNSPEC;
	if (hook != NF_INET_FORWARD
#ifdef CONFIG_BRIDGE_NETFILTER
	    || (nskb->nf_bridge && nskb->nf_bridge->mask & BRNF_BRIDGED)
#endif
	   )
		addr_type = RTN_LOCAL;

	/* ip_route_me_harder expects skb->dst to be set */
	skb_dst_set(nskb, dst_clone(skb_dst(oldskb)));

	if (ip_route_me_harder(nskb, addr_type))
		goto free_nskb;

	niph->ttl	= dst_metric(skb_dst(nskb), RTAX_HOPLIMIT);
	nskb->ip_summed = CHECKSUM_NONE;

	/* "Never happens" */
	if (nskb->len > dst_mtu(skb_dst(nskb)))
		goto free_nskb;

	nf_ct_attach(nskb, oldskb);

	ip_local_out(nskb);
	return;

 free_nskb:
	kfree_skb(nskb);
}
Example #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 guaranteed by ip_conntrack_tcp.c */
	struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
	unsigned int tcplen = iph->tot_len - iph->ihl * 4;
//	int dir = CTINFO2DIR(ctinfo);
	struct pptp_pkt_hdr		*pptph;
	pptph = (struct pptp_pkt_hdr *) ((char *) iph + sizeof(struct iphdr) + sizeof(struct tcphdr));

	/* 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("pptp: Conntrackinfo = %u\n", ctinfo);
		return NF_ACCEPT;
	}

	/* If we get a FIN or RST, this connection's going down, and so is */
	/* the GRE tunnel. Deal. */
	if (tcph->rst || tcph->fin) {
		DEBUGP("pptp: bringing down gre connection.\n");
		delete_connection(ct, ctinfo);
	}
	
	/* Not whole TCP header? */
	if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff*4) {
		DEBUGP("pptp: 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("pptp_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
		       tcph, tcplen, NIPQUAD(iph->saddr),
		       NIPQUAD(iph->daddr));

		/* WHAT?!?  Win2k seems to send OUT_CALL_REQ packets with bogus checksums...
	 	 */
		/* return NF_ACCEPT; */
	}

	/* verify we have data (i.e. pptph points before end of packet) */
	if ((void *) pptph >= (void *) ((iph) + len)) {
		DEBUGP("pptp_help(): no TCP data in pkt\n");
		return NF_ACCEPT;
	}

	/* if it's not a control message we can't do anything with it */
        if (ntohs(pptph->packetType) != PPTP_CONTROL_PACKET ||
	    ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
		DEBUGP("pptp_help(): not a control pkt\n");
		return NF_ACCEPT;
	}

	if(ctinfo >= IP_CT_IS_REPLY)
		ip_inbound_pptp_tcp(iph, ct, ctinfo);
	else
		ip_outbound_pptp_tcp(iph, ct, ctinfo);

	return NF_ACCEPT;
}
Example #20
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;
}
Example #21
0
/* Send RST reply */
static void send_reset(struct sk_buff *oldskb, int hook)
{
	struct sk_buff *nskb;
	struct tcphdr *otcph, *tcph;
	struct rtable *rt;
	unsigned int otcplen;
	u_int16_t tmp_port;
	u_int32_t tmp_addr;
	int needs_ack;
	int hh_len;

	/* IP header checks: fragment, too short. */
	if (oldskb->nh.iph->frag_off & htons(IP_OFFSET)
	    || oldskb->len < (oldskb->nh.iph->ihl<<2) + sizeof(struct tcphdr))
		return;

	otcph = (struct tcphdr *)((u_int32_t*)oldskb->nh.iph + oldskb->nh.iph->ihl);
	otcplen = oldskb->len - oldskb->nh.iph->ihl*4;

	/* No RST for RST. */
	if (otcph->rst)
		return;

	/* Check checksum. */
	if (tcp_v4_check(otcph, otcplen, oldskb->nh.iph->saddr,
			 oldskb->nh.iph->daddr,
			 csum_partial((char *)otcph, otcplen, 0)) != 0)
		return;

	if ((rt = route_reverse(oldskb, hook)) == NULL)
		return;

	hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;


	/* Copy skb (even if skb is about to be dropped, we can't just
           clone it because there may be other things, such as tcpdump,
           interested in it). We also need to expand headroom in case
	   hh_len of incoming interface < hh_len of outgoing interface */
	nskb = skb_copy_expand(oldskb, hh_len, skb_tailroom(oldskb),
			       GFP_ATOMIC);
	if (!nskb) {
		dst_release(&rt->u.dst);
		return;
	}

	dst_release(nskb->dst);
	nskb->dst = &rt->u.dst;

	/* This packet will not be the same as the other: clear nf fields */
	nf_reset(nskb);
	nskb->nfcache = 0;
	nskb->nfmark = 0;

	tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);

	/* Swap source and dest */
	tmp_addr = nskb->nh.iph->saddr;
	nskb->nh.iph->saddr = nskb->nh.iph->daddr;
	nskb->nh.iph->daddr = tmp_addr;
	tmp_port = tcph->source;
	tcph->source = tcph->dest;
	tcph->dest = tmp_port;

	/* Truncate to length (no data) */
	tcph->doff = sizeof(struct tcphdr)/4;
	skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr));
	nskb->nh.iph->tot_len = htons(nskb->len);

	if (tcph->ack) {
		needs_ack = 0;
		tcph->seq = otcph->ack_seq;
		tcph->ack_seq = 0;
	} else {
		needs_ack = 1;
		tcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn + otcph->fin
				      + otcplen - (otcph->doff<<2));
		tcph->seq = 0;
	}

	/* Reset flags */
	((u_int8_t *)tcph)[13] = 0;
	tcph->rst = 1;
	tcph->ack = needs_ack;

	tcph->window = 0;
	tcph->urg_ptr = 0;

	/* Adjust TCP checksum */
	tcph->check = 0;
	tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr),
				   nskb->nh.iph->saddr,
				   nskb->nh.iph->daddr,
				   csum_partial((char *)tcph,
						sizeof(struct tcphdr), 0));

	/* Adjust IP TTL, DF */
	nskb->nh.iph->ttl = MAXTTL;
	/* Set DF, id = 0 */
	nskb->nh.iph->frag_off = htons(IP_DF);
	nskb->nh.iph->id = 0;

	/* Adjust IP checksum */
	nskb->nh.iph->check = 0;
	nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph, 
					   nskb->nh.iph->ihl);

	/* "Never happens" */
	if (nskb->len > nskb->dst->pmtu)
		goto free_nskb;

	nf_ct_attach(nskb, oldskb);

	NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
		ip_finish_output);
	return;

 free_nskb:
	kfree_skb(nskb);
}