Clean up unused variables.
[vde.git] / vde-2 / src / vde_router / vde_router.c
blob722d1988d7f0f73bbeff25d5d497e67069ea5de6
1 /* VDE_ROUTER (C) 2007:2011 Daniele Lacamera
3 * Licensed under the GPLv2
5 * Description: this module is just a frontend for command line,
6 * configuration, etc.
8 * For the router engine see vder_datalink.c
9 */
10 #include "vder_olsr.h"
11 #include "vder_datalink.h"
12 #include "vde_router.h"
13 #include "vder_queue.h"
14 #include "vder_packet.h"
15 #include "vder_dhcp.h"
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <stdio.h>
19 #include <stdarg.h>
20 #include <fcntl.h>
21 #include <sys/poll.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <sys/socket.h>
25 #include <sys/un.h>
26 #include <sys/stat.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <getopt.h>
30 #include <libgen.h>
33 static char *mgmt;
34 static int mgmtmode=0700;
35 static char *progname;
36 #define MAXCMD 128
38 #define match_input(c, i) ((strncmp(c, i, strlen(c)) == 0) && (strlen(c) == strlen(i)))
40 extern struct vde_router Router;
42 static char header[]="\nVDE Router \n(C) D.Lacamera 2011 - GPLv2\n";
43 static char prompt[]="\nVDE-Router$ ";
45 static void printoutc(int fd, const char *format, ...)
47 va_list arg;
48 char outbuf[MAXCMD+1];
50 va_start (arg, format);
51 vsnprintf(outbuf,MAXCMD,format,arg);
52 strcat(outbuf,"\n");
53 write(fd,outbuf,strlen(outbuf));
55 static int help(int fd,char *s)
57 char *nextargs = NULL, *arg;
58 arg = strtok_r(s, " ", &nextargs);
59 if(!arg) {
60 /* No arguments */
61 printoutc(fd, "COMMAND HELP");
62 printoutc(fd, "------------ ------------");
63 printoutc(fd, "help print a summary of mgmt commands. Use \"help <command>\" for details.");
64 printoutc(fd, "connect create a new interface connect it to vde socket");
65 printoutc(fd, "ifconfig show/change interface addresses configuration");
66 printoutc(fd, "dhcpd start/stop dhcp server on a specific interface");
67 printoutc(fd, "olsr start/stop OLSR");
68 printoutc(fd, "route show/change routing table");
69 printoutc(fd, "arp show neighbors ip/mac associations");
70 printoutc(fd, "queue show/change outgoing frames queues");
71 printoutc(fd, "ipfilter show/change ip filtering configuration");
72 printoutc(fd, "stats print interface statistics");
73 printoutc(fd, "logout close current management session");
74 printoutc(fd, "shutdown turn the router off");
75 return 0;
76 } else if (match_input("help",arg)) {
77 printoutc(fd, "help print a summary of mgmt commands.");
78 printoutc(fd, "Use \"help <command>\" for details.");
79 return 0;
80 } else if (match_input("connect",arg)) {
81 printoutc(fd, "Syntax:");
82 printoutc(fd, "\tconnect <vde_sock_path> [<macaddress>]");
83 printoutc(fd, "Connects to a vde socket at path <vde_sock_path> by creating a new virtual ethernet device.");
84 printoutc(fd, "If no <macaddress> is provided, it will be assigned automatically.");
85 printoutc(fd, "");
86 printoutc(fd, "Examples:");
87 printoutc(fd, "connect /var/run/vde.ctl");
88 printoutc(fd, "connect /var/run/my_sock.ctl 00:11:22:33:44:55");
89 return 0;
90 } else if (match_input("ifconfig",arg)) {
91 printoutc(fd, "Syntax:");
92 printoutc(fd, "\tifconfig [<devname> [<action> <address> <netmask>]]");
93 printoutc(fd, "--or--");
94 printoutc(fd, "\tifconfig <devname> add dhcp");
95 printoutc(fd, "Show/store IP address configuration. If no <devname> is provided, the default action");
96 printoutc(fd, "will be to display the current configuration for all the existing ethernet devices.");
97 printoutc(fd, "<action> can be \"add\" or \"del\". If \"add\" is specified, all other arguments are mandatory.");
98 printoutc(fd, "If \"del\" is specified, only <address> will be used to search for an existing entry.");
99 printoutc(fd, "Each virtual ethernet can be associated to more than one IP addresses. A static route for");
100 printoutc(fd, "the resulting neighborhood will be added.");
101 printoutc(fd, "Dhcp option allows to ask for a dynamic IP address.");
102 printoutc(fd, "");
103 printoutc(fd, "Examples:");
104 printoutc(fd, "ifconfig");
105 printoutc(fd, "ifconfig eth0");
106 printoutc(fd, "ifconfig eth1 add 10.0.0.1 255.0.0.0");
107 printoutc(fd, "ifconfig eth1 add dhcp");
108 printoutc(fd, "ifconfig eth1 del 10.0.0.1");
109 return 0;
110 } else if (match_input("dhcpd",arg)) {
111 printoutc(fd, "Syntax:");
112 printoutc(fd, "\tdhcpd start <devname> <dhcp_pool_start> <dhcp_pool_end>");
113 printoutc(fd, "--or--");
114 printoutc(fd, "\tdhcpd stop <devname>");
115 printoutc(fd, "Start/stop DHCP server on a specific interface. Devices/machines connected to the router");
116 printoutc(fd, "will be provided with a dynamic IP address on request.");
117 printoutc(fd, "");
118 printoutc(fd, "Examples:");
119 printoutc(fd, "dhcpd start eth0 10.0.0.101 10.0.0.120");
120 printoutc(fd, "dhcpd stop eth0");
121 return 0;
122 } else if (match_input("olsr",arg)) {
123 printoutc(fd, "Syntax:");
124 printoutc(fd, "\tolsr start <devname> [<devname> [<devname> [<...>]]]");
125 printoutc(fd, "--or--");
126 printoutc(fd, "\tolsr stop");
127 printoutc(fd, "Start/stop olsr service on specified interface(s). Devices/machines connected to the router");
128 printoutc(fd, "will be notified about routing via OLSR messages");
129 printoutc(fd, "");
130 printoutc(fd, "Examples:");
131 printoutc(fd, "olsr start eth0 eth1");
132 printoutc(fd, "olsr stop");
133 return 0;
134 } else if (match_input("route",arg)) {
135 printoutc(fd, "Syntax:");
136 printoutc(fd, "\troute [<action> <address> <netmask> [gw <gateway>] [via <interface>] [metric <metric>]]");
137 printoutc(fd, "--or--");
138 printoutc(fd, "\troute <action> default [address]");
139 printoutc(fd, "Show/store routing table information. If no <action> is given, the default behavior is to");
140 printoutc(fd, "show the current (full) routing table.");
141 printoutc(fd, "<action> can be \"add\" or \"del\". If \"add\" or \"del\" is specified, address and netmask are");
142 printoutc(fd, "mandatory, unless the \"default\" keyword is present. \"default\" is used to manage default ");
143 printoutc(fd, "gateway entry.");
144 printoutc(fd, "");
145 printoutc(fd, "Examples:");
146 printoutc(fd, "route");
147 printoutc(fd, "route add default 10.0.0.254");
148 printoutc(fd, "route del default");
149 printoutc(fd, "route add 192.168.0.0 255.255.0.0 gw 10.0.0.253 metric 2");
150 printoutc(fd, "route add 192.168.1.0 255.255.255.0 via eth2");
151 return 0;
152 } else if (match_input("queue",arg)) {
153 printoutc(fd, "Syntax:");
154 printoutc(fd, "\tqueue [<devname>:<queuename> <policy> <policy_options>]");
155 printoutc(fd, "");
156 printoutc(fd, "Show/store queuing policy information. If no <action> is specified,");
157 printoutc(fd, "the current queue policy and information are displayed, otherwise you need");
158 printoutc(fd, "to specify the options for the selected queue.");
159 printoutc(fd, "");
160 printoutc(fd, "Selecting the queue consists in naming the interface and the associated queue.");
161 printoutc(fd, "Every interface has one \":output\" queue and 32 priority queues named from");
162 printoutc(fd, "\":prio0\" to \":prio31\".");
163 printoutc(fd, "");
164 printoutc(fd, "The following policies are available:");
165 printoutc(fd, "");
166 printoutc(fd, "- 'unlimited' (default).");
167 printoutc(fd, "\tthis policy requires no options. It is the default policy, and it will allow");
168 printoutc(fd, "\tto enqueue virtually an unlimited amount of data before it is dequeued.");
169 printoutc(fd, "");
170 printoutc(fd, "- 'fifo' (usage: fifo limit <limit>)");
171 printoutc(fd, "\tthis policy will allow at most <limit> bytes to be enqueued, and a tail-drop");
172 printoutc(fd, "\twill be adopted to all the exceeding frames when the queue is full.");
173 printoutc(fd, "");
174 printoutc(fd, "");
175 printoutc(fd, "- 'red' (usage: red min <min> max <max> probability <P> limit <limit>)");
176 printoutc(fd, "\tthis is the \"Random Early Detection\" queuing policy. It consists of setting");
177 printoutc(fd, "\ta dynamic limit to the queue during the enqueue operation. The probability");
178 printoutc(fd, "\tof dropping packets during enqueue will be 0 under <min> bytes, then it will ");
179 printoutc(fd, "\tincrease linearly to reach <P> between <min> and <max>. Between <max> and <limit>");
180 printoutc(fd, "\tit will be <P>. Over the physical limit <limit>, all packets will be dropped (P=1).");
181 printoutc(fd, "");
182 printoutc(fd, "- 'token' (usage: tbf limit <limit> bitrate <bitrate>");
183 printoutc(fd, "\tThis is the \"Token Bucket\" queuing policy, allowing traffic to be dequeued at");
184 printoutc(fd, "\tthe specified <bitrate>. Enqueuing will be limited to <limit> bytes, so if the");
185 printoutc(fd, "\tqueue is full all the exceeding frames will be dropped.");
186 printoutc(fd, "Examples:");
187 printoutc(fd, "queue");
188 printoutc(fd, "queue eth0:output fifo limit 40000");
189 printoutc(fd, "queue eth0:prio3 red min 80000 max 160000 probability 0.1 limit 300000");
190 printoutc(fd, "queue eth0:prio15 unlimited");
191 return 0;
192 } else if (match_input("ipfilter",arg)) {
193 printoutc(fd, "Syntax:");
194 printoutc(fd, "\tipfilter [<action> [src <interface>] [from <address> <netmask>]");
195 printoutc(fd, " [to <address> <netmask>] [proto <proto>] [tos <tos>]");
196 printoutc(fd, " [sport <sport>] [dport <dport>] <filter_action> [<priority>]]");
197 printoutc(fd, "Show/store IP filtering information. If no <action> is specified, ");
198 printoutc(fd, "the current ip filtering table is shown, else <action> can be \"add\" or \"del\"");
199 printoutc(fd, "If \"add\" is specified, no other argument is mandatory but the <filter_action>.");
200 printoutc(fd, "<filter_action> can be one of \"accept\" \"drop\" \"reject\" or \"prio\". Accept is the");
201 printoutc(fd, "default behavior. \"reject\" is like \"drop\" except that it will send a icmp packet filtered ");
202 printoutc(fd, "towards the source every time the rule is hit. \"prio\" changes the priority of the ");
203 printoutc(fd, "packet when it gets inserted to the output queue system, allowing IP-based QoS.");
204 printoutc(fd, "When \"prio\" is selected as <filter_action>, the argument <priority> is mandatory.");
205 printoutc(fd, "If <del> is specified as <action>, all the arguments must match the previously ");
206 printoutc(fd, "inserted rule, except the <filter_action> and the <priority> that get discarded.");
207 printoutc(fd, "");
208 printoutc(fd, "Please note that the rules will be processed on the inverse order as they were ");
209 printoutc(fd, "inserted, so to drop all packets from eth0 except those coming from 10.0.0.3, insert");
210 printoutc(fd, "the rules in the followinf order (generic to specific):");
211 printoutc(fd, "");
212 printoutc(fd, "ipfilter add src eth0 drop");
213 printoutc(fd, "ipfilter add src eth0 from 10.0.0.3 255.255.255.255 accept");
214 printoutc(fd, "");
215 printoutc(fd, "other Examples:");
216 printoutc(fd, "");
217 printoutc(fd, "ipfilter");
218 printoutc(fd, "ipfilter add src eth1 tos 2 to 172.16.0.0 255.255.0.0 prio 7");
219 printoutc(fd, "ipfilter del src eth1 tos 2 to 172.16.0.0 255.255.0.0");
220 return 0;
221 } else if (match_input("arp",arg)) {
222 printoutc(fd, "Syntax:");
223 printoutc(fd, "\tarp");
224 return 0;
225 } else if (match_input("stats",arg)) {
226 printoutc(fd, "Syntax:");
227 printoutc(fd, "\tstats");
228 return 0;
229 } else if (match_input("logout",arg)) {
230 printoutc(fd, "Syntax:");
231 printoutc(fd, "\tlogout");
232 return 0;
233 } else if (match_input("shutdown",arg)) {
234 printoutc(fd, "Syntax:");
235 printoutc(fd, "\tshutdown");
236 return 0;
237 } else {
238 printoutc(fd, "No help available for %s", arg);
240 return ENOENT;
243 static int logout(int fd,char *s)
245 return EPIPE;
248 static int doshutdown(int fd,char *s)
250 exit(0);
254 static int not_understood(int fd, char *s)
256 printoutc(fd, "parameter \"%s\" not understood. Try \"help\"", s);
257 return EINVAL;
260 static void show_ifconfig(int fd, struct vder_iface *iface)
262 struct vder_ip4address *addr;
263 printoutc(fd, "Interface: eth%d mac:%02x:%02x:%02x:%02x:%02x:%02x sock:%s",
264 iface->interface_id, iface->macaddr[0],iface->macaddr[1],iface->macaddr[2],
265 iface->macaddr[3],iface->macaddr[4],iface->macaddr[5],
266 iface->vde_sock
268 addr = iface->address_list;
269 while(addr) {
270 char *txt_address, *txt_netmask;
271 txt_address = strdup(vder_ntoa(addr->address));
272 txt_netmask= strdup(vder_ntoa(addr->netmask));
273 if (addr->address == (uint32_t)(-1))
274 printoutc(fd, "\tAcquiring one IP address via DHCP...");
275 else
276 printoutc(fd, "\taddress: %s netmask: %s", txt_address, txt_netmask);
277 free(txt_address);
278 free(txt_netmask);
279 addr = addr->next;
283 enum command_action_enum {
284 ACTION_DELETE = 0,
285 ACTION_ADD,
286 ACTION_ADD_DEFAULT,
287 ACTION_DEL_DEFAULT
290 static inline int is_unicast(uint32_t addr)
292 uint32_t h_addr = ntohl(addr);
293 if ( (h_addr == 0) ||(h_addr >= 0xe0000000) )
294 return 0;
295 return 1;
298 static inline int is_netmask(uint32_t addr)
300 int i;
301 uint32_t h_netmask = ntohl(addr), valid_value = 0;
302 for (i = 31; i >= 0; i--) {
303 valid_value += (1 << i);
304 if (h_netmask == valid_value)
305 return 1;
307 return 0;
310 static inline int not_a_number(char *p)
312 if (!p)
313 return 1;
314 if ((p[0] < '0') || (p[0] > '9'))
315 return 1;
316 return 0;
319 static struct vder_iface *select_interface(char *arg)
321 struct vder_iface *iface, *selected = NULL;;
322 int iface_id;
325 if (strncmp(arg,"eth",3)) {
326 return NULL;
329 if (not_a_number(arg + 3))
330 return NULL;
332 iface_id = strtol(arg + 3, NULL, 10);
333 iface = Router.iflist;
334 while(iface) {
335 if (iface_id == iface->interface_id) {
336 selected = iface;
337 break;
339 iface = iface->next;
341 return selected;
345 static int ifconfig(int fd,char *s)
347 char *nextargs = NULL, *arg;
348 struct vder_iface *iface;
349 arg = strtok_r(s, " ", &nextargs);
350 if(!arg) {
351 /* No arguments */
352 iface = Router.iflist;
353 while(iface) {
354 show_ifconfig(fd, iface);
355 printoutc(fd, "");
356 iface = iface->next;
358 return 0;
359 } else {
360 struct vder_iface *selected;
361 struct in_addr temp_address, temp_netmask;
362 enum command_action_enum action = -1;
363 selected = select_interface(arg);
364 if (!selected) {
365 printoutc(fd, "Interface %s not found.", arg);
366 return ENOENT;
368 arg = strtok_r(NULL, " ", &nextargs);
369 if (!arg) {
370 show_ifconfig(fd, selected);
371 return 0;
373 if ((!arg) || (strlen(arg) != 3) || ((strncmp(arg, "add", 3) != 0) && (strncmp(arg, "del", 3) != 0))) {
374 printoutc(fd, "Invalid action \"%s\".", arg);
375 return EINVAL;
377 if (strncmp(arg, "del", 3) == 0)
378 action = ACTION_DELETE;
379 else
380 action = ACTION_ADD;
382 arg = strtok_r(NULL, " ", &nextargs);
383 if (!arg) {
384 not_understood(fd, "");
385 return EINVAL;
387 if (match_input("dhcp", arg)) {
388 temp_address.s_addr = (uint32_t)(-1);
389 pthread_create(&selected->dhcpclient, 0, dhcp_client_loop, selected);
391 else if (!inet_aton(arg, &temp_address) || !is_unicast(temp_address.s_addr)) {
392 printoutc(fd, "Invalid address \"%s\"", arg);
393 return EINVAL;
395 arg = strtok_r(NULL, " ", &nextargs);
396 if (!arg && (action == ACTION_ADD) && (temp_address.s_addr != (uint32_t)(-1))) {
397 printoutc(fd, "Error: parameter 'netmask' required.");
398 return EINVAL;
400 if ((action == ACTION_ADD) && (temp_address.s_addr != (uint32_t)(-1)) &&
401 (!inet_aton(arg, &temp_netmask) || !is_netmask(temp_netmask.s_addr))) {
402 printoutc(fd, "Invalid netmask \"%s\"", arg);
403 return EINVAL;
405 if (action == ACTION_ADD) {
406 if (vder_iface_address_add(selected, temp_address.s_addr, temp_netmask.s_addr) != 0)
407 return errno;
408 } else {
409 if (vder_iface_address_del(selected, temp_address.s_addr) != 0)
410 return errno;
414 return 0;
418 static void show_route(int fd, struct vder_route *ro)
420 char *dest = strdup(vder_ntoa(ro->dest_addr));
421 char *netmask = strdup(vder_ntoa(ro->netmask));
422 char *gateway = strdup(vder_ntoa(ro->gateway));
423 if (ro->iface)
424 printoutc(fd, "destination %s netmask %s gw %s via eth%d metric %d %s", dest, netmask, gateway,
425 ro->iface->interface_id, ro->metric,
426 ro->netmask==0?"default":"");
427 else
428 printoutc(fd, "destination %s netmask %s gw %s metric %d %s", dest, netmask, gateway,
429 ro->metric,
430 ro->netmask==0?"default":"");
433 free(dest);
434 free(netmask);
435 free(gateway);
438 static int route(int fd,char *s)
440 char *nextargs = NULL, *arg;
441 struct vder_route *ro;
442 struct vder_iface *selected = NULL;
443 struct in_addr temp_address, temp_netmask, temp_gateway;
444 int metric = 1;
445 enum command_action_enum action = -1;
447 arg = strtok_r(s, " ", &nextargs);
448 if(!arg) {
449 /* No arguments */
450 ro = Router.routing_table;
451 while(ro) {
452 show_route(fd, ro);
453 ro = ro->next;
455 return 0;
458 if ((!arg) || (strlen(arg) != 3) || ((strncmp(arg, "add", 3) != 0) && (strncmp(arg, "del", 3) != 0))) {
459 printoutc(fd, "Invalid action \"%s\".", arg);
460 return EINVAL;
462 if (strncmp(arg, "del", 3) == 0)
463 action = ACTION_DELETE;
464 else
465 action = ACTION_ADD;
467 arg = strtok_r(NULL, " ", &nextargs);
468 if (!arg) {
469 not_understood(fd, "");
470 return EINVAL;
472 if (match_input("default", arg)) {
473 if (action == ACTION_ADD)
474 action = ACTION_ADD_DEFAULT;
475 if (action == ACTION_DELETE) {
476 if (vder_route_del(0, 0, 1))
477 return errno;
478 else
479 return 0;
481 arg = strtok_r(NULL, " ", &nextargs);
484 if (!inet_aton(arg, &temp_address) || !is_unicast(temp_address.s_addr)) {
485 printoutc(fd, "Invalid address \"%s\"", arg);
486 return EINVAL;
489 if (action == ACTION_ADD_DEFAULT) {
490 if (vder_route_add(0, 0, temp_address.s_addr, 1, NULL))
491 return errno;
492 else
493 return 0;
496 arg = strtok_r(NULL, " ", &nextargs);
497 if (!arg) {
498 printoutc(fd, "Error: parameter 'netmask' required.");
499 return EINVAL;
502 if (!inet_aton(arg, &temp_netmask) || !is_netmask(temp_netmask.s_addr)) {
503 printoutc(fd, "Invalid netmask \"%s\"", arg);
504 return EINVAL;
507 arg = strtok_r(NULL, " ", &nextargs);
508 while(arg) {
509 if (match_input("via", arg)) {
510 arg = strtok_r(NULL, " ", &nextargs);
511 selected = select_interface(arg);
512 if (!selected)
513 return EINVAL;
514 } else if (match_input("gw", arg)) {
515 arg = strtok_r(NULL, " ", &nextargs);
516 if (!inet_aton(arg, &temp_gateway) || !is_unicast(temp_gateway.s_addr)) {
517 printoutc(fd, "Invalid gateway \"%s\"", arg);
518 return EINVAL;
520 } else if (match_input("metric", arg)) {
521 arg = strtok_r(NULL, " ", &nextargs);
522 metric = atoi(arg);
523 if (metric < 1) {
524 printoutc(fd, "Invalid metric \"%s\"", arg);
525 return EINVAL;
527 } else {
528 return EINVAL;
530 arg = strtok_r(NULL, " ", &nextargs);
533 if ((action == ACTION_DELETE) &&
534 (vder_route_del(temp_address.s_addr, temp_netmask.s_addr, metric))) {
535 return errno;
536 } else if ((action == ACTION_ADD) &&
537 (vder_route_add(temp_address.s_addr, temp_netmask.s_addr, temp_gateway.s_addr, metric, selected))) {
538 return errno;
540 return 0;
543 const char action_name[4][30] = {"accept", "prio", "reject", "drop" };
545 static void proto_name(uint8_t proto, char *name)
547 switch(proto) {
548 case IPPROTO_ICMP:
549 sprintf(name, "icmp");
550 break;
551 case IPPROTO_IGMP:
552 sprintf(name, "igmp");
553 break;
554 case IPPROTO_TCP:
555 sprintf(name, "tcp");
556 break;
557 case IPPROTO_UDP:
558 sprintf(name, "udp");
559 break;
560 default:
561 sprintf(name, "unknown(%d)", ntohs(proto));
566 static void show_filter(int fd, struct vder_filter *filter)
568 char *saddr_address = strdup(vder_ntoa(filter->saddr.address));
569 char *daddr_address = strdup(vder_ntoa(filter->daddr.address));
570 char *saddr_netmask = strdup(vder_ntoa(filter->saddr.netmask));
571 char *daddr_netmask = strdup(vder_ntoa(filter->daddr.netmask));
572 char source[10] = "any";
573 char tos[10] = "any";
574 char proto[30] = "any";
577 if (filter->src_iface){
578 snprintf(source, 10, "eth%d", filter->src_iface->interface_id);
580 if (filter->tos >= 0) {
581 snprintf(tos, 10, "tos %d", filter->tos);
583 if (filter->proto > 0) {
584 proto_name(filter->proto, proto);
586 printoutc(fd, "[iface: %s] %s:%d/%s -> %s:%d/%s proto %s tos %s verdict: %s Stats: %d packets, %d bytes",
587 source, saddr_address, ntohs(filter->sport), saddr_netmask, daddr_address, ntohs(filter->dport), daddr_netmask, proto, tos,
588 action_name[filter->action], filter->stats_packets, filter->stats_bytes);
590 free(saddr_address);
591 free(saddr_netmask);
592 free(daddr_address);
593 free(daddr_netmask);
597 static int filter(int fd,char *s)
599 struct vder_filter *cur = Router.filtering_table;
600 int action;
601 struct vder_iface *vif = NULL;
602 uint8_t proto = 0;
603 struct in_addr s_addr = {0}, s_nm = {0}, d_addr = {0}, d_nm = {0};
604 uint16_t sport = 0, dport = 0;
605 int tos = -1;
606 uint8_t priority = PRIO_BESTEFFORT;
607 enum filter_action filter_action = filter_invalid;
608 char *nextargs = NULL, *arg;
610 arg = strtok_r(s, " ", &nextargs);
611 if(!arg) {
612 /* No arguments */
613 while(cur) {
614 show_filter(fd, cur);
615 cur = cur->next;
617 return 0;
620 if ((!arg) || (strlen(arg) != 3) || ((strncmp(arg, "add", 3) != 0) && (strncmp(arg, "del", 3) != 0))) {
621 printoutc(fd, "Invalid action \"%s\".", arg);
622 return EINVAL;
624 if (strncmp(arg, "del", 3) == 0)
625 action = ACTION_DELETE;
626 else
627 action = ACTION_ADD;
629 arg = strtok_r(NULL, " ", &nextargs);
630 if (!arg) {
631 not_understood(fd, "");
632 return EINVAL;
635 while(arg) {
636 if (match_input("src", arg)) {
637 arg = strtok_r(NULL, " ", &nextargs);
638 if (!arg)
639 return EINVAL;
640 vif = select_interface(arg);
641 } else if(match_input("proto", arg)) {
642 arg = strtok_r(NULL, " ", &nextargs);
643 if (!arg)
644 return EINVAL;
645 if (not_a_number(arg)) {
646 if (match_input("tcp", arg))
647 proto = IPPROTO_TCP;
648 else if (match_input("udp", arg))
649 proto = IPPROTO_UDP;
650 else if (match_input("igmp", arg))
651 proto = IPPROTO_IGMP;
652 else if (match_input("icmp", arg))
653 proto = IPPROTO_ICMP;
654 else {
655 printoutc(fd, "Invalid protocol \"%s\"", arg);
656 return EINVAL;
658 } else {
659 proto = atoi(arg);
660 if (proto <= 0) {
661 printoutc(fd, "Invalid protocol \"%s\"", arg);
662 return EINVAL;
665 } else if (match_input("from",arg)) {
666 arg = strtok_r(NULL, " ", &nextargs);
667 if (!arg)
668 return EINVAL;
669 if (!inet_aton(arg, &s_addr) || !is_unicast(s_addr.s_addr)) {
670 printoutc(fd, "Invalid from address \"%s\"", arg);
671 return EINVAL;
673 arg = strtok_r(NULL, " ", &nextargs);
674 if (!arg) {
675 printoutc(fd, "from address: netmask is required");
676 return EINVAL;
678 if (!inet_aton(arg, &s_nm) || !is_netmask(s_nm.s_addr)) {
679 printoutc(fd, "Invalid netmask \"%s\"", arg);
680 return EINVAL;
682 } else if (match_input("to",arg)) {
683 arg = strtok_r(NULL, " ", &nextargs);
684 if (!arg)
685 return EINVAL;
686 if (!inet_aton(arg, &d_addr) || !is_unicast(d_addr.s_addr)) {
687 printoutc(fd, "Invalid from address \"%s\"", arg);
688 return EINVAL;
690 arg = strtok_r(NULL, " ", &nextargs);
691 if (!arg) {
692 printoutc(fd, "from address: netmask is required");
693 return EINVAL;
695 if (!inet_aton(arg, &d_nm) || !is_netmask(d_nm.s_addr)) {
696 printoutc(fd, "Invalid netmask \"%s\"", arg);
697 return EINVAL;
699 } else if (match_input("tos",arg)) {
700 arg = strtok_r(NULL, " ", &nextargs);
701 if (!arg)
702 return EINVAL;
703 tos = atoi(arg);
704 if ((tos < 0) || not_a_number(arg)) {
705 printoutc(fd, "Invalid tos %s", arg);
706 return EINVAL;
708 } else if (match_input("sport",arg)) {
709 arg = strtok_r(NULL, " ", &nextargs);
710 if (!arg)
711 return EINVAL;
712 if ((sport < 0) || not_a_number(arg)) {
713 printoutc(fd, "Invalid sport %s", arg);
714 return EINVAL;
716 sport = htons(atoi(arg));
717 } else if (match_input("dport",arg)) {
718 arg = strtok_r(NULL, " ", &nextargs);
719 if (!arg)
720 return EINVAL;
721 if (not_a_number(arg)) {
722 printoutc(fd, "Invalid dport %s", arg);
723 return EINVAL;
725 dport = htons(atoi(arg));
726 } else if (match_input("prio",arg)) {
727 if (filter_action != filter_invalid) {
728 printoutc(fd, "Invalid double action for filter");
730 arg = strtok_r(NULL, " ", &nextargs);
731 if (!arg)
732 return EINVAL;
733 priority = atoi(arg);
734 if ((priority < 0) || (priority >= PRIO_NUM) || not_a_number(arg)) {
735 printoutc(fd, "Invalid priority %s", arg);
736 return EINVAL;
738 filter_action = filter_priority;
739 } else if (match_input("accept",arg)) {
740 if (filter_action != filter_invalid) {
741 printoutc(fd, "Invalid double action for filter");
743 filter_action = filter_accept;
744 } else if (match_input("reject",arg)) {
745 if (filter_action != filter_invalid) {
746 printoutc(fd, "Invalid double action for filter");
748 filter_action = filter_reject;
749 } else if (match_input("drop",arg)) {
750 if (filter_action != filter_invalid) {
751 printoutc(fd, "Invalid double action for filter");
753 filter_action = filter_drop;
755 arg = strtok_r(NULL, " ", &nextargs);
757 if ((filter_action == filter_invalid) && (action == ACTION_ADD)) {
758 printoutc(fd, "Error: an action is required for filter");
759 return EINVAL;
761 if (action == ACTION_ADD) {
762 if (vder_filter_add(vif, proto, s_addr.s_addr, s_nm.s_addr, d_addr.s_addr, d_nm.s_addr, tos, sport, dport, filter_action, priority))
763 return errno;
764 } else {
765 if (vder_filter_del(vif, proto, s_addr.s_addr, s_nm.s_addr, d_addr.s_addr, d_nm.s_addr, tos, sport, dport))
766 return errno;
768 return 0;
772 static void fill_queue_info(struct vder_queue *q, char *info)
774 if(!q)
775 return;
776 switch(q->policy) {
777 case QPOLICY_UNLIMITED:
778 snprintf(info, MAXCMD, "unlimited");
779 break;
780 case QPOLICY_FIFO:
781 snprintf(info, MAXCMD, "pfifo limit: %u (%d packets dropped)",
782 q->policy_opt.fifo.limit,
783 q->policy_opt.fifo.stats_drop);
784 break;
785 case QPOLICY_RED:
786 snprintf(info, MAXCMD, "red min: %u, max: %u, probability: %lf limit: %u (%d packets dropped, %d packets fired)",
787 q->policy_opt.red.min,
788 q->policy_opt.red.max,
789 q->policy_opt.red.P,
790 q->policy_opt.red.limit,
791 q->policy_opt.red.stats_drop,
792 q->policy_opt.red.stats_probability_drop
794 break;
795 case QPOLICY_TOKEN:
796 snprintf(info, MAXCMD, "token interval: %llu usec, limit: %u (%u packets dropped)",
797 q->policy_opt.token.interval,
798 q->policy_opt.token.limit,
799 q->policy_opt.token.stats_drop);
800 break;
805 static void show_queues(int fd, struct vder_iface *vif)
807 char ifname[10];
808 char queue_info[MAXCMD];
809 int i;
810 if (!vif)
811 return;
813 snprintf(ifname, 10, "eth%d", vif->interface_id);
815 fill_queue_info(&vif->out_q, queue_info);
816 printoutc(fd, "%s:output %s size: %lu", ifname, queue_info, vif->out_q.size);
817 for (i = 0; i < 32; i++) {
818 fill_queue_info(&vif->prio_q[i], queue_info);
819 printoutc(fd, "%s:prio%d %s size: %lu", ifname, i, queue_info, vif->prio_q[i].size);
824 /*!! Warning !!*/
825 /* 0 == ERROR here! */
826 double get_labeled_arg(int fd, char *label, char **nextargs) {
827 char *arg = strtok_r(NULL, " ", nextargs);
828 if (!arg) {
829 printoutc(fd, "missing parameter '%s'", label);
830 return 0.0; //error
832 if (!match_input(label, arg)) {
833 printoutc(fd, "invalid parameter \"%s\", expecting \"%s\"", arg, label);
834 return 0.0; //error
836 arg = strtok_r(NULL, " ", nextargs);
837 if (not_a_number(arg) && arg[0] != '.') {
838 printoutc(fd, "invalid value \"%s\"", arg);
839 return 0.0; //error
841 return strtod(arg, NULL);
846 static int queue(int fd, char *s)
848 struct vder_iface *cur = Router.iflist, *selected = NULL;
849 struct vder_queue *q;
850 char *nextargs, *arg;
851 int if_id;
852 int prio_id = -1;
853 char output_word[MAXCMD] = "";
854 enum queue_policy_e newpolicy;
856 arg = strtok_r(s, " ", &nextargs);
857 if(!arg) {
858 /* No arguments */
859 while(cur) {
860 show_queues(fd, cur);
861 cur = cur->next;
863 return 0;
865 if ((sscanf(arg, "eth%d:prio%d", &if_id, &prio_id) != 2) && (sscanf(arg, "eth%d:%s", &if_id, output_word) != 2))
866 return EINVAL;
867 else {
868 if (prio_id < 0 && !match_input("output", output_word)) {
869 return EINVAL;
871 cur = Router.iflist;
872 while(cur) {
873 if (cur->interface_id == if_id) {
874 selected = cur;
875 break;
877 cur = cur->next;
880 if (!selected) {
881 printoutc(fd, "Cannot find interface eth%d", if_id);
882 return ENOENT;
885 /* Match policy */
886 arg = strtok_r(NULL, " ", &nextargs);
887 if (!arg) {
888 printoutc(fd, "queue: queue policy required");
889 return EINVAL;
891 if (match_input("unlimited", arg)) {
892 newpolicy = QPOLICY_UNLIMITED;
893 } else if (match_input("fifo", arg)) {
894 newpolicy = QPOLICY_FIFO;
895 } else if (match_input("red", arg)) {
896 newpolicy = QPOLICY_RED;
897 } else if (match_input("token", arg)) {
898 newpolicy = QPOLICY_TOKEN;
899 } else {
900 printoutc(fd, "queue: invalid queue policy \"%s\"", arg);
901 return EINVAL;
903 if (prio_id >= 0) {
904 if (prio_id > 31) {
905 printoutc(fd, "Invalid priority queue %s", arg);
906 return EINVAL;
908 q = &selected->prio_q[prio_id];
909 } else {
910 printoutc(fd, "selected if=%d, outq", if_id);
911 q = &selected->out_q;
914 /* Match arguments */
915 if (newpolicy == QPOLICY_UNLIMITED) {
916 qunlimited_setup(q);
917 } else if (newpolicy == QPOLICY_FIFO) {
918 uint32_t limit;
919 arg = strtok_r(NULL, " ", &nextargs);
920 if (!arg) {
921 printoutc(fd, "fifo: missing parameter 'limit'");
922 return EINVAL;
924 if (!match_input("limit", arg)) {
925 printoutc(fd, "fifo: invalid parameter \"%s\"", arg);
926 return EINVAL;
928 arg = strtok_r(NULL, " ", &nextargs);
929 if (not_a_number(arg)) {
930 printoutc(fd, "fifo: invalid limit");
931 return EINVAL;
933 limit = strtol(arg, NULL, 10);
934 qfifo_setup(q,limit);
936 } else if (newpolicy == QPOLICY_RED) {
937 uint32_t min, max, limit;
938 double P;
939 min = (uint32_t) get_labeled_arg(fd,"min", &nextargs);
940 max = (uint32_t) get_labeled_arg(fd,"max", &nextargs);
941 P = get_labeled_arg(fd,"probability", &nextargs);
942 limit = (uint32_t) get_labeled_arg(fd,"limit", &nextargs);
943 if (!min || !max || !limit)
944 return EINVAL;
945 qred_setup(q, min, max, P, limit);
946 } else if (newpolicy == QPOLICY_TOKEN) {
947 uint32_t limit, bitrate;
948 limit = (uint32_t) get_labeled_arg(fd, "limit", &nextargs);
949 bitrate = (uint32_t) get_labeled_arg(fd, "bitrate", &nextargs);
950 if (!limit || !bitrate)
951 return EINVAL;
952 qtoken_setup(q, bitrate, limit);
954 return 0;
958 static int doconnect(int fd,char *s)
960 char *nextargs = NULL, *arg;
961 struct vder_iface *created = NULL;
962 int mac[6];
963 uint8_t outmac[6], *newmac = NULL;
964 char sock[1024];
966 arg = strtok_r(s, " ", &nextargs);
967 if (!arg) {
968 printoutc(fd, "sock argument is required.");
969 return EINVAL;
970 } else {
971 strncpy(sock, arg, 1023);
973 arg = strtok_r(NULL, " ", &nextargs);
974 if (arg) {
975 if ((sscanf(arg,"%02x:%02x:%02x:%02x:%02x:%02x",&mac[0],
976 &mac[1], &mac[2], &mac[3], &mac[4], &mac[5] )) != ETHERNET_ADDRESS_SIZE) {
978 printoutc(fd, "invalid mac address \"%s\"", arg);
979 return EINVAL;
980 } else {
981 outmac[0] = (uint8_t)mac[0];
982 outmac[1] = (uint8_t)mac[1];
983 outmac[2] = (uint8_t)mac[2];
984 outmac[3] = (uint8_t)mac[3];
985 outmac[4] = (uint8_t)mac[4];
986 outmac[5] = (uint8_t)mac[5];
987 newmac = outmac;
990 created = vder_iface_new(sock, newmac);
991 if (created == NULL)
992 return errno;
993 pthread_create(&created->sender, 0, vder_core_send_loop, created);
994 pthread_create(&created->receiver, 0, vder_core_recv_loop, created);
995 pthread_create(&created->queue_manager, 0, vder_core_queuer_loop, created);
997 printoutc(fd, "Created interface eth%d", created->interface_id);
998 return 0;
1001 static int stats(int fd, char *args)
1003 struct vder_iface *iface;
1004 if (strlen(args) > 0)
1005 return EINVAL;
1006 iface = Router.iflist;
1007 while(iface) {
1008 printoutc(fd, "eth%d frames sent:%d, frames received:%d",
1009 iface->interface_id, iface->stats.sent, iface->stats.recvd);
1010 printoutc(fd, "");
1011 iface = iface->next;
1013 return 0;
1016 static int arp(int fd, char *args)
1018 struct vder_iface *iface;
1019 struct rb_node *node;
1020 if (strlen(args) > 0)
1021 return EINVAL;
1022 iface = Router.iflist;
1023 while(iface) {
1024 node = iface->arp_table.rb_node;
1025 while (node) {
1026 struct vder_arp_entry *ae = rb_entry(node, struct vder_arp_entry, rb_node);
1027 char *txt_address = strdup(vder_ntoa(ae->ipaddr));
1028 printoutc(fd, "%s %02x:%02x:%02x:%02x:%02x:%02x (eth%d)", txt_address,
1029 ae->macaddr[0], ae->macaddr[1], ae->macaddr[2], ae->macaddr[3], ae->macaddr[4], ae->macaddr[5],
1030 iface->interface_id);
1031 free(txt_address);
1032 node = node->rb_left;
1034 node = iface->arp_table.rb_node;
1035 if (node)
1036 node = node->rb_right;
1037 while (node) {
1038 struct vder_arp_entry *ae = rb_entry(node, struct vder_arp_entry, rb_node);
1039 char *txt_address = strdup(vder_ntoa(ae->ipaddr));
1040 printoutc(fd, "%s %02x:%02x:%02x:%02x:%02x:%02x (eth%d)", txt_address,
1041 ae->macaddr[0], ae->macaddr[1], ae->macaddr[2], ae->macaddr[3], ae->macaddr[4], ae->macaddr[5],
1042 iface->interface_id);
1043 free(txt_address);
1044 node = node->rb_right;
1046 iface = iface->next;
1048 return 0;
1052 #define DEFAULT_LEASE_TIME htonl(0xa8c0)
1053 static int dhcpd(int fd,char *s)
1055 char *nextargs = NULL, *arg;
1056 struct vder_dhcpd_settings *dhcpd_settings;
1057 struct vder_iface *selected = NULL;
1058 struct in_addr temp_pool_start, temp_pool_end;
1059 enum command_action_enum action = -1;
1061 arg = strtok_r(s, " ", &nextargs);
1062 if(!arg) {
1063 printoutc(fd, "Error: arguments required");
1064 return EINVAL;
1066 if ((!arg) || (strlen(arg) < 4) || ((strncmp(arg, "start", 5) != 0) && (strncmp(arg, "stop", 4) != 0))) {
1067 printoutc(fd, "Invalid action \"%s\".", arg);
1068 return EINVAL;
1070 if (strncmp(arg, "start", 5) == 0)
1071 action = ACTION_ADD;
1072 else
1073 action = ACTION_DELETE;
1076 arg = strtok_r(NULL, " ", &nextargs);
1077 if (!arg) {
1078 not_understood(fd, "");
1079 return EINVAL;
1081 if ((strlen(arg) < 4) || (strncmp(arg, "eth", 3)!= 0)) {
1082 printoutc(fd, "Invalid interface \"%s\".", arg);
1083 return EINVAL;
1085 selected = select_interface(arg);
1086 if (!selected)
1087 return ENXIO;
1089 if (action == ACTION_ADD) {
1090 arg = strtok_r(NULL, " ", &nextargs);
1091 if (!arg) {
1092 not_understood(fd, "");
1093 return EINVAL;
1096 if (!inet_aton(arg, &temp_pool_start) || !is_unicast(temp_pool_start.s_addr)) {
1097 printoutc(fd, "Invalid pool start address \"%s\"", arg);
1098 return EINVAL;
1101 arg = strtok_r(NULL, " ", &nextargs);
1102 if (!arg) {
1103 not_understood(fd, "");
1104 return EINVAL;
1106 if (!inet_aton(arg, &temp_pool_end) || !is_unicast(temp_pool_end.s_addr)) {
1107 printoutc(fd, "Invalid pool end address \"%s\"", arg);
1108 return EINVAL;
1111 dhcpd_settings = malloc(sizeof(struct vder_dhcpd_settings));
1112 if (!dhcpd_settings)
1113 return ENOMEM;
1115 dhcpd_settings->iface = selected;
1116 dhcpd_settings->my_ip = vder_get_right_localip(selected, temp_pool_start.s_addr);
1117 dhcpd_settings->netmask = vder_get_netmask(selected, dhcpd_settings->my_ip);
1118 dhcpd_settings->pool_start = temp_pool_start.s_addr;
1119 dhcpd_settings->pool_end = temp_pool_end.s_addr;
1120 dhcpd_settings->lease_time = DEFAULT_LEASE_TIME;
1121 dhcpd_settings->flags = 0;
1122 selected->dhcpd_started = 1;
1123 pthread_create(&selected->dhcpd, 0, dhcp_server_loop, dhcpd_settings);
1124 } else if (selected->dhcpd_started) {
1125 pthread_cancel(selected->dhcpd);
1126 selected->dhcpd_started = 0;
1128 return 0;
1131 static int olsr(int fd,char *s)
1133 char *nextargs = NULL, *arg;
1134 struct olsr_setup *olsr_settings;
1135 struct vder_iface *selected = NULL;
1136 enum command_action_enum action = -1;
1137 static pthread_t olsr_thread;
1140 arg = strtok_r(s, " ", &nextargs);
1141 if(!arg) {
1142 printoutc(fd, "Error: arguments required");
1143 return EINVAL;
1145 if ((!arg) || (strlen(arg) < 4) || ((strncmp(arg, "start", 5) != 0) && (strncmp(arg, "stop", 4) != 0))) {
1146 printoutc(fd, "Invalid action \"%s\".", arg);
1147 return EINVAL;
1149 if (strncmp(arg, "start", 5) == 0)
1150 action = ACTION_ADD;
1151 else
1152 action = ACTION_DELETE;
1154 if (action == ACTION_ADD) {
1155 olsr_settings = malloc(sizeof(struct olsr_setup));
1156 memset(olsr_settings, 0, sizeof(struct olsr_setup));
1157 arg = strtok_r(NULL, " ", &nextargs);
1158 while (arg) {
1159 if ((strlen(arg) < 4) || (strncmp(arg, "eth", 3)!= 0)) {
1160 printoutc(fd, "Invalid interface \"%s\".", arg);
1161 free(olsr_settings);
1162 return EINVAL;
1164 selected = select_interface(arg);
1165 if (!selected) {
1166 free(olsr_settings);
1167 return ENXIO;
1169 olsr_settings->ifaces[olsr_settings->n_ifaces++] = selected;
1170 arg = strtok_r(NULL, " ", &nextargs);
1172 if (olsr_settings->n_ifaces == 0) {
1173 free(olsr_settings);
1174 return EINVAL;
1176 pthread_create(&olsr_thread, 0, vder_olsr_loop, olsr_settings);
1177 } else {
1178 pthread_cancel(olsr_thread);
1179 /* stop */
1181 return 0;
1185 #define WITHFILE 0x80
1186 static struct comlist {
1187 char *tag;
1188 int (*fun)(int fd,char *arg);
1189 unsigned char type;
1190 } commandlist [] = {
1191 {"help", help, WITHFILE},
1192 {"ifconfig", ifconfig, WITHFILE},
1193 {"arp", arp, WITHFILE},
1194 {"route", route, WITHFILE},
1195 {"connect", doconnect, 0},
1196 {"stats", stats, WITHFILE},
1197 {"ipfilter", filter, WITHFILE},
1198 {"queue", queue, WITHFILE},
1199 {"dhcpd", dhcpd, 0 },
1200 {"olsr", olsr, 0 },
1201 {"logout",logout, 0},
1202 {"shutdown",doshutdown, 0}
1205 #define NCL sizeof(commandlist)/sizeof(struct comlist)
1207 static inline void delnl(char *buf)
1209 int len=strlen(buf)-1;
1210 while (len>0 &&
1211 (buf[len]=='\n' || buf[len]==' ' || buf[len]=='\t')) {
1212 buf[len]=0;
1213 len--;
1217 static int handle_cmd(int fd,char *inbuf)
1219 int rv=ENOSYS;
1220 int i;
1221 char *cmd=inbuf;
1222 while (*inbuf == ' ' || *inbuf == '\t' || *inbuf == '\n') inbuf++;
1223 delnl(inbuf);
1224 if (*inbuf != '\0' && *inbuf != '#') {
1225 for (i=0; i<NCL
1226 && strncmp(commandlist[i].tag,inbuf,strlen(commandlist[i].tag))!=0;
1227 i++)
1229 if (i<NCL)
1231 inbuf += strlen(commandlist[i].tag);
1232 while (*inbuf == ' ' || *inbuf == '\t') inbuf++;
1233 if (fd>=0 && commandlist[i].type & WITHFILE)
1234 printoutc(fd,"0000 DATA END WITH '.'");
1235 rv=commandlist[i].fun(fd,inbuf);
1236 if (fd>=0 && commandlist[i].type & WITHFILE)
1237 printoutc(fd,".");
1239 if (fd >= 0) {
1240 if (rv == 0) {
1241 printoutc(fd,"1000 Success");
1242 } else {
1243 printoutc(fd,"1%03d %s",rv,strerror(rv));
1245 } else if (rv != 0) {
1246 fprintf(stderr,"rc command error: %s %s",cmd,strerror(rv));
1248 return rv;
1250 return rv;
1254 static int mgmtcommand(int fd)
1256 char buf[MAXCMD+1];
1257 int n,rv;
1258 int outfd=fd;
1259 if (fd==STDIN_FILENO)
1260 outfd=STDOUT_FILENO;
1262 n = read(fd, buf, MAXCMD);
1263 if (n<0) {
1264 fprintf(stderr,"%s: read from mgmt %s",progname,strerror(errno));
1265 return -1;
1267 else if (n==0){
1268 return -1;
1269 /* Remote end has closed connection. */
1271 else {
1272 buf[n]=0;
1273 rv=handle_cmd(outfd,buf);
1274 if (rv>=0)
1275 write(outfd,prompt,strlen(prompt));
1276 return rv;
1280 static int delmgmtconn(int i,struct pollfd *pfd,int nfds)
1282 if (i<nfds) {
1283 close(pfd[i].fd);
1284 if (pfd[i].fd == STDIN_FILENO) /* close stdin implies exit */
1285 exit(0);
1286 memmove(pfd+i,pfd+i+1,sizeof (struct pollfd) * (nfds-i-1));
1287 nfds--;
1289 return nfds;
1292 static int openmgmt(char *mgmt)
1294 int mgmtconnfd;
1295 struct sockaddr_un sun;
1296 int one = 1;
1298 if((mgmtconnfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0){
1299 fprintf(stderr,"%s: mgmt socket: %s",progname,strerror(errno));
1300 exit(1);
1302 if(setsockopt(mgmtconnfd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
1303 sizeof(one)) < 0){
1304 fprintf(stderr,"%s: mgmt setsockopt: %s",progname,strerror(errno));
1305 exit(1);
1307 if(fcntl(mgmtconnfd, F_SETFL, O_NONBLOCK) < 0){
1308 fprintf(stderr,"%s: Setting O_NONBLOCK on mgmt fd: %s",progname,strerror(errno));
1309 exit(1);
1311 sun.sun_family = PF_UNIX;
1312 snprintf(sun.sun_path,sizeof(sun.sun_path),"%s",mgmt);
1313 if(bind(mgmtconnfd, (struct sockaddr *) &sun, sizeof(sun)) < 0){
1314 fprintf(stderr,"%s: mgmt bind %s",progname,strerror(errno));
1315 exit(1);
1317 chmod(sun.sun_path,mgmtmode);
1318 if(listen(mgmtconnfd, 15) < 0){
1319 fprintf(stderr,"%s: mgmt listen: %s",progname,strerror(errno));
1320 exit(1);
1322 return mgmtconnfd;
1325 int config_readline (int fd, char *l)
1327 int len = 0;
1328 while(read(fd, &l[len], 1) > 0) {
1330 /* Skip leading spaces and empty lines */
1331 if ((len == 0) && (l[len]=='\n' || l[len]==' ' || l[len]=='\t'))
1332 continue;
1334 if (l[len] == '\n') {
1335 l[len] = (char)0;
1336 break;
1337 } else {
1338 if (++len == MAXCMD) {
1339 l[MAXCMD-1] = 0;
1340 break;
1344 return len;
1347 #define MAXCONN 6
1348 static int newmgmtconn(int fd,struct pollfd *pfd,int nfds)
1350 int new;
1351 unsigned int len;
1352 char buf[MAXCMD];
1353 struct sockaddr addr;
1354 new = accept(fd, &addr, &len);
1355 if(new < 0) {
1356 fprintf(stderr, "mgmt accept %s",strerror(errno));
1357 return nfds;
1359 if (nfds < MAXCONN) {
1360 snprintf(buf,MAXCMD,header);
1361 write(new,buf,strlen(buf));
1362 write(new,prompt,strlen(prompt));
1363 pfd[nfds].fd=new;
1364 pfd[nfds].events=POLLIN | POLLHUP;
1365 return ++nfds;
1366 } else {
1367 fprintf(stderr,"too many mgmt connections\n");
1368 close (new);
1369 return nfds;
1373 void cleanup(void)
1375 if(mgmt)
1376 unlink(mgmt);
1379 void usage(void)
1381 fprintf(stderr, "Usage: %s [-c configfile] [-M mgmt_socket] [-m mgmt_mode] [-p pidfile] [-d]\n", progname);
1382 exit(1);
1385 int main(int argc, char *argv[])
1387 char cmd[MAXCMD];
1388 int npfd = 0;
1389 struct pollfd pfd[MAXCONN];
1390 int mgmtindex = -1;
1391 int i, n, daemon = 0;
1392 char *pidfile = NULL, *configfile = NULL;
1393 int option_index;
1394 static struct option long_options[] = {
1395 {"help",0 , 0, 'h'},
1396 {"config",1 , 0, 'c'},
1397 {"mgmt", 1, 0, 'M'},
1398 {"mgmtmode", 1, 0, 'm'},
1399 {"daemon",0 , 0, 'd'},
1400 {"pidfile", 1, 0, 'p'},
1401 {0,0,0,0}
1403 progname=basename(argv[0]);
1404 vderouter_init();
1405 atexit(cleanup);
1407 while(1) {
1408 int c;
1409 c = getopt_long (argc, argv, "hM:c:dmp:", long_options, &option_index);
1410 if (c<0)
1411 break;
1412 switch (c) {
1413 case 'h':
1414 usage();
1415 break;
1416 case 'c':
1417 configfile = strdup(optarg);
1418 break;
1419 case 'M':
1420 mgmt=strdup(optarg);
1421 break;
1422 case 'm':
1423 sscanf(optarg,"%o",&mgmtmode);
1424 break;
1425 case 'd':
1426 daemon=1;
1427 break;
1428 case 'p':
1429 pidfile=strdup(optarg);
1430 break;
1431 default:
1432 usage();
1433 break;
1436 if (optind < argc)
1437 usage();
1439 if (configfile) {
1440 int fd = open(configfile, O_RDONLY);
1441 if (fd < 0) {
1442 perror("Opening configuration file");
1443 exit(1);
1445 while (config_readline(fd,cmd) > 0) {
1446 handle_cmd(STDOUT_FILENO, cmd);
1448 close(fd);
1451 if (daemon) {
1452 close(STDIN_FILENO);
1453 close(STDOUT_FILENO);
1454 if (fork() > 0) {
1455 exit (0);
1457 if (fork() > 0) {
1458 exit (0);
1460 setsid();
1461 } else {
1462 pfd[npfd].fd = STDIN_FILENO;
1463 pfd[npfd].events = POLLIN | POLLHUP;
1464 write(STDOUT_FILENO,header,strlen(header));
1465 write(STDOUT_FILENO,prompt,strlen(prompt));
1466 npfd++;
1469 if (pidfile) {
1470 int pid_fd = open(pidfile, O_WRONLY|O_CREAT|O_TRUNC, 0644);
1471 char pidstr[7] = "";
1472 if (pid_fd >= 0) {
1473 snprintf(pidstr, 6, "%d", getpid());
1474 write(pid_fd, pidstr, strlen(pidstr));
1475 close(pid_fd);
1476 } else {
1477 fprintf(stderr, "Cannot open pidfile: %s", strerror(errno));
1481 if(mgmt != NULL) {
1482 int mgmtfd = openmgmt(mgmt);
1483 mgmtindex = npfd;
1484 pfd[npfd].fd = mgmtfd;
1485 pfd[npfd].events = POLLIN | POLLHUP;
1486 npfd++;
1490 while(1) {
1491 n = poll(pfd, npfd, -1);
1492 if (n>0) {
1493 for (i = 0; i < npfd; i++) {
1494 if ((pfd[i].revents == POLLIN) && (i == mgmtindex)) {
1495 npfd = newmgmtconn(pfd[i].fd, pfd, npfd);
1496 break;
1497 } else if (i != mgmtindex) {
1498 if (pfd[i].revents == POLLIN) {
1499 mgmtcommand(pfd[i].fd);
1500 } else if (pfd[i].revents&POLLHUP) {
1501 npfd = delmgmtconn(i, pfd, npfd);
1502 break;
1508 exit(0);