Browse Source

monster update: add tai, taia, iopause, case, and ipv6 enhanced dns

master
Felix von Leitner 18 years ago
parent
commit
051de3819a
63 changed files with 2280 additions and 23 deletions
  1. +45
    -13
      Makefile
  2. +24
    -0
      README
  3. +2
    -0
      byte.h
  4. +21
    -0
      case.h
  5. +18
    -0
      case/case_diffb.c
  6. +17
    -0
      case/case_diffs.c
  7. +11
    -0
      case/case_lowerb.c
  8. +10
    -0
      case/case_lowers.c
  9. +93
    -0
      dns.h
  10. +69
    -0
      dns/dns_dfd.c
  11. +73
    -0
      dns/dns_domain.c
  12. +35
    -0
      dns/dns_dtda.c
  13. +75
    -0
      dns/dns_ip.c
  14. +103
    -0
      dns/dns_ip6.c
  15. +71
    -0
      dns/dns_ipq.c
  16. +72
    -0
      dns/dns_ipq6.c
  17. +49
    -0
      dns/dns_mx.c
  18. +63
    -0
      dns/dns_name.c
  19. +24
    -0
      dns/dns_nd.c
  20. +28
    -0
      dns/dns_nd6.c
  21. +77
    -0
      dns/dns_packet.c
  22. +63
    -0
      dns/dns_random.c
  23. +85
    -0
      dns/dns_rcip.c
  24. +131
    -0
      dns/dns_rcrw.c
  25. +30
    -0
      dns/dns_resolve.c
  26. +20
    -0
      dns/dns_sortip.c
  27. +20
    -0
      dns/dns_sortip6.c
  28. +367
    -0
      dns/dns_transmit.c
  29. +59
    -0
      dns/dns_txt.c
  30. +19
    -0
      iopause.h1
  31. +18
    -0
      iopause.h2
  32. +16
    -0
      open/openreadclose.c
  33. +21
    -0
      open/readclose.c
  34. +8
    -0
      openreadclose.h
  35. +9
    -0
      readclose.h
  36. +3
    -0
      scan.h
  37. +10
    -0
      select.h1
  38. +11
    -0
      select.h2
  39. +2
    -0
      str.h
  40. +1
    -3
      stralloc.h
  41. +1
    -1
      stralloc/stralloc_copy.c
  42. +42
    -0
      t.c
  43. +26
    -0
      tai.h
  44. +6
    -0
      tai/tai_add.c
  45. +7
    -0
      tai/tai_now.c
  46. +16
    -0
      tai/tai_pack.c
  47. +6
    -0
      tai/tai_sub.c
  48. +6
    -0
      tai/tai_uint.c
  49. +16
    -0
      tai/tai_unpack.c
  50. +68
    -0
      taia.h
  51. +18
    -0
      taia/taia_add.c
  52. +6
    -0
      taia/taia_approx.c
  53. +6
    -0
      taia/taia_frac.c
  54. +12
    -0
      taia/taia_less.c
  55. +12
    -0
      taia/taia_now.c
  56. +20
    -0
      taia/taia_pack.c
  57. +21
    -0
      taia/taia_sub.c
  58. +6
    -0
      taia/taia_tai.c
  59. +10
    -0
      taia/taia_uint.c
  60. +18
    -0
      trypoll.c
  61. +8
    -0
      trysysel.c
  62. +0
    -6
      uint64.h
  63. +76
    -0
      unix/iopause.c

+ 45
- 13
Makefile View File

@@ -3,13 +3,14 @@ LIBDIR=${prefix}/lib
INCLUDEDIR=${prefix}/include
MAN3DIR=${prefix}/man/man3

all: t byte.a fmt.a scan.a str.a uint.a open.a stralloc.a unix.a socket.a buffer.a mmap.a libowfat.a
all: t byte.a fmt.a scan.a str.a uint.a open.a stralloc.a unix.a socket.a \
buffer.a mmap.a taia.a tai.a dns.a case.a libowfat.a

VPATH=str:byte:fmt:scan:uint:open:stralloc:unix:socket:buffer:mmap:textcode
VPATH=str:byte:fmt:scan:uint:open:stralloc:unix:socket:buffer:mmap:textcode:taia:tai:dns:case

