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