1
1
/*
2
2
* Copyright (C) 2017 Lubomir Rintel
3
- *
4
- * Copyright (C) 2013-2020 Tobias Brunner
3
+ * Copyright (C) 2013-2023 Tobias Brunner
5
4
* Copyright (C) 2008-2009 Martin Willi
6
5
*
7
6
* This program is free software; you can redistribute it and/or modify it
15
14
* for more details.
16
15
*/
17
16
17
+ #include <stdio.h>
18
+ #include <inttypes.h>
19
+ #include <net/if.h>
20
+
18
21
#include "nm_service.h"
19
22
20
23
#include <daemon.h>
23
26
#include <config/peer_cfg.h>
24
27
#include <credentials/certificates/x509.h>
25
28
#include <networking/tun_device.h>
29
+ #include <plugins/kernel_netlink/kernel_netlink_xfrmi.h>
26
30
27
- #include <stdio.h>
31
+ #define XFRMI_DEFAULT_MTU 1400
28
32
29
33
/**
30
34
* Private data of NMStrongswanPlugin
@@ -40,7 +44,13 @@ typedef struct {
40
44
nm_creds_t * creds ;
41
45
/* attribute handler for DNS/NBNS server information */
42
46
nm_handler_t * handler ;
43
- /* dummy TUN device */
47
+ /* manager for XFRM interfaces, if supported */
48
+ kernel_netlink_xfrmi_t * xfrmi_manager ;
49
+ /* interface ID of XFRM interface */
50
+ uint32_t xfrmi_id ;
51
+ /* name of XFRM interface if one is used */
52
+ char * xfrmi ;
53
+ /* dummy TUN device if not using XFRM interface */
44
54
tun_device_t * tun ;
45
55
/* name of the connection */
46
56
char * name ;
@@ -107,6 +117,24 @@ static GVariant* handler_to_variant(nm_handler_t *handler, char *variant_type,
107
117
return g_variant_builder_end (& builder );
108
118
}
109
119
120
+ /**
121
+ * Destroy any allocated XFRM or TUN interface
122
+ */
123
+ static void delete_interface (NMStrongswanPluginPrivate * priv )
124
+ {
125
+ if (priv -> xfrmi )
126
+ {
127
+ priv -> xfrmi_manager -> delete (priv -> xfrmi_manager , priv -> xfrmi );
128
+ free (priv -> xfrmi );
129
+ priv -> xfrmi = NULL ;
130
+ }
131
+ if (priv -> tun )
132
+ {
133
+ priv -> tun -> destroy (priv -> tun );
134
+ priv -> tun = NULL ;
135
+ }
136
+ }
137
+
110
138
/**
111
139
* Signal IP config to NM, set connection as established
112
140
*/
@@ -127,27 +155,53 @@ static void signal_ip_config(NMVpnServicePlugin *plugin,
127
155
128
156
handler = priv -> handler ;
129
157
130
- /* NM apparently requires to know the gateway */
158
+ /* NM apparently requires to know the gateway (it uses it to install a
159
+ * direct route via physical interface if conflicting routes are passed) */
131
160
other = ike_sa -> get_other_host (ike_sa );
132
161
g_variant_builder_add (& builder , "{sv}" , NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY ,
133
162
host_to_variant (other ));
134
163
135
164
/* systemd-resolved requires a device to properly install DNS servers, but
136
- * Netkey does not use one. Passing the physical interface is not ideal,
165
+ * Netkey does not require one. Passing the physical interface is not ideal,
137
166
* as NM fiddles around with it and systemd-resolved likes a separate
138
- * device. So we pass a dummy TUN device along for NM etc. to play with...
167
+ * device. So we pass either an XFRM interface or a dummy TUN device along
168
+ * for NM etc. to play with...
139
169
*/
140
- DESTROY_IF (priv -> tun );
141
- priv -> tun = tun_device_create (NULL );
142
- if (priv -> tun )
170
+ delete_interface (priv );
171
+ if (priv -> xfrmi_manager && priv -> xfrmi_id )
172
+ {
173
+ char name [IFNAMSIZ ];
174
+ int mtu ;
175
+
176
+ /* use the interface ID to get a unique name, fine if it's cut off */
177
+ snprintf (name , sizeof (name ), "nm-xfrm-%" PRIu32 , priv -> xfrmi_id );
178
+ mtu = lib -> settings -> get_int (lib -> settings , "charon-nm.mtu" ,
179
+ XFRMI_DEFAULT_MTU );
180
+
181
+ if (priv -> xfrmi_manager -> create (priv -> xfrmi_manager , name ,
182
+ priv -> xfrmi_id , NULL , mtu ))
183
+ {
184
+ priv -> xfrmi = strdup (name );
185
+ }
186
+ }
187
+ if (!priv -> xfrmi )
188
+ {
189
+ priv -> tun = tun_device_create (NULL );
190
+ }
191
+ if (priv -> xfrmi )
192
+ {
193
+ g_variant_builder_add (& builder , "{sv}" , NM_VPN_PLUGIN_CONFIG_TUNDEV ,
194
+ g_variant_new_string (priv -> xfrmi ));
195
+ }
196
+ else if (priv -> tun )
143
197
{
144
198
g_variant_builder_add (& builder , "{sv}" , NM_VPN_PLUGIN_CONFIG_TUNDEV ,
145
199
g_variant_new_string (priv -> tun -> get_name (priv -> tun )));
146
200
}
147
201
else
148
202
{
149
- DBG1 (DBG_CFG , "failed to create dummy TUN device, might affect DNS "
150
- "server installation negatively" );
203
+ DBG1 (DBG_CFG , "failed to create XFRM or dummy TUN device, might affect "
204
+ "DNS server installation negatively" );
151
205
}
152
206
153
207
/* pass the first virtual IPs we got or use the physical IP */
@@ -191,18 +245,16 @@ static void signal_ip_config(NMVpnServicePlugin *plugin,
191
245
host_to_variant (vip4 ));
192
246
g_variant_builder_add (& ip4builder , "{sv}" , NM_VPN_PLUGIN_IP4_CONFIG_PREFIX ,
193
247
g_variant_new_uint32 (vip4 -> get_address (vip4 ).len * 8 ));
194
-
195
- /* prevent NM from changing the default route. we set our own route in our
196
- * own routing table
197
- */
198
- g_variant_builder_add (& ip4builder , "{sv}" , NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT ,
199
- g_variant_new_boolean (TRUE));
200
-
201
248
g_variant_builder_add (& ip4builder , "{sv}" , NM_VPN_PLUGIN_IP4_CONFIG_DNS ,
202
249
handler_to_variant (handler , "au" , INTERNAL_IP4_DNS ));
203
-
204
250
g_variant_builder_add (& ip4builder , "{sv}" , NM_VPN_PLUGIN_IP4_CONFIG_NBNS ,
205
251
handler_to_variant (handler , "au" , INTERNAL_IP4_NBNS ));
252
+
253
+ /* prevent NM from changing the default route, as we set our own routes
254
+ * in a separate routing table
255
+ */
256
+ g_variant_builder_add (& ip4builder , "{sv}" , NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT ,
257
+ g_variant_new_boolean (TRUE));
206
258
}
207
259
208
260
if (vip6 )
@@ -211,11 +263,12 @@ static void signal_ip_config(NMVpnServicePlugin *plugin,
211
263
host_to_variant (vip6 ));
212
264
g_variant_builder_add (& ip6builder , "{sv}" , NM_VPN_PLUGIN_IP6_CONFIG_PREFIX ,
213
265
g_variant_new_uint32 (vip6 -> get_address (vip6 ).len * 8 ));
214
- g_variant_builder_add (& ip6builder , "{sv}" , NM_VPN_PLUGIN_IP6_CONFIG_NEVER_DEFAULT ,
215
- g_variant_new_boolean (TRUE));
216
266
g_variant_builder_add (& ip6builder , "{sv}" , NM_VPN_PLUGIN_IP6_CONFIG_DNS ,
217
267
handler_to_variant (handler , "aay" , INTERNAL_IP6_DNS ));
218
268
/* NM_VPN_PLUGIN_IP6_CONFIG_NBNS is not defined */
269
+
270
+ g_variant_builder_add (& ip6builder , "{sv}" , NM_VPN_PLUGIN_IP6_CONFIG_NEVER_DEFAULT ,
271
+ g_variant_new_boolean (TRUE));
219
272
}
220
273
221
274
ip4config = g_variant_builder_end (& ip4builder );
@@ -653,6 +706,11 @@ static gboolean connect_(NMVpnServicePlugin *plugin, NMConnection *connection,
653
706
NM_TYPE_SETTING_CONNECTION ));
654
707
vpn = NM_SETTING_VPN (nm_connection_get_setting (connection ,
655
708
NM_TYPE_SETTING_VPN ));
709
+ if (priv -> xfrmi_manager )
710
+ {
711
+ /* allocate a random interface ID */
712
+ priv -> xfrmi_id = random ();
713
+ }
656
714
if (priv -> name )
657
715
{
658
716
free (priv -> name );
@@ -1020,12 +1078,8 @@ static gboolean do_disconnect(gpointer plugin)
1020
1078
* secrets from earlier connections) before we clear them in connect() */
1021
1079
priv -> creds -> clear (priv -> creds );
1022
1080
1023
- /* delete the dummy TUN device */
1024
- if (priv -> tun )
1025
- {
1026
- priv -> tun -> destroy (priv -> tun );
1027
- priv -> tun = NULL ;
1028
- }
1081
+ /* delete any allocated interface */
1082
+ delete_interface (priv );
1029
1083
return FALSE;
1030
1084
}
1031
1085
@@ -1057,8 +1111,7 @@ static void nm_strongswan_plugin_init(NMStrongswanPlugin *plugin)
1057
1111
priv -> listener .ike_reestablish_pre = _ike_reestablish_pre ;
1058
1112
priv -> listener .ike_reestablish_post = _ike_reestablish_post ;
1059
1113
charon -> bus -> add_listener (charon -> bus , & priv -> listener );
1060
- priv -> tun = NULL ;
1061
- priv -> name = NULL ;
1114
+ priv -> xfrmi_manager = lib -> get (lib , KERNEL_NETLINK_XFRMI_MANAGER );
1062
1115
}
1063
1116
1064
1117
/**
@@ -1071,11 +1124,7 @@ static void nm_strongswan_plugin_dispose(GObject *obj)
1071
1124
1072
1125
plugin = NM_STRONGSWAN_PLUGIN (obj );
1073
1126
priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE (plugin );
1074
- if (priv -> tun )
1075
- {
1076
- priv -> tun -> destroy (priv -> tun );
1077
- priv -> tun = NULL ;
1078
- }
1127
+ delete_interface (priv );
1079
1128
G_OBJECT_CLASS (nm_strongswan_plugin_parent_class )-> dispose (obj );
1080
1129
}
1081
1130
0 commit comments