Example #1
0
 def addProxy(self):
     transwww = self.sysconf.Shorewall
     # XXX We should have support for multiple LANPrimary interfaces here.
     net = [i for j,i in Utils.getLanNetworks(self.sysconf).items()][0]
     transwww['rules'].append([
         1, "REDIRECT loc      8080     tcp     80      -     !%s" % (net)
     ])
     self.sysconf.Shorewall = transwww
Example #2
0
    def addProxy(self):
        transwww = self.sysconf.Shorewall
        net = [i for j, i in Utils.getLanNetworks(self.sysconf).items()][0]

        if not transwww.get('redirect'):
            transwww['redirect'] = []

        transwww['redirect'].append([
            1,
            "REDIRECT loc      8080     tcp     80      -     !%s" % (net)
        ])
        self.sysconf.Shorewall = transwww
Example #3
0
 def __init__(self):
     self.config = confparse.Config()
     self.lanNetworks = [
         i for k, i in Utils.getLanNetworks(self.config).items()
     ]
     #self.lanNetwork = '.'.join(self.config.EthernetDevices[self.config.LANPrimary]['ip'].split('.')[:2]) + '.'
     self.db = Database.AggregatorDatabase()
     self.portCache = {}  # Cache for service lookups
     self.lastSeen = []
     self.sourcesSeen = {}
     self.itime = 60  # 60 is good
     self.rtime = 5 * 60  # 5*60 is good
     reactor.callLater(self.itime, self.persistFlows)
     print "[NetFlowCollector] Working with LANs: ", self.lanNetworks
Example #4
0
    def submitRoute(self, ctx, form, data):
        eth = self.sysconf.EthernetDevices
        target = None
        destination = data['dest'].encode("ascii", "replace").lower()
        if data['gate']:
            gateway = data['gate'].encode("ascii", "replace")
            if data['device']:
                target = data['device'].encode("ascii", "replace")
        else:
            gateway = data['device'].encode("ascii", "replace")

        if '0.0.0.0/0' in destination:
            destination = 'default'

        if destination == 'default':
            # Purge existing default routes, if any
            for dev, items in eth.items():
                oldRoutes = items.get('routes', [])
                newRoutes = []
                for dst, gw in oldRoutes:
                    if dst == "default":
                        continue
                    newRoutes.append((dst, gw))
                eth[dev]['routes'] = newRoutes

        if (not target) and data['gate']:
            # Dunno where to go... Look at gateway and make an intelligent choice
            for iface, net in Utils.getLanNetworks(self.sysconf).items():
                print data['gate']
                if Utils.matchIP(net, gateway):
                    # Gateway matches this interface local-link
                    target = iface
        if not target:
            # Still nothing, go for broke - these will be added to Quagga anyways
            target = Utils.getLans(self.sysconf)[0]

        routes = eth[target].get('routes', [])
        routes.append((destination, gateway))

        eth[target]['routes'] = routes
        self.sysconf.EthernetDevices = eth

        def next(_):
            return url.root.child('Routing')

        return applySettings().addCallback(next)
Example #5
0
    def lanTest(self):
        def lanScan(res):
            hosts = {}
            lastIP = ""
            ipOrder = []
            for i in res.split('\n'):
                if "Host" in i:
                    if "(" in i:
                        host = i.split()[1]
                        ip = i.split()[2].replace('(', '').replace(')', '')
                    else:
                        ip = i.split()[1]
                        host = ip

                    hosts[ip] = [unicode(host), u"", u""]
                    ipOrder.append(ip)
                    lastIP = ip
                elif "MAC" in i:
                    mac = i.split()[2]
                    brand = i.split()[3].replace('(', '').replace(')', '')
                    hosts[lastIP][1] = unicode(mac)
                    hosts[lastIP][2] = unicode(brand)

            bundle = []

            for k in ipOrder:
                v = hosts[k]
                sortKey = [int(i) for i in k.split('.')]
                bundle.append((unicode(k), v[0], v[1], v[2]))

            return bundle

        loc = []
        for k, v in Utils.getLanNetworks(self.sysconf).items():
            loc.append('nmap -sP %s 2>&1 | grep -E "(be up|MAC)"' % (v))

        return WebUtils.system(';'.join(loc)).addCallback(lanScan)
Example #6
0
    def submitRoute(self, ctx, form, data):
        eth = self.sysconf.EthernetDevices
        target = None
        destination = data['dest'].encode()
        if data['gate']:
            gateway = data['gate'].encode()
        else:
            gateway = data['device'].encode()

        if '0.0.0.0/0' in destination:
            destination = u'default'
            if 'eth' in self.sysconf.WANPrimary:
                target = self.sysconf.WANPrimary
            else:
                target = Utils.getLans(self.sysconf)[0]

        if (not target) and data['gate']:
            # Dunno where to go... Look at gateway and make an intelligent choice
            for iface, net in Utils.getLanNetworks(self.sysconf).items():
                print data['gate']
                if Utils.matchIP(net, gateway):
                    # Gateway matches this interface local-link
                    target = iface
        if not target:
            # Still nothing, go for broke
            target = Utils.getLans(self.sysconf)[0]

        routes = eth[target].get('routes', [])
        routes.append((destination, gateway))
        
        eth[target]['routes'] = routes
        self.sysconf.EthernetDevices = eth

        def next(_):
            return url.root.child('Routing')
        return applySettings().addCallback(next)
