static int
udp_match(const struct sk_buff *skb,
	  const struct net_device *in,
	  const struct net_device *out,
	  const struct xt_match *match,
	  const void *matchinfo,
	  int offset,
	  unsigned int protoff,
	  int *hotdrop)
{
	struct udphdr _udph, *uh;
	const struct xt_udp *udpinfo = matchinfo;

	/* Must not be a fragment. */
	if (offset)
		return 0;

	uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph);
	if (uh == NULL) {
		/* We've been asked to examine this packet, and we
		   can't.  Hence, no choice but to drop. */
		duprintf("Dropping evil UDP tinygram.\n");
		*hotdrop = 1;
		return 0;
	}

	return port_match(udpinfo->spts[0], udpinfo->spts[1],
			  ntohs(uh->source),
			  !!(udpinfo->invflags & XT_UDP_INV_SRCPT))
		&& port_match(udpinfo->dpts[0], udpinfo->dpts[1],
			      ntohs(uh->dest),
			      !!(udpinfo->invflags & XT_UDP_INV_DSTPT));
}
static bool udp_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
	const struct udphdr *uh;
	struct udphdr _udph;
	const struct xt_udp *udpinfo = par->matchinfo;

	/* Must not be a fragment. */
	if (par->fragoff != 0)
		return false;

	uh = skb_header_pointer(skb, par->thoff, sizeof(_udph), &_udph);
	if (uh == NULL) {
		/* We've been asked to examine this packet, and we
		   can't.  Hence, no choice but to drop. */
		pr_debug("Dropping evil UDP tinygram.\n");
		par->hotdrop = true;
		return false;
	}

	return port_match(udpinfo->spts[0], udpinfo->spts[1],
			  ntohs(uh->source),
			  !!(udpinfo->invflags & XT_UDP_INV_SRCPT))
		&& port_match(udpinfo->dpts[0], udpinfo->dpts[1],
			      ntohs(uh->dest),
			      !!(udpinfo->invflags & XT_UDP_INV_DSTPT));
}
static bool tcp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
{
	const struct tcphdr *th;
	struct tcphdr _tcph;
	const struct xt_tcp *tcpinfo = par->matchinfo;

	if (par->fragoff != 0) {
		/* To quote Alan:

		   Don't allow a fragment of TCP 8 bytes in. Nobody normal
		   causes this. Its a cracker trying to break in by doing a
		   flag overwrite to pass the direction checks.
		*/
		if (par->fragoff == 1) {
			pr_debug("Dropping evil TCP offset=1 frag.\n");
			*par->hotdrop = true;
		}
		/* Must not be a fragment. */
		return false;
	}

#define FWINVTCP(bool, invflg) ((bool) ^ !!(tcpinfo->invflags & (invflg)))

	th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph);
	if (th == NULL) {
		/* We've been asked to examine this packet, and we
		   can't.  Hence, no choice but to drop. */
		pr_debug("Dropping evil TCP offset=0 tinygram.\n");
		*par->hotdrop = true;
		return false;
	}

	if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
			ntohs(th->source),
			!!(tcpinfo->invflags & XT_TCP_INV_SRCPT)))
		return false;
	if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
			ntohs(th->dest),
			!!(tcpinfo->invflags & XT_TCP_INV_DSTPT)))
		return false;
	if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
		      == tcpinfo->flg_cmp,
		      XT_TCP_INV_FLAGS))
		return false;
	if (tcpinfo->option) {
		if (th->doff * 4 < sizeof(_tcph)) {
			*par->hotdrop = true;
			return false;
		}
		if (!tcp_find_option(tcpinfo->option, skb, par->thoff,
				     th->doff*4 - sizeof(_tcph),
				     tcpinfo->invflags & XT_TCP_INV_OPTION,
				     par->hotdrop))
			return false;
	}
	return true;
}
Exemple #4
0
static void
deps_diff_inv (struct hs *hs, uint32_t port, const struct deps *deps,
	       const struct tf *tf)
{
  for (int i = 0; i < deps->n; i++) {
    const struct dep *dep = &deps->deps[i];
    if (dep->port > 0 && dep->port != port) continue;
    if (dep->port < 0 && !port_match (port, dep->port, tf)) continue;
    hs_diff (hs, DATA_ARR (dep->match));
  }
}
Exemple #5
0
Fichier : tf.c Projet : NetSys/sts
static void
deps_diff (struct hs *hs, uint32_t port, const struct deps *deps,
           const struct tf *tf, const uint32_t *app, int napp)
{
  for (int i = 0; i < deps->n; i++) {
    const struct dep *dep = &deps->deps[i];
    if (app && !int_find (dep->rule, app, napp)) continue;
    if (dep->port > 0 && dep->port != port) continue;
    if (dep->port < 0 && !port_match (port, dep->port, tf)) continue;
    hs_diff (hs, DATA_ARR (dep->match));
  }
}
Exemple #6
0
static struct user_cap *user_db_get_pref(	const struct passwd *pw,
											in_port_t lport,
											in_port_t fport,
											struct sockaddr_storage *laddr,
											struct sockaddr_storage *faddr)
{
	list_t *cap_list;
	list_t *cur;

	cap_list = user_db_get_pref_list(pw);

	for (cur = cap_list ; cur != NULL ; cur = cur->next) {
		struct user_cap *cur_cap = cur->data;

		if (port_match(lport, cur_cap->lport) == false)
			continue;

		if (port_match(fport, cur_cap->fport) == false)
			continue;

		if (addr_match(laddr, cur_cap->src) == false)
			continue;

		if (addr_match(faddr, cur_cap->dest) == false)
			continue;

		/*
		** Don't let list_destroy destroy this one.
		*/
		cur->data = NULL;

		list_destroy(cap_list, user_db_cap_destroy_data);
		return (cur_cap);
	}

	list_destroy(cap_list, user_db_cap_destroy_data);
	return (NULL);
}
Exemple #7
0
struct list_res
rule_inv_apply (const struct tf *tf, const struct rule *r, const struct res *in,
		bool append)
{
  /* Given a rule `r` in a tf `tf`, apply the inverse of `r` on the input
     (headerspace,port) `in`. */
  struct list_res res = {0};

  // prune cases where rule outport doesn't include the current port
  if (r->out > 0 && r->out != in->port) return res;
  if (r->out < 0 && !port_match(in->port, r->out, tf)) return res;
  if (!r->out) return res;

  // set up inverse match and rewrite arrays
  array_t *inv_rw=0, *inv_mat=0;
  if (r->mask) { // rewrite rule
    inv_mat = rule_set_inv_mat (r, in->hs.len);
    inv_rw  = rule_set_inv_rw (r, in->hs.len);
  }
  else { // fwding and topology rules
    if (r->match) inv_mat = array_copy (DATA_ARR (r->match), in->hs.len);
  }

  struct hs hs;
  if (!r->match) hs_copy (&hs, &in->hs); // topology rule
  else { // fwding and rewrite rules
    if (!hs_isect_arr (&hs, &in->hs, inv_mat)) return res;
    if (r->mask) hs_rewrite (&hs, DATA_ARR (r->mask), inv_rw);
  }

  // there is a new hs result corresponding to each rule inport
  bool used_hs = port_append_res (&res, r, tf, in, r->in, append, &hs, true);

  if (inv_rw) array_free (inv_rw);
  if (inv_mat) array_free (inv_mat);
  if (!used_hs) hs_destroy (&hs);

  return res;
}
Exemple #8
0
static int
match_cookie(ParsedURL *pu, struct cookie *cookie, char *domainname)
{
    if (!domainname)
	return 0;

    if (!domain_match(domainname, cookie->domain->ptr))
	return 0;
    if (strncmp(cookie->path->ptr, pu->file, cookie->path->length) != 0)
	return 0;
#ifdef USE_SSL
    if (cookie->flag & COO_SECURE && pu->scheme != SCM_HTTPS)
	return 0;
#else				/* not USE_SSL */
    if (cookie->flag & COO_SECURE)
	return 0;
#endif				/* not USE_SSL */
    if (cookie->portl && !port_match(cookie->portl, pu->port))
	return 0;

    return 1;
}
Exemple #9
0
Fichier : tf.c Projet : NetSys/sts
struct list_res
tf_apply (const struct tf *tf, const struct res *in, bool append)
{
  assert (in->hs.len == data_arrs_len);
  uint32_t app[MAX_APP];
  int napp = 0;
  struct list_res res = {0};

  const struct port_map_elem *rules = rule_get (tf, in->port);
  if (!rules) return res;

  if (rules->start != UINT32_MAX) {
    for (uint32_t cur = rules->start; cur < tf->nrules; cur++) {
      const struct rule *r = &tf->rules[cur];
      assert (r->in > 0);
      if (r->in != in->port) break;

      struct list_res tmp;
      tmp = rule_apply (r, tf, in, append, app, &napp);
      list_concat (&res, &tmp);
    }
  }

  /* Check all rules with multiple ports. */
  for (int i = 0; i < tf->nrules; i++) {
    const struct rule *r = &tf->rules[i];
    if (r->in >= 0) break;
    if (!port_match (in->port, r->in, tf)) continue;

    struct list_res tmp;
    tmp = rule_apply (r, tf, in, append, app, &napp);
    list_concat (&res, &tmp);
  }

  return res;
}
Exemple #10
0
int ip_fw_chk(struct iphdr *ip, struct device *rif, __u16 *redirport, struct ip_fw *chain, int policy, int mode)
{
	struct ip_fw *f;
	struct tcphdr		*tcp=(struct tcphdr *)((__u32 *)ip+ip->ihl);
	struct udphdr		*udp=(struct udphdr *)((__u32 *)ip+ip->ihl);
	struct icmphdr		*icmp=(struct icmphdr *)((__u32 *)ip+ip->ihl);
	__u32			src, dst;
	__u16			src_port=0xFFFF, dst_port=0xFFFF, icmp_type=0xFF;
	unsigned short		f_prt=0, prt;
	char			notcpsyn=0, notcpack=0, match;
	unsigned short		offset;
	int			answer;
	unsigned char		tosand, tosxor;

	/*
	 *	If the chain is empty follow policy. The BSD one
	 *	accepts anything giving you a time window while
	 *	flushing and rebuilding the tables.
	 */
	 
	src = ip->saddr;
	dst = ip->daddr;

	/* 
	 *	This way we handle fragmented packets.
	 *	we ignore all fragments but the first one
	 *	so the whole packet can't be reassembled.
	 *	This way we relay on the full info which
	 *	stored only in first packet.
	 *
	 *	Note that this theoretically allows partial packet
	 *	spoofing. Not very dangerous but paranoid people may
	 *	wish to play with this. It also allows the so called
	 *	"fragment bomb" denial of service attack on some types
	 *	of system.
	 */

	offset = ntohs(ip->frag_off) & IP_OFFSET;
	
	/*
	 *	Don't allow a fragment of TCP 8 bytes in. Nobody
	 *	normal causes this. Its a cracker trying to break
	 *	in by doing a flag overwrite to pass the direction
	 *	checks.
	 */
	 
	if (offset == 1 && ip->protocol == IPPROTO_TCP)
		return FW_BLOCK;
		
	if (offset!=0 && !(mode & (IP_FW_MODE_ACCT_IN|IP_FW_MODE_ACCT_OUT)) &&
		(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP ||
			ip->protocol == IPPROTO_ICMP))
		return FW_ACCEPT;
		
	/*
	 *	 Header fragment for TCP is too small to check the bits.
	 */
	 
	if(ip->protocol==IPPROTO_TCP && (ip->ihl<<2)+16 > ntohs(ip->tot_len))
		return FW_BLOCK;
	
	/*
	 *	Too short.
	 *
	 *	But only too short for a packet with ports...
	 */
	 
	else if((ntohs(ip->tot_len)<8+(ip->ihl<<2))&&(ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP))
		return FW_BLOCK;
		
	src = ip->saddr;
	dst = ip->daddr;

	/*
	 *	If we got interface from which packet came
	 *	we can use the address directly. This is unlike
	 *	4.4BSD derived systems that have an address chain
	 *	per device. We have a device per address with dummy
	 *	devices instead.
	 */
	 
	dprintf1("Packet ");
	switch(ip->protocol) 
	{
		case IPPROTO_TCP:
			dprintf1("TCP ");
			/* ports stay 0xFFFF if it is not the first fragment */
			if (!offset) {
				src_port=ntohs(tcp->source);
				dst_port=ntohs(tcp->dest);
				if(!tcp->ack && !tcp->rst)
					/* We do NOT have ACK, value TRUE */
					notcpack=1;
				if(!tcp->syn || !notcpack)
					/* We do NOT have SYN, value TRUE */
					notcpsyn=1;
			}
			prt=IP_FW_F_TCP;
			break;
		case IPPROTO_UDP:
			dprintf1("UDP ");
			/* ports stay 0xFFFF if it is not the first fragment */
			if (!offset) {
				src_port=ntohs(udp->source);
				dst_port=ntohs(udp->dest);
			}
			prt=IP_FW_F_UDP;
			break;
		case IPPROTO_ICMP:
			/* icmp_type stays 255 if it is not the first fragment */
			if (!offset)
				icmp_type=(__u16)(icmp->type);
			dprintf2("ICMP:%d ",icmp_type);
			prt=IP_FW_F_ICMP;
			break;
		default:
			dprintf2("p=%d ",ip->protocol);
			prt=IP_FW_F_ALL;
			break;
	}
#ifdef DEBUG_IP_FIREWALL
	dprint_ip(ip->saddr);
	
	if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP)
		/* This will print 65535 when it is not the first fragment! */
		dprintf2(":%d ", src_port);
	dprint_ip(ip->daddr);
	if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP)
		/* This will print 65535 when it is not the first fragment! */
		dprintf2(":%d ",dst_port);
	dprintf1("\n");
#endif	

	for (f=chain;f;f=f->fw_next) 
	{
		/*
		 *	This is a bit simpler as we don't have to walk
		 *	an interface chain as you do in BSD - same logic
		 *	however.
		 */

		/*
		 *	Match can become 0x01 (a "normal" match was found),
		 *	0x02 (a reverse match was found), and 0x03 (the
		 *	IP addresses match in both directions).
		 *	Now we know in which direction(s) we should look
		 *	for a match for the TCP/UDP ports.  Both directions
		 *	might match (e.g., when both addresses are on the
		 *	same network for which an address/mask is given), but
		 *	the ports might only match in one direction.
		 *	This was obviously wrong in the original BSD code.
		 */
		match = 0x00;

		if ((src&f->fw_smsk.s_addr)==f->fw_src.s_addr
		&&  (dst&f->fw_dmsk.s_addr)==f->fw_dst.s_addr)
			/* normal direction */
			match |= 0x01;

		if ((f->fw_flg & IP_FW_F_BIDIR) &&
		    (dst&f->fw_smsk.s_addr)==f->fw_src.s_addr
		&&  (src&f->fw_dmsk.s_addr)==f->fw_dst.s_addr)
			/* reverse direction */
			match |= 0x02;

		if (!match)
			continue;

		/*
		 *	Look for a VIA address match 
		 */
		if(f->fw_via.s_addr && rif)
		{
			if(rif->pa_addr!=f->fw_via.s_addr)
				continue;	/* Mismatch */
		}

		/*
		 *	Look for a VIA device match 
		 */
		if(f->fw_viadev)
		{
			if(rif!=f->fw_viadev)
				continue;	/* Mismatch */
		}

		/*
		 *	Ok the chain addresses match.
		 */

#ifdef CONFIG_IP_ACCT
		/*
		 *	See if we're in accounting mode and only want to
		 *	count incoming or outgoing packets.
		 */

		if (mode & (IP_FW_MODE_ACCT_IN|IP_FW_MODE_ACCT_OUT) &&
		   ((mode == IP_FW_MODE_ACCT_IN && f->fw_flg&IP_FW_F_ACCTOUT) ||
		    (mode == IP_FW_MODE_ACCT_OUT && f->fw_flg&IP_FW_F_ACCTIN)))
			continue;

#endif
		/*
		 * For all non-TCP packets and/or non-first fragments,
		 * notcpsyn and notcpack will always be FALSE,
		 * so the IP_FW_F_TCPSYN and IP_FW_F_TCPACK flags
		 * are actually ignored for these packets.
		 */
		 
		if((f->fw_flg&IP_FW_F_TCPSYN) && notcpsyn)
		 	continue;

		if((f->fw_flg&IP_FW_F_TCPACK) && notcpack)
		 	continue;

		f_prt=f->fw_flg&IP_FW_F_KIND;
		if (f_prt!=IP_FW_F_ALL) 
		{
			/*
			 *	Specific firewall - packet's protocol
			 *	must match firewall's.
			 */

			if(prt!=f_prt)
				continue;
				
			if((prt==IP_FW_F_ICMP &&
				! port_match(&f->fw_pts[0], f->fw_nsp,
					icmp_type,f->fw_flg&IP_FW_F_SRNG)) ||
			    !(prt==IP_FW_F_ICMP || ((match & 0x01) &&
				port_match(&f->fw_pts[0], f->fw_nsp, src_port,
					f->fw_flg&IP_FW_F_SRNG) &&
				port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, dst_port,
					f->fw_flg&IP_FW_F_DRNG)) || ((match & 0x02) &&
				port_match(&f->fw_pts[0], f->fw_nsp, dst_port,
					f->fw_flg&IP_FW_F_SRNG) &&
				port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, src_port,
					f->fw_flg&IP_FW_F_DRNG))))
			{
				continue;
			}
		}

