tracer.c
上传用户:sddyfurun
上传日期:2007-01-04
资源大小:525k
文件大小:11k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /* Copyright (c) 1995,1996,1997 NEC Corporation.  All rights reserved.       */
  2. /*                                                                           */
  3. /* The redistribution, use and modification in source or binary forms of     */
  4. /* this software is subject to the conditions set forth in the copyright     */
  5. /* document ("Copyright") included with this distribution.                   */
  6. /*
  7.  * $Id: tracer.c,v 1.40.4.3 1998/11/04 00:03:40 steve Exp $
  8.  */
  9. #include "socks5p.h"
  10. #include "daemon.h"
  11. #include "protocol.h"
  12. #include "validate.h"
  13. #include "sident.h"
  14. #include "msgids.h"
  15. #include "flow.h"
  16. #include "info.h"
  17. #include "log.h"
  18. #include "msg.h"
  19. #include "s2s.h"
  20. struct ptinfo {
  21.     S5IOInfo iio, oio, pio;
  22.     int stopchild, childpid, exitval, msgsent;
  23.     char tmpmsg[GENERICBUFSIZE], idtentry[IDTENTRY_SIZE];
  24.     char *packetbuf;
  25. };
  26. typedef struct ptinfo PTInfo;
  27. #define CommandName(x) (((x)->peerCommand == SOCKS_PING)?"PING":"Traceroute")
  28. #ifndef REPLYTIMEOUT
  29. #define REPLYTIMEOUT 60
  30. #endif
  31. static int Popen(S5LinkInfo *pri, PTInfo *ptinfo) {
  32.     S5IOHandle pds[2];
  33. #ifndef TROUTEPROG
  34.     if (pri->peerCommand == SOCKS_TRACER) {
  35. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "%s: No real program to exec", CommandName(pri));
  36. return -1;
  37.     }
  38. #endif
  39. #ifndef PINGPROG
  40.     if (pri->peerCommand != SOCKS_TRACER) {
  41. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "%s: No real program to exec", CommandName(pri));
  42. return -1;
  43.     }
  44. #endif
  45.     if (pipe(pds) < 0) {
  46. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "%s pipe failed: %m", CommandName(pri));
  47. return -1;
  48.     }
  49.     if ((ptinfo->childpid = fork()) < 0) {
  50. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "%s fork failed: %m", CommandName(pri));
  51. close(pds[0]);
  52. close(pds[1]);
  53. return -1;
  54.     }
  55.     S5BufSetupContext(&ptinfo->pio);
  56.     ptinfo->pio.fd        = pds[0];
  57.     if (ptinfo->childpid == 0) {
  58. close(pds[0]);
  59. if (dup2(pds[1], STDOUT_FILENO) < 0) _exit(-1);
  60. if (dup2(pds[1], STDERR_FILENO) < 0) _exit(-1);
  61. close(pds[1]);
  62. #ifdef TROUTEPROG
  63. if ((pri->peerCommand == SOCKS_TRACER)) {
  64.     int verbose = pri->peerReserved & SOCKS5_FLAG_VERBOSE;
  65.     int noname  = pri->peerReserved & SOCKS5_FLAG_NONAME;
  66.     
  67.     if (pri->nextVersion) {
  68.      if (noname) execlp(TROUTEPROG, "traceroute", "-n", (verbose?"-v":pri->sckName), verbose?pri->sckName:NULL, NULL);
  69.      else        execlp(TROUTEPROG, "traceroute",       (verbose?"-v":pri->sckName), verbose?pri->sckName:NULL, NULL);
  70.     } else {
  71.      if (noname) execlp(TROUTEPROG, "traceroute", "-n", (verbose?"-v":pri->dstName), verbose?pri->dstName:NULL, NULL);
  72.      else        execlp(TROUTEPROG, "traceroute",       (verbose?"-v":pri->dstName), verbose?pri->dstName:NULL, NULL);
  73.     }
  74. #endif
  75. #ifdef PINGPROG
  76. if (!(pri->peerCommand == SOCKS_TRACER)) {
  77.     execlp(PINGPROG, "ping", pri->dstName, NULL);
  78. }     
  79. #endif
  80. _exit(0);
  81.     }
  82.     ptinfo->stopchild  = 1;
  83.     close(pds[1]);
  84.     return 0;
  85. }
  86. static int InitProxy(S5LinkInfo *pri, PTInfo *ptinfo) {
  87.     S5NetAddr junk;
  88.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "%s Using proxy (version %d) %s:%d", CommandName(pri), (int)pri->nextVersion, ADDRANDPORT(&pri->sckAddr));
  89.     if ((ptinfo->oio.fd = socket(AF_INET, SOCK_STREAM, 0)) == S5InvalidIOHandle) {
  90. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "%s socket failed: %m", CommandName(pri));
  91. return -1;
  92.     }
  93.     if (S5SExchangeProtocol(&ptinfo->iio, &ptinfo->oio, pri, ptinfo->idtentry, &pri->dstAddr, &junk) == 0) {
  94. return 0;
  95.     }
  96.     CLOSESOCKET(ptinfo->oio.fd);
  97.     ptinfo->oio.fd = S5InvalidIOHandle;
  98.     return -1;
  99. }
  100. static void WaitChild(PTInfo *coption) {
  101.     int wstatus;
  102.     if (!coption->stopchild) return;
  103. #ifdef HAVE_WAITPID
  104.     waitpid(coption->childpid, &wstatus, 0);
  105. #else
  106.     wait4(coption->childpid, &wstatus, 0, NULL);
  107. #endif
  108.     close(coption->pio.fd);
  109.     coption->pio.fd    = S5InvalidIOHandle;
  110.     coption->stopchild = 0;
  111.     coption->childpid  = 0;
  112. }    
  113. static int PTRecvPkt(S5Packet *packet, S5LinkInfo *pri, PTInfo *coption, int *dir) {
  114.     int rv = EXIT_ERR, savedir;
  115.     if (!coption) {
  116. return EXIT_ERR;
  117.     } else if (coption->pio.fd != S5InvalidIOHandle && !coption->msgsent) {
  118. packet->data = (char *)malloc(GENERICBUFSIZE * sizeof(char));
  119. packet->len  = GENERICBUFSIZE;
  120. packet->off  = 0;
  121. if (packet->data) {
  122.     strcpy(packet->data, coption->tmpmsg);
  123.     packet->off = rv = strlen(coption->tmpmsg);
  124.     *dir = S5_DIRECTION_IN;
  125.     coption->msgsent = 1;
  126. } else return EXIT_ERR;
  127.     } else {
  128. if (coption->pio.fd != S5InvalidIOHandle) {
  129.     for (;;) {
  130.         savedir = *dir;
  131.         rv = S5TcpFlowRecv(&coption->iio, &coption->pio, packet, dir);
  132.         if (rv == 0 && *dir == S5_DIRECTION_IN) {
  133.          /* The pipe is closed (command done) as just the first part   */
  134.          /* of a 2 part process by closing the pipe and go to the      */
  135.          /* second part to get dome "real" data...                     */
  136.          WaitChild(coption);
  137.          *dir = savedir;
  138.       if (pri->nextVersion) rv = S5TcpFlowRecv(&coption->iio, &coption->oio, packet, dir);
  139.         } else if (rv > 0 && *dir == S5_DIRECTION_OUT) {
  140.          /* If the client sends anything, it is a message to stop.     */
  141.          if (coption->stopchild) {
  142. kill(coption->childpid, SIGINT);
  143.           coption->stopchild = 0;
  144.     }
  145.          *dir = savedir;
  146.     packet->off = 0;
  147.     continue;
  148.         }
  149.         break;
  150.     }
  151. } else rv = S5TcpFlowRecv(&coption->iio, &coption->oio, packet, dir);
  152.     }
  153.     if (rv < 0) coption->exitval = EXIT_ERR;
  154.     else        coption->exitval = EXIT_OK;
  155.     if (packet->data) coption->packetbuf = packet->data;
  156.     return rv;
  157. }
  158. static int PTSendPkt(S5Packet *packet, S5LinkInfo *pri, PTInfo *coption, int *dir) {
  159.     int rv;
  160.     
  161.     if (!coption) return -1;
  162.     rv = S5TcpFlowSend(&coption->iio, &coption->oio, packet, dir);
  163.     
  164.     if (rv < 0) coption->exitval = EXIT_ERR;
  165.     else        coption->exitval = EXIT_OK;
  166.     
  167.     return rv;
  168. }
  169. static int PTClose(S5LinkInfo *linkinfo, PTInfo *coption) {
  170.     if (!coption) return -1;
  171.     
  172.     if (coption->childpid > 0 && coption->stopchild) {
  173.         kill(coption->childpid, SIGINT);
  174. WaitChild(coption);
  175.     }
  176.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, MSGID_SERVER_PT_END, "%s Proxy Terminated: %s (%s to %s) for user %s: %d bytes out, %d bytes in",
  177. CommandName(linkinfo), (coption->exitval == EXIT_ERR)?"Abnormal":"Normal",
  178. linkinfo->srcName, linkinfo->dstName, linkinfo->srcUser,
  179. linkinfo->outbc,    linkinfo->inbc);
  180.     
  181.     S5BufCleanContext(&coption->oio);
  182.     S5BufCleanContext(&coption->iio);
  183.     S5BufCleanContext(&coption->pio);
  184.     if (coption->packetbuf) free(coption->packetbuf);
  185.     RemoveIdentEntry(coption->idtentry);
  186.     free(coption);
  187.     return 0;
  188. }
  189. int PTSetup(S5IOInfo *ioinfo, S5LinkInfo *linkinfo, S5CommandInfo *cinfo) {
  190.     int turnon = 1, rval = EXIT_ERR;
  191.     PTInfo *ptinfo;
  192.     
  193.     if (ResolveNames(linkinfo) < 0) {
  194. goto cleanup;
  195.     }
  196.     if (!(cinfo->option = (void *)(ptinfo = (PTInfo *)malloc(sizeof(PTInfo))))) {
  197. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "%s malloc failed", CommandName(linkinfo));
  198. goto cleanup;
  199.     }
  200.     ptinfo->exitval       = EXIT_OK;
  201.     ptinfo->msgsent       = 0;
  202.     ptinfo->stopchild     = 0;
  203.     ptinfo->childpid      = 0;
  204.     ptinfo->iio           = *ioinfo;
  205.     ptinfo->packetbuf     = NULL;
  206.     InitIdentEntry(ptinfo->idtentry);
  207.     S5BufSetupContext(&ptinfo->oio);
  208.     S5BufSetupContext(&ptinfo->pio);
  209.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, MSGID_SERVER_PT_START, "%s Proxy Request: (%s to %s) for user %s",
  210.     CommandName(linkinfo), linkinfo->srcName, linkinfo->dstName, linkinfo->srcUser);
  211.     if (Authorize(linkinfo, 0) != AUTH_OK) {
  212. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, MSGID_SERVER_PT_AUTH, "%s Authorization failed", CommandName(linkinfo));
  213. rval = EXIT_AUTH;
  214. goto cleanup;
  215.     }
  216.     
  217.     if (linkinfo->nextVersion && InitProxy(linkinfo, ptinfo) < 0) {
  218. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "%s Init Proxy Failed", CommandName(linkinfo));
  219. goto cleanup;
  220.     }
  221.     if (linkinfo->peerCommand == SOCKS_TRACER) {
  222. sprintf(ptinfo->tmpmsg, "nTraceroute to %s...n", linkinfo->nextVersion?linkinfo->sckName:linkinfo->dstName);
  223.     } else {
  224. ptinfo->msgsent = 1;
  225.     }
  226.     if (!linkinfo->nextVersion || linkinfo->peerCommand == SOCKS_TRACER) {
  227. if (Popen(linkinfo, ptinfo) < 0) {
  228.     if (!linkinfo->nextVersion) {
  229. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "%s Failed to open pipe for real command", CommandName(linkinfo));
  230. goto cleanup;
  231.     }
  232.     if (linkinfo->peerCommand == SOCKS_TRACER) {
  233. strcat(ptinfo->tmpmsg, "Traceroute not available on this hostn");
  234.     }
  235. }
  236.     }
  237.     /* Set out of band data inline, since we won't be dealing with it....    */
  238.     if (setsockopt(ptinfo->iio.fd, SOL_SOCKET, SO_OOBINLINE, (char *)&turnon, sizeof(int)) < 0) {
  239. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "%s Setup: Failed to inline out-of-band data: %m", CommandName(linkinfo));
  240. rval = EXIT_NETERR;
  241. goto cleanup;
  242.     }
  243.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, MSGID_SERVER_PT_ESTAB, "%s Proxy Established: (%s to %s) for user %s",
  244.     CommandName(linkinfo), linkinfo->srcName, linkinfo->dstName, linkinfo->srcUser);
  245.     if (lsSendResponse(ptinfo->iio.fd, &ptinfo->iio, &linkinfo->dstAddr, linkinfo->peerVersion, 0, 0, NULL) < 0) {
  246. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Client closed connection");
  247. rval = EXIT_NETERR;
  248. goto cleanup;
  249.     }
  250.     recv_sigio(ioinfo->fd);
  251.     cinfo->recvpkt = (int (*)(S5Packet *, S5LinkInfo *, void *, int *))PTRecvPkt;
  252.     cinfo->sendpkt = (int (*)(S5Packet *, S5LinkInfo *, void *, int *))PTSendPkt;
  253.     cinfo->clean   = (int (*)(S5LinkInfo *, void *))PTClose;
  254.     return EXIT_OK;
  255.   cleanup:
  256.     if (rval != EXIT_NETERR) lsSendResponse(ioinfo->fd, ioinfo, &linkinfo->dstAddr, linkinfo->peerVersion, 1, 0, NULL);
  257.     if (ptinfo != NULL) {
  258. ptinfo->exitval = EXIT_ERR;
  259.      PTClose(linkinfo, ptinfo);
  260.     } else {
  261.      S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, MSGID_SERVER_PT_END, "%s Proxy Terminated: %s (%s to %s) for user %s: %d bytes out, %d bytes in",
  262.          CommandName(linkinfo), "Abnormal",
  263.          linkinfo->srcName, linkinfo->dstName, linkinfo->srcUser,
  264.          linkinfo->outbc,    linkinfo->inbc);
  265.      S5BufCleanContext(ioinfo);
  266.     }
  267.     cinfo->option = NULL;
  268.     if (rval == EXIT_OK) rval = EXIT_ERR;
  269.     return rval;
  270. }