Discussion:
dnsrbl.c
Nikola Vladov
2010-08-19 09:55:29 UTC
Permalink
I wrote next for me. I use ir to test if IP(s) is in RBL list.
Maybe it is useful for some people

Enjoy, Nikola


-------------------------------------------------------
/* dnsrbl.c
save 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 "dns.h"
#include "fmt.h"
#include "scan.h"
#include "byte.h"
#include "openreadclose.h"
#include "buffer.h"
#include <alloca.h>

extern int close(int);
extern void _exit(int);

#ifndef USE_LIBOWFAT
#include "strerr.h"
#include "env.h"
char buf_1sp[128];
buffer buf_rbl = BUFFER_INIT(buffer_unixwrite,1,buf_1sp,sizeof(buf_1sp));
#define buffer_rbl_1 &buf_rbl

#else
#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
#define buffer_rbl_1 buffer_1small
#endif

#define B_p(s,l) buffer_put(buffer_rbl_1, s, l)
#define B_ps(st) buffer_puts(buffer_rbl_1, st)
#define B_f buffer_flush(buffer_rbl_1)

#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 Xfor(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, srv) { char *z = t->ip;\
z[0]=A; z[1]=B; z[2]=C; z[3]=D; }\
t->rbl = *srv

struct line {
char *rbl; /* if (rbl) -> active */
iopause_fd *io;
struct dns_transmit d;
char ip[4];
} *xxx;

static iopause_fd *io;
static stralloc fqdn, sa, out;
static char txt_ip[20];

static int exit_status, flagdebug, resolv_conf, io_flush;
static unsigned int numactive, left;
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 int b[8]) {
unsigned int k, n;
unsigned long u;
char *x = s;
for (n=0;; n++) {
k = scan_ulong(x, &u); x += k; u %= 256; b[0] = u; if (k==0) return 0;
if (*x == '-') { k = scan_ulong(++x, &u); x += k; if (k==0) u = 255; }
b[4] = u % 256;
if (b[0] > b[4]) return 0;
++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(out.s, out.len);
B_ps("\n");
B_f;
exit_status |= 1;
}

void io_loop() {
while ((io_flush && numactive) || numactive >= maxactive) {
struct taia stamp, deadline;
unsigned int kactive, i, k;

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->rbl) {
t->io = io + k++;
dns_transmit_io(&t->d, t->io, &deadline);
}
}
iopause(io,k,&deadline,&stamp);

for (i=0, k=0, kactive=numactive; k < kactive; ++i) {
set_t(i);
if (t->rbl) {
int r = dns_transmit_get(&t->d, t->io, &stamp);
++k;
if (r == 0) continue;

if (r == -1) got_err(t);
else {
if (dns_txt_packet(&out,t->d.packet,t->d.packetlen) ==-1) got_err(t);
if (flagdebug > 1 || out.len) got_rbl(t);
}

--numactive;
t->rbl = 0;
if (i < left) left = i;
}
}
}
}

void nomem() { strerr_die2x(111,FATAL,"out of memory"); }

int main(int argc,char **argv) {
int flaglist=0;
char *buf=0, *rbl=0, *Q=0;
char **rblservers, **p, **q;
char split_char = '\n', base[] = RBLSERVERS;
unsigned int len, A,B,C,D, ip_buf[8];

char servers[16 * sizeof(xxx->d.localip)];
static char localip[sizeof(xxx->d.localip)];

close(0); ++argv; (void)argc;

while (*argv && **argv == '-') {
char *opt, *z=argv[0]+1;
for (; *z; z++) {
switch (*z) {
case 'l': flaglist++; break;
case 'v': flagdebug++; break;
case 'f':
case 'c':
opt = z++;
if (*z == 0) {
z = *++argv;
if (z == 0)
strerr_die3x(100, "Option -",opt," requires an argument");
}

if (*opt == 'f') rbl = z;
else {
unsigned long u;
scan_ulong(z,&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;

len = splitmem(0, buf, split_char);
rblservers = alloca((len+2) * sizeof(char *));
splitmem(rblservers, buf, split_char);

for (q=rblservers, p=rblservers; *p; p++)
if ((unsigned char)((**p | 32) - 'a') < 26) *q++ = *p;
*q=0;

if (flaglist) {
for (p=rblservers; *p; B_ps("\n"), p++)
B_ps(*p);
B_f;
_exit(0);
}

if (!stralloc_ready(&fqdn,40)) nomem();
io = alloca(maxactive * sizeof(iopause_fd));

len = maxactive * sizeof(struct line);
xxx = alloca(len);
byte_zero(xxx, len);

while (*argv) {
if (!scan_rbl(*argv, ip_buf)) {
++io_flush;
io_loop();
strerr_die3x(111,FATAL,"unable to parse IP address ",*argv);
}

Xfor(A,0) Xfor(B,1) Xfor(C,2) Xfor(D,3) for (p=rblservers; *p; p++) {
for (;; left++) {
set_t(left);
if (t->rbl == 0) {
set_ip(zzz, t, p);

fqdn.len = fmt_rbl(fqdn.s, t->ip, 1);
fqdn.s[fqdn.len++] = '.';
if (!stralloc_cats(&fqdn, t->rbl)) nomem();

if (resolv_conf==0) {
resolv_conf = 1024;
if (dns_resolvconfip(servers) == -1)
strerr_die2sys(111,FATAL,"unable to read /etc/resolv.conf: ");
} else resolv_conf--;

if (dns_domain_fromdot(&Q, fqdn.s, fqdn.len) == 0 ||
dns_transmit_start(&t->d,servers,1,Q,DNS_T_TXT,localip) == -1) {
got_err(t);
t->rbl = 0;
} else {
++numactive;
io_loop();
}

break;
}
}
}
++argv;
if (*argv == 0) { ++io_flush; io_loop(); }
}
_exit(exit_status);
}


#if 0
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. Test it with:
dnsrbl -l -fRBL_File

The manual page is missing currently...
Version: Sat Aug 19 07:40:02 UTC 2010
#endif

Loading...