mirror of
https://github.com/vanhoefm/fragattacks.git
synced 2025-01-17 18:34:03 -05:00
AP: Add Neighbor Discovery snooping mechanism for Proxy ARP
This commit establishes the infrastructure, and handles the Neighbor Solicitation and Neighbor Advertisement frames. This will be extended in the future to handle other frames. Signed-off-by: Kyeyoon Park <kyeyoonp@qca.qualcomm.com>
This commit is contained in:
parent
5c58944d08
commit
bd00c4311c
@ -855,6 +855,7 @@ ifdef CONFIG_PROXYARP
|
||||
CFLAGS += -DCONFIG_PROXYARP
|
||||
OBJS += ../src/ap/x_snoop.o
|
||||
OBJS += ../src/ap/dhcp_snoop.o
|
||||
OBJS += ../src/ap/ndisc_snoop.o
|
||||
endif
|
||||
|
||||
OBJS += ../src/drivers/driver_common.o
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "bss_load.h"
|
||||
#include "x_snoop.h"
|
||||
#include "dhcp_snoop.h"
|
||||
#include "ndisc_snoop.h"
|
||||
|
||||
|
||||
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
|
||||
@ -314,6 +315,7 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
|
||||
#endif /* CONFIG_INTERWORKING */
|
||||
|
||||
bss_load_update_deinit(hapd);
|
||||
ndisc_snoop_deinit(hapd);
|
||||
dhcp_snoop_deinit(hapd);
|
||||
x_snoop_deinit(hapd);
|
||||
|
||||
@ -907,6 +909,12 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
|
||||
"DHCP snooping initialization failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ndisc_snoop_init(hapd)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Neighbor Discovery snooping initialization failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hostapd_drv_none(hapd) && vlan_init(hapd)) {
|
||||
|
@ -243,6 +243,7 @@ struct hostapd_data {
|
||||
#endif /* CONFIG_INTERWORKING */
|
||||
#ifdef CONFIG_PROXYARP
|
||||
struct l2_packet_data *sock_dhcp;
|
||||
struct l2_packet_data *sock_ndisc;
|
||||
#endif /* CONFIG_PROXYARP */
|
||||
#ifdef CONFIG_MESH
|
||||
int num_plinks;
|
||||
|
@ -1718,6 +1718,7 @@ static void handle_disassoc(struct hostapd_data *hapd,
|
||||
ieee802_1x_free_station(sta);
|
||||
if (sta->ipaddr)
|
||||
hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
|
||||
ap_sta_ip6addr_del(hapd, sta);
|
||||
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||
|
||||
if (sta->timeout_next == STA_NULLFUNC ||
|
||||
|
156
src/ap/ndisc_snoop.c
Normal file
156
src/ap/ndisc_snoop.c
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Neighbor Discovery snooping for Proxy ARP
|
||||
* Copyright (c) 2014, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/icmpv6.h>
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "l2_packet/l2_packet.h"
|
||||
#include "hostapd.h"
|
||||
#include "sta_info.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "list.h"
|
||||
#include "x_snoop.h"
|
||||
|
||||
struct ip6addr {
|
||||
struct in6_addr addr;
|
||||
struct dl_list list;
|
||||
};
|
||||
|
||||
struct icmpv6_ndmsg {
|
||||
struct ipv6hdr ipv6h;
|
||||
struct icmp6hdr icmp6h;
|
||||
struct in6_addr target_addr;
|
||||
u8 opt_type;
|
||||
u8 len;
|
||||
u8 opt_lladdr[0];
|
||||
};
|
||||
|
||||
#define NEIGHBOR_SOLICITATION 135
|
||||
#define NEIGHBOR_ADVERTISEMENT 136
|
||||
#define SOURCE_LL_ADDR 1
|
||||
|
||||
static int sta_ip6addr_add(struct sta_info *sta, struct in6_addr *addr)
|
||||
{
|
||||
struct ip6addr *ip6addr;
|
||||
|
||||
ip6addr = os_zalloc(sizeof(*ip6addr));
|
||||
if (!ip6addr)
|
||||
return -1;
|
||||
|
||||
os_memcpy(&ip6addr->addr, addr, sizeof(*addr));
|
||||
|
||||
dl_list_add_tail(&sta->ip6addr, &ip6addr->list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
struct ip6addr *ip6addr, *prev;
|
||||
|
||||
dl_list_for_each_safe(ip6addr, prev, &sta->ip6addr, struct ip6addr,
|
||||
list) {
|
||||
hostapd_drv_br_delete_ip_neigh(hapd, 6, (u8 *) &ip6addr->addr);
|
||||
os_free(ip6addr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int sta_has_ip6addr(struct sta_info *sta, struct in6_addr *addr)
|
||||
{
|
||||
struct ip6addr *ip6addr;
|
||||
|
||||
dl_list_for_each(ip6addr, &sta->ip6addr, struct ip6addr, list) {
|
||||
if (ip6addr->addr.s6_addr32[0] == addr->s6_addr32[0] &&
|
||||
ip6addr->addr.s6_addr32[1] == addr->s6_addr32[1] &&
|
||||
ip6addr->addr.s6_addr32[2] == addr->s6_addr32[2] &&
|
||||
ip6addr->addr.s6_addr32[3] == addr->s6_addr32[3])
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void handle_ndisc(void *ctx, const u8 *src_addr, const u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct icmpv6_ndmsg *msg;
|
||||
struct in6_addr *saddr;
|
||||
struct sta_info *sta;
|
||||
int res;
|
||||
|
||||
if (len < ETH_HLEN + sizeof(*msg))
|
||||
return;
|
||||
msg = (struct icmpv6_ndmsg *) &buf[ETH_HLEN];
|
||||
switch (msg->icmp6h.icmp6_type) {
|
||||
case NEIGHBOR_SOLICITATION:
|
||||
if (msg->opt_type != SOURCE_LL_ADDR)
|
||||
return;
|
||||
|
||||
saddr = &msg->ipv6h.saddr;
|
||||
if (!(saddr->s6_addr32[0] == 0 && saddr->s6_addr32[1] == 0 &&
|
||||
saddr->s6_addr32[2] == 0 && saddr->s6_addr32[3] == 0)) {
|
||||
if (len < ETH_HLEN + sizeof(*msg) + ETH_ALEN)
|
||||
return;
|
||||
sta = ap_get_sta(hapd, msg->opt_lladdr);
|
||||
if (!sta)
|
||||
return;
|
||||
|
||||
if (sta_has_ip6addr(sta, saddr))
|
||||
return;
|
||||
|
||||
hostapd_drv_br_delete_ip_neigh(hapd, 6, (u8 *) saddr);
|
||||
res = hostapd_drv_br_add_ip_neigh(hapd, 6, (u8 *) saddr,
|
||||
128, sta->addr);
|
||||
if (res) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"ndisc_snoop: Adding ip neigh failed: %d",
|
||||
res);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sta_ip6addr_add(sta, saddr))
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case NEIGHBOR_ADVERTISEMENT:
|
||||
for (sta = hapd->sta_list; sta; sta = sta->next) {
|
||||
x_snoop_mcast_to_ucast_convert_send(hapd, sta,
|
||||
(u8 *) buf, len);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int ndisc_snoop_init(struct hostapd_data *hapd)
|
||||
{
|
||||
hapd->sock_ndisc = x_snoop_get_l2_packet(hapd, handle_ndisc,
|
||||
L2_PACKET_FILTER_NDISC);
|
||||
if (hapd->sock_ndisc == NULL) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ndisc_snoop: Failed to initialize L2 packet processing for NDISC packets: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void ndisc_snoop_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
l2_packet_deinit(hapd->sock_ndisc);
|
||||
}
|
36
src/ap/ndisc_snoop.h
Normal file
36
src/ap/ndisc_snoop.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Neighbor Discovery snooping for Proxy ARP
|
||||
* Copyright (c) 2014, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef NDISC_SNOOP_H
|
||||
#define NDISC_SNOOP_H
|
||||
|
||||
#ifdef CONFIG_PROXYARP
|
||||
|
||||
int ndisc_snoop_init(struct hostapd_data *hapd);
|
||||
void ndisc_snoop_deinit(struct hostapd_data *hapd);
|
||||
void sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
|
||||
#else /* CONFIG_PROXYARP */
|
||||
|
||||
static inline int ndisc_snoop_init(struct hostapd_data *hapd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ndisc_snoop_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void sta_ip6addr_del(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PROXYARP */
|
||||
|
||||
#endif /* NDISC_SNOOP_H */
|
@ -31,6 +31,7 @@
|
||||
#include "ap_drv_ops.h"
|
||||
#include "gas_serv.h"
|
||||
#include "wnm_ap.h"
|
||||
#include "ndisc_snoop.h"
|
||||
#include "sta_info.h"
|
||||
|
||||
static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
|
||||
@ -144,6 +145,12 @@ static void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
}
|
||||
|
||||
|
||||
void ap_sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
sta_ip6addr_del(hapd, sta);
|
||||
}
|
||||
|
||||
|
||||
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
int set_beacon = 0;
|
||||
@ -158,6 +165,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
|
||||
if (sta->ipaddr)
|
||||
hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
|
||||
ap_sta_ip6addr_del(hapd, sta);
|
||||
|
||||
if (!hapd->iface->driver_ap_teardown &&
|
||||
!(sta->flags & WLAN_STA_PREAUTH))
|
||||
@ -605,6 +613,7 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
|
||||
sta->ssid = &hapd->conf->ssid;
|
||||
ap_sta_remove_in_other_bss(hapd, sta);
|
||||
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
|
||||
dl_list_init(&sta->ip6addr);
|
||||
|
||||
return sta;
|
||||
}
|
||||
@ -616,6 +625,7 @@ static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
|
||||
if (sta->ipaddr)
|
||||
hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
|
||||
ap_sta_ip6addr_del(hapd, sta);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Removing STA " MACSTR " from kernel driver",
|
||||
MAC2STR(sta->addr));
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include "common/defs.h"
|
||||
#endif /* CONFIG_MESH */
|
||||
|
||||
#include "list.h"
|
||||
|
||||
/* STA flags */
|
||||
#define WLAN_STA_AUTH BIT(0)
|
||||
#define WLAN_STA_ASSOC BIT(1)
|
||||
@ -47,6 +49,7 @@ struct sta_info {
|
||||
struct sta_info *hnext; /* next entry in hash table list */
|
||||
u8 addr[6];
|
||||
be32 ipaddr;
|
||||
struct dl_list ip6addr; /* list head for struct ip6addr */
|
||||
u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */
|
||||
u32 flags; /* Bitfield of WLAN_STA_* */
|
||||
u16 capability;
|
||||
@ -193,6 +196,7 @@ struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta);
|
||||
struct sta_info * ap_get_sta_p2p(struct hostapd_data *hapd, const u8 *addr);
|
||||
void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void ap_sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void hostapd_free_stas(struct hostapd_data *hapd);
|
||||
void ap_handle_timer(void *eloop_ctx, void *timeout_ctx);
|
||||
void ap_sta_replenish_timeout(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
|
Loading…
Reference in New Issue
Block a user