Smörgåsbord

Ambachtelijk bereide beschouwingen.

Nice hardware, but no channel 13

Last week I got myself a TP-Link TL-WR1043ND and pressed it into service as a smart 5-port gigabit switch (with VLAN capabilities) and wireless-N bridge. It is a fine piece of hardware and unbelievably cheap. Best of all, you can install the OpenWRT linux distribution on it. OpenWRT doesn’t target the inexperienced, but it is very customizable, offers a fair amount of documentation, and the build system seems very worthy of giving it a spin.

However. I noticed I couldn’t select a wireless channel >11. That’s odd, because over here in Europe we’re allowed to use the frequencies of channel 12 and 13, too.

Here’s what dmesg told me:

cfg80211: Calling CRDA to update world regulatory domain
cfg80211: World regulatory domain updated:
    (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)
    (2402000 KHz - 2472000 KHz @ 40000 KHz), (300 mBi, 2000 mBm)
    (2457000 KHz - 2482000 KHz @ 20000 KHz), (300 mBi, 2000 mBm)
    (2474000 KHz - 2494000 KHz @ 20000 KHz), (300 mBi, 2000 mBm)
    (5170000 KHz - 5250000 KHz @ 40000 KHz), (300 mBi, 2000 mBm)
    (5735000 KHz - 5835000 KHz @ 40000 KHz), (300 mBi, 2000 mBm)
ath: EEPROM regdomain: 0x0
ath: EEPROM indicates default country code should be used
ath: doing EEPROM country->regdmn map search
ath: country maps to regdmn code: 0x3a
ath: Country alpha2 being used: US
ath: Regpair used: 0x3a
phy0: Selected rate control algorithm 'ath9k_rate_control'
phy0: Atheros AR9100 MAC/BB Rev:0 AR2133 RF Rev:a2 mem=0xb80c0000, irq=2
cfg80211: Calling CRDA for country: US
cfg80211: Regulatory domain changed to country: US
    (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)
    (2402000 KHz - 2472000 KHz @ 40000 KHz), (300 mBi, 2700 mBm)
    (5170000 KHz - 5250000 KHz @ 40000 KHz), (300 mBi, 1700 mBm)
    (5250000 KHz - 5330000 KHz @ 40000 KHz), (300 mBi, 2000 mBm)
    (5490000 KHz - 5600000 KHz @ 40000 KHz), (300 mBi, 2000 mBm)
    (5650000 KHz - 5710000 KHz @ 40000 KHz), (300 mBi, 2000 mBm)
    (5735000 KHz - 5835000 KHz @ 40000 KHz), (300 mBi, 3000 mBm)

So why does the system think I am in the US? And how can I tell it that I’m actually in the Netherlands? At first glance, it should be as easy as iw reg set NL. Result:

cfg80211: Calling CRDA for country: NL
cfg80211: Regulatory domain changed to country: NL
    (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)
    (2402000 KHz - 2482000 KHz @ 40000 KHz), (N/A, 2000 mBm)
    (5170000 KHz - 5250000 KHz @ 40000 KHz), (N/A, 2000 mBm)
    (5250000 KHz - 5330000 KHz @ 40000 KHz), (N/A, 2000 mBm)
    (5490000 KHz - 5710000 KHz @ 40000 KHz), (N/A, 2700 mBm)

Looks about right, doesn’t it? Because 2482000 > 2472000. 2472 KHz is the upper bound of the 22 KHz wide channel 11. Likewise, 2482 KHz is the upper bound of channel 13. So am I all good for channel 13 now? Turns out I am not. iwlist wlan0 channel says:

wlan0     11 channels in total; available frequencies :
          Channel 01 : 2.412 GHz
          Channel 02 : 2.417 GHz
          Channel 03 : 2.422 GHz
          Channel 04 : 2.427 GHz
          Channel 05 : 2.432 GHz
          Channel 06 : 2.437 GHz
          Channel 07 : 2.442 GHz
          Channel 08 : 2.447 GHz
          Channel 09 : 2.452 GHz
          Channel 10 : 2.457 GHz
          Channel 11 : 2.462 GHz
          Current Frequency=2.452 GHz (Channel 9)

The wherefore and the why. And the how.

No channel 13. Wut? I found this informative mailing list post detailing what’s happening here. Basically, the kernel first loads the rules for the ‘world’ domain. On planet Earth, no countries exist that allow you to go beyond these frequencies (for domestic wifi). But many countries have additional restrictions. In Japan, you can use channel 14, in Europe you can’t. You can use 12 and 13 though, which in the US you can’t.
The kernel (well, the “ath” driver) then proceeds to look for any hints from the hardware. In my case the value burned into the hardware EEPROM is 0×0. That’s a value, which, per the Atheros specs, should map to the US. The kernel calls a userspace program crda to get the list of allowed frequencies and signal strenghts for the US.
After this has been done, you can do iw reg set FOO until you drop but you wont be able to go beyond the limits set previously.

