resolve #1
This commit is contained in:
504
draft-yukinet-cn86-registry-01
Normal file
504
draft-yukinet-cn86-registry-01
Normal file
@@ -0,0 +1,504 @@
|
||||
# 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」前缀。
|
||||
Reference in New Issue
Block a user