Jim's Depository

this code is not yet written
 

I have a need to survive ISP outages, but am not large enough to have real things like BGP and serious internet connections, so I am using a telco and a cable company with a few static IPs on each.

There are various tutorials on the internet for how to cope with this, but they seem to primarily involve using iptables MARK to stain packets and then use the iproute2 functions to route them. I dislike conjoining these two tools. I am using source routing to keep everything straight, though there is a gotcha involving SNAT that needs attention when a link goes down.

Requirements:

  • Support more than one ISP.
  • Use the right source IP on each link to not trip packet spoof detection.
  • Survive a link going down and back up.
  • Lots of IPv4 private address machines on the inside need to be NATed on the way out.
  • IPv6 is mandatory. Using 6rd while my ISPs recover from being blindsided by that 20 year old RFC for IPv6.
  • Some servers live outside the firewall/router, I won’t speak any more of them, but they are there.

Non-requirement:

  • Load balancing. This can be addressed with your outgoing rules, but given the disparity in quality, there is little point in using the U-verse link for outbound connections if the Charter one is up. The inbound connections will still use it.
  • A single point of failure router is fine with me.

Strategy Overview:

  • Use a VLAN switch so I don’t need a flock of switches and multiple ethernet ports on the router and “outside the firewall” boxes. 
    Not required, but when you see decimal points in my ethernet device names, those are the VLAN ids.
  • Use source routing so that all packets go out the interface that matches their source IP address.
  • Use iptables SNAT to let the local machines out. Choose their SNAT address based on the outgoing interface. Let the routing rules do the routing.
  • Use conntrack to forget cached SNAT mappings when a link goes down or comes up. This is important!

VLAN Switch, 802.11q Is Your Friend

Go read about 802.11q if you are not familiar. With this you need only one switch. You can have as many virtual LANs as you like and configure on a port by port basis which LANs appear on that port. If you have gear that doesn’t do 802.11q you can set a single VLAN to show up there and work fine without any changes to that device. You will pay more for a “smart switch” with 802.11q support, but you are going to save on the number of switches, cabling, and ethernet cards. (e.g. in January 2013 I paid $220 for a 24 port gigabit 802.11q switch.)

You will have to configure your switch. My NetGear switch is configured through a web interface apparently writing by a maniacal sociopath, but it can be made to do the job.

The Source Routing

We are going to need two auxiliary routing tables to hold rules for when we know we have a U-verse address or a Charter address. These are going to get names which means we add lines to /etc/iproute2/rt_tables, (which is just a file mapping numbers to names)…

echo "200 att" >> /etc/iproute2/rt_tables
echo "201 charter" >> /etc/iproute2/rt_tables

When an interface comes up, we are going to add an ip routing rule to force packets with a Charter source address to look in that charter routing table and go out the right interface, likewise for AT&T… (Notice the “throw” rules. Some people duplicate their main table here, but I’d never keep that in sync, so I defer to the main table instead.)

# This is what makes source routing happen
ip rule add from 99.178.257.57/29 table att

# get a fresh start on the routing table
ip route flush table att
ip route add default via 99.178.257.62 dev eth2.4 table att

# get the RFC1812 private networks out, they don't want to go out this interface
# the "throw" will make them go back to your regular routing tables.
ip route add throw 10.0.0.0/8 table att
ip route add throw 172.16.0.0/12 table att
ip route add throw 192.168.0.0/16 table att

The SNAT For Our Private Addresses

Nothing new here, yet…

iptables -t nat -A POSTROUTING -o eth2.4 -s 172.16.0.0/12 -j SNAT --to-source 99.178.257.57
iptables -t nat -A POSTROUTING -o eth2.4 -s 192.168.0.0/16 -j SNAT --to-source 99.178.257.57
iptables -t nat -A POSTROUTING -o eth2.4 -s 10.0.0.0/8 -j SNAT --to-source 99.178.257.57

But wait! Now we have a problem. iptables connection tracking is going to learn these SNAT rules, and for instance, if you have a ping running, it will happily keep trying the dead interface after you take one down. The fix I’m using is to clear the SNAT connection tracking information with an interface goes up or down. I use this in my /etc/network/interfaces stanzas (install conntrack first)…

# We need to make NAT'd addresses choose a new path
# e.g. ICMP echo will be stuck on a dead interface if it was using this one
up conntrack -D --src-nat
down conntrack -D --src-nat

