1 | /* |
---|
2 | * ntp_restrict.c - find out what restrictions this host is running under |
---|
3 | */ |
---|
4 | #ifdef HAVE_CONFIG_H |
---|
5 | #include <config.h> |
---|
6 | #endif |
---|
7 | |
---|
8 | #include <stdio.h> |
---|
9 | #include <sys/types.h> |
---|
10 | |
---|
11 | #include "ntpd.h" |
---|
12 | #include "ntp_if.h" |
---|
13 | #include "ntp_stdlib.h" |
---|
14 | |
---|
15 | /* |
---|
16 | * This code keeps a simple address-and-mask list of hosts we want |
---|
17 | * to place restrictions on (or remove them from). The restrictions |
---|
18 | * are implemented as a set of flags which tell you what the host |
---|
19 | * can't do. There is a subroutine entry to return the flags. The |
---|
20 | * list is kept sorted to reduce the average number of comparisons |
---|
21 | * and make sure you get the set of restrictions most specific to |
---|
22 | * the address. |
---|
23 | * |
---|
24 | * The algorithm is that, when looking up a host, it is first assumed |
---|
25 | * that the default set of restrictions will apply. It then searches |
---|
26 | * down through the list. Whenever it finds a match it adopts the match's |
---|
27 | * flags instead. When you hit the point where the sorted address is |
---|
28 | * greater than the target, you return with the last set of flags you |
---|
29 | * found. Because of the ordering of the list, the most specific match |
---|
30 | * will provide the final set of flags. |
---|
31 | * |
---|
32 | * This was originally intended to restrict you from sync'ing to your |
---|
33 | * own broadcasts when you are doing that, by restricting yourself |
---|
34 | * from your own interfaces. It was also thought it would sometimes |
---|
35 | * be useful to keep a misbehaving host or two from abusing your primary |
---|
36 | * clock. It has been expanded, however, to suit the needs of those |
---|
37 | * with more restrictive access policies. |
---|
38 | */ |
---|
39 | |
---|
40 | /* |
---|
41 | * Memory allocation parameters. We allocate INITRESLIST entries |
---|
42 | * initially, and add INCRESLIST entries to the free list whenever |
---|
43 | * we run out. |
---|
44 | */ |
---|
45 | #define INITRESLIST 10 |
---|
46 | #define INCRESLIST 5 |
---|
47 | |
---|
48 | /* |
---|
49 | * The restriction list |
---|
50 | */ |
---|
51 | struct restrictlist *restrictlist; |
---|
52 | static int restrictcount; /* count of entries in the restriction list */ |
---|
53 | |
---|
54 | /* |
---|
55 | * The free list and associated counters. Also some uninteresting |
---|
56 | * stat counters. |
---|
57 | */ |
---|
58 | static struct restrictlist *resfree; |
---|
59 | static int numresfree; /* number of structures on free list */ |
---|
60 | |
---|
61 | u_long res_calls; |
---|
62 | u_long res_found; |
---|
63 | u_long res_not_found; |
---|
64 | u_long res_timereset; |
---|
65 | |
---|
66 | /* |
---|
67 | * Parameters of the RES_LIMITED restriction option. |
---|
68 | * client_limit is the number of hosts allowed per source net |
---|
69 | * client_limit_period is the number of seconds after which an entry |
---|
70 | * is no longer considered for client limit determination |
---|
71 | */ |
---|
72 | u_long client_limit; |
---|
73 | u_long client_limit_period; |
---|
74 | /* |
---|
75 | * count number of restriction entries referring to RES_LIMITED |
---|
76 | * controls activation/deactivation of monitoring |
---|
77 | * (with respect ro RES_LIMITED control) |
---|
78 | */ |
---|
79 | u_long res_limited_refcnt; |
---|
80 | |
---|
81 | /* |
---|
82 | * Our initial allocation of list entries. |
---|
83 | */ |
---|
84 | static struct restrictlist resinit[INITRESLIST]; |
---|
85 | |
---|
86 | /* |
---|
87 | * Imported from the timer module |
---|
88 | */ |
---|
89 | extern u_long current_time; |
---|
90 | |
---|
91 | /* |
---|
92 | * debug flag |
---|
93 | */ |
---|
94 | extern int debug; |
---|
95 | |
---|
96 | /* |
---|
97 | * init_restrict - initialize the restriction data structures |
---|
98 | */ |
---|
99 | void |
---|
100 | init_restrict() |
---|
101 | { |
---|
102 | register int i; |
---|
103 | char bp[80]; |
---|
104 | |
---|
105 | /* |
---|
106 | * Zero the list and put all but one on the free list |
---|
107 | */ |
---|
108 | resfree = 0; |
---|
109 | memset((char *)resinit, 0, sizeof resinit); |
---|
110 | |
---|
111 | for (i = 1; i < INITRESLIST; i++) { |
---|
112 | resinit[i].next = resfree; |
---|
113 | resfree = &resinit[i]; |
---|
114 | } |
---|
115 | |
---|
116 | numresfree = INITRESLIST-1; |
---|
117 | |
---|
118 | /* |
---|
119 | * Put the remaining item at the head of the |
---|
120 | * list as our default entry. Everything in here |
---|
121 | * should be zero for now. |
---|
122 | */ |
---|
123 | resinit[0].addr = htonl(INADDR_ANY); |
---|
124 | resinit[0].mask = 0; |
---|
125 | restrictlist = &resinit[0]; |
---|
126 | restrictcount = 1; |
---|
127 | |
---|
128 | |
---|
129 | /* |
---|
130 | * fix up stat counters |
---|
131 | */ |
---|
132 | res_calls = 0; |
---|
133 | res_found = 0; |
---|
134 | res_not_found = 0; |
---|
135 | res_timereset = 0; |
---|
136 | |
---|
137 | /* |
---|
138 | * set default values for RES_LIMIT functionality |
---|
139 | */ |
---|
140 | client_limit = 3; |
---|
141 | client_limit_period = 3600; |
---|
142 | res_limited_refcnt = 0; |
---|
143 | |
---|
144 | sprintf(bp, "client_limit=%ld", client_limit); |
---|
145 | set_sys_var(bp, strlen(bp)+1, RO); |
---|
146 | sprintf(bp, "client_limit_period=%ld", client_limit_period); |
---|
147 | set_sys_var(bp, strlen(bp)+1, RO); |
---|
148 | } |
---|
149 | |
---|
150 | |
---|
151 | /* |
---|
152 | * restrictions - return restrictions for this host |
---|
153 | */ |
---|
154 | int |
---|
155 | restrictions(srcadr) |
---|
156 | struct sockaddr_in *srcadr; |
---|
157 | { |
---|
158 | register struct restrictlist *rl; |
---|
159 | register struct restrictlist *match; |
---|
160 | register u_int32 hostaddr; |
---|
161 | register int isntpport; |
---|
162 | |
---|
163 | res_calls++; |
---|
164 | /* |
---|
165 | * We need the host address in host order. Also need to know |
---|
166 | * whether this is from the ntp port or not. |
---|
167 | */ |
---|
168 | hostaddr = SRCADR(srcadr); |
---|
169 | isntpport = (SRCPORT(srcadr) == NTP_PORT); |
---|
170 | |
---|
171 | /* |
---|
172 | * Set match to first entry, which is default entry. Work our |
---|
173 | * way down from there. |
---|
174 | */ |
---|
175 | match = restrictlist; |
---|
176 | |
---|
177 | for (rl = match->next; rl != 0 && rl->addr <= hostaddr; rl = rl->next) |
---|
178 | if ((hostaddr & rl->mask) == rl->addr) { |
---|
179 | if ((rl->mflags & RESM_NTPONLY) && !isntpport) |
---|
180 | continue; |
---|
181 | match = rl; |
---|
182 | } |
---|
183 | |
---|
184 | match->count++; |
---|
185 | if (match == restrictlist) |
---|
186 | res_not_found++; |
---|
187 | else |
---|
188 | res_found++; |
---|
189 | |
---|
190 | /* |
---|
191 | * The following implements limiting the number of clients |
---|
192 | * accepted from a given network. The notion of "same network" |
---|
193 | * is determined by the mask and addr fields of the restrict |
---|
194 | * list entry. The monitor mechanism has to be enabled for |
---|
195 | * collecting info on current clients. |
---|
196 | * |
---|
197 | * The policy is as follows: |
---|
198 | * - take the list of clients recorded |
---|
199 | * from the given "network" seen within the last |
---|
200 | * client_limit_period seconds |
---|
201 | * - if there are at most client_limit entries: |
---|
202 | * --> access allowed |
---|
203 | * - otherwise sort by time first seen |
---|
204 | * - current client among the first client_limit seen |
---|
205 | * hosts? |
---|
206 | * if yes: access allowed |
---|
207 | * else: eccess denied |
---|
208 | */ |
---|
209 | if (match->flags & RES_LIMITED) { |
---|
210 | int lcnt; |
---|
211 | struct mon_data *md, *this_client; |
---|
212 | extern int mon_enabled; |
---|
213 | extern struct mon_data mon_fifo_list, mon_mru_list; |
---|
214 | |
---|
215 | #ifdef DEBUG |
---|
216 | if (debug > 2) |
---|
217 | printf("limited clients check: %ld clients, period %ld seconds, net is 0x%lX\n", |
---|
218 | client_limit, client_limit_period, |
---|
219 | (u_long)netof(hostaddr)); |
---|
220 | #endif /*DEBUG*/ |
---|
221 | if (mon_enabled == MON_OFF) { |
---|
222 | #ifdef DEBUG |
---|
223 | if (debug > 4) |
---|
224 | printf("no limit - monitoring is off\n"); |
---|
225 | #endif |
---|
226 | return (int)(match->flags & ~RES_LIMITED); |
---|
227 | } |
---|
228 | |
---|
229 | /* |
---|
230 | * How nice, MRU list provides our current client as the |
---|
231 | * first entry in the list. |
---|
232 | * Monitoring was verified to be active above, thus we |
---|
233 | * know an entry for our client must exist, or some |
---|
234 | * brain dead set the memory limit for mon entries to ZERO!!! |
---|
235 | */ |
---|
236 | this_client = mon_mru_list.mru_next; |
---|
237 | |
---|
238 | for (md = mon_fifo_list.fifo_next,lcnt = 0; |
---|
239 | md != &mon_fifo_list; |
---|
240 | md = md->fifo_next) { |
---|
241 | if ((current_time - md->lasttime) |
---|
242 | > client_limit_period) { |
---|
243 | #ifdef DEBUG |
---|
244 | if (debug > 5) |
---|
245 | printf("checking: %s: ignore: too old: %ld\n", |
---|
246 | numtoa(md->rmtadr), |
---|
247 | current_time - md->lasttime); |
---|
248 | #endif |
---|
249 | continue; |
---|
250 | } |
---|
251 | if (md->mode == MODE_BROADCAST || |
---|
252 | md->mode == MODE_CONTROL || |
---|
253 | md->mode == MODE_PRIVATE) { |
---|
254 | #ifdef DEBUG |
---|
255 | if (debug > 5) |
---|
256 | printf("checking: %s: ignore mode %d\n", |
---|
257 | numtoa(md->rmtadr), |
---|
258 | md->mode); |
---|
259 | #endif |
---|
260 | continue; |
---|
261 | } |
---|
262 | if (netof(md->rmtadr) != |
---|
263 | netof(hostaddr)) { |
---|
264 | #ifdef DEBUG |
---|
265 | if (debug > 5) |
---|
266 | printf("checking: %s: different net 0x%lX\n", |
---|
267 | numtoa(md->rmtadr), |
---|
268 | (u_long)netof(md->rmtadr)); |
---|
269 | #endif |
---|
270 | continue; |
---|
271 | } |
---|
272 | lcnt++; |
---|
273 | if (lcnt > (int) client_limit || |
---|
274 | md->rmtadr == hostaddr) { |
---|
275 | #ifdef DEBUG |
---|
276 | if (debug > 5) |
---|
277 | printf("considering %s: found host\n", |
---|
278 | numtoa(md->rmtadr)); |
---|
279 | #endif |
---|
280 | break; |
---|
281 | } |
---|
282 | #ifdef DEBUG |
---|
283 | else { |
---|
284 | if (debug > 5) |
---|
285 | printf("considering %s: same net\n", |
---|
286 | numtoa(md->rmtadr)); |
---|
287 | } |
---|
288 | #endif |
---|
289 | |
---|
290 | } |
---|
291 | #ifdef DEBUG |
---|
292 | if (debug > 4) |
---|
293 | printf("this one is rank %d in list, limit is %lu: %s\n", |
---|
294 | lcnt, client_limit, |
---|
295 | (lcnt <= (int) client_limit) ? "ALLOW" : "REJECT"); |
---|
296 | #endif |
---|
297 | if (lcnt <= (int) client_limit) { |
---|
298 | this_client->lastdrop = 0; |
---|
299 | return (int)(match->flags & ~RES_LIMITED); |
---|
300 | } else { |
---|
301 | this_client->lastdrop = current_time; |
---|
302 | } |
---|
303 | } |
---|
304 | return (int)match->flags; |
---|
305 | } |
---|
306 | |
---|
307 | |
---|
308 | /* |
---|
309 | * restrict - add/subtract/manipulate entries on the restrict list |
---|
310 | */ |
---|
311 | void |
---|
312 | restrict(op, resaddr, resmask, mflags, flags) |
---|
313 | int op; |
---|
314 | struct sockaddr_in *resaddr; |
---|
315 | struct sockaddr_in *resmask; |
---|
316 | int mflags; |
---|
317 | int flags; |
---|
318 | { |
---|
319 | register u_int32 addr; |
---|
320 | register u_int32 mask; |
---|
321 | register struct restrictlist *rl; |
---|
322 | register struct restrictlist *rlprev; |
---|
323 | int i; |
---|
324 | |
---|
325 | /* |
---|
326 | * Get address and mask in host byte order |
---|
327 | */ |
---|
328 | addr = SRCADR(resaddr); |
---|
329 | mask = SRCADR(resmask); |
---|
330 | addr &= mask; /* make sure low bits are zero */ |
---|
331 | |
---|
332 | /* |
---|
333 | * If this is the default address, point at first on list. Else |
---|
334 | * go searching for it. |
---|
335 | */ |
---|
336 | if (addr == htonl(INADDR_ANY)) { |
---|
337 | rlprev = 0; |
---|
338 | rl = restrictlist; |
---|
339 | } else { |
---|
340 | rlprev = restrictlist; |
---|
341 | rl = rlprev->next; |
---|
342 | while (rl != 0) { |
---|
343 | if (rl->addr > addr) { |
---|
344 | rl = 0; |
---|
345 | break; |
---|
346 | } else if (rl->addr == addr) { |
---|
347 | if (rl->mask == mask) { |
---|
348 | if ((mflags & RESM_NTPONLY) |
---|
349 | == (rl->mflags & RESM_NTPONLY)) |
---|
350 | break; /* exact match */ |
---|
351 | if (!(mflags & RESM_NTPONLY)) { |
---|
352 | /* |
---|
353 | * No flag fits before flag |
---|
354 | */ |
---|
355 | rl = 0; |
---|
356 | break; |
---|
357 | } |
---|
358 | /* continue on */ |
---|
359 | } else if (rl->mask > mask) { |
---|
360 | rl = 0; |
---|
361 | break; |
---|
362 | } |
---|
363 | } |
---|
364 | rlprev = rl; |
---|
365 | rl = rl->next; |
---|
366 | } |
---|
367 | } |
---|
368 | /* |
---|
369 | * In case the above wasn't clear :-), either rl now points |
---|
370 | * at the entry this call refers to, or rl is zero and rlprev |
---|
371 | * points to the entry prior to where this one should go in |
---|
372 | * the sort. |
---|
373 | */ |
---|
374 | |
---|
375 | /* |
---|
376 | * Switch based on operation |
---|
377 | */ |
---|
378 | switch (op) { |
---|
379 | case RESTRICT_FLAGS: |
---|
380 | /* |
---|
381 | * Here we add bits to the flags. If this is a new |
---|
382 | * restriction add it. |
---|
383 | */ |
---|
384 | if (rl == 0) { |
---|
385 | if (numresfree == 0) { |
---|
386 | rl = (struct restrictlist *) emalloc( |
---|
387 | INCRESLIST*sizeof(struct restrictlist)); |
---|
388 | memset((char *)rl, 0, |
---|
389 | INCRESLIST*sizeof(struct restrictlist)); |
---|
390 | |
---|
391 | for (i = 0; i < INCRESLIST; i++) { |
---|
392 | rl->next = resfree; |
---|
393 | resfree = rl; |
---|
394 | rl++; |
---|
395 | } |
---|
396 | numresfree = INCRESLIST; |
---|
397 | } |
---|
398 | |
---|
399 | rl = resfree; |
---|
400 | resfree = rl->next; |
---|
401 | numresfree--; |
---|
402 | |
---|
403 | rl->addr = addr; |
---|
404 | rl->mask = mask; |
---|
405 | rl->mflags = (u_short)mflags; |
---|
406 | |
---|
407 | rl->next = rlprev->next; |
---|
408 | rlprev->next = rl; |
---|
409 | restrictcount++; |
---|
410 | } |
---|
411 | if ((rl->flags ^ (u_short)flags) & RES_LIMITED) { |
---|
412 | res_limited_refcnt++; |
---|
413 | mon_start(MON_RES); /* ensure data gets collected */ |
---|
414 | } |
---|
415 | rl->flags |= (u_short)flags; |
---|
416 | break; |
---|
417 | |
---|
418 | case RESTRICT_UNFLAG: |
---|
419 | /* |
---|
420 | * Remove some bits from the flags. If we didn't |
---|
421 | * find this one, just return. |
---|
422 | */ |
---|
423 | if (rl != 0) { |
---|
424 | if ((rl->flags ^ (u_short)flags) & RES_LIMITED) { |
---|
425 | res_limited_refcnt--; |
---|
426 | if (res_limited_refcnt == 0) |
---|
427 | mon_stop(MON_RES); |
---|
428 | } |
---|
429 | rl->flags &= (u_short)~flags; |
---|
430 | } |
---|
431 | break; |
---|
432 | |
---|
433 | case RESTRICT_REMOVE: |
---|
434 | /* |
---|
435 | * Remove an entry from the table entirely if we found one. |
---|
436 | * Don't remove the default entry and don't remove an |
---|
437 | * interface entry. |
---|
438 | */ |
---|
439 | if (rl != 0 |
---|
440 | && rl->addr != htonl(INADDR_ANY) |
---|
441 | && !(rl->mflags & RESM_INTERFACE)) { |
---|
442 | rlprev->next = rl->next; |
---|
443 | restrictcount--; |
---|
444 | if (rl->flags & RES_LIMITED) { |
---|
445 | res_limited_refcnt--; |
---|
446 | if (res_limited_refcnt == 0) |
---|
447 | mon_stop(MON_RES); |
---|
448 | } |
---|
449 | memset((char *)rl, 0, sizeof(struct restrictlist)); |
---|
450 | |
---|
451 | rl->next = resfree; |
---|
452 | resfree = rl; |
---|
453 | numresfree++; |
---|
454 | } |
---|
455 | break; |
---|
456 | |
---|
457 | default: |
---|
458 | /* Oh, well */ |
---|
459 | break; |
---|
460 | } |
---|
461 | |
---|
462 | /* done! */ |
---|
463 | } |
---|