You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
249 lines
5.6 KiB
249 lines
5.6 KiB
/* Shared library add-on to ip6tables to add mobility header support. */ |
|
/* |
|
* Copyright (C)2006 USAGI/WIDE Project |
|
* |
|
* This program is free software; you can redistribute it and/or modify |
|
* it under the terms of the GNU General Public License version 2 as |
|
* published by the Free Software Foundation. |
|
* |
|
* Author: |
|
* Masahide NAKAMURA @USAGI <masahide.nakamura.cz@hitachi.com> |
|
* |
|
* Based on libip6t_{icmpv6,udp}.c |
|
*/ |
|
#include <stdint.h> |
|
#include <stdio.h> |
|
#include <string.h> |
|
#include <stdlib.h> |
|
#include <xtables.h> |
|
#include <linux/netfilter_ipv6/ip6t_mh.h> |
|
|
|
enum { |
|
O_MH_TYPE = 0, |
|
}; |
|
|
|
struct mh_name { |
|
const char *name; |
|
uint8_t type; |
|
}; |
|
|
|
static const struct mh_name mh_names[] = { |
|
{ "binding-refresh-request", 0, }, |
|
/* Alias */ { "brr", 0, }, |
|
{ "home-test-init", 1, }, |
|
/* Alias */ { "hoti", 1, }, |
|
{ "careof-test-init", 2, }, |
|
/* Alias */ { "coti", 2, }, |
|
{ "home-test", 3, }, |
|
/* Alias */ { "hot", 3, }, |
|
{ "careof-test", 4, }, |
|
/* Alias */ { "cot", 4, }, |
|
{ "binding-update", 5, }, |
|
/* Alias */ { "bu", 5, }, |
|
{ "binding-acknowledgement", 6, }, |
|
/* Alias */ { "ba", 6, }, |
|
{ "binding-error", 7, }, |
|
/* Alias */ { "be", 7, }, |
|
}; |
|
|
|
static void print_types_all(void) |
|
{ |
|
unsigned int i; |
|
printf("Valid MH types:"); |
|
|
|
for (i = 0; i < ARRAY_SIZE(mh_names); ++i) { |
|
if (i && mh_names[i].type == mh_names[i-1].type) |
|
printf(" (%s)", mh_names[i].name); |
|
else |
|
printf("\n%s", mh_names[i].name); |
|
} |
|
printf("\n"); |
|
} |
|
|
|
static void mh_help(void) |
|
{ |
|
printf( |
|
"mh match options:\n" |
|
"[!] --mh-type type[:type] match mh type\n"); |
|
print_types_all(); |
|
} |
|
|
|
static void mh_init(struct xt_entry_match *m) |
|
{ |
|
struct ip6t_mh *mhinfo = (struct ip6t_mh *)m->data; |
|
|
|
mhinfo->types[1] = 0xFF; |
|
} |
|
|
|
static unsigned int name_to_type(const char *name) |
|
{ |
|
int namelen = strlen(name); |
|
static const unsigned int limit = ARRAY_SIZE(mh_names); |
|
unsigned int match = limit; |
|
unsigned int i; |
|
|
|
for (i = 0; i < limit; i++) { |
|
if (strncasecmp(mh_names[i].name, name, namelen) == 0) { |
|
int len = strlen(mh_names[i].name); |
|
if (match == limit || len == namelen) |
|
match = i; |
|
} |
|
} |
|
|
|
if (match != limit) { |
|
return mh_names[match].type; |
|
} else { |
|
unsigned int number; |
|
|
|
if (!xtables_strtoui(name, NULL, &number, 0, UINT8_MAX)) |
|
xtables_error(PARAMETER_PROBLEM, |
|
"Invalid MH type `%s'\n", name); |
|
return number; |
|
} |
|
} |
|
|
|
static void parse_mh_types(const char *mhtype, uint8_t *types) |
|
{ |
|
char *buffer; |
|
char *cp; |
|
|
|
buffer = strdup(mhtype); |
|
if ((cp = strchr(buffer, ':')) == NULL) |
|
types[0] = types[1] = name_to_type(buffer); |
|
else { |
|
*cp = '\0'; |
|
cp++; |
|
|
|
types[0] = buffer[0] ? name_to_type(buffer) : 0; |
|
types[1] = cp[0] ? name_to_type(cp) : 0xFF; |
|
|
|
if (types[0] > types[1]) |
|
xtables_error(PARAMETER_PROBLEM, |
|
"Invalid MH type range (min > max)"); |
|
} |
|
free(buffer); |
|
} |
|
|
|
static void mh_parse(struct xt_option_call *cb) |
|
{ |
|
struct ip6t_mh *mhinfo = cb->data; |
|
|
|
xtables_option_parse(cb); |
|
parse_mh_types(cb->arg, mhinfo->types); |
|
if (cb->invert) |
|
mhinfo->invflags |= IP6T_MH_INV_TYPE; |
|
} |
|
|
|
static const char *type_to_name(uint8_t type) |
|
{ |
|
unsigned int i; |
|
|
|
for (i = 0; i < ARRAY_SIZE(mh_names); ++i) |
|
if (mh_names[i].type == type) |
|
return mh_names[i].name; |
|
|
|
return NULL; |
|
} |
|
|
|
static void print_type(uint8_t type, int numeric) |
|
{ |
|
const char *name; |
|
if (numeric || !(name = type_to_name(type))) |
|
printf("%u", type); |
|
else |
|
printf("%s", name); |
|
} |
|
|
|
static void print_types(uint8_t min, uint8_t max, int invert, int numeric) |
|
{ |
|
const char *inv = invert ? "!" : ""; |
|
|
|
if (min != 0 || max != 0xFF || invert) { |
|
printf(" "); |
|
if (min == max) { |
|
printf("%s", inv); |
|
print_type(min, numeric); |
|
} else { |
|
printf("%s", inv); |
|
print_type(min, numeric); |
|
printf(":"); |
|
print_type(max, numeric); |
|
} |
|
} |
|
} |
|
|
|
static void mh_print(const void *ip, const struct xt_entry_match *match, |
|
int numeric) |
|
{ |
|
const struct ip6t_mh *mhinfo = (struct ip6t_mh *)match->data; |
|
|
|
printf(" mh"); |
|
print_types(mhinfo->types[0], mhinfo->types[1], |
|
mhinfo->invflags & IP6T_MH_INV_TYPE, |
|
numeric); |
|
if (mhinfo->invflags & ~IP6T_MH_INV_MASK) |
|
printf(" Unknown invflags: 0x%X", |
|
mhinfo->invflags & ~IP6T_MH_INV_MASK); |
|
} |
|
|
|
static void mh_save(const void *ip, const struct xt_entry_match *match) |
|
{ |
|
const struct ip6t_mh *mhinfo = (struct ip6t_mh *)match->data; |
|
|
|
if (mhinfo->types[0] == 0 && mhinfo->types[1] == 0xFF) |
|
return; |
|
|
|
if (mhinfo->invflags & IP6T_MH_INV_TYPE) |
|
printf(" !"); |
|
|
|
if (mhinfo->types[0] != mhinfo->types[1]) |
|
printf(" --mh-type %u:%u", mhinfo->types[0], mhinfo->types[1]); |
|
else |
|
printf(" --mh-type %u", mhinfo->types[0]); |
|
} |
|
|
|
static int mh_xlate(struct xt_xlate *xl, |
|
const struct xt_xlate_mt_params *params) |
|
{ |
|
const struct ip6t_mh *mhinfo = (struct ip6t_mh *)params->match->data; |
|
|
|
if (mhinfo->types[0] == 0 && mhinfo->types[1] == 0xff) |
|
return 1; |
|
|
|
if (mhinfo->types[0] != mhinfo->types[1]) |
|
xt_xlate_add(xl, "mh type %s%u-%u", |
|
mhinfo->invflags & IP6T_MH_INV_TYPE ? "!= " : "", |
|
mhinfo->types[0], mhinfo->types[1]); |
|
else |
|
xt_xlate_add(xl, "mh type %s%u", |
|
mhinfo->invflags & IP6T_MH_INV_TYPE ? "!= " : "", |
|
mhinfo->types[0]); |
|
|
|
return 1; |
|
} |
|
|
|
static const struct xt_option_entry mh_opts[] = { |
|
{.name = "mh-type", .id = O_MH_TYPE, .type = XTTYPE_STRING, |
|
.flags = XTOPT_INVERT}, |
|
XTOPT_TABLEEND, |
|
}; |
|
|
|
static struct xtables_match mh_mt6_reg = { |
|
.name = "mh", |
|
.version = XTABLES_VERSION, |
|
.family = NFPROTO_IPV6, |
|
.size = XT_ALIGN(sizeof(struct ip6t_mh)), |
|
.userspacesize = XT_ALIGN(sizeof(struct ip6t_mh)), |
|
.help = mh_help, |
|
.init = mh_init, |
|
.x6_parse = mh_parse, |
|
.print = mh_print, |
|
.save = mh_save, |
|
.x6_options = mh_opts, |
|
.xlate = mh_xlate, |
|
}; |
|
|
|
void _init(void) |
|
{ |
|
xtables_register_match(&mh_mt6_reg); |
|
}
|
|
|