2 * Copyright (c) 2020 Darren Tucker <dtucker@openbsd.org>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/socket.h>
20 #include <sys/types.h>
34 static int max_children
, max_persource
, ipv4_masklen
, ipv6_masklen
;
36 /* Per connection state, used to enforce unauthenticated connection limit. */
37 static struct child_info
{
43 srclimit_init(int max
, int persource
, int ipv4len
, int ipv6len
)
48 ipv4_masklen
= ipv4len
;
49 ipv6_masklen
= ipv6len
;
50 max_persource
= persource
;
51 if (max_persource
== INT_MAX
) /* no limit */
53 debug("%s: max connections %d, per source %d, masks %d,%d", __func__
,
54 max
, persource
, ipv4len
, ipv6len
);
56 fatal("%s: invalid number of sockets: %d", __func__
, max
);
57 child
= xcalloc(max_children
, sizeof(*child
));
58 for (i
= 0; i
< max_children
; i
++)
62 /* returns 1 if connection allowed, 0 if not allowed. */
64 srclimit_check_allow(int sock
, int id
)
66 struct xaddr xa
, xb
, xmask
;
67 struct sockaddr_storage addr
;
68 socklen_t addrlen
= sizeof(addr
);
69 struct sockaddr
*sa
= (struct sockaddr
*)&addr
;
70 int i
, bits
, first_unused
, count
= 0;
73 if (max_persource
== INT_MAX
) /* no limit */
76 debug("%s: sock %d id %d limit %d", __func__
, sock
, id
, max_persource
);
77 if (getpeername(sock
, sa
, &addrlen
) != 0)
78 return 1; /* not remote socket? */
79 if (addr_sa_to_xaddr(sa
, addrlen
, &xa
) != 0)
80 return 1; /* unknown address family? */
82 /* Mask address off address to desired size. */
83 bits
= xa
.af
== AF_INET
? ipv4_masklen
: ipv6_masklen
;
84 if (addr_netmask(xa
.af
, bits
, &xmask
) != 0 ||
85 addr_and(&xb
, &xa
, &xmask
) != 0) {
86 debug3("%s: invalid mask %d bits", __func__
, bits
);
90 first_unused
= max_children
;
91 /* Count matching entries and find first unused one. */
92 for (i
= 0; i
< max_children
; i
++) {
93 if (child
[i
].id
== -1) {
96 } else if (addr_cmp(&child
[i
].addr
, &xb
) == 0) {
100 if (addr_ntop(&xa
, xas
, sizeof(xas
)) != 0) {
101 debug3("%s: addr ntop failed", __func__
);
104 debug3("%s: new unauthenticated connection from %s/%d, at %d of %d",
105 __func__
, xas
, bits
, count
, max_persource
);
107 if (first_unused
== max_children
) { /* no free slot found */
108 debug3("%s: no free slot", __func__
);
111 if (first_unused
< 0 || first_unused
>= max_children
)
112 fatal("%s: internal error: first_unused out of range",
115 if (count
>= max_persource
)
118 /* Connection allowed, store masked address. */
119 child
[first_unused
].id
= id
;
120 memcpy(&child
[first_unused
].addr
, &xb
, sizeof(xb
));
125 srclimit_done(int id
)
129 if (max_persource
== INT_MAX
) /* no limit */
132 debug("%s: id %d", __func__
, id
);
133 /* Clear corresponding state entry. */
134 for (i
= 0; i
< max_children
; i
++) {
135 if (child
[i
].id
== id
) {