Example #1
0
static int
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 ip_auth_hdr *ah, _ah;
	const struct ip6t_ah *ahinfo = matchinfo;
	unsigned int ptr;
	unsigned int hdrlen = 0;
	int err;

	err = ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH, NULL);
	if (err < 0) {
		if (err != -ENOENT)
			*hotdrop = 1;
		return 0;
	}

	ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah);
	if (ah == NULL) {
		*hotdrop = 1;
		return 0;
	}

	hdrlen = (ah->hdrlen + 2) << 2;

	DEBUGP("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen);
	DEBUGP("RES %04X ", ah->reserved);
	DEBUGP("SPI %u %08X\n", ntohl(ah->spi), ntohl(ah->spi));

	DEBUGP("IPv6 AH spi %02X ",
	       (spi_match(ahinfo->spis[0], ahinfo->spis[1],
	                  ntohl(ah->spi),
	                  !!(ahinfo->invflags & IP6T_AH_INV_SPI))));
	DEBUGP("len %02X %04X %02X ",
	       ahinfo->hdrlen, hdrlen,
	       (!ahinfo->hdrlen ||
	        (ahinfo->hdrlen == hdrlen) ^
	        !!(ahinfo->invflags & IP6T_AH_INV_LEN)));
	DEBUGP("res %02X %04X %02X\n",
	       ahinfo->hdrres, ah->reserved,
	       !(ahinfo->hdrres && ah->reserved));

	return (ah != NULL)
	       &&
	       (spi_match(ahinfo->spis[0], ahinfo->spis[1],
	                  ntohl(ah->spi),
	                  !!(ahinfo->invflags & IP6T_AH_INV_SPI)))
	       &&
	       (!ahinfo->hdrlen ||
	        (ahinfo->hdrlen == hdrlen) ^
	        !!(ahinfo->invflags & IP6T_AH_INV_LEN))
	       &&
	       !(ahinfo->hdrres && ah->reserved);
}
static int
match(const struct sk_buff *skb,
      const struct net_device *in,
      const struct net_device *out,
      const void *matchinfo,
      int offset,
      unsigned int protoff,
      int *hotdrop)
{
	struct ip_esp_hdr _esp, *eh;
	const struct ip6t_esp *espinfo = matchinfo;
	unsigned int ptr;

	/* Make sure this isn't an evil packet */
	/*DEBUGP("ipv6_esp entered \n");*/

	if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ESP) < 0)
		return 0;

	eh = skb_header_pointer(skb, ptr, sizeof(_esp), &_esp);
	if (eh == NULL) {
		*hotdrop = 1;
		return 0;
	}

	DEBUGP("IPv6 ESP SPI %u %08X\n", ntohl(eh->spi), ntohl(eh->spi));

	return (eh != NULL)
		&& spi_match(espinfo->spis[0], espinfo->spis[1],
			      ntohl(eh->spi),
			      !!(espinfo->invflags & IP6T_ESP_INV_SPI));
}
Example #3
0
static inline void
__nft_netdev_set_pktinfo_ipv6(struct nft_pktinfo *pkt,
			      const struct nf_hook_ops *ops,
			      struct sk_buff *skb,
			      const struct nf_hook_state *state)
{
#if IS_ENABLED(CONFIG_IPV6)
	struct ipv6hdr *ip6h, _ip6h;
	unsigned int thoff = 0;
	unsigned short frag_off;
	int protohdr;
	u32 pkt_len;

	ip6h = skb_header_pointer(skb, skb_network_offset(skb), sizeof(*ip6h),
				  &_ip6h);
	if (!ip6h)
		return;

	if (ip6h->version != 6)
		return;

	pkt_len = ntohs(ip6h->payload_len);
	if (pkt_len + sizeof(*ip6h) > skb->len)
		return;

	protohdr = ipv6_find_hdr(pkt->skb, &thoff, -1, &frag_off, NULL);
	if (protohdr < 0)
                return;

	pkt->tprot = protohdr;
	pkt->xt.thoff = thoff;
	pkt->xt.fragoff = frag_off;
#endif
}
Example #4
0
/* Performance critical - called for every packet */
static inline bool
ip6_packet_match(const struct sk_buff *skb,
		 const char *indev,
		 const char *outdev,
		 const struct ip6t_ip6 *ip6info,
		 unsigned int *protoff,
		 int *fragoff, bool *hotdrop)
{
	unsigned long ret;
	const struct ipv6hdr *ipv6 = ipv6_hdr(skb);

	if (NF_INVF(ip6info, IP6T_INV_SRCIP,
		    ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk,
					 &ip6info->src)) ||
	    NF_INVF(ip6info, IP6T_INV_DSTIP,
		    ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
					 &ip6info->dst)))
		return false;

	ret = ifname_compare_aligned(indev, ip6info->iniface, ip6info->iniface_mask);

	if (NF_INVF(ip6info, IP6T_INV_VIA_IN, ret != 0))
		return false;

	ret = ifname_compare_aligned(outdev, ip6info->outiface, ip6info->outiface_mask);

	if (NF_INVF(ip6info, IP6T_INV_VIA_OUT, ret != 0))
		return false;

/* ... might want to do something with class and flowlabel here ... */

	/* look for the desired protocol header */
	if (ip6info->flags & IP6T_F_PROTO) {
		int protohdr;
		unsigned short _frag_off;

		protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off, NULL);
		if (protohdr < 0) {
			if (_frag_off == 0)
				*hotdrop = true;
			return false;
		}
		*fragoff = _frag_off;

		if (ip6info->proto == protohdr) {
			if (ip6info->invflags & IP6T_INV_PROTO)
				return false;

			return true;
		}

		/* We need match for the '-p all', too! */
		if ((ip6info->proto != 0) &&
			!(ip6info->invflags & IP6T_INV_PROTO))
			return false;
	}
	return true;
}
Example #5
0
static int
hmark_pkt_set_htuple_ipv6(const struct sk_buff *skb, struct hmark_tuple *t,
			  const struct xt_hmark_info *info)
{
	struct ipv6hdr *ip6, _ip6;
	int flag = IP6T_FH_F_AUTH;
	unsigned int nhoff = 0;
	u16 fragoff = 0;
	int nexthdr;

	ip6 = (struct ipv6hdr *) (skb->data + skb_network_offset(skb));
	nexthdr = ipv6_find_hdr(skb, &nhoff, -1, &fragoff, &flag);
	if (nexthdr < 0)
		return 0;
	/* No need to check for icmp errors on fragments */
	if ((flag & IP6T_FH_F_FRAG) || (nexthdr != IPPROTO_ICMPV6))
		goto noicmp;
	/* Use inner header in case of ICMP errors */
	if (get_inner6_hdr(skb, &nhoff)) {
		ip6 = skb_header_pointer(skb, nhoff, sizeof(_ip6), &_ip6);
		if (ip6 == NULL)
			return -1;
		/* If AH present, use SPI like in ESP. */
		flag = IP6T_FH_F_AUTH;
		nexthdr = ipv6_find_hdr(skb, &nhoff, -1, &fragoff, &flag);
		if (nexthdr < 0)
			return -1;
	}
noicmp:
	t->src = hmark_addr6_mask(ip6->saddr.s6_addr32, info->src_mask.all);
	t->dst = hmark_addr6_mask(ip6->daddr.s6_addr32, info->dst_mask.all);

	if (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3))
		return 0;

	t->proto = nexthdr;
	if (t->proto == IPPROTO_ICMPV6)
		return 0;

	if (flag & IP6T_FH_F_FRAG)
		return 0;

	hmark_set_tuple_ports(skb, nhoff, t, info);
	return 0;
}
Example #6
0
static bool ah_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
{
    struct ip_auth_hdr _ah;
    const struct ip_auth_hdr *ah;
    const struct ip6t_ah *ahinfo = par->matchinfo;
    unsigned int ptr;
    unsigned int hdrlen = 0;
    int err;

    err = ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH, NULL);
    if (err < 0) {
        if (err != -ENOENT)
            *par->hotdrop = true;
        return false;
    }

    ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah);
    if (ah == NULL) {
        *par->hotdrop = true;
        return false;
    }

    hdrlen = (ah->hdrlen + 2) << 2;

    pr_debug("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen);
    pr_debug("RES %04X ", ah->reserved);
    pr_debug("SPI %u %08X\n", ntohl(ah->spi), ntohl(ah->spi));

    pr_debug("IPv6 AH spi %02X ",
             spi_match(ahinfo->spis[0], ahinfo->spis[1],
                       ntohl(ah->spi),
                       !!(ahinfo->invflags & IP6T_AH_INV_SPI)));
    pr_debug("len %02X %04X %02X ",
             ahinfo->hdrlen, hdrlen,
             (!ahinfo->hdrlen ||
              (ahinfo->hdrlen == hdrlen) ^
              !!(ahinfo->invflags & IP6T_AH_INV_LEN)));
    pr_debug("res %02X %04X %02X\n",
             ahinfo->hdrres, ah->reserved,
             !(ahinfo->hdrres && ah->reserved));

    return (ah != NULL)
           &&
           spi_match(ahinfo->spis[0], ahinfo->spis[1],
                     ntohl(ah->spi),
                     !!(ahinfo->invflags & IP6T_AH_INV_SPI))
           &&
           (!ahinfo->hdrlen ||
            (ahinfo->hdrlen == hdrlen) ^
            !!(ahinfo->invflags & IP6T_AH_INV_LEN))
           &&
           !(ahinfo->hdrres && ah->reserved);
}
Example #7
0
struct sock *nf_sk_lookup_slow_v6(struct net *net, const struct sk_buff *skb,
				  const struct net_device *indev)
{
	__be16 uninitialized_var(dport), uninitialized_var(sport);
	const struct in6_addr *daddr = NULL, *saddr = NULL;
	struct ipv6hdr *iph = ipv6_hdr(skb);
	struct sk_buff *data_skb = NULL;
	int doff = 0;
	int thoff = 0, tproto;

	tproto = ipv6_find_hdr(skb, &thoff, -1, NULL, NULL);
	if (tproto < 0) {
		pr_debug("unable to find transport header in IPv6 packet, dropping\n");
		return NULL;
	}

	if (tproto == IPPROTO_UDP || tproto == IPPROTO_TCP) {
		struct tcphdr _hdr;
		struct udphdr *hp;

		hp = skb_header_pointer(skb, thoff, tproto == IPPROTO_UDP ?
					sizeof(*hp) : sizeof(_hdr), &_hdr);
		if (hp == NULL)
			return NULL;

		saddr = &iph->saddr;
		sport = hp->source;
		daddr = &iph->daddr;
		dport = hp->dest;
		data_skb = (struct sk_buff *)skb;
		doff = tproto == IPPROTO_TCP ?
			thoff + __tcp_hdrlen((struct tcphdr *)hp) :
			thoff + sizeof(*hp);

	} else if (tproto == IPPROTO_ICMPV6) {
		struct ipv6hdr ipv6_var;

		if (extract_icmp6_fields(skb, thoff, &tproto, &saddr, &daddr,
					 &sport, &dport, &ipv6_var))
			return NULL;
	} else {
		return NULL;
	}

	return nf_socket_get_sock_v6(net, data_skb, doff, tproto, saddr, daddr,
				     sport, dport, indev);
}
Example #8
0
struct sock*
xt_socket_get6_sk(const struct sk_buff *skb, struct xt_action_param *par)
{
	struct ipv6hdr *iph = ipv6_hdr(skb);
	struct udphdr _hdr, *hp = NULL;
	struct sock *sk;
	struct in6_addr *daddr = NULL, *saddr = NULL;
	__be16 dport, sport;
	int thoff, tproto;

	dport = sport = 0;

	tproto = ipv6_find_hdr(skb, &thoff, -1, NULL);
	if (tproto < 0) {
		pr_debug("unable to find transport header in IPv6 packet, dropping\n");
		return NF_DROP;
	}

	if (tproto == IPPROTO_UDP || tproto == IPPROTO_TCP) {
		hp = skb_header_pointer(skb, thoff,
					sizeof(_hdr), &_hdr);
		if (hp == NULL)
			return NULL;

		saddr = &iph->saddr;
		sport = hp->source;
		daddr = &iph->daddr;
		dport = hp->dest;

	} else if (tproto == IPPROTO_ICMPV6) {
		if (extract_icmp6_fields(skb, thoff, &tproto, &saddr, &daddr,
					 &sport, &dport))
			return NULL;
	} else {
		return NULL;
	}

	sk = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto,
				   saddr, daddr, sport, dport, par->in, NFT_LOOKUP_ANY);
	pr_debug("proto %hhd %pI6:%hu -> %pI6:%hu "
		 "(orig %pI6:%hu) sock %p\n",
		 tproto, saddr, ntohs(sport),
		 daddr, ntohs(dport),
		 &iph->daddr, hp ? ntohs(hp->dest) : 0, sk);
	return sk;
}
Example #9
0
static bool l2tp_mt6(const struct sk_buff *skb, struct xt_action_param *par)
{
	unsigned int thoff = 0;
	unsigned short fragoff = 0;
	int ipproto;

	ipproto = ipv6_find_hdr(skb, &thoff, -1, &fragoff, NULL);
	if (fragoff != 0)
		return false;

	/* l2tp_mt_check6 already restricts the transport protocol */
	switch (ipproto) {
	case IPPROTO_UDP:
		return l2tp_udp_mt(skb, par, thoff);
	case IPPROTO_L2TP:
		return l2tp_ip_mt(skb, par, thoff);
	}

	return false;
}
Example #10
0
static bool
socket_mt4_v0(const struct sk_buff *skb, struct xt_action_param *par)
{
	static struct xt_socket_mtinfo1 xt_info_v0 = {
		.flags = 0,
	};

	return socket_match(skb, par, &xt_info_v0);
}

static bool
socket_mt4_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
{
	return socket_match(skb, par, par->matchinfo);
}

#ifdef XT_SOCKET_HAVE_IPV6

static int
extract_icmp6_fields(const struct sk_buff *skb,
		     unsigned int outside_hdrlen,
		     int *protocol,
		     const struct in6_addr **raddr,
		     const struct in6_addr **laddr,
		     __be16 *rport,
		     __be16 *lport,
		     struct ipv6hdr *ipv6_var)
{
	const struct ipv6hdr *inside_iph;
	struct icmp6hdr *icmph, _icmph;
	__be16 *ports, _ports[2];
	u8 inside_nexthdr;
	__be16 inside_fragoff;
	int inside_hdrlen;

	icmph = skb_header_pointer(skb, outside_hdrlen,
				   sizeof(_icmph), &_icmph);
	if (icmph == NULL)
		return 1;

	if (icmph->icmp6_type & ICMPV6_INFOMSG_MASK)
		return 1;

	inside_iph = skb_header_pointer(skb, outside_hdrlen + sizeof(_icmph),
					sizeof(*ipv6_var), ipv6_var);
	if (inside_iph == NULL)
		return 1;
	inside_nexthdr = inside_iph->nexthdr;

	inside_hdrlen = ipv6_skip_exthdr(skb, outside_hdrlen + sizeof(_icmph) +
					      sizeof(*ipv6_var),
					 &inside_nexthdr, &inside_fragoff);
	if (inside_hdrlen < 0)
		return 1; /* hjm: Packet has no/incomplete transport layer headers. */

	if (inside_nexthdr != IPPROTO_TCP &&
	    inside_nexthdr != IPPROTO_UDP)
		return 1;

	ports = skb_header_pointer(skb, inside_hdrlen,
				   sizeof(_ports), &_ports);
	if (ports == NULL)
		return 1;

	/* the inside IP packet is the one quoted from our side, thus
	 * its saddr is the local address */
	*protocol = inside_nexthdr;
	*laddr = &inside_iph->saddr;
	*lport = ports[0];
	*raddr = &inside_iph->daddr;
	*rport = ports[1];

	return 0;
}

static struct sock *
xt_socket_get_sock_v6(struct net *net, const u8 protocol,
		      const struct in6_addr *saddr, const struct in6_addr *daddr,
		      const __be16 sport, const __be16 dport,
		      const struct net_device *in)
{
	switch (protocol) {
	case IPPROTO_TCP:
		return inet6_lookup(net, &tcp_hashinfo,
				    saddr, sport, daddr, dport,
				    in->ifindex);
	case IPPROTO_UDP:
		return udp6_lib_lookup(net, saddr, sport, daddr, dport,
				       in->ifindex);
	}

	return NULL;
}

static bool
socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
{
	struct ipv6hdr ipv6_var, *iph = ipv6_hdr(skb);
	struct udphdr _hdr, *hp = NULL;
	struct sock *sk = skb->sk;
	const struct in6_addr *daddr = NULL, *saddr = NULL;
	__be16 uninitialized_var(dport), uninitialized_var(sport);
	int thoff = 0, uninitialized_var(tproto);
	const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo;

	tproto = ipv6_find_hdr(skb, &thoff, -1, NULL, NULL);
	if (tproto < 0) {
		pr_debug("unable to find transport header in IPv6 packet, dropping\n");
		return NF_DROP;
	}

	if (tproto == IPPROTO_UDP || tproto == IPPROTO_TCP) {
		hp = skb_header_pointer(skb, thoff,
					sizeof(_hdr), &_hdr);
		if (hp == NULL)
			return false;

		saddr = &iph->saddr;
		sport = hp->source;
		daddr = &iph->daddr;
		dport = hp->dest;

	} else if (tproto == IPPROTO_ICMPV6) {
		if (extract_icmp6_fields(skb, thoff, &tproto, &saddr, &daddr,
					 &sport, &dport, &ipv6_var))
			return false;
	} else {
		return false;
	}

	if (!sk)
		sk = xt_socket_get_sock_v6(dev_net(skb->dev), tproto,
					   saddr, daddr, sport, dport,
					   par->in);
	if (sk) {
		bool wildcard;
		bool transparent = true;

		/* Ignore sockets listening on INADDR_ANY
		 * unless XT_SOCKET_NOWILDCARD is set
		 */
		wildcard = (!(info->flags & XT_SOCKET_NOWILDCARD) &&
			    sk->sk_state != TCP_TIME_WAIT &&
			    ipv6_addr_any(&sk->sk_v6_rcv_saddr));

		/* Ignore non-transparent sockets,
		   if XT_SOCKET_TRANSPARENT is used */
		if (info->flags & XT_SOCKET_TRANSPARENT)
			transparent = ((sk->sk_state != TCP_TIME_WAIT &&
					inet_sk(sk)->transparent) ||
				       (sk->sk_state == TCP_TIME_WAIT &&
					inet_twsk(sk)->tw_transparent));

		if (sk != skb->sk)
			sock_gen_put(sk);

		if (wildcard || !transparent)
			sk = NULL;
	}

	pr_debug("proto %hhd %pI6:%hu -> %pI6:%hu "
		 "(orig %pI6:%hu) sock %p\n",
		 tproto, saddr, ntohs(sport),
		 daddr, ntohs(dport),
		 &iph->daddr, hp ? ntohs(hp->dest) : 0, sk);

	return (sk != NULL);
}
#endif

static int socket_mt_v1_check(const struct xt_mtchk_param *par)
{
	const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo;

	if (info->flags & ~XT_SOCKET_FLAGS_V1) {
		pr_info("unknown flags 0x%x\n", info->flags & ~XT_SOCKET_FLAGS_V1);
		return -EINVAL;
	}
	return 0;
}

static int socket_mt_v2_check(const struct xt_mtchk_param *par)
{
	const struct xt_socket_mtinfo2 *info = (struct xt_socket_mtinfo2 *) par->matchinfo;

	if (info->flags & ~XT_SOCKET_FLAGS_V2) {
		pr_info("unknown flags 0x%x\n", info->flags & ~XT_SOCKET_FLAGS_V2);
		return -EINVAL;
	}
	return 0;
}

