mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
137 lines
6 KiB
C
137 lines
6 KiB
C
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
|
│ │
|
|
│ 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. │
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
#include "libc/calls/calls.h"
|
|
#include "libc/intrin/bits.h"
|
|
#include "libc/log/check.h"
|
|
#include "libc/log/log.h"
|
|
#include "libc/mem/gc.internal.h"
|
|
#include "libc/mem/mem.h"
|
|
#include "libc/stdio/stdio.h"
|
|
#include "net/http/http.h"
|
|
#include "net/http/ip.h"
|
|
#include "third_party/maxmind/maxminddb.h"
|
|
|
|
#define PATH(...) \
|
|
(const char *const[]) { \
|
|
__VA_ARGS__, 0 \
|
|
}
|
|
|
|
MMDB_s *ipdb, *asdb;
|
|
|
|
int PrintIpInfo(const char *ipstr) {
|
|
int error;
|
|
bool uhoh;
|
|
int64_t ip;
|
|
uint16_t cc;
|
|
MMDB_entry_data_s e, f;
|
|
MMDB_lookup_result_s r;
|
|
if ((ip = ParseIp(ipstr, -1)) == -1) {
|
|
fprintf(stderr, "BAD IP: %s\n", ipstr);
|
|
return -1;
|
|
}
|
|
r = MMDB_lookup(ipdb, ip, &error);
|
|
CHECK_EQ(MMDB_SUCCESS, error);
|
|
if (!r.found_entry) {
|
|
fprintf(stderr, "NOT FOUND: %s\n", ipstr);
|
|
return -1;
|
|
}
|
|
printf("%hhu.%hhu.%hhu.%hhu\n", ip >> 24, ip >> 16, ip >> 8, ip);
|
|
if (!MMDB_aget_value(&r.entry, &e, PATH("location", "metro_code"))) {
|
|
printf("%s: %s\n", "metro", GetMetroName(e.uint16));
|
|
}
|
|
if (!MMDB_aget_value(&r.entry, &e, PATH("postal", "code"))) {
|
|
printf("%s: %.*s\n", "postal", e.data_size, e.utf8_string);
|
|
}
|
|
if (!MMDB_aget_value(&r.entry, &e, PATH("city", "names", "en"))) {
|
|
printf("%s: %.*s\n", "city", e.data_size, e.utf8_string);
|
|
}
|
|
if (!MMDB_aget_value(&r.entry, &e, PATH("subdivisions", "0", "iso_code")) &&
|
|
!MMDB_aget_value(&r.entry, &f,
|
|
PATH("subdivisions", "0", "names", "en"))) {
|
|
printf("%s: %.*s (%.*s)\n", "region", e.data_size, e.utf8_string,
|
|
f.data_size, f.utf8_string);
|
|
}
|
|
if (!MMDB_aget_value(&r.entry, &e, PATH("country", "iso_code")) &&
|
|
!MMDB_aget_value(&r.entry, &f, PATH("country", "names", "en"))) {
|
|
printf("%s: %.*s (%.*s)\n", "country", e.data_size, e.utf8_string,
|
|
f.data_size, f.utf8_string);
|
|
cc = READ16LE(e.utf8_string);
|
|
} else {
|
|
cc = 0;
|
|
}
|
|
if (!MMDB_aget_value(&r.entry, &e, PATH("registered_country", "iso_code")) &&
|
|
!MMDB_aget_value(&r.entry, &f,
|
|
PATH("registered_country", "names", "en"))) {
|
|
uhoh = cc && cc != READ16LE(e.utf8_string);
|
|
printf("%s%s: %.*s (%.*s)%s\n", uhoh ? "\e[1m" : "", "registered",
|
|
e.data_size, e.utf8_string, f.data_size, f.utf8_string,
|
|
uhoh ? "\e[0m" : "");
|
|
}
|
|
if ((!MMDB_aget_value(&r.entry, &e,
|
|
PATH("country", "is_in_european_union")) &&
|
|
e.boolean) ||
|
|
(!MMDB_aget_value(&r.entry, &e,
|
|
PATH("registered_country", "is_in_european_union")) &&
|
|
e.boolean)) {
|
|
printf("%s: %s\n", "is_in_european_union", "true");
|
|
}
|
|
if (!MMDB_aget_value(&r.entry, &e, PATH("continent", "code")) &&
|
|
!MMDB_aget_value(&r.entry, &f, PATH("continent", "names", "en"))) {
|
|
printf("%s: %.*s (%.*s)\n", "continent", e.data_size, e.utf8_string,
|
|
f.data_size, f.utf8_string);
|
|
}
|
|
if (!MMDB_aget_value(&r.entry, &e, PATH("location", "time_zone"))) {
|
|
printf("%s: %.*s\n", "timezone", e.data_size, e.utf8_string);
|
|
}
|
|
if (!MMDB_aget_value(&r.entry, &e, PATH("location", "latitude")) &&
|
|
!MMDB_aget_value(&r.entry, &f, PATH("location", "longitude"))) {
|
|
printf("%s: %g %g\n", "location", e.double_value, f.double_value);
|
|
}
|
|
if (!MMDB_aget_value(&r.entry, &e, PATH("location", "accuracy_radius"))) {
|
|
printf("%s: %dkm\n", "accuracy", e.uint16);
|
|
}
|
|
printf("%s: %s\n", "category", GetIpCategoryName(CategorizeIp(ip)));
|
|
if ((r = MMDB_lookup(asdb, ip, &error)).found_entry &&
|
|
!MMDB_aget_value(&r.entry, &e, PATH("autonomous_system_number")) &&
|
|
!MMDB_aget_value(&r.entry, &f, PATH("autonomous_system_organization"))) {
|
|
printf("%s: AS%u (%.*s)\n", "asn", e.uint32, f.data_size, f.utf8_string);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
int i, rc;
|
|
ipdb = gc(calloc(1, sizeof(MMDB_s)));
|
|
CHECK_EQ(MMDB_SUCCESS,
|
|
MMDB_open("/usr/local/share/maxmind/GeoLite2-City.mmdb", 0, ipdb));
|
|
asdb = gc(calloc(1, sizeof(MMDB_s)));
|
|
CHECK_EQ(MMDB_SUCCESS,
|
|
MMDB_open("/usr/local/share/maxmind/GeoLite2-ASN.mmdb", 0, asdb));
|
|
for (rc = 0, i = 1; i < argc; ++i) {
|
|
if (PrintIpInfo(argv[i]) != -1) {
|
|
if (i + 1 < argc) printf("\n");
|
|
} else {
|
|
fprintf(stderr, "NOT FOUND: %s\n", argv[i]);
|
|
rc = 1;
|
|
}
|
|
}
|
|
MMDB_close(asdb);
|
|
MMDB_close(ipdb);
|
|
return rc;
|
|
}
|