19a9c0cf9732214c3a35a40720b7d975726f05a2
[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 "net_os.h"
59 #include "net_olsr.h"
60 #include "ipcalc.h"
61 #include "olsr_logging.h"
62
63 #if defined WINCE
64 #define WIDE_STRING(s) L##s
65 #else
66 #define WIDE_STRING(s) s
67 #endif
68
69 void WinSockPError(const char *Str);
70 void PError(const char *);
71
72 void DisableIcmpRedirects(void);
73 int disable_ip_forwarding(int Ver);
74
75
76 int
77 getsocket4(int bufspace, struct interface *ifp, bool bind_to_unicast, uint16_t port)
78 {
79   struct sockaddr_in Addr;
80   int On = 1;
81   unsigned long Len;
82   int Sock = socket(AF_INET, SOCK_DGRAM, 0);
83   if (Sock < 0) {
84     OLSR_ERROR(LOG_NETWORKING, "Cannot open socket for OLSR PDUs (%s)\n", strerror(errno));
85     olsr_exit(EXIT_FAILURE);
86   }
87
88   if (setsockopt(Sock, SOL_SOCKET, SO_BROADCAST, (char *)&On, sizeof(On)) < 0) {
89     OLSR_ERROR(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to broadcast mode (%s)\n", strerror(errno));
90     CLOSESOCKET(Sock);
91     olsr_exit(EXIT_FAILURE);
92   }
93
94   if (setsockopt(Sock, SOL_SOCKET, SO_REUSEADDR, (char *)&On, sizeof(On)) < 0) {
95     OLSR_ERROR(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to broadcast mode (%s)\n", strerror(errno));
96     CLOSESOCKET(Sock);
97     olsr_exit(EXIT_FAILURE);
98   }
99
100   while (bufspace > 8192) {
101     if (setsockopt(Sock, SOL_SOCKET, SO_RCVBUF, (char *)&bufspace, sizeof(bufspace)) == 0)
102       break;
103
104     bufspace -= 1024;
105   }
106
107   if (bufspace <= 8192)
108     OLSR_WARN(LOG_NETWORKING, "Cannot set IPv4 socket receive buffer.\n");
109
110   memset(&Addr, 0, sizeof(Addr));
111   Addr.sin_family = AF_INET;
112   Addr.sin_port = htons(port);
113
114   if(bind_to_unicast) {
115     Addr.sin_addr.s_addr = ifp->int_src.v4.sin_addr.s_addr;
116   }
117   else {
118     Addr.sin_addr.s_addr = INADDR_ANY;
119   }
120
121   if (bind(Sock, (struct sockaddr *)&Addr, sizeof(Addr)) < 0) {
122     OLSR_ERROR(LOG_NETWORKING, "Could not bind socket for OLSR PDUs to device (%s)\n", strerror(errno));
123     CLOSESOCKET(Sock);
124     olsr_exit(EXIT_FAILURE);
125   }
126
127   if (WSAIoctl(Sock, FIONBIO, &On, sizeof(On), NULL, 0, &Len, NULL, NULL) < 0) {
128     OLSR_ERROR(LOG_NETWORKING, "WSAIoctl");
129     CLOSESOCKET(Sock);
130     olsr_exit(EXIT_FAILURE);
131   }
132
133   return Sock;
134 }
135
136 int
137 getsocket6(int bufspace, struct interface *ifp, bool bind_to_unicast, uint16_t port)
138 {
139   struct sockaddr_in6 Addr6;
140   int On = 1;
141   int Sock = socket(AF_INET6, SOCK_DGRAM, 0);
142   if (Sock < 0) {
143     OLSR_ERROR(LOG_NETWORKING, "Cannot open socket for OLSR PDUs (%s)\n", strerror(errno));
144     olsr_exit(EXIT_FAILURE);
145   }
146
147   if (setsockopt(Sock, SOL_SOCKET, SO_BROADCAST, (char *)&On, sizeof(On)) < 0) {
148     OLSR_ERROR(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to broadcast mode (%s)\n", strerror(errno));
149     CLOSESOCKET(Sock);
150     olsr_exit(EXIT_FAILURE);
151   }
152
153   if (setsockopt(Sock, SOL_SOCKET, SO_REUSEADDR, (char *)&On, sizeof(On)) < 0) {
154     OLSR_ERROR(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to broadcast mode (%s)\n", strerror(errno));
155     CLOSESOCKET(Sock);
156     olsr_exit(EXIT_FAILURE);
157   }
158
159   while (bufspace > 8192) {
160     if (setsockopt(Sock, SOL_SOCKET, SO_RCVBUF, (char *)&bufspace, sizeof(bufspace)) == 0)
161       break;
162
163     bufspace -= 1024;
164   }
165
166   if (bufspace <= 8192)
167     OLSR_WARN(LOG_NETWORKING, "Cannot set IPv6 socket receive buffer.\n");
168
169   memset(&Addr6, 0, sizeof(Addr6));
170   Addr6.sin6_family = AF_INET6;
171   Addr6.sin6_port = htons(port);
172
173   if(bind_to_unicast) {
174     memcpy(&Addr6.sin6_addr, &ifp->int_src.v6.sin6_addr, sizeof(struct in6_addr));
175   }
176
177   if (bind(Sock, (struct sockaddr *)&Addr6, sizeof(Addr6)) < 0) {
178     OLSR_ERROR(LOG_NETWORKING, "Could not bind socket for OLSR PDUs to device (%s)\n", strerror(errno));
179     CLOSESOCKET(Sock);
180     olsr_exit(EXIT_FAILURE);
181   }
182
183   return Sock;
184 }
185
186 void
187 os_set_olsr_socketoptions(int sock __attribute__ ((unused))) {
188 }
189
190 static OVERLAPPED RouterOver;
191
192 int
193 enable_ip_forwarding(int Ver)
194 {
195   HMODULE Lib;
196   unsigned int __stdcall(*EnableRouterFunc) (HANDLE * Hand, OVERLAPPED * Over);
197   HANDLE Hand;
198
199   Ver = Ver;
200
201   Lib = LoadLibrary(WIDE_STRING("iphlpapi.dll"));
202
203   if (Lib == NULL)
204     return 0;
205
206   EnableRouterFunc = (unsigned int __stdcall(*)(HANDLE *, OVERLAPPED *))
207     GetProcAddress(Lib, WIDE_STRING("EnableRouter"));
208
209   if (EnableRouterFunc == NULL)
210     return 0;
211
212   memset(&RouterOver, 0, sizeof(OVERLAPPED));
213
214   RouterOver.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
215
216   if (RouterOver.hEvent == NULL) {
217     OLSR_WARN(LOG_NETWORKING, "CreateEvent()");
218     return -1;
219   }
220
221   if (EnableRouterFunc(&Hand, &RouterOver) != ERROR_IO_PENDING) {
222     OLSR_WARN(LOG_NETWORKING, "EnableRouter()");
223     return -1;
224   }
225
226   OLSR_DEBUG(LOG_NETWORKING, "Routing enabled.\n");
227
228   return 0;
229 }
230
231 int
232 disable_ip_forwarding(int Ver)
233 {
234   HMODULE Lib;
235   unsigned int __stdcall(*UnenableRouterFunc) (OVERLAPPED * Over, unsigned int *Count);
236   unsigned int Count;
237
238   Ver = Ver;
239
240   Lib = LoadLibrary(WIDE_STRING("iphlpapi.dll"));
241
242   if (Lib == NULL)
243     return 0;
244
245   UnenableRouterFunc = (unsigned int __stdcall(*)(OVERLAPPED *, unsigned int *))
246     GetProcAddress(Lib, WIDE_STRING("UnenableRouter"));
247
248   if (UnenableRouterFunc == NULL)
249     return 0;
250
251   if (UnenableRouterFunc(&RouterOver, &Count) != NO_ERROR) {
252     OLSR_WARN(LOG_NETWORKING, "UnenableRouter()");
253     return -1;
254   }
255
256   OLSR_DEBUG(LOG_NETWORKING, "Routing disabled, count = %u.\n", Count);
257
258   return 0;
259 }
260
261 int
262 restore_settings(int Ver)
263 {
264   disable_ip_forwarding(Ver);
265
266   return 0;
267 }
268
269 static int
270 SetEnableRedirKey(unsigned long New)
271 {
272 #if !defined WINCE
273   HKEY Key;
274   unsigned long Type;
275   unsigned long Len;
276   unsigned long Old;
277
278   if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
279                    "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", 0, KEY_READ | KEY_WRITE, &Key) != ERROR_SUCCESS)
280     return -1;
281
282   Len = sizeof(Old);
283
284   if (RegQueryValueEx(Key, "EnableICMPRedirect", NULL, &Type, (unsigned char *)&Old, &Len) != ERROR_SUCCESS || Type != REG_DWORD)
285     Old = 1;
286
287   if (RegSetValueEx(Key, "EnableICMPRedirect", 0, REG_DWORD, (unsigned char *)&New, sizeof(New))) {
288     RegCloseKey(Key);
289     return -1;
290   }
291
292   RegCloseKey(Key);
293   return Old;
294 #else
295   return 0;
296 #endif
297 }
298
299 void
300 DisableIcmpRedirects(void)
301 {
302   int Res;
303
304   Res = SetEnableRedirKey(0);
305
306   if (Res != 1)
307     return;
308
309   OLSR_ERROR(LOG_NETWORKING, "\n*** IMPORTANT *** IMPORTANT *** IMPORTANT *** IMPORTANT *** IMPORTANT ***\n\n");
310
311 #if 0
312   if (Res < 0) {
313     OLSR_ERROR(LOG_NETWORKING, "Cannot disable ICMP redirect processing in the registry.\n");
314     OLSR_ERROR(LOG_NETWORKING, "Please disable it manually. Continuing in 3 seconds...\n");
315     Sleep(3000);
316
317     return;
318   }
319 #endif
320
321   OLSR_ERROR(LOG_NETWORKING, "I have disabled ICMP redirect processing in the registry for you.\n");
322   OLSR_ERROR(LOG_NETWORKING, "REBOOT NOW, so that these changes take effect. Exiting...\n\n");
323
324   exit(0);
325 }
326
327
328 int
329 join_mcast(struct interface *Nic, int Sock)
330 {
331   /* See linux/in6.h */
332   struct ipaddr_str buf;
333   struct ipv6_mreq McastReq;
334
335   McastReq.ipv6mr_multiaddr = Nic->int_multicast.v6.sin6_addr;
336   McastReq.ipv6mr_interface = Nic->if_index;
337
338   OLSR_DEBUG(LOG_NETWORKING, "Interface %s joining multicast %s...", Nic->int_name,
339              olsr_ip_to_string(&buf, (union olsr_ip_addr *)&Nic->int_multicast.v6.sin6_addr));
340   /* Send multicast */
341   if (setsockopt(Sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&McastReq, sizeof(struct ipv6_mreq))
342       < 0) {
343     OLSR_WARN(LOG_NETWORKING, "Join multicast: %s\n", strerror(errno));
344     return -1;
345   }
346
347   /* Old libc fix */
348 #ifdef IPV6_JOIN_GROUP
349   /* Join reciever group */
350   if (setsockopt(Sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&McastReq, sizeof(struct ipv6_mreq))
351       < 0)
352 #else
353   /* Join reciever group */
354   if (setsockopt(Sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&McastReq, sizeof(struct ipv6_mreq))
355       < 0)
356 #endif
357   {
358     OLSR_WARN(LOG_NETWORKING, "Join multicast send: %s\n", strerror(errno));
359     return -1;
360   }
361
362
363   if (setsockopt(Sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&McastReq.ipv6mr_interface, sizeof(McastReq.ipv6mr_interface))
364       < 0) {
365     OLSR_WARN(LOG_NETWORKING, "Join multicast if: %s\n", strerror(errno));
366     return -1;
367   }
368
369   return 0;
370 }
371
372
373 /**
374  * Wrapper for sendto(2)
375  */
376
377 ssize_t
378 olsr_sendto(int s, const void *buf, size_t len, int flags, const union olsr_sockaddr *sock)
379 {
380   return sendto(s, buf, len, flags, &sock->std, sizeof(*sock));
381 }
382
383
384 /**
385  * Wrapper for recvfrom(2)
386  */
387
388 ssize_t
389 olsr_recvfrom(int s, void *buf, size_t len, int flags __attribute__ ((unused)), union olsr_sockaddr *sock, socklen_t * fromlen)
390 {
391   return recvfrom(s, buf, len, 0, &sock->std, fromlen);
392 }
393
394 /**
395  * Wrapper for select(2)
396  */
397
398 int
399 olsr_select(int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval *timeout)
400 {
401   return select(nfds, readfds, writefds, exceptfds, timeout);
402 }
403
404 /*
405  * Local Variables:
406  * c-basic-offset: 2
407  * indent-tabs-mode: nil
408  * End:
409  */