Annoying users abusing public WiFi? Automatically boot them.

At a cafe I frequent, people aren’t very considerate of other wifi users. I usually sit there and code and browse blogs and news, but some people like to watch Netflix, Youtube, Amazon Prime streaming, and basically do other stupid high-bandwidth things. I should note that this cafe usually has at least 20 people with laptops, and we’re all sharing a ~6mbit DSL connection with about 128K upload (as in about 1/8th of one mbit).

When people at this cafe watch videos, it sucks for everyone. The internet there is already stupid slow with that many people just browsing Facebook. When you add video streams to the mix, it becomes unusable. Normal ping times to my current place of employment (about 30 miles away) are in the neighborhood of 2,000-5,000ms. When I press a single key in an SSH session to my co-located server, it takes a few seconds for that to show up on screen. This makes coding on a remote box or trying to debug basically anything impossible.

Of course, I like to implement solutions when I have a computer problem, and this is very much a computer problem. The solution is the awesome Aircrack-ng suite of tools. I used to be quite a bit more involved in the Aircrack-ng community (testing beta software, helping with driver issues, helping in IRC, etc), but there hasn’t been much new interesting stuff happening there in a while.

First, we need to identify who is abusing their free internet access. To do that, we’ll use Airodump-ng to inspect the network. We need to be able to parse the output, so we’ll write out a CSV file. There is actually another step before this (putting the interface into monitor mode or using patched WiFi drivers) which should be automatic, but is otherwise left as an exercise to the reader(you’ll need to go through that stuff and modify this script a bit if you’re using an Atheros chipset and/or the excellent MadWiFi drivers).
(( If you’re having driver problems, I feel bad for you son, I got 99 chipsets but Broadcom ain’t one ))

Next, we need to parse our CSV and grab the MAC of clients who are being stupid. We’ll set the “stupidity” threshold based on packet count over a defined period (I picked 5 seconds, you might need to play with this a bit). I picked 50 packets over a 5 second period as my threshold (again, YMMV — is easy to change). We use some fun AWK to get this info, then launch Aireplay-ng to inject our deauth frames, and we’ll also go ahead and spoof the MAC of the base station, because connected clients tend to ignore deauth frames not coming from there.

For added fun, you can run this on a cycle every few minutes:

while true; do bash script.sh; sleep $(($RANDOM / 50)); done

Most users will eventually just stop being stupid or leave in frustration, which I’ll also consider a win for us in this case.

Update: Video demo now up on YouTube.

Clicky kitty:

Magento Connect Extension Key Unhider

I really really really hate sites that force you to register / login, and I’ll do anything in my power to circumvent them. Luckily, on the Magento Connect site, it’s super easy bypass the “mandatory” login just to get the extension key that you need to install an extension. The core of this hack is the following Javascript, which you could just run via your JS console:

document.getElementById("actkey").type = "none";

That sucker will pop the extension key up on your page just like logging in would. However, I also made a Greasemonkey script to do this for me because I don’t like typing all that in every time I need to hook up an extension. Click here to install.

Eliminate distracting sites with a little Bash

Sometimes you just need to force yourself to NOT look at websites. This simple bash script lets you manage your /etc/hosts entries and easily add sites to, remove sites from, enable, and disable the blacklist.

Usage:
Block a site: bash [script] add [site]
Remove a blocked site: bash [script] remove [site]
Enable all blocks: bash [script] on
Disable all blocks: bash [script] off

Note that if you don’t want something to be affected by this, just make sure it DOES NOT have a leading space — for example, if you want an entry to be “sticky” like ’127.0.0.1 localhost’ , then just make sure it doesn’t have a space in front of it and this script won’t disable it. Simple, elegant, and effective.

#!/bin/bash

case $1 in

"add")
  grep $2 /etc/hosts || echo " 127.0.0.1 $2" >> /etc/hosts
;;
"remove")
  grep $2 /etc/hosts && sed -i "/$2/d" /etc/hosts
;;
"on")
  sed -i "s/#/ /g" /etc/hosts
;;
"off")
  sed -i "s/^ /#/" /etc/hosts
;;
esac

Simple website monitoring with Python and pynotify

We had a problem: our website was going down from time to time and coming back up before our regular monitoring system (Opsview, based on Nagios) or Pingdom could catch it. I wrote a quick ditty to pull the URL up every 5 seconds and pop a notification if the site couldn’t be loaded.

To use this, you’ll want to change ‘someurl’, the ‘retryinterval’, and probably edit the ‘vresp’ list to be whatever response codes are acceptable to you.

Description of standard HTTP response codes

If there is any demand for it in the comments, I can adapt this to use smart-notify which would let it pop growl notifications on OSX.

import time
import urllib2
import pynotify

someurl = 'http://www.nexcess.net'
vresps = [200, 301, 302]
retryinterval = 10

def checkWeb(checkurl, httptimeout=None, validHTTPResponseCodes=None):
    if httptimeout is None:
        httptimeout = 10
    if validHTTPResponseCodes is None:
        validHTTPResponseCodes = [200, 301, 302]

    try:
        myresp = urllib2.urlopen(checkurl, timeout=int(httptimeout))
    except (urllib2.URLError, urllib2.HTTPError), e:
        return False, e

    respcode = myresp.getcode()
    if respcode in validHTTPResponseCodes:
        return True, respcode
    else:
        return False, respcode

while 1:
    ok = checkWeb(someurl, retryinterval, vresps)
    if ok[0] is True:
        print 'HTTP Code:', ok[1], time.asctime(time.localtime(time.time()))
    else:
        n = pynotify.Notification("Site down!", someurl + '\nResponse: ' + str(ok[1]) + '\n' + time.asctime(time.localtime(time.time())), "dialog-warning")
        n.set_urgency(pynotify.URGENCY_CRITICAL)
        # n.set_timeout(pynotify.EXPIRES_NEVER) # optional, makes the alert never go away automatically
        n.show()
        print ok[1], time.asctime(time.localtime(time.time()))

    time.sleep(int(retryinterval))

Wunderground forecast XML API in Python

The problem: I want to look up the weather from wunderground from my terminal without opening up a web browser. I figured “hey, this should be easy / fun to do using Python!” — WRONG! XML is always a pain to work with, and there is no *easy* way to get XML schema into a dict. Most people don’t even use XML correctly; you should use JSON if you just have strings inside of XML tags and nothing more. Every API I’ve ever seen / worked with uses XML in this way, and so they could all replace it with the *much* easier to parse JSON.

Update: You can now pass in the location as the first argument to the script. Currently only the first word before a space is supported due to some issues with urlencode that I don’t feel like solving right this second. You can use *any* location search format that wunderground supports; this includes zipcode, airport code, city name, etc. In the example below, I’m using ‘sfo’ which is the airport code for San Francisco, CA. There is also a default specified in the code should a location not be passed.

Anyway, here is what should come out when you run this:

likwid@helios python$ weather dallas texas
Location: dallas+texas
Sunrise: 6:18
Sunset: 20:37
Moon visible: 95% 

Friday - Partly Cloudy - 79F to 99F - 0% chance of rain
Saturday - Partly Cloudy - 79F to 104F - 10% chance of rain
Sunday - Partly Cloudy - 79F to 101F - 10% chance of rain
Monday - Partly Cloudy - 77F to 99F - 10% chance of rain
Tuesday - Chance of a Thunderstorm - 77F to 95F - 20% chance of rain
Wednesday - Chance of a Thunderstorm - 76F to 92F - 30% chance of rain

Perfect! Here is the code, which is much longer than I’d like for it to be. I would have used xpath, but apparently my lxml version didn’t have that.

Update: Thanks for the comment regarding lxml xpath! I’ll patch it on Github when I get a minute.
Update: Patched to accept location names like ‘dallas tx’ or whatever. You could do ‘ann arbor michigan’ and it would work as well!
Update: Now on pypi as ‘pycliweather’
Update: Now available as a Flask webapp on Github under the ‘webapp’ branch!

Clicky kitty:

Bash pick random cron time from array

At work, I recently needed to change the time that the cron.daily jobs run across a few hundred servers. Here is what I came up with:

#!/bin/bash
myarray=("0 1 * * * "
"15 1 * * * "
"30 1 * * * "
"45 1 * * * "
"0 2 * * * "
"15 2 * * * "
"30 2 * * * "
"45 2 * * * "
"0 3 * * * "
"15 3 * * * "
"30 3 * * * "
"30 4 * * * "
"45 4 * * * "
"0 5 * * * ")

num_arr=${#myarray[@]}        # Count elements in myarray

#grab a random time.  We could have put this line in the sed line, but the sed line is unreadable enough already!
crontime="${myarray[$((RANDOM%num_arr))]}" 

# in sedease, this says "select THE ENTIRE LINE (is why we have ^ and $) and replace it with our variable crontime and this other string"

sed -i "s|^.*/etc/cron.daily$|${crontime} root run-parts /etc/cron.daily|" /etc/crontab
Page 4 of 16« First...23456...10...Last »