Skittle Sorter

I had been working on a machine that sorts skittles by color. It’s made out of 3D printed parts, PVC pipe and some aluminum extrusion. It was a fun challenge, since I have given myself only a week to work on it. The entire design is from scratch, some parts are scavenged, some parts are there because it was all I could find. Between bouts of exhaustion, I remember how much fun and gratification there is in building something that exists physically, with the challenge of a deadline and the creativity that comes from using whatever is available.


Fisherprice Record Player Hack (Schematic and some code)

It’s been a while since I’ve posted progress on replacing the childrens songs in my son’s toy record player with full albums. Many who have seen it have asked to see schematics and code. When I get more time, I’ll post another video.

Schematic:

Screen Shot 2014-03-19 at 11.56.13 PM

Code:

This code is running on an Arduino Uno. On the SD card I have named each track sequentially: track001.mp3, track002.mp3 etc.. Regarding nomenclature, tracks are not separated by albums. Instead, records[] is an array with each element containing the number of tracks in each album. needle[] is an array of inputs from the needle head (analog pins A0-A3) that I treat as binary and convert to decimal using the bit() function. This is how I map physical records to a particular set of mp3 tracks. It calculates what track to start on depending on how many tracks are in each album. So for example track012.mp3 starts the first track in the ‘Who’ album, which has a decimal equivalent of 6 represented in binary by the buttons on the physical player’s needle. The physical record has grooves that push down on the buttons on the needle (see video in last post). I use speaker_onoff to turn off / on an opamp to stop an annoying click that I encountered when changing tracks.. There is a physical pull down resistor (see schematic) to keep it off by default and pull it high with the controller only after it starts playing.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include <SFEMP3Shield.h>
 
SdFat sd;
SFEMP3Shield MP3player;
 
// Inputs correspond that correspond to head on record player
int needle[]={A0, A1, A2, A3}; 
 
int old_album=99; 
int speaker_onoff=5; // Pin to turn off the op amp
 
void setup() {
  pinMode(speaker_onoff, OUTPUT);
  digitalWrite(speaker_onoff, LOW);
  for (int i=0; i<4; i++)
    pinMode(needle[i], INPUT);
  randomSeed(analogRead(4));
  Serial.begin(9600);
  //start the shield
   if(!sd.begin(SD_SEL, SPI_HALF_SPEED)) sd.initErrorHalt(); // newly required in 1.01.00 and higher
   MP3player.begin();
}
 
 
void loop() {
  int album=0;
  // convert record player needle buttons to decimal
  for (int i=0; i < 4; i++)
    if(digitalRead(needle[i]))
      album+=bit(i);
  Serial.println(album);
 
  // Check if user change the record
  if (album!=old_album && album!=0)
    playalbum(album);
  else if (album==0)
    MP3player.stopTrack();
  old_album=album;
  delay(100); 
}
 
void playalbum(int album) {
  digitalWrite(speaker_onoff, LOW);
  MP3player.stopTrack();
  int album_begin, album_end, track;
  album_begin=0;
 
  //0zeppelin, 1who, 2jethro, 3doors, 4deep purple, 5sabbath, 6clapton, 7queen
  int records[] = {0,0,0,0,0,11,10,8,0,6,7,8,12,5};
 
  // Calculate what track to start on depending on the album
  for (int i=0; i<album; i++)
    album_begin+=records[i];
  album_begin++;
  album_end=album_begin+records[album];
 
  // Pick a random track in the album and play it.
  track=random(album_begin, album_end);
  MP3player.playTrack(track);
  digitalWrite(speaker_onoff, HIGH);
}

Wireless Guest Network With Web Authentication

In a previous post titled, “Home Wireless Router” I walked through my custom built FreeBSD, wireless router at home. In this post, we’ll add web based authentication for guests. Essentially, when an unknown users connects to our network and browses the web, we’ll display our own website with a note letting them know we’re watching. They’ll have to agree to behave before they can actually browse the internet on port 80.

This will build on the previous “Home Wireless Router” post; start there first and make the appropriate changes noted below.

Using dhcpd to setup a split network:

We’ll make 10.0.0.0/24 the network for trusted users and 10.0.2.0/24 the network for our untrusted guests. Perhaps, in the future we can even throttle their bandwidth!

Here is what my /usr/local/etc/dhcpd.conf file now looks like.

subnet 10.0.0.0 netmask 255.255.0.0 {
  pool {
          range 10.0.0.2 10.0.0.254;
          option domain-name-servers 4.2.2.1;
          deny unknown-clients;
  }
  pool {
        range 10.0.2.2 10.0.2.254;
        option domain-name-servers 66.206.120.20;
        allow unknown-clients;
  }
  option domain-name "CANAAN";
  option routers 10.0.0.1;
  option broadcast-address 10.0.255.255;
  default-lease-time 600;
  max-lease-time 7200;
}
 
group trusted {
        host phone { hardware ethernet 00:0e:08:d5:c9:af;}
        host dell { hardware ethernet 00:11:43:75:0d:89; }
        host android1 { hardware ethernet f8:7b:7a:f0:c8:4b; }
        host android2 { hardware ethernet f8:7b:7a:f0:71:8b; }
        host ipad { hardware ethernet 10:93:e9:41:8f:26; }
        host macmini { hardware ethernet 68:a8:6d:59:9f:c9; }
}

I’m embarrassed, I really didn’t pay for all of those Mac products. If it isn’t obvious, you’ll need to replace the hosts and their hardware Ethernet addresses with the actual hardware Ethernet addresses of your trusted machines.

Packet Filter