#ifdef CONFIG_IP_FIREWALL_VERBOSE
		/*
		 * VERY ugly piece of code which actually
		 * makes kernel printf for matching packets...
		 */

		if (f->fw_flg & IP_FW_F_PRN)
		{
			__u32 *opt = (__u32 *) (ip + 1);
			int opti;

			if(mode == IP_FW_MODE_ACCT_IN)
				printk(KERN_INFO "IP acct in ");
			else if(mode == IP_FW_MODE_ACCT_OUT)
				printk(KERN_INFO "IP acct out ");
			else {
				if(chain == ip_fw_fwd_chain)
					printk(KERN_INFO "IP fw-fwd ");
				else if(chain == ip_fw_in_chain)
					printk(KERN_INFO "IP fw-in ");
				else
					printk(KERN_INFO "IP fw-out ");
				if(f->fw_flg&IP_FW_F_ACCEPT) {
					if(f->fw_flg&IP_FW_F_REDIR)
						printk("acc/r%d ", f->fw_pts[f->fw_nsp+f->fw_ndp]);
					else if(f->fw_flg&IP_FW_F_MASQ)
						printk("acc/masq ");
					else
						printk("acc ");
				} else if(f->fw_flg&IP_FW_F_ICMPRPL)
					printk("rej ");
				else
					printk("deny ");
			}
			printk(rif ? rif->name : "-");
			switch(ip->protocol)
			{
				case IPPROTO_TCP:
					printk(" TCP ");
					break;
				case IPPROTO_UDP:
					printk(" UDP ");
					break;
				case IPPROTO_ICMP:
					printk(" ICMP/%d ", icmp_type);
					break;
				default:
					printk(" PROTO=%d ", ip->protocol);
					break;
			}
			print_ip(ip->saddr);
			if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP)
				printk(":%hu", src_port);
			printk(" ");
			print_ip(ip->daddr);
			if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP)
				printk(":%hu", dst_port);
			printk(" L=%hu S=0x%2.2hX I=%hu F=0x%4.4hX T=%hu",
				ntohs(ip->tot_len), ip->tos, ntohs(ip->id),
				ntohs(ip->frag_off), ip->ttl);
			for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++)
				printk(" O=0x%8.8X", *opt++);
			printk("\n");
		}
#endif		
		if (mode != IP_FW_MODE_CHK) {
			f->fw_bcnt+=ntohs(ip->tot_len);
			f->fw_pcnt++;
		}
		if (!(mode & (IP_FW_MODE_ACCT_IN|IP_FW_MODE_ACCT_OUT)))
			break;
	} /* Loop */
	
	if (!(mode & (IP_FW_MODE_ACCT_IN|IP_FW_MODE_ACCT_OUT))) {

		/*
		 * We rely on policy defined in the rejecting entry or, if no match
		 * was found, we rely on the general policy variable for this type
		 * of firewall.
		 */

		if (f!=NULL) {
			policy=f->fw_flg;
			tosand=f->fw_tosand;
			tosxor=f->fw_tosxor;
		} else {
			tosand=0xFF;
			tosxor=0x00;
		}

		if (policy&IP_FW_F_ACCEPT) {
			/* Adjust priority and recompute checksum */
			__u8 old_tos = ip->tos;
			ip->tos = (old_tos & tosand) ^ tosxor;
			if (ip->tos != old_tos)
		 		ip_send_check(ip);
#ifdef CONFIG_IP_TRANSPARENT_PROXY
			if (policy&IP_FW_F_REDIR) {
				if (redirport)
					if ((*redirport = htons(f->fw_pts[f->fw_nsp+f->fw_ndp])) == 0) {
						/* Wildcard redirection.
						 * Note that redirport will become
						 * 0xFFFF for non-TCP/UDP packets.
						 */
						*redirport = htons(dst_port);
					}
				answer = FW_REDIRECT;
			} else
#endif
#ifdef CONFIG_IP_MASQUERADE
			if (policy&IP_FW_F_MASQ)
				answer = FW_MASQUERADE;
			else
#endif
				answer = FW_ACCEPT;
			
		} else if(policy&IP_FW_F_ICMPRPL)
			answer = FW_REJECT;
		else
			answer = FW_BLOCK;

		return answer;
	} else
		/* we're doing accounting, always ok */
		return 0;
}
Exemple #11
0
static int
tcp_match(const struct sk_buff *skb,
	  const struct net_device *in,
	  const struct net_device *out,
	  const struct xt_match *match,
	  const void *matchinfo,
	  int offset,
	  unsigned int protoff,
	  int *hotdrop)
{
	struct tcphdr _tcph, *th;
	const struct xt_tcp *tcpinfo = matchinfo;

	if (offset) {
		/* To quote Alan:

		   Don't allow a fragment of TCP 8 bytes in. Nobody normal
		   causes this. Its a cracker trying to break in by doing a
		   flag overwrite to pass the direction checks.
		*/
		if (offset == 1) {
			duprintf("Dropping evil TCP offset=1 frag.\n");
			*hotdrop = 1;
		}
		/* Must not be a fragment. */
		return 0;
	}

#define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))

	th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
	if (th == NULL) {
		/* We've been asked to examine this packet, and we
		   can't.  Hence, no choice but to drop. */
		duprintf("Dropping evil TCP offset=0 tinygram.\n");
		*hotdrop = 1;
		return 0;
	}

	if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
			ntohs(th->source),
			!!(tcpinfo->invflags & XT_TCP_INV_SRCPT)))
		return 0;
	if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
			ntohs(th->dest),
			!!(tcpinfo->invflags & XT_TCP_INV_DSTPT)))
		return 0;
	if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
		      == tcpinfo->flg_cmp,
		      XT_TCP_INV_FLAGS))
		return 0;
	if (tcpinfo->option) {
		if (th->doff * 4 < sizeof(_tcph)) {
			*hotdrop = 1;
			return 0;
		}
		if (!tcp_find_option(tcpinfo->option, skb, protoff,
				     th->doff*4 - sizeof(_tcph),
				     tcpinfo->invflags & XT_TCP_INV_OPTION,
				     hotdrop))
			return 0;
	}
	return 1;
}
Exemple #12
0
static int ip6_fw_accept_trans(struct ip6_fw_rule *rl,
			       struct fl_acc_args *args)
{
	int res = FLOWR_NODECISION;
	int proto = 0;
	int sport = 0;
	int dport = 0;

	switch (args->type) {
	case FL_ARG_FORWARD:
	{
		struct sk_buff *skb = args->fl_u.skb;
		struct ipv6hdr *hdr = skb->nh.ipv6h;
		int len;

		len = skb->len - sizeof(struct ipv6hdr);

		proto = hdr->nexthdr;

		switch (proto) {
		case IPPROTO_TCP:
		{
			struct tcphdr *th;

			if (len < sizeof(struct tcphdr)) {
				res = FLOWR_ERROR;
				goto out;
			}
			th = (struct tcphdr *)(hdr + 1);
			sport = th->source;
			dport = th->dest;
			break;
		}
		case IPPROTO_UDP:
		{
			struct udphdr *uh;

			if (len < sizeof(struct udphdr)) {
				res = FLOWR_ERROR;
				goto out;
			}
			uh = (struct udphdr *)(hdr + 1);
			sport = uh->source;
			dport = uh->dest;
			break;
		}
		default:
			goto out;
		};
		break;
	}

	case FL_ARG_ORIGIN:
	{
		proto = args->fl_u.fl_o.flow->proto;

		if (proto == IPPROTO_ICMPV6) {
			goto out;
		} else {
			sport = args->fl_u.fl_o.flow->uli_u.ports.sport;
			dport = args->fl_u.fl_o.flow->uli_u.ports.dport;
		}
		break;
	}

	if (proto == rl->info.proto &&
	    port_match(args->fl_u.fl_o.flow->uli_u.ports.sport, sport) &&
	    port_match(args->fl_u.fl_o.flow->uli_u.ports.dport, dport)) {
		if (rl->policy & IP6_FW_REJECT)
			res = FLOWR_SELECT;
		else
			res = FLOWR_CLEAR;
	}

	default:
#if IP6_FW_DEBUG >= 1
		printk(KERN_DEBUG "ip6_fw_accept: unknown arg type\n");
#endif
		goto out;
	};

out:
	return res;
}
Exemple #13
0
/* Returns whether matches rule or not. */
static int ip_rule_match(struct ip_fwkernel *f,
			 const char *ifname,
			 struct iphdr *ip,
			 char tcpsyn,
			 __u16 src_port, __u16 dst_port,
			 char isfrag)
{
#define FWINV(bool,invflg) ((bool) ^ !!(f->ipfw.fw_invflg & invflg))
	/*
	 *	This is a bit simpler as we don't have to walk
	 *	an interface chain as you do in BSD - same logic
	 *	however.
	 */

	if (FWINV((ip->saddr&f->ipfw.fw_smsk.s_addr) != f->ipfw.fw_src.s_addr,
		  IP_FW_INV_SRCIP)
	    || FWINV((ip->daddr&f->ipfw.fw_dmsk.s_addr)!=f->ipfw.fw_dst.s_addr,
		     IP_FW_INV_DSTIP)) {
		dprintf("Source or dest mismatch.\n");

		dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
			f->ipfw.fw_smsk.s_addr, f->ipfw.fw_src.s_addr,
			f->ipfw.fw_invflg & IP_FW_INV_SRCIP ? " (INV)" : "");
		dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
			f->ipfw.fw_dmsk.s_addr, f->ipfw.fw_dst.s_addr,
			f->ipfw.fw_invflg & IP_FW_INV_DSTIP ? " (INV)" : "");
		return 0;
	}

	/*
	 *	Look for a VIA device match
	 */
	if (f->ipfw.fw_flg & IP_FW_F_WILDIF) {
	    if (FWINV(strncmp(ifname, f->ipfw.fw_vianame,
			      strlen(f->ipfw.fw_vianame)) != 0,
		      IP_FW_INV_VIA)) {
		dprintf("Wildcard interface mismatch.%s\n",
			f->ipfw.fw_invflg & IP_FW_INV_VIA ? " (INV)" : "");
		return 0;	/* Mismatch */
	    }
	}
	else if (FWINV(strcmp(ifname, f->ipfw.fw_vianame) != 0,
		       IP_FW_INV_VIA)) {
	    dprintf("Interface name does not match.%s\n",
		    f->ipfw.fw_invflg & IP_FW_INV_VIA
		    ? " (INV)" : "");
	    return 0;	/* Mismatch */
	}

	/*
	 *	Ok the chain addresses match.
	 */

	/* If we have a fragment rule but the packet is not a fragment
	 * the we return zero */
	if (FWINV((f->ipfw.fw_flg&IP_FW_F_FRAG) && !isfrag, IP_FW_INV_FRAG)) {
		dprintf("Fragment rule but not fragment.%s\n",
			f->ipfw.fw_invflg & IP_FW_INV_FRAG ? " (INV)" : "");
		return 0;
	}

	/* Fragment NEVER passes a SYN test, even an inverted one. */
	if (FWINV((f->ipfw.fw_flg&IP_FW_F_TCPSYN) && !tcpsyn, IP_FW_INV_SYN)
	    || (isfrag && (f->ipfw.fw_flg&IP_FW_F_TCPSYN))) {
		dprintf("Rule requires SYN and packet has no SYN.%s\n",
			f->ipfw.fw_invflg & IP_FW_INV_SYN ? " (INV)" : "");
		return 0;
	}

	if (f->ipfw.fw_proto) {
		/*
		 *	Specific firewall - packet's protocol
		 *	must match firewall's.
		 */

		if (FWINV(ip->protocol!=f->ipfw.fw_proto, IP_FW_INV_PROTO)) {
			dprintf("Packet protocol %hi does not match %hi.%s\n",
				ip->protocol, f->ipfw.fw_proto,
				f->ipfw.fw_invflg&IP_FW_INV_PROTO ? " (INV)":"");
			return 0;
		}

		/* For non TCP/UDP/ICMP, port range is max anyway. */
		if (!port_match(f->ipfw.fw_spts[0],
				f->ipfw.fw_spts[1],
				src_port, isfrag,
				!!(f->ipfw.fw_invflg&IP_FW_INV_SRCPT))
		    || !port_match(f->ipfw.fw_dpts[0],
				   f->ipfw.fw_dpts[1],
				   dst_port, isfrag,
				   !!(f->ipfw.fw_invflg
				      &IP_FW_INV_DSTPT))) {
		    dprintf("Port match failed.\n");
		    return 0;
		}
	}

	dprintf("Match succeeded.\n");
	return 1;
}
Exemple #14
0
int
add_cookie(ParsedURL *pu, Str name, Str value,
	   time_t expires, Str domain, Str path,
	   int flag, Str comment, int version, Str port, Str commentURL)
{
    struct cookie *p;
    char *domainname = (version == 0) ? FQDN(pu->host) : pu->host;
    Str odomain = domain, opath = path;
    struct portlist *portlist = NULL;
    int use_security = !(flag & COO_OVERRIDE);

#define COOKIE_ERROR(err) if(!((err) & COO_OVERRIDE_OK) || use_security) return (err)

#ifdef DEBUG
    fprintf(stderr, "host: [%s, %s] %d\n", pu->host, pu->file, flag);
    fprintf(stderr, "cookie: [%s=%s]\n", name->ptr, value->ptr);
    fprintf(stderr, "expires: [%s]\n", asctime(gmtime(&expires)));
    if (domain)
	fprintf(stderr, "domain: [%s]\n", domain->ptr);
    if (path)
	fprintf(stderr, "path: [%s]\n", path->ptr);
    fprintf(stderr, "version: [%d]\n", version);
    if (port)
	fprintf(stderr, "port: [%s]\n", port->ptr);
#endif				/* DEBUG */
    /* [RFC 2109] s. 4.3.2 case 2; but this (no request-host) shouldn't happen */
    if (!domainname)
	return COO_ENODOT;

    if (domain) {
	char *dp;
	/* [DRAFT 12] s. 4.2.2 (does not apply in the case that
	 * host name is the same as domain attribute for version 0
	 * cookie)
	 * I think that this rule has almost the same effect as the
	 * tail match of [NETSCAPE].
	 */
	if (domain->ptr[0] != '.' &&
	    (version > 0 || strcasecmp(domainname, domain->ptr) != 0))
	    domain = Sprintf(".%s", domain->ptr);

	if (version == 0) {
	    /* [NETSCAPE] rule */
	    int n = total_dot_number(domain->ptr,
				     domain->ptr + domain->length,
				     3);
	    if (n < 2) {
		if (! check_avoid_wrong_number_of_dots_domain(domain)) {
		    COOKIE_ERROR(COO_ESPECIAL);
		}
	    }
	    else if (n == 2) {
		char **sdomain;
		int ok = 0;
		for (sdomain = special_domain; !ok && *sdomain; sdomain++) {
		    int offset = domain->length - strlen(*sdomain);
		    if (offset >= 0 &&
			strcasecmp(*sdomain, &domain->ptr[offset]) == 0)
			ok = 1;
		}
		if (!ok && ! check_avoid_wrong_number_of_dots_domain(domain)) {
		    COOKIE_ERROR(COO_ESPECIAL);
		}
	    }
	}
	else {
	    /* [DRAFT 12] s. 4.3.2 case 2 */
	    if (strcasecmp(domain->ptr, ".local") != 0 &&
		contain_no_dots(&domain->ptr[1], &domain->ptr[domain->length]))
		COOKIE_ERROR(COO_ENODOT);
	}

	/* [RFC 2109] s. 4.3.2 case 3 */
	if (!(dp = domain_match(domainname, domain->ptr)))
	    COOKIE_ERROR(COO_EDOM);
	/* [RFC 2409] s. 4.3.2 case 4 */
	/* Invariant: dp contains matched domain */
	if (version > 0 && !contain_no_dots(domainname, dp))
	    COOKIE_ERROR(COO_EBADHOST);
    }
    if (path) {
	/* [RFC 2109] s. 4.3.2 case 1 */
	if (version > 0 && strncmp(path->ptr, pu->file, path->length) != 0)
	    COOKIE_ERROR(COO_EPATH);
    }
    if (port) {
	/* [DRAFT 12] s. 4.3.2 case 5 */
	portlist = make_portlist(port);
	if (portlist && !port_match(portlist, pu->port))
	    COOKIE_ERROR(COO_EPORT);
    }

    if (!domain)
	domain = Strnew_charp(domainname);
    if (!path) {
	path = Strnew_charp(pu->file);
	while (path->length > 0 && Strlastchar(path) != '/')
	    Strshrink(path, 1);
	if (Strlastchar(path) == '/')
	    Strshrink(path, 1);
    }

    p = get_cookie_info(domain, path, name);
    if (!p) {
	p = New(struct cookie);
	p->flag = 0;
	if (default_use_cookie)
	    p->flag |= COO_USE;
	p->next = First_cookie;
	First_cookie = p;
    }
int ip_fw_chk(struct iphdr *ip, struct net_device *rif, __u16 *redirport,
	      struct ip_fw *chain, int policy, int mode)
{
	struct ip_fw *f;
	struct tcphdr		*tcp=(struct tcphdr *)((__u32 *)ip+ip->ihl);
	struct udphdr		*udp=(struct udphdr *)((__u32 *)ip+ip->ihl);
	struct icmphdr		*icmp=(struct icmphdr *)((__u32 *)ip+ip->ihl);
	__u32			src, dst;
	__u16			src_port=0xFFFF, dst_port=0xFFFF, icmp_type=0xFF;
	unsigned short		f_prt=0, prt;
	char			notcpsyn=0, notcpack=0, match;
	unsigned short		offset;
	int			answer;
	unsigned char		tosand, tosxor;

	/*
	 *	If the chain is empty follow policy. The BSD one
	 *	accepts anything giving you a time window while
	 *	flushing and rebuilding the tables.
	 */

	src = ip->saddr;
	dst = ip->daddr;

	/*
	 *	This way we handle fragmented packets.
	 *	we ignore all fragments but the first one
	 *	so the whole packet can't be reassembled.
	 *	This way we relay on the full info which
	 *	stored only in first packet.
	 *
	 *	Note that this theoretically allows partial packet
	 *	spoofing. Not very dangerous but paranoid people may
	 *	wish to play with this. It also allows the so called
	 *	"fragment bomb" denial of service attack on some types
	 *	of system.
	 */

	offset = ntohs(ip->frag_off) & IP_OFFSET;

	/*
	 *	Don't allow a fragment of TCP 8 bytes in. Nobody
	 *	normal causes this. Its a cracker trying to break
	 *	in by doing a flag overwrite to pass the direction
	 *	checks.
	 */

	if (offset == 1 && ip->protocol == IPPROTO_TCP)
		return FW_BLOCK;

	if (offset!=0 && !(mode & (IP_FW_MODE_ACCT_IN|IP_FW_MODE_ACCT_OUT)) &&
		(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP ||
			ip->protocol == IPPROTO_ICMP))
		return FW_ACCEPT;

	/*
	 *	 Header fragment for TCP is too small to check the bits.
	 */

	if(ip->protocol==IPPROTO_TCP && (ip->ihl<<2)+16 > ntohs(ip->tot_len))
		return FW_BLOCK;

	/*
	 *	Too short.
	 *
	 *	But only too short for a packet with ports...
	 */

	else if((ntohs(ip->tot_len)<8+(ip->ihl<<2))&&(ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP))
		return FW_BLOCK;

	src = ip->saddr;
	dst = ip->daddr;

	/*
	 *	If we got interface from which packet came
	 *	we can use the address directly. This is unlike
	 *	4.4BSD derived systems that have an address chain
	 *	per device. We have a device per address with dummy
	 *	devices instead.
	 */

	dprintf1("Packet ");
	switch(ip->protocol)
	{
		case IPPROTO_TCP:
			dprintf1("TCP ");
			/* ports stay 0xFFFF if it is not the first fragment */
			if (!offset) {
				src_port=ntohs(tcp->source);
				dst_port=ntohs(tcp->dest);
				if(!tcp->ack && !tcp->rst)
					/* We do NOT have ACK, value TRUE */
					notcpack=1;
				if(!tcp->syn || !notcpack)
					/* We do NOT have SYN, value TRUE */
					notcpsyn=1;
			}
			prt=IP_FW_F_TCP;
			break;
		case IPPROTO_UDP:
			dprintf1("UDP ");
			/* ports stay 0xFFFF if it is not the first fragment */
			if (!offset) {
				src_port=ntohs(udp->source);
				dst_port=ntohs(udp->dest);
			}
			prt=IP_FW_F_UDP;
			break;
		case IPPROTO_ICMP:
			/* icmp_type stays 255 if it is not the first fragment */
			if (!offset)
				icmp_type=(__u16)(icmp->type);
			dprintf2("ICMP:%d ",icmp_type);
			prt=IP_FW_F_ICMP;
			break;
		default:
			dprintf2("p=%d ",ip->protocol);
			prt=IP_FW_F_ALL;
			break;
	}
#ifdef DEBUG_IP_FIREWALL
	dprint_ip(ip->saddr);

	if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP)
		/* This will print 65535 when it is not the first fragment! */
		dprintf2(":%d ", src_port);
	dprint_ip(ip->daddr);
	if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP)
		/* This will print 65535 when it is not the first fragment! */
		dprintf2(":%d ",dst_port);
	dprintf1("\n");
