Пример #1
0
MMDB_lookup_result_s lookup_sockaddr_ok(MMDB_s *mmdb, const char *ip,
                                        const char *file, const char *mode_desc)
{
    int ai_flags = AI_NUMERICHOST;
    struct addrinfo hints = {
        .ai_socktype = SOCK_STREAM
    };
    struct addrinfo *addresses;

    if (ip[0] == ':') {
        hints.ai_flags = ai_flags;
#ifdef AI_V4MAPPED
        hints.ai_flags |= AI_V4MAPPED;
#endif
        hints.ai_family = AF_INET6;
    } else {
        hints.ai_flags = ai_flags;
        hints.ai_family = AF_INET;
    }

    int gai_error = getaddrinfo(ip, NULL, &hints, &addresses);

    int mmdb_error = 0;
    MMDB_lookup_result_s result;
    if (gai_error == 0) {
        result = MMDB_lookup_sockaddr(mmdb, addresses->ai_addr, &mmdb_error);
    }
    freeaddrinfo(addresses);

    test_lookup_errors(gai_error, mmdb_error, "MMDB_lookup_sockaddr", ip, file,
                       mode_desc);

    return result;
}
MMDB_lookup_result_s lookup_sockaddr_ok(MMDB_s *mmdb, const char *ip,
                                        const char *file, const char *mode_desc)
{
    int ai_flags = AI_NUMERICHOST;
    struct addrinfo hints = {
        .ai_socktype = SOCK_STREAM
    };
    struct addrinfo *addresses = NULL;

    if (ip[0] == ':') {
        hints.ai_flags = ai_flags;
#if defined AI_V4MAPPED && !defined __FreeBSD__
        hints.ai_flags |= AI_V4MAPPED;
#endif
        hints.ai_family = AF_INET6;
    } else {
        hints.ai_flags = ai_flags;
        hints.ai_family = AF_INET;
    }

    int gai_error = getaddrinfo(ip, NULL, &hints, &addresses);

    int mmdb_error = 0;
    MMDB_lookup_result_s result = { .found_entry = false };
    if (gai_error == 0) {
        result = MMDB_lookup_sockaddr(mmdb, addresses->ai_addr, &mmdb_error);
    }
    if (NULL != addresses) {
        freeaddrinfo(addresses);
    }

    test_lookup_errors(gai_error, mmdb_error, "MMDB_lookup_sockaddr", ip, file,
                       mode_desc);

    return result;
}

void test_lookup_errors(int gai_error, int mmdb_error,
                        const char *function, const char *ip,
                        const char *file, const char *mode_desc)
{

    int is_ok = ok(0 == gai_error,
                   "no getaddrinfo error in call to %s for %s - %s - %s",
                   function, ip, file, mode_desc);

    if (!is_ok) {
        diag("error from call to getaddrinfo for %s - %s",
             ip, gai_strerror(gai_error));
    }

    is_ok = ok(0 == mmdb_error,
               "no MMDB error in call to %s for %s - %s - %s",
               function, ip, file, mode_desc);

    if (!is_ok) {
        diag("MMDB error - %s", MMDB_strerror(mmdb_error));
    }
}
static ngx_int_t
ngx_http_geoip2_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
    uintptr_t data)
{
    ngx_http_geoip2_ctx_t   *geoip2 = (ngx_http_geoip2_ctx_t *) data;
    ngx_http_geoip2_db_t    *database = geoip2->database;
    int                     mmdb_error;
    MMDB_entry_data_s       entry_data;
    ngx_http_geoip2_conf_t  *gcf;
    ngx_addr_t              addr;
    ngx_array_t             *xfwd;
    u_char                  *p;

#if (NGX_HAVE_INET6)
    uint8_t address[16], *addressp = address;
#else
    unsigned long address;
#endif

    gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip2_module);
    addr.sockaddr = r->connection->sockaddr;
    addr.socklen = r->connection->socklen;

    xfwd = &r->headers_in.x_forwarded_for;

    if (xfwd->nelts > 0 && gcf->proxies != NULL) {
        (void) ngx_http_get_forwarded_addr(r, &addr, xfwd, NULL,
                                           gcf->proxies, gcf->proxy_recursive);
    }

    switch (addr.sockaddr->sa_family) {
        case AF_INET:
#if (NGX_HAVE_INET6)
            ngx_memset(addressp, 0, 12);
            ngx_memcpy(addressp + 12, &((struct sockaddr_in *)
                                        addr.sockaddr)->sin_addr.s_addr, 4);
            break;

        case AF_INET6:
            ngx_memcpy(addressp, &((struct sockaddr_in6 *)
                                   addr.sockaddr)->sin6_addr.s6_addr, 16);
#else
            address = ((struct sockaddr_in *)addr.sockaddr)->sin_addr.s_addr;
#endif
            break;

        default:
            goto not_found;
    }

#if (NGX_HAVE_INET6)
    if (ngx_memcmp(&address, &database->address, sizeof(address))
        != 0) {
#else
    if (address != database->address) {
#endif
        memcpy(&database->address, &address, sizeof(address));
        database->result = MMDB_lookup_sockaddr(&database->mmdb,
                                           addr.sockaddr, &mmdb_error);

        if (mmdb_error != MMDB_SUCCESS) {
            goto not_found;
        }
    }

    if (!database->result.found_entry
            || MMDB_aget_value(&database->result.entry, &entry_data,
                               geoip2->lookup) != MMDB_SUCCESS) {
        goto not_found;
    }

    if (!entry_data.has_data) {
        goto not_found;
    }

    switch (entry_data.type) {
        case MMDB_DATA_TYPE_UTF8_STRING:
            v->data = (u_char *) entry_data.utf8_string;
            v->len = entry_data.data_size;
            break;
        case MMDB_DATA_TYPE_UINT32:
            p = ngx_palloc(r->pool, NGX_OFF_T_LEN);
            if (p == NULL) {
                return NGX_ERROR;
            }
            v->len = ngx_sprintf(p, "%O", entry_data.uint32) - p;
            v->data = p;
            break;
        default:
            goto not_found;
    }

    v->valid = 1;
    v->no_cacheable = 0;
    v->not_found = 0;

    return NGX_OK;

not_found:
    if (geoip2->default_value.len > 0) {
        v->data = geoip2->default_value.data;
        v->len = geoip2->default_value.len;

        v->valid = 1;
        v->no_cacheable = 0;
        v->not_found = 0;
    } else {
        v->not_found = 1;
    }

    return NGX_OK;
}


