Skip to content

Instantly share code, notes, and snippets.

@Snawoot
Created June 26, 2015 14:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save Snawoot/7826240899835a5878b6 to your computer and use it in GitHub Desktop.
Save Snawoot/7826240899835a5878b6 to your computer and use it in GitHub Desktop.
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <byteswap.h>
#include <maxminddb.h>
#define STR_MAX 256
void usage(char *progname) {
fprintf(stderr,
"Usage:\n%s <mmdb file> <start ip_address> <end ip_address>\n", progname);
exit(6);
}
void emit_range(in_addr_t start, in_addr_t end, char *value) {
in_addr_t base = start, step;
while (base <= end)
{
step = 0;
while ((base | (1 << step)) != base) {
if ((base | (((~0) & 0xffffffff) >> (31-step))) > end) {
break;
}
step++;
}
struct in_addr base_s;
base_s.s_addr = bswap_32(base);
printf("%s/%d %s;\n", inet_ntoa(base_s), 32-step, value);
base += 1 << step;
}
}
int main(int argc, char **argv)
{
//Validate arguments count
if (argc != 4) usage(argv[0]);
char *mmdbfname = argv[1], *startipstr = argv[2], *endipstr = argv[3];
//Parse arguments
struct in_addr s_startip, s_endip;
if ( ! (inet_aton(startipstr, &s_startip) && inet_aton(endipstr, &s_endip)) ) {
fprintf(stderr, "Garbage input: ipaddress is not recognized.\n");
return 7;
}
//Convert network address form to normal byte order and validate range
in_addr_t startip = bswap_32(s_startip.s_addr), endip = bswap_32(s_endip.s_addr);
if (startip > endip) {
fprintf(stderr, "Garbage input: startip is higher than endip.\n");
return 8;
}
//Open MaxMind database
MMDB_s mmdb;
int status = MMDB_open(mmdbfname, MMDB_MODE_MMAP, &mmdb);
if (MMDB_SUCCESS != status) {
fprintf(stderr, "\n Can't open %s - %s\n",
mmdbfname, MMDB_strerror(status));
if (MMDB_IO_ERROR == status) {
fprintf(stderr, " IO error: %s\n", strerror(errno));
}
return 1;
}
//Query all range
struct sockaddr_in curr_sa;
curr_sa.sin_family = AF_INET;
in_addr_t i=startip, rangestart=startip;
char lastisocode[] = "\0\0", isocode[] = "\0\0";
for (; i <= endip ; i++) {
*isocode = '\0';
curr_sa.sin_addr.s_addr = bswap_32(i);
int mmdb_error;
MMDB_lookup_result_s result =
MMDB_lookup_sockaddr(&mmdb, (struct sockaddr*)&curr_sa, &mmdb_error);
if (MMDB_SUCCESS == mmdb_error) {
MMDB_entry_data_s entry_data;
status =
MMDB_get_value(&result.entry, &entry_data, "country", "iso_code", NULL);
if (
MMDB_SUCCESS == status &&
entry_data.has_data &&
entry_data.type == MMDB_DATA_TYPE_UTF8_STRING
) {
strncpy(isocode, entry_data.utf8_string, sizeof(isocode)-1);
if (strcmp(isocode, "UA") == 0) {
status =
MMDB_get_value(&result.entry, &entry_data, "subdivisions", "0", "names", "en", NULL);
if (
MMDB_SUCCESS == status &&
entry_data.has_data &&
entry_data.type == MMDB_DATA_TYPE_UTF8_STRING
) {
char subdiv[STR_MAX];
size_t border = (entry_data.data_size > sizeof(subdiv)-1) ? sizeof(subdiv)-1 : entry_data.data_size;
strncpy(subdiv, entry_data.utf8_string, border);
subdiv[border] = '\0';
if (
strstr(subdiv, "Sevastopol") ||
strstr(subdiv, "Crimea")
) strcpy(isocode, "RU");
}
}
}
}
if (strcmp(isocode, lastisocode)) {
if (*lastisocode) emit_range(rangestart, i-1, lastisocode);
strcpy(lastisocode, isocode);
rangestart = i;
}
if (i == endip) break;
}
if (*lastisocode) emit_range(rangestart, endip, lastisocode);
MMDB_close(&mmdb);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment