mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-10-30 18:07:52 +00:00
spotfilter: discover ip address via ARP
Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
committed by
John Crispin
parent
de425e8f17
commit
ae9d1b64c3
@@ -12,6 +12,7 @@
|
||||
struct cache_entry {
|
||||
struct avl_node node;
|
||||
uint8_t macaddr[ETH_ALEN];
|
||||
uint32_t arp_ip4addr;
|
||||
uint32_t ip4addr;
|
||||
uint32_t ip6addr[4];
|
||||
uint32_t time;
|
||||
@@ -144,6 +145,8 @@ int client_set(struct interface *iface, const void *addr, const char *id,
|
||||
if (c) {
|
||||
if (!cl->data.ip4addr)
|
||||
cl->data.ip4addr = c->ip4addr;
|
||||
if (!cl->arp_ip4addr)
|
||||
cl->arp_ip4addr = c->arp_ip4addr;
|
||||
if (!cl->data.ip6addr[0])
|
||||
memcpy(cl->data.ip6addr, c->ip6addr, sizeof(cl->data.ip6addr));
|
||||
}
|
||||
@@ -186,25 +189,38 @@ int client_set(struct interface *iface, const void *addr, const char *id,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void client_set_ipaddr(const void *mac, const void *addr, bool ipv6)
|
||||
static struct cache_entry *
|
||||
client_get_cache_entry(const void *mac)
|
||||
{
|
||||
static struct uloop_timeout gc_timer = {
|
||||
.cb = client_gc
|
||||
};
|
||||
struct cache_entry *c;
|
||||
|
||||
c = avl_find_element(&cache, mac, c, node);
|
||||
if (c)
|
||||
goto out;
|
||||
|
||||
c = calloc(1, sizeof(*c));
|
||||
memcpy(c->macaddr, mac, ETH_ALEN);
|
||||
c->node.key = c->macaddr;
|
||||
avl_insert(&cache, &c->node);
|
||||
if (!gc_timer.pending)
|
||||
uloop_timeout_set(&gc_timer, CACHE_TIMEOUT * 1000);
|
||||
|
||||
out:
|
||||
c->time = client_gettime();
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void client_set_ipaddr(const void *mac, const void *addr, bool ipv6)
|
||||
{
|
||||
struct interface *iface;
|
||||
struct cache_entry *c;
|
||||
struct client *cl;
|
||||
|
||||
c = avl_find_element(&cache, mac, c, node);
|
||||
if (!c) {
|
||||
c = calloc(1, sizeof(*c));
|
||||
memcpy(c->macaddr, mac, ETH_ALEN);
|
||||
c->node.key = c->macaddr;
|
||||
avl_insert(&cache, &c->node);
|
||||
if (!gc_timer.pending)
|
||||
uloop_timeout_set(&gc_timer, CACHE_TIMEOUT * 1000);
|
||||
}
|
||||
|
||||
c = client_get_cache_entry(mac);
|
||||
if (!ipv6 && !c->ip4addr)
|
||||
memcpy(&c->ip4addr, addr, sizeof(c->ip4addr));
|
||||
else if (ipv6 && !c->ip6addr[0])
|
||||
@@ -212,8 +228,6 @@ void client_set_ipaddr(const void *mac, const void *addr, bool ipv6)
|
||||
else
|
||||
return;
|
||||
|
||||
c->time = client_gettime();
|
||||
|
||||
avl_for_each_element(&interfaces, iface, node) {
|
||||
cl = avl_find_element(&iface->clients, mac, cl, node);
|
||||
if (!cl)
|
||||
@@ -231,3 +245,21 @@ void client_set_ipaddr(const void *mac, const void *addr, bool ipv6)
|
||||
spotfilter_bpf_set_client(iface, &cl->key, &cl->data);
|
||||
}
|
||||
}
|
||||
|
||||
void client_set_arp_ipaddr(const void *mac, const void *addr)
|
||||
{
|
||||
struct interface *iface;
|
||||
struct cache_entry *c;
|
||||
struct client *cl;
|
||||
|
||||
c = client_get_cache_entry(mac);
|
||||
memcpy(&c->arp_ip4addr, addr, sizeof(c->arp_ip4addr));
|
||||
|
||||
avl_for_each_element(&interfaces, iface, node) {
|
||||
cl = avl_find_element(&iface->clients, mac, cl, node);
|
||||
if (!cl)
|
||||
continue;
|
||||
|
||||
cl->arp_ip4addr = c->arp_ip4addr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ struct client {
|
||||
struct kvlist kvdata;
|
||||
int idle;
|
||||
|
||||
uint32_t arp_ip4addr;
|
||||
struct spotfilter_client_key key;
|
||||
struct spotfilter_client_data data;
|
||||
char *device;
|
||||
@@ -25,6 +26,7 @@ int client_set(struct interface *iface, const void *addr, const char *id,
|
||||
const char *device, bool flush);
|
||||
void client_free(struct interface *iface, struct client *cl);
|
||||
void client_set_ipaddr(const void *mac, const void *addr, bool ipv6);
|
||||
void client_set_arp_ipaddr(const void *mac, const void *addr);
|
||||
void client_init_interface(struct interface *iface);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <netinet/udp.h>
|
||||
#include <netpacket/packet.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
@@ -48,6 +49,20 @@ int spotfilter_ifb_ifindex;
|
||||
static struct uloop_fd ufd;
|
||||
static struct uloop_timeout cname_gc_timer;
|
||||
|
||||
struct arp_packet {
|
||||
uint16_t hwtype;
|
||||
uint16_t proto;
|
||||
uint8_t h_size;
|
||||
uint8_t p_size;
|
||||
uint16_t op;
|
||||
|
||||
uint8_t src_mac[ETH_ALEN];
|
||||
uint8_t src_ip[4];
|
||||
|
||||
uint8_t dest_mac[ETH_ALEN];
|
||||
uint8_t dest_ip[4];
|
||||
};
|
||||
|
||||
struct vlan_hdr {
|
||||
uint16_t tci;
|
||||
uint16_t proto;
|
||||
@@ -395,6 +410,7 @@ spotfilter_packet_cb(struct packet *pkt)
|
||||
struct ip6_hdr *ip6;
|
||||
struct ip *ip;
|
||||
struct udphdr *udp;
|
||||
struct arp_packet *arp;
|
||||
bool ipv4;
|
||||
|
||||
eth = pkt_pull(pkt, sizeof(*eth));
|
||||
@@ -413,6 +429,19 @@ spotfilter_packet_cb(struct packet *pkt)
|
||||
}
|
||||
|
||||
switch (proto) {
|
||||
case ETH_P_ARP:
|
||||
arp = pkt_peek(pkt, sizeof(*arp));
|
||||
if (!arp)
|
||||
break;
|
||||
|
||||
if (arp->hwtype != cpu_to_be16(1) ||
|
||||
arp->proto != cpu_to_be16(0x800) ||
|
||||
arp->h_size != 6 || arp->p_size != 4 ||
|
||||
arp->op != cpu_to_be16(1))
|
||||
break;
|
||||
|
||||
client_set_arp_ipaddr(eth->h_source, &arp->src_ip);
|
||||
break;
|
||||
case ETH_P_IP:
|
||||
ip = pkt_peek(pkt, sizeof(struct ip));
|
||||
if (!ip)
|
||||
|
||||
@@ -227,8 +227,11 @@ int spotfilter_in(struct __sk_buff *skb)
|
||||
|
||||
if (!is_control)
|
||||
wl_val = bpf_map_lookup_elem(&whitelist_ipv6, &ip6h->daddr);
|
||||
} else if (info.proto == bpf_htons(ETH_P_ARP)) {
|
||||
bpf_clone_redirect(skb, config.snoop_ifindex, BPF_F_INGRESS);
|
||||
return TC_ACT_UNSPEC;
|
||||
} else {
|
||||
return TC_ACT_UNSPEC;
|
||||
return TC_ACT_UNSPEC;
|
||||
}
|
||||
|
||||
if (wl_val) {
|
||||
|
||||
@@ -257,6 +257,12 @@ static void client_dump(struct interface *iface, struct client *cl)
|
||||
if (cl->id_node.key)
|
||||
blobmsg_add_string(&b, "id", (const char *)cl->id_node.key);
|
||||
|
||||
if (cl->arp_ip4addr) {
|
||||
buf = blobmsg_alloc_string_buffer(&b, "arp_ip4addr", INET6_ADDRSTRLEN);
|
||||
inet_ntop(AF_INET, (const void *)&cl->arp_ip4addr, buf, INET6_ADDRSTRLEN);
|
||||
blobmsg_add_string_buffer(&b);
|
||||
}
|
||||
|
||||
if (cl->data.ip4addr) {
|
||||
buf = blobmsg_alloc_string_buffer(&b, "ip4addr", INET6_ADDRSTRLEN);
|
||||
inet_ntop(AF_INET, (const void *)&cl->data.ip4addr, buf, INET6_ADDRSTRLEN);
|
||||
|
||||
Reference in New Issue
Block a user