BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file net_ipv4_dhcp.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 * DHCP client module.
32 *
33 * Synopsis:
34 * net.ipv4.dhcp(string ifname [, list opts])
35 *
36 * Description:
37 * Runs a DHCP client on a network interface. When an address is obtained,
38 * transitions up (but does not assign anything). If the lease times out,
39 * transitions down.
40 * The interface must already be up.
41 * Supported options (in the opts argument):
42 * - "hostname", (string value): send this hostname to the DHCP server
43 * - "vendorclassid", (string value): send this vendor class identifier
44 * - "auto_clientid": send a client identifier generated from the MAC address
45 *
46 * Variables:
47 * string addr - assigned IP address ("A.B.C.D")
48 * string prefix - address prefix length ("N")
49 * string cidr_addr - address and prefix in CIDR notation ("A.B.C.D/N")
50 * string gateway - router address ("A.B.C.D"), or "none" if not provided
51 * list(string) dns_servers - DNS server addresses ("A.B.C.D" ...)
52 * string server_mac - MAC address of the DHCP server (6 two-digit caps hexadecimal values
53 * separated with colons, e.g."AB:CD:EF:01:02:03")
54 */
55  
56 #include <stdlib.h>
57 #include <string.h>
58 #include <stdio.h>
59  
60 #include <misc/debug.h>
61 #include <misc/ipaddr.h>
62 #include <dhcpclient/BDHCPClient.h>
63  
64 #include <ncd/module_common.h>
65  
66 #include <generated/blog_channel_ncd_net_ipv4_dhcp.h>
67  
68 struct instance {
69 NCDModuleInst *i;
70 BDHCPClient dhcp;
71 int up;
72 };
73  
74 static void instance_free (struct instance *o, int is_error);
75  
76 static void dhcp_handler (struct instance *o, int event)
77 {
78 switch (event) {
79 case BDHCPCLIENT_EVENT_UP: {
80 ASSERT(!o->up)
81 o->up = 1;
82 NCDModuleInst_Backend_Up(o->i);
83 } break;
84  
85 case BDHCPCLIENT_EVENT_DOWN: {
86 ASSERT(o->up)
87 o->up = 0;
88 NCDModuleInst_Backend_Down(o->i);
89 } break;
90  
91 case BDHCPCLIENT_EVENT_ERROR: {
92 instance_free(o, 1);
93 return;
94 } break;
95  
96 default: ASSERT(0);
97 }
98 }
99  
100 static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
101 {
102 struct instance *o = vo;
103 o->i = i;
104  
105 // check arguments
106 NCDValRef ifname_arg;
107 NCDValRef opts_arg = NCDVal_NewInvalid();
108 if (!NCDVal_ListRead(params->args, 1, &ifname_arg) && !NCDVal_ListRead(params->args, 2, &ifname_arg, &opts_arg)) {
109 ModuleLog(o->i, BLOG_ERROR, "wrong arity");
110 goto fail0;
111 }
112 if (!NCDVal_IsStringNoNulls(ifname_arg) || (!NCDVal_IsInvalid(opts_arg) && !NCDVal_IsList(opts_arg))) {
113 ModuleLog(o->i, BLOG_ERROR, "wrong type");
114 goto fail0;
115 }
116  
117 NCDValNullTermString hostname_nts = NCDValNullTermString_NewDummy();
118 NCDValNullTermString vendorclassid_nts = NCDValNullTermString_NewDummy();
119  
120 struct BDHCPClient_opts opts = {};
121  
122 // read options
123 size_t count = NCDVal_IsInvalid(opts_arg) ? 0 : NCDVal_ListCount(opts_arg);
124 for (size_t j = 0; j < count; j++) {
125 NCDValRef opt = NCDVal_ListGet(opts_arg, j);
126  
127 // read name
128 if (!NCDVal_IsString(opt)) {
129 ModuleLog(o->i, BLOG_ERROR, "wrong option name type");
130 goto fail1;
131 }
132  
133 if (NCDVal_StringEquals(opt, "hostname") || NCDVal_StringEquals(opt, "vendorclassid")) {
134 int is_hostname = NCDVal_StringEquals(opt, "hostname");
135  
136 // read value
137 if (j == count) {
138 ModuleLog(o->i, BLOG_ERROR, "option value missing");
139 goto fail1;
140 }
141 NCDValRef val = NCDVal_ListGet(opts_arg, j + 1);
142 if (!NCDVal_IsStringNoNulls(val)) {
143 ModuleLog(o->i, BLOG_ERROR, "wrong option value type");
144 goto fail1;
145 }
146  
147 // null terminate
148 NCDValNullTermString nts;
149 if (!NCDVal_StringNullTerminate(val, &nts)) {
150 ModuleLog(o->i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
151 goto fail1;
152 }
153 NCDValNullTermString *nts_ptr = (is_hostname ? &hostname_nts : &vendorclassid_nts);
154 NCDValNullTermString_Free(nts_ptr);
155 *nts_ptr = nts;
156  
157 if (is_hostname) {
158 opts.hostname = nts.data;
159 } else {
160 opts.vendorclassid = nts.data;
161 }
162  
163 j++;
164 }
165 else if (NCDVal_StringEquals(opt, "auto_clientid")) {
166 opts.auto_clientid = 1;
167 }
168 else {
169 ModuleLog(o->i, BLOG_ERROR, "unknown option name");
170 goto fail1;
171 }
172 }
173  
174 // null terminate ifname
175 NCDValNullTermString ifname_nts;
176 if (!NCDVal_StringNullTerminate(ifname_arg, &ifname_nts)) {
177 ModuleLog(i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
178 goto fail1;
179 }
180  
181 // init DHCP
182 int res = BDHCPClient_Init(&o->dhcp, ifname_nts.data, opts, o->i->params->iparams->reactor, o->i->params->iparams->random2, (BDHCPClient_handler)dhcp_handler, o);
183 NCDValNullTermString_Free(&ifname_nts);
184 if (!res) {
185 ModuleLog(o->i, BLOG_ERROR, "BDHCPClient_Init failed");
186 goto fail1;
187 }
188  
189 // set not up
190 o->up = 0;
191  
192 // free options nts's
193 NCDValNullTermString_Free(&hostname_nts);
194 NCDValNullTermString_Free(&vendorclassid_nts);
195 return;
196  
197 fail1:
198 NCDValNullTermString_Free(&hostname_nts);
199 NCDValNullTermString_Free(&vendorclassid_nts);
200 fail0:
201 NCDModuleInst_Backend_DeadError(i);
202 }
203  
204 static void instance_free (struct instance *o, int is_error)
205 {
206 // free DHCP
207 BDHCPClient_Free(&o->dhcp);
208  
209 if (is_error) {
210 NCDModuleInst_Backend_DeadError(o->i);
211 } else {
212 NCDModuleInst_Backend_Dead(o->i);
213 }
214 }
215  
216 static void func_die (void *vo)
217 {
218 struct instance *o = vo;
219  
220 instance_free(o, 0);
221 }
222  
223 static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
224 {
225 struct instance *o = vo;
226 ASSERT(o->up)
227  
228 if (!strcmp(name, "addr")) {
229 uint32_t addr;
230 BDHCPClient_GetClientIP(&o->dhcp, &addr);
231  
232 char str[IPADDR_PRINT_MAX];
233 ipaddr_print_addr(addr, str);
234  
235 *out = NCDVal_NewString(mem, str);
236 return 1;
237 }
238  
239 if (!strcmp(name, "prefix")) {
240 uint32_t addr;
241 BDHCPClient_GetClientIP(&o->dhcp, &addr);
242 uint32_t mask;
243 BDHCPClient_GetClientMask(&o->dhcp, &mask);
244  
245 struct ipv4_ifaddr ifaddr;
246 if (!ipaddr_ipv4_ifaddr_from_addr_mask(addr, mask, &ifaddr)) {
247 ModuleLog(o->i, BLOG_ERROR, "bad netmask");
248 return 0;
249 }
250  
251 char str[10];
252 sprintf(str, "%d", ifaddr.prefix);
253  
254 *out = NCDVal_NewString(mem, str);
255 return 1;
256 }
257  
258 if (!strcmp(name, "cidr_addr")) {
259 uint32_t addr;
260 BDHCPClient_GetClientIP(&o->dhcp, &addr);
261 uint32_t mask;
262 BDHCPClient_GetClientMask(&o->dhcp, &mask);
263  
264 struct ipv4_ifaddr ifaddr;
265 if (!ipaddr_ipv4_ifaddr_from_addr_mask(addr, mask, &ifaddr)) {
266 ModuleLog(o->i, BLOG_ERROR, "bad netmask");
267 return 0;
268 }
269  
270 char str[IPADDR_PRINT_MAX];
271 ipaddr_print_ifaddr(ifaddr, str);
272  
273 *out = NCDVal_NewString(mem, str);
274 return 1;
275 }
276  
277 if (!strcmp(name, "gateway")) {
278 char str[IPADDR_PRINT_MAX];
279  
280 uint32_t addr;
281 if (!BDHCPClient_GetRouter(&o->dhcp, &addr)) {
282 strcpy(str, "none");
283 } else {
284 ipaddr_print_addr(addr, str);
285 }
286  
287 *out = NCDVal_NewString(mem, str);
288 return 1;
289 }
290  
291 if (!strcmp(name, "dns_servers")) {
292 uint32_t servers[BDHCPCLIENT_MAX_DOMAIN_NAME_SERVERS];
293 int num_servers = BDHCPClient_GetDNS(&o->dhcp, servers, BDHCPCLIENT_MAX_DOMAIN_NAME_SERVERS);
294  
295 *out = NCDVal_NewList(mem, num_servers);
296 if (NCDVal_IsInvalid(*out)) {
297 goto fail;
298 }
299  
300 for (int i = 0; i < num_servers; i++) {
301 char str[IPADDR_PRINT_MAX];
302 ipaddr_print_addr(servers[i], str);
303  
304 NCDValRef server = NCDVal_NewString(mem, str);
305 if (NCDVal_IsInvalid(server)) {
306 goto fail;
307 }
308  
309 if (!NCDVal_ListAppend(*out, server)) {
310 goto fail;
311 }
312 }
313  
314 return 1;
315 }
316  
317 if (!strcmp(name, "server_mac")) {
318 uint8_t mac[6];
319 BDHCPClient_GetServerMAC(&o->dhcp, mac);
320  
321 char str[18];
322 sprintf(str, "%02"PRIX8":%02"PRIX8":%02"PRIX8":%02"PRIX8":%02"PRIX8":%02"PRIX8,
323 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
324  
325 *out = NCDVal_NewString(mem, str);
326 return 1;
327 }
328  
329 return 0;
330  
331 fail:
332 *out = NCDVal_NewInvalid();
333 return 1;
334 }
335  
336 static struct NCDModule modules[] = {
337 {
338 .type = "net.ipv4.dhcp",
339 .func_new2 = func_new,
340 .func_die = func_die,
341 .func_getvar = func_getvar,
342 .alloc_size = sizeof(struct instance)
343 }, {
344 .type = NULL
345 }
346 };
347  
348 const struct NCDModuleGroup ncdmodule_net_ipv4_dhcp = {
349 .modules = modules
350 };