Home | History | Annotate | Download | only in utils
      1 /*
      2  * Copyright (c) 2005 Evgeniy Polyakov <johnpol (at) 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 }
    486