2 * Copyright (c) 2005 Evgeniy Polyakov <johnpol@2ka.mxt.ru>
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.
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.
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
20 #include <sys/types.h>
21 #include <sys/socket.h>
25 #include <arpa/inet.h>
36 #include <netinet/ip.h>
37 #include <netinet/tcp.h>
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>
45 #include <libnfnetlink/libnfnetlink.h>
47 #include <linux/netfilter/nfnetlink.h>
48 #include <linux/netfilter/xt_osf.h>
52 #define MAXOPTSTRLEN 128
55 #define NIPQUAD(addr) \
56 ((unsigned char *)&addr)[0], \
57 ((unsigned char *)&addr)[1], \
58 ((unsigned char *)&addr)[2], \
59 ((unsigned char *)&addr)[3]
62 static struct nfnl_handle *nfnlh;
63 static struct nfnl_subsys_handle *nfnlssh;
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,},
95 static FILE *osf_log_stream;
97 static void uloga(const char *f, ...)
102 osf_log_stream = stdout;
105 vfprintf(osf_log_stream, f, ap);
108 fflush(osf_log_stream);
111 static void ulog(const char *f, ...)
119 osf_log_stream = stdout;
121 gettimeofday(&tv, NULL);
122 localtime_r((time_t *)&tv.tv_sec, &tm);
123 strftime(str, sizeof(str), "%F %R:%S", &tm);
125 fprintf(osf_log_stream, "%s.%lu %ld ", str, tv.tv_usec, syscall(__NR_gettid));
128 vfprintf(osf_log_stream, f, ap);
131 fflush(osf_log_stream);
134 #define ulog_err(f, a...) uloga(f ": %s [%d].\n", ##a, strerror(errno), errno)
136 static char *xt_osf_strchr(char *ptr, char c)
140 tmp = strchr(ptr, c);
144 while (tmp && tmp + 1 && isspace(*(tmp + 1)))
150 static void xt_osf_parse_opt(struct xt_osf_opt *opt, __u16 *optnum, char *obuf, int olen)
158 while (ptr != NULL && i < olen && *ptr != 0) {
165 ptr = xt_osf_strchr(&obuf[i], OPTDEL);
169 i += (int)(ptr - &obuf[i]);
175 ptr = xt_osf_strchr(&obuf[i], OPTDEL);
179 i += (int)(ptr - &obuf[i]);
185 ptr = xt_osf_strchr(&obuf[i], OPTDEL);
189 i += (int)(ptr - &obuf[i]);
195 ptr = xt_osf_strchr(&obuf[i], OPTDEL);
197 switch (obuf[i + 1]) {
215 val = strtoul(&obuf[i + 2], NULL, 10);
217 val = strtoul(&obuf[i + 1], NULL, 10);
218 i += (int)(ptr - &obuf[i]);
225 ptr = xt_osf_strchr(&obuf[i], OPTDEL);
227 if (obuf[i + 1] == '%')
232 val = strtoul(&obuf[i + 2], NULL, 10);
234 val = strtoul(&obuf[i + 1], NULL, 10);
235 i += (int)(ptr - &obuf[i]);
241 ptr = xt_osf_strchr(&obuf[i], OPTDEL);
245 i += (int)(ptr - &obuf[i]);
251 ptr = xt_osf_strchr(&obuf[i], OPTDEL);
254 i += (int)(ptr - &obuf[i]);
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;
270 static int osf_load_line(char *buffer, int len, int del)
273 char obuf[MAXOPTSTRLEN];
274 struct xt_osf_user_finger f;
276 char buf[NFNL_HEADER_LEN + NFA_LENGTH(sizeof(struct xt_osf_user_finger))];
277 struct nlmsghdr *nmh = (struct nlmsghdr *) buf;
279 memset(&f, 0, sizeof(struct xt_osf_user_finger));
281 ulog("Loading '%s'.\n", buffer);
283 for (i = 0; i < len && buffer[i] != '\0'; ++i) {
284 if (buffer[i] == ':')
289 ulog("Wrong input line '%s': cnt: %d, must be 8, i: %d, must be %d.\n", buffer, cnt, i, len);
293 memset(obuf, 0, sizeof(obuf));
296 pend = xt_osf_strchr(pbeg, OSFPDEL);
299 if (pbeg[0] == 'S') {
300 f.wss.wc = OSF_WSS_MSS;
302 f.wss.val = strtoul(&pbeg[2], NULL, 10);
303 else if (pbeg[1] == '*')
306 f.wss.val = strtoul(&pbeg[1], NULL, 10);
307 } else if (pbeg[0] == 'T') {
308 f.wss.wc = OSF_WSS_MTU;
310 f.wss.val = strtoul(&pbeg[2], NULL, 10);
311 else if (pbeg[1] == '*')
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);
325 pend = xt_osf_strchr(pbeg, OSFPDEL);
328 f.ttl = strtoul(pbeg, NULL, 10);
331 pend = xt_osf_strchr(pbeg, OSFPDEL);
334 f.df = strtoul(pbeg, NULL, 10);
337 pend = xt_osf_strchr(pbeg, OSFPDEL);
340 f.ss = strtoul(pbeg, NULL, 10);
344 pend = xt_osf_strchr(pbeg, OSFPDEL);
347 cnt = snprintf(obuf, sizeof(obuf), "%s,", pbeg);
351 pend = xt_osf_strchr(pbeg, OSFPDEL);
354 if (pbeg[0] == '@' || pbeg[0] == '*')
355 cnt = snprintf(f.genre, sizeof(f.genre), "%s", pbeg + 1);
357 cnt = snprintf(f.genre, sizeof(f.genre), "%s", pbeg);
361 pend = xt_osf_strchr(pbeg, OSFPDEL);
364 cnt = snprintf(f.version, sizeof(f.version), "%s", pbeg);
368 pend = xt_osf_strchr(pbeg, OSFPDEL);
372 snprintf(f.subtype, sizeof(f.subtype), "%s", pbeg);
376 xt_osf_parse_opt(f.opt, &f.opt_num, obuf, sizeof(obuf));
378 memset(buf, 0, sizeof(buf));
381 nfnl_fill_hdr(nfnlssh, nmh, 0, AF_UNSPEC, 0, OSF_MSG_REMOVE, NLM_F_REQUEST);
383 nfnl_fill_hdr(nfnlssh, nmh, 0, AF_UNSPEC, 0, OSF_MSG_ADD, NLM_F_REQUEST | NLM_F_CREATE);
385 nfnl_addattr_l(nmh, sizeof(buf), OSF_ATTR_FINGER, &f, sizeof(struct xt_osf_user_finger));
387 return nfnl_talk(nfnlh, nmh, 0, 0, NULL, NULL, NULL);
390 static int osf_load_entries(char *path, int del)
396 inf = fopen(path, "r");
398 ulog_err("Failed to open file '%s'", path);
402 while(fgets(buf, sizeof(buf), inf)) {
405 if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r')
408 len = strlen(buf) - 1;
415 err = osf_load_line(buf, len, del);
419 memset(buf, 0, sizeof(buf));
426 int main(int argc, char *argv[])
428 int ch, del = 0, err;
429 char *fingerprints = NULL;
431 while ((ch = getopt(argc, argv, "f:dh")) != -1) {
434 fingerprints = optarg;
441 "Usage: %s -f fingerprints -d <del rules> -h\n",
455 ulog_err("Failed to create nfnl handler");
459 #ifndef NFNL_SUBSYS_OSF
460 #define NFNL_SUBSYS_OSF 5
463 nfnlssh = nfnl_subsys_open(nfnlh, NFNL_SUBSYS_OSF, OSF_MSG_MAX, 0);
466 ulog_err("Faied to create nfnl subsystem");
470 err = osf_load_entries(fingerprints, del);
472 goto err_out_close_subsys;
474 nfnl_subsys_close(nfnlssh);
479 err_out_close_subsys:
480 nfnl_subsys_close(nfnlssh);