static struct xt_match socket_mt_reg[] __read_mostly = {
	{
		.name		= "socket",
		.revision	= 0,
		.family		= NFPROTO_IPV4,
		.match		= socket_mt4_v0,
		.hooks		= (1 << NF_INET_PRE_ROUTING) |
				  (1 << NF_INET_LOCAL_IN),
		.me		= THIS_MODULE,
	},
	{
		.name		= "socket",
		.revision	= 1,
		.family		= NFPROTO_IPV4,
		.match		= socket_mt4_v1_v2,
		.checkentry	= socket_mt_v1_check,
		.matchsize	= sizeof(struct xt_socket_mtinfo1),
		.hooks		= (1 << NF_INET_PRE_ROUTING) |
				  (1 << NF_INET_LOCAL_IN),
		.me		= THIS_MODULE,
	},
#ifdef XT_SOCKET_HAVE_IPV6
	{
		.name		= "socket",
static bool
frag_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
{
	struct frag_hdr _frag;
	const struct frag_hdr *fh;
	const struct ip6t_frag *fraginfo = par->matchinfo;
	unsigned int ptr;
	int err;

	err = ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT, NULL);
	if (err < 0) {
		if (err != -ENOENT)
			*par->hotdrop = true;
		return false;
	}

	fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag);
	if (fh == NULL) {
		*par->hotdrop = true;
		return false;
	}

	pr_debug("INFO %04X ", fh->frag_off);
	pr_debug("OFFSET %04X ", ntohs(fh->frag_off) & ~0x7);
	pr_debug("RES %02X %04X", fh->reserved, ntohs(fh->frag_off) & 0x6);
	pr_debug("MF %04X ", fh->frag_off & htons(IP6_MF));
	pr_debug("ID %u %08X\n", ntohl(fh->identification),
		 ntohl(fh->identification));

	pr_debug("IPv6 FRAG id %02X ",
		 id_match(fraginfo->ids[0], fraginfo->ids[1],
			  ntohl(fh->identification),
			  !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)));
	pr_debug("res %02X %02X%04X %02X ",
		 fraginfo->flags & IP6T_FRAG_RES, fh->reserved,
		 ntohs(fh->frag_off) & 0x6,
		 !((fraginfo->flags & IP6T_FRAG_RES) &&
		   (fh->reserved || (ntohs(fh->frag_off) & 0x06))));
	pr_debug("first %02X %02X %02X ",
		 fraginfo->flags & IP6T_FRAG_FST,
		 ntohs(fh->frag_off) & ~0x7,
		 !((fraginfo->flags & IP6T_FRAG_FST) &&
		   (ntohs(fh->frag_off) & ~0x7)));
	pr_debug("mf %02X %02X %02X ",
		 fraginfo->flags & IP6T_FRAG_MF,
		 ntohs(fh->frag_off) & IP6_MF,
		 !((fraginfo->flags & IP6T_FRAG_MF) &&
		   !((ntohs(fh->frag_off) & IP6_MF))));
	pr_debug("last %02X %02X %02X\n",
		 fraginfo->flags & IP6T_FRAG_NMF,
		 ntohs(fh->frag_off) & IP6_MF,
		 !((fraginfo->flags & IP6T_FRAG_NMF) &&
		   (ntohs(fh->frag_off) & IP6_MF)));

	return (fh != NULL) &&
		id_match(fraginfo->ids[0], fraginfo->ids[1],
			 ntohl(fh->identification),
			 !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)) &&
		!((fraginfo->flags & IP6T_FRAG_RES) &&
		  (fh->reserved || (ntohs(fh->frag_off) & 0x6))) &&
		!((fraginfo->flags & IP6T_FRAG_FST) &&
		  (ntohs(fh->frag_off) & ~0x7)) &&
		!((fraginfo->flags & IP6T_FRAG_MF) &&
		  !(ntohs(fh->frag_off) & IP6_MF)) &&
		!((fraginfo->flags & IP6T_FRAG_NMF) &&
		  (ntohs(fh->frag_off) & IP6_MF));
}
Example #12
0
static bool
socket_mt4_v0(const struct sk_buff *skb, struct xt_action_param *par)
{
	static struct xt_socket_mtinfo1 xt_info_v0 = {
		.flags = 0,
	};

	return socket_match(skb, par, &xt_info_v0);
}

static bool
socket_mt4_v1_v2_v3(const struct sk_buff *skb, struct xt_action_param *par)
{
	return socket_match(skb, par, par->matchinfo);
}

#ifdef XT_SOCKET_HAVE_IPV6

static int
extract_icmp6_fields(const struct sk_buff *skb,
		     unsigned int outside_hdrlen,
		     int *protocol,
		     const struct in6_addr **raddr,
		     const struct in6_addr **laddr,
		     __be16 *rport,
		     __be16 *lport,
		     struct ipv6hdr *ipv6_var)
{
	const struct ipv6hdr *inside_iph;
	struct icmp6hdr *icmph, _icmph;
	__be16 *ports, _ports[2];
	u8 inside_nexthdr;
	__be16 inside_fragoff;
	int inside_hdrlen;

	icmph = skb_header_pointer(skb, outside_hdrlen,
				   sizeof(_icmph), &_icmph);
	if (icmph == NULL)
		return 1;

	if (icmph->icmp6_type & ICMPV6_INFOMSG_MASK)
		return 1;

	inside_iph = skb_header_pointer(skb, outside_hdrlen + sizeof(_icmph),
					sizeof(*ipv6_var), ipv6_var);
	if (inside_iph == NULL)
		return 1;
	inside_nexthdr = inside_iph->nexthdr;

	inside_hdrlen = ipv6_skip_exthdr(skb, outside_hdrlen + sizeof(_icmph) +
					      sizeof(*ipv6_var),
					 &inside_nexthdr, &inside_fragoff);
	if (inside_hdrlen < 0)
		return 1; /* hjm: Packet has no/incomplete transport layer headers. */

	if (inside_nexthdr != IPPROTO_TCP &&
	    inside_nexthdr != IPPROTO_UDP)
		return 1;

	ports = skb_header_pointer(skb, inside_hdrlen,
				   sizeof(_ports), &_ports);
	if (ports == NULL)
		return 1;

	/* the inside IP packet is the one quoted from our side, thus
	 * its saddr is the local address */
	*protocol = inside_nexthdr;
	*laddr = &inside_iph->saddr;
	*lport = ports[0];
	*raddr = &inside_iph->daddr;
	*rport = ports[1];

	return 0;
}

static struct sock *
xt_socket_get_sock_v6(struct net *net, struct sk_buff *skb, int doff,
		      const u8 protocol,
		      const struct in6_addr *saddr, const struct in6_addr *daddr,
		      const __be16 sport, const __be16 dport,
		      const struct net_device *in)
{
	switch (protocol) {
	case IPPROTO_TCP:
		return inet6_lookup(net, &tcp_hashinfo, skb, doff,
				    saddr, sport, daddr, dport,
				    in->ifindex);
	case IPPROTO_UDP:
		return udp6_lib_lookup(net, saddr, sport, daddr, dport,
				       in->ifindex);
	}

	return NULL;
}