Choosing the Best Interface for Outgoing Traffic

You will want to use a metric on your default routes in order to choose the best one. (Alternatively you can get into load balancing, but my asymmetry is too high to care about that.)

I do this by not using the gateway declaration in my iface stanzas, but just do a up command instead…

#gateway 99.178.257.62 --- but we want an explicit metric, so we do it this way
up ip route add default via 99.178.257.62 dev eth2.4 metric 1 || true

… that is my shunned AT&T connection. I use a metric of zero on the Charter line so traffic prefers it, but will use AT&T if Charter goes down.

Now IPv6

IPv6 gets the same treatment, except you don’t have to screw with SNAT and conntrack, unless you really want to. Also, you will need some “-6” keystrokes. It helps to remember that those routing tables for att and charter are really four tables, two for IPv4 and two for IPv6.

I’ll just show you my Charter 6rd stanza, you can work it out from there.

iface charter6rd inet6 v4tunnel

# Force 6rd gateway to be on the Charter interface
pre-up ip route add 68.114.165.1 via 96.35.289.49 || true

# 2nd 32bits of this is my IPv4 address 
      address 2602:0100:6023:gd32::1
      netmask 32
      remote 68.114.165.1
      endpoint 68.114.165.1
      local 96.35.289.50
      tty 64
      up ip -6 rule add from 2602:100:6023:gd32::/59 table charter || true
      down ip -6 rule del from 2602:100:6023:gd32::/59 table charter || true
      up ip -6 route add default dev charter6rd table charter
      post-down ip route del 68.114.165.1 via 96.35.289.49
      up   ip -6 route add 2000::/3 dev charter6rd metric 5
      down ip -6 route flush dev charter6rd

What Is Wrong With This Strategy

When one of the ISPs is broken, I need to bring down their interface, otherwise traffic will happily still try to use it. There may be automated ways to do this, but I’m a simple barbarian and given the rarity of the events, I just use a little cron job that if it can’t see some portion of the internet out a particular interface, brings that interface down for a little while. I suppose playing with the default route metrics would be nicer, but like I said, simple barbarian. (I do have a nagging suspicion that if I were smarter about the load balancing it would “just work”. But I’m not.)

These are the three recipes I copied out from my mother’s box which were copied from her mother’s box. But first, let me add some things that may be obvious to cooks, but I learned from making a bunch of these pies.

  • Butterscotch doesn’t get appreciably thicker after it leaves the double boiler. Keep at it.
  • An extra egg white or two is a good idea for the meringue so you are sure you have enough.
  • I use whole milk, because I think that may have been what “milk” meant when this was first written down.
  • It is possible to whip the meringues while stirring the double boiler, but it gets a bit tricky with a hand mixer.
  • Get a head start on the double boiling before starting the meringue whipping. The butterscotch will keep warm if it gets done first.
  • As near as I can tell, the pie crust recipe is a cruel hoax. The Pillsbury pie crust box mix from the store works much better and you won’t spend 5 minutes scraping failed pie crust from your hands.
  • When you precook the pie crusts, make sure they overlap the edge of the pan. You are going to need that flange to overlap the meringue to get a good seal or the meringue will pull away as it cooks leaving you with a meringue island on your pie. I even run the meringue a little bit past the crust so it catches.
  • As you near the end of baking, flip on the broiler and then watch it like a hawk. Do not avert your gaze from the meringue. Pull the pie out when the meringue just begins to brown.

Butterscotch Pie

1 cup brown sugar
1 cup milk
3 tbsp flour
3 tbsp butter
2 egg yolks (well beaten)
1 tsp vanillaMix flour and sugar. Add yolks, butter, and milk.
Cook in a double boiler until thick.
Add vanilla.
Put in a baked pie shell.
Cover with meringue.
Bake at 225°F (about 15-20 minutes)

Pie Meringue

Beat egg white until stiff. Allow 2 tbsp of sugar for each egg.
Add sugar slowly, beating constantly.
Flavor, allowing 1/4 tsp of vanilla for 2 egg whites.

Two Crust Pie, 9 inch

2 cups flour
1 tsp salt
3/4 cup of shortening
1/2 cup ice waterAdd ice water little by little while tossing mixture.
When it sticks together that is enough water.
Bake at 500°F for 12 minutes.

Searching for nitrile gloves on Amazon. Won't buy these.

Amazon offer to sell me used exam gloves.

Attachments

amazon.png 63535 bytes

I know better than to look at graphs in my local paper. They use them like illuminated initials or other works of the rubricator. Everyone knows it isn't a 21st century newspaper article until you've rubricated.
But today I received this treat…
Clearly the reds beat the blues in the senate, their column is longer. Except the numbers say the left side has 51, so maybe the blues won. And why is there a blue hiding in the red column with the pales and the zinc chromate green party? And there are only 50 dots on the blue side, not 51.
I think I see where they were heading. The 50 and the gray line provide a clue. The gray line marks the center line, so they are trying to show a tipping point for party line voting. I have no idea why they chose a different horizontal dimension to distort the data on the Senate and Governor tables.
As far as I know there is no mechanism for governors to party line vote amongst themselves, so that middle line is meaningless.
A little dragging about in Preview fixes the quantitative visualization for them… … the voting governors issue is irreparable. I should have reordered to put the winning party fill beginning in the upper left for House and Governor, but that's more clicking and dragging than I feel like this morning.

Attachments

election-fixed.png 36712 bytes
election.png 48624 bytes

One of the special priveleges of coding alone…

At the end of a two hour debugging session where somehow a nearly valid pointer was showing up in an IO call back routine in a multithreaded C program I found this comment…

// ### NEEDS WORK

… and I really don’t get to blame anyone else.

I was right though. It did need work.

AT&T woke me up at 4:42am this morning to tell me that they were going to give lists of all my phone calls, who I talk to, and which web sites I visit and when to a broad list of marketing companies so that those companies could try to sell me things.

This afternoon I went to AT&T and asked for them to disable their locks from my iPhone so I could use it while out of the country. They refused since I still had a few days left in my contract with them. I was clear that I wasn’t leaving the contract, this would cost AT&T nothing. They refused.

So let’s try to opt out of CPNI:

• Link in email, wants the account id and zip code. Does not work. Account is now locked and won’t unlock. It suggests I click on a “chat” button of which there is none on the page. (This may be because I had to change the account billing zip code to my daughter’s residence to enable her femtocell.)

• The CPNI opt out page suggests I get my account number from the email. The email does not contain my account number because they replaced most of it with “x”s.

• Find my account number on an old bill…

We’re Having Trouble Processing Your CPNI Request You can still make your request by phone. Please call a representative at 1-800-288-2020.

• Call the 800 number, navigate the voice robot to be told “This office is now closed, please call during normal business hours.” No hint what those might be.

• Try to 800 number automated system. This one worked! It took three tries to get the account number in, it doesn’t like pauses while you look for the next few digits, but it did work. Maybe. There is no apparent way to see if you are actually opted in or out.

They could have just included a working link, with a unique identifier, in the opt out notification email and saved me 20 minutes. But they also could have not woken me up early on Sunday morning with their email too. They just aren’t that kind of company.

I’m not sure where this cropped up, I leaped many kernel versions, but when one of my LXC based virtual machines suddenly was unable to start machines after a kernel upgrade, the error presented like this:

root@cloud8:\~\# lxc-start -n rattus
lxc-start: Invalid argument - failed to create
'/sys/fs/cgroup//lxc/rattus' directory
lxc-start: failed to spawn 'rattus' lxc-start: No such file or directory
- failed to remove cgroup '/sys/fs/cgroup//lxc/rattus'

Further probing revealed that I could mkdir a subdirectory (like lxc in the above example) in my cgroup filesystem, but not a second level subdirectory (like rattus) within the first one.

After a bit of adding printk() calls to the kernel and rebooting, it turned out that the Network Priority cgroup (CONFIG_NETPRIO_CGROUP) was the problem. Turning that off fixed my woes.

Further poking about suggests this check in netprio_cgroup.c is probably to blame, but I don’t understand what prioidx is, so I leave it here.

if (cgrp->parent && cgrp_netprio_state(cgrp->parent)->prioidx) {
    kfree(cs); 
    return ERR_PTR(-EINVAL); 
}
Hey I am so excited I found your wegbape, I really found you by error, while I was searching on Askjeeve for something else, Anyhow I am here now and would just like to say thank you for a marvelous post and a all round thrilling blog (I also love the theme/design), I done28099t have time to go through it all at the moment but I have bookmarked it and also added in your RSS feeds, so when I have time I will be back to read a great deal more, Please do keep up the awesome work.

I fervently hope that Google brings you this search result in a timely manner.

CATransform3D is a row major matrix. When they say “m23”, they mean row 2, column 3.

GLKMatrix4 is a column major matrix. When they say “m23”, they mean row 3, column 2.

This means they are NOT laid out the same in memory, their initializers are acceptable to one another but incompatible, and if you called GLKMatrix4Make(…) with row major thoughts in your head, you will be very sad after you later call GLKMatrix4Multiply.

The people who write documentation, and perhaps mathematicians, don’t like to sully their hands with details like row major and column major, after all rows and columns are simply logical fictions. (You can’t actually tell what CATransform3D thinks is a row or column until you do a multiply, but GLKit has some functions with Row and Column in the name.)

Programmers, who might like their OpenGL view to display something do care.

You can get it wrong and not notice, except for a nagging feeling that all your matrix multiplications ( CATransform3dConcat or GLKMatrix4Multiply) are backwards. The other operations are happy to work transposed.

The OpenGL Profiler in Xcode 4.3 is known to be ruined for 10.7.3. Apple suggests you get the one from Xcode 4.2.1.

Here are the steps they may not have mentioned:

  1. Download the 1.8GB of xcode_4.2.1_for_lion.dmg from the developer downloads.
  2. Try to install, but fail because you have a shiny new 4.3 installed.
  3. Repetitive use of “file”, “man”, and three unarchiving programs will let you dig your way down through the layers of archiving, it ends up being something like…
  4. mkdir ~/Desktop/xcode
    cd ~/Desktop/xcode
    xar -x -v -f "/Volumes/Install Xcode/InstallXcodeLion.pkg" # archive layer 1
    cd InstallXcodeLion.pkg/
    cpio -i -t < Payload # archive layer 2
    cd "Applications/Install Xcode.app/Contents/Resources/Packages"
    xar -x -f OpenGLApps.pkg # archive layer 3
    gunzip < Payload > Payload.big # silent compression
    cpio -i < Payload.big # archive layer 4
    cd "Applications/Graphics Tools"
    ls "OpenGL Profiler" # Hurray!
    
  5. Just before the last step, you should remember that you have Time Machine and just go back a couple weeks and snag the one from /Developer. That’s what I did, but I thought I’d finish the instructions in case you didn’t have one.

It still crashes my program in some profiler function when I attach, so nothing gained, and doesn’t ever start profiling if I launch, but maybe it will help you.

Let’s say you have a Debian Squeeze based gateway machine and your ISP wasn’t reading ahead far enough in the RFCs to get to the IPv6 chapter.

Don’t let that hold you back, you can go to IPV6 without your ISP.

What we are going to do is use a little thing called 6to4 to make your only little bubble of the IPv6 internet and stitch it to the rest of IPv6 land with your existing IPv4 connection.

  1. Find out the 6to4 tunneled IPV6 address for your IPv4 address: I use 6to4 address calculator
  2. You are going to get a /48 subnet, that is, you will have the equivalent of 65536 entire IPv4 internets to allocate inside your machine. I generally use the one with all zeroes and a single one at the end as the address of my 6to4 gateway, so my IPv6 address ends up looking like: 2002:dead:beef::1. Notice that ‘::‘? That is IPv6 for “all the 16 bit blocks between here are zero”.
  3. Edit your /etc/network/interfaces file to add this interface:
    ~~~~~~~~ iface tun6to4 inet6 v4tunnel address 2002:YOUR-IPV6-ADDRESS-GOES-HERE!!!!!! netmask 16 remote 192.88.99.1 # anycast gateway endpoint any local YOUR-IPv4-ADDRESS-GOES-HERE!!!!! tty 255 up ip -6 route add 2000::/3 via ::192.88.99.1 dev tun6to4 down ip -6 route flush dev tun6to4 ~~~~~~~~
  4. Turn on your interface: ifup tun6to4
  5. Ping google’s machine: ping6 ipv6.google.com
  6. Go back and add the auto tun6to4 to your /etc/network/interfaces

Well that was easy. If you are a single machine you could be done.

But let’s say you are a gateway and you want to provide access to all of the machines behind you…

  1. Pick a subnet number. I’m going to use 1101 in this example, because it is the one I’m using. Any 4 digit hex number will suffice.
  2. Edit your /etc/network/interfaces again to add the subnet to your internal ethernet device:
    ~~~~~~~~ iface eth1 inet6 static address YOUR-FIRST-THREE-PARTS:1101::1 # 1101 is 17.1, it cohabits my 172.17.1.* net mask 64 ~~~~~~~~
  3. Bounce your internal interface to bring it up. (You could also skip the ifdown and use the force flag on ifup if you didn’t want to risk chopping your legs off if something goes wrong.)   ~~~~~~~~ ifdown eth0 ; ifup eth0 ~~~~~~~~
  4. Note: I have a problem here. It doesn’t add the route for that network, so I have to ip route add YOUR-FIRST-THREE-PARTS:1101::/64 dev eth0 I have no idea why. If you see  Dead loop on virtual device tun6to4, fix it urgently! in your syslog, you forgot this step.

That was also easy. Now you need to advertise the IPv6 network so clients can use it.

  1. aptitude install radvd  (route advertiser. It won’t start without a config)
  2. Turn on IPv6 forwarding, edit /etc/sysctl.conf and uncomment the line that says
    net.ipv6.conf.all.forwarding=1 Then echo 1 > /proc/sys/net/ipv6/conf/all/forwarding to make it happen without a reboot.
  3. Create your /etc/radvd.conf file, something like this should work…
    ~~~~~~~~ interface eth1 <<<<<< make that your network device { AdvSendAdvert on;

    prefix YOUR-FIRST-THREE-PARTS:1101::/64 { AdvOnLink on; AdvAutonomous on; AdvRouterAddr on; }; }; ~~~~~~~~

  4. Restart radvd: /etc/init.d/radvd restart

Now THINK! You just blew open your firewall and are allowing access to all of your internal machines over IPv6! Time to look at ip6tables. Yes, you have to do all those rules again. You might do something basic like this to prevent anyone from coming in, except to your defined ports, and allow yourself to go out as you wish…

#
# IPv6 rules 
/sbin/ip6tables -F # flush all 
/sbin/ip6tables -X # delete all 
/sbin/ip6tables -t mangle -F 
/sbin/ip6tables -t mangle -X

# open loopback wide 
/sbin/ip6tables -A INPUT -i lo -j ACCEPT
/sbin/ip6tables -A OUTPUT -o lo -j ACCEPT

# drop everything inbound by default 
/sbin/ip6tables -P INPUT DROP
/sbin/ip6tables -P FORWARD DROP 
/sbin/ip6tables -P OUTPUT ACCEPT

# forwarding basis: outgoing is fine, incoming is not 
/sbin/ip6tables -A FORWARD -i tun6to4 -m state --state ESTABLISHED,RELATED -j ACCEPT # allow established 
/sbin/ip6tables -A FORWARD -o tun6to4 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT # allow outgoing 
/sbin/ip6tables -A FORWARD -i eth0 -o eth0 -j ACCEPT # we can talk amongst ourselves 
# I don't like the preceding rule, it combinatorially explodes with more
than 1 interface

# by default, allow my own outgoing but no incoming 
/sbin/ip6tables -A INPUT -i tun6to4 -m state --state ESTABLISHED,RELATED -j ACCEPT # no new incoming

# allow ICMP 
/sbin/ip6tables -A INPUT -p ipv6-icmp -j ACCEPT

# open my ports 
/sbin/ip6tables -A INPUT -i tun6to4 -p tcp --destination-port 80 -j ACCEPT /sbin/ip6tables -A INPUT -i tun6to4 -p tcp --destination-port 22 -j ACCEPT

# see the failures 
/sbin/ip6tables -A FORWARD -m limit --limit 15/minute -j LOG --log-level info /sbin/ip6tables -A INPUT -m limit --limit 15/minute -j LOG --log-level info

Most of your machines with IPv6 enabled will just work at this point. You may wish to give some of them static addresses so you can get to them from outside (after added a firewall rule of course). The IETF took mercy on us poor old IPv4 folk and made a syntax for using IPv4 dotted quads in IPv6 addresses so you don’t have to invent all new numbers. Like this…

iface eth0 inet static

address 172.17.1.214

...
iface eth0 inet6 static 
   address 2002:63b2:9d39:1101::172.17.1.214 <<<< see me using my IPv4 for sanity netmask 64

… that will make the IPv6 address 2002:63b2:9d39:1101::ac11:1d6

That about does it. Someday you will get real IPv6 addresses from your ISP and need to renumber everything to add those addresses in parallel with your 6to4 addresses.

more articles