The weird thing with radio hardware is that not only the users are subject to regulation, the sellers are too. You can’t sell non-compliant radio hardware. Now, the wifi chip manufacturers do not physically limit a chip intended for sale in the US to channels 1-11. Rather, they mass produce chips and then the equipment manufacturers are supposed to configure the chip in compliance with its target market. (As if you’d never take your equipment to Japan).
As I understand it, TP-Link messed up here.

Compare the above setup with what happens on my laptop’s Atheros chip:

ath: EEPROM regdomain: 0x65
ath: EEPROM indicates we should expect a direct regpair map
ath: Country alpha2 being used: 00
ath: Regpair used: 0x65

Looking at the Linux 2.6.35 sourcecode in drivers/net/wireless/ath/regd_common.h you’ll see that 0×65 maps to WOR5_ETSIC, which holds rules for compliance with EU regulation. Which I suppose is right since I’ve bought that laptop in the EU. But my TP-link comes out as FCC3_FCCA ­— that’s FCC-land, the US.

Fixing it

So either patch the kernel’s mappings, or patch the userspace ‘crda‘ program to supply a modified list of allowed frequencies for the ‘US’. I chose the latter. Reading a bit more about this program and its database, it didn’t appear I could fix it easily — the database is digitally signed and the public key needs to be known to the crda program at compile-time. No problem on a Gentoo system, but the target system was OpenWRT. On a MIPS machine. That meant cross-compiling, so I proceeded by downloading the OpenWRT dev environment for the Backfire release, and had a look around. And whaddayaknow, package/crda/patches/101-make_crypto_use_optional.patch made me hope that signature checking wasn’t even compiled in! On my OpenWRT box:

root@t33t:~# ldd /sbin/crda 
	libnl-tiny.so => /usr/lib/libnl-tiny.so (0x2aabe000)
	libm.so.0 => /lib/libm.so.0 (0x2aad6000)
	libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x2aaff000)
	libc.so.0 => /lib/libc.so.0 (0x2ab1f000)
	ld-uClibc.so.0 => /lib/ld-uClibc.so.0 (0x2aaa8000)

(Don’t you just love it). Now I don’t know a lot about embedded environments and uclibc, but I don’t see any libcrypto.so or libgcrypt.so in there. It looks like I can just supply any old unsigned database. More reading of documentation, some compiling of tools.
regdbdump /usr/lib64/crda/regulatory.bin gives me an editable version of the database. I didn’t feel like limiting myself, so I replaced this:

country 00:
	(2402.000 - 2472.000 @ 40.000), (3.00, 20.00)
	(2457.000 - 2482.000 @ 20.000), (3.00, 20.00), PASSIVE-SCAN, NO-IBSS
	(2474.000 - 2494.000 @ 20.000), (3.00, 20.00), NO-OFDM, PASSIVE-SCAN, NO-IBSS
	(5170.000 - 5250.000 @ 40.000), (3.00, 20.00), PASSIVE-SCAN, NO-IBSS
	(5735.000 - 5835.000 @ 40.000), (3.00, 20.00), PASSIVE-SCAN, NO-IBSS

country US:
	(2402.000 - 2472.000 @ 40.000), (3.00, 27.00)
	(5170.000 - 5250.000 @ 40.000), (3.00, 17.00)
	(5250.000 - 5330.000 @ 40.000), (3.00, 20.00), DFS
	(5490.000 - 5600.000 @ 40.000), (3.00, 20.00), DFS
	(5650.000 - 5710.000 @ 40.000), (3.00, 20.00), DFS
	(5735.000 - 5835.000 @ 40.000), (3.00, 30.00)

with this:

country 00:
  (2402.000 - 2494.000 @ 40.000), (N/A, 30.00)
  (4910.000 - 5835.000 @ 40.000), (N/A, 30.00)

country US:
  (2402.000 - 2494.000 @ 40.000), (N/A, 30.00)
  (4910.000 - 5835.000 @ 40.000), (N/A, 30.00)

and then I converted the database to its binary form with db2bin.py which one can find in the wireless-regdb source code releases. Copied the new database over to my OpenWRT machine, restarted it, dmesg, presto:

cfg80211: Calling CRDA to update world regulatory domain
cfg80211: World regulatory domain updated:
    (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)
    (2402000 KHz - 2494000 KHz @ 40000 KHz), (N/A, 3000 mBm)
    (4910000 KHz - 5835000 KHz @ 40000 KHz), (N/A, 3000 mBm)
