Add a routine to fetch raw bytes into a fixed-length buffer as a string.
[gd/wireshark/.git] / mmdbresolve.c
1 /* Read IPv4 and IPv6 addresses on stdin and print their MMDB entries on stdout.
2  *
3  * Wireshark - Network traffic analyzer
4  * By Gerald Combs <gerald@wireshark.org>
5  * Copyright 1998 Gerald Combs
6  *
7  * This progam uses the MaxMind DB library (libmaxminddb) and MUST be
8  * compatible with its license (Apache 2.0).
9  *
10  * SPDX-License-Identifier: MIT
11  *
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <errno.h>
17 #include <string.h>
18
19 #include <maxminddb.h>
20
21 #define MAX_ADDR_LEN 46
22 #define MMDBR_STRINGIFY(x) MMDBR_STRINGIFY_S(x)
23 #define MMDBR_STRINGIFY_S(s) #s
24 #define OUT_BUF_SIZE 65536
25
26 // Uncomment to enable slow lookups. Only useful on Windows for now.
27 // #define MMDB_DEBUG_SLOW 1
28
29 #ifdef MMDB_DEBUG_SLOW
30 #ifdef _WIN32
31 #include <Windows.h>
32 #endif
33 #endif
34
35 static const char *co_iso_key[]     = {"country", "iso_code", NULL};
36 static const char *co_name_key[]    = {"country", "names", "en", NULL};
37 static const char *ci_name_key[]    = {"city", "names", "en", NULL};
38 static const char *asn_o_key[]      = {"autonomous_system_organization", NULL};
39 static const char *asn_key[]        = {"autonomous_system_number", NULL};
40 static const char *l_lat_key[]      = {"location", "latitude", NULL};
41 static const char *l_lon_key[]      = {"location", "longitude", NULL};
42 static const char *l_accuracy_key[] = {"location", "accuracy_radius", NULL};
43 static const char *empty_key[]      = {NULL};
44
45 static const char **lookup_keys[] = {
46     co_iso_key,
47     co_name_key,
48     ci_name_key,
49     asn_o_key,
50     asn_key,
51     l_lat_key,
52     l_lon_key,
53     l_accuracy_key,
54     empty_key
55 };
56
57 static void exit_err(void) {
58     fprintf(stderr, "Usage: mmdbresolve -f db_file [-f db_file ...]\n");
59     exit(1);
60 }
61
62 int
63 main(int argc, char *argv[])
64 {
65     char addr_str[MAX_ADDR_LEN+1];
66     size_t mmdb_count = 0;
67     MMDB_s *mmdbs = NULL, *new_mmdbs;
68     int mmdb_err;
69
70     char *out_buf = (char *) malloc(OUT_BUF_SIZE);
71     if (out_buf == NULL) {
72         fprintf(stdout, "ERROR: malloc failed\n");
73         return 1;
74     }
75     setvbuf(stdout, out_buf, _IOFBF, OUT_BUF_SIZE);
76
77     fprintf(stdout, "[init]\n");
78
79     // If we need to handle anything beyond "-f" we'll probably want to
80     // link with GLib and use GOption.
81     int arg_idx = 0;
82     while (arg_idx < argc - 1) {
83         if (strcmp(argv[arg_idx], "-f") == 0) {
84             arg_idx++;
85             const char *db_arg = argv[arg_idx];
86             MMDB_s try_mmdb;
87             mmdb_err = MMDB_open(db_arg, 0, &try_mmdb);
88             fprintf(stdout, "db.%zd.path: %s\n", mmdb_count, db_arg);
89             fprintf(stdout, "db.%zd.status: ", mmdb_count);
90             if (mmdb_err == MMDB_SUCCESS) {
91                 mmdb_count++;
92                 new_mmdbs = (MMDB_s *) realloc(mmdbs, mmdb_count * sizeof(MMDB_s));
93                 if (new_mmdbs == NULL) {
94                     free(mmdbs);
95                     fprintf(stdout, "ERROR out of memory\n");
96                     return 1;
97                 }
98                 mmdbs = new_mmdbs;
99                 mmdbs[mmdb_count - 1] = try_mmdb;
100                 fprintf(stdout, "OK\n");
101                 fprintf(stdout, "db.%zd.type: %s\n", mmdb_count, mmdbs[mmdb_count - 1].metadata.database_type);
102             } else {
103                 fprintf(stdout, "ERROR %s\n", MMDB_strerror(mmdb_err));
104             }
105         }
106         arg_idx++;
107     }
108
109     fprintf(stdout, "mmdbresolve.status: %s\n", mmdb_count > 0 ? "true": "false");
110     fprintf(stdout, "# End init\n");
111     fflush(stdout);
112
113     if (arg_idx != argc || mmdb_count < 1) {
114         exit_err();
115     }
116
117     int in_items = 0;
118     while (in_items != EOF) {
119         int gai_err;
120
121         in_items = fscanf(stdin, "%" MMDBR_STRINGIFY(MAX_ADDR_LEN) "s", addr_str);
122
123         if (in_items < 1) {
124             continue;
125         }
126
127         fprintf(stdout, "[%s]\n", addr_str);
128
129 #ifdef MMDB_DEBUG_SLOW
130 #ifdef _WIN32
131         Sleep(1000);
132 #endif
133 #endif
134
135         for (size_t mmdb_idx = 0; mmdb_idx < mmdb_count; mmdb_idx++) {
136             fprintf(stdout, "# %s\n", mmdbs[mmdb_idx].metadata.database_type);
137             MMDB_lookup_result_s result = MMDB_lookup_string(&mmdbs[mmdb_idx], addr_str, &gai_err, &mmdb_err);
138
139             if (result.found_entry && gai_err == 0 && mmdb_err == MMDB_SUCCESS) {
140                 for (size_t key_idx = 0; lookup_keys[key_idx][0]; key_idx++) {
141                     MMDB_entry_data_s entry_data;
142                     int status = MMDB_aget_value(&result.entry, &entry_data, lookup_keys[key_idx]);
143                     if (status == MMDB_SUCCESS && entry_data.has_data) {
144                         char *sep = "";
145                         for (int idx = 0; lookup_keys[key_idx][idx] != 0; idx++) {
146                             fprintf(stdout, "%s%s", sep, lookup_keys[key_idx][idx]);
147                             sep = ".";
148                         }
149                         switch (entry_data.type) {
150                             case MMDB_DATA_TYPE_UTF8_STRING:
151                             {
152                                 char len_fmt[12]; // : %.xxxxxs\n\0
153                                 snprintf(len_fmt, 11, ": %%.%us\n", entry_data.data_size);
154                                 fprintf(stdout, len_fmt, entry_data.utf8_string);
155                             }
156                             break;
157                             case MMDB_DATA_TYPE_UINT16:
158                                 fprintf(stdout, ": %u\n", entry_data.uint16);
159                                 break;
160                             case MMDB_DATA_TYPE_UINT32:
161                                 fprintf(stdout, ": %u\n", entry_data.uint32);
162                                 break;
163                             case MMDB_DATA_TYPE_INT32:
164                                 fprintf(stdout, ": %d\n", entry_data.int32);
165                                 break;
166                             case MMDB_DATA_TYPE_BOOLEAN:
167                                 fprintf(stdout, ": %s\n", entry_data.boolean ? "True" : "False");
168                                 break;
169                             case MMDB_DATA_TYPE_DOUBLE:
170                                 fprintf(stdout, ": %f\n", entry_data.double_value);
171                                 break;
172                             case MMDB_DATA_TYPE_FLOAT:
173                                 fprintf(stdout, ": %f\n", entry_data.float_value);
174                                 break;
175                             default:
176                                 fprintf(stdout, ": UNKNOWN (%u)\n", entry_data.type);
177                         }
178                     }
179                 }
180             } else {
181                 // dump error info.
182             }
183         }
184         fprintf(stdout, "# End %s\n", addr_str);
185         fflush(stdout);
186     }
187
188     free(mmdbs);
189
190     return 0;
191 }
192
193 /*
194  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
195  *
196  * Local variables:
197  * c-basic-offset: 4
198  * tab-width: 8
199  * indent-tabs-mode: nil
200  * End:
201  *
202  * vi: set shiftwidth=4 tabstop=8 expandtab:
203  * :indentSize=4:tabSize=8:noTabs=true:
204  */