Tuesday, September 17, 2013

Android Update Brings IPv6

I was disappointed with AT&T not providing the Android 4.1.2 update when other US-based carriers made it available, especially since we got the 4.1.1 update pretty early. Even more disappointing was when this was finally available - around the beginning of August - my device never upgraded. A Google search the other night showed it was available and when I manually checked for updates - sure enough, it was.

I will say I'm pleased with the update. Multiwindow is pretty cool even if not standard. It doesn't support all apps - and even some common ones I use that would be nice to use in multiwindow mode - like Google Keep.

The best part is that IPv6 now seems to work! At least over WIFI. I have IPv6 running at home and was (again) disappointed when my wife's iPad and iPhone could get to IPv6 sites and my Android couldn't. But after the update, I tried What Is My IPv6 Address from my Android and got an IPv6 address back (you'll see your IPv4 address if IPv6 isn't working)! I confirmed with my favorite IPv6-only site Loops of Zen.

Monday, September 16, 2013

Reach the Beach Relay - 2013

This year was a bit different. We only had 6 people, but only 2 of those 6 (Ashley and I) were willing to do the ultra. So we opted for a "half-team" option where RTB matched us with 6 people in a similar situation. As always, it was an adventure. We started counting and recording "pieces of flair" (i.e., "road kills") - number of people passed while running.

Massakruliks - Half Team

197/474 - 5/8

Vert
Distance Difficulty Gain Loss Net Flair Time Pace
Leg 8 6.61 Moderate 101 125 -24 +9 43:30 6:35
Leg 20 6.83 Hard 725 826 -101 +23 45:20 6:38
Leg 32 6.69 Moderate 324 413 -89 +15 45:55 6:52
20.13 +47 2:14:45 6:42

Monday, June 03, 2013

IPv6 to IPv4 Server Load Balancing Testing in GNS3

My last post talked about testing IPv4 / IPv6 web and proxy services using Qemu in GNS3. My next challenge was to understand the "easy" way to IPv6-enable an IPv4-only web site - configure your load balancer to do it.

The simple explanation for Server Load Balancing IPv6 to IPv4 (SLB64) is that it performs traditional server load balancing functions but additionally does address family translation from the requested IPv6 address to the real IPv4 address of the internal servers in the server farm.

I don't have a big name load balancer at my disposal nor does my laptop have the power needed to download a virtual image and spin up VMware connected to my GNS3 simulation. So I went looking for a linux software based alternative and found HAProxy. The site indicates IPv6 support came along in version 1.1 and of course there is a Tiny Core linux package available. That meant following the Qemu "installation" procedure I described in a previous post and doing the proper 'filetool' backup.

My lab looks like the following, including an Apache web server running on Qemu in GNS3 as described in the last post:

IPV6 = 2001:db8

 192.168.100.254    192.168.100.1      10.100.100.17
IPV6:192:168::254  IPV6:192:168::1
     HOST      ------    R1    ------   Web Server
                    10.200.200.1          (Qemu)
                   IPv6:AC8:C800::1
                          |
                          |
                    10.200.200.17
                  IPV6:AC8:C800::254
                       HAProxy
                       (Qemu)

The HAProxy package didn't come with a configuration or startup script, so I had to create them. First, the configuration file was pretty simple to create in /usr/local/etc/haproxy.conf:

global
  user tc
  group staff
  daemon
defaults
  mode tcp
  retries 3
  timeout connect 5000
  timeout client 50000
  timeout server 50000
listen ipv6proxy80 :::80
  server ipv4server80 10.100.100.17:80

A little translation: the 'global' and 'default' headings just set some standard parameters for HAProxy operation. The 'listen' heading is where I tell HAProxy to listen for all incoming IPv6 traffic to TCP port 80 (TCP comes from the 'mode tcp' command in the 'defaults' section). HAProxy should then distribute matched traffic to the listed servers - in this case only 10.100.100.17 on port 80. Listening on IPv6 and distributing to an IPv4 server causes HAProxy to do the address family translation from IPv6 to IPv4. Note that you can make this configuration much more secure and/or selective, but this is perfect for my little test.

Next, the startup script in /etc/init.d/services/loadbal:

#!/bin/sh
case "${1}" in
  start)
    /usr/local/sbin/haproxy -f /usr/local/etc/haproxy.conf -p /var/run/haproxy.pid -D
    ;;
  stop)
    pkill haproxy
    ;;
  status)
    pidof haproxy
    ;;
  *)
    exit 1
    ;;
esac

HAProxy is now started with "sudo /etc/init.d/services/loadbal start".

To test we need to remember that HAProxy is our load balancer and thus is advertising the "outside" (read: Internet) address of the web server. So on the HOST, I open a browser and point it to:

http://[2001:db8:AC8:C800::254]:80

SUCCESS! I get the home page from the Apache web server complete with the link to the CGI script to print my environment variables as described in my last post. That certainly comes in handy to see where the web server thinks the connection is coming from as does a 'netstat -an' on the HAProxy Qemu linux console.

Thursday, May 30, 2013

IPv4 / IPv6 Web and Proxy Server Testing in GNS3

In a previous post, I described how I got some additional packages installed on Tiny Core linux to use with Qemu in my GNS3 simulations. While that post describes how I got a DHCPv6 client loaded on my Tiny Core image, at the time I also loaded Apache. This gave me an IPv4 / IPv6 web server to test with. Additionally, Apache can be run as a proxy server, so I could test IPv4 / IPv6 proxy services with the single Apache install.

The first step was to create a configuration file for both web server and proxy. The default is installed in /usr/local/apache2/conf/httpd.conf and is suitable for the web server configuration. I copied that file to /usr/local/apache2/conf/proxy.conf and edited it. I kept only the "LoadModule" commands and then added:

ServerRoot "/usr/local/apache2"
listen 8080
User tc
Group staff
ProxyRequests On

You can get fancier, but that's all you really need for testing in a closed GNS3 lab environment.

Next, a nice home page on the web server that automatically displays some information would be nice. Printing environment variables like client IP address and server IP address will come in handy when testing through a proxy server to see what address (IPv4 or IPv6, client or proxy server) the "world" will see. Thankfully, the default install has this file. Unfortunately, it didn't work for me.

I had a permission issue and since the CGI script was really a link to the file, I couldn't change the permissions. Easy solution was to simply copy the file to the CGI bin directory and make the appropriate edits.

So first I need an index.html in /usr/local/apache2/htdocs. That looks like this:

<html>
<head>
<title>Title</title>
</head>
<body>
<h1>It works!</h1>
<a href = "cgi-bin/test-cgi-new">Environment</a>
</body>

Next, the actual /usr/local/apache2/cgi-bin/test-cgi-new script is create with:

cd /usr/local/apache2/cgi-bin
cp ./test-cgi ./test-cgi-new
chown tc test-cgi-new
chgrp staff test-cgi-new
chmod 755 test-cgi-new

Finally, a startup script for both web server and proxy server in /etc/init.d/services:

--httpd--

#!/bin/sh
case "${1}" in
  start)
    /usr/local/apache2/bin/httpd
    ;;
  stop)
    pkill httpd
    ;;
  status)
    pidof httpd
    ;;
  *)
    exit 1
    ;;
esac

--proxy--

#!/bin/sh
case "${1}" in
  start)
    /usr/local/apache2/bin/httpd -f /usr/local/apache2/conf/proxy.conf
    ;;
  stop)
    pkill httpd
    ;;
  status)
    pidof httpd
    ;;
  *)
    exit 1
    ;;
esac

Now I can start them with "sudo /etc/init.d/services/httpd start" and "sudo /etc/init.d/services/proxy start".

Of course, make sure you do this on Qemu outside of GNS3 and save your configurations by editing the appropriate "/opt/.filetool.lst" file and running "filetool" to backup as described in the previous post.

Then, I created a simple GNS3 lab with a router in the middle. I made one connection bridged to my host machine (loopback interface) and added some routes on the host to point towards the simulation networks. I made another router connection to one instance of Qemu where I run the proxy service. The final router connection goes to another instance of Qemu where I run the web server. Now I can test from my host browser on IPv4 and IPv6 to the test web server and I can also configure the simulation proxy server on my host to test out IPv4 / IPv6 proxy services to the web server in the simulation.

Next, I'll describe how I setup and tested Server Load Balancing 6 to 4 (SLB64) with HAProxy.

Tuesday, April 02, 2013

Open Source and Closed Protocols

There isn't a better way to learn a protocol for me than reading the RFC and watching Wireshark captures and decodes. However, it becomes difficult when we're talking about a closed proprietary protocol.