Our packet filter configuration (/etc/pf.conf) is going to look a lot different than it did when we only had a wireless nat, but it should be obvious what the differences do:

ext_if="re0"
int_if="bridge0"
allowed_out="{http, https, ssh, domain}"
table  {}
set block-policy return
nat on $ext_if from 10.0.0.0/24 to any -&gt; ($ext_if)
nat on $ext_if from 10.0.2.0/24 to any port $allowed_out -&gt;($ext_if)
no rdr on $int_if proto tcp from  to any port 80
rdr on $int_if proto tcp from 10.0.2.0/24 to any port 80 -&gt; 127.0.0.1 port 80

In my prior wireless post, I stripped out all my fancy variables. Since we are now referring to the internal and external interfaces quite often, we might as well make our lives a bit easier by using variables.

Nat’ing works as usual for the 10.0.0.0/24 network, however 10.0.2.0/24 only allows the ports we’ve specified in $allowed_out. The “rdr on” rule forwards port 80 on our untrusted network to our localhost’s port 80. So now, no matter what website our guests visit, they end up on our webserver! The “no rdr” rule excludes IP addresses listed in the “goodboys” table from our subsequent “rdr on” rule.

All we need to do once a guest authenticates is run a simple command from the command line to add their IP address to the “goodboys” list. That command would look something like this:

pfctl -t goodboys -T add 10.0.2.2

Setting up the web server
It’s pretty obvious what to do next. Setup a webserver on localhost. You can write any sort of authentication script you like. I’ve placed a simple note letting my guests know that I’m not a sucker, nor a socialist and that by using my network they agree to my terms. The link “I Agree” takes them to a simple php script:

$output=exec("/usr/local/bin/sudo /sbin/pfctl -t goodboys -T add " . $_SERVER["REMOTE_ADDR"]);
header ("location: http://www.mises.org/");

It would be simple enough to do that in any other language.

But wait… pfctl needs to be run as root…

Right.. Install sudo and add this to your /usr/local/etc/sudoers file:

www ALL=NOPASSWD: /sbin/pfctl -t goodboys -T add 10.0.2.[2-254]

I used a regular expression so that a vulnerability in my script couldn’t give a crafty guest free reign over pfctl. I’m sure you could also play with the permissions of /dev/pf and make use of /etc/devfs.conf … but ehh.. I think this does the trick.

Oh.. and don’t forget to change the netmask on your gateway

Our network is now 10.0.0.1/16 (not /24) in comparison to the previous “Home Wireless” post. You’ll need to make the change in ifconfig and rc.conf .

Maybe not so obvious pitfalls..

  • A crafty user could assign themselves an IP address on the trusted network. If this were a product and we were concerned with real authentication, we wouldn’t have a trusted “backdoor” network.
  • Only port 80 is forced into our authentication scheme. The user could still make use of any other protocol in the $allowed_out variable. Again, if this were a product, we’d keep other ports closed and open them using our “goodboys” table, which contains the list of authenticated users.

Home Wireless Router: FreeBSD 8

Perhaps a future post will demonstrate the use of FreeBSD for wireless AP’s in a commercial environment with roaming. This post will demonstrate a basic home router setup.

Hardware:

  • My wireless card (ath0) is equipped with the Atheros chipset.
  • Ethernet Nic (re0) is connected to a cable modem.
  • Ethernet Nic (em0) is connected to a switch for wired internet access.

Network:

  • Internal NAT: 10.0.0.0/24
  • We’ll bridge (bridge0) em0 and ath0’s wlan device (wlan0).
  • ISC-DHCP31 will respond to DHCP requests.
  • Packet Filter (PF) will do our routing.

You will need to know what to replace with your own configuration (not much).

Step 1: Install & Configure ISC-DHCP31 Server

  1. `cd /usr/ports/net/isc-dhcp31-server`
  2. `make && make install`
  3. Add dhcpd_enable=”YES” to your /etc/rc.conf file
  4. My /usr/local/etc/dhcp.conf looks like this (be sure to change the domain-name and any other custom settings):
subnet 10.0.0.0 netmask 255.255.255.0 {
  range 10.0.0.2 10.0.0.254;
  option domain-name-servers 4.2.2.1;
  option domain-name "CANAAN";
  option routers 10.0.0.1;
  option broadcast-address 10.0.0.255;
  default-lease-time 600;
  max-lease-time 7200;
}

Step 2: Configure Network Settings

  1. Add the following to /etc/rc.conf
pf_enable="YES"
pf_rules="/etc/pf.conf"
gateway_enable="YES"
wlans_ath0="wlan0"
create_args_wlan0="wlanmode ap"
ifconfig_re0="dhcp"   #remember this is my cable modem, it gets an IP address via DHCP
cloned_interfaces="bridge0"
ifconfig_bridge0="addm wlan0 addm em0"
ipv4_addrs_bridge0="10.0.0.1/24"
ifconfig_em0="up"
ifconfig_wlan0="ssid chicken up"
hostname="CANAAN" #You'll want to change this.

Step 3: Configure Packet Filter

  1. Add the following to /etc/pf.conf
nat on re0 from 10.0.0.0/24 to any -&gt; (re0)

REMEMBER: re0 is the ethernet device connected to my cable modem. Your setup WILL be different. Want to learn more about that Packet Filter rule? Here is an EXCELLENT tutorial: http://www.openbsd.org/faq/pf/nat.html

Done! Who thought it could be so simple?

You can either restart your computer or:

  1. `/etc/rc.d/netif restart`
  2. `sysctl net.inet.ip.forwarding=1`
  3. `/etc/rc.d/pf start`
  4. `/usr/local/etc/rc.d/isc-dhcpd start`