#endif

	for (f=chain;f;f=f->fw_next)
	{
		/*
		 *	This is a bit simpler as we don't have to walk
		 *	an interface chain as you do in BSD - same logic
		 *	however.
		 */

		/*
		 *	Match can become 0x01 (a "normal" match was found),
		 *	0x02 (a reverse match was found), and 0x03 (the
		 *	IP addresses match in both directions).
		 *	Now we know in which direction(s) we should look
		 *	for a match for the TCP/UDP ports.  Both directions
		 *	might match (e.g., when both addresses are on the
		 *	same network for which an address/mask is given), but
		 *	the ports might only match in one direction.
		 *	This was obviously wrong in the original BSD code.
		 */
		match = 0x00;

		if ((src&f->fw_smsk.s_addr)==f->fw_src.s_addr
		&&  (dst&f->fw_dmsk.s_addr)==f->fw_dst.s_addr)
			/* normal direction */
			match |= 0x01;

		if ((f->fw_flg & IP_FW_F_BIDIR) &&
		    (dst&f->fw_smsk.s_addr)==f->fw_src.s_addr
		&&  (src&f->fw_dmsk.s_addr)==f->fw_dst.s_addr)
			/* reverse direction */
			match |= 0x02;

		if (!match)
			continue;

		/*
		 *	Look for a VIA device match
		 */
		if(f->fw_viadev)
		{
			if(rif!=f->fw_viadev)
				continue;	/* Mismatch */
		}

		/* This looks stupid, because we scan almost static
		   list, searching for static key. However, this way seems
		   to be only reasonable way of handling fw_via rules
		   (btw bsd makes the same thing).

		   It will not affect performance if you will follow
		   the following simple rules:

		   - if inteface is aliased, ALWAYS specify fw_viadev,
		     so that previous check will guarantee, that we will
		     not waste time when packet arrive on another interface.

		   - avoid using fw_via.s_addr if fw_via.s_addr is owned
		     by an aliased interface.

		                                                       --ANK
		 */
		if (f->fw_via.s_addr && rif) {
			struct in_ifaddr *ifa;

			if (rif->ip_ptr == NULL)
				continue;	/* Mismatch */

			for (ifa = ((struct in_device*)(rif->ip_ptr))->ifa_list;
			     ifa; ifa = ifa->ifa_next) {
				if (ifa->ifa_local == f->fw_via.s_addr)
					goto ifa_ok;
			}
			continue;	/* Mismatch */

		ifa_ok:;
		}

		/*
		 *	Ok the chain addresses match.
		 */

#ifdef CONFIG_IP_ACCT
		/*
		 *	See if we're in accounting mode and only want to
		 *	count incoming or outgoing packets.
		 */

		if (mode & (IP_FW_MODE_ACCT_IN|IP_FW_MODE_ACCT_OUT) &&
		   ((mode == IP_FW_MODE_ACCT_IN && f->fw_flg&IP_FW_F_ACCTOUT) ||
		    (mode == IP_FW_MODE_ACCT_OUT && f->fw_flg&IP_FW_F_ACCTIN)))
			continue;

#endif
		/*
		 * For all non-TCP packets and/or non-first fragments,
		 * notcpsyn and notcpack will always be FALSE,
		 * so the IP_FW_F_TCPSYN and IP_FW_F_TCPACK flags
		 * are actually ignored for these packets.
		 */

		if((f->fw_flg&IP_FW_F_TCPSYN) && notcpsyn)
		 	continue;

		if((f->fw_flg&IP_FW_F_TCPACK) && notcpack)
		 	continue;

		f_prt=f->fw_flg&IP_FW_F_KIND;
		if (f_prt!=IP_FW_F_ALL)
		{
			/*
			 *	Specific firewall - packet's protocol
			 *	must match firewall's.
			 */

			if(prt!=f_prt)
				continue;

			if((prt==IP_FW_F_ICMP &&
				! port_match(&f->fw_pts[0], f->fw_nsp,
					icmp_type,f->fw_flg&IP_FW_F_SRNG)) ||
			    !(prt==IP_FW_F_ICMP || ((match & 0x01) &&
				port_match(&f->fw_pts[0], f->fw_nsp, src_port,
					f->fw_flg&IP_FW_F_SRNG) &&
				port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, dst_port,
					f->fw_flg&IP_FW_F_DRNG)) || ((match & 0x02) &&
				port_match(&f->fw_pts[0], f->fw_nsp, dst_port,
					f->fw_flg&IP_FW_F_SRNG) &&
				port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, src_port,
					f->fw_flg&IP_FW_F_DRNG))))
			{
				continue;
			}
		}

