1 /*
2 * Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009, 2010, 2011,
3 * 2012, 2013, 2014, 2016
4 * Inferno Nettverk A/S, Norway. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. The above copyright notice, this list of conditions and the following
10 * disclaimer must appear in all copies of the software, derivative works
11 * or modified versions, and any portions thereof, aswell as in all
12 * supporting documentation.
13 * 2. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by
16 * Inferno Nettverk A/S, Norway.
17 * 3. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * Inferno Nettverk A/S requests users of this software to return to
32 *
33 * Software Distribution Coordinator or sdc@inet.no
34 * Inferno Nettverk A/S
35 * Oslo Research Park
36 * Gaustadall�en 21
37 * NO-0349 Oslo
38 * Norway
39 *
40 * any improvements or extensions that they make and grant Inferno Nettverk A/S
41 * the rights to redistribute these changes.
42 *
43 */
44
45 #include "common.h"
46
47 static const char rcsid[] =
48 "$Id: shmem.c,v 1.238.4.6.2.2 2017/01/31 08:17:38 karls Exp $";
49
50
51 #define FIRST_SHMEMID (0)
52
53 typedef enum { keytype_ipv4 = 1, keytype_ipv6 } keystate_data_type;
54
55 typedef struct {
56 keystate_data_type type;
57
58 union {
59 struct in_addr ipv4;
60 struct in6_addr ipv6;
61 } data;
62 } keystate_data_t;
63
64 static unsigned long
65 mem2shmem(struct config *config, const unsigned long firstid);
66 /*
67 * Deallocates from all rules starting with "firstrule" ordinary memory for
68 * objects that should be in shared memory and allocates shared memory
69 * for it instead.
70 * "firstid" is the id to use for the first allocation. The id of
71 * subsequent allocations is incremented by one.
72 *
73 * Returns the id of the last id used.
74 */
75
76 static void
77 keystate_removeindex(keystate_t *keystate, const size_t index);
78 /*
79 * Removes the keystate entry with index "index".
80 */
81
82 static keystate_data_t *
83 keystate_data(const keystate_t *keystate, const size_t index,
84 keystate_data_t *key);
85 /*
86 * Returns the keystate data at index "index" corresponding to the key
87 * set in keystate.
88 */
89
90 static const char *
91 keydata2string(const keystate_data_t *keydata, char *buf, size_t buflen);
92 /*
93 * Stores a string representation of keydata "keydata" in "buf" and
94 * returns a pointer to buf.
95 *
96 * If "buf" is NULL, the representation is written to a local static buffer
97 * and a pointer to it is returned.
98 */
99
100 static size_t
101 keystate_clientcount(const keystate_t *keystate, const size_t index);
102 /*
103 * Returns the current clientcount for the keystate entry with index "index".
104 */
105
106 static ssize_t
107 keystate_timer(const shmem_object_t *shmem);
108 /*
109 * is there a relevant timer we can use for calculating how often to
110 * scan for old keystate entries to expire and remove in "shmem"?
111 *
112 * Returns the timer as number of seconds if so, or -1 if not.
113 */
114
115 static int
116 should_do_expirescan(const shmem_object_t *shmem);
117 /*
118 * Should we do a scan for old keyentries in shmem at this time?
119 * Returns true if so, false otherwise.
120 */
121
122 void
shmem_setup(void)123 shmem_setup(void)
124 {
125 const char *function = "shmem_setup()";
126 char *p;
127
128 /*
129 * Main shmem-stuff. sockd.conf and shmemfd used for locking access
130 * to shmem-stuff.
131 */
132
133 SASSERTX(sockscf.shmemfd == -1);
134 SASSERTX(pidismother(sockscf.state.pid) == 1);
135
136 STRCPY_ASSERTSIZE(sockscf.shmem_fnamebase, SOCKD_SHMEMFILE);
137
138 /*
139 * First check that this works ok. If e.g., user has changed some
140 * config-files and made strings too long, it might fail.
141 */
142 if ((sockscf.shmemfd = socks_mklock(sockscf.shmem_fnamebase,
143 sockscf.shmem_fnamebase,
144 sizeof(sockscf.shmem_fnamebase))) == -1)
145 serr("%s: socks_mklock() failed to create shmemfile using base %s",
146 function, sockscf.shmem_fnamebase);
147
148 if ((p = sockd_getshmemname((unsigned long)FIRST_SHMEMID, key_from)) == NULL)
149 serrx("%s: failed to generate shmem filename based on fnamebase "
150 "\"%s\" and id %d",
151 function, sockscf.shmem_fnamebase, FIRST_SHMEMID);
152
153 if (strlen(p) >= sizeof(sockscf.shmem_fnamebase))
154 serrx("%s: shmem filename is %ld bytes too long for this system. Please "
155 "reduce the length of the SOCKD_SHMEMFILE define and recompile",
156 function,
157 (unsigned long)(strlen(p) + 1) - sizeof(sockscf.shmem_fnamebase));
158
159 if ((sockscf.shmeminfo = sockd_mmap(NULL,
160 sizeof(*sockscf.shmeminfo),
161 PROT_READ | PROT_WRITE,
162 MAP_SHARED,
163 sockscf.shmemfd,
164 1)) == MAP_FAILED)
165 serr("%s: failed to mmap shmeminfo", function);
166
167 /* can unlink this file; all children will inherit the fd. */
168 if (unlink(sockscf.shmem_fnamebase) != 0)
169 serr("%s: failed to unlink shmemfile %s",
170 function, sockscf.shmem_fnamebase);
171
172 SASSERTX(sockscf.shmemconfigfd == -1);
173 if ((sockscf.shmemconfigfd
174 = socks_mklock(SOCKD_SHMEMFILE, NULL, 0)) == -1)
175 serr("%s: socks_mklock() failed to create shmemfile using base %s",
176 function, SOCKD_SHMEMFILE);
177
178 /*
179 * Hostcache also uses shmem, but has it's own area.
180 */
181 hostcachesetup();
182
183 #if HAVE_LDAP
184 /*
185 * And so does the LDAP module.
186 */
187 ldapcachesetup();
188 #endif /* HAVE_LDAP */
189
190 }
191
192 void
shmem_idupdate(config)193 shmem_idupdate(config)
194 struct config *config;
195 {
196 static size_t lastshmid = FIRST_SHMEMID + 1;
197
198 lastshmid = mem2shmem(config, lastshmid);
199 ++lastshmid;
200 }
201
202 void
sockd_shmdt(rule,objects)203 sockd_shmdt(rule, objects)
204 rule_t *rule;
205 const int objects;
206 {
207 const char *function = "sockd_shmdt()";
208
209 if ((objects & SHMEM_BW) && rule->bw_shmid)
210 HANDLE_SHMDT(rule, bw, bw_shmid);
211
212 if ((objects & SHMEM_MONITOR) && rule->mstats_shmid)
213 HANDLE_SHMDT(rule, mstats, mstats_shmid);
214
215 if ((objects & SHMEM_SS) && rule->ss_shmid)
216 HANDLE_SHMDT(rule, ss, ss_shmid);
217 }
218
219 int
sockd_shmat(rule,objects)220 sockd_shmat(rule, objects)
221 rule_t *rule;
222 int objects;
223 {
224 const char *function = "sockd_shmat()";
225 int haveerror = 0;
226
227 if ((objects & SHMEM_BW) && rule->bw_shmid != 0) {
228 HANDLE_SHMAT(rule, bw, bw_shmid);
229
230 if (rule->bw_shmid) {
231 #if DEBUG /* memory-mapped file contents may not be saved in coredumps. */
232 shmem_object_t _shmem = *rule->bw;
233 #endif /* DEBUG */
234
235 SASSERTX(rule->bw->type == SHMEM_BW);
236 }
237 else {
238 SASSERTX(rule->bw == NULL);
239
240 haveerror = 1;
241 objects &= ~SHMEM_BW;
242 }
243 }
244 #if DEBUG
245 else
246 slog(LOG_DEBUG, "%s: no bw_shmid we need to (re)attach to for rule #%lu",
247 function, (unsigned long)rule->number);
248 #endif /* DEBUG */
249
250 if ((objects & SHMEM_MONITOR) && rule->mstats_shmid != 0) {
251 /*
252 * monitor-files are deleted and reset on every sighup, so can
253 * be deleted even if mother still exists.
254 */
255 HANDLE_SHMAT(rule, mstats, mstats_shmid);
256
257 if (rule->mstats_shmid) {
258 #if DEBUG /* memory-mapped file contents may not be saved in coredumps. */
259 shmem_object_t _shmem = *rule->mstats;
260 #endif /* DEBUG */
261
262 SASSERTX(rule->mstats->type == SHMEM_MONITOR);
263 }
264 else {
265 SASSERTX(rule->mstats == NULL);
266
267 haveerror = 1;
268 objects &= ~SHMEM_MONITOR;
269 }
270 }
271 #if DEBUG
272 else
273 slog(LOG_DEBUG,
274 "%s: no mstats_shmid we need to (re)attach to for rule #%lu",
275 function, (unsigned long)rule->number);
276 #endif /* DEBUG */
277
278 if ((objects & SHMEM_SS) && rule->ss_shmid != 0) {
279 HANDLE_SHMAT(rule, ss, ss_shmid);
280
281 if (rule->ss_shmid) {
282 #if DEBUG /* memory-mapped file contents may not be saved in coredumps. */
283 shmem_object_t _shmem = *rule->ss;
284 #endif /* DEBUG */
285
286 SASSERTX(rule->ss->type == SHMEM_SS);
287 }
288 else {
289 SASSERTX(rule->ss == NULL);
290
291 haveerror = 1;
292 objects &= ~SHMEM_SS;
293 }
294 }
295 #if DEBUG
296 else
297 slog(LOG_DEBUG, "%s: no ss_shmid we need to (re)attach to for rule #%lu",
298 function, (unsigned long)rule->number);
299 #endif /* DEBUG */
300
301 if (haveerror)
302 return -1;
303 else
304 return 0;
305 }
306
307 int
shmem_userule(rule,cinfo,emsg,emsglen)308 shmem_userule(rule, cinfo, emsg, emsglen)
309 rule_t *rule;
310 const clientinfo_t *cinfo;
311 char *emsg;
312 const size_t emsglen;
313 {
314 const char *function = "shmem_userule()";
315 size_t attached_to;
316
317 slog(LOG_DEBUG, "%s: cinfo: %s",
318 function, clientinfo2string(cinfo, NULL, 0));
319
320 log_ruleinfo_shmid(rule, function, NULL);
321
322 /*
323 * Do sessions first, since that's the one that can fail.
324 */
325
326 attached_to = 0;
327
328 if (rule->ss_shmid != 0 && rule->ss == NULL)
329 if (sockd_shmat(rule, SHMEM_SS) == 0)
330 attached_to |= SHMEM_SS;
331
332 if (rule->ss_shmid != 0) {
333 if (!session_use(rule->ss,
334 cinfo,
335 sockscf.shmemfd,
336 emsg,
337 emsglen)) {
338 SASSERTX(rule->ss_shmid == (rule)->ss->mstate.shmid);
339
340 sockd_shmdt(rule, attached_to);
341 return -1;
342 }
343 }
344
345 if (rule->bw_shmid != 0 && rule->bw == NULL)
346 if (sockd_shmat(rule, SHMEM_BW) == 0)
347 attached_to |= SHMEM_BW;
348
349 if (rule->bw_shmid != 0)
350 bw_use(rule->bw, cinfo, sockscf.shmemfd);
351
352 if (rule->mstats_shmid != 0 && rule->mstats == NULL)
353 if (sockd_shmat(rule, SHMEM_MONITOR) == 0)
354 attached_to |= SHMEM_MONITOR;
355
356 if (rule->mstats_shmid != 0)
357 monitor_use(rule->mstats, cinfo, sockscf.shmemfd);
358
359 sockd_shmdt(rule, attached_to);
360
361 return 0;
362 }
363
364
365 char *
sockd_getshmemname(id,key)366 sockd_getshmemname(id, key)
367 const unsigned long id;
368 const statekey_t key;
369 {
370 /* const char *function = "sockd_getshmemname()"; */
371 static char name[PATH_MAX];
372
373 SASSERTX(*sockscf.shmem_fnamebase != NUL);
374
375 if (key == key_unset)
376 snprintf(name, sizeof(name), "%s.%lu", sockscf.shmem_fnamebase, id);
377 else
378 snprintf(name, sizeof(name), "%s.%lu.%d",
379 sockscf.shmem_fnamebase, id, (int)key);
380
381 return name;
382 }
383
384 void *
sockd_mmap(mapping,size,prot,flags,fd,docreate)385 sockd_mmap(mapping, size, prot, flags, fd, docreate)
386 void *mapping;
387 size_t size;
388 const int prot;
389 const int flags;
390 const int fd;
391 const int docreate;
392 {
393 const char *function = "sockd_mmap()";
394 const void *oldmapping = mapping;
395
396 if (size == 0)
397 return MAP_FAILED;
398
399 if (docreate) {
400 if (ftruncate(fd, (off_t)size) == -1) {
401 swarn("%s: ftruncate() to offset %lu failed",
402 function, (unsigned long)size);
403
404 return MAP_FAILED;
405 }
406 }
407
408 slog(LOG_DEBUG, "%s: mmap(2)'ing %lu bytes from fd %d, mapping = %p",
409 function, (unsigned long)size, fd, mapping);
410
411 if ((mapping = mmap(mapping,
412 size,
413 prot,
414 flags,
415 fd,
416 (off_t)0)) == MAP_FAILED)
417 swarn("%s: %smmap(2) of %lu bytes from fd %d failed",
418 function, oldmapping == NULL ? "" : "re-", (unsigned long)size, fd);
419
420 return mapping;
421 }
422
423 int
shmem_use(shmem,cinfo,lock,mapisopen)424 shmem_use(shmem, cinfo, lock, mapisopen)
425 shmem_object_t *shmem;
426 const clientinfo_t *cinfo;
427 const int lock;
428 const int mapisopen;
429 {
430 const char *function = "shmem_use()";
431 const int doclosemap = (mapisopen ? 0 : 1);
432 #if DEBUG /* memory-mapped file contents may not be saved in coredumps. */
433 shmem_object_t _shmem = *shmem;
434 #endif /* DEBUG */
435 ssize_t statecount = -1;
436
437 SASSERTX(shmem != NULL);
438 SASSERTX(shmem->mstate.number > 0);
439
440 if (sockscf.option.debug >= DEBUG_VERBOSE)
441 slog(LOG_DEBUG,
442 "%s: pre-use: lock = %d, # of clients = %lu, rule = %lu, "
443 "shmem = %p, keystate = %p, mapisopen = %d, cinfo = %s, shmid %ld, "
444 "key %d",
445 function,
446 lock,
447 (unsigned long)shmem->mstate.clients,
448 (unsigned long)shmem->mstate.number,
449 shmem,
450 shmem->keystate.keyv,
451 mapisopen,
452 clientinfo2string(cinfo, NULL, 0),
453 shmem->mstate.shmid,
454 (int)shmem->keystate.key);
455
456 switch (shmem->type) {
457 case SHMEM_BW:
458 case SHMEM_MONITOR:
459 case SHMEM_SS:
460 break;
461
462 default:
463 SERRX(shmem->type);
464 }
465
466 socks_lock(lock, (off_t)shmem->mstate.shmid, 1, 1, 1);
467
468 MUNPROTECT_SHMEMHEADER(shmem);
469
470 ++shmem->mstate.clients;
471
472 MPROTECT_SHMEMHEADER(shmem);
473 if (shmem->keystate.key != key_unset) {
474 size_t sizemapped;
475 ssize_t i;
476 int rc;
477
478 if (!mapisopen) {
479 MUNPROTECT_SHMEMHEADER(shmem);
480
481 rc = keystate_openmap(shmem->mstate.shmid,
482 &shmem->keystate,
483 &sizemapped);
484
485 MPROTECT_SHMEMHEADER(shmem);
486
487 if (rc != 0) {
488 socks_unlock(lock, (off_t)shmem->mstate.shmid, 1);
489
490 slog(LOG_DEBUG, "%s: keystate_openmap() of shmid %lu failed: %s",
491 function, (unsigned long)shmem->mstate.shmid, strerror(errno));
492 return -1;
493 }
494 }
495
496 /*
497 * increment the current count for address, or add an entry for the addr.
498 */
499 if ((i = keystate_index(shmem, cinfo, should_do_expirescan(shmem))) >= 0)
500 slog(LOG_DEBUG, "%s: entry exists at index #%lu",
501 function, (unsigned long)i);
502 else {
503 /*
504 * a bit more complex. Need to expand the array and add the new
505 * entry; remap with a larger size first.
506 */
507 const char *fname = sockd_getshmemname(shmem->mstate.shmid,
508 shmem->keystate.key);
509 void *newmap;
510 int fd;
511
512 slog(LOG_DEBUG,
513 "%s: need to expand keyv array to %lu entries for cinfo %s",
514 function,
515 (unsigned long)shmem->keystate.keyc + 1,
516 clientinfo2string(cinfo, NULL, 0));
517
518 if ((fd = open(fname, O_RDWR)) == -1) {
519 swarn("%s: could not open shmemfile %s", function, fname);
520
521 if (doclosemap) {
522 MUNPROTECT_SHMEMHEADER(shmem);
523
524 keystate_closemap(shmem->mstate.shmid,
525 &shmem->keystate,
526 sizemapped,
527 -1);
528
529 MPROTECT_SHMEMHEADER(shmem);
530 }
531
532 socks_unlock(lock, (off_t)shmem->mstate.shmid, 1);
533
534 return -1;
535 }
536
537 sizemapped
538 = (shmem->keystate.keyc + 1) * sizeof(*shmem->keystate.keyv);
539
540 MUNPROTECT_SHMEMHEADER(shmem);
541
542 newmap = sockd_mmap(shmem->keystate.keyv,
543 sizemapped,
544 PROT_READ | PROT_WRITE,
545 MAP_SHARED,
546 fd,
547 1);
548
549 MPROTECT_SHMEMHEADER(shmem);
550
551 close(fd);
552
553 if (newmap == MAP_FAILED) {
554 swarn("%s: failed to mmap(2) shmeminfo of size %lu from "
555 "file %s on fd %d",
556 function, (unsigned long)sizemapped, fname, fd);
557
558 socks_unlock(lock, (off_t)shmem->mstate.shmid, 1);
559 return -1;
560 }
561
562 shmem->keystate.keyv = newmap;
563
564 i = shmem->keystate.keyc;
565
566 MUNPROTECT_SHMEMHEADER(shmem);
567
568 ++shmem->keystate.keyc;
569
570 MPROTECT_SHMEMHEADER(shmem);
571 }
572
573 SASSERTX((size_t)i < shmem->keystate.keyc);
574
575 MUNPROTECT_SHMEMHEADER(shmem);
576 switch (shmem->keystate.key) {
577 case key_from: {
578 void *dst;
579
580 switch (cinfo->from.ss_family) {
581 case AF_INET:
582 dst = &shmem->keystate.keyv[i].data.from.addr.ipv4;
583 break;
584
585 case AF_INET6:
586 dst = &shmem->keystate.keyv[i].data.from.addr.ipv6;
587 break;
588
589 default:
590 SERRX(cinfo->from.ss_family);
591 }
592
593 shmem->keystate.keyv[i].data.from.safamily = cinfo->from.ss_family;
594 memcpy(dst,
595 GET_SOCKADDRADDR(&cinfo->from),
596 inaddrlen(cinfo->from.ss_family));
597 ++shmem->keystate.keyv[i].data.from.addrc;
598
599 statecount = (ssize_t)shmem->keystate.keyv[i].data.from.addrc;
600
601 slog(LOG_DEBUG, "%s: updated entry for address %s at index #%lu",
602 function,
603 sockaddr2string2(&cinfo->from, 0, NULL, 0),
604 (unsigned long)i);
605
606 break;
607 }
608
609 #if HAVE_SOCKS_HOSTID
610 case key_hostid:
611 SASSERTX(shmem->keystate.keyinfo.hostindex <= cinfo->hostidc);
612
613 shmem->keystate.keyv[i].data.hostid.ipv4
614 = cinfo->hostidv[shmem->keystate.keyinfo.hostindex - 1];
615
616 ++shmem->keystate.keyv[i].data.hostid.addrc;
617
618 statecount = (ssize_t)shmem->keystate.keyv[i].data.hostid.addrc;
619
620 break;
621 #endif /* HAVE_SOCKS_HOSTID */
622
623 default:
624 SERRX(shmem->keystate.key);
625 }
626
627 if (doclosemap) {
628 MUNPROTECT_SHMEMHEADER(shmem);
629
630 keystate_closemap(shmem->mstate.shmid,
631 &shmem->keystate,
632 sizemapped,
633 i);
634
635 MPROTECT_SHMEMHEADER(shmem);
636 }
637 }
638 MUNPROTECT_SHMEMHEADER(shmem);
639
640 if (sockscf.option.debug >= DEBUG_VERBOSE)
641 slog(LOG_DEBUG,
642 "%s: post-use: lock = %d, clients = %lu (%ld), shmem = %p, "
643 "shmid %ld, cinfo = %s",
644 function,
645 lock,
646 (unsigned long)shmem->mstate.clients,
647 (long)statecount,
648 shmem,
649 shmem->mstate.shmid,
650 clientinfo2string(cinfo, NULL, 0));
651
652 socks_unlock(lock, (off_t)shmem->mstate.shmid, 1);
653 return 0;
654 }
655
656 int
shmem_unuse(shmem,cinfo,lock)657 shmem_unuse(shmem, cinfo, lock)
658 shmem_object_t *shmem;
659 const clientinfo_t *cinfo;
660 int lock;
661 {
662 const char *function = "shmem_unuse()";
663 #if DEBUG /* memory-mapped file contents may not be saved in coredumps. */
664 shmem_object_t _shmem = *shmem;
665 #endif /* DEBUG */
666 ssize_t statecount = -1;
667
668 SASSERTX(shmem != NULL);
669 SASSERTX(shmem->mstate.number > 0);
670
671 if (sockscf.option.debug >= DEBUG_VERBOSE)
672 slog(LOG_DEBUG, "%s: pre-use: lock = %d, # of clients = %lu, rule = %lu, "
673 "shmem = %p, cinfo = %s, shmid %ld, key %d",
674 function,
675 lock,
676 (unsigned long)shmem->mstate.clients,
677 (unsigned long)shmem->mstate.number,
678 shmem,
679 clientinfo2string(cinfo, NULL, 0),
680 shmem->mstate.shmid,
681 (int)shmem->keystate.key);
682
683 switch (shmem->type) {
684 case SHMEM_BW:
685 case SHMEM_MONITOR:
686 case SHMEM_SS:
687 break;
688
689 default:
690 SERRX(shmem->type);
691 }
692
693 socks_lock(lock, (off_t)shmem->mstate.shmid, 1, 1, 1);
694
695 if (shmem->keystate.key != key_unset) {
696 #if DEBUG /* memory-mapped file contents may not be saved in coredumps. */
697 keystate_t _keystate;
698 #endif /* DEBUG */
699 ssize_t i;
700 size_t sizemapped;
701 int rc;
702
703 SASSERTX(shmem->keystate.keyv == NULL);
704 SASSERTX(shmem->keystate.keyc > 0);
705
706 MUNPROTECT_SHMEMHEADER(shmem);
707
708 rc = keystate_openmap(shmem->mstate.shmid, &shmem->keystate, &sizemapped);
709
710 MPROTECT_SHMEMHEADER(shmem);
711
712 if (rc != 0) {
713 socks_unlock(lock, (off_t)shmem->mstate.shmid, 1);
714
715 slog(LOG_DEBUG, "%s: keystate_openmap() of shmid %lu failed: %s",
716 function, (unsigned long)shmem->mstate.shmid, strerror(errno));
717
718 return -1;
719 }
720
721 #if DEBUG /* memory-mapped file contents may not be saved in coredumps. */
722 _keystate = shmem->keystate;
723 #endif /* DEBUG */
724
725 SASSERTX(sizemapped > 0);
726 SASSERTX(shmem->keystate.keyv != NULL);
727 SASSERTX(shmem->keystate.keyc > 0);
728
729 i = keystate_index(shmem, cinfo, should_do_expirescan(shmem));
730 SASSERTX(i >= 0);
731 SASSERTX((size_t)i < shmem->keystate.keyc);
732
733 MUNPROTECT_SHMEMHEADER(shmem);
734
735 switch (shmem->keystate.key) {
736 case key_from:
737 SASSERTX(shmem->keystate.keyv[i].data.from.addrc > 0);
738 --shmem->keystate.keyv[i].data.from.addrc;
739 statecount = (ssize_t)shmem->keystate.keyv[i].data.from.addrc;
740 break;
741
742 #if HAVE_SOCKS_HOSTID
743 case key_hostid:
744 SASSERTX(shmem->keystate.keyv[i].data.hostid.addrc > 0);
745 --shmem->keystate.keyv[i].data.hostid.addrc;
746 statecount = (ssize_t)shmem->keystate.keyv[i].data.hostid.addrc;
747 break;
748 #endif /* HAVE_SOCKS_HOSTID */
749
750 default:
751 SERRX(shmem->keystate.key);
752 }
753
754 keystate_closemap(shmem->mstate.shmid, &shmem->keystate, sizemapped, i);
755
756 MPROTECT_SHMEMHEADER(shmem);
757 }
758
759 MUNPROTECT_SHMEMHEADER(shmem);
760
761 SASSERTX(shmem->mstate.clients > 0);
762 --shmem->mstate.clients;
763
764 MPROTECT_SHMEMHEADER(shmem);
765
766 if (sockscf.option.debug >= DEBUG_VERBOSE)
767 slog(LOG_DEBUG,
768 "%s: post-use: lock = %d, clients = %lu (%ld), shmem = %p, "
769 "shmid = %ld, cinfo = %s",
770 function,
771 lock,
772 (unsigned long)shmem->mstate.clients,
773 (long)statecount,
774 shmem,
775 shmem->mstate.shmid,
776 clientinfo2string(cinfo, NULL, 0));
777
778 socks_unlock(lock, (off_t)shmem->mstate.shmid, 1);
779 return 0;
780 }
781
782
783 int
keystate_hasexpired(shmem,keyindex,timenow)784 keystate_hasexpired(shmem, keyindex, timenow)
785 const shmem_object_t *shmem;
786 const size_t keyindex;
787 const struct timeval *timenow;
788 {
789 const char *function = "keystate_hasexpired()";
790 struct timeval tdiff;
791 char buf[64];
792 int expired = 0;
793
794 SASSERTX(keyindex < shmem->keystate.keyc);
795
796 switch (shmem->type) {
797 case SHMEM_SS: {
798
799 if (!shmem->object.ss.throttle_perstate_isset)
800 break; /* only throttle-limit can expire. */
801
802 timersub(timenow,
803 &shmem->keystate.keyv[keyindex].info.ss.starttime,
804 &tdiff);
805
806 if (tdiff.tv_sec >= shmem->object.ss.throttle_perstate.limit.seconds)
807 expired = 1;
808
809 break;
810 }
811
812 default:
813 break;
814 }
815
816 if (expired) {
817 if (!timerisset(&shmem->keystate.keyv[keyindex].info.ss.starttime))
818 snprintf(buf, sizeof(buf), "yes (init)");
819 else
820 snprintf(buf, sizeof(buf), "yes, %ld.%06lds ago",
821 (long)tdiff.tv_sec, (long)tdiff.tv_usec);
822 }
823
824 if (sockscf.option.debug) {
825 const char *keystring;
826 keystate_data_t key;
827
828 keystate_data(&shmem->keystate, keyindex, &key);
829 keystring = keydata2string(&key, NULL, 0);
830
831 slog(LOG_DEBUG,
832 "%s: keystate address %s, index %lu, starttime = %ld.%06ld, "
833 "clients = %lu, expired: %s",
834 function,
835 keystring,
836 (unsigned long)keyindex,
837 (long)shmem->keystate.keyv[keyindex].info.ss.starttime.tv_sec,
838 (long)shmem->keystate.keyv[keyindex].info.ss.starttime.tv_usec,
839 (unsigned long)keystate_clientcount(&shmem->keystate, keyindex),
840 expired ? buf : "no");
841 }
842
843 return expired;
844 }
845
846 static unsigned long
mem2shmem(config,firstid)847 mem2shmem(config, firstid)
848 struct config *config;
849 const unsigned long firstid;
850 {
851 const char *function = "mem2shmem()";
852 monitor_t *monitor;
853 rule_t *rule;
854 rule_t *rulev[] = { config->crule,
855
856 #if HAVE_SOCKS_HOSTID
857 config->hrule,
858 #endif /* HAVE_SOCKS_HOSTID */
859
860 #if HAVE_SOCKS_RULES
861 config->srule
862 #endif /* HAVE_SOCKS_RULES */
863 };
864 unsigned long nextid;
865 size_t i;
866
867 /*
868 * Only main mother allocates the memory. Children just set the
869 * shmid value and use it to attach to the memory as needed later on.
870 * Mother makes sure all the ids are in consecutive order starting
871 * from the passed "firstid" argument, so children just need to
872 * increment it to get the shmid of the next object.
873 */
874 SASSERTX(pidismother(sockscf.state.pid) == 1);
875
876 /*
877 * Mother needs to create and fill in the correct contents initially,
878 * but after that, the child-processes attach and update the segments
879 * as needed.
880 */
881 #define HANDLE_SHMCR(object, memfield, idfield, id) \
882 do { \
883 const statekey_t key = (object)->memfield->keystate.key; \
884 const char *fname = sockd_getshmemname(id, key_unset); \
885 const int flags = O_RDWR | O_CREAT | O_EXCL; \
886 const mode_t mode = S_IRUSR | S_IWUSR; \
887 shmem_object_t *mem; \
888 int fd; \
889 \
890 SASSERTX(id != 0); \
891 SASSERTX(fname != NULL && *fname != NUL); \
892 \
893 SASSERTX((object)->memfield->mstate.number > 0); \
894 SASSERTX((object)->memfield->mstate.parenttype != object_none); \
895 SASSERTX((object)->type != object_none); \
896 SASSERTX((object)->memfield->type != SHMEM_NONE); \
897 \
898 if ((fd = open(fname, flags, mode)) == -1) \
899 serr("%s: failed to create shmemfile \"%s\"", function, fname); \
900 \
901 slog(LOG_DEBUG, \
902 "%s: will use filename %s for shmid %ld when creating shmem segment " \
903 "for " #memfield " in %s #%lu", \
904 function, \
905 fname, \
906 (id), \
907 objecttype2string(object->type), \
908 (unsigned long)(object)->number); \
909 \
910 if ((mem = sockd_mmap(NULL, \
911 sizeof(*(object)->memfield), \
912 PROT_READ | PROT_WRITE, \
913 MAP_SHARED, \
914 fd, \
915 1)) == MAP_FAILED) \
916 serr("%s: sockd_mmap of size %lu failed", \
917 function, (unsigned long)sizeof(*(object)->memfield)); \
918 \
919 \
920 /* \
921 * replace the ordinary memory with shared memory. \
922 */ \
923 *mem = *(object)->memfield; \
924 free((object)->memfield); \
925 (object)->memfield = mem; \
926 \
927 close(fd); \
928 \
929 if (key != key_unset) { \
930 const char *fname = sockd_getshmemname(id, key); \
931 \
932 SASSERTX(fname != NULL && *fname != NUL); \
933 \
934 if ((fd = open(fname, flags, mode)) == -1) \
935 serr("%s: failed to create file %s", function, fname); \
936 \
937 /* \
938 * Just create the file for now. Nothing to init. \
939 */ \
940 \
941 close(fd); \
942 \
943 slog(LOG_DEBUG, \
944 "%s: will use filename %s for shmid %lu/key %lu when creating " \
945 "shmem segment for " #memfield " in %s #%lu", \
946 function, \
947 fname, \
948 (unsigned long)(id), \
949 (unsigned long)(key), \
950 objecttype2string((object)->type), \
951 (unsigned long)(object)->number); \
952 } \
953 \
954 SASSERTX((object)->memfield->mstate.shmid == 0); \
955 (object)->memfield->mstate.shmid = (id); \
956 \
957 SASSERTX((object)->idfield == 0); \
958 (object)->idfield = (id); \
959 \
960 slog(LOG_DEBUG, "%s: allocated " #idfield " %ld for object #%lu", \
961 function, (object)->idfield, (unsigned long)(object)->number); \
962 \
963 SASSERTX(munmap((object)->memfield, sizeof(*(object)->memfield)) == 0); \
964 (object)->memfield = NULL; \
965 } while (/* CONSTCOND */ 0)
966
967
968 nextid = firstid;
969
970 /*
971 * Shmem for rules.
972 */
973 for (i = 0; i < ELEMENTS(rulev); ++i) {
974 rule = rulev[i];
975
976 while (rule != NULL) {
977 if (rule->bw != NULL) {
978 SASSERTX(rule->bw->type == SHMEM_BW);
979 HANDLE_SHMCR(rule, bw, bw_shmid, nextid);
980 ++nextid;
981 }
982
983 if (rule->ss != NULL) {
984 SASSERTX(rule->ss->type == SHMEM_SS);
985 HANDLE_SHMCR(rule, ss, ss_shmid, nextid);
986 ++nextid;
987 }
988
989 rule = rule->next;
990 }
991 }
992
993 /*
994 * Shmem for monitors.
995 */
996 for (monitor = config->monitor; monitor != NULL; monitor = monitor->next) {
997 if (monitor->mstats != NULL) {
998 SASSERTX(monitor->mstats->type == SHMEM_MONITOR);
999 HANDLE_SHMCR(monitor, mstats, mstats_shmid, nextid);
1000 ++nextid;
1001 }
1002 }
1003
1004 slog(LOG_DEBUG,
1005 "%s: ok, allocated %ld shared memory id%s, first id is %lu, "
1006 "last id is %lu",
1007 function,
1008 (long)(nextid - firstid),
1009 nextid - firstid == 1 ? "" : "s",
1010 firstid,
1011 nextid);
1012
1013 return nextid;
1014 }
1015
1016 static void
keystate_removeindex(keystate,index)1017 keystate_removeindex(keystate, index)
1018 keystate_t *keystate;
1019 const size_t index;
1020 {
1021 const char *function = "keystate_removeindex()";
1022 sa_family_t safamily;
1023 void *addr;
1024
1025 switch (keystate->key) {
1026 case key_from:
1027 switch (keystate->keyv[index].data.from.safamily) {
1028 case AF_INET:
1029 safamily = AF_INET;
1030 addr = &keystate->keyv[index].data.from.addr.ipv4;
1031 break;
1032
1033 case AF_INET6:
1034 safamily = AF_INET6;
1035 addr = &keystate->keyv[index].data.from.addr.ipv6;
1036 break;
1037
1038 default:
1039 SERRX(keystate->keyv[index].data.from.safamily);
1040 }
1041
1042 break;
1043
1044
1045 #if HAVE_SOCKS_HOSTID
1046 case key_hostid:
1047 safamily = AF_INET6;
1048 addr = &keystate->keyv[index].data.hostid.ipv4;
1049 break;
1050 #endif /* HAVE_SOCKS_HOSTID */
1051
1052 default:
1053 SERRX(keystate->key);
1054 }
1055
1056 if (sockscf.option.debug) {
1057 char ntop[MAXSOCKADDRSTRING];
1058
1059 if (inet_ntop(safamily, addr, ntop, sizeof(ntop)) == NULL) {
1060 swarn("%s: inet_ntop(3) failed on safamily %s, addr %s",
1061 function,
1062 safamily2string(safamily),
1063 addr2hexstring(addr, safamily, NULL, 0));
1064 }
1065
1066 slog(LOG_DEBUG,
1067 "%s: removing entry for address %s (key: %s) at index #%lu "
1068 "from keystate. Will have %lu entries in keyv afterwards",
1069 function,
1070 ntop,
1071 statekey2string(keystate->key),
1072 (unsigned long)index,
1073 (unsigned long)keystate->keyc - 1);
1074 }
1075
1076
1077 /*
1078 * bzero the removed entry, so that if somebody overwrites it before
1079 * we close and reopen the mmap(2)-ed file, it will be zero.
1080 */
1081 bzero(&keystate->keyv[index], sizeof(*keystate->keyv));
1082
1083 if (keystate->keyc > 1)
1084 memmove(&keystate->keyv[index],
1085 &keystate->keyv[index + 1],
1086 sizeof(*keystate->keyv) * (keystate->keyc - (index + 1)));
1087
1088 --keystate->keyc;
1089
1090 if (sockscf.option.debug) {
1091 size_t i;
1092
1093 for (i = 0; i < keystate->keyc; ++i) {
1094 const char *keystring;
1095 keystate_data_t key;
1096
1097 keystate_data(keystate, i, &key);
1098 keystring = keydata2string(&key, NULL, 0);
1099
1100 slog(LOG_DEBUG, "%s: entry #%lu: %s",
1101 function, (unsigned long)i, keystring);
1102 }
1103 }
1104 }
1105
1106 ssize_t
keystate_index(shmem,cinfo,doexpirescan)1107 keystate_index(shmem, cinfo, doexpirescan)
1108 shmem_object_t *shmem;
1109 const clientinfo_t *cinfo;
1110 const int doexpirescan;
1111 {
1112 const char *function = "keystate_index()";
1113 static ssize_t lastmatched = -1;
1114 const void *datatomatch;
1115 keystate_data_t keydata;
1116 keystate_data_type datatype;
1117 struct timeval timenow;
1118 ssize_t matchedi;
1119 size_t i, datalen;
1120 char extrainfo[128] = { NUL };
1121
1122 if (doexpirescan)
1123 gettimeofday_monotonic(&timenow);
1124
1125 SASSERTX(shmem->keystate.key != key_unset);
1126
1127 switch (shmem->keystate.key) {
1128 case key_from:
1129 switch (cinfo->from.ss_family) {
1130 case AF_INET:
1131 datatype = keytype_ipv4;
1132 break;
1133
1134 case AF_INET6:
1135 datatype = keytype_ipv6;
1136 break;
1137
1138 default:
1139 SERRX(cinfo->from.ss_family);
1140 }
1141
1142 datatomatch = GET_SOCKADDRADDR(&cinfo->from);
1143 datalen = inaddrlen(cinfo->from.ss_family);
1144 break;
1145
1146 #if HAVE_SOCKS_HOSTID
1147 case key_hostid:
1148 SASSERTX(shmem->keystate.keyinfo.hostindex <= cinfo->hostidc);
1149
1150 datatomatch = &cinfo->hostidv[shmem->keystate.keyinfo.hostindex - 1];
1151 datatype = keytype_ipv4;
1152 datalen = sizeof(keydata.data.ipv4);
1153
1154 snprintf(extrainfo, sizeof(extrainfo), "(hostindex = %u)",
1155 (unsigned)shmem->keystate.keyinfo.hostindex);
1156
1157 break;
1158 #endif /* HAVE_SOCKS_HOSTID */
1159
1160 default:
1161 SERRX(shmem->keystate.key);
1162 }
1163
1164 if (lastmatched != -1 && lastmatched < (ssize_t)shmem->keystate.keyc) {
1165 keystate_data(&shmem->keystate, lastmatched, &keydata);
1166
1167 switch (keydata.type) {
1168 case keytype_ipv4:
1169 if (memcmp(&keydata.data.ipv4, datatomatch, datalen) == 0)
1170 matchedi = lastmatched;
1171 else
1172 matchedi = -1;
1173 break;
1174
1175 case keytype_ipv6:
1176 if (memcmp(&keydata.data.ipv6, datatomatch, datalen) == 0)
1177 matchedi = lastmatched;
1178 else
1179 matchedi = -1;
1180 break;
1181
1182 default:
1183 SERRX(keydata.type);
1184 }
1185 }
1186 else
1187 matchedi = -1;
1188
1189 if (sockscf.option.debug) {
1190 char ntop[MAXSOCKADDRSTRING];
1191
1192 switch (datatype) {
1193 case keytype_ipv4:
1194 if (inet_ntop(AF_INET, datatomatch, ntop, sizeof(ntop)) == NULL) {
1195 swarn("%s: inet_ntop(3) failed on %s %x",
1196 function,
1197 atype2string(AF_INET),
1198 ((const struct in_addr *)datatomatch)->s_addr);
1199
1200 snprintf(ntop, sizeof(ntop), "<unknown>");
1201 }
1202 break;
1203
1204 case keytype_ipv6:
1205 if (inet_ntop(AF_INET6, datatomatch, ntop, sizeof(ntop)) == NULL) {
1206 swarn("%s: inet_ntop(3) failed on %s " IP6_FMTSTR,
1207 function,
1208 atype2string(AF_INET6),
1209 IP6_ELEMENTS((const struct in6_addr *)datatomatch));
1210
1211 snprintf(ntop, sizeof(ntop), "<unknown>");
1212 }
1213 break;
1214
1215 default:
1216 SERRX(datatype);
1217 }
1218
1219 slog(LOG_DEBUG,
1220 "%s: trying to find a match for key %s, address %s%s%s in keyv "
1221 "array with %lu entries. Doexpirescan = %d, matchedi = %ld%s",
1222 function,
1223 statekey2string(shmem->keystate.key),
1224 ntop,
1225 *extrainfo == NUL ? "" : " ",
1226 *extrainfo == NUL ? "" : extrainfo,
1227 (unsigned long)shmem->keystate.keyc,
1228 doexpirescan,
1229 (long)matchedi,
1230 matchedi == -1 ?
1231 "" : doexpirescan ?
1232 ". Not scanning since index from last time matches" : "");
1233 }
1234
1235 if (matchedi != -1)
1236 return matchedi;
1237
1238 i = 0;
1239 while (i < shmem->keystate.keyc) {
1240 keystate_data_t keydata;
1241 int matches;
1242
1243 if (doexpirescan && keystate_hasexpired(shmem, i, &timenow)) {
1244 MUNPROTECT_SHMEMHEADER(shmem);
1245
1246 if (keystate_clientcount(&shmem->keystate, i) == 0) {
1247 keystate_removeindex(&shmem->keystate, i);
1248 continue;
1249 }
1250 else /* can't remove as long as long as entry is in use; just reset. */
1251 RESET_THROTTLE(&shmem->object.ss.throttle, timenow);
1252
1253 MPROTECT_SHMEMHEADER(shmem);
1254 }
1255
1256 keystate_data(&shmem->keystate, i, &keydata);
1257
1258 if (keydata.type == datatype) {
1259 switch (keydata.type) {
1260 case keytype_ipv4:
1261 matches
1262 = (memcmp(&keydata.data.ipv4, datatomatch, datalen) == 0);
1263 break;
1264
1265 case keytype_ipv6:
1266 matches
1267 = (memcmp(&keydata.data.ipv6, datatomatch, datalen) == 0);
1268 break;
1269
1270 default:
1271 SERRX(keydata.type);
1272 }
1273
1274 if (sockscf.option.debug)
1275 slog(LOG_DEBUG,
1276 "%s: compared against %s at index #%lu using %lu bytes: %s",
1277 function,
1278 keydata2string(&keydata, NULL, 0),
1279 (unsigned long)i,
1280 (unsigned long)datalen,
1281 matches ? "matches" : "no match");
1282 }
1283 else /* can't possibly match. */
1284 matches = 0;
1285
1286 if (matches) {
1287 SASSERTX(matchedi == -1);
1288 matchedi = lastmatched = (ssize_t)i;
1289
1290 if (!doexpirescan)
1291 break;
1292 }
1293
1294 ++i;
1295 }
1296
1297 if (doexpirescan) {
1298 MUNPROTECT_SHMEMHEADER(shmem);
1299
1300 shmem->keystate.lastexpirescan = timenow.tv_sec;
1301
1302 MPROTECT_SHMEMHEADER(shmem);
1303 }
1304 return matchedi;
1305 }
1306
1307 int
keystate_openmap(id,keystate,sizemapped)1308 keystate_openmap(id, keystate, sizemapped)
1309 const unsigned long id;
1310 keystate_t *keystate;
1311 size_t *sizemapped;
1312 {
1313 const char *function = "keystate_openmap()";
1314 const char *fname = sockd_getshmemname(id, keystate->key);
1315 size_t _sizemapped;
1316
1317 SASSERTX(fname != NULL && *fname != NUL);
1318 SASSERTX(keystate->key != key_unset);
1319
1320 slog(LOG_DEBUG, "%s: shmid %ld, key %d",
1321 function, id, (int)keystate->key);
1322
1323 if (sizemapped == NULL)
1324 sizemapped = &_sizemapped;
1325
1326 *sizemapped = keystate->keyc * sizeof(*keystate->keyv);
1327
1328 if (*sizemapped == 0) {
1329 SASSERTX(keystate->keyc == 0);
1330 SASSERTX(keystate->keyv == NULL);
1331 }
1332 else {
1333 const int fd = open(fname, O_RDWR);
1334
1335 if (fd == -1) {
1336 slog(sockd_motherexists() ? LOG_WARNING: LOG_DEBUG,
1337 "%s: could not open shmemfile %s generated from "
1338 "id %ld, key %d: %s",
1339 function,
1340 fname,
1341 id,
1342 (int)keystate->key,
1343 getppid() == 1 ?
1344 "probably because mother has exited and deleted it already"
1345 : strerror(errno));
1346
1347 return -1;
1348 }
1349
1350 if ((keystate->keyv = sockd_mmap(NULL,
1351 *sizemapped,
1352 PROT_READ | PROT_WRITE,
1353 MAP_SHARED,
1354 fd,
1355 0)) == MAP_FAILED) {
1356 swarn("%s: could not mmap shmemfile %s of size %lu generated from "
1357 "id %ld, key %d",
1358 function,
1359 fname,
1360 (unsigned long)*sizemapped,
1361 id,
1362 (int)keystate->key);
1363
1364 keystate->keyv = NULL;
1365 close(fd);
1366
1367 return -1;
1368 }
1369
1370 close(fd);
1371 }
1372
1373 slog(LOG_DEBUG, "%s: mapped %lu bytes for shmid %ld, key %d, at address %p",
1374 function,
1375 (unsigned long)*sizemapped,
1376 id,
1377 (int)keystate->key,
1378 keystate->keyv);
1379
1380 return 0;
1381 }
1382
1383 void
keystate_closemap(id,keystate,mappedsize,changedindex)1384 keystate_closemap(id, keystate, mappedsize, changedindex)
1385 const unsigned long id;
1386 keystate_t *keystate;
1387 const size_t mappedsize;
1388 const ssize_t changedindex;
1389 {
1390 const char *function = "keystate_closemap()";
1391 const char *fname = sockd_getshmemname(id, keystate->key);
1392 size_t newsize;
1393
1394 newsize = keystate->keyc * sizeof(*keystate->keyv);
1395
1396 slog(LOG_DEBUG,
1397 "%s: mapped size for keystate of id %lu is %lu, newsize is %lu, "
1398 "changedindex: %ld",
1399 function,
1400 (unsigned long)id,
1401 (unsigned long)mappedsize,
1402 (unsigned long)newsize,
1403 (long)changedindex);
1404
1405 if (sockscf.option.debug) {
1406 keystate_data_t keydata;
1407 size_t i;
1408
1409 for (i = 0; i < keystate->keyc; ++i)
1410 slog(LOG_DEBUG, "%s: entry #%lu: %s",
1411 function,
1412 (unsigned long)i,
1413 keydata2string(keystate_data(keystate, i, &keydata), NULL, 0));
1414 }
1415
1416 if (mappedsize == 0)
1417 SASSERTX(keystate->keyv == NULL);
1418 else {
1419 #if !HAVE_UNIFIED_BUFFERCACHE
1420 /*
1421 * With a unified buffer cache, modifications to the mmap(2)-ed file will
1422 * be visible by other processes that open(2) and mmap(2) the same file
1423 * without having to msync(2) the memory to file. I.e., this will work
1424 * Process1:
1425 * t1: open(2) file F.
1426 * t2: mmap(2) file F.
1427 * t3: <modify mmap(2)-ed memory>
1428 *
1429 * Process2:
1430 * t4: open(2) file F.
1431 * t5: mmap(2) file F.
1432 * t6: <see same thing Process1 sees>
1433 *
1434 * This code is for platforms where it does not work. Currently
1435 * only OpenBSD AFAIK (5.1 at least).
1436 */
1437 void *addr;
1438 size_t len;
1439 int needmsync;
1440
1441 SASSERTX(keystate->keyv != NULL);
1442
1443 if (mappedsize < newsize) {
1444 needmsync = 1;
1445
1446 /*
1447 * don't know what has changed, have to msync everything.
1448 */
1449
1450 addr = keystate->keyv;
1451 len = newsize;
1452 }
1453 else if (changedindex != -1) {
1454 needmsync = 1;
1455
1456 addr = (void *)ROUNDDOWN((uintptr_t)&keystate->keyv[changedindex],
1457 sockscf.state.pagesize);
1458
1459 SASSERTX((uintptr_t)keystate->keyv <= (uintptr_t)addr);
1460
1461 len = ((uintptr_t)&keystate->keyv[changedindex] - (uintptr_t)addr)
1462 + sizeof(keystate->keyv[changedindex]);
1463 }
1464 else {
1465 SASSERTX(mappedsize == newsize);
1466 needmsync = 0;
1467 }
1468
1469 if (needmsync) {
1470 const int rc = msync(addr, len, MS_SYNC);
1471
1472 slog(rc == 0 ? LOG_DEBUG : LOG_WARNING,
1473 "%s: msync(%p, %lu, MS_SYNC), based on mappedsize %lu, "
1474 "newsize %lu, changedindex %ld, keyv %p %s (%s)",
1475 function,
1476 addr,
1477 len,
1478 (unsigned long)mappedsize,
1479 (unsigned long)newsize,
1480 (long)changedindex,
1481 keystate->keyv,
1482 rc == 0 ? "is ok" : "failed",
1483 strerror(errno));
1484 }
1485 #endif /* !HAVE_UNIFIED_BUFFERCACHE */
1486
1487 SASSERTX(keystate->keyv != NULL);
1488
1489 if (munmap(keystate->keyv, mappedsize) != 0)
1490 swarn("%s: munmap(2) of keystate.keyv (%p) of size %lu failed",
1491 function, keystate->keyv, (unsigned long)mappedsize);
1492
1493 keystate->keyv = NULL;
1494 }
1495
1496 if (newsize != mappedsize) {
1497 if (truncate(fname, (off_t)newsize) == 0)
1498 slog(LOG_DEBUG, "%s: truncated shmemfile %s to size %lu",
1499 function, fname, (unsigned long)newsize);
1500 else
1501 swarn("%s: could not truncate shmemfile %s to size %lu",
1502 function, fname, (unsigned long)newsize);
1503 }
1504 }
1505
1506 #if DIAGNOSTIC && !SOCKS_CLIENT /* for internal debugging/testing. */
1507 void
shmemcheck(void)1508 shmemcheck(void)
1509 {
1510 const int errno_s = errno;
1511 rule_t *rulev[] = { sockscf.crule,
1512
1513 #if HAVE_SOCKS_HOSTID
1514 sockscf.hrule,
1515 #endif /* HAVE_SOCKS_HOSTID */
1516
1517 #if HAVE_SOCKS_RULES
1518 sockscf.srule
1519 #endif /* HAVE_SOCKS_RULES */
1520 };
1521 size_t i;
1522
1523 /*
1524 * Shmem for existing rules.
1525 */
1526 for (i = 0; i < ELEMENTS(rulev); ++i) {
1527 rule_t *_rule = rulev[i];
1528
1529 while (_rule != NULL) {
1530 rule_t rule = *_rule;
1531
1532 /*
1533 * sockd_shm{at,dt} will do the checking.
1534 */
1535 sockd_shmat(&rule, SHMEM_ALL);
1536 sockd_shmdt(&rule, SHMEM_ALL);
1537
1538 _rule = _rule->next;
1539 }
1540 }
1541
1542 if (pidismother(sockscf.state.pid) == 1) {
1543 /*
1544 * Shmem for old rules.
1545 */
1546 for (i = 0; i < sockscf.oldshmemc; ++i) {
1547 rule_t rule;
1548
1549 bzero(&rule, sizeof(rule));
1550
1551 switch (sockscf.oldshmemv[i].type) {
1552 case SHMEM_BW:
1553 rule.bw_shmid = sockscf.oldshmemv[i].id;
1554 break;
1555
1556 case SHMEM_MONITOR:
1557 rule.mstats_shmid = sockscf.oldshmemv[i].id;
1558 break;
1559
1560 case SHMEM_SS:
1561 rule.ss_shmid = sockscf.oldshmemv[i].id;
1562 break;
1563
1564 default:
1565 SERRX(sockscf.oldshmemv[i].type);
1566 }
1567
1568 (void)sockd_shmat(&rule, sockscf.oldshmemv[i].type);
1569 (void)sockd_shmdt(&rule, sockscf.oldshmemv[i].type);
1570 }
1571 }
1572
1573 errno = errno_s;
1574 }
1575 #endif /* DIAGNOSTIC && !SOCKS_CLIENT */
1576
1577 static int
should_do_expirescan(shmem)1578 should_do_expirescan(shmem)
1579 const shmem_object_t *shmem;
1580 {
1581 ssize_t timer;
1582
1583 if ((timer = keystate_timer(shmem)) != -1
1584 && socks_difftime(time_monotonic(NULL),
1585 shmem->keystate.lastexpirescan) >= timer)
1586 return 1;
1587
1588 return 0;
1589 }
1590
1591 static ssize_t
keystate_timer(shmem)1592 keystate_timer(shmem)
1593 const shmem_object_t *shmem;
1594 {
1595
1596 switch (shmem->type) {
1597 case SHMEM_SS:
1598 if (shmem->object.ss.throttle_perstate_isset)
1599 return (size_t)shmem->object.ss.throttle_perstate.limit.seconds;
1600 else
1601 return -1;
1602
1603 default:
1604 return -1;
1605 }
1606 }
1607
1608 static keystate_data_t *
keystate_data(keystate,index,keydata)1609 keystate_data(keystate, index, keydata)
1610 const keystate_t *keystate;
1611 const size_t index;
1612 keystate_data_t *keydata;
1613 {
1614
1615 SASSERTX(index < keystate->keyc);
1616 switch (keystate->key) {
1617 case key_from:
1618 switch (keystate->keyv[index].data.from.safamily) {
1619 case AF_INET:
1620 keydata->type = keytype_ipv4;
1621 keydata->data.ipv4 = keystate->keyv[index].data.from.addr.ipv4;
1622 break;
1623
1624 case AF_INET6:
1625 keydata->type = keytype_ipv6;
1626 keydata->data.ipv6 = keystate->keyv[index].data.from.addr.ipv6;
1627 break;
1628
1629 default:
1630 SERRX(keystate->keyv[index].data.from.safamily);
1631 }
1632
1633 break;
1634
1635
1636 #if HAVE_SOCKS_HOSTID
1637 case key_hostid:
1638 keydata->type = keytype_ipv4;
1639 keydata->data.ipv4 = keystate->keyv[index].data.hostid.ipv4;
1640 break;
1641 #endif /* HAVE_SOCKS_HOSTID */
1642
1643 default:
1644 SERRX(keystate->key);
1645 }
1646
1647 return keydata;
1648 }
1649
1650 static const char *
keydata2string(keydata,buf,buflen)1651 keydata2string(keydata, buf, buflen)
1652 const keystate_data_t *keydata;
1653 char *buf;
1654 size_t buflen;
1655
1656 {
1657 const char *function = "keydata2string()";
1658 const void *addr;
1659 sa_family_t safamily;
1660
1661 if (buf == NULL) {
1662 static char _buf[MAXSOCKADDRSTRING];
1663
1664 buf = _buf;
1665 buflen = sizeof(_buf);
1666 }
1667
1668 switch (keydata->type) {
1669 case keytype_ipv4:
1670 safamily = AF_INET;
1671 addr = &keydata->data.ipv4;
1672 break;
1673
1674 case keytype_ipv6:
1675 safamily = AF_INET6;
1676 addr = &keydata->data.ipv6;
1677 break;
1678
1679 default:
1680 SERRX(keydata->type);
1681 }
1682
1683 if (inet_ntop(safamily, addr, buf, buflen) == NULL) {
1684 addr2hexstring(addr, safamily, buf, buflen);
1685 swarn("%s: inet_ntop(3) failed on safamily %s, addr %s",
1686 function, safamily2string(safamily), buf);
1687 }
1688
1689 return buf;
1690 }
1691
1692 static size_t
keystate_clientcount(keystate,index)1693 keystate_clientcount(keystate, index)
1694 const keystate_t *keystate;
1695 const size_t index;
1696 {
1697
1698 SASSERTX(index < keystate->keyc);
1699
1700 switch (keystate->key) {
1701 case key_from:
1702 return keystate->keyv[index].data.from.addrc;
1703
1704 #if HAVE_SOCKS_HOSTID
1705 case key_hostid:
1706 return keystate->keyv[index].data.hostid.addrc;
1707 #endif /* HAVE_SOCKS_HOSTID */
1708
1709 default:
1710 SERRX(keystate->key);
1711 }
1712
1713 /* NOTREACHED */
1714 }
1715