1 /* TUNTAP.C (c) Copyright James A. Pierson, 2002-2009 */
2 /* (c) Copyright "Fish" (David B. Trout), 2002-2009 */
3 /* Hercules - TUN/TAP Abstraction Layer */
4
5 // TUN/TAP implementations differ among platforms. Linux and FreeBSD
6 // offer much the same functionality but with differing semantics.
7 // Windows does not have TUN/TAP but thanks to "Fish" (David B. Trout)
8 // we have a way of emulating the TUN/TAP interface through a set of
9 // custom DLLs he has provided us.
10 //
11 // This abstraction layer is an attempt to create a common API set
12 // that works on all platforms with (hopefully) equal results.
13 //
14
15 #include "hstdinc.h"
16
17 /* jbs 1/19/2008 added ifdef on __SOLARIS__ */
18 #if !defined(__SOLARIS__)
19
20 #include "hercules.h"
21 #include "tuntap.h"
22 #include "devtype.h"
23 #include "ctcadpt.h"
24 #include "hercifc.h"
25
26 #if defined( OPTION_W32_CTCI )
27 #include "w32ctca.h"
28 #endif
29
30 // ====================================================================
31 // Declarations
32 // ====================================================================
33
34 #ifndef OPTION_W32_CTCI
35
36 static int IFC_IOCtl( int fd, unsigned long int iRequest, char* argp );
37 static int ifc_fd[2] = { -1, -1 };
38 static pid_t ifc_pid = 0;
39
tuntap_term(void)40 static void tuntap_term(void)
41 {
42 close(ifc_fd[0]);
43 close(ifc_fd[1]);
44 ifc_fd[0] = ifc_fd[1] = -1;
45 kill(ifc_pid, SIGINT);
46 }
47
48 #endif
49
50 // ====================================================================
51 // Primary Module Entry Points
52 // ====================================================================
53
TUNTAP_SetMode(int fd,struct ifreq * ifr)54 static int TUNTAP_SetMode (int fd, struct ifreq *ifr)
55 {
56 int rc;
57
58 /* Try TUNTAP_ioctl first */
59 rc = TUNTAP_IOCtl (fd, TUNSETIFF, (char *) ifr);
60
61 #if !defined(OPTION_W32_CTCI)
62 /* If invalid value, try with the pre-2.4.5 value */
63 if (rc != 0 && errno == EINVAL)
64 rc = TUNTAP_IOCtl (fd, ('T' << 8) | 202, (char *) ifr);
65
66 /* kludge for EPERM and linux 2.6.18 */
67 if (rc != 0 && errno == EPERM)
68 {
69 int ifd[2];
70 char *hercifc;
71 pid_t pid;
72 CTLREQ ctlreq;
73 fd_set selset;
74 struct timeval tv;
75 int sv_err;
76 int status;
77
78 if (socketpair (AF_UNIX, SOCK_STREAM, 0, ifd) < 0)
79 return -1;
80
81 if (!(hercifc = getenv ("HERCULES_IFC")))
82 hercifc = HERCIFC_CMD;
83
84 pid = fork();
85
86 if (pid < 0)
87 return -1;
88 else if (pid == 0)
89 {
90 /* child */
91 dup2 (ifd[0], STDIN_FILENO);
92 dup2 (STDOUT_FILENO, STDERR_FILENO);
93 dup2 (ifd[0], STDOUT_FILENO);
94 close (ifd[1]);
95 rc = execlp (hercifc, hercifc, NULL );
96 return -1;
97 }
98
99 /* parent */
100 close(ifd[0]);
101
102 /* Request hercifc to issue the TUNSETIFF ioctl */
103 memset (&ctlreq, 0, CTLREQ_SIZE);
104 ctlreq.iCtlOp = TUNSETIFF;
105 ctlreq.iProcID = fd;
106 memcpy (&ctlreq.iru.ifreq, ifr, sizeof (struct ifreq));
107 write (ifd[1], &ctlreq, CTLREQ_SIZE);
108
109 /* Get response, if any, from hercifc */
110 FD_ZERO (&selset);
111 FD_SET (ifd[1], &selset);
112 tv.tv_sec = 5;
113 tv.tv_usec = 0;
114 rc = select (ifd[1]+1, &selset, NULL, NULL, &tv);
115 if (rc > 0)
116 {
117 rc = read (ifd[1], &ctlreq, CTLREQ_SIZE);
118 if (rc > 0)
119 memcpy (ifr, &ctlreq.iru.ifreq, sizeof (struct ifreq));
120 }
121 else if (rc == 0)
122 {
123 logmsg (_("HHCTU001E %s timeout, possible older version?\n"),
124 hercifc);
125 errno = EPERM;
126 rc = -1;
127 }
128
129 /* clean-up */
130 sv_err = errno;
131 close (ifd[1]);
132 kill (pid, SIGINT);
133 waitpid (pid, &status, 0);
134 errno = sv_err;
135 }
136 #endif /* if !defined(OPTION_W32_CTCI) */
137
138 return rc;
139 }
140
141 //
142 // TUNTAP_CreateInterface
143 //
144 //
145 // Creates a new network interface using TUN/TAP. Reading from or
146 // writing to the file descriptor returned from this call will pass
147 // network packets to/from the virtual network interface.
148 //
149 // A TUN interface is a Point-To-Point connection from the driving
150 // system's IP stack to the guest OS running within Hercules.
151 //
152 // A TAP interface in a virtual network adapter that "tap's" off the
153 // driving system's network stack.
154 //
155 // On *nix boxen, this is accomplished by opening the special TUN/TAP
156 // character device (usually /dev/net/tun). Once the character device
157 // is opened, an ioctl call is done to set they type of interface to be
158 // created, IFF_TUN or IFF_TAP. Once the interface is created, the
159 // interface name is returned in pszNetDevName.
160 //
161 // Input:
162 // pszTUNDevice Pointer to the name of the TUN/TAP char device
163 // iFlags Flags for the new interface:
164 // IFF_TAP - Create a TAP interface or
165 // IFF_TUN - Create a TUN interface
166 // IFF_NO_PI - Do not include packet information
167 //
168 // On Win32, calls are made to Fish's TT32 DLL's to accomplish the same
169 // functionality. There are a few differences in regards to the arguments
170 // however:
171 //
172 // Input:
173 // pszTUNDevice Pointer to a string that describes the physical
174 // adapter to attach the TUN/TAP interface to.
175 // This string can contain any of the following:
176 // 1) IP address (in a.b.c.d notation)
177 // 2) MAC address (in xx-xx-xx-xx-xx-xx or
178 // xx:xx:xx:xx:xx:xx notation).
179 // 3) Name of the adapter as displayed on your
180 // Network and Dial-ip Connections window
181 // (Windows 2000 only future implementation)
182 // iFlags Flags for the new interface:
183 // IFF_TAP - Create a TAP interface or
184 // IFF_TUN - Create a TUN interface
185 // IFF_NO_PI - Do not include packet information
186 //
187 // Output:
188 // pfd Pointer to receive the file descriptor of the
189 // TUN/TAP interface.
190 // pszNetDevName Pointer to receive the name if the interface.
191 //
192
TUNTAP_CreateInterface(char * pszTUNDevice,int iFlags,int * pfd,char * pszNetDevName)193 int TUNTAP_CreateInterface( char* pszTUNDevice,
194 int iFlags,
195 int* pfd,
196 char* pszNetDevName )
197 {
198 int fd; // File descriptor
199 #if !defined( OPTION_W32_CTCI )
200 struct utsname utsbuf;
201
202 if( uname( &utsbuf ) != 0 )
203 {
204 logmsg( _("HHCTU001E Unable to determine operating system type: %s\n"),
205 strerror( errno ) );
206
207 return -1;
208 }
209 #endif
210
211 // Open TUN device
212 fd = TUNTAP_Open( pszTUNDevice, O_RDWR );
213
214 if( fd < 0 )
215 {
216 logmsg( _("HHCTU002E Error opening TUN/TAP device: %s: %s\n"),
217 pszTUNDevice, strerror( errno ) );
218
219 return -1;
220 }
221
222 *pfd = fd;
223
224 #if !defined( OPTION_W32_CTCI )
225 if ( strncasecmp( utsbuf.sysname, "linux", 5 ) == 0 )
226 #endif
227 {
228 // Linux kernel (builtin tun device) or Windows
229 struct ifreq ifr;
230
231 memset( &ifr, 0, sizeof( ifr ) );
232 ifr.ifr_flags = iFlags;
233
234 if( TUNTAP_SetMode (fd, &ifr) < 0 )
235 {
236 logmsg( _("HHCTU003E Error setting TUN/TAP mode: %s: %s\n"),
237 pszTUNDevice, strerror( errno ) );
238 return -1;
239 }
240
241 strcpy( pszNetDevName, ifr.ifr_name );
242 }
243 #if !defined( OPTION_W32_CTCI )
244 else if ( strncasecmp( utsbuf.sysname, "FreeBSD", 7 ) == 0 )
245 {
246 struct stat sb;
247
248 if ( ( iFlags & IFF_TAP ) == IFF_TAP )
249 {
250 logmsg( _("HHCTU011E TAP device not yet supported\n") );
251 return -1;
252 }
253
254 if ( fstat(fd, &sb) == 0 )
255 devname_r(sb.st_rdev, S_IFCHR, pszNetDevName, IFNAMSIZ);
256 else
257 {
258 logmsg( _("HHCTU010E Error getting TUN/TAP device name: %s\n"),
259 strerror( errno ) );
260 return -1;
261 }
262 }
263 else
264 {
265 // Other OS: Simply use basename of the device
266 // Notes: (JAP) This is problematic at best. Until we have a
267 // clean FreeBSD compile from the base tree I can't
268 // spend a lot of time on this... so it will remain.
269 // My best guess is that this will cause other functions
270 // to fail miserably but I have no way to test it.
271 // This should work on OS X with Christoph Pfisterer's TUN driver,
272 // since it does set the device name to the basename of the
273 // file. -- JRM
274 char *p = strrchr( pszTUNDevice, '/' );
275
276 if( p )
277 strncpy( pszNetDevName, ++p, IFNAMSIZ );
278 else
279 {
280 logmsg( _("HHCTU004E Invalid TUN/TAP device name: %s\n"),
281 pszTUNDevice );
282 return -1;
283 }
284 }
285 #endif
286
287 return 0;
288 }
289
290 //
291 // Redefine 'TUNTAP_IOCtl' for the remainder of the functions.
292 // This forces all 'ioctl' calls to go to 'hercifc'.
293 //
294
295 #if !defined( OPTION_W32_CTCI )
296 #undef TUNTAP_IOCtl
297 #define TUNTAP_IOCtl IFC_IOCtl
298 #endif
299
300 #ifdef OPTION_TUNTAP_CLRIPADDR
301 //
302 // TUNTAP_ClrIPAddr
303 //
304
TUNTAP_ClrIPAddr(char * pszNetDevName)305 int TUNTAP_ClrIPAddr( char* pszNetDevName )
306 {
307 struct ifreq ifreq;
308
309 memset( &ifreq, 0, sizeof( struct ifreq ) );
310
311 if( !pszNetDevName || !*pszNetDevName )
312 {
313 logmsg( _("HHCTU005E Invalid net device name specified: %s\n"),
314 pszNetDevName ? pszNetDevName : "(null pointer)" );
315 return -1;
316 }
317
318 strcpy( ifreq.ifr_name, pszNetDevName );
319
320 return TUNTAP_IOCtl( 0, SIOCDIFADDR, (char*)&ifreq );
321 }
322 #endif /* OPTION_TUNTAP_CLRIPADDR */
323
324 //
325 // TUNTAP_SetIPAddr
326 //
327
TUNTAP_SetIPAddr(char * pszNetDevName,char * pszIPAddr)328 int TUNTAP_SetIPAddr( char* pszNetDevName,
329 char* pszIPAddr )
330 {
331 struct ifreq ifreq;
332 struct sockaddr_in* sin;
333
334 memset( &ifreq, 0, sizeof( struct ifreq ) );
335
336 sin = (struct sockaddr_in*)&ifreq.ifr_addr;
337
338 sin->sin_family = AF_INET;
339 set_sockaddr_in_sin_len( sin );
340
341 if( !pszNetDevName || !*pszNetDevName )
342 {
343 logmsg( _("HHCTU005E Invalid net device name specified: %s\n"),
344 pszNetDevName ? pszNetDevName : "(null pointer)" );
345 return -1;
346 }
347
348 strcpy( ifreq.ifr_name, pszNetDevName );
349
350 if( !pszIPAddr ||
351 !inet_aton( pszIPAddr, &sin->sin_addr ) )
352 {
353 logmsg( _("HHCTU006E %s: Invalid IP address: %s.\n"),
354 pszNetDevName, !pszIPAddr ? "NULL" : pszIPAddr );
355 return -1;
356 }
357
358 return TUNTAP_IOCtl( 0, SIOCSIFADDR, (char*)&ifreq );
359 }
360
361 //
362 // TUNTAP_SetDestAddr
363 //
364
TUNTAP_SetDestAddr(char * pszNetDevName,char * pszDestAddr)365 int TUNTAP_SetDestAddr( char* pszNetDevName,
366 char* pszDestAddr )
367 {
368 struct ifreq ifreq;
369 struct sockaddr_in* sin;
370
371 memset( &ifreq, 0, sizeof( struct ifreq ) );
372
373 sin = (struct sockaddr_in*)&ifreq.ifr_addr;
374
375 sin->sin_family = AF_INET;
376 set_sockaddr_in_sin_len( sin );
377
378 if( !pszNetDevName || !*pszNetDevName )
379 {
380 logmsg( _("HHCTU007E Invalid net device name specified: %s\n"),
381 pszNetDevName ? pszNetDevName : "(null pointer)" );
382 return -1;
383 }
384
385 strcpy( ifreq.ifr_name, pszNetDevName );
386
387 if( !pszDestAddr ||
388 !inet_aton( pszDestAddr, &sin->sin_addr ) )
389 {
390 logmsg( _("HHCTU008E %s: Invalid destination address: %s.\n"),
391 pszNetDevName, !pszDestAddr ? "NULL" : pszDestAddr );
392 return -1;
393 }
394
395 return TUNTAP_IOCtl( 0, SIOCSIFDSTADDR, (char*)&ifreq );
396 }
397
398 //
399 // TUNTAP_SetNetMask
400 //
401 #ifdef OPTION_TUNTAP_SETNETMASK
TUNTAP_SetNetMask(char * pszNetDevName,char * pszNetMask)402 int TUNTAP_SetNetMask( char* pszNetDevName,
403 char* pszNetMask )
404 {
405 struct ifreq ifreq;
406 struct sockaddr_in* sin;
407
408 memset( &ifreq, 0, sizeof( struct ifreq ) );
409
410 sin = (struct sockaddr_in*)&ifreq.ifr_netmask;
411
412 sin->sin_family = AF_INET;
413 set_sockaddr_in_sin_len( sin );
414
415 if( !pszNetDevName || !*pszNetDevName )
416 {
417 logmsg( _("HHCTU009E Invalid net device name specified: %s\n"),
418 pszNetDevName ? pszNetDevName : "(null pointer)" );
419 return -1;
420 }
421
422 strcpy( ifreq.ifr_name, pszNetDevName );
423
424 if( !pszNetMask ||
425 !inet_aton( pszNetMask, &sin->sin_addr ) )
426 {
427 logmsg( _("HHCTU010E %s: Invalid net mask: %s.\n"),
428 pszNetDevName, !pszNetMask ? "NULL" : pszNetMask );
429 return -1;
430 }
431
432 return TUNTAP_IOCtl( 0, SIOCSIFNETMASK, (char*)&ifreq );
433 }
434 #endif // OPTION_TUNTAP_SETNETMASK
435
436 //
437 // TUNTAP_SetMTU
438 //
TUNTAP_SetMTU(char * pszNetDevName,char * pszMTU)439 int TUNTAP_SetMTU( char* pszNetDevName,
440 char* pszMTU )
441 {
442 struct ifreq ifreq;
443 struct sockaddr_in* sin;
444 int iMTU;
445
446 memset( &ifreq, 0, sizeof( struct ifreq ) );
447
448 sin = (struct sockaddr_in*)&ifreq.ifr_addr;
449
450 sin->sin_family = AF_INET;
451 set_sockaddr_in_sin_len( sin );
452
453 if( !pszNetDevName || !*pszNetDevName )
454 {
455 logmsg( _("HHCTU011E Invalid net device name specified: %s\n"),
456 pszNetDevName ? pszNetDevName : "(null pointer)" );
457 return -1;
458 }
459
460 strcpy( ifreq.ifr_name, pszNetDevName );
461
462 if( !pszMTU || !*pszMTU )
463 {
464 logmsg( _("HHCTU012E %s: Invalid null or empty MTU.\n"),
465 pszNetDevName );
466 return -1;
467 }
468
469 iMTU = atoi( pszMTU );
470
471 if( iMTU < 46 || iMTU > 65536 )
472 {
473 logmsg( _("HHCTU013E %s: Invalid MTU: %s.\n"),
474 pszNetDevName, pszMTU );
475 return -1;
476 }
477
478 ifreq.ifr_mtu = iMTU;
479
480 return TUNTAP_IOCtl( 0, SIOCSIFMTU, (char*)&ifreq );
481 }
482
483 //
484 // TUNTAP_SetMACAddr
485 //
486 #ifdef OPTION_TUNTAP_SETMACADDR
TUNTAP_SetMACAddr(char * pszNetDevName,char * pszMACAddr)487 int TUNTAP_SetMACAddr( char* pszNetDevName,
488 char* pszMACAddr )
489 {
490 struct ifreq ifreq;
491 struct sockaddr* addr;
492 MAC mac;
493
494 memset( &ifreq, 0, sizeof( struct ifreq ) );
495
496 addr = (struct sockaddr*)&ifreq.ifr_hwaddr;
497
498 addr->sa_family = AF_UNIX;
499
500 if( !pszNetDevName || !*pszNetDevName )
501 {
502 logmsg( _("HHCTU014E Invalid net device name specified: %s\n"),
503 pszNetDevName ? pszNetDevName : "(null pointer)" );
504 return -1;
505 }
506
507 strcpy( ifreq.ifr_name, pszNetDevName );
508
509 if( !pszMACAddr || ParseMAC( pszMACAddr, mac ) != 0 )
510 {
511 logmsg( _("HHCTU015E %s: Invalid MAC address: %s.\n"),
512 pszNetDevName, !pszMACAddr ? "NULL" : pszMACAddr );
513 return -1;
514 }
515
516 memcpy( addr->sa_data, mac, IFHWADDRLEN );
517
518 return TUNTAP_IOCtl( 0, SIOCSIFHWADDR, (char*)&ifreq );
519 }
520 #endif // OPTION_TUNTAP_SETMACADDR
521
522 //
523 // TUNTAP_SetFlags
524 //
525
TUNTAP_SetFlags(char * pszNetDevName,int iFlags)526 int TUNTAP_SetFlags ( char* pszNetDevName,
527 int iFlags )
528 {
529 struct ifreq ifreq;
530 struct sockaddr_in* sin;
531
532 memset( &ifreq, 0, sizeof( struct ifreq ) );
533
534 sin = (struct sockaddr_in*)&ifreq.ifr_addr;
535
536 sin->sin_family = AF_INET;
537 set_sockaddr_in_sin_len( sin );
538
539 if( !pszNetDevName || !*pszNetDevName )
540 {
541 logmsg( _("HHCTU016E Invalid net device name specified: %s\n"),
542 pszNetDevName ? pszNetDevName : "(null pointer)" );
543 return -1;
544 }
545
546 strlcpy( ifreq.ifr_name, pszNetDevName, sizeof(ifreq.ifr_name) );
547
548 ifreq.ifr_flags = iFlags;
549
550 return TUNTAP_IOCtl( 0, SIOCSIFFLAGS, (char*)&ifreq );
551 }
552
553 //
554 // TUNTAP_GetFlags
555 //
556
TUNTAP_GetFlags(char * pszNetDevName,int * piFlags)557 int TUNTAP_GetFlags ( char* pszNetDevName,
558 int* piFlags )
559 {
560 struct ifreq ifreq;
561 struct sockaddr_in* sin;
562 int rc;
563
564 memset( &ifreq, 0, sizeof( struct ifreq ) );
565
566 sin = (struct sockaddr_in*)&ifreq.ifr_addr;
567
568 sin->sin_family = AF_INET;
569
570 if( !pszNetDevName || !*pszNetDevName )
571 {
572 logmsg( _("HHCTU016E Invalid net device name specified: %s\n"),
573 pszNetDevName ? pszNetDevName : "(null pointer)" );
574 return -1;
575 }
576
577 strlcpy( ifreq.ifr_name, pszNetDevName, sizeof(ifreq.ifr_name) );
578
579 // PROGRAMMING NOTE: hercifc can't "get" information,
580 // only "set" it. Thus because we normally use hercifc
581 // to issue ioctl codes to the interface (on non-Win32)
582 // we bypass hercifc altogether and issue the ioctl
583 // ourselves directly to the device itself, bypassing
584 // hercifc completely. Note that for Win32 however,
585 // 'TUNTAP_IOCtl' routes to a TunTap32.DLL call and
586 // thus works just fine. We need special handling
587 // only for non-Win32 platforms. - Fish
588
589 #if defined( OPTION_W32_CTCI )
590
591 rc = TUNTAP_IOCtl( 0, SIOCGIFFLAGS, (char*)&ifreq );
592
593 #else // (non-Win32 platforms)
594 {
595 int sockfd = socket( AF_INET, SOCK_DGRAM, 0 );
596 rc = ioctl( sockfd, SIOCGIFFLAGS, &ifreq );
597 }
598 #endif
599
600 *piFlags = ifreq.ifr_flags;
601
602 return rc;
603 }
604
605 //
606 // TUNTAP_AddRoute
607 //
608 #ifdef OPTION_TUNTAP_DELADD_ROUTES
TUNTAP_AddRoute(char * pszNetDevName,char * pszDestAddr,char * pszNetMask,char * pszGWAddr,int iFlags)609 int TUNTAP_AddRoute( char* pszNetDevName,
610 char* pszDestAddr,
611 char* pszNetMask,
612 char* pszGWAddr,
613 int iFlags )
614 {
615 struct rtentry rtentry;
616 struct sockaddr_in* sin;
617
618 memset( &rtentry, 0, sizeof( struct rtentry ) );
619
620 if( !pszNetDevName || !*pszNetDevName )
621 {
622 logmsg( _("HHCTU017E Invalid net device name specified: %s\n"),
623 pszNetDevName ? pszNetDevName : "(null pointer)" );
624 return -1;
625 }
626
627 rtentry.rt_dev = pszNetDevName;
628
629 sin = (struct sockaddr_in*)&rtentry.rt_dst;
630 sin->sin_family = AF_INET;
631 set_sockaddr_in_sin_len( sin );
632
633 if( !pszDestAddr ||
634 !inet_aton( pszDestAddr, &sin->sin_addr ) )
635 {
636 logmsg( _("HHCTU018E %s: Invalid destiniation address: %s.\n"),
637 pszNetDevName, !pszDestAddr ? "NULL" : pszDestAddr );
638 return -1;
639 }
640
641 sin = (struct sockaddr_in*)&rtentry.rt_genmask;
642 sin->sin_family = AF_INET;
643 set_sockaddr_in_sin_len( sin );
644
645 if( !pszNetMask ||
646 !inet_aton( pszNetMask, &sin->sin_addr ) )
647 {
648 logmsg( _("HHCTU019E %s: Invalid net mask: %s.\n"),
649 pszNetDevName, !pszNetMask ? "NULL" : pszNetMask );
650 return -1;
651 }
652
653 sin = (struct sockaddr_in*)&rtentry.rt_gateway;
654 sin->sin_family = AF_INET;
655 set_sockaddr_in_sin_len( sin );
656
657 if( pszGWAddr )
658 {
659 if( !inet_aton( pszGWAddr, &sin->sin_addr ) )
660 {
661 logmsg( _("HHCTU020E %s: Invalid gateway address: %s.\n"),
662 pszNetDevName, pszGWAddr );
663 return -1;
664 }
665 }
666
667 rtentry.rt_flags = iFlags;
668
669 return TUNTAP_IOCtl( 0, SIOCADDRT, (char*)&rtentry );
670 }
671 #endif // OPTION_TUNTAP_DELADD_ROUTES
672
673 //
674 // TUNTAP_DelRoute
675 //
676 #ifdef OPTION_TUNTAP_DELADD_ROUTES
TUNTAP_DelRoute(char * pszNetDevName,char * pszDestAddr,char * pszNetMask,char * pszGWAddr,int iFlags)677 int TUNTAP_DelRoute( char* pszNetDevName,
678 char* pszDestAddr,
679 char* pszNetMask,
680 char* pszGWAddr,
681 int iFlags )
682 {
683 struct rtentry rtentry;
684 struct sockaddr_in* sin;
685
686 memset( &rtentry, 0, sizeof( struct rtentry ) );
687
688 if( !pszNetDevName || !*pszNetDevName )
689 {
690 logmsg( _("HHCTU021E Invalid net device name specified: %s\n"),
691 pszNetDevName ? pszNetDevName : "(null pointer)" );
692 return -1;
693 }
694
695 rtentry.rt_dev = pszNetDevName;
696
697 sin = (struct sockaddr_in*)&rtentry.rt_dst;
698 sin->sin_family = AF_INET;
699 set_sockaddr_in_sin_len( sin );
700
701 if( !pszDestAddr ||
702 !inet_aton( pszDestAddr, &sin->sin_addr ) )
703 {
704 logmsg( _("HHCTU022E %s: Invalid destiniation address: %s.\n"),
705 pszNetDevName, !pszDestAddr ? "NULL" : pszDestAddr );
706 return -1;
707 }
708
709 sin = (struct sockaddr_in*)&rtentry.rt_genmask;
710 sin->sin_family = AF_INET;
711 set_sockaddr_in_sin_len( sin );
712
713 if( !pszNetMask ||
714 !inet_aton( pszNetMask, &sin->sin_addr ) )
715 {
716 logmsg( _("HHCTU023E %s: Invalid net mask: %s.\n"),
717 pszNetDevName, !pszNetMask ? "NULL" : pszNetMask );
718 return -1;
719 }
720
721 sin = (struct sockaddr_in*)&rtentry.rt_gateway;
722 sin->sin_family = AF_INET;
723 set_sockaddr_in_sin_len( sin );
724
725 if( pszGWAddr )
726 {
727 if( !inet_aton( pszGWAddr, &sin->sin_addr ) )
728 {
729 logmsg( _("HHCTU024E %s: Invalid gateway address: %s.\n"),
730 pszNetDevName, pszGWAddr );
731 return -1;
732 }
733 }
734
735 rtentry.rt_flags = iFlags;
736
737 return TUNTAP_IOCtl( 0, SIOCDELRT, (char*)&rtentry );
738 }
739 #endif // OPTION_TUNTAP_DELADD_ROUTES
740
741 #if !defined( OPTION_W32_CTCI )
742 // ====================================================================
743 // HercIFC Helper Functions
744 // ====================================================================
745
746 //
747 // IFC_IOCtl
748 //
749
IFC_IOCtl(int fd,unsigned long int iRequest,char * argp)750 static int IFC_IOCtl( int fd, unsigned long int iRequest, char* argp )
751 {
752 char* pszCfgCmd; // Interface config command
753 int rc;
754 CTLREQ ctlreq;
755 char* request_name; // debugging: name of ioctl request
756 #if defined(DEBUG) || defined(_DEBUG)
757 char unknown_request[] = "Unknown (0x00000000)";
758 #endif
759
760 UNREFERENCED( fd );
761
762 memset( &ctlreq, 0, CTLREQ_SIZE );
763
764 ctlreq.iCtlOp = iRequest;
765
766 #if defined(DEBUG) || defined(_DEBUG)
767
768 // Select string to represent ioctl request for debugging.
769
770 switch (iRequest) {
771 #ifdef OPTION_TUNTAP_CLRIPADDR
772 case SIOCDIFADDR:
773 request_name="SIOCDIFADDR"; break;
774 #endif
775 case SIOCSIFADDR:
776 request_name="SIOCSIFADDR"; break;
777
778 case SIOCSIFDSTADDR:
779 request_name="SIOCSIFDSTADDR"; break;
780
781 case SIOCSIFMTU:
782 request_name="SIOCSIFMTU"; break;
783
784 case SIOCSIFFLAGS:
785 request_name="SIOCSIFFLAGS"; break;
786
787 case SIOCGIFFLAGS:
788 request_name="SIOCGIFFLAGS"; break;
789
790 #ifdef OPTION_TUNTAP_SETNETMASK
791 case SIOCSIFNETMASK:
792 request_name="SIOCSIFNETMASK"; break;
793 #endif
794 #ifdef OPTION_TUNTAP_SETMACADDR
795 case SIOCSIFHWADDR:
796 request_name="SIOCSIFHWADDR"; break;
797 #endif
798 #ifdef OPTION_TUNTAP_DELADD_ROUTES
799 case SIOCADDRT:
800 request_name="SIOCADDRT"; break;
801
802 case SIOCDELRT:
803 request_name="SIOCDELRT"; break;
804 #endif
805 default:
806 sprintf(unknown_request,"Unknown (0x%x)",iRequest);
807 request_name=unknown_request;
808 }
809
810 #endif // defined(DEBUG) || defined(_DEBUG)
811
812 #ifdef OPTION_TUNTAP_DELADD_ROUTES
813 if( iRequest == SIOCADDRT ||
814 iRequest == SIOCDELRT )
815 {
816 strcpy( ctlreq.szIFName, ((struct rtentry*)argp)->rt_dev );
817 memcpy( &ctlreq.iru.rtentry, argp, sizeof( struct rtentry ) );
818 ((struct rtentry*)argp)->rt_dev = NULL;
819 }
820 else
821 #endif
822 {
823 memcpy( &ctlreq.iru.ifreq, argp, sizeof( struct ifreq ) );
824 }
825
826 if( ifc_fd[0] == -1 && ifc_fd[1] == -1 )
827 {
828 if( socketpair( AF_UNIX, SOCK_STREAM, 0, ifc_fd ) < 0 )
829 {
830 logmsg( _("HHCTU025E Call to socketpair failed: %s\n"),
831 strerror( errno ) );
832 return -1;
833 }
834
835 // Obtain the name of the interface config program or default
836 if( !( pszCfgCmd = getenv( "HERCULES_IFC" ) ) )
837 pszCfgCmd = HERCIFC_CMD;
838
839 TRACE(_("HHCTU029I Executing '%s' to configure interface\n"),
840 pszCfgCmd);
841
842 // Fork a process to execute the hercifc
843 ifc_pid = fork();
844
845 if( ifc_pid < 0 )
846 {
847 logmsg( _("HHCTU026E Call to fork failed: %s\n"),
848 strerror( errno ) );
849 return -1;
850 }
851
852 // The child process executes the configuration command
853 if( ifc_pid == 0 )
854 {
855 /* @ISW@ Close all file descriptors
856 * (except ifc_fd[1] and STDOUT FILENO)
857 * (otherwise some devices are never closed)
858 * (ex: SCSI tape devices can never be re-opened)
859 */
860 struct rlimit rlim;
861 int i;
862 rlim_t file_limit;
863 getrlimit(RLIMIT_NOFILE,&rlim);
864 /* While Linux and Cygwin have limits of 1024 files by default,
865 * Mac OS X does not - its default is -1, or completely unlimited.
866 * The following hack is to defend against trying to close 2
867 * billion files. -- JRM */
868 file_limit=rlim.rlim_max;
869 file_limit=(file_limit>1024)?1024:file_limit;
870
871 TRACE(_("HHCTU031I Closing %" I64_FMT "d files\n"),
872 (long long)file_limit);
873
874 for(i=0;(unsigned int)i<file_limit;i++)
875 {
876 if(i!=ifc_fd[1] && i!=STDOUT_FILENO)
877 {
878 close(i);
879 }
880 }
881 /* @ISW@ Close spurious FDs END */
882 dup2( ifc_fd[1], STDIN_FILENO );
883 dup2( STDOUT_FILENO, STDERR_FILENO );
884
885 // Execute the interface configuration command
886 rc = execlp( pszCfgCmd, pszCfgCmd, NULL );
887
888 // The exec function returns only if unsuccessful
889 logmsg( _("HHCTU027E execl error on %s: %s.\n"),
890 pszCfgCmd, strerror( errno ) );
891
892 exit( 127 );
893 }
894
895 /* Terminate TunTap on shutdown */
896 hdl_adsc("tuntap_term", tuntap_term, NULL);
897 }
898
899 // Populate some common fields
900 ctlreq.iType = 1;
901
902 TRACE(_("HHCTU030I IFC_IOCtl called for %s on FDs %d %d\n"),
903 request_name,ifc_fd[0],ifc_fd[1]);
904
905 write( ifc_fd[0], &ctlreq, CTLREQ_SIZE );
906
907 return 0;
908 }
909
910 #endif // !defined( OPTION_W32_CTCI )
911
912 // The following function used by Win32 *and* NON-Win32 platforms...
913
build_herc_iface_mac(BYTE * out_mac,const BYTE * in_ip)914 void build_herc_iface_mac ( BYTE* out_mac, const BYTE* in_ip )
915 {
916 // Routine to build a default MAC address for the CTCI device's
917 // virtual interface... (used by ctc_ctci.c CTCI_Init function)
918
919 if (!in_ip || !out_mac)
920 {
921 ASSERT( FALSE );
922 return; // (nothing for us to do!)
923 }
924
925 #if defined( OPTION_W32_CTCI )
926
927 // We prefer to let TunTap32 do it for us (since IT'S the one
928 // that decides what it should really be) but if they're using
929 // an older version of TunTap32 that doesn't have the function
930 // then we'll do it ourselves just like before...
931
932 if (tt32_build_herc_iface_mac( out_mac, in_ip ))
933 return;
934
935 #endif
936
937 // Build a default MAC addr based on the guest (destination) ip
938 // address so as to effectively *UNOFFICIALLY* assign ourselves
939 // the following Ethernet address block:
940
941 /* (from: http://www.iana.org/assignments/ethernet-numbers)
942 (only the first 2 and last 2 paragraphs are of interest)
943
944 IANA ETHERNET ADDRESS BLOCK - UNICAST USE
945
946 The IANA owns an Ethernet address block which may be used for
947 unicast address asignments or other special purposes.
948
949 The IANA may assign unicast global IEEE 802 MAC address from it's
950 assigned OUI (00-00-5E) for use in IETF standard track protocols. The
951 intended usage is for dynamic mapping between IP addresses and IEEE
952 802 MAC addresses. These IEEE 802 MAC addresses are not to be
953 permanently assigned to any hardware interface, nor is this a
954 substitute for a network equipment supplier getting its own OUI.
955
956 ... (snipped)
957
958 Using this representation, the range of Internet Unicast addresses is:
959
960 00-00-5E-00-00-00 to 00-00-5E-FF-FF-FF in hex, ...
961
962 ... (snipped)
963
964 The low order 24 bits of these unicast addresses are assigned as
965 follows:
966
967 Dotted Decimal Description Reference
968 ----------------------- ------------------------------- ---------
969 000.000.000-000.000.255 Reserved [IANA]
970 000.001.000-000.001.255 Virual Router Redundancy (VRRP) [Hinden]
971 000.002.000-127.255.255 Reserved [IANA]
972 128.000.000-255.255.255 Hercules TUNTAP (CTCI) [Fish] (*UNOFFICIAL*)
973 */
974
975 // Here's what we're basically doing:
976
977 // 00-00-5E-00-00-00 to 00-00-5E-00-00-FF = 'Reserved' by IANA
978 // 00-00-5E-00-01-00 to 00-00-5E-00-01-FF = 'VRRP' by Hinden
979 // 00-00-5E-00-02-00 to 00-00-5E-7F-FF-FF = (unassigned)
980 // 00-00-5E-80-00-00 to 00-00-5E-FF-FF-FF = 'Hercules' by Fish (*UNOFFICIAL*)
981
982 // 00-00-5E-00-00-00 (starting value)
983 // 00-00-5E-ip-ip-ip (move in low-order 3 bytes of destination IP address)
984 // 00-00-5E-8p-ip-ip ('OR' on the x'80' high-order bit)
985
986 *(out_mac+0) = 0x00;
987 *(out_mac+1) = 0x00;
988 *(out_mac+2) = 0x5E;
989 *(out_mac+3) = *(in_ip+1) | 0x80;
990 *(out_mac+4) = *(in_ip+2);
991 *(out_mac+5) = *(in_ip+3);
992 }
993
994 #endif /* !defined(__SOLARIS__) jbs*/
995