Пример #1
0
static int icmp_echo_reply (const in_Header *ip, const union ICMP_PKT *req,
                            unsigned len)
{
  struct _pkt     *pkt;
  union  ICMP_PKT *icmp;

  if (!icmp_check(ip,ICMP_ECHO))
     return (0);

  icmp_print (2, _LANG("PING reply sent"), 0);

#if defined(USE_FRAGMENTS)
  if (len > _mtu - sizeof(*ip))
  {
    icmp = (union ICMP_PKT*) req;        /* reuse input for output */
    icmp->echo.type     = ICMP_ECHOREPLY;
    icmp->echo.checksum = 0;
    icmp->echo.checksum = ~CHECKSUM (icmp, len);
    return _IP4_SEND_FRAGMENTS (NULL, ICMP_PROTO, ip->source, icmp, len);
  }
#endif

  pkt  = (struct _pkt*) _eth_formatpacket (MAC_SRC(ip), IP4_TYPE);
  icmp = &pkt->icmp;

  len = min (len, _mtu - sizeof(*ip));
  memcpy (icmp, req, len);
  icmp->echo.type = ICMP_ECHOREPLY;
  icmp->echo.code = req->echo.code; /* Win uses 0, Unix !0 */

  /* Use supplied ip values in case we ever multi-home.
   * Note that ip values are still in network order.
   */
  return icmp_send (pkt, ip->destination, ip->source, len);
}
Пример #2
0
/**
 * Send an ICMP destination/protocol unreachable back to 'ip->source'.
 * Limit the rate of these to 20 per second. Ref. RFC-1812.
 */
int icmp_send_unreach (const in_Header *ip, int code)
{
  static DWORD next_time = 0UL;
  struct _pkt    *pkt;
  union ICMP_PKT *unr;
  unsigned        len;

  if (!icmp_check(ip,ICMP_UNREACH))
     return (0);

  if (next_time && !chk_timeout(next_time))
     return (0);

  next_time = set_timeout (50);

  pkt = (struct _pkt*) _eth_formatpacket (MAC_SRC(ip), IP4_TYPE);
  unr = &pkt->icmp;
  len = intel16 (ip->length) - in_GetHdrLen (ip);
  len = min (len, sizeof(*ip)+sizeof(unr->unused.spares));

  icmp_print (1, _LANG(icmp_unreach_str[code]), ip->destination);
  memcpy (&unr->unused.ip, ip, len);
  unr->unused.type = ICMP_UNREACH;
  unr->unused.code = (BYTE) code;

  return icmp_send (pkt, ip->destination, ip->source, sizeof(unr->unused));
}
Пример #3
0
/**
 * Handle incoming PPPoE packets.
 */
int pppoe_handler (const pppoe_Packet *pkt)
{
  const BYTE *buf;
  const void *src;
  const void *dst;
  WORD  proto, len;
  BOOL  bcast, delivered = FALSE;

  if (pkt->type != 1 || pkt->ver != 1)
     return (0);

  src   = MAC_SRC (pkt);
  dst   = MAC_DST (pkt);
  proto = MAC_TYP (pkt);
  bcast = !memcmp (dst, _eth_brdcast, _eth_mac_len);

  if (proto == PPPOE_SESS_TYPE && state == StateSession)
  {
    if (pkt->code    == PPPOE_CODE_SESS &&
        pkt->session == session         && !bcast &&
        !memcmp(dst, _eth_addr, _eth_mac_len) &&  /* to us? */
        !memcmp(src, ac_macAddr, _eth_mac_len))
    {
      len = intel16 (pkt->length);
      buf = &pkt->data[0];
      ppp_input (buf, len);    /* assume ppp_input() traces it */
      delivered = TRUE;
    }
  }
  else if (!bcast && proto == PPPOE_DISC_TYPE && state == StateDiscovery)
  {
    if (pkt->code == PPPOE_CODE_PADO)          /* Offer (can this be bcast?) */
    {
      got_PADO = TRUE;
      memcpy (ac_macAddr, src, _eth_mac_len);
    }
    else if (pkt->code == PPPOE_CODE_PADT &&  /* Terminate */
             pkt->session == session)
    {
      if (cfg.trace)
         outsnl (_LANG("PPPoE: session terminated"));
      got_PADT = TRUE;
      session  = 0;
    }
    else if (pkt->code == PPPOE_CODE_PADS)    /* Session-confirmation */
    {
      got_PADS = TRUE;
      session  = pkt->session;
    }
    else if (pkt->code == PPPOE_CODE_PADM)    /* Message (what to do?) */
    {
      got_PADM = TRUE;
    }
  }
  if (!delivered)
     DEBUG_RX (NULL, pkt);
  return (1);
}
Пример #4
0
/*
 *  Send an ICMP destination/protocol unreachable back to ip->source
 */
void icmp_unreach (const in_Header *ip, int code)
{
  struct _pkt    *pkt;
  union icmp_pkt *unr;
  int             len;

  if (!icmp_chk_src(ip,ICMP_UNREACH))
     return;

  pkt = (struct _pkt*) _eth_formatpacket (MAC_SRC(ip), IP_TYPE);
  unr = &pkt->icmp;
  len = intel16 (ip->length) - in_GetHdrLen (ip);
  len = min (len, sizeof(*ip)+sizeof(unr->unused.spares));

  icmp_print (1, icmp_unreach_str[code], ip->destination);
  memcpy (&unr->unused.ip, ip, len);
  unr->unused.type = ICMP_UNREACH;
  unr->unused.code = code;

  icmp_send (pkt, ip->destination, ip->source, sizeof(unr->unused));
}
Пример #5
0
/*
 *  Handler for incoming ICMP packets
 */
void icmp_handler (const in_Header *ip, BOOL broadcast)
{
  union icmp_pkt *icmp;
  in_Header      *orig_ip;
  int             len, type, code;
  BOOL            for_me, i_orig;  /* is it for me, did I originate it */
  const char     *msg;

  DEBUG_RX (NULL, ip);

  if (block_icmp)   /* application is handling ICMP; not needed */
     return;

  len    = in_GetHdrLen (ip);
  icmp   = (union icmp_pkt*) ((BYTE*)ip + len);
  len    = intel16 (ip->length) - len;
  for_me = (DWORD) (intel(ip->destination) - my_ip_addr) <= multihomes;

  if (!for_me || broadcast)  /* drop broadcast pings.. */
     return;

  if (len < sizeof(icmp->info))
  {
    STAT (icmpstats.icps_tooshort++);
    return;
  }

  if (checksum(icmp,len) != 0xFFFF)
  {
    STAT (icmpstats.icps_checksum++);
    icmp_print (1, _LANG("bad checksum"), ip->source);
    return;
  }

  type    = icmp->unused.type;
  code    = icmp->unused.code;
  orig_ip = &icmp->ip.ip;
  i_orig  = is_local_addr (intel(orig_ip->source));

  if (type == ICMP_MASKREPLY)
  {
    if (!_domask_req)
       return;
    i_orig = TRUE;
  }

  /* !! this needs work
   */
  if (!i_orig &&
      (type != ICMP_ECHOREPLY && type != ICMP_ECHO &&
       type != ICMP_IREQREPLY && type != ICMP_TSTAMP))
  {
    icmp_bogus (ip, type, NULL);
    return;
  }

  switch (type)
  {
    case ICMP_ECHOREPLY:  /* check if we were waiting for it */
         STAT (icmpstats.icps_inhist[ICMP_ECHOREPLY]++);
         ping_hcache = intel (ip->source);
         ping_tcache = set_timeout (1000) - *(DWORD*)&icmp->echo.identifier;
         if (ping_tcache > 0x7FFFFFFFL)
             ping_tcache += 0x1800B0L;
         ping_number = *(DWORD*)(((BYTE*)&icmp->echo.identifier) + 4);
         return;

    case ICMP_UNREACH:
         STAT (icmpstats.icps_inhist[ICMP_UNREACH]++);
         if (code < DIM(icmp_unreach_str))
         {
           icmp_print (1, msg = icmp_unreach_str[code], ip->source);
#if !defined(USE_UDP_ONLY)
           if (orig_ip->proto == TCP_PROTO)
              _tcp_cancel (orig_ip, type, msg, 0);
           else
#endif
           if (orig_ip->proto == UDP_PROTO)
              _udp_cancel (orig_ip, type, msg, 0);
         }
         else
           STAT (icmpstats.icps_badcode++);
         return;

    case ICMP_SOURCEQUENCH:
         STAT (icmpstats.icps_inhist[ICMP_SOURCEQUENCH]++);
#if !defined(USE_UDP_ONLY)
         if (orig_ip->proto == TCP_PROTO)
         {
           icmp_print (1, _LANG("Source Quench"), ip->source);
           _tcp_cancel (orig_ip, type, NULL, 0);
         }
#endif
         return;

    case ICMP_REDIRECT:
         STAT (icmpstats.icps_inhist[ICMP_REDIRECT]++);
         if (code < 4)
         {
           DWORD new_gw = intel (icmp->ip.ipaddr);

           /* Check if new gateway is on our subnet
            */
           if ((new_gw ^ my_ip_addr) & sin_mask)
           {
             char buf[100], adr[20];
             strcpy (buf, ", GW = ");
             strcat (buf, _inet_ntoa(adr,new_gw));
             icmp_bogus (ip, type, buf);
             return;
           }
           icmp_print (1, msg = icmp_redirect_str[code], ip->source);

           switch (orig_ip->proto)
           {
#if !defined(USE_UDP_ONLY)
             case TCP_PROTO:
                  if (do_redirect.tcp)  /* do it to some socket */
                     _tcp_cancel (orig_ip, type, msg, new_gw);
                  break;
#endif
             case UDP_PROTO:
                  if (do_redirect.udp)
                     _udp_cancel (orig_ip, type, msg, new_gw);
                  break;

             case ICMP_PROTO:
                  if (do_redirect.icmp)
                  {
                    _ip_recursion = 1;
                    _arp_register (new_gw, intel(orig_ip->destination), 0);
                    _ip_recursion = 0;
                  }
                  break;

             case IGMP_PROTO:
                  if (do_redirect.igmp)
                  {
                    _ip_recursion = 1;
                    _arp_register (new_gw, intel(orig_ip->destination), 0);
                    _ip_recursion = 0;
                  }
                  break;
           }
         }
         else
           STAT (icmpstats.icps_badcode++);
         return;

    case ICMP_ECHO:
         STAT (icmpstats.icps_inhist[ICMP_ECHO]++);
         icmp_print (2, _LANG("PING requested of us"), ip->source);
         {
           /* Extract eth-address and create Echo reply packet.
            */
           struct _pkt     *pkt;
           union  icmp_pkt *newicmp;

           if (!icmp_chk_src(ip,ICMP_ECHO))
              return;

           pkt     = (struct _pkt*) _eth_formatpacket (MAC_SRC(ip), IP_TYPE);
           newicmp = &pkt->icmp;

           /* Don't let a huge reassembled ICMP-packet kill us.
            */
           len = min (len, mtu - sizeof(*ip));
           memcpy (newicmp, icmp, len);
           newicmp->echo.type = ICMP_ECHOREPLY;
           newicmp->echo.code = code;

           /* Use supplied ip values in case we ever multi-home.
            * Note that ip values are still in network order.
            */
           icmp_send (pkt, ip->destination, ip->source, len);
           icmp_print (2, _LANG("PING reply sent"), 0);
         }
         return;

    case ICMP_TIMXCEED:
         if (code >= DIM(icmp_exceed_str))
         {
           STAT (icmpstats.icps_badcode++);
           return;
         }
         STAT (icmpstats.icps_inhist[ICMP_TIMXCEED]++);

         if (code != 1)
            switch (orig_ip->proto)
            {
#if !defined(USE_UDP_ONLY)
              case TCP_PROTO:
                   icmp_print (1, icmp_exceed_str[code], ip->source);
                   _tcp_cancel (orig_ip, ICMP_TIMXCEED, NULL, 0);
                   break;
#endif
              case UDP_PROTO:
                   icmp_print (1, icmp_exceed_str[code], ip->source);
                   _udp_cancel (orig_ip, ICMP_TIMXCEED, NULL, 0);
                   break;
            }
         return;

    case ICMP_PARAMPROB:
         STAT (icmpstats.icps_inhist[ICMP_PARAMPROB]++);
         switch (orig_ip->proto)
         {
#if !defined(USE_UDP_ONLY)
           case TCP_PROTO:
                icmp_print (0, _LANG(icmp_type_str[type]), ip->source);
                _tcp_cancel (orig_ip, type, NULL, 0);
                break;
#endif
           case UDP_PROTO:
                icmp_print (0, _LANG(icmp_type_str[type]), ip->source);
                _udp_cancel (orig_ip, type, NULL, 0);
                break;
         }
         return;

    case ICMP_ROUTERADVERT:  /* todo !! */
         STAT (icmpstats.icps_inhist[ICMP_ROUTERADVERT]++);
         icmp_print (1, _LANG(icmp_type_str[type]), ip->source);
         return;

    case ICMP_ROUTERSOLICIT: /* todo !! */
         STAT (icmpstats.icps_inhist[ICMP_ROUTERSOLICIT]++);
         icmp_print (1, _LANG(icmp_type_str[type]), ip->source);
         return;

    case ICMP_TSTAMP:
         STAT (icmpstats.icps_inhist[ICMP_TSTAMP]++);
         icmp_print (1, _LANG(icmp_type_str[type]), ip->source);
         /* todo!!, send reply? */
         return;

    case ICMP_TSTAMPREPLY:
         STAT (icmpstats.icps_inhist[ICMP_TSTAMPREPLY]++);
         icmp_print (1, _LANG(icmp_type_str[type]), ip->source);
         /* todo!!, should store */
         return;

    case ICMP_IREQ:
         STAT (icmpstats.icps_inhist[ICMP_IREQ]++);
         icmp_print (1, _LANG(icmp_type_str[type]), ip->source);
         /* todo!!, send reply */
         return;

    case ICMP_IREQREPLY:
         STAT (icmpstats.icps_inhist[ICMP_IREQREPLY]++);
         icmp_print (1, _LANG(icmp_type_str[type]), ip->source);
         /* todo!!, send reply upwards */
         return;

    case ICMP_MASKREQ:
         STAT (icmpstats.icps_inhist[ICMP_MASKREQ]++);
         break;

    case ICMP_MASKREPLY:
         STAT (icmpstats.icps_inhist[ICMP_MASKREPLY]++);
         icmp_print (0, _LANG(icmp_type_str[type]), ip->source);
         if ((icmp->mask.identifier == addr_mask_id)    &&
             (icmp->mask.sequence   == addr_mask_seq-1) &&
             sin_mask != intel(icmp->mask.mask))
            outsnl ("Conflicting net-mask from \"ICMP Addr Mask Reply\"\7");
         addr_mask_id = 0;
         return;
  }
}
Пример #6
0
/**
 * Enqueue a link-layer frame (IPv4/v6 only) to the internal loopback device.
 *
 * \note This function uses call-by-value. Thus `pkt' buffer can
 *       be modified by loopback_device() and loopback handler may
 *       send using _eth_send().
 *
 * \note Loopback device cannot send to itself (potential recursion).
 */
