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