Coming from Maintenance mode galore, this topic is about further investigating how we could manage to find out about the IP address when an ESP32-based Pycom device is connected to the same local network your workstation is running on.
We will try to conduct some tests about how the FiPy connects to the WiFi network, especially regarding DHCP leasing as well as DNS- and ARP-table announcements and how this information can be inquired and processed appropriately.
As our FiPy libero device we are using for conducting these tests doesn’t have any sensors attached, it will be the perfect target. Its alive-time and the connectivity window is so small the device doesn’t even manage to get into the network to be found by its name espressif appropriately – at least for me: socket.gethostbyname('espressif') just yields a cute "host not found", even when run in a tight loop to prevent eventual misses.
So, this is how my arp table looks after running the device for one hour on my local network, made up by a standard Fritz!Box 7660.
watch -n0.5 "arp -a | grep '80:7d:3a'"
? (192.168.178.113) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.115) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.117) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.119) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.121) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.123) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.125) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.127) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.130) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.132) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.135) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.137) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.139) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.141) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.143) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.145) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
Another session right after the first one running for some minutes yielded
? (192.168.178.20) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.159) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.162) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.165) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.167) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.169) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.20) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
espressif.fritz.box (192.168.178.21) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.22) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.20) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.21) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.23) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.24) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.20) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.21) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.23) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
espressif.fritz.box (192.168.178.24) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.20) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
espressif.fritz.box (192.168.178.21) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.24) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.20) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.21) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.22) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.24) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
When the device is on the network, it is visible for just a few seconds which might look like that.
ping 192.168.178.20
64 bytes from 192.168.178.20: icmp_seq=185 ttl=255 time=53.298 ms
64 bytes from 192.168.178.20: icmp_seq=186 ttl=255 time=3.768 ms
64 bytes from 192.168.178.20: icmp_seq=187 ttl=255 time=4.700 ms
64 bytes from 192.168.178.20: icmp_seq=188 ttl=255 time=17.620 ms
ping 192.168.178.21
64 bytes from 192.168.178.21: icmp_seq=93 ttl=255 time=53.213 ms
64 bytes from 192.168.178.21: icmp_seq=94 ttl=255 time=5.307 ms
64 bytes from 192.168.178.21: icmp_seq=95 ttl=255 time=6.069 ms
64 bytes from 192.168.178.21: icmp_seq=96 ttl=255 time=4.014 ms
64 bytes from 192.168.178.21: icmp_seq=97 ttl=255 time=3.092 ms
ping 192.168.178.22
64 bytes from 192.168.178.22: icmp_seq=177 ttl=255 time=4899.730 ms
64 bytes from 192.168.178.22: icmp_seq=178 ttl=255 time=3898.889 ms
64 bytes from 192.168.178.22: icmp_seq=179 ttl=255 time=2895.240 ms
64 bytes from 192.168.178.22: icmp_seq=180 ttl=255 time=1893.755 ms
64 bytes from 192.168.178.22: icmp_seq=181 ttl=255 time=889.207 ms
64 bytes from 192.168.178.22: icmp_seq=182 ttl=255 time=5.730 ms
64 bytes from 192.168.178.22: icmp_seq=183 ttl=255 time=6.098 ms
64 bytes from 192.168.178.22: icmp_seq=184 ttl=255 time=6.574 ms
64 bytes from 192.168.178.22: icmp_seq=185 ttl=255 time=3.800 ms
64 bytes from 192.168.178.22: icmp_seq=186 ttl=255 time=5.970 ms
ping 192.168.178.20
64 bytes from 192.168.178.20: icmp_seq=363 ttl=255 time=7.287 ms
64 bytes from 192.168.178.20: icmp_seq=364 ttl=255 time=3.836 ms
64 bytes from 192.168.178.20: icmp_seq=365 ttl=255 time=3.356 ms
64 bytes from 192.168.178.20: icmp_seq=366 ttl=255 time=7.973 ms
64 bytes from 192.168.178.20: icmp_seq=367 ttl=255 time=27.211 ms
ping 192.168.178.21
64 bytes from 192.168.178.21: icmp_seq=336 ttl=255 time=76.273 ms
64 bytes from 192.168.178.21: icmp_seq=337 ttl=255 time=3.750 ms
64 bytes from 192.168.178.21: icmp_seq=338 ttl=255 time=3.783 ms
64 bytes from 192.168.178.21: icmp_seq=339 ttl=255 time=5.420 ms
64 bytes from 192.168.178.21: icmp_seq=340 ttl=255 time=3.772 ms
ping 192.168.178.20
64 bytes from 192.168.178.20: icmp_seq=543 ttl=255 time=107.740 ms
64 bytes from 192.168.178.20: icmp_seq=544 ttl=255 time=3.901 ms
64 bytes from 192.168.178.20: icmp_seq=545 ttl=255 time=4.072 ms
64 bytes from 192.168.178.20: icmp_seq=546 ttl=255 time=4.066 ms
ping 192.168.178.20
64 bytes from 192.168.178.20: icmp_seq=632 ttl=255 time=56.037 ms
64 bytes from 192.168.178.20: icmp_seq=633 ttl=255 time=10.913 ms
64 bytes from 192.168.178.20: icmp_seq=634 ttl=255 time=3.716 ms
64 bytes from 192.168.178.20: icmp_seq=635 ttl=255 time=7.521 ms
64 bytes from 192.168.178.20: icmp_seq=636 ttl=255 time=5.889 ms
Connectivity seems to iterate between x.20, x.21 and x.22.
? (192.168.178.74) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.77) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.79) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.81) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.83) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.85) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.87) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.89) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.91) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.93) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.95) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.97) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.99) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.102) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.104) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.106) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.109) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
During that session, my workstation was sitting on 192.168.178.101.
We just have been able to hit the device on a single random sampling without having run that in a tight loop yet. Lucky us.
$ nmap -p 23 192.168.178.0/24
Starting Nmap 7.70 ( https://nmap.org ) at 2019-07-04 15:18 CEST
Nmap scan report for fritz.box (192.168.178.1)
Host is up (0.0074s latency).
PORT STATE SERVICE
23/tcp closed telnet
Nmap scan report for fritz.repeater (192.168.178.35)
Host is up (0.0071s latency).
PORT STATE SERVICE
23/tcp closed telnet
Nmap scan report for 192.168.178.58
Host is up (0.0095s latency).
PORT STATE SERVICE
23/tcp open telnet
Nmap scan report for offgrid.fritz.box (192.168.178.101)
Host is up (0.00088s latency).
PORT STATE SERVICE
23/tcp closed telnet
Nmap done: 256 IP addresses (4 hosts up) scanned in 3.10 seconds
It’s this guy:
Nmap scan report for 192.168.178.58
Host is up (0.0095s latency).
PORT STATE SERVICE
23/tcp open telnet
By not skipping host discovery like
-Pn: Treat all hosts as online -- skip host discovery
scanning time seems to be reasonably fast:
$ nmap -p 23 192.168.178.0/24
[...]
Nmap done: 256 IP addresses (4 hosts up) scanned in 3.10 seconds
After power cycling Fritz and Libero [1], Libero starts obtaining addresses starting at x.20 again.
ARP table
? (192.168.178.20) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.22) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.24) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.26) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.29) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.31) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
? (192.168.178.33) at 80:7d:3a:c2:de:44 on en1 ifscope [ethernet]
TIMING AND PERFORMANCE:
Options which take <time> are in seconds, or append 'ms' (milliseconds),
's' (seconds), 'm' (minutes), or 'h' (hours) to the value (e.g. 30m).
-T<0-5>: Set timing template (higher is faster)
--min-hostgroup/max-hostgroup <size>: Parallel host scan group sizes
--min-parallelism/max-parallelism <numprobes>: Probe parallelization
--min-rtt-timeout/max-rtt-timeout/initial-rtt-timeout <time>: Specifies
probe round trip time.
--max-retries <tries>: Caps number of port scan probe retransmissions.
--host-timeout <time>: Give up on target after this long
--scan-delay/--max-scan-delay <time>: Adjust delay between probes
--min-rate <number>: Send packets no slower than <number> per second
--max-rate <number>: Send packets no faster than <number> per second
Outcome
Host probing by ping scan
$ sudo nmap -sn --min-parallelism 128 -oG - 192.168.178.0/24
Warning: Your --min-parallelism option is pretty high! This can hurt reliability.
# Nmap 7.70 scan initiated Thu Jul 4 15:51:00 2019 as: nmap -sn --min-parallelism 128 -oG - 192.168.178.0/24
Host: 192.168.178.1 (fritz.box) Status: Up
Host: 192.168.178.34 (andromeda.fritz.box) Status: Up
Host: 192.168.178.35 (fritz.repeater) Status: Up
Host: 192.168.178.53 () Status: Up
Host: 192.168.178.101 (offgrid.fritz.box) Status: Up
# Nmap done at Thu Jul 4 15:51:01 2019 -- 256 IP addresses (5 hosts up) scanned in 0.68 seconds
Port probing, with Host discovery
$ nmap -p 23 --min-parallelism 128 -oG - 192.168.178.0/24
Warning: Your --min-parallelism option is pretty high! This can hurt reliability.
# Nmap 7.70 scan initiated Thu Jul 4 15:52:32 2019 as: nmap --min-parallelism 128 -p 23 -oG - 192.168.178.0/24
Host: 192.168.178.1 (fritz.box) Status: Up
Host: 192.168.178.1 (fritz.box) Ports: 23/closed/tcp//telnet///
Host: 192.168.178.35 (fritz.repeater) Status: Up
Host: 192.168.178.35 (fritz.repeater) Ports: 23/closed/tcp//telnet///
Host: 192.168.178.55 () Status: Up
Host: 192.168.178.55 () Ports: 23/open/tcp//telnet///
Host: 192.168.178.101 (offgrid.fritz.box) Status: Up
Host: 192.168.178.101 (offgrid.fritz.box) Ports: 23/closed/tcp//telnet///
# Nmap done at Thu Jul 4 15:52:33 2019 -- 256 IP addresses (4 hosts up) scanned in 1.27 seconds
Isn’t this a function of DHCP? We can recommend to assign always the same IP. This is possible in the Fritzbox settings, but of cause no general solution.
May I humbly ask @MKO, @clemens or @tonke to check whether this will work on a WSL2’ed Debian/Ubuntu and tell me about its outcome? I’m actually interested in success and speed. Thanks already!
P.S.: If this works and you feel adventurous, you might want to try speeding things up:
#! /usr/bin/env python
import sys
from scapy.all import *
def arp_monitor_callback(pkt):
if ARP in pkt and pkt[ARP].op in (1,2): #who-has or is-at
print(pkt.sprintf("%ARP.hwsrc% %ARP.psrc%"))
sys.stdout.flush()
sniff(prn=arp_monitor_callback, filter="arp", store=0)