From f921b8cbb09f5f1aac334ae0c56dce06e03ca65b Mon Sep 17 00:00:00 2001 From: leitner Date: Mon, 16 Sep 2002 01:09:56 +0000 Subject: [PATCH] monster update: add tai, taia, iopause, case, and ipv6 enhanced dns --- Makefile | 58 +++++-- README | 24 +++ byte.h | 2 + case.h | 21 +++ case/case_diffb.c | 18 ++ case/case_diffs.c | 17 ++ case/case_lowerb.c | 11 ++ case/case_lowers.c | 10 ++ dns.h | 93 ++++++++++ dns/dns_dfd.c | 69 ++++++++ dns/dns_domain.c | 73 ++++++++ dns/dns_dtda.c | 35 ++++ dns/dns_ip.c | 75 ++++++++ dns/dns_ip6.c | 103 +++++++++++ dns/dns_ipq.c | 71 ++++++++ dns/dns_ipq6.c | 72 ++++++++ dns/dns_mx.c | 49 ++++++ dns/dns_name.c | 63 +++++++ dns/dns_nd.c | 24 +++ dns/dns_nd6.c | 28 +++ dns/dns_packet.c | 77 ++++++++ dns/dns_random.c | 63 +++++++ dns/dns_rcip.c | 85 +++++++++ dns/dns_rcrw.c | 131 ++++++++++++++ dns/dns_resolve.c | 30 ++++ dns/dns_sortip.c | 20 +++ dns/dns_sortip6.c | 20 +++ dns/dns_transmit.c | 367 +++++++++++++++++++++++++++++++++++++++ dns/dns_txt.c | 59 +++++++ iopause.h1 | 19 ++ iopause.h2 | 18 ++ open/openreadclose.c | 16 ++ open/readclose.c | 21 +++ openreadclose.h | 8 + readclose.h | 9 + scan.h | 3 + select.h1 | 10 ++ select.h2 | 11 ++ str.h | 2 + stralloc.h | 4 +- stralloc/stralloc_copy.c | 2 +- t.c | 42 +++++ tai.h | 26 +++ tai/tai_add.c | 6 + tai/tai_now.c | 7 + tai/tai_pack.c | 16 ++ tai/tai_sub.c | 6 + tai/tai_uint.c | 6 + tai/tai_unpack.c | 16 ++ taia.h | 68 ++++++++ taia/taia_add.c | 18 ++ taia/taia_approx.c | 6 + taia/taia_frac.c | 6 + taia/taia_less.c | 12 ++ taia/taia_now.c | 12 ++ taia/taia_pack.c | 20 +++ taia/taia_sub.c | 21 +++ taia/taia_tai.c | 6 + taia/taia_uint.c | 10 ++ trypoll.c | 18 ++ trysysel.c | 8 + uint64.h | 6 - unix/iopause.c | 76 ++++++++ 63 files changed, 2280 insertions(+), 23 deletions(-) create mode 100644 README create mode 100644 case.h create mode 100644 case/case_diffb.c create mode 100644 case/case_diffs.c create mode 100644 case/case_lowerb.c create mode 100644 case/case_lowers.c create mode 100644 dns.h create mode 100644 dns/dns_dfd.c create mode 100644 dns/dns_domain.c create mode 100644 dns/dns_dtda.c create mode 100644 dns/dns_ip.c create mode 100644 dns/dns_ip6.c create mode 100644 dns/dns_ipq.c create mode 100644 dns/dns_ipq6.c create mode 100644 dns/dns_mx.c create mode 100644 dns/dns_name.c create mode 100644 dns/dns_nd.c create mode 100644 dns/dns_nd6.c create mode 100644 dns/dns_packet.c create mode 100644 dns/dns_random.c create mode 100644 dns/dns_rcip.c create mode 100644 dns/dns_rcrw.c create mode 100644 dns/dns_resolve.c create mode 100644 dns/dns_sortip.c create mode 100644 dns/dns_sortip6.c create mode 100644 dns/dns_transmit.c create mode 100644 dns/dns_txt.c create mode 100644 iopause.h1 create mode 100644 iopause.h2 create mode 100644 open/openreadclose.c create mode 100644 open/readclose.c create mode 100644 openreadclose.h create mode 100644 readclose.h create mode 100644 select.h1 create mode 100644 select.h2 create mode 100644 tai.h create mode 100644 tai/tai_add.c create mode 100644 tai/tai_now.c create mode 100644 tai/tai_pack.c create mode 100644 tai/tai_sub.c create mode 100644 tai/tai_uint.c create mode 100644 tai/tai_unpack.c create mode 100644 taia.h create mode 100644 taia/taia_add.c create mode 100644 taia/taia_approx.c create mode 100644 taia/taia_frac.c create mode 100644 taia/taia_less.c create mode 100644 taia/taia_now.c create mode 100644 taia/taia_pack.c create mode 100644 taia/taia_sub.c create mode 100644 taia/taia_tai.c create mode 100644 taia/taia_uint.c create mode 100644 trypoll.c create mode 100644 trysysel.c create mode 100644 unix/iopause.c diff --git a/Makefile b/Makefile index 7107338..4b375ee 100644 --- a/Makefile +++ b/Makefile @@ -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 \ diff --git a/README b/README new file mode 100644 index 0000000..7dd1e39 --- /dev/null +++ b/README @@ -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. diff --git a/byte.h b/byte.h index b1df0ee..04b9ac3 100644 --- a/byte.h +++ b/byte.h @@ -1,7 +1,9 @@ #ifndef BYTE_H #define BYTE_H +#ifdef __dietlibc__ #include +#endif #ifndef __pure__ #define __pure__ diff --git a/case.h b/case.h new file mode 100644 index 0000000..27049b0 --- /dev/null +++ b/case.h @@ -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 diff --git a/case/case_diffb.c b/case/case_diffb.c new file mode 100644 index 0000000..b62a4b2 --- /dev/null +++ b/case/case_diffb.c @@ -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; +} diff --git a/case/case_diffs.c b/case/case_diffs.c new file mode 100644 index 0000000..683977a --- /dev/null +++ b/case/case_diffs.c @@ -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); +} diff --git a/case/case_lowerb.c b/case/case_lowerb.c new file mode 100644 index 0000000..eac86e2 --- /dev/null +++ b/case/case_lowerb.c @@ -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; + } +} diff --git a/case/case_lowers.c b/case/case_lowers.c new file mode 100644 index 0000000..774b97a --- /dev/null +++ b/case/case_lowers.c @@ -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; + } +} diff --git a/dns.h b/dns.h new file mode 100644 index 0000000..6827512 --- /dev/null +++ b/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 diff --git a/dns/dns_dfd.c b/dns/dns_dfd.c new file mode 100644 index 0000000..b98646e --- /dev/null +++ b/dns/dns_dfd.c @@ -0,0 +1,69 @@ +#include +#include +#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; +} diff --git a/dns/dns_domain.c b/dns/dns_domain.c new file mode 100644 index 0000000..80ac5ea --- /dev/null +++ b/dns/dns_domain.c @@ -0,0 +1,73 @@ +#include +#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; + } +} diff --git a/dns/dns_dtda.c b/dns/dns_dtda.c new file mode 100644 index 0000000..ba1db4f --- /dev/null +++ b/dns/dns_dtda.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; + } +} diff --git a/dns/dns_ip.c b/dns/dns_ip.c new file mode 100644 index 0000000..e7c3a9a --- /dev/null +++ b/dns/dns_ip.c @@ -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; +} diff --git a/dns/dns_ip6.c b/dns/dns_ip6.c new file mode 100644 index 0000000..8df7f82 --- /dev/null +++ b/dns/dns_ip6.c @@ -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; +} diff --git a/dns/dns_ipq.c b/dns/dns_ipq.c new file mode 100644 index 0000000..5b65e23 --- /dev/null +++ b/dns/dns_ipq.c @@ -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); +} diff --git a/dns/dns_ipq6.c b/dns/dns_ipq6.c new file mode 100644 index 0000000..d5cea12 --- /dev/null +++ b/dns/dns_ipq6.c @@ -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); +} diff --git a/dns/dns_mx.c b/dns/dns_mx.c new file mode 100644 index 0000000..8d38a7f --- /dev/null +++ b/dns/dns_mx.c @@ -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; +} diff --git a/dns/dns_name.c b/dns/dns_name.c new file mode 100644 index 0000000..1f03186 --- /dev/null +++ b/dns/dns_name.c @@ -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; +} diff --git a/dns/dns_nd.c b/dns/dns_nd.c new file mode 100644 index 0000000..aa54e5d --- /dev/null +++ b/dns/dns_nd.c @@ -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"); +} diff --git a/dns/dns_nd6.c b/dns/dns_nd6.c new file mode 100644 index 0000000..68522cb --- /dev/null +++ b/dns/dns_nd6.c @@ -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; +} + diff --git a/dns/dns_packet.c b/dns/dns_packet.c new file mode 100644 index 0000000..d548cb0 --- /dev/null +++ b/dns/dns_packet.c @@ -0,0 +1,77 @@ +/* +DNS should have used LZ77 instead of its own sophomoric compression algorithm. +*/ + +#include +#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; +} diff --git a/dns/dns_random.c b/dns/dns_random.c new file mode 100644 index 0000000..2158ed4 --- /dev/null +++ b/dns/dns_random.c @@ -0,0 +1,63 @@ +#include +#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; +} diff --git a/dns/dns_rcip.c b/dns/dns_rcip.c new file mode 100644 index 0000000..a127d4a --- /dev/null +++ b/dns/dns_rcip.c @@ -0,0 +1,85 @@ +#include +#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; +} diff --git a/dns/dns_rcrw.c b/dns/dns_rcrw.c new file mode 100644 index 0000000..26262a1 --- /dev/null +++ b/dns/dns_rcrw.c @@ -0,0 +1,131 @@ +#include +#include +#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; +} diff --git a/dns/dns_resolve.c b/dns/dns_resolve.c new file mode 100644 index 0000000..82b5bbb --- /dev/null +++ b/dns/dns_resolve.c @@ -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; + } +} diff --git a/dns/dns_sortip.c b/dns/dns_sortip.c new file mode 100644 index 0000000..af9b235 --- /dev/null +++ b/dns/dns_sortip.c @@ -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); + } +} diff --git a/dns/dns_sortip6.c b/dns/dns_sortip6.c new file mode 100644 index 0000000..7e752e9 --- /dev/null +++ b/dns/dns_sortip6.c @@ -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); + } +} diff --git a/dns/dns_transmit.c b/dns/dns_transmit.c new file mode 100644 index 0000000..9511511 --- /dev/null +++ b/dns/dns_transmit.c @@ -0,0 +1,367 @@ +#include +#include +#include +#include +#include "socket.h" +#include +#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; +} diff --git a/dns/dns_txt.c b/dns/dns_txt.c new file mode 100644 index 0000000..44deafe --- /dev/null +++ b/dns/dns_txt.c @@ -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; +} diff --git a/iopause.h1 b/iopause.h1 new file mode 100644 index 0000000..dae0a33 --- /dev/null +++ b/iopause.h1 @@ -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 diff --git a/iopause.h2 b/iopause.h2 new file mode 100644 index 0000000..2cf5cf8 --- /dev/null +++ b/iopause.h2 @@ -0,0 +1,18 @@ +#ifndef IOPAUSE_H +#define IOPAUSE_H + +/* sysdep: +poll */ +#define IOPAUSE_POLL + +#include +#include + +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 diff --git a/open/openreadclose.c b/open/openreadclose.c new file mode 100644 index 0000000..6c881f9 --- /dev/null +++ b/open/openreadclose.c @@ -0,0 +1,16 @@ +#include +#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; +} diff --git a/open/readclose.c b/open/readclose.c new file mode 100644 index 0000000..9ca110b --- /dev/null +++ b/open/readclose.c @@ -0,0 +1,21 @@ +#include +#include +#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); +} diff --git a/openreadclose.h b/openreadclose.h new file mode 100644 index 0000000..31c54f3 --- /dev/null +++ b/openreadclose.h @@ -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 diff --git a/readclose.h b/readclose.h new file mode 100644 index 0000000..409a02a --- /dev/null +++ b/readclose.h @@ -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 diff --git a/scan.h b/scan.h index d2d2fd3..be8fbae 100644 --- a/scan.h +++ b/scan.h @@ -1,7 +1,10 @@ #ifndef SCAN_H #define SCAN_H +#ifdef __dietlibc__ #include +#endif + #ifndef __pure__ #define __pure__ #endif diff --git a/select.h1 b/select.h1 new file mode 100644 index 0000000..fe725b6 --- /dev/null +++ b/select.h1 @@ -0,0 +1,10 @@ +#ifndef SELECT_H +#define SELECT_H + +/* sysdep: -sysselect */ + +#include +#include +extern int select(); + +#endif diff --git a/select.h2 b/select.h2 new file mode 100644 index 0000000..2bc2044 --- /dev/null +++ b/select.h2 @@ -0,0 +1,11 @@ +#ifndef SELECT_H +#define SELECT_H + +/* sysdep: +sysselect */ + +#include +#include +#include +extern int select(); + +#endif diff --git a/str.h b/str.h index 5d59345..a0f0229 100644 --- a/str.h +++ b/str.h @@ -1,7 +1,9 @@ #ifndef STR_H #define STR_H +#ifdef __dietlibc__ #include +#endif #ifndef __pure__ #define __pure__ #endif diff --git a/stralloc.h b/stralloc.h index 361d3fa..5bd63e6 100644 --- a/stralloc.h +++ b/stralloc.h @@ -1,8 +1,6 @@ #ifndef STRALLOC_H #define STRALLOC_H -#include - /* 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 diff --git a/stralloc/stralloc_copy.c b/stralloc/stralloc_copy.c index 3504e68..1c5b731 100644 --- a/stralloc/stralloc_copy.c +++ b/stralloc/stralloc_copy.c @@ -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); } diff --git a/t.c b/t.c index d629a47..f5ba1f3 100644 --- a/t.c +++ b/t.c @@ -11,15 +11,57 @@ #include "open.h" #include "byte.h" #include "textcode.h" +#include "dns.h" +#include "case.h" #include #include +#include +#include #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"); + return 111; + } + if (dns_ip4(&out,&fqdn) == -1) { + buffer_puts(buffer_2,"unable to find IP address for "); + buffer_puts(buffer_2,*argv); + buffer_puts(buffer_2,": "); + buffer_puts(buffer_2,strerror(errno)); + buffer_putnlflush(buffer_2); + return 111; + } + + for (i = 0;i + 4 <= out.len;i += 4) { + buffer_put(buffer_1,str,ip4_fmt(str,out.s + i)); + buffer_puts(buffer_1," "); + } + buffer_puts(buffer_1,"\n"); + ++argv; + } + buffer_flush(buffer_1); + return 0; +#if 0 + char buf[]="FnOrD"; + case_lowers(buf); + puts(buf); +#endif +#if 0 char buf[100]="foo bar baz"; printf("%d (expect 7)\n",byte_rchr(buf,11,' ')); +#endif #if 0 unsigned long size; char* buf=mmap_read(argv[1],&size); diff --git a/tai.h b/tai.h new file mode 100644 index 0000000..b8db5e5 --- /dev/null +++ b/tai.h @@ -0,0 +1,26 @@ +#ifndef TAI_H +#define TAI_H + +#include "uint64.h" + +struct tai { + uint64 x; +} ; + +#define tai_unix(t,u) ((void) ((t)->x = 4611686018427387914ULL + (uint64) (u))) + +extern void tai_now(struct tai *); + +#define tai_approx(t) ((double) ((t)->x)) + +extern void tai_add(struct tai *,const struct tai *,const struct tai *); +extern void tai_sub(struct tai *,const struct tai *,const struct tai *); +#define tai_less(t,u) ((t)->x < (u)->x) + +#define TAI_PACK 8 +extern void tai_pack(char *,const struct tai *); +extern void tai_unpack(const char *,struct tai *); + +extern void tai_uint(struct tai *,unsigned int); + +#endif diff --git a/tai/tai_add.c b/tai/tai_add.c new file mode 100644 index 0000000..4226ab4 --- /dev/null +++ b/tai/tai_add.c @@ -0,0 +1,6 @@ +#include "tai.h" + +void tai_add(struct tai *t,const struct tai *u,const struct tai *v) +{ + t->x = u->x + v->x; +} diff --git a/tai/tai_now.c b/tai/tai_now.c new file mode 100644 index 0000000..91e84da --- /dev/null +++ b/tai/tai_now.c @@ -0,0 +1,7 @@ +#include +#include "tai.h" + +void tai_now(struct tai *t) +{ + tai_unix(t,time((time_t *) 0)); +} diff --git a/tai/tai_pack.c b/tai/tai_pack.c new file mode 100644 index 0000000..0a2bc06 --- /dev/null +++ b/tai/tai_pack.c @@ -0,0 +1,16 @@ +#include "tai.h" + +void tai_pack(char *s,const struct tai *t) +{ + uint64 x; + + x = t->x; + s[7] = x & 255; x >>= 8; + s[6] = x & 255; x >>= 8; + s[5] = x & 255; x >>= 8; + s[4] = x & 255; x >>= 8; + s[3] = x & 255; x >>= 8; + s[2] = x & 255; x >>= 8; + s[1] = x & 255; x >>= 8; + s[0] = x; +} diff --git a/tai/tai_sub.c b/tai/tai_sub.c new file mode 100644 index 0000000..6ebf7b2 --- /dev/null +++ b/tai/tai_sub.c @@ -0,0 +1,6 @@ +#include "tai.h" + +void tai_sub(struct tai *t,const struct tai *u,const struct tai *v) +{ + t->x = u->x - v->x; +} diff --git a/tai/tai_uint.c b/tai/tai_uint.c new file mode 100644 index 0000000..b01184c --- /dev/null +++ b/tai/tai_uint.c @@ -0,0 +1,6 @@ +#include "tai.h" + +void tai_uint(struct tai *t,unsigned int u) +{ + t->x = u; +} diff --git a/tai/tai_unpack.c b/tai/tai_unpack.c new file mode 100644 index 0000000..b725ae0 --- /dev/null +++ b/tai/tai_unpack.c @@ -0,0 +1,16 @@ +#include "tai.h" + +void tai_unpack(const char *s,struct tai *t) +{ + uint64 x; + + x = (unsigned char) s[0]; + x <<= 8; x += (unsigned char) s[1]; + x <<= 8; x += (unsigned char) s[2]; + x <<= 8; x += (unsigned char) s[3]; + x <<= 8; x += (unsigned char) s[4]; + x <<= 8; x += (unsigned char) s[5]; + x <<= 8; x += (unsigned char) s[6]; + x <<= 8; x += (unsigned char) s[7]; + t->x = x; +} diff --git a/taia.h b/taia.h new file mode 100644 index 0000000..fc0e98d --- /dev/null +++ b/taia.h @@ -0,0 +1,68 @@ +#ifndef TAIA_H +#define TAIA_H + +/* Times with 1 attosecond precision */ + +#include "tai.h" + +/* A struct taia value is a number between 0 inclusive and 2^64 + * exclusive. The number is a multiple of 10^-18. The format of struct + * taia is designed to speed up common operations; applications should + * not look inside struct taia. */ +struct taia { + struct tai sec; + unsigned long nano; /* 0...999999999 */ + unsigned long atto; /* 0...999999999 */ +}; + +/* extract seconds */ +extern void taia_tai(const struct taia *source,struct tai *dest); + +/* get current time */ +extern void taia_now(struct taia *); + +/* return double-precision approximation; always nonnegative */ +extern double taia_approx(const struct taia *); +/* return double-precision approximation of the fraction part; + * always nonnegative */ +extern double taia_frac(const struct taia *); + +/* add source1 to source2 modulo 2^64 and put the result in dest. + * The inputs and output may overlap */ +extern void taia_add(struct taia *dest,const struct taia *source1,const struct taia *source2); +/* add secs seconds to source modulo 2^64 and put the result in dest. */ +extern void taia_addsec(struct taia *dest,const struct taia *source,int secs); +/* subtract source2 from source1 modulo 2^64 and put the result in dest. + * The inputs and output may overlap */ +extern void taia_sub(struct taia *,const struct taia *,const struct taia *); +/* divide source by 2, rouding down to a multiple of 10^-18, and put the + * result into dest. The input and output may overlap */ +extern void taia_half(struct taia *dest,const struct taia *source); +/* return 1 if a is less than b, 0 otherwise */ +extern int taia_less(const struct taia *a,const struct taia *b); + +#define TAIA_PACK 16 +/* char buf[TAIA_PACK] can be used to store a TAI64NA label in external + * representation, which can then be used to transmit the binary + * representation over a network or store it on disk in a byte order + * independent fashion */ + +/* convert a TAI64NA label from internal format in src to external + * TAI64NA format in buf. */ +extern void taia_pack(char *buf,const struct taia *src); +/* convert a TAI64NA label from external TAI64NA format in buf to + * internal format in dest. */ +extern void taia_unpack(const char *buf,struct taia *dest); + +#define TAIA_FMTFRAC 19 +/* print the 18-digit fraction part of t in decimal, without a decimal + * point but with leading zeros, into the character buffer s, without a + * terminating \0. It returns 18, the number of characters written. s + * may be zero; then taia_fmtfrac returns 18 without printing anything. + * */ +extern unsigned int taia_fmtfrac(char *s,const struct taia *t); + +/* initialize t to secs seconds. */ +extern void taia_uint(struct taia *t,unsigned int secs); + +#endif diff --git a/taia/taia_add.c b/taia/taia_add.c new file mode 100644 index 0000000..3044a26 --- /dev/null +++ b/taia/taia_add.c @@ -0,0 +1,18 @@ +#include "taia.h" + +/* XXX: breaks tai encapsulation */ + +void taia_add(struct taia *t,const struct taia *u,const struct taia *v) +{ + t->sec.x = u->sec.x + v->sec.x; + t->nano = u->nano + v->nano; + t->atto = u->atto + v->atto; + if (t->atto > 999999999UL) { + t->atto -= 1000000000UL; + ++t->nano; + } + if (t->nano > 999999999UL) { + t->nano -= 1000000000UL; + ++t->sec.x; + } +} diff --git a/taia/taia_approx.c b/taia/taia_approx.c new file mode 100644 index 0000000..2a3b429 --- /dev/null +++ b/taia/taia_approx.c @@ -0,0 +1,6 @@ +#include "taia.h" + +double taia_approx(const struct taia *t) +{ + return tai_approx(&t->sec) + taia_frac(t); +} diff --git a/taia/taia_frac.c b/taia/taia_frac.c new file mode 100644 index 0000000..b6b48bc --- /dev/null +++ b/taia/taia_frac.c @@ -0,0 +1,6 @@ +#include "taia.h" + +double taia_frac(const struct taia *t) +{ + return (t->atto * 0.000000001 + t->nano) * 0.000000001; +} diff --git a/taia/taia_less.c b/taia/taia_less.c new file mode 100644 index 0000000..2d889c8 --- /dev/null +++ b/taia/taia_less.c @@ -0,0 +1,12 @@ +#include "taia.h" + +/* XXX: breaks tai encapsulation */ + +int taia_less(const struct taia *t,const struct taia *u) +{ + if (t->sec.x < u->sec.x) return 1; + if (t->sec.x > u->sec.x) return 0; + if (t->nano < u->nano) return 1; + if (t->nano > u->nano) return 0; + return t->atto < u->atto; +} diff --git a/taia/taia_now.c b/taia/taia_now.c new file mode 100644 index 0000000..ccc260d --- /dev/null +++ b/taia/taia_now.c @@ -0,0 +1,12 @@ +#include +#include +#include "taia.h" + +void taia_now(struct taia *t) +{ + struct timeval now; + gettimeofday(&now,(struct timezone *) 0); + tai_unix(&t->sec,now.tv_sec); + t->nano = 1000 * now.tv_usec + 500; + t->atto = 0; +} diff --git a/taia/taia_pack.c b/taia/taia_pack.c new file mode 100644 index 0000000..89e2c16 --- /dev/null +++ b/taia/taia_pack.c @@ -0,0 +1,20 @@ +#include "taia.h" + +void taia_pack(char *s,const struct taia *t) +{ + unsigned long x; + + tai_pack(s,&t->sec); + s += 8; + + x = t->atto; + s[7] = x & 255; x >>= 8; + s[6] = x & 255; x >>= 8; + s[5] = x & 255; x >>= 8; + s[4] = x; + x = t->nano; + s[3] = x & 255; x >>= 8; + s[2] = x & 255; x >>= 8; + s[1] = x & 255; x >>= 8; + s[0] = x; +} diff --git a/taia/taia_sub.c b/taia/taia_sub.c new file mode 100644 index 0000000..6944689 --- /dev/null +++ b/taia/taia_sub.c @@ -0,0 +1,21 @@ +#include "taia.h" + +/* XXX: breaks tai encapsulation */ + +void taia_sub(struct taia *t,const struct taia *u,const struct taia *v) +{ + unsigned long unano = u->nano; + unsigned long uatto = u->atto; + + t->sec.x = u->sec.x - v->sec.x; + t->nano = unano - v->nano; + t->atto = uatto - v->atto; + if (t->atto > uatto) { + t->atto += 1000000000UL; + --t->nano; + } + if (t->nano > unano) { + t->nano += 1000000000UL; + --t->sec.x; + } +} diff --git a/taia/taia_tai.c b/taia/taia_tai.c new file mode 100644 index 0000000..ef4d4fc --- /dev/null +++ b/taia/taia_tai.c @@ -0,0 +1,6 @@ +#include "taia.h" + +void taia_tai(const struct taia *ta,struct tai *t) +{ + *t = ta->sec; +} diff --git a/taia/taia_uint.c b/taia/taia_uint.c new file mode 100644 index 0000000..167936c --- /dev/null +++ b/taia/taia_uint.c @@ -0,0 +1,10 @@ +#include "taia.h" + +/* XXX: breaks tai encapsulation */ + +void taia_uint(struct taia *t,unsigned int s) +{ + t->sec.x = s; + t->nano = 0; + t->atto = 0; +} diff --git a/trypoll.c b/trypoll.c new file mode 100644 index 0000000..30bea3d --- /dev/null +++ b/trypoll.c @@ -0,0 +1,18 @@ +#include +#include +#include + +int main() +{ + struct pollfd x; + + x.fd = open("trypoll.c",O_RDONLY); + if (x.fd == -1) _exit(111); + x.events = POLLIN; + if (poll(&x,1,10) == -1) _exit(1); + if (x.revents != POLLIN) _exit(1); + + /* XXX: try to detect and avoid poll() imitation libraries */ + + _exit(0); +} diff --git a/trysysel.c b/trysysel.c new file mode 100644 index 0000000..f6ed055 --- /dev/null +++ b/trysysel.c @@ -0,0 +1,8 @@ +#include +#include +#include /* SVR4 silliness */ + +void foo() +{ + ; +} diff --git a/uint64.h b/uint64.h index 792c56c..734d2c2 100644 --- a/uint64.h +++ b/uint64.h @@ -1,12 +1,6 @@ #ifndef UINT64_H #define UINT64_H -#include - -#if __WORDSIZE == 64 -typedef unsigned long uint64; -#else typedef unsigned long long uint64; -#endif #endif diff --git a/unix/iopause.c b/unix/iopause.c new file mode 100644 index 0000000..b8034de --- /dev/null +++ b/unix/iopause.c @@ -0,0 +1,76 @@ +#include "taia.h" +#include "select.h" +#include "iopause.h" + +void iopause(iopause_fd *x,unsigned int len,struct taia *deadline,struct taia *stamp) +{ + struct taia t; + int millisecs; + double d; + int i; + + if (taia_less(deadline,stamp)) + millisecs = 0; + else { + t = *stamp; + taia_sub(&t,deadline,&t); + d = taia_approx(&t); + if (d > 1000.0) d = 1000.0; + millisecs = d * 1000.0 + 20.0; + } + + for (i = 0;i < len;++i) + x[i].revents = 0; + +#ifdef IOPAUSE_POLL + + poll(x,len,millisecs); + /* XXX: some kernels apparently need x[0] even if len is 0 */ + /* XXX: how to handle EAGAIN? are kernels really this dumb? */ + /* XXX: how to handle EINVAL? when exactly can this happen? */ + +#else +{ + + struct timeval tv; + fd_set rfds; + fd_set wfds; + int nfds; + int fd; + + FD_ZERO(&rfds); + FD_ZERO(&wfds); + + nfds = 1; + for (i = 0;i < len;++i) { + fd = x[i].fd; + if (fd < 0) continue; + if (fd >= 8 * sizeof(fd_set)) continue; /*XXX*/ + + if (fd >= nfds) nfds = fd + 1; + if (x[i].events & IOPAUSE_READ) FD_SET(fd,&rfds); + if (x[i].events & IOPAUSE_WRITE) FD_SET(fd,&wfds); + } + + tv.tv_sec = millisecs / 1000; + tv.tv_usec = 1000 * (millisecs % 1000); + + if (select(nfds,&rfds,&wfds,(fd_set *) 0,&tv) <= 0) + return; + /* XXX: for EBADF, could seek out and destroy the bad descriptor */ + + for (i = 0;i < len;++i) { + fd = x[i].fd; + if (fd < 0) continue; + if (fd >= 8 * sizeof(fd_set)) continue; /*XXX*/ + + if (x[i].events & IOPAUSE_READ) + if (FD_ISSET(fd,&rfds)) x[i].revents |= IOPAUSE_READ; + if (x[i].events & IOPAUSE_WRITE) + if (FD_ISSET(fd,&wfds)) x[i].revents |= IOPAUSE_WRITE; + } + +} +#endif + +}