Hi,
I need help to rewrite djbdns source code to accept 1024 bytes via UDP (limit is 512)
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "uint16.h"
#include "uint32.h"
#include "str.h"
#include "byte.h"
#include "fmt.h"
#include "ip4.h"
#include "exit.h"
#include "case.h"
#include "scan.h"
#include "buffer.h"
#include "strerr.h"
#include "getln.h"
#include "cdb_make.h"
#include "stralloc.h"
#include "open.h"
#include "dns.h"
#define TTL_NS 259200
#define TTL_POSITIVE 86400
#define TTL_NEGATIVE 2560
#define FATAL "tinydns-data: fatal: "
void die_datatmp(void)
{
strerr_die2sys(111,FATAL,"unable to create data.tmp: ");
}
void nomem(void)
{
strerr_die1sys(111,FATAL);
}
void ttdparse(stralloc *sa,char ttd[8])
{
unsigned int i;
char ch;
byte_zero(ttd,8);
for (i = 0;(i < 16) && (i < sa->len);++i) {
ch = sa->s;
if ((ch >= '0') && (ch <= '9'))
ch -= '0';
else if ((ch >= 'a') && (ch <= 'f'))
ch -= 'a' - 10;
else
ch = 0;
if (!(i & 1)) ch <<= 4;
ttd[i >> 1] |= ch;
}
}
void locparse(stralloc *sa,char loc[2])
{
loc[0] = (sa->len > 0) ? sa->s[0] : 0;
loc[1] = (sa->len > 1) ? sa->s[1] : 0;
}
void ipprefix_cat(stralloc *out,char *s)
{
unsigned long u;
char ch;
unsigned int j;
for (;;)
if (*s == '.')
++s;
else {
j = scan_ulong(s,&u);
if (!j) return;
s += j;
ch = u;
if (!stralloc_catb(out,&ch,1)) nomem();
}
}
void txtparse(stralloc *sa)
{
char ch;
unsigned int i;
unsigned int j;
j = 0;
i = 0;
while (i < sa->len) {
ch = sa->s[i++];
if (ch == '\\') {
if (i >= sa->len) break;
ch = sa->s[i++];
if ((ch >= '0') && (ch <= '7')) {
ch -= '0';
if ((i < sa->len) && (sa->s >= '0') && (sa->s <= '7')) {
ch <<= 3;
ch += sa->s[i++] - '0';
if ((i < sa->len) && (sa->s >= '0') && (sa->s <= '7')) {
ch <<= 3;
ch += sa->s[i++] - '0';
}
}
}
}
sa->s[j++] = ch;
}
sa->len = j;
}
char defaultsoa[20];
void defaultsoa_init(int fd)
{
struct stat st;
if (fstat(fd,&st) == -1)
strerr_die2sys(111,FATAL,"unable to stat data: ");
uint32_pack_big(defaultsoa,st.st_mtime);
if (byte_equal(defaultsoa,4,"\0\0\0\0"))
defaultsoa[3] = 1;
byte_copy(defaultsoa + 4,16,"\0\0\100\000\0\0\010\000\0\020\000\000\0\0\012\000");
}
int fdcdb;
struct cdb_make cdb;
static stralloc key;
static stralloc result;
void rr_add(const char *buf,unsigned int len)
{
if (!stralloc_catb(&result,buf,len)) nomem();
}
void rr_addname(const char *d)
{
rr_add(d,dns_domain_length(d));
}
void rr_start(const char type[2],unsigned long ttl,const char ttd[8],const char loc[2])
{
char buf[4];
if (!stralloc_copyb(&result,type,2)) nomem();
if (byte_equal(loc,2,"\0\0"))
rr_add("=",1);
else {
rr_add(">",1);
rr_add(loc,2);
}
uint32_pack_big(buf,ttl);
rr_add(buf,4);
rr_add(ttd,8);
}
void rr_finish(const char *owner)
{
if (byte_equal(owner,2,"\1*")) {
owner += 2;
result.s[2] -= 19;
}
if (!stralloc_copyb(&key,owner,dns_domain_length(owner))) nomem();
case_lowerb(key.s,key.len);
if (cdb_make_add(&cdb,key.s,key.len,result.s,result.len) == -1)
die_datatmp();
}
buffer b;
char bspace[1024];
static stralloc line;
int match = 1;
unsigned long linenum = 0;
#define NUMFIELDS 15
static stralloc f[NUMFIELDS];
static char *d1;
static char *d2;
char dptr[DNS_NAME4_DOMAIN];
char strnum[FMT_ULONG];
void syntaxerror(const char *why)
{
strnum[fmt_ulong(strnum,linenum)] = 0;
strerr_die4x(111,FATAL,"unable to parse data line ",strnum,why);
}
int main()
{
int fddata;
int i;
int j;
int k;
char ch;
unsigned long ttl;
char ttd[8];
char loc[2];
unsigned long u;
char ip[4];
char type[2];
char soa[20];
char buf[4];
umask(022);
fddata = open_read("data");
if (fddata == -1)
strerr_die2sys(111,FATAL,"unable to open data: ");
defaultsoa_init(fddata);
buffer_init(&b,buffer_unixread,fddata,bspace,sizeof bspace);
fdcdb = open_trunc("data.tmp");
if (fdcdb == -1) die_datatmp();
if (cdb_make_start(&cdb,fdcdb) == -1) die_datatmp();
while (match) {
++linenum;
if (getln(&b,&line,&match,'\n') == -1)
strerr_die2sys(111,FATAL,"unable to read line: ");
while (line.len) {
ch = line.s[line.len - 1];
if ((ch != ' ') && (ch != '\t') && (ch != '\n')) break;
--line.len;
}
if (!line.len) continue;
if (line.s[0] == '#') continue;
if (line.s[0] == '-') continue;
j = 1;
for (i = 0;i < NUMFIELDS;++i) {
if (j >= line.len) {
if (!stralloc_copys(&f,"")) nomem();
}
else {
k = byte_chr(line.s + j,line.len - j,':');
if (!stralloc_copyb(&f,line.s + j,k)) nomem();
j += k + 1;
}
}
switch(line.s[0]) {
case '%':
locparse(&f[0],loc);
if (!stralloc_copyb(&key,"\0%",2)) nomem();
if (!stralloc_0(&f[1])) nomem();
ipprefix_cat(&key,f[1].s);
if (cdb_make_add(&cdb,key.s,key.len,loc,2) == -1)
die_datatmp();
break;
case 'Z':
if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
if (!stralloc_0(&f[3])) nomem();
if (!scan_ulong(f[3].s,&u)) uint32_unpack_big(defaultsoa,&u);
uint32_pack_big(soa,u);
if (!stralloc_0(&f[4])) nomem();
if (!scan_ulong(f[4].s,&u)) uint32_unpack_big(defaultsoa + 4,&u);
uint32_pack_big(soa + 4,u);
if (!stralloc_0(&f[5])) nomem();
if (!scan_ulong(f[5].s,&u)) uint32_unpack_big(defaultsoa + 8,&u);
uint32_pack_big(soa + 8,u);
if (!stralloc_0(&f[6])) nomem();
if (!scan_ulong(f[6].s,&u)) uint32_unpack_big(defaultsoa + 12,&u);
uint32_pack_big(soa + 12,u);
if (!stralloc_0(&f[7])) nomem();
if (!scan_ulong(f[7].s,&u)) uint32_unpack_big(defaultsoa + 16,&u);
uint32_pack_big(soa + 16,u);
if (!stralloc_0(&f[8])) nomem();
if (!scan_ulong(f[8].s,&ttl)) ttl = TTL_NEGATIVE;
ttdparse(&f[9],ttd);
locparse(&f[10],loc);
rr_start(DNS_T_SOA,ttl,ttd,loc);
if (!dns_domain_fromdot(&d2,f[1].s,f[1].len)) nomem();
rr_addname(d2);
if (!dns_domain_fromdot(&d2,f[2].s,f[2].len)) nomem();
rr_addname(d2);
rr_add(soa,20);
rr_finish(d1);
break;
case '.': case '&':
if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
if (!stralloc_0(&f[3])) nomem();
if (!scan_ulong(f[3].s,&ttl)) ttl = TTL_NS;
ttdparse(&f[4],ttd);
locparse(&f[5],loc);
if (!stralloc_0(&f[1])) nomem();
if (byte_chr(f[2].s,f[2].len,'.') >= f[2].len) {
if (!stralloc_cats(&f[2],".ns.")) nomem();
if (!stralloc_catb(&f[2],f[0].s,f[0].len)) nomem();
}
if (!dns_domain_fromdot(&d2,f[2].s,f[2].len)) nomem();
if (line.s[0] == '.') {
rr_start(DNS_T_SOA,ttl ? TTL_NEGATIVE : 0,ttd,loc);
rr_addname(d2);
rr_add("\12hostmaster",11);
rr_addname(d1);
rr_add(defaultsoa,20);
rr_finish(d1);
}
rr_start(DNS_T_NS,ttl,ttd,loc);
rr_addname(d2);
rr_finish(d1);
if (ip4_scan(f[1].s,ip)) {
rr_start(DNS_T_A,ttl,ttd,loc);
rr_add(ip,4);
rr_finish(d2);
}
break;
case '+': case '=':
if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
if (!stralloc_0(&f[2])) nomem();
if (!scan_ulong(f[2].s,&ttl)) ttl = TTL_POSITIVE;
ttdparse(&f[3],ttd);
locparse(&f[4],loc);
if (!stralloc_0(&f[1])) nomem();
if (ip4_scan(f[1].s,ip)) {
rr_start(DNS_T_A,ttl,ttd,loc);
rr_add(ip,4);
rr_finish(d1);
if (line.s[0] == '=') {
dns_name4_domain(dptr,ip);
rr_start(DNS_T_PTR,ttl,ttd,loc);
rr_addname(d1);
rr_finish(dptr);
}
}
break;
case '@':
if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
if (!stralloc_0(&f[4])) nomem();
if (!scan_ulong(f[4].s,&ttl)) ttl = TTL_POSITIVE;
ttdparse(&f[5],ttd);
locparse(&f[6],loc);
if (!stralloc_0(&f[1])) nomem();
if (byte_chr(f[2].s,f[2].len,'.') >= f[2].len) {
if (!stralloc_cats(&f[2],".mx.")) nomem();
if (!stralloc_catb(&f[2],f[0].s,f[0].len)) nomem();
}
if (!dns_domain_fromdot(&d2,f[2].s,f[2].len)) nomem();
if (!stralloc_0(&f[3])) nomem();
if (!scan_ulong(f[3].s,&u)) u = 0;
rr_start(DNS_T_MX,ttl,ttd,loc);
uint16_pack_big(buf,u);
rr_add(buf,2);
rr_addname(d2);
rr_finish(d1);
if (ip4_scan(f[1].s,ip)) {
rr_start(DNS_T_A,ttl,ttd,loc);
rr_add(ip,4);
rr_finish(d2);
}
break;
case '^': case 'C':
if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
if (!dns_domain_fromdot(&d2,f[1].s,f[1].len)) nomem();
if (!stralloc_0(&f[2])) nomem();
if (!scan_ulong(f[2].s,&ttl)) ttl = TTL_POSITIVE;
ttdparse(&f[3],ttd);
locparse(&f[4],loc);
if (line.s[0] == 'C')
rr_start(DNS_T_CNAME,ttl,ttd,loc);
else
rr_start(DNS_T_PTR,ttl,ttd,loc);
rr_addname(d2);
rr_finish(d1);
break;
case '\'':
if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
if (!stralloc_0(&f[2])) nomem();
if (!scan_ulong(f[2].s,&ttl)) ttl = TTL_POSITIVE;
ttdparse(&f[3],ttd);
locparse(&f[4],loc);
rr_start(DNS_T_TXT,ttl,ttd,loc);
txtparse(&f[1]);
i = 0;
while (i < f[1].len) {
k = f[1].len - i;
if (k > 127) k = 127;
ch = k;
rr_add(&ch,1);
rr_add(f[1].s + i,k);
i += k;
}
rr_finish(d1);
break;
case ':':
if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
if (!stralloc_0(&f[3])) nomem();
if (!scan_ulong(f[3].s,&ttl)) ttl = TTL_POSITIVE;
ttdparse(&f[4],ttd);
locparse(&f[5],loc);
if (!stralloc_0(&f[1])) nomem();
scan_ulong(f[1].s,&u);
uint16_pack_big(type,u);
if (byte_equal(type,2,DNS_T_AXFR))
syntaxerror(": type AXFR prohibited");
if (byte_equal(type,2,"\0\0"))
syntaxerror(": type 0 prohibited");
if (byte_equal(type,2,DNS_T_SOA))
syntaxerror(": type SOA prohibited");
if (byte_equal(type,2,DNS_T_NS))
syntaxerror(": type NS prohibited");
if (byte_equal(type,2,DNS_T_CNAME))
syntaxerror(": type CNAME prohibited");
if (byte_equal(type,2,DNS_T_PTR))
syntaxerror(": type PTR prohibited");
if (byte_equal(type,2,DNS_T_MX))
syntaxerror(": type MX prohibited");
txtparse(&f[2]);
rr_start(type,ttl,ttd,loc);
rr_add(f[2].s,f[2].len);
rr_finish(d1);
break;
default:
syntaxerror(": unrecognized leading character");
}
}
if (cdb_make_finish(&cdb) == -1) die_datatmp();
if (fsync(fdcdb) == -1) die_datatmp();
if (close(fdcdb) == -1) die_datatmp(); /* NFS stupidity */
if (rename("data.tmp","data.cdb") == -1)
strerr_die2sys(111,FATAL,"unable to move data.tmp to data.cdb: ");
_exit(0);
}
---------- Post updated at 04:18 AM ---------- Previous update was at 02:36 AM ----------
I guess I found it in dns_transmit.c - need to change
if (len + 16 > 512) return firsttcp(d);
return firstudp(d);
}
to 1024 and
char udpbuf[513];
to 1025
Whole code is here
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include "socket.h"
#include "alloc.h"
#include "error.h"
#include "byte.h"
#include "uint16.h"
#include "dns.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 = error_again; 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)) { alloc_free(dn); return 1; }
alloc_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;
alloc_free(d->packet);
d->packet = 0;
}
static void queryfree(struct dns_transmit *d)
{
if (!d->query) return;
alloc_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_bind4(d->s1 - 1,d->localip,1025 + dns_random(64510)) == 0)
return 0;
if (socket_bind4(d->s1 - 1,d->localip,0) == 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 + 4 * d->curserver;
if (byte_diff(ip,4,"\0\0\0\0")) {
d->query[2] = dns_random(256);
d->query[3] = dns_random(256);
d->s1 = 1 + socket_udp();
if (!d->s1) { dns_transmit_free(d); return -1; }
if (randombind(d) == -1) { dns_transmit_free(d); return -1; }
if (socket_connect4(d->s1 - 1,ip,53) == 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 + 4 * d->curserver;
if (byte_diff(ip,4,"\0\0\0\0")) {
d->query[2] = dns_random(256);
d->query[3] = dns_random(256);
d->s1 = 1 + socket_tcp();
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_connect4(d->s1 - 1,ip,53) == 0) {
d->tcpstate = 2;
return 0;
}
if ((errno == error_inprogress) || (errno == error_wouldblock)) {
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[64],int flagrecursive,const char *q,const char qtype[2],const char localip[4])
{
unsigned int len;
dns_transmit_free(d);
errno = error_io;
len = dns_domain_length(q);
d->querylen = len + 18;
d->query = alloc(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,4,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 = error_io;
fd = d->s1 - 1;
if (!x->revents) {
if (taia_less(when,&d->deadline)) return 0;
errno = error_timeout;
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 == error_connrefused) 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 = alloc(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 = alloc(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;
}