Пример #1
0
// reference: ngx_http_proxy_process_status_line
ngx_int_t ngx_http_fetch_decode(ngx_http_request_t *r)
{
    ngx_http_fetch_ctx_t * ctx = ngx_http_fetch_get_module_ctx(r);
    if (!ctx)
    {
        return NGX_ERROR;
    }

    ngx_http_upstream_t * u = r->upstream;

    ngx_int_t rc = ngx_http_parse_status_line(r, &u->buffer, &ctx->status);

    if (rc == NGX_AGAIN)
    {
        return rc;
    }

    if (rc == NGX_ERROR)
    {
        r->http_version = NGX_HTTP_VERSION_9;
        u->state->status = NGX_HTTP_OK;
        u->headers_in.connection_close = 1;

        return NGX_OK;
    }

    if (u->state && u->state->status == 0)
    {
        u->state->status = ctx->status.code;
    }

    u->headers_in.status_n = ctx->status.code;

    size_t len = ctx->status.end - ctx->status.start;
    u->headers_in.status_line.len = len;

    u->headers_in.status_line.data = ngx_pnalloc(r->pool, len);
    if (!u->headers_in.status_line.data)
    {
        return NGX_ERROR;
    }

    ngx_memcpy(u->headers_in.status_line.data, ctx->status.start, len);

    if (ctx->status.http_version < NGX_HTTP_VERSION_11)
    {
        u->headers_in.connection_close = 1;
    }

    u->process_header = __decode_header;

    return __decode_header(r);
}
int __dns_lookup(const char *name, int type, int nscount, char **nsip,
			   unsigned char **outpacket, struct resolv_answer *a)
{
	int i, j, len, fd, pos, rc;
	struct timeval tv;
	fd_set fds;
	struct resolv_header h;
	struct resolv_question q;
	int retries = 0;
	unsigned char * packet = malloc(PACKETSZ);
	int outpacketlen;
	char *dns, *lookup = malloc(MAXDNAME);
	int variant = 0;
	struct sockaddr_in sa;
#ifdef __UCLIBC_HAS_IPV6__
	int v6;
	struct sockaddr_in6 sa6;
#endif

	fd = -1;

	if (!packet || !lookup || !nscount)
	    goto fail;

	DPRINTF("Looking up type %d answer for '%s'\n", type, name);

	LOCK;
	ns %= nscount;
	UNLOCK;

	while (retries++ < MAX_RETRIES) {
		if (fd != -1)
			close(fd);

		memset(packet, 0, PACKETSZ);

		memset(&h, 0, sizeof(h));

		/* Mess with globals while under lock */
		LOCK;
		++id;
		id &= 0xffff;
		h.id = id;
		dns = nsip[ns];
		UNLOCK;

		h.qdcount = 1;
		h.rd = 1;

		DPRINTF("encoding header\n", h.rd);

		i = __encode_header(&h, packet, PACKETSZ);
		if (i < 0)
			goto fail;

		strncpy(lookup,name,MAXDNAME);
		BIGLOCK;
		if (variant < __searchdomains && strchr(lookup, '.') == NULL)
		{
		    strncat(lookup,".", MAXDNAME);
		    strncat(lookup,__searchdomain[variant], MAXDNAME);
		}
		BIGUNLOCK;
		DPRINTF("lookup name: %s\n", lookup);
		q.dotted = (char *)lookup;
		q.qtype = type;
		q.qclass = C_IN; /* CLASS_IN */

		j = __encode_question(&q, packet+i, PACKETSZ-i);
		if (j < 0)
			goto fail;

		len = i + j;

		DPRINTF("On try %d, sending query to port %d of machine %s\n",
				retries, NAMESERVER_PORT, dns);

#ifdef __UCLIBC_HAS_IPV6__
		v6 = inet_pton(AF_INET6, dns, &sa6.sin6_addr) > 0;
		fd = socket(v6 ? AF_INET6 : AF_INET, SOCK_DGRAM, IPPROTO_UDP);
#else
		fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
#endif
		if (fd < 0) {
		    continue;
		}

		/* Connect to the UDP socket so that asyncronous errors are returned */		 
#ifdef __UCLIBC_HAS_IPV6__
		if (v6) {
		    sa6.sin6_family = AF_INET6;
		    sa6.sin6_port = htons(NAMESERVER_PORT);
		    /* sa6.sin6_addr is already here */
		    rc = connect(fd, (struct sockaddr *) &sa6, sizeof(sa6));
		} else {
#endif
		    sa.sin_family = AF_INET;
		    sa.sin_port = htons(NAMESERVER_PORT);
		    sa.sin_addr.s_addr = inet_addr(dns);
		    rc = connect(fd, (struct sockaddr *) &sa, sizeof(sa));
#ifdef __UCLIBC_HAS_IPV6__
		}
#endif
		if (rc < 0) {
		    if (errno == ENETUNREACH) {
			/* routing error, presume not transient */
			goto tryall;
		    } else
			/* retry */
			continue;
		}

		DPRINTF("Transmitting packet of length %d, id=%d, qr=%d\n",
				len, h.id, h.qr);

		send(fd, packet, len, 0);

		FD_ZERO(&fds);
		FD_SET(fd, &fds);
		tv.tv_sec = REPLY_TIMEOUT;
		tv.tv_usec = 0;
		if (select(fd + 1, &fds, NULL, NULL, &tv) <= 0) {
		    DPRINTF("Timeout\n");

			/* timed out, so retry send and receive, 
			 * to next nameserver on queue */
			goto again;
		}

		i = recv(fd, packet, 512, 0);
		outpacketlen = i;
		if (i < HFIXEDSZ) {
			/* too short ! */
			goto again;
		}

		__decode_header(packet, &h);

		DPRINTF("id = %d, qr = %d\n", h.id, h.qr);

		LOCK;
		if ((h.id != id) || (!h.qr)) {
			UNLOCK;
			/* unsolicited */
			goto again;
		}
		UNLOCK;


		DPRINTF("Got response %s\n", "(i think)!");
		DPRINTF("qrcount=%d,ancount=%d,nscount=%d,arcount=%d\n",
				h.qdcount, h.ancount, h.nscount, h.arcount);
		DPRINTF("opcode=%d,aa=%d,tc=%d,rd=%d,ra=%d,rcode=%d\n",
				h.opcode, h.aa, h.tc, h.rd, h.ra, h.rcode);

		if ((h.rcode) || (h.ancount < 1)) {
			/* negative result, not present */
			goto again;
		}

		pos = HFIXEDSZ;

		for (j = 0; j < h.qdcount; j++) {
			DPRINTF("Skipping question %d at %d\n", j, pos);
			i = __length_question(packet, pos);
			DPRINTF("Length of question %d is %d\n", j, i);
			if (i < 0)
				goto again;
			pos += i;
		}
		DPRINTF("Decoding answer at pos %d\n", pos);

		for (j=0;j<h.ancount;j++)
		{
		    i = __decode_answer(packet, pos, a);

		    if (i<0) {
			DPRINTF("failed decode %d\n", i);
			goto again;
		    }
		    /* For all but T_SIG, accept first answer */
		    if (a->atype != T_SIG)
			break;

		    DPRINTF("skipping T_SIG %d\n", i);
		    free(a->dotted);
		    pos += i;
		}

		DPRINTF("Answer name = |%s|\n", a->dotted);
		DPRINTF("Answer type = |%d|\n", a->atype);

		close(fd);

		if (outpacket)
			*outpacket = packet;
		else
			free(packet);
		free(lookup);
		return (outpacketlen);		/* success! */

	  tryall:
		/* if there are other nameservers, give them a go,
		   otherwise return with error */
		{
		    int sdomains;

		    BIGLOCK;
		    sdomains=__searchdomains;
		    BIGUNLOCK;
		    variant = 0;
		    if (retries >= nscount*(sdomains+1))
			goto fail;
		}

	  again:
		/* if there are searchdomains, try them or fallback as passed */
		{
		    int sdomains;
		    BIGLOCK;
		    sdomains=__searchdomains;
		    BIGUNLOCK;

		    if (variant < sdomains) {
			/* next search */
			variant++;
		    } else {
			/* next server, first search */
			LOCK;
			ns = (ns + 1) % nscount;
			UNLOCK;
			variant = 0;
		    }
		}
	}

fail:
	if (fd != -1)
	    close(fd);
	if (lookup)
	    free(lookup);
	if (packet)
	    free(packet);
	return -1;
}
int __decode_packet(unsigned char *data, struct resolv_header *h)
{
	return __decode_header(data, h);
}