Zabbix Aggregate Checks and “Unsupported Item Key”

Problem:

Trying to create an aggregate check in Zabbix to measure total bandwidth in a group of servers using ‘grpsum’, get status ‘Not supported’ and error message ‘Unsupported item key.’

Solution:

It’s not anywhere obvious in the docs  or after googling the error, but the item type needs to be changed from ‘Zabbix agent’ to ‘Zabbix aggregate’

Hide ‘attempt to remove non jni…’ logcat spam

Problem:

Tonnes of logcat spam in Eclipse ‘attempt to remove non jni local reference’

Solution:

edit filter configuration

^(?!.*(non-JNI)).*$

 

From http://stackoverflow.com/questions/16017356/how-to-hide-remove-filter-logs-in-the-logcat-in-eclipse-for-android

 

Converting InnoDB to MyISAM

Problem:

Trying to convert from InnoDB to MyISAM for smaller RAM footprint MySQL on a tiny VPS

Solution:

adding skip-innodb on its own didn’t work, had to add:

default-storage-engine = MYISAM

skip-innodb

And then run:

CONVERT_SCRIPT=Convert_InnoDB_to_MyISAM.sql
mysql -u... -p... -AN -e"SELECT CONCAT('ALTER TABLE ',table_schema,'.',table_name,' ENGINE=MyISAM;') FROM information_schema.tables WHERE engine ='InnoDB';" > ${CONVERT_SCRIPT}
mysql -u... -p... -A < ${CONVERT_SCRIPT}

Installing luasec with luarocks on ubuntu

Came across this error today while trying to install luasec:

Error: Could not find expected file libssl.a, or libssl.so, or libssl.so.* for OPENSSL — you may have to install OPENSSL in your system and/or pass OPENSSL_DIR or OPENSSL_LIBDIR to the luarocks command. Example: luarocks install luasec OPENSSL_DIR=/usr/local

The solution is to find the libssl files

find / -name ‘libssl.*’

and then add the the path using OPENSSL_LIBDIR on the end of the command, e.g:

sudo luarocks install luasec OPENSSL_LIBDIR=/usr/lib/x86_64-linux-gnu/

Minecraft DDOS protection part 1: GRE Tunnels

Chiisana from /r/admincraft has a really nice write-up about basic DDOS protection here, so rather than rehashing it I’ll just write a brief summary and then continue to extend the ideas a little, covering GRE Tunnels, Zabbix monitoring, and DNS automation with Cloudflare.

Basic Idea

When dealing with a Denial of Service by sheer bandwidth, by the time the traffic hits our server it’s already too late: no amount of shaping or blocking will change the fact that our link is saturated. To protect it, we sit a few cheap VPS’s between the players and the server and limit the bandwidth before it hits our server. The players are distributed between VPS’s using round robin DNS, and if attackers saturate one VPS link, the others will still remain up.

Adding GRE Tunnels

Rather than using tcptunnel, I’m using GRE tunnels, so that the minecraft server gets the IP of the player connecting, and not the VPS IP.

The BuyVM guide is a good start for setting up a GRE tunnel, but it mixes up the VPS and server commands a little, and doesn’t really explain what the commands are doing.

VPS commands:

echo ‘net.ipv4.ip_forward=1’ >> /etc/sysctl.conf

iptunnel add gre1 mode gre local VPS_GLOBAL_IP remote MC_GLOBAL_IP ttl 255

ip addr add 192.168.10.2/30 dev gre1
ip link set gre1 up

iptables -t nat -A POSTROUTING -s 192.168.10.0/30 -j SNAT –to-source VPS_GLOBAL_IP
iptables -t nat -A PREROUTING -p tcp -d VPS_GLOBAL_IP –dport 25565 -j DNAT –to-destination 192.168.10.1:25565
iptables -A FORWARD -p tcp -d 192.168.1.1 –dport 25565 -m state –state NEW,ESTABLISHED,RELATED -j ACCEPT

Breakdown

  • echo ‘net.ipv4.ip_forward=1’ >> /etc/sysctl.conf

This enables IP forwarding, and only needs to be run once.

  • iptunnel add gre1 mode gre local VPS_GLOBAL_IP remote MC_GLOBAL_IP ttl 255

This creates a new tunnel interface with the name “gre1”, with type set to “gre”,  local and remote IP’s defining the tunnel endpoints.

  • ip addr add 192.168.10.2/30 dev gre1

We then give the interface a private IP address used to communicate with the interface on the other end of the tunnel.

  • ip link set gre1 up

Bring the interface up, it should now be listed when running “ifconfig”

  • iptables -t nat -A POSTROUTING -s 192.168.10.0/30 -j SNAT –to-source VPS_GLOBAL_IP

Re-write the source IP of all packets coming from our tunnel out to the players to the global IP of the VPS

  • iptables -t nat -A PREROUTING -p tcp -d VPS_GLOBAL_IP –dport 25565 -j DNAT –to-destination 192.168.10.1:25565

Change the destination port and IP of the packets incoming from the VPS’s global IP to the other end of the tunnel

  • iptables -A FORWARD -p tcp -d 192.168.10.1 –dport 25565 -m state –state NEW,ESTABLISHED,RELATED -j ACCEPT

Finally we re-route the traffic down our GRE tunnel to the MC server.

MC Server commands:

iptunnel add gre1 mode gre local MC_GLOBAL_IP remote VPS_GLOBAL_IP ttl 255
ip addr add 192.168.10.1/30 dev gre1
ip link set gre1 up

echo ‘101 ATGRE’ >> /etc/iproute2/rt_tables
ip rule add from 192.168.10.0/30 table ATGRE
ip route add default via 192.168.10.2 table ATGRE

Breakdown

The first block is just the same as for the VPS except the IP’s are swapped round; remember not to use a subnet that conflicts with your LAN subnet.

  • echo ‘101 GRETUN’ >> /etc/iproute2/rt_tables

Linux has a pretty powerful set of routing features, in this case allowing us to define multiple routing tables so that we can define some source routing policies. This command adds a new routing table into rt_tables, that we can use to add some rules specific to our tunnel.

  • ip rule add from 192.168.10.0/30 table GRETUN

Tell our system that all traffic from 192.168.10.0/30 will be dealt with by our “GRETUN” routing table.

  • ip route add default via 192.168.10.2 table ATGRE

Send any traffic from our 192.168.10.0/30 subnet (that we have no route for) to the other end of our tunnel, the VPS.

Once your happy with your config, you can add it to /etc/rc.local so that it runs each time the system boots. This means you can change it easily simply by restarting.

Notes:

  • If your MC server is sitting behind a firewall and has no global IP, you can use 0.0.0.0 as the MC IP in the MC server config, point your VPS’s tunnel to your firewall’s global IP, and set up the firewall to pass gre traffic through to your MC server.
  • For any other services sitting on the same machine as the MC server, you can simply duplicate the iptables rules on the VPS, replacing the ports and protocol with that of your other service.
  • Since my website sits on a different machine behind the firewall, I’m going to use Cloudflare to mask it’s IP, which I’ll cover later on.

Customising Google Maps Markers pt.2, Graph Overlay

Quick update from the previous post: I decided I wanted to add more detail to my map by showing small pie charts instead of markers.

After trying and failing to use Google’s old Image Charts for the marker images, I found a very neat solution on StackOverflow that solves the problem nicely by rendering Google’s new interactive charts onto a custom overlay above the map:

map3

I then added a piehole to make overlapping charts easier to see:

map2

Passing in the extra data was also a slight pain because I needed to use a Dictionary<string, int> for the values of the pie chart, which csharp can’t serialise to JSON for some reason. Luckily someone has already written a nice serialisable version which did the job.

Next on the list is showing more details when clicking on the graph.

Customising Google Maps Markers

Quick delve into the world of Google maps this weekend when trying to map ADSL faults to their location.

My aims were to group the faults by the exchange they connect to, change the image icon, and resize it based on the number of faults at that exchange.

MarkerClusterer groups markers by proximity but doesn’t seem to allow custom grouping, so I decide to DIY it.

After testing the basics with PHP, I set up a simple WebService with C# that would provide the latitude and longitude of the Exchange, its name, and the number of faults. I then call the WebService using ajax:

$.ajax({
type: "POST",
url: "WebService.asmx/GetMarkers",
data: '',
contentType: "application/json; charset=utf-8", dataType: "json",
success: function (msg) {

I then iterate through each object in the JSON array and use the count value for the number of faults to set the

$.each(msg.d, function (index, item) {
size = 5 + Math.min( (item.Count / 2) * 5, 50);
var image = new google.maps.MarkerImage("disconnect2.png", null, null, null, new google.maps.Size(size, size));

and then generate the marker with a custom image, the calculated size, and the exchange code:

var marker = new google.maps.Marker({
position: new google.maps.LatLng(parseFloat(item.Lat), parseFloat(item.Long)),
map: map,
icon: image,
title: item.CircuitID
});

And then we get this!

map

Using Chosen with ASP.net: pre filling and saving multiple selections

The problem
– You want to use Chosen to snazz up your dropdowns.
– You need to store the selected values.
– You need to prefill the selected values when the page is reloaded.
Setting up chosen: Add chosen to the project. The simplest way is to use NuGet Package Manager:

– Right click solution explorer > Manager NuGet Packages > Search for “chosen” > “Install”

Once it has installed you will need to reference it in your .aspx file:

<link href="../Content/chosen.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="../Scripts/chosen.jquery.js">script>

Add the chosen class to your select:
(The data-placeholder is the test shown before you make a selection)

<select class="chosen" data-placeholder="Select Recipients..." multiple="true" id="recipients" name = "recipientselect">select>

Initialise chosen:

<script type="text/javascript">
        $(document).ready(function () {
            //initialise the recipients field with Chosen
            $(".chosen").chosen();    
script>

Reading the selected fields:

In codebehind on postback we access the select using its name, and then split the results and loop through them:

 string recipients = Request.Form["recipientselect"];
        if (recipients != null) {
            string[] recList = recipients.Split(',');
            foreach (string rec in recList) {
                // save the selected recipients
            }
        }



Re-loading the selections into chosen:

Probably not the best way, but it works; I’ve set up a basic service returning the selected recipients and then added that selection to the dropdown:

function FillSelectedRecipients() {
            var docID = $("#<%= hidDocID.ClientID %>").val()

            if (docID.length > 0) {
                $.ajax({
                    type: "POST", url: "EchoService.asmx/GetRecipients",
                    data: '{"DocID": "' + $("#<%= hidDocID.ClientID %>").val() + '"}',
                    contentType: "application/json; charset=utf-8", dataType: "json",
                    success: function (msg) {
                        $("#recipients").val(msg.d).trigger("liszt:updated");
                    },
                    error: function () { 
                    }
                });
            }
        }

The recipients can be loaded in directly as json, but the chosen dropdown needs to be updated using

.trigger("liszt:updated")

in order to display correctly.