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