statzone.cpp (4624B)
1 /* 2 * StatZone 1.1.1 3 * Copyright (c) 2012-2022, Frederic Cambus 4 * https://www.statdns.com 5 * 6 * Created: 2012-02-13 7 * Last Updated: 2022-02-25 8 * 9 * StatZone is released under the BSD 2-Clause license. 10 * See LICENSE file for details. 11 * 12 * SPDX-License-Identifier: BSD-2-Clause 13 */ 14 15 #include <getopt.h> 16 #include <string.h> 17 18 #include <chrono> 19 #include <csignal> 20 #include <iostream> 21 #include <string> 22 #include <unordered_set> 23 24 #ifdef HAVE_SECCOMP 25 #include <sys/prctl.h> 26 #include <linux/seccomp.h> 27 #include "seccomp.h" 28 #endif 29 30 #include "config.hpp" 31 #include "strtolower.hpp" 32 33 std::chrono::steady_clock::time_point begin, current, elapsed; 34 struct results results; 35 36 static void 37 usage() 38 { 39 printf("statzone [-hv] zonefile\n\n" 40 "The options are as follows:\n\n" 41 " -h Display usage.\n" 42 " -v Display version.\n"); 43 } 44 45 static void 46 summary() 47 { 48 /* Get current timer value */ 49 current = std::chrono::steady_clock::now(); 50 51 /* Print summary */ 52 std::cerr << "Processed " << results.processedLines << " lines in "; 53 std::cerr << std::chrono::duration_cast<std::chrono::microseconds>(current - begin).count() / 1E6; 54 std::cerr << " seconds." << std::endl; 55 } 56 57 #ifdef SIGINFO 58 void 59 siginfo_handler(int signum) 60 { 61 summary(); 62 } 63 #endif 64 65 int 66 main(int argc, char *argv[]) 67 { 68 std::unordered_set<std::string> signed_domains; 69 std::unordered_set<std::string> unique_ns; 70 71 int opt, token_count; 72 73 char *linebuffer = NULL; 74 size_t linesize = 0; 75 76 char *input; 77 std::string domain, previous_domain; 78 char *rdata, *token = nullptr, *token_lc = nullptr; 79 80 FILE *zonefile; 81 82 #ifdef HAVE_SECCOMP 83 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 84 perror("Can't initialize seccomp"); 85 return EXIT_FAILURE; 86 } 87 88 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &statzone)) { 89 perror("Can't load seccomp filter"); 90 return EXIT_FAILURE; 91 } 92 #endif 93 94 #ifdef SIGINFO 95 signal(SIGINFO, siginfo_handler); 96 #endif 97 98 while ((opt = getopt(argc, argv, "hv")) != -1) { 99 switch (opt) { 100 101 case 'h': 102 usage(); 103 return EXIT_SUCCESS; 104 105 case 'v': 106 printf("%s\n", VERSION); 107 return EXIT_SUCCESS; 108 } 109 } 110 111 if (optind < argc) { 112 input = argv[optind]; 113 } else { 114 usage(); 115 return EXIT_SUCCESS; 116 } 117 118 /* Starting timer */ 119 begin = std::chrono::steady_clock::now(); 120 121 /* Open zone file */ 122 if (!strcmp(input, "-")) { 123 /* Read from standard input */ 124 zonefile = stdin; 125 } else { 126 /* Attempt to read from file */ 127 if (!(zonefile = fopen(input, "r"))) { 128 perror("Can't open zone file"); 129 return EXIT_FAILURE; 130 } 131 } 132 133 while (getline(&linebuffer, &linesize, zonefile) != -1) { 134 if (!*linebuffer) 135 continue; 136 137 if (*linebuffer == ';') /* Comments */ 138 continue; 139 140 if (*linebuffer == '$') /* Directives */ 141 continue; 142 143 token_count = 0; 144 token = strtok(linebuffer, " \t"); 145 146 if (token) 147 domain = strtolower(token); 148 149 while (token) { 150 if (*token == ';') { /* Comments */ 151 token = nullptr; 152 continue; 153 } 154 155 token_lc = strtolower(token); 156 if (token_count && !strcmp(token_lc, "nsec")) { 157 token = nullptr; 158 continue; 159 } 160 161 if (token_count && !strcmp(token_lc, "nsec3")) { 162 token = nullptr; 163 continue; 164 } 165 166 if (token_count && !strcmp(token_lc, "rrsig")) { 167 token = nullptr; 168 continue; 169 } 170 171 if (token_count && !strcmp(token_lc, "a")) 172 results.a++; 173 174 if (token_count && !strcmp(token_lc, "aaaa")) 175 results.aaaa++; 176 177 if (token_count && !strcmp(token_lc, "ds")) { 178 results.ds++; 179 180 signed_domains.insert(domain); 181 } 182 183 if (!strcmp(token_lc, "ns")) { 184 results.ns++; 185 186 if (domain.compare(previous_domain)) { 187 results.domains++; 188 189 previous_domain = domain; 190 191 if (!domain.compare(0, 4, "xn--")) 192 results.idn++; 193 } 194 195 rdata = strtok(nullptr, "\n"); 196 197 if (rdata && strchr(rdata, ' ')) 198 rdata = strtok(nullptr, "\n"); 199 200 if (rdata) 201 unique_ns.insert(rdata); 202 } 203 204 token = strtok(nullptr, " \t"); 205 token_count++; 206 } 207 208 results.processedLines++; 209 } 210 211 /* Don't count origin */ 212 if (results.domains) 213 results.domains--; 214 215 /* Printing CVS values */ 216 std::cout << "---[ CSV values ]--------------------------------------------------------------" << std::endl; 217 std::cout << "IPv4 Glue,IPv6 Glue,NS,Unique NS,DS,Signed,IDNs,Domains" << std::endl; 218 std::cout << results.a << ","; 219 std::cout << results.aaaa << ","; 220 std::cout << results.ns << ","; 221 std::cout << unique_ns.size() << ","; 222 std::cout << results.ds << ","; 223 std::cout << signed_domains.size() << ","; 224 std::cout << results.idn << ","; 225 std::cout << results.domains << std::endl; 226 227 /* Printing results */ 228 summary(); 229 230 /* Clean up */ 231 free(linebuffer); 232 fclose(zonefile); 233 234 return EXIT_SUCCESS; 235 }