• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 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 
uloga(const char * f,...)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 
ulog(const char * f,...)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 
xt_osf_strchr(char * ptr,char c)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 && isspace(*(tmp + 1)))
145 		tmp++;
146 
147 	return tmp;
148 }
149 
xt_osf_parse_opt(struct xt_osf_opt * opt,__u16 * optnum,char * obuf,int olen)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 		wc = OSF_WSS_PLAIN;
161 		switch (obuf[i]) {
162 		case 'N':
163 			op = OSFOPT_NOP;
164 			ptr = xt_osf_strchr(&obuf[i], OPTDEL);
165 			if (ptr) {
166 				*ptr = '\0';
167 				ptr++;
168 				i += (int)(ptr - &obuf[i]);
169 			} else
170 				i++;
171 			break;
172 		case 'S':
173 			op = OSFOPT_SACKP;
174 			ptr = xt_osf_strchr(&obuf[i], OPTDEL);
175 			if (ptr) {
176 				*ptr = '\0';
177 				ptr++;
178 				i += (int)(ptr - &obuf[i]);
179 			} else
180 				i++;
181 			break;
182 		case 'T':
183 			op = OSFOPT_TS;
184 			ptr = xt_osf_strchr(&obuf[i], OPTDEL);
185 			if (ptr) {
186 				*ptr = '\0';
187 				ptr++;
188 				i += (int)(ptr - &obuf[i]);
189 			} else
190 				i++;
191 			break;
192 		case 'W':
193 			op = OSFOPT_WSO;
194 			ptr = xt_osf_strchr(&obuf[i], OPTDEL);
195 			if (ptr) {
196 				switch (obuf[i + 1]) {
197 				case '%':
198 					wc = OSF_WSS_MODULO;
199 					break;
200 				case 'S':
201 					wc = OSF_WSS_MSS;
202 					break;
203 				case 'T':
204 					wc = OSF_WSS_MTU;
205 					break;
206 				default:
207 					wc = OSF_WSS_PLAIN;
208 					break;
209 				}
210 
211 				*ptr = '\0';
212 				ptr++;
213 				if (wc)
214 					val = strtoul(&obuf[i + 2], NULL, 10);
215 				else
216 					val = strtoul(&obuf[i + 1], NULL, 10);
217 				i += (int)(ptr - &obuf[i]);
218 
219 			} else
220 				i++;
221 			break;
222 		case 'M':
223 			op = OSFOPT_MSS;
224 			ptr = xt_osf_strchr(&obuf[i], OPTDEL);
225 			if (ptr) {
226 				if (obuf[i + 1] == '%')
227 					wc = OSF_WSS_MODULO;
228 				*ptr = '\0';
229 				ptr++;
230 				if (wc)
231 					val = strtoul(&obuf[i + 2], NULL, 10);
232 				else
233 					val = strtoul(&obuf[i + 1], NULL, 10);
234 				i += (int)(ptr - &obuf[i]);
235 			} else
236 				i++;
237 			break;
238 		case 'E':
239 			op = OSFOPT_EOL;
240 			ptr = xt_osf_strchr(&obuf[i], OPTDEL);
241 			if (ptr) {
242 				*ptr = '\0';
243 				ptr++;
244 				i += (int)(ptr - &obuf[i]);
245 			} else
246 				i++;
247 			break;
248 		default:
249 			op = OSFOPT_EMPTY;
250 			ptr = xt_osf_strchr(&obuf[i], OPTDEL);
251 			if (ptr) {
252 				ptr++;
253 				i += (int)(ptr - &obuf[i]);
254 			} else
255 				i++;
256 			break;
257 		}
258 
259 		if (op != OSFOPT_EMPTY) {
260 			opt[*optnum].kind = IANA_opts[op].kind;
261 			opt[*optnum].length = IANA_opts[op].length;
262 			opt[*optnum].wc.wc = wc;
263 			opt[*optnum].wc.val = val;
264 			(*optnum)++;
265 		}
266 	}
267 }
268 
osf_load_line(char * buffer,int len,int del)269 static int osf_load_line(char *buffer, int len, int del)
270 {
271 	int i, cnt = 0;
272 	char obuf[MAXOPTSTRLEN];
273 	struct xt_osf_user_finger f;
274 	char *pbeg, *pend;
275 	char buf[NFNL_HEADER_LEN + NFA_LENGTH(sizeof(struct xt_osf_user_finger))];
276 	struct nlmsghdr *nmh = (struct nlmsghdr *) buf;
277 
278 	memset(&f, 0, sizeof(struct xt_osf_user_finger));
279 
280 	ulog("Loading '%s'.\n", buffer);
281 
282 	for (i = 0; i < len && buffer[i] != '\0'; ++i) {
283 		if (buffer[i] == ':')
284 			cnt++;
285 	}
286 
287 	if (cnt != 8) {
288 		ulog("Wrong input line '%s': cnt: %d, must be 8, i: %d, must be %d.\n", buffer, cnt, i, len);
289 		return -EINVAL;
290 	}
291 
292 	memset(obuf, 0, sizeof(obuf));
293 
294 	pbeg = buffer;
295 	pend = xt_osf_strchr(pbeg, OSFPDEL);
296 	if (pend) {
297 		*pend = '\0';
298 		if (pbeg[0] == 'S') {
299 			f.wss.wc = OSF_WSS_MSS;
300 			if (pbeg[1] == '%')
301 				f.wss.val = strtoul(&pbeg[2], NULL, 10);
302 			else if (pbeg[1] == '*')
303 				f.wss.val = 0;
304 			else
305 				f.wss.val = strtoul(&pbeg[1], NULL, 10);
306 		} else if (pbeg[0] == 'T') {
307 			f.wss.wc = OSF_WSS_MTU;
308 			if (pbeg[1] == '%')
309 				f.wss.val = strtoul(&pbeg[2], NULL, 10);
310 			else if (pbeg[1] == '*')
311 				f.wss.val = 0;
312 			else
313 				f.wss.val = strtoul(&pbeg[1], NULL, 10);
314 		} else if (pbeg[0] == '%') {
315 			f.wss.wc = OSF_WSS_MODULO;
316 			f.wss.val = strtoul(&pbeg[1], NULL, 10);
317 		} else if (isdigit(pbeg[0])) {
318 			f.wss.wc = OSF_WSS_PLAIN;
319 			f.wss.val = strtoul(&pbeg[0], NULL, 10);
320 		}
321 
322 		pbeg = pend + 1;
323 	}
324 	pend = xt_osf_strchr(pbeg, OSFPDEL);
325 	if (pend) {
326 		*pend = '\0';
327 		f.ttl = strtoul(pbeg, NULL, 10);
328 		pbeg = pend + 1;
329 	}
330 	pend = xt_osf_strchr(pbeg, OSFPDEL);
331 	if (pend) {
332 		*pend = '\0';
333 		f.df = strtoul(pbeg, NULL, 10);
334 		pbeg = pend + 1;
335 	}
336 	pend = xt_osf_strchr(pbeg, OSFPDEL);
337 	if (pend) {
338 		*pend = '\0';
339 		f.ss = strtoul(pbeg, NULL, 10);
340 		pbeg = pend + 1;
341 	}
342 
343 	pend = xt_osf_strchr(pbeg, OSFPDEL);
344 	if (pend) {
345 		*pend = '\0';
346 		i = sizeof(obuf);
347 		snprintf(obuf, i, "%.*s,", i - 2, pbeg);
348 		pbeg = pend + 1;
349 	}
350 
351 	pend = xt_osf_strchr(pbeg, OSFPDEL);
352 	if (pend) {
353 		*pend = '\0';
354 		i = sizeof(f.genre);
355 		if (pbeg[0] == '@' || pbeg[0] == '*')
356 			pbeg++;
357 		snprintf(f.genre, i, "%.*s", i - 1, pbeg);
358 		pbeg = pend + 1;
359 	}
360 
361 	pend = xt_osf_strchr(pbeg, OSFPDEL);
362 	if (pend) {
363 		*pend = '\0';
364 		i = sizeof(f.version);
365 		snprintf(f.version, i, "%.*s", i - 1, pbeg);
366 		pbeg = pend + 1;
367 	}
368 
369 	pend = xt_osf_strchr(pbeg, OSFPDEL);
370 	if (pend) {
371 		*pend = '\0';
372 		i = sizeof(f.subtype);
373 		snprintf(f.subtype, i, "%.*s", i - 1, pbeg);
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,
382 			      NLM_F_ACK | NLM_F_REQUEST);
383 	else
384 		nfnl_fill_hdr(nfnlssh, nmh, 0, AF_UNSPEC, 0, OSF_MSG_ADD,
385 			      NLM_F_ACK | NLM_F_REQUEST | NLM_F_CREATE);
386 
387 	nfnl_addattr_l(nmh, sizeof(buf), OSF_ATTR_FINGER, &f, sizeof(struct xt_osf_user_finger));
388 
389 	return nfnl_query(nfnlh, nmh);
390 }
391 
osf_load_entries(char * path,int del)392 static int osf_load_entries(char *path, int del)
393 {
394 	FILE *inf;
395 	int err = 0, lineno = 0;
396 	char buf[1024];
397 
398 	inf = fopen(path, "r");
399 	if (!inf) {
400 		ulog_err("Failed to open file '%s'", path);
401 		return -1;
402 	}
403 
404 	while(fgets(buf, sizeof(buf), inf)) {
405 		int len, rc;
406 
407 		lineno++;
408 
409 		if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r')
410 			continue;
411 
412 		len = strlen(buf) - 1;
413 
414 		if (len <= 0)
415 			continue;
416 
417 		buf[len] = '\0';
418 
419 		rc = osf_load_line(buf, len, del);
420 		if (rc && (!del || errno != ENOENT)) {
421 			ulog_err("Failed to load line %d", lineno);
422 			err = rc;
423 		}
424 
425 		memset(buf, 0, sizeof(buf));
426 	}
427 
428 	fclose(inf);
429 	return err;
430 }
431 
main(int argc,char * argv[])432 int main(int argc, char *argv[])
433 {
434 	int ch, del = 0, err;
435 	char *fingerprints = NULL;
436 
437 	while ((ch = getopt(argc, argv, "f:dh")) != -1) {
438 		switch (ch) {
439 			case 'f':
440 				fingerprints = optarg;
441 				break;
442 			case 'd':
443 				del = 1;
444 				break;
445 			default:
446 				fprintf(stderr,
447 					"Usage: %s -f fingerprints [-d]\n",
448 					argv[0]);
449 				return -1;
450 		}
451 	}
452 
453 	if (!fingerprints) {
454 		err = -ENOENT;
455 		ulog("Missing fingerprints file argument.\n");
456 		goto err_out_exit;
457 	}
458 
459 	nfnlh = nfnl_open();
460 	if (!nfnlh) {
461 		err = -EINVAL;
462 		ulog_err("Failed to create nfnl handler");
463 		goto err_out_exit;
464 	}
465 
466 #ifndef NFNL_SUBSYS_OSF
467 #define NFNL_SUBSYS_OSF	5
468 #endif
469 
470 	nfnlssh = nfnl_subsys_open(nfnlh, NFNL_SUBSYS_OSF, OSF_MSG_MAX, 0);
471 	if (!nfnlssh) {
472 		err = -EINVAL;
473 		ulog_err("Faied to create nfnl subsystem");
474 		goto err_out_close;
475 	}
476 
477 	err = osf_load_entries(fingerprints, del);
478 	if (err)
479 		goto err_out_close_subsys;
480 
481 	nfnl_subsys_close(nfnlssh);
482 	nfnl_close(nfnlh);
483 
484 	return 0;
485 
486 err_out_close_subsys:
487 	nfnl_subsys_close(nfnlssh);
488 err_out_close:
489 	nfnl_close(nfnlh);
490 err_out_exit:
491 	return err;
492 }
493