So during this quarantine break I was setting up a new network layout for my parents place which includes 2 wireless OpenWRT routers connected together via an 802.11ac channel. Each wifi router broadcasts an 802.11n AP which has the same SSID & KEY but on different CHANNELS and BSSIDS. The traffic can be forwarded back and forth between the 2 separate APs via the single private AC connection (using the OWRT relayd package):
/usr/sbin/relayd -I wlan1 -I wlan0 -t -1 -p -1 -B
Each AP has dnsmasq running, however, they are each set to hand out a subset of unique addresses that are shared in a /20 block (so that whatever AP you are on, you can communicate to any other host on any of the APs as if you are on the same network). I noticed that when switching between the 2 APs, my machine was getting the same last octet in the IP range set! I thought this was pretty cool because even though the rest of the IP prefix was different, I could simply memorize the last digits if I wanted to connect to another machine on the network in the future. I then started looking into dnsmasq’s source code to see how it was doing this since the only info DHCP usually has is one’s MAC address:
https://github.com/dnsmasq/dnsmasq/blob/master/src/dhcp.c#L638
…note: they added a fix for the j variable recently: j= instead of j+=…
…note: note: there is a IP loop and epoch counter variable that gets increased in case of any hashing collisions or errors that occur!
So if you compile the code below and want to pre-calculate your likely IP address when asking dnsmasq for one, you can run the following (you need to know the IP range that was given in your configs):
$ a="11:22:33:44:55:66" $ b=$(echo "$a" | sed -e 's/^/\\x/' -e 's/:/\\x/g') $ c=$(printf "${b}") $ ./dd "$c" 6 192.168.17.101 192.168.17.190 [192.168.17.106] [3842235635] [6]
---
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> int main(int argc, char *argv[]) { int i, l=atoi(argv[2]); unsigned int j, e=0; struct in_addr temp, addr; struct sockaddr_in beg, end; unsigned char *hwaddr = (unsigned char *)argv[1]; for (j = 0, i = 0; i < l; i++) { j = hwaddr[i] + (j << 6) + (j << 16) - j; } int pass; for (pass = 0; pass <= 1; pass++) { inet_pton(AF_INET, argv[3], &(beg.sin_addr)); inet_pton(AF_INET, argv[4], &(end.sin_addr)); temp.s_addr = htonl(ntohl(beg.sin_addr.s_addr) + ((j + e) % (1 + ntohl(end.sin_addr.s_addr) - ntohl(beg.sin_addr.s_addr)))); addr = temp; do { addr.s_addr = htonl(ntohl(addr.s_addr) + 1); if (addr.s_addr == htonl(ntohl(end.sin_addr.s_addr) + 1)) addr = beg.sin_addr; } while (addr.s_addr != temp.s_addr); } char str[64]; bzero(str, 64 * sizeof(char)); inet_ntop(AF_INET, &(addr.s_addr), str, INET_ADDRSTRLEN); printf("[%s] [%u] [%d]\n", str, j, l); return 0; }