static void *
ngx_http_geoip2_create_conf(ngx_conf_t *cf)
{
    ngx_pool_cleanup_t      *cln;
    ngx_http_geoip2_conf_t  *conf;

    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip2_conf_t));
    if (conf == NULL) {
        return NULL;
    }

    conf->proxy_recursive = NGX_CONF_UNSET;

    cln = ngx_pool_cleanup_add(cf->pool, 0);
    if (cln == NULL) {
        return NULL;
    }

    cln->handler = ngx_http_geoip2_cleanup;
    cln->data = conf;

    return conf;
}
Пример #4
0
vmod_geoip2_lookup(VRT_CTX, struct vmod_geoip2_geoip2 *vp,
    VCL_STRING path, VCL_IP addr)
{
	MMDB_lookup_result_s res;
	MMDB_entry_data_s data;
	const struct sockaddr *sa;
	socklen_t addrlen;
	const char **ap, *arrpath[COMPONENT_MAX];
	char buf[LOOKUP_PATH_MAX];
	char *p, *last;
	uint32_t i;
	int error;

	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
	AN(addr);

	if (!vp) {
		VSLb(ctx->vsl, SLT_Error,
		    "geoip2.lookup: Database not open");
		return (NULL);
	}

	if (!path || !*path || strlen(path) >= sizeof(buf)) {
		VSLb(ctx->vsl, SLT_Error,
		    "geoip2.lookup: Invalid or missing path (%s)",
		    path ? path : "NULL");
		return (NULL);
	}

	sa = VSA_Get_Sockaddr(addr, &addrlen);
	AN(sa);

	res = MMDB_lookup_sockaddr(&vp->mmdb, sa, &error);
	if (error != MMDB_SUCCESS) {
		VSLb(ctx->vsl, SLT_Error,
		    "geoip2.lookup: MMDB_lookup_sockaddr: %s",
		    MMDB_strerror(error));
		return (NULL);
	}

	if (!res.found_entry) {
		VSLb(ctx->vsl, SLT_Debug,
		    "geoip2.lookup: No entry for this IP address (%s)",
		    VRT_IP_string(ctx, addr));
		return (NULL);
	}

	strncpy(buf, path, sizeof(buf));

	last = NULL;
	for (p = buf, ap = arrpath; ap < &arrpath[COMPONENT_MAX - 1] &&
	    (*ap = strtok_r(p, "/", &last)) != NULL; p = NULL) {
		if (**ap != '\0')
			ap++;
	}
	*ap = NULL;

	error = MMDB_aget_value(&res.entry, &data, arrpath);
	if (error != MMDB_SUCCESS &&
	    error != MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR) {
		VSLb(ctx->vsl, SLT_Error,
		    "geoip2.lookup: MMDB_aget_value: %s",
		    MMDB_strerror(error));
		return (NULL);
	}

	if (!data.has_data) {
		VSLb(ctx->vsl, SLT_Debug,
		    "geoip2.lookup: No data for this path (%s)",
		    path);
		return (NULL);
	}

	switch (data.type) {
	case MMDB_DATA_TYPE_BOOLEAN:
		p = WS_Printf(ctx->ws, "%s", data.boolean ?
		    "true" : "false");
		break;

	case MMDB_DATA_TYPE_BYTES:
		p = WS_Alloc(ctx->ws, data.data_size * 2 + 1);
		if (p)
			for (i = 0; i < data.data_size; i++)
				sprintf(&p[i * 2], "%02X", data.bytes[i]);
		break;

	case MMDB_DATA_TYPE_DOUBLE:
		p = WS_Printf(ctx->ws, "%f", data.double_value);
		break;

	case MMDB_DATA_TYPE_FLOAT:
		p = WS_Printf(ctx->ws, "%f", data.float_value);
		break;

	case MMDB_DATA_TYPE_INT32:
		p = WS_Printf(ctx->ws, "%i", data.int32);
		break;

	case MMDB_DATA_TYPE_UINT16:
		p = WS_Printf(ctx->ws, "%u", data.uint16);
		break;

	case MMDB_DATA_TYPE_UINT32:
		p = WS_Printf(ctx->ws, "%u", data.uint32);
		break;

	case MMDB_DATA_TYPE_UINT64:
		p = WS_Printf(ctx->ws, "%ju", (uintmax_t)data.uint64);
		break;

	case MMDB_DATA_TYPE_UTF8_STRING:
		p = WS_Alloc(ctx->ws, data.data_size + 1);
		if (p) {
			memcpy(p, data.utf8_string, data.data_size);
			p[data.data_size] = '\0';
		}
		break;

	default:
		VSLb(ctx->vsl, SLT_Error,
		    "geoip2.lookup: Unsupported data type (%d)",
		    data.type);
		return (NULL);
	}

	if (!p)
		VSLb(ctx->vsl, SLT_Error,
		    "geoip2.lookup: Out of workspace");

	return (p);
}