December 11, 2002

Moving IP ranges


Warning: DOMDocument::loadHTML() [function.DOMDocument-loadHTML]: Unexpected end tag : p in Entity, line: 97 in /srv/www/darkness.codefu.org/root/wordpress/wp-content/plugins/postxform/postxform.php on line 43

Warning: DOMDocument::loadHTML() [function.DOMDocument-loadHTML]: Unexpected end tag : p in Entity, line: 113 in /srv/www/darkness.codefu.org/root/wordpress/wp-content/plugins/postxform/postxform.php on line 43

Urgent need to change from one ISP to the other. Don’t really want to speak of the reasons for this here. Anyway, since last night I’ve been working on this every waking hour that I could spare. Even put off commitments to a big customer to get this done with. Bad news: it’s still not done. I need to make this entry quick, but I don’t want to miss too much of what I’ve been doing.

My iptables rules are a leap forward for me compared to what I’ve been doing. I think I might try and dumb down my iptables rules script that I’m going to try using after I’ve (A) ironed out any bugs, and (B) removed sensitive information, dumbed it down into an example, etc. Things I’m doing that I’ve (stupidly) never done before: for services, branch to a chain that lists all the hosts providing that service when you match the service’s port; reorganizing rules based on which has the most packets (iptables -nvL); when mucking with iptables rules remotely, make a “safe host” entry at the top of the the INPUT and FORWARD chains that contains an unqualified ACCEPT for that IP address.

I also recompiled my kernel/iptables/wanpipe with the CONNMARK patch. Here’s the reason: I’ve got two Internet connections with different IP ranges on them. I’ve got one internal network with reserved addresses. To make an example, say an incoming SMTP connection comes in on Internet connection B. Packet gets NAT’ed, sent through to SMTP server. Now SMTP server makes a response to the client. When this datagram hits the server, you have no way of determining whether the packet should be sent out Internet connection A or Internet connection B (where it belongs), except giving the SMTP server two IPs and filtering on that perhaps. CONNMARK adds a field to the structures already maintained by the conntrack code which is basically like fwmark. You can match on this “connection mark” (connmark), copy fwmark to the connmark, or copy the connmark to the fwmark. In my case, when the SYN for the SMTP connection came in I’d set the connmark on that connection. Then when any packet that has a connmark is about to be routed (in the mangle table, PREROUTING chain) I copy the connmark to the fwmark for any packets that have connmark set. Once you’ve got fwmark set, you can route with ip rule based on the fwmark. Nice.

Note on building this setup, though. I wanted an athlon kernel. AFAIK, the only way to get source is to just rpmbuild -ba the spec file with no explicit target. So I have to build twice: once with rpmbuild -ba --target athlon kernel-2.4.spec, and once with rpmbuild -ba kernel-2.4.spec. (I could do this all in one step with --target i386,athlon I think — but I also noticed that apparently rpmbuild -ba is building for i586, though the arch tag on the resulting binary RPM is i386? Am I going insane here? This is RH 8.0, too; isn’t that only supposed to support i686? If it had built an i686 kernel and called it i386, maybe I’d buy it, but… i586?)

Also, the CONNMARK patch wasn’t as simple as the MARK_operations patch I had applied earlier: it had a bunch of files, some of which weren’t exactly in patch(1) format AFAIK. So I pointed KERNEL_DIR at a copy of /usr/src/linux, had it patch that copy, then diff -urN /usr/src/linux /my/usr/src/linux/copy > linux-2.4.18-CONNMARK.patch. Fun. Put patch in spec file, rebuild kernel RPMs. This patch didn’t modify iptables, either, which I found weird since I needed it to build the CONNMARK target and connmark matcher. I later found out that (at least when building from the RH 8.0 iptables 1.2.6a patch), iptables will check /usr/src/linux for certain files corresponding to the presence of the CONNMARK patch in the kernel; it will build this target and matcher if it finds them. So: patch kernel source, install kernel source, then build iptables.

Then, I broke the Internet when I rebooted. I realized that wanpipe wouldn’t work when it was built for i386 and the kernel was built for athlon. This didn’t see quite right to me, but the modules would give me unresolved symbols. In the end, I ended up doing the same thing as I did for the CONNMARK patch above: I let the wanpipe stuff patch a copy of the kernel, diff‘ed the two, applied that patch, rebuilt kernel RPM. Voila, now the modules that ship with the kernel are just fine. I should split the modules out of my wanpipe RPM.

That was yesterday. Today I came up with a checklist of things that I have to do to hosts to bring them over to the new reserved IPs I’m switching to on the Internal network. I also added new iptables rules in preparation for the switch.

I ran into problems with DNS, though. I’ve got two weird DNS situations:

  1. Hosts in our domain need to resolve to internal IPs when queried from the inside, and external IPs when queried from the outside.

  2. At home I need some of the hosts from my primary domain name to resolve to internal IPs, and some to resolve the same as they would everywhere else. The rest of the hosts should resolve to one address regardless of where I’m querying them from.

I’ll start with (1); (2)’s not too related to work, really. I was going to use views to do (1), but then I remembered that you had to define every zone for each view; i.e., you can’t have some zones in a view and some outside (like “all zones in your specific view are checked first, then any zones not in a specific view are checked”). I also only have one DNS server (really two, but primary and secondary) so typical split horizon DNS as described in Bv9ARM isn’t real do-able. (I don’t want to run multiple copies of bind.) I didn’t want to maintain each zone directive in each view.

So rather than hit an obvious solution (coming later) I went off on tangents. I looked at a patch I had made to allow records like * NS ns1.foo.com which actually works, but is applicable to (2) and not really (1). Then I started reading on DNS and eventually hit some random guy’s “Frequently Given Answers” which had some information on DJBDNS. I started looking in to it and decided I should perhaps try DJBDNS. I actually started to like the idea of synchronizing between master and slave(s) with ssh/rsync. I came to accept the idea that I would run tinydns on one IP and dnscache on another IP. OK. Then I realized it didn’t support RFC 2136 dynamic updates like Bind 9. Then I read some more and really thought hard about DJBDNS’ sort of lack of standards support. The only other thing I can really think of that it doesn’t support is DNSSIG (or was it DNSSEC? You know what I mean), which isn’t really done nor too useful – especially if you listen to DJB and his advocates. (BTW, I recommend reading a DJB vs. Bind thread or something similar on any number of mailing lists like IETF’s namedroppers list for example. His page on DJBDNS also has a bit about how he’s being oppressed by the moderator for namedroppers, I believe it was.) I could probably live without DNSSIG, at least for now, but dynamic updates? I really like those. I also read about the extreme overhead some people had for doing a make (rebuilding the CDB files, AFAIK) with large numbers of records. They had much, much, much greater demands than I, but I still thought about it. Now that I think about it, I doubt Bind could keep up with some of their needs too.

Anyway, I ended up dropping DJBDNS. I considered running three views in Bind 9: one for internal zones, one for external zones, and one for “common” zones that needed to be queried from either of the first two views with the same resolutions (RR’s, IP’s returned, whatever) for both. I was going to have the server listen on port 54 in addition to the usual ports. Then I would setup the internal and external views to match based on the source, and set them up as forward only views. They would answer queries for the few (two, I much later realized) internal zones they had information for, but forward to localhost port 54 for any other queries. localhost:54 would be caught by the common view. Voila, a union of sorts. One problem I thought of, though, was CNAMEs: request comes in for www.customer.com, internal zone gets query, doesn’t have authoritative information for it in this view and so forwards to localhost:54, common view gets it, finds www.customer.com. CNAME web1.ourdomain.com., goes to look up web1.ourdomain.com. (Note: at this point I’m not sure I’m correct. The name server might not try to look this up, but instead return the CNAME with no other information back to the internal view. In this case, the rest of this example is moot.) Now it tries to look up ourdomain.com, which is a zone that has different addresses depending on whether it’s queried internally or externally. However, if localhost:54 tries to send a query to localhost:53, and the internal/external zones match on source address of the query, which view do they answer from for the address of www.customer.com? Kaplooey, brokenness.

Then I somehow started thinking about DNS tools, and I kind of hit me: hey, isn’t there an include statement. Sure enough, and it says it basically just acts like the contents of the named file were inserted into the configuration at that point. Bingo: create internal-zones.conf, external-zones.conf, and common-zones.conf. Two views that discriminate based on query source, they both have all the zones that we’re authoritative for, and I don’t have to manage two separate lists of zone statements in two separate view statements. I haven’t tested this yet, but I suspect it will work. The only odd thing about this might be my one dynamic zone; I’m not sure if it’s going to reflect the changes to the zone in both views if I simply point the zone statements at the same files. I’m kind of worried about the journal I believe it makes. I’ll get back to you later if this actually all works out.

I don’t actually feel like writing much about (2) right now. My wildcard NS patch (which I’ll make available upon request; mail me if you want it) fixes things up. My home server is configured with this patch, and the real primary/secondary for the domains are listed with * NS on my home server. In this manner, my home server tries to match the record from more specific records in the zone it has, but if it can’t find any will just return the referral to my real primary/secondary servers.

In other news, I’m still without high-speed Internet access at home. ardent, euphorik and I have discussed using 802.11b to set up a secure link between our two apartments, and then euphorik and I will get DSL while ardent keeps his cable. In this way we’d hopefully never both be out of Internet access (unless we lost power or something) and can use the other person’s connection as a backup. Details to be finalized, and we’re not even sure if we can get the wireless link through the building — which is how it’s going to have to be, I think. I don’t think the apartment complex would much appreciate me extending an arm off my third story porch 10′-15′ to point an antenna at ardent’s porch.