Handling loopback interface in IPv6 stack
I read a few months ago or even more, that IPv6 stack is handling loopback differently than IPv4. In other words, it allows sources with ::1
as the real candidate from outside.
I checked kernel 4.8 sources and it has such a code for handling this only for the destination address. Basically, it checks if the destination address isn’t loopback.
int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
{
...
if (!(dev->flags & IFF_LOOPBACK) &&
ipv6_addr_loopback(&hdr->daddr))
goto err;
...
}
while IPv4 stack has:
static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
u8 tos, struct net_device *dev)
{
...
if (ipv4_is_loopback(daddr)) {
if (!IN_DEV_NET_ROUTE_LOCALNET(in_dev, net))
goto martian_destination;
} else if (ipv4_is_loopback(saddr)) {
if (!IN_DEV_NET_ROUTE_LOCALNET(in_dev, net))
goto martian_source;
}
...
}
According to this, I’m able to send packets from outside (maybe local network would be more accurate regarding other reverse path filterings) interface with source as “originated from ::1”. Looks promising ;-)
I’m not sure if it would be enough to introduce additional check for source address using the same way as with destination like (assuming that I don’t have any free time for kinda hobby contributions):
ipv6_addr_loopback(&hdr->daddr) || ipv6_addr_loopback(&hdr->saddr)
But in general, it looks it could be solved trivially.
The current solution for this sort of “bug” is to filter out those abnormal packets using netfilter:
ip6tables -A INPUT -s ::1 -d ::1 -i lo -j ACCEPT
ip6tables -A INPUT -s ::1 -j DROP
Conclusion
- I’m still surprised - why it’s still not fixed, while it’s really not a big deal?;
- There is no synchronization between IPv4 and IPv6 stacks in Linux kernel.