Wi-Fi: Hostapd VLAN for guest network

Hello all and sorry for my lack of posts this year.

I have had many visitors who have given my private Wi-FI password because they needed internet access, but later I thought that I don’t like having them on my private network.

What I wanted was locking them out, without creating a new “Guest Network”, but keeping the same SSID/key. In other words, I’d wanted my trusted devices and the visitor’s devices on two Layer 2 separated networks. The answer is: VLAN.

Oh… The trusted list is a MAC address list.

My access point is based on hostapd, a linux daemon that is managing the Wi-Fi cards (PCI or USB) and it has a couple of settings to manage VLANs:

# Dynamic VLAN mode; allow RADIUS authentication server to decide which VLAN
# is used for the stations. This information is parsed from following RADIUS
# attributes based on RFC 3580 and RFC 2868: Tunnel-Type (value 13 = VLAN),
# Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value
# VLANID as a string). Optionally, the local MAC ACL list (accept_mac_file) can
# be used to set static client MAC address to VLAN ID mapping.
# 0 = disabled (default)
# 1 = option; use default interface if RADIUS server does not include VLAN ID
# 2 = required; reject authentication if RADIUS server does not include VLAN ID
#dynamic_vlan=0

# Station MAC address -based authentication
# 0 = accept unless in deny list
# 1 = deny unless in accept list
# 2 = use external RADIUS server (accept/deny lists are searched first)
#macaddr_acl=0

As you can see, one option is using the ‘accept_mac_file’ file, which permits a static mapping of your MAC Addresses <-> VLANs. Anyway, using this approach would force you to list all the MAC addresses of every device connecting to your Wi-Fi network. That’s because you can’t use any wildcard for the MAC addresses on that file!

But there is another approach, using RADIUS.

