Page MenuHomeFreeBSD

pf: support SCTP multihoming
ClosedPublic

Authored by kp on Aug 29 2023, 7:05 PM.
Tags
None
Referenced Files
F102422895: D41637.diff
Tue, Nov 12, 1:53 AM
Unknown Object (File)
Wed, Oct 23, 12:46 PM
Unknown Object (File)
Wed, Oct 23, 12:45 PM
Unknown Object (File)
Wed, Oct 23, 12:45 PM
Unknown Object (File)
Wed, Oct 23, 12:45 PM
Unknown Object (File)
Wed, Oct 23, 12:28 PM
Unknown Object (File)
Oct 3 2024, 12:08 PM
Unknown Object (File)
Sep 24 2024, 2:47 PM

Details

Summary

SCTP may announce additional IP addresses it'll use in the INIT/INIT_ACK
chunks, or in ASCONF chunks at any time during the connection. Parse these
parameters and create the corresponding states.

MFC after: 3 weeks
Sponsored by: Orange Business Services

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Passed
Unit
No Test Coverage
Build Status
Buildable 53401
Build 50292: arc lint + arc unit

Event Timeline

kp requested review of this revision.Aug 29 2023, 7:05 PM

One of the things I'm still thinking about is how to handle NAT.

It seems reasonable to also translate the IP addresses in INIT/ASCONF chunks, but ASCONF especially can be authenticated so any packet mangling is going to be detected.
I wonder if we ought to detect that, or if we ought to mangle the connection setup to remove AUTH from the supported extensions list.

Questions since I'm not familiar with the pf code:
Is my understanding correct that you create multiple entries for a single SCTP association, which is multihomed. One for each address parameter in the INIT or INIT ACK chunk and for the ASCOF chunk? If that is correct, what happens if you observer a graceful shutdown of the association? Do you remove one entry or all entries?
You also protect against the case where the source address is listed in the INIT and INIT ACK. Do you also protect against the case where the INIT or INIT ACK contains an address more than once?

Another question: You change the firewall state because addresses are listed in the INIT and INIT ACK chunk (let us focus on that). How to you protect against the case where on end point, which is allowed to communicate with, lists an address of another end point, which it is not allowed to communicate with. Is it possible for malicious peer to circumvent the rules by listing arbitrary addresses in the INIT and INIT ACK? I'm asking since in the protocol implementation addresses must be verified before they can actually be used...

In D41637#948933, @kp wrote:

One of the things I'm still thinking about is how to handle NAT.

It seems reasonable to also translate the IP addresses in INIT/ASCONF chunks, but ASCONF especially can be authenticated so any packet mangling is going to be detected.

An endpoint sending an INIT/INIT ACK/ASCONF chunk to some address should not list an address with a smaller scope.
This means if you send an INIT/INIT ACK/ASCONF to a global address, you should not list private or loopback addresses. So I guess whatever handling you are thinking about, it will not be used a lot.
We never finished the internet draft (draft-stewart-tsvwg-sctp-ipv4-00 and the same would apply to IPv6, but this is implemented.

I wonder if we ought to detect that, or if we ought to mangle the connection setup to remove AUTH from the supported extensions list.

If you remove AUTH from the list, no ASCONF chunks will be processed. It is required in RFC 5061.

A way how to do NAT is that the end point does not list relevant addresses in the INIT/INIT ACK/ASCONF. It sets up the association single homed and does not list any addresses in the INIT chunk. After the association is setup, it adds an address by sending an ASCONF chunk adding 0.0.0.0 or :: from the source address it wants to send. This way the NAT could add the state and the peer would add the public address (the source address the NAT has assigned). But this means the end points and the middle boxes need to cooperate...

Questions since I'm not familiar with the pf code:
Is my understanding correct that you create multiple entries for a single SCTP association, which is multihomed. One for each address parameter in the INIT or INIT ACK chunk and for the ASCOF chunk? If that is correct, what happens if you observer a graceful shutdown of the association?

That's correct, yes.

Do you remove one entry or all entries?

Only the one that sees the shutdown, the others would eventually time out and be removed that way. There's currently no link between each pf state for the SCTP association.
We could potentially track the verification tag and use that (perhaps along with src/dst ports, to reduce the risk of collisions) the terminate all states for the association, but that'd either mean a scan over the full state table (which would get very expensive), or a new hash table specifically for SCTP.
(Having links between states would be a locking nightmare, and also really painful to pfsync.)

You also protect against the case where the source address is listed in the INIT and INIT ACK. Do you also protect against the case where the INIT or INIT ACK contains an address more than once?

Not explicitly, however we'd later fail the pf_create_state() call from pf_sctp_multihome_delayed(). The check here is mostly to avoid doing the setup work that we know is pointless anyway, for the common case.

Another question: You change the firewall state because addresses are listed in the INIT and INIT ACK chunk (let us focus on that). How to you protect against the case where on end point, which is allowed to communicate with, lists an address of another end point, which it is not allowed to communicate with. Is it possible for malicious peer to circumvent the rules by listing arbitrary addresses in the INIT and INIT ACK? I'm asking since in the protocol implementation addresses must be verified before they can actually be used...

There's no further evaluation of the rules right now. The connection is trusted to add more addresses. It would probably be better to run pf_test_rule() again and create states that way. That'd run the ruleset against the new addresses.

In D41637#948933, @kp wrote:

One of the things I'm still thinking about is how to handle NAT.

It seems reasonable to also translate the IP addresses in INIT/ASCONF chunks, but ASCONF especially can be authenticated so any packet mangling is going to be detected.

An endpoint sending an INIT/INIT ACK/ASCONF chunk to some address should not list an address with a smaller scope.
This means if you send an INIT/INIT ACK/ASCONF to a global address, you should not list private or loopback addresses. So I guess whatever handling you are thinking about, it will not be used a lot.
We never finished the internet draft (draft-stewart-tsvwg-sctp-ipv4-00 and the same would apply to IPv6, but this is implemented.

The immediate case that comes to mind is the 'home network', where the client machine has 192.168.1.2 and 192.168.1.3 as addresses, and gets NATed to say 1.2.3.4 (possibly with multiple WAN addresses, so having the secondary connection would make at least some sense). We already NAT the IP header address (otherwise nothing would work), but if the client also lists the secondary address in INIT or ASCONF we'd want to do something about that.

I wonder if we ought to detect that, or if we ought to mangle the connection setup to remove AUTH from the supported extensions list.

If you remove AUTH from the list, no ASCONF chunks will be processed. It is required in RFC 5061.

That's certainly good to know.
I'm tempted to implement a scrub action to remove AUTH/ASCONF, mostly to at least have a workaround for basic NAT setups, but I'm going to sleep on that at least.

A way how to do NAT is that the end point does not list relevant addresses in the INIT/INIT ACK/ASCONF. It sets up the association single homed and does not list any addresses in the INIT chunk. After the association is setup, it adds an address by sending an ASCONF chunk adding 0.0.0.0 or :: from the source address it wants to send. This way the NAT could add the state and the peer would add the public address (the source address the NAT has assigned). But this means the end points and the middle boxes need to cooperate...

I believe my code currently doesn't handle the 0.0.0.0 case, but that ought to be straightforward to add at least.

In D41637#949255, @kp wrote:
In D41637#948933, @kp wrote:

One of the things I'm still thinking about is how to handle NAT.

It seems reasonable to also translate the IP addresses in INIT/ASCONF chunks, but ASCONF especially can be authenticated so any packet mangling is going to be detected.

An endpoint sending an INIT/INIT ACK/ASCONF chunk to some address should not list an address with a smaller scope.
This means if you send an INIT/INIT ACK/ASCONF to a global address, you should not list private or loopback addresses. So I guess whatever handling you are thinking about, it will not be used a lot.
We never finished the internet draft (draft-stewart-tsvwg-sctp-ipv4-00 and the same would apply to IPv6, but this is implemented.

The immediate case that comes to mind is the 'home network', where the client machine has 192.168.1.2 and 192.168.1.3 as addresses, and gets NATed to say 1.2.3.4 (possibly with multiple WAN addresses, so having the secondary connection would make at least some sense). We already NAT the IP header address (otherwise nothing would work), but if the client also lists the secondary address in INIT or ASCONF we'd want to do something about that.

As I said above: In this use case the client in the 'home network' will use one of its private addresses as a source, a global address as the destination address and will not list the other private addresses in the INIT. If the client would do this, the association could be blackholed. As far as I know, most implementation behave like this.

I wonder if we ought to detect that, or if we ought to mangle the connection setup to remove AUTH from the supported extensions list.

If you remove AUTH from the list, no ASCONF chunks will be processed. It is required in RFC 5061.

That's certainly good to know.
I'm tempted to implement a scrub action to remove AUTH/ASCONF, mostly to at least have a workaround for basic NAT setups, but I'm going to sleep on that at least.

If you will interfere with AUTH, you will break DTLS over SCTP, which uses AUTH. I don't think you want to do this. You could remove the ASCONF and ASCONF ACK entries in the 'Supported Extensions Parameter' of the INIT and INIT ACK chunks, such that each side thinks its peer does not support the address reconfiguration option. However, that breaks the way the SCTP specific way of NAT would work. But, again, this internet draft was killed after WGLC.

A way how to do NAT is that the end point does not list relevant addresses in the INIT/INIT ACK/ASCONF. It sets up the association single homed and does not list any addresses in the INIT chunk. After the association is setup, it adds an address by sending an ASCONF chunk adding 0.0.0.0 or :: from the source address it wants to send. This way the NAT could add the state and the peer would add the public address (the source address the NAT has assigned). But this means the end points and the middle boxes need to cooperate...

I believe my code currently doesn't handle the 0.0.0.0 case, but that ought to be straightforward to add at least.

I guess it is simple. If the address to add is 0.0.0.0, use the source address instead.

In D41637#949254, @kp wrote:

Questions since I'm not familiar with the pf code:
Is my understanding correct that you create multiple entries for a single SCTP association, which is multihomed. One for each address parameter in the INIT or INIT ACK chunk and for the ASCOF chunk? If that is correct, what happens if you observer a graceful shutdown of the association?

That's correct, yes.

Do you remove one entry or all entries?

Only the one that sees the shutdown, the others would eventually time out and be removed that way. There's currently no link between each pf state for the SCTP association.
We could potentially track the verification tag and use that (perhaps along with src/dst ports, to reduce the risk of collisions) the terminate all states for the association, but that'd either mean a scan over the full state table (which would get very expensive), or a new hash table specifically for SCTP.
(Having links between states would be a locking nightmare, and also really painful to pfsync.)

You also protect against the case where the source address is listed in the INIT and INIT ACK. Do you also protect against the case where the INIT or INIT ACK contains an address more than once?

Not explicitly, however we'd later fail the pf_create_state() call from pf_sctp_multihome_delayed(). The check here is mostly to avoid doing the setup work that we know is pointless anyway, for the common case.

Another question: You change the firewall state because addresses are listed in the INIT and INIT ACK chunk (let us focus on that). How to you protect against the case where on end point, which is allowed to communicate with, lists an address of another end point, which it is not allowed to communicate with. Is it possible for malicious peer to circumvent the rules by listing arbitrary addresses in the INIT and INIT ACK? I'm asking since in the protocol implementation addresses must be verified before they can actually be used...

There's no further evaluation of the rules right now. The connection is trusted to add more addresses. It would probably be better to run pf_test_rule() again and create states that way. That'd run the ruleset against the new addresses.

In the end point we don't trust the peer. We assume the peer can report any addresses, in particular addresses it doesn't own to perform attacks. Therefore, the address verification was added (see RFC 9260. I think for a firewall, it is important to deal with this in an appropriate way.

  • evaluate rules for new connections within the association
  • SDT probe point for state creation failure
  • interpret INADDR_ANY as being the packet source address

By the way, I very much appreciate the feedback on these patches. It's very, very useful.

I don't know if you plan to go to any of the *BSD conferences, but you're owed several beverages.

This revision was not accepted when it landed; it landed in state Needs Review.Sep 7 2023, 5:05 PM
This revision was automatically updated to reflect the committed changes.