Contrôle du trafic ARP sous Linux : arp_ignore, arp_filter et rp_filter

Ordre de traitement dans le noyau

Lorsqu'une requête ARP arrive, le noyau évalue d'abord arp_ignore. Si celui-ci autorise une réponse, le code vérifie ensuite, si arp_filter est activé, que le chemin de retour emprunterait bien l'interface sur laquelle la requête a été reçue. Le fragment suivant illustre cette logique :

int refuse = arp_ignore(in_dev, src_ip, dst_ip);

if (!refuse && IN_DEV_ARPFILTER(in_dev))
    refuse = arp_filter(src_ip, dst_ip, dev);

if (refuse)
    goto out_consume_skb;

struct neighbour *n = neigh_event_ns(&arp_tbl, sha, &src_ip, dev);
if (n) {
    arp_send_dst(ARPOP_REPLY, ETH_P_ARP,
                 src_ip, dev, dst_ip, sha,
                 dev->dev_addr, sha, reply_dst);
    neigh_release(n);
}
goto out_consume_skb;

Rôle de arp_filter

arp_filter réalise une vérification de routage inverse au niveau ARP. Il consulte la table de routage pour connaître l'interface qui serait utilisée pour atteindre l'adresse source depuis l'adresse destinasion. Si l'interface obtenue diffère de celle ayant reçu la requête, la réponse est bloquée. Une implémentation équivalente est :

static int arp_filter(__be32 src, __be32 dst, struct net_device *netdev)
{
    struct rtable *route;
    struct net *net = dev_net(netdev);
    int reject = 0;

    route = ip_route_output(net, src, dst, 0, 0);
    if (IS_ERR(route))
        return 1;

    if (route->dst.dev != netdev) {
        __NET_INC_STATS(net, LINUX_MIB_ARPFILTER);
        reject = 1;
    }

    ip_rt_put(route);
    return reject;
}

Différence avec rp_filter

rp_filter effectue également une vérification de routage inverse, mais au niveau IP, après que le paquet a atteint la couche réseau. ARP, quant à lui, est situé en dessous de la couche IP ; il n'a donc pas accès aux mécanismes de rp_filter. C'est pourquoi arp_filter existe comme contrepartie ARP du reverse-path filtering.

Cas d'usage : interfaces multiples dans le même sous-réseau

Ces paramètres devinenent pertinents lorsqu'une même machine dispose de plusieurs cartes réseau connectées à un seul et même sous-réseau. Sans filtrage, le noyau pourrait répondre à une requête ARP sur une interface alors que le chemin de retour des paquets passerait par une autre, conduisant à des asymétries de trafic difficiles à diagnostiquer. arp_filter permet de forcer la cohérence entre l'interface d'entrée et l'interface de sortie prévue par le routage.

Étiquettes: Linux kernel ARP rp_filter arp_filter arp_ignore

Publié le 16 août à 02h51