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

master
Felix von Leitner 21 years ago
parent ffde3478a0
commit 051de3819a

@ -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 \

@ -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.

@ -1,7 +1,9 @@
#ifndef BYTE_H
#define BYTE_H
#ifdef __dietlibc__
#include <sys/cdefs.h>
#endif
#ifndef __pure__
#define __pure__

@ -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

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

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

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

@ -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
dns.h

@ -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

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

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

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

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

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

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

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

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

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

@ -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");
}

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

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

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

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

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

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