Author: Alexander Zangerl <az@debian.org>
Subject: add support for squid 3

--- a/rewrite.c
+++ b/rewrite.c
@@ -25,7 +25,8 @@
  *
  */
 
-#include<stdio.h>
+#include <stdio.h>
+#include <stdlib.h>
 #ifdef LINUX
 #include<string.h>
 #else
@@ -61,89 +62,85 @@ static int match_accel(char *, char *, i
 
 int
 parse_buff(char *buff, char **url, char **src_addr, char **ident,
-	     char **method, char **urlgroup, ip_acl *ip, pattern_item *p)
-	     //char **method, ip_acl *ip, pattern_item *p)
+	   char **method, int *chanid, ip_acl *ip)
 {
-    int c, i;
-    struct in_addr address;
-    char *token, *new_token;
-    char *end[5];
-    //char **urlgroup;
-    
-    c = 0;
-    *urlgroup = '\0';
-
-    token = strchr(buff,' ');
-    if ( token ) {       /* URL */
-	c++;
-	*token = '\0';
-	end[0] = token;
-	*url = buff;
-
-	new_token = strchr(++token,' ');
-	if (new_token) {     /* Address */
-	    c++;
-	    *new_token = '\0';
-	    end[1] = new_token;
-	    *src_addr = token;
-
-	    token = strchr(++new_token,' ');
-	    if (token) {      /* Ident */
-		c++;
-		*token = '\0';
-		end[2] = token;
-		*ident = new_token;
-
-		/* this might be the last token, check for a space
-		 or a newline */
-		if (!( new_token = strchr(++token,' ')))
-			new_token = strchr(token,'\n');
-		if (new_token) { /* Method */
-		    c++;
-		    *new_token = '\0';
-		    end[3] = new_token;
-		    *method = token;
-
-		    /* this will be the last token, stop at a space or newline
-                       to avoid spaces in urlgroup.  maybe be too rare to 
-                       waste a test on */
-		    if (!( token = strchr(++new_token,' ')))
-			token = strchr(new_token,'\n');
-		    if (token) {      /* urlgroup */
-			c++;
-			*token = '\0';
-			end[4] = token;
-			/* squid sends "-" as indicator for no urlgroup  */
-			if (strcmp(new_token,"-"))
-			   *urlgroup = new_token;
-
-		}
-	    }
-
-	    }
-	}
-    }
-
-    /* 4 pre 2.6 or no urlgroup
-       5 post 2.6 with a urlgroup */
-    if(( c != 5) && ( c != 4)) {
-	for(i = 0; i < c; i++) {
-	    if ( end[i] )
-		*end[i] = ' ';
-	}
-	mylog(ERROR, "incorrect input (%d): %s", c, buff);
-	return 1;
-    }
-
-    
+   int j;
+   struct in_addr address;
+   char *token;
+   char *next_token = buff;
+   char *errorptr;
+
+   /* az [2015-10-23 Fri 21:20]
+      goodbye squid2..3.3, hello squid3.5
+
+      no more url groups; a numeric channel id, a url, space
+      and extra stuff or a newline.
+      apparently extras was configurable with url_rewrite_extras,
+      but that has been removed in one of the newest squid
+      versions (the docs re this are pretty damn confused...)
+
+      [channel-ID <SP>] URL [<SP> extras]<NL>
+      and extras are supposed to be (adjustable in 3.5,
+      adjustability removed(??) in 4)
+      ip/fqdn username method myip=<ip> myport=<port>
+   */
+
+   /* start of url or start of extras? */
+   if (!(token = strsep(&next_token, " ")))
+   {
+      mylog(ERROR, "invalid input, no extras in (%s)", buff);
+      return 1;
+   }
+
+   /* channel-id? must be numeric */
+   j = (int)strtol(buff, &errorptr, 10);
+   if (!*errorptr)	/* conversion successful */
+   {
+      *chanid = j;
+      *url = next_token;
+
+      /* now find end of url/start of ip/fqdn */
+      if (!(token = strsep(&next_token, " ")))
+      {
+	 mylog(ERROR, "invalid input, no ip/fqdn in (%s)", buff);
+	 return 1;
+      }
+   }
+   else
+   {
+      *url = buff;
+      *chanid = -1;	/* no channel id present; it is non-negative when used */
+   }
+
+   /* find end of ip/fqdn */
+   if (!(token = strsep(&next_token, " ")))
+   {
+      mylog(ERROR, "invalid input, no username in (%s)", buff);
+      return 1;
+   }
+   *src_addr = token;
+
+   /* find end of username */
+   if (!(token = strsep(&next_token, " ")))
+   {
+      mylog(ERROR, "invalid input, no method in (%s)", buff);
+      return 1;
+   }
+   *ident = token;
+
+   /* find end of method */
+   if (!(token = strsep(&next_token, " ")))
+   {
+      mylog(ERROR, "invalid input, no kv pairs in (%s)", buff);
+      return 1;
+   }
+   *method = token;
+   /* and the rest we don't care about... */
 
 #ifdef DEBUG
-    mylog(DEBG, "Request: %s %s %s %s\n", *url, *src_addr, *ident, *method);
+   mylog(DEBG, "Request: %d %s %s %s %s\n", *chanid, *url, *src_addr, *ident, *method);
 #endif    
     
-    /* forward all methods */
-    /* removed restriction to GET or ICP_QUERY */
-	    
     /* URL with less than 7 char is invalid */
     if(strlen(*url) <= 7) {
 	mylog(ERROR, "strlen url to short (%d)\n", strlen(*url));
@@ -159,7 +156,7 @@ parse_buff(char *buff, char **url, char
        it is already loaded, when squid runs - so not much waste of
        memory ;-) */
     if ( (address.s_addr = inet_addr(*src_addr)) == -1 ) {
-	mylog(ERROR, "client IP address not valid %s\n",
+	mylog(ERROR, "client IP address (%s) not valid\n",
 	    *src_addr ? *src_addr : "");
 	if ( token )
 	    *token = '/';
@@ -171,7 +168,7 @@ parse_buff(char *buff, char **url, char
     /* make sure the IP source address matches that of the ones in our list */
     if( ip_access_check(address, ip) == IP_DENY ) {
 #ifdef DEBUG
-	mylog(DEBG, "client IP address %s not matched\n", *src_addr);
+	mylog(DEBG, "client IP address (%s) not matched\n", *src_addr);
 #endif  
 	return 1;
     }
--- a/main.c
+++ b/main.c
@@ -23,6 +23,7 @@
 
 #include<stdio.h>
 #include<stdlib.h>
+#include <unistd.h>
 #include<string.h>
 #include<sys/signal.h>
 #include<sys/types.h>
@@ -75,7 +76,7 @@ int main(int argc, char **argv)
 /*    int first_run = 1; */
     char buff[BUFSIZE];
     char redirect_url[BUFSIZE];
-    char *url, *src_addr, *ident, *method, *urlgroup;
+    char *url, *src_addr, *ident, *method, *urlgroup = "";
     int finished = 0;
     int buff_status = 0;
     ip_acl *ip_list = NULL;
@@ -93,7 +94,7 @@ int main(int argc, char **argv)
     /* main program loop, executed  forever more unless terminated
        by a kill signal or EOF on stdin */
     while(! finished) {
-	int val;
+       int val, chanid;
 	
 	sig_hup = 0;
 	mylog(INFO, "Freeing up old linked lists\n");
@@ -111,49 +112,86 @@ int main(int argc, char **argv)
 	mylog(INFO, "%s (PID %d) started\n", APPNAME, (int)getpid());
 	
 	while((!sig_hup) && (fgets(buff, BUFSIZE, stdin) != NULL)){
-	    if(echo_mode) {
-		puts("");
-		fflush(stdout);
-		continue;
+	    if(echo_mode) {	/* this doesn't work if a channel-id is present. */
+	       printf("ERR\n");
+	       fflush(stdout);
+	       continue;
 	    }
-	    /* separate the four fields from the single input line of stdin */
+	    /* separate the fields from the single input line of stdin */
 	    buff_status = parse_buff(buff, &url, &src_addr, &ident, &method,
-				     &urlgroup, ip_list, pattern_list);
+				     &chanid, ip_list);
 	    /* error during parsing the passed line from squid - no rewrite */
 	    if(buff_status) {
-		puts("");
-		fflush(stdout);
-		continue;
+	       if (chanid != -1)
+		  printf("%d ",chanid);
+	       printf("ERR\n");
+	       fflush(stdout);
+	       continue;
 	    }
 	    /* check echo_mode again (sighup)*/
 	    if(echo_mode) {
-		puts("");
-		fflush(stdout);
-		mylog(ERROR, "Invalid condition - continuing in ECHO mode\n");
-		continue;
+	       if (chanid != -1)
+		  printf("%d ",chanid);
+	       printf("ERR\n");
+	       fflush(stdout);
+	       mylog(ERROR, "Invalid condition - continuing in ECHO mode\n");
+	       continue;
 	    }
 	    /* find a rule for rewriting the URL */
 	    val = pattern_compare(url, urlgroup, redirect_url, pattern_list);
-	    if( val < 1 ) {
-		/* no rule found = 0, or ABORT rule -N */
-		puts("");
-		fflush(stdout);
-		continue;
+	    if( val < 1 )
+	    {
+	       /* no rule found = 0, or ABORT rule -N */
+	       if (chanid != -1)
+		  printf("%d ", chanid);
+	       printf("OK\n");
+	       fflush(stdout);
+	       continue;
 	    }
-	    else {
-		/* redirect_url contains the replacement URL */
-		if ( redirect_url[0] == '\0' ) {
-		    /* regex[i] abort, i.e. empty replacement URL */
-		    puts("");
-		    fflush(stdout);
-		}
-		else {
-		    printf("%s %s %s %s\n",
-			   redirect_url, src_addr, ident, method);
-		    fflush(stdout);
-		    mylog(MATCH, "%s %s %s %d\n", src_addr, url, redirect_url,
+	    else
+	    {
+	       /* redirect_url contains the replacement URL */
+	       if ( redirect_url[0] == '\0' ) {
+		  /* regex[i] abort, i.e. empty replacement URL */
+		  if (chanid != -1)
+		     printf("%d ", chanid);
+		  printf("OK\n");
+		  fflush(stdout);
+	       }
+	       else
+	       {
+		  int code;
+		  char *just_url;
+
+		  if (chanid != -1)
+		     printf("%d ", chanid);
+
+		  /* az [2015-10-23 Fri 23:19]
+		     squid3.4 and 3.5 no longer support the 30X:url format,
+		     at least according to SOME of the very inconsistent docs.
+
+		     the protocol helper descripton page
+		     http://wiki.squid-cache.org/Features/AddonHelpers
+		     makes little sense; the protocol it describes is not at
+		     all what the url_rewrite_program describes.
+		     so i'll take a guess :-(
+
+		     the tool should provide a very different response
+		     for these...the sscanf isn't very efficient, but
+		     i can't be bothered rewriting the rules parser
+		     to support a separate code field...
+		  */
+		  if (2 == sscanf(redirect_url, "%d:%ms", &code, &just_url))
+		  {
+		     printf("OK code=%d url=%s\n", code, just_url);
+		     free(just_url);
+		  }
+		  else
+		     printf("OK rewrite-url=%s\n", redirect_url);
+		  fflush(stdout);
+		  mylog(MATCH, "%s %s %s %d\n", src_addr, url, redirect_url,
 			val);
-		}
+	       }
 	    }
 	}
 	if(! sig_hup)
--- a/rewrite.h
+++ b/rewrite.h
@@ -28,7 +28,7 @@
 #ifndef REWRITE_H
 #define REWRITE_H
 
-extern int parse_buff(char *, char **, char **, char **, char **, char **,
-		      ip_acl *, pattern_item *);
+extern int parse_buff(char *buff, char **url, char **src_addr, char **ident, char **method,
+		      int *chanid, ip_acl *ip);
 
 #endif