# comment out the following line if you don't want to build with the
# diet libc (http://www.fefe.de/dietlibc/).
DIET=diet -Os
DIET=/opt/diet/bin/diet -Os
CC=gcc
CFLAGS=-I. -pipe -Wall -O2 -fomit-frame-pointer
#CFLAGS=-pipe -Os -march=pentiumpro -mcpu=pentiumpro -fomit-frame-pointer -fschedule-insns2 -Wall
@@ -26,6 +27,10 @@ SOCKET_OBJS=$(patsubst socket/%.c,%.o,$(wildcard socket/*.c))
BUFFER_OBJS=$(patsubst buffer/%.c,%.o,$(wildcard buffer/*.c))
MMAP_OBJS=$(patsubst mmap/%.c,%.o,$(wildcard mmap/*.c))
TEXTCODE_OBJS=$(patsubst textcode/%.c,%.o,$(wildcard textcode/*.c))
TAI_OBJS=$(patsubst tai/%.c,%.o,$(wildcard tai/*.c))
TAIA_OBJS=$(patsubst taia/%.c,%.o,$(wildcard taia/*.c))
DNS_OBJS=$(patsubst dns/%.c,%.o,$(wildcard dns/*.c))
CASE_OBJS=$(patsubst case/%.c,%.o,$(wildcard case/*.c))

$(BYTE_OBJS): byte.h
$(FMT_OBJS): fmt.h
@@ -37,6 +42,14 @@ $(SOCKET_OBJS): socket.h
$(BUFFER_OBJS): buffer.h
$(MMAP_OBJS): mmap.h
$(TEXTCODE_OBJS): textcode.h
$(TAI_OBJS): tai.h uint64.h
$(TAIA_OBJS): taia.h tai.h uint64.h
$(DNS_OBJS): dns.h stralloc.h taia.h tai.h uint64.h iopause.h
$(CASE_OBJS): case.h

iopause.o: select.h
openreadclose.o readclose.o: readclose.h
dns_rcip.o dns_rcrw.o openreadclose.o: openreadclose.h

byte.a: $(BYTE_OBJS)
fmt.a: $(FMT_OBJS)
@@ -50,10 +63,15 @@ socket.a: $(SOCKET_OBJS)
buffer.a: $(BUFFER_OBJS)
mmap.a: $(MMAP_OBJS)
textcode.a: $(TEXTCODE_OBJS)
taia.a: $(TAIA_OBJS)
tai.a: $(TAI_OBJS)
dns.a: $(DNS_OBJS)
case.a: $(CASE_OBJS)

libowfat.a: $(BYTE_OBJS) $(FMT_OBJS) $(SCAN_OBJS) $(STR_OBJS) \
$(UINT_OBJS) $(OPEN_OBJS) $(STRA_OBJS) $(UNIX_OBJS) $(SOCKET_OBJS) \
$(BUFFER_OBJS) $(MMAP_OBJS) $(TEXTCODE_OBJS)
libowfat.a: $(DNS_OBJS) $(BYTE_OBJS) $(FMT_OBJS) $(SCAN_OBJS) \
$(STR_OBJS) $(UINT_OBJS) $(OPEN_OBJS) $(STRA_OBJS) $(UNIX_OBJS) \
$(SOCKET_OBJS) $(BUFFER_OBJS) $(MMAP_OBJS) $(TEXTCODE_OBJS) \
$(TAIA_OBJS) $(TAI_OBJS) $(CASE_OBJS)

%.o: %.c
$(DIET) $(CC) -c $< -o $@ $(CFLAGS)
@@ -67,9 +85,12 @@ t: t.o libowfat.a

.PHONY: clean tar install rename
clean:
rm -f *.o *.a *.da *.bbg *.bb core t haveip6.h haven2i.h havesl.h haveinline.h
rm -f *.o *.a *.da *.bbg *.bb core t haveip6.h haven2i.h havesl.h haveinline.h \
iopause.h select.h

INCLUDES=buffer.h byte.h fmt.h ip4.h ip6.h mmap.h scan.h socket.h str.h stralloc.h uint16.h uint32.h uint64.h open.h textcode.h
INCLUDES=buffer.h byte.h fmt.h ip4.h ip6.h mmap.h scan.h socket.h str.h stralloc.h \
uint16.h uint32.h uint64.h open.h textcode.h tai.h taia.h dns.h iopause.h case.h \
openreadclose.h readclose.h

install: libowfat.a
install -d $(INCLUDEDIR) $(MAN3DIR) $(LIBDIR)
@@ -91,25 +112,36 @@ tar: clean rename
rename:
if test $(CURNAME) != $(VERSION); then cd .. && mv $(CURNAME) $(VERSION); fi

haveip6.h:
haveip6.h: tryip6.c
-rm -f $@
if $(DIET) $(CC) -c tryip6.c >/dev/null 2>&1; then echo "#define LIBC_HAS_IP6"; fi > $@
-rm -f tryip6.o

haven2i.h:
haven2i.h: tryn2i.c
-rm -f $@
if $(DIET) $(CC) -o t tryn2i.c >/dev/null 2>&1; then echo "#define HAVE_N2I"; fi > $@
-rm -f t

havesl.h:
havesl.h: trysl.c
-rm -f $@
if ! $(DIET) $(CC) -o t trysl.c >/dev/null 2>&1; then echo "typedef int socklen_t;"; fi > $@
-rm -f t

haveinline.h:
haveinline.h: tryinline.c
-rm -f $@
if ! $(DIET) $(CC) -c tryinline.c >/dev/null 2>&1; then echo "#define inline"; fi > $@
-rm -f tryip6.o
-rm -f tryinline.o

iopause.h: iopause.h1 iopause.h2 trypoll.c
-rm -f $@
if $(DIET) $(CC) -o t trypoll.c >/dev/null 2>&1; then cp iopause.h2 iopause.h; else cp iopause.h1 iopause.h; fi
-rm -f t

select.h: select.h1 select.h2 trysysel.c
-rm -f $@
if $(DIET) $(CC) -c trysysel.c >/dev/null 2>&1; then cp select.h2 select.h; else cp select.h1 select.h; fi
-rm -f trysysel.o


socket_accept6.o socket_connect6.o socket_local6.o socket_mchopcount6.o \
socket_mcjoin6.o socket_mcleave6.o socket_mcloop6.o socket_recv6.o \


+ 24
- 0
README View File

@@ -0,0 +1,24 @@
libowfat is a library of general purpose APIs extracted from Dan
Bernstein's software, reimplemented and covered by the GNU General
Public License Version 2 (no later versions).

The API has been slightly extended (for example, I provide a uint32_read
function, and I extended the socket API to support IPv6) where I found
it necessary or beneficial in a specific project.

Many of the functions I implement here have since been placed in the
public domain, so there are other sources to get this code (except for
my extensions obviously). The implementations here may not be as
portable as the original versions; I tend to focus on the Single Unix
Specification and not on some obsolete legacy systems found in the
basements of some vintage hardware clubs.

I also provide man pages for many functions, mostly extracted from Dan's
web documentation or documentation found in earlier versions of his
software. For some reason, he abandoned man pages in favor of HTML
recently.

On July 4 2002, Dan also placed his DNS routines and supporting
low level functions in the public domain, so I copy them here instead of
reimplementing them. http://online.securityfocus.com/archive/1/280642
has an online version of the bugtraq posting.

+ 2
- 0
byte.h View File

@@ -1,7 +1,9 @@
#ifndef BYTE_H
#define BYTE_H

#ifdef __dietlibc__
#include <sys/cdefs.h>
#endif

#ifndef __pure__
#define __pure__


+ 21
- 0
case.h View File

@@ -0,0 +1,21 @@
#ifndef CASE_H
#define CASE_H

/* turn upper case letters to lower case letters, ASCIIZ */
extern void case_lowers(char *s);
/* turn upper case letters to lower case letters, binary */
extern void case_lowerb(char *buf,unsigned int len);

/* like str_diff, ignoring case */
extern int case_diffs(const char *,const char *);
/* like byte_diff, ignoring case */
extern int case_diffb(const char *,unsigned int,const char *);

/* like str_start, ignoring case */
extern int case_starts(const char *,const char *);
/* alias for case_diffb? */
extern int case_startb(const char *,unsigned int,const char *);

#define case_equals(s,t) (!case_diffs((s),(t)))

#endif

+ 18
- 0
case/case_diffb.c View File

@@ -0,0 +1,18 @@
#include "case.h"

int case_diffb(register const char *s,register unsigned int len,register const char *t)
{
register unsigned char x;
register unsigned char y;

while (len > 0) {
--len;
x = *s++ - 'A';
if (x <= 'Z' - 'A') x += 'a'; else x += 'A';
y = *t++ - 'A';
if (y <= 'Z' - 'A') y += 'a'; else y += 'A';
if (x != y)
return ((int)(unsigned int) x) - ((int)(unsigned int) y);
}
return 0;
}

+ 17
- 0
case/case_diffs.c View File

@@ -0,0 +1,17 @@
#include "case.h"

int case_diffs(register const char *s,register const char *t)
{
register unsigned char x;
register unsigned char y;

for (;;) {
x = *s++ - 'A';
if (x <= 'Z' - 'A') x += 'a'; else x += 'A';
y = *t++ - 'A';
if (y <= 'Z' - 'A') y += 'a'; else y += 'A';
if (x != y) break;
if (!x) break;
}
return ((int)(unsigned int) x) - ((int)(unsigned int) y);
}

+ 11
- 0
case/case_lowerb.c View File

@@ -0,0 +1,11 @@
#include "case.h"

void case_lowerb(char *s,unsigned int len) {
unsigned char x;
while (len > 0) {
--len;
x = *s - 'A';
if (x <= 'Z' - 'A') *s = x + 'a';
++s;
}
}

+ 10
- 0
case/case_lowers.c View File

@@ -0,0 +1,10 @@
#include "case.h"

void case_lowers(char *s) {
unsigned char x;
for (;;) {
if (!(x=*s)) break;
if ((x -= 'A') <= 'Z' - 'A') *s = x + 'a';
++s;
}
}

+ 93
- 0
dns.h View File

@@ -0,0 +1,93 @@
#ifndef DNS_H
#define DNS_H

#include "stralloc.h"
#include "iopause.h"
#include "taia.h"

#define DNS_C_IN "\0\1"
#define DNS_C_ANY "\0\377"

#define DNS_T_A "\0\1"
#define DNS_T_NS "\0\2"
#define DNS_T_CNAME "\0\5"
#define DNS_T_SOA "\0\6"
#define DNS_T_PTR "\0\14"
#define DNS_T_HINFO "\0\15"
#define DNS_T_MX "\0\17"
#define DNS_T_TXT "\0\20"
#define DNS_T_RP "\0\21"
#define DNS_T_SIG "\0\30"
#define DNS_T_KEY "\0\31"
#define DNS_T_AAAA "\0\34"
#define DNS_T_AXFR "\0\374"
#define DNS_T_ANY "\0\377"

struct dns_transmit {
char *query; /* 0, or dynamically allocated */
unsigned int querylen;
char *packet; /* 0, or dynamically allocated */
unsigned int packetlen;
int s1; /* 0, or 1 + an open file descriptor */
int tcpstate;
unsigned int udploop;
unsigned int curserver;
struct taia deadline;
unsigned int pos;
const char *servers;
char localip[16];
unsigned int scope_id;
char qtype[2];
} ;

extern void dns_random_init(const char *);
extern unsigned int dns_random(unsigned int);

extern void dns_sortip(char *,unsigned int);
extern void dns_sortip6(char *,unsigned int);

extern void dns_domain_free(char **);
extern int dns_domain_copy(char **,const char *);
extern unsigned int dns_domain_length(const char *);
extern int dns_domain_equal(const char *,const char *);
extern int dns_domain_suffix(const char *,const char *);
extern unsigned int dns_domain_suffixpos(const char *,const char *);
extern int dns_domain_fromdot(char **,const char *,unsigned int);
extern int dns_domain_todot_cat(stralloc *,const char *);

extern unsigned int dns_packet_copy(const char *,unsigned int,unsigned int,char *,unsigned int);
extern unsigned int dns_packet_getname(const char *,unsigned int,unsigned int,char **);
extern unsigned int dns_packet_skipname(const char *,unsigned int,unsigned int);

extern int dns_transmit_start(struct dns_transmit *,const char *,int,const char *,const char *,const char *);
extern void dns_transmit_free(struct dns_transmit *);
extern void dns_transmit_io(struct dns_transmit *,iopause_fd *,struct taia *);
extern int dns_transmit_get(struct dns_transmit *,const iopause_fd *,const struct taia *);

extern int dns_resolvconfip(char *);
extern int dns_resolve(const char *,const char *);
extern struct dns_transmit dns_resolve_tx;

extern int dns_ip4_packet(stralloc *,const char *,unsigned int);
extern int dns_ip4(stralloc *,const stralloc *);
extern int dns_ip6_packet(stralloc *,char *,unsigned int);
extern int dns_ip6(stralloc *,stralloc *);
extern int dns_name_packet(stralloc *,const char *,unsigned int);
extern void dns_name4_domain(char *,const char *);
#define DNS_NAME4_DOMAIN 31
extern int dns_name4(stralloc *,const char *);
extern int dns_txt_packet(stralloc *,const char *,unsigned int);
extern int dns_txt(stralloc *,const stralloc *);
extern int dns_mx_packet(stralloc *,const char *,unsigned int);
extern int dns_mx(stralloc *,const stralloc *);

extern int dns_resolvconfrewrite(stralloc *);
extern int dns_ip4_qualify_rules(stralloc *,stralloc *,const stralloc *,const stralloc *);
extern int dns_ip4_qualify(stralloc *,stralloc *,const stralloc *);
extern int dns_ip6_qualify_rules(stralloc *,stralloc *,const stralloc *,const stralloc *);
extern int dns_ip6_qualify(stralloc *,stralloc *,const stralloc *);

extern int dns_name6_domain(char *,char *);
#define DNS_NAME6_DOMAIN (4*16+10)

#endif

+ 69
- 0
dns/dns_dfd.c View File

@@ -0,0 +1,69 @@
#include <stdlib.h>
#include <errno.h>
#include "byte.h"
#include "dns.h"

int dns_domain_fromdot(char **out,const char *buf,unsigned int n)
{
char label[63];
unsigned int labellen = 0; /* <= sizeof label */
char name[255];
unsigned int namelen = 0; /* <= sizeof name */
char ch;
char *x;

errno = EPROTO;

for (;;) {
if (!n) break;
ch = *buf++; --n;
if (ch == '.') {
if (labellen) {
if (namelen + labellen + 1 > sizeof name) return 0;
name[namelen++] = labellen;
byte_copy(name + namelen,labellen,label);
namelen += labellen;
labellen = 0;
}
continue;
}
if (ch == '\\') {
if (!n) break;
ch = *buf++; --n;
if ((ch >= '0') && (ch <= '7')) {
ch -= '0';
if (n && (*buf >= '0') && (*buf <= '7')) {
ch <<= 3;
ch += *buf - '0';
++buf; --n;
if (n && (*buf >= '0') && (*buf <= '7')) {
ch <<= 3;
ch += *buf - '0';
++buf; --n;
}
}
}
}
if (labellen >= sizeof label) return 0;
label[labellen++] = ch;
}

if (labellen) {
if (namelen + labellen + 1 > sizeof name) return 0;
name[namelen++] = labellen;
byte_copy(name + namelen,labellen,label);
namelen += labellen;
labellen = 0;
}

if (namelen + 1 > sizeof name) return 0;
name[namelen++] = 0;

x = malloc(namelen);
if (!x) return 0;
byte_copy(x,namelen,name);

if (*out) free(*out);
*out = x;
return 1;
}

+ 73
- 0
dns/dns_domain.c View File

@@ -0,0 +1,73 @@
#include <stdlib.h>
#include "case.h"
#include "byte.h"
#include "dns.h"

unsigned int dns_domain_length(const char *dn)
{
const char *x;
unsigned char c;

x = dn;
while ((c = *x++))
x += (unsigned int) c;
return x - dn;
}

void dns_domain_free(char **out)
{
if (*out) {
free(*out);
*out = 0;
}
}

int dns_domain_copy(char **out,const char *in)
{
unsigned int len;
char *x;

len = dns_domain_length(in);
x = malloc(len);
if (!x) return 0;
byte_copy(x,len,in);
if (*out) free(*out);
*out = x;
return 1;
}

int dns_domain_equal(const char *dn1,const char *dn2)
{
unsigned int len;

len = dns_domain_length(dn1);
if (len != dns_domain_length(dn2)) return 0;

if (case_diffb(dn1,len,dn2)) return 0; /* safe since 63 < 'A' */
return 1;
}

int dns_domain_suffix(const char *big,const char *little)
{
unsigned char c;

for (;;) {
if (dns_domain_equal(big,little)) return 1;
c = *big++;
if (!c) return 0;
big += c;
}
}

unsigned int dns_domain_suffixpos(const char *big,const char *little)
{
const char *orig = big;
unsigned char c;

for (;;) {
if (dns_domain_equal(big,little)) return big - orig;
c = *big++;
if (!c) return 0;
big += c;
}
}

+ 35
- 0
dns/dns_dtda.c View File

@@ -0,0 +1,35 @@
#include "stralloc.h"
#include "dns.h"

int dns_domain_todot_cat(stralloc *out,const char *d)
{
char ch;
char ch2;
unsigned char ch3;
char buf[4];

if (!*d)
return stralloc_append(out,".");

for (;;) {
ch = *d++;
while (ch--) {
ch2 = *d++;
if ((ch2 >= 'A') && (ch2 <= 'Z'))
ch2 += 32;
if (((ch2 >= 'a') && (ch2 <= 'z')) || ((ch2 >= '0') && (ch2 <= '9')) || (ch2 == '-') || (ch2 == '_')) {
if (!stralloc_append(out,&ch2)) return 0;
}
else {
ch3 = ch2;
buf[3] = '0' + (ch3 & 7); ch3 >>= 3;
buf[2] = '0' + (ch3 & 7); ch3 >>= 3;
buf[1] = '0' + (ch3 & 7);
buf[0] = '\\';
if (!stralloc_catb(out,buf,4)) return 0;
}
}
if (!*d) return 1;
if (!stralloc_append(out,".")) return 0;
}
}

+ 75
- 0
dns/dns_ip.c View File

@@ -0,0 +1,75 @@
#include "stralloc.h"
#include "uint16.h"
#include "byte.h"
#include "dns.h"

int dns_ip4_packet(stralloc *out,const char *buf,unsigned int len)
{
unsigned int pos;
char header[12];
uint16 numanswers;
uint16 datalen;

if (!stralloc_copys(out,"")) return -1;

pos = dns_packet_copy(buf,len,0,header,12); if (!pos) return -1;
uint16_unpack_big(header + 6,&numanswers);
pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1;
pos += 4;

while (numanswers--) {
pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1;
pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) return -1;
uint16_unpack_big(header + 8,&datalen);
if (byte_equal(header,2,DNS_T_A))
if (byte_equal(header + 2,2,DNS_C_IN))
if (datalen == 4) {
if (!dns_packet_copy(buf,len,pos,header,4)) return -1;
if (!stralloc_catb(out,header,4)) return -1;
}
pos += datalen;
}

dns_sortip(out->s,out->len);
return 0;
}

static char *q = 0;

int dns_ip4(stralloc *out,const stralloc *fqdn)
{
unsigned int i;
char code;
char ch;

if (!stralloc_copys(out,"")) return -1;
code = 0;
for (i = 0;i <= fqdn->len;++i) {
if (i < fqdn->len)
ch = fqdn->s[i];
else
ch = '.';

if ((ch == '[') || (ch == ']')) continue;
if (ch == '.') {
if (!stralloc_append(out,&code)) return -1;
code = 0;
continue;
}
if ((ch >= '0') && (ch <= '9')) {
code *= 10;
code += ch - '0';
continue;
}

if (!dns_domain_fromdot(&q,fqdn->s,fqdn->len)) return -1;
if (dns_resolve(q,DNS_T_A) == -1) return -1;
if (dns_ip4_packet(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) == -1) return -1;
dns_transmit_free(&dns_resolve_tx);
dns_domain_free(&q);
return 0;
}

out->len &= ~3;
return 0;
}

+ 103
- 0
dns/dns_ip6.c View File

@@ -0,0 +1,103 @@
#include "stralloc.h"
#include "uint16.h"
#include "byte.h"
#include "dns.h"
#include "ip4.h"
#include "ip6.h"

static int dns_ip6_packet_add(stralloc *out,char *buf,unsigned int len)
{
unsigned int pos;
char header[16];
uint16 numanswers;
uint16 datalen;

pos = dns_packet_copy(buf,len,0,header,12); if (!pos) return -1;
uint16_unpack_big(header + 6,&numanswers);
pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1;
pos += 4;

while (numanswers--) {
pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1;
pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) return -1;
uint16_unpack_big(header + 8,&datalen);
if (byte_equal(header,2,DNS_T_AAAA)) {
if (byte_equal(header + 2,2,DNS_C_IN))
if (datalen == 16) {
if (!dns_packet_copy(buf,len,pos,header,16)) return -1;
if (!stralloc_catb(out,header,16)) return -1;
}
} else if (byte_equal(header,2,DNS_T_A))
if (byte_equal(header + 2,2,DNS_C_IN))
if (datalen == 4) {
byte_copy(header,12,V4mappedprefix);
if (!dns_packet_copy(buf,len,pos,header+12,4)) return -1;
if (!stralloc_catb(out,header,16)) return -1;
}
pos += datalen;
}

dns_sortip6(out->s,out->len);
return 0;
}