Recently, I've been creating new protocol modules for the Net::Frame Perl module suite. Hot Standby Router Protocol (HSRP) is a Cisco proprietary protocol but is detailed in RFC 2281. However, that's only version 1. Version 2 isn't in an open RFC. Another example is Cisco Discovery Protocol (CDP) which has no RFC for version 1 or version 2. Luckily, there is plenty of information on the Internet.

I couldn't get all the information for all the CDP message types, but I'm about 90% there. A more interesting note was in the CDP header itself. There is a checksum that's described as the "normal Internet checksum". However, when I implemented that in a Net::Frame::Layer::CDP module, it didn't work. What was the problem?

A Google search lead me to the source code for Wireshark and a file called packet-cdp.c. A comment beginning on line 230 explains:

"CDP doesn't adhere to RFC 1071 section 2. (B). It incorrectly assumes checksums are calculated on a big endian platform, therefore i.s.o. padding odd sized data with a zero byte _at the end_ it sets the last big endian _word_ to contain the last network _octet_. This byteswap has to be done on the last octet of network data before feeding it to the Internet checksum routine. CDP checksumming code has a bug in the addition of this last _word_ as a signed number into the long word intermediate checksum. When reducing this long to word size checksum an off-by-one error can be made. This off-by-one error is compensated for in the last _word_ of the network data."

That meant I needed some "massaging" of my payload before sending to my Internet checksum routine. A quick proof of concept proved correct and then some solicitation for simplification produced this:

   [...]

   if (length( $payload )%2) {
      if (substr($payload, -1) ge "\x80") {
         substr $payload, -1, 1, chr(ord(substr $payload, -1) - 1);
         substr $payload, -1, 0, "\xff";
      } else {
         substr $payload, -1, 0, "\0";
      }
   }

   [...]

   $self->checksum(inetChecksum($phpkt));

I also found a very long thread in a mailing list archive that describes how some smart guys found this problem and came up with the Wireshark solution. Thanks for open source - even on closed protocols!

Tuesday, March 05, 2013

Thinking Outside the "Package" for Packets

I responded to a query on a community forum for Perl about creating a DNS update with a spoofed source address. I was ASSURED it was for a contest and the code was what was essential. The contest site recommended scapy, but the poster was looking for a Perl solution. I had the easy answer: Perl Packet Crafter.

The poster went on to detail some code that created the DNS update but when he sent the packet, he couldn't change the source IP address. Obviously. He used Net::DNS as follows:

use strict;
use warnings;
use Net::DNS;

my $update = Net::DNS::Update->new('evil.zz');
$update->push(prerequisite => nxrrset('hacker11.evil.zz. A'));
$update->push(update => rr_add('hacker11.evil.zz. 86400 A 127.0.0.1'));

my $res = Net::DNS::Resolver->new;
$res->nameservers('192.168.200.113');

my $reply = $res->send($update);

The last line sends the update by taking the created DNS data and letting standard socket routines create the Layer 3 header. Perl Packet Crafter (PPC) can create the custom Layer 3 header and with Net::Frame::Layer::DNS (which I wrote), one can easily create the required packet. However, with most of the work done, is it necessary to recode the original script using Net::Frame::Layer::DNS? Turns out ... no.

Because of the layered nature of the Net::Frame suite of modules on which PPC is based, one can easily create any or all layers of a frame with the objects or simply by hand crafting an octet stream. Or ... even using another Perl module that can output the required stream.

For Net::DNS, there is an undocumented sub called make_query_packet() in the Net::DNS::Resolver::Base code that creates a Net::DNS::Packet object on which the data() method can be called to create the necessary octet stream. It may sound complicated, but all it means is replace the last line of code above with:

$dnsdata = $res->make_query_packet($update);

Now, in PPC, you can use the $dnsdata->data call to create the DNS payload in a UDP packet. It looks like the following:

VinsWorldcom@C:\tmp\> ppc.pl -i "Wireless Network Connection"
Welcome to Perl Packet Crafter (PPC)
Copyright (C) Michael Vincent 2012

Wireless Network Connection

ppc> use Net::DNS;
ppc> $update = Net::DNS::Update->new('evil.zz');
ppc> $update->push(prerequisite => nxrrset('hacker11.evil.zz. A'));
ppc> $update->push(update => rr_add('hacker11.evil.zz. 86400 A 127.0.0.1'));
ppc> $res = Net::DNS::Resolver->new;
ppc> $res->nameservers('192.168.200.113');
ppc> $dnsdata = $res->make_query_packet($update);

