events: Limit subscriber count
Protect against DoS by limiting the number of subscribers we allow to a total of 500, and immediately removing subscribers from our list if we encounter an error communicating with them.
This commit is contained in:
		
							
								
								
									
										26
									
								
								upnpevents.c
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								upnpevents.c
									
									
									
									
									
								
							| @@ -83,18 +83,18 @@ struct subscriber { | ||||
|  | ||||
| struct upnp_event_notify { | ||||
| 	LIST_ENTRY(upnp_event_notify) entries; | ||||
|     int s;  /* socket */ | ||||
|     enum { ECreated=1, | ||||
| 	int s;  /* socket */ | ||||
| 	enum { ECreated=1, | ||||
| 	       EConnecting, | ||||
| 	       ESending, | ||||
| 	       EWaitingForResponse, | ||||
| 	       EFinished, | ||||
| 	       EError } state; | ||||
|     struct subscriber * sub; | ||||
|     char * buffer; | ||||
|     int buffersize; | ||||
| 	struct subscriber * sub; | ||||
| 	char * buffer; | ||||
| 	int buffersize; | ||||
| 	int tosend; | ||||
|     int sent; | ||||
| 	int sent; | ||||
| 	const char * path; | ||||
| 	char addrstr[16]; | ||||
| 	char portstr[8]; | ||||
| @@ -110,6 +110,9 @@ LIST_HEAD(listhead, subscriber) subscriberlist = { NULL }; | ||||
| /* notify list */ | ||||
| LIST_HEAD(listheadnotif, upnp_event_notify) notifylist = { NULL }; | ||||
|  | ||||
| #define MAX_SUBSCRIBERS 500 | ||||
| static uint16_t nsubscribers = 0; | ||||
|  | ||||
| /* create a new subscriber */ | ||||
| static struct subscriber * | ||||
| newSubscriber(const char * eventurl, const char * callback, int callbacklen) | ||||
| @@ -151,12 +154,15 @@ upnpevents_addSubscriber(const char * eventurl, | ||||
| 	struct subscriber * tmp; | ||||
| 	DPRINTF(E_DEBUG, L_HTTP, "addSubscriber(%s, %.*s, %d)\n", | ||||
| 	       eventurl, callbacklen, callback, timeout); | ||||
| 	if (nsubscribers >= MAX_SUBSCRIBERS) | ||||
| 		return NULL; | ||||
| 	tmp = newSubscriber(eventurl, callback, callbacklen); | ||||
| 	if(!tmp) | ||||
| 		return NULL; | ||||
| 	if(timeout) | ||||
| 		tmp->timeout = time(NULL) + timeout; | ||||
| 	LIST_INSERT_HEAD(&subscriberlist, tmp, entries); | ||||
| 	nsubscribers++; | ||||
| 	upnp_event_create_notify(tmp); | ||||
| 	return tmp->uuid; | ||||
| } | ||||
| @@ -189,6 +195,7 @@ upnpevents_removeSubscriber(const char * sid, int sidlen) | ||||
| 				sub->notify->sub = NULL; | ||||
| 			} | ||||
| 			LIST_REMOVE(sub, entries); | ||||
| 			nsubscribers--; | ||||
| 			free(sub); | ||||
| 			return 0; | ||||
| 		} | ||||
| @@ -468,28 +475,27 @@ void upnpevents_processfds(fd_set *readset, fd_set *writeset) | ||||
| 			} | ||||
| 			if(obj->sub) | ||||
| 				obj->sub->notify = NULL; | ||||
| #if 0 /* Just let it time out instead of explicitly removing the subscriber */ | ||||
| 			/* remove also the subscriber from the list if there was an error */ | ||||
| 			if(obj->state == EError && obj->sub) { | ||||
| 				LIST_REMOVE(obj->sub, entries); | ||||
| 				nsubscribers--; | ||||
| 				free(obj->sub); | ||||
| 			} | ||||
| #endif | ||||
| 			free(obj->buffer); | ||||
| 			LIST_REMOVE(obj, entries); | ||||
| 			free(obj); | ||||
| 		} | ||||
| 		obj = next; | ||||
| 	} | ||||
| 	/* remove timeouted subscribers */ | ||||
| 	/* remove timed-out subscribers */ | ||||
| 	curtime = time(NULL); | ||||
| 	for(sub = subscriberlist.lh_first; sub != NULL; ) { | ||||
| 		subnext = sub->entries.le_next; | ||||
| 		if(sub->timeout && curtime > sub->timeout && sub->notify == NULL) { | ||||
| 			LIST_REMOVE(sub, entries); | ||||
| 			nsubscribers--; | ||||
| 			free(sub); | ||||
| 		} | ||||
| 		sub = subnext; | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user