utils

small programs, scripts and utils
git clone https://git.e1e0.net/utils.git
Log | Files | Refs

commit 7125cc3eda3bd95d63ec07f09cf310e7bf50b09f
Author: Paco Esteban <paco@e1e0.net>
Date:   Mon, 10 Feb 2020 19:28:26 +0100

first commit with geoloc

Diffstat:
Ageoloc/.gitignore | 2++
Ageoloc/LICENSE | 13+++++++++++++
Ageoloc/Makefile | 20++++++++++++++++++++
Ageoloc/README | 39+++++++++++++++++++++++++++++++++++++++
Ageoloc/geoloc.1 | 39+++++++++++++++++++++++++++++++++++++++
Ageoloc/geoloc.c | 217+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 330 insertions(+), 0 deletions(-)

diff --git a/geoloc/.gitignore b/geoloc/.gitignore @@ -0,0 +1,2 @@ +geoloc +*.o diff --git a/geoloc/LICENSE b/geoloc/LICENSE @@ -0,0 +1,13 @@ +Copyright 2019 Paco Esteban + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/geoloc/Makefile b/geoloc/Makefile @@ -0,0 +1,20 @@ +CC = cc +CFLAGS != curl-config --cflags +LIBS != curl-config --libs +LIBS += -ljson-c +PREFIX = /usr/local + +.PHONY: all clean +.SUFFIXES: .in.1 .1 + +all: geoloc + +clean: + rm -f geoloc geoloc.o + +install: all + install -m 0755 geoloc $(PREFIX)/bin + install -m 0644 geoloc.1 $(PREFIX)/man/man1 + +geoloc: geoloc.o + $(CC) -o geoloc geoloc.o $(LIBS) diff --git a/geoloc/README b/geoloc/README @@ -0,0 +1,39 @@ +# geoloc + +## description + +`geoloc` is a small utility to get geolocalization information given an ip +address. + +It's written in C and uses [libcurl][1] and [json-c][2] do do its job. + +## installation + +``` +make +make install # with enough privileges +``` + +You'll need `libcurl` and `json-c` on the _"usual locations"_ + +If you need to make some adjustments, take a look at the `Makefile`, is +quite simple. + +## disclaimer + +This is a personal project to play with C. It is definitely not ready for any +kind of production use. This is a toy. + +## license + +Distributed under the [ISC][3] license + +## bugs + +Probably more than lines of code. +Patches are welcome. Send them to <patches@e1e0.net> + +--- +[1]: https://curl.haxx.se/libcurl/ +[2]: https://github.com/json-c/json-c +[3]: https://opensource.org/licenses/ISC diff --git a/geoloc/geoloc.1 b/geoloc/geoloc.1 @@ -0,0 +1,39 @@ +.Dd July 29, 2019 +.Dt GEOLOC 1 +.Os +.Sh NAME +.Nm geoloc +.Nd get geolocation data for IP addresses +.Sh SYNOPSIS +.Nm +.Op Fl v +.Op Fl f +.Ar ip +.Sh DESCRIPTION +.Nm +uses +.Lk https://ipapi.co/ +to get geolocation information about the provided +.Ar ip . +It accepts IPv4 or IPv6 addresses. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl v +Prints version and exists. +.It Fl f +.Dq Full , +gives more information. +.It Ar ip +The ip to look for. +This is mandatory. +.El +.Sh EXIT STATUS +.Ex -std +.Sh AUTHORS +.An Paco Esteban +.Mt paco@e1e0.net +.Sh BUGS +Probably many. +If you find one and want to send a patch, please to so to: +.Mt patches@e1e0.net diff --git a/geoloc/geoloc.c b/geoloc/geoloc.c @@ -0,0 +1,217 @@ +#include <sys/socket.h> +#include <arpa/inet.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <curl/curl.h> +#include <json-c/json.h> + +const char *version = "v0.1.0"; + +struct MemoryStruct { + char *memory; + size_t size; +}; + +// Usage function +void +usage(void) +{ + (void)fprintf(stderr, + "usage: geoloc [-v] [-f] <ip>\n"); + exit(1); +} + +// libcurl callback to write contents to memory +static size_t +WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) +{ + size_t realsize = size * nmemb; + struct MemoryStruct *mem = (struct MemoryStruct *)userp; + + char *ptr = realloc(mem->memory, mem->size + realsize + 1); + if(ptr == NULL) { + /* out of memory! */ + printf("not enough memory (realloc returned NULL)\n"); + return 0; + } + + mem->memory = ptr; + memcpy(&(mem->memory[mem->size]), contents, realsize); + mem->size += realsize; + mem->memory[mem->size] = 0; + + return realsize; +} + +int +main(int argc, char *argv[]) +{ + int ch; + int f_help = 0; + int f_full = 0; + int f_version = 0; + + int is_v4, is_v6; + void *inet_dst; // we do not actually use this. Only to check valid ip + + CURL *curl_handle; + CURLcode res; + struct MemoryStruct chunk; + char url[64]; + char *base_url = "https://ipapi.co/"; + char *json_url = "/json"; + + // we get back a json object in key/value pairs, nothing complex + struct json_object *parsed_json; + struct json_object *ip; + struct json_object *city; + struct json_object *region; + // struct json_object *region_code; + // struct json_object *country; + struct json_object *country_name; + struct json_object *continent_code; + // struct json_object *in_eu; + struct json_object *postal; + struct json_object *latitude; + struct json_object *longitude; + struct json_object *timezone; + struct json_object *utc_offset; + // struct json_object *country_calling_code; + struct json_object *currency; + // struct json_object *languages; + struct json_object *asn; + struct json_object *org; + + chunk.memory = malloc(1); /* will be grown as needed by the realloc above */ + chunk.size = 0; /* no data at this point */ + + while ((ch = getopt(argc, argv, "fv")) != -1) { + switch (ch) { + case 'f': + f_full = 1; + break; + case 'v': + f_version = 1; + break; + default: + usage(); + } + } + // remove already processed arg count and advance index in vector + argc -= optind; + argv += optind; + + if (f_version == 1) { + (void)fprintf(stderr, "%s\n", version); + return 0; + } + + if (argc < 1) { + usage(); + return 1; + } + + // validate ip input + is_v4 = inet_pton(AF_INET, argv[0], inet_dst); + is_v6 = inet_pton(AF_INET6, argv[0], inet_dst); + if ((is_v4 != 1) && (is_v6 != 1)) { + fprintf(stderr, "Not a valid IP address\n"); + return 3; + } + + // if ip is ok, create the API url we'll call + strlcpy(url, base_url, sizeof(url)); + strlcat(url, argv[0], sizeof(url)); + strlcat(url, json_url, sizeof(url)); + + curl_global_init(CURL_GLOBAL_ALL); + curl_handle = curl_easy_init(); + curl_easy_setopt(curl_handle, CURLOPT_URL, url); + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, + WriteMemoryCallback); /* send all data to this function */ + /* we pass our 'chunk' struct to the callback function */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk); + curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); + + res = curl_easy_perform(curl_handle); + + if(res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + } + else { + /* + * Now, our chunk.memory points to a memory block that is + * chunk.size bytes big and contains the remote file. + * We'll now parse the json response. + */ + + parsed_json = json_tokener_parse(chunk.memory); + json_object_object_get_ex(parsed_json, "ip", &ip); + json_object_object_get_ex(parsed_json, "city", &city); + json_object_object_get_ex(parsed_json, "region", &region); + /* json_object_object_get_ex(parsed_json, "region_code", + &region_code); */ + // json_object_object_get_ex(parsed_json, "country", &country); + json_object_object_get_ex(parsed_json, "country_name", + &country_name); + json_object_object_get_ex(parsed_json, "continent_code", + &continent_code); + // json_object_object_get_ex(parsed_json, "in_eu", &in_eu); + json_object_object_get_ex(parsed_json, "postal", &postal); + json_object_object_get_ex(parsed_json, "latitude", &latitude); + json_object_object_get_ex(parsed_json, "longitude", &longitude); + json_object_object_get_ex(parsed_json, "timezone", &timezone); + json_object_object_get_ex(parsed_json, "utc_offset", + &utc_offset); + /* json_object_object_get_ex(parsed_json, "country_calling_code", + &country_calling_code); */ + json_object_object_get_ex(parsed_json, "currency", &currency); + // json_object_object_get_ex(parsed_json, "languages", &languages); + json_object_object_get_ex(parsed_json, "asn", &asn); + json_object_object_get_ex(parsed_json, "org", &org); + + // and print the requested info + printf("Requested ip:\t%s\n", json_object_get_string(ip)); + if (f_full == 1) { + printf("Location:\t%s - %s\n", + json_object_get_string(postal), + json_object_get_string(city)); + printf("\t\t%s - %s (%s)\n", + json_object_get_string(region), + json_object_get_string(country_name), + json_object_get_string(continent_code)); + printf("\t\t%s (%s)\n", + json_object_get_string(timezone), + json_object_get_string(utc_offset)); + printf("\t\t%s\n", + json_object_get_string(currency)); + } else { + printf("Country:\t%s (%s)\n", + json_object_get_string(country_name), + json_object_get_string(postal)); + } + printf("Org:\t\t%s (%s)\n", json_object_get_string(org), + json_object_get_string(asn)); + printf("Coordinates:\t%f, %f\n", json_object_get_double(latitude), + json_object_get_double(longitude)); + printf( + "See on map:\thttps://www.openstreetmap.org/search?query=%f%%2C%f#map=12/%f/%f\n", + json_object_get_double(latitude), json_object_get_double(longitude), + json_object_get_double(latitude), json_object_get_double(longitude)); + } + + /* cleanup curl stuff */ + curl_easy_cleanup(curl_handle); + + free(chunk.memory); + + /* we're done with libcurl, so clean it up */ + curl_global_cleanup(); + + return 0; +}