1 //  hosts2zones.c
2 //  hosts2zones
3 //
4 //  Created by Dr. Rolf Jansen on 2014-07-06.
5 //  Copyright (c) 2014 projectworld.net. All rights reserved.
6 //
7 //  Redistribution and use in source and binary forms, with or without modification,
8 //  are permitted provided that the following conditions are met:
9 //
10 //  1. Redistributions of source code must retain the above copyright notice,
11 //     this list of conditions and the following disclaimer.
12 //
13 //  2. Redistributions in binary form must reproduce the above copyright notice,
14 //     this list of conditions and the following disclaimer in the documentation
15 //     and/or other materials provided with the distribution.
16 //
17 //  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
18 //  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
19 //  AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
20 //  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 //  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 //  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23 //  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
24 //  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <stdbool.h>
30 #include <stdint.h>
31 #include <string.h>
32 #include <sys/stat.h>
33 
34 #include "binutils.h"
35 #include "store.h"
36 
37 
38 #define hcnt 65535
39 
40 int     hosts_count = 0;
41 int     zones_count = 0;
42 FILE   *in, *out;
43 Node  **domainStore;
44 
45 
zoneOutput(Node * node)46 void zoneOutput(Node *node)
47 {
48    if (node)
49    {
50       zoneOutput(node->L);
51       zoneOutput(node->R);
52 
53       bool  ontop = true;
54       int   n, level = 0;
55       char *q, *p = node->name;
56 
57       for (q = p + node->naml, n = 0; ontop && q > p; q--, n++)
58          if (*q && *(q-1) == '.' && (++level >= 3 || level == 2 && n > 6) && findName(domainStore, q, n))
59             ontop = false;
60 
61       if (ontop && level && !node->value.b)
62       {
63          fprintf(out, "local-zone: \"%s\" static\n", node->name);
64          zones_count++;
65       }
66    }
67 }
68 
69 
main(int argc,const char * argv[])70 int main(int argc, const char *argv[])
71 {
72    if (argc >= 3 && (out = fopen(argv[1], "w")))
73    {
74       domainStore = createTable(hcnt);
75 
76       int    inc;
77       struct stat st;
78       for (inc = 2; inc < argc; inc++)
79          if (stat(argv[inc], &st) == noerr && st.st_size > 3 && (in = fopen(argv[inc], "r")))
80          {
81             char *hosts = allocate(st.st_size + 2, false);
82             if (fread(hosts, st.st_size, 1, in) == 1)
83             {
84                *(uint16_t *)&hosts[st.st_size] = *(uint16_t *)"\n";                    // guaranteed end of line + end of string at the end of the read-in data
85 
86                bool  iswhite;
87                int   dl, ll, wl;
88                char *word, *lineend, *nextword, *nextline;
89                char *line = hosts + blanklen(hosts);                                   // get the start of the first line by skipping leading blanks + blank lines
90 
91                while (line < hosts + st.st_size)
92                {
93                   ll = linelen(line);
94                   lineend   = bskip(line+ll);                                          // skip trailing blanks
95                   *lineend  = '\0';                                                    // separate the entry as string
96 
97                   nextline  = line + ll+1;                                             // get the start of the next line
98                   nextline += blanklen(nextline);                                      // by skipping leading blanks + blank lines
99 
100                   if (*line != '#')                                                    // skip comment lines
101                   {
102                      word = NULL;                                                      // assume an inacceptable entry
103 
104                      line[wl = wordlen(line)] = '\0';                                  // pickup the first entry on the line
105                      if (line+wl == lineend &&                                         // accept a single domain name per line which
106                          0 < (dl = domainlen(line)) && dl < wl)                        // must contain at least 1 non-leading & non-traling dot
107                         word = line, iswhite = false;                                  // simple domain lists are always black lists
108                                                                                        // otherwise assume the Hosts file format
109                      else if ((iswhite = *(int64_t *)line == *(int64_t *)"1.1.1.1") || // entries starting with 1.1.1.1 shall be white listed
110                              /*isblack*/ *(int64_t *)line == *(int64_t *)"0.0.0.0"  || // 0.0.0.0 or 127.0.0.1 are black list entries
111                              /*isblack*/ *(int16_t *)line == *(int16_t *)"12" &&
112                                     *(int64_t *)(line+=2) == *(int64_t *)"7.0.0.1")
113                         word = line + 8, word += blanklen(word);                       // skip IP address and leading blanks
114 
115                      if (word)                                                         // only process simple domain entries or entries in Hosts file format
116                         while (*word && *word != '#' && word < nextline)               // Hosts files may contain more than one domain per line
117                         {
118                            wl = wordlen(word);
119                            nextword = word + wl;
120                            *nextword++ = '\0';
121                            nextword += blanklen(nextword);
122 
123                            if (*lowercase(word, wl) &&                                 // convert to lowercase, end check if it is a non empty string
124                                (*(int64_t *)word != *(int64_t *)"localhos"             // don't process 'localhost' entries
125                                 || *(int16_t *)(word+8) != *(int16_t *)"t") &&
126                                !findName(domainStore, word, wl))                       // if the entry does not exit in the domain store
127                            {                                                           // then create a new one for the given domain name
128                               Value value = {Simple, .b = iswhite};
129                               storeName(domainStore, word, wl, &value);
130                               hosts_count++;
131                            }
132 
133                            word = nextword;
134                         }
135                   }
136 
137                   line = nextline;
138                }
139             }
140 
141             deallocate(VPR(hosts), false);
142             fclose(in);
143          }
144 
145       for (size_t h = 1; h <= hcnt; h++)
146          zoneOutput(domainStore[h]);
147 
148       releaseTable(domainStore);
149       fclose(out);
150 
151       printf("Number of Hosts: %d\nNumber of Zones: %d\n", hosts_count, zones_count);
152 
153       return (zones_count > 0) ? 0 : 1;
154    }
155    else
156       return 1;
157 }
158