c5cfa7e9878e8bb6cc8427b3db8de162ee24f327
[olsrd.git] / src / ipc_frontend.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)
3  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright
11  *   notice, this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in
14  *   the documentation and/or other materials provided with the
15  *   distribution.
16  * * Neither the name of olsr.org, olsrd nor the names of its
17  *   contributors may be used to endorse or promote products derived
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Visit http://www.olsr.org for more information.
34  *
35  * If you find this software useful feel free to make a donation
36  * to the project. For more information see the website or contact
37  * the copyright holders.
38  *
39  */
40
41 /*
42  *
43  *IPC - interprocess communication
44  *for the OLSRD - GUI front-end
45  *
46  */
47
48 #include "ipc_frontend.h"
49 #include "link_set.h"
50 #include "olsr.h"
51 #include "log.h"
52 #include "parser.h"
53 #include "scheduler.h"
54 #include "net_olsr.h"
55 #include "ipcalc.h"
56 #include "olsr_ip_prefix_list.h"
57
58 #include <unistd.h>
59 #include <stdlib.h>
60
61 #ifdef WIN32
62 #define perror(x) WinSockPError(x)
63 void
64 WinSockPError(const char *);
65 #endif
66
67 #ifndef MSG_NOSIGNAL
68 #define MSG_NOSIGNAL 0
69 #endif
70
71 /*
72  *IPC message sent to the front-end
73  *at every route update. Both delete
74  *and add
75  */
76 struct ipcmsg {
77   uint8_t          msgtype;
78   uint16_t         size;
79   uint8_t          metric;
80   uint8_t          add;
81   union olsr_ip_addr target_addr;
82   union olsr_ip_addr gateway_addr;
83   char               device[4];
84 };
85
86
87 struct ipc_net_msg {
88   uint8_t            msgtype;
89   uint16_t           size;
90   uint8_t            mids; /* No. of extra interfaces */
91   uint8_t            hnas; /* No. of HNA nets */
92   uint8_t            unused1;
93   uint16_t           hello_int;
94   uint16_t           hello_lan_int;
95   uint16_t           tc_int;
96   uint16_t           neigh_hold;
97   uint16_t           topology_hold;
98   uint8_t            ipv6;
99   union olsr_ip_addr   main_addr;
100 };
101
102 static int ipc_sock = -1;
103 static int ipc_conn = -1;
104
105 static int
106 ipc_send_all_routes(int fd);
107
108 static int
109 ipc_send_net_info(int fd);
110
111 static void
112 ipc_accept(int, void *, unsigned int);
113
114 #if 0
115 static int
116 ipc_input(int);
117 #endif
118
119 static bool
120 ipc_check_allowed_ip(union olsr_ip_addr *);
121
122 static bool
123 frontend_msgparser(union olsr_message *, struct interface *, union olsr_ip_addr *);
124
125
126 /**
127  *Create the socket to use for IPC to the
128  *GUI front-end
129  *
130  *@return the socket FD
131  */
132 int
133 ipc_init(void)
134 {
135   struct sockaddr_in sin4;
136   int yes;
137
138   /* Add parser function */
139   olsr_parser_add_function(&frontend_msgparser, PROMISCUOUS);
140
141   /* get an internet domain socket */
142   ipc_sock = socket(AF_INET, SOCK_STREAM, 0);
143   if (ipc_sock == -1) {
144     perror("IPC socket");
145     olsr_exit(EXIT_FAILURE);
146   }
147
148   yes = 1;
149   if (setsockopt(ipc_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) {
150     perror("SO_REUSEADDR failed");
151     return 0;
152   }
153
154   /* complete the socket structure */
155   memset(&sin4, 0, sizeof(sin4));
156   sin4.sin_family = AF_INET;
157   sin4.sin_addr.s_addr = INADDR_ANY;
158   sin4.sin_port = htons(IPC_PORT);
159
160   /* bind the socket to the port number */
161   if (bind(ipc_sock, (struct sockaddr *)&sin4, sizeof(sin4)) == -1) {
162     perror("IPC bind");
163     OLSR_PRINTF(1, "Will retry in 10 seconds...\n");
164     sleep(10);
165     if (bind(ipc_sock, (struct sockaddr *)&sin4, sizeof(sin4)) == -1) {
166       perror("IPC bind");
167       olsr_exit(EXIT_FAILURE);
168     }
169     OLSR_PRINTF(1, "OK\n");
170   }
171
172   /* show that we are willing to listen */
173   if (listen(ipc_sock, olsr_cnf->ipc_connections) == -1) {
174     perror("IPC listen");
175     olsr_exit(EXIT_FAILURE);
176   }
177
178   /* Register the socket with the socket parser */
179   add_olsr_socket(ipc_sock, &ipc_accept, NULL, NULL, SP_PR_READ);
180
181   return ipc_sock;
182 }
183
184 static bool
185 ipc_check_allowed_ip(union olsr_ip_addr *addr)
186 {
187   if (addr->v4.s_addr == ntohl(INADDR_LOOPBACK)) {
188     return true;
189   }
190
191   /* check nets */
192   return ip_acl_acceptable(&olsr_cnf->ipc_nets, addr, olsr_cnf->ip_version);
193 }
194
195 static void
196 ipc_accept(int fd, void *data __attribute__((unused)), unsigned int flags __attribute__((unused)))
197 {
198   struct sockaddr_in pin;
199   char *addr;
200   socklen_t addrlen = sizeof (struct sockaddr_in);
201
202   ipc_conn = accept(fd, (struct sockaddr *)&pin, &addrlen);
203   if (ipc_conn == -1) {
204     perror("IPC accept");
205     olsr_exit(EXIT_FAILURE);
206   } else {
207     OLSR_PRINTF(1, "Front end connected\n");
208     addr = inet_ntoa(pin.sin_addr);
209     if (ipc_check_allowed_ip((union olsr_ip_addr *)&pin.sin_addr.s_addr)) {
210       ipc_send_net_info(ipc_conn);
211       ipc_send_all_routes(ipc_conn);
212       OLSR_PRINTF(1, "Connection from %s\n",addr);
213     } else {
214       OLSR_WARN(LOG_IPC, "Front end-connection from foregin host(%s) not allowed!\n", addr);
215       CLOSESOCKET(ipc_conn);
216     }
217   }
218 }
219
220 #if 0
221 /**
222  *Read input from the IPC socket. Not in use.
223  *
224  *@todo for future use
225  *@param sock the IPC socket
226  *@return 1
227  */
228 static int
229 ipc_input(int sock)
230 {
231   union {
232     char        buf[MAXPACKETSIZE+1];
233     struct olsr olsr;
234   } inbuf;
235
236   if (recv(sock, dir, sizeof(dir), 0) == -1) {
237     perror("recv");
238     exit(1);
239   }
240   return 1;
241 }
242 #endif
243
244 /**
245  *Sends a olsr packet on the IPC socket.
246  *
247  *@param olsr the olsr struct representing the packet
248  *
249  *@return true for not preventing forwarding
250  */
251 static bool
252 frontend_msgparser(union olsr_message *msg,
253                    struct interface *in_if __attribute__((unused)),
254                    union olsr_ip_addr *from_addr __attribute__((unused)))
255 {
256   if (ipc_conn >= 0) {
257     const size_t len = olsr_cnf->ip_version == AF_INET ? ntohs(msg->v4.olsr_msgsize) : ntohs(msg->v6.olsr_msgsize);
258     if (send(ipc_conn, (void *)msg, len, MSG_NOSIGNAL) < 0) {
259       OLSR_PRINTF(1, "(OUTPUT)IPC connection lost!\n");
260       CLOSESOCKET(ipc_conn);
261     }
262   }
263   return true;
264 }
265
266
267 /**
268  *Send a route table update to the front-end.
269  *
270  *@param kernel_route a rtentry describing the route update
271  *@param add 1 if the route is to be added 0 if it is to be deleted
272  *@param int_name the name of the interface the route is set to go by
273  *
274  *@return negative on error
275  */
276 int
277 ipc_route_send_rtentry(const union olsr_ip_addr *dst,
278                        const union olsr_ip_addr *gw,
279                        int met,
280                        int add,
281                        const char *int_name)
282 {
283   struct ipcmsg packet;
284
285   if (olsr_cnf->ipc_connections <= 0) {
286     return -1;
287   }
288
289   if (ipc_conn < 0) {
290     return 0;
291   }
292   memset(&packet, 0, sizeof(packet));
293   packet.size = htons(IPC_PACK_SIZE);
294   packet.msgtype = ROUTE_IPC;
295
296   packet.target_addr = *dst;
297
298   packet.add = add;
299   if (add && gw) {
300     packet.metric = met;
301     packet.gateway_addr = *gw;
302   }
303
304   if (int_name != NULL) {
305     memcpy(&packet.device[0], int_name, 4);
306   } else {
307     memset(&packet.device[0], 0, 4);
308   }
309
310   /*
311   x = 0;
312   for(i = 0; i < IPC_PACK_SIZE;i++)
313     {
314       if (x == 4)
315         {
316           x = 0;
317           printf("\n\t");
318         }
319       x++;
320       printf(" %03i", (u_char) tmp[i]);
321     }
322
323   printf("\n");
324   */
325
326   if (send(ipc_conn, (void *)&packet, IPC_PACK_SIZE, MSG_NOSIGNAL) < 0) { // MSG_NOSIGNAL to avoid sigpipe
327     OLSR_PRINTF(1, "(RT_ENTRY)IPC connection lost!\n");
328     CLOSESOCKET(ipc_conn);
329     return -1;
330   }
331
332   return 1;
333 }
334
335
336
337 static int
338 ipc_send_all_routes(int fd)
339 {
340   struct rt_entry  *rt;
341
342   if (ipc_conn < 0) {
343     return 0;
344   }
345
346   OLSR_FOR_ALL_RT_ENTRIES(rt) {
347     struct ipcmsg packet;
348
349     memset(&packet, 0, sizeof(packet));
350     packet.size = htons(IPC_PACK_SIZE);
351     packet.msgtype = ROUTE_IPC;
352
353     packet.target_addr = rt->rt_dst.prefix;
354
355     packet.add = 1;
356     packet.metric = rt->rt_best->rtp_metric.hops;
357
358     packet.gateway_addr = rt->rt_nexthop.gateway;
359
360     memcpy(&packet.device[0], rt->rt_nexthop.interface->int_name, 4);
361
362     /* MSG_NOSIGNAL to avoid sigpipe */
363     if (send(fd, (void *)&packet, IPC_PACK_SIZE, MSG_NOSIGNAL) < 0) {
364       OLSR_PRINTF(1, "(RT_ENTRY)IPC connection lost!\n");
365       CLOSESOCKET(ipc_conn);
366       return -1;
367     }
368   } OLSR_FOR_ALL_RT_ENTRIES_END(rt);
369   return 1;
370 }
371
372
373
374 /**
375  *Sends OLSR info to the front-end. This info consists of
376  *the different time intervals and holding times, number
377  *of interfaces, HNA routes and main address.
378  *
379  *@return negative on error
380  */
381 static int
382 ipc_send_net_info(int fd)
383 {
384   //int x, i;
385   struct ipc_net_msg net_msg;
386
387   OLSR_PRINTF(1, "Sending net-info to front end...\n");
388
389   memset(&net_msg, 0, sizeof(net_msg));
390
391   /* Message size */
392   net_msg.size = htons(sizeof(net_msg));
393   /* Message type */
394   net_msg.msgtype = NET_IPC;
395
396   /* MIDs */
397   /* XXX fix IPC MIDcnt */
398   net_msg.mids = (!list_is_empty(&interface_head)) ? 1 : 0;
399
400   /* HNAs */
401   net_msg.hnas = list_is_empty(&olsr_cnf->hna_entries) ? 0 : 1;
402
403   /* Different values */
404   /* Temporary fixes */
405   /* XXX fix IPC intervals */
406   net_msg.hello_int = 0;//htons((uint16_t)hello_int);
407   net_msg.hello_lan_int = 0;//htons((uint16_t)hello_int_nw);
408   net_msg.tc_int = 0;//htons((uint16_t)tc_int);
409   net_msg.neigh_hold = 0;//htons((uint16_t)neighbor_hold_time);
410   net_msg.topology_hold = 0;//htons((uint16_t)topology_hold_time);
411
412   net_msg.ipv6 = olsr_cnf->ip_version == AF_INET ? 0 : 1;
413
414   /* Main addr */
415   net_msg.main_addr = olsr_cnf->router_id;
416
417   /*
418   printf("\t");
419   x = 0;
420   for(i = 0; i < sizeof(struct ipc_net_msg);i++)
421     {
422       if (x == 4)
423         {
424           x = 0;
425           printf("\n\t");
426         }
427       x++;
428       printf(" %03i", (u_char) msg[i]);
429     }
430
431   printf("\n");
432   */
433
434   if (send(fd, (void *)&net_msg, sizeof(net_msg), MSG_NOSIGNAL) < 0) {
435     OLSR_PRINTF(1, "(NETINFO)IPC connection lost!\n");
436     CLOSESOCKET(ipc_conn);
437     return -1;
438   }
439   return 0;
440 }
441
442
443
444 void
445 shutdown_ipc(void)
446 {
447   OLSR_PRINTF(1, "Shutting down IPC...\n");
448   CLOSESOCKET(ipc_conn);
449 }
450
451 /*
452  * Local Variables:
453  * c-basic-offset: 2
454  * indent-tabs-mode: nil
455  * End:
456  */