9 #include <netinet/in.h>
15 #define PROXY_TIMEOUT 10
16 // HTTP proxy timeout in seconds (for the CONNECT method)
20 #define OPENSSL_NO_KRB5 1
21 #include <openssl/ssl.h>
22 #include <openssl/err.h>
26 #include <gnutls/gnutls.h>
30 #include <nss_compat_ossl/nss_compat_ossl.h>
34 static int in_http_connect
= 0;
36 #if defined(HAVE_OPENSSL) || defined(HAVE_NSS_COMPAT)
38 static SSL_CTX
*ctx
= NULL
;
39 typedef struct { int fd
; SSL
*ssl
; } sslsock
;
43 typedef struct { int fd
; gnutls_session_t session
; } sslsock
;
49 static sslsock
*socks
= 0;
50 static int sockcount
= 0;
52 static sslsock
*getsock(int fd
) {
55 for(i
= 0; i
< sockcount
; i
++)
62 static sslsock
*addsock(int fd
) {
66 gnutls_certificate_credentials_t xcred
;
70 socks
= (sslsock
*) realloc(socks
, sizeof(sslsock
)*++sockcount
);
72 socks
= (sslsock
*) malloc(sizeof(sslsock
)*++sockcount
);
74 p
= &socks
[sockcount
-1];
76 #if defined(HAVE_OPENSSL) || defined(HAVE_NSS_COMPAT)
80 SSL_load_error_strings();
83 SSLeay_add_all_algorithms();
85 OpenSSL_add_all_algorithms();
87 ctx
= SSL_CTX_new(SSLv23_client_method());
89 p
->ssl
= SSL_new(ctx
);
90 SSL_set_fd(p
->ssl
, p
->fd
= fd
);
92 gnutls_global_init ();
93 gnutls_certificate_allocate_credentials (&xcred
);
94 gnutls_init (&(p
->session
), GNUTLS_CLIENT
);
95 gnutls_set_default_priority (p
->session
);
96 gnutls_credentials_set (p
->session
, GNUTLS_CRD_CERTIFICATE
, xcred
);
98 gnutls_transport_set_ptr(p
->session
,(gnutls_transport_ptr_t
)fd
);
104 static void delsock(int fd
) {
112 for(i
= 0; i
< sockcount
; i
++) {
113 if(socks
[i
].fd
!= fd
) {
114 socks
[nsockcount
++] = socks
[i
];
116 #if defined(HAVE_OPENSSL) || defined(HAVE_NSS_COMPAT)
118 SSL_free(socks
[i
].ssl
);
122 gnutls_bye( socks
[i
].session
, GNUTLS_SHUT_WR
);
123 gnutls_deinit(socks
[i
].session
);
128 socks
= realloc(socks
, sizeof(sslsock
)*(nsockcount
));
129 sockcount
= nsockcount
;
135 static char *bindaddr
= 0, *proxyhost
= 0, *proxyuser
= 0, *proxypass
= 0;
136 static int proxyport
= 3128;
137 static int proxy_ssl
= 0;
139 #define SOCKOUT(s) write(sockfd, s, strlen(s))
141 int cw_http_connect(int sockfd
, const struct sockaddr
*serv_addr
, int addrlen
) {
143 struct hostent
*server
;
144 struct sockaddr_in paddr
;
151 if(!(server
= gethostbyname(proxyhost
))) {
157 memset(&paddr
, 0, sizeof(paddr
));
158 paddr
.sin_family
= AF_INET
;
159 memcpy(&paddr
.sin_addr
.s_addr
, *server
->h_addr_list
, server
->h_length
);
160 paddr
.sin_port
= htons(proxyport
);
162 fl
= fcntl(sockfd
, F_GETFL
);
163 fcntl(sockfd
, F_SETFL
, fl
& ~O_NONBLOCK
);
167 err
= cw_connect(sockfd
, (struct sockaddr
*) &paddr
, sizeof(paddr
), proxy_ssl
);
170 errno
= ECONNREFUSED
;
173 struct sockaddr_in
*sin
= (struct sockaddr_in
*) serv_addr
;
174 char *ip
= inet_ntoa(sin
->sin_addr
), c
;
177 sprintf(buf
, "%d", ntohs(sin
->sin_port
));
182 SOCKOUT(" HTTP/1.0\r\n");
186 SOCKOUT("Proxy-Authorization: Basic ");
188 sprintf(buf
, "%s:%s", proxyuser
, proxypass
);
189 b
= cw_base64_encode(buf
);
202 FD_SET(sockfd
, &rfds
);
204 tv
.tv_sec
= PROXY_TIMEOUT
;
207 err
= select(sockfd
+1, &rfds
, 0, 0, &tv
);
209 if(err
< 1) err
= -1;
211 if(err
!= -1 && FD_ISSET(sockfd
, &rfds
)) {
212 err
= read(sockfd
, &c
, 1);
221 if(!strcmp(buf
+strlen(buf
)-4, "\r\n\r\n"))
228 if(err
!= -1 && strlen(buf
)) {
229 char *p
= strstr(buf
, " ");
237 fcntl(sockfd
, F_SETFL
, fl
);
238 if(fl
& O_NONBLOCK
) {
249 int cw_connect(int sockfd
, const struct sockaddr
*serv_addr
, int addrlen
, int ssl
) {
251 struct sockaddr_in ba
;
254 if(strlen(bindaddr
)) {
255 #ifdef HAVE_INET_ATON
257 rc
= inet_aton(bindaddr
, &addr
);
258 ba
.sin_addr
.s_addr
= addr
.s_addr
;
260 rc
= inet_pton(AF_INET
, bindaddr
, &ba
);
265 rc
= bind(sockfd
, (struct sockaddr
*) &ba
, sizeof(ba
));
266 if ((rc
==-1) && (errno
== EINVAL
))
275 if(proxyhost
&& !in_http_connect
) {
276 rc
= cw_http_connect(sockfd
, serv_addr
, addrlen
);
279 rc
= connect(sockfd
, serv_addr
, addrlen
);
284 sslsock
*p
= addsock(sockfd
);
285 #if defined(HAVE_OPENSSL) || defined(HAVE_NSS_COMPAT)
286 if(SSL_connect(p
->ssl
) != 1){
287 //fprintf(stderr, "cw_connect(%d) - cannot connect to SSL\n", sockfd);
290 #elif defined(HAVE_GNUTLS)
293 ret
= gnutls_handshake(p
->session
);
294 } while ((ret
== GNUTLS_E_AGAIN
) || (ret
== GNUTLS_E_INTERRUPTED
));
305 int cw_nb_connect(int sockfd
, const struct sockaddr
*serv_addr
, int addrlen
, int ssl
, int *state
) {
308 struct sockaddr_in ba
;
311 if(strlen(bindaddr
)) {
312 #ifdef HAVE_INET_ATON
314 rc
= inet_aton(bindaddr
, &addr
);
315 ba
.sin_addr
.s_addr
= addr
.s_addr
;
317 rc
= inet_pton(AF_INET
, bindaddr
, &ba
);
322 rc
= bind(sockfd
, (struct sockaddr
*) &ba
, sizeof(ba
));
323 if ((rc
==-1) && (errno
== EINVAL
))
334 if ( !(*state
& CW_CONNECT_WANT_SOMETHING
)){
335 rc
= cw_connect(sockfd
, serv_addr
, addrlen
, 0);
337 else{ /* check if the socket is connected correctly */
338 int optlen
= sizeof(int), optval
;
339 if (getsockopt(sockfd
, SOL_SOCKET
, SO_ERROR
, &optval
, &optlen
) || optval
){
341 /* Look for a better solution to print errors */
342 //fprintf(stderr,"cw_nb_connect(%d): getsockopt error!!\n", sockfd);
349 if (*state
& CW_CONNECT_SSL
)
356 ret
= gnutls_handshake(p
->session
);
357 }while ((ret
== GNUTLS_E_AGAIN
) || (ret
== GNUTLS_E_INTERRUPTED
));
359 /* gnutls_deinit(p->session);
360 will be dealt with in delsock()
370 #elif defined(HAVE_OPENSSL) || defined(HAVE_NSS_COMPAT)
371 rc
= SSL_connect(p
->ssl
);
379 switch (SSL_get_error(p
->ssl
, rc
)){
380 case SSL_ERROR_WANT_READ
:
381 *state
= CW_CONNECT_SSL
| CW_CONNECT_WANT_READ
;
383 case SSL_ERROR_WANT_WRITE
:
384 *state
= CW_CONNECT_SSL
| CW_CONNECT_WANT_WRITE
;
392 else{ // catch EINPROGRESS error from the connect call
393 if (errno
== EINPROGRESS
){
394 *state
= CW_CONNECT_STARTED
| CW_CONNECT_WANT_WRITE
;
402 if ( !(*state
& CW_CONNECT_WANT_SOMETHING
)){
403 rc
= connect(sockfd
, serv_addr
, addrlen
);
405 else{ /* check if the socket is connected correctly */
406 int optlen
= sizeof(int), optval
;
407 if (getsockopt(sockfd
, SOL_SOCKET
, SO_ERROR
, &optval
, &optlen
) || optval
) {
408 //fprintf(stderr,"getsockopt error!!");
415 if (errno
== EINPROGRESS
){
416 *state
= CW_CONNECT_STARTED
| CW_CONNECT_WANT_WRITE
;
422 int cw_accept(int s
, struct sockaddr
*addr
, int *addrlen
, int ssl
) {
423 #if defined(HAVE_OPENSSL) || defined(HAVE_NSS_COMPAT)
427 rc
= accept(s
, addr
, addrlen
);
430 sslsock
*p
= addsock(s
);
431 if(SSL_accept(p
->ssl
) != 1)
439 return accept(s
, addr
, addrlen
);
442 int cw_write(int fd
, const void *buf
, int count
, int ssl
) {
451 ret
= gnutls_record_send( p
->session
, buf
, count
);
454 #elif defined(HAVE_OPENSSL) || defined(HAVE_NSS_COMPAT)
456 return SSL_write(p
->ssl
, buf
, count
);
458 return write(fd
, buf
, count
);
461 int cw_read(int fd
, void *buf
, int count
, int ssl
) {
471 ret
= gnutls_record_recv(p
->session
, buf
, count
);
472 } while ( ret
< 0 && (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
) );
475 #elif defined(HAVE_OPENSSL) || defined(HAVE_NSS_COMPAT)
477 return SSL_read(p
->ssl
, buf
, count
);
479 return read(fd
, buf
, count
);
482 int cw_close(int fd
) {
489 #define FREEVAR(v) if(v) free(v), v = 0;
491 void cw_setbind(const char *abindaddr
) {
493 bindaddr
= strdup(abindaddr
);
496 void cw_setproxy(const char *aproxyhost
, int aproxyport
, const char *aproxyuser
, const char *aproxypass
) {
501 if(aproxyhost
&& strlen(aproxyhost
)) proxyhost
= strdup(aproxyhost
);
502 if(aproxyuser
&& strlen(aproxyuser
)) proxyuser
= strdup(aproxyuser
);
503 if(aproxypass
&& strlen(aproxypass
)) proxypass
= strdup(aproxypass
);
504 proxyport
= aproxyport
;
507 char *cw_base64_encode(const char *in
) {
508 static char base64digits
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._";
511 int inlen
= strlen(in
);
512 char *out
= (char *) malloc(inlen
*4+1), c
;
514 for(out
[0] = 0; inlen
>= 3; inlen
-= 3) {
515 strncat(out
, &base64digits
[ in
[j
] >> 2 ], 1);
516 strncat(out
, &base64digits
[ ((in
[j
] << 4) & 0x30) | (in
[j
+1] >> 4) ], 1);
517 strncat(out
, &base64digits
[ ((in
[j
+1] << 2) & 0x3c) | (in
[j
+2] >> 6) ], 1);
518 strncat(out
, &base64digits
[ in
[j
+2] & 0x3f ], 1);
523 unsigned char fragment
;
525 strncat(out
, &base64digits
[in
[j
] >> 2], 1);
526 fragment
= (in
[j
] << 4) & 0x30;
529 fragment
|= in
[j
+1] >> 4;
531 strncat(out
, &base64digits
[fragment
], 1);
533 c
= (inlen
< 2) ? '-' : base64digits
[ (in
[j
+1] << 2) & 0x3c ];