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