Download | Plain Text | Line Numbers
/* prettycache.c
diet -Os gcc -s -o prettycache prettycache.c -Wall -W -lowfat
http://riemann.fmi.uni-sofia.bg/
or in ./djbdns-1.05/ with:
./compile prettycache.c
./load prettycache buffer.a byte.a libtai.a unix.a
*/
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>
#include "tai.h"
#include "buffer.h"
#include "uint32.h"
#include "uint16.h"
#include "fmt.h"
#define outs(x) buffer_puts(buffer_1,x)
#define out(x,y) buffer_put(buffer_1,x,y)
int outu(uint32 u) {char tmp[12]; return out(tmp,fmt_ulong(tmp,u));}
static uint32 pos;
static int flagdot, flagupper, flagtai, flagflat, flagalive;
struct tai now;
char hex[16] = "0123456789abcdef";
void die(int n, const char *s1, const char *s2, const char *s3) {
buffer_flush(buffer_1);
if (s1) buffer_puts(buffer_2, s1);
if (s2) buffer_puts(buffer_2, s2);
if (s3) buffer_puts(buffer_2, s3);
buffer_puts(buffer_2, "\n");
buffer_flush(buffer_2);
_exit(n);
}
void bad_input() {
char tmp[12];
tmp[fmt_ulong(tmp, pos)]=0;
die(111,"\n\ntruncated input near to ", tmp, " position");
}
void u_octal(unsigned char ch) {
char buf[4];
buf[3] = '0' + (ch & 7); ch >>= 3;
buf[2] = '0' + (ch & 7); ch >>= 3;
buf[1] = '0' + (ch & 7);
buf[0] = '\\';
out(buf,4);
}
int dns_dtodot(const char *d, uint32 len) {
char ch, ch2;
int total=0;
if (!len) return 0;
if (!*d) { outs("."); return 1; }
for (;len;) {
ch = *d++;
total++;
len--;
while (len && ch--) {
ch2 = *d++;
total++;
len--;
if (!flagupper)
if ((ch2 >= 'A') && (ch2 <= 'Z'))
ch2 += 32;
if (((ch2 >= 'a') && (ch2 <= 'z')) ||
((ch2 >= '0') && (ch2 <= '9')) || (ch2 == '-') || (ch2 == '_') ||
((ch2 >= 'A') && (ch2 <= 'Z'))) {
out(&ch2,1);
}
else
u_octal((unsigned char)ch2);
}
if (len && !*d) { if (flagdot) out(".",1); return ++total; }
out(".",1);
}
return -1;
}
void u_misc(char *s, uint32 len) {
char *a=s, *end=a+len;
while(a<end) {
out(hex + ((a[0] >> 4) & 15), 1);
out(hex + ((a[0]) & 15), 1);
++a;
}
}
void u_a(char *s, uint32 len) {
char *a=s, *end=a+len;
while(a+4<=end) {
int i=0;
for(i=0; i<4; i++) {
outu((uint32)(unsigned char)a[i]);
if (i<3) outs(".");
}
a += 4;
if (a+4 <= end) outs(" ");
}
}
void u_hex(unsigned char *p) {
char x[4];
int i;
x[0]=hex[p[0] >> 4];
x[1]=hex[p[0] & 15];
x[2]=hex[p[1] >> 4];
x[3]=hex[p[1] & 15];
for (i=0; i<3 && x[i]=='0';) i++;
out(x+i, 4-i);
}
void u_ip6(unsigned char *ip) {
int k, p0,len0, p1,len1, compr;
for (k=0, p0=0,len0=0, p1=0, compr=0; k<16; k+=2) {
if (ip[k]==0 && ip[k+1]==0) {
if (!compr) {
compr=1;
p1=k;
}
if (k==14) { k=16; goto last; }
} else if (compr) {
last:
if ((len1 = k-p1) > len0) {
len0=len1;
p0=p1;
}
compr=0;
}
}
for (k=0; k<16; k+=2) {
if (p0 == k && len0) {
out("::", 1 + !p0);
k += len0-2;
continue;
}
u_hex(ip + k);
if (k<14) outs(":");
}
}
void u_aaaa(char *s, uint32 len) {
char *end = s + len;
while (s+18 <= end) {
if (flagflat) u_misc(s+2,16);
else u_ip6((unsigned char*)s+2);
s += 18;
if (s+18 <= end) outs(" ");
}
}
void u_txt(char *a, uint32 len) {
unsigned int txtlen,i;
txtlen=0;
for (i = 2;i < len;++i) {
char ch = a[i];
if (!txtlen)
txtlen = (unsigned char) ch;
else {
--txtlen;
if (ch < 32 || ch > 126) u_octal((unsigned char)ch);
else out(&ch,1);
}
}
if (txtlen) bad_input();
}
void u_name(char *s, uint32 len) {
char *a=s, *end=a+len;
unsigned long r;
while(a<end) {
if ((r = dns_dtodot(a,end-a))<=0) bad_input();
a += r;
if (a<end) outs(" ");
}
}
void u_mx(char *s, uint32 len) {
char *a=s, *end=a+len;
unsigned long r;
uint16 u;
while(a+3<end) {
uint16_unpack_big(a, &u);
outu(u);
outs(" ");
if ((r=dns_dtodot(a+2, end-(a+2)))<=0) bad_input();
a += r+2;
if (a+3<end) outs(" ");
}
}
int u_time(char *tai) {
struct tai expire;
uint32 exp;
tai_unpack(tai, &expire);
if (expire.x <= now.x) {
if (flagalive) return 1;
exp = 0;
} else
exp = (uint32)(expire.x - now.x);
if (flagtai) {
outs("@");
u_misc(tai,8);
outs("00000000");
} else {
char sp[] = " ";
int len = fmt_ulong(0, exp);
if (len<6) out(sp, 6-len);
outu((uint32)exp);
}
outs(" ");
return 0;
}
int main(int argc, char **argv) {
uint32 len;
uint32 keylen;
uint32 datalen;
uint32 out;
char *p, buf[8];
const char *type, *sep=" ";
int fd;
void (*uu)(char*, uint32);
while (argc>1 && argv[1][0] == '-') {
for (p=argv[1]+1; *p; p++)
switch (*p) {
case 'A': flagalive=1; break;
case 'u': flagupper=1; break;
case 'd': flagdot=1; break;
case 't': flagtai=1; break;
case 'f': flagflat=1; break;
case 'T': sep="\t"; break;
default: goto usage;
}
argc--; argv++;
}
if (argc<2) {usage: die(1,"usage: prettycache [-AdftTu] data",0,0);}
if ((fd=open(argv[1],O_RDONLY)) == -1)
die(21, argv[1], ": open ", "error");
if ((len=lseek(fd,0,SEEK_END)) == (uint32)-1)
die(21, argv[1], ": lseek ", "error");
if ((p=mmap(0,len,PROT_READ,MAP_SHARED,fd,0))==MAP_FAILED)
die(21, "mmap ", "error", 0);
close(fd);
tai_now(&now);
pos = 0;
while (pos+16 <= len) {
char *a,*b;
uint16 u;
uint32_unpack(p + pos, &keylen);
uint32_unpack(p + pos + 4, &datalen);
out = 16 + keylen + datalen;
if (pos + out > len) bad_input();
if (keylen < 3 || keylen > 1024) bad_input();
if (datalen > 1000000) bad_input();
if (u_time(p + pos + 8)) goto next;
a = p + pos + 16;
b = a + keylen;
uint16_unpack_big(a, &u);
uu=u_misc;
switch (u) {
case 1: uu=u_a; type="a"; break;
case 2: uu=u_name; type="ns"; break;
case 5: uu=u_name; type="cname"; break;
case 12: uu=u_name; type="ptr"; break;
case 15: uu=u_mx; type="mx"; break;
case 16: uu=u_txt; type="txt"; break;
case 28: uu=u_aaaa; type="aaaa"; break;
case 33: type="srv"; break;
case 252: type="servfail"; break;
case 255: type="nxdomain"; break;
default: buf[fmt_ulong(buf,u)]=0; type=buf; break;
}
outs(type); outs(sep);
u_name(a+2, keylen-2); outs(sep);
uu(b,datalen); outs("\n");
next:
pos += out;
}
buffer_flush(buffer_1);
munmap(p,len);
return 0;
}