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 2006 Sun Microsystems, Inc. All rights reserved. 9 * Use is subject to license terms. 10 */ 11 12 #pragma ident "%Z%%M% %I% %E% SMI" 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 61 #ifdef __hpux 62 # define nlist nlist64 63 #endif 64 65 #if defined(sun) && !SOLARIS2 66 # define STRERROR(x) sys_errlist[x] 67 extern char *sys_errlist[]; 68 #else 69 # define STRERROR(x) strerror(x) 70 #endif 71 72 #if !defined(lint) 73 static const char sccsid[] ="@(#)ipnat.c 1.9 6/5/96 (C) 1993 Darren Reed"; 74 static const char rcsid[] = "@(#)$Id: ipnat.c,v 1.24.2.2 2005/05/10 21:19:30 darrenr Exp $"; 75 #endif 76 77 78 #if SOLARIS 79 #define bzero(a,b) memset(a,0,b) 80 #endif 81 int use_inet6 = 0; 82 char thishost[MAXHOSTNAMELEN]; 83 84 extern char *optarg; 85 86 void dostats __P((natstat_t *, int)), flushtable __P((int, int)); 87 void usage __P((char *)); 88 int main __P((int, char*[])); 89 void showhostmap __P((natstat_t *nsp)); 90 void natstat_dead __P((natstat_t *, char *)); 91 92 int opts; 93 94 void usage(name) 95 char *name; 96 { 97 fprintf(stderr, "Usage: %s [-CdFhlnrRsv] [-f filename]\n", name); 98 exit(1); 99 } 100 101 102 int main(argc, argv) 103 int argc; 104 char *argv[]; 105 { 106 char *file, *core, *kernel; 107 natstat_t ns, *nsp; 108 int fd, c, mode; 109 ipfobj_t obj; 110 111 fd = -1; 112 opts = 0; 113 nsp = &ns; 114 file = NULL; 115 core = NULL; 116 kernel = NULL; 117 mode = O_RDWR; 118 119 while ((c = getopt(argc, argv, "CdFf:hlM:N:nrRsv")) != -1) 120 switch (c) 121 { 122 case 'C' : 123 opts |= OPT_CLEAR; 124 break; 125 case 'd' : 126 opts |= OPT_DEBUG; 127 break; 128 case 'f' : 129 file = optarg; 130 break; 131 case 'F' : 132 opts |= OPT_FLUSH; 133 break; 134 case 'h' : 135 opts |=OPT_HITS; 136 break; 137 case 'l' : 138 opts |= OPT_LIST; 139 mode = O_RDONLY; 140 break; 141 case 'M' : 142 core = optarg; 143 break; 144 case 'N' : 145 kernel = optarg; 146 break; 147 case 'n' : 148 opts |= OPT_DONOTHING; 149 mode = O_RDONLY; 150 break; 151 case 'R' : 152 opts |= OPT_NORESOLVE; 153 break; 154 case 'r' : 155 opts |= OPT_REMOVE; 156 break; 157 case 's' : 158 opts |= OPT_STAT; 159 mode = O_RDONLY; 160 break; 161 case 'v' : 162 opts |= OPT_VERBOSE; 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 if (openkmem(kernel, core) == -1) 187 exit(1); 188 189 if (((fd = open(IPNAT_NAME, mode)) == -1) && 190 ((fd = open(IPNAT_NAME, O_RDONLY)) == -1)) { 191 (void) fprintf(stderr, "%s: open: %s\n", IPNAT_NAME, 192 STRERROR(errno)); 193 exit(1); 194 } 195 196 bzero((char *)&obj, sizeof(obj)); 197 obj.ipfo_rev = IPFILTER_VERSION; 198 obj.ipfo_size = sizeof(*nsp); 199 obj.ipfo_type = IPFOBJ_NATSTAT; 200 obj.ipfo_ptr = (void *)nsp; 201 if (ioctl(fd, SIOCGNATS, &obj) == -1) { 202 perror("ioctl(SIOCGNATS)"); 203 exit(1); 204 } 205 (void) setgid(getgid()); 206 (void) setreuid(getuid(), getuid()); 207 } else if ((kernel != NULL) || (core != NULL)) { 208 if (openkmem(kernel, core) == -1) 209 exit(1); 210 211 natstat_dead(nsp, kernel); 212 if (opts & (OPT_LIST|OPT_STAT)) 213 dostats(nsp, opts); 214 exit(0); 215 } 216 217 if (opts & (OPT_FLUSH|OPT_CLEAR)) 218 flushtable(fd, opts); 219 if (file) { 220 ipnat_parsefile(fd, ipnat_addrule, ioctl, file); 221 } 222 if (opts & (OPT_LIST|OPT_STAT)) 223 dostats(nsp, opts); 224 return 0; 225 } 226 227 228 /* 229 * Read NAT statistic information in using a symbol table and memory file 230 * rather than doing ioctl's. 231 */ 232 void natstat_dead(nsp, kernel) 233 natstat_t *nsp; 234 char *kernel; 235 { 236 struct nlist nat_nlist[10] = { 237 { "nat_table" }, /* 0 */ 238 { "nat_list" }, 239 { "maptable" }, 240 { "ipf_nattable_sz" }, 241 { "ipf_natrules_sz" }, 242 { "ipf_rdrrules_sz" }, /* 5 */ 243 { "ipf_hostmap_sz" }, 244 { "nat_instances" }, 245 { "ap_sess_list" }, 246 { NULL } 247 }; 248 void *tables[2]; 249 250 if (nlist(kernel, nat_nlist) == -1) { 251 fprintf(stderr, "nlist error\n"); 252 return; 253 } 254 255 /* 256 * Normally the ioctl copies all of these values into the structure 257 * for us, before returning it to userland, so here we must copy each 258 * one in individually. 259 */ 260 kmemcpy((char *)&tables, nat_nlist[0].n_value, sizeof(tables)); 261 nsp->ns_table[0] = tables[0]; 262 nsp->ns_table[1] = tables[1]; 263 264 kmemcpy((char *)&nsp->ns_list, nat_nlist[1].n_value, 265 sizeof(nsp->ns_list)); 266 kmemcpy((char *)&nsp->ns_maptable, nat_nlist[2].n_value, 267 sizeof(nsp->ns_maptable)); 268 kmemcpy((char *)&nsp->ns_nattab_sz, nat_nlist[3].n_value, 269 sizeof(nsp->ns_nattab_sz)); 270 kmemcpy((char *)&nsp->ns_rultab_sz, nat_nlist[4].n_value, 271 sizeof(nsp->ns_rultab_sz)); 272 kmemcpy((char *)&nsp->ns_rdrtab_sz, nat_nlist[5].n_value, 273 sizeof(nsp->ns_rdrtab_sz)); 274 kmemcpy((char *)&nsp->ns_hostmap_sz, nat_nlist[6].n_value, 275 sizeof(nsp->ns_hostmap_sz)); 276 kmemcpy((char *)&nsp->ns_instances, nat_nlist[7].n_value, 277 sizeof(nsp->ns_instances)); 278 kmemcpy((char *)&nsp->ns_apslist, nat_nlist[8].n_value, 279 sizeof(nsp->ns_apslist)); 280 } 281 282 283 /* 284 * Display NAT statistics. 285 */ 286 void dostats(nsp, opts) 287 natstat_t *nsp; 288 int opts; 289 { 290 nat_t *np, nat; 291 ipnat_t ipn; 292 293 /* 294 * Show statistics ? 295 */ 296 if (opts & OPT_STAT) { 297 printf("mapped\tin\t%lu\tout\t%lu\n", 298 nsp->ns_mapped[0], nsp->ns_mapped[1]); 299 printf("added\t%lu\texpired\t%lu\n", 300 nsp->ns_added, nsp->ns_expire); 301 printf("no memory\t%lu\tbad nat\t%lu\n", 302 nsp->ns_memfail, nsp->ns_badnat); 303 printf("inuse\t%lu\nrules\t%lu\n", 304 nsp->ns_inuse, nsp->ns_rules); 305 printf("wilds\t%u\n", nsp->ns_wilds); 306 if (opts & OPT_VERBOSE) 307 printf("table %p list %p\n", 308 nsp->ns_table, nsp->ns_list); 309 } 310 311 /* 312 * Show list of NAT rules and NAT sessions ? 313 */ 314 if (opts & OPT_LIST) { 315 printf("List of active MAP/Redirect filters:\n"); 316 while (nsp->ns_list) { 317 if (kmemcpy((char *)&ipn, (long)nsp->ns_list, 318 sizeof(ipn))) { 319 perror("kmemcpy"); 320 break; 321 } 322 if (opts & OPT_HITS) 323 printf("%lu ", ipn.in_hits); 324 printnat(&ipn, opts & (OPT_DEBUG|OPT_VERBOSE)); 325 nsp->ns_list = ipn.in_next; 326 } 327 328 printf("\nList of active sessions:\n"); 329 330 for (np = nsp->ns_instances; np; np = nat.nat_next) { 331 if (kmemcpy((char *)&nat, (long)np, sizeof(nat))) 332 break; 333 printactivenat(&nat, opts); 334 if (nat.nat_aps) 335 printaps(nat.nat_aps, opts); 336 } 337 338 if (opts & OPT_VERBOSE) 339 showhostmap(nsp); 340 } 341 } 342 343 344 /* 345 * Display the active host mapping table. 346 */ 347 void showhostmap(nsp) 348 natstat_t *nsp; 349 { 350 hostmap_t hm, *hmp, **maptable; 351 u_int hv; 352 353 printf("\nList of active host mappings:\n"); 354 355 maptable = (hostmap_t **)malloc(sizeof(hostmap_t *) * 356 nsp->ns_hostmap_sz); 357 if (maptable == NULL) { 358 perror("malloc"); 359 exit(1); 360 } 361 if (kmemcpy((char *)maptable, (u_long)nsp->ns_maptable, 362 sizeof(hostmap_t *) * nsp->ns_hostmap_sz)) { 363 perror("kmemcpy (maptable)"); 364 return; 365 } 366 367 for (hv = 0; hv < nsp->ns_hostmap_sz; hv++) { 368 hmp = maptable[hv]; 369 370 while (hmp) { 371 if (kmemcpy((char *)&hm, (u_long)hmp, sizeof(hm))) { 372 perror("kmemcpy (hostmap)"); 373 return; 374 } 375 376 printhostmap(&hm, hv); 377 hmp = hm.hm_next; 378 } 379 } 380 free(maptable); 381 } 382 383 384 /* 385 * Issue an ioctl to flush either the NAT rules table or the active mapping 386 * table or both. 387 */ 388 void flushtable(fd, opts) 389 int fd, opts; 390 { 391 int n = 0; 392 393 if (opts & OPT_FLUSH) { 394 n = 0; 395 if (!(opts & OPT_DONOTHING) && ioctl(fd, SIOCIPFFL, &n) == -1) 396 perror("ioctl(SIOCFLNAT)"); 397 else 398 printf("%d entries flushed from NAT table\n", n); 399 } 400 401 if (opts & OPT_CLEAR) { 402 n = 1; 403 if (!(opts & OPT_DONOTHING) && ioctl(fd, SIOCIPFFL, &n) == -1) 404 perror("ioctl(SIOCCNATL)"); 405 else 406 printf("%d entries flushed from NAT list\n", n); 407 } 408 } 409