Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
jolav
committed
Nov 27, 2018
0 parents
commit 7a760e6
Showing
20 changed files
with
1,347 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
} |
Oops, something went wrong.