mirror of /home/gitosis/repositories/libowfat.git

63 changed files with 2280 additions and 23 deletions
@ -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; |
||||
< |