123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- /* ipv6header match - matches IPv6 packets based
- on whether they contain certain headers */
- /* Original idea: Brad Chapman
- * Rewritten by: Andras Kis-Szabo <kisza@sch.bme.hu> */
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <netdb.h>
- #include <xtables.h>
- #include <linux/netfilter_ipv6/ip6t_ipv6header.h>
- enum {
- O_HEADER = 0,
- O_SOFT,
- };
- /* A few hardcoded protocols for 'all' and in case the user has no
- * /etc/protocols */
- struct pprot {
- char *name;
- uint8_t num;
- };
- struct numflag {
- uint8_t proto;
- uint8_t flag;
- };
- static const struct pprot chain_protos[] = {
- { "hop-by-hop", IPPROTO_HOPOPTS },
- { "protocol", IPPROTO_RAW },
- { "hop", IPPROTO_HOPOPTS },
- { "dst", IPPROTO_DSTOPTS },
- { "route", IPPROTO_ROUTING },
- { "frag", IPPROTO_FRAGMENT },
- { "auth", IPPROTO_AH },
- { "esp", IPPROTO_ESP },
- { "none", IPPROTO_NONE },
- { "prot", IPPROTO_RAW },
- { "0", IPPROTO_HOPOPTS },
- { "60", IPPROTO_DSTOPTS },
- { "43", IPPROTO_ROUTING },
- { "44", IPPROTO_FRAGMENT },
- { "51", IPPROTO_AH },
- { "50", IPPROTO_ESP },
- { "59", IPPROTO_NONE },
- { "255", IPPROTO_RAW },
- /* { "all", 0 }, */
- };
- static const struct numflag chain_flags[] = {
- { IPPROTO_HOPOPTS, MASK_HOPOPTS },
- { IPPROTO_DSTOPTS, MASK_DSTOPTS },
- { IPPROTO_ROUTING, MASK_ROUTING },
- { IPPROTO_FRAGMENT, MASK_FRAGMENT },
- { IPPROTO_AH, MASK_AH },
- { IPPROTO_ESP, MASK_ESP },
- { IPPROTO_NONE, MASK_NONE },
- { IPPROTO_RAW, MASK_PROTO },
- };
- static const char *
- proto_to_name(uint8_t proto, int nolookup)
- {
- unsigned int i;
- if (proto && !nolookup) {
- const struct protoent *pent = getprotobynumber(proto);
- if (pent)
- return pent->p_name;
- }
- for (i = 0; i < ARRAY_SIZE(chain_protos); ++i)
- if (chain_protos[i].num == proto)
- return chain_protos[i].name;
- return NULL;
- }
- static uint16_t
- name_to_proto(const char *s)
- {
- unsigned int proto=0;
- const struct protoent *pent;
- if ((pent = getprotobyname(s)))
- proto = pent->p_proto;
- else {
- unsigned int i;
- for (i = 0; i < ARRAY_SIZE(chain_protos); ++i)
- if (strcmp(s, chain_protos[i].name) == 0) {
- proto = chain_protos[i].num;
- break;
- }
- if (i == ARRAY_SIZE(chain_protos))
- xtables_error(PARAMETER_PROBLEM,
- "unknown header `%s' specified",
- s);
- }
- return proto;
- }
- static unsigned int
- add_proto_to_mask(int proto){
- unsigned int i=0, flag=0;
- for (i = 0; i < ARRAY_SIZE(chain_flags); ++i)
- if (proto == chain_flags[i].proto){
- flag = chain_flags[i].flag;
- break;
- }
- if (i == ARRAY_SIZE(chain_flags))
- xtables_error(PARAMETER_PROBLEM,
- "unknown header `%d' specified",
- proto);
-
- return flag;
- }
- static void ipv6header_help(void)
- {
- printf(
- "ipv6header match options:\n"
- "[!] --header headers Type of header to match, by name\n"
- " names: hop,dst,route,frag,auth,esp,none,proto\n"
- " long names: hop-by-hop,ipv6-opts,ipv6-route,\n"
- " ipv6-frag,ah,esp,ipv6-nonxt,protocol\n"
- " numbers: 0,60,43,44,51,50,59\n"
- "--soft The header CONTAINS the specified extensions\n");
- }
- static const struct xt_option_entry ipv6header_opts[] = {
- {.name = "header", .id = O_HEADER, .type = XTTYPE_STRING,
- .flags = XTOPT_MAND | XTOPT_INVERT},
- {.name = "soft", .id = O_SOFT, .type = XTTYPE_NONE},
- XTOPT_TABLEEND,
- };
- static unsigned int
- parse_header(const char *flags) {
- unsigned int ret = 0;
- char *ptr;
- char *buffer;
- buffer = strdup(flags);
- for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ","))
- ret |= add_proto_to_mask(name_to_proto(ptr));
-
- free(buffer);
- return ret;
- }
- static void ipv6header_parse(struct xt_option_call *cb)
- {
- struct ip6t_ipv6header_info *info = cb->data;
- xtables_option_parse(cb);
- switch (cb->entry->id) {
- case O_HEADER:
- if (!(info->matchflags = parse_header(cb->arg)))
- xtables_error(PARAMETER_PROBLEM, "ip6t_ipv6header: cannot parse header names");
- if (cb->invert)
- info->invflags |= 0xFF;
- break;
- case O_SOFT:
- info->modeflag |= 0xFF;
- break;
- }
- }
- static void
- print_header(uint8_t flags){
- int have_flag = 0;
- while (flags) {
- unsigned int i;
- for (i = 0; (flags & chain_flags[i].flag) == 0; i++);
- if (have_flag)
- printf(",");
- printf("%s", proto_to_name(chain_flags[i].proto,0));
- have_flag = 1;
- flags &= ~chain_flags[i].flag;
- }
- if (!have_flag)
- printf("NONE");
- }
- static void ipv6header_print(const void *ip,
- const struct xt_entry_match *match, int numeric)
- {
- const struct ip6t_ipv6header_info *info = (const struct ip6t_ipv6header_info *)match->data;
- printf(" ipv6header");
- if (info->matchflags || info->invflags) {
- printf(" flags:%s", info->invflags ? "!" : "");
- if (numeric)
- printf("0x%02X", info->matchflags);
- else {
- print_header(info->matchflags);
- }
- }
- if (info->modeflag)
- printf(" soft");
- }
- static void ipv6header_save(const void *ip, const struct xt_entry_match *match)
- {
- const struct ip6t_ipv6header_info *info = (const struct ip6t_ipv6header_info *)match->data;
- printf("%s --header ", info->invflags ? " !" : "");
- print_header(info->matchflags);
- if (info->modeflag)
- printf(" --soft");
- }
- static struct xtables_match ipv6header_mt6_reg = {
- .name = "ipv6header",
- .version = XTABLES_VERSION,
- .family = NFPROTO_IPV6,
- .size = XT_ALIGN(sizeof(struct ip6t_ipv6header_info)),
- .userspacesize = XT_ALIGN(sizeof(struct ip6t_ipv6header_info)),
- .help = ipv6header_help,
- .print = ipv6header_print,
- .save = ipv6header_save,
- .x6_parse = ipv6header_parse,
- .x6_options = ipv6header_opts,
- };
- void _init(void)
- {
- xtables_register_match(&ipv6header_mt6_reg);
- }
|