static struct sock *xt_socket_lookup_slow_v6(struct net *net,
					     const struct sk_buff *skb,
					     const struct net_device *indev)
{
	__be16 uninitialized_var(dport), uninitialized_var(sport);
	const struct in6_addr *daddr = NULL, *saddr = NULL;
	struct ipv6hdr *iph = ipv6_hdr(skb);
	struct sk_buff *data_skb = NULL;
	int doff = 0;
	int thoff = 0, tproto;

	tproto = ipv6_find_hdr(skb, &thoff, -1, NULL, NULL);
	if (tproto < 0) {
		pr_debug("unable to find transport header in IPv6 packet, dropping\n");
		return NULL;
	}

	if (tproto == IPPROTO_UDP || tproto == IPPROTO_TCP) {
		struct udphdr _hdr, *hp;

		hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr);
		if (hp == NULL)
			return NULL;

		saddr = &iph->saddr;
		sport = hp->source;
		daddr = &iph->daddr;
		dport = hp->dest;
		data_skb = (struct sk_buff *)skb;
		doff = tproto == IPPROTO_TCP ?
			thoff + __tcp_hdrlen((struct tcphdr *)hp) :
			thoff + sizeof(*hp);

	} else if (tproto == IPPROTO_ICMPV6) {
		struct ipv6hdr ipv6_var;

		if (extract_icmp6_fields(skb, thoff, &tproto, &saddr, &daddr,
					 &sport, &dport, &ipv6_var))
			return NULL;
	} else {
		return NULL;
	}

	return xt_socket_get_sock_v6(net, data_skb, doff, tproto, saddr, daddr,
				     sport, dport, indev);
}
Example #13
0
/* Returns whether matches rule or not. */
static inline int
ip6_packet_match(const struct sk_buff *skb,
		 const char *indev,
		 const char *outdev,
		 const struct ip6t_ip6 *ip6info,
		 unsigned int *protoff,
		 int *fragoff, int *hotdrop)
{
	size_t i;
	unsigned long ret;
	const struct ipv6hdr *ipv6 = skb->nh.ipv6h;

#define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))

	if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk,
				       &ip6info->src), IP6T_INV_SRCIP)
	    || FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
					  &ip6info->dst), IP6T_INV_DSTIP)) {
		dprintf("Source or dest mismatch.\n");
/*
		dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
			ipinfo->smsk.s_addr, ipinfo->src.s_addr,
			ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
		dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
			ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
			ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
		return 0;
	}

	/* Look for ifname matches; this should unroll nicely. */
	for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
		ret |= (((const unsigned long *)indev)[i]
			^ ((const unsigned long *)ip6info->iniface)[i])
			& ((const unsigned long *)ip6info->iniface_mask)[i];
	}

	if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
		dprintf("VIA in mismatch (%s vs %s).%s\n",
			indev, ip6info->iniface,
			ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
		return 0;
	}

	for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
		ret |= (((const unsigned long *)outdev)[i]
			^ ((const unsigned long *)ip6info->outiface)[i])
			& ((const unsigned long *)ip6info->outiface_mask)[i];
	}

	if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
		dprintf("VIA out mismatch (%s vs %s).%s\n",
			outdev, ip6info->outiface,
			ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
		return 0;
	}

