@@ -29,15 +29,33 @@ static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops,
unsigned int ret;
struct nft_pktinfo pkt;
u32 mark;
+ __be32 saddr, daddr;
+ u_int8_t tos;
+ const struct iphdr *iph;
nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out);
- // FIXME: length validation
+ /* root is playing with raw sockets. */
+ if (skb->len < sizeof(struct iphdr) ||
+ ip_hdrlen(skb) < sizeof(struct iphdr))
+ return NF_ACCEPT;
+
mark = skb->mark;
+ iph = ip_hdr(skb);
+ saddr = iph->saddr;
+ daddr = iph->daddr;
+ tos = iph->tos;
+
ret = nft_do_chain_pktinfo(&pkt, ops);
if (ret != NF_DROP && ret != NF_QUEUE) {
- if (skb->mark != mark && ip_route_me_harder(skb, RTN_UNSPEC))
- ret = NF_DROP;
+ iph = ip_hdr(skb);
+
+ if (iph->saddr != saddr ||
+ iph->daddr != daddr ||
+ skb->mark != mark ||
+ iph->tos != tos)
+ if (ip_route_me_harder(skb, RTN_UNSPEC))
+ ret = NF_DROP;
}
return ret;
}
@@ -30,17 +30,31 @@ static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops,
{
unsigned int ret;
struct nft_pktinfo pkt;
- u32 mark;
+ struct in6_addr saddr, daddr;
+ u_int8_t hop_limit;
+ u32 mark, flowlabel;
if (nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out) < 0)
return NF_DROP;
+ /* save source/dest address, mark, hoplimit, flowlabel, priority */
+ memcpy(&saddr, &ipv6_hdr(skb)->saddr, sizeof(saddr));
+ memcpy(&daddr, &ipv6_hdr(skb)->daddr, sizeof(daddr));
mark = skb->mark;
+ hop_limit = ipv6_hdr(skb)->hop_limit;
+
+ /* flowlabel and prio (includes version, which shouldn't change either */
+ flowlabel = *((u32 *)ipv6_hdr(skb));
+
ret = nft_do_chain_pktinfo(&pkt, ops);
- if (ret != NF_DROP && ret != NF_QUEUE) {
- if (skb->mark != mark && ip6_route_me_harder(skb))
- ret = NF_DROP;
- }
+ if (ret != NF_DROP && ret != NF_QUEUE &&
+ (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) ||
+ memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) ||
+ skb->mark != mark ||
+ ipv6_hdr(skb)->hop_limit != hop_limit ||
+ flowlabel != *((u_int32_t *)ipv6_hdr(skb))))
+ return ip6_route_me_harder(skb) == 0 ? ret : NF_DROP;
+
return ret;
}