--- /dev/null
+#! /bin/bash
+
+### Script to set up an iodine tunnel route traffic through it
+###
+### Copyright 2008 Barak A. Pearlmutter <bap@debian.org>
+###
+### License: MIT
+###
+### Permission to use, copy, modify, and distribute this software for
+### any purpose with or without fee is hereby granted, provided that
+### the above copyright notice and this permission notice appear in
+### all copies.
+###
+### THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+### WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+### WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+### AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+### CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+### LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+### NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+### CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+## Cause script to bail immediately on failed command
+set -e
+
+## Options for user to set.
+
+## Minimal customization: put the two lines
+## subdomain=your.tunnel.sub.domain
+## passed=password_for_that_tunnel
+## in the file /etc/default/iodine-client.
+
+echo "${iodine_client_rc:=/etc/default/iodine-client}" > /dev/null
+
+if [ -r ${iodine_client_rc} ]; then
+ . ${iodine_client_rc}
+else
+ echo WARNING: Cannot read ${iodine_client_rc}
+fi
+
+if [ -z ${subdomain} ]; then
+ read -p "DNS tunnel DNS subdomain: " subdomain
+fi
+
+if [ -z ${subdomain} ]; then
+ echo ERROR: Must set subdomain.
+ exit 1
+fi
+
+if [ -z ${passwd} ]; then
+ read -p "Password for DNS tunnel over ${subdomain}: " passwd
+fi
+
+## This is a host name used for testing DNS and for pinging
+echo "${testhost:=slashdot.org}" > /dev/null
+
+## Set if local network should be taken down and then up
+echo "${bounce_localnet:=true}" > /dev/null
+
+## Set for testing network availability via ping at various points
+echo "${test_ping_localnet:=true}" > /dev/null
+echo "${test_ping_tunnel:=true}" > /dev/null
+echo "${test_ping_final:=true}" > /dev/null
+
+## Set if the script cannot find and then incorrectly guesses the
+## local network router
+echo "${default_router}" > /dev/null
+
+## Set if script uses the wrong hardware interface
+echo "{interface}" > /dev/null
+
+## Set if the script should continue even if a command fails.
+## Used to test script when running as non-root.
+if [ $(whoami) = root ]; then
+ echo "${continue_on_error:=false}" > /dev/null
+else
+ echo "${continue_on_error:=true}" > /dev/null
+fi
+
+## DEBIAN PACKAGES TO INSTALL: these are needed to run this script
+## iodine (for /usr/sbin/iodine)
+## iproute (for /bin/ip)
+## ipcalc (for /usr/bin/ipcalc)
+## dnsutils (for /usr/bin/dig)
+## fping (for /usr/bin/fping)
+
+## The default tunnel MTU is 1024.
+## If local DNS server restricts to 512 byte packets then do this:
+# ifconfig ${d} mtu 220
+
+## TO DO
+## - avoid double ping when DNS server and local router are the same
+## - option to not kill existing iodine DNS tunnels, in case there
+## are meant to be more than one
+## - sanify check whether default_router is on local network
+
+echo ==== Creating IP-over-DNS tunnel over local network connection...
+
+
+## Find a network interface
+
+if [ -z ${interface} ]; then
+ interface=$(tail --lines=+3 /proc/net/wireless \
+ | head -1 | tr -d : | awk '{print $1}')
+fi
+
+if [ -z ${interface} ]; then
+ interface=$(ifconfig -a | egrep '^[^ ].*encap:Ethernet' \
+ | head -1 | awk '{print $1}')
+fi
+
+if [ -z ${interface} ]; then
+ echo ERROR: No network interface found.
+ exit 1
+fi
+
+echo ==== Local network interface: ${interface}
+
+## Down any existing DNS tunnel (wish there were "approved" way to do this)
+
+echo ==== Killing existing DNS tunnels...
+if killall --quiet --wait --verbose --signal HUP iodine; then
+ sleep 2
+fi
+
+## Stabilize local network
+
+if ${bounce_localnet}; then
+ echo ==== Bouncing local network connection...
+ ifdown --force ${interface} || true
+ ifup ${interface} || ${continue_on_error}
+fi
+
+## Fetch some information about the local network
+
+addr=$(ip -4 addr show dev ${interface} scope global \
+ | tail -1 | awk '{print $2}')
+prefix_len=$(echo ${addr} | sed 'sX^.*/XX')
+local_net=$(ipcalc --nobinary ${addr} | awk '$1=="Network:" {print $2}')
+
+echo ==== Local address: ${addr}
+echo ==== Local network: ${local_net}
+
+router=$(ip -4 route list dev ${interface} \
+ | awk '$1=="default" {print $3}' | head -1)
+if [ -z ${router} ]; then
+ ## This can happen when the default local route is already deleted
+ if [ -z ${default_router} ]; then
+ echo WARNING: no default route, guessing local router IP address.
+ ## Minimum address on local net is usually right
+ router=$(ipcalc --nobinary ${addr} | awk '$1=="HostMin:" {print $2}')
+ else
+ echo WARNING: no default route, using configured default router.
+ ## But sometimes need to hardwire...
+ router=${default_router}
+ fi
+fi
+
+echo ==== Local network router: ${router}
+
+## Test DNS service
+
+testhost_ip=$(dig +short -t A -q ${testhost})
+if [ -z ${testhost_ip} ]; then
+ echo WARNING: Failure on DNS lookup of ${testhost}.
+fi
+
+## fetch DNS servers
+
+nameservers=$(awk '$1=="nameserver" {print $2}' /etc/resolv.conf)
+if [ -n "${nameservers}" ]; then
+ echo ==== DNS servers: ${nameservers}
+else
+ echo ERROR: No DNS servers found.
+ exit 1
+fi
+
+## Test if local network is up
+
+if ${test_ping_localnet}; then
+ echo ==== Ping test of local network router and DNS servers...
+ fping -C1 ${router} ${nameservers} \
+ || echo WARNING: Ping test failed.
+fi
+
+## Add point-to-point routes for any non-local DNS servers
+
+for n in ${nameservers}; do
+ n_net=$(ipcalc --nobinary ${n}/${prefix_len} | awk '$1=="Network:" {print $2}')
+ if [ "${n_net}" != "${local_net}" ]; then
+ echo ==== Adding point-to-point route for DNS server ${n}
+ ip -4 route add ${n}/32 via ${router} || ${continue_on_error}
+ fi
+done
+
+## Bring up DNS tunnel
+
+echo ==== Creating IP-over-DNS tunnel...
+iodine -P ${passwd} ${subdomain} || ${continue_on_error}
+
+## Find DNS tunnel interface
+
+tunnel_interface=$(ifconfig -a | egrep '^dns' | awk '{print $1}' | head -1)
+if [ -z "${tunnel_interface}" ]; then
+ echo WARNING: Cannot find DNS tunnel interface, using default.
+ tunnel_interface=dns0
+fi
+echo ==== DNS tunnel interface: ${tunnel_interface}
+
+## Figure out router at other end of tunnel, assuming router uses final octet .1
+## (There should be some way to get this information out of iodine, since
+## it *prints* it as it sets up the tunnel, so it does know it.)
+
+tunnel_remote=$(ip -4 address show dev ${tunnel_interface} \
+ | awk '$1=="inet" {print gensub("[.][0-9]*/.*", ".1", 1, $2)}' | head -1)
+
+if [ -z ${tunnel_remote} ]; then
+ echo ERROR: Cannot find DNS tunnel remote endpoint.
+ ${continue_on_error}
+ ## set something random if debugging
+ echo WARNING: Confabulating DNS tunnel remote endpoint.
+ tunnel_remote=192.168.253.1
+fi
+
+echo ==== DNS tunnel remote endpoint: ${tunnel_remote}
+
+if ${test_ping_tunnel}; then
+ echo ==== Ping test of local router, nameserver, and DNS tunnel...
+ fping -C1 ${router} ${nameservers} ${tunnel_remote} \
+ || echo WARNING: Ping test failed.
+fi
+
+## Modify routing table to send trafic via DNS tunnel
+
+echo ==== Setting default route through DNS tunnel...
+
+## Remove default route via local router
+ip -4 route del default via ${router} || ${continue_on_error}
+## Add default via tunnel
+ip -4 route add default via ${tunnel_remote} || ${continue_on_error}
+
+## Test if all is well
+
+if ${test_ping_final}; then
+ echo ==== Ping test of local router, nameserver, DNS tunnel, external test host...
+ fping -C1 ${router} ${nameservers} ${tunnel_remote} ${testhost_ip:-${testhost}} \
+ || echo WARNING: Ping test failed.
+fi
--- /dev/null
+#! /usr/bin/perl
+# substitution_solver solves substitution problems, and is released
+# under the terms of the GPL version 2, or any later version, at your
+# option. See the file README and COPYING for more information.
+# Copyright 2006 by Don Armstrong <don@donarmstrong.com>.
+# $Id: perl_script 495 2006-08-10 08:02:01Z don $
+
+
+use warnings;
+use strict;
+
+use Getopt::Long;
+use Pod::Usage;
+
+=head1 NAME
+
+substitution_solver - Solve substitution puzzles using known substitution methods
+
+=head1 SYNOPSIS
+
+ substitution_solver [options]
+
+ Options:
+ --log, -l file to log to
+ --input, -i initial input
+ --substitutions, -s directory of substitutions
+ --debug, -d debugging level (Default 0)
+ --help, -h display this help
+ --man, -m display manual
+
+=head1 OPTIONS
+
+=over
+
+=item B<--log,-l>
+
+An optional file to log the puzzle solution process
+
+=item B<--input,-i>
+
+Initial input to start puzzle solving with
+
+=item B<--transforms,-t>
+
+Directory of transforms to use; defaults to ~/.substitution_solver/transforms
+
+=item B<--debug, -d>
+
+Debug verbosity. (Default 0)
+
+=item B<--help, -h>
+
+Display brief useage information.
+
+=item B<--man, -m>
+
+Display this manual.
+
+=back
+
+=head1 EXAMPLES
+
+
+=cut
+
+
+use vars qw($DEBUG);
+
+my %options = (debug => 0,
+ help => 0,
+ man => 0,
+ transforms => [$ENV{HOME}.'/lib/substitution_solver/transforms'],
+ );
+
+GetOptions(\%options,'debug|d+','help|h|?','man|m',
+ 'log|l=s','input|i=s',
+ 'transforms|t=s@',
+ );
+
+pod2usage() if $options{help};
+pod2usage({verbose=>2}) if $options{man};
+
+$DEBUG = $options{debug};
+
+use IO::File;
+use File::Temp qw(tempfile);
+use Term::ReadLine;
+use File::Spec qw(catfile rel2abs);
+use Params::Validate qw(validate_with :types);
+
+my $logfh;
+
+if (defined $options{log}) {
+ $logfh = IO::File->new($options{log},'w') or die "Unable to open $logfh for writing: $!";
+}
+else {
+ # we write to a tempfile for now
+ if ( -w '/dev/null') {
+ $logfh = IO::File->new('/dev/null','w') or die "Unable to open /dev/null for writing: $!";
+ }
+ else {
+ $logfh = tempfile();
+ }
+}
+
+my %transforms;
+
+my @input_stack = ('');
+my $input_pos = 0;
+
+if (defined $options{input}) {
+ read_input($options{input});
+}
+
+# read transformations
+
+my $surpress_status = 0;
+
+
+my $done = 0;
+
+load_transforms(@{$options{transforms}});
+
+
+my $readline = Term::ReadLine->new('substitutionsolver');
+
+while (not $done) {
+ my $line = $readline->readline('['.$input_pos.']: ');
+ local $_ = $line;
+ s/^\s+//;
+ chomp;
+ print {$logfh} $line;
+ if (/^quit\s*$/) {
+ $done = 1;
+ }
+ elsif (/^input\s+(.+)/) {
+ read_input($1);
+ }
+ elsif (/^stat(?:s|istics)?\s*$/) {
+ output_statistics($1);
+ $surpress_status = 1;
+ }
+ elsif (/^list\s*$/) {
+ list_transformations();
+ $surpress_status = 1;
+ }
+ elsif (/^applicable/) {
+ list_transformations(applicable=>1);
+ $surpress_status = 1;
+ }
+ elsif (/^print\s+stack\s*$/) {
+ print join("\n",map {"$_: $input_stack[$_]\n"} 0..$#input_stack);
+ }
+ elsif (/^p(?:rint)?\s*$/) {
+ print "Current input:\n";
+ print $input_stack[$input_pos];
+ print "\n";
+ }
+ elsif (/^perl\s*(.+)/) {
+ do_perl_eval($1);
+ }
+ elsif (/^output\s+(.+)/) {
+ write_output($1);
+ }
+ elsif (/^undo\s*$/) {
+ $input_pos-- if $input_pos > 0;
+ }
+ elsif (/^redo\s*$/) {
+ $input_pos++ if ($input_pos+1) < $#input_stack;
+ }
+ elsif (/^\#/) {
+ # ignore comments
+ }
+ else {
+ print "Unknown command '$_'\n";
+ }
+}
+
+
+sub read_input {
+ my ($file) = @_;
+ my $fh = IO::File->new($file,'r');
+ if (not $fh) {
+ print "Unable to open $file for reading: $!\n";
+ return;
+ }
+ local $/;
+ my $content = <$fh>;
+ @input_stack = ($content);
+ $input_pos = 0;
+}
+
+sub output_statistics {
+ my $current_input = $input_stack[$input_pos];
+ my %counts;
+ $counts{uc($_)}++ foreach grep /\S/, split //, $current_input;
+ for my $key (sort {$counts{$b} <=> $counts{$a}} keys %counts) {
+ print "$key: $counts{$key}\n";
+ }
+}
+
+sub do_perl_eval{
+ my ($perl) = @_;
+ local $_ = $input_stack[$input_pos];
+ my $return = eval $perl;
+ if ($@) {
+ print "Failure while evaluating perl code\n";
+ print $@;
+ print "\n";
+ }
+ else {
+ increment_stack($return);
+ }
+}
+
+sub write_output{
+ my ($file) = @_;
+ my $fh = IO::File->new($file,'w');
+ if (not $fh) {
+ print "Unable to open $file for writing: $!\n";
+ return;
+ }
+ print {$fh} $input_stack[$input_pos];
+}
+
+sub increment_stack{
+ $input_stack[++$input_pos] = $_[0];
+}
+
+sub load_transformations{
+ my @transforms = @_;
+ my @transform_files;
+ for my $transform (@transforms) {
+ if (-f $transform) {
+ push @transform_files,rel2abs($transform);
+ }
+ elsif (-d $transform) {
+ my $dir = IO::Dir->new($transform);
+ if (not $dir) {
+ print "Unable to open $transform for reading: $!";
+ next;
+ }
+ my $file;
+ while ($file = $dir->readdir) {
+ next unless /^[a-z0-9][a-z0-9-]*$/;
+ next unless -f rel2abs(catfile($transform,$file));
+ push @transform_files,rel2abs(catfile($transform,$file));
+ }
+ }
+ }
+ for my $transform_file (@transform_files) {
+ my $fh = IO::File->new($transform_file);
+ if (not $fh) {
+ print "Unable to open $transform_file for reading: $!";
+ }
+ my ($type,$name,$content) = (undef,undef,'');
+ while (<$fh>) {
+ if (/^name\:/ and not defined $name) {
+ chomp;
+ s/^name\:\s*//;
+ $name = $_;
+ next;
+ }
+ elsif (/^type:/ and not defined $type) {
+ chomp;
+ s/^type\:\s*//;
+ $type = $_;
+ next;
+ }
+ elsif (/^\#/) {
+ next;
+ }
+ else {
+ $content .= $_;
+ }
+ }
+ if (not defined $type or not defined $name) {
+ print "Badly formed transform file $transform_file; no type or name\n";
+ next;
+ }
+ if ($type eq 'tr') {
+ my @content = grep /./, split /\n/, $content;
+ $transforms{$name} = {type => 'tr',
+ name => $name,
+ content => $content,
+ from => $content[0],
+ to => $content[1],
+ };
+ }
+ elsif ($type eq 'map') {
+ my @content = grep /./, split /\n/, $content;
+ my %map;
+ my %map_reverse;
+ for my $line (@content) {
+ my ($from,$to) = split /\t+/,$line;
+ $map{$from} = $to;
+ $map_reverse{$to} = $from;
+ }
+ $transforms{$name} = {type => 'map',
+ name => $name,
+ content => $content,
+ map => \%map,
+ map_reverse => \%map,
+ };
+ }
+ elsif ($type eq 'perl') {
+ $transforms{$name} = {type => 'perl',
+ name => $name,
+ content => $content,
+ };
+ }
+ else {
+ print "Unknown type $type for transform $transform_file\n";
+ next;
+ }
+ }
+}
+
+sub list_transformations{
+ my %param = validate_with(params => \@_,
+ spec => {applicable => {type => BOOLEAN,
+ default => 0,
+ },
+ },
+ );
+ for my $transform (keys %transforms) {
+ if ($param{applicable}) {
+ # figure out if we can apply a transform
+ my $output = attempt_transform($transform);
+ if (not defined $output) {
+ next;
+ }
+ }
+ print "$transform\n";
+ }
+}
+
+
+sub attempt_transform{
+ my ($name) = @_;
+ my $transform = $transforms{$name};
+ $transform->{}
+}
+
+
+__END__