예제 #1
0
/* returns 0 if it could create lock; 1 if the lock exists; -1 on error */
int xiogetlock(const char *lockfile) {
   char *s;
   struct stat strat;
   int fd;
   pid_t pid;
   char pidbuf[3*sizeof(pid_t)+1];
   size_t bytes;

   if (Lstat(lockfile, &strat) == 0) {
      return 1;
   }
   switch (errno) {
   case ENOENT: break;
   default:
      Error3("Lstat(\"%s\", %p): %s", lockfile, &strat, strerror(errno));
      return -1;
   }
   /* in this moment, the file did not exist */

   if ((s = Malloc(strlen(lockfile)+8)) == NULL) {
      errno = ENOMEM;
      return -1;
   }
   strcpy(s, lockfile);
   strcat(s, ".XXXXXX");

   if ((fd = Mkstemp(s)) < 0) {
      Error2("mkstemp(\"%s\"): %s", s, strerror(errno));
      return -1;
   }
  
   pid = Getpid();
   bytes = sprintf(pidbuf, F_pid, pid);
   if (writefull(fd, pidbuf, bytes) < 0) {
      Error4("write(%d, %p, "F_Zu"): %s", fd, pidbuf, bytes, strerror(errno));
      return -1;
   }
   Close(fd);

   /* Chmod(lockfile, 0600); */
   if (Link(s, lockfile) < 0) {
      int _errno = errno;
      Error3("link(\"%s\", \"%s\"): %s", s, lockfile, strerror(errno));
      Unlink(s);
      errno = _errno;
      return -1;
   }
   Unlink(s);

   return 0;
}
예제 #2
0
파일: xio-socks.c 프로젝트: michas2/socat
/* perform socks4 client dialog on existing FD.
   Called within fork/retry loop, after connect() */
int _xioopen_socks4_connect(struct single *xfd,
                            struct socks4 *sockhead,
                            size_t headlen,
                            int level) {
    ssize_t bytes;
    int result;
    unsigned char buff[SIZEOF_STRUCT_SOCKS4];
    struct socks4 *replyhead = (struct socks4 *)buff;
    char *destdomname = NULL;

    /* send socks header (target addr+port, +auth) */
#if WITH_MSGLEVEL <= E_INFO
    if (ntohl(sockhead->dest) <= 0x000000ff) {
        destdomname = strchr(sockhead->userid, '\0')+1;
    }
    Info11("sending socks4%s request VN=%d DC=%d DSTPORT=%d DSTIP=%d.%d.%d.%d USERID=%s%s%s",
           destdomname?"a":"",
           sockhead->version, sockhead->action, ntohs(sockhead->port),
           ((unsigned char *)&sockhead->dest)[0],
           ((unsigned char *)&sockhead->dest)[1],
           ((unsigned char *)&sockhead->dest)[2],
           ((unsigned char *)&sockhead->dest)[3],
           sockhead->userid,
           destdomname?" DESTNAME=":"",
           destdomname?destdomname:"");
#endif /* WITH_MSGLEVEL <= E_INFO */
#if WITH_MSGLEVEL <= E_DEBUG
    {
        char *msgbuff;
        if ((msgbuff = Malloc(3*headlen)) != NULL) {
            xiohexdump((const unsigned char *)sockhead, headlen, msgbuff);
            Debug1("sending socks4(a) request data %s", msgbuff);
        }
    }
#endif /* WITH_MSGLEVEL <= E_DEBUG */
    if (writefull(xfd->fd, sockhead, headlen) < 0) {
        Msg4(level, "write(%d, %p, "F_Zu"): %s",
             xfd->fd, sockhead, headlen, strerror(errno));
        if (Close(xfd->fd) < 0) {
            Info2("close(%d): %s", xfd->fd, strerror(errno));
        }
        return STAT_RETRYLATER;	/* retry complete open cycle */
    }

    bytes = 0;
    Info("waiting for socks reply");
    while (bytes >= 0) {	/* loop over answer chunks until complete or error */
        /* receive socks answer */
        do {
            result = Read(xfd->fd, buff+bytes, SIZEOF_STRUCT_SOCKS4-bytes);
        } while (result < 0 && errno == EINTR);
        if (result < 0) {
            Msg4(level, "read(%d, %p, "F_Zu"): %s",
                 xfd->fd, buff+bytes, SIZEOF_STRUCT_SOCKS4-bytes,
                 strerror(errno));
            if (Close(xfd->fd) < 0) {
                Info2("close(%d): %s", xfd->fd, strerror(errno));
            }
        }
        if (result == 0) {
            Msg(level, "read(): EOF during read of socks reply, peer might not be a socks4 server");
            if (Close(xfd->fd) < 0) {
                Info2("close(%d): %s", xfd->fd, strerror(errno));
            }
            return STAT_RETRYLATER;
        }
#if WITH_MSGLEVEL <= E_DEBUG
        {
            char msgbuff[3*SIZEOF_STRUCT_SOCKS4];
            * xiohexdump((const unsigned char *)replyhead+bytes, result, msgbuff)
                = '\0';
            Debug2("received socks4 reply data (offset "F_Zd"): %s", bytes, msgbuff);
        }
#endif /* WITH_MSGLEVEL <= E_DEBUG */
        bytes += result;
        if (bytes == SIZEOF_STRUCT_SOCKS4) {
            Debug1("received all "F_Zd" bytes", bytes);
            break;
        }
        Debug2("received %d bytes, waiting for "F_Zu" more bytes",
               result, SIZEOF_STRUCT_SOCKS4-bytes);
    }
    if (result <= 0) {	/* we had a problem while reading socks answer */
        return STAT_RETRYLATER;	/* retry complete open cycle */
    }

    Info7("received socks reply VN=%u CD=%u DSTPORT=%u DSTIP=%u.%u.%u.%u",
          replyhead->version, replyhead->action, ntohs(replyhead->port),
          ((uint8_t *)&replyhead->dest)[0],
          ((uint8_t *)&replyhead->dest)[1],
          ((uint8_t *)&replyhead->dest)[2],
          ((uint8_t *)&replyhead->dest)[3]);
    if (replyhead->version != 0) {
        Warn1("socks: reply code version is not 0 (%d)",
              replyhead->version);
    }

    switch (replyhead->action) {
    case SOCKS_CD_GRANTED:
        /* Notice("socks: connect request succeeded"); */
#if 0
        if (Getsockname(xfd->fd, (struct sockaddr *)&us, &uslen) < 0) {
            Warn4("getsockname(%d, %p, {%d}): %s",
                  xfd->fd, &us, uslen, strerror(errno));
        }
        Notice1("successfully connected from %s via socks4",
                sockaddr_info((struct sockaddr *)&us, infobuff, sizeof(infobuff)));
#else
        Notice("successfully connected via socks4");
#endif
        break;

    case SOCKS_CD_FAILED:
        Msg(level, "socks: connect request rejected or failed");
        return STAT_RETRYLATER;

    case SOCKS_CD_NOIDENT:
        Msg(level, "socks: ident refused by client");
        return STAT_RETRYLATER;

    case SOCKS_CD_IDENTFAILED:
        Msg(level, "socks: ident failed");
        return STAT_RETRYLATER;

    default:
        Msg1(level, "socks: undefined status %u", replyhead->action);
    }

    return STAT_OK;
}
예제 #3
0
int _xioopen_proxy_connect(struct single *xfd,
			   struct proxyvars *proxyvars,
			   int level) {
   size_t offset;
   char request[CONNLEN];
   char buff[BUFLEN+1];
#if CONNLEN > BUFLEN
#error not enough buffer space 
#endif
   char textbuff[2*BUFLEN+1];	/* just for sanitizing print data */
   char *eol = buff;
   int state;
   ssize_t sresult;

   /* generate proxy request header - points to final target */
   sprintf(request, "CONNECT %s:%u HTTP/1.0\r\n",
	   proxyvars->targetaddr, proxyvars->targetport);

   /* send proxy CONNECT request (target addr+port) */
   * xiosanitize(request, strlen(request), textbuff) = '\0';
   Info1("sending \"%s\"", textbuff);
   /* write errors are assumed to always be hard errors, no retry */
   if (writefull(xfd->fd, request, strlen(request)) < 0) {
      Msg4(level, "write(%d, %p, "F_Zu"): %s",
	   xfd->fd, request, strlen(request), strerror(errno));
      if (Close(xfd->fd) < 0) {
	 Info2("close(%d): %s", xfd->fd, strerror(errno));
      }
      return STAT_RETRYLATER;
   }

   if (proxyvars->authstring) {
      /* send proxy authentication header */
#     define XIOAUTHHEAD "Proxy-authorization: Basic "
#     define XIOAUTHLEN  27
      static const char *authhead = XIOAUTHHEAD;
#     define HEADLEN 256
      char *header, *next;

      /* ...\r\n\0 */
      if ((header =
	   Malloc(XIOAUTHLEN+((strlen(proxyvars->authstring)+2)/3)*4+3))
	  == NULL) {
	 return -1;
      }
      strcpy(header, authhead);
      next = xiob64encodeline(proxyvars->authstring,
			      strlen(proxyvars->authstring),
			      strchr(header, '\0'));
      *next = '\0';
      Info1("sending \"%s\\r\\n\"", header);
      *next++ = '\r';  *next++ = '\n'; *next++ = '\0';
      if (writefull(xfd->fd, header, strlen(header)) < 0) {
	 Msg4(level, "write(%d, %p, "F_Zu"): %s",
	      xfd->fd, header, strlen(header), strerror(errno));
	 if (Close(xfd->fd) < 0) {
	    Info2("close(%d): %s", xfd->fd, strerror(errno));
	 }
	 return STAT_RETRYLATER;
      }

      free(header);
   }

   Info("sending \"\\r\\n\"");
   if (writefull(xfd->fd, "\r\n", 2) < 0) {
      Msg2(level, "write(%d, \"\\r\\n\", 2): %s",
	   xfd->fd, strerror(errno));
      if (Close(xfd->fd) < 0) {
	 Info2("close(%d): %s", xfd->fd, strerror(errno));
      }
      return STAT_RETRYLATER;
   }

   /* request is kept for later error messages */
   *strstr(request, " HTTP") = '\0';

   /* receive proxy answer; looks like "HTTP/1.0 200 .*\r\nHeaders..\r\n\r\n" */
   /* socat version 1 depends on a valid fd for data transfer; address
      therefore cannot buffer data. So, to prevent reading beyond the end of
      the answer headers, only single bytes are read. puh. */
   state = XIOSTATE_HTTP1;
   offset = 0;	/* up to where the buffer is filled (relative) */
   /*eol;*/	/* points to the first lineterm of the current line */
   do {
      sresult = xioproxy_recvbytes(xfd, buff+offset, 1, level);
      if (sresult <= 0) {
	 state = XIOSTATE_ERROR;
	 break;	/* leave read cycles */
      }
      
      switch (state) {

      case XIOSTATE_HTTP1:
	 /* 0 or more bytes of first line received, no '\r' yet */
	 if (*(buff+offset) == '\r') {
	    eol = buff+offset;
	    state = XIOSTATE_HTTP2;
	    break;
	 }
	 if (proxyvars->ignorecr && *(buff+offset) == '\n') {
	    eol = buff+offset;
	    state = XIOSTATE_HTTP3;
	    break;
	 }
	 break;

      case XIOSTATE_HTTP2:
	 /* first line received including '\r' */
	 if (*(buff+offset) != '\n') {
	    state = XIOSTATE_HTTP1;
	    break;
	 }
	 state = XIOSTATE_HTTP3;
	 break;

      case XIOSTATE_HTTP3:
	 /* received status (first line) and "\r\n" */
	 if (*(buff+offset) == '\r') {
	    state = XIOSTATE_HTTP7;
	    break;
	 }
	 if (proxyvars->ignorecr && *(buff+offset) == '\n') {
	    state = XIOSTATE_HTTP8;
	    break;
	 }
	 state = XIOSTATE_HTTP4;
	 break;
	 
      case XIOSTATE_HTTP4:
	 /* within header */
	 if (*(buff+offset) == '\r') {
	    eol = buff+offset;
	    state = XIOSTATE_HTTP5;
	    break;
	 }
	 if (proxyvars->ignorecr && *(buff+offset) == '\n') {
	    eol = buff+offset;
	    state = XIOSTATE_HTTP6;
	    break;
	 }
	 break;

      case XIOSTATE_HTTP5:
	 /* within header, '\r' received */
	 if (*(buff+offset) != '\n') {
	    state = XIOSTATE_HTTP4;
	    break;
	 }
	 state = XIOSTATE_HTTP6;
	 break;

      case XIOSTATE_HTTP6:
	 /* received status (first line) and 1 or more headers, "\r\n" */
	 if (*(buff+offset) == '\r') {
	    state = XIOSTATE_HTTP7;
	    break;
	 }
	 if (proxyvars->ignorecr && *(buff+offset) == '\n') {
	    state = XIOSTATE_HTTP8;
	    break;
	 }
	 state = XIOSTATE_HTTP4;
	 break;

      case XIOSTATE_HTTP7:
	 /* received status (first line), 0 or more headers, "\r\n\r" */
	 if (*(buff+offset) == '\n') {
	    state = XIOSTATE_HTTP8;
	    break;
	 }
	 if (*(buff+offset) == '\r') {
	    if (proxyvars->ignorecr) {
	       break;	/* ignore it, keep waiting for '\n' */
	    } else {
	       state = XIOSTATE_HTTP5;
	    }
	    break;
	 }
	 state = XIOSTATE_HTTP4;
	 break;

      }
      ++offset;

      /* end of status line reached */
      if (state == XIOSTATE_HTTP3) {
	 char *ptr;
	 /* set a terminating null - on or after CRLF? */
	 *(buff+offset) = '\0';

	 * xiosanitize(buff, Min(offset, (sizeof(textbuff)-1)>>1), textbuff)
	    = '\0';
	 Info1("proxy_connect: received answer \"%s\"", textbuff);
	 *eol = '\0';
	 * xiosanitize(buff, Min(strlen(buff), (sizeof(textbuff)-1)>>1),
		       textbuff) = '\0';
	 if (strncmp(buff, "HTTP/1.0 ", 9) &&
	     strncmp(buff, "HTTP/1.1 ", 9)) {
	    /* invalid answer */
	    Msg1(level, "proxy: invalid answer \"%s\"", textbuff);
	    return STAT_RETRYLATER;
	 }
	 ptr = buff+9;

	 /* skip multiple spaces */
	 while (*ptr == ' ')  ++ptr;

	 /* HTTP answer */
	 if (strncmp(ptr, "200", 3)) {
	    /* not ok */
	    /* CERN:
	       "HTTP/1.0 200 Connection established"
	       "HTTP/1.0 400 Invalid request "CONNECT 10.244.9.3:8080 HTTP/1.0" (unknown method)"
	       "HTTP/1.0 403 Forbidden - by rule"
	       "HTTP/1.0 407 Proxy Authentication Required"
	       Proxy-Authenticate: Basic realm="Squid proxy-caching web server"
>  50 72 6f 78 79 2d 61 75 74 68 6f 72 69 7a 61 74  Proxy-authorizat
>  69 6f 6e 3a 20 42 61 73 69 63 20 61 57 4e 6f 63  ion: Basic aWNoc
>  32 56 73 59 6e 4e 30 4f 6e 4e 30 63 6d 56 75 5a  2VsYnN0OnN0cmVuZ
>  32 64 6c 61 47 56 70 62 51 3d 3d 0d 0a           2dlaGVpbQ==..
                b64encode("username:password")
	       "HTTP/1.0 500 Can't connect to host"
	    */
	    /* Squid:
	       "HTTP/1.0 400 Bad Request"
	       "HTTP/1.0 403 Forbidden"
	       "HTTP/1.0 503 Service Unavailable"
	       interesting header: "X-Squid-Error: ERR_CONNECT_FAIL 111" */
	    /* Apache:
	       "HTTP/1.0 400 Bad Request"
	       "HTTP/1.1 405 Method Not Allowed"
	    */
	    /* WTE:
	       "HTTP/1.1 200 Connection established"
	       "HTTP/1.1 404 Host not found or not responding, errno:  79"
	       "HTTP/1.1 404 Host not found or not responding, errno:  32"
	       "HTTP/1.1 404 Host not found or not responding, errno:  13"
	    */
	    /* IIS:
	       "HTTP/1.1 404 Object Not Found"
	    */
	    ptr += 3;
	    while (*ptr == ' ')  ++ptr;
	    
	    Msg2(level, "%s: %s", request, ptr);
	    return STAT_RETRYLATER;
	 }

	 /* ok!! */
	 /* "HTTP/1.0 200 Connection established" */
	 /*Info1("proxy: \"%s\"", textbuff+13);*/
	 offset = 0;

      } else if (state == XIOSTATE_HTTP6) {
      /* end of a header line reached */
	 char *endp;

	 /* set a terminating null */
	 *(buff+offset) = '\0';

	 endp =
	    xiosanitize(buff, Min(offset, (sizeof(textbuff)-1)>>1),
			textbuff);
	 *endp = '\0';
	 Info1("proxy_connect: received header \"%s\"", textbuff);
	 offset = 0;
      }