NICMx / Jool

SIIT and NAT64 for Linux
GNU General Public License v2.0
336 stars 66 forks source link

Add support for BIB entries with dynamic IPv4 addresses #304

Open tiagogaspar8 opened 5 years ago

tiagogaspar8 commented 5 years ago

Hey Everyone!

It's just a suggestion but could we add a way to configure jool from a file, using uci or some other type of file configuration?

Thanks!

ydahhrk commented 5 years ago

Are you aware of this?

tiagogaspar8 commented 5 years ago

No I wasn't! I thought I had read all the documentation but I guess I was wrong. I'd like to add a default startup script to OpenWRT but for that I needed Jool to have a default configuration file. I'll be trying to do that. Just one question off topic, How do I do a type of "port forwarding"? I've seen the bib static entries but those require me to enter a ipv4 address and my wan has a dynamic IP address.

ydahhrk commented 5 years ago

It cannot be done as currently implemented, but if it's a legitimate use case I could add support for it.

But how are you expecting port forwarding to work? If your IPv4 address changes constantly, how is your IPv4 client supposed to know it?

ydahhrk commented 5 years ago

I'd like to add a default startup script to OpenWRT but for that I needed Jool to have a default configuration file.

By the way: I'm not entirely sure, but from a quick Google search it seems OpenWRT uses init.d. We already have init scripts for Jool, in case you want to reuse them:

(They might need some adjustments, such as binary paths)

tiagogaspar8 commented 5 years ago

For the outside connection I use a dynamic DNS, so clients never lose access. So for example if I want to connect to a server on my LAN from the external IPv4 WAN address I'd do:

client on WAN-IP4 - - - - - - > WAN-IP4:443 - - - - - - >SERVER-IP6:443
                 (connects to)              (forwards to)

As for the scripts you provided, they use some functions I really have no idea of what they are like for example . /lib/lsb/init-functions witch doesn't exist in OpenWRT. Also there are som sections of the script that I don't understand what they do like check_permissions(if this is to check if the software running the script has enough privileges to execute the needed commands OpenWRT doesn't need it), also I believe the check_workspace isn't also needed since upon install OpenWRT adds the config file and the binaries, so at least the section for checking the existence of the program are not needed. If you want I can show you the files I made and you can give me some help, what do you think?

ydahhrk commented 5 years ago

check_permissions(), check_workspace() and probably others exist for the sake of Linux Standard Base (LSB) conformance. For example, check_permissions() ensures that the script returns 4 on "user had insufficient privilege", and not something else. LSB conformance was required by Debian, but it's possible OpenWRT might not care about it.

For the outside connection I use a dynamic DNS, so clients never lose access.

Ok, but just to understand this a little better: Are these connections supposed to survive the address change? Do the clients open new connections when the address changes? Or do these clients somehow modify their socket addresses so as to avoid repeating the TCP handshake?

tiagogaspar8 commented 5 years ago

LSB conformance was required by Debian, but it's possible OpenWRT might not care about it.

OpenWRT just need to have the commands necessary to the start of the package, if it can check some stuff before starting, ok, but it's not mandatory. I'm going to be pushing it to a temporary branch in my forked packages repository, check it out if you want! ๐Ÿ˜„

Ok, but just to understand this a little better: Are these connections supposed to survive the address change? Do the clients open new connections when the address changes? Or do these clients somehow modify their socket addresses so as to avoid repeating the TCP handshake?

You're asking hard questions, I want my server to serve a nextcloud instance to the outside, it's rarely going to be used, but I belive OpenWRT would keep the connection open even after the IP changed, so if the address changes the client would continue to communicate with the new address (?) I believe at least.

ydahhrk commented 5 years ago

I want my server to serve a nextcloud instance to the outside, it's rarely going to be used, but I belive OpenWRT would keep the connection open even after the IP changed, so if the address changes the client would continue to communicate with the new address (?) I believe at least.

As far as I know, a connection (whether TCP or UDP) is invariably identified by its IP addresses and ports. If you change one address, then the connection breaks and needs to be re-established from scratch. (Unless I'm missing some strange hack.)

And if that's what you expect to happen, then I think it would be most elegant if the dynamic DNS informed Jool of the new address every time it's changed (by updating the BIB and perhaps pool4 as well). I mean Jool could theoretically monitor the address and respond appropriately whenever it changes, but I feel like this wouldn't be optimal or terribly reliable.

What do you think?

tiagogaspar8 commented 5 years ago

I see what you mean, sorry for the delay answering but shchool's been hard ahaha. I don't think there's any need for it, jool can automatically obtain the IP address from the linux routing table or from the interface's IP address. I believe you're right TCP and UDP would break connection but there's no problem for three reasons: 1st - TCP will break the connection when the timeout is reached even if the IP doesn't change so there's no issue there. 2nd - UDP bindings aren't reliable, they're not suitable for connections that need a reliable strem so there's no issue there either. 3rd - HTTP will soon be moving towards HTTP/3 and this one is a protocol (QUIC) that predicts and adapts to changes in the IP address.

So for me, there just needs to be a simple port-forwarding system that redirects connections coming form the WAN address to some specified LAN address.

Also, on another note, what do you think of this? Did I do it right? https://github.com/tiagogaspar8/packages/commit/baec51718cb4c693f5000e0bc54bacb5b5482c86

ydahhrk commented 5 years ago

Ok. My prediction is that this will look something like

jool bib add 2001:db8::1#1080 *#1080

I can't think of any problems with this idea (other than what I expect is going to be a horrifyingly messy implementation) but I'll keep thinking.

Also, on another note, what do you think of this? Did I do it right?

Your sample configuration files are going to create a lot of problems for careless users who trust their defaults to be reasonable. I don't think anyone should enable logging-session (it's a pointless and dumb configuration field and I'm planning to remove it at some point), and your mtu-plateaus might cause some of your clients to think they need to create impossibly small packets (sized 6, in fact. Not even enough for an IPv4 header). People should definitely not enable ss-enabled willy-nilly because it's not performance-friendly, and your f-args is optimized for certain poorly-designed application protocols and nothing else.

If you want to include every configuration option for the sake of easy modification it's fine, but you should probably use Jool's default values instead of random ones.

tiagogaspar8 commented 5 years ago

I can't think of any problems with this idea (other than what I expect is going to be a horrifyingly messy implementation) but I'll keep thinking.

That seems about right If you need any help just summon me and I'll be here when I can.

If you want to include every configuration option for the sake of easy modification it's fine, but you should probably use Jool's default values instead of random ones.

I can just add default configuration files all commented out and let people fill it. What do you think?

ydahhrk commented 4 years ago

I can just add default configuration files all commented out and let people fill it. What do you think?

Agreed.

tiagogaspar8 commented 4 years ago

Ok, I'll get to it. Where can I get the default configuration files?

ydahhrk commented 4 years ago

The defaults values are hardcoded: https://github.com/NICMx/Jool/blob/master/src/common/constants.h#L66 You can also find them here: https://jool.mx/en/usr-flags-global.html

On Sun, Dec 22, 2019 at 7:14 PM Tiago Gaspar notifications@github.com wrote:

Ok, I'll get to it. Where can I get the default configuration files?

โ€” You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/NICMx/Jool/issues/304?email_source=notifications&email_token=AASHNF5WKHDBDMRPV7H3Q2LQ2AGIPA5CNFSM4JJXVTD2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEHP6OTY#issuecomment-568321871, or unsubscribe https://github.com/notifications/unsubscribe-auth/AASHNFZJ62YTB34YYD2GZJ3Q2AGIPANCNFSM4JJXVTDQ .

tiagogaspar8 commented 4 years ago

Oh god. I'll do it as soon as I can.

tiagogaspar8 commented 4 years ago

Well after a bit of research, JSON doesn't support comments, so I have decided to switch the "manually-enabled" option to enabled, that way jool won't start unless this is set to disabled, right? Sorry for the long delay.

ydahhrk commented 4 years ago

"comment" tags are specified to be ignored by Jool's interpreter in any context.

You can therefore group sample fields in comment tags, and Jool should ignore them:

"global": {
    "comment": {
        "pool6": "64:ff9b::/96",
        "manually-enabled": false,
        "zeroize-traffic-class": true,
        "override-tos": false,
        "tos": 254,
        "mtu-plateaus": [1, 2, 3, 4, 5, 6],
        "amend-udp-checksum-zero": true,
        "eam-hairpin-mode": "simple",
        "randomize-rfc6791-addresses": false,
        "rfc6791v6-prefix": null,
        "rfc6791v4-prefix": null
    }
},

(Disclaimer: Untested, but you should get the general idea.)

ydahhrk commented 4 years ago

(Although, for the record, I still think you should include sensible default values. "manually-enabled": true is certainly sensible.)

tiagogaspar8 commented 4 years ago

I think that if "manually-enabled" makes jool not start it is the best way to not screw things up while leaving the configuration files clean and "simple", right? If you agree with me as soon as I'm ready I'll show you the final commit

ydahhrk commented 4 years ago

Hmm... I think there's some sort of language barrier getting in the way of our conversation.

I will try to be as clear as I can:

manually-enabled is a configuration option that behaves like this:

My opinion is that manually-enabled should be true by default. This is because we don't want to add unnecessary steps to Jool's starting procedure. If translators instances are disabled by default, new users would struggle to enable them.

As currently implemented, manually-enabled is in fact true if you omit it. manually-enabled is not false by default. Jool is automatically enabled by default.

Therefore, you don't need to include manually-enabled in the sample configuration, unless you're trying to list every available configuration option for the sake of being as explicit as possible.

And if you do want to list every configuration option, my opinion is that you should not change the default values, because their current defaults make the most sense in the vast majority of production environments.

Therefore, my opinion is that you should include the following global defaults for NAT64:

"global": {
    "manually-enabled": true,
    "pool6": "64:ff9b::/96",
    "zeroize-traffic-class": false,
    "override-tos": false,
    "tos": 0,
    "mtu-plateaus": [65535, 32000, 17914, 8166, 4352, 2002, 1492, 1006, 508, 296, 68],
    "address-dependent-filtering": false,
    "drop-icmpv6-info": false,
    "drop-externally-initiated-tcp": false,
    "udp-timeout": "5:00",
    "tcp-est-timeout": "1:00",
    "tcp-trans-timeout": "2:00:00",
    "icmp-timeout": "4:00",
    "maximum-simultaneous-opens": 10,
    "source-icmpv6-errors-better": true,
    "f-args": 11,
    "handle-rst-during-fin-rcv": false,
    "logging-bib": false,
    "logging-session": false,
    "ss-enabled": false,
    "ss-flush-asap": true,
    "ss-flush-deadline": 2000,
    "ss-capacity": 512,
    "ss-max-payload": 1452
},

and the following global defaults for SIIT:

"global": {
    "manually-enabled": true,
    "comment": "Please change pool6 according to your needs!",
    "pool6": null,
    "zeroize-traffic-class": false,
    "override-tos": false,
    "tos": 0,
    "mtu-plateaus": [65535, 32000, 17914, 8166, 4352, 2002, 1492, 1006, 508, 296, 68],
    "amend-udp-checksum-zero": false,
    "eam-hairpin-mode": "intrinsic",
    "randomize-rfc6791-addresses": true,
    "rfc6791v6-prefix": null,
    "rfc6791v4-prefix": null
},

(Actually, SIIT is a bit of a lost cause, because we can't provide a pool6 that will always workโ€”users always need to define it according to their network. But this is as complete as it can be.)

Or you can just do what I do with the Debian package, which is keep the sample configuration as minimalist as possible. (Because I'm assuming that most users will not want to modify the global values.)

tiagogaspar8 commented 4 years ago

I see what you mean and maybe I'm not explaining myself correctly.

Let's assume that I leave the default configurations (witch I intend to) including manually-enabled as true. When you select in OpenWRT the jool package, the building process automatically enables the packages to start at boot, witch isn't good and we cant change as it is default OpenWrt behavior. So the jool package will be started at boot with the configuration files, and starts working with the configuration we add by default

The alternatives we have:

  1. Comment out all the configurations making jool do nothing (or apply the default config, not sure)
  2. Switch the manually-enabled config to false and that makes jool do nothing

See what I mean? I hope I'm explaining myself correctly.๐Ÿ˜…๐Ÿ˜…๐Ÿ˜…

ydahhrk commented 4 years ago

Ah, I see.

  1. Switch the manually-enabled config to false and that makes jool do nothing

Well, perhaps one problem with this is that OpenWRT will think the service is enabled, even though Jool is technically disabled. It's going to look confusing, I think.

  1. Comment out all the configurations making jool do nothing (or apply the default config, not sure)

What I do in Debian is not provide default configuration files, and this naturally prevents the service from starting.

(This is partly because I have access to a thing called ConditionPathExists, which makes systemd check the file before attempting to start the service. But even if OpenWRT doesn't provide a ConditionPathExists, the missing files would still prevent the service from starting because jool file handle throws an error when it can't find the file.)

I actually do provide sample configuration files in Debian, but I do so in the dedicated example directory (/usr/share/doc/jool-tools/examples/). You can see that I ask users to copy the file they want in the documentation.

tiagogaspar8 commented 4 years ago

It's going to look confusing

I see what you mean, but people usually configure stuff, not using the default value. But I can add a "verification" that checks if the flag manually-enables is off and display a info reminder in the syslog.

the missing files would still prevent the service from starting because jool file handle throws an error when it can't find the file.)

Well, what kind of error? does it say "file /etc/jool/jool.conf.json not found"? or just says invalid file?

Also, in a recent test I ran into an issue:

Thu Jan  9 02:21:45 2020 kern.warn kernel: [837448.622609] jool: Unknown symbol target_ipv4 (err -2)
Thu Jan  9 02:21:45 2020 kern.warn kernel: [837448.627851] jool: Unknown symbol target_ipv6 (err -2)
Thu Jan  9 02:21:45 2020 kern.warn kernel: [837448.633142] jool: Unknown symbol jool_nat64_get (err -2)
Thu Jan  9 02:21:45 2020 kern.warn kernel: [837448.638631] jool: Unknown symbol jool_nat64_put (err -2)
Thu Jan  9 02:21:45 2020 kern.warn kernel: [837448.644168] jool: Unknown symbol target_checkentry (err -2)

Do you have any idea?

ydahhrk commented 4 years ago

Well, what kind of error? does it say "file /etc/jool/jool.conf.json not found"? or just says invalid file?

# jool file handle /i/do/not/exist
Error: Could not open file "/i/do/not/exist": No such file or directory
# echo $?
2

Also, in a recent test I ran into an issue:

You installed jool.ko and (also presumably) jool_siit.ko, but not jool_common.ko.

See https://jool.mx/en/install.html#introduction

ydahhrk commented 4 years ago

You installed jool.ko and (also presumably) jool_siit.ko, but not jool_common.ko.

jool_common is new; it first appeared in version 4.0.6 I believe.

tiagogaspar8 commented 4 years ago

Could not open file "/i/do/not/exist"

If that is the case We can do this: I'll leave a file with the default values named for example "jool_nat64.conf.json.defaults" that way when the program goes searching for the "jool_nat64.conf.json" file it won't find it, and won't run, leaving a entry in the syslog. I'll see if I can find a way for the start script to check for the file first and display a error message that I write. Do you agree?

jool_common is new; it first appeared in version 4.0.6 I believe.

AHA! That's why. the makefile doesn't foresee that third kernel module I believe. I'll get around to that.

ydahhrk commented 4 years ago

If that is the case We can do this: I'll leave a file with the default values named for example "jool_nat64.conf.json.defaults" that way when the program goes searching for the "jool_nat64.conf.json" file it won't find it, and won't run, leaving a entry in the syslog. I'll see if I can find a way for the start script to check for the file first and display a error message that I write. Do you agree?

Yes, absolutely.

tiagogaspar8 commented 4 years ago

Hey!

I haven't forgotten about this issue, I just haven't been doing more cause I saw that @blocktronn has been working on the jool init and even uci configuration in his branch https://github.com/blocktrron/packages/tree/jool-init . I'm currently waiting for developments on this matter before I put in more work.

rnhmjoj commented 1 year ago

Couldn't this be simply a hook that rebuilds the BIB on changes to the WAN interface? I don't think we gain anything useful by implementing this in jool: if the IP address changes connections are going to break anyway, so there's always going to be some downtime. On openwrt I would imagine something like (untested)

$ cat /etc/jool/jool-nat64.conf.json.in
{
  "instance": "default",
  "framework": "netfilter",
  "global": { "pool6": "64:ff9b::/96" },
  "bib" : [
    { "protocol": "TCP", "ipv6 address": "2001:db8::1#22", "ipv4 address": "WAN_ADDR#22" },
    { "protocol": "TCP", "ipv6 address": "2001:db8::3#80", "ipv4 address": "WAN_ADDR#80" }
  ],
    "pool4": [
        { "protocol": "TCP",  "prefix": "WAN_ADDR/32", "port range": "1-65635" },
    { "protocol": "UDP",  "prefix": "WAN_ADDR/32", "port range": "1-65635" },
        { "protocol": "ICMP", "prefix": "WAN_ADDR/32", "port range": "1-65635" }
    ]
}

$ cat /etc/hotplug.d/99-update-jool-bib
# if WAN is up
test "$INTERFACE" != "$WAN_INTERFACE" -o "$ACTION" != "ifup" && exit 0

# get WAN IPv4 address
. /lib/functions/network.sh
network_get_ipaddr WAN_ADDR "$WAN_INTERFACE"

# update the BIB
. /etc/init.d/jool
sed "s/WAN_ADDR/$WAN_ADDR/g" "$CONFIGFILE_NAT64.in" > "$CONFIGFILE_NAT64"

service jool restart
rnhmjoj commented 1 year ago

Ok, I tested and it works perfectly fine. Here's a ready-made openwrt solution. Just put the following into /etc/rc.local and update the BIB entries accordingly.

# install jool BIB update script
cat <<'EOF' > /etc/hotplug.d/iface/99-jool-bib
test "$INTERFACE" != wan4 -o "$ACTION" != "ifup" && exit 0
service jool restart
EOF

# configure stateful NAT64
cat <<'EOF' > /etc/jool/jool-nat64.conf.json.in
{
  "instance": "default",
  "framework": "netfilter",
  "global": { "pool6": "64:ff9b::/96" },
  "bib": [
    {
      "comment": "Forward WAN_ADDR:80 -> 2001:db8::1:80",
      "protocol": "TCP",
      "ipv4 address": "WAN_ADDR#80",
      "ipv6 address": "2001:db8::1#80"
    },
}
EOF

# patch init.d script to compute the WAN address
grep -q BIB /etc/init.d/jool || sed -i '/config_parser()/{
  i splice_config() {
  i \   # get WAN IPv4 address
  i \   . /lib/functions/network.sh
  i \   network_get_ipaddr WAN_ADDR wan4
  i
  i \   # update the BIB
  i \   sed "s/WAN_ADDR/$WAN_ADDR/g" "$CONFIGFILE_NAT64.in" > "$CONFIGFILE_NAT64"
  i }
  i
  } 
  /start()/{
  a \   splice_config
  }' /etc/init.d/jool

service jool restart