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