dnsrbl.c
Nikola Vladov <[email protected]> 31 Jul 2010 10:38:58 -0000
| Newsgroups | gmane.linux.lib.dietlibc |
|---|---|
| Message-ID | <[email protected]> |
This is a command line utility to test if an IP(s) is in RBL-srever list.
See the examples at the end of this message. Maybe I will post it
in djbdns mailing list. I expect first some comment here :)
It work asynchronous like dnsfilter. I use it te test if a network
send spam (tcpserver: allow, deny).
Enjoy, Nikola
/* dnsrbl.c
safe me under dnstxt.c in djbdns-1.05 and recompile.
then: mv dnstxt dnsrbl
or
diet -Os gcc -Wall -W -DUSE_LIBOWFAT -s -o dnsrbl dnsrbl.c -lowfat
author: Nikola Vladov
http://riemann.fmi.uni-sofia.bg/programs/
See some examples at the end of this file!
*/
#define MAX_RBL_CONNECTIONS 10
#define RBLSERVERS \
"sbl.spamhaus.org\n" \
"xbl.spamhaus.org\n" \
"zen.spamhaus.org\n" \
"dnsbl.njabl.org\n" \
"bl.spamcop.net\n" \
"cbl.abuseat.org\n" \
"spam.dnsbl.sorbs.net";
#include "buffer.h"
#ifndef USE_LIBOWFAT
#include "exit.h"
#include "strerr.h"
#include "env.h"
#else
#include <unistd.h>
#include "errmsg.h"
#define strerr_die3x(n,a,b,c) die(n,a,b,c)
#define strerr_die2x(n,a,b) die(n,a,b)
#define strerr_die1x(n,a) die(n,a)
#define strerr_die2sys(n,a,b) diesys(n,a)
#define strerr_die4sys(n,a,b,c,d) diesys(n,a,b,c)
#define strerr_warn6(a,b,c,d,e,f,E) carpsys(a,b,c,d,e);
#define env_get getenv
#endif
#include "dns.h"
#if defined(DNS_NAME6_DOMAIN) || defined(USE_LIBOWFAT)
static char servers[256], localip[16]; /* libowfat */
#else
static char servers[64], localip[4];
#endif
#include "fmt.h"
#include "scan.h"
#include "byte.h"
#include "openreadclose.h"
#include <alloca.h>
#define FATAL "dnsrbl: fatal: "
#define WARNING "dnsrbl: warning: "
#define MSG_HELP \
"usage: dnsrbl [options] ip.ad.dr.ess a[-b].c[-d].e[-f].g[-h] ...\n"\
"options: [-lv] [-fRBLfile] [-cNumber]\n"\
"environ: DNSCACHEIP, DNSRBLSERVERS"
#define B_p(s,l) buffer_put(buffer_1, s, l)
#define B_ps(st) buffer_puts(buffer_1, st)
#define B_f buffer_flush(buffer_1)
#define do_it(x,from) for (x=ip_buf[from]; x<=ip_buf[from+4]; x++)
#define set_t(i) struct line *t = xxx + i
#define set_ip(z, t) char *z = t->ip;\
z[0]=A; z[1]=B; z[2]=C; z[3]=D;\
t->rbl = *p
struct line {
char *rbl;
iopause_fd *io; /* if (io) -> active */
stralloc out;
struct dns_transmit dt;
char ip[4];
} *xxx;
static stralloc fqdn, sa;
static char *Q, txt_ip[20];
static int exit_status, flagdebug;
static unsigned int numactive, left, A,B,C,D;
unsigned int maxactive = MAX_RBL_CONNECTIONS;
unsigned int splitmem(char **v, char *s, char c) /*EXTRACT_INCL*/ {
if (v) {
char **w=v;
*w++=s;
for (;;) {
while (*s && *s!=c) s++;
if (*s==0) break;
*s=0;
*w++ = ++s;
}
*w=0;
return (w-v);
} else {
unsigned int n=1;
for (; *s; s++) if (*s==c) n++;
return n;
}
}
unsigned int scan_rbl(char *s, unsigned char *b) {
unsigned int k, n;
unsigned long u;
char *x = s;
for (n=0;; n++) {
k = scan_ulong(x, &u); x += k; b[0] = b[8] = u; if (k==0) return 0;
u = *b;
if (*x == '-') { k = scan_ulong(++x, &u); x += k; if (k==0) u = 255; }
if (u < *b) return 0;
b[4] = u;
++b;
if (n == 3) break;
if (*x != '.') return 0;
++x;
}
return x-s;
}
unsigned int fmt_rbl(char *s, char *b, int reverse) {
char *t=s;
int n;
for (n=0; n<4; n++) {
unsigned char c = (reverse) ? b[3-n] : b[n];
t += fmt_ulong(t, c);
if (n == 3) break;
*t++ = '.';
}
*t = 0;
return t-s;
}
void got_err(struct line *t) {
exit_status |= 2;
fmt_rbl(txt_ip, t->ip, 0);
strerr_warn6(WARNING,"unable to find TXT records for ",
txt_ip, "-", t->rbl,": ",&strerr_sys);
}
void got_rbl(struct line *t) {
fmt_rbl(txt_ip, t->ip, 0);
B_ps(txt_ip);
if (flagdebug) {
B_ps("-");
B_ps(t->rbl);
}
B_ps(":\t");
B_p(t->out.s, t->out.len);
B_ps("\n");
B_f;
exit_status |= 1;
}
void nomem() { strerr_die2x(111,FATAL,"out of memory"); }
int main(int argc,char **argv) {
int flaglist=0;
char *buf = 0, *rbl = 0;
char **rblservers, **p, **q;
char split_char = '\n';
char base[] = RBLSERVERS;
struct taia stamp;
struct taia deadline;
unsigned int i,k;
int r,got_last=0;
unsigned char ip_buf[8];
iopause_fd *io;
(void)argc;
while (*++argv && **argv == '-') {
char *z=argv[0]+1;
for (; *z; z++) {
unsigned long u;
switch (*z) {
case 'l': flaglist++; break;
case 'v': flagdebug++; break;
case 'f': rbl = z+1; goto next;
case 'c':
scan_ulong(z+1,&u);
if (u < 1) u = 1;
if (u > 1000) u = 1000;
maxactive = u;
goto next;
default:
strerr_die1x(100, MSG_HELP);
}
}
next:
argv++;
}
if (rbl == 0) {
buf = env_get("DNSRBLSERVERS");
if (buf) split_char = ':';
} else {
if (1 != openreadclose(rbl, &sa, 128))
strerr_die4sys(100,FATAL,"error reading ",rbl,": ");
if (!stralloc_0(&sa)) nomem();
buf = sa.s;
}
if (buf==0) buf = base;
i = splitmem(0, buf, split_char);
rblservers = alloca((i+2) * sizeof(char *));
splitmem(rblservers, buf, split_char);
for (q=rblservers, p=rblservers; *p; p++) {
unsigned char c = **p;
if (c >= 'a') c -= 32;
c -= 'A';
if (c <= 26) *q++ = *p;
}
*q=0;
if (flaglist) {
for (p=rblservers; *p; p++) {
B_ps(*p);
B_ps("\n");
}
B_f;
_exit(0);
}
if (!stralloc_ready(&fqdn,40)) nomem();
i = maxactive * sizeof(struct line);
xxx = alloca(i);
byte_zero(xxx,i);
io = alloca(maxactive * sizeof(iopause_fd));
while (*argv) {
if (!scan_rbl(*argv, ip_buf))
strerr_die3x(111,FATAL,"unable to parse IP address ",*argv);
do_it(A,0) do_it(B,1) do_it(C,2) do_it(D,3) for (p=rblservers; *p; p++) {
if (!got_last && numactive < maxactive) {
for (;;) {
set_t(left++);
if (t->io == 0) {
set_ip(zzz, t);
fqdn.len = fmt_rbl(fqdn.s, t->ip, 1);
fqdn.s[fqdn.len++] = '.';
if (!stralloc_cats(&fqdn, t->rbl)) nomem();
if (dns_resolvconfip(servers) == -1)
strerr_die2sys(111,FATAL,"unable to read /etc/resolv.conf: ");
if (!dns_domain_fromdot(&Q, fqdn.s, fqdn.len) ||
dns_transmit_start(&t->dt,servers,1,Q,DNS_T_TXT,localip) ==-1)
got_err(t);
else {
t->io += 1;
++numactive;
}
break;
}
}
}
again:
while ((got_last && numactive) || numactive >= maxactive) {
unsigned int kactive;
taia_now(&stamp);
taia_uint(&deadline,120);
taia_add(&deadline,&deadline,&stamp);
for (i=0, k=0; k<numactive; ++i) {
set_t(i);
if (t->io) {
t->io = io + k++;
dns_transmit_io(&t->dt, t->io, &deadline);
}
}
iopause(io,k,&deadline,&stamp);
for (i=0, k=0, kactive=numactive; k < kactive; ++i) {
set_t(i);
if (t->io) {
++k;
r = dns_transmit_get(&t->dt, t->io, &stamp);
if (r == 0) continue;
--numactive;
t->io = 0;
if (i < left) left = i;
if (r == -1) got_err(t);
else {
if (dns_txt_packet(&t->out, t->dt.packet,
t->dt.packetlen) == -1) got_err(t);
if (flagdebug > 1 || t->out.len) got_rbl(t);
}
}
}
}
}
if (numactive) { got_last=1; goto again; }
got_last=0;
argv++;
}
_exit(exit_status);
}
#if 0
Do not put spaces after options with arguments!
dnsrbl -h
dnsrbl 127.0.0.2
dnsrbl -v 127.0.0.2-30
dnsrbl -vv -c30 127.0.0.2-30
dnsrbl -c100 208.66.77.60-80
DNSCACHEIP=8.8.8.8 dnsrbl -c1 208.66.70-80.60-70
dnsrbl 20-.20.40.50
dnsrbl -l
dnsrbl -fSome_RBL_File 127.0.0.2
DNSRBLSERVERS=zen.spamhaus.org dnsrbl -c100 127.0.0.0-255
DNSCACHEIP=8.8.8.8 DNSRBLSERVERS=zen.spamhaus.org dnsrbl -c20 127.0.0.0-255
DNSRBLSERVERS=sbl.spamhaus.org:xbl.spamhaus.org dnsrbl -c20 127.0.0.1-12
Format of RBL_File (option -f)
Text lines. If the first letter of a line is different from [a-zA-Z]
this line is comment. Do not put spaces or tabs at the end of line.
Test it with:
dnsrbl -l -fRBL_File
The manual page is missing currently...
Version: Sat Jul 31 09:31:02 UTC 2010
#endif