1/***************************************************************** 2** 3** @(#) zkt-soaserial.c (c) Oct 2007 Holger Zuleger hznet.de 4** 5** A small utility to print out the (unixtime) soa serial 6** number in a human readable form 7** 8** Copyright (c) Oct 2007, Holger Zuleger HZnet. All rights reserved. 9** 10** This software is open source. 11** 12** Redistribution and use in source and binary forms, with or without 13** modification, are permitted provided that the following conditions 14** are met: 15** 16** Redistributions of source code must retain the above copyright notice, 17** this list of conditions and the following disclaimer. 18** 19** Redistributions in binary form must reproduce the above copyright notice, 20** this list of conditions and the following disclaimer in the documentation 21** and/or other materials provided with the distribution. 22** 23** Neither the name of Holger Zuleger HZnet nor the names of its contributors may 24** be used to endorse or promote products derived from this software without 25** specific prior written permission. 26** 27** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 28** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 31** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37** POSSIBILITY OF SUCH DAMAGE. 38** 39*****************************************************************/ 40# include <stdio.h> 41# include <string.h> 42# include <sys/types.h> 43# include <time.h> 44# include <utime.h> 45# include <assert.h> 46# include <stdlib.h> 47# include <ctype.h> 48#ifdef HAVE_CONFIG_H 49# include <config.h> 50#endif 51# include "config_zkt.h" 52 53static const char *progname; 54 55static char *timestr (time_t sec); 56static int read_serial_fromfile (const char *fname, unsigned long *serial); 57static void printserial (const char *fname, unsigned long serial); 58static void usage (const char *msg); 59 60/***************************************************************** 61** timestr (sec) 62*****************************************************************/ 63static char *timestr (time_t sec) 64{ 65 struct tm *t; 66 static char timestr[31+1]; /* 27+1 should be enough */ 67 68#if defined(HAVE_STRFTIME) && HAVE_STRFTIME 69 t = localtime (&sec); 70 strftime (timestr, sizeof (timestr), "%b %d %Y %T %z", t); 71#else 72 static char *mstr[] = { 73 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 74 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 75 }; 76 int h, s; 77 78 t = localtime (&sec); 79 s = abs (t->tm_gmtoff); 80 h = t->tm_gmtoff / 3600; 81 s = t->tm_gmtoff % 3600; 82 snprintf (timestr, sizeof (timestr), "%s %2d %4d %02d:%02d:%02d %c%02d%02d", 83 mstr[t->tm_mon], t->tm_mday, t->tm_year + 1900, 84 t->tm_hour, t->tm_min, t->tm_sec, 85 t->tm_gmtoff < 0 ? '-': '+', 86 h, s); 87#endif 88 89 return timestr; 90} 91 92 93/**************************************************************** 94** 95** int read_serial_fromfile (filename) 96** 97** This function depends on a special syntax formating the 98** SOA record in the zone file!! 99** 100** To match the SOA record, the SOA RR must be formatted 101** like this: 102** @ IN SOA <master.fq.dn.> <hostmaster.fq.dn.> ( 103** <SPACEes or TABs> 1234567890; serial number 104** <SPACEes or TABs> 86400 ; other values 105** ... 106** 107****************************************************************/ 108static int read_serial_fromfile (const char *fname, unsigned long *serial) 109{ 110 FILE *fp; 111 char buf[4095+1]; 112 char master[254+1]; 113 int c; 114 int soafound; 115 116 if ( (fp = fopen (fname, "r")) == NULL ) 117 return -1; /* file not found */ 118 119 /* read until the line matches the beginning of a soa record ... */ 120 soafound = 0; 121 while ( !soafound && fgets (buf, sizeof buf, fp) ) 122 { 123 if ( sscanf (buf, "%*s %*d IN SOA %255s %*s (\n", master) == 1 ) 124 soafound = 1; 125 else if ( sscanf (buf, "%*s IN SOA %255s %*s (\n", master) == 1 ) 126 soafound = 1; 127 } 128 129 if ( !soafound ) 130 return -2; /* no zone file (soa not found) */ 131 132 /* move forward until any non ws is reached */ 133 while ( (c = getc (fp)) != EOF && isspace (c) ) 134 ; 135 ungetc (c, fp); /* pushback the non ws */ 136 137 *serial = 0L; /* read in the current serial number */ 138 if ( fscanf (fp, "%lu", serial) != 1 ) /* try to get serial no */ 139 return -3; /* no serial number found */ 140 141 fclose (fp); 142 143 return 0; /* ok! */ 144} 145 146/***************************************************************** 147** printserial() 148*****************************************************************/ 149static void printserial (const char *fname, unsigned long serial) 150{ 151 if ( fname && *fname ) 152 printf ("%-30s\t", fname); 153 154 printf ("%10lu", serial); 155 156 /* try to guess the soa serial format */ 157 if ( serial < 1136070000L ) /* plain integer (this is 2006-1-1 00:00 in unixtime format) */ 158 ; 159 else if ( serial > 2006010100L ) /* date format */ 160 { 161 int y, m, d, v; 162 163 v = serial % 100; 164 serial /= 100; 165 d = serial % 100; 166 serial /= 100; 167 m = serial % 100; 168 serial /= 100; 169 y = serial; 170 171 printf ("\t%d-%02d-%02d Version %02d", y, m, d, v); 172 } 173 else /* unixtime */ 174 printf ("\t%s\n", timestr (serial) ); 175 176 printf ("\n"); 177} 178 179/***************************************************************** 180** usage (msg) 181*****************************************************************/ 182static void usage (const char *msg) 183{ 184 if ( msg && *msg ) 185 fprintf (stderr, "%s\n", msg); 186 fprintf (stderr, "usage: %s {-s serial | signed_zonefile [...]}\n", progname); 187 188 exit (1); 189} 190 191/***************************************************************** 192** main() 193*****************************************************************/ 194int main (int argc, char *argv[]) 195{ 196 unsigned long serial; 197 198 progname = *argv; 199 200 if ( --argc == 0 ) 201 usage (""); 202 203 if ( argv[1][0] == '-' ) 204 { 205 if ( argv[1][1] != 's' ) 206 usage ("illegal option"); 207 208 if ( argc != 2 ) 209 usage ("Option -s requires an argument"); 210 211 serial = atol (argv[2]); 212 printserial ("", serial); 213 } 214 else 215 while ( argc-- > 0 ) 216 if ( (read_serial_fromfile (*++argv, &serial)) != 0 ) 217 fprintf (stderr, "couldn't read serial number from file %s\n", *argv); 218 else 219 printserial (*argv, serial); 220 221 return 0; 222} 223