mirror of
				https://github.com/Telecominfraproject/wlan-ap.git
				synced 2025-10-31 02:17:58 +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 cache_entry { | ||||||
| 	struct avl_node node; | 	struct avl_node node; | ||||||
| 	uint8_t macaddr[ETH_ALEN]; | 	uint8_t macaddr[ETH_ALEN]; | ||||||
|  | 	uint32_t arp_ip4addr; | ||||||
| 	uint32_t ip4addr; | 	uint32_t ip4addr; | ||||||
| 	uint32_t ip6addr[4]; | 	uint32_t ip6addr[4]; | ||||||
| 	uint32_t time; | 	uint32_t time; | ||||||
| @@ -144,6 +145,8 @@ int client_set(struct interface *iface, const void *addr, const char *id, | |||||||
| 	if (c) { | 	if (c) { | ||||||
| 		if (!cl->data.ip4addr) | 		if (!cl->data.ip4addr) | ||||||
| 			cl->data.ip4addr = c->ip4addr; | 			cl->data.ip4addr = c->ip4addr; | ||||||
|  | 		if (!cl->arp_ip4addr) | ||||||
|  | 			cl->arp_ip4addr = c->arp_ip4addr; | ||||||
| 		if (!cl->data.ip6addr[0]) | 		if (!cl->data.ip6addr[0]) | ||||||
| 			memcpy(cl->data.ip6addr, c->ip6addr, sizeof(cl->data.ip6addr)); | 			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; | 	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 = { | 	static struct uloop_timeout gc_timer = { | ||||||
| 		.cb = client_gc | 		.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 interface *iface; | ||||||
| 	struct cache_entry *c; | 	struct cache_entry *c; | ||||||
| 	struct client *cl; | 	struct client *cl; | ||||||
|  |  | ||||||
| 	c = avl_find_element(&cache, mac, c, node); | 	c = client_get_cache_entry(mac); | ||||||
| 	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); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (!ipv6 && !c->ip4addr) | 	if (!ipv6 && !c->ip4addr) | ||||||
| 		memcpy(&c->ip4addr, addr, sizeof(c->ip4addr)); | 		memcpy(&c->ip4addr, addr, sizeof(c->ip4addr)); | ||||||
| 	else if (ipv6 && !c->ip6addr[0]) | 	else if (ipv6 && !c->ip6addr[0]) | ||||||
| @@ -212,8 +228,6 @@ void client_set_ipaddr(const void *mac, const void *addr, bool ipv6) | |||||||
| 	else | 	else | ||||||
| 		return; | 		return; | ||||||
|  |  | ||||||
| 	c->time = client_gettime(); |  | ||||||
|  |  | ||||||
| 	avl_for_each_element(&interfaces, iface, node) { | 	avl_for_each_element(&interfaces, iface, node) { | ||||||
| 		cl = avl_find_element(&iface->clients, mac, cl, node); | 		cl = avl_find_element(&iface->clients, mac, cl, node); | ||||||
| 		if (!cl) | 		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); | 		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; | 	struct kvlist kvdata; | ||||||
| 	int idle; | 	int idle; | ||||||
|  |  | ||||||
|  | 	uint32_t arp_ip4addr; | ||||||
| 	struct spotfilter_client_key key; | 	struct spotfilter_client_key key; | ||||||
| 	struct spotfilter_client_data data; | 	struct spotfilter_client_data data; | ||||||
| 	char *device; | 	char *device; | ||||||
| @@ -25,6 +26,7 @@ int client_set(struct interface *iface, const void *addr, const char *id, | |||||||
| 	       const char *device, bool flush); | 	       const char *device, bool flush); | ||||||
| void client_free(struct interface *iface, struct client *cl); | void client_free(struct interface *iface, struct client *cl); | ||||||
| void client_set_ipaddr(const void *mac, const void *addr, bool ipv6); | 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); | void client_init_interface(struct interface *iface); | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ | |||||||
| #include <netinet/udp.h> | #include <netinet/udp.h> | ||||||
| #include <netpacket/packet.h> | #include <netpacket/packet.h> | ||||||
| #include <net/if.h> | #include <net/if.h> | ||||||
|  | #include <net/if_arp.h> | ||||||
| #include <arpa/inet.h> | #include <arpa/inet.h> | ||||||
| #include <sys/socket.h> | #include <sys/socket.h> | ||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
| @@ -48,6 +49,20 @@ int spotfilter_ifb_ifindex; | |||||||
| static struct uloop_fd ufd; | static struct uloop_fd ufd; | ||||||
| static struct uloop_timeout cname_gc_timer; | 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 { | struct vlan_hdr { | ||||||
| 	uint16_t tci; | 	uint16_t tci; | ||||||
| 	uint16_t proto; | 	uint16_t proto; | ||||||
| @@ -395,6 +410,7 @@ spotfilter_packet_cb(struct packet *pkt) | |||||||
| 	struct ip6_hdr *ip6; | 	struct ip6_hdr *ip6; | ||||||
| 	struct ip *ip; | 	struct ip *ip; | ||||||
| 	struct udphdr *udp; | 	struct udphdr *udp; | ||||||
|  | 	struct arp_packet *arp; | ||||||
| 	bool ipv4; | 	bool ipv4; | ||||||
|  |  | ||||||
| 	eth = pkt_pull(pkt, sizeof(*eth)); | 	eth = pkt_pull(pkt, sizeof(*eth)); | ||||||
| @@ -413,6 +429,19 @@ spotfilter_packet_cb(struct packet *pkt) | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	switch (proto) { | 	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: | 	case ETH_P_IP: | ||||||
| 		ip = pkt_peek(pkt, sizeof(struct ip)); | 		ip = pkt_peek(pkt, sizeof(struct ip)); | ||||||
| 		if (!ip) | 		if (!ip) | ||||||
|   | |||||||
| @@ -227,8 +227,11 @@ int spotfilter_in(struct __sk_buff *skb) | |||||||
|  |  | ||||||
| 		if (!is_control) | 		if (!is_control) | ||||||
| 			wl_val = bpf_map_lookup_elem(&whitelist_ipv6, &ip6h->daddr); | 			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 { | 	} else { | ||||||
| 			return TC_ACT_UNSPEC; | 		return TC_ACT_UNSPEC; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (wl_val) { | 	if (wl_val) { | ||||||
|   | |||||||
| @@ -257,6 +257,12 @@ static void client_dump(struct interface *iface, struct client *cl) | |||||||
| 	if (cl->id_node.key) | 	if (cl->id_node.key) | ||||||
| 		blobmsg_add_string(&b, "id", (const char *)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) { | 	if (cl->data.ip4addr) { | ||||||
| 		buf = blobmsg_alloc_string_buffer(&b, "ip4addr", INET6_ADDRSTRLEN); | 		buf = blobmsg_alloc_string_buffer(&b, "ip4addr", INET6_ADDRSTRLEN); | ||||||
| 		inet_ntop(AF_INET, (const void *)&cl->data.ip4addr, buf, INET6_ADDRSTRLEN); | 		inet_ntop(AF_INET, (const void *)&cl->data.ip4addr, buf, INET6_ADDRSTRLEN); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user