/* ... might want to do something with class and flowlabel here ... */

	/* look for the desired protocol header */
	if((ip6info->flags & IP6T_F_PROTO)) {
		int protohdr;
		unsigned short _frag_off;

		protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off);
		if (protohdr < 0) {
			if (_frag_off == 0)
				*hotdrop = 1;
			return 0;
		}
		*fragoff = _frag_off;

		dprintf("Packet protocol %hi ?= %s%hi.\n",
				protohdr,
				ip6info->invflags & IP6T_INV_PROTO ? "!":"",
				ip6info->proto);

		if (ip6info->proto == protohdr) {
			if(ip6info->invflags & IP6T_INV_PROTO) {
				return 0;
			}
			return 1;
		}

		/* We need match for the '-p all', too! */
		if ((ip6info->proto != 0) &&
			!(ip6info->invflags & IP6T_INV_PROTO))
			return 0;
	}
	return 1;
}
Example #14
0
static bool
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,
      bool *hotdrop)
{
	struct ipv6_rt_hdr _route;
	const struct ipv6_rt_hdr *rh;
	const struct ip6t_rt *rtinfo = matchinfo;
	unsigned int temp;
	unsigned int ptr;
	unsigned int hdrlen = 0;
	bool ret = false;
	struct in6_addr _addr;
	const struct in6_addr *ap;
	int err;

	err = ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING, NULL);
	if (err < 0) {
		if (err != -ENOENT)
			*hotdrop = true;
		return false;
	}

	rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route);
	if (rh == NULL) {
		*hotdrop = true;
		return false;
	}

	hdrlen = ipv6_optlen(rh);
	if (skb->len - ptr < hdrlen) {
		/* Pcket smaller than its length field */
		return false;
	}

	DEBUGP("IPv6 RT LEN %u %u ", hdrlen, rh->hdrlen);
	DEBUGP("TYPE %04X ", rh->type);
	DEBUGP("SGS_LEFT %u %02X\n", rh->segments_left, rh->segments_left);

	DEBUGP("IPv6 RT segsleft %02X ",
	       (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
			       rh->segments_left,
			       !!(rtinfo->invflags & IP6T_RT_INV_SGS))));
	DEBUGP("type %02X %02X %02X ",
	       rtinfo->rt_type, rh->type,
	       (!(rtinfo->flags & IP6T_RT_TYP) ||
		((rtinfo->rt_type == rh->type) ^
		 !!(rtinfo->invflags & IP6T_RT_INV_TYP))));
	DEBUGP("len %02X %04X %02X ",
	       rtinfo->hdrlen, hdrlen,
	       (!(rtinfo->flags & IP6T_RT_LEN) ||
		((rtinfo->hdrlen == hdrlen) ^
		 !!(rtinfo->invflags & IP6T_RT_INV_LEN))));
	DEBUGP("res %02X %02X %02X ",
	       (rtinfo->flags & IP6T_RT_RES),
	       ((const struct rt0_hdr *)rh)->reserved,
	       !((rtinfo->flags & IP6T_RT_RES) &&
		 (((const struct rt0_hdr *)rh)->reserved)));

	ret = (rh != NULL)
	      &&
	      (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
			      rh->segments_left,
			      !!(rtinfo->invflags & IP6T_RT_INV_SGS)))
	      &&
	      (!(rtinfo->flags & IP6T_RT_LEN) ||
	       ((rtinfo->hdrlen == hdrlen) ^
		!!(rtinfo->invflags & IP6T_RT_INV_LEN)))
	      &&
	      (!(rtinfo->flags & IP6T_RT_TYP) ||
	       ((rtinfo->rt_type == rh->type) ^
		!!(rtinfo->invflags & IP6T_RT_INV_TYP)));

	if (ret && (rtinfo->flags & IP6T_RT_RES)) {
		const u_int32_t *rp;
		u_int32_t _reserved;
		rp = skb_header_pointer(skb,
					ptr + offsetof(struct rt0_hdr,
						       reserved),
					sizeof(_reserved),
					&_reserved);

		ret = (*rp == 0);
	}

	DEBUGP("#%d ", rtinfo->addrnr);
	if (!(rtinfo->flags & IP6T_RT_FST)) {
		return ret;
	} else if (rtinfo->flags & IP6T_RT_FST_NSTRICT) {
		DEBUGP("Not strict ");
		if (rtinfo->addrnr > (unsigned int)((hdrlen - 8) / 16)) {
			DEBUGP("There isn't enough space\n");
			return false;
		} else {
			unsigned int i = 0;

			DEBUGP("#%d ", rtinfo->addrnr);
			for (temp = 0;
			     temp < (unsigned int)((hdrlen - 8) / 16);
			     temp++) {
				ap = skb_header_pointer(skb,
							ptr
							+ sizeof(struct rt0_hdr)
							+ temp * sizeof(_addr),
							sizeof(_addr),
							&_addr);

				BUG_ON(ap == NULL);

				if (ipv6_addr_equal(ap, &rtinfo->addrs[i])) {
					DEBUGP("i=%d temp=%d;\n", i, temp);
					i++;
				}
				if (i == rtinfo->addrnr)
					break;
			}
			DEBUGP("i=%d #%d\n", i, rtinfo->addrnr);
			if (i == rtinfo->addrnr)
				return ret;
			else
				return false;
		}
	} else {
		DEBUGP("Strict ");
		if (rtinfo->addrnr > (unsigned int)((hdrlen - 8) / 16)) {
			DEBUGP("There isn't enough space\n");
			return false;
		} else {
			DEBUGP("#%d ", rtinfo->addrnr);
			for (temp = 0; temp < rtinfo->addrnr; temp++) {
				ap = skb_header_pointer(skb,
							ptr
							+ sizeof(struct rt0_hdr)
							+ temp * sizeof(_addr),
							sizeof(_addr),
							&_addr);
				BUG_ON(ap == NULL);

				if (!ipv6_addr_equal(ap, &rtinfo->addrs[temp]))
					break;
			}
			DEBUGP("temp=%d #%d\n", temp, rtinfo->addrnr);
			if ((temp == rtinfo->addrnr) &&
			    (temp == (unsigned int)((hdrlen - 8) / 16)))
				return ret;
			else
				return false;
		}
	}

	return false;
}
int xtnu_ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
    int target, unsigned short *fragoff, int *fragflg)
{
	return ipv6_find_hdr(skb, offset, target, fragoff);
}
static int
match(const struct sk_buff *skb,
      const struct net_device *in,
      const struct net_device *out,
      const void *matchinfo,
      int offset,
      unsigned int protoff,
      int *hotdrop)
{
	struct ipv6_rt_hdr _route, *rh;
	const struct ip6t_rt *rtinfo = matchinfo;
	unsigned int temp;
	unsigned int ptr;
	unsigned int hdrlen = 0;
	unsigned int ret = 0;
	struct in6_addr *ap, _addr;
/* purpose     : Cisco CIAM Alert    author : Rain    date : 2011-07-06 */
/* description : Patch ip6t_rt.c 2.6.16.31  for Cisco CIAM Alert        */
	int err;

/* purpose     : Cisco CIAM Alert    author : Rain    date : 2011-07-06 */
/* description : Patch ip6t_rt.c 2.6.16.31  for Cisco CIAM Alert        */
	/*if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING, NULL) < 0)
		return 0;*/
	err = ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING, NULL);
	if (err < 0) {
		if (err != -ENOENT)
			*hotdrop = 1;
		return 0;
	}

	rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route);
	if (rh == NULL) {
		*hotdrop = 1;
		return 0;
	}

	hdrlen = ipv6_optlen(rh);
	if (skb->len - ptr < hdrlen) {
		/* Pcket smaller than its length field */
		return 0;
	}

	DEBUGP("IPv6 RT LEN %u %u ", hdrlen, rh->hdrlen);
	DEBUGP("TYPE %04X ", rh->type);
	DEBUGP("SGS_LEFT %u %02X\n", rh->segments_left, rh->segments_left);

	DEBUGP("IPv6 RT segsleft %02X ",
	       (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
			       rh->segments_left,
			       !!(rtinfo->invflags & IP6T_RT_INV_SGS))));
	DEBUGP("type %02X %02X %02X ",
	       rtinfo->rt_type, rh->type,
	       (!(rtinfo->flags & IP6T_RT_TYP) ||
		((rtinfo->rt_type == rh->type) ^
		 !!(rtinfo->invflags & IP6T_RT_INV_TYP))));
	DEBUGP("len %02X %04X %02X ",
	       rtinfo->hdrlen, hdrlen,
	       (!(rtinfo->flags & IP6T_RT_LEN) ||
		((rtinfo->hdrlen == hdrlen) ^
		 !!(rtinfo->invflags & IP6T_RT_INV_LEN))));
	DEBUGP("res %02X %02X %02X ",
	       (rtinfo->flags & IP6T_RT_RES),
	       ((struct rt0_hdr *)rh)->reserved,
	       !((rtinfo->flags & IP6T_RT_RES) &&
		 (((struct rt0_hdr *)rh)->reserved)));

	ret = (rh != NULL)
	      &&
	      (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
			      rh->segments_left,
			      !!(rtinfo->invflags & IP6T_RT_INV_SGS)))
	      &&
	      (!(rtinfo->flags & IP6T_RT_LEN) ||
	       ((rtinfo->hdrlen == hdrlen) ^
		!!(rtinfo->invflags & IP6T_RT_INV_LEN)))
	      &&
	      (!(rtinfo->flags & IP6T_RT_TYP) ||
	       ((rtinfo->rt_type == rh->type) ^
		!!(rtinfo->invflags & IP6T_RT_INV_TYP)));

	if (ret && (rtinfo->flags & IP6T_RT_RES)) {
		u_int32_t *rp, _reserved;
		rp = skb_header_pointer(skb,
					ptr + offsetof(struct rt0_hdr,
						       reserved),
					sizeof(_reserved),
					&_reserved);

		ret = (*rp == 0);
	}
