Exports and imports of transaction database. mats
authorMats Erik Andersson <debian@gisladisker.se>
Thu, 14 Oct 2010 16:43:54 +0000 (18:43 +0200)
committerEmil Mikulic <emikulic@gmail.com>
Mon, 9 May 2011 13:16:57 +0000 (23:16 +1000)
The importing of databases is backwards compatible to the
previous version 3.0.173 of Darkstat. Exporting always uses
a new graph format that includes stanzas for IPv6 traffic.

Likwise a new version of host exports writes the IPv6 address
for such hosts. Importing senses whatever formats were stored.

darkstat.8.in
db.c
export-format.txt
graph_db.c
graph_db.h
hosts_db.c

index 471f0a1..88a0dc4 100644 (file)
@@ -230,8 +230,14 @@ with this, do not use the \fB\-\-daylog\fR functionality.
 If the daylog argument is not specified, no logging is performed.
 
 The daylog format is:
-
+.IP
 localtime|time_t|bytes_in|bytes_out|pkts_in|pkts_outs
+.PP
+possibly augmented on the right by two further fields
+.IP
+|bytes_in6|bytes_out6
+.PP
+These latter are present in IPv6 capable versions of \fIdarkstat\fR.
 
 Lines starting with a # are comments stating when logging started and
 stopped.
diff --git a/db.c b/db.c
index 6a15ade..232a002 100644 (file)
--- a/db.c
+++ b/db.c
@@ -26,6 +26,7 @@
 static const unsigned char export_file_header[] = {0xDA, 0x31, 0x41, 0x59};
 static const unsigned char export_tag_hosts_ver1[] = {0xDA, 'H', 'S', 0x01};
 static const unsigned char export_tag_graph_ver1[] = {0xDA, 'G', 'R', 0x01};
+static const unsigned char export_tag_graph_ver2[] = {0xDA, 'G', 'R', 0x02};
 
 #ifndef swap64
 static inline uint64_t
@@ -286,11 +287,24 @@ read_file_header(const int fd, const uint8_t expected[4])
 static int
 db_import_from_fd(const int fd)
 {
+   int version = 0;
+   char hdr[4];
+
    if (!read_file_header(fd, export_file_header)) return 0;
    if (!read_file_header(fd, export_tag_hosts_ver1)) return 0;
    if (!hosts_db_import(fd)) return 0;
-   if (!read_file_header(fd, export_tag_graph_ver1)) return 0;
-   if (!graph_import(fd)) return 0;
+   if (!readn(fd, hdr, sizeof(hdr))) return 0;
+   if (memcmp(hdr, export_tag_graph_ver2, sizeof(hdr)) == 0)
+      version = 2;
+   else if (memcmp(hdr, export_tag_graph_ver1, sizeof(hdr)) == 0)
+      version = 1;
+   else {
+      warnx("bad graph header: %02x%02x%02x%02x",
+         hdr[0], hdr[1], hdr[2], hdr[3]);
+      return 0;
+   }
+   verbosef("Found graphs exported in version %d.", version);
+   if (!graph_import(fd, version)) return 0;
    return 1;
 }
 
@@ -321,9 +335,9 @@ db_export_to_fd(const int fd)
       return 0;
    if (!hosts_db_export(fd))
       return 0;
-   if (!writen(fd, export_tag_graph_ver1, sizeof(export_tag_graph_ver1)))
+   if (!writen(fd, export_tag_graph_ver2, sizeof(export_tag_graph_ver2)))
       return 0;
-   if (!graph_export(fd))
+   if (!graph_export(fd, 2 /* version */))
       return 0;
    return 1;
 }
index 11d7978..f05fb88 100644 (file)
@@ -43,4 +43,22 @@ FILE HEADER 0xDA314159                              darkstat export format
                 64 bits - bytes in
                 64 bits - bytes out
 
-Host header version 1 is just version 2 without the last_seen time.
+Alternate formats:
+
+A) Host header version 1 is just version 2 without the last_seen time.
+
+B) Host header version 3 replaces the IPv4 address with an IPv6 address,
+   and all byte counters refer to IPv6 traffic for the particular host.
+
+C) Graph header version 2 adds IPv6 counters:
+
+    SECTION HEADER 0xDA 'G' 'R' 0x02                graph_db ver2
+        LAST_TIME (time_t as 64-bit uint)
+        For each of 4 graphs: (60 seconds, 60 minutes, 24 hours, 31 days)
+            8 bits - number of bars in this graph
+            8 bits - index of last_time bar, in the range [0:n_bars)
+            For each bar:
+                64 bits - bytes in IPv4
+                64 bits - bytes out IPv4
+                64 bits - bytes in IPv6
+                64 bits - bytes out IPv6
index 62f0975..c186c90 100644 (file)
@@ -256,7 +256,7 @@ graph_rotate(void)
  * the start of the data.
  */
 int
-graph_import(const int fd)
+graph_import(const int fd, int version)
 {
    uint64_t last;
    unsigned int i, j;
@@ -290,8 +290,11 @@ graph_import(const int fd)
       for (j=0; j<num_bars; j++) {
          if (!read64(fd, &(graph_db[i]->in[j]))) return 0;
          if (!read64(fd, &(graph_db[i]->out[j]))) return 0;
-         if (!read64(fd, &(graph_db[i]->in6[j]))) return 0;
-         if (!read64(fd, &(graph_db[i]->out6[j]))) return 0;
+         if (version >= 2) {
+            if (!read64(fd, &(graph_db[i]->in6[j]))) return 0;
+            if (!read64(fd, &(graph_db[i]->out6[j]))) return 0;
+         } else
+            graph_db[i]->in6[j] = graph_db[i]->out6[j] = 0;
       }
    }
 
@@ -303,7 +306,7 @@ graph_import(const int fd)
  * The caller is responsible for writing out the header first.
  */
 int
-graph_export(const int fd)
+graph_export(const int fd, int version)
 {
    unsigned int i, j;
 
@@ -315,8 +318,10 @@ graph_export(const int fd)
       for (j=0; j<graph_db[i]->num_bars; j++) {
          if (!write64(fd, graph_db[i]->in[j])) return 0;
          if (!write64(fd, graph_db[i]->out[j])) return 0;
-         if (!write64(fd, graph_db[i]->in6[j])) return 0;
-         if (!write64(fd, graph_db[i]->out6[j])) return 0;
+         if (version >= 2) {
+            if (!write64(fd, graph_db[i]->in6[j])) return 0;
+            if (!write64(fd, graph_db[i]->out6[j])) return 0;
+         }
       }
    }
    return 1;
index 2940ff7..93e6f7a 100644 (file)
@@ -20,8 +20,8 @@ void graph_reset(void);
 void graph_free(void);
 void graph_acct(uint64_t amount, enum graph_dir dir);
 void graph_rotate(void);
-int graph_import(const int fd);
-int graph_export(const int fd);
+int graph_import(const int fd, int version);
+int graph_export(const int fd, int version);
 
 struct str *html_front_page(void);
 struct str *xml_graphs(void);
index d0d0b85..c490c02 100644 (file)
@@ -1119,8 +1119,9 @@ static const char
    export_proto_udp = 'U';
 
 static const unsigned char
-   export_tag_host_ver1[] = {'H', 'S', 'T', 0x01},
-   export_tag_host_ver2[] = {'H', 'S', 'T', 0x02};
+   export_tag_host_ver1[] = {'H', 'S', 'T', 0x01}, /* IPv4 host, no timing */
+   export_tag_host_ver2[] = {'H', 'S', 'T', 0x02}, /* IPv4 host */
+   export_tag_host_ver3[] = {'H', 'S', 'T', 0x03}; /* IPv6 host */
 
 /* ---------------------------------------------------------------------------
  * Load a host's ip_proto table from a file.
@@ -1233,7 +1234,9 @@ hosts_db_import_host(const int fd)
    int ver = 0;
 
    if (!readn(fd, hdr, sizeof(hdr))) return 0;
-   if (memcmp(hdr, export_tag_host_ver2, sizeof(hdr)) == 0)
+   if (memcmp(hdr, export_tag_host_ver3, sizeof(hdr)) == 0)
+      ver = 3;
+   else if (memcmp(hdr, export_tag_host_ver2, sizeof(hdr)) == 0)
       ver = 2;
    else if (memcmp(hdr, export_tag_host_ver1, sizeof(hdr)) == 0)
       ver = 1;
@@ -1243,11 +1246,22 @@ hosts_db_import_host(const int fd)
       return 0;
    }
 
-   ipaddr.af = AF_INET;
+   /* Only version 3 can contain an IPv6 address.  */
+   if (ver == 3)
+      ipaddr.af = AF_INET6;
+   else
+      ipaddr.af = AF_INET;
+
    if (!readaddr(fd, &ipaddr)) return 0;
    verbosef("at file pos %u, importing host %s", pos, ip_to_str(&ipaddr));
    host = host_get(&ipaddr);
-   assert(host->u.host.ipaddr.addr.ip.s_addr == ipaddr.addr.ip.s_addr); /* make fn? */
+
+   if (ver == 3) /* make fn? */
+      assert(memcmp(&host->u.host.ipaddr.addr.ip6, &ipaddr.addr.ip6,
+                     sizeof(ipaddr.addr.ip6)) == 0);
+   else /* Versions 1 and 2.  */
+      assert(memcmp(&host->u.host.ipaddr.addr.ip, &ipaddr.addr.ip,
+                     sizeof(ipaddr.addr.ip)) == 0);
 
    if (ver > 1) {
       uint64_t t;
@@ -1273,7 +1287,8 @@ hosts_db_import_host(const int fd)
 
       if (!readn(fd, host->u.host.dns, hostname_len)) return 0;
       host->u.host.dns[hostname_len] = '\0';
-   }
+   } else
+      host->u.host.dns = NULL;
 
    if (!read64(fd, &in)) return 0;
    if (!read64(fd, &out)) return 0;
@@ -1322,8 +1337,16 @@ int hosts_db_export(const int fd)
    for (i = 0; i<hosts_db->size; i++)
    for (b = hosts_db->table[i]; b != NULL; b = b->next) {
       /* For each host: */
-      if (!writen(fd, export_tag_host_ver2, sizeof(export_tag_host_ver2)))
-         return 0;
+      switch (b->u.host.ipaddr.af) {
+         case AF_INET6:
+            if (!writen(fd, export_tag_host_ver3, sizeof(export_tag_host_ver3)))
+               return 0;
+            break;
+         case AF_INET:
+         default:
+            if (!writen(fd, export_tag_host_ver2, sizeof(export_tag_host_ver2)))
+               return 0;
+      }
 
       if (!writeaddr(fd, &b->u.host.ipaddr)) return 0;