c93903b3f07b2b851e4d732fb27a3e4b98741eb5
[olsrd.git] / src / ipc_frontend.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)
3  * Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org)
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
57 #include <unistd.h>
58 #include <stdlib.h>
59
60 #ifdef WIN32
61 #define close(x) closesocket(x)
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   olsr_u8_t          msgtype;
78   olsr_u16_t         size;
79   olsr_u8_t          metric;
80   olsr_u8_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   olsr_u8_t            msgtype;
89   olsr_u16_t           size;
90   olsr_u8_t            mids; /* No. of extra interfaces */
91   olsr_u8_t            hnas; /* No. of HNA nets */
92   olsr_u8_t            unused1;
93   olsr_u16_t           hello_int;
94   olsr_u16_t           hello_lan_int;
95   olsr_u16_t           tc_int;
96   olsr_u16_t           neigh_hold;
97   olsr_u16_t           topology_hold;
98   olsr_u8_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 olsr_bool
120 ipc_check_allowed_ip(const union olsr_ip_addr *);
121
122 static olsr_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("IPC socket", 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("IPC bind", 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("IPC listen", 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 olsr_bool
185 ipc_check_allowed_ip(const union olsr_ip_addr *addr)
186 {
187   struct ip_prefix_list *ipcn;
188
189   if (addr->v4.s_addr == ntohl(INADDR_LOOPBACK)) {
190     return OLSR_TRUE;
191   }
192
193   /* check nets */
194   for (ipcn = olsr_cnf->ipc_nets; ipcn != NULL; ipcn = ipcn->next) {
195     if (ip_in_net(addr, &ipcn->net)) {
196       return OLSR_TRUE;
197     }
198   }
199
200   return OLSR_FALSE;
201 }
202
203 static void
204 ipc_accept(int fd, void *data __attribute__((unused)), unsigned int flags __attribute__((unused)))
205 {
206   struct sockaddr_in pin;
207   char *addr;
208   socklen_t addrlen = sizeof (struct sockaddr_in);
209
210   ipc_conn = accept(fd, (struct sockaddr *)&pin, &addrlen);
211   if (ipc_conn == -1) {
212     perror("IPC accept");
213     olsr_exit("IPC accept", EXIT_FAILURE);
214   } else {
215     OLSR_PRINTF(1, "Front end connected\n");
216     addr = inet_ntoa(pin.sin_addr);
217     if (ipc_check_allowed_ip((union olsr_ip_addr *)&pin.sin_addr.s_addr)) {
218       ipc_send_net_info(ipc_conn);
219       ipc_send_all_routes(ipc_conn);
220       OLSR_PRINTF(1, "Connection from %s\n",addr);
221     } else {
222       OLSR_PRINTF(1, "Front end-connection from foregin host(%s) not allowed!\n", addr);
223       olsr_syslog(OLSR_LOG_ERR, "OLSR: Front end-connection from foregin host(%s) not allowed!\n", addr);
224       CLOSE(ipc_conn);
225     }
226   }
227 }
228
229 #if 0
230 /**
231  *Read input from the IPC socket. Not in use.
232  *
233  *@todo for future use
234  *@param sock the IPC socket
235  *@return 1
236  */
237 static int
238 ipc_input(int sock)
239 {
240   union {
241     char        buf[MAXPACKETSIZE+1];
242     struct olsr olsr;
243   } inbuf;
244
245   if (recv(sock, dir, sizeof(dir), 0) == -1) {
246     perror("recv");
247     exit(1);
248   }
249   return 1;
250 }
251 #endif
252
253 /**
254  *Sends a olsr packet on the IPC socket.
255  *
256  *@param olsr the olsr struct representing the packet
257  *
258  *@return true for not preventing forwarding
259  */
260 static olsr_bool
261 frontend_msgparser(union olsr_message *msg, struct interface *in_if __attribute__((unused)), union olsr_ip_addr *from_addr __attribute__((unused)))
262 {
263   if (ipc_conn < 0) {
264     return OLSR_TRUE;
265   }
266   if (send(ipc_conn,
267            (void *)msg,
268            olsr_cnf->ip_version == AF_INET ? ntohs(msg->v4.olsr_msgsize) : ntohs(msg->v6.olsr_msgsize),
269            MSG_NOSIGNAL) < 0) {
270     OLSR_PRINTF(1, "(OUTPUT)IPC connection lost!\n");
271     CLOSE(ipc_conn);
272   }
273   return OLSR_TRUE;
274 }
275
276
277 /**
278  *Send a route table update to the front-end.
279  *
280  *@param kernel_route a rtentry describing the route update
281  *@param add 1 if the route is to be added 0 if it is to be deleted
282  *@param int_name the name of the interface the route is set to go by
283  *
284  *@return negative on error
285  */
286 int
287 ipc_route_send_rtentry(const union olsr_ip_addr *dst,
288                        const union olsr_ip_addr *gw,
289                        int met,
290                        int add,
291                        const char *int_name)
292 {
293   struct ipcmsg packet;
294
295   if (olsr_cnf->ipc_connections <= 0) {
296     return -1;
297   }
298
299   if (ipc_conn < 0) {
300     return 0;
301   }
302   memset(&packet, 0, sizeof(packet));
303   packet.size = htons(IPC_PACK_SIZE);
304   packet.msgtype = ROUTE_IPC;
305
306   packet.target_addr = *dst;
307
308   packet.add = add;
309   if (add && gw) {
310     packet.metric = met;
311     packet.gateway_addr = *gw;
312   }
313
314   if (int_name != NULL) {
315     memcpy(&packet.device[0], int_name, 4);
316   } else {
317     memset(&packet.device[0], 0, 4);
318   }
319
320   /*
321   x = 0;
322   for(i = 0; i < IPC_PACK_SIZE;i++)
323     {
324       if (x == 4)
325         {
326           x = 0;
327           printf("\n\t");
328         }
329       x++;
330       printf(" %03i", (u_char) tmp[i]);
331     }
332
333   printf("\n");
334   */
335
336   if (send(ipc_conn, (void *)&packet, IPC_PACK_SIZE, MSG_NOSIGNAL) < 0) { // MSG_NOSIGNAL to avoid sigpipe
337     OLSR_PRINTF(1, "(RT_ENTRY)IPC connection lost!\n");
338     CLOSE(ipc_conn);
339     return -1;
340   }
341
342   return 1;
343 }
344
345
346
347 static int
348 ipc_send_all_routes(int fd)
349 {
350   struct rt_entry  *rt;
351
352   if (ipc_conn < 0) {
353     return 0;
354   }
355
356   OLSR_FOR_ALL_RT_ENTRIES(rt) {
357     struct ipcmsg packet;
358
359     memset(&packet, 0, sizeof(packet));
360     packet.size = htons(IPC_PACK_SIZE);
361     packet.msgtype = ROUTE_IPC;
362
363     packet.target_addr = rt->rt_dst.prefix;
364
365     packet.add = 1;
366     packet.metric = rt->rt_best->rtp_metric.hops;
367
368     packet.gateway_addr = rt->rt_nexthop.gateway;
369
370     memcpy(&packet.device[0], if_ifwithindex_name(rt->rt_nexthop.iif_index), 4);
371
372     /* MSG_NOSIGNAL to avoid sigpipe */
373     if (send(fd, (void *)&packet, IPC_PACK_SIZE, MSG_NOSIGNAL) < 0) {
374       OLSR_PRINTF(1, "(RT_ENTRY)IPC connection lost!\n");
375       CLOSE(ipc_conn);
376       return -1;
377     }
378   } OLSR_FOR_ALL_RT_ENTRIES_END(rt);
379   return 1;
380 }
381
382
383
384 /**
385  *Sends OLSR info to the front-end. This info consists of
386  *the different time intervals and holding times, number
387  *of interfaces, HNA routes and main address.
388  *
389  *@return negative on error
390  */
391 static int
392 ipc_send_net_info(int fd)
393 {
394   //int x, i;
395   struct ipc_net_msg net_msg;
396
397   OLSR_PRINTF(1, "Sending net-info to front end...\n");
398
399   memset(&net_msg, 0, sizeof(net_msg));
400
401   /* Message size */
402   net_msg.size = htons(sizeof(net_msg));
403   /* Message type */
404   net_msg.msgtype = NET_IPC;
405
406   /* MIDs */
407   /* XXX fix IPC MIDcnt */
408   net_msg.mids = (ifnet != NULL && ifnet->int_next != NULL) ? 1 : 0;
409
410   /* HNAs */
411   net_msg.hnas = olsr_cnf->hna_entries == NULL ? 0 : 1;
412
413   /* Different values */
414   /* Temporary fixes */
415   /* XXX fix IPC intervals */
416   net_msg.hello_int = 0;//htons((olsr_u16_t)hello_int);
417   net_msg.hello_lan_int = 0;//htons((olsr_u16_t)hello_int_nw);
418   net_msg.tc_int = 0;//htons((olsr_u16_t)tc_int);
419   net_msg.neigh_hold = 0;//htons((olsr_u16_t)neighbor_hold_time);
420   net_msg.topology_hold = 0;//htons((olsr_u16_t)topology_hold_time);
421
422   net_msg.ipv6 = olsr_cnf->ip_version == AF_INET ? 0 : 1;
423
424   /* Main addr */
425   net_msg.main_addr = olsr_cnf->main_addr;
426
427   /*
428   printf("\t");
429   x = 0;
430   for(i = 0; i < sizeof(struct ipc_net_msg);i++)
431     {
432       if (x == 4)
433         {
434           x = 0;
435           printf("\n\t");
436         }
437       x++;
438       printf(" %03i", (u_char) msg[i]);
439     }
440
441   printf("\n");
442   */
443
444   if (send(fd, (void *)&net_msg, sizeof(net_msg), MSG_NOSIGNAL) < 0) {
445     OLSR_PRINTF(1, "(NETINFO)IPC connection lost!\n");
446     CLOSE(ipc_conn);
447     return -1;
448   }
449   return 0;
450 }
451
452
453
454 void
455 shutdown_ipc(void)
456 {
457   OLSR_PRINTF(1, "Shutting down IPC...\n");
458   CLOSE(ipc_sock);
459   CLOSE(ipc_conn);
460 }
461
462 /*
463  * Local Variables:
464  * c-basic-offset: 2
465  * indent-tabs-mode: nil
466  * End:
467  */