Friday, 13 March 2015

Super Simple Linked List In C

When writing code in a high level scripting language like Perl, Ruby or Python it is easy to take for granted what a nice feature it is to have automatic types like arrays or hashs. Variable that you can just dump data in to and pull it back out any way you like. These features were not always there, someone had to write the code to make it to this.

A linked list in C is a way to store values, as many as you like for as much memory as you have. Memory for a variable is created on the fly as needed and stored in a location that knows information about it's neighbour.  A good linked list will have features to let you search, insert, delete from any point, move backwards and forwards in the list and most importantly a good list would protect your code from accidental memory bugs. My example today has non of those features.

This is the bare minimum of a simple linked list. It is a single linked list so you can only move forward. A double linked list lets you move backwards also.
#include<stdio.h>
#include<stdlib.h>

struct DataNode {
 void *Load;
 struct DataNode *Next;
};

struct DataNode *TheFirst = NULL;
struct DataNode *Current = NULL;
struct DataNode *Last = NULL;

void* NewList(void *Load) {
 struct DataNode *Pointer = (struct DataNode*)malloc(sizeof(struct DataNode));
 if(NULL == Pointer) {
  return NULL;
 }
 Pointer->Load = Load;
 Pointer->Next = NULL;

 TheFirst = Last = Current = Pointer;
 return(Pointer);
}

void* Add(void *Load) {
 if(TheFirst == NULL) {
  return (NewList(Load));
 }

 struct DataNode *Pointer = (struct DataNode*)malloc(sizeof(struct DataNode));
 Pointer->Load = Load;
 Pointer->Next = NULL;

 Last->Next = Pointer;
 Current = Last = Pointer;
 return(Pointer);
}

void* First() {
 Current = TheFirst;
 if(Current == NULL) return(NULL);
 return(Current->Load);
}

void* GetNext() {
 struct DataNode *Pointer = Current;

 // Advance to next
 if(Pointer->Next) {
  Current = Pointer->Next;
  return(Current->Load); 
 }
 return(NULL);
}

int DeleteFirst() {
 int Return = 0;
 if(TheFirst) {
  if(TheFirst->Next) {
   Current = TheFirst->Next;
   Return = 1;
  } else {
   Current = NULL;
  }
 }
 free(TheFirst);
 TheFirst = Current;
 return(Return);
}

int main(void) {
 char* ToDoList;
 Add("Pet the dog");
 Add("Feed the fish");
 Add("Let the cat out");
 Add("Do the dishes");
 Add("Gas up the car");
 Add("Watch some TV");
 ToDoList = First();
 while(ToDoList != NULL) {
  printf("%s\n", ToDoList);
  ToDoList = GetNext();
 }
 while(DeleteFirst()) {}
 return 0;
}

Tuesday, 3 March 2015

Instant hash in Perl, just do the splits

Today I needed a Perl script that could create a lot of hash cells fast and the names of the cells will not be know until run time. I did not want to use a for loop, I looked for a better way to do this in less code. When I found the solution I was reminded of some Perl documentation that I read saying that most people think the @ symbol means an array but it does not, it means many. The way this works it when you reference the hash with the @ symbol you can put many values in to many cells in one line of code.

The first split turns the Fields string in to the cell name identifiers, the second split turns the Values string in to the data, putting many data in to many cells named in a hash.



#!/usr/bin/perl

my $Fields = "name:address:phone";
my $Values = "Bob:123 Hill Rd:505-050-4321";
my %Hash;
@Hash{split(/:/, $Fields)} = split(/:/, $Values);

for my $key (keys %Hash) {
 print "$key = '$Hash{$key}'\n";
}

Thursday, 26 February 2015

Live firewall hacking

I am a bit of a jerk when it comes to security. If I find out that you emailed your private SSH key, I will remove your public key from everywhere. A lot of people think I am paranoid, I call those people "low hanging fruit".

When it comes to the Linux firewall I never want to restart or restore on a public facing server. There is a long list of bad things that can happen when your firewall is down for just a second.

The correct thing to do is edit just the lines in your firewall rule that you need to change. We can do this in iptables using options like --line-numbers to give us the exact line to alter and --replace or --delete to modify that line.


iptables -v --replace INPUT $(iptables -nvL INPUT --line-numbers | grep ^[1-9] | grep "4.3.2.6" | awk '{print $1}') -s 6.2.3.4 -d 4.3.2.6 -j ACCEPT
ACCEPT  all opt -- in * out *  6.2.3.4  -> 4.3.2.6  
iptables -nvL INPUT
Chain INPUT (policy ACCEPT 238 packets, 69612 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       all  --  *      *       1.2.3.4              4.3.2.1             
    0     0 ACCEPT     all  --  *      *       6.2.3.4              4.3.2.6             
    0     0 DROP       all  --  *      *       6.9.3.4              4.3.9.6             
iptables -v --replace INPUT $(iptables -nvL INPUT --line-numbers | grep ^[1-9] | grep "4.3.2.6" | awk '{print $1}') -s 6.2.3.4 -d 4.3.2.6 -j DROP
DROP  all opt -- in * out *  6.2.3.4  -> 4.3.2.6  
iptables -nvL INPUT
Chain INPUT (policy ACCEPT 18 packets, 2545 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       all  --  *      *       1.2.3.4              4.3.2.1             
    0     0 DROP       all  --  *      *       6.2.3.4              4.3.2.6             
    0     0 DROP       all  --  *      *       6.9.3.4              4.3.9.6             
iptables -v --delete INPUT $(iptables -nvL INPUT --line-numbers | grep ^[1-9] | grep "4.3.2.6" | awk '{print $1}')
iptables -nvL INPUT
Chain INPUT (policy ACCEPT 12 packets, 1631 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       all  --  *      *       1.2.3.4              4.3.2.1             
    0     0 DROP       all  --  *      *       6.9.3.4              4.3.9.6  

Tuesday, 24 February 2015

Running a tight BASH script

A few things I like to do with important bash scripts so that they live on as useful tools for many years is:
1) Send error output to the standard system logger.
2) Clean up any child processes that were started
3) Clean up any temporary files


You don't always need all of these but they are good to have handy.

Notice how trap is used to call a function so that the exit of the script can do a few extra things.

#!/bin/bash

# Log any errors to the standard system logs
exec 2> >(logger -s -t $(basename $0))

# Clean up when the program exits
function CleanExit {
 # stop any long running commands
 for k in $(jobs -p); do { kill -p $k; }

 # remove any temporary files created
 # rm -f $TEMPFILE
 exit
}
trap "CleanExit" EXIT

# Your code goes here

Friday, 13 February 2015

Get values and catch exit code in one line of BASH

Often it is helpful if a variable is only used when a command is successful.


FILE_SIZE=$(stat --format="%s" /bin/bash) && { 
 echo "Size is $FILE_SIZE"; 
} || { 
 echo "File size is unknown."; 
}


This becomes tricky if you used a pipe to parse the result because the pipe will fork a new shell completely isolated from the original command. Using PIPESTATUS it is possible to check the exit code of the previous command to the left and then it is easy to test the result.

HOST_IP=$(host $SOME_HOST_NAME | awk '{print $NF}'; [ ${PIPESTATUS[0]} -eq 0 ] ) && {
 echo "Host IP is $HOST_IP"
} || {
 echo "no such host"
}

Thursday, 12 February 2015

Unit convertion wih awk

I needed a simple unit converter to change number to kilo, mega and giga to I went looking and found some large complex code and decided I could make it so must smaller.

This will convert your number to a human readable value.

Try this with it.
for i in $(seq 1 1 64); do echo -n "$(echo "2^$i"|bc) =  "; echo "2^$i"|bc|awk -f convert.awk; done


{
 S=$1;
 Us=" kMGTPEZY";
 U="";
 i=2;
 while(S>1024){
  S/=1024;
  U=substr(Us,i,1);
  i++;  
 };
 printf "%0.0f%sb\n", S, U
}

Wednesday, 11 February 2015

Perl named capture containers, the coolest parsing trick ever.

Named capture containers only works in Perl 5.10 and up. In this example I am able to match lines in a log file by a key word. The tags like <time> become the key name in the hash %+.

Values can be extracted like you would with a normal hash.



while (<>) {
 $Line = $_;
 $Line =~ s/\n//;
 $Line =~ m/^(?<time>\d{10}.\d{3})\s*(?<status>connection)\s*(?<fd>\d*)\s*(?<ipaddress>\d*.\d*.\d*.\d).*/ ||
 $Line =~ m/^(?<time>\d{10}.\d{3})\s*(?<status>disconnect)\s*(?<fd>\d*).*/ ||
 $Line =~ m/^(?<time>\d{10}.\d{3})\s*(?<status>monitor)\s*(?<fd>\d*).*/;
 if(keys(%+) > 0) {
  foreach my $KeyName (keys %+) {
   $x{$KeyName} = $+{$KeyName};
  }
 }
}