📄 res_send.c
字号:
/*------------------------------------------------------------------------*/
static int name_server_send (int ns, struct sockaddr_in *nsap)
{
int resplen = 0;
if (badns & (1 << ns)) /* this NameServer already marked bad */
{
resolve_close();
return (NEXT_NS);
}
if (Qhook)
{
int done = 0;
int loops = 0;
do
{
res_sendhookact act = (*Qhook)(&nsap, (const u_char**)&ns_buf,
&ns_buflen, ns_ans, ns_anssiz,
&resplen);
switch (act)
{
case res_goahead:
done = 1;
break;
case res_nextns:
resolve_close();
return (NEXT_NS);
case res_done:
return (resplen);
case res_modified:
/* give the hook another try */
if (++loops < 42)
break;
/* fallthrough */
case res_error:
/* fallthrough */
default:
return (-1);
}
}
while (!done);
}
Dprint (_res.options & RES_DEBUG,
(";; Querying server (# %d) address = %s\n",
ns + 1, inet_ntoa(nsap->sin_addr)));
if (v_circuit) /* i.e. TCP */
{
int truncated;
u_short len;
u_char *cp;
/* Use virtual circuit; at most one attempt per server.
*/
try = _res.retry;
truncated = 0;
if (!sock || !vc)
{
DWORD his_ip = ntohl (nsap->sin_addr.s_addr);
WORD his_port = ntohs (nsap->sin_port);
if (sock)
resolve_close();
sock = malloc (sizeof(tcp_Socket));
if (!sock)
{
Perror ("malloc(vc)", "no memory");
return (-1);
}
if (!tcp_open(&sock->tcp,0,his_ip,his_port,NULL) ||
!tcp_conn(&sock->tcp,&errno,dns_timeout))
{
Aerror ("tcp_open/vc", "failed/timeout", *nsap);
badns |= (1 << ns);
resolve_close();
return (NEXT_NS);
}
vc = 1;
}
/* Send length & message
*/
{
BYTE *send_buf = alloca (INT16SZ + ns_buflen);
PUTSHORT (ns_buflen, send_buf);
memcpy (&send_buf[INT16SZ],ns_buf,ns_buflen);
if (sock_write(sock,send_buf,INT16SZ+ns_buflen) != INT16SZ+ns_buflen)
{
Perror ("sock_write() failed", sockerr(&sock->tcp));
badns |= (1 << ns);
resolve_close();
return (NEXT_NS);
}
}
/* Receive length & response
*/
cp = ns_ans;
len = INT16SZ;
while ((n = tcp_read(&sock->tcp,cp,len,&errno,dns_timeout)) > 0)
{
cp += n;
if ((len -= n) <= 0)
break;
}
if (n <= 0)
{
Perror ("tcp_read() failed", sockerr(&sock->tcp));
resolve_close();
return (NEXT_NS);
}
resplen = _getshort (ns_ans);
if (resplen > ns_anssiz)
{
Dprint(_res.options & RES_DEBUG,(";; response truncated\n"));
truncated = 1;
len = ns_anssiz;
}
else
len = resplen;
cp = ns_ans;
while (len && (n = tcp_read(&sock->tcp,cp,len,&errno,dns_timeout)) > 0)
{
cp += n;
len -= n;
}
if (n <= 0)
{
Perror ("tcp_read(vc)",sockerr(&sock->tcp));
resolve_close();
return (NEXT_NS);
}
if (truncated)
{
/* Flush rest of answer so connection stays in synch.
*/
anhp->tc = 1;
len = resplen - ns_anssiz;
while (len)
{
u_char junk[PACKETSZ];
n = (len > sizeof(junk) ? sizeof(junk) : len);
n = tcp_read (&sock->tcp,junk,n,&errno,dns_timeout);
if (n > 0)
len -= n;
else break;
}
}
}
else /* !v_circuit, i.e. UDP */
{
DWORD timeout;
if (!sock || vc)
{
if (vc)
resolve_close();
sock = malloc (sizeof(udp_Socket));
if (!sock)
{
Perror ("malloc(dg)", "no memory");
return (-1);
}
connected = 0;
}
/* Connect only if we are sure we won't
* receive a response from another server.
*/
if (!connected)
{
DWORD his_ip = ntohl (nsap->sin_addr.s_addr);
WORD his_port = ntohs (nsap->sin_port);
if (!udp_open(&sock->udp,0,his_ip,his_port,NULL))
{
Aerror ("connect/dg", "ARP failed", *nsap);
badns |= (1 << ns);
resolve_close();
return (NEXT_NS);
}
connected = 1;
}
if (sock_write(sock,(BYTE*)ns_buf,ns_buflen) != ns_buflen)
{
Perror ("sock_write() failed", "");
badns |= (1 << ns);
resolve_close();
return (NEXT_NS);
}
/* Wait for reply
*/
timeout = (unsigned)_res.retrans << try;
if (try > 0)
timeout /= _res.nscount;
if ((long)timeout <= 0)
timeout = 1;
wait:
n = udp_read (&sock->udp, ns_ans, ns_anssiz, &errno, timeout);
if (n == 0)
{
Dprint (_res.options & RES_DEBUG, (";; timeout\n"));
gotsomewhere = 1;
resolve_close();
return (NEXT_NS);
}
gotsomewhere = 1;
if (hp->id != anhp->id)
{
/* response from old query, ignore it.
* XXX - potential security hazard could be detected here.
*/
DprintQ ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_REPLY),
(";; old answer:\n"), ns_ans, resplen);
goto wait;
}
if (!(_res.options & RES_INSECURE2) &&
!res_queriesmatch(ns_buf, ns_buf+ns_buflen, ns_ans, ns_ans+ns_anssiz))
{
/* response contains wrong query? ignore it.
* XXX - potential security hazard could be detected here.
*/
DprintQ ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_REPLY),
(";; wrong query name:\n"), ns_ans, resplen);
goto wait;
}
if (anhp->rcode == SERVFAIL ||
anhp->rcode == NOTIMP ||
anhp->rcode == REFUSED)
{
DprintQ (_res.options & RES_DEBUG,("server rejected query:\n"),
ns_ans,resplen);
badns |= (1 << ns);
resolve_close();
/* don't retry if called from dig */
if (!_res.pfcode)
return (NEXT_NS);
}
if (!(_res.options & RES_IGNTC) && anhp->tc)
{
/* get rest of answer; use TCP with same server.
*/
Dprint (_res.options & RES_DEBUG, (";; truncated answer\n"));
v_circuit = 1;
resolve_close();
return (SAME_NS);
}
} /* if vcicuit / dg */
Dprint ((_res.options & RES_DEBUG) ||
((_res.pfcode & RES_PRF_REPLY) && (_res.pfcode & RES_PRF_HEAD1)),
(";; got answer:\n"));
DprintQ ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_REPLY),
(" \b"), ns_ans, resplen);
/*
* If using virtual circuits (TCP), we assume that the first server
* is preferred over the rest (i.e. it is on the local machine) and
* only keep that one open. If we have temporarily opened a virtual
* circuit, or if we haven't been asked to keep a socket open,
* close the socket.
*/
if ((v_circuit && (!(_res.options & RES_USEVC) || ns != 0)) ||
!(_res.options & RES_STAYOPEN))
resolve_close();
if (Rhook)
{
int done = 0, loops = 0;
do
{
res_sendhookact act = (*Rhook)(nsap, ns_buf, ns_buflen,
ns_ans, ns_anssiz, &resplen);
switch (act)
{
case res_goahead:
case res_done:
done = 1;
break;
case res_nextns:
resolve_close();
return (NEXT_NS);
case res_modified:
/* give the hook another try */
if (++loops < 42)
break;
/* fallthrough */
case res_error:
/* fallthrough */
default:
return (-1);
}
}
while (!done);
}
return (resplen);
}
/*
* This routine is for closing the socket if a virtual circuit is used and
* the program wants to close it. This provides support for endhostent()
* which expects to close the socket.
*
* This routine is not expected to be user visible.
*/
static void resolve_close (void)
{
if (sock)
{
if (sock->tcp.ip_type == TCP_PROTO &&
sock->tcp.state < tcp_StateCLOSED)
{
sock_close (sock);
sock_abort (sock);
}
free (sock);
sock = NULL;
connected = 0;
vc = 0;
}
}
#endif /* USE_BIND */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -