da0a1861fd5a3d7b0e53ff11c7cd667f2a604f39
[rahunas] / src / rh-config.c
1 /**
2  * RahuNAS configuration
3  * Author: Suriya Soutmun <darksolar@gmail.com>
4  * Date:   2008-11-26
5  */
6 #include <ctype.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <syslog.h>
10 #include <dirent.h>
11 #include <errno.h>
12
13 #include "rahunasd.h"
14 #include "rh-config.h"
15
16 GList *interfaces_list = NULL;
17 static unsigned long ifb_reserved = 0;
18
19 enum lcfg_status rahunas_visitor(const char *key, void *data, size_t size, 
20                                  void *user_data) {
21   char *value = strndup(data, size);
22   union rahunas_config *config = (union rahunas_config *)user_data;
23   char *clone_key = NULL;
24   char *sep = NULL; 
25   char *main_key = NULL;
26   char *sub_key = NULL;
27   enum config_type cfg_type;
28
29   if(config == NULL)
30     return lcfg_status_error;
31
32   if(value == NULL)
33     return lcfg_status_error;
34
35   clone_key = strdup(key);
36   if (clone_key == NULL)
37     return lcfg_status_error;
38
39   sep = strstr(clone_key, ".");
40   main_key = clone_key;
41   sub_key = sep + 1;
42   *sep = '\0';
43
44   if (strncmp(main_key, "main", 4) == 0) {
45     cfg_type = MAIN;
46   } else {
47     cfg_type = VSERVER;
48     if (config->rh_vserver.vserver_name == NULL)
49       config->rh_vserver.vserver_name = strdup(main_key);
50   }
51
52   switch (cfg_type) {
53     case MAIN:
54       if (strncmp(sub_key, "conf_dir", 8) == 0) {
55         if (config->rh_main.conf_dir != NULL)
56           free(config->rh_main.conf_dir);
57         config->rh_main.conf_dir = strdup(value);
58       } else if (strncmp(sub_key, "log_file", 8) == 0) {
59         if (config->rh_main.log_file != NULL)
60           free(config->rh_main.log_file);
61         config->rh_main.log_file = strdup(value); 
62       } else if (strncmp(sub_key, "dhcp", 4) == 0) {
63         if (config->rh_main.dhcp != NULL)
64           free(config->rh_main.dhcp);
65         config->rh_main.dhcp = strdup(value);
66       } else if (strncmp(sub_key, "bandwidth_shape", 15) == 0) {
67         if (strncmp(value, "yes", 3) == 0)
68           config->rh_main.bandwidth_shape = 1; 
69         else
70           config->rh_main.bandwidth_shape = 0;
71       } else if (strncmp(sub_key, "bittorrent_download_max", 23) == 0) {
72         config->rh_main.bittorrent_download_max = atoi(value); 
73       } else if (strncmp(sub_key, "bittorrent_upload_max", 21) == 0) {
74         config->rh_main.bittorrent_upload_max = atoi(value); 
75       } else if (strncmp(sub_key, "polling_interval", 16) == 0) {
76         config->rh_main.polling_interval = atoi(value);
77       }      
78       break;
79
80     case VSERVER:
81       if (strncmp(sub_key, "vserver_id", 10) == 0) {
82         config->rh_vserver.vserver_id = atoi(value);
83       } else if (strncmp(sub_key, "dev_external", 12) == 0) {
84         if (config->rh_vserver.dev_external != NULL)
85           free(config->rh_vserver.dev_external);
86         config->rh_vserver.dev_external = strdup(value);
87       } else if (strncmp(sub_key, "dev_internal", 12) == 0) {
88         if (config->rh_vserver.dev_internal != NULL)
89           free(config->rh_vserver.dev_internal);
90         config->rh_vserver.dev_internal = strdup(value);
91       } else if (strncmp(sub_key, "vlan", 4) == 0) {
92         if (config->rh_vserver.vlan != NULL)
93           free(config->rh_vserver.vlan);
94         config->rh_vserver.vlan = strdup(value);
95       } else if (strncmp(sub_key, "vlan_raw_dev_external", 21) == 0) {
96         if (config->rh_vserver.vlan_raw_dev_external != NULL)
97           free(config->rh_vserver.vlan_raw_dev_external);
98         config->rh_vserver.vlan_raw_dev_external = strdup(value);
99        } else if (strncmp(sub_key, "vlan_raw_dev_internal", 21) == 0) {
100         if (config->rh_vserver.vlan_raw_dev_internal != NULL)
101           free(config->rh_vserver.vlan_raw_dev_internal);
102         config->rh_vserver.vlan_raw_dev_internal = strdup(value);
103       } else if (strncmp(sub_key, "bridge", 6) == 0) {
104         if (config->rh_vserver.bridge != NULL)
105           free(config->rh_vserver.bridge);
106         config->rh_vserver.bridge = strdup(value);
107       } else if (strncmp(sub_key, "masquerade", 10) == 0) {
108         if (config->rh_vserver.masquerade != NULL)
109           free(config->rh_vserver.masquerade);
110         config->rh_vserver.masquerade = strdup(value);
111       } else if (strncmp(sub_key, "ignore_mac", 10) == 0) {
112         if (config->rh_vserver.ignore_mac != NULL)
113           free(config->rh_vserver.ignore_mac);
114         config->rh_vserver.ignore_mac = strdup(value);
115       } else if (strncmp(sub_key, "vserver_ip", 10) == 0) {
116         if (config->rh_vserver.vserver_ip != NULL)
117           free(config->rh_vserver.vserver_ip);
118         config->rh_vserver.vserver_ip = strdup(value); 
119       } else if (strncmp(sub_key, "vserver_fqdn", 12) == 0) {
120         if (config->rh_vserver.vserver_fqdn != NULL)
121           free(config->rh_vserver.vserver_fqdn);
122         config->rh_vserver.vserver_fqdn = strdup(value);
123       } else if (strncmp(sub_key, "vserver_ports_allow", 19) == 0) {
124         if (config->rh_vserver.vserver_ports_allow != NULL)
125           free(config->rh_vserver.vserver_ports_allow);
126         config->rh_vserver.vserver_ports_allow = strdup(value);
127       } else if (strncmp(sub_key, "vserver_ports_intercept", 23) == 0) {
128         if (config->rh_vserver.vserver_ports_intercept != NULL)
129           free(config->rh_vserver.vserver_ports_intercept);
130         config->rh_vserver.vserver_ports_intercept = strdup(value);
131       } else if (strncmp(sub_key, "clients", 7) == 0) {
132         if (config->rh_vserver.clients != NULL)
133           free(config->rh_vserver.clients);
134         config->rh_vserver.clients = strdup(value);
135       } else if (strncmp(sub_key, "excluded", 8) == 0) {
136         if (config->rh_vserver.excluded != NULL)
137           free(config->rh_vserver.excluded);
138         config->rh_vserver.excluded = strdup(value);
139       } else if (strncmp(sub_key, "idle_timeout", 12) == 0) {
140         config->rh_vserver.idle_timeout = atoi(value);
141       } else if (strncmp(sub_key, "dns", 3) == 0) {
142         if (config->rh_vserver.dns != NULL)
143           free(config->rh_vserver.dns);
144         config->rh_vserver.dns = strdup(value);
145       } else if (strncmp(sub_key, "ssh", 3) == 0) {
146         if (config->rh_vserver.ssh != NULL)
147           free(config->rh_vserver.ssh);
148         config->rh_vserver.ssh = strdup(value);
149       } else if (strncmp(sub_key, "proxy", 5) == 0) {
150         if (strncmp(sub_key, "proxy_host", 10) == 0) {
151           if (config->rh_vserver.proxy_host != NULL)
152             free(config->rh_vserver.proxy_host);
153           config->rh_vserver.proxy_host = strdup(value);
154         } else if (strncmp(sub_key, "proxy_port", 10) == 0) {
155           if (config->rh_vserver.proxy_port != NULL)
156             free(config->rh_vserver.proxy_port);
157           config->rh_vserver.proxy_port = strdup(value);
158         } else {
159           if (config->rh_vserver.proxy != NULL)
160             free(config->rh_vserver.proxy);
161           config->rh_vserver.proxy = strdup(value);
162         }
163       } else if (strncmp(sub_key, "bittorrent", 10) == 0) {
164         if (strncmp(sub_key, "bittorrent_allow", 16) == 0) {
165           if (config->rh_vserver.bittorrent_allow != NULL)
166             free(config->rh_vserver.bittorrent_allow);
167           config->rh_vserver.bittorrent_allow = strdup(value);
168         } else {
169           if (config->rh_vserver.bittorrent != NULL)
170             free(config->rh_vserver.bittorrent);
171           config->rh_vserver.bittorrent = strdup(value);
172         }
173       } else if (strncmp(sub_key, "radius_host", 11) == 0) {
174         if (config->rh_vserver.radius_host != NULL)
175           free(config->rh_vserver.radius_host);
176         config->rh_vserver.radius_host = strdup(value);
177       } else if (strncmp(sub_key, "radius_secret", 13) == 0) {
178         if (config->rh_vserver.radius_secret != NULL)
179           free(config->rh_vserver.radius_secret);
180         config->rh_vserver.radius_secret = strdup(value);
181       } else if (strncmp(sub_key, "radius_encrypt", 14) == 0) {
182         if (config->rh_vserver.radius_encrypt != NULL)
183           free(config->rh_vserver.radius_encrypt);
184         config->rh_vserver.radius_encrypt = strdup(value);
185       } else if (strncmp(sub_key, "radius_auth_port", 16) == 0) {
186         if (config->rh_vserver.radius_auth_port != NULL)
187           free(config->rh_vserver.radius_auth_port);
188         config->rh_vserver.radius_auth_port = strdup(value);
189       } else if (strncmp(sub_key, "radius_account_port", 19) == 0) {
190         if (config->rh_vserver.radius_account_port != NULL)
191           free(config->rh_vserver.radius_account_port);
192         config->rh_vserver.radius_account_port = strdup(value);
193       } else if (strncmp(sub_key, "nas_identifier", 14) == 0) {
194         if (config->rh_vserver.nas_identifier != NULL)
195           free(config->rh_vserver.nas_identifier);
196         config->rh_vserver.nas_identifier = strdup(value);
197       } else if (strncmp(sub_key, "nas_port", 8) == 0) {
198         if (config->rh_vserver.nas_port != NULL)
199           free(config->rh_vserver.nas_port);
200         config->rh_vserver.nas_port = strdup(value);
201       } else if (strncmp(sub_key, "nas_login_title", 15) == 0) {
202         if (config->rh_vserver.nas_login_title != NULL)
203           free(config->rh_vserver.nas_login_title);
204         config->rh_vserver.nas_login_title = strdup(value);
205       } else if (strncmp(sub_key, "nas_default_redirect", 20) == 0) {
206         if (config->rh_vserver.nas_default_redirect != NULL)
207           free(config->rh_vserver.nas_default_redirect);
208         config->rh_vserver.nas_default_redirect = strdup(value);
209       } else if (strncmp(sub_key, "nas_default_language", 20) == 0) {
210         if (config->rh_vserver.nas_default_language != NULL)
211           free(config->rh_vserver.nas_default_language);
212         config->rh_vserver.nas_default_language = strdup(value);
213       } else if (strncmp(sub_key, "nas_weblogin_template", 21) == 0) {
214         if (config->rh_vserver.nas_weblogin_template != NULL)
215           free(config->rh_vserver.nas_weblogin_template);
216         config->rh_vserver.nas_weblogin_template = strdup(value);
217       } else if (strncmp(sub_key, "vipmap_attribute",
218                  strlen("vipmap_attribute")) == 0) {
219         if (config->rh_vserver.vipmap_attribute != NULL)
220           free(config->rh_vserver.vipmap_attribute);
221         config->rh_vserver.vipmap_attribute = strdup(value);
222       } else if (strncmp(sub_key, "vipmap_network",
223                  strlen("vipmap_network")) == 0) {
224         if (config->rh_vserver.vipmap_network != NULL)
225           free(config->rh_vserver.vipmap_network);
226         config->rh_vserver.vipmap_network = strdup(value);
227       } else if (strncmp(sub_key, "vipmap_fake_arp",
228                  strlen("vipmap_fake_arp")) == 0) {
229         if (config->rh_vserver.vipmap_fake_arp != NULL)
230           free(config->rh_vserver.vipmap_fake_arp);
231         config->rh_vserver.vipmap_fake_arp = strdup(value);
232       } else if (strncmp(sub_key, "vipmap", strlen("vipmap")) == 0) {
233         if (config->rh_vserver.vipmap != NULL)
234           free(config->rh_vserver.vipmap);
235         config->rh_vserver.vipmap = strdup(value);
236
237         if (strncmp(config->rh_vserver.vipmap, "yes", strlen("yes")) == 0) {
238           config->rh_vserver.vipmap_enable = 1;
239
240           config->rh_vserver.vserver_vip_name =
241             g_strdup_printf ("%s-vip", config->rh_vserver.vserver_name);
242         }
243       }
244       break;
245   }
246
247   
248   rh_free(&clone_key);
249
250   return lcfg_status_ok;
251 }
252
253 int get_config(const char *cfg_file, union rahunas_config *config) {
254   lcfg_visitor_function visitor_func = rahunas_visitor;
255   struct lcfg *c = lcfg_new(cfg_file);
256   
257   syslog(LOG_INFO, "Parsing config file: %s", cfg_file);
258
259   if (lcfg_parse(c) != lcfg_status_ok) {
260     syslog(LOG_ERR, "config error: %s", lcfg_error_get(c));
261     lcfg_delete(c);
262     return -1;
263   }
264
265   syslog(LOG_INFO, "Processing config file: %s", cfg_file);
266   if (lcfg_accept(c, visitor_func, config) != lcfg_status_ok) {
267     syslog(LOG_ERR, "config error: %s", lcfg_error_get(c));
268     lcfg_delete(c);
269     return -1;
270   }
271
272   lcfg_delete(c);
273
274   return 0;
275 }
276
277
278 int get_value(const char *cfg_file, const char *key, void **data, size_t *len)
279 {
280   lcfg_visitor_function visitor_func = rahunas_visitor;
281   struct lcfg *c = lcfg_new(cfg_file);
282   
283   if (lcfg_parse(c) != lcfg_status_ok) {
284     syslog(LOG_ERR, "config error: %s", lcfg_error_get(c));
285     lcfg_delete(c);
286     return -1;
287   }
288
289   if (lcfg_value_get(c, key, data, len) != lcfg_status_ok) {
290     lcfg_delete(c);
291     return -1;
292   } 
293
294   lcfg_delete(c);
295
296   return 0;
297 }
298
299 int get_vservers_config(const char *conf_dir, struct main_server *server)
300 {
301   DIR *dp;
302   struct dirent *dirp;
303   void *data = NULL;
304   size_t len;
305   char conf_file[200];
306
307   if ((dp = opendir(conf_dir)) == NULL)
308     return errno;
309   
310   while ((dirp = readdir(dp)) != NULL) {
311     if (strstr(dirp->d_name, ".conf") == NULL)
312       continue;
313
314     memset(conf_file, 0, sizeof(conf_file));
315
316     strncat(conf_file, conf_dir, sizeof(conf_file));
317     strncat(conf_file, "/", 1);
318     strncat(conf_file, dirp->d_name, sizeof(conf_file));
319
320     syslog(LOG_INFO, "Loading config file: %s", conf_file);
321     
322     register_vserver(server, conf_file);
323   }
324   
325   closedir(dp);
326   return 0;
327 }
328
329
330 int cleanup_vserver_config(struct rahunas_vserver_config *config)
331 {
332   rh_free(&(config->vserver_name));  
333   rh_free(&(config->dev_external));
334   rh_free(&(config->dev_internal));
335   rh_free(&(config->vlan));
336   rh_free(&(config->vlan_raw_dev_external));
337   rh_free(&(config->vlan_raw_dev_internal));
338   rh_free(&(config->bridge));
339   rh_free(&(config->masquerade));
340   rh_free(&(config->ignore_mac));
341   rh_free(&(config->vserver_ip));
342   rh_free(&(config->vserver_fqdn));
343   rh_free(&(config->vserver_ports_allow));
344   rh_free(&(config->vserver_ports_intercept));
345   rh_free(&(config->clients));
346   rh_free(&(config->excluded));
347   rh_free(&(config->dns));
348   rh_free(&(config->ssh));
349   rh_free(&(config->proxy));
350   rh_free(&(config->proxy_host));
351   rh_free(&(config->proxy_port));
352   rh_free(&(config->bittorrent));
353   rh_free(&(config->bittorrent_allow));
354   rh_free(&(config->radius_host));
355   rh_free(&(config->radius_secret));
356   rh_free(&(config->radius_encrypt));
357   rh_free(&(config->radius_auth_port));
358   rh_free(&(config->radius_account_port));
359   rh_free(&(config->nas_identifier));
360   rh_free(&(config->nas_port));
361   rh_free(&(config->nas_login_title));
362   rh_free(&(config->nas_default_redirect));
363   rh_free(&(config->nas_default_language));
364   rh_free(&(config->nas_weblogin_template));
365   rh_free(&(config->vipmap));
366   rh_free(&(config->vipmap_attribute));
367   rh_free(&(config->vipmap_network));
368   rh_free(&(config->vipmap_fake_arp));
369
370   return 0;
371 }
372
373 int cleanup_mainserver_config(struct rahunas_main_config *config)
374 {
375   rh_free(&(config->conf_dir));  
376   rh_free(&(config->log_file));
377   rh_free(&(config->dhcp));
378
379   return 0;
380 }
381
382
383 GList *append_interface (GList *inf, 
384                          const char *inf_name)
385 {
386   GList *runner = NULL;
387   struct interfaces *iface = NULL;
388   struct interfaces *item  = NULL;
389   int    ifb_ifno;
390
391   if (!inf_name)
392     return inf;
393
394   item = (struct interfaces *) malloc (sizeof (struct interfaces));
395   if (!item)
396     return inf;
397
398   runner = g_list_first (inf);
399   while (runner != NULL)
400     {
401       iface = (struct interfaces *)runner->data;
402       if (iface->dev_internal &&
403           strncmp(iface->dev_internal, inf_name, strlen(inf_name)) == 0)
404         {
405           // Already in the list
406           (iface->hit)++;
407           free(item); 
408           return inf;
409         }
410       runner = g_list_next (runner);
411     }
412
413 done:
414   ifb_ifno = ifb_interface_reserve ();
415   if (ifb_ifno < 0)
416     {
417       free (item);
418       return inf;
419     }
420
421   strncpy(item->dev_internal, inf_name, sizeof (item->dev_internal));
422   snprintf(item->dev_ifb, sizeof (item->dev_ifb), "ifb%d", ifb_ifno);
423   item->init = 0;
424   item->hit  = 1;
425   DP ("Interface append: %s, %s", item->dev_internal, item->dev_ifb);
426   
427   return g_list_append (inf, item);
428 }
429
430 GList *remove_interface (GList *inf,
431                          const char *inf_name)
432 {
433   GList *runner = NULL;
434   struct interfaces *iface = NULL;
435   int    ifb_ifno;
436
437   if (!inf_name || !inf)
438     return inf;
439
440   runner = g_list_first (inf);
441   while (runner != NULL)
442     {
443       iface = (struct interfaces *)runner->data;
444       if (iface->dev_internal &&
445           strncmp (iface->dev_internal, inf_name, strlen (inf_name)) == 0)
446         {
447           iface->hit--;
448           if (iface->hit <=0 )
449             {
450               sscanf (iface->dev_ifb, "ifb%d", &ifb_ifno);
451               ifb_interface_release (ifb_ifno);
452               if (iface)
453                 free (iface);
454
455               return g_list_delete_link (inf, runner);
456             }
457         }
458
459       runner = g_list_next (runner);
460     }
461
462   return inf;
463 }
464
465
466 struct interfaces *get_interface (GList *inf,
467                                   const char *inf_name)
468 {
469   GList *runner = NULL;
470   struct interfaces *iface = NULL;
471   
472   if (!inf_name || !inf)
473     return NULL;
474
475   runner = g_list_first (inf);
476
477   while (runner != NULL)
478     {
479       iface = (struct interfaces *) runner->data;
480       if (strncmp (iface->dev_internal, inf_name, strlen (inf_name)) == 0)
481         return iface;
482
483       runner = g_list_next (runner);
484     } 
485
486   return NULL;
487 }
488
489 int ifb_interface_reserve (void)
490 {
491   int i;
492   unsigned long mask = 1;
493
494   for (i=0; i < MAX_IFB_IFACE; i++)
495     {
496       mask = 1 << i;
497       if (!(ifb_reserved & mask))
498         {
499           ifb_reserved |= mask;
500           return i;
501         } 
502     }
503
504   return -1;
505 }
506
507 void ifb_interface_release (int ifno)
508 {
509   unsigned long mask = 1;
510
511   mask <<= ifno;
512   mask = ~mask;
513   ifb_reserved &= mask;
514 }