ath: EEPROM regdomain: 0x0
ath: EEPROM indicates default country code should be used
ath: doing EEPROM country->regdmn map search
ath: country maps to regdmn code: 0x3a
ath: Country alpha2 being used: US
ath: Regpair used: 0x3a
phy0: Selected rate control algorithm 'ath9k_rate_control'
phy0: Atheros AR9100 MAC/BB Rev:0 AR2133 RF Rev:a2 mem=0xb80c0000, irq=2
cfg80211: Calling CRDA for country: US
cfg80211: Regulatory domain changed to country: US
    (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)
    (2402000 KHz - 2494000 KHz @ 40000 KHz), (N/A, 3000 mBm)
    (4910000 KHz - 5835000 KHz @ 40000 KHz), (N/A, 3000 mBm)
root@t33t:~# iwlist wlan0 channel
wlan0     14 channels in total; available frequencies :
          Channel 01 : 2.412 GHz
          Channel 02 : 2.417 GHz
          Channel 03 : 2.422 GHz
          Channel 04 : 2.427 GHz
          Channel 05 : 2.432 GHz
          Channel 06 : 2.437 GHz
          Channel 07 : 2.442 GHz
          Channel 08 : 2.447 GHz
          Channel 09 : 2.452 GHz
          Channel 10 : 2.457 GHz
          Channel 11 : 2.462 GHz
          Channel 12 : 2.467 GHz
          Channel 13 : 2.472 GHz
          Channel 14 : 2.484 GHz
          Current Frequency=2.452 GHz (Channel 9)

Legality

This is a rather libertarian approach. Not legal on Earth, it doesn’t even comply with the ‘World’ regulatory domain. Yes, among other things, this gives you access to the ‘Japanese’ channel 14. The rules don’t prevent you from going totally EMP on your neighbourhood. (Your hardware does, though).
It’s now YOUR responsibility to comply with local regulations. If you look out the window and see an airliner perform a barrel roll, you know it’s time to iw reg set $YOURCOUNTRYCODE.
And remember, interference works both ways. The fact that your neighbours cannot use some frequencies doesn’t necessarily mean you’ll get good performance using those (frequencies I mean). It may well be that you’ll have lousy reception because other (possibly more powerful) equipment is legally being used on those channels. Just stick with your country’s regulations OK?

I kept the previous ‘US’ entry as ‘UX’ so I can still comply with US regulations if necessary. I hear they’re big on regulations in the US. Especially if it involves foreigners.


Tags: , , , , ,

There are times you need to connect to ‘dirty’ networks such as public WiFi hotspots. Hopefully you’re ensuring that sensitive information is encapsulated in transport layer security enabled protocols such as SSL, because anyone on the same link (in the case of WiFi, that’s the air surrounding you. A vacuum will do, too, but that’s less common) can listen in on the traffic you’re sending. With SSL encapsulation such as HTTP over SSL (https://), your traffic can still be read — but for those who do it’s an extremely boring read because they don’t know the session key, only you and the other endpoint do. Hopefully.

One particularly nasty thing that can happen to you is when your machine is subverted into using the attacker’s machine as the router. That is known as ARP poison routing. The attacker can proceed to not only read the traffic coming from your machine (which, on a shared medium, could be done anyway), or read the traffic going into your machine (again: on a shared medium, that could be done anyway), but the attacker can now also modify the traffic between you and the rest of the non-local network, e.g., the internet, in both directions. And that’s when he can really go to town with your traffic. Injecting a javascript keylogger into all the webpages you visit. ‘Sidejacking‘ your sessions, so he does not even need to know your passwords, just your session cookies — which you happen to transmit with every page request.

All possible unless you use transport layer security, which is tamper-proof once properly set up. Once properly set up. But setting up can have problems of itself — there are ways of preventing you ever going from HTTP to HTTPS. If you know a thing or two about HTTP and SSL you’ll be delighted to learn about Moxie’s very evil but very clever ways of doing so.

Anyway, some level of security can be achieved if you tell your machine to ignore any messages sent to you from the other machines on the local network. That includes messages that will make your machine believe that the router has suddenly changed its physical address — which is quite unlikely to happen, but those messages are exactly the type of message an impersonator would send you. Of course we’d need to whitelist the routers of the network, otherwise we can’t get traffic out of it and onto other networks. DNS resolvers will need whitelisting too, unless you’re running one on your own machine (probably not).
Not openly announcing your presence may also be something you wish for. If you have ever been on a network with a Mac user you have probably seen them popping up in your Zeroconf service browser as “Firstname Lastname’s iSomething”. Let’s cut down on that kind of promiscuity, too. But you should understand now that you can not actually hide unless you turn off your WiFi. Shared medium, remember?

I prepared a simple script to accomplish the above. I’ve used ip from the iproute2 package instead of sticking to old-school route, ifconfig, arp & co. And I must say ip neigh flush nud stale has a poetic ring to it, wouldn’t you agree?

Take note: this will only protect you from some kind of attacks, and only partially. An attacker has a window of opportunity between your machine getting assigned a DHCP lease and you running this script, for instance. Or maybe the access point is rigged. Actually all protection other than end-to-end encryption combined with mutual authentication is pretty useless on shared networks ;-)

