| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#include "easyxs/easyxs.h" |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
#include "wireguard.h" |
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
#define PERL_NS "Linux::WireGuard" |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
#define IPV4_STRLEN sizeof( ((struct sockaddr_in*) NULL)->sin_addr.s_addr) |
|
8
|
|
|
|
|
|
|
#define IPV6_STRLEN sizeof( ((struct sockaddr_in6*) NULL)->sin6_addr) |
|
9
|
|
|
|
|
|
|
|
|
10
|
0
|
|
|
|
|
|
static HV* _wgallowedip_to_hv (pTHX_ wg_allowedip* allowedip) { |
|
11
|
0
|
|
|
|
|
|
HV* ip_hv = newHV(); |
|
12
|
|
|
|
|
|
|
|
|
13
|
0
|
|
|
|
|
|
hv_stores(ip_hv, "family", newSVuv(allowedip->family)); |
|
14
|
|
|
|
|
|
|
|
|
15
|
0
|
|
|
|
|
|
SV* addr_sv = NULL; |
|
16
|
|
|
|
|
|
|
|
|
17
|
0
|
|
|
|
|
|
switch (allowedip->family) { |
|
18
|
|
|
|
|
|
|
case AF_INET: |
|
19
|
0
|
|
|
|
|
|
addr_sv = newSVpvn((char*) &allowedip->ip4.s_addr, IPV4_STRLEN); |
|
20
|
0
|
|
|
|
|
|
break; |
|
21
|
|
|
|
|
|
|
case AF_INET6: |
|
22
|
0
|
|
|
|
|
|
addr_sv = newSVpvn((char*) &allowedip->ip6.s6_addr, IPV6_STRLEN); |
|
23
|
0
|
|
|
|
|
|
break; |
|
24
|
|
|
|
|
|
|
default: |
|
25
|
|
|
|
|
|
|
assert(0); |
|
26
|
|
|
|
|
|
|
} |
|
27
|
|
|
|
|
|
|
|
|
28
|
0
|
|
|
|
|
|
hv_stores(ip_hv, "addr", addr_sv); |
|
29
|
0
|
|
|
|
|
|
hv_stores(ip_hv, "cidr", newSVuv(allowedip->cidr)); |
|
30
|
|
|
|
|
|
|
|
|
31
|
0
|
|
|
|
|
|
return ip_hv; |
|
32
|
|
|
|
|
|
|
} |
|
33
|
|
|
|
|
|
|
|
|
34
|
0
|
|
|
|
|
|
static HV* _wgpeer_to_hv (pTHX_ wg_peer *peer) { |
|
35
|
|
|
|
|
|
|
wg_allowedip* allowedip; |
|
36
|
|
|
|
|
|
|
|
|
37
|
0
|
|
|
|
|
|
HV* hv = newHV(); |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
// hv_stores(hv, "flags", newSViv(peer->flags)); |
|
40
|
|
|
|
|
|
|
|
|
41
|
0
|
0
|
|
|
|
|
hv_stores(hv, "public_key", (peer->flags & WGPEER_HAS_PUBLIC_KEY) ? newSVpvn((char*) peer->public_key, sizeof(peer->public_key)) : &PL_sv_undef); |
|
42
|
0
|
0
|
|
|
|
|
hv_stores(hv, "preshared_key", (peer->flags & WGPEER_HAS_PRESHARED_KEY) ? newSVpvn( (char*) peer->preshared_key, sizeof(peer->preshared_key)) : &PL_sv_undef); |
|
43
|
|
|
|
|
|
|
|
|
44
|
0
|
|
|
|
|
|
unsigned endpoint_len = 0; |
|
45
|
0
|
|
|
|
|
|
switch (peer->endpoint.addr.sa_family) { |
|
46
|
|
|
|
|
|
|
case 0: |
|
47
|
0
|
|
|
|
|
|
break; |
|
48
|
|
|
|
|
|
|
case AF_INET: |
|
49
|
0
|
|
|
|
|
|
endpoint_len = sizeof(struct sockaddr_in); |
|
50
|
0
|
|
|
|
|
|
break; |
|
51
|
|
|
|
|
|
|
case AF_INET6: |
|
52
|
0
|
|
|
|
|
|
endpoint_len = sizeof(struct sockaddr_in6); |
|
53
|
0
|
|
|
|
|
|
break; |
|
54
|
|
|
|
|
|
|
default: |
|
55
|
|
|
|
|
|
|
assert(0); |
|
56
|
|
|
|
|
|
|
} |
|
57
|
|
|
|
|
|
|
|
|
58
|
0
|
0
|
|
|
|
|
hv_stores(hv, "endpoint", endpoint_len ? newSVpvn((char*) &peer->endpoint, endpoint_len) : &PL_sv_undef); |
|
59
|
|
|
|
|
|
|
|
|
60
|
0
|
|
|
|
|
|
hv_stores(hv, "rx_bytes", newSVuv(peer->rx_bytes)); |
|
61
|
0
|
|
|
|
|
|
hv_stores(hv, "tx_bytes", newSVuv(peer->tx_bytes)); |
|
62
|
0
|
0
|
|
|
|
|
hv_stores(hv, "persistent_keepalive_interval", (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL) ? newSVuv(peer->persistent_keepalive_interval) : &PL_sv_undef); |
|
63
|
|
|
|
|
|
|
|
|
64
|
0
|
|
|
|
|
|
hv_stores(hv, "last_handshake_time_sec", newSViv(peer->last_handshake_time.tv_sec)); |
|
65
|
0
|
|
|
|
|
|
hv_stores(hv, "last_handshake_time_nsec", newSViv(peer->last_handshake_time.tv_nsec)); |
|
66
|
|
|
|
|
|
|
|
|
67
|
0
|
|
|
|
|
|
AV* allowed_ips = newAV(); |
|
68
|
0
|
|
|
|
|
|
hv_stores(hv, "allowed_ips", newRV_noinc((SV*) allowed_ips)); |
|
69
|
|
|
|
|
|
|
|
|
70
|
0
|
0
|
|
|
|
|
wg_for_each_allowedip(peer, allowedip) { |
|
71
|
0
|
|
|
|
|
|
HV* ip_hv = _wgallowedip_to_hv(aTHX_ allowedip); |
|
72
|
0
|
|
|
|
|
|
av_push(allowed_ips, newRV_noinc((SV*)ip_hv)); |
|
73
|
|
|
|
|
|
|
} |
|
74
|
|
|
|
|
|
|
|
|
75
|
0
|
|
|
|
|
|
return hv; |
|
76
|
|
|
|
|
|
|
} |
|
77
|
|
|
|
|
|
|
|
|
78
|
0
|
|
|
|
|
|
static HV* _wgdev_to_hv (pTHX_ wg_device *dev) { |
|
79
|
|
|
|
|
|
|
wg_peer *peer; |
|
80
|
|
|
|
|
|
|
|
|
81
|
0
|
|
|
|
|
|
HV* dev_hv = newHV(); |
|
82
|
|
|
|
|
|
|
|
|
83
|
0
|
|
|
|
|
|
hv_stores(dev_hv, "name", newSVpv(dev->name, 0)); |
|
84
|
0
|
|
|
|
|
|
hv_stores(dev_hv, "ifindex", newSVuv(dev->ifindex)); |
|
85
|
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
// hv_stores(dev_hv, "flags", newSViv(dev->flags)); |
|
87
|
|
|
|
|
|
|
|
|
88
|
0
|
0
|
|
|
|
|
hv_stores(dev_hv, "public_key", dev->flags & WGDEVICE_HAS_PUBLIC_KEY ? newSVpvn((char*) dev->public_key, sizeof(dev->public_key)) : &PL_sv_undef); |
|
89
|
0
|
0
|
|
|
|
|
hv_stores(dev_hv, "private_key", dev->flags & WGDEVICE_HAS_PRIVATE_KEY ? newSVpvn((char*) dev->private_key, sizeof(dev->private_key)) : &PL_sv_undef); |
|
90
|
|
|
|
|
|
|
|
|
91
|
0
|
0
|
|
|
|
|
hv_stores(dev_hv, "fwmark", dev->flags & WGDEVICE_HAS_FWMARK ? newSVuv(dev->fwmark) : &PL_sv_undef); |
|
92
|
0
|
0
|
|
|
|
|
hv_stores(dev_hv, "listen_port", dev->flags & WGDEVICE_HAS_LISTEN_PORT ? newSVuv(dev->listen_port) : &PL_sv_undef); |
|
93
|
|
|
|
|
|
|
|
|
94
|
0
|
|
|
|
|
|
AV* peers = newAV(); |
|
95
|
0
|
|
|
|
|
|
hv_stores(dev_hv, "peers", newRV_noinc((SV*) peers)); |
|
96
|
|
|
|
|
|
|
|
|
97
|
0
|
0
|
|
|
|
|
wg_for_each_peer(dev, peer) { |
|
98
|
0
|
|
|
|
|
|
HV* peer_hv = _wgpeer_to_hv(aTHX_ peer); |
|
99
|
0
|
|
|
|
|
|
av_push(peers, newRV_noinc((SV*) peer_hv)); |
|
100
|
|
|
|
|
|
|
} |
|
101
|
|
|
|
|
|
|
|
|
102
|
0
|
|
|
|
|
|
return dev_hv; |
|
103
|
|
|
|
|
|
|
} |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
// Doesn’t seem to be useful: |
|
106
|
|
|
|
|
|
|
#define _LWG_CREATE_CONST_UV(ns, theconst) \ |
|
107
|
|
|
|
|
|
|
newCONSTSUB(gv_stashpv(ns, 0), #theconst, newSVuv(theconst)); |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
// ---------------------------------------------------------------------- |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
MODULE = Linux::WireGuard PACKAGE = Linux::WireGuard |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
PROTOTYPES: DISABLE |
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
void |
|
116
|
|
|
|
|
|
|
list_device_names() |
|
117
|
|
|
|
|
|
|
PPCODE: |
|
118
|
|
|
|
|
|
|
char *device_names, *device_name; |
|
119
|
|
|
|
|
|
|
size_t len; |
|
120
|
|
|
|
|
|
|
|
|
121
|
1
|
|
|
|
|
|
device_names = wg_list_device_names(); |
|
122
|
1
|
50
|
|
|
|
|
if (!device_names) { |
|
123
|
0
|
|
|
|
|
|
croak("Failed to retrieve device names: %s", strerror(errno)); |
|
124
|
|
|
|
|
|
|
} |
|
125
|
|
|
|
|
|
|
|
|
126
|
1
|
|
|
|
|
|
unsigned count=0; |
|
127
|
|
|
|
|
|
|
|
|
128
|
1
|
50
|
|
|
|
|
wg_for_each_device_name(device_names, device_name, len) { |
|
129
|
0
|
|
|
|
|
|
count++; |
|
130
|
0
|
0
|
|
|
|
|
mXPUSHp(device_name, len); |
|
131
|
|
|
|
|
|
|
} |
|
132
|
|
|
|
|
|
|
|
|
133
|
1
|
|
|
|
|
|
free(device_names); |
|
134
|
|
|
|
|
|
|
|
|
135
|
1
|
|
|
|
|
|
XSRETURN(count); |
|
136
|
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
SV* |
|
138
|
|
|
|
|
|
|
get_device (SV* name_sv) |
|
139
|
|
|
|
|
|
|
CODE: |
|
140
|
|
|
|
|
|
|
wg_device *dev; |
|
141
|
|
|
|
|
|
|
|
|
142
|
0
|
|
|
|
|
|
const char* devname = exs_SvPVbyte_nolen(name_sv); |
|
143
|
|
|
|
|
|
|
|
|
144
|
0
|
0
|
|
|
|
|
if (wg_get_device(&dev, devname) < 0) { |
|
145
|
0
|
|
|
|
|
|
croak("Failed to retrieve device `%s`: %s", devname, strerror(errno)); |
|
146
|
|
|
|
|
|
|
} |
|
147
|
|
|
|
|
|
|
|
|
148
|
0
|
|
|
|
|
|
HV* dev_hv = _wgdev_to_hv(aTHX_ dev); |
|
149
|
|
|
|
|
|
|
|
|
150
|
0
|
|
|
|
|
|
wg_free_device(dev); |
|
151
|
|
|
|
|
|
|
|
|
152
|
0
|
|
|
|
|
|
RETVAL = newRV_noinc((SV*) dev_hv); |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
OUTPUT: |
|
155
|
|
|
|
|
|
|
RETVAL |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
void |
|
158
|
|
|
|
|
|
|
add_device (SV* name_sv) |
|
159
|
|
|
|
|
|
|
ALIAS: |
|
160
|
|
|
|
|
|
|
del_device = 1 |
|
161
|
|
|
|
|
|
|
CODE: |
|
162
|
2
|
|
|
|
|
|
const char* devname = exs_SvPVbyte_nolen(name_sv); |
|
163
|
|
|
|
|
|
|
|
|
164
|
2
|
50
|
|
|
|
|
int result = ix ? wg_del_device(devname) : wg_add_device(devname); |
|
165
|
2
|
50
|
|
|
|
|
if (result) { |
|
166
|
2
|
50
|
|
|
|
|
croak("Failed to %s device `%s`: %s", ix ? "delete" : "add", devname, strerror(errno)); |
|
167
|
|
|
|
|
|
|
} |
|
168
|
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
SV* |
|
170
|
|
|
|
|
|
|
generate_private_key() |
|
171
|
|
|
|
|
|
|
ALIAS: |
|
172
|
|
|
|
|
|
|
generate_preshared_key = 1 |
|
173
|
|
|
|
|
|
|
CODE: |
|
174
|
|
|
|
|
|
|
wg_key key; |
|
175
|
|
|
|
|
|
|
|
|
176
|
4
|
100
|
|
|
|
|
if (ix) { |
|
177
|
2
|
|
|
|
|
|
wg_generate_preshared_key(key); |
|
178
|
|
|
|
|
|
|
} |
|
179
|
|
|
|
|
|
|
else { |
|
180
|
2
|
|
|
|
|
|
wg_generate_private_key(key); |
|
181
|
|
|
|
|
|
|
} |
|
182
|
|
|
|
|
|
|
|
|
183
|
4
|
|
|
|
|
|
RETVAL = newSVpv((char*) key, sizeof(wg_key)); |
|
184
|
|
|
|
|
|
|
OUTPUT: |
|
185
|
|
|
|
|
|
|
RETVAL |
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
SV* |
|
188
|
|
|
|
|
|
|
generate_public_key(SV* private_key_sv) |
|
189
|
|
|
|
|
|
|
CODE: |
|
190
|
|
|
|
|
|
|
wg_key public_key; |
|
191
|
|
|
|
|
|
|
|
|
192
|
2
|
50
|
|
|
|
|
if (SvROK(private_key_sv)) { |
|
193
|
0
|
|
|
|
|
|
croak("Reference is nonsensical here!"); |
|
194
|
|
|
|
|
|
|
} |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
STRLEN keylen; |
|
197
|
2
|
50
|
|
|
|
|
const char* private_key_char = SvPVbyte(private_key_sv, keylen); |
|
198
|
|
|
|
|
|
|
|
|
199
|
2
|
50
|
|
|
|
|
if (keylen != sizeof(wg_key)) { |
|
200
|
0
|
|
|
|
|
|
croak("Key must be exactly %lu characters, not %lu!", sizeof(wg_key), keylen); |
|
201
|
|
|
|
|
|
|
} |
|
202
|
|
|
|
|
|
|
|
|
203
|
2
|
|
|
|
|
|
wg_generate_public_key(public_key, (const void*) private_key_char); |
|
204
|
|
|
|
|
|
|
|
|
205
|
2
|
|
|
|
|
|
RETVAL = newSVpv((char*) public_key, sizeof(wg_key)); |
|
206
|
|
|
|
|
|
|
OUTPUT: |
|
207
|
|
|
|
|
|
|
RETVAL |