/*
    ettercap -- inet utilities -- Module for LINUX 2.0.x  FULL
                                                   2.2.x  FULL
                                                   2.4.x  FULL

    Copyright (C) 2001  ALoR <alor@users.sourceforge.net>, NaGA <crwm@freemail.it>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

    $Id: ec_inet_linux.c,v 1.13 2003/02/25 11:03:32 alor Exp $
*/

#include "../../include/ec_main.h"

#include <ctype.h>
#include <sys/ioctl.h>
#include <fcntl.h>

#include "../../include/ec_thread.h"
#include "../../include/ec_inet.h"
#include "../../include/ec_inet_forge.h"
#include "../../include/ec_inet_structures.h"

struct ifreq old_ifr;      // old iface flags
char IpForward_status;     // old ipforward status

static char ETH_BROADCAST[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
static char ARP_BROADCAST[6] = {0x0,0x0,0x0,0x0,0x0,0x0};

// protos...

int Inet_FindIFace(char *iface);
int Inet_CorrectIface(char *iface);
int Inet_GetIfaceInfo(char *iface, int *MTU, char *MyMAC, u_long *IP, u_long *NetMask);
int Inet_SetPromisc(char *iface);
int Inet_OpenRawSock(char *iface);
void Inet_CloseRawSock(int sock);
int Inet_GetRawPacket(int sock, char *buffer, int MTU, short *type);
int Inet_SendRawPacket(int sock, char *buffer, int len);
void Inet_SetNonBlock(int sock);
void Inet_Restore_ifr(void);
void Inet_DisableForwarding(void);
void Inet_RestoreForwarding(void);
char *Inet_MacFromIP(unsigned long ip);
#ifdef PERMIT_HTTPS
   void Inet_UnSetARPEntry(void);
   int Inet_SetARPEntry(unsigned long IP, char MAC[6]);
   void Inet_UnsetRoute(void);
   void Inet_SetRoute(void);
#endif


// ----------------------------------------------

int Inet_FindIFace(char *iface)     // adapded from pcap_lookupdev
{
   int fd, minunit, n;
   char *cp;
   struct ifreq *ifrp, *ifend, *ifnext, *mp;
   struct ifconf ifc;
   char *buf;
   struct ifreq ifr;
   unsigned int buf_size;

   fd = socket(AF_INET, SOCK_DGRAM, 0);
   if (fd < 0)
      ERROR_MSG("socket()");

   buf_size = 8192;

   for (;;) {
      buf = malloc (buf_size);
      if (buf == NULL)
         ERROR_MSG("malloc()");

      ifc.ifc_len = buf_size;
      ifc.ifc_buf = buf;
      memset (buf, 0, buf_size);
      if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 && errno != EINVAL)
         ERROR_MSG("ioctl(SIOCGIFCONF)");

      if (ifc.ifc_len < buf_size)
         break;

      free (buf);
      buf_size *= 2;
   }

   ifrp = (struct ifreq *)buf;
   ifend = (struct ifreq *)(buf + ifc.ifc_len);

   mp = NULL;
   minunit = 666;
   for (; ifrp < ifend; ifrp = ifnext)
   {
      const char *endcp;

#ifdef HAVE_SOCKADDR_SA_LEN
   n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
   if (n < sizeof(*ifrp))
      ifnext = ifrp + 1;
   else
      ifnext = (struct ifreq *)((char *)ifrp + n);
   if (ifrp->ifr_addr.sa_family != AF_INET)
      continue;
#else
   ifnext = ifrp + 1;
#endif

      strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name));

      if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0)
      {
         if (errno == ENXIO)
            continue;

         ERROR_MSG("ioctl(SIOCGIFFLAGS)");
      }

      DEBUG_MSG("Inet_FindIFace -- check for [%s]", ifr.ifr_name);

      /* Must be up and not the loopback */
      if ((ifr.ifr_flags & IFF_UP) == 0 || (ifr.ifr_flags & IFF_LOOPBACK) != 0)
         continue;

      if ( ioctl(fd, SIOCGIFHWADDR, &ifr) < 0 )
         ERROR_MSG("ioctl(SIOCGIFHWADDR)");

      /* Must be ethernet */
      if ( ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER )
         continue;

      endcp = ifrp->ifr_name + strlen(ifrp->ifr_name);
      for (cp = ifrp->ifr_name; cp < endcp && !isdigit(*cp); ++cp)
         continue;

      if (isdigit (*cp)) {
         n = atoi(cp);
      } else {
         n = 0;
      }
      if (n < minunit) {
         minunit = n;
         mp = ifrp;
      }
   }

   close(fd);

   if (mp == NULL)   // no device found
   {
      free(buf);
      return -1;
   }

   strlcpy(iface, mp->ifr_name, sizeof(Options.netiface));

   free(buf);

   DEBUG_MSG("Inet_FindIFace\t\tIface: %s", iface);

   return 0;

}


int Inet_CorrectIface(char *iface)
{
   int sock;
   struct ifreq ifr;

   DEBUG_MSG("Inet_CorrectIface\t\tIface: %s", iface);

   sock = socket(AF_INET, SOCK_DGRAM, 0);
   if (sock < 0)
      ERROR_MSG("socket()");

   memset(&ifr, 0, sizeof(ifr));
   strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
   if ( ioctl(sock, SIOCGIFFLAGS, &ifr) < 0)             // check for iface
   {
      close(sock);
      return -1;
   }

   if (!(ifr.ifr_flags & IFF_UP ))                       // check for flag UP
   {
      close(sock);
      return -1;
   }

   if (ifr.ifr_flags & IFF_LOOPBACK )                    // check for loopback
   {
      Options.normal = 1;
      Error_msg("Ettercap can't be run on loopback device");
   }

   if ( ioctl(sock, SIOCGIFADDR, &ifr) < 0 )             // check for alias
   {
      close(sock);
      return -1;
   }

   if ( ioctl(sock, SIOCGIFHWADDR, &ifr) < 0 )
      ERROR_MSG("ioctl(SIOCGIFHWADDR)");

   switch (ifr.ifr_hwaddr.sa_family)
   {
        case ARPHRD_ETHER:    // only ethernet is supported
            break;

        default:
            Error_msg("Device type not supported (only ethernet)");
   }

   close(sock);

   return 0;

}


int Inet_GetIfaceInfo(char *iface, int *MTU, char *MyMAC, unsigned long *IP, unsigned long *NetMask)
{
   int sock;
   struct ifreq ifr;

   sock = Inet_OpenRawSock(iface);

   memset(&ifr, 0, sizeof(ifr));
   strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));

   if (MTU != NULL)
   {
      if ( ioctl(sock, SIOCGIFMTU, &ifr) < 0)
      {
         DEBUG_MSG("Inet_IPBased_Run -- MTU FAILED... assuming 1500");
         *MTU = 1500;
      }
      else
         *MTU = ifr.ifr_mtu;
   }


   if (MyMAC != NULL)
   {
      if ( ioctl(sock, SIOCGIFHWADDR, &ifr) < 0 )
         ERROR_MSG("ioctl(SIOCGIFHWADDR)");
      memcpy(MyMAC, ifr.ifr_hwaddr.sa_data, 6);
   }

   if (IP != NULL)
   {
      if ( ioctl(sock, SIOCGIFADDR, &ifr) < 0 )
         ERROR_MSG("ioctl(SIOCGIFADDR)");
      memcpy((char *)IP, ifr.ifr_addr.sa_data+2, 4);
   }

   if (NetMask != NULL)
   {
      if ( ioctl(sock, SIOCGIFNETMASK, &ifr) < 0 )
         ERROR_MSG("ioctl(SIOCGIFNETMASK)");
      memcpy((char *)NetMask, ifr.ifr_addr.sa_data+2, 4);
      if (strcmp(Options.netmask, ""))       // specified on command line
         *NetMask = inet_addr(Options.netmask);
   }

   Inet_CloseRawSock(sock);

   return 0;

}


void Inet_SetNonBlock(int sock)
{
   DEBUG_MSG("Inet_SetNonBlock fd = %d", sock);

   fcntl(sock, F_SETFL, O_NONBLOCK);

}


void Inet_CloseRawSock(int sock)
{

   DEBUG_MSG("Inet_CloseRawSock \t fd = %d", sock);

   close(sock);

}



int Inet_OpenRawSock(char *iface)
{
   int sock;
#if defined (HAVE_PF_PACKET) && defined (NETPACKET_PACKET_H)
   struct ifreq ifr;
   struct sockaddr_ll sll;
#else
   struct sockaddr sa;
#endif

#if defined (HAVE_PF_PACKET) && defined (NETPACKET_PACKET_H)
   sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
#else
   sock = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL));
#endif
   if (sock < 0)
      ERROR_MSG("socket()");

   DEBUG_MSG("Inet_OpenRawSock %s \t fd = %d", iface, sock);

#if defined (HAVE_PF_PACKET) && defined (NETPACKET_PACKET_H)

   memset(&ifr, 0, sizeof(ifr));
   strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));

   if ( ioctl(sock, SIOCGIFINDEX, &ifr) < 0)
      ERROR_MSG("ioctl(SIOCGIFINDEX)");

   memset(&sll, 0, sizeof(sll));
   sll.sll_family = AF_PACKET;
   sll.sll_ifindex = ifr.ifr_ifindex;
   sll.sll_protocol = htons(ETH_P_ALL);

   if ( bind(sock, (struct sockaddr *) &sll, sizeof(sll)) == -1)
      ERROR_MSG("bind()");
#else

   memset(&sa, 0, sizeof(sa));
   strncpy(sa.sa_data, iface, sizeof(sa.sa_data));
   if ( bind(sock, &sa, sizeof(sa)) == -1)
      ERROR_MSG("bind()");

#endif

   return sock;
}



int Inet_GetRawPacket(int sock, char *buffer, int MTU, short *type)
{
   int len = 0;
   socklen_t fromlen;
   struct sockaddr from;
   static char MyMAC[6]={0x65,0x74,0x74,0x65,0x72,0x63};

   fromlen = sizeof(from);
   len = recvfrom(sock, buffer, MTU+64, MSG_TRUNC, (struct sockaddr *)&from, &fromlen);

   if (len > MTU + ETH_HEADER) len = MTU + ETH_HEADER;   // workaround for bugged kernel (2.2.14)
                                                         // this kernel passes us the MTU + ETH_HEADER + FCS
                                                         // for a total of 1518 byte !!!

   // the address returned for SOCK_PACKET lacks the packet type information.
   if (type != NULL)
   {
       if (!strncmp(MyMAC,"etterc",6))    // only the first time...
           Inet_GetIfaceInfo(Options.netiface, NULL, MyMAC, NULL, NULL);
       if (!memcmp(MyMAC,buffer,6))
           *type = 0; // PACKET_HOST
       else
           *type = 1; // !PACKET_HOST
   }

   // TODO
   // handle fragmented packets...

   return len;
}



int Inet_SendRawPacket(int sock, char *buffer, int len)
{
   int sent;
   static char first_time = 1;
#if defined (HAVE_PF_PACKET) && defined (NETPACKET_PACKET_H)
   static struct sockaddr_ll dest;
   static struct ifreq ifr;
#else
   static struct sockaddr dest;
#endif

   if (first_time)
   {
      memset(&dest, 0, sizeof (dest));
      first_time = 0;

      #if defined (HAVE_PF_PACKET) && defined (NETPACKET_PACKET_H)

         memset(&ifr, 0, sizeof(ifr));
         strncpy(ifr.ifr_name, Options.netiface, sizeof(ifr.ifr_name));

         if ( ioctl(sock, SIOCGIFINDEX, &ifr) < 0)
            ERROR_MSG("ioctl(SIOCGIFINDEX)");

         dest.sll_family = AF_PACKET;
         dest.sll_ifindex = ifr.ifr_ifindex;
         dest.sll_protocol = htons(ETH_P_ALL);
      #else
         strncpy(dest.sa_data, Options.netiface, sizeof (dest.sa_data));
      #endif
   }

   sent = sendto(sock, buffer, len, 0, (struct sockaddr *)&dest, sizeof(dest));
   if (sent < len)
   {
      while (errno == ENOBUFS || errno == EAGAIN)
      {
         usleep(5000);
         sent = sendto(sock, buffer, len, 0, (struct sockaddr *)&dest, sizeof(dest));
         if (sent == len) return (sent);
      }

      Error_msg("ec_inet_linux:%d sendto() %d(%d) | ERRNO : %d | %s \n", __LINE__, len, sent, errno, strerror(errno));
   }

   return (sent);

}



int Inet_SetPromisc(char *iface)
{

   int sock;
   struct ifreq ifr;

   DEBUG_MSG("Inet_SetPromisc\tiface: %s", iface);

   sock = Inet_OpenRawSock(iface);

   memset(&ifr, 0, sizeof(ifr));
   strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));

   if ( ioctl(sock, SIOCGIFFLAGS, &ifr) < 0 )
      ERROR_MSG("ioctl(SIOCGIFFLAGS)");

   memset(&old_ifr, 0, sizeof(old_ifr));
   old_ifr.ifr_flags = ifr.ifr_flags;              //save old flags

   if (!(ifr.ifr_flags & IFF_PROMISC))
   {
      ifr.ifr_flags |= IFF_PROMISC;
      if ( ioctl(sock, SIOCSIFFLAGS, &ifr) < 0 )      // promisc mode
         ERROR_MSG("ioctl(SIOCSIFFLAGS) | promisc on");
      atexit(Inet_Restore_ifr);
   }


   Inet_CloseRawSock(sock);
   return 0;

}



void Inet_Restore_ifr(void)
{
   int sock;
   struct ifreq ifr;

   DEBUG_MSG("Inet_Restore_ifr");

   sock = Inet_OpenRawSock(Options.netiface);

   memset(&ifr, 0, sizeof(ifr));
   strncpy(ifr.ifr_name, Options.netiface, sizeof(ifr.ifr_name));

   ifr.ifr_flags = old_ifr.ifr_flags;

   if ( ioctl(sock, SIOCSIFFLAGS, &ifr) < 0 )     // flag restoring
      ERROR_MSG("ioctl(SIOCSIFFLAGS) | flag restoring");

   Inet_CloseRawSock(sock);
}


void Inet_DisableForwarding(void)
{
   FILE *fd;

   fd = fopen("/proc/sys/net/ipv4/ip_forward", "r");
   if (fd == NULL)
      Error_msg("failed to open /proc/sys/net/ipv4/ip_forward");

   fscanf(fd, "%c", &IpForward_status);
   fclose(fd);

   DEBUG_MSG("Inet_DisableForwarding from %c", IpForward_status);

   atexit(Inet_RestoreForwarding);

   fd = fopen("/proc/sys/net/ipv4/ip_forward", "w");
   if (fd == NULL)
      Error_msg("failed to open /proc/sys/net/ipv4/ip_forward");

   fprintf(fd, "0");
   fclose(fd);
}



void Inet_RestoreForwarding(void)
{
   FILE *fd;

   if (strcmp(ECThread_getname(pthread_self()), PROGRAM)) return;

   fd = fopen("/proc/sys/net/ipv4/ip_forward", "w");
   if (fd == NULL)
      Error_msg("failed to open /proc/sys/net/ipv4/ip_forward");

   DEBUG_MSG("Inet_RestoreForwarding to %c", IpForward_status);

   fprintf(fd, "%c", IpForward_status );
   fclose(fd);
}



char *Inet_MacFromIP(unsigned long ip)
{
   int sock_raw;
   static struct arpreq ar;
   struct sockaddr_in *sa_in;

   DEBUG_MSG("Inet_MacFromIP");

   memset((char *)&ar, 0, sizeof(ar));
   strncpy(ar.arp_dev, Options.netiface, sizeof(ar.arp_dev));
   sa_in = (struct sockaddr_in *)&ar.arp_pa;
   sa_in->sin_family = AF_INET;
   sa_in->sin_addr.s_addr = ip;

   sock_raw =Inet_OpenRawSock(Options.netiface);

   if (ioctl(sock_raw, SIOCGARP, (caddr_t)&ar) == -1)  // not in cache... try to find it...
   {
      struct recv_packet recvpck;
      char MyMAC[6];
      u_long MyIP;
      int MTU, sock;
      TIME_DECLARE;

      DEBUG_MSG("Inet_MacFromIP -- try to find it");

      sock = Inet_OpenRawSock(Options.netiface);

      Inet_GetIfaceInfo(Options.netiface, &MTU, MyMAC, &MyIP, NULL);

      if (ip == MyIP) {
         DEBUG_MSG("Inet_MacFromIP -- try to find me... ;)");

         memcpy(&ar.arp_ha.sa_data, MyMAC, ETHER_ADDR_LEN);
         Inet_CloseRawSock(sock);
         Inet_CloseRawSock(sock_raw);
         return (char *) ar.arp_ha.sa_data;
      }

      recvpck.buf = Inet_Forge_packet( MTU + ALIGN_ETH_TO_WORD );
      recvpck.aligned = recvpck.buf + ALIGN_ETH_TO_WORD;

      Inet_Forge_ethernet( recvpck.aligned, MyMAC, ETH_BROADCAST, ETH_P_ARP );

      Inet_Forge_arp(recvpck.aligned + ETH_HEADER, ARPOP_REQUEST,
                         MyMAC, MyIP,
                         ARP_BROADCAST, ip );

      Inet_SendRawPacket(sock, recvpck.aligned, ETH_HEADER + ARP_HEADER);

		memset(recvpck.aligned, 0, MTU);

      fcntl(sock, F_SETFL, O_NONBLOCK);
      TIME_START;

      do
      {
         int len;
         short pkttype;
         ETH_header *ethpkt;
         ARP_header *arppkt;

         len = Inet_GetRawPacket(sock, recvpck.aligned, MTU, &pkttype);

         ethpkt = (ETH_header *)recvpck.aligned;
         arppkt = (ARP_header *)(ethpkt + 1);

         TIME_FINISH;

         if (len > 0 && pkttype == PACKET_HOST && ethpkt->type == htons(ETH_P_ARP) && arppkt->opcode == htons(ARPOP_REPLY))
         {
            if ( *(unsigned long *)arppkt->source_ip == ip )
            {
               memcpy(&ar.arp_ha.sa_data, &arppkt->source_add, ETHER_ADDR_LEN);
               Inet_Forge_packet_destroy( recvpck.buf );
               Inet_CloseRawSock(sock);
               Inet_CloseRawSock(sock_raw);
               return (char *) ar.arp_ha.sa_data;
            }
         }
      } while ( TIME_ELAPSED < 0.5 );

		Inet_Forge_packet_destroy( recvpck.buf );
      Inet_CloseRawSock(sock);
      Inet_CloseRawSock(sock_raw);
      return ETH_BROADCAST;  // workaround for non local ip
   }

   Inet_CloseRawSock(sock_raw);
   return (char *) ar.arp_ha.sa_data;

}

#ifdef PERMIT_HTTPS

// ARP ENTRY MANAGEMENT ---------------------------

unsigned long SavedIP;
unsigned char SavedMAC[6];

void Inet_UnSetARPEntry(void)
{
   struct arpreq req;
   int sockfd;
   struct sockaddr_in *sa_in;

   DEBUG_MSG("Inet_UnSetARPEntry");

   sockfd = socket(AF_INET, SOCK_DGRAM, 0);

   memset((char *) &req, 0, sizeof(req));
   sa_in = (struct sockaddr_in *)&req.arp_pa;
   sa_in->sin_family = AF_INET;
   sa_in->sin_addr.s_addr = SavedIP;
   req.arp_flags = ATF_PERM | ATF_COM;

   memcpy(req.arp_ha.sa_data, SavedMAC, 6);
   strlcpy(req.arp_dev, Options.netiface, sizeof(req.arp_dev));

   ioctl(sockfd, SIOCDARP, &req);

   close(sockfd);
}


int Inet_SetARPEntry(unsigned long IP, char MAC[6])
{
   struct arpreq req;
   int sockfd;
   struct sockaddr_in *sa_in;
   int retval;

   DEBUG_MSG("Inet_SetARPEntry");

   sockfd = socket(AF_INET, SOCK_DGRAM, 0);

   memset((char *) &req, 0, sizeof(req));
   sa_in = (struct sockaddr_in *)&req.arp_pa;
   sa_in->sin_family = AF_INET;
   sa_in->sin_addr.s_addr = IP;
   req.arp_flags = ATF_PERM | ATF_COM;

   memcpy(req.arp_ha.sa_data, MAC, 6);
   strlcpy(req.arp_dev, Options.netiface, sizeof(req.arp_dev));

   retval = ioctl(sockfd, SIOCSARP, &req);

   close(sockfd);

   SavedIP=IP;
   memcpy(SavedMAC, MAC, 6);
   atexit(Inet_UnSetARPEntry);

   return retval;
}

// ROUTE MANAGEMENT ---------------------------

struct rtentry
{
    unsigned long int rt_pad1;
    struct sockaddr_in rt_dst;
    struct sockaddr_in rt_gateway;
    struct sockaddr_in rt_genmask;
    unsigned short int rt_flags;
    short int rt_pad2;
    unsigned long int rt_pad3;
    unsigned char rt_tos;
    unsigned char rt_class;
    short int rt_pad4;
    short int rt_metric;
    char *rt_dev;
    unsigned long int rt_mtu;
    unsigned long int rt_window;
    unsigned short int rt_irtt;
};

void Inet_UnsetRoute(void)
{
    int skfd;
    struct rtentry rt;

    DEBUG_MSG("Inet_UnsetRoute");

    skfd = socket(AF_INET, SOCK_DGRAM, 0);

    memset((char *)&rt,0, sizeof(struct rtentry));

    rt.rt_dst.sin_family=AF_INET;
    rt.rt_dst.sin_addr.s_addr=inet_addr("1.0.0.1");
    rt.rt_genmask.sin_family=AF_INET;
    rt.rt_genmask.sin_addr.s_addr=inet_addr("255.255.255.255");
    rt.rt_flags=5;
    rt.rt_dev=Options.netiface;

    ioctl(skfd, SIOCDELRT, &rt);

    rt.rt_dst.sin_addr.s_addr=inet_addr("1.0.0.0");
    rt.rt_gateway.sin_family=AF_INET;
    rt.rt_gateway.sin_addr.s_addr=inet_addr("1.0.0.1");
    rt.rt_genmask.sin_addr.s_addr=inet_addr("255.0.0.0");
    rt.rt_flags=3;

    ioctl(skfd, SIOCDELRT, &rt);

    close(skfd);
}

void Inet_SetRoute(void)
{
    int skfd;
    struct rtentry rt;

    DEBUG_MSG("Inet_SetRoute");

    skfd = socket(AF_INET, SOCK_DGRAM, 0);

    memset((char *)&rt,0, sizeof(struct rtentry));

    rt.rt_dst.sin_family=AF_INET;
    rt.rt_dst.sin_addr.s_addr=inet_addr("1.0.0.1");
    rt.rt_genmask.sin_family=AF_INET;
    rt.rt_genmask.sin_addr.s_addr=inet_addr("255.255.255.255");
    rt.rt_flags=5;
    rt.rt_dev=Options.netiface;

    ioctl(skfd, SIOCADDRT, &rt);

    rt.rt_dst.sin_addr.s_addr=inet_addr("1.0.0.0");
    rt.rt_gateway.sin_family=AF_INET;
    rt.rt_gateway.sin_addr.s_addr=inet_addr("1.0.0.1");
    rt.rt_genmask.sin_addr.s_addr=inet_addr("255.0.0.0");
    rt.rt_flags=3;

    ioctl(skfd, SIOCADDRT, &rt);

    close(skfd);

    atexit(Inet_UnsetRoute);
}

#endif

/* EOF */

// vim:ts=3:expandtab

