⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 loopback.c

📁 开放源码的编译器open watcom 1.6.0版的源代码
💻 C
字号:
/*
 *  A simple loopback device.
 *  Handles ICMP Echo-request and UDP sink/discard packets.
 *
 *  Add protocol handlers to `loopback_handler' pointer as required.
 *
 *  The modified (src/dst IP swapped) ip packet is enqueued to the IP
 *  receive queue after loopback_device() returns.
 *
 *  The return value is:
 *    -1  if IP-packet should not be enqueued to IP input queue
 *    >0  length of (modified) IP-packet
 *
 *  Gisle Vanem  10 Dec. 1997
 */

#include <stdio.h>
#include <stdlib.h>

#include "copyrigh.h"
#include "wattcp.h"
#include "chksum.h"
#include "ip_out.h"
#include "pcstat.h"
#include "pcicmp.h"
#include "loopback.h"

#if defined(USE_LOOPBACK)

#if 0

  A sketch of calls involved in sending/receiving an IP-packet


  Sending an IP-packet            |             Receiving an IP-packet
  --------------------------------|-----------------------------------
      |                           |                     |
      |                           |               tcp_tick()
      |                           |                     |
   _eth_formatpacket() ->buffer X |               _eth_arrived()
      |                           |                     |
   _ip_output()                   |               poll_recv_queues()
      |                           |                     |
      |                           |                     |
   _eth_send()                    enqueue copy of       |
      |                           X to IP-queue         |
      *----->loopback_device()--*-->>>>>>-<-------poll_ip_queue()
      |                         | |   |            |    |
      |                         | |   |            |    |
   _pkt_send()    drop buffer X \ |   |          none ip_defragment()
      |                           |   |            |    |
      |                           |   |            \  _ip_handler()
      |                           |   |                 |
      |                           |   |               protocol handlers
      |                           |   |                 |
      |                           |   |               _eth_free()
      v                           |   |                 |
  packet-driver                   |   `-----------<-- pkt_free_pkt()
      |                           |                     |
  Ethernet/PPP                                          \

  From the above it evident the current design cannot easily send
  IP-fragments. _ip_output() must be rewritten to handle max. 64kB
  packets, split them in make_fragments(), format a link-layer packet
  using _eth_formatpacket() and repetively call _eth_send().

#endif


int loopback_enable = 1; 

int (*loopback_handler) (in_Header*) = NULL;

static int icmp_loopback (ICMP_PKT   *icmp, unsigned icmp_len);
static int udp_loopback  (udp_Header *udp,  unsigned udp_len);

/*
 * We have been called with an ip-packet located on stack in
 * _eth_send_loopback(). Hence, it's safe to call _eth_send() again
 * here. MAC-header is in front of 'ip'.
 */
int loopback_device (in_Header *ip)
{
  int   ip_hlen, ip_len;
  DWORD ip_dst;
  DWORD ip_ofs;
  WORD  ip_flg;

  if (!loopback_enable || !_chk_ip_header(ip)) /* silently discard */
     return (-1);

  ip_hlen = in_GetHdrLen (ip);    /* length of IP-header (w/options) */
  ip_len  = intel16 (ip->length); /* total length of IP-packet */
  ip_dst  = ip->destination;

  ip->destination = ip->source;   /* swap source and destination */
  ip->source      = ip_dst;
  ip->checksum    = 0;
  ip->checksum    = ~checksum (ip, ip_hlen);   /* redo check-sum */

  ip_ofs = intel16 (ip->frag_ofs);
  ip_flg = ip_ofs & ~IP_OFFMASK;
  ip_ofs = (ip_ofs & IP_OFFMASK) << 3; /* 0 <= ip_ofs <= 65536-8 */
   
  if (ip_ofs || (ip_flg & IP_MF)) /* fragment; let _ip_fragment() */
     return (ip_len);             /* handle it on next poll */

  if (ip->proto == ICMP_PROTO)
  {
    ICMP_PKT *icmp = (ICMP_PKT*) ((BYTE*)ip + ip_hlen);
    int       len  = icmp_loopback (icmp, ip_len - ip_hlen);

    if (len > 0)
       return (ip_hlen+len);
  }
  else if (ip->proto == UDP_PROTO)
  {
    udp_Header *udp = (udp_Header*) ((BYTE*)ip + ip_hlen);
    int         len = udp_loopback (udp, ip_len-ip_hlen);

    if (len > 0)
       return (ip_hlen+len);
  }

  if (loopback_handler)
     ip_len = (*loopback_handler) (ip);
  return (ip_len);
}

static int icmp_loopback (ICMP_PKT *icmp, unsigned icmp_len)
{
  if (icmp_len >= sizeof(icmp->echo)    &&
      checksum(icmp,icmp_len) == 0xFFFF &&
      icmp->echo.type == ICMP_ECHO)
  {
    static WORD echo_seq_num = 0;

    icmp->echo.type     = ICMP_ECHOREPLY;
    icmp->echo.sequence = echo_seq_num++;
    icmp->echo.checksum = 0;
    icmp->echo.checksum = ~checksum (icmp, icmp_len);
    STAT (icmpstats.icps_reflect++);
    STAT (icmpstats.icps_outhist[ICMP_ECHOREPLY]++);
    return (icmp_len);
  }
  /* !!to-do: fall-through to another ICMP loopback handler */

  return (0);
}

static int udp_loopback (udp_Header *udp, unsigned udp_len)
{
  if (intel16(udp->dstPort) == IPPORT_ECHO)
  {
    /* !!to-do */
  }
  else if (intel16(udp->dstPort) == IPPORT_DISCARD)
  {
    /* !!to-do */
  }
  ARGSUSED (udp_len);
  return (0);
}

/*
 *  An example loopback handler for RPC Portmapper (udp port 111)
 *  (Maybe an contradiction in terms to do RPC locally :-)
 *
 *  int (*old_loopback) (in_Header*) = NULL;
 *
 *  static int pmap_loopback (in_Header *ip)
 *  {
 *    WORD        hlen = in_GetHdrLen (ip);
 *    udp_Header *udp  = (udp_Header*) ((BYTE*)ip + hlen);
 *
 *    if (ip->proto == UDP_PROTO && intel16(udp->dstPort) == 111)
 *       return do_portmapper (udp); (return length of IP reply packet)
 *
 *    if (old_loopback)
 *       return (*old_loopback) (ip);
 *    return (length);
 *  }
 *
 *  void init_pmap_loopback (void)
 *  {
 *    old_loopback = loopback_handler;
 *    loopback_handler = pmap_loopback;
 *  }
 */

#endif /* USE_LOOPBACK */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -