#include #include #include #include #include /* ULTRIX didn't like stat with types*/ #include #include #include #include #include #include #include #include /* for inet_ntoa */ #include /* for ctime */ #include #include #include #include #include #include #include /* openssl libraries*/ #include #include #include #include #include #include #include #include #ifdef RULE_MODULE #include "config.h" #include "lock.h" #else #include "session.h" #endif #include "headers.h" int ServerSocket (u_short,int); static int getConnection(int socket_type,u_short port,int *listener,int max_serv); int makeConnection(char *,int,char *); static int sockWrite(int sockfd,char *str,size_t count); static int sockGets (int,char *,size_t); static int sockPuts (int,char *); static int getPeerInfo(int sockfd,struct front_server *client); int iread (int,char *,int); static int sockGetsSSL(SSL *ssl,char *str,size_t count); static int sockWriteSSL(SSL *ssl,char *str,size_t count); static int sockPutsSSL(SSL *ssl,char *str); static int sockReadSSL(SSL *ssl,char *buf,size_t n); /* ** sockRead() ** like read() system call, except that it will make sure that all ** the data goes through the socket ** taken from steven's network programming (page 279) */ int XXsockRead(int sockfd,char *buf,size_t nbytes) { int nleft, nread; nleft=nbytes; while (nleft > 0) { nread=read(sockfd,buf,nleft); if (nread < 0) /* error */ return (-1); else if (nread == 0) /* EOF */ break; nleft -= nread; buf += nread; } return (nbytes-nleft); /* return >= 0 */ } int serverSocket(u_short port,int max_server) { int dummy=(-1); int sock_fd; u_short nport; /* ** convert port to netword byte word */ nport=htons(port); sock_fd=getConnection(SOCK_STREAM,nport,&dummy,max_server); return (sock_fd); } int setConnection(int socket_type,u_short port,int *listener,int max_serv) { struct sockaddr_in address; int listeningSocket; int one = 1; /* ** setup internet address information ** this is used with the bind () call */ memset((char *) &address,0,sizeof(address)); address.sin_family=AF_INET; address.sin_port=port; address.sin_addr.s_addr=htonl(INADDR_ANY); listeningSocket=socket(AF_INET,socket_type,0); if (listeningSocket < 0) { (void) fprintf (stderr,"Unable to open socket!\n"); perror("socket"); return (-1); } if (listener != (int *) NULL) *listener=listeningSocket; /* ** we will resuse port */ setsockopt(listeningSocket,SOL_SOCKET,SO_REUSEADDR,(char *) &one, sizeof(int)); /* ** we will set keep alive. read Steven, Network Prog. 2nd edition, p186 */ one=1; setsockopt(listeningSocket,SOL_SOCKET,SO_KEEPALIVE,(char *) &one, sizeof(int)); if (bind(listeningSocket,(struct sockaddr *) &address, sizeof(address)) < 0) { (void) fprintf (stderr,"Unable to bind to socket\n"); (void) fprintf (stderr,"Probably the port is already in use!\n"); (void) fprintf(stderr,"Or you do not have permission to bind!\n"); close(listeningSocket); return (-1); } if (socket_type == SOCK_STREAM) { /* ** queue up max_serv connections before having them ** automatically rejected */ listen(listeningSocket,max_serv); return listeningSocket; } return -1; } int RuleSocket(u_short port,int max_server) { int dummy=(-1); int sock_fd; u_short nport; /* ** convert port to netword byte word */ nport=htons(port); return (setConnection(SOCK_STREAM,nport,&dummy,max_server)); } /* ** iread() ** same as read() system call except for automatic ** recovery for EINTR errors */ int iread(int fd,char *buf,int nbyte) { int maxfd, nready, ret=0; struct timeval tv; fd_set readfds; FD_ZERO(&readfds); maxfd=fd+1; FD_SET(fd,&readfds); tv.tv_sec=CLIENT_TIMEOUT; tv.tv_usec=0; nready=select(maxfd,&readfds,NULL,NULL,&tv); if (nready == 0) { (void) fprintf(stderr," *** read pid %d Timed out in %d seconds ***\n",getpid(),CLIENT_TIMEOUT); return -1; } /* ** get request */ if (FD_ISSET(fd,&readfds)) { while (1) { ret=read(fd,buf,nbyte); if ((ret < 0) && (errno == EINTR)) continue; else return (ret); } } return (-1); /* won't be here but for saftey */ } int sockRead(int sockfd,char *buf,size_t n) { int total_nbytes=0; int nbytes; int saved_errno; while (total_nbytes < n) { nbytes=iread(sockfd,&buf[total_nbytes], n-total_nbytes); if (nbytes < 0) { saved_errno=errno; if (saved_errno == ECONNRESET) { return (-3); } else return (-1); } else if (nbytes == 0) return (total_nbytes); else total_nbytes += nbytes; } return (total_nbytes); } #if 0 static void preforkServer(u_short port) { int sockd, one = 1; struct sockaddr_in mysocket; struct linger li; bzero((char *)&mysocket,sizeof(mysocket)); mysocket.sin_port = htons(port); mysocket.sin_addr.s_addr = INADDR_ANY; mysocket.sin_family = AF_INET; if((sockd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0) { fprintf(stderr,"socket creation error socket\n"); exit(-1); } /* ** we will resuse port */ setsockopt(sockd,SOL_SOCKET,SO_REUSEADDR,(char *) &one, sizeof(int)); /* ** we will set keep alive. read Steven, Network Prog. 2nd edition, p186 */ one=1; setsockopt(sockd,SOL_SOCKET,SO_KEEPALIVE,(char *) &one, sizeof(int)); li.l_onoff=1; li.l_linger=30; setsockopt(sockd,SOL_SOCKET,SO_LINGER,(char *) &li, sizeof(struct linger)); if(bind(sockd,(struct sockaddr *)&mysocket,sizeof(mysocket)) < 0) { fprintf(stderr,"unable to bind\n"); exit( -1); } listen(sockd,511); { int len = sizeof(mysocket); if(getsockname(sockd,(struct sockaddr *)&mysocket,&len) < 0) { perror("getsockname"); exit(-1); } printf("bound to %d\n",ntohs(mysocket.sin_port)); fflush(stdout); } init_daemon("SSL_PROXY",(int) StartServers,(int) MaxClients,(int) MaxRequestsPerChild,(int) MaxSpareServers,(int) MinSpareServers,child_function,(int)sockd); exit(0); } #endif int connectReal(char *netaddress, int port) { struct hostent *host; struct sockaddr_in address; int sockOut, retval; if ((sockOut = socket(AF_INET, SOCK_STREAM, 0)) == -1) { return -1; } /* ** i tried to use gethostbyname_r but i failed badly, so i am using this technique of locking the process before call to gethostbyname */ netaddress[strlen(netaddress)]='\0'; bzero((char *) &address, sizeof(address)); address.sin_family = AF_INET; address.sin_port = htons(port); critical_lock_on(); host = gethostbyname(netaddress); critical_lock_off(); #if 1 switch (h_errno) { case HOST_NOT_FOUND: (void) fprintf (stderr,"connect() to\'%s\'failed because of HOST_NOT_FOUND error \n",netaddress); break; case NO_ADDRESS: (void) fprintf (stderr,"connect() to %s failed because of NO_ADDRESS error \n",netaddress); break; case NO_RECOVERY: (void) fprintf (stderr,"connect() to %s failed because of NO_RECOVERY error \n",netaddress); break; case TRY_AGAIN: (void) fprintf (stderr,"connect() to %s failed because of TRY_AGAIN error \n",netaddress); break; } #endif if (host == (struct hostent *) NULL) { return -1; } bcopy((char *) host->h_addr, (char *) &address.sin_addr, host->h_length); retval = connect(sockOut, (struct sockaddr *) &address, sizeof(address)); if(retval == -1) { (void) fprintf (stderr,"connect() failed!h_errorno errno %d \n",h_errno,errno); close(sockOut); return -1; } return sockOut; /* connection OK */ } int connectTo(char *netaddress, int port) { struct hostent *host; struct sockaddr_in address; int sockOut, retval; if ((sockOut = socket(AF_INET, SOCK_STREAM, 0)) == -1) { return -1; } /* ** i tried to use gethostbyname_r but i failed badly, so i am using this technique of locking the process before call to gethostbyname */ /* netaddress[strlen(netaddress)]='\0'; */ bzero((char *) &address, sizeof(address)); address.sin_family = AF_INET; address.sin_port = htons(port); critical_lock_on(); host = gethostbyname(netaddress); critical_lock_off(); if (host == (struct hostent *) NULL) return -1; bcopy((char *) host->h_addr, (char *) &address.sin_addr, host->h_length); retval = connect(sockOut, (struct sockaddr *) &address, sizeof(address)); if(retval == -1) { (void) fprintf (stderr,"connect() to %s failed !\n",netaddress); close(sockOut); return -1; } return sockOut; /* connection OK */ } /* ** this function listens on a port and returns connecions. ** it forks returns off internally, so the calling funcion does not ** have to worry about that. ** the function will create a new process for every incomming connection, ** so in the listening process, it will never return. Only when a connection ** comes in, and we create a process for it, will the function return. ** THE CALLING FUNCION SHOULD NOT LOOP */ static int getConnection(int socket_type,u_short port,int *listener,int max_serv) { struct linger li; struct sockaddr_in address; int listeningSocket; int connectedSocket = -1; int newProcess; int one = 1; /* ** setup internet address information ** this is used with the bind () call */ memset((char *) &address,0,sizeof(address)); address.sin_family=AF_INET; address.sin_port=port; address.sin_addr.s_addr=htonl(INADDR_ANY); listeningSocket=socket(AF_INET,socket_type,0); if (listeningSocket < 0) { (void) fprintf (stderr,"Unable to open socket!\n"); perror("socket"); exit (1); } if (listener != (int *) NULL) *listener=listeningSocket; /* ** we will resuse port */ setsockopt(listeningSocket,SOL_SOCKET,SO_REUSEADDR,(char *) &one, sizeof(int)); /* ** we will set keep alive. read Steven, Network Prog. 2nd edition, p186 */ one=1; setsockopt(listeningSocket,SOL_SOCKET,SO_KEEPALIVE,(char *) &one, sizeof(int)); li.l_onoff=1; li.l_linger=30; setsockopt(listeningSocket,SOL_SOCKET,SO_LINGER,(char *) &li, sizeof(struct linger)); if (bind(listeningSocket,(struct sockaddr *) &address, sizeof(address)) < 0) { (void) fprintf (stderr,"\n\nUnable to bind to socket at port: %d\n", ntohs(port)); (void) fprintf (stderr,"Probably the port is already in use!\n"); (void) fprintf(stderr,"Or you do not have permission to bind!\n"); close(listeningSocket); exit (1); } if (socket_type == SOCK_STREAM) { /* ** queue up max_serv connections before having them ** automatically rejected */ if (listen(listeningSocket,max_serv) == 0) { (void) fprintf(stderr,"\nhttpd listening at port: %d\n", ntohs(port)); } else { perror("listen()"); } while (connectedSocket < 0) { connectedSocket=accept(listeningSocket,NULL,NULL); if (connectedSocket < 0) { /* ** either a real error occured or blocking was ** interrupted for some reason. only abort execution ** if a real error occured */ if (errno != EINTR) { (void) fprintf (stderr,"unable to accept!\n"); perror("accept"); close (listeningSocket); exit (1); } else continue; /* don't fork, do the accept again*/ } newProcess=fork(); if (newProcess < 0) { (void) fprintf (stderr,"failed to fork!\n"); perror("fork"); close(connectedSocket); connectedSocket=(-1); } else { /* ** we have a new process (child) */ if (newProcess == 0) { /* ** this is the new process ** close our copy of the socket */ close(listeningSocket); *listener=(-1); /* closed in this process, we are not ** responsible for it */ } else { /* ** this is the main loop. close copy of connected ** socket, and continue loop */ close (connectedSocket); connectedSocket=(-1); } } } return (connectedSocket); } else return (listeningSocket); } int sockGets(int sockfd,char *str,size_t count) { int bytesRead; int totalCount=0; char *currentPosition; char lastRead=0; currentPosition=str; while (lastRead != 10) { bytesRead=read(sockfd,&lastRead,1); if (bytesRead <= 0) { /* ** the other side may have closed unexpectedly */ return (-1); } if ((totalCount < count) && (lastRead != 10) && (lastRead != 13)) { *currentPosition=lastRead; currentPosition++; totalCount++; } } *currentPosition='\r'; currentPosition++; *currentPosition='\n'; currentPosition++; *currentPosition='\0'; currentPosition++; if(count > 0) *currentPosition=0; return (totalCount); } /* ** this function writes a character string out to a socket. ** it returns -1 if the connection is closed while it is trying to ** write */ static int sockPuts(int sockfd,char *str) { return (sockWrite(sockfd,str,strlen(str))); } static int sockWrite(int sockfd,char *str,size_t count) { size_t bytesSent=0; int thisWrite; while (bytesSent < count) { do thisWrite=write(sockfd,str,count-bytesSent); while ((thisWrite < 0) && (errno == EINTR)); if (thisWrite <= 0) return (thisWrite); bytesSent += thisWrite; str += thisWrite; } return (count); } /* ** i an currently retriving client port but it may not be of use!! got to wait and see -- gkgodava@archie.uccs.edu */ static int getPeerInfo(int sockfd,struct front_server *client) { struct sockaddr_in cs; int len; struct hostent *ch; char temp[64]; len=sizeof(cs); if (getpeername(sockfd,(struct sockaddr *) &cs,(socklen_t *) &len) < 0) { return (-1); } /* ** extract client IP */ client->addr=(u_long) ntohl(cs.sin_addr.s_addr); /* network byte ordering */ /* ** extract client_port */ client->port=ntohs(cs.sin_port); return (1); } static int ireadSSL(SSL *ssl,char *buf,int nbyte) { int ret=0; while (1) { ret=SSL_read(ssl,buf,nbyte); if ((ret < 0) && (errno == EINTR)) continue; else return (ret); } return (ret); /* won't be here */ } static int sockReadSSL(SSL *ssl,char *buf,size_t n) { int total_nbytes=0, nbytes, saved_errno; while (total_nbytes < n) { nbytes=ireadSSL(ssl,&buf[total_nbytes], n-total_nbytes); if (nbytes < 0) { saved_errno=errno; if (saved_errno == ECONNRESET) { return (-3); } else return (-1); } else if (nbytes == 0) return (total_nbytes); else total_nbytes += nbytes; } return (total_nbytes); } /* ** this function writes a character string out to a socket. ** it returns -1 if the connection is closed while it is trying to ** write */ static int sockPutsSSL(SSL *ssl,char *str) { return (sockWriteSSL(ssl,str,strlen(str))); } static int sockWriteSSL(SSL *ssl,char *str,size_t count) { size_t bytesSent=0; int thisWrite; if (!SSL_is_init_finished(ssl)) { (void) fprintf(stderr,"SSL_is_init_finished(ssl) retuned that there is some problem"); SSL_accept(ssl); } while (bytesSent < count) { do { thisWrite=SSL_write(ssl,str,count-bytesSent); switch (SSL_get_error(ssl,thisWrite)) { case SSL_ERROR_NONE : break; case SSL_ERROR_WANT_WRITE : case SSL_ERROR_WANT_READ : case SSL_ERROR_WANT_X509_LOOKUP : fprintf(stderr,"pid %d ssl Write BLOCK\n",getpid()); return -1; break; case SSL_ERROR_SYSCALL : fprintf(stderr," pid %d Peek_error %d SSL_ERROR_SYSCALL %d\n",getpid(),ERR_peek_error, ERR_get_error()); return -1; break; case SSL_ERROR_SSL : fprintf(stderr,"pid %d SSL_ERROR_SSL %d\n",getpid(), ERR_get_error()); return -1; break; case SSL_ERROR_ZERO_RETURN : fprintf(stderr,"pid %d SSL_ERROR_ZERO_RETURN %d \n",getpid(), ERR_get_error()); return -1; break; } } while ((thisWrite < 0) && (errno == EINTR)); if (thisWrite <= 0) { (void) fprintf(stderr,"pid %d unable to write to the socket\n",getpid()); return (thisWrite); } bytesSent += thisWrite; str += thisWrite; } return (count); } static int sockGetsSSL(SSL *ssl,char *str,size_t count) { int bytesRead, totalCount=0; char *currentPosition, lastRead=0; currentPosition=str; while (lastRead != 10) { bytesRead=SSL_read(ssl,&lastRead,1); if (bytesRead <= 0) { /* ** the other side may have closed unexpectedly */ return (-1); } if ((totalCount < count) && (lastRead != 10) && (lastRead != 13)) { *currentPosition=lastRead; currentPosition++; totalCount++; } } *currentPosition='\r'; currentPosition++; *currentPosition='\n'; currentPosition++; if(count > 0) *currentPosition=0; return (totalCount); }