int dns_ip6_packet(stralloc *out,char *buf,unsigned int len) {
if (!stralloc_copys(out,"")) return -1;
return dns_ip6_packet_add(out,buf,len);
}

static char *q = 0;

int dns_ip6(stralloc *out,stralloc *fqdn)
{
unsigned int i;
char code;
char ch;
char ip[16];

if (!stralloc_copys(out,"")) return -1;
if (!stralloc_readyplus(fqdn,1)) return -1;
fqdn->s[fqdn->len]=0;
if ((i=scan_ip6(fqdn->s,ip))) {
if (fqdn->s[i]) return -1;
stralloc_copyb(out,ip,16);
return 0;
}
code = 0;
for (i = 0;i <= fqdn->len;++i) {
if (i < fqdn->len)
ch = fqdn->s[i];
else
ch = '.';

if ((ch == '[') || (ch == ']')) continue;
if (ch == '.') {
if (!stralloc_append(out,&code)) return -1;
code = 0;
continue;
}
if ((ch >= '0') && (ch <= '9')) {
code *= 10;
code += ch - '0';
continue;
}

if (!dns_domain_fromdot(&q,fqdn->s,fqdn->len)) return -1;
if (!stralloc_copys(out,"")) return -1;
if (dns_resolve(q,DNS_T_AAAA) != -1)
if (dns_ip6_packet_add(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) != -1) {
dns_transmit_free(&dns_resolve_tx);
dns_domain_free(&q);
}
if (!dns_domain_fromdot(&q,fqdn->s,fqdn->len)) return -1;
if (dns_resolve(q,DNS_T_A) != -1)
if (dns_ip6_packet_add(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) != -1) {
dns_transmit_free(&dns_resolve_tx);
dns_domain_free(&q);
}
return out->a>0?0:-1;
}

out->len &= ~3;
return 0;
}