With ‘dynamic_vlan=1’ plus ‘macaddr_acl=2’, the accept/reject request based on the MAC Address pass through the RADIUS server, which reply with or without the “Tunnel-Private-Group-ID” (VLAN ID). The RADIUS server must be configured to accept any request (remember, the network is already protected by your PSK key) but including the “Tunnel-Private-Group-ID” parameter only to the unknown MAC addresses, because we want the well known MACs to be left on the default VLAN (dynamic_vlan=1 # use default interface if RADIUS server does not include VLAN ID).

This is the theory. Now the practice..

apt-get install freeradius

On a Ubuntu 15.10 I didn’t modify much of the freeradius configuration.

The most important file is /etc/freeradius/users in which we can define the replies to give back to hostapd daemon. You must configure first the well known MAC addresses with the Auth-Type ‘Accept’ but without the VLAN specification. For example my ESP8266 has the ’18:fe:34:fa:5a:ba’ MAC address, so…

18fe34fa5aba Auth-Type := Accept

Then, if an unknown MAC address is requesting connectivity to our network, we have a default entry accepting it and assigning the guest VLAN ID to it. On the hostapd side, this means that the device will be attached to the brvlan1000 bridge.

DEFAULT Auth-Type := Accept
Tunnel-Type = VLAN,
Tunnel-Medium-Type = IEEE-802,
Tunnel-Private-Group-Id := 1000

To complete the post, here’s my hostapd.conf:

interface=wlan1
bridge=br0

# AP Name Definition
ssid=MyNetwork
hw_mode=g
ieee80211n=1
ieee80211d=1
country_code=GD
wmm_enabled=1
channel=1

# WPA-PSK Passphrase definition
wpa=2 # WPA2 only
auth_algs=1 # 1=wpa, 2=wep, 3=both
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP
wpa_pairwise=TKIP
wpa_passphrase=secret

# RADIUS authentication server
own_ip_addr=127.0.0.1
auth_server_addr=127.0.0.1
auth_server_port=1812
auth_server_shared_secret=testing123

# VLAN Configuration #
#
# use default interface if RADIUS server does not include VLAN ID
dynamic_vlan=1
# defining vlan
vlan_file=/etc/hostapd/hostapd1.vlan
# use external RADIUS server for MAC Address filtering
macaddr_acl=2

Do not forget to define the VLANs on /etc/hostapd/hostapd1.vlan (1000 + default) and attach the brvlan1000 to your firewall with your rules.

 

BTRFS snapshots, a new way to upgrade your Ubuntu

Do you want upgrade your Ubuntu installation to the new 15.04 (Vivid Vervet) with the ability to rollback the upgrade anytime? Do you want to simply “try” the upgrade procedure leaving the system intact? You will only need the disk space to keep both versions, and the ButterFS will maintain the old system state in parallel to the new one. Quite cool, isn’t it?

One of the BTRFS features that I really love, is the ability to work on subvolumes and snapshots. For those who still do not know, the BTRFS filesystem is organized in some kind of “containers”, identified by labels or numeric IDs, called subvolumes. A subvolume can be used to “contain” the root filesystem, or the /home filesystem, or whatever, so you can think to it as a very advanced mix of partition and filesystem, together. Once created, the subvol can be mounted specifying its label/ID.

To create a subvolume ‘mysubvol’ on the partition /dev/sdX…

mkfs.btrfs /dev/sdX
mount -t btrfs -o subvolid=0 /dev/sdX /mnt
btrfs sub create /mnt/mysubvol

The list of subvol(s) and their IDs can be obtained with this command..

btrfs sub list /mnt
ID 257 gen 56437 top level 5 path mysubvol

Now we will mount the new ‘mysubvol’ on /mysubvol

mkdir /mysubvol
mount -t btrfs -o subvolid=257 /dev/sdX /mysubvol

That’s it. You can now play on /mysubvol (creating file, folders, copying whatever…).

The second key feature of BTRFS is the ability to take snapshots. Using this feature on a subvolume you can create a copy of it in just a second, without any additional disk space. This is possible because the filesystem is smart enough to know that the snapshot contains the same files already stored on the original subvol, so it won’t require any additional space. The snapshot *is* a subvolume itself, so it has a label/ID and it can be mounted wherever.

going back to the Ubuntu upgrade…

This procedure is not difficult, but you should have medium knowledge of linux administration. I won’t write here a step-by-step guide, but this would be just an hint for you to try and discover, so…

Think about having your Ubuntu root filesystem on a subvolume. You could make a snapshot before any system modification and rollback if necessary! But you could do more, having multiple subvolumes containing different Ubuntu versions or even multiple linux distributions at the same time and then configuring your boot loader to load the right subvol! Having them on the sameĀ BTRFS partition will bring you the advantage of deduplication (same 1MB file copied 1000 times still require 1MB of disk space), you can use snapshots, you can test any upgrade and going back to the origin any time…

You will ask yourself how you lived without till today!šŸ™‚

The best starting point is having your data stored on /home (another subvolume) and your kernel on a separate /boot partition (ext2 formatted). Furthermore, I really like to have my own compiled kernel because I can build-in the BTRFS support (or any other module required to boot..)

Summarizing …

  • compiling your own kernel makes the initial ram disk (initrd) unnecessary
  • having the kernel on /boot is easier to maintain, because you do not need to re-install the boot loader (LILO or grub) every time you modify the subvolume
  • having your data (/home) on a separate subvolume keeps the root subvolume “light” and easier to maintain

Now, if you wish to upgrade maintaining the old system intact…

Mount the main volume (subvolid=0) somewhere:

mount -t btrfs -o subvolid=0 /dev/sdX /mnt

On /mnt you should be able to see the current root subvolume: take a snapshot of it!

btrfs sub snap /mnt/rootfs /mnt/rootfs-snap
Create a snapshot of '/mnt/rootfs/' in '/mnt/rootfs-snap'
btrfs sub list /mnt/
ID 257 gen 56437 top level 5 path rootfs
ID 324 gen 56633 top level 5 path rootfs-snap

Now, start the update and don’t worry.

..after a few cups of tea..

.. your new Ubuntu Vivid VervetĀ  is running on the subvolume ‘rootfs’ (ID 257). The snapshot taken before the update (supposing you were running Ubuntu Trusty Thar 14.04 LTS) is still intact. Wanna boot into it? Just modify the kernel command line and reboot!

rootflags=subvol=rootfs-snap

Quite useful, isn’t it?

Connecting a SIP proxy to an internal PBX – asterisk / FreePBX

What about having your SIP address (and jabber/XMPP address) matching your e-mail address? Having a single address that identify you on multiple channels is called Unified Communications (described here by Debian) and it looks professional. I won’t write about the SIP proxy or Jabber/XMPP server configuration because it has already been done by someone else (www.rtcquickstart.org) probably better than what I could even be able to do.

My goal was another, once configured the system for Federated VOIP and connected my android phone to it (csipsimple), I felt the need to call the old-style numeric phone numbers using the same app. The idea came immediately to my mind: I had to search how to connect my new SIP address to my personal PBX (asterisk, FreePBX), which had been already linked to a cheap VOIP provider.

I started readingĀ  “Using the repro SIP proxy with Asterisk or FreeSWITCH“, then I found another guide pretty useful written by Daniel Popock (a resiprocate.org developer) but both guides did not match my goal at 100%.

Technically, I had needed the newly configured sip proxy (located on the public internet) to route any numeric DIDs to my PBX (located on my LAN) who wouldĀ  forwarded the call through the VOIP provider. Quite simple, or not?

Unfortunately it has been impossible to find a *complete* guide for what I was looking for, just confused settings scattered here and there without explanations. I’m not the kind of person that can copy-paste an entire configuration. In other words, I need to understand what I’m doing to reach my goal.

I started reading RFC about SIP and other stuff and then, after a couple on nights thinking and trying to make my setup working, the right solution appeared from the darkness. I’ll describe here the proxy setup, the asterisk setup and the firewall rules necessary to have this setup working.

The repro SIP proxy:


The repro configuration must define 2 SIP transports.

I used the TLS transport (tcp/5061 port) to connect my clients to the proxy itself and the TCP transport (tcp/5060 port) to connect the proxy to my PBX. If you followed the RTC HOWTO, the TLS configuration should be already done, what you are missing is the TCP transport. Let’s summarize the most important part of the repro’s configuration file.

Transport1Interface = PROXY_IP:5061
Transport1Type = TLS
Transport1TlsDomain = example.net
Transport1TlsClientVerification = Optional
Transport1RecordRouteUri = sip:example.net;transport=TLS
Transport1TlsPrivateKey = /etc/ssl/private/example.net-key.pem
Transport1TlsCertificate = /etc/ssl/public/example.net.pem

Transport2Interface = PROXY_IP:5060
Transport2Type = TCP
Transport2RecordRouteUri = sip:PROXY_IP:5060;transport=TCP

It’s also very important to define the realm of the proxy. In my case the realm is the domain name. It MUST match the realm used on the asterisk PBX, otherwise the authentication will not work. Please note that the asterisk default realm is ‘asterisk’, therefore you could also use that realm on the repro config.

HttpAdminRealm = example.net
StaticRealm = example.net

Restart the proxy and login to its web interface to setup the route for the numeric DIDs and remember to trust the IP/port/transport of your asterisk installation.

Click ROUTES -> ADD ROUTE

URI:^sip:([0-9]*)@example\.net
Destination: sip:$1@ASTERISK_IP:5060;transport=tcp

Click CONFIGURE -> ACLS

Add ASTERISK_IP, 5060 port and select TCP protocol

Using the standard port tcp/5060 for asterisk has been very important to me, because my SIP softphone (csipsimple) was ignoring any different port settings. It should NOT be a problem to use a non-default port, but in my case it was.. Don’t worry to leave that port opened from outside, you can setup a firewall rule to accept communications ONLY from the proxy IP address.

FreePBX/Asterisk settings


The settings described here can be adapted to any asterisk installation, but this guide refers to the FreePBX distribution. I assume that the asterisk installation is on a private network behind a firewall forwarding only the RTP ports and the tcp/5060 to the asterisk box. Note that the firewall rules should permit any source address to reach the asterisk’s RTP ports (UDP only) but, on the tcp/5060 port, the source address MUST be restricted toĀ  the proxy IP *only*. In my case, the firewall WAN have a static IP address, that’s better (and easier) to setup.

On asterisk we have to:

  • enable the TCP/5060 port
  • set the realm matching the realm of the proxy server
  • create a user with the same credentials used on the proxy
  • Set the externip and localnet correctly (on FreePBX: Settings->Asterisk SIP Settings)

On the FreePBX web interface, open the Settings -> Asterisk SIP Settings menu’, then add those settings at the end of the page..

tcpenable=yes
tcpbindaddr=0.0.0.0:5060
realm=example.net

Now proceed to create the extension_name (the part before the @ sign of the sip address).

Note that is not possible to configure an alphanumeric extension from the FreePBX web interface, because it only accepts numeric extensions. Asterisk has not that limitation, so you can open a shell session (SSH) to your asterisk server and edit the file /etc/asterisk/sip_custom.conf, adding the extension details as described below.

[yourname]
deny=0.0.0.0/0.0.0.0
secret=your_password
dtmfmode=rfc2833
dtlsenable=no
canreinvite=no
context=from-internal
host=dynamic
trustrpid=yes
sendrpid=no
type=user
nat=yes
port=5061
qualify=yes
qualifyfreq=60
transport=tls
avpf=no
srtpcapable=no
icesupport=no
encryption=no
callgroup=
pickupgroup=
dial=SIP/yourname
mailbox=yourname@device
permit=0.0.0.0/0.0.0.0
callerid=Your Name
callcounter=yes
faxdetect=no

yourname and your_password must be the same configured on the proxy, otherwise your client won’t identify correctly. Moreover, host must be dynamic and nat must be yes.

The dtmfmode in conjunction to the srtpcapable/encryption are the settings that controls the use of SRTP for the media channel. Remember that some clients refuse to use SRTP (for the media channel) if the signaling (SIP channel) is not encrypted too. That’s obvious becauseĀ  trying to setup a secure communication exchanging the keys over a not-encrypted channel is silly!šŸ™‚ Therefore, because the transport channel between the proxy and asterisk is not encrypted (standard tcp, remember?), the use of SRTP is inadvisable or not working at all. Anyway, I’m not describing here an encrypted communication setup, thus my settings will disable the encryption.

Another very important setting is the context which put the extension into the from-internal context. The client identified with that name/secret will be considered local, gaining access to the internal dialplan.

Firewall setup


Now the setup is almost complete, but nothing has been said about the security.

When I read about this setup, my first concern has been about exposing asterisk to the public internet. I really didn’t want a similar setup in any case. Having a proxy on internet and asterisk behind a firewall on a private LAN sounds more acceptable, isn’it?

On the repro SIP proxy (public IP):

  • 5061/tcp must be opened from anywhere
  • 5060/tcp should accept connections only from the PBX external IP

On the firewall protecting your PBX:

  • 5060/tcp must be forwarded to asterisk and the source IP must be the proxy only.
  • UDP ports 10000->20000 must be forwarded to asterisk and opened from anywhere.

Asterisk reserves 10.000 RTP ports for media channels. It’s a huge amount of ports, unnecessary if you are not bringing up a corporate system. Reading the asterisk FAQs, a single call can use 4 ports, so if you plan to do a maximum of 10 concurrent calls, you could use just 40 RTP ports. Asterisk can define the range of port to use, look here.

Final words


You should now be able to call any number on your asterisk dialplan from your new account sip:yourname@example.net. Pretty cool, isn’it?

https://freephonebox.net/

http://www.sip5060.net/test-calls (you MUST use mutual TLS to call those numbers)

http://www.voip-info.org/wiki/view/Phone+Numbers

Note: that I excluded from this guide any word about the ICE/TURN/STUN server, but If you experience audio problems, probably you should implement that server too. Don’t worry, it’s easy =)

QEMU guest with USB to Ethernet adapter (passthrough)

I encountered a problem trying to use my usb ethernet adapter (chipset asix AX88772) on a QEMU guest using USB passthrough. The device was visible to the guest, the link was up, but I were not able to communicate through the adapter.

After a while I realized that the guest was using USB 1.1 instead of USB 2.0, because I missed to specify the bus type to use (EHCI).

So, just a small hint to those that needs to use USB 2.0 with QEMU:

  • You must emulate the EHCI bus (usb 2.0)

-device usb-ehci,id=ehci

Now you can passthrough the USB device specifying the EHCI bus ID (note that in this case the bus ID is ehci.0, not just ehci) and the vendorid/productid of the USB device you intend to pass through

-device usb-host,id=asix,bus=ehci.0,vendorid=0x0b95,productid=0x7720

The USB to Ethernet adapter now works flawlessy.

Source: here!

 

Adding email reminders to Owncloud calendar with a bash script

Owncloud 6 calendar has notĀ yet implemented the email reminders.

I will show you how to send email reminders using a simple bash script started by cron. My goal is to have a weekly email, generated on monday morning, that reminds me about my week appointments, plus a daily reminder generated from monday to saturday. If you desire, it’s very simple to add a reminder generated x minutes before the event.

Requirements:

  • Owncloud must use MySQL backend.
  • A bash shell with SQL access to the owncloud database
  • If you want to send emails, a working MTA