#ifdef CONFIG_IP_FIREWALL_VERBOSE
		if (f->fw_flg & IP_FW_F_PRN)
		{
			char buf[16];

			print_packet(ip, src_port, dst_port, icmp_type,
				     chain_name(chain, mode),
				     rule_name(f, mode, buf),
				     rif ? rif->name : "-");
		}
#endif
		if (mode != IP_FW_MODE_CHK) {
			f->fw_bcnt+=ntohs(ip->tot_len);
			f->fw_pcnt++;
		}
		if (!(mode & (IP_FW_MODE_ACCT_IN|IP_FW_MODE_ACCT_OUT)))
			break;
	} /* Loop */

	if (!(mode & (IP_FW_MODE_ACCT_IN|IP_FW_MODE_ACCT_OUT))) {

		/*
		 * We rely on policy defined in the rejecting entry or, if no match
		 * was found, we rely on the general policy variable for this type
		 * of firewall.
		 */

		if (f!=NULL) {
			policy=f->fw_flg;
			tosand=f->fw_tosand;
			tosxor=f->fw_tosxor;
		} else {
			tosand=0xFF;
			tosxor=0x00;
		}

		if (policy&IP_FW_F_ACCEPT) {
			/* Adjust priority and recompute checksum */
			__u8 old_tos = ip->tos;
			ip->tos = (old_tos & tosand) ^ tosxor;
			if (ip->tos != old_tos)
		 		ip_send_check(ip);
#ifdef CONFIG_IP_TRANSPARENT_PROXY
			if (policy&IP_FW_F_REDIR) {
				if (redirport)
					if ((*redirport = htons(f->fw_pts[f->fw_nsp+f->fw_ndp])) == 0) {
						/* Wildcard redirection.
						 * Note that redirport will become
						 * 0xFFFF for non-TCP/UDP packets.
						 */
						*redirport = htons(dst_port);
					}
				answer = FW_REDIRECT;
			} else
#endif
#ifdef CONFIG_IP_MASQUERADE
			if (policy&IP_FW_F_MASQ)
				answer = FW_MASQUERADE;
			else
#endif
				answer = FW_ACCEPT;

		} else if(policy&IP_FW_F_ICMPRPL)
			answer = FW_REJECT;
		else
			answer = FW_BLOCK;

#ifdef CONFIG_IP_FIREWALL_NETLINK
		if((policy&IP_FW_F_PRN) && (answer == FW_REJECT || answer == FW_BLOCK))
		{
			struct sk_buff *skb=alloc_skb(128, GFP_ATOMIC);
			if(skb)
			{
				int len = min_t(unsigned int,
					      128, ntohs(ip->tot_len));

				skb_put(skb,len);
				memcpy(skb->data,ip,len);
				if(netlink_post(NETLINK_FIREWALL, skb))
					kfree_skb(skb);
			}
		}
#endif
		return answer;
	} else
		/* we're doing accounting, always ok */
		return 0;
Exemple #16
0
static int 
ip_fw_chk(struct ip **pip, int hlen,
	struct ifnet *oif, int ignport, struct mbuf **m)
{
	struct ip_fw_chain *chain;
	struct ip_fw *rule = NULL;
	struct ip *ip = *pip;
	struct ifnet *const rif = (*m)->m_pkthdr.rcvif;
	u_short offset = (ip->ip_off & IP_OFFMASK);
	u_short src_port, dst_port;

	/*
	 * Go down the chain, looking for enlightment
	 */
	for (chain=ip_fw_chain.lh_first; chain; chain = chain->chain.le_next) {
		register struct ip_fw *const f = chain->rule;

		/* Check direction inbound */
		if (!oif && !(f->fw_flg & IP_FW_F_IN))
			continue;

		/* Check direction outbound */
		if (oif && !(f->fw_flg & IP_FW_F_OUT))
			continue;

		/* Fragments */
		if ((f->fw_flg & IP_FW_F_FRAG) && !(ip->ip_off & IP_OFFMASK))
			continue;

		/* If src-addr doesn't match, not this rule. */
		if (((f->fw_flg & IP_FW_F_INVSRC) != 0) ^ ((ip->ip_src.s_addr
		    & f->fw_smsk.s_addr) != f->fw_src.s_addr))
			continue;

		/* If dest-addr doesn't match, not this rule. */
		if (((f->fw_flg & IP_FW_F_INVDST) != 0) ^ ((ip->ip_dst.s_addr
		    & f->fw_dmsk.s_addr) != f->fw_dst.s_addr))
			continue;

		/* Interface check */
		if ((f->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) {
			struct ifnet *const iface = oif ? oif : rif;

			/* Backwards compatibility hack for "via" */
			if (!iface || !iface_match(iface,
			    &f->fw_in_if, f->fw_flg & IP_FW_F_OIFNAME))
				continue;
		} else {
			/* Check receive interface */
			if ((f->fw_flg & IP_FW_F_IIFACE)
			    && (!rif || !iface_match(rif,
			      &f->fw_in_if, f->fw_flg & IP_FW_F_IIFNAME)))
				continue;
			/* Check outgoing interface */
			if ((f->fw_flg & IP_FW_F_OIFACE)
			    && (!oif || !iface_match(oif,
			      &f->fw_out_if, f->fw_flg & IP_FW_F_OIFNAME)))
				continue;
		}

		/* Check IP options */
		if (f->fw_ipopt != f->fw_ipnopt && !ipopts_match(ip, f))
			continue;

		/* Check protocol; if wildcard, match */
		if (f->fw_prot == IPPROTO_IP)
			goto got_match;

		/* If different, don't match */
		if (ip->ip_p != f->fw_prot) 
			continue;

#define PULLUP_TO(len)	do {						\
			    if ((*m)->m_len < (len)			\
				&& (*m = m_pullup(*m, (len))) == 0) {	\
				    goto bogusfrag;			\
			    }						\
			    *pip = ip = mtod(*m, struct ip *);		\
			    offset = (ip->ip_off & IP_OFFMASK);		\
			} while (0)

		/* Protocol specific checks */
		switch (ip->ip_p) {
		case IPPROTO_TCP:
		    {
			struct tcphdr *tcp;

			if (offset == 1)	/* cf. RFC 1858 */
				goto bogusfrag;
			if (offset != 0) {
				/*
				 * TCP flags and ports aren't available in this
				 * packet -- if this rule specified either one,
				 * we consider the rule a non-match.
				 */
				if (f->fw_nports != 0 ||
				    f->fw_tcpf != f->fw_tcpnf)
					continue;

				break;
			}
			PULLUP_TO(hlen + 14);
			tcp = (struct tcphdr *) ((u_long *)ip + ip->ip_hl);
			if (f->fw_tcpf != f->fw_tcpnf && !tcpflg_match(tcp, f))
				continue;
			src_port = ntohs(tcp->th_sport);
			dst_port = ntohs(tcp->th_dport);
			goto check_ports;
		    }

		case IPPROTO_UDP:
		    {
			struct udphdr *udp;

			if (offset != 0) {
				/*
				 * Port specification is unavailable -- if this
				 * rule specifies a port, we consider the rule
				 * a non-match.
				 */
				if (f->fw_nports != 0)
					continue;

				break;
			}
			PULLUP_TO(hlen + 4);
			udp = (struct udphdr *) ((u_long *)ip + ip->ip_hl);
			src_port = ntohs(udp->uh_sport);
			dst_port = ntohs(udp->uh_dport);
check_ports:
			if (!port_match(&f->fw_pts[0],
			    IP_FW_GETNSRCP(f), src_port,
			    f->fw_flg & IP_FW_F_SRNG))
				continue;
			if (!port_match(&f->fw_pts[IP_FW_GETNSRCP(f)],
			    IP_FW_GETNDSTP(f), dst_port,
			    f->fw_flg & IP_FW_F_DRNG)) 
				continue;
			break;
		    }

		case IPPROTO_ICMP:
		    {
			struct icmp *icmp;

			if (offset != 0)	/* Type isn't valid */
				break;
			PULLUP_TO(hlen + 2);
			icmp = (struct icmp *) ((u_long *)ip + ip->ip_hl);
			if (!icmptype_match(icmp, f))
				continue;
			break;
		    }
#undef PULLUP_TO

bogusfrag:
			if (fw_verbose)
				ipfw_report(NULL, ip, rif, oif);
			goto dropit;
		}

got_match:
		/* Ignore divert/tee rule if socket port is "ignport" */
		switch (f->fw_flg & IP_FW_F_COMMAND) {
		case IP_FW_F_DIVERT:
		case IP_FW_F_TEE:
			if (f->fw_divert_port == ignport)
				continue;       /* ignore this rule */
			break;
		}

		/* Update statistics */
		f->fw_pcnt += 1;
		f->fw_bcnt += ip->ip_len;
		f->timestamp = rtems_bsdnet_seconds_since_boot();

		/* Log to console if desired */
		if ((f->fw_flg & IP_FW_F_PRN) && fw_verbose)
			ipfw_report(f, ip, rif, oif);

		/* Take appropriate action */
		switch (f->fw_flg & IP_FW_F_COMMAND) {
		case IP_FW_F_ACCEPT:
			return(0);
		case IP_FW_F_COUNT:
			continue;
		case IP_FW_F_DIVERT:
			return(f->fw_divert_port);
		case IP_FW_F_TEE:
			/*
			 * XXX someday tee packet here, but beware that you
			 * can't use m_copym() or m_copypacket() because
			 * the divert input routine modifies the mbuf
			 * (and these routines only increment reference
			 * counts in the case of mbuf clusters), so need
			 * to write custom routine.
			 */
			continue;
		case IP_FW_F_SKIPTO:
#ifdef DIAGNOSTIC
			while (chain->chain.le_next
			    && chain->chain.le_next->rule->fw_number
				< f->fw_skipto_rule)
#else
			while (chain->chain.le_next->rule->fw_number
			    < f->fw_skipto_rule)
#endif
				chain = chain->chain.le_next;
			continue;
		}

		/* Deny/reject this packet using this rule */
		rule = f;
		break;
	}

#ifdef DIAGNOSTIC
	/* Rule 65535 should always be there and should always match */
	if (!chain)
		panic("ip_fw: chain");
#endif

