On Tue, Mar 14, 2000 at 07:09:59PM +0300, Anand Buddhdev wrote: > On Tue, Mar 14, 2000 at 04:43:30PM +0100, Petr Novotny wrote: > > > > I would like to add the following to my tcp.smtp file for tcprules: > > > > > > .domain.com:allow,RELAYCLIENT="" > > > > > > My question is can you use domain names with tcprules, or does it have > > > to be IP addresses. In the man page all expamples use Ips and not > > > domains. > > > > It has to be IP address. > > With the new tcpserver v 0.86, you can use hostnames. See the > documentation. I have patched tcpserver 0.84 for domainnames and domain wildcards, attached patch is it. This might not be useful anymore since 0.86 now does do domainnames, but for those who do not want to upgrade for whatever reason, here it is. NOTE: this patch has only been tested very lightly, and one other guy looked at it but never tested it. No guarantees. Greetz, Peter. -- Peter van Dijk - student/sysadmin/ircoper/madly in love/pretending coder | | 'C makes it easy to shoot yourself in the foot; | C++ makes it harder, but when you do it blows your whole leg off.' | Bjarne Stroustrup, Inventor of C++
diff -ruN ucspi-tcp-0.84/Makefile ucspi-tcp-domrules/Makefile --- ucspi-tcp-0.84/Makefile Thu Nov 12 06:32:01 1998 +++ ucspi-tcp-domrules/Makefile Tue Dec 21 14:30:38 1999 @@ -397,6 +397,7 @@ man: \ tcpclient.0 tcpserver.0 tcprules.0 tcprulescheck.0 tcp-environ.0 \ +tcpdomrules.0 tcpdomrulescheck.0 \ [email protected] [email protected] [email protected] [email protected] tcpcat.0 mconnect.0 fixcr.0 addcr.0 \ delcr.0 argv0.0 recordio.0 error.0 error_str.0 alloc.0 case.0 cdb.0 \ env.0 fd_copy.0 fd_move.0 getln.0 getln2.0 sgetopt.0 subgetopt.0 \ @@ -448,6 +449,7 @@ prog: \ tcpclient tcpserver tcprules tcprulescheck who@ date@ finger@ http@ \ +tcpdomrules tcpdomrulescheck \ tcpcat mconnect mconnect-io fixcr addcr delcr argv0 recordio rts recordio: \ @@ -513,7 +515,9 @@ [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] tcpcat.1 \ tcpcat.sh mconnect.1 mconnect.sh mconnect-io.c delcr.1 delcr.c \ addcr.1 addcr.c fixcr.1 fixcr.c tcpserver.1 tcpserver.c tcprules.1 \ +tcpdomrules.1 \ tcprules.c tcprulescheck.1 tcprulescheck.c tcp-environ.5 recordio.1 \ +tcpdomrules.c tcpdomrulescheck.1 tcpdomrulescheck.c \ recordio.c argv0.1 argv0.c rts.sh rts.tests rts.exp conf-cc conf-ld \ find-systype.sh trycpp.c warn-auto.sh INSTALL hier.c conf-home \ auto-str.c auto_home.h install.c instcheck.c substdio.h substdio.c \ @@ -757,30 +761,62 @@ stralloc.a substdio.a alloc.a error.a open.a seek.a str.a \ fs.a +tcpdomrules: \ +load tcpdomrules.o cdbmss.o cdbmake.a getln.a strerr.a stralloc.a \ +substdio.a alloc.a error.a open.a seek.a str.a fs.a + ./load tcpdomrules cdbmss.o cdbmake.a getln.a strerr.a \ + stralloc.a substdio.a alloc.a error.a open.a seek.a str.a \ + fs.a + tcprules.0: \ tcprules.1 nroff -man tcprules.1 > tcprules.0 +tcpdomrules.0: \ +tcpdomrules.1 + nroff -man tcpdomrules.1 > tcpdomrules.0 + tcprules.o: \ compile tcprules.c strerr.h stralloc.h gen_alloc.h getln.h substdio.h \ subfd.h substdio.h exit.h fmt.h byte.h cdbmss.h cdbmake.h uint32.h \ substdio.h ./compile tcprules.c +tcpdomrules.o: \ +compile tcpdomrules.c strerr.h stralloc.h gen_alloc.h getln.h substdio.h \ +subfd.h substdio.h exit.h fmt.h byte.h cdbmss.h cdbmake.h uint32.h \ +substdio.h + ./compile tcpdomrules.c + tcprulescheck: \ load tcprulescheck.o cdb.a stralloc.a alloc.a strerr.a substdio.a \ error.a str.a open.a ./load tcprulescheck cdb.a stralloc.a alloc.a strerr.a \ substdio.a error.a str.a open.a +tcpdomrulescheck: \ +load tcpdomrulescheck.o cdb.a stralloc.a alloc.a strerr.a substdio.a \ +error.a str.a open.a + ./load tcpdomrulescheck cdb.a stralloc.a alloc.a strerr.a \ + substdio.a error.a str.a open.a + tcprulescheck.0: \ tcprulescheck.1 nroff -man tcprulescheck.1 > tcprulescheck.0 +tcpdomrulescheck.0: \ +tcpdomrulescheck.1 + nroff -man tcpdomrulescheck.1 > tcpdomrulescheck.0 + tcprulescheck.o: \ compile tcprulescheck.c substdio.h subfd.h substdio.h strerr.h \ stralloc.h gen_alloc.h alloc.h cdb.h uint32.h ./compile tcprulescheck.c + +tcpdomrulescheck.o: \ +compile tcpdomrulescheck.c substdio.h subfd.h substdio.h strerr.h \ +stralloc.h gen_alloc.h alloc.h cdb.h uint32.h + ./compile tcpdomrulescheck.c tcpserver: \ load tcpserver.o ip.o ipalloc.o dns.o remoteinfo.o timeoutconn.o \ diff -ruN ucspi-tcp-0.84/tcpdomrules.1 ucspi-tcp-domrules/tcpdomrules.1 --- ucspi-tcp-0.84/tcpdomrules.1 Thu Jan 1 01:00:00 1970 +++ ucspi-tcp-domrules/tcpdomrules.1 Tue Dec 21 14:26:44 1999 @@ -0,0 +1,208 @@ +.TH tcpdomrules 1 +.SH NAME +tcpdomrules \- compile domain rules for tcpserver +.SH SYNOPSIS +.B tcpdomrules +.I domrules.cdb +.I domrules.tmp +.SH OVERVIEW +.B tcpserver +optionally follows rules to decide whether a TCP connection is acceptable. +For example, a rule of + +.EX + .example.net:deny +.EE + +prohibits connections from hostnames ending in .example.net. + +.B tcpdomrules +reads rules from its standard input +and writes them into +.I domrules.cdb +in a binary format suited +for quick access by +.BR tcpserver . + +.B tcpdomrules +can be used while +.B tcpserver +is running: +it ensures that +.I domrules.cdb +is updated atomically. +It does this by first writing the rules to +.I domrules.tmp +and then moving +.I domrules.tmp +on top of +.IR domrules.cdb . +If +.I domrules.tmp +already exists, it is destroyed. +The directories containing +.I domrules.cdb +and +.I domrules.tmp +must be writable to +.BR tcpdomrules ; +they must also be on the same filesystem. + +If there is a problem with the input, +.B tcpdomrules +complains and leaves +.I domrules.cdb +alone. + +The binary +.I domrules.cdb +format is portable across machines. +.SH "DOMRULE FORMAT" +A rule takes up one line. +A file containing rules +may also contain comments: lines beginning with # are ignored. + +Each rule contains an +.BR address , +a colon, +and a list of +.BR instructions , +with no extra spaces. +When +.B tcpserver +receives a connection from that address, +it follows the instructions. +.SH "ADDRESSES" +.B tcpserver +starts by looking for a rule with address +.IR TCPREMOTEINFO\fB@\fITCPREMOTEHOST . +If it doesn't find one, or if +.I TCPREMOTEINFO +is not set, it tries the address +.IR TCPREMOTEHOST . +If that doesn't work, it tries shorter and shorter suffixes of +.I TCPREMOTEHOST +starting with a dot. +If none of them work, it tries the empty string. + +For example, here are some rules: + +.EX + [EMAIL PROTECTED]:first +.br + wuh.example.com:second +.br + .example.com:third +.br + :fourth +.EE + +If +.I TCPREMOTEHOST +is +.BR yo.example.org , +.B tcpserver +will follow the +.B fourth +instructions. + +If +.I TCPREMOTEHOST +is +.BR wuh.example.com , +.B tcpserver +will follow the +.B second +instructions. + +If +.I TCPREMOTEINFO +is +.B bill +and +.I TCPREMOTEHOST +is +.BR xxx.example.com , +.B tcpserver +will follow the +.B third +instructions. + +If +.I TCPREMOTEINFO +is +.B joe +and +.I TCPREMOTEHOST +is +.BR blah.example.com , +.B tcpserver +will follow the +.B first +instructions. +#.SH "ADDRESS RANGES" +#.B tcprules +#treats +#.B 1.2.3.37-53:ins +#as an abbreviation +#for the rules +#.BR 1.2.3.37:ins , +#.BR 1.2.3.38:ins , +#and so on up through +#.BR 1.2.3.53:ins . +#Similarly, +#.BR 10.2-3.:ins +#is an abbreviation for +#.B 10.2.:ins +#and +#.BR 10.3.:ins . +.SH "INSTRUCTIONS" +The instructions in a rule must begin with either +.B allow +or +.BR deny . +.B deny +tells +.B tcpserver +to drop the connection without running anything. +For example, the rule + +.EX + :deny +.EE + +tells +.B tcpserver +to drop all connections that aren't handled by more specific rules. + +The instructions may continue with some environment variables, +in the format +.IR ,VAR="VALUE" . +.B tcpserver +adds +.I VAR=VALUE +to the current environment. +For example, + +.EX + .nt.example.net:allow,RELAYCLIENT="@fix.me" +.EE + +adds +.B [EMAIL PROTECTED] +to the environment. +The quotes here may be replaced by any repeated character: + +.EX + .nt.example.net:allow,[EMAIL PROTECTED]/ +.EE + +Any number of variables may be listed: + +.EX + localhost:allow,RELAYCLIENT="",TCPLOCALHOST="movie.edu" +.EE +.SH "SEE ALSO" +tcpdomrulescheck(1), +tcpserver(1), +tcp-environ(5) diff -ruN ucspi-tcp-0.84/tcpdomrules.c ucspi-tcp-domrules/tcpdomrules.c --- ucspi-tcp-0.84/tcpdomrules.c Thu Jan 1 01:00:00 1970 +++ ucspi-tcp-domrules/tcpdomrules.c Tue Dec 21 14:26:44 1999 @@ -0,0 +1,179 @@ +#include "strerr.h" +#include "stralloc.h" +#include "getln.h" +#include "substdio.h" +#include "subfd.h" +#include "exit.h" +#include "fmt.h" +#include "byte.h" +#include "cdbmss.h" + +#define FATAL "tcpdomrules: fatal: " + +unsigned long linenum = 0; +char *fntemp; +char *fn; + +stralloc line = {0}; +int match = 1; + +stralloc address = {0}; +stralloc data = {0}; +stralloc key = {0}; + +struct cdbmss cdbmss; + +void die_nomem() { + strerr_die2x(111,FATAL,"out of memory"); +} +void usage() { + strerr_die1x(100,"tcpdomrules: usage: tcpdomrules domrules.cdb domrules.tmp"); +} +void die_bad() { + if (!stralloc_0(&line)) die_nomem(); + strerr_die3x(100,FATAL,"unable to parse this line: ",line.s); +} +void die_write() { + strerr_die4sys(111,FATAL,"unable to write to ",fntemp,": "); +} + +char strnum[FMT_ULONG]; +stralloc sanum = {0}; + +void getnum(buf,len,u) +char *buf; +int len; +unsigned long *u; +{ + if (!stralloc_copyb(&sanum,buf,len)) die_nomem(); + if (!stralloc_0(&sanum)) die_nomem(); + if (sanum.s[scan_ulong(sanum.s,u)]) die_bad(); +} + +void doaddressdata() +{ + int i; + int left; + int right; + unsigned long bot; + unsigned long top; + +#if 0 /* handling of IPranges, not interesting for domrules */ + if (byte_chr(address.s,address.len,'@') == address.len) { + i = byte_chr(address.s,address.len,'-'); + if (i < address.len) { + left = byte_rchr(address.s,i,'.'); + if (left == i) left = 0; else ++left; + + ++i; + right = i + byte_chr(address.s + i,address.len - i,'.'); + + getnum(address.s + left,i - 1 - left,&bot); + getnum(address.s + i,right - i,&top); + if (top > 255) top = 255; + + while (bot <= top) { + if (!stralloc_copyb(&key,address.s,left)) die_nomem(); + if (!stralloc_catb(&key,strnum,fmt_ulong(strnum,bot))) die_nomem(); + if (!stralloc_catb(&key,address.s + right,address.len - right)) die_nomem(); + if (cdbmss_add(&cdbmss,key.s,key.len,data.s,data.len) == -1) die_write(); + ++bot; + } + + return; + } + } +#endif /* 0 */ + + if (!stralloc_copy(&key,&address)) die_nomem(); + if (cdbmss_add(&cdbmss,key.s,key.len,data.s,data.len) == -1) die_write(); +} + +void main(argc,argv) +int argc; +char **argv; +{ + int colon; + char *x; + int len; + int fd; + int i; + char ch; + + fn = argv[1]; + if (!fn) usage(); + fntemp = argv[2]; + if (!fntemp) usage(); + + fd = open_trunc(fntemp); + if (fd == -1) + strerr_die4sys(111,FATAL,"unable to create ",fntemp,": "); + if (cdbmss_start(&cdbmss,fd) == -1) die_write(); + + while (match) { + if (getln(subfdin,&line,&match,'\n') == -1) + strerr_die2sys(111,FATAL,"unable to read input: "); + + x = line.s; len = line.len; + + if (!len) break; + if (x[0] == '#') continue; + if (x[0] == '\n') continue; + + while (len) { + ch = x[len - 1]; + if (ch != '\n') if (ch != ' ') if (ch != '\t') break; + --len; + } + line.len = len; /* for die_bad() */ + + colon = byte_chr(x,len,':'); + if (colon == len) continue; + + if (!stralloc_copyb(&address,x,colon)) die_nomem(); + if (!stralloc_copys(&data,"")) die_nomem(); + + x += colon + 1; len -= colon + 1; + + if ((len >= 4) && byte_equal(x,4,"deny")) { + if (!stralloc_catb(&data,"D",2)) die_nomem(); + x += 4; len -= 4; + } + else if ((len >= 5) && byte_equal(x,5,"allow")) { + x += 5; len -= 5; + } + else + die_bad(); + + while (len) + switch(*x) { + case ',': + i = byte_chr(x,len,'='); + if (i == len) die_bad(); + if (!stralloc_catb(&data,"+",1)) die_nomem(); + if (!stralloc_catb(&data,x + 1,i)) die_nomem(); + x += i + 1; len -= i + 1; + if (!len) die_bad(); + ch = *x; + x += 1; len -= 1; + i = byte_chr(x,len,ch); + if (i == len) die_bad(); + if (!stralloc_catb(&data,x,i)) die_nomem(); + if (!stralloc_0(&data)) die_nomem(); + x += i + 1; len -= i + 1; + break; + default: + die_bad(); + } + + doaddressdata(); + } + + if (cdbmss_finish(&cdbmss) == -1) die_write(); + if (fsync(fd) == -1) die_write(); + if (close(fd) == -1) die_write(); /* NFS stupidity */ + if (rename(fntemp,fn)) + strerr_die6sys(111,FATAL,"unable to move ",fntemp," to ",fn,": "); + + _exit(0); +} diff -ruN ucspi-tcp-0.84/tcpdomrulescheck.1 ucspi-tcp-domrules/tcpdomrulescheck.1 --- ucspi-tcp-0.84/tcpdomrulescheck.1 Thu Jan 1 01:00:00 1970 +++ ucspi-tcp-domrules/tcpdomrulescheck.1 Tue Dec 21 14:26:44 1999 @@ -0,0 +1,25 @@ +.TH tcpdomrulescheck 1 +.SH NAME +tcpdomrulescheck \- try out domrules for tcpserver +.SH SYNTAX +.B tcpdomrulescheck +.I domrules.cdb +.I tcpremotehost +[ +.I tcpremoteinfo +] +.SH DESCRIPTION +.B tcpdomrulescheck +says what +.B tcpserver +will do with a connection from +IP address +.IR tcpremotehost , +following the rules compiled into +.I domrules.cdb +by +.BR tcpdomrules . +.SH "SEE ALSO" +tcpdomrules(1), +tcpserver(1), +tcp-environ(5) diff -ruN ucspi-tcp-0.84/tcpdomrulescheck.c ucspi-tcp-domrules/tcpdomrulescheck.c --- ucspi-tcp-0.84/tcpdomrulescheck.c Thu Jan 1 01:00:00 1970 +++ ucspi-tcp-domrules/tcpdomrulescheck.c Tue Dec 21 15:20:18 1999 @@ -0,0 +1,105 @@ +#include "substdio.h" +#include "subfd.h" +#include "strerr.h" +#include "stralloc.h" +#include "alloc.h" +#include "cdb.h" + +#define FATAL "tcpdomrulescheck: fatal: " + +char *fndomrules; +int fddomrules; + +void die_usage() +{ + strerr_die1x(100,"tcpdomrulescheck: usage: tcpdomrulescheck domrules.cdb +tcpremotehost [ tcpremoteinfo ]"); +} +void die_read() +{ + strerr_die4sys(111,FATAL,"unable to read ",fndomrules,": "); +} +void nomem() +{ + strerr_die2x(111,FATAL,"out of memory"); +} + +static stralloc tmp = {0}; + +void dodomrule() +{ + char *data; + uint32 dlen32; + unsigned int datalen; + unsigned int next0; + + switch(cdb_seek(fddomrules,tmp.s,tmp.len,&dlen32)) { + case -1: die_read(); + case 0: return; + } + + datalen = dlen32; + data = alloc(datalen); + if (!data) nomem(); + if (cdb_bread(fddomrules,data,datalen) != 0) die_read(); + + substdio_puts(subfdout,"rule "); + substdio_put(subfdout,tmp.s,tmp.len); + substdio_puts(subfdout,":\n"); + while ((next0 = byte_chr(data,datalen,0)) < datalen) { + switch(data[0]) { + case 'D': + substdio_puts(subfdout,"deny connection\n"); + substdio_flush(subfdout); + _exit(0); /* XXX: could still set env vars for logs */ + case '+': + substdio_puts(subfdout,"set environment variable "); + substdio_puts(subfdout,data + 1); + substdio_puts(subfdout,"\n"); + break; + } + data += next0 + 1; datalen -= next0 + 1; + } + substdio_puts(subfdout,"allow connection\n"); + substdio_flush(subfdout); + _exit(0); +} + +void main(argc,argv) +int argc; +char **argv; +{ + char *tcpremotehost; + char *tcpremoteinfo; + + fndomrules = argv[1]; + if (!fndomrules) die_usage(); + + tcpremotehost = argv[2]; + if (!tcpremotehost) die_usage(); + + tcpremoteinfo = argv[3]; + + fddomrules = open_read(fndomrules); + if (fddomrules == -1) die_read(); + + if (tcpremoteinfo) { + if (!stralloc_copys(&tmp,tcpremoteinfo)) nomem(); + if (!stralloc_cats(&tmp,"@")) nomem(); + if (!stralloc_cats(&tmp,tcpremotehost)) nomem(); + dodomrule(); + } + + if (!stralloc_copys(&tmp,tcpremotehost)) nomem(); + dodomrule(); + while (tmp.len > 0) { + if (tmp.s[0] == '.') + dodomrule(); + --tmp.len; + byte_copy(tmp.s,tmp.len+1,tmp.s+1); + } + + dodomrule(); + + substdio_putsflush(subfdout,"default:\nallow connection\n"); + _exit(0); +} diff -ruN ucspi-tcp-0.84/tcpserver.c ucspi-tcp-domrules/tcpserver.c --- ucspi-tcp-0.84/tcpserver.c Thu Nov 12 06:32:01 1998 +++ ucspi-tcp-domrules/tcpserver.c Tue Dec 21 15:20:18 1999 @@ -48,6 +48,7 @@ [ -1pPhHrRoOdDqQv ] \ [ -c limit ] \ [ -x rules.cdb ] \ +[ -y domrules.cdb ] \ [ -B banner ] \ [ -g gid ] \ [ -u uid ] \ @@ -100,6 +101,8 @@ int fdrules; char *fnrules = 0; +int fddomrules; +char *fndomrules = 0; int flagdeny = 0; void printenv() @@ -184,6 +187,12 @@ _exit(111); } +void drop_domrules() +{ + if (verbosity) strerr_warn4(DROP,"unable to read ",fndomrules,": ",&strerr_sys); + _exit(111); +} + int dorule() { char *data; @@ -211,6 +220,33 @@ return 1; } +int dodomrule() +{ + char *data; + uint32 dlen32; + unsigned int datalen; + unsigned int next0; + + switch(cdb_seek(fddomrules,tmp.s,tmp.len,&dlen32)) { + case -1: drop_domrules(); + case 0: return 0; + } + + datalen = dlen32; + data = alloc(datalen); + if (!data) drop_nomem(); + if (cdb_bread(fddomrules,data,datalen) != 0) drop_domrules(); + + while ((next0 = byte_chr(data,datalen,0)) < datalen) { + switch(data[0]) { + case 'D': flagdeny = 1; break; + case '+': if (!env_put(data + 1)) drop_nomem(); break; + } + data += next0 + 1; datalen -= next0 + 1; + } + return 1; +} + void rules() { if (!fnrules) return; @@ -239,6 +275,41 @@ close(fdrules); } +void domrules() +{ + char *tcpremotehost; + + if (!fndomrules) return; + + tcpremotehost = env_get("TCPREMOTEHOST"); + + if (!tcpremotehost) return; + + fddomrules = open_read(fndomrules); + if (fddomrules == -1) drop_domrules(); + + if (tcpremoteinfo) { + if (!stralloc_copys(&tmp,tcpremoteinfo)) drop_nomem(); + if (!stralloc_cats(&tmp,"@")) drop_nomem(); + if (!stralloc_cats(&tmp,tcpremotehost)) drop_nomem(); + if (dodomrule()) goto done; + } + + if (!stralloc_copys(&tmp,tcpremotehost)) drop_nomem(); + if (dodomrule()) goto done; + while (tmp.len > 0) { + if (tmp.s[0] == '.') + if (dodomrule()) goto done; + --tmp.len; + byte_copy(tmp.s,tmp.len,tmp.s+1); + } + + dodomrule(); + + done: + close(fddomrules); +} + int flagkillopts = 1; int flagdelay = 1; int flagremoteinfo = 1; @@ -266,11 +337,12 @@ struct servent *se; int j; - while ((opt = getopt(argc,argv,"dDvqQhHrR1x:t:u:g:l:b:B:c:pPoO")) != opteof) + while ((opt = getopt(argc,argv,"dDvqQhHrR1x:y:t:u:g:l:b:B:c:pPoO")) != opteof) switch(opt) { case 'b': scan_ulong(optarg,&backlog); break; case 'c': scan_ulong(optarg,&limit); break; case 'x': fnrules = optarg; break; + case 'y': fndomrules = optarg; break; case 'B': banner = optarg; break; case 'd': flagdelay = 1; break; case 'D': flagdelay = 0; break; @@ -486,6 +558,7 @@ } rules(); + domrules(); printenv(); if (flagdeny) _exit(100);
