Skip to content

Commit 53b9bb7

Browse files
committed
Add support for IP limits in inetd mode
1 parent ab6ceaa commit 53b9bb7

File tree

3 files changed

+171
-0
lines changed

3 files changed

+171
-0
lines changed

src/daemons.c

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,154 @@ unsigned int daemons(const in_port_t server_port)
9595

9696
return nbcnx;
9797
}
98+
99+
#ifndef IN_PURE_MRTGINFO
100+
static unsigned int count_perip(in_port_t server_port,
101+
const struct sockaddr_storage *peer,
102+
const char * const file)
103+
{
104+
int f;
105+
int r;
106+
int c;
107+
int b = 0;
108+
int e = 0;
109+
unsigned int d = 0U;
110+
char buf[2049];
111+
unsigned char peer_bytes[16];
112+
size_t peer_len;
113+
int is_ipv6 = (STORAGE_FAMILY(*peer) == AF_INET6);
114+
115+
if (is_ipv6) {
116+
memcpy(peer_bytes, &STORAGE_SIN_ADDR6_CONST(*peer), 16);
117+
peer_len = 16;
118+
} else {
119+
memcpy(peer_bytes, &STORAGE_SIN_ADDR_CONST(*peer), 4);
120+
peer_len = 4;
121+
}
122+
123+
if ((f = open(file, O_RDONLY)) == -1) {
124+
return 0;
125+
}
126+
buf[2048] = 0;
127+
128+
for (;;) {
129+
while ((r = (int) read(f, buf + e, (size_t) (2048U - e)))
130+
< (ssize_t) 0 && errno == EINTR);
131+
if (r <= (ssize_t) 0) {
132+
break;
133+
}
134+
e += r;
135+
136+
c = b;
137+
while (c < e && buf[c] != '\n') {
138+
c++;
139+
}
140+
while (c < e) {
141+
buf[c++] = 0;
142+
while (b < c && buf[b] != ':' && buf[b] != '\n') {
143+
b++;
144+
}
145+
if (b < c && buf[b] == ':') {
146+
b++;
147+
while (b < e && buf[b] != ':') {
148+
b++;
149+
}
150+
b++;
151+
if (strtoul(buf + b, NULL, 16) ==
152+
(unsigned long) server_port) {
153+
while (b < e && buf[b] != ' ') {
154+
b++;
155+
}
156+
if (buf[b] == ' ') {
157+
unsigned char remote_bytes[16];
158+
char *hex_start = buf + b + 1;
159+
char *colon;
160+
size_t hex_len;
161+
size_t i;
162+
int match = 1;
163+
164+
colon = strchr(hex_start, ':');
165+
if (colon != NULL) {
166+
hex_len = (size_t)(colon - hex_start);
167+
if ((hex_len == 8 && peer_len == 4) ||
168+
(hex_len == 32 && peer_len == 16)) {
169+
for (i = 0; i < peer_len; i++) {
170+
unsigned int byte_val;
171+
char hex_byte[3];
172+
hex_byte[0] = hex_start[i * 2];
173+
hex_byte[1] = hex_start[i * 2 + 1];
174+
hex_byte[2] = 0;
175+
byte_val = (unsigned int) strtoul(hex_byte, NULL, 16);
176+
remote_bytes[i] = (unsigned char) byte_val;
177+
}
178+
if (peer_len == 4) {
179+
unsigned char swapped[4];
180+
swapped[0] = remote_bytes[3];
181+
swapped[1] = remote_bytes[2];
182+
swapped[2] = remote_bytes[1];
183+
swapped[3] = remote_bytes[0];
184+
memcpy(remote_bytes, swapped, 4);
185+
} else {
186+
unsigned char swapped[16];
187+
for (i = 0; i < 4; i++) {
188+
swapped[i * 4 + 0] = remote_bytes[i * 4 + 3];
189+
swapped[i * 4 + 1] = remote_bytes[i * 4 + 2];
190+
swapped[i * 4 + 2] = remote_bytes[i * 4 + 1];
191+
swapped[i * 4 + 3] = remote_bytes[i * 4 + 0];
192+
}
193+
memcpy(remote_bytes, swapped, 16);
194+
}
195+
for (i = 0; i < peer_len; i++) {
196+
if (remote_bytes[i] != peer_bytes[i]) {
197+
match = 0;
198+
break;
199+
}
200+
}
201+
if (match) {
202+
while (b < e && buf[b] != ' ') {
203+
b++;
204+
}
205+
b++;
206+
if (strtoul(buf + b, NULL, 16) == TCP_STATE_CNX) {
207+
d++;
208+
}
209+
}
210+
}
211+
}
212+
}
213+
}
214+
}
215+
b = c;
216+
while (c < e && buf[c] != '\n') {
217+
c++;
218+
}
219+
}
220+
if (e > b) {
221+
(void) memmove(buf, buf + b, (size_t) (e - b));
222+
}
223+
e -= b;
224+
b = 0;
225+
}
226+
close(f);
227+
228+
return d;
229+
}
230+
231+
unsigned int daemons_perip(const in_port_t server_port,
232+
const struct sockaddr_storage *peer)
233+
{
234+
unsigned int nbcnx;
235+
236+
if (STORAGE_FAMILY(*peer) == AF_INET6) {
237+
nbcnx = count_perip(server_port, peer, "/proc/net/tcp6");
238+
} else {
239+
nbcnx = count_perip(server_port, peer, "/proc/net/tcp");
240+
}
241+
242+
return nbcnx;
243+
}
244+
#endif
245+
98246
#else
99247
extern signed char v6ready;
100248
#endif

src/ftpd.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4944,6 +4944,27 @@ static void doit(void)
49444944
}
49454945
}
49464946

4947+
#ifndef NO_INETD
4948+
if (maxip > 0U) {
4949+
# ifdef NO_STANDALONE
4950+
users = daemons_perip(serverport, &peer);
4951+
# else
4952+
if (!standalone) {
4953+
users = daemons_perip(serverport, &peer);
4954+
}
4955+
# endif
4956+
# ifdef NO_STANDALONE
4957+
if (users >= maxip) {
4958+
# else
4959+
if (!standalone && users >= maxip) {
4960+
# endif
4961+
addreply(421, MSG_MAX_USERS_IP, (unsigned long) maxip);
4962+
doreply();
4963+
_EXIT(1);
4964+
}
4965+
}
4966+
#endif
4967+
49474968
#ifndef DONT_LOG_IP
49484969
for (;;) {
49494970
int eai;

src/ftpd.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,8 @@ void doreply(void);
377377
void sighandler(int sig);
378378
void prevent(char *arg);
379379
unsigned int daemons(in_port_t server_port);
380+
unsigned int daemons_perip(in_port_t server_port,
381+
const struct sockaddr_storage *peer);
380382
void logfile(const int facility, const char *format, ...)
381383
__attribute__ ((format(printf, 2, 3)));
382384
char *skip_telnet_controls(const char *str);

0 commit comments

Comments
 (0)