mirror of
				https://github.com/Telecominfraproject/wlan-ap.git
				synced 2025-10-31 18:38:10 +00:00 
			
		
		
		
	spotfilter: discover ip address via ARP
Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
		 Felix Fietkau
					Felix Fietkau
				
			
				
					committed by
					
						 John Crispin
						John Crispin
					
				
			
			
				
	
			
			
			 John Crispin
						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