src/http/modules/ngx_http_geoip_module.c - nginx-1.7.10

Global variables defined

Data types defined

Functions defined

Macros defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_http.h>

  8. #include <GeoIP.h>
  9. #include <GeoIPCity.h>


  10. #define NGX_GEOIP_COUNTRY_CODE   0
  11. #define NGX_GEOIP_COUNTRY_CODE3  1
  12. #define NGX_GEOIP_COUNTRY_NAME   2


  13. typedef struct {
  14.     GeoIP        *country;
  15.     GeoIP        *org;
  16.     GeoIP        *city;
  17.     ngx_array_t  *proxies;    /* array of ngx_cidr_t */
  18.     ngx_flag_t    proxy_recursive;
  19. #if (NGX_HAVE_GEOIP_V6)
  20.     unsigned      country_v6:1;
  21.     unsigned      org_v6:1;
  22.     unsigned      city_v6:1;
  23. #endif
  24. } ngx_http_geoip_conf_t;


  25. typedef struct {
  26.     ngx_str_t    *name;
  27.     uintptr_t     data;
  28. } ngx_http_geoip_var_t;


  29. typedef const char *(*ngx_http_geoip_variable_handler_pt)(GeoIP *,
  30.     u_long addr);


  31. ngx_http_geoip_variable_handler_pt ngx_http_geoip_country_functions[] = {
  32.     GeoIP_country_code_by_ipnum,
  33.     GeoIP_country_code3_by_ipnum,
  34.     GeoIP_country_name_by_ipnum,
  35. };


  36. #if (NGX_HAVE_GEOIP_V6)

  37. typedef const char *(*ngx_http_geoip_variable_handler_v6_pt)(GeoIP *,
  38.     geoipv6_t addr);


  39. ngx_http_geoip_variable_handler_v6_pt ngx_http_geoip_country_v6_functions[] = {
  40.     GeoIP_country_code_by_ipnum_v6,
  41.     GeoIP_country_code3_by_ipnum_v6,
  42.     GeoIP_country_name_by_ipnum_v6,
  43. };

  44. #endif


  45. static ngx_int_t ngx_http_geoip_country_variable(ngx_http_request_t *r,
  46.     ngx_http_variable_value_t *v, uintptr_t data);
  47. static ngx_int_t ngx_http_geoip_org_variable(ngx_http_request_t *r,
  48.     ngx_http_variable_value_t *v, uintptr_t data);
  49. static ngx_int_t ngx_http_geoip_city_variable(ngx_http_request_t *r,
  50.     ngx_http_variable_value_t *v, uintptr_t data);
  51. static ngx_int_t ngx_http_geoip_region_name_variable(ngx_http_request_t *r,
  52.     ngx_http_variable_value_t *v, uintptr_t data);
  53. static ngx_int_t ngx_http_geoip_city_float_variable(ngx_http_request_t *r,
  54.     ngx_http_variable_value_t *v, uintptr_t data);
  55. static ngx_int_t ngx_http_geoip_city_int_variable(ngx_http_request_t *r,
  56.     ngx_http_variable_value_t *v, uintptr_t data);
  57. static GeoIPRecord *ngx_http_geoip_get_city_record(ngx_http_request_t *r);

  58. static ngx_int_t ngx_http_geoip_add_variables(ngx_conf_t *cf);
  59. static void *ngx_http_geoip_create_conf(ngx_conf_t *cf);
  60. static char *ngx_http_geoip_init_conf(ngx_conf_t *cf, void *conf);
  61. static char *ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd,
  62.     void *conf);
  63. static char *ngx_http_geoip_org(ngx_conf_t *cf, ngx_command_t *cmd,
  64.     void *conf);
  65. static char *ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd,
  66.     void *conf);
  67. static char *ngx_http_geoip_proxy(ngx_conf_t *cf, ngx_command_t *cmd,
  68.     void *conf);
  69. static ngx_int_t ngx_http_geoip_cidr_value(ngx_conf_t *cf, ngx_str_t *net,
  70.     ngx_cidr_t *cidr);
  71. static void ngx_http_geoip_cleanup(void *data);


  72. static ngx_command_t  ngx_http_geoip_commands[] = {

  73.     { ngx_string("geoip_country"),
  74.       NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE12,
  75.       ngx_http_geoip_country,
  76.       NGX_HTTP_MAIN_CONF_OFFSET,
  77.       0,
  78.       NULL },

  79.     { ngx_string("geoip_org"),
  80.       NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE12,
  81.       ngx_http_geoip_org,
  82.       NGX_HTTP_MAIN_CONF_OFFSET,
  83.       0,
  84.       NULL },

  85.     { ngx_string("geoip_city"),
  86.       NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE12,
  87.       ngx_http_geoip_city,
  88.       NGX_HTTP_MAIN_CONF_OFFSET,
  89.       0,
  90.       NULL },

  91.     { ngx_string("geoip_proxy"),
  92.       NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
  93.       ngx_http_geoip_proxy,
  94.       NGX_HTTP_MAIN_CONF_OFFSET,
  95.       0,
  96.       NULL },

  97.     { ngx_string("geoip_proxy_recursive"),
  98.       NGX_HTTP_MAIN_CONF|NGX_CONF_FLAG,
  99.       ngx_conf_set_flag_slot,
  100.       NGX_HTTP_MAIN_CONF_OFFSET,
  101.       offsetof(ngx_http_geoip_conf_t, proxy_recursive),
  102.       NULL },

  103.       ngx_null_command
  104. };


  105. static ngx_http_module_t  ngx_http_geoip_module_ctx = {
  106.     ngx_http_geoip_add_variables,          /* preconfiguration */
  107.     NULL,                                  /* postconfiguration */

  108.     ngx_http_geoip_create_conf,            /* create main configuration */
  109.     ngx_http_geoip_init_conf,              /* init main configuration */

  110.     NULL,                                  /* create server configuration */
  111.     NULL,                                  /* merge server configuration */

  112.     NULL,                                  /* create location configuration */
  113.     NULL                                   /* merge location configuration */
  114. };


  115. ngx_module_t  ngx_http_geoip_module = {
  116.     NGX_MODULE_V1,
  117.     &ngx_http_geoip_module_ctx,            /* module context */
  118.     ngx_http_geoip_commands,               /* module directives */
  119.     NGX_HTTP_MODULE,                       /* module type */
  120.     NULL,                                  /* init master */
  121.     NULL,                                  /* init module */
  122.     NULL,                                  /* init process */
  123.     NULL,                                  /* init thread */
  124.     NULL,                                  /* exit thread */
  125.     NULL,                                  /* exit process */
  126.     NULL,                                  /* exit master */
  127.     NGX_MODULE_V1_PADDING
  128. };


  129. static ngx_http_variable_t  ngx_http_geoip_vars[] = {

  130.     { ngx_string("geoip_country_code"), NULL,
  131.       ngx_http_geoip_country_variable,
  132.       NGX_GEOIP_COUNTRY_CODE, 0, 0 },

  133.     { ngx_string("geoip_country_code3"), NULL,
  134.       ngx_http_geoip_country_variable,
  135.       NGX_GEOIP_COUNTRY_CODE3, 0, 0 },

  136.     { ngx_string("geoip_country_name"), NULL,
  137.       ngx_http_geoip_country_variable,
  138.       NGX_GEOIP_COUNTRY_NAME, 0, 0 },

  139.     { ngx_string("geoip_org"), NULL,
  140.       ngx_http_geoip_org_variable,
  141.       0, 0, 0 },

  142.     { ngx_string("geoip_city_continent_code"), NULL,
  143.       ngx_http_geoip_city_variable,
  144.       offsetof(GeoIPRecord, continent_code), 0, 0 },

  145.     { ngx_string("geoip_city_country_code"), NULL,
  146.       ngx_http_geoip_city_variable,
  147.       offsetof(GeoIPRecord, country_code), 0, 0 },

  148.     { ngx_string("geoip_city_country_code3"), NULL,
  149.       ngx_http_geoip_city_variable,
  150.       offsetof(GeoIPRecord, country_code3), 0, 0 },

  151.     { ngx_string("geoip_city_country_name"), NULL,
  152.       ngx_http_geoip_city_variable,
  153.       offsetof(GeoIPRecord, country_name), 0, 0 },

  154.     { ngx_string("geoip_region"), NULL,
  155.       ngx_http_geoip_city_variable,
  156.       offsetof(GeoIPRecord, region), 0, 0 },

  157.     { ngx_string("geoip_region_name"), NULL,
  158.       ngx_http_geoip_region_name_variable,
  159.       0, 0, 0 },

  160.     { ngx_string("geoip_city"), NULL,
  161.       ngx_http_geoip_city_variable,
  162.       offsetof(GeoIPRecord, city), 0, 0 },

  163.     { ngx_string("geoip_postal_code"), NULL,
  164.       ngx_http_geoip_city_variable,
  165.       offsetof(GeoIPRecord, postal_code), 0, 0 },

  166.     { ngx_string("geoip_latitude"), NULL,
  167.       ngx_http_geoip_city_float_variable,
  168.       offsetof(GeoIPRecord, latitude), 0, 0 },

  169.     { ngx_string("geoip_longitude"), NULL,
  170.       ngx_http_geoip_city_float_variable,
  171.       offsetof(GeoIPRecord, longitude), 0, 0 },

  172.     { ngx_string("geoip_dma_code"), NULL,
  173.       ngx_http_geoip_city_int_variable,
  174.       offsetof(GeoIPRecord, dma_code), 0, 0 },

  175.     { ngx_string("geoip_area_code"), NULL,
  176.       ngx_http_geoip_city_int_variable,
  177.       offsetof(GeoIPRecord, area_code), 0, 0 },

  178.     { ngx_null_string, NULL, NULL, 0, 0, 0 }
  179. };


  180. static u_long
  181. ngx_http_geoip_addr(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf)
  182. {
  183.     ngx_addr_t           addr;
  184.     ngx_array_t         *xfwd;
  185.     struct sockaddr_in  *sin;

  186.     addr.sockaddr = r->connection->sockaddr;
  187.     addr.socklen = r->connection->socklen;
  188.     /* addr.name = r->connection->addr_text; */

  189.     xfwd = &r->headers_in.x_forwarded_for;

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

  194. #if (NGX_HAVE_INET6)

  195.     if (addr.sockaddr->sa_family == AF_INET6) {
  196.         u_char           *p;
  197.         in_addr_t         inaddr;
  198.         struct in6_addr  *inaddr6;

  199.         inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr;

  200.         if (IN6_IS_ADDR_V4MAPPED(inaddr6)) {
  201.             p = inaddr6->s6_addr;

  202.             inaddr = p[12] << 24;
  203.             inaddr += p[13] << 16;
  204.             inaddr += p[14] << 8;
  205.             inaddr += p[15];

  206.             return inaddr;
  207.         }
  208.     }

  209. #endif

  210.     if (addr.sockaddr->sa_family != AF_INET) {
  211.         return INADDR_NONE;
  212.     }

  213.     sin = (struct sockaddr_in *) addr.sockaddr;
  214.     return ntohl(sin->sin_addr.s_addr);
  215. }


  216. #if (NGX_HAVE_GEOIP_V6)

  217. static geoipv6_t
  218. ngx_http_geoip_addr_v6(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf)
  219. {
  220.     ngx_addr_t            addr;
  221.     ngx_array_t          *xfwd;
  222.     in_addr_t             addr4;
  223.     struct in6_addr       addr6;
  224.     struct sockaddr_in   *sin;
  225.     struct sockaddr_in6  *sin6;

  226.     addr.sockaddr = r->connection->sockaddr;
  227.     addr.socklen = r->connection->socklen;
  228.     /* addr.name = r->connection->addr_text; */

  229.     xfwd = &r->headers_in.x_forwarded_for;

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

  234.     switch (addr.sockaddr->sa_family) {

  235.     case AF_INET:
  236.         /* Produce IPv4-mapped IPv6 address. */
  237.         sin = (struct sockaddr_in *) addr.sockaddr;
  238.         addr4 = ntohl(sin->sin_addr.s_addr);

  239.         ngx_memzero(&addr6, sizeof(struct in6_addr));
  240.         addr6.s6_addr[10] = 0xff;
  241.         addr6.s6_addr[11] = 0xff;
  242.         addr6.s6_addr[12] = addr4 >> 24;
  243.         addr6.s6_addr[13] = addr4 >> 16;
  244.         addr6.s6_addr[14] = addr4 >> 8;
  245.         addr6.s6_addr[15] = addr4;
  246.         return addr6;

  247.     case AF_INET6:
  248.         sin6 = (struct sockaddr_in6 *) addr.sockaddr;
  249.         return sin6->sin6_addr;

  250.     default:
  251.         return in6addr_any;
  252.     }
  253. }

  254. #endif


  255. static ngx_int_t
  256. ngx_http_geoip_country_variable(ngx_http_request_t *r,
  257.     ngx_http_variable_value_t *v, uintptr_t data)
  258. {
  259.     ngx_http_geoip_variable_handler_pt     handler =
  260.         ngx_http_geoip_country_functions[data];
  261. #if (NGX_HAVE_GEOIP_V6)
  262.     ngx_http_geoip_variable_handler_v6_pt  handler_v6 =
  263.         ngx_http_geoip_country_v6_functions[data];
  264. #endif

  265.     const char             *val;
  266.     ngx_http_geoip_conf_t  *gcf;

  267.     gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);

  268.     if (gcf->country == NULL) {
  269.         goto not_found;
  270.     }

  271. #if (NGX_HAVE_GEOIP_V6)
  272.     val = gcf->country_v6
  273.               ? handler_v6(gcf->country, ngx_http_geoip_addr_v6(r, gcf))
  274.               : handler(gcf->country, ngx_http_geoip_addr(r, gcf));
  275. #else
  276.     val = handler(gcf->country, ngx_http_geoip_addr(r, gcf));
  277. #endif

  278.     if (val == NULL) {
  279.         goto not_found;
  280.     }

  281.     v->len = ngx_strlen(val);
  282.     v->valid = 1;
  283.     v->no_cacheable = 0;
  284.     v->not_found = 0;
  285.     v->data = (u_char *) val;

  286.     return NGX_OK;

  287. not_found:

  288.     v->not_found = 1;

  289.     return NGX_OK;
  290. }


  291. static ngx_int_t
  292. ngx_http_geoip_org_variable(ngx_http_request_t *r,
  293.     ngx_http_variable_value_t *v, uintptr_t data)
  294. {
  295.     size_t                  len;
  296.     char                   *val;
  297.     ngx_http_geoip_conf_t  *gcf;

  298.     gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);

  299.     if (gcf->org == NULL) {
  300.         goto not_found;
  301.     }

  302. #if (NGX_HAVE_GEOIP_V6)
  303.     val = gcf->org_v6
  304.               ? GeoIP_name_by_ipnum_v6(gcf->org,
  305.                                        ngx_http_geoip_addr_v6(r, gcf))
  306.               : GeoIP_name_by_ipnum(gcf->org,
  307.                                     ngx_http_geoip_addr(r, gcf));
  308. #else
  309.     val = GeoIP_name_by_ipnum(gcf->org, ngx_http_geoip_addr(r, gcf));
  310. #endif

  311.     if (val == NULL) {
  312.         goto not_found;
  313.     }

  314.     len = ngx_strlen(val);
  315.     v->data = ngx_pnalloc(r->pool, len);
  316.     if (v->data == NULL) {
  317.         ngx_free(val);
  318.         return NGX_ERROR;
  319.     }

  320.     ngx_memcpy(v->data, val, len);

  321.     v->len = len;
  322.     v->valid = 1;
  323.     v->no_cacheable = 0;
  324.     v->not_found = 0;

  325.     ngx_free(val);

  326.     return NGX_OK;

  327. not_found:

  328.     v->not_found = 1;

  329.     return NGX_OK;
  330. }


  331. static ngx_int_t
  332. ngx_http_geoip_city_variable(ngx_http_request_t *r,
  333.     ngx_http_variable_value_t *v, uintptr_t data)
  334. {
  335.     char         *val;
  336.     size_t        len;
  337.     GeoIPRecord  *gr;

  338.     gr = ngx_http_geoip_get_city_record(r);
  339.     if (gr == NULL) {
  340.         goto not_found;
  341.     }

  342.     val = *(char **) ((char *) gr + data);
  343.     if (val == NULL) {
  344.         goto no_value;
  345.     }

  346.     len = ngx_strlen(val);
  347.     v->data = ngx_pnalloc(r->pool, len);
  348.     if (v->data == NULL) {
  349.         GeoIPRecord_delete(gr);
  350.         return NGX_ERROR;
  351.     }

  352.     ngx_memcpy(v->data, val, len);

  353.     v->len = len;
  354.     v->valid = 1;
  355.     v->no_cacheable = 0;
  356.     v->not_found = 0;

  357.     GeoIPRecord_delete(gr);

  358.     return NGX_OK;

  359. no_value:

  360.     GeoIPRecord_delete(gr);

  361. not_found:

  362.     v->not_found = 1;

  363.     return NGX_OK;
  364. }


  365. static ngx_int_t
  366. ngx_http_geoip_region_name_variable(ngx_http_request_t *r,
  367.     ngx_http_variable_value_t *v, uintptr_t data)
  368. {
  369.     size_t        len;
  370.     const char   *val;
  371.     GeoIPRecord  *gr;

  372.     gr = ngx_http_geoip_get_city_record(r);
  373.     if (gr == NULL) {
  374.         goto not_found;
  375.     }

  376.     val = GeoIP_region_name_by_code(gr->country_code, gr->region);

  377.     GeoIPRecord_delete(gr);

  378.     if (val == NULL) {
  379.         goto not_found;
  380.     }

  381.     len = ngx_strlen(val);
  382.     v->data = ngx_pnalloc(r->pool, len);
  383.     if (v->data == NULL) {
  384.         return NGX_ERROR;
  385.     }

  386.     ngx_memcpy(v->data, val, len);

  387.     v->len = len;
  388.     v->valid = 1;
  389.     v->no_cacheable = 0;
  390.     v->not_found = 0;

  391.     return NGX_OK;

  392. not_found:

  393.     v->not_found = 1;

  394.     return NGX_OK;
  395. }


  396. static ngx_int_t
  397. ngx_http_geoip_city_float_variable(ngx_http_request_t *r,
  398.     ngx_http_variable_value_t *v, uintptr_t data)
  399. {
  400.     float         val;
  401.     GeoIPRecord  *gr;

  402.     gr = ngx_http_geoip_get_city_record(r);
  403.     if (gr == NULL) {
  404.         v->not_found = 1;
  405.         return NGX_OK;
  406.     }

  407.     v->data = ngx_pnalloc(r->pool, NGX_INT64_LEN + 5);
  408.     if (v->data == NULL) {
  409.         GeoIPRecord_delete(gr);
  410.         return NGX_ERROR;
  411.     }

  412.     val = *(float *) ((char *) gr + data);

  413.     v->len = ngx_sprintf(v->data, "%.4f", val) - v->data;
  414.     v->valid = 1;
  415.     v->no_cacheable = 0;
  416.     v->not_found = 0;

  417.     GeoIPRecord_delete(gr);

  418.     return NGX_OK;
  419. }


  420. static ngx_int_t
  421. ngx_http_geoip_city_int_variable(ngx_http_request_t *r,
  422.     ngx_http_variable_value_t *v, uintptr_t data)
  423. {
  424.     int           val;
  425.     GeoIPRecord  *gr;

  426.     gr = ngx_http_geoip_get_city_record(r);
  427.     if (gr == NULL) {
  428.         v->not_found = 1;
  429.         return NGX_OK;
  430.     }

  431.     v->data = ngx_pnalloc(r->pool, NGX_INT64_LEN);
  432.     if (v->data == NULL) {
  433.         GeoIPRecord_delete(gr);
  434.         return NGX_ERROR;
  435.     }

  436.     val = *(int *) ((char *) gr + data);

  437.     v->len = ngx_sprintf(v->data, "%d", val) - v->data;
  438.     v->valid = 1;
  439.     v->no_cacheable = 0;
  440.     v->not_found = 0;

  441.     GeoIPRecord_delete(gr);

  442.     return NGX_OK;
  443. }


  444. static GeoIPRecord *
  445. ngx_http_geoip_get_city_record(ngx_http_request_t *r)
  446. {
  447.     ngx_http_geoip_conf_t  *gcf;

  448.     gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);

  449.     if (gcf->city) {
  450. #if (NGX_HAVE_GEOIP_V6)
  451.         return gcf->city_v6
  452.                    ? GeoIP_record_by_ipnum_v6(gcf->city,
  453.                                               ngx_http_geoip_addr_v6(r, gcf))
  454.                    : GeoIP_record_by_ipnum(gcf->city,
  455.                                            ngx_http_geoip_addr(r, gcf));
  456. #else
  457.         return GeoIP_record_by_ipnum(gcf->city, ngx_http_geoip_addr(r, gcf));
  458. #endif
  459.     }

  460.     return NULL;
  461. }


  462. static ngx_int_t
  463. ngx_http_geoip_add_variables(ngx_conf_t *cf)
  464. {
  465.     ngx_http_variable_t  *var, *v;

  466.     for (v = ngx_http_geoip_vars; v->name.len; v++) {
  467.         var = ngx_http_add_variable(cf, &v->name, v->flags);
  468.         if (var == NULL) {
  469.             return NGX_ERROR;
  470.         }

  471.         var->get_handler = v->get_handler;
  472.         var->data = v->data;
  473.     }

  474.     return NGX_OK;
  475. }


  476. static void *
  477. ngx_http_geoip_create_conf(ngx_conf_t *cf)
  478. {
  479.     ngx_pool_cleanup_t     *cln;
  480.     ngx_http_geoip_conf_t  *conf;

  481.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip_conf_t));
  482.     if (conf == NULL) {
  483.         return NULL;
  484.     }

  485.     conf->proxy_recursive = NGX_CONF_UNSET;

  486.     cln = ngx_pool_cleanup_add(cf->pool, 0);
  487.     if (cln == NULL) {
  488.         return NULL;
  489.     }

  490.     cln->handler = ngx_http_geoip_cleanup;
  491.     cln->data = conf;

  492.     return conf;
  493. }


  494. static char *
  495. ngx_http_geoip_init_conf(ngx_conf_t *cf, void *conf)
  496. {
  497.     ngx_http_geoip_conf_t  *gcf = conf;

  498.     ngx_conf_init_value(gcf->proxy_recursive, 0);

  499.     return NGX_CONF_OK;
  500. }


  501. static char *
  502. ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  503. {
  504.     ngx_http_geoip_conf_t  *gcf = conf;

  505.     ngx_str_t  *value;

  506.     if (gcf->country) {
  507.         return "is duplicate";
  508.     }

  509.     value = cf->args->elts;

  510.     gcf->country = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);

  511.     if (gcf->country == NULL) {
  512.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  513.                            "GeoIP_open(\"%V\") failed", &value[1]);

  514.         return NGX_CONF_ERROR;
  515.     }

  516.     if (cf->args->nelts == 3) {
  517.         if (ngx_strcmp(value[2].data, "utf8") == 0) {
  518.             GeoIP_set_charset(gcf->country, GEOIP_CHARSET_UTF8);

  519.         } else {
  520.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  521.                                "invalid parameter \"%V\"", &value[2]);
  522.             return NGX_CONF_ERROR;
  523.         }
  524.     }

  525.     switch (gcf->country->databaseType) {

  526.     case GEOIP_COUNTRY_EDITION:

  527.         return NGX_CONF_OK;

  528. #if (NGX_HAVE_GEOIP_V6)
  529.     case GEOIP_COUNTRY_EDITION_V6:

  530.         gcf->country_v6 = 1;
  531.         return NGX_CONF_OK;
  532. #endif

  533.     default:
  534.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  535.                            "invalid GeoIP database \"%V\" type:%d",
  536.                            &value[1], gcf->country->databaseType);
  537.         return NGX_CONF_ERROR;
  538.     }
  539. }


  540. static char *
  541. ngx_http_geoip_org(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  542. {
  543.     ngx_http_geoip_conf_t  *gcf = conf;

  544.     ngx_str_t  *value;

  545.     if (gcf->org) {
  546.         return "is duplicate";
  547.     }

  548.     value = cf->args->elts;

  549.     gcf->org = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);

  550.     if (gcf->org == NULL) {
  551.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  552.                            "GeoIP_open(\"%V\") failed", &value[1]);

  553.         return NGX_CONF_ERROR;
  554.     }

  555.     if (cf->args->nelts == 3) {
  556.         if (ngx_strcmp(value[2].data, "utf8") == 0) {
  557.             GeoIP_set_charset(gcf->org, GEOIP_CHARSET_UTF8);

  558.         } else {
  559.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  560.                                "invalid parameter \"%V\"", &value[2]);
  561.             return NGX_CONF_ERROR;
  562.         }
  563.     }

  564.     switch (gcf->org->databaseType) {

  565.     case GEOIP_ISP_EDITION:
  566.     case GEOIP_ORG_EDITION:
  567.     case GEOIP_DOMAIN_EDITION:
  568.     case GEOIP_ASNUM_EDITION:

  569.         return NGX_CONF_OK;

  570. #if (NGX_HAVE_GEOIP_V6)
  571.     case GEOIP_ISP_EDITION_V6:
  572.     case GEOIP_ORG_EDITION_V6:
  573.     case GEOIP_DOMAIN_EDITION_V6:
  574.     case GEOIP_ASNUM_EDITION_V6:

  575.         gcf->org_v6 = 1;
  576.         return NGX_CONF_OK;
  577. #endif

  578.     default:
  579.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  580.                            "invalid GeoIP database \"%V\" type:%d",
  581.                            &value[1], gcf->org->databaseType);
  582.         return NGX_CONF_ERROR;
  583.     }
  584. }


  585. static char *
  586. ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  587. {
  588.     ngx_http_geoip_conf_t  *gcf = conf;

  589.     ngx_str_t  *value;

  590.     if (gcf->city) {
  591.         return "is duplicate";
  592.     }

  593.     value = cf->args->elts;

  594.     gcf->city = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);

  595.     if (gcf->city == NULL) {
  596.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  597.                            "GeoIP_open(\"%V\") failed", &value[1]);

  598.         return NGX_CONF_ERROR;
  599.     }

  600.     if (cf->args->nelts == 3) {
  601.         if (ngx_strcmp(value[2].data, "utf8") == 0) {
  602.             GeoIP_set_charset(gcf->city, GEOIP_CHARSET_UTF8);

  603.         } else {
  604.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  605.                                "invalid parameter \"%V\"", &value[2]);
  606.             return NGX_CONF_ERROR;
  607.         }
  608.     }

  609.     switch (gcf->city->databaseType) {

  610.     case GEOIP_CITY_EDITION_REV0:
  611.     case GEOIP_CITY_EDITION_REV1:

  612.         return NGX_CONF_OK;

  613. #if (NGX_HAVE_GEOIP_V6)
  614.     case GEOIP_CITY_EDITION_REV0_V6:
  615.     case GEOIP_CITY_EDITION_REV1_V6:

  616.         gcf->city_v6 = 1;
  617.         return NGX_CONF_OK;
  618. #endif

  619.     default:
  620.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  621.                            "invalid GeoIP City database \"%V\" type:%d",
  622.                            &value[1], gcf->city->databaseType);
  623.         return NGX_CONF_ERROR;
  624.     }
  625. }


  626. static char *
  627. ngx_http_geoip_proxy(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  628. {
  629.     ngx_http_geoip_conf_t  *gcf = conf;

  630.     ngx_str_t   *value;
  631.     ngx_cidr_t  cidr, *c;

  632.     value = cf->args->elts;

  633.     if (ngx_http_geoip_cidr_value(cf, &value[1], &cidr) != NGX_OK) {
  634.         return NGX_CONF_ERROR;
  635.     }

  636.     if (gcf->proxies == NULL) {
  637.         gcf->proxies = ngx_array_create(cf->pool, 4, sizeof(ngx_cidr_t));
  638.         if (gcf->proxies == NULL) {
  639.             return NGX_CONF_ERROR;
  640.         }
  641.     }

  642.     c = ngx_array_push(gcf->proxies);
  643.     if (c == NULL) {
  644.         return NGX_CONF_ERROR;
  645.     }

  646.     *c = cidr;

  647.     return NGX_CONF_OK;
  648. }

  649. static ngx_int_t
  650. ngx_http_geoip_cidr_value(ngx_conf_t *cf, ngx_str_t *net, ngx_cidr_t *cidr)
  651. {
  652.     ngx_int_t  rc;

  653.     if (ngx_strcmp(net->data, "255.255.255.255") == 0) {
  654.         cidr->family = AF_INET;
  655.         cidr->u.in.addr = 0xffffffff;
  656.         cidr->u.in.mask = 0xffffffff;

  657.         return NGX_OK;
  658.     }

  659.     rc = ngx_ptocidr(net, cidr);

  660.     if (rc == NGX_ERROR) {
  661.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid network \"%V\"", net);
  662.         return NGX_ERROR;
  663.     }

  664.     if (rc == NGX_DONE) {
  665.         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  666.                            "low address bits of %V are meaningless", net);
  667.     }

  668.     return NGX_OK;
  669. }


  670. static void
  671. ngx_http_geoip_cleanup(void *data)
  672. {
  673.     ngx_http_geoip_conf_t  *gcf = data;

  674.     if (gcf->country) {
  675.         GeoIP_delete(gcf->country);
  676.     }

  677.     if (gcf->org) {
  678.         GeoIP_delete(gcf->org);
  679.     }

  680.     if (gcf->city) {
  681.         GeoIP_delete(gcf->city);
  682.     }
  683. }