We've used PPC to enter the original code with the modified last line - instead of send, use the make_query_packet() routine to create the Net::DNS::Packet object. Continuing, we create the packet in PPC:

ppc> $ether = ETHER;
ppc> $ipv4 = IPv4(src=>'1.1.1.1',dst=>'192.168.200.113',protocol=>NF_I+Pv4_PROTOCOL_UDP);
ppc> $udp = UDP(dst=>53,payload=>$dnsdata->data);
ppc> $packet = packet $ether,$ipv4,$udp;

And to be sure before we send it, we can use Net::Frame::Layer::DNS for a nice decode:

ppc> use Net::Frame::Layer::DNS qw(:consts);
ppc> decode $packet;
ETH: dst:55:66:88:78:aa:30  src:c0:c1:c2:08:46:56  type:0x0800
IPv4: version:4  hlen:5  tos:0x00  length:90  id:23417
IPv4: flags:0x00  offset:0  ttl:128  protocol:0x11  checksum:0x53fe
IPv4: src:1.1.1.1  dst:192.168.200.113
UDP: src:50281  dst:53  length:70  checksum:0x5661
DNS: id:5329  qr:0  opcode:5  flags:0x00  rcode:0
DNS: qdCount:1  anCount:1
DNS: nsCount:1  arCount:0
DNS::Question: name:evil.zz
DNS::Question: type:6  class:1
DNS::RR: name:hacker11.[@12(evil.zz)]
DNS::RR: type:1  class:254  ttl:0  rdlength:0
DNS::RR: name:[@25(hacker11.[@12(evil.zz)])]
DNS::RR: type:1  class:1  ttl:86400  rdlength:4
DNS::RR::A: address:127.0.0.1

Job done!

Note this can also be done with other Perl modules like Net::DHCP::Packet with the new() and serialize() calls, for example.

Friday, March 01, 2013

Blog about NOT Logging

A question came across a mailing list I subscribe to about limiting the syslog messages sent from a Cisco router to a syslog server. The question arose since a certain Cisco blade switch has a known bug where it reports the redundant power supply is faulty even though it doesn't have one. The message - sent every 5 minutes - was becoming quite bother to the operations folks since there were 80 such devices all reporting the erroneous error.

The asker had already found the 'logging discriminator ...' command, but couldn't apply it. A quick test in Dynamips and I had the answer for him.

The 'discriminator' option as we applied it looked for a regular expression in the syslog message body and was configured to "drop" the message (not send it to the syslog server). It worked with the following configuration:

logging discriminator NOREPORT msg-body drops "Redundant power supply faulty or in standby mode"
logging host 1.1.1.1 discriminator NOREPORT

Satisfied we had a working fix, it was time for some more investigation.

I've selectively enabled SNMP traps with the 'snmp-server enable traps XXX' commands, but I didn't know it was possible with syslog messages - I never really tried to be honest. In fact, all logging is enabled with a simple command:

logging 192.168.100.254

There are options for which facility or severity to send, but not many options for creative tuning - they're all of certain class or nothing. The 'discriminator' option seemed pretty useful. However ...

The 'discriminator NAME' doesn't work like an access-list where you can add multiple lines. You get one (1) discriminator and you get one (1) time to apply it to the syslog host. So how long can the regular expression be? Not very - as soon as I started to get fancy with the regular expression to block multiple messages, I got errors:

R1(config)#$msg-body drops "((Configured from)|(Interface         ))"
R1(config)#$msg-body drops "((Configured from)|(Interface          ))"
% unmatched ()

With the grouping parenthesis and the logical or vertical bar (pipe), I could only get a maximum of 38 characters. When I tried 39, I started getting the "unmatched" error and looking at the 'show run', my configuration line was truncated at 38 characters:

R1(config)#do sh run | i logg
logging discriminator NOREPORT msg-body drops ((Configured from)|(Interface          )

Notice the last parenthesis is left off (should be two of them). This severely limits the creativity when trying to selectively block syslog messages. There are other alternatives, like 'mnemonic' which will block an entire category of syslog messages by regular expression. So less characters to fit within the 38, but entire classes of messages dropped.

Maybe there's a better way?

 

Copyright © VinsWorld. All Rights Reserved.