static int send_loopback (link_Packet pkt, BOOL is_ip6, unsigned *err_line)
{
  struct pkt_ringbuf *q;
  const  in_Header   *ip;
  int    ip_len;

  SIO_TRACE (("send_loopback"));

  if (!_pkt_inf)
  {
    *err_line = __LINE__;
    goto drop_it;
  }

  /* Call loopback handler with IP-packet
   */
  ip     = (in_Header*) ((BYTE*)&pkt + _pkt_ip_ofs);
  ip_len = loopback_device ((in_Header*)ip);

  q = &_pkt_inf->pkt_queue;

  if (!q || ip_len > (int)_mtu)
  {
    *err_line = __LINE__;
    goto drop_it;
  }

  if (ip_len > 0)
  {
#if defined(USE_FAST_PKT)
    /*
     * Don't let pkt_receiver() modify the queue while testing/copying.
     */
    if (pkt_buffers_used() >= _pkt_inf->pkt_queue.num_buf - 1)
    {
      *err_line = __LINE__;
      goto drop_it;
    }
    {
      char     tx_buf [ETH_MAX];
      unsigned len = ip_len;

      /* Enqueue packet to head of input IP-queue.
       */
      if (!_pktserial)
      {
        void *data = (*mac_tx_format) (tx_buf, _eth_addr,
                                       is_ip6 ? IP6_TYPE : IP4_TYPE);
        memcpy (MAC_SRC(data), &_eth_loop_addr, sizeof(mac_address));
        memcpy (data, ip, ip_len);
        len += _pkt_ip_ofs;
      }
      else
        memcpy (tx_buf, ip, ip_len);

      if (!pkt_append_recv(tx_buf, len))
      {
        *err_line = __LINE__;
        goto drop_it;
      }
    }
#elif defined(WIN32)
    struct pkt_rx_element *head;

    ENTER_CRIT();
    if (pktq_in_index(q) == q->out_index)  /* queue is full, drop it */
    {
      q->num_drop++;
      LEAVE_CRIT();
      *err_line = __LINE__;
      goto drop_it;
    }

    head = (struct pkt_rx_element*) pktq_in_buf (q);
    head->rx_length = _pkt_ip_ofs + ip_len;
    gettimeofday (&head->tstamp_put, NULL);

    /* Enqueue packet to head of input IP-queue.
     */
    if (!_pktserial)
    {
      void *data = (*mac_tx_format) (&head->rx_buf, _eth_addr,
                                     is_ip6 ? IP6_TYPE : IP4_TYPE);
      memcpy (MAC_SRC(data), &_eth_loop_addr, sizeof(mac_address));
      memcpy (data, ip, ip_len);
    }
    else
      memcpy (head, ip, ip_len);

    /* Update queue head index
     */
    q->in_index = pktq_in_index (q);

    LEAVE_CRIT();

#else
    union link_Packet *head;

    DISABLE();
    if (pktq_in_index(q) == q->out_index)  /* queue is full, drop it */
    {
      q->num_drop++;
      ENABLE();
      *err_line = __LINE__;
      goto drop_it;
    }

    head = (union link_Packet*) pktq_in_buf (q);

    /* Enqueue packet to head of input IP-queue.
     */
    if (!_pktserial)
    {
      void *data = (*mac_tx_format) (head, _eth_addr,
                                     is_ip6 ? IP6_TYPE : IP4_TYPE);
      memcpy (MAC_SRC(data), &_eth_loop_addr, sizeof(mac_address));
      memcpy (data, ip, ip_len);
    }
    else
      memcpy (head, ip, ip_len);

    /* Update queue head index
     */
    q->in_index = pktq_in_index (q);

    ENABLE();
#endif
  }
  *err_line = 0;
  return (ip_len + _pkt_ip_ofs);

drop_it:
  /*
   * Maybe this should be an input counter
   */
  if (is_ip6)
       STAT (ip6stats.ip6s_odropped++);
  else STAT (ip4stats.ips_odropped++);
  return (0);
}