Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Linux AP scanning #29

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

oldgalileo
Copy link

Adds support for Linux AP scanning, with unit tests handling unicode in AP SSIDs.

@SuperQ
Copy link
Collaborator

SuperQ commented Jun 14, 2023

This needs a rebase.

@DAT4
Copy link

DAT4 commented Aug 19, 2023

(maybe stupid question) Why is multicast group needed here?

I am getting operation not supported when using dump flag on the TRIGGER_SCAN.

I don't know enough about netlink and nl80211 yet, but I am trying to learn. I would love if anyone could point me in a direction. Right now the only method I have is to try out commands from here and parsing the response manually. I am looking at iw, and wpa_supplicant sourcecode as well, but it is not easy for me to understand because I am not a C programmer.

I changed the first call to socket using the get method on the cli, and I changed dump to acknowlegde, because then I will get other errors.

	msgs, err := c.get(
		unix.NL80211_CMD_TRIGGER_SCAN,
		netlink.Acknowledge,
		ifi,
		func(ae *netlink.AttributeEncoder) {
			ae.Nested(unix.NL80211_ATTR_SCAN_SSIDS,
				func(nae *netlink.AttributeEncoder) error {
					nae.Bytes(
						unix.NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
						nlenc.Bytes(""),
					)
					return nil
				})
			ae.Bytes(
				unix.NL80211_ATTR_IFINDEX,
				nlenc.Uint32Bytes(uint32(ifi.Index)),
			)
		},
	)
	if err != nil {
		return nil, fmt.Errorf("failed to trigger scheduled scan: %s", err)
	}

First error was not permitted, so I run with sudo, and get: netlink validate: mismatched sequence in netlink reply.

So I removed the part where you create a multicast group and join it.

Then I get the error that the header version is not the family version and the response from the first call to socket is:

{{0 0} [48 0 0 0 36 0 5 0 203 41 13 27 209 148 2 0]}

I don't know how to interpret it.

The final response from CMD_GET_SCAN is one or more of this:

&{  0 0s 0s authenticated}
&{  0 0s 0s authenticated}
&{  0 0s 0s authenticated}
&{  0 0s 0s authenticated}

Here is a copy of the whole function, how it look on my machine now

func (c *client) Scan(ifi *Interface) ([]*BSS, error) {
	//family, err := c.c.GetFamily(unix.NL80211_GENL_NAME)
	//if err != nil {
	//	return nil, err
	//}
	//var mcastScan genetlink.MulticastGroup
	//for _, mcast := range family.Groups {
	//	if mcast.Name == unix.NL80211_MULTICAST_GROUP_SCAN {
	//		mcastScan = mcast
	//	}
	//}
	//if mcastScan.Name != unix.NL80211_MULTICAST_GROUP_SCAN {
	//	return nil, errMissingMulticastGroupScan
	//}

	//err = c.c.JoinGroup(mcastScan.ID)
	//if err != nil {
	//	return nil, err
	//}

	msgs, err := c.get(
		unix.NL80211_CMD_TRIGGER_SCAN,
		netlink.Acknowledge,
		ifi,
		func(ae *netlink.AttributeEncoder) {
			ae.Nested(unix.NL80211_ATTR_SCAN_SSIDS,
				func(nae *netlink.AttributeEncoder) error {
					nae.Bytes(
						unix.NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
						nlenc.Bytes(""),
					)
					return nil
				})
			ae.Bytes(
				unix.NL80211_ATTR_IFINDEX,
				nlenc.Uint32Bytes(uint32(ifi.Index)),
			)
		},
	)
	if err != nil {
		return nil, fmt.Errorf("failed to trigger scheduled scan: %s", err)
	}

	for _, m := range msgs {
		fmt.Println(m)
		//if m.Header.Version != c.familyVersion {
		//	fmt.Println(m.Header.Version)
		//	return nil, errInvalidFamilyVersion
		//}
		if m.Header.Command == unix.NL80211_CMD_ABORT_SCAN {
			return nil, errScanAborted
		}
		if m.Header.Command == unix.NL80211_CMD_NEW_SCAN_RESULTS {
			fmt.Println("ok")
			break
		}
	}

	//err = c.c.LeaveGroup(mcastScan.ID)
	//if err != nil {
	//	return nil, err
	//}

	msgs, err = c.get(unix.NL80211_CMD_GET_SCAN, netlink.Dump, ifi,
		func(ae *netlink.AttributeEncoder) {
			ae.Bytes(
				unix.NL80211_ATTR_IFINDEX,
				nlenc.Uint32Bytes(uint32(ifi.Index)),
			)
		},
	)
	if err != nil {
		return nil, err
	}

	//if err := c.checkMessages(msgs, unix.NL80211_CMD_NEW_SCAN_RESULTS); err != nil {
	//	return nil, err
	//}

	bssm, err := parseBSSMulti(msgs)
	if err != nil {
		return nil, err
	}

	return bssm, nil
}

@lukas-mbag
Copy link
Contributor

@oldgalileo Do you still work on this?

I am planing to implement something similar (Trigger Scans and more importantly receive all scan results).
Can I join into the effort?

@SuperQ
Copy link
Collaborator

SuperQ commented Dec 1, 2023

@lukas-mbag this seems to be abandoned long enough that I would go ahead with what you want to work on. You're welcome to cherry-pick changes from this PR if that makes sense.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants