IP기반 Seed 데이터 생성, 업데이트에 반영
This commit is contained in:
@@ -35,6 +35,9 @@ func main() {
|
||||
if err := userprogram.Sync(ctx, userprogram.SyncConfig{
|
||||
MySQL: mysqlCfg,
|
||||
DatabaseURL: dbURL,
|
||||
Backend: userprogram.BackendFromEnv(),
|
||||
LookupQuery: os.Getenv("GEOIP_LOOKUP_QUERY"),
|
||||
MMDBPath: os.Getenv("GEOIP_DB_PATH"),
|
||||
InitialCSV: paths.InitialCSV,
|
||||
UpdateDir: paths.UpdateDir,
|
||||
LogDir: paths.LogDir,
|
||||
|
||||
5880
initial_data/ip_geoinfo_seed_20251208.sql
Normal file
5880
initial_data/ip_geoinfo_seed_20251208.sql
Normal file
File diff suppressed because it is too large
Load Diff
653
initial_data/public_ip_list_20251208.csv
Normal file
653
initial_data/public_ip_list_20251208.csv
Normal file
@@ -0,0 +1,653 @@
|
||||
"login_public_ip"
|
||||
"14.48.84.141"
|
||||
"211.234.204.251"
|
||||
"117.111.6.13"
|
||||
"211.198.190.49"
|
||||
"211.235.72.178"
|
||||
"1.235.81.27"
|
||||
"114.200.179.133"
|
||||
"121.184.7.188"
|
||||
"211.234.192.13"
|
||||
"211.235.72.147"
|
||||
"218.158.86.157"
|
||||
"125.133.48.195"
|
||||
"112.161.155.175"
|
||||
"183.99.124.97"
|
||||
"220.66.76.78"
|
||||
"121.191.223.33"
|
||||
"125.138.71.211"
|
||||
"59.11.165.82"
|
||||
"115.178.65.26"
|
||||
"211.235.91.226"
|
||||
"59.10.150.245"
|
||||
"211.234.207.159"
|
||||
"115.21.217.190"
|
||||
"211.234.201.231"
|
||||
"118.47.158.73"
|
||||
"211.227.202.187"
|
||||
"211.107.218.58"
|
||||
"211.216.248.115"
|
||||
"220.66.76.90"
|
||||
"182.229.32.154"
|
||||
"220.66.75.59"
|
||||
"211.234.180.197"
|
||||
"110.13.11.131"
|
||||
"121.191.17.213"
|
||||
"61.255.88.218"
|
||||
"175.223.11.244"
|
||||
"1.239.250.231"
|
||||
"220.66.76.12"
|
||||
"220.77.100.238"
|
||||
"220.82.170.73"
|
||||
"121.169.76.48"
|
||||
"106.101.1.212"
|
||||
"140.174.179.52"
|
||||
"59.14.240.38"
|
||||
"220.66.76.27"
|
||||
"220.86.36.184"
|
||||
"125.142.226.122"
|
||||
"211.230.115.75"
|
||||
"106.246.182.243"
|
||||
"27.171.216.148"
|
||||
"218.158.239.173"
|
||||
"118.33.187.225"
|
||||
"59.16.104.87"
|
||||
"147.46.92.180"
|
||||
"59.16.73.144"
|
||||
"14.40.91.101"
|
||||
"106.101.3.30"
|
||||
"211.253.98.34"
|
||||
"58.232.80.152"
|
||||
"121.184.234.136"
|
||||
"183.100.230.19"
|
||||
"175.204.180.9"
|
||||
"61.78.80.26"
|
||||
"118.36.229.195"
|
||||
"220.66.76.86"
|
||||
"222.120.70.104"
|
||||
"119.196.164.92"
|
||||
"156.59.47.103"
|
||||
"147.46.91.174"
|
||||
"59.151.192.104"
|
||||
"211.234.192.53"
|
||||
"118.42.197.237"
|
||||
"202.150.191.177"
|
||||
"110.70.51.111"
|
||||
"121.139.50.83"
|
||||
"147.46.91.171"
|
||||
"147.46.92.184"
|
||||
"147.46.91.170"
|
||||
"61.73.2.206"
|
||||
"59.31.157.91"
|
||||
"110.8.170.18"
|
||||
"106.244.132.248"
|
||||
"211.192.150.114"
|
||||
"115.22.123.154"
|
||||
"211.234.195.205"
|
||||
"211.234.207.45"
|
||||
"114.108.4.68"
|
||||
"14.56.254.183"
|
||||
"220.66.76.34"
|
||||
"210.121.223.76"
|
||||
"180.80.112.236"
|
||||
"147.46.91.163"
|
||||
"118.216.73.120"
|
||||
"59.29.126.221"
|
||||
"14.7.55.231"
|
||||
"211.244.123.114"
|
||||
"220.121.164.74"
|
||||
"147.46.91.167"
|
||||
"115.138.239.234"
|
||||
"121.157.84.116"
|
||||
"147.46.92.169"
|
||||
"121.135.102.173"
|
||||
"220.90.89.151"
|
||||
"119.204.165.88"
|
||||
"147.46.91.138"
|
||||
"147.46.91.150"
|
||||
"211.235.72.16"
|
||||
"121.153.208.177"
|
||||
"121.132.197.222"
|
||||
"183.99.111.70"
|
||||
"223.39.177.150"
|
||||
"147.46.91.168"
|
||||
"147.46.91.130"
|
||||
"211.234.192.51"
|
||||
"121.164.134.117"
|
||||
"211.226.165.121"
|
||||
"182.208.205.103"
|
||||
"58.224.147.180"
|
||||
"220.66.76.25"
|
||||
"220.125.153.37"
|
||||
"156.59.47.87"
|
||||
"220.66.75.19"
|
||||
"220.66.76.97"
|
||||
"211.235.83.117"
|
||||
"115.95.35.118"
|
||||
"147.46.92.183"
|
||||
"211.234.201.160"
|
||||
"147.46.92.75"
|
||||
"221.153.165.116"
|
||||
"147.46.91.156"
|
||||
"147.46.91.161"
|
||||
"61.85.224.4"
|
||||
"106.101.130.197"
|
||||
"220.74.62.74"
|
||||
"121.180.83.184"
|
||||
"220.77.186.166"
|
||||
"112.166.96.247"
|
||||
"175.210.109.187"
|
||||
"125.129.140.58"
|
||||
"220.66.76.95"
|
||||
"211.234.197.119"
|
||||
"220.66.75.146"
|
||||
"1.235.32.245"
|
||||
"49.142.69.179"
|
||||
"218.146.23.149"
|
||||
"14.34.247.171"
|
||||
"125.135.247.165"
|
||||
"211.234.226.128"
|
||||
"211.234.200.241"
|
||||
"106.101.0.195"
|
||||
"218.153.177.253"
|
||||
"211.235.72.65"
|
||||
"221.154.56.116"
|
||||
"220.66.76.16"
|
||||
"39.127.71.122"
|
||||
"222.105.23.150"
|
||||
"223.39.219.99"
|
||||
"220.90.15.33"
|
||||
"121.149.50.106"
|
||||
"121.64.161.83"
|
||||
"211.235.65.89"
|
||||
"140.174.179.101"
|
||||
"39.7.47.68"
|
||||
"211.218.250.217"
|
||||
"221.138.240.198"
|
||||
"106.101.9.220"
|
||||
"220.66.76.29"
|
||||
"211.198.63.117"
|
||||
"147.46.91.145"
|
||||
"211.221.180.2"
|
||||
"59.186.123.155"
|
||||
"58.77.140.10"
|
||||
"222.239.194.164"
|
||||
"220.66.75.28"
|
||||
"27.165.137.52"
|
||||
"175.223.26.63"
|
||||
"121.141.47.152"
|
||||
"125.133.34.162"
|
||||
"147.46.92.177"
|
||||
"223.39.212.136"
|
||||
"147.46.91.141"
|
||||
"220.116.237.88"
|
||||
"106.101.11.6"
|
||||
"125.242.55.17"
|
||||
"106.101.128.56"
|
||||
"210.117.14.133"
|
||||
"156.59.47.101"
|
||||
"147.46.92.84"
|
||||
"118.221.140.2"
|
||||
"211.36.143.98"
|
||||
"106.101.136.2"
|
||||
"220.78.198.149"
|
||||
"147.46.92.182"
|
||||
"59.186.123.246"
|
||||
"112.163.158.164"
|
||||
"61.81.132.10"
|
||||
"117.111.21.63"
|
||||
"140.174.179.5"
|
||||
"121.151.201.239"
|
||||
"182.215.120.69"
|
||||
"218.144.247.3"
|
||||
"116.33.55.218"
|
||||
"147.46.91.137"
|
||||
"220.66.75.39"
|
||||
"220.117.8.14"
|
||||
"175.223.26.207"
|
||||
"116.34.125.138"
|
||||
"1.241.69.200"
|
||||
"211.234.194.156"
|
||||
"121.138.66.189"
|
||||
"210.105.187.27"
|
||||
"221.160.85.228"
|
||||
"58.237.207.130"
|
||||
"220.66.76.24"
|
||||
"211.234.192.81"
|
||||
"122.44.13.14"
|
||||
"220.66.76.11"
|
||||
"117.111.14.205"
|
||||
"125.248.23.189"
|
||||
"118.35.141.164"
|
||||
"210.99.28.101"
|
||||
"119.197.226.84"
|
||||
"211.234.203.248"
|
||||
"1.247.148.164"
|
||||
"61.39.66.227"
|
||||
"112.161.208.191"
|
||||
"175.213.178.48"
|
||||
"14.35.204.124"
|
||||
"211.234.188.148"
|
||||
"211.234.199.137"
|
||||
"1.238.107.99"
|
||||
"119.206.79.88"
|
||||
"147.46.35.247"
|
||||
"106.101.1.8"
|
||||
"223.39.176.122"
|
||||
"222.103.33.142"
|
||||
"110.70.47.11"
|
||||
"114.108.4.72"
|
||||
"147.46.91.177"
|
||||
"220.74.14.94"
|
||||
"211.234.194.250"
|
||||
"112.158.34.172"
|
||||
"112.170.16.221"
|
||||
"221.161.34.243"
|
||||
"59.1.172.178"
|
||||
"147.46.92.195"
|
||||
"121.148.130.230"
|
||||
"220.121.167.216"
|
||||
"115.89.238.220"
|
||||
"220.74.97.67"
|
||||
"222.99.115.189"
|
||||
"112.218.197.242"
|
||||
"156.59.47.105"
|
||||
"106.101.3.174"
|
||||
"114.108.4.74"
|
||||
"211.36.152.1"
|
||||
"110.70.54.119"
|
||||
"211.36.152.88"
|
||||
"211.218.206.137"
|
||||
"211.222.129.21"
|
||||
"218.148.114.204"
|
||||
"156.59.47.89"
|
||||
"156.59.47.102"
|
||||
"221.159.100.39"
|
||||
"210.206.95.190"
|
||||
"223.39.176.221"
|
||||
"125.137.245.86"
|
||||
"118.44.169.233"
|
||||
"211.185.247.104"
|
||||
"175.121.118.4"
|
||||
"125.136.144.163"
|
||||
"61.77.58.136"
|
||||
"222.110.160.71"
|
||||
"14.39.86.155"
|
||||
"211.36.158.211"
|
||||
"112.164.250.69"
|
||||
"1.235.111.48"
|
||||
"223.39.219.238"
|
||||
"211.36.159.30"
|
||||
"223.39.174.191"
|
||||
"106.248.204.158"
|
||||
"211.234.198.196"
|
||||
"114.203.88.3"
|
||||
"211.109.114.59"
|
||||
"125.130.142.245"
|
||||
"222.116.153.103"
|
||||
"58.227.62.3"
|
||||
"121.188.105.131"
|
||||
"121.188.98.4"
|
||||
"118.235.88.163"
|
||||
"110.35.50.202"
|
||||
"175.204.137.93"
|
||||
"14.45.119.89"
|
||||
"59.8.140.188"
|
||||
"59.0.82.13"
|
||||
"147.46.91.134"
|
||||
"211.36.152.213"
|
||||
"140.174.179.54"
|
||||
"147.46.91.155"
|
||||
"106.101.9.19"
|
||||
"147.46.91.136"
|
||||
"211.234.188.82"
|
||||
"223.39.219.31"
|
||||
"27.166.222.166"
|
||||
"118.44.178.75"
|
||||
"121.187.10.74"
|
||||
"210.204.169.25"
|
||||
"218.152.55.210"
|
||||
"118.39.26.132"
|
||||
"147.46.91.162"
|
||||
"61.82.142.93"
|
||||
"147.46.91.169"
|
||||
"147.46.91.148"
|
||||
"211.185.247.57"
|
||||
"121.66.158.246"
|
||||
"59.1.229.49"
|
||||
"119.207.27.75"
|
||||
"118.235.13.218"
|
||||
"106.101.11.31"
|
||||
"203.228.37.61"
|
||||
"121.177.226.29"
|
||||
"211.36.142.3"
|
||||
"175.197.85.244"
|
||||
"115.23.63.15"
|
||||
"220.149.222.50"
|
||||
"112.164.121.147"
|
||||
"112.170.151.209"
|
||||
"220.76.77.96"
|
||||
"59.27.94.66"
|
||||
"211.234.181.75"
|
||||
"220.70.176.152"
|
||||
"112.187.54.166"
|
||||
"220.66.76.85"
|
||||
"125.132.106.239"
|
||||
"147.46.92.153"
|
||||
"121.151.201.47"
|
||||
"211.211.117.44"
|
||||
"211.253.98.18"
|
||||
"223.39.218.48"
|
||||
"116.121.107.104"
|
||||
"110.70.54.144"
|
||||
"211.235.82.41"
|
||||
"211.193.241.72"
|
||||
"220.84.21.5"
|
||||
"147.46.91.140"
|
||||
"117.111.12.85"
|
||||
"39.125.46.181"
|
||||
"220.66.76.22"
|
||||
"223.53.98.220"
|
||||
"147.46.92.67"
|
||||
"211.36.136.245"
|
||||
"220.66.76.81"
|
||||
"222.114.41.134"
|
||||
"211.48.217.138"
|
||||
"42.27.139.140"
|
||||
"220.66.76.89"
|
||||
"175.223.19.27"
|
||||
"223.39.218.24"
|
||||
"147.46.91.146"
|
||||
"119.207.166.243"
|
||||
"14.53.188.21"
|
||||
"147.46.92.81"
|
||||
"147.46.91.149"
|
||||
"27.168.114.250"
|
||||
"118.37.166.161"
|
||||
"211.234.181.59"
|
||||
"125.179.210.215"
|
||||
"211.223.112.37"
|
||||
"211.235.74.158"
|
||||
"117.111.5.23"
|
||||
"106.101.2.36"
|
||||
"211.54.94.161"
|
||||
"42.20.3.222"
|
||||
"211.234.226.189"
|
||||
"211.234.180.75"
|
||||
"147.46.92.69"
|
||||
"211.234.203.21"
|
||||
"39.7.54.240"
|
||||
"210.93.112.123"
|
||||
"123.111.42.110"
|
||||
"119.204.117.36"
|
||||
"220.83.108.31"
|
||||
"223.39.218.193"
|
||||
"147.46.91.143"
|
||||
"222.107.72.242"
|
||||
"140.174.179.105"
|
||||
"220.66.75.91"
|
||||
"223.39.215.148"
|
||||
"147.46.91.166"
|
||||
"147.46.91.157"
|
||||
"121.187.162.200"
|
||||
"119.196.119.220"
|
||||
"211.108.72.139"
|
||||
"106.101.10.48"
|
||||
"211.196.60.173"
|
||||
"14.33.76.159"
|
||||
"59.3.140.180"
|
||||
"175.196.195.93"
|
||||
"156.59.47.84"
|
||||
"121.157.148.27"
|
||||
"211.54.213.71"
|
||||
"220.89.134.177"
|
||||
"106.101.2.74"
|
||||
"121.177.240.182"
|
||||
"222.121.148.227"
|
||||
"119.195.149.96"
|
||||
"211.235.66.78"
|
||||
"220.66.76.114"
|
||||
"14.51.248.237"
|
||||
"117.111.6.3"
|
||||
"220.66.76.249"
|
||||
"211.234.197.154"
|
||||
"218.232.187.68"
|
||||
"221.154.0.234"
|
||||
"211.219.72.198"
|
||||
"59.23.24.93"
|
||||
"112.167.22.71"
|
||||
"112.162.165.45"
|
||||
"61.98.205.242"
|
||||
"218.157.197.208"
|
||||
"59.186.123.237"
|
||||
"220.124.17.116"
|
||||
"121.161.151.28"
|
||||
"211.106.83.170"
|
||||
"220.66.76.21"
|
||||
"220.66.75.147"
|
||||
"220.121.253.183"
|
||||
"14.35.122.213"
|
||||
"211.234.202.228"
|
||||
"121.136.241.72"
|
||||
"221.165.252.99"
|
||||
"175.223.39.226"
|
||||
"106.101.1.169"
|
||||
"59.22.166.228"
|
||||
"118.235.74.207"
|
||||
"218.153.99.248"
|
||||
"211.169.233.104"
|
||||
"58.73.175.11"
|
||||
"175.210.233.213"
|
||||
"121.188.1.125"
|
||||
"211.234.227.38"
|
||||
"116.121.101.233"
|
||||
"211.234.201.135"
|
||||
"147.46.91.88"
|
||||
"125.242.55.15"
|
||||
"211.234.227.148"
|
||||
"180.65.219.52"
|
||||
"112.167.22.15"
|
||||
"222.118.36.105"
|
||||
"220.93.249.247"
|
||||
"61.85.177.75"
|
||||
"220.93.204.199"
|
||||
"211.234.204.13"
|
||||
"211.234.200.217"
|
||||
"121.169.114.68"
|
||||
"220.66.76.26"
|
||||
"223.39.219.47"
|
||||
"220.78.14.27"
|
||||
"59.2.190.227"
|
||||
"58.236.57.152"
|
||||
"175.194.216.115"
|
||||
"210.222.164.40"
|
||||
"14.36.217.161"
|
||||
"61.78.80.148"
|
||||
"147.46.91.142"
|
||||
"59.21.93.51"
|
||||
"112.166.253.199"
|
||||
"121.66.57.91"
|
||||
"211.234.203.150"
|
||||
"168.126.136.68"
|
||||
"106.101.2.252"
|
||||
"140.174.179.37"
|
||||
"49.175.164.136"
|
||||
"59.11.2.104"
|
||||
"223.39.202.254"
|
||||
"183.100.80.51"
|
||||
"42.19.21.126"
|
||||
"220.66.76.98"
|
||||
"219.251.6.155"
|
||||
"121.135.117.130"
|
||||
"112.186.236.215"
|
||||
"14.52.96.21"
|
||||
"211.36.145.170"
|
||||
"118.43.43.39"
|
||||
"222.102.162.27"
|
||||
"211.234.204.209"
|
||||
"115.138.239.252"
|
||||
"223.39.207.59"
|
||||
"110.70.47.253"
|
||||
"147.46.92.175"
|
||||
"211.235.82.89"
|
||||
"218.145.201.114"
|
||||
"169.211.153.84"
|
||||
"211.54.188.233"
|
||||
"140.174.179.7"
|
||||
"121.149.3.47"
|
||||
"118.42.56.19"
|
||||
"211.234.200.239"
|
||||
"14.35.229.40"
|
||||
"222.98.49.97"
|
||||
"14.53.69.245"
|
||||
"220.66.76.79"
|
||||
"147.46.92.93"
|
||||
"211.196.60.230"
|
||||
"223.38.94.117"
|
||||
"27.179.218.211"
|
||||
"211.170.25.65"
|
||||
"119.203.157.49"
|
||||
"220.66.76.91"
|
||||
"118.235.74.19"
|
||||
"61.43.126.201"
|
||||
"220.66.75.120"
|
||||
"59.26.59.41"
|
||||
"118.235.81.217"
|
||||
"147.46.92.179"
|
||||
"1.240.55.8"
|
||||
"220.71.159.105"
|
||||
"1.217.176.218"
|
||||
"114.71.128.87"
|
||||
"124.50.176.34"
|
||||
"147.46.91.131"
|
||||
"108.181.53.234"
|
||||
"211.198.89.114"
|
||||
"116.125.137.239"
|
||||
"183.98.129.158"
|
||||
"59.13.18.98"
|
||||
"147.47.202.18"
|
||||
"211.234.205.141"
|
||||
"58.150.67.157"
|
||||
"220.66.76.187"
|
||||
"211.215.11.165"
|
||||
"175.209.199.226"
|
||||
"211.234.206.165"
|
||||
"106.252.47.68"
|
||||
"59.19.225.21"
|
||||
"121.185.248.189"
|
||||
"110.35.154.135"
|
||||
"112.173.236.204"
|
||||
"147.46.91.151"
|
||||
"211.177.40.198"
|
||||
"59.3.164.233"
|
||||
"106.101.133.232"
|
||||
"42.22.207.68"
|
||||
"14.47.241.67"
|
||||
"118.235.73.87"
|
||||
"59.26.225.202"
|
||||
"61.83.185.245"
|
||||
"121.169.114.207"
|
||||
"112.168.110.147"
|
||||
"147.46.92.113"
|
||||
"112.170.153.89"
|
||||
"211.34.121.59"
|
||||
"222.232.200.179"
|
||||
"147.46.92.171"
|
||||
"59.29.17.192"
|
||||
"222.103.222.144"
|
||||
"222.112.53.139"
|
||||
"147.46.91.160"
|
||||
"1.241.255.157"
|
||||
"147.46.91.129"
|
||||
"14.48.158.224"
|
||||
"211.39.65.160"
|
||||
"116.124.153.130"
|
||||
"223.57.95.239"
|
||||
"106.101.3.193"
|
||||
"211.50.13.130"
|
||||
"218.150.119.207"
|
||||
"221.156.11.154"
|
||||
"211.218.253.1"
|
||||
"220.116.71.64"
|
||||
"147.46.92.173"
|
||||
"210.204.169.106"
|
||||
"59.0.165.173"
|
||||
"124.63.32.14"
|
||||
"211.234.180.120"
|
||||
"140.174.179.38"
|
||||
"211.235.91.16"
|
||||
"220.66.75.129"
|
||||
"147.46.91.61"
|
||||
"175.223.34.69"
|
||||
"119.193.183.73"
|
||||
"1.212.25.154"
|
||||
"106.101.0.26"
|
||||
"14.48.58.175"
|
||||
"203.231.144.61"
|
||||
"211.235.82.193"
|
||||
"59.28.27.189"
|
||||
"222.101.203.48"
|
||||
"175.206.14.81"
|
||||
"220.66.76.23"
|
||||
"211.234.192.25"
|
||||
"121.139.197.234"
|
||||
"147.46.91.158"
|
||||
"118.45.86.71"
|
||||
"121.162.82.93"
|
||||
"121.136.197.44"
|
||||
"211.228.5.235"
|
||||
"220.66.76.19"
|
||||
"147.46.92.71"
|
||||
"220.125.6.119"
|
||||
"59.21.195.163"
|
||||
"106.101.128.18"
|
||||
"59.12.200.34"
|
||||
"211.231.46.88"
|
||||
"147.46.91.139"
|
||||
"220.66.75.25"
|
||||
"123.214.63.222"
|
||||
"118.235.85.152"
|
||||
"59.186.123.249"
|
||||
"121.190.157.218"
|
||||
"223.39.218.74"
|
||||
"121.143.215.121"
|
||||
"61.254.28.177"
|
||||
"61.98.205.243"
|
||||
"115.138.209.44"
|
||||
"211.234.195.169"
|
||||
"59.186.123.226"
|
||||
"211.108.69.179"
|
||||
"27.163.144.150"
|
||||
"14.34.247.68"
|
||||
"121.185.152.100"
|
||||
"140.174.179.56"
|
||||
"118.223.231.46"
|
||||
"175.208.232.133"
|
||||
"147.46.91.175"
|
||||
"175.223.39.20"
|
||||
"121.124.88.96"
|
||||
"140.174.179.102"
|
||||
"222.98.163.179"
|
||||
"119.207.37.231"
|
||||
"147.46.91.165"
|
||||
"59.17.243.62"
|
||||
"14.46.56.26"
|
||||
"59.26.225.230"
|
||||
"42.22.217.197"
|
||||
"125.186.69.146"
|
||||
"211.234.199.135"
|
||||
"221.150.16.242"
|
||||
"121.124.172.71"
|
||||
"147.46.91.173"
|
||||
"147.46.92.152"
|
||||
"108.181.53.228"
|
||||
"220.66.76.17"
|
||||
"1.226.226.50"
|
||||
"223.39.218.225"
|
||||
"147.46.92.176"
|
||||
"58.79.5.215"
|
||||
"125.131.30.128"
|
||||
"61.75.98.148"
|
||||
"114.71.128.111"
|
||||
"211.223.30.241"
|
||||
"119.207.221.210"
|
||||
|
@@ -1,12 +1,23 @@
|
||||
package userprogram
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"geoip-rest/internal/geo"
|
||||
)
|
||||
|
||||
type Backend string
|
||||
|
||||
const (
|
||||
BackendMMDB Backend = "mmdb"
|
||||
BackendPostgres Backend = "postgres"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -88,6 +99,42 @@ func NewPathsFromEnv() (Paths, error) {
|
||||
return paths, nil
|
||||
}
|
||||
|
||||
func BackendFromEnv() Backend {
|
||||
val := strings.ToLower(env("GEOIP_BACKEND", string(BackendMMDB)))
|
||||
switch val {
|
||||
case string(BackendMMDB), "":
|
||||
return BackendMMDB
|
||||
case string(BackendPostgres):
|
||||
return BackendPostgres
|
||||
default:
|
||||
return BackendMMDB
|
||||
}
|
||||
}
|
||||
|
||||
func ResolveBackend(cfg geo.Config) (geo.Resolver, error) {
|
||||
switch Backend(cfg.Backend) {
|
||||
case BackendMMDB, "":
|
||||
if cfg.MMDBPath == "" {
|
||||
return nil, errors.New("MMDBPath required for mmdb backend")
|
||||
}
|
||||
return geo.NewResolver(geo.Config{
|
||||
Backend: geo.BackendMMDB,
|
||||
MMDBPath: cfg.MMDBPath,
|
||||
})
|
||||
case BackendPostgres:
|
||||
if cfg.DatabaseURL == "" {
|
||||
return nil, errors.New("DatabaseURL required for postgres backend")
|
||||
}
|
||||
return geo.NewResolver(geo.Config{
|
||||
Backend: geo.BackendPostgres,
|
||||
DatabaseURL: cfg.DatabaseURL,
|
||||
LookupQuery: cfg.LookupQuery,
|
||||
})
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported backend %s", cfg.Backend)
|
||||
}
|
||||
}
|
||||
|
||||
func ParseTargetDate(raw string) (time.Time, error) {
|
||||
if raw == "" {
|
||||
return yesterdayKST(), nil
|
||||
|
||||
192
internal/userprogram/ip_geoinfo.go
Normal file
192
internal/userprogram/ip_geoinfo.go
Normal file
@@ -0,0 +1,192 @@
|
||||
package userprogram
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
|
||||
"geoip-rest/internal/geo"
|
||||
)
|
||||
|
||||
func EnsureIPGeoInfoTable(ctx context.Context, conn *pgx.Conn, schema string) error {
|
||||
ddl := fmt.Sprintf(`
|
||||
CREATE TABLE IF NOT EXISTS %s.ip_geoinfo (
|
||||
id bigserial PRIMARY KEY,
|
||||
ip inet UNIQUE NOT NULL,
|
||||
country text,
|
||||
region text,
|
||||
city text,
|
||||
address text,
|
||||
latitude double precision,
|
||||
longitude double precision
|
||||
);`, pgx.Identifier{schema}.Sanitize())
|
||||
_, err := conn.Exec(ctx, ddl)
|
||||
return err
|
||||
}
|
||||
|
||||
// ExportPublicIPs writes distinct login_public_ip values to a CSV file with header.
|
||||
func ExportPublicIPs(ctx context.Context, conn *pgx.Conn, schema, path string) error {
|
||||
rows, err := conn.Query(ctx, fmt.Sprintf(`
|
||||
SELECT DISTINCT login_public_ip
|
||||
FROM %s.user_program_info_replica
|
||||
WHERE login_public_ip IS NOT NULL AND login_public_ip <> ''
|
||||
ORDER BY login_public_ip;`, pgx.Identifier{schema}.Sanitize()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var ips []string
|
||||
for rows.Next() {
|
||||
var ip string
|
||||
if err := rows.Scan(&ip); err != nil {
|
||||
return err
|
||||
}
|
||||
ips = append(ips, ip)
|
||||
}
|
||||
if rows.Err() != nil {
|
||||
return rows.Err()
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if _, err := f.WriteString(`"login_public_ip"` + "\n"); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, ip := range ips {
|
||||
if _, err := f.WriteString(fmt.Sprintf(`"%s"`+"\n", ip)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateIPGeoInfoSQL builds an upsert SQL file for IPs. If onlyNew is true, it skips
|
||||
// IPs already present in ip_geoinfo.
|
||||
func GenerateIPGeoInfoSQL(ctx context.Context, conn *pgx.Conn, schema string, resolver geo.Resolver, output string, onlyNew bool) (int, error) {
|
||||
query := fmt.Sprintf(`
|
||||
SELECT DISTINCT login_public_ip
|
||||
FROM %s.user_program_info_replica r
|
||||
WHERE login_public_ip IS NOT NULL AND login_public_ip <> ''`, pgx.Identifier{schema}.Sanitize())
|
||||
if onlyNew {
|
||||
query += fmt.Sprintf(`
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM %s.ip_geoinfo g WHERE g.ip = r.login_public_ip::inet
|
||||
)`, pgx.Identifier{schema}.Sanitize())
|
||||
}
|
||||
query += ";"
|
||||
|
||||
rows, err := conn.Query(ctx, query)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var ips []string
|
||||
for rows.Next() {
|
||||
var ip string
|
||||
if err := rows.Scan(&ip); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
ips = append(ips, ip)
|
||||
}
|
||||
if rows.Err() != nil {
|
||||
return 0, rows.Err()
|
||||
}
|
||||
if len(ips) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
sort.Strings(ips)
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(output), 0o755); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
f, err := os.Create(output)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
header := fmt.Sprintf("-- generated at %s KST\n", time.Now().In(kst()).Format(time.RFC3339))
|
||||
header += fmt.Sprintf("CREATE SCHEMA IF NOT EXISTS %s;\n", schemaIdent(schema))
|
||||
header += fmt.Sprintf(`CREATE TABLE IF NOT EXISTS %s.ip_geoinfo (
|
||||
id bigserial PRIMARY KEY,
|
||||
ip inet UNIQUE NOT NULL,
|
||||
country text,
|
||||
region text,
|
||||
city text,
|
||||
address text,
|
||||
latitude double precision,
|
||||
longitude double precision
|
||||
);`+"\n", schemaIdent(schema))
|
||||
if _, err := f.WriteString(header); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
count := 0
|
||||
for _, ip := range ips {
|
||||
loc, err := resolver.Lookup(ip)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
stmt := fmt.Sprintf(`INSERT INTO %s.ip_geoinfo (ip, country, region, city, address, latitude, longitude)
|
||||
VALUES ('%s', %s, %s, %s, %s, %f, %f)
|
||||
ON CONFLICT (ip) DO UPDATE SET
|
||||
country = EXCLUDED.country,
|
||||
region = EXCLUDED.region,
|
||||
city = EXCLUDED.city,
|
||||
address = EXCLUDED.address,
|
||||
latitude = EXCLUDED.latitude,
|
||||
longitude = EXCLUDED.longitude;
|
||||
`, schemaIdent(schema), toHostCIDR(ip), quote(loc.Country), quote(loc.Region), quote(loc.City), quote(loc.Address), loc.Latitude, loc.Longitude)
|
||||
if _, err := f.WriteString(stmt); err != nil {
|
||||
return count, err
|
||||
}
|
||||
count++
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func ExecuteSQLFile(ctx context.Context, conn *pgx.Conn, path string) error {
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = conn.Exec(ctx, string(content))
|
||||
return err
|
||||
}
|
||||
|
||||
func toHostCIDR(ipStr string) string {
|
||||
ip := net.ParseIP(ipStr)
|
||||
if ip == nil {
|
||||
return ""
|
||||
}
|
||||
if ip.To4() != nil {
|
||||
return ip.String() + "/32"
|
||||
}
|
||||
return ip.String() + "/128"
|
||||
}
|
||||
|
||||
func quote(s string) string {
|
||||
return fmt.Sprintf("'%s'", strings.ReplaceAll(s, "'", "''"))
|
||||
}
|
||||
|
||||
func schemaIdent(s string) string {
|
||||
return `"` + strings.ReplaceAll(s, `"`, `""`) + `"`
|
||||
}
|
||||
@@ -4,16 +4,23 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
|
||||
"geoip-rest/internal/geo"
|
||||
"geoip-rest/internal/importer"
|
||||
)
|
||||
|
||||
const defaultMMDBPath = "/initial_data/GeoLite2-City.mmdb"
|
||||
|
||||
type SyncConfig struct {
|
||||
MySQL MySQLConfig
|
||||
DatabaseURL string
|
||||
Backend Backend
|
||||
MMDBPath string
|
||||
LookupQuery string
|
||||
InitialCSV string
|
||||
UpdateDir string
|
||||
LogDir string
|
||||
@@ -34,6 +41,9 @@ func (c *SyncConfig) defaults() {
|
||||
if c.Schema == "" {
|
||||
c.Schema = DefaultSchema
|
||||
}
|
||||
if c.MMDBPath == "" {
|
||||
c.MMDBPath = defaultMMDBPath
|
||||
}
|
||||
if c.Logger == nil {
|
||||
c.Logger = log.Default()
|
||||
}
|
||||
@@ -90,6 +100,10 @@ func Sync(ctx context.Context, cfg SyncConfig) error {
|
||||
return fmt.Errorf("import updates: %w", err)
|
||||
}
|
||||
|
||||
if err := ensureIPGeoInfo(ctx, cfg, conn); err != nil {
|
||||
cfg.Logger.Printf("ip_geoinfo update warning: %v", err)
|
||||
}
|
||||
|
||||
cfg.Logger.Printf("sync complete (last_id=%d -> %d)", lastID, upperID)
|
||||
|
||||
if err := verifyCounts(ctx, cfg, dumper, conn, upperID); err != nil {
|
||||
@@ -116,3 +130,39 @@ func verifyCounts(ctx context.Context, cfg SyncConfig, dumper *Dumper, conn *pgx
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ensureIPGeoInfo(ctx context.Context, cfg SyncConfig, conn *pgx.Conn) error {
|
||||
if err := EnsureIPGeoInfoTable(ctx, conn, cfg.Schema); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ts := time.Now().In(kst()).Format("20060102-150405")
|
||||
ipListPath := filepath.Join(cfg.UpdateDir, fmt.Sprintf("public_ip_list_%s.csv", ts))
|
||||
if err := ExportPublicIPs(ctx, conn, cfg.Schema, ipListPath); err != nil {
|
||||
return fmt.Errorf("export public ip list: %w", err)
|
||||
}
|
||||
|
||||
resolver, err := ResolveBackend(geo.Config{
|
||||
Backend: geo.Backend(cfg.Backend),
|
||||
MMDBPath: cfg.MMDBPath,
|
||||
DatabaseURL: cfg.DatabaseURL,
|
||||
LookupQuery: cfg.LookupQuery,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("init resolver for ip_geoinfo: %w", err)
|
||||
}
|
||||
defer resolver.Close()
|
||||
|
||||
sqlPath := filepath.Join(cfg.UpdateDir, fmt.Sprintf("ip_geoinfo_update-%s.sql", ts))
|
||||
count, err := GenerateIPGeoInfoSQL(ctx, conn, cfg.Schema, resolver, sqlPath, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("generate ip_geoinfo sql: %w", err)
|
||||
}
|
||||
if count == 0 {
|
||||
return nil
|
||||
}
|
||||
if err := ExecuteSQLFile(ctx, conn, sqlPath); err != nil {
|
||||
return fmt.Errorf("execute ip_geoinfo sql: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
2
to-do.md
2
to-do.md
@@ -20,6 +20,8 @@
|
||||
- [x] 초기 적재+백필+일일 업데이트를 Go 라이브러리(`internal/userprogram`)로 통합, `user-program-sync`가 초기 CSV 임포트 후 최신 일자까지 덤프/적재하도록 리팩토링 완료: 2025-12-10 10:03 KST
|
||||
- [x] 증분 기준을 created_at 날짜에서 PK(id) 기반으로 변경, 마지막 id 이후 어제까지의 최대 id까지 덤프/업서트하도록 Sync/Dump 경로 리팩토링 완료: 2025-12-10 10:20 KST
|
||||
- [x] 컨테이너 사용자 UID/GID를 빌드 시 지정 가능하도록 하고 볼륨 소유권을 맞춰 권한 오류 해결 (`APP_UID`/`APP_GID`, chown 적용) 완료: 2025-12-10 10:56 KST
|
||||
- [x] access log 파일 출력 + 10MB 롤링, 헤더 길이 1KB로 절단 및 프록시 IP 정보 포함 완료: 2025-12-10 12:20 KST
|
||||
- [x] `ip_geoinfo` 테이블 초기/증분 upsert 자동화: sync 완료 후 public_ip 리스트를 CSV로 내보내고 신규 IP만 GeoIP 조회해 SQL 생성·실행하도록 추가 완료: 2025-12-10 12:27 KST
|
||||
|
||||
## 진행 예정
|
||||
- [x] PostgreSQL 전용 Docker 이미지(또는 build 단계)에서 `maxminddb_fdw` 설치 후 `GeoLite2-City.mmdb` 볼륨을 `/data`로 마운트하는 `postgres` 서비스 추가 및 5432 외부 노출
|
||||
|
||||
Reference in New Issue
Block a user