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_http.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    ngx_array_t  *proxies;    /* array of ngx_cidr_t */
26e18a033bSKonstantin Ananyev    ngx_flag_t    proxy_recursive;
27e18a033bSKonstantin Ananyev#if (NGX_HAVE_GEOIP_V6)
28e18a033bSKonstantin Ananyev    unsigned      country_v6:1;
29e18a033bSKonstantin Ananyev    unsigned      org_v6:1;
30e18a033bSKonstantin Ananyev    unsigned      city_v6:1;
31e18a033bSKonstantin Ananyev#endif
32e18a033bSKonstantin Ananyev} ngx_http_geoip_conf_t;
33e18a033bSKonstantin Ananyev
34e18a033bSKonstantin Ananyev
35e18a033bSKonstantin Ananyevtypedef struct {
36e18a033bSKonstantin Ananyev    ngx_str_t    *name;
37e18a033bSKonstantin Ananyev    uintptr_t     data;
38e18a033bSKonstantin Ananyev} ngx_http_geoip_var_t;
39e18a033bSKonstantin Ananyev
40e18a033bSKonstantin Ananyev
41e18a033bSKonstantin Ananyevtypedef const char *(*ngx_http_geoip_variable_handler_pt)(GeoIP *,
42e18a033bSKonstantin Ananyev    u_long addr);
43e18a033bSKonstantin Ananyev
44e18a033bSKonstantin Ananyev
45e18a033bSKonstantin Ananyevngx_http_geoip_variable_handler_pt ngx_http_geoip_country_functions[] = {
46e18a033bSKonstantin Ananyev    GeoIP_country_code_by_ipnum,
47e18a033bSKonstantin Ananyev    GeoIP_country_code3_by_ipnum,
48e18a033bSKonstantin Ananyev    GeoIP_country_name_by_ipnum,
49e18a033bSKonstantin Ananyev};
50e18a033bSKonstantin Ananyev
51e18a033bSKonstantin Ananyev
52e18a033bSKonstantin Ananyev#if (NGX_HAVE_GEOIP_V6)
53e18a033bSKonstantin Ananyev
54e18a033bSKonstantin Ananyevtypedef const char *(*ngx_http_geoip_variable_handler_v6_pt)(GeoIP *,
55e18a033bSKonstantin Ananyev    geoipv6_t addr);
56e18a033bSKonstantin Ananyev
57e18a033bSKonstantin Ananyev
58e18a033bSKonstantin Ananyevngx_http_geoip_variable_handler_v6_pt ngx_http_geoip_country_v6_functions[] = {
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_http_geoip_country_variable(ngx_http_request_t *r,
68e18a033bSKonstantin Ananyev    ngx_http_variable_value_t *v, uintptr_t data);
69e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_geoip_org_variable(ngx_http_request_t *r,
70e18a033bSKonstantin Ananyev    ngx_http_variable_value_t *v, uintptr_t data);
71e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_geoip_city_variable(ngx_http_request_t *r,
72e18a033bSKonstantin Ananyev    ngx_http_variable_value_t *v, uintptr_t data);
73e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_geoip_region_name_variable(ngx_http_request_t *r,
74e18a033bSKonstantin Ananyev    ngx_http_variable_value_t *v, uintptr_t data);
75e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_geoip_city_float_variable(ngx_http_request_t *r,
76e18a033bSKonstantin Ananyev    ngx_http_variable_value_t *v, uintptr_t data);
77e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_geoip_city_int_variable(ngx_http_request_t *r,
78e18a033bSKonstantin Ananyev    ngx_http_variable_value_t *v, uintptr_t data);
79e18a033bSKonstantin Ananyevstatic GeoIPRecord *ngx_http_geoip_get_city_record(ngx_http_request_t *r);
80e18a033bSKonstantin Ananyev
81e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_geoip_add_variables(ngx_conf_t *cf);
82e18a033bSKonstantin Ananyevstatic void *ngx_http_geoip_create_conf(ngx_conf_t *cf);
83e18a033bSKonstantin Ananyevstatic char *ngx_http_geoip_init_conf(ngx_conf_t *cf, void *conf);
84e18a033bSKonstantin Ananyevstatic char *ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd,
85e18a033bSKonstantin Ananyev    void *conf);
86e18a033bSKonstantin Ananyevstatic char *ngx_http_geoip_org(ngx_conf_t *cf, ngx_command_t *cmd,
87e18a033bSKonstantin Ananyev    void *conf);
88e18a033bSKonstantin Ananyevstatic char *ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd,
89e18a033bSKonstantin Ananyev    void *conf);
90e18a033bSKonstantin Ananyevstatic char *ngx_http_geoip_proxy(ngx_conf_t *cf, ngx_command_t *cmd,
91e18a033bSKonstantin Ananyev    void *conf);
92e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_geoip_cidr_value(ngx_conf_t *cf, ngx_str_t *net,
93e18a033bSKonstantin Ananyev    ngx_cidr_t *cidr);
94e18a033bSKonstantin Ananyevstatic void ngx_http_geoip_cleanup(void *data);
95e18a033bSKonstantin Ananyev
96e18a033bSKonstantin Ananyev
97e18a033bSKonstantin Ananyevstatic ngx_command_t  ngx_http_geoip_commands[] = {
98e18a033bSKonstantin Ananyev
99e18a033bSKonstantin Ananyev    { ngx_string("geoip_country"),
100e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE12,
101e18a033bSKonstantin Ananyev      ngx_http_geoip_country,
102e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF_OFFSET,
103e18a033bSKonstantin Ananyev      0,
104e18a033bSKonstantin Ananyev      NULL },
105e18a033bSKonstantin Ananyev
106e18a033bSKonstantin Ananyev    { ngx_string("geoip_org"),
107e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE12,
108e18a033bSKonstantin Ananyev      ngx_http_geoip_org,
109e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF_OFFSET,
110e18a033bSKonstantin Ananyev      0,
111e18a033bSKonstantin Ananyev      NULL },
112e18a033bSKonstantin Ananyev
113e18a033bSKonstantin Ananyev    { ngx_string("geoip_city"),
114e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE12,
115e18a033bSKonstantin Ananyev      ngx_http_geoip_city,
116e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF_OFFSET,
117e18a033bSKonstantin Ananyev      0,
118e18a033bSKonstantin Ananyev      NULL },
119e18a033bSKonstantin Ananyev
120e18a033bSKonstantin Ananyev    { ngx_string("geoip_proxy"),
121e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
122e18a033bSKonstantin Ananyev      ngx_http_geoip_proxy,
123e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF_OFFSET,
124e18a033bSKonstantin Ananyev      0,
125e18a033bSKonstantin Ananyev      NULL },
126e18a033bSKonstantin Ananyev
127e18a033bSKonstantin Ananyev    { ngx_string("geoip_proxy_recursive"),
128e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_CONF_FLAG,
129e18a033bSKonstantin Ananyev      ngx_conf_set_flag_slot,
130e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF_OFFSET,
131e18a033bSKonstantin Ananyev      offsetof(ngx_http_geoip_conf_t, proxy_recursive),
132e18a033bSKonstantin Ananyev      NULL },
133e18a033bSKonstantin Ananyev
134e18a033bSKonstantin Ananyev      ngx_null_command
135e18a033bSKonstantin Ananyev};
136e18a033bSKonstantin Ananyev
137e18a033bSKonstantin Ananyev
138e18a033bSKonstantin Ananyevstatic ngx_http_module_t  ngx_http_geoip_module_ctx = {
139e18a033bSKonstantin Ananyev    ngx_http_geoip_add_variables,          /* preconfiguration */
140e18a033bSKonstantin Ananyev    NULL,                                  /* postconfiguration */
141e18a033bSKonstantin Ananyev
142e18a033bSKonstantin Ananyev    ngx_http_geoip_create_conf,            /* create main configuration */
143e18a033bSKonstantin Ananyev    ngx_http_geoip_init_conf,              /* init main configuration */
144e18a033bSKonstantin Ananyev
145e18a033bSKonstantin Ananyev    NULL,                                  /* create server configuration */
146e18a033bSKonstantin Ananyev    NULL,                                  /* merge server configuration */
147e18a033bSKonstantin Ananyev
148e18a033bSKonstantin Ananyev    NULL,                                  /* create location configuration */
149e18a033bSKonstantin Ananyev    NULL                                   /* merge location configuration */
150e18a033bSKonstantin Ananyev};
151e18a033bSKonstantin Ananyev
152e18a033bSKonstantin Ananyev
153e18a033bSKonstantin Ananyevngx_module_t  ngx_http_geoip_module = {
154e18a033bSKonstantin Ananyev    NGX_MODULE_V1,
155e18a033bSKonstantin Ananyev    &ngx_http_geoip_module_ctx,            /* module context */
156e18a033bSKonstantin Ananyev    ngx_http_geoip_commands,               /* module directives */
157e18a033bSKonstantin Ananyev    NGX_HTTP_MODULE,                       /* module type */
158e18a033bSKonstantin Ananyev    NULL,                                  /* init master */
159e18a033bSKonstantin Ananyev    NULL,                                  /* init module */
160e18a033bSKonstantin Ananyev    NULL,                                  /* init process */
161e18a033bSKonstantin Ananyev    NULL,                                  /* init thread */
162e18a033bSKonstantin Ananyev    NULL,                                  /* exit thread */
163e18a033bSKonstantin Ananyev    NULL,                                  /* exit process */
164e18a033bSKonstantin Ananyev    NULL,                                  /* exit master */
165e18a033bSKonstantin Ananyev    NGX_MODULE_V1_PADDING
166e18a033bSKonstantin Ananyev};
167e18a033bSKonstantin Ananyev
168e18a033bSKonstantin Ananyev
169e18a033bSKonstantin Ananyevstatic ngx_http_variable_t  ngx_http_geoip_vars[] = {
170e18a033bSKonstantin Ananyev
171e18a033bSKonstantin Ananyev    { ngx_string("geoip_country_code"), NULL,
172e18a033bSKonstantin Ananyev      ngx_http_geoip_country_variable,
173e18a033bSKonstantin Ananyev      NGX_GEOIP_COUNTRY_CODE, 0, 0 },
174e18a033bSKonstantin Ananyev
175e18a033bSKonstantin Ananyev    { ngx_string("geoip_country_code3"), NULL,
176e18a033bSKonstantin Ananyev      ngx_http_geoip_country_variable,
177e18a033bSKonstantin Ananyev      NGX_GEOIP_COUNTRY_CODE3, 0, 0 },
178e18a033bSKonstantin Ananyev
179e18a033bSKonstantin Ananyev    { ngx_string("geoip_country_name"), NULL,
180e18a033bSKonstantin Ananyev      ngx_http_geoip_country_variable,
181e18a033bSKonstantin Ananyev      NGX_GEOIP_COUNTRY_NAME, 0, 0 },
182e18a033bSKonstantin Ananyev
183e18a033bSKonstantin Ananyev    { ngx_string("geoip_org"), NULL,
184e18a033bSKonstantin Ananyev      ngx_http_geoip_org_variable,
185e18a033bSKonstantin Ananyev      0, 0, 0 },
186e18a033bSKonstantin Ananyev
187e18a033bSKonstantin Ananyev    { ngx_string("geoip_city_continent_code"), NULL,
188e18a033bSKonstantin Ananyev      ngx_http_geoip_city_variable,
189e18a033bSKonstantin Ananyev      offsetof(GeoIPRecord, continent_code), 0, 0 },
190e18a033bSKonstantin Ananyev
191e18a033bSKonstantin Ananyev    { ngx_string("geoip_city_country_code"), NULL,
192e18a033bSKonstantin Ananyev      ngx_http_geoip_city_variable,
193e18a033bSKonstantin Ananyev      offsetof(GeoIPRecord, country_code), 0, 0 },
194e18a033bSKonstantin Ananyev
195e18a033bSKonstantin Ananyev    { ngx_string("geoip_city_country_code3"), NULL,
196e18a033bSKonstantin Ananyev      ngx_http_geoip_city_variable,
197e18a033bSKonstantin Ananyev      offsetof(GeoIPRecord, country_code3), 0, 0 },
198e18a033bSKonstantin Ananyev
199e18a033bSKonstantin Ananyev    { ngx_string("geoip_city_country_name"), NULL,
200e18a033bSKonstantin Ananyev      ngx_http_geoip_city_variable,
201e18a033bSKonstantin Ananyev      offsetof(GeoIPRecord, country_name), 0, 0 },
202e18a033bSKonstantin Ananyev
203e18a033bSKonstantin Ananyev    { ngx_string("geoip_region"), NULL,
204e18a033bSKonstantin Ananyev      ngx_http_geoip_city_variable,
205e18a033bSKonstantin Ananyev      offsetof(GeoIPRecord, region), 0, 0 },
206e18a033bSKonstantin Ananyev
207e18a033bSKonstantin Ananyev    { ngx_string("geoip_region_name"), NULL,
208e18a033bSKonstantin Ananyev      ngx_http_geoip_region_name_variable,
209e18a033bSKonstantin Ananyev      0, 0, 0 },
210e18a033bSKonstantin Ananyev
211e18a033bSKonstantin Ananyev    { ngx_string("geoip_city"), NULL,
212e18a033bSKonstantin Ananyev      ngx_http_geoip_city_variable,
213e18a033bSKonstantin Ananyev      offsetof(GeoIPRecord, city), 0, 0 },
214e18a033bSKonstantin Ananyev
215e18a033bSKonstantin Ananyev    { ngx_string("geoip_postal_code"), NULL,
216e18a033bSKonstantin Ananyev      ngx_http_geoip_city_variable,
217e18a033bSKonstantin Ananyev      offsetof(GeoIPRecord, postal_code), 0, 0 },
218e18a033bSKonstantin Ananyev
219e18a033bSKonstantin Ananyev    { ngx_string("geoip_latitude"), NULL,
220e18a033bSKonstantin Ananyev      ngx_http_geoip_city_float_variable,
221e18a033bSKonstantin Ananyev      offsetof(GeoIPRecord, latitude), 0, 0 },
222e18a033bSKonstantin Ananyev
223e18a033bSKonstantin Ananyev    { ngx_string("geoip_longitude"), NULL,
224e18a033bSKonstantin Ananyev      ngx_http_geoip_city_float_variable,
225e18a033bSKonstantin Ananyev      offsetof(GeoIPRecord, longitude), 0, 0 },
226e18a033bSKonstantin Ananyev
227e18a033bSKonstantin Ananyev    { ngx_string("geoip_dma_code"), NULL,
228e18a033bSKonstantin Ananyev      ngx_http_geoip_city_int_variable,
229e18a033bSKonstantin Ananyev      offsetof(GeoIPRecord, dma_code), 0, 0 },
230e18a033bSKonstantin Ananyev
231e18a033bSKonstantin Ananyev    { ngx_string("geoip_area_code"), NULL,
232e18a033bSKonstantin Ananyev      ngx_http_geoip_city_int_variable,
233e18a033bSKonstantin Ananyev      offsetof(GeoIPRecord, area_code), 0, 0 },
234e18a033bSKonstantin Ananyev
235e18a033bSKonstantin Ananyev    { ngx_null_string, NULL, NULL, 0, 0, 0 }
236e18a033bSKonstantin Ananyev};
237e18a033bSKonstantin Ananyev
238e18a033bSKonstantin Ananyev
239e18a033bSKonstantin Ananyevstatic u_long
240e18a033bSKonstantin Ananyevngx_http_geoip_addr(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf)
241e18a033bSKonstantin Ananyev{
242e18a033bSKonstantin Ananyev    ngx_addr_t           addr;
243e18a033bSKonstantin Ananyev    ngx_array_t         *xfwd;
244e18a033bSKonstantin Ananyev    struct sockaddr_in  *sin;
245e18a033bSKonstantin Ananyev
246e18a033bSKonstantin Ananyev    addr.sockaddr = r->connection->sockaddr;
247e18a033bSKonstantin Ananyev    addr.socklen = r->connection->socklen;
248e18a033bSKonstantin Ananyev    /* addr.name = r->connection->addr_text; */
249e18a033bSKonstantin Ananyev
250e18a033bSKonstantin Ananyev    xfwd = &r->headers_in.x_forwarded_for;
251e18a033bSKonstantin Ananyev
252e18a033bSKonstantin Ananyev    if (xfwd->nelts > 0 && gcf->proxies != NULL) {
253e18a033bSKonstantin Ananyev        (void) ngx_http_get_forwarded_addr(r, &addr, xfwd, NULL,
254e18a033bSKonstantin Ananyev                                           gcf->proxies, gcf->proxy_recursive);
255e18a033bSKonstantin Ananyev    }
256e18a033bSKonstantin Ananyev
257e18a033bSKonstantin Ananyev#if (NGX_HAVE_INET6)
258e18a033bSKonstantin Ananyev
259e18a033bSKonstantin Ananyev    if (addr.sockaddr->sa_family == AF_INET6) {
260e18a033bSKonstantin Ananyev        u_char           *p;
261e18a033bSKonstantin Ananyev        in_addr_t         inaddr;
262e18a033bSKonstantin Ananyev        struct in6_addr  *inaddr6;
263e18a033bSKonstantin Ananyev
264e18a033bSKonstantin Ananyev        inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr;
265e18a033bSKonstantin Ananyev
266e18a033bSKonstantin Ananyev        if (IN6_IS_ADDR_V4MAPPED(inaddr6)) {
267e18a033bSKonstantin Ananyev            p = inaddr6->s6_addr;
268e18a033bSKonstantin Ananyev
269e18a033bSKonstantin Ananyev            inaddr = p[12] << 24;
270e18a033bSKonstantin Ananyev            inaddr += p[13] << 16;
271e18a033bSKonstantin Ananyev            inaddr += p[14] << 8;
272e18a033bSKonstantin Ananyev            inaddr += p[15];
273e18a033bSKonstantin Ananyev
274e18a033bSKonstantin Ananyev            return inaddr;
275e18a033bSKonstantin Ananyev        }
276e18a033bSKonstantin Ananyev    }
277e18a033bSKonstantin Ananyev
278e18a033bSKonstantin Ananyev#endif
279e18a033bSKonstantin Ananyev
280e18a033bSKonstantin Ananyev    if (addr.sockaddr->sa_family != AF_INET) {
281e18a033bSKonstantin Ananyev        return INADDR_NONE;
282e18a033bSKonstantin Ananyev    }
283e18a033bSKonstantin Ananyev
284e18a033bSKonstantin Ananyev    sin = (struct sockaddr_in *) addr.sockaddr;
285e18a033bSKonstantin Ananyev    return ntohl(sin->sin_addr.s_addr);
286e18a033bSKonstantin Ananyev}
287e18a033bSKonstantin Ananyev
288e18a033bSKonstantin Ananyev
289e18a033bSKonstantin Ananyev#if (NGX_HAVE_GEOIP_V6)
290e18a033bSKonstantin Ananyev
291e18a033bSKonstantin Ananyevstatic geoipv6_t
292e18a033bSKonstantin Ananyevngx_http_geoip_addr_v6(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf)
293e18a033bSKonstantin Ananyev{
294e18a033bSKonstantin Ananyev    ngx_addr_t            addr;
295e18a033bSKonstantin Ananyev    ngx_array_t          *xfwd;
296e18a033bSKonstantin Ananyev    in_addr_t             addr4;
297e18a033bSKonstantin Ananyev    struct in6_addr       addr6;
298e18a033bSKonstantin Ananyev    struct sockaddr_in   *sin;
299e18a033bSKonstantin Ananyev    struct sockaddr_in6  *sin6;
300e18a033bSKonstantin Ananyev
301e18a033bSKonstantin Ananyev    addr.sockaddr = r->connection->sockaddr;
302e18a033bSKonstantin Ananyev    addr.socklen = r->connection->socklen;
303e18a033bSKonstantin Ananyev    /* addr.name = r->connection->addr_text; */
304e18a033bSKonstantin Ananyev
305e18a033bSKonstantin Ananyev    xfwd = &r->headers_in.x_forwarded_for;
306e18a033bSKonstantin Ananyev
307e18a033bSKonstantin Ananyev    if (xfwd->nelts > 0 && gcf->proxies != NULL) {
308e18a033bSKonstantin Ananyev        (void) ngx_http_get_forwarded_addr(r, &addr, xfwd, NULL,
309e18a033bSKonstantin Ananyev                                           gcf->proxies, gcf->proxy_recursive);
310e18a033bSKonstantin Ananyev    }
311e18a033bSKonstantin Ananyev
312e18a033bSKonstantin Ananyev    switch (addr.sockaddr->sa_family) {
313e18a033bSKonstantin Ananyev
314e18a033bSKonstantin Ananyev    case AF_INET:
315e18a033bSKonstantin Ananyev        /* Produce IPv4-mapped IPv6 address. */
316e18a033bSKonstantin Ananyev        sin = (struct sockaddr_in *) addr.sockaddr;
317e18a033bSKonstantin Ananyev        addr4 = ntohl(sin->sin_addr.s_addr);
318e18a033bSKonstantin Ananyev
319e18a033bSKonstantin Ananyev        ngx_memzero(&addr6, sizeof(struct in6_addr));
320e18a033bSKonstantin Ananyev        addr6.s6_addr[10] = 0xff;
321e18a033bSKonstantin Ananyev        addr6.s6_addr[11] = 0xff;
322e18a033bSKonstantin Ananyev        addr6.s6_addr[12] = addr4 >> 24;
323e18a033bSKonstantin Ananyev        addr6.s6_addr[13] = addr4 >> 16;
324e18a033bSKonstantin Ananyev        addr6.s6_addr[14] = addr4 >> 8;
325e18a033bSKonstantin Ananyev        addr6.s6_addr[15] = addr4;
326e18a033bSKonstantin Ananyev        return addr6;
327e18a033bSKonstantin Ananyev
328e18a033bSKonstantin Ananyev    case AF_INET6:
329e18a033bSKonstantin Ananyev        sin6 = (struct sockaddr_in6 *) addr.sockaddr;
330e18a033bSKonstantin Ananyev        return sin6->sin6_addr;
331e18a033bSKonstantin Ananyev
332e18a033bSKonstantin Ananyev    default:
333e18a033bSKonstantin Ananyev        return in6addr_any;
334e18a033bSKonstantin Ananyev    }
335e18a033bSKonstantin Ananyev}
336e18a033bSKonstantin Ananyev
337e18a033bSKonstantin Ananyev#endif
338e18a033bSKonstantin Ananyev
339e18a033bSKonstantin Ananyev
340e18a033bSKonstantin Ananyevstatic ngx_int_t
341e18a033bSKonstantin Ananyevngx_http_geoip_country_variable(ngx_http_request_t *r,
342e18a033bSKonstantin Ananyev    ngx_http_variable_value_t *v, uintptr_t data)
343e18a033bSKonstantin Ananyev{
344e18a033bSKonstantin Ananyev    ngx_http_geoip_variable_handler_pt     handler =
345e18a033bSKonstantin Ananyev        ngx_http_geoip_country_functions[data];
346e18a033bSKonstantin Ananyev#if (NGX_HAVE_GEOIP_V6)
347e18a033bSKonstantin Ananyev    ngx_http_geoip_variable_handler_v6_pt  handler_v6 =
348e18a033bSKonstantin Ananyev        ngx_http_geoip_country_v6_functions[data];
349e18a033bSKonstantin Ananyev#endif
350e18a033bSKonstantin Ananyev
351e18a033bSKonstantin Ananyev    const char             *val;
352e18a033bSKonstantin Ananyev    ngx_http_geoip_conf_t  *gcf;
353e18a033bSKonstantin Ananyev
354e18a033bSKonstantin Ananyev    gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);
355e18a033bSKonstantin Ananyev
356e18a033bSKonstantin Ananyev    if (gcf->country == NULL) {
357e18a033bSKonstantin Ananyev        goto not_found;
358e18a033bSKonstantin Ananyev    }
359e18a033bSKonstantin Ananyev
360e18a033bSKonstantin Ananyev#if (NGX_HAVE_GEOIP_V6)
361e18a033bSKonstantin Ananyev    val = gcf->country_v6
362e18a033bSKonstantin Ananyev              ? handler_v6(gcf->country, ngx_http_geoip_addr_v6(r, gcf))
363e18a033bSKonstantin Ananyev              : handler(gcf->country, ngx_http_geoip_addr(r, gcf));
364e18a033bSKonstantin Ananyev#else
365e18a033bSKonstantin Ananyev    val = handler(gcf->country, ngx_http_geoip_addr(r, gcf));
366e18a033bSKonstantin Ananyev#endif
367e18a033bSKonstantin Ananyev
368e18a033bSKonstantin Ananyev    if (val == NULL) {
369e18a033bSKonstantin Ananyev        goto not_found;
370e18a033bSKonstantin Ananyev    }
371e18a033bSKonstantin Ananyev
372e18a033bSKonstantin Ananyev    v->len = ngx_strlen(val);
373e18a033bSKonstantin Ananyev    v->valid = 1;
374e18a033bSKonstantin Ananyev    v->no_cacheable = 0;
375e18a033bSKonstantin Ananyev    v->not_found = 0;
376e18a033bSKonstantin Ananyev    v->data = (u_char *) val;
377e18a033bSKonstantin Ananyev
378e18a033bSKonstantin Ananyev    return NGX_OK;
379e18a033bSKonstantin Ananyev
380e18a033bSKonstantin Ananyevnot_found:
381e18a033bSKonstantin Ananyev
382e18a033bSKonstantin Ananyev    v->not_found = 1;
383e18a033bSKonstantin Ananyev
384e18a033bSKonstantin Ananyev    return NGX_OK;
385e18a033bSKonstantin Ananyev}
386e18a033bSKonstantin Ananyev
387e18a033bSKonstantin Ananyev
388e18a033bSKonstantin Ananyevstatic ngx_int_t
389e18a033bSKonstantin Ananyevngx_http_geoip_org_variable(ngx_http_request_t *r,
390e18a033bSKonstantin Ananyev    ngx_http_variable_value_t *v, uintptr_t data)
391e18a033bSKonstantin Ananyev{
392e18a033bSKonstantin Ananyev    size_t                  len;
393e18a033bSKonstantin Ananyev    char                   *val;
394e18a033bSKonstantin Ananyev    ngx_http_geoip_conf_t  *gcf;
395e18a033bSKonstantin Ananyev
396e18a033bSKonstantin Ananyev    gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);
397e18a033bSKonstantin Ananyev
398e18a033bSKonstantin Ananyev    if (gcf->org == NULL) {
399e18a033bSKonstantin Ananyev        goto not_found;
400e18a033bSKonstantin Ananyev    }
401e18a033bSKonstantin Ananyev
402e18a033bSKonstantin Ananyev#if (NGX_HAVE_GEOIP_V6)
403e18a033bSKonstantin Ananyev    val = gcf->org_v6
404e18a033bSKonstantin Ananyev              ? GeoIP_name_by_ipnum_v6(gcf->org,
405e18a033bSKonstantin Ananyev                                       ngx_http_geoip_addr_v6(r, gcf))
406e18a033bSKonstantin Ananyev              : GeoIP_name_by_ipnum(gcf->org,
407e18a033bSKonstantin Ananyev                                    ngx_http_geoip_addr(r, gcf));
408e18a033bSKonstantin Ananyev#else
409e18a033bSKonstantin Ananyev    val = GeoIP_name_by_ipnum(gcf->org, ngx_http_geoip_addr(r, gcf));
410e18a033bSKonstantin Ananyev#endif
411e18a033bSKonstantin Ananyev
412e18a033bSKonstantin Ananyev    if (val == NULL) {
413e18a033bSKonstantin Ananyev        goto not_found;
414e18a033bSKonstantin Ananyev    }
415e18a033bSKonstantin Ananyev
416e18a033bSKonstantin Ananyev    len = ngx_strlen(val);
417