Example #17
0
static bool srh_mt6(const struct sk_buff *skb, struct xt_action_param *par)
{
	const struct ip6t_srh *srhinfo = par->matchinfo;
	struct ipv6_sr_hdr *srh;
	struct ipv6_sr_hdr _srh;
	int hdrlen, srhoff = 0;

	if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, NULL) < 0)
		return false;
	srh = skb_header_pointer(skb, srhoff, sizeof(_srh), &_srh);
	if (!srh)
		return false;

	hdrlen = ipv6_optlen(srh);
	if (skb->len - srhoff < hdrlen)
		return false;

	if (srh->type != IPV6_SRCRT_TYPE_4)
		return false;

	if (srh->segments_left > srh->first_segment)
		return false;

	/* Next Header matching */
	if (srhinfo->mt_flags & IP6T_SRH_NEXTHDR)
		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_NEXTHDR,
				!(srh->nexthdr == srhinfo->next_hdr)))
			return false;

	/* Header Extension Length matching */
	if (srhinfo->mt_flags & IP6T_SRH_LEN_EQ)
		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LEN_EQ,
				!(srh->hdrlen == srhinfo->hdr_len)))
			return false;

	if (srhinfo->mt_flags & IP6T_SRH_LEN_GT)
		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LEN_GT,
				!(srh->hdrlen > srhinfo->hdr_len)))
			return false;

	if (srhinfo->mt_flags & IP6T_SRH_LEN_LT)
		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LEN_LT,
				!(srh->hdrlen < srhinfo->hdr_len)))
			return false;

	/* Segments Left matching */
	if (srhinfo->mt_flags & IP6T_SRH_SEGS_EQ)
		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_SEGS_EQ,
				!(srh->segments_left == srhinfo->segs_left)))
			return false;

	if (srhinfo->mt_flags & IP6T_SRH_SEGS_GT)
		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_SEGS_GT,
				!(srh->segments_left > srhinfo->segs_left)))
			return false;

	if (srhinfo->mt_flags & IP6T_SRH_SEGS_LT)
		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_SEGS_LT,
				!(srh->segments_left < srhinfo->segs_left)))
			return false;

	/**
	 * Last Entry matching
	 * Last_Entry field was introduced in revision 6 of the SRH draft.
	 * It was called First_Segment in the previous revision
	 */
	if (srhinfo->mt_flags & IP6T_SRH_LAST_EQ)
		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LAST_EQ,
				!(srh->first_segment == srhinfo->last_entry)))
			return false;

	if (srhinfo->mt_flags & IP6T_SRH_LAST_GT)
		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LAST_GT,
				!(srh->first_segment > srhinfo->last_entry)))
			return false;

	if (srhinfo->mt_flags & IP6T_SRH_LAST_LT)
		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LAST_LT,
				!(srh->first_segment < srhinfo->last_entry)))
			return false;

	/**
	 * Tag matchig
	 * Tag field was introduced in revision 6 of the SRH draft.
	 */
	if (srhinfo->mt_flags & IP6T_SRH_TAG)
		if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_TAG,
				!(srh->tag == srhinfo->tag)))
			return false;
	return true;
}
Example #18
0
static bool
socket_mt6_v1(const struct sk_buff *skb, struct xt_action_param *par)
{
	struct ipv6hdr *iph = ipv6_hdr(skb);
	struct udphdr _hdr, *hp = NULL;
	struct sock *sk;
	struct in6_addr *daddr, *saddr;
	__be16 dport, sport;
	int thoff = 0, tproto;
	const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo;

	tproto = ipv6_find_hdr(skb, &thoff, -1, NULL, NULL);
	if (tproto < 0) {
		pr_debug("unable to find transport header in IPv6 packet, dropping\n");
		return NF_DROP;
	}

	if (tproto == IPPROTO_UDP || tproto == IPPROTO_TCP) {
		hp = skb_header_pointer(skb, thoff,
					sizeof(_hdr), &_hdr);
		if (hp == NULL)
			return false;

		saddr = &iph->saddr;
		sport = hp->source;
		daddr = &iph->daddr;
		dport = hp->dest;

	} else if (tproto == IPPROTO_ICMPV6) {
		if (extract_icmp6_fields(skb, thoff, &tproto, &saddr, &daddr,
					 &sport, &dport))
			return false;
	} else {
		return false;
	}

	sk = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto,
				   saddr, daddr, sport, dport, par->in, NFT_LOOKUP_ANY);
	if (sk != NULL) {
		bool wildcard;
		bool transparent = true;

		/* Ignore sockets listening on INADDR_ANY */
		wildcard = (sk->sk_state != TCP_TIME_WAIT &&
			    ipv6_addr_any(&inet6_sk(sk)->rcv_saddr));

		/* Ignore non-transparent sockets,
		   if XT_SOCKET_TRANSPARENT is used */
		if (info && info->flags & XT_SOCKET_TRANSPARENT)
			transparent = ((sk->sk_state != TCP_TIME_WAIT &&
					inet_sk(sk)->transparent) ||
				       (sk->sk_state == TCP_TIME_WAIT &&
					inet_twsk(sk)->tw_transparent));

		xt_socket_put_sk(sk);

		if (wildcard || !transparent)
			sk = NULL;
	}

	pr_debug("proto %hhd %pI6:%hu -> %pI6:%hu "
		 "(orig %pI6:%hu) sock %p\n",
		 tproto, saddr, ntohs(sport),
		 daddr, ntohs(dport),
		 &iph->daddr, hp ? ntohs(hp->dest) : 0, sk);

	return (sk != NULL);
}
Example #19
0
/* Returns whether matches rule or not. */
static inline bool
ip6_packet_match(const struct sk_buff *skb,
		 const char *indev,
		 const char *outdev,
		 const struct ip6t_ip6 *ip6info,
		 unsigned int *protoff,
		 int *fragoff, bool *hotdrop)
{
	unsigned long ret;
	const struct ipv6hdr *ipv6 = ipv6_hdr(skb);

#define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))

	if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk,
				       &ip6info->src), IP6T_INV_SRCIP)
	    || FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
					  &ip6info->dst), IP6T_INV_DSTIP)) {
		dprintf("Source or dest mismatch.\n");
/*
		dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
			ipinfo->smsk.s_addr, ipinfo->src.s_addr,
			ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
		dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
			ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
			ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
		return false;
	}

	ret = ifname_compare_aligned(indev, ip6info->iniface, ip6info->iniface_mask);

	if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
		dprintf("VIA in mismatch (%s vs %s).%s\n",
			indev, ip6info->iniface,
			ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
		return false;
	}

	ret = ifname_compare_aligned(outdev, ip6info->outiface, ip6info->outiface_mask);

	if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
		dprintf("VIA out mismatch (%s vs %s).%s\n",
			outdev, ip6info->outiface,
			ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
		return false;
	}

/* ... might want to do something with class and flowlabel here ... */

	/* look for the desired protocol header */
	if((ip6info->flags & IP6T_F_PROTO)) {
		int protohdr;
		unsigned short _frag_off;

		protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off);
		if (protohdr < 0) {
			if (_frag_off == 0)
				*hotdrop = true;
			return false;
		}
		*fragoff = _frag_off;

		dprintf("Packet protocol %hi ?= %s%hi.\n",
				protohdr,
				ip6info->invflags & IP6T_INV_PROTO ? "!":"",
				ip6info->proto);

		if (ip6info->proto == protohdr) {
			if(ip6info->invflags & IP6T_INV_PROTO) {
				return false;
			}
			return true;
		}

		/* We need match for the '-p all', too! */
		if ((ip6info->proto != 0) &&
			!(ip6info->invflags & IP6T_INV_PROTO))
			return false;
	}
	return true;
}
Example #20
0
static int
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 frag_hdr _frag, *fh;
	const struct ip6t_frag *fraginfo = matchinfo;
	unsigned int ptr;

	if (ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT, NULL) < 0)
		return 0;

	fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag);
	if (fh == NULL) {
		*hotdrop = 1;
		return 0;
	}

	DEBUGP("INFO %04X ", fh->frag_off);
	DEBUGP("OFFSET %04X ", ntohs(fh->frag_off) & ~0x7);
	DEBUGP("RES %02X %04X", fh->reserved, ntohs(fh->frag_off) & 0x6);
	DEBUGP("MF %04X ", fh->frag_off & htons(IP6_MF));
	DEBUGP("ID %u %08X\n", ntohl(fh->identification),
	       ntohl(fh->identification));

	DEBUGP("IPv6 FRAG id %02X ",
	       (id_match(fraginfo->ids[0], fraginfo->ids[1],
			 ntohl(fh->identification),
			 !!(fraginfo->invflags & IP6T_FRAG_INV_IDS))));
	DEBUGP("res %02X %02X%04X %02X ",
	       (fraginfo->flags & IP6T_FRAG_RES), fh->reserved,
	       ntohs(fh->frag_off) & 0x6,
	       !((fraginfo->flags & IP6T_FRAG_RES)
		 && (fh->reserved || (ntohs(fh->frag_off) & 0x06))));
	DEBUGP("first %02X %02X %02X ",
	       (fraginfo->flags & IP6T_FRAG_FST),
	       ntohs(fh->frag_off) & ~0x7,
	       !((fraginfo->flags & IP6T_FRAG_FST)
		 && (ntohs(fh->frag_off) & ~0x7)));
	DEBUGP("mf %02X %02X %02X ",
	       (fraginfo->flags & IP6T_FRAG_MF),
	       ntohs(fh->frag_off) & IP6_MF,
	       !((fraginfo->flags & IP6T_FRAG_MF)
		 && !((ntohs(fh->frag_off) & IP6_MF))));
	DEBUGP("last %02X %02X %02X\n",
	       (fraginfo->flags & IP6T_FRAG_NMF),
	       ntohs(fh->frag_off) & IP6_MF,
	       !((fraginfo->flags & IP6T_FRAG_NMF)
		 && (ntohs(fh->frag_off) & IP6_MF)));

	return (fh != NULL)
	       &&
	       (id_match(fraginfo->ids[0], fraginfo->ids[1],
			 ntohl(fh->identification),
			 !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)))
	       &&
	       !((fraginfo->flags & IP6T_FRAG_RES)
		 && (fh->reserved || (ntohs(fh->frag_off) & 0x6)))
	       &&
	       !((fraginfo->flags & IP6T_FRAG_FST)
		 && (ntohs(fh->frag_off) & ~0x7))
	       &&
	       !((fraginfo->flags & IP6T_FRAG_MF)
		 && !(ntohs(fh->frag_off) & IP6_MF))
	       &&
	       !((fraginfo->flags & IP6T_FRAG_NMF)
		 && (ntohs(fh->frag_off) & IP6_MF));
}
Example #21
0
static unsigned int
tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par)
{
	const struct ipv6hdr *iph = ipv6_hdr(skb);
	const struct xt_tproxy_target_info_v1 *tgi = par->targinfo;
	struct udphdr _hdr, *hp;
	struct sock *sk;
	const struct in6_addr *laddr;
	__be16 lport;
	int thoff = 0;
	int tproto;

	tproto = ipv6_find_hdr(skb, &thoff, -1, NULL, NULL);
	if (tproto < 0) {
		pr_debug("unable to find transport header in IPv6 packet, dropping\n");
		return NF_DROP;
	}

	hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr);
	if (hp == NULL) {
		pr_debug("unable to grab transport header contents in IPv6 packet, dropping\n");
		return NF_DROP;
	}

	/* check if there's an ongoing connection on the packet
	 * addresses, this happens if the redirect already happened
	 * and the current packet belongs to an already established
	 * connection */
	sk = nf_tproxy_get_sock_v6(xt_net(par), skb, thoff, tproto,
				   &iph->saddr, &iph->daddr,
				   hp->source, hp->dest,
				   xt_in(par), NF_TPROXY_LOOKUP_ESTABLISHED);

	laddr = nf_tproxy_laddr6(skb, &tgi->laddr.in6, &iph->daddr);
	lport = tgi->lport ? tgi->lport : hp->dest;

	/* UDP has no TCP_TIME_WAIT state, so we never enter here */
	if (sk && sk->sk_state == TCP_TIME_WAIT) {
		const struct xt_tproxy_target_info_v1 *tgi = par->targinfo;
		/* reopening a TIME_WAIT connection needs special handling */
		sk = nf_tproxy_handle_time_wait6(skb, tproto, thoff,
					      xt_net(par),
					      &tgi->laddr.in6,
					      tgi->lport,
					      sk);
	}
	else if (!sk)
		/* no there's no established connection, check if
		 * there's a listener on the redirected addr/port */
		sk = nf_tproxy_get_sock_v6(xt_net(par), skb, thoff,
					   tproto, &iph->saddr, laddr,
					   hp->source, lport,
					   xt_in(par), NF_TPROXY_LOOKUP_LISTENER);

	/* NOTE: assign_sock consumes our sk reference */
	if (sk && nf_tproxy_sk_is_transparent(sk)) {
		/* This should be in a separate target, but we don't do multiple
		   targets on the same rule yet */
		skb->mark = (skb->mark & ~tgi->mark_mask) ^ tgi->mark_value;

		pr_debug("redirecting: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n",
			 tproto, &iph->saddr, ntohs(hp->source),
			 laddr, ntohs(lport), skb->mark);

		nf_tproxy_assign_sock(skb, sk);
		return NF_ACCEPT;
	}

	pr_debug("no socket, dropping: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n",
		 tproto, &iph->saddr, ntohs(hp->source),
		 &iph->daddr, ntohs(hp->dest), skb->mark);

	return NF_DROP;
}