顯示具有 geoip 標籤的文章。 顯示所有文章
顯示具有 geoip 標籤的文章。 顯示所有文章

2024年12月5日 星期四

PHP 開發筆記 - 產生 CountryCode, CountryName, CityName, GeoLocation 列表

原本一直盧 AI 產出,發現產出的品質很難控,最後就轉個彎去把 GeoIP DB 內的資料輸出即可,而策略也很簡單,單純用 IP 暴力輪詢。理論上可以優雅一點去了解 DB Record format,總之,暴力解也很快,就順手先記錄一下,此例僅列出部分資訊(非輪詢所有 IPv4):

```
<?php
if (!extension_loaded('geoip')) {
    die("GeoIP extension is not installed\n");
}

class GeoIPParser {
    private $dbPath;
    
    public function __construct($dbPath = '/tmp/db.dat') {
        $this->dbPath = $dbPath;
        geoip_setup_custom_directory('/tmp');
    }
    
    public function parse() {
        if (!file_exists($this->dbPath)) {
            throw new Exception("GeoIP City database not found at {$this->dbPath}");
        }
        
        $locations = [];
        $processed = [];
        
        try {
            // 遍歷 IP 範圍,每個 /16 subnet 取樣幾個 IP
            for ($first = 1; $first <= 255; $first++) {
                fprintf(STDERR, "\rProcessing IP block: %d/255", $first);
                
                for ($second = 0; $second <= 255; $second += 5) {
                    $ip = "$first.$second.1.1";
                    $record = geoip_record_by_name($ip);
                    
                    if ($record && 
                        !empty($record['country_code']) && 
                        !empty($record['city'])) {
                        
                        $key = $record['country_code'] . '|' . $record['city'];
                        
                        if (!isset($processed[$key])) {
                            $location = [
                                'country_code' => $record['country_code'],
                                'country_name' => $record['country_name'],
                                'city_name' => $record['city'],
                                'geo_location' => [
                                    'latitude' => round($record['latitude'], 4),
                                    'longitude' => round($record['longitude'], 4)
                                ]
                            ];
                            
                            $locations[] = $location;
                            $processed[$key] = true;
                        }
                    }
                }
            }
            
            fprintf(STDERR, "\nProcessing completed. Total locations found: " . count($locations) . "\n");
            
            // 按國家代碼和城市名稱排序
            usort($locations, function($a, $b) {
                $countryComp = strcmp($a['country_code'], $b['country_code']);
                return $countryComp === 0 ? 
                    strcmp($a['city_name'], $b['city_name']) : 
                    $countryComp;
            });
            
            return $locations;
        } catch (Exception $e) {
            fprintf(STDERR, "Error during processing: " . $e->getMessage() . "\n");
            throw $e;
        }
    }
}

try {
    $parser = new GeoIPParser();
    $locations = $parser->parse();
    
    // 輸出為格式化的 JSON
    echo json_encode($locations, 
        JSON_PRETTY_PRINT | 
        JSON_UNESCAPED_UNICODE | 
        JSON_UNESCAPED_SLASHES
    );
    
} catch (Exception $e) {
    fwrite(STDERR, "Error: " . $e->getMessage() . "\n");
    exit(1);
}
```

產出:

```
% php83 -ini | grep geoip
/opt/local/var/db/php83/geoip.ini,
geoip
geoip support => enabled
geoip extension version => 1.1.1
geoip library version => 1005000
geoip.custom_directory => no value => no value
% php83 geo-lookup.php 
Processing IP block: 255/255
Processing completed. Total locations found: 2657
...
```

片段資料: 

% php83 list-geo-city.php | jq '[.[]|select(.country_code=="TW")]'         
Processing IP block: 255/255
Processing completed. Total locations found: 8020
[
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Anping District",
    "geo_location": {
      "latitude": 22.9965,
      "longitude": 120.1617
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Bade District",
    "geo_location": {
      "latitude": 24.9259,
      "longitude": 121.2763
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Banqiao",
    "geo_location": {
      "latitude": 25.0104,
      "longitude": 121.4683
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Beitou",
    "geo_location": {
      "latitude": 25.1403,
      "longitude": 121.4948
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Chang-hua",
    "geo_location": {
      "latitude": 24.0759,
      "longitude": 120.5657
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Chiayi City",
    "geo_location": {
      "latitude": 23.4815,
      "longitude": 120.4498
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Chiyayi County",
    "geo_location": {
      "latitude": 23.4461,
      "longitude": 120.5728
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Daan",
    "geo_location": {
      "latitude": 25.0316,
      "longitude": 121.5345
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Dacun",
    "geo_location": {
      "latitude": 23.9978,
      "longitude": 120.547
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Dawan",
    "geo_location": {
      "latitude": 23.2073,
      "longitude": 120.1906
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Daya",
    "geo_location": {
      "latitude": 24.2226,
      "longitude": 120.6493
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Douliu",
    "geo_location": {
      "latitude": 23.7125,
      "longitude": 120.545
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "East District",
    "geo_location": {
      "latitude": 22.9721,
      "longitude": 120.2224
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Guishan",
    "geo_location": {
      "latitude": 25.0273,
      "longitude": 121.359
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Hsinchu",
    "geo_location": {
      "latitude": 24.8065,
      "longitude": 120.9706
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Hsinchu County",
    "geo_location": {
      "latitude": 24.673,
      "longitude": 121.1614
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Hualien City",
    "geo_location": {
      "latitude": 23.9807,
      "longitude": 121.6115
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Jian",
    "geo_location": {
      "latitude": 23.9516,
      "longitude": 121.5639
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Jinshan",
    "geo_location": {
      "latitude": 25.0613,
      "longitude": 121.5705
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Kaohsiung City",
    "geo_location": {
      "latitude": 22.6148,
      "longitude": 120.3139
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Keelung",
    "geo_location": {
      "latitude": 25.1322,
      "longitude": 121.742
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Linkou District",
    "geo_location": {
      "latitude": 25.0738,
      "longitude": 121.3935
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Miaoli",
    "geo_location": {
      "latitude": 24.5641,
      "longitude": 120.8275
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Nantou City",
    "geo_location": {
      "latitude": 23.9082,
      "longitude": 120.6558
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Neihu District",
    "geo_location": {
      "latitude": 25.0811,
      "longitude": 121.5838
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "New Taipei City",
    "geo_location": {
      "latitude": 24.9466,
      "longitude": 121.586
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Penghu County",
    "geo_location": {
      "latitude": 23.5748,
      "longitude": 119.6098
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Pingtung City",
    "geo_location": {
      "latitude": 22.6745,
      "longitude": 120.491
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Puli",
    "geo_location": {
      "latitude": 23.9678,
      "longitude": 120.9644
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Sanchong District",
    "geo_location": {
      "latitude": 25.0691,
      "longitude": 121.4878
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Sanxia District",
    "geo_location": {
      "latitude": 24.9336,
      "longitude": 121.372
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Shiding District",
    "geo_location": {
      "latitude": 24.9956,
      "longitude": 121.6546
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Shoufeng",
    "geo_location": {
      "latitude": 23.8341,
      "longitude": 121.521
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Taibao",
    "geo_location": {
      "latitude": 23.4603,
      "longitude": 120.3284
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Taichung",
    "geo_location": {
      "latitude": 24.144,
      "longitude": 120.6844
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Taichung City",
    "geo_location": {
      "latitude": 24.1547,
      "longitude": 120.6716
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Tainan City",
    "geo_location": {
      "latitude": 22.9917,
      "longitude": 120.2147
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Taipei",
    "geo_location": {
      "latitude": 25.0504,
      "longitude": 121.5324
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Taitung",
    "geo_location": {
      "latitude": 22.7563,
      "longitude": 121.1418
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Taoyuan",
    "geo_location": {
      "latitude": 24.9977,
      "longitude": 121.2965
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Taoyuan District",
    "geo_location": {
      "latitude": 24.9889,
      "longitude": 121.3175
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Xizhi District",
    "geo_location": {
      "latitude": 25.0696,
      "longitude": 121.6577
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Yilan",
    "geo_location": {
      "latitude": 24.7574,
      "longitude": 121.7421
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Yongkang District",
    "geo_location": {
      "latitude": 23.0204,
      "longitude": 120.2591
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Yunlin",
    "geo_location": {
      "latitude": 23.7113,
      "longitude": 120.3897
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Zhongli District",
    "geo_location": {
      "latitude": 24.9614,
      "longitude": 121.2437
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Zhubei",
    "geo_location": {
      "latitude": 24.8351,
      "longitude": 121.0056
    }
  },
  {
    "country_code": "TW",
    "country_name": "Taiwan",
    "city_name": "Zuoying",
    "geo_location": {
      "latitude": 22.6868,
      "longitude": 120.2971
    }
  }
]

2021年4月22日 星期四

[PHP] 下載 Maxmind GeoIP Legacy Databases 和 ngx_http_geoip_module 相關處理 @ macOS 11.2, PHP 7.3.24

由於 Maxmind 在推 GeoIP2 ,不開放 .dat 的 GeoIP DB 了,以前下載位置:

  • http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
  • http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
現在官方都說要改用 GeoLite2 DB ,其格式:
  • GeoIP2 Binary (.mmdb)
  • GeoIP2 CSV 
目前先偷懶不處理 nginx ,因為 nginx 採用 GeoIP Legacy Databases。

有找到一個網站 https://www.miyuru.lk/geoiplegacy,從中下載:
連續動作:

% php -v
WARNING: PHP is not recommended
PHP is included in macOS for compatibility with legacy software.
Future versions of macOS will not include PHP.
PHP 7.3.24-(to be removed in future macOS) (cli) (built: Dec 21 2020 21:33:25) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.24, Copyright (c) 1998-2018 Zend Technologies

% php composer.phar require geoip/geoip:~1.16

% wget https://dl.miyuru.lk/geoip/maxmind/city/maxmind4.dat.gz
% gunzip -d maxmind4.dat.gz

% cat test-ip-via-geoip.php
<?php
require 'vendor/autoload.php';
$gi = geoip_open("maxmind4.dat",GEOIP_STANDARD);
$country = geoip_country_code_by_addr($gi, $argv[1]);
echo "lookup [".$argv[1]."], result: [$country]\n";

% php test-ip-via-geoip.php 8.8.8.8
lookup [8.8.8.8], result: [US]

% nslookup tw.yahoo.com
Server: 8.8.8.8
Address: 8.8.8.8#53

Non-authoritative answer:
tw.yahoo.com canonical name = atsv2-fp-shed.wg1.b.yahoo.com.
Name: atsv2-fp-shed.wg1.b.yahoo.com
Address: 180.222.102.201
Name: atsv2-fp-shed.wg1.b.yahoo.com
Address: 180.222.102.202

% php test-ip-via-geoip.php 180.222.102.202
lookup [180.222.102.202], result: [IN]

% curl ipinfo.io/180.222.102.202
{
  "ip": "180.222.102.202",
  "hostname": "media-router-fp74.prod.media.vip.tp2.yahoo.com",
  "city": "Taoyuan City",
  "region": "Taiwan",
  "country": "TW",
  "loc": "24.9937,121.2970",
  "org": "AS24506 YAHOO! TAIWAN",
  "timezone": "Asia/Taipei",
  "readme": "https://ipinfo.io/missingauth"
}

% nslookup facebook.com
Server: 8.8.8.8
Address: 8.8.8.8#53

Non-authoritative answer:
Name: facebook.com
Address: 31.13.87.36

% curl ipinfo.io/31.13.87.36
{
  "ip": "31.13.87.36",
  "hostname": "edge-star-mini-shv-01-tpe1.facebook.com",
  "city": "Hong Kong",
  "region": "Central and Western",
  "country": "HK",
  "loc": "22.2783,114.1747",
  "org": "AS32934 Facebook, Inc.",
  "timezone": "Asia/Hong_Kong",
  "readme": "https://ipinfo.io/missingauth"
}

% nslookup www.gov.tw
Server: 8.8.8.8
Address: 8.8.8.8#53

Non-authoritative answer:
Name: www.gov.tw
Address: 223.200.155.55

% php test-ip-via-geoip.php 223.200.155.55
lookup [223.200.155.55], result: [TW]

% curl ipinfo.io/223.200.155.55
{
  "ip": "223.200.155.55",
  "hostname": "223-200-155-55.hinet-ip.hinet.net",
  "city": "Hualien City",
  "region": "Taiwan",
  "country": "TW",
  "loc": "23.9769,121.6044",
  "org": "AS4782 Data Communication Business Group",
  "timezone": "Asia/Taipei",
  "readme": "https://ipinfo.io/missingauth"
}

2021年4月9日 星期五

[PHP] 透過 Maxmind GeoIP DB 統計用戶資訊 @ macOS 11.2, PHP 7.3.24

真是超級久沒用 maxmind.com 的 GeoIP DB 了,一時之間還以為沒有免費使用的方式,追了一下是要註冊帳號才能下載,而 maxmind 也有提供自動化每天更新 GeoIP DB 的機制。

在此對一份類似 Access Logs 做分析,將其轉成 CSV 格式來分析,其中 CSV 裡頭有 id 跟 remote_ip 兩個欄位,將 remote_ip 分析完後直接歸類屬於哪個 country_code,程式碼很簡單:

% php -v

WARNING: PHP is not recommended
PHP is included in macOS for compatibility with legacy software.
Future versions of macOS will not include PHP.
PHP 7.3.24-(to be removed in future macOS) (cli) (built: Dec 21 2020 21:33:25) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.24, Copyright (c) 1998-2018 Zend Technologies

% cat composer.json
{
  "require": {
    "geoip2/geoip2": "~2.0"
  }
}

% php composer.phar install
No lock file found. Updating dependencies instead of installing from lock file. Use composer update over composer install if you do not have a lock file.
Loading composer repositories with package information
Updating dependencies
Lock file operations: 4 installs, 0 updates, 0 removals
- Locking composer/ca-bundle (1.2.9)
- Locking geoip2/geoip2 (v2.11.0)
- Locking maxmind-db/reader (v1.10.0)
- Locking maxmind/web-service-common (v0.8.1)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 4 installs, 0 updates, 0 removals
- Installing composer/ca-bundle (1.2.9): Extracting archive
- Installing maxmind/web-service-common (v0.8.1): Extracting archive
- Installing maxmind-db/reader (v1.10.0): Extracting archive
- Installing geoip2/geoip2 (v2.11.0): Extracting archive
2 package suggestions were added by new dependencies, use `composer suggest` to see details.

Generating autoload files
1 package you are using is looking for funding.
Use the `composer fund` command to find out more!

% cat job.php
<?php

require 'vendor/autoload.php';

// https://github.com/maxmind/GeoIP2-php
use GeoIp2\Database\Reader;
$reader = new Reader('GeoLite2-City.mmdb');

// https://www.php.net/manual/en/function.fgetcsv.php
$row = 1;
$header_row = NULL;
$header = array();
$country_group = array(); 
$lookup = array();

$tracking_time_cost_per_run = microtime(true);
echo "[".date("Y-m-d H:i:s")."]\tinit\n";
if (($handle = fopen("access_log.csv", "r")) !== FALSE) {
while (($data = fgetcsv($handle, 10240, ",")) !== FALSE) {
if (is_null($header_row)) {
$header_row = $data;
foreach($header_row as $index => $name) {
$header[$name] = $index;
}
continue;
}
$remote_ip = $data[ $header['remote_ip'] ];
$data_id = $data[ $header['id'] ];

try {
$record = $reader->city($remote_ip);
} catch (Exception $e) {
continue;
}
if (!is_null($record) && property_exists($record, 'country') && !is_null($record->country) && isset($record->country->isoCode)) {
if (!isset($country_group[$record->country->isoCode]))
$country_group[$record->country->isoCode] = array();
$hash_key = $remote_ip.'-'.$record->country->isoCode;
if (!isset($lookup[$hash_key])) {
$lookup[$hash_key] = 1;
array_push($country_group[$record->country->isoCode], $data_id);
}
}
++$row;
if ($row % 100000 == 0) {
echo "[".date("Y-m-d H:i:s")."]\t".number_format($row).", time cost: ".(microtime(true) - $tracking_time_cost_per_run)."\n";
$tracking_time_cost_per_run = microtime(true);
file_put_contents('/tmp/lookup-result.json', json_encode($country_group));
}
}
fclose($handle);

echo "[".date("Y-m-d H:i:s")."]\t".number_format($row)."\n";
echo "Total #: $row\n";
print_r($header);
file_put_contents('lookup-result.json', json_encode($country_group));
}

產出:
% time php job.php
[2021-04-09 21:03:51] init
[2021-04-09 21:05:18] 100,000, time cost: 86.867056131363
[2021-04-09 21:06:41] 200,000, time cost: 83.395349025726 
...

% jq '' /tmp/lookup-result.json | head -n10

{
  "TW": [
    "1",
    "68",
    "101",
    "121",
    "147",
    "193",
    "236",
    "259", 
... 

就把一堆 record id 擺在某個 country_code 下面,每 85秒處理完 10萬筆資料。

2016年9月8日 星期四

Ansible 筆記 - 設定 Nginx 啟用 ngx_http_geoip_module.so 片段程式 @ Ubuntu 14.0

其實該寫成 Ansible Role 的,但一時之間有點懶,先把練習的片段紀錄一下。

安裝 nginx-module-geoip:

$ cat geoip-nginx.yml
---
    - name: install geoip packages
      apt: name={{ item }} update_cache=yes state=latest
      with_items:
        - nginx-module-geoip
      when: install_package is defined and install_package

    - name: check maxmind db - http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
      command: bash -c 'test -e /data/GeoIP.dat || curl http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz | gunzip - > /data/GeoIP.dat'

    - name: check maxmind db - http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
      command: bash -c 'test -e /data/GeoLiteCity.dat || curl http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz | gunzip - > /data/GeoLiteCity.dat'


設定 nginx.conf:

$ cat server-deploy.yml
...
  tasks:
    ...
    - include: geoip-nginx.yml
    - name: setup nginx config file - add modules/ngx_http_geoip_module.so
      lineinfile:
        dest: /etc/nginx/nginx.conf
        insertbefore: '^user '
        line: 'load_module "modules/ngx_http_geoip_module.so";'

    - name: setup nginx config file - setup geoip resource path
      lineinfile:
        dest: /etc/nginx/nginx.conf
        insertafter: '^http {'
        line: '    geoip_country /data/GeoIP.dat; geoip_proxy 192.168.0.0/16; geoip_proxy 10.0.0.0/24; geoip_proxy_recursive on;'
        #line: '    geoip_city    /data/GeoLiteCity.dat;'

    - name: setup nginx file to enable geoip - update log format
      lineinfile:
        dest: /etc/nginx/nginx.conf
        regexp: ".*?http_user_agent.*?http_x_forwarded_for"
        line: "                      '\"$http_user_agent\" \"$http_x_forwarded_for\"' $geoip_country_code \"$geoip_country_name\" ;"

    - name: setup nginx file to enable geoip - add GEOIP_COUNTRY_CODE for FastCGI
      lineinfile:
        dest: /etc/nginx/fastcgi_params
        insertbefore: "^fastcgi_param QUERY_STRING"
        line: "fastcgi_param     GEOIP_COUNTRY_CODE $geoip_country_code;"


如此一來,產生的 nginx.conf 如下:

$ cat /etc/nginx/nginx.conf && sudo nginx -t

load_module "modules/ngx_http_geoip_module.so";
user www-data;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    geoip_country /data/GeoIP.dat; geoip_proxy 192.168.0.0/16; geoip_proxy 10.0.0.0/24; geoip_proxy_recursive on;
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"' $geoip_country_code "$geoip_country_name" ;

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful


查看 /var/log/nginx/access.log 就可以看到類似的範例:

.... CN,CHN,"China"
.... US,USA,"United States"


更多變數定義,請參考:http://nginx.org/en/docs/http/ngx_http_geoip_module.html

2016年9月7日 星期三

[Linux] Nginx 啟用 nginx-module-geoip @ Ubuntu 14.04

Nginx 從 1.9.1 起,支援 Dynamic Modules 囉,此例是想要使用 MaxMind 來進行 IP 反查,接著想說有沒有方便的整合方式,像是寫 PHP 就用 MaxMind PHP library 等。

接著,就先查一下自己的 nginx 情況吧!

$ nginx -V
nginx version: nginx/1.10.1
... 找關鍵字 ...
--with-http_geoip_module=dynamic
...


很 OK ,接著再裝一下 ngx_http_geoip_module.so 吧!

$ apt-cache search nginx-module-geoip
nginx-module-geoip - geoip module
$ sudo apt-get install nginx-module-geoip
...
The GeoIP dynamic module for nginx has been installed.
To enable this module, add the following to /etc/nginx/nginx.conf
and reload nginx:

    load_module modules/ngx_http_geoip_module.so;

Please refer to the module documentation for further details:
http://nginx.org/en/docs/http/ngx_http_geoip_module.html
...


下載 MaxMind 資料:

$ curl http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz | gunzip - > /data/GeoIP.dat
$ curl http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz | gunzip - > /data/GeoLiteCity.dat


設置 Nginx,把 load_module 擺在最前頭
$ sudo vim /etc/nginx/nginx.conf
load_module "modules/ngx_http_geoip_module.so";
...

http {
    #geoip_country /data/GeoIP.dat;
    geoip_city    /data/GeoLiteCity.dat;
    ...

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" '
                      'GeoCountry[ "$geoip_country_name" "$geoip_country_code" "$geoip_country_code3" ] '
                      'GeoCity[ "$geoip_city_country_code" "$geoip_city_country_code3" "$geoip_city_country_name" ] '
                      'GeoLocation[ "$geoip_latitude" "$geoip_longitude" "$geoip_region" "$geoip_region_name" "$geoip_city" "$geoip_postal_code" ] '
    ;

    access_log  /var/log/nginx/access.log  main;
...

$ sudo service nginx reload


如此一來,就可以翻 /var/log/nginx/access.log 看看豐富的 GeoInfo 啦

2014年6月25日 星期三

[Linux] Apache/GeoIP/mod_geoip: 依據 Client IP Country 回傳指定 Server Location @ Ubuntu 14.04、Apache 2.4.7

$ apt-cache show libapache2-mod-geoip
Package: libapache2-mod-geoip
Priority: optional
Section: universe/web
Installed-Size: 86
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Original-Maintainer: Prach Pongpanich <prachpub@gmail.com>
Architecture: amd64
Version: 1.2.8-2
Depends: apache2-api-20120211, libc6 (>= 2.3.4), libgeoip1
Filename: pool/universe/liba/libapache2-mod-geoip/libapache2-mod-geoip_1.2.8-2_amd64.deb
Size: 18748
MD5sum: fc16528f6d8acabaf8d40c70fe47b1b2
SHA1: 457df303c09556297a8b1f6887fe7a901d8bd063
SHA256: 26eabfe728014a506186f2856a3149f00e7bfcb6db9226dbfe13976ab3b4d584
Description-en: GeoIP support for apache2
 This is an apache2 module for finding the country that a web request
 originated from. It uses the GeoIP library and database to perform
 the lookup. The module allows manipulation of client requests from within
 Apache based on the country of origin.
 .
 This module only works on Apache 2 servers.
Description-md5: e4085008663af571952df21045e8534a
Homepage: http://www.maxmind.com/app/mod_geoip
Bugs: https://bugs.launchpad.net/ubuntu/+filebug
Origin: Ubuntu

$ sudo apt-get install libapache2-mod-geoip

$ ls -la /usr/share/GeoIP/
total 3852
-rw-r--r--   1 root root  827301 Apr  7 14:20 GeoIP.dat
-rw-r--r--   1 root root 3105495 Apr  7 14:21 GeoIPv6.dat


基本上安裝完就等同啟動 mod_geoip ,可以在 /etc/apache2/mods-enabled 看到 geoip.conf, geoip.load 蹤影。

編輯 Apache configure file:

<IfModule mod_geoip.c>
        GeoIPEnable On
        <IfModule mod_rewrite.c>
                RewriteEngine On
                RewriteCond %{ENV:GEOIP_COUNTRY_CODE} ^CN$
                RewriteRule ^(.*)$ http://example.com.cn$1 [L]
        </IfModule>
</IfModule>


如此一來,當 Client IP 判斷是 CN 時,透過 Web Server 導向 CN 區的機器。

使用這招的目的是...大陸架設服務時,需要"備案",在備案還沒通過時,使用 domainname 連線過去的機器會被 ban 掉,這時候可以先稍微用已備案的或是 IP 來頂替了。

當備案成功後,就可以大方地使用 GeoDNS 的解法,讓使用者不必先連到指定機器再轉址。

最後,如果要留一些 debug 模式,可以多加上 hostname 的判斷,限定特定 hostname 才會依照使用者 IP 位置轉址。

<IfModule mod_geoip.c>
        GeoIPEnable On
        <IfModule mod_rewrite.c>
                RewriteEngine On
                RewriteCond %{HTTP_HOST} .
                RewriteCond %{HTTP_HOST} ^www\.example\.com$
                RewriteCond %{ENV:GEOIP_COUNTRY_CODE} ^CN$
                RewriteRule ^(.*)$ http://www.example.com.cn$1 [L]
        </IfModule>
</IfModule>


參考資料:

2014年2月20日 星期四

[Linux] 使用 MAXMIND GeoLite2 Free 進行 Offline 查詢 IP 與 Country 和 City 對應 @ Ubuntu 12.04

使用 MAXMIND DB 進行 Offline 查詢 IP 與 Country 和 City 對應

雖然網路上還有不少可以線上查詢的服務,將 IP 轉成地區資訊,如:

$ curl ipinfo.io/8.8.8.8
{
  "ip": "8.8.8.8",
  "hostname": "google-public-dns-a.google.com",
  "city": null,
  "region": null,
  "country": "US",
  "loc": "38.0000,-97.0000",
  "org": "AS15169 Google Inc."
}


不過,大多都有查詢次數的限制,所以,自己架一個來處理吧,在此就挑選 MAXMIND GeoLite2 Free 來使用,其中 FREE 版本就只提供查詢 Country 跟 City 而已。

以 GeoLite2-City.mmdb 為例:

<?php

$target_ip = isset( $_REQUEST['ip'] ) && !empty($_REQUEST['ip']) ? $_REQUEST['ip'] : ( isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : NULL ) ;
// $target_ip = '8.8.8.8';

require( 'MaxMind/Db/Reader.php' );
require( 'MaxMind/Db/Reader/Decoder.php' );
require( 'MaxMind/Db/Reader/InvalidDatabaseException.php' );
require( 'MaxMind/Db/Reader/Metadata.php' );

$reader = new MaxMind\Db\Reader('/path/GeoLite2-City.mmdb');
$record = $reader->get($target_ip);
$reader->close();
echo "<pre>";
print_r( $record );
echo "</pre>";


其中 MaxMind 程式碼可在 github.com/maxmind/MaxMind-DB-Reader-php 下載,此外,在 Ubuntu apt-get 上也有 php5-geoip - GeoIP module for php5 可安裝。

查詢 8.8.8.8:

Array
(
    [continent] => Array
        (
            [code] => NA
            [geoname_id] => 6255149
            [names] => Array
                (
                    [de] => Nordamerika
                    [en] => North America
                    [es] => Norteamérica
                    [fr] => Amérique du Nord
                    [ja] => 北アメリカ
                    [pt-BR] => América do Norte
                    [ru] => Северная Америка
                    [zh-CN] => 北美洲
                )

        )

    [country] => Array
        (
            [geoname_id] => 6252001
            [iso_code] => US
            [names] => Array
                (
                    [de] => USA
                    [en] => United States
                    [es] => Estados Unidos
                    [fr] => États-Unis
                    [ja] => アメリカ合衆国
                    [pt-BR] => Estados Unidos
                    [ru] => США
                    [zh-CN] => 美国
                )

        )

    [location] => Array
        (
            [latitude] => 38
            [longitude] => -97
        )

    [registered_country] => Array
        (
            [geoname_id] => 6252001
            [iso_code] => US
            [names] => Array
                (
                    [de] => USA
                    [en] => United States
                    [es] => Estados Unidos
                    [fr] => États-Unis
                    [ja] => アメリカ合衆国
                    [pt-BR] => Estados Unidos
                    [ru] => США
                    [zh-CN] => 美国
                )

        )

)


查詢台灣IP:

Array
(
    [city] => Array
        (
            [geoname_id] => 1668341
            [names] => Array
                (
                    [de] => Taipeh
                    [en] => Taipei
                    [es] => Taipéi
                    [fr] => Taipei
                    [ja] => 台北市
                    [pt-BR] => Taipé
                    [ru] => Тайбэй
                    [zh-CN] => 台北市
                )

        )

    [continent] => Array
        (
            [code] => AS
            [geoname_id] => 6255147
            [names] => Array
                (
                    [de] => Asien
                    [en] => Asia
                    [es] => Asia
                    [fr] => Asie
                    [ja] => アジア
                    [pt-BR] => Ásia
                    [ru] => Азия
                    [zh-CN] => 亚洲
                )

        )

    [country] => Array
        (
            [geoname_id] => 1668284
            [iso_code] => TW
            [names] => Array
                (
                    [de] => Republik China
                    [en] => Taiwan
                    [es] => Taiwán
                    [fr] => Taïwan
                    [ja] => 中華民国
                    [pt-BR] => Taiwan
                    [ru] => Тайвань
                    [zh-CN] => 台湾
                )

        )

    [location] => Array
        (
            [latitude] => 25.0392
            [longitude] => 121.525
            [time_zone] => Asia/Taipei
        )

    [registered_country] => Array
        (
            [geoname_id] => 1668284
            [iso_code] => TW
            [names] => Array
                (
                    [de] => Republik China
                    [en] => Taiwan
                    [es] => Taiwán
                    [fr] => Taïwan
                    [ja] => 中華民国
                    [pt-BR] => Taiwan
                    [ru] => Тайвань
                    [zh-CN] => 台湾
                )

        )

    [subdivisions] => Array
        (
            [0] => Array
                (
                    [geoname_id] => 7280290
                    [names] => Array
                        (
                            [de] => Taipeh
                            [en] => Taipei
                            [es] => Taipéi
                            [ja] => 台北市
                            [pt-BR] => Taipé
                            [ru] => Тайбэй
                        )

                )

        )

)