Print a warning if an illegal value is used for the spi but continue
[vpnc.git] / sysdep.c
blobd8f181d537fade0a02589bf7d4d37352302ca3f6
1 /* IPSec VPN client compatible with Cisco equipment.
2 Copyright (C) 2007 Maurice Massar
3 Copyright (C) 2007 Paolo Zarpellon <paolo.zarpellon@gmail.com> (Cygwin support)
5 based on VTun - Virtual Tunnel over TCP/IP network.
6 Copyright (C) 1998-2000 Maxim Krasnyansky <max_mk@yahoo.com>
7 VTun has been derived from VPPP package by Maxim Krasnyansky.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <syslog.h>
26 #include <sys/ioctl.h>
27 #include <errno.h>
29 #include <sys/socket.h>
30 #include <net/if.h>
32 #ifdef __sun__
33 #include <ctype.h>
34 #include <sys/time.h>
35 #include <sys/wait.h>
36 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <sys/sockio.h>
39 #include <signal.h>
40 #include <stropts.h>
41 #include <netinet/in.h>
42 #include <netinet/in_systm.h>
43 #include <netinet/ip.h>
44 #include <netinet/tcp.h>
45 #endif
47 #if defined(__CYGWIN__)
48 #include <io.h>
49 #include <w32api/windef.h>
50 #include <w32api/winbase.h>
51 #include <w32api/winnt.h>
52 #include <w32api/winioctl.h>
53 #include <w32api/iphlpapi.h>
54 #include <w32api/iptypes.h>
55 #include <w32api/winreg.h>
56 #include <sys/cygwin.h>
57 #endif
59 #if defined(__DragonFly__)
60 #include <net/tun/if_tun.h>
61 #elif defined(__linux__)
62 #include <linux/if_tun.h>
63 #elif defined(__APPLE__)
64 /* no header for tun */
65 #elif defined(__CYGWIN__)
66 #include "tap-win32.h"
67 #else
68 #include <net/if_tun.h>
69 #endif
71 #include "sysdep.h"
73 #if !defined(HAVE_VASPRINTF) || !defined(HAVE_ASPRINTF) || !defined(HAVE_ERROR)
74 #include <stdarg.h>
75 #endif
77 #if defined(__sun__)
78 extern char **environ;
79 static int ip_fd = -1, muxid;
80 #endif
82 #if defined(__CYGWIN__)
84 * Overlapped structures for asynchronous read and write
86 static OVERLAPPED overlap_read, overlap_write;
88 typedef enum {
89 SEARCH_IF_GUID_FROM_NAME,
90 SEARCH_IF_NAME_FROM_GUID
91 } search_if_en;
92 #endif
95 * Allocate TUN/TAP device, returns opened fd.
96 * Stores dev name in the first arg(must be large enough).
98 #if defined(__sun__)
99 int tun_open(char *dev, enum if_mode_enum mode)
101 int tun_fd, if_fd, ppa = -1;
102 struct ifreq ifr;
103 char *ptr;
105 if (*dev) {
106 ptr = dev;
107 while (*ptr && !isdigit((int)*ptr))
108 ptr++;
109 ppa = atoi(ptr);
112 if ((ip_fd = open("/dev/ip", O_RDWR, 0)) < 0) {
113 logmsg(LOG_ERR, "Can't open /dev/ip");
114 return -1;
117 if ((tun_fd = open(((mode == IF_MODE_TUN) ? "/dev/tun" : "/dev/tap"), O_RDWR, 0)) < 0) {
118 logmsg(LOG_ERR, "Can't open /dev/tun");
119 return -1;
122 /* Assign a new PPA and get its unit number. */
123 if ((ppa = ioctl(tun_fd, TUNNEWPPA, ppa)) < 0) {
124 logmsg(LOG_ERR, "Can't assign new interface");
125 return -1;
128 if ((if_fd = open(((mode == IF_MODE_TUN) ? "/dev/tun" : "/dev/tap"), O_RDWR, 0)) < 0) {
129 logmsg(LOG_ERR, "Can't open /dev/tun (2)");
130 return -1;
132 if (ioctl(if_fd, I_PUSH, "ip") < 0) {
133 logmsg(LOG_ERR, "Can't push IP module");
134 return -1;
137 /* Assign ppa according to the unit number returned by tun device */
138 if (ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0 && errno != EEXIST) {
139 logmsg(LOG_ERR, "Can't set PPA %d", ppa);
140 return -1;
142 if ((muxid = ioctl(ip_fd, I_PLINK, if_fd)) < 0) {
143 logmsg(LOG_ERR, "Can't link TUN device to IP");
144 return -1;
146 close(if_fd);
148 snprintf(dev, IFNAMSIZ, "%s%d", ((mode == IF_MODE_TUN) ? "tun" : "tap"), ppa);
150 memset(&ifr, 0, sizeof(ifr));
151 strcpy(ifr.ifr_name, dev);
152 ifr.ifr_ip_muxid = muxid;
154 if (ioctl(ip_fd, SIOCSIFMUXID, &ifr) < 0) {
155 ioctl(ip_fd, I_PUNLINK, muxid);
156 logmsg(LOG_ERR, "Can't set multiplexor id");
157 return -1;
160 return tun_fd;
162 #elif defined(__CYGWIN__)
164 * Get interface guid/name from registry
166 static char *search_if(char *value, char *key, search_if_en type)
168 int i = 0;
169 LONG status;
170 DWORD len;
171 HKEY net_conn_key;
172 BOOL found = FALSE;
173 char guid[256];
174 char ifname[256];
175 char conn_string[512];
176 HKEY conn_key;
177 DWORD value_type;
179 if (!value || !key) {
180 return NULL;
183 status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
184 NETWORK_CONNECTIONS_KEY,
186 KEY_READ,
187 &net_conn_key);
189 if (status != ERROR_SUCCESS) {
190 printf("Error opening registry key: %s\n", NETWORK_CONNECTIONS_KEY);
191 return NULL;
194 while (!found) {
195 len = sizeof(guid);
196 status = RegEnumKeyEx(net_conn_key, i++, guid, &len,
197 NULL, NULL, NULL, NULL);
198 if (status == ERROR_NO_MORE_ITEMS) {
199 break;
200 } else if (status != ERROR_SUCCESS) {
201 continue;
203 snprintf(conn_string, sizeof(conn_string),
204 "%s\\%s\\Connection",
205 NETWORK_CONNECTIONS_KEY, guid);
206 status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
207 conn_string,
209 KEY_READ,
210 &conn_key);
211 if (status != ERROR_SUCCESS) {
212 continue;
214 len = sizeof(ifname);
215 status = RegQueryValueEx(conn_key, "Name", NULL,
216 &value_type, ifname, &len);
217 if (status != ERROR_SUCCESS || value_type != REG_SZ) {
218 RegCloseKey(conn_key);
219 continue;
222 switch (type) {
223 case SEARCH_IF_GUID_FROM_NAME:
224 if (!strcmp(key, ifname)) {
225 strcpy(value, guid);
226 found = TRUE;
228 break;
229 case SEARCH_IF_NAME_FROM_GUID:
230 if (!strcmp(key, guid)) {
231 strcpy(value, ifname);
232 found = TRUE;
234 break;
235 default:
236 break;
238 RegCloseKey(conn_key);
240 RegCloseKey(net_conn_key);
242 if (found) {
243 return value;
246 return NULL;
250 * Open the TUN/TAP device with the provided guid
252 static int open_tun_device (char *guid, char *dev, enum if_mode_enum mode)
254 HANDLE handle;
255 ULONG len, status, info[3];
256 char device_path[512];
258 printf("Device: %s\n", dev);
260 if (mode == IF_MODE_TUN) {
261 printf("TUN mode is not supported\n");
262 return -1;
266 * Let's try to open Windows TAP-Win32 adapter
268 snprintf(device_path, sizeof(device_path), "%s%s%s",
269 USERMODEDEVICEDIR, guid, TAPSUFFIX);
271 handle = CreateFile(device_path,
272 GENERIC_READ | GENERIC_WRITE,
273 0, /* Don't let other processes share or open
274 the resource until the handle's been closed */
276 OPEN_EXISTING,
277 FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
280 if (handle == INVALID_HANDLE_VALUE) {
281 return -1;
285 * get driver version info
287 memset(info, 0, sizeof(info));
288 if (DeviceIoControl(handle, TAP_IOCTL_GET_VERSION,
289 &info, sizeof(info),
290 &info, sizeof(info), &len, NULL)) {
291 printf("TAP-Win32 Driver Version %d.%d %s\n",
292 (int) info[0],
293 (int) info[1],
294 (info[2] ? "(DEBUG)" : ""));
298 * Set driver media status to 'connected'
300 status = TRUE;
301 if (!DeviceIoControl(handle, TAP_IOCTL_SET_MEDIA_STATUS,
302 &status, sizeof(status),
303 &status, sizeof(status), &len, NULL)) {
304 printf("WARNING: The TAP-Win32 driver rejected a "
305 "TAP_IOCTL_SET_MEDIA_STATUS DeviceIoControl call.\n");
309 * Initialize overlapped structures
311 overlap_read.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
312 overlap_write.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
313 if (!overlap_read.hEvent || !overlap_write.hEvent) {
314 return -1;
318 * Return fd
320 return cygwin_attach_handle_to_fd(NULL, -1, handle, 1, GENERIC_READ | GENERIC_WRITE);
324 * Allocate TUN device, returns opened fd.
325 * Stores dev name in the first arg (must be large enough).
327 int tun_open (char *dev, enum if_mode_enum mode)
329 int fd = -1;
330 HKEY unit_key;
331 char guid[256];
332 char comp_id[256];
333 char enum_name[256];
334 char unit_string[512];
335 BOOL found = FALSE;
336 HKEY adapter_key;
337 DWORD value_type;
338 LONG status;
339 DWORD len;
341 if (!dev) {
342 return -1;
346 * Device name has been provided. Open such device.
348 if (*dev != '\0') {
349 if (!search_if(guid, dev, SEARCH_IF_GUID_FROM_NAME)) {
350 return -1;
352 return open_tun_device(guid, dev, mode);
356 * Device name has non been specified. Look for one available!
358 int i = 0;
359 status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
360 ADAPTER_KEY,
362 KEY_READ,
363 &adapter_key);
364 if (status != ERROR_SUCCESS) {
365 printf("Error opening registry key: %s", ADAPTER_KEY);
366 return -1;
369 while (!found) {
370 len = sizeof(enum_name);
371 status = RegEnumKeyEx(adapter_key, i++,
372 enum_name, &len,
373 NULL, NULL, NULL, NULL);
374 if (status == ERROR_NO_MORE_ITEMS) {
375 break;
376 } else if (status != ERROR_SUCCESS) {
377 continue;
379 snprintf(unit_string, sizeof(unit_string), "%s\\%s",
380 ADAPTER_KEY, enum_name);
381 status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
382 unit_string,
384 KEY_READ,
385 &unit_key);
386 if (status != ERROR_SUCCESS) {
387 continue;
389 len = sizeof(comp_id);
390 status = RegQueryValueEx(unit_key,
391 "ComponentId", NULL,
392 &value_type, comp_id, &len);
393 if (status != ERROR_SUCCESS || value_type != REG_SZ) {
394 RegCloseKey(unit_key);
395 continue;
397 len = sizeof(guid);
398 status = RegQueryValueEx(unit_key,
399 "NetCfgInstanceId", NULL,
400 &value_type, guid, &len);
401 if (status != ERROR_SUCCESS || value_type != REG_SZ) {
402 RegCloseKey(unit_key);
403 continue;
406 int j = 0;
407 while (TAP_COMPONENT_ID[j]) {
408 if (!strcmp(comp_id, TAP_COMPONENT_ID[j])) {
409 break;
411 j++;
413 if (!TAP_COMPONENT_ID[j]) {
414 RegCloseKey(unit_key);
415 continue;
419 * Let's try to open this device
421 search_if(dev, guid, SEARCH_IF_NAME_FROM_GUID);
422 fd = open_tun_device(guid, dev, mode);
423 if (fd != -1) {
424 found = TRUE;
427 RegCloseKey(unit_key);
429 RegCloseKey(adapter_key);
431 return fd;
433 #elif defined(IFF_TUN)
434 int tun_open(char *dev, enum if_mode_enum mode)
436 struct ifreq ifr;
437 int fd, err;
439 if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
440 error(0, errno,
441 "can't open /dev/net/tun, check that it is either device char 10 200 or (with DevFS) a symlink to ../misc/net/tun (not misc/net/tun)");
442 return -1;
445 memset(&ifr, 0, sizeof(ifr));
446 ifr.ifr_flags = ((mode == IF_MODE_TUN) ? IFF_TUN : IFF_TAP) | IFF_NO_PI;
447 if (*dev)
448 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
450 if ((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0) {
451 close(fd);
452 return err;
454 strcpy(dev, ifr.ifr_name);
455 return fd;
457 #else
458 int tun_open(char *dev, enum if_mode_enum mode)
460 char tunname[14];
461 int i, fd;
463 if (*dev) {
464 if (strncmp(dev, ((mode == IF_MODE_TUN) ? "tun" : "tap"), 3))
465 error(1, 0,
466 "error: arbitrary naming tunnel interface is not supported in this version\n");
467 snprintf(tunname, sizeof(tunname), "/dev/%s", dev);
468 return open(tunname, O_RDWR);
471 for (i = 0; i < 255; i++) {
472 snprintf(tunname, sizeof(tunname), "/dev/%s%d",
473 ((mode == IF_MODE_TUN) ? "tun" : "tap"), i);
474 /* Open device */
475 if ((fd = open(tunname, O_RDWR)) > 0) {
476 snprintf(dev, IFNAMSIZ, "%s%d",
477 ((mode == IF_MODE_TUN) ? "tun" : "tap"), i);
478 return fd;
481 return -1;
483 #endif /* New driver support */
486 * Close TUN device.
488 #if defined(__sun__)
489 int tun_close(int fd, char *dev)
491 struct ifreq ifr;
493 memset(&ifr, 0, sizeof(ifr));
494 strcpy(ifr.ifr_name, dev);
495 if (ioctl(ip_fd, SIOCGIFFLAGS, &ifr) < 0) {
496 logmsg(LOG_ERR, "Can't get iface flags");
497 return 0;
500 if (ioctl(ip_fd, I_PUNLINK, muxid) < 0) {
501 logmsg(LOG_ERR, "Can't unlink interface");
502 return 0;
505 close(ip_fd);
506 ip_fd = -1;
507 close(fd);
508 return 0;
510 #elif defined(__CYGWIN__)
511 int tun_close(int fd, char *dev)
513 dev = NULL; /* unused */
514 return CloseHandle((HANDLE) get_osfhandle(fd));
516 #else
517 int tun_close(int fd, char *dev)
519 dev = NULL; /*unused */
520 return close(fd);
522 #endif
525 #if defined(__sun__)
526 int tun_write(int fd, unsigned char *buf, int len)
528 struct strbuf sbuf;
529 sbuf.len = len;
530 sbuf.buf = buf;
531 return putmsg(fd, NULL, &sbuf, 0) >= 0 ? sbuf.len : -1;
534 int tun_read(int fd, unsigned char *buf, int len)
536 struct strbuf sbuf;
537 int f = 0;
539 sbuf.maxlen = len;
540 sbuf.buf = buf;
541 return getmsg(fd, NULL, &sbuf, &f) >= 0 ? sbuf.len : -1;
543 #elif defined(__CYGWIN__)
544 int tun_read(int fd, unsigned char *buf, int len)
546 DWORD read_size;
548 ResetEvent(overlap_read.hEvent);
549 if (ReadFile((HANDLE) get_osfhandle(fd), buf, len, &read_size, &overlap_read)) {
550 return read_size;
552 switch (GetLastError()) {
553 case ERROR_IO_PENDING:
554 WaitForSingleObject(overlap_read.hEvent, INFINITE);
555 GetOverlappedResult((HANDLE) get_osfhandle(fd), &overlap_read, &read_size, FALSE);
556 return read_size;
557 break;
558 default:
559 break;
562 return -1;
565 int tun_write(int fd, unsigned char *buf, int len)
567 DWORD write_size;
569 ResetEvent(overlap_write.hEvent);
570 if (WriteFile((HANDLE) get_osfhandle(fd),
571 buf,
572 len,
573 &write_size,
574 &overlap_write)) {
575 return write_size;
577 switch (GetLastError()) {
578 case ERROR_IO_PENDING:
579 WaitForSingleObject(overlap_write.hEvent, INFINITE);
580 GetOverlappedResult((HANDLE) get_osfhandle(fd), &overlap_write,
581 &write_size, FALSE);
582 return write_size;
583 break;
584 default:
585 break;
588 return -1;
590 #elif defined(NEW_TUN)
591 #define MAX_MRU 2048
592 struct tun_data {
593 union {
594 uint32_t family;
595 uint32_t timeout;
596 } header;
597 u_char data[MAX_MRU];
600 /* Read/write frames from TUN device */
601 int tun_write(int fd, unsigned char *buf, int len)
603 char *data;
604 struct tun_data tun;
606 if (len > (int)sizeof(tun.data))
607 return -1;
609 memcpy(tun.data, buf, len);
610 tun.header.family = htonl(AF_INET);
611 len += (sizeof(tun) - sizeof(tun.data));
612 data = (char *)&tun;
614 return write(fd, data, len) - (sizeof(tun) - sizeof(tun.data));
617 int tun_read(int fd, unsigned char *buf, int len)
619 struct tun_data tun;
620 char *data;
621 size_t sz;
622 int pack;
624 data = (char *)&tun;
625 sz = sizeof(tun);
626 pack = read(fd, data, sz);
627 if (pack == -1)
628 return -1;
630 pack -= sz - sizeof(tun.data);
631 if (pack > len)
632 pack = len; /* truncate packet */
634 memcpy(buf, tun.data, pack);
636 return pack;
639 #else
641 int tun_write(int fd, unsigned char *buf, int len)
643 return write(fd, buf, len);
646 int tun_read(int fd, unsigned char *buf, int len)
648 return read(fd, buf, len);
651 #endif
654 * Get HW addr
656 int tun_get_hwaddr(int fd, char *dev, uint8_t *hwaddr)
658 #if defined(__CYGWIN__)
659 ULONG len;
661 dev = NULL; /* unused */
662 if (!DeviceIoControl((HANDLE) get_osfhandle(fd), TAP_IOCTL_GET_MAC,
663 hwaddr, ETH_ALEN, hwaddr, ETH_ALEN, &len, NULL)) {
664 printf("Cannot get HW address\n");
665 return -1;
668 return 0;
669 #elif defined(SIOCGIFHWADDR)
670 struct ifreq ifr;
672 /* Use a new socket fd! */
673 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
674 return -1;
677 memset(&ifr, 0, sizeof(struct ifreq));
678 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
680 if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
681 return -1;
684 memcpy(hwaddr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN);
686 return 0;
687 #else
688 /* todo: implement using SIOCGLIFADDR */
689 fd = 0;
690 dev = 0;
691 hwaddr = 0;
692 errno = ENOSYS;
693 return -1;
694 #endif
697 /***********************************************************************/
698 /* other support functions */
700 #ifndef HAVE_VASPRINTF
701 int vasprintf(char **strp, const char *fmt, va_list ap)
703 int ret;
704 char *strbuf;
706 ret = vsnprintf(NULL, 0, fmt, ap);
707 strbuf = (char *)malloc(ret + 1);
708 if (strbuf == NULL) {
709 errno = ENOMEM;
710 ret = -1;
712 vsnprintf(strbuf, ret + 1, fmt, ap);
713 *strp = strbuf;
714 return ret;
716 #endif
718 #ifndef HAVE_ASPRINTF
719 int asprintf(char **strp, const char *fmt, ...)
721 int ret;
722 va_list ap;
724 va_start(ap, fmt);
725 ret = vasprintf(strp, fmt, ap);
726 va_end(ap);
728 return ret;
730 #endif
732 #ifndef HAVE_ERROR
733 void error(int status, int errornum, const char *fmt, ...)
735 char *buf2;
736 va_list ap;
738 va_start(ap, fmt);
739 vasprintf(&buf2, fmt, ap);
740 va_end(ap);
741 fprintf(stderr, "%s", buf2);
742 if (errornum)
743 fprintf(stderr, ": %s\n", strerror(errornum));
744 else
745 fprintf(stderr, "\n");
746 free(buf2);
748 if (status)
749 exit(status);
751 #endif
753 #ifndef HAVE_UNSETENV
754 int unsetenv(const char *name)
756 int i, len;
758 len = strlen(name);
759 for (i = 0; environ[i]; i++)
760 if (!strncmp(name, environ[i], len))
761 if (environ[i][len] == '=')
762 break;
764 for (; environ[i] && environ[i + 1]; i++)
765 environ[i] = environ[i + 1];
767 return 0;
769 #endif
771 #ifndef HAVE_SETENV
772 int setenv(const char *name, const char *value, int overwrite)
774 int ret;
775 char *newenv;
777 if (overwrite == 0)
778 if (getenv(name) != NULL)
779 return 0;
781 newenv = malloc(strlen(name) + 1 + strlen(value) + 1);
782 if (newenv == NULL)
783 return -1;
785 *newenv = '\0';
786 strcat(newenv, name);
787 strcat(newenv, "=");
788 strcat(newenv, value);
790 ret = putenv(newenv);
791 if (ret == -1)
792 free(newenv);
794 return ret;
796 #endif