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