home *** CD-ROM | disk | FTP | other *** search
/ PC World 2001 April / PCWorld_2001-04_cd.bin / Software / TemaCD / junkbust / linux / jcc.c < prev    next >
C/C++ Source or Header  |  1998-10-30  |  23KB  |  1,065 lines

  1. char *jcc_rcs = "$Id: jcc.c,v 3.42 1998/10/29 03:11:21 ACJC Exp $";
  2. /* Written and copyright 1997 Anonymous Coders and Junkbusters Corporation.
  3.  * Distributed under the GNU General Public License; see the README file.
  4.  * This code comes with NO WARRANTY. http://www.junkbusters.com/ht/en/gpl.html
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include <sys/types.h>
  9. #include <stdlib.h>
  10. #include <ctype.h>
  11. #include <string.h>
  12. #include <signal.h>
  13. #include <fcntl.h>
  14. #include <errno.h>
  15.  
  16. #ifdef _WIN32
  17.  
  18. #include <sys/timeb.h>
  19. #include <windows.h>
  20. #include <io.h>
  21. #include <process.h>
  22.  
  23. #else
  24.  
  25. #include <unistd.h>
  26. #include <sys/time.h>
  27. #include <sys/wait.h>
  28. #include <sys/stat.h>
  29.  
  30. #ifdef __BEOS__
  31. #include <socket.h>    /* BeOS has select() for sockets only. */
  32. #include <OS.h>        /* declarations for threads and stuff. */
  33. #endif
  34.  
  35. #ifndef FD_ZERO
  36. #include <select.h>
  37. #endif
  38.  
  39. #endif
  40.  
  41. #ifdef REGEX
  42. #include <gnu_regex.h>
  43. #endif
  44.  
  45. #include "jcc.h"
  46.  
  47. char *prog;
  48.  
  49. #define BODY    "<body bgcolor=\"#f8f8f0\" link=\"#000078\" alink=\"#ff0022\" vlink=\"#787878\">\n"
  50.  
  51. char CFAIL[]   = "HTTP/1.0 503 Connect failed\n"
  52.          "Content-Type: text/html\n\n"
  53.          "<html>\n"
  54.          "<head>\n"
  55.          "<title>Internet Junkbuster: Connect failed</title>\n"
  56.          "</head>\n"
  57.          BODY
  58.          "<h1><center>"
  59.          BANNER
  60.          "</center></h1>"
  61.          "TCP connection to '%s' failed: %s.\n<br>"
  62.          "</body>\n"
  63.          "</html>\n"
  64.          ;
  65.  
  66. char CNXDOM[]  = "HTTP/1.0 404 Non-existent domain\n"
  67.          "Content-Type: text/html\n\n"
  68.          "<html>\n"
  69.          "<head>\n"
  70.          "<title>Internet Junkbuster: Non-existent domain</title>\n"
  71.          "</head>\n"
  72.          BODY
  73.          "<h1><center>"
  74.          BANNER
  75.          "</center></h1>"
  76.          "No such domain: %s\n"
  77.          "</body>\n"
  78.          "</html>\n"
  79.          ;
  80. char CSUCCEED[] = "HTTP/1.0 200 Connection established\n"
  81.           "Proxy-Agent: IJ/" VERSION "\n\n"
  82.           ;
  83.  
  84. char CHEADER[] = "HTTP/1.0 400 Invalid header received from browser\n\n";
  85.  
  86. char SHEADER[] = "HTTP/1.0 502 Invalid header received from server\n\n";
  87.  
  88. char VANILLA_WAFER[] =
  89.     "NOTICE=TO_WHOM_IT_MAY_CONCERN_"
  90.     "Do_not_send_me_any_copyrighted_information_other_than_the_"
  91.     "document_that_I_am_requesting_or_any_of_its_necessary_components._"
  92.     "In_particular_do_not_send_me_any_cookies_that_"
  93.     "are_subject_to_a_claim_of_copyright_by_anybody._"
  94.     "Take_notice_that_I_refuse_to_be_bound_by_any_license_condition_"
  95.     "(copyright_or_otherwise)_applying_to_any_cookie._";
  96.  
  97. char DEFAULT_USER_AGENT[] ="User-Agent: Mozilla/3.01Gold (Macintosh; I; 68K)";
  98.  
  99. int debug           = 0;
  100. int multi_threaded  = 1;
  101. int hideConsole     = 0;
  102.  
  103. #ifdef _WIN32
  104. #define sleep(N)    Sleep(((N) * 1000))
  105. #endif
  106.  
  107. char *logfile = NULL;
  108. FILE *logfp;
  109.  
  110. char *blockfile    = NULL;
  111. char *cookiefile   = NULL;
  112. char *trustfile    = NULL;
  113. char *forwardfile  = NULL;
  114. char *aclfile      = NULL;
  115.  
  116. char *jarfile = NULL;
  117. FILE *jar;
  118.  
  119. char *referrer   = NULL;
  120. char *uagent     = NULL;
  121. char *from       = NULL;
  122.  
  123. int suppress_vanilla_wafer = 0;
  124. int add_forwarded      = 0;
  125.  
  126. struct client_state clients[1];
  127. struct file_list    files[1];
  128.  
  129. struct list wafer_list[1];
  130. struct list xtra_list[1];
  131. struct list trust_info[1];
  132.  
  133. struct url_spec * trust_list[64];
  134.  
  135.  
  136. int (*loaders[NLOADERS])();
  137.  
  138. struct gateway gateways[] = {
  139. /* type         function        gw type/host/port,    fw host/port*/
  140. { "direct",    direct_connect, 0,        NULL, 0,     NULL, 0    },
  141. { ".",        direct_connect, 0,        NULL, 0,     NULL, 0    },
  142. { "socks",    socks4_connect, SOCKS_4,  NULL, 1080,  NULL, 0    },
  143. { "socks4",    socks4_connect, SOCKS_4,  NULL, 1080,  NULL, 0    },
  144. { "socks4a",    socks4_connect, SOCKS_4A, NULL, 1080,  NULL, 0    },
  145. { NULL,        NULL,           0,        NULL, 0,     NULL, 0    }
  146. };
  147.  
  148. struct gateway *gw_default = gateways;
  149.  
  150. char *haddr = "127.0.0.1";    /* default binding to localhost */
  151. int   hport = 8000;
  152.  
  153. struct proxy_args proxy_args[1];
  154.  
  155. int
  156. write_socket(int fd, char *buf, int n)
  157. {
  158.     if(n <= 0) return(0);
  159.  
  160.     if(DEBUG(LOG)) fwrite(buf, n, 1, logfp);
  161.  
  162. #if defined(_WIN32) || defined(__BEOS__)
  163.     return send(fd, buf, n, 0);
  164. #else
  165.     return write(fd, buf, n);
  166. #endif
  167. }
  168.  
  169. int
  170. read_socket(int fd, char *buf, int n)
  171. {
  172.     if(n <= 0) return(0);
  173. #if defined(_WIN32) || defined(__BEOS__)
  174.     return recv(fd, buf, n, 0);
  175. #else
  176.     return read(fd, buf, n);
  177. #endif
  178. }
  179.  
  180. void
  181. close_socket(int fd)
  182. {
  183. #if defined(_WIN32) || defined(__BEOS__)
  184.     closesocket(fd);
  185. #else
  186.     close(fd);
  187. #endif
  188. }
  189.  
  190. void
  191. chat(struct client_state *csp)
  192. {
  193.     char buf[BUFSIZ], *hdr, *p, *req;
  194.     char *err = NULL;
  195.     char *eno;
  196.     fd_set rfds;
  197.     int n, maxfd, server_body;
  198.     struct cookie_spec *cs;
  199.     struct gateway *gw;
  200.     struct http_request *http;
  201.  
  202.     http = csp->http;
  203.  
  204.     /* read the client's request.
  205.      * note that since we're not using select()
  206.      * we could get blocked here if a client 
  207.      * connected, then didn't say anything!
  208.      */
  209.  
  210.     for(;;) {
  211.         n = read_socket(csp->cfd, buf, sizeof(buf));
  212.  
  213.         if(n <= 0) break;        /* error! */
  214.  
  215.         add_to_iob(csp, buf, n);
  216.  
  217.         req = get_header(csp);
  218.  
  219.         if(req == NULL) break;        /* no HTTP request! */
  220.  
  221.         if(*req == '\0') continue;    /* more to come! */
  222.  
  223.         parse_http_request(req, http, csp);
  224.         freez(req);
  225.         break;
  226.     }
  227.  
  228.     if(http->cmd == NULL) {
  229.         strcpy(buf, CHEADER);
  230.         write_socket(csp->cfd, buf, strlen(buf));
  231.         return;
  232.     }
  233.  
  234.     /* decide how to route the HTTP request */
  235.  
  236.     if((gw = forward_url(http, csp)) == NULL) {
  237.  
  238.         fprintf(logfp,
  239.             "%s: gateway spec is NULL!?!?  This can't happen!\n", prog);
  240.         abort();
  241.     }
  242.  
  243.     /* build the http request to send to the server
  244.      * we have to do one of the following:
  245.      *
  246.      * create = use the original HTTP request to create a new
  247.      *          HTTP request that has only the path component
  248.      *          without the http://domainspec
  249.      * pass   = pass the original HTTP request unchanged
  250.      *
  251.      * drop   = drop the HTTP request
  252.      *        
  253.      * here's the matrix:
  254.      *                        SSL
  255.      *                    0        1
  256.          *                +--------+--------+
  257.          *                |        |        |
  258.          *             0  | create | drop   |
  259.          *                |        |        |
  260.          *  Forwarding    +--------+--------+
  261.          *                |        |        |
  262.          *             1  | pass   | pass   |
  263.          *                |        |        |
  264.          *                +--------+--------+
  265.          *
  266.          */
  267.  
  268.     if(gw->forward_host) {
  269.             /* if forwarding, just pass the request as is */
  270.             enlist(csp->headers, http->cmd);
  271.     } else {
  272.         if(http->ssl == 0) {
  273.             /* otherwise elide the host information from the url */
  274.             p = NULL;
  275.             p = strsav(p, http->gpc);
  276.             p = strsav(p, " ");
  277.             p = strsav(p, http->path);
  278.             p = strsav(p, " ");
  279.             p = strsav(p, http->ver);
  280.             enlist(csp->headers, p);
  281.             freez(p);
  282.         }
  283.     }
  284.  
  285.     /* decide what we're to do with cookies */
  286.  
  287.     if((cs = cookie_url(http, csp))) {
  288.         csp->accept_server_cookie  = cs->accept_server_cookie;
  289.         csp->send_user_cookie      = cs->send_user_cookie;
  290.     } else {
  291.         csp->accept_server_cookie  = 0;
  292.         csp->send_user_cookie      = 0;
  293.     }
  294.  
  295.     /* grab the rest of the client's headers */
  296.  
  297.     for(;;) {
  298.         if(( p = get_header(csp))
  299.         && (*p == '\0')) {
  300.             n = read_socket(csp->cfd, buf, sizeof(buf));
  301.             if(n <= 0) {
  302.                 fprintf(logfp,
  303.                     "%s: read from client failed: ", prog);
  304.                 fperror(logfp, "");
  305.                 return;
  306.             }
  307.             add_to_iob(csp, buf, n);
  308.             continue;
  309.         }
  310.  
  311.         if(p == NULL) break;
  312.  
  313.         enlist(csp->headers, p);
  314.         freez(p);
  315.     }
  316.  
  317.     /* filter it as required */
  318.  
  319.     hdr = sed(client_patterns, add_client_headers, csp);
  320.  
  321.     destroy_list(csp->headers);
  322.  
  323.     if((p = intercept_url(http, csp))
  324.     || (p =     block_url(http, csp))
  325.     || (p =     trust_url(http, csp))) {
  326.         if(DEBUG(GPC)) {
  327.             fprintf(logfp, "%s: GPC\t%s%s crunch!\n",
  328.                 prog, http->hostport, http->path);
  329.         }
  330.  
  331.         write_socket(csp->cfd, p, strlen(p));
  332.  
  333.         if(DEBUG(LOG)) fwrite(p, strlen(p), 1, logfp);
  334.  
  335.         freez(p);
  336.         freez(hdr);
  337.         return;
  338.     }
  339.  
  340.     if(DEBUG(GPC)) {
  341.         fprintf(logfp, "%s: GPC\t%s%s\n",
  342.             prog, http->hostport, http->path);
  343.     }
  344.  
  345.     if(DEBUG(CON)) {
  346.         if(gw->forward_host) {
  347.             fprintf(logfp,
  348.                 "%s: connect via %s:%d to: %s ... ",
  349.                     prog,
  350.                     gw->forward_host,
  351.                     gw->forward_port,
  352.                     http->hostport);
  353.         } else {
  354.             fprintf(logfp,
  355.                 "%s: connect to: %s ... ",
  356.                     prog, http->hostport);
  357.         }
  358.     }
  359.  
  360.     /* here we connect to the server, gateway, or the forwarder */
  361.  
  362.     csp->sfd = (gw->conn)(gw, http, csp);
  363.  
  364.     if(csp->sfd < 0) {
  365.         if(DEBUG(CON)) {
  366.             fprintf(logfp, "%s: connect to: %s failed: ",
  367.                     prog, http->hostport);
  368.             fperror(logfp, "");
  369.         }
  370.  
  371.         if(errno == EINVAL) {
  372.             err = zalloc(strlen(CNXDOM) + strlen(http->host));
  373.             sprintf(err, CNXDOM, http->host);
  374.         } else {
  375.             eno = safe_strerror(errno);
  376.             err = zalloc(strlen(CFAIL) + strlen(http->hostport) + strlen(eno));
  377.             sprintf(err, CFAIL, http->hostport, eno);
  378.         }
  379.  
  380.         write_socket(csp->cfd, err, strlen(err));
  381.  
  382.         if(DEBUG(LOG)) fwrite(err, strlen(err), 1, logfp);
  383.  
  384.         freez(err);
  385.         freez(hdr);
  386.         return;
  387.     }
  388.  
  389.     if(DEBUG(CON)) {
  390.         fprintf(logfp, "OK\n");
  391.     }
  392.  
  393.     if(gw->forward_host || (http->ssl == 0)) {
  394.         /* write the client's (modified) header to the server
  395.          * (along with anything else that may be in the buffer)
  396.          */
  397.  
  398.         n = strlen(hdr);
  399.  
  400.         if((write_socket(csp->sfd, hdr, n) != n)
  401.         || (flush_socket(csp->sfd, csp   ) <  0)) {
  402.             if(DEBUG(CON)) {
  403.                 fprintf(logfp, "%s: write header to: %s failed: ",
  404.                     prog, http->hostport);
  405.                 fperror(logfp, "");
  406.             }
  407.  
  408.             eno = safe_strerror(errno);
  409.             err = zalloc(strlen(CFAIL) + strlen(http->hostport) + strlen(eno));
  410.             sprintf(err, CFAIL, http->hostport, eno);
  411.             write_socket(csp->cfd, err, strlen(err));
  412.  
  413.             freez(err);
  414.             freez(hdr);
  415.             return;
  416.         }
  417.     } else {
  418.         /* we're running an SSL tunnel and we're not
  419.          * forwarding, so just send the "connect succeeded"
  420.          * message to the client, flush the rest, and
  421.          * get out of the way.
  422.          */
  423.  
  424.         if(write_socket(csp->cfd, CSUCCEED, sizeof(CSUCCEED)-1) < 0) {
  425.             freez(hdr);
  426.             return;
  427.         }
  428.         IOB_RESET(csp);
  429.     }
  430.  
  431.     /* we're finished with the client's header */
  432.     freez(hdr);
  433.  
  434.     maxfd = ( csp->cfd > csp->sfd ) ? csp->cfd : csp->sfd;
  435.  
  436.     /* pass data between the client and server
  437.      * until one or the other shuts down the connection.
  438.      */
  439.  
  440.     server_body = 0;
  441.  
  442.     for(;;) {
  443.         FD_ZERO(&rfds);
  444.  
  445.         FD_SET(csp->cfd, &rfds);
  446.         FD_SET(csp->sfd, &rfds);
  447.  
  448.         n = select(maxfd+1, &rfds, NULL, NULL, NULL);
  449.  
  450.         if(n < 0) {
  451.             fprintf(logfp, "%s: select() failed!: ", prog);
  452.             fperror(logfp, "");
  453.             return;
  454.         }
  455.  
  456.         /* this is the body of the browser's request
  457.          * just read it and write it.
  458.          */
  459.  
  460.         if(FD_ISSET(csp->cfd, &rfds)) {
  461.  
  462.             n = read_socket(csp->cfd, buf, sizeof(buf));
  463.  
  464.             if(n <= 0) break; /* "game over, man" */
  465.  
  466.             if(write_socket(csp->sfd, buf, n) != n) {
  467.                 fprintf(logfp, "%s: write to: %s failed: ",
  468.                         prog, http->host);
  469.                 fperror(logfp, "");
  470.                 return;
  471.             }
  472.             continue;
  473.         }
  474.  
  475.         /* the server wants to talk.
  476.          * it could be the header or the body.
  477.          * if `hdr' is null, then it's the header
  478.          * otherwise it's the body
  479.          */
  480.  
  481.         if(FD_ISSET(csp->sfd, &rfds)) {
  482.  
  483.             n = read_socket(csp->sfd, buf, sizeof(buf));
  484.  
  485.             if(n < 0) {
  486.                 fprintf(logfp, "%s: read from: %s failed: ",
  487.                         prog, http->host);
  488.                 fperror(logfp, "");
  489.  
  490.                 eno = safe_strerror(errno);
  491.                 sprintf(buf, CFAIL, http->hostport, eno);
  492.                 freez(eno);
  493.                 write_socket(csp->cfd, buf, strlen(buf));
  494.                 return;
  495.             }
  496.  
  497.             if(n == 0) break; /* "game over, man" */
  498.  
  499.             /* if this is an SSL connection or we're in the body
  500.              * of the server document, just write it to the client.
  501.              */
  502.  
  503.             if(server_body || http->ssl) {
  504.                 /* just write */
  505.                 if(write_socket(csp->cfd, buf, n) != n) {
  506.                     fprintf(logfp, "%s: write to client failed: ",
  507.                             prog);
  508.                     fperror(logfp, "");
  509.                     return;
  510.                 }
  511.                 continue;
  512.             } else {
  513.                 /* we're still looking for the end of the
  514.                  * server's header ... (does that make header
  515.                  * parsing an "out of body experience" ?
  516.                  */
  517.  
  518.                 /* buffer up the data we just read */
  519.                 add_to_iob(csp, buf, n);
  520.  
  521.                 /* get header lines from the iob */
  522.                 while((p = get_header(csp))) {
  523.                     if(*p == '\0') {
  524.                         /* see following note */
  525.                         break;
  526.                     }
  527.                     enlist(csp->headers, p);
  528.                     freez(p);
  529.                 }
  530.  
  531.                 /* NOTE: there are no "empty" headers so
  532.                  * if the pointer `p' is not NULL we must
  533.                  * assume that we reached the end of the
  534.                  * buffer before we hit the end of the header.
  535.                  *
  536.                  * Since we have to wait for more from the
  537.                  * server before we can parse the headers
  538.                  * we just continue here.
  539.                  */
  540.  
  541.                 if(p) continue;
  542.  
  543.                 /* we have now received the entire header.
  544.                  * filter it and send the result to the client
  545.                  */
  546.  
  547.                 hdr = sed(
  548.                     server_patterns,
  549.                     add_server_headers,
  550.                     csp);
  551.  
  552.                 n   = strlen(hdr);
  553.  
  554.                 /* write the server's (modified) header to
  555.                  * the client (along with anything else that
  556.                  * may be in the buffer)
  557.                  */
  558.  
  559.                 if((write_socket(csp->cfd, hdr, n) != n)
  560.                 || (flush_socket(csp->cfd, csp   ) <  0)) {
  561.                     if(DEBUG(CON)) {
  562.                         fprintf(logfp,
  563.                             "%s: write header to client failed: ",
  564.                                 prog);
  565.                         fperror(logfp, "");
  566.                     }
  567.                     /* the write failed, so don't bother
  568.                      * mentioning it to the client...
  569.                      * it probably can't hear us anyway.
  570.                      */
  571.                     freez(hdr);
  572.                     return;
  573.                 }
  574.  
  575.                 /* we're finished with the server's header */
  576.  
  577.                 freez(hdr);
  578.                 server_body = 1;
  579.             }
  580.             continue;
  581.         }
  582.  
  583.         return; /* huh? we should never get here */
  584.     }
  585. }
  586.  
  587. void
  588. serve(struct client_state *csp)
  589. {
  590.     chat(csp);
  591.     close_socket(csp->cfd);
  592.  
  593.     if(csp->sfd >= 0) {
  594.         close_socket(csp->sfd);
  595.     }
  596.  
  597.     csp->active = 0;
  598. }
  599.  
  600. #ifdef __BEOS__
  601. int32
  602. server_thread(void *data)
  603. {
  604.     serve((struct client_state *) data);
  605.     return 0;
  606. }
  607. #endif
  608.  
  609. int
  610. main(int argc, char *argv[])
  611. {
  612.     char buf[BUFSIZ];
  613.     int cfd, bfd;
  614.     char *p, *q;
  615.     extern char *optarg;
  616.     extern int optind;
  617.     struct client_state *csp;
  618.  
  619.     char *default_configfile = NULL;
  620.     char *configfile = NULL;
  621.     FILE *configfp = NULL;
  622.  
  623.     int err = 0;
  624.  
  625.     prog = argv[0];
  626.  
  627.     logfp = stdout;
  628.  
  629.     init_proxy_args(argc, argv);
  630.  
  631.     cfd  = -1;
  632.  
  633. #ifdef _WIN32
  634.     default_configfile = "junkbstr.ini";
  635. #endif
  636.  
  637.     configfile = default_configfile;
  638.  
  639.     if(argc > 1) {
  640.         configfile = argv[1];
  641.     }
  642.  
  643.     if(configfile) {
  644.         if((configfp = fopen(configfile, "r")) == NULL) {
  645.             if(configfile != default_configfile) {
  646.                 fprintf(logfp,
  647.                     "%s: can't open configuration file '%s': ",
  648.                         prog, configfile);
  649.                 fperror(logfp, "");
  650.                 exit(1);
  651.             }
  652.         }
  653.     }
  654.  
  655.     if(configfp) {
  656.         int line_num = 0;
  657.         while(fgets(buf, sizeof(buf), configfp)) {
  658.             char cmd[BUFSIZ];
  659.             char arg[BUFSIZ];
  660.             char tmp[BUFSIZ];
  661.  
  662.             line_num++;
  663.  
  664.             strcpy(tmp, buf);
  665.  
  666.             if((p = strpbrk(tmp, "#\r\n"))) *p = '\0';
  667.  
  668.             p = tmp;
  669.  
  670.             /* leading skip whitespace */
  671.             while(*p && ((*p == ' ') || (*p == '\t'))) p++;
  672.  
  673.             q = cmd;
  674.  
  675.             while(*p && (*p != ' ') && (*p != '\t')) *q++ = *p++;
  676.  
  677.             *q = '\0';
  678.  
  679.             while(*p && ((*p == ' ') || (*p == '\t'))) p++;
  680.  
  681.             strcpy(arg, p);
  682.  
  683.             p = arg + strlen(arg) - 1;
  684.  
  685.             /* ignore trailing whitespace */
  686.             while(*p && ((*p == ' ') || (*p == '\t'))) *p-- = '\0';
  687.  
  688.             if(*cmd == '\0') continue;
  689.  
  690.             /* insure the command field is lower case */
  691.             for(p=cmd; *p; p++) if(isupper(*p)) *p = tolower(*p);
  692.  
  693.             savearg(cmd, arg);
  694.  
  695.             if(strcmp(cmd, "trustfile") == 0) {
  696.                 trustfile = strdup(arg);
  697.                 continue;
  698.             }
  699.  
  700.             if(strcmp(cmd, "trust_info_url") == 0) {
  701.                 enlist(trust_info, arg);
  702.                 continue;
  703.             }
  704.  
  705.             if(strcmp(cmd, "debug") == 0) {
  706.                 debug |= atoi(arg);
  707.                 continue;
  708.             }
  709.  
  710.             if(strcmp(cmd, "add-forwarded-header") == 0) {
  711.                 add_forwarded = 1;
  712.                 continue;
  713.             }
  714.  
  715.             if(strcmp(cmd, "single-threaded") == 0) {
  716.                 multi_threaded = 0;
  717.                 continue;
  718.             }
  719.  
  720.             if(strcmp(cmd, "suppress-vanilla-wafer") == 0) {
  721.                 suppress_vanilla_wafer = 1;
  722.                 continue;
  723.             }
  724.  
  725.             if(strcmp(cmd, "wafer") == 0) {
  726.                 enlist(wafer_list, arg);
  727.                 continue;
  728.             }
  729.  
  730.             if(strcmp(cmd, "add-header") == 0) {
  731.                 enlist(xtra_list,  arg);
  732.                 continue;
  733.             }
  734.  
  735.             if(strcmp(cmd, "cookiefile") == 0) {
  736.                 cookiefile = strdup(arg);
  737.                 continue;
  738.             }
  739.  
  740.             if(strcmp(cmd, "logfile") == 0) {
  741.                 logfile = strdup(arg);
  742.                 continue;
  743.             }
  744.  
  745.             if(strcmp(cmd, "blockfile") == 0) {
  746.                 blockfile = strdup(arg);
  747.                 continue;
  748.             }
  749.  
  750.             if(strcmp(cmd, "jarfile") == 0) {
  751.                 jarfile = strdup(arg);
  752.                 continue;
  753.             }
  754.  
  755.             if(strcmp(cmd, "listen-address") == 0) {
  756.                 haddr = strdup(arg);
  757.                 continue;
  758.             }
  759.  
  760.             if(strcmp(cmd, "forwardfile") == 0) {
  761.                 forwardfile = strdup(arg);
  762.                 continue;
  763.             }
  764.  
  765.             if(strcmp(cmd, "aclfile") == 0) {
  766.                 aclfile = strdup(arg);
  767.                 continue;
  768.             }
  769.  
  770.             if(strcmp(cmd, "user-agent") == 0) {
  771.                 uagent = strdup(arg);
  772.                 continue;
  773.             }
  774.  
  775.             if((strcmp(cmd, "referrer") == 0)
  776.             || (strcmp(cmd, "referer" ) == 0)) {
  777.                 referrer = strdup(arg);
  778.                 continue;
  779.             }
  780.  
  781.             if(strcmp(cmd, "from") == 0) {
  782.                 from = strdup(arg);
  783.                 continue;
  784.             }
  785.  
  786.             if(strcmp(cmd, "hide-console") == 0) {
  787.                 hideConsole = 1;
  788.                 continue;
  789.             }
  790.  
  791.             fprintf(logfp,
  792.                 "%s: unrecognized directive "
  793.                 "in configuration file "
  794.                 "at line number %d:\n%s",
  795.                 prog, line_num, buf);
  796.             err = 1;
  797.         }
  798.         fclose(configfp);
  799.     }
  800.  
  801.     if(err) exit(1);
  802.  
  803. #ifdef _WIN32
  804.     InitWin32();
  805. #endif
  806.  
  807.     if(logfile) {
  808.         FILE *tlog = fopen(logfile, "a");
  809.         if(tlog == NULL) {
  810.             fprintf(logfp, "%s: can't open logfile '%s': ",
  811.                 prog, logfile);
  812.             fperror(logfp, "");
  813.             err = 1;
  814.         }
  815.         logfp = tlog;
  816.     }
  817.  
  818.     setbuf(logfp, NULL);
  819.  
  820.     if(cookiefile)   add_loader(load_cookiefile);
  821.  
  822.     if(blockfile)    add_loader(load_blockfile);
  823.  
  824.     if(trustfile)    add_loader(load_trustfile);
  825.  
  826.     if(forwardfile)  add_loader(load_forwardfile);
  827.  
  828.     if(aclfile)      add_loader(load_aclfile);
  829.  
  830.     if(jarfile) {
  831.         jar = fopen(jarfile, "a");
  832.         if(jar == NULL) {
  833.             fprintf(logfp, "%s: can't open jarfile '%s': ",
  834.                 prog, jarfile);
  835.             fperror(logfp, "");
  836.             err = 1;
  837.         }
  838.         setbuf(jar, NULL);
  839.     }
  840.  
  841.     if(haddr) {
  842.         if((p = strchr(haddr, ':'))) {
  843.             *p++ = '\0';
  844.             if(*p) hport = atoi(p);
  845.         }
  846.  
  847.         if(hport <= 0) {
  848.             *--p = ':' ;
  849.             fprintf(logfp, "%s: invalid bind port spec %s",
  850.                 prog, haddr);
  851.             err = 1;
  852.         }
  853.         if(*haddr == '\0') haddr = NULL;
  854.     }
  855.  
  856.     if(run_loader(NULL)) err = 1;
  857.  
  858.     if(err) exit(1);
  859.  
  860.     /* if we're logging cookies in a cookie jar,
  861.      * and the user has not supplied any wafers,
  862.      * and the user has not told us to suppress the vanilla wafer,
  863.      * then send the vanilla wafer.
  864.      */
  865.     if((jarfile != NULL)
  866.     && (wafer_list->next == NULL)
  867.     && (suppress_vanilla_wafer == 0)) {
  868.         enlist(wafer_list, VANILLA_WAFER);
  869.     }
  870.  
  871.     if(DEBUG(CON)) {
  872.         fprintf(logfp, "%s: bind (%s, %d)\n",
  873.             prog, haddr ? haddr : "INADDR_ANY", hport);
  874.     }
  875.  
  876.     bfd = bind_port(haddr, hport);
  877.  
  878.     if(bfd < 0) {
  879.         fprintf(logfp, "%s: can't bind %s:%d: ",
  880.             prog, haddr ? haddr : "INADDR_ANY", hport);
  881.         fperror(logfp, "");
  882.         fprintf(logfp,
  883.             "There may be another junkbuster or some other "
  884.             "proxy running on port %d\n", hport);
  885.         err = 1;
  886.     }
  887.  
  888.     if(err) exit(1);
  889.  
  890.     end_proxy_args();
  891.  
  892. #ifndef _WIN32
  893.     signal(SIGPIPE, SIG_IGN);
  894.     signal(SIGCHLD, SIG_IGN);
  895. #endif
  896.  
  897. #ifdef _WIN32
  898. {
  899.     /* print a verbose messages about FAQ's and such */
  900.     extern char *win32_blurb;
  901.     if(logfp == stdout) fprintf(logfp, win32_blurb);
  902. }
  903. #endif
  904.  
  905.     for(;;) {
  906.  
  907. #if !defined(_WIN32) && !defined(__BEOS__)
  908.         while(waitpid(-1, NULL, WNOHANG) > 0) {
  909.             /* zombie children */
  910.         }
  911. #endif
  912.         sweep();
  913.  
  914.         if(DEBUG(CON)) {
  915.             fprintf(logfp, "%s: accept connection ... ", prog);
  916.         }
  917.  
  918.         cfd = accept_connection(bfd);
  919.  
  920.         if(cfd < 0) {
  921.             if(DEBUG(CON)) {
  922.                 fprintf(logfp, "%s: accept failed: ", prog);
  923.                 fperror(logfp, "");
  924.             }
  925.             continue;
  926.         } else {
  927.             if(DEBUG(CON)) {
  928.                 fprintf(logfp, "OK\n");
  929.             }
  930.         }
  931.  
  932.         csp = (struct client_state *) malloc(sizeof(*csp));
  933.  
  934.         if(csp == NULL) {
  935.             fprintf(logfp, "%s: malloc(%d) for csp failed: ", prog, sizeof(*csp));
  936.             fperror(logfp, "");
  937.             close_socket(cfd);
  938.             continue;
  939.         }
  940.  
  941.         memset(csp, '\0', sizeof(*csp));
  942.  
  943.         csp->active = 1;
  944.         csp->cfd    = cfd;
  945.         csp->sfd    =  -1;
  946.         csp->ip_addr_str  = remote_ip_str;
  947.         csp->ip_addr_long = remote_ip_long;
  948.  
  949.         /* add it to the list of clients */
  950.         csp->next = clients->next;
  951.         clients->next = csp;
  952.  
  953.         if(run_loader(csp)) {
  954.             fprintf(logfp, "%s: a loader failed - must exit\n", prog);
  955.             exit(1);
  956.         }
  957.  
  958.         if(multi_threaded) {
  959.             int child_id;
  960.  
  961. /* this is a switch() statment in the C preprocessor - ugh */
  962. #undef SELECTED_ONE_OPTION
  963.  
  964. #if defined(_WIN32) && !defined(SELECTED_ONE_OPTION)
  965. #define SELECTED_ONE_OPTION
  966.             child_id = _beginthread(
  967.                     (void*)serve,
  968.                     64 * 1024,
  969.                     csp);
  970. #endif
  971.  
  972. #if defined(__BEOS__) && !defined(SELECTED_ONE_OPTION)
  973. #define SELECTED_ONE_OPTION
  974.             {
  975.                 thread_id tid = spawn_thread
  976.                     (server_thread, "server", B_NORMAL_PRIORITY, csp);
  977.  
  978.                 if ((tid >= 0) && (resume_thread(tid) == B_OK)) {
  979.                     child_id = (int) tid;
  980.                 } else {
  981.                     child_id = -1;
  982.                 }
  983.             }
  984. #endif
  985.  
  986. #if !defined(SELECTED_ONE_OPTION)
  987.             child_id = fork();
  988. #endif
  989.  
  990. #undef SELECTED_ONE_OPTION
  991. /* end of cpp switch() */
  992.  
  993.             if(child_id < 0) {    /* failed */
  994.                 fprintf(logfp, "%s: can't fork: ", prog);
  995.                 fperror(logfp, "");
  996.  
  997.                 sprintf(buf , "%s: can't fork: errno = %d",
  998.                     prog, errno);
  999.  
  1000.                 write_socket(csp->cfd, buf, strlen(buf));
  1001.                 close_socket(csp->cfd);
  1002.                 csp->active = 0;
  1003.                 sleep(5);
  1004.                 continue;
  1005.             }
  1006. #if !defined(_WIN32) && !defined(__BEOS__)
  1007.             /* This block is only needed when using fork().
  1008.              * When using threads, the server thread was
  1009.              * created and run by the call to _beginthread().
  1010.              */
  1011.             if(child_id == 0) {    /* child */
  1012.  
  1013.                 serve(csp);
  1014.                 _exit(0);
  1015.  
  1016.             } else {        /* parent */
  1017.  
  1018.                 /* in a fork()'d environment, the parent's
  1019.                  * copy of the client socket and the CSP
  1020.                  * are not used.
  1021.                  */
  1022.  
  1023.                 close_socket(csp->cfd);
  1024.                 csp->active = 0;
  1025.             }
  1026. #endif
  1027.         } else {
  1028.             serve(csp);
  1029.         }
  1030.     }
  1031.     /* NOTREACHED */
  1032. }
  1033.  
  1034.  
  1035. char *
  1036. safe_strerror(int err)
  1037. {
  1038.     char buf[BUFSIZ];
  1039.     char *s = NULL;
  1040.  
  1041. #ifndef   NOSTRERROR
  1042.     s = strerror(err);
  1043. #endif /* NOSTRERROR */
  1044.  
  1045.     if(s == NULL) {
  1046.         sprintf(buf, "(errno = %d)", err);
  1047.         s = buf;
  1048.     }
  1049.  
  1050.     return(strdup(s));
  1051. }
  1052.  
  1053. void
  1054. fperror(FILE *fp, char *str)
  1055. {
  1056.     char *eno = safe_strerror(errno);
  1057.  
  1058.     if(str && *str) {
  1059.         fprintf(fp, "%s: %s\n", str, eno);
  1060.     } else {
  1061.         fprintf(fp, "%s\n", eno);
  1062.     }
  1063.     freez(eno);
  1064. }
  1065.