From: Florent Bruneau Date: Sun, 5 Oct 2008 13:22:54 +0000 (+0200) Subject: Merge branch 'master' into with-dns-bl X-Git-Url: http://git.madism.org/?p=apps%2Fpfixtools.git;a=commitdiff_plain;h=f47b916bf7581b0070431eb70f43710e4c79fc98;hp=91da9fe6f37e6a82b226622e1a3e90ee85a9a138 Merge branch 'master' into with-dns-bl Conflicts: postlicyd/iplist.c postlicyd/tst-rbl.c Signed-off-by: Florent Bruneau --- diff --git a/common/Makefile b/common/Makefile index be9d473..3f30e73 100644 --- a/common/Makefile +++ b/common/Makefile @@ -35,4 +35,6 @@ TESTS = tst-trie lib_SOURCES = str.c buffer.c common.c epoll.c server.c trie.c file.c rbl.c tst-trie_SOURCES = tst-trie.c lib.a +all: + include ../mk/common.mk diff --git a/common/array.h b/common/array.h index cd0090a..6f5217d 100644 --- a/common/array.h +++ b/common/array.h @@ -178,6 +178,7 @@ ARRAY(char) ARRAY(int) ARRAY(bool) +ARRAY(uint16_t) ARRAY(uint32_t) PARRAY(void) diff --git a/common/common.c b/common/common.c index af95efa..3d2862f 100644 --- a/common/common.c +++ b/common/common.c @@ -52,7 +52,7 @@ static FILE *pidfile = NULL; void common_sighandler(int sig) { switch (sig) { - case SIGTERM: + case SIGTERM: case SIGINT: sigint = true; return; @@ -62,7 +62,7 @@ void common_sighandler(int sig) return; default: - err("Killed (got signal %d)...", sig); + err("Killed (got signal %d)...", sig); exit(-1); } } @@ -199,11 +199,11 @@ int daemon_detach(void) pid = fork(); if (pid < 0) { return -1; - } + } if (pid) { - daemon_process = false; + daemon_process = false; exit(0); - } + } setsid(); return 0; @@ -236,20 +236,11 @@ int drop_privileges(const char *user, const char *group) int pidfile_open(const char *name) { - struct flock lock; - p_clear(&lock, 1); - lock.l_type = F_WRLCK; if (name) { pidfile = fopen(name, "w"); if (!pidfile) return -1; - if (fcntl(fileno(pidfile), F_SETLK, &lock) == -1) { - crit("program already started"); - fclose(pidfile); - pidfile = NULL; - return -1; - } - fprintf(pidfile, "%d\n", getpid()); + fprintf(pidfile, "%d\n", getpid()); return fflush(pidfile); } return 0; @@ -268,14 +259,12 @@ int pidfile_refresh(void) static void pidfile_close(void) { - struct flock lock; - p_clear(&lock, 1); - lock.l_type = F_UNLCK; if (pidfile) { - rewind(pidfile); - ftruncate(fileno(pidfile), 0); - fcntl(fileno(pidfile), F_SETLK, &lock); - fclose(pidfile); + if (daemon_process) { + rewind(pidfile); + ftruncate(fileno(pidfile), 0); + } + fclose(pidfile); pidfile = NULL; } } @@ -283,6 +272,11 @@ static void pidfile_close(void) int common_setup(const char* pidfilename, bool unsafe, const char* runas_user, const char* runas_group, bool daemonize) { + if (pidfile_open(pidfilename) < 0) { + crit("unable to write pidfile %s", pidfilename); + return EXIT_FAILURE; + } + if (!unsafe && drop_privileges(runas_user, runas_group) < 0) { crit("unable to drop privileges"); return EXIT_FAILURE; @@ -293,11 +287,6 @@ int common_setup(const char* pidfilename, bool unsafe, const char* runas_user, return EXIT_FAILURE; } - if (pidfile_open(pidfilename) < 0) { - crit("unable to write pidfile %s", pidfilename); - return EXIT_FAILURE; - } - pidfile_refresh(); return EXIT_SUCCESS; } @@ -307,10 +296,10 @@ extern exitcall_t __madexit[]; static void common_shutdown(void) { - if (daemon_process) { - info("stopping..."); - } - pidfile_close(); + if (daemon_process) { + info("stopping..."); + } + pidfile_close(); for (int i = -1; __madexit[i]; i--) { (*__madexit[i])(); } diff --git a/common/tst-trie.c b/common/tst-trie.c index c9e16dc..9f69b1e 100644 --- a/common/tst-trie.c +++ b/common/tst-trie.c @@ -128,7 +128,7 @@ int main(int argc, char *argv[]) */ if (argc > 1) { trie = create_trie_from_file(argv[1]); - trie_inspect(trie, true); + trie_inspect(trie, false); trie_delete(&trie); } return 0; diff --git a/example/postlicyd.conf b/example/postlicyd.conf index 123c66a..12d8ff5 100644 --- a/example/postlicyd.conf +++ b/example/postlicyd.conf @@ -70,6 +70,8 @@ # declare a file to load. If lock is given, the klist is locked into the # RAM. The weight is a number giving the weight of this blaclist file in the # score of the IP +# - rbldns: (no)?lock:weight:filename +# this is an alias for file. # - soft_threshold: score (default: 1) # minimum score to match the soft_match return value # - hard_threshold: score (default: 1) @@ -117,6 +119,12 @@ spamhaus_and_abuseat { # * a file that contains "postmaster@" in "partial-prefix" mode will match all # postmaster emails. # * a file open without "partial-" modifier match exact strings. +# - rbldns: (no)?lock:weight:filename +# declare a rbldns zone file to load. This is exactly the same as file excepted that it wraps +# parsing of hostname to split them into 2 categories: +# * names beginning with '*' are sorted as 'domains' and are matched as suffix +# * names starting with an alphanumirical character are sorted as 'hostnames' and are +# process via exact matching. # - soft_threshold: score (default: 1) # minimum score to match the soft_match return value # - hard_threshold: score (default: 1) @@ -149,7 +157,8 @@ client_whitelist { # configuration file = lock:1:suffix:/var/spool/postlicyd/client_whitelist; - fields = client_name; + rbldns = lock:1:/va/spool/postlicyd/abuse.rfc-ignorant.org; + fields = client_name,sender_domain,helo_name; # hooks on_hard_match = postfix:OK; diff --git a/pfix-srsd/Makefile b/pfix-srsd/Makefile index 65f3f36..0be9e82 100644 --- a/pfix-srsd/Makefile +++ b/pfix-srsd/Makefile @@ -34,4 +34,6 @@ PROGRAMS = pfix-srsd pfix-srsd_SOURCES = main-srsd.c ../common/lib.a pfix-srsd_LIBADD = -lsrs2 +all: + include ../mk/common.mk diff --git a/postlicyd/Makefile b/postlicyd/Makefile index 84dec14..0983841 100644 --- a/postlicyd/Makefile +++ b/postlicyd/Makefile @@ -36,18 +36,20 @@ GENERATED = policy_tokens.h policy_tokens.c \ filter_tokens.h filter_tokens.c \ hook_tokens.h hook_tokens.c \ param_tokens.h param_tokens.c -TESTS = test-rbl tst-filters +TESTS = tst-rbl tst-filters FILTERS = iplist.c greylist.c strlist.c match.c postlicyd_SOURCES = main-postlicyd.c ../common/lib.a filter.c config.c query.c $(FILTERS) $(GENERATED) postlicyd_LIBADD = $(TC_LIBS) -tst-rbl_SOURCES = tst-rbl.c +tst-rbl_SOURCES = tst-rbl.c ../common/lib.a filter.c config.c query.c iplist.c $(GENERATED) tst-filters_SOURCES = tst-filters.c ../common/lib.a config.c filter.c query.c $(FILTERS) $(GENERATED) tst-filters_LIBADD = $(TC_LIBS) hook_tokens.h hook_tokens.c: $(FILTERS) param_tokens.c param_tokens.h: $(FILTERS) config.c +all: + include ../mk/common.mk diff --git a/postlicyd/iplist.c b/postlicyd/iplist.c index 256c360..3c14fda 100644 --- a/postlicyd/iplist.c +++ b/postlicyd/iplist.c @@ -62,7 +62,7 @@ enum { }; struct rbldb_t { - A(uint32_t) ips; + A(uint16_t) ips[1 << 16]; }; ARRAY(rbldb_t) @@ -123,6 +123,7 @@ rbldb_t *rbldb_create(const char *file, bool lock) rbldb_t *db; file_map_t map; const char *p, *end; + uint32_t ips = 0; if (!file_map_open(&map, file, false)) { return NULL; @@ -148,33 +149,37 @@ rbldb_t *rbldb_create(const char *file, bool lock) if (parse_ipv4(p, &p, &ip) < 0) { p = (char *)memchr(p, '\n', end - p) + 1; } else { - array_add(db->ips, ip); + array_add(db->ips[ip >> 16], ip & 0xffff); + ++ips; } } file_map_close(&map); /* Lookup may perform serveral I/O, so avoid swap. */ - array_adjust(db->ips); - if (lock && !array_lock(db->ips)) { - UNIXERR("mlock"); - } - - if (db->ips.len) { -# define QSORT_TYPE uint32_t -# define QSORT_BASE db->ips.data -# define QSORT_NELT db->ips.len + for (int i = 0 ; i < 1 << 16 ; ++i) { + array_adjust(db->ips[i]); + if (lock && !array_lock(db->ips[i])) { + UNIXERR("mlock"); + } + if (db->ips[i].len) { +# define QSORT_TYPE uint16_t +# define QSORT_BASE db->ips[i].data +# define QSORT_NELT db->ips[i].len # define QSORT_LT(a,b) *a < *b # include "qsort.c" + } } - info("rbl %s loaded, %d IPs", file, db->ips.len); + info("rbl %s loaded, %d IPs", file, ips); return db; } static void rbldb_wipe(rbldb_t *db) { - array_wipe(db->ips); + for (int i = 0 ; i < 1 << 16 ; ++i) { + array_wipe(db->ips[i]); + } } void rbldb_delete(rbldb_t **db) @@ -187,20 +192,26 @@ void rbldb_delete(rbldb_t **db) uint32_t rbldb_stats(const rbldb_t *rbl) { - return rbl->ips.len; + uint32_t ips = 0; + for (int i = 0 ; i < 1 << 16 ; ++i) { + ips += array_len(rbl->ips[i]); + } + return ips; } bool rbldb_ipv4_lookup(const rbldb_t *db, uint32_t ip) { - int l = 0, r = db->ips.len; + const uint16_t hip = ip >> 16; + const uint16_t lip = ip & 0xffff; + int l = 0, r = db->ips[hip].len; while (l < r) { int i = (r + l) / 2; - if (array_elt(db->ips, i) == ip) + if (array_elt(db->ips[hip], i) == lip) return true; - if (ip < array_elt(db->ips, i)) { + if (lip < array_elt(db->ips[hip], i)) { r = i; } else { l = i + 1; @@ -268,7 +279,7 @@ static bool rbl_filter_constructor(filter_t *filter) * the file pointed by filename MUST be a valid ip list issued from * the rsync (or equivalent) service of a (r)bl. */ - case ATK_FILE: { + case ATK_FILE: case ATK_RBLDNS: { bool lock = false; int weight = 0; rbldb_t *rbl = NULL; @@ -314,11 +325,11 @@ static bool rbl_filter_constructor(filter_t *filter) } } break; - /* host parameter. + /* dns parameter. * weight:hostname. * define a RBL to use through DNS resolution. */ - case ATK_HOST: { + case ATK_DNS: { int weight = 0; const char *current = param->value; const char *p = m_strchrnul(param->value, ':'); @@ -451,7 +462,8 @@ static int rbl_init(void) /* Parameters. */ (void)filter_param_register(type, "file"); - (void)filter_param_register(type, "host"); + (void)filter_param_register(type, "rbldns"); + (void)filter_param_register(type, "dns"); (void)filter_param_register(type, "hard_threshold"); (void)filter_param_register(type, "soft_threshold"); return 0; diff --git a/postlicyd/main-postlicyd.c b/postlicyd/main-postlicyd.c index 1f286eb..9ff1bc5 100644 --- a/postlicyd/main-postlicyd.c +++ b/postlicyd/main-postlicyd.c @@ -204,6 +204,11 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } + if (pidfile_open(pidfile) < 0) { + crit("unable to write pidfile %s", pidfile); + return EXIT_FAILURE; + } + if (drop_privileges(RUNAS_USER, RUNAS_GROUP) < 0) { crit("unable to drop privileges"); return EXIT_FAILURE; @@ -217,8 +222,14 @@ int main(int argc, char *argv[]) config->port = port; } - if (common_setup(pidfile, true, NULL, NULL, daemonize) != EXIT_SUCCESS - || start_listener(config->port) < 0) { + if (daemonize && daemon_detach() < 0) { + crit("unable to fork"); + return EXIT_FAILURE; + } + + pidfile_refresh(); + + if (start_listener(config->port) < 0) { return EXIT_FAILURE; } else { return server_loop(query_starter, (delete_client_t)query_delete, diff --git a/postlicyd/strlist.c b/postlicyd/strlist.c index 19fd0b2..c2704f1 100644 --- a/postlicyd/strlist.c +++ b/postlicyd/strlist.c @@ -148,6 +148,86 @@ static trie_t *strlist_create(const char *file, bool reverse, bool lock) return db; } +static bool strlist_create_from_rhbl(const char *file, bool lock, + trie_t **phosts, trie_t **pdomains) +{ + trie_t *hosts, *domains; + uint32_t host_count, domain_count; + file_map_t map; + const char *p, *end; + char line[BUFSIZ]; + + if (!file_map_open(&map, file, false)) { + return false; + } + p = map.map; + end = map.end; + while (end > p && end[-1] != '\n') { + --end; + } + if (end != map.end) { + warn("file %s miss a final \\n, ignoring last line", + file); + } + + hosts = trie_new(); + host_count = 0; + domains = trie_new(); + domain_count = 0; + while (p < end && p != NULL) { + const char *eol = (char *)memchr(p, '\n', end - p); + if (eol == NULL) { + eol = end; + } + if (eol - p >= BUFSIZ) { + err("unreasonnable long line"); + file_map_close(&map); + trie_delete(&hosts); + trie_delete(&domains); + return false; + } + if (*p != '#') { + const char *eos = eol; + while (p < eos && isspace(*p)) { + ++p; + } + while (p < eos && isspace(eos[-1])) { + --eos; + } + if (p < eos) { + if (isalnum(*p)) { + strlist_copy(line, p, eos - p, true); + trie_insert(hosts, line); + ++host_count; + } else if (*p == '*') { + ++p; + strlist_copy(line, p, eos - p, true); + trie_insert(domains, line); + ++domain_count; + } + } + } + p = eol + 1; + } + file_map_close(&map); + if (host_count > 0) { + trie_compile(hosts, lock); + *phosts = hosts; + } else { + trie_delete(&hosts); + *phosts = NULL; + } + if (domain_count > 0) { + trie_compile(domains, lock); + *pdomains = domains; + } else { + trie_delete(&domains); + *pdomains = NULL; + } + return hosts != NULL || domains != NULL; + +} + static bool strlist_filter_constructor(filter_t *filter) { @@ -165,7 +245,7 @@ static bool strlist_filter_constructor(filter_t *filter) foreach (filter_param_t *param, filter->params) { switch (param->type) { /* file parameter is: - * [no]lock:(prefix|suffix):weight:filename + * [no]lock:(partial-)(prefix|suffix):weight:filename * valid options are: * - lock: memlock the database in memory. * - nolock: don't memlock the database in memory. @@ -241,6 +321,72 @@ static bool strlist_filter_constructor(filter_t *filter) } } break; + /* rbldns parameter is: + * [no]lock::weight:filename + * valid options are: + * - lock: memlock the database in memory. + * - nolock: don't memlock the database in memory. + * - \d+: a number describing the weight to give to the match + * the given list [mandatory] + * directly import a file issued from a rhbl in rbldns format. + */ + case ATK_RBLDNS: { + bool lock = false; + int weight = 0; + trie_t *trie_hosts = NULL; + trie_t *trie_domains = NULL; + const char *current = param->value; + const char *p = m_strchrnul(param->value, ':'); + char *next = NULL; + for (int i = 0 ; i < 3 ; ++i) { + PARSE_CHECK(i == 2 || *p, + "file parameter must contains a locking state " + "and a weight option"); + switch (i) { + case 0: + if ((p - current) == 4 && strncmp(current, "lock", 4) == 0) { + lock = true; + } else if ((p - current) == 6 && strncmp(current, "nolock", 6) == 0) { + lock = false; + } else { + PARSE_CHECK(false, "illegal locking state %.*s", + p - current, current); + } + break; + + case 1: + weight = strtol(current, &next, 10); + PARSE_CHECK(next == p && weight >= 0 && weight <= 1024, + "illegal weight value %.*s", + (p - current), current); + break; + + case 2: + PARSE_CHECK(strlist_create_from_rhbl(current, lock, + &trie_hosts, &trie_domains), + "cannot load string list from rhbl %s", current); + if (trie_hosts != NULL) { + array_add(config->tries, trie_hosts); + array_add(config->weights, weight); + array_add(config->reverses, true); + array_add(config->partiales, false); + } + if (trie_domains != NULL) { + array_add(config->tries, trie_domains); + array_add(config->weights, weight); + array_add(config->reverses, true); + array_add(config->partiales, true); + } + config->is_hostname = true; + break; + } + if (i != 2) { + current = p + 1; + p = m_strchrnul(current, ':'); + } + } + } break; + /* hard_threshold parameter is an integer. * If the matching score is greater or equal than this threshold, * the hook "hard_match" is called. @@ -383,6 +529,7 @@ static int strlist_init(void) /* Parameters. */ (void)filter_param_register(type, "file"); + (void)filter_param_register(type, "rbldns"); (void)filter_param_register(type, "hard_threshold"); (void)filter_param_register(type, "soft_threshold"); (void)filter_param_register(type, "fields"); diff --git a/postlicyd/tst-rbl.c b/postlicyd/tst-rbl.c index 057018f..9cafae1 100644 --- a/postlicyd/tst-rbl.c +++ b/postlicyd/tst-rbl.c @@ -38,14 +38,21 @@ __FILE__, __LINE__, __func__, ##__VA_ARGS__) #include "common.h" -#include "iplist.c" +#include "iplist.h" +#include "array.h" int main(int argc, char *argv[]) { if (argc > 1) { rbldb_t *db = rbldb_create(argv[1], false); printf("loaded: %s, %d ips, %d o\n", argv[1], rbldb_stats(db), - rbldb_stats(db) * 4); + rbldb_stats(db) * 1 + 65536 * sizeof(A(uint16_t))); + + time_t now = time(NULL); + for (uint32_t i = 0 ; i < 1000000000 ; ++i) { + rbldb_ipv4_lookup(db, (88 << 24) | (170 << 16) | (239 << 8) | (132)); + } + printf("%ld request per second\n", 1000000000 / (time(NULL) - now)); rbldb_delete(&db); } return 0; diff --git a/tools/postgrey2postlicyd b/tools/postgrey2postlicyd new file mode 100755 index 0000000..2c50b74 --- /dev/null +++ b/tools/postgrey2postlicyd @@ -0,0 +1,112 @@ +#!/usr/bin/env python +############################################################################## +# pfixtools: a collection of postfix related tools # +# ~~~~~~~~~ # +# ________________________________________________________________________ # +# # +# Redistribution and use in source and binary forms, with or without # +# modification, are permitted provided that the following conditions # +# are met: # +# # +# 1. Redistributions of source code must retain the above copyright # +# notice, this list of conditions and the following disclaimer. # +# 2. Redistributions in binary form must reproduce the above copyright # +# notice, this list of conditions and the following disclaimer in the # +# documentation and/or other materials provided with the distribution. # +# 3. The names of its contributors may not be used to endorse or promote # +# products derived from this software without specific prior written # +# permission. # +# # +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND # +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR # +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS # +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF # +# THE POSSIBILITY OF SUCH DAMAGE. # +############################################################################## + +# Copyright (c) 2008 Aymeric Augustin + + +# Convert the postgrey_whitelist_clients file to a format +# suitable for use with the postlicyd Postfix policy daemon + + +import os, re, sys + +def process(infile, outfile): + + # Write headers + file.write("# Do not edit, file autogenerated by %s\n" % sys.argv[0]) + if len(sys.argv) > 1 and sys.argv[1] != '-': + file.write("# This file has been generated from %s\n" % sys.argv[1]) + + re_domain_name = re.compile(r'[a-z0-9.\-]+\.[a-z]+') + re_ip_address = re.compile(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') + + # Store each entry to avoid duplicates + entries = [] + + for line in infile: + # Comments: keep them + if line == '\n' or line[0] == '#': + outfile.write(line) + # IP addresses: keep as is + elif re_ip_address.match(line): + outfile.write(line) + # Regexps: extract final constant part + elif line[0] == '/': + line = line.rstrip(r'$/').replace(r'\.', r'.') + host = re_domain_name.findall(line)[-1] + result = host + '\n' + if result not in entries: + entries.append(result) + outfile.write(result) + # Domain names: prepend a dot if the domain name contains only one dot + elif re_domain_name.match(line): + if line.count('.') < 2: + result = '.' + line + else: + result = line + if result not in entries: + entries.append(result) + outfile.write(result) + # Unrecognized: report on stderr and comment in output + else: + outfile.write('# IGNORED: ' + line) + sys.stderr.write("Couldn't process line: %s" % line) + + +if __name__ == '__main__': + + # Check number of arguments + if len(sys.argv) > 3: + print "Usage: %s [input] [output]" % sys.argv[0] + print "If input/output is omitted or -, stdin/stdout is used." + sys.exit(1) + + # Parse first argument + if len(sys.argv) > 1 and sys.argv[1] != '-': + infile = open(sys.argv[1], 'r') + else: + infile = sys.stdin + + # Parse second argument + if len(sys.argv) > 2 and sys.argv[2] != '-': + if sys.argv[1] == sys.argv[2]: + print "Source file and destination file are identical, aborting" + sys.exit(1) + if os.path.exists(sys.argv[2]): + print "Destination file %s already exists, aborting" % sys.argv[2] + sys.exit(1) + outfile = open(sys.argv[2], 'w') + else: + outfile = sys.stdout + + # Do the processing + process(infile, outfile) diff --git a/tools/rbldns2postlicyd b/tools/rbldns2postlicyd new file mode 100755 index 0000000..64966a0 --- /dev/null +++ b/tools/rbldns2postlicyd @@ -0,0 +1,63 @@ +#!/usr/bin/env python +############################################################################## +# pfixtools: a collection of postfix related tools # +# ~~~~~~~~~ # +# ________________________________________________________________________ # +# # +# Redistribution and use in source and binary forms, with or without # +# modification, are permitted provided that the following conditions # +# are met: # +# # +# 1. Redistributions of source code must retain the above copyright # +# notice, this list of conditions and the following disclaimer. # +# 2. Redistributions in binary form must reproduce the above copyright # +# notice, this list of conditions and the following disclaimer in the # +# documentation and/or other materials provided with the distribution. # +# 3. The names of its contributors may not be used to endorse or promote # +# products derived from this software without specific prior written # +# permission. # +# # +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND # +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR # +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS # +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF # +# THE POSSIBILITY OF SUCH DAMAGE. # +############################################################################## + +# Copyright (c) 2008 Florent Bruneau + +import os, re, sys + +def headers(file, source, type): + file.write("# Do not edit, file autogenerated by %s\n" % sys.argv[0]) + file.write("# This file has been generated from %s blacklist\n" % source) + file.write("# it contains %s matching rules for postlicyd\n" % type) + +def convert(rbl): + source = open(rbl, "r") + hosts = open("%s_hosts" % rbl, "w") + domains = open("%s_domains" % rbl, "w") + + headers(hosts, rbl, "hosts") + headers(domains, rbl, "domains") + + for line in source: + if line[0].isalnum(): + hosts.write(line); + elif line[0] == '*': + domains.write(line[1:]); + +if __name__ == '__main__': + if len(sys.argv) == 1: + print "Usage: %s [input] ..." % sys.argv[0] + sys.exit(1) + + map(convert, sys.argv[1:]) + +# vim:set syntax=python: