1 /* VDE_ROUTER (C) 2007:2011 Daniele Lacamera
3 * Licensed under the GPLv2
5 * Description: this module is just a frontend for command line,
8 * For the router engine see vder_datalink.c
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"
24 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
34 static int mgmtmode
=0700;
35 static char *progname
;
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
, ...)
48 char outbuf
[MAXCMD
+1];
50 va_start (arg
, format
);
51 vsnprintf(outbuf
,MAXCMD
,format
,arg
);
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
);
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");
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.");
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.");
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");
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.");
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");
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.");
118 printoutc(fd
, "Examples:");
119 printoutc(fd
, "dhcpd start eth0 10.0.0.101 10.0.0.120");
120 printoutc(fd
, "dhcpd stop eth0");
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");
130 printoutc(fd
, "Examples:");
131 printoutc(fd
, "olsr start eth0 eth1");
132 printoutc(fd
, "olsr stop");
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.");
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");
152 } else if (match_input("queue",arg
)) {
153 printoutc(fd
, "Syntax:");
154 printoutc(fd
, "\tqueue [<devname>:<queuename> <policy> <policy_options>]");
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.");
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\".");
164 printoutc(fd
, "The following policies are available:");
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.");
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.");
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).");
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");
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.");
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):");
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");
215 printoutc(fd
, "other Examples:");
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");
221 } else if (match_input("arp",arg
)) {
222 printoutc(fd
, "Syntax:");
223 printoutc(fd
, "\tarp");
225 } else if (match_input("stats",arg
)) {
226 printoutc(fd
, "Syntax:");
227 printoutc(fd
, "\tstats");
229 } else if (match_input("logout",arg
)) {
230 printoutc(fd
, "Syntax:");
231 printoutc(fd
, "\tlogout");
233 } else if (match_input("shutdown",arg
)) {
234 printoutc(fd
, "Syntax:");
235 printoutc(fd
, "\tshutdown");
238 printoutc(fd
, "No help available for %s", arg
);
243 static int logout(int fd
,char *s
)
248 static int doshutdown(int fd
,char *s
)
254 static int not_understood(int fd
, char *s
)
256 printoutc(fd
, "parameter \"%s\" not understood. Try \"help\"", s
);
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],
268 addr
= iface
->address_list
;
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...");
276 printoutc(fd
, "\taddress: %s netmask: %s", txt_address
, txt_netmask
);
283 enum command_action_enum
{
290 static inline int is_unicast(uint32_t addr
)
292 uint32_t h_addr
= ntohl(addr
);
293 if ( (h_addr
== 0) ||(h_addr
>= 0xe0000000) )
298 static inline int is_netmask(uint32_t addr
)
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
)
310 static inline int not_a_number(char *p
)
314 if ((p
[0] < '0') || (p
[0] > '9'))
319 static struct vder_iface
*select_interface(char *arg
)
321 struct vder_iface
*iface
, *selected
= NULL
;;
325 if (strncmp(arg
,"eth",3)) {
329 if (not_a_number(arg
+ 3))
332 iface_id
= strtol(arg
+ 3, NULL
, 10);
333 iface
= Router
.iflist
;
335 if (iface_id
== iface
->interface_id
) {
345 static int ifconfig(int fd
,char *s
)
347 char *nextargs
= NULL
, *arg
;
348 struct vder_iface
*iface
;
349 arg
= strtok_r(s
, " ", &nextargs
);
352 iface
= Router
.iflist
;
354 show_ifconfig(fd
, iface
);
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
);
365 printoutc(fd
, "Interface %s not found.", arg
);
368 arg
= strtok_r(NULL
, " ", &nextargs
);
370 show_ifconfig(fd
, selected
);
373 if ((!arg
) || (strlen(arg
) != 3) || ((strncmp(arg
, "add", 3) != 0) && (strncmp(arg
, "del", 3) != 0))) {
374 printoutc(fd
, "Invalid action \"%s\".", arg
);
377 if (strncmp(arg
, "del", 3) == 0)
378 action
= ACTION_DELETE
;
382 arg
= strtok_r(NULL
, " ", &nextargs
);
384 not_understood(fd
, "");
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
);
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.");
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
);
405 if (action
== ACTION_ADD
) {
406 if (vder_iface_address_add(selected
, temp_address
.s_addr
, temp_netmask
.s_addr
) != 0)
409 if (vder_iface_address_del(selected
, temp_address
.s_addr
) != 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
));
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":"");
428 printoutc(fd
, "destination %s netmask %s gw %s metric %d %s", dest
, netmask
, gateway
,
430 ro
->netmask
==0?"default":"");
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
;
445 enum command_action_enum action
= -1;
447 arg
= strtok_r(s
, " ", &nextargs
);
450 ro
= Router
.routing_table
;
458 if ((!arg
) || (strlen(arg
) != 3) || ((strncmp(arg
, "add", 3) != 0) && (strncmp(arg
, "del", 3) != 0))) {
459 printoutc(fd
, "Invalid action \"%s\".", arg
);
462 if (strncmp(arg
, "del", 3) == 0)
463 action
= ACTION_DELETE
;
467 arg
= strtok_r(NULL
, " ", &nextargs
);
469 not_understood(fd
, "");
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))
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
);
489 if (action
== ACTION_ADD_DEFAULT
) {
490 if (vder_route_add(0, 0, temp_address
.s_addr
, 1, NULL
))
496 arg
= strtok_r(NULL
, " ", &nextargs
);
498 printoutc(fd
, "Error: parameter 'netmask' required.");
502 if (!inet_aton(arg
, &temp_netmask
) || !is_netmask(temp_netmask
.s_addr
)) {
503 printoutc(fd
, "Invalid netmask \"%s\"", arg
);
507 arg
= strtok_r(NULL
, " ", &nextargs
);
509 if (match_input("via", arg
)) {
510 arg
= strtok_r(NULL
, " ", &nextargs
);
511 selected
= select_interface(arg
);
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
);
520 } else if (match_input("metric", arg
)) {
521 arg
= strtok_r(NULL
, " ", &nextargs
);
524 printoutc(fd
, "Invalid metric \"%s\"", arg
);
530 arg
= strtok_r(NULL
, " ", &nextargs
);
533 if ((action
== ACTION_DELETE
) &&
534 (vder_route_del(temp_address
.s_addr
, temp_netmask
.s_addr
, metric
))) {
536 } else if ((action
== ACTION_ADD
) &&
537 (vder_route_add(temp_address
.s_addr
, temp_netmask
.s_addr
, temp_gateway
.s_addr
, metric
, selected
))) {
543 const char action_name
[4][30] = {"accept", "prio", "reject", "drop" };
545 static void proto_name(uint8_t proto
, char *name
)
549 sprintf(name
, "icmp");
552 sprintf(name
, "igmp");
555 sprintf(name
, "tcp");
558 sprintf(name
, "udp");
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
);
597 static int filter(int fd
,char *s
)
599 struct vder_filter
*cur
= Router
.filtering_table
;
601 struct vder_iface
*vif
= NULL
;
603 struct in_addr s_addr
= {0}, s_nm
= {0}, d_addr
= {0}, d_nm
= {0};
604 uint16_t sport
= 0, dport
= 0;
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
);
614 show_filter(fd
, cur
);
620 if ((!arg
) || (strlen(arg
) != 3) || ((strncmp(arg
, "add", 3) != 0) && (strncmp(arg
, "del", 3) != 0))) {
621 printoutc(fd
, "Invalid action \"%s\".", arg
);
624 if (strncmp(arg
, "del", 3) == 0)
625 action
= ACTION_DELETE
;
629 arg
= strtok_r(NULL
, " ", &nextargs
);
631 not_understood(fd
, "");
636 if (match_input("src", arg
)) {
637 arg
= strtok_r(NULL
, " ", &nextargs
);
640 vif
= select_interface(arg
);
641 } else if(match_input("proto", arg
)) {
642 arg
= strtok_r(NULL
, " ", &nextargs
);
645 if (not_a_number(arg
)) {
646 if (match_input("tcp", arg
))
648 else if (match_input("udp", arg
))
650 else if (match_input("igmp", arg
))
651 proto
= IPPROTO_IGMP
;
652 else if (match_input("icmp", arg
))
653 proto
= IPPROTO_ICMP
;
655 printoutc(fd
, "Invalid protocol \"%s\"", arg
);
661 printoutc(fd
, "Invalid protocol \"%s\"", arg
);
665 } else if (match_input("from",arg
)) {
666 arg
= strtok_r(NULL
, " ", &nextargs
);
669 if (!inet_aton(arg
, &s_addr
) || !is_unicast(s_addr
.s_addr
)) {
670 printoutc(fd
, "Invalid from address \"%s\"", arg
);
673 arg
= strtok_r(NULL
, " ", &nextargs
);
675 printoutc(fd
, "from address: netmask is required");
678 if (!inet_aton(arg
, &s_nm
) || !is_netmask(s_nm
.s_addr
)) {
679 printoutc(fd
, "Invalid netmask \"%s\"", arg
);
682 } else if (match_input("to",arg
)) {
683 arg
= strtok_r(NULL
, " ", &nextargs
);
686 if (!inet_aton(arg
, &d_addr
) || !is_unicast(d_addr
.s_addr
)) {
687 printoutc(fd
, "Invalid from address \"%s\"", arg
);
690 arg
= strtok_r(NULL
, " ", &nextargs
);
692 printoutc(fd
, "from address: netmask is required");
695 if (!inet_aton(arg
, &d_nm
) || !is_netmask(d_nm
.s_addr
)) {
696 printoutc(fd
, "Invalid netmask \"%s\"", arg
);
699 } else if (match_input("tos",arg
)) {
700 arg
= strtok_r(NULL
, " ", &nextargs
);
704 if ((tos
< 0) || not_a_number(arg
)) {
705 printoutc(fd
, "Invalid tos %s", arg
);
708 } else if (match_input("sport",arg
)) {
709 arg
= strtok_r(NULL
, " ", &nextargs
);
712 if ((sport
< 0) || not_a_number(arg
)) {
713 printoutc(fd
, "Invalid sport %s", arg
);
716 sport
= htons(atoi(arg
));
717 } else if (match_input("dport",arg
)) {
718 arg
= strtok_r(NULL
, " ", &nextargs
);
721 if (not_a_number(arg
)) {
722 printoutc(fd
, "Invalid dport %s", arg
);
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
);
733 priority
= atoi(arg
);
734 if ((priority
< 0) || (priority
>= PRIO_NUM
) || not_a_number(arg
)) {
735 printoutc(fd
, "Invalid priority %s", arg
);
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");
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
))
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
))
772 static void fill_queue_info(struct vder_queue
*q
, char *info
)
777 case QPOLICY_UNLIMITED
:
778 snprintf(info
, MAXCMD
, "unlimited");
781 snprintf(info
, MAXCMD
, "pfifo limit: %u (%d packets dropped)",
782 q
->policy_opt
.fifo
.limit
,
783 q
->policy_opt
.fifo
.stats_drop
);
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
,
790 q
->policy_opt
.red
.limit
,
791 q
->policy_opt
.red
.stats_drop
,
792 q
->policy_opt
.red
.stats_probability_drop
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
);
805 static void show_queues(int fd
, struct vder_iface
*vif
)
808 char queue_info
[MAXCMD
];
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
);
825 /* 0 == ERROR here! */
826 double get_labeled_arg(int fd
, char *label
, char **nextargs
) {
827 char *arg
= strtok_r(NULL
, " ", nextargs
);
829 printoutc(fd
, "missing parameter '%s'", label
);
832 if (!match_input(label
, arg
)) {
833 printoutc(fd
, "invalid parameter \"%s\", expecting \"%s\"", arg
, label
);
836 arg
= strtok_r(NULL
, " ", nextargs
);
837 if (not_a_number(arg
) && arg
[0] != '.') {
838 printoutc(fd
, "invalid value \"%s\"", arg
);
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
;
853 char output_word
[MAXCMD
] = "";
854 enum queue_policy_e newpolicy
;
856 arg
= strtok_r(s
, " ", &nextargs
);
860 show_queues(fd
, cur
);
865 if ((sscanf(arg
, "eth%d:prio%d", &if_id
, &prio_id
) != 2) && (sscanf(arg
, "eth%d:%s", &if_id
, output_word
) != 2))
868 if (prio_id
< 0 && !match_input("output", output_word
)) {
873 if (cur
->interface_id
== if_id
) {
881 printoutc(fd
, "Cannot find interface eth%d", if_id
);
886 arg
= strtok_r(NULL
, " ", &nextargs
);
888 printoutc(fd
, "queue: queue policy required");
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
;
900 printoutc(fd
, "queue: invalid queue policy \"%s\"", arg
);
905 printoutc(fd
, "Invalid priority queue %s", arg
);
908 q
= &selected
->prio_q
[prio_id
];
910 printoutc(fd
, "selected if=%d, outq", if_id
);
911 q
= &selected
->out_q
;
914 /* Match arguments */
915 if (newpolicy
== QPOLICY_UNLIMITED
) {
917 } else if (newpolicy
== QPOLICY_FIFO
) {
919 arg
= strtok_r(NULL
, " ", &nextargs
);
921 printoutc(fd
, "fifo: missing parameter 'limit'");
924 if (!match_input("limit", arg
)) {
925 printoutc(fd
, "fifo: invalid parameter \"%s\"", arg
);
928 arg
= strtok_r(NULL
, " ", &nextargs
);
929 if (not_a_number(arg
)) {
930 printoutc(fd
, "fifo: invalid limit");
933 limit
= strtol(arg
, NULL
, 10);
934 qfifo_setup(q
,limit
);
936 } else if (newpolicy
== QPOLICY_RED
) {
937 uint32_t min
, max
, limit
;
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
)
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
)
952 qtoken_setup(q
, bitrate
, limit
);
958 static int doconnect(int fd
,char *s
)
960 char *nextargs
= NULL
, *arg
;
961 struct vder_iface
*created
= NULL
;
963 uint8_t outmac
[6], *newmac
= NULL
;
966 arg
= strtok_r(s
, " ", &nextargs
);
968 printoutc(fd
, "sock argument is required.");
971 strncpy(sock
, arg
, 1023);
973 arg
= strtok_r(NULL
, " ", &nextargs
);
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
);
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];
990 created
= vder_iface_new(sock
, newmac
);
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
);
1001 static int stats(int fd
, char *args
)
1003 struct vder_iface
*iface
;
1004 if (strlen(args
) > 0)
1006 iface
= Router
.iflist
;
1008 printoutc(fd
, "eth%d frames sent:%d, frames received:%d",
1009 iface
->interface_id
, iface
->stats
.sent
, iface
->stats
.recvd
);
1011 iface
= iface
->next
;
1016 static int arp(int fd
, char *args
)
1018 struct vder_iface
*iface
;
1019 struct rb_node
*node
;
1020 if (strlen(args
) > 0)
1022 iface
= Router
.iflist
;
1024 node
= iface
->arp_table
.rb_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
);
1032 node
= node
->rb_left
;
1034 node
= iface
->arp_table
.rb_node
;
1036 node
= node
->rb_right
;
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
);
1044 node
= node
->rb_right
;
1046 iface
= iface
->next
;
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
);
1063 printoutc(fd
, "Error: arguments required");
1066 if ((!arg
) || (strlen(arg
) < 4) || ((strncmp(arg
, "start", 5) != 0) && (strncmp(arg
, "stop", 4) != 0))) {
1067 printoutc(fd
, "Invalid action \"%s\".", arg
);
1070 if (strncmp(arg
, "start", 5) == 0)
1071 action
= ACTION_ADD
;
1073 action
= ACTION_DELETE
;
1076 arg
= strtok_r(NULL
, " ", &nextargs
);
1078 not_understood(fd
, "");
1081 if ((strlen(arg
) < 4) || (strncmp(arg
, "eth", 3)!= 0)) {
1082 printoutc(fd
, "Invalid interface \"%s\".", arg
);
1085 selected
= select_interface(arg
);
1089 if (action
== ACTION_ADD
) {
1090 arg
= strtok_r(NULL
, " ", &nextargs
);
1092 not_understood(fd
, "");
1096 if (!inet_aton(arg
, &temp_pool_start
) || !is_unicast(temp_pool_start
.s_addr
)) {
1097 printoutc(fd
, "Invalid pool start address \"%s\"", arg
);
1101 arg
= strtok_r(NULL
, " ", &nextargs
);
1103 not_understood(fd
, "");
1106 if (!inet_aton(arg
, &temp_pool_end
) || !is_unicast(temp_pool_end
.s_addr
)) {
1107 printoutc(fd
, "Invalid pool end address \"%s\"", arg
);
1111 dhcpd_settings
= malloc(sizeof(struct vder_dhcpd_settings
));
1112 if (!dhcpd_settings
)
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;
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
);
1142 printoutc(fd
, "Error: arguments required");
1145 if ((!arg
) || (strlen(arg
) < 4) || ((strncmp(arg
, "start", 5) != 0) && (strncmp(arg
, "stop", 4) != 0))) {
1146 printoutc(fd
, "Invalid action \"%s\".", arg
);
1149 if (strncmp(arg
, "start", 5) == 0)
1150 action
= ACTION_ADD
;
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
);
1159 if ((strlen(arg
) < 4) || (strncmp(arg
, "eth", 3)!= 0)) {
1160 printoutc(fd
, "Invalid interface \"%s\".", arg
);
1161 free(olsr_settings
);
1164 selected
= select_interface(arg
);
1166 free(olsr_settings
);
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
);
1176 pthread_create(&olsr_thread
, 0, vder_olsr_loop
, olsr_settings
);
1178 pthread_cancel(olsr_thread
);
1185 #define WITHFILE 0x80
1186 static struct comlist
{
1188 int (*fun
)(int fd
,char *arg
);
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 },
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;
1211 (buf
[len
]=='\n' || buf
[len
]==' ' || buf
[len
]=='\t')) {
1217 static int handle_cmd(int fd
,char *inbuf
)
1222 while (*inbuf
== ' ' || *inbuf
== '\t' || *inbuf
== '\n') inbuf
++;
1224 if (*inbuf
!= '\0' && *inbuf
!= '#') {
1226 && strncmp(commandlist
[i
].tag
,inbuf
,strlen(commandlist
[i
].tag
))!=0;
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
)
1241 printoutc(fd
,"1000 Success");
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
));
1254 static int mgmtcommand(int fd
)
1259 if (fd
==STDIN_FILENO
)
1260 outfd
=STDOUT_FILENO
;
1262 n
= read(fd
, buf
, MAXCMD
);
1264 fprintf(stderr
,"%s: read from mgmt %s",progname
,strerror(errno
));
1269 /* Remote end has closed connection. */
1273 rv
=handle_cmd(outfd
,buf
);
1275 write(outfd
,prompt
,strlen(prompt
));
1280 static int delmgmtconn(int i
,struct pollfd
*pfd
,int nfds
)
1284 if (pfd
[i
].fd
== STDIN_FILENO
) /* close stdin implies exit */
1286 memmove(pfd
+i
,pfd
+i
+1,sizeof (struct pollfd
) * (nfds
-i
-1));
1292 static int openmgmt(char *mgmt
)
1295 struct sockaddr_un sun
;
1298 if((mgmtconnfd
= socket(PF_UNIX
, SOCK_STREAM
, 0)) < 0){
1299 fprintf(stderr
,"%s: mgmt socket: %s",progname
,strerror(errno
));
1302 if(setsockopt(mgmtconnfd
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &one
,
1304 fprintf(stderr
,"%s: mgmt setsockopt: %s",progname
,strerror(errno
));
1307 if(fcntl(mgmtconnfd
, F_SETFL
, O_NONBLOCK
) < 0){
1308 fprintf(stderr
,"%s: Setting O_NONBLOCK on mgmt fd: %s",progname
,strerror(errno
));
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
));
1317 chmod(sun
.sun_path
,mgmtmode
);
1318 if(listen(mgmtconnfd
, 15) < 0){
1319 fprintf(stderr
,"%s: mgmt listen: %s",progname
,strerror(errno
));
1325 int config_readline (int fd
, char *l
)
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'))
1334 if (l
[len
] == '\n') {
1338 if (++len
== MAXCMD
) {
1348 static int newmgmtconn(int fd
,struct pollfd
*pfd
,int nfds
)
1353 struct sockaddr addr
;
1354 new = accept(fd
, &addr
, &len
);
1356 fprintf(stderr
, "mgmt accept %s",strerror(errno
));
1359 if (nfds
< MAXCONN
) {
1360 snprintf(buf
,MAXCMD
,header
);
1361 write(new,buf
,strlen(buf
));
1362 write(new,prompt
,strlen(prompt
));
1364 pfd
[nfds
].events
=POLLIN
| POLLHUP
;
1367 fprintf(stderr
,"too many mgmt connections\n");
1381 fprintf(stderr
, "Usage: %s [-c configfile] [-M mgmt_socket] [-m mgmt_mode] [-p pidfile] [-d]\n", progname
);
1385 int main(int argc
, char *argv
[])
1389 struct pollfd pfd
[MAXCONN
];
1391 int i
, n
, daemon
= 0;
1392 char *pidfile
= NULL
, *configfile
= NULL
;
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'},
1403 progname
=basename(argv
[0]);
1409 c
= getopt_long (argc
, argv
, "hM:c:dmp:", long_options
, &option_index
);
1417 configfile
= strdup(optarg
);
1420 mgmt
=strdup(optarg
);
1423 sscanf(optarg
,"%o",&mgmtmode
);
1429 pidfile
=strdup(optarg
);
1440 int fd
= open(configfile
, O_RDONLY
);
1442 perror("Opening configuration file");
1445 while (config_readline(fd
,cmd
) > 0) {
1446 handle_cmd(STDOUT_FILENO
, cmd
);
1452 close(STDIN_FILENO
);
1453 close(STDOUT_FILENO
);
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
));
1470 int pid_fd
= open(pidfile
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0644);
1471 char pidstr
[7] = "";
1473 snprintf(pidstr
, 6, "%d", getpid());
1474 write(pid_fd
, pidstr
, strlen(pidstr
));
1477 fprintf(stderr
, "Cannot open pidfile: %s", strerror(errno
));
1482 int mgmtfd
= openmgmt(mgmt
);
1484 pfd
[npfd
].fd
= mgmtfd
;
1485 pfd
[npfd
].events
= POLLIN
| POLLHUP
;
1491 n
= poll(pfd
, npfd
, -1);
1493 for (i
= 0; i
< npfd
; i
++) {
1494 if ((pfd
[i
].revents
== POLLIN
) && (i
== mgmtindex
)) {
1495 npfd
= newmgmtconn(pfd
[i
].fd
, pfd
, npfd
);
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
);