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

📄 utility.c

📁 linux下telnet服务端的源码实现
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Copyright (C) 1998,2001,2005 Free Software Foundation, Inc.   This file is part of GNU Inetutils.   GNU Inetutils 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, or (at your option)   any later version.   GNU Inetutils is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR 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 GNU Inetutils; see the file COPYING.  If not, write   to the Free Software Foundation, Inc., 51 Franklin Street,   Fifth Floor, Boston, MA 02110-1301 USA. */#define TELOPTS#define TELCMDS#define SLC_NAMES#include "telnetd.h"#include <stdarg.h>#ifdef HAVE_TERMIO_H# include <termio.h>#endif#if defined(AUTHENTICATION) || defined(ENCRYPTION)# include <libtelnet/misc.h># define NET_ENCRYPT net_encrypt#else# define NET_ENCRYPT()#endifstatic char netobuf[BUFSIZ+NETSLOP], *nfrontp, *nbackp;static char *neturg;    /* one past last byte of urgent data */#ifdef  ENCRYPTIONstatic char *nclearto;#endifstatic char ptyobuf[BUFSIZ+NETSLOP], *pfrontp, *pbackp;static char netibuf[BUFSIZ], *netip;static int ncc;static char ptyibuf[BUFSIZ], *ptyip;static int pcc;int not42;static intreadstream (int p, char *ibuf, int bufsize){#ifndef HAVE_STREAMSPTY  return read (p, ibuf, bufsize);#else  int flags = 0;  int ret = 0;  struct termios *tsp;  struct termio *tp;  struct iocblk *ip;  char vstop, vstart;  int ixon;  int newflow;  struct  strbuf strbufc, strbufd;  unsigned char ctlbuf[BUFSIZ];  static int flowstate = -1;   strbufc.maxlen = BUFSIZ;  strbufc.buf = (char *)ctlbuf;  strbufd.maxlen = bufsize-1;  strbufd.len = 0;  strbufd.buf = ibuf+1;  ibuf[0] = 0;  ret = getmsg(p, &strbufc, &strbufd, &flags);  if (ret < 0)  /* error of some sort -- probably EAGAIN */    return -1;  if (strbufc.len <= 0 || ctlbuf[0] == M_DATA)    {      /* data message */      if (strbufd.len > 0) /* real data */        return strbufd.len + 1;        /* count header char */      else        {          /* nothing there */          errno = EAGAIN;          return -1;        }    }  /*   * It's a control message.  Return 1, to look at the flag we set   */  switch (ctlbuf[0])    {    case M_FLUSH:      if (ibuf[1] & FLUSHW)        ibuf[0] = TIOCPKT_FLUSHWRITE;      return 1;    case M_IOCTL:      ip = (struct iocblk *) (ibuf+1);      switch (ip->ioc_cmd)        {        case TCSETS:        case TCSETSW:        case TCSETSF:          tsp = (struct termios *) (ibuf + 1 + sizeof(struct iocblk));          vstop = tsp->c_cc[VSTOP];          vstart = tsp->c_cc[VSTART];          ixon = tsp->c_iflag & IXON;          break;        case TCSETA:        case TCSETAW:        case TCSETAF:          tp = (struct termio *) (ibuf + 1 + sizeof(struct iocblk));          vstop = tp->c_cc[VSTOP];          vstart = tp->c_cc[VSTART];          ixon = tp->c_iflag & IXON;          break;        default:          errno = EAGAIN;          return -1;        }      newflow =  (ixon && (vstart == 021) && (vstop == 023)) ? 1 : 0;      if (newflow != flowstate)  /* it's a change */        {          flowstate = newflow;          ibuf[0] = newflow ? TIOCPKT_DOSTOP : TIOCPKT_NOSTOP;          return 1;        }    }  /* nothing worth doing anything about */  errno = EAGAIN;  return -1;#endif /* HAVE_STREAMSPTY */}/* ************************************************************************* *//* Net and PTY I/O functions */voidio_setup (){  pfrontp = pbackp = ptyobuf;  nfrontp = nbackp = netobuf;#ifdef  ENCRYPTION  nclearto = 0;#endif   netip = netibuf;  ptyip = ptyibuf;}voidset_neturg (){  neturg = nfrontp - 1;}/* net-buffers */voidnet_output_byte (int c){  *nfrontp++ = c;}intnet_output_data (const char *format,...){  va_list args;  size_t remaining, ret;  va_start (args, format);  remaining = BUFSIZ - (nfrontp - netobuf);  /* try a netflush() if the room is too low */  if (strlen (format) > remaining || BUFSIZ / 4 > remaining)    {      netflush ();      remaining = BUFSIZ - (nfrontp - netobuf);    }  ret = vsnprintf (nfrontp, remaining, format, args);  nfrontp += ((ret < remaining - 1) ? ret : remaining - 1);  va_end (args);  return ret;}intnet_output_datalen (const void *buf, size_t l){  size_t remaining;  remaining = BUFSIZ - (nfrontp - netobuf);  if (remaining < l)    {      netflush ();      remaining = BUFSIZ - (nfrontp - netobuf);    }  if (remaining < l)    return -1;  memmove (nfrontp, buf, l);  nfrontp += l;  return (int) l;}intnet_input_level (){  return ncc;}intnet_output_level (){  return nfrontp - nbackp;}intnet_buffer_is_full (){  return (&netobuf[BUFSIZ] - nfrontp) < 2;}intnet_get_char (int peek){  if (peek)    return *netip;  else if (ncc > 0)    {      ncc--;      return *netip++ & 0377;    }}intnet_read (){  ncc = read (net, netibuf, sizeof (netibuf));  if (ncc < 0 && errno == EWOULDBLOCK)    ncc = 0;  else if (ncc == 0)    {      syslog (LOG_INFO, "telnetd:  peer died");      cleanup(0);    }  else if (ncc > 0)    {      netip = netibuf;      DEBUG(debug_report,1,	    debug_output_data ("td: netread %d chars\r\n", ncc));      DEBUG(debug_net_data,1,	  	    printdata("nd", netip, ncc));    }  return ncc;}/* PTY buffer functions */intpty_buffer_is_full (){  return (&ptyobuf[BUFSIZ] - pfrontp) < 2;}voidpty_output_byte (int c){  *pfrontp++ = c;}	     voidpty_output_datalen (const void *data, size_t len){  if ((&ptyobuf[BUFSIZ] - pfrontp) > len)    ptyflush ();  memcpy (pfrontp, data, len);  pfrontp += len;}intpty_input_level (){  return pcc;}intpty_output_level (){  return pfrontp - pbackp;}voidptyflush(){  int n;    if ((n = pfrontp - pbackp) > 0)    {      DEBUG(debug_report, 1,	    debug_output_data ("td: ptyflush %d chars\r\n", n));      DEBUG(debug_pty_data, 1,	    printdata("pd", pbackp, n));      n = write(pty, pbackp, n);    }  if (n < 0)    {      if (errno == EWOULDBLOCK || errno == EINTR)	return;      cleanup(0);    }  pbackp += n;  if (pbackp == pfrontp)    pbackp = pfrontp = ptyobuf;}intpty_get_char (int peek){  if (peek)    return *ptyip;  else if (pcc > 0)    {      pcc--;      return *ptyip++ & 0377;    }}intpty_input_putback (const char *str, size_t len){  if (len > &ptyibuf[BUFSIZ] - ptyip)    len = &ptyibuf[BUFSIZ] - ptyip;  strncpy (ptyip, str, len);  pcc += len;}intpty_read (){  pcc = readstream (pty, ptyibuf, BUFSIZ);  if (pcc < 0      && (errno == EWOULDBLOCK #ifdef	EAGAIN	  || errno == EAGAIN #endif	  || errno == EIO))     pcc = 0;  ptyip = ptyibuf;  DEBUG(debug_report,1,	debug_output_data ("ptyread %d chars\r\n", pcc));  DEBUG(debug_pty_data,1,	  	printdata("pty", ptyip, pcc));  return pcc;}/* ************************************************************************* *//* io_drain () *    *   *	A small subroutine to flush the network output buffer, get some data * from the network, and pass it through the telnet state machine.  We * also flush the pty input buffer (by dropping its data) if it becomes * too full. */voidio_drain (){  DEBUG(debug_report, 1, debug_output_data("td: ttloop\r\n"));  if (nfrontp - nbackp > 0)     netflush (); again:  ncc = read (net, netibuf, sizeof netibuf);  if (ncc < 0)    {      if (errno == EAGAIN)	{	  syslog (LOG_INFO, "ttloop: retrying");	  goto again;	}      syslog (LOG_INFO, "ttloop:  read: %m\n");      exit (1);    }  else if (ncc == 0)    {      syslog (LOG_INFO, "ttloop:  peer died: %m\n");      exit (1);    }  DEBUG(debug_report, 1,	debug_output_data ("td: ttloop read %d chars\r\n", ncc));  netip = netibuf;  telrcv ();			/* state machine */  if (ncc > 0)    {      pfrontp = pbackp = ptyobuf;      telrcv ();    }}  /* end of ttloop *//* * Check a descriptor to see if out of band data exists on it. *//* int	s; socket number */intstilloob (int s){  static struct timeval timeout = { 0 };  fd_set excepts;  int value;  do    {      FD_ZERO (&excepts);      FD_SET (s, &excepts);      value = select (s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);    }  while (value == -1 && errno == EINTR);  if (value < 0)    fatalperror (pty, "select");  return FD_ISSET (s, &excepts);}/* * nextitem() *   *	Return the address of the next "item" in the TELNET data * stream.  This will be the address of the next character if * the current address is a user data character, or it will * be the address of the character following the TELNET command * if the current address is a TELNET IAC ("I Am a Command") * character. */char *nextitem (char *current){  if ((*current&0xff) != IAC)     return current+1;  switch (*(current+1)&0xff)    {    case DO:    case DONT:    case WILL:    case WONT:	return current+3;	    case SB:		/* loop forever looking for the SE */      {	register char *look = current+2;	for (;;) 	  if ((*look++&0xff) == IAC	      && (*look++&0xff) == SE) 	    return look;	      default:	return current+2;      }    }}  /* end of nextitem *//* * netclear() *   *	We are about to do a TELNET SYNCH operation.  Clear * the path to the network. *   *	Things are a bit tricky since we may have sent the first * byte or so of a previous TELNET command into the network. * So, we have to scan the network buffer from the beginning * until we are up to where we want to be. *   *	A side effect of what we do, just to keep things * simple, is to clear the urgent data pointer.  The principal * caller should be setting the urgent data pointer AFTER calling * us in any case. */#define	wewant(p) \  ((nfrontp > p) && ((*p&0xff) == IAC) && \   ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))voidnetclear (){  register char *thisitem, *next;  char *good;  #ifdef	ENCRYPTION  thisitem = nclearto > netobuf ? nclearto : netobuf;#else	/* ENCRYPTION */  thisitem = netobuf;#endif	/* ENCRYPTION */  while ((next = nextitem (thisitem)) <= nbackp)    thisitem = next;  /* Now, thisitem is first before/at boundary. */#ifdef	ENCRYPTION  good = nclearto > netobuf ? nclearto : netobuf;#else	/* ENCRYPTION */  good = netobuf;	/* where the good bytes go */#endif	/* ENCRYPTION */  while (nfrontp > thisitem)    {      if (wewant (thisitem))	{	  int length;	  for (next = thisitem; wewant (next) && nfrontp > next;	       next = nextitem(next))	    ;	  length = next - thisitem;	  memmove (good, thisitem, length);	  good += length;	  thisitem = next;	}      else	{	  thisitem = nextitem (thisitem);	}    }  nbackp = netobuf;  nfrontp = good;		/* next byte to be sent */  neturg = 0;}  /* end of netclear *//* *  netflush *		Send as much data as possible to the network, *	handling requests for urgent data. */voidnetflush (){  int n;    if ((n = nfrontp - nbackp) > 0)    {      NET_ENCRYPT ();      /*       * if no urgent data, or if the other side appears to be an       * old 4.2 client (and thus unable to survive TCP urgent data),       * write the entire buffer in non-OOB mode.       */      if (!neturg || !not42) 	n = write (net, nbackp, n);	/* normal write */      else	{	  n = neturg - nbackp;	  /*	   * In 4.2 (and 4.3) systems, there is some question about	   * what byte in a sendOOB operation is the "OOB" data.	   * To make ourselves compatible, we only send ONE byte	   * out of band, the one WE THINK should be OOB (though	   * we really have more the TCP philosophy of urgent data	   * rather than the Unix philosophy of OOB data).	   */	  if (n > 1) 	    n = send (net, nbackp, n-1, 0);	/* send URGENT all by itself */	  else 	    n = send (net, nbackp, n, MSG_OOB);	/* URGENT data */	}    }  if (n < 0)    {      if (errno == EWOULDBLOCK || errno == EINTR)	return;      cleanup (0);    }    nbackp += n;#ifdef	ENCRYPTION  if (nbackp > nclearto)    nclearto = 0;#endif	/* ENCRYPTION */  if (nbackp >= neturg)    neturg = 0;  if (nbackp == nfrontp)    {      nbackp = nfrontp = netobuf;

⌨️ 快捷键说明

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