OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * L2TP/IPsec VPN plugin. | |
3 * | |
4 * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. | |
5 * Use of this source code is governed by a BSD-style license that can be | |
6 * found in the LICENSE file. | |
7 * | |
8 */ | |
9 | |
10 #ifdef HAVE_CONFIG_H | |
11 #include <config.h> | |
12 #endif | |
13 | |
14 #include <string.h> | |
15 #include <errno.h> | |
16 #include <unistd.h> | |
17 #include <sys/types.h> | |
18 #include <sys/stat.h> | |
19 #include <fcntl.h> | |
20 | |
21 #include <stdio.h> | |
22 #include <net/if.h> | |
23 | |
24 #include <glib.h> | |
25 | |
26 #define CONNMAN_API_SUBJECT_TO_CHANGE | |
27 #include <connman/plugin.h> | |
28 #include <connman/provider.h> | |
29 #include <connman/log.h> | |
30 #include <connman/task.h> | |
31 #include <connman/dbus.h> | |
32 #include <connman/inet.h> | |
33 | |
34 #include "vpn.h" | |
35 | |
36 #define _DBG_VPN(fmt, arg...) DBG(DBG_VPN, fmt, ## arg) | |
37 | |
38 static DBusConnection *connection; | |
39 | |
40 static DBusMessage *li_get_sec(struct connman_task *task, | |
41 DBusMessage *msg, void *user_data) | |
42 { | |
43 const char *user, *passwd; | |
44 struct connman_provider *provider = user_data; | |
45 | |
46 DBG(DBG_VPN, "li_get_sec: security request"); | |
47 | |
48 if (dbus_message_get_no_reply(msg) == FALSE) { | |
49 DBusMessage *reply; | |
50 | |
51 user = connman_provider_get_string(provider, "L2TPIPsec.User"); | |
52 passwd = connman_provider_get_string(provider, | |
53 "L2TPIPsec.Password"); | |
54 | |
55 if (user == NULL || strlen(user) == 0 || | |
56 passwd == NULL || strlen(passwd) == 0) | |
Sam Leffler
2011/03/04 17:47:45
debug msg or connman_error?
kmixter1
2011/03/05 09:30:51
Done.
| |
57 return NULL; | |
58 | |
59 reply = dbus_message_new_method_return(msg); | |
60 if (reply == NULL) | |
61 return NULL; | |
62 | |
63 dbus_message_append_args(reply, DBUS_TYPE_STRING, &user, | |
64 DBUS_TYPE_STRING, &passwd, | |
65 DBUS_TYPE_INVALID); | |
66 | |
67 return reply; | |
68 } | |
69 | |
70 return NULL; | |
71 } | |
72 | |
73 static int li_notify(DBusMessage *msg, struct connman_provider *provider) | |
74 { | |
75 DBusMessageIter iter, dict; | |
76 const char *reason, *key, *value; | |
77 char *ifname = NULL; | |
78 char *dns1 = NULL; | |
79 char *dns2 = NULL; | |
80 struct connman_ipaddress ipaddr; | |
81 | |
82 DBG(DBG_VPN, "li_notify: interface up message"); | |
83 | |
84 dbus_message_iter_init(msg, &iter); | |
85 | |
86 dbus_message_iter_get_basic(&iter, &reason); | |
87 dbus_message_iter_next(&iter); | |
88 | |
89 if (!provider) { | |
Sam Leffler
2011/03/04 17:47:45
prevailing style is to compare ptr's to NULL
kmixter1
2011/03/05 09:30:51
Done.
| |
90 connman_error("No provider found"); | |
Sam Leffler
2011/03/04 17:47:45
uniquely identify; e.g. connman_error("%s: no prov
kmixter1
2011/03/05 09:30:51
Done.
| |
91 return VPN_STATE_FAILURE; | |
92 } | |
93 | |
94 if (strcmp(reason, "connect")) | |
95 return VPN_STATE_DISCONNECT; | |
96 | |
97 memset(&ipaddr, 0, sizeof(ipaddr)); | |
98 ipaddr.af = AF_INET; | |
99 ipaddr.mask |= CONNMAN_IPCONFIG_AF; | |
100 | |
101 dbus_message_iter_recurse(&iter, &dict); | |
102 | |
103 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { | |
104 DBusMessageIter entry; | |
105 | |
106 dbus_message_iter_recurse(&dict, &entry); | |
107 dbus_message_iter_get_basic(&entry, &key); | |
108 dbus_message_iter_next(&entry); | |
109 dbus_message_iter_get_basic(&entry, &value); | |
110 | |
111 DBG(DBG_VPN, "%s = %s", key, value); | |
Sam Leffler
2011/03/04 17:47:45
_DBG_VPN
kmixter1
2011/03/05 09:30:51
Done.
| |
112 | |
113 if (!strcmp(key, "INTERNAL_IP4_ADDRESS")) { | |
114 ipaddr.local = g_strdup(value); | |
115 ipaddr.mask |= CONNMAN_IPCONFIG_LOCAL; | |
116 } else if (!strcmp(key, "EXTERNAL_IP4_ADDRESS")) { | |
117 ipaddr.peer = g_strdup(value); | |
kmixter1
2011/03/04 02:06:02
I'm getting 0.0.0.0 from the pppd plugin. Trying
kmixter1
2011/03/05 09:30:51
FWIW, I found the peer address and it's now return
| |
118 ipaddr.mask |= CONNMAN_IPCONFIG_PEER; | |
119 } else if (!strcmp(key, "DNS1")) { | |
120 dns1 = g_strdup(value); | |
121 } else if (!strcmp(key, "DNS2")) { | |
122 dns2 = g_strdup(value); | |
123 } else if (!strcmp(key, "INTERNAL_IFNAME")) { | |
124 ifname = g_strdup(value); | |
125 } | |
126 | |
127 dbus_message_iter_next(&dict); | |
128 } | |
129 | |
130 ipaddr.dns_servers = g_try_new0(gchar *, 3); | |
131 if (dns1 != NULL) { | |
132 ipaddr.dns_servers[0] = dns1; | |
133 if (dns2 != NULL) | |
134 ipaddr.dns_servers[1] = dns2; | |
135 ipaddr.mask |= CONNMAN_IPCONFIG_DNS; | |
136 } | |
137 | |
138 /* TODO(kmixter): Should this go before or after ipconfig_set? | |
139 No routes come through? */ | |
Sam Leffler
2011/03/04 17:47:45
should not matter because the ipconfig settings ar
kmixter1
2011/03/05 09:30:51
Done.
| |
140 if (vpn_set_ifname(provider, ifname) <0) { | |
141 g_free(ifname); | |
142 return VPN_STATE_FAILURE; | |
143 } | |
144 | |
145 DBG(DBG_VPN, "li_notify: doing ipconfig set"); | |
146 | |
147 connman_provider_ipconfig_set(provider, &ipaddr); | |
kmixter1
2011/03/04 02:06:02
So this is failing... it fails because ipv4config
Sam Leffler
2011/03/04 17:47:45
Can't comment on upstream. We allocate ipv4config
kmixter1
2011/03/05 09:30:51
Sort of - it tries to enter that state but ultimat
| |
148 | |
149 g_free(ifname); | |
150 g_free(dns1); | |
151 g_free(dns2); | |
152 g_strfreev(ipaddr.dns_servers); /* TODO(kmixter): OK to free? */ | |
153 | |
154 return VPN_STATE_CONNECT; | |
155 } | |
156 | |
157 static int li_connect(struct connman_provider *provider, | |
158 struct connman_task *task, const char *if_name) | |
159 { | |
160 #define OPT_STR(property, option) do { \ | |
161 const char *s = connman_provider_get_string(provider, property); \ | |
162 if (s != NULL) \ | |
163 connman_task_add_argument(task, option, (char *)s); \ | |
164 } while (0) | |
165 #define OPT_BOOL(property, option) do { \ | |
166 const char *s = connman_provider_get_string(provider, property); \ | |
167 if (s != NULL) \ | |
168 connman_task_add_argument(task, option, NULL); \ | |
169 } while (0) | |
170 const char *vpnhost; | |
171 int err, fd; | |
172 | |
173 if (connman_task_set_notify(task, "getsec", | |
174 li_get_sec, provider)) | |
175 return -ENOMEM; | |
176 | |
177 vpnhost = connman_provider_get_string(provider, "Host"); | |
178 if (!vpnhost) { | |
179 connman_error("%s: host not set; cannot enable VPN", __func__); | |
180 return -EINVAL; | |
181 } | |
182 | |
183 connman_task_add_argument(task, "--remote", (char *)vpnhost); | |
184 // TODO: figure out the local address. | |
185 connman_task_add_argument(task, "--local", "172.22.75.194"); | |
186 connman_task_add_argument(task, "--pppd_plugin", | |
187 SCRIPTDIR "/libppp-plugin.so"); | |
188 OPT_STR("L2TPIPsec.CACert", "--server_ca_file"); | |
189 OPT_STR("L2TPIPsec.Key", "--client_key_file"); | |
190 OPT_STR("L2TPIPsec.Cert", "--client_cert_file"); | |
191 OPT_STR("L2TPIPsec.PSK", "--psk_file"); | |
192 OPT_STR("L2TPIPsec.User", "--user"); | |
193 | |
194 fd = fileno(stderr); | |
195 err = connman_task_run(task, vpn_died, provider, | |
196 NULL, &fd, &fd); | |
197 if (err < 0) { | |
198 connman_error("l2tpipsec failed to start"); | |
199 return -EIO; | |
200 } | |
201 | |
202 return 0; | |
203 } | |
204 | |
205 static struct vpn_driver vpn_driver = { | |
206 .flags = VPN_FLAG_NO_TUN, | |
207 .notify = li_notify, | |
208 .connect = li_connect, | |
209 }; | |
210 | |
211 static int li_init(void) | |
212 { | |
213 connection = connman_dbus_get_connection(); | |
214 | |
215 return vpn_register("l2tpipsec", &vpn_driver, L2TPIPSEC); | |
216 } | |
217 | |
218 static void li_exit(void) | |
219 { | |
220 vpn_unregister("l2tpipsec"); | |
221 | |
222 dbus_connection_unref(connection); | |
223 } | |
224 | |
225 CONNMAN_PLUGIN_DEFINE(l2tpipsec, "l2tpipsec plugin", VERSION, | |
226 CONNMAN_PLUGIN_PRIORITY_DEFAULT, li_init, li_exit) | |
OLD | NEW |