/************************ * sslconnect 0.2 * Last Change: 2013-06-17 * C Implementation by Simon Rettberg * Original sslconnect 0.1 was written in perl by Martin Walter */ #include #include #include #include #include #include #include #include #include #include #include #include /* Init libs and data strctures */ void init(); /* print error report of something failed */ void ssl_error(); /* connect via ssl */ SSL* ssl_connect(char * host, uint16_t port, uint16_t local_port, SSL_CTX ** ctx); /* read from ssl connection */ ssize_t ssl_read(SSL * bio, char * buffer, ssize_t length); /* write to ssl connection */ int ssl_write(SSL * bio, char * buffer, ssize_t length); int main(int argc, char ** argv); void init() { SSL_load_error_strings(); SSL_library_init(); OpenSSL_add_all_algorithms(); } void ssl_error(char* message) { fprintf(stderr, message); fprintf(stderr, "\n%s\n", ERR_error_string(ERR_get_error(), NULL)); fprintf(stderr, "Details: %s\n", ERR_reason_error_string(ERR_get_error())); ERR_print_errors_fp(stderr); } SSL* ssl_connect(char * host, uint16_t port, uint16_t local_port, SSL_CTX ** ctx) { int ret = 0; /* create socket. needs to be done manually in order to bind to local port */ int fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { fprintf(stderr, "Could not create socket.\n"); return NULL; } struct sockaddr_in sa_dest, sa_local; memset(&sa_local, 0, sizeof(sa_local)); memset(&sa_dest, 0, sizeof(sa_dest)); sa_local.sin_family = AF_INET; sa_local.sin_port = htons(local_port); ret = bind(fd, (struct sockaddr *)&sa_local, sizeof(struct sockaddr)); if (ret == -1) { fprintf(stderr, "Could not bind local socket to 0.0.0.0:%d (%d)\n", (int)local_port, (int)errno); close(fd); return NULL; } sa_dest.sin_family = AF_INET; sa_dest.sin_port = htons(port); struct hostent * rec; rec = gethostbyname(host); if (rec == NULL) { fprintf(stderr, "Error: Invalid host: %s\n", host); return NULL; } memcpy(&(sa_dest.sin_addr), rec->h_addr, sizeof(struct in_addr)); ret = connect(fd, (struct sockaddr *)&sa_dest, sizeof(struct sockaddr)); if (ret == -1) { fprintf(stderr, "Could not connect to %s:%d (%d)\n", host, (int)port, (int)errno); close(fd); return NULL; } /* openssl part */ SSL * ssl; /* Set up the SSL pointers */ *ctx = SSL_CTX_new(SSLv23_client_method()); ssl = SSL_new(*ctx); SSL_set_fd(ssl, fd); ret = SSL_connect(ssl); if (ret <= 0) { ssl_error("Unable to SSL_connect"); return NULL; } SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); return ssl; } ssize_t ssl_read(SSL * ssl, char * buffer, ssize_t length) { ssize_t ret = -1; int retries = 10; while (ret < 0 && --retries > 0) { ret = SSL_read(ssl, buffer, length); if (ret >= 0) { return ret; } ssl_error("SSL_read failed"); return -1; } return -1; } int ssl_write(SSL * ssl, char * buffer, ssize_t length) { ssize_t ret = -1; int retries = 10; while (ret < 0 && --retries > 0) { ret = SSL_write(ssl, buffer, length); if (ret >= 0) { return ret; } ssl_error("SSL_write failed"); return -1; } return -1; } #define READBUF 5000 int main(int argc, char ** argv) { if (argc < 2) { fprintf(stderr, "Usage: %s host:port\n", argv[0]); return 1; } init(); char buffer[READBUF]; SSL_CTX * ctx = NULL; SSL * ssl; ssize_t len; size_t ret; char * pos; int port, lport; pos = strchr(argv[1], ':'); if (pos == NULL) { fprintf(stderr, "Error: No Port given.\n"); return 5; } port = atoi(pos+1); *pos = '\0'; lport = rand() % 800 + 95; ssl = ssl_connect(argv[1], (uint16_t)port, (uint16_t)lport, &ctx); if (ssl == NULL) { return 2; } ssl_write(ssl, "", 0); for (;;) { len = ssl_read(ssl, buffer, READBUF); if (len <= 0) { break; } ret = fwrite(buffer, 1, len, stdout); if (ret != len) { fprintf(stderr, "Error: fwrite could not write all received data to stdout.\n"); return 3; } } if (len < 0) { return 4; } return 0; }