BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file net_backend_badvpn.c
3 * @author Ambroz Bizjak <ambrop7@gmail.com>
4 *
5 * @section LICENSE
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the
15 * names of its contributors may be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * @section DESCRIPTION
30 *
31 * BadVPN interface module.
32 *
33 * Synopsis: net.backend.badvpn(string ifname, string user, string exec, list(string) args)
34 */
35  
36 #include <stdlib.h>
37 #include <string.h>
38  
39 #include <misc/cmdline.h>
40 #include <ncd/extra/NCDIfConfig.h>
41  
42 #include <ncd/module_common.h>
43  
44 #include <generated/blog_channel_ncd_net_backend_badvpn.h>
45  
46 #define RETRY_TIME 5000
47  
48 struct instance {
49 NCDModuleInst *i;
50 NCDValNullTermString ifname_nts;
51 NCDValNullTermString user_nts;
52 MemRef exec;
53 NCDValRef args;
54 int dying;
55 int started;
56 BTimer timer;
57 BProcess process;
58 };
59  
60 static void try_process (struct instance *o);
61 static void process_handler (struct instance *o, int normally, uint8_t normally_exit_status);
62 static void timer_handler (struct instance *o);
63 static void instance_free (struct instance *o);
64  
65 void try_process (struct instance *o)
66 {
67 CmdLine c;
68 if (!CmdLine_Init(&c)) {
69 goto fail0;
70 }
71  
72 // append exec
73 if (!CmdLine_AppendNoNullMr(&c, o->exec)) {
74 goto fail1;
75 }
76  
77 // append tapdev
78 if (!CmdLine_Append(&c, "--tapdev") || !CmdLine_Append(&c, o->ifname_nts.data)) {
79 goto fail1;
80 }
81  
82 // append arguments
83 size_t count = NCDVal_ListCount(o->args);
84 for (size_t j = 0; j < count; j++) {
85 NCDValRef arg = NCDVal_ListGet(o->args, j);
86 if (!CmdLine_AppendNoNullMr(&c, NCDVal_StringMemRef(arg))) {
87 goto fail1;
88 }
89 }
90  
91 // terminate cmdline
92 if (!CmdLine_Finish(&c)) {
93 goto fail1;
94 }
95  
96 // start process
97 if (!BProcess_Init(&o->process, o->i->params->iparams->manager, (BProcess_handler)process_handler, o, ((char **)c.arr.v)[0], (char **)c.arr.v, o->user_nts.data)) {
98 ModuleLog(o->i, BLOG_ERROR, "BProcess_Init failed");
99 goto fail1;
100 }
101  
102 CmdLine_Free(&c);
103  
104 // set started
105 o->started = 1;
106  
107 return;
108  
109 fail1:
110 CmdLine_Free(&c);
111 fail0:
112 // retry
113 o->started = 0;
114 BReactor_SetTimer(o->i->params->iparams->reactor, &o->timer);
115 }
116  
117 void process_handler (struct instance *o, int normally, uint8_t normally_exit_status)
118 {
119 ASSERT(o->started)
120  
121 ModuleLog(o->i, BLOG_INFO, "process terminated");
122  
123 // free process
124 BProcess_Free(&o->process);
125  
126 // set not started
127 o->started = 0;
128  
129 if (o->dying) {
130 instance_free(o);
131 return;
132 }
133  
134 // set timer
135 BReactor_SetTimer(o->i->params->iparams->reactor, &o->timer);
136 }
137  
138 void timer_handler (struct instance *o)
139 {
140 ASSERT(!o->started)
141  
142 ModuleLog(o->i, BLOG_INFO, "retrying");
143  
144 // try starting process again
145 try_process(o);
146 }
147  
148 static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
149 {
150 struct instance *o = vo;
151 o->i = i;
152  
153 // read arguments
154 NCDValRef ifname_arg;
155 NCDValRef user_arg;
156 NCDValRef exec_arg;
157 NCDValRef args_arg;
158 if (!NCDVal_ListRead(params->args, 4, &ifname_arg, &user_arg, &exec_arg, &args_arg)) {
159 ModuleLog(o->i, BLOG_ERROR, "wrong arity");
160 goto fail0;
161 }
162 if (!NCDVal_IsStringNoNulls(ifname_arg) || !NCDVal_IsStringNoNulls(user_arg) ||
163 !NCDVal_IsStringNoNulls(exec_arg) || !NCDVal_IsList(args_arg)) {
164 ModuleLog(o->i, BLOG_ERROR, "wrong type");
165 goto fail0;
166 }
167  
168 o->exec = NCDVal_StringMemRef(exec_arg);
169 o->args = args_arg;
170  
171 // check arguments
172 size_t count = NCDVal_ListCount(o->args);
173 for (size_t j = 0; j < count; j++) {
174 NCDValRef arg = NCDVal_ListGet(o->args, j);
175 if (!NCDVal_IsStringNoNulls(arg)) {
176 ModuleLog(o->i, BLOG_ERROR, "wrong type");
177 goto fail0;
178 }
179 }
180  
181 // null terminate user
182 if (!NCDVal_StringNullTerminate(user_arg, &o->user_nts)) {
183 ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
184 goto fail0;
185 }
186  
187 // null terminate ifname
188 if (!NCDVal_StringNullTerminate(ifname_arg, &o->ifname_nts)) {
189 ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
190 goto fail1;
191 }
192  
193 // create TAP device
194 if (!NCDIfConfig_make_tuntap(o->ifname_nts.data, o->user_nts.data, 0)) {
195 ModuleLog(o->i, BLOG_ERROR, "failed to create TAP device");
196 goto fail2;
197 }
198  
199 // set device up
200 if (!NCDIfConfig_set_up(o->ifname_nts.data)) {
201 ModuleLog(o->i, BLOG_ERROR, "failed to set device up");
202 goto fail3;
203 }
204  
205 // set not dying
206 o->dying = 0;
207  
208 // init timer
209 BTimer_Init(&o->timer, RETRY_TIME, (BTimer_handler)timer_handler, o);
210  
211 // signal up
212 NCDModuleInst_Backend_Up(o->i);
213  
214 // try starting process
215 try_process(o);
216 return;
217  
218 fail3:
219 if (!NCDIfConfig_remove_tuntap(o->ifname_nts.data, 0)) {
220 ModuleLog(o->i, BLOG_ERROR, "failed to remove TAP device");
221 }
222 fail2:
223 NCDValNullTermString_Free(&o->ifname_nts);
224 fail1:
225 NCDValNullTermString_Free(&o->user_nts);
226 fail0:
227 NCDModuleInst_Backend_DeadError(i);
228 }
229  
230 void instance_free (struct instance *o)
231 {
232 ASSERT(!o->started)
233  
234 // free timer
235 BReactor_RemoveTimer(o->i->params->iparams->reactor, &o->timer);
236  
237 // set device down
238 if (!NCDIfConfig_set_down(o->ifname_nts.data)) {
239 ModuleLog(o->i, BLOG_ERROR, "failed to set device down");
240 }
241  
242 // free TAP device
243 if (!NCDIfConfig_remove_tuntap(o->ifname_nts.data, 0)) {
244 ModuleLog(o->i, BLOG_ERROR, "failed to remove TAP device");
245 }
246  
247 // free ifname nts
248 NCDValNullTermString_Free(&o->ifname_nts);
249  
250 // free user nts
251 NCDValNullTermString_Free(&o->user_nts);
252  
253 NCDModuleInst_Backend_Dead(o->i);
254 }
255  
256 static void func_die (void *vo)
257 {
258 struct instance *o = vo;
259 ASSERT(!o->dying)
260  
261 if (!o->started) {
262 instance_free(o);
263 return;
264 }
265  
266 // request termination
267 BProcess_Terminate(&o->process);
268  
269 // remember dying
270 o->dying = 1;
271 }
272  
273 static struct NCDModule modules[] = {
274 {
275 .type = "net.backend.badvpn",
276 .func_new2 = func_new,
277 .func_die = func_die,
278 .alloc_size = sizeof(struct instance)
279 }, {
280 .type = NULL
281 }
282 };
283  
284 const struct NCDModuleGroup ncdmodule_net_backend_badvpn = {
285 .modules = modules
286 };