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

代理服务器

开发平台:

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: wrap_udp.c,v 1.61.2.1.2.8 1998/11/11 23:28:39 wlu Exp $
  8.  */
  9. #include "socks5p.h"
  10. #include "buffer.h"
  11. #include "addr.h"
  12. #include "protocol.h"
  13. #include "wrap.h"
  14. #include "libproto.h"
  15. #include "hostname.h"
  16. #include "cache.h"
  17. #include "log.h"
  18. #include "msg.h"
  19. #define CODEABLE(x) ((x) && (x)->cinfo.auth.encode)
  20. #define AINFO(x)    ((x)->cinfo.auth)
  21. #define SETVERS(x, y)   ((x)[0] = (y))
  22. #define SETRESV(x, y)   memset(x, 0, 2)
  23. #define SETFRAG(x, y)   ((x)[2] = (y))
  24. /* implements the SOCKS_SEND protocol, sending a message to the server, and  */
  25. /* perhaps sometime down the road receiving an advisory deny-send message.   */
  26. /* adds the header (toport, toaddr, fragment info(if any)) to the message    */  
  27. /* message and sends it to the proxy                                         */
  28. /*                                                                           */
  29. /* C==>P  <resv(2)><frag(1)><atype(1)><host(4/v)><port(2)><data>             */
  30. /*                                                                           */
  31. /* returns the number of bytes sent on success; -1 on failure                */
  32. static IORETTYPE lsProtoSend(S5IOHandle fd, lsProxyInfo *pri, const IOPTRTYPE msg, IOLENTYPE len, int flags, const ss *dest, int dstlen) {
  33.     char hostname[S5_HOSTNAME_SIZE], header[UDP_MAX_PAYLOAD];
  34.     int headerlen, rval, nlen;
  35.     S5NetAddr name;
  36.     S5Packet buf[2];
  37.     
  38.     memset(&name, 0, sizeof(S5NetAddr));
  39.     if (!lsGetCachedHostname((S5NetAddr *)dest, hostname, sizeof(hostname))) {
  40. name.sa.sa_family = AF_S5NAME;
  41. name.sn.sn_port   = lsAddr2Port((S5NetAddr *)dest);
  42. strcpy(name.sn.sn_name, hostname);
  43.     } else {
  44. lsAddrCopy(&name, (S5NetAddr *)dest, dstlen);
  45.     }
  46.     SETVERS(header, 0);
  47.     SETRESV(header, 0);                                 /* unused - reserved */
  48.     SETFRAG(header, 0);                                 /* unused - fragment */
  49.     lsSetProtoAddr(SOCKS5_VERSION, header, &name);
  50.     
  51.     if ((nlen = len + (headerlen = HDRSIZE(header))) > UDP_MAX_PAYLOAD) {
  52. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS sendto: Message too big for encapsulation...");
  53. SETSOCKETERROR(EMSGSIZE);
  54. return -1;
  55.     }
  56.     memcpy(header + headerlen, (char *)msg, len);
  57.     if (CODEABLE(pri)) {
  58. buf[0].data = header;
  59. buf[0].len  = nlen;
  60. buf[1].data = NULL;
  61. buf[1].len  = 0;
  62. if (AINFO(pri).encode(&buf[0], &buf[1], S5_ENCODE, AINFO(pri).context) < nlen) {
  63.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS sendto: Encode failed...");
  64.     SETSOCKETERROR(EFAULT);
  65.     return -1;
  66. }
  67. /* If the buffer was too big, bail.  Otherwise, copy it...           */
  68. if ((nlen = buf[1].len) > UDP_MAX_PAYLOAD) {
  69.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS sendto: Encoded Message too big for encapsulation...");
  70.     SETSOCKETERROR(EMSGSIZE);
  71.     return -1;
  72. }
  73. memcpy(header, buf[1].data, buf[1].len);
  74. free(buf[1].data);
  75. nlen = buf[1].len;
  76.     }
  77.     
  78.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS sendto: Sent %d byte msg to proxy %s:%d...", nlen, ADDRANDPORT(&pri->prxyin));
  79.     rval = REAL(sendto)(fd, header, nlen, flags, (ss *)&pri->prxyin, sizeof(ssi));
  80.     return (rval == nlen)?len:-1;
  81. }
  82. /* extracts the header info from msg and fills in the appropriate fields...  */
  83. /* returns 0 on success and -1 on failure...                                 */
  84. static int lsUdpExtractHeader(char *msg, int n, int *headerlen, ss *from, int fromlen) {
  85.     S5NetAddr netaddr;
  86.     
  87.     /* Here we make sure that we really go a valid message...                */
  88.     if (n < (*headerlen = HDRSIZE(msg))) {
  89. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS recvfrom: invalid message");
  90. return -1;
  91.     } 
  92.     /* Extract the address from the header, and mark how long the header was */
  93.     if (lsGetProtoAddr(SOCKS5_VERSION, msg, &netaddr) < 0) {
  94. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS recvfrom: invalid message");
  95. return -1;
  96.     }
  97.     /* If the result came back as a name, we sent it as a name, so we can    */
  98.     /* just call gethostbyname on the name to find out what address we faked */
  99.     /* it as...                                                              */
  100.     switch (netaddr.sa.sa_family) {
  101. case AF_S5NAME:
  102.     lsGetCachedAddress(netaddr.sn.sn_name, (S5NetAddr *)from);
  103.     lsAddrSetPort((S5NetAddr *)from, netaddr.sn.sn_port);
  104.     break;
  105. default:
  106.     lsAddrCopy((S5NetAddr *)from, &netaddr, fromlen);
  107.     break;
  108.     }
  109.     
  110.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS recvfrom: %s:%d", ADDRANDPORT((S5NetAddr *)from));
  111.     return 0;
  112. }
  113. /* wrapper around the connect system call.                                   */
  114. int lsUdpConnect(S5IOHandle sd, CONST ss *name, int namelen) {
  115.     lsSocksInfo *pcon = lsConnectionFind(sd);
  116.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsUdpConnect: fd %d", sd);
  117.     /* if they were just trying to delete the current connection, do it.     */
  118.     if (name == NULL) {
  119. if (pcon) lsConnectionDel(sd);
  120. return 0;
  121.     }
  122.     /* If we think this isn't a udp socket, check to see if it's still ok.   */
  123.     /* If it is, return EISCONN as errno, otherwise delete it -- invalid.    */
  124.     if (pcon) {
  125. if (pcon->cmd != SOCKS_UDP) {
  126.     if (S5IOCheck(pcon->fd) >= 0) {
  127. SETSOCKETERROR(EISCONN);
  128. return -1;
  129.     }
  130.     lsConnectionDel(sd);
  131.     pcon = NULL;
  132. }
  133. /* If we're already talking to the right person, we're done...       */
  134. if (pcon && ADDRCOMP((ssi *)name, &pcon->peer.sin)) return 0;
  135.     }
  136.     /* Make a connection since one didn't exit... or qthe address was wrong   */
  137.     if ((pcon = lsLibProtoExchg(sd, (S5NetAddr *)name, SOCKS_UDP)) == NULL) {
  138. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsUdpConnect: Protocol exchange failed");
  139. return -1;
  140.     }
  141.     pcon->status = CON_ESTABLISHED;
  142.     if (!pcon->cur || pcon->cur->how == DIRECT) return REAL(connect)(sd, (ss *)name, namelen);
  143.     return 0;
  144. }
  145. static int proxy_bind(S5IOHandle sd, const S5NetAddr *dst) {
  146.     lsSocksInfo *pcon;
  147.     lsProxyInfo *pri;
  148.     S5NetAddr na;
  149.     int rval = 0;
  150.     /* First establish the UDP session. Then exchange UDP_BIND sub-command    */
  151.     /* If the server doesn't support UDP sub-command, do the DISCARDHACK...   */
  152.     lsAddrCopy(&na, dst, lsAddrSize(dst));
  153.     if ((pcon = lsLibProtoExchg(sd, &na, SOCKS_UDP)) == NULL) {
  154. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "proxy_bind: Protocol exchange failed");
  155. return -1;
  156.     }
  157.     if ((pri = pcon->cur) != NULL && pri->how != DIRECT) {
  158. if (pri->reserved & S5UDP_USECTRL) {
  159.     if (pcon->myport != (u_short)0) lsAddrSetPort(&na, pcon->myport);
  160.     rval = lsLibExchgUdpCmd(pcon, &na, S5UDP_BIND);
  161. } else { /* DISCARDHACK                                                 */
  162.     char msg = '';
  163.     lsAddrSetPort(&na, 9);
  164.             rval = lsProtoSend(pcon->fd, pri, &msg, 1, 0, &na.sa, lsAddrSize(&na));
  165. }
  166.     }
  167.     if (rval < 0) {
  168. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "proxy_bind: UDP bind failed");
  169.         return -1;
  170.     }
  171.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "proxy_bind: Done");
  172.     return 0;
  173. }
  174. int lsUdpBind(S5IOHandle sd, CONST ss *name, int namelen) {
  175.     lsSocksInfo *pcon;
  176.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsUdpBind: fd %d", sd);
  177.     /* keep a record of binded socket for future use                          */
  178.     pcon = lsLibProtoExchg(sd, NULL, SOCKS_UDP);
  179.     /* More checking is needed, such as connected UDP socket, etc...          */
  180.     if (!lsLastCon || !lsLastCon->pri || lsLastCon->pri->how != SOCKS5_VERSION) {
  181. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsUdpBind: No prior connection found, binding locally");
  182. return REAL(bind)(sd, (ss *)name, namelen);
  183.     }
  184.     if (((ssi *)name)->sin_port != (u_short)0) {
  185. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsUdpBind: bind local to %d", (int)((ssi *)name)->sin_port);
  186.      if (REAL(bind)(sd, (ss *)name, namelen) < 0) return -1;
  187.     }
  188.     if (proxy_bind(sd, &lsLastCon->peer) < 0) {
  189. if (pcon && pcon->pri) lsProxyCacheDel(pcon, pcon->pri);
  190. return -1;
  191.     }
  192.     pcon->status = CON_BOUND;
  193.     return 0;
  194. }
  195. /* wrapper around the send system call.                                      */
  196. IORETTYPE lsUdpSend(S5IOHandle sd, const IOPTRTYPE msg, IOLENTYPE len, int flags) {
  197.     lsSocksInfo *pcon = lsConnectionFind(sd);
  198.     S5NetAddr junk;
  199.     /* If we can't find a valid connection, for whatever reason, return a    */
  200.     /* direct send...                                                        */
  201.     if (!pcon || (pcon->status != CON_ESTABLISHED && pcon->status != CON_ESTABLISHEDSEND)) {
  202. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsUdpSend: No valid connection found, returning direct send");
  203. return REAL(send)(sd, msg, len, flags);
  204.     }
  205.     junk = pcon->peer;
  206.     
  207.     /* PROXY, see if the control connection is still there; if not reconnect */
  208.     if ((pcon = lsLibProtoExchg(sd, &junk, SOCKS_UDP)) == NULL) {
  209. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsUdpSend: Protocol exchange failed");
  210. return -1;
  211.     }
  212.     pcon->status = CON_ESTABLISHEDSEND;
  213.     if (!pcon->cur || pcon->cur->how == DIRECT) return REAL(send)(sd, msg, len, flags);
  214.     return lsProtoSend(sd, pcon->cur, msg, len, flags, &pcon->peer.sa, lsAddrSize(&pcon->peer));
  215. }
  216. /* wrapper around the sendto system call.                                    */
  217. IORETTYPE lsUdpSendto(S5IOHandle s, const IOPTRTYPE msg, IOLENTYPE len, int flags, ss *to, int tolen) {
  218.     lsSocksInfo *pcon = lsConnectionFind(s);
  219.     u_char bs = CON_NOTESTABLISHED;
  220.     S5NetAddr bp;
  221.     int rval;
  222.     /* Apparently some OSs allow a NULL address to mean send.                */
  223.     /* Unfortunately, this may get us caught in a loop, where lsUdpSendto    */
  224.     /* calls lsUdpSend which calls sendto which calls lsUdpSendto... So we   */
  225.     /* have all this DontLoop code to protect against that...                */
  226.     if (to == NULL) return lsUdpSend(s, msg, len, flags);
  227.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKSsendto %s:%d...", ADDRANDPORT((S5NetAddr *)to));
  228.     
  229.     /* only ok to sendto() the person we're connected to...                  */
  230.     if (pcon && (pcon->status == CON_ESTABLISHED || pcon->status == CON_ESTABLISHEDSEND)) {
  231. if (!ADDRCOMP((ssi *)to, &pcon->peer.sin)) {
  232.     memset(&bp, 0 , sizeof(S5NetAddr));
  233.     lsAddrCopy(&bp, &pcon->peer, lsAddrSize(&pcon->peer));
  234.     bs = pcon->status;
  235.      } else return lsUdpSend(s, msg, len, flags);
  236.     }
  237.     /* No udp association for this socket, so send directly                  */
  238.     if ((pcon = lsLibProtoExchg(s, (S5NetAddr *)to, SOCKS_UDP)) == NULL) {
  239. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsUdpSendto: Protocol exchange failed");
  240. return -1;
  241.     }
  242.     /* Don't send a message using the wrong protocol...                      */
  243.     if (!pcon->cur || pcon->cur->how != SOCKS5_VERSION) {
  244. rval = REAL(sendto)(s, msg, len, flags, to, tolen);
  245.     } else {
  246. rval = lsProtoSend(s, pcon->cur, msg, len, flags, to, tolen);
  247.     }
  248.     if (bs != CON_NOTESTABLISHED) {
  249.         pcon->status = bs;
  250.         lsAddrCopy(&pcon->peer, &bp, lsAddrSize(&bp));
  251.     } else if (pcon) pcon->status = CON_SENDTO;
  252.     return rval;
  253. }
  254. /* wrapper around the recvfrom system call.                                  */
  255. IORETTYPE lsUdpRecvfrom(S5IOHandle s, IOPTRTYPE msg, IOLENTYPE len, int flags, ss *from, int *fromlen, int isRecv) {
  256.     lsSocksInfo *pcon = lsConnectionFind(s);
  257.     char recvbuf[UDP_MAX_PAYLOAD+1], *obuf = NULL;
  258.     int olen = 0, oset, fl = sizeof(ssi);
  259.     lsProxyInfo *pri;
  260.     ssi tmp;
  261.     S5Packet buf[2];
  262.     
  263.     if (!isRecv) {
  264. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKSrecvfrom...");
  265.     } else {
  266. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKSrecv...");
  267.     }
  268.     if (!from) {
  269. from = (ss *)&tmp;
  270. fromlen = &fl;
  271.     }
  272.     if (!pcon || pcon->cmd != SOCKS_UDP) {
  273. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "No valid connection found, returning direct recvfrom");
  274. if (isRecv) return REAL(recv)(s, msg, len, flags);
  275. return REAL(recvfrom)(s, msg, len, flags, from, fromlen);
  276.     }
  277.     /* Do we need to check whether the socket has sent a message or binded   */
  278.     /* remotely? We might need to do a remote bind here if neither is true.. */
  279.     /*                                                                       */
  280.     /* If it is locally binded and remote tcp connection is available, do a  */
  281.     /* remote bind.                                                          */
  282.     if (pcon->status == CON_NOTESTABLISHED) {
  283. if (lsLastCon != NULL) proxy_bind(s, &lsLastCon->peer);
  284. pcon->status = CON_RECV;
  285.     }
  286.     obuf = recvbuf;
  287.     oset = 0;
  288.     /* get a new message                                                     */
  289.     if ((olen = REAL(recvfrom)(s, recvbuf, UDP_MAX_PAYLOAD, flags, from, fromlen)) < 0) {
  290. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "recvfrom failed: %m");
  291. return -1;
  292.     }
  293.     /* verify the contents as being from the right person                    */
  294.     if (!(pri = lsProxyCacheFind(pcon, (S5NetAddr *)from, SOCKS5_VERSION, 1)) || pri->how != SOCKS5_VERSION) {
  295. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Direct recvfrom (%x;%d)", pri, pri?pri->how:0);
  296. goto done;
  297.     }
  298.     /* verify if the server is alive. If not, discard the packet and         */
  299.     /* and delete the proxy cache....                                        */
  300.     if (S5IOCheck(pri->cinfo.fd) < 0) {
  301. lsProxyCacheDel(pcon, pri);
  302. return -1;
  303.     }
  304.     if (!ADDRCOMP(&pri->prxyin.sin, (ssi *)from)) {
  305. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Recv from wrong host");
  306. return -1;
  307.     }
  308.     if (CODEABLE(pri)) {
  309. buf[0].data = recvbuf;
  310. buf[0].len  = olen;
  311. buf[0].off  = olen;
  312. buf[1].data = NULL;
  313. buf[1].len  = 0;
  314. buf[1].off  = 0;
  315. if (AINFO(pri).encode(&buf[0], &buf[1], S5_DECODE, AINFO(pri).context) < 0) {
  316.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Decoding failed");
  317.     return -1;
  318. }
  319. obuf = buf[1].data;
  320. olen = buf[1].len;
  321.     }
  322.     if (lsUdpExtractHeader(obuf, olen, &oset, from, *fromlen) != 0) {
  323. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Header extraction failed");
  324. if (obuf && obuf != recvbuf) free(obuf);
  325. return -1;
  326.     }
  327.   done:
  328.     if (*fromlen > sizeof(ssi)) *fromlen = sizeof(ssi);
  329.     memcpy((char *)msg, obuf + oset, olen = MIN((int)len, olen - oset));
  330.     if (obuf && obuf != recvbuf) free(obuf);
  331.     return olen;
  332. }
  333. /* wrapper around the getpeername system call.                               */
  334. /* returns 0 on success; -1 on failure                                       */
  335. int lsUdpGetpeername(S5IOHandle sd, ss *name, int *namelen) {
  336.     lsSocksInfo *pcon = lsConnectionFind(sd);
  337.     if (!pcon || pcon->cmd != SOCKS_UDP || (pcon->status != CON_ESTABLISHED && pcon->status != CON_ESTABLISHEDSEND)) 
  338. return REAL(getpeername)(sd, name, namelen);
  339.     if (name) {
  340. *namelen = MIN(*namelen, lsAddrSize(&pcon->peer));
  341.         lsAddrCopy((S5NetAddr *)name, &pcon->peer, *namelen);
  342.     }
  343.     return 0;
  344. }
  345. /* wrapper around the getpeername system call.                               */
  346. /* returns 0 on success; -1 on failure                                       */
  347. int lsUdpGetsockname(S5IOHandle sd, ss *name, int *namelen) {
  348.     int rval;
  349.     S5NetAddr junk;
  350.     lsProxyInfo *pri;
  351.     lsSocksInfo *pcon = lsConnectionFind(sd);
  352.     rval = REAL(getsockname)(sd, name, namelen);
  353.     if (!pcon || pcon->cmd != SOCKS_UDP || !lsAddrIsNull(&pcon->peer) || rval < 0) return rval;
  354.     junk = pcon->peer;
  355.     pcon = lsLibProtoExchg(sd, &junk, SOCKS_UDP);
  356.     if (!pcon || !(pri = pcon->cur) || !(pri->reserved & S5UDP_USECTRL)) return rval;
  357.     if (lsAddr2Port(&pri->prxyout) == (u_short)0 && lsLibExchgUdpCmd(pcon, &junk, S5UDP_GETSOCKNAME) < 0) return -1;
  358.     ((ssi *)name)->sin_addr.s_addr = INADDR_ANY;
  359.     lsAddrSetPort((S5NetAddr *)name, lsAddr2Port(&pri->prxyout));
  360.     if (*namelen > sizeof(ssi)) *namelen = sizeof(ssi);
  361.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsUdpGetSockname: %s:%d", ADDRANDPORT((S5NetAddr *)name));
  362.     return 0;
  363. }
  364. #ifdef HAVE_SENDMSG
  365. IORETTYPE
  366. lsUdpSendmsg(S5IOHandle s, ms *msg, int flags)
  367. {
  368. ss *to;
  369. int tolen, i, len=0;
  370. char *buf;
  371. S5NetAddr dst;
  372. lsSocksInfo *pcon = lsConnectionFind(s);
  373.  
  374.     memset(&dst, 0 , sizeof(S5NetAddr));
  375.  
  376.     to = (struct sockaddr *) msg->msg_name;
  377.     tolen = sizeof((struct sockaddr *) msg->msg_name);
  378.  
  379.     for(i=0; i<msg->msg_iovlen; i++)
  380.      len += msg->msg_iov[i].iov_len;
  381.  
  382.     buf = (char *) malloc(len);
  383.     for(i=0; i<msg->msg_iovlen; i++) {
  384.      memcpy(buf, msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len);
  385.      buf = buf + msg->msg_iov[i].iov_len;
  386.     }
  387.     buf = buf - len;
  388.  
  389.     if(!to)
  390.      return lsUdpSend(s, buf, len, flags);
  391.     else
  392.      lsAddrCopy(&dst, (S5NetAddr *)to, lsAddrSize((S5NetAddr *)to));
  393.  
  394.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0,"SOCKSsendmsg %s:%d..",
  395.                 ADDRANDPORT(&dst));
  396.     /* only ok to sendmsg() the person we're connected to.   */
  397.  
  398.     if(pcon&&(pcon->status == CON_ESTABLISHED || 
  399.              pcon->status == CON_ESTABLISHEDSEND)) {
  400.      if(!ADDRCOMP((ssi *)to, &pcon->peer.sin)) {
  401.       SETSOCKETERROR(EISCONN);
  402.       return -1;
  403.      }
  404.      else
  405.       return lsUdpSend(s, buf, len, flags);
  406.     }
  407.  
  408.     /* No udp association for this socket, so send directly     */
  409.  
  410.     if((pcon = lsLibProtoExchg(s, &dst, SOCKS_UDP)) == NULL) {
  411.      S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0,
  412.                     "lsUdpSendmsg: Protocol exchange failed");
  413.      SETSOCKETERROR(EBADF);
  414.      return -1;
  415.     }
  416.    
  417.     pcon->status = CON_SENDTO;
  418.  
  419.     /* Don't send a message using the wrong protocol...         */
  420.  
  421.     if(!pcon->cur || pcon->cur->how != SOCKS5_VERSION)
  422.      return REAL(sendmsg)(s, msg, flags);
  423.  
  424.  
  425.     /* Send the message directly...                      */
  426.     return lsProtoSend(s, pcon->cur, (u_char *)buf, len, flags, to, tolen);
  427. }
  428. IORETTYPE
  429. lsUdpRecvmsg(S5IOHandle s, ms *msg, int flags)
  430. {
  431. u_char recvbuf[UDP_MAX_PAYLOAD+1], *obuf = NULL;
  432. int olen = 0, oset, fl = sizeof(ssi);
  433. lsProxyInfo *pri;
  434. ss          *from;
  435. int         fromlen;
  436. int         len=0;
  437. int         i;
  438. ssi tmp;
  439. lsSocksInfo *pcon = lsConnectionFind(s);
  440.  
  441.  
  442.  
  443.     S5Packet buf[2];
  444.    
  445.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKSrecvmsg...");
  446.  
  447.     from = (struct sockaddr *) msg->msg_name;
  448.     fromlen = sizeof((struct sockaddr *) msg->msg_name);
  449.     for(i=0; i<msg->msg_iovlen; i++)
  450.      len += msg->msg_iov[i].iov_len;
  451.  
  452.  
  453.     if(!from) {
  454.      from = (ss *)&tmp;
  455.      fromlen = fl;
  456.     }
  457.  
  458.     if(!pcon || pcon->cmd != SOCKS_UDP) {
  459.      S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0,
  460.                 "No valid connection found, returning direct recvmsg");
  461.      return REAL(recvmsg)(s, msg, flags);
  462.     }
  463.  
  464. /* Do we need to check whether the socket has sent a message or bound    */
  465. /* remotely? We might need to do a remote bind here if neither is true.. */
  466. /*                                                                       */
  467. /* If it is locally bound and remote tcp connection is available, do a  */
  468. /* remote bind.                                                         */
  469.  
  470.     if(pcon->status == CON_NOTESTABLISHED) {
  471.      if(lsLastCon != NULL && proxy_bind(s, &lsLastCon->peer) < 0)
  472.       return -1;
  473.      pcon->status = CON_RECV;
  474.     }
  475.  
  476.     for(oset = 0, obuf = recvbuf;; oset = 0, obuf = recvbuf) {
  477.      if(olen != 0 && (flags & MSG_PEEK)) {
  478.       S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0,"Purging old message");
  479.       REAL(recvmsg)(s, msg, flags&~MSG_PEEK);
  480.      }
  481.  
  482. /* get a new message    */
  483.  
  484.      if((olen = REAL(recvmsg)(s, msg, flags )) < 0) {
  485.       S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10),0,"recvmsg failed: %m");
  486.       return -1;
  487.      }
  488.  
  489.     /* verify the contents as being from the right person */
  490.      if((pri = (lsProxyCacheFind(pcon, (S5NetAddr *)from,SOCKS5_VERSION, 1))) == NULL || 
  491. pri->how != SOCKS5_VERSION) {
  492.       S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Direct recvmsg (%x;%d)", pri, pri?pri->how:0);
  493.       goto done;
  494.      }
  495.  
  496.     /* verify if the server is alive. If not, discard the packet and     */
  497.     /* and delete the proxy cache....                                    */
  498.  
  499.      if(S5IOCheck(pri->cinfo.fd) < 0) {
  500.       lsProxyCacheDel(pcon, pri);
  501.       continue;
  502.      }
  503.  
  504.      if(!ADDRCOMP(&pri->prxyin.sin, (ssi *)from)) {
  505.       S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0,"Recvmsg from wrong host");
  506.       continue;
  507.      }
  508.  
  509.      if(CODEABLE(pri)) {
  510.       buf[0].data = recvbuf;
  511.       buf[0].len  = olen;
  512.       buf[0].off  = olen;
  513.       buf[1].data = NULL;
  514.       buf[1].len  = 0;
  515.       buf[1].off  = 0;
  516.       if(AINFO(pri).encode(&buf[0],&buf[1],S5_DECODE,AINFO(pri).context) < 0) {
  517.        S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Decoding failed");
  518.        continue;
  519.       }
  520.  
  521.       obuf = buf[1].data;
  522.       olen = buf[1].len;
  523.      }
  524.  
  525.      if(lsUdpExtractHeader(obuf, olen, &oset, from, fromlen) != 0) {
  526.       S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0,"Header extraction failed");
  527.       if(obuf != recvbuf)
  528.        free(obuf);
  529.       continue;
  530.      }
  531.  
  532.      if((pcon->status == CON_ESTABLISHED || pcon->status == CON_ESTABLISHEDSEND)) {
  533.       if (!ADDRCOMP(&pcon->peer.sin, (ssi *)from)) {
  534.        S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0,"Recvmsg from wrong host");
  535.        if(obuf != recvbuf)
  536.         free(obuf);
  537.        continue;
  538.       }         /* if (!ADDRCOMP(&pcon->peer.sin, (ssi *)from)) */
  539.      }          /* if(isRecv && (pcon->status == CON_ESTABLISHED....*/
  540.  
  541.     done:
  542.      if(fromlen > sizeof(ssi))
  543.       fromlen = sizeof(ssi);
  544.  
  545.      memcpy((u_char *)msg, obuf + oset, olen = MIN((int)len, olen - oset));
  546.      if(obuf != recvbuf)
  547.       free(obuf);
  548.      return olen;
  549.     }                   /* for(oset = 0, obuf = recvbuf;;   ...) */
  550. }
  551. #endif   /* HAVE_SENDMSG */