The unified diff between revisions [a3802f74..] and [e1a50326..] is displayed below. It can also be downloaded as a raw diff.

#
#
# patch "src/cf.data.pre"
#  from [5aeb62e462b3aff61a10ad72b2eb7c212572573b]
#    to [dee12a5d9cd30791b72bbc422710d1cf8d388d02]
#
# patch "src/wccp2.c"
#  from [a1761d5b6b937698f6ddfd87488c885f730d2adb]
#    to [1b190df818172582f99db350a9efb6c578107aba]
#
============================================================
--- src/cf.data.pre	5aeb62e462b3aff61a10ad72b2eb7c212572573b
+++ src/cf.data.pre	dee12a5d9cd30791b72bbc422710d1cf8d388d02
@@ -3514,11 +3514,16 @@ DOC_START
 	The "standard" type does not require a wccp2_service_info option - just
 	the service id will suffice.

+	MD5 service authentication can be enabled by adding "password=<password>"
+	to the end of this service declaration.
+
 	Examples:

 	wccp2_service standard 0	# for the 'web-cache' standard service
 	wccp2_service dynamic 80	# a dynamic service type which will be
 					# fleshed out with subsequent options.
+	wccp2_service standard 0 password=foo
+
 DOC_END

 NAME: wccp2_service_info
============================================================
--- src/wccp2.c	a1761d5b6b937698f6ddfd87488c885f730d2adb
+++ src/wccp2.c	1b190df818172582f99db350a9efb6c578107aba
@@ -49,6 +49,7 @@
 #define WCCP_I_SEE_YOU 8
 #define WCCP_ASSIGN_BUCKET 9

+
 static int theInWccp2Connection = -1;
 static int theOutWccp2Connection = -1;
 static int wccp2_connected = 0;
@@ -66,11 +67,11 @@ static EVH wccp2AssignBuckets;

 #define WCCP2_SECURITY_INFO		0
 #define WCCP2_NO_SECURITY		0
-#define WCCP2_MD5_SECURITY		1	/* Not Supported Yet */
+#define WCCP2_MD5_SECURITY		1

 #define WCCP2_SERVICE_INFO		1
 #define WCCP2_SERVICE_STANDARD		0
-#define WCCP2_SERVICE_DYNAMIC		1	/* Not Supported Yet */
+#define WCCP2_SERVICE_DYNAMIC		1
 #define WCCP2_SERVICE_ID_HTTP		0x00

 #define WCCP2_SERVICE_SRC_IP_HASH	0x1
@@ -110,6 +111,7 @@ static EVH wccp2AssignBuckets;

 /* Useful defines */
 #define	WCCP2_NUMPORTS	8
