Skip to content

Commit

Permalink
😺 😺
Browse files Browse the repository at this point in the history
  • Loading branch information
jolav committed Nov 27, 2018
0 parents commit 7a760e6
Show file tree
Hide file tree
Showing 20 changed files with 1,347 additions and 0 deletions.
22 changes: 22 additions & 0 deletions .gitignore
@@ -0,0 +1,22 @@
# Ignore these directories
_aux/
logs/
tmp/
_data

# Ignore these files
.env
.DS_Store
_private.js
_private.json
a_private.go
error.log
hits.log


# binaries
geoip
geoip-*

# databases
_data/GeoLite2-City.mmdb
13 changes: 13 additions & 0 deletions LICENSE.md
@@ -0,0 +1,13 @@
BSD 3-Clause License

Copyright (c) 2017, Jolav All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

* Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49 changes: 49 additions & 0 deletions README.md
@@ -0,0 +1,49 @@

![Version](https://img.shields.io/badge/version-0.1.0-orange.svg)
![Maintained YES](https://img.shields.io/badge/Maintained%3F-YES-green.svg)
![Ask Me Anything !](https://img.shields.io/badge/Ask%20me-anything-1abc9c.svg)

# ![logo](https://github.com/jolav/geoip-xyz/blob/master/www/_public/icons/ip48.png?raw=true) **[GEOIP.XYZ](https://geoip.xyz)**

version 0.1.0

- Free service that provides a public secure API (CORS enabled) to retrieve geolocation from any IP or hostname.
- 10 request per second. Once reached subsequent requests will result in error 429 until your quota is cleared.
- This API requires no key or signup.
- JSON and XML supported
- IPv4 and IPv6 supported
- CORS support out of the box makes this perfect to your front end apps or webs


Examples

https://geoip.xyz/v1/json
https://geoip.xyz/v1/json?q=codetabs.com
https://geoip.xyz/v1/xml?q=8.8.8.8
https://geoip.xyz/v1/xml?q=2a00:1450:4006:803::200e

Response JSON :

```json
{
"ip": "172.168.90.240",
"country_code": "FR",
"country_name": "France",
"region_code": "IDF",
"region_name": "Ile-de-France",
"city": "Paris",
"zip_code": "75001",
"time_zone": "Europe/Paris",
"latitude": 48.8628,
"longitude": 2.3292
}
```

<hr>



## **Acknowledgment**


* This site includes GeoLite2 data created by MaxMind, available from [maxmind.com](http://maxmind.com)
58 changes: 58 additions & 0 deletions _db/db.go
@@ -0,0 +1,58 @@
package stats

import (
"database/sql"
"fmt"
"log"

lib "../_lib"

// mysql driver
_ "github.com/go-sql-driver/mysql"
)

type configuration struct {
Mysql struct {
Host string `json:"host"`
Port int `json:"port"`
Db string `json:"db"`
Table string `json:"table"`
User string `json:"user"`
Password string `json:"password"`
} `json:"mysql"`
}

type myDB struct{}

var db *sql.DB
var c configuration

// MYDB ...
var MYDB myDB

func (MYDB *myDB) InitDB() {
lib.LoadConfig(mysqljson, &c)
connPath := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", c.Mysql.User, c.Mysql.Password, c.Mysql.Host, c.Mysql.Port, c.Mysql.Db)
//fmt.Println(connPath)
var err error
db, err = sql.Open("mysql", connPath)
if err != nil {
log.Printf("ERROR 1 DB %s\n", err)
} else {
log.Printf("INFO DB %s sql.Open() => OK\n", c.Mysql.Db)
}
}

func (MYDB *myDB) InsertHit(datenow string) {
sql := fmt.Sprintf("INSERT INTO `%s` (time, geoip) VALUES ('%s', 0) ON DUPLICATE KEY UPDATE geoip = geoip + 1;", c.Mysql.Table, datenow)
stmt, err := db.Prepare(sql)
if err != nil {
log.Printf("ERROR 2 DB %s\n", err)
return
}
defer stmt.Close()
_, err = stmt.Exec()
if err != nil {
log.Printf("ERROR 3 DB %s\n", err)
}
}
85 changes: 85 additions & 0 deletions _lib/lib.go
@@ -0,0 +1,85 @@
package lib

import (
"encoding/json"
"encoding/xml"
"log"
"math"
"net"
"net/http"
"strings"
)

// SendJSONToClient ...
func SendJSONToClient(w http.ResponseWriter, d interface{}) {
w.Header().Set("Content-Type", "application/json")
var dataJSON = []byte(`{}`)
dataJSON, err := json.MarshalIndent(d, "", " ")
if err != nil {
log.Printf("ERROR Marshaling %s\n", err)
w.Write([]byte(`{}`))
}
w.Write(dataJSON)
}

// SendXMLToClient ...
func SendXMLToClient(w http.ResponseWriter, d interface{}) {
w.Header().Set("Content-Type", "application/xml")
var dataXML = []byte(`<output></output>`)
dataXML, err := xml.Marshal(&d)
if err != nil {
log.Printf("ERROR Parsing into XML %s\n", err)
w.Write([]byte(`{}`))
}
w.Write(dataXML)
}

// SendErrorToClient ...
func SendErrorToClient(w http.ResponseWriter, d interface{}) {
w.WriteHeader(http.StatusBadRequest)
w.Header().Set("Content-Type", "application/json")
var dataJSON = []byte(`{}`)
dataJSON, err := json.MarshalIndent(d, "", " ")
if err != nil {
log.Printf("ERROR Marshaling %s\n", err)
w.Write([]byte(`{}`))
}
w.Write(dataJSON)
}

// ToFixedFloat64 (untruncated, num) -> untruncated.toFixed(num)
func ToFixedFloat64(untruncated float64, precision int) float64 {
coef := math.Pow10(precision)
truncated := float64(int(untruncated*coef)) / coef
return truncated
}

// LoadConfig ...
func LoadConfig(configjson []byte, c interface{}) {
err := json.Unmarshal(configjson, &c)
if err != nil {
log.Printf("ERROR LoadConfig %s\n", err)
}
}

// GetIP ...
func GetIP(r *http.Request) string {
ip := r.Header.Get("X-Forwarded-For")
ip = strings.Split(ip, ",")[0]
if len(ip) > 0 {
return ip
}
ip, _, _ = net.SplitHostPort(r.RemoteAddr)
ip = strings.Split(ip, ",")[0]
return ip
}

// SliceContainsString ... returns true/false
func SliceContainsString(str string, slice []string) bool {
for _, v := range slice {
if v == str {
return true
}
}
return false
}
55 changes: 55 additions & 0 deletions a_config.go
@@ -0,0 +1,55 @@
package main

var configjson = []byte(`
{
"app": {
"version": "0.1.0",
"mode": "production",
"port": 3700,
"hitslog":"./hits.log",
"errlog":"./error.log"
},
"geoip": {
"geoDataBaseFile": "./_data/GeoLite2-City.mmdb",
"formats": ["json","xml"]
}
}
`)

var c configuration
var e myError

type configuration struct {
App struct {
Mode string //`json:"mode"`
Port int //`json:"port"`
Service string //`json:"service"`
Version string //`json:"version"`
HitsLog string
ErrLog string
Services []string
} //`json:"app"`
Geoip struct {
GeoDataBaseFile string
Formats []string
}
}

type myError struct {
Error string `json:"Error,omitempty"`
}

// GEOIP

type geoipOutput struct {
IP string `json:"ip" xml:"ip,omitempty"`
CountryCode string `json:"country_code" xml:"country_code,omitempty"`
CountryName string `json:"country_name" xml:"country_name,omitempty"`
RegionCode string `json:"region_code" xml:"region_code,omitempty"`
RegionName string `json:"region_name" xml:"region_name,omitempty"`
City string `json:"city" xml:"city,omitempty"`
ZipCode string `json:"zip_code" xml:"zip_code,omitempty"`
TimeZone string `json:"time_zone" xml:"time_zone,omitempty"`
Latitude float64 `json:"latitude" xml:"latitude,omitempty"`
Longitude float64 `json:"longitude" xml:"longitude,omitempty"`
}
60 changes: 60 additions & 0 deletions geoip.go
@@ -0,0 +1,60 @@
package main

import (
"fmt"
"log"
"net"

lib "./_lib"
geoip2 "github.com/oschwald/geoip2-golang"

"net/http"
)

func doGeoipRequest(w http.ResponseWriter, f string, q string) {
o := geoipOutput{}
addr, err := net.LookupIP(q)
if err != nil {
msg := fmt.Sprintf("%s is a unknown host, not a valid IP or hostname", q)
if c.App.Mode != "test" {
log.Printf(msg + "\n")
}
e.Error = msg
lib.SendErrorToClient(w, e)
return
}
getMaxMind(addr[0].String(), &o)

if f == "xml" {
lib.SendXMLToClient(w, o)
return
}
lib.SendJSONToClient(w, o)
}

func getMaxMind(newip string, o *geoipOutput) {
db, err := geoip2.Open(c.Geoip.GeoDataBaseFile)
if err != nil {
log.Printf("ERROR reading geoip database %s", err)
return
}
defer db.Close()
ip := net.ParseIP(newip)
record, err := db.City(ip)
if err != nil {
log.Printf("ERROR reading geoip database city %s", err)
return
}
o.IP = ip.String()
o.CountryCode = record.Country.IsoCode
o.CountryName = record.Country.Names["en"]
if len(record.Subdivisions) > 0 {
o.RegionCode = record.Subdivisions[0].IsoCode
o.RegionName = record.Subdivisions[0].Names["en"]
}
o.City = record.City.Names["en"]
o.ZipCode = record.Postal.Code
o.TimeZone = record.Location.TimeZone
o.Latitude = lib.ToFixedFloat64(record.Location.Latitude, 4)
o.Longitude = lib.ToFixedFloat64(record.Location.Longitude, 4)
}

0 comments on commit 7a760e6

Please sign in to comment.