nfqws: backport from nfqws2 nl80211 ssid discovery fix for newer kernels

This commit is contained in:
bol-van
2025-12-17 10:59:07 +03:00
parent 8e766744b6
commit 813fe416f8
3 changed files with 121 additions and 37 deletions

View File

@@ -579,4 +579,5 @@ blockcheck: fix broken dns cache
73.5 73.5
nfqws2: fix broken l7proto profile rediscovery nfqws: fix broken l7proto profile rediscovery
nfqws: backport from nfqws2 nl80211 ssid discovery fix for newer kernels

View File

@@ -1870,9 +1870,9 @@ bool rawsend_queue(struct rawpacket_tailhead *q)
// linux-specific wlan retrieval implementation // linux-specific wlan retrieval implementation
typedef void netlink_prepare_nlh_cb_t(struct nlmsghdr *nlh); typedef void netlink_prepare_nlh_cb_t(struct nlmsghdr *nlh, void *param);
static bool netlink_genl_simple_transact(struct mnl_socket* nl, uint16_t type, uint16_t flags, uint8_t cmd, uint8_t version, netlink_prepare_nlh_cb_t cb_prepare_nlh, mnl_cb_t cb_data, void *data) static bool netlink_genl_simple_transact(struct mnl_socket* nl, uint16_t type, uint16_t flags, uint8_t cmd, uint8_t version, netlink_prepare_nlh_cb_t cb_prepare_nlh, void *prepare_data, mnl_cb_t cb_data, void *data)
{ {
char buf[MNL_SOCKET_BUFFER_SIZE]; char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *nlh; struct nlmsghdr *nlh;
@@ -1887,7 +1887,7 @@ static bool netlink_genl_simple_transact(struct mnl_socket* nl, uint16_t type, u
genl->cmd = cmd; genl->cmd = cmd;
genl->version = version; genl->version = version;
if (cb_prepare_nlh) cb_prepare_nlh(nlh); if (cb_prepare_nlh) cb_prepare_nlh(nlh, prepare_data);
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
{ {
@@ -1911,7 +1911,7 @@ static bool netlink_genl_simple_transact(struct mnl_socket* nl, uint16_t type, u
return false; return false;
} }
static void wlan_id_prepare(struct nlmsghdr *nlh) static void wlan_id_prepare(struct nlmsghdr *nlh, void *param)
{ {
mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, "nl80211"); mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, "nl80211");
} }
@@ -1943,7 +1943,7 @@ static int wlan_id_cb(const struct nlmsghdr *nlh, void *data)
static uint16_t wlan_get_family_id(struct mnl_socket* nl) static uint16_t wlan_get_family_id(struct mnl_socket* nl)
{ {
uint16_t id; uint16_t id;
return netlink_genl_simple_transact(nl, GENL_ID_CTRL, NLM_F_REQUEST | NLM_F_ACK, CTRL_CMD_GETFAMILY, 1, wlan_id_prepare, wlan_id_cb, &id) ? id : 0; return netlink_genl_simple_transact(nl, GENL_ID_CTRL, NLM_F_REQUEST | NLM_F_ACK, CTRL_CMD_GETFAMILY, 1, wlan_id_prepare, NULL, wlan_id_cb, &id) ? id : 0;
} }
static int wlan_info_attr_cb(const struct nlattr *attr, void *data) static int wlan_info_attr_cb(const struct nlattr *attr, void *data)
@@ -1978,42 +1978,130 @@ static int wlan_info_attr_cb(const struct nlattr *attr, void *data)
} }
return MNL_CB_OK; return MNL_CB_OK;
} }
struct wlan_info_req
{
struct wlan_interface_collection *wc;
bool bReqSSID;
};
static int wlan_info_cb(const struct nlmsghdr *nlh, void *data) static int wlan_info_cb(const struct nlmsghdr *nlh, void *data)
{
int ret;
struct wlan_info_req *wr = (struct wlan_info_req*)data;
if (wr->wc->count>=WLAN_INTERFACE_MAX) return MNL_CB_OK;
memset(wr->wc->wlan + wr->wc->count,0,sizeof(struct wlan_interface));
ret = mnl_attr_parse(nlh, sizeof(struct genlmsghdr), wlan_info_attr_cb, wr->wc->wlan + wr->wc->count);
if (ret>=0 && (!wr->bReqSSID || *wr->wc->wlan[wr->wc->count].ssid) && *wr->wc->wlan[wr->wc->count].ifname && wr->wc->wlan[wr->wc->count].ifindex)
wr->wc->count++;
return ret;
}
static bool wlan_info(struct mnl_socket* nl, uint16_t wlan_family_id, struct wlan_interface_collection* w, bool bReqSSID)
{
struct wlan_info_req req = { .bReqSSID = bReqSSID, .wc = w };
return netlink_genl_simple_transact(nl, wlan_family_id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP, NL80211_CMD_GET_INTERFACE, 0, NULL, NULL, wlan_info_cb, &req);
}
static void scan_prepare(struct nlmsghdr *nlh, void *param)
{
mnl_attr_put_u32(nlh, NL80211_ATTR_IFINDEX, *(int*)param);
}
static uint8_t *find_ie(uint8_t *buf, size_t len, uint8_t ie)
{
while (len>=2)
{
if (len<(2+buf[1])) break;
if (buf[0]==ie) return buf;
buf+=buf[1]+2;
len-=buf[1]+2;
}
return NULL;
}
static int scan_info_attr_cb(const struct nlattr *attr, void *data)
{
struct wlan_interface *wlan = (struct wlan_interface *)data;
const struct nlattr *nested;
uint8_t *payload, *ie;
uint16_t payload_len;
bool ok;
switch(mnl_attr_get_type(attr))
{
case NL80211_ATTR_IFINDEX:
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
{
DLOG_PERROR("mnl_attr_validate");
return MNL_CB_ERROR;
}
wlan->ifindex = mnl_attr_get_u32(attr);
if (!if_indextoname(wlan->ifindex, wlan->ifname))
DLOG_PERROR("if_indextoname");
break;
case NL80211_ATTR_BSS:
if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
{
DLOG_PERROR("mnl_attr_validate");
return MNL_CB_ERROR;
}
ok = false;
mnl_attr_for_each_nested(nested, attr)
{
if (mnl_attr_get_type(nested)==NL80211_BSS_STATUS)
{
uint32_t status = mnl_attr_get_u32(nested);
if (status==NL80211_BSS_STATUS_ASSOCIATED || status==NL80211_BSS_STATUS_AUTHENTICATED || status==NL80211_BSS_STATUS_IBSS_JOINED)
{
ok=1;
break;
}
}
}
if (!ok) break;
mnl_attr_for_each_nested(nested, attr)
{
switch(mnl_attr_get_type(nested))
{
case NL80211_BSS_INFORMATION_ELEMENTS:
payload_len = mnl_attr_get_payload_len(nested);
payload = mnl_attr_get_payload(nested);
ie = find_ie(payload,payload_len,0);
if (ie)
{
uint8_t l = ie[1];
if (l>=(sizeof(wlan->ssid))) l=sizeof(wlan->ssid)-1;
memcpy(wlan->ssid,ie+2,l);
wlan->ssid[l]=0;
}
break;
}
}
break;
}
return MNL_CB_OK;
}
static int scan_info_cb(const struct nlmsghdr *nlh, void *data)
{ {
int ret; int ret;
struct wlan_interface_collection *wc = (struct wlan_interface_collection*)data; struct wlan_interface_collection *wc = (struct wlan_interface_collection*)data;
if (wc->count>=WLAN_INTERFACE_MAX) return MNL_CB_OK; if (wc->count>=WLAN_INTERFACE_MAX) return MNL_CB_OK;
memset(wc->wlan+wc->count,0,sizeof(wc->wlan[0])); memset(wc->wlan+wc->count,0,sizeof(wc->wlan[0]));
ret = mnl_attr_parse(nlh, sizeof(struct genlmsghdr), wlan_info_attr_cb, wc->wlan+wc->count); ret = mnl_attr_parse(nlh, sizeof(struct genlmsghdr), scan_info_attr_cb, wc->wlan+wc->count);
if (ret>=0 && *wc->wlan[wc->count].ifname && wc->wlan[wc->count].ifindex) if (ret>=0 && *wc->wlan[wc->count].ssid && *wc->wlan[wc->count].ifname && wc->wlan[wc->count].ifindex)
{ wc->count++;
if (*wc->wlan[wc->count].ssid)
wc->count++;
else
{
// sometimes nl80211 does not return SSID but wireless ext does
int wext_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (wext_fd!=-1)
{
struct iwreq req;
snprintf(req.ifr_ifrn.ifrn_name,sizeof(req.ifr_ifrn.ifrn_name),"%s",wc->wlan[wc->count].ifname);
req.u.essid.pointer = wc->wlan[wc->count].ssid;
req.u.essid.length = sizeof(wc->wlan[wc->count].ssid);
req.u.essid.flags = 0;
if (ioctl(wext_fd, SIOCGIWESSID, &req)!=-1)
if (*wc->wlan[wc->count].ssid)
wc->count++;
close(wext_fd);
}
}
}
return ret; return ret;
} }
static bool wlan_info(struct mnl_socket* nl, uint16_t wlan_family_id, struct wlan_interface_collection* w) static bool scan_info(struct mnl_socket* nl, uint16_t wlan_family_id, struct wlan_interface_collection* w)
{ {
return netlink_genl_simple_transact(nl, wlan_family_id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP, NL80211_CMD_GET_INTERFACE, 0, NULL, wlan_info_cb, w); struct wlan_interface_collection wc_all = { .count = 0 };
// wlan_info does not return ssid since kernel 5.19
// it's used to enumerate all wifi interfaces then call scan_info on each
if (!wlan_info(nl, wlan_family_id, &wc_all, false)) return false;
for(int i=0;i<wc_all.count;i++)
if (!netlink_genl_simple_transact(nl, wlan_family_id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP, NL80211_CMD_GET_SCAN, 0, scan_prepare, (void*)&wc_all.wlan[i].ifindex, scan_info_cb, w))
return false;
return true;
} }
static bool wlan_init80211(struct mnl_socket** nl) static bool wlan_init80211(struct mnl_socket** nl)
{ {
if (!(*nl = mnl_socket_open(NETLINK_GENERIC))) if (!(*nl = mnl_socket_open(NETLINK_GENERIC)))
@@ -2047,7 +2135,7 @@ static bool wlan_info_rate_limited(struct mnl_socket* nl, uint16_t wlan_family_i
// do not purge too often to save resources // do not purge too often to save resources
if (wlan_info_last != now) if (wlan_info_last != now)
{ {
bres = wlan_info(nl,wlan_family_id,w); bres = scan_info(nl,wlan_family_id,w);
wlan_info_last = now; wlan_info_last = now;
} }
return bres; return bres;
@@ -2073,10 +2161,6 @@ bool wlan_info_init(void)
} }
return true; return true;
} }
bool wlan_info_get(void)
{
return wlan_info(nl_wifi, id_nl80211, &wlans);
}
bool wlan_info_get_rate_limited(void) bool wlan_info_get_rate_limited(void)
{ {
return wlan_info_rate_limited(nl_wifi, id_nl80211, &wlans); return wlan_info_rate_limited(nl_wifi, id_nl80211, &wlans);

View File

@@ -298,7 +298,6 @@ extern struct wlan_interface_collection wlans;
void wlan_info_deinit(void); void wlan_info_deinit(void);
bool wlan_info_init(void); bool wlan_info_init(void);
bool wlan_info_get(void);
bool wlan_info_get_rate_limited(void); bool wlan_info_get_rate_limited(void);
const char *wlan_ssid_search_ifname(const char *ifname); const char *wlan_ssid_search_ifname(const char *ifname);
const char *wlan_ssid_search_ifidx(int ifidx); const char *wlan_ssid_search_ifidx(int ifidx);