+#define	WCCP2_PASSWORD_LEN	8

 /* WCCP v2 packet header */
 struct wccp2_here_i_am_header_t {
@@ -134,8 +136,6 @@ struct wccp2_security_md5_t {
 	uint8_t	security_implementation[WCCP2_MD5_SECURITY_LEN];
 };

-static struct wccp2_security_none_t wccp2_security_none;
-
 /* Service info struct */
 struct wccp2_service_info_t {
 	uint16_t service_type;
@@ -286,11 +286,13 @@ struct wccp2_service_list_t {
 	int lowest_ip;
 	uint32_t change_num;
 	struct wccp2_identity_info_t *wccp2_identity_info_ptr;
-	struct wccp2_security_none_t *security_info;
+	struct wccp2_security_md5_t *security_info;
 	struct wccp2_service_info_t *service_info;
 	char wccp_packet[WCCP_RESPONSE_SIZE];
 	size_t wccp_packet_size;
 	struct wccp2_service_list_t *next;
+	char wccp_password[WCCP2_PASSWORD_LEN+1];	/* hold the trailing C-string NUL */
+	uint32_t wccp2_security_type;
 };

 static struct wccp2_service_list_t *wccp2_service_list_head = NULL;
@@ -299,7 +301,7 @@ void wccp2_add_service_list(int service,

 /* END WCCP V2 */
 void wccp2_add_service_list(int service, int service_id, int service_priority,
-    int service_proto, int service_flags, int ports[]);
+    int service_proto, int service_flags, int ports[], int security_type, char *password);

 /*
  * The functions used during startup:
@@ -338,7 +340,8 @@ wccp2_add_service_list(int service, int

 void
 wccp2_add_service_list(int service, int service_id, int service_priority,
-    int service_proto, int service_flags, int ports[])
+    int service_proto, int service_flags, int ports[], int security_type,
+    char *password)
 {
     struct wccp2_service_list_t *wccp2_service_list_ptr;

@@ -352,7 +355,9 @@ wccp2_add_service_list(int service, int
     wccp2_service_list_ptr->change_num=0;
     wccp2_update_service(wccp2_service_list_ptr, service, service_id,
       service_priority, service_proto, service_flags, ports);
-
+    wccp2_service_list_ptr->wccp2_security_type = security_type;
+    bzero(wccp2_service_list_ptr->wccp_password, WCCP2_PASSWORD_LEN + 1);
+    strncpy(wccp2_service_list_ptr->wccp_password, password, WCCP2_PASSWORD_LEN);
     /* add to linked list - XXX this should use the Squid dlink* routines! */
     wccp2_service_list_ptr->next = wccp2_service_list_head;
     wccp2_service_list_head = wccp2_service_list_ptr;
@@ -377,59 +382,55 @@ wccp2_get_service_by_id(int service, int
  * Update the md5 security header, if possible
  *
  * Returns: 1 if we set it, 0 if not (eg, no security section, or non-md5)
- *
- * Comments:
- *
- * This routine is a bit of a hack and its not that efficient.
- * I'm implementing it this way so I don't have to keep track of
- * where in my WCCP message I'm stashing the MD5 security header.
- * This should be tidied up later on.
  */
 char
-wccp2_update_md5_security(char *password, char *packet, int len)
+wccp2_update_md5_security(char *password, char *ptr, char *packet, int len)
 {
 	u_int8_t md5_digest[16];
-	char pwd[8];
+	char pwd[WCCP2_PASSWORD_LEN];
 	MD5_CTX M;
 	struct wccp2_security_md5_t *ws;
-	char *p = packet + 8;	/* Skip the 8-byte Type/version/length header */

+	debug(80, 5) ("wccp2_update_md5_security: called\n");
+
 	/* The password field, for the MD5 hash, needs to be 8 bytes and NUL padded. */
 	bzero(pwd, sizeof(pwd));
 	strncpy(pwd, password, sizeof(pwd));
-	/* Search for the security section */
-	while (p < (packet+len)) {
-		/* p should point at the type/length header */
-		ws = (struct wccp2_security_md5_t *) p;
-		if (ws->security_type != WCCP2_SECURITY_INFO) {
-			/* The length here doesn't include the type/length part (4 bytes) */
-			p += ws->security_length + 4;
-			continue;
-		}
-		/* Its the security part */
-		if (ws->security_option != WCCP2_MD5_SECURITY) {
-			return 0;
-		}
-		/* And now its the MD5 section! */
-		/* According to the draft, the MD5 security hash is the combination of
-		 * the 8-octet password (padded w/ NUL bytes) and the entire WCCP packet,
-		 * including the WCCP message header. The WCCP security implementation
-		 * area should be zero'ed before calculating the MD5 hash.
-		 */
-		/* XXX eventually we should be able to kill md5_digest and blit it directly in */
-		bzero(ws->security_implementation, sizeof(ws->security_implementation));
-		MD5Init(&M);
-		MD5Update(&M, pwd, 8);
-		MD5Update(&M, packet, len);
-		MD5Final(md5_digest, &M);
-		memcpy(ws->security_implementation, md5_digest, sizeof(md5_digest));
-		/* Finished! */
-		return 1;
+	ws = (struct wccp2_security_md5_t *) ptr;
+	assert(ws->security_type == WCCP2_SECURITY_INFO);
+	/* Its the security part */
+	if (htonl(ws->security_option) != WCCP2_MD5_SECURITY) {
+		debug(80, 5) ("wccp2_update_md5_security: this service ain't md5'ing, abort\n");
+		return 0;
 	}
-	/* Didn't find the security section */
-	return 0;
+	/* And now its the MD5 section! */
+	/* According to the draft, the MD5 security hash is the combination of
+	 * the 8-octet password (padded w/ NUL bytes) and the entire WCCP packet,
+	 * including the WCCP message header. The WCCP security implementation
+	 * area should be zero'ed before calculating the MD5 hash.
+	 */
+	/* XXX eventually we should be able to kill md5_digest and blit it directly in */
+	bzero(ws->security_implementation, sizeof(ws->security_implementation));
+	MD5Init(&M);
+	MD5Update(&M, pwd, 8);
+	MD5Update(&M, packet, len);
+	MD5Final(md5_digest, &M);
+	memcpy(ws->security_implementation, md5_digest, sizeof(md5_digest));
+	/* Finished! */
+	return 1;
 }

+
+/*
+ * Check the given WCCP2 packet against the given password.
+ */
+char
+wccp2_check_security(struct wccp2_service_list_t *srv, char *security, char *packet, int len)
+{
+	return 1;
+}
+
+
 void
 wccp2Init(void)
 {
@@ -437,6 +438,7 @@ wccp2Init(void)
     char *ptr;
     struct wccp2_service_list_t *service_list_ptr;
     struct wccp2_router_list_t *router_list_ptr;
+    struct wccp2_security_md5_t wccp2_security_md5;

     debug(80, 5) ("wccp2Init: Called\n");
     if (wccp2_connected == 1)
@@ -469,14 +471,29 @@ wccp2Init(void)
 	ptr = service_list_ptr->wccp_packet + sizeof(wccp2_here_i_am_header);

 	/* add the security section */
-	wccp2_here_i_am_header.length += sizeof(struct wccp2_security_none_t);
+	/* XXX this is ugly */
+	if (service_list_ptr->wccp2_security_type == WCCP2_MD5_SECURITY) {
+		wccp2_security_md5.security_option = htonl(WCCP2_MD5_SECURITY);
+		wccp2_security_md5.security_length = htons(sizeof(struct wccp2_security_md5_t)-4);
+	} else if (service_list_ptr->wccp2_security_type == WCCP2_NO_SECURITY) {
+		wccp2_security_md5.security_option = htonl(WCCP2_NO_SECURITY);
+		/* XXX I hate magic length numbers! */
+		wccp2_security_md5.security_length = htons(4);
+	} else {
+		fatalf("Bad WCCP2 security type\n");
+	}
+	wccp2_here_i_am_header.length += sizeof(struct wccp2_security_md5_t);
 	assert(wccp2_here_i_am_header.length <= WCCP_RESPONSE_SIZE);
-	wccp2_security_none.security_type = htons(WCCP2_SECURITY_INFO);
-	wccp2_security_none.security_length = htons(sizeof(struct wccp2_security_none_t)-4);
-	wccp2_security_none.security_option = htonl(WCCP2_NO_SECURITY); /* TODO: MD5 security */
-	xmemcpy(ptr,&wccp2_security_none,sizeof(struct wccp2_security_none_t));
-	service_list_ptr->security_info=(struct wccp2_security_none_t *)ptr;
-	ptr += sizeof(struct wccp2_security_none_t);
+	wccp2_security_md5.security_type = htons(WCCP2_SECURITY_INFO);
+	service_list_ptr->security_info =(struct wccp2_security_md5_t *)ptr;
+	if (service_list_ptr->wccp2_security_type == WCCP2_MD5_SECURITY) {
+		xmemcpy(ptr,&wccp2_security_md5,sizeof(struct wccp2_security_md5_t));
+		ptr += sizeof(struct wccp2_security_md5_t);
+	} else {
+		/* assume NONE, and XXX I hate magic length numbers */
+		xmemcpy(ptr,&wccp2_security_md5, 8);
+		ptr += 8;
+	}

 	/* Add the service info section */
 	wccp2_here_i_am_header.length += sizeof(struct wccp2_service_info_t);
@@ -876,11 +893,16 @@ wccp2HandleUdp(int sock, void *not_used)
     }

     /* TODO: MD5 security */
-    if(ntohl(security_info->security_option) != service_list_ptr->security_info->security_option) {
-	debug(80, 1) ("Invalid security option in WCCPv2 Packet (%d).\n",
-	    ntohl(security_info->security_option));
+    if(ntohl(security_info->security_option) != ntohl(service_list_ptr->security_info->security_option)) {
+	debug(80, 1) ("Invalid security option in WCCPv2 Packet (%d vs %d).\n",
+	    ntohl(security_info->security_option),
+	    ntohl(service_list_ptr->security_info->security_option));
 	return;
     }
+    if (! wccp2_check_security(service_list_ptr, (char *)security_info, (char *)&wccp2_i_see_you, len)) {
+	debug(80, 1) ("Received WCCPv2 Packet failed authentication\n");
+	return;
+    }

     /* Check that the router address is configured on this router */
     for (router_list_ptr=&service_list_ptr->router_list_head;router_list_ptr->next != NULL;router_list_ptr=router_list_ptr->next) {
@@ -1054,7 +1076,10 @@ wccp2HereIam(void *voidnotused)

 	    /* Set the cache id (ip) */
 	    service_list_ptr->wccp2_identity_info_ptr->cache_identity.addr=router_list_ptr->local_ip;
-
+	    /* Security update, if needed */
+	    if (service_list_ptr->wccp2_security_type == WCCP2_MD5_SECURITY) {
+            	wccp2_update_md5_security(service_list_ptr->wccp_password, (char *)service_list_ptr->security_info, service_list_ptr->wccp_packet, service_list_ptr->wccp_packet_size);
+            }
 	    debug(80,3) ("Sending HereIam packet size %d\n", (int)service_list_ptr->wccp_packet_size);
 	    /* Send the packet */
 	    sendto(theOutWccp2Connection,
@@ -1086,7 +1111,7 @@ wccp2AssignBuckets(void *voidnotused)

     /* Packet segments */
     struct wccp2_here_i_am_header_t *main_header;
-    struct wccp2_security_none_t *security;	/* TODO: add MD5 */
+    struct wccp2_security_md5_t *security = NULL;
     /* service from service struct */
     struct wccp2_item_header_t *assignment_header;
     struct assignment_key_t *assignment_key;
@@ -1122,9 +1147,22 @@ wccp2AssignBuckets(void *voidnotused)

 	/* build packet header from hereIam packet */
 	/* Security info */
-	security=(struct wccp2_security_none_t *)&wccp_packet[offset];
-	memcpy(security,service_list_ptr->security_info,sizeof(struct wccp2_security_none_t));
-	offset += sizeof(struct wccp2_security_none_t);
+	/* XXX this should be made more generic! */
+	/* XXX and I hate magic numbers! */
+	switch (service_list_ptr->wccp2_security_type) {
+		case WCCP2_NO_SECURITY:
+			security=(struct wccp2_security_md5_t *)&wccp_packet[offset];
+			memcpy(security,service_list_ptr->security_info, 8);
+			offset += 8;
+			break;
+		case WCCP2_MD5_SECURITY:
+			security=(struct wccp2_security_md5_t *)&wccp_packet[offset];
+			memcpy(security,service_list_ptr->security_info,sizeof(struct wccp2_security_md5_t));
+			offset += sizeof(struct wccp2_security_md5_t);
+			break;
+		default:
+			fatalf("Unknown Wccp2 security type\n");
+	}

 	/* Service info */
 	memcpy(&wccp_packet[offset],service_list_ptr->service_info,sizeof(struct wccp2_service_info_t));
@@ -1197,6 +1235,10 @@ wccp2AssignBuckets(void *voidnotused)
 	    /* set the destination address */
 	    router.sin_addr = router_list_ptr->router_sendto_address;

+	    /* Security update, if needed */
+	    if (service_list_ptr->wccp2_security_type == WCCP2_MD5_SECURITY) {
+            	wccp2_update_md5_security(service_list_ptr->wccp_password, (char *) security, wccp_packet, offset);
+            }
 	    if(ntohl(router_list_ptr->num_caches)) {
 		/* send packet */
 		sendto(theOutWccp2Connection,
@@ -1219,7 +1261,7 @@ wccp2AssignBuckets(void *voidnotused)
 /*
  * Format:
  *
- * wccp2_service {standard|dynamic} {id}
+ * wccp2_service {standard|dynamic} {id} (password=password)
  */
 void
 parse_wccp2_service(void *v)
@@ -1227,6 +1269,8 @@ parse_wccp2_service(void *v)
 	char *t;
 	int service = 0;
 	int service_id = 0;
+	int security_type = WCCP2_NO_SECURITY;
+	char wccp_password[WCCP2_PASSWORD_LEN + 1];

 	if (wccp2_connected == 1) {
 		debug(80, 1) ("WCCPv2: Somehow reparsing the configuration "
@@ -1254,8 +1298,17 @@ parse_wccp2_service(void *v)
 		self_destruct();
 	}

+	/* Handle password, if any */
+	if ((t = strtok(NULL, w_space)) != NULL) {
+		if (strncmp(t, "password=", 9) == 0) {
+			security_type = WCCP2_MD5_SECURITY;
+			bzero(wccp_password, WCCP2_PASSWORD_LEN + 1);
+			strncpy(wccp_password, t + 9, WCCP2_PASSWORD_LEN);
+		}
+	}
+
 	/* Create a placeholder service record */
-	wccp2_add_service_list(service, service_id, 0, 0, 0, empty_portlist);
+	wccp2_add_service_list(service, service_id, 0, 0, 0, empty_portlist, security_type, wccp_password);
 }

 void
@@ -1265,9 +1318,12 @@ dump_wccp2_service(StoreEntry *e, const
 	srv = wccp2_service_list_head;
 	while (srv != NULL) {
 		debug(80, 3) ("dump_wccp2_service: id %d, type %d\n", srv->info.service_id, srv->info.service);
-		storeAppendPrintf(e, "%s %s %d\n", label,
+		storeAppendPrintf(e, "%s %s %d", label,
 		    (srv->info.service == WCCP2_SERVICE_DYNAMIC) ? "dynamic" : "standard",
 		    srv->info.service_id);
+		if (srv->wccp2_security_type == WCCP2_MD5_SECURITY) {
+			storeAppendPrintf(e, " %s", srv->wccp_password);
+		}
 		srv = srv->next;
 	}
 }