Fork for IVI and add .changes file
[profile/ivi/iptables.git] / utils / nfnl_osf.c
1 /*
2  * Copyright (c) 2005 Evgeniy Polyakov <johnpol@2ka.mxt.ru>
3  * 
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */
19
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <sys/poll.h>
23 #include <sys/time.h>
24
25 #include <arpa/inet.h>
26
27 #include <ctype.h>
28 #include <errno.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <stdarg.h>
33 #include <time.h>
34 #include <unistd.h>
35
36 #include <netinet/ip.h>
37 #include <netinet/tcp.h>
38
39 #include <linux/connector.h>
40 #include <linux/types.h>
41 #include <linux/netlink.h>
42 #include <linux/rtnetlink.h>
43 #include <linux/unistd.h>
44
45 #include <libnfnetlink/libnfnetlink.h>
46
47 #include <linux/netfilter/nfnetlink.h>
48 #include <linux/netfilter/xt_osf.h>
49
50 #define OPTDEL                  ','
51 #define OSFPDEL                 ':'
52 #define MAXOPTSTRLEN            128
53
54 #ifndef NIPQUAD
55 #define NIPQUAD(addr) \
56         ((unsigned char *)&addr)[0], \
57         ((unsigned char *)&addr)[1], \
58         ((unsigned char *)&addr)[2], \
59         ((unsigned char *)&addr)[3]
60 #endif
61
62 static struct nfnl_handle *nfnlh;
63 static struct nfnl_subsys_handle *nfnlssh;
64
65 static struct xt_osf_opt IANA_opts[] = {
66         { .kind = 0, .length = 1,},
67         { .kind=1, .length=1,},
68         { .kind=2, .length=4,},
69         { .kind=3, .length=3,},
70         { .kind=4, .length=2,},
71         { .kind=5, .length=1,},         /* SACK length is not defined */
72         { .kind=6, .length=6,},
73         { .kind=7, .length=6,},
74         { .kind=8, .length=10,},
75         { .kind=9, .length=2,},
76         { .kind=10, .length=3,},
77         { .kind=11, .length=1,},                /* CC: Suppose 1 */
78         { .kind=12, .length=1,},                /* the same */
79         { .kind=13, .length=1,},                /* and here too */
80         { .kind=14, .length=3,},
81         { .kind=15, .length=1,},                /* TCP Alternate Checksum Data. Length is not defined */
82         { .kind=16, .length=1,},
83         { .kind=17, .length=1,},
84         { .kind=18, .length=3,},
85         { .kind=19, .length=18,},
86         { .kind=20, .length=1,},
87         { .kind=21, .length=1,},
88         { .kind=22, .length=1,},
89         { .kind=23, .length=1,},
90         { .kind=24, .length=1,},
91         { .kind=25, .length=1,},
92         { .kind=26, .length=1,},
93 };
94
95 static FILE *osf_log_stream;
96
97 static void uloga(const char *f, ...)
98 {
99         va_list ap;
100
101         if (!osf_log_stream)
102                 osf_log_stream = stdout;
103
104         va_start(ap, f);
105         vfprintf(osf_log_stream, f, ap);
106         va_end(ap);
107
108         fflush(osf_log_stream);
109 }
110
111 static void ulog(const char *f, ...)
112 {
113         char str[64];
114         struct tm tm;
115         struct timeval tv;
116         va_list ap;
117
118         if (!osf_log_stream)
119                 osf_log_stream = stdout;
120
121         gettimeofday(&tv, NULL);
122         localtime_r((time_t *)&tv.tv_sec, &tm);
123         strftime(str, sizeof(str), "%F %R:%S", &tm);
124
125         fprintf(osf_log_stream, "%s.%lu %ld ", str, tv.tv_usec, syscall(__NR_gettid));
126
127         va_start(ap, f);
128         vfprintf(osf_log_stream, f, ap);
129         va_end(ap);
130
131         fflush(osf_log_stream);
132 }
133
134 #define ulog_err(f, a...) uloga(f ": %s [%d].\n", ##a, strerror(errno), errno)
135
136 static char *xt_osf_strchr(char *ptr, char c)
137 {
138         char *tmp;
139
140         tmp = strchr(ptr, c);
141         if (tmp)
142                 *tmp = '\0';
143
144         while (tmp && tmp + 1 && isspace(*(tmp + 1)))
145                 tmp++;
146
147         return tmp;
148 }
149
150 static void xt_osf_parse_opt(struct xt_osf_opt *opt, __u16 *optnum, char *obuf, int olen)
151 {
152         int i, op;
153         char *ptr, wc;
154         unsigned long val;
155
156         ptr = &obuf[0];
157         i = 0;
158         while (ptr != NULL && i < olen && *ptr != 0) {
159                 val = 0;
160                 op = 0;
161                 wc = OSF_WSS_PLAIN;
162                 switch (obuf[i]) {
163                 case 'N':
164                         op = OSFOPT_NOP;
165                         ptr = xt_osf_strchr(&obuf[i], OPTDEL);
166                         if (ptr) {
167                                 *ptr = '\0';
168                                 ptr++;
169                                 i += (int)(ptr - &obuf[i]);
170                         } else
171                                 i++;
172                         break;
173                 case 'S':
174                         op = OSFOPT_SACKP;
175                         ptr = xt_osf_strchr(&obuf[i], OPTDEL);
176                         if (ptr) {
177                                 *ptr = '\0';
178                                 ptr++;
179                                 i += (int)(ptr - &obuf[i]);
180                         } else
181                                 i++;
182                         break;
183                 case 'T':
184                         op = OSFOPT_TS;
185                         ptr = xt_osf_strchr(&obuf[i], OPTDEL);
186                         if (ptr) {
187                                 *ptr = '\0';
188                                 ptr++;
189                                 i += (int)(ptr - &obuf[i]);
190                         } else
191                                 i++;
192                         break;
193                 case 'W':
194                         op = OSFOPT_WSO;
195                         ptr = xt_osf_strchr(&obuf[i], OPTDEL);
196                         if (ptr) {
197                                 switch (obuf[i + 1]) {
198                                 case '%':
199                                         wc = OSF_WSS_MODULO;
200                                         break;
201                                 case 'S':
202                                         wc = OSF_WSS_MSS;
203                                         break;
204                                 case 'T':
205                                         wc = OSF_WSS_MTU;
206                                         break;
207                                 default:
208                                         wc = OSF_WSS_PLAIN;
209                                         break;
210                                 }
211
212                                 *ptr = '\0';
213                                 ptr++;
214                                 if (wc)
215                                         val = strtoul(&obuf[i + 2], NULL, 10);
216                                 else
217                                         val = strtoul(&obuf[i + 1], NULL, 10);
218                                 i += (int)(ptr - &obuf[i]);
219
220                         } else
221                                 i++;
222                         break;
223                 case 'M':
224                         op = OSFOPT_MSS;
225                         ptr = xt_osf_strchr(&obuf[i], OPTDEL);
226                         if (ptr) {
227                                 if (obuf[i + 1] == '%')
228                                         wc = OSF_WSS_MODULO;
229                                 *ptr = '\0';
230                                 ptr++;
231                                 if (wc)
232                                         val = strtoul(&obuf[i + 2], NULL, 10);
233                                 else
234                                         val = strtoul(&obuf[i + 1], NULL, 10);
235                                 i += (int)(ptr - &obuf[i]);
236                         } else
237                                 i++;
238                         break;
239                 case 'E':
240                         op = OSFOPT_EOL;
241                         ptr = xt_osf_strchr(&obuf[i], OPTDEL);
242                         if (ptr) {
243                                 *ptr = '\0';
244                                 ptr++;
245                                 i += (int)(ptr - &obuf[i]);
246                         } else
247                                 i++;
248                         break;
249                 default:
250                         op = OSFOPT_EMPTY;
251                         ptr = xt_osf_strchr(&obuf[i], OPTDEL);
252                         if (ptr) {
253                                 ptr++;
254                                 i += (int)(ptr - &obuf[i]);
255                         } else
256                                 i++;
257                         break;
258                 }
259
260                 if (op != OSFOPT_EMPTY) {
261                         opt[*optnum].kind = IANA_opts[op].kind;
262                         opt[*optnum].length = IANA_opts[op].length;
263                         opt[*optnum].wc.wc = wc;
264                         opt[*optnum].wc.val = val;
265                         (*optnum)++;
266                 }
267         }
268 }
269
270 static int osf_load_line(char *buffer, int len, int del)
271 {
272         int i, cnt = 0;
273         char obuf[MAXOPTSTRLEN];
274         struct xt_osf_user_finger f;
275         char *pbeg, *pend;
276         char buf[NFNL_HEADER_LEN + NFA_LENGTH(sizeof(struct xt_osf_user_finger))];
277         struct nlmsghdr *nmh = (struct nlmsghdr *) buf;
278
279         memset(&f, 0, sizeof(struct xt_osf_user_finger));
280
281         ulog("Loading '%s'.\n", buffer);
282
283         for (i = 0; i < len && buffer[i] != '\0'; ++i) {
284                 if (buffer[i] == ':')
285                         cnt++;
286         }
287
288         if (cnt != 8) {
289                 ulog("Wrong input line '%s': cnt: %d, must be 8, i: %d, must be %d.\n", buffer, cnt, i, len);
290                 return -EINVAL;
291         }
292
293         memset(obuf, 0, sizeof(obuf));
294
295         pbeg = buffer;
296         pend = xt_osf_strchr(pbeg, OSFPDEL);
297         if (pend) {
298                 *pend = '\0';
299                 if (pbeg[0] == 'S') {
300                         f.wss.wc = OSF_WSS_MSS;
301                         if (pbeg[1] == '%')
302                                 f.wss.val = strtoul(&pbeg[2], NULL, 10);
303                         else if (pbeg[1] == '*')
304                                 f.wss.val = 0;
305                         else
306                                 f.wss.val = strtoul(&pbeg[1], NULL, 10);
307                 } else if (pbeg[0] == 'T') {
308                         f.wss.wc = OSF_WSS_MTU;
309                         if (pbeg[1] == '%')
310                                 f.wss.val = strtoul(&pbeg[2], NULL, 10);
311                         else if (pbeg[1] == '*')
312                                 f.wss.val = 0;
313                         else
314                                 f.wss.val = strtoul(&pbeg[1], NULL, 10);
315                 } else if (pbeg[0] == '%') {
316                         f.wss.wc = OSF_WSS_MODULO;
317                         f.wss.val = strtoul(&pbeg[1], NULL, 10);
318                 } else if (isdigit(pbeg[0])) {
319                         f.wss.wc = OSF_WSS_PLAIN;
320                         f.wss.val = strtoul(&pbeg[0], NULL, 10);
321                 }
322
323                 pbeg = pend + 1;
324         }
325         pend = xt_osf_strchr(pbeg, OSFPDEL);
326         if (pend) {
327                 *pend = '\0';
328                 f.ttl = strtoul(pbeg, NULL, 10);
329                 pbeg = pend + 1;
330         }
331         pend = xt_osf_strchr(pbeg, OSFPDEL);
332         if (pend) {
333                 *pend = '\0';
334                 f.df = strtoul(pbeg, NULL, 10);
335                 pbeg = pend + 1;
336         }
337         pend = xt_osf_strchr(pbeg, OSFPDEL);
338         if (pend) {
339                 *pend = '\0';
340                 f.ss = strtoul(pbeg, NULL, 10);
341                 pbeg = pend + 1;
342         }
343
344         pend = xt_osf_strchr(pbeg, OSFPDEL);
345         if (pend) {
346                 *pend = '\0';
347                 cnt = snprintf(obuf, sizeof(obuf), "%s,", pbeg);
348                 pbeg = pend + 1;
349         }
350
351         pend = xt_osf_strchr(pbeg, OSFPDEL);
352         if (pend) {
353                 *pend = '\0';
354                 if (pbeg[0] == '@' || pbeg[0] == '*')
355                         cnt = snprintf(f.genre, sizeof(f.genre), "%s", pbeg + 1);
356                 else
357                         cnt = snprintf(f.genre, sizeof(f.genre), "%s", pbeg);
358                 pbeg = pend + 1;
359         }
360
361         pend = xt_osf_strchr(pbeg, OSFPDEL);
362         if (pend) {
363                 *pend = '\0';
364                 cnt = snprintf(f.version, sizeof(f.version), "%s", pbeg);
365                 pbeg = pend + 1;
366         }
367
368         pend = xt_osf_strchr(pbeg, OSFPDEL);
369         if (pend) {
370                 *pend = '\0';
371                 cnt =
372                     snprintf(f.subtype, sizeof(f.subtype), "%s", pbeg);
373                 pbeg = pend + 1;
374         }
375
376         xt_osf_parse_opt(f.opt, &f.opt_num, obuf, sizeof(obuf));
377
378         memset(buf, 0, sizeof(buf));
379
380         if (del)
381                 nfnl_fill_hdr(nfnlssh, nmh, 0, AF_UNSPEC, 0, OSF_MSG_REMOVE, NLM_F_REQUEST);
382         else
383                 nfnl_fill_hdr(nfnlssh, nmh, 0, AF_UNSPEC, 0, OSF_MSG_ADD, NLM_F_REQUEST | NLM_F_CREATE);
384
385         nfnl_addattr_l(nmh, sizeof(buf), OSF_ATTR_FINGER, &f, sizeof(struct xt_osf_user_finger));
386
387         return nfnl_talk(nfnlh, nmh, 0, 0, NULL, NULL, NULL);
388 }
389
390 static int osf_load_entries(char *path, int del)
391 {
392         FILE *inf;
393         int err = 0;
394         char buf[1024];
395
396         inf = fopen(path, "r");
397         if (!inf) {
398                 ulog_err("Failed to open file '%s'", path);
399                 return -1;
400         }
401
402         while(fgets(buf, sizeof(buf), inf)) {
403                 int len;
404
405                 if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r')
406                         continue;
407
408                 len = strlen(buf) - 1;
409
410                 if (len <= 0)
411                         continue;
412
413                 buf[len] = '\0';
414
415                 err = osf_load_line(buf, len, del);
416                 if (err)
417                         break;
418
419                 memset(buf, 0, sizeof(buf));
420         }
421
422         fclose(inf);
423         return err;
424 }
425
426 int main(int argc, char *argv[])
427 {
428         int ch, del = 0, err;
429         char *fingerprints = NULL;
430
431         while ((ch = getopt(argc, argv, "f:dh")) != -1) {
432                 switch (ch) {
433                         case 'f':
434                                 fingerprints = optarg;
435                                 break;
436                         case 'd':
437                                 del = 1;
438                                 break;
439                         default:
440                                 fprintf(stderr,
441                                         "Usage: %s -f fingerprints -d <del rules> -h\n",
442                                         argv[0]);
443                                 return -1;
444                 }
445         }
446
447         if (!fingerprints) {
448                 err = -ENOENT;
449                 goto err_out_exit;
450         }
451
452         nfnlh = nfnl_open();
453         if (!nfnlh) {
454                 err = -EINVAL;
455                 ulog_err("Failed to create nfnl handler");
456                 goto err_out_exit;
457         }
458
459 #ifndef NFNL_SUBSYS_OSF
460 #define NFNL_SUBSYS_OSF 5
461 #endif
462
463         nfnlssh = nfnl_subsys_open(nfnlh, NFNL_SUBSYS_OSF, OSF_MSG_MAX, 0);
464         if (!nfnlssh) {
465                 err = -EINVAL;
466                 ulog_err("Faied to create nfnl subsystem");
467                 goto err_out_close;
468         }
469
470         err = osf_load_entries(fingerprints, del);
471         if (err)
472                 goto err_out_close_subsys;
473
474         nfnl_subsys_close(nfnlssh);
475         nfnl_close(nfnlh);
476
477         return 0;
478
479 err_out_close_subsys:
480         nfnl_subsys_close(nfnlssh);
481 err_out_close:
482         nfnl_close(nfnlh);
483 err_out_exit:
484         return err;
485 }