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 int use_inet6 = 0; 74 extern char thishost[MAXHOSTNAMELEN]; 75 76 extern char *optarg; 77 78 void dostats __P((int, natstat_t *, int, int)); 79 void flushtable __P((int, int)); 80 void usage __P((char *)); 81 int main __P((int, char *[])); 82 void showhostmap __P((natstat_t *nsp)); 83 void natstat_dead __P((natstat_t *, char *)); 84 void dostats_live __P((int, natstat_t *, int)); 85 void showhostmap_live __P((int, natstat_t *)); 86 87 int opts; 88 89 void 90 usage(char *name) 91 { 92 fprintf(stderr, "Usage: %s [-CdFhlnrRsv] [-f filename]", name); 93 fprintf(stderr, " [-G|-z zonename]\n"); 94 exit(1); 95 } 96 97 98 int 99 main(int argc, char *argv[]) 100 { 101 char *file, *core, *kernel; 102 natstat_t ns, *nsp; 103 int fd, c, mode; 104 ipfobj_t obj; 105 106 fd = -1; 107 opts = 0; 108 nsp = &ns; 109 file = NULL; 110 core = NULL; 111 kernel = NULL; 112 mode = O_RDWR; 113 114 while ((c = getopt(argc, argv, "CdFf:G:hlM:N:nrRsvz:")) != -1) 115 switch (c) { 116 case 'C' : 117 opts |= OPT_CLEAR; 118 break; 119 case 'd' : 120 opts |= OPT_DEBUG; 121 break; 122 case 'f' : 123 file = optarg; 124 break; 125 case 'F' : 126 opts |= OPT_FLUSH; 127 break; 128 case 'G' : 129 setzonename_global(optarg); 130 break; 131 case 'h' : 132 opts |= OPT_HITS; 133 break; 134 case 'l' : 135 opts |= OPT_LIST; 136 mode = O_RDONLY; 137 break; 138 case 'M' : 139 core = optarg; 140 break; 141 case 'N' : 142 kernel = optarg; 143 break; 144 case 'n' : 145 opts |= OPT_DONOTHING; 146 mode = O_RDONLY; 147 break; 148 case 'R' : 149 opts |= OPT_NORESOLVE; 150 break; 151 case 'r' : 152 opts |= OPT_REMOVE; 153 break; 154 case 's' : 155 opts |= OPT_STAT; 156 mode = O_RDONLY; 157 break; 158 case 'v' : 159 opts |= OPT_VERBOSE; 160 break; 161 case 'z' : 162 setzonename(optarg); 163 break; 164 default : 165 usage(argv[0]); 166 } 167 168 initparse(); 169 170 if ((kernel != NULL) || (core != NULL)) { 171 (void) setgid(getgid()); 172 (void) setreuid(getuid(), getuid()); 173 } 174 175 bzero((char *)&ns, sizeof (ns)); 176 177 if ((opts & OPT_DONOTHING) == 0) { 178 if (checkrev(IPL_NAME) == -1) { 179 fprintf(stderr, "User/kernel version check failed\n"); 180 exit(1); 181 } 182 } 183 184 185 if (!(opts & OPT_DONOTHING) && (kernel == NULL) && (core == NULL)) { 186 #ifdef notdef 187 if (openkmem(kernel, core) == -1) 188 exit(1); 189 #endif 190 if (((fd = open(IPNAT_NAME, mode)) == -1) && 191 ((fd = open(IPNAT_NAME, O_RDONLY)) == -1)) { 192 (void) fprintf(stderr, "%s: open: %s\n", IPNAT_NAME, 193 STRERROR(errno)); 194 exit(1); 195 } 196 197 if (setzone(fd) != 0) { 198 close(fd); 199 exit(1); 200 } 201 202 bzero((char *)&obj, sizeof (obj)); 203 obj.ipfo_rev = IPFILTER_VERSION; 204 obj.ipfo_size = sizeof (*nsp); 205 obj.ipfo_type = IPFOBJ_NATSTAT; 206 obj.ipfo_ptr = (void *)nsp; 207 if (ioctl(fd, SIOCGNATS, &obj) == -1) { 208 perror("ioctl(SIOCGNATS)"); 209 exit(1); 210 } 211 (void) setgid(getgid()); 212 (void) setreuid(getuid(), getuid()); 213 } else if ((kernel != NULL) || (core != NULL)) { 214 if (openkmem(kernel, core) == -1) 215 exit(1); 216 217 natstat_dead(nsp, kernel); 218 if (opts & (OPT_LIST|OPT_STAT)) 219 dostats(fd, nsp, opts, 0); 220 exit(0); 221 } 222 223 if (opts & (OPT_FLUSH|OPT_CLEAR)) 224 flushtable(fd, opts); 225 if (file) { 226 ipnat_parsefile(fd, ipnat_addrule, ioctl, file); 227 } 228 if (opts & (OPT_LIST|OPT_STAT)) 229 dostats(fd, nsp, opts, 1); 230 return (0); 231 } 232 233 234 /* 235 * Read NAT statistic information in using a symbol table and memory file 236 * rather than doing ioctl's. 237 */ 238 void 239 natstat_dead(natstat_t *nsp, char *kernel) 240 { 241 struct nlist nat_nlist[10] = { 242 { "nat_table" }, /* 0 */ 243 { "nat_list" }, 244 { "maptable" }, 245 { "ipf_nattable_sz" }, 246 { "ipf_natrules_sz" }, 247 { "ipf_rdrrules_sz" }, /* 5 */ 248 { "ipf_hostmap_sz" }, 249 { "nat_instances" }, 250 { "ap_sess_list" }, 251 { NULL } 252 }; 253 void *tables[2]; 254 255 if (nlist(kernel, nat_nlist) == -1) { 256 fprintf(stderr, "nlist error\n"); 257 return; 258 } 259 260 /* 261 * Normally the ioctl copies all of these values into the structure 262 * for us, before returning it to userland, so here we must copy each 263 * one in individually. 264 */ 265 kmemcpy((char *)&tables, nat_nlist[0].n_value, sizeof (tables)); 266 nsp->ns_table[0] = tables[0]; 267 nsp->ns_table[1] = tables[1]; 268 269 kmemcpy((char *)&nsp->ns_list, nat_nlist[1].n_value, 270 sizeof (nsp->ns_list)); 271 kmemcpy((char *)&nsp->ns_maptable, nat_nlist[2].n_value, 272 sizeof (nsp->ns_maptable)); 273 kmemcpy((char *)&nsp->ns_nattab_sz, nat_nlist[3].n_value, 274 sizeof (nsp->ns_nattab_sz)); 275 kmemcpy((char *)&nsp->ns_rultab_sz, nat_nlist[4].n_value, 276 sizeof (nsp->ns_rultab_sz)); 277 kmemcpy((char *)&nsp->ns_rdrtab_sz, nat_nlist[5].n_value, 278 sizeof (nsp->ns_rdrtab_sz)); 279 kmemcpy((char *)&nsp->ns_hostmap_sz, nat_nlist[6].n_value, 280 sizeof (nsp->ns_hostmap_sz)); 281 kmemcpy((char *)&nsp->ns_instances, nat_nlist[7].n_value, 282 sizeof (nsp->ns_instances)); 283 kmemcpy((char *)&nsp->ns_apslist, nat_nlist[8].n_value, 284 sizeof (nsp->ns_apslist)); 285 } 286 287 288 /* 289 * Display NAT statistics. 290 */ 291 void 292 dostats(int fd, natstat_t *nsp, int opts, int alive) 293 { 294 nat_t *np, nat; 295 ipnat_t ipn; 296 297 /* 298 * Show statistics ? 299 */ 300 if (opts & OPT_STAT) { 301 printf("mapped\tin\t%lu\tout\t%lu\n", 302 nsp->ns_mapped[0], nsp->ns_mapped[1]); 303 printf("added\t%lu\texpired\t%lu\n", 304 nsp->ns_added, nsp->ns_expire); 305 printf("no memory\t%lu\tbad nat\t%lu\n", 306 nsp->ns_memfail, nsp->ns_badnat); 307 printf("inuse\t%lu\norphans\t%u\nrules\t%lu\n", 308 nsp->ns_inuse, nsp->ns_orphans, nsp->ns_rules); 309 printf("wilds\t%u\n", nsp->ns_wilds); 310 if (opts & OPT_VERBOSE) 311 printf("table %p list %p\n", 312 nsp->ns_table, nsp->ns_list); 313 } 314 315 /* 316 * Show list of NAT rules and NAT sessions ? 317 */ 318 if (opts & OPT_LIST) { 319 if (alive) { 320 dostats_live(fd, nsp, opts); 321 return; 322 } 323 printf("List of active MAP/Redirect filters:\n"); 324 while (nsp->ns_list) { 325 if (kmemcpy((char *)&ipn, (long)nsp->ns_list, 326 sizeof (ipn))) { 327 perror("kmemcpy"); 328 break; 329 } 330 if (opts & OPT_HITS) 331 printf("%lu ", ipn.in_hits); 332 printnat(&ipn, opts & (OPT_DEBUG|OPT_VERBOSE)); 333 nsp->ns_list = ipn.in_next; 334 } 335 336 printf("\nList of active sessions:\n"); 337 338 for (np = nsp->ns_instances; np; np = nat.nat_next) { 339 if (kmemcpy((char *)&nat, (long)np, sizeof (nat))) 340 break; 341 printactivenat(&nat, opts, 0); 342 if (nat.nat_aps) 343 printaps(nat.nat_aps, opts); 344 } 345 346 if (opts & OPT_VERBOSE) 347 showhostmap(nsp); 348 } 349 } 350 351 352 /* 353 * Display the active host mapping table. 354 */ 355 void 356 showhostmap(natstat_t *nsp) 357 { 358 hostmap_t hm, *hmp, **maptable; 359 uint_t hv; 360 361 printf("\nList of active host mappings:\n"); 362 363 maptable = (hostmap_t **)malloc(sizeof (hostmap_t *) * 364 nsp->ns_hostmap_sz); 365 if (maptable == NULL) { 366 perror("malloc"); 367 exit(1); 368 } 369 if (kmemcpy((char *)maptable, (ulong_t)nsp->ns_maptable, 370 sizeof (hostmap_t *) * nsp->ns_hostmap_sz)) { 371 perror("kmemcpy (maptable)"); 372 return; 373 } 374 375 for (hv = 0; hv < nsp->ns_hostmap_sz; hv++) { 376 hmp = maptable[hv]; 377 378 while (hmp) { 379 if (kmemcpy((char *)&hm, (ulong_t)hmp, sizeof (hm))) { 380 perror("kmemcpy (hostmap)"); 381 return; 382 } 383 384 printhostmap(&hm, hv); 385 hmp = hm.hm_next; 386 } 387 } 388 free(maptable); 389 } 390 391 392 /* 393 * Issue an ioctl to flush either the NAT rules table or the active mapping 394 * table or both. 395 */ 396 void 397 flushtable(int fd, int opts) 398 { 399 int n = 0; 400 401 if (opts & OPT_FLUSH) { 402 n = FLUSH_TABLE_ALL; 403 if (!(opts & OPT_DONOTHING) && ioctl(fd, SIOCIPFFL, &n) == -1) 404 perror("ioctl(SIOCFLNAT)"); 405 else 406 printf("%d entries flushed from NAT table\n", n); 407 } 408 409 if (opts & OPT_CLEAR) { 410 n = FLUSH_LIST; 411 if (!(opts & OPT_DONOTHING) && ioctl(fd, SIOCIPFFL, &n) == -1) 412 perror("ioctl(SIOCCNATL)"); 413 else 414 printf("%d entries flushed from NAT list\n", n); 415 } 416 } 417 418 /* 419 * Display NAT statistics. 420 */ 421 void 422 dostats_live(int fd, natstat_t *nsp, int opts) 423 { 424 ipfgeniter_t iter; 425 ipfobj_t obj; 426 ipnat_t ipn; 427 nat_t nat; 428 429 bzero((char *)&obj, sizeof (obj)); 430 obj.ipfo_rev = IPFILTER_VERSION; 431 obj.ipfo_type = IPFOBJ_GENITER; 432 obj.ipfo_size = sizeof (iter); 433 obj.ipfo_ptr = &iter; 434 435 iter.igi_type = IPFGENITER_IPNAT; 436 iter.igi_nitems = 1; 437 iter.igi_data = &ipn; 438 439 /* 440 * Show list of NAT rules and NAT sessions ? 441 */ 442 printf("List of active MAP/Redirect filters:\n"); 443 while (nsp->ns_list) { 444 if (ioctl(fd, SIOCGENITER, &obj) == -1) 445 break; 446 if (opts & OPT_HITS) 447 printf("%lu ", ipn.in_hits); 448 printnat(&ipn, opts & (OPT_DEBUG|OPT_VERBOSE)); 449 nsp->ns_list = ipn.in_next; 450 } 451 452 printf("\nList of active sessions:\n"); 453 454 iter.igi_type = IPFGENITER_NAT; 455 iter.igi_nitems = 1; 456 iter.igi_data = &nat; 457 458 while (nsp->ns_instances != NULL) { 459 if (ioctl(fd, SIOCGENITER, &obj) == -1) 460 break; 461 printactivenat(&nat, opts, 1); 462 if (nat.nat_aps) 463 printaps(nat.nat_aps, opts); 464 nsp->ns_instances = nat.nat_next; 465 } 466 467 if (opts & OPT_VERBOSE) 468 showhostmap_live(fd, nsp); 469 } 470 471 /* 472 * Display the active host mapping table. 473 */ 474 void 475 showhostmap_live(int fd, 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