	/*
	 * At this point, we're going to drop the packet.
	 * Send a reject notice if all of the following are true:
	 *
	 * - The packet matched a reject rule
	 * - The packet is not an ICMP packet
	 * - The packet is not a multicast or broadcast packet
	 */
	if ((rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_REJECT
	    && ip->ip_p != IPPROTO_ICMP
	    && !((*m)->m_flags & (M_BCAST|M_MCAST))
	    && !IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
		switch (rule->fw_reject_code) {
		case IP_FW_REJECT_RST:
		  {
			struct tcphdr *const tcp =
				(struct tcphdr *) ((u_long *)ip + ip->ip_hl);
			struct tcpiphdr ti, *const tip = (struct tcpiphdr *) ip;

			if (offset != 0 || (tcp->th_flags & TH_RST))
				break;
			ti.ti_i = *((struct ipovly *) ip);
			ti.ti_t = *tcp;
			bcopy(&ti, ip, sizeof(ti));
			NTOHL(tip->ti_seq);
			NTOHL(tip->ti_ack);
			tip->ti_len = ip->ip_len - hlen - (tip->ti_off << 2);
			if (tcp->th_flags & TH_ACK) {
				tcp_respond(NULL, tip, *m,
				    (tcp_seq)0, ntohl(tcp->th_ack), TH_RST);
			} else {
				if (tcp->th_flags & TH_SYN)
					tip->ti_len++;
				tcp_respond(NULL, tip, *m, tip->ti_seq
				    + tip->ti_len, (tcp_seq)0, TH_RST|TH_ACK);
			}
			*m = NULL;
			break;
		  }
		default:	/* Send an ICMP unreachable using code */
			icmp_error(*m, ICMP_UNREACH,
			    rule->fw_reject_code, 0L, 0);
			*m = NULL;
			break;
		}
	}

dropit:
	/*
	 * Finally, drop the packet.
	 */
	if (*m) {
		m_freem(*m);
		*m = NULL;
	}
	return(0);
}
Exemple #17
0
static int 
ip_fw_chk(struct ip **pip, int hlen,
	struct ifnet *oif, u_int16_t *cookie, struct mbuf **m,
	struct ip_fw_chain **flow_id)
{
	struct ip_fw_chain *chain;
	struct ip_fw *rule = NULL;
	struct ip *ip = NULL ;
	struct ifnet *const rif = (*m)->m_pkthdr.rcvif;
	u_short offset ;
	u_short src_port, dst_port;
#ifdef	IPFW_DIVERT_RESTART
	u_int16_t skipto = *cookie;
#else
	u_int16_t ignport = ntohs(*cookie);
#endif

	if (pip) { /* normal ip packet */
	    ip = *pip;
	    offset = (ip->ip_off & IP_OFFMASK);
	} else { /* bridged or non-ip packet */
	    struct ether_header *eh = mtod(*m, struct ether_header *);
	    switch (ntohs(eh->ether_type)) {
	    case ETHERTYPE_IP :
		if ((*m)->m_len<sizeof(struct ether_header) + sizeof(struct ip))
		    goto non_ip ;
		ip = (struct ip *)(eh + 1 );
		if (ip->ip_v != IPVERSION)
		    goto non_ip ;
		hlen = ip->ip_hl << 2;
		if (hlen < sizeof(struct ip)) /* minimum header length */
		    goto non_ip ;
		if ((*m)->m_len < 14 + hlen + 14) {
		    printf("-- m_len %d, need more...\n", (*m)->m_len);
		    goto non_ip ;
		}
		offset = (ip->ip_off & IP_OFFMASK);
		break ;
	    default :
non_ip:		ip = NULL ;
		break ;
	    }
	}