+ 71
- 0
dns/dns_ipq.c View File

@@ -0,0 +1,71 @@
#include "stralloc.h"
#include "case.h"
#include "byte.h"
#include "str.h"
#include "dns.h"

static int doit(stralloc *work,const char *rule)
{
char ch;
unsigned int colon;
unsigned int prefixlen;

ch = *rule++;
if ((ch != '?') && (ch != '=') && (ch != '*') && (ch != '-')) return 1;
colon = str_chr(rule,':');
if (!rule[colon]) return 1;

if (work->len < colon) return 1;
prefixlen = work->len - colon;
if ((ch == '=') && prefixlen) return 1;
if (case_diffb(rule,colon,work->s + prefixlen)) return 1;
if (ch == '?') {
if (byte_chr(work->s,prefixlen,'.') < prefixlen) return 1;
if (byte_chr(work->s,prefixlen,'[') < prefixlen) return 1;
if (byte_chr(work->s,prefixlen,']') < prefixlen) return 1;
}

work->len = prefixlen;
if (ch == '-') work->len = 0;
return stralloc_cats(work,rule + colon + 1);
}

int dns_ip4_qualify_rules(stralloc *out,stralloc *fqdn,const stralloc *in,const stralloc *rules)
{
unsigned int i;
unsigned int j;
unsigned int plus;
unsigned int fqdnlen;

if (!stralloc_copy(fqdn,in)) return -1;

for (j = i = 0;j < rules->len;++j)
if (!rules->s[j]) {
if (!doit(fqdn,rules->s + i)) return -1;
i = j + 1;
}

fqdnlen = fqdn->len;
plus = byte_chr(fqdn->s,fqdnlen,'+');
if (plus >= fqdnlen)
return dns_ip4(out,fqdn);

i = plus + 1;
for (;;) {
j = byte_chr(fqdn->s + i,fqdnlen - i,'+');
byte_copy(fqdn->s + plus,j,fqdn->s + i);
fqdn->len = plus + j;
if (dns_ip4(out,fqdn) == -1) return -1;
if (out->len) return 0;
i += j;
if (i >= fqdnlen) return 0;
++i;
}
}

int dns_ip4_qualify(stralloc *out,stralloc *fqdn,const stralloc *in)
{
static stralloc rules;
if (dns_resolvconfrewrite(&rules) == -1) return -1;
return dns_ip4_qualify_rules(out,fqdn,in,&rules);
}

+ 72
- 0
dns/dns_ipq6.c View File

@@ -0,0 +1,72 @@
#include "stralloc.h"
#include "case.h"
#include "byte.h"
#include "str.h"
#include "dns.h"

static int doit(stralloc *work,const char *rule)
{
char ch;
unsigned int colon;
unsigned int prefixlen;

ch = *rule++;
if ((ch != '?') && (ch != '=') && (ch != '*') && (ch != '-')) return 1;
colon = str_chr(rule,':');
if (!rule[colon]) return 1;

if (work->len < colon) return 1;
prefixlen = work->len - colon;
if ((ch == '=') && prefixlen) return 1;
if (case_diffb(rule,colon,work->s + prefixlen)) return 1;
if (ch == '?') {
if (byte_chr(work->s,prefixlen,'.') < prefixlen) return 1;
if (byte_chr(work->s,prefixlen,':') < prefixlen) return 1;
if (byte_chr(work->s,prefixlen,'[') < prefixlen) return 1;
if (byte_chr(work->s,prefixlen,']') < prefixlen) return 1;
}

work->len = prefixlen;
if (ch == '-') work->len = 0;
return stralloc_cats(work,rule + colon + 1);
}

int dns_ip6_qualify_rules(stralloc *out,stralloc *fqdn,const stralloc *in,const stralloc *rules)
{
unsigned int i;
unsigned int j;
unsigned int plus;
unsigned int fqdnlen;

if (!stralloc_copy(fqdn,in)) return -1;

for (j = i = 0;j < rules->len;++j)
if (!rules->s[j]) {
if (!doit(fqdn,rules->s + i)) return -1;
i = j + 1;
}

fqdnlen = fqdn->len;
plus = byte_chr(fqdn->s,fqdnlen,'+');
if (plus >= fqdnlen)
return dns_ip6(out,fqdn);

i = plus + 1;
for (;;) {
j = byte_chr(fqdn->s + i,fqdnlen - i,'+');
byte_copy(fqdn->s + plus,j,fqdn->s + i);
fqdn->len = plus + j;
if (dns_ip6(out,fqdn) == -1) return -1;
if (out->len) return 0;
i += j;
if (i >= fqdnlen) return 0;
++i;
}
}

int dns_ip6_qualify(stralloc *out,stralloc *fqdn,const stralloc *in)
{
static stralloc rules;
if (dns_resolvconfrewrite(&rules) == -1) return -1;
return dns_ip6_qualify_rules(out,fqdn,in,&rules);
}

+ 49
- 0
dns/dns_mx.c View File

@@ -0,0 +1,49 @@
#include "stralloc.h"
#include "byte.h"
#include "uint16.h"
#include "dns.h"

static char *q = 0;

int dns_mx_packet(stralloc *out,const char *buf,unsigned int len)
{
unsigned int pos;
char header[12];
char pref[2];
uint16 numanswers;
uint16 datalen;

if (!stralloc_copys(out,"")) return -1;

pos = dns_packet_copy(buf,len,0,header,12); if (!pos) return -1;
uint16_unpack_big(header + 6,&numanswers);
pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1;
pos += 4;

while (numanswers--) {
pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1;
pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) return -1;
uint16_unpack_big(header + 8,&datalen);
if (byte_equal(header,2,DNS_T_MX))
if (byte_equal(header + 2,2,DNS_C_IN)) {
if (!dns_packet_copy(buf,len,pos,pref,2)) return -1;
if (!dns_packet_getname(buf,len,pos + 2,&q)) return -1;
if (!stralloc_catb(out,pref,2)) return -1;
if (!dns_domain_todot_cat(out,q)) return -1;
if (!stralloc_0(out)) return -1;
}
pos += datalen;
}

return 0;
}

int dns_mx(stralloc *out,const stralloc *fqdn)
{
if (!dns_domain_fromdot(&q,fqdn->s,fqdn->len)) return -1;
if (dns_resolve(q,DNS_T_MX) == -1) return -1;
if (dns_mx_packet(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) == -1) return -1;
dns_transmit_free(&dns_resolve_tx);
dns_domain_free(&q);
return 0;
}

+ 63
- 0
dns/dns_name.c View File

@@ -0,0 +1,63 @@
#include "stralloc.h"
#include "uint16.h"
#include "byte.h"
#include "dns.h"
#include "ip6.h"

static char *q = 0;

int dns_name_packet(stralloc *out,const char *buf,unsigned int len)
{
unsigned int pos;
char header[12];
uint16 numanswers;
uint16 datalen;

if (!stralloc_copys(out,"")) return -1;

pos = dns_packet_copy(buf,len,0,header,12); if (!pos) return -1;
uint16_unpack_big(header + 6,&numanswers);
pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1;
pos += 4;

while (numanswers--) {
pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1;
pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) return -1;
uint16_unpack_big(header + 8,&datalen);
if (byte_equal(header,2,DNS_T_PTR))
if (byte_equal(header + 2,2,DNS_C_IN)) {
if (!dns_packet_getname(buf,len,pos,&q)) return -1;
if (!dns_domain_todot_cat(out,q)) return -1;
return 0;
}
pos += datalen;
}

return 0;
}

int dns_name4(stralloc *out,const char ip[4])
{
char name[DNS_NAME4_DOMAIN];

dns_name4_domain(name,ip);
if (dns_resolve(name,DNS_T_PTR) == -1) return -1;
if (dns_name_packet(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) == -1) return -1;
dns_transmit_free(&dns_resolve_tx);
dns_domain_free(&q);
return 0;
}

int dns_name6(stralloc *out,char ip[16])
{
char name[DNS_NAME6_DOMAIN];

if (ip6_isv4mapped(ip))
return dns_name4(out,ip+12);
dns_name6_domain(name,ip);
if (dns_resolve(name,DNS_T_PTR) == -1) return -1;
if (dns_name_packet(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) == -1) return -1;
dns_transmit_free(&dns_resolve_tx);
dns_domain_free(&q);
return 0;
}

+ 24
- 0
dns/dns_nd.c View File

@@ -0,0 +1,24 @@
#include "byte.h"
#include "fmt.h"
#include "dns.h"

void dns_name4_domain(char name[DNS_NAME4_DOMAIN],const char ip[4])
{
unsigned int namelen;
unsigned int i;

namelen = 0;
i = fmt_ulong(name + namelen + 1,(unsigned long) (unsigned char) ip[3]);
name[namelen++] = i;
namelen += i;
i = fmt_ulong(name + namelen + 1,(unsigned long) (unsigned char) ip[2]);
name[namelen++] = i;
namelen += i;
i = fmt_ulong(name + namelen + 1,(unsigned long) (unsigned char) ip[1]);
name[namelen++] = i;
namelen += i;
i = fmt_ulong(name + namelen + 1,(unsigned long) (unsigned char) ip[0]);
name[namelen++] = i;
namelen += i;
byte_copy(name + namelen,14,"\7in-addr\4arpa\0");
}

+ 28
- 0
dns/dns_nd6.c View File

@@ -0,0 +1,28 @@
#include "byte.h"
#include "fmt.h"
#include "dns.h"

/* RFC1886:
* 4321:0:1:2:3:4:567:89ab
* ->
* b.a.9.8.7.6.5.0.4.0.0.0.3.0.0.0.2.0.0.0.1.0.0.0.0.0.0.0.1.2.3.4.IP6.INT.
*/

static inline char tohex(char c) {
return c>=10?c-10+'a':c+'0';
}

int dns_name6_domain(char name[DNS_NAME6_DOMAIN],char ip[16])
{
unsigned int j;

for (j=0; j<16; j++) {
name[j*4]=1;
name[j*4+1]=tohex(ip[15-j] & 15);
name[j*4+2]=1;
name[j*4+3]=tohex((unsigned char)ip[15-j] >> 4);
}
byte_copy(name + 4*16,9,"\3ip6\3int\0");
return 4*16+9;
}


+ 77
- 0
dns/dns_packet.c View File

@@ -0,0 +1,77 @@
/*
DNS should have used LZ77 instead of its own sophomoric compression algorithm.
*/

#include <errno.h>
#include "dns.h"

unsigned int dns_packet_copy(const char *buf,unsigned int len,unsigned int pos,char *out,unsigned int outlen)
{
while (outlen) {
if (pos >= len) { errno = EPROTO; return 0; }
*out = buf[pos++];
++out; --outlen;
}
return pos;
}

unsigned int dns_packet_skipname(const char *buf,unsigned int len,unsigned int pos)
{
unsigned char ch;

for (;;) {
if (pos >= len) break;
ch = buf[pos++];
if (ch >= 192) return pos + 1;
if (ch >= 64) break;
if (!ch) return pos;
pos += ch;
}

errno = EPROTO;
return 0;
}

unsigned int dns_packet_getname(const char *buf,unsigned int len,unsigned int pos,char **d)
{
unsigned int loop = 0;
unsigned int state = 0;
unsigned int firstcompress = 0;
unsigned int where;
unsigned char ch;
char name[255];
unsigned int namelen = 0;

for (;;) {
if (pos >= len) goto PROTO; ch = buf[pos++];
if (++loop >= 1000) goto PROTO;

if (state) {
if (namelen + 1 > sizeof name) goto PROTO; name[namelen++] = ch;
--state;
}
else {
while (ch >= 192) {
where = ch; where -= 192; where <<= 8;
if (pos >= len) goto PROTO; ch = buf[pos++];
if (!firstcompress) firstcompress = pos;
pos = where + ch;
if (pos >= len) goto PROTO; ch = buf[pos++];
if (++loop >= 1000) goto PROTO;
}
if (ch >= 64) goto PROTO;
if (namelen + 1 > sizeof name) goto PROTO; name[namelen++] = ch;
if (!ch) break;
state = ch;
}
}

if (!dns_domain_copy(d,name)) return 0;

if (firstcompress) return firstcompress;
return pos;

PROTO:
errno = EPROTO;
return 0;
}

+ 63
- 0
dns/dns_random.c View File

@@ -0,0 +1,63 @@
#include <unistd.h>
#include "dns.h"
#include "taia.h"
#include "uint32.h"

static uint32 seed[32];
static uint32 in[12];
static uint32 out[8];
static int outleft = 0;

#define ROTATE(x,b) (((x) << (b)) | ((x) >> (32 - (b))))
#define MUSH(i,b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x,b));

static void surf(void)
{
uint32 t[12]; uint32 x; uint32 sum = 0;
int r; int i; int loop;

for (i = 0;i < 12;++i) t[i] = in[i] ^ seed[12 + i];
for (i = 0;i < 8;++i) out[i] = seed[24 + i];
x = t[11];
for (loop = 0;loop < 2;++loop) {
for (r = 0;r < 16;++r) {
sum += 0x9e3779b9;
MUSH(0,5) MUSH(1,7) MUSH(2,9) MUSH(3,13)
MUSH(4,5) MUSH(5,7) MUSH(6,9) MUSH(7,13)
MUSH(8,5) MUSH(9,7) MUSH(10,9) MUSH(11,13)
}
for (i = 0;i < 8;++i) out[i] ^= t[i + 4];
}
}

void dns_random_init(const char data[128])
{
int i;
struct taia t;
char tpack[16];

for (i = 0;i < 32;++i)
uint32_unpack(data + 4 * i,seed + i);

taia_now(&t);
taia_pack(tpack,&t);
for (i = 0;i < 4;++i)
uint32_unpack(tpack + 4 * i,in + 4 + i);

in[8] = getpid();
in[9] = getppid();
/* more space in 10 and 11, but this is probably enough */
}

unsigned int dns_random(unsigned int n)
{
if (!n) return 0;

if (!outleft) {
if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
surf();
outleft = 8;
}

return out[--outleft] % n;
}

+ 85
- 0
dns/dns_rcip.c View File

@@ -0,0 +1,85 @@
#include <stdlib.h>
#include "taia.h"
#include "openreadclose.h"
#include "byte.h"
#include "ip4.h"
#include "ip6.h"
#include "dns.h"

static stralloc data = {0};

static int init(char ip[256])
{
int i;
int j;
int iplen = 0;
char *x;

x = getenv("DNSCACHEIP");
if (x)
while (iplen <= 60) {
if (*x == '.')
++x;
else {
i = scan_ip6(x,ip + iplen);
if (!i) break;
x += i;
iplen += 16;
}
}

if (!iplen) {
i = openreadclose("/etc/resolv.conf",&data,64);
if (i == -1) return -1;
if (i) {
if (!stralloc_append(&data,"\n")) return -1;
i = 0;
for (j = 0;j < data.len;++j)
if (data.s[j] == '\n') {
if (byte_equal("nameserver ",11,data.s + i) || byte_equal("nameserver\t",11,data.s + i)) {
i += 10;
while ((data.s[i] == ' ') || (data.s[i] == '\t'))
++i;
if (iplen <= 60)
if (scan_ip6(data.s + i,ip + iplen)) {
iplen += 16;
}
}
i = j + 1;
}
}
}

if (!iplen) {
byte_copy(ip,16,"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1");
iplen = 16;
}
byte_zero(ip + iplen,256 - iplen);
return 0;
}

static int ok = 0;
static unsigned int uses;
static struct taia deadline;
static char ip[256]; /* defined if ok */

int dns_resolvconfip(char s[256])
{
struct taia now;

taia_now(&now);
if (taia_less(&deadline,&now)) ok = 0;
if (!uses) ok = 0;

if (!ok) {
if (init(ip) == -1) return -1;
taia_uint(&deadline,600);
taia_add(&deadline,&now,&deadline);
uses = 10000;
ok = 1;
}

--uses;
byte_copy(s,256,ip);
return 0;
}

+ 131
- 0
dns/dns_rcrw.c View File

@@ -0,0 +1,131 @@
#include <unistd.h>
#include <stdlib.h>
#include "taia.h"
#include "byte.h"
#include "str.h"
#include "openreadclose.h"
#include "dns.h"

static stralloc data = {0};

static int init(stralloc *rules)
{
char host[256];
const char *x;
int i;
int j;
int k;

if (!stralloc_copys(rules,"")) return -1;

x = getenv("DNSREWRITEFILE");
if (!x) x = "/etc/dnsrewrite";

i = openreadclose(x,&data,64);
if (i == -1) return -1;

if (i) {
if (!stralloc_append(&data,"\n")) return -1;
i = 0;
for (j = 0;j < data.len;++j)
if (data.s[j] == '\n') {
if (!stralloc_catb(rules,data.s + i,j - i)) return -1;
while (rules->len) {
if (rules->s[rules->len - 1] != ' ')
if (rules->s[rules->len - 1] != '\t')
if (rules->s[rules->len - 1] != '\r')
break;
--rules->len;
}
if (!stralloc_0(rules)) return -1;
i = j + 1;
}
return 0;
}

x = getenv("LOCALDOMAIN");
if (x) {
if (!stralloc_copys(&data,x)) return -1;
if (!stralloc_append(&data," ")) return -1;
if (!stralloc_copys(rules,"?:")) return -1;
i = 0;
for (j = 0;j < data.len;++j)
if (data.s[j] == ' ') {
if (!stralloc_cats(rules,"+.")) return -1;
if (!stralloc_catb(rules,data.s + i,j - i)) return -1;
i = j + 1;
}
if (!stralloc_0(rules)) return -1;
if (!stralloc_cats(rules,"*.:")) return -1;
if (!stralloc_0(rules)) return -1;
return 0;
}

i = openreadclose("/etc/resolv.conf",&data,64);
if (i == -1) return -1;

if (i) {
if (!stralloc_append(&data,"\n")) return -1;
i = 0;
for (j = 0;j < data.len;++j)
if (data.s[j] == '\n') {
if (byte_equal("search ",7,data.s + i) || byte_equal("search\t",7,data.s + i) || byte_equal("domain ",7,data.s + i) || byte_equal("domain\t",7,data.s + i)) {
if (!stralloc_copys(rules,"?:")) return -1;
i += 7;
while (i < j) {
k = byte_chr(data.s + i,j - i,' ');
k = byte_chr(data.s + i,k,'\t');
if (!k) { ++i; continue; }
if (!stralloc_cats(rules,"+.")) return -1;
if (!stralloc_catb(rules,data.s + i,k)) return -1;
i += k;
}
if (!stralloc_0(rules)) return -1;
if (!stralloc_cats(rules,"*.:")) return -1;
if (!stralloc_0(rules)) return -1;
return 0;
}
i = j + 1;
}
}

host[0] = 0;
if (gethostname(host,sizeof host) == -1) return -1;
host[(sizeof host) - 1] = 0;
i = str_chr(host,'.');
if (host[i]) {
if (!stralloc_copys(rules,"?:")) return -1;
if (!stralloc_cats(rules,host + i)) return -1;
if (!stralloc_0(rules)) return -1;
}
if (!stralloc_cats(rules,"*.:")) return -1;
if (!stralloc_0(rules)) return -1;

return 0;
}

static int ok = 0;
static unsigned int uses;
static struct taia deadline;
static stralloc rules = {0}; /* defined if ok */

int dns_resolvconfrewrite(stralloc *out)
{
struct taia now;

taia_now(&now);
if (taia_less(&deadline,&now)) ok = 0;
if (!uses) ok = 0;

if (!ok) {
if (init(&rules) == -1) return -1;
taia_uint(&deadline,600);
taia_add(&deadline,&now,&deadline);
uses = 10000;
ok = 1;
}

--uses;
if (!stralloc_copy(out,&rules)) return -1;
return 0;
}

+ 30
- 0
dns/dns_resolve.c View File

@@ -0,0 +1,30 @@
#include "iopause.h"
#include "taia.h"
#include "byte.h"
#include "dns.h"
#include "ip6.h"

struct dns_transmit dns_resolve_tx = {0};

int dns_resolve(const char *q,const char qtype[2])
{
struct taia stamp;
struct taia deadline;
char servers[256];
iopause_fd x[1];
int r;

if (dns_resolvconfip(servers) == -1) return -1;
if (dns_transmit_start(&dns_resolve_tx,servers,1,q,qtype,V6any) == -1) return -1;

for (;;) {
taia_now(&stamp);
taia_uint(&deadline,120);
taia_add(&deadline,&deadline,&stamp);
dns_transmit_io(&dns_resolve_tx,x,&deadline);
iopause(x,1,&deadline,&stamp);
r = dns_transmit_get(&dns_resolve_tx,x,&stamp);
if (r == -1) return -1;
if (r == 1) return 0;
}
}

+ 20
- 0
dns/dns_sortip.c View File

@@ -0,0 +1,20 @@
#include "byte.h"
#include "dns.h"

/* XXX: sort servers by configurable notion of closeness? */
/* XXX: pay attention to competence of each server? */

void dns_sortip(char *s,unsigned int n)
{
unsigned int i;
char tmp[4];

n >>= 2;
while (n > 1) {
i = dns_random(n);
--n;
byte_copy(tmp,4,s + (i << 2));
byte_copy(s + (i << 2),4,s + (n << 2));
byte_copy(s + (n << 2),4,tmp);
}
}

+ 20
- 0
dns/dns_sortip6.c View File

@@ -0,0 +1,20 @@
#include "byte.h"
#include "dns.h"

/* XXX: sort servers by configurable notion of closeness? */
/* XXX: pay attention to competence of each server? */

void dns_sortip6(char *s,unsigned int n)
{
unsigned int i;
char tmp[16];

n >>= 4;
while (n > 1) {
i = dns_random(n);
--n;
byte_copy(tmp,16,s + (i << 4));
byte_copy(s + (i << 4),16,s + (n << 4));
byte_copy(s + (n << 4),16,tmp);
}
}

+ 367
- 0
dns/dns_transmit.c View File

@@ -0,0 +1,367 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include "socket.h"
#include <errno.h>
#include "byte.h"
#include "uint16.h"
#include "dns.h"
#include "ip6.h"

static int serverwantstcp(const char *buf,unsigned int len)
{
char out[12];

if (!dns_packet_copy(buf,len,0,out,12)) return 1;
if (out[2] & 2) return 1;
return 0;
}

