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;
}