LoginSignup
1
1

More than 5 years have passed since last update.

corkscrewをSSLなプロキシに対応させた

Posted at

Corkscrew は HTTP プロキシを使ったトンネリングで SSH を使うためのプログラムです。

あるとき HTTPS なウェブサーバの背後にあるプロキシサーバへセッションを張る必要があって、Corkscrew を SSL 対応にするためのパッチを作成しました。

通常の corkscrew の使い方に加えて、第一引数に -ssl を指定することで、プロキシサーバへSSLで接続します。

usage: corkscrew [-ssl] <proxyhost> <proxyport> <desthost> <destport> [authfile]

コードのパッチだけなので、ビルドのときには、

make LDADD="-lcrypto -lssl"

のように追加で SSL ライブラリを与える必要があります。

% diff -u corkscrew-2.0/corkscrew.c corkscrew-2.0/corkscrew.c 
--- corkscrew-2.0/corkscrew.c   2001-08-24 03:27:32.000000000 +0900
+++ corkscrew-2.0/corkscrew.c   2014-11-11 19:35:08.000000000 +0900
@@ -12,6 +12,12 @@
 #include <sys/types.h>
 #include <unistd.h>

+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+#define CHK_NULL(x) if ((x)==NULL) { fprintf(stderr, "NULL pointer\n"); exit(-1); }
+
 #if HAVE_SYS_FILIO_H
 #include <sys/filio.h>
 #endif
@@ -27,7 +33,7 @@

 char *base64_encodei PARAMS((char *in));
 void usage PARAMS((void));
-int sock_connect PARAMS((const char *hname, int port));
+int sock_connect PARAMS((int fd, const char *hname, int port));
 int main PARAMS((int argc, char *argv[]));

 #define BUFSIZE 4096
@@ -132,21 +138,17 @@
 }

 #ifdef ANSI_FUNC
-int sock_connect (const char *hname, int port)
+int sock_connect (int fd, const char *hname, int port)
 #else
-int sock_connect (hname, port)
+int sock_connect (fd, hname, port)
+int fd;
 const char *hname;
 int port;
 #endif
 {
-   int fd;
    struct sockaddr_in addr;
    struct hostent *hent;

-   fd = socket(AF_INET, SOCK_STREAM, 0);
-   if (fd == -1)
-       return -1;
-
    hent = gethostbyname(hname);
    if (hent == NULL)
        addr.sin_addr.s_addr = inet_addr(hname);
@@ -181,32 +183,52 @@
    struct timeval tv;
    ssize_t len;
    FILE *fp;
+   int use_ssl = 0;
+   char **av;
+   int ac;
+   int n;
+   char *p;
+   SSL_METHOD *ssl_meth;
+   SSL_CTX* ctx;
+   SSL* ssl;

    port = 80;

-   if ((argc == 5) || (argc == 6)) {
-       if (argc == 5) {
-           host = argv[1];
-           port = atoi(argv[2]);
-           desthost = argv[3];
-           destport = argv[4];
+   ac = argc - 1;
+   av = argv + 1;
+   if (ac >= 1 && strcmp(av[0], "-ssl") == 0) {
+       use_ssl = 1;
+       av++;
+       ac--;
+       port = 443;
+   }
+   if (ac >= 4) {
+       host = av[0];
+       port = atoi(av[1]);
+       desthost = av[2];
+       destport = av[3];
+       av += 4;
+       ac -= 4;
+       if (ac > 1) {
+           usage();
+           exit(-1);
        }
-       if ((argc == 6)) {
-           host = argv[1];
-           port = atoi(argv[2]);
-           desthost = argv[3];
-           destport = argv[4];
-           fp = fopen(argv[5], "r");
+       if (ac == 1) {
+           fp = fopen(av[0], "r");
            if (fp == NULL) {
-               fprintf(stderr, "Error opening %s: %s\n", argv[5], strerror(errno));
+               fprintf(stderr, "Error opening %s: %s\n", av[0], strerror(errno));
                exit(-1);
-           } else {
-               char line[4096];
-               fscanf(fp, "%s", line);
-               up = malloc(sizeof(line));
-               up = line;
-               fclose(fp);
            }
+           if (fgets(buffer, sizeof buffer - 1, fp)) {
+               len = strlen(buffer);
+               if (buffer[len - 1] == '\n')
+                   buffer[len - 1] = '\0';
+               up = malloc(len + 1);
+               strcpy(up, buffer);
+           }
+           fclose(fp);
+           av++;
+           ac--;
        }
    } else {
        usage();
@@ -218,18 +240,40 @@
    strncat(uri, ":", sizeof(uri) - strlen(uri) - 1);
    strncat(uri, destport, sizeof(uri) - strlen(uri) - 1);
    strncat(uri, " HTTP/1.0", sizeof(uri) - strlen(uri) - 1);
-   if ((argc == 6) || (argc == 7)) {
-       strncat(uri, "\nProxy-Authorization: Basic ", sizeof(uri) - strlen(uri) - 1);
+   if (up && *up) {
+       strncat(uri, "\r\nProxy-Authorization: Basic ", sizeof(uri) - strlen(uri) - 1);
        strncat(uri, base64_encode(up), sizeof(uri) - strlen(uri) - 1);
    }
    strncat(uri, linefeed, sizeof(uri) - strlen(uri) - 1);

-   csock = sock_connect(host, port);
-   if(csock == -1) {
+   csock = socket(AF_INET, SOCK_STREAM, 0);
+   if (csock == -1) {
+       fprintf(stderr, "Couldn't create socket: %s\n", strerror(errno));
+       exit(-1);
+   }
+   if (sock_connect(csock, host, port) < 0 &&
+       errno && errno != EINPROGRESS) {
        fprintf(stderr, "Couldn't establish connection to proxy: %s\n", strerror(errno));
        exit(-1);
    }

+   if (use_ssl) {
+       SSLeay_add_ssl_algorithms();
+       SSL_load_error_strings();
+       SSL_library_init();
+       ssl_meth = SSLv23_client_method();
+       ctx = SSL_CTX_new(ssl_meth);
+       CHK_NULL(ctx);
+       SSL_CTX_set_options(ctx,SSL_OP_ALL);
+       ssl = SSL_new(ctx);
+       CHK_NULL(ssl);
+       SSL_set_fd(ssl, csock);
+       if (SSL_connect(ssl) < 0) {
+           fprintf(stderr, "Couldn't establish connection to proxy: %s\n", strerror(errno));
+           exit(-1);
+       }
+   }
+
    sent = 0;
    setup = 0;
    for(;;) {
@@ -249,7 +293,11 @@
        /* there's probably a better way to do this */
        if (setup == 0) {
            if (FD_ISSET(csock, &rfd)) {
-               len = read(csock, buffer, sizeof(buffer));
+               if (use_ssl) {
+                   len = SSL_read(ssl, buffer, sizeof(buffer));
+               } else {
+                   len = read(csock, buffer, sizeof(buffer));
+               }
                if (len<=0)
                    break;
                else {
@@ -265,7 +313,11 @@
                }
            }
            if (FD_ISSET(csock, &sfd) && (sent == 0)) {
-               len = write(csock, uri, strlen(uri));
+               if (use_ssl) {
+                   len = SSL_write(ssl, uri, strlen(uri));
+               } else {
+                   len = write(csock, uri, strlen(uri));
+               }
                if (len<=0)
                    break;
                else
@@ -273,7 +325,11 @@
            }
        } else {
            if (FD_ISSET(csock, &rfd)) {
-               len = read(csock, buffer, sizeof(buffer));
+               if (use_ssl) {
+                   len = SSL_read(ssl, buffer, sizeof(buffer));
+               } else {
+                   len = read(csock, buffer, sizeof(buffer));
+               }
                if (len<=0) break;
                len = write(1, buffer, len);
                if (len<=0) break;
@@ -282,10 +338,23 @@
            if (FD_ISSET(0, &rfd)) {
                len = read(0, buffer, sizeof(buffer));
                if (len<=0) break;
-               len = write(csock, buffer, len);
+               if (use_ssl) {
+                   len = SSL_write(ssl, buffer, len);
+               } else {
+                   len = write(csock, buffer, len);
+               }
                if (len<=0) break;
            }
        }
    }
+   if (use_ssl) {
+       SSL_shutdown(ssl);
+       close(csock);
+       SSL_free(ssl);
+       SSL_CTX_free(ctx);
+   } else {
+       close(csock);
+   }
+
    exit(0);
 }
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1