monster update: add tai, taia, iopause, case, and ipv6 enhanced dns
parent
dd2d9119fc
commit
f921b8cbb0
@ -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.
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -0,0 +1,367 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include "socket.h"
|
||||
#include <errno.h>
|
||||
#include "byte.h"
|
||||
#include "uint16.h"
|
||||
#include "dns.h"
|
||||
#include "ip6.h"
|
||||
|
||||
static int serverwantstcp(const char *buf,unsigned int len)
|
||||
{
|
||||
char out[12];
|
||||
|
||||
if (!dns_packet_copy(buf,len,0,out,12)) return 1;
|
||||
if (out[2] & 2) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serverfailed(const char *buf,unsigned int len)
|
||||
{
|
||||
char out[12];
|
||||
unsigned int rcode;
|
||||
|
||||
if (!dns_packet_copy(buf,len,0,out,12)) return 1;
|
||||
rcode = out[3];
|
||||
rcode &= 15;
|
||||
if (rcode && (rcode != 3)) { errno = EAGAIN; return 1; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int irrelevant(const struct dns_transmit *d,const char *buf,unsigned int len)
|
||||
{
|
||||
char out[12];
|
||||
char *dn;
|
||||
unsigned int pos;
|
||||
|
||||
pos = dns_packet_copy(buf,len,0,out,12); if (!pos) return 1;
|
||||
if (byte_diff(out,2,d->query + 2)) return 1;
|
||||
if (out[4] != 0) return 1;
|
||||
if (out[5] != 1) return 1;
|
||||
|
||||
dn = 0;
|
||||
pos = dns_packet_getname(buf,len,pos,&dn); if (!pos) return 1;
|
||||
if (!dns_domain_equal(dn,d->query + 14)) { free(dn); return 1; }
|
||||
free(dn);
|
||||
|
||||
pos = dns_packet_copy(buf,len,pos,out,4); if (!pos) return 1;
|
||||
if (byte_diff(out,2,d->qtype)) return 1;
|
||||
if (byte_diff(out + 2,2,DNS_C_IN)) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void packetfree(struct dns_transmit *d)
|
||||
{
|
||||
if (!d->packet) return;
|
||||
free(d->packet);
|
||||
d->packet = 0;
|
||||
}
|
||||
|
||||
static void queryfree(struct dns_transmit *d)
|
||||
{
|
||||
if (!d->query) return;
|
||||
free(d->query);
|
||||
d->query = 0;
|
||||
}
|
||||
|
||||
static void socketfree(struct dns_transmit *d)
|
||||
{
|
||||
if (!d->s1) return;
|
||||
close(d->s1 - 1);
|
||||
d->s1 = 0;
|
||||
}
|
||||
|
||||
void dns_transmit_free(struct dns_transmit *d)
|
||||
{
|
||||
queryfree(d);
|
||||
socketfree(d);
|
||||
packetfree(d);
|
||||
}
|
||||
|
||||
static int randombind(struct dns_transmit *d)
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = 0;j < 10;++j)
|
||||
if (socket_bind6(d->s1 - 1,d->localip,1025 + dns_random(64510),d->scope_id) == 0)
|
||||
return 0;
|
||||
if (socket_bind6(d->s1 - 1,d->localip,0,d->scope_id) == 0)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static const int timeouts[4] = { 1, 3, 11, 45 };
|
||||
|
||||
static int thisudp(struct dns_transmit *d)
|
||||
{
|
||||
const char *ip;
|
||||
|
||||
socketfree(d);
|
||||
|
||||
while (d->udploop < 4) {
|
||||
for (;d->curserver < 16;++d->curserver) {
|
||||
ip = d->servers + 16 * d->curserver;
|
||||
if (byte_diff(ip,16,V6any)) {
|
||||
d->query[2] = dns_random(256);
|
||||
d->query[3] = dns_random(256);
|
||||
|
||||
d->s1 = 1 + socket_udp6();
|
||||
if (!d->s1) { dns_transmit_free(d); return -1; }
|
||||
if (randombind(d) == -1) { dns_transmit_free(d); return -1; }
|
||||
|
||||
if (socket_connect6(d->s1 - 1,ip,53,d->scope_id) == 0)
|
||||
if (send(d->s1 - 1,d->query + 2,d->querylen - 2,0) == d->querylen - 2) {
|
||||
struct taia now;
|
||||
taia_now(&now);
|
||||
taia_uint(&d->deadline,timeouts[d->udploop]);
|
||||
taia_add(&d->deadline,&d->deadline,&now);
|
||||
d->tcpstate = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
socketfree(d);
|
||||
}
|
||||
}
|
||||
|
||||
++d->udploop;
|
||||
d->curserver = 0;
|
||||
}
|
||||
|
||||
dns_transmit_free(d); return -1;
|
||||
}
|
||||
|
||||
static int firstudp(struct dns_transmit *d)
|
||||
{
|
||||
d->curserver = 0;
|
||||
return thisudp(d);
|
||||
}
|
||||
|
||||
static int nextudp(struct dns_transmit *d)
|
||||
{
|
||||
++d->curserver;
|
||||
return thisudp(d);
|
||||
}
|
||||
|
||||
static int thistcp(struct dns_transmit *d)
|
||||
{
|
||||
struct taia now;
|
||||
const char *ip;
|
||||
|
||||
socketfree(d);
|
||||
packetfree(d);
|
||||
|
||||
for (;d->curserver < 16;++d->curserver) {
|
||||
ip = d->servers + 16 * d->curserver;
|
||||
if (byte_diff(ip,16,V6any)) {
|
||||
d->query[2] = dns_random(256);
|
||||
d->query[3] = dns_random(256);
|
||||
|
||||
d->s1 = 1 + socket_tcp6();
|
||||
if (!d->s1) { dns_transmit_free(d); return -1; }
|
||||
if (randombind(d) == -1) { dns_transmit_free(d); return -1; }
|
||||
|
||||
taia_now(&now);
|
||||
taia_uint(&d->deadline,10);
|
||||
taia_add(&d->deadline,&d->deadline,&now);
|
||||
if (socket_connect6(d->s1 - 1,ip,53,d->scope_id) == 0) {
|
||||
d->tcpstate = 2;
|
||||
return 0;
|
||||
}
|
||||
if ((errno == EINPROGRESS) || (errno == EWOULDBLOCK)) {
|
||||
d->tcpstate = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
socketfree(d);
|
||||
}
|
||||
}
|
||||
|
||||
dns_transmit_free(d); return -1;
|
||||
}
|
||||
|
||||
static int firsttcp(struct dns_transmit *d)
|
||||
{
|
||||
d->curserver = 0;
|
||||
return thistcp(d);
|
||||
}
|
||||
|
||||
static int nexttcp(struct dns_transmit *d)
|
||||
{
|
||||
++d->curserver;
|
||||
return thistcp(d);
|
||||
}
|
||||
|
||||
int dns_transmit_start(struct dns_transmit *d,const char servers[256],int flagrecursive,const char *q,const char qtype[2],const char localip[16])
|
||||
{
|
||||
unsigned int len;
|
||||
|
||||
dns_transmit_free(d);
|
||||
errno = EIO;
|
||||
|
||||
len = dns_domain_length(q);
|
||||
d->querylen = len + 18;
|
||||
d->query = malloc(d->querylen);
|
||||
if (!d->query) return -1;
|
||||
|
||||
uint16_pack_big(d->query,len + 16);
|
||||
byte_copy(d->query + 2,12,flagrecursive ? "\0\0\1\0\0\1\0\0\0\0\0\0" : "\0\0\0\0\0\1\0\0\0\0\0\0gcc-bug-workaround");
|
||||
byte_copy(d->query + 14,len,q);
|
||||
byte_copy(d->query + 14 + len,2,qtype);
|
||||
byte_copy(d->query + 16 + len,2,DNS_C_IN);
|
||||
|
||||
byte_copy(d->qtype,2,qtype);
|
||||
d->servers = servers;
|
||||
byte_copy(d->localip,16,localip);
|
||||
|
||||
d->udploop = flagrecursive ? 1 : 0;
|
||||
|
||||
if (len + 16 > 512) return firsttcp(d);
|
||||
return firstudp(d);
|
||||
}
|
||||
|
||||
void dns_transmit_io(struct dns_transmit *d,iopause_fd *x,struct taia *deadline)
|
||||
{
|
||||
x->fd = d->s1 - 1;
|
||||
|
||||
switch(d->tcpstate) {
|
||||
case 0: case 3: case 4: case 5:
|
||||
x->events = IOPAUSE_READ;
|
||||
break;
|
||||
case 1: case 2:
|
||||
x->events = IOPAUSE_WRITE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (taia_less(&d->deadline,deadline))
|
||||
*deadline = d->deadline;
|
||||
}
|
||||
|
||||
int dns_transmit_get(struct dns_transmit *d,const iopause_fd *x,const struct taia *when)
|
||||
{
|
||||
char udpbuf[513];
|
||||
unsigned char ch;
|
||||
int r;
|
||||
int fd;
|
||||
|
||||
errno = EIO;
|
||||
fd = d->s1 - 1;
|
||||
|
||||
if (!x->revents) {
|
||||
if (taia_less(when,&d->deadline)) return 0;
|
||||
errno = ETIMEDOUT;
|
||||
if (d->tcpstate == 0) return nextudp(d);
|
||||
return nexttcp(d);
|
||||
}
|
||||
|
||||
if (d->tcpstate == 0) {
|
||||
/*
|
||||
have attempted to send UDP query to each server udploop times
|
||||
have sent query to curserver on UDP socket s
|
||||
*/
|
||||
r = recv(fd,udpbuf,sizeof udpbuf,0);
|
||||
if (r <= 0) {
|
||||
if (errno == ECONNREFUSED) if (d->udploop == 2) return 0;
|
||||
return nextudp(d);
|
||||
}
|
||||
if (r + 1 > sizeof udpbuf) return 0;
|
||||
|
||||
if (irrelevant(d,udpbuf,r)) return 0;
|
||||
if (serverwantstcp(udpbuf,r)) return firsttcp(d);
|
||||
if (serverfailed(udpbuf,r)) {
|
||||
if (d->udploop == 2) return 0;
|
||||
return nextudp(d);
|
||||
}
|
||||
socketfree(d);
|
||||
|
||||
d->packetlen = r;
|
||||
d->packet = malloc(d->packetlen);
|
||||
if (!d->packet) { dns_transmit_free(d); return -1; }
|
||||
byte_copy(d->packet,d->packetlen,udpbuf);
|
||||
queryfree(d);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (d->tcpstate == 1) {
|
||||
/*
|
||||
have sent connection attempt to curserver on TCP socket s
|
||||
pos not defined
|
||||
*/
|
||||
if (!socket_connected(fd)) return nexttcp(d);
|
||||
d->pos = 0;
|
||||
d->tcpstate = 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (d->tcpstate == 2) {
|
||||
/*
|
||||
have connection to curserver on TCP socket s
|
||||
have sent pos bytes of query
|
||||
*/
|
||||
r = write(fd,d->query + d->pos,d->querylen - d->pos);
|
||||
if (r <= 0) return nexttcp(d);
|
||||
d->pos += r;
|
||||
if (d->pos == d->querylen) {
|
||||
struct taia now;
|
||||
taia_now(&now);
|
||||
taia_uint(&d->deadline,10);
|
||||
taia_add(&d->deadline,&d->deadline,&now);
|
||||
d->tcpstate = 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (d->tcpstate == 3) {
|
||||
/*
|
||||
have sent entire query to curserver on TCP socket s
|
||||
pos not defined
|
||||
*/
|
||||
r = read(fd,&ch,1);
|
||||
if (r <= 0) return nexttcp(d);
|
||||
d->packetlen = ch;
|
||||
d->tcpstate = 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (d->tcpstate == 4) {
|
||||
/*
|
||||
have sent entire query to curserver on TCP socket s
|
||||
pos not defined
|
||||
have received one byte of packet length into packetlen
|
||||
*/
|
||||
r = read(fd,&ch,1);
|
||||
if (r <= 0) return nexttcp(d);
|
||||
d->packetlen <<= 8;
|
||||
d->packetlen += ch;
|
||||
d->tcpstate = 5;
|
||||
d->pos = 0;
|
||||
d->packet = malloc(d->packetlen);
|
||||
if (!d->packet) { dns_transmit_free(d); return -1; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (d->tcpstate == 5) {
|
||||
/*
|
||||
have sent entire query to curserver on TCP socket s
|
||||
have received entire packet length into packetlen
|
||||
packet is allocated
|
||||
have received pos bytes of packet
|
||||
*/
|
||||
r = read(fd,d->packet + d->pos,d->packetlen - d->pos);
|
||||
if (r <= 0) return nexttcp(d);
|
||||
d->pos += r;
|
||||
if (d->pos < d->packetlen) return 0;
|
||||
|
||||
socketfree(d);
|
||||
if (irrelevant(d,d->packet,d->packetlen)) return nexttcp(d);
|
||||
if (serverwantstcp(d->packet,d->packetlen)) return nexttcp(d);
|
||||
if (serverfailed(d->packet,d->packetlen)) return nexttcp(d);
|
||||
|
||||
queryfree(d);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
|
@ -0,0 +1,18 @@
|
||||
#ifndef IOPAUSE_H
|
||||
#define IOPAUSE_H
|
||||
|
||||
/* sysdep: +poll */
|
||||
#define IOPAUSE_POLL
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <poll.h>
|
||||
|
||||
typedef struct pollfd iopause_fd;
|
||||
#define IOPAUSE_READ POLLIN
|
||||
#define IOPAUSE_WRITE POLLOUT
|
||||
|
||||
#include "taia.h"
|
||||
|
||||
extern void iopause(iopause_fd *,unsigned int,struct taia *,struct taia *);
|
||||
|
||||
#endif
|
@ -0,0 +1,16 @@
|
||||
#include <errno.h>
|
||||
#include "open.h"
|
||||
#include "readclose.h"
|
||||
#include "openreadclose.h"
|
||||
|
||||
int openreadclose(const char *fn,stralloc *sa,unsigned int bufsize)
|
||||
{
|
||||
int fd;
|
||||
fd = open_read(fn);
|
||||
if (fd == -1) {
|
||||
if (errno == ENOENT) return 0;
|
||||
return -1;
|
||||
}
|
||||
if (readclose(fd,sa,bufsize) == -1) return -1;
|
||||
return 1;
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include "readclose.h"
|
||||
|
||||
int readclose_append(int fd,stralloc *sa,unsigned int bufsize)
|
||||
{
|
||||
int r;
|
||||
for (;;) {
|
||||
if (!stralloc_readyplus(sa,bufsize)) { close(fd); return -1; }
|
||||
r = read(fd,sa->s + sa->len,bufsize);
|
||||
if (r == -1) if (errno == EINTR) continue;
|
||||
if (r <= 0) { close(fd); return r; }
|
||||
sa->len += r;
|
||||
}
|
||||
}
|
||||
|
||||
int readclose(int fd,stralloc *sa,unsigned int bufsize)
|
||||
{
|
||||
if (!stralloc_copys(sa,"")) { close(fd); return -1; }
|
||||
return readclose_append(fd,sa,bufsize);
|
||||
}
|
@ -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
|
@ -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
|
@ -0,0 +1,10 @@
|
||||
#ifndef SELECT_H
|
||||
#define SELECT_H
|
||||
|
||||
/* sysdep: -sysselect */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
extern int select();
|
||||
|
||||
#endif
|
@ -0,0 +1,11 @@
|
||||
#ifndef SELECT_H
|
||||
#define SELECT_H
|
||||
|
||||
/* sysdep: +sysselect */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/select.h>
|
||||
extern int select();
|
||||
|
||||
#endif
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
#include <time.h>
|
||||
#include "tai.h"
|
||||
|
||||
void tai_now(struct tai *t)
|
||||
{
|
||||
tai_unix(t,time((time_t *) 0));
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
#include "tai.h"
|
||||
|
||||
void tai_uint(struct tai *t,unsigned int u)
|
||||
{
|
||||
t->x = u;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
#include "taia.h"
|
||||
|
||||
double taia_approx(const struct taia *t)
|
||||
{
|
||||
return tai_approx(&t->sec) + taia_frac(t);
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
#include "taia.h"
|
||||
|
||||
double taia_frac(const struct taia *t)
|
||||
{
|
||||
return (t->atto * 0.000000001 + t->nano) * 0.000000001;
|
||||
}
|
@ -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;
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
#include "taia.h"
|
||||
|
||||
void taia_tai(const struct taia *ta,struct tai *t)
|
||||
{
|
||||
*t = ta->sec;
|
||||
}
|
@ -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;
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
|
||||
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);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/select.h> /* SVR4 silliness */
|
||||
|
||||
void foo()
|
||||
{
|
||||
;
|
||||
}
|
@ -1,12 +1,6 @@
|
||||
#ifndef UINT64_H
|
||||
#define UINT64_H
|
||||
|
||||
#include <endian.h>
|
||||
|
||||
#if __WORDSIZE == 64
|
||||
typedef unsigned long uint64;
|
||||
#else
|
||||
typedef unsigned long long uint64;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -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
|
||||
|
||||
}
|
Loading…
Reference in New Issue