GNU libmicrohttpd  0.9.72
daemon_ip_limit.c
Go to the documentation of this file.
1 /*
2  This file is part of libmicrohttpd
3  Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Lesser General Public
7  License as published by the Free Software Foundation; either
8  version 2.1 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public
16  License along with this library; if not, write to the Free Software
17  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19 
25 #include "internal.h"
26 #include "daemon_ip_limit.h"
27 #if HAVE_SEARCH_H
28 #include <search.h>
29 #else
30 #include "tsearch.h"
31 #endif
32 
33 
37 struct MHD_IPCount
38 {
42  int family;
43 
47  union
48  {
52  struct in_addr ipv4;
53 #if HAVE_INET6
57  struct in6_addr ipv6;
58 #endif
59  } addr;
60 
64  unsigned int count;
65 };
66 
67 
75 static struct MHD_Daemon*
76 get_master (struct MHD_Daemon *daemon)
77 {
78  while (NULL != daemon->master)
79  daemon = daemon->master;
80  return daemon;
81 }
82 
83 
89 static void
90 MHD_ip_count_lock (struct MHD_Daemon *daemon)
91 {
93 }
94 
95 
101 static void
103 {
105 }
106 
107 
117 static int
118 MHD_ip_addr_compare (const void *a1,
119  const void *a2)
120 {
121  return memcmp (a1,
122  a2,
123  offsetof (struct MHD_IPCount,
124  count));
125 }
126 
127 
136 static int
137 MHD_ip_addr_to_key (const struct sockaddr *addr,
138  socklen_t addrlen,
139  struct MHD_IPCount *key)
140 {
141  memset (key,
142  0,
143  sizeof(*key));
144 
145  /* IPv4 addresses */
146  if (sizeof (struct sockaddr_in) == addrlen)
147  {
148  const struct sockaddr_in *addr4 = (const struct sockaddr_in*) addr;
149 
150  key->family = AF_INET;
151  memcpy (&key->addr.ipv4,
152  &addr4->sin_addr,
153  sizeof(addr4->sin_addr));
154  return MHD_YES;
155  }
156 
157 #if HAVE_INET6
158  /* IPv6 addresses */
159  if (sizeof (struct sockaddr_in6) == addrlen)
160  {
161  const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*) addr;
162 
163  key->family = AF_INET6;
164  memcpy (&key->addr.ipv6,
165  &addr6->sin6_addr,
166  sizeof(addr6->sin6_addr));
167  return MHD_YES;
168  }
169 #endif
170 
171  /* Some other address */
172  return MHD_NO;
173 }
174 
175 
187 int
188 MHD_ip_limit_add (struct MHD_Daemon *daemon,
189  const struct sockaddr *addr,
190  socklen_t addrlen)
191 {
192  struct MHD_IPCount *key;
193  void **nodep;
194  void *node;
195  int result;
196 
197  daemon = get_master (daemon);
198  /* Ignore if no connection limit assigned */
199  if (0 == daemon->ip_connection_limit)
200  return MHD_YES;
201 
202  if (NULL == (key = malloc (sizeof(*key))))
203  return MHD_NO;
204 
205  /* Initialize key */
206  if (MHD_NO == MHD_ip_addr_to_key (addr,
207  addrlen,
208  key))
209  {
210  /* Allow unhandled address types through */
211  free (key);
212  return MHD_YES;
213  }
214  MHD_ip_count_lock (daemon);
215 
216  /* Search for the IP address */
217  if (NULL == (nodep = tsearch (key,
218  &daemon->per_ip_connection_count,
220  {
221 #ifdef HAVE_MESSAGES
222  MHD_DLOG (daemon,
223  MHD_SC_IP_COUNTER_FAILURE,
224  _ ("Failed to add IP connection count node.\n"));
225 #endif
226  MHD_ip_count_unlock (daemon);
227  free (key);
228  return MHD_NO;
229  }
230  node = *nodep;
231  /* If we got an existing node back, free the one we created */
232  if (node != key)
233  free (key);
234  key = (struct MHD_IPCount *) node;
235  /* Test if there is room for another connection; if so,
236  * increment count */
237  result = (key->count < daemon->ip_connection_limit) ? MHD_YES : MHD_NO;
238  if (MHD_YES == result)
239  ++key->count;
240 
241  MHD_ip_count_unlock (daemon);
242  return result;
243 }
244 
245 
254 void
255 MHD_ip_limit_del (struct MHD_Daemon *daemon,
256  const struct sockaddr *addr,
257  socklen_t addrlen)
258 {
259  struct MHD_IPCount search_key;
260  struct MHD_IPCount *found_key;
261  void **nodep;
262 
263  daemon = get_master (daemon);
264  /* Ignore if no connection limit assigned */
265  if (0 == daemon->ip_connection_limit)
266  return;
267  /* Initialize search key */
268  if (MHD_NO == MHD_ip_addr_to_key (addr,
269  addrlen,
270  &search_key))
271  return;
272 
273  MHD_ip_count_lock (daemon);
274 
275  /* Search for the IP address */
276  if (NULL == (nodep = tfind (&search_key,
277  &daemon->per_ip_connection_count,
279  {
280  /* Something's wrong if we couldn't find an IP address
281  * that was previously added */
282  MHD_PANIC (_ ("Failed to find previously-added IP address.\n"));
283  }
284  found_key = (struct MHD_IPCount *) *nodep;
285  /* Validate existing count for IP address */
286  if (0 == found_key->count)
287  {
288  MHD_PANIC (_ ("Previously-added IP address had counter of zero.\n"));
289  }
290  /* Remove the node entirely if count reduces to 0 */
291  if (0 == --found_key->count)
292  {
293  tdelete (found_key,
294  &daemon->per_ip_connection_count,
296  free (found_key);
297  }
298 
299  MHD_ip_count_unlock (daemon);
300 }
301 
302 
303 /* end of daemon_ip_limit.c */
static void MHD_ip_count_unlock(struct MHD_Daemon *daemon)
static int MHD_ip_addr_compare(const void *a1, const void *a2)
static int MHD_ip_addr_to_key(const struct sockaddr *addr, socklen_t addrlen, struct MHD_IPCount *key)
static void MHD_ip_count_lock(struct MHD_Daemon *daemon)
int MHD_ip_limit_add(struct MHD_Daemon *daemon, const struct sockaddr *addr, socklen_t addrlen)
void MHD_ip_limit_del(struct MHD_Daemon *daemon, const struct sockaddr *addr, socklen_t addrlen)
static struct MHD_Daemon * get_master(struct MHD_Daemon *daemon)
counting of connections per IP
#define MHD_PANIC(msg)
Definition: internal.h:69
#define MHD_mutex_unlock_chk_(pmutex)
Definition: mhd_locks.h:180
#define MHD_mutex_lock_chk_(pmutex)
Definition: mhd_locks.h:154
#define NULL
Definition: reason_phrase.c:30
void * tsearch(const void *vkey, void **vrootp, int(*compar)(const void *, const void *))
Definition: tsearch.c:27
void * tfind(const void *vkey, void *const *vrootp, int(*compar)(const void *, const void *))
Definition: tsearch.c:63
void * tdelete(const void *__restrict vkey, void **__restrict vrootp, int(*compar)(const void *, const void *))
Definition: tsearch.c:95
#define _(String)
Definition: mhd_options.h:42
internal shared structures
@ MHD_YES
Definition: microhttpd.h:151
@ MHD_NO
Definition: microhttpd.h:146
MHD_mutex_ per_ip_connection_mutex
Definition: internal.h:1259
void * per_ip_connection_count
Definition: internal.h:1187
unsigned int ip_connection_limit
Definition: internal.h:1356
struct MHD_Daemon * master
Definition: internal.h:1068