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