Date: Fri, 21 Jun 2002 03:12:33 +0300 From: Giorgos Keramidas <keramida@FreeBSD.org> To: hackers@FreeBSD.org Subject: Re: Limiting clients per source IP address (ftpd, inetd, etc.) Message-ID: <20020621001233.GB2178@hades.hell.gr> In-Reply-To: <20020621000924.GA2178@hades.hell.gr> References: <20020621000924.GA2178@hades.hell.gr>
next in thread | previous in thread | raw e-mail | index | archive | help
[-- Attachment #1 --]
On 2002-06-21 03:09 +0000, Giorgos Keramidas wrote:
> Below is a prototype I'm playing the last few days with, trying to
> make something that implements the above scheme using <queue.h>
> macros. Now, what do you all think about this? Does it sound like a
> nice idea to pursue further?
It would be nice if I also included the source *grin*
%%%
#include <netinet/in.h>
#include <sys/queue.h>
#include <sys/types.h>
#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
LIST_HEAD(cpidhead, childpid);
struct childpid {
pid_t cp_pid; /* Process ID of a child. */
LIST_ENTRY(childpid) cp_entry; /* Glue to the other list elements. */
};
LIST_HEAD(ciphead, childaddr);
struct childaddr {
struct in_addr ca_addr; /* Address of a host. */
int ca_count; /* Number of items in pid list. */
struct cpidhead ca_pid; /* Head of the PID list. */
LIST_ENTRY(childaddr) ca_entry; /* Glue to the other list elements. */
};
/*
* This hash keeps a number of pointers to `ciphead' lists.
* Use the iphash() function to find the proper element of this array
* for the records related to an IP address.
*/
struct ciphead *ciphash[UINT16_MAX];
static unsigned short iphash(struct in_addr *paddr);
static struct childaddr *cip_find(struct ciphead *ph, struct in_addr *addr);
static struct childaddr *cip_add(struct ciphead *ph, struct in_addr *addr);
static struct childpid *cpid_find(struct cpidhead *ph, pid_t pid);
static struct childpid *cpid_add(struct childaddr *pa, pid_t pid);
int
main(void)
{
struct in_addr lo;
struct childaddr *pa;
struct childpid *pp;
uint16_t hval;
/* Add the address of localhost to the proper place in ciphash[]. */
lo.s_addr = htonl(0x7f000001);
hval = iphash(&lo);
if (ciphash[hval] == NULL) {
ciphash[hval] = malloc(sizeof(struct ciphead));
if (ciphash[hval] == NULL)
exit(1);
} else
LIST_INIT(ciphash[hval]);
pa = cip_find(ciphash[hval], &lo);
if (pa == NULL && (pa = cip_add(ciphash[hval], &lo)) == NULL) {
if (LIST_FIRST(ciphash[hval]) == NULL)
free(ciphash[hval]);
exit(1);
}
/* Add the PID to the list `pa->ca_pid'. */
cpid_add(pa, getpid());
/* Print the mess we created so far. */
printf("%p: struct ciphead {\n", ciphash[hval]);
printf(" lh_first = %p,\n", pa = LIST_FIRST((ciphash[hval])));
printf("};\n");
printf("\n");
printf("%p: struct childaddr {\n", pa);
printf(" ca_addr = 0x%08x,\n", (pa->ca_addr).s_addr);
printf(" ca_count = %d,\n", pa->ca_count);
printf(" ca_pid = %p,\n", &(pa->ca_pid));
printf("};\n");
printf("\n");
printf("%p: struct cpidhead {\n", &(pa->ca_pid));
printf(" lh_first = %p,\n", pp = LIST_FIRST((&(pa->ca_pid))));
printf("};\n");
printf("\n");
printf("%p: struct childpid {\n", pp);
printf(" pid = %d,\n", pp->cp_pid);
printf("};\n");
printf("\n");
return (0);
}
/*
* Return a very simple XOR-based hash value, derived from the bytes of a
* `struct in_addr' structure.
*/
static uint16_t
iphash(struct in_addr *paddr)
{
uint16_t *sp;
uint16_t val;
size_t len;
size_t k;
assert(paddr != NULL);
sp = ((uint16_t *) paddr);
val = 0;
len = sizeof(struct in_addr) / sizeof(uint16_t);
if (len == 0 || len == 1) {
val = 0xffff;
} else {
for (k = 0; k < len; k++)
val ^= sp[k];
val &= 0xffff;
}
return (val);
}
/*
* Look in all the elements of `ph' and see if they match `addr'.
* Return the address of the first match, or NULL if none is found.
*/
static struct childaddr *
cip_find(struct ciphead *ph, struct in_addr *addr)
{
struct childaddr *pa;
assert(ph != NULL && addr != NULL);
LIST_FOREACH(pa, ph, ca_entry)
if ((pa->ca_addr).s_addr == (*addr).s_addr)
return (pa);
return (NULL);
}
/*
* Add a new address structure, in the list of childaddr's pointed at by
* the `ph' list head. This doesn't check for an existing match, so
* duplicates might end up in your list, if you don't use cip_find() first to
* look for older matches.
*/
struct childaddr *
cip_add(struct ciphead *ph, struct in_addr *addr)
{
struct childaddr *pa;
assert(ph != NULL && addr != NULL);
/* Try to allocate a new childaddr record. */
if ((pa = malloc(sizeof(struct childaddr))) == NULL)
return (NULL);
pa->ca_addr = *addr;
pa->ca_count = 0;
LIST_INIT(&(pa->ca_pid));
LIST_INSERT_HEAD(ph, pa, ca_entry);
return (pa);
}
/*
* Look in the list of childpid records pointed at by `ph' for the given PID.
* Return a pointer to the proper (struct childpid) or NULL if a match can not
* be found at all.
*/
static struct childpid *
cpid_find(struct cpidhead *ph, pid_t pid)
{
struct childpid *p;
assert(ph != NULL);
LIST_FOREACH(p, ph, cp_entry)
if (p->cp_pid == pid)
return (p);
return (NULL);
}
/*
* Add a new PID to the list of process IDs help under `pa'.
*/
static struct childpid *
cpid_add(struct childaddr *pa, pid_t pid)
{
struct childpid *pp;
struct cpidhead *ph;
assert(pa != NULL);
ph = &(pa->ca_pid);
pp = cpid_find(ph, pid);
if (pp == NULL) {
pp = malloc(sizeof(struct childpid));
if (pp == NULL)
return (NULL);
pp->cp_pid = pid;
LIST_INSERT_HEAD(ph, pp, cp_entry);
pa->ca_count++;
return pp;
}
return (NULL);
}
%%%
[-- Attachment #2 --]
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.7 (FreeBSD)
iD8DBQE9Em9w1g+UGjGGA7YRAif6AJ49abLA7PiNVdEGmJ1xyKPOcCtWrgCfY1D0
rhAqNdnQW2ITgQvXZ+N0x+w=
=x+Yz
-----END PGP SIGNATURE-----
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020621001233.GB2178>
