Overview
I2P lacks a centralized DNS system. However, the address book, together with the b32 hostname system, allows the router to look up full destinations and fetch lease sets, which contain a list of gateways and keys so that clients may connect to that destination.
So, leasesets are somewhat like a DNS record. But there is currently no facility to find out if that host supports any services, either on that destination or a different one, in a manner similar to DNS SRV records [SRV] [RFC2782].
The first application for this may be peer-to-peer email. Other possible applications: DNS, GNS, key servers, certificate authorities, time servers, bittorrent, cryptocurrencies, other peer-to-peer applications.
Design
Service records are placed in the (currently unused) options section in LS2 [LS2]. Not supported for LS1.
To lookup a service address for a specific hostname or b32, the router fetches the leaseset and looks up the service record in the properties.
The service may be hosted on the same destination as the LS itself, or may reference a different hostname/b32.
If the target destination for the service is different, the target LS must also include a service record, pointing to itself, indicating that it supports the service.
The design does not require special support or caching or any changes in the floodfills. Only the leaseset publisher, and the client looking up a service record, must support these changes.
Specification
LS2 Option Specification
Defined as follows:
- serviceoption := optionkey optionvalue
- optionkey := _service._proto
- service := The symbolic name of the desired service. Must be lower case. Example: "smtp". Allowed chars are [a-z0-9-] and must not start or end with a '-'. Standard identifiers from [REGISTRY] or Linux /etc/services must be used if defined there.
- proto := The transport protocol of the desired service. Must be lower case, either "tcp" or "udp". "tcp" means streaming and "udp" means repliable datagrams. Protocol indicators for raw datagrams and datagram2 may be defined later. Allowed chars are [a-z0-9-] and must not start or end with a '-'.
- optionvalue := self | srvrecord[,srvrecord]*
- self := "0" ttl port [appoptions]
- srvrecord := "1" ttl priority weight port target [appoptions]
- ttl := time to live, integer seconds. Positive integer. Example: "86400". A minimum of 86400 (one day) is recommended, see Recommendations section below for details.
- priority := The priority of the target host, lower value means more preferred. Non-negative integer. Example: "0" Only useful if more than one record, but required even if just one record.
- weight := A relative weight for records with the same priority. Higher value means more chance of getting picked. Non-negative integer. Example: "0" Only useful if more than one record, but required even if just one record.
- port := The I2CP port on which the service is to be found. Non-negative integer. Example: "25" Port 0 is supported but not recommended.
- target := The hostname or b32 of the destination providing the service. A valid hostname as in [NAMING]. Must be lower case. Example: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.b32.i2p" or "example.i2p". b32 is recommended unless the hostname is "well known", i.e. in official or default address books.
- appoptions := arbitrary text specific to the application, must not contain " " or ",". Encoding is UTF-8.
Examples
In LS2 for aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.b32.i2p, pointing to two SMTP servers:
"_smtp._tcp" "1 86400 0 0 25 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.b32.i2p,86400 1 0 25 cccccccccccccccccccccccccccccccccccccccccccc.b32.i2p"
In LS2 for bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.b32.i2p, pointing to itself as a SMTP server:
"_smtp._tcp" "0 999999 25"
Possible format for redirecting email (see below):
"_smtp._tcp" "1 86400 0 0 25 smtp.postman.i2p example@mail.i2p"
Limits
The Mapping data structure format used for LS2 options limits keys and values to 255 bytes (not chars) max. With a b32 target, the optionvalue is about 67 bytes, so only 3 records would fit. Maybe only one or two with a long appoptions field, or up to four or five with a short hostname. This should be sufficient; multiple records should be rare.
Differences from [RFC2782]
- No trailing dots
- No name after the proto
- Lower case required
- In text format with comma-separated records, not binary DNS format
- Different record type indicators
- Additional appoptions field
Notes
No wildcarding such as (asterisk), (asterisk)._tcp, or _tcp is allowed. Each supported service must have its own record.
Service Name Registry
Non-standard identifiers that are not listed in [REGISTRY] or Linux /etc/services may be requested and added to the common structures specification [LS2].
Service-specific appoptions formats may also be added there.
I2CP Specification
The [I2CP] protocol may need to be extended to support service lookups; or, maybe, just do a lookup for "_service._proto.xxx.b32.i2p" and the router figures it out. But no way to pass ttl and port back without changes. See Recommendations section below.
Additional MessageStatusMessage and/or HostReplyMessage error codes related to service lookup may be required and must be added to the [I2CP] document.
Configuration is implementation-dependent. We may define standard I2CP options for i2ptunnel and SAM, to be documented in [I2CP-OPTIONS].
TODO
SAM Specification
The [SAMv3] protocol may need to be extended to support service lookups; or, maybe, just do a lookup for "_service._proto.xxx.b32.i2p" and the router figures it out. But no way to pass ttl and port back without changes. See Recommendations section below.
TODO
Naming Specification
Update [NAMING] to specify handling of hostnames starting with '_', as documented in the implementation section below.
Recommendations
It may be difficult and low-priority for us to design and implement the I2CP and SAM changes necessary to pass through the TTL and port information to the client. If those are unavailable to the application, it should assume a TTL of 86400 (one day) and use the standard internet port (e.g. 25 for SMTP) as the I2CP port.
Servers should specify a TTL of at least 86400, and the standard port for the application.
Advanced Features
Recursive Lookups
It may be desirable to support recursive lookups, where each successive leaseset is checked for a service record pointing to another leaseset, DNS-style. This is probably not necessary, at least in an initial implementation.
TODO
Application-specific fields
It may be desirable to have application-specific data in the service record. For example, the operator of example.i2p may wish to indicate that email should be forwarded to example@mail.i2p. The "example@" part would need to be in a separate field of the service record, or stripped from the target.
Even if the operator runs his own email service, he may wish to indicate that email should be sent to example@example.i2p. Most I2P services are run by a single person. So a separate field may be helpful here as well.
TODO how to do this in a generic way
Changes required for Email
Out of the scope of this proposal. See [DOTWELLKNOWN] for a discussion.
Implementation Notes
Caching of service records up to the TTL may be done by the router or the application, implementation-dependent. Whether to cache persistently is also implementation-dependent.
Configuration is implementation-dependent. We may define standard I2CP options for i2ptunnel and SAM, to be documented in [I2CP-OPTIONS].
Naming service subsystems must check for a leading "_", strip off the first two labels, look up the leaseset for the remaining part of the hostname, and then lookup the two labels in the options field of the leaseset.
Lookups must also lookup the target leaseset and verify it contains a "self" record before returning the target destination to the client.
Security Analysis
As the leaseset is signed, any service records within it are authenticated by the signing key of the destination.
The service records are public and visible to floodfills, unless the leaseset is encrypted. Any router requesting the leaseset will be able to see the service records.
A SRV record other than "self" (i.e., one that points to a different hostname/b32 target) does not require the consent of the targeted hostname/b32. It's not clear if a redirection of a service to an arbitrary destination could facilitate some sort of attack, or what the purpose of such an attack would be. However, this proposal mitigates such an attack by requiring that the target also publish a "self" SRV record. Implementers must check for a "self" record in the leaseset of the target.
Compatibility
No issues. All known implementations currently ignore the options field in LS2, and correctly skip over a non-empty options field. This was verified in recent testing by both Java I2P and i2pd. LS2 was implemented in 0.9.38 in 2016 and is well-supported by all router implementations.
The design does not require special support or caching or any changes in the floodfills.
'_' is not a valid character in i2p hostnames.
Migration
Implementations may add support at any time, no coordination is needed.
References
[DOTWELLKNOWN] | (1, 2) http://i2pforum.i2p/viewtopic.php?p=3102 |
[I2CP] | (1, 2) http://i2p.net/spec/i2cp |
[I2CP-OPTIONS] | (1, 2) http://i2p.net/en/docs/protocol/i2cp |
[LS2] | (1, 2) http://i2p.net/spec/common-structures |
[GNS] | http://zzz.i2p/topcs/1545 |
[NAMING] | (1, 2) http://i2p.net/en/docs/naming |
[Prop123] | http://i2p.net/spec/proposals/123-new-netdb-entries |
[REGISTRY] | (1, 2) http://www.dns-sd.org/ServiceTypes.html |
[RFC2782] | (1, 2) https://datatracker.ietf.org/doc/html/rfc2782 |
[SAMv3] | /en/docs/api/samv3 |
[SRV] | https://en.wikipedia.org/wiki/SRV_record |