Quick Blog Links

  HTML Char Escape   [Python]
  RADIUS/SSH OTP   [Python / C]
  SSH-Pass Automation   [Python]
  VPN-Tunneled Traffic   [Python]
  DHCP/ARP Client-AP WiFi-Management   [C / Python]
  OpenSSH Setup   SSH VPN Tunnel
  FreeRADIUS Setup   Radius CA Capture
  Cisco/OpenWRT Setup   ebtables/iptables Firewall
  Seneca College – Secure LAN Communication   [Thesis]
  Seneca College – Teaching Hacking   [Paper]
  ARM Assembly – Basic Introduction   [Post]
  What Motivates Us   /   Career ~ Resume   /   Seneca Project Links   /   Office Space
Quick Blog Links

Trying out a modified version of openwrt for my linksys router

So there is modified version of openwrt (called davidc502) that is meant to include a more updated set of wireless drivers for the radios in the linksys wrt32x router. It’s a pretty cool alternative that I’m glad exists which is trying to make the stability and performance better for these devices that are poorly supported by its creators. For example, I recorded the wifi module versions of openwrt vs davidc502 below:

# opkg list-installed | grep -i wifi
kmod-mwlwifi - 4.14.195+2019-03-02-31d93860-1
mwlwifi-firmware-88w8864 - 2019-03-02-31d93860-1

# opkg list-installed | grep -i wifi
kmod-mwlwifi - 5.4.42+2020-02-06-a2fd00bb-1
mwlwifi-firmware-88w8864 - 2020-02-06-a2fd00bb-1
mwlwifi-firmware-88w8897 - 2020-02-06-a2fd00bb-1
mwlwifi-firmware-88w8964 - 2020-02-06-a2fd00bb-1

However, one thing to note, when I first ran netstat on it I was surprised to see soo many running services listening on all kinds of ports, I had to go through and turn most of them off in the services tab manually:


Trying out a modified version of openwrt for my linksys router

Trying to block all possible web connections to facebook (with the Chrome browser)

The first extension I always install in Chrome is “uBlock Origin” of course to try and prevent as many wasteful ads as possible but it doesn’t specifically target entire web properties such as all of facebooks sub domains that exist out there (for example, if someone puts a fb image or like button on their site and your browser loads that content, it’s another signal they can use with your information even though I don’t have a fb account).

I found a cool extension for Chrome called “Domain Blocker” which lets you specify wildcard sub domain names in a simple list to block any web requests at the browser level directly (no messy etc/hosts file setups or maintenance needed). For example, you can grab a master list of facebook domain names and place some basic regex in it to produce a nice short list to block automatically:

$ curl -sL 'https://raw.githubusercontent.com/jmdugan/blocklists/master/corporations/facebook/all' | tr '.' ' ' | awk '{ print $(NF-1)"."$NF }' | sort | uniq | awk '{ print $1 ; print "*."$1 }'


This will now produce a blocked message if your browser tries to load any content from any of those domains (links, imgs, scripts, frames, etc.):

www.facebook.com is blocked
Requests to the server have been blocked by an extension.
Try disabling your extensions.

Reminder: Also make sure to block third party cookies in Chrome’s settings as well, it will help a lot to keep things clean along the way!

Trying to block all possible web connections to facebook (with the Chrome browser)

Last piece of relay software needed for my home bridged network

If you are running a bridged/relayd network with macs on it you may need to also forward the multicast broadcasts (mDNS related) that allow the devices to automatically discover each other. On the WRT wifi client side, there is a pkg called avahi-daemon and you can configure to operate in “reflector” mode to forward these broadcasts across the specified interfaces. Running this service along with the dhcprb C program which takes care of layer 2 arp requests & dhcp gateway forwarding has been pretty smooth so far!

74:DA:88:8F:50:00  -47 dBm / -89 dBm (SNR 42)  990 ms ago
	RX: 1300.0 MBit/s, VHT-MCS 9, 80MHz, VHT-NSS 3   6413214 Pkts.
	TX: 1170.0 MBit/s, VHT-MCS 8, 80MHz, VHT-NSS 3   3557598 Pkts.

 2570 root       704 S    ./dhcprb br-wan wlan0
# /etc/avahi/avahi-daemon.conf




Last piece of relay software needed for my home bridged network

Final version of relayd functionality written in C (arp & dhcp bridging)

So it took me a while to update & re-write the dhcp relayd functionality that I made in python previously. This new C file can relay & rebroadcast both arp and dhcp packets via raw sockets. For DHCP relaying, it has to be able to insert the bridges IP address into the request so that the server replies back to us and then we can forward it on (so we can run only 1 dhcp server total on the network). The last interface specified in the list is designated as the dhcp server interface to send the requests coming in.

Also tried to reduce the number of system calls made by reading both the arp table proc file and routing table file instead (only 1 sys call to replace host route entries on the bridge router).

It’s been a while since I used select with multiple sockets but this compile uses less memory while running versus the python version, although the py version is easier to read and maintain (depends on your needs).


I’ll run this for a while and see how it performs!

Jon C

Final version of relayd functionality written in C (arp & dhcp bridging)

Last Part Of The WiFi-AP Bridge Setup (DHCP Relay/Forwarder) in Py

I was having troubles getting dnsmasq to be a simple DHCP relay/forwarder/proxy and I didn’t want to add this into the ARP relay C code to keep that as simple as possible so I wrote this little Python script that will basically bridge 2 interfaces together (one that has DHCP clients on it and one that is connected to the DHCP server [1 main server running for the whole network]).

I stored this in the ARP-relay GIT repo I created prior since it is related to the same bridged setup:

An example usage & output from running it so far:

root@OpenWRT:~# python dhcprb.py br-wan wlan0
('00:be:ee:ca:fe:00', '', '<-->', '00:be:ee:ca:fe:ff', '')
request-> ('', 68) [304] {wlan0}
<-reply ('', 67) [300] {br-wan:}
request-> ('', 68) [300] {wlan0}
<-reply ('', 67) [300] {br-wan:}

Last Part Of The WiFi-AP Bridge Setup (DHCP Relay/Forwarder) in Py

802.11n -> 802.11ac AP-Client Kick-Off Script (Py)

So I have been running multiple APs with the same SSID on separate channels and frequencies and noticed that the clients are really good at switching from a weak 802.11ac signal strength to the stronger but lower speed 802.11n AP station. This is good, however, they don’t seem to be as aggressive in switching back to 802.11ac once they get closer again (unless they turn off or shutdown or restart their network stack since the 802.11n just gets stronger the closer you get). I found an OpenWRT compatible shell script which kicks clients off a given radio depending on their signal strength to the router. I adjusted it to disconnect a client if they start to get too close to the N router as they are likely going to get a good signal strength from the AC AP instead. You can set the AP deauth time (ex 19 seconds), the time between kicking the same client on/off again (ex 31 mins), and it checks for the signal-to-noise ratio to get above a certain amount (ex 45 SNR) before activating on a client!

python apc.py n 20 40
import os,sys,time

radios = []
mode = sys.argv[1]
secs = (int(sys.argv[2]) * 1000)
macs = {}
band = (int(sys.argv[3]) * 60)

if (mode == "ac"):
	radios = ["wlan0"]

if (mode == "n"):
	radios = ["wlan1"]

while True:
	sec = int(time.time())

	for intf in radios:
		os.system("iwinfo '%s' assoclist | grep 'SNR' | tr '(/)' ' ' | tr -s ' ' > /tmp/apc.log" % (intf))
		f = open("/tmp/apc.log", "r")
		lines = f.readlines()

		for line in lines:
			info = line.strip().split(" ")
			(mac, sig, snr) = (info[0], int(info[1]), abs(int(info[6])))
			print("> %d %d [%s][%s]" % (snr, sig, intf, mac))

			if (secs >= 1000):
				delc = 0 ; kick = "true"
				opts = ("'addr':'%s', 'reason':5, 'deauth':%s, 'ban_time':%s" % (mac, kick, secs))

				if ((mode == "ac") and (sig <= -83)):
					delc = 1

				#if ((mode == "n") and (sig >= -51)):
				#	delc = 1

				if ((mode == "n") and (snr >= 45)):
					delc = 1

				if (delc == 1):
					if (not mac in macs.keys()):
						macs[mac] = 0
					if (sec >= (macs[mac] + band)):
						macs[mac] = sec
						print("* %d %d [%s][%s][%d][%d]" % (macs[mac], sec, mac, intf, sig, snr))
						os.system('ubus call "hostapd.%s" del_client "{%s}"' % (intf, opts))

	for mac in macs.keys():
		if (sec >= (macs[mac] + band)):
			print("x", mac, macs[mac])
			del macs[mac]


802.11n -> 802.11ac AP-Client Kick-Off Script (Py)

Creating a simple relayd replacement in C (compiled for an ARMv7 WRT router)

