A great start to the New Year

Happy New Year! FlingOS had a fantastic year in 2015 and 2016 promises to be another exciting year of big progress. Here’s some of the highlights from 2015 and our plans for 2016.

Happy New Year! FlingOS had a fantastic year in 2015 and 2016 promises to be another exciting year of big progress. Already in the first 24-hours of 2016 we’ve had over 12,000 views of our website (and that’s before we count the blog, community forums, codebase and YouTube videos!) Here’s some of the highlights from 2015 and our plans for 2016.

Our first summer intern, Roland Baranyi, joined us to add MIPS support to our compiler and created our FlingOops testing kernel. Sponsored by Imagination Technologies, Roland helped reform the Drivers Compiler into a cross-platform compiler and added the MIPS target architecture library. We also created a basic test kernel for the Creator CI20. More on where this is headed in 2016 further down!

On September 17th we launched a new FlingOS – a total new look for our website and a lot of content and progress to back it up. We added over 30 new articles and published our 10-video Getting Started tutorial series on YouTube. Since launch we’ve had thousands of views per month of the articles and just over a thousand per month of our videos.

On top of all that, I’ve been presenting about FlingOS and the educational problems the project is solving, in and around Bristol. I’ll be giving another talk in Hereford in February 2016. I also ran a series of lectures and workshops in the University of Bristol which were a resounding success.

In 2016 we’re aiming to build on our progress but also to better align what we’re producing with what industry wants and education needs. To achieve this, we’ll be creating an OS dev starter kit, aimed at A-Level and first-year university students.

The kit will be based on a embedded device to align with what new OS dev industry is aimed at (and which we hope Imagination will support us with using the Creator CI20 or their latest CI40 board). We will be creating a complete self-teach course and lecture course (with slides, notes, examples and exercises) and selling the complete kit at low cost. But as always, our main codebase a core articles will remain free and open-source.

To succeed in producing all this, FlingOS needs sponsorship (or investment) to hire 3 to 5 interns next summer (myself included!) and to cover our basic costs. We’re still looking for sponsors, investors or people to donate! Please head to our Sponsor page to find out more if you think you can help.

2016 promises to be a year of big progress, with lots of new articles, a solid codebase and more great tutorial videos. We hope you’ll join us on our journey and support us by sharing, liking and Tweeting (@Fling_OS).

Many thanks to everyone who helped make 2015 a solid milestone in the project’s development!

Following up: “Avoiding the UK IoT Disaster” (BrisTech, 2015-12-03)

I thought I’d take the time to write a short blog post following up on my presentation that I gave to BrisTech the other night (2015-02-03) titled “Avoiding the UK IoT Disaster”. In the talk, I highlighted not security or technical problems with IoT but a key educational problem that will be putting our industry at serious risk: Low-level development is not being taught in schools and is barely taught at Universities. Slides are available here.

During the presentation I highlighted a couple of possible problem-applications, where IoT devices are being programmed using high-level code (often Python) on top of an embedded Linux stacks. Such stacks and programming in Python allows rapid development and ease-of-update in future (which is useful/key for security) but sacrifices hardware efficiency and, even more so, battery life.

The specific example that I brought up was an IoT thermometer programmed in Python with wireless connectivity. I stated during the presentation that such a setup was not a good idea because thermometers were relatively simple devices that didn’t require such a complex stack and also that, as a device installed in a home, you would want a decent battery life.

This example caused some controversy and was the subject of a lot of the discussion at the end of the talk. One member of the audience, who works in the IoT industry, gave an interesting piece of analysis which is where I would like to start. His key point I feel worth highlighting is that, in his work, he sees three types of IoT device:

  1. Long-term, hard-to-replace devices, such as tremor and stress sensors built into bridges which often can’t be replaced, need to be extremely reliable and last a very, very long time (relative to standard technology cycles).
  2. Long-term, easy-to-replace devices, such as the thermometer example I gave earlier. These are devices which the user may want to have for a long time but they are easily replaceable.
  3. Short-term devices, where short-term is roughly the length of a standard technology cycle, 18 months to 2 years. These are devices which we would only expect to last that length of time before they need replacing.

The design approach for type (1) devices is relatively straightforward to analyse. These are devices which we may never be able to replace and which need to last a long time thus battery life is a top priority. So is reliability and security, which is easier to assure when there is less hardware and less software to test. Minimising the amount of hardware and minimising the amount of software executing for any length of time is key to increasing battery life. This is only possible using low-level software where modules can be stripped to a minimum and Python certainly doesn’t come under the heading of “low-power”.

The design approach for type (3) is arguably equally simple because the developers are likely to need the device to come quickly to market and to rapidly develop the next version and the version after that. This means Python and embedded Linux, which has regular security updates, and keep be developed and reasonably tested pretty quickly, makes sense.

The design approach for type (2) is what caused the most debate. Arguably, it is better for the user if the battery life is longer since, for a long-term device, it will be cheaper to not have to replace the battery or entire device so often. However, since the device can easily be replaced, it will probably not be an expensive, critical device with high per-unit margins (or at least, replacing the battery will be cheap so in the long-term, the per-unit profit is massively affected by the initial and maintained development cost). So using entirely low-level favours battery life but increases development cost. Using high-level significantly reduces development cost but also battery life and (possibly) user satisfaction. Which side of the line you go for probably depends on the specific device. Popular opinion at the talk was that Python for a thermometer was reasonable and on reflection I am inclined to agree.

In conversation after the event, Adam B. from Simpleweb showed me an unusual (but very cool) little device called an iBeacon. For those unfamiliar with iBeacons, they are small, thumb-sized low-energy Bluetooth devices which you can track the location of. This allows tracking people as they move through a shop or similar areas. The devices shown to me were sealed units, extremely small (so no space for big memory chips and processors nor heat dissipation) and without a replaceable battery. But per-unit they are pretty expensive and typical use cases require longevity. Thus software for such a device is likely to need to be entirely low-level, for battery life, despite the fact that the devices themselves are easily replaceable. This is an example of a type (2) device better suited to C-based dev than Python-based dev.

This example brought us to think about the development process for the devices. Adam, Roger Shepherd, a few others and I discussed the following areas which we agreed make sense as ideas but need significant work to improve or integrate with standard IoT development practices:

  1. As an example, using a Creator CI40 for rapid development (in Python or otherwise), experimenting with features, nailing down an exact design and then creating the final product in proper low-level code (if necessary). In an ideal world, it would be an easy, automated process to go from Python to pure low-level so that any device can be developed for best battery life. As it stands at the moment, this isn’t possible, which brings me on to points 2 and 3.
  2. GCC and similar C compilers are a nightmare to set up. Which makes development with them flaky and hard to do, all of which contributes to extended development time.
  3. Also, the C language and C libraries have poor modularisation in most code bases and there is a distinct lack of open-source, free systems for C-based package management. Thus, dedicated IoT software is either written from scratch every time or bought (at great expense) from another company (but often the bought libraries aren’t stripped down to just what is required). Thus low-level development for IoT (in C) is currently very expensive whereas in Python, there is great package management and modularisation.

Furthermore, as highlighted in my talk, C development is only going to get more expensive, as knowledge and understanding of low-level development by graudates entering the IoT industry decreases and the onus falls on companies to train new developers.

In conclusion then, while the example I gave during the talk was not the strongest technical example, there is still a strong case for teaching low-level development in schools and universities (though not to the exclusion of everything else). Furthermore, if  as an industry we could perfect a technique for high-level prototype development with easy transition to production low-level code, that’d be great. It would cut development costs, improve products (and reduce hardware costs). In the meantime, we will have to rely on team leaders to make an informed per-device choice of the tools and language used.

Stage 2 : Boot a custom OS

Earlier this week I tweeted that “Stage1: Boot a different OS – complete” meaning that I had successfully booted an alternative OS on the Creator CI20s (which were kindly provided by our sponsor Imagination Technologies®. Well, today I succeeded in booting a very basic custom operating system on the CI20s, so here’s how I did it.

For starters, I downloaded and installed the current compiler toolchain for Windows – Sourcey Codebench for MIPS available here. I installed mine to a non-standard directory but it works just fine. We’ll come on to how to use it later.

I also downloaded and install Putty and Serva – both of which are necessary tools. Putty provides a console interface to the serial connection required to talk to the CI20’s U-Boot bootloader. Serva provides an easy way to set up a TFTP server on Windows. Both of these tools are free. Again, we’ll come on to how to use them later.

Lastly, I had to buy one small (cheap) bit of extra hardware – a USB to UART converter. Be aware that there are two chips widely used to produce these devices. One of them only supports Linux and version of Windows 7 and earlier. The other chip supports Linux and all current versions of Windows – so make sure you get the right one! I bought one for Windows 8.1 (i.e. the second type of chip) from Amazon (with one day delivery on a Sunday no less!). I ordered from 3C4u who use Amazon. (The first time I tried to order two of these the package never arrived. I re-ordered and they were delivered fine. Amazon gave me a refund and Prime subscription extension for the first order so I’m not complaining too much!)

For the custom OS I wanted to try out something which I knew worked. So I went online and found Lardcave.net’s great series of tutorials on writing a custom CI20 OS. I cloned the Git repo and started following the instructions. For the USB to TTL chip I have, the tutorial is correct, you need to connect RXD on the converter to TXD on the CI20, and visa-versa for TXD on the converter and RXD on the CI20. To avoid having to use the power cable, you can also attach the 5V pin to abny of the CI20’s 5V_IN pins on the primary expansion header. The board will power on as soon as you connect the 5V pin so hold off until later for that! You’ll also need to connect an Ethernet cable to the same hub or switch your PC/laptop/WiFi hub is connected to – this will be so the CI20 can connect to the TFTP server.

After cloning the Git repo I ran across a few issues. The Lardcave.net tutorials were written for Max/Linux and for if you compile GCC yourself. Since I installed Sourcery CodeBench , the Makefile was not set up to compile properly. I eventually worked out how to it so it works properly. Here is a copy of my make file:

AS=mips-linux-gnu-as -mips32
CC=mips-linux-gnu-gcc
LD=mips-linux-gnu-ld
OBJCOPY=mips-linux-gnu-objcopy
CFLAGS=-Os

OBJS=start.o main.o

hello.bin: hello.elf
 $(OBJCOPY) -O binary $< $@

hello.elf: $(OBJS)
 $(LD) -EL -T linker.lds -o $@ $+

%.o: %.[Sc]
 $(CC) $(CFLAGS) -EL -c -o $@ $<

clean:
 rm -f *.o *.elf *.bin

I combined this with a simple batch script called build.bat in the same directory as the Makefile which allows me to specify the path to Sourcery CodeBench’s bin folder, instead of other version of GCC which I have installed. The batch script looked like this:

@echo off
SET BD=C:\Users\Ed\Documents\Coding\C\2015\MIPS\Compiler\bin
%BD%\cs-make
pause
@echo on

Where BD is set to the path to Sourcery CodeBench’s “bin” folder.

Having compiled the “hello.bin” file I proceeded to set up Putty and the TFTP server. Here are a series of images I took showing the process. By the time I was done entering the commands into Putty (also shown below), the CI20 showed the nice, purple LED as expected.

2015-08-02 - Putty Config
Putty configuration

For the Putty configuration shown above, remember to update the COM port name to the name of the COM port device on your computer. This can be found by opening Device Manager and looking under the Ports node of the tree.

Serva config
Serva config

For the Serva configuration shown above, remember to update the “TFTP Server root directory” to the same folder as your “hello.bin” file is in.

2015-08-02 - Putty Console
Putty console

For the commands to U-Boot, remember to replace the serverip “192.168.0.6” and the ipaddr “192.168.0.20” with values for your network. The IP should be the IP address of the computer which is running Serva (which can be looked up by doing “ipconfig /all” in a Windows command prompt on the server computer). The “ipaddr” can be any value you like but the first three parts must match the IP address of your server.

2015-08-02 - Serva Log
Serva log

If the boot completes successfully, you should see a Serva log similar to the one above. The LED on the CI20 should turn purple as shown below.

Final result
Final result

Poor Design: A subjective statement

60 lines of code changed. 100 times faster.

By changing just 50 lines of code, I was able to make FlingOS™ read files from a FAT file system 64 times faster. Add just ten more lines and reading files from FAT on a USB stick is up to 100 times faster. But how can such small changes lead to such a large increase?

Progression: From good design to better design

The simple answer is: poor design. FlingOS is designed to be easy to understand both in terms of reading the code and in terms of overall structure and control flows. Unfortunately, this can lead to massive inefficiencies. FAT file systems, USB Mass Storage devices and EHCI Controllers are by no means simple, so writing clean code is difficult. Furthermore, writing code you can just jump-into without knowing the rest of the system is even harder. But that is what I have attempted with FlingOS (and hopefully achieved). So how can I call my original code both a poor design and a good design?

When I was first writing the code for USB Mass Storage devices, I decided that reading one sector was easier than multiple sectors. So I implemented the basic code for reading a single sector and that was that. Originally, therefore, the design was very good for simplicity and readability – the key things which make code understandable. But from a performance view it was highly inefficient (for both hardware and software). From one perspective my original design was good and from the other it was poor.

As the features of FlingOS have expanded (conforming to standards along the way), the underlying USB code has become capable of reading multiple sectors in a single request. The USB code has grown somewhat in complexity (by necessity) but remains understandable. With the new capability of reading multiple sectors all at once, suddenly my original design looks poor from both perspectives. Because reading one sector at a time makes no sense if you can just as easily read many at once. This reduces how easy the USB Mass Storage code is to understand because it adds a layer of confusion. As a result, it has become necessary to updater the USB MSD driver code.

But what about reading files from FAT? For that, FlingOS uses the FATFileStream class. Again, this is a story of progression. It started (and remained for a long time) totally simple. It just read one cluster at a time till it had read all the data that was requested. This was largely because reading multiple sectors at a time wasn’t supported by the underlying device drivers, so it was pointless to request more than one cluster at a time. But since the underlying device drivers (the USB Mass Storage driver, PATA driver and PATAPI driver) all now supported multiple-sector reads, why not? In fact, you can increase read speed by requesting as many contiguous clusters as possible. The algorithm for doing so is actually just as easy to understand as reading one sector at a time.

Today, therefore, I finally implemented the USB MSD multiple sector read and FAT File Stream multiple cluster read. It changed just 60 lines of code to utilise the new, underlying features. The result? Up to 64 (contiguous) clusters can be read at once and there’s no specific software cap on number of sectors to read at once. The overall effect of which is the code runs around 100 times faster (over small files. Possibly even faster for large ones due to other factors). This makes drivers loaded from a USB stick much more viable (which is what FlingOS is currently working towards).

Judging a design

So I’d like to leave you with this:

Calling code “bad” or “good” are highly subjective judgements.

You may call one piece of code very poor. Someone else may say it’s the best in the world. It all depends on how you’re judging it – be that by performance, readability, memory efficiency (which itself has many factors), lines-of-code used (ugh…) or any other measurement you care to make. All code will compromise (or excel) at something; you just have to work out what. When you’re judging someone’s code (even your own), remember to state what factors you took into consideration. What was your perspective.

The bug that went undetected for over a year…

Yesterday I announced that:

Just fixed a bug which has existed since the first week that I wrote FlingOS – so excited!!

I promised a blog post would follow, so here is that blog post – it’s going to be a good one. So sit back, relax and read on as I take you through the history of this bug.

When I first started writing FlingOS I had somewhere between no idea and less than no idea what I was doing. Seriously, all I knew was the structure of a C# to native compiler – I had worked on Cosmos for about 5 months but for various reasons I decided I wanted to write my own C# OS, with a different structure. I had my own compiler working relatively quickly and the next step was to implement basic features that would underpin the entire OS.

It’s probably reasonable to say that if something is going to underpin your entire system, you want to get it right, lest it have any nasty, invisible side effects later on. One such underpinning component was the Heap. Ahh the Heap… The heap implementation has caused much confusion and difficulty. This is not because a heap is difficult to understand or use, it’s just fiddly and crops up all over the place such that slight errors kill the entire OS. Some such errors have included not using spin locks (after I introduced multi-threading a few months back) and not allocating the heap enough space. (The heap space use to be allocated in the .TEXT section of the code! 120MiB .ISO files ;D With the new drivers compiler I shifted it to .BSS where it should be.)

When I first looked at implementing a heap, I wasn’t too interested in the internal workings. I knew what a heap did, I knew there were lots of ways of implementing them, each with pros and cons. I just wanted something simple and easy that I could use. Of course, FlingOS being one of only three active C# operating systems worldwide, there aren’t many (if any) suitable heap implementations floating around. However, there are lots of samples in C. The one I lumped for was a simple one from OSDev.

Over time I have adapted and updated the implementation to add things like allocation on or avoiding a boundary (as required by USB). The main Alloc function, however, has remained the same. Entirely the same. And this is where the issue lies. Early on in my development I found that with a 10MiB heap, my OS regularly seemed to run out of allocatable memory resulting in seemingly random page faults. My somewhat ignorant solution at the time was? : Make the heap 100MiB! This seemed to fix the problem, even though 90% of the heap was never allocated.

As time has gone on, page faults have appeared and disappeared sporadically until recently when I started trying to read large files from USB sticks. This used a lot of heap memory and suddenly the page faults were happening all the time. Not having really had to deal with page faults before I had no idea what was causing it. My instinct said that a page fault is due to unmapped memory, so something must be allocating an invalid pointer. But the heap wasn’t anywhere near out of memory. Unfortunately, with so many compiler changes going on in the past few months, there was no consistency to the issue. Even in the past few days the faulting address (or even instruction address) was not reproducible. It was seemingly random.

I investigated everything from interrupts to memory leaks to who knows what trying to trace this. Eventually I realised I wasn’t going to be able to unless I had a better view of two things:

  1. The sequence of events which lead to the page fault (and subsequent crash)
  2. The layout of all memory so I could see where things might be going wrong

For point (1) I had previously just outputted stuff to the screen through FlingOS’s BasicConsole class. But this wasn’t enough. I needed traceability and the ability to go back more than  a screen’s worth of information. So I implemented a new Serial class and hooked into the BasicConsole to redirect the output to a file on my host machine. As it turns out, I never needed to implement anything for point (2) – I realised what was going on before I got that far.

I realised the issue was to do with USB code, so I turned on all the trace code for the USB stack and inspected the output. The output contained the key piece of information : virtual and physical addresses of the memory the heap was allocating. They were invalid. They were valid addresses, but they didn’t fit inside the heap’s allotted block of memory! They were overrunning the end of the heap. I’d found my one, consistent piece of information.

Naturally I went looking for what could be overwritten by code writing to space beyond the end of the heap. Sure enough, immediately the heap memory were the unprotected page tables. And because USB uses physical addresses, there was no way I could have protected the page tables. I tested by allocating padding space between the page tables and the heap – sure enough the code took far longer to crash.

So the issue was in the heap. But the OSDev implementation looked pretty solid and many people had tested it. So I must’ve converted the code incorrectly to C#.  In the 18 months I’ve been doing low-level programming my understanding of pointers and pointer manipulation has grown – a lot. I went back to look at the heap in detail and found this spurious line of code:

void* result = (void*)(x * b->bsize + (UInt32*)(&b[1]));

This line of code is supposed to calculate the address of a block (x) with block size (b->bsize) and offset from the start of the heap (&b[1]). For those who understand pointer arithmetic they will easily see my mistake from when I converted the code – UInt32* will result in the pointer being multiplied by 4 (because UInt32 is 4 bytes in size). In my defence, however, the original line of code was thus:

return (void*)(x * b->bsize + (uintptr)&b[1]);

I asked a number of experienced programmers what they would expect uintptr to be a type for and all but one said: pointer to a uint (i.e. UInt32*). Only one was able to give me the actual definition (as per C99, which I found online) which is:

In C99, uintptr is “an unsigned integer type with the property that any valid pointer to void can be converted to this type, then converted back to pointer to void, and the result will compare equal to the original pointer”.

Great…so uintptr is not UInt32* it is in fact just UInt32 in C#.

Here’s a few caveats for those pedantic types amongst you:

  • Yes, pointers can be 8, 16, 32 or 64-bit. So it shouldn’t be UInt32 it should be some other form of UInt that allows agnostic size. However, FlingOS is entirely a 32-bit OS and C# doesn’t have a useful equivalent for uintptr (see next point).
  • Yes, C# has an IntPtr type – but it is intended for managed pointers and doesn’t play easily with most of the low-level code I’m trying to write for FlingOS. I may start using it in future, I may not. It might need some compiler updates to support it.

Detecting ATAPI drives

In the past few days I’ve been tackling a problem I’ve had for a while now – how to make ATAPI detection and retrieving device information reliable. I found that if I confined myself to a virtual machine then the existing code was pretty stable. However, with the large range of real-hardware I now have available to me, “it works in a VM” just wasn’t satisfactory. So I started testing and researching.

What I found was that I could reliably detect CD / DVD drives on all hardware. However, almost completely consistently, issuing the Device Identify Packet command resulted in the error bit being set. Yet my code worked exactly the same as many other people’s online examples. I reached the following conclusions:

  1. My code wasn’t doing something properly. It must be missing a step that would allow the ATAPI disc to respond properly.
  2. Other people’s code clearly hadn’t been tested on real hardware. There were various other indications of this which I won’t go into detail about here.

What I realised, however, was that once an ATA device has reported an error, it does not clear the error flag until you send it a new command. I also noted that part of the process of detecting an ATAPI disc, involves issuing the Identify command and then checking various registers to look for the PATAPI/SATA/SATAPI signatures. You check for the signatures even if the device reports an error.

So what was happening was some devices flagged up an error for the Identify command and some didn’t. The ones which did, required an additional command to be sent prior to the Identify Device Packet command otherwise it would still report an error. I went looking for a reset command and found one. Technically it only affects PATA/SATA not PATAPI/SATAPI devices. However, because it reset everything on the bus, and ATAPI devices have to be ATA responsive, ATAPI devices count this as a command. Thus issuing the Reset command clears the error flag. The problem was solved 🙂

Head over to this file on my dev branch in FlingOS’s BitBucket repository for sample Reset method code and usage.

Apply now for a sneak-preview of the tutorials…

The tutorial scripts are written and the resources are coming along nicely! FlingOS is about to enter the recording stage for its upcoming tutorial video series but if you’re excited to learn OS dev today, you can apply for a sneak-preview of the scripts! All we ask in return is that you provide some useful feedback on style, content coverage and perhaps the odd grammatical error too. Apply today by commenting below or emailing flingos@outlook.com or post on our Facebook page.

Easy PXE Network boot

I had been meaning to set up a network boot system for FlingOS for a while. Yesterday I finally got around to it and after several hours of trying different software and solutions, I finally found one which worked nicely.

I had been meaning to set up a network boot system for FlingOS for a while. Yesterday I finally got around to it and after several hours of trying different software and solutions, I finally found one which worked nicely.

There is a modest selection of software out there which will let you set up PXE Network booting. The majority of it focuses around Windows installation and updating. What I needed was a system that would allow me to switch on any network-connected laptop and have it boot the latest version of FlingOS that I just compiled on my PC or main laptop. FlingOS already uses Syslinux as its bootloader so it made sense to use the Pxelinux variant of Syslinux. Unfortunately, Pxelinux requires something that most PXE Server programs don’t support – something called the tsize command.

PXE relies on a combination of DHCP, Binl and TFTP to allow a PC to detect the availability of a PXE server and to retrieve the boot image(s). Pxelinux requires that the TFTP server supports the unusual tsize command. “tsize” allows Pxelinux to request the size of a file ahead of time i.e. before it starts to retrieve it.

After various attempts using Serva and other software, I came across TinyPXE. Finally something that would work. TinyPXE was written by a guy who needed a simple, effective, no-install solution to running a PXE server. Perfect. It even comes with support for Pxelinux, Grub and others. What’s even better, is that it can auto-load everything from a human-readable config file. So once you’ve worked out what setup you need, you can just put it in the config file and never have to worry after that.

Here’s a copy of the contents of my config file (config.ini):

[arch]
;will over rule the bootp filename or opt67 if the client arch matches one of the below
00006=bootia32.efi
00007=bootx64.efi
[dhcp]
;needed to tell TFTPd where is the root folder
root=G:\Fling OS\Fling OS\Kernel\Kernel\bin\Debug\DriversCompiler\ISO
;bootp filename as in http://tools.ietf.org/html/rfc951
;filename=ipxe-undionly.kpxe
filename=pxelinux.0
;alternative bootp filename if request comes from ipxe or gpxe
; altfilename=menu.ipxe
;start HTTPd
httpd=0
binl=1
start=1
dnsd=0
proxydhcp=1
;default=1
bind=0
;tftpd=1 by default
;will share (netbios) the root folder as PXE
smb=0
;will log to log.txt
log=0
opt1=255.255.255.0
opt3=192.168.43.1
opt6=192.168.43.1
opt28=192.168.43.255
;opt15=
;opt17=
;opt43=
;opt51=
opt54=192.168.43.120
;opt67=
;opt66=
;opt252=
poolstart=192.168.43.121
poolsize=20
;alternative bootp filename if request comes thru proxydhcp (udp:4011)
;proxybootfilename=
;any extra dhcp options
;my gpxe / ipxe dhcp options
optextra=175.6.1.1.1.8.1.1
;the below will be executed when clicking on the online button
;cmd=_test.bat
;if log=1, will log to log.txt
log=1
[frmDHCPServer]
top=441
left=258

Google Analytics spam data

I’ve been using Google Analytics on the FlingOS website for over 6 months now and while it is very good at tracking, with low-volumes of requests most of the tracking data is rendered useless. Spam websites such as free-social-buttons.com, ilovevitaly.com and simple-share-buttons.com log between tens and hundreds of requests per month. This leaves the remaining statistics heavily skewed.

These sites are performing these spam requests in an effort to get their referrer in your analytics list. This is in the hope that unwise web-admins will go to the referrer URL to see what is causing the traffic and then fall foul of the spoof sites which are there. These sites are distinct from auto-bots or search-engine crawlers in two primary ways. One is that crawlers don’t leave a referrer and often use a non-standard browser (or at least user-agent). Crawlers are not trying to pretend they are humans nor hide themselves. Crawlers also pay attention to do-not-follow headers, site maps and robots.txt files and so leave far fewer requests. Lastly, most crawlers are detected and automatically filtered by Google Analytics (based on the user-agent or other more sophisticated mechanism).

In an effort to reduce the level of spam, I switched on IIS’s IP blocking and reverse looked-up the various spam website’s IP addresses. This was, as it turns out, very effective. The number of visits with the targeted spam referrers almost entirely disappeared. Unfortunately, spam websites are relentless and as soon as you’ve eliminated one, another appears. I found myself endlessly updating the IP address block list. This is both tedious and dangerous because over time IP addresses shift, so the filter can potentially end up blocking genuine requests.

So how do I solve this problem? I don’t know! If you have any ideas, please let me know by commenting below or emailing me directly at flingos@outlook.com.