1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
*/
#include "unetd.h"
static const struct wg_ops *wg_get_ops(struct network *net)
{
if (wg_user_ops.check(net))
return &wg_user_ops;
#ifdef linux
return &wg_linux_ops;
#else
return NULL;
#endif
}
int wg_init_network(struct network *net)
{
net->wg.ops = wg_get_ops(net);
if (!net->wg.ops)
return -1;
return net->wg.ops->init(net);
}
void wg_cleanup_network(struct network *net)
{
if (net->wg.ops)
net->wg.ops->cleanup(net);
}
static void
wg_peer_set_connected(struct network *net, struct network_peer *peer, bool val)
{
if (peer->state.connected == val)
return;
peer->state.connected = val;
network_services_peer_update(net, peer);
}
int wg_peer_refresh(struct network *net)
{
struct network_peer *peer;
vlist_for_each_element(&net->peers, peer, node) {
if (peer->indirect)
continue;
peer->state.handshake = false;
peer->state.idle++;
if (peer->state.ping_wait > 0)
peer->state.ping_wait--;
if (peer->state.idle >= 2 * net->net_config.keepalive)
wg_peer_set_connected(net, peer, false);
if (peer->state.idle > net->net_config.keepalive)
network_pex_event(net, peer, PEX_EV_PING);
}
return net->wg.ops->peer_refresh(net);
}
struct network_peer *wg_peer_update_start(struct network *net, const uint8_t *key)
{
struct network_peer *peer;
peer = vlist_find(&net->peers, key, peer, node);
if (!peer || peer->indirect)
return NULL;
return peer;
}
void wg_peer_update_done(struct network *net, struct network_peer *peer)
{
if (!peer->state.handshake)
return;
peer->state.handshake = false;
network_pex_event(net, peer, PEX_EV_HANDSHAKE);
}
void wg_peer_set_last_handshake(struct network *net, struct network_peer *peer,
uint64_t now, uint64_t sec)
{
peer->state.last_handshake_diff = now - sec;
if (sec == peer->state.last_handshake)
return;
peer->state.handshake = true;
peer->state.last_handshake = sec;
sec = now - sec;
if (sec <= net->net_config.keepalive) {
if (peer->state.idle > sec)
peer->state.idle = sec;
wg_peer_set_connected(net, peer, true);
}
}
void wg_peer_set_rx_bytes(struct network *net, struct network_peer *peer,
uint64_t bytes)
{
int64_t diff = bytes - peer->state.rx_bytes;
bool first = !peer->state.has_rx_bytes;
peer->state.has_rx_bytes = true;
peer->state.rx_bytes = bytes;
if (first)
return;
if (diff > 0) {
peer->state.idle = 0;
wg_peer_set_connected(net, peer, true);
}
}
void wg_peer_set_tx_bytes(struct network *net, struct network_peer *peer,
uint64_t bytes)
{
peer->state.tx_bytes = bytes;
}
void wg_peer_set_endpoint(struct network *net, struct network_peer *peer,
void *data, size_t len)
{
if (len > sizeof(peer->state.endpoint))
return;
if (!memcmp(&peer->state.endpoint, data, len))
return;
memset(&peer->state.endpoint, 0, sizeof(peer->state.endpoint));
memcpy(&peer->state.endpoint, data, len);
network_pex_event(net, peer, PEX_EV_ENDPOINT_CHANGE);
}
|