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;
}
}