	if (*flow_id) {
	    if (fw_one_pass)
		return 0 ; /* accept if passed first test */
	    /*
	     * pkt has already been tagged. Look for the next rule
	     * to restart processing
	     */
	    if ( (chain = (*flow_id)->rule->next_rule_ptr) == NULL )
		chain = (*flow_id)->rule->next_rule_ptr =
			lookup_next_rule(*flow_id) ;
		if (!chain)
		    goto dropit;
	} else {
	    chain=LIST_FIRST(&ip_fw_chain);
#ifdef IPFW_DIVERT_RESTART
	    if ( skipto ) {
		/*
		 * If we've been asked to start at a given rule immediatly,
		 * do so.
		 */
                if (skipto >= 65535)
                        goto dropit;
                while (chain && (chain->rule->fw_number <= skipto)) {
                        chain = LIST_NEXT(chain, chain);
                }
                if (! chain)
		    goto dropit;
	    }
#endif /* IPFW_DIVERT_RESTART */
        }
	*cookie = 0;
	for (; chain; chain = LIST_NEXT(chain, chain)) {
		register struct ip_fw *f;
again:
		f = chain->rule;

		if (oif) {
			/* Check direction outbound */
			if (!(f->fw_flg & IP_FW_F_OUT))
				continue;
		} else {
			/* Check direction inbound */
			if (!(f->fw_flg & IP_FW_F_IN))
				continue;
		}

		if (ip == NULL ) {
		    /*
		     * do relevant checks for non-ip packets:
		     * after this, only goto got_match or continue
		     */
		    struct ether_header *eh = mtod(*m, struct ether_header *);
		    int i, h, l ;
#if 0
		    printf("-- ip_fw: rule %d(%d) for %6D <- %6D type 0x%04x\n",
			    f->fw_number, IP_FW_GETNSRCP(f),
			    eh->ether_dhost, ".", eh->ether_shost, ".",
			    ntohs(eh->ether_type) );
#endif
		    /*
		     * make default rule always match or we have a panic
		     */
		    if (f->fw_number == 65535)
			goto got_match ;

		    /*
		     * temporary hack: 
		     *   udp from 0.0.0.0 means this rule applies.
		     *   1 src port is match ether type
		     *   2 src ports (interval) is match ether type
		     *   3 src ports is match ether address
		     */
		    if (f->fw_src.s_addr != 0 || f->fw_prot != IPPROTO_UDP)
			continue ;
		    switch (IP_FW_GETNSRCP(f)) {
		    case 1: /* match one type */
			if (  /* ( (f->fw_flg & IP_FW_F_INVSRC) != 0) ^ */
			      ( f->fw_pts[0] == ntohs(eh->ether_type) )  ) {
			    printf("match!\n");
			    goto got_match ;
			}
		    default:
			break ;
		    }
		    continue;
		}
		/* Fragments */
		if ((f->fw_flg & IP_FW_F_FRAG) && !(ip->ip_off & IP_OFFMASK))
			continue;

		/* If src-addr doesn't match, not this rule. */
		if (((f->fw_flg & IP_FW_F_INVSRC) != 0) ^ ((ip->ip_src.s_addr
		    & f->fw_smsk.s_addr) != f->fw_src.s_addr))
			continue;

		/* If dest-addr doesn't match, not this rule. */
		if (((f->fw_flg & IP_FW_F_INVDST) != 0) ^ ((ip->ip_dst.s_addr
		    & f->fw_dmsk.s_addr) != f->fw_dst.s_addr))
			continue;

		/* Interface check */
		if ((f->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) {
			struct ifnet *const iface = oif ? oif : rif;

			/* Backwards compatibility hack for "via" */
			if (!iface || !iface_match(iface,
			    &f->fw_in_if, f->fw_flg & IP_FW_F_OIFNAME))
				continue;
		} else {
			/* Check receive interface */
			if ((f->fw_flg & IP_FW_F_IIFACE)
			    && (!rif || !iface_match(rif,
			      &f->fw_in_if, f->fw_flg & IP_FW_F_IIFNAME)))
				continue;
			/* Check outgoing interface */
			if ((f->fw_flg & IP_FW_F_OIFACE)
			    && (!oif || !iface_match(oif,
			      &f->fw_out_if, f->fw_flg & IP_FW_F_OIFNAME)))
				continue;
		}

		/* Check IP options */
		if (f->fw_ipopt != f->fw_ipnopt && !ipopts_match(ip, f))
			continue;

		/* Check protocol; if wildcard, match */
		if (f->fw_prot == IPPROTO_IP)
			goto got_match;

		/* If different, don't match */
		if (ip->ip_p != f->fw_prot) 
			continue;

#define PULLUP_TO(len)	do {						\
			    if ((*m)->m_len < (len) ) {			\
				if ( (*m = m_pullup(*m, (len))) == 0) 	\
				    goto bogusfrag;			\
				*pip = ip = mtod(*m, struct ip *);	\
				offset = (ip->ip_off & IP_OFFMASK);	\
			    }						\
			} while (0)

		/* Protocol specific checks */
		switch (ip->ip_p) {
		case IPPROTO_TCP:
		    {
			struct tcphdr *tcp;

			if (offset == 1)	/* cf. RFC 1858 */
				goto bogusfrag;
			if (offset != 0) {
				/*
				 * TCP flags and ports aren't available in this
				 * packet -- if this rule specified either one,
				 * we consider the rule a non-match.
				 */
				if (f->fw_nports != 0 ||
				    f->fw_tcpf != f->fw_tcpnf)
					continue;

				break;
			}
			PULLUP_TO(hlen + 14);
			tcp = (struct tcphdr *) ((u_long *)ip + ip->ip_hl);
			if (f->fw_tcpf != f->fw_tcpnf && !tcpflg_match(tcp, f))
				continue;
			src_port = ntohs(tcp->th_sport);
			dst_port = ntohs(tcp->th_dport);
			goto check_ports;
		    }

		case IPPROTO_UDP:
		    {
			struct udphdr *udp;

			if (offset != 0) {
				/*
				 * Port specification is unavailable -- if this
				 * rule specifies a port, we consider the rule
				 * a non-match.
				 */
				if (f->fw_nports != 0)
					continue;

				break;
			}
			PULLUP_TO(hlen + 4);
			udp = (struct udphdr *) ((u_long *)ip + ip->ip_hl);
			src_port = ntohs(udp->uh_sport);
			dst_port = ntohs(udp->uh_dport);
check_ports:
			if (!port_match(&f->fw_pts[0],
			    IP_FW_GETNSRCP(f), src_port,
			    f->fw_flg & IP_FW_F_SRNG))
				continue;
			if (!port_match(&f->fw_pts[IP_FW_GETNSRCP(f)],
			    IP_FW_GETNDSTP(f), dst_port,
			    f->fw_flg & IP_FW_F_DRNG)) 
				continue;
			break;
		    }

		case IPPROTO_ICMP:
		    {
			struct icmp *icmp;

			if (offset != 0)	/* Type isn't valid */
				break;
			PULLUP_TO(hlen + 2);
			icmp = (struct icmp *) ((u_long *)ip + ip->ip_hl);
			if (!icmptype_match(icmp, f))
				continue;
			break;
		    }
#undef PULLUP_TO

bogusfrag:
			if (fw_verbose)
				ipfw_report(NULL, ip, rif, oif);
			goto dropit;
		}

got_match:
		*flow_id = chain ; /* XXX set flow id */
#ifndef IPFW_DIVERT_RESTART
		/* Ignore divert/tee rule if socket port is "ignport" */
		switch (f->fw_flg & IP_FW_F_COMMAND) {
		case IP_FW_F_DIVERT:
		case IP_FW_F_TEE:
			if (f->fw_divert_port == ignport)
				continue;       /* ignore this rule */
			break;
		}

#endif /* IPFW_DIVERT_RESTART */
		/* Update statistics */
		f->fw_pcnt += 1;
		/*
		 * note -- bridged-ip packets still have some fields
		 * in network order, including ip_len
		 */
		if (ip) {
		    if (pip)
			f->fw_bcnt += ip->ip_len;
		    else
			f->fw_bcnt += ntohs(ip->ip_len);
		}
		f->timestamp = time.tv_sec;

		/* Log to console if desired */
		if ((f->fw_flg & IP_FW_F_PRN) && fw_verbose)
			ipfw_report(f, ip, rif, oif);

		/* Take appropriate action */
		switch (f->fw_flg & IP_FW_F_COMMAND) {
		case IP_FW_F_ACCEPT:
			return(0);
		case IP_FW_F_COUNT:
			continue;
#ifdef IPDIVERT
		case IP_FW_F_DIVERT:
#ifdef IPFW_DIVERT_RESTART
			*cookie = f->fw_number;
#else
			*cookie = htons(f->fw_divert_port);
#endif /* IPFW_DIVERT_RESTART */
			return(f->fw_divert_port);
#endif
		case IP_FW_F_TEE:
			/*
			 * XXX someday tee packet here, but beware that you
			 * can't use m_copym() or m_copypacket() because
			 * the divert input routine modifies the mbuf
			 * (and these routines only increment reference
			 * counts in the case of mbuf clusters), so need
			 * to write custom routine.
			 */
			continue;
		case IP_FW_F_SKIPTO: /* XXX check */
		    if ( f->next_rule_ptr )
			chain = f->next_rule_ptr ;
		    else
			chain = lookup_next_rule(chain) ;
		    if (!chain)
			goto dropit;
		    goto again ;
#ifdef DUMMYNET
		case IP_FW_F_PIPE:
			return(f->fw_pipe_nr | 0x10000 );
#endif
		}

		/* Deny/reject this packet using this rule */
		rule = f;
		break;
	}

#ifdef DIAGNOSTIC
	/* Rule 65535 should always be there and should always match */
	if (!chain)
		panic("ip_fw: chain");
#endif

	/*
	 * At this point, we're going to drop the packet.
	 * Send a reject notice if all of the following are true:
	 *
	 * - The packet matched a reject rule
	 * - The packet is not an ICMP packet, or is an ICMP query packet
	 * - The packet is not a multicast or broadcast packet
	 */
	if ((rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_REJECT
	    && ip
	    && (ip->ip_p != IPPROTO_ICMP || is_icmp_query(ip))
	    && !((*m)->m_flags & (M_BCAST|M_MCAST))
	    && !IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
		switch (rule->fw_reject_code) {
		case IP_FW_REJECT_RST:
		  {
			struct tcphdr *const tcp =
				(struct tcphdr *) ((u_long *)ip + ip->ip_hl);
			struct tcpiphdr ti, *const tip = (struct tcpiphdr *) ip;

			if (offset != 0 || (tcp->th_flags & TH_RST))
				break;
			ti.ti_i = *((struct ipovly *) ip);
			ti.ti_t = *tcp;
			bcopy(&ti, ip, sizeof(ti));
			NTOHL(tip->ti_seq);
			NTOHL(tip->ti_ack);
			tip->ti_len = ip->ip_len - hlen - (tip->ti_off << 2);
			if (tcp->th_flags & TH_ACK) {
				tcp_respond(NULL, tip, *m,
				    (tcp_seq)0, ntohl(tcp->th_ack), TH_RST);
			} else {
				if (tcp->th_flags & TH_SYN)
					tip->ti_len++;
				tcp_respond(NULL, tip, *m, tip->ti_seq
				    + tip->ti_len, (tcp_seq)0, TH_RST|TH_ACK);
			}
			*m = NULL;
			break;
		  }
		default:	/* Send an ICMP unreachable using code */
			icmp_error(*m, ICMP_UNREACH,
			    rule->fw_reject_code, 0L, 0);
			*m = NULL;
			break;
		}
	}

dropit:
	/*
	 * Finally, drop the packet.
	 */
	if (*m) {
		m_freem(*m);
		*m = NULL;
	}
	return(0);
}