reality: реклама reality-параметров сокетов через BGP и применение к исходящим TCP-линкам
This commit is contained in:
1 parent
edb3bb36e1
commit
898a0a4a66
13 files changed
+615
-22
No files matched your search
@@ -54,6 +54,26 @@ static void free_v4_sub_list(struct memory_pool* pool, struct TOPO_SUBNET4* head
|
||||
static void free_v6_sub_list(struct memory_pool* pool, struct TOPO_SUBNET6* head) {
|
||||
while (head) { struct TOPO_SUBNET6* next = head->next; memory_pool_free(pool, head); head = next; }
|
||||
}
|
||||
static void free_reality_sock_list(struct TOPO_REALITY_SOCK* head) {
|
||||
while (head) { struct TOPO_REALITY_SOCK* next = head->next; u_free(head); head = next; }
|
||||
}
|
||||
|
||||
const struct TOPO_REALITY_SOCK* topo_node_find_reality_sock(const struct TOPO_NODE* ni, uint8_t socket_id) {
|
||||
if (!ni) return NULL;
|
||||
for (const struct TOPO_REALITY_SOCK* r = ni->reality_socks; r; r = r->next)
|
||||
if (r->socket_id == socket_id) return r;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void topo_node_apply_reality(struct ETCP_LINK* link, const struct TOPO_REALITY_SOCK* rs) {
|
||||
if (!link || !rs) return;
|
||||
memcpy(link->reality.server_static_pubkey, rs->server_pubkey, REALITY_AUTH_KEY_SIZE);
|
||||
memcpy(link->reality.short_id, rs->short_id, REALITY_SHORT_ID_SIZE);
|
||||
memcpy(link->reality.version, rs->version, REALITY_VERSION_SIZE);
|
||||
snprintf(link->reality.server_name, sizeof(link->reality.server_name), "%s", rs->server_name);
|
||||
link->reality.fingerprint = REALITY_FP_CHROME;
|
||||
link->reality_set = 1;
|
||||
}
|
||||
|
||||
/* Упорядоченное сравнение списков адресов/мета (порядок обхода сокетов детерминирован,
|
||||
prepend даёт одинаковый порядок при неизменном наборе сокетов). */
|
||||
@@ -87,6 +107,17 @@ static int addr6_list_equal(struct TOPO_ADDR6* a, struct TOPO_ADDR6* b) {
|
||||
}
|
||||
return a == NULL && b == NULL;
|
||||
}
|
||||
static int reality_sock_list_equal(struct TOPO_REALITY_SOCK* a, struct TOPO_REALITY_SOCK* b) {
|
||||
while (a && b) {
|
||||
if (a->socket_id != b->socket_id ||
|
||||
memcmp(a->short_id, b->short_id, 8) != 0 ||
|
||||
memcmp(a->server_pubkey, b->server_pubkey, 32) != 0 ||
|
||||
memcmp(a->version, b->version, 3) != 0 ||
|
||||
strncmp(a->server_name, b->server_name, TOPO_REALITY_SNAME_MAX) != 0) return 0;
|
||||
a = a->next; b = b->next;
|
||||
}
|
||||
return a == NULL && b == NULL;
|
||||
}
|
||||
|
||||
/* извлекает hop_list из лучшего живого path в nq->paths (или любого, если живых нет).
|
||||
память принадлежит TOPO_NODEPATH в paths, не освобождать */
|
||||
@@ -109,6 +140,7 @@ void topo_node_free_raw(struct TOPO_GROUPS* groups, struct TOPO_NODE* ni) {
|
||||
free_v6_sock_list(groups->v6_sock_meta_pool, ni->v6_sock_meta);
|
||||
free_v6_addr_list(groups->v6_addr_pool, ni->v6_addrs);
|
||||
}
|
||||
free_reality_sock_list(ni->reality_socks);
|
||||
u_free(ni->node_name);
|
||||
u_free(ni);
|
||||
}
|
||||
@@ -125,8 +157,10 @@ void topo_nodeq_free_group_fields(struct TOPO_GROUPS* groups, struct TOPO_GROUP_
|
||||
free_v4_addr_list(groups->v4_addr_pool, ni->v4_addrs);
|
||||
free_v6_sock_list(groups->v6_sock_meta_pool, ni->v6_sock_meta);
|
||||
free_v6_addr_list(groups->v6_addr_pool, ni->v6_addrs);
|
||||
free_reality_sock_list(ni->reality_socks);
|
||||
ni->v4_sock_meta = NULL; ni->v4_addrs = NULL;
|
||||
ni->v6_sock_meta = NULL; ni->v6_addrs = NULL;
|
||||
ni->reality_socks = NULL;
|
||||
topo_node_registry_unref(groups, nq->node_id);
|
||||
}
|
||||
if (nq->subnets) {
|
||||
@@ -164,6 +198,7 @@ struct TOPO_NODE* topo_node_registry_store(struct TOPO_GROUPS* groups, struct TO
|
||||
topo_node_ref(existing);
|
||||
if (!existing->v4_addrs && ni->v4_addrs) { existing->v4_addrs = ni->v4_addrs; ni->v4_addrs = NULL; }
|
||||
if (!existing->v6_addrs && ni->v6_addrs) { existing->v6_addrs = ni->v6_addrs; ni->v6_addrs = NULL; }
|
||||
if (!existing->reality_socks && ni->reality_socks) { existing->reality_socks = ni->reality_socks; ni->reality_socks = NULL; }
|
||||
topo_node_free_raw(groups, ni);
|
||||
return existing;
|
||||
}
|
||||
@@ -235,6 +270,17 @@ int topo_node_build_sig_msg(struct TOPO_NODE* ni, uint8_t* buf, size_t buf_size)
|
||||
buf[off++] = (uint8_t)(e->port & 0xFF); buf[off++] = (uint8_t)((e->port >> 8) & 0xFF);
|
||||
buf[off++] = e->type; buf[off++] = e->socket_id; buf[off++] = e->protocol; e = e->next;
|
||||
}}
|
||||
{ struct TOPO_REALITY_SOCK* e = ni->reality_socks; while (e) {
|
||||
size_t nlen = strnlen(e->server_name, TOPO_REALITY_SNAME_MAX);
|
||||
if (off + 1 + 8 + 32 + 3 + nlen + 1 > buf_size) return -1;
|
||||
buf[off++] = e->socket_id;
|
||||
memcpy(buf + off, e->short_id, 8); off += 8;
|
||||
memcpy(buf + off, e->server_pubkey, 32); off += 32;
|
||||
memcpy(buf + off, e->version, 3); off += 3;
|
||||
if (nlen) { memcpy(buf + off, e->server_name, nlen); off += nlen; }
|
||||
buf[off++] = '\0';
|
||||
e = e->next;
|
||||
}}
|
||||
|
||||
return (int)off;
|
||||
}
|
||||
@@ -253,6 +299,7 @@ int topo_node_dyn_size(const struct TOPOMSG_NODE* msg) {
|
||||
+ msg->local_v4_addrs * sizeof(struct TOPOMSG_ADDR4)
|
||||
+ msg->local_v6_sockets * sizeof(struct TOPOMSG_SOCKMETA6)
|
||||
+ msg->local_v6_addrs * sizeof(struct TOPOMSG_ADDR6)
|
||||
+ msg->local_reality_socks * sizeof(struct TOPOMSG_REALITY_SOCK)
|
||||
+ ((msg->flags & TOPO_FLAG_SEND_SUBNETS)
|
||||
? (msg->local_v4_subnets * sizeof(struct TOPOMSG_SUBNET4) + msg->local_v6_subnets * sizeof(struct TOPOMSG_SUBNET6))
|
||||
: 0)
|
||||
@@ -278,6 +325,7 @@ int topo_node_serialize(struct TOPO_NODE* ni, struct TOPO_GROUP_NODE* nq,
|
||||
msg.local_v4_addrs = topo_list_count((struct _topo_head*)ni->v4_addrs);
|
||||
msg.local_v6_sockets = topo_list_count((struct _topo_head*)ni->v6_sock_meta);
|
||||
msg.local_v6_addrs = topo_list_count((struct _topo_head*)ni->v6_addrs);
|
||||
msg.local_reality_socks = topo_list_count((struct _topo_head*)ni->reality_socks);
|
||||
msg.local_v4_subnets = nq->subnets ? topo_list_count((struct _topo_head*)nq->subnets->v4_subnets) : 0;
|
||||
msg.local_v6_subnets = nq->subnets ? topo_list_count((struct _topo_head*)nq->subnets->v6_subnets) : 0;
|
||||
{ uint8_t hc; uint64_t* hl = topo_node_best_hop_list(nq, &hc, NULL);
|
||||
@@ -310,6 +358,15 @@ int topo_node_serialize(struct TOPO_NODE* ni, struct TOPO_GROUP_NODE* nq,
|
||||
struct TOPOMSG_ADDR6 w = { .port=e->port, .type=e->type, .socket_id=e->socket_id, .protocol=e->protocol };
|
||||
memcpy(w.addr, e->addr, 16); memcpy(dp, &w, sizeof(w)); dp += sizeof(w); e = e->next;
|
||||
}}
|
||||
{ struct TOPO_REALITY_SOCK* e = ni->reality_socks; while (e) {
|
||||
struct TOPOMSG_REALITY_SOCK w; memset(&w, 0, sizeof(w));
|
||||
w.socket_id = e->socket_id;
|
||||
memcpy(w.short_id, e->short_id, 8);
|
||||
memcpy(w.server_pubkey, e->server_pubkey, 32);
|
||||
memcpy(w.version, e->version, 3);
|
||||
memcpy(w.server_name, e->server_name, TOPO_REALITY_SNAME_MAX);
|
||||
memcpy(dp, &w, sizeof(w)); dp += sizeof(w); e = e->next;
|
||||
}}
|
||||
if (msg.flags & TOPO_FLAG_SEND_SUBNETS) {
|
||||
if (nq->subnets) {
|
||||
{ struct TOPO_SUBNET4* e = nq->subnets->v4_subnets; while (e) {
|
||||
@@ -393,6 +450,21 @@ int topo_node_deserialize(struct TOPO_GROUP* group, const uint8_t* data, size_t
|
||||
if (!head) head = tail = e; else { tail->next = e; tail = e; }
|
||||
}
|
||||
ni->v6_addrs = head; }
|
||||
{ struct TOPO_REALITY_SOCK* head = NULL; struct TOPO_REALITY_SOCK* tail = NULL;
|
||||
for (int i = 0; i < msg->local_reality_socks; i++) {
|
||||
const struct TOPOMSG_REALITY_SOCK* w = (const struct TOPOMSG_REALITY_SOCK*)dp; dp += sizeof(*w);
|
||||
struct TOPO_REALITY_SOCK* e = u_calloc(1, sizeof(struct TOPO_REALITY_SOCK));
|
||||
if (!e) { topo_node_free_raw(group->instance->topo_groups, ni); return -1; }
|
||||
e->socket_id = w->socket_id;
|
||||
memcpy(e->short_id, w->short_id, 8);
|
||||
memcpy(e->server_pubkey, w->server_pubkey, 32);
|
||||
memcpy(e->version, w->version, 3);
|
||||
memcpy(e->server_name, w->server_name, TOPO_REALITY_SNAME_MAX);
|
||||
e->server_name[TOPO_REALITY_SNAME_MAX - 1] = 0;
|
||||
e->next = NULL;
|
||||
if (!head) head = tail = e; else { tail->next = e; tail = e; }
|
||||
}
|
||||
ni->reality_socks = head; }
|
||||
|
||||
if (out_subnets && (msg->flags & TOPO_FLAG_SEND_SUBNETS) && (msg->local_v4_subnets || msg->local_v6_subnets)) {
|
||||
struct TOPO_NODESUBNETS* r = u_calloc(1, sizeof(struct TOPO_NODESUBNETS));
|
||||
@@ -818,6 +890,23 @@ int topo_node_update_my_addresses(struct UTUN_INSTANCE* instance) {
|
||||
struct TOPO_ADDR4* v4_head = NULL;
|
||||
struct TOPO_SOCKMETA6* m6_head = NULL;
|
||||
struct TOPO_ADDR6* v6_head = NULL;
|
||||
struct TOPO_REALITY_SOCK* r_head = NULL;
|
||||
|
||||
/* node-global reality-параметры (одинаковы для всех reality-сокетов): рекламируем первый short_id */
|
||||
uint8_t r_short_id[8], r_pubkey[32], r_version[3]; char r_sname[TOPO_REALITY_SNAME_MAX];
|
||||
uint8_t r_valid = 0;
|
||||
{ const struct reality_config* rc = &instance->config->global.reality;
|
||||
if (rc->enabled && rc->has_private_key) {
|
||||
if (reality_pubkey_from_priv(rc->private_key, r_pubkey) == REALITY_OK) {
|
||||
if (rc->short_id_count > 0) memcpy(r_short_id, rc->short_ids[0], 8);
|
||||
else memcpy(r_short_id, rc->short_id, 8);
|
||||
memcpy(r_version, rc->version, 3);
|
||||
memset(r_sname, 0, sizeof(r_sname));
|
||||
strncpy(r_sname, rc->server_name, sizeof(r_sname) - 1);
|
||||
r_valid = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ETCP_SOCKET* e_sock = instance->etcp_sockets;
|
||||
while (e_sock) {
|
||||
@@ -879,18 +968,32 @@ int topo_node_update_my_addresses(struct UTUN_INSTANCE* instance) {
|
||||
a6->type = TOPO_ADDR_INTERFACE; a6->socket_id = ts->sock_id; a6->protocol = TOPO_PROTO_TCP;
|
||||
a6->next = v6_head; v6_head = a6; }
|
||||
}
|
||||
if (r_valid && ts->reality_enabled) {
|
||||
struct TOPO_REALITY_SOCK* r = u_calloc(1, sizeof(struct TOPO_REALITY_SOCK));
|
||||
if (!r) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "reality_sock alloc failed"); }
|
||||
else {
|
||||
r->socket_id = ts->sock_id;
|
||||
memcpy(r->short_id, r_short_id, 8);
|
||||
memcpy(r->server_pubkey, r_pubkey, 32);
|
||||
memcpy(r->version, r_version, 3);
|
||||
memcpy(r->server_name, r_sname, TOPO_REALITY_SNAME_MAX);
|
||||
r->next = r_head; r_head = r;
|
||||
}
|
||||
}
|
||||
ts = ts->next; }
|
||||
}
|
||||
|
||||
/* Без изменений — подпись/рассылку гасим, но БД всё равно синхронизируем:
|
||||
она могла быть не готова (или пуста) при предыдущем вызове. */
|
||||
int changed = !(sockmeta4_list_equal(ni->v4_sock_meta, m4_head) && addr4_list_equal(ni->v4_addrs, v4_head) &&
|
||||
sockmeta6_list_equal(ni->v6_sock_meta, m6_head) && addr6_list_equal(ni->v6_addrs, v6_head));
|
||||
sockmeta6_list_equal(ni->v6_sock_meta, m6_head) && addr6_list_equal(ni->v6_addrs, v6_head) &&
|
||||
reality_sock_list_equal(ni->reality_socks, r_head));
|
||||
if (changed) {
|
||||
free_v4_sock_list(instance->topo_groups->v4_sock_meta_pool, ni->v4_sock_meta); ni->v4_sock_meta = m4_head;
|
||||
free_v4_addr_list(instance->topo_groups->v4_addr_pool, ni->v4_addrs); ni->v4_addrs = v4_head;
|
||||
free_v6_sock_list(instance->topo_groups->v6_sock_meta_pool, ni->v6_sock_meta); ni->v6_sock_meta = m6_head;
|
||||
free_v6_addr_list(instance->topo_groups->v6_addr_pool, ni->v6_addrs); ni->v6_addrs = v6_head;
|
||||
free_reality_sock_list(ni->reality_socks); ni->reality_socks = r_head;
|
||||
ni->ver = (ni->ver % 255) + 1;
|
||||
topo_node_sign_self(instance, ni);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "my addresses updated, new ver=%d", ni->ver);
|
||||
@@ -899,6 +1002,7 @@ int topo_node_update_my_addresses(struct UTUN_INSTANCE* instance) {
|
||||
free_v4_addr_list(instance->topo_groups->v4_addr_pool, v4_head);
|
||||
free_v6_sock_list(instance->topo_groups->v6_sock_meta_pool, m6_head);
|
||||
free_v6_addr_list(instance->topo_groups->v6_addr_pool, v6_head);
|
||||
free_reality_sock_list(r_head);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "my addresses unchanged (ver=%d), persist DB", ni->ver);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user