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;
}