99
100
= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', 'f', '0', 'c'};
101
102
static struct option original_opts[] = {
102
{ "append", 1, NULL, 'A' },
103
{ "delete", 1, NULL, 'D' },
104
{ "insert", 1, NULL, 'I' },
105
{ "replace", 1, NULL, 'R' },
106
{ "list", 2, NULL, 'L' },
107
{ "flush", 2, NULL, 'F' },
108
{ "zero", 2, NULL, 'Z' },
109
{ "new-chain", 1, NULL, 'N' },
110
{ "delete-chain", 2, NULL, 'X' },
111
{ "rename-chain", 1, NULL, 'E' },
112
{ "policy", 1, NULL, 'P' },
113
{ "source", 1, NULL, 's' },
114
{ "destination", 1, NULL, 'd' },
115
{ "src", 1, NULL, 's' }, /* synonym */
116
{ "dst", 1, NULL, 'd' }, /* synonym */
117
{ "protocol", 1, NULL, 'p' },
118
{ "in-interface", 1, NULL, 'i' },
119
{ "jump", 1, NULL, 'j' },
120
{ "table", 1, NULL, 't' },
121
{ "match", 1, NULL, 'm' },
122
{ "numeric", 0, NULL, 'n' },
123
{ "out-interface", 1, NULL, 'o' },
124
{ "verbose", 0, NULL, 'v' },
125
{ "exact", 0, NULL, 'x' },
126
{ "fragments", 0, NULL, 'f' },
127
{ "version", 0, NULL, 'V' },
128
{ "help", 2, NULL, 'h' },
129
{ "line-numbers", 0, NULL, '0' },
130
{ "modprobe", 1, NULL, 'M' },
131
{ "set-counters", 1, NULL, 'c' },
132
{ "goto", 1, NULL, 'g' },
103
{.name = "append", .has_arg = 1, .val = 'A'},
104
{.name = "delete", .has_arg = 1, .val = 'D'},
105
{.name = "insert", .has_arg = 1, .val = 'I'},
106
{.name = "replace", .has_arg = 1, .val = 'R'},
107
{.name = "list", .has_arg = 2, .val = 'L'},
108
{.name = "list-rules", .has_arg = 2, .val = 'S'},
109
{.name = "flush", .has_arg = 2, .val = 'F'},
110
{.name = "zero", .has_arg = 2, .val = 'Z'},
111
{.name = "new-chain", .has_arg = 1, .val = 'N'},
112
{.name = "delete-chain", .has_arg = 2, .val = 'X'},
113
{.name = "rename-chain", .has_arg = 1, .val = 'E'},
114
{.name = "policy", .has_arg = 1, .val = 'P'},
115
{.name = "source", .has_arg = 1, .val = 's'},
116
{.name = "destination", .has_arg = 1, .val = 'd'},
117
{.name = "src", .has_arg = 1, .val = 's'}, /* synonym */
118
{.name = "dst", .has_arg = 1, .val = 'd'}, /* synonym */
119
{.name = "protocol", .has_arg = 1, .val = 'p'},
120
{.name = "in-interface", .has_arg = 1, .val = 'i'},
121
{.name = "jump", .has_arg = 1, .val = 'j'},
122
{.name = "table", .has_arg = 1, .val = 't'},
123
{.name = "match", .has_arg = 1, .val = 'm'},
124
{.name = "numeric", .has_arg = 0, .val = 'n'},
125
{.name = "out-interface", .has_arg = 1, .val = 'o'},
126
{.name = "verbose", .has_arg = 0, .val = 'v'},
127
{.name = "exact", .has_arg = 0, .val = 'x'},
128
{.name = "fragments", .has_arg = 0, .val = 'f'},
129
{.name = "version", .has_arg = 0, .val = 'V'},
130
{.name = "help", .has_arg = 2, .val = 'h'},
131
{.name = "line-numbers", .has_arg = 0, .val = '0'},
132
{.name = "modprobe", .has_arg = 1, .val = 'M'},
133
{.name = "set-counters", .has_arg = 1, .val = 'c'},
134
{.name = "goto", .has_arg = 1, .val = 'g'},
136
138
/* we need this for iptables-restore. iptables-restore.c sets line to the
165
167
/*ZERO*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
166
168
/*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
167
169
/*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
168
/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x','x','x'},
169
/*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'}
170
/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x','x',' '},
171
/*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
172
/*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x','x'}
172
175
static int inverse_for_options[NUMBER_OF_OPT] =
256
static struct in_addr *
257
__dotted_to_addr(const char *dotted, int type)
259
static struct in_addr addr;
260
unsigned char *addrp;
262
unsigned int onebyte;
266
/* copy dotted string, because we need to modify it */
267
strncpy(buf, dotted, sizeof(buf) - 1);
268
buf[sizeof(buf) - 1] = '\0';
269
addrp = (unsigned char *) &(addr.s_addr);
272
for (i = 0; i < 3; i++) {
273
if ((q = strchr(p, '.')) == NULL) {
274
if (type == IPT_DOTTED_ADDR) {
275
/* autocomplete, this is a network address */
276
if (string_to_number(p, 0, 255, &onebyte) == -1)
277
return (struct in_addr *) NULL;
279
addrp[i] = (unsigned char) onebyte;
285
return (struct in_addr *) NULL;
289
if (string_to_number(p, 0, 255, &onebyte) == -1)
290
return (struct in_addr *) NULL;
292
addrp[i] = (unsigned char) onebyte;
296
/* we've checked 3 bytes, now we check the last one */
297
if (string_to_number(p, 0, 255, &onebyte) == -1)
298
return (struct in_addr *) NULL;
300
addrp[3] = (unsigned char) onebyte;
306
dotted_to_addr(const char *dotted)
308
return __dotted_to_addr(dotted, IPT_DOTTED_ADDR);
312
dotted_to_mask(const char *dotted)
314
return __dotted_to_addr(dotted, IPT_DOTTED_MASK);
317
static struct in_addr *
318
network_to_addr(const char *name)
321
static struct in_addr addr;
323
if ((net = getnetbyname(name)) != NULL) {
324
if (net->n_addrtype != AF_INET)
325
return (struct in_addr *) NULL;
326
addr.s_addr = htonl((unsigned long) net->n_net);
330
return (struct in_addr *) NULL;
334
inaddrcpy(struct in_addr *dst, struct in_addr *src)
336
/* memcpy(dst, src, sizeof(struct in_addr)); */
337
dst->s_addr = src->s_addr;
340
257
static void free_opts(int reset_offset)
342
259
if (opts != original_opts) {
596
480
* return global static data.
599
static struct in_addr *
600
parse_hostnetwork(const char *name, unsigned int *naddrs)
602
struct in_addr *addrp, *addrptmp;
604
if ((addrptmp = dotted_to_addr(name)) != NULL ||
605
(addrptmp = network_to_addr(name)) != NULL) {
606
addrp = fw_malloc(sizeof(struct in_addr));
607
inaddrcpy(addrp, addrptmp);
611
if ((addrp = host_to_addr(name, naddrs)) != NULL)
614
exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", name);
617
static struct in_addr *
618
parse_mask(char *mask)
620
static struct in_addr maskaddr;
621
struct in_addr *addrp;
625
/* no mask at all defaults to 32 bits */
626
maskaddr.s_addr = 0xFFFFFFFF;
629
if ((addrp = dotted_to_mask(mask)) != NULL)
630
/* dotted_to_addr already returns a network byte order addr */
632
if (string_to_number(mask, 0, 32, &bits) == -1)
633
exit_error(PARAMETER_PROBLEM,
634
"invalid mask `%s' specified", mask);
636
maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
640
maskaddr.s_addr = 0L;
645
parse_hostnetworkmask(const char *name, struct in_addr **addrpp,
646
struct in_addr *maskp, unsigned int *naddrs)
648
struct in_addr *addrp;
653
strncpy(buf, name, sizeof(buf) - 1);
654
buf[sizeof(buf) - 1] = '\0';
655
if ((p = strrchr(buf, '/')) != NULL) {
657
addrp = parse_mask(p + 1);
659
addrp = parse_mask(NULL);
660
inaddrcpy(maskp, addrp);
662
/* if a null mask is given, the name is ignored, like in "any/0" */
663
if (maskp->s_addr == 0L)
664
strcpy(buf, "0.0.0.0");
666
addrp = *addrpp = parse_hostnetwork(buf, naddrs);
668
for (i = 0, j = 0; i < n; i++) {
669
addrp[j++].s_addr &= maskp->s_addr;
670
for (k = 0; k < j - 1; k++) {
671
if (addrp[k].s_addr == addrp[j - 1].s_addr) {
680
483
/* Christophe Burki wants `-p 6' to imply `-m tcp'. */
681
static struct iptables_match *
484
static struct xtables_match *
682
485
find_proto(const char *pname, enum ipt_tryload tryload, int nolookup, struct iptables_rule_match **matches)
684
487
unsigned int proto;
1114
static void print_proto(u_int16_t proto, int invert)
1118
const char *invertstr = invert ? "! " : "";
1120
struct protoent *pent = getprotobynumber(proto);
1122
printf("-p %s%s ", invertstr, pent->p_name);
1126
for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++)
1127
if (chain_protos[i].num == proto) {
1129
invertstr, chain_protos[i].name);
1133
printf("-p %s%u ", invertstr, proto);
1137
#define IP_PARTS_NATIVE(n) \
1138
(unsigned int)((n)>>24)&0xFF, \
1139
(unsigned int)((n)>>16)&0xFF, \
1140
(unsigned int)((n)>>8)&0xFF, \
1141
(unsigned int)((n)&0xFF)
1143
#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n))
1145
/* This assumes that mask is contiguous, and byte-bounded. */
1147
print_iface(char letter, const char *iface, const unsigned char *mask,
1155
printf("-%c %s", letter, invert ? "! " : "");
1157
for (i = 0; i < IFNAMSIZ; i++) {
1159
if (iface[i] != '\0')
1160
printf("%c", iface[i]);
1162
/* we can access iface[i-1] here, because
1163
* a few lines above we make sure that mask[0] != 0 */
1164
if (iface[i-1] != '\0')
1173
static int print_match_save(const struct ipt_entry_match *e,
1174
const struct ipt_ip *ip)
1176
struct xtables_match *match
1177
= find_match(e->u.user.name, TRY_LOAD, NULL);
1180
printf("-m %s ", e->u.user.name);
1182
/* some matches don't provide a save function */
1186
if (e->u.match_size) {
1188
"Can't find library for match `%s'\n",
1196
/* print a given ip including mask if neccessary */
1197
static void print_ip(char *prefix, u_int32_t ip, u_int32_t mask, int invert)
1199
u_int32_t bits, hmask = ntohl(mask);
1202
if (!mask && !ip && !invert)
1205
printf("%s %s%u.%u.%u.%u",
1210
if (mask == 0xFFFFFFFFU) {
1217
while (--i >= 0 && hmask != bits)
1222
printf("/%u.%u.%u.%u ", IP_PARTS(mask));
1225
/* We want this to be readable, so only print out neccessary fields.
1226
* Because that's the kind of world I want to live in. */
1227
void print_rule(const struct ipt_entry *e,
1228
iptc_handle_t *h, const char *chain, int counters)
1230
struct ipt_entry_target *t;
1231
const char *target_name;
1233
/* print counters for iptables-save */
1235
printf("[%llu:%llu] ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
1237
/* print chain name */
1238
printf("-A %s ", chain);
1240
/* Print IP part. */
1241
print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr,
1242
e->ip.invflags & IPT_INV_SRCIP);
1244
print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr,
1245
e->ip.invflags & IPT_INV_DSTIP);
1247
print_iface('i', e->ip.iniface, e->ip.iniface_mask,
1248
e->ip.invflags & IPT_INV_VIA_IN);
1250
print_iface('o', e->ip.outiface, e->ip.outiface_mask,
1251
e->ip.invflags & IPT_INV_VIA_OUT);
1253
print_proto(e->ip.proto, e->ip.invflags & IPT_INV_PROTO);
1255
if (e->ip.flags & IPT_F_FRAG)
1257
e->ip.invflags & IPT_INV_FRAG ? "! " : "");
1259
/* Print matchinfo part */
1260
if (e->target_offset) {
1261
IPT_MATCH_ITERATE(e, print_match_save, &e->ip);
1264
/* print counters for iptables -R */
1266
printf("-c %llu %llu ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt);
1268
/* Print target name */
1269
target_name = iptc_get_target(e, h);
1270
if (target_name && (*target_name != '\0'))
1272
printf("-%c %s ", e->ip.flags & IPT_F_GOTO ? 'g' : 'j', target_name);
1274
printf("-j %s ", target_name);
1277
/* Print targinfo part */
1278
t = ipt_get_target((struct ipt_entry *)e);
1279
if (t->u.user.name[0]) {
1280
struct xtables_target *target
1281
= find_target(t->u.user.name, TRY_LOAD);
1284
fprintf(stderr, "Can't find library for target `%s'\n",
1290
target->save(&e->ip, t);
1292
/* If the target size is greater than ipt_entry_target
1293
* there is something to be saved, we just don't know
1294
* how to print it */
1295
if (t->u.target_size !=
1296
sizeof(struct ipt_entry_target)) {
1297
fprintf(stderr, "Target `%s' is missing "
1308
list_rules(const ipt_chainlabel chain, int rulenum, int counters,
1309
iptc_handle_t *handle)
1311
const char *this = NULL;
1315
counters = -1; /* iptables -c format */
1317
/* Dump out chain names first,
1318
* thereby preventing dependency conflicts */
1319
if (!rulenum) for (this = iptc_first_chain(handle);
1321
this = iptc_next_chain(handle)) {
1322
if (chain && strcmp(this, chain) != 0)
1325
if (iptc_builtin(this, *handle)) {
1326
struct ipt_counters count;
1327
printf("-P %s %s", this, iptc_get_policy(this, &count, handle));
1329
printf(" -c %llu %llu", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
1332
printf("-N %s\n", this);
1336
for (this = iptc_first_chain(handle);
1338
this = iptc_next_chain(handle)) {
1339
const struct ipt_entry *e;
1342
if (chain && strcmp(this, chain) != 0)
1345
/* Dump out rules */
1346
e = iptc_first_rule(this, handle);
1349
if (!rulenum || num == rulenum)
1350
print_rule(e, handle, this, counters);
1351
e = iptc_next_rule(e, handle);
1378
1360
static struct ipt_entry *
1379
1361
generate_entry(const struct ipt_entry *fw,
1380
1362
struct iptables_rule_match *matches,