Files
draft-yukinet-cn86-registry/draft-yukinet-cn86-registry-01
2025-12-31 12:08:26 +08:00

504 lines
16 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CN86 号码资源注册数据库规范
_草案版本 01_
## 关于本文
本文是一份 CN86 规范草案。
本文尚未经过 CN86 社区的审议,不应作为规范使用。
关于此份草案的意见和建议,欢迎在 CN86 QQ 群提出。
## 维护者注册数据库
维护者应当通过 CN86 Gitea 平台创建维护者注册数据库,以取得 CN86 号码资源分配,并通过该数据库进行后续管理和维护。
维护者注册数据库的名称必须为 `.cn86registry`,并可通过其 Gitea 平台账号的命名空间(即 `git.cn86.dev/<username>/.cn86registry`)访问。
该仓库可见性应当设置为公有。
### `resources.yaml`
维护者注册数据库(`.cn86registry`)必须包含文件 `resources.yaml` 文件。
`resources.yaml` 文件应当符合 YAML 语法。下面给出 `resources.yaml` 文件的示例:
**`resources.yaml` 文件示例**
```yaml
auth:
- ssh-ed25519 AAA...
email: nic@cn86.dev
description: CN86 Network Information Center
qq: 10001
twitter: @elonmusk
bilibili: 36081646
activitypub:
- nic@mastodon.cn86.dev
- nic@misskey.cn86.dev
ipv4:
- address: 10.86.86.0/24
description: CN86 Anycast Network
nameservers: [ns1.dns.cn86, ns2.dns.cn86]
geofeed: https://geofeed.anycast.cn86/geofeed.csv
country: CN
subdivision: SH
iata: SHA
geolocation: 30.9176 121.9197
postal: 201308
domains:
- name: anycast.cn86
nameservers: [ns1.dns.cn86, ns2.dns.cn86]
- name: dns.cn86
nameservers:
- server: ns1.example.cn86
addresses: 10.86.86.53
- server: ns2.example.cn86
addresses:
- 10.86.86.54
- 10.86.86.55
```
#### `resources.yaml` 文件的字段
`resources.yaml` 文件的数据结构,参照下方给出的 TypeScript 定义:
```typescript
type ALPHA =
'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' |
'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' |
'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' |
'Y' | 'Z';
type DIGIT =
'0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' |
'8' | '9';
type ALPHADIGIT = ALPHA | DIGIT;
type IPv4Address = `${number}.${number}.${number}.${number}`;
type IPv6Address = string;
type CountryCode = `${ALPHA}${ALPHA}`;
type SubdivisionCode = `${ALPHADIGIT}${ALPHADIGIT}`;
type SSHPublicKey = `ssh-ed25519 ${string}` | `ssh-rsa ${string}` |
`ssh-ecdsa-nistp256 ${string}` |
`ssh-ecdsa-nistp384 ${string}` |
`ssh-ecdsa-nistp521 ${string}`;
type NonEmptyArray<T> = [T, ...T[]];
type OneOrMore<T> = T | NonEmptyArray<T>;
/**
* CN86 维护者注册数据库的 `resources.yaml` 文件数据结构
*/
type MaintainerRegistryEntry = Maintainer & MaintainerResources;
```
## 中心注册数据库
中心注册数据库的应当在 `cn86` 命名空间下,并命名为 `registry`。
中心注册数据库的应当可通过 `git.cn86.dev/cn86/registry` 命名空间访问。
中心注册数据库的应当使用下面的文件系统结构:
```
git.cn86.dev/cn86/registry/index.json
git.cn86.dev/cn86/registry/ipv4/<ipv4>.json
git.cn86.dev/cn86/registry/domains/<domain>.json
git.cn86.dev/cn86/registry/maintainers/<username>.json
```
### 中心注册数据库的对象定义
中心注册数据库的文件应当符合规范的 JSON 语法。其中对象的定义,参照以下 TypeScript 定义:
#### `index.json` 文件
```typescript
/**
* CN86 中心注册数据库的 `index.json` 索引文件结构
*/
interface CentralRegistryIndex {
type: "registry-index";
maintainers: string[];
ipv4: IPv4Address[];
domains: `${string}.cn86`[];
source: `CN86`;
}
```
#### `maintainers/<maintainer>.json` 文件
```typescript
/**
* CN86 中心注册数据库的基础数据结构
*/
interface CentralRegistryEntry<T extends
("maintainer" | "ipv4" | "domain")
> {
type: T;
maintainer: Maintainer;
source: `CN86`;
}
/**
* CN86 中心注册数据库的 `cn86/registry/maintainers/<maintainer>.json` 文件数据结构
*/
type CentralRegistryMaintainerEntry = Record<string,
Maintainer & CentralRegistryEntry<`maintainer`>>;
```
#### `ipv4/<ipv4>.json` 文件
```typescript
/**
* CN86 中心注册数据库的 `cn86/registry/ipv4/<ipv4>.json` 文件数据结构
*/
type CentralRegistryIPv4Entry = Record<`${IPv4Address}_${number}`,
IPv4Resource & CentralRegistryEntry<`ipv4`>>;
```
#### `domains/<domain>.json` 文件
```typescript
/**
* CN86 中心注册数据库的 `cn86/registry/domains/<domain>.json` 文件数据结构
*/
type CentralRegistryDomainEntry = Record<`${string}.cn86`,
DomainResource & CentralRegistryEntry<`domain`>>;
```
## 数据结构
前文提到的数据结构,参照下方给出的 TypeScript 定义。
### 基础架构
所有数据结构都可任意扩展,包括定义未在本文中说明或保留的字段。
```typescript
/**
* CN86 数据结构的基础架构
*/
interface ExtraFields {
/**
* **[可选]**
*
* 资源的其他属性,可自行定义。
*/
[key: string]: any;
}
```
### 维护者及其所有资源
```typescript
/**
* CN86 的资源维护者
*/
interface Maintainer extends ExtraFields {
/**
* **[必填][非空数组]**
*
* 维护者 SSH 公钥,用于身份认证。
*
* 可以是字符串,也可以是字符串数组。
*
* 至少填写一个。
*/
auth: OneOrMore<SSHPublicKey>;
/**
* **[可选]**
*
* 维护者的描述,可以为任意形式文本。
*/
description?: string;
/**
* **[必填][消费者应当 (SHALL) 实现]**
*
* 维护者的电子邮件,用于联系和身份认证。
*/
email: OneOrMore<`${string}@${string}`>;
/**
* **[可选][消费者可选 (OPTIONAL) 实现]**
*
* 维护者的 QQ。
*
* `number` 类型为 QQ 号。
*
* `string` 类型为 QID。
*/
qq?: OneOrMore<number | string>;
/**
* **[可选][消费者可选 (OPTIONAL) 实现]**
*
* 维护者的微信号。
*
* 可以填写手机号或微信号。
*/
wechat?: OneOrMore<number | string | `wxid_${string}`>;
/**
* **[可选][消费者可选 (OPTIONAL) 实现]**
*
* 维护者的 Telegram 账号,开头包含 `@`。
*
* 可以填写手机号或微信号。
*/
telegram?: OneOrMore<`@${string}`>;
/**
* **[可选][消费者可选 (OPTIONAL) 实现]**
*
* 维护者的 Twitter (X) 账号,开头包含 `@`。
*/
twitter?: OneOrMore<`@${string}`>;
/**
* **[可选][消费者可选 (OPTIONAL) 实现]**
*
* 维护者的 BlueSky 账号,开头包含 `@`。
*/
bluesky?: OneOrMore<`@${string}`>;
/**
* **[可选][消费者可选 (OPTIONAL) 实现]**
*
* 维护者的 ActivityPub 协议的联邦宇宙 (FediVerse) 社交媒体账号。格式为 `@{user}@{server}`。
*/
activitypub?: OneOrMore<`@${string}@${string}`>;
/**
* **[可选][消费者可选 (OPTIONAL) 实现]**
*
* 维护者的微博账号。
*
* `number` 类型为 URL 中的 UID。
*
* `@${string}` 类型为 `@` 开头的用户名。
*/
weibo?: OneOrMore<number | `@${string}`>;
/**
* **[可选][消费者可选 (OPTIONAL) 实现]**
*
* 维护者的抖音账号。
*/
douyin?: OneOrMore<string>;
/**
* **[可选][消费者可选 (OPTIONAL) 实现]**
*
* 维护者的 TikTok 账号。
*/
tiktok?: OneOrMore<string>;
/**
* **[可选][消费者可选 (OPTIONAL) 实现]**
*
* 维护者的哔哩哔哩账号。需要填写 UID。
*
* 注意 UID 的范围为 64 位无符号整数。
*/
bilibili?: OneOrMore<number>;
}
/**
* CN86 的资源维护者所拥有的资源
*/
interface MaintainerResources {
/**
* **[保留]**
*
* 维护者拥有的自治系统号资源。
*
* **保留以供未来使用,禁止自定义字段使用此名称。**
*/
asn: null | undefined
/**
* **[保留]**
*
* 维护者拥有的 E.164 (电话号码) 资源。
*
* **保留以供未来使用,禁止自定义字段使用此名称。**
*/
e164: null | undefined
/**
* **[必填][可为空数组]**
*
* 维护者拥有的 IPv4 资源。
*/
ipv4: IPv4Resource[];
/**
* **[保留]**
*
* 维护者拥有的 IPv6 资源。
*
* **保留以供未来使用,禁止自定义字段使用此名称。**
*/
ipv6: null | undefined
/**
* **[必填][可为空数组]**
*
* 维护者拥有的域名资源。
*/
domains: DomainResource[];
}
```
### IP 地址
```typescript
/**
* CN86 的 IPv4 资源
*/
interface IPv4Resource extends IPResource {
/**
* **[必填]**
*
* IPv4 资源的 CIDR 表示。
*/
address: `${IPv4Address}/${number}`;
}
/**
* CN86 IP 地址资源条目的通用字段
*/
interface IPResource extends ExtraFields {
/**
* **[可选]**
*
* IP 资源的描述,可以为任意形式文本。
*/
description?: string;
/**
* **[可选][消费者应当 (SHELL) 实现]**
*
* 如果填写空数组,视为未填写。
*
* IP 的反向解析名称服务器。
*/
nameservers?: string[];
/**
* **[必填][消费者必须 (MUST) 实现]**
*
* IP 地址的所属国家,格式为 [ISO 3166-1 Alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)
* 格式的国家代码。
*/
country: `${ALPHA}${ALPHA}`;
/**
* **[选填][消费者应当 (SHELL) 实现]**
*
* IP 地址的所属国家,格式为 [ISO 3166-2 Alpha-2](https://en.wikipedia.org/wiki/ISO_3166-2)
* 格式的国家代码。
*/
subdivision?: `${ALPHADIGIT}{ALPHADIGIT}`;
/**
* **[选填][消费者推荐 (RECOMMEND) 实现]**
*
* IP 地址的 Geofeed应当为指向一个 [RFC 8805](https://www.rfc-editor.org/rfc/rfc8805.html)
* 格式 CSV 的 URL。
*/
geofeed?: string;
/**
* **[可选][消费者推荐 (RECOMMEND) 实现]**
*
* IP 地址的位置坐标,格式为 `[纬度] [经度]`。
*/
geolocation?: `${number} ${number}`;
/**
* **[可选][消费者可选 (OPTIONAL) 实现]**
*
* IP 地址的邮政编码。
*/
postal?: `${number} ${number}`;
/**
* **[可选][消费者可选 (OPTIONAL) 实现]**
*
* IP 地址所属或附近机场(或港口)的 IATA 或 FAA 编码。
*/
iata?: `${ALPHADIGIT}${ALPHADIGIT}${ALPHADIGIT}`;
/**
* **[可选][消费者可选 (OPTIONAL) 实现]**
*
* IP 地址的 [梅登黑德网格](https://en.wikipedia.org/wiki/Maidenhead_Locator_System)。
*/
maidenhead?: `${number} ${number}`;
}
```
### 域名
```typescript
/**
* CN86 的域名资源
*/
interface DomainResource extends ExtraFields {
/**
* **[必填]**
*
* CN86 顶级(一级)域下的的二级域名资源名称。
*/
domain: `${string}.cn86`;
/**
* **[可选]**
*
* 域名资源描述,可以为任意形式文本。
*/
description?: string;
/**
* **[必填][非空数组]**
*
* 域名资源的权威解析服务器。
*
* 应 (SHOULD) 填写 CN86 域名组成的数组,或 Glue 记录数据结构组成的数组。
*
* 若有 Glue 记录Glue 记录的地址也应指向 CN86 IP 地址。
*
* 消费者可选 (OPTIONAL) 实现通过公网域名解析。
*
* 至少填写一个。
*/
nameservers: NonEmptyArray<string | {
server: string;
addresses?: OneOrMore<IPv4Address | IPv6Address>;
}>;
}
```
## 聚合代理
### 聚合代理的行为
聚合代理应当在维护者注册数据库创建、更新和删除时,执行下文所述的聚合流程。
聚合代理也应当定期执行下文所述的聚合流程。
### 聚合代理的聚合流程
1. 聚合代理通过 Gitea 平台提供的 API 列举所有维护者注册数据库 (`.cn86registry` 仓库),并按本文所述规范,读取并解析仓库中的注册数据库文件。
2. 聚合代理对相关文件进行 YAML 解析和字段格式验证。
- 如果遇到错误,聚合代理应使用 Email、Gitea Issue 或其他方式通知用户。
- 聚合代理应进行状态管理,对于关于同一注册数据库文件,只向同一用户通知一次。
- 聚合代理应该能包容单个维护者或单个文件的错误,并继续处理其他维护者或同一维护者的其他文件。
3. 聚合代理检查新增号码资源是否和已有号码资源冲突。
- 如果遭遇错误,聚合代理应通过 Gitea Issue、电子邮件等方式向试图新增该号码资源的用户发送通知。
- 对于号码资源主键的修改,聚合代理应该视为删除已存在资源,和新增号码资源两个操作。
- 聚合代理不应向已有号码资源的维护者发送通知。
- 聚合代理应进行状态管理,对于关于同一冲突资源,向同一用户只通知一次。
- 聚合代理应该能号码资源冲突,处理冲突后应能继续聚合流程。
4. 聚合代理对号码资源的修改和删除进行身份验证。
- 对于已存在的号码资源,聚合代理应当拒绝非其维护者发起的修改或删除操作。
- 聚合代理应当基于 Gitea 平台的唯一 ID而非用户名进行身份认证的判断。
- 对于失败的身份验证,聚合代理应分别向已存在资源的维护者,和试图修改或删除资源的维护者,通过 Email、Gitea Issue 或其他方式通知用户。
5. 聚合代理按照本文所述的文件系统和数据结构,应用中心注册数据库的更新。
## 术语表
本文中使用的「必须 (MUST)」、「不得 (MUST NOT)」、「必需 (REQUIRED)」、「应当 (SHALL)」、「不应当 (SHALL NOT)」、「应 (SHOULD)」、「不应 (SHOULD NOT)」、「建议 (RECOMMENDED)」、「不建议 (NOT RECOMMENDED)」、「可 (MAY)」、「可选 (OPTIONAL)」词汇,应按照 [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) 中给出的定义解释。
本文定义了以下术语:
- **号码资源**:用于网际互联和路由的标识符。在 CN86 中,特指由 CN86 分配和管理,用于 CN86 参与者网络间互联和路由的 IPv4 地址和 `.cn86` 域。
- **Gitea 平台**:在 git.cn86.dev 上提供服务,以供 CN86 参与者管理和维护网络资源和其他元信息的 Gitea 应用。
- **维护者**:在 CN86 Gitea 平台注册,以本文所述方式,对 CN86 网络号码资源进行管理和维护的 CN86 参与者。
- **聚合代理**:通过访问维护者注册数据库,实现特定的完整性和一致性检查、权限控制、信息存取机制,以实现对 CN86 号码资源管理维护,并产生维护者注册数据库的数据处理程序。
- **注册数据库**:通过 CN86 Gitea 平台上的数据存取,实现对 CN86 号码资源进行管理和维护的 Git 仓库。
- **中心注册数据库**:由 CN86 所有,包含所有由 CN86 已分配的号码资源信息,并通过聚合代理以自动化方式管理的注册数据库。
- **维护者注册数据库**:由维护者所有,仅包含维护者取得分配的号码资源信息,并由维护者自行管理的注册数据库。
本文中所定义的术语在不引起歧义的情况下均可省略「CN86」前缀。