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