Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

introduce XLAT, native IPv4 for clients #1808

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ Several Freifunk communities in Germany use Gluon as the foundation of their Fre
:caption: Packages
:maxdepth: 1

package/gluon-464xlat-clat
package/gluon-client-bridge
package/gluon-config-mode-domain-select
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lacking documentation for gluon-ddhcpd.

package/gluon-ebtables-filter-multicast
Expand Down
32 changes: 32 additions & 0 deletions docs/package/gluon-464xlat-clat.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
gluon-464xlat-clat
==================

This package provides the kernel module and functionality required to support
ipv4 clients on an ipv6-only backbone.
rotanid marked this conversation as resolved.
Show resolved Hide resolved

Assumptions
-----------

* Clients will be given IPv4 addresses by a dhcp daemon that runs on each node.
rotanid marked this conversation as resolved.
Show resolved Hide resolved
gluon-ddhcpd is a great choice for this.
* There is a component on the network that does plat on the default network
64:ff9b::/96. https://github.com/FreifunkMD/jool-docker.git can do this.

Limitations
-----------
* When roaming, clients will experience temporary loss of IPv4 connectivity

site.conf
---------

clat_range : mandatory
- infrastructure net (ULA) from which a /96 clat prefix will be generated.
- This must be a /48 prefix.
Copy link
Contributor

@mweinelt mweinelt Mar 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A short subclause, explaining why a /48, e.g. how it is partitioned, would go a long way.

- This can be the same for each community and is pre-registered at https://wiki.freifunk.net/IP-Netze#IPv6 as part of fdff:ffff:ff00::/40
rotanid marked this conversation as resolved.
Show resolved Hide resolved

Example::

{
clat_range = 'fdff:ffff:ffff::/48',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation

}

15 changes: 15 additions & 0 deletions package/gluon-464xlat-clat/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
include $(TOPDIR)/rules.mk

PKG_NAME:=gluon-464xlat-clat
PKG_VERSION:=1

include ../gluon.mk

PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG)
rotanid marked this conversation as resolved.
Show resolved Hide resolved

define Package/gluon-464xlat-clat
TITLE:=Support translating IPv4 addresses to IPv6 using 464xlat
neocturne marked this conversation as resolved.
Show resolved Hide resolved
DEPENDS:=+gluon-core +kmod-nat46
endef

$(eval $(call BuildPackageGluon,gluon-464xlat-clat))
2 changes: 2 additions & 0 deletions package/gluon-464xlat-clat/check_site.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
need_string(in_domain({'clat_range'}))
need_string_match(in_domain({'next_node', 'ip4'}), '^%d+.%d+.%d+.%d+$', true)
2 changes: 2 additions & 0 deletions package/gluon-464xlat-clat/files/50-clat-sysctl.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
net.ipv4.conf.clat.accept_local=1
net.ipv6.conf.clat.use_oif_addrs_only=1
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
net.ipv4.conf.clat.accept_local=1
net.ipv6.conf.clat.use_oif_addrs_only=1
171 changes: 171 additions & 0 deletions package/gluon-464xlat-clat/files/lib/netifd/proto/xlat464clat.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
#!/bin/sh
# Copyright 2018 Vincent Wiemann <[email protected]>
#
# 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.

CTR=/proc/net/nat46/control

[ -n "$INCLUDE_ONLY" ] || {
. /lib/functions.sh
. ../netifd-proto.sh
init_proto "$@"
}

proto_464xlatclat_init_config() {
proto_config_add_string "zone"
proto_config_add_string "zone4"
proto_config_add_string "local_style"
proto_config_add_string "local_v4"
proto_config_add_string "local_v6"
proto_config_add_string "local_ea_len"
proto_config_add_string "local_psid"
proto_config_add_boolean "local_fmr_flag"
proto_config_add_string "remote_style"
proto_config_add_string "remote_v4"
proto_config_add_string "remote_v6"
proto_config_add_string "remote_ea_len"
proto_config_add_string "remote_psid"
proto_config_add_string "ip4table"
proto_config_add_boolean "debug"
available=1
no_device=1
}

proto_464xlatclat_setup() {
local config="$1"
local clat_cfg="config ${config}"
local local_style
local local_v4
local local_v6
local local_ea_len
local local_psid
local local_fmr
local remote_style
local remote_v4
local remote_v6
local remote_ea_len
local remote_psid
local zone
local zone4
local ip4table

config_load network
config_get ip4table "${config}" "ip4table"
config_get zone "${config}" "zone"
config_get zone4 "${config}" "zone4"
config_get_bool debug "${config}" "debug" 0
config_get local_style "${config}" "local_style"
config_get local_v4 "${config}" "local_v4"
config_get local_v6 "${config}" "local_v6"
config_get local_ea_len "${config}" "local_ea_len"
config_get local_psid "${config}" "local_psid_offset"
config_get_bool local_fmr "${config}" "local_fmr_flag" 0
config_get remote_style "${config}" "remote_style"
config_get remote_v4 "${config}" "remote_v4"
config_get remote_v6 "${config}" "remote_v6"
config_get remote_ea_len "${config}" "remote_ea_len"
config_get remote_psid "${config}" "remote_psid_offset"
config_get local_ip "${config}" "local_ip"

zone="${zone:-wan}"
zone4="${zone4:-lan}"
local_v6="${local_v6:-fd00:13:37:13:37::/96}"
remote_v4="${remote_v4:-0.0.0.0/0}"

[ "$debug" -ne 0 ] && clat_cfg="$clat_cfg debug 1"
[ "${local_fmr}" -ne 0 ] && clat_cfg="$clat_cfg local.fmr-flag 1"

clat_cfg="${clat_cfg} local.style ${local_style:-RFC6052} local.v4 ${local_v4:-192.168.1.0/24} local.v6 ${local_v6}"
clat_cfg="${clat_cfg} local.ea-len ${local_ea_len:-0} local.psid-offset ${local_psid:-0}"
clat_cfg="${clat_cfg} remote.style ${remote_style:-RFC6052} remote.v4 ${remote_v4} remote.v6 ${remote_v6:-64:ff9b::/96}"
clat_cfg="${clat_cfg} remote.ea-len ${remote_ea_len:-0} remote.psid-offset ${remote_psid:-0}"

echo "add ${config}" > ${CTR}
echo "${clat_cfg}" > ${CTR}

[ "${ip4table}" ] && ip -4 rule add from "${local_v4}" lookup "${ip4table}"

proto_init_update "${config}" 1

# add routes
case "${local_v6}" in
*:*/*)
proto_add_ipv6_route "${local_v6%%/*}" "${local_v6##*/}"
;;
*:*)
proto_add_ipv6_route "${local_v6%%/*}" "128"
;;
esac

case "${remote_v4}" in
*.*/*)
proto_add_ipv4_route "${remote_v4%%/*}" "${remote_v4##*/}" "" "" 2048
;;
*.*)
proto_add_ipv4_route "${remote_v4%%/*}" "32" "" "" 2048
;;
esac

proto_add_data
[ "${zone}" != "-" ] && json_add_string zone "${zone}"

json_add_array firewall
# if forwarding within "zone" and between zone<->zone4 is allowed you can set zone = "-"
if [ "${zone}" != "-" ]; then
json_add_object ""
json_add_string type rule
json_add_string family inet6
json_add_string proto all
json_add_string direction in
json_add_string dest "${zone}"
json_add_string src "${zone}"
json_add_string src_ip "$local_v6"
json_add_string target ACCEPT
json_close_object
# if a forwarding between zone and zone4 exists (e.g. lan<->wan) you can set zone4 = "-"
if [ "${zone4}" != "-" ]; then
json_add_object ""
json_add_string type rule
json_add_string family inet
json_add_string proto all
json_add_string direction out
json_add_string dest "${zone}"
[ "$remote_v4" != "0.0.0.0/0" ] && json_add_string dest_ip "$remote_v4"
json_add_string src "${zone4}"
json_add_string src_ip "$local_v4"
json_add_string target ACCEPT
json_close_object
fi
fi

json_close_array

proto_close_data

proto_send_update "$config"

# this rule relies on the ll-address being set. This rule will set the
# src-address for icmp packets to the ipv4 next-node address
clat_ll_ip="$(ip -o a s dev clat |cut -d" " -f7|cut -d"/" -f1)/128"
clat_cfg="insert $config local.v4 ${local_ip} local.v6 :: local.style NONE"
clat_cfg="${clat_cfg} local.ea-len 0 local.psid-offset 0"
clat_cfg="${clat_cfg} remote.v4 ${local_ip} remote.v6 $clat_ll_ip"
clat_cfg="${clat_cfg} remote.style NONE remote.ea-len 0 remote.psid-offset 0"
echo "${clat_cfg}" > ${CTR}
}

proto_464xlatclat_teardown() {
local config="$1"
echo "del ${config}" > ${CTR}
}

