1e18a033bSKonstantin Ananyev
2e18a033bSKonstantin Ananyev/*
3e18a033bSKonstantin Ananyev * Copyright (C) Igor Sysoev
4e18a033bSKonstantin Ananyev * Copyright (C) Nginx, Inc.
5e18a033bSKonstantin Ananyev */
6e18a033bSKonstantin Ananyev
7e18a033bSKonstantin Ananyev
8e18a033bSKonstantin Ananyev#include <ngx_config.h>
9e18a033bSKonstantin Ananyev#include <ngx_core.h>
10e18a033bSKonstantin Ananyev#include <ngx_stream.h>
11e18a033bSKonstantin Ananyev
12e18a033bSKonstantin Ananyev#include <GeoIP.h>
13e18a033bSKonstantin Ananyev#include <GeoIPCity.h>
14e18a033bSKonstantin Ananyev
15e18a033bSKonstantin Ananyev
16e18a033bSKonstantin Ananyev#define NGX_GEOIP_COUNTRY_CODE   0
17e18a033bSKonstantin Ananyev#define NGX_GEOIP_COUNTRY_CODE3  1
18e18a033bSKonstantin Ananyev#define NGX_GEOIP_COUNTRY_NAME   2
19e18a033bSKonstantin Ananyev
20e18a033bSKonstantin Ananyev
21e18a033bSKonstantin Ananyevtypedef struct {
22e18a033bSKonstantin Ananyev    GeoIP        *country;
23e18a033bSKonstantin Ananyev    GeoIP        *org;
24e18a033bSKonstantin Ananyev    GeoIP        *city;
25e18a033bSKonstantin Ananyev#if (NGX_HAVE_GEOIP_V6)
26e18a033bSKonstantin Ananyev    unsigned      country_v6:1;
27e18a033bSKonstantin Ananyev    unsigned      org_v6:1;
28e18a033bSKonstantin Ananyev    unsigned      city_v6:1;
29e18a033bSKonstantin Ananyev#endif
30e18a033bSKonstantin Ananyev} ngx_stream_geoip_conf_t;
31e18a033bSKonstantin Ananyev
32e18a033bSKonstantin Ananyev
33e18a033bSKonstantin Ananyevtypedef struct {
34e18a033bSKonstantin Ananyev    ngx_str_t    *name;
35e18a033bSKonstantin Ananyev    uintptr_t     data;
36e18a033bSKonstantin Ananyev} ngx_stream_geoip_var_t;
37e18a033bSKonstantin Ananyev
38e18a033bSKonstantin Ananyev
39e18a033bSKonstantin Ananyevtypedef const char *(*ngx_stream_geoip_variable_handler_pt)(GeoIP *,
40e18a033bSKonstantin Ananyev    u_long addr);
41e18a033bSKonstantin Ananyev
42e18a033bSKonstantin Ananyev
43e18a033bSKonstantin Ananyevngx_stream_geoip_variable_handler_pt ngx_stream_geoip_country_functions[] = {
44e18a033bSKonstantin Ananyev    GeoIP_country_code_by_ipnum,
45e18a033bSKonstantin Ananyev    GeoIP_country_code3_by_ipnum,
46e18a033bSKonstantin Ananyev    GeoIP_country_name_by_ipnum,
47e18a033bSKonstantin Ananyev};
48e18a033bSKonstantin Ananyev
49e18a033bSKonstantin Ananyev
50e18a033bSKonstantin Ananyev#if (NGX_HAVE_GEOIP_V6)
51e18a033bSKonstantin Ananyev
52e18a033bSKonstantin Ananyevtypedef const char *(*ngx_stream_geoip_variable_handler_v6_pt)(GeoIP *,
53e18a033bSKonstantin Ananyev    geoipv6_t addr);
54e18a033bSKonstantin Ananyev
55e18a033bSKonstantin Ananyev
56e18a033bSKonstantin Ananyevngx_stream_geoip_variable_handler_v6_pt
57e18a033bSKonstantin Ananyev    ngx_stream_geoip_country_v6_functions[] =
58e18a033bSKonstantin Ananyev{
59e18a033bSKonstantin Ananyev    GeoIP_country_code_by_ipnum_v6,
60e18a033bSKonstantin Ananyev    GeoIP_country_code3_by_ipnum_v6,
61e18a033bSKonstantin Ananyev    GeoIP_country_name_by_ipnum_v6,
62e18a033bSKonstantin Ananyev};
63e18a033bSKonstantin Ananyev
64e18a033bSKonstantin Ananyev#endif
65e18a033bSKonstantin Ananyev
66e18a033bSKonstantin Ananyev
67e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_geoip_country_variable(ngx_stream_session_t *s,
68e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t *v, uintptr_t data);
69e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_geoip_org_variable(ngx_stream_session_t *s,
70e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t *v, uintptr_t data);
71e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_geoip_city_variable(ngx_stream_session_t *s,
72e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t *v, uintptr_t data);
73e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_geoip_region_name_variable(ngx_stream_session_t *s,
74e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t *v, uintptr_t data);
75e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_geoip_city_float_variable(ngx_stream_session_t *s,
76e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t *v, uintptr_t data);
77e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_geoip_city_int_variable(ngx_stream_session_t *s,
78e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t *v, uintptr_t data);
79e18a033bSKonstantin Ananyevstatic GeoIPRecord *ngx_stream_geoip_get_city_record(ngx_stream_session_t *s);
80e18a033bSKonstantin Ananyev
81e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_geoip_add_variables(ngx_conf_t *cf);
82e18a033bSKonstantin Ananyevstatic void *ngx_stream_geoip_create_conf(ngx_conf_t *cf);
83e18a033bSKonstantin Ananyevstatic char *ngx_stream_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd,
84e18a033bSKonstantin Ananyev    void *conf);
85e18a033bSKonstantin Ananyevstatic char *ngx_stream_geoip_org(ngx_conf_t *cf, ngx_command_t *cmd,
86e18a033bSKonstantin Ananyev    void *conf);
87e18a033bSKonstantin Ananyevstatic char *ngx_stream_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd,
88e18a033bSKonstantin Ananyev    void *conf);
89e18a033bSKonstantin Ananyevstatic void ngx_stream_geoip_cleanup(void *data);
90e18a033bSKonstantin Ananyev
91e18a033bSKonstantin Ananyev
92e18a033bSKonstantin Ananyevstatic ngx_command_t  ngx_stream_geoip_commands[] = {
93e18a033bSKonstantin Ananyev
94e18a033bSKonstantin Ananyev    { ngx_string("geoip_country"),
95e18a033bSKonstantin Ananyev      NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE12,
96e18a033bSKonstantin Ananyev      ngx_stream_geoip_country,
97e18a033bSKonstantin Ananyev      NGX_STREAM_MAIN_CONF_OFFSET,
98e18a033bSKonstantin Ananyev      0,
99e18a033bSKonstantin Ananyev      NULL },
100e18a033bSKonstantin Ananyev
101e18a033bSKonstantin Ananyev    { ngx_string("geoip_org"),
102e18a033bSKonstantin Ananyev      NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE12,
103e18a033bSKonstantin Ananyev      ngx_stream_geoip_org,
104e18a033bSKonstantin Ananyev      NGX_STREAM_MAIN_CONF_OFFSET,
105e18a033bSKonstantin Ananyev      0,
106e18a033bSKonstantin Ananyev      NULL },
107e18a033bSKonstantin Ananyev
108e18a033bSKonstantin Ananyev    { ngx_string("geoip_city"),
109e18a033bSKonstantin Ananyev      NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE12,
110e18a033bSKonstantin Ananyev      ngx_stream_geoip_city,
111e18a033bSKonstantin Ananyev      NGX_STREAM_MAIN_CONF_OFFSET,
112e18a033bSKonstantin Ananyev      0,
113e18a033bSKonstantin Ananyev      NULL },
114e18a033bSKonstantin Ananyev
115e18a033bSKonstantin Ananyev      ngx_null_command
116e18a033bSKonstantin Ananyev};
117e18a033bSKonstantin Ananyev
118e18a033bSKonstantin Ananyev
119e18a033bSKonstantin Ananyevstatic ngx_stream_module_t  ngx_stream_geoip_module_ctx = {
120e18a033bSKonstantin Ananyev    ngx_stream_geoip_add_variables,        /* preconfiguration */
121e18a033bSKonstantin Ananyev    NULL,                                  /* postconfiguration */
122e18a033bSKonstantin Ananyev
123e18a033bSKonstantin Ananyev    ngx_stream_geoip_create_conf,          /* create main configuration */
124e18a033bSKonstantin Ananyev    NULL,                                  /* init main configuration */
125e18a033bSKonstantin Ananyev
126e18a033bSKonstantin Ananyev    NULL,                                  /* create server configuration */
127e18a033bSKonstantin Ananyev    NULL                                   /* merge server configuration */
128e18a033bSKonstantin Ananyev};
129e18a033bSKonstantin Ananyev
130e18a033bSKonstantin Ananyev
131e18a033bSKonstantin Ananyevngx_module_t  ngx_stream_geoip_module = {
132e18a033bSKonstantin Ananyev    NGX_MODULE_V1,
133e18a033bSKonstantin Ananyev    &ngx_stream_geoip_module_ctx,          /* module context */
134e18a033bSKonstantin Ananyev    ngx_stream_geoip_commands,             /* module directives */
135e18a033bSKonstantin Ananyev    NGX_STREAM_MODULE,                     /* module type */
136e18a033bSKonstantin Ananyev    NULL,                                  /* init master */
137e18a033bSKonstantin Ananyev    NULL,                                  /* init module */
138e18a033bSKonstantin Ananyev    NULL,                                  /* init process */
139e18a033bSKonstantin Ananyev    NULL,                                  /* init thread */
140e18a033bSKonstantin Ananyev    NULL,                                  /* exit thread */
141e18a033bSKonstantin Ananyev    NULL,                                  /* exit process */
142e18a033bSKonstantin Ananyev    NULL,                                  /* exit master */
143e18a033bSKonstantin Ananyev    NGX_MODULE_V1_PADDING
144e18a033bSKonstantin Ananyev};
145e18a033bSKonstantin Ananyev
146e18a033bSKonstantin Ananyev
147e18a033bSKonstantin Ananyevstatic ngx_stream_variable_t  ngx_stream_geoip_vars[] = {
148e18a033bSKonstantin Ananyev
149e18a033bSKonstantin Ananyev    { ngx_string("geoip_country_code"), NULL,
150e18a033bSKonstantin Ananyev      ngx_stream_geoip_country_variable,
151e18a033bSKonstantin Ananyev      NGX_GEOIP_COUNTRY_CODE, 0, 0 },
152e18a033bSKonstantin Ananyev
153e18a033bSKonstantin Ananyev    { ngx_string("geoip_country_code3"), NULL,
154e18a033bSKonstantin Ananyev      ngx_stream_geoip_country_variable,
155e18a033bSKonstantin Ananyev      NGX_GEOIP_COUNTRY_CODE3, 0, 0 },
156e18a033bSKonstantin Ananyev
157e18a033bSKonstantin Ananyev    { ngx_string("geoip_country_name"), NULL,
158e18a033bSKonstantin Ananyev      ngx_stream_geoip_country_variable,
159e18a033bSKonstantin Ananyev      NGX_GEOIP_COUNTRY_NAME, 0, 0 },
160e18a033bSKonstantin Ananyev
161e18a033bSKonstantin Ananyev    { ngx_string("geoip_org"), NULL,
162e18a033bSKonstantin Ananyev      ngx_stream_geoip_org_variable,
163e18a033bSKonstantin Ananyev      0, 0, 0 },
164e18a033bSKonstantin Ananyev
165e18a033bSKonstantin Ananyev    { ngx_string("geoip_city_continent_code"), NULL,
166e18a033bSKonstantin Ananyev      ngx_stream_geoip_city_variable,
167e18a033bSKonstantin Ananyev      offsetof(GeoIPRecord, continent_code), 0, 0 },
168e18a033bSKonstantin Ananyev
169e18a033bSKonstantin Ananyev    { ngx_string("geoip_city_country_code"), NULL,
170e18a033bSKonstantin Ananyev      ngx_stream_geoip_city_variable,
171e18a033bSKonstantin Ananyev      offsetof(GeoIPRecord, country_code), 0, 0 },
172e18a033bSKonstantin Ananyev
173e18a033bSKonstantin Ananyev    { ngx_string("geoip_city_country_code3"), NULL,
174e18a033bSKonstantin Ananyev      ngx_stream_geoip_city_variable,
175e18a033bSKonstantin Ananyev      offsetof(GeoIPRecord, country_code3), 0, 0 },
176e18a033bSKonstantin Ananyev
177e18a033bSKonstantin Ananyev    { ngx_string("geoip_city_country_name"), NULL,
178e18a033bSKonstantin Ananyev      ngx_stream_geoip_city_variable,
179e18a033bSKonstantin Ananyev      offsetof(GeoIPRecord, country_name), 0, 0 },
180e18a033bSKonstantin Ananyev
181e18a033bSKonstantin Ananyev    { ngx_string("geoip_region"), NULL,
182e18a033bSKonstantin Ananyev      ngx_stream_geoip_city_variable,
183e18a033bSKonstantin Ananyev      offsetof(GeoIPRecord, region), 0, 0 },
184e18a033bSKonstantin Ananyev
185e18a033bSKonstantin Ananyev    { ngx_string("geoip_region_name"), NULL,
186e18a033bSKonstantin Ananyev      ngx_stream_geoip_region_name_variable,
187e18a033bSKonstantin Ananyev      0, 0, 0 },
188e18a033bSKonstantin Ananyev
189e18a033bSKonstantin Ananyev    { ngx_string("geoip_city"), NULL,
190e18a033bSKonstantin Ananyev      ngx_stream_geoip_city_variable,
191e18a033bSKonstantin Ananyev      offsetof(GeoIPRecord, city), 0, 0 },
192e18a033bSKonstantin Ananyev
193e18a033bSKonstantin Ananyev    { ngx_string("geoip_postal_code"), NULL,
194e18a033bSKonstantin Ananyev      ngx_stream_geoip_city_variable,
195e18a033bSKonstantin Ananyev      offsetof(GeoIPRecord, postal_code), 0, 0 },
196e18a033bSKonstantin Ananyev
197e18a033bSKonstantin Ananyev    { ngx_string("geoip_latitude"), NULL,
198e18a033bSKonstantin Ananyev      ngx_stream_geoip_city_float_variable,
199e18a033bSKonstantin Ananyev      offsetof(GeoIPRecord, latitude), 0, 0 },
200e18a033bSKonstantin Ananyev
201e18a033bSKonstantin Ananyev    { ngx_string("geoip_longitude"), NULL,
202e18a033bSKonstantin Ananyev      ngx_stream_geoip_city_float_variable,
203e18a033bSKonstantin Ananyev      offsetof(GeoIPRecord, longitude), 0, 0 },
204e18a033bSKonstantin Ananyev
205e18a033bSKonstantin Ananyev    { ngx_string("geoip_dma_code"), NULL,
206e18a033bSKonstantin Ananyev      ngx_stream_geoip_city_int_variable,
207e18a033bSKonstantin Ananyev      offsetof(GeoIPRecord, dma_code), 0, 0 },
208e18a033bSKonstantin Ananyev
209e18a033bSKonstantin Ananyev    { ngx_string("geoip_area_code"), NULL,
210e18a033bSKonstantin Ananyev      ngx_stream_geoip_city_int_variable,
211e18a033bSKonstantin Ananyev      offsetof(GeoIPRecord, area_code), 0, 0 },
212e18a033bSKonstantin Ananyev
213e18a033bSKonstantin Ananyev    { ngx_null_string, NULL, NULL, 0, 0, 0 }
214e18a033bSKonstantin Ananyev};
215e18a033bSKonstantin Ananyev
216e18a033bSKonstantin Ananyev
217e18a033bSKonstantin Ananyevstatic u_long
218e18a033bSKonstantin Ananyevngx_stream_geoip_addr(ngx_stream_session_t *s, ngx_stream_geoip_conf_t *gcf)
219e18a033bSKonstantin Ananyev{
220e18a033bSKonstantin Ananyev    ngx_addr_t           addr;
221e18a033bSKonstantin Ananyev    struct sockaddr_in  *sin;
222e18a033bSKonstantin Ananyev
223e18a033bSKonstantin Ananyev    addr.sockaddr = s->connection->sockaddr;
224e18a033bSKonstantin Ananyev    addr.socklen = s->connection->socklen;
225e18a033bSKonstantin Ananyev    /* addr.name = s->connection->addr_text; */
226e18a033bSKonstantin Ananyev
227e18a033bSKonstantin Ananyev#if (NGX_HAVE_INET6)
228e18a033bSKonstantin Ananyev
229e18a033bSKonstantin Ananyev    if (addr.sockaddr->sa_family == AF_INET6) {
230e18a033bSKonstantin Ananyev        u_char           *p;
231e18a033bSKonstantin Ananyev        in_addr_t         inaddr;
232e18a033bSKonstantin Ananyev        struct in6_addr  *inaddr6;
233e18a033bSKonstantin Ananyev
234e18a033bSKonstantin Ananyev        inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr;
235e18a033bSKonstantin Ananyev
236e18a033bSKonstantin Ananyev        if (IN6_IS_ADDR_V4MAPPED(inaddr6)) {
237e18a033bSKonstantin Ananyev            p = inaddr6->s6_addr;
238e18a033bSKonstantin Ananyev
239e18a033bSKonstantin Ananyev            inaddr = p[12] << 24;
240e18a033bSKonstantin Ananyev            inaddr += p[13] << 16;
241e18a033bSKonstantin Ananyev            inaddr += p[14] << 8;
242e18a033bSKonstantin Ananyev            inaddr += p[15];
243e18a033bSKonstantin Ananyev
244e18a033bSKonstantin Ananyev            return inaddr;
245e18a033bSKonstantin Ananyev        }
246e18a033bSKonstantin Ananyev    }
247e18a033bSKonstantin Ananyev
248e18a033bSKonstantin Ananyev#endif
249e18a033bSKonstantin Ananyev
250e18a033bSKonstantin Ananyev    if (addr.sockaddr->sa_family != AF_INET) {
251e18a033bSKonstantin Ananyev        return INADDR_NONE;
252e18a033bSKonstantin Ananyev    }
253e18a033bSKonstantin Ananyev
254e18a033bSKonstantin Ananyev    sin = (struct sockaddr_in *) addr.sockaddr;
255e18a033bSKonstantin Ananyev    return ntohl(sin->sin_addr.s_addr);
256e18a033bSKonstantin Ananyev}
257e18a033bSKonstantin Ananyev
258e18a033bSKonstantin Ananyev
259e18a033bSKonstantin Ananyev#if (NGX_HAVE_GEOIP_V6)
260e18a033bSKonstantin Ananyev
261e18a033bSKonstantin Ananyevstatic geoipv6_t
262e18a033bSKonstantin Ananyevngx_stream_geoip_addr_v6(ngx_stream_session_t *s, ngx_stream_geoip_conf_t *gcf)
263e18a033bSKonstantin Ananyev{
264e18a033bSKonstantin Ananyev    ngx_addr_t            addr;
265e18a033bSKonstantin Ananyev    in_addr_t             addr4;
266e18a033bSKonstantin Ananyev    struct in6_addr       addr6;
267e18a033bSKonstantin Ananyev    struct sockaddr_in   *sin;
268e18a033bSKonstantin Ananyev    struct sockaddr_in6  *sin6;
269e18a033bSKonstantin Ananyev
270e18a033bSKonstantin Ananyev    addr.sockaddr = s->connection->sockaddr;
271e18a033bSKonstantin Ananyev    addr.socklen = s->connection->socklen;
272e18a033bSKonstantin Ananyev    /* addr.name = s->connection->addr_text; */
273e18a033bSKonstantin Ananyev
274e18a033bSKonstantin Ananyev    switch (addr.sockaddr->sa_family) {
275e18a033bSKonstantin Ananyev
276e18a033bSKonstantin Ananyev    case AF_INET:
277e18a033bSKonstantin Ananyev        /* Produce IPv4-mapped IPv6 address. */
278e18a033bSKonstantin Ananyev        sin = (struct sockaddr_in *) addr.sockaddr;
279e18a033bSKonstantin Ananyev        addr4 = ntohl(sin->sin_addr.s_addr);
280e18a033bSKonstantin Ananyev
281e18a033bSKonstantin Ananyev        ngx_memzero(&addr6, sizeof(struct in6_addr));
282e18a033bSKonstantin Ananyev        addr6.s6_addr[10] = 0xff;
283e18a033bSKonstantin Ananyev        addr6.s6_addr[11] = 0xff;
284e18a033bSKonstantin Ananyev        addr6.s6_addr[12] = addr4 >> 24;
285e18a033bSKonstantin Ananyev        addr6.s6_addr[13] = addr4 >> 16;
286e18a033bSKonstantin Ananyev        addr6.s6_addr[14] = addr4 >> 8;
287e18a033bSKonstantin Ananyev        addr6.s6_addr[15] = addr4;
288e18a033bSKonstantin Ananyev        return addr6;
289e18a033bSKonstantin Ananyev
290e18a033bSKonstantin Ananyev    case AF_INET6:
291e18a033bSKonstantin Ananyev        sin6 = (struct sockaddr_in6 *) addr.sockaddr;
292e18a033bSKonstantin Ananyev        return sin6->sin6_addr;
293e18a033bSKonstantin Ananyev
294e18a033bSKonstantin Ananyev    default:
295e18a033bSKonstantin Ananyev        return in6addr_any;
296e18a033bSKonstantin Ananyev    }
297e18a033bSKonstantin Ananyev}
298e18a033bSKonstantin Ananyev
299e18a033bSKonstantin Ananyev#endif
300e18a033bSKonstantin Ananyev
301e18a033bSKonstantin Ananyev
302e18a033bSKonstantin Ananyevstatic ngx_int_t
303e18a033bSKonstantin Ananyevngx_stream_geoip_country_variable(ngx_stream_session_t *s,
304e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t *v, uintptr_t data)
305e18a033bSKonstantin Ananyev{
306e18a033bSKonstantin Ananyev    ngx_stream_geoip_variable_handler_pt     handler =
307e18a033bSKonstantin Ananyev        ngx_stream_geoip_country_functions[data];
308e18a033bSKonstantin Ananyev#if (NGX_HAVE_GEOIP_V6)
309e18a033bSKonstantin Ananyev    ngx_stream_geoip_variable_handler_v6_pt  handler_v6 =
310e18a033bSKonstantin Ananyev        ngx_stream_geoip_country_v6_functions[data];
311e18a033bSKonstantin Ananyev#endif
312e18a033bSKonstantin Ananyev
313e18a033bSKonstantin Ananyev    const char               *val;
314e18a033bSKonstantin Ananyev    ngx_stream_geoip_conf_t  *gcf;
315e18a033bSKonstantin Ananyev
316e18a033bSKonstantin Ananyev    gcf = ngx_stream_get_module_main_conf(s, ngx_stream_geoip_module);
317e18a033bSKonstantin Ananyev
318e18a033bSKonstantin Ananyev    if (gcf->country == NULL) {
319e18a033bSKonstantin Ananyev        goto not_found;
320e18a033bSKonstantin Ananyev    }
321e18a033bSKonstantin Ananyev
322e18a033bSKonstantin Ananyev#if (NGX_HAVE_GEOIP_V6)
323e18a033bSKonstantin Ananyev    val = gcf->country_v6
324e18a033bSKonstantin Ananyev              ? handler_v6(gcf->country, ngx_stream_geoip_addr_v6(s, gcf))
325e18a033bSKonstantin Ananyev              : handler(gcf->country, ngx_stream_geoip_addr(s, gcf));
326e18a033bSKonstantin Ananyev#else
327e18a033bSKonstantin Ananyev    val = handler(gcf->country, ngx_stream_geoip_addr(s, gcf));
328e18a033bSKonstantin Ananyev#endif
329e18a033bSKonstantin Ananyev
330e18a033bSKonstantin Ananyev    if (val == NULL) {
331e18a033bSKonstantin Ananyev        goto not_found;
332e18a033bSKonstantin Ananyev    }
333e18a033bSKonstantin Ananyev
334e18a033bSKonstantin Ananyev    v->len = ngx_strlen(val);
335e18a033bSKonstantin Ananyev    v->valid = 1;
336e18a033bSKonstantin Ananyev    v->no_cacheable = 0;
337e18a033bSKonstantin Ananyev    v->not_found = 0;
338e18a033bSKonstantin Ananyev    v->data = (u_char *) val;
339e18a033bSKonstantin Ananyev
340e18a033bSKonstantin Ananyev    return NGX_OK;
341e18a033bSKonstantin Ananyev
342e18a033bSKonstantin Ananyevnot_found:
343e18a033bSKonstantin Ananyev
344e18a033bSKonstantin Ananyev    v->not_found = 1;
345e18a033bSKonstantin Ananyev
346e18a033bSKonstantin Ananyev    return NGX_OK;
347e18a033bSKonstantin Ananyev}
348e18a033bSKonstantin Ananyev
349e18a033bSKonstantin Ananyev
350e18a033bSKonstantin Ananyevstatic ngx_int_t
351e18a033bSKonstantin Ananyevngx_stream_geoip_org_variable(ngx_stream_session_t *s,
352e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t *v, uintptr_t data)
353e18a033bSKonstantin Ananyev{
354e18a033bSKonstantin Ananyev    size_t                    len;
355e18a033bSKonstantin Ananyev    char                     *val;
356e18a033bSKonstantin Ananyev    ngx_stream_geoip_conf_t  *gcf;
357e18a033bSKonstantin Ananyev
358e18a033bSKonstantin Ananyev    gcf = ngx_stream_get_module_main_conf(s, ngx_stream_geoip_module);
359e18a033bSKonstantin Ananyev
360e18a033bSKonstantin Ananyev    if (gcf->org == NULL) {
361e18a033bSKonstantin Ananyev        goto not_found;
362e18a033bSKonstantin Ananyev    }
363e18a033bSKonstantin Ananyev
364e18a033bSKonstantin Ananyev#if (NGX_HAVE_GEOIP_V6)
365e18a033bSKonstantin Ananyev    val = gcf->org_v6
366e18a033bSKonstantin Ananyev              ? GeoIP_name_by_ipnum_v6(gcf->org,
367e18a033bSKonstantin Ananyev                                       ngx_stream_geoip_addr_v6(s, gcf))
368e18a033bSKonstantin Ananyev              : GeoIP_name_by_ipnum(gcf->org,
369e18a033bSKonstantin Ananyev                                    ngx_stream_geoip_addr(s, gcf));
370e18a033bSKonstantin Ananyev#else
371e18a033bSKonstantin Ananyev    val = GeoIP_name_by_ipnum(gcf->org, ngx_stream_geoip_addr(s, gcf));
372e18a033bSKonstantin Ananyev#endif
373e18a033bSKonstantin Ananyev
374e18a033bSKonstantin Ananyev    if (val == NULL) {
375e18a033bSKonstantin Ananyev        goto not_found;
376e18a033bSKonstantin Ananyev    }
377e18a033bSKonstantin Ananyev
378e18a033bSKonstantin Ananyev    len = ngx_strlen(val);
379e18a033bSKonstantin Ananyev    v->data = ngx_pnalloc(s->connection->pool, len);
380e18a033bSKonstantin Ananyev    if (v->data == NULL) {
381e18a033bSKonstantin Ananyev        ngx_free(val);
382e18a033bSKonstantin Ananyev        return NGX_ERROR;
383e18a033bSKonstantin Ananyev    }
384e18a033bSKonstantin Ananyev
385e18a033bSKonstantin Ananyev    ngx_memcpy(v->data, val, len);
386e18a033bSKonstantin Ananyev
387e18a033bSKonstantin Ananyev    v->len = len;
388e18a033bSKonstantin Ananyev    v->valid = 1;
389e18a033bSKonstantin Ananyev    v->no_cacheable = 0;
390e18a033bSKonstantin Ananyev    v->not_found = 0;
391e18a033bSKonstantin Ananyev
392e18a033bSKonstantin Ananyev    ngx_free(val);
393e18a033bSKonstantin Ananyev
394e18a033bSKonstantin Ananyev    return NGX_OK;
395e18a033bSKonstantin Ananyev
396e18a033bSKonstantin Ananyevnot_found:
397e18a033bSKonstantin Ananyev
398e18a033bSKonstantin Ananyev    v->not_found = 1;
399e18a033bSKonstantin Ananyev
400e18a033bSKonstantin Ananyev    return NGX_OK;
401e18a033bSKonstantin Ananyev}
402e18a033bSKonstantin Ananyev
403e18a033bSKonstantin Ananyev
404e18a033bSKonstantin Ananyevstatic ngx_int_t
405e18a033bSKonstantin Ananyevngx_stream_geoip_city_variable(ngx_stream_session_t *s,
406e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t *v, uintptr_t data)
407e18a033bSKonstantin Ananyev{
408e18a033bSKonstantin Ananyev    char         *val;
409e18a033bSKonstantin Ananyev    size_t        len;
410e18a033bSKonstantin Ananyev    GeoIPRecord  *gr;
411e18a033bSKonstantin Ananyev
412e18a033bSKonstantin Ananyev    gr = ngx_stream_geoip_get_city_record(s);
413e18a033bSKonstantin Ananyev    if (gr == NULL) {
414e18a033bSKonstantin Ananyev        goto not_found;
415e18a033bSKonstantin Ananyev    }
416e18a033bSKonstantin Ananyev
417