1 // SPDX-License-Identifier: LGPL-2.1+
2 // Copyright (C) 2023 Andre Heider <a.heider@gmail.com>
5 #include <netinet/in.h>
6 #include <sys/socket.h>
12 #include <libubox/blobmsg.h>
13 #include <libubox/blobmsg_json.h>
17 #include <rpcd/plugin.h>
19 #include "wireguard.h"
21 static struct blob_buf buf
;
28 static const struct blobmsg_policy rpc_privatekey_policy
[__RPC_PK_MAX
] = {
29 [RPC_PK_DEVICE
] = { .name
= "private", .type
= BLOBMSG_TYPE_STRING
},
32 static void rpc_wireguard_add_endpoint(const wg_endpoint
*endpoint
)
34 char host
[1025]; // NI_MAXHOST
35 char serv
[32]; // NI_MAXSERV
36 char res
[sizeof(host
) + sizeof(serv
) + 4];
39 memset(res
, 0, sizeof(res
));
40 if (endpoint
->addr
.sa_family
== AF_INET
)
41 addr_len
= sizeof(struct sockaddr_in
);
42 else if (endpoint
->addr
.sa_family
== AF_INET6
)
43 addr_len
= sizeof(struct sockaddr_in6
);
47 if (getnameinfo(&endpoint
->addr
, addr_len
, host
, sizeof(host
), serv
, sizeof(serv
),
48 NI_DGRAM
| NI_NUMERICHOST
| NI_NUMERICSERV
))
51 if (endpoint
->addr
.sa_family
== AF_INET6
&& strchr(host
, ':'))
52 snprintf(res
, sizeof(res
), "[%s]:%s", host
, serv
);
54 snprintf(res
, sizeof(res
), "%s:%s", host
, serv
);
55 res
[sizeof(res
) - 1] = 0;
57 blobmsg_add_string(&buf
, "endpoint", res
);
60 static void rpc_wireguard_add_allowedip(const wg_allowedip
*allowedip
)
62 char res
[INET6_ADDRSTRLEN
+ 4 + 1];
64 memset(res
, 0, sizeof(res
));
65 if (allowedip
->family
== AF_INET
)
66 inet_ntop(AF_INET
, &allowedip
->ip4
, res
, INET6_ADDRSTRLEN
);
67 else if (allowedip
->family
== AF_INET6
)
68 inet_ntop(AF_INET6
, &allowedip
->ip6
, res
, INET6_ADDRSTRLEN
);
75 sprintf(res
+ strlen(res
), "/%u", allowedip
->cidr
);
76 res
[sizeof(res
) - 1] = 0;
78 blobmsg_add_string(&buf
, NULL
, res
);
81 static void rpc_wireguard_add_peer(const wg_peer
*peer
)
84 struct wg_allowedip
*allowedip
;
86 rpc_wireguard_add_endpoint(&peer
->endpoint
);
88 c
= blobmsg_open_array(&buf
, "allowed_ips");
89 wg_for_each_allowedip(peer
, allowedip
)
90 rpc_wireguard_add_allowedip(allowedip
);
91 blobmsg_close_array(&buf
, c
);
93 blobmsg_add_u64(&buf
, "last_handshake", peer
->last_handshake_time
.tv_sec
);
94 blobmsg_add_u64(&buf
, "rx_bytes", peer
->rx_bytes
);
95 blobmsg_add_u64(&buf
, "tx_bytes", peer
->tx_bytes
);
96 if (peer
->persistent_keepalive_interval
)
97 blobmsg_add_u16(&buf
, "persistent_keepalive_interval", peer
->persistent_keepalive_interval
);
100 static void rpc_wireguard_add_device(const wg_device
*device
)
104 wg_key_b64_string key
;
106 blobmsg_add_u32(&buf
, "ifindex", device
->ifindex
);
108 if (device
->flags
& WGDEVICE_HAS_PUBLIC_KEY
) {
109 wg_key_to_base64(key
, device
->public_key
);
110 blobmsg_add_string(&buf
, "public_key", key
);
113 if (device
->listen_port
)
114 blobmsg_add_u16(&buf
, "listen_port", device
->listen_port
);
117 blobmsg_add_u32(&buf
, "fwmark", device
->fwmark
);
119 c
= blobmsg_open_table(&buf
, "peers");
120 wg_for_each_peer(device
, peer
) {
121 wg_key_to_base64(key
, peer
->public_key
);
122 d
= blobmsg_open_table(&buf
, key
);
123 rpc_wireguard_add_peer(peer
);
124 blobmsg_close_table(&buf
, d
);
126 blobmsg_close_table(&buf
, c
);
129 static int rpc_wireguard_status(struct ubus_context
*ctx
, struct ubus_object
*obj
,
130 struct ubus_request_data
*req
, const char *method
, struct blob_attr
*msg
)
133 char *device_names
, *device_name
;
136 device_names
= wg_list_device_names();
138 return UBUS_STATUS_NOT_FOUND
;
140 blob_buf_init(&buf
, 0);
142 wg_for_each_device_name(device_names
, device_name
, len
) {
145 if (wg_get_device(&device
, device_name
) < 0)
148 c
= blobmsg_open_table(&buf
, device_name
);
149 rpc_wireguard_add_device(device
);
150 blobmsg_close_table(&buf
, c
);
152 wg_free_device(device
);
157 ubus_send_reply(ctx
, req
, buf
.head
);
159 return UBUS_STATUS_OK
;
162 static int rpc_wireguard_genkey(struct ubus_context
*ctx
, struct ubus_object
*obj
,
163 struct ubus_request_data
*req
, const char *method
, struct blob_attr
*msg
)
165 wg_key private_key
, public_key
;
166 wg_key_b64_string key
;
168 wg_generate_private_key(private_key
);
169 wg_generate_public_key(public_key
, private_key
);
171 blob_buf_init(&buf
, 0);
172 wg_key_to_base64(key
, private_key
);
173 blobmsg_add_string(&buf
, "private", key
);
174 wg_key_to_base64(key
, public_key
);
175 blobmsg_add_string(&buf
, "public", key
);
176 ubus_send_reply(ctx
, req
, buf
.head
);
178 return UBUS_STATUS_OK
;
181 static int rpc_wireguard_genpsk(struct ubus_context
*ctx
, struct ubus_object
*obj
,
182 struct ubus_request_data
*req
, const char *method
, struct blob_attr
*msg
)
184 wg_key preshared_key
;
185 wg_key_b64_string key
;
187 wg_generate_preshared_key(preshared_key
);
189 blob_buf_init(&buf
, 0);
190 wg_key_to_base64(key
, preshared_key
);
191 blobmsg_add_string(&buf
, "preshared", key
);
192 ubus_send_reply(ctx
, req
, buf
.head
);
194 return UBUS_STATUS_OK
;
197 static int rpc_wireguard_pubkey(struct ubus_context
*ctx
, struct ubus_object
*obj
,
198 struct ubus_request_data
*req
, const char *method
, struct blob_attr
*msg
)
200 static struct blob_attr
*tb
[__RPC_PK_MAX
];
201 wg_key_b64_string key
;
202 wg_key private_key
, public_key
;
204 blobmsg_parse(rpc_privatekey_policy
, __RPC_PK_MAX
, tb
, blob_data(msg
), blob_len(msg
));
206 if (!tb
[RPC_PK_DEVICE
])
207 return UBUS_STATUS_INVALID_ARGUMENT
;
209 if (wg_key_from_base64(private_key
, blobmsg_get_string(tb
[RPC_PK_DEVICE
])))
210 return UBUS_STATUS_INVALID_ARGUMENT
;
212 wg_generate_public_key(public_key
, private_key
);
213 blob_buf_init(&buf
, 0);
214 wg_key_to_base64(key
, public_key
);
215 blobmsg_add_string(&buf
, "public", key
);
216 ubus_send_reply(ctx
, req
, buf
.head
);
218 return UBUS_STATUS_OK
;
221 static int rpc_wireguard_api_init(const struct rpc_daemon_ops
*ops
, struct ubus_context
*ctx
)
223 static const struct ubus_method wireguard_methods
[] = {
224 UBUS_METHOD_NOARG("status", rpc_wireguard_status
),
225 UBUS_METHOD_NOARG("genkey", rpc_wireguard_genkey
),
226 UBUS_METHOD_NOARG("genpsk", rpc_wireguard_genpsk
),
227 UBUS_METHOD("pubkey", rpc_wireguard_pubkey
, rpc_privatekey_policy
),
230 static struct ubus_object_type wireguard_type
=
231 UBUS_OBJECT_TYPE("rpcd-plugin-wireguard", wireguard_methods
);
233 static struct ubus_object obj
= {
235 .type
= &wireguard_type
,
236 .methods
= wireguard_methods
,
237 .n_methods
= ARRAY_SIZE(wireguard_methods
),
240 return ubus_add_object(ctx
, &obj
);
243 struct rpc_plugin rpc_plugin
= {
244 .init
= rpc_wireguard_api_init