Example #7
0
    def writeConfig(self, *a):
        path = "/etc/squid/"
        # Make sure Dansguardian is sorted
        os.system('mkdir -p /var/log/dansguardian')
        os.system('touch /var/log/dansguardian/access.log')
        os.system('chown -R dansguardian:dansguardian /var/log/dansguardian')

        # Sort out update cache permissions
        os.system('mkdir -p /var/lib/samba/updates/download')
        os.system('chown -R proxy:proxy /var/lib/samba/updates')
        os.system('chmod -R a+rwx /var/lib/samba/updates')
        os.system('chmod -R a+rwx /usr/local/tcs/tums/uaxeldb')
        #Fix read permissions for config files
        os.system('chmod a+r /etc/squid')
        os.system('chmod a+r /etc/squid/allow_hosts')
        os.system('chmod a+r /etc/squid/allow_dst')
        os.system('chmod a+r /etc/squid/allow_domains')

        allowDest = ""
        allowHost = ""
        allowDom = "vulaniblockdomainholder.vulani\n"
        blockDom = "vulaniblockdomainholder.vulani\n"
        for h in config.ProxyAllowedDomains:
            allowDom += "%s\n" % h

        for h in config.ProxyBlockedDomains:
            blockDom += "%s\n" % h

        for h in config.ProxyAllowedDestinations:
            allowDest += "%s\n" % h

        for h in config.ProxyAllowedHosts:
            allowHost += "%s\n" % h

        l = open(path + 'allow_dst', 'wt')
        l.write(allowDest)
        l.close()

        l = open(path + 'allow_hosts', 'wt')
        l.write(allowHost)
        l.close()

        l = open(path + 'allow_domains', 'wt')
        l.write(allowDom)
        l.close()

        l = open(path + 'denied_domains', 'wt')
        l.write(blockDom)
        l.close()

        adGroupAuth = ""
        adGroups = []

        aclEntries = [
        ]  #Make sure we don't break the squid config by making reference to undefined acls keep a list of defined acls and only use them if they are in this list

        if config.ProxyConfig.get('adauth', None):
            if config.ProxyConfig.get(
                    'addom', None) and config.ProxyConfig.get(
                        'adldapuser', None) and config.ProxyConfig.get(
                            'adldappass', None):
                basedn = str.join(',', [
                    "dc=" + str(dfrag) for dfrag in config.ProxyConfig.get(
                        'addom', str).split('.')
                ])
                adInfo = {
                    'basedn': basedn,
                    'ldapuser': config.ProxyConfig['adldapuser'],
                    'ldappass': config.ProxyConfig['adldappass'],
                    'adserver': config.ProxyConfig['adserver']
                }
                authentication = "auth_param basic program /usr/lib/squid/ldap_auth -R -b \"%(basedn)s\" -D \"%(ldapuser)s\" -w \"%(ldappass)s\" -f sAMAccountName=%%s -h %(adserver)s -p389" % adInfo

                if config.ProxyConfig.get('adacls', None):
                    adGroupPaths = []
                    for adacl in config.ProxyConfig.get('adacls', []):
                        if '=' in adacl[1]:
                            filter = "(memberof=cn=%%a,%s,%s)" % (adacl[1],
                                                                  basedn)
                            if filter not in adGroupPaths:
                                adGroupPaths.append(filter)
                            adGroups.append(
                                "acl vacl_%s external adACLGroup %s" %
                                (adacl[2], adacl[0]))
                            aclEntries.append(adacl[2])
                        else:
                            print "Invalid AD Group path", adacl[1]

                    if len(adGroupPaths) > 0:
                        if len(adGroupPaths) > 1:
                            adInfo["adGroupFilter"] = "(|%s)" % str.join(
                                "", adGroupPaths)
                        else:
                            adInfo["adGroupFilter"] = adGroupPaths[0]

                        authentication = authentication + "\nexternal_acl_type adACLGroup %%LOGIN /usr/lib/squid/squid_ldap_group -R -b \"%(basedn)s\" -D \"%(ldapuser)s\" -w \"%(ldappass)s\" -f \"(&%(adGroupFilter)s(objectclass=person)(sAMAccountName=%%v))\" -h %(adserver)s -p389" % adInfo

            else:
                authentication = "auth_param basic program /usr/lib/squid/msnt_auth"
                l = open(path + 'msntauth.conf', 'wt')
                l.write('server      %s       %s       %s\n' %
                        (config.ProxyConfig['adserver'],
                         config.ProxyConfig['adserver'],
                         config.ProxyConfig['addom']))
                l.close()
                os.system('chmod a+r %smsntauth' % path)
        else:
            #authentication = "auth_param basic program /usr/libexec/squid/squid_ldap_auth -b "ou=People,%s,o=%s" -f (&(uid=%%s)(employeeType=squid)) localhost
            #""" % (','.join(["dc=%s"%(i,) for i in config.Domain.split('.')]), config.LDAPBase)

            authentication = "auth_param basic program /usr/libexec/squid/squid_ldap_auth -b \"o=%s\" -f " % config.LDAPBase
            # Muchos haxed ldap search
            authentication += "(&(|(mail=%%s@%s)(mail=%%s))(employeeType=squid)) localhost \n" % config.Domain

        if config.ProxyConfig.get('contentfilter', None):
            cfilter = "cache_peer 127.0.0.1 parent 8081 0 no-query login=*:nopassword\n"
        else:
            cfilter = ""

        timeAcls = ""

        # Do user ACLS here

        for usrs, aclname in config.ProxyConfig.get('aclusers', []):
            timeAcls += "acl vacl_%s proxy_auth %s\n" % (aclname, ' '.join(
                [i.strip() for i in usrs.split(',')]))
            aclEntries.append(aclname)

        # Do more destination ACL's here
        for doms, aclname in config.ProxyConfig.get('domacls', []):
            timeAcls += "acl vacl_%s dstdomain %s\n" % (aclname, ' '.join(
                [i.strip() for i in doms.split(',')]))
            aclEntries.append(aclname)

        srcacls = ""
        for i in config.ProxyConfig.get('srcacls', []):
            src, acl = i
            if not '/' in src:
                src_ip = "%s/32" % src
            else:
                src_ip = src

            srcacls += "acl vacl_%s src %s\n" % (acl, src_ip)
            aclEntries.append(acl)

        denys = ""
        allows = ""
        cnt = 0
        if config.ProxyConfig.get('timedaccess', None):
            for action, days, times, domain, exacl in config.ProxyConfig[
                    'timedaccess']:
                if exacl not in aclEntries:
                    continue
                cnt += 1
                timeAcls += "acl time_acl%s time %s %s\n" % (cnt, days, times)
                if domain:
                    timeAcls += "acl domain_acl%s dstdomain %s\n" % (cnt,
                                                                     domain)

                if action:
                    allows += "http_access allow all time_acl%s" % (cnt, )
                else:
                    allows += "http_access deny all time_acl%s" % (cnt, )

                if domain:
                    allows += " domain_acl%s" % (cnt)

                if exacl:
                    allows += " vacl_%s" % exacl

                allows += "\n"

        bindaddr = ""
        if config.ProxyConfig.get('bindaddr'):
            bindaddr = "tcp_outgoing_address %s" % config.ProxyConfig.get(
                'bindaddr')

        routingacls = ""
        for i in config.ProxyConfig.get('aclgateways', []):
            gateway, acl = i
            if acl in aclEntries:
                routingacls += "tcp_outgoing_address %s vacl_%s\n" % (gateway,
                                                                      acl)

        for acl, perm in config.ProxyConfig.get('aclperms', []):
            aclList = []
            for e in acl.split():
                if e in aclEntries:
                    aclList.append('vacl_' + e)
            if aclList:
                if perm == "allow":
                    allows += "http_access allow all %s\n" % str.join(
                        ' ', aclList)
                else:
                    allows += "http_access deny all %s\n" % str.join(
                        ' ', aclList)

        # Configure our update accelerator
        updator = ""
        redirCache = ""
        redircacheallow = ""
        if config.ProxyConfig.get('updates', {}).get('enabled', None):

            # Allow redir hosts to bypass all Squid auth when we use a captive portal. Also point all to the rewriter
            if config.ProxyConfig.get('captive'):
                redirCache = "acl redir_hosts src \"/etc/squid/redir_hosts\""
                redircacheallow = "http_access allow redir_hosts"

            rfi = open('/etc/squid/redir_hosts', 'wt')
            for iface, net in Utils.getLanNetworks(config).items():
                rfi.write(net + '\n')
            rfi.close()

            updateConf = config.ProxyConfig['updates']
            # Get config options and set some defaults
            diskspace = updateConf.get('maxspace', 95)
            speed = updateConf.get('maxspeed', 256)

            # accelerator.conf
            accelerator = """#Proxy Settings
UPSTREAM_USER=
UPSTREAM_PASSWORD=
PROXY_PORT=8080
ENABLE_UPDXLRATOR=on
UPSTREAM_PROXY=

#Accelerator Settings
AUTOCHECK_SCHEDULE=daily
LOW_DOWNLOAD_PRIORITY=off
ENABLE_AUTOCHECK=on
PASSIVE_MODE=off
FULL_AUTOSYNC=off
ENABLE_LOG=on
MAX_DISK_USAGE=%s
NOT_ACCESSED_LAST=month1
CHILDREN=5
MAX_DOWNLOAD_RATE=%s

GREEN_ADDRESS=127.0.0.1\n""" % (diskspace, speed)

            acc = open('/etc/squid/accelerator.conf', 'wt')
            acc.write(accelerator)
            acc.close()

            # meh
            os.system('chmod a+r /etc/squid/accelerator.conf')

            # squid.conf directives
            updator = "url_rewrite_program /usr/local/tcs/tums/bin/update_cache\n"
            updator += "url_rewrite_children 20\n"
            updator += "url_rewrite_access allow redir_cache\n"
            if config.ProxyConfig.get('captive'):
                updator += "url_rewrite_access allow redir_hosts\n"
            updator += "url_rewrite_access deny allow_hosts\n"
            updator += "url_rewrite_access deny allow_domain\n"
            updator += "url_rewrite_access deny allow_dst\n"

            if not config.ProxyConfig.get('captive'):
                updator += "url_rewrite_access deny all\n"

        #Allow for someone to specify alternative bound ports asside from the default 8080
        #Some installations require explicit binding to port 3128, by no means does this mean
        #that it should be encouraged ...
        squidConf_bindPorts = ""
        if config.ProxyConfig.get('bindports'):
            bindPorts = str(config.ProxyConfig.get('bindports'))
            for port in bindPorts.replace(' ', '').split(','):
                if port == "8080":
                    continue
                squidConf_bindPorts += "http_port %s transparent\n" % (port)

        squidconf = """http_port 8080 transparent
%(bindPorts)s
visible_hostname %(host)s
hierarchy_stoplist cgi-bin ? .pl
acl QUERY urlpath_regex cgi-bin \\? .pl .asp mail.%(domain)s
no_cache deny QUERY
cache_mem 32 MB
maximum_object_size 1000000 KB
cache_dir ufs /var/cache/squid/ 10000 16 256
cache_access_log /var/log/squid/access.log
cache_log  /var/log/squid/cache.log
cache_store_log none
pid_filename /var/run/squid.pid
#ftp_user [email protected]
ignore_expect_100 on

hosts_file /etc/hosts
%(auth)s
auth_param basic children 5
auth_param basic realm Vulani Web Proxy
auth_param basic credentialsttl 2 hours
refresh_pattern ^ftp:           1440    20%%     10080
refresh_pattern ^gopher:        1440    0%%      1440
refresh_pattern .               0       20%%     4320
refresh_pattern windowsupdate.com/.*\\.(cab|exe)         4320 100%% 43200 reload-into-ims
refresh_pattern download.microsoft.com/.*\\.(cab|exe)    4320 100%% 43200 reload-into-ims
refresh_pattern akamai.net/.*\\.(cab|exe)                4320 100%% 43200 reload-into-ims
strip_query_terms off
#acl support.microsoft.com dstdomain support.microsoft.com
#reply_header_access Accept-Encoding deny support.microsoft.com
#request_header_access Accept-Encoding deny support.microsoft.com
acl all src 0.0.0.0/0.0.0.0
acl manager proto cache_object
acl localhost src 127.0.0.1/32
acl to_localhost dst 127.0.0.0/8
%(srcacls)s
%(adAcls)s
acl allow_hosts src "/etc/squid/allow_hosts"
acl denied_domains dstdomain "/etc/squid/denied_domains"
acl allow_domain dstdomain "/etc/squid/allow_domains"
acl allow_dst dst "/etc/squid/allow_dst"
acl redir_cache dstdomain .microsoft.com
acl redir_cache dstdomain .windowsupdate.com
acl redir_cache dstdomain .mirror.ac.za
acl redir_cache dstdomain .debian.org
acl redir_cache dstdomain .ubuntu.com
acl redir_cache dstdomain .avg.com
%(redircache)s
%(timeacls)s
acl password proxy_auth REQUIRED
acl SSL_ports port 443 563
acl Safe_ports port 80          # http
acl Safe_ports port 21          # ftp
acl Safe_ports port 443 563     # https, snews
acl Safe_ports port 70          # gopher
acl Safe_ports port 210         # wais
acl Safe_ports port 1025-65535  # unregistered ports
acl Safe_ports port 280         # http-mgmt
acl Safe_ports port 488         # gss-http
acl Safe_ports port 591         # filemaker
acl Safe_ports port 777         # multiling http
acl Safe_ports port 901         # SWAT
acl purge method PURGE
acl CONNECT method CONNECT
redirector_access deny localhost
http_access allow manager localhost
http_access deny manager
http_access allow purge localhost
http_access deny purge
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
http_access deny to_localhost
http_access allow all localhost
%(allows)s
http_access deny denied_domains

http_access allow allow_domain
http_access allow allow_dst
%(denys)s
http_access allow allow_hosts
%(redircacheallow)s
%(passwordAuth)s
http_access deny all
http_reply_access allow all
icp_access allow all
cache_mgr postmaster@%(domain)s
logfile_rotate 7
append_domain .%(domain)s
forwarded_for on
cachemgr_passwd %(ldappass)s shutdown
cachemgr_passwd %(ldappass)s info stats/objects
cachemgr_passwd disable all
snmp_access allow localhost
coredump_dir /var/log/squid
extension_methods REPORT MERGE MKACTIVITY CHECKOUT
acl snmpcommunity snmp_community public
snmp_port 3401
snmp_access allow snmpcommunity localhost
snmp_access deny all\n%(updator)s\n%(bindaddr)s\n%(cfilter)s\n%(routingacls)s""" % {
            'redircache':
            redirCache,
            'host':
            config.Hostname + "." + config.Domain,
            'bindPorts':
            squidConf_bindPorts,
            'domain':
            config.Domain,
            'auth':
            authentication,
            'ldappass':
            config.LDAPPassword,
            'timeacls':
            timeAcls,
            'allows':
            allows,
            'denys':
            denys,
            'redircacheallow':
            redircacheallow,
            'updator':
            updator,
            'bindaddr':
            bindaddr,
            'cfilter':
            cfilter,
            'routingacls':
            routingacls,
            'srcacls':
            srcacls,
            'adAcls':
            str.join('\n', adGroups),
            'passwordAuth':
            len(adGroups) > 0
            and config.ProxyConfig.get('adGroupDefaultDeny', False) and ' '
            or 'http_access allow all password'
        }
        # Apply debian fixes
        squidconf = squidconf.replace('/usr/libexec/squid/squid_ldap_auth',
                                      '/usr/lib/squid/ldap_auth')
        #squidconf = squidconf.replace('/etc/squid/', '/etc/squid/')
        os.system('mkdir -p /var/cache/squid > /dev/null 2>&1')
        os.system('mkdir -p /var/log/squid > /dev/null 2>&1')
        os.system('chown proxy:proxy /var/cache/squid')
        os.system('touch /var/log/tums_cache.log')
        os.system('chown proxy:proxy /var/log/tums_cache.log')
        os.system('chmod a+rwx /var/log/tums_cache.log')
        os.system('chown -R proxy:proxy /var/log/squid')
        os.system('rm -r /var/log/squid3 > /dev/null 2>&1')
        l = open(path + 'squid.conf', 'wt')
        l.write(squidconf)
        l.close()

        # Configure WPAD script for each LAN range.
        for ip in Utils.getLanIPs(config):
            pacfile = """function FindProxyForURL(url, host)
{
  if (shExpMatch(url, "http:*")) 
     return "PROXY %(proxyUrl)s:8080";
  if (shExpMatch(url, "https:*"))
     return "PROXY %(proxyUrl)s:8080";
  if (shExpMatch(url, "ftp:*"))
     return "PROXY %(proxyUrl)s:8080";

  return "DIRECT";
}\n""" % {
                'proxyUrl': ip
            }
            fp = open(
                '/var/www/localhost/htdocs/wpad-%s.pac' % ip.replace('.', '-'),
                'wt')
            fp.write(pacfile)
            fp.close()

        try:
            default = Utils.getLanIPs(config)[0]
            os.system(
                'cp /var/www/localhost/htdocs/wpad-%s.pac /var/www/localhost/htdocs/wpad.dat'
                % default.replace('.', '-'))
        except:
            pass
