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