[ -n "$INCLUDE_ONLY" ] || {
add_protocol 464xlatclat
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/lua
local site = require 'gluon.site'
local sysconfig = require 'gluon.sysconfig'
local uci = require('simple-uci').cursor()

local f = io.open("/etc/iproute2/rt_tables", "r")
if f then
if not f:read("*a"):find("10\tclat") then
f:close()
f = io.open("/etc/iproute2/rt_tables", "a")
if f then
f:write("\n10\tclat\n")
end
end
f:close()
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


local plat_prefix = uci:get('network', 'plat', 'local_v6') or "64:ff9b::/96"

uci:set('network', 'local_node', 'ip4table', 'clat')

local appendix = sysconfig.primary_mac:gsub('%:', '')
appendix = string.format('%x:%x:%x', tonumber(appendix:sub(1, 4), 16),
tonumber(appendix:sub(5, 8), 16),
tonumber(appendix:sub(9, 12), 16))
local clat_prefix = string.format('%s%s::/96', site.clat_range():gsub(':/.+', ''), appendix)

uci:delete('network', 'clat')
uci:section('network', 'interface', 'clat', {
proto = '464xlatclat',
local_v4 = site.prefix4(),
local_v6 = clat_prefix,
remote_v6 = plat_prefix,
zone = "local_client",
zone4 = "local_client",
ip4table = "clat",
local_ip = site.next_node.ip4() .. '/32'
})
uci:save('network')
13 changes: 13 additions & 0 deletions package/gluon-ddhcpd/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
include $(TOPDIR)/rules.mk

PKG_NAME:=gluon-ddhcpd
PKG_VERSION:=1

include ../gluon.mk

define Package/gluon-ddhcpd
TITLE:=Distributed DHCP Daemon for Gluon
DEPENDS:=+gluon-core +ddhcpd
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does ddhcpd come from?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If gluon-ddhcpd depends on mmfd that dependency is missing here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ddhcpd depends on a means to distribute multicast throughout the network. In babel networks this capability is provided by mmfd. in batman networks this is provided by the l2-property of batman. It could also be provided by bier or any other means. There is no way to model that currently and depending on mmfd is not the right thing to do for batman - as such a dependency was not placed.

endef

$(eval $(call BuildPackageGluon,gluon-ddhcpd))
2 changes: 2 additions & 0 deletions package/gluon-ddhcpd/check_site.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

empty line?

need_string_match(in_domain({'next_node', 'ip4'}), '^%d+.%d+.%d+.%d+$', true)
6 changes: 6 additions & 0 deletions package/gluon-ddhcpd/files/etc/ddhcp-hook.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/sh

for i in /etc/ddhcpd.d/*
do
$i "$@"
done
53 changes: 53 additions & 0 deletions package/gluon-ddhcpd/files/etc/init.d/gluon-ddhcpd
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/bin/sh /etc/rc.common

START=90
USE_PROCD=1
NAME=ddhcpd
DAEMON=/usr/sbin/ddhcpd
MAXDELAY=10

validate_section_ddhcpd() {
uci_validate_section "$NAME" ddhcpd settings \
'dhcp_interface:string:br-client' \
'server_interface:string:br-client' \
'block_size_pow:uinteger:2' \
'spare_blocks:uinteger:1' \
'timeout:uinteger:30' \
'block_network:cidr4' \
'dhcp_lease_time:uinteger:300'
server_interface=$(ubus call network.interface dump | jsonfilter -e "@.interface[@.interface='$(cat /lib/gluon/respondd/client.dev 2>/dev/null)' && @.up=true].device")
}

start_service() {
[ -x /lib/gluon/ddhcpd/arguments ] || exit 1

procd_open_instance
procd_set_param command $DAEMON -D

config_load "${NAME}"

validate_section_ddhcpd || {
echo "validation failed"
return 1
}

procd_append_param command -s "$spare_blocks"
procd_append_param command -b "$block_size_pow"
procd_append_param command -c "$dhcp_interface"
procd_append_param command -i "$server_interface"
procd_append_param command -N "$block_network"
procd_append_param command -o "51:4:0.0.1.44"
procd_append_param command -o "3:4:$(lua -e 'print(require("gluon.site").next_node.ip4())')"
procd_append_param command -o "6:4:$(lua -e 'print(require("gluon.site").next_node.ip4())')"
procd_append_param command $(/lib/gluon/ddhcpd/arguments)
procd_set_param respawn
procd_set_param netdev "$dhcp_interface"
[ "$dhcp_interface" == "$server_interface" ] || procd_append_param netdev "$server_interface"
procd_set_param stderr 1
procd_close_instance
}

service_triggers() {
procd_add_config_trigger "config.change" "ddhcpd" /etc/init.d/ddhcpd restart
procd_add_interface_trigger "interface.*" "$server_interface" /etc/init.d/ddhcpd restart
}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh

uci set ddhcpd.settings.enabled="0"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be merged into 316-ddhcp

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done, please check if it was done correctly

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/lua
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WIth the mmfd rule it's probably appropriate to call the file ddhcpd-firewall.


local uci = require('simple-uci').cursor()

uci:section('firewall', 'rule', 'local_node_dhcp', {
src = 'local_client',
name = 'allow_dhcp_local_client',
dest_port = '67',
proto = 'udp',
target = 'ACCEPT'
rotanid marked this conversation as resolved.
Show resolved Hide resolved
})

uci:section('firewall', 'rule', 'ddhcpd_mmfd', {
dest_port = '1234',
src = 'mmfd',
src_ip = 'fe80::/64',
name = 'allow_ddhcp_to_reserve_blocks',
proto = 'udp',
target = 'ACCEPT'
})

uci:save('firewall')
9 changes: 9 additions & 0 deletions package/gluon-ddhcpd/luasrc/lib/gluon/upgrade/316-ddhcp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/lua
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no need to sort this behind the firewall rules, both can be put at position 315.


local site = require 'gluon.site'

local uci = require('simple-uci').cursor()

uci:set('ddhcpd', 'settings', 'block_network', site.prefix4())

uci:save('ddhcpd')
5 changes: 5 additions & 0 deletions package/gluon-l3roamd/files/etc/ddhcpd.d/l3roamd
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/sh
if [ "$1" = "lease" ]
then
echo add_address "$2" "$3" | uc /var/run/l3roamd.sock
fi
Loading