parent
3224643614
commit
bb932910dd
@ -0,0 +1,44 @@ |
||||
#
|
||||
# Copyright (C) 2014 OpenWrt.org
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk |
||||
|
||||
PKG_NAME:=map
|
||||
PKG_VERSION:=1
|
||||
PKG_RELEASE:=1
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk |
||||
include $(INCLUDE_DIR)/cmake.mk |
||||
|
||||
define Package/map |
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
DEPENDS:=+kmod-ipv6 +kmod-ip6-tunnel +libubox +libubus +iptables-mod-conntrack-extra
|
||||
TITLE:=MAP-E and Lightweight 4over6 configuration support
|
||||
MAINTAINER:=Steven Barth <steven@midlink.org>
|
||||
endef |
||||
|
||||
define Package/map/description |
||||
Provides support for MAP-E (draft-ietf-softwire-map) and
|
||||
Lightweight 4over6 (draft-ietf-softwire-lw4over6) in /etc/config/network.
|
||||
Refer to http://wiki.openwrt.org/doc/uci/network for
|
||||
configuration details.
|
||||
endef |
||||
|
||||
define Build/Prepare |
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
$(CP) ./src/* $(PKG_BUILD_DIR)/
|
||||
endef |
||||
|
||||
define Package/map/install |
||||
$(INSTALL_DIR) $(1)/lib/netifd/proto
|
||||
$(INSTALL_BIN) ./files/map.sh $(1)/lib/netifd/proto/map.sh
|
||||
$(INSTALL_DIR) $(1)/usr/sbin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/mapcalc $(1)/usr/sbin/
|
||||
endef |
||||
|
||||
$(eval $(call BuildPackage,map)) |
@ -0,0 +1,160 @@ |
||||
#!/bin/sh |
||||
# map.sh - IPv4-in-IPv6 tunnel backend |
||||
# |
||||
# Author: Steven Barth <cyrus@openwrt.org> |
||||
# Copyright (c) 2014 cisco Systems, Inc. |
||||
# |
||||
# 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 |
||||
# |
||||
# This program is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
|
||||
[ -n "$INCLUDE_ONLY" ] || { |
||||
. /lib/functions.sh |
||||
. /lib/functions/network.sh |
||||
. ../netifd-proto.sh |
||||
init_proto "$@" |
||||
} |
||||
|
||||
proto_map_setup() { |
||||
local cfg="$1" |
||||
local iface="$2" |
||||
local link="map-$cfg" |
||||
|
||||
# uncomment for legacy MAP0 mode |
||||
#export LEGACY=1 |
||||
|
||||
local type mtu ttl tunlink zone |
||||
local rule ipaddr ip4prefixlen ip6prefix ip6prefixlen peeraddr ealen psidlen psid offset |
||||
json_get_vars type mtu ttl tunlink zone |
||||
json_get_vars rule ipaddr ip4prefixlen ip6prefix ip6prefixlen peeraddr ealen psidlen psid offset |
||||
|
||||
[ -z "$zone" ] && zone="wan" |
||||
[ -z "$type" ] && type="map-e" |
||||
[ -z "$ip4prefixlen" ] && ip4prefixlen=32 |
||||
|
||||
( proto_add_host_dependency "$cfg" "::" "$tunlink" ) |
||||
|
||||
if [ -z "$rule" ]; then |
||||
rule="type=$type,ipv6prefix=$ip6prefix,prefix6len=$ip6prefixlen,ipv4prefix=$ipaddr,prefix4len=$ip4prefixlen" |
||||
[ -n "$psid" ] && rule="$rule,psid=$psid" |
||||
[ -n "$psidlen" ] && rule="$rule,psidlen=$psidlen" |
||||
[ -n "$offset" ] && rule="$rule,offset=$offset" |
||||
[ -n "$ealen" ] && rule="$rule,ealen=$ealen" |
||||
rule="$rule,br=$peeraddr" |
||||
fi |
||||
|
||||
RULE_DATA=$(mapcalc ${tunlink:-\*} $rule) |
||||
if [ "$?" != 0 ]; then |
||||
proto_notify_error "$cfg" "INVALID_MAP_RULE" |
||||
proto_block_restart "$cfg" |
||||
return |
||||
fi |
||||
|
||||
eval $RULE_DATA |
||||
|
||||
if [ -z "$RULE_BMR" ]; then |
||||
proto_notify_error "$cfg" "NO_MATCHING_PD" |
||||
proto_block_restart "$cfg" |
||||
return |
||||
fi |
||||
|
||||
k=$RULE_BMR |
||||
if [ "$type" = "lw4o6" -o "$type" = "map-e" ]; then |
||||
proto_init_update "$link" 1 |
||||
proto_add_ipv4_address $(eval "echo \$RULE_${k}_IPV4ADDR") "" "" "" |
||||
|
||||
proto_add_tunnel |
||||
json_add_string mode ipip6 |
||||
json_add_int mtu "${mtu:-1280}" |
||||
json_add_int ttl "${ttl:-64}" |
||||
json_add_string local $(eval "echo \$RULE_${k}_IPV6ADDR") |
||||
json_add_string remote $(eval "echo \$RULE_${k}_BR") |
||||
json_add_string link $(eval "echo \$RULE_${k}_PD6IFACE") |
||||
|
||||
if [ "$type" = "map-e" ]; then |
||||
json_add_array "fmrs" |
||||
for i in $(seq $RULE_COUNT); do |
||||
[ "$(eval "echo \$RULE_${i}_FMR")" != 1 ] && continue |
||||
fmr="$(eval "echo \$RULE_${i}_IPV6PREFIX")/$(eval "echo \$RULE_${i}_PREFIX6LEN")" |
||||
fmr="$fmr,$(eval "echo \$RULE_${i}_IPV4PREFIX")/$(eval "echo \$RULE_${i}_PREFIX4LEN")" |
||||
fmr="$fmr,$(eval "echo \$RULE_${i}_EALEN"),$(eval "echo \$RULE_${i}_OFFSET")" |
||||
json_add_string "" "$fmr" |
||||
done |
||||
json_close_array |
||||
fi |
||||
|
||||
proto_close_tunnel |
||||
else |
||||
proto_notify_error "$cfg" "UNSUPPORTED_TYPE" |
||||
proto_block_restart "$cfg" |
||||
fi |
||||
|
||||
proto_add_ipv4_route "0.0.0.0" 0 |
||||
proto_add_data |
||||
[ "$zone" != "-" ] && json_add_string zone "$zone" |
||||
|
||||
json_add_array firewall |
||||
for portset in $(eval "echo \$RULE_${k}_PORTSETS"); do |
||||
for proto in icmp tcp udp; do |
||||
json_add_object "" |
||||
json_add_string type nat |
||||
json_add_string target SNAT |
||||
json_add_string family inet |
||||
json_add_string proto "$proto" |
||||
json_add_boolean connlimit_ports 1 |
||||
json_add_string snat_ip $(eval "echo \$RULE_${k}_IPV4ADDR") |
||||
json_add_string snat_port "$portset" |
||||
json_close_object |
||||
done |
||||
done |
||||
json_close_array |
||||
proto_close_data |
||||
|
||||
proto_send_update "$cfg" |
||||
|
||||
if [ "$type" = "lw4o6" -o "$type" = "map-e" ]; then |
||||
json_init |
||||
json_add_string name "${cfg}_local" |
||||
json_add_string ifname "@$(eval "echo \$RULE_${k}_PD6IFACE")" |
||||
json_add_string proto "static" |
||||
json_add_array ip6addr |
||||
json_add_string "" "$(eval "echo \$RULE_${k}_IPV6ADDR")" |
||||
json_close_array |
||||
json_close_object |
||||
ubus call network add_dynamic "$(json_dump)" |
||||
fi |
||||
} |
||||
|
||||
proto_map_teardown() { |
||||
local cfg="$1" |
||||
ifdown "${cfg}_local" |
||||
} |
||||
|
||||
proto_map_init_config() { |
||||
no_device=1 |
||||
available=1 |
||||
|
||||
proto_config_add_string "rule" |
||||
proto_config_add_string "ipaddr" |
||||
proto_config_add_int "ip4prefixlen" |
||||
proto_config_add_string "ip6prefix" |
||||
proto_config_add_int "ip6prefixlen" |
||||
proto_config_add_string "peeraddr" |
||||
proto_config_add_int "psidlen" |
||||
proto_config_add_int "psid" |
||||
proto_config_add_int "offset" |
||||
|
||||
proto_config_add_string "tunlink" |
||||
proto_config_add_int "mtu" |
||||
proto_config_add_int "ttl" |
||||
proto_config_add_string "zone" |
||||
} |
||||
|
||||
[ -n "$INCLUDE_ONLY" ] || { |
||||
add_protocol map |
||||
} |
@ -0,0 +1,26 @@ |
||||
cmake_minimum_required(VERSION 2.8.1) |
||||
|
||||
project(mapcalc C) |
||||
|
||||
set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") |
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -std=c99") |
||||
|
||||
add_definitions(-D_GNU_SOURCE -Wall -Wno-gnu -Wextra) |
||||
|
||||
add_executable(mapcalc mapcalc.c) |
||||
target_link_libraries(mapcalc ubus ubox) |
||||
|
||||
install(TARGETS mapcalc DESTINATION sbin/) |
||||
|
||||
|
||||
# Packaging rules |
||||
set(CPACK_PACKAGE_VERSION "1") |
||||
set(CPACK_PACKAGE_CONTACT "Steven Barth <steven@midlink.org>") |
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "hnetd") |
||||
set(CPACK_GENERATOR "DEB;RPM;STGZ") |
||||
set(CPACK_STRIP_FILES true) |
||||
|
||||
SET(CPACK_DEBIAN_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION}) |
||||
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}_${CPACK_DEBIAN_PACKAGE_VERSION}") |
||||
|
||||
include(CPack) |
@ -0,0 +1,367 @@ |
||||
/*
|
||||
* mapcalc - MAP parameter calculation |
||||
* |
||||
* Author: Steven Barth <cyrus@openwrt.org> |
||||
* Copyright (c) 2014 cisco Systems, Inc. |
||||
* |
||||
* 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 |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
*/ |
||||
|
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
#include <arpa/inet.h> |
||||
#include <errno.h> |
||||
#include <libubus.h> |
||||
#include <libubox/utils.h> |
||||
|
||||
|
||||
struct blob_attr *dump = NULL; |
||||
|
||||
enum { |
||||
DUMP_ATTR_INTERFACE, |
||||
DUMP_ATTR_MAX |
||||
}; |
||||
|
||||
static const struct blobmsg_policy dump_attrs[DUMP_ATTR_MAX] = { |
||||
[DUMP_ATTR_INTERFACE] = { .name = "interface", .type = BLOBMSG_TYPE_ARRAY }, |
||||
}; |
||||
|
||||
|
||||
enum { |
||||
IFACE_ATTR_INTERFACE, |
||||
IFACE_ATTR_PREFIX, |
||||
IFACE_ATTR_MAX, |
||||
}; |
||||
|
||||
static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = { |
||||
[IFACE_ATTR_INTERFACE] = { .name = "interface", .type = BLOBMSG_TYPE_STRING }, |
||||
[IFACE_ATTR_PREFIX] = { .name = "ipv6-prefix", .type = BLOBMSG_TYPE_ARRAY }, |
||||
}; |
||||
|
||||
|
||||
enum { |
||||
PREFIX_ATTR_ADDRESS, |
||||
PREFIX_ATTR_MASK, |
||||
PREFIX_ATTR_MAX, |
||||
}; |
||||
|
||||
static const struct blobmsg_policy prefix_attrs[PREFIX_ATTR_MAX] = { |
||||
[PREFIX_ATTR_ADDRESS] = { .name = "address", .type = BLOBMSG_TYPE_STRING }, |
||||
[PREFIX_ATTR_MASK] = { .name = "mask", .type = BLOBMSG_TYPE_INT32 }, |
||||
}; |
||||
|
||||
static int bmemcmp(const void *av, const void *bv, size_t bits) |
||||
{ |
||||
const uint8_t *a = av, *b = bv; |
||||
size_t bytes = bits / 8; |
||||
bits %= 8; |
||||
|
||||
int res = memcmp(a, b, bytes); |
||||
if (res == 0 && bits > 0) |
||||
res = (a[bytes] >> (8 - bits)) - (b[bytes] >> (8 - bits)); |
||||
|
||||
return res; |
||||
} |
||||
|
||||
static void bmemcpy(void *av, const void *bv, size_t bits) |
||||
{ |
||||
uint8_t *a = av; |
||||
const uint8_t *b = bv; |
||||
|
||||
size_t bytes = bits / 8; |
||||
bits %= 8; |
||||
memcpy(a, b, bytes); |
||||
|
||||
if (bits > 0) { |
||||
uint8_t mask = (1 << (8 - bits)) - 1; |
||||
a[bytes] = (a[bytes] & mask) | ((~mask) & b[bytes]); |
||||
} |
||||
} |
||||
|
||||
static void bmemcpys64(void *av, const void *bv, size_t frombits, size_t nbits) |
||||
{ |
||||
uint64_t buf = 0; |
||||
const uint8_t *b = bv; |
||||
size_t frombyte = frombits / 8, tobyte = (frombits + nbits) / 8; |
||||
|
||||
memcpy(&buf, &b[frombyte], tobyte - frombyte + 1); |
||||
buf = cpu_to_be64(be64_to_cpu(buf) << (frombits % 8)); |
||||
|
||||
bmemcpy(av, &buf, nbits); |
||||
} |
||||
|
||||
static void handle_dump(struct ubus_request *req __attribute__((unused)), |
||||
int type __attribute__((unused)), struct blob_attr *msg) |
||||
{ |
||||
struct blob_attr *tb[DUMP_ATTR_INTERFACE]; |
||||
blobmsg_parse(dump_attrs, DUMP_ATTR_MAX, tb, blob_data(msg), blob_len(msg)); |
||||
|
||||
if (!tb[DUMP_ATTR_INTERFACE]) |
||||
return; |
||||
|
||||
dump = blob_memdup(tb[DUMP_ATTR_INTERFACE]); |
||||
} |
||||
|
||||
enum { |
||||
OPT_TYPE, |
||||
OPT_FMR, |
||||
OPT_EALEN, |
||||
OPT_PREFIX4LEN, |
||||
OPT_PREFIX6LEN, |
||||
OPT_IPV6PREFIX, |
||||
OPT_IPV4PREFIX, |
||||
OPT_OFFSET, |
||||
OPT_PSIDLEN, |
||||
OPT_PSID, |
||||
OPT_BR, |
||||
OPT_DMR, |
||||
OPT_MAX |
||||
}; |
||||
|
||||
static char *const token[] = { |
||||
[OPT_TYPE] = "type", |
||||
[OPT_FMR] = "fmr", |
||||
[OPT_EALEN] = "ealen", |
||||
[OPT_PREFIX4LEN] = "prefix4len", |
||||
[OPT_PREFIX6LEN] = "prefix6len", |
||||
[OPT_IPV6PREFIX] = "ipv6prefix", |
||||
[OPT_IPV4PREFIX] = "ipv4prefix", |
||||
[OPT_OFFSET] = "offset", |
||||
[OPT_PSIDLEN] = "psidlen", |
||||
[OPT_PSID] = "psid", |
||||
[OPT_BR] = "br", |
||||
[OPT_DMR] = "dmr", |
||||
[OPT_MAX] = NULL |
||||
}; |
||||
|
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
int status = 0; |
||||
const char *iface = argv[1]; |
||||
|
||||
const char *legacy_env = getenv("LEGACY"); |
||||
bool legacy = legacy_env && atoi(legacy_env); |
||||
|
||||
|
||||
if (argc < 3) { |
||||
fprintf(stderr, "Usage: %s <interface|*> <rule1> [rule2] [...]\n", argv[0]); |
||||
return 1; |
||||
} |
||||
|
||||
uint32_t network_interface; |
||||
struct ubus_context *ubus = ubus_connect(NULL); |
||||
if (ubus) { |
||||
ubus_lookup_id(ubus, "network.interface", &network_interface); |
||||
ubus_invoke(ubus, network_interface, "dump", NULL, handle_dump, NULL, 5000); |
||||
} |
||||
|
||||
int rulecnt = 0; |
||||
for (int i = 2; i < argc; ++i) { |
||||
bool lw4o6 = false; |
||||
bool fmr = false; |
||||
int ealen = -1; |
||||
int addr4len = 32; |
||||
int prefix4len = 32; |
||||
int prefix6len = -1; |
||||
int pdlen = -1; |
||||
struct in_addr ipv4prefix = {INADDR_ANY}; |
||||
struct in_addr ipv4addr = {INADDR_ANY}; |
||||
struct in6_addr ipv6addr = IN6ADDR_ANY_INIT; |
||||
struct in6_addr ipv6prefix = IN6ADDR_ANY_INIT; |
||||
struct in6_addr pd = IN6ADDR_ANY_INIT; |
||||
int offset = -1; |
||||
int psidlen = -1; |
||||
int psid = -1; |
||||
uint16_t psid16 = 0; |
||||
const char *dmr = NULL; |
||||
const char *br = NULL; |
||||
|
||||
for (char *rule = strdup(argv[i]); *rule; ) { |
||||
char *value; |
||||
int intval; |
||||
int idx = getsubopt(&rule, token, &value); |
||||
errno = 0; |
||||
|
||||
if (idx == OPT_TYPE) { |
||||
lw4o6 = (value && !strcmp(value, "lw4o6")); |
||||
} else if (idx == OPT_FMR) { |
||||
fmr = true; |
||||
} else if (idx == OPT_EALEN && (intval = strtoul(value, NULL, 0)) <= 48 && !errno) { |
||||
ealen = intval; |
||||
} else if (idx == OPT_PREFIX4LEN && (intval = strtoul(value, NULL, 0)) <= 32 && !errno) { |
||||
prefix4len = intval; |
||||
} else if (idx == OPT_PREFIX6LEN && (intval = strtoul(value, NULL, 0)) <= 112 && !errno) { |
||||
prefix6len = intval; |
||||
} else if (idx == OPT_IPV4PREFIX && inet_pton(AF_INET, value, &ipv4prefix) == 1) { |
||||
// dummy
|
||||
} else if (idx == OPT_IPV6PREFIX && inet_pton(AF_INET6, value, &ipv6prefix) == 1) { |
||||
// dummy
|
||||
} else if (idx == OPT_OFFSET && (intval = strtoul(value, NULL, 0)) <= 16 && !errno) { |
||||
offset = intval; |
||||
} else if (idx == OPT_PSIDLEN && (intval = strtoul(value, NULL, 0)) <= 16 && !errno) { |
||||
psidlen = intval; |
||||
} else if (idx == OPT_PSID && (intval = strtoul(value, NULL, 0)) <= 65535 && !errno) { |
||||
psid = intval; |
||||
} else if (idx == OPT_DMR) { |
||||
dmr = value; |
||||
} else if (idx == OPT_BR) { |
||||
br = value; |
||||
} else { |
||||
if (idx == -1 || idx >= OPT_MAX) |
||||
fprintf(stderr, "Skipped invalid option: %s\n", value); |
||||
else |
||||
fprintf(stderr, "Skipped invalid value %s for option %s\n", |
||||
value, token[idx]); |
||||
} |
||||
} |
||||
|
||||
if (offset < 0) |
||||
offset = (lw4o6) ? 0 : (legacy) ? 4 : 6; |
||||
|
||||
// Find PD
|
||||
struct blob_attr *c, *cur; |
||||
unsigned rem; |
||||
blobmsg_for_each_attr(c, dump, rem) { |
||||
struct blob_attr *tb[IFACE_ATTR_MAX]; |
||||
blobmsg_parse(iface_attrs, IFACE_ATTR_MAX, tb, blobmsg_data(c), blobmsg_data_len(c)); |
||||
|
||||
if (!tb[IFACE_ATTR_INTERFACE] || (strcmp(argv[1], "*") && strcmp(argv[1], |
||||
blobmsg_get_string(tb[IFACE_ATTR_INTERFACE])))) |
||||
continue; |
||||
|
||||
if ((cur = tb[IFACE_ATTR_PREFIX])) { |
||||
if (blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY || !blobmsg_check_attr(cur, NULL)) |
||||
continue; |
||||
|
||||
struct blob_attr *d; |
||||
unsigned drem; |
||||
blobmsg_for_each_attr(d, cur, drem) { |
||||
struct blob_attr *ptb[PREFIX_ATTR_MAX]; |
||||
blobmsg_parse(prefix_attrs, PREFIX_ATTR_MAX, ptb, |
||||
blobmsg_data(d), blobmsg_data_len(d)); |
||||
|
||||
if (!ptb[PREFIX_ATTR_ADDRESS] || !ptb[PREFIX_ATTR_MASK]) |
||||
continue; |
||||
|
||||
struct in6_addr prefix = IN6ADDR_ANY_INIT; |
||||
int mask = blobmsg_get_u32(ptb[PREFIX_ATTR_MASK]); |
||||
inet_pton(AF_INET6, blobmsg_get_string(ptb[PREFIX_ATTR_ADDRESS]), &prefix); |
||||
|
||||
if (mask >= prefix6len && !bmemcmp(&prefix, &ipv6prefix, prefix6len)) { |
||||
pd = prefix; |
||||
pdlen = mask; |
||||
iface = blobmsg_get_string(tb[IFACE_ATTR_INTERFACE]); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (pdlen >= 0) |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (ealen < 0 && pdlen >= 0) |
||||
ealen = pdlen - prefix6len; |
||||
|
||||
if (psidlen < 0) |
||||
psidlen = ealen - (32 - prefix4len); |
||||
|
||||
if (psid < 0 && psidlen <= 16 && psidlen >= 0 && pdlen >= 0 && ealen >= psidlen) { |
||||
bmemcpys64(&psid16, &pd, prefix6len + ealen - psidlen, psidlen); |
||||
psid = be16_to_cpu(psid16); |
||||
} |
||||
|
||||
psid16 = cpu_to_be16(psid >> (16 - psidlen)); |
||||
|
||||
if ((pdlen >= 0 || ealen == psidlen) && ealen >= psidlen) { |
||||
bmemcpys64(&ipv4addr, &pd, prefix6len, ealen - psidlen); |
||||
ipv4addr.s_addr = htonl(ntohl(ipv4addr.s_addr) >> prefix4len); |
||||
bmemcpy(&ipv4addr, &ipv4prefix, prefix4len); |
||||
|
||||
if (prefix4len + ealen < 32) |
||||
addr4len = prefix4len + ealen; |
||||
} |
||||
|
||||
if (prefix4len < 0 || prefix6len < 0 || ealen < 0 || ealen < psidlen) { |
||||
fprintf(stderr, "Skipping invalid or incomplete rule: %s\n", argv[i]); |
||||
status = 1; |
||||
continue; |
||||
} |
||||
|
||||
if (pdlen < 0 && !fmr) { |
||||
fprintf(stderr, "Skipping non-FMR without matching PD: %s\n", argv[i]); |
||||
status = 1; |
||||
continue; |
||||
} else if (pdlen >= 0) { |
||||
size_t v4offset = (legacy) ? 9 : 10; |
||||
memcpy(&ipv6addr.s6_addr[v4offset], &ipv4addr, 4); |
||||
memcpy(&ipv6addr.s6_addr[v4offset + 4], &psid16, 2); |
||||
bmemcpy(&ipv6addr, &pd, pdlen); |
||||
} |
||||
|
||||
++rulecnt; |
||||
char ipv4addrbuf[INET_ADDRSTRLEN]; |
||||
char ipv4prefixbuf[INET_ADDRSTRLEN]; |
||||
char ipv6prefixbuf[INET6_ADDRSTRLEN]; |
||||
char ipv6addrbuf[INET6_ADDRSTRLEN]; |
||||
char pdbuf[INET6_ADDRSTRLEN]; |
||||
|
||||
inet_ntop(AF_INET, &ipv4addr, ipv4addrbuf, sizeof(ipv4addrbuf)); |
||||
inet_ntop(AF_INET, &ipv4prefix, ipv4prefixbuf, sizeof(ipv4prefixbuf)); |
||||
inet_ntop(AF_INET6, &ipv6prefix, ipv6prefixbuf, sizeof(ipv6prefixbuf)); |
||||
inet_ntop(AF_INET6, &ipv6addr, ipv6addrbuf, sizeof(ipv6addrbuf)); |
||||
inet_ntop(AF_INET6, &pd, pdbuf, sizeof(pdbuf)); |
||||
|
||||
printf("RULE_%d_FMR=%d\n", rulecnt, fmr); |
||||
printf("RULE_%d_EALEN=%d\n", rulecnt, ealen); |
||||
printf("RULE_%d_PSIDLEN=%d\n", rulecnt, psidlen); |
||||
printf("RULE_%d_OFFSET=%d\n", rulecnt, offset); |
||||
printf("RULE_%d_PREFIX4LEN=%d\n", rulecnt, prefix4len); |
||||
printf("RULE_%d_PREFIX6LEN=%d\n", rulecnt, prefix6len); |
||||
printf("RULE_%d_IPV4PREFIX=%s\n", rulecnt, ipv4prefixbuf); |
||||
printf("RULE_%d_IPV6PREFIX=%s\n", rulecnt, ipv6prefixbuf); |
||||
|
||||
if (pdlen >= 0) { |
||||
printf("RULE_%d_IPV6PD=%s\n", rulecnt, pdbuf); |
||||
printf("RULE_%d_PD6LEN=%d\n", rulecnt, pdlen); |
||||
printf("RULE_%d_PD6IFACE=%s\n", rulecnt, iface); |
||||
printf("RULE_%d_IPV6ADDR=%s\n", rulecnt, ipv6addrbuf); |
||||
printf("RULE_BMR=%d\n", rulecnt); |
||||
} |
||||
|
||||
if (ipv4addr.s_addr) { |
||||
printf("RULE_%d_IPV4ADDR=%s\n", rulecnt, ipv4addrbuf); |
||||
printf("RULE_%d_ADDR4LEN=%d\n", rulecnt, addr4len); |
||||
} |
||||
|
||||
|
||||
if (psidlen == 0) { |
||||
printf("RULE_%d_PORTSETS=0-65535\n", rulecnt); |
||||
} else if (psid >= 0) { |
||||
printf("RULE_%d_PORTSETS='", rulecnt); |
||||
for (int k = (offset) ? 1 : 0; k < (1 << offset); ++k) { |
||||
int start = (k << (16 - offset)) | (psid >> offset); |
||||
int end = start + (1 << (16 - offset - psidlen)) - 1; |
||||
printf("%d-%d ", start, end); |
||||
} |
||||
printf("'\n"); |
||||
} |
||||
|
||||
if (dmr) |
||||
printf("RULE_%d_DMR=%s\n", rulecnt, dmr); |
||||
|
||||
if (br) |
||||
printf("RULE_%d_BR=%s\n", rulecnt, br); |
||||
} |
||||
|
||||
printf("RULE_COUNT=%d\n", rulecnt); |
||||
return status; |
||||
} |
Loading…
Reference in new issue