1 /* Code to save the iptables state, in human readable-form. */ 2 /* (C) 1999 by Paul 'Rusty' Russell <rusty (at) rustcorp.com.au> and 3 * (C) 2000-2002 by Harald Welte <laforge (at) gnumonks.org> 4 * 5 * This code is distributed under the terms of GNU GPL v2 6 * 7 */ 8 #include <getopt.h> 9 #include <sys/errno.h> 10 #include <stdio.h> 11 #include <fcntl.h> 12 #include <stdlib.h> 13 #include <string.h> 14 #include <dlfcn.h> 15 #include <time.h> 16 #include <netdb.h> 17 #include "libiptc/libiptc.h" 18 #include "iptables.h" 19 20 static int binary = 0, counters = 0; 21 22 static struct option options[] = { 23 { "binary", 0, 0, 'b' }, 24 { "counters", 0, 0, 'c' }, 25 { "dump", 0, 0, 'd' }, 26 { "table", 1, 0, 't' }, 27 { 0 } 28 }; 29 30 #define IP_PARTS_NATIVE(n) \ 31 (unsigned int)((n)>>24)&0xFF, \ 32 (unsigned int)((n)>>16)&0xFF, \ 33 (unsigned int)((n)>>8)&0xFF, \ 34 (unsigned int)((n)&0xFF) 35 36 #define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n)) 37 38 /* This assumes that mask is contiguous, and byte-bounded. */ 39 static void 40 print_iface(char letter, const char *iface, const unsigned char *mask, 41 int invert) 42 { 43 unsigned int i; 44 45 if (mask[0] == 0) 46 return; 47 48 printf("-%c %s", letter, invert ? "! " : ""); 49 50 for (i = 0; i < IFNAMSIZ; i++) { 51 if (mask[i] != 0) { 52 if (iface[i] != '\0') 53 printf("%c", iface[i]); 54 } else { 55 /* we can access iface[i-1] here, because 56 * a few lines above we make sure that mask[0] != 0 */ 57 if (iface[i-1] != '\0') 58 printf("+"); 59 break; 60 } 61 } 62 63 printf(" "); 64 } 65 66 /* These are hardcoded backups in iptables.c, so they are safe */ 67 struct pprot { 68 char *name; 69 u_int8_t num; 70 }; 71 72 /* FIXME: why don't we use /etc/protocols ? */ 73 static const struct pprot chain_protos[] = { 74 { "tcp", IPPROTO_TCP }, 75 { "udp", IPPROTO_UDP }, 76 { "icmp", IPPROTO_ICMP }, 77 { "esp", IPPROTO_ESP }, 78 { "ah", IPPROTO_AH }, 79 { "sctp", IPPROTO_SCTP }, 80 }; 81 82 static void print_proto(u_int16_t proto, int invert) 83 { 84 if (proto) { 85 unsigned int i; 86 const char *invertstr = invert ? "! " : ""; 87 88 struct protoent *pent = getprotobynumber(proto); 89 if (pent) { 90 printf("-p %s%s ", invertstr, pent->p_name); 91 return; 92 } 93 94 for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++) 95 if (chain_protos[i].num == proto) { 96 printf("-p %s%s ", 97 invertstr, chain_protos[i].name); 98 return; 99 } 100 101 printf("-p %s%u ", invertstr, proto); 102 } 103 } 104 105 #if 0 106 static int non_zero(const void *ptr, size_t size) 107 { 108 unsigned int i; 109 110 for (i = 0; i < size; i++) 111 if (((char *)ptr)[i]) 112 return 0; 113 114 return 1; 115 } 116 #endif 117 118 static int print_match(const struct ipt_entry_match *e, 119 const struct ipt_ip *ip) 120 { 121 struct iptables_match *match 122 = find_match(e->u.user.name, TRY_LOAD, NULL); 123 124 if (match) { 125 printf("-m %s ", e->u.user.name); 126 127 /* some matches don't provide a save function */ 128 if (match->save) 129 match->save(ip, e); 130 } else { 131 if (e->u.match_size) { 132 fprintf(stderr, 133 "Can't find library for match `%s'\n", 134 e->u.user.name); 135 exit(1); 136 } 137 } 138 return 0; 139 } 140 141 /* print a given ip including mask if neccessary */ 142 static void print_ip(char *prefix, u_int32_t ip, u_int32_t mask, int invert) 143 { 144 if (!mask && !ip && !invert) 145 return; 146 147 printf("%s %s%u.%u.%u.%u", 148 prefix, 149 invert ? "! " : "", 150 IP_PARTS(ip)); 151 152 if (mask != 0xffffffff) 153 printf("/%u.%u.%u.%u ", IP_PARTS(mask)); 154 else 155 printf(" "); 156 } 157 158 /* We want this to be readable, so only print out neccessary fields. 159 * Because that's the kind of world I want to live in. */ 160 static void print_rule(const struct ipt_entry *e, 161 iptc_handle_t *h, const char *chain, int counters) 162 { 163 struct ipt_entry_target *t; 164 const char *target_name; 165 166 /* print counters */ 167 if (counters) 168 printf("[%llu:%llu] ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt); 169 170 /* print chain name */ 171 printf("-A %s ", chain); 172 173 /* Print IP part. */ 174 print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr, 175 e->ip.invflags & IPT_INV_SRCIP); 176 177 print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr, 178 e->ip.invflags & IPT_INV_DSTIP); 179 180 print_iface('i', e->ip.iniface, e->ip.iniface_mask, 181 e->ip.invflags & IPT_INV_VIA_IN); 182 183 print_iface('o', e->ip.outiface, e->ip.outiface_mask, 184 e->ip.invflags & IPT_INV_VIA_OUT); 185 186 print_proto(e->ip.proto, e->ip.invflags & IPT_INV_PROTO); 187 188 if (e->ip.flags & IPT_F_FRAG) 189 printf("%s-f ", 190 e->ip.invflags & IPT_INV_FRAG ? "! " : ""); 191 192 /* Print matchinfo part */ 193 if (e->target_offset) { 194 IPT_MATCH_ITERATE(e, print_match, &e->ip); 195 } 196 197 /* Print target name */ 198 target_name = iptc_get_target(e, h); 199 if (target_name && (*target_name != '\0')) 200 #ifdef IPT_F_GOTO 201 printf("-%c %s ", e->ip.flags & IPT_F_GOTO ? 'g' : 'j', target_name); 202 #else 203 printf("-j %s ", target_name); 204 #endif 205 206 /* Print targinfo part */ 207 t = ipt_get_target((struct ipt_entry *)e); 208 if (t->u.user.name[0]) { 209 struct iptables_target *target 210 = find_target(t->u.user.name, TRY_LOAD); 211 212 if (!target) { 213 fprintf(stderr, "Can't find library for target `%s'\n", 214 t->u.user.name); 215 exit(1); 216 } 217 218 if (target->save) 219 target->save(&e->ip, t); 220 else { 221 /* If the target size is greater than ipt_entry_target 222 * there is something to be saved, we just don't know 223 * how to print it */ 224 if (t->u.target_size != 225 sizeof(struct ipt_entry_target)) { 226 fprintf(stderr, "Target `%s' is missing " 227 "save function\n", 228 t->u.user.name); 229 exit(1); 230 } 231 } 232 } 233 printf("\n"); 234 } 235 236 /* Debugging prototype. */ 237 static int for_each_table(int (*func)(const char *tablename)) 238 { 239 int ret = 1; 240 FILE *procfile = NULL; 241 char tablename[IPT_TABLE_MAXNAMELEN+1]; 242 243 procfile = fopen("/proc/net/ip_tables_names", "r"); 244 if (!procfile) 245 return 0; 246 247 while (fgets(tablename, sizeof(tablename), procfile)) { 248 if (tablename[strlen(tablename) - 1] != '\n') 249 exit_error(OTHER_PROBLEM, 250 "Badly formed tablename `%s'\n", 251 tablename); 252 tablename[strlen(tablename) - 1] = '\0'; 253 ret &= func(tablename); 254 } 255 256 return ret; 257 } 258 259 260 static int do_output(const char *tablename) 261 { 262 iptc_handle_t h; 263 const char *chain = NULL; 264 265 if (!tablename) 266 return for_each_table(&do_output); 267 268 h = iptc_init(tablename); 269 if (!h) 270 exit_error(OTHER_PROBLEM, "Can't initialize: %s\n", 271 iptc_strerror(errno)); 272 273 if (!binary) { 274 time_t now = time(NULL); 275 276 printf("# Generated by iptables-save v%s on %s", 277 IPTABLES_VERSION, ctime(&now)); 278 printf("*%s\n", tablename); 279 280 /* Dump out chain names first, 281 * thereby preventing dependency conflicts */ 282 for (chain = iptc_first_chain(&h); 283 chain; 284 chain = iptc_next_chain(&h)) { 285 286 printf(":%s ", chain); 287 if (iptc_builtin(chain, h)) { 288 struct ipt_counters count; 289 printf("%s ", 290 iptc_get_policy(chain, &count, &h)); 291 printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt); 292 } else { 293 printf("- [0:0]\n"); 294 } 295 } 296 297 298 for (chain = iptc_first_chain(&h); 299 chain; 300 chain = iptc_next_chain(&h)) { 301 const struct ipt_entry *e; 302 303 /* Dump out rules */ 304 e = iptc_first_rule(chain, &h); 305 while(e) { 306 print_rule(e, &h, chain, counters); 307 e = iptc_next_rule(e, &h); 308 } 309 } 310 311 now = time(NULL); 312 printf("COMMIT\n"); 313 printf("# Completed on %s", ctime(&now)); 314 } else { 315 /* Binary, huh? OK. */ 316 exit_error(OTHER_PROBLEM, "Binary NYI\n"); 317 } 318 319 iptc_free(&h); 320 321 return 1; 322 } 323 324 /* Format: 325 * :Chain name POLICY packets bytes 326 * rule 327 */ 328 #ifdef IPTABLES_MULTI 329 int 330 iptables_save_main(int argc, char *argv[]) 331 #else 332 int 333 main(int argc, char *argv[]) 334 #endif 335 { 336 const char *tablename = NULL; 337 int c; 338 339 program_name = "iptables-save"; 340 program_version = IPTABLES_VERSION; 341 342 lib_dir = getenv("IPTABLES_LIB_DIR"); 343 if (!lib_dir) 344 lib_dir = IPT_LIB_DIR; 345 346 #ifdef NO_SHARED_LIBS 347 init_extensions(); 348 #endif 349 350 while ((c = getopt_long(argc, argv, "bcdt:", options, NULL)) != -1) { 351 switch (c) { 352 case 'b': 353 binary = 1; 354 break; 355 356 case 'c': 357 counters = 1; 358 break; 359 360 case 't': 361 /* Select specific table. */ 362 tablename = optarg; 363 break; 364 case 'd': 365 do_output(tablename); 366 exit(0); 367 } 368 } 369 370 if (optind < argc) { 371 fprintf(stderr, "Unknown arguments found on commandline"); 372 exit(1); 373 } 374 375 return !do_output(tablename); 376 } 377