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