static int thistcp (struct dns_transmit *d) { struct taia now; const char *ip = NULL; 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->pos = 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; }
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); }
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; }
/** Request the name (PTR) record for an IPv4 address. */ int dns_name4_r(struct dns_transmit* tx, struct dns_result* out, const ipv4addr *ip) { char name[DNS_NAME4_DOMAIN]; dns_name4_domain(name,ip); if (dns_resolve(tx,name,DNS_T_PTR) == -1) return -1; if (dns_name_packet(out,tx->packet,tx->packetlen) == -1) return -1; dns_transmit_free(tx); return 0; }
static int doit(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=ip6_scan(fqdn->s,ip))) { if (!fqdn->s[i]) { stralloc_copyb(out,ip,16); return 0; } } if ((i=ip4_scan(fqdn->s,ip+12))) { if (!fqdn->s[i]) { byte_zero(ip,10); ip[10]=ip[11]=0xff; 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 (dns_resolve(q,DNS_T_AAAA) == -1) return -1; if (dns_ip6_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; }
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 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 == error_inprogress) || (errno == error_wouldblock)) { d->tcpstate = 1; return 0; } socketfree(d); } } dns_transmit_free(d); return -1; }
/** Request the IPv4 address (A) records for a domain name. */ int dns_ip4_r(struct dns_transmit* tx, struct dns_result *out, const char* fqdn) { char *q = 0; ipv4addr ip; const char* x; if ((x = ipv4_scan(fqdn, &ip)) != 0 && *x == 0) { if (dns_result_alloc(out, DNS_T_A, 1, 0) < 0) return -1; memcpy(out->rr.ip4, &ip, sizeof ip); return 0; } if (!dns_domain_fromdot(&q,fqdn,strlen(fqdn))) return -1; if (dns_resolve(tx,q,DNS_T_A) == -1) { free(q); return -1; } free(q); if (dns_ip4_packet(out,tx->packet,tx->packetlen) == -1) return -1; dns_transmit_free(tx); return 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; }
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; }
static int thisudp (struct dns_transmit *d) { const char *ip = NULL; socketfree (d); mergefree (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")) { if (merge_enable && try_merge (d)) { if (merge_logger) merge_logger (ip, d->qtype, d->query + 14); return 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; if (merge_enable) register_inprogress (d); return 0; } } socketfree (d); } } ++d->udploop; d->curserver = 0; } dns_transmit_free (d); return -1; }