home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2000 January / PCW0001.ISO / software / hw / pc2000 / junkbust.exe / jcc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-07  |  24.2 KB  |  1,117 lines

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