process.c
changeset 14 51eb85ae4de4
parent 13 23a242d7b7fa
child 15 2706fc514dea
equal deleted inserted replaced
13:23a242d7b7fa 14:51eb85ae4de4
    29 */
    29 */
    30 
    30 
    31 #include "volta.h"
    31 #include "volta.h"
    32 #include "db.h"
    32 #include "db.h"
    33 
    33 
       
    34 
       
    35 /*
       
    36  * Given a redirect +line+ from squid, send it to the parser,
       
    37  * perform database lookups, and conditonally perform the rewrite.
       
    38  *
       
    39  */
    34 void
    40 void
    35 process( char *line )
    41 process( char *line )
    36 {
    42 {
    37 	request *p_request = parse( line );
    43 	parsed *p_request = parse_request( line ), *rule = NULL;
    38 	rewrite *p_rewrite = prepare_rewrite( p_request );
    44 	parsed *results[ DB_RESULTS_MAX ] = { NULL }; /* array of response matches */
       
    45 	unsigned int rcount = 0;
    39 
    46 
    40 	/* count lines in debugmode */
    47 	/* count lines in debugmode */
    41 	if ( v.debugmode > 2 ) v.timer.lines++;
    48 	if ( v.debugmode > 2 ) v.timer.lines++;
    42 
    49 
    43 	/* If parsing failed or there wasn't a successful rewrite match,
    50 	/* If request parsing failed, return a blank line to squid
    44 	 * return a blank line to squid to allow the request to pass
    51 	   to allow the request to pass through unmolested. */
    45 	 * through unmolested. */
    52 	if ( p_request == NULL ) {
    46 	if ( p_request == NULL || p_rewrite == NULL ) {
       
    47 		out( "\n" );
    53 		out( "\n" );
    48 		finish_request( p_request );
    54 		finish_parsed( p_request );
    49 		finish_rewrite( p_rewrite );
       
    50 		return;
    55 		return;
    51 	}
    56 	}
    52 
    57 
    53 	if ( v.debugmode < 4 ) {
    58 	/*
    54 		if ( p_rewrite->redir == REDIR_TEMPORARY ) printf( "302:" );
    59 	 * Main rewrite logic.
    55 		if ( p_rewrite->redir == REDIR_PERMANENT ) printf( "301:" );
    60 	 *
       
    61 	 * First, try and match the host exactly.
       
    62 	 *
       
    63 	 * Second, match the TLD of the host, so separate rules aren't needed for
       
    64 	 * every possible subdomain of one particular domain.
       
    65 	 *
       
    66 	 * Finally, look for '*', if for some reason the rules provided don't care to
       
    67 	 * match specific hosts, and instead just match on any path.
       
    68 	 *
       
    69 	 * If DB matches are found at any step above, the rules are tried in order
       
    70 	 * to attempt a match against the path.  Exact string match attempted
       
    71 	 * first, then fallback to regexp.
       
    72 	 * 
       
    73 	 * First rule match wins, and elements of the URL are rewritten based on
       
    74 	 * what is present in the rule -- any missing parts just use the original
       
    75 	 * URL element.  (this way, you can rewrite just the host and leave the
       
    76 	 * path intact, or redir to https, for example.)
       
    77 	 *
       
    78 	 */
       
    79 	rcount = find_records( p_request->host, results );
       
    80 	rule = find_matching_rule( results, rcount, p_request );
    56 
    81 
    57 		if ( p_request->scheme || p_rewrite->scheme )
    82 	if ( rule == NULL ) {
    58 			printf( "%s", p_rewrite->scheme ? p_rewrite->scheme : p_request->scheme );
    83 		reset_results( results, rcount );
    59 		printf( "%s", p_rewrite->host   ? p_rewrite->host   : p_request->host );
    84 		rcount = find_records( p_request->tld, results );
    60 		printf( "%s", p_rewrite->path   ? p_rewrite->path   : p_request->path );
    85 		rule = find_matching_rule( results, rcount, p_request );
    61 		if ( p_request->port != 0 || p_rewrite->port != 0 )
       
    62 			printf( ":%d", p_rewrite->port ? p_rewrite->port : p_request->port );
       
    63 		printf("\n");
       
    64 	}
       
    65 	else {
       
    66 		debug( 5, LOC, "Rewrite match on %s/%s\n", p_request->host, p_request->path );
       
    67 		debug( 5, LOC, "    --> %s/%s\n", p_rewrite->host, p_rewrite->path );
       
    68 	}
    86 	}
    69 
    87 
       
    88 	if ( rule == NULL ) {
       
    89 		reset_results( results, rcount );
       
    90 		rcount = find_records( "*", results );
       
    91 		rule = find_matching_rule( results, rcount, p_request );
       
    92 	}
    70 
    93 
    71 	/* unsigned long hst, net; */
    94 	/* no matching rule still?  no need to rewrite anything. */
    72 	/* hst = inet_lnaof( *(p_request->client_ip) ); */
    95 	if ( rule == NULL ) {
    73 	/* net = inet_netof( *(p_request->client_ip) ); */
    96 		out( "\n" );
    74 	/* printf("%14s : net=0x%08lX host=0x%08lX\n", inet_ntoa( *(p_request->client_ip) ), net, hst); */
    97 	}
    75 	/* printf("%14s : net=%lu host=%lu\n", inet_ntoa( *(p_request->client_ip) ), net, hst); */
    98 	/* otherwise, perform the rewrite */
       
    99 	else {
       
   100 		rewrite( p_request, rule );
       
   101 	}
    76 
   102 
    77 	/*
   103 	reset_results( results, rcount );
    78 	 * create function bigint_to_inet(bigint) returns inet as $$
   104 	finish_parsed( p_request );
    79 	 * select
       
    80 	 * (($1>>24&255)||'.'||($1>>16&255)||'.'||($1>>8&255)||'.'||($1>>0&255))::inet
       
    81 	 * $$ language sql;
       
    82 	 * */
       
    83 
       
    84 	/*
       
    85 	char ip[ INET_ADDRSTRLEN ];
       
    86 	inet_ntop( AF_INET, p_request->client_ip, ip, INET_ADDRSTRLEN );
       
    87 	printf( "%s\n", ip );
       
    88 	*/
       
    89 
       
    90 	finish_request( p_request );
       
    91 	finish_rewrite( p_rewrite );
       
    92 	return;
   105 	return;
    93 }
   106 }
    94 
   107 
       
   108 
       
   109 /*
       
   110  * Output a rewritten URL for squid.
       
   111  *
       
   112  */
       
   113 void
       
   114 rewrite( parsed *request, parsed *rule )
       
   115 {
       
   116 	if ( rule == NULL || v.debugmode >= 5 ) return;
       
   117 
       
   118 	if ( rule->redir ) printf( "%s:", rule->redir );
       
   119 	printf( "%s%s", (rule->scheme ? rule->scheme : request->scheme), rule->host );
       
   120 	if ( rule->port ) printf( ":%s", rule->port );
       
   121 	printf( "%s", rule->path ? rule->path : request->path );
       
   122 
       
   123 	printf("\n");
       
   124 	return;
       
   125 }
       
   126 
       
   127 
       
   128 /*
       
   129  * Search through a result set, and return the first
       
   130  * matching path (or NULL).
       
   131  *
       
   132  */
       
   133 parsed *
       
   134 find_matching_rule( parsed **results, unsigned int resultcount, parsed *p_request )
       
   135 {
       
   136 	unsigned int i = 0;
       
   137 	int re_rv;
       
   138 	regex_t re;
       
   139 	char re_err[128];
       
   140 	parsed *rule = NULL;
       
   141 
       
   142 	if ( resultcount == 0 || p_request->path == NULL ) return( NULL );
       
   143 
       
   144 	for ( i = 0; i < resultcount; i++ ) {
       
   145 		/* quick comparison */
       
   146 		if ( (strcasecmp( results[i]->path_re, p_request->path ) == 0) ||
       
   147 			 (strcmp( results[i]->path_re, "*" ) == 0) ) {
       
   148 			debug( 4, LOC, "Rule %d match (non regexp)\n", i+1 );
       
   149 			rule = results[i];
       
   150 			break;
       
   151 		}
       
   152 
       
   153 		/* compile the regexp */
       
   154 		if ( (re_rv = regcomp( &re, results[i]->path_re, REG_EXTENDED | REG_NOSUB )) != 0 ) {
       
   155 			regerror( re_rv, &re, re_err, 128 );
       
   156 			debug( 4, LOC, "Invalid regex: \"%s\": %s\n", results[i]->path_re, re_err );
       
   157 			regfree( &re );
       
   158 			continue;
       
   159 		}
       
   160 
       
   161 		/* compare! */
       
   162 		if ( (regexec( &re, p_request->path, 0, NULL, 0 )) == 0 ) {
       
   163 			debug( 4, LOC, "Rule %d match (regexp)\n", i+1 );
       
   164 			rule = results[i];
       
   165 			regfree( &re );
       
   166 			break;
       
   167 		}
       
   168 	}
       
   169 
       
   170 	return( rule );
       
   171 }
       
   172 
       
   173 
       
   174 /*
       
   175  * Clear the results array and free memory.
       
   176  *
       
   177  */
       
   178 void
       
   179 reset_results( parsed **results, unsigned int count )
       
   180 {
       
   181 	unsigned int i = 0;
       
   182 
       
   183 	for ( ; i < count && i < DB_RESULTS_MAX; i++ ) finish_parsed( results[i] );
       
   184 	memset( results, 0, sizeof(results) );
       
   185 
       
   186 	return;
       
   187 }
       
   188