static const struct xt_icmp_names { const char *name; uint8_t type; uint8_t code_min, code_max; } icmp_codes[] = { { "any", 0xFF, 0, 0xFF }, { "echo-reply", 0, 0, 0xFF }, /* Alias */ { "pong", 0, 0, 0xFF }, { "destination-unreachable", 3, 0, 0xFF }, { "network-unreachable", 3, 0, 0 }, { "host-unreachable", 3, 1, 1 }, { "protocol-unreachable", 3, 2, 2 }, { "port-unreachable", 3, 3, 3 }, { "fragmentation-needed", 3, 4, 4 }, { "source-route-failed", 3, 5, 5 }, { "network-unknown", 3, 6, 6 }, { "host-unknown", 3, 7, 7 }, { "network-prohibited", 3, 9, 9 }, { "host-prohibited", 3, 10, 10 }, { "TOS-network-unreachable", 3, 11, 11 }, { "TOS-host-unreachable", 3, 12, 12 }, { "communication-prohibited", 3, 13, 13 }, { "host-precedence-violation", 3, 14, 14 }, { "precedence-cutoff", 3, 15, 15 }, { "source-quench", 4, 0, 0xFF }, { "redirect", 5, 0, 0xFF }, { "network-redirect", 5, 0, 0 }, { "host-redirect", 5, 1, 1 }, { "TOS-network-redirect", 5, 2, 2 }, { "TOS-host-redirect", 5, 3, 3 }, { "echo-request", 8, 0, 0xFF }, /* Alias */ { "ping", 8, 0, 0xFF }, { "router-advertisement", 9, 0, 0xFF }, { "router-solicitation", 10, 0, 0xFF }, { "time-exceeded", 11, 0, 0xFF }, /* Alias */ { "ttl-exceeded", 11, 0, 0xFF }, { "ttl-zero-during-transit", 11, 0, 0 }, { "ttl-zero-during-reassembly", 11, 1, 1 }, { "parameter-problem", 12, 0, 0xFF }, { "ip-header-bad", 12, 0, 0 }, { "required-option-missing", 12, 1, 1 }, { "timestamp-request", 13, 0, 0xFF }, { "timestamp-reply", 14, 0, 0xFF }, { "address-mask-request", 17, 0, 0xFF }, { "address-mask-reply", 18, 0, 0xFF } }, icmpv6_codes[] = { { "destination-unreachable", 1, 0, 0xFF }, { "no-route", 1, 0, 0 }, { "communication-prohibited", 1, 1, 1 }, { "beyond-scope", 1, 2, 2 }, { "address-unreachable", 1, 3, 3 }, { "port-unreachable", 1, 4, 4 }, { "failed-policy", 1, 5, 5 }, { "reject-route", 1, 6, 6 }, { "packet-too-big", 2, 0, 0xFF }, { "time-exceeded", 3, 0, 0xFF }, /* Alias */ { "ttl-exceeded", 3, 0, 0xFF }, { "ttl-zero-during-transit", 3, 0, 0 }, { "ttl-zero-during-reassembly", 3, 1, 1 }, { "parameter-problem", 4, 0, 0xFF }, { "bad-header", 4, 0, 0 }, { "unknown-header-type", 4, 1, 1 }, { "unknown-option", 4, 2, 2 }, { "echo-request", 128, 0, 0xFF }, /* Alias */ { "ping", 128, 0, 0xFF }, { "echo-reply", 129, 0, 0xFF }, /* Alias */ { "pong", 129, 0, 0xFF }, { "mld-listener-query", 130, 0, 0xFF }, { "mld-listener-report", 131, 0, 0xFF }, { "mld-listener-done", 132, 0, 0xFF }, /* Alias */ { "mld-listener-reduction", 132, 0, 0xFF }, { "router-solicitation", 133, 0, 0xFF }, { "router-advertisement", 134, 0, 0xFF }, { "neighbour-solicitation", 135, 0, 0xFF }, /* Alias */ { "neighbor-solicitation", 135, 0, 0xFF }, { "neighbour-advertisement", 136, 0, 0xFF }, /* Alias */ { "neighbor-advertisement", 136, 0, 0xFF }, { "redirect", 137, 0, 0xFF }, }, igmp_types[] = { { "membership-query", 0x11 }, { "membership-report-v1", 0x12 }, { "membership-report-v2", 0x16 }, { "leave-group", 0x17 }, { "membership-report-v3", 0x22 }, }; static inline char *parse_range(const char *str, unsigned int res[]) { char *next; if (!xtables_strtoui(str, &next, &res[0], 0, 255)) return NULL; res[1] = res[0]; if (*next == ':') { str = next + 1; if (!xtables_strtoui(str, &next, &res[1], 0, 255)) return NULL; } return next; } static void __parse_icmp(const struct xt_icmp_names codes[], size_t n_codes, const char *codes_name, const char *fmtstring, uint8_t type[], uint8_t code[]) { unsigned int match = n_codes; unsigned int i, number[2]; for (i = 0; i < n_codes; i++) { if (strncasecmp(codes[i].name, fmtstring, strlen(fmtstring))) continue; if (match != n_codes) xtables_error(PARAMETER_PROBLEM, "Ambiguous %s type `%s': `%s' or `%s'?", codes_name, fmtstring, codes[match].name, codes[i].name); match = i; } if (match < n_codes) { type[0] = type[1] = codes[match].type; if (code) { code[0] = codes[match].code_min; code[1] = codes[match].code_max; } } else { char *next = parse_range(fmtstring, number); if (!next) xtables_error(PARAMETER_PROBLEM, "Unknown %s type `%s'", codes_name, fmtstring); type[0] = (uint8_t) number[0]; type[1] = (uint8_t) number[1]; switch (*next) { case 0: if (code) { code[0] = 0; code[1] = 255; } return; case '/': if (!code) break; next = parse_range(next + 1, number); if (!next) xtables_error(PARAMETER_PROBLEM, "Unknown %s code `%s'", codes_name, fmtstring); code[0] = (uint8_t) number[0]; code[1] = (uint8_t) number[1]; if (!*next) break; /* fallthrough */ default: xtables_error(PARAMETER_PROBLEM, "unknown character %c", *next); } } } static inline void __ipt_parse_icmp(const struct xt_icmp_names *codes, size_t n_codes, const char *codes_name, const char *fmtstr, uint8_t *type, uint8_t code[]) { uint8_t types[2]; __parse_icmp(codes, n_codes, codes_name, fmtstr, types, code); if (types[1] != types[0]) xtables_error(PARAMETER_PROBLEM, "%s type range not supported", codes_name); *type = types[0]; } static inline void ipt_parse_icmp(const char *str, uint8_t *type, uint8_t code[]) { __ipt_parse_icmp(icmp_codes, ARRAY_SIZE(icmp_codes), "ICMP", str, type, code); } static inline void ipt_parse_icmpv6(const char *str, uint8_t *type, uint8_t code[]) { __ipt_parse_icmp(icmpv6_codes, ARRAY_SIZE(icmpv6_codes), "ICMPv6", str, type, code); } static inline void ebt_parse_icmp(const char *str, uint8_t type[], uint8_t code[]) { __parse_icmp(icmp_codes, ARRAY_SIZE(icmp_codes), "ICMP", str, type, code); } static inline void ebt_parse_icmpv6(const char *str, uint8_t type[], uint8_t code[]) { __parse_icmp(icmpv6_codes, ARRAY_SIZE(icmpv6_codes), "ICMPv6", str, type, code); } static inline void ebt_parse_igmp(const char *str, uint8_t type[]) { __parse_icmp(igmp_types, ARRAY_SIZE(igmp_types), "IGMP", str, type, NULL); } static void xt_print_icmp_types(const struct xt_icmp_names *_icmp_codes, unsigned int n_codes) { unsigned int i; for (i = 0; i < n_codes; ++i) { if (i && _icmp_codes[i].type == _icmp_codes[i-1].type) { if (_icmp_codes[i].code_min == _icmp_codes[i-1].code_min && (_icmp_codes[i].code_max == _icmp_codes[i-1].code_max)) printf(" (%s)", _icmp_codes[i].name); else printf("\n %s", _icmp_codes[i].name); } else printf("\n%s", _icmp_codes[i].name); } printf("\n"); }