63e8622f827a665d957ee70b2b55cb587db6e3cd
[olsrd.git] / src / win32 / net.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 #if defined WINCE
43 #include <sys/types.h>          // for time_t
44 #endif
45
46 #define WIN32_LEAN_AND_MEAN
47 #include <windows.h>
48 #include <winsock2.h>
49 #include <ws2tcpip.h>
50 #include <iphlpapi.h>
51 #undef interface
52
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <errno.h>
56
57 #include "defs.h"
58 #include "os_net.h"
59 #include "net_olsr.h"
60 #include "ipcalc.h"
61 #include "olsr_logging.h"
62 #include "win32/compat.h"
63 #include "os_system.h"
64 #if defined WINCE
65 #define WIDE_STRING(s) L##s
66 #else
67 #define WIDE_STRING(s) s
68 #endif
69
70 void WinSockPError(const char *Str);
71 void PError(const char *);
72
73 static void DisableIcmpRedirects(void);
74
75 /**
76  * Argument preprocessor
77  * @param argc
78  * @param argv
79  */
80 void
81 os_arg(int *argc __attribute__ ((unused)), char **argv __attribute__ ((unused))) {
82   return;
83 }
84
85 /**
86  * Wrapper for exit call
87  * @param ret return value
88  */
89 void  __attribute__((noreturn))
90 os_exit(int ret) {
91   exit(ret);
92 }
93
94 /**
95  * Wrapper for closing sockets
96  * @param
97  * @param sock
98  * @return
99  */
100 int
101 os_close(int sock) {
102   return os_close(sock);
103 }
104
105 int
106 os_socket_set_nonblocking(int fd)
107 {
108   /* make the fd non-blocking */
109   unsigned long flags = 1;
110   if (ioctlsocket(fd, FIONBIO, &flags) != 0) {
111     OLSR_WARN(LOG_NETWORKING, "Cannot set the socket flags: %s", win32_strerror(WSAGetLastError()));
112     return -1;
113   }
114   return 0;
115 }
116
117 int
118 os_getsocket4(const char *if_name __attribute__ ((unused)), uint16_t port, int bufspace, union olsr_sockaddr *bindto)
119 {
120   struct sockaddr_in Addr;
121   int On = 1;
122   unsigned long Len;
123   int Sock = socket(AF_INET, SOCK_DGRAM, 0);
124   if (Sock < 0) {
125     OLSR_ERROR(LOG_NETWORKING, "Cannot open socket for OLSR PDUs (%s)\n", strerror(errno));
126     olsr_exit(EXIT_FAILURE);
127   }
128
129   if (setsockopt(Sock, SOL_SOCKET, SO_BROADCAST, (char *)&On, sizeof(On)) < 0) {
130     OLSR_ERROR(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to broadcast mode (%s)\n", strerror(errno));
131     os_close(Sock);
132     olsr_exit(EXIT_FAILURE);
133   }
134
135   if (setsockopt(Sock, SOL_SOCKET, SO_REUSEADDR, (char *)&On, sizeof(On)) < 0) {
136     OLSR_ERROR(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to broadcast mode (%s)\n", strerror(errno));
137     os_close(Sock);
138     olsr_exit(EXIT_FAILURE);
139   }
140
141   while (bufspace > 8192) {
142     if (setsockopt(Sock, SOL_SOCKET, SO_RCVBUF, (char *)&bufspace, sizeof(bufspace)) == 0)
143       break;
144
145     bufspace -= 1024;
146   }
147
148   if (bufspace <= 8192)
149     OLSR_WARN(LOG_NETWORKING, "Cannot set IPv4 socket receive buffer.\n");
150
151   if (bindto == NULL) {
152     memset(&Addr, 0, sizeof(Addr));
153     Addr.sin_family = AF_INET;
154     Addr.sin_port = htons(port);
155     Addr.sin_addr.s_addr = INADDR_ANY;
156
157     bindto = (union olsr_sockaddr *)&Addr;
158   }
159
160   if (bind(Sock, &bindto->std, sizeof(Addr)) < 0) {
161     OLSR_ERROR(LOG_NETWORKING, "Could not bind socket for OLSR PDUs to device (%s)\n", strerror(errno));
162     os_close(Sock);
163     olsr_exit(EXIT_FAILURE);
164   }
165
166   if (WSAIoctl(Sock, FIONBIO, &On, sizeof(On), NULL, 0, &Len, NULL, NULL) < 0) {
167     OLSR_ERROR(LOG_NETWORKING, "WSAIoctl");
168     os_close(Sock);
169     olsr_exit(EXIT_FAILURE);
170   }
171
172   return Sock;
173 }
174
175 int
176 os_getsocket6(const char *if_name __attribute__ ((unused)), uint16_t port, int bufspace, union olsr_sockaddr *bindto)
177 {
178   struct sockaddr_in6 Addr6;
179   int On = 1;
180   int Sock = socket(AF_INET6, SOCK_DGRAM, 0);
181   if (Sock < 0) {
182     OLSR_ERROR(LOG_NETWORKING, "Cannot open socket for OLSR PDUs (%s)\n", strerror(errno));
183     olsr_exit(EXIT_FAILURE);
184   }
185
186   if (setsockopt(Sock, SOL_SOCKET, SO_BROADCAST, (char *)&On, sizeof(On)) < 0) {
187     OLSR_ERROR(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to broadcast mode (%s)\n", strerror(errno));
188     os_close(Sock);
189     olsr_exit(EXIT_FAILURE);
190   }
191
192   if (setsockopt(Sock, SOL_SOCKET, SO_REUSEADDR, (char *)&On, sizeof(On)) < 0) {
193     OLSR_ERROR(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to broadcast mode (%s)\n", strerror(errno));
194     os_close(Sock);
195     olsr_exit(EXIT_FAILURE);
196   }
197
198   while (bufspace > 8192) {
199     if (setsockopt(Sock, SOL_SOCKET, SO_RCVBUF, (char *)&bufspace, sizeof(bufspace)) == 0)
200       break;
201
202     bufspace -= 1024;
203   }
204
205   if (bufspace <= 8192)
206     OLSR_WARN(LOG_NETWORKING, "Cannot set IPv6 socket receive buffer.\n");
207
208   if (bindto == NULL) {
209     memset(&Addr6, 0, sizeof(Addr6));
210     Addr6.sin6_family = AF_INET6;
211     Addr6.sin6_port = htons(port);
212     bindto = (union olsr_sockaddr *)&Addr6;
213   }
214
215   if (bind(Sock, &bindto->std, sizeof(Addr6)) < 0) {
216     OLSR_ERROR(LOG_NETWORKING, "Could not bind socket for OLSR PDUs to device (%s)\n", strerror(errno));
217     os_close(Sock);
218     olsr_exit(EXIT_FAILURE);
219   }
220
221   return Sock;
222 }
223
224 static int
225 join_mcast(struct interface *Nic, int Sock)
226 {
227   /* See linux/in6.h */
228   struct ipaddr_str buf;
229   struct ipv6_mreq McastReq;
230
231   McastReq.ipv6mr_multiaddr = Nic->int_multicast.v6.sin6_addr;
232   McastReq.ipv6mr_interface = Nic->if_index;
233
234   OLSR_DEBUG(LOG_NETWORKING, "Interface %s joining multicast %s...", Nic->int_name,
235              olsr_ip_to_string(&buf, (union olsr_ip_addr *)&Nic->int_multicast.v6.sin6_addr));
236   /* Send multicast */
237   if (setsockopt(Sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&McastReq, sizeof(struct ipv6_mreq))
238       < 0) {
239     OLSR_WARN(LOG_NETWORKING, "Join multicast: %s\n", strerror(errno));
240     return -1;
241   }
242
243   /* Old libc fix */
244 #ifdef IPV6_JOIN_GROUP
245   /* Join reciever group */
246   if (setsockopt(Sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&McastReq, sizeof(struct ipv6_mreq))
247       < 0)
248 #else
249   /* Join reciever group */
250   if (setsockopt(Sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&McastReq, sizeof(struct ipv6_mreq))
251       < 0)
252 #endif
253   {
254     OLSR_WARN(LOG_NETWORKING, "Join multicast send: %s\n", strerror(errno));
255     return -1;
256   }
257
258
259   if (setsockopt(Sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&McastReq.ipv6mr_interface, sizeof(McastReq.ipv6mr_interface))
260       < 0) {
261     OLSR_WARN(LOG_NETWORKING, "Join multicast if: %s\n", strerror(errno));
262     return -1;
263   }
264
265   return 0;
266 }
267
268 void
269 os_socket_set_olsr_options(struct interface *ifp, int sock) {
270   join_mcast(ifp, sock);
271 }
272
273 static int
274 SetEnableRedirKey(unsigned long New)
275 {
276 #if !defined WINCE
277   HKEY Key;
278   unsigned long Type;
279   unsigned long Len;
280   unsigned long Old;
281
282   if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
283                    "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", 0, KEY_READ | KEY_WRITE, &Key) != ERROR_SUCCESS)
284     return -1;
285
286   Len = sizeof(Old);
287
288   if (RegQueryValueEx(Key, "EnableICMPRedirect", NULL, &Type, (unsigned char *)&Old, &Len) != ERROR_SUCCESS || Type != REG_DWORD)
289     Old = 1;
290
291   if (RegSetValueEx(Key, "EnableICMPRedirect", 0, REG_DWORD, (unsigned char *)&New, sizeof(New))) {
292     RegCloseKey(Key);
293     return -1;
294   }
295
296   RegCloseKey(Key);
297   return Old;
298 #else
299   return 0;
300 #endif
301 }
302
303 static void
304 DisableIcmpRedirects(void)
305 {
306   int Res;
307
308   Res = SetEnableRedirKey(0);
309
310   if (Res != 1)
311     return;
312
313   OLSR_ERROR(LOG_NETWORKING, "\n*** IMPORTANT *** IMPORTANT *** IMPORTANT *** IMPORTANT *** IMPORTANT ***\n\n");
314
315 #if 0
316   if (Res < 0) {
317     OLSR_ERROR(LOG_NETWORKING, "Cannot disable ICMP redirect processing in the registry.\n");
318     OLSR_ERROR(LOG_NETWORKING, "Please disable it manually. Continuing in 3 seconds...\n");
319     Sleep(3000);
320
321     return;
322   }
323 #endif
324
325   OLSR_ERROR(LOG_NETWORKING, "I have disabled ICMP redirect processing in the registry for you.\n");
326   OLSR_ERROR(LOG_NETWORKING, "REBOOT NOW, so that these changes take effect. Exiting...\n\n");
327
328   exit(0);
329 }
330
331 static OVERLAPPED RouterOver;
332
333 /* enable IP forwarding */
334 void os_init(void)
335 {
336   HMODULE Lib;
337   unsigned int __stdcall(*EnableRouterFunc) (HANDLE * Hand, OVERLAPPED * Over);
338   HANDLE Hand;
339
340   Lib = LoadLibrary(WIDE_STRING("iphlpapi.dll"));
341
342   if (Lib == NULL)
343     return;
344
345   EnableRouterFunc = (unsigned int __stdcall(*)(HANDLE *, OVERLAPPED *))
346     GetProcAddress(Lib, WIDE_STRING("EnableRouter"));
347
348   if (EnableRouterFunc == NULL)
349     return;
350
351   memset(&RouterOver, 0, sizeof(OVERLAPPED));
352
353   RouterOver.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
354
355   if (RouterOver.hEvent == NULL) {
356     OLSR_WARN(LOG_NETWORKING, "CreateEvent()");
357     return;
358   }
359
360   if (EnableRouterFunc(&Hand, &RouterOver) != ERROR_IO_PENDING) {
361     OLSR_WARN(LOG_NETWORKING, "EnableRouter()");
362     return;
363   }
364
365   OLSR_DEBUG(LOG_NETWORKING, "Routing enabled.\n");
366
367   DisableIcmpRedirects();
368
369   return;
370 }
371
372 /**
373  * disable IP forwarding
374  */
375 void os_cleanup(void) {
376   HMODULE Lib;
377   unsigned int __stdcall(*UnenableRouterFunc) (OVERLAPPED * Over, unsigned int *Count);
378   unsigned int Count;
379
380   Lib = LoadLibrary(WIDE_STRING("iphlpapi.dll"));
381
382   if (Lib == NULL)
383     return;
384
385   UnenableRouterFunc = (unsigned int __stdcall(*)(OVERLAPPED *, unsigned int *))
386     GetProcAddress(Lib, WIDE_STRING("UnenableRouter"));
387
388   if (UnenableRouterFunc == NULL)
389     return;
390
391   if (UnenableRouterFunc(&RouterOver, &Count) != NO_ERROR) {
392     OLSR_WARN(LOG_NETWORKING, "UnenableRouter()");
393     return;
394   }
395
396   OLSR_DEBUG(LOG_NETWORKING, "Routing disabled, count = %u.\n", Count);
397 }
398
399 /**
400  * Wrapper for sendto(2)
401  */
402
403 ssize_t
404 os_sendto(int s, const void *buf, size_t len, int flags, const union olsr_sockaddr *sock)
405 {
406   return sendto(s, buf, len, flags, &sock->std, sizeof(*sock));
407 }
408
409
410 /**
411  * Wrapper for recvfrom(2)
412  */
413
414 ssize_t
415 os_recvfrom(int s, void *buf, size_t len, int flags __attribute__ ((unused)), union olsr_sockaddr *sock, socklen_t * fromlen)
416 {
417   return recvfrom(s, buf, len, 0, &sock->std, fromlen);
418 }
419
420 /**
421  * Wrapper for select(2)
422  */
423
424 int
425 os_select(int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval *timeout)
426 {
427   return select(nfds, readfds, writefds, exceptfds, timeout);
428 }
429
430 /*
431  * Local Variables:
432  * c-basic-offset: 2
433  * indent-tabs-mode: nil
434  * End:
435  */