static int serverfailed(const char *buf,unsigned int len)
{
char out[12];
unsigned int rcode;

if (!dns_packet_copy(buf,len,0,out,12)) return 1;
rcode = out[3];
rcode &= 15;
if (rcode && (rcode != 3)) { errno = EAGAIN; return 1; }
return 0;
}

static int irrelevant(const struct dns_transmit *d,const char *buf,unsigned int len)
{
char out[12];
char *dn;
unsigned int pos;

pos = dns_packet_copy(buf,len,0,out,12); if (!pos) return 1;
if (byte_diff(out,2,d->query + 2)) return 1;
if (out[4] != 0) return 1;
if (out[5] != 1) return 1;

dn = 0;
pos = dns_packet_getname(buf,len,pos,&dn); if (!pos) return 1;
if (!dns_domain_equal(dn,d->query + 14)) { free(dn); return 1; }
free(dn);

pos = dns_packet_copy(buf,len,pos,out,4); if (!pos) return 1;
if (byte_diff(out,2,d->qtype)) return 1;
if (byte_diff(out + 2,2,DNS_C_IN)) return 1;

return 0;
}

static void packetfree(struct dns_transmit *d)
{
if (!d->packet) return;
free(d->packet);
d->packet = 0;
}

static void queryfree(struct dns_transmit *d)
{
if (!d->query) return;
free(d->query);
d->query = 0;
}

static void socketfree(struct dns_transmit *d)
{
if (!d->s1) return;
close(d->s1 - 1);
d->s1 = 0;
}

void dns_transmit_free(struct dns_transmit *d)
{
queryfree(d);
socketfree(d);
packetfree(d);
}

static int randombind(struct dns_transmit *d)
{
int j;

for (j = 0;j < 10;++j)
if (socket_bind6(d->s1 - 1,d->localip,1025 + dns_random(64510),d->scope_id) == 0)
return 0;
if (socket_bind6(d->s1 - 1,d->localip,0,d->scope_id) == 0)
return 0;
return -1;
}

static const int timeouts[4] = { 1, 3, 11, 45 };

static int thisudp(struct dns_transmit *d)
{
const char *ip;

socketfree(d);

while (d->udploop < 4) {
for (;d->curserver < 16;++d->curserver) {
ip = d->servers + 16 * d->curserver;
if (byte_diff(ip,16,V6any)) {
d->query[2] = dns_random(256);
d->query[3] = dns_random(256);
d->s1 = 1 + socket_udp6();
if (!d->s1) { dns_transmit_free(d); return -1; }
if (randombind(d) == -1) { dns_transmit_free(d); return -1; }

if (socket_connect6(d->s1 - 1,ip,53,d->scope_id) == 0)
if (send(d->s1 - 1,d->query + 2,d->querylen - 2,0) == d->querylen - 2) {
struct taia now;
taia_now(&now);
taia_uint(&d->deadline,timeouts[d->udploop]);
taia_add(&d->deadline,&d->deadline,&now);
d->tcpstate = 0;
return 0;
}
socketfree(d);
}
}

++d->udploop;
d->curserver = 0;
}

dns_transmit_free(d); return -1;
}

static int firstudp(struct dns_transmit *d)
{
d->curserver = 0;
return thisudp(d);
}

static int nextudp(struct dns_transmit *d)
{
++d->curserver;
return thisudp(d);
}

static int thistcp(struct dns_transmit *d)
{
struct taia now;
const char *ip;

socketfree(d);
packetfree(d);

for (;d->curserver < 16;++d->curserver) {
ip = d->servers + 16 * d->curserver;
if (byte_diff(ip,16,V6any)) {
d->query[2] = dns_random(256);
d->query[3] = dns_random(256);

d->s1 = 1 + socket_tcp6();
if (!d->s1) { dns_transmit_free(d); return -1; }
if (randombind(d) == -1) { dns_transmit_free(d); return -1; }
taia_now(&now);
taia_uint(&d->deadline,10);
taia_add(&d->deadline,&d->deadline,&now);
if (socket_connect6(d->s1 - 1,ip,53,d->scope_id) == 0) {
d->tcpstate = 2;
return 0;
}
if ((errno == EINPROGRESS) || (errno == EWOULDBLOCK)) {
d->tcpstate = 1;
return 0;
}
socketfree(d);
}
}

dns_transmit_free(d); return -1;
}

static int firsttcp(struct dns_transmit *d)
{
d->curserver = 0;
return thistcp(d);
}

static int nexttcp(struct dns_transmit *d)
{
++d->curserver;
return thistcp(d);
}

int dns_transmit_start(struct dns_transmit *d,const char servers[256],int flagrecursive,const char *q,const char qtype[2],const char localip[16])
{
unsigned int len;

dns_transmit_free(d);
errno = EIO;

len = dns_domain_length(q);
d->querylen = len + 18;
d->query = malloc(d->querylen);
if (!d->query) return -1;

uint16_pack_big(d->query,len + 16);
byte_copy(d->query + 2,12,flagrecursive ? "\0\0\1\0\0\1\0\0\0\0\0\0" : "\0\0\0\0\0\1\0\0\0\0\0\0gcc-bug-workaround");
byte_copy(d->query + 14,len,q);
byte_copy(d->query + 14 + len,2,qtype);
byte_copy(d->query + 16 + len,2,DNS_C_IN);

byte_copy(d->qtype,2,qtype);
d->servers = servers;
byte_copy(d->localip,16,localip);

d->udploop = flagrecursive ? 1 : 0;

if (len + 16 > 512) return firsttcp(d);
return firstudp(d);
}

void dns_transmit_io(struct dns_transmit *d,iopause_fd *x,struct taia *deadline)
{
x->fd = d->s1 - 1;

switch(d->tcpstate) {
case 0: case 3: case 4: case 5:
x->events = IOPAUSE_READ;
break;
case 1: case 2:
x->events = IOPAUSE_WRITE;
break;
}

if (taia_less(&d->deadline,deadline))
*deadline = d->deadline;
}

int dns_transmit_get(struct dns_transmit *d,const iopause_fd *x,const struct taia *when)
{
char udpbuf[513];
unsigned char ch;
int r;
int fd;

errno = EIO;
fd = d->s1 - 1;

if (!x->revents) {
if (taia_less(when,&d->deadline)) return 0;
errno = ETIMEDOUT;
if (d->tcpstate == 0) return nextudp(d);
return nexttcp(d);
}

if (d->tcpstate == 0) {
/*
have attempted to send UDP query to each server udploop times
have sent query to curserver on UDP socket s
*/
r = recv(fd,udpbuf,sizeof udpbuf,0);
if (r <= 0) {
if (errno == ECONNREFUSED) if (d->udploop == 2) return 0;
return nextudp(d);
}
if (r + 1 > sizeof udpbuf) return 0;

if (irrelevant(d,udpbuf,r)) return 0;
if (serverwantstcp(udpbuf,r)) return firsttcp(d);
if (serverfailed(udpbuf,r)) {
if (d->udploop == 2) return 0;
return nextudp(d);
}
socketfree(d);

d->packetlen = r;
d->packet = malloc(d->packetlen);
if (!d->packet) { dns_transmit_free(d); return -1; }
byte_copy(d->packet,d->packetlen,udpbuf);
queryfree(d);
return 1;
}

if (d->tcpstate == 1) {
/*
have sent connection attempt to curserver on TCP socket s
pos not defined
*/
if (!socket_connected(fd)) return nexttcp(d);
d->pos = 0;
d->tcpstate = 2;
return 0;
}

if (d->tcpstate == 2) {
/*
have connection to curserver on TCP socket s
have sent pos bytes of query
*/
r = write(fd,d->query + d->pos,d->querylen - d->pos);
if (r <= 0) return nexttcp(d);
d->pos += r;
if (d->pos == d->querylen) {
struct taia now;
taia_now(&now);
taia_uint(&d->deadline,10);
taia_add(&d->deadline,&d->deadline,&now);
d->tcpstate = 3;
}
return 0;
}

if (d->tcpstate == 3) {
/*
have sent entire query to curserver on TCP socket s
pos not defined
*/
r = read(fd,&ch,1);
if (r <= 0) return nexttcp(d);
d->packetlen = ch;
d->tcpstate = 4;
return 0;
}

if (d->tcpstate == 4) {
/*
have sent entire query to curserver on TCP socket s
pos not defined
have received one byte of packet length into packetlen
*/
r = read(fd,&ch,1);
if (r <= 0) return nexttcp(d);
d->packetlen <<= 8;
d->packetlen += ch;
d->tcpstate = 5;
d->pos = 0;
d->packet = malloc(d->packetlen);
if (!d->packet) { dns_transmit_free(d); return -1; }
return 0;
}

if (d->tcpstate == 5) {
/*
have sent entire query to curserver on TCP socket s
have received entire packet length into packetlen
packet is allocated
have received pos bytes of packet
*/
r = read(fd,d->packet + d->pos,d->packetlen - d->pos);
if (r <= 0) return nexttcp(d);
d->pos += r;
if (d->pos < d->packetlen) return 0;

socketfree(d);
if (irrelevant(d,d->packet,d->packetlen)) return nexttcp(d);
if (serverwantstcp(d->packet,d->packetlen)) return nexttcp(d);
if (serverfailed(d->packet,d->packetlen)) return nexttcp(d);

queryfree(d);
return 1;
}

return 0;
}

+ 59
- 0
dns/dns_txt.c View File

@@ -0,0 +1,59 @@
#include "stralloc.h"
#include "uint16.h"
#include "byte.h"
#include "dns.h"

int dns_txt_packet(stralloc *out,const char *buf,unsigned int len)
{
unsigned int pos;
char header[12];
uint16 numanswers;
uint16 datalen;
char ch;
unsigned int txtlen;
int i;

if (!stralloc_copys(out,"")) return -1;

pos = dns_packet_copy(buf,len,0,header,12); if (!pos) return -1;
uint16_unpack_big(header + 6,&numanswers);
pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1;
pos += 4;

while (numanswers--) {
pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1;
pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) return -1;
uint16_unpack_big(header + 8,&datalen);
if (byte_equal(header,2,DNS_T_TXT))
if (byte_equal(header + 2,2,DNS_C_IN)) {
if (pos + datalen > len) return -1;
txtlen = 0;
for (i = 0;i < datalen;++i) {
ch = buf[pos + i];
if (!txtlen)
txtlen = (unsigned char) ch;
else {
--txtlen;
if (ch < 32) ch = '?';
if (ch > 126) ch = '?';
if (!stralloc_append(out,&ch)) return -1;
}
}
}
pos += datalen;
}

return 0;
}

static char *q = 0;

int dns_txt(stralloc *out,const stralloc *fqdn)
{
if (!dns_domain_fromdot(&q,fqdn->s,fqdn->len)) return -1;
if (dns_resolve(q,DNS_T_TXT) == -1) return -1;
if (dns_txt_packet(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) == -1) return -1;
dns_transmit_free(&dns_resolve_tx);
dns_domain_free(&q);
return 0;
}

+ 19
- 0
iopause.h1 View File

@@ -0,0 +1,19 @@
#ifndef IOPAUSE_H
#define IOPAUSE_H

/* sysdep: -poll */

typedef struct {
int fd;
short events;
short revents;
} iopause_fd;

#define IOPAUSE_READ 1
#define IOPAUSE_WRITE 4

#include "taia.h"

extern void iopause(iopause_fd *,unsigned int,struct taia *,struct taia *);

#endif

+ 18
- 0
iopause.h2 View File

@@ -0,0 +1,18 @@
#ifndef IOPAUSE_H
#define IOPAUSE_H

/* sysdep: +poll */
#define IOPAUSE_POLL

#include <sys/types.h>
#include <poll.h>

typedef struct pollfd iopause_fd;
#define IOPAUSE_READ POLLIN
#define IOPAUSE_WRITE POLLOUT

#include "taia.h"

extern void iopause(iopause_fd *,unsigned int,struct taia *,struct taia *);

#endif

+ 16
- 0
open/openreadclose.c View File

@@ -0,0 +1,16 @@
#include <errno.h>
#include "open.h"
#include "readclose.h"
#include "openreadclose.h"

int openreadclose(const char *fn,stralloc *sa,unsigned int bufsize)
{
int fd;
fd = open_read(fn);
if (fd == -1) {
if (errno == ENOENT) return 0;
return -1;
}
if (readclose(fd,sa,bufsize) == -1) return -1;
return 1;
}

+ 21
- 0
open/readclose.c View File

@@ -0,0 +1,21 @@
#include <unistd.h>
#include <errno.h>
#include "readclose.h"

int readclose_append(int fd,stralloc *sa,unsigned int bufsize)
{
int r;
for (;;) {
if (!stralloc_readyplus(sa,bufsize)) { close(fd); return -1; }
r = read(fd,sa->s + sa->len,bufsize);
if (r == -1) if (errno == EINTR) continue;
if (r <= 0) { close(fd); return r; }
sa->len += r;
}
}

int readclose(int fd,stralloc *sa,unsigned int bufsize)
{
if (!stralloc_copys(sa,"")) { close(fd); return -1; }
return readclose_append(fd,sa,bufsize);
}

+ 8
- 0
openreadclose.h View File

@@ -0,0 +1,8 @@
#ifndef OPENREADCLOSE_H
#define OPENREADCLOSE_H

#include "stralloc.h"

extern int openreadclose(const char *filename,stralloc *buf,unsigned int initiallength);

#endif

+ 9
- 0
readclose.h View File

@@ -0,0 +1,9 @@
#ifndef READCLOSE_H
#define READCLOSE_H

#include "stralloc.h"

extern int readclose_append(int fd,stralloc *buf,unsigned int initlen);
extern int readclose(int fd,stralloc *buf,unsigned int initlen);

#endif

+ 3
- 0
scan.h View File

@@ -1,7 +1,10 @@
#ifndef SCAN_H
#define SCAN_H

#ifdef __dietlibc__
#include <sys/cdefs.h>
#endif

#ifndef __pure__
#define __pure__
#endif


+ 10
- 0
select.h1 View File

@@ -0,0 +1,10 @@
#ifndef SELECT_H
#define SELECT_H

/* sysdep: -sysselect */

#include <sys/types.h>
#include <sys/time.h>
extern int select();

#endif

+ 11
- 0
select.h2 View File

@@ -0,0 +1,11 @@
#ifndef SELECT_H
#define SELECT_H

/* sysdep: +sysselect */

#include <sys/types.h>
#include <sys/time.h>
#include <sys/select.h>
extern int select();

#endif

+ 2
- 0
str.h View File

@@ -1,7 +1,9 @@
#ifndef STR_H
#define STR_H

#ifdef __dietlibc__
#include <sys/cdefs.h>
#endif
#ifndef __pure__
#define __pure__
#endif


+ 1
- 3
stralloc.h View File

@@ -1,8 +1,6 @@
#ifndef STRALLOC_H
#define STRALLOC_H

#include <sys/cdefs.h>

/* stralloc is the internal data structure all functions are working on.
* s is the string.
* len is the used length of the string.
@@ -41,7 +39,7 @@ extern int stralloc_copys(stralloc* sa,const char* buf);

/* stralloc_copy copies the string stored in sa2 into sa. It is the same
* as stralloc_copyb(&sa,sa2.s,sa2.len). sa2 must already be allocated. */
extern int stralloc_copy(stralloc* sa,stralloc* sa2);
extern int stralloc_copy(stralloc* sa,const stralloc* sa2);

/* stralloc_catb adds the string buf[0], buf[1], ... buf[len-1] to the
* end of the string stored in sa, allocating space if necessary, and


+ 1
- 1
stralloc/stralloc_copy.c View File

@@ -1,7 +1,7 @@
#include "stralloc.h"
#include "str.h"

extern int stralloc_copy(stralloc *sa,stralloc *sa2) {
extern int stralloc_copy(stralloc *sa,const stralloc *sa2) {
return stralloc_copyb(sa,sa2->s,sa2->len);
}


+ 42
- 0
t.c View File

<
@@ -11,15 +11,57 @@
#include "open.h"
#include "byte.h"
#include "textcode.h"
#include "dns.h"
#include "case.h"
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

#define rdtscl(low) \
__asm__ __volatile__ ("rdtsc" : "=a" (low) : : "edx")

int main(int argc,char* argv[]) {
static char seed[128];
static stralloc fqdn;
static stralloc out;
char str[IP4_FMT];
int i;

dns_random_init(seed);
if (*argv) ++argv;
while (*argv) {
if (!stralloc_copys(&fqdn,*argv)) {
buffer_putsflush(buffer_2,"out of memory\n");