Here’s the script. Linux-only. If you want to use it, get the latest version from my public repository.

#!/bin/bash
 
# arpshield 0.2
# Protects against ARP poisoning and cloaks your machine for all 
# local link devices but the router(s) and the DNS server(s).
# Whitelisting DHCP servers also works if you use the dhcpcd program
# to obtain DHCP leases.
# This program is of no help if your setup is already poisoned.
# Have a look at ArpON (http://arpon.sourceforge.net/manpage.html) if
# you need more extensive protection.
#
# Needs 'ip', 'awk', 'sed', 'arptables', and 'arping' and expects
# them on $PATH. Needs appropriate privileges (so use sudo).
# Takes a network interface as an argument. The network interface
# should be up and configured. If no argument is given, clear all
# rules. Obviously you should do that before connecting to a new
# network.
#
# Copyright 2010 Wicher Minnaard (wicher@gavagai.eu)
# License: Creative Commons Attribution-Share Alike 3.0
 
# Do you use dhcpcd for aquiring DHCP leases? And is it running?
dhcpcdLEASEFILE="/var/lib/dhcpcd-${1}.info"
dhcpcdPIDFILE="/var/run/dhcpcd-${1}.pid"
test -f ${dhcpcdLEASEFILE} && test -f ${dhcpcdPIDFILE} && source ${dhcpcdLEASEFILE}
 
# In case you lack the luxury of dhcpcd, where is your resolv.conf?
RESOLV="/etc/resolv.conf"
 
# No user-servicable parts below this line.
DEV="${1}"
 
# I know, I know. But if your routing table contains 0.333.456.789 you have bigger problems ;-)
IPREGEX="\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}"
 
# Register
MACreg=""
 
# If not run as root, bail
[ "$(id -u)" != "0" ] && echo "You need root privileges to modify networking parameters. Exiting." 1>&2 && exit 2
 
getmac(){
# sets MAC register by IP. Sets to nil, if the MAC is not on the local link. 
  getMAC=$(ip neigh show ${1} | awk '{print $5}')
  if [ -z "${getMAC}" ]; then
    arping -c1 -I ${DEV} ${1} > /dev/null 2>&1
    getMAC=$(ip neigh show ${1} | awk '{print $5}')
  fi
  MACreg=${getMAC}
}
 
allow(){
  # Whitelists traffic to and from particular IP+MAC pairings and
  # adds them to static ARP.
  IP=${1}
  MAC=${2}
  if [[ -n "${IP}" && -n "${MAC}" ]]; then
    arptables -A INPUT  -s ${IP} --source-mac      ${MAC} -j ACCEPT
    arptables -A OUTPUT -d ${IP} --destination-mac ${MAC} -j ACCEPT
    ip neigh replace ${IP} lladdr ${MAC} nud permanent dev ${DEV}
  fi
}
 
if [ -n "${DEV}" ]; then
  # whitelist the routers
  test -z ${GATEWAYS} && GATEWAYS=$(ip route show dev ${DEV}| sed -n "s:.* via \(${IPREGEX}\).*:\1:p")
  for GWIP in ${GATEWAYS}; do
    MACreg=""
    getmac ${GWIP}
    allow ${GWIP} ${MACreg}
  done
  # whitelist the DNS servers
  test -z ${DNSSERVERS} && DNSSERVERS=$(sed -n "s:^nameserver \(${IPREGEX}\):\1:p" ${RESOLV})
  for DNS in ${DNSSERVERS}; do
    MACreg=""
    getmac ${DNS}
    allow ${DNS} ${MACreg}
  done
  # if using dhcpcd, we can whitelist the DHCP server too
  test -n ${DHCPSID} && getmac ${DHCPSID} && allow ${DHCPSID} ${MACreg}
  # set default policy to DROP    
  arptables -P INPUT DROP
  arptables -P OUTPUT DROP
  # clear out non-hardcoded ARP cache entries
  ip neigh flush nud reachable
  ip neigh flush nud stale
else
  # No argument given, so clean up.
  arptables -F
  arptables -P INPUT ACCEPT
  arptables -P OUTPUT ACCEPT
  ip neigh flush nud permanent
fi

Tags: , , ,
© 2009-2011 Wicher Minnaard | electronic mail | theme: righteously modified "dark strict"