示例#1
0
文件: tcp.c 项目: dancahill/nsp
int tcp_connect(nsp_state *N, TCP_SOCKET *sock, char *host, unsigned short port, short int use_ssl)
{
#define __FN__ __FILE__ ":tcp_connect()"
	struct hostent *hp;
	struct sockaddr_in serv;

	if ((hp = gethostbyname(host)) == NULL) {
		n_warn(N, __FN__, "Host lookup error for %s", host);
		return -1;
	}
	nc_memset((char *)&serv, 0, sizeof(serv));
	nc_memcpy((char *)&serv.sin_addr, hp->h_addr, hp->h_length);
	serv.sin_family = hp->h_addrtype;
	serv.sin_port = htons(port);
	if ((sock->socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) return -2;
	/*	setsockopt(sock->socket, SOL_SOCKET, SO_KEEPALIVE, 0, 0); */
	if (tcp_conn(N, sock, &serv, sizeof(serv), use_ssl) < 0) {
		/* n_warn(N, __FN__, "Error connecting to %s:%d", host, port); */
		return -2;
	}
	return 0;
#undef __FN__
}
示例#2
0
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 = (sock_type*) calloc (sizeof(_tcp_Socket), 1);
      if (!sock)
      {
        Perror ("calloc(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
     */
    {
      int   send_len = INT16SZ + ns_buflen;
      BYTE *send_buf = (BYTE*) alloca (send_len);

      PUTSHORT (ns_buflen, send_buf);
      memcpy (send_buf + INT16SZ, ns_buf, ns_buflen);
      if (sock_write(sock,send_buf,send_len) != send_len)
      {
        Perror ("sock_write() failed", sockerr(sock));
        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;
      len -= n;
      if ((signed)len <= 0)
         break;
    }
    if (n <= 0)
    {
      Perror ("tcp_read() failed", sockerr(sock));
      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));
      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 = (sock_type*) calloc (sizeof(_udp_Socket), 1);
      if (!sock)
      {
        Perror ("calloc(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,(const 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);
}