1#!/usr/local/bin/bash
2#
3# Simple shell script to update IP2Location database files
4#
5# For updating non-sample files, credentials are or token is required:
6#  provided by file $HOME/.ip2location
7#   credential-based authentication:
8#    login=EMAIL
9#    password=PASSWORD
10#   token-based authentication:
11#    token=TOKEN
12#
13# Project    : ipv6calc/IP2Location
14# File       : IP2Location-update.sh
15# Version    : $Id: 51d432e406fc84c7f196a92c9037e730e1172131 $
16# Copyright  : 2012-2021 by Peter Bieringer <pb (at) bieringer.de>
17# License    : GNU GPL version 2
18
19# 20150416: remove softlink support, no longer needed
20# 20210528: add support for 'token'
21
22IP2LOCATION_CONFIG=${IP2LOCATION_CONFIG:-"$HOME/.ip2location"}
23
24IP2LOCATION_DAT_DIR_DEFAULT="@IP2LOCATION_DB@"
25[ -z "$IP2LOCATION_DAT_DIR" -a -n "$IPV6CALC_DB_IP2LOCATION_DIR" ] && IP2LOCATION_DAT_DIR="$IPV6CALC_DB_IP2LOCATION_DIR"
26[ -z "$IP2LOCATION_DAT_DIR" ] && IP2LOCATION_DAT_DIR="$IP2LOCATION_DAT_DIR_DEFAULT"
27
28IP2LOCATION_DAT_URL_BASE="https://www.ip2location.com/download?login=@LOGIN@&password=@PASSWORD@&token=@TOKEN@"
29IP2LOCATION_DAT_URL_BASE_SAMPLE="https://www.ip2location.com/downloads"
30IP2LOCATION_DAT_URL_BASE_LITE_FREE="https://download.ip2location.com/lite"
31
32# Format: Proto:DB-Number
33
34# free downloads
35IP2LOCATION_DAT_FILES_LITE_FREE=${IP2LOCATION_DAT_FILES_LITE_FREE:-"IPv4:1 IPv6:1"}
36
37# (free) subscription is required for LITE DB-Number > 1
38IP2LOCATION_DAT_FILES_LITE=${IP2LOCATION_DAT_FILES_LITE:-"IPv4:11 IPv6:11"}
39
40# list of normal (purchased subscription required)
41IP2LOCATION_DAT_FILES="${IP2LOCATION_DAT_FILES}"
42
43# list of recommended SAMPLE
44IP2LOCATION_DAT_FILES_SAMPLE=${IP2LOCATION_DAT_FILES_SAMPLE:-"IPv4:20 IPv6:20 IPv4:24 IPv6:24"}
45
46
47help() {
48	cat <<END
49Usage: $(basename "$0") [-D <dir>] [-n] [-s] [-t] [-v]
50	-D <dir>	database destination directory (optional)
51	-n		no action (dry-run)
52	-s		skip already successfully downloaded files
53	-t		enforce use of 'token' instead of using 'login' & 'password'
54	-v		verbose
55
56	database directory: $IP2LOCATION_DAT_DIR (default: $IP2LOCATION_DAT_DIR_DEFAULT)
57
58	it honors externally defined environment value:
59		prio 1: IP2LOCATION_DAT_DIR
60		prio 2: IPV6CALC_DB_IP2LOCATION_DIR
61
62 this script will download data from ip2location.com
63  into given/set database directory
64
65 Sample databases:
66  IP2LOCATION_DAT_FILES_SAMPLE=$IP2LOCATION_DAT_FILES_SAMPLE
67
68 Lite (free) databases:
69  IP2LOCATION_DAT_FILES_LITE_FREE=$IP2LOCATION_DAT_FILES_LITE_FREE
70
71 With authentication (requires login/password or token in $IP2LOCATION_CONFIG) and a valid subscription
72  IP2LOCATION_DAT_FILES_LITE=$IP2LOCATION_DAT_FILES_LITE
73  IP2LOCATION_DAT_FILES=$IP2LOCATION_DAT_FILES
74
75 Credentials or token must be defined in \$HOME/.ip2location by
76  login=IP2LOCATION-LOGIN       ${login:+found: ${login:0:2}...}
77  password=IP2LOCATION-PASSWORD ${password:+found: ${password:0:2}...}
78  token=IP2LOCATION-TOKEN       ${token:+found: ${token:0:2}...}
79
80 In addition settings from above can be overwritten by setting related variables
81END
82}
83
84# source credentials (must provide login= and password= or token=)
85authenticated=false
86has_token=false
87has_credentials=false
88verbose=false
89
90if [ -f "$IP2LOCATION_CONFIG" ]; then
91	source "$IP2LOCATION_CONFIG" || exit 1
92
93	if [ -n "${token}" ]; then
94		has_token=true
95		authenticated=true
96		echo "INFO  : found token in: $IP2LOCATION_CONFIG (for authenticated downloads)"
97	fi
98
99	if [ -n "${login}" -a -n "${password}" ]; then
100		has_credentials=true
101		authenticated=true
102		echo "INFO  : found credentials in: $IP2LOCATION_CONFIG (for authenticated downloads)"
103	fi
104
105	if ! $authenticated; then
106		echo "NOTICE: missing credentials/token in: $IP2LOCATION_CONFIG (skip authenticated downloads)"
107	fi
108fi
109
110# option parsing
111while getopts "vfsntD:h\?" opt; do
112	case $opt in
113	    D)
114		IP2LOCATION_DAT_DIR=$OPTARG
115		;;
116	    n)
117		NO_ACTION=1
118		;;
119	    s)
120		SKIP_OK=1
121		;;
122	    t)
123		has_credentials=false
124		;;
125	    v)
126		verbose=true
127		;;
128	    *)
129		help
130		exit 1
131		;;
132	esac
133done
134
135
136# directory check
137if [ ! -d "$IP2LOCATION_DAT_DIR" ]; then
138	echo "ERROR : missing directory: $IP2LOCATION_DAT_DIR (check option -D or set IP2LOCATION_DAT_DIR)"
139	exit 1
140fi
141
142if [ ! -w "$IP2LOCATION_DAT_DIR" ]; then
143	echo "ERROR : missing write permissions on directory: $IP2LOCATION_DAT_DIR"
144	exit 1
145fi
146
147# required binary check
148if ! which unzip >/dev/null 2>&1; then
149	echo "ERROR : missing binary: unzip"
150	exit 1
151fi
152
153if ! $authenticated; then
154	echo "NOTICE: IP2Location credentials/token not found, clear IP2LOCATION_DAT_FILES"
155	IP2LOCATION_DAT_FILES=""
156
157	echo "NOTICE: IP2Location credentials/token not found, clear IP2LOCATION_DAT_FILES_LITE"
158	IP2LOCATION_DAT_FILES_LITE=""
159fi
160
161if $has_credentials; then
162	# replace placeholders
163	IP2LOCATION_DAT_URL_BASE=${IP2LOCATION_DAT_URL_BASE//@LOGIN@/$login}
164	IP2LOCATION_DAT_URL_BASE=${IP2LOCATION_DAT_URL_BASE//@PASSWORD@/$password}
165	# clear token parameter
166	IP2LOCATION_DAT_URL_BASE=${IP2LOCATION_DAT_URL_BASE//@TOKEN@/}
167fi
168
169if $has_token; then
170	# replace placeholders
171	IP2LOCATION_DAT_URL_BASE=${IP2LOCATION_DAT_URL_BASE//@TOKEN@/$token}
172	# clear credential parameters
173	IP2LOCATION_DAT_URL_BASE=${IP2LOCATION_DAT_URL_BASE//@LOGIN@/}
174	IP2LOCATION_DAT_URL_BASE=${IP2LOCATION_DAT_URL_BASE//@PASSWORD@/}
175fi
176
177# Download and unpack non-sample files
178for list in IP2LOCATION_DAT_FILES_LITE IP2LOCATION_DAT_FILES IP2LOCATION_DAT_FILES_LITE_FREE IP2LOCATION_DAT_FILES_SAMPLE; do
179	if [ -z "${!list}" ]; then
180		echo "NOTICE: empty list, skip: $list"
181		continue
182	fi
183
184	$verbose && echo "INFO  : download list $list: ${!list}"
185
186	url_base="$IP2LOCATION_DAT_URL_BASE"
187
188	case $list in
189	    *_LITE|*_LITE_FREE)
190		code_suffix="LITEBIN"
191		file_prefix="IP2LOCATION-LITE"
192
193		case $list in
194		    *_LITE_FREE)
195			url_base="$IP2LOCATION_DAT_URL_BASE_LITE_FREE"
196			;;
197		esac
198		;;
199	    *_SAMPLE)
200		url_base="$IP2LOCATION_DAT_URL_BASE_SAMPLE"
201		;;
202	    *)
203		code_suffix="BIN"
204		file_prefix="IP2LOCATION"
205		;;
206	esac
207
208	file_dest="$IP2LOCATION_DAT_DIR/$file"
209
210	if [ "${!list}" = "skip" ]; then
211		echo "NOTICE: skip list (by keyword 'skip'): $list"
212		continue
213	fi
214
215	for item in ${!list}; do
216		proto=${item/:*}
217		number=${item/*:}
218
219		case $list in
220		    *_SAMPLE)
221			case $proto in
222			    IPv4)
223				protoitem=""
224				;;
225			    IPv6)
226				protoitem="6"
227				;;
228			    *)
229				echo "ERROR : unsupported 'proto' in item: $item"
230				exit 1
231				;;
232			esac
233
234			file="sample${protoitem}.bin.db${number}.zip"
235			;;
236		    *)
237			case $proto in
238			    IPv4)
239				code="DB${number}${code_suffix}"
240				file="${file_prefix}-DB${number}.BIN.ZIP"
241				;;
242			    IPv6)
243				code="DB${number}${code_suffix}IPV6"
244				file="${file_prefix}-DB${number}.IPV6.BIN.ZIP"
245				;;
246			    *)
247				echo "ERROR : unsupported 'proto' in item: $item"
248				exit 1
249				;;
250			esac
251
252			;;
253		esac
254
255		case $list in
256		    *_SAMPLE|*_LITE_FREE)
257			url="$url_base/$file"
258			;;
259		    *)
260			url="$url_base&productcode=$code"
261			;;
262		esac
263
264		file_dest="$IP2LOCATION_DAT_DIR/$file"
265
266		if [ "$NO_ACTION" = "1" ]; then
267			if $has_credentials; then
268				echo "NOTICE: download skipped by option: ${url/password=*&/password=**PASS**&} ($file_dest)"
269				continue
270			fi
271			if $has_token; then
272				echo "NOTICE: download skipped by option: ${url/token=*&/token=**TOK**&} ($file_dest)"
273				continue
274			fi
275		fi
276
277		if [ "$SKIP_OK" = "1" ]; then
278			if file "$file_dest" | grep -q "Zip archive data"; then
279				echo "NOTICE: download skipped by option because file already existing and is a ZIP file: $code ($file_dest)"
280
281				file_unzip=$(unzip -l "$file_dest" '*.BIN' | grep "\.BIN$" | awk '{ print $NF }' | head -1)
282
283				if [ -n "$file_unzip" ]; then
284					if [ ! -f "$IP2LOCATION_DAT_DIR/$file_unzip" ]; then
285						unzip -o -d "$IP2LOCATION_DAT_DIR" "$file_dest" '*.BIN'
286						if [ $? -ne 0 ]; then
287							echo "ERROR : unzip of file not successful: $file_dest"
288							continue
289						else
290							echo "INFO  : unzip of file successful: $file_dest"
291						fi
292					else
293						echo "INFO  : skip unzip because unzipped file already existing: $code ($file_dest)"
294					fi
295				fi
296				continue
297			fi
298		fi
299
300		if $has_credentials; then
301			$verbose && echo "INFO  : try to download URL: ${url/password=*&/password=**PASS**&} ($file_dest)"
302		fi
303		if $has_token; then
304			$verbose && echo "INFO  : try to download URL: ${url/token=*&/token=**TOK**&} ($file_dest)"
305		fi
306
307		wget -q -O "$file_dest" "$url"
308		result=$?
309
310		if [ $result -ne 0 ]; then
311			echo "ERROR : download of file not successful: $file_dest ($!)"
312			continue
313		fi
314		$verbose && echo "INFO  : download of file successful: $file_dest"
315
316		if [ ! -s "$file_dest" ]; then
317			echo "ERROR : downloaded file has ZERO size: $file_dest"
318			continue
319		fi
320
321		if ! file "$file_dest" | grep -q "Zip archive data"; then
322			if file "$file_dest" | grep -q "ASCII text"; then
323				echo "ERROR : downloaded file is not a ZIP archive: $file_dest ($(head -1 "$file_dest"))"
324			else
325				echo "ERROR : downloaded file is not a ZIP archive: $file_dest"
326			fi
327			continue
328		fi
329
330		unzip -o -d "$IP2LOCATION_DAT_DIR" "$file_dest" '*.BIN'
331		if [ $? -ne 0 ]; then
332			echo "ERROR : unzip of file not successful: $file_dest"
333			continue
334		fi
335		$verbose && echo "INFO  : unzip of file successful: $file_dest (remove downloaded file now)"
336		rm -f "$file_dest"
337
338		echo "NOTICE: download/unzip successful: $item"
339	done
340done
341
342# Adjust permissions
343if [ "$NO_ACTION" != "1" ]; then
344	chmod 644 $IP2LOCATION_DAT_DIR/*.BIN
345fi
346