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