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

'scapy.all' has no attribute 'get_if_raw_hwaddr' #3

Open
TechTheGuy opened this issue Oct 12, 2024 · 12 comments
Open

'scapy.all' has no attribute 'get_if_raw_hwaddr' #3

TechTheGuy opened this issue Oct 12, 2024 · 12 comments
Assignees
Labels
bug Something isn't working

Comments

@TechTheGuy
Copy link

TechTheGuy commented Oct 12, 2024

Hey everybody, I first of all want to let you all know how awesome this module is!!
Anyways, I had to work a bit to get it working.
I am using python 3.9.5 with scapy 2.6.0 and, when running the first example in the readme, it fails.
Here's the code:

from ESPythoNOW import *
import time

def callback(from_mac, to_mac, msg):
  print("ESP-NOW message from %s to %s: %s" % (from_mac, to_mac, msg))

espnow = ESPythoNow(interface="wlan0mon", callback=callback)
espnow.start()

while True:
  msg=b'\x01'
  espnow.send("FF:FF:FF:FF:FF:FF", msg)
  time.sleep(3)

And, when ran with sudo python test.py, it fails with:

Traceback (most recent call last):
  File "/home/mindyourbusiness/fix_espnow/ESPythoNOW/test.py", line 7, in <module>
    espnow = ESPythoNow(interface="wlan0mon", callback=callback)
  File "/home/mindyourbusiness/fix_espnow/ESPythoNOW/ESPythoNOW.py", line 38, in __init__
    self.local_hw_mac        = self.hw_mac_as_str(self.interface)        # Interface's actual HW MAC
  File "/home/mindyourbusiness/fix_espnow/ESPythoNOW/ESPythoNOW.py", line 248, in hw_mac_as_str
    return ("%02X:" * 6)[:-1] % tuple(scapy.orb(x) for x in scapy.get_if_raw_hwaddr(self.l2_socket.iface)[1])
AttributeError: module 'scapy.all' has no attribute 'get_if_raw_hwaddr'

I think I got it to work with my pull request:
Line 247 defines the function hw_mac_as_str in a pretty weird way (it's got an unused argument(interface) and reconstructs the string version of the interface's mac address. What's the point of that if there's scapy's get_if_hwaddr function for it?

I fixed it (now there are no errors and Wireshark detects the packets) and am about to open a PR, once I figure out how to upload the fix...
Give me a few minutes so I can feel the glory of publishing my first PR please :-)

@TechTheGuy
Copy link
Author

Here's the pull request.
#4

@TechTheGuy
Copy link
Author

There's a problem: Wireshark sees the packets but the esp8266 doesn't receive them. That's weird.
Here's the sender code

from ESPythoNOW import *
import time

def callback(from_mac, to_mac, msg):
  print("ESP-NOW message from %s to %s: %s" % (from_mac, to_mac, msg))

espnow = ESPythoNow(interface="wlan0mon", callback=callback)
espnow.start()

while True:
  msg=b'\x01\x10'
  espnow.send("d8:bf:c0:11:2e:cd", msg)
  time.sleep(3)

And here's the esp8266 code:

//I mostly copied this code : https://randomnerdtutorials.com/esp-now-esp8266-nodemcu-arduino-ide/
#include <Arduino.h>
#include <espnow.h>
#include <ESP8266WiFi.h>

// Structure example to receive data
// Must match the sender structure
typedef struct struct_message {
  uint8_t a, b;
} struct_message;

// Create a struct_message called myData
struct_message myData;

// Callback function that will be executed when data is received
void OnDataRecv(uint8_t * mac, uint8_t *incomingData, uint8_t len) {
  memcpy(&myData, incomingData, sizeof(myData));
  Serial.print("Bytes received: ");
  Serial.println(len);
  Serial.print("a: ");
  Serial.println(myData.a);
  Serial.print("b: ");
  Serial.println(myData.b);
  Serial.println();
}
 
void setup() {
  // Initialize Serial Monitor
  Serial.begin(115200);
  
  // Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);

  // Init ESP-NOW
  if (esp_now_init() != 0) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  
  // Once ESPNow is successfully Init, we will register for recv CB to
  // get recv packer info
  esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
  esp_now_register_recv_cb(OnDataRecv);
  Serial.println(WiFi.channel());
}

void loop() {
  yield(); 
}

The receiver mac and channel is right (1)
The esp doesn't send any serial packets...

@ChuckMash
Copy link
Owner

Must be some differences in the scapy versions, I'll do some testing when I have some time and get back to you on this and the PR.

@ChuckMash ChuckMash added the bug Something isn't working label Oct 14, 2024
@MRIIOT
Copy link

MRIIOT commented Oct 14, 2024

There's a problem: Wireshark sees the packets but the esp8266 doesn't receive them. That's weird. Here's the sender code

from ESPythoNOW import *
import time

def callback(from_mac, to_mac, msg):
  print("ESP-NOW message from %s to %s: %s" % (from_mac, to_mac, msg))

espnow = ESPythoNow(interface="wlan0mon", callback=callback)
espnow.start()

while True:
  msg=b'\x01\x10'
  espnow.send("d8:bf:c0:11:2e:cd", msg)
  time.sleep(3)

And here's the esp8266 code:

//I mostly copied this code : https://randomnerdtutorials.com/esp-now-esp8266-nodemcu-arduino-ide/
#include <Arduino.h>
#include <espnow.h>
#include <ESP8266WiFi.h>

// Structure example to receive data
// Must match the sender structure
typedef struct struct_message {
  uint8_t a, b;
} struct_message;

// Create a struct_message called myData
struct_message myData;

// Callback function that will be executed when data is received
void OnDataRecv(uint8_t * mac, uint8_t *incomingData, uint8_t len) {
  memcpy(&myData, incomingData, sizeof(myData));
  Serial.print("Bytes received: ");
  Serial.println(len);
  Serial.print("a: ");
  Serial.println(myData.a);
  Serial.print("b: ");
  Serial.println(myData.b);
  Serial.println();
}
 
void setup() {
  // Initialize Serial Monitor
  Serial.begin(115200);
  
  // Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);

  // Init ESP-NOW
  if (esp_now_init() != 0) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  
  // Once ESPNow is successfully Init, we will register for recv CB to
  // get recv packer info
  esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
  esp_now_register_recv_cb(OnDataRecv);
  Serial.println(WiFi.channel());
}

void loop() {
  yield(); 
}

The receiver mac and channel is right (1) The esp doesn't send any serial packets...

Is your Linux setup receiving messages with your changes?

@ChuckMash ChuckMash self-assigned this Oct 14, 2024
@TechTheGuy
Copy link
Author

TechTheGuy commented Oct 15, 2024

I tried running the code on a laptop and a desktop which both have interfaces that support monitor mode and packet injection (I tested them with airplay and they work).
However, the sender computer receives its own packets via Wireshark but the receiver rarely does.
in about 1 h of tinkering I managed to get the packages received by the receiver only once and only in Wireshark.
When they are received I can read their content in Wireshark but espythonow does not show them.
And yes, I set the correct receiver mac...
It's as if only a specified set of channels works.
Edit for clarity: I didn't check if the sender can receive its own packets via the library. I will

@ChuckMash
Copy link
Owner

A couple things to check:

What is the output (if any) from prep.sh being run with the correct interface and channel set?

Try adding adding accept_all
espnow = ESPythoNow(interface="wlan0mon", callback=callback, accept_all=True)

Can you describe your setup?
I'll have time to examine this problem more deeply in about a week.

@TechTheGuy
Copy link
Author

TechTheGuy commented Oct 15, 2024