Example #8
0
File: Exim.py Project: calston/tums
    def writeConfig(self, *a):
        # VERY IMPORTANT NOTICE! 
        #
        #  All lines are lead by 8 spaces. These spaces are stripped out at the end.
        #  If you have less than 8 spaces before any new line written to the config
        #  then it will be broken
        #  This is done to make the source semi readable 
        # 
        # END OF IMPORTANT NOTICE

        # Setup local delivery domains
        locals = "\n".join(config.LocalDomains)

        # A list of servers we redeliver or hub mail to
        serverhosts = ['127.0.0.1']

        # Configure hubbed hosts and relay domains
        relayDoms = config.Mail.get('relay', [])
        hubs = ""
        mailReroute = ""
        for dom, dest in config.Mail.get('hubbed', []):
            if dest not in serverhosts:
                serverhosts.append(dest)
            if "@" in dom:
                mailReroute += "%s       %s        byname\n" % (dom,dest)
                dom = dom.split('@')[-1]
            else:
                hubs += "%s        %s        byname\n" % (dom, dest)

            if dom not in relayDoms:
                relayDoms.append(dom)

        # Branch configuration 
        branches = config.Mail.get('branchtopology', {})
        branchMap = {}
        for r in config.Mail.get('branches', []):

            # if the items in branches are not lists, we assume an old datastructure
            if not isinstance(r, list):
                branchMap[r] = None
                continue

            svr, relay = r


            branchMap[svr] = None

            if relay:
                branchMap[svr] = relay.replace(' ', '').replace(';', ',').replace(':', ',').split(',')

        branchReroute = ""
        for branch, addrs in branches.items():
            for addr in addrs:
                # Extend relay domains to handle this remote server too
                dom = addr.split('@')[-1]
                if dom not in relayDoms:
                    relayDoms.append(dom)

                if branchMap[branch]:
                    relay = ':'.join(branchMap[branch])
                else:
                    relay = branch
                
                if relay not in serverhosts:
                    serverhosts.append(relay)

                # Add the address to mail reroute
                branchReroute += "%s       %s        byname\n" % (
                    addr,
                    relay
                )
                
        # Setup our relay list
        relays = "\n".join(relayDoms)

        # Initialise blacklists
        blacklistSender = ""
        blacklistHost = ""
        blacklistDom  = ""
        
        for b in config.Mail.get('blacklist', []):
            if "@" in b:
                blacklistSender += b + '\n'
            else:
                try:
                    int(b.split('.')[0])
                    blacklistHost += b + '\n'
                except:
                    blacklistDom += b + '\n'

        whitelistSender = ""
        whitelistHost = ""
        whitelistDom = ""
        for w in config.Mail.get('whitelist', []):
            if "@" in w:
                whitelistSender += w + "\n"
            else:
                try:
                    int(w.split('.')[0])
                    whitelistHost += w + '\n'
                except:
                    whitelistDom += w + '\n'

        catchall = ""
        for c in config.Mail.get('catchall', []):
            catchall += c + "\n"

        # System filters
        copyTo = "#System Filter\nif error_message then finish endif\n\n"

        if config.Mail.get('copytoall', None):
            copyTo += "if first_delivery then\n"
            copyTo += "    unseen deliver %s errors_to postmaster@%s\n" % (config.Mail['copytoall'], config.Domain)
            copyTo += "endif\n\n"

        for addr, dest in config.Mail.get('copys', []):
            copyTo += "if $recipients contains %s then\n" % addr
            copyTo += "    unseen deliver %s errors_to postmaster@%s\n" % (dest, config.Domain)
            copyTo += "endif\n\n"

        # Global system filter
        if os.path.exists('/usr/local/tcs/tums/filter.db'):
            filterCont = open('/usr/local/tcs/tums/filter.db').read()
            copyTo += filterCont
            copyTo += "\n"
        
        allowsend = ""
        if config.Mail.get('allowsend', None):
            allowsend = "\n".join(config.Mail['allowsend'])

        if config.Mail.get('disableratelimit', None):
            rateLimit = ""
        else:
            rateLimit = """
        # System-wide rate limit for dodgey senders
          defer message = Connection limited: Sender rate $sender_rate / $sender_rate_period.
                hosts            = +relay_hosts
                !sender_domains  = +local_domains : +relay_domains
                !senders         = :
                ratelimit = 50 / 1h / strict\n"""

        if config.Mail.get('disablerpfilter', None):
            senderRpFilter = ""
        else:
            senderRpFilter = """
        # Block mail from forged address on the local side. 
          deny message  =  Vulani has rejected this message from $sender_address because it is not local to this site. http://vulani.net/
                !sender_domains  = +local_domains : +relay_domains
                !senders         = :
                !senders         = +acl_allowed_senders
                hosts            = +relay_hosts
                !hosts           = +server_hosts\n"""


        Utils.writeConf('/etc/exim4/sender_whitelist', whitelistSender, '#')
        Utils.writeConf('/etc/exim4/host_whitelist', whitelistHost, '#')
        Utils.writeConf('/etc/exim4/domain_whitelist', whitelistDom, '#')

        Utils.writeConf('/etc/exim4/sender_blacklist', blacklistSender, '#')
        Utils.writeConf('/etc/exim4/host_blacklist', blacklistHost, '#')
        Utils.writeConf('/etc/exim4/domain_blacklist', blacklistDom, '#')

        Utils.writeConf('/etc/exim4/allowed_senders', allowsend, '#')

        Utils.writeConf('/etc/exim4/host_noavscan', "", '#')

        Utils.writeConf('/etc/exim4/local_domains', locals, '#')
        Utils.writeConf('/etc/exim4/relay_domains', relays, '#')
        Utils.writeConf('/etc/exim4/hubbed_hosts', hubs, '#')
        Utils.writeConf('/etc/exim4/mail_reroute', mailReroute, '#')
        Utils.writeConf('/etc/exim4/branch_reroute', branchReroute, '#')
        Utils.writeConf('/etc/exim4/system_filter', copyTo, '#')
        Utils.writeConf('/etc/exim4/catchall_domains', catchall, '#')

        # Get rid of the autogenerated tag so aptitude doesn't break us
        os.system('rm /var/lib/exim4/config.autogenerated > /dev/null 2>&1')
        systemFilter = "system_filter = /etc/exim4/system_filter\n"
 
        if config.Mail.get('noavscan'):
            avScan = ""
            avscanacl = ""
            print "Antivirus scanning disabled!"
        else:
            avScan = "av_scanner = clamd:/var/run/clamav/clamd.sock"
            avscanacl = """            accept condition  = ${if <={$message_size}{250k}{yes}{no}}
            deny message      = This message contains a virus ($malware_name)
                !hosts        = +acl_host_noavscan
                malware       = *\n"""

        primaryDomain = config.Domain
        hostname = config.ExternalName  # Must be externally lookupable(?!?) name
        mailSize = config.Mail.get('mailsize', '')
        localNet = " : ".join([v for k,v in Utils.getLanNetworks(config).items()])
        
        for n in Utils.getLanIP6s(config):
            localNet += ' : %s ' % n.replace(':', '::')

        # fill in allowed hosts (config.Mail.relay-from)
        if config.Mail.get('relay-from'):
            localNet += ' : ' + ' : '.join(config.Mail['relay-from'])
        extensionBlock = ""

        # Blocked file extensions
        if config.Mail.get('blockedfiles', []):
            extensionBlock = "            deny  message     = We do not accept \".$found_extension\" attachments here.\n"
            extensionBlock += "                 demime      = %s\n" % ':'.join(config.Mail['blockedfiles'])

        # Mail rewrite rules
        rewriteRules = ""
        for fromm,too,flags in config.Mail.get('rewrites', []):
            # flags is one of TtFfbcr
            rewriteRules+='        *@%s    $1@%s   %s\n' % (fromm, too, flags)

        # Get any mailman settings
        mm_router, mm_transport, mm_main = self.MailMan()

        # SpamAssassin required score
        spamscore = config.Mail.get('spamscore', 70)

        # Get greylisting ACLS (if greylisting is enabled)
        aclCheckSenderGreylist, aclCheckDataGreylist = self.Greylisting()

        ### Enable tweaked performance
        performanceTweak = ""
        if config.Mail.get('performance', False):
            performanceTweak =  "        # use muliple directories (default false)\n"
            performanceTweak += "        split_spool_directory\n"
            performanceTweak += "        # queue incoming if load high (no default)\n"
            performanceTweak += "        queue_only_load = 4\n"
            performanceTweak += "        # maximum simultaneous queue runners (default 5)\n"
            performanceTweak += "        queue_run_max = 0\n"
            performanceTweak += "        # parallel delivery of one message to a number of remote hosts (default 2)\n"
            performanceTweak += "        remote_max_parallel = 30\n"
            performanceTweak += "        # simultaneous connections from a single host (default 10)\n"
            performanceTweak += "        smtp_accept_max_per_connection = 20\n"
            performanceTweak += "        # maximum number of waiting SMTP connections (default 20)\n"
            performanceTweak += "        smtp_connect_backlog = 50\n"
            performanceTweak += "        # maximum number of simultaneous incoming SMTP calls that Exim will accept (default 20)\n"
            performanceTweak += "        smtp_accept_max = 0\n"

        if config.Mail.get('rbls'):
            RBL = config.Mail.get('rbls')
        else:
            RBL = [
                "dsn.rfc-ignorant.org/$sender_address_domain",
                "zen.spamhaus.org",
                "dnsbl.njabl.org",
                "bhnc.njabl.org",
                "combined.njabl.org",
                "bl.spamcop.net",
                "psbl-mirror.surriel.com",
                "blackholes.mail-abuse.org",
                "dialup.mail-abuse.org"
            ]


        ### Exim main configuration

        eximMain = """
        ######################################################################
        #                    MAIN CONFIGURATION SETTINGS                     #
        ######################################################################
        ldap_default_servers = %(ldap)s
        primary_hostname = %(hostname)s
        %(avScan)s
        spamd_address = 127.0.0.1 783
        %(systemFilter)s
        
        domainlist local_domains = @ : lsearch;/etc/exim4/local_domains
        domainlist relay_domains = lsearch;/etc/exim4/relay_domains
        hostlist   relay_hosts = 127.0.0.1 : %(hostlist)s
        hostlist   server_hosts = %(serverhosts)s
        
        domainlist acl_domain_whitelist = lsearch;/etc/exim4/domain_whitelist
        hostlist acl_host_whitelist = net-iplsearch;/etc/exim4/host_whitelist
        addresslist acl_sender_whitelist = lsearch*@;/etc/exim4/sender_whitelist
        domainlist acl_domain_blacklist = lsearch;/etc/exim4/domain_blacklist
        hostlist acl_host_blacklist = net-iplsearch;/etc/exim4/host_blacklist
        addresslist acl_sender_blacklist = lsearch*@;/etc/exim4/sender_blacklist
        addresslist acl_allowed_senders = /etc/exim4/allowed_senders

        hostlist acl_host_noavscan = net-iplsearch;/etc/exim4/host_noavscan

        acl_smtp_connect = acl_check_host
        acl_smtp_helo = acl_check_helo
        acl_smtp_mail = acl_check_sender
        acl_smtp_rcpt = acl_check_rcpt
        acl_smtp_data = acl_check_data
        acl_smtp_etrn = acl_check_etrn

        qualify_domain = %(domain)s
        trusted_users = mail
        message_size_limit = %(mailSize)s
        helo_allow_chars = _
        host_lookup = *
        smtp_enforce_sync = false 
        helo_accept_junk_hosts = *
        strip_excess_angle_brackets
        strip_trailing_dot
        delay_warning_condition = "\\
                ${if match{$h_precedence:}{(?i)bulk|list|junk}{no}{yes}}"
        #rfc1413_hosts = ${if eq{$interface_port}{SMTP_PORT} {*}{! *}}
        rfc1413_query_timeout = 0s
        sender_unqualified_hosts = %(hostlist)s
        recipient_unqualified_hosts = %(hostlist)s
        ignore_bounce_errors_after = 2d
        timeout_frozen_after = 7d
        recipients_max = 0
        # SSL/TLS cert and key
        tls_certificate = /etc/exim4/exim.cert
        tls_privatekey = /etc/exim4/exim.key
        # Advertise TLS to anyone
        tls_advertise_hosts = *
        smtp_etrn_command = /etc/exim4/etrn_script $domain

        LDAP_AUTH_CHECK_LOGIN = ${lookup ldap { \\
            user="******"cn=Manager,o=%(base)s" pass=%(pass)s ldap:///?dn?sub?(&(accountStatus=active)(mail=${quote_ldap:$1}))}}" \\
            pass="******" ldap:///?mail?sub?(&(accountStatus=active)(mail=${quote_ldap:$1}))}{yes}{no}}
        
        LDAP_AUTH_CHECK_PLAIN = ${lookup ldap { \\
            user="******"cn=Manager,o=%(base)s" pass=%(pass)s ldap:///?dn?sub?(&(accountStatus=active)(mail=${quote_ldap:$2}))}}" \\
            pass="******" ldap:///?mail?sub?(&(accountStatus=active)(mail=${quote_ldap:$2}))}{yes}{no}}
        

%(extra)s
        """ % {
            'ldap':         '127.0.0.1',
            'hostname':     hostname,
            'hostlist':     localNet,
            'serverhosts':  ' : '.join(serverhosts),
            'domain':       primaryDomain,
            'mailSize':     mailSize,
            'extra':        performanceTweak + mm_main,
            'systemFilter': systemFilter,
            'avScan':       avScan,
            'base':config.LDAPBase,
            'pass':config.LDAPPassword
        }

        eximACL="""
        ######################################################################
        #                       ACL CONFIGURATION                            #
        #         Specifies access control lists for incoming SMTP mail      #
        ######################################################################

        begin acl

        ######################################################################
        # Check connecting host (DNSBL's checked in acl_check_rcpt to ensure no reconnect attempt)
        ######################################################################
        acl_check_host:
            deny hosts        = +acl_host_blacklist
            accept

        ######################################################################
        # Check conencting host is not pretending to be the localhost
        ######################################################################
        acl_check_helo:

            accept hosts         = +relay_hosts
        # If the HELO pretend to be this host
            deny condition       = ${if or { \\
                                  {eq {${lc:$sender_helo_name}}{%(hostname)s}} \\
                                  {eq {${lc:$sender_helo_name}}{%(domain)s}} \\
                                  } {true}{false} }
            accept


        ######################################################################
        # Check sender address
        ######################################################################
        acl_check_sender:
            deny message      = sender envelope address $sender_address is locally blacklisted here.
                senders         = +acl_sender_blacklist

            accept


        ######################################################################
        # Check incoming messages
        ######################################################################
        acl_check_rcpt:

        # Accept if source is local SMTP
          accept hosts      = :
        # Deny if illegal characters in email address
          deny local_parts  = ^.*[@%%!/|] : ^\\\\.

%(ratelimit)s

        # Accept mail to postmaster at any local domain without any checks
          accept local_parts = postmaster
                domains    = +local_domains

%(senderRpFilter)s

        # Accept local, authenticated, whitelisted and dnswl'd hosts
          accept hosts      = +relay_hosts
          accept authenticated = *
          accept dnslists   = list.dnswl.org
          accept hosts      = +acl_host_whitelist
          accept domains    = +acl_domain_whitelist
          accept senders    = +acl_sender_whitelist

        # Deny if domain is locally blacklisted
          deny message        = rejected because $sender_domain is locally blacklisted here
                domains             = +acl_domain_blacklist

        # Deny if listed in a DNSBL
          deny message      = rejected because $sender_host_address is in a blacklist \\
                              at $dnslist_domain\\n$dnslist_text
            !senders        = :
            domains         = +local_domains : +relay_domains
            dnslists        = %(rbl)s

        # Accept if this is a local domain
          accept domains    = +local_domains
            endpass
            message         = unknown user
            verify          = recipient

        # Accept if this is a relay domain
          accept domains    = +relay_domains
            endpass
            message         = unrouteable address
            verify          = recipient

%(senderGreylist)s

        # Deny everything else
            deny message    = relay not permitted

        ######################################################################
        # Check contents of email
        ######################################################################
        acl_check_data:
%(dataGreylist)s

        # ClamAV virus scanning
            deny message      = Vulani has rejected this message because it contains a virus: ($malware_name) http://vulani.net
                log_message   = rejected VIRUS ($malware_name) from $sender_address to $recipients
                !hosts        = +acl_host_noavscan
                demime        = *
                malware       = */defer_ok

        # Reject messages that have serious MIME errors. This calls the demime
        # condition again, but will return cached results.
            deny message      = Vulani has rejected this message because it contains a broken MIME container ($demime_reason) http://vulani.net
                log_message   = rejected broken MIME container ($demime_reason) from $sender_address to $recipients
                condition     = ${if >{$demime_errorlevel}{2}{1}{0}}
                demime        = *

        # SpamAssassin Content Filtering
        # Include Spam Score in Header
            warn message      = X-Spam-Score: $spam_score\\n\\
                                X-Spam-Score-Int: $spam_score_int\\n\\
                                X-Spam-Bar: $spam_bar
                condition     = ${if <{$message_size}{250k}{1}{0}}
                !hosts        = +relay_hosts
                spam          = nobody:true/defer_ok

        # Reject spam messages with score over 7, using an extra condition.
            deny message      = Vulani has rejected this message because it scored $spam_score spam points and is considered to be unsolicited http://vulani.net
                log_message   = rejected SPAM score above threshhold in message from $sender_address to $recipients
                !hosts        = +acl_host_noavscan
                condition     = ${if >{$spam_score_int}{70}{1}{0}}
                spam          = nobody:true

%(extblock)s

            accept

        ######################################################################
        # Check ETRN requests
        ######################################################################
        acl_check_etrn:
            accept hosts = 0.0.0.0/0

        """ % {
            'rbl':              ' : '.join(RBL),        # DNS block lists
            'spamlow':          int(spamscore)-20,      # Warn spam score
            'spamhigh':         int(spamscore),         # Drop spam score.
            'senderGreylist':   aclCheckSenderGreylist, # Greylisting configuration
            'dataGreylist':     aclCheckDataGreylist,   #
            'extblock':         extensionBlock,         # Blocked file extensions
            'hostname':         hostname,
            'domain':       primaryDomain,
            'senderRpFilter': senderRpFilter,
            'ratelimit':    rateLimit,
            'avscan':       avscanacl
        }

        # Trigger our disclaimer transport 
        if config.Mail.get('disclaimer'):
            transport = "remote_smtp_filter"
        else:
            transport = "remote_smtp"

        # Set the external router depending on how the relay is set
        if config.SMTPRelay:
            externalRouter = """
        gateway:
            driver = manualroute
            domains = ! +local_domains
            route_list = * %s bydns
            transport = %s
           """ % (config.SMTPRelay, transport)
        else:
            externalRouter = """
        dnslookup:
            driver = dnslookup
            domains = ! +local_domains
            transport = %s
            ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8
            no_more
            """ % transport

        eximRouters = """
        ######################################################################
        #                      ROUTERS CONFIGURATION                         #
        ######################################################################

        begin routers

        etrn_already:
            driver = accept
            transport = bsmtp_for_etrn
            require_files = /var/spool/mail/etrn/$domain
            domains = lsearch;/etc/exim/etrn_domains

        etrn_delay:
            driver = accept
            transport = bsmtp_for_etrn
            condition = ${if >{$message_age}{1800} {yes}{no}}
            domains = lsearch;/etc/exim/etrn_domains

        mail_reroute:
            driver = manualroute
            route_data = ${lookup{$local_part@$domain}lsearch{/etc/exim4/mail_reroute}}
            transport = remote_smtp

        branch_reroute:
            driver = manualroute
            route_data = ${lookup{$local_part@$domain}lsearch{/etc/exim4/branch_reroute}}
            transport = remote_smtp

        hubbed_hosts:
            driver = manualroute
            domains = ! +local_domains
            route_data = ${lookup{$domain}lsearch{/etc/exim/hubbed_hosts}}
            transport = remote_smtp

%(extro)s

        userforward:
            driver = redirect
            domains = +local_domains
            file = /var/spool/mail/forward/${local_part}@${domain}
            no_verify
            no_expn
            check_ancestor
            file_transport = address_file
            pipe_transport = address_pipe
            reply_transport = address_reply

        alias_user_vacation:
            driver = redirect
            domains = +local_domains
            allow_defer
            allow_fail
            data = ${lookup ldap {user="******" pass=%(ldappass)s \\
                   ldap:///?mail?sub?(mailAlternateAddress=${local_part}@${domain})}}
            redirect_router = user_vacation
            retry_use_local_part

        user_vacation:
            driver = accept
            domains = +local_domains
            require_files = /var/spool/mail/vacation/${local_part}@${domain}.txt
            no_verify
            user = apache
            senders = !^.*-request@.* : !^owner-.*@.* : !^postmaster@.* : \\
                      ! ^listmaster@.* : !^mailer-daemon@.* : !^noreply@.* : \\
                      !^.*-bounces@.*
            transport = vacation_reply
            unseen

        ldap_aliases:
            driver = redirect
            domains = +local_domains
            allow_defer
            allow_fail
            data = ${lookup ldap {user="******" pass=%(ldappass)s \\
                   ldap:///?mail?sub?(mailAlternateAddress=${local_part}@${domain})}}
            redirect_router = ldap_forward
            retry_use_local_part

        ldap_forward:
            driver = redirect
            domains = +local_domains
            allow_defer
            allow_fail
            data = ${lookup ldap {user="******" pass=%(ldappass)s \\
                    ldap:///?mailForwardingAddress?sub?\\
                    (&(accountStatus=active)(mail=${local_part}@${domain}))}{$value}fail}
            no_expn
            retry_use_local_part
            no_verify

        ldap_user:
            driver = accept
            domains = +local_domains
            condition =   ${if eq {}{${lookup ldap {user="******" pass=%(ldappass)s \\
                          ldap:///?mail?sub?(&(accountStatus=active)(mail=${local_part}@${domain}))}}}{no}{yes}}
            group = users
            retry_use_local_part
            transport = local_delivery

        catchall:
            domains = lsearch;/etc/exim/catchall_domains
            driver = redirect
            data = catchall@${domain}

%(router)s

        #localuser:
        #    driver = accept
        #    domains = +local_domains
        #    check_local_user
        #    transport = local_delivery
        """ % {
            'router': mm_router,
            'ldapbase': config.LDAPBase,
            'ldappass': config.LDAPPassword,
            'extro': externalRouter,
        }

        ## Prevent bounce of failed hosts? (Maximum send timeout reached)
        hostfailBounce = ""
        if config.Mail.get('hostfailbounce', False):
            hostfailBounce += "    delay_after_cutoff = false\n"

        if config.Mail.get('smtpinterface'):
            hostfailBounce += "    interface = %s\n" % config.Mail.get('smtpinterface')

        eximTransports = """
        ######################################################################
        #                      TRANSPORTS CONFIGURATION                      #
        ######################################################################

        begin transports

        bsmtp_for_etrn:
            driver=appendfile
            file=/var/spool/mail/etrn/$domain
            user=mail
            batch_max=1000
            use_bsmtp

        vacation_reply:
            debug_print = "T: vacation_reply for $local_part@$domain"
            driver = autoreply
            file = /var/spool/mail/vacation/${local_part}@${domain}.txt
            file_expand
            log = /var/spool/mail/vacation/${local_part}@${domain}.log
            once_repeat = 7d
            once = /var/spool/mail/vacation/${local_part}@${domain}.db
            from = ${local_part}@${domain}
            to = $sender_address
            subject = "Re: $h_subject"
            text = "\\
            This is an automated response for $local_part@${domain}:\\n\\
            ====================================================\\n\\n"

        remote_smtp:
            driver = smtp
            %(iface)s

        remote_smtp_filter:
            driver = smtp
            transport_filter = /usr/local/tcs/tums/bin/remime
            %(iface)s

        local_delivery:
            driver = appendfile
            create_directory
            delivery_date_add
            directory = ${lookup ldap {user="******" pass=%(wpass)s \\
                        ldap:///?mailMessageStore?sub?(&(accountStatus=active)\\
                        (mail=${local_part}@${domain}))}}
            directory_mode = 770
            envelope_to_add
            group = mail
            maildir_format
            mode = 660
            return_path_add
            user = mail

        address_pipe:
            driver = pipe
            return_output

        address_file:
            driver = appendfile
            delivery_date_add
            envelope_to_add
            return_path_add

        address_reply:
            driver = autoreply

        %(mm)s\n""" % {
            'iface': hostfailBounce, 
            'basedn': config.LDAPBase, 
            'wpass': config.LDAPPassword, 
            'mm': mm_transport
        }

        eximOther = """
        ######################################################################
        #                      RETRY CONFIGURATION                           #
        ######################################################################

        begin retry
        *        *   senders=:      F,2m,1m
        *        *                  F,2h,15m; G,16h,1h,1.5; F,7d,4h

        ######################################################################
        #                      REWRITE CONFIGURATION                         #
        ######################################################################

        begin rewrite
%(rewrite)s
        ######################################################################
        #                   AUTHENTICATION CONFIGURATION                     #
        ######################################################################

        begin authenticators

        login:
            driver = plaintext
            public_name = LOGIN
            server_prompts = "Username:: : Password::"
            server_advertise_condition = yes
            server_condition = ${if match_ip{$sender_host_address}{+relay_hosts}{yes}{LDAP_AUTH_CHECK_LOGIN}}
            server_set_id = $1
        plain:
            driver = plaintext
            public_name = PLAIN
            server_prompts = :
            server_advertise_condition = yes
            server_condition = ${if match_ip{$sender_host_address}{+relay_hosts}{yes}{LDAP_AUTH_CHECK_PLAIN}}
            server_set_id = $2 
        """ % {
            'base':config.LDAPBase,
            'pass':config.LDAPPassword,
            'rewrite': rewriteRules
        }

        confFile = eximMain + eximACL + eximRouters + eximTransports + eximOther
        os.system('mkdir -p /var/spool/mail/forward/')
        os.system('mkdir -p /var/spool/mail/etrn/')

        # Reprocess the config file
        lp = confFile.split('\n')
        confFile = ""
        for i in lp:
            confFile += i[8:] + '\n'

        confFile = confFile.replace('/etc/exim/', '/etc/exim4/').replace('apache', 'www-data')
        # Patches user names
        confFile = confFile.replace('user=mail', 'user=Debian-exim')
        Utils.writeConf('/etc/exim4/exim4.conf', confFile, '#')
        os.system('chmod a+r /etc/exim4/*')
        os.system('chmod -R a+r /usr/local/tcs/tums/data')
        os.system('chmod a+x /etc/exim4/etrn_script >/dev/null 2>&1')
        os.system('chmod a+rx /var/mail/vacation >/dev/null 2>&1')
        os.system('chown Debian-exim:Debian-exim /var/spool/mail/etrn')
        os.system('mkdir /var/cache/vulani/ >/dev/null 2>&1')

        ### Mailname
        mailname = "%s.%s\n" % ( config.Hostname, config.Domain )
        l = open('/etc/mailname', 'wt')
        l.write(mailname)
        l.close()
