Added wrappers for sendto and recvfrom and moved olsr_input and net_output back to...
[olsrd.git] / src / linux / net.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)
3  * Copyright (c) 2004, Andreas T√łnnesen(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  * $Id: net.c,v 1.15 2005/02/14 16:55:37 kattemat Exp $
40  */
41
42
43 /*
44  * Linux spesific code
45  */
46
47 #include "net.h"
48 #include "../defs.h"
49 #include "../net_os.h"
50 #include "../parser.h"
51
52 /**
53  *Bind a socket to a device
54  *
55  *@param sock the socket to bind
56  *@param dev_name name of the device
57  *
58  *@return negative if error
59  */
60
61 int
62 bind_socket_to_device(int sock, char *dev_name)
63 {
64   /*
65    *Bind to device using the SO_BINDTODEVICE flag
66    */
67   olsr_printf(3, "Binding socket %d to device %s\n", sock, dev_name);
68   return setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, dev_name, strlen(dev_name)+1);
69
70 }
71
72
73
74
75 /**
76  *Enable IP forwarding.
77  *Just writing "1" to the /proc/sys/net/ipv4/ip_forward
78  *if using IPv4 or /proc/sys/net/ipv6/conf/all/forwarding
79  *if using IPv6.
80  *Could probably drop the check for
81  *"0" here and write "1" anyways.
82  *
83  *@param version IP version.
84  *
85  *@return 1 on sucess 0 on failiure
86  */ 
87 int
88 enable_ip_forwarding(int version)
89 {
90   FILE *proc_fwd;
91   char procfile[FILENAME_MAX];
92
93   if(version == AF_INET)
94     {
95       strcpy(procfile, "/proc/sys/net/ipv4/ip_forward");
96     }
97   else
98     if(version == AF_INET6)
99       {
100         strcpy(procfile, "/proc/sys/net/ipv6/conf/all/forwarding");
101       }
102     else
103       return -1;
104
105
106   if ((proc_fwd=fopen(procfile, "r"))==NULL)
107     {
108       /* IPv4 */
109       if(version == AF_INET)
110         fprintf(stderr, "WARNING! Could not open the %s file to check/enable IP forwarding!\nAre you using the procfile filesystem?\nDoes your system support IPv4?\nI will continue(in 3 sec) - but you should mannually ensure that IP forwarding is enabeled!\n\n", procfile);
111       /* IPv6 */
112       else
113         fprintf(stderr, "WARNING! Could not open the %s file to check/enable IP forwarding!\nAre you using the procfile filesystem?\nDoes your system support IPv6?\nI will continue(in 3 sec) - but you should mannually ensure that IP forwarding is enabeled!\n\n", procfile);
114       
115       sleep(3);
116       return 0;
117     }
118   
119   else
120     {
121       orig_fwd_state = fgetc(proc_fwd);
122       fclose(proc_fwd);
123       if(orig_fwd_state == '1')
124         {
125           olsr_printf(3, "\nIP forwarding is enabled on this system\n");
126         }
127       else
128         {
129           if ((proc_fwd=fopen(procfile, "w"))==NULL)
130             {
131               fprintf(stderr, "Could not open %s for writing!\n", procfile);
132               fprintf(stderr, "I will continue(in 3 sec) - but you should mannually ensure that IP forwarding is enabeled!\n\n");
133               sleep(3);
134               return 0;
135             }
136           else
137             {
138               syslog(LOG_INFO, "Writing \"1\" to %s\n", procfile);
139               fputs("1", proc_fwd);
140             }
141           fclose(proc_fwd);
142
143         }
144     }
145   return 1;
146       
147 }
148
149
150 /**
151  *
152  *@return 1 on sucess 0 on failiure
153  */ 
154 int
155 disable_redirects(char *if_name, int index, int version)
156 {
157   FILE *proc_redirect;
158   char procfile[FILENAME_MAX];
159
160   if(version == AF_INET6)
161     return -1;
162
163   /* Generate the procfile name */
164   sprintf(procfile, REDIRECT_PROC, if_name);
165
166
167   if((proc_redirect = fopen(procfile, "r")) == NULL)
168     {
169       fprintf(stderr, "WARNING! Could not open the %s file to check/disable ICMP redirects!\nAre you using the procfile filesystem?\nDoes your system support IPv4?\nI will continue(in 3 sec) - but you should mannually ensure that ICMP redirects are disabled!\n\n", procfile);
170       
171       sleep(3);
172       return 0;
173     }
174   else
175     {
176       nic_states[index].redirect = fgetc(proc_redirect);
177       fclose(proc_redirect);
178       
179     }
180
181   if ((proc_redirect = fopen(procfile, "w"))==NULL)
182     {
183       fprintf(stderr, "Could not open %s for writing!\n", procfile);
184       fprintf(stderr, "I will continue(in 3 sec) - but you should mannually ensure that ICMP redirect is disabeled!\n\n");
185       sleep(3);
186       return 0;
187     }
188   else
189     {
190       syslog(LOG_INFO, "Writing \"0\" to %s", procfile);
191       fputs("0", proc_redirect);
192     }
193   fclose(proc_redirect);
194
195   return 1;
196 }
197
198
199
200 /**
201  *
202  *@return 1 on sucess 0 on failiure
203  */ 
204 int
205 deactivate_spoof(char *if_name, int index, int version)
206 {
207   FILE *proc_spoof;
208   char procfile[FILENAME_MAX];
209
210   if(version == AF_INET6)
211     return -1;
212
213
214   /* Generate the procfile name */
215   sprintf(procfile, SPOOF_PROC, if_name);
216
217
218   if((proc_spoof = fopen(procfile, "r")) == NULL)
219     {
220       fprintf(stderr, "WARNING! Could not open the %s file to check/disable the IP spoof filter!\nAre you using the procfile filesystem?\nDoes your system support IPv4?\nI will continue(in 3 sec) - but you should mannually ensure that IP spoof filtering is disabled!\n\n", procfile);
221       
222       sleep(3);
223       return 0;
224     }
225   else
226     {
227       nic_states[index].spoof = fgetc(proc_spoof);
228       fclose(proc_spoof);
229       
230     }
231
232   if ((proc_spoof = fopen(procfile, "w")) == NULL)
233     {
234       fprintf(stderr, "Could not open %s for writing!\n", procfile);
235       fprintf(stderr, "I will continue(in 3 sec) - but you should mannually ensure that IP spoof filtering is disabeled!\n\n");
236       sleep(3);
237       return 0;
238     }
239   else
240     {
241       syslog(LOG_INFO, "Writing \"0\" to %s", procfile);
242       fputs("0", proc_spoof);
243     }
244   fclose(proc_spoof);
245
246   return 1;
247 }
248
249
250
251 /**
252  *Resets the spoof filter and ICMP redirect settings
253  */
254
255 int
256 restore_settings(int version)
257 {
258   FILE *proc_fd;
259   char procfile[FILENAME_MAX];
260   struct interface *ifs;
261
262   olsr_printf(1, "Restoring network state\n");
263
264   /* Restore IP forwarding to "off" */
265   if(orig_fwd_state == '0')
266     {
267       if(version == AF_INET)
268         {
269           strcpy(procfile, "/proc/sys/net/ipv4/ip_forward");
270         }
271       else if(version == AF_INET6)
272         {
273           strcpy(procfile, "/proc/sys/net/ipv6/conf/all/forwarding");
274         }
275
276       if ((proc_fd = fopen(procfile, "w")) == NULL)
277         {
278           fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
279         }
280       else
281         {
282           syslog(LOG_INFO, "Resetting %s to %c\n", procfile, orig_fwd_state);
283           fputc(orig_fwd_state, proc_fd);
284           fclose(proc_fd);
285         }
286
287     }
288
289   if(version == AF_INET6)
290     return 0;
291
292   for(ifs = ifnet; ifs != NULL; ifs = ifs->int_next)
293     {
294       /* ICMP redirects */
295       
296       /* Generate the procfile name */
297       sprintf(procfile, REDIRECT_PROC, ifs->int_name);
298       
299       if ((proc_fd = fopen(procfile, "w")) == NULL)
300         {
301           fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
302         }
303       else
304         {
305           syslog(LOG_INFO, "Resetting %s to %c\n", procfile, nic_states[ifs->if_nr].redirect);
306
307           fputc(nic_states[ifs->if_nr].redirect, proc_fd);
308           fclose(proc_fd);
309         }
310
311       
312       /* Spoof filter */
313       
314       /* Generate the procfile name */
315       sprintf(procfile, SPOOF_PROC, ifs->int_name);
316
317       if ((proc_fd = fopen(procfile, "w")) == NULL)
318         {
319           fprintf(stderr, "Could not open %s for writing!\nSettings not restored!\n", procfile);
320         }
321       else
322         {
323           syslog(LOG_INFO, "Resetting %s to %c\n", procfile, nic_states[ifs->if_nr].spoof);
324
325           fputc(nic_states[ifs->if_nr].spoof, proc_fd);
326           fclose(proc_fd);
327         }
328
329     }
330   return 1;
331
332 }
333
334
335
336 /**
337  *Creates a nonblocking broadcast socket.
338  *@param sa sockaddr struct. Used for bind(2).
339  *@return the FD of the socket or -1 on error.
340  */
341 int
342 getsocket(struct sockaddr *sa, int bufspace, char *int_name)
343 {
344   struct sockaddr_in *sin=(struct sockaddr_in *)sa;
345   int sock, on = 1;
346
347
348
349   if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 
350     {
351       perror("socket");
352       syslog(LOG_ERR, "socket: %m");
353       return (-1);
354     }
355
356
357
358 #ifdef SO_BROADCAST
359   if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0)
360     {
361       perror("setsockopt");
362       syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
363       close(sock);
364       return (-1);
365     }
366 #endif
367
368   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) 
369     {
370       perror("SO_REUSEADDR failed");
371       return (-1);
372     }
373
374
375
376 #ifdef SO_RCVBUF
377
378   for (on = bufspace; ; on -= 1024) 
379     {
380       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
381                      &on, sizeof (on)) == 0)
382         break;
383       if (on <= 8*1024) 
384         {
385           perror("setsockopt");
386           syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
387           break;
388         }
389     }
390
391
392 #endif
393
394
395   /*
396    * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
397    */
398
399   /* Bind to device */
400   if(bind_socket_to_device(sock, int_name) < 0)
401     {
402       fprintf(stderr, "Could not bind socket to device... exiting!\n\n");
403       syslog(LOG_ERR, "Could not bind socket to device... exiting!\n\n");
404       return -1;
405     }
406
407
408   if (bind(sock, (struct sockaddr *)sin, sizeof (*sin)) < 0) 
409     {
410       perror("bind");
411       syslog(LOG_ERR, "bind: %m");
412       close(sock);
413       return (-1);
414     }
415
416   /*
417    *One should probably fetch the flags first
418    *using F_GETFL....
419    */
420   if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
421     syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
422
423   return (sock);
424 }
425
426
427 /**
428  *Creates a nonblocking IPv6 socket
429  *@param sin sockaddr_in6 struct. Used for bind(2).
430  *@return the FD of the socket or -1 on error.
431  */
432 int
433 getsocket6(struct sockaddr_in6 *sin, int bufspace, char *int_name)
434 {
435   int sock, on = 1;
436
437
438
439   if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 
440     {
441       perror("socket");
442       syslog(LOG_ERR, "socket: %m");
443       return (-1);
444     }
445
446
447
448   //#ifdef SO_BROADCAST
449   /*
450   if (setsockopt(sock, SOL_SOCKET, SO_MULTICAST, &on, sizeof (on)) < 0)
451     {
452       perror("setsockopt");
453       syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
454       close(sock);
455       return (-1);
456     }
457   */
458   //#endif
459
460
461
462
463 #ifdef SO_RCVBUF
464   for (on = bufspace; ; on -= 1024) 
465     {
466       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
467                      &on, sizeof (on)) == 0)
468         break;
469       if (on <= 8*1024) 
470         {
471           perror("setsockopt");
472           syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
473           break;
474         }
475     }
476
477
478 #endif
479
480   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) 
481     {
482       perror("SO_REUSEADDR failed");
483       return (-1);
484     }
485
486
487   /*
488    * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!!
489    */
490
491   /* Bind to device */
492   if(bind_socket_to_device(sock, int_name) < 0)
493     {
494       fprintf(stderr, "Could not bind socket to device... exiting!\n\n");
495       syslog(LOG_ERR, "Could not bind socket to device... exiting!\n\n");
496       return -1;
497     }
498
499
500   if (bind(sock, (struct sockaddr *)sin, sizeof (*sin)) < 0) 
501     {
502       perror("bind");
503       syslog(LOG_ERR, "bind: %m");
504       close(sock);
505       return (-1);
506     }
507
508   /*
509    *One should probably fetch the flags first
510    *using F_GETFL....
511    */
512   if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
513     syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
514
515
516
517   return (sock);
518 }
519
520
521 /*
522  *From net-tools lib/interface.c
523  *
524  */
525
526 int
527 get_ipv6_address(char *ifname, struct sockaddr_in6 *saddr6, int scope_in)
528 {
529   char addr6[40], devname[IFNAMSIZ];
530   char addr6p[8][5];
531   int plen, scope, dad_status, if_idx;
532   FILE *f;
533   struct sockaddr_in6 tmp_sockaddr6;
534
535   if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) 
536     {
537       while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
538                     addr6p[0], addr6p[1], addr6p[2], addr6p[3],
539                     addr6p[4], addr6p[5], addr6p[6], addr6p[7],
540                     &if_idx, &plen, &scope, &dad_status, devname) != EOF) 
541         {
542           if (!strcmp(devname, ifname)) 
543             {
544               sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
545                       addr6p[0], addr6p[1], addr6p[2], addr6p[3],
546                       addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
547               olsr_printf(5, "\tinet6 addr: %s\n", addr6);
548               olsr_printf(5, "\tScope: %d", scope);
549               if(scope == scope_in)
550                 {
551                   olsr_printf(4, "IPv6 addr:\n");
552                   inet_pton(AF_INET6,addr6,&tmp_sockaddr6);
553                   memcpy(&saddr6->sin6_addr, &tmp_sockaddr6, sizeof(struct in6_addr));    
554                   fclose(f);
555                   return 1;
556                 }
557             }
558         }
559       fclose(f);
560     }
561   
562   return 0;
563 }
564
565
566 /**
567  * Wrapper for sendto(2)
568  */
569
570 ssize_t
571 olsr_sendto(int s, 
572             const void *buf, 
573             size_t len, 
574             int flags, 
575             const struct sockaddr *to, 
576             socklen_t tolen)
577 {
578   return sendto(s, buf, len, flags, to, tolen);
579 }
580
581 /**
582  * Wrapper for recvfrom(2)
583  */
584
585 ssize_t  
586 olsr_recvfrom(int  s, 
587               void *buf, 
588               size_t len, 
589               int flags, 
590               struct sockaddr *from,
591               socklen_t *fromlen)
592 {
593   return recvfrom(s, 
594                   buf, 
595                   len, 
596                   0, 
597                   from, 
598                   fromlen);
599 }