Skip site navigation (1)Skip section navigation (2)
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

--5I6of5zJg18YgZEa
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

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);
}
%%%

--5I6of5zJg18YgZEa
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.7 (FreeBSD)

iD8DBQE9Em9w1g+UGjGGA7YRAif6AJ49abLA7PiNVdEGmJ1xyKPOcCtWrgCfY1D0
rhAqNdnQW2ITgQvXZ+N0x+w=
=x+Yz
-----END PGP SIGNATURE-----

--5I6of5zJg18YgZEa--

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020621001233.GB2178>