sudo bash prep.sh wlan0mon 8
Returns nothing and effectively works (it does almost exactly what I did manually: Iwconfig:

wlan0mon  IEEE 802.11  Mode:Monitor  Frequency:2.447 GHz  Tx-Power=20 dBm   
          Retry short limit:7   RTS thr=2347 B   Fragment thr:off
          Power Management:on

I also enabled the accept_all flag and it now somehow works: When either computer sends a message to the other one, the library on the recipient side sees the packet!
It reads "ESP-NOW message from [src mac] to [destination mac]: b''"
where destination mac is the mac of the computer that's outputting the text.
So it works.
However, the message is read as empty.

To sum up, I now used the prep script and enabled that accept_all flag. I can now receive the packets but not the messages.

Also, if I turn off the accept_all flag the program stops outputting data (even though its the right receiver mac).
That's weird.

Edit: Wireshark on the sender side shows that each packet gets retransmitted a few times and only the first transmission contains the intended message.
On the other hand, Wireshark on the receiver side never shows the payload.

@ChuckMash
Copy link
Owner

accept_all should only mean it will accept any message no matter the recipient MAC. Sound like there may be a MAC address mismatch.

As for the missing function, I used/use scapy version 2.5.0 for development, so the function must be removed for version 2.6.0. I'll take a look.

There was a reason for the strange method of gathering the local MAC, I'll have to try and track down why I did it like that initially. It may be related to local MAC spoofing.

I'll keeping looking.

@hpsaturn
Copy link

hpsaturn commented Nov 7, 2024

Hi guys,
I was trying to test this, and I have the same issue. I tried with the PR mentioned but nothing. With the PR I don't have any error, but the sniffer example don't capture nothing. I tried with all channels but nothing. Also my wireless device supports monitor mode, I guess, because the iwconfing command show this:

lp4s0    IEEE 802.11  Mode:Monitor  Frequency:2.447 GHz  Tx-Power=3 dBm   
          Retry short limit:7   RTS thr:off   Fragment thr:off
          Power Management:on

And lshw command show:

capabilities: pciexpress msi pm bus_master cap_list logical wireless
configuration: broadcast=yes driver=mt7921e driverversion=6.1.0-0.deb11.17-amd6

Also I did the steps for run this with privileges. But I have some doubts with this step:

sudo setcap cap_net_raw=eip env/bin/python_netraw

One question, I was trying it with a esp32 that is sending packages from C++, don't matter right?

@MRIIOT
Copy link

MRIIOT commented Nov 7, 2024

Hi guys, I was trying to test this, and I have the same issue. I tried with the PR mentioned but nothing. With the PR I don't have any error, but the sniffer example don't capture nothing. I tried with all channels but nothing. Also my wireless device supports monitor mode, I guess, because the iwconfing command show this:

lp4s0    IEEE 802.11  Mode:Monitor  Frequency:2.447 GHz  Tx-Power=3 dBm   
          Retry short limit:7   RTS thr:off   Fragment thr:off
          Power Management:on

And lshw command show:

capabilities: pciexpress msi pm bus_master cap_list logical wireless
configuration: broadcast=yes driver=mt7921e driverversion=6.1.0-0.deb11.17-amd6

Also I did the steps for run this with privileges. But I have some doubts with this step:

sudo setcap cap_net_raw=eip env/bin/python_netraw

One question, I was trying it with a esp32 that is sending packages from C++, don't matter right?

What does your python code look like? What does your ESP code look like?

@hpsaturn
Copy link

hpsaturn commented Nov 7, 2024

Hi again,

I found the solution in my case, following the next steps:

  1. I used the PR Fixed issue n3: no member "get_if_raw_hwaddr" #4
  2. I ran the aircrack kill process: sudo airmon-ng check kill
  3. I putted the mode monitor with aircrack: sudo airmon-ng start wlp4s0
  4. I ran the prep.sh script but using the channel 1: sudo bash prep.sh wlp4s0 1

And I have messages with the sniffer sample like this:

ESP-NOW message from 74:4D:BD:81:4E:FC to FF:FF:FF:FF:FF:FF: b'\xec\x13\x12d\x16\x8a))\x80\xb4~4\x94\xb9\xa0\x02\x8a(\xa0\x02\x92\x96\x92\x80\x1ai\r8\xd2\x11Lci)i(\x00\xa2\x8a(\x00\xa2\x8a(\x00\xa2\x8a(\x00\xa2\x92\x8a`\x14\xb4RP\x01E\x14R\x00\xa2\x8a(\x01E-6\x94P\x03\xa9i\xb4\xb4\x00\xb4RR\xd2\x01)\xc2\x9b\xde\x94\x1a\x00u%\x14P \xa2\x8a(\x00\xa2\x8aJ\x00\xff\xd9'

One question please, is possible use nanopb (protocol buffers) with this Python package? I'm coding the messages from the ESP32 using nanopb.

Thanks, pretty nice Python package.

@hpsaturn
Copy link

hpsaturn commented Nov 7, 2024

What does your python code look like? What does your ESP code look like?

Sorry, I didn't reload the page and I didn't seen this question.

My Python code is the sample sniffer code without any change, but using the PR #4
My ESP32 code is my ESPNowCam library, I'm sending messages from an ESP32 XIAO Camera, using one of my samples, the XIAO-fpv-sender sample of this library

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants