ip2location.go 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139
  1. // This ip2location package provides a fast lookup of country, region, city, latitude, longitude, ZIP code, time zone,
  2. // ISP, domain name, connection type, IDD code, area code, weather station code, station name, MCC, MNC,
  3. // mobile brand, elevation, and usage type from IP address by using IP2Location database.
  4. package ip2location
  5. import (
  6. "bytes"
  7. "encoding/binary"
  8. "fmt"
  9. "math"
  10. "math/big"
  11. "net"
  12. "os"
  13. "strconv"
  14. )
  15. type ip2locationmeta struct {
  16. databasetype uint8
  17. databasecolumn uint8
  18. databaseday uint8
  19. databasemonth uint8
  20. databaseyear uint8
  21. ipv4databasecount uint32
  22. ipv4databaseaddr uint32
  23. ipv6databasecount uint32
  24. ipv6databaseaddr uint32
  25. ipv4indexbaseaddr uint32
  26. ipv6indexbaseaddr uint32
  27. ipv4columnsize uint32
  28. ipv6columnsize uint32
  29. }
  30. // The IP2Locationrecord struct stores all of the available
  31. // geolocation info found in the IP2Location database.
  32. type IP2Locationrecord struct {
  33. Country_short string
  34. Country_long string
  35. Region string
  36. City string
  37. Isp string
  38. Latitude float32
  39. Longitude float32
  40. Domain string
  41. Zipcode string
  42. Timezone string
  43. Netspeed string
  44. Iddcode string
  45. Areacode string
  46. Weatherstationcode string
  47. Weatherstationname string
  48. Mcc string
  49. Mnc string
  50. Mobilebrand string
  51. Elevation float32
  52. Usagetype string
  53. }
  54. type DB struct {
  55. f *os.File
  56. meta ip2locationmeta
  57. country_position_offset uint32
  58. region_position_offset uint32
  59. city_position_offset uint32
  60. isp_position_offset uint32
  61. domain_position_offset uint32
  62. zipcode_position_offset uint32
  63. latitude_position_offset uint32
  64. longitude_position_offset uint32
  65. timezone_position_offset uint32
  66. netspeed_position_offset uint32
  67. iddcode_position_offset uint32
  68. areacode_position_offset uint32
  69. weatherstationcode_position_offset uint32
  70. weatherstationname_position_offset uint32
  71. mcc_position_offset uint32
  72. mnc_position_offset uint32
  73. mobilebrand_position_offset uint32
  74. elevation_position_offset uint32
  75. usagetype_position_offset uint32
  76. country_enabled bool
  77. region_enabled bool
  78. city_enabled bool
  79. isp_enabled bool
  80. domain_enabled bool
  81. zipcode_enabled bool
  82. latitude_enabled bool
  83. longitude_enabled bool
  84. timezone_enabled bool
  85. netspeed_enabled bool
  86. iddcode_enabled bool
  87. areacode_enabled bool
  88. weatherstationcode_enabled bool
  89. weatherstationname_enabled bool
  90. mcc_enabled bool
  91. mnc_enabled bool
  92. mobilebrand_enabled bool
  93. elevation_enabled bool
  94. usagetype_enabled bool
  95. metaok bool
  96. }
  97. var defaultDB = &DB{}
  98. var country_position = [25]uint8{0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}
  99. var region_position = [25]uint8{0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}
  100. var city_position = [25]uint8{0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}
  101. var isp_position = [25]uint8{0, 0, 3, 0, 5, 0, 7, 5, 7, 0, 8, 0, 9, 0, 9, 0, 9, 0, 9, 7, 9, 0, 9, 7, 9}
  102. var latitude_position = [25]uint8{0, 0, 0, 0, 0, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}
  103. var longitude_position = [25]uint8{0, 0, 0, 0, 0, 6, 6, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6}
  104. var domain_position = [25]uint8{0, 0, 0, 0, 0, 0, 0, 6, 8, 0, 9, 0, 10, 0, 10, 0, 10, 0, 10, 8, 10, 0, 10, 8, 10}
  105. var zipcode_position = [25]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 0, 7, 7, 7, 0, 7, 0, 7, 7, 7, 0, 7}
  106. var timezone_position = [25]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 7, 8, 8, 8, 7, 8, 0, 8, 8, 8, 0, 8}
  107. var netspeed_position = [25]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 11, 0, 11, 8, 11, 0, 11, 0, 11, 0, 11}
  108. var iddcode_position = [25]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 12, 0, 12, 0, 12, 9, 12, 0, 12}
  109. var areacode_position = [25]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 13, 0, 13, 0, 13, 10, 13, 0, 13}
  110. var weatherstationcode_position = [25]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 14, 0, 14, 0, 14, 0, 14}
  111. var weatherstationname_position = [25]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 15, 0, 15, 0, 15, 0, 15}
  112. var mcc_position = [25]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 16, 0, 16, 9, 16}
  113. var mnc_position = [25]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 17, 0, 17, 10, 17}
  114. var mobilebrand_position = [25]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 18, 0, 18, 11, 18}
  115. var elevation_position = [25]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 19, 0, 19}
  116. var usagetype_position = [25]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 20}
  117. const api_version string = "8.3.0"
  118. var max_ipv4_range = big.NewInt(4294967295)
  119. var max_ipv6_range = big.NewInt(0)
  120. var from_v4mapped = big.NewInt(281470681743360)
  121. var to_v4mapped = big.NewInt(281474976710655)
  122. var from_6to4 = big.NewInt(0)
  123. var to_6to4 = big.NewInt(0)
  124. var from_teredo = big.NewInt(0)
  125. var to_teredo = big.NewInt(0)
  126. var last_32bits = big.NewInt(4294967295)
  127. const countryshort uint32 = 0x00001
  128. const countrylong uint32 = 0x00002
  129. const region uint32 = 0x00004
  130. const city uint32 = 0x00008
  131. const isp uint32 = 0x00010
  132. const latitude uint32 = 0x00020
  133. const longitude uint32 = 0x00040
  134. const domain uint32 = 0x00080
  135. const zipcode uint32 = 0x00100
  136. const timezone uint32 = 0x00200
  137. const netspeed uint32 = 0x00400
  138. const iddcode uint32 = 0x00800
  139. const areacode uint32 = 0x01000
  140. const weatherstationcode uint32 = 0x02000
  141. const weatherstationname uint32 = 0x04000
  142. const mcc uint32 = 0x08000
  143. const mnc uint32 = 0x10000
  144. const mobilebrand uint32 = 0x20000
  145. const elevation uint32 = 0x40000
  146. const usagetype uint32 = 0x80000
  147. const all uint32 = countryshort | countrylong | region | city | isp | latitude | longitude | domain | zipcode | timezone | netspeed | iddcode | areacode | weatherstationcode | weatherstationname | mcc | mnc | mobilebrand | elevation | usagetype
  148. const invalid_address string = "Invalid IP address."
  149. const missing_file string = "Invalid database file."
  150. const not_supported string = "This parameter is unavailable for selected data file. Please upgrade the data file."
  151. // get IP type and calculate IP number; calculates index too if exists
  152. func (d *DB) checkip(ip string) (iptype uint32, ipnum *big.Int, ipindex uint32) {
  153. iptype = 0
  154. ipnum = big.NewInt(0)
  155. ipnumtmp := big.NewInt(0)
  156. ipindex = 0
  157. ipaddress := net.ParseIP(ip)
  158. if ipaddress != nil {
  159. v4 := ipaddress.To4()
  160. if v4 != nil {
  161. iptype = 4
  162. ipnum.SetBytes(v4)
  163. } else {
  164. v6 := ipaddress.To16()
  165. if v6 != nil {
  166. iptype = 6
  167. ipnum.SetBytes(v6)
  168. if ipnum.Cmp(from_v4mapped) >= 0 && ipnum.Cmp(to_v4mapped) <= 0 {
  169. // ipv4-mapped ipv6 should treat as ipv4 and read ipv4 data section
  170. iptype = 4
  171. ipnum.Sub(ipnum, from_v4mapped)
  172. } else if ipnum.Cmp(from_6to4) >= 0 && ipnum.Cmp(to_6to4) <= 0 {
  173. // 6to4 so need to remap to ipv4
  174. iptype = 4
  175. ipnum.Rsh(ipnum, 80)
  176. ipnum.And(ipnum, last_32bits)
  177. } else if ipnum.Cmp(from_teredo) >= 0 && ipnum.Cmp(to_teredo) <= 0 {
  178. // Teredo so need to remap to ipv4
  179. iptype = 4
  180. ipnum.Not(ipnum)
  181. ipnum.And(ipnum, last_32bits)
  182. }
  183. }
  184. }
  185. }
  186. if iptype == 4 {
  187. if d.meta.ipv4indexbaseaddr > 0 {
  188. ipnumtmp.Rsh(ipnum, 16)
  189. ipnumtmp.Lsh(ipnumtmp, 3)
  190. ipindex = uint32(ipnumtmp.Add(ipnumtmp, big.NewInt(int64(d.meta.ipv4indexbaseaddr))).Uint64())
  191. }
  192. } else if iptype == 6 {
  193. if d.meta.ipv6indexbaseaddr > 0 {
  194. ipnumtmp.Rsh(ipnum, 112)
  195. ipnumtmp.Lsh(ipnumtmp, 3)
  196. ipindex = uint32(ipnumtmp.Add(ipnumtmp, big.NewInt(int64(d.meta.ipv6indexbaseaddr))).Uint64())
  197. }
  198. }
  199. return
  200. }
  201. // read byte
  202. func (d *DB) readuint8(pos int64) (uint8, error) {
  203. var retval uint8
  204. data := make([]byte, 1)
  205. _, err := d.f.ReadAt(data, pos-1)
  206. if err != nil {
  207. return 0, err
  208. }
  209. retval = data[0]
  210. return retval, nil
  211. }
  212. // read unsigned 32-bit integer from slices
  213. func (d *DB) readuint32_row(row []byte, pos uint32) uint32 {
  214. var retval uint32
  215. data := row[pos : pos+4]
  216. retval = binary.LittleEndian.Uint32(data)
  217. return retval
  218. }
  219. // read unsigned 32-bit integer
  220. func (d *DB) readuint32(pos uint32) (uint32, error) {
  221. pos2 := int64(pos)
  222. var retval uint32
  223. data := make([]byte, 4)
  224. _, err := d.f.ReadAt(data, pos2-1)
  225. if err != nil {
  226. return 0, err
  227. }
  228. buf := bytes.NewReader(data)
  229. err = binary.Read(buf, binary.LittleEndian, &retval)
  230. if err != nil {
  231. fmt.Printf("binary read failed: %v", err)
  232. }
  233. return retval, nil
  234. }
  235. // read unsigned 128-bit integer
  236. func (d *DB) readuint128(pos uint32) (*big.Int, error) {
  237. pos2 := int64(pos)
  238. retval := big.NewInt(0)
  239. data := make([]byte, 16)
  240. _, err := d.f.ReadAt(data, pos2-1)
  241. if err != nil {
  242. return nil, err
  243. }
  244. // little endian to big endian
  245. for i, j := 0, len(data)-1; i < j; i, j = i+1, j-1 {
  246. data[i], data[j] = data[j], data[i]
  247. }
  248. retval.SetBytes(data)
  249. return retval, nil
  250. }
  251. // read string
  252. func (d *DB) readstr(pos uint32) (string, error) {
  253. pos2 := int64(pos)
  254. var retval string
  255. lenbyte := make([]byte, 1)
  256. _, err := d.f.ReadAt(lenbyte, pos2)
  257. if err != nil {
  258. return "", err
  259. }
  260. strlen := lenbyte[0]
  261. data := make([]byte, strlen)
  262. _, err = d.f.ReadAt(data, pos2+1)
  263. if err != nil {
  264. return "", err
  265. }
  266. retval = string(data[:strlen])
  267. return retval, nil
  268. }
  269. // read float from slices
  270. func (d *DB) readfloat_row(row []byte, pos uint32) float32 {
  271. var retval float32
  272. data := row[pos : pos+4]
  273. bits := binary.LittleEndian.Uint32(data)
  274. retval = math.Float32frombits(bits)
  275. return retval
  276. }
  277. // read float
  278. func (d *DB) readfloat(pos uint32) (float32, error) {
  279. pos2 := int64(pos)
  280. var retval float32
  281. data := make([]byte, 4)
  282. _, err := d.f.ReadAt(data, pos2-1)
  283. if err != nil {
  284. return 0, err
  285. }
  286. buf := bytes.NewReader(data)
  287. err = binary.Read(buf, binary.LittleEndian, &retval)
  288. if err != nil {
  289. fmt.Printf("binary read failed: %v", err)
  290. }
  291. return retval, nil
  292. }
  293. func fatal(db *DB, err error) (*DB, error) {
  294. _ = db.f.Close()
  295. return nil, err
  296. }
  297. // Open takes the path to the IP2Location BIN database file. It will read all the metadata required to
  298. // be able to extract the embedded geolocation data, and return the underlining DB object.
  299. func OpenDB(dbpath string) (*DB, error) {
  300. var db = &DB{}
  301. max_ipv6_range.SetString("340282366920938463463374607431768211455", 10)
  302. from_6to4.SetString("42545680458834377588178886921629466624", 10)
  303. to_6to4.SetString("42550872755692912415807417417958686719", 10)
  304. from_teredo.SetString("42540488161975842760550356425300246528", 10)
  305. to_teredo.SetString("42540488241204005274814694018844196863", 10)
  306. var err error
  307. db.f, err = os.Open(dbpath)
  308. if err != nil {
  309. return nil, err
  310. }
  311. db.meta.databasetype, err = db.readuint8(1)
  312. if err != nil {
  313. return fatal(db, err)
  314. }
  315. db.meta.databasecolumn, err = db.readuint8(2)
  316. if err != nil {
  317. return fatal(db, err)
  318. }
  319. db.meta.databaseyear, err = db.readuint8(3)
  320. if err != nil {
  321. return fatal(db, err)
  322. }
  323. db.meta.databasemonth, err = db.readuint8(4)
  324. if err != nil {
  325. return fatal(db, err)
  326. }
  327. db.meta.databaseday, err = db.readuint8(5)
  328. if err != nil {
  329. return fatal(db, err)
  330. }
  331. db.meta.ipv4databasecount, err = db.readuint32(6)
  332. if err != nil {
  333. return fatal(db, err)
  334. }
  335. db.meta.ipv4databaseaddr, err = db.readuint32(10)
  336. if err != nil {
  337. return fatal(db, err)
  338. }
  339. db.meta.ipv6databasecount, err = db.readuint32(14)
  340. if err != nil {
  341. return fatal(db, err)
  342. }
  343. db.meta.ipv6databaseaddr, err = db.readuint32(18)
  344. if err != nil {
  345. return fatal(db, err)
  346. }
  347. db.meta.ipv4indexbaseaddr, err = db.readuint32(22)
  348. if err != nil {
  349. return fatal(db, err)
  350. }
  351. db.meta.ipv6indexbaseaddr, err = db.readuint32(26)
  352. if err != nil {
  353. return fatal(db, err)
  354. }
  355. db.meta.ipv4columnsize = uint32(db.meta.databasecolumn << 2) // 4 bytes each column
  356. db.meta.ipv6columnsize = uint32(16 + ((db.meta.databasecolumn - 1) << 2)) // 4 bytes each column, except IPFrom column which is 16 bytes
  357. dbt := db.meta.databasetype
  358. // since both IPv4 and IPv6 use 4 bytes for the below columns, can just do it once here
  359. // if country_position[dbt] != 0 {
  360. // country_position_offset = uint32(country_position[dbt] - 1) << 2
  361. // country_enabled = true
  362. // }
  363. // if region_position[dbt] != 0 {
  364. // region_position_offset = uint32(region_position[dbt] - 1) << 2
  365. // region_enabled = true
  366. // }
  367. // if city_position[dbt] != 0 {
  368. // city_position_offset = uint32(city_position[dbt] - 1) << 2
  369. // city_enabled = true
  370. // }
  371. // if isp_position[dbt] != 0 {
  372. // isp_position_offset = uint32(isp_position[dbt] - 1) << 2
  373. // isp_enabled = true
  374. // }
  375. // if domain_position[dbt] != 0 {
  376. // domain_position_offset = uint32(domain_position[dbt] - 1) << 2
  377. // domain_enabled = true
  378. // }
  379. // if zipcode_position[dbt] != 0 {
  380. // zipcode_position_offset = uint32(zipcode_position[dbt] - 1) << 2
  381. // zipcode_enabled = true
  382. // }
  383. // if latitude_position[dbt] != 0 {
  384. // latitude_position_offset = uint32(latitude_position[dbt] - 1) << 2
  385. // latitude_enabled = true
  386. // }
  387. // if longitude_position[dbt] != 0 {
  388. // longitude_position_offset = uint32(longitude_position[dbt] - 1) << 2
  389. // longitude_enabled = true
  390. // }
  391. // if timezone_position[dbt] != 0 {
  392. // timezone_position_offset = uint32(timezone_position[dbt] - 1) << 2
  393. // timezone_enabled = true
  394. // }
  395. // if netspeed_position[dbt] != 0 {
  396. // netspeed_position_offset = uint32(netspeed_position[dbt] - 1) << 2
  397. // netspeed_enabled = true
  398. // }
  399. // if iddcode_position[dbt] != 0 {
  400. // iddcode_position_offset = uint32(iddcode_position[dbt] - 1) << 2
  401. // iddcode_enabled = true
  402. // }
  403. // if areacode_position[dbt] != 0 {
  404. // areacode_position_offset = uint32(areacode_position[dbt] - 1) << 2
  405. // areacode_enabled = true
  406. // }
  407. // if weatherstationcode_position[dbt] != 0 {
  408. // weatherstationcode_position_offset = uint32(weatherstationcode_position[dbt] - 1) << 2
  409. // weatherstationcode_enabled = true
  410. // }
  411. // if weatherstationname_position[dbt] != 0 {
  412. // weatherstationname_position_offset = uint32(weatherstationname_position[dbt] - 1) << 2
  413. // weatherstationname_enabled = true
  414. // }
  415. // if mcc_position[dbt] != 0 {
  416. // mcc_position_offset = uint32(mcc_position[dbt] - 1) << 2
  417. // mcc_enabled = true
  418. // }
  419. // if mnc_position[dbt] != 0 {
  420. // mnc_position_offset = uint32(mnc_position[dbt] - 1) << 2
  421. // mnc_enabled = true
  422. // }
  423. // if mobilebrand_position[dbt] != 0 {
  424. // mobilebrand_position_offset = uint32(mobilebrand_position[dbt] - 1) << 2
  425. // mobilebrand_enabled = true
  426. // }
  427. // if elevation_position[dbt] != 0 {
  428. // elevation_position_offset = uint32(elevation_position[dbt] - 1) << 2
  429. // elevation_enabled = true
  430. // }
  431. // if usagetype_position[dbt] != 0 {
  432. // usagetype_position_offset = uint32(usagetype_position[dbt] - 1) << 2
  433. // usagetype_enabled = true
  434. // }
  435. if country_position[dbt] != 0 {
  436. db.country_position_offset = uint32(country_position[dbt]-2) << 2
  437. db.country_enabled = true
  438. }
  439. if region_position[dbt] != 0 {
  440. db.region_position_offset = uint32(region_position[dbt]-2) << 2
  441. db.region_enabled = true
  442. }
  443. if city_position[dbt] != 0 {
  444. db.city_position_offset = uint32(city_position[dbt]-2) << 2
  445. db.city_enabled = true
  446. }
  447. if isp_position[dbt] != 0 {
  448. db.isp_position_offset = uint32(isp_position[dbt]-2) << 2
  449. db.isp_enabled = true
  450. }
  451. if domain_position[dbt] != 0 {
  452. db.domain_position_offset = uint32(domain_position[dbt]-2) << 2
  453. db.domain_enabled = true
  454. }
  455. if zipcode_position[dbt] != 0 {
  456. db.zipcode_position_offset = uint32(zipcode_position[dbt]-2) << 2
  457. db.zipcode_enabled = true
  458. }
  459. if latitude_position[dbt] != 0 {
  460. db.latitude_position_offset = uint32(latitude_position[dbt]-2) << 2
  461. db.latitude_enabled = true
  462. }
  463. if longitude_position[dbt] != 0 {
  464. db.longitude_position_offset = uint32(longitude_position[dbt]-2) << 2
  465. db.longitude_enabled = true
  466. }
  467. if timezone_position[dbt] != 0 {
  468. db.timezone_position_offset = uint32(timezone_position[dbt]-2) << 2
  469. db.timezone_enabled = true
  470. }
  471. if netspeed_position[dbt] != 0 {
  472. db.netspeed_position_offset = uint32(netspeed_position[dbt]-2) << 2
  473. db.netspeed_enabled = true
  474. }
  475. if iddcode_position[dbt] != 0 {
  476. db.iddcode_position_offset = uint32(iddcode_position[dbt]-2) << 2
  477. db.iddcode_enabled = true
  478. }
  479. if areacode_position[dbt] != 0 {
  480. db.areacode_position_offset = uint32(areacode_position[dbt]-2) << 2
  481. db.areacode_enabled = true
  482. }
  483. if weatherstationcode_position[dbt] != 0 {
  484. db.weatherstationcode_position_offset = uint32(weatherstationcode_position[dbt]-2) << 2
  485. db.weatherstationcode_enabled = true
  486. }
  487. if weatherstationname_position[dbt] != 0 {
  488. db.weatherstationname_position_offset = uint32(weatherstationname_position[dbt]-2) << 2
  489. db.weatherstationname_enabled = true
  490. }
  491. if mcc_position[dbt] != 0 {
  492. db.mcc_position_offset = uint32(mcc_position[dbt]-2) << 2
  493. db.mcc_enabled = true
  494. }
  495. if mnc_position[dbt] != 0 {
  496. db.mnc_position_offset = uint32(mnc_position[dbt]-2) << 2
  497. db.mnc_enabled = true
  498. }
  499. if mobilebrand_position[dbt] != 0 {
  500. db.mobilebrand_position_offset = uint32(mobilebrand_position[dbt]-2) << 2
  501. db.mobilebrand_enabled = true
  502. }
  503. if elevation_position[dbt] != 0 {
  504. db.elevation_position_offset = uint32(elevation_position[dbt]-2) << 2
  505. db.elevation_enabled = true
  506. }
  507. if usagetype_position[dbt] != 0 {
  508. db.usagetype_position_offset = uint32(usagetype_position[dbt]-2) << 2
  509. db.usagetype_enabled = true
  510. }
  511. db.metaok = true
  512. return db, nil
  513. }
  514. // Open takes the path to the IP2Location BIN database file. It will read all the metadata required to
  515. // be able to extract the embedded geolocation data.
  516. //
  517. // Deprecated: No longer being updated.
  518. func Open(dbpath string) {
  519. db, err := OpenDB(dbpath)
  520. if err != nil {
  521. return
  522. }
  523. defaultDB = db
  524. }
  525. // Close will close the file handle to the BIN file.
  526. //
  527. // Deprecated: No longer being updated.
  528. func Close() {
  529. defaultDB.Close()
  530. }
  531. // Api_version returns the version of the component.
  532. func Api_version() string {
  533. return api_version
  534. }
  535. // populate record with message
  536. func loadmessage(mesg string) IP2Locationrecord {
  537. var x IP2Locationrecord
  538. x.Country_short = mesg
  539. x.Country_long = mesg
  540. x.Region = mesg
  541. x.City = mesg
  542. x.Isp = mesg
  543. x.Domain = mesg
  544. x.Zipcode = mesg
  545. x.Timezone = mesg
  546. x.Netspeed = mesg
  547. x.Iddcode = mesg
  548. x.Areacode = mesg
  549. x.Weatherstationcode = mesg
  550. x.Weatherstationname = mesg
  551. x.Mcc = mesg
  552. x.Mnc = mesg
  553. x.Mobilebrand = mesg
  554. x.Usagetype = mesg
  555. return x
  556. }
  557. func handleError(rec IP2Locationrecord, err error) IP2Locationrecord {
  558. if err != nil {
  559. fmt.Print(err)
  560. }
  561. return rec
  562. }
  563. // Get_all will return all geolocation fields based on the queried IP address.
  564. //
  565. // Deprecated: No longer being updated.
  566. func Get_all(ipaddress string) IP2Locationrecord {
  567. return handleError(defaultDB.query(ipaddress, all))
  568. }
  569. // Get_country_short will return the ISO-3166 country code based on the queried IP address.
  570. //
  571. // Deprecated: No longer being updated.
  572. func Get_country_short(ipaddress string) IP2Locationrecord {
  573. return handleError(defaultDB.query(ipaddress, countryshort))
  574. }
  575. // Get_country_long will return the country name based on the queried IP address.
  576. //
  577. // Deprecated: No longer being updated.
  578. func Get_country_long(ipaddress string) IP2Locationrecord {
  579. return handleError(defaultDB.query(ipaddress, countrylong))
  580. }
  581. // Get_region will return the region name based on the queried IP address.
  582. //
  583. // Deprecated: No longer being updated.
  584. func Get_region(ipaddress string) IP2Locationrecord {
  585. return handleError(defaultDB.query(ipaddress, region))
  586. }
  587. // Get_city will return the city name based on the queried IP address.
  588. //
  589. // Deprecated: No longer being updated.
  590. func Get_city(ipaddress string) IP2Locationrecord {
  591. return handleError(defaultDB.query(ipaddress, city))
  592. }
  593. // Get_isp will return the Internet Service Provider name based on the queried IP address.
  594. //
  595. // Deprecated: No longer being updated.
  596. func Get_isp(ipaddress string) IP2Locationrecord {
  597. return handleError(defaultDB.query(ipaddress, isp))
  598. }
  599. // Get_latitude will return the latitude based on the queried IP address.
  600. //
  601. // Deprecated: No longer being updated.
  602. func Get_latitude(ipaddress string) IP2Locationrecord {
  603. return handleError(defaultDB.query(ipaddress, latitude))
  604. }
  605. // Get_longitude will return the longitude based on the queried IP address.
  606. //
  607. // Deprecated: No longer being updated.
  608. func Get_longitude(ipaddress string) IP2Locationrecord {
  609. return handleError(defaultDB.query(ipaddress, longitude))
  610. }
  611. // Get_domain will return the domain name based on the queried IP address.
  612. //
  613. // Deprecated: No longer being updated.
  614. func Get_domain(ipaddress string) IP2Locationrecord {
  615. return handleError(defaultDB.query(ipaddress, domain))
  616. }
  617. // Get_zipcode will return the postal code based on the queried IP address.
  618. //
  619. // Deprecated: No longer being updated.
  620. func Get_zipcode(ipaddress string) IP2Locationrecord {
  621. return handleError(defaultDB.query(ipaddress, zipcode))
  622. }
  623. // Get_timezone will return the time zone based on the queried IP address.
  624. //
  625. // Deprecated: No longer being updated.
  626. func Get_timezone(ipaddress string) IP2Locationrecord {
  627. return handleError(defaultDB.query(ipaddress, timezone))
  628. }
  629. // Get_netspeed will return the Internet connection speed based on the queried IP address.
  630. //
  631. // Deprecated: No longer being updated.
  632. func Get_netspeed(ipaddress string) IP2Locationrecord {
  633. return handleError(defaultDB.query(ipaddress, netspeed))
  634. }
  635. // Get_iddcode will return the International Direct Dialing code based on the queried IP address.
  636. //
  637. // Deprecated: No longer being updated.
  638. func Get_iddcode(ipaddress string) IP2Locationrecord {
  639. return handleError(defaultDB.query(ipaddress, iddcode))
  640. }
  641. // Get_areacode will return the area code based on the queried IP address.
  642. //
  643. // Deprecated: No longer being updated.
  644. func Get_areacode(ipaddress string) IP2Locationrecord {
  645. return handleError(defaultDB.query(ipaddress, areacode))
  646. }
  647. // Get_weatherstationcode will return the weather station code based on the queried IP address.
  648. //
  649. // Deprecated: No longer being updated.
  650. func Get_weatherstationcode(ipaddress string) IP2Locationrecord {
  651. return handleError(defaultDB.query(ipaddress, weatherstationcode))
  652. }
  653. // Get_weatherstationname will return the weather station name based on the queried IP address.
  654. //
  655. // Deprecated: No longer being updated.
  656. func Get_weatherstationname(ipaddress string) IP2Locationrecord {
  657. return handleError(defaultDB.query(ipaddress, weatherstationname))
  658. }
  659. // Get_mcc will return the mobile country code based on the queried IP address.
  660. //
  661. // Deprecated: No longer being updated.
  662. func Get_mcc(ipaddress string) IP2Locationrecord {
  663. return handleError(defaultDB.query(ipaddress, mcc))
  664. }
  665. // Get_mnc will return the mobile network code based on the queried IP address.
  666. //
  667. // Deprecated: No longer being updated.
  668. func Get_mnc(ipaddress string) IP2Locationrecord {
  669. return handleError(defaultDB.query(ipaddress, mnc))
  670. }
  671. // Get_mobilebrand will return the mobile carrier brand based on the queried IP address.
  672. //
  673. // Deprecated: No longer being updated.
  674. func Get_mobilebrand(ipaddress string) IP2Locationrecord {
  675. return handleError(defaultDB.query(ipaddress, mobilebrand))
  676. }
  677. // Get_elevation will return the elevation in meters based on the queried IP address.
  678. //
  679. // Deprecated: No longer being updated.
  680. func Get_elevation(ipaddress string) IP2Locationrecord {
  681. return handleError(defaultDB.query(ipaddress, elevation))
  682. }
  683. // Get_usagetype will return the usage type based on the queried IP address.
  684. //
  685. // Deprecated: No longer being updated.
  686. func Get_usagetype(ipaddress string) IP2Locationrecord {
  687. return handleError(defaultDB.query(ipaddress, usagetype))
  688. }
  689. // Get_all will return all geolocation fields based on the queried IP address.
  690. func (d *DB) Get_all(ipaddress string) (IP2Locationrecord, error) {
  691. return d.query(ipaddress, all)
  692. }
  693. // Get_country_short will return the ISO-3166 country code based on the queried IP address.
  694. func (d *DB) Get_country_short(ipaddress string) (IP2Locationrecord, error) {
  695. return d.query(ipaddress, countryshort)
  696. }
  697. // Get_country_long will return the country name based on the queried IP address.
  698. func (d *DB) Get_country_long(ipaddress string) (IP2Locationrecord, error) {
  699. return d.query(ipaddress, countrylong)
  700. }
  701. // Get_region will return the region name based on the queried IP address.
  702. func (d *DB) Get_region(ipaddress string) (IP2Locationrecord, error) {
  703. return d.query(ipaddress, region)
  704. }
  705. // Get_city will return the city name based on the queried IP address.
  706. func (d *DB) Get_city(ipaddress string) (IP2Locationrecord, error) {
  707. return d.query(ipaddress, city)
  708. }
  709. // Get_isp will return the Internet Service Provider name based on the queried IP address.
  710. func (d *DB) Get_isp(ipaddress string) (IP2Locationrecord, error) {
  711. return d.query(ipaddress, isp)
  712. }
  713. // Get_latitude will return the latitude based on the queried IP address.
  714. func (d *DB) Get_latitude(ipaddress string) (IP2Locationrecord, error) {
  715. return d.query(ipaddress, latitude)
  716. }
  717. // Get_longitude will return the longitude based on the queried IP address.
  718. func (d *DB) Get_longitude(ipaddress string) (IP2Locationrecord, error) {
  719. return d.query(ipaddress, longitude)
  720. }
  721. // Get_domain will return the domain name based on the queried IP address.
  722. func (d *DB) Get_domain(ipaddress string) (IP2Locationrecord, error) {
  723. return d.query(ipaddress, domain)
  724. }
  725. // Get_zipcode will return the postal code based on the queried IP address.
  726. func (d *DB) Get_zipcode(ipaddress string) (IP2Locationrecord, error) {
  727. return d.query(ipaddress, zipcode)
  728. }
  729. // Get_timezone will return the time zone based on the queried IP address.
  730. func (d *DB) Get_timezone(ipaddress string) (IP2Locationrecord, error) {
  731. return d.query(ipaddress, timezone)
  732. }
  733. // Get_netspeed will return the Internet connection speed based on the queried IP address.
  734. func (d *DB) Get_netspeed(ipaddress string) (IP2Locationrecord, error) {
  735. return d.query(ipaddress, netspeed)
  736. }
  737. // Get_iddcode will return the International Direct Dialing code based on the queried IP address.
  738. func (d *DB) Get_iddcode(ipaddress string) (IP2Locationrecord, error) {
  739. return d.query(ipaddress, iddcode)
  740. }
  741. // Get_areacode will return the area code based on the queried IP address.
  742. func (d *DB) Get_areacode(ipaddress string) (IP2Locationrecord, error) {
  743. return d.query(ipaddress, areacode)
  744. }
  745. // Get_weatherstationcode will return the weather station code based on the queried IP address.
  746. func (d *DB) Get_weatherstationcode(ipaddress string) (IP2Locationrecord, error) {
  747. return d.query(ipaddress, weatherstationcode)
  748. }
  749. // Get_weatherstationname will return the weather station name based on the queried IP address.
  750. func (d *DB) Get_weatherstationname(ipaddress string) (IP2Locationrecord, error) {
  751. return d.query(ipaddress, weatherstationname)
  752. }
  753. // Get_mcc will return the mobile country code based on the queried IP address.
  754. func (d *DB) Get_mcc(ipaddress string) (IP2Locationrecord, error) {
  755. return d.query(ipaddress, mcc)
  756. }
  757. // Get_mnc will return the mobile network code based on the queried IP address.
  758. func (d *DB) Get_mnc(ipaddress string) (IP2Locationrecord, error) {
  759. return d.query(ipaddress, mnc)
  760. }
  761. // Get_mobilebrand will return the mobile carrier brand based on the queried IP address.
  762. func (d *DB) Get_mobilebrand(ipaddress string) (IP2Locationrecord, error) {
  763. return d.query(ipaddress, mobilebrand)
  764. }
  765. // Get_elevation will return the elevation in meters based on the queried IP address.
  766. func (d *DB) Get_elevation(ipaddress string) (IP2Locationrecord, error) {
  767. return d.query(ipaddress, elevation)
  768. }
  769. // Get_usagetype will return the usage type based on the queried IP address.
  770. func (d *DB) Get_usagetype(ipaddress string) (IP2Locationrecord, error) {
  771. return d.query(ipaddress, usagetype)
  772. }
  773. // main query
  774. func (d *DB) query(ipaddress string, mode uint32) (IP2Locationrecord, error) {
  775. x := loadmessage(not_supported) // default message
  776. // read metadata
  777. if !d.metaok {
  778. x = loadmessage(missing_file)
  779. return x, nil
  780. }
  781. // check IP type and return IP number & index (if exists)
  782. iptype, ipno, ipindex := d.checkip(ipaddress)
  783. if iptype == 0 {
  784. x = loadmessage(invalid_address)
  785. return x, nil
  786. }
  787. var err error
  788. var colsize uint32
  789. var baseaddr uint32
  790. var low uint32
  791. var high uint32
  792. var mid uint32
  793. var rowoffset uint32
  794. var rowoffset2 uint32
  795. ipfrom := big.NewInt(0)
  796. ipto := big.NewInt(0)
  797. maxip := big.NewInt(0)
  798. if iptype == 4 {
  799. baseaddr = d.meta.ipv4databaseaddr
  800. high = d.meta.ipv4databasecount
  801. maxip = max_ipv4_range
  802. colsize = d.meta.ipv4columnsize
  803. } else {
  804. baseaddr = d.meta.ipv6databaseaddr
  805. high = d.meta.ipv6databasecount
  806. maxip = max_ipv6_range
  807. colsize = d.meta.ipv6columnsize
  808. }
  809. // reading index
  810. if ipindex > 0 {
  811. low, err = d.readuint32(ipindex)
  812. if err != nil {
  813. return x, err
  814. }
  815. high, err = d.readuint32(ipindex + 4)
  816. if err != nil {
  817. return x, err
  818. }
  819. }
  820. if ipno.Cmp(maxip) >= 0 {
  821. ipno.Sub(ipno, big.NewInt(1))
  822. }
  823. for low <= high {
  824. mid = ((low + high) >> 1)
  825. rowoffset = baseaddr + (mid * colsize)
  826. rowoffset2 = rowoffset + colsize
  827. if iptype == 4 {
  828. ipfrom32, err := d.readuint32(rowoffset)
  829. if err != nil {
  830. return x, err
  831. }
  832. ipfrom = big.NewInt(int64(ipfrom32))
  833. ipto32, err := d.readuint32(rowoffset2)
  834. if err != nil {
  835. return x, err
  836. }
  837. ipto = big.NewInt(int64(ipto32))
  838. } else {
  839. ipfrom, err = d.readuint128(rowoffset)
  840. if err != nil {
  841. return x, err
  842. }
  843. ipto, err = d.readuint128(rowoffset2)
  844. if err != nil {
  845. return x, err
  846. }
  847. }
  848. if ipno.Cmp(ipfrom) >= 0 && ipno.Cmp(ipto) < 0 {
  849. var firstcol uint32 = 4 // 4 bytes for ip from
  850. if iptype == 6 {
  851. firstcol = 16 // 16 bytes for ipv6
  852. // rowoffset = rowoffset + 12 // coz below is assuming all columns are 4 bytes, so got 12 left to go to make 16 bytes total
  853. }
  854. row := make([]byte, colsize-firstcol) // exclude the ip from field
  855. _, err := d.f.ReadAt(row, int64(rowoffset+firstcol-1))
  856. if err != nil {
  857. return x, err
  858. }
  859. if mode&countryshort == 1 && d.country_enabled {
  860. // x.Country_short = readstr(readuint32(rowoffset + country_position_offset))
  861. if x.Country_short, err = d.readstr(d.readuint32_row(row, d.country_position_offset)); err != nil {
  862. return x, err
  863. }
  864. }
  865. if mode&countrylong != 0 && d.country_enabled {
  866. // x.Country_long = readstr(readuint32(rowoffset + country_position_offset) + 3)
  867. if x.Country_long, err = d.readstr(d.readuint32_row(row, d.country_position_offset) + 3); err != nil {
  868. return x, err
  869. }
  870. }
  871. if mode&region != 0 && d.region_enabled {
  872. // x.Region = readstr(readuint32(rowoffset + region_position_offset))
  873. if x.Region, err = d.readstr(d.readuint32_row(row, d.region_position_offset)); err != nil {
  874. return x, err
  875. }
  876. }
  877. if mode&city != 0 && d.city_enabled {
  878. // x.City = readstr(readuint32(rowoffset + city_position_offset))
  879. if x.City, err = d.readstr(d.readuint32_row(row, d.city_position_offset)); err != nil {
  880. return x, err
  881. }
  882. }
  883. if mode&isp != 0 && d.isp_enabled {
  884. // x.Isp = readstr(readuint32(rowoffset + isp_position_offset))
  885. if x.Isp, err = d.readstr(d.readuint32_row(row, d.isp_position_offset)); err != nil {
  886. return x, err
  887. }
  888. }
  889. if mode&latitude != 0 && d.latitude_enabled {
  890. // x.Latitude = readfloat(rowoffset + latitude_position_offset)
  891. x.Latitude = d.readfloat_row(row, d.latitude_position_offset)
  892. }
  893. if mode&longitude != 0 && d.longitude_enabled {
  894. // x.Longitude = readfloat(rowoffset + longitude_position_offset)
  895. x.Longitude = d.readfloat_row(row, d.longitude_position_offset)
  896. }
  897. if mode&domain != 0 && d.domain_enabled {
  898. // x.Domain = readstr(readuint32(rowoffset + domain_position_offset))
  899. if x.Domain, err = d.readstr(d.readuint32_row(row, d.domain_position_offset)); err != nil {
  900. return x, err
  901. }
  902. }
  903. if mode&zipcode != 0 && d.zipcode_enabled {
  904. // x.Zipcode = readstr(readuint32(rowoffset + zipcode_position_offset))
  905. if x.Zipcode, err = d.readstr(d.readuint32_row(row, d.zipcode_position_offset)); err != nil {
  906. return x, err
  907. }
  908. }
  909. if mode&timezone != 0 && d.timezone_enabled {
  910. // x.Timezone = readstr(readuint32(rowoffset + timezone_position_offset))
  911. if x.Timezone, err = d.readstr(d.readuint32_row(row, d.timezone_position_offset)); err != nil {
  912. return x, err
  913. }
  914. }
  915. if mode&netspeed != 0 && d.netspeed_enabled {
  916. // x.Netspeed = readstr(readuint32(rowoffset + netspeed_position_offset))
  917. if x.Netspeed, err = d.readstr(d.readuint32_row(row, d.netspeed_position_offset)); err != nil {
  918. return x, err
  919. }
  920. }
  921. if mode&iddcode != 0 && d.iddcode_enabled {
  922. // x.Iddcode = readstr(readuint32(rowoffset + iddcode_position_offset))
  923. if x.Iddcode, err = d.readstr(d.readuint32_row(row, d.iddcode_position_offset)); err != nil {
  924. return x, err
  925. }
  926. }
  927. if mode&areacode != 0 && d.areacode_enabled {
  928. // x.Areacode = readstr(readuint32(rowoffset + areacode_position_offset))
  929. if x.Areacode, err = d.readstr(d.readuint32_row(row, d.areacode_position_offset)); err != nil {
  930. return x, err
  931. }
  932. }
  933. if mode&weatherstationcode != 0 && d.weatherstationcode_enabled {
  934. // x.Weatherstationcode = readstr(readuint32(rowoffset + weatherstationcode_position_offset))
  935. if x.Weatherstationcode, err = d.readstr(d.readuint32_row(row, d.weatherstationcode_position_offset)); err != nil {
  936. return x, err
  937. }
  938. }
  939. if mode&weatherstationname != 0 && d.weatherstationname_enabled {
  940. // x.Weatherstationname = readstr(readuint32(rowoffset + weatherstationname_position_offset))
  941. if x.Weatherstationname, err = d.readstr(d.readuint32_row(row, d.weatherstationname_position_offset)); err != nil {
  942. return x, err
  943. }
  944. }
  945. if mode&mcc != 0 && d.mcc_enabled {
  946. // x.Mcc = readstr(readuint32(rowoffset + mcc_position_offset))
  947. if x.Mcc, err = d.readstr(d.readuint32_row(row, d.mcc_position_offset)); err != nil {
  948. return x, err
  949. }
  950. }
  951. if mode&mnc != 0 && d.mnc_enabled {
  952. // x.Mnc = readstr(readuint32(rowoffset + mnc_position_offset))
  953. if x.Mnc, err = d.readstr(d.readuint32_row(row, d.mnc_position_offset)); err != nil {
  954. return x, err
  955. }
  956. }
  957. if mode&mobilebrand != 0 && d.mobilebrand_enabled {
  958. // x.Mobilebrand = readstr(readuint32(rowoffset + mobilebrand_position_offset))
  959. if x.Mobilebrand, err = d.readstr(d.readuint32_row(row, d.mobilebrand_position_offset)); err != nil {
  960. return x, err
  961. }
  962. }
  963. if mode&elevation != 0 && d.elevation_enabled {
  964. // f, _ := strconv.ParseFloat(readstr(readuint32(rowoffset + elevation_position_offset)), 32)
  965. res, err := d.readstr(d.readuint32_row(row, d.elevation_position_offset))
  966. if err != nil {
  967. return x, err
  968. }
  969. f, _ := strconv.ParseFloat(res, 32)
  970. x.Elevation = float32(f)
  971. }
  972. if mode&usagetype != 0 && d.usagetype_enabled {
  973. // x.Usagetype = readstr(readuint32(rowoffset + usagetype_position_offset))
  974. if x.Usagetype, err = d.readstr(d.readuint32_row(row, d.usagetype_position_offset)); err != nil {
  975. return x, err
  976. }
  977. }
  978. return x, nil
  979. } else {
  980. if ipno.Cmp(ipfrom) < 0 {
  981. high = mid - 1
  982. } else {
  983. low = mid + 1
  984. }
  985. }
  986. }
  987. return x, nil
  988. }
  989. func (d *DB) Close() {
  990. _ = d.f.Close()
  991. }
  992. // Printrecord is used to output the geolocation data for debugging purposes.
  993. func Printrecord(x IP2Locationrecord) {
  994. fmt.Printf("country_short: %s\n", x.Country_short)
  995. fmt.Printf("country_long: %s\n", x.Country_long)
  996. fmt.Printf("region: %s\n", x.Region)
  997. fmt.Printf("city: %s\n", x.City)
  998. fmt.Printf("isp: %s\n", x.Isp)
  999. fmt.Printf("latitude: %f\n", x.Latitude)
  1000. fmt.Printf("longitude: %f\n", x.Longitude)
  1001. fmt.Printf("domain: %s\n", x.Domain)
  1002. fmt.Printf("zipcode: %s\n", x.Zipcode)
  1003. fmt.Printf("timezone: %s\n", x.Timezone)
  1004. fmt.Printf("netspeed: %s\n", x.Netspeed)
  1005. fmt.Printf("iddcode: %s\n", x.Iddcode)
  1006. fmt.Printf("areacode: %s\n", x.Areacode)
  1007. fmt.Printf("weatherstationcode: %s\n", x.Weatherstationcode)
  1008. fmt.Printf("weatherstationname: %s\n", x.Weatherstationname)
  1009. fmt.Printf("mcc: %s\n", x.Mcc)
  1010. fmt.Printf("mnc: %s\n", x.Mnc)
  1011. fmt.Printf("mobilebrand: %s\n", x.Mobilebrand)
  1012. fmt.Printf("elevation: %f\n", x.Elevation)
  1013. fmt.Printf("usagetype: %s\n", x.Usagetype)
  1014. }