diff --git a/modules/net/srv/dap_chain_net_srv_countries.h b/modules/net/srv/dap_chain_net_srv_countries.h
new file mode 100644
index 0000000000000000000000000000000000000000..06d47dd512aef5a463565213847cfab94cb0d0ae
--- /dev/null
+++ b/modules/net/srv/dap_chain_net_srv_countries.h
@@ -0,0 +1,258 @@
+/*
+ * CountryCodes
+ * ISO, ISO3, Country, Continent
+ */
+const char *s_server_countries[] = {
+	"AD", "AND", "Andorra", "EU",
+	"AE", "ARE", "United Arab Emirates", "AS",
+	"AF", "AFG", "Afghanistan", "AS",
+	"AG", "ATG", "Antigua and Barbuda", "NA",
+	"AI", "AIA", "Anguilla", "NA",
+	"AL", "ALB", "Albania", "EU",
+	"AM", "ARM", "Armenia", "AS",
+	"AO", "AGO", "Angola", "AF",
+	"AQ", "ATA", "Antarctica", "AN",
+	"AR", "ARG", "Argentina", "SA",
+	"AS", "ASM", "American Samoa", "OC",
+	"AT", "AUT", "Austria", "EU",
+	"AU", "AUS", "Australia", "OC",
+	"AW", "ABW", "Aruba", "NA",
+	"AX", "ALA", "Aland Islands", "EU",
+	"AZ", "AZE", "Azerbaijan", "AS",
+	"BA", "BIH", "Bosnia and Herzegovina", "EU",
+	"BB", "BRB", "Barbados", "NA",
+	"BD", "BGD", "Bangladesh", "AS",
+	"BE", "BEL", "Belgium", "EU",
+	"BF", "BFA", "Burkina Faso", "AF",
+	"BG", "BGR", "Bulgaria", "EU",
+	"BH", "BHR", "Bahrain", "AS",
+	"BI", "BDI", "Burundi", "AF",
+	"BJ", "BEN", "Benin", "AF",
+	"BL", "BLM", "Saint Barthelemy", "NA",
+	"BM", "BMU", "Bermuda", "NA",
+	"BN", "BRN", "Brunei", "AS",
+	"BO", "BOL", "Bolivia", "SA",
+	"BQ", "BES", "Bonaire", "NA",
+	"BR", "BRA", "Brazil", "SA",
+	"BS", "BHS", "Bahamas", "NA",
+	"BT", "BTN", "Bhutan", "AS",
+	"BV", "BVT", "Bouvet Island", "AN",
+	"BW", "BWA", "Botswana", "AF",
+	"BY", "BLR", "Belarus", "EU",
+	"BZ", "BLZ", "Belize", "NA",
+	"CA", "CAN", "Canada", "NA",
+	"CC", "CCK", "Cocos Islands", "AS",
+	"CD", "COD", "Democratic Republic of the Congo", "AF",
+	"CF", "CAF", "Central African Republic", "AF",
+	"CG", "COG", "Republic of the Congo", "AF",
+	"CH", "CHE", "Switzerland", "EU",
+	"CI", "CIV", "Ivory Coast", "AF",
+	"CK", "COK", "Cook Islands", "OC",
+	"CL", "CHL", "Chile", "SA",
+	"CM", "CMR", "Cameroon", "AF",
+	"CN", "CHN", "China", "AS",
+	"CO", "COL", "Colombia", "SA",
+	"CR", "CRI", "Costa Rica", "NA",
+	"CU", "CUB", "Cuba", "NA",
+	"CV", "CPV", "Cabo Verde", "AF",
+	"CW", "CUW", "Curacao", "NA",
+	"CX", "CXR", "Christmas Island", "OC",
+	"CY", "CYP", "Cyprus", "EU",
+	"CZ", "CZE", "Czechia", "EU",
+	"DE", "DEU", "Germany", "EU",
+	"DJ", "DJI", "Djibouti", "AF",
+	"DK", "DNK", "Denmark", "EU",
+	"DM", "DMA", "Dominica", "NA",
+	"DO", "DOM", "Dominican Republic", "NA",
+	"DZ", "DZA", "Algeria", "AF",
+	"EC", "ECU", "Ecuador", "SA",
+	"EE", "EST", "Estonia", "EU",
+	"EG", "EGY", "Egypt", "AF",
+	"EH", "ESH", "Western Sahara", "AF",
+	"ER", "ERI", "Eritrea", "AF",
+	"ES", "ESP", "Spain", "EU",
+	"ET", "ETH", "Ethiopia", "AF",
+	"FI", "FIN", "Finland", "EU",
+	"FJ", "FJI", "Fiji", "OC",
+	"FK", "FLK", "Falkland Islands", "SA",
+	"FM", "FSM", "Micronesia", "OC",
+	"FO", "FRO", "Faroe Islands", "EU",
+	"FR", "FRA", "France", "EU",
+	"GA", "GAB", "Gabon", "AF",
+	"GB", "GBR", "United Kingdom", "EU",
+	"GD", "GRD", "Grenada", "NA",
+	"GE", "GEO", "Georgia", "AS",
+	"GF", "GUF", "French Guiana", "SA",
+	"GG", "GGY", "Guernsey", "EU",
+	"GH", "GHA", "Ghana", "AF",
+	"GI", "GIB", "Gibraltar", "EU",
+	"GL", "GRL", "Greenland", "NA",
+	"GM", "GMB", "Gambia", "AF",
+	"GN", "GIN", "Guinea", "AF",
+	"GP", "GLP", "Guadeloupe", "NA",
+	"GQ", "GNQ", "Equatorial Guinea", "AF",
+	"GR", "GRC", "Greece", "EU",
+	"GS", "SGS", "South Georgia and the South Sandwich Islands", "AN",
+	"GT", "GTM", "Guatemala", "NA",
+	"GU", "GUM", "Guam", "OC",
+	"GW", "GNB", "Guinea-Bissau", "AF",
+	"GY", "GUY", "Guyana", "SA",
+	"HK", "HKG", "Hong Kong", "AS",
+	"HM", "HMD", "Heard Island and McDonald Islands", "AN",
+	"HN", "HND", "Honduras", "NA",
+	"HR", "HRV", "Croatia", "EU",
+	"HT", "HTI", "Haiti", "NA",
+	"HU", "HUN", "Hungary", "EU",
+	"ID", "IDN", "Indonesia", "AS",
+	"IE", "IRL", "Ireland", "EU",
+	"IL", "ISR", "Israel", "AS",
+	"IM", "IMN", "Isle of Man", "EU",
+	"IN", "IND", "India", "AS",
+	"IO", "IOT", "British Indian Ocean Territory", "AS",
+	"IQ", "IRQ", "Iraq", "AS",
+	"IR", "IRN", "Iran", "AS",
+	"IS", "ISL", "Iceland", "EU",
+	"IT", "ITA", "Italy", "EU",
+	"JE", "JEY", "Jersey", "EU",
+	"JM", "JAM", "Jamaica", "NA",
+	"JO", "JOR", "Jordan", "AS",
+	"JP", "JPN", "Japan", "AS",
+	"KE", "KEN", "Kenya", "AF",
+	"KG", "KGZ", "Kyrgyzstan", "AS",
+	"KH", "KHM", "Cambodia", "AS",
+	"KI", "KIR", "Kiribati", "OC",
+	"KM", "COM", "Comoros", "AF",
+	"KN", "KNA", "Saint Kitts and Nevis", "NA",
+	"KP", "PRK", "North Korea", "AS",
+	"KR", "KOR", "South Korea", "AS",
+	"XK", "XKX", "Kosovo", "EU",
+	"KW", "KWT", "Kuwait", "AS",
+	"KY", "CYM", "Cayman Islands", "NA",
+	"KZ", "KAZ", "Kazakhstan", "AS",
+	"LA", "LAO", "Laos", "AS",
+	"LB", "LBN", "Lebanon", "AS",
+	"LC", "LCA", "Saint Lucia", "NA",
+	"LI", "LIE", "Liechtenstein", "EU",
+	"LK", "LKA", "Sri Lanka", "AS",
+	"LR", "LBR", "Liberia", "AF",
+	"LS", "LSO", "Lesotho", "AF",
+	"LT", "LTU", "Lithuania", "EU",
+	"LU", "LUX", "Luxembourg", "EU",
+	"LV", "LVA", "Latvia", "EU",
+	"LY", "LBY", "Libya", "AF",
+	"MA", "MAR", "Morocco", "AF",
+	"MC", "MCO", "Monaco", "EU",
+	"MD", "MDA", "Moldova", "EU",
+	"ME", "MNE", "Montenegro", "EU",
+	"MF", "MAF", "Saint Martin", "NA",
+	"MG", "MDG", "Madagascar", "AF",
+	"MH", "MHL", "Marshall Islands", "OC",
+	"MK", "MKD", "North Macedonia", "EU",
+	"ML", "MLI", "Mali", "AF",
+	"MM", "MMR", "Myanmar", "AS",
+	"MN", "MNG", "Mongolia", "AS",
+	"MO", "MAC", "Macao", "AS",
+	"MP", "MNP", "Northern Mariana Islands", "OC",
+	"MQ", "MTQ", "Martinique", "NA",
+	"MR", "MRT", "Mauritania", "AF",
+	"MS", "MSR", "Montserrat", "NA",
+	"MT", "MLT", "Malta", "EU",
+	"MU", "MUS", "Mauritius", "AF",
+	"MV", "MDV", "Maldives", "AS",
+	"MW", "MWI", "Malawi", "AF",
+	"MX", "MEX", "Mexico", "NA",
+	"MY", "MYS", "Malaysia", "AS",
+	"MZ", "MOZ", "Mozambique", "AF",
+	"NA", "NAM", "Namibia", "AF",
+	"NC", "NCL", "New Caledonia", "OC",
+	"NE", "NER", "Niger", "AF",
+	"NF", "NFK", "Norfolk Island", "OC",
+	"NG", "NGA", "Nigeria", "AF",
+	"NI", "NIC", "Nicaragua", "NA",
+	"NL", "NLD", "Netherlands", "EU",
+	"NO", "NOR", "Norway", "EU",
+	"NP", "NPL", "Nepal", "AS",
+	"NR", "NRU", "Nauru", "OC",
+	"NU", "NIU", "Niue", "OC",
+	"NZ", "NZL", "New Zealand", "OC",
+	"OM", "OMN", "Oman", "AS",
+	"PA", "PAN", "Panama", "NA",
+	"PE", "PER", "Peru", "SA",
+	"PF", "PYF", "French Polynesia", "OC",
+	"PG", "PNG", "Papua New Guinea", "OC",
+	"PH", "PHL", "Philippines", "AS",
+	"PK", "PAK", "Pakistan", "AS",
+	"PL", "POL", "Poland", "EU",
+	"PM", "SPM", "Saint Pierre and Miquelon", "NA",
+	"PN", "PCN", "Pitcairn", "OC",
+	"PR", "PRI", "Puerto Rico", "NA",
+	"PS", "PSE", "Palestinian Territory", "AS",
+	"PT", "PRT", "Portugal", "EU",
+	"PW", "PLW", "Palau", "OC",
+	"PY", "PRY", "Paraguay", "SA",
+	"QA", "QAT", "Qatar", "AS",
+	"RE", "REU", "Reunion", "AF",
+	"RO", "ROU", "Romania", "EU",
+	"RS", "SRB", "Serbia", "EU",
+	"RU", "RUS", "Russia", "EU",
+	"RW", "RWA", "Rwanda", "AF",
+	"SA", "SAU", "Saudi Arabia", "AS",
+	"SB", "SLB", "Solomon Islands", "OC",
+	"SC", "SYC", "Seychelles", "AF",
+	"SD", "SDN", "Sudan", "AF",
+	"SS", "SSD", "South Sudan", "AF",
+	"SE", "SWE", "Sweden", "EU",
+	"SG", "SGP", "Singapore", "AS",
+	"SH", "SHN", "Saint Helena", "AF",
+	"SI", "SVN", "Slovenia", "EU",
+	"SJ", "SJM", "Svalbard and Jan Mayen", "EU",
+	"SK", "SVK", "Slovakia", "EU",
+	"SL", "SLE", "Sierra Leone", "AF",
+	"SM", "SMR", "San Marino", "EU",
+	"SN", "SEN", "Senegal", "AF",
+	"SO", "SOM", "Somalia", "AF",
+	"SR", "SUR", "Suriname", "SA",
+	"ST", "STP", "Sao Tome and Principe", "AF",
+	"SV", "SLV", "El Salvador", "NA",
+	"SX", "SXM", "Sint Maarten", "NA",
+	"SY", "SYR", "Syria", "AS",
+	"SZ", "SWZ", "Eswatini", "AF",
+	"TC", "TCA", "Turks and Caicos Islands", "NA",
+	"TD", "TCD", "Chad", "AF",
+	"TF", "ATF", "French Southern Territories", "AN",
+	"TG", "TGO", "Togo", "AF",
+	"TH", "THA", "Thailand", "AS",
+	"TJ", "TJK", "Tajikistan", "AS",
+	"TK", "TKL", "Tokelau", "OC",
+	"TL", "TLS", "Timor Leste", "OC",
+	"TM", "TKM", "Turkmenistan", "AS",
+	"TN", "TUN", "Tunisia", "AF",
+	"TO", "TON", "Tonga", "OC",
+	"TR", "TUR", "Turkey", "AS",
+	"TT", "TTO", "Trinidad and Tobago", "NA",
+	"TV", "TUV", "Tuvalu", "OC",
+	"TW", "TWN", "Taiwan", "AS",
+	"TZ", "TZA", "Tanzania", "AF",
+	"UA", "UKR", "Ukraine", "EU",
+	"UG", "UGA", "Uganda", "AF",
+	"UM", "UMI", "United States Minor Outlying Islands", "OC",
+	"US", "USA", "United States", "NA",
+	"UY", "URY", "Uruguay", "SA",
+	"UZ", "UZB", "Uzbekistan", "AS",
+	"VA", "VAT", "Vatican", "EU",
+	"VC", "VCT", "Saint Vincent and the Grenadines", "NA",
+	"VE", "VEN", "Venezuela", "SA",
+	"VG", "VGB", "British Virgin Islands", "NA",
+	"VI", "VIR", "U.S. Virgin Islands", "NA",
+	"VN", "VNM", "Vietnam", "AS",
+	"VU", "VUT", "Vanuatu", "OC",
+	"WF", "WLF", "Wallis and Futuna", "OC",
+	"WS", "WSM", "Samoa", "OC",
+	"YE", "YEM", "Yemen", "AS",
+	"YT", "MYT", "Mayotte", "AF",
+	"ZA", "ZAF", "South Africa", "AF",
+	"ZM", "ZMB", "Zambia", "AF",
+	"ZW", "ZWE", "Zimbabwe", "AF",
+	"CS", "SCG", "Serbia and Montenegro", "EU",
+	"AN", "ANT", "Netherlands Antilles", "NA"
+};
diff --git a/modules/net/srv/dap_chain_net_srv_geoip.c b/modules/net/srv/dap_chain_net_srv_geoip.c
index 2c52b92d4d8f9bda53589c5e8ef4b96232e2f6b4..a0f1a31b0b300f7c9d755fda8a7057b377f1c7f2 100644
--- a/modules/net/srv/dap_chain_net_srv_geoip.c
+++ b/modules/net/srv/dap_chain_net_srv_geoip.c
@@ -35,6 +35,7 @@
 #include "libmaxminddb/maxminddb.h"
 
 #define LOG_TAG "chain_net_srv_geoip"
+#define LOCALE_DEFAULT  "en"
 
 /**
  * @brief m_request_response
@@ -45,18 +46,19 @@
 static void m_request_getip_response(void * a_response, size_t a_response_size, void * a_obj)
 {
     char *l_addr = (char *) a_obj;
-    printf("m_request_getip_response %s\n", a_response);
+    //printf("m_request_getip_response %s\n", a_response);
 }
 
 static void m_request_getip_request_error(int a_err_code, void *a_obj)
 {
     char *l_addr = (char *) a_obj;
-    printf("m_request_getip_request_error %s\n", l_addr);
+    //printf("m_request_getip_request_error %s\n", l_addr);
 }
 
 geoip_info_t *chain_net_geoip_get_ip_info_by_web(const char *a_ip_str)
 {
-    // https://geoip.maxmind.com/geoip/v2.1/insights/%s
+    // https://geoip.maxmind.com/geoip/v2.1/insights/<ip>
+	// https://geoip.maxmind.com/geoip/v2.1/city/<ip>
     char *l_path = dap_strdup_printf("/geoip/v2.1/insights/%s", a_ip_str);
     //104.16.38.47:443
     // geoip.maxmind.com
@@ -67,17 +69,105 @@ geoip_info_t *chain_net_geoip_get_ip_info_by_web(const char *a_ip_str)
     const char *user_id = "288651";
     const char *license_key = "1JGvRmd3Ux1kcBkb";
     char *l_auth = dap_strdup_printf("%s:%s", user_id, license_key);
-    size_t l_out_len = dap_enc_base64_encode(l_auth, strlen(l_auth), &l_out, DAP_ENC_DATA_TYPE_B64);
+    size_t l_out_len = dap_enc_base64_encode(l_auth, strlen(l_auth), l_out, DAP_ENC_DATA_TYPE_B64);
     char * l_custom = l_out_len > 0 ? dap_strdup_printf("Authorization: Basic %s", l_out) : NULL;
     size_t l_custom_count = 1;
-    // todo
+    // todo just need to finish up https request
     dap_client_http_request_custom("geoip.maxmind.com", 443, "GET", "application/json", l_path, NULL,
-            0, NULL, m_request_getip_response, m_request_getip_request_error, NULL, l_custom, l_custom_count);
-    return NULL ;
+            0, NULL, m_request_getip_response, m_request_getip_request_error, NULL, &l_custom, l_custom_count);
+    return NULL;
 }
 
-geoip_info_t *chain_net_geoip_get_ip_info_by_local_db(const char *a_ip_str)
+/*
+ * Get value from mmdb by 2 strings
+ */
+static int mmdb_get_value_double2(MMDB_lookup_result_s *a_result, const char *a_one, const char *a_two, double *a_out_double)
+{
+	if (!a_out_double || !a_result || !a_result->found_entry)
+		return -1;
+	MMDB_entry_data_s entry_data;
+	int l_status = MMDB_get_value(&a_result->entry, &entry_data, a_one, a_two, NULL);
+	if (MMDB_SUCCESS != l_status) {
+		log_it(L_DEBUG, "False get_value [%s->%s] with errcode=%d", a_one, a_two, l_status);
+		return -2;
+	}
+	if (entry_data.has_data) {
+		if (a_out_double && entry_data.type == MMDB_DATA_TYPE_DOUBLE) {
+			//memcpy(a_out_double, &entry_data.double_value, entry_data.data_size);
+			*a_out_double = entry_data.double_value;
+		} else
+			log_it(L_DEBUG,
+					"error value [%s->%s] has size=%d(>0) type=%d(%d)",
+					a_one, a_two, entry_data.data_size,
+					entry_data.type, MMDB_DATA_TYPE_DOUBLE);
+	}
+	else
+		return -3;
+	return 0;
+}
+
+/*
+ * Get value from mmdb by 2 strings
+ */
+static int mmdb_get_value_str2(MMDB_lookup_result_s *a_result, const char *a_one, const char *a_two, char *a_out_str, size_t a_out_str_size)
+{
+	if (!a_out_str || !a_result || !a_result->found_entry)
+		return -1;
+	MMDB_entry_data_s entry_data;
+	int l_status = MMDB_get_value(&a_result->entry, &entry_data, a_one, a_two, NULL);
+	if (MMDB_SUCCESS != l_status) {
+		log_it(L_DEBUG, "False get_value [%s->%s] with errcode=%d", a_one, a_two, l_status);
+		return -2;
+	}
+	if (entry_data.has_data) {
+		if (entry_data.data_size > 0 && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
+			size_t l_size = min(a_out_str_size-1, entry_data.data_size);
+			strncpy(a_out_str, entry_data.utf8_string, l_size);
+			a_out_str[l_size] = 0;
+		} else
+			log_it(L_DEBUG,
+					"error value [%s->%s] has size=%d(>0) type=%d(%d)",
+					a_one, a_two, entry_data.data_size,
+					entry_data.type, MMDB_DATA_TYPE_UTF8_STRING);
+	}
+	else
+		return -3;
+	return 0;
+}
+
+/*
+ * Get value from mmdb by 3 strings
+ */
+static int mmdb_get_value_str3(MMDB_lookup_result_s *a_result, const char *a_one, const char *a_two, const char *a_three, char *a_out_str, size_t a_out_str_size)
+{
+	if (!a_out_str || !a_result || !a_result->found_entry)
+		return -1;
+	MMDB_entry_data_s entry_data;
+	int l_status = MMDB_get_value(&a_result->entry, &entry_data, a_one, a_two, a_three, NULL);
+	if (MMDB_SUCCESS != l_status) {
+		log_it(L_DEBUG, "False get_value [%s->%s->%s] with errcode=%d", a_one, a_two, a_three, l_status);
+		return -2;
+	}
+	if (entry_data.has_data) {
+		if (entry_data.data_size > 0 && entry_data.type == MMDB_DATA_TYPE_UTF8_STRING) {
+			size_t l_size = min(a_out_str_size-1, entry_data.data_size);
+			strncpy(a_out_str, entry_data.utf8_string, l_size);
+			a_out_str[l_size] = 0;
+		} else
+			log_it(L_DEBUG,
+					"error value [%s->%s->%s] has size=%d(>0) type=%d(%d)",
+					a_one, a_two, a_three, entry_data.data_size,
+					entry_data.type, MMDB_DATA_TYPE_UTF8_STRING);
+	}
+	else
+		return -3;
+	return 0;
+}
+
+geoip_info_t *chain_net_geoip_get_ip_info_by_local_db(const char *a_ip_str, const char *a_locale)
 {
+	// https://geoip.maxmind.com/geoip/v2.1/city/178.7.88.55
+	// https://maxmind.github.io/libmaxminddb/
     char *l_file_db_name = dap_strdup_printf("%s/share/geoip/GeoLite2-City.mmdb", g_sys_dir_path);
     if(!dap_file_test(l_file_db_name)) {
         DAP_DELETE(l_file_db_name);
@@ -91,30 +181,74 @@ geoip_info_t *chain_net_geoip_get_ip_info_by_local_db(const char *a_ip_str)
     }
     DAP_DELETE(l_file_db_name);
 
-    int gai_error, mmdb_error;
-    MMDB_lookup_result_s result =
-            MMDB_lookup_string(&mmdb, a_ip_str, &gai_error, &mmdb_error);
-    if(0 != gai_error || MMDB_SUCCESS != mmdb_error) {
-        log_it(L_WARNING, "no lookup ip=%s with errcode=%d", a_ip_str, l_status);
-    }
+	geoip_info_t *l_ret = DAP_NEW_Z(geoip_info_t);
 
-    if(result.found_entry) {
-        MMDB_entry_data_s entry_data;
-        l_status = MMDB_get_value(&result.entry, &entry_data, "names", "en", NULL);
-        if(MMDB_SUCCESS != l_status) {
-            log_it(L_DEBUG, "no get_value with errcode=%d", l_status);
-        }
-        if(entry_data.has_data) {
-            ;
-        }
-    }
+	int gai_error, mmdb_error;
+	MMDB_lookup_result_s result = MMDB_lookup_string(&mmdb, a_ip_str, &gai_error, &mmdb_error);
+	if (0 != gai_error || MMDB_SUCCESS != mmdb_error) {
+		log_it(L_WARNING, "no lookup ip=%s with errcode=%d", a_ip_str, l_status);
+	}
+
+	// continent
+	if (mmdb_get_value_str3(&result, "continent", "names", a_locale, l_ret->continent, sizeof(l_ret->continent))) {
+		if (mmdb_get_value_str3(&result, "continent", "names", LOCALE_DEFAULT, l_ret->continent, sizeof(l_ret->continent))) {
+			MMDB_close(&mmdb);
+			DAP_FREE(l_ret);
+			return NULL;
+		}
+	}
+	// country
+	if (mmdb_get_value_str3(&result, "country", "names", a_locale, l_ret->country_name, sizeof(l_ret->country_name))) {
+		if (mmdb_get_value_str3(&result, "country", "names", LOCALE_DEFAULT, l_ret->country_name, sizeof(l_ret->country_name))) {
+			MMDB_close(&mmdb);
+			DAP_FREE(l_ret);
+			return NULL;
+		}
+	}
+	// all the country names http://download.geonames.org/export/dump/countryInfo.txt
+	if (mmdb_get_value_str2(&result, "country", "iso_code", l_ret->country_code, sizeof(l_ret->country_code))) {
+		MMDB_close(&mmdb);
+		DAP_FREE(l_ret);
+		return NULL;
+	}
+	// city
+	/*if (mmdb_get_value_str3(&result, "city", "names", a_locale, l_ret->city_name, sizeof(l_ret->city_name))) {
+		if (mmdb_get_value_str3(&result, "city", "names", LOCALE_DEFAULT, l_ret->city_name, sizeof(l_ret->city_name))) {
+			MMDB_close(&mmdb);
+			DAP_FREE(l_ret);
+			return NULL;
+		}
+	}*/
+
+	//location
+	if (mmdb_get_value_double2(&result, "location", "latitude", &l_ret->latitude)) {
+		MMDB_close(&mmdb);
+		DAP_FREE(l_ret);
+		return NULL;
+	}
+	if (mmdb_get_value_double2(&result, "location", "longitude", &l_ret->longitude)) {
+		MMDB_close(&mmdb);
+		DAP_FREE(l_ret);
+		return NULL;
+	}
+
+	// IP
+	/*if (mmdb_get_value_str2(&result, "traits", "ip_address", l_ret->ip_str, sizeof(l_ret->ip_str))) {
+		MMDB_close(&mmdb);
+		DAP_FREE(l_ret);
+		return NULL;
+	}*/
+	int a = sizeof(l_ret->ip_str);
+	size_t l_size = min(dap_strlen(a_ip_str), sizeof(l_ret->ip_str));
+	l_ret->ip_str[l_size] = 0;
+	strncpy(l_ret->ip_str, a_ip_str, l_size);
 
-    MMDB_close(&mmdb);
-    return NULL ;
+	MMDB_close(&mmdb);
+	return l_ret;
 }
 
 geoip_info_t *chain_net_geoip_get_ip_info(const char *a_ip_str)
 {
-    return chain_net_geoip_get_ip_info_by_local_db(a_ip_str);
+    return chain_net_geoip_get_ip_info_by_local_db(a_ip_str, "en");
     //return chain_net_geoip_get_ip_info_by_web(a_ip_str);
 }
diff --git a/modules/net/srv/dap_chain_net_srv_geoip.h b/modules/net/srv/dap_chain_net_srv_geoip.h
index d7b6ba5f858623c956d6e26f0835ce8ab21c1a62..714dbc62f243ff722285a3633aaaf04324787352 100644
--- a/modules/net/srv/dap_chain_net_srv_geoip.h
+++ b/modules/net/srv/dap_chain_net_srv_geoip.h
@@ -24,7 +24,13 @@
 
 typedef struct geoip_info {
 
-    char *ip_str;
+    char ip_str[20];
+    char continent[60];
+    char country_name[64];
+    char country_code[3];// iso_code, all the country names http://download.geonames.org/export/dump/countryInfo.txt
+    char city_name[64];
+    double latitude;
+    double longitude;
 
 } geoip_info_t;
 
diff --git a/modules/net/srv/dap_chain_net_srv_order.c b/modules/net/srv/dap_chain_net_srv_order.c
index 104424e56a1842fd67c42f38aa0cd2ed3c938951..81c490d689347d6ec19f76c970a27a76edd3f3b6 100644
--- a/modules/net/srv/dap_chain_net_srv_order.c
+++ b/modules/net/srv/dap_chain_net_srv_order.c
@@ -22,13 +22,28 @@
  along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <stdio.h>
+#include <strings.h>
+
 #include "dap_chain_net_srv_order.h"
 
 #include "dap_hash.h"
 #include "dap_chain_global_db.h"
+#include "dap_chain_net_srv_countries.h"
+//#include "dap_chain_net_srv_geoip.h"
 
 #define LOG_TAG "dap_chain_net_srv_order"
 
+/*
+Continent codes :
+AF : Africa			geonameId=6255146
+AS : Asia			geonameId=6255147
+EU : Europe			geonameId=6255148
+NA : North America		geonameId=6255149
+OC : Oceania			geonameId=6255151
+SA : South America		geonameId=6255150
+AN : Antarctica			geonameId=6255152
+ */
 char *s_server_continents[]={
         "None",
         "Africa",
@@ -36,7 +51,10 @@ char *s_server_continents[]={
         "North America",
         "South America",
         "Southeast Asia",
-        "Near East",
+		"Asia",
+        //"Near East",
+		"Oceania",
+		"Antarctica"
  };
 
 /**
@@ -46,6 +64,7 @@ char *s_server_continents[]={
 int dap_chain_net_srv_order_init(void)
 {
 
+	//geoip_info_t *l_ipinfo = chain_net_geoip_get_ip_info("8.8.8.8");
     return 0;
 }
 
@@ -112,8 +131,7 @@ bool dap_chain_net_srv_order_get_continent_region(dap_chain_net_srv_order_t *a_o
            memcpy(a_continent_num, a_order->ext + 1, sizeof(uint8_t));
         else
            a_continent_num = 0;
-    }else
-        a_continent_num = 0;
+    }
     if(a_region) {
         size_t l_size = a_order->ext_size - sizeof(uint8_t) - 1;
         if(l_size > 0) {
@@ -126,6 +144,26 @@ bool dap_chain_net_srv_order_get_continent_region(dap_chain_net_srv_order_t *a_o
     return true;
 }
 
+/**
+ * @brief dap_chain_net_srv_order_get_country_code
+ * @param a_order
+ */
+const char* dap_chain_net_srv_order_get_country_code(dap_chain_net_srv_order_t *a_order)
+{
+	char *l_region = NULL;
+	if (!dap_chain_net_srv_order_get_continent_region(a_order, NULL, &l_region))
+		return NULL;
+	int l_countries = sizeof(s_server_countries)/sizeof(char*);
+	for (int i = 0; i < l_countries; i+=4) {
+		if(l_region && (!strcasecmp(l_region, s_server_countries[i+1]) || !strcasecmp(l_region, s_server_countries[i+2]))){
+			const char *l_country_code = s_server_countries[i];
+			DAP_DELETE(l_region);
+			return l_country_code;
+		}
+	}
+	DAP_DELETE(l_region);
+	return NULL;
+}
 
 /**
  * @brief dap_chain_net_srv_order_continents_count
diff --git a/modules/net/srv/include/dap_chain_net_srv_order.h b/modules/net/srv/include/dap_chain_net_srv_order.h
index 3aa88fd18145045a68c158a1edd97bd760588f22..d99377fcbf8935a2601800a3915bee50b0d8a8c5 100644
--- a/modules/net/srv/include/dap_chain_net_srv_order.h
+++ b/modules/net/srv/include/dap_chain_net_srv_order.h
@@ -57,6 +57,7 @@ size_t dap_chain_net_srv_order_get_size(dap_chain_net_srv_order_t *a_order);
 bool dap_chain_net_srv_order_set_continent_region(dap_chain_net_srv_order_t **a_order, uint8_t a_continent_num, const char *a_region);
 bool dap_chain_net_srv_order_get_continent_region(dap_chain_net_srv_order_t *a_order, uint8_t *a_continent_num, char **a_region);
 
+const char* dap_chain_net_srv_order_get_country_code(dap_chain_net_srv_order_t *a_order);
 size_t dap_chain_net_srv_order_continents_count(void);
 const char* dap_chain_net_srv_order_continent_to_str(int8_t a_num);
 int8_t dap_chain_net_srv_order_continent_to_num(const char *l_continent_str);
diff --git a/modules/service/vpn/dap_chain_net_srv_vpn_cdb_server_list.c b/modules/service/vpn/dap_chain_net_srv_vpn_cdb_server_list.c
index 571383aba425ba26a6097826dca39a1b6f73f2c1..0e883881a18d8f59badd0434f82d1ea5ae67b3a4 100644
--- a/modules/service/vpn/dap_chain_net_srv_vpn_cdb_server_list.c
+++ b/modules/service/vpn/dap_chain_net_srv_vpn_cdb_server_list.c
@@ -27,6 +27,7 @@
 #include <time.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdint.h>
 #include <string.h>
 #include <unistd.h>
 
@@ -43,6 +44,7 @@
 #include "dap_chain_net_srv.h"
 #include "dap_chain_net_srv_vpn.h"
 #include "dap_chain_net_srv_order.h"
+#include "dap_chain_net_srv_geoip.h"
 
 #include "dap_http.h"
 #include "dap_http_simple.h"
@@ -154,6 +156,9 @@ static void s_http_simple_proc(dap_http_simple_t *a_http_simple, void *a_arg)
     dap_string_t *l_reply_str = dap_string_new("[\n");
 
 
+    char *l_client_ip = a_http_simple->http->client->s_ip;//"77.222.110.44"
+    geoip_info_t *l_geoip_info = chain_net_geoip_get_ip_info(l_client_ip);
+
     log_it(L_DEBUG, "Have %zd chain networks for cdb lists", s_cdb_net_count );
 
     for ( size_t i = 0; i < s_cdb_net_count ; i++ ) {
@@ -225,21 +230,47 @@ static void s_http_simple_proc(dap_http_simple_t *a_http_simple, void *a_arg)
                 }
             }
 
-            // random node
-            int l_count = 0;
-            while(l_orders_num > 0) {
-                // first random node
-                size_t k = rand() % l_orders_num;
-                dap_chain_net_srv_order_t *l_order = l_orders_pos[k];
-                if(!order_info_print(l_reply_str, l_net, l_order, "Auto", -1)){
-                    dap_string_append_printf(l_reply_str, ",\n");
-                    break;
-                }
-                if (l_count>20)
-                    break;
-                l_count++;
+            int8_t l_client_continent = dap_chain_net_srv_order_continent_to_num(l_geoip_info->continent);
+            // random node on client's continent
+			if (l_client_continent) {
+				int l_count = 0;
+				while (l_orders_num > 0) {
+					size_t k = rand() % l_continents_numbers[l_client_continent];
+					dap_chain_net_srv_order_t *l_order = l_orders_pos[k];
+					const char *country_code = dap_chain_net_srv_order_get_country_code(l_order);
+					if (country_code) {
+						// only for other countries
+						if (dap_strcmp(l_geoip_info->country_code, country_code)){
+							if (!order_info_print(l_reply_str, l_net, l_order, "Auto", -1)) {
+								dap_string_append_printf(l_reply_str, ",\n");
+								break;
+							}
+						}
+					}
+					if (l_count > 20)
+						break;
+					l_count++;
+				}
+
+			}
+			// random node for the whole world
+			else {
+				int l_count = 0;
+				while(l_orders_num > 0) {
+					// first random node
+					size_t k = rand() % l_orders_num;
+					dap_chain_net_srv_order_t *l_order = l_orders_pos[k];
+					if(!order_info_print(l_reply_str, l_net, l_order, "Auto", -1)){
+						dap_string_append_printf(l_reply_str, ",\n");
+						break;
+					}
+					if (l_count>20)
+						break;
+					l_count++;
+				}
             }
             // random nodes for continents
+            int l_count = 0;
             for(size_t l_c = 0; l_c < l_continents_count; l_c++) {
                 while(l_continents_numbers[l_c] > 0) {
                     // random node for continent
@@ -290,6 +321,7 @@ static void s_http_simple_proc(dap_http_simple_t *a_http_simple, void *a_arg)
             }
         }
     }
+    DAP_DELETE(l_geoip_info);
     dap_string_append_printf( l_reply_str, "]\n\n");
     dap_http_simple_reply( a_http_simple, l_reply_str->str, l_reply_str->len );
     dap_string_free(l_reply_str, true);