I’ve been running into different issues with relayd that I tried to manually fix in the framework, for example: not locking host route entries onto a specific interface, better detection for when a host changes interfaces, better arp table & ip routing management, etc.. However, I’ve still been experiencing some flakiness in it’s operation so I made a simple alternative that I can run which duplicates its most essential features needed for layer 2 bridging:

  • Layer 2 server socket to listen for ARP request packets
  • Layer 2 client sockets to send ARP packets with the routers MAC address inserted into the ARP replies for each host and for each bridged interface
  • Layer 3 UDP socket-based pinging for unknown host detection & discovery (auto IP-to-MAC ARP table entry resolution for each bridged interface)
  • Layer 3 IP routing-table host-entry updates related to which bridged interface the client is currently on

The code is just under 300 lines but it seems to be working so far and will keep testing it out to see if it works better than what I was experiencing with relayd!


arp req [42] [1544][256] [][]
arp reply [wlan0] [00:be:ee:ca:fe:ff][] <-> []
arp req [42] [1544][256] [][]
arp reply [br-wan] [00:be:ee:ca:fe:00][] <-> []

... snippet ...

void send_arp(struct intf relay, char *who_adr, uchar *dst_mac, char *dst_adr) {
	printf("arp reply [%s] [%s][%s] <-> [%s]\n", relay.ifn, relay.smac, who_adr, dst_adr);

	int sock = relay.sock;
	unsigned char *src_mac = relay.mac;
	struct sockaddr ssa = relay.ssa;

	struct in_addr src_adr;
	struct arp_packet pkt;

	pkt.frame_type = htons(FRAME_HW_TYPE);
	pkt.hw_type    = htons(ETHER_HW_TYPE);
	pkt.proto_type = htons(IP_PROTO_TYPE);
	pkt.hw_size    = HW_ADDR_LEN;
	pkt.proto_size = IP_ADDR_LEN;
	pkt.op         = htons(OP_ARP_REPLY);

	bcopy(src_mac, pkt.sorc_hw_addr, HW_ADDR_LEN);
	bcopy(dst_mac, pkt.targ_hw_addr, HW_ADDR_LEN);

	bcopy(src_mac, pkt.sndr_hw_addr, HW_ADDR_LEN); /* target mac */
	src_adr.s_addr = inet_addr(who_adr);
	bcopy(&src_adr, pkt.sndr_ip_addr, IP_ADDR_LEN); /* target ip */

	bcopy(dst_mac, pkt.rcpt_hw_addr, HW_ADDR_LEN); /* requester mac */
	src_adr.s_addr = inet_addr(dst_adr);
	bcopy(&src_adr, pkt.rcpt_ip_addr, IP_ADDR_LEN); /* requester ip */

	sendto(sock, &pkt, sizeof(pkt), 0, &ssa, sizeof(ssa));

Creating a simple relayd replacement in C (compiled for an ARMv7 WRT router)

Following along with the OpenWRT subreddit users

There was a post on a subreddit that I follow (OpenWRT) that was asking for peoples router/network setups and how they are using OpenWRT to accomplish that so I decided to try and make a network diagram of the setup I worked on here at my parents home while I’ve been working remotely (needing stable Internet/WiFi!). There are 2 levels that are covered and the Internet comes into the lower level which then gets sent up via a dedicated 802.11ac radio (separate backchannel). That is then rebroadcasted to the rest of the home with another dedicated, separate 802.11ac AP via the middle relay bridge in between. The relay bridge runs the customized app below that I compiled and it all shares one flat network throughout the home (one /20)! There is also 802.11n sent out for better reach and distance just in case as well 🙂

Edit: You can also add guest networks on each of the radios but with different SSIDs and wlan interfaces which will let them act like wifi-vlans that you can section off with dnsmasq & iptables…

Edit-edit (Updated diagram/layout):

I made this network graph with this site: https://www.lucidchart.com/documents#/dashboard

Historical documentation purposes,
Previous setup with semi-ok results:

Following along with the OpenWRT subreddit users

Turning a small stream cipher (ARC4) into a hash function (ARCH)!

$ python hash.py b b
('fd5f1b4640e0f5cdda0368b67601b9077cbe4a4931a94b52fdf46bf1be0c2bf5', '3a4627878dca5c4daeb243a661b56ebbaa03c268f659b6001cd84911051c103b', 'bb', 2)

$ python hash.py b c
('1181834e637bf3519010de1902889807341cd57a1d2e68a281524d91f2f86cf9', '7deadb485c3d329026d04cefadb4b43a9af19536aaf450052a2edce404f6065f', 'bc', 2)

$ python hash.py c b
('2f4802585ed79a61d25c92a3d7af8fa2a16e2e269e9c6fbd21891e6a7bae15ec', '6a25a3b18a93d966d7c878f9263f053d653618782a9f7918db05b06e0fa27787', 'cb', 2)

$ python hash.py c c
('6683682f501fdaa1c4a95e1ec6b7fb5ff49206af34e1729a17ded27fda355ea4', '7f12dc4dd32e3c9b31d03382b9c9af1efc0ea3ba620ba8e27fa9b9d8ebc1a88b', 'cc', 2)
import os,sys

def swap(s, a, b):
	t = s[a] ; s[a] = s[b] ; s[b] = t
	return s

def init(mesg, leng):
	j = 0 ; skey = []
	for i in range(0, 256):
	for i in range(0, 256+leng):
		k = (i % 256) ; m = (i % leng)
		l = (((i + 1 + ord(mesg[m])) * leng) % 256)
		j = ((j + skey[k] + skey[l]) % 256)
		swap(skey, k, j)
	return skey

def arch(skey):
	i = 0 ; j = 0
	l = 0 ; rnds = 4 ; outp = ""
	for z in range(0, 256*rnds):
		i = ((i + 1) % 256)
		j = ((j + skey[i]) % 256)
		swap(skey, i, j)
	for z in range(0, 32):
		i = ((i + 1) % 256)
		j = ((j + skey[i]) % 256)
		swap(skey, i, j)
		k = ((skey[i] + skey[j] + skey[l]) % 256)
		outp += chr(skey[k])
		l = (l ^ ord(outp[z]))
	return outp

def hmac(mesg, mlen, skey, klen):
	inner_pad = 0x36 ; outer_pad = 0x5C
	block_size = 64 ; ikey = "" ; okey = ""
	tkey = skey ; tlen = klen
	if (klen > block_size):
		zkey = init(skey, klen)
		tkey = arch(zkey)
		tlen = len(tkey)
	for x in range(0, block_size):
		c = 0
		if (x < tlen):
			c = ord(tkey[x])
		ikey += chr(inner_pad ^ c)
		okey += chr(outer_pad ^ c)
	zkey = init(ikey+mesg, block_size+mlen)
	ihsh = arch(zkey)
	ilen = len(ihsh)
	zkey = init(okey+ihsh, block_size+ilen)
	ohsh = arch(zkey)
	return ohsh

def stoh(inpt):
	o = ""
	for c in inpt:
		s = hex(ord(c))[2:]
		if len(s) != 2:
			s = "0" + s
		o += s
	return o

m = sys.argv[1] ; l = len(m)
k = sys.argv[2] ; n = len(k)
z = init(m+k, l+n)
print(stoh(hmac(m, l, k, n)), stoh(arch(z)), m+k, l+n)

Turning a small stream cipher (ARC4) into a hash function (ARCH)!

A simpler improvement to relayd (checking the arp table before expiring)

So instead of running a process heavy static arp broadcaster client/server service, I realized that I could just make relayd a bit smarter in order to properly detect disconnected hosts faster (simply by double checking the arp table). I was also able to compile this software in an Ubuntu VM running in a VirtualBox on OSX for mips & armv7 (archer c7 tplink & wrt1900acs wifi extended setup):


./relayd -I wlan0 -I wlan1 -t 2 -p -1 -B -D -P

With a couple of arp table clean up helper scripts the setup is much simpler with this and less involved in managing the arp table entries!

mode:  ap  |  ssid:  Peppi Place      bmac: 00:be:ee:ca:fe:01  key: psk2+ccmp  |  freq: 2.4GHz  chan:   1  mode:  HT40  |  timeouts: 300 300
mode:  ap  |  ssid:  Peppi Place      bmac: 00:be:ee:ca:fe:11  key: psk2+ccmp  |  freq: 2.4GHz  chan:  11  mode:  HT40  |  timeouts: 300 300
mode:  ap  |  ssid:  Peppi Place      bmac: 00:be:ee:ca:fe:61  key: psk2+ccmp  |  freq: 5.0GHz  chan: 161  mode: VHT80  |  timeouts: 300 300
mode:  ap  |  ssid:  Peppi Place AC   bmac: 00:be:ee:ca:fe:63  key: psk2+ccmp  |  freq: 5.0GHz  chan: 161  mode: VHT80  |  timeouts: 300 300

A simpler improvement to relayd (checking the arp table before expiring)