Example #9
0
File: DHCP.py Project: calston/tums
    def writeConfig(self, *a):
        lans = Utils.getLanNetworks(config)
        extramain = config.DHCP.get('main','')
        
        ips = Utils.getLanIPs(config)
        myIp = ips[0]
        rev = '.'.join([i for i in reversed(myIp.split('.')[:3])])

        ifaces = []
        
        dhcpconf = """# DHCPD config generated by TUMS Configurator
ddns-update-style interim;
default-lease-time 21600;
max-lease-time 21600;
allow booting;
allow bootp;
authoritative;
log-facility local7;

zone %(domain)s. {
    primary 127.0.0.1;
}

zone %(rev)s.in-addr.arpa. {
    primary 127.0.0.1;
}

option local-pac-server code 252 = text;

%(extramain)s
"""     % {
            'extramain': extramain, 
            'domain': config.Domain,
            'rev': rev
        }
        
        n = 0 
        for k,v in lans.items():
            myNet = v
            myIp = config.EthernetDevices[k].get('ip', '/').split('/')[0]
            
            dhcpConf = config.DHCP.get(k, {})
            
            if not myIp:
                # No IP set for this interface (is DHCP itself)
                continue 
            if not config.EthernetDevices[k].get('dhcpserver'):
                # Not set to do DHCP
                continue
            
            ifaces.append(k)

            statics = ""
            
            for ip, hostmac in config.DHCP.get('leases',{}).items():
                if Utils.matchIP(myNet, ip):
                    # make sure the IP is in this network
                    host, mac = hostmac
                    statics += """    host %s {
            fixed-address %s;
            hardware ethernet %s;
        }\n""" % (host, ip, mac)
            
            myNetmask = Utils.cidr2netmask(myNet.split('/')[1])
            
            rangeStart  = dhcpConf.get('rangeStart', "100")
            rangeEnd    = dhcpConf.get('rangeEnd', "240")

            netmask     = dhcpConf.get('netmask', myNetmask)
            netbios     = dhcpConf.get('netbios', myIp)
            nameserver  = dhcpConf.get('nameserver', myIp)
            router      = dhcpConf.get('gateway', myIp)
            myNet       = dhcpConf.get('network', Utils.getNetwork(config.EthernetDevices[k]['ip']))
            domain      = dhcpConf.get('domain', config.Domain)
            if not '/' in myNet:
                # AAAAAAAAAAAARGH GOD DAMN DIE IN HELL PAUL VIXIE
                cdr = Utils.netmask2cidr(netmask)
                myNet = "%s/%s" % (myNet, cdr)
                bcast       = Utils.getBroadcast(myNet)
            else:
                bcast = Utils.getBroadcast(myNet)
            
            # allow custom configuration options
            custom = dhcpConf.get('custom', '')
            
            netL = '.'.join(myNet.split('.')[:3])

            if not ("." in rangeStart):
                rangeStart = "%s.%s" % (netL, rangeStart)
                rangeEnd = "%s.%s" % (netL, rangeEnd)

            defn = {
                'netname': 'DHCP%s' % k.upper(),
                'myIp': myIp,
                'pacIp': myIp.replace('.', '-'),
                'domain': domain,
                'network': netL,
                'networkF': myNet.split('/')[0],
                'static': statics,
                'custom': custom,
                'netmask': netmask,
                'rangeStart': rangeStart,
                'rangeEnd': rangeEnd,
                'myNetbios': netbios,
                'myDns': nameserver,
                'myRouter': router,
                'extramain': extramain,
                'bcast': bcast
            }
            
            dhcpnet = """
shared-network %(netname)s {
    use-host-decl-names           on;
    option domain-name            "%(domain)s";
    option domain-name-servers    %(myDns)s;
    
    option netbios-name-servers   %(myNetbios)s;
    option netbios-node-type      8;

    option local-pac-server "http://%(myIp)s/wpad-%(pacIp)s.pac"; 

    option ntp-servers            %(myIp)s;
    option time-servers           %(myIp)s;
    option log-servers            %(myIp)s;
    option font-servers           %(myIp)s;
    option pop-server             %(myIp)s;
    option smtp-server            %(myIp)s;
    option x-display-manager      %(myIp)s;
    
    subnet %(networkF)s netmask %(netmask)s {
        range dynamic-bootp           %(rangeStart)s %(rangeEnd)s;
        option subnet-mask            %(netmask)s;
        option broadcast-address      %(bcast)s;
        option routers                %(myRouter)s;
    }
%(static)s
%(custom)s
}\n"""      % defn
            
            dhcpconf += dhcpnet
        
        # Check for debianism (goes in /etc/dhcp3)
        f = open('/etc/dhcp3/dhcpd.conf', 'wt')
        f.write(dhcpconf)
        f.close()

        f = open('/etc/default/dhcp3-server', 'wt')
        f.write('# On what interfaces should the DHCP server (dhcpd) serve DHCP requests?\n')
        f.write('#       Separate multiple interfaces with spaces, e.g. "eth0 eth1".\n')
        f.write('INTERFACES="%s"\n' % ' '.join(ifaces))
        f.close()