1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
|
#include "iprange.h"
static uint32_t endianness = 0x1A2B3C4D;
/* ----------------------------------------------------------------------------
* binary files v1.0
*
*/
int ipset_load_binary_v10(FILE *fp, ipset *ips, int first_line_missing) {
char buffer[MAX_LINE + 1], *s;
unsigned long entries, bytes, lines, unique_ips;
uint32_t endian;
size_t loaded;
if(!first_line_missing) {
s = fgets(buffer, MAX_LINE, fp);
buffer[MAX_LINE] = '\0';
if(!s || strcmp(s, BINARY_HEADER_V10)) {
fprintf(stderr, "%s: %s expecting binary header but found '%s'.\n", PROG, ips->filename, s?s:"");
return 1;
}
}
s = fgets(buffer, MAX_LINE, fp);
buffer[MAX_LINE] = '\0';
if(!s || ( strcmp(s, "optimized\n") && strcmp(s, "non-optimized\n") )) {
fprintf(stderr, "%s: %s 2nd line should be the optimized flag, but found '%s'.\n", PROG, ips->filename, s?s:"");
return 1;
}
if(!strcmp(s, "optimized\n")) ips->flags |= IPSET_FLAG_OPTIMIZED;
else ips->flags &= ~IPSET_FLAG_OPTIMIZED;
s = fgets(buffer, MAX_LINE, fp);
buffer[MAX_LINE] = '\0';
if(!s || strncmp(s, "record size ", 12)) {
fprintf(stderr, "%s: %s 3rd line should be the record size, but found '%s'.\n", PROG, ips->filename, s?s:"");
return 1;
}
if(atol(&s[12]) != sizeof(network_addr_t)) {
fprintf(stderr, "%s: %s: invalid record size %ld (expected %lu)\n", PROG, ips->filename, atol(&s[12]), (unsigned long)sizeof(network_addr_t));
return 1;
}
s = fgets(buffer, MAX_LINE, fp);
buffer[MAX_LINE] = '\0';
if(!s || strncmp(s, "records ", 8)) {
fprintf(stderr, "%s: %s 4th line should be the number of records, but found '%s'.\n", PROG, ips->filename, s?s:"");
return 1;
}
entries = strtoul(&s[8], NULL, 10);
s = fgets(buffer, MAX_LINE, fp);
buffer[MAX_LINE] = '\0';
if(!s || strncmp(s, "bytes ", 6)) {
fprintf(stderr, "%s: %s 5th line should be the number of bytes, but found '%s'.\n", PROG, ips->filename, s?s:"");
return 1;
}
bytes = strtoul(&s[6], NULL, 10);
s = fgets(buffer, MAX_LINE, fp);
buffer[MAX_LINE] = '\0';
if(!s || strncmp(s, "lines ", 6)) {
fprintf(stderr, "%s: %s 6th line should be the number of lines read, but found '%s'.\n", PROG, ips->filename, s?s:"");
return 1;
}
lines = strtoul(&s[6], NULL, 10);
s = fgets(buffer, MAX_LINE, fp);
buffer[MAX_LINE] = '\0';
if(!s || strncmp(s, "unique ips ", 11)) {
fprintf(stderr, "%s: %s 7th line should be the number of unique IPs, but found '%s'.\n", PROG, ips->filename, s?s:"");
return 1;
}
unique_ips = strtoul(&s[11], NULL, 10);
if(bytes != ((sizeof(network_addr_t) * entries) + sizeof(uint32_t))) {
fprintf(stderr, "%s: %s invalid number of bytes, found %lu, expected %lu.\n", PROG, ips->filename, bytes, ((sizeof(network_addr_t) * entries) + sizeof(uint32_t)));
return 1;
}
loaded = fread(&endian, sizeof(uint32_t), 1, fp);
if(loaded != 1) {
fprintf(stderr, "%s: %s: cannot load ipset header\n", PROG, ips->filename);
return 1;
}
if(endian != endianness) {
fprintf(stderr, "%s: %s: incompatible endianness\n", PROG, ips->filename);
return 1;
}
if(unique_ips < entries) {
fprintf(stderr, "%s: %s: unique IPs (%lu) cannot be less than entries (%lu)\n", PROG, ips->filename, unique_ips, entries);
return 1;
}
if(lines < entries) {
fprintf(stderr, "%s: %s: lines (%lu) cannot be less than entries (%lu)\n", PROG, ips->filename, lines, entries);
return 1;
}
ipset_grow(ips, entries);
loaded = fread(&ips->netaddrs[ips->entries], sizeof(network_addr_t), entries, fp);
if(loaded != entries) {
fprintf(stderr, "%s: %s: expected to load %lu entries, loaded %zu\n", PROG, ips->filename, entries, loaded);
return 1;
}
ips->entries += loaded;
ips->lines += lines;
ips->unique_ips += unique_ips;
return 0;
}
void ipset_save_binary_v10(ipset *ips) {
// it is crucial not to generate any output
// if the ipset is empty:
// the caller may do 'test -s file' to check it
if(!ips->entries) return;
fprintf(stdout, BINARY_HEADER_V10);
if(ips->flags & IPSET_FLAG_OPTIMIZED) fprintf(stdout, "optimized\n");
else fprintf(stdout, "non-optimized\n");
fprintf(stdout, "record size %zu\n", sizeof(network_addr_t));
fprintf(stdout, "records %zu\n", ips->entries);
fprintf(stdout, "bytes %zu\n", (sizeof(network_addr_t) * ips->entries) + sizeof(uint32_t));
fprintf(stdout, "lines %zu\n", ips->entries);
fprintf(stdout, "unique ips %zu\n", ips->unique_ips);
fwrite(&endianness, sizeof(uint32_t), 1, stdout);
fwrite(ips->netaddrs, sizeof(network_addr_t), ips->entries, stdout);
}
|