1 #include <cstdlib>
2 #include <unistd.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <map>
6 #include <sys/socket.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <netinet/in.h>
10 #include <arpa/inet.h>
11 
12 #include "logtools.h"
13 
14 using namespace std;
15 
usage()16 void usage()
17 {
18   fprintf(stderr
19         , "Usage: clfsplit -d defaultfile -f file -s spec [-f file -s spec]\n"
20           "\nSpec is a list of IP ranges or a file containing such a list.\n"
21   "\nVersion: " VERSION "\n");
22   exit(ERR_PARAM);
23 }
24 
25 class file_wrap
26 {
27 public:
file_wrap(FILE * fp,const char * name)28   file_wrap(FILE *fp, const char *name)
29    : m_fp(fp)
30    , m_name(name)
31   { }
32 
33 
close()34   void close() { if(m_fp) { fclose(m_fp); m_fp = NULL; } }
35 
write(const char * line)36   void write(const char *line)
37   {
38     if(EOF == fputs(line, m_fp))
39     {
40       fprintf(stderr, "Can't write to output file %s\n", m_name);
41       exit(ERR_OUTPUT);
42     }
43   }
44 
45 private:
46   FILE *m_fp;
47   const char *m_name;
48 
49   file_wrap(const file_wrap&);
50   file_wrap & operator=(const file_wrap&);
51 };
52 
53 class details;
54 typedef map<int, details *> MAP;
55 
inet_itoa(unsigned int ip)56 const char *inet_itoa(unsigned int ip)
57 {
58   static char buf[30];
59   sprintf(buf, "%d.%d.%d.%d", ip >> 24, (ip >> 16) % 256, (ip >> 8) % 256, ip % 256);
60   return buf;
61 }
62 
63 class details
64 {
65 public:
details(unsigned int begin,unsigned int end,file_wrap * wrap,MAP & m)66   details(unsigned int begin, unsigned int end, file_wrap *wrap, MAP &m)
67    : m_begin(begin)
68    , m_end(end)
69    , m_wrap(wrap)
70   {
71     m[begin] = this;
72   }
73 
~details()74   ~details() { m_wrap->close(); }
75 
check_item(unsigned int ip,const char * line)76   bool check_item(unsigned int ip, const char *line)
77   {
78     if(ip >= m_begin && ip <= m_end)
79     {
80       m_wrap->write(line);
81       return true;
82     }
83     return false;
84   }
85 
86 private:
87   unsigned int m_begin, m_end;
88   file_wrap *m_wrap;
89 
90   details(const details&);
91   details & operator=(const details&);
92 };
93 
94 
inet_atoi(const char * n)95 unsigned int inet_atoi(const char *n)
96 {
97   char tmp[16];
98   strncpy(tmp, n, sizeof(tmp) - 1);
99   tmp[sizeof(tmp) - 1] = '\0';
100   for(unsigned int i = 0; i < sizeof(tmp); i++)
101   {
102     if(tmp[i] == ' ')
103       tmp[i] = '\0';
104   }
105   return ntohl(inet_addr(tmp));
106 }
107 
open_output_file(const char * file)108 FILE *open_output_file(const char *file)
109 {
110   if(!file)
111     usage();
112 
113   const char *mode = "w";
114   struct stat stat_buf;
115   if(!stat(file, &stat_buf) && S_ISREG(stat_buf.st_mode))
116     mode = "a";
117   FILE *output = fopen(file, mode);
118   if(!output)
119     fprintf(stderr, "Can't open file %s\n", file);
120   return output;
121 }
122 
process_spec(MAP & m,const char * file,const char * opt)123 void process_spec(MAP &m, const char *file, const char *opt)
124 {
125   FILE *output = open_output_file(file);
126   if(!output)
127     exit(ERR_OUTPUT);
128   file_wrap *wrap = new file_wrap(output, file);
129 
130   FILE *fp = NULL;
131   char buf[4096];
132   char *ptr = buf;
133   if(opt[0] < '0' || opt[0] > '9')
134   {
135     fp = fopen(opt, "r");
136     if(!fp)
137     {
138       fprintf(stderr, "Can't open file %s\n", opt);
139       exit(ERR_SPEC);
140     }
141     if(!fgets(buf, sizeof(buf), fp) )
142     {
143       fprintf(stderr, "Can't read from file %s\n", opt);
144       exit(ERR_SPEC);
145     }
146   }
147   else
148   {
149     ptr = strdup(opt);
150   }
151   do
152   {
153     buf[sizeof(buf) - 1] = '\0';
154 
155     char *item;
156     item = strtok(ptr, "\r\n:");
157     do
158     {
159       int i;
160       char *it = strdup(item);
161       for(i = 0; item[i] != '\0' && item[i] != '-' && item[i] != '/'; i++)
162       { }
163 
164       unsigned int first_ip = 0;
165       unsigned int second_ip = 0;
166       switch(item[i])
167       {
168         case '\0':
169           first_ip = inet_atoi(item);
170           second_ip = first_ip;
171         break;
172         case '-':
173           item[i] = '\0';
174           first_ip = inet_atoi(item);
175           second_ip = inet_atoi(&item[i + 1]);
176         break;
177         case '/':
178         {
179           item[i] = '\0';
180           first_ip = inet_atoi(item);
181           unsigned int sub = atoi(&item[i + 1]);
182           second_ip = first_ip + (1 << (32 - sub)) - 1;
183         }
184         break;
185       }
186       new details(first_ip, second_ip, wrap, m);
187       free(it);
188     } while( (item = strtok(NULL, "\r\n:")) );
189 
190   } while(fp && fgets(buf, sizeof(buf), fp) );
191   if(fp)
192     fclose(fp);
193   else
194     free(ptr);
195 }
196 
197 
main(int argc,char ** argv)198 int main(int argc, char **argv)
199 {
200   int int_c;
201   const char *defaultfile = NULL;
202   const char *file = NULL;
203   MAP m;
204   FILE *input = stdin;
205   bool new_input = false;
206   optind = 1;
207   while(-1 != (int_c = getopt(argc, argv, "d:i:f:s:")) )
208   {
209     switch(char(int_c))
210     {
211       case '?':
212       case ':':
213         usage();
214       break;
215       case 'd':
216         defaultfile = optarg;
217       break;
218       case 'i':
219         if(new_input)
220           usage();
221         input = fopen(optarg, "r");
222         if(!input)
223         {
224           fprintf(stderr, "Can't open file %s\n", optarg);
225           return ERR_INPUT;
226         }
227         new_input = true;
228       break;
229       case 'f':
230         file = optarg;
231       break;
232       case 's':
233         process_spec(m, file, optarg);
234       break;
235     }
236   }
237   new details(0, 0, NULL, m);
238   FILE *def = open_output_file(defaultfile);
239   if(!def)
240     return ERR_OUTPUT;
241   char buf[4096];
242   while(fgets(buf, sizeof(buf), input))
243   {
244     buf[sizeof(buf) - 1] = '\0';
245     unsigned int ip = inet_atoi(buf);
246     if(ip)
247     {
248       MAP::iterator i = m.upper_bound(ip);
249       bool done = false;
250       if(i != m.begin() )
251       {
252         i--;
253         done = (*i).second->check_item(ip, buf);
254       }
255       if(!done)
256       {
257         if(EOF == fputs(buf, def))
258         {
259           fprintf(stderr, "Can't write to output file %s\n", defaultfile);
260           return ERR_OUTPUT;
261         }
262       }
263     }
264   }
265   if(new_input)
266     fclose(input);
267   return 0;
268 }
269 
270