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

Support of RFC9164 Semantic Tags for IP Addresses/Prefixes #232

Open
1 task done
kc2rxo opened this issue Apr 16, 2024 · 2 comments
Open
1 task done

Support of RFC9164 Semantic Tags for IP Addresses/Prefixes #232

kc2rxo opened this issue Apr 16, 2024 · 2 comments

Comments

@kc2rxo
Copy link

kc2rxo commented Apr 16, 2024

Things to check first

  • I have searched the existing issues and didn't find my feature already requested there

Feature description

RFC9164 changes the semantic tags for IP Addresses and prefixes. See the RFC for specific details.

TLDR: Instead of 260 and 261 there is now semantic tags 52 (for IPv4) and 54 (for IPv6). Each tag supports a combination of full address and prefix forms. The originals are deprecated.

Use case

IANA has, per RFC9164, marked the original semantic tags as deprecated in favor of the RFC9164 tags.

While I am unsure of how much these new tags are used in the wild, I am currently proposing their use in various documents for the Drone Remote ID Protocol (DRIP). For some examples see this document, Section 9 and Appendix A.

@agronholm
Copy link
Owner

I think these new tags are a perfect fit for the ipaddress module.

@kc2rxo
Copy link
Author

kc2rxo commented Apr 22, 2024

I've done a little bit of work on this, just to see how this could be done before integration and have come up with the following code:

import cbor2
import ipaddress

ip4a = ipaddress.IPv4Address("192.0.2.1")
ip4n = ipaddress.IPv4Network("192.0.2.0/24")
ip4n_pl = ip4n.prefixlen
ip4n_addr = ip4n.network_address.packed[:int(ip4n_pl / 8)]

ip4_addr = cbor2.CBORTag(52, ip4a.packed)
ip4_pfix = cbor2.CBORTag(52, [ip4n_pl, ip4n_addr])
ip4_iface = cbor2.CBORTag(52, [ip4a.packed, 24, 'eth0'])

print(ip4_addr)
print(ip4_pfix)
print(ip4_iface)

ip6a = ipaddress.IPv6Address("2001:0db8:1234:deed:beef:cafe:face:feed")
ip6n = ipaddress.IPv6Network("2001:db8:1234::/48")
ip6n_pl = ip6n.prefixlen
ip6n_addr = ip6n.network_address.packed[:int(ip6n_pl / 8)]

ip6_addr = cbor2.CBORTag(54, ip6a.packed)
ip6_pfix = cbor2.CBORTag(54, [ip6n_pl, ip6n_addr])
ip6_iface = cbor2.CBORTag(54, [ip6a.packed, 56, 'eth1'])

print(ip6_addr)
print(ip6_pfix)
print(ip6_iface)

It should be worth noting that the interface (ipX_iface) definition the zone element (final element) can be either a string, integer or not present at all. The order of the array elements dictates the form you are encoding/decoding.

On the topic of the optional zone identifier, how would this be handled? It looks like the scope_id of ipaddress.IPv6Address is what would be expected but I have never seen or used this function before. The ipaddress documentation doesn't even mention it for IPv4Address. Perhaps it could be ignored for now and only the address and prefix forms of RFC9164 are supported?

To match the examples in RFC9164 I had to extract the address manually from the CIDR notation and perform a slice of the packed address to remove excess value not required in CBOR, thus resulting in the ipX_addr values. This is probably bad practice but I do not see a clean way to get the value required from ipaddress objects.

Obviously the CBORTag's above would be used in a call of encode_semantic() resulting in the desired bytes for the new tags.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants