Some high-end cars come with GPS trackers that report their position in case of theft (until the thieves put your car inside a refrigerated truck or metal shipping container on its way to its new “owner” abroad). These usually come with a monthly subscription of around £/$/€25, which seems like rather a lot when a mobile phone contract is often much less. What about making your own version that will last a lifetime, for less than the cost of four months’ subscription on a commercial version? In fact, it can do a lot more than that too!
This article contains some technical stuff about Linux, Raspberry Pis, navigation satellites, the cyber kill chain, Chinese espionage devices, NMEA sentences, Bash scripting, Google Maps APIs, funky car wiring, broken Land Rovers, DC-DC converters, cooking car criminals with CANBUS, and Perl. Don’t worry, there’s not too much Perl.
I live in London, so crime is… not exactly unknown. I’m also an engineer, so I have a propensity to put my own Linux-based computers in just about everything with a power supply. Thanks to Moore’s Law and Eben Upton, we’re now able to buy some seriously powerful computers for pocket money. Like the one represented by this abstract fruity logo:
Lots of people have put Linux-based computers in their cars before, and plenty of the cheap double-DIN head units you can find on eBay run Android, which is essentially Linux. I’m happy with the head unit my car comes with, I just want a hidden headless computer in the car that I can do lots of other stuff with. A bit like my rooftop music player that has subsequently become a dual-head DVB-T2 TV server and multi-band SDR receiver as well (more about that in future posts). It runs my rooftop fairy lights at Christmas, too.
Today’s requirement: a Linux-based headless “carputer” for GPS tracking
We want this thing to keep an internal log of its position, and also send its position to a remote server periodically so we can see its last reported position when it is offline.
You need a computer. I chose a Raspberry Pi 3B+ because it was the first one I found in my drawer. You could probably use a smaller and cheaper Pi like the Pi Zero, or a competitor like the Beaglebone, but make sure its USB ports can supply enough juice to run the 3G dongle because those things are thirsty. You could use a rack-mount quad-core Xeon if you really want to, but that would be silly. And your car battery won’t thank you.
GPS (or, strictly speaking, “GNSS”) dongle
There are loads of cheap dongles on eBay and Amazon, but I like those based on the u-blox MAX-7 chipset because they’re cheap and work well. They support both the American GPS and the Russian GLONASS systems so they can get a quicker and better fix by using more satellites. Some modern chipsets also support the Chinese BeiDou and the European Galileo system, when it’s working.
Whichever dongle you choose, it’ll need as good a view of the sky as you can give it. If you car has built-in Satnav then its GNSS antenna is probably hidden underneath a plastic panel on the roof, which is a good place to put it. It’s not so easy for us without ripping the car apart and poking holes in it. It’ll be fine under some plastic trim next to a window. A 1-2 metre USB extension cable won’t be too lossy.
OK, pedants: yes, 4G will work great and 5G is designed for exactly this kind of thing (although they call it the “Internet of Things, because they have a marketing budget). 3G dongles are cheap and plentiful and you want to keep the cost down so you aren’t going to be streaming HD films on this thing anyway. You want a connection that’s fast enough for a simple shell connection and flinging some lines of text between your car and a server. Cheap is good.
I’ve tried a few of these and – long story short – buy a Huawei E3231. They’re around £15-20 second-hand on eBay and they just work. I spent hours trying to get an older dongle to connect to the 3G network, playing with different kernel modules, server and client programs and APN settings to no avail. Perseverance is a fine quality in an engineer, but life is finite and I’ve got lots of other things to get done. Spend £16 and save yourself some grey hairs.
The E3231 is virtually plug-and-play. Raspbian automagically sets up a VLAN and a gateway so it’ll connect to the Interwebs just like that. It defaults to the 192.168.1.0/24 subnet, so make sure that doesn’t conflict with any other networks you have set up on your Pi. What else might you have connected? I’ve connected the Raspberry Pi’s built-in WiFi to the untrusted segment of my home network with a high-gain (+15dB) WiFi antenna on my roof pointing at my car in the street. This saves my monthly 3G allowance when I’m running updates and downloading GPS logs at home.
Of course, it is made by Huawei so we’d better encrypt anything we put over it, hmm?
This dongle also needs to be positioned somewhere with a good view of the nearest cell tower: use a short (for minimum loss) USB extension cable and, like the GNSS dongle, tuck it under the plastic trim near a window.
Prepay (PAYG) deals change all the time, but I got a PAYG SIM from 3 (a UK cell provider, not a typo) that cost £10 and tops itself up with 200MB every month for free. I’m their worst customer: my Pi never needs more than 200MB a month so I never need to pay a penny more. £10 for a lifetime of Internet connectivity – perfect!
Get Raspbian up and running on your Pi, then add some flavour. I’ve published the RPi and server-side code on Github.
GPS logging – NMEA 0183 and GPX
NMEA is the American standards body for electronics fitted to ships. NMEA 0183 is the standard (dated, replaced by NMEA 2000) used for sending information (GPS, AIS, wind speed, compass direction, etc) between a vessel’s systems. Since ships have made use of GPS for far longer than cars and mobile phones (and because they could justify the cost when it was still really expensive), NMEA 0183 messages have become the defacto output standard for GPS devices. If you cat the GPS device, you’ll probably see raw NMEA 0183. Here’s one such a message logged on my Pi:
$GP means it’s from the GPS system. GSA means the message contains a list of the satellites that are being used to determine a position fix. A means automatic and 3 means it’s a 3D fix. It’s using 8 satellites (30, 02, 09, 23, 06, 07, 29 and 16) to provide the fix. The extra commas are for more satellites (up to a total of 12) that it could use in the fix if they had a good enough signal. The last 3 figures before the * are the fix accuracy, expressed as DOP (dilution of precision) in metres for overall position (PDOP), horizontal (HDOP), and vertical (VDOP). The 04 on the end is a checksum.
MicroSD cards are cheap, so I don’t mind logging raw NMEA data on the Pi’s card. We’ll use gpsd to save all the NMEA sentences in a daily logfile on the Pi. The guys at Instructables have provided comprehensive instructions for this bit here.
As the Instructables folks have also pointed out, we’ll need to convert it to a useful format (like GPX) to do anything useful with it. GPSBabel is a great tool that does exactly that.
gpsbabel -i nmea -f [input_filename.nmea] -o gpx -F [output_filename.gpx]
There are lots of things that can display GPX files, including Google Earth with a simple drag-and-drop. Here’s one I prepared earlier. This is a GPX file that I created from the NMEA dump of a distillery tour I did on Islay. Bowmore, Laphroig, Lagavullin and Ardbeg. I won the coin toss and my amazing wife did the driving 😀
Sending our position to the server
There are plenty of websites that offer to do all this work for you if you send them your GPS position, but do you really trust them to follow your every move? Even if they’re not spamming your personal data all over the Internet, they’ve probably failed to secure their S3 buckets properly and are just waiting for Little Bobby Tables to come and play with their SQL API. As usual, if you want something done properly…
I’ve got a number of web servers doing various things. For the sake of argument, I’ll assume you also have a spare one for this purpose. It needs to be Internet-accessible (have a public IP address) and run a web server (like nginx or Apache).
We’ll use gpspipe to get our GPS data in a useful format. There are lots of different NMEA message types from our GPS device and we’re only interested in those that contain a position. We’ll get 10 lines of output from our GPS dongle (-n 10) and ask it to output in JSON format (-w) instead of raw NMEA. We’ll grep that output for positions (using the JSON tag “lat”):
gpspipe -w -n 10 | grep lat | head -n 1
We can extract the relevant JSON tags using jq:
lat=$( echo $gpsdata | jq '.lat' )
We want to save our (likely expensive) data allowance and only send updates when the vehicle has moved a certain amount. One degree of latitude is about 110km, so 10-5 degrees is about 10 metres. The size of a degree of longitude will vary with latitude (to zero at the poles) but, unless we’re using this for an arctic expedition, we can safely approximate a distance from longitude the same way.
moved=$(echo "scale=9; latdiff=(($lat-$lastlat)^2); londiff=(($lon-$lastlon)^2); latdiff || londiff " | bc -l)
That uses the bc (calculator) utility to take the square of the difference between the latitude now and the previous latitude (to make it positive) with a “scale” of 9 (i.e. to 9 decimal places). If it evaluates to 0 then the position has not moved significantly. It does the same with longitude and takes an XOR of those to output either exactly 0 (neither has moved significantly) or a positive number (at least one has).
We’ll use POST to send this data to the server, so we assemble the string and if the vehicle has moved we send it.
gpsstring=$(echo "-F 'dtg=$dtg' -F 'veh=$veh' -F 'lat=$lat' -F 'lon=$lon' -F 'spd=$spd' -F 'trk=$trk'") if [ $moved -ne 0 ] then curl -o sendcurrentposition.log -X POST $gpsstring https://servername/update.php fi
The complete bash script is on my Github.
Updates to your vehicle’s position are sent to update.php, sanitised and updated in that vehicle’s log file.
The default page (index.php) takes the name of the vehicle as a GET parameter and displays the vehicle’s position using LeafletJS. Check Github for the code: I’ve made some pretty graphics and added an infobox in the bottom corner.
You’ve got a remote headless server, so obviously you want to be able to SSH into it to control it. Problem: its IP address is at the whim of your cell network provider. You could use DynDNS, but it is probably hidden behind a NAT as well so that won’t help you. So you can’t SSH to your Pi from across the Internet. Oh noes!
Fortunately, hackers solved this problem years ago. Imagine you’re pentesting a client. You’ve thrown a USB stick over the fence into the company car park where loyal employee Joe Bloggs finds it and, being a helpful chap, wants to return it to its rightful owner. Joe sticks it into his computer to see what’s on it and it and, unbeknown to him, it installs the hacker’s malware in the background. Our white-hat heroine is working her way down the Cyber Kill Chain and has now passed Delivery (the USB stick), Exploitation (of an unpatched flaw on Joe’s computer), and reached Installation (of a persistent implant on Joe’s computer).
Mr Bloggs’ company has a commercial firewall at its network boundary, protecting it from nasty stuff on the Internet. So how does Ms Hacker get to the next step in the Kill Chain: Command and Control? How does she reach in from the Internet to control her payload?
She doesn’t – the implant reaches out to her instead. Most firewalls are designed to block external threats and don’t do much about internal ones reaching out to the Internet.
A Reverse Proxy is a simple technique that exploits this. Instead of our SSH client connecting to the SSH server on the Pi, the Pi connects to our server and presents its own SSH server as a port on our server that we can connect to with our client as if we were connecting to the Pi’s SSH server. Eh? Here’s an SSH command for the Pi that sets up a reverse SSH tunnel.
ssh -N -R [server_port]:localhost:22 [server_user]@[server_address]
You’ll need to set up a user on your server beforehand, and set up a certificate in your authorized_hosts file so it doesn’t need a password. You might use the same user and certificate that you used to upload your GPS data to the server. Make sure this user has very limited permissions. I’d recommend setting the user’s shell to /dev/null in your /etc/passwd file too.
Put that, or something equivalent, in to an executable script and put that script in a cronjob so it runs every time the Pi boots. Here’s the complete user crontab on my Pi, including the scripts for logging the position in the last section:
# m h dom mon dow command */1 * * * * ~/create_ssh_tunnel.sh > tunnel.log 2>&1 */1 * * * * ~/gpscurrentposition.sh > gpslog.log 2>&1 */5 * * * * ~/sendcurrentposition.sh > gpslog.log 2>&1
You’ll then be able to SSH to your Pi by SSHing to your chosen port on your server. You can reconfigure it, update it (be careful of your monthly data allowance!) and pull files off of it using SCP. Perfect.
Installing it in your car
Usual health-warnings apply: only do this if you know what you’re doing, get supervised by an adult (or an unusually precocious child), car insurance blah blah, don’t sue me, objects in the mirror aren’t vampires, your investment may go down as well as bang…
I used to own a Land Rover, so I learnt a great deal about fixing broken cars. If you’ve got an old one with electrics by Lucas the Prince of Darkness then you’ll know exactly what I mean.
“A Land Rover will go anywhere. And break down when it gets there”.Me, just now.
There are plenty of options for powering this thing, but the simplest option is to take a tap off a 12V supply somewhere convenient. Obviously, your Pi runs off 5V not 12V so you’ll need a step-down converter (aka “buck”) and there are lots of them available on Amazon and eBay. DROK is a reliable brand. Get one that can supply at least 3A at 5V so it isn’t struggling or getting hot. Get one with a MicroUSB connector on the end to make life easier.
In an older car there are plenty of wires connected to “+12V ACC” which are powered when you turn the key and unpowered when you’ve turned the ignition off – ideal for a GPS tracker. Unfortunately, I have a newer car with electrics that are too clever for their own good. I couldn’t find a convenient ACC cable so I had to connect it to BATT, i.e. permanent +12V. This is good for continuing to use the Pi after I’ve parked, but bad because it keeps draining the battery. I needed one of these:
This is a “low voltage disconnect module”, or battery-saver. It turns on at a pre-set voltage and off at another pre-set voltage with a handy green/red LED to tell you its state. I’ve set the DIP switches to turn mine on at +12.8V (when the alternator is running) and off at +12.1V so, if the battery is in good condition, it’ll stay on for a little while when I’ve parked but turn off before it kills the battery (I tried it set to 11.4V and I don’t want to have to jump start my car again).
Needless to say, every new circuit in the car should be fused in case something goes awry with the wiring. I installed my Pi near a fuse box in the back of my car, so the easiest way to tap into +12V with an inline fuse on my new circuit is one of these:
You put the original fuse in the bottom holder and an appropriate fuse for the Pi in the top holder. The Pi draws a maximum of 2A from a 5V supply, which is 10W, which is less than 1A at 12V. Add in a fudge factor for conversion losses in the step-down converter and I chose a 1.5A fuse. Obviously make sure the circuit you’re tapping into has enough capacity for another Amp, which shouldn’t be a problem 99.9% of the time. Assuming your car is chassis-earthed, connect the ground to a convenient bolt welded to something solid nearby. The end result looks something like this:
Et voilà! A headless carputer running Linux, turning itself on and connecting to your server every time it boots, logging its position and regularly sending updates to your server, turning itself off before it flattens your battery and with lots of spare capacity for future projects.
What else can I do with this thing now I’ve installed it?
Oh, plenty! Recording a mere few GPS positions leaves lots of CPU cycles free for doing more-exciting things. Here are some things I’ll think about when I have more time:
Add a camera
There’s a header on the Raspberry Pi for its own-brand camera, but really any old USB webcam will do. You could put it inside the car to take a selfie of the criminal who’s just stolen your car, and then send that, the GPS log and the car’s current position to the local rozzers to go and snatch the felon red-handed.
Alternatively, if you sit on the other side of the legal fence (and if you do you should be ashamed of yourself!), you could put the camera on the back of the car and run a some open-source ANPR software to alert you when the car behind you is an undercover police car following you home from your recent bank job. But don’t do that. It’s naughty.
Maybe you’d just like to record a picture of the scenery every ten minutes to document your road-trip. Car selfie!
Connect it to the Infotainment system
You could play music from your MP3 collection or Spotify account, if the mood takes you. Or you could play a message through the car speakers to the aforementioned criminal, politely asking him/her to refrain from purloining your pride and joy.
Depending on how your car is set up, this could be as simple as connecting an audio jack into your amplifier or as complex as tapping into the car’s fibre-optic AV CANBUS network. Which brings me on to…
Add a CANBUS module
Pretty much all modern cars have done away with thick wiring looms for discrete systems and instead use a bus to send messages between the various components. These things are usually hideously insecure, which is a good thing if you want to play with them.
You could log the engine performance of your racing car and link it to its position on the track you’re recording with the GPS logger.
You could make the car do strange things when it’s been stolen. I’d suggest this would include turning off the engine but, if you want to make the crim sweat a bit first (literally), then you could turn the heating and seat heater to max and lock the doors. Hours of fun.
CANBUS hacking is a huge topic in itself (which I may cover at a later date), but the good news is that Wireshark now supports CANBUS so it’s much easier to have a look at which messages are travelling over which bit of which bus and take it from there. You can get a USB CANBUS adaptor from eBay, or a cheap USB/Bluetooth OBD-II device that plugs into the diagnostic port you’ll find somewhere near the steering wheel of all modern cars.
My car comes with a small diesel-powered heater under the bonnet for pre-heating the cabin on a cold morning. You can set this on a timer the night before, but I never remember. I’d love to turn it on from my phone before I walk down to the car on a cold morning. A future project for the Raspberry Pi!