1 /* 2 * Copyright (C) 1993-2001 by Darren Reed. 3 * 4 * See the IPFILTER.LICENCE file for details on licencing. 5 * 6 * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com) 7 * 8 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 9 * Use is subject to license terms. 10 */ 11 12 #include <stdio.h> 13 #include <string.h> 14 #include <fcntl.h> 15 #include <errno.h> 16 #include <sys/types.h> 17 #if !defined(__SVR4) && !defined(__svr4__) 18 #include <strings.h> 19 #else 20 #include <sys/byteorder.h> 21 #endif 22 #include <sys/time.h> 23 #include <sys/param.h> 24 #include <stdlib.h> 25 #include <unistd.h> 26 #include <stddef.h> 27 #include <sys/file.h> 28 #define _KERNEL 29 #include <sys/uio.h> 30 #undef _KERNEL 31 #include <sys/socket.h> 32 #include <sys/ioctl.h> 33 #if defined(sun) && (defined(__svr4__) || defined(__SVR4)) 34 # include <sys/ioccom.h> 35 # include <sys/sysmacros.h> 36 #endif 37 #include <netinet/in.h> 38 #include <netinet/in_systm.h> 39 #include <netinet/ip.h> 40 #include <netinet/tcp.h> 41 #include <net/if.h> 42 #if __FreeBSD_version >= 300000 43 # include <net/if_var.h> 44 #endif 45 #include <netdb.h> 46 #include <arpa/nameser.h> 47 #include <arpa/inet.h> 48 #include <resolv.h> 49 #include <ctype.h> 50 #if defined(linux) 51 # include <linux/a.out.h> 52 #else 53 # include <nlist.h> 54 #endif 55 #include "ipf.h" 56 #include "netinet/ipl.h" 57 #include "kmem.h" 58 59 #ifdef __hpux 60 # define nlist nlist64 61 #endif 62 63 #if defined(sun) && !SOLARIS2 64 # define STRERROR(x) sys_errlist[x] 65 extern char *sys_errlist[]; 66 #else 67 # define STRERROR(x) strerror(x) 68 #endif 69 70 #if !defined(lint) 71 static const char sccsid[] ="@(#)ipnat.c 1.9 6/5/96 (C) 1993 Darren Reed"; 72 static const char rcsid[] = "@(#)$Id: ipnat.c,v 1.24.2.2 2005/05/10 21:19:30 darrenr Exp $"; 73 #endif 74 75 76 #if SOLARIS 77 #define bzero(a,b) memset(a,0,b) 78 #endif 79 int use_inet6 = 0; 80 char thishost[MAXHOSTNAMELEN]; 81 82 extern char *optarg; 83 84 void dostats __P((int, natstat_t *, int, int)); 85 void flushtable __P((int, int)); 86 void usage __P((char *)); 87 int main __P((int, char*[])); 88 void showhostmap __P((natstat_t *nsp)); 89 void natstat_dead __P((natstat_t *, char *)); 90 void dostats_live __P((int, natstat_t *, int)); 91 void showhostmap_live __P((int, natstat_t *)); 92 93 int opts; 94 95 void usage(name) 96 char *name; 97 { 98 fprintf(stderr, "Usage: %s [-CdFhlnrRsv] [-f filename]\n", name); 99 exit(1); 100 } 101 102 103 int main(argc, argv) 104 int argc; 105 char *argv[]; 106 { 107 char *file, *core, *kernel; 108 natstat_t ns, *nsp; 109 int fd, c, mode; 110 ipfobj_t obj; 111 112 fd = -1; 113 opts = 0; 114 nsp = &ns; 115 file = NULL; 116 core = NULL; 117 kernel = NULL; 118 mode = O_RDWR; 119 120 while ((c = getopt(argc, argv, "CdFf:hlM:N:nrRsv")) != -1) 121 switch (c) 122 { 123 case 'C' : 124 opts |= OPT_CLEAR; 125 break; 126 case 'd' : 127 opts |= OPT_DEBUG; 128 break; 129 case 'f' : 130 file = optarg; 131 break; 132 case 'F' : 133 opts |= OPT_FLUSH; 134 break; 135 case 'h' : 136 opts |=OPT_HITS; 137 break; 138 case 'l' : 139 opts |= OPT_LIST; 140 mode = O_RDONLY; 141 break; 142 case 'M' : 143 core = optarg; 144 break; 145 case 'N' : 146 kernel = optarg; 147 break; 148 case 'n' : 149 opts |= OPT_DONOTHING; 150 mode = O_RDONLY; 151 break; 152 case 'R' : 153 opts |= OPT_NORESOLVE; 154 break; 155 case 'r' : 156 opts |= OPT_REMOVE; 157 break; 158 case 's' : 159 opts |= OPT_STAT; 160 mode = O_RDONLY; 161 break; 162 case 'v' : 163 opts |= OPT_VERBOSE; 164 break; 165 default : 166 usage(argv[0]); 167 } 168 169 initparse(); 170 171 if ((kernel != NULL) || (core != NULL)) { 172 (void) setgid(getgid()); 173 (void) setreuid(getuid(), getuid()); 174 } 175 176 bzero((char *)&ns, sizeof(ns)); 177 178 if ((opts & OPT_DONOTHING) == 0) { 179 if (checkrev(IPL_NAME) == -1) { 180 fprintf(stderr, "User/kernel version check failed\n"); 181 exit(1); 182 } 183 } 184 185 186 if (!(opts & OPT_DONOTHING) && (kernel == NULL) && (core == NULL)) { 187 #ifdef notdef 188 if (openkmem(kernel, core) == -1) 189 exit(1); 190 #endif 191 if (((fd = open(IPNAT_NAME, mode)) == -1) && 192 ((fd = open(IPNAT_NAME, O_RDONLY)) == -1)) { 193 (void) fprintf(stderr, "%s: open: %s\n", IPNAT_NAME, 194 STRERROR(errno)); 195 exit(1); 196 } 197 198 bzero((char *)&obj, sizeof(obj)); 199 obj.ipfo_rev = IPFILTER_VERSION; 200 obj.ipfo_size = sizeof(*nsp); 201 obj.ipfo_type = IPFOBJ_NATSTAT; 202 obj.ipfo_ptr = (void *)nsp; 203 if (ioctl(fd, SIOCGNATS, &obj) == -1) { 204 perror("ioctl(SIOCGNATS)"); 205 exit(1); 206 } 207 (void) setgid(getgid()); 208 (void) setreuid(getuid(), getuid()); 209 } else if ((kernel != NULL) || (core != NULL)) { 210 if (openkmem(kernel, core) == -1) 211 exit(1); 212 213 natstat_dead(nsp, kernel); 214 if (opts & (OPT_LIST|OPT_STAT)) 215 dostats(fd, nsp, opts, 0); 216 exit(0); 217 } 218 219 if (opts & (OPT_FLUSH|OPT_CLEAR)) 220 flushtable(fd, opts); 221 if (file) { 222 ipnat_parsefile(fd, ipnat_addrule, ioctl, file); 223 } 224 if (opts & (OPT_LIST|OPT_STAT)) 225 dostats(fd, nsp, opts, 1); 226 return 0; 227 } 228 229 230 /* 231 * Read NAT statistic information in using a symbol table and memory file 232 * rather than doing ioctl's. 233 */ 234 void natstat_dead(nsp, kernel) 235 natstat_t *nsp; 236 char *kernel; 237 { 238 struct nlist nat_nlist[10] = { 239 { "nat_table" }, /* 0 */ 240 { "nat_list" }, 241 { "maptable" }, 242 { "ipf_nattable_sz" }, 243 { "ipf_natrules_sz" }, 244 { "ipf_rdrrules_sz" }, /* 5 */ 245 { "ipf_hostmap_sz" }, 246 { "nat_instances" }, 247 { "ap_sess_list" }, 248 { NULL } 249 }; 250 void *tables[2]; 251 252 if (nlist(kernel, nat_nlist) == -1) { 253 fprintf(stderr, "nlist error\n"); 254 return; 255 } 256 257 /* 258 * Normally the ioctl copies all of these values into the structure 259 * for us, before returning it to userland, so here we must copy each 260 * one in individually. 261 */ 262 kmemcpy((char *)&tables, nat_nlist[0].n_value, sizeof(tables)); 263 nsp->ns_table[0] = tables[0]; 264 nsp->ns_table[1] = tables[1]; 265 266 kmemcpy((char *)&nsp->ns_list, nat_nlist[1].n_value, 267 sizeof(nsp->ns_list)); 268 kmemcpy((char *)&nsp->ns_maptable, nat_nlist[2].n_value, 269 sizeof(nsp->ns_maptable)); 270 kmemcpy((char *)&nsp->ns_nattab_sz, nat_nlist[3].n_value, 271 sizeof(nsp->ns_nattab_sz)); 272 kmemcpy((char *)&nsp->ns_rultab_sz, nat_nlist[4].n_value, 273 sizeof(nsp->ns_rultab_sz)); 274 kmemcpy((char *)&nsp->ns_rdrtab_sz, nat_nlist[5].n_value, 275 sizeof(nsp->ns_rdrtab_sz)); 276 kmemcpy((char *)&nsp->ns_hostmap_sz, nat_nlist[6].n_value, 277 sizeof(nsp->ns_hostmap_sz)); 278 kmemcpy((char *)&nsp->ns_instances, nat_nlist[7].n_value, 279 sizeof(nsp->ns_instances)); 280 kmemcpy((char *)&nsp->ns_apslist, nat_nlist[8].n_value, 281 sizeof(nsp->ns_apslist)); 282 } 283 284 285 /* 286 * Display NAT statistics. 287 */ 288 void dostats(fd, nsp, opts, alive) 289 natstat_t *nsp; 290 int fd, opts, alive; 291 { 292 nat_t *np, nat; 293 ipnat_t ipn; 294 295 /* 296 * Show statistics ? 297 */ 298 if (opts & OPT_STAT) { 299 printf("mapped\tin\t%lu\tout\t%lu\n", 300 nsp->ns_mapped[0], nsp->ns_mapped[1]); 301 printf("added\t%lu\texpired\t%lu\n", 302 nsp->ns_added, nsp->ns_expire); 303 printf("no memory\t%lu\tbad nat\t%lu\n", 304 nsp->ns_memfail, nsp->ns_badnat); 305 printf("inuse\t%lu\norphans\t%u\nrules\t%lu\n", 306 nsp->ns_inuse, nsp->ns_orphans, nsp->ns_rules); 307 printf("wilds\t%u\n", nsp->ns_wilds); 308 if (opts & OPT_VERBOSE) 309 printf("table %p list %p\n", 310 nsp->ns_table, nsp->ns_list); 311 } 312 313 /* 314 * Show list of NAT rules and NAT sessions ? 315 */ 316 if (opts & OPT_LIST) { 317 if (alive) { 318 dostats_live(fd, nsp, opts); 319 return; 320 } 321 printf("List of active MAP/Redirect filters:\n"); 322 while (nsp->ns_list) { 323 if (kmemcpy((char *)&ipn, (long)nsp->ns_list, 324 sizeof(ipn))) { 325 perror("kmemcpy"); 326 break; 327 } 328 if (opts & OPT_HITS) 329 printf("%lu ", ipn.in_hits); 330 printnat(&ipn, opts & (OPT_DEBUG|OPT_VERBOSE)); 331 nsp->ns_list = ipn.in_next; 332 } 333 334 printf("\nList of active sessions:\n"); 335 336 for (np = nsp->ns_instances; np; np = nat.nat_next) { 337 if (kmemcpy((char *)&nat, (long)np, sizeof(nat))) 338 break; 339 printactivenat(&nat, opts, 0); 340 if (nat.nat_aps) 341 printaps(nat.nat_aps, opts); 342 } 343 344 if (opts & OPT_VERBOSE) 345 showhostmap(nsp); 346 } 347 } 348 349 350 /* 351 * Display the active host mapping table. 352 */ 353 void showhostmap(nsp) 354 natstat_t *nsp; 355 { 356 hostmap_t hm, *hmp, **maptable; 357 u_int hv; 358 359 printf("\nList of active host mappings:\n"); 360 361 maptable = (hostmap_t **)malloc(sizeof(hostmap_t *) * 362 nsp->ns_hostmap_sz); 363 if (maptable == NULL) { 364 perror("malloc"); 365 exit(1); 366 } 367 if (kmemcpy((char *)maptable, (u_long)nsp->ns_maptable, 368 sizeof(hostmap_t *) * nsp->ns_hostmap_sz)) { 369 perror("kmemcpy (maptable)"); 370 return; 371 } 372 373 for (hv = 0; hv < nsp->ns_hostmap_sz; hv++) { 374 hmp = maptable[hv]; 375 376 while (hmp) { 377 if (kmemcpy((char *)&hm, (u_long)hmp, sizeof(hm))) { 378 perror("kmemcpy (hostmap)"); 379 return; 380 } 381 382 printhostmap(&hm, hv); 383 hmp = hm.hm_next; 384 } 385 } 386 free(maptable); 387 } 388 389 390 /* 391 * Issue an ioctl to flush either the NAT rules table or the active mapping 392 * table or both. 393 */ 394 void flushtable(fd, opts) 395 int fd, opts; 396 { 397 int n = 0; 398 399 if (opts & OPT_FLUSH) { 400 n = 0; 401 if (!(opts & OPT_DONOTHING) && ioctl(fd, SIOCIPFFL, &n) == -1) 402 perror("ioctl(SIOCFLNAT)"); 403 else 404 printf("%d entries flushed from NAT table\n", n); 405 } 406 407 if (opts & OPT_CLEAR) { 408 n = 1; 409 if (!(opts & OPT_DONOTHING) && ioctl(fd, SIOCIPFFL, &n) == -1) 410 perror("ioctl(SIOCCNATL)"); 411 else 412 printf("%d entries flushed from NAT list\n", n); 413 } 414 } 415 416 /* 417 * Display NAT statistics. 418 */ 419 void dostats_live(fd, nsp, opts) 420 natstat_t *nsp; 421 int fd, opts; 422 { 423 ipfgeniter_t iter; 424 ipfobj_t obj; 425 ipnat_t ipn; 426 nat_t nat; 427 428 bzero((char *)&obj, sizeof(obj)); 429 obj.ipfo_rev = IPFILTER_VERSION; 430 obj.ipfo_type = IPFOBJ_GENITER; 431 obj.ipfo_size = sizeof(iter); 432 obj.ipfo_ptr = &iter; 433 434 iter.igi_type = IPFGENITER_IPNAT; 435 iter.igi_nitems = 1; 436 iter.igi_data = &ipn; 437 438 /* 439 * Show list of NAT rules and NAT sessions ? 440 */ 441 printf("List of active MAP/Redirect filters:\n"); 442 while (nsp->ns_list) { 443 if (ioctl(fd, SIOCGENITER, &obj) == -1) 444 break; 445 if (opts & OPT_HITS) 446 printf("%lu ", ipn.in_hits); 447 printnat(&ipn, opts & (OPT_DEBUG|OPT_VERBOSE)); 448 nsp->ns_list = ipn.in_next; 449 } 450 451 printf("\nList of active sessions:\n"); 452 453 iter.igi_type = IPFGENITER_NAT; 454 iter.igi_nitems = 1; 455 iter.igi_data = &nat; 456 457 while (nsp->ns_instances != NULL) { 458 if (ioctl(fd, SIOCGENITER, &obj) == -1) 459 break; 460 printactivenat(&nat, opts, 1); 461 if (nat.nat_aps) 462 printaps(nat.nat_aps, opts); 463 nsp->ns_instances = nat.nat_next; 464 } 465 466 if (opts & OPT_VERBOSE) 467 showhostmap_live(fd, nsp); 468 } 469 470 /* 471 * Display the active host mapping table. 472 */ 473 void showhostmap_live(fd, nsp) 474 int fd; 475 natstat_t *nsp; 476 { 477 hostmap_t hm, *hmp; 478 ipfgeniter_t iter; 479 ipfobj_t obj; 480 481 bzero((char *)&obj, sizeof(obj)); 482 obj.ipfo_rev = IPFILTER_VERSION; 483 obj.ipfo_type = IPFOBJ_GENITER; 484 obj.ipfo_size = sizeof(iter); 485 obj.ipfo_ptr = &iter; 486 487 iter.igi_type = IPFGENITER_HOSTMAP; 488 iter.igi_nitems = 1; 489 iter.igi_data = &hm; 490 491 printf("\nList of active host mappings:\n"); 492 493 while (nsp->ns_maplist != NULL) { 494 if (ioctl(fd, SIOCGENITER, &obj) == -1) 495 break; 496 printhostmap(&hm, 0); 497 nsp->ns_maplist = hm.hm_next; 498 } 499 } 500