The first thing you need is the ID of the calendar you want to examine.

SELECT userid,displayname,id FROM oc_clndr_calendars

Now it’s easy to write a bash script getting the events from the chosen calendar and performing some kind of action.

Here an example of sending an email with today’s events (remember to substitute the your_calendarid1 and your_calendarid2 on the SQL query in case you have multiple calendars):

query="SELECT startdate,summary FROM oc_clndr_objects WHERE calendarid IN (your_calendarid1,your_calendarid2) AND DATE(startdate) = DATE(NOW()) ORDER by startdate"

mail -s "Reminder for Today" you@example.com < <(mysql -uUser -pPass owncloud -Bse "$query")

Different query for the weekly reminder..

SELECT DAYNAME(startdate),summary FROM oc_clndr_objects WHERE calendarid IN (your_calendarid1,your_calendarid2) AND startdate BETWEEN DATE(CURDATE()) AND DATE_SUB( CURDATE(), INTERVAL -7 DAY ) ORDER by startdate

I’m not saying that this is the best approach, but until the owncloud developers are still working to integrate the reminders on the calendar UI, this could be a useful workaround.

How to make FreePBX searching Caller ID from a CardDAV server

My goal was to make my voip phone search for CallerID(s) through my mobile’s address book. I haveĀ  no coding skills, for this reason I was searching for a simple solution involving only existing software.

FreePBX (my admin interface to asterisk pbx) has an interesting module named Caller ID Lookup Sources. Using that feature you enable asterisk to search for the incoming CID(s) through various sources including MySQL, but unfortunately not through a CardDAV server. So, to reach the goal, you should have something that connects to the CardDAV server and keeps the addressbook syncronized with a local MySQL table (you could also use a carddav server that stores the data into MySQL, but that’s not my case).

Mine isn’t propably the best or cleanest solution but I’m using the roundcube webmail on the same server where asterisk is running and, you know, roundcube stores everything into MySQL, including contacts! Furthermore, itĀ  has a plugin to sync contacts from a carddav server!šŸ™‚ Now the circle is closed…

Now, leaving the theory…

With your mobile and the roundcube webmail syncronized to your carddav server, go to the “Module Admin” of your FreePBX installation and enable the Caller ID Lookup Sources. Now create a MySQL source looking into the roundcube mysql databaseĀ  (table carddav_contacts).

The query should be something like :

SELECT name from carddav_contacts WHERE `words` LIKE ‘%[NUMBER]%’

Obviously, when someone is calling, the variable %[NUMBER]% is substituted with the caller’s phone number and the query returns his name from the roundcube’s addressbook!šŸ™‚

Enjoy!

post scriptum: If you intend to make asterisk search the CallerID through your Google contacts, this is what you want.