diff --git a/src/hostinfo/dhcpd.py b/src/hostinfo/dhcpd.py
index 65d74b6ba769e8bb66a4b9e958e42d8241276d42..e1f69efd718669b31589269b8c82453d18e50568 100755
--- a/src/hostinfo/dhcpd.py
+++ b/src/hostinfo/dhcpd.py
@@ -1,7 +1,22 @@
 import sys
 import os
 from hostinfo.util import ntoa, aton
+import hostinfo.util as util
 
+CLASS_PXECLIENT = """
+  class "pxeclient" {
+    match if substring (option vendor-class-identifier, 0, 9) = "PXEClient";
+      next-server %(next_server)s;
+      if option arch = 00:06 {
+        filename "pxelinux/bootia32.efi";
+      } else if option arch = 00:07 {
+        filename "pxelinux/bootx64.efi";
+      } else {
+        filename "pxelinux.0";
+      }
+    }
+  }
+"""
 def MacOS_NETBOOT(dhcphost):
     if not os.path.exists('/local/macos'):
         return ''
@@ -86,59 +101,58 @@ def generate(tree, dhcphost, kickstart, next_server=None):
                 address.append(ip.address[0])
                 pass
             pass
+        result += 'shared-network "MAC(%s)" {\n\n' % i.ethernet[0]
         result += emit_network(tree, dhcphost, address, kickstart,
-                               i.ethernet[0], next_server=next_server)
+                               interface=i, next_server=next_server)
+        result += "}\n"
         for v in vlan:
             result += emit_network(tree, dhcphost, [ v ], kickstart,
-                                   None, next_server=next_server)
+                                   next_server=next_server)
             pass
         pass
     return result
                     
-def emit_network(tree, dhcphost, addr, kickstart, ethernet=None,
-                 next_server=None):
+def emit_network(tree, dhcphost, addr, kickstart, 
+                 interface=None, next_server=None):
     result = ""
-    network = {}
-    for n in tree._subnet_:
-        if not n.network[0]:
-            continue
-        netmask = aton(n.netmask[0])
-        subnet = aton(n.network[0]) & netmask
+    subnet = {}
+    for s in filter(util.network, tree._subnet_):
+        n = util.network(s)
         for a in addr:
-            if aton(a) & netmask == subnet:
-                network[ntoa(subnet)] = n
-    if len(network.keys()) > 1:
-        # Multiple networks served on this interface
-        result += 'shared-network "MAC(%s)" {\n\n' % ethernet
-        for n in network.values():
-            for l in emit_subnet(tree, n, dhcphost, kickstart,
-                                 next_server=next_server).split("\n"):
-                result += "  %s\n" % l
-        result += "}\n"
-    else:
-        result += emit_subnet(tree, network.values()[0], dhcphost, kickstart,
-                              next_server=next_server)
+            if util.address(a) in n:
+                subnet[n] = s
+                pass
+            pass
+        pass
+    
+    for n in sorted(subnet):
+        for l in emit_subnet(tree, subnet[n], dhcphost, kickstart,
+                             interface=interface, 
+                             next_server=next_server).split("\n"):
+            result += "  %s\n" % l
+            pass
+        pass
     return result
 
-def emit_subnet(tree, n, dhcphost, kickstart, next_server=None):
+def emit_subnet(tree, subnet, dhcphost, kickstart, 
+                interface=None, next_server=None):
     result = ""
-
+    net = util.network(subnet)
     if next_server == None:
         next_server = dhcphost
         pass
-    netmask = aton(n.netmask[0])
-    subnet = aton(n.network[0]) & netmask
     static = {}
-    dynamic = {}
+    dynamic = set()
     never = []
     for ip in tree._host_._interface_._ip_:
         # Find all hosts that belong to this network
-        if ip.address[0]:
-            net = aton(ip.address[0]) & netmask
-            if net == subnet:
+        a = util.address(ip)
+        if a:
+            a = util.address(ip)
+            if a in net:
                 if ip.dynamic[0] == dhcphost:
                     # Dynamic address served by this host
-                    dynamic[aton(ip.address[0])] = ip
+                    dynamic.add(a)
                     pass
                 else:
                     static[ip.name[0:]] = ip
@@ -146,53 +160,55 @@ def emit_subnet(tree, n, dhcphost, kickstart, next_server=None):
                 pass
             pass
         if ip.never[0]:
-            net = aton(ip.never[0]) & netmask
-            if net == subnet:
+            a = util.address(ip.never[0])
+            if a in net:
                 never.append(ip.ethernet[0:])
                 pass
             pass
         pass
-    
-    result += "subnet %s netmask %s {\n" % (n.network[0], n.netmask[0])
-    result += "  option subnet-mask %s;\n" % n.netmask[0]
-    if n.broadcast[0]:
-        result += "  option broadcast-address %s;\n" % n.broadcast[0]
-        pass
-    if n.gateway[0]:
-        result += "  option routers %s;\n" % n.gateway[0]
+    result += "subnet %s netmask %s {\n" % (net.network, net.netmask)
+    result += "  option subnet-mask %s;\n" % net.netmask
+    result += "  option broadcast-address %s;\n" % net.broadcast
+    if subnet.gateway[0]:
+        result += "  option routers %s;\n" % subnet.gateway[0]
         pass
-    if n.domain[0]:
-        result += "  option domain-name \"%s\";\n" % n.domain[0]
+    if subnet.domain[0]:
+        result += "  option domain-name \"%s\";\n" % subnet.domain[0]
         pass
-    if n.name_servers[0]:
-        result += "  option domain-name-servers %s;\n" % n.name_servers[0]
+    if subnet.name_servers[0]:
+        result += "  option domain-name-servers %s;\n" % subnet.name_servers[0]
         pass
-    if n.ntp_servers[0]:
-        result += "  option ntp-servers %s;\n" % (n.ntp_servers[0])
+    if subnet.ntp_servers[0]:
+        result += "  option ntp-servers %s;\n" % (subnet.ntp_servers[0])
         pass
     #
     # Emit dynamic hosts
     #
     result += "  default-lease-time 14400; # 4 hours\n"
     result += "  max-lease-time 86400; # 1 day\n"
-    dk = dynamic.keys()
-    dk.sort()
+    for s in interface_subnets_matching(interface, net):
+        if s.first[0] and s.last[0]:
+            result += "  range %s %s;\n" % (util.address(s.first[0]),
+                                            util.address(s.last[0]))
+            pass
+        pass
+    # FIXME: Old style dynamic...
     min = 0
     max = 0
-    for d in dk:
+    for d in sorted(dynamic):
         if d == max + 1:
             max = d
             pass
         else:
             if min:
-                result += "  range %s %s;\n" % (ntoa(min), ntoa(max))
+                result += "  range %s %s;\n" % (min, max)
                 pass
             min = d
             max = d
             pass
         pass
     if min:
-        result += "  range %s %s;\n" % (ntoa(min), ntoa(max))
+        result += "  range %s %s;\n" % (min, max)
         pass
     result += "  get-lease-hostnames true;\n"
     result += "  use-host-decl-names on;\n"
@@ -211,7 +227,7 @@ def emit_subnet(tree, n, dhcphost, kickstart, next_server=None):
         ip = i.address[0]
         if ether:
             assert ether.lower() == ether, "%s is not lower-case" % ether
-            result += "    host %s.%s {\n"% (i.name[0:], n.domain[0])
+            result += "    host %s.%s {\n"% (i.name[0:], subnet.domain[0])
             result += "      hardware ethernet %s;\n" % ether
             result += "      fixed-address %s;\n" % ip
             result += "      option host-name \"%s\";\n" % i.name[0:]
@@ -241,8 +257,52 @@ def emit_subnet(tree, n, dhcphost, kickstart, next_server=None):
         result += "      ignore booting;\n"
         result += "    }\n"
         pass
-    
+
+#    result += CLASS_PXECLIENT % { 'next_server': next_server }
+    for s in interface_subnets_matching(interface, net):
+        if s.kickstart[0] != 'any':
+            continue
+        else:
+            continue
+        for i in filter(lambda i: i.ethernet[0] and i._kickstart_, 
+                        tree._host_._interface_):
+            e = i.ethernet[0] 
+            assert e.lower() == e, "%s not lower-case" % e
+            result += "    host %s {\n"% (i.name[0:])
+            result += "      hardware ethernet %s;\n" % e
+            result += "      option host-name \"%s\";\n" % i.name[0:]
+            if not kickstart:
+                raise Exception("--kickstart needed for %s" % i.name[0:])
+            kf = i._kickstart_[0].file[0]
+            result += "      server-name \"%s\";\n" % dhcphost
+            result += "      next-server %s;\n" % next_server
+            result += "      if substring(option vendor-class-identifier, "
+            result += "0, 20) = \n"
+            result += "         \"PXEClient:Arch:00000\" {\n"
+            result += "        filename \"pxelinux.0\";\n"
+            result += "      } else {\n"
+            result += "        filename \"%s/%s\";\n" % (kickstart, kf)
+            result += "      }\n"
+            result += "    }\n"
+            pass
+        result += "    if substring(option vendor-class-identifier, "
+        result += "0, 20) = \n"
+        result += "       \"PXEClient:Arch:00000\" {\n"
+        result += "      filename \"pxelinux.0\";\n"
+        result += "    } else {\n"
+        result += "      filename \"%s/default\";\n" % (kickstart)
+        result += "    }\n"
+        break
+
     result += "  }\n"
     result += "}\n"
     
     return result
+
+def interface_subnets_matching(interface, net):
+    if not interface:
+        return
+    for s in filter(lambda s: util.network(s) == net, interface._subnet_):
+        yield s
+        pass
+    pass
diff --git a/src/hostinfo/dhcpd_ipv6.py b/src/hostinfo/dhcpd_ipv6.py
index b7bd2ca92ecf5471217f3a62909d637fa4467799..840f9229d3c3b18696ffaff801f25c744e853279 100755
--- a/src/hostinfo/dhcpd_ipv6.py
+++ b/src/hostinfo/dhcpd_ipv6.py
@@ -53,14 +53,14 @@ def emit_interface_ipv6(tree, interface, options):
     subnet = set()
     for ip in [ ip for ip in interface._ipv6_ if ip.address[0] ]:
         a = ipaddr.IPAddress(ip.address[0])
-        subnet.update([ (s.prefix[0], s) for s in tree._subnet_ipv6_ 
+        subnet.update([ (s.prefix[0], s) for s in tree._subnet_ 
                         if (s.prefix[0] and a in ipaddr.IPNetwork(s.prefix[0])) 
                         ])
         pass
     for k,s in sorted(subnet):
         result = StringArray()
         dynamic = [ map(ipaddr.IPAddress, (r.first[0], r.last[0])) 
-                    for r in interface._dhcpserver_._subnet_ipv6_ 
+                    for r in interface._dhcpserver_._subnet_ 
                     if r.first[0] and r.last[0] and r.prefix[0] == s.prefix[0] ]
         result.append('subnet6 %s {' % ipaddr.IPNetwork(s.prefix[0]) )
         result.extend(emit_subnet_ipv6(tree, s, dynamic, options).indent())
diff --git a/src/hostinfo/ifconfig.py b/src/hostinfo/ifconfig.py
index 47c9050f462ee647b0f8771dfac828afef3e6bc7..cd7f8ca9434dbc52208f2667fe66cf06ce264b35 100755
--- a/src/hostinfo/ifconfig.py
+++ b/src/hostinfo/ifconfig.py
@@ -1,4 +1,5 @@
 from hostinfo.util import aton
+import hostinfo.util as util
 import subprocess
 import re
 import ipaddr
@@ -113,11 +114,9 @@ def generate_ifcfgv6(tree, interface):
         pass
     else:
         address = []
-        for ipv6 in interface._ipv6_:
-            if not ipv6.address[0]:
-                continue
-            a = ipaddr.IPAddress(ipv6.address[0])
-            for s in [ ipaddr.IPNetwork(s.prefix[0]) for s in tree._subnet_ipv6_ ]:
+        for ipv6 in filter(util.address, interface._ipv6_):
+            a = util.address(ipv6)
+            for s in map(util.network, filter(util.network, tree._subnet_ )):
                 if a in s:
                     address.append('%s/%d' % (a, s.prefixlen))
                     pass
diff --git a/src/hostinfo/named.py b/src/hostinfo/named.py
index ae268ad9bf673ff5c90c22724b1afac56bab196d..54ed6d1fa37d051410f41ee3045fe07fa63b60b6 100755
--- a/src/hostinfo/named.py
+++ b/src/hostinfo/named.py
@@ -1,7 +1,33 @@
 import copy
 import hostinfo.parser
-from hostinfo.util import ntoa, aton, fqn, by_ip
+from hostinfo.util import fqn, by_ip, network, address
 import ipaddr
+import itertools
+
+def reverse_addr(addr):
+    if addr == None:
+        return None
+    if addr.version == 4:
+        def join(l):
+            return '.'.join(reversed(l))+'.in-addr.arpa'
+        if isinstance(addr, ipaddr._BaseNet):
+            assert addr.prefixlen % 8 == 0
+            n = addr.prefixlen / 8
+            return join(addr.exploded.split('.')[0:n])
+        else:
+            return join(addr.exploded.split('.'))
+        pass
+    elif addr.version == 6:
+        def join(l):
+            return '.'.join(reversed(l))+'.ip6.arpa'
+        if isinstance(addr, ipaddr._BaseNet):
+            assert addr.prefixlen % 4 == 0
+            n = addr.prefixlen / 4
+            return join(map(None, addr.exploded.replace(':', ''))[0:n])
+        else:
+            return join(map(None, addr.exploded.replace(':', '')))
+    else:
+	raise Exception('Unknown address version %s' % addr)
 
 def generate(tree, host):
     #
@@ -40,33 +66,41 @@ def generate(tree, host):
     conf += '  file "0.0.127.in-addr.arpa";\n'
     conf += '};\n'
     result.append(("named/%s" % rzone, reverse_local(tree, host)))
+
+    forward = {}
+    reverse = {}
     for s in tree._subnet_:
-        fzone = s.domain[0]
-        if not done.has_key(fzone):
-            if forward(tree, s):
-                conf += "zone \"%s\" { \n" % fzone
-                conf += "  type master; file \"hosts-%s\"; \n" % fzone
-                conf += "};\n"
-                result.append(("named/hosts-%s" % fzone, forward(tree, s)))
-                pass
-            done[fzone] = 1
+        if not s.domain[0] in forward:
+            forward[s.domain[0]] = generate_forward(tree, s)
             pass
-            
-        if s.network[0]:
-            t = s.network[0].split(".")[0:3]
-            t.reverse()
-            rzone = ".".join(t) + ".in-addr.arpa"
-            if not done.has_key(rzone):
-                if reverse(tree, s):
-                    conf += "zone \"%s\" { \n" % rzone
-                    conf += "  type master; file \"%s\"; \n" % rzone
-                    conf += "};\n"
-                    result.append(("named/%s" % rzone, reverse(tree, s)))
-                    pass
-                done[rzone] = 1
-                pass
+        r = reverse_addr(network(s))
+        if r and not r in reverse:
+            reverse[r] = generate_reverse(tree, s)
             pass
+
+    for s in tree._subnet_ipv6_:
+        if not s.domain[0] in forward:
+            forward[s.domain[0]] = generate_forward(tree, s)
+            pass
+        r = reverse_addr(network(s))
+        if r and not r in reverse:
+            reverse[r] = generate_reverse(tree, s)
+            pass
+        pass
+
+    for f in filter(lambda f: forward[f], sorted(forward)):
+        conf += "zone \"%s\" { \n" % f
+        conf += "  type master; file \"hosts-%s\"; \n" % f
+        conf += "};\n"
+        result.append(("named/hosts-%s" % f, forward[f]))
+        pass
+    for r in filter(lambda r: reverse[r], sorted(reverse)):
+        conf += "zone \"%s\" { \n" % r
+        conf += "  type master; file \"%s\"; \n" % r
+        conf += "};\n"
+        result.append(("named/%s" % r, reverse[r])) 
         pass
+
     result.append(("named.conf", conf))
     
     return result
@@ -113,20 +147,14 @@ def header(tree, domain, origin=None):
     result += ";\n"
     return result
 
-def forward(tree, domain):
+def generate_forward(tree, domain):
     result = header(tree, domain.domain[0], domain.domain[0])
     if not result:
         return None
     net = []
     for s in tree._subnet_:
-        if s.network[0] and s.domain[0] == domain.domain[0]:
-            net.append((aton(s.network[0]), aton(s.netmask[0])))
-            pass
-        pass
-    net_ipv6 = []
-    for s in tree._subnet_ipv6_:
-        if s.prefix[0] and s.domain[0] == domain.domain[0]:
-            net_ipv6.append(ipaddr.IPNetwork(s.prefix[0]))
+        if network(s) and s.domain[0] == domain.domain[0]:
+            net.append(network(s))
             pass
         pass
 
@@ -161,15 +189,17 @@ def forward(tree, domain):
         if not name in host:
             host[name] = []
             pass
-        host[name].append((kind, value))
+        if not (kind, value) in host[name]:
+            host[name].append((kind, value))
+            pass
         pass
-    for i in tree._host_._interface_._ip_:
+    for i in filter(address, tree._host_._interface_._ip_):
         # Find all hosts that belong to this network
-        for (n, m) in net:
-            if i.address[0] and aton(i.address[0]) & m == n:
+        for n in net:
+            if address(i) in n:
                 add_entry(i.name[1:], 'A', '%s' % i.address[0])
                 for a in i._alias_:
-                    add_entry(a.name[0], 'CNAME', '%s' % i.name[1:])
+                    add_entry(a.name[0], 'A', '%s' % i.address[0])
                     pass
                 for s in i._srv_:
                     port = int(s.port[0] or 0)
@@ -182,13 +212,17 @@ def forward(tree, domain):
             pass
         pass
 
-    for i in tree._host_._interface_._ipv6_:
-        for p in net_ipv6:
-            if ipaddr.IPAddress(i.address[0]) in p:
+    for i in filter(address, tree._host_._interface_._ipv6_):
+        for n in net:
+            if address(i) in n:
                 add_entry(i.name[1:], 'AAAA', '%s' % i.address[0])
+                for a in i._alias_:
+                    add_entry(a.name[0], 'AAAA', '%s' % i.address[0])
+                    pass
+                pass
             pass
         pass
-    
+
     for c in domain._cname_:
         # Emit cnames defined in subnet
         add_entry(c.alias[0], 'CNAME', '%s' % c.name[0])
@@ -203,26 +237,31 @@ def forward(tree, domain):
     
     return result
 
-def reverse(tree, net):
-    t = net.network[0].split(".")[0:3]
-    t.reverse()
-    origin = ".".join(t) + ".in-addr.arpa"
-    result = header(tree, net.domain[0], origin)
+def generate_reverse(tree, subnet):
+    net = network(subnet)
+    origin = reverse_addr(net)
+    result = header(tree, subnet.domain[0], origin)
     if not result:
         return None
     host = {}
-    m = aton(net.netmask[0])
-    n = aton(net.network[0])
-    for i in tree._host_._interface_._ip_:
+    for i in itertools.chain(tree._host_._interface_._ip_,
+                             tree._host_._interface_._ipv6_):
         # Find all hosts that belong to this network
-        if i.address[0] and aton(i.address[0]) & m == n:
-            addr = aton(i.address[0]) & ~m
-            host[addr] = "PTR     %s" % fqn(tree, i)
-
-    hk = host.keys()
-    hk.sort()
-    for h in hk:
-        result += "%-16dIN      %s\n" % (h, host[h])
+        a = address(i)
+        if not a:
+            continue
+        if a in net:
+            r = reverse_addr(a).replace('.%s' % origin, '')
+            host[r] = "PTR     %s" % fqn(tree, i)
+            pass
+        pass
+    def order(a, b):
+        def int16(v):
+            return int(v, 16)
+        return cmp(map(int16, a.split('.')),
+                   map(int16, b.split('.')))
+    for h in sorted(host, order):
+        result += "%-15s IN      %s\n" % (h, host[h])
         pass
     return result
   
@@ -263,5 +302,5 @@ def reverse_local(tree, nameserver):
             t._add(h)
             break
         pass
-    return reverse(t, net)
+    return generate_reverse(t, net)
   
diff --git a/src/hostinfo/util.py b/src/hostinfo/util.py
index d0cccabe28269484690496b81442d62072de3239..24532f10ad5d66013ef62239032982a0ba518378 100755
--- a/src/hostinfo/util.py
+++ b/src/hostinfo/util.py
@@ -1,3 +1,23 @@
+import ipaddr
+import itertools
+import types
+
+def network(s):
+    if s.network[0] and s.netmask[0]:
+        return ipaddr.IPNetwork('%s/%s' % (s.network[0], s.netmask[0]))
+    elif s.prefix[0]:
+        return ipaddr.IPNetwork(s.prefix[0])
+    else:
+        return None
+
+def address(ip):
+    if isinstance(ip, types.StringTypes):
+        return ipaddr.IPAddress(ip)
+    elif ip.address[0]:
+        return ipaddr.IPAddress(ip.address[0])
+    else:
+        return None
+
 def aton(addr):
     result = long(0)
     for s in addr.split('.'):
@@ -12,14 +32,14 @@ def fqn(tree, host):
         name of host"""
     if host.name[0:].endswith('.'):
         return host.name[0:]
-    if host._tag == 'ip':
-        ip_addr = host.address[0]
+    if host._tag in  [ 'ip', 'ipv6' ]:
+        ip_addr = address(host)
     elif host._tag == 'interface':
         for ip in host._ip_:
             if ip.alias[0] or ip.vlan[0]:
                 continue
             if ip.address[0]:
-                ip_addr = ip.address[0]
+                ip_addr = address(ip)
                 break
             pass
         pass
@@ -28,9 +48,9 @@ def fqn(tree, host):
 
     if ip_addr:
         for s in tree._subnet_:
-            if (s.network[0] and 
-                aton(ip_addr) & aton(s.netmask[0]) == aton(s.network[0])):
-                return "%s.%s." % (host.name[1:],s.domain[0])
+            net = network(s)
+            if net and ip_addr in net:
+                return "%s.%s." % (host.name[1:], s.domain[0])
             pass
         raise Exception("No subnet declaration for '%s' (